diff options
Diffstat (limited to 'src')
339 files changed, 6084 insertions, 2918 deletions
diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index 2aa3f9c7ec0..9e56dd3770d 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -79,6 +79,7 @@ def _download(path, url, probably_big, verbose, exception): option = "-#" else: option = "-s" + require(["curl", "--version"]) run(["curl", option, "-y", "30", "-Y", "10", # timeout if speed is < 10 bytes/sec for > 30 seconds "--connect-timeout", "30", # timeout if cannot connect within 30 seconds @@ -143,6 +144,21 @@ def run(args, verbose=False, exception=False, **kwargs): sys.exit(err) +def require(cmd, exit=True): + '''Run a command, returning its output. + On error, + If `exit` is `True`, exit the process. + Otherwise, return None.''' + try: + return subprocess.check_output(cmd).strip() + except (subprocess.CalledProcessError, OSError) as exc: + if not exit: + return None + print("error: unable to run `{}`: {}".format(' '.join(cmd), exc)) + print("Please make sure it's installed and in the path.") + sys.exit(1) + + def stage0_data(rust_root): """Build a dictionary from stage0.txt""" nightlies = os.path.join(rust_root, "src/stage0.txt") @@ -164,16 +180,12 @@ def format_build_time(duration): def default_build_triple(): """Build triple as in LLVM""" default_encoding = sys.getdefaultencoding() - try: - ostype = subprocess.check_output( - ['uname', '-s']).strip().decode(default_encoding) - cputype = subprocess.check_output( - ['uname', '-m']).strip().decode(default_encoding) - except (subprocess.CalledProcessError, OSError): - if sys.platform == 'win32': - return 'x86_64-pc-windows-msvc' - err = "uname not found" - sys.exit(err) + required = not sys.platform == 'win32' + ostype = require(["uname", "-s"], exit=required).decode(default_encoding) + cputype = require(['uname', '-m'], exit=required).decode(default_encoding) + + if ostype is None or cputype is None: + return 'x86_64-pc-windows-msvc' # The goal here is to come up with the same triple as LLVM would, # at least for the subset of platforms we're willing to target. @@ -203,12 +215,7 @@ def default_build_triple(): # output from that option is too generic for our purposes (it will # always emit 'i386' on x86/amd64 systems). As such, isainfo -k # must be used instead. - try: - cputype = subprocess.check_output( - ['isainfo', '-k']).strip().decode(default_encoding) - except (subprocess.CalledProcessError, OSError): - err = "isainfo not found" - sys.exit(err) + cputype = require(['isainfo', '-k']).decode(default_encoding) elif ostype.startswith('MINGW'): # msys' `uname` does not print gcc configuration, but prints msys # configuration. so we cannot believe `uname -m`: @@ -766,13 +773,8 @@ class RustBuild(object): default_encoding = sys.getdefaultencoding() # check the existence and version of 'git' command - try: - git_version_output = subprocess.check_output(['git', '--version']) - git_version_str = git_version_output.strip().split()[2].decode(default_encoding) - self.git_version = distutils.version.LooseVersion(git_version_str) - except (subprocess.CalledProcessError, OSError): - print("error: `git` is not found, please make sure it's installed and in the path.") - sys.exit(1) + git_version_str = require(['git', '--version']).split()[2].decode(default_encoding) + self.git_version = distutils.version.LooseVersion(git_version_str) slow_submodules = self.get_toml('fast-submodules') == "false" start_time = time() diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs index 5d6e401d5b3..fb380af0a47 100644 --- a/src/bootstrap/flags.rs +++ b/src/bootstrap/flags.rs @@ -106,18 +106,18 @@ impl Flags { Usage: x.py <subcommand> [options] [<paths>...] Subcommands: - build Compile either the compiler or libraries - check Compile either the compiler or libraries, using cargo check + build, b Compile either the compiler or libraries + check, c Compile either the compiler or libraries, using cargo check clippy Run clippy (uses rustup/cargo-installed clippy binary) fix Run cargo fix fmt Run rustfmt - test Build and run some test suites + test, t Build and run some test suites bench Build and run some benchmarks doc Build documentation clean Clean out build directories dist Build distribution artifacts install Install distribution artifacts - run Run tools contained in this repository + run, r Run tools contained in this repository To learn more about a subcommand, run `./x.py <subcommand> -h`", ); @@ -184,17 +184,21 @@ To learn more about a subcommand, run `./x.py <subcommand> -h`", // there on out. let subcommand = args.iter().find(|&s| { (s == "build") + || (s == "b") || (s == "check") + || (s == "c") || (s == "clippy") || (s == "fix") || (s == "fmt") || (s == "test") + || (s == "t") || (s == "bench") || (s == "doc") || (s == "clean") || (s == "dist") || (s == "install") || (s == "run") + || (s == "r") }); let subcommand = match subcommand { Some(s) => s, @@ -210,7 +214,7 @@ To learn more about a subcommand, run `./x.py <subcommand> -h`", // Some subcommands get extra options match subcommand.as_str() { - "test" => { + "test" | "t" => { opts.optflag("", "no-fail-fast", "Run all tests regardless of failure"); opts.optmulti("", "test-args", "extra arguments", "ARGS"); opts.optmulti( @@ -285,7 +289,7 @@ To learn more about a subcommand, run `./x.py <subcommand> -h`", } // Extra help text for some commands match subcommand.as_str() { - "build" => { + "build" | "b" => { subcommand_help.push_str( "\n Arguments: @@ -312,7 +316,7 @@ Arguments: Once this is done, build/$ARCH/stage1 contains a usable compiler.", ); } - "check" => { + "check" | "c" => { subcommand_help.push_str( "\n Arguments: @@ -362,7 +366,7 @@ Arguments: ./x.py fmt --check", ); } - "test" => { + "test" | "t" => { subcommand_help.push_str( "\n Arguments: @@ -407,7 +411,7 @@ Arguments: ./x.py doc --stage 1", ); } - "run" => { + "run" | "r" => { subcommand_help.push_str( "\n Arguments: @@ -453,11 +457,11 @@ Arguments: } let cmd = match subcommand.as_str() { - "build" => Subcommand::Build { paths }, - "check" => Subcommand::Check { paths }, + "build" | "b" => Subcommand::Build { paths }, + "check" | "c" => Subcommand::Check { paths }, "clippy" => Subcommand::Clippy { paths }, "fix" => Subcommand::Fix { paths }, - "test" => Subcommand::Test { + "test" | "t" => Subcommand::Test { paths, bless: matches.opt_present("bless"), compare_mode: matches.opt_str("compare-mode"), @@ -487,7 +491,7 @@ Arguments: "fmt" => Subcommand::Format { check: matches.opt_present("check") }, "dist" => Subcommand::Dist { paths }, "install" => Subcommand::Install { paths }, - "run" => { + "run" | "r" => { if paths.is_empty() { println!("\nrun requires at least a path!\n"); usage(1, &opts, &subcommand_help, &extra_help); diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index 90b8b5eea94..0cf47d20ead 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -528,7 +528,7 @@ impl Step for Clippy { host, "test", "src/tools/clippy", - SourceType::Submodule, + SourceType::InTree, &[], ); diff --git a/src/bootstrap/toolstate.rs b/src/bootstrap/toolstate.rs index e6560771c0e..6c219cee01e 100644 --- a/src/bootstrap/toolstate.rs +++ b/src/bootstrap/toolstate.rs @@ -78,7 +78,6 @@ static STABLE_TOOLS: &[(&str, &str)] = &[ ("edition-guide", "src/doc/edition-guide"), ("rls", "src/tools/rls"), ("rustfmt", "src/tools/rustfmt"), - ("clippy-driver", "src/tools/clippy"), ]; // These tools are permitted to not build on the beta/stable channels. @@ -89,7 +88,7 @@ static STABLE_TOOLS: &[(&str, &str)] = &[ static NIGHTLY_TOOLS: &[(&str, &str)] = &[ ("miri", "src/tools/miri"), ("embedded-book", "src/doc/embedded-book"), - ("rustc-dev-guide", "src/doc/rustc-dev-guide"), + // ("rustc-dev-guide", "src/doc/rustc-dev-guide"), ]; fn print_error(tool: &str, submodule: &str) { diff --git a/src/ci/docker/mingw-check/Dockerfile b/src/ci/docker/mingw-check/Dockerfile index 17d844a1f99..97e4d3fd749 100644 --- a/src/ci/docker/mingw-check/Dockerfile +++ b/src/ci/docker/mingw-check/Dockerfile @@ -27,4 +27,5 @@ ENV SCRIPT python3 ../x.py test src/tools/expand-yaml-anchors && \ python3 ../x.py build --stage 0 src/tools/build-manifest && \ python3 ../x.py test --stage 0 src/tools/compiletest && \ python3 ../x.py test src/tools/tidy && \ + python3 ../x.py doc --stage 0 src/libstd && \ /scripts/validate-toolstate.sh diff --git a/src/ci/docker/x86_64-gnu-tools/checktools.sh b/src/ci/docker/x86_64-gnu-tools/checktools.sh index 00ac20c08dc..c9d1cb21da8 100755 --- a/src/ci/docker/x86_64-gnu-tools/checktools.sh +++ b/src/ci/docker/x86_64-gnu-tools/checktools.sh @@ -14,7 +14,6 @@ python3 "$X_PY" test --no-fail-fast \ src/doc/rust-by-example \ src/doc/embedded-book \ src/doc/edition-guide \ - src/doc/rustc-dev-guide \ src/tools/clippy \ src/tools/rls \ src/tools/rustfmt \ diff --git a/src/ci/scripts/install-msys2-packages.sh b/src/ci/scripts/install-msys2-packages.sh index 3874a86e120..ff7479c05d0 100755 --- a/src/ci/scripts/install-msys2-packages.sh +++ b/src/ci/scripts/install-msys2-packages.sh @@ -9,11 +9,19 @@ if isWindows; then pacman -S --noconfirm --needed base-devel ca-certificates make diffutils tar \ binutils + # Detect the native Python version installed on the agent. On GitHub + # Actions, the C:\hostedtoolcache\windows\Python directory contains a + # subdirectory for each installed Python version. + # + # The -V flag of the sort command sorts the input by version number. + native_python_version="$(ls /c/hostedtoolcache/windows/Python | sort -Vr | head -n 1)" + # Make sure we use the native python interpreter instead of some msys equivalent # one way or another. The msys interpreters seem to have weird path conversions # baked in which break LLVM's build system one way or another, so let's use the # native version which keeps everything as native as possible. - python_home="C:/hostedtoolcache/windows/Python/3.7.6/x64" + python_home="/c/hostedtoolcache/windows/Python/${native_python_version}/x64" cp "${python_home}/python.exe" "${python_home}/python3.exe" - ciCommandAddPath "C:\\hostedtoolcache\\windows\\Python\\3.7.6\\x64" + ciCommandAddPath "C:\\hostedtoolcache\\windows\\Python\\${native_python_version}\\x64" + ciCommandAddPath "C:\\hostedtoolcache\\windows\\Python\\${native_python_version}\\x64\\Scripts" fi diff --git a/src/doc/rustc/src/codegen-options/index.md b/src/doc/rustc/src/codegen-options/index.md index 08b5ab10817..dbe281be7df 100644 --- a/src/doc/rustc/src/codegen-options/index.md +++ b/src/doc/rustc/src/codegen-options/index.md @@ -62,24 +62,40 @@ the linker. ## embed-bitcode -This flag controls whether or not the compiler puts LLVM bitcode into generated -rlibs. It takes one of the following values: +This flag controls whether or not the compiler embeds LLVM bitcode into object +files. It takes one of the following values: * `y`, `yes`, `on`, or no value: put bitcode in rlibs (the default). * `n`, `no`, or `off`: omit bitcode from rlibs. -LLVM bitcode is only needed when link-time optimization (LTO) is being -performed, but it is enabled by default for backwards compatibility reasons. +LLVM bitcode is required when rustc is performing link-time optimization (LTO). +It is also required on some targets like iOS ones where vendors look for LLVM +bitcode. Embedded bitcode will appear in rustc-generated object files inside of +a section whose name is defined by the target platform. Most of the time this is +`.llvmbc`. The use of `-C embed-bitcode=no` can significantly improve compile times and -reduce generated file sizes. For these reasons, Cargo uses `-C -embed-bitcode=no` whenever possible. Likewise, if you are building directly -with `rustc` we recommend using `-C embed-bitcode=no` whenever you are not -using LTO. +reduce generated file sizes if your compilation does not actually need bitcode +(e.g. if you're not compiling for iOS or you're not performing LTO). For these +reasons, Cargo uses `-C embed-bitcode=no` whenever possible. Likewise, if you +are building directly with `rustc` we recommend using `-C embed-bitcode=no` +whenever you are not using LTO. If combined with `-C lto`, `-C embed-bitcode=no` will cause `rustc` to abort at start-up, because the combination is invalid. +> **Note**: if you're building Rust code with LTO then you probably don't even +> need the `embed-bitcode` option turned on. You'll likely want to use +> `-Clinker-plugin-lto` instead which skips generating object files entirely and +> simply replaces object files with LLVM bitcode. The only purpose for +> `-Cembed-bitcode` is when you're generating an rlib that is both being used +> with and without LTO. For example Rust's standard library ships with embedded +> bitcode since users link to it both with and without LTO. +> +> This also may make you wonder why the default is `yes` for this option. The +> reason for that is that it's how it was for rustc 1.44 and prior. In 1.45 this +> option was added to turn off what had always been the default. + ## extra-filename This option allows you to put extra data in each output filename. It takes a @@ -98,6 +114,18 @@ values: The default behaviour, if frame pointers are not force-enabled, depends on the target. +## force-unwind-tables + +This flag forces the generation of unwind tables. It takes one of the following +values: + +* `y`, `yes`, `on`, or no value: Unwind tables are forced to be generated. +* `n`, `no`, or `off`: Unwind tables are not forced to be generated. If unwind + tables are required by the target or `-C panic=unwind`, an error will be + emitted. + +The default if not specified depends on the target. + ## incremental This flag allows you to enable incremental compilation, which allows `rustc` @@ -187,6 +215,18 @@ the following values: * `n`, `no`, or `off`: disable linker plugin LTO (the default). * A path to the linker plugin. +More specifically this flag will cause the compiler to replace its typical +object file output with LLVM bitcode files. For example an rlib produced with +`-Clinker-plugin-lto` will still have `*.o` files in it, but they'll all be LLVM +bitcode instead of actual machine code. It is expected that the native platform +linker is capable of loading these LLVM bitcode files and generating code at +link time (typically after performing optimizations). + +Note that rustc can also read its own object files produced with +`-Clinker-plugin-lto`. If an rlib is only ever going to get used later with a +`-Clto` compilation then you can pass `-Clinker-plugin-lto` to speed up +compilation and avoid generating object files that aren't used. + ## llvm-args This flag can be used to pass a list of arguments directly to LLVM. diff --git a/src/liballoc/benches/btree/map.rs b/src/liballoc/benches/btree/map.rs index 83cdebf0e3f..38d19c59ad1 100644 --- a/src/liballoc/benches/btree/map.rs +++ b/src/liballoc/benches/btree/map.rs @@ -1,6 +1,6 @@ use std::collections::BTreeMap; use std::iter::Iterator; -use std::ops::Bound::{Excluded, Unbounded}; +use std::ops::RangeBounds; use std::vec::Vec; use rand::{seq::SliceRandom, thread_rng, Rng}; @@ -117,7 +117,7 @@ map_find_rand_bench! {find_rand_10_000, 10_000, BTreeMap} map_find_seq_bench! {find_seq_100, 100, BTreeMap} map_find_seq_bench! {find_seq_10_000, 10_000, BTreeMap} -fn bench_iter(b: &mut Bencher, size: i32) { +fn bench_iteration(b: &mut Bencher, size: i32) { let mut map = BTreeMap::<i32, i32>::new(); let mut rng = thread_rng(); @@ -133,21 +133,21 @@ fn bench_iter(b: &mut Bencher, size: i32) { } #[bench] -pub fn iter_20(b: &mut Bencher) { - bench_iter(b, 20); +pub fn iteration_20(b: &mut Bencher) { + bench_iteration(b, 20); } #[bench] -pub fn iter_1000(b: &mut Bencher) { - bench_iter(b, 1000); +pub fn iteration_1000(b: &mut Bencher) { + bench_iteration(b, 1000); } #[bench] -pub fn iter_100000(b: &mut Bencher) { - bench_iter(b, 100000); +pub fn iteration_100000(b: &mut Bencher) { + bench_iteration(b, 100000); } -fn bench_iter_mut(b: &mut Bencher, size: i32) { +fn bench_iteration_mut(b: &mut Bencher, size: i32) { let mut map = BTreeMap::<i32, i32>::new(); let mut rng = thread_rng(); @@ -163,18 +163,18 @@ fn bench_iter_mut(b: &mut Bencher, size: i32) { } #[bench] -pub fn iter_mut_20(b: &mut Bencher) { - bench_iter_mut(b, 20); +pub fn iteration_mut_20(b: &mut Bencher) { + bench_iteration_mut(b, 20); } #[bench] -pub fn iter_mut_1000(b: &mut Bencher) { - bench_iter_mut(b, 1000); +pub fn iteration_mut_1000(b: &mut Bencher) { + bench_iteration_mut(b, 1000); } #[bench] -pub fn iter_mut_100000(b: &mut Bencher) { - bench_iter_mut(b, 100000); +pub fn iteration_mut_100000(b: &mut Bencher) { + bench_iteration_mut(b, 100000); } fn bench_first_and_last(b: &mut Bencher, size: i32) { @@ -202,57 +202,83 @@ pub fn first_and_last_10k(b: &mut Bencher) { bench_first_and_last(b, 10_000); } -#[bench] -pub fn range_excluded_excluded(b: &mut Bencher) { - let size = 144; - let map: BTreeMap<_, _> = (0..size).map(|i| (i, i)).collect(); +const BENCH_RANGE_SIZE: i32 = 145; +const BENCH_RANGE_COUNT: i32 = BENCH_RANGE_SIZE * (BENCH_RANGE_SIZE - 1) / 2; + +fn bench_range<F, R>(b: &mut Bencher, f: F) +where + F: Fn(i32, i32) -> R, + R: RangeBounds<i32>, +{ + let map: BTreeMap<_, _> = (0..BENCH_RANGE_SIZE).map(|i| (i, i)).collect(); b.iter(|| { - for first in 0..size { - for last in first + 1..size { - black_box(map.range((Excluded(first), Excluded(last)))); + let mut c = 0; + for i in 0..BENCH_RANGE_SIZE { + for j in i + 1..BENCH_RANGE_SIZE { + black_box(map.range(f(i, j))); + c += 1; } } + debug_assert_eq!(c, BENCH_RANGE_COUNT); }); } #[bench] -pub fn range_excluded_unbounded(b: &mut Bencher) { - let size = 144; - let map: BTreeMap<_, _> = (0..size).map(|i| (i, i)).collect(); - b.iter(|| { - for first in 0..size { - black_box(map.range((Excluded(first), Unbounded))); - } - }); +pub fn range_included_excluded(b: &mut Bencher) { + bench_range(b, |i, j| i..j); } #[bench] pub fn range_included_included(b: &mut Bencher) { - let size = 144; - let map: BTreeMap<_, _> = (0..size).map(|i| (i, i)).collect(); - b.iter(|| { - for first in 0..size { - for last in first..size { - black_box(map.range(first..=last)); - } - } - }); + bench_range(b, |i, j| i..=j); } #[bench] pub fn range_included_unbounded(b: &mut Bencher) { - let size = 144; + bench_range(b, |i, _| i..); +} + +#[bench] +pub fn range_unbounded_unbounded(b: &mut Bencher) { + bench_range(b, |_, _| ..); +} + +fn bench_iter(b: &mut Bencher, repeats: i32, size: i32) { let map: BTreeMap<_, _> = (0..size).map(|i| (i, i)).collect(); b.iter(|| { - for first in 0..size { - black_box(map.range(first..)); + for _ in 0..repeats { + black_box(map.iter()); } }); } +/// Contrast range_unbounded_unbounded with `iter()`. #[bench] -pub fn range_unbounded_unbounded(b: &mut Bencher) { - let size = 144; - let map: BTreeMap<_, _> = (0..size).map(|i| (i, i)).collect(); - b.iter(|| map.range(..)); +pub fn range_unbounded_vs_iter(b: &mut Bencher) { + bench_iter(b, BENCH_RANGE_COUNT, BENCH_RANGE_SIZE); +} + +#[bench] +pub fn iter_0(b: &mut Bencher) { + bench_iter(b, 1_000, 0); +} + +#[bench] +pub fn iter_1(b: &mut Bencher) { + bench_iter(b, 1_000, 1); +} + +#[bench] +pub fn iter_100(b: &mut Bencher) { + bench_iter(b, 1_000, 100); +} + +#[bench] +pub fn iter_10k(b: &mut Bencher) { + bench_iter(b, 1_000, 10_000); +} + +#[bench] +pub fn iter_1m(b: &mut Bencher) { + bench_iter(b, 1_000, 1_000_000); } diff --git a/src/liballoc/collections/btree/map.rs b/src/liballoc/collections/btree/map.rs index c0b976565e4..113df80d0c2 100644 --- a/src/liballoc/collections/btree/map.rs +++ b/src/liballoc/collections/btree/map.rs @@ -556,7 +556,8 @@ impl<K: Ord, V> BTreeMap<K, V> { /// map.insert(1, "a"); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - pub fn new() -> BTreeMap<K, V> { + #[rustc_const_unstable(feature = "const_btree_new", issue = "71835")] + pub const fn new() -> BTreeMap<K, V> { BTreeMap { root: None, length: 0 } } @@ -1540,16 +1541,10 @@ impl<K, V> IntoIterator for BTreeMap<K, V> { fn into_iter(self) -> IntoIter<K, V> { let mut me = ManuallyDrop::new(self); - if let Some(root) = me.root.as_mut() { - let root1 = unsafe { ptr::read(root).into_ref() }; - let root2 = unsafe { ptr::read(root).into_ref() }; - let len = me.length; - - IntoIter { - front: Some(root1.first_leaf_edge()), - back: Some(root2.last_leaf_edge()), - length: len, - } + if let Some(root) = me.root.take() { + let (f, b) = full_range_search(root.into_ref()); + + IntoIter { front: Some(f), back: Some(b), length: me.length } } else { IntoIter { front: None, back: None, length: 0 } } @@ -2037,6 +2032,7 @@ where } } +/// Finds the leaf edges delimiting a specified range in or underneath a node. fn range_search<BorrowType, K, V, Q: ?Sized, R: RangeBounds<Q>>( root: NodeRef<BorrowType, K, V, marker::LeafOrInternal>, range: R, @@ -2122,6 +2118,33 @@ where } } +/// Equivalent to `range_search(k, v, ..)` without the `Ord` bound. +fn full_range_search<BorrowType, K, V>( + root: NodeRef<BorrowType, K, V, marker::LeafOrInternal>, +) -> ( + Handle<NodeRef<BorrowType, K, V, marker::Leaf>, marker::Edge>, + Handle<NodeRef<BorrowType, K, V, marker::Leaf>, marker::Edge>, +) { + // We duplicate the root NodeRef here -- we will never access it in a way + // that overlaps references obtained from the root. + let mut min_node = unsafe { ptr::read(&root) }; + let mut max_node = root; + loop { + let front = min_node.first_edge(); + let back = max_node.last_edge(); + match (front.force(), back.force()) { + (Leaf(f), Leaf(b)) => { + return (f, b); + } + (Internal(min_int), Internal(max_int)) => { + min_node = min_int.descend(); + max_node = max_int.descend(); + } + _ => unreachable!("BTreeMap has different depths"), + }; + } +} + impl<K, V> BTreeMap<K, V> { /// Gets an iterator over the entries of the map, sorted by key. /// @@ -2146,12 +2169,12 @@ impl<K, V> BTreeMap<K, V> { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn iter(&self) -> Iter<'_, K, V> { - Iter { - range: Range { - front: self.root.as_ref().map(|r| r.as_ref().first_leaf_edge()), - back: self.root.as_ref().map(|r| r.as_ref().last_leaf_edge()), - }, - length: self.length, + if let Some(root) = &self.root { + let (f, b) = full_range_search(root.as_ref()); + + Iter { range: Range { front: Some(f), back: Some(b) }, length: self.length } + } else { + Iter { range: Range { front: None, back: None }, length: 0 } } } @@ -2178,19 +2201,15 @@ impl<K, V> BTreeMap<K, V> { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn iter_mut(&mut self) -> IterMut<'_, K, V> { - IterMut { - range: if let Some(root) = &mut self.root { - let root1 = root.as_mut(); - let root2 = unsafe { ptr::read(&root1) }; - RangeMut { - front: Some(root1.first_leaf_edge()), - back: Some(root2.last_leaf_edge()), - _marker: PhantomData, - } - } else { - RangeMut { front: None, back: None, _marker: PhantomData } - }, - length: self.length, + if let Some(root) = &mut self.root { + let (f, b) = full_range_search(root.as_mut()); + + IterMut { + range: RangeMut { front: Some(f), back: Some(b), _marker: PhantomData }, + length: self.length, + } + } else { + IterMut { range: RangeMut { front: None, back: None, _marker: PhantomData }, length: 0 } } } @@ -2499,15 +2518,14 @@ impl<'a, K: Ord, V> VacantEntry<'a, K, V> { /// /// ``` /// use std::collections::BTreeMap; + /// use std::collections::btree_map::Entry; /// - /// let mut count: BTreeMap<&str, usize> = BTreeMap::new(); + /// let mut map: BTreeMap<&str, u32> = BTreeMap::new(); /// - /// // count the number of occurrences of letters in the vec - /// for x in vec!["a","b","a","c","a","b"] { - /// *count.entry(x).or_insert(0) += 1; + /// if let Entry::Vacant(o) = map.entry("poneyland") { + /// o.insert(37); /// } - /// - /// assert_eq!(count["a"], 3); + /// assert_eq!(map["poneyland"], 37); /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn insert(self, value: V) -> &'a mut V { diff --git a/src/liballoc/collections/btree/set.rs b/src/liballoc/collections/btree/set.rs index 9bf483f269f..dee5fb878ff 100644 --- a/src/liballoc/collections/btree/set.rs +++ b/src/liballoc/collections/btree/set.rs @@ -309,7 +309,8 @@ impl<T: Ord> BTreeSet<T> { /// let mut set: BTreeSet<i32> = BTreeSet::new(); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - pub fn new() -> BTreeSet<T> { + #[rustc_const_unstable(feature = "const_btree_new", issue = "71835")] + pub const fn new() -> BTreeSet<T> { BTreeSet { map: BTreeMap::new() } } diff --git a/src/liballoc/collections/linked_list.rs b/src/liballoc/collections/linked_list.rs index bfa4045787f..cc0f07b8227 100644 --- a/src/liballoc/collections/linked_list.rs +++ b/src/liballoc/collections/linked_list.rs @@ -1496,6 +1496,31 @@ impl<'a, T> CursorMut<'a, T> { } } + /// Removes the current element from the `LinkedList` without deallocating the list node. + /// + /// The node that was removed is returned as a new `LinkedList` containing only this node. + /// The cursor is moved to point to the next element in the current `LinkedList`. + /// + /// If the cursor is currently pointing to the "ghost" non-element then no element + /// is removed and `None` is returned. + #[unstable(feature = "linked_list_cursors", issue = "58533")] + pub fn remove_current_as_list(&mut self) -> Option<LinkedList<T>> { + let mut unlinked_node = self.current?; + unsafe { + self.current = unlinked_node.as_ref().next; + self.list.unlink_node(unlinked_node); + + unlinked_node.as_mut().prev = None; + unlinked_node.as_mut().next = None; + Some(LinkedList { + head: Some(unlinked_node), + tail: Some(unlinked_node), + len: 1, + marker: PhantomData, + }) + } + } + /// Inserts the elements from the given `LinkedList` after the current one. /// /// If the cursor is pointing at the "ghost" non-element then the new elements are diff --git a/src/liballoc/fmt.rs b/src/liballoc/fmt.rs index 13ef2f063f9..26077f3c8d1 100644 --- a/src/liballoc/fmt.rs +++ b/src/liballoc/fmt.rs @@ -50,8 +50,8 @@ //! The internal iterator over the argument has not been advanced by the time //! the first `{}` is seen, so it prints the first argument. Then upon reaching //! the second `{}`, the iterator has advanced forward to the second argument. -//! Essentially, parameters which explicitly name their argument do not affect -//! parameters which do not name an argument in terms of positional specifiers. +//! Essentially, parameters that explicitly name their argument do not affect +//! parameters that do not name an argument in terms of positional specifiers. //! //! A format string is required to use all of its arguments, otherwise it is a //! compile-time error. You may refer to the same argument more than once in the @@ -60,7 +60,7 @@ //! ## Named parameters //! //! Rust itself does not have a Python-like equivalent of named parameters to a -//! function, but the [`format!`] macro is a syntax extension which allows it to +//! function, but the [`format!`] macro is a syntax extension that allows it to //! leverage named parameters. Named parameters are listed at the end of the //! argument list and have the syntax: //! @@ -77,7 +77,7 @@ //! ``` //! //! It is not valid to put positional parameters (those without names) after -//! arguments which have names. Like with positional parameters, it is not +//! arguments that have names. Like with positional parameters, it is not //! valid to provide named parameters that are unused by the format string. //! //! # Formatting Parameters @@ -130,7 +130,7 @@ //! //! The default [fill/alignment](#fillalignment) for non-numerics is a space and //! left-aligned. The -//! defaults for numeric formatters is also a space but with right-alignment. If +//! default for numeric formatters is also a space character but with right-alignment. If //! the `0` flag (see below) is specified for numerics, then the implicit fill character is //! `0`. //! @@ -161,7 +161,7 @@ //! `Signed` trait. This flag indicates that the correct sign (`+` or `-`) //! should always be printed. //! * `-` - Currently not used -//! * `#` - This flag is indicates that the "alternate" form of printing should +//! * `#` - This flag indicates that the "alternate" form of printing should //! be used. The alternate forms are: //! * `#?` - pretty-print the [`Debug`] formatting //! * `#x` - precedes the argument with a `0x` @@ -173,9 +173,9 @@ //! like `{:08}` would yield `00000001` for the integer `1`, while the //! same format would yield `-0000001` for the integer `-1`. Notice that //! the negative version has one fewer zero than the positive version. -//! Note that padding zeroes are always placed after the sign (if any) +//! Note that padding zeros are always placed after the sign (if any) //! and before the digits. When used together with the `#` flag, a similar -//! rule applies: padding zeroes are inserted after the prefix but before +//! rule applies: padding zeros are inserted after the prefix but before //! the digits. The prefix is included in the total width. //! //! ## Precision @@ -251,7 +251,7 @@ //! //! In some programming languages, the behavior of string formatting functions //! depends on the operating system's locale setting. The format functions -//! provided by Rust's standard library do not have any concept of locale, and +//! provided by Rust's standard library do not have any concept of locale and //! will produce the same results on all systems regardless of user //! configuration. //! @@ -470,7 +470,7 @@ //! //! ### `format_args!` //! -//! This is a curious macro which is used to safely pass around +//! This is a curious macro used to safely pass around //! an opaque object describing the format string. This object //! does not require any heap allocations to create, and it only //! references information on the stack. Under the hood, all of @@ -495,7 +495,7 @@ //! This structure can then be passed to the [`write`] and [`format`] functions //! inside this module in order to process the format string. //! The goal of this macro is to even further prevent intermediate allocations -//! when dealing formatting strings. +//! when dealing with formatting strings. //! //! For example, a logging library could use the standard formatting syntax, but //! it would internally pass around this structure until it has been determined diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index ecec1fb039b..5365c9d0168 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -82,6 +82,7 @@ #![feature(cfg_sanitize)] #![feature(cfg_target_has_atomic)] #![feature(coerce_unsized)] +#![feature(const_btree_new)] #![feature(const_generic_impls_guard)] #![feature(const_generics)] #![feature(const_in_array_repeat_expressions)] diff --git a/src/liballoc/sync.rs b/src/liballoc/sync.rs index a81e0cf7e1d..19d289c87fd 100644 --- a/src/liballoc/sync.rs +++ b/src/liballoc/sync.rs @@ -776,6 +776,79 @@ impl<T: ?Sized> Arc<T> { this.inner().strong.load(SeqCst) } + /// Increments the strong reference count on the `Arc<T>` associated with the + /// provided pointer by one. + /// + /// # Safety + /// + /// The pointer must have been obtained through `Arc::into_raw`, and the + /// associated `Arc` instance must be valid (i.e. the strong count must be at + /// least 1) for the duration of this method. + /// + /// # Examples + /// + /// ``` + /// #![feature(arc_mutate_strong_count)] + /// + /// use std::sync::Arc; + /// + /// let five = Arc::new(5); + /// + /// unsafe { + /// let ptr = Arc::into_raw(five); + /// Arc::incr_strong_count(ptr); + /// + /// // This assertion is deterministic because we haven't shared + /// // the `Arc` between threads. + /// let five = Arc::from_raw(ptr); + /// assert_eq!(2, Arc::strong_count(&five)); + /// } + /// ``` + #[inline] + #[unstable(feature = "arc_mutate_strong_count", issue = "71983")] + pub unsafe fn incr_strong_count(ptr: *const T) { + // Retain Arc, but don't touch refcount by wrapping in ManuallyDrop + let arc = mem::ManuallyDrop::new(Arc::<T>::from_raw(ptr)); + // Now increase refcount, but don't drop new refcount either + let _arc_clone: mem::ManuallyDrop<_> = arc.clone(); + } + + /// Decrements the strong reference count on the `Arc<T>` associated with the + /// provided pointer by one. + /// + /// # Safety + /// + /// The pointer must have been obtained through `Arc::into_raw`, and the + /// associated `Arc` instance must be valid (i.e. the strong count must be at + /// least 1) when invoking this method. This method can be used to release the final + /// `Arc` and backing storage, but **should not** be called after the final `Arc` has been + /// released. + /// + /// # Examples + /// + /// ``` + /// #![feature(arc_mutate_strong_count)] + /// + /// use std::sync::Arc; + /// + /// let five = Arc::new(5); + /// + /// unsafe { + /// let ptr = Arc::into_raw(five); + /// Arc::decr_strong_count(ptr); + /// + /// // This assertion is deterministic because we haven't shared + /// // the `Arc` between threads. + /// let five = Arc::from_raw(ptr); + /// assert_eq!(0, Arc::strong_count(&five)); + /// } + /// ``` + #[inline] + #[unstable(feature = "arc_mutate_strong_count", issue = "71983")] + pub unsafe fn decr_strong_count(ptr: *const T) { + mem::drop(Arc::from_raw(ptr)); + } + #[inline] fn inner(&self) -> &ArcInner<T> { // This unsafety is ok because while this arc is alive we're guaranteed diff --git a/src/liballoc/task.rs b/src/liballoc/task.rs index a64d5d7a63b..745444a152e 100644 --- a/src/liballoc/task.rs +++ b/src/liballoc/task.rs @@ -1,6 +1,6 @@ #![unstable(feature = "wake_trait", issue = "69912")] //! Types and Traits for working with asynchronous tasks. -use core::mem::{self, ManuallyDrop}; +use core::mem::ManuallyDrop; use core::task::{RawWaker, RawWakerVTable, Waker}; use crate::sync::Arc; @@ -60,9 +60,11 @@ impl<W: Wake + Send + Sync + 'static> From<Arc<W>> for RawWaker { fn raw_waker<W: Wake + Send + Sync + 'static>(waker: Arc<W>) -> RawWaker { // Increment the reference count of the arc to clone it. unsafe fn clone_waker<W: Wake + Send + Sync + 'static>(waker: *const ()) -> RawWaker { - let waker: Arc<W> = Arc::from_raw(waker as *const W); - mem::forget(Arc::clone(&waker)); - raw_waker(waker) + Arc::incr_strong_count(waker as *const W); + RawWaker::new( + waker as *const (), + &RawWakerVTable::new(clone_waker::<W>, wake::<W>, wake_by_ref::<W>, drop_waker::<W>), + ) } // Wake by value, moving the Arc into the Wake::wake function @@ -79,7 +81,7 @@ fn raw_waker<W: Wake + Send + Sync + 'static>(waker: Arc<W>) -> RawWaker { // Decrement the reference count of the Arc on drop unsafe fn drop_waker<W: Wake + Send + Sync + 'static>(waker: *const ()) { - mem::drop(Arc::from_raw(waker as *const W)); + Arc::decr_strong_count(waker as *const W); } RawWaker::new( diff --git a/src/libcore/array/mod.rs b/src/libcore/array/mod.rs index 937451274cf..549228ffffa 100644 --- a/src/libcore/array/mod.rs +++ b/src/libcore/array/mod.rs @@ -375,6 +375,7 @@ where } } +/// Implements comparison of arrays lexicographically. #[stable(feature = "rust1", since = "1.0.0")] impl<T: Ord, const N: usize> Ord for [T; N] where diff --git a/src/libcore/future/mod.rs b/src/libcore/future/mod.rs index e7f681c2e94..b5a102916a0 100644 --- a/src/libcore/future/mod.rs +++ b/src/libcore/future/mod.rs @@ -10,9 +10,17 @@ use crate::{ }; mod future; +mod pending; +mod ready; + #[stable(feature = "futures_api", since = "1.36.0")] pub use self::future::Future; +#[unstable(feature = "future_readiness_fns", issue = "70921")] +pub use pending::{pending, Pending}; +#[unstable(feature = "future_readiness_fns", issue = "70921")] +pub use ready::{ready, Ready}; + /// This type is needed because: /// /// a) Generators cannot implement `for<'a, 'b> Generator<&'a mut Context<'b>>`, so we need to pass diff --git a/src/libcore/future/pending.rs b/src/libcore/future/pending.rs new file mode 100644 index 00000000000..74887b68aa0 --- /dev/null +++ b/src/libcore/future/pending.rs @@ -0,0 +1,57 @@ +use crate::future::Future; +use crate::marker; +use crate::pin::Pin; +use crate::task::{Context, Poll}; + +/// Creates a future which never resolves, representing a computation that never +/// finishes. +/// +/// This `struct` is created by the [`pending`] function. See its +/// documentation for more. +/// +/// [`pending`]: fn.pending.html +#[unstable(feature = "future_readiness_fns", issue = "70921")] +#[derive(Debug)] +#[must_use = "futures do nothing unless you `.await` or poll them"] +pub struct Pending<T> { + _data: marker::PhantomData<T>, +} + +/// Creates a future which never resolves, representing a computation that never +/// finishes. +/// +/// # Examples +/// +/// ```no_run +/// #![feature(future_readiness_fns)] +/// use core::future; +/// +/// # async fn run() { +/// let future = future::pending(); +/// let () = future.await; +/// unreachable!(); +/// # } +/// ``` +#[unstable(feature = "future_readiness_fns", issue = "70921")] +pub fn pending<T>() -> Pending<T> { + Pending { _data: marker::PhantomData } +} + +#[unstable(feature = "future_readiness_fns", issue = "70921")] +impl<T> Future for Pending<T> { + type Output = T; + + fn poll(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<T> { + Poll::Pending + } +} + +#[unstable(feature = "future_readiness_fns", issue = "70921")] +impl<T> Unpin for Pending<T> {} + +#[unstable(feature = "future_readiness_fns", issue = "70921")] +impl<T> Clone for Pending<T> { + fn clone(&self) -> Self { + pending() + } +} diff --git a/src/libcore/future/ready.rs b/src/libcore/future/ready.rs new file mode 100644 index 00000000000..31b39d7fb6c --- /dev/null +++ b/src/libcore/future/ready.rs @@ -0,0 +1,45 @@ +use crate::future::Future; +use crate::pin::Pin; +use crate::task::{Context, Poll}; + +/// Creates a future that is immediately ready with a value. +/// +/// This `struct` is created by the [`ready`] function. See its +/// documentation for more. +/// +/// [`ready`]: fn.ready.html +#[unstable(feature = "future_readiness_fns", issue = "70921")] +#[derive(Debug, Clone)] +#[must_use = "futures do nothing unless you `.await` or poll them"] +pub struct Ready<T>(Option<T>); + +#[unstable(feature = "future_readiness_fns", issue = "70921")] +impl<T> Unpin for Ready<T> {} + +#[unstable(feature = "future_readiness_fns", issue = "70921")] +impl<T> Future for Ready<T> { + type Output = T; + + #[inline] + fn poll(mut self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<T> { + Poll::Ready(self.0.take().expect("Ready polled after completion")) + } +} + +/// Creates a future that is immediately ready with a value. +/// +/// # Examples +/// +/// ``` +/// #![feature(future_readiness_fns)] +/// use core::future; +/// +/// # async fn run() { +/// let a = future::ready(1); +/// assert_eq!(a.await, 1); +/// # } +/// ``` +#[unstable(feature = "future_readiness_fns", issue = "70921")] +pub fn ready<T>(t: T) -> Ready<T> { + Ready(Some(t)) +} diff --git a/src/libcore/num/f32.rs b/src/libcore/num/f32.rs index 32f49563289..4483940c9a7 100644 --- a/src/libcore/num/f32.rs +++ b/src/libcore/num/f32.rs @@ -18,15 +18,46 @@ use crate::num::FpCategory; /// The radix or base of the internal representation of `f32`. /// Use [`f32::RADIX`](../../std/primitive.f32.html#associatedconstant.RADIX) instead. +/// +/// # Examples +/// +/// ```rust +/// // deprecated way +/// let r = std::f32::RADIX; +/// +/// // intended way +/// let r = f32::RADIX; +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub const RADIX: u32 = f32::RADIX; /// Number of significant digits in base 2. /// Use [`f32::MANTISSA_DIGITS`](../../std/primitive.f32.html#associatedconstant.MANTISSA_DIGITS) instead. +/// +/// # Examples +/// +/// ```rust +/// // deprecated way +/// let d = std::f32::MANTISSA_DIGITS; +/// +/// // intended way +/// let d = f32::MANTISSA_DIGITS; +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub const MANTISSA_DIGITS: u32 = f32::MANTISSA_DIGITS; + /// Approximate number of significant digits in base 10. /// Use [`f32::DIGITS`](../../std/primitive.f32.html#associatedconstant.DIGITS) instead. +/// +/// # Examples +/// +/// ```rust +/// // deprecated way +/// let d = std::f32::DIGITS; +/// +/// // intended way +/// let d = f32::DIGITS; +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub const DIGITS: u32 = f32::DIGITS; @@ -36,50 +67,166 @@ pub const DIGITS: u32 = f32::DIGITS; /// This is the difference between `1.0` and the next larger representable number. /// /// [Machine epsilon]: https://en.wikipedia.org/wiki/Machine_epsilon +/// +/// # Examples +/// +/// ```rust +/// // deprecated way +/// let e = std::f32::EPSILON; +/// +/// // intended way +/// let e = f32::EPSILON; +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub const EPSILON: f32 = f32::EPSILON; /// Smallest finite `f32` value. /// Use [`f32::MIN`](../../std/primitive.f32.html#associatedconstant.MIN) instead. +/// +/// # Examples +/// +/// ```rust +/// // deprecated way +/// let min = std::f32::MIN; +/// +/// // intended way +/// let min = f32::MIN; +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub const MIN: f32 = f32::MIN; + /// Smallest positive normal `f32` value. /// Use [`f32::MIN_POSITIVE`](../../std/primitive.f32.html#associatedconstant.MIN_POSITIVE) instead. +/// +/// # Examples +/// +/// ```rust +/// // deprecated way +/// let min = std::f32::MIN_POSITIVE; +/// +/// // intended way +/// let min = f32::MIN_POSITIVE; +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub const MIN_POSITIVE: f32 = f32::MIN_POSITIVE; + /// Largest finite `f32` value. /// Use [`f32::MAX`](../../std/primitive.f32.html#associatedconstant.MAX) instead. +/// +/// # Examples +/// +/// ```rust +/// // deprecated way +/// let max = std::f32::MAX; +/// +/// // intended way +/// let max = f32::MAX; +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub const MAX: f32 = f32::MAX; /// One greater than the minimum possible normal power of 2 exponent. /// Use [`f32::MIN_EXP`](../../std/primitive.f32.html#associatedconstant.MIN_EXP) instead. +/// +/// # Examples +/// +/// ```rust +/// // deprecated way +/// let min = std::f32::MIN_EXP; +/// +/// // intended way +/// let min = f32::MIN_EXP; +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub const MIN_EXP: i32 = f32::MIN_EXP; + /// Maximum possible power of 2 exponent. /// Use [`f32::MAX_EXP`](../../std/primitive.f32.html#associatedconstant.MAX_EXP) instead. +/// +/// # Examples +/// +/// ```rust +/// // deprecated way +/// let max = std::f32::MAX_EXP; +/// +/// // intended way +/// let max = f32::MAX_EXP; +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub const MAX_EXP: i32 = f32::MAX_EXP; /// Minimum possible normal power of 10 exponent. /// Use [`f32::MIN_10_EXP`](../../std/primitive.f32.html#associatedconstant.MIN_10_EXP) instead. +/// +/// # Examples +/// +/// ```rust +/// // deprecated way +/// let min = std::f32::MIN_10_EXP; +/// +/// // intended way +/// let min = f32::MIN_10_EXP; +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub const MIN_10_EXP: i32 = f32::MIN_10_EXP; + /// Maximum possible power of 10 exponent. /// Use [`f32::MAX_10_EXP`](../../std/primitive.f32.html#associatedconstant.MAX_10_EXP) instead. +/// +/// # Examples +/// +/// ```rust +/// // deprecated way +/// let max = std::f32::MAX_10_EXP; +/// +/// // intended way +/// let max = f32::MAX_10_EXP; +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub const MAX_10_EXP: i32 = f32::MAX_10_EXP; /// Not a Number (NaN). /// Use [`f32::NAN`](../../std/primitive.f32.html#associatedconstant.NAN) instead. +/// +/// # Examples +/// +/// ```rust +/// // deprecated way +/// let nan = std::f32::NAN; +/// +/// // intended way +/// let nan = f32::NAN; +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub const NAN: f32 = f32::NAN; + /// Infinity (∞). /// Use [`f32::INFINITY`](../../std/primitive.f32.html#associatedconstant.INFINITY) instead. +/// +/// # Examples +/// +/// ```rust +/// // deprecated way +/// let inf = std::f32::INFINITY; +/// +/// // intended way +/// let inf = f32::INFINITY; +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub const INFINITY: f32 = f32::INFINITY; + /// Negative infinity (−∞). /// Use [`f32::NEG_INFINITY`](../../std/primitive.f32.html#associatedconstant.NEG_INFINITY) instead. +/// +/// # Examples +/// +/// ```rust +/// // deprecated way +/// let ninf = std::f32::NEG_INFINITY; +/// +/// // intended way +/// let ninf = f32::NEG_INFINITY; +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub const NEG_INFINITY: f32 = f32::NEG_INFINITY; diff --git a/src/libcore/num/f64.rs b/src/libcore/num/f64.rs index b38fd804ee8..df45e588369 100644 --- a/src/libcore/num/f64.rs +++ b/src/libcore/num/f64.rs @@ -18,15 +18,46 @@ use crate::num::FpCategory; /// The radix or base of the internal representation of `f64`. /// Use [`f64::RADIX`](../../std/primitive.f64.html#associatedconstant.RADIX) instead. +/// +/// # Examples +/// +/// ```rust +/// // deprecated way +/// let r = std::f64::RADIX; +/// +/// // intended way +/// let r = f64::RADIX; +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub const RADIX: u32 = f64::RADIX; /// Number of significant digits in base 2. /// Use [`f64::MANTISSA_DIGITS`](../../std/primitive.f64.html#associatedconstant.MANTISSA_DIGITS) instead. +/// +/// # Examples +/// +/// ```rust +/// // deprecated way +/// let d = std::f64::MANTISSA_DIGITS; +/// +/// // intended way +/// let d = f64::MANTISSA_DIGITS; +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub const MANTISSA_DIGITS: u32 = f64::MANTISSA_DIGITS; + /// Approximate number of significant digits in base 10. /// Use [`f64::DIGITS`](../../std/primitive.f64.html#associatedconstant.DIGITS) instead. +/// +/// # Examples +/// +/// ```rust +/// // deprecated way +/// let d = std::f64::DIGITS; +/// +/// // intended way +/// let d = f64::DIGITS; +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub const DIGITS: u32 = f64::DIGITS; @@ -36,50 +67,166 @@ pub const DIGITS: u32 = f64::DIGITS; /// This is the difference between `1.0` and the next larger representable number. /// /// [Machine epsilon]: https://en.wikipedia.org/wiki/Machine_epsilon +/// +/// # Examples +/// +/// ```rust +/// // deprecated way +/// let e = std::f64::EPSILON; +/// +/// // intended way +/// let e = f64::EPSILON; +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub const EPSILON: f64 = f64::EPSILON; /// Smallest finite `f64` value. /// Use [`f64::MIN`](../../std/primitive.f64.html#associatedconstant.MIN) instead. +/// +/// # Examples +/// +/// ```rust +/// // deprecated way +/// let min = std::f64::MIN; +/// +/// // intended way +/// let min = f64::MIN; +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub const MIN: f64 = f64::MIN; + /// Smallest positive normal `f64` value. /// Use [`f64::MIN_POSITIVE`](../../std/primitive.f64.html#associatedconstant.MIN_POSITIVE) instead. +/// +/// # Examples +/// +/// ```rust +/// // deprecated way +/// let min = std::f64::MIN_POSITIVE; +/// +/// // intended way +/// let min = f64::MIN_POSITIVE; +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub const MIN_POSITIVE: f64 = f64::MIN_POSITIVE; + /// Largest finite `f64` value. /// Use [`f64::MAX`](../../std/primitive.f64.html#associatedconstant.MAX) instead. +/// +/// # Examples +/// +/// ```rust +/// // deprecated way +/// let max = std::f64::MAX; +/// +/// // intended way +/// let max = f64::MAX; +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub const MAX: f64 = f64::MAX; /// One greater than the minimum possible normal power of 2 exponent. /// Use [`f64::MIN_EXP`](../../std/primitive.f64.html#associatedconstant.MIN_EXP) instead. +/// +/// # Examples +/// +/// ```rust +/// // deprecated way +/// let min = std::f64::MIN_EXP; +/// +/// // intended way +/// let min = f64::MIN_EXP; +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub const MIN_EXP: i32 = f64::MIN_EXP; + /// Maximum possible power of 2 exponent. /// Use [`f64::MAX_EXP`](../../std/primitive.f64.html#associatedconstant.MAX_EXP) instead. +/// +/// # Examples +/// +/// ```rust +/// // deprecated way +/// let max = std::f64::MAX_EXP; +/// +/// // intended way +/// let max = f64::MAX_EXP; +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub const MAX_EXP: i32 = f64::MAX_EXP; /// Minimum possible normal power of 10 exponent. /// Use [`f64::MIN_10_EXP`](../../std/primitive.f64.html#associatedconstant.MIN_10_EXP) instead. +/// +/// # Examples +/// +/// ```rust +/// // deprecated way +/// let min = std::f64::MIN_10_EXP; +/// +/// // intended way +/// let min = f64::MIN_10_EXP; +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub const MIN_10_EXP: i32 = f64::MIN_10_EXP; + /// Maximum possible power of 10 exponent. /// Use [`f64::MAX_10_EXP`](../../std/primitive.f64.html#associatedconstant.MAX_10_EXP) instead. +/// +/// # Examples +/// +/// ```rust +/// // deprecated way +/// let max = std::f64::MAX_10_EXP; +/// +/// // intended way +/// let max = f64::MAX_10_EXP; +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub const MAX_10_EXP: i32 = f64::MAX_10_EXP; /// Not a Number (NaN). /// Use [`f64::NAN`](../../std/primitive.f64.html#associatedconstant.NAN) instead. +/// +/// # Examples +/// +/// ```rust +/// // deprecated way +/// let nan = std::f64::NAN; +/// +/// // intended way +/// let nan = f64::NAN; +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub const NAN: f64 = f64::NAN; + /// Infinity (∞). /// Use [`f64::INFINITY`](../../std/primitive.f64.html#associatedconstant.INFINITY) instead. +/// +/// # Examples +/// +/// ```rust +/// // deprecated way +/// let inf = std::f64::INFINITY; +/// +/// // intended way +/// let inf = f64::INFINITY; +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub const INFINITY: f64 = f64::INFINITY; + /// Negative infinity (−∞). /// Use [`f64::NEG_INFINITY`](../../std/primitive.f64.html#associatedconstant.NEG_INFINITY) instead. +/// +/// # Examples +/// +/// ```rust +/// // deprecated way +/// let ninf = std::f64::NEG_INFINITY; +/// +/// // intended way +/// let ninf = f64::NEG_INFINITY; +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub const NEG_INFINITY: f64 = f64::NEG_INFINITY; @@ -474,11 +621,11 @@ impl f64 { /// assuming that the value is finite and fits in that type. /// /// ``` - /// let value = 4.6_f32; + /// let value = 4.6_f64; /// let rounded = unsafe { value.to_int_unchecked::<u16>() }; /// assert_eq!(rounded, 4); /// - /// let value = -128.9_f32; + /// let value = -128.9_f64; /// let rounded = unsafe { value.to_int_unchecked::<i8>() }; /// assert_eq!(rounded, i8::MIN); /// ``` diff --git a/src/libcore/num/int_macros.rs b/src/libcore/num/int_macros.rs index 5035445ba93..ffd30b03f21 100644 --- a/src/libcore/num/int_macros.rs +++ b/src/libcore/num/int_macros.rs @@ -12,14 +12,36 @@ macro_rules! int_module { ($T:ident, #[$attr:meta]) => ( doc_comment! { concat!("The smallest value that can be represented by this integer type. -Use [`", stringify!($T), "::MIN", "`](../../std/primitive.", stringify!($T), ".html#associatedconstant.MIN) instead."), +Use [`", stringify!($T), "::MIN", "`](../../std/primitive.", stringify!($T), ".html#associatedconstant.MIN) instead. + +# Examples + +```rust +// deprecated way +let min = std::", stringify!($T), "::MIN; + +// intended way +let min = ", stringify!($T), "::MIN; +``` +"), #[$attr] pub const MIN: $T = $T::MIN; } doc_comment! { concat!("The largest value that can be represented by this integer type. -Use [`", stringify!($T), "::MAX", "`](../../std/primitive.", stringify!($T), ".html#associatedconstant.MAX) instead."), +Use [`", stringify!($T), "::MAX", "`](../../std/primitive.", stringify!($T), ".html#associatedconstant.MAX) instead. + +# Examples + +```rust +// deprecated way +let max = std::", stringify!($T), "::MAX; + +// intended way +let max = ", stringify!($T), "::MAX; +``` +"), #[$attr] pub const MAX: $T = $T::MAX; } diff --git a/src/libcore/ops/drop.rs b/src/libcore/ops/drop.rs index 5233b475c46..06cfc363636 100644 --- a/src/libcore/ops/drop.rs +++ b/src/libcore/ops/drop.rs @@ -1,85 +1,139 @@ -/// Used to run some code when a value goes out of scope. -/// This is sometimes called a 'destructor'. +/// Custom code within the destructor. /// -/// When a value goes out of scope, it will have its `drop` method called if -/// its type implements `Drop`. Then, any fields the value contains will also -/// be dropped recursively. +/// When a value is no longer needed, Rust will run a "destructor" on that value. +/// The most common way that a value is no longer needed is when it goes out of +/// scope. Destructors may still run in other circumstances, but we're going to +/// focus on scope for the examples here. To learn about some of those other cases, +/// please see [the reference] section on destructors. /// -/// Because of this recursive dropping, you do not need to implement this trait -/// unless your type needs its own destructor logic. +/// [the reference]: https://doc.rust-lang.org/reference/destructors.html /// -/// Refer to [the chapter on `Drop` in *The Rust Programming Language*][book] -/// for some more elaboration. +/// This destructor consists of two components: +/// - A call to `Drop::drop` for that value, if this special `Drop` trait is implemented for its type. +/// - The automatically generated "drop glue" which recursively calls the destructors +/// of the all fields of this value. /// -/// [book]: ../../book/ch15-03-drop.html +/// As Rust automatically calls the destructors of all contained fields, +/// you don't have to implement `Drop` in most cases. But there are some cases where +/// it is useful, for example for types which directly manage a resource. +/// That resource may be memory, it may be a file descriptor, it may be a network socket. +/// Once a value of that type is no longer going to be used, it should "clean up" its +/// resource by freeing the memory or closing the file or socket. This is +/// the job of a destructor, and therefore the job of `Drop::drop`. /// -/// # Examples +/// ## Examples /// -/// ## Implementing `Drop` +/// To see destructors in action, let's take a look at the following program: /// -/// The `drop` method is called when `_x` goes out of scope, and therefore -/// `main` prints `Dropping!`. -/// -/// ``` +/// ```rust /// struct HasDrop; /// /// impl Drop for HasDrop { /// fn drop(&mut self) { -/// println!("Dropping!"); +/// println!("Dropping HasDrop!"); +/// } +/// } +/// +/// struct HasTwoDrops { +/// one: HasDrop, +/// two: HasDrop, +/// } +/// +/// impl Drop for HasTwoDrops { +/// fn drop(&mut self) { +/// println!("Dropping HasTwoDrops!"); /// } /// } /// /// fn main() { -/// let _x = HasDrop; +/// let _x = HasTwoDrops { one: HasDrop, two: HasDrop }; +/// println!("Running!"); /// } /// ``` /// -/// ## Dropping is done recursively +/// Rust will first call `Drop::drop` for `_x` and then for both `_x.one` and `_x.two`, +/// meaning that running this will print /// -/// When `outer` goes out of scope, the `drop` method will be called first for -/// `Outer`, then for `Inner`. Therefore, `main` prints `Dropping Outer!` and -/// then `Dropping Inner!`. +/// ```text +/// Running! +/// Dropping HasTwoDrops! +/// Dropping HasDrop! +/// Dropping HasDrop! +/// ``` +/// +/// Even if we remove the implementation of `Drop` for `HasTwoDrop`, the destructors of its fields are still called. +/// This would result in /// +/// ```test +/// Running! +/// Dropping HasDrop! +/// Dropping HasDrop! /// ``` -/// struct Inner; -/// struct Outer(Inner); /// -/// impl Drop for Inner { +/// ## You cannot call `Drop::drop` yourself +/// +/// Because `Drop::drop` is used to clean up a value, it may be dangerous to use this value after +/// the method has been called. As `Drop::drop` does not take ownership of its input, +/// Rust prevents misuse by not allowing you to call `Drop::drop` directly. +/// +/// In other words, if you tried to explicitly call `Drop::drop` in the above example, you'd get a compiler error. +/// +/// If you'd like explicitly call the destructor of a value, [`std::mem::drop`] can be used instead. +/// +/// [`std::mem::drop`]: ../../std/mem/fn.drop.html +/// +/// ## Drop order +/// +/// Which of our two `HasDrop` drops first, though? For structs, it's the same +/// order that they're declared: first `one`, then `two`. If you'd like to try +/// this yourself, you can modify `HasDrop` above to contain some data, like an +/// integer, and then use it in the `println!` inside of `Drop`. This behavior is +/// guaranteed by the language. +/// +/// Unlike for structs, local variables are dropped in reverse order: +/// +/// ```rust +/// struct Foo; +/// +/// impl Drop for Foo { /// fn drop(&mut self) { -/// println!("Dropping Inner!"); +/// println!("Dropping Foo!") /// } /// } /// -/// impl Drop for Outer { +/// struct Bar; +/// +/// impl Drop for Bar { /// fn drop(&mut self) { -/// println!("Dropping Outer!"); +/// println!("Dropping Bar!") /// } /// } /// /// fn main() { -/// let _x = Outer(Inner); +/// let _foo = Foo; +/// let _bar = Bar; /// } /// ``` /// -/// ## Variables are dropped in reverse order of declaration -/// -/// `_first` is declared first and `_second` is declared second, so `main` will -/// print `Declared second!` and then `Declared first!`. +/// This will print /// +/// ```text +/// Dropping Bar! +/// Dropping Foo! /// ``` -/// struct PrintOnDrop(&'static str); /// -/// impl Drop for PrintOnDrop { -/// fn drop(&mut self) { -/// println!("{}", self.0); -/// } -/// } +/// Please see [the reference] for the full rules. /// -/// fn main() { -/// let _first = PrintOnDrop("Declared first!"); -/// let _second = PrintOnDrop("Declared second!"); -/// } -/// ``` +/// [the reference]: https://doc.rust-lang.org/reference/destructors.html +/// +/// ## `Copy` and `Drop` are exclusive +/// +/// You cannot implement both [`Copy`] and `Drop` on the same type. Types that +/// are `Copy` get implicitly duplicated by the compiler, making it very +/// hard to predict when, and how often destructors will be executed. As such, +/// these types cannot have destructors. +/// +/// [`Copy`]: ../../std/marker/trait.Copy.html #[lang = "drop"] #[stable(feature = "rust1", since = "1.0.0")] pub trait Drop { diff --git a/src/librustc_ast/lib.rs b/src/librustc_ast/lib.rs index f81622d0914..cb3118cba23 100644 --- a/src/librustc_ast/lib.rs +++ b/src/librustc_ast/lib.rs @@ -19,6 +19,10 @@ #![feature(unicode_internals)] #![recursion_limit = "256"] +// FIXME(#56935): Work around ICEs during cross-compilation. +#[allow(unused)] +extern crate rustc_macros; + #[macro_export] macro_rules! unwrap_or { ($opt:expr, $default:expr) => { diff --git a/src/librustc_ast_lowering/expr.rs b/src/librustc_ast_lowering/expr.rs index cbe192d35e5..251faf6af00 100644 --- a/src/librustc_ast_lowering/expr.rs +++ b/src/librustc_ast_lowering/expr.rs @@ -3,6 +3,7 @@ use super::{ImplTraitContext, LoweringContext, ParamMode, ParenthesizedGenericAr use rustc_ast::ast::*; use rustc_ast::attr; use rustc_ast::ptr::P as AstP; +use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_data_structures::thin_vec::ThinVec; use rustc_errors::struct_span_err; use rustc_hir as hir; @@ -20,192 +21,206 @@ impl<'hir> LoweringContext<'_, 'hir> { } pub(super) fn lower_expr_mut(&mut self, e: &Expr) -> hir::Expr<'hir> { - let kind = match e.kind { - ExprKind::Box(ref inner) => hir::ExprKind::Box(self.lower_expr(inner)), - ExprKind::Array(ref exprs) => hir::ExprKind::Array(self.lower_exprs(exprs)), - ExprKind::Repeat(ref expr, ref count) => { - let expr = self.lower_expr(expr); - let count = self.lower_anon_const(count); - hir::ExprKind::Repeat(expr, count) - } - ExprKind::Tup(ref elts) => hir::ExprKind::Tup(self.lower_exprs(elts)), - ExprKind::Call(ref f, ref args) => { - let f = self.lower_expr(f); - hir::ExprKind::Call(f, self.lower_exprs(args)) - } - ExprKind::MethodCall(ref seg, ref args) => { - let hir_seg = self.arena.alloc(self.lower_path_segment( - e.span, - seg, - ParamMode::Optional, - 0, - ParenthesizedGenericArgs::Err, - ImplTraitContext::disallowed(), - None, - )); - let args = self.lower_exprs(args); - hir::ExprKind::MethodCall(hir_seg, seg.ident.span, args) - } - ExprKind::Binary(binop, ref lhs, ref rhs) => { - let binop = self.lower_binop(binop); - let lhs = self.lower_expr(lhs); - let rhs = self.lower_expr(rhs); - hir::ExprKind::Binary(binop, lhs, rhs) - } - ExprKind::Unary(op, ref ohs) => { - let op = self.lower_unop(op); - let ohs = self.lower_expr(ohs); - hir::ExprKind::Unary(op, ohs) - } - ExprKind::Lit(ref l) => hir::ExprKind::Lit(respan(l.span, l.kind.clone())), - ExprKind::Cast(ref expr, ref ty) => { - let expr = self.lower_expr(expr); - let ty = self.lower_ty(ty, ImplTraitContext::disallowed()); - hir::ExprKind::Cast(expr, ty) - } - ExprKind::Type(ref expr, ref ty) => { - let expr = self.lower_expr(expr); - let ty = self.lower_ty(ty, ImplTraitContext::disallowed()); - hir::ExprKind::Type(expr, ty) - } - ExprKind::AddrOf(k, m, ref ohs) => { - let ohs = self.lower_expr(ohs); - hir::ExprKind::AddrOf(k, m, ohs) - } - ExprKind::Let(ref pat, ref scrutinee) => self.lower_expr_let(e.span, pat, scrutinee), - ExprKind::If(ref cond, ref then, ref else_opt) => { - self.lower_expr_if(e.span, cond, then, else_opt.as_deref()) - } - ExprKind::While(ref cond, ref body, opt_label) => self.with_loop_scope(e.id, |this| { - this.lower_expr_while_in_loop_scope(e.span, cond, body, opt_label) - }), - ExprKind::Loop(ref body, opt_label) => self.with_loop_scope(e.id, |this| { - hir::ExprKind::Loop(this.lower_block(body, false), opt_label, hir::LoopSource::Loop) - }), - ExprKind::TryBlock(ref body) => self.lower_expr_try_block(body), - ExprKind::Match(ref expr, ref arms) => hir::ExprKind::Match( - self.lower_expr(expr), - self.arena.alloc_from_iter(arms.iter().map(|x| self.lower_arm(x))), - hir::MatchSource::Normal, - ), - ExprKind::Async(capture_clause, closure_node_id, ref block) => self.make_async_expr( - capture_clause, - closure_node_id, - None, - block.span, - hir::AsyncGeneratorKind::Block, - |this| this.with_new_scopes(|this| this.lower_block_expr(block)), - ), - ExprKind::Await(ref expr) => self.lower_expr_await(e.span, expr), - ExprKind::Closure( - capture_clause, - asyncness, - movability, - ref decl, - ref body, - fn_decl_span, - ) => { - if let Async::Yes { closure_id, .. } = asyncness { - self.lower_expr_async_closure( - capture_clause, - closure_id, - decl, - body, - fn_decl_span, + ensure_sufficient_stack(|| { + let kind = match e.kind { + ExprKind::Box(ref inner) => hir::ExprKind::Box(self.lower_expr(inner)), + ExprKind::Array(ref exprs) => hir::ExprKind::Array(self.lower_exprs(exprs)), + ExprKind::Repeat(ref expr, ref count) => { + let expr = self.lower_expr(expr); + let count = self.lower_anon_const(count); + hir::ExprKind::Repeat(expr, count) + } + ExprKind::Tup(ref elts) => hir::ExprKind::Tup(self.lower_exprs(elts)), + ExprKind::Call(ref f, ref args) => { + let f = self.lower_expr(f); + hir::ExprKind::Call(f, self.lower_exprs(args)) + } + ExprKind::MethodCall(ref seg, ref args) => { + let hir_seg = self.arena.alloc(self.lower_path_segment( + e.span, + seg, + ParamMode::Optional, + 0, + ParenthesizedGenericArgs::Err, + ImplTraitContext::disallowed(), + None, + )); + let args = self.lower_exprs(args); + hir::ExprKind::MethodCall(hir_seg, seg.ident.span, args) + } + ExprKind::Binary(binop, ref lhs, ref rhs) => { + let binop = self.lower_binop(binop); + let lhs = self.lower_expr(lhs); + let rhs = self.lower_expr(rhs); + hir::ExprKind::Binary(binop, lhs, rhs) + } + ExprKind::Unary(op, ref ohs) => { + let op = self.lower_unop(op); + let ohs = self.lower_expr(ohs); + hir::ExprKind::Unary(op, ohs) + } + ExprKind::Lit(ref l) => hir::ExprKind::Lit(respan(l.span, l.kind.clone())), + ExprKind::Cast(ref expr, ref ty) => { + let expr = self.lower_expr(expr); + let ty = self.lower_ty(ty, ImplTraitContext::disallowed()); + hir::ExprKind::Cast(expr, ty) + } + ExprKind::Type(ref expr, ref ty) => { + let expr = self.lower_expr(expr); + let ty = self.lower_ty(ty, ImplTraitContext::disallowed()); + hir::ExprKind::Type(expr, ty) + } + ExprKind::AddrOf(k, m, ref ohs) => { + let ohs = self.lower_expr(ohs); + hir::ExprKind::AddrOf(k, m, ohs) + } + ExprKind::Let(ref pat, ref scrutinee) => { + self.lower_expr_let(e.span, pat, scrutinee) + } + ExprKind::If(ref cond, ref then, ref else_opt) => { + self.lower_expr_if(e.span, cond, then, else_opt.as_deref()) + } + ExprKind::While(ref cond, ref body, opt_label) => self + .with_loop_scope(e.id, |this| { + this.lower_expr_while_in_loop_scope(e.span, cond, body, opt_label) + }), + ExprKind::Loop(ref body, opt_label) => self.with_loop_scope(e.id, |this| { + hir::ExprKind::Loop( + this.lower_block(body, false), + opt_label, + hir::LoopSource::Loop, ) - } else { - self.lower_expr_closure(capture_clause, movability, decl, body, fn_decl_span) + }), + ExprKind::TryBlock(ref body) => self.lower_expr_try_block(body), + ExprKind::Match(ref expr, ref arms) => hir::ExprKind::Match( + self.lower_expr(expr), + self.arena.alloc_from_iter(arms.iter().map(|x| self.lower_arm(x))), + hir::MatchSource::Normal, + ), + ExprKind::Async(capture_clause, closure_node_id, ref block) => self + .make_async_expr( + capture_clause, + closure_node_id, + None, + block.span, + hir::AsyncGeneratorKind::Block, + |this| this.with_new_scopes(|this| this.lower_block_expr(block)), + ), + ExprKind::Await(ref expr) => self.lower_expr_await(e.span, expr), + ExprKind::Closure( + capture_clause, + asyncness, + movability, + ref decl, + ref body, + fn_decl_span, + ) => { + if let Async::Yes { closure_id, .. } = asyncness { + self.lower_expr_async_closure( + capture_clause, + closure_id, + decl, + body, + fn_decl_span, + ) + } else { + self.lower_expr_closure( + capture_clause, + movability, + decl, + body, + fn_decl_span, + ) + } } - } - ExprKind::Block(ref blk, opt_label) => { - hir::ExprKind::Block(self.lower_block(blk, opt_label.is_some()), opt_label) - } - ExprKind::Assign(ref el, ref er, span) => { - hir::ExprKind::Assign(self.lower_expr(el), self.lower_expr(er), span) - } - ExprKind::AssignOp(op, ref el, ref er) => hir::ExprKind::AssignOp( - self.lower_binop(op), - self.lower_expr(el), - self.lower_expr(er), - ), - ExprKind::Field(ref el, ident) => hir::ExprKind::Field(self.lower_expr(el), ident), - ExprKind::Index(ref el, ref er) => { - hir::ExprKind::Index(self.lower_expr(el), self.lower_expr(er)) - } - ExprKind::Range(Some(ref e1), Some(ref e2), RangeLimits::Closed) => { - self.lower_expr_range_closed(e.span, e1, e2) - } - ExprKind::Range(ref e1, ref e2, lims) => { - self.lower_expr_range(e.span, e1.as_deref(), e2.as_deref(), lims) - } - ExprKind::Path(ref qself, ref path) => { - let qpath = self.lower_qpath( - e.id, - qself, - path, - ParamMode::Optional, - ImplTraitContext::disallowed(), - ); - hir::ExprKind::Path(qpath) - } - ExprKind::Break(opt_label, ref opt_expr) => { - let opt_expr = opt_expr.as_ref().map(|x| self.lower_expr(x)); - hir::ExprKind::Break(self.lower_jump_destination(e.id, opt_label), opt_expr) - } - ExprKind::Continue(opt_label) => { - hir::ExprKind::Continue(self.lower_jump_destination(e.id, opt_label)) - } - ExprKind::Ret(ref e) => { - let e = e.as_ref().map(|x| self.lower_expr(x)); - hir::ExprKind::Ret(e) - } - ExprKind::LlvmInlineAsm(ref asm) => self.lower_expr_asm(asm), - ExprKind::Struct(ref path, ref fields, ref maybe_expr) => { - let maybe_expr = maybe_expr.as_ref().map(|x| self.lower_expr(x)); - hir::ExprKind::Struct( - self.arena.alloc(self.lower_qpath( + ExprKind::Block(ref blk, opt_label) => { + hir::ExprKind::Block(self.lower_block(blk, opt_label.is_some()), opt_label) + } + ExprKind::Assign(ref el, ref er, span) => { + hir::ExprKind::Assign(self.lower_expr(el), self.lower_expr(er), span) + } + ExprKind::AssignOp(op, ref el, ref er) => hir::ExprKind::AssignOp( + self.lower_binop(op), + self.lower_expr(el), + self.lower_expr(er), + ), + ExprKind::Field(ref el, ident) => hir::ExprKind::Field(self.lower_expr(el), ident), + ExprKind::Index(ref el, ref er) => { + hir::ExprKind::Index(self.lower_expr(el), self.lower_expr(er)) + } + ExprKind::Range(Some(ref e1), Some(ref e2), RangeLimits::Closed) => { + self.lower_expr_range_closed(e.span, e1, e2) + } + ExprKind::Range(ref e1, ref e2, lims) => { + self.lower_expr_range(e.span, e1.as_deref(), e2.as_deref(), lims) + } + ExprKind::Path(ref qself, ref path) => { + let qpath = self.lower_qpath( e.id, - &None, + qself, path, ParamMode::Optional, ImplTraitContext::disallowed(), - )), - self.arena.alloc_from_iter(fields.iter().map(|x| self.lower_field(x))), - maybe_expr, - ) - } - ExprKind::Paren(ref ex) => { - let mut ex = self.lower_expr_mut(ex); - // Include parens in span, but only if it is a super-span. - if e.span.contains(ex.span) { - ex.span = e.span; + ); + hir::ExprKind::Path(qpath) + } + ExprKind::Break(opt_label, ref opt_expr) => { + let opt_expr = opt_expr.as_ref().map(|x| self.lower_expr(x)); + hir::ExprKind::Break(self.lower_jump_destination(e.id, opt_label), opt_expr) + } + ExprKind::Continue(opt_label) => { + hir::ExprKind::Continue(self.lower_jump_destination(e.id, opt_label)) + } + ExprKind::Ret(ref e) => { + let e = e.as_ref().map(|x| self.lower_expr(x)); + hir::ExprKind::Ret(e) + } + ExprKind::LlvmInlineAsm(ref asm) => self.lower_expr_asm(asm), + ExprKind::Struct(ref path, ref fields, ref maybe_expr) => { + let maybe_expr = maybe_expr.as_ref().map(|x| self.lower_expr(x)); + hir::ExprKind::Struct( + self.arena.alloc(self.lower_qpath( + e.id, + &None, + path, + ParamMode::Optional, + ImplTraitContext::disallowed(), + )), + self.arena.alloc_from_iter(fields.iter().map(|x| self.lower_field(x))), + maybe_expr, + ) + } + ExprKind::Yield(ref opt_expr) => self.lower_expr_yield(e.span, opt_expr.as_deref()), + ExprKind::Err => hir::ExprKind::Err, + ExprKind::Try(ref sub_expr) => self.lower_expr_try(e.span, sub_expr), + ExprKind::Paren(ref ex) => { + let mut ex = self.lower_expr_mut(ex); + // Include parens in span, but only if it is a super-span. + if e.span.contains(ex.span) { + ex.span = e.span; + } + // Merge attributes into the inner expression. + let mut attrs = e.attrs.clone(); + attrs.extend::<Vec<_>>(ex.attrs.into()); + ex.attrs = attrs; + return ex; } - // Merge attributes into the inner expression. - let mut attrs = e.attrs.clone(); - attrs.extend::<Vec<_>>(ex.attrs.into()); - ex.attrs = attrs; - return ex; - } - - ExprKind::Yield(ref opt_expr) => self.lower_expr_yield(e.span, opt_expr.as_deref()), - ExprKind::Err => hir::ExprKind::Err, + // Desugar `ExprForLoop` + // from: `[opt_ident]: for <pat> in <head> <body>` + ExprKind::ForLoop(ref pat, ref head, ref body, opt_label) => { + return self.lower_expr_for(e, pat, head, body, opt_label); + } + ExprKind::MacCall(_) => panic!("{:?} shouldn't exist here", e.span), + }; - // Desugar `ExprForLoop` - // from: `[opt_ident]: for <pat> in <head> <body>` - ExprKind::ForLoop(ref pat, ref head, ref body, opt_label) => { - return self.lower_expr_for(e, pat, head, body, opt_label); + hir::Expr { + hir_id: self.lower_node_id(e.id), + kind, + span: e.span, + attrs: e.attrs.iter().map(|a| self.lower_attr(a)).collect::<Vec<_>>().into(), } - ExprKind::Try(ref sub_expr) => self.lower_expr_try(e.span, sub_expr), - ExprKind::MacCall(_) => panic!("Shouldn't exist here"), - }; - - hir::Expr { - hir_id: self.lower_node_id(e.id), - kind, - span: e.span, - attrs: e.attrs.iter().map(|a| self.lower_attr(a)).collect::<Vec<_>>().into(), - } + }) } fn lower_unop(&mut self, u: UnOp) -> hir::UnOp { diff --git a/src/librustc_ast_lowering/pat.rs b/src/librustc_ast_lowering/pat.rs index 28469dc5367..d54ad2036d5 100644 --- a/src/librustc_ast_lowering/pat.rs +++ b/src/librustc_ast_lowering/pat.rs @@ -2,83 +2,89 @@ use super::{ImplTraitContext, LoweringContext, ParamMode}; use rustc_ast::ast::*; use rustc_ast::ptr::P; +use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_hir as hir; use rustc_hir::def::Res; use rustc_span::{source_map::Spanned, Span}; impl<'a, 'hir> LoweringContext<'a, 'hir> { crate fn lower_pat(&mut self, p: &Pat) -> &'hir hir::Pat<'hir> { - let node = match p.kind { - PatKind::Wild => hir::PatKind::Wild, - PatKind::Ident(ref binding_mode, ident, ref sub) => { - let lower_sub = |this: &mut Self| sub.as_ref().map(|s| this.lower_pat(&*s)); - let node = self.lower_pat_ident(p, binding_mode, ident, lower_sub); - node - } - PatKind::Lit(ref e) => hir::PatKind::Lit(self.lower_expr(e)), - PatKind::TupleStruct(ref path, ref pats) => { - let qpath = self.lower_qpath( - p.id, - &None, - path, - ParamMode::Optional, - ImplTraitContext::disallowed(), - ); - let (pats, ddpos) = self.lower_pat_tuple(pats, "tuple struct"); - hir::PatKind::TupleStruct(qpath, pats, ddpos) - } - PatKind::Or(ref pats) => { - hir::PatKind::Or(self.arena.alloc_from_iter(pats.iter().map(|x| self.lower_pat(x)))) - } - PatKind::Path(ref qself, ref path) => { - let qpath = self.lower_qpath( - p.id, - qself, - path, - ParamMode::Optional, - ImplTraitContext::disallowed(), - ); - hir::PatKind::Path(qpath) - } - PatKind::Struct(ref path, ref fields, etc) => { - let qpath = self.lower_qpath( - p.id, - &None, - path, - ParamMode::Optional, - ImplTraitContext::disallowed(), - ); + ensure_sufficient_stack(|| { + let node = match p.kind { + PatKind::Wild => hir::PatKind::Wild, + PatKind::Ident(ref binding_mode, ident, ref sub) => { + let lower_sub = |this: &mut Self| sub.as_ref().map(|s| this.lower_pat(&*s)); + let node = self.lower_pat_ident(p, binding_mode, ident, lower_sub); + node + } + PatKind::Lit(ref e) => hir::PatKind::Lit(self.lower_expr(e)), + PatKind::TupleStruct(ref path, ref pats) => { + let qpath = self.lower_qpath( + p.id, + &None, + path, + ParamMode::Optional, + ImplTraitContext::disallowed(), + ); + let (pats, ddpos) = self.lower_pat_tuple(pats, "tuple struct"); + hir::PatKind::TupleStruct(qpath, pats, ddpos) + } + PatKind::Or(ref pats) => hir::PatKind::Or( + self.arena.alloc_from_iter(pats.iter().map(|x| self.lower_pat(x))), + ), + PatKind::Path(ref qself, ref path) => { + let qpath = self.lower_qpath( + p.id, + qself, + path, + ParamMode::Optional, + ImplTraitContext::disallowed(), + ); + hir::PatKind::Path(qpath) + } + PatKind::Struct(ref path, ref fields, etc) => { + let qpath = self.lower_qpath( + p.id, + &None, + path, + ParamMode::Optional, + ImplTraitContext::disallowed(), + ); - let fs = self.arena.alloc_from_iter(fields.iter().map(|f| hir::FieldPat { - hir_id: self.next_id(), - ident: f.ident, - pat: self.lower_pat(&f.pat), - is_shorthand: f.is_shorthand, - span: f.span, - })); - hir::PatKind::Struct(qpath, fs, etc) - } - PatKind::Tuple(ref pats) => { - let (pats, ddpos) = self.lower_pat_tuple(pats, "tuple"); - hir::PatKind::Tuple(pats, ddpos) - } - PatKind::Box(ref inner) => hir::PatKind::Box(self.lower_pat(inner)), - PatKind::Ref(ref inner, mutbl) => hir::PatKind::Ref(self.lower_pat(inner), mutbl), - PatKind::Range(ref e1, ref e2, Spanned { node: ref end, .. }) => hir::PatKind::Range( - e1.as_deref().map(|e| self.lower_expr(e)), - e2.as_deref().map(|e| self.lower_expr(e)), - self.lower_range_end(end, e2.is_some()), - ), - PatKind::Slice(ref pats) => self.lower_pat_slice(pats), - PatKind::Rest => { - // If we reach here the `..` pattern is not semantically allowed. - self.ban_illegal_rest_pat(p.span) - } - PatKind::Paren(ref inner) => return self.lower_pat(inner), - PatKind::MacCall(_) => panic!("Shouldn't exist here"), - }; + let fs = self.arena.alloc_from_iter(fields.iter().map(|f| hir::FieldPat { + hir_id: self.next_id(), + ident: f.ident, + pat: self.lower_pat(&f.pat), + is_shorthand: f.is_shorthand, + span: f.span, + })); + hir::PatKind::Struct(qpath, fs, etc) + } + PatKind::Tuple(ref pats) => { + let (pats, ddpos) = self.lower_pat_tuple(pats, "tuple"); + hir::PatKind::Tuple(pats, ddpos) + } + PatKind::Box(ref inner) => hir::PatKind::Box(self.lower_pat(inner)), + PatKind::Ref(ref inner, mutbl) => hir::PatKind::Ref(self.lower_pat(inner), mutbl), + PatKind::Range(ref e1, ref e2, Spanned { node: ref end, .. }) => { + hir::PatKind::Range( + e1.as_deref().map(|e| self.lower_expr(e)), + e2.as_deref().map(|e| self.lower_expr(e)), + self.lower_range_end(end, e2.is_some()), + ) + } + PatKind::Slice(ref pats) => self.lower_pat_slice(pats), + PatKind::Rest => { + // If we reach here the `..` pattern is not semantically allowed. + self.ban_illegal_rest_pat(p.span) + } + // FIXME: consider not using recursion to lower this. + PatKind::Paren(ref inner) => return self.lower_pat(inner), + PatKind::MacCall(_) => panic!("{:?} shouldn't exist here", p.span), + }; - self.pat_with_node_id_of(p, node) + self.pat_with_node_id_of(p, node) + }) } fn lower_pat_tuple( diff --git a/src/librustc_ast_passes/ast_validation.rs b/src/librustc_ast_passes/ast_validation.rs index 395fd746085..cc88fbb295c 100644 --- a/src/librustc_ast_passes/ast_validation.rs +++ b/src/librustc_ast_passes/ast_validation.rs @@ -23,6 +23,7 @@ use rustc_session::Session; use rustc_span::symbol::{kw, sym}; use rustc_span::Span; use std::mem; +use std::ops::DerefMut; const MORE_EXTERN: &str = "for more information, visit https://doc.rust-lang.org/std/keyword.extern.html"; @@ -1113,17 +1114,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { for predicate in &generics.where_clause.predicates { if let WherePredicate::EqPredicate(ref predicate) = *predicate { - self.err_handler() - .struct_span_err( - predicate.span, - "equality constraints are not yet supported in `where` clauses", - ) - .span_label(predicate.span, "not supported") - .note( - "see issue #20041 <https://github.com/rust-lang/rust/issues/20041> \ - for more information", - ) - .emit(); + deny_equality_constraints(self, predicate, generics); } } @@ -1300,6 +1291,89 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } } +/// When encountering an equality constraint in a `where` clause, emit an error. If the code seems +/// like it's setting an associated type, provide an appropriate suggestion. +fn deny_equality_constraints( + this: &mut AstValidator<'_>, + predicate: &WhereEqPredicate, + generics: &Generics, +) { + let mut err = this.err_handler().struct_span_err( + predicate.span, + "equality constraints are not yet supported in `where` clauses", + ); + err.span_label(predicate.span, "not supported"); + + // Given `<A as Foo>::Bar = RhsTy`, suggest `A: Foo<Bar = RhsTy>`. + if let TyKind::Path(Some(qself), full_path) = &predicate.lhs_ty.kind { + if let TyKind::Path(None, path) = &qself.ty.kind { + match &path.segments[..] { + [PathSegment { ident, args: None, .. }] => { + for param in &generics.params { + if param.ident == *ident { + let param = ident; + match &full_path.segments[qself.position..] { + [PathSegment { ident, .. }] => { + // Make a new `Path` from `foo::Bar` to `Foo<Bar = RhsTy>`. + let mut assoc_path = full_path.clone(); + // Remove `Bar` from `Foo::Bar`. + assoc_path.segments.pop(); + let len = assoc_path.segments.len() - 1; + // Build `<Bar = RhsTy>`. + let arg = AngleBracketedArg::Constraint(AssocTyConstraint { + id: rustc_ast::node_id::DUMMY_NODE_ID, + ident: *ident, + kind: AssocTyConstraintKind::Equality { + ty: predicate.rhs_ty.clone(), + }, + span: ident.span, + }); + // Add `<Bar = RhsTy>` to `Foo`. + match &mut assoc_path.segments[len].args { + Some(args) => match args.deref_mut() { + GenericArgs::Parenthesized(_) => continue, + GenericArgs::AngleBracketed(args) => { + args.args.push(arg); + } + }, + empty_args => { + *empty_args = AngleBracketedArgs { + span: ident.span, + args: vec![arg], + } + .into(); + } + } + err.span_suggestion_verbose( + predicate.span, + &format!( + "if `{}` is an associated type you're trying to set, \ + use the associated type binding syntax", + ident + ), + format!( + "{}: {}", + param, + pprust::path_to_string(&assoc_path) + ), + Applicability::MaybeIncorrect, + ); + } + _ => {} + }; + } + } + } + _ => {} + } + } + } + err.note( + "see issue #20041 <https://github.com/rust-lang/rust/issues/20041> for more information", + ); + err.emit(); +} + pub fn check_crate(session: &Session, krate: &Crate, lints: &mut LintBuffer) -> bool { let mut validator = AstValidator { session, diff --git a/src/librustc_attr/build.rs b/src/librustc_attr/build.rs index d230ba91039..863f2b7337b 100644 --- a/src/librustc_attr/build.rs +++ b/src/librustc_attr/build.rs @@ -1,4 +1,5 @@ fn main() { println!("cargo:rerun-if-changed=build.rs"); - println!("cargo:rerun-if-env-changed=CFG_VERSION"); + println!("cargo:rerun-if-env-changed=CFG_RELEASE"); + println!("cargo:rerun-if-env-changed=CFG_RELEASE_CHANNEL"); } diff --git a/src/librustc_attr/builtin.rs b/src/librustc_attr/builtin.rs index ce38e3f5f4e..a592bbc2bf9 100644 --- a/src/librustc_attr/builtin.rs +++ b/src/librustc_attr/builtin.rs @@ -652,9 +652,12 @@ pub fn eval_condition( return false; } }; - let version = Version::parse(env!("CFG_VERSION")).unwrap(); + let channel = env!("CFG_RELEASE_CHANNEL"); + let nightly = channel == "nightly" || channel == "dev"; + let rustc_version = Version::parse(env!("CFG_RELEASE")).unwrap(); - version >= min_version + // See https://github.com/rust-lang/rust/issues/64796#issuecomment-625474439 for details + if nightly { rustc_version > min_version } else { rustc_version >= min_version } } ast::MetaItemKind::List(ref mis) => { for mi in mis.iter() { diff --git a/src/librustc_attr/lib.rs b/src/librustc_attr/lib.rs index 66c4495c5af..5754bb48d24 100644 --- a/src/librustc_attr/lib.rs +++ b/src/librustc_attr/lib.rs @@ -6,6 +6,10 @@ #![feature(or_patterns)] +// FIXME(#56935): Work around ICEs during cross-compilation. +#[allow(unused)] +extern crate rustc_macros; + mod builtin; pub use builtin::*; diff --git a/src/librustc_builtin_macros/deriving/debug.rs b/src/librustc_builtin_macros/deriving/debug.rs index 71f6eb44858..cea7e8176b6 100644 --- a/src/librustc_builtin_macros/deriving/debug.rs +++ b/src/librustc_builtin_macros/deriving/debug.rs @@ -88,7 +88,7 @@ fn show_substructure(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_> // Use `let _ = expr;` to avoid triggering the // unused_results lint. - stmts.push(stmt_let_undescore(cx, span, expr)); + stmts.push(stmt_let_underscore(cx, span, expr)); } } ast::VariantData::Struct(..) => { @@ -112,7 +112,7 @@ fn show_substructure(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_> Ident::new(sym::field, span), vec![name, field], ); - stmts.push(stmt_let_undescore(cx, span, expr)); + stmts.push(stmt_let_underscore(cx, span, expr)); } } } @@ -124,7 +124,7 @@ fn show_substructure(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_> cx.expr_block(block) } -fn stmt_let_undescore(cx: &mut ExtCtxt<'_>, sp: Span, expr: P<ast::Expr>) -> ast::Stmt { +fn stmt_let_underscore(cx: &mut ExtCtxt<'_>, sp: Span, expr: P<ast::Expr>) -> ast::Stmt { let local = P(ast::Local { pat: cx.pat_wild(sp), ty: None, diff --git a/src/librustc_builtin_macros/test_harness.rs b/src/librustc_builtin_macros/test_harness.rs index fa5993471c4..aca1c69dfd5 100644 --- a/src/librustc_builtin_macros/test_harness.rs +++ b/src/librustc_builtin_macros/test_harness.rs @@ -255,8 +255,8 @@ fn generate_test_harness( /// /// The expansion here can be controlled by two attributes: /// -/// `reexport_test_harness_main` provides a different name for the `main` -/// function and `test_runner` provides a path that replaces +/// [`TestCtxt::reexport_test_harness_main`] provides a different name for the `main` +/// function and [`TestCtxt::test_runner`] provides a path that replaces /// `test::test_main_static`. fn mk_main(cx: &mut TestCtxt<'_>) -> P<ast::Item> { let sp = cx.def_site; diff --git a/src/librustc_codegen_llvm/allocator.rs b/src/librustc_codegen_llvm/allocator.rs index a78546571e2..bc1d9e1818c 100644 --- a/src/librustc_codegen_llvm/allocator.rs +++ b/src/librustc_codegen_llvm/allocator.rs @@ -54,7 +54,7 @@ pub(crate) unsafe fn codegen(tcx: TyCtxt<'_>, mods: &mut ModuleLlvm, kind: Alloc if tcx.sess.target.target.options.default_hidden_visibility { llvm::LLVMRustSetVisibility(llfn, llvm::Visibility::Hidden); } - if tcx.sess.target.target.options.requires_uwtable { + if tcx.sess.must_emit_unwind_tables() { attributes::emit_uwtable(llfn, true); } diff --git a/src/librustc_codegen_llvm/attributes.rs b/src/librustc_codegen_llvm/attributes.rs index fc357ebb05d..64412843f6d 100644 --- a/src/librustc_codegen_llvm/attributes.rs +++ b/src/librustc_codegen_llvm/attributes.rs @@ -13,7 +13,6 @@ use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, TyCtxt}; use rustc_session::config::{OptLevel, Sanitizer}; use rustc_session::Session; -use rustc_target::spec::PanicStrategy; use crate::attributes; use crate::llvm::AttributePlace::Function; @@ -271,9 +270,7 @@ pub fn from_fn_attrs(cx: &CodegenCx<'ll, 'tcx>, llfn: &'ll Value, instance: ty:: // // You can also find more info on why Windows is whitelisted here in: // https://bugzilla.mozilla.org/show_bug.cgi?id=1302078 - if cx.sess().panic_strategy() == PanicStrategy::Unwind - || cx.sess().target.target.options.requires_uwtable - { + if cx.sess().must_emit_unwind_tables() { attributes::emit_uwtable(llfn, true); } diff --git a/src/librustc_codegen_llvm/back/write.rs b/src/librustc_codegen_llvm/back/write.rs index 6d175fda45f..e261ac65446 100644 --- a/src/librustc_codegen_llvm/back/write.rs +++ b/src/librustc_codegen_llvm/back/write.rs @@ -651,10 +651,8 @@ pub(crate) unsafe fn codegen( "LLVM_module_codegen_embed_bitcode", &module.name[..], ); - embed_bitcode(cgcx, llcx, llmod, Some(data)); + embed_bitcode(cgcx, llcx, llmod, &config.bc_cmdline, data); } - } else if config.emit_obj == EmitObj::ObjectCode(BitcodeSection::Marker) { - embed_bitcode(cgcx, llcx, llmod, None); } if config.emit_ir { @@ -777,8 +775,8 @@ pub(crate) unsafe fn codegen( /// * __LLVM,__cmdline /// /// It appears *both* of these sections are necessary to get the linker to -/// recognize what's going on. For us though we just always throw in an empty -/// cmdline section. +/// recognize what's going on. A suitable cmdline value is taken from the +/// target spec. /// /// Furthermore debug/O1 builds don't actually embed bitcode but rather just /// embed an empty section. @@ -789,9 +787,10 @@ unsafe fn embed_bitcode( cgcx: &CodegenContext<LlvmCodegenBackend>, llcx: &llvm::Context, llmod: &llvm::Module, - bitcode: Option<&[u8]>, + cmdline: &str, + bitcode: &[u8], ) { - let llconst = common::bytes_in_context(llcx, bitcode.unwrap_or(&[])); + let llconst = common::bytes_in_context(llcx, bitcode); let llglobal = llvm::LLVMAddGlobal( llmod, common::val_ty(llconst), @@ -800,14 +799,15 @@ unsafe fn embed_bitcode( llvm::LLVMSetInitializer(llglobal, llconst); let is_apple = cgcx.opts.target_triple.triple().contains("-ios") - || cgcx.opts.target_triple.triple().contains("-darwin"); + || cgcx.opts.target_triple.triple().contains("-darwin") + || cgcx.opts.target_triple.triple().contains("-tvos"); let section = if is_apple { "__LLVM,__bitcode\0" } else { ".llvmbc\0" }; llvm::LLVMSetSection(llglobal, section.as_ptr().cast()); llvm::LLVMRustSetLinkage(llglobal, llvm::Linkage::PrivateLinkage); llvm::LLVMSetGlobalConstant(llglobal, llvm::True); - let llconst = common::bytes_in_context(llcx, &[]); + let llconst = common::bytes_in_context(llcx, cmdline.as_bytes()); let llglobal = llvm::LLVMAddGlobal( llmod, common::val_ty(llconst), @@ -853,7 +853,9 @@ unsafe fn embed_bitcode( || cgcx.opts.target_triple.triple().starts_with("asmjs") { // nothing to do here - } else if cgcx.opts.target_triple.triple().contains("windows") { + } else if cgcx.opts.target_triple.triple().contains("windows") + || cgcx.opts.target_triple.triple().contains("uefi") + { let asm = " .section .llvmbc,\"n\" .section .llvmcmd,\"n\" diff --git a/src/librustc_codegen_ssa/back/write.rs b/src/librustc_codegen_ssa/back/write.rs index c53fc5551fd..21eb56f12b9 100644 --- a/src/librustc_codegen_ssa/back/write.rs +++ b/src/librustc_codegen_ssa/back/write.rs @@ -23,7 +23,7 @@ use rustc_hir::def_id::{CrateNum, LOCAL_CRATE}; use rustc_incremental::{ copy_cgu_workproducts_to_incr_comp_cache_dir, in_incr_comp_dir, in_incr_comp_dir_sess, }; -use rustc_middle::dep_graph::{WorkProduct, WorkProductFileKind, WorkProductId}; +use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; use rustc_middle::middle::cstore::EncodedMetadata; use rustc_middle::middle::exported_symbols::SymbolExportLevel; use rustc_middle::ty::TyCtxt; @@ -68,10 +68,6 @@ pub enum BitcodeSection { // No bitcode section. None, - // An empty bitcode section (to placate tools such as the iOS linker that - // require this section even if they don't use it). - Marker, - // A full, uncompressed bitcode section. Full, } @@ -101,6 +97,7 @@ pub struct ModuleConfig { pub emit_ir: bool, pub emit_asm: bool, pub emit_obj: EmitObj, + pub bc_cmdline: String, // Miscellaneous flags. These are mostly copied from command-line // options. @@ -147,14 +144,8 @@ impl ModuleConfig { || sess.opts.cg.linker_plugin_lto.enabled() { EmitObj::Bitcode - } else if need_crate_bitcode_for_rlib(sess) { - let force_full = need_crate_bitcode_for_rlib(sess); - match sess.opts.optimize { - config::OptLevel::No | config::OptLevel::Less if !force_full => { - EmitObj::ObjectCode(BitcodeSection::Marker) - } - _ => EmitObj::ObjectCode(BitcodeSection::Full), - } + } else if need_bitcode_in_object(sess) { + EmitObj::ObjectCode(BitcodeSection::Full) } else { EmitObj::ObjectCode(BitcodeSection::None) }; @@ -211,6 +202,7 @@ impl ModuleConfig { false ), emit_obj, + bc_cmdline: sess.target.target.options.bitcode_llvm_cmdline.clone(), verify_llvm_ir: sess.verify_llvm_ir(), no_prepopulate_passes: sess.opts.cg.no_prepopulate_passes, @@ -372,10 +364,12 @@ pub struct CompiledModules { pub allocator_module: Option<CompiledModule>, } -fn need_crate_bitcode_for_rlib(sess: &Session) -> bool { - sess.opts.cg.embed_bitcode +fn need_bitcode_in_object(sess: &Session) -> bool { + let requested_for_rlib = sess.opts.cg.embed_bitcode && sess.crate_types.borrow().contains(&CrateType::Rlib) - && sess.opts.output_types.contains_key(&OutputType::Exe) + && sess.opts.output_types.contains_key(&OutputType::Exe); + let forced_by_target = sess.target.target.options.forces_embed_bitcode; + requested_for_rlib || forced_by_target } fn need_pre_lto_bitcode_for_incr_comp(sess: &Session) -> bool { @@ -477,10 +471,7 @@ fn copy_all_cgu_workproducts_to_incr_comp_cache_dir( let mut files = vec![]; if let Some(ref path) = module.object { - files.push((WorkProductFileKind::Object, path.clone())); - } - if let Some(ref path) = module.bytecode { - files.push((WorkProductFileKind::Bytecode, path.clone())); + files.push(path.clone()); } if let Some((id, product)) = @@ -817,20 +808,9 @@ fn execute_copy_from_cache_work_item<B: ExtraBackendMethods>( ) -> Result<WorkItemResult<B>, FatalError> { let incr_comp_session_dir = cgcx.incr_comp_session_dir.as_ref().unwrap(); let mut object = None; - let mut bytecode = None; - for (kind, saved_file) in &module.source.saved_files { - let obj_out = match kind { - WorkProductFileKind::Object => { - let path = cgcx.output_filenames.temp_path(OutputType::Object, Some(&module.name)); - object = Some(path.clone()); - path - } - WorkProductFileKind::Bytecode => { - let path = cgcx.output_filenames.temp_path(OutputType::Bitcode, Some(&module.name)); - bytecode = Some(path.clone()); - path - } - }; + for saved_file in &module.source.saved_files { + let obj_out = cgcx.output_filenames.temp_path(OutputType::Object, Some(&module.name)); + object = Some(obj_out.clone()); let source_file = in_incr_comp_dir(&incr_comp_session_dir, &saved_file); debug!( "copying pre-existing module `{}` from {:?} to {}", @@ -850,13 +830,12 @@ fn execute_copy_from_cache_work_item<B: ExtraBackendMethods>( } assert_eq!(object.is_some(), module_config.emit_obj != EmitObj::None); - assert_eq!(bytecode.is_some(), module_config.emit_bc); Ok(WorkItemResult::Compiled(CompiledModule { name: module.name, kind: ModuleKind::Regular, object, - bytecode, + bytecode: None, })) } diff --git a/src/librustc_codegen_ssa/mir/rvalue.rs b/src/librustc_codegen_ssa/mir/rvalue.rs index 19a0138d9cb..bb532abd84b 100644 --- a/src/librustc_codegen_ssa/mir/rvalue.rs +++ b/src/librustc_codegen_ssa/mir/rvalue.rs @@ -768,7 +768,7 @@ fn cast_float_to_int<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( ) -> Bx::Value { let fptosui_result = if signed { bx.fptosi(x, int_ty) } else { bx.fptoui(x, int_ty) }; - if !bx.cx().sess().opts.debugging_opts.saturating_float_casts { + if let Some(false) = bx.cx().sess().opts.debugging_opts.saturating_float_casts { return fptosui_result; } diff --git a/src/librustc_data_structures/Cargo.toml b/src/librustc_data_structures/Cargo.toml index 6d7022acc78..f543f8051a4 100644 --- a/src/librustc_data_structures/Cargo.toml +++ b/src/librustc_data_structures/Cargo.toml @@ -10,7 +10,7 @@ path = "lib.rs" doctest = false [dependencies] -ena = "0.13.1" +ena = "0.14" indexmap = "1" log = "0.4" jobserver_crate = { version = "0.1.13", package = "jobserver" } @@ -28,6 +28,7 @@ rustc_index = { path = "../librustc_index", package = "rustc_index" } bitflags = "1.2.1" measureme = "0.7.1" libc = "0.2" +stacker = "0.1.6" [dependencies.parking_lot] version = "0.10" diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index bc2da535fd3..9164734783c 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -80,10 +80,12 @@ pub mod stable_set; #[macro_use] pub mod stable_hasher; pub mod sharded; +pub mod stack; pub mod sync; pub mod thin_vec; pub mod tiny_list; pub mod transitive_relation; +pub use ena::undo_log; pub use ena::unify; mod atomic_ref; pub mod fingerprint; diff --git a/src/librustc_data_structures/snapshot_map/mod.rs b/src/librustc_data_structures/snapshot_map/mod.rs index b71163a8f94..52865f55f78 100644 --- a/src/librustc_data_structures/snapshot_map/mod.rs +++ b/src/librustc_data_structures/snapshot_map/mod.rs @@ -1,77 +1,75 @@ use crate::fx::FxHashMap; +use crate::undo_log::{Rollback, Snapshots, UndoLogs, VecLog}; +use std::borrow::{Borrow, BorrowMut}; use std::hash::Hash; -use std::mem; +use std::marker::PhantomData; use std::ops; +pub use crate::undo_log::Snapshot; + #[cfg(test)] mod tests; -pub struct SnapshotMap<K, V> -where - K: Clone + Eq, -{ - map: FxHashMap<K, V>, - undo_log: Vec<UndoLog<K, V>>, - num_open_snapshots: usize, +pub type SnapshotMapStorage<K, V> = SnapshotMap<K, V, FxHashMap<K, V>, ()>; +pub type SnapshotMapRef<'a, K, V, L> = SnapshotMap<K, V, &'a mut FxHashMap<K, V>, &'a mut L>; + +pub struct SnapshotMap<K, V, M = FxHashMap<K, V>, L = VecLog<UndoLog<K, V>>> { + map: M, + undo_log: L, + _marker: PhantomData<(K, V)>, } // HACK(eddyb) manual impl avoids `Default` bounds on `K` and `V`. -impl<K, V> Default for SnapshotMap<K, V> +impl<K, V, M, L> Default for SnapshotMap<K, V, M, L> where - K: Hash + Clone + Eq, + M: Default, + L: Default, { fn default() -> Self { - SnapshotMap { map: Default::default(), undo_log: Default::default(), num_open_snapshots: 0 } + SnapshotMap { map: Default::default(), undo_log: Default::default(), _marker: PhantomData } } } -pub struct Snapshot { - len: usize, -} - -enum UndoLog<K, V> { +pub enum UndoLog<K, V> { Inserted(K), Overwrite(K, V), Purged, } -impl<K, V> SnapshotMap<K, V> +impl<K, V, M, L> SnapshotMap<K, V, M, L> { + pub fn with_log<L2>(&mut self, undo_log: L2) -> SnapshotMap<K, V, &mut M, L2> { + SnapshotMap { map: &mut self.map, undo_log, _marker: PhantomData } + } +} + +impl<K, V, M, L> SnapshotMap<K, V, M, L> where K: Hash + Clone + Eq, + M: BorrowMut<FxHashMap<K, V>> + Borrow<FxHashMap<K, V>>, + L: UndoLogs<UndoLog<K, V>>, { pub fn clear(&mut self) { - self.map.clear(); + self.map.borrow_mut().clear(); self.undo_log.clear(); - self.num_open_snapshots = 0; - } - - fn in_snapshot(&self) -> bool { - self.num_open_snapshots > 0 } pub fn insert(&mut self, key: K, value: V) -> bool { - match self.map.insert(key.clone(), value) { + match self.map.borrow_mut().insert(key.clone(), value) { None => { - if self.in_snapshot() { - self.undo_log.push(UndoLog::Inserted(key)); - } + self.undo_log.push(UndoLog::Inserted(key)); true } Some(old_value) => { - if self.in_snapshot() { - self.undo_log.push(UndoLog::Overwrite(key, old_value)); - } + self.undo_log.push(UndoLog::Overwrite(key, old_value)); false } } } pub fn remove(&mut self, key: K) -> bool { - match self.map.remove(&key) { + match self.map.borrow_mut().remove(&key) { Some(old_value) => { - if self.in_snapshot() { - self.undo_log.push(UndoLog::Overwrite(key, old_value)); - } + self.undo_log.push(UndoLog::Overwrite(key, old_value)); true } None => false, @@ -79,83 +77,64 @@ where } pub fn get(&self, key: &K) -> Option<&V> { - self.map.get(key) + self.map.borrow().get(key) } +} +impl<K, V> SnapshotMap<K, V> +where + K: Hash + Clone + Eq, +{ pub fn snapshot(&mut self) -> Snapshot { - let len = self.undo_log.len(); - self.num_open_snapshots += 1; - Snapshot { len } - } - - fn assert_open_snapshot(&self, snapshot: &Snapshot) { - assert!(self.undo_log.len() >= snapshot.len); - assert!(self.num_open_snapshots > 0); + self.undo_log.start_snapshot() } pub fn commit(&mut self, snapshot: Snapshot) { - self.assert_open_snapshot(&snapshot); - if self.num_open_snapshots == 1 { - // The root snapshot. It's safe to clear the undo log because - // there's no snapshot further out that we might need to roll back - // to. - assert!(snapshot.len == 0); - self.undo_log.clear(); - } - - self.num_open_snapshots -= 1; + self.undo_log.commit(snapshot) } - pub fn partial_rollback<F>(&mut self, snapshot: &Snapshot, should_revert_key: &F) - where - F: Fn(&K) -> bool, - { - self.assert_open_snapshot(snapshot); - for i in (snapshot.len..self.undo_log.len()).rev() { - let reverse = match self.undo_log[i] { - UndoLog::Purged => false, - UndoLog::Inserted(ref k) => should_revert_key(k), - UndoLog::Overwrite(ref k, _) => should_revert_key(k), - }; - - if reverse { - let entry = mem::replace(&mut self.undo_log[i], UndoLog::Purged); - self.reverse(entry); - } - } + pub fn rollback_to(&mut self, snapshot: Snapshot) { + let map = &mut self.map; + self.undo_log.rollback_to(|| map, snapshot) } +} - pub fn rollback_to(&mut self, snapshot: Snapshot) { - self.assert_open_snapshot(&snapshot); - while self.undo_log.len() > snapshot.len { - let entry = self.undo_log.pop().unwrap(); - self.reverse(entry); - } +impl<'k, K, V, M, L> ops::Index<&'k K> for SnapshotMap<K, V, M, L> +where + K: Hash + Clone + Eq, + M: Borrow<FxHashMap<K, V>>, +{ + type Output = V; + fn index(&self, key: &'k K) -> &V { + &self.map.borrow()[key] + } +} - self.num_open_snapshots -= 1; +impl<K, V, M, L> Rollback<UndoLog<K, V>> for SnapshotMap<K, V, M, L> +where + K: Eq + Hash, + M: Rollback<UndoLog<K, V>>, +{ + fn reverse(&mut self, undo: UndoLog<K, V>) { + self.map.reverse(undo) } +} - fn reverse(&mut self, entry: UndoLog<K, V>) { - match entry { +impl<K, V> Rollback<UndoLog<K, V>> for FxHashMap<K, V> +where + K: Eq + Hash, +{ + fn reverse(&mut self, undo: UndoLog<K, V>) { + match undo { UndoLog::Inserted(key) => { - self.map.remove(&key); + self.remove(&key); } UndoLog::Overwrite(key, old_value) => { - self.map.insert(key, old_value); + self.insert(key, old_value); } UndoLog::Purged => {} } } } - -impl<'k, K, V> ops::Index<&'k K> for SnapshotMap<K, V> -where - K: Hash + Clone + Eq, -{ - type Output = V; - fn index(&self, key: &'k K) -> &V { - &self.map[key] - } -} diff --git a/src/librustc_data_structures/stack.rs b/src/librustc_data_structures/stack.rs new file mode 100644 index 00000000000..a4964b7aa0c --- /dev/null +++ b/src/librustc_data_structures/stack.rs @@ -0,0 +1,17 @@ +// This is the amount of bytes that need to be left on the stack before increasing the size. +// It must be at least as large as the stack required by any code that does not call +// `ensure_sufficient_stack`. +const RED_ZONE: usize = 100 * 1024; // 100k + +// Only the first stack that is pushed, grows exponentially (2^n * STACK_PER_RECURSION) from then +// on. This flag has performance relevant characteristics. Don't set it too high. +const STACK_PER_RECURSION: usize = 1 * 1024 * 1024; // 1MB + +/// Grows the stack on demand to prevent stack overflow. Call this in strategic locations +/// to "break up" recursive calls. E.g. almost any call to `visit_expr` or equivalent can benefit +/// from this. +/// +/// Should not be sprinkled around carelessly, as it causes a little bit of overhead. +pub fn ensure_sufficient_stack<R>(f: impl FnOnce() -> R) -> R { + stacker::maybe_grow(RED_ZONE, STACK_PER_RECURSION, f) +} diff --git a/src/librustc_errors/registry.rs b/src/librustc_errors/registry.rs index 32700c6500b..b1d770d5bd5 100644 --- a/src/librustc_errors/registry.rs +++ b/src/librustc_errors/registry.rs @@ -10,12 +10,12 @@ pub struct Registry { impl Registry { pub fn new(long_descriptions: &[(&'static str, Option<&'static str>)]) -> Registry { - Registry { long_descriptions: long_descriptions.iter().cloned().collect() } + Registry { long_descriptions: long_descriptions.iter().copied().collect() } } /// This will panic if an invalid error code is passed in pub fn find_description(&self, code: &str) -> Option<&'static str> { - self.try_find_description(code).unwrap() + self.long_descriptions[code] } /// Returns `InvalidErrorCode` if the code requested does not exist in the /// registry. Otherwise, returns an `Option` where `None` means the error @@ -24,9 +24,6 @@ impl Registry { &self, code: &str, ) -> Result<Option<&'static str>, InvalidErrorCode> { - if !self.long_descriptions.contains_key(code) { - return Err(InvalidErrorCode); - } - Ok(*self.long_descriptions.get(code).unwrap()) + self.long_descriptions.get(code).copied().ok_or(InvalidErrorCode) } } diff --git a/src/librustc_hir/hir.rs b/src/librustc_hir/hir.rs index 258428d77da..75a5c198ec7 100644 --- a/src/librustc_hir/hir.rs +++ b/src/librustc_hir/hir.rs @@ -1291,6 +1291,53 @@ impl BodyOwnerKind { } } +/// The kind of an item that requires const-checking. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum ConstContext { + /// A `const fn`. + ConstFn, + + /// A `static` or `static mut`. + Static(Mutability), + + /// A `const`, associated `const`, or other const context. + /// + /// Other contexts include: + /// - Array length expressions + /// - Enum discriminants + /// - Const generics + /// + /// For the most part, other contexts are treated just like a regular `const`, so they are + /// lumped into the same category. + Const, +} + +impl ConstContext { + /// A description of this const context that can appear between backticks in an error message. + /// + /// E.g. `const` or `static mut`. + pub fn keyword_name(self) -> &'static str { + match self { + Self::Const => "const", + Self::Static(Mutability::Not) => "static", + Self::Static(Mutability::Mut) => "static mut", + Self::ConstFn => "const fn", + } + } +} + +/// A colloquial, trivially pluralizable description of this const context for use in error +/// messages. +impl fmt::Display for ConstContext { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match *self { + Self::Const => write!(f, "constant"), + Self::Static(_) => write!(f, "static"), + Self::ConstFn => write!(f, "constant function"), + } + } +} + /// A literal. pub type Lit = Spanned<LitKind>; @@ -2626,8 +2673,42 @@ impl Node<'_> { match self { Node::TraitItem(TraitItem { generics, .. }) | Node::ImplItem(ImplItem { generics, .. }) - | Node::Item(Item { kind: ItemKind::Fn(_, generics, _), .. }) => Some(generics), + | Node::Item(Item { + kind: + ItemKind::Trait(_, _, generics, ..) + | ItemKind::Impl { generics, .. } + | ItemKind::Fn(_, generics, _), + .. + }) => Some(generics), _ => None, } } + + pub fn hir_id(&self) -> Option<HirId> { + match self { + Node::Item(Item { hir_id, .. }) + | Node::ForeignItem(ForeignItem { hir_id, .. }) + | Node::TraitItem(TraitItem { hir_id, .. }) + | Node::ImplItem(ImplItem { hir_id, .. }) + | Node::Field(StructField { hir_id, .. }) + | Node::AnonConst(AnonConst { hir_id, .. }) + | Node::Expr(Expr { hir_id, .. }) + | Node::Stmt(Stmt { hir_id, .. }) + | Node::Ty(Ty { hir_id, .. }) + | Node::Binding(Pat { hir_id, .. }) + | Node::Pat(Pat { hir_id, .. }) + | Node::Arm(Arm { hir_id, .. }) + | Node::Block(Block { hir_id, .. }) + | Node::Local(Local { hir_id, .. }) + | Node::MacroDef(MacroDef { hir_id, .. }) + | Node::Lifetime(Lifetime { hir_id, .. }) + | Node::Param(Param { hir_id, .. }) + | Node::GenericParam(GenericParam { hir_id, .. }) => Some(*hir_id), + Node::TraitRef(TraitRef { hir_ref_id, .. }) => Some(*hir_ref_id), + Node::PathSegment(PathSegment { hir_id, .. }) => *hir_id, + Node::Variant(Variant { id, .. }) => Some(*id), + Node::Ctor(variant) => variant.ctor_hir_id(), + Node::Crate(_) | Node::Visibility(_) => None, + } + } } diff --git a/src/librustc_incremental/persist/load.rs b/src/librustc_incremental/persist/load.rs index b75a428c62a..99c799950c0 100644 --- a/src/librustc_incremental/persist/load.rs +++ b/src/librustc_incremental/persist/load.rs @@ -134,7 +134,7 @@ pub fn load_dep_graph(sess: &Session) -> DepGraphFuture { for swp in work_products { let mut all_files_exist = true; - for &(_, ref file_name) in swp.work_product.saved_files.iter() { + for file_name in swp.work_product.saved_files.iter() { let path = in_incr_comp_dir_sess(sess, file_name); if !path.exists() { all_files_exist = false; diff --git a/src/librustc_incremental/persist/save.rs b/src/librustc_incremental/persist/save.rs index 6d4ba45c2e6..4db6297712c 100644 --- a/src/librustc_incremental/persist/save.rs +++ b/src/librustc_incremental/persist/save.rs @@ -74,9 +74,9 @@ pub fn save_work_product_index( if !new_work_products.contains_key(id) { work_product::delete_workproduct_files(sess, wp); debug_assert!( - wp.saved_files.iter().all(|&(_, ref file_name)| { - !in_incr_comp_dir_sess(sess, file_name).exists() - }) + wp.saved_files + .iter() + .all(|file_name| { !in_incr_comp_dir_sess(sess, file_name).exists() }) ); } } @@ -85,7 +85,7 @@ pub fn save_work_product_index( debug_assert!({ new_work_products .iter() - .flat_map(|(_, wp)| wp.saved_files.iter().map(|&(_, ref name)| name)) + .flat_map(|(_, wp)| wp.saved_files.iter()) .map(|name| in_incr_comp_dir_sess(sess, name)) .all(|path| path.exists()) }); diff --git a/src/librustc_incremental/persist/work_product.rs b/src/librustc_incremental/persist/work_product.rs index 3601b997059..a15ee6d81db 100644 --- a/src/librustc_incremental/persist/work_product.rs +++ b/src/librustc_incremental/persist/work_product.rs @@ -2,7 +2,7 @@ use crate::persist::fs::*; use rustc_fs_util::link_or_copy; -use rustc_middle::dep_graph::{WorkProduct, WorkProductFileKind, WorkProductId}; +use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; use rustc_session::Session; use std::fs as std_fs; use std::path::PathBuf; @@ -10,22 +10,18 @@ use std::path::PathBuf; pub fn copy_cgu_workproducts_to_incr_comp_cache_dir( sess: &Session, cgu_name: &str, - files: &[(WorkProductFileKind, PathBuf)], + files: &[PathBuf], ) -> Option<(WorkProductId, WorkProduct)> { debug!("copy_cgu_workproducts_to_incr_comp_cache_dir({:?},{:?})", cgu_name, files); sess.opts.incremental.as_ref()?; let saved_files = files .iter() - .map(|&(kind, ref path)| { - let extension = match kind { - WorkProductFileKind::Object => "o", - WorkProductFileKind::Bytecode => "bc", - }; - let file_name = format!("{}.{}", cgu_name, extension); + .map(|path| { + let file_name = format!("{}.o", cgu_name); let path_in_incr_dir = in_incr_comp_dir_sess(sess, &file_name); match link_or_copy(path, &path_in_incr_dir) { - Ok(_) => Some((kind, file_name)), + Ok(_) => Some(file_name), Err(err) => { sess.warn(&format!( "error copying object file `{}` \ @@ -47,7 +43,7 @@ pub fn copy_cgu_workproducts_to_incr_comp_cache_dir( } pub fn delete_workproduct_files(sess: &Session, work_product: &WorkProduct) { - for &(_, ref file_name) in &work_product.saved_files { + for file_name in &work_product.saved_files { let path = in_incr_comp_dir_sess(sess, file_name); match std_fs::remove_file(&path) { Ok(()) => {} diff --git a/src/librustc_infer/infer/combine.rs b/src/librustc_infer/infer/combine.rs index b03044b72da..d4af4704996 100644 --- a/src/librustc_infer/infer/combine.rs +++ b/src/librustc_infer/infer/combine.rs @@ -76,7 +76,7 @@ impl<'infcx, 'tcx> InferCtxt<'infcx, 'tcx> { (&ty::Infer(ty::IntVar(a_id)), &ty::Infer(ty::IntVar(b_id))) => { self.inner .borrow_mut() - .int_unification_table + .int_unification_table() .unify_var_var(a_id, b_id) .map_err(|e| int_unification_error(a_is_expected, e))?; Ok(a) @@ -98,7 +98,7 @@ impl<'infcx, 'tcx> InferCtxt<'infcx, 'tcx> { (&ty::Infer(ty::FloatVar(a_id)), &ty::Infer(ty::FloatVar(b_id))) => { self.inner .borrow_mut() - .float_unification_table + .float_unification_table() .unify_var_var(a_id, b_id) .map_err(|e| float_unification_error(relation.a_is_expected(), e))?; Ok(a) @@ -133,8 +133,8 @@ impl<'infcx, 'tcx> InferCtxt<'infcx, 'tcx> { return Ok(a); } - let a = replace_if_possible(&mut self.inner.borrow_mut().const_unification_table, a); - let b = replace_if_possible(&mut self.inner.borrow_mut().const_unification_table, b); + let a = replace_if_possible(&mut self.inner.borrow_mut().const_unification_table(), a); + let b = replace_if_possible(&mut self.inner.borrow_mut().const_unification_table(), b); let a_is_expected = relation.a_is_expected(); @@ -145,7 +145,7 @@ impl<'infcx, 'tcx> InferCtxt<'infcx, 'tcx> { ) => { self.inner .borrow_mut() - .const_unification_table + .const_unification_table() .unify_var_var(a_vid, b_vid) .map_err(|e| const_unification_error(a_is_expected, e))?; return Ok(a); @@ -179,7 +179,7 @@ impl<'infcx, 'tcx> InferCtxt<'infcx, 'tcx> { ) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>> { self.inner .borrow_mut() - .const_unification_table + .const_unification_table() .unify_var_value( vid, ConstVarValue { @@ -202,7 +202,7 @@ impl<'infcx, 'tcx> InferCtxt<'infcx, 'tcx> { ) -> RelateResult<'tcx, Ty<'tcx>> { self.inner .borrow_mut() - .int_unification_table + .int_unification_table() .unify_var_value(vid, Some(val)) .map_err(|e| int_unification_error(vid_is_expected, e))?; match val { @@ -219,7 +219,7 @@ impl<'infcx, 'tcx> InferCtxt<'infcx, 'tcx> { ) -> RelateResult<'tcx, Ty<'tcx>> { self.inner .borrow_mut() - .float_unification_table + .float_unification_table() .unify_var_value(vid, Some(ty::FloatVarValue(val))) .map_err(|e| float_unification_error(vid_is_expected, e))?; Ok(self.tcx.mk_mach_float(val)) @@ -266,7 +266,7 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> { use self::RelationDir::*; // Get the actual variable that b_vid has been inferred to - debug_assert!(self.infcx.inner.borrow_mut().type_variables.probe(b_vid).is_unknown()); + debug_assert!(self.infcx.inner.borrow_mut().type_variables().probe(b_vid).is_unknown()); debug!("instantiate(a_ty={:?} dir={:?} b_vid={:?})", a_ty, dir, b_vid); @@ -286,7 +286,7 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> { "instantiate(a_ty={:?}, dir={:?}, b_vid={:?}, generalized b_ty={:?})", a_ty, dir, b_vid, b_ty ); - self.infcx.inner.borrow_mut().type_variables.instantiate(b_vid, b_ty); + self.infcx.inner.borrow_mut().type_variables().instantiate(b_vid, b_ty); if needs_wf { self.obligations.push(Obligation::new( @@ -344,7 +344,7 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> { debug!("generalize: ambient_variance = {:?}", ambient_variance); - let for_universe = match self.infcx.inner.borrow_mut().type_variables.probe(for_vid) { + let for_universe = match self.infcx.inner.borrow_mut().type_variables().probe(for_vid) { v @ TypeVariableValue::Known { .. } => { panic!("instantiating {:?} which has a known value {:?}", for_vid, v,) } @@ -356,7 +356,7 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> { let mut generalize = Generalizer { infcx: self.infcx, span: self.trace.cause.span, - for_vid_sub_root: self.infcx.inner.borrow_mut().type_variables.sub_root_var(for_vid), + for_vid_sub_root: self.infcx.inner.borrow_mut().type_variables().sub_root_var(for_vid), for_universe, ambient_variance, needs_wf: false, @@ -508,14 +508,14 @@ impl TypeRelation<'tcx> for Generalizer<'_, 'tcx> { // us from creating infinitely sized types. match t.kind { ty::Infer(ty::TyVar(vid)) => { - let vid = self.infcx.inner.borrow_mut().type_variables.root_var(vid); - let sub_vid = self.infcx.inner.borrow_mut().type_variables.sub_root_var(vid); + let vid = self.infcx.inner.borrow_mut().type_variables().root_var(vid); + let sub_vid = self.infcx.inner.borrow_mut().type_variables().sub_root_var(vid); if sub_vid == self.for_vid_sub_root { // If sub-roots are equal, then `for_vid` and // `vid` are related via subtyping. Err(TypeError::CyclicTy(self.root_ty)) } else { - let probe = self.infcx.inner.borrow_mut().type_variables.probe(vid); + let probe = self.infcx.inner.borrow_mut().type_variables().probe(vid); match probe { TypeVariableValue::Known { value: u } => { debug!("generalize: known value {:?}", u); @@ -542,12 +542,13 @@ impl TypeRelation<'tcx> for Generalizer<'_, 'tcx> { } let origin = - *self.infcx.inner.borrow_mut().type_variables.var_origin(vid); - let new_var_id = self.infcx.inner.borrow_mut().type_variables.new_var( - self.for_universe, - false, - origin, - ); + *self.infcx.inner.borrow_mut().type_variables().var_origin(vid); + let new_var_id = self + .infcx + .inner + .borrow_mut() + .type_variables() + .new_var(self.for_universe, false, origin); let u = self.tcx().mk_ty_var(new_var_id); debug!("generalize: replacing original vid={:?} with new={:?}", vid, u); Ok(u) @@ -618,7 +619,8 @@ impl TypeRelation<'tcx> for Generalizer<'_, 'tcx> { match c.val { ty::ConstKind::Infer(InferConst::Var(vid)) => { - let variable_table = &mut self.infcx.inner.borrow_mut().const_unification_table; + let mut inner = self.infcx.inner.borrow_mut(); + let variable_table = &mut inner.const_unification_table(); let var_value = variable_table.probe_value(vid); match var_value.val { ConstVariableValue::Known { value: u } => self.relate(&u, &u), diff --git a/src/librustc_infer/infer/equate.rs b/src/librustc_infer/infer/equate.rs index e05094cda27..d054070e292 100644 --- a/src/librustc_infer/infer/equate.rs +++ b/src/librustc_infer/infer/equate.rs @@ -72,14 +72,14 @@ impl TypeRelation<'tcx> for Equate<'combine, 'infcx, 'tcx> { } let infcx = self.fields.infcx; - let a = infcx.inner.borrow_mut().type_variables.replace_if_possible(a); - let b = infcx.inner.borrow_mut().type_variables.replace_if_possible(b); + let a = infcx.inner.borrow_mut().type_variables().replace_if_possible(a); + let b = infcx.inner.borrow_mut().type_variables().replace_if_possible(b); debug!("{}.tys: replacements ({:?}, {:?})", self.tag(), a, b); match (&a.kind, &b.kind) { (&ty::Infer(TyVar(a_id)), &ty::Infer(TyVar(b_id))) => { - infcx.inner.borrow_mut().type_variables.equate(a_id, b_id); + infcx.inner.borrow_mut().type_variables().equate(a_id, b_id); } (&ty::Infer(TyVar(a_id)), _) => { diff --git a/src/librustc_infer/infer/error_reporting/mod.rs b/src/librustc_infer/infer/error_reporting/mod.rs index 50e97c8fb7a..a8d6c01785f 100644 --- a/src/librustc_infer/infer/error_reporting/mod.rs +++ b/src/librustc_infer/infer/error_reporting/mod.rs @@ -1388,6 +1388,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { terr: &TypeError<'tcx>, ) { let span = cause.span(self.tcx); + debug!("note_type_err cause={:?} values={:?}, terr={:?}", cause, values, terr); // For some types of errors, expected-found does not make // sense, so just ignore the values we were given. @@ -1599,11 +1600,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { self.tcx.hir().body_owner_def_id(hir::BodyId { hir_id: cause.body_id }) }); self.check_and_note_conflicting_crates(diag, terr); - self.tcx.note_and_explain_type_err(diag, terr, span, body_owner_def_id.to_def_id()); + self.tcx.note_and_explain_type_err(diag, terr, cause, span, body_owner_def_id.to_def_id()); // It reads better to have the error origin as the final // thing. - self.note_error_origin(diag, &cause, exp_found); + self.note_error_origin(diag, cause, exp_found); } /// When encountering a case where `.as_ref()` on a `Result` or `Option` would be appropriate, diff --git a/src/librustc_infer/infer/error_reporting/need_type_info.rs b/src/librustc_infer/infer/error_reporting/need_type_info.rs index 93c8e505697..d8133c58df7 100644 --- a/src/librustc_infer/infer/error_reporting/need_type_info.rs +++ b/src/librustc_infer/infer/error_reporting/need_type_info.rs @@ -59,7 +59,7 @@ impl<'a, 'tcx> FindHirNodeVisitor<'a, 'tcx> { .infcx .inner .borrow_mut() - .type_variables + .type_variables() .sub_unified(a_vid, b_vid), _ => false, } @@ -194,7 +194,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { highlight: Option<ty::print::RegionHighlightMode>, ) -> (String, Option<Span>, Cow<'static, str>, Option<String>, Option<&'static str>) { if let ty::Infer(ty::TyVar(ty_vid)) = ty.kind { - let ty_vars = &self.inner.borrow().type_variables; + let mut inner = self.inner.borrow_mut(); + let ty_vars = &inner.type_variables(); let var_origin = ty_vars.var_origin(ty_vid); if let TypeVariableOriginKind::TypeParameterDefinition(name, def_id) = var_origin.kind { let parent_def_id = def_id.and_then(|def_id| self.tcx.parent(def_id)); @@ -248,7 +249,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { 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.inner.borrow().type_variables; + let mut inner = self.inner.borrow_mut(); + let ty_vars = inner.type_variables(); let getter = move |ty_vid| { let var_origin = ty_vars.var_origin(ty_vid); if let TypeVariableOriginKind::TypeParameterDefinition(name, _) = var_origin.kind { diff --git a/src/librustc_infer/infer/freshen.rs b/src/librustc_infer/infer/freshen.rs index 636cf42198b..47346c3a856 100644 --- a/src/librustc_infer/infer/freshen.rs +++ b/src/librustc_infer/infer/freshen.rs @@ -147,7 +147,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for TypeFreshener<'a, 'tcx> { match t.kind { ty::Infer(ty::TyVar(v)) => { - let opt_ty = self.infcx.inner.borrow_mut().type_variables.probe(v).known(); + let opt_ty = self.infcx.inner.borrow_mut().type_variables().probe(v).known(); self.freshen_ty(opt_ty, ty::TyVar(v), ty::FreshTy) } @@ -155,7 +155,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for TypeFreshener<'a, 'tcx> { self.infcx .inner .borrow_mut() - .int_unification_table + .int_unification_table() .probe_value(v) .map(|v| v.to_type(tcx)), ty::IntVar(v), @@ -166,7 +166,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for TypeFreshener<'a, 'tcx> { self.infcx .inner .borrow_mut() - .float_unification_table + .float_unification_table() .probe_value(v) .map(|v| v.to_type(tcx)), ty::FloatVar(v), @@ -222,7 +222,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for TypeFreshener<'a, 'tcx> { .infcx .inner .borrow_mut() - .const_unification_table + .const_unification_table() .probe_value(v) .val .known(); diff --git a/src/librustc_infer/infer/fudge.rs b/src/librustc_infer/infer/fudge.rs index 1a58e100fb3..c6651108df5 100644 --- a/src/librustc_infer/infer/fudge.rs +++ b/src/librustc_infer/infer/fudge.rs @@ -3,18 +3,30 @@ use rustc_middle::ty::{self, ConstVid, FloatVid, IntVid, RegionVid, Ty, TyCtxt, use super::type_variable::TypeVariableOrigin; use super::InferCtxt; -use super::{ConstVariableOrigin, RegionVariableOrigin}; +use super::{ConstVariableOrigin, RegionVariableOrigin, UnificationTable}; +use rustc_data_structures::snapshot_vec as sv; use rustc_data_structures::unify as ut; use ut::UnifyKey; use std::ops::Range; +fn vars_since_snapshot<'tcx, T>( + table: &mut UnificationTable<'_, 'tcx, T>, + snapshot_var_len: usize, +) -> Range<T> +where + T: UnifyKey, + super::UndoLog<'tcx>: From<sv::UndoLog<ut::Delegate<T>>>, +{ + T::from_index(snapshot_var_len as u32)..T::from_index(table.len() as u32) +} + fn const_vars_since_snapshot<'tcx>( - table: &mut ut::UnificationTable<ut::InPlace<ConstVid<'tcx>>>, - snapshot: &ut::Snapshot<ut::InPlace<ConstVid<'tcx>>>, + table: &mut UnificationTable<'_, 'tcx, ConstVid<'tcx>>, + snapshot_var_len: usize, ) -> (Range<ConstVid<'tcx>>, Vec<ConstVariableOrigin>) { - let range = table.vars_since_snapshot(snapshot); + let range = vars_since_snapshot(table, snapshot_var_len); ( range.start..range.end, (range.start.index..range.end.index) @@ -23,7 +35,26 @@ fn const_vars_since_snapshot<'tcx>( ) } +struct VariableLengths { + type_var_len: usize, + const_var_len: usize, + int_var_len: usize, + float_var_len: usize, + region_constraints_len: usize, +} + impl<'a, 'tcx> InferCtxt<'a, 'tcx> { + fn variable_lengths(&self) -> VariableLengths { + let mut inner = self.inner.borrow_mut(); + VariableLengths { + type_var_len: inner.type_variables().num_vars(), + const_var_len: inner.const_unification_table().len(), + int_var_len: inner.int_unification_table().len(), + float_var_len: inner.float_unification_table().len(), + region_constraints_len: inner.unwrap_region_constraints().num_region_vars(), + } + } + /// This rather funky routine is used while processing expected /// types. What happens here is that we want to propagate a /// coercion through the return type of a fn to its @@ -70,7 +101,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { { debug!("fudge_inference_if_ok()"); - let (mut fudger, value) = self.probe(|snapshot| { + let variable_lengths = self.variable_lengths(); + let (mut fudger, value) = self.probe(|_| { match f() { Ok(value) => { let value = self.resolve_vars_if_possible(&value); @@ -83,17 +115,21 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { let mut inner = self.inner.borrow_mut(); let type_vars = - inner.type_variables.vars_since_snapshot(&snapshot.type_snapshot); - let int_vars = - inner.int_unification_table.vars_since_snapshot(&snapshot.int_snapshot); - let float_vars = - inner.float_unification_table.vars_since_snapshot(&snapshot.float_snapshot); + inner.type_variables().vars_since_snapshot(variable_lengths.type_var_len); + let int_vars = vars_since_snapshot( + &mut inner.int_unification_table(), + variable_lengths.int_var_len, + ); + let float_vars = vars_since_snapshot( + &mut inner.float_unification_table(), + variable_lengths.float_var_len, + ); let region_vars = inner .unwrap_region_constraints() - .vars_since_snapshot(&snapshot.region_constraints_snapshot); + .vars_since_snapshot(variable_lengths.region_constraints_len); let const_vars = const_vars_since_snapshot( - &mut inner.const_unification_table, - &snapshot.const_snapshot, + &mut inner.const_unification_table(), + variable_lengths.const_var_len, ); let fudger = InferenceFudger { @@ -161,7 +197,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for InferenceFudger<'a, 'tcx> { // that it is unbound, so we can just return // it. debug_assert!( - self.infcx.inner.borrow_mut().type_variables.probe(vid).is_unknown() + self.infcx.inner.borrow_mut().type_variables().probe(vid).is_unknown() ); ty } diff --git a/src/librustc_infer/infer/lattice.rs b/src/librustc_infer/infer/lattice.rs index c29614b8556..1bf43e74dcd 100644 --- a/src/librustc_infer/infer/lattice.rs +++ b/src/librustc_infer/infer/lattice.rs @@ -56,8 +56,8 @@ where } let infcx = this.infcx(); - let a = infcx.inner.borrow_mut().type_variables.replace_if_possible(a); - let b = infcx.inner.borrow_mut().type_variables.replace_if_possible(b); + let a = infcx.inner.borrow_mut().type_variables().replace_if_possible(a); + let b = infcx.inner.borrow_mut().type_variables().replace_if_possible(b); match (&a.kind, &b.kind) { // If one side is known to be a variable and one is not, // create a variable (`v`) to represent the LUB. Make sure to diff --git a/src/librustc_infer/infer/mod.rs b/src/librustc_infer/infer/mod.rs index 54f80e8f388..2cf9dd882e4 100644 --- a/src/librustc_infer/infer/mod.rs +++ b/src/librustc_infer/infer/mod.rs @@ -6,11 +6,14 @@ pub use self::RegionVariableOrigin::*; pub use self::SubregionOrigin::*; pub use self::ValuePairs::*; +pub(crate) use self::undo_log::{InferCtxtUndoLogs, Snapshot, UndoLog}; + use crate::traits::{self, ObligationCause, PredicateObligations, TraitEngine}; use rustc_ast::ast; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::sync::Lrc; +use rustc_data_structures::undo_log::Rollback; use rustc_data_structures::unify as ut; use rustc_errors::DiagnosticBuilder; use rustc_hir as hir; @@ -42,7 +45,9 @@ use self::free_regions::RegionRelations; use self::lexical_region_resolve::LexicalRegionResolutions; use self::outlives::env::OutlivesEnvironment; use self::region_constraints::{GenericKind, RegionConstraintData, VarInfos, VerifyBound}; -use self::region_constraints::{RegionConstraintCollector, RegionSnapshot}; +use self::region_constraints::{ + RegionConstraintCollector, RegionConstraintStorage, RegionSnapshot, +}; use self::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; pub mod at; @@ -64,6 +69,7 @@ pub mod region_constraints; pub mod resolve; mod sub; pub mod type_variable; +mod undo_log; use crate::infer::canonical::OriginalQueryValues; pub use rustc_middle::infer::unify_key; @@ -80,6 +86,10 @@ pub type Bound<T> = Option<T>; pub type UnitResult<'tcx> = RelateResult<'tcx, ()>; // "unify result" pub type FixupResult<'tcx, T> = Result<T, FixupError<'tcx>>; // "fixup result" +pub(crate) type UnificationTable<'a, 'tcx, T> = ut::UnificationTable< + ut::InPlace<T, &'a mut ut::UnificationStorage<T>, &'a mut InferCtxtUndoLogs<'tcx>>, +>; + /// How we should handle region solving. /// /// This is used so that the region values inferred by HIR region solving are @@ -136,28 +146,28 @@ pub struct InferCtxtInner<'tcx> { /// Cache for projections. This cache is snapshotted along with the infcx. /// /// Public so that `traits::project` can use it. - pub projection_cache: traits::ProjectionCache<'tcx>, + pub projection_cache: traits::ProjectionCacheStorage<'tcx>, /// We instantiate `UnificationTable` with `bounds<Ty>` because the types /// that might instantiate a general type variable have an order, /// represented by its upper and lower bounds. - type_variables: type_variable::TypeVariableTable<'tcx>, + type_variable_storage: type_variable::TypeVariableStorage<'tcx>, /// Map from const parameter variable to the kind of const it represents. - const_unification_table: ut::UnificationTable<ut::InPlace<ty::ConstVid<'tcx>>>, + const_unification_storage: ut::UnificationTableStorage<ty::ConstVid<'tcx>>, /// Map from integral variable to the kind of integer it represents. - int_unification_table: ut::UnificationTable<ut::InPlace<ty::IntVid>>, + int_unification_storage: ut::UnificationTableStorage<ty::IntVid>, /// Map from floating variable to the kind of float it represents. - float_unification_table: ut::UnificationTable<ut::InPlace<ty::FloatVid>>, + float_unification_storage: ut::UnificationTableStorage<ty::FloatVid>, /// Tracks the set of region variables and the constraints between them. /// This is initially `Some(_)` but when /// `resolve_regions_and_report_errors` is invoked, this gets set to `None` /// -- further attempts to perform unification, etc., may fail if new /// region constraints would've been added. - region_constraints: Option<RegionConstraintCollector<'tcx>>, + region_constraint_storage: Option<RegionConstraintStorage<'tcx>>, /// A set of constraints that regionck must validate. Each /// constraint has the form `T:'a`, meaning "some type `T` must @@ -190,24 +200,78 @@ pub struct InferCtxtInner<'tcx> { /// for each body-id in this map, which will process the /// obligations within. This is expected to be done 'late enough' /// that all type inference variables have been bound and so forth. - pub region_obligations: Vec<(hir::HirId, RegionObligation<'tcx>)>, + region_obligations: Vec<(hir::HirId, RegionObligation<'tcx>)>, + + undo_log: InferCtxtUndoLogs<'tcx>, } impl<'tcx> InferCtxtInner<'tcx> { fn new() -> InferCtxtInner<'tcx> { InferCtxtInner { projection_cache: Default::default(), - type_variables: type_variable::TypeVariableTable::new(), - const_unification_table: ut::UnificationTable::new(), - int_unification_table: ut::UnificationTable::new(), - float_unification_table: ut::UnificationTable::new(), - region_constraints: Some(RegionConstraintCollector::new()), + type_variable_storage: type_variable::TypeVariableStorage::new(), + undo_log: InferCtxtUndoLogs::default(), + const_unification_storage: ut::UnificationTableStorage::new(), + int_unification_storage: ut::UnificationTableStorage::new(), + float_unification_storage: ut::UnificationTableStorage::new(), + region_constraint_storage: Some(RegionConstraintStorage::new()), region_obligations: vec![], } } - pub fn unwrap_region_constraints(&mut self) -> &mut RegionConstraintCollector<'tcx> { - self.region_constraints.as_mut().expect("region constraints already solved") + pub fn region_obligations(&self) -> &[(hir::HirId, RegionObligation<'tcx>)] { + &self.region_obligations + } + + pub fn projection_cache(&mut self) -> traits::ProjectionCache<'_, 'tcx> { + self.projection_cache.with_log(&mut self.undo_log) + } + + fn type_variables(&mut self) -> type_variable::TypeVariableTable<'_, 'tcx> { + self.type_variable_storage.with_log(&mut self.undo_log) + } + + fn int_unification_table( + &mut self, + ) -> ut::UnificationTable< + ut::InPlace< + ty::IntVid, + &mut ut::UnificationStorage<ty::IntVid>, + &mut InferCtxtUndoLogs<'tcx>, + >, + > { + self.int_unification_storage.with_log(&mut self.undo_log) + } + + fn float_unification_table( + &mut self, + ) -> ut::UnificationTable< + ut::InPlace< + ty::FloatVid, + &mut ut::UnificationStorage<ty::FloatVid>, + &mut InferCtxtUndoLogs<'tcx>, + >, + > { + self.float_unification_storage.with_log(&mut self.undo_log) + } + + fn const_unification_table( + &mut self, + ) -> ut::UnificationTable< + ut::InPlace< + ty::ConstVid<'tcx>, + &mut ut::UnificationStorage<ty::ConstVid<'tcx>>, + &mut InferCtxtUndoLogs<'tcx>, + >, + > { + self.const_unification_storage.with_log(&mut self.undo_log) + } + + pub fn unwrap_region_constraints(&mut self) -> RegionConstraintCollector<'_, 'tcx> { + self.region_constraint_storage + .as_mut() + .expect("region constraints already solved") + .with_log(&mut self.undo_log) } } @@ -643,16 +707,10 @@ impl<'tcx> InferOk<'tcx, ()> { #[must_use = "once you start a snapshot, you should always consume it"] pub struct CombinedSnapshot<'a, 'tcx> { - projection_cache_snapshot: traits::ProjectionCacheSnapshot, - type_snapshot: type_variable::Snapshot<'tcx>, - const_snapshot: ut::Snapshot<ut::InPlace<ty::ConstVid<'tcx>>>, - int_snapshot: ut::Snapshot<ut::InPlace<ty::IntVid>>, - float_snapshot: ut::Snapshot<ut::InPlace<ty::FloatVid>>, + undo_snapshot: Snapshot<'tcx>, region_constraints_snapshot: RegionSnapshot, - region_obligations_snapshot: usize, universe: ty::UniverseIndex, was_in_snapshot: bool, - was_skip_leak_check: bool, _in_progress_tables: Option<Ref<'a, ty::TypeckTables<'tcx>>>, } @@ -667,7 +725,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { pub fn type_var_diverges(&'a self, ty: Ty<'_>) -> bool { match ty.kind { - ty::Infer(ty::TyVar(vid)) => self.inner.borrow().type_variables.var_diverges(vid), + ty::Infer(ty::TyVar(vid)) => self.inner.borrow_mut().type_variables().var_diverges(vid), _ => false, } } @@ -681,14 +739,14 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { use rustc_middle::ty::error::UnconstrainedNumeric::{UnconstrainedFloat, UnconstrainedInt}; match ty.kind { ty::Infer(ty::IntVar(vid)) => { - if self.inner.borrow_mut().int_unification_table.probe_value(vid).is_some() { + if self.inner.borrow_mut().int_unification_table().probe_value(vid).is_some() { Neither } else { UnconstrainedInt } } ty::Infer(ty::FloatVar(vid)) => { - if self.inner.borrow_mut().float_unification_table.probe_value(vid).is_some() { + if self.inner.borrow_mut().float_unification_table().probe_value(vid).is_some() { Neither } else { UnconstrainedFloat @@ -703,21 +761,21 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { // FIXME(const_generics): should there be an equivalent function for const variables? let mut vars: Vec<Ty<'_>> = inner - .type_variables + .type_variables() .unsolved_variables() .into_iter() .map(|t| self.tcx.mk_ty_var(t)) .collect(); vars.extend( - (0..inner.int_unification_table.len()) + (0..inner.int_unification_table().len()) .map(|i| ty::IntVid { index: i as u32 }) - .filter(|&vid| inner.int_unification_table.probe_value(vid).is_none()) + .filter(|&vid| inner.int_unification_table().probe_value(vid).is_none()) .map(|v| self.tcx.mk_int_var(v)), ); vars.extend( - (0..inner.float_unification_table.len()) + (0..inner.float_unification_table().len()) .map(|i| ty::FloatVid { index: i as u32 }) - .filter(|&vid| inner.float_unification_table.probe_value(vid).is_none()) + .filter(|&vid| inner.float_unification_table().probe_value(vid).is_none()) .map(|v| self.tcx.mk_float_var(v)), ); vars @@ -769,17 +827,12 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { let in_snapshot = self.in_snapshot.replace(true); let mut inner = self.inner.borrow_mut(); + CombinedSnapshot { - projection_cache_snapshot: inner.projection_cache.snapshot(), - type_snapshot: inner.type_variables.snapshot(), - const_snapshot: inner.const_unification_table.snapshot(), - int_snapshot: inner.int_unification_table.snapshot(), - float_snapshot: inner.float_unification_table.snapshot(), + undo_snapshot: inner.undo_log.start_snapshot(), region_constraints_snapshot: inner.unwrap_region_constraints().start_snapshot(), - region_obligations_snapshot: inner.region_obligations.len(), universe: self.universe(), was_in_snapshot: in_snapshot, - was_skip_leak_check: self.skip_leak_check.get(), // Borrow tables "in progress" (i.e., during typeck) // to ban writes from within a snapshot to them. _in_progress_tables: self.in_progress_tables.map(|tables| tables.borrow()), @@ -789,59 +842,34 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { fn rollback_to(&self, cause: &str, snapshot: CombinedSnapshot<'a, 'tcx>) { debug!("rollback_to(cause={})", cause); let CombinedSnapshot { - projection_cache_snapshot, - type_snapshot, - const_snapshot, - int_snapshot, - float_snapshot, + undo_snapshot, region_constraints_snapshot, - region_obligations_snapshot, universe, was_in_snapshot, - was_skip_leak_check, _in_progress_tables, } = snapshot; self.in_snapshot.set(was_in_snapshot); self.universe.set(universe); - self.skip_leak_check.set(was_skip_leak_check); let mut inner = self.inner.borrow_mut(); - inner.projection_cache.rollback_to(projection_cache_snapshot); - inner.type_variables.rollback_to(type_snapshot); - inner.const_unification_table.rollback_to(const_snapshot); - inner.int_unification_table.rollback_to(int_snapshot); - inner.float_unification_table.rollback_to(float_snapshot); + inner.rollback_to(undo_snapshot); inner.unwrap_region_constraints().rollback_to(region_constraints_snapshot); - inner.region_obligations.truncate(region_obligations_snapshot); } fn commit_from(&self, snapshot: CombinedSnapshot<'a, 'tcx>) { debug!("commit_from()"); let CombinedSnapshot { - projection_cache_snapshot, - type_snapshot, - const_snapshot, - int_snapshot, - float_snapshot, - region_constraints_snapshot, - region_obligations_snapshot: _, + undo_snapshot, + region_constraints_snapshot: _, universe: _, was_in_snapshot, - was_skip_leak_check, _in_progress_tables, } = snapshot; self.in_snapshot.set(was_in_snapshot); - self.skip_leak_check.set(was_skip_leak_check); - let mut inner = self.inner.borrow_mut(); - inner.projection_cache.commit(projection_cache_snapshot); - inner.type_variables.commit(type_snapshot); - inner.const_unification_table.commit(const_snapshot); - inner.int_unification_table.commit(int_snapshot); - inner.float_unification_table.commit(float_snapshot); - inner.unwrap_region_constraints().commit(region_constraints_snapshot); + self.inner.borrow_mut().commit(undo_snapshot); } /// Executes `f` and commit the bindings. @@ -895,10 +923,13 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { { debug!("probe()"); let snapshot = self.start_snapshot(); - let skip_leak_check = should_skip || self.skip_leak_check.get(); - self.skip_leak_check.set(skip_leak_check); + let was_skip_leak_check = self.skip_leak_check.get(); + if should_skip { + self.skip_leak_check.set(true); + } let r = f(&snapshot); self.rollback_to("probe", snapshot); + self.skip_leak_check.set(was_skip_leak_check); r } @@ -914,7 +945,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { self.inner .borrow_mut() .unwrap_region_constraints() - .region_constraints_added_in_snapshot(&snapshot.region_constraints_snapshot) + .region_constraints_added_in_snapshot(&snapshot.undo_snapshot) } pub fn add_given(&self, sub: ty::Region<'tcx>, sup: ty::RegionVid) { @@ -1032,7 +1063,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } pub fn next_ty_var_id(&self, diverging: bool, origin: TypeVariableOrigin) -> TyVid { - self.inner.borrow_mut().type_variables.new_var(self.universe(), diverging, origin) + self.inner.borrow_mut().type_variables().new_var(self.universe(), diverging, origin) } pub fn next_ty_var(&self, origin: TypeVariableOrigin) -> Ty<'tcx> { @@ -1044,7 +1075,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { origin: TypeVariableOrigin, universe: ty::UniverseIndex, ) -> Ty<'tcx> { - let vid = self.inner.borrow_mut().type_variables.new_var(universe, false, origin); + let vid = self.inner.borrow_mut().type_variables().new_var(universe, false, origin); self.tcx.mk_ty_var(vid) } @@ -1069,20 +1100,20 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { let vid = self .inner .borrow_mut() - .const_unification_table + .const_unification_table() .new_key(ConstVarValue { origin, val: ConstVariableValue::Unknown { universe } }); self.tcx.mk_const_var(vid, ty) } pub fn next_const_var_id(&self, origin: ConstVariableOrigin) -> ConstVid<'tcx> { - self.inner.borrow_mut().const_unification_table.new_key(ConstVarValue { + self.inner.borrow_mut().const_unification_table().new_key(ConstVarValue { origin, val: ConstVariableValue::Unknown { universe: self.universe() }, }) } fn next_int_var_id(&self) -> IntVid { - self.inner.borrow_mut().int_unification_table.new_key(None) + self.inner.borrow_mut().int_unification_table().new_key(None) } pub fn next_int_var(&self) -> Ty<'tcx> { @@ -1090,7 +1121,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } fn next_float_var_id(&self) -> FloatVid { - self.inner.borrow_mut().float_unification_table.new_key(None) + self.inner.borrow_mut().float_unification_table().new_key(None) } pub fn next_float_var(&self) -> Ty<'tcx> { @@ -1161,7 +1192,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { // used in a path such as `Foo::<T, U>::new()` will // use an inference variable for `C` with `[T, U]` // as the substitutions for the default, `(T, U)`. - let ty_var_id = self.inner.borrow_mut().type_variables.new_var( + let ty_var_id = self.inner.borrow_mut().type_variables().new_var( self.universe(), false, TypeVariableOrigin { @@ -1181,7 +1212,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { span, }; let const_var_id = - self.inner.borrow_mut().const_unification_table.new_key(ConstVarValue { + self.inner.borrow_mut().const_unification_table().new_key(ConstVarValue { origin, val: ConstVariableValue::Unknown { universe: self.universe() }, }); @@ -1234,18 +1265,21 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { outlives_env: &OutlivesEnvironment<'tcx>, mode: RegionckMode, ) { - assert!( - self.is_tainted_by_errors() || self.inner.borrow().region_obligations.is_empty(), - "region_obligations not empty: {:#?}", - self.inner.borrow().region_obligations - ); - let (var_infos, data) = self - .inner - .borrow_mut() - .region_constraints - .take() - .expect("regions already resolved") - .into_infos_and_data(); + let (var_infos, data) = { + let mut inner = self.inner.borrow_mut(); + let inner = &mut *inner; + assert!( + self.is_tainted_by_errors() || inner.region_obligations.is_empty(), + "region_obligations not empty: {:#?}", + inner.region_obligations + ); + inner + .region_constraint_storage + .take() + .expect("regions already resolved") + .with_log(&mut inner.undo_log) + .into_infos_and_data() + }; let region_rels = &RegionRelations::new( self.tcx, @@ -1306,12 +1340,12 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { /// called. This is used only during NLL processing to "hand off" ownership /// of the set of region variables into the NLL region context. pub fn take_region_var_origins(&self) -> VarInfos { - let (var_infos, data) = self - .inner - .borrow_mut() - .region_constraints + let mut inner = self.inner.borrow_mut(); + let (var_infos, data) = inner + .region_constraint_storage .take() .expect("regions already resolved") + .with_log(&mut inner.undo_log) .into_infos_and_data(); assert!(data.is_empty()); var_infos @@ -1335,7 +1369,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { pub fn probe_ty_var(&self, vid: TyVid) -> Result<Ty<'tcx>, ty::UniverseIndex> { use self::type_variable::TypeVariableValue; - match self.inner.borrow_mut().type_variables.probe(vid) { + match self.inner.borrow_mut().type_variables().probe(vid) { TypeVariableValue::Known { value } => Ok(value), TypeVariableValue::Unknown { universe } => Err(universe), } @@ -1357,7 +1391,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } pub fn root_var(&self, var: ty::TyVid) -> ty::TyVid { - self.inner.borrow_mut().type_variables.root_var(var) + self.inner.borrow_mut().type_variables().root_var(var) } /// Where possible, replaces type/const variables in @@ -1395,7 +1429,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { &self, vid: ty::ConstVid<'tcx>, ) -> Result<&'tcx ty::Const<'tcx>, ty::UniverseIndex> { - match self.inner.borrow_mut().const_unification_table.probe_value(vid).val { + match self.inner.borrow_mut().const_unification_table().probe_value(vid).val { ConstVariableValue::Known { value } => Ok(value), ConstVariableValue::Unknown { universe } => Err(universe), } @@ -1513,7 +1547,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { pub fn clear_caches(&self) { self.selection_cache.clear(); self.evaluation_cache.clear(); - self.inner.borrow_mut().projection_cache.clear(); + self.inner.borrow_mut().projection_cache().clear(); } fn universe(&self) -> ty::UniverseIndex { @@ -1576,14 +1610,14 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { // // Note: if these two lines are combined into one we get // dynamic borrow errors on `self.inner`. - let known = self.inner.borrow_mut().type_variables.probe(v).known(); + let known = self.inner.borrow_mut().type_variables().probe(v).known(); known.map(|t| self.shallow_resolve_ty(t)).unwrap_or(typ) } ty::Infer(ty::IntVar(v)) => self .inner .borrow_mut() - .int_unification_table + .int_unification_table() .probe_value(v) .map(|v| v.to_type(self.tcx)) .unwrap_or(typ), @@ -1591,7 +1625,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { ty::Infer(ty::FloatVar(v)) => self .inner .borrow_mut() - .float_unification_table + .float_unification_table() .probe_value(v) .map(|v| v.to_type(self.tcx)) .unwrap_or(typ), @@ -1611,13 +1645,14 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { /// having to resort to storing full `GenericArg`s in `stalled_on`. #[inline(always)] pub fn ty_or_const_infer_var_changed(&self, infer_var: TyOrConstInferVar<'tcx>) -> bool { + let mut inner = self.inner.borrow_mut(); match infer_var { TyOrConstInferVar::Ty(v) => { use self::type_variable::TypeVariableValue; // If `inlined_probe` returns a `Known` value, it never equals // `ty::Infer(ty::TyVar(v))`. - match self.inner.borrow_mut().type_variables.inlined_probe(v) { + match inner.type_variables().inlined_probe(v) { TypeVariableValue::Unknown { .. } => false, TypeVariableValue::Known { .. } => true, } @@ -1627,7 +1662,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { // If `inlined_probe_value` returns a value it's always a // `ty::Int(_)` or `ty::UInt(_)`, which never matches a // `ty::Infer(_)`. - self.inner.borrow_mut().int_unification_table.inlined_probe_value(v).is_some() + inner.int_unification_table().inlined_probe_value(v).is_some() } TyOrConstInferVar::TyFloat(v) => { @@ -1635,7 +1670,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { // `ty::Float(_)`, which never matches a `ty::Infer(_)`. // // Not `inlined_probe_value(v)` because this call site is colder. - self.inner.borrow_mut().float_unification_table.probe_value(v).is_some() + inner.float_unification_table().probe_value(v).is_some() } TyOrConstInferVar::Const(v) => { @@ -1643,7 +1678,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { // `ty::ConstKind::Infer(ty::InferConst::Var(v))`. // // Not `inlined_probe_value(v)` because this call site is colder. - match self.inner.borrow_mut().const_unification_table.probe_value(v).val { + match inner.const_unification_table().probe_value(v).val { ConstVariableValue::Unknown { .. } => false, ConstVariableValue::Known { .. } => true, } @@ -1718,7 +1753,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for ShallowResolver<'a, 'tcx> { self.infcx .inner .borrow_mut() - .const_unification_table + .const_unification_table() .probe_value(*vid) .val .known() diff --git a/src/librustc_infer/infer/nll_relate/mod.rs b/src/librustc_infer/infer/nll_relate/mod.rs index a2907e6e373..7aea26987a2 100644 --- a/src/librustc_infer/infer/nll_relate/mod.rs +++ b/src/librustc_infer/infer/nll_relate/mod.rs @@ -311,7 +311,7 @@ where match value_ty.kind { ty::Infer(ty::TyVar(value_vid)) => { // Two type variables: just equate them. - self.infcx.inner.borrow_mut().type_variables.equate(vid, value_vid); + self.infcx.inner.borrow_mut().type_variables().equate(vid, value_vid); return Ok(value_ty); } @@ -332,7 +332,7 @@ where assert!(!generalized_ty.has_infer_types_or_consts()); } - self.infcx.inner.borrow_mut().type_variables.instantiate(vid, generalized_ty); + self.infcx.inner.borrow_mut().type_variables().instantiate(vid, generalized_ty); // The generalized values we extract from `canonical_var_values` have // been fully instantiated and hence the set of scopes we have @@ -362,7 +362,7 @@ where delegate: &mut self.delegate, first_free_index: ty::INNERMOST, ambient_variance: self.ambient_variance, - for_vid_sub_root: self.infcx.inner.borrow_mut().type_variables.sub_root_var(for_vid), + for_vid_sub_root: self.infcx.inner.borrow_mut().type_variables().sub_root_var(for_vid), universe, }; @@ -859,7 +859,8 @@ where } ty::Infer(ty::TyVar(vid)) => { - let variables = &mut self.infcx.inner.borrow_mut().type_variables; + let mut inner = self.infcx.inner.borrow_mut(); + let variables = &mut inner.type_variables(); let vid = variables.root_var(vid); let sub_vid = variables.sub_root_var(vid); if sub_vid == self.for_vid_sub_root { @@ -961,7 +962,8 @@ where bug!("unexpected inference variable encountered in NLL generalization: {:?}", a); } ty::ConstKind::Infer(InferConst::Var(vid)) => { - let variable_table = &mut self.infcx.inner.borrow_mut().const_unification_table; + let mut inner = self.infcx.inner.borrow_mut(); + let variable_table = &mut inner.const_unification_table(); let var_value = variable_table.probe_value(vid); match var_value.val.known() { Some(u) => self.relate(&u, &u), diff --git a/src/librustc_infer/infer/outlives/obligations.rs b/src/librustc_infer/infer/outlives/obligations.rs index c904926e9d9..48f6d937f2f 100644 --- a/src/librustc_infer/infer/outlives/obligations.rs +++ b/src/librustc_infer/infer/outlives/obligations.rs @@ -61,13 +61,16 @@ use crate::infer::outlives::env::RegionBoundPairs; use crate::infer::outlives::verify::VerifyBoundCx; -use crate::infer::{self, GenericKind, InferCtxt, RegionObligation, SubregionOrigin, VerifyBound}; +use crate::infer::{ + self, GenericKind, InferCtxt, RegionObligation, SubregionOrigin, UndoLog, VerifyBound, +}; use crate::traits::ObligationCause; use rustc_middle::ty::outlives::Component; use rustc_middle::ty::subst::GenericArgKind; use rustc_middle::ty::{self, Region, Ty, TyCtxt, TypeFoldable}; use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::undo_log::UndoLogs; use rustc_hir as hir; use smallvec::smallvec; @@ -84,7 +87,9 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { ) { debug!("register_region_obligation(body_id={:?}, obligation={:?})", body_id, obligation); - self.inner.borrow_mut().region_obligations.push((body_id, obligation)); + let mut inner = self.inner.borrow_mut(); + inner.undo_log.push(UndoLog::PushRegionObligation); + inner.region_obligations.push((body_id, obligation)); } pub fn register_region_obligation_with_cause( diff --git a/src/librustc_infer/infer/region_constraints/leak_check.rs b/src/librustc_infer/infer/region_constraints/leak_check.rs index 18e86162eb5..473550d5433 100644 --- a/src/librustc_infer/infer/region_constraints/leak_check.rs +++ b/src/librustc_infer/infer/region_constraints/leak_check.rs @@ -1,9 +1,10 @@ use super::*; use crate::infer::{CombinedSnapshot, PlaceholderMap}; +use rustc_data_structures::undo_log::UndoLogs; use rustc_middle::ty::error::TypeError; use rustc_middle::ty::relate::RelateResult; -impl<'tcx> RegionConstraintCollector<'tcx> { +impl<'tcx> RegionConstraintCollector<'_, 'tcx> { /// Searches region constraints created since `snapshot` that /// affect one of the placeholders in `placeholder_map`, returning /// an error if any of the placeholders are related to another @@ -31,7 +32,7 @@ impl<'tcx> RegionConstraintCollector<'tcx> { ) -> RelateResult<'tcx, ()> { debug!("leak_check(placeholders={:?})", placeholder_map); - assert!(self.in_snapshot()); + assert!(UndoLogs::<super::UndoLog<'_>>::in_snapshot(&self.undo_log)); // Go through each placeholder that we created. for &placeholder_region in placeholder_map.values() { @@ -45,7 +46,11 @@ impl<'tcx> RegionConstraintCollector<'tcx> { // in some way. This means any region that either outlives // or is outlived by a placeholder. let mut taint_set = TaintSet::new(TaintDirections::both(), placeholder_region); - taint_set.fixed_point(tcx, &self.undo_log, &self.data.verifys); + taint_set.fixed_point( + tcx, + self.undo_log.region_constraints(), + &self.storage.data.verifys, + ); let tainted_regions = taint_set.into_set(); // Report an error if two placeholders in the same universe @@ -88,19 +93,21 @@ impl<'tcx> TaintSet<'tcx> { TaintSet { directions, regions } } - fn fixed_point( + fn fixed_point<'a>( &mut self, tcx: TyCtxt<'tcx>, - undo_log: &[UndoLog<'tcx>], + undo_log: impl IntoIterator<Item = &'a UndoLog<'tcx>> + Clone, verifys: &[Verify<'tcx>], - ) { + ) where + 'tcx: 'a, + { let mut prev_len = 0; while prev_len < self.len() { debug!("tainted: prev_len = {:?} new_len = {:?}", prev_len, self.len()); prev_len = self.len(); - for undo_entry in undo_log { + for undo_entry in undo_log.clone() { match undo_entry { &AddConstraint(Constraint::VarSubVar(a, b)) => { self.add_edge(tcx.mk_region(ReVar(a)), tcx.mk_region(ReVar(b))); diff --git a/src/librustc_infer/infer/region_constraints/mod.rs b/src/librustc_infer/infer/region_constraints/mod.rs index 2be6ec4481c..0c9f002a2a2 100644 --- a/src/librustc_infer/infer/region_constraints/mod.rs +++ b/src/librustc_infer/infer/region_constraints/mod.rs @@ -4,11 +4,15 @@ use self::CombineMapType::*; use self::UndoLog::*; use super::unify_key; -use super::{MiscVariable, RegionVariableOrigin, SubregionOrigin}; +use super::{ + InferCtxtUndoLogs, MiscVariable, RegionVariableOrigin, Rollback, Snapshot, SubregionOrigin, +}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::sync::Lrc; +use rustc_data_structures::undo_log::UndoLogs; use rustc_data_structures::unify as ut; +use rustc_data_structures::unify::UnifyKey; use rustc_hir::def_id::DefId; use rustc_index::vec::IndexVec; use rustc_middle::ty::ReStatic; @@ -26,7 +30,7 @@ mod leak_check; pub use rustc_middle::infer::MemberConstraint; #[derive(Default)] -pub struct RegionConstraintCollector<'tcx> { +pub struct RegionConstraintStorage<'tcx> { /// For each `RegionVid`, the corresponding `RegionVariableOrigin`. var_infos: IndexVec<RegionVid, RegionVariableInfo>, @@ -42,20 +46,6 @@ pub struct RegionConstraintCollector<'tcx> { /// exist). This prevents us from making many such regions. glbs: CombineMap<'tcx>, - /// The undo log records actions that might later be undone. - /// - /// Note: `num_open_snapshots` is used to track if we are actively - /// snapshotting. When the `start_snapshot()` method is called, we - /// increment `num_open_snapshots` to indicate that we are now actively - /// snapshotting. The reason for this is that otherwise we end up adding - /// entries for things like the lower bound on a variable and so forth, - /// which can never be rolled back. - undo_log: Vec<UndoLog<'tcx>>, - - /// The number of open snapshots, i.e., those that haven't been committed or - /// rolled back. - num_open_snapshots: usize, - /// When we add a R1 == R2 constriant, we currently add (a) edges /// R1 <= R2 and R2 <= R1 and (b) we unify the two regions in this /// table. You can then call `opportunistic_resolve_var` early @@ -64,13 +54,31 @@ pub struct RegionConstraintCollector<'tcx> { /// is iterating to a fixed point, because otherwise we sometimes /// would wind up with a fresh stream of region variables that /// have been equated but appear distinct. - unification_table: ut::UnificationTable<ut::InPlace<ty::RegionVid>>, + pub(super) unification_table: ut::UnificationTableStorage<ty::RegionVid>, /// a flag set to true when we perform any unifications; this is used /// to micro-optimize `take_and_reset_data` any_unifications: bool, } +pub struct RegionConstraintCollector<'a, 'tcx> { + storage: &'a mut RegionConstraintStorage<'tcx>, + undo_log: &'a mut InferCtxtUndoLogs<'tcx>, +} + +impl std::ops::Deref for RegionConstraintCollector<'_, 'tcx> { + type Target = RegionConstraintStorage<'tcx>; + fn deref(&self) -> &RegionConstraintStorage<'tcx> { + self.storage + } +} + +impl std::ops::DerefMut for RegionConstraintCollector<'_, 'tcx> { + fn deref_mut(&mut self) -> &mut RegionConstraintStorage<'tcx> { + self.storage + } +} + pub type VarInfos = IndexVec<RegionVid, RegionVariableInfo>; /// The full set of region constraints gathered up by the collector. @@ -258,13 +266,13 @@ pub enum VerifyBound<'tcx> { } #[derive(Copy, Clone, PartialEq, Eq, Hash)] -struct TwoRegions<'tcx> { +pub(crate) struct TwoRegions<'tcx> { a: Region<'tcx>, b: Region<'tcx>, } #[derive(Copy, Clone, PartialEq)] -enum UndoLog<'tcx> { +pub(crate) enum UndoLog<'tcx> { /// We added `RegionVid`. AddVar(RegionVid), @@ -290,7 +298,7 @@ enum UndoLog<'tcx> { } #[derive(Copy, Clone, PartialEq)] -enum CombineMapType { +pub(crate) enum CombineMapType { Lub, Glb, } @@ -304,8 +312,6 @@ pub struct RegionVariableInfo { } pub struct RegionSnapshot { - length: usize, - region_snapshot: ut::Snapshot<ut::InPlace<ty::RegionVid>>, any_unifications: bool, } @@ -334,11 +340,48 @@ impl TaintDirections { } } -impl<'tcx> RegionConstraintCollector<'tcx> { +impl<'tcx> RegionConstraintStorage<'tcx> { pub fn new() -> Self { Self::default() } + pub(crate) fn with_log<'a>( + &'a mut self, + undo_log: &'a mut InferCtxtUndoLogs<'tcx>, + ) -> RegionConstraintCollector<'a, 'tcx> { + RegionConstraintCollector { storage: self, undo_log } + } + + fn rollback_undo_entry(&mut self, undo_entry: UndoLog<'tcx>) { + match undo_entry { + Purged => { + // nothing to do here + } + AddVar(vid) => { + self.var_infos.pop().unwrap(); + assert_eq!(self.var_infos.len(), vid.index() as usize); + } + AddConstraint(ref constraint) => { + self.data.constraints.remove(constraint); + } + AddVerify(index) => { + self.data.verifys.pop(); + assert_eq!(self.data.verifys.len(), index); + } + AddGiven(sub, sup) => { + self.data.givens.remove(&(sub, sup)); + } + AddCombination(Glb, ref regions) => { + self.glbs.remove(regions); + } + AddCombination(Lub, ref regions) => { + self.lubs.remove(regions); + } + } + } +} + +impl<'tcx> RegionConstraintCollector<'_, 'tcx> { pub fn num_region_vars(&self) -> usize { self.var_infos.len() } @@ -351,8 +394,8 @@ impl<'tcx> RegionConstraintCollector<'tcx> { /// /// Not legal during a snapshot. pub fn into_infos_and_data(self) -> (VarInfos, RegionConstraintData<'tcx>) { - assert!(!self.in_snapshot()); - (self.var_infos, self.data) + assert!(!UndoLogs::<super::UndoLog<'_>>::in_snapshot(&self.undo_log)); + (mem::take(&mut self.storage.var_infos), mem::take(&mut self.storage.data)) } /// Takes (and clears) the current set of constraints. Note that @@ -368,21 +411,19 @@ impl<'tcx> RegionConstraintCollector<'tcx> { /// /// Not legal during a snapshot. pub fn take_and_reset_data(&mut self) -> RegionConstraintData<'tcx> { - assert!(!self.in_snapshot()); + assert!(!UndoLogs::<super::UndoLog<'_>>::in_snapshot(&self.undo_log)); // If you add a new field to `RegionConstraintCollector`, you // should think carefully about whether it needs to be cleared // or updated in some way. - let RegionConstraintCollector { + let RegionConstraintStorage { var_infos: _, data, lubs, glbs, - undo_log: _, - num_open_snapshots: _, - unification_table, + unification_table: _, any_unifications, - } = self; + } = self.storage; // Clear the tables of (lubs, glbs), so that we will create // fresh regions if we do a LUB operation. As it happens, @@ -391,102 +432,35 @@ impl<'tcx> RegionConstraintCollector<'tcx> { lubs.clear(); glbs.clear(); + let data = mem::take(data); + // Clear all unifications and recreate the variables a "now // un-unified" state. Note that when we unify `a` and `b`, we // also insert `a <= b` and a `b <= a` edges, so the // `RegionConstraintData` contains the relationship here. if *any_unifications { - unification_table.reset_unifications(|vid| unify_key::RegionVidKey { min_vid: vid }); *any_unifications = false; + self.unification_table() + .reset_unifications(|vid| unify_key::RegionVidKey { min_vid: vid }); } - mem::take(data) + data } pub fn data(&self) -> &RegionConstraintData<'tcx> { &self.data } - fn in_snapshot(&self) -> bool { - self.num_open_snapshots > 0 - } - pub fn start_snapshot(&mut self) -> RegionSnapshot { - let length = self.undo_log.len(); - debug!("RegionConstraintCollector: start_snapshot({})", length); - self.num_open_snapshots += 1; - RegionSnapshot { - length, - region_snapshot: self.unification_table.snapshot(), - any_unifications: self.any_unifications, - } - } - - fn assert_open_snapshot(&self, snapshot: &RegionSnapshot) { - assert!(self.undo_log.len() >= snapshot.length); - assert!(self.num_open_snapshots > 0); - } - - pub fn commit(&mut self, snapshot: RegionSnapshot) { - debug!("RegionConstraintCollector: commit({})", snapshot.length); - self.assert_open_snapshot(&snapshot); - - if self.num_open_snapshots == 1 { - // The root snapshot. It's safe to clear the undo log because - // there's no snapshot further out that we might need to roll back - // to. - assert!(snapshot.length == 0); - self.undo_log.clear(); - } - - self.num_open_snapshots -= 1; - - self.unification_table.commit(snapshot.region_snapshot); + debug!("RegionConstraintCollector: start_snapshot"); + RegionSnapshot { any_unifications: self.any_unifications } } pub fn rollback_to(&mut self, snapshot: RegionSnapshot) { debug!("RegionConstraintCollector: rollback_to({:?})", snapshot); - self.assert_open_snapshot(&snapshot); - - while self.undo_log.len() > snapshot.length { - let undo_entry = self.undo_log.pop().unwrap(); - self.rollback_undo_entry(undo_entry); - } - - self.num_open_snapshots -= 1; - - self.unification_table.rollback_to(snapshot.region_snapshot); self.any_unifications = snapshot.any_unifications; } - fn rollback_undo_entry(&mut self, undo_entry: UndoLog<'tcx>) { - match undo_entry { - Purged => { - // nothing to do here - } - AddVar(vid) => { - self.var_infos.pop().unwrap(); - assert_eq!(self.var_infos.len(), vid.index() as usize); - } - AddConstraint(ref constraint) => { - self.data.constraints.remove(constraint); - } - AddVerify(index) => { - self.data.verifys.pop(); - assert_eq!(self.data.verifys.len(), index); - } - AddGiven(sub, sup) => { - self.data.givens.remove(&(sub, sup)); - } - AddCombination(Glb, ref regions) => { - self.glbs.remove(regions); - } - AddCombination(Lub, ref regions) => { - self.lubs.remove(regions); - } - } - } - pub fn new_region_var( &mut self, universe: ty::UniverseIndex, @@ -494,11 +468,9 @@ impl<'tcx> RegionConstraintCollector<'tcx> { ) -> RegionVid { let vid = self.var_infos.push(RegionVariableInfo { origin, universe }); - let u_vid = self.unification_table.new_key(unify_key::RegionVidKey { min_vid: vid }); + let u_vid = self.unification_table().new_key(unify_key::RegionVidKey { min_vid: vid }); assert_eq!(vid, u_vid); - if self.in_snapshot() { - self.undo_log.push(AddVar(vid)); - } + self.undo_log.push(AddVar(vid)); debug!("created new region variable {:?} in {:?} with origin {:?}", vid, universe, origin); vid } @@ -520,19 +492,29 @@ impl<'tcx> RegionConstraintCollector<'tcx> { pub fn pop_placeholders(&mut self, placeholders: &FxHashSet<ty::Region<'tcx>>) { debug!("pop_placeholders(placeholders={:?})", placeholders); - assert!(self.in_snapshot()); + assert!(UndoLogs::<super::UndoLog<'_>>::in_snapshot(&self.undo_log)); let constraints_to_kill: Vec<usize> = self .undo_log .iter() .enumerate() .rev() - .filter(|&(_, undo_entry)| kill_constraint(placeholders, undo_entry)) + .filter(|&(_, undo_entry)| match undo_entry { + super::UndoLog::RegionConstraintCollector(undo_entry) => { + kill_constraint(placeholders, undo_entry) + } + _ => false, + }) .map(|(index, _)| index) .collect(); for index in constraints_to_kill { - let undo_entry = mem::replace(&mut self.undo_log[index], Purged); + let undo_entry = match &mut self.undo_log[index] { + super::UndoLog::RegionConstraintCollector(undo_entry) => { + mem::replace(undo_entry, Purged) + } + _ => unreachable!(), + }; self.rollback_undo_entry(undo_entry); } @@ -566,12 +548,9 @@ impl<'tcx> RegionConstraintCollector<'tcx> { // never overwrite an existing (constraint, origin) - only insert one if it isn't // present in the map yet. This prevents origins from outside the snapshot being // replaced with "less informative" origins e.g., during calls to `can_eq` - let in_snapshot = self.in_snapshot(); let undo_log = &mut self.undo_log; - self.data.constraints.entry(constraint).or_insert_with(|| { - if in_snapshot { - undo_log.push(AddConstraint(constraint)); - } + self.storage.data.constraints.entry(constraint).or_insert_with(|| { + undo_log.push(AddConstraint(constraint)); origin }); } @@ -589,9 +568,7 @@ impl<'tcx> RegionConstraintCollector<'tcx> { let index = self.data.verifys.len(); self.data.verifys.push(verify); - if self.in_snapshot() { - self.undo_log.push(AddVerify(index)); - } + self.undo_log.push(AddVerify(index)); } pub fn add_given(&mut self, sub: Region<'tcx>, sup: ty::RegionVid) { @@ -599,9 +576,7 @@ impl<'tcx> RegionConstraintCollector<'tcx> { if self.data.givens.insert((sub, sup)) { debug!("add_given({:?} <= {:?})", sub, sup); - if self.in_snapshot() { - self.undo_log.push(AddGiven(sub, sup)); - } + self.undo_log.push(AddGiven(sub, sup)); } } @@ -619,7 +594,7 @@ impl<'tcx> RegionConstraintCollector<'tcx> { if let (ty::ReVar(sub), ty::ReVar(sup)) = (*sub, *sup) { debug!("make_eqregion: uniying {:?} with {:?}", sub, sup); - self.unification_table.union(sub, sup); + self.unification_table().union(sub, sup); self.any_unifications = true; } } @@ -741,7 +716,7 @@ impl<'tcx> RegionConstraintCollector<'tcx> { tcx: TyCtxt<'tcx>, rid: RegionVid, ) -> ty::Region<'tcx> { - let vid = self.unification_table.probe_value(rid).min_vid; + let vid = self.unification_table().probe_value(rid).min_vid; tcx.mk_region(ty::ReVar(vid)) } @@ -769,9 +744,7 @@ impl<'tcx> RegionConstraintCollector<'tcx> { let c_universe = cmp::max(a_universe, b_universe); let c = self.new_region_var(c_universe, MiscVariable(origin.span())); self.combine_map(t).insert(vars, c); - if self.in_snapshot() { - self.undo_log.push(AddCombination(t, vars)); - } + self.undo_log.push(AddCombination(t, vars)); let new_r = tcx.mk_region(ReVar(c)); for &old_r in &[a, b] { match t { @@ -799,9 +772,10 @@ impl<'tcx> RegionConstraintCollector<'tcx> { pub fn vars_since_snapshot( &self, - mark: &RegionSnapshot, + value_count: usize, ) -> (Range<RegionVid>, Vec<RegionVariableOrigin>) { - let range = self.unification_table.vars_since_snapshot(&mark.region_snapshot); + let range = RegionVid::from_index(value_count as u32) + ..RegionVid::from_index(self.unification_table.len() as u32); ( range.clone(), (range.start.index()..range.end.index()) @@ -810,10 +784,10 @@ impl<'tcx> RegionConstraintCollector<'tcx> { ) } - /// See `InferCtxt::region_constraints_added_in_snapshot`. - pub fn region_constraints_added_in_snapshot(&self, mark: &RegionSnapshot) -> Option<bool> { - self.undo_log[mark.length..] - .iter() + /// See [`RegionInference::region_constraints_added_in_snapshot`]. + pub fn region_constraints_added_in_snapshot(&self, mark: &Snapshot<'tcx>) -> Option<bool> { + self.undo_log + .region_constraints_in_snapshot(mark) .map(|&elt| match elt { AddConstraint(constraint) => Some(constraint.involves_placeholders()), _ => None, @@ -821,11 +795,15 @@ impl<'tcx> RegionConstraintCollector<'tcx> { .max() .unwrap_or(None) } + + fn unification_table(&mut self) -> super::UnificationTable<'_, 'tcx, ty::RegionVid> { + ut::UnificationTable::with_log(&mut self.storage.unification_table, self.undo_log) + } } impl fmt::Debug for RegionSnapshot { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "RegionSnapshot(length={})", self.length) + write!(f, "RegionSnapshot") } } @@ -910,3 +888,9 @@ impl<'tcx> RegionConstraintData<'tcx> { && givens.is_empty() } } + +impl<'tcx> Rollback<UndoLog<'tcx>> for RegionConstraintStorage<'tcx> { + fn reverse(&mut self, undo: UndoLog<'tcx>) { + self.rollback_undo_entry(undo) + } +} diff --git a/src/librustc_infer/infer/resolve.rs b/src/librustc_infer/infer/resolve.rs index bd9d108cfe8..e28cf49c7f2 100644 --- a/src/librustc_infer/infer/resolve.rs +++ b/src/librustc_infer/infer/resolve.rs @@ -123,7 +123,8 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for UnresolvedTypeFinder<'a, 'tcx> { // Since we called `shallow_resolve` above, this must // be an (as yet...) unresolved inference variable. let ty_var_span = if let ty::TyVar(ty_vid) = infer_ty { - let ty_vars = &self.infcx.inner.borrow().type_variables; + let mut inner = self.infcx.inner.borrow_mut(); + let ty_vars = &inner.type_variables(); if let TypeVariableOrigin { kind: TypeVariableOriginKind::TypeParameterDefinition(_, _), span, diff --git a/src/librustc_infer/infer/sub.rs b/src/librustc_infer/infer/sub.rs index 080af37492d..0abcc15d6fc 100644 --- a/src/librustc_infer/infer/sub.rs +++ b/src/librustc_infer/infer/sub.rs @@ -80,8 +80,8 @@ impl TypeRelation<'tcx> for Sub<'combine, 'infcx, 'tcx> { } let infcx = self.fields.infcx; - let a = infcx.inner.borrow_mut().type_variables.replace_if_possible(a); - let b = infcx.inner.borrow_mut().type_variables.replace_if_possible(b); + let a = infcx.inner.borrow_mut().type_variables().replace_if_possible(a); + let b = infcx.inner.borrow_mut().type_variables().replace_if_possible(b); match (&a.kind, &b.kind) { (&ty::Infer(TyVar(a_vid)), &ty::Infer(TyVar(b_vid))) => { // Shouldn't have any LBR here, so we can safely put @@ -95,7 +95,7 @@ impl TypeRelation<'tcx> for Sub<'combine, 'infcx, 'tcx> { // have to record in the `type_variables` tracker that // the two variables are equal modulo subtyping, which // is important to the occurs check later on. - infcx.inner.borrow_mut().type_variables.sub(a_vid, b_vid); + infcx.inner.borrow_mut().type_variables().sub(a_vid, b_vid); self.fields.obligations.push(Obligation::new( self.fields.trace.cause.clone(), self.fields.param_env, diff --git a/src/librustc_infer/infer/type_variable.rs b/src/librustc_infer/infer/type_variable.rs index 1de820cdb62..f68692391a2 100644 --- a/src/librustc_infer/infer/type_variable.rs +++ b/src/librustc_infer/infer/type_variable.rs @@ -3,19 +3,68 @@ use rustc_middle::ty::{self, Ty, TyVid}; use rustc_span::symbol::Symbol; use rustc_span::Span; +use crate::infer::InferCtxtUndoLogs; + use rustc_data_structures::snapshot_vec as sv; use rustc_data_structures::unify as ut; use std::cmp; use std::marker::PhantomData; use std::ops::Range; -pub struct TypeVariableTable<'tcx> { - values: sv::SnapshotVec<Delegate>, +use rustc_data_structures::undo_log::{Rollback, UndoLogs}; + +/// Represents a single undo-able action that affects a type inference variable. +pub(crate) enum UndoLog<'tcx> { + EqRelation(sv::UndoLog<ut::Delegate<TyVidEqKey<'tcx>>>), + SubRelation(sv::UndoLog<ut::Delegate<ty::TyVid>>), + Values(sv::UndoLog<Delegate>), +} + +/// Convert from a specific kind of undo to the more general UndoLog +impl<'tcx> From<sv::UndoLog<ut::Delegate<TyVidEqKey<'tcx>>>> for UndoLog<'tcx> { + fn from(l: sv::UndoLog<ut::Delegate<TyVidEqKey<'tcx>>>) -> Self { + UndoLog::EqRelation(l) + } +} + +/// Convert from a specific kind of undo to the more general UndoLog +impl<'tcx> From<sv::UndoLog<ut::Delegate<ty::TyVid>>> for UndoLog<'tcx> { + fn from(l: sv::UndoLog<ut::Delegate<ty::TyVid>>) -> Self { + UndoLog::SubRelation(l) + } +} + +/// Convert from a specific kind of undo to the more general UndoLog +impl<'tcx> From<sv::UndoLog<Delegate>> for UndoLog<'tcx> { + fn from(l: sv::UndoLog<Delegate>) -> Self { + UndoLog::Values(l) + } +} + +/// Convert from a specific kind of undo to the more general UndoLog +impl<'tcx> From<Instantiate> for UndoLog<'tcx> { + fn from(l: Instantiate) -> Self { + UndoLog::Values(sv::UndoLog::Other(l)) + } +} + +impl<'tcx> Rollback<UndoLog<'tcx>> for TypeVariableStorage<'tcx> { + fn reverse(&mut self, undo: UndoLog<'tcx>) { + match undo { + UndoLog::EqRelation(undo) => self.eq_relations.reverse(undo), + UndoLog::SubRelation(undo) => self.sub_relations.reverse(undo), + UndoLog::Values(undo) => self.values.reverse(undo), + } + } +} + +pub struct TypeVariableStorage<'tcx> { + values: sv::SnapshotVecStorage<Delegate>, /// Two variables are unified in `eq_relations` when we have a /// constraint `?X == ?Y`. This table also stores, for each key, /// the known value. - eq_relations: ut::UnificationTable<ut::InPlace<TyVidEqKey<'tcx>>>, + eq_relations: ut::UnificationTableStorage<TyVidEqKey<'tcx>>, /// Two variables are unified in `sub_relations` when we have a /// constraint `?X <: ?Y` *or* a constraint `?Y <: ?X`. This second @@ -34,7 +83,17 @@ pub struct TypeVariableTable<'tcx> { /// This is reasonable because, in Rust, subtypes have the same /// "skeleton" and hence there is no possible type such that /// (e.g.) `Box<?3> <: ?3` for any `?3`. - sub_relations: ut::UnificationTable<ut::InPlace<ty::TyVid>>, + sub_relations: ut::UnificationTableStorage<ty::TyVid>, +} + +pub struct TypeVariableTable<'a, 'tcx> { + values: &'a mut sv::SnapshotVecStorage<Delegate>, + + eq_relations: &'a mut ut::UnificationTableStorage<TyVidEqKey<'tcx>>, + + sub_relations: &'a mut ut::UnificationTableStorage<ty::TyVid>, + + undo_log: &'a mut InferCtxtUndoLogs<'tcx>, } #[derive(Copy, Clone, Debug)] @@ -62,7 +121,7 @@ pub enum TypeVariableOriginKind { LatticeVariable, } -struct TypeVariableData { +pub(crate) struct TypeVariableData { origin: TypeVariableOrigin, diverging: bool, } @@ -91,27 +150,31 @@ impl<'tcx> TypeVariableValue<'tcx> { } } -pub struct Snapshot<'tcx> { - snapshot: sv::Snapshot, - eq_snapshot: ut::Snapshot<ut::InPlace<TyVidEqKey<'tcx>>>, - sub_snapshot: ut::Snapshot<ut::InPlace<ty::TyVid>>, -} - -struct Instantiate { +pub(crate) struct Instantiate { vid: ty::TyVid, } -struct Delegate; +pub(crate) struct Delegate; -impl<'tcx> TypeVariableTable<'tcx> { - pub fn new() -> TypeVariableTable<'tcx> { - TypeVariableTable { - values: sv::SnapshotVec::new(), - eq_relations: ut::UnificationTable::new(), - sub_relations: ut::UnificationTable::new(), +impl<'tcx> TypeVariableStorage<'tcx> { + pub fn new() -> TypeVariableStorage<'tcx> { + TypeVariableStorage { + values: sv::SnapshotVecStorage::new(), + eq_relations: ut::UnificationTableStorage::new(), + sub_relations: ut::UnificationTableStorage::new(), } } + pub(crate) fn with_log<'a>( + &'a mut self, + undo_log: &'a mut InferCtxtUndoLogs<'tcx>, + ) -> TypeVariableTable<'a, 'tcx> { + let TypeVariableStorage { values, eq_relations, sub_relations } = self; + TypeVariableTable { values, eq_relations, sub_relations, undo_log } + } +} + +impl<'tcx> TypeVariableTable<'_, 'tcx> { /// Returns the diverges flag given when `vid` was created. /// /// Note that this function does not return care whether @@ -134,8 +197,8 @@ impl<'tcx> TypeVariableTable<'tcx> { pub fn equate(&mut self, a: ty::TyVid, b: ty::TyVid) { debug_assert!(self.probe(a).is_unknown()); debug_assert!(self.probe(b).is_unknown()); - self.eq_relations.union(a, b); - self.sub_relations.union(a, b); + self.eq_relations().union(a, b); + self.sub_relations().union(a, b); } /// Records that `a <: b`, depending on `dir`. @@ -144,7 +207,7 @@ impl<'tcx> TypeVariableTable<'tcx> { pub fn sub(&mut self, a: ty::TyVid, b: ty::TyVid) { debug_assert!(self.probe(a).is_unknown()); debug_assert!(self.probe(b).is_unknown()); - self.sub_relations.union(a, b); + self.sub_relations().union(a, b); } /// Instantiates `vid` with the type `ty`. @@ -154,18 +217,18 @@ impl<'tcx> TypeVariableTable<'tcx> { let vid = self.root_var(vid); debug_assert!(self.probe(vid).is_unknown()); debug_assert!( - self.eq_relations.probe_value(vid).is_unknown(), + self.eq_relations().probe_value(vid).is_unknown(), "instantiating type variable `{:?}` twice: new-value = {:?}, old-value={:?}", vid, ty, - self.eq_relations.probe_value(vid) + self.eq_relations().probe_value(vid) ); - self.eq_relations.union_value(vid, TypeVariableValue::Known { value: ty }); + self.eq_relations().union_value(vid, TypeVariableValue::Known { value: ty }); // Hack: we only need this so that `types_escaping_snapshot` // can see what has been unified; see the Delegate impl for // more details. - self.values.record(Instantiate { vid }); + self.undo_log.push(Instantiate { vid }); } /// Creates a new type variable. @@ -184,12 +247,12 @@ impl<'tcx> TypeVariableTable<'tcx> { diverging: bool, origin: TypeVariableOrigin, ) -> ty::TyVid { - let eq_key = self.eq_relations.new_key(TypeVariableValue::Unknown { universe }); + let eq_key = self.eq_relations().new_key(TypeVariableValue::Unknown { universe }); - let sub_key = self.sub_relations.new_key(()); + let sub_key = self.sub_relations().new_key(()); assert_eq!(eq_key.vid, sub_key); - let index = self.values.push(TypeVariableData { origin, diverging }); + let index = self.values().push(TypeVariableData { origin, diverging }); assert_eq!(eq_key.vid.index, index as u32); debug!( @@ -211,7 +274,7 @@ impl<'tcx> TypeVariableTable<'tcx> { /// algorithm), so `root_var(a) == root_var(b)` implies that `a == /// b` (transitively). pub fn root_var(&mut self, vid: ty::TyVid) -> ty::TyVid { - self.eq_relations.find(vid).vid + self.eq_relations().find(vid).vid } /// Returns the "root" variable of `vid` in the `sub_relations` @@ -222,7 +285,7 @@ impl<'tcx> TypeVariableTable<'tcx> { /// /// exists X. (a <: X || X <: a) && (b <: X || X <: b) pub fn sub_root_var(&mut self, vid: ty::TyVid) -> ty::TyVid { - self.sub_relations.find(vid) + self.sub_relations().find(vid) } /// Returns `true` if `a` and `b` have same "sub-root" (i.e., exists some @@ -240,7 +303,7 @@ impl<'tcx> TypeVariableTable<'tcx> { /// An always-inlined variant of `probe`, for very hot call sites. #[inline(always)] pub fn inlined_probe(&mut self, vid: ty::TyVid) -> TypeVariableValue<'tcx> { - self.eq_relations.inlined_probe_value(vid) + self.eq_relations().inlined_probe_value(vid) } /// If `t` is a type-inference variable, and it has been @@ -256,56 +319,29 @@ impl<'tcx> TypeVariableTable<'tcx> { } } - /// Creates a snapshot of the type variable state. This snapshot - /// must later be committed (`commit()`) or rolled back - /// (`rollback_to()`). Nested snapshots are permitted, but must - /// be processed in a stack-like fashion. - pub fn snapshot(&mut self) -> Snapshot<'tcx> { - Snapshot { - snapshot: self.values.start_snapshot(), - eq_snapshot: self.eq_relations.snapshot(), - sub_snapshot: self.sub_relations.snapshot(), - } + fn values( + &mut self, + ) -> sv::SnapshotVec<Delegate, &mut Vec<TypeVariableData>, &mut InferCtxtUndoLogs<'tcx>> { + self.values.with_log(self.undo_log) } - /// Undoes all changes since the snapshot was created. Any - /// snapshots created since that point must already have been - /// committed or rolled back. - pub fn rollback_to(&mut self, s: Snapshot<'tcx>) { - debug!("rollback_to{:?}", { - for action in self.values.actions_since_snapshot(&s.snapshot) { - if let sv::UndoLog::NewElem(index) = *action { - debug!("inference variable _#{}t popped", index) - } - } - }); - - let Snapshot { snapshot, eq_snapshot, sub_snapshot } = s; - self.values.rollback_to(snapshot); - self.eq_relations.rollback_to(eq_snapshot); - self.sub_relations.rollback_to(sub_snapshot); + fn eq_relations(&mut self) -> super::UnificationTable<'_, 'tcx, TyVidEqKey<'tcx>> { + self.eq_relations.with_log(self.undo_log) } - /// Commits all changes since the snapshot was created, making - /// them permanent (unless this snapshot was created within - /// another snapshot). Any snapshots created since that point - /// must already have been committed or rolled back. - pub fn commit(&mut self, s: Snapshot<'tcx>) { - let Snapshot { snapshot, eq_snapshot, sub_snapshot } = s; - self.values.commit(snapshot); - self.eq_relations.commit(eq_snapshot); - self.sub_relations.commit(sub_snapshot); + fn sub_relations(&mut self) -> super::UnificationTable<'_, 'tcx, ty::TyVid> { + self.sub_relations.with_log(self.undo_log) } /// Returns a range of the type variables created during the snapshot. pub fn vars_since_snapshot( &mut self, - s: &Snapshot<'tcx>, + value_count: usize, ) -> (Range<TyVid>, Vec<TypeVariableOrigin>) { - let range = self.eq_relations.vars_since_snapshot(&s.eq_snapshot); + let range = TyVid { index: value_count as u32 }..TyVid { index: self.num_vars() as u32 }; ( - range.start.vid..range.end.vid, - (range.start.vid.index..range.end.vid.index) + range.start..range.end, + (range.start.index..range.end.index) .map(|index| self.values.get(index as usize).origin) .collect(), ) @@ -317,14 +353,15 @@ impl<'tcx> TypeVariableTable<'tcx> { /// a type variable `V0`, then we started the snapshot, then we /// created a type variable `V1`, unified `V0` with `T0`, and /// unified `V1` with `T1`, this function would return `{T0}`. - pub fn types_escaping_snapshot(&mut self, s: &Snapshot<'tcx>) -> Vec<Ty<'tcx>> { + pub fn types_escaping_snapshot(&mut self, s: &super::Snapshot<'tcx>) -> Vec<Ty<'tcx>> { let mut new_elem_threshold = u32::MAX; let mut escaping_types = Vec::new(); - let actions_since_snapshot = self.values.actions_since_snapshot(&s.snapshot); + let actions_since_snapshot = self.undo_log.actions_since_snapshot(s); debug!("actions_since_snapshot.len() = {}", actions_since_snapshot.len()); - for action in actions_since_snapshot { - match *action { - sv::UndoLog::NewElem(index) => { + for i in 0..actions_since_snapshot.len() { + let actions_since_snapshot = self.undo_log.actions_since_snapshot(s); + match actions_since_snapshot[i] { + super::UndoLog::TypeVariables(UndoLog::Values(sv::UndoLog::NewElem(index))) => { // if any new variables were created during the // snapshot, remember the lower index (which will // always be the first one we see). Note that this @@ -334,11 +371,17 @@ impl<'tcx> TypeVariableTable<'tcx> { debug!("NewElem({}) new_elem_threshold={}", index, new_elem_threshold); } - sv::UndoLog::Other(Instantiate { vid, .. }) => { + super::UndoLog::TypeVariables(UndoLog::Values(sv::UndoLog::Other( + Instantiate { vid, .. }, + ))) => { if vid.index < new_elem_threshold { // quick check to see if this variable was // created since the snapshot started or not. - let escaping_type = match self.eq_relations.probe_value(vid) { + let mut eq_relations = ut::UnificationTable::with_log( + &mut *self.eq_relations, + &mut *self.undo_log, + ); + let escaping_type = match eq_relations.probe_value(vid) { TypeVariableValue::Unknown { .. } => bug!(), TypeVariableValue::Known { value } => value, }; @@ -395,7 +438,7 @@ impl sv::SnapshotVecDelegate for Delegate { /// for the `eq_relations`; they carry a `TypeVariableValue` along /// with them. #[derive(Copy, Clone, Debug, PartialEq, Eq)] -struct TyVidEqKey<'tcx> { +pub(crate) struct TyVidEqKey<'tcx> { vid: ty::TyVid, // in the table, we map each ty-vid to one of these: diff --git a/src/librustc_infer/infer/undo_log.rs b/src/librustc_infer/infer/undo_log.rs new file mode 100644 index 00000000000..56cb182dbf0 --- /dev/null +++ b/src/librustc_infer/infer/undo_log.rs @@ -0,0 +1,217 @@ +use std::marker::PhantomData; + +use rustc_data_structures::snapshot_vec as sv; +use rustc_data_structures::undo_log::{Rollback, UndoLogs}; +use rustc_data_structures::unify as ut; +use rustc_middle::ty; + +use crate::{ + infer::{region_constraints, type_variable, InferCtxtInner}, + traits, +}; + +pub struct Snapshot<'tcx> { + pub(crate) undo_len: usize, + _marker: PhantomData<&'tcx ()>, +} + +/// Records the 'undo' data fora single operation that affects some form of inference variable. +pub(crate) enum UndoLog<'tcx> { + TypeVariables(type_variable::UndoLog<'tcx>), + ConstUnificationTable(sv::UndoLog<ut::Delegate<ty::ConstVid<'tcx>>>), + IntUnificationTable(sv::UndoLog<ut::Delegate<ty::IntVid>>), + FloatUnificationTable(sv::UndoLog<ut::Delegate<ty::FloatVid>>), + RegionConstraintCollector(region_constraints::UndoLog<'tcx>), + RegionUnificationTable(sv::UndoLog<ut::Delegate<ty::RegionVid>>), + ProjectionCache(traits::UndoLog<'tcx>), + PushRegionObligation, +} + +macro_rules! impl_from { + ($($ctor: ident ($ty: ty),)*) => { + $( + impl<'tcx> From<$ty> for UndoLog<'tcx> { + fn from(x: $ty) -> Self { + UndoLog::$ctor(x.into()) + } + } + )* + } +} + +// Upcast from a single kind of "undoable action" to the general enum +impl_from! { + RegionConstraintCollector(region_constraints::UndoLog<'tcx>), + TypeVariables(type_variable::UndoLog<'tcx>), + + TypeVariables(sv::UndoLog<ut::Delegate<type_variable::TyVidEqKey<'tcx>>>), + TypeVariables(sv::UndoLog<ut::Delegate<ty::TyVid>>), + TypeVariables(sv::UndoLog<type_variable::Delegate>), + TypeVariables(type_variable::Instantiate), + + IntUnificationTable(sv::UndoLog<ut::Delegate<ty::IntVid>>), + + FloatUnificationTable(sv::UndoLog<ut::Delegate<ty::FloatVid>>), + + ConstUnificationTable(sv::UndoLog<ut::Delegate<ty::ConstVid<'tcx>>>), + + RegionUnificationTable(sv::UndoLog<ut::Delegate<ty::RegionVid>>), + ProjectionCache(traits::UndoLog<'tcx>), +} + +/// The Rollback trait defines how to rollback a particular action. +impl<'tcx> Rollback<UndoLog<'tcx>> for InferCtxtInner<'tcx> { + fn reverse(&mut self, undo: UndoLog<'tcx>) { + match undo { + UndoLog::TypeVariables(undo) => self.type_variable_storage.reverse(undo), + UndoLog::ConstUnificationTable(undo) => self.const_unification_storage.reverse(undo), + UndoLog::IntUnificationTable(undo) => self.int_unification_storage.reverse(undo), + UndoLog::FloatUnificationTable(undo) => self.float_unification_storage.reverse(undo), + UndoLog::RegionConstraintCollector(undo) => { + self.region_constraint_storage.as_mut().unwrap().reverse(undo) + } + UndoLog::RegionUnificationTable(undo) => { + self.region_constraint_storage.as_mut().unwrap().unification_table.reverse(undo) + } + UndoLog::ProjectionCache(undo) => self.projection_cache.reverse(undo), + UndoLog::PushRegionObligation => { + self.region_obligations.pop(); + } + } + } +} + +/// The combined undo log for all the various unification tables. For each change to the storage +/// for any kind of inference variable, we record an UndoLog entry in the vector here. +pub(crate) struct InferCtxtUndoLogs<'tcx> { + logs: Vec<UndoLog<'tcx>>, + num_open_snapshots: usize, +} + +impl Default for InferCtxtUndoLogs<'_> { + fn default() -> Self { + Self { logs: Default::default(), num_open_snapshots: Default::default() } + } +} + +/// The UndoLogs trait defines how we undo a particular kind of action (of type T). We can undo any +/// action that is convertable into a UndoLog (per the From impls above). +impl<'tcx, T> UndoLogs<T> for InferCtxtUndoLogs<'tcx> +where + UndoLog<'tcx>: From<T>, +{ + fn num_open_snapshots(&self) -> usize { + self.num_open_snapshots + } + + fn push(&mut self, undo: T) { + if self.in_snapshot() { + self.logs.push(undo.into()) + } + } + + fn clear(&mut self) { + self.logs.clear(); + self.num_open_snapshots = 0; + } + + fn extend<J>(&mut self, undos: J) + where + Self: Sized, + J: IntoIterator<Item = T>, + { + if self.in_snapshot() { + self.logs.extend(undos.into_iter().map(UndoLog::from)) + } + } +} + +impl<'tcx> InferCtxtInner<'tcx> { + pub fn rollback_to(&mut self, snapshot: Snapshot<'tcx>) { + debug!("rollback_to({})", snapshot.undo_len); + self.undo_log.assert_open_snapshot(&snapshot); + + while self.undo_log.logs.len() > snapshot.undo_len { + let undo = self.undo_log.logs.pop().unwrap(); + self.reverse(undo); + } + + if self.undo_log.num_open_snapshots == 1 { + // The root snapshot. It's safe to clear the undo log because + // there's no snapshot further out that we might need to roll back + // to. + assert!(snapshot.undo_len == 0); + self.undo_log.logs.clear(); + } + + self.undo_log.num_open_snapshots -= 1; + } + + pub fn commit(&mut self, snapshot: Snapshot<'tcx>) { + debug!("commit({})", snapshot.undo_len); + + if self.undo_log.num_open_snapshots == 1 { + // The root snapshot. It's safe to clear the undo log because + // there's no snapshot further out that we might need to roll back + // to. + assert!(snapshot.undo_len == 0); + self.undo_log.logs.clear(); + } + + self.undo_log.num_open_snapshots -= 1; + } +} + +impl<'tcx> InferCtxtUndoLogs<'tcx> { + pub fn actions_since_snapshot(&self, snapshot: &Snapshot<'tcx>) -> &[UndoLog<'tcx>] { + &self.logs[snapshot.undo_len..] + } + + pub fn start_snapshot(&mut self) -> Snapshot<'tcx> { + self.num_open_snapshots += 1; + Snapshot { undo_len: self.logs.len(), _marker: PhantomData } + } + + pub(crate) fn region_constraints_in_snapshot( + &self, + s: &Snapshot<'tcx>, + ) -> impl Iterator<Item = &'_ region_constraints::UndoLog<'tcx>> + Clone { + self.logs[s.undo_len..].iter().filter_map(|log| match log { + UndoLog::RegionConstraintCollector(log) => Some(log), + _ => None, + }) + } + + pub(crate) fn region_constraints( + &self, + ) -> impl Iterator<Item = &'_ region_constraints::UndoLog<'tcx>> + Clone { + self.logs.iter().filter_map(|log| match log { + UndoLog::RegionConstraintCollector(log) => Some(log), + _ => None, + }) + } + + fn assert_open_snapshot(&self, snapshot: &Snapshot<'tcx>) { + // Failures here may indicate a failure to follow a stack discipline. + assert!(self.logs.len() >= snapshot.undo_len); + assert!(self.num_open_snapshots > 0); + } + + pub(crate) fn iter(&self) -> std::slice::Iter<'_, UndoLog<'tcx>> { + self.logs.iter() + } +} + +impl<'tcx> std::ops::Index<usize> for InferCtxtUndoLogs<'tcx> { + type Output = UndoLog<'tcx>; + + fn index(&self, key: usize) -> &Self::Output { + &self.logs[key] + } +} + +impl<'tcx> std::ops::IndexMut<usize> for InferCtxtUndoLogs<'tcx> { + fn index_mut(&mut self, key: usize) -> &mut Self::Output { + &mut self.logs[key] + } +} diff --git a/src/librustc_infer/traits/mod.rs b/src/librustc_infer/traits/mod.rs index 2210c663d14..a8585fd2935 100644 --- a/src/librustc_infer/traits/mod.rs +++ b/src/librustc_infer/traits/mod.rs @@ -20,9 +20,10 @@ pub use self::Vtable::*; pub use self::engine::{TraitEngine, TraitEngineExt}; pub use self::project::MismatchedProjectionTypes; +pub(crate) use self::project::UndoLog; pub use self::project::{ Normalized, NormalizedTy, ProjectionCache, ProjectionCacheEntry, ProjectionCacheKey, - ProjectionCacheSnapshot, Reveal, + ProjectionCacheStorage, Reveal, }; crate use self::util::elaborate_predicates; diff --git a/src/librustc_infer/traits/project.rs b/src/librustc_infer/traits/project.rs index 48375a9ddf4..f0d21a7d022 100644 --- a/src/librustc_infer/traits/project.rs +++ b/src/librustc_infer/traits/project.rs @@ -2,12 +2,19 @@ use super::PredicateObligation; -use rustc_data_structures::snapshot_map::{Snapshot, SnapshotMap}; -use rustc_middle::ty::fold::TypeFoldable; +use crate::infer::InferCtxtUndoLogs; + +use rustc_data_structures::{ + snapshot_map::{self, SnapshotMapRef, SnapshotMapStorage}, + undo_log::Rollback, +}; use rustc_middle::ty::{self, Ty}; pub use rustc_middle::traits::Reveal; +pub(crate) type UndoLog<'tcx> = + snapshot_map::UndoLog<ProjectionCacheKey<'tcx>, ProjectionCacheEntry<'tcx>>; + #[derive(Clone)] pub struct MismatchedProjectionTypes<'tcx> { pub err: ty::error::TypeError<'tcx>, @@ -58,9 +65,14 @@ impl<'tcx, T> Normalized<'tcx, T> { // // FIXME: we probably also want some sort of cross-infcx cache here to // reduce the amount of duplication. Let's see what we get with the Chalk reforms. +pub struct ProjectionCache<'a, 'tcx> { + map: &'a mut SnapshotMapStorage<ProjectionCacheKey<'tcx>, ProjectionCacheEntry<'tcx>>, + undo_log: &'a mut InferCtxtUndoLogs<'tcx>, +} + #[derive(Default)] -pub struct ProjectionCache<'tcx> { - map: SnapshotMap<ProjectionCacheKey<'tcx>, ProjectionCacheEntry<'tcx>>, +pub struct ProjectionCacheStorage<'tcx> { + map: SnapshotMapStorage<ProjectionCacheKey<'tcx>, ProjectionCacheEntry<'tcx>>, } #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] @@ -82,30 +94,29 @@ pub enum ProjectionCacheEntry<'tcx> { NormalizedTy(NormalizedTy<'tcx>), } -// N.B., intentionally not Clone -pub struct ProjectionCacheSnapshot { - snapshot: Snapshot, -} - -impl<'tcx> ProjectionCache<'tcx> { - pub fn clear(&mut self) { - self.map.clear(); - } - - pub fn snapshot(&mut self) -> ProjectionCacheSnapshot { - ProjectionCacheSnapshot { snapshot: self.map.snapshot() } - } - - pub fn rollback_to(&mut self, snapshot: ProjectionCacheSnapshot) { - self.map.rollback_to(snapshot.snapshot); +impl<'tcx> ProjectionCacheStorage<'tcx> { + pub(crate) fn with_log<'a>( + &'a mut self, + undo_log: &'a mut InferCtxtUndoLogs<'tcx>, + ) -> ProjectionCache<'a, 'tcx> { + ProjectionCache { map: &mut self.map, undo_log } } +} - pub fn rollback_placeholder(&mut self, snapshot: &ProjectionCacheSnapshot) { - self.map.partial_rollback(&snapshot.snapshot, &|k| k.ty.has_re_placeholders()); +impl<'tcx> ProjectionCache<'_, 'tcx> { + fn map( + &mut self, + ) -> SnapshotMapRef< + '_, + ProjectionCacheKey<'tcx>, + ProjectionCacheEntry<'tcx>, + InferCtxtUndoLogs<'tcx>, + > { + self.map.with_log(self.undo_log) } - pub fn commit(&mut self, snapshot: ProjectionCacheSnapshot) { - self.map.commit(snapshot.snapshot); + pub fn clear(&mut self) { + self.map().clear(); } /// Try to start normalize `key`; returns an error if @@ -115,11 +126,12 @@ impl<'tcx> ProjectionCache<'tcx> { &mut self, key: ProjectionCacheKey<'tcx>, ) -> Result<(), ProjectionCacheEntry<'tcx>> { - if let Some(entry) = self.map.get(&key) { + let mut map = self.map(); + if let Some(entry) = map.get(&key) { return Err(entry.clone()); } - self.map.insert(key, ProjectionCacheEntry::InProgress); + map.insert(key, ProjectionCacheEntry::InProgress); Ok(()) } @@ -129,7 +141,7 @@ impl<'tcx> ProjectionCache<'tcx> { "ProjectionCacheEntry::insert_ty: adding cache entry: key={:?}, value={:?}", key, value ); - let fresh_key = self.map.insert(key, ProjectionCacheEntry::NormalizedTy(value)); + let fresh_key = self.map().insert(key, ProjectionCacheEntry::NormalizedTy(value)); assert!(!fresh_key, "never started projecting `{:?}`", key); } @@ -138,7 +150,8 @@ impl<'tcx> ProjectionCache<'tcx> { /// snapshot - if the snapshot is rolled back, the obligations will be /// marked as incomplete again). pub fn complete(&mut self, key: ProjectionCacheKey<'tcx>) { - let ty = match self.map.get(&key) { + let mut map = self.map(); + let ty = match map.get(&key) { Some(&ProjectionCacheEntry::NormalizedTy(ref ty)) => { debug!("ProjectionCacheEntry::complete({:?}) - completing {:?}", key, ty); ty.value @@ -151,7 +164,7 @@ impl<'tcx> ProjectionCache<'tcx> { } }; - self.map.insert( + map.insert( key, ProjectionCacheEntry::NormalizedTy(Normalized { value: ty, obligations: vec![] }), ); @@ -163,7 +176,7 @@ impl<'tcx> ProjectionCache<'tcx> { // We want to insert `ty` with no obligations. If the existing value // already has no obligations (as is common) we don't insert anything. if !ty.obligations.is_empty() { - self.map.insert( + self.map().insert( key, ProjectionCacheEntry::NormalizedTy(Normalized { value: ty.value, @@ -178,14 +191,20 @@ impl<'tcx> ProjectionCache<'tcx> { /// type information (in which case, the "fully resolved" key will /// be different). pub fn ambiguous(&mut self, key: ProjectionCacheKey<'tcx>) { - let fresh = self.map.insert(key, ProjectionCacheEntry::Ambiguous); + let fresh = self.map().insert(key, ProjectionCacheEntry::Ambiguous); assert!(!fresh, "never started projecting `{:?}`", key); } /// Indicates that trying to normalize `key` resulted in /// error. pub fn error(&mut self, key: ProjectionCacheKey<'tcx>) { - let fresh = self.map.insert(key, ProjectionCacheEntry::Error); + let fresh = self.map().insert(key, ProjectionCacheEntry::Error); assert!(!fresh, "never started projecting `{:?}`", key); } } + +impl<'tcx> Rollback<UndoLog<'tcx>> for ProjectionCacheStorage<'tcx> { + fn reverse(&mut self, undo: UndoLog<'tcx>) { + self.map.reverse(undo); + } +} diff --git a/src/librustc_interface/tests.rs b/src/librustc_interface/tests.rs index 0a200426e38..1c20ea9e824 100644 --- a/src/librustc_interface/tests.rs +++ b/src/librustc_interface/tests.rs @@ -415,6 +415,7 @@ fn test_codegen_options_tracking_hash() { tracked!(debuginfo, 0xdeadbeef); tracked!(embed_bitcode, false); tracked!(force_frame_pointers, Some(false)); + tracked!(force_unwind_tables, Some(true)); tracked!(inline_threshold, Some(0xf007ba11)); tracked!(linker_plugin_lto, LinkerPluginLto::LinkerPluginAuto); tracked!(llvm_args, vec![String::from("1"), String::from("2")]); @@ -558,7 +559,7 @@ fn test_debugging_options_tracking_hash() { tracked!(sanitizer, Some(Sanitizer::Address)); tracked!(sanitizer_memory_track_origins, 2); tracked!(sanitizer_recover, vec![Sanitizer::Address]); - tracked!(saturating_float_casts, true); + tracked!(saturating_float_casts, Some(true)); tracked!(share_generics, Some(true)); tracked!(show_span, Some(String::from("abc"))); tracked!(src_hash_algorithm, Some(SourceFileHashAlgorithm::Sha1)); diff --git a/src/librustc_interface/util.rs b/src/librustc_interface/util.rs index c5a4d28d151..0797ab33827 100644 --- a/src/librustc_interface/util.rs +++ b/src/librustc_interface/util.rs @@ -81,14 +81,7 @@ pub fn create_session( (Lrc::new(sess), Lrc::new(codegen_backend), source_map) } -// Temporarily have stack size set to 32MB to deal with various crates with long method -// chains or deep syntax trees, except when on Haiku. -// FIXME(oli-obk): get https://github.com/rust-lang/rust/pull/55617 the finish line -#[cfg(not(target_os = "haiku"))] -const STACK_SIZE: usize = 32 * 1024 * 1024; - -#[cfg(target_os = "haiku")] -const STACK_SIZE: usize = 16 * 1024 * 1024; +const STACK_SIZE: usize = 8 * 1024 * 1024; fn get_stack_size() -> Option<usize> { // FIXME: Hacks on hacks. If the env is trying to override the stack size diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs index 4033c2b2849..521a0d67b59 100644 --- a/src/librustc_lint/lib.rs +++ b/src/librustc_lint/lib.rs @@ -6,9 +6,9 @@ //! other phases of the compiler, which are generally required to hold in order //! to compile the program at all. //! -//! Most lints can be written as `LintPass` instances. These run after +//! Most lints can be written as [LintPass] instances. These run after //! all other analyses. The `LintPass`es built into rustc are defined -//! within `rustc_session::lint::builtin`, +//! within [rustc_session::lint::builtin], //! which has further comments on how to add such a lint. //! rustc can also load user-defined lint plugins via the plugin mechanism. //! @@ -19,7 +19,7 @@ //! example) requires more effort. See `emit_lint` and `GatherNodeLevels` //! in `context.rs`. //! -//! Some code also exists in `rustc_session::lint`, `rustc_middle::lint`. +//! Some code also exists in [rustc_session::lint], [rustc_middle::lint]. //! //! ## Note //! diff --git a/src/librustc_middle/dep_graph/mod.rs b/src/librustc_middle/dep_graph/mod.rs index 207c6d0fbff..f997df25e99 100644 --- a/src/librustc_middle/dep_graph/mod.rs +++ b/src/librustc_middle/dep_graph/mod.rs @@ -12,7 +12,7 @@ mod dep_node; pub(crate) use rustc_query_system::dep_graph::DepNodeParams; pub use rustc_query_system::dep_graph::{ debug, hash_result, DepContext, DepNodeColor, DepNodeIndex, SerializedDepNodeIndex, - WorkProduct, WorkProductFileKind, WorkProductId, + WorkProduct, WorkProductId, }; pub use dep_node::{label_strs, DepConstructor, DepKind, DepNode, DepNodeExt}; diff --git a/src/librustc_middle/hir/map/mod.rs b/src/librustc_middle/hir/map/mod.rs index 1c71fc57bea..235d1d80192 100644 --- a/src/librustc_middle/hir/map/mod.rs +++ b/src/librustc_middle/hir/map/mod.rs @@ -408,6 +408,9 @@ impl<'hir> Map<'hir> { }) } + /// Returns the `BodyOwnerKind` of this `LocalDefId`. + /// + /// Panics if `LocalDefId` does not have an associated body. pub fn body_owner_kind(&self, id: HirId) -> BodyOwnerKind { match self.get(id) { Node::Item(&Item { kind: ItemKind::Const(..), .. }) @@ -424,6 +427,23 @@ impl<'hir> Map<'hir> { } } + /// Returns the `ConstContext` of the body associated with this `LocalDefId`. + /// + /// Panics if `LocalDefId` does not have an associated body. + pub fn body_const_context(&self, did: LocalDefId) -> Option<ConstContext> { + let hir_id = self.local_def_id_to_hir_id(did); + let ccx = match self.body_owner_kind(hir_id) { + BodyOwnerKind::Const => ConstContext::Const, + BodyOwnerKind::Static(mt) => ConstContext::Static(mt), + + BodyOwnerKind::Fn if self.tcx.is_constructor(did.to_def_id()) => return None, + BodyOwnerKind::Fn if self.tcx.is_const_fn_raw(did.to_def_id()) => ConstContext::ConstFn, + BodyOwnerKind::Fn | BodyOwnerKind::Closure => return None, + }; + + Some(ccx) + } + pub fn ty_param_owner(&self, id: HirId) -> HirId { match self.get(id) { Node::Item(&Item { kind: ItemKind::Trait(..) | ItemKind::TraitAlias(..), .. }) => id, diff --git a/src/librustc_middle/infer/unify_key.rs b/src/librustc_middle/infer/unify_key.rs index e205453a48c..2580ac6bebd 100644 --- a/src/librustc_middle/infer/unify_key.rs +++ b/src/librustc_middle/infer/unify_key.rs @@ -1,6 +1,9 @@ use crate::ty::{self, FloatVarValue, InferConst, IntVarValue, Ty, TyCtxt}; -use rustc_data_structures::unify::InPlace; -use rustc_data_structures::unify::{EqUnifyValue, NoError, UnificationTable, UnifyKey, UnifyValue}; +use rustc_data_structures::snapshot_vec; +use rustc_data_structures::undo_log::UndoLogs; +use rustc_data_structures::unify::{ + self, EqUnifyValue, InPlace, NoError, UnificationTable, UnifyKey, UnifyValue, +}; use rustc_span::symbol::Symbol; use rustc_span::{Span, DUMMY_SP}; @@ -212,10 +215,14 @@ impl<'tcx> UnifyValue for ConstVarValue<'tcx> { impl<'tcx> EqUnifyValue for &'tcx ty::Const<'tcx> {} -pub fn replace_if_possible( - table: &mut UnificationTable<InPlace<ty::ConstVid<'tcx>>>, +pub fn replace_if_possible<V, L>( + table: &mut UnificationTable<InPlace<ty::ConstVid<'tcx>, V, L>>, c: &'tcx ty::Const<'tcx>, -) -> &'tcx ty::Const<'tcx> { +) -> &'tcx ty::Const<'tcx> +where + V: snapshot_vec::VecLike<unify::Delegate<ty::ConstVid<'tcx>>>, + L: UndoLogs<snapshot_vec::UndoLog<unify::Delegate<ty::ConstVid<'tcx>>>>, +{ if let ty::Const { val: ty::ConstKind::Infer(InferConst::Var(vid)), .. } = c { match table.probe_value(*vid).val.known() { Some(c) => c, diff --git a/src/librustc_middle/mir/interpret/error.rs b/src/librustc_middle/mir/interpret/error.rs index 4b88467ac11..ffe71eb3a09 100644 --- a/src/librustc_middle/mir/interpret/error.rs +++ b/src/librustc_middle/mir/interpret/error.rs @@ -3,8 +3,7 @@ use super::{AllocId, Pointer, RawConst, ScalarMaybeUndef}; use crate::mir::interpret::ConstValue; use crate::ty::layout::LayoutError; use crate::ty::query::TyCtxtAt; -use crate::ty::tls; -use crate::ty::{self, layout, Ty}; +use crate::ty::{self, layout, tls, FnSig, Ty}; use rustc_data_structures::sync::Lock; use rustc_errors::{struct_span_err, DiagnosticBuilder, ErrorReported}; @@ -329,7 +328,7 @@ impl fmt::Display for CheckInAllocMsg { } /// Error information for when the program caused Undefined Behavior. -pub enum UndefinedBehaviorInfo { +pub enum UndefinedBehaviorInfo<'tcx> { /// Free-form case. Only for errors that are never caught! Ub(String), /// Unreachable code was executed. @@ -347,6 +346,8 @@ pub enum UndefinedBehaviorInfo { PointerArithOverflow, /// Invalid metadata in a wide pointer (using `str` to avoid allocations). InvalidMeta(&'static str), + /// Invalid drop function in vtable. + InvalidDropFn(FnSig<'tcx>), /// Reading a C string that does not end within its allocation. UnterminatedCString(Pointer), /// Dereferencing a dangling pointer after it got freed. @@ -380,6 +381,8 @@ pub enum UndefinedBehaviorInfo { InvalidDiscriminant(ScalarMaybeUndef), /// Using a pointer-not-to-a-function as function pointer. InvalidFunctionPointer(Pointer), + /// Using a string that is not valid UTF-8, + InvalidStr(std::str::Utf8Error), /// Using uninitialized data where it is not allowed. InvalidUndefBytes(Option<Pointer>), /// Working with a local that is not currently live. @@ -391,7 +394,7 @@ pub enum UndefinedBehaviorInfo { }, } -impl fmt::Display for UndefinedBehaviorInfo { +impl fmt::Display for UndefinedBehaviorInfo<'_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { use UndefinedBehaviorInfo::*; match self { @@ -404,6 +407,11 @@ impl fmt::Display for UndefinedBehaviorInfo { RemainderByZero => write!(f, "calculating the remainder with a divisor of zero"), PointerArithOverflow => write!(f, "overflowing in-bounds pointer arithmetic"), InvalidMeta(msg) => write!(f, "invalid metadata in wide pointer: {}", msg), + InvalidDropFn(sig) => write!( + f, + "invalid drop function signature: got {}, expected exactly one argument which must be a pointer type", + sig + ), UnterminatedCString(p) => write!( f, "reading a null-terminated string starting at {} with no null found before end of allocation", @@ -446,6 +454,7 @@ impl fmt::Display for UndefinedBehaviorInfo { InvalidFunctionPointer(p) => { write!(f, "using {} as function pointer but it does not point to a function", p) } + InvalidStr(err) => write!(f, "this string is not valid UTF-8: {}", err), InvalidUndefBytes(Some(p)) => write!( f, "reading uninitialized memory at {}, but this operation requires initialized memory", @@ -549,7 +558,7 @@ impl dyn MachineStopType { pub enum InterpError<'tcx> { /// The program caused undefined behavior. - UndefinedBehavior(UndefinedBehaviorInfo), + UndefinedBehavior(UndefinedBehaviorInfo<'tcx>), /// The program did something the interpreter does not support (some of these *might* be UB /// but the interpreter is not sure). Unsupported(UnsupportedOpInfo), diff --git a/src/librustc_middle/traits/mod.rs b/src/librustc_middle/traits/mod.rs index d6989fd8e4e..3a05d577bfa 100644 --- a/src/librustc_middle/traits/mod.rs +++ b/src/librustc_middle/traits/mod.rs @@ -194,6 +194,9 @@ pub enum ObligationCauseCode<'tcx> { DerivedObligation(DerivedObligationCause<'tcx>), /// Error derived when matching traits/impls; see ObligationCause for more details + CompareImplConstObligation, + + /// Error derived when matching traits/impls; see ObligationCause for more details CompareImplMethodObligation { item_name: ast::Name, impl_item_def_id: DefId, diff --git a/src/librustc_middle/traits/structural_impls.rs b/src/librustc_middle/traits/structural_impls.rs index 69a5213d3e4..668c84ad5e6 100644 --- a/src/librustc_middle/traits/structural_impls.rs +++ b/src/librustc_middle/traits/structural_impls.rs @@ -164,6 +164,7 @@ impl<'a, 'tcx> Lift<'tcx> for traits::ObligationCauseCode<'a> { tcx.lift(cause).map(super::ImplDerivedObligation) } super::DerivedObligation(ref cause) => tcx.lift(cause).map(super::DerivedObligation), + super::CompareImplConstObligation => Some(super::CompareImplConstObligation), super::CompareImplMethodObligation { item_name, impl_item_def_id, diff --git a/src/librustc_middle/ty/diagnostics.rs b/src/librustc_middle/ty/diagnostics.rs index 790eb8f49af..613d66d59c5 100644 --- a/src/librustc_middle/ty/diagnostics.rs +++ b/src/librustc_middle/ty/diagnostics.rs @@ -2,7 +2,12 @@ use crate::ty::sty::InferTy; use crate::ty::TyKind::*; -use crate::ty::TyS; +use crate::ty::{TyCtxt, TyS}; +use rustc_errors::{Applicability, DiagnosticBuilder}; +use rustc_hir as hir; +use rustc_hir::def_id::DefId; +use rustc_hir::{QPath, TyKind, WhereBoundPredicate, WherePredicate}; +use rustc_span::{BytePos, Span}; impl<'tcx> TyS<'tcx> { /// Similar to `TyS::is_primitive`, but also considers inferred numeric values to be primitive. @@ -67,3 +72,180 @@ impl<'tcx> TyS<'tcx> { } } } + +/// Suggest restricting a type param with a new bound. +pub fn suggest_constraining_type_param( + tcx: TyCtxt<'_>, + generics: &hir::Generics<'_>, + err: &mut DiagnosticBuilder<'_>, + param_name: &str, + constraint: &str, + def_id: Option<DefId>, +) -> bool { + let param = generics.params.iter().find(|p| p.name.ident().as_str() == param_name); + + let param = if let Some(param) = param { + param + } else { + return false; + }; + + const MSG_RESTRICT_BOUND_FURTHER: &str = "consider further restricting this bound"; + let msg_restrict_type = format!("consider restricting type parameter `{}`", param_name); + let msg_restrict_type_further = + format!("consider further restricting type parameter `{}`", param_name); + + if def_id == tcx.lang_items().sized_trait() { + // Type parameters are already `Sized` by default. + err.span_label(param.span, &format!("this type parameter needs to be `{}`", constraint)); + return true; + } + let mut suggest_restrict = |span| { + err.span_suggestion_verbose( + span, + MSG_RESTRICT_BOUND_FURTHER, + format!(" + {}", constraint), + Applicability::MachineApplicable, + ); + }; + + if param_name.starts_with("impl ") { + // If there's an `impl Trait` used in argument position, suggest + // restricting it: + // + // fn foo(t: impl Foo) { ... } + // -------- + // | + // help: consider further restricting this bound with `+ Bar` + // + // Suggestion for tools in this case is: + // + // fn foo(t: impl Foo) { ... } + // -------- + // | + // replace with: `impl Foo + Bar` + + suggest_restrict(param.span.shrink_to_hi()); + return true; + } + + if generics.where_clause.predicates.is_empty() + // Given `trait Base<T = String>: Super<T>` where `T: Copy`, suggest restricting in the + // `where` clause instead of `trait Base<T: Copy = String>: Super<T>`. + && !matches!(param.kind, hir::GenericParamKind::Type { default: Some(_), .. }) + { + if let Some(bounds_span) = param.bounds_span() { + // If user has provided some bounds, suggest restricting them: + // + // fn foo<T: Foo>(t: T) { ... } + // --- + // | + // help: consider further restricting this bound with `+ Bar` + // + // Suggestion for tools in this case is: + // + // fn foo<T: Foo>(t: T) { ... } + // -- + // | + // replace with: `T: Bar +` + suggest_restrict(bounds_span.shrink_to_hi()); + } else { + // If user hasn't provided any bounds, suggest adding a new one: + // + // fn foo<T>(t: T) { ... } + // - help: consider restricting this type parameter with `T: Foo` + err.span_suggestion_verbose( + param.span.shrink_to_hi(), + &msg_restrict_type, + format!(": {}", constraint), + Applicability::MachineApplicable, + ); + } + + true + } else { + // This part is a bit tricky, because using the `where` clause user can + // provide zero, one or many bounds for the same type parameter, so we + // have following cases to consider: + // + // 1) When the type parameter has been provided zero bounds + // + // Message: + // fn foo<X, Y>(x: X, y: Y) where Y: Foo { ... } + // - help: consider restricting this type parameter with `where X: Bar` + // + // Suggestion: + // fn foo<X, Y>(x: X, y: Y) where Y: Foo { ... } + // - insert: `, X: Bar` + // + // + // 2) When the type parameter has been provided one bound + // + // Message: + // fn foo<T>(t: T) where T: Foo { ... } + // ^^^^^^ + // | + // help: consider further restricting this bound with `+ Bar` + // + // Suggestion: + // fn foo<T>(t: T) where T: Foo { ... } + // ^^ + // | + // replace with: `T: Bar +` + // + // + // 3) When the type parameter has been provided many bounds + // + // Message: + // fn foo<T>(t: T) where T: Foo, T: Bar {... } + // - help: consider further restricting this type parameter with `where T: Zar` + // + // Suggestion: + // fn foo<T>(t: T) where T: Foo, T: Bar {... } + // - insert: `, T: Zar` + + let mut param_spans = Vec::new(); + + for predicate in generics.where_clause.predicates { + if let WherePredicate::BoundPredicate(WhereBoundPredicate { + span, bounded_ty, .. + }) = predicate + { + if let TyKind::Path(QPath::Resolved(_, path)) = &bounded_ty.kind { + if let Some(segment) = path.segments.first() { + if segment.ident.to_string() == param_name { + param_spans.push(span); + } + } + } + } + } + + let where_clause_span = generics.where_clause.span_for_predicates_or_empty_place(); + // Account for `fn foo<T>(t: T) where T: Foo,` so we don't suggest two trailing commas. + let mut trailing_comma = false; + if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(where_clause_span) { + trailing_comma = snippet.ends_with(','); + } + let where_clause_span = if trailing_comma { + let hi = where_clause_span.hi(); + Span::new(hi - BytePos(1), hi, where_clause_span.ctxt()) + } else { + where_clause_span.shrink_to_hi() + }; + + match ¶m_spans[..] { + &[¶m_span] => suggest_restrict(param_span.shrink_to_hi()), + _ => { + err.span_suggestion_verbose( + where_clause_span, + &msg_restrict_type_further, + format!(", {}: {}", param_name, constraint), + Applicability::MachineApplicable, + ); + } + } + + true + } +} diff --git a/src/librustc_middle/ty/error.rs b/src/librustc_middle/ty/error.rs index 78a94b62d47..f3b6a53dfeb 100644 --- a/src/librustc_middle/ty/error.rs +++ b/src/librustc_middle/ty/error.rs @@ -1,10 +1,13 @@ +use crate::traits::{ObligationCause, ObligationCauseCode}; +use crate::ty::diagnostics::suggest_constraining_type_param; use crate::ty::{self, BoundRegion, Region, Ty, TyCtxt}; use rustc_ast::ast; -use rustc_errors::{pluralize, Applicability, DiagnosticBuilder}; +use rustc_errors::Applicability::{MachineApplicable, MaybeIncorrect}; +use rustc_errors::{pluralize, DiagnosticBuilder}; use rustc_hir as hir; use rustc_hir::def_id::DefId; -use rustc_span::symbol::sym; -use rustc_span::Span; +use rustc_span::symbol::{sym, Symbol}; +use rustc_span::{BytePos, MultiSpan, Span}; use rustc_target::spec::abi; use std::borrow::Cow; @@ -332,11 +335,12 @@ impl<'tcx> TyCtxt<'tcx> { self, db: &mut DiagnosticBuilder<'_>, err: &TypeError<'tcx>, + cause: &ObligationCause<'tcx>, sp: Span, body_owner_def_id: DefId, ) { use self::TypeError::*; - + debug!("note_and_explain_type_err err={:?} cause={:?}", err, cause); match err { Sorts(values) => { let expected_str = values.expected.sort_string(self); @@ -370,7 +374,7 @@ impl<'tcx> TyCtxt<'tcx> { sp, "use a float literal", format!("{}.0", snippet), - Applicability::MachineApplicable, + MachineApplicable, ); } } @@ -398,10 +402,49 @@ impl<'tcx> TyCtxt<'tcx> { (ty::Projection(_), ty::Projection(_)) => { db.note("an associated type was expected, but a different one was found"); } - (ty::Param(_), ty::Projection(_)) | (ty::Projection(_), ty::Param(_)) => { - db.note("you might be missing a type parameter or trait bound"); + (ty::Param(p), ty::Projection(proj)) | (ty::Projection(proj), ty::Param(p)) => { + let generics = self.generics_of(body_owner_def_id); + let p_span = self.def_span(generics.type_param(p, self).def_id); + if !sp.contains(p_span) { + db.span_label(p_span, "this type parameter"); + } + let hir = self.hir(); + let mut note = true; + if let Some(generics) = generics + .type_param(p, self) + .def_id + .as_local() + .map(|id| hir.as_local_hir_id(id)) + .and_then(|id| self.hir().find(self.hir().get_parent_node(id))) + .as_ref() + .and_then(|node| node.generics()) + { + // Synthesize the associated type restriction `Add<Output = Expected>`. + // FIXME: extract this logic for use in other diagnostics. + let trait_ref = proj.trait_ref(self); + let path = + self.def_path_str_with_substs(trait_ref.def_id, trait_ref.substs); + let item_name = self.item_name(proj.item_def_id); + let path = if path.ends_with('>') { + format!("{}, {} = {}>", &path[..path.len() - 1], item_name, p) + } else { + format!("{}<{} = {}>", path, item_name, p) + }; + note = !suggest_constraining_type_param( + self, + generics, + db, + &format!("{}", proj.self_ty()), + &path, + None, + ); + } + if note { + db.note("you might be missing a type parameter or trait bound"); + } } - (ty::Param(p), _) | (_, ty::Param(p)) => { + (ty::Param(p), ty::Dynamic(..) | ty::Opaque(..)) + | (ty::Dynamic(..) | ty::Opaque(..), ty::Param(p)) => { let generics = self.generics_of(body_owner_def_id); let p_span = self.def_span(generics.type_param(p, self).def_id); if !sp.contains(p_span) { @@ -441,44 +484,40 @@ impl<T> Trait<T> for X { #traits-as-parameters", ); } - (ty::Projection(_), _) => { - db.note(&format!( - "consider constraining the associated type `{}` to `{}` or calling a \ - method that returns `{}`", - values.expected, values.found, values.expected, - )); - if self.sess.teach(&db.get_code().unwrap()) { - db.help( - "given an associated type `T` and a method `foo`: -``` -trait Trait { - type T; - fn foo(&self) -> Self::T; -} -``` -the only way of implementing method `foo` is to constrain `T` with an explicit associated type: -``` -impl Trait for X { - type T = String; - fn foo(&self) -> Self::T { String::new() } -} -```", - ); + (ty::Param(p), _) | (_, ty::Param(p)) => { + let generics = self.generics_of(body_owner_def_id); + let p_span = self.def_span(generics.type_param(p, self).def_id); + if !sp.contains(p_span) { + db.span_label(p_span, "this type parameter"); } - db.note( - "for more information, visit \ - https://doc.rust-lang.org/book/ch19-03-advanced-traits.html", + } + (ty::Projection(proj_ty), _) => { + self.expected_projection( + db, + proj_ty, + values, + body_owner_def_id, + &cause.code, ); } - (_, ty::Projection(_)) => { - db.note(&format!( + (_, ty::Projection(proj_ty)) => { + let msg = format!( "consider constraining the associated type `{}` to `{}`", values.found, values.expected, - )); - db.note( - "for more information, visit \ - https://doc.rust-lang.org/book/ch19-03-advanced-traits.html", ); + if !self.suggest_constraint( + db, + &msg, + body_owner_def_id, + proj_ty, + values.expected, + ) { + db.help(&msg); + db.note( + "for more information, visit \ + https://doc.rust-lang.org/book/ch19-03-advanced-traits.html", + ); + } } _ => {} } @@ -513,4 +552,357 @@ impl Trait for X { _ => {} } } + + fn suggest_constraint( + &self, + db: &mut DiagnosticBuilder<'_>, + msg: &str, + body_owner_def_id: DefId, + proj_ty: &ty::ProjectionTy<'tcx>, + ty: Ty<'tcx>, + ) -> bool { + let assoc = self.associated_item(proj_ty.item_def_id); + let trait_ref = proj_ty.trait_ref(*self); + if let Some(item) = self.hir().get_if_local(body_owner_def_id) { + if let Some(hir_generics) = item.generics() { + // Get the `DefId` for the type parameter corresponding to `A` in `<A as T>::Foo`. + // This will also work for `impl Trait`. + let def_id = if let ty::Param(param_ty) = proj_ty.self_ty().kind { + let generics = self.generics_of(body_owner_def_id); + generics.type_param(¶m_ty, *self).def_id + } else { + return false; + }; + + // First look in the `where` clause, as this might be + // `fn foo<T>(x: T) where T: Trait`. + for predicate in hir_generics.where_clause.predicates { + if let hir::WherePredicate::BoundPredicate(pred) = predicate { + if let hir::TyKind::Path(hir::QPath::Resolved(None, path)) = + pred.bounded_ty.kind + { + if path.res.opt_def_id() == Some(def_id) { + // This predicate is binding type param `A` in `<A as T>::Foo` to + // something, potentially `T`. + } else { + continue; + } + } else { + continue; + } + + if self.constrain_generic_bound_associated_type_structured_suggestion( + db, + &trait_ref, + pred.bounds, + &assoc, + ty, + msg, + ) { + return true; + } + } + } + for param in hir_generics.params { + if self.hir().opt_local_def_id(param.hir_id).map(|id| id.to_def_id()) + == Some(def_id) + { + // This is type param `A` in `<A as T>::Foo`. + return self.constrain_generic_bound_associated_type_structured_suggestion( + db, + &trait_ref, + param.bounds, + &assoc, + ty, + msg, + ); + } + } + } + } + false + } + + /// An associated type was expected and a different type was found. + /// + /// We perform a few different checks to see what we can suggest: + /// + /// - In the current item, look for associated functions that return the expected type and + /// suggest calling them. (Not a structured suggestion.) + /// - If any of the item's generic bounds can be constrained, we suggest constraining the + /// associated type to the found type. + /// - If the associated type has a default type and was expected inside of a `trait`, we + /// mention that this is disallowed. + /// - If all other things fail, and the error is not because of a mismatch between the `trait` + /// and the `impl`, we provide a generic `help` to constrain the assoc type or call an assoc + /// fn that returns the type. + fn expected_projection( + &self, + db: &mut DiagnosticBuilder<'_>, + proj_ty: &ty::ProjectionTy<'tcx>, + values: &ExpectedFound<Ty<'tcx>>, + body_owner_def_id: DefId, + cause_code: &ObligationCauseCode<'_>, + ) { + let msg = format!( + "consider constraining the associated type `{}` to `{}`", + values.expected, values.found + ); + let body_owner = self.hir().get_if_local(body_owner_def_id); + let current_method_ident = body_owner.and_then(|n| n.ident()).map(|i| i.name); + + // We don't want to suggest calling an assoc fn in a scope where that isn't feasible. + let callable_scope = match body_owner { + Some( + hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(..), .. }) + | hir::Node::TraitItem(hir::TraitItem { kind: hir::TraitItemKind::Fn(..), .. }) + | hir::Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Fn(..), .. }), + ) => true, + _ => false, + }; + let impl_comparison = matches!( + cause_code, + ObligationCauseCode::CompareImplMethodObligation { .. } + | ObligationCauseCode::CompareImplTypeObligation { .. } + | ObligationCauseCode::CompareImplConstObligation + ); + let assoc = self.associated_item(proj_ty.item_def_id); + if !callable_scope || impl_comparison { + // We do not want to suggest calling functions when the reason of the + // type error is a comparison of an `impl` with its `trait` or when the + // scope is outside of a `Body`. + } else { + // If we find a suitable associated function that returns the expected type, we don't + // want the more general suggestion later in this method about "consider constraining + // the associated type or calling a method that returns the associated type". + let point_at_assoc_fn = self.point_at_methods_that_satisfy_associated_type( + db, + assoc.container.id(), + current_method_ident, + proj_ty.item_def_id, + values.expected, + ); + // Possibly suggest constraining the associated type to conform to the + // found type. + if self.suggest_constraint(db, &msg, body_owner_def_id, proj_ty, values.found) + || point_at_assoc_fn + { + return; + } + } + + if let ty::Opaque(def_id, _) = proj_ty.self_ty().kind { + // When the expected `impl Trait` is not defined in the current item, it will come from + // a return type. This can occur when dealing with `TryStream` (#71035). + if self.constrain_associated_type_structured_suggestion( + db, + self.def_span(def_id), + &assoc, + values.found, + &msg, + ) { + return; + } + } + + if self.point_at_associated_type(db, body_owner_def_id, values.found) { + return; + } + + if !impl_comparison { + // Generic suggestion when we can't be more specific. + if callable_scope { + db.help(&format!("{} or calling a method that returns `{}`", msg, values.expected)); + } else { + db.help(&msg); + } + db.note( + "for more information, visit \ + https://doc.rust-lang.org/book/ch19-03-advanced-traits.html", + ); + } + if self.sess.teach(&db.get_code().unwrap()) { + db.help( + "given an associated type `T` and a method `foo`: +``` +trait Trait { +type T; +fn foo(&self) -> Self::T; +} +``` +the only way of implementing method `foo` is to constrain `T` with an explicit associated type: +``` +impl Trait for X { +type T = String; +fn foo(&self) -> Self::T { String::new() } +} +```", + ); + } + } + + fn point_at_methods_that_satisfy_associated_type( + &self, + db: &mut DiagnosticBuilder<'_>, + assoc_container_id: DefId, + current_method_ident: Option<Symbol>, + proj_ty_item_def_id: DefId, + expected: Ty<'tcx>, + ) -> bool { + let items = self.associated_items(assoc_container_id); + // Find all the methods in the trait that could be called to construct the + // expected associated type. + // FIXME: consider suggesting the use of associated `const`s. + let methods: Vec<(Span, String)> = items + .items + .iter() + .filter(|(name, item)| { + ty::AssocKind::Fn == item.kind && Some(**name) != current_method_ident + }) + .filter_map(|(_, item)| { + let method = self.fn_sig(item.def_id); + match method.output().skip_binder().kind { + ty::Projection(ty::ProjectionTy { item_def_id, .. }) + if item_def_id == proj_ty_item_def_id => + { + Some(( + self.sess.source_map().guess_head_span(self.def_span(item.def_id)), + format!("consider calling `{}`", self.def_path_str(item.def_id)), + )) + } + _ => None, + } + }) + .collect(); + if !methods.is_empty() { + // Use a single `help:` to show all the methods in the trait that can + // be used to construct the expected associated type. + let mut span: MultiSpan = + methods.iter().map(|(sp, _)| *sp).collect::<Vec<Span>>().into(); + let msg = format!( + "{some} method{s} {are} available that return{r} `{ty}`", + some = if methods.len() == 1 { "a" } else { "some" }, + s = pluralize!(methods.len()), + are = if methods.len() == 1 { "is" } else { "are" }, + r = if methods.len() == 1 { "s" } else { "" }, + ty = expected + ); + for (sp, label) in methods.into_iter() { + span.push_span_label(sp, label); + } + db.span_help(span, &msg); + return true; + } + false + } + + fn point_at_associated_type( + &self, + db: &mut DiagnosticBuilder<'_>, + body_owner_def_id: DefId, + found: Ty<'tcx>, + ) -> bool { + let hir_id = match body_owner_def_id.as_local().map(|id| self.hir().as_local_hir_id(id)) { + Some(hir_id) => hir_id, + None => return false, + }; + // When `body_owner` is an `impl` or `trait` item, look in its associated types for + // `expected` and point at it. + let parent_id = self.hir().get_parent_item(hir_id); + let item = self.hir().find(parent_id); + debug!("expected_projection parent item {:?}", item); + match item { + Some(hir::Node::Item(hir::Item { kind: hir::ItemKind::Trait(.., items), .. })) => { + // FIXME: account for `#![feature(specialization)]` + for item in &items[..] { + match item.kind { + hir::AssocItemKind::Type | hir::AssocItemKind::OpaqueTy => { + if self.type_of(self.hir().local_def_id(item.id.hir_id)) == found { + if let hir::Defaultness::Default { has_value: true } = + item.defaultness + { + db.span_label( + item.span, + "associated type defaults can't be assumed inside the \ + trait defining them", + ); + } else { + db.span_label(item.span, "expected this associated type"); + } + return true; + } + } + _ => {} + } + } + } + Some(hir::Node::Item(hir::Item { + kind: hir::ItemKind::Impl { items, .. }, .. + })) => { + for item in &items[..] { + match item.kind { + hir::AssocItemKind::Type | hir::AssocItemKind::OpaqueTy => { + if self.type_of(self.hir().local_def_id(item.id.hir_id)) == found { + db.span_label(item.span, "expected this associated type"); + return true; + } + } + _ => {} + } + } + } + _ => {} + } + false + } + + /// Given a slice of `hir::GenericBound`s, if any of them corresponds to the `trait_ref` + /// requirement, provide a strucuted suggestion to constrain it to a given type `ty`. + fn constrain_generic_bound_associated_type_structured_suggestion( + &self, + db: &mut DiagnosticBuilder<'_>, + trait_ref: &ty::TraitRef<'tcx>, + bounds: hir::GenericBounds<'_>, + assoc: &ty::AssocItem, + ty: Ty<'tcx>, + msg: &str, + ) -> bool { + // FIXME: we would want to call `resolve_vars_if_possible` on `ty` before suggesting. + bounds.iter().any(|bound| match bound { + hir::GenericBound::Trait(ptr, hir::TraitBoundModifier::None) => { + // Relate the type param against `T` in `<A as T>::Foo`. + ptr.trait_ref.trait_def_id() == Some(trait_ref.def_id) + && self.constrain_associated_type_structured_suggestion( + db, ptr.span, assoc, ty, msg, + ) + } + _ => false, + }) + } + + /// Given a span corresponding to a bound, provide a structured suggestion to set an + /// associated type to a given type `ty`. + fn constrain_associated_type_structured_suggestion( + &self, + db: &mut DiagnosticBuilder<'_>, + span: Span, + assoc: &ty::AssocItem, + ty: Ty<'tcx>, + msg: &str, + ) -> bool { + if let Ok(has_params) = + self.sess.source_map().span_to_snippet(span).map(|snippet| snippet.ends_with('>')) + { + let (span, sugg) = if has_params { + let pos = span.hi() - BytePos(1); + let span = Span::new(pos, pos, span.ctxt()); + (span, format!(", {} = {}", assoc.ident, ty)) + } else { + (span.shrink_to_hi(), format!("<{} = {}>", assoc.ident, ty)) + }; + db.span_suggestion_verbose(span, msg, sugg, MaybeIncorrect); + return true; + } + false + } } diff --git a/src/librustc_middle/ty/inhabitedness/mod.rs b/src/librustc_middle/ty/inhabitedness/mod.rs index b166c4dea0c..d1b5eed921b 100644 --- a/src/librustc_middle/ty/inhabitedness/mod.rs +++ b/src/librustc_middle/ty/inhabitedness/mod.rs @@ -6,6 +6,7 @@ use crate::ty::TyKind::*; use crate::ty::{AdtDef, FieldDef, Ty, TyS, VariantDef}; use crate::ty::{AdtKind, Visibility}; use crate::ty::{DefId, SubstsRef}; +use rustc_data_structures::stack::ensure_sufficient_stack; mod def_id_forest; @@ -196,7 +197,9 @@ impl<'tcx> TyS<'tcx> { /// Calculates the forest of `DefId`s from which this type is visibly uninhabited. fn uninhabited_from(&self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> DefIdForest { match self.kind { - Adt(def, substs) => def.uninhabited_from(tcx, substs, param_env), + Adt(def, substs) => { + ensure_sufficient_stack(|| def.uninhabited_from(tcx, substs, param_env)) + } Never => DefIdForest::full(tcx), diff --git a/src/librustc_middle/ty/layout.rs b/src/librustc_middle/ty/layout.rs index 4cdcd5320e7..ade89ab39d4 100644 --- a/src/librustc_middle/ty/layout.rs +++ b/src/librustc_middle/ty/layout.rs @@ -2607,7 +2607,7 @@ where // `Box` (`UniqueBorrowed`) are not necessarily dereferenceable // for the entire duration of the function as they can be deallocated - // any time. Set their valid size to 0. + // at any time. Set their valid size to 0. attrs.pointee_size = match kind { PointerKind::UniqueOwned => Size::ZERO, _ => pointee.size, diff --git a/src/librustc_middle/ty/query/plumbing.rs b/src/librustc_middle/ty/query/plumbing.rs index 82ee8ca29fa..c711de9476e 100644 --- a/src/librustc_middle/ty/query/plumbing.rs +++ b/src/librustc_middle/ty/query/plumbing.rs @@ -68,7 +68,9 @@ impl QueryContext for TyCtxt<'tcx> { }; // Use the `ImplicitCtxt` while we execute the query. - tls::enter_context(&new_icx, |_| compute(*self)) + tls::enter_context(&new_icx, |_| { + rustc_data_structures::stack::ensure_sufficient_stack(|| compute(*self)) + }) }) } } diff --git a/src/librustc_mir/borrow_check/def_use.rs b/src/librustc_mir/borrow_check/def_use.rs new file mode 100644 index 00000000000..689ec249a2f --- /dev/null +++ b/src/librustc_mir/borrow_check/def_use.rs @@ -0,0 +1,78 @@ +use rustc_middle::mir::visit::{ + MutatingUseContext, NonMutatingUseContext, NonUseContext, PlaceContext, +}; + +#[derive(Eq, PartialEq, Clone)] +pub enum DefUse { + Def, + Use, + Drop, +} + +pub fn categorize(context: PlaceContext) -> Option<DefUse> { + match context { + /////////////////////////////////////////////////////////////////////////// + // DEFS + + PlaceContext::MutatingUse(MutatingUseContext::Store) | + + // This is potentially both a def and a use... + PlaceContext::MutatingUse(MutatingUseContext::AsmOutput) | + + // We let Call define the result in both the success and + // unwind cases. This is not really correct, however it + // does not seem to be observable due to the way that we + // generate MIR. To do things properly, we would apply + // the def in call only to the input from the success + // path and not the unwind path. -nmatsakis + PlaceContext::MutatingUse(MutatingUseContext::Call) | + PlaceContext::MutatingUse(MutatingUseContext::Yield) | + + // Storage live and storage dead aren't proper defines, but we can ignore + // values that come before them. + PlaceContext::NonUse(NonUseContext::StorageLive) | + PlaceContext::NonUse(NonUseContext::StorageDead) => Some(DefUse::Def), + + /////////////////////////////////////////////////////////////////////////// + // REGULAR USES + // + // These are uses that occur *outside* of a drop. For the + // purposes of NLL, these are special in that **all** the + // lifetimes appearing in the variable must be live for each regular use. + + PlaceContext::NonMutatingUse(NonMutatingUseContext::Projection) | + PlaceContext::MutatingUse(MutatingUseContext::Projection) | + + // Borrows only consider their local used at the point of the borrow. + // This won't affect the results since we use this analysis for generators + // and we only care about the result at suspension points. Borrows cannot + // cross suspension points so this behavior is unproblematic. + PlaceContext::MutatingUse(MutatingUseContext::Borrow) | + PlaceContext::NonMutatingUse(NonMutatingUseContext::SharedBorrow) | + PlaceContext::NonMutatingUse(NonMutatingUseContext::ShallowBorrow) | + PlaceContext::NonMutatingUse(NonMutatingUseContext::UniqueBorrow) | + + PlaceContext::MutatingUse(MutatingUseContext::AddressOf) | + PlaceContext::NonMutatingUse(NonMutatingUseContext::AddressOf) | + PlaceContext::NonMutatingUse(NonMutatingUseContext::Inspect) | + PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy) | + PlaceContext::NonMutatingUse(NonMutatingUseContext::Move) | + PlaceContext::NonUse(NonUseContext::AscribeUserTy) | + PlaceContext::MutatingUse(MutatingUseContext::Retag) => + Some(DefUse::Use), + + /////////////////////////////////////////////////////////////////////////// + // DROP USES + // + // These are uses that occur in a DROP (a MIR drop, not a + // call to `std::mem::drop()`). For the purposes of NLL, + // uses in drop are special because `#[may_dangle]` + // attributes can affect whether lifetimes must be live. + + PlaceContext::MutatingUse(MutatingUseContext::Drop) => + Some(DefUse::Drop), + + // Debug info is neither def nor use. + PlaceContext::NonUse(NonUseContext::VarDebugInfo) => None, + } +} diff --git a/src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs b/src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs index 9eb55bca868..5f1c0911da2 100644 --- a/src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs +++ b/src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs @@ -10,10 +10,9 @@ use rustc_middle::mir::{ FakeReadCause, Local, LocalDecl, LocalInfo, LocalKind, Location, Operand, Place, PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind, TerminatorKind, VarBindingForm, }; -use rustc_middle::ty::{self, Ty}; +use rustc_middle::ty::{self, suggest_constraining_type_param, Ty}; use rustc_span::source_map::DesugaringKind; use rustc_span::Span; -use rustc_trait_selection::traits::error_reporting::suggest_constraining_type_param; use crate::dataflow::drop_flag_effects; use crate::dataflow::indexes::{MoveOutIndex, MovePathIndex}; diff --git a/src/librustc_mir/borrow_check/diagnostics/find_use.rs b/src/librustc_mir/borrow_check/diagnostics/find_use.rs index 6c6bde8ae2c..8d8cdfb5293 100644 --- a/src/librustc_mir/borrow_check/diagnostics/find_use.rs +++ b/src/librustc_mir/borrow_check/diagnostics/find_use.rs @@ -2,10 +2,10 @@ use std::collections::VecDeque; use std::rc::Rc; use crate::borrow_check::{ + def_use::{self, DefUse}, nll::ToRegionVid, region_infer::{Cause, RegionInferenceContext}, }; -use crate::util::liveness::{self, DefUse}; use rustc_data_structures::fx::FxHashSet; use rustc_middle::mir::visit::{MirVisitable, PlaceContext, Visitor}; use rustc_middle::mir::{Body, Local, Location}; @@ -117,7 +117,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for DefUseVisitor<'cx, 'tcx> { }); if found_it { - self.def_use_result = match liveness::categorize(context) { + self.def_use_result = match def_use::categorize(context) { Some(DefUse::Def) => Some(DefUseResult::Def), Some(DefUse::Use) => Some(DefUseResult::UseLive { local }), Some(DefUse::Drop) => Some(DefUseResult::UseDrop { local }), diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs index 7d8a2b540a9..457f0f8444b 100644 --- a/src/librustc_mir/borrow_check/mod.rs +++ b/src/librustc_mir/borrow_check/mod.rs @@ -32,13 +32,13 @@ use std::mem; use std::rc::Rc; use crate::dataflow; +use crate::dataflow::impls::{ + Borrows, EverInitializedPlaces, MaybeInitializedPlaces, MaybeUninitializedPlaces, +}; use crate::dataflow::indexes::{BorrowIndex, InitIndex, MoveOutIndex, MovePathIndex}; use crate::dataflow::move_paths::{InitLocation, LookupResult, MoveData, MoveError}; -use crate::dataflow::Borrows; -use crate::dataflow::EverInitializedPlaces; use crate::dataflow::MoveDataParamEnv; use crate::dataflow::{Analysis, BorrowckFlowState as Flows, BorrowckResults}; -use crate::dataflow::{MaybeInitializedPlaces, MaybeUninitializedPlaces}; use crate::transform::MirSource; use self::diagnostics::{AccessKind, RegionName}; @@ -51,6 +51,7 @@ use self::path_utils::*; mod borrow_set; mod constraint_generation; mod constraints; +mod def_use; mod diagnostics; mod facts; mod invalidation; @@ -180,11 +181,14 @@ fn do_mir_borrowck<'a, 'tcx>( let location_table = &LocationTable::new(&body); let mut errors_buffer = Vec::new(); - let (move_data, move_errors): (MoveData<'tcx>, Option<Vec<(Place<'tcx>, MoveError<'tcx>)>>) = + let (move_data, move_errors): (MoveData<'tcx>, Vec<(Place<'tcx>, MoveError<'tcx>)>) = match MoveData::gather_moves(&body, tcx, param_env) { - Ok(move_data) => (move_data, None), - Err((move_data, move_errors)) => (move_data, Some(move_errors)), + Ok(move_data) => (move_data, Vec::new()), + Err((move_data, move_errors)) => (move_data, move_errors), }; + let promoted_errors = promoted + .iter_enumerated() + .map(|(idx, body)| (idx, MoveData::gather_moves(&body, tcx, param_env))); let mdpe = MoveDataParamEnv { move_data, param_env }; @@ -264,6 +268,41 @@ fn do_mir_borrowck<'a, 'tcx>( _ => true, }; + for (idx, move_data_results) in promoted_errors { + let promoted_body = &promoted[idx]; + let dominators = promoted_body.dominators(); + + if let Err((move_data, move_errors)) = move_data_results { + let mut promoted_mbcx = MirBorrowckCtxt { + infcx, + body: promoted_body, + mir_def_id: def_id.to_def_id(), + move_data: &move_data, + location_table: &LocationTable::new(promoted_body), + movable_generator, + locals_are_invalidated_at_exit, + access_place_error_reported: Default::default(), + reservation_error_reported: Default::default(), + reservation_warnings: Default::default(), + move_error_reported: BTreeMap::new(), + uninitialized_error_reported: Default::default(), + errors_buffer, + regioncx: regioncx.clone(), + used_mut: Default::default(), + used_mut_upvars: SmallVec::new(), + borrow_set: borrow_set.clone(), + dominators, + upvars: Vec::new(), + local_names: IndexVec::from_elem(None, &promoted_body.local_decls), + region_names: RefCell::default(), + next_region_name: RefCell::new(1), + polonius_output: None, + }; + promoted_mbcx.report_move_errors(move_errors); + errors_buffer = promoted_mbcx.errors_buffer; + }; + } + let dominators = body.dominators(); let mut mbcx = MirBorrowckCtxt { @@ -301,9 +340,7 @@ fn do_mir_borrowck<'a, 'tcx>( borrows: flow_borrows, }; - if let Some(errors) = move_errors { - mbcx.report_move_errors(errors); - } + mbcx.report_move_errors(move_errors); dataflow::visit_results( &body, diff --git a/src/librustc_mir/borrow_check/nll.rs b/src/librustc_mir/borrow_check/nll.rs index e0cfcdb87a5..29636a06709 100644 --- a/src/librustc_mir/borrow_check/nll.rs +++ b/src/librustc_mir/borrow_check/nll.rs @@ -21,8 +21,8 @@ use std::str::FromStr; use self::mir_util::PassWhere; use polonius_engine::{Algorithm, Output}; +use crate::dataflow::impls::MaybeInitializedPlaces; use crate::dataflow::move_paths::{InitKind, InitLocation, MoveData}; -use crate::dataflow::MaybeInitializedPlaces; use crate::dataflow::ResultsCursor; use crate::transform::MirSource; use crate::util as mir_util; diff --git a/src/librustc_mir/borrow_check/type_check/liveness/local_use_map.rs b/src/librustc_mir/borrow_check/type_check/liveness/local_use_map.rs index 0fdf96710c6..995e3a60a0c 100644 --- a/src/librustc_mir/borrow_check/type_check/liveness/local_use_map.rs +++ b/src/librustc_mir/borrow_check/type_check/liveness/local_use_map.rs @@ -3,8 +3,7 @@ use rustc_index::vec::IndexVec; use rustc_middle::mir::visit::{PlaceContext, Visitor}; use rustc_middle::mir::{Body, Local, Location}; -use crate::util::liveness::{categorize, DefUse}; - +use crate::borrow_check::def_use::{self, DefUse}; use crate::borrow_check::region_infer::values::{PointIndex, RegionValueElements}; /// A map that cross references each local with the locations where it @@ -160,7 +159,7 @@ impl LocalUseMapBuild<'_> { impl Visitor<'tcx> for LocalUseMapBuild<'_> { fn visit_local(&mut self, &local: &Local, context: PlaceContext, location: Location) { if self.locals_with_use_data[local] { - match categorize(context) { + match def_use::categorize(context) { Some(DefUse::Def) => self.insert_def(local, location), Some(DefUse::Use) => self.insert_use(local, location), Some(DefUse::Drop) => self.insert_drop(local, location), diff --git a/src/librustc_mir/borrow_check/type_check/liveness/mod.rs b/src/librustc_mir/borrow_check/type_check/liveness/mod.rs index 717bfb8fe7d..bddcd34ed3e 100644 --- a/src/librustc_mir/borrow_check/type_check/liveness/mod.rs +++ b/src/librustc_mir/borrow_check/type_check/liveness/mod.rs @@ -3,8 +3,8 @@ use rustc_middle::mir::{Body, Local}; use rustc_middle::ty::{RegionVid, TyCtxt}; use std::rc::Rc; +use crate::dataflow::impls::MaybeInitializedPlaces; use crate::dataflow::move_paths::MoveData; -use crate::dataflow::MaybeInitializedPlaces; use crate::dataflow::ResultsCursor; use crate::borrow_check::{ diff --git a/src/librustc_mir/borrow_check/type_check/liveness/polonius.rs b/src/librustc_mir/borrow_check/type_check/liveness/polonius.rs index 2e033896ce1..d285098c52a 100644 --- a/src/librustc_mir/borrow_check/type_check/liveness/polonius.rs +++ b/src/librustc_mir/borrow_check/type_check/liveness/polonius.rs @@ -1,7 +1,7 @@ +use crate::borrow_check::def_use::{self, DefUse}; use crate::borrow_check::location::{LocationIndex, LocationTable}; use crate::dataflow::indexes::MovePathIndex; use crate::dataflow::move_paths::{LookupResult, MoveData}; -use crate::util::liveness::{categorize, DefUse}; use rustc_middle::mir::visit::{MutatingUseContext, PlaceContext, Visitor}; use rustc_middle::mir::{Body, Local, Location, Place}; use rustc_middle::ty::subst::GenericArg; @@ -56,7 +56,7 @@ impl UseFactsExtractor<'_> { impl Visitor<'tcx> for UseFactsExtractor<'_> { fn visit_local(&mut self, &local: &Local, context: PlaceContext, location: Location) { - match categorize(context) { + match def_use::categorize(context) { Some(DefUse::Def) => self.insert_def(local, location), Some(DefUse::Use) => self.insert_use(local, location), Some(DefUse::Drop) => self.insert_drop_use(local, location), diff --git a/src/librustc_mir/borrow_check/type_check/liveness/trace.rs b/src/librustc_mir/borrow_check/type_check/liveness/trace.rs index 41c77cf21a7..f04736e04a0 100644 --- a/src/librustc_mir/borrow_check/type_check/liveness/trace.rs +++ b/src/librustc_mir/borrow_check/type_check/liveness/trace.rs @@ -8,9 +8,9 @@ use rustc_trait_selection::traits::query::type_op::outlives::DropckOutlives; use rustc_trait_selection::traits::query::type_op::TypeOp; use std::rc::Rc; +use crate::dataflow::impls::MaybeInitializedPlaces; use crate::dataflow::indexes::MovePathIndex; use crate::dataflow::move_paths::{HasMoveData, MoveData}; -use crate::dataflow::MaybeInitializedPlaces; use crate::dataflow::ResultsCursor; use crate::borrow_check::{ diff --git a/src/librustc_mir/borrow_check/type_check/mod.rs b/src/librustc_mir/borrow_check/type_check/mod.rs index bd38ad04e7e..ee8a4358147 100644 --- a/src/librustc_mir/borrow_check/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/type_check/mod.rs @@ -39,8 +39,8 @@ use rustc_trait_selection::traits::query::type_op::custom::CustomTypeOp; use rustc_trait_selection::traits::query::{Fallible, NoSolution}; use rustc_trait_selection::traits::{self, ObligationCause, PredicateObligations}; +use crate::dataflow::impls::MaybeInitializedPlaces; use crate::dataflow::move_paths::MoveData; -use crate::dataflow::MaybeInitializedPlaces; use crate::dataflow::ResultsCursor; use crate::transform::{ check_consts::ConstCx, @@ -2293,36 +2293,54 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { right, ) => { let ty_left = left.ty(body, tcx); - if let ty::RawPtr(_) | ty::FnPtr(_) = ty_left.kind { - let ty_right = right.ty(body, tcx); - let common_ty = self.infcx.next_ty_var(TypeVariableOrigin { - kind: TypeVariableOriginKind::MiscVariable, - span: body.source_info(location).span, - }); - self.sub_types( - common_ty, - ty_left, - location.to_locations(), - ConstraintCategory::Boring, - ) - .unwrap_or_else(|err| { - bug!("Could not equate type variable with {:?}: {:?}", ty_left, err) - }); - if let Err(terr) = self.sub_types( - common_ty, - ty_right, - location.to_locations(), - ConstraintCategory::Boring, - ) { - span_mirbug!( - self, - rvalue, - "unexpected comparison types {:?} and {:?} yields {:?}", + match ty_left.kind { + // Types with regions are comparable if they have a common super-type. + ty::RawPtr(_) | ty::FnPtr(_) => { + let ty_right = right.ty(body, tcx); + let common_ty = self.infcx.next_ty_var(TypeVariableOrigin { + kind: TypeVariableOriginKind::MiscVariable, + span: body.source_info(location).span, + }); + self.relate_types( + common_ty, + ty::Variance::Contravariant, ty_left, - ty_right, - terr + location.to_locations(), + ConstraintCategory::Boring, ) + .unwrap_or_else(|err| { + bug!("Could not equate type variable with {:?}: {:?}", ty_left, err) + }); + if let Err(terr) = self.relate_types( + common_ty, + ty::Variance::Contravariant, + ty_right, + location.to_locations(), + ConstraintCategory::Boring, + ) { + span_mirbug!( + self, + rvalue, + "unexpected comparison types {:?} and {:?} yields {:?}", + ty_left, + ty_right, + terr + ) + } } + // For types with no regions we can just check that the + // both operands have the same type. + ty::Int(_) | ty::Uint(_) | ty::Bool | ty::Char | ty::Float(_) + if ty_left == right.ty(body, tcx) => {} + // Other types are compared by trait methods, not by + // `Rvalue::BinaryOp`. + _ => span_mirbug!( + self, + rvalue, + "unexpected comparison types {:?} and {:?}", + ty_left, + right.ty(body, tcx) + ), } } diff --git a/src/librustc_mir/dataflow/impls/liveness.rs b/src/librustc_mir/dataflow/impls/liveness.rs index 5e9bec89ac0..d24faacd377 100644 --- a/src/librustc_mir/dataflow/impls/liveness.rs +++ b/src/librustc_mir/dataflow/impls/liveness.rs @@ -6,6 +6,13 @@ use crate::dataflow::{AnalysisDomain, Backward, BottomValue, GenKill, GenKillAna /// A [live-variable dataflow analysis][liveness]. /// +/// This analysis considers references as being used only at the point of the +/// borrow. In other words, this analysis does not track uses because of references that already +/// exist. See [this `mir-datalow` test][flow-test] for an example. You almost never want to use +/// this analysis without also looking at the results of [`MaybeBorrowedLocals`]. +/// +/// [`MaybeBorrowedLocals`]: ../struct.MaybeBorrowedLocals.html +/// [flow-test]: https://github.com/rust-lang/rust/blob/a08c47310c7d49cbdc5d7afb38408ba519967ecd/src/test/ui/mir-dataflow/liveness-ptr.rs /// [liveness]: https://en.wikipedia.org/wiki/Live_variable_analysis pub struct MaybeLiveLocals; diff --git a/src/librustc_mir/dataflow/impls/mod.rs b/src/librustc_mir/dataflow/impls/mod.rs index 222ae137d96..e199a174efb 100644 --- a/src/librustc_mir/dataflow/impls/mod.rs +++ b/src/librustc_mir/dataflow/impls/mod.rs @@ -21,14 +21,14 @@ use super::on_lookup_result_bits; use crate::dataflow::drop_flag_effects; mod borrowed_locals; +pub(super) mod borrows; mod liveness; mod storage_liveness; -pub use self::borrowed_locals::*; +pub use self::borrowed_locals::{MaybeBorrowedLocals, MaybeMutBorrowedLocals}; +pub use self::borrows::Borrows; pub use self::liveness::MaybeLiveLocals; -pub use self::storage_liveness::*; - -pub(super) mod borrows; +pub use self::storage_liveness::{MaybeRequiresStorage, MaybeStorageLive}; /// `MaybeInitializedPlaces` tracks all places that might be /// initialized upon reaching a particular point in the control flow diff --git a/src/librustc_mir/dataflow/mod.rs b/src/librustc_mir/dataflow/mod.rs index a05b4a5385d..ae1328dbd12 100644 --- a/src/librustc_mir/dataflow/mod.rs +++ b/src/librustc_mir/dataflow/mod.rs @@ -8,17 +8,12 @@ pub use self::framework::{ BottomValue, Engine, Forward, GenKill, GenKillAnalysis, Results, ResultsCursor, ResultsRefCursor, ResultsVisitor, }; -pub use self::impls::{ - borrows::Borrows, DefinitelyInitializedPlaces, EverInitializedPlaces, MaybeBorrowedLocals, - MaybeInitializedPlaces, MaybeLiveLocals, MaybeMutBorrowedLocals, MaybeRequiresStorage, - MaybeStorageLive, MaybeUninitializedPlaces, -}; use self::move_paths::MoveData; pub mod drop_flag_effects; mod framework; -mod impls; +pub mod impls; pub mod move_paths; pub(crate) mod indexes { diff --git a/src/librustc_mir/interpret/memory.rs b/src/librustc_mir/interpret/memory.rs index d1881524172..39e428cee1d 100644 --- a/src/librustc_mir/interpret/memory.rs +++ b/src/librustc_mir/interpret/memory.rs @@ -400,18 +400,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { // We can still be zero-sized in this branch, in which case we have to // return `None`. - if size.bytes() == 0 { - // We may be reading from a static. - // In order to ensure that `static FOO: Type = FOO;` causes a cycle error - // instead of magically pulling *any* ZST value from the ether, we need to - // actually access the referenced allocation. The caller is likely - // to short-circuit on `None`, so we trigger the access here to - // make sure it happens. - self.get_raw(ptr.alloc_id)?; - None - } else { - Some(ptr) - } + if size.bytes() == 0 { None } else { Some(ptr) } } }) } diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs index e2fb9de486f..db836d88dd0 100644 --- a/src/librustc_mir/interpret/operand.rs +++ b/src/librustc_mir/interpret/operand.rs @@ -240,6 +240,13 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { { Some(ptr) => ptr, None => { + if let Scalar::Ptr(ptr) = mplace.ptr { + // We may be reading from a static. + // In order to ensure that `static FOO: Type = FOO;` causes a cycle error + // instead of magically pulling *any* ZST value from the ether, we need to + // actually access the referenced allocation. + self.memory.get_raw(ptr.alloc_id)?; + } return Ok(Some(ImmTy { // zero-sized type imm: Scalar::zst().into(), @@ -320,8 +327,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { pub fn read_str(&self, mplace: MPlaceTy<'tcx, M::PointerTag>) -> InterpResult<'tcx, &str> { let len = mplace.len(self)?; let bytes = self.memory.read_bytes(mplace.ptr, Size::from_bytes(len))?; - let str = ::std::str::from_utf8(bytes) - .map_err(|err| err_ub_format!("this string is not valid UTF-8: {}", err))?; + let str = ::std::str::from_utf8(bytes).map_err(|err| err_ub!(InvalidStr(err)))?; Ok(str) } diff --git a/src/librustc_mir/interpret/traits.rs b/src/librustc_mir/interpret/traits.rs index 7edd787c986..b9f9d37df76 100644 --- a/src/librustc_mir/interpret/traits.rs +++ b/src/librustc_mir/interpret/traits.rs @@ -147,14 +147,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // The drop function takes `*mut T` where `T` is the type being dropped, so get that. let args = fn_sig.inputs(); if args.len() != 1 { - throw_ub_format!("drop fn should have 1 argument, but signature is {:?}", fn_sig); + throw_ub!(InvalidDropFn(fn_sig)); } - let ty = args[0] - .builtin_deref(true) - .ok_or_else(|| { - err_ub_format!("drop fn argument type {} is not a pointer type", args[0]) - })? - .ty; + let ty = args[0].builtin_deref(true).ok_or_else(|| err_ub!(InvalidDropFn(fn_sig)))?.ty; Ok((drop_instance, ty)) } diff --git a/src/librustc_mir/interpret/validity.rs b/src/librustc_mir/interpret/validity.rs index b6991349ff4..eb743675d91 100644 --- a/src/librustc_mir/interpret/validity.rs +++ b/src/librustc_mir/interpret/validity.rs @@ -25,43 +25,39 @@ use super::{ }; macro_rules! throw_validation_failure { - ($what:expr, $where:expr $(, $expected:expr )?) => {{ - let mut msg = format!("encountered {}", $what); + ($where:expr, { $( $what_fmt:expr ),+ } $( expected { $( $expected_fmt:expr ),+ } )?) => {{ + let mut msg = String::new(); + msg.push_str("encountered "); + write!(&mut msg, $($what_fmt),+).unwrap(); let where_ = &$where; if !where_.is_empty() { msg.push_str(" at "); write_path(&mut msg, where_); } - $( write!(&mut msg, ", but expected {}", $expected).unwrap(); )? + $( + msg.push_str(", but expected "); + write!(&mut msg, $($expected_fmt),+).unwrap(); + )? throw_ub!(ValidationFailure(msg)) }}; } -/// Returns a validation failure for any Err value of $e. -// FIXME: Replace all usages of try_validation! with try_validation_pat!. -macro_rules! try_validation { - ($e:expr, $what:expr, $where:expr $(, $expected:expr )?) => {{ - try_validation_pat!($e, $where, { - _ => { "{}", $what } $( expected { "{}", $expected } )?, - }) - }}; -} -/// Like try_validation, but will throw a validation error if any of the patterns in $p are -/// matched. Other errors are passed back to the caller, unchanged. This lets you use the patterns -/// as a kind of validation blacklist: +/// If $e throws an error matching the pattern, throw a validation failure. +/// Other errors are passed back to the caller, unchanged -- and if they reach the root of +/// the visitor, we make sure only validation errors and `InvalidProgram` errors are left. +/// This lets you use the patterns as a kind of validation whitelist, asserting which errors +/// can possibly happen: /// /// ``` -/// let v = try_validation_pat!(some_fn(), some_path, { +/// let v = try_validation!(some_fn(), some_path, { /// Foo | Bar | Baz => { "some failure" }, /// }); -/// // Failures that match $p are thrown up as validation errors, but other errors are passed back -/// // unchanged. /// ``` /// /// An additional expected parameter can also be added to the failure message: /// /// ``` -/// let v = try_validation_pat!(some_fn(), some_path, { +/// let v = try_validation!(some_fn(), some_path, { /// Foo | Bar | Baz => { "some failure" } expected { "something that wasn't a failure" }, /// }); /// ``` @@ -70,24 +66,25 @@ macro_rules! try_validation { /// the format string in directly: /// /// ``` -/// let v = try_validation_pat!(some_fn(), some_path, { +/// let v = try_validation!(some_fn(), some_path, { /// Foo | Bar | Baz => { "{:?}", some_failure } expected { "{}", expected_value }, /// }); /// ``` /// -macro_rules! try_validation_pat { - ($e:expr, $where:expr, { $( $p:pat )|+ => - { $( $what_fmt:expr ),+ } $( expected { $( $expected_fmt:expr ),+ } )? $( , )?}) => {{ +macro_rules! try_validation { + ($e:expr, $where:expr, + $( $( $p:pat )|+ => { $( $what_fmt:expr ),+ } $( expected { $( $expected_fmt:expr ),+ } )? ),+ $(,)? + ) => {{ match $e { Ok(x) => x, // We catch the error and turn it into a validation failure. We are okay with // allocation here as this can only slow down builds that fail anyway. - $( Err(InterpErrorInfo { kind: $p, .. }) )|+ => + $( $( Err(InterpErrorInfo { kind: $p, .. }) )|+ => throw_validation_failure!( - format_args!($( $what_fmt ),+), - $where - $(, format_args!($( $expected_fmt ),+))? + $where, + { $( $what_fmt ),+ } $( expected { $( $expected_fmt ),+ } )? ), + )+ #[allow(unreachable_patterns)] Err(e) => Err::<!, _>(e)?, } @@ -303,32 +300,46 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' match tail.kind { ty::Dynamic(..) => { let vtable = meta.unwrap_meta(); + // Direct call to `check_ptr_access_align` checks alignment even on CTFE machines. try_validation!( - self.ecx.memory.check_ptr_access( + self.ecx.memory.check_ptr_access_align( vtable, 3 * self.ecx.tcx.data_layout.pointer_size, // drop, size, align - self.ecx.tcx.data_layout.pointer_align.abi, + Some(self.ecx.tcx.data_layout.pointer_align.abi), + CheckInAllocMsg::InboundsTest, ), - "dangling or unaligned vtable pointer in wide pointer or too small vtable", - self.path + self.path, + err_ub!(DanglingIntPointer(..)) | + err_ub!(PointerUseAfterFree(..)) | + err_unsup!(ReadBytesAsPointer) => + { "dangling vtable pointer in wide pointer" }, + err_ub!(AlignmentCheckFailed { .. }) => + { "unaligned vtable pointer in wide pointer" }, + err_ub!(PointerOutOfBounds { .. }) => + { "too small vtable" }, ); try_validation!( self.ecx.read_drop_type_from_vtable(vtable), - "invalid drop fn in vtable", - self.path + self.path, + err_ub!(DanglingIntPointer(..)) | + err_ub!(InvalidFunctionPointer(..)) | + err_unsup!(ReadBytesAsPointer) => + { "invalid drop function pointer in vtable (not pointing to a function)" }, + err_ub!(InvalidDropFn(..)) => + { "invalid drop function pointer in vtable (function has incompatible signature)" }, ); try_validation!( self.ecx.read_size_and_align_from_vtable(vtable), - "invalid size or align in vtable", - self.path + self.path, + err_unsup!(ReadPointerAsBytes) => { "invalid size or align in vtable" }, ); // FIXME: More checks for the vtable. } ty::Slice(..) | ty::Str => { let _len = try_validation!( meta.unwrap_meta().to_machine_usize(self.ecx), - "non-integer slice length in wide pointer", - self.path + self.path, + err_unsup!(ReadPointerAsBytes) => { "non-integer slice length in wide pointer" }, ); // We do not check that `len * elem_size <= isize::MAX`: // that is only required for references, and there it falls out of the @@ -354,78 +365,52 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' // Check metadata early, for better diagnostics let place = try_validation!( self.ecx.ref_to_mplace(value), - format_args!("uninitialized {}", kind), - self.path + self.path, + err_ub!(InvalidUndefBytes(..)) => { "uninitialized {}", kind }, ); if place.layout.is_unsized() { self.check_wide_ptr_meta(place.meta, place.layout)?; } // Make sure this is dereferenceable and all. - let size_and_align = match self.ecx.size_and_align_of(place.meta, place.layout) { - Ok(res) => res, - Err(err) => match err.kind { - err_ub!(InvalidMeta(msg)) => throw_validation_failure!( - format_args!("invalid {} metadata: {}", kind, msg), - self.path - ), - _ => bug!("unexpected error during ptr size_and_align_of: {}", err), - }, - }; + let size_and_align = try_validation!( + self.ecx.size_and_align_of(place.meta, place.layout), + self.path, + err_ub!(InvalidMeta(msg)) => { "invalid {} metadata: {}", kind, msg }, + ); let (size, align) = size_and_align // for the purpose of validity, consider foreign types to have // alignment and size determined by the layout (size will be 0, // alignment should take attributes into account). .unwrap_or_else(|| (place.layout.size, place.layout.align.abi)); - let ptr: Option<_> = match self.ecx.memory.check_ptr_access_align( - place.ptr, - size, - Some(align), - CheckInAllocMsg::InboundsTest, - ) { - Ok(ptr) => ptr, - Err(err) => { - info!( - "{:?} did not pass access check for size {:?}, align {:?}", - place.ptr, size, align - ); - match err.kind { - err_ub!(DanglingIntPointer(0, _)) => { - throw_validation_failure!(format_args!("a NULL {}", kind), self.path) - } - err_ub!(DanglingIntPointer(i, _)) => throw_validation_failure!( - format_args!("a {} to unallocated address {}", kind, i), - self.path - ), - err_ub!(AlignmentCheckFailed { required, has }) => throw_validation_failure!( - format_args!( - "an unaligned {} (required {} byte alignment but found {})", - kind, - required.bytes(), - has.bytes() - ), - self.path - ), - err_unsup!(ReadBytesAsPointer) => throw_validation_failure!( - format_args!("a dangling {} (created from integer)", kind), - self.path - ), - err_ub!(PointerOutOfBounds { .. }) => throw_validation_failure!( - format_args!( - "a dangling {} (going beyond the bounds of its allocation)", - kind - ), - self.path - ), - // This cannot happen during const-eval (because interning already detects - // dangling pointers), but it can happen in Miri. - err_ub!(PointerUseAfterFree(_)) => throw_validation_failure!( - format_args!("a dangling {} (use-after-free)", kind), - self.path - ), - _ => bug!("Unexpected error during ptr inbounds test: {}", err), - } - } - }; + // Direct call to `check_ptr_access_align` checks alignment even on CTFE machines. + let ptr: Option<_> = try_validation!( + self.ecx.memory.check_ptr_access_align( + place.ptr, + size, + Some(align), + CheckInAllocMsg::InboundsTest, + ), + self.path, + err_ub!(AlignmentCheckFailed { required, has }) => + { + "an unaligned {} (required {} byte alignment but found {})", + kind, + required.bytes(), + has.bytes() + }, + err_ub!(DanglingIntPointer(0, _)) => + { "a NULL {}", kind }, + err_ub!(DanglingIntPointer(i, _)) => + { "a dangling {} (address 0x{:x} is unallocated)", kind, i }, + err_ub!(PointerOutOfBounds { .. }) => + { "a dangling {} (going beyond the bounds of its allocation)", kind }, + err_unsup!(ReadBytesAsPointer) => + { "a dangling {} (created from integer)", kind }, + // This cannot happen during const-eval (because interning already detects + // dangling pointers), but it can happen in Miri. + err_ub!(PointerUseAfterFree(..)) => + { "a dangling {} (use-after-free)", kind }, + ); // Recursive checking if let Some(ref mut ref_tracking) = self.ref_tracking_for_consts { if let Some(ptr) = ptr { @@ -440,9 +425,8 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' // We also need to do it here instead of going on to avoid running // into the `before_access_global` check during validation. if !self.may_ref_to_static && self.ecx.tcx.is_static(did) { - throw_validation_failure!( - format_args!("a {} pointing to a static variable", kind), - self.path + throw_validation_failure!(self.path, + { "a {} pointing to a static variable", kind } ); } // `extern static` cannot be validated as they have no body. @@ -489,12 +473,20 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' match ty.kind { ty::Bool => { let value = self.ecx.read_scalar(value)?; - try_validation!(value.to_bool(), value, self.path, "a boolean"); + try_validation!( + value.to_bool(), + self.path, + err_ub!(InvalidBool(..)) => { "{}", value } expected { "a boolean" }, + ); Ok(true) } ty::Char => { let value = self.ecx.read_scalar(value)?; - try_validation!(value.to_char(), value, self.path, "a valid unicode codepoint"); + try_validation!( + value.to_char(), + self.path, + err_ub!(InvalidChar(..)) => { "{}", value } expected { "a valid unicode codepoint" }, + ); Ok(true) } ty::Float(_) | ty::Int(_) | ty::Uint(_) => { @@ -505,10 +497,8 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' // Integers/floats in CTFE: Must be scalar bits, pointers are dangerous let is_bits = value.not_undef().map_or(false, |v| v.is_bits()); if !is_bits { - throw_validation_failure!( - value, - self.path, - "initialized plain (non-pointer) bytes" + throw_validation_failure!(self.path, + { "{}", value } expected { "initialized plain (non-pointer) bytes" } ) } } else { @@ -521,9 +511,11 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' // We are conservative with undef for integers, but try to // actually enforce the strict rules for raw pointers (mostly because // that lets us re-use `ref_to_mplace`). - let place = try_validation_pat!(self.ecx.ref_to_mplace(self.ecx.read_immediate(value)?), self.path, { + let place = try_validation!( + self.ecx.ref_to_mplace(self.ecx.read_immediate(value)?), + self.path, err_ub!(InvalidUndefBytes(..)) => { "uninitialized raw pointer" }, - }); + ); if place.layout.is_unsized() { self.check_wide_ptr_meta(place.meta, place.layout)?; } @@ -541,14 +533,16 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' let value = self.ecx.read_scalar(value)?; let _fn = try_validation!( value.not_undef().and_then(|ptr| self.ecx.memory.get_fn(ptr)), - value, self.path, - "a function pointer" + err_ub!(DanglingIntPointer(..)) | + err_ub!(InvalidFunctionPointer(..)) | + err_unsup!(ReadBytesAsPointer) => + { "{}", value } expected { "a function pointer" }, ); // FIXME: Check if the signature matches Ok(true) } - ty::Never => throw_validation_failure!("a value of the never type `!`", self.path), + ty::Never => throw_validation_failure!(self.path, { "a value of the never type `!`" }), ty::Foreign(..) | ty::FnDef(..) => { // Nothing to check. Ok(true) @@ -598,35 +592,33 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' // At least one value is excluded. Get the bits. let value = try_validation!( value.not_undef(), - value, self.path, - format_args!("something {}", wrapping_range_format(valid_range, max_hi),) + err_ub!(InvalidUndefBytes(..)) => { "{}", value } + expected { "something {}", wrapping_range_format(valid_range, max_hi) }, ); let bits = match value.to_bits_or_ptr(op.layout.size, self.ecx) { Err(ptr) => { if lo == 1 && hi == max_hi { // Only NULL is the niche. So make sure the ptr is NOT NULL. if self.ecx.memory.ptr_may_be_null(ptr) { - throw_validation_failure!( - "a potentially NULL pointer", - self.path, - format_args!( + throw_validation_failure!(self.path, + { "a potentially NULL pointer" } + expected { "something that cannot possibly fail to be {}", wrapping_range_format(valid_range, max_hi) - ) + } ) } return Ok(()); } else { // Conservatively, we reject, because the pointer *could* have a bad // value. - throw_validation_failure!( - "a pointer", - self.path, - format_args!( + throw_validation_failure!(self.path, + { "a pointer" } + expected { "something that cannot possibly fail to be {}", wrapping_range_format(valid_range, max_hi) - ) + } ) } } @@ -636,10 +628,9 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' if wrapping_range_contains(&valid_range, bits) { Ok(()) } else { - throw_validation_failure!( - bits, - self.path, - format_args!("something {}", wrapping_range_format(valid_range, max_hi)) + throw_validation_failure!(self.path, + { "{}", bits } + expected { "something {}", wrapping_range_format(valid_range, max_hi) } ) } } @@ -703,19 +694,14 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> assert!(op.layout.ty.builtin_deref(true).is_none()); // Recursively walk the type. Translate some possible errors to something nicer. - match self.walk_value(op) { - Ok(()) => {} - Err(err) => match err.kind { - err_ub!(InvalidDiscriminant(val)) => { - throw_validation_failure!(val, self.path, "a valid enum discriminant") - } - err_unsup!(ReadPointerAsBytes) => { - throw_validation_failure!("a pointer", self.path, "plain (non-pointer) bytes") - } - // Propagate upwards (that will also check for unexpected errors). - _ => return Err(err), - }, - } + try_validation!( + self.walk_value(op), + self.path, + err_ub!(InvalidDiscriminant(val)) => + { "{}", val } expected { "a valid enum discriminant" }, + err_unsup!(ReadPointerAsBytes) => + { "a pointer" } expected { "plain (non-pointer) bytes" }, + ); // *After* all of this, check the ABI. We need to check the ABI to handle // types like `NonNull` where the `Scalar` info is more restrictive than what @@ -729,9 +715,8 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> // MyNewtype and then the scalar in there). match op.layout.abi { Abi::Uninhabited => { - throw_validation_failure!( - format_args!("a value of uninhabited type {:?}", op.layout.ty), - self.path + throw_validation_failure!(self.path, + { "a value of uninhabited type {:?}", op.layout.ty } ); } Abi::Scalar(ref scalar_layout) => { @@ -761,8 +746,8 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> let mplace = op.assert_mem_place(self.ecx); // strings are never immediate try_validation!( self.ecx.read_str(mplace), - "uninitialized or non-UTF-8 data in str", - self.path + self.path, + err_ub!(InvalidStr(..)) => { "uninitialized or non-UTF-8 data in str" }, ); } ty::Array(tys, ..) | ty::Slice(tys) @@ -815,7 +800,8 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> Ok(()) => {} // Some error happened, try to provide a more detailed description. Err(err) => { - // For some errors we might be able to provide extra information + // For some errors we might be able to provide extra information. + // (This custom logic does not fit the `try_validation!` macro.) match err.kind { err_ub!(InvalidUndefBytes(Some(ptr))) => { // Some byte was uninitialized, determine which @@ -825,7 +811,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> .unwrap(); self.path.push(PathElem::ArrayElem(i)); - throw_validation_failure!("uninitialized bytes", self.path) + throw_validation_failure!(self.path, { "uninitialized bytes" }) } // Propagate upwards (that will also check for unexpected errors). _ => return Err(err), @@ -876,7 +862,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // validate and each caller will know best what to do with them. Err(err) if matches!(err.kind, InterpError::InvalidProgram(_)) => Err(err), // Avoid other errors as those do not show *where* in the value the issue lies. - Err(err) => bug!("Unexpected error during validation: {}", err), + Err(err) => { + err.print_backtrace(); + bug!("Unexpected error during validation: {}", err); + } } } diff --git a/src/librustc_mir/monomorphize/collector.rs b/src/librustc_mir/monomorphize/collector.rs index dfcd2c3c936..3d798254735 100644 --- a/src/librustc_mir/monomorphize/collector.rs +++ b/src/librustc_mir/monomorphize/collector.rs @@ -369,7 +369,9 @@ fn collect_items_rec<'tcx>( recursion_depth_reset = Some(check_recursion_limit(tcx, instance, recursion_depths)); check_type_length_limit(tcx, instance); - collect_neighbours(tcx, instance, &mut neighbors); + rustc_data_structures::stack::ensure_sufficient_stack(|| { + collect_neighbours(tcx, instance, &mut neighbors); + }); } MonoItem::GlobalAsm(..) => { recursion_depth_reset = None; @@ -1146,7 +1148,9 @@ fn collect_miri<'tcx>(tcx: TyCtxt<'tcx>, alloc_id: AllocId, output: &mut Vec<Mon Some(GlobalAlloc::Memory(alloc)) => { trace!("collecting {:?} with {:#?}", alloc_id, alloc); for &((), inner) in alloc.relocations().values() { - collect_miri(tcx, inner, output); + rustc_data_structures::stack::ensure_sufficient_stack(|| { + collect_miri(tcx, inner, output); + }); } } Some(GlobalAlloc::Function(fn_instance)) => { diff --git a/src/librustc_mir/transform/check_consts/mod.rs b/src/librustc_mir/transform/check_consts/mod.rs index 46a46aa5ae9..7c439f80ef6 100644 --- a/src/librustc_mir/transform/check_consts/mod.rs +++ b/src/librustc_mir/transform/check_consts/mod.rs @@ -9,8 +9,6 @@ use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_middle::mir; use rustc_middle::ty::{self, TyCtxt}; -use std::fmt; - pub use self::qualifs::Qualif; mod ops; @@ -25,7 +23,7 @@ pub struct ConstCx<'mir, 'tcx> { pub tcx: TyCtxt<'tcx>, pub def_id: DefId, pub param_env: ty::ParamEnv<'tcx>, - pub const_kind: Option<ConstKind>, + pub const_kind: Option<hir::ConstContext>, } impl ConstCx<'mir, 'tcx> { @@ -40,78 +38,18 @@ impl ConstCx<'mir, 'tcx> { body: &'mir mir::Body<'tcx>, param_env: ty::ParamEnv<'tcx>, ) -> Self { - let const_kind = ConstKind::for_item(tcx, def_id); - + let const_kind = tcx.hir().body_const_context(def_id); ConstCx { body, tcx, def_id: def_id.to_def_id(), param_env, const_kind } } /// Returns the kind of const context this `Item` represents (`const`, `static`, etc.). /// /// Panics if this `Item` is not const. - pub fn const_kind(&self) -> ConstKind { + pub fn const_kind(&self) -> hir::ConstContext { self.const_kind.expect("`const_kind` must not be called on a non-const fn") } } -/// The kinds of items which require compile-time evaluation. -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub enum ConstKind { - /// A `static` item. - Static, - /// A `static mut` item. - StaticMut, - /// A `const fn` item. - ConstFn, - /// A `const` item or an anonymous constant (e.g. in array lengths). - Const, -} - -impl ConstKind { - /// Returns the validation mode for the item with the given `DefId`, or `None` if this item - /// does not require validation (e.g. a non-const `fn`). - pub fn for_item(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Option<Self> { - use hir::BodyOwnerKind as HirKind; - - let hir_id = tcx.hir().as_local_hir_id(def_id); - - let mode = match tcx.hir().body_owner_kind(hir_id) { - HirKind::Closure => return None, - - // Note: this is deliberately checking for `is_const_fn_raw`, as the `is_const_fn` - // checks take into account the `rustc_const_unstable` attribute combined with enabled - // feature gates. Otherwise, const qualification would _not check_ whether this - // function body follows the `const fn` rules, as an unstable `const fn` would - // be considered "not const". More details are available in issue #67053. - HirKind::Fn if tcx.is_const_fn_raw(def_id) => ConstKind::ConstFn, - HirKind::Fn => return None, - - HirKind::Const => ConstKind::Const, - - HirKind::Static(hir::Mutability::Not) => ConstKind::Static, - HirKind::Static(hir::Mutability::Mut) => ConstKind::StaticMut, - }; - - Some(mode) - } - - pub fn is_static(self) -> bool { - match self { - ConstKind::Static | ConstKind::StaticMut => true, - ConstKind::ConstFn | ConstKind::Const => false, - } - } -} - -impl fmt::Display for ConstKind { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match *self { - ConstKind::Const => write!(f, "constant"), - ConstKind::Static | ConstKind::StaticMut => write!(f, "static"), - ConstKind::ConstFn => write!(f, "constant function"), - } - } -} - /// Returns `true` if this `DefId` points to one of the official `panic` lang items. pub fn is_lang_panic_fn(tcx: TyCtxt<'tcx>, def_id: DefId) -> bool { Some(def_id) == tcx.lang_items().panic_fn() || Some(def_id) == tcx.lang_items().begin_panic_fn() diff --git a/src/librustc_mir/transform/check_consts/ops.rs b/src/librustc_mir/transform/check_consts/ops.rs index fe20ceb47ee..28743ee8e36 100644 --- a/src/librustc_mir/transform/check_consts/ops.rs +++ b/src/librustc_mir/transform/check_consts/ops.rs @@ -1,13 +1,14 @@ //! Concrete error types for all operations which may be invalid in a certain const context. use rustc_errors::struct_span_err; +use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_session::config::nightly_options; use rustc_session::parse::feature_err; use rustc_span::symbol::sym; use rustc_span::{Span, Symbol}; -use super::{ConstCx, ConstKind}; +use super::ConstCx; /// An operation that is not *always* allowed in a const context. pub trait NonConstOp: std::fmt::Debug { @@ -39,6 +40,9 @@ pub trait NonConstOp: std::fmt::Debug { "{} contains unimplemented expression type", ccx.const_kind() ); + if let Some(feat) = Self::feature_gate() { + err.help(&format!("add `#![feature({})]` to the crate attributes to enable", feat)); + } if ccx.tcx.sess.teach(&err.get_code().unwrap()) { err.note( "A function call isn't allowed in the const's initialization expression \ @@ -323,7 +327,7 @@ impl NonConstOp for RawPtrToIntCast { pub struct StaticAccess; impl NonConstOp for StaticAccess { fn is_allowed_in_item(&self, ccx: &ConstCx<'_, '_>) -> bool { - ccx.const_kind().is_static() + matches!(ccx.const_kind(), hir::ConstContext::Static(_)) } fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) { @@ -371,7 +375,7 @@ pub struct UnionAccess; impl NonConstOp for UnionAccess { fn is_allowed_in_item(&self, ccx: &ConstCx<'_, '_>) -> bool { // Union accesses are stable in all contexts except `const fn`. - ccx.const_kind() != ConstKind::ConstFn + ccx.const_kind() != hir::ConstContext::ConstFn || ccx.tcx.features().enabled(Self::feature_gate().unwrap()) } diff --git a/src/librustc_mir/transform/check_consts/validation.rs b/src/librustc_mir/transform/check_consts/validation.rs index 10cf47d47ff..8c005fdcdbf 100644 --- a/src/librustc_mir/transform/check_consts/validation.rs +++ b/src/librustc_mir/transform/check_consts/validation.rs @@ -1,7 +1,7 @@ //! The `Visitor` responsible for actually checking a `mir::Body` for invalid operations. use rustc_errors::struct_span_err; -use rustc_hir::lang_items; +use rustc_hir::{self as hir, lang_items}; use rustc_hir::{def_id::DefId, HirId}; use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor}; @@ -18,9 +18,9 @@ use std::ops::Deref; use super::ops::{self, NonConstOp}; use super::qualifs::{self, CustomEq, HasMutInterior, NeedsDrop}; use super::resolver::FlowSensitiveAnalysis; -use super::{is_lang_panic_fn, ConstCx, ConstKind, Qualif}; +use super::{is_lang_panic_fn, ConstCx, Qualif}; use crate::const_eval::{is_const_fn, is_unstable_const_fn}; -use crate::dataflow::MaybeMutBorrowedLocals; +use crate::dataflow::impls::MaybeMutBorrowedLocals; use crate::dataflow::{self, Analysis}; // We are using `MaybeMutBorrowedLocals` as a proxy for whether an item may have been mutated @@ -145,17 +145,13 @@ impl Qualifs<'mir, 'tcx> { // We don't care whether a `const fn` returns a value that is not structurally // matchable. Functions calls are opaque and always use type-based qualification, so // this value should never be used. - ConstKind::ConstFn => true, + hir::ConstContext::ConstFn => true, // If we know that all values of the return type are structurally matchable, there's no // need to run dataflow. - ConstKind::Const | ConstKind::Static | ConstKind::StaticMut - if !CustomEq::in_any_value_of_ty(ccx, ccx.body.return_ty()) => - { - false - } + _ if !CustomEq::in_any_value_of_ty(ccx, ccx.body.return_ty()) => false, - ConstKind::Const | ConstKind::Static | ConstKind::StaticMut => { + hir::ConstContext::Const | hir::ConstContext::Static(_) => { let mut cursor = FlowSensitiveAnalysis::new(CustomEq, ccx) .into_engine(ccx.tcx, &ccx.body, ccx.def_id) .iterate_to_fixpoint() @@ -198,7 +194,7 @@ impl Validator<'mir, 'tcx> { pub fn check_body(&mut self) { let ConstCx { tcx, body, def_id, const_kind, .. } = *self.ccx; - let use_min_const_fn_checks = (const_kind == Some(ConstKind::ConstFn) + let use_min_const_fn_checks = (const_kind == Some(hir::ConstContext::ConstFn) && crate::const_eval::is_min_const_fn(tcx, def_id)) && !tcx.sess.opts.debugging_opts.unleash_the_miri_inside_of_you; @@ -222,8 +218,9 @@ impl Validator<'mir, 'tcx> { self.visit_body(&body); // Ensure that the end result is `Sync` in a non-thread local `static`. - let should_check_for_sync = - const_kind == Some(ConstKind::Static) && !tcx.is_thread_local_static(def_id); + let should_check_for_sync = const_kind + == Some(hir::ConstContext::Static(hir::Mutability::Not)) + && !tcx.is_thread_local_static(def_id); if should_check_for_sync { let hir_id = tcx.hir().as_local_hir_id(def_id.expect_local()); @@ -351,7 +348,9 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> { let ty = place.ty(self.body, self.tcx).ty; let is_allowed = match ty.kind { // Inside a `static mut`, `&mut [...]` is allowed. - ty::Array(..) | ty::Slice(_) if self.const_kind() == ConstKind::StaticMut => { + ty::Array(..) | ty::Slice(_) + if self.const_kind() == hir::ConstContext::Static(hir::Mutability::Mut) => + { true } diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index aae80185b4d..7926bf535b3 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -787,6 +787,7 @@ impl<'tcx> Visitor<'tcx> for CanConstProp { | NonMutatingUse(NonMutatingUseContext::Inspect) | NonMutatingUse(NonMutatingUseContext::Projection) | NonUse(_) => {} + // FIXME(felix91gr): explain the reasoning behind this MutatingUse(MutatingUseContext::Projection) => { if self.local_kinds[local] != LocalKind::Temp { self.can_const_prop[local] = ConstPropMode::NoPropagation; @@ -969,13 +970,58 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> { | TerminatorKind::GeneratorDrop | TerminatorKind::FalseEdges { .. } | TerminatorKind::FalseUnwind { .. } => {} - //FIXME(wesleywiser) Call does have Operands that could be const-propagated - TerminatorKind::Call { .. } => {} + // Every argument in our function calls can be const propagated. + TerminatorKind::Call { ref mut args, .. } => { + let mir_opt_level = self.tcx.sess.opts.debugging_opts.mir_opt_level; + // Constant Propagation into function call arguments is gated + // under mir-opt-level 2, because LLVM codegen gives performance + // regressions with it. + if mir_opt_level >= 2 { + for opr in args { + /* + The following code would appear to be incomplete, because + the function `Operand::place()` returns `None` if the + `Operand` is of the variant `Operand::Constant`. In this + context however, that variant will never appear. This is why: + + When constructing the MIR, all function call arguments are + copied into `Locals` of `LocalKind::Temp`. At least, all arguments + that are not unsized (Less than 0.1% are unsized. See #71170 + to learn more about those). + + This means that, conversely, all `Operands` found as function call + arguments are of the variant `Operand::Copy`. This allows us to + simplify our handling of `Operands` in this case. + */ + if let Some(l) = opr.place().and_then(|p| p.as_local()) { + if let Some(value) = self.get_const(l) { + if self.should_const_prop(value) { + // FIXME(felix91gr): this code only handles `Scalar` cases. + // For now, we're not handling `ScalarPair` cases because + // doing so here would require a lot of code duplication. + // We should hopefully generalize `Operand` handling into a fn, + // and use it to do const-prop here and everywhere else + // where it makes sense. + if let interpret::Operand::Immediate( + interpret::Immediate::Scalar( + interpret::ScalarMaybeUndef::Scalar(scalar), + ), + ) = *value + { + *opr = self.operand_from_scalar( + scalar, + value.layout.ty, + source_info.span, + ); + } + } + } + } + } + } + } } // We remove all Locals which are restricted in propagation to their containing blocks. - // We wouldn't need to clone, but the borrow checker can't see that we're not aliasing - // the locals_of_current_block field, so we need to clone it first. - // let ecx = &mut self.ecx; for local in self.locals_of_current_block.iter() { Self::remove_const(&mut self.ecx, local); } diff --git a/src/librustc_mir/transform/elaborate_drops.rs b/src/librustc_mir/transform/elaborate_drops.rs index a1becf062ee..e379e5ee656 100644 --- a/src/librustc_mir/transform/elaborate_drops.rs +++ b/src/librustc_mir/transform/elaborate_drops.rs @@ -1,10 +1,10 @@ use crate::dataflow; +use crate::dataflow::impls::{MaybeInitializedPlaces, MaybeUninitializedPlaces}; use crate::dataflow::move_paths::{LookupResult, MoveData, MovePathIndex}; use crate::dataflow::on_lookup_result_bits; use crate::dataflow::MoveDataParamEnv; use crate::dataflow::{on_all_children_bits, on_all_drop_children_bits}; use crate::dataflow::{Analysis, ResultsCursor}; -use crate::dataflow::{MaybeInitializedPlaces, MaybeUninitializedPlaces}; use crate::transform::{MirPass, MirSource}; use crate::util::elaborate_drops::{elaborate_drop, DropFlagState, Unwind}; use crate::util::elaborate_drops::{DropElaborator, DropFlagMode, DropStyle}; diff --git a/src/librustc_mir/transform/generator.rs b/src/librustc_mir/transform/generator.rs index 91f0297710e..d334006d7b5 100644 --- a/src/librustc_mir/transform/generator.rs +++ b/src/librustc_mir/transform/generator.rs @@ -49,10 +49,10 @@ //! For generators with state 1 (returned) and state 2 (poisoned) it does nothing. //! Otherwise it drops all the values in scope at the last suspension point. -use crate::dataflow::{self, Analysis}; -use crate::dataflow::{ +use crate::dataflow::impls::{ MaybeBorrowedLocals, MaybeLiveLocals, MaybeRequiresStorage, MaybeStorageLive, }; +use crate::dataflow::{self, Analysis}; use crate::transform::no_landing_pads::no_landing_pads; use crate::transform::simplify; use crate::transform::{MirPass, MirSource}; diff --git a/src/librustc_mir/transform/mod.rs b/src/librustc_mir/transform/mod.rs index 1d982d18eeb..02356a43699 100644 --- a/src/librustc_mir/transform/mod.rs +++ b/src/librustc_mir/transform/mod.rs @@ -182,7 +182,7 @@ pub fn run_passes( } fn mir_const_qualif(tcx: TyCtxt<'_>, def_id: DefId) -> ConstQualifs { - let const_kind = check_consts::ConstKind::for_item(tcx, def_id.expect_local()); + let const_kind = tcx.hir().body_const_context(def_id.expect_local()); // No need to const-check a non-const `fn`. if const_kind.is_none() { diff --git a/src/librustc_mir/transform/promote_consts.rs b/src/librustc_mir/transform/promote_consts.rs index ebb162eca46..6dade3c8dca 100644 --- a/src/librustc_mir/transform/promote_consts.rs +++ b/src/librustc_mir/transform/promote_consts.rs @@ -13,6 +13,7 @@ //! move analysis runs after promotion on broken MIR. use rustc_ast::ast::LitKind; +use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_middle::mir::traversal::ReversePostorder; use rustc_middle::mir::visit::{MutVisitor, MutatingUseContext, PlaceContext, Visitor}; @@ -30,7 +31,7 @@ use std::cell::Cell; use std::{cmp, iter, mem}; use crate::const_eval::{is_const_fn, is_unstable_const_fn}; -use crate::transform::check_consts::{is_lang_panic_fn, qualifs, ConstCx, ConstKind}; +use crate::transform::check_consts::{is_lang_panic_fn, qualifs, ConstCx}; use crate::transform::{MirPass, MirSource}; /// A `MirPass` for promotion. @@ -352,7 +353,9 @@ impl<'tcx> Validator<'_, 'tcx> { // In theory, any zero-sized value could be borrowed // mutably without consequences. However, only &mut [] // is allowed right now, and only in functions. - if self.const_kind == Some(ConstKind::StaticMut) { + if self.const_kind + == Some(hir::ConstContext::Static(hir::Mutability::Mut)) + { // Inside a `static mut`, &mut [...] is also allowed. match ty.kind { ty::Array(..) | ty::Slice(_) => {} @@ -517,7 +520,7 @@ impl<'tcx> Validator<'_, 'tcx> { if let Some(def_id) = c.check_static_ptr(self.tcx) { // Only allow statics (not consts) to refer to other statics. // FIXME(eddyb) does this matter at all for promotion? - let is_static = self.const_kind.map_or(false, |k| k.is_static()); + let is_static = matches!(self.const_kind, Some(hir::ConstContext::Static(_))); if !is_static { return Err(Unpromotable); } @@ -607,7 +610,7 @@ impl<'tcx> Validator<'_, 'tcx> { // In theory, any zero-sized value could be borrowed // mutably without consequences. However, only &mut [] // is allowed right now, and only in functions. - if self.const_kind == Some(ConstKind::StaticMut) { + if self.const_kind == Some(hir::ConstContext::Static(hir::Mutability::Mut)) { // Inside a `static mut`, &mut [...] is also allowed. match ty.kind { ty::Array(..) | ty::Slice(_) => {} diff --git a/src/librustc_mir/transform/rustc_peek.rs b/src/librustc_mir/transform/rustc_peek.rs index 43ddc0c914c..5eb374e7ee2 100644 --- a/src/librustc_mir/transform/rustc_peek.rs +++ b/src/librustc_mir/transform/rustc_peek.rs @@ -9,14 +9,14 @@ use rustc_index::bit_set::BitSet; use rustc_middle::mir::{self, Body, Local, Location}; use rustc_middle::ty::{self, Ty, TyCtxt}; +use crate::dataflow::impls::{ + DefinitelyInitializedPlaces, MaybeInitializedPlaces, MaybeLiveLocals, MaybeMutBorrowedLocals, + MaybeUninitializedPlaces, +}; use crate::dataflow::move_paths::{HasMoveData, MoveData}; use crate::dataflow::move_paths::{LookupResult, MovePathIndex}; -use crate::dataflow::MaybeMutBorrowedLocals; use crate::dataflow::MoveDataParamEnv; use crate::dataflow::{Analysis, Results, ResultsCursor}; -use crate::dataflow::{ - DefinitelyInitializedPlaces, MaybeInitializedPlaces, MaybeLiveLocals, MaybeUninitializedPlaces, -}; pub struct SanityCheck; diff --git a/src/librustc_mir/util/liveness.rs b/src/librustc_mir/util/liveness.rs deleted file mode 100644 index c261219cc73..00000000000 --- a/src/librustc_mir/util/liveness.rs +++ /dev/null @@ -1,326 +0,0 @@ -//! Liveness analysis which computes liveness of MIR local variables at the boundary of basic -//! blocks. -//! -//! This analysis considers references as being used only at the point of the -//! borrow. This means that this does not track uses because of references that -//! already exist: -//! -//! ```rust -//! fn foo() { -//! x = 0; -//! // `x` is live here ... -//! GLOBAL = &x: *const u32; -//! // ... but not here, even while it can be accessed through `GLOBAL`. -//! foo(); -//! x = 1; -//! // `x` is live again here, because it is assigned to `OTHER_GLOBAL`. -//! OTHER_GLOBAL = &x: *const u32; -//! // ... -//! } -//! ``` -//! -//! This means that users of this analysis still have to check whether -//! pre-existing references can be used to access the value (e.g., at movable -//! generator yield points, all pre-existing references are invalidated, so this -//! doesn't matter). - -use crate::transform::MirSource; -use crate::util::pretty::{dump_enabled, write_basic_block, write_mir_intro}; -use rustc_data_structures::work_queue::WorkQueue; -use rustc_index::bit_set::BitSet; -use rustc_index::vec::{Idx, IndexVec}; -use rustc_middle::mir::visit::{ - MutatingUseContext, NonMutatingUseContext, NonUseContext, PlaceContext, Visitor, -}; -use rustc_middle::mir::Local; -use rustc_middle::mir::*; -use rustc_middle::ty::{self, TyCtxt}; -use std::fs; -use std::io::{self, BufWriter, Write}; -use std::path::{Path, PathBuf}; - -pub type LiveVarSet = BitSet<Local>; - -/// This gives the result of the liveness analysis at the boundary of -/// basic blocks. -/// -/// The `V` type defines the set of variables that we computed -/// liveness for. This is often `Local`, in which case we computed -/// liveness for all variables -- but it can also be some other type, -/// which indicates a subset of the variables within the graph. -pub struct LivenessResult { - /// Live variables on exit to each basic block. This is equal to - /// the union of the `ins` for each successor. - pub outs: IndexVec<BasicBlock, LiveVarSet>, -} - -/// Computes which local variables are live within the given function -/// `mir`, including drops. -pub fn liveness_of_locals(body: &Body<'_>) -> LivenessResult { - let num_live_vars = body.local_decls.len(); - - let def_use: IndexVec<_, DefsUses> = - body.basic_blocks().iter().map(|b| block(b, num_live_vars)).collect(); - - let mut outs: IndexVec<_, LiveVarSet> = - body.basic_blocks().indices().map(|_| LiveVarSet::new_empty(num_live_vars)).collect(); - - let mut bits = LiveVarSet::new_empty(num_live_vars); - - // The dirty queue contains the set of basic blocks whose entry sets have changed since they - // were last processed. At the start of the analysis, we initialize the queue in post-order to - // make it more likely that the entry set for a given basic block will have the effects of all - // its successors in the CFG applied before it is processed. - // - // FIXME(ecstaticmorse): Reverse post-order on the reverse CFG may generate a better iteration - // order when cycles are present, but the overhead of computing the reverse CFG may outweigh - // any benefits. Benchmark this and find out. - let mut dirty_queue: WorkQueue<BasicBlock> = WorkQueue::with_none(body.basic_blocks().len()); - for (bb, _) in traversal::postorder(&body) { - dirty_queue.insert(bb); - } - - // Add blocks which are not reachable from START_BLOCK to the work queue. These blocks will - // be processed after the ones added above. - for bb in body.basic_blocks().indices() { - dirty_queue.insert(bb); - } - - let predecessors = body.predecessors(); - - while let Some(bb) = dirty_queue.pop() { - // bits = use ∪ (bits - def) - bits.overwrite(&outs[bb]); - def_use[bb].apply(&mut bits); - - // `bits` now contains the live variables on entry. Therefore, - // add `bits` to the `out` set for each predecessor; if those - // bits were not already present, then enqueue the predecessor - // as dirty. - // - // (note that `union` returns true if the `self` set changed) - for &pred_bb in &predecessors[bb] { - if outs[pred_bb].union(&bits) { - dirty_queue.insert(pred_bb); - } - } - } - - LivenessResult { outs } -} - -#[derive(Eq, PartialEq, Clone)] -pub enum DefUse { - Def, - Use, - Drop, -} - -pub fn categorize(context: PlaceContext) -> Option<DefUse> { - match context { - /////////////////////////////////////////////////////////////////////////// - // DEFS - - PlaceContext::MutatingUse(MutatingUseContext::Store) | - - // This is potentially both a def and a use... - PlaceContext::MutatingUse(MutatingUseContext::AsmOutput) | - - // We let Call define the result in both the success and - // unwind cases. This is not really correct, however it - // does not seem to be observable due to the way that we - // generate MIR. To do things properly, we would apply - // the def in call only to the input from the success - // path and not the unwind path. -nmatsakis - PlaceContext::MutatingUse(MutatingUseContext::Call) | - PlaceContext::MutatingUse(MutatingUseContext::Yield) | - - // Storage live and storage dead aren't proper defines, but we can ignore - // values that come before them. - PlaceContext::NonUse(NonUseContext::StorageLive) | - PlaceContext::NonUse(NonUseContext::StorageDead) => Some(DefUse::Def), - - /////////////////////////////////////////////////////////////////////////// - // REGULAR USES - // - // These are uses that occur *outside* of a drop. For the - // purposes of NLL, these are special in that **all** the - // lifetimes appearing in the variable must be live for each regular use. - - PlaceContext::NonMutatingUse(NonMutatingUseContext::Projection) | - PlaceContext::MutatingUse(MutatingUseContext::Projection) | - - // Borrows only consider their local used at the point of the borrow. - // This won't affect the results since we use this analysis for generators - // and we only care about the result at suspension points. Borrows cannot - // cross suspension points so this behavior is unproblematic. - PlaceContext::MutatingUse(MutatingUseContext::Borrow) | - PlaceContext::NonMutatingUse(NonMutatingUseContext::SharedBorrow) | - PlaceContext::NonMutatingUse(NonMutatingUseContext::ShallowBorrow) | - PlaceContext::NonMutatingUse(NonMutatingUseContext::UniqueBorrow) | - - PlaceContext::MutatingUse(MutatingUseContext::AddressOf) | - PlaceContext::NonMutatingUse(NonMutatingUseContext::AddressOf) | - PlaceContext::NonMutatingUse(NonMutatingUseContext::Inspect) | - PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy) | - PlaceContext::NonMutatingUse(NonMutatingUseContext::Move) | - PlaceContext::NonUse(NonUseContext::AscribeUserTy) | - PlaceContext::MutatingUse(MutatingUseContext::Retag) => - Some(DefUse::Use), - - /////////////////////////////////////////////////////////////////////////// - // DROP USES - // - // These are uses that occur in a DROP (a MIR drop, not a - // call to `std::mem::drop()`). For the purposes of NLL, - // uses in drop are special because `#[may_dangle]` - // attributes can affect whether lifetimes must be live. - - PlaceContext::MutatingUse(MutatingUseContext::Drop) => - Some(DefUse::Drop), - - // Debug info is neither def nor use. - PlaceContext::NonUse(NonUseContext::VarDebugInfo) => None, - } -} - -struct DefsUsesVisitor { - defs_uses: DefsUses, -} - -#[derive(Eq, PartialEq, Clone)] -struct DefsUses { - defs: LiveVarSet, - uses: LiveVarSet, -} - -impl DefsUses { - fn apply(&self, bits: &mut LiveVarSet) -> bool { - bits.subtract(&self.defs) | bits.union(&self.uses) - } - - fn add_def(&mut self, index: Local) { - // If it was used already in the block, remove that use - // now that we found a definition. - // - // Example: - // - // // Defs = {X}, Uses = {} - // X = 5 - // // Defs = {}, Uses = {X} - // use(X) - self.uses.remove(index); - self.defs.insert(index); - } - - fn add_use(&mut self, index: Local) { - // Inverse of above. - // - // Example: - // - // // Defs = {}, Uses = {X} - // use(X) - // // Defs = {X}, Uses = {} - // X = 5 - // // Defs = {}, Uses = {X} - // use(X) - self.defs.remove(index); - self.uses.insert(index); - } -} - -impl<'tcx> Visitor<'tcx> for DefsUsesVisitor { - fn visit_local(&mut self, &local: &Local, context: PlaceContext, _: Location) { - match categorize(context) { - Some(DefUse::Def) => self.defs_uses.add_def(local), - Some(DefUse::Use | DefUse::Drop) => self.defs_uses.add_use(local), - _ => (), - } - } -} - -fn block(b: &BasicBlockData<'_>, locals: usize) -> DefsUses { - let mut visitor = DefsUsesVisitor { - defs_uses: DefsUses { - defs: LiveVarSet::new_empty(locals), - uses: LiveVarSet::new_empty(locals), - }, - }; - - let dummy_location = Location { block: BasicBlock::new(0), statement_index: 0 }; - - // Visit the various parts of the basic block in reverse. If we go - // forward, the logic in `add_def` and `add_use` would be wrong. - visitor.visit_terminator(b.terminator(), dummy_location); - for statement in b.statements.iter().rev() { - visitor.visit_statement(statement, dummy_location); - } - - visitor.defs_uses -} - -pub fn dump_mir<'tcx>( - tcx: TyCtxt<'tcx>, - pass_name: &str, - source: MirSource<'tcx>, - body: &Body<'tcx>, - result: &LivenessResult, -) { - if !dump_enabled(tcx, pass_name, source.def_id()) { - return; - } - let node_path = ty::print::with_forced_impl_filename_line(|| { - // see notes on #41697 below - tcx.def_path_str(source.def_id()) - }); - dump_matched_mir_node(tcx, pass_name, &node_path, source, body, result); -} - -fn dump_matched_mir_node<'tcx>( - tcx: TyCtxt<'tcx>, - pass_name: &str, - node_path: &str, - source: MirSource<'tcx>, - body: &Body<'tcx>, - result: &LivenessResult, -) { - let mut file_path = PathBuf::new(); - file_path.push(Path::new(&tcx.sess.opts.debugging_opts.dump_mir_dir)); - let item_id = tcx.hir().as_local_hir_id(source.def_id().expect_local()); - let file_name = format!("rustc.node{}{}-liveness.mir", item_id, pass_name); - file_path.push(&file_name); - let _ = fs::File::create(&file_path).and_then(|file| { - let mut file = BufWriter::new(file); - writeln!(file, "// MIR local liveness analysis for `{}`", node_path)?; - writeln!(file, "// source = {:?}", source)?; - writeln!(file, "// pass_name = {}", pass_name)?; - writeln!(file)?; - write_mir_fn(tcx, source, body, &mut file, result)?; - Ok(()) - }); -} - -pub fn write_mir_fn<'tcx>( - tcx: TyCtxt<'tcx>, - src: MirSource<'tcx>, - body: &Body<'tcx>, - w: &mut dyn Write, - result: &LivenessResult, -) -> io::Result<()> { - write_mir_intro(tcx, src, body, w)?; - for block in body.basic_blocks().indices() { - let print = |w: &mut dyn Write, prefix, result: &IndexVec<BasicBlock, LiveVarSet>| { - let live: Vec<String> = - result[block].iter().map(|local| format!("{:?}", local)).collect(); - writeln!(w, "{} {{{}}}", prefix, live.join(", ")) - }; - write_basic_block(tcx, block, body, &mut |_, _| Ok(()), w)?; - print(w, " ", &result.outs)?; - if block.index() + 1 != body.basic_blocks().len() { - writeln!(w)?; - } - } - - writeln!(w, "}}")?; - Ok(()) -} diff --git a/src/librustc_mir/util/mod.rs b/src/librustc_mir/util/mod.rs index 3e501193e8d..8bbe207c077 100644 --- a/src/librustc_mir/util/mod.rs +++ b/src/librustc_mir/util/mod.rs @@ -8,7 +8,6 @@ pub mod storage; mod alignment; pub mod collect_writes; mod graphviz; -pub mod liveness; pub(crate) mod pretty; pub use self::aggregate::expand_aggregate; diff --git a/src/librustc_mir_build/build/expr/as_temp.rs b/src/librustc_mir_build/build/expr/as_temp.rs index 50bd5a73e25..d82abd87767 100644 --- a/src/librustc_mir_build/build/expr/as_temp.rs +++ b/src/librustc_mir_build/build/expr/as_temp.rs @@ -3,6 +3,7 @@ use crate::build::scope::DropKind; use crate::build::{BlockAnd, BlockAndExtension, Builder}; use crate::hair::*; +use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_hir as hir; use rustc_middle::middle::region; use rustc_middle::mir::*; @@ -21,7 +22,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { M: Mirror<'tcx, Output = Expr<'tcx>>, { let expr = self.hir.mirror(expr); - self.expr_as_temp(block, temp_lifetime, expr, mutability) + // + // this is the only place in mir building that we need to truly need to worry about + // infinite recursion. Everything else does recurse, too, but it always gets broken up + // at some point by inserting an intermediate temporary + ensure_sufficient_stack(|| self.expr_as_temp(block, temp_lifetime, expr, mutability)) } fn expr_as_temp( diff --git a/src/librustc_mir_build/hair/pattern/_match.rs b/src/librustc_mir_build/hair/pattern/_match.rs index de3ae2e961f..cdafb63f1eb 100644 --- a/src/librustc_mir_build/hair/pattern/_match.rs +++ b/src/librustc_mir_build/hair/pattern/_match.rs @@ -580,22 +580,11 @@ crate struct MatchCheckCtxt<'a, 'tcx> { /// outside it's module and should not be matchable with an empty match /// statement. crate module: DefId, - param_env: ty::ParamEnv<'tcx>, + crate param_env: ty::ParamEnv<'tcx>, crate pattern_arena: &'a TypedArena<Pat<'tcx>>, } impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> { - crate fn create_and_enter<R>( - tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, - module: DefId, - f: impl FnOnce(MatchCheckCtxt<'_, 'tcx>) -> R, - ) -> R { - let pattern_arena = TypedArena::default(); - - f(MatchCheckCtxt { tcx, param_env, module, pattern_arena: &pattern_arena }) - } - fn is_uninhabited(&self, ty: Ty<'tcx>) -> bool { if self.tcx.features().exhaustive_patterns { self.tcx.is_ty_uninhabited_from(self.module, ty, self.param_env) diff --git a/src/librustc_mir_build/hair/pattern/check_match.rs b/src/librustc_mir_build/hair/pattern/check_match.rs index c90634e511b..0f22288437c 100644 --- a/src/librustc_mir_build/hair/pattern/check_match.rs +++ b/src/librustc_mir_build/hair/pattern/check_match.rs @@ -1,9 +1,9 @@ use super::_match::Usefulness::*; use super::_match::WitnessPreference::*; use super::_match::{expand_pattern, is_useful, MatchCheckCtxt, Matrix, PatStack}; - use super::{PatCtxt, PatKind, PatternError}; +use arena::TypedArena; use rustc_ast::ast::Mutability; use rustc_errors::{error_code, struct_span_err, Applicability, DiagnosticBuilder}; use rustc_hir as hir; @@ -17,7 +17,6 @@ use rustc_session::lint::builtin::{IRREFUTABLE_LET_PATTERNS, UNREACHABLE_PATTERN use rustc_session::parse::feature_err; use rustc_session::Session; use rustc_span::{sym, Span}; - use std::slice; crate fn check_match(tcx: TyCtxt<'_>, def_id: DefId) { @@ -26,8 +25,12 @@ crate fn check_match(tcx: TyCtxt<'_>, def_id: DefId) { Some(id) => tcx.hir().body_owned_by(tcx.hir().as_local_hir_id(id)), }; - let mut visitor = - MatchVisitor { tcx, tables: tcx.body_tables(body_id), param_env: tcx.param_env(def_id) }; + let mut visitor = MatchVisitor { + tcx, + tables: tcx.body_tables(body_id), + param_env: tcx.param_env(def_id), + pattern_arena: TypedArena::default(), + }; visitor.visit_body(tcx.hir().body(body_id)); } @@ -39,6 +42,7 @@ struct MatchVisitor<'a, 'tcx> { tcx: TyCtxt<'tcx>, tables: &'a ty::TypeckTables<'tcx>, param_env: ty::ParamEnv<'tcx>, + pattern_arena: TypedArena<super::Pat<'tcx>>, } impl<'tcx> Visitor<'tcx> for MatchVisitor<'_, 'tcx> { @@ -143,9 +147,13 @@ impl<'tcx> MatchVisitor<'_, 'tcx> { (pattern, pattern_ty) } - fn check_in_cx(&self, hir_id: HirId, f: impl FnOnce(MatchCheckCtxt<'_, 'tcx>)) { - let module = self.tcx.parent_module(hir_id); - MatchCheckCtxt::create_and_enter(self.tcx, self.param_env, module.to_def_id(), |cx| f(cx)); + fn new_cx(&self, hir_id: HirId) -> MatchCheckCtxt<'_, 'tcx> { + MatchCheckCtxt { + tcx: self.tcx, + param_env: self.param_env, + module: self.tcx.parent_module(hir_id).to_def_id(), + pattern_arena: &self.pattern_arena, + } } fn check_match( @@ -159,91 +167,88 @@ impl<'tcx> MatchVisitor<'_, 'tcx> { self.check_patterns(arm.guard.is_some(), &arm.pat); } - self.check_in_cx(scrut.hir_id, |ref mut cx| { - let mut have_errors = false; + let mut cx = self.new_cx(scrut.hir_id); - let inlined_arms: Vec<_> = arms - .iter() - .map(|hir::Arm { pat, guard, .. }| { - (self.lower_pattern(cx, pat, &mut have_errors).0, pat.hir_id, guard.is_some()) - }) - .collect(); + let mut have_errors = false; - // Bail out early if inlining failed. - if have_errors { - return; - } + let inlined_arms: Vec<_> = arms + .iter() + .map(|hir::Arm { pat, guard, .. }| { + (self.lower_pattern(&mut cx, pat, &mut have_errors).0, pat.hir_id, guard.is_some()) + }) + .collect(); + + // Bail out early if inlining failed. + if have_errors { + return; + } - // Fourth, check for unreachable arms. - let matrix = check_arms(cx, &inlined_arms, source); + // Fourth, check for unreachable arms. + let matrix = check_arms(&mut cx, &inlined_arms, source); - // Fifth, check if the match is exhaustive. - let scrut_ty = self.tables.node_type(scrut.hir_id); - // Note: An empty match isn't the same as an empty matrix for diagnostics purposes, - // since an empty matrix can occur when there are arms, if those arms all have guards. - let is_empty_match = inlined_arms.is_empty(); - check_exhaustive(cx, scrut_ty, scrut.span, &matrix, scrut.hir_id, is_empty_match); - }) + // Fifth, check if the match is exhaustive. + let scrut_ty = self.tables.node_type(scrut.hir_id); + // Note: An empty match isn't the same as an empty matrix for diagnostics purposes, + // since an empty matrix can occur when there are arms, if those arms all have guards. + let is_empty_match = inlined_arms.is_empty(); + check_exhaustive(&mut cx, scrut_ty, scrut.span, &matrix, scrut.hir_id, is_empty_match); } fn check_irrefutable(&self, pat: &'tcx Pat<'tcx>, origin: &str, sp: Option<Span>) { - self.check_in_cx(pat.hir_id, |ref mut cx| { - let (pattern, pattern_ty) = self.lower_pattern(cx, pat, &mut false); - let pats: Matrix<'_, '_> = vec![PatStack::from_pattern(pattern)].into_iter().collect(); - - let witnesses = match check_not_useful(cx, pattern_ty, &pats, pat.hir_id) { - Ok(_) => return, - Err(err) => err, - }; - - let joined_patterns = joined_uncovered_patterns(&witnesses); - let mut err = struct_span_err!( - self.tcx.sess, - pat.span, - E0005, - "refutable pattern in {}: {} not covered", - origin, - joined_patterns - ); - let suggest_if_let = match &pat.kind { - hir::PatKind::Path(hir::QPath::Resolved(None, path)) - if path.segments.len() == 1 && path.segments[0].args.is_none() => - { - const_not_var(&mut err, cx.tcx, pat, path); - false - } - _ => { - err.span_label( - pat.span, - pattern_not_covered_label(&witnesses, &joined_patterns), - ); - true - } - }; + let mut cx = self.new_cx(pat.hir_id); - if let (Some(span), true) = (sp, suggest_if_let) { - err.note( - "`let` bindings require an \"irrefutable pattern\", like a `struct` or \ - an `enum` with only one variant", - ); - if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) { - err.span_suggestion( - span, - "you might want to use `if let` to ignore the variant that isn't matched", - format!("if {} {{ /* */ }}", &snippet[..snippet.len() - 1]), - Applicability::HasPlaceholders, - ); - } - err.note( - "for more information, visit \ - https://doc.rust-lang.org/book/ch18-02-refutability.html", + let (pattern, pattern_ty) = self.lower_pattern(&mut cx, pat, &mut false); + let pats: Matrix<'_, '_> = vec![PatStack::from_pattern(pattern)].into_iter().collect(); + + let witnesses = match check_not_useful(&mut cx, pattern_ty, &pats, pat.hir_id) { + Ok(_) => return, + Err(err) => err, + }; + + let joined_patterns = joined_uncovered_patterns(&witnesses); + let mut err = struct_span_err!( + self.tcx.sess, + pat.span, + E0005, + "refutable pattern in {}: {} not covered", + origin, + joined_patterns + ); + let suggest_if_let = match &pat.kind { + hir::PatKind::Path(hir::QPath::Resolved(None, path)) + if path.segments.len() == 1 && path.segments[0].args.is_none() => + { + const_not_var(&mut err, cx.tcx, pat, path); + false + } + _ => { + err.span_label(pat.span, pattern_not_covered_label(&witnesses, &joined_patterns)); + true + } + }; + + if let (Some(span), true) = (sp, suggest_if_let) { + err.note( + "`let` bindings require an \"irrefutable pattern\", like a `struct` or \ + an `enum` with only one variant", + ); + if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) { + err.span_suggestion( + span, + "you might want to use `if let` to ignore the variant that isn't matched", + format!("if {} {{ /* */ }}", &snippet[..snippet.len() - 1]), + Applicability::HasPlaceholders, ); } + err.note( + "for more information, visit \ + https://doc.rust-lang.org/book/ch18-02-refutability.html", + ); + } - adt_defined_here(cx, &mut err, pattern_ty, &witnesses); - err.note(&format!("the matched value is of type `{}`", pattern_ty)); - err.emit(); - }); + adt_defined_here(&mut cx, &mut err, pattern_ty, &witnesses); + err.note(&format!("the matched value is of type `{}`", pattern_ty)); + err.emit(); } } diff --git a/src/librustc_mir_build/hair/pattern/const_to_pat.rs b/src/librustc_mir_build/hair/pattern/const_to_pat.rs index ad87afc3e03..4cc6a27a6da 100644 --- a/src/librustc_mir_build/hair/pattern/const_to_pat.rs +++ b/src/librustc_mir_build/hair/pattern/const_to_pat.rs @@ -111,21 +111,22 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { } if let Some(non_sm_ty) = structural { - let adt_def = match non_sm_ty { - traits::NonStructuralMatchTy::Adt(adt_def) => adt_def, + let msg = match non_sm_ty { + traits::NonStructuralMatchTy::Adt(adt_def) => { + let path = self.tcx().def_path_str(adt_def.did); + format!( + "to use a constant of type `{}` in a pattern, \ + `{}` must be annotated with `#[derive(PartialEq, Eq)]`", + path, path, + ) + } + traits::NonStructuralMatchTy::Dynamic => { + format!("trait objects cannot be used in patterns") + } traits::NonStructuralMatchTy::Param => { bug!("use of constant whose type is a parameter inside a pattern") } }; - let path = self.tcx().def_path_str(adt_def.did); - - let make_msg = || -> String { - format!( - "to use a constant of type `{}` in a pattern, \ - `{}` must be annotated with `#[derive(PartialEq, Eq)]`", - path, path, - ) - }; // double-check there even *is* a semantic `PartialEq` to dispatch to. // @@ -155,13 +156,13 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { if !ty_is_partial_eq { // span_fatal avoids ICE from resolution of non-existent method (rare case). - self.tcx().sess.span_fatal(self.span, &make_msg()); + self.tcx().sess.span_fatal(self.span, &msg); } else if mir_structural_match_violation { self.tcx().struct_span_lint_hir( lint::builtin::INDIRECT_STRUCTURAL_MATCH, self.id, self.span, - |lint| lint.build(&make_msg()).emit(), + |lint| lint.build(&msg).emit(), ); } else { debug!( diff --git a/src/librustc_parse/parser/expr.rs b/src/librustc_parse/parser/expr.rs index 55c9f26999b..b3bb72554e9 100644 --- a/src/librustc_parse/parser/expr.rs +++ b/src/librustc_parse/parser/expr.rs @@ -13,7 +13,7 @@ use rustc_ast::util::classify; use rustc_ast::util::literal::LitError; use rustc_ast::util::parser::{prec_let_scrutinee_needs_par, AssocOp, Fixity}; use rustc_ast_pretty::pprust; -use rustc_errors::{Applicability, PResult}; +use rustc_errors::{Applicability, DiagnosticBuilder, PResult}; use rustc_span::source_map::{self, Span, Spanned}; use rustc_span::symbol::{kw, sym, Symbol}; use std::mem; @@ -1068,8 +1068,8 @@ impl<'a> Parser<'a> { } fn parse_path_start_expr(&mut self, attrs: AttrVec) -> PResult<'a, P<Expr>> { - let lo = self.token.span; let path = self.parse_path(PathStyle::Expr)?; + let lo = path.span; // `!`, as an operator, is prefix, so we know this isn't that. let (hi, kind) = if self.eat(&token::Not) { @@ -1081,7 +1081,7 @@ impl<'a> Parser<'a> { }; (self.prev_token.span, ExprKind::MacCall(mac)) } else if self.check(&token::OpenDelim(token::Brace)) { - if let Some(expr) = self.maybe_parse_struct_expr(lo, &path, &attrs) { + if let Some(expr) = self.maybe_parse_struct_expr(&path, &attrs) { return expr; } else { (path.span, ExprKind::Path(None, path)) @@ -1895,16 +1895,15 @@ impl<'a> Parser<'a> { fn maybe_parse_struct_expr( &mut self, - lo: Span, path: &ast::Path, attrs: &AttrVec, ) -> Option<PResult<'a, P<Expr>>> { let struct_allowed = !self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL); if struct_allowed || self.is_certainly_not_a_block() { // This is a struct literal, but we don't can't accept them here. - let expr = self.parse_struct_expr(lo, path.clone(), attrs.clone()); + let expr = self.parse_struct_expr(path.clone(), attrs.clone()); if let (Ok(expr), false) = (&expr, struct_allowed) { - self.error_struct_lit_not_allowed_here(lo, expr.span); + self.error_struct_lit_not_allowed_here(path.span, expr.span); } return Some(expr); } @@ -1923,17 +1922,23 @@ impl<'a> Parser<'a> { pub(super) fn parse_struct_expr( &mut self, - lo: Span, pth: ast::Path, mut attrs: AttrVec, ) -> PResult<'a, P<Expr>> { - let struct_sp = lo.to(self.prev_token.span); self.bump(); let mut fields = Vec::new(); let mut base = None; + let mut recover_async = false; attrs.extend(self.parse_inner_attributes()?); + let mut async_block_err = |e: &mut DiagnosticBuilder<'_>, span: Span| { + recover_async = true; + e.span_label(span, "`async` blocks are only allowed in the 2018 edition"); + e.help("set `edition = \"2018\"` in `Cargo.toml`"); + e.note("for more on editions, read https://doc.rust-lang.org/edition-guide"); + }; + while self.token != token::CloseDelim(token::Brace) { if self.eat(&token::DotDot) { let exp_span = self.prev_token.span; @@ -1952,7 +1957,11 @@ impl<'a> Parser<'a> { let parsed_field = match self.parse_field() { Ok(f) => Some(f), Err(mut e) => { - e.span_label(struct_sp, "while parsing this struct"); + if pth == kw::Async { + async_block_err(&mut e, pth.span); + } else { + e.span_label(pth.span, "while parsing this struct"); + } e.emit(); // If the next token is a comma, then try to parse @@ -1976,15 +1985,19 @@ impl<'a> Parser<'a> { } } Err(mut e) => { - e.span_label(struct_sp, "while parsing this struct"); - if let Some(f) = recovery_field { - fields.push(f); - e.span_suggestion( - self.prev_token.span.shrink_to_hi(), - "try adding a comma", - ",".into(), - Applicability::MachineApplicable, - ); + if pth == kw::Async { + async_block_err(&mut e, pth.span); + } else { + e.span_label(pth.span, "while parsing this struct"); + if let Some(f) = recovery_field { + fields.push(f); + e.span_suggestion( + self.prev_token.span.shrink_to_hi(), + "try adding a comma", + ",".into(), + Applicability::MachineApplicable, + ); + } } e.emit(); self.recover_stmt_(SemiColonMode::Comma, BlockMode::Ignore); @@ -1993,9 +2006,10 @@ impl<'a> Parser<'a> { } } - let span = lo.to(self.token.span); + let span = pth.span.to(self.token.span); self.expect(&token::CloseDelim(token::Brace))?; - Ok(self.mk_expr(span, ExprKind::Struct(pth, fields, base), attrs)) + let expr = if recover_async { ExprKind::Err } else { ExprKind::Struct(pth, fields, base) }; + Ok(self.mk_expr(span, expr, attrs)) } /// Use in case of error after field-looking code: `S { foo: () with a }`. diff --git a/src/librustc_parse/parser/item.rs b/src/librustc_parse/parser/item.rs index e9f5f2c0dea..7fb814973e2 100644 --- a/src/librustc_parse/parser/item.rs +++ b/src/librustc_parse/parser/item.rs @@ -1550,7 +1550,7 @@ impl<'a> Parser<'a> { if span.rust_2015() { let diag = self.diagnostic(); struct_span_err!(diag, span, E0670, "`async fn` is not permitted in the 2015 edition") - .note("to use `async fn`, switch to Rust 2018") + .span_label(span, "to use `async fn`, switch to Rust 2018") .help("set `edition = \"2018\"` in `Cargo.toml`") .note("for more on editions, read https://doc.rust-lang.org/edition-guide") .emit(); diff --git a/src/librustc_parse/parser/stmt.rs b/src/librustc_parse/parser/stmt.rs index e5d0ab247aa..849193151c3 100644 --- a/src/librustc_parse/parser/stmt.rs +++ b/src/librustc_parse/parser/stmt.rs @@ -79,7 +79,7 @@ impl<'a> Parser<'a> { } let expr = if self.check(&token::OpenDelim(token::Brace)) { - self.parse_struct_expr(lo, path, AttrVec::new())? + self.parse_struct_expr(path, AttrVec::new())? } else { let hi = self.prev_token.span; self.mk_expr(lo.to(hi), ExprKind::Path(None, path), AttrVec::new()) diff --git a/src/librustc_passes/check_const.rs b/src/librustc_passes/check_const.rs index c42f2fc264a..94f9c619a3a 100644 --- a/src/librustc_passes/check_const.rs +++ b/src/librustc_passes/check_const.rs @@ -7,7 +7,6 @@ //! errors. We still look for those primitives in the MIR const-checker to ensure nothing slips //! through, but errors for structured control flow in a `const` should be emitted here. -use rustc_ast::ast::Mutability; use rustc_errors::struct_span_err; use rustc_hir as hir; use rustc_hir::def_id::DefId; @@ -19,8 +18,6 @@ use rustc_session::config::nightly_options; use rustc_session::parse::feature_err; use rustc_span::{sym, Span, Symbol}; -use std::fmt; - /// An expression that is not *always* legal in a const context. #[derive(Clone, Copy)] enum NonConstExpr { @@ -65,46 +62,6 @@ impl NonConstExpr { } } -#[derive(Copy, Clone)] -enum ConstKind { - Static, - StaticMut, - ConstFn, - Const, - AnonConst, -} - -impl ConstKind { - fn for_body(body: &hir::Body<'_>, tcx: TyCtxt<'_>) -> Option<Self> { - let owner = tcx.hir().body_owner(body.id()); - let const_kind = match tcx.hir().body_owner_kind(owner) { - hir::BodyOwnerKind::Const => Self::Const, - hir::BodyOwnerKind::Static(Mutability::Mut) => Self::StaticMut, - hir::BodyOwnerKind::Static(Mutability::Not) => Self::Static, - - hir::BodyOwnerKind::Fn if tcx.is_const_fn_raw(tcx.hir().local_def_id(owner)) => { - Self::ConstFn - } - hir::BodyOwnerKind::Fn | hir::BodyOwnerKind::Closure => return None, - }; - - Some(const_kind) - } -} - -impl fmt::Display for ConstKind { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let s = match self { - Self::Static => "static", - Self::StaticMut => "static mut", - Self::Const | Self::AnonConst => "const", - Self::ConstFn => "const fn", - }; - - write!(f, "{}", s) - } -} - fn check_mod_const_bodies(tcx: TyCtxt<'_>, module_def_id: DefId) { let mut vis = CheckConstVisitor::new(tcx); tcx.hir().visit_item_likes_in_module(module_def_id, &mut vis.as_deep_visitor()); @@ -117,7 +74,7 @@ pub(crate) fn provide(providers: &mut Providers<'_>) { #[derive(Copy, Clone)] struct CheckConstVisitor<'tcx> { tcx: TyCtxt<'tcx>, - const_kind: Option<ConstKind>, + const_kind: Option<hir::ConstContext>, } impl<'tcx> CheckConstVisitor<'tcx> { @@ -147,7 +104,8 @@ impl<'tcx> CheckConstVisitor<'tcx> { let const_kind = self .const_kind .expect("`const_check_violated` may only be called inside a const context"); - let msg = format!("{} is not allowed in a `{}`", expr.name(), const_kind); + + let msg = format!("{} is not allowed in a `{}`", expr.name(), const_kind.keyword_name()); let required_gates = required_gates.unwrap_or(&[]); let missing_gates: Vec<_> = @@ -191,7 +149,7 @@ impl<'tcx> CheckConstVisitor<'tcx> { } /// Saves the parent `const_kind` before calling `f` and restores it afterwards. - fn recurse_into(&mut self, kind: Option<ConstKind>, f: impl FnOnce(&mut Self)) { + fn recurse_into(&mut self, kind: Option<hir::ConstContext>, f: impl FnOnce(&mut Self)) { let parent_kind = self.const_kind; self.const_kind = kind; f(self); @@ -207,12 +165,13 @@ impl<'tcx> Visitor<'tcx> for CheckConstVisitor<'tcx> { } fn visit_anon_const(&mut self, anon: &'tcx hir::AnonConst) { - let kind = Some(ConstKind::AnonConst); + let kind = Some(hir::ConstContext::Const); self.recurse_into(kind, |this| intravisit::walk_anon_const(this, anon)); } fn visit_body(&mut self, body: &'tcx hir::Body<'tcx>) { - let kind = ConstKind::for_body(body, self.tcx); + let owner = self.tcx.hir().body_owner_def_id(body.id()); + let kind = self.tcx.hir().body_const_context(owner); self.recurse_into(kind, |this| intravisit::walk_body(this, body)); } diff --git a/src/librustc_query_system/dep_graph/graph.rs b/src/librustc_query_system/dep_graph/graph.rs index ba3ce16ae36..5f14a09b24d 100644 --- a/src/librustc_query_system/dep_graph/graph.rs +++ b/src/librustc_query_system/dep_graph/graph.rs @@ -861,13 +861,7 @@ impl<K: DepKind> DepGraph<K> { pub struct WorkProduct { pub cgu_name: String, /// Saved files associated with this CGU. - pub saved_files: Vec<(WorkProductFileKind, String)>, -} - -#[derive(Clone, Copy, Debug, RustcEncodable, RustcDecodable, PartialEq)] -pub enum WorkProductFileKind { - Object, - Bytecode, + pub saved_files: Vec<String>, } #[derive(Clone)] diff --git a/src/librustc_query_system/dep_graph/mod.rs b/src/librustc_query_system/dep_graph/mod.rs index f571e902211..f85462eb78b 100644 --- a/src/librustc_query_system/dep_graph/mod.rs +++ b/src/librustc_query_system/dep_graph/mod.rs @@ -6,7 +6,6 @@ mod query; mod serialized; pub use dep_node::{DepNode, DepNodeParams, WorkProductId}; -pub use graph::WorkProductFileKind; pub use graph::{hash_result, DepGraph, DepNodeColor, DepNodeIndex, TaskDeps, WorkProduct}; pub use prev::PreviousDepGraph; pub use query::DepGraphQuery; diff --git a/src/librustc_resolve/diagnostics.rs b/src/librustc_resolve/diagnostics.rs index 450293b991b..8e82480c630 100644 --- a/src/librustc_resolve/diagnostics.rs +++ b/src/librustc_resolve/diagnostics.rs @@ -47,6 +47,7 @@ impl TypoSuggestion { /// A free importable items suggested in case of resolution failure. crate struct ImportSuggestion { pub did: Option<DefId>, + pub descr: &'static str, pub path: Path, } @@ -652,7 +653,7 @@ impl<'a> Resolver<'a> { Res::Def(DefKind::Ctor(..), did) => this.parent(did), _ => res.opt_def_id(), }; - candidates.push(ImportSuggestion { did, path }); + candidates.push(ImportSuggestion { did, descr: res.descr(), path }); } } } @@ -1445,7 +1446,7 @@ fn find_span_immediately_after_crate_name( crate fn show_candidates( err: &mut DiagnosticBuilder<'_>, // This is `None` if all placement locations are inside expansions - span: Option<Span>, + use_placement_span: Option<Span>, candidates: &[ImportSuggestion], better: bool, found_use: bool, @@ -1453,6 +1454,7 @@ crate fn show_candidates( if candidates.is_empty() { return; } + // we want consistent results across executions, but candidates are produced // by iterating through a hash map, so make sure they are ordered: let mut path_strings: Vec<_> = @@ -1460,14 +1462,15 @@ crate fn show_candidates( path_strings.sort(); path_strings.dedup(); - let better = if better { "better " } else { "" }; - let msg_diff = match path_strings.len() { - 1 => " is found in another module, you can import it", - _ => "s are found in other modules, you can import them", + let (determiner, kind) = if candidates.len() == 1 { + ("this", candidates[0].descr) + } else { + ("one of these", "items") }; - let msg = format!("possible {}candidate{} into scope", better, msg_diff); + let instead = if better { " instead" } else { "" }; + let msg = format!("consider importing {} {}{}", determiner, kind, instead); - if let Some(span) = span { + if let Some(span) = use_placement_span { for candidate in &mut path_strings { // produce an additional newline to separate the new use statement // from the directly following item. diff --git a/src/librustc_resolve/late.rs b/src/librustc_resolve/late.rs index f369e827a40..6214186a901 100644 --- a/src/librustc_resolve/late.rs +++ b/src/librustc_resolve/late.rs @@ -1522,11 +1522,20 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { ident: Ident, has_sub: bool, ) -> Option<Res> { + // An immutable (no `mut`) by-value (no `ref`) binding pattern without + // a sub pattern (no `@ $pat`) is syntactically ambiguous as it could + // also be interpreted as a path to e.g. a constant, variant, etc. + let is_syntactic_ambiguity = !has_sub && bm == BindingMode::ByValue(Mutability::Not); + let ls_binding = self.resolve_ident_in_lexical_scope(ident, ValueNS, None, pat.span)?; let (res, binding) = match ls_binding { - LexicalScopeBinding::Item(binding) if binding.is_ambiguity() => { + LexicalScopeBinding::Item(binding) + if is_syntactic_ambiguity && binding.is_ambiguity() => + { // For ambiguous bindings we don't know all their definitions and cannot check // whether they can be shadowed by fresh bindings or not, so force an error. + // issues/33118#issuecomment-233962221 (see below) still applies here, + // but we have to ignore it for backward compatibility. self.r.record_use(ident, ValueNS, binding, false); return None; } @@ -1534,11 +1543,6 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { LexicalScopeBinding::Res(res) => (res, None), }; - // An immutable (no `mut`) by-value (no `ref`) binding pattern without - // a sub pattern (no `@ $pat`) is syntactically ambiguous as it could - // also be interpreted as a path to e.g. a constant, variant, etc. - let is_syntactic_ambiguity = !has_sub && bm == BindingMode::ByValue(Mutability::Not); - match res { Res::SelfCtor(_) // See #70549. | Res::Def( diff --git a/src/librustc_resolve/late/diagnostics.rs b/src/librustc_resolve/late/diagnostics.rs index f6213189d94..6041a56d366 100644 --- a/src/librustc_resolve/late/diagnostics.rs +++ b/src/librustc_resolve/late/diagnostics.rs @@ -151,7 +151,11 @@ impl<'a> LateResolutionVisitor<'a, '_, '_> { }; ( format!("cannot find {} `{}` in {}{}", expected, item_str, mod_prefix, mod_str), - format!("not found in {}", mod_str), + if path_str == "async" && expected.starts_with("struct") { + "`async` blocks are only allowed in the 2018 edition".to_string() + } else { + format!("not found in {}", mod_str) + }, item_span, false, ) @@ -873,7 +877,10 @@ impl<'a> LateResolutionVisitor<'a, '_, '_> { let module_def_id = module.def_id().unwrap(); if module_def_id == def_id { let path = Path { span: name_binding.span, segments: path_segments }; - result = Some((module, ImportSuggestion { did: Some(def_id), path })); + result = Some(( + module, + ImportSuggestion { did: Some(def_id), descr: "module", path }, + )); } else { // add the module to the lookup if seen_modules.insert(module_def_id) { diff --git a/src/librustc_session/options.rs b/src/librustc_session/options.rs index b03fc00d93d..1d314238b86 100644 --- a/src/librustc_session/options.rs +++ b/src/librustc_session/options.rs @@ -668,6 +668,8 @@ options! {CodegenOptions, CodegenSetter, basic_codegen_options, "extra data to put in each output filename"), force_frame_pointers: Option<bool> = (None, parse_opt_bool, [TRACKED], "force use of the frame pointers"), + force_unwind_tables: Option<bool> = (None, parse_opt_bool, [TRACKED], + "force use of unwind tables"), incremental: Option<String> = (None, parse_opt_string, [UNTRACKED], "enable incremental compilation"), inline_threshold: Option<usize> = (None, parse_opt_uint, [TRACKED], @@ -936,9 +938,9 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "enable origins tracking in MemorySanitizer"), sanitizer_recover: Vec<Sanitizer> = (vec![], parse_sanitizer_list, [TRACKED], "enable recovery for selected sanitizers"), - saturating_float_casts: bool = (false, parse_bool, [TRACKED], + saturating_float_casts: Option<bool> = (None, parse_opt_bool, [TRACKED], "make float->int casts UB-free: numbers outside the integer type's range are clipped to \ - the max/min integer respectively, and NaN is mapped to 0 (default: no)"), + the max/min integer respectively, and NaN is mapped to 0 (default: yes)"), save_analysis: bool = (false, parse_bool, [UNTRACKED], "write syntax and type analysis (in JSON format) information, in \ addition to normal output (default: no)"), diff --git a/src/librustc_session/session.rs b/src/librustc_session/session.rs index 93a1315c6b5..48e36fdb3d4 100644 --- a/src/librustc_session/session.rs +++ b/src/librustc_session/session.rs @@ -646,6 +646,33 @@ impl Session { } } + pub fn must_emit_unwind_tables(&self) -> bool { + // This is used to control the emission of the `uwtable` attribute on + // LLVM functions. + // + // At the very least, unwind tables are needed when compiling with + // `-C panic=unwind`. + // + // On some targets (including windows), however, exceptions include + // other events such as illegal instructions, segfaults, etc. This means + // that on Windows we end up still needing unwind tables even if the `-C + // panic=abort` flag is passed. + // + // You can also find more info on why Windows needs unwind tables in: + // https://bugzilla.mozilla.org/show_bug.cgi?id=1302078 + // + // If a target requires unwind tables, then they must be emitted. + // Otherwise, we can defer to the `-C force-unwind-tables=<yes/no>` + // value, if it is provided, or disable them, if not. + if self.panic_strategy() == PanicStrategy::Unwind { + true + } else if self.target.target.options.requires_uwtable { + true + } else { + self.opts.cg.force_unwind_tables.unwrap_or(false) + } + } + /// Returns the symbol name for the registrar function, /// given the crate `Svh` and the function `DefIndex`. pub fn generate_plugin_registrar_symbol(&self, disambiguator: CrateDisambiguator) -> String { @@ -1224,6 +1251,23 @@ fn validate_commandline_args_with_session_available(sess: &Session) { } } + // Unwind tables cannot be disabled if the target requires them. + if let Some(include_uwtables) = sess.opts.cg.force_unwind_tables { + if sess.panic_strategy() == PanicStrategy::Unwind && !include_uwtables { + sess.err( + "panic=unwind requires unwind tables, they cannot be disabled \ + with `-C force-unwind-tables=no`.", + ); + } + + if sess.target.target.options.requires_uwtable && !include_uwtables { + sess.err( + "target requires unwind tables, they cannot be disabled with \ + `-C force-unwind-tables=no`.", + ); + } + } + // PGO does not work reliably with panic=unwind on Windows. Let's make it // an error to combine the two for now. It always runs into an assertions // if LLVM is built with assertions, but without assertions it sometimes diff --git a/src/librustc_span/lib.rs b/src/librustc_span/lib.rs index 060ad604369..dd7ba5cb6fc 100644 --- a/src/librustc_span/lib.rs +++ b/src/librustc_span/lib.rs @@ -14,6 +14,10 @@ #![feature(optin_builtin_traits)] #![feature(specialization)] +// FIXME(#56935): Work around ICEs during cross-compilation. +#[allow(unused)] +extern crate rustc_macros; + use rustc_data_structures::AtomicRef; use rustc_macros::HashStable_Generic; use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; diff --git a/src/librustc_target/lib.rs b/src/librustc_target/lib.rs index b2965fb8806..a0229a5daf0 100644 --- a/src/librustc_target/lib.rs +++ b/src/librustc_target/lib.rs @@ -17,6 +17,10 @@ #![feature(associated_type_bounds)] #![feature(exhaustive_patterns)] +// FIXME(#56935): Work around ICEs during cross-compilation. +#[allow(unused)] +extern crate rustc_macros; + #[macro_use] extern crate log; diff --git a/src/librustc_target/spec/aarch64_apple_ios.rs b/src/librustc_target/spec/aarch64_apple_ios.rs index e896b46da9a..eac2c3e6aa4 100644 --- a/src/librustc_target/spec/aarch64_apple_ios.rs +++ b/src/librustc_target/spec/aarch64_apple_ios.rs @@ -19,6 +19,18 @@ pub fn target() -> TargetResult { eliminate_frame_pointer: false, max_atomic_width: Some(128), abi_blacklist: super::arm_base::abi_blacklist(), + forces_embed_bitcode: true, + // Taken from a clang build on Xcode 11.4.1. + // These arguments are not actually invoked - they just have + // to look right to pass App Store validation. + bitcode_llvm_cmdline: "-triple\0\ + arm64-apple-ios11.0.0\0\ + -emit-obj\0\ + -disable-llvm-passes\0\ + -target-abi\0\ + darwinpcs\0\ + -Os\0" + .to_string(), ..base }, }) diff --git a/src/librustc_target/spec/aarch64_apple_tvos.rs b/src/librustc_target/spec/aarch64_apple_tvos.rs index 794bc7900e7..f1cd14ffd11 100644 --- a/src/librustc_target/spec/aarch64_apple_tvos.rs +++ b/src/librustc_target/spec/aarch64_apple_tvos.rs @@ -19,6 +19,7 @@ pub fn target() -> TargetResult { eliminate_frame_pointer: false, max_atomic_width: Some(128), abi_blacklist: super::arm_base::abi_blacklist(), + forces_embed_bitcode: true, ..base }, }) diff --git a/src/librustc_target/spec/mod.rs b/src/librustc_target/spec/mod.rs index e853c07632f..51dce9e144c 100644 --- a/src/librustc_target/spec/mod.rs +++ b/src/librustc_target/spec/mod.rs @@ -783,6 +783,10 @@ pub struct TargetOptions { // If we give emcc .o files that are actually .bc files it // will 'just work'. pub obj_is_bitcode: bool, + /// Whether the target requires that emitted object code includes bitcode. + pub forces_embed_bitcode: bool, + /// Content of the LLVM cmdline section associated with embedded bitcode. + pub bitcode_llvm_cmdline: String, /// Don't use this field; instead use the `.min_atomic_width()` method. pub min_atomic_width: Option<u64>, @@ -939,6 +943,8 @@ impl Default for TargetOptions { allow_asm: true, has_elf_tls: false, obj_is_bitcode: false, + forces_embed_bitcode: false, + bitcode_llvm_cmdline: String::new(), min_atomic_width: None, max_atomic_width: None, atomic_cas: true, @@ -1278,6 +1284,8 @@ impl Target { key!(main_needs_argc_argv, bool); key!(has_elf_tls, bool); key!(obj_is_bitcode, bool); + key!(forces_embed_bitcode, bool); + key!(bitcode_llvm_cmdline); key!(max_atomic_width, Option<u64>); key!(min_atomic_width, Option<u64>); key!(atomic_cas, bool); @@ -1505,6 +1513,8 @@ impl ToJson for Target { target_option_val!(main_needs_argc_argv); target_option_val!(has_elf_tls); target_option_val!(obj_is_bitcode); + target_option_val!(forces_embed_bitcode); + target_option_val!(bitcode_llvm_cmdline); target_option_val!(min_atomic_width); target_option_val!(max_atomic_width); target_option_val!(atomic_cas); diff --git a/src/librustc_trait_selection/traits/auto_trait.rs b/src/librustc_trait_selection/traits/auto_trait.rs index 6326a87c5ed..e19ddcd9e5e 100644 --- a/src/librustc_trait_selection/traits/auto_trait.rs +++ b/src/librustc_trait_selection/traits/auto_trait.rs @@ -195,7 +195,7 @@ impl<'tcx> AutoTraitFinder<'tcx> { let body_id_map: FxHashMap<_, _> = infcx .inner .borrow() - .region_obligations + .region_obligations() .iter() .map(|&(id, _)| (id, vec![])) .collect(); diff --git a/src/librustc_trait_selection/traits/error_reporting/mod.rs b/src/librustc_trait_selection/traits/error_reporting/mod.rs index fa2af24c945..6c51afa9660 100644 --- a/src/librustc_trait_selection/traits/error_reporting/mod.rs +++ b/src/librustc_trait_selection/traits/error_reporting/mod.rs @@ -15,17 +15,16 @@ use rustc_data_structures::fx::FxHashMap; use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder, ErrorReported}; use rustc_hir as hir; use rustc_hir::def_id::{DefId, LOCAL_CRATE}; -use rustc_hir::{Node, QPath, TyKind, WhereBoundPredicate, WherePredicate}; +use rustc_hir::Node; use rustc_middle::mir::interpret::ErrorHandled; use rustc_middle::ty::error::ExpectedFound; -use rustc_middle::ty::fast_reject; use rustc_middle::ty::fold::TypeFolder; -use rustc_middle::ty::SubtypePredicate; use rustc_middle::ty::{ - self, AdtKind, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness, + self, fast_reject, AdtKind, SubtypePredicate, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, + TypeFoldable, WithConstness, }; use rustc_session::DiagnosticMessageId; -use rustc_span::{BytePos, ExpnKind, Span, DUMMY_SP}; +use rustc_span::{ExpnKind, Span, DUMMY_SP}; use std::fmt; use crate::traits::query::evaluate_obligation::InferCtxtExt as _; @@ -1492,12 +1491,26 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> { ty::Predicate::Projection(ref data) => { let trait_ref = data.to_poly_trait_ref(self.tcx); let self_ty = trait_ref.self_ty(); + let ty = data.skip_binder().ty; if predicate.references_error() { return; } - let mut err = self.need_type_info_err(body_id, span, self_ty, ErrorCode::E0284); - err.note(&format!("cannot satisfy `{}`", predicate)); - err + if self_ty.needs_infer() && ty.needs_infer() { + // We do this for the `foo.collect()?` case to produce a suggestion. + let mut err = self.need_type_info_err(body_id, span, self_ty, ErrorCode::E0284); + err.note(&format!("cannot satisfy `{}`", predicate)); + err + } else { + let mut err = struct_span_err!( + self.tcx.sess, + span, + E0284, + "type annotations needed: cannot satisfy `{}`", + predicate, + ); + err.span_label(span, &format!("cannot satisfy `{}`", predicate)); + err + } } _ => { @@ -1700,180 +1713,3 @@ impl ArgKind { } } } - -/// Suggest restricting a type param with a new bound. -pub fn suggest_constraining_type_param( - tcx: TyCtxt<'_>, - generics: &hir::Generics<'_>, - err: &mut DiagnosticBuilder<'_>, - param_name: &str, - constraint: &str, - def_id: Option<DefId>, -) -> bool { - let param = generics.params.iter().find(|p| p.name.ident().as_str() == param_name); - - let param = if let Some(param) = param { - param - } else { - return false; - }; - - const MSG_RESTRICT_BOUND_FURTHER: &str = "consider further restricting this bound"; - let msg_restrict_type = format!("consider restricting type parameter `{}`", param_name); - let msg_restrict_type_further = - format!("consider further restricting type parameter `{}`", param_name); - - if def_id == tcx.lang_items().sized_trait() { - // Type parameters are already `Sized` by default. - err.span_label(param.span, &format!("this type parameter needs to be `{}`", constraint)); - return true; - } - let mut suggest_restrict = |span| { - err.span_suggestion_verbose( - span, - MSG_RESTRICT_BOUND_FURTHER, - format!(" + {}", constraint), - Applicability::MachineApplicable, - ); - }; - - if param_name.starts_with("impl ") { - // If there's an `impl Trait` used in argument position, suggest - // restricting it: - // - // fn foo(t: impl Foo) { ... } - // -------- - // | - // help: consider further restricting this bound with `+ Bar` - // - // Suggestion for tools in this case is: - // - // fn foo(t: impl Foo) { ... } - // -------- - // | - // replace with: `impl Foo + Bar` - - suggest_restrict(param.span.shrink_to_hi()); - return true; - } - - if generics.where_clause.predicates.is_empty() - // Given `trait Base<T = String>: Super<T>` where `T: Copy`, suggest restricting in the - // `where` clause instead of `trait Base<T: Copy = String>: Super<T>`. - && !matches!(param.kind, hir::GenericParamKind::Type { default: Some(_), .. }) - { - if let Some(bounds_span) = param.bounds_span() { - // If user has provided some bounds, suggest restricting them: - // - // fn foo<T: Foo>(t: T) { ... } - // --- - // | - // help: consider further restricting this bound with `+ Bar` - // - // Suggestion for tools in this case is: - // - // fn foo<T: Foo>(t: T) { ... } - // -- - // | - // replace with: `T: Bar +` - suggest_restrict(bounds_span.shrink_to_hi()); - } else { - // If user hasn't provided any bounds, suggest adding a new one: - // - // fn foo<T>(t: T) { ... } - // - help: consider restricting this type parameter with `T: Foo` - err.span_suggestion_verbose( - param.span.shrink_to_hi(), - &msg_restrict_type, - format!(": {}", constraint), - Applicability::MachineApplicable, - ); - } - - true - } else { - // This part is a bit tricky, because using the `where` clause user can - // provide zero, one or many bounds for the same type parameter, so we - // have following cases to consider: - // - // 1) When the type parameter has been provided zero bounds - // - // Message: - // fn foo<X, Y>(x: X, y: Y) where Y: Foo { ... } - // - help: consider restricting this type parameter with `where X: Bar` - // - // Suggestion: - // fn foo<X, Y>(x: X, y: Y) where Y: Foo { ... } - // - insert: `, X: Bar` - // - // - // 2) When the type parameter has been provided one bound - // - // Message: - // fn foo<T>(t: T) where T: Foo { ... } - // ^^^^^^ - // | - // help: consider further restricting this bound with `+ Bar` - // - // Suggestion: - // fn foo<T>(t: T) where T: Foo { ... } - // ^^ - // | - // replace with: `T: Bar +` - // - // - // 3) When the type parameter has been provided many bounds - // - // Message: - // fn foo<T>(t: T) where T: Foo, T: Bar {... } - // - help: consider further restricting this type parameter with `where T: Zar` - // - // Suggestion: - // fn foo<T>(t: T) where T: Foo, T: Bar {... } - // - insert: `, T: Zar` - - let mut param_spans = Vec::new(); - - for predicate in generics.where_clause.predicates { - if let WherePredicate::BoundPredicate(WhereBoundPredicate { - span, bounded_ty, .. - }) = predicate - { - if let TyKind::Path(QPath::Resolved(_, path)) = &bounded_ty.kind { - if let Some(segment) = path.segments.first() { - if segment.ident.to_string() == param_name { - param_spans.push(span); - } - } - } - } - } - - let where_clause_span = generics.where_clause.span_for_predicates_or_empty_place(); - // Account for `fn foo<T>(t: T) where T: Foo,` so we don't suggest two trailing commas. - let mut trailing_comma = false; - if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(where_clause_span) { - trailing_comma = snippet.ends_with(','); - } - let where_clause_span = if trailing_comma { - let hi = where_clause_span.hi(); - Span::new(hi - BytePos(1), hi, where_clause_span.ctxt()) - } else { - where_clause_span.shrink_to_hi() - }; - - match ¶m_spans[..] { - &[¶m_span] => suggest_restrict(param_span.shrink_to_hi()), - _ => { - err.span_suggestion_verbose( - where_clause_span, - &msg_restrict_type_further, - format!(", {}: {}", param_name, constraint), - Applicability::MachineApplicable, - ); - } - } - - true - } -} diff --git a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs index 5ec2d68ab2a..74dd47a91c2 100644 --- a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs +++ b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs @@ -3,7 +3,6 @@ use super::{ }; use crate::infer::InferCtxt; -use crate::traits::error_reporting::suggest_constraining_type_param; use rustc_errors::{error_code, struct_span_err, Applicability, DiagnosticBuilder, Style}; use rustc_hir as hir; @@ -13,7 +12,8 @@ use rustc_hir::intravisit::Visitor; use rustc_hir::{AsyncGeneratorKind, GeneratorKind, Node}; use rustc_middle::ty::TypeckTables; use rustc_middle::ty::{ - self, AdtKind, DefIdTree, Infer, InferTy, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness, + self, suggest_constraining_type_param, AdtKind, DefIdTree, Infer, InferTy, ToPredicate, Ty, + TyCtxt, TypeFoldable, WithConstness, }; use rustc_span::symbol::{kw, sym, Symbol}; use rustc_span::{MultiSpan, Span, DUMMY_SP}; @@ -1738,6 +1738,13 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { predicate )); } + ObligationCauseCode::CompareImplConstObligation => { + err.note(&format!( + "the requirement `{}` appears on the associated impl constant \ + but not on the corresponding associated trait constant", + predicate + )); + } ObligationCauseCode::ReturnType | ObligationCauseCode::ReturnValue(_) | ObligationCauseCode::BlockTailExpression(_) => (), diff --git a/src/librustc_trait_selection/traits/fulfill.rs b/src/librustc_trait_selection/traits/fulfill.rs index 300acf95c99..1e056c96acd 100644 --- a/src/librustc_trait_selection/traits/fulfill.rs +++ b/src/librustc_trait_selection/traits/fulfill.rs @@ -240,9 +240,15 @@ struct FulfillProcessor<'a, 'b, 'tcx> { register_region_obligations: bool, } -fn mk_pending(os: Vec<PredicateObligation<'tcx>>) -> Vec<PendingPredicateObligation<'tcx>> { +fn mk_pending( + infcx: &InferCtxt<'_, 'tcx>, + os: Vec<PredicateObligation<'tcx>>, +) -> Vec<PendingPredicateObligation<'tcx>> { os.into_iter() - .map(|o| PendingPredicateObligation { obligation: o, stalled_on: vec![] }) + .map(|mut o| { + o.predicate = infcx.resolve_vars_if_possible(&o.predicate); + PendingPredicateObligation { obligation: o, stalled_on: vec![] } + }) .collect() } @@ -312,6 +318,8 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> { debug!("process_obligation: obligation = {:?} cause = {:?}", obligation, obligation.cause); + let infcx = self.selcx.infcx(); + match obligation.predicate { ty::Predicate::Trait(ref data, _) => { let trait_obligation = obligation.with(*data); @@ -319,7 +327,7 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> { if data.is_global() { // no type variables present, can use evaluation for better caching. // FIXME: consider caching errors too. - if self.selcx.infcx().predicate_must_hold_considering_regions(&obligation) { + if infcx.predicate_must_hold_considering_regions(&obligation) { debug!( "selecting trait `{:?}` at depth {} evaluated to holds", data, obligation.recursion_depth @@ -334,7 +342,7 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> { "selecting trait `{:?}` at depth {} yielded Ok(Some)", data, obligation.recursion_depth ); - ProcessResult::Changed(mk_pending(vtable.nested_obligations())) + ProcessResult::Changed(mk_pending(infcx, vtable.nested_obligations())) } Ok(None) => { debug!( @@ -351,7 +359,7 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> { debug!( "process_predicate: pending obligation {:?} now stalled on {:?}", - self.selcx.infcx().resolve_vars_if_possible(obligation), + infcx.resolve_vars_if_possible(obligation), pending_obligation.stalled_on ); @@ -369,7 +377,7 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> { } ty::Predicate::RegionOutlives(ref binder) => { - match self.selcx.infcx().region_outlives_predicate(&obligation.cause, binder) { + match infcx.region_outlives_predicate(&obligation.cause, binder) { Ok(()) => ProcessResult::Changed(vec![]), Err(_) => ProcessResult::Error(CodeSelectionError(Unimplemented)), } @@ -428,7 +436,7 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> { trait_ref_type_vars(self.selcx, data.to_poly_trait_ref(tcx)); ProcessResult::Unchanged } - Ok(Some(os)) => ProcessResult::Changed(mk_pending(os)), + Ok(Some(os)) => ProcessResult::Changed(mk_pending(infcx, os)), Err(e) => ProcessResult::Error(CodeProjectionError(e)), } } @@ -467,7 +475,7 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> { vec![TyOrConstInferVar::maybe_from_ty(ty).unwrap()]; ProcessResult::Unchanged } - Some(os) => ProcessResult::Changed(mk_pending(os)), + Some(os) => ProcessResult::Changed(mk_pending(infcx, os)), } } @@ -485,7 +493,7 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> { ]; ProcessResult::Unchanged } - Some(Ok(ok)) => ProcessResult::Changed(mk_pending(ok.obligations)), + Some(Ok(ok)) => ProcessResult::Changed(mk_pending(infcx, ok.obligations)), Some(Err(err)) => { let expected_found = ExpectedFound::new( subtype.skip_binder().a_is_expected, diff --git a/src/librustc_trait_selection/traits/project.rs b/src/librustc_trait_selection/traits/project.rs index 2b4a0409fd1..bf0e1ed7b89 100644 --- a/src/librustc_trait_selection/traits/project.rs +++ b/src/librustc_trait_selection/traits/project.rs @@ -18,6 +18,7 @@ use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use crate::infer::{InferCtxt, InferOk, LateBoundRegionConversionTime}; use crate::traits::error_reporting::InferCtxtExt; use rustc_ast::ast::Ident; +use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_errors::ErrorReported; use rustc_hir::def_id::DefId; use rustc_middle::ty::fold::{TypeFoldable, TypeFolder}; @@ -261,7 +262,7 @@ where { debug!("normalize_with_depth(depth={}, value={:?})", depth, value); let mut normalizer = AssocTypeNormalizer::new(selcx, param_env, cause, depth, obligations); - let result = normalizer.fold(value); + let result = ensure_sufficient_stack(|| normalizer.fold(value)); debug!( "normalize_with_depth: depth={} result={:?} with {} obligations", depth, @@ -471,7 +472,7 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>( // bounds. It might be the case that we want two distinct caches, // or else another kind of cache entry. - let cache_result = infcx.inner.borrow_mut().projection_cache.try_start(cache_key); + let cache_result = infcx.inner.borrow_mut().projection_cache().try_start(cache_key); match cache_result { Ok(()) => {} Err(ProjectionCacheEntry::Ambiguous) => { @@ -537,7 +538,7 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>( // Once we have inferred everything we need to know, we // can ignore the `obligations` from that point on. if infcx.unresolved_type_vars(&ty.value).is_none() { - infcx.inner.borrow_mut().projection_cache.complete_normalized(cache_key, &ty); + infcx.inner.borrow_mut().projection_cache().complete_normalized(cache_key, &ty); // No need to extend `obligations`. } else { obligations.extend(ty.obligations); @@ -604,7 +605,7 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>( }; let cache_value = prune_cache_value_obligations(infcx, &result); - infcx.inner.borrow_mut().projection_cache.insert_ty(cache_key, cache_value); + infcx.inner.borrow_mut().projection_cache().insert_ty(cache_key, cache_value); obligations.extend(result.obligations); Some(result.value) } @@ -615,7 +616,7 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>( projected_ty ); let result = Normalized { value: projected_ty, obligations: vec![] }; - infcx.inner.borrow_mut().projection_cache.insert_ty(cache_key, result.clone()); + infcx.inner.borrow_mut().projection_cache().insert_ty(cache_key, result.clone()); // No need to extend `obligations`. Some(result.value) } @@ -624,7 +625,7 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>( "opt_normalize_projection_type: \ too many candidates" ); - infcx.inner.borrow_mut().projection_cache.ambiguous(cache_key); + infcx.inner.borrow_mut().projection_cache().ambiguous(cache_key); None } Err(ProjectionTyError::TraitSelectionError(_)) => { @@ -634,7 +635,7 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>( // Trait`, which when processed will cause the error to be // reported later - infcx.inner.borrow_mut().projection_cache.error(cache_key); + infcx.inner.borrow_mut().projection_cache().error(cache_key); let result = normalize_to_error(selcx, param_env, projection_ty, cause, depth); obligations.extend(result.obligations); Some(result.value) diff --git a/src/librustc_trait_selection/traits/query/normalize.rs b/src/librustc_trait_selection/traits/query/normalize.rs index 0da26abc330..3b985a4b150 100644 --- a/src/librustc_trait_selection/traits/query/normalize.rs +++ b/src/librustc_trait_selection/traits/query/normalize.rs @@ -7,6 +7,7 @@ use crate::infer::canonical::OriginalQueryValues; use crate::infer::{InferCtxt, InferOk}; use crate::traits::error_reporting::InferCtxtExt; use crate::traits::{Obligation, ObligationCause, PredicateObligation, Reveal}; +use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_infer::traits::Normalized; use rustc_middle::ty::fold::{TypeFoldable, TypeFolder}; use rustc_middle::ty::subst::Subst; @@ -131,7 +132,7 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> { ty ); } - let folded_ty = self.fold_ty(concrete_ty); + let folded_ty = ensure_sufficient_stack(|| self.fold_ty(concrete_ty)); self.anon_depth -= 1; folded_ty } diff --git a/src/librustc_trait_selection/traits/select.rs b/src/librustc_trait_selection/traits/select.rs index dfbb0742448..27d3b2ec9cb 100644 --- a/src/librustc_trait_selection/traits/select.rs +++ b/src/librustc_trait_selection/traits/select.rs @@ -37,6 +37,7 @@ use crate::traits::error_reporting::InferCtxtExt; use crate::traits::project::ProjectionCacheKeyExt; use rustc_ast::attr; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_hir::lang_items; @@ -471,7 +472,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { if let Some(key) = ProjectionCacheKey::from_poly_projection_predicate(self, data) { - self.infcx.inner.borrow_mut().projection_cache.complete(key); + self.infcx.inner.borrow_mut().projection_cache().complete(key); } result } @@ -2365,13 +2366,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { self.infcx.commit_unconditionally(|_| { let (skol_ty, _) = self.infcx.replace_bound_vars_with_placeholders(&ty); let Normalized { value: normalized_ty, mut obligations } = - project::normalize_with_depth( - self, - param_env, - cause.clone(), - recursion_depth, - &skol_ty, - ); + ensure_sufficient_stack(|| { + project::normalize_with_depth( + self, + param_env, + cause.clone(), + recursion_depth, + &skol_ty, + ) + }); let skol_obligation = predicate_for_trait_def( self.tcx(), param_env, @@ -2525,13 +2528,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { }; let cause = obligation.derived_cause(BuiltinDerivedObligation); - self.collect_predicates_for_types( - obligation.param_env, - cause, - obligation.recursion_depth + 1, - trait_def, - nested, - ) + ensure_sufficient_stack(|| { + self.collect_predicates_for_types( + obligation.param_env, + cause, + obligation.recursion_depth + 1, + trait_def, + nested, + ) + }) } else { vec![] }; @@ -2568,38 +2573,39 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { nested: ty::Binder<Vec<Ty<'tcx>>>, ) -> VtableAutoImplData<PredicateObligation<'tcx>> { debug!("vtable_auto_impl: nested={:?}", nested); + ensure_sufficient_stack(|| { + let cause = obligation.derived_cause(BuiltinDerivedObligation); + let mut obligations = self.collect_predicates_for_types( + obligation.param_env, + cause, + obligation.recursion_depth + 1, + trait_def_id, + nested, + ); - let cause = obligation.derived_cause(BuiltinDerivedObligation); - let mut obligations = self.collect_predicates_for_types( - obligation.param_env, - cause, - obligation.recursion_depth + 1, - trait_def_id, - nested, - ); - - let trait_obligations: Vec<PredicateObligation<'_>> = - self.infcx.commit_unconditionally(|_| { - let poly_trait_ref = obligation.predicate.to_poly_trait_ref(); - let (trait_ref, _) = - self.infcx.replace_bound_vars_with_placeholders(&poly_trait_ref); - let cause = obligation.derived_cause(ImplDerivedObligation); - self.impl_or_trait_obligations( - cause, - obligation.recursion_depth + 1, - obligation.param_env, - trait_def_id, - &trait_ref.substs, - ) - }); + let trait_obligations: Vec<PredicateObligation<'_>> = + self.infcx.commit_unconditionally(|_| { + let poly_trait_ref = obligation.predicate.to_poly_trait_ref(); + let (trait_ref, _) = + self.infcx.replace_bound_vars_with_placeholders(&poly_trait_ref); + let cause = obligation.derived_cause(ImplDerivedObligation); + self.impl_or_trait_obligations( + cause, + obligation.recursion_depth + 1, + obligation.param_env, + trait_def_id, + &trait_ref.substs, + ) + }); - // Adds the predicates from the trait. Note that this contains a `Self: Trait` - // predicate as usual. It won't have any effect since auto traits are coinductive. - obligations.extend(trait_obligations); + // Adds the predicates from the trait. Note that this contains a `Self: Trait` + // predicate as usual. It won't have any effect since auto traits are coinductive. + obligations.extend(trait_obligations); - debug!("vtable_auto_impl: obligations={:?}", obligations); + debug!("vtable_auto_impl: obligations={:?}", obligations); - VtableAutoImplData { trait_def_id, nested: obligations } + VtableAutoImplData { trait_def_id, nested: obligations } + }) } fn confirm_impl_candidate( @@ -2615,13 +2621,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let substs = self.rematch_impl(impl_def_id, obligation, snapshot); debug!("confirm_impl_candidate: substs={:?}", substs); let cause = obligation.derived_cause(ImplDerivedObligation); - self.vtable_impl( - impl_def_id, - substs, - cause, - obligation.recursion_depth + 1, - obligation.param_env, - ) + ensure_sufficient_stack(|| { + self.vtable_impl( + impl_def_id, + substs, + cause, + obligation.recursion_depth + 1, + obligation.param_env, + ) + }) }) } @@ -2734,13 +2742,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ) .map_bound(|(trait_ref, _)| trait_ref); - let Normalized { value: trait_ref, obligations } = project::normalize_with_depth( - self, - obligation.param_env, - obligation.cause.clone(), - obligation.recursion_depth + 1, - &trait_ref, - ); + let Normalized { value: trait_ref, obligations } = ensure_sufficient_stack(|| { + project::normalize_with_depth( + self, + obligation.param_env, + obligation.cause.clone(), + obligation.recursion_depth + 1, + &trait_ref, + ) + }); self.confirm_poly_trait_refs( obligation.cause.clone(), @@ -2798,13 +2808,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { debug!("confirm_generator_candidate({:?},{:?},{:?})", obligation, generator_def_id, substs); let trait_ref = self.generator_trait_ref_unnormalized(obligation, substs); - let Normalized { value: trait_ref, mut obligations } = normalize_with_depth( - self, - obligation.param_env, - obligation.cause.clone(), - obligation.recursion_depth + 1, - &trait_ref, - ); + let Normalized { value: trait_ref, mut obligations } = ensure_sufficient_stack(|| { + normalize_with_depth( + self, + obligation.param_env, + obligation.cause.clone(), + obligation.recursion_depth + 1, + &trait_ref, + ) + }); debug!( "confirm_generator_candidate(generator_def_id={:?}, \ @@ -2843,13 +2855,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { }; let trait_ref = self.closure_trait_ref_unnormalized(obligation, substs); - let Normalized { value: trait_ref, mut obligations } = normalize_with_depth( - self, - obligation.param_env, - obligation.cause.clone(), - obligation.recursion_depth + 1, - &trait_ref, - ); + let Normalized { value: trait_ref, mut obligations } = ensure_sufficient_stack(|| { + normalize_with_depth( + self, + obligation.param_env, + obligation.cause.clone(), + obligation.recursion_depth + 1, + &trait_ref, + ) + }); debug!( "confirm_closure_candidate(closure_def_id={:?}, trait_ref={:?}, obligations={:?})", @@ -3139,15 +3153,17 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { nested.extend(obligations); // Construct the nested `T: Unsize<U>` predicate. - nested.push(predicate_for_trait_def( - tcx, - obligation.param_env, - obligation.cause.clone(), - obligation.predicate.def_id(), - obligation.recursion_depth + 1, - a_last.expect_ty(), - &[b_last], - )); + nested.push(ensure_sufficient_stack(|| { + predicate_for_trait_def( + tcx, + obligation.param_env, + obligation.cause.clone(), + obligation.predicate.def_id(), + obligation.recursion_depth + 1, + a_last.expect_ty(), + &[b_last], + ) + })); } _ => bug!(), @@ -3208,13 +3224,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let impl_trait_ref = impl_trait_ref.subst(self.tcx(), impl_substs); let Normalized { value: impl_trait_ref, obligations: mut nested_obligations } = - project::normalize_with_depth( - self, - obligation.param_env, - obligation.cause.clone(), - obligation.recursion_depth + 1, - &impl_trait_ref, - ); + ensure_sufficient_stack(|| { + project::normalize_with_depth( + self, + obligation.param_env, + obligation.cause.clone(), + obligation.recursion_depth + 1, + &impl_trait_ref, + ) + }); debug!( "match_impl(impl_def_id={:?}, obligation={:?}, \ diff --git a/src/librustc_trait_selection/traits/structural_match.rs b/src/librustc_trait_selection/traits/structural_match.rs index fbe1fcb08f2..8007290f35d 100644 --- a/src/librustc_trait_selection/traits/structural_match.rs +++ b/src/librustc_trait_selection/traits/structural_match.rs @@ -11,6 +11,7 @@ use rustc_span::Span; pub enum NonStructuralMatchTy<'tcx> { Adt(&'tcx AdtDef), Param, + Dynamic, } /// This method traverses the structure of `ty`, trying to find an @@ -137,6 +138,10 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for Search<'a, 'tcx> { self.found = Some(NonStructuralMatchTy::Param); return true; // Stop visiting. } + ty::Dynamic(..) => { + self.found = Some(NonStructuralMatchTy::Dynamic); + return true; // Stop visiting. + } ty::RawPtr(..) => { // structural-match ignores substructure of // `*const _`/`*mut _`, so skip `super_visit_with`. diff --git a/src/librustc_traits/dropck_outlives.rs b/src/librustc_traits/dropck_outlives.rs index 93b15e146ec..76ff58d61a2 100644 --- a/src/librustc_traits/dropck_outlives.rs +++ b/src/librustc_traits/dropck_outlives.rs @@ -191,10 +191,12 @@ fn dtorck_constraint_for_ty<'tcx>( ty::Array(ety, _) | ty::Slice(ety) => { // single-element containers, behave like their element - dtorck_constraint_for_ty(tcx, span, for_ty, depth + 1, ety, constraints)?; + rustc_data_structures::stack::ensure_sufficient_stack(|| { + dtorck_constraint_for_ty(tcx, span, for_ty, depth + 1, ety, constraints) + })?; } - ty::Tuple(tys) => { + ty::Tuple(tys) => rustc_data_structures::stack::ensure_sufficient_stack(|| { for ty in tys.iter() { dtorck_constraint_for_ty( tcx, @@ -205,13 +207,15 @@ fn dtorck_constraint_for_ty<'tcx>( constraints, )?; } - } + Ok::<_, NoSolution>(()) + })?, - ty::Closure(_, substs) => { + ty::Closure(_, substs) => rustc_data_structures::stack::ensure_sufficient_stack(|| { for ty in substs.as_closure().upvar_tys() { dtorck_constraint_for_ty(tcx, span, for_ty, depth + 1, ty, constraints)?; } - } + Ok::<_, NoSolution>(()) + })?, ty::Generator(_, substs, _movability) => { // rust-lang/rust#49918: types can be constructed, stored diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 39fcd075645..cd6cd94b143 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -1753,7 +1753,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { potential_assoc_types: Vec<Span>, trait_bounds: &[hir::PolyTraitRef<'_>], ) { - if !associated_types.values().any(|v| !v.is_empty()) { + if associated_types.values().all(|v| v.is_empty()) { return; } let tcx = self.tcx(); diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs index 1acbcc03889..035e5880dc5 100644 --- a/src/librustc_typeck/check/closure.rs +++ b/src/librustc_typeck/check/closure.rs @@ -178,7 +178,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { match expected_ty.kind { ty::Dynamic(ref object_type, ..) => { let sig = object_type.projection_bounds().find_map(|pb| { - let pb = pb.with_self_ty(self.tcx, self.tcx.types.err); + let pb = pb.with_self_ty(self.tcx, self.tcx.types.trait_object_dummy_self); self.deduce_sig_from_projection(None, &pb) }); let kind = object_type diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs index 6e4af6d769a..29cd9681295 100644 --- a/src/librustc_typeck/check/compare_method.rs +++ b/src/librustc_typeck/check/compare_method.rs @@ -966,6 +966,7 @@ crate fn compare_const_impl<'tcx>( let impl_ty = tcx.type_of(impl_c.def_id); let trait_ty = tcx.type_of(trait_c.def_id).subst(tcx, trait_to_impl_substs); let mut cause = ObligationCause::misc(impl_c_span, impl_c_hir_id); + cause.code = ObligationCauseCode::CompareImplConstObligation; // There is no "body" here, so just pass dummy id. let impl_ty = diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs index 9e14efb67a9..8ae5ee4c3f9 100644 --- a/src/librustc_typeck/check/demand.rs +++ b/src/librustc_typeck/check/demand.rs @@ -909,13 +909,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { cast_suggestion, Applicability::MaybeIncorrect, // lossy conversion ); - err.warn( - "if the rounded value cannot be represented by the target \ - integer type, including `Inf` and `NaN`, casting will cause \ - undefined behavior \ - (see issue #10184 <https://github.com/rust-lang/rust/issues/10184> \ - for more information)", - ); } true } diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index 228c40ac853..857cc972559 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -947,65 +947,59 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // this isn't perfect (that is, there are cases when // implementing a trait would be legal but is rejected // here). - !unsatisfied_predicates.iter().any(|(p, _)| match p { - // Hide traits if they are present in predicates as they can be fixed without - // having to implement them. - ty::Predicate::Trait(t, _) => t.def_id() != info.def_id, - ty::Predicate::Projection(p) => p.item_def_id() != info.def_id, - _ => true, - }) && (type_is_local || info.def_id.is_local()) - && self - .associated_item(info.def_id, item_name, Namespace::ValueNS) - .filter(|item| { - if let ty::AssocKind::Fn = item.kind { - let id = item.def_id.as_local().map(|def_id| { - self.tcx.hir().as_local_hir_id(def_id) - }); - if let Some(hir::Node::TraitItem(hir::TraitItem { - kind: hir::TraitItemKind::Fn(fn_sig, method), - .. - })) = id.map(|id| self.tcx.hir().get(id)) + unsatisfied_predicates.iter().all(|(p, _)| match p { + // Hide traits if they are present in predicates as they can be fixed without + // having to implement them. + ty::Predicate::Trait(t, _) => t.def_id() == info.def_id, + ty::Predicate::Projection(p) => p.item_def_id() == info.def_id, + _ => false, + }) && (type_is_local || info.def_id.is_local()) + && self + .associated_item(info.def_id, item_name, Namespace::ValueNS) + .filter(|item| { + if let ty::AssocKind::Fn = item.kind { + let id = item + .def_id + .as_local() + .map(|def_id| self.tcx.hir().as_local_hir_id(def_id)); + if let Some(hir::Node::TraitItem(hir::TraitItem { + kind: hir::TraitItemKind::Fn(fn_sig, method), + .. + })) = id.map(|id| self.tcx.hir().get(id)) + { + let self_first_arg = match method { + hir::TraitFn::Required([ident, ..]) => { + ident.name == kw::SelfLower + } + hir::TraitFn::Provided(body_id) => { + self.tcx.hir().body(*body_id).params.first().map_or( + false, + |param| { + matches!( + param.pat.kind, + hir::PatKind::Binding(_, _, ident, _) + if ident.name == kw::SelfLower + ) + }, + ) + } + _ => false, + }; + + if !fn_sig.decl.implicit_self.has_implicit_self() + && self_first_arg { - let self_first_arg = match method { - hir::TraitFn::Required([ident, ..]) => { - ident.name == kw::SelfLower - } - hir::TraitFn::Provided(body_id) => { - match &self.tcx.hir().body(*body_id).params[..] { - [hir::Param { - pat: - hir::Pat { - kind: - hir::PatKind::Binding( - _, - _, - ident, - .., - ), - .. - }, - .. - }, ..] => ident.name == kw::SelfLower, - _ => false, - } - } - _ => false, - }; - - if !fn_sig.decl.implicit_self.has_implicit_self() - && self_first_arg - { - if let Some(ty) = fn_sig.decl.inputs.get(0) { - arbitrary_rcvr.push(ty.span); - } - return false; + if let Some(ty) = fn_sig.decl.inputs.get(0) { + arbitrary_rcvr.push(ty.span); } + return false; } } - // We only want to suggest public or local traits (#45781). - item.vis == ty::Visibility::Public || info.def_id.is_local() - }) - .is_some() + } + // We only want to suggest public or local traits (#45781). + item.vis == ty::Visibility::Public || info.def_id.is_local() + }) + .is_some() }) .collect::<Vec<_>>(); for span in &arbitrary_rcvr { diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 6274a11ebd5..bff1ca2433a 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -5387,7 +5387,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { _ => return None, }; let last_expr_ty = self.node_ty(last_expr.hir_id); - if self.can_sub(self.param_env, last_expr_ty, expected_ty).is_err() { + if matches!(last_expr_ty.kind, ty::Error) + || self.can_sub(self.param_env, last_expr_ty, expected_ty).is_err() + { return None; } let original_span = original_sp(last_stmt.span, blk.span); diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs index cac9113fd5d..e6cbc8ab723 100644 --- a/src/librustc_typeck/check/op.rs +++ b/src/librustc_typeck/check/op.rs @@ -10,7 +10,7 @@ use rustc_middle::ty::adjustment::{ Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability, }; use rustc_middle::ty::TyKind::{Adt, Array, Char, FnDef, Never, Ref, Str, Tuple, Uint}; -use rustc_middle::ty::{self, Ty, TypeFoldable}; +use rustc_middle::ty::{self, suggest_constraining_type_param, Ty, TyCtxt, TypeFoldable}; use rustc_span::Span; use rustc_trait_selection::infer::InferCtxtExt; @@ -251,8 +251,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } Err(()) => { // error types are considered "builtin" - if !lhs_ty.references_error() { + if !lhs_ty.references_error() && !rhs_ty.references_error() { let source_map = self.tcx.sess.source_map(); + match is_assign { IsAssign::Yes => { let mut err = struct_span_err!( @@ -317,12 +318,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // This has nothing here because it means we did string // concatenation (e.g., "Hello " += "World!"). This means // we don't want the note in the else clause to be emitted - } else if let ty::Param(_) = lhs_ty.kind { - // FIXME: point to span of param - err.note(&format!( - "`{}` might need a bound for `{}`", - lhs_ty, missing_trait - )); + } else if let ty::Param(p) = lhs_ty.kind { + suggest_constraining_param( + self.tcx, + self.body_id, + &mut err, + lhs_ty, + rhs_ty, + missing_trait, + p, + false, + ); } else if !suggested_deref { suggest_impl_missing(&mut err, lhs_ty, &missing_trait); } @@ -330,46 +336,56 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { err.emit(); } IsAssign::No => { - let (message, missing_trait) = match op.node { + let (message, missing_trait, use_output) = match op.node { hir::BinOpKind::Add => ( format!("cannot add `{}` to `{}`", rhs_ty, lhs_ty), Some("std::ops::Add"), + true, ), hir::BinOpKind::Sub => ( format!("cannot subtract `{}` from `{}`", rhs_ty, lhs_ty), Some("std::ops::Sub"), + true, ), hir::BinOpKind::Mul => ( format!("cannot multiply `{}` to `{}`", rhs_ty, lhs_ty), Some("std::ops::Mul"), + true, ), hir::BinOpKind::Div => ( format!("cannot divide `{}` by `{}`", lhs_ty, rhs_ty), Some("std::ops::Div"), + true, ), hir::BinOpKind::Rem => ( format!("cannot mod `{}` by `{}`", lhs_ty, rhs_ty), Some("std::ops::Rem"), + true, ), hir::BinOpKind::BitAnd => ( format!("no implementation for `{} & {}`", lhs_ty, rhs_ty), Some("std::ops::BitAnd"), + true, ), hir::BinOpKind::BitXor => ( format!("no implementation for `{} ^ {}`", lhs_ty, rhs_ty), Some("std::ops::BitXor"), + true, ), hir::BinOpKind::BitOr => ( format!("no implementation for `{} | {}`", lhs_ty, rhs_ty), Some("std::ops::BitOr"), + true, ), hir::BinOpKind::Shl => ( format!("no implementation for `{} << {}`", lhs_ty, rhs_ty), Some("std::ops::Shl"), + true, ), hir::BinOpKind::Shr => ( format!("no implementation for `{} >> {}`", lhs_ty, rhs_ty), Some("std::ops::Shr"), + true, ), hir::BinOpKind::Eq | hir::BinOpKind::Ne => ( format!( @@ -378,6 +394,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { lhs_ty ), Some("std::cmp::PartialEq"), + false, ), hir::BinOpKind::Lt | hir::BinOpKind::Le @@ -389,6 +406,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { lhs_ty ), Some("std::cmp::PartialOrd"), + false, ), _ => ( format!( @@ -397,6 +415,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { lhs_ty ), None, + false, ), }; let mut err = struct_span_err!( @@ -459,12 +478,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // This has nothing here because it means we did string // concatenation (e.g., "Hello " + "World!"). This means // we don't want the note in the else clause to be emitted - } else if let ty::Param(_) = lhs_ty.kind { - // FIXME: point to span of param - err.note(&format!( - "`{}` might need a bound for `{}`", - lhs_ty, missing_trait - )); + } else if let ty::Param(p) = lhs_ty.kind { + suggest_constraining_param( + self.tcx, + self.body_id, + &mut err, + lhs_ty, + rhs_ty, + missing_trait, + p, + use_output, + ); } else if !suggested_deref && !involves_fn { suggest_impl_missing(&mut err, lhs_ty, &missing_trait); } @@ -911,3 +935,43 @@ fn suggest_impl_missing(err: &mut DiagnosticBuilder<'_>, ty: Ty<'_>, missing_tra } } } + +fn suggest_constraining_param( + tcx: TyCtxt<'_>, + body_id: hir::HirId, + mut err: &mut DiagnosticBuilder<'_>, + lhs_ty: Ty<'_>, + rhs_ty: Ty<'_>, + missing_trait: &str, + p: ty::ParamTy, + set_output: bool, +) { + let hir = tcx.hir(); + let msg = &format!("`{}` might need a bound for `{}`", lhs_ty, missing_trait); + // Try to find the def-id and details for the parameter p. We have only the index, + // so we have to find the enclosing function's def-id, then look through its declared + // generic parameters to get the declaration. + let def_id = hir.body_owner_def_id(hir::BodyId { hir_id: body_id }); + let generics = tcx.generics_of(def_id); + let param_def_id = generics.type_param(&p, tcx).def_id; + if let Some(generics) = param_def_id + .as_local() + .map(|id| hir.as_local_hir_id(id)) + .and_then(|id| hir.find(hir.get_parent_item(id))) + .as_ref() + .and_then(|node| node.generics()) + { + let output = if set_output { format!("<Output = {}>", rhs_ty) } else { String::new() }; + suggest_constraining_type_param( + tcx, + generics, + &mut err, + &format!("{}", lhs_ty), + &format!("{}{}", missing_trait, output), + None, + ); + } else { + let span = tcx.def_span(param_def_id); + err.span_label(span, msg); + } +} diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 03d1dc21816..51ad1f04340 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -204,6 +204,56 @@ pub fn new_handler( ) } +/// This function is used to setup the lint initialization. By default, in rustdoc, everything +/// is "allowed". Depending if we run in test mode or not, we want some of them to be at their +/// default level. For example, the "INVALID_CODEBLOCK_ATTRIBUTE" lint is activated in both +/// modes. +/// +/// A little detail easy to forget is that there is a way to set the lint level for all lints +/// through the "WARNINGS" lint. To prevent this to happen, we set it back to its "normal" level +/// inside this function. +/// +/// It returns a tuple containing: +/// * Vector of tuples of lints' name and their associated "max" level +/// * HashMap of lint id with their associated "max" level +pub fn init_lints<F>( + mut whitelisted_lints: Vec<String>, + lint_opts: Vec<(String, lint::Level)>, + filter_call: F, +) -> (Vec<(String, lint::Level)>, FxHashMap<lint::LintId, lint::Level>) +where + F: Fn(&lint::Lint) -> Option<(String, lint::Level)>, +{ + let warnings_lint_name = lint::builtin::WARNINGS.name; + + whitelisted_lints.push(warnings_lint_name.to_owned()); + whitelisted_lints.extend(lint_opts.iter().map(|(lint, _)| lint).cloned()); + + let lints = || { + lint::builtin::HardwiredLints::get_lints() + .into_iter() + .chain(rustc_lint::SoftLints::get_lints().into_iter()) + }; + + let lint_opts = lints() + .filter_map(|lint| if lint.name == warnings_lint_name { None } else { filter_call(lint) }) + .chain(lint_opts.into_iter()) + .collect::<Vec<_>>(); + + let lint_caps = lints() + .filter_map(|lint| { + // We don't want to whitelist *all* lints so let's + // ignore those ones. + if whitelisted_lints.iter().any(|l| lint.name == l) { + None + } else { + Some((lint::LintId::of(lint), lint::Allow)) + } + }) + .collect(); + (lint_opts, lint_caps) +} + pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOptions) { // Parse, resolve, and typecheck the given crate. @@ -247,7 +297,6 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt let input = Input::File(input); let intra_link_resolution_failure_name = lint::builtin::INTRA_DOC_LINK_RESOLUTION_FAILURE.name; - let warnings_lint_name = lint::builtin::WARNINGS.name; let missing_docs = rustc_lint::builtin::MISSING_DOCS.name; let missing_doc_example = rustc_lint::builtin::MISSING_DOC_CODE_EXAMPLES.name; let private_doc_tests = rustc_lint::builtin::PRIVATE_DOC_TESTS.name; @@ -256,8 +305,7 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt // In addition to those specific lints, we also need to whitelist those given through // command line, otherwise they'll get ignored and we don't want that. - let mut whitelisted_lints = vec![ - warnings_lint_name.to_owned(), + let whitelisted_lints = vec![ intra_link_resolution_failure_name.to_owned(), missing_docs.to_owned(), missing_doc_example.to_owned(), @@ -266,39 +314,15 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt invalid_codeblock_attribute_name.to_owned(), ]; - whitelisted_lints.extend(lint_opts.iter().map(|(lint, _)| lint).cloned()); - - let lints = || { - lint::builtin::HardwiredLints::get_lints() - .into_iter() - .chain(rustc_lint::SoftLints::get_lints().into_iter()) - }; - - let lint_opts = lints() - .filter_map(|lint| { - if lint.name == warnings_lint_name - || lint.name == intra_link_resolution_failure_name - || lint.name == invalid_codeblock_attribute_name - { - None - } else { - Some((lint.name_lower(), lint::Allow)) - } - }) - .chain(lint_opts.into_iter()) - .collect::<Vec<_>>(); - - let lint_caps = lints() - .filter_map(|lint| { - // We don't want to whitelist *all* lints so let's - // ignore those ones. - if whitelisted_lints.iter().any(|l| lint.name == l) { - None - } else { - Some((lint::LintId::of(lint), lint::Allow)) - } - }) - .collect(); + let (lint_opts, lint_caps) = init_lints(whitelisted_lints, lint_opts, |lint| { + if lint.name == intra_link_resolution_failure_name + || lint.name == invalid_codeblock_attribute_name + { + None + } else { + Some((lint.name_lower(), lint::Allow)) + } + }); let crate_types = if proc_macro_crate { vec![CrateType::ProcMacro] } else { vec![CrateType::Rlib] }; diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 4bb50f75791..550f672ed4c 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -1129,9 +1129,36 @@ pub struct IdMap { map: FxHashMap<String, usize>, } +fn init_id_map() -> FxHashMap<String, usize> { + let mut map = FxHashMap::default(); + // This is the list of IDs used by rustdoc templates. + map.insert("mainThemeStyle".to_owned(), 1); + map.insert("themeStyle".to_owned(), 1); + map.insert("theme-picker".to_owned(), 1); + map.insert("theme-choices".to_owned(), 1); + map.insert("settings-menu".to_owned(), 1); + map.insert("main".to_owned(), 1); + map.insert("search".to_owned(), 1); + map.insert("crate-search".to_owned(), 1); + map.insert("render-detail".to_owned(), 1); + map.insert("toggle-all-docs".to_owned(), 1); + map.insert("all-types".to_owned(), 1); + // This is the list of IDs used by rustdoc sections. + map.insert("fields".to_owned(), 1); + map.insert("variants".to_owned(), 1); + map.insert("implementors-list".to_owned(), 1); + map.insert("synthetic-implementors-list".to_owned(), 1); + map.insert("implementations".to_owned(), 1); + map.insert("trait-implementations".to_owned(), 1); + map.insert("synthetic-implementations".to_owned(), 1); + map.insert("blanket-implementations".to_owned(), 1); + map.insert("deref-methods".to_owned(), 1); + map +} + impl IdMap { pub fn new() -> Self { - IdMap::default() + IdMap { map: init_id_map() } } pub fn populate<I: IntoIterator<Item = String>>(&mut self, ids: I) { @@ -1141,7 +1168,7 @@ impl IdMap { } pub fn reset(&mut self) { - self.map = FxHashMap::default(); + self.map = init_id_map(); } pub fn derive(&mut self, candidate: String) -> String { diff --git a/src/librustdoc/html/markdown/tests.rs b/src/librustdoc/html/markdown/tests.rs index c871587a0a9..bf0451a1d9d 100644 --- a/src/librustdoc/html/markdown/tests.rs +++ b/src/librustdoc/html/markdown/tests.rs @@ -29,8 +29,8 @@ fn test_unique_id() { "examples-2", "method.into_iter-1", "foo-1", - "main", - "search", + "main-1", + "search-1", "methods", "examples-3", "method.into_iter-2", @@ -191,8 +191,8 @@ fn test_header_ids_multiple_blocks() { t( &mut map, "# Main", - "<h1 id=\"main\" class=\"section-header\">\ - <a href=\"#main\">Main</a></h1>", + "<h1 id=\"main-1\" class=\"section-header\">\ + <a href=\"#main-1\">Main</a></h1>", ); t( &mut map, diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 387ef03f067..666e59b9a04 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -3413,8 +3413,8 @@ fn render_assoc_items( write!( w, "\ - <h2 id='methods' class='small-section-header'>\ - Methods<a href='#methods' class='anchor'></a>\ + <h2 id='implementations' class='small-section-header'>\ + Implementations<a href='#implementations' class='anchor'></a>\ </h2>\ " ); @@ -3475,10 +3475,10 @@ fn render_assoc_items( write!( w, "\ - <h2 id='implementations' class='small-section-header'>\ - Trait Implementations<a href='#implementations' class='anchor'></a>\ + <h2 id='trait-implementations' class='small-section-header'>\ + Trait Implementations<a href='#trait-implementations' class='anchor'></a>\ </h2>\ - <div id='implementations-list'>{}</div>", + <div id='trait-implementations-list'>{}</div>", impls ); } @@ -4097,8 +4097,8 @@ fn sidebar_assoc_items(it: &clean::Item) -> String { ret.sort(); if !ret.is_empty() { out.push_str(&format!( - "<a class=\"sidebar-title\" href=\"#methods\">Methods\ - </a><div class=\"sidebar-links\">{}</div>", + "<a class=\"sidebar-title\" href=\"#implementations\">Methods</a>\ + <div class=\"sidebar-links\">{}</div>", ret.join("") )); } @@ -4191,8 +4191,8 @@ fn sidebar_assoc_items(it: &clean::Item) -> String { if !concrete_format.is_empty() { out.push_str( - "<a class=\"sidebar-title\" href=\"#implementations\">\ - Trait Implementations</a>", + "<a class=\"sidebar-title\" href=\"#trait-implementations\">\ + Trait Implementations</a>", ); out.push_str(&format!("<div class=\"sidebar-links\">{}</div>", concrete_format)); } @@ -4200,7 +4200,7 @@ fn sidebar_assoc_items(it: &clean::Item) -> String { if !synthetic_format.is_empty() { out.push_str( "<a class=\"sidebar-title\" href=\"#synthetic-implementations\">\ - Auto Trait Implementations</a>", + Auto Trait Implementations</a>", ); out.push_str(&format!("<div class=\"sidebar-links\">{}</div>", synthetic_format)); } @@ -4208,7 +4208,7 @@ fn sidebar_assoc_items(it: &clean::Item) -> String { if !blanket_format.is_empty() { out.push_str( "<a class=\"sidebar-title\" href=\"#blanket-implementations\">\ - Blanket Implementations</a>", + Blanket Implementations</a>", ); out.push_str(&format!("<div class=\"sidebar-links\">{}</div>", blanket_format)); } diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index 3f12fb893a4..a023d5a2d95 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -2180,7 +2180,7 @@ function getSearchElement() { if (collapse) { toggleAllDocs(pageId, true); } else if (getCurrentValue("rustdoc-auto-hide-trait-implementations") !== "false") { - var impl_list = document.getElementById("implementations-list"); + var impl_list = document.getElementById("trait-implementations-list"); if (impl_list !== null) { onEachLazy(impl_list.getElementsByClassName("collapse-toggle"), function(e) { diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index 5028bb46b00..4a9ad39e236 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -28,6 +28,7 @@ use std::str; use crate::clean::Attributes; use crate::config::Options; +use crate::core::init_lints; use crate::html::markdown::{self, ErrorCodes, Ignore, LangString}; use crate::passes::span_of_attrs; @@ -45,44 +46,19 @@ pub struct TestOptions { pub fn run(options: Options) -> i32 { let input = config::Input::File(options.input.clone()); - let warnings_lint_name = lint::builtin::WARNINGS.name; let invalid_codeblock_attribute_name = rustc_lint::builtin::INVALID_CODEBLOCK_ATTRIBUTE.name; // In addition to those specific lints, we also need to whitelist those given through // command line, otherwise they'll get ignored and we don't want that. - let mut whitelisted_lints = - vec![warnings_lint_name.to_owned(), invalid_codeblock_attribute_name.to_owned()]; + let whitelisted_lints = vec![invalid_codeblock_attribute_name.to_owned()]; - whitelisted_lints.extend(options.lint_opts.iter().map(|(lint, _)| lint).cloned()); - - let lints = || { - lint::builtin::HardwiredLints::get_lints() - .into_iter() - .chain(rustc_lint::SoftLints::get_lints().into_iter()) - }; - - let lint_opts = lints() - .filter_map(|lint| { - if lint.name == warnings_lint_name || lint.name == invalid_codeblock_attribute_name { - None - } else { - Some((lint.name_lower(), lint::Allow)) - } - }) - .chain(options.lint_opts.clone().into_iter()) - .collect::<Vec<_>>(); - - let lint_caps = lints() - .filter_map(|lint| { - // We don't want to whitelist *all* lints so let's - // ignore those ones. - if whitelisted_lints.iter().any(|l| lint.name == l) { - None - } else { - Some((lint::LintId::of(lint), lint::Allow)) - } - }) - .collect(); + let (lint_opts, lint_caps) = init_lints(whitelisted_lints, options.lint_opts.clone(), |lint| { + if lint.name == invalid_codeblock_attribute_name { + None + } else { + Some((lint.name_lower(), lint::Allow)) + } + }); let crate_types = if options.proc_macro_crate { vec![CrateType::ProcMacro] } else { vec![CrateType::Rlib] }; diff --git a/src/libstd/Cargo.toml b/src/libstd/Cargo.toml index ceb39c01c67..923d5fa8cac 100644 --- a/src/libstd/Cargo.toml +++ b/src/libstd/Cargo.toml @@ -41,7 +41,7 @@ dlmalloc = { version = "0.1", features = ['rustc-dep-of-std'] } fortanix-sgx-abi = { version = "0.3.2", features = ['rustc-dep-of-std'] } [target.'cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_os = "hermit"))'.dependencies] -hermit-abi = { version = "0.1.10", features = ['rustc-dep-of-std'] } +hermit-abi = { version = "0.1.12", features = ['rustc-dep-of-std'] } [target.wasm32-wasi.dependencies] wasi = { version = "0.9.0", features = ['rustc-dep-of-std'], default-features = false } diff --git a/src/libstd/sys/hermit/thread.rs b/src/libstd/sys/hermit/thread.rs index 7e3fb4c6d20..e11afed6687 100644 --- a/src/libstd/sys/hermit/thread.rs +++ b/src/libstd/sys/hermit/thread.rs @@ -16,25 +16,24 @@ pub struct Thread { unsafe impl Send for Thread {} unsafe impl Sync for Thread {} -pub const DEFAULT_MIN_STACK_SIZE: usize = 262144; +pub const DEFAULT_MIN_STACK_SIZE: usize = 1 << 20; impl Thread { pub unsafe fn new_with_coreid( - _stack: usize, + stack: usize, p: Box<dyn FnOnce()>, core_id: isize, ) -> io::Result<Thread> { let p = Box::into_raw(box p); - let mut tid: Tid = u32::MAX; - let ret = abi::spawn( - &mut tid as *mut Tid, + let tid = abi::spawn2( thread_start, - &*p as *const _ as *const u8 as usize, + p as usize, abi::Priority::into(abi::NORMAL_PRIO), + stack, core_id, ); - return if ret != 0 { + return if tid == 0 { // The thread failed to start and as a result p was not consumed. Therefore, it is // safe to reconstruct the box so that it gets deallocated. drop(Box::from_raw(p)); diff --git a/src/libstd/sys/unix/ext/net.rs b/src/libstd/sys/unix/ext/net.rs index bfdc39ada75..32c2ac43129 100644 --- a/src/libstd/sys/unix/ext/net.rs +++ b/src/libstd/sys/unix/ext/net.rs @@ -7,6 +7,7 @@ use libc; // FIXME(#43348): Make libc adapt #[doc(cfg(...))] so we don't need these fake definitions here? #[cfg(not(unix))] +#[allow(non_camel_case_types)] mod libc { pub use libc::c_int; pub type socklen_t = u32; diff --git a/src/libstd/sys/unix/ext/raw.rs b/src/libstd/sys/unix/ext/raw.rs index d81368a18b4..40fa53d484f 100644 --- a/src/libstd/sys/unix/ext/raw.rs +++ b/src/libstd/sys/unix/ext/raw.rs @@ -11,10 +11,15 @@ #![allow(deprecated)] #[stable(feature = "raw_ext", since = "1.1.0")] +#[allow(non_camel_case_types)] pub type uid_t = u32; + #[stable(feature = "raw_ext", since = "1.1.0")] +#[allow(non_camel_case_types)] pub type gid_t = u32; + #[stable(feature = "raw_ext", since = "1.1.0")] +#[allow(non_camel_case_types)] pub type pid_t = i32; #[doc(inline)] diff --git a/src/libstd/sys/unix/fs.rs b/src/libstd/sys/unix/fs.rs index 2cfc63d9492..80cf6a5dbc2 100644 --- a/src/libstd/sys/unix/fs.rs +++ b/src/libstd/sys/unix/fs.rs @@ -703,6 +703,10 @@ impl File { | opts.get_access_mode()? | opts.get_creation_mode()? | (opts.custom_flags as c_int & !libc::O_ACCMODE); + // The third argument of `open64` is documented to have type `mode_t`. On + // some platforms (like macOS, where `open64` is actually `open`), `mode_t` is `u16`. + // However, since this is a variadic function, C integer promotion rules mean that on + // the ABI level, this still gets passed as `c_int` (aka `u32` on Unix platforms). let fd = cvt_r(|| unsafe { open64(path.as_ptr(), flags, opts.mode as c_int) })?; let fd = FileDesc::new(fd); diff --git a/src/libstd/sys/unix/mutex.rs b/src/libstd/sys/unix/mutex.rs index 103d87e3d2f..45c600f75f5 100644 --- a/src/libstd/sys/unix/mutex.rs +++ b/src/libstd/sys/unix/mutex.rs @@ -28,14 +28,20 @@ impl Mutex { // // A pthread mutex initialized with PTHREAD_MUTEX_INITIALIZER will have // a type of PTHREAD_MUTEX_DEFAULT, which has undefined behavior if you - // try to re-lock it from the same thread when you already hold a lock. + // try to re-lock it from the same thread when you already hold a lock + // (https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_mutex_init.html). + // This is the case even if PTHREAD_MUTEX_DEFAULT == PTHREAD_MUTEX_NORMAL + // (https://github.com/rust-lang/rust/issues/33770#issuecomment-220847521) -- in that + // case, `pthread_mutexattr_settype(PTHREAD_MUTEX_DEFAULT)` will of course be the same + // as setting it to `PTHREAD_MUTEX_NORMAL`, but not setting any mode will result in + // a Mutex where re-locking is UB. // // In practice, glibc takes advantage of this undefined behavior to // implement hardware lock elision, which uses hardware transactional // memory to avoid acquiring the lock. While a transaction is in // progress, the lock appears to be unlocked. This isn't a problem for // other threads since the transactional memory will abort if a conflict - // is detected, however no abort is generated if re-locking from the + // is detected, however no abort is generated when re-locking from the // same thread. // // Since locking the same mutex twice will result in two aliasing &mut diff --git a/src/libstd/sys/unix/rwlock.rs b/src/libstd/sys/unix/rwlock.rs index 079dea671ef..2b5067a34f6 100644 --- a/src/libstd/sys/unix/rwlock.rs +++ b/src/libstd/sys/unix/rwlock.rs @@ -22,32 +22,33 @@ impl RWLock { pub unsafe fn read(&self) { let r = libc::pthread_rwlock_rdlock(self.inner.get()); - // According to the pthread_rwlock_rdlock spec, this function **may** - // fail with EDEADLK if a deadlock is detected. On the other hand - // pthread mutexes will *never* return EDEADLK if they are initialized - // as the "fast" kind (which ours always are). As a result, a deadlock - // situation may actually return from the call to pthread_rwlock_rdlock - // instead of blocking forever (as mutexes and Windows rwlocks do). Note - // that not all unix implementations, however, will return EDEADLK for - // their rwlocks. + // According to POSIX, when a thread tries to acquire this read lock + // while it already holds the write lock + // (or vice versa, or tries to acquire the write lock twice), + // "the call shall either deadlock or return [EDEADLK]" + // (https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_rwlock_wrlock.html, + // https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_rwlock_rdlock.html). + // So, in principle, all we have to do here is check `r == 0` to be sure we properly + // got the lock. // - // We roughly maintain the deadlocking behavior by panicking to ensure - // that this lock acquisition does not succeed. - // - // We also check whether this lock is already write locked. This - // is only possible if it was write locked by the current thread and - // the implementation allows recursive locking. The POSIX standard - // doesn't require recursively locking a rwlock to deadlock, but we can't - // allow that because it could lead to aliasing issues. + // However, (at least) glibc before version 2.25 does not conform to this spec, + // and can return `r == 0` even when this thread already holds the write lock. + // We thus check for this situation ourselves and panic when detecting that a thread + // got the write lock more than once, or got a read and a write lock. if r == libc::EAGAIN { panic!("rwlock maximum reader count exceeded"); } else if r == libc::EDEADLK || (r == 0 && *self.write_locked.get()) { + // Above, we make sure to only access `write_locked` when `r == 0` to avoid + // data races. if r == 0 { + // `pthread_rwlock_rdlock` succeeded when it should not have. self.raw_unlock(); } panic!("rwlock read lock would result in deadlock"); } else { - assert_eq!(r, 0); + // According to POSIX, for a properly initialized rwlock this can only + // return EAGAIN or EDEADLK or 0. We rely on that. + debug_assert_eq!(r, 0); self.num_readers.fetch_add(1, Ordering::Relaxed); } } @@ -56,6 +57,7 @@ impl RWLock { let r = libc::pthread_rwlock_tryrdlock(self.inner.get()); if r == 0 { if *self.write_locked.get() { + // `pthread_rwlock_tryrdlock` succeeded when it should not have. self.raw_unlock(); false } else { @@ -69,17 +71,22 @@ impl RWLock { #[inline] pub unsafe fn write(&self) { let r = libc::pthread_rwlock_wrlock(self.inner.get()); - // See comments above for why we check for EDEADLK and write_locked. We - // also need to check that num_readers is 0. + // See comments above for why we check for EDEADLK and write_locked. For the same reason, + // we also need to check that there are no readers (tracked in `num_readers`). if r == libc::EDEADLK - || *self.write_locked.get() + || (r == 0 && *self.write_locked.get()) || self.num_readers.load(Ordering::Relaxed) != 0 { + // Above, we make sure to only access `write_locked` when `r == 0` to avoid + // data races. if r == 0 { + // `pthread_rwlock_wrlock` succeeded when it should not have. self.raw_unlock(); } panic!("rwlock write lock would result in deadlock"); } else { + // According to POSIX, for a properly initialized rwlock this can only + // return EDEADLK or 0. We rely on that. debug_assert_eq!(r, 0); } *self.write_locked.get() = true; @@ -89,6 +96,7 @@ impl RWLock { let r = libc::pthread_rwlock_trywrlock(self.inner.get()); if r == 0 { if *self.write_locked.get() || self.num_readers.load(Ordering::Relaxed) != 0 { + // `pthread_rwlock_trywrlock` succeeded when it should not have. self.raw_unlock(); false } else { diff --git a/src/libunwind/build.rs b/src/libunwind/build.rs index c8d2419ab45..1462639259c 100644 --- a/src/libunwind/build.rs +++ b/src/libunwind/build.rs @@ -89,6 +89,7 @@ mod llvm_libunwind { cfg.flag("-fno-rtti"); cfg.flag("-fstrict-aliasing"); cfg.flag("-funwind-tables"); + cfg.flag("-fvisibility=hidden"); } let mut unwind_sources = vec![ diff --git a/src/test/auxiliary/rust_test_helpers.c b/src/test/auxiliary/rust_test_helpers.c index 897c940149b..92b7dd4b7c5 100644 --- a/src/test/auxiliary/rust_test_helpers.c +++ b/src/test/auxiliary/rust_test_helpers.c @@ -368,6 +368,7 @@ rust_dbg_unpack_option_u64(struct U8TaggedEnumOptionU64 o, uint64_t *into) { return 0; default: assert(0 && "unexpected tag"); + return 0; } } @@ -411,5 +412,6 @@ rust_dbg_unpack_option_u64u64(struct U8TaggedEnumOptionU64U64 o, uint64_t *a, ui return 0; default: assert(0 && "unexpected tag"); + return 0; } } diff --git a/src/test/codegen/ffi-out-of-bounds-loads.rs b/src/test/codegen/ffi-out-of-bounds-loads.rs new file mode 100644 index 00000000000..139a06ab53d --- /dev/null +++ b/src/test/codegen/ffi-out-of-bounds-loads.rs @@ -0,0 +1,25 @@ +// Regression test for #29988 + +// compile-flags: -C no-prepopulate-passes +// only-x86_64 +// ignore-windows + +#[repr(C)] +struct S { + f1: i32, + f2: i32, + f3: i32, +} + +extern { + fn foo(s: S); +} + +fn main() { + let s = S { f1: 1, f2: 2, f3: 3 }; + unsafe { + // CHECK: load { i64, i32 }, { i64, i32 }* {{.*}}, align 4 + // CHECK: call void @foo({ i64, i32 } {{.*}}) + foo(s); + } +} diff --git a/src/test/codegen/force-unwind-tables.rs b/src/test/codegen/force-unwind-tables.rs new file mode 100644 index 00000000000..fbaf38d69df --- /dev/null +++ b/src/test/codegen/force-unwind-tables.rs @@ -0,0 +1,7 @@ +// min-llvm-version 8.0 +// compile-flags: -C no-prepopulate-passes -C force-unwind-tables=y + +#![crate_type="lib"] + +// CHECK: attributes #{{.*}} uwtable +pub fn foo() {} diff --git a/src/test/codegen/unchecked-float-casts.rs b/src/test/codegen/unchecked-float-casts.rs index 34e96122223..789feea12d6 100644 --- a/src/test/codegen/unchecked-float-casts.rs +++ b/src/test/codegen/unchecked-float-casts.rs @@ -1,7 +1,7 @@ -// compile-flags: -C no-prepopulate-passes +// This file tests that we don't generate any code for saturation when using the +// unchecked intrinsics. -// This file tests that we don't generate any code for saturation if -// -Z saturating-float-casts is not enabled. +// compile-flags: -C opt-level=3 #![crate_type = "lib"] @@ -12,7 +12,7 @@ pub fn f32_to_u32(x: f32) -> u32 { // CHECK-NOT: fcmp // CHECK-NOT: icmp // CHECK-NOT: select - x as u32 + unsafe { x.to_int_unchecked() } } // CHECK-LABEL: @f32_to_i32 @@ -22,7 +22,7 @@ pub fn f32_to_i32(x: f32) -> i32 { // CHECK-NOT: fcmp // CHECK-NOT: icmp // CHECK-NOT: select - x as i32 + unsafe { x.to_int_unchecked() } } #[no_mangle] @@ -31,5 +31,5 @@ pub fn f64_to_u16(x: f64) -> u16 { // CHECK-NOT: fcmp // CHECK-NOT: icmp // CHECK-NOT: select - x as u16 + unsafe { x.to_int_unchecked() } } diff --git a/src/test/compile-fail/unwind-tables-panic-required.rs b/src/test/compile-fail/unwind-tables-panic-required.rs new file mode 100644 index 00000000000..314d9e778d5 --- /dev/null +++ b/src/test/compile-fail/unwind-tables-panic-required.rs @@ -0,0 +1,10 @@ +// Tests that the compiler errors if the user tries to turn off unwind tables +// when they are required. +// +// compile-flags: -C panic=unwind -C force-unwind-tables=no +// ignore-tidy-linelength +// +// error-pattern: panic=unwind requires unwind tables, they cannot be disabled with `-C force-unwind-tables=no`. + +pub fn main() { +} diff --git a/src/test/compile-fail/unwind-tables-target-required.rs b/src/test/compile-fail/unwind-tables-target-required.rs new file mode 100644 index 00000000000..14c17893764 --- /dev/null +++ b/src/test/compile-fail/unwind-tables-target-required.rs @@ -0,0 +1,11 @@ +// Tests that the compiler errors if the user tries to turn off unwind tables +// when they are required. +// +// only-x86_64-windows-msvc +// compile-flags: -C force-unwind-tables=no +// ignore-tidy-linelength +// +// error-pattern: target requires unwind tables, they cannot be disabled with `-C force-unwind-tables=no`. + +pub fn main() { +} diff --git a/src/test/mir-opt/const_prop/scalar_literal_propagation/rustc.main.ConstProp.diff b/src/test/mir-opt/const_prop/scalar_literal_propagation/rustc.main.ConstProp.diff index 0183ff7716c..596ddcb4353 100644 --- a/src/test/mir-opt/const_prop/scalar_literal_propagation/rustc.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/scalar_literal_propagation/rustc.main.ConstProp.diff @@ -22,20 +22,27 @@ StorageLive(_2); // scope 1 at $DIR/scalar_literal_propagation.rs:4:5: 4:15 StorageLive(_3); // scope 1 at $DIR/scalar_literal_propagation.rs:4:13: 4:14 - _3 = _1; // scope 1 at $DIR/scalar_literal_propagation.rs:4:13: 4:14 +- _2 = const consume(move _3) -> bb1; // scope 1 at $DIR/scalar_literal_propagation.rs:4:5: 4:15 + _3 = const 1u32; // scope 1 at $DIR/scalar_literal_propagation.rs:4:13: 4:14 -+ // ty::Const + // ty::Const + // + ty: u32 + // + val: Value(Scalar(0x00000001)) + // mir::Constant + // + span: $DIR/scalar_literal_propagation.rs:4:13: 4:14 + // + literal: Const { ty: u32, val: Value(Scalar(0x00000001)) } - _2 = const consume(move _3) -> bb1; // scope 1 at $DIR/scalar_literal_propagation.rs:4:5: 4:15 - // ty::Const ++ _2 = const consume(const 1u32) -> bb1; // scope 1 at $DIR/scalar_literal_propagation.rs:4:5: 4:15 ++ // ty::Const // + ty: fn(u32) {consume} // + val: Value(Scalar(<ZST>)) // mir::Constant // + span: $DIR/scalar_literal_propagation.rs:4:5: 4:12 // + literal: Const { ty: fn(u32) {consume}, val: Value(Scalar(<ZST>)) } ++ // ty::Const ++ // + ty: u32 ++ // + val: Value(Scalar(0x00000001)) ++ // mir::Constant ++ // + span: $DIR/scalar_literal_propagation.rs:4:5: 4:15 ++ // + literal: Const { ty: u32, val: Value(Scalar(0x00000001)) } } bb1: { diff --git a/src/test/mir-opt/simplify-locals-removes-unused-consts/rustc.main.SimplifyLocals.diff b/src/test/mir-opt/simplify-locals-removes-unused-consts/rustc.main.SimplifyLocals.diff index 0742f655730..0bd4ba97b3c 100644 --- a/src/test/mir-opt/simplify-locals-removes-unused-consts/rustc.main.SimplifyLocals.diff +++ b/src/test/mir-opt/simplify-locals-removes-unused-consts/rustc.main.SimplifyLocals.diff @@ -50,6 +50,7 @@ - StorageDead(_2); // scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:13:27: 13:28 - StorageDead(_1); // scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:13:28: 13:29 - StorageLive(_4); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:14:5: 14:22 +- StorageLive(_5); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:14:13: 14:21 - StorageLive(_6); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:14:14: 14:16 - _6 = const (); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:14:14: 14:16 - // ty::Const @@ -66,6 +67,13 @@ - // mir::Constant - // + span: $DIR/simplify-locals-removes-unused-consts.rs:14:18: 14:20 - // + literal: Const { ty: (), val: Value(Scalar(<ZST>)) } +- _5 = const ((), ()); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:14:13: 14:21 +- // ty::Const +- // + ty: ((), ()) +- // + val: Value(Scalar(<ZST>)) +- // mir::Constant +- // + span: $DIR/simplify-locals-removes-unused-consts.rs:14:13: 14:21 +- // + literal: Const { ty: ((), ()), val: Value(Scalar(<ZST>)) } - StorageDead(_7); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:14:20: 14:21 - StorageDead(_6); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:14:20: 14:21 - _4 = const use_zst(const ((), ())) -> bb1; // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:14:5: 14:22 @@ -79,13 +87,15 @@ // + ty: ((), ()) // + val: Value(Scalar(<ZST>)) // mir::Constant - // + span: $DIR/simplify-locals-removes-unused-consts.rs:14:13: 14:21 + // + span: $DIR/simplify-locals-removes-unused-consts.rs:14:5: 14:22 // + literal: Const { ty: ((), ()), val: Value(Scalar(<ZST>)) } } bb1: { +- StorageDead(_5); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:14:21: 14:22 - StorageDead(_4); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:14:22: 14:23 - StorageLive(_8); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:16:5: 16:35 +- StorageLive(_9); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:16:12: 16:34 - StorageLive(_10); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:16:12: 16:30 - StorageLive(_11); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:16:12: 16:28 - _11 = const Temp { x: 40u8 }; // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:16:12: 16:28 @@ -105,6 +115,13 @@ - // mir::Constant - // + span: $DIR/simplify-locals-removes-unused-consts.rs:16:12: 16:30 - // + literal: Const { ty: u8, val: Value(Scalar(0x28)) } +- _9 = const 42u8; // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:16:12: 16:34 +- // ty::Const +- // + ty: u8 +- // + val: Value(Scalar(0x2a)) +- // mir::Constant +- // + span: $DIR/simplify-locals-removes-unused-consts.rs:16:12: 16:34 +- // + literal: Const { ty: u8, val: Value(Scalar(0x2a)) } - StorageDead(_10); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:16:33: 16:34 - _8 = const use_u8(const 42u8) -> bb2; // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:16:5: 16:35 - // ty::Const @@ -117,11 +134,12 @@ // + ty: u8 // + val: Value(Scalar(0x2a)) // mir::Constant - // + span: $DIR/simplify-locals-removes-unused-consts.rs:16:12: 16:34 + // + span: $DIR/simplify-locals-removes-unused-consts.rs:16:5: 16:35 // + literal: Const { ty: u8, val: Value(Scalar(0x2a)) } } bb2: { +- StorageDead(_9); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:16:34: 16:35 - StorageDead(_11); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:16:35: 16:36 - StorageDead(_8); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:16:35: 16:36 + StorageDead(_2); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:16:35: 16:36 diff --git a/src/test/rustdoc/auxiliary/issue-27362.rs b/src/test/rustdoc/auxiliary/issue-27362-aux.rs index 077bdc33e66..077bdc33e66 100644 --- a/src/test/rustdoc/auxiliary/issue-27362.rs +++ b/src/test/rustdoc/auxiliary/issue-27362-aux.rs diff --git a/src/test/rustdoc/const-generics/add-impl.rs b/src/test/rustdoc/const-generics/add-impl.rs index 54bdd768f8a..905f9588268 100644 --- a/src/test/rustdoc/const-generics/add-impl.rs +++ b/src/test/rustdoc/const-generics/add-impl.rs @@ -11,7 +11,7 @@ pub struct Simd<T, const WIDTH: usize> { inner: T, } -// @has foo/struct.Simd.html '//div[@id="implementations-list"]/h3/code' 'impl Add<Simd<u8, 16usize>> for Simd<u8, 16>' +// @has foo/struct.Simd.html '//div[@id="trait-implementations-list"]/h3/code' 'impl Add<Simd<u8, 16usize>> for Simd<u8, 16>' impl Add for Simd<u8, 16> { type Output = Self; diff --git a/src/test/rustdoc/duplicate_impls/issue-33054.rs b/src/test/rustdoc/duplicate_impls/issue-33054.rs index 3f7cec18563..112d632971a 100644 --- a/src/test/rustdoc/duplicate_impls/issue-33054.rs +++ b/src/test/rustdoc/duplicate_impls/issue-33054.rs @@ -1,7 +1,7 @@ // @has issue_33054/impls/struct.Foo.html // @has - '//code' 'impl Foo' // @has - '//code' 'impl Bar for Foo' -// @count - '//*[@id="implementations-list"]/*[@class="impl"]' 1 +// @count - '//*[@id="trait-implementations-list"]/*[@class="impl"]' 1 // @count - '//*[@id="main"]/*[@class="impl"]' 1 // @has issue_33054/impls/bar/trait.Bar.html // @has - '//code' 'impl Bar for Foo' diff --git a/src/test/rustdoc/issue-21474.rs b/src/test/rustdoc/issue-21474.rs index 4c530f72b8a..896fc1a78f1 100644 --- a/src/test/rustdoc/issue-21474.rs +++ b/src/test/rustdoc/issue-21474.rs @@ -7,5 +7,5 @@ mod inner { pub trait Blah { } // @count issue_21474/struct.What.html \ -// '//*[@id="implementations-list"]/*[@class="impl"]' 1 +// '//*[@id="trait-implementations-list"]/*[@class="impl"]' 1 pub struct What; diff --git a/src/test/rustdoc/issue-27362.rs b/src/test/rustdoc/issue-27362.rs index 3f3878350d5..1cbba4b663d 100644 --- a/src/test/rustdoc/issue-27362.rs +++ b/src/test/rustdoc/issue-27362.rs @@ -1,10 +1,10 @@ -// aux-build:issue-27362.rs +// aux-build:issue-27362-aux.rs // ignore-cross-compile -// ignore-test This test fails on beta/stable #32019 -extern crate issue_27362; -pub use issue_27362 as quux; +extern crate issue_27362_aux; -// @matches issue_27362/quux/fn.foo.html '//pre' "pub const fn foo()" -// @matches issue_27362/quux/fn.bar.html '//pre' "pub const unsafe fn bar()" -// @matches issue_27362/quux/struct.Foo.html '//code' "const unsafe fn baz()" +pub use issue_27362_aux::*; + +// @matches issue_27362/fn.foo.html '//pre' "pub const fn foo()" +// @matches issue_27362/fn.bar.html '//pre' "pub const unsafe fn bar()" +// @matches issue_27362/struct.Foo.html '//code' "const unsafe fn baz()" diff --git a/src/test/rustdoc/issue-45584.rs b/src/test/rustdoc/issue-45584.rs index cd8c275d852..0225c0c5c2f 100644 --- a/src/test/rustdoc/issue-45584.rs +++ b/src/test/rustdoc/issue-45584.rs @@ -4,12 +4,12 @@ pub trait Bar<T, U> {} // @has 'foo/struct.Foo1.html' pub struct Foo1; -// @count - '//*[@id="implementations-list"]/*[@class="impl"]' 1 +// @count - '//*[@id="trait-implementations-list"]/*[@class="impl"]' 1 // @has - '//*[@class="impl"]' "impl Bar<Foo1, &'static Foo1> for Foo1" impl Bar<Foo1, &'static Foo1> for Foo1 {} // @has 'foo/struct.Foo2.html' pub struct Foo2; -// @count - '//*[@id="implementations-list"]/*[@class="impl"]' 1 +// @count - '//*[@id="trait-implementations-list"]/*[@class="impl"]' 1 // @has - '//*[@class="impl"]' "impl Bar<&'static Foo2, Foo2> for u8" impl Bar<&'static Foo2, Foo2> for u8 {} diff --git a/src/test/rustdoc/issue-55321.rs b/src/test/rustdoc/issue-55321.rs index 8c001db06c5..d312a511459 100644 --- a/src/test/rustdoc/issue-55321.rs +++ b/src/test/rustdoc/issue-55321.rs @@ -1,8 +1,8 @@ #![feature(negative_impls)] // @has issue_55321/struct.A.html -// @has - '//*[@id="implementations-list"]/*[@class="impl"]//code' "impl !Send for A" -// @has - '//*[@id="implementations-list"]/*[@class="impl"]//code' "impl !Sync for A" +// @has - '//*[@id="trait-implementations-list"]/*[@class="impl"]//code' "impl !Send for A" +// @has - '//*[@id="trait-implementations-list"]/*[@class="impl"]//code' "impl !Sync for A" pub struct A(); impl !Send for A {} diff --git a/src/test/rustdoc/negative-impl-sidebar.rs b/src/test/rustdoc/negative-impl-sidebar.rs index cb46d1778d9..3414d954077 100644 --- a/src/test/rustdoc/negative-impl-sidebar.rs +++ b/src/test/rustdoc/negative-impl-sidebar.rs @@ -4,6 +4,6 @@ pub struct Foo; // @has foo/struct.Foo.html -// @has - '//*[@class="sidebar-title"][@href="#implementations"]' 'Trait Implementations' +// @has - '//*[@class="sidebar-title"][@href="#trait-implementations"]' 'Trait Implementations' // @has - '//*[@class="sidebar-links"]/a' '!Sync' impl !Sync for Foo {} diff --git a/src/test/rustdoc/struct-implementations-title.rs b/src/test/rustdoc/struct-implementations-title.rs new file mode 100644 index 00000000000..96eb11311d6 --- /dev/null +++ b/src/test/rustdoc/struct-implementations-title.rs @@ -0,0 +1,9 @@ +#![crate_name = "foo"] + +pub struct Struc; + +// @has foo/struct.Struc.html +// @has - '//*[@id="main"]/h2[@id="implementations"]' "Implementations" +impl Struc { + pub const S: u64 = 0; +} diff --git a/src/test/rustdoc/synthetic_auto/manual.rs b/src/test/rustdoc/synthetic_auto/manual.rs index 458403462d6..d20b4744af1 100644 --- a/src/test/rustdoc/synthetic_auto/manual.rs +++ b/src/test/rustdoc/synthetic_auto/manual.rs @@ -2,10 +2,10 @@ // @has - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]//code' 'impl<T> Sync for \ // Foo<T> where T: Sync' // -// @has - '//*[@id="implementations-list"]/*[@class="impl"]//code' \ +// @has - '//*[@id="trait-implementations-list"]/*[@class="impl"]//code' \ // 'impl<T> Send for Foo<T>' // -// @count - '//*[@id="implementations-list"]/*[@class="impl"]' 1 +// @count - '//*[@id="trait-implementations-list"]/*[@class="impl"]' 1 // @count - '//*[@id="synthetic-implementations-list"]/*[@class="impl"]' 4 pub struct Foo<T> { field: T, diff --git a/src/test/rustdoc/typedef.rs b/src/test/rustdoc/typedef.rs index 80351ff52f5..7f834d3d5a5 100644 --- a/src/test/rustdoc/typedef.rs +++ b/src/test/rustdoc/typedef.rs @@ -13,8 +13,8 @@ impl MyStruct { // @has - '//*[@class="impl"]//code' 'impl MyTrait for MyAlias' // @has - 'Alias docstring' // @has - '//*[@class="sidebar"]//p[@class="location"]' 'Type Definition MyAlias' -// @has - '//*[@class="sidebar"]//a[@href="#methods"]' 'Methods' -// @has - '//*[@class="sidebar"]//a[@href="#implementations"]' 'Trait Implementations' +// @has - '//*[@class="sidebar"]//a[@href="#implementations"]' 'Methods' +// @has - '//*[@class="sidebar"]//a[@href="#trait-implementations"]' 'Trait Implementations' /// Alias docstring pub type MyAlias = MyStruct; diff --git a/src/test/ui/associated-const/associated-const-generic-obligations.stderr b/src/test/ui/associated-const/associated-const-generic-obligations.stderr index d6cdcd4747f..d8bac07e058 100644 --- a/src/test/ui/associated-const/associated-const-generic-obligations.stderr +++ b/src/test/ui/associated-const/associated-const-generic-obligations.stderr @@ -9,8 +9,6 @@ LL | const FROM: &'static str = "foo"; | = note: expected associated type `<T as Foo>::Out` found reference `&'static str` - = note: consider constraining the associated type `<T as Foo>::Out` to `&'static str` or calling a method that returns `<T as Foo>::Out` - = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html error: aborting due to previous error diff --git a/src/test/ui/associated-types/associated-types-eq-3.stderr b/src/test/ui/associated-types/associated-types-eq-3.stderr index a8608abb4d9..dffa4780a09 100644 --- a/src/test/ui/associated-types/associated-types-eq-3.stderr +++ b/src/test/ui/associated-types/associated-types-eq-3.stderr @@ -8,8 +8,10 @@ LL | let _: Bar = x.boo(); | = note: expected struct `Bar` found associated type `<I as Foo>::A` - = note: consider constraining the associated type `<I as Foo>::A` to `Bar` - = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html +help: consider constraining the associated type `<I as Foo>::A` to `Bar` + | +LL | fn foo2<I: Foo<A = Bar>>(x: I) { + | ^^^^^^^^^ error[E0271]: type mismatch resolving `<isize as Foo>::A == Bar` --> $DIR/associated-types-eq-3.rs:38:5 diff --git a/src/test/ui/associated-types/associated-types-issue-20346.stderr b/src/test/ui/associated-types/associated-types-issue-20346.stderr index 8f2b760840c..db35c1af171 100644 --- a/src/test/ui/associated-types/associated-types-issue-20346.stderr +++ b/src/test/ui/associated-types/associated-types-issue-20346.stderr @@ -12,8 +12,6 @@ LL | is_iterator_of::<Option<T>, _>(&adapter); | = note: expected enum `std::option::Option<T>` found type `T` - = help: type parameters must be constrained to match other types - = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters error: aborting due to previous error diff --git a/src/test/ui/associated-types/associated-types-multiple-types-one-trait.stderr b/src/test/ui/associated-types/associated-types-multiple-types-one-trait.stderr index 4e481411b4d..b8f20d00ff8 100644 --- a/src/test/ui/associated-types/associated-types-multiple-types-one-trait.stderr +++ b/src/test/ui/associated-types/associated-types-multiple-types-one-trait.stderr @@ -9,8 +9,10 @@ LL | fn want_y<T:Foo<Y=i32>>(t: &T) { } | = note: expected type `i32` found associated type `<T as Foo>::Y` - = note: consider constraining the associated type `<T as Foo>::Y` to `i32` - = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html +help: consider constraining the associated type `<T as Foo>::Y` to `i32` + | +LL | fn have_x_want_y<T:Foo<X=u32, Y = i32>>(t: &T) + | ^^^^^^^^^ error[E0271]: type mismatch resolving `<T as Foo>::X == u32` --> $DIR/associated-types-multiple-types-one-trait.rs:18:5 @@ -23,8 +25,10 @@ LL | fn want_x<T:Foo<X=u32>>(t: &T) { } | = note: expected type `u32` found associated type `<T as Foo>::X` - = note: consider constraining the associated type `<T as Foo>::X` to `u32` - = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html +help: consider constraining the associated type `<T as Foo>::X` to `u32` + | +LL | fn have_y_want_x<T:Foo<Y=i32, X = u32>>(t: &T) + | ^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/associated-types/associated-types-overridden-binding.stderr b/src/test/ui/associated-types/associated-types-overridden-binding.stderr index 3aed85645ae..b8321ce5b25 100644 --- a/src/test/ui/associated-types/associated-types-overridden-binding.stderr +++ b/src/test/ui/associated-types/associated-types-overridden-binding.stderr @@ -1,22 +1,18 @@ -error[E0284]: type annotations needed +error[E0284]: type annotations needed: cannot satisfy `<Self as std::iter::Iterator>::Item == i32` --> $DIR/associated-types-overridden-binding.rs:4:12 | LL | trait Foo: Iterator<Item = i32> {} | ---------- required by this bound in `Foo` LL | trait Bar: Foo<Item = u32> {} - | ^^^^^^^^^^^^^^^ cannot infer type for type parameter `Self` - | - = note: cannot satisfy `<Self as std::iter::Iterator>::Item == i32` + | ^^^^^^^^^^^^^^^ cannot satisfy `<Self as std::iter::Iterator>::Item == i32` -error[E0284]: type annotations needed +error[E0284]: type annotations needed: cannot satisfy `<Self as std::iter::Iterator>::Item == i32` --> $DIR/associated-types-overridden-binding.rs:7:21 | LL | trait I32Iterator = Iterator<Item = i32>; | ---------- required by this bound in `I32Iterator` LL | trait U32Iterator = I32Iterator<Item = u32>; - | ^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type for type parameter `Self` - | - = note: cannot satisfy `<Self as std::iter::Iterator>::Item == i32` + | ^^^^^^^^^^^^^^^^^^^^^^^ cannot satisfy `<Self as std::iter::Iterator>::Item == i32` error: aborting due to 2 previous errors diff --git a/src/test/ui/associated-types/defaults-in-other-trait-items.rs b/src/test/ui/associated-types/defaults-in-other-trait-items.rs index 9f2e8aca477..4014f46285d 100644 --- a/src/test/ui/associated-types/defaults-in-other-trait-items.rs +++ b/src/test/ui/associated-types/defaults-in-other-trait-items.rs @@ -3,15 +3,13 @@ // Associated type defaults may not be assumed inside the trait defining them. // ie. they only resolve to `<Self as Tr>::A`, not the actual type `()` trait Tr { - type A = (); + type A = (); //~ NOTE associated type defaults can't be assumed inside the trait defining them fn f(p: Self::A) { let () = p; //~^ ERROR mismatched types //~| NOTE expected associated type, found `()` //~| NOTE expected associated type `<Self as Tr>::A` - //~| NOTE consider constraining the associated type - //~| NOTE for more information, visit } } @@ -31,15 +29,13 @@ impl Tr for u8 { } trait AssocConst { - type Ty = u8; + type Ty = u8; //~ NOTE associated type defaults can't be assumed inside the trait defining them // Assoc. consts also cannot assume that default types hold const C: Self::Ty = 0u8; //~^ ERROR mismatched types //~| NOTE expected associated type, found `u8` //~| NOTE expected associated type `<Self as AssocConst>::Ty` - //~| NOTE consider constraining the associated type - //~| NOTE for more information, visit } // An impl can, however diff --git a/src/test/ui/associated-types/defaults-in-other-trait-items.stderr b/src/test/ui/associated-types/defaults-in-other-trait-items.stderr index 9ecfe49c2b5..493df30a64d 100644 --- a/src/test/ui/associated-types/defaults-in-other-trait-items.stderr +++ b/src/test/ui/associated-types/defaults-in-other-trait-items.stderr @@ -1,24 +1,26 @@ error[E0308]: mismatched types --> $DIR/defaults-in-other-trait-items.rs:9:13 | +LL | type A = (); + | ------------ associated type defaults can't be assumed inside the trait defining them +... LL | let () = p; | ^^ expected associated type, found `()` | = note: expected associated type `<Self as Tr>::A` found unit type `()` - = note: consider constraining the associated type `<Self as Tr>::A` to `()` or calling a method that returns `<Self as Tr>::A` - = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html error[E0308]: mismatched types - --> $DIR/defaults-in-other-trait-items.rs:37:25 + --> $DIR/defaults-in-other-trait-items.rs:35:25 | +LL | type Ty = u8; + | ------------- associated type defaults can't be assumed inside the trait defining them +... LL | const C: Self::Ty = 0u8; | ^^^ expected associated type, found `u8` | = note: expected associated type `<Self as AssocConst>::Ty` found type `u8` - = note: consider constraining the associated type `<Self as AssocConst>::Ty` to `u8` or calling a method that returns `<Self as AssocConst>::Ty` - = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html error: aborting due to 2 previous errors diff --git a/src/test/ui/associated-types/defaults-specialization.stderr b/src/test/ui/associated-types/defaults-specialization.stderr index 1dd536ec636..37a4d9b60fd 100644 --- a/src/test/ui/associated-types/defaults-specialization.stderr +++ b/src/test/ui/associated-types/defaults-specialization.stderr @@ -9,8 +9,6 @@ LL | fn make() -> u8 { 0 } | = note: expected fn pointer `fn() -> <A<T> as Tr>::Ty` found fn pointer `fn() -> u8` - = note: consider constraining the associated type `<A<T> as Tr>::Ty` to `u8` or calling a method that returns `<A<T> as Tr>::Ty` - = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html error[E0053]: method `make` has an incompatible type for trait --> $DIR/defaults-specialization.rs:34:18 @@ -18,17 +16,21 @@ error[E0053]: method `make` has an incompatible type for trait LL | fn make() -> Self::Ty { | -------- type in trait ... +LL | default type Ty = bool; + | ----------------------- expected this associated type +LL | LL | fn make() -> bool { true } | ^^^^ expected associated type, found `bool` | = note: expected fn pointer `fn() -> <B<T> as Tr>::Ty` found fn pointer `fn() -> bool` - = note: consider constraining the associated type `<B<T> as Tr>::Ty` to `bool` or calling a method that returns `<B<T> as Tr>::Ty` - = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html error[E0308]: mismatched types --> $DIR/defaults-specialization.rs:9:9 | +LL | type Ty = u8; + | ------------- associated type defaults can't be assumed inside the trait defining them +LL | LL | fn make() -> Self::Ty { | -------- expected `<Self as Tr>::Ty` because of return type LL | 0u8 @@ -36,8 +38,6 @@ LL | 0u8 | = note: expected associated type `<Self as Tr>::Ty` found type `u8` - = note: consider constraining the associated type `<Self as Tr>::Ty` to `u8` or calling a method that returns `<Self as Tr>::Ty` - = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html error[E0308]: mismatched types --> $DIR/defaults-specialization.rs:25:29 @@ -49,12 +49,15 @@ LL | fn make() -> Self::Ty { 0u8 } | = note: expected associated type `<A2<T> as Tr>::Ty` found type `u8` - = note: consider constraining the associated type `<A2<T> as Tr>::Ty` to `u8` or calling a method that returns `<A2<T> as Tr>::Ty` + = help: consider constraining the associated type `<A2<T> as Tr>::Ty` to `u8` or calling a method that returns `<A2<T> as Tr>::Ty` = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html error[E0308]: mismatched types --> $DIR/defaults-specialization.rs:43:29 | +LL | default type Ty = bool; + | ----------------------- expected this associated type +LL | LL | fn make() -> Self::Ty { true } | -------- ^^^^ expected associated type, found `bool` | | @@ -62,8 +65,6 @@ LL | fn make() -> Self::Ty { true } | = note: expected associated type `<B2<T> as Tr>::Ty` found type `bool` - = note: consider constraining the associated type `<B2<T> as Tr>::Ty` to `bool` or calling a method that returns `<B2<T> as Tr>::Ty` - = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html error[E0308]: mismatched types --> $DIR/defaults-specialization.rs:86:32 @@ -75,8 +76,11 @@ LL | let _: <B<()> as Tr>::Ty = 0u8; | = note: expected associated type `<B<()> as Tr>::Ty` found type `u8` - = note: consider constraining the associated type `<B<()> as Tr>::Ty` to `u8` or calling a method that returns `<B<()> as Tr>::Ty` - = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html +help: a method is available that returns `<B<()> as Tr>::Ty` + --> $DIR/defaults-specialization.rs:8:5 + | +LL | fn make() -> Self::Ty { + | ^^^^^^^^^^^^^^^^^^^^^ consider calling `Tr::make` error[E0308]: mismatched types --> $DIR/defaults-specialization.rs:87:32 @@ -88,8 +92,11 @@ LL | let _: <B<()> as Tr>::Ty = true; | = note: expected associated type `<B<()> as Tr>::Ty` found type `bool` - = note: consider constraining the associated type `<B<()> as Tr>::Ty` to `bool` or calling a method that returns `<B<()> as Tr>::Ty` - = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html +help: a method is available that returns `<B<()> as Tr>::Ty` + --> $DIR/defaults-specialization.rs:8:5 + | +LL | fn make() -> Self::Ty { + | ^^^^^^^^^^^^^^^^^^^^^ consider calling `Tr::make` error[E0308]: mismatched types --> $DIR/defaults-specialization.rs:88:33 @@ -101,8 +108,11 @@ LL | let _: <B2<()> as Tr>::Ty = 0u8; | = note: expected associated type `<B2<()> as Tr>::Ty` found type `u8` - = note: consider constraining the associated type `<B2<()> as Tr>::Ty` to `u8` or calling a method that returns `<B2<()> as Tr>::Ty` - = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html +help: a method is available that returns `<B2<()> as Tr>::Ty` + --> $DIR/defaults-specialization.rs:8:5 + | +LL | fn make() -> Self::Ty { + | ^^^^^^^^^^^^^^^^^^^^^ consider calling `Tr::make` error[E0308]: mismatched types --> $DIR/defaults-specialization.rs:89:33 @@ -114,8 +124,11 @@ LL | let _: <B2<()> as Tr>::Ty = true; | = note: expected associated type `<B2<()> as Tr>::Ty` found type `bool` - = note: consider constraining the associated type `<B2<()> as Tr>::Ty` to `bool` or calling a method that returns `<B2<()> as Tr>::Ty` - = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html +help: a method is available that returns `<B2<()> as Tr>::Ty` + --> $DIR/defaults-specialization.rs:8:5 + | +LL | fn make() -> Self::Ty { + | ^^^^^^^^^^^^^^^^^^^^^ consider calling `Tr::make` error: aborting due to 9 previous errors diff --git a/src/test/ui/associated-types/impl-trait-return-missing-constraint.rs b/src/test/ui/associated-types/impl-trait-return-missing-constraint.rs new file mode 100644 index 00000000000..5f994f26534 --- /dev/null +++ b/src/test/ui/associated-types/impl-trait-return-missing-constraint.rs @@ -0,0 +1,32 @@ +trait Foo { + type Item; +} + +trait Bar: Foo {} + +struct S; + +impl Foo for S { + type Item = i32; +} +impl Bar for S {} + +struct T; + +impl Foo for T { + type Item = u32; +} +impl Bar for T {} + +fn bar() -> impl Bar { + T +} + +fn baz() -> impl Bar<Item = i32> { +//~^ ERROR type mismatch resolving `<impl Bar as Foo>::Item == i32` + bar() +} + +fn main() { + let _ = baz(); +} diff --git a/src/test/ui/associated-types/impl-trait-return-missing-constraint.stderr b/src/test/ui/associated-types/impl-trait-return-missing-constraint.stderr new file mode 100644 index 00000000000..566e390a31e --- /dev/null +++ b/src/test/ui/associated-types/impl-trait-return-missing-constraint.stderr @@ -0,0 +1,20 @@ +error[E0271]: type mismatch resolving `<impl Bar as Foo>::Item == i32` + --> $DIR/impl-trait-return-missing-constraint.rs:25:13 + | +LL | fn bar() -> impl Bar { + | -------- the expected opaque type +... +LL | fn baz() -> impl Bar<Item = i32> { + | ^^^^^^^^^^^^^^^^^^^^ expected associated type, found `i32` + | + = note: expected associated type `<impl Bar as Foo>::Item` + found type `i32` + = note: the return type of a function must have a statically known size +help: consider constraining the associated type `<impl Bar as Foo>::Item` to `i32` + | +LL | fn bar() -> impl Bar<Item = i32> { + | ^^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0271`. diff --git a/src/test/ui/associated-types/issue-26681.stderr b/src/test/ui/associated-types/issue-26681.stderr index da10933df92..74411008c9d 100644 --- a/src/test/ui/associated-types/issue-26681.stderr +++ b/src/test/ui/associated-types/issue-26681.stderr @@ -6,7 +6,7 @@ LL | const C: <Self::Fv as Foo>::Bar = 6665; | = note: expected associated type `<<Self as Baz>::Fv as Foo>::Bar` found type `{integer}` - = note: consider constraining the associated type `<<Self as Baz>::Fv as Foo>::Bar` to `{integer}` or calling a method that returns `<<Self as Baz>::Fv as Foo>::Bar` + = help: consider constraining the associated type `<<Self as Baz>::Fv as Foo>::Bar` to `{integer}` = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html error: aborting due to previous error diff --git a/src/test/ui/async-await/edition-deny-async-fns-2015.stderr b/src/test/ui/async-await/edition-deny-async-fns-2015.stderr index f3d982801bb..8bffeb2131d 100644 --- a/src/test/ui/async-await/edition-deny-async-fns-2015.stderr +++ b/src/test/ui/async-await/edition-deny-async-fns-2015.stderr @@ -2,9 +2,8 @@ error[E0670]: `async fn` is not permitted in the 2015 edition --> $DIR/edition-deny-async-fns-2015.rs:3:1 | LL | async fn foo() {} - | ^^^^^ + | ^^^^^ to use `async fn`, switch to Rust 2018 | - = note: to use `async fn`, switch to Rust 2018 = help: set `edition = "2018"` in `Cargo.toml` = note: for more on editions, read https://doc.rust-lang.org/edition-guide @@ -12,9 +11,8 @@ error[E0670]: `async fn` is not permitted in the 2015 edition --> $DIR/edition-deny-async-fns-2015.rs:5:12 | LL | fn baz() { async fn foo() {} } - | ^^^^^ + | ^^^^^ to use `async fn`, switch to Rust 2018 | - = note: to use `async fn`, switch to Rust 2018 = help: set `edition = "2018"` in `Cargo.toml` = note: for more on editions, read https://doc.rust-lang.org/edition-guide @@ -22,9 +20,8 @@ error[E0670]: `async fn` is not permitted in the 2015 edition --> $DIR/edition-deny-async-fns-2015.rs:7:1 | LL | async fn async_baz() { - | ^^^^^ + | ^^^^^ to use `async fn`, switch to Rust 2018 | - = note: to use `async fn`, switch to Rust 2018 = help: set `edition = "2018"` in `Cargo.toml` = note: for more on editions, read https://doc.rust-lang.org/edition-guide @@ -32,9 +29,8 @@ error[E0670]: `async fn` is not permitted in the 2015 edition --> $DIR/edition-deny-async-fns-2015.rs:8:5 | LL | async fn bar() {} - | ^^^^^ + | ^^^^^ to use `async fn`, switch to Rust 2018 | - = note: to use `async fn`, switch to Rust 2018 = help: set `edition = "2018"` in `Cargo.toml` = note: for more on editions, read https://doc.rust-lang.org/edition-guide @@ -42,9 +38,8 @@ error[E0670]: `async fn` is not permitted in the 2015 edition --> $DIR/edition-deny-async-fns-2015.rs:14:5 | LL | async fn foo() {} - | ^^^^^ + | ^^^^^ to use `async fn`, switch to Rust 2018 | - = note: to use `async fn`, switch to Rust 2018 = help: set `edition = "2018"` in `Cargo.toml` = note: for more on editions, read https://doc.rust-lang.org/edition-guide @@ -52,9 +47,8 @@ error[E0670]: `async fn` is not permitted in the 2015 edition --> $DIR/edition-deny-async-fns-2015.rs:18:5 | LL | async fn foo() {} - | ^^^^^ + | ^^^^^ to use `async fn`, switch to Rust 2018 | - = note: to use `async fn`, switch to Rust 2018 = help: set `edition = "2018"` in `Cargo.toml` = note: for more on editions, read https://doc.rust-lang.org/edition-guide @@ -62,9 +56,8 @@ error[E0670]: `async fn` is not permitted in the 2015 edition --> $DIR/edition-deny-async-fns-2015.rs:36:9 | LL | async fn bar() {} - | ^^^^^ + | ^^^^^ to use `async fn`, switch to Rust 2018 | - = note: to use `async fn`, switch to Rust 2018 = help: set `edition = "2018"` in `Cargo.toml` = note: for more on editions, read https://doc.rust-lang.org/edition-guide @@ -72,9 +65,8 @@ error[E0670]: `async fn` is not permitted in the 2015 edition --> $DIR/edition-deny-async-fns-2015.rs:26:9 | LL | async fn foo() {} - | ^^^^^ + | ^^^^^ to use `async fn`, switch to Rust 2018 | - = note: to use `async fn`, switch to Rust 2018 = help: set `edition = "2018"` in `Cargo.toml` = note: for more on editions, read https://doc.rust-lang.org/edition-guide @@ -82,9 +74,8 @@ error[E0670]: `async fn` is not permitted in the 2015 edition --> $DIR/edition-deny-async-fns-2015.rs:31:13 | LL | async fn bar() {} - | ^^^^^ + | ^^^^^ to use `async fn`, switch to Rust 2018 | - = note: to use `async fn`, switch to Rust 2018 = help: set `edition = "2018"` in `Cargo.toml` = note: for more on editions, read https://doc.rust-lang.org/edition-guide diff --git a/src/test/ui/binding/ambiguity-item.rs b/src/test/ui/binding/ambiguity-item.rs index 10613cc6164..0f48340c2cd 100644 --- a/src/test/ui/binding/ambiguity-item.rs +++ b/src/test/ui/binding/ambiguity-item.rs @@ -14,5 +14,6 @@ fn main() { let v = f; //~ ERROR `f` is ambiguous match v { f => {} //~ ERROR `f` is ambiguous + mut f => {} // OK, unambiguously a fresh binding due to `mut` } } diff --git a/src/test/ui/borrowck/move-error-in-promoted-2.rs b/src/test/ui/borrowck/move-error-in-promoted-2.rs new file mode 100644 index 00000000000..13da34f3922 --- /dev/null +++ b/src/test/ui/borrowck/move-error-in-promoted-2.rs @@ -0,0 +1,10 @@ +// Regression test for #70934 + +struct S; + +fn foo() { + &([S][0],); + //~^ ERROR cannot move out of type `[S; 1]` +} + +fn main() {} diff --git a/src/test/ui/borrowck/move-error-in-promoted-2.stderr b/src/test/ui/borrowck/move-error-in-promoted-2.stderr new file mode 100644 index 00000000000..38dba94bdd4 --- /dev/null +++ b/src/test/ui/borrowck/move-error-in-promoted-2.stderr @@ -0,0 +1,12 @@ +error[E0508]: cannot move out of type `[S; 1]`, a non-copy array + --> $DIR/move-error-in-promoted-2.rs:6:7 + | +LL | &([S][0],); + | ^^^^^^ + | | + | cannot move out of here + | move occurs because value has type `S`, which does not implement the `Copy` trait + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0508`. diff --git a/src/test/ui/borrowck/move-error-in-promoted.rs b/src/test/ui/borrowck/move-error-in-promoted.rs new file mode 100644 index 00000000000..b94db645131 --- /dev/null +++ b/src/test/ui/borrowck/move-error-in-promoted.rs @@ -0,0 +1,17 @@ +// Regression test for #70934 + +fn f() { + const C: [S2; 1] = [S2]; + let _ = S1(C[0]).clone(); + //~^ ERROR cannot move out of type `[S2; 1]` +} + +#[derive(Clone)] +struct S1(S2); + +#[derive(Clone)] +struct S2; + +fn main() { + f(); +} diff --git a/src/test/ui/borrowck/move-error-in-promoted.stderr b/src/test/ui/borrowck/move-error-in-promoted.stderr new file mode 100644 index 00000000000..a4432e38da0 --- /dev/null +++ b/src/test/ui/borrowck/move-error-in-promoted.stderr @@ -0,0 +1,12 @@ +error[E0508]: cannot move out of type `[S2; 1]`, a non-copy array + --> $DIR/move-error-in-promoted.rs:5:16 + | +LL | let _ = S1(C[0]).clone(); + | ^^^^ + | | + | cannot move out of here + | move occurs because value has type `S2`, which does not implement the `Copy` trait + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0508`. diff --git a/src/test/ui/check-static-values-constraints.stderr b/src/test/ui/check-static-values-constraints.stderr index 7d7ecbd1a26..6b5a739899c 100644 --- a/src/test/ui/check-static-values-constraints.stderr +++ b/src/test/ui/check-static-values-constraints.stderr @@ -18,6 +18,8 @@ error[E0019]: static contains unimplemented expression type | LL | static STATIC11: Box<MyOwned> = box MyOwned; | ^^^^^^^ + | + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable error[E0015]: calls in statics are limited to constant functions, tuple structs and tuple variants --> $DIR/check-static-values-constraints.rs:90:32 @@ -36,6 +38,8 @@ error[E0019]: static contains unimplemented expression type | LL | box MyOwned, | ^^^^^^^ + | + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable error[E0010]: allocations are not allowed in statics --> $DIR/check-static-values-constraints.rs:97:5 @@ -48,6 +52,8 @@ error[E0019]: static contains unimplemented expression type | LL | box MyOwned, | ^^^^^^^ + | + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable error[E0010]: allocations are not allowed in statics --> $DIR/check-static-values-constraints.rs:102:6 @@ -60,6 +66,8 @@ error[E0019]: static contains unimplemented expression type | LL | &box MyOwned, | ^^^^^^^ + | + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable error[E0010]: allocations are not allowed in statics --> $DIR/check-static-values-constraints.rs:104:6 @@ -72,6 +80,8 @@ error[E0019]: static contains unimplemented expression type | LL | &box MyOwned, | ^^^^^^^ + | + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable error[E0010]: allocations are not allowed in statics --> $DIR/check-static-values-constraints.rs:111:5 @@ -84,6 +94,8 @@ error[E0019]: static contains unimplemented expression type | LL | box 3; | ^ + | + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable error[E0507]: cannot move out of static item `x` --> $DIR/check-static-values-constraints.rs:116:45 @@ -105,6 +117,8 @@ error[E0019]: static contains unimplemented expression type | LL | let y = { static x: Box<isize> = box 3; x }; | ^ + | + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable error: aborting due to 17 previous errors diff --git a/src/test/ui/class-missing-self.stderr b/src/test/ui/class-missing-self.stderr index 681d0ffea8b..d501200d73c 100644 --- a/src/test/ui/class-missing-self.stderr +++ b/src/test/ui/class-missing-self.stderr @@ -10,7 +10,7 @@ error[E0425]: cannot find function `sleep` in this scope LL | sleep(); | ^^^^^ not found in this scope | -help: possible candidate is found in another module, you can import it into scope +help: consider importing this function | LL | use std::thread::sleep; | diff --git a/src/test/ui/collections-const-new.rs b/src/test/ui/collections-const-new.rs index a93f9a136db..978f25f9a93 100644 --- a/src/test/ui/collections-const-new.rs +++ b/src/test/ui/collections-const-new.rs @@ -3,9 +3,18 @@ // Test several functions can be used for constants // 1. Vec::new() // 2. String::new() +// 3. BTreeMap::new() +// 4. BTreeSet::new() + +#![feature(const_btree_new)] const MY_VEC: Vec<usize> = Vec::new(); const MY_STRING: String = String::new(); +use std::collections::{BTreeMap, BTreeSet}; +const MY_BTREEMAP: BTreeMap<u32, u32> = BTreeMap::new(); + +const MY_BTREESET: BTreeSet<u32> = BTreeSet::new(); + fn main() {} diff --git a/src/test/ui/const-generics/issues/issue-63322-forbid-dyn.rs b/src/test/ui/const-generics/issues/issue-63322-forbid-dyn.rs new file mode 100644 index 00000000000..2bacd6c9a9c --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-63322-forbid-dyn.rs @@ -0,0 +1,15 @@ +#![feature(const_generics)] +//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash + +trait A {} +struct B; +impl A for B {} + +fn test<const T: &'static dyn A>() { + //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` to be used + unimplemented!() +} + +fn main() { + test::<{ &B }>(); +} diff --git a/src/test/ui/const-generics/issues/issue-63322-forbid-dyn.stderr b/src/test/ui/const-generics/issues/issue-63322-forbid-dyn.stderr new file mode 100644 index 00000000000..c3db6c65a8f --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-63322-forbid-dyn.stderr @@ -0,0 +1,17 @@ +warning: the feature `const_generics` is incomplete and may cause the compiler to crash + --> $DIR/issue-63322-forbid-dyn.rs:1:12 + | +LL | #![feature(const_generics)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + +error[E0741]: `&'static (dyn A + 'static)` must be annotated with `#[derive(PartialEq, Eq)]` to be used as the type of a const parameter + --> $DIR/issue-63322-forbid-dyn.rs:8:18 + | +LL | fn test<const T: &'static dyn A>() { + | ^^^^^^^^^^^^^^ `&'static (dyn A + 'static)` doesn't derive both `PartialEq` and `Eq` + +error: aborting due to previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0741`. diff --git a/src/test/ui/const-generics/trait-const-args.rs b/src/test/ui/const-generics/trait-const-args.rs new file mode 100644 index 00000000000..b60d7e89651 --- /dev/null +++ b/src/test/ui/const-generics/trait-const-args.rs @@ -0,0 +1,29 @@ +// check-pass +#![allow(incomplete_features)] +#![feature(const_generics)] + +struct Const<const N: usize>; +trait Foo<const N: usize> {} + +impl<const N: usize> Foo<N> for Const<N> {} + +fn foo_impl(_: impl Foo<3>) {} + +fn foo_explicit<T: Foo<3>>(_: T) {} + +fn foo_where<T>(_: T) +where + T: Foo<3>, +{ +} + +fn main() { + foo_impl(Const); + foo_impl(Const::<3>); + + foo_explicit(Const); + foo_explicit(Const::<3>); + + foo_where(Const); + foo_where(Const::<3>); +} diff --git a/src/test/ui/const-suggest-feature.rs b/src/test/ui/const-suggest-feature.rs new file mode 100644 index 00000000000..89fafbbe6f0 --- /dev/null +++ b/src/test/ui/const-suggest-feature.rs @@ -0,0 +1,9 @@ +const WRITE: () = unsafe { + *std::ptr::null_mut() = 0; + //~^ ERROR dereferencing raw pointers in constants is unstable + //~| HELP add `#![feature(const_raw_ptr_deref)]` to the crate attributes to enable + //~| ERROR constant contains unimplemented expression type + //~| HELP add `#![feature(const_mut_refs)]` to the crate attributes to enable +}; + +fn main() {} diff --git a/src/test/ui/const-suggest-feature.stderr b/src/test/ui/const-suggest-feature.stderr new file mode 100644 index 00000000000..6b91df6b42d --- /dev/null +++ b/src/test/ui/const-suggest-feature.stderr @@ -0,0 +1,21 @@ +error[E0658]: dereferencing raw pointers in constants is unstable + --> $DIR/const-suggest-feature.rs:2:5 + | +LL | *std::ptr::null_mut() = 0; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #51911 <https://github.com/rust-lang/rust/issues/51911> for more information + = help: add `#![feature(const_raw_ptr_deref)]` to the crate attributes to enable + +error[E0019]: constant contains unimplemented expression type + --> $DIR/const-suggest-feature.rs:2:5 + | +LL | *std::ptr::null_mut() = 0; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0019, E0658. +For more information about an error, try `rustc --explain E0019`. diff --git a/src/test/ui/consts/const-eval/assign-to-static-within-other-static-2.stderr b/src/test/ui/consts/const-eval/assign-to-static-within-other-static-2.stderr index 148b1210d39..14dcc074639 100644 --- a/src/test/ui/consts/const-eval/assign-to-static-within-other-static-2.stderr +++ b/src/test/ui/consts/const-eval/assign-to-static-within-other-static-2.stderr @@ -3,6 +3,8 @@ error[E0019]: static contains unimplemented expression type | LL | *FOO.0.get() = 5; | ^^^^^^^^^^^^^^^^ + | + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/consts/const-eval/mod-static-with-const-fn.stderr b/src/test/ui/consts/const-eval/mod-static-with-const-fn.stderr index 50cd3214507..44ae1ecf047 100644 --- a/src/test/ui/consts/const-eval/mod-static-with-const-fn.stderr +++ b/src/test/ui/consts/const-eval/mod-static-with-const-fn.stderr @@ -3,6 +3,8 @@ error[E0019]: static contains unimplemented expression type | LL | *FOO.0.get() = 5; | ^^^^^^^^^^^^^^^^ + | + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable error[E0015]: calls in statics are limited to constant functions, tuple structs and tuple variants --> $DIR/mod-static-with-const-fn.rs:21:5 diff --git a/src/test/ui/consts/const-eval/ub-wide-ptr.rs b/src/test/ui/consts/const-eval/ub-wide-ptr.rs index 0200bfe9f08..29ac32fcf22 100644 --- a/src/test/ui/consts/const-eval/ub-wide-ptr.rs +++ b/src/test/ui/consts/const-eval/ub-wide-ptr.rs @@ -104,6 +104,14 @@ const TRAIT_OBJ_SHORT_VTABLE_2: &dyn Trait = unsafe { mem::transmute((&92u8, &3u // bad trait object const TRAIT_OBJ_INT_VTABLE: &dyn Trait = unsafe { mem::transmute((&92u8, 4usize)) }; //~^ ERROR it is undefined behavior to use this value +const TRAIT_OBJ_UNALIGNED_VTABLE: &dyn Trait = unsafe { mem::transmute((&92u8, &[0u8; 128])) }; +//~^ ERROR it is undefined behavior to use this value +const TRAIT_OBJ_BAD_DROP_FN_NULL: &dyn Trait = unsafe { mem::transmute((&92u8, &[0usize; 8])) }; +//~^ ERROR it is undefined behavior to use this value +const TRAIT_OBJ_BAD_DROP_FN_INT: &dyn Trait = unsafe { mem::transmute((&92u8, &[1usize; 8])) }; +//~^ ERROR it is undefined behavior to use this value +const TRAIT_OBJ_BAD_DROP_FN_NOT_FN_PTR: &dyn Trait = unsafe { mem::transmute((&92u8, &[&42u8; 8])) }; +//~^ ERROR it is undefined behavior to use this value // bad data *inside* the trait object const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = unsafe { mem::transmute::<_, &bool>(&3u8) }; diff --git a/src/test/ui/consts/const-eval/ub-wide-ptr.stderr b/src/test/ui/consts/const-eval/ub-wide-ptr.stderr index e56459a7bde..063ea81036b 100644 --- a/src/test/ui/consts/const-eval/ub-wide-ptr.stderr +++ b/src/test/ui/consts/const-eval/ub-wide-ptr.stderr @@ -138,7 +138,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-wide-ptr.rs:99:1 | LL | const TRAIT_OBJ_SHORT_VTABLE_1: &dyn Trait = unsafe { mem::transmute((&92u8, &3u8)) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered dangling or unaligned vtable pointer in wide pointer or too small vtable + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered too small vtable | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. @@ -146,7 +146,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-wide-ptr.rs:102:1 | LL | const TRAIT_OBJ_SHORT_VTABLE_2: &dyn Trait = unsafe { mem::transmute((&92u8, &3u64)) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered dangling or unaligned vtable pointer in wide pointer or too small vtable + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered too small vtable | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. @@ -154,46 +154,78 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-wide-ptr.rs:105:1 | LL | const TRAIT_OBJ_INT_VTABLE: &dyn Trait = unsafe { mem::transmute((&92u8, 4usize)) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered dangling or unaligned vtable pointer in wide pointer or too small vtable + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered dangling vtable pointer in wide pointer + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-wide-ptr.rs:107:1 + | +LL | const TRAIT_OBJ_UNALIGNED_VTABLE: &dyn Trait = unsafe { mem::transmute((&92u8, &[0u8; 128])) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered unaligned vtable pointer in wide pointer | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value --> $DIR/ub-wide-ptr.rs:109:1 | +LL | const TRAIT_OBJ_BAD_DROP_FN_NULL: &dyn Trait = unsafe { mem::transmute((&92u8, &[0usize; 8])) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered invalid drop function pointer in vtable (not pointing to a function) + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-wide-ptr.rs:111:1 + | +LL | const TRAIT_OBJ_BAD_DROP_FN_INT: &dyn Trait = unsafe { mem::transmute((&92u8, &[1usize; 8])) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered invalid drop function pointer in vtable (not pointing to a function) + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-wide-ptr.rs:113:1 + | +LL | const TRAIT_OBJ_BAD_DROP_FN_NOT_FN_PTR: &dyn Trait = unsafe { mem::transmute((&92u8, &[&42u8; 8])) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered invalid drop function pointer in vtable (not pointing to a function) + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-wide-ptr.rs:117:1 + | LL | const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = unsafe { mem::transmute::<_, &bool>(&3u8) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0x03 at .<deref>.<dyn-downcast>, but expected a boolean | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:113:1 + --> $DIR/ub-wide-ptr.rs:121:1 | LL | const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { mem::transmute((&92u8, 0usize)) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered dangling or unaligned vtable pointer in wide pointer or too small vtable + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered dangling vtable pointer in wide pointer | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:115:1 + --> $DIR/ub-wide-ptr.rs:123:1 | LL | const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { mem::transmute((&92u8, &3u64)) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered dangling or unaligned vtable pointer in wide pointer or too small vtable + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered too small vtable | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: could not evaluate static initializer - --> $DIR/ub-wide-ptr.rs:121:5 + --> $DIR/ub-wide-ptr.rs:129:5 | LL | mem::transmute::<_, &dyn Trait>((&92u8, 0usize)) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ inbounds test failed: 0x0 is not a valid pointer error[E0080]: could not evaluate static initializer - --> $DIR/ub-wide-ptr.rs:125:5 + --> $DIR/ub-wide-ptr.rs:133:5 | LL | mem::transmute::<_, &dyn Trait>((&92u8, &3u64)) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: pointer must be in-bounds at offset N, but is outside bounds of allocN which has size N -error: aborting due to 24 previous errors +error: aborting due to 28 previous errors For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/ui/consts/const_let_assign3.stderr b/src/test/ui/consts/const_let_assign3.stderr index 5e2a85cc03d..62fd04ea522 100644 --- a/src/test/ui/consts/const_let_assign3.stderr +++ b/src/test/ui/consts/const_let_assign3.stderr @@ -3,6 +3,8 @@ error[E0019]: constant function contains unimplemented expression type | LL | self.state = x; | ^^^^^^^^^^^^^^ + | + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable error[E0658]: references in constants may only refer to immutable values --> $DIR/const_let_assign3.rs:16:5 @@ -27,6 +29,8 @@ error[E0019]: constant contains unimplemented expression type | LL | *y = 42; | ^^^^^^^ + | + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable error: aborting due to 4 previous errors diff --git a/src/test/ui/consts/ice-zst-static-access.rs b/src/test/ui/consts/ice-zst-static-access.rs new file mode 100644 index 00000000000..b68e442a57c --- /dev/null +++ b/src/test/ui/consts/ice-zst-static-access.rs @@ -0,0 +1,32 @@ +// check-pass + +// This is a regression test for ICEs from +// https://github.com/rust-lang/rust/issues/71612 +// and +// https://github.com/rust-lang/rust/issues/71709 + +#[derive(Copy, Clone)] +pub struct Glfw; + +static mut GLFW: Option<Glfw> = None; +pub fn new() -> Glfw { + unsafe { + if let Some(glfw) = GLFW { + return glfw; + } else { + todo!() + } + }; +} + +extern "C" { + static _dispatch_queue_attr_concurrent: [u8; 0]; +} + +static DISPATCH_QUEUE_CONCURRENT: &'static [u8; 0] = + unsafe { &_dispatch_queue_attr_concurrent }; + +fn main() { + *DISPATCH_QUEUE_CONCURRENT; + new(); +} diff --git a/src/test/ui/consts/projection_qualif.stock.stderr b/src/test/ui/consts/projection_qualif.stock.stderr index 75625a4bd1b..cfa48d947c9 100644 --- a/src/test/ui/consts/projection_qualif.stock.stderr +++ b/src/test/ui/consts/projection_qualif.stock.stderr @@ -21,6 +21,8 @@ error[E0019]: constant contains unimplemented expression type | LL | unsafe { *b = 5; } | ^^^^^^ + | + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable error: aborting due to 3 previous errors diff --git a/src/test/ui/consts/static_mut_containing_mut_ref2.stock.stderr b/src/test/ui/consts/static_mut_containing_mut_ref2.stock.stderr index c70431886e8..cc169351bf2 100644 --- a/src/test/ui/consts/static_mut_containing_mut_ref2.stock.stderr +++ b/src/test/ui/consts/static_mut_containing_mut_ref2.stock.stderr @@ -12,6 +12,8 @@ error[E0019]: static contains unimplemented expression type | LL | pub static mut STDERR_BUFFER: () = unsafe { *(&mut STDERR_BUFFER_SPACE) = 42; }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable error: aborting due to 2 previous errors diff --git a/src/test/ui/crate-in-paths.stderr b/src/test/ui/crate-in-paths.stderr index 38d222f980d..c3aa135f77d 100644 --- a/src/test/ui/crate-in-paths.stderr +++ b/src/test/ui/crate-in-paths.stderr @@ -4,7 +4,7 @@ error[E0425]: cannot find value `Foo` in this scope LL | Foo; | ^^^ not found in this scope | -help: possible candidate is found in another module, you can import it into scope +help: consider importing this unit struct | LL | use crate::bar::Foo; | diff --git a/src/test/ui/deriving/deriving-hash.rs b/src/test/ui/deriving/deriving-hash.rs index 68c68c235ef..8b51370bca5 100644 --- a/src/test/ui/deriving/deriving-hash.rs +++ b/src/test/ui/deriving/deriving-hash.rs @@ -24,7 +24,7 @@ struct Person { enum E { A=1, B } fn hash<T: Hash>(t: &T) -> u64 { - let mut s = SipHasher::new_with_keys(0, 0); + let mut s = SipHasher::new(); t.hash(&mut s); s.finish() } diff --git a/src/test/ui/did_you_mean/issue-56028-there-is-an-enum-variant.stderr b/src/test/ui/did_you_mean/issue-56028-there-is-an-enum-variant.stderr index 792b36e00bb..9429a0b5765 100644 --- a/src/test/ui/did_you_mean/issue-56028-there-is-an-enum-variant.stderr +++ b/src/test/ui/did_you_mean/issue-56028-there-is-an-enum-variant.stderr @@ -22,7 +22,7 @@ error[E0425]: cannot find value `Set` in this scope LL | fn setup() -> Set { Set } | ^^^ not found in this scope | -help: possible candidates are found in other modules, you can import them into scope +help: consider importing one of these items | LL | use AffixHeart::Set; | diff --git a/src/test/ui/editions/async-block-2015.rs b/src/test/ui/editions/async-block-2015.rs new file mode 100644 index 00000000000..985606a6f25 --- /dev/null +++ b/src/test/ui/editions/async-block-2015.rs @@ -0,0 +1,30 @@ +async fn foo() { +//~^ ERROR `async fn` is not permitted in the 2015 edition +//~| NOTE to use `async fn`, switch to Rust 2018 +//~| HELP set `edition = "2018"` in `Cargo.toml` +//~| NOTE for more on editions, read https://doc.rust-lang.org/edition-guide + + let x = async {}; + //~^ ERROR cannot find struct, variant or union type `async` in this scope + //~| NOTE `async` blocks are only allowed in the 2018 edition + let y = async { //~ NOTE `async` blocks are only allowed in the 2018 edition + let x = 42; + //~^ ERROR expected identifier, found keyword `let` + //~| NOTE expected identifier, found keyword + //~| HELP set `edition = "2018"` in `Cargo.toml` + //~| NOTE for more on editions, read https://doc.rust-lang.org/edition-guide + 42 + }; + let z = async { //~ NOTE `async` blocks are only allowed in the 2018 edition + 42 + //~^ ERROR expected identifier, found `42` + //~| NOTE expected identifier + //~| HELP set `edition = "2018"` in `Cargo.toml` + //~| NOTE for more on editions, read https://doc.rust-lang.org/edition-guide + }; + y.await; + z.await; + x +} + +fn main() {} diff --git a/src/test/ui/editions/async-block-2015.stderr b/src/test/ui/editions/async-block-2015.stderr new file mode 100644 index 00000000000..8e5e5d8bfab --- /dev/null +++ b/src/test/ui/editions/async-block-2015.stderr @@ -0,0 +1,41 @@ +error[E0670]: `async fn` is not permitted in the 2015 edition + --> $DIR/async-block-2015.rs:1:1 + | +LL | async fn foo() { + | ^^^^^ to use `async fn`, switch to Rust 2018 + | + = help: set `edition = "2018"` in `Cargo.toml` + = note: for more on editions, read https://doc.rust-lang.org/edition-guide + +error: expected identifier, found keyword `let` + --> $DIR/async-block-2015.rs:11:9 + | +LL | let y = async { + | ----- `async` blocks are only allowed in the 2018 edition +LL | let x = 42; + | ^^^ expected identifier, found keyword + | + = help: set `edition = "2018"` in `Cargo.toml` + = note: for more on editions, read https://doc.rust-lang.org/edition-guide + +error: expected identifier, found `42` + --> $DIR/async-block-2015.rs:19:9 + | +LL | let z = async { + | ----- `async` blocks are only allowed in the 2018 edition +LL | 42 + | ^^ expected identifier + | + = help: set `edition = "2018"` in `Cargo.toml` + = note: for more on editions, read https://doc.rust-lang.org/edition-guide + +error[E0422]: cannot find struct, variant or union type `async` in this scope + --> $DIR/async-block-2015.rs:7:13 + | +LL | let x = async {}; + | ^^^^^ `async` blocks are only allowed in the 2018 edition + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0422, E0670. +For more information about an error, try `rustc --explain E0422`. diff --git a/src/test/ui/enum/issue-67945-1.rs b/src/test/ui/enum/issue-67945-1.rs new file mode 100644 index 00000000000..7977bddae7b --- /dev/null +++ b/src/test/ui/enum/issue-67945-1.rs @@ -0,0 +1,8 @@ +enum Bug<S> { + Var = { + let x: S = 0; //~ ERROR: mismatched types + 0 + }, +} + +fn main() {} diff --git a/src/test/ui/enum/issue-67945-1.stderr b/src/test/ui/enum/issue-67945-1.stderr new file mode 100644 index 00000000000..6583fe13d0c --- /dev/null +++ b/src/test/ui/enum/issue-67945-1.stderr @@ -0,0 +1,17 @@ +error[E0308]: mismatched types + --> $DIR/issue-67945-1.rs:3:20 + | +LL | enum Bug<S> { + | - this type parameter +LL | Var = { +LL | let x: S = 0; + | - ^ expected type parameter `S`, found integer + | | + | expected due to this + | + = note: expected type parameter `S` + found type `{integer}` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/enum/issue-67945-2.rs b/src/test/ui/enum/issue-67945-2.rs new file mode 100644 index 00000000000..16bd8530ab3 --- /dev/null +++ b/src/test/ui/enum/issue-67945-2.rs @@ -0,0 +1,9 @@ +#![feature(type_ascription)] + +enum Bug<S> { + Var = 0: S, + //~^ ERROR: mismatched types + //~| ERROR: mismatched types +} + +fn main() {} diff --git a/src/test/ui/enum/issue-67945-2.stderr b/src/test/ui/enum/issue-67945-2.stderr new file mode 100644 index 00000000000..c40506d59ed --- /dev/null +++ b/src/test/ui/enum/issue-67945-2.stderr @@ -0,0 +1,25 @@ +error[E0308]: mismatched types + --> $DIR/issue-67945-2.rs:4:11 + | +LL | enum Bug<S> { + | - this type parameter +LL | Var = 0: S, + | ^ expected type parameter `S`, found integer + | + = note: expected type parameter `S` + found type `{integer}` + +error[E0308]: mismatched types + --> $DIR/issue-67945-2.rs:4:11 + | +LL | enum Bug<S> { + | - this type parameter +LL | Var = 0: S, + | ^^^^ expected `isize`, found type parameter `S` + | + = note: expected type `isize` + found type parameter `S` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/eprint-on-tls-drop.rs b/src/test/ui/eprint-on-tls-drop.rs index 9c4800c1a3f..f5243077384 100644 --- a/src/test/ui/eprint-on-tls-drop.rs +++ b/src/test/ui/eprint-on-tls-drop.rs @@ -1,5 +1,6 @@ // run-pass // ignore-emscripten no processes +// ignore-sgx no processes use std::cell::RefCell; use std::env; diff --git a/src/test/ui/error-codes/E0010-teach.stderr b/src/test/ui/error-codes/E0010-teach.stderr index 4c9d140692a..c15ab5c655a 100644 --- a/src/test/ui/error-codes/E0010-teach.stderr +++ b/src/test/ui/error-codes/E0010-teach.stderr @@ -12,6 +12,7 @@ error[E0019]: constant contains unimplemented expression type LL | const CON : Box<i32> = box 0; | ^ | + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable = note: A function call isn't allowed in the const's initialization expression because the expression's value must be known at compile-time. = note: Remember: you can't use a function call inside a const's initialization expression! However, you can use it anywhere else. diff --git a/src/test/ui/error-codes/E0010.stderr b/src/test/ui/error-codes/E0010.stderr index 48472d8acda..f49fb9c4632 100644 --- a/src/test/ui/error-codes/E0010.stderr +++ b/src/test/ui/error-codes/E0010.stderr @@ -9,6 +9,8 @@ error[E0019]: constant contains unimplemented expression type | LL | const CON : Box<i32> = box 0; | ^ + | + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable error: aborting due to 2 previous errors diff --git a/src/test/ui/error-codes/E0017.stderr b/src/test/ui/error-codes/E0017.stderr index 2e687c18ed3..f959ad0d008 100644 --- a/src/test/ui/error-codes/E0017.stderr +++ b/src/test/ui/error-codes/E0017.stderr @@ -12,6 +12,8 @@ error[E0019]: static contains unimplemented expression type | LL | static STATIC_REF: &'static mut i32 = &mut X; | ^^^^^^ + | + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable error[E0658]: references in statics may only refer to immutable values --> $DIR/E0017.rs:6:39 diff --git a/src/test/ui/error-codes/E0388.stderr b/src/test/ui/error-codes/E0388.stderr index 52822ebdd9e..8bdfbac3681 100644 --- a/src/test/ui/error-codes/E0388.stderr +++ b/src/test/ui/error-codes/E0388.stderr @@ -12,6 +12,8 @@ error[E0019]: static contains unimplemented expression type | LL | static STATIC_REF: &'static mut i32 = &mut X; | ^^^^^^ + | + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable error[E0658]: references in statics may only refer to immutable values --> $DIR/E0388.rs:5:39 diff --git a/src/test/ui/fully-qualified-type/fully-qualified-type-name3.rs b/src/test/ui/fully-qualified-type/fully-qualified-type-name3.rs deleted file mode 100644 index 22faa66d9fb..00000000000 --- a/src/test/ui/fully-qualified-type/fully-qualified-type-name3.rs +++ /dev/null @@ -1,14 +0,0 @@ -// Test that we use fully-qualified type names in error messages. - -// ignore-test - -type T1 = usize; -type T2 = isize; - -fn bar(x: T1) -> T2 { - return x; - //~^ ERROR mismatched types: expected `T2`, found `T1` -} - -fn main() { -} diff --git a/src/test/ui/generic-associated-types/construct_with_other_type.stderr b/src/test/ui/generic-associated-types/construct_with_other_type.stderr index bad746f7ef1..b9468b3330b 100644 --- a/src/test/ui/generic-associated-types/construct_with_other_type.stderr +++ b/src/test/ui/generic-associated-types/construct_with_other_type.stderr @@ -2,11 +2,16 @@ error[E0271]: type mismatch resolving `for<'a> <<T as Baz>::Baa<'a> as std::ops: --> $DIR/construct_with_other_type.rs:19:9 | LL | impl<T> Baz for T where T: Foo { - | ^^^ expected type parameter `T`, found associated type + | - ^^^ expected type parameter `T`, found associated type + | | + | this type parameter | = note: expected associated type `<T as Foo>::Bar<'_, 'static>` found associated type `<<T as Baz>::Quux<'_> as Foo>::Bar<'_, 'static>` - = note: you might be missing a type parameter or trait bound +help: consider further restricting this bound + | +LL | impl<T> Baz for T where T: Foo + Baz<Quux = T> { + | ^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/generic-associated-types/iterable.stderr b/src/test/ui/generic-associated-types/iterable.stderr index b1298163aab..6e754621225 100644 --- a/src/test/ui/generic-associated-types/iterable.stderr +++ b/src/test/ui/generic-associated-types/iterable.stderr @@ -6,7 +6,7 @@ LL | type Item<'a> where T: 'a = <std::slice::Iter<'a, T> as Iterator>::Item | = note: expected reference `&T` found associated type `<std::vec::Vec<T> as Iterable>::Item<'_>` - = note: consider constraining the associated type `<std::vec::Vec<T> as Iterable>::Item<'_>` to `&_` + = help: consider constraining the associated type `<std::vec::Vec<T> as Iterable>::Item<'_>` to `&_` = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html error[E0271]: type mismatch resolving `for<'a> <<[T] as Iterable>::Iter<'a> as std::iter::Iterator>::Item == <[T] as Iterable>::Item<'a>` @@ -17,7 +17,7 @@ LL | type Item<'a> where T: 'a = <std::slice::Iter<'a, T> as Iterator>::Item | = note: expected reference `&T` found associated type `<[T] as Iterable>::Item<'_>` - = note: consider constraining the associated type `<[T] as Iterable>::Item<'_>` to `&_` + = help: consider constraining the associated type `<[T] as Iterable>::Item<'_>` to `&_` = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html error[E0271]: type mismatch resolving `for<'a> <<std::vec::Vec<T> as Iterable>::Iter<'a> as std::iter::Iterator>::Item == <std::vec::Vec<T> as Iterable>::Item<'a>` @@ -34,7 +34,7 @@ LL | fn iter<'a>(&'a self) -> Self::Iter<'a> { | = note: expected associated type `<std::vec::Vec<T> as Iterable>::Item<'_>` found reference `&T` - = note: consider constraining the associated type `<std::vec::Vec<T> as Iterable>::Item<'_>` to `&_` or calling a method that returns `<std::vec::Vec<T> as Iterable>::Item<'_>` + = help: consider constraining the associated type `<std::vec::Vec<T> as Iterable>::Item<'_>` to `&_` or calling a method that returns `<std::vec::Vec<T> as Iterable>::Item<'_>` = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html error[E0271]: type mismatch resolving `for<'a> <<[T] as Iterable>::Iter<'a> as std::iter::Iterator>::Item == <[T] as Iterable>::Item<'a>` @@ -51,7 +51,7 @@ LL | fn iter<'a>(&'a self) -> Self::Iter<'a> { | = note: expected associated type `<[T] as Iterable>::Item<'_>` found reference `&T` - = note: consider constraining the associated type `<[T] as Iterable>::Item<'_>` to `&_` or calling a method that returns `<[T] as Iterable>::Item<'_>` + = help: consider constraining the associated type `<[T] as Iterable>::Item<'_>` to `&_` or calling a method that returns `<[T] as Iterable>::Item<'_>` = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html error: aborting due to 4 previous errors diff --git a/src/test/ui/generic-associated-types/missing-bounds.fixed b/src/test/ui/generic-associated-types/missing-bounds.fixed new file mode 100644 index 00000000000..364d2388741 --- /dev/null +++ b/src/test/ui/generic-associated-types/missing-bounds.fixed @@ -0,0 +1,46 @@ +// run-rustfix + +use std::ops::Add; + +struct A<B>(B); + +impl<B> Add for A<B> where B: Add + std::ops::Add<Output = B> { + type Output = Self; + + fn add(self, rhs: Self) -> Self { + A(self.0 + rhs.0) //~ ERROR mismatched types + } +} + +struct C<B>(B); + +impl<B: Add + std::ops::Add<Output = B>> Add for C<B> { + type Output = Self; + + fn add(self, rhs: Self) -> Self { + Self(self.0 + rhs.0) //~ ERROR mismatched types + } +} + +struct D<B>(B); + +impl<B: std::ops::Add<Output = B>> Add for D<B> { + type Output = Self; + + fn add(self, rhs: Self) -> Self { + Self(self.0 + rhs.0) //~ ERROR cannot add `B` to `B` + } +} + +struct E<B>(B); + +impl<B: Add> Add for E<B> where B: Add<Output = B>, B: std::ops::Add<Output = B> { + //~^ ERROR equality constraints are not yet supported in `where` clauses + type Output = Self; + + fn add(self, rhs: Self) -> Self { + Self(self.0 + rhs.0) //~ ERROR mismatched types + } +} + +fn main() {} diff --git a/src/test/ui/generic-associated-types/missing-bounds.rs b/src/test/ui/generic-associated-types/missing-bounds.rs new file mode 100644 index 00000000000..ffafff5e9f5 --- /dev/null +++ b/src/test/ui/generic-associated-types/missing-bounds.rs @@ -0,0 +1,46 @@ +// run-rustfix + +use std::ops::Add; + +struct A<B>(B); + +impl<B> Add for A<B> where B: Add { + type Output = Self; + + fn add(self, rhs: Self) -> Self { + A(self.0 + rhs.0) //~ ERROR mismatched types + } +} + +struct C<B>(B); + +impl<B: Add> Add for C<B> { + type Output = Self; + + fn add(self, rhs: Self) -> Self { + Self(self.0 + rhs.0) //~ ERROR mismatched types + } +} + +struct D<B>(B); + +impl<B> Add for D<B> { + type Output = Self; + + fn add(self, rhs: Self) -> Self { + Self(self.0 + rhs.0) //~ ERROR cannot add `B` to `B` + } +} + +struct E<B>(B); + +impl<B: Add> Add for E<B> where <B as Add>::Output = B { + //~^ ERROR equality constraints are not yet supported in `where` clauses + type Output = Self; + + fn add(self, rhs: Self) -> Self { + Self(self.0 + rhs.0) //~ ERROR mismatched types + } +} + +fn main() {} diff --git a/src/test/ui/generic-associated-types/missing-bounds.stderr b/src/test/ui/generic-associated-types/missing-bounds.stderr new file mode 100644 index 00000000000..50536fdaca9 --- /dev/null +++ b/src/test/ui/generic-associated-types/missing-bounds.stderr @@ -0,0 +1,77 @@ +error: equality constraints are not yet supported in `where` clauses + --> $DIR/missing-bounds.rs:37:33 + | +LL | impl<B: Add> Add for E<B> where <B as Add>::Output = B { + | ^^^^^^^^^^^^^^^^^^^^^^ not supported + | + = note: see issue #20041 <https://github.com/rust-lang/rust/issues/20041> for more information +help: if `Output` is an associated type you're trying to set, use the associated type binding syntax + | +LL | impl<B: Add> Add for E<B> where B: Add<Output = B> { + | ^^^^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/missing-bounds.rs:11:11 + | +LL | impl<B> Add for A<B> where B: Add { + | - this type parameter +... +LL | A(self.0 + rhs.0) + | ^^^^^^^^^^^^^^ expected type parameter `B`, found associated type + | + = note: expected type parameter `B` + found associated type `<B as std::ops::Add>::Output` +help: consider further restricting this bound + | +LL | impl<B> Add for A<B> where B: Add + std::ops::Add<Output = B> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/missing-bounds.rs:21:14 + | +LL | impl<B: Add> Add for C<B> { + | - this type parameter +... +LL | Self(self.0 + rhs.0) + | ^^^^^^^^^^^^^^ expected type parameter `B`, found associated type + | + = note: expected type parameter `B` + found associated type `<B as std::ops::Add>::Output` +help: consider further restricting this bound + | +LL | impl<B: Add + std::ops::Add<Output = B>> Add for C<B> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0369]: cannot add `B` to `B` + --> $DIR/missing-bounds.rs:31:21 + | +LL | Self(self.0 + rhs.0) + | ------ ^ ----- B + | | + | B + | +help: consider restricting type parameter `B` + | +LL | impl<B: std::ops::Add<Output = B>> Add for D<B> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/missing-bounds.rs:42:14 + | +LL | impl<B: Add> Add for E<B> where <B as Add>::Output = B { + | - this type parameter +... +LL | Self(self.0 + rhs.0) + | ^^^^^^^^^^^^^^ expected type parameter `B`, found associated type + | + = note: expected type parameter `B` + found associated type `<B as std::ops::Add>::Output` +help: consider further restricting type parameter `B` + | +LL | impl<B: Add> Add for E<B> where <B as Add>::Output = B, B: std::ops::Add<Output = B> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 5 previous errors + +Some errors have detailed explanations: E0308, E0369. +For more information about an error, try `rustc --explain E0308`. diff --git a/src/test/ui/glob-resolve1.stderr b/src/test/ui/glob-resolve1.stderr index efbd53fd223..995da6cc1f9 100644 --- a/src/test/ui/glob-resolve1.stderr +++ b/src/test/ui/glob-resolve1.stderr @@ -4,7 +4,7 @@ error[E0425]: cannot find function `fpriv` in this scope LL | fpriv(); | ^^^^^ not found in this scope | -help: possible candidate is found in another module, you can import it into scope +help: consider importing this function | LL | use bar::fpriv; | @@ -15,7 +15,7 @@ error[E0425]: cannot find function `epriv` in this scope LL | epriv(); | ^^^^^ not found in this scope | -help: possible candidate is found in another module, you can import it into scope +help: consider importing this function | LL | use bar::epriv; | @@ -32,7 +32,7 @@ error[E0425]: cannot find value `C` in this scope LL | C; | ^ not found in this scope | -help: possible candidate is found in another module, you can import it into scope +help: consider importing this unit struct | LL | use bar::C; | @@ -56,7 +56,7 @@ help: an enum with a similar name exists | LL | foo::<B>(); | ^ -help: possible candidate is found in another module, you can import it into scope +help: consider importing this enum | LL | use bar::A; | @@ -74,7 +74,7 @@ help: an enum with a similar name exists | LL | foo::<B>(); | ^ -help: possible candidate is found in another module, you can import it into scope +help: consider importing this struct | LL | use bar::C; | @@ -92,7 +92,7 @@ help: an enum with a similar name exists | LL | foo::<B>(); | ^ -help: possible candidate is found in another module, you can import it into scope +help: consider importing this type alias | LL | use bar::D; | diff --git a/src/test/ui/hrtb/issue-62203-hrtb-ice.stderr b/src/test/ui/hrtb/issue-62203-hrtb-ice.stderr index 759c7302d13..1c7bfa65d7c 100644 --- a/src/test/ui/hrtb/issue-62203-hrtb-ice.stderr +++ b/src/test/ui/hrtb/issue-62203-hrtb-ice.stderr @@ -6,7 +6,7 @@ LL | let v = Unit2.m( | = note: expected struct `Unit4` found associated type `<_ as Ty<'_>>::V` - = note: consider constraining the associated type `<_ as Ty<'_>>::V` to `Unit4` + = help: consider constraining the associated type `<_ as Ty<'_>>::V` to `Unit4` = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html error[E0271]: type mismatch resolving `<[closure@$DIR/issue-62203-hrtb-ice.rs:42:17: 42:39] as std::ops::FnOnce<((&u8,),)>>::Output == Unit3` diff --git a/src/test/ui/hygiene/globs.stderr b/src/test/ui/hygiene/globs.stderr index 153ad8cbecf..8f6b7aca8fd 100644 --- a/src/test/ui/hygiene/globs.stderr +++ b/src/test/ui/hygiene/globs.stderr @@ -4,7 +4,7 @@ error[E0425]: cannot find function `f` in this scope LL | f(); | ^ not found in this scope | -help: possible candidate is found in another module, you can import it into scope +help: consider importing one of these items | LL | use foo::f; | @@ -23,7 +23,7 @@ LL | | } | |_____- in this macro invocation | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -help: possible candidates are found in other modules, you can import them into scope +help: consider importing one of these items | LL | use bar::g; | @@ -41,7 +41,7 @@ LL | n!(f); LL | n!(f); | ^ not found in this scope | - = note: possible candidate is found in another module, you can import it into scope: + = note: consider importing one of these items: foo::f = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) @@ -54,7 +54,7 @@ LL | n!(f); LL | f | ^ not found in this scope | - = note: possible candidate is found in another module, you can import it into scope: + = note: consider importing one of these items: foo::f = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/src/test/ui/impl-trait/bound-normalization-fail.stderr b/src/test/ui/impl-trait/bound-normalization-fail.stderr index 314ed96fd5e..f5092044627 100644 --- a/src/test/ui/impl-trait/bound-normalization-fail.stderr +++ b/src/test/ui/impl-trait/bound-normalization-fail.stderr @@ -14,9 +14,11 @@ LL | fn foo_fail<T: Trait>() -> impl FooLike<Output=T::Assoc> { | = note: expected type `()` found associated type `<T as impl_trait::Trait>::Assoc` - = note: consider constraining the associated type `<T as impl_trait::Trait>::Assoc` to `()` - = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html = note: the return type of a function must have a statically known size +help: consider constraining the associated type `<T as impl_trait::Trait>::Assoc` to `()` + | +LL | fn foo_fail<T: Trait<Assoc = ()>>() -> impl FooLike<Output=T::Assoc> { + | ^^^^^^^^^^^^ error: `impl Trait` return type cannot contain a projection or `Self` that references lifetimes from a parent scope --> $DIR/bound-normalization-fail.rs:43:41 @@ -32,9 +34,11 @@ LL | fn foo2_fail<'a, T: Trait<'a>>() -> impl FooLike<Output=T::Assoc> { | = note: expected type `()` found associated type `<T as lifetimes::Trait<'static>>::Assoc` - = note: consider constraining the associated type `<T as lifetimes::Trait<'static>>::Assoc` to `()` - = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html = note: the return type of a function must have a statically known size +help: consider constraining the associated type `<T as lifetimes::Trait<'static>>::Assoc` to `()` + | +LL | fn foo2_fail<'a, T: Trait<'a, Assoc = ()>>() -> impl FooLike<Output=T::Assoc> { + | ^^^^^^^^^^^^ error: aborting due to 3 previous errors; 1 warning emitted diff --git a/src/test/ui/impl-trait/equality2.stderr b/src/test/ui/impl-trait/equality2.stderr index b882514f616..2454c218ffc 100644 --- a/src/test/ui/impl-trait/equality2.stderr +++ b/src/test/ui/impl-trait/equality2.stderr @@ -25,7 +25,7 @@ LL | let _: i32 = Leak::leak(hide(0_i32)); | = note: expected type `i32` found associated type `<impl Foo as Leak>::T` - = note: consider constraining the associated type `<impl Foo as Leak>::T` to `i32` + = help: consider constraining the associated type `<impl Foo as Leak>::T` to `i32` = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html error[E0308]: mismatched types diff --git a/src/test/ui/impl-trait/universal-mismatched-type.stderr b/src/test/ui/impl-trait/universal-mismatched-type.stderr index 3ffa2b55712..a12b01b4d2b 100644 --- a/src/test/ui/impl-trait/universal-mismatched-type.stderr +++ b/src/test/ui/impl-trait/universal-mismatched-type.stderr @@ -10,8 +10,6 @@ LL | x | = note: expected struct `std::string::String` found type parameter `impl Debug` - = help: type parameters must be constrained to match other types - = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters error: aborting due to previous error diff --git a/src/test/ui/impl-trait/universal_wrong_bounds.stderr b/src/test/ui/impl-trait/universal_wrong_bounds.stderr index 32b638dc465..3b1a5e5f4ad 100644 --- a/src/test/ui/impl-trait/universal_wrong_bounds.stderr +++ b/src/test/ui/impl-trait/universal_wrong_bounds.stderr @@ -4,7 +4,7 @@ error[E0404]: expected trait, found derive macro `Debug` LL | fn wants_debug(g: impl Debug) { } | ^^^^^ not a trait | -help: possible better candidate is found in another module, you can import it into scope +help: consider importing this trait instead | LL | use std::fmt::Debug; | @@ -15,7 +15,7 @@ error[E0404]: expected trait, found derive macro `Debug` LL | fn wants_display(g: impl Debug) { } | ^^^^^ not a trait | -help: possible better candidate is found in another module, you can import it into scope +help: consider importing this trait instead | LL | use std::fmt::Debug; | diff --git a/src/test/ui/issues-71798.rs b/src/test/ui/issues-71798.rs new file mode 100644 index 00000000000..08b10463d39 --- /dev/null +++ b/src/test/ui/issues-71798.rs @@ -0,0 +1,7 @@ +fn test_ref(x: &u32) -> impl std::future::Future<Output = u32> + '_ { + *x //~^ ERROR the trait bound `u32: std::future::Future` is not satisfied +} + +fn main() { + let _ = test_ref & u; //~ ERROR cannot find value `u` in this scope +} diff --git a/src/test/ui/issues-71798.stderr b/src/test/ui/issues-71798.stderr new file mode 100644 index 00000000000..85da87914e7 --- /dev/null +++ b/src/test/ui/issues-71798.stderr @@ -0,0 +1,20 @@ +error[E0425]: cannot find value `u` in this scope + --> $DIR/issues-71798.rs:6:24 + | +LL | let _ = test_ref & u; + | ^ not found in this scope + +error[E0277]: the trait bound `u32: std::future::Future` is not satisfied + --> $DIR/issues-71798.rs:1:25 + | +LL | fn test_ref(x: &u32) -> impl std::future::Future<Output = u32> + '_ { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::future::Future` is not implemented for `u32` +LL | *x + | -- this returned value is of type `u32` + | + = note: the return type of a function must have a statically known size + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0277, E0425. +For more information about an error, try `rustc --explain E0277`. diff --git a/src/test/ui/issues/issue-12028.stderr b/src/test/ui/issues/issue-12028.stderr index 434c5de2874..30cb7a1df80 100644 --- a/src/test/ui/issues/issue-12028.stderr +++ b/src/test/ui/issues/issue-12028.stderr @@ -1,10 +1,8 @@ -error[E0284]: type annotations needed +error[E0284]: type annotations needed: cannot satisfy `<_ as StreamHasher>::S == <H as StreamHasher>::S` --> $DIR/issue-12028.rs:27:14 | LL | self.input_stream(&mut stream); - | ^^^^^^^^^^^^ cannot infer type for type parameter `H` declared on the trait `StreamHash` - | - = note: cannot satisfy `<_ as StreamHasher>::S == <H as StreamHasher>::S` + | ^^^^^^^^^^^^ cannot satisfy `<_ as StreamHasher>::S == <H as StreamHasher>::S` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-13853.stderr b/src/test/ui/issues/issue-13853.stderr index 2f31636f8ad..3f1b955dddb 100644 --- a/src/test/ui/issues/issue-13853.stderr +++ b/src/test/ui/issues/issue-13853.stderr @@ -9,8 +9,6 @@ LL | self.iter() | = note: expected type parameter `I` found struct `std::slice::Iter<'_, N>` - = help: type parameters must be constrained to match other types - = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters error[E0599]: no method named `iter` found for reference `&G` in the current scope --> $DIR/issue-13853.rs:27:23 diff --git a/src/test/ui/issues/issue-15487.rs b/src/test/ui/issues/issue-15487.rs index 98714cba0e4..17b16a62a74 100644 --- a/src/test/ui/issues/issue-15487.rs +++ b/src/test/ui/issues/issue-15487.rs @@ -2,6 +2,7 @@ #![allow(unused_attributes)] // ignore-windows // ignore-wasm32-bare no libs to link +// ignore-sgx no libs to link #![feature(link_args)] diff --git a/src/test/ui/issues/issue-16530.rs b/src/test/ui/issues/issue-16530.rs index 22a6ef7fa09..25817a2a63d 100644 --- a/src/test/ui/issues/issue-16530.rs +++ b/src/test/ui/issues/issue-16530.rs @@ -7,9 +7,9 @@ use std::hash::{SipHasher, Hasher, Hash}; struct Empty; pub fn main() { - let mut s1 = SipHasher::new_with_keys(0, 0); + let mut s1 = SipHasher::new(); Empty.hash(&mut s1); - let mut s2 = SipHasher::new_with_keys(0, 0); + let mut s2 = SipHasher::new(); Empty.hash(&mut s2); assert_eq!(s1.finish(), s2.finish()); } diff --git a/src/test/ui/issues/issue-17025.rs b/src/test/ui/issues/issue-17025.rs deleted file mode 100644 index 6b7b6d010aa..00000000000 --- a/src/test/ui/issues/issue-17025.rs +++ /dev/null @@ -1,13 +0,0 @@ -// ignore-test the unsized enum no longer compiles - -enum A { - B(char), - C([Box<A>]), -} - -fn c(c:char) { - A::B(c); - //~^ ERROR cannot move a value of type A: the size of A cannot be statically determined -} - -pub fn main() {} diff --git a/src/test/ui/issues/issue-17546.rs b/src/test/ui/issues/issue-17546.rs index dbfdad25e5b..6c62010f176 100644 --- a/src/test/ui/issues/issue-17546.rs +++ b/src/test/ui/issues/issue-17546.rs @@ -1,3 +1,5 @@ +// ignore-sgx std::os::fortanix_sgx::usercalls::raw::Result changes compiler suggestions + use foo::MyEnum::Result; use foo::NoResult; // Through a re-export diff --git a/src/test/ui/issues/issue-17546.stderr b/src/test/ui/issues/issue-17546.stderr index 5bbe6d3b171..8bf40790f0b 100644 --- a/src/test/ui/issues/issue-17546.stderr +++ b/src/test/ui/issues/issue-17546.stderr @@ -1,5 +1,5 @@ error[E0573]: expected type, found variant `NoResult` - --> $DIR/issue-17546.rs:12:17 + --> $DIR/issue-17546.rs:14:17 | LL | fn new() -> NoResult<MyEnum, String> { | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -19,12 +19,12 @@ LL | fn new() -> Result<MyEnum, String> { | ^^^^^^ error[E0573]: expected type, found variant `Result` - --> $DIR/issue-17546.rs:22:17 + --> $DIR/issue-17546.rs:24:17 | LL | fn new() -> Result<foo::MyEnum, String> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ not a type | -help: possible better candidates are found in other modules, you can import them into scope +help: consider importing one of these items instead | LL | use std::fmt::Result; | @@ -37,12 +37,12 @@ LL | use std::result::Result; and 1 other candidate error[E0573]: expected type, found variant `Result` - --> $DIR/issue-17546.rs:28:13 + --> $DIR/issue-17546.rs:30:13 | LL | fn new() -> Result<foo::MyEnum, String> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ not a type | -help: possible better candidates are found in other modules, you can import them into scope +help: consider importing one of these items instead | LL | use std::fmt::Result; | @@ -55,7 +55,7 @@ LL | use std::result::Result; and 1 other candidate error[E0573]: expected type, found variant `NoResult` - --> $DIR/issue-17546.rs:33:15 + --> $DIR/issue-17546.rs:35:15 | LL | fn newer() -> NoResult<foo::MyEnum, String> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/issues/issue-20005.stderr b/src/test/ui/issues/issue-20005.stderr index 19ccf707619..f53489a99f3 100644 --- a/src/test/ui/issues/issue-20005.stderr +++ b/src/test/ui/issues/issue-20005.stderr @@ -5,12 +5,18 @@ LL | trait From<Src> { | --- required by this bound in `From` ... LL | ) -> <Dst as From<Self>>::Result where Dst: From<Self> { - | ^^^^^^^^^^- help: consider further restricting `Self`: `, Self: std::marker::Sized` - | | - | doesn't have a size known at compile-time + | ^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `Self` = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait> +help: consider further restricting `Self` + | +LL | ) -> <Dst as From<Self>>::Result where Dst: From<Self>, Self: std::marker::Sized { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: consider relaxing the implicit `Sized` restriction + | +LL | trait From<Src: ?Sized> { + | ^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-20225.stderr b/src/test/ui/issues/issue-20225.stderr index 1c5911e05f7..3bcc50ded84 100644 --- a/src/test/ui/issues/issue-20225.stderr +++ b/src/test/ui/issues/issue-20225.stderr @@ -8,8 +8,6 @@ LL | extern "rust-call" fn call(&self, (_,): (T,)) {} | = note: expected fn pointer `extern "rust-call" fn(&Foo, (&'a T,))` found fn pointer `extern "rust-call" fn(&Foo, (T,))` - = help: type parameters must be constrained to match other types - = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters error[E0053]: method `call_mut` has an incompatible type for trait --> $DIR/issue-20225.rs:11:3 @@ -21,8 +19,6 @@ LL | extern "rust-call" fn call_mut(&mut self, (_,): (T,)) {} | = note: expected fn pointer `extern "rust-call" fn(&mut Foo, (&'a T,))` found fn pointer `extern "rust-call" fn(&mut Foo, (T,))` - = help: type parameters must be constrained to match other types - = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters error[E0053]: method `call_once` has an incompatible type for trait --> $DIR/issue-20225.rs:18:3 @@ -35,8 +31,6 @@ LL | extern "rust-call" fn call_once(self, (_,): (T,)) {} | = note: expected fn pointer `extern "rust-call" fn(Foo, (&'a T,))` found fn pointer `extern "rust-call" fn(Foo, (T,))` - = help: type parameters must be constrained to match other types - = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters error: aborting due to 3 previous errors diff --git a/src/test/ui/issues/issue-24204.stderr b/src/test/ui/issues/issue-24204.stderr index d69efc86005..d5cbcf786bf 100644 --- a/src/test/ui/issues/issue-24204.stderr +++ b/src/test/ui/issues/issue-24204.stderr @@ -7,7 +7,9 @@ LL | type A: MultiDispatch<Self::B, O = Self>; | -------- required by this bound in `Trait` ... LL | fn test<T: Trait<B=i32>>(b: i32) -> T where T::A: MultiDispatch<i32> { T::new(b) } - | ^^^^^^^^^^^^ expected type parameter `T`, found associated type + | - ^^^^^^^^^^^^ expected type parameter `T`, found associated type + | | + | this type parameter | = note: expected type parameter `T` found associated type `<<T as Trait>::A as MultiDispatch<i32>>::O` diff --git a/src/test/ui/issues/issue-32323.stderr b/src/test/ui/issues/issue-32323.stderr index 7c0928b1924..369f56b9869 100644 --- a/src/test/ui/issues/issue-32323.stderr +++ b/src/test/ui/issues/issue-32323.stderr @@ -8,8 +8,10 @@ LL | pub fn f<'a, T: Tr<'a>>() -> <T as Tr<'a>>::Out {} | = note: expected associated type `<T as Tr<'a>>::Out` found unit type `()` - = note: consider constraining the associated type `<T as Tr<'a>>::Out` to `()` or calling a method that returns `<T as Tr<'a>>::Out` - = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html +help: consider constraining the associated type `<T as Tr<'a>>::Out` to `()` + | +LL | pub fn f<'a, T: Tr<'a, Out = ()>>() -> <T as Tr<'a>>::Out {} + | ^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-35675.stderr b/src/test/ui/issues/issue-35675.stderr index a9a27da55b1..8637e574c5e 100644 --- a/src/test/ui/issues/issue-35675.stderr +++ b/src/test/ui/issues/issue-35675.stderr @@ -15,7 +15,7 @@ error[E0425]: cannot find function, tuple struct or tuple variant `Apple` in thi LL | Apple(5) | ^^^^^ not found in this scope | -help: possible candidate is found in another module, you can import it into scope +help: consider importing this tuple variant | LL | use Fruit::Apple; | @@ -35,7 +35,7 @@ error[E0425]: cannot find function, tuple struct or tuple variant `Apple` in thi LL | Apple(5) | ^^^^^ not found in this scope | -help: possible candidate is found in another module, you can import it into scope +help: consider importing this tuple variant | LL | use Fruit::Apple; | diff --git a/src/test/ui/issues/issue-37534.stderr b/src/test/ui/issues/issue-37534.stderr index b82e7b38914..5d008cf24dc 100644 --- a/src/test/ui/issues/issue-37534.stderr +++ b/src/test/ui/issues/issue-37534.stderr @@ -4,7 +4,7 @@ error[E0404]: expected trait, found derive macro `Hash` LL | struct Foo<T: ?Hash> { } | ^^^^ not a trait | -help: possible better candidate is found in another module, you can import it into scope +help: consider importing this trait instead | LL | use std::hash::Hash; | diff --git a/src/test/ui/issues/issue-38293.stderr b/src/test/ui/issues/issue-38293.stderr index cc3c72b496f..d2450ab1250 100644 --- a/src/test/ui/issues/issue-38293.stderr +++ b/src/test/ui/issues/issue-38293.stderr @@ -10,7 +10,7 @@ error[E0423]: expected function, found module `baz` LL | baz(); | ^^^ not a function | -help: possible better candidate is found in another module, you can import it into scope +help: consider importing this function instead | LL | use bar::baz; | diff --git a/src/test/ui/issues/issue-42944.stderr b/src/test/ui/issues/issue-42944.stderr index c71194f41c1..e7e251e39c0 100644 --- a/src/test/ui/issues/issue-42944.stderr +++ b/src/test/ui/issues/issue-42944.stderr @@ -10,7 +10,7 @@ error[E0425]: cannot find function, tuple struct or tuple variant `B` in this sc LL | B(()); | ^ not found in this scope | -help: possible candidate is found in another module, you can import it into scope +help: consider importing this tuple struct | LL | use foo::B; | diff --git a/src/test/ui/issues/issue-43162.stderr b/src/test/ui/issues/issue-43162.stderr index 0ed3d27c65b..a443db40732 100644 --- a/src/test/ui/issues/issue-43162.stderr +++ b/src/test/ui/issues/issue-43162.stderr @@ -17,9 +17,6 @@ LL | fn foo() -> bool { | --- ^^^^ expected `bool`, found `()` | | | implicitly returns `()` as its body has no tail or `return` expression -LL | -LL | break true; - | - help: consider removing this semicolon error: aborting due to 3 previous errors diff --git a/src/test/ui/issues/issue-4366-2.stderr b/src/test/ui/issues/issue-4366-2.stderr index 60a1155c614..ecee595d4ab 100644 --- a/src/test/ui/issues/issue-4366-2.stderr +++ b/src/test/ui/issues/issue-4366-2.stderr @@ -4,7 +4,7 @@ error[E0412]: cannot find type `Bar` in this scope LL | fn sub() -> Bar { 1 } | ^^^ not found in this scope | -help: possible candidate is found in another module, you can import it into scope +help: consider importing this type alias | LL | use a::b::Bar; | @@ -15,7 +15,7 @@ error[E0423]: expected function, found module `foo` LL | foo(); | ^^^ not a function | -help: possible better candidates are found in other modules, you can import them into scope +help: consider importing one of these items instead | LL | use foo::foo; | diff --git a/src/test/ui/issues/issue-4366.stderr b/src/test/ui/issues/issue-4366.stderr index d931d519117..a094180572d 100644 --- a/src/test/ui/issues/issue-4366.stderr +++ b/src/test/ui/issues/issue-4366.stderr @@ -4,7 +4,7 @@ error[E0425]: cannot find function `foo` in this scope LL | fn sub() -> isize { foo(); 1 } | ^^^ not found in this scope | -help: possible candidates are found in other modules, you can import them into scope +help: consider importing one of these items | LL | use foo::foo; | diff --git a/src/test/ui/issues/issue-50599.stderr b/src/test/ui/issues/issue-50599.stderr index 378c57011ac..7ec567a06f0 100644 --- a/src/test/ui/issues/issue-50599.stderr +++ b/src/test/ui/issues/issue-50599.stderr @@ -4,7 +4,7 @@ error[E0425]: cannot find value `LOG10_2` in module `std::f64` LL | const M: usize = (f64::from(N) * std::f64::LOG10_2) as usize; | ^^^^^^^ not found in `std::f64` | -help: possible candidates are found in other modules, you can import them into scope +help: consider importing one of these items | LL | use std::f32::consts::LOG10_2; | diff --git a/src/test/ui/issues/issue-6738.stderr b/src/test/ui/issues/issue-6738.stderr index 82b670bd03b..a428ff7e91f 100644 --- a/src/test/ui/issues/issue-6738.stderr +++ b/src/test/ui/issues/issue-6738.stderr @@ -6,7 +6,10 @@ LL | self.x += v.x; | | | cannot use `+=` on type `T` | - = note: `T` might need a bound for `std::ops::AddAssign` +help: consider restricting type parameter `T` + | +LL | impl<T: std::ops::AddAssign> Foo<T> { + | ^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-69306.stderr b/src/test/ui/issues/issue-69306.stderr index a2a42739ca8..58e85ec700d 100644 --- a/src/test/ui/issues/issue-69306.stderr +++ b/src/test/ui/issues/issue-69306.stderr @@ -8,8 +8,6 @@ LL | const C: S0<u8> = Self(0); | = note: expected type parameter `T` found type `{integer}` - = help: type parameters must be constrained to match other types - = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters error[E0308]: mismatched types --> $DIR/issue-69306.rs:5:23 @@ -21,8 +19,6 @@ LL | const C: S0<u8> = Self(0); | = note: expected struct `S0<u8>` found struct `S0<T>` - = help: type parameters must be constrained to match other types - = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters error[E0308]: mismatched types --> $DIR/issue-69306.rs:10:14 @@ -35,8 +31,6 @@ LL | Self(0); | = note: expected type parameter `T` found type `{integer}` - = help: type parameters must be constrained to match other types - = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters error[E0308]: mismatched types --> $DIR/issue-69306.rs:27:14 @@ -49,8 +43,6 @@ LL | Self(0); | = note: expected type parameter `T` found type `{integer}` - = help: type parameters must be constrained to match other types - = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters error[E0308]: mismatched types --> $DIR/issue-69306.rs:33:32 @@ -62,8 +54,6 @@ LL | const C: S1<u8, u8> = Self(0, 1); | = note: expected type parameter `T` found type `{integer}` - = help: type parameters must be constrained to match other types - = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters error[E0308]: mismatched types --> $DIR/issue-69306.rs:33:27 @@ -75,8 +65,6 @@ LL | const C: S1<u8, u8> = Self(0, 1); | = note: expected struct `S1<u8, _>` found struct `S1<T, _>` - = help: type parameters must be constrained to match other types - = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters error[E0308]: mismatched types --> $DIR/issue-69306.rs:41:14 diff --git a/src/test/ui/issues/issue-69455.rs b/src/test/ui/issues/issue-69455.rs index 017654554be..f1935ae2534 100644 --- a/src/test/ui/issues/issue-69455.rs +++ b/src/test/ui/issues/issue-69455.rs @@ -26,5 +26,5 @@ impl Test<u64> for u64 { fn main() { let xs: Vec<u64> = vec![1, 2, 3]; - println!("{}", 23u64.test(xs.iter().sum())); //~ ERROR: type annotations needed [E0284] + println!("{}", 23u64.test(xs.iter().sum())); //~ ERROR: type annotations needed } diff --git a/src/test/ui/issues/issue-69455.stderr b/src/test/ui/issues/issue-69455.stderr index 4caa1aca9fd..430bbcabf83 100644 --- a/src/test/ui/issues/issue-69455.stderr +++ b/src/test/ui/issues/issue-69455.stderr @@ -1,16 +1,8 @@ -error[E0284]: type annotations needed +error[E0284]: type annotations needed: cannot satisfy `<u64 as Test<_>>::Output == _` --> $DIR/issue-69455.rs:29:26 | -LL | type Output; - | ------------ `<Self as Test<Rhs>>::Output` defined here -... LL | println!("{}", 23u64.test(xs.iter().sum())); - | ------^^^^----------------- - | | | - | | cannot infer type for type `u64` - | this method call resolves to `<Self as Test<Rhs>>::Output` - | - = note: cannot satisfy `<u64 as Test<_>>::Output == _` + | ^^^^ cannot satisfy `<u64 as Test<_>>::Output == _` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-69683.rs b/src/test/ui/issues/issue-69683.rs new file mode 100644 index 00000000000..cc7f1fa0f55 --- /dev/null +++ b/src/test/ui/issues/issue-69683.rs @@ -0,0 +1,32 @@ +pub trait Element<S> { + type Array; +} + +impl<T> Element<()> for T { + type Array = T; +} + +impl<T: Element<S>, S> Element<[S; 3]> for T { + type Array = [T::Array; 3]; +} + +trait Foo<I> +where + u8: Element<I>, +{ + fn foo(self, x: <u8 as Element<I>>::Array); +} + +impl<I> Foo<I> for u16 +where + u8: Element<I>, +{ + fn foo(self, _: <u8 as Element<I>>::Array) {} +} + +fn main() { + let b: [u8; 3] = [0u8; 3]; + + 0u16.foo(b); //~ ERROR type annotations needed + //<u16 as Foo<[(); 3]>>::foo(0u16, b); +} diff --git a/src/test/ui/issues/issue-69683.stderr b/src/test/ui/issues/issue-69683.stderr new file mode 100644 index 00000000000..776370331a4 --- /dev/null +++ b/src/test/ui/issues/issue-69683.stderr @@ -0,0 +1,9 @@ +error[E0284]: type annotations needed: cannot satisfy `<u8 as Element<_>>::Array == [u8; 3]` + --> $DIR/issue-69683.rs:30:10 + | +LL | 0u16.foo(b); + | ^^^ cannot satisfy `<u8 as Element<_>>::Array == [u8; 3]` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0284`. diff --git a/src/test/ui/issues/issue-71584.rs b/src/test/ui/issues/issue-71584.rs new file mode 100644 index 00000000000..c96cd598f0c --- /dev/null +++ b/src/test/ui/issues/issue-71584.rs @@ -0,0 +1,5 @@ +fn main() { + let n: u32 = 1; + let mut d: u64 = 2; + d = d % n.into(); //~ ERROR type annotations needed +} diff --git a/src/test/ui/issues/issue-71584.stderr b/src/test/ui/issues/issue-71584.stderr new file mode 100644 index 00000000000..c162d338a93 --- /dev/null +++ b/src/test/ui/issues/issue-71584.stderr @@ -0,0 +1,9 @@ +error[E0284]: type annotations needed: cannot satisfy `<u64 as std::ops::Rem<_>>::Output == u64` + --> $DIR/issue-71584.rs:4:11 + | +LL | d = d % n.into(); + | ^ cannot satisfy `<u64 as std::ops::Rem<_>>::Output == u64` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0284`. diff --git a/src/test/ui/issues/issue-7364.stderr b/src/test/ui/issues/issue-7364.stderr index 1f1079555a9..efff2c24525 100644 --- a/src/test/ui/issues/issue-7364.stderr +++ b/src/test/ui/issues/issue-7364.stderr @@ -9,6 +9,8 @@ error[E0019]: static contains unimplemented expression type | LL | static boxed: Box<RefCell<isize>> = box RefCell::new(0); | ^^^^^^^^^^^^^^^ + | + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable error[E0277]: `std::cell::RefCell<isize>` cannot be shared between threads safely --> $DIR/issue-7364.rs:6:1 diff --git a/src/test/ui/lexical-scopes.stderr b/src/test/ui/lexical-scopes.stderr index 6bb0877e9b9..dce70545170 100644 --- a/src/test/ui/lexical-scopes.stderr +++ b/src/test/ui/lexical-scopes.stderr @@ -4,7 +4,7 @@ error[E0574]: expected struct, variant or union type, found type parameter `T` LL | let t = T { i: 0 }; | ^ not a struct, variant or union type | -help: possible better candidate is found in another module, you can import it into scope +help: consider importing this struct instead | LL | use T; | diff --git a/src/test/ui/lifetimes/issue-34979.rs b/src/test/ui/lifetimes/issue-34979.rs new file mode 100644 index 00000000000..252486dd921 --- /dev/null +++ b/src/test/ui/lifetimes/issue-34979.rs @@ -0,0 +1,9 @@ +trait Foo {} +impl<'a, T> Foo for &'a T {} + +struct Ctx<'a>(&'a ()) +where + &'a (): Foo, //~ ERROR: type annotations needed + &'static (): Foo; + +fn main() {} diff --git a/src/test/ui/lifetimes/issue-34979.stderr b/src/test/ui/lifetimes/issue-34979.stderr new file mode 100644 index 00000000000..04ad0d12766 --- /dev/null +++ b/src/test/ui/lifetimes/issue-34979.stderr @@ -0,0 +1,14 @@ +error[E0283]: type annotations needed + --> $DIR/issue-34979.rs:6:13 + | +LL | trait Foo {} + | --------- required by this bound in `Foo` +... +LL | &'a (): Foo, + | ^^^ cannot infer type for reference `&'a ()` + | + = note: cannot satisfy `&'a (): Foo` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0283`. diff --git a/src/test/ui/lint/lint-exceeding-bitshifts.noopt.stderr b/src/test/ui/lint/lint-exceeding-bitshifts.noopt.stderr index 0c328a2594a..8dbfeff7972 100644 --- a/src/test/ui/lint/lint-exceeding-bitshifts.noopt.stderr +++ b/src/test/ui/lint/lint-exceeding-bitshifts.noopt.stderr @@ -5,7 +5,7 @@ LL | const N: i32 = T::N << 42; | ^^^^^^^^^^ attempt to shift left with overflow | note: the lint level is defined here - --> $DIR/lint-exceeding-bitshifts.rs:8:9 + --> $DIR/lint-exceeding-bitshifts.rs:9:9 | LL | #![warn(arithmetic_overflow, const_err)] | ^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/lint/lint-exceeding-bitshifts.opt.stderr b/src/test/ui/lint/lint-exceeding-bitshifts.opt.stderr index 0c328a2594a..8dbfeff7972 100644 --- a/src/test/ui/lint/lint-exceeding-bitshifts.opt.stderr +++ b/src/test/ui/lint/lint-exceeding-bitshifts.opt.stderr @@ -5,7 +5,7 @@ LL | const N: i32 = T::N << 42; | ^^^^^^^^^^ attempt to shift left with overflow | note: the lint level is defined here - --> $DIR/lint-exceeding-bitshifts.rs:8:9 + --> $DIR/lint-exceeding-bitshifts.rs:9:9 | LL | #![warn(arithmetic_overflow, const_err)] | ^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/lint/lint-exceeding-bitshifts.opt_with_overflow_checks.stderr b/src/test/ui/lint/lint-exceeding-bitshifts.opt_with_overflow_checks.stderr index 0c328a2594a..8dbfeff7972 100644 --- a/src/test/ui/lint/lint-exceeding-bitshifts.opt_with_overflow_checks.stderr +++ b/src/test/ui/lint/lint-exceeding-bitshifts.opt_with_overflow_checks.stderr @@ -5,7 +5,7 @@ LL | const N: i32 = T::N << 42; | ^^^^^^^^^^ attempt to shift left with overflow | note: the lint level is defined here - --> $DIR/lint-exceeding-bitshifts.rs:8:9 + --> $DIR/lint-exceeding-bitshifts.rs:9:9 | LL | #![warn(arithmetic_overflow, const_err)] | ^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/lint/lint-exceeding-bitshifts.rs b/src/test/ui/lint/lint-exceeding-bitshifts.rs index 565bef49c9f..4d56d103a83 100644 --- a/src/test/ui/lint/lint-exceeding-bitshifts.rs +++ b/src/test/ui/lint/lint-exceeding-bitshifts.rs @@ -3,11 +3,11 @@ //[opt]compile-flags: -O //[opt_with_overflow_checks]compile-flags: -C overflow-checks=on -O // build-pass +// ignore-pass (test emits codegen-time warnings and verifies that they are not errors) #![crate_type="lib"] #![warn(arithmetic_overflow, const_err)] -#![allow(unused_variables)] -#![allow(dead_code)] + pub trait Foo { const N: i32; diff --git a/src/test/ui/lint/use_suggestion_json.rs b/src/test/ui/lint/use_suggestion_json.rs index 1828b8c2dc7..d7efa4aac65 100644 --- a/src/test/ui/lint/use_suggestion_json.rs +++ b/src/test/ui/lint/use_suggestion_json.rs @@ -1,5 +1,6 @@ // ignore-cloudabi // ignore-windows +// ignore-sgx std::os::fortanix_sgx::usercalls::alloc::Iter changes compiler suggestions // compile-flags: --error-format pretty-json --json=diagnostic-rendered-ansi // The output for humans should just highlight the whole span without showing diff --git a/src/test/ui/lint/use_suggestion_json.stderr b/src/test/ui/lint/use_suggestion_json.stderr index 7176f17bc3f..d0d91bb61f4 100644 --- a/src/test/ui/lint/use_suggestion_json.stderr +++ b/src/test/ui/lint/use_suggestion_json.stderr @@ -72,10 +72,10 @@ mod foo { "spans": [ { "file_name": "$DIR/use_suggestion_json.rs", - "byte_start": 471, - "byte_end": 475, - "line_start": 12, - "line_end": 12, + "byte_start": 560, + "byte_end": 564, + "line_start": 13, + "line_end": 13, "column_start": 12, "column_end": 16, "is_primary": true, @@ -94,16 +94,16 @@ mod foo { ], "children": [ { - "message": "possible candidates are found in other modules, you can import them into scope", + "message": "consider importing one of these items", "code": null, "level": "help", "spans": [ { "file_name": "$DIR/use_suggestion_json.rs", - "byte_start": 448, - "byte_end": 448, - "line_start": 11, - "line_end": 11, + "byte_start": 537, + "byte_end": 537, + "line_start": 12, + "line_end": 12, "column_start": 1, "column_end": 1, "is_primary": true, @@ -123,10 +123,10 @@ mod foo { }, { "file_name": "$DIR/use_suggestion_json.rs", - "byte_start": 448, - "byte_end": 448, - "line_start": 11, - "line_end": 11, + "byte_start": 537, + "byte_end": 537, + "line_start": 12, + "line_end": 12, "column_start": 1, "column_end": 1, "is_primary": true, @@ -146,10 +146,10 @@ mod foo { }, { "file_name": "$DIR/use_suggestion_json.rs", - "byte_start": 448, - "byte_end": 448, - "line_start": 11, - "line_end": 11, + "byte_start": 537, + "byte_end": 537, + "line_start": 12, + "line_end": 12, "column_start": 1, "column_end": 1, "is_primary": true, @@ -169,10 +169,10 @@ mod foo { }, { "file_name": "$DIR/use_suggestion_json.rs", - "byte_start": 448, - "byte_end": 448, - "line_start": 11, - "line_end": 11, + "byte_start": 537, + "byte_end": 537, + "line_start": 12, + "line_end": 12, "column_start": 1, "column_end": 1, "is_primary": true, @@ -192,10 +192,10 @@ mod foo { }, { "file_name": "$DIR/use_suggestion_json.rs", - "byte_start": 448, - "byte_end": 448, - "line_start": 11, - "line_end": 11, + "byte_start": 537, + "byte_end": 537, + "line_start": 12, + "line_end": 12, "column_start": 1, "column_end": 1, "is_primary": true, @@ -215,10 +215,10 @@ mod foo { }, { "file_name": "$DIR/use_suggestion_json.rs", - "byte_start": 448, - "byte_end": 448, - "line_start": 11, - "line_end": 11, + "byte_start": 537, + "byte_end": 537, + "line_start": 12, + "line_end": 12, "column_start": 1, "column_end": 1, "is_primary": true, @@ -238,10 +238,10 @@ mod foo { }, { "file_name": "$DIR/use_suggestion_json.rs", - "byte_start": 448, - "byte_end": 448, - "line_start": 11, - "line_end": 11, + "byte_start": 537, + "byte_end": 537, + "line_start": 12, + "line_end": 12, "column_start": 1, "column_end": 1, "is_primary": true, @@ -261,10 +261,10 @@ mod foo { }, { "file_name": "$DIR/use_suggestion_json.rs", - "byte_start": 448, - "byte_end": 448, - "line_start": 11, - "line_end": 11, + "byte_start": 537, + "byte_end": 537, + "line_start": 12, + "line_end": 12, "column_start": 1, "column_end": 1, "is_primary": true, @@ -284,10 +284,10 @@ mod foo { }, { "file_name": "$DIR/use_suggestion_json.rs", - "byte_start": 448, - "byte_end": 448, - "line_start": 11, - "line_end": 11, + "byte_start": 537, + "byte_end": 537, + "line_start": 12, + "line_end": 12, "column_start": 1, "column_end": 1, "is_primary": true, @@ -307,10 +307,10 @@ mod foo { }, { "file_name": "$DIR/use_suggestion_json.rs", - "byte_start": 448, - "byte_end": 448, - "line_start": 11, - "line_end": 11, + "byte_start": 537, + "byte_end": 537, + "line_start": 12, + "line_end": 12, "column_start": 1, "column_end": 1, "is_primary": true, @@ -330,10 +330,10 @@ mod foo { }, { "file_name": "$DIR/use_suggestion_json.rs", - "byte_start": 448, - "byte_end": 448, - "line_start": 11, - "line_end": 11, + "byte_start": 537, + "byte_end": 537, + "line_start": 12, + "line_end": 12, "column_start": 1, "column_end": 1, "is_primary": true, @@ -353,10 +353,10 @@ mod foo { }, { "file_name": "$DIR/use_suggestion_json.rs", - "byte_start": 448, - "byte_end": 448, - "line_start": 11, - "line_end": 11, + "byte_start": 537, + "byte_end": 537, + "line_start": 12, + "line_end": 12, "column_start": 1, "column_end": 1, "is_primary": true, @@ -380,12 +380,12 @@ mod foo { } ], "rendered": "\u001b[0m\u001b[1m\u001b[38;5;9merror[E0412]\u001b[0m\u001b[0m\u001b[1m: cannot find type `Iter` in this scope\u001b[0m -\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m--> \u001b[0m\u001b[0m$DIR/use_suggestion_json.rs:12:12\u001b[0m +\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m--> \u001b[0m\u001b[0m$DIR/use_suggestion_json.rs:13:12\u001b[0m \u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m \u001b[0m\u001b[1m\u001b[38;5;12mLL\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m| \u001b[0m\u001b[0m let x: Iter;\u001b[0m \u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m| \u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;9m^^^^\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;9mnot found in this scope\u001b[0m \u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m -\u001b[0m\u001b[1m\u001b[38;5;14mhelp\u001b[0m\u001b[0m: possible candidates are found in other modules, you can import them into scope\u001b[0m +\u001b[0m\u001b[1m\u001b[38;5;14mhelp\u001b[0m\u001b[0m: consider importing one of these items\u001b[0m \u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m \u001b[0m\u001b[1m\u001b[38;5;12mLL\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m| \u001b[0m\u001b[0muse std::collections::binary_heap::Iter;\u001b[0m \u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m diff --git a/src/test/ui/macros/macro-outer-attributes.stderr b/src/test/ui/macros/macro-outer-attributes.stderr index 86a6baca053..8e064d980af 100644 --- a/src/test/ui/macros/macro-outer-attributes.stderr +++ b/src/test/ui/macros/macro-outer-attributes.stderr @@ -4,7 +4,7 @@ error[E0425]: cannot find function `bar` in module `a` LL | a::bar(); | ^^^ not found in `a` | -help: possible candidate is found in another module, you can import it into scope +help: consider importing this function | LL | use b::bar; | diff --git a/src/test/ui/match/issue-70972-dyn-trait.rs b/src/test/ui/match/issue-70972-dyn-trait.rs new file mode 100644 index 00000000000..a9b2699cafd --- /dev/null +++ b/src/test/ui/match/issue-70972-dyn-trait.rs @@ -0,0 +1,10 @@ +const F: &'static dyn Send = &7u32; + +fn main() { + let a: &dyn Send = &7u32; + match a { + F => panic!(), + //~^ ERROR trait objects cannot be used in patterns + _ => {} + } +} diff --git a/src/test/ui/match/issue-70972-dyn-trait.stderr b/src/test/ui/match/issue-70972-dyn-trait.stderr new file mode 100644 index 00000000000..a4e827357de --- /dev/null +++ b/src/test/ui/match/issue-70972-dyn-trait.stderr @@ -0,0 +1,8 @@ +error: trait objects cannot be used in patterns + --> $DIR/issue-70972-dyn-trait.rs:6:9 + | +LL | F => panic!(), + | ^ + +error: aborting due to previous error + diff --git a/src/test/ui/mismatched_types/issue-35030.stderr b/src/test/ui/mismatched_types/issue-35030.stderr index 6fb04ef5c99..9f4e4398984 100644 --- a/src/test/ui/mismatched_types/issue-35030.stderr +++ b/src/test/ui/mismatched_types/issue-35030.stderr @@ -9,8 +9,6 @@ LL | Some(true) | = note: expected type parameter `bool` (type parameter `bool`) found type `bool` (`bool`) - = help: type parameters must be constrained to match other types - = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters error: aborting due to previous error diff --git a/src/test/ui/namespace/namespace-mix.stderr b/src/test/ui/namespace/namespace-mix.stderr index f82c83fd5b0..c80055f00d7 100644 --- a/src/test/ui/namespace/namespace-mix.stderr +++ b/src/test/ui/namespace/namespace-mix.stderr @@ -12,7 +12,7 @@ help: a tuple struct with a similar name exists | LL | check(m1::TS); | ^^ -help: possible better candidates are found in other modules, you can import them into scope +help: consider importing one of these items instead | LL | use m2::S; | @@ -35,7 +35,7 @@ help: a tuple struct with a similar name exists | LL | check(xm1::TS); | ^^ -help: possible better candidates are found in other modules, you can import them into scope +help: consider importing one of these items instead | LL | use m2::S; | @@ -57,7 +57,7 @@ help: a tuple variant with a similar name exists | LL | check(m7::TV); | ^^ -help: possible better candidates are found in other modules, you can import them into scope +help: consider importing one of these items instead | LL | use m8::V; | @@ -79,7 +79,7 @@ help: a tuple variant with a similar name exists | LL | check(xm7::TV); | ^^ -help: possible better candidates are found in other modules, you can import them into scope +help: consider importing one of these items instead | LL | use m8::V; | diff --git a/src/test/ui/nll/type-check-pointer-comparisons.rs b/src/test/ui/nll/type-check-pointer-comparisons.rs index 298a6ef7ab3..3c900356fab 100644 --- a/src/test/ui/nll/type-check-pointer-comparisons.rs +++ b/src/test/ui/nll/type-check-pointer-comparisons.rs @@ -21,13 +21,13 @@ fn compare_fn_ptr<'a, 'b, 'c>(f: fn(&'c mut &'a i32), g: fn(&'c mut &'b i32)) { } fn compare_hr_fn_ptr<'a>(f: fn(&'a i32), g: fn(&i32)) { - f == g; - //~^ ERROR higher-ranked subtype error + // Ideally this should compile with the operands swapped as well, but HIR + // type checking prevents it (and stops compilation) for now. + f == g; // OK } fn compare_const_fn_ptr<'a>(f: *const fn(&'a i32), g: *const fn(&i32)) { - f == g; - //~^ ERROR higher-ranked subtype error + f == g; // OK } fn main() {} diff --git a/src/test/ui/nll/type-check-pointer-comparisons.stderr b/src/test/ui/nll/type-check-pointer-comparisons.stderr index 0fc7480260f..f350b861eb6 100644 --- a/src/test/ui/nll/type-check-pointer-comparisons.stderr +++ b/src/test/ui/nll/type-check-pointer-comparisons.stderr @@ -76,17 +76,5 @@ LL | f == g; help: `'a` and `'b` must be the same: replace one with the other -error: higher-ranked subtype error - --> $DIR/type-check-pointer-comparisons.rs:24:5 - | -LL | f == g; - | ^^^^^^ - -error: higher-ranked subtype error - --> $DIR/type-check-pointer-comparisons.rs:29:5 - | -LL | f == g; - | ^^^^^^ - -error: aborting due to 8 previous errors +error: aborting due to 6 previous errors diff --git a/src/test/ui/no-implicit-prelude-nested.stderr b/src/test/ui/no-implicit-prelude-nested.stderr index e57d8af5f99..8a26366d751 100644 --- a/src/test/ui/no-implicit-prelude-nested.stderr +++ b/src/test/ui/no-implicit-prelude-nested.stderr @@ -4,7 +4,7 @@ error[E0405]: cannot find trait `Add` in this scope LL | impl Add for Test {} | ^^^ not found in this scope | -help: possible candidate is found in another module, you can import it into scope +help: consider importing this trait | LL | use std::ops::Add; | @@ -15,7 +15,7 @@ error[E0404]: expected trait, found derive macro `Clone` LL | impl Clone for Test {} | ^^^^^ not a trait | -help: possible better candidates are found in other modules, you can import them into scope +help: consider importing one of these items instead | LL | use std::clone::Clone; | @@ -28,7 +28,7 @@ error[E0405]: cannot find trait `Iterator` in this scope LL | impl Iterator for Test {} | ^^^^^^^^ not found in this scope | -help: possible candidates are found in other modules, you can import them into scope +help: consider importing one of these items | LL | use std::iter::Iterator; | @@ -41,7 +41,7 @@ error[E0405]: cannot find trait `ToString` in this scope LL | impl ToString for Test {} | ^^^^^^^^ not found in this scope | -help: possible candidates are found in other modules, you can import them into scope +help: consider importing one of these items | LL | use std::prelude::v1::ToString; | @@ -60,7 +60,7 @@ error[E0425]: cannot find function `drop` in this scope LL | drop(2) | ^^^^ not found in this scope | -help: possible candidates are found in other modules, you can import them into scope +help: consider importing one of these items | LL | use std::mem::drop; | @@ -73,7 +73,7 @@ error[E0405]: cannot find trait `Add` in this scope LL | impl Add for Test {} | ^^^ not found in this scope | -help: possible candidate is found in another module, you can import it into scope +help: consider importing this trait | LL | use std::ops::Add; | @@ -84,7 +84,7 @@ error[E0404]: expected trait, found derive macro `Clone` LL | impl Clone for Test {} | ^^^^^ not a trait | -help: possible better candidates are found in other modules, you can import them into scope +help: consider importing one of these items instead | LL | use std::clone::Clone; | @@ -97,7 +97,7 @@ error[E0405]: cannot find trait `Iterator` in this scope LL | impl Iterator for Test {} | ^^^^^^^^ not found in this scope | -help: possible candidates are found in other modules, you can import them into scope +help: consider importing one of these items | LL | use std::iter::Iterator; | @@ -110,7 +110,7 @@ error[E0405]: cannot find trait `ToString` in this scope LL | impl ToString for Test {} | ^^^^^^^^ not found in this scope | -help: possible candidates are found in other modules, you can import them into scope +help: consider importing one of these items | LL | use std::prelude::v1::ToString; | @@ -129,7 +129,7 @@ error[E0425]: cannot find function `drop` in this scope LL | drop(2) | ^^^^ not found in this scope | -help: possible candidates are found in other modules, you can import them into scope +help: consider importing one of these items | LL | use std::mem::drop; | @@ -142,7 +142,7 @@ error[E0405]: cannot find trait `Add` in this scope LL | impl Add for Test {} | ^^^ not found in this scope | -help: possible candidate is found in another module, you can import it into scope +help: consider importing this trait | LL | use std::ops::Add; | @@ -153,7 +153,7 @@ error[E0404]: expected trait, found derive macro `Clone` LL | impl Clone for Test {} | ^^^^^ not a trait | -help: possible better candidates are found in other modules, you can import them into scope +help: consider importing one of these items instead | LL | use std::clone::Clone; | @@ -166,7 +166,7 @@ error[E0405]: cannot find trait `Iterator` in this scope LL | impl Iterator for Test {} | ^^^^^^^^ not found in this scope | -help: possible candidates are found in other modules, you can import them into scope +help: consider importing one of these items | LL | use std::iter::Iterator; | @@ -179,7 +179,7 @@ error[E0405]: cannot find trait `ToString` in this scope LL | impl ToString for Test {} | ^^^^^^^^ not found in this scope | -help: possible candidates are found in other modules, you can import them into scope +help: consider importing one of these items | LL | use std::prelude::v1::ToString; | @@ -198,7 +198,7 @@ error[E0425]: cannot find function `drop` in this scope LL | drop(2) | ^^^^ not found in this scope | -help: possible candidates are found in other modules, you can import them into scope +help: consider importing one of these items | LL | use std::mem::drop; | diff --git a/src/test/ui/no-implicit-prelude.stderr b/src/test/ui/no-implicit-prelude.stderr index 8b99529f4dd..9cda4f64c79 100644 --- a/src/test/ui/no-implicit-prelude.stderr +++ b/src/test/ui/no-implicit-prelude.stderr @@ -4,7 +4,7 @@ error[E0405]: cannot find trait `Add` in this scope LL | impl Add for Test {} | ^^^ not found in this scope | -help: possible candidate is found in another module, you can import it into scope +help: consider importing this trait | LL | use std::ops::Add; | @@ -15,7 +15,7 @@ error[E0404]: expected trait, found derive macro `Clone` LL | impl Clone for Test {} | ^^^^^ not a trait | -help: possible better candidates are found in other modules, you can import them into scope +help: consider importing one of these items instead | LL | use std::clone::Clone; | @@ -28,7 +28,7 @@ error[E0405]: cannot find trait `Iterator` in this scope LL | impl Iterator for Test {} | ^^^^^^^^ not found in this scope | -help: possible candidates are found in other modules, you can import them into scope +help: consider importing one of these items | LL | use std::iter::Iterator; | @@ -41,7 +41,7 @@ error[E0405]: cannot find trait `ToString` in this scope LL | impl ToString for Test {} | ^^^^^^^^ not found in this scope | -help: possible candidates are found in other modules, you can import them into scope +help: consider importing one of these items | LL | use std::prelude::v1::ToString; | @@ -60,7 +60,7 @@ error[E0425]: cannot find function `drop` in this scope LL | drop(2) | ^^^^ not found in this scope | -help: possible candidates are found in other modules, you can import them into scope +help: consider importing one of these items | LL | use std::mem::drop; | diff --git a/src/test/ui/numbers-arithmetic/saturating-float-casts.rs b/src/test/ui/numbers-arithmetic/saturating-float-casts.rs index f13964fb386..e6d0c94a02f 100644 --- a/src/test/ui/numbers-arithmetic/saturating-float-casts.rs +++ b/src/test/ui/numbers-arithmetic/saturating-float-casts.rs @@ -1,15 +1,22 @@ // run-pass +// compile-flags:-Zmir-opt-level=0 // Tests saturating float->int casts. See u128-as-f32.rs for the opposite direction. -// compile-flags: -Z saturating-float-casts +// +// Some of these tests come from a similar file in miri, +// tests/run-pass/float.rs. Individual test cases are potentially duplicated +// with the previously existing tests, but since this runs so quickly anyway, +// we're not spending the time to figure out exactly which ones should be +// merged. #![feature(test, stmt_expr_attributes)] +#![feature(track_caller)] #![deny(overflowing_literals)] extern crate test; use std::{f32, f64}; -use std::{u8, i8, u16, i16, u32, i32, u64, i64}; -#[cfg(not(target_os="emscripten"))] -use std::{u128, i128}; +#[cfg(not(target_os = "emscripten"))] +use std::{i128, u128}; +use std::{i16, i32, i64, i8, u16, u32, u64, u8}; use test::black_box; macro_rules! test { @@ -17,31 +24,18 @@ macro_rules! test { // black_box disables constant evaluation to test run-time conversions: assert_eq!(black_box::<$src_ty>($val) as $dest_ty, $expected, "run-time {} -> {}", stringify!($src_ty), stringify!($dest_ty)); - ); - - ($fval:expr, f* -> $ity:ident, $ival:expr) => ( - test!($fval, f32 -> $ity, $ival); - test!($fval, f64 -> $ity, $ival); - ) -} -// This macro tests const eval in addition to run-time evaluation. -// If and when saturating casts are adopted, this macro should be merged with test!() to ensure -// that run-time and const eval agree on inputs that currently trigger a const eval error. -macro_rules! test_c { - ($val:expr, $src_ty:ident -> $dest_ty:ident, $expected:expr) => ({ - test!($val, $src_ty -> $dest_ty, $expected); { const X: $src_ty = $val; const Y: $dest_ty = X as $dest_ty; assert_eq!(Y, $expected, "const eval {} -> {}", stringify!($src_ty), stringify!($dest_ty)); } - }); + ); ($fval:expr, f* -> $ity:ident, $ival:expr) => ( - test_c!($fval, f32 -> $ity, $ival); - test_c!($fval, f64 -> $ity, $ival); + test!($fval, f32 -> $ity, $ival); + test!($fval, f64 -> $ity, $ival); ) } @@ -55,11 +49,11 @@ macro_rules! common_fptoi_tests { // as well, the test is just slightly misplaced. test!($ity::MIN as $fty, $fty -> $ity, $ity::MIN); test!($ity::MAX as $fty, $fty -> $ity, $ity::MAX); - test_c!(0., $fty -> $ity, 0); - test_c!($fty::MIN_POSITIVE, $fty -> $ity, 0); + test!(0., $fty -> $ity, 0); + test!($fty::MIN_POSITIVE, $fty -> $ity, 0); test!(-0.9, $fty -> $ity, 0); - test_c!(1., $fty -> $ity, 1); - test_c!(42., $fty -> $ity, 42); + test!(1., $fty -> $ity, 1); + test!(42., $fty -> $ity, 42); )+ }); (f* -> $($ity:ident)+) => ({ @@ -85,11 +79,392 @@ macro_rules! fptoui_tests { }) } +use std::fmt::Debug; + +// Helper function to avoid promotion so that this tests "run-time" casts, not CTFE. +#[track_caller] +#[inline(never)] +fn assert_eq<T: PartialEq + Debug>(x: T, y: T) { + assert_eq!(x, y); +} + +trait FloatToInt<Int>: Copy { + fn cast(self) -> Int; + unsafe fn cast_unchecked(self) -> Int; +} + +impl FloatToInt<i8> for f32 { + fn cast(self) -> i8 { + self as _ + } + unsafe fn cast_unchecked(self) -> i8 { + self.to_int_unchecked() + } +} +impl FloatToInt<i32> for f32 { + fn cast(self) -> i32 { + self as _ + } + unsafe fn cast_unchecked(self) -> i32 { + self.to_int_unchecked() + } +} +impl FloatToInt<u32> for f32 { + fn cast(self) -> u32 { + self as _ + } + unsafe fn cast_unchecked(self) -> u32 { + self.to_int_unchecked() + } +} +impl FloatToInt<i64> for f32 { + fn cast(self) -> i64 { + self as _ + } + unsafe fn cast_unchecked(self) -> i64 { + self.to_int_unchecked() + } +} +impl FloatToInt<u64> for f32 { + fn cast(self) -> u64 { + self as _ + } + unsafe fn cast_unchecked(self) -> u64 { + self.to_int_unchecked() + } +} + +impl FloatToInt<i8> for f64 { + fn cast(self) -> i8 { + self as _ + } + unsafe fn cast_unchecked(self) -> i8 { + self.to_int_unchecked() + } +} +impl FloatToInt<i32> for f64 { + fn cast(self) -> i32 { + self as _ + } + unsafe fn cast_unchecked(self) -> i32 { + self.to_int_unchecked() + } +} +impl FloatToInt<u32> for f64 { + fn cast(self) -> u32 { + self as _ + } + unsafe fn cast_unchecked(self) -> u32 { + self.to_int_unchecked() + } +} +impl FloatToInt<i64> for f64 { + fn cast(self) -> i64 { + self as _ + } + unsafe fn cast_unchecked(self) -> i64 { + self.to_int_unchecked() + } +} +impl FloatToInt<u64> for f64 { + fn cast(self) -> u64 { + self as _ + } + unsafe fn cast_unchecked(self) -> u64 { + self.to_int_unchecked() + } +} +// FIXME emscripten does not support i128 +#[cfg(not(target_os = "emscripten"))] +impl FloatToInt<i128> for f64 { + fn cast(self) -> i128 { + self as _ + } + unsafe fn cast_unchecked(self) -> i128 { + self.to_int_unchecked() + } +} +// FIXME emscripten does not support i128 +#[cfg(not(target_os = "emscripten"))] +impl FloatToInt<u128> for f64 { + fn cast(self) -> u128 { + self as _ + } + unsafe fn cast_unchecked(self) -> u128 { + self.to_int_unchecked() + } +} + +/// Test this cast both via `as` and via `to_int_unchecked` (i.e., it must not saturate). +#[track_caller] +#[inline(never)] +fn test_both_cast<F, I>(x: F, y: I) +where + F: FloatToInt<I>, + I: PartialEq + Debug, +{ + assert_eq!(x.cast(), y); + assert_eq!(unsafe { x.cast_unchecked() }, y); +} + +fn casts() { + // f32 -> i8 + test_both_cast::<f32, i8>(127.99, 127); + test_both_cast::<f32, i8>(-128.99, -128); + + // f32 -> i32 + test_both_cast::<f32, i32>(0.0, 0); + test_both_cast::<f32, i32>(-0.0, 0); + test_both_cast::<f32, i32>(/*0x1p-149*/ f32::from_bits(0x00000001), 0); + test_both_cast::<f32, i32>(/*-0x1p-149*/ f32::from_bits(0x80000001), 0); + test_both_cast::<f32, i32>(/*0x1.19999ap+0*/ f32::from_bits(0x3f8ccccd), 1); + test_both_cast::<f32, i32>(/*-0x1.19999ap+0*/ f32::from_bits(0xbf8ccccd), -1); + test_both_cast::<f32, i32>(1.9, 1); + test_both_cast::<f32, i32>(-1.9, -1); + test_both_cast::<f32, i32>(5.0, 5); + test_both_cast::<f32, i32>(-5.0, -5); + test_both_cast::<f32, i32>(2147483520.0, 2147483520); + test_both_cast::<f32, i32>(-2147483648.0, -2147483648); + // unrepresentable casts + assert_eq::<i32>(2147483648.0f32 as i32, i32::MAX); + assert_eq::<i32>(-2147483904.0f32 as i32, i32::MIN); + assert_eq::<i32>(f32::MAX as i32, i32::MAX); + assert_eq::<i32>(f32::MIN as i32, i32::MIN); + assert_eq::<i32>(f32::INFINITY as i32, i32::MAX); + assert_eq::<i32>(f32::NEG_INFINITY as i32, i32::MIN); + assert_eq::<i32>(f32::NAN as i32, 0); + assert_eq::<i32>((-f32::NAN) as i32, 0); + + // f32 -> u32 + test_both_cast::<f32, u32>(0.0, 0); + test_both_cast::<f32, u32>(-0.0, 0); + test_both_cast::<f32, u32>(-0.9999999, 0); + test_both_cast::<f32, u32>(/*0x1p-149*/ f32::from_bits(0x1), 0); + test_both_cast::<f32, u32>(/*-0x1p-149*/ f32::from_bits(0x80000001), 0); + test_both_cast::<f32, u32>(/*0x1.19999ap+0*/ f32::from_bits(0x3f8ccccd), 1); + test_both_cast::<f32, u32>(1.9, 1); + test_both_cast::<f32, u32>(5.0, 5); + test_both_cast::<f32, u32>(2147483648.0, 0x8000_0000); + test_both_cast::<f32, u32>(4294967040.0, 0u32.wrapping_sub(256)); + test_both_cast::<f32, u32>(/*-0x1.ccccccp-1*/ f32::from_bits(0xbf666666), 0); + test_both_cast::<f32, u32>(/*-0x1.fffffep-1*/ f32::from_bits(0xbf7fffff), 0); + test_both_cast::<f32, u32>((u32::MAX - 128) as f32, u32::MAX - 255); // rounding loss + + // unrepresentable casts: + + // rounds up and then becomes unrepresentable + assert_eq::<u32>((u32::MAX - 127) as f32 as u32, u32::MAX); + + assert_eq::<u32>(4294967296.0f32 as u32, u32::MAX); + assert_eq::<u32>(-5.0f32 as u32, 0); + assert_eq::<u32>(f32::MAX as u32, u32::MAX); + assert_eq::<u32>(f32::MIN as u32, 0); + assert_eq::<u32>(f32::INFINITY as u32, u32::MAX); + assert_eq::<u32>(f32::NEG_INFINITY as u32, 0); + assert_eq::<u32>(f32::NAN as u32, 0); + assert_eq::<u32>((-f32::NAN) as u32, 0); + + // f32 -> i64 + test_both_cast::<f32, i64>(4294967296.0, 4294967296); + test_both_cast::<f32, i64>(-4294967296.0, -4294967296); + test_both_cast::<f32, i64>(9223371487098961920.0, 9223371487098961920); + test_both_cast::<f32, i64>(-9223372036854775808.0, -9223372036854775808); + + // f64 -> i8 + test_both_cast::<f64, i8>(127.99, 127); + test_both_cast::<f64, i8>(-128.99, -128); + + // f64 -> i32 + test_both_cast::<f64, i32>(0.0, 0); + test_both_cast::<f64, i32>(-0.0, 0); + test_both_cast::<f64, i32>(/*0x1.199999999999ap+0*/ f64::from_bits(0x3ff199999999999a), 1); + test_both_cast::<f64, i32>( + /*-0x1.199999999999ap+0*/ f64::from_bits(0xbff199999999999a), + -1, + ); + test_both_cast::<f64, i32>(1.9, 1); + test_both_cast::<f64, i32>(-1.9, -1); + test_both_cast::<f64, i32>(1e8, 100_000_000); + test_both_cast::<f64, i32>(2147483647.0, 2147483647); + test_both_cast::<f64, i32>(-2147483648.0, -2147483648); + // unrepresentable casts + assert_eq::<i32>(2147483648.0f64 as i32, i32::MAX); + assert_eq::<i32>(-2147483649.0f64 as i32, i32::MIN); + + // f64 -> i64 + test_both_cast::<f64, i64>(0.0, 0); + test_both_cast::<f64, i64>(-0.0, 0); + test_both_cast::<f64, i64>(/*0x0.0000000000001p-1022*/ f64::from_bits(0x1), 0); + test_both_cast::<f64, i64>( + /*-0x0.0000000000001p-1022*/ f64::from_bits(0x8000000000000001), + 0, + ); + test_both_cast::<f64, i64>(/*0x1.199999999999ap+0*/ f64::from_bits(0x3ff199999999999a), 1); + test_both_cast::<f64, i64>( + /*-0x1.199999999999ap+0*/ f64::from_bits(0xbff199999999999a), + -1, + ); + test_both_cast::<f64, i64>(5.0, 5); + test_both_cast::<f64, i64>(5.9, 5); + test_both_cast::<f64, i64>(-5.0, -5); + test_both_cast::<f64, i64>(-5.9, -5); + test_both_cast::<f64, i64>(4294967296.0, 4294967296); + test_both_cast::<f64, i64>(-4294967296.0, -4294967296); + test_both_cast::<f64, i64>(9223372036854774784.0, 9223372036854774784); + test_both_cast::<f64, i64>(-9223372036854775808.0, -9223372036854775808); + // unrepresentable casts + assert_eq::<i64>(9223372036854775808.0f64 as i64, i64::MAX); + assert_eq::<i64>(-9223372036854777856.0f64 as i64, i64::MIN); + assert_eq::<i64>(f64::MAX as i64, i64::MAX); + assert_eq::<i64>(f64::MIN as i64, i64::MIN); + assert_eq::<i64>(f64::INFINITY as i64, i64::MAX); + assert_eq::<i64>(f64::NEG_INFINITY as i64, i64::MIN); + assert_eq::<i64>(f64::NAN as i64, 0); + assert_eq::<i64>((-f64::NAN) as i64, 0); + + // f64 -> u64 + test_both_cast::<f64, u64>(0.0, 0); + test_both_cast::<f64, u64>(-0.0, 0); + test_both_cast::<f64, u64>(-0.99999999999, 0); + test_both_cast::<f64, u64>(5.0, 5); + test_both_cast::<f64, u64>(1e16, 10000000000000000); + test_both_cast::<f64, u64>((u64::MAX - 1024) as f64, u64::MAX - 2047); // rounding loss + test_both_cast::<f64, u64>(9223372036854775808.0, 9223372036854775808); + // unrepresentable casts + assert_eq::<u64>(-5.0f64 as u64, 0); + // rounds up and then becomes unrepresentable + assert_eq::<u64>((u64::MAX - 1023) as f64 as u64, u64::MAX); + assert_eq::<u64>(18446744073709551616.0f64 as u64, u64::MAX); + assert_eq::<u64>(f64::MAX as u64, u64::MAX); + assert_eq::<u64>(f64::MIN as u64, 0); + assert_eq::<u64>(f64::INFINITY as u64, u64::MAX); + assert_eq::<u64>(f64::NEG_INFINITY as u64, 0); + assert_eq::<u64>(f64::NAN as u64, 0); + assert_eq::<u64>((-f64::NAN) as u64, 0); + + // FIXME emscripten does not support i128 + #[cfg(not(target_os = "emscripten"))] + { + // f64 -> i128 + assert_eq::<i128>(f64::MAX as i128, i128::MAX); + assert_eq::<i128>(f64::MIN as i128, i128::MIN); + + // f64 -> u128 + assert_eq::<u128>(f64::MAX as u128, u128::MAX); + assert_eq::<u128>(f64::MIN as u128, 0); + } + + // int -> f32 + assert_eq::<f32>(127i8 as f32, 127.0); + assert_eq::<f32>(2147483647i32 as f32, 2147483648.0); + assert_eq::<f32>((-2147483648i32) as f32, -2147483648.0); + assert_eq::<f32>(1234567890i32 as f32, /*0x1.26580cp+30*/ f32::from_bits(0x4e932c06)); + assert_eq::<f32>(16777217i32 as f32, 16777216.0); + assert_eq::<f32>((-16777217i32) as f32, -16777216.0); + assert_eq::<f32>(16777219i32 as f32, 16777220.0); + assert_eq::<f32>((-16777219i32) as f32, -16777220.0); + assert_eq::<f32>( + 0x7fffff4000000001i64 as f32, + /*0x1.fffffep+62*/ f32::from_bits(0x5effffff), + ); + assert_eq::<f32>( + 0x8000004000000001u64 as i64 as f32, + /*-0x1.fffffep+62*/ f32::from_bits(0xdeffffff), + ); + assert_eq::<f32>( + 0x0020000020000001i64 as f32, + /*0x1.000002p+53*/ f32::from_bits(0x5a000001), + ); + assert_eq::<f32>( + 0xffdfffffdfffffffu64 as i64 as f32, + /*-0x1.000002p+53*/ f32::from_bits(0xda000001), + ); + // FIXME emscripten does not support i128 + #[cfg(not(target_os = "emscripten"))] + { + assert_eq::<f32>(i128::MIN as f32, -170141183460469231731687303715884105728.0f32); + assert_eq::<f32>(u128::MAX as f32, f32::INFINITY); // saturation + } + + // int -> f64 + assert_eq::<f64>(127i8 as f64, 127.0); + assert_eq::<f64>(i16::MIN as f64, -32768.0f64); + assert_eq::<f64>(2147483647i32 as f64, 2147483647.0); + assert_eq::<f64>(-2147483648i32 as f64, -2147483648.0); + assert_eq::<f64>(987654321i32 as f64, 987654321.0); + assert_eq::<f64>(9223372036854775807i64 as f64, 9223372036854775807.0); + assert_eq::<f64>(-9223372036854775808i64 as f64, -9223372036854775808.0); + assert_eq::<f64>(4669201609102990i64 as f64, 4669201609102990.0); // Feigenbaum (?) + assert_eq::<f64>(9007199254740993i64 as f64, 9007199254740992.0); + assert_eq::<f64>(-9007199254740993i64 as f64, -9007199254740992.0); + assert_eq::<f64>(9007199254740995i64 as f64, 9007199254740996.0); + assert_eq::<f64>(-9007199254740995i64 as f64, -9007199254740996.0); + // FIXME emscripten does not support i128 + #[cfg(not(target_os = "emscripten"))] + { + // even that fits... + assert_eq::<f64>(u128::MAX as f64, 340282366920938463463374607431768211455.0f64); + } + + // f32 -> f64 + assert_eq::<u64>((0.0f32 as f64).to_bits(), 0.0f64.to_bits()); + assert_eq::<u64>(((-0.0f32) as f64).to_bits(), (-0.0f64).to_bits()); + assert_eq::<f64>(5.0f32 as f64, 5.0f64); + assert_eq::<f64>( + /*0x1p-149*/ f32::from_bits(0x1) as f64, + /*0x1p-149*/ f64::from_bits(0x36a0000000000000), + ); + assert_eq::<f64>( + /*-0x1p-149*/ f32::from_bits(0x80000001) as f64, + /*-0x1p-149*/ f64::from_bits(0xb6a0000000000000), + ); + assert_eq::<f64>( + /*0x1.fffffep+127*/ f32::from_bits(0x7f7fffff) as f64, + /*0x1.fffffep+127*/ f64::from_bits(0x47efffffe0000000), + ); + assert_eq::<f64>( + /*-0x1.fffffep+127*/ (-f32::from_bits(0x7f7fffff)) as f64, + /*-0x1.fffffep+127*/ -f64::from_bits(0x47efffffe0000000), + ); + assert_eq::<f64>( + /*0x1p-119*/ f32::from_bits(0x4000000) as f64, + /*0x1p-119*/ f64::from_bits(0x3880000000000000), + ); + assert_eq::<f64>( + /*0x1.8f867ep+125*/ f32::from_bits(0x7e47c33f) as f64, + 6.6382536710104395e+37, + ); + assert_eq::<f64>(f32::INFINITY as f64, f64::INFINITY); + assert_eq::<f64>(f32::NEG_INFINITY as f64, f64::NEG_INFINITY); + + // f64 -> f32 + assert_eq::<u32>((0.0f64 as f32).to_bits(), 0.0f32.to_bits()); + assert_eq::<u32>(((-0.0f64) as f32).to_bits(), (-0.0f32).to_bits()); + assert_eq::<f32>(5.0f64 as f32, 5.0f32); + assert_eq::<f32>(/*0x0.0000000000001p-1022*/ f64::from_bits(0x1) as f32, 0.0); + assert_eq::<f32>(/*-0x0.0000000000001p-1022*/ (-f64::from_bits(0x1)) as f32, -0.0); + assert_eq::<f32>( + /*0x1.fffffe0000000p-127*/ f64::from_bits(0x380fffffe0000000) as f32, + /*0x1p-149*/ f32::from_bits(0x800000), + ); + assert_eq::<f32>( + /*0x1.4eae4f7024c7p+108*/ f64::from_bits(0x46b4eae4f7024c70) as f32, + /*0x1.4eae5p+108*/ f32::from_bits(0x75a75728), + ); + assert_eq::<f32>(f64::MAX as f32, f32::INFINITY); + assert_eq::<f32>(f64::MIN as f32, f32::NEG_INFINITY); + assert_eq::<f32>(f64::INFINITY as f32, f32::INFINITY); + assert_eq::<f32>(f64::NEG_INFINITY as f32, f32::NEG_INFINITY); +} + pub fn main() { + casts(); // from miri's tests + common_fptoi_tests!(f* -> i8 i16 i32 i64 u8 u16 u32 u64); fptoui_tests!(f* -> u8 u16 u32 u64); // FIXME emscripten does not support i128 - #[cfg(not(target_os="emscripten"))] { + #[cfg(not(target_os = "emscripten"))] + { common_fptoi_tests!(f* -> i128 u128); fptoui_tests!(f* -> u128); } @@ -97,39 +472,39 @@ pub fn main() { // The following tests cover edge cases for some integer types. // # u8 - test_c!(254., f* -> u8, 254); + test!(254., f* -> u8, 254); test!(256., f* -> u8, 255); // # i8 - test_c!(-127., f* -> i8, -127); + test!(-127., f* -> i8, -127); test!(-129., f* -> i8, -128); - test_c!(126., f* -> i8, 126); + test!(126., f* -> i8, 126); test!(128., f* -> i8, 127); // # i32 // -2147483648. is i32::MIN (exactly) - test_c!(-2147483648., f* -> i32, i32::MIN); + test!(-2147483648., f* -> i32, i32::MIN); // 2147483648. is i32::MAX rounded up test!(2147483648., f32 -> i32, 2147483647); // With 24 significand bits, floats with magnitude in [2^30 + 1, 2^31] are rounded to // multiples of 2^7. Therefore, nextDown(round(i32::MAX)) is 2^31 - 128: - test_c!(2147483520., f32 -> i32, 2147483520); + test!(2147483520., f32 -> i32, 2147483520); // Similarly, nextUp(i32::MIN) is i32::MIN + 2^8 and nextDown(i32::MIN) is i32::MIN - 2^7 test!(-2147483904., f* -> i32, i32::MIN); - test_c!(-2147483520., f* -> i32, -2147483520); + test!(-2147483520., f* -> i32, -2147483520); // # u32 // round(MAX) and nextUp(round(MAX)) - test_c!(4294967040., f* -> u32, 4294967040); + test!(4294967040., f* -> u32, 4294967040); test!(4294967296., f* -> u32, 4294967295); // # u128 - #[cfg(not(target_os="emscripten"))] + #[cfg(not(target_os = "emscripten"))] { // float->int: - test_c!(f32::MAX, f32 -> u128, 0xffffff00000000000000000000000000); + test!(f32::MAX, f32 -> u128, 0xffffff00000000000000000000000000); // nextDown(f32::MAX) = 2^128 - 2 * 2^104 const SECOND_LARGEST_F32: f32 = 340282326356119256160033759537265639424.; - test_c!(SECOND_LARGEST_F32, f32 -> u128, 0xfffffe00000000000000000000000000); + test!(SECOND_LARGEST_F32, f32 -> u128, 0xfffffe00000000000000000000000000); } } diff --git a/src/test/ui/parser/circular_modules_main.stderr b/src/test/ui/parser/circular_modules_main.stderr index 90f81c64835..5d4db8c31a2 100644 --- a/src/test/ui/parser/circular_modules_main.stderr +++ b/src/test/ui/parser/circular_modules_main.stderr @@ -10,7 +10,7 @@ error[E0425]: cannot find function `say_hello` in module `circular_modules_hello LL | circular_modules_hello::say_hello(); | ^^^^^^^^^ not found in `circular_modules_hello` | -help: possible candidate is found in another module, you can import it into scope +help: consider importing this function | LL | use circular_modules_hello::say_hello; | diff --git a/src/test/ui/privacy/privacy-ns1.stderr b/src/test/ui/privacy/privacy-ns1.stderr index 45ca00f55ab..4d2af735fa6 100644 --- a/src/test/ui/privacy/privacy-ns1.stderr +++ b/src/test/ui/privacy/privacy-ns1.stderr @@ -11,7 +11,7 @@ help: a unit struct with a similar name exists | LL | Baz(); | ^^^ -help: possible better candidates are found in other modules, you can import them into scope +help: consider importing one of these items instead | LL | use foo1::Bar; | @@ -33,7 +33,7 @@ help: a unit struct with a similar name exists | LL | Baz(); | ^^^ -help: possible candidates are found in other modules, you can import them into scope +help: consider importing one of these items | LL | use foo1::Bar; | @@ -55,7 +55,7 @@ help: a struct with a similar name exists | LL | let _x: Box<Baz>; | ^^^ -help: possible candidates are found in other modules, you can import them into scope +help: consider importing one of these items | LL | use foo1::Bar; | diff --git a/src/test/ui/privacy/privacy-ns2.stderr b/src/test/ui/privacy/privacy-ns2.stderr index 0c826147a1c..f1aa523742a 100644 --- a/src/test/ui/privacy/privacy-ns2.stderr +++ b/src/test/ui/privacy/privacy-ns2.stderr @@ -4,7 +4,7 @@ error[E0423]: expected function, tuple struct or tuple variant, found trait `Bar LL | Bar(); | ^^^ not a function, tuple struct or tuple variant | -help: possible better candidates are found in other modules, you can import them into scope +help: consider importing one of these items instead | LL | use foo1::Bar; | @@ -26,7 +26,7 @@ help: a unit struct with a similar name exists | LL | Baz(); | ^^^ -help: possible better candidates are found in other modules, you can import them into scope +help: consider importing one of these items instead | LL | use foo1::Bar; | @@ -45,7 +45,7 @@ help: use `=` if you meant to assign | LL | let _x = Bar(); | ^ -help: possible better candidates are found in other modules, you can import them into scope +help: consider importing one of these items instead | LL | use foo1::Bar; | diff --git a/src/test/ui/proc-macro/attributes-on-modules-fail.stderr b/src/test/ui/proc-macro/attributes-on-modules-fail.stderr index f0ab107e151..b37f1bd393c 100644 --- a/src/test/ui/proc-macro/attributes-on-modules-fail.stderr +++ b/src/test/ui/proc-macro/attributes-on-modules-fail.stderr @@ -50,7 +50,7 @@ help: a type alias with a similar name exists | LL | type A = A; | ^ -help: possible candidate is found in another module, you can import it into scope +help: consider importing this struct | LL | use Y; | @@ -65,7 +65,7 @@ help: a type alias with a similar name exists | LL | type A = A; | ^ -help: possible candidate is found in another module, you can import it into scope +help: consider importing this struct | LL | use m::X; | diff --git a/src/test/ui/proc-macro/crt-static.rs b/src/test/ui/proc-macro/crt-static.rs index 90e3d422b3c..97f6265e308 100644 --- a/src/test/ui/proc-macro/crt-static.rs +++ b/src/test/ui/proc-macro/crt-static.rs @@ -3,6 +3,7 @@ // override -Ctarget-feature=-crt-static from compiletest // compile-flags: -Ctarget-feature= // ignore-wasm32 +// ignore-sgx no support for proc-macro crate type // build-pass #![crate_type = "proc-macro"] diff --git a/src/test/ui/proc-macro/generate-mod.stderr b/src/test/ui/proc-macro/generate-mod.stderr index 5a329639e8e..9b946b5e244 100644 --- a/src/test/ui/proc-macro/generate-mod.stderr +++ b/src/test/ui/proc-macro/generate-mod.stderr @@ -4,7 +4,7 @@ error[E0412]: cannot find type `FromOutside` in this scope LL | generate_mod::check!(); | ^^^^^^^^^^^^^^^^^^^^^^^ not found in this scope | - = note: possible candidate is found in another module, you can import it into scope: + = note: consider importing this struct: FromOutside = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) @@ -14,7 +14,7 @@ error[E0412]: cannot find type `Outer` in this scope LL | generate_mod::check!(); | ^^^^^^^^^^^^^^^^^^^^^^^ not found in this scope | - = note: possible candidate is found in another module, you can import it into scope: + = note: consider importing this struct: Outer = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) @@ -24,7 +24,7 @@ error[E0412]: cannot find type `FromOutside` in this scope LL | #[generate_mod::check_attr] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ not found in this scope | - = note: possible candidate is found in another module, you can import it into scope: + = note: consider importing this struct: FromOutside = note: this error originates in an attribute macro (in Nightly builds, run with -Z macro-backtrace for more info) @@ -34,7 +34,7 @@ error[E0412]: cannot find type `OuterAttr` in this scope LL | #[generate_mod::check_attr] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ not found in this scope | - = note: possible candidate is found in another module, you can import it into scope: + = note: consider importing this struct: OuterAttr = note: this error originates in an attribute macro (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/src/test/ui/proc-macro/mixed-site-span.stderr b/src/test/ui/proc-macro/mixed-site-span.stderr index 30a4cd7c116..81d2113c3b2 100644 --- a/src/test/ui/proc-macro/mixed-site-span.stderr +++ b/src/test/ui/proc-macro/mixed-site-span.stderr @@ -27,7 +27,7 @@ LL | pass_dollar_crate!(); | ^^^^^^^^^^^^^^^^^^^^^ not found in `$crate` | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -help: possible candidate is found in another module, you can import it into scope +help: consider importing this struct | LL | use ItemUse; | diff --git a/src/test/ui/resolve/enums-are-namespaced-xc.stderr b/src/test/ui/resolve/enums-are-namespaced-xc.stderr index 61816709ecc..621686dd292 100644 --- a/src/test/ui/resolve/enums-are-namespaced-xc.stderr +++ b/src/test/ui/resolve/enums-are-namespaced-xc.stderr @@ -4,7 +4,7 @@ error[E0425]: cannot find value `A` in crate `namespaced_enums` LL | let _ = namespaced_enums::A; | ^ not found in `namespaced_enums` | -help: possible candidate is found in another module, you can import it into scope +help: consider importing this unit variant | LL | use namespaced_enums::Foo::A; | @@ -15,7 +15,7 @@ error[E0425]: cannot find function, tuple struct or tuple variant `B` in crate ` LL | let _ = namespaced_enums::B(10); | ^ not found in `namespaced_enums` | -help: possible candidate is found in another module, you can import it into scope +help: consider importing this tuple variant | LL | use namespaced_enums::Foo::B; | @@ -26,7 +26,7 @@ error[E0422]: cannot find struct, variant or union type `C` in crate `namespaced LL | let _ = namespaced_enums::C { a: 10 }; | ^ not found in `namespaced_enums` | -help: possible candidate is found in another module, you can import it into scope +help: consider importing this variant | LL | use namespaced_enums::Foo::C; | diff --git a/src/test/ui/resolve/issue-16058.rs b/src/test/ui/resolve/issue-16058.rs index d41023e82c0..048aaf65fbf 100644 --- a/src/test/ui/resolve/issue-16058.rs +++ b/src/test/ui/resolve/issue-16058.rs @@ -1,3 +1,5 @@ +// ignore-sgx std::os::fortanix_sgx::usercalls::raw::Result changes compiler suggestions + pub struct GslResult { pub val: f64, pub err: f64 diff --git a/src/test/ui/resolve/issue-16058.stderr b/src/test/ui/resolve/issue-16058.stderr index 31f4998bd83..c47d22cef5f 100644 --- a/src/test/ui/resolve/issue-16058.stderr +++ b/src/test/ui/resolve/issue-16058.stderr @@ -1,10 +1,10 @@ error[E0574]: expected struct, variant or union type, found enum `Result` - --> $DIR/issue-16058.rs:8:9 + --> $DIR/issue-16058.rs:10:9 | LL | Result { | ^^^^^^ not a struct, variant or union type | -help: possible better candidates are found in other modules, you can import them into scope +help: consider importing one of these items instead | LL | use std::fmt::Result; | diff --git a/src/test/ui/resolve/issue-17518.stderr b/src/test/ui/resolve/issue-17518.stderr index 6098d4f4901..034d0d01bfb 100644 --- a/src/test/ui/resolve/issue-17518.stderr +++ b/src/test/ui/resolve/issue-17518.stderr @@ -4,7 +4,7 @@ error[E0422]: cannot find struct, variant or union type `E` in this scope LL | E { name: "foobar" }; | ^ not found in this scope | -help: possible candidate is found in another module, you can import it into scope +help: consider importing this variant | LL | use SomeEnum::E; | diff --git a/src/test/ui/resolve/issue-21221-1.stderr b/src/test/ui/resolve/issue-21221-1.stderr index 27fd612faca..d3e19534353 100644 --- a/src/test/ui/resolve/issue-21221-1.stderr +++ b/src/test/ui/resolve/issue-21221-1.stderr @@ -4,7 +4,7 @@ error[E0405]: cannot find trait `Mul` in this scope LL | impl Mul for Foo { | ^^^ not found in this scope | -help: possible candidates are found in other modules, you can import them into scope +help: consider importing one of these items | LL | use mul1::Mul; | @@ -19,7 +19,7 @@ error[E0412]: cannot find type `Mul` in this scope LL | fn getMul() -> Mul { | ^^^ not found in this scope | -help: possible candidates are found in other modules, you can import them into scope +help: consider importing one of these items | LL | use mul1::Mul; | @@ -43,7 +43,7 @@ error[E0405]: cannot find trait `Div` in this scope LL | impl Div for Foo { | ^^^ not found in this scope | -help: possible candidate is found in another module, you can import it into scope +help: consider importing this trait | LL | use std::ops::Div; | diff --git a/src/test/ui/resolve/issue-21221-2.stderr b/src/test/ui/resolve/issue-21221-2.stderr index b360fda6f9d..f9263d2af50 100644 --- a/src/test/ui/resolve/issue-21221-2.stderr +++ b/src/test/ui/resolve/issue-21221-2.stderr @@ -4,7 +4,7 @@ error[E0405]: cannot find trait `T` in this scope LL | impl T for Foo { } | ^ not found in this scope | -help: possible candidate is found in another module, you can import it into scope +help: consider importing this trait | LL | use foo::bar::T; | diff --git a/src/test/ui/resolve/issue-21221-3.stderr b/src/test/ui/resolve/issue-21221-3.stderr index f2c94d467e2..f12e5b09bac 100644 --- a/src/test/ui/resolve/issue-21221-3.stderr +++ b/src/test/ui/resolve/issue-21221-3.stderr @@ -4,7 +4,7 @@ error[E0405]: cannot find trait `OuterTrait` in this scope LL | impl OuterTrait for Foo {} | ^^^^^^^^^^ not found in this scope | -help: possible candidate is found in another module, you can import it into scope +help: consider importing this trait | LL | use issue_21221_3::outer::OuterTrait; | diff --git a/src/test/ui/resolve/issue-21221-4.stderr b/src/test/ui/resolve/issue-21221-4.stderr index 0b1527f91bd..fc15444d0c0 100644 --- a/src/test/ui/resolve/issue-21221-4.stderr +++ b/src/test/ui/resolve/issue-21221-4.stderr @@ -4,7 +4,7 @@ error[E0405]: cannot find trait `T` in this scope LL | impl T for Foo {} | ^ not found in this scope | -help: possible candidate is found in another module, you can import it into scope +help: consider importing this trait | LL | use issue_21221_4::T; | diff --git a/src/test/ui/resolve/issue-3907.stderr b/src/test/ui/resolve/issue-3907.stderr index 16436a9accc..4d0b0af58a3 100644 --- a/src/test/ui/resolve/issue-3907.stderr +++ b/src/test/ui/resolve/issue-3907.stderr @@ -9,7 +9,7 @@ help: you might have meant to use `#![feature(trait_alias)]` instead of a `type` | LL | type Foo = dyn issue_3907::Foo; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -help: possible better candidate is found in another module, you can import it into scope +help: consider importing this trait instead | LL | use issue_3907::Foo; | diff --git a/src/test/ui/resolve/privacy-enum-ctor.stderr b/src/test/ui/resolve/privacy-enum-ctor.stderr index 30ac783ea2f..d9b1b9c5955 100644 --- a/src/test/ui/resolve/privacy-enum-ctor.stderr +++ b/src/test/ui/resolve/privacy-enum-ctor.stderr @@ -67,7 +67,7 @@ LL | let _: E = E::Struct; | ^^^^^^^^^ LL | let _: E = E::Unit; | ^^^^^^^ -help: possible better candidates are found in other modules, you can import them into scope +help: consider importing one of these items instead | LL | use std::f32::consts::E; | @@ -99,7 +99,7 @@ LL | let _: E = E::Struct; | ^^^^^^^^^ LL | let _: E = E::Unit; | ^^^^^^^ -help: possible better candidates are found in other modules, you can import them into scope +help: consider importing one of these items instead | LL | use std::f32::consts::E; | @@ -130,7 +130,7 @@ help: an enum with a similar name exists | LL | let _: E = m::n::Z; | ^ -help: possible candidate is found in another module, you can import it into scope +help: consider importing this enum | LL | use m::n::Z; | @@ -163,7 +163,7 @@ help: an enum with a similar name exists | LL | let _: E = m::n::Z::Fn; | ^ -help: possible candidate is found in another module, you can import it into scope +help: consider importing this enum | LL | use m::n::Z; | @@ -181,7 +181,7 @@ help: an enum with a similar name exists | LL | let _: E = m::n::Z::Struct; | ^ -help: possible candidate is found in another module, you can import it into scope +help: consider importing this enum | LL | use m::n::Z; | @@ -210,7 +210,7 @@ help: an enum with a similar name exists | LL | let _: E = m::n::Z::Unit {}; | ^ -help: possible candidate is found in another module, you can import it into scope +help: consider importing this enum | LL | use m::n::Z; | diff --git a/src/test/ui/resolve/privacy-struct-ctor.stderr b/src/test/ui/resolve/privacy-struct-ctor.stderr index baf7dd84eb0..e0305b129a8 100644 --- a/src/test/ui/resolve/privacy-struct-ctor.stderr +++ b/src/test/ui/resolve/privacy-struct-ctor.stderr @@ -33,7 +33,7 @@ error[E0423]: expected value, found struct `xcrate::S` LL | xcrate::S; | ^^^^^^^^^ constructor is not visible here due to private fields | -help: possible better candidate is found in another module, you can import it into scope +help: consider importing this tuple struct instead | LL | use m::S; | diff --git a/src/test/ui/resolve/resolve-primitive-fallback.stderr b/src/test/ui/resolve/resolve-primitive-fallback.stderr index 9d381a8a94e..8611306e82d 100644 --- a/src/test/ui/resolve/resolve-primitive-fallback.stderr +++ b/src/test/ui/resolve/resolve-primitive-fallback.stderr @@ -10,7 +10,7 @@ error[E0412]: cannot find type `u8` in the crate root LL | let _: ::u8; | ^^ not found in the crate root | -help: possible candidate is found in another module, you can import it into scope +help: consider importing this builtin type | LL | use std::primitive::u8; | diff --git a/src/test/ui/resolve/use_suggestion_placement.stderr b/src/test/ui/resolve/use_suggestion_placement.stderr index ef451ea847a..9c337f515ad 100644 --- a/src/test/ui/resolve/use_suggestion_placement.stderr +++ b/src/test/ui/resolve/use_suggestion_placement.stderr @@ -4,7 +4,7 @@ error[E0412]: cannot find type `Path` in this scope LL | type Bar = Path; | ^^^^ not found in this scope | -help: possible candidate is found in another module, you can import it into scope +help: consider importing this struct | LL | use std::path::Path; | @@ -15,7 +15,7 @@ error[E0425]: cannot find value `A` in this scope LL | let _ = A; | ^ not found in this scope | -help: possible candidate is found in another module, you can import it into scope +help: consider importing this constant | LL | use m::A; | @@ -26,7 +26,7 @@ error[E0412]: cannot find type `HashMap` in this scope LL | type Dict<K, V> = HashMap<K, V>; | ^^^^^^^ not found in this scope | -help: possible candidates are found in other modules, you can import them into scope +help: consider importing one of these items | LL | use std::collections::HashMap; | diff --git a/src/test/ui/rust-2018/issue-52202-use-suggestions.stderr b/src/test/ui/rust-2018/issue-52202-use-suggestions.stderr index c712fd048f1..38cd9713d1a 100644 --- a/src/test/ui/rust-2018/issue-52202-use-suggestions.stderr +++ b/src/test/ui/rust-2018/issue-52202-use-suggestions.stderr @@ -4,7 +4,7 @@ error[E0422]: cannot find struct, variant or union type `Drain` in this scope LL | let _d = Drain {}; | ^^^^^ not found in this scope | -help: possible candidates are found in other modules, you can import them into scope +help: consider importing one of these items | LL | use crate::plumbing::Drain; | diff --git a/src/test/ui/self/self_type_keyword.stderr b/src/test/ui/self/self_type_keyword.stderr index fa603276c8e..7997cdc2957 100644 --- a/src/test/ui/self/self_type_keyword.stderr +++ b/src/test/ui/self/self_type_keyword.stderr @@ -66,7 +66,7 @@ error[E0531]: cannot find unit struct, unit variant or constant `Self` in this s LL | mut Self => (), | ^^^^ not found in this scope | -help: possible candidate is found in another module, you can import it into scope +help: consider importing this unit struct | LL | use foo::Self; | diff --git a/src/test/ui/span/issue-35987.stderr b/src/test/ui/span/issue-35987.stderr index 3245d8655e8..2bc3ff4c3b6 100644 --- a/src/test/ui/span/issue-35987.stderr +++ b/src/test/ui/span/issue-35987.stderr @@ -4,7 +4,7 @@ error[E0404]: expected trait, found type parameter `Add` LL | impl<T: Clone, Add> Add for Foo<T> { | ^^^ not a trait | -help: possible better candidate is found in another module, you can import it into scope +help: consider importing this trait instead | LL | use std::ops::Add; | diff --git a/src/test/ui/specialization/specialization-default-projection.stderr b/src/test/ui/specialization/specialization-default-projection.stderr index d03aec7ab30..ac15ab0681a 100644 --- a/src/test/ui/specialization/specialization-default-projection.stderr +++ b/src/test/ui/specialization/specialization-default-projection.stderr @@ -9,7 +9,7 @@ LL | () | = note: expected associated type `<T as Foo>::Assoc` found unit type `()` - = note: consider constraining the associated type `<T as Foo>::Assoc` to `()` or calling a method that returns `<T as Foo>::Assoc` + = help: consider constraining the associated type `<T as Foo>::Assoc` to `()` or calling a method that returns `<T as Foo>::Assoc` = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html error[E0308]: mismatched types @@ -25,7 +25,7 @@ LL | generic::<()>() | = note: expected unit type `()` found associated type `<() as Foo>::Assoc` - = note: consider constraining the associated type `<() as Foo>::Assoc` to `()` + = help: consider constraining the associated type `<() as Foo>::Assoc` to `()` = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html error: aborting due to 2 previous errors diff --git a/src/test/ui/specialization/specialization-default-types.stderr b/src/test/ui/specialization/specialization-default-types.stderr index 257c114252c..7233387eba1 100644 --- a/src/test/ui/specialization/specialization-default-types.stderr +++ b/src/test/ui/specialization/specialization-default-types.stderr @@ -1,6 +1,8 @@ error[E0308]: mismatched types --> $DIR/specialization-default-types.rs:15:9 | +LL | default type Output = Box<T>; + | ----------------------------- expected this associated type LL | default fn generate(self) -> Self::Output { | ------------ expected `<T as Example>::Output` because of return type LL | Box::new(self) @@ -8,8 +10,6 @@ LL | Box::new(self) | = note: expected associated type `<T as Example>::Output` found struct `std::boxed::Box<T>` - = note: consider constraining the associated type `<T as Example>::Output` to `std::boxed::Box<T>` or calling a method that returns `<T as Example>::Output` - = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html error[E0308]: mismatched types --> $DIR/specialization-default-types.rs:25:5 @@ -21,7 +21,7 @@ LL | Example::generate(t) | = note: expected struct `std::boxed::Box<T>` found associated type `<T as Example>::Output` - = note: consider constraining the associated type `<T as Example>::Output` to `std::boxed::Box<T>` + = help: consider constraining the associated type `<T as Example>::Output` to `std::boxed::Box<T>` = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html error: aborting due to 2 previous errors diff --git a/src/test/ui/static/static-mut-not-constant.stderr b/src/test/ui/static/static-mut-not-constant.stderr index 3560be0e29e..a618b49d108 100644 --- a/src/test/ui/static/static-mut-not-constant.stderr +++ b/src/test/ui/static/static-mut-not-constant.stderr @@ -9,6 +9,8 @@ error[E0019]: static contains unimplemented expression type | LL | static mut a: Box<isize> = box 3; | ^ + | + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable error: aborting due to 2 previous errors diff --git a/src/test/ui/suggestions/expected-boxed-future-isnt-pinned.stderr b/src/test/ui/suggestions/expected-boxed-future-isnt-pinned.stderr index ff256eb3094..52e13dbc2dd 100644 --- a/src/test/ui/suggestions/expected-boxed-future-isnt-pinned.stderr +++ b/src/test/ui/suggestions/expected-boxed-future-isnt-pinned.stderr @@ -12,8 +12,6 @@ LL | x | = note: expected struct `std::pin::Pin<std::boxed::Box<(dyn std::future::Future<Output = i32> + std::marker::Send + 'static)>>` found type parameter `F` - = help: type parameters must be constrained to match other types - = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters error[E0308]: mismatched types --> $DIR/expected-boxed-future-isnt-pinned.rs:18:5 @@ -40,8 +38,6 @@ LL | Pin::new(x) | = note: expected struct `std::boxed::Box<dyn std::future::Future<Output = i32> + std::marker::Send>` found type parameter `F` - = help: type parameters must be constrained to match other types - = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters = note: for more on the distinction between the stack and the heap, read https://doc.rust-lang.org/book/ch15-01-box.html, https://doc.rust-lang.org/rust-by-example/std/box.html, and https://doc.rust-lang.org/std/boxed/index.html error[E0277]: `dyn std::future::Future<Output = i32> + std::marker::Send` cannot be unpinned diff --git a/src/test/ui/suggestions/no-extern-crate-in-type.stderr b/src/test/ui/suggestions/no-extern-crate-in-type.stderr index 22aad3b0a9f..876eef2b624 100644 --- a/src/test/ui/suggestions/no-extern-crate-in-type.stderr +++ b/src/test/ui/suggestions/no-extern-crate-in-type.stderr @@ -4,7 +4,7 @@ error[E0412]: cannot find type `Foo` in this scope LL | type Output = Option<Foo>; | ^^^ not found in this scope | -help: possible candidate is found in another module, you can import it into scope +help: consider importing this struct | LL | use foo::Foo; | diff --git a/src/test/ui/suggestions/raw-name-use-suggestion.stderr b/src/test/ui/suggestions/raw-name-use-suggestion.stderr index 62b76318e09..7447cf87ce1 100644 --- a/src/test/ui/suggestions/raw-name-use-suggestion.stderr +++ b/src/test/ui/suggestions/raw-name-use-suggestion.stderr @@ -26,7 +26,7 @@ error[E0425]: cannot find function `r#break` in this scope LL | r#break(); | ^^^^^^^ not found in this scope | -help: possible candidate is found in another module, you can import it into scope +help: consider importing this function | LL | use foo::r#break; | diff --git a/src/test/ui/suggestions/trait-with-missing-associated-type-restriction-fixable.fixed b/src/test/ui/suggestions/trait-with-missing-associated-type-restriction-fixable.fixed new file mode 100644 index 00000000000..8ef7e34ab30 --- /dev/null +++ b/src/test/ui/suggestions/trait-with-missing-associated-type-restriction-fixable.fixed @@ -0,0 +1,43 @@ +// run-rustfix +#![allow(unused)] // for the fixed file + +trait Trait<T = Self> { + type A; + + fn func(&self) -> Self::A; +} + +struct S<T>(T); +impl<K> S<K> { + fn foo<'a, T: Trait + 'a>(&self, _: impl Trait, x: impl Trait<A = usize>, _: T) { + qux(x.func()) //~ ERROR mismatched types + } + + fn ban<T>(x: T) where T: Trait<A = usize> { + qux(x.func()) //~ ERROR mismatched types + } +} + +fn foo<'a, T: Trait + 'a>(_: impl Trait, x: impl Trait<A = usize>, _: T) { + qux(x.func()) //~ ERROR mismatched types +} + +fn bar<T: Trait<A = usize>>(x: T) { + qux(x.func()) //~ ERROR mismatched types +} + +fn foo2(x: impl Trait<i32, A = usize>) { + qux(x.func()) //~ ERROR mismatched types +} + +fn bar2<T: Trait<i32, A = usize>>(x: T) { + qux(x.func()) //~ ERROR mismatched types +} + +fn ban<T>(x: T) where T: Trait<A = usize> { + qux(x.func()) //~ ERROR mismatched types +} + +fn qux(_: usize) {} + +fn main() {} diff --git a/src/test/ui/suggestions/trait-with-missing-associated-type-restriction-fixable.rs b/src/test/ui/suggestions/trait-with-missing-associated-type-restriction-fixable.rs new file mode 100644 index 00000000000..7bd38d0d45d --- /dev/null +++ b/src/test/ui/suggestions/trait-with-missing-associated-type-restriction-fixable.rs @@ -0,0 +1,43 @@ +// run-rustfix +#![allow(unused)] // for the fixed file + +trait Trait<T = Self> { + type A; + + fn func(&self) -> Self::A; +} + +struct S<T>(T); +impl<K> S<K> { + fn foo<'a, T: Trait + 'a>(&self, _: impl Trait, x: impl Trait, _: T) { + qux(x.func()) //~ ERROR mismatched types + } + + fn ban<T>(x: T) where T: Trait { + qux(x.func()) //~ ERROR mismatched types + } +} + +fn foo<'a, T: Trait + 'a>(_: impl Trait, x: impl Trait, _: T) { + qux(x.func()) //~ ERROR mismatched types +} + +fn bar<T: Trait>(x: T) { + qux(x.func()) //~ ERROR mismatched types +} + +fn foo2(x: impl Trait<i32>) { + qux(x.func()) //~ ERROR mismatched types +} + +fn bar2<T: Trait<i32>>(x: T) { + qux(x.func()) //~ ERROR mismatched types +} + +fn ban<T>(x: T) where T: Trait { + qux(x.func()) //~ ERROR mismatched types +} + +fn qux(_: usize) {} + +fn main() {} diff --git a/src/test/ui/suggestions/trait-with-missing-associated-type-restriction-fixable.stderr b/src/test/ui/suggestions/trait-with-missing-associated-type-restriction-fixable.stderr new file mode 100644 index 00000000000..f785f7b84a7 --- /dev/null +++ b/src/test/ui/suggestions/trait-with-missing-associated-type-restriction-fixable.stderr @@ -0,0 +1,94 @@ +error[E0308]: mismatched types + --> $DIR/trait-with-missing-associated-type-restriction-fixable.rs:13:13 + | +LL | qux(x.func()) + | ^^^^^^^^ expected `usize`, found associated type + | + = note: expected type `usize` + found associated type `<impl Trait as Trait>::A` +help: consider constraining the associated type `<impl Trait as Trait>::A` to `usize` + | +LL | fn foo<'a, T: Trait + 'a>(&self, _: impl Trait, x: impl Trait<A = usize>, _: T) { + | ^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/trait-with-missing-associated-type-restriction-fixable.rs:17:13 + | +LL | qux(x.func()) + | ^^^^^^^^ expected `usize`, found associated type + | + = note: expected type `usize` + found associated type `<T as Trait>::A` +help: consider constraining the associated type `<T as Trait>::A` to `usize` + | +LL | fn ban<T>(x: T) where T: Trait<A = usize> { + | ^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/trait-with-missing-associated-type-restriction-fixable.rs:22:9 + | +LL | qux(x.func()) + | ^^^^^^^^ expected `usize`, found associated type + | + = note: expected type `usize` + found associated type `<impl Trait as Trait>::A` +help: consider constraining the associated type `<impl Trait as Trait>::A` to `usize` + | +LL | fn foo<'a, T: Trait + 'a>(_: impl Trait, x: impl Trait<A = usize>, _: T) { + | ^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/trait-with-missing-associated-type-restriction-fixable.rs:26:9 + | +LL | qux(x.func()) + | ^^^^^^^^ expected `usize`, found associated type + | + = note: expected type `usize` + found associated type `<T as Trait>::A` +help: consider constraining the associated type `<T as Trait>::A` to `usize` + | +LL | fn bar<T: Trait<A = usize>>(x: T) { + | ^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/trait-with-missing-associated-type-restriction-fixable.rs:30:9 + | +LL | qux(x.func()) + | ^^^^^^^^ expected `usize`, found associated type + | + = note: expected type `usize` + found associated type `<impl Trait<i32> as Trait<i32>>::A` +help: consider constraining the associated type `<impl Trait<i32> as Trait<i32>>::A` to `usize` + | +LL | fn foo2(x: impl Trait<i32, A = usize>) { + | ^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/trait-with-missing-associated-type-restriction-fixable.rs:34:9 + | +LL | qux(x.func()) + | ^^^^^^^^ expected `usize`, found associated type + | + = note: expected type `usize` + found associated type `<T as Trait<i32>>::A` +help: consider constraining the associated type `<T as Trait<i32>>::A` to `usize` + | +LL | fn bar2<T: Trait<i32, A = usize>>(x: T) { + | ^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/trait-with-missing-associated-type-restriction-fixable.rs:38:9 + | +LL | qux(x.func()) + | ^^^^^^^^ expected `usize`, found associated type + | + = note: expected type `usize` + found associated type `<T as Trait>::A` +help: consider constraining the associated type `<T as Trait>::A` to `usize` + | +LL | fn ban<T>(x: T) where T: Trait<A = usize> { + | ^^^^^^^^^^^ + +error: aborting due to 7 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/suggestions/trait-with-missing-associated-type-restriction.rs b/src/test/ui/suggestions/trait-with-missing-associated-type-restriction.rs new file mode 100644 index 00000000000..7465049787f --- /dev/null +++ b/src/test/ui/suggestions/trait-with-missing-associated-type-restriction.rs @@ -0,0 +1,43 @@ +// These are all the possible variations of this error I could think of for. +// `trait-with-missing-associated-type-restriction-fixable.rs` contains the subset of these that +// can be fixed with `rustfix`. + +trait Trait<T = Self> { + type A; + + fn func(&self) -> Self::A; + fn funk(&self, _: Self::A); +} + +fn foo(_: impl Trait, x: impl Trait) { + qux(x.func()) //~ ERROR mismatched types +} + +fn bar<T: Trait>(x: T) { + qux(x.func()) //~ ERROR mismatched types +} + +fn foo2(x: impl Trait<i32>) { + qux(x.func()) //~ ERROR mismatched types +} + +fn bar2<T: Trait<i32>>(x: T) { + x.funk(3); //~ ERROR mismatched types + qux(x.func()) //~ ERROR mismatched types +} + +fn baz<D: std::fmt::Debug, T: Trait<A = D>>(x: T) { + qux(x.func()) //~ ERROR mismatched types +} + +fn bat(x: &mut dyn Trait<(), A = ()>) { + qux(x.func()) //~ ERROR mismatched types +} + +fn ban<T>(x: T) where T: Trait { + qux(x.func()) //~ ERROR mismatched types +} + +fn qux(_: usize) {} + +fn main() {} diff --git a/src/test/ui/suggestions/trait-with-missing-associated-type-restriction.stderr b/src/test/ui/suggestions/trait-with-missing-associated-type-restriction.stderr new file mode 100644 index 00000000000..5ae1d45c6b7 --- /dev/null +++ b/src/test/ui/suggestions/trait-with-missing-associated-type-restriction.stderr @@ -0,0 +1,103 @@ +error[E0308]: mismatched types + --> $DIR/trait-with-missing-associated-type-restriction.rs:13:9 + | +LL | qux(x.func()) + | ^^^^^^^^ expected `usize`, found associated type + | + = note: expected type `usize` + found associated type `<impl Trait as Trait>::A` +help: consider constraining the associated type `<impl Trait as Trait>::A` to `usize` + | +LL | fn foo(_: impl Trait, x: impl Trait<A = usize>) { + | ^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/trait-with-missing-associated-type-restriction.rs:17:9 + | +LL | qux(x.func()) + | ^^^^^^^^ expected `usize`, found associated type + | + = note: expected type `usize` + found associated type `<T as Trait>::A` +help: consider constraining the associated type `<T as Trait>::A` to `usize` + | +LL | fn bar<T: Trait<A = usize>>(x: T) { + | ^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/trait-with-missing-associated-type-restriction.rs:21:9 + | +LL | qux(x.func()) + | ^^^^^^^^ expected `usize`, found associated type + | + = note: expected type `usize` + found associated type `<impl Trait<i32> as Trait<i32>>::A` +help: consider constraining the associated type `<impl Trait<i32> as Trait<i32>>::A` to `usize` + | +LL | fn foo2(x: impl Trait<i32, A = usize>) { + | ^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/trait-with-missing-associated-type-restriction.rs:25:12 + | +LL | x.funk(3); + | ^ expected associated type, found integer + | + = note: expected associated type `<T as Trait<i32>>::A` + found type `{integer}` +help: a method is available that returns `<T as Trait<i32>>::A` + --> $DIR/trait-with-missing-associated-type-restriction.rs:8:5 + | +LL | fn func(&self) -> Self::A; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ consider calling `Trait::func` +help: consider constraining the associated type `<T as Trait<i32>>::A` to `{integer}` + | +LL | fn bar2<T: Trait<i32, A = {integer}>>(x: T) { + | ^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/trait-with-missing-associated-type-restriction.rs:26:9 + | +LL | qux(x.func()) + | ^^^^^^^^ expected `usize`, found associated type + | + = note: expected type `usize` + found associated type `<T as Trait<i32>>::A` +help: consider constraining the associated type `<T as Trait<i32>>::A` to `usize` + | +LL | fn bar2<T: Trait<i32, A = usize>>(x: T) { + | ^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/trait-with-missing-associated-type-restriction.rs:30:9 + | +LL | fn baz<D: std::fmt::Debug, T: Trait<A = D>>(x: T) { + | - this type parameter +LL | qux(x.func()) + | ^^^^^^^^ expected `usize`, found type parameter `D` + | + = note: expected type `usize` + found type parameter `D` + +error[E0308]: mismatched types + --> $DIR/trait-with-missing-associated-type-restriction.rs:34:9 + | +LL | qux(x.func()) + | ^^^^^^^^ expected `usize`, found `()` + +error[E0308]: mismatched types + --> $DIR/trait-with-missing-associated-type-restriction.rs:38:9 + | +LL | qux(x.func()) + | ^^^^^^^^ expected `usize`, found associated type + | + = note: expected type `usize` + found associated type `<T as Trait>::A` +help: consider constraining the associated type `<T as Trait>::A` to `usize` + | +LL | fn ban<T>(x: T) where T: Trait<A = usize> { + | ^^^^^^^^^^^ + +error: aborting due to 8 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/test-panic-abort-nocapture.rs b/src/test/ui/test-panic-abort-nocapture.rs index 75f79838650..978732a9ec3 100644 --- a/src/test/ui/test-panic-abort-nocapture.rs +++ b/src/test/ui/test-panic-abort-nocapture.rs @@ -7,6 +7,7 @@ // ignore-wasm no panic or subprocess support // ignore-emscripten no panic or subprocess support +// ignore-sgx no subprocess support #![cfg(test)] diff --git a/src/test/ui/test-panic-abort-nocapture.run.stderr b/src/test/ui/test-panic-abort-nocapture.run.stderr index 37fbe3d3ff2..3388813d5a0 100644 --- a/src/test/ui/test-panic-abort-nocapture.run.stderr +++ b/src/test/ui/test-panic-abort-nocapture.run.stderr @@ -1,9 +1,9 @@ thread 'main' panicked at 'assertion failed: `(left == right)` left: `2`, - right: `4`', $DIR/test-panic-abort-nocapture.rs:31:5 + right: `4`', $DIR/test-panic-abort-nocapture.rs:32:5 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace thread 'main' panicked at 'assertion failed: `(left == right)` left: `2`, - right: `4`', $DIR/test-panic-abort-nocapture.rs:25:5 + right: `4`', $DIR/test-panic-abort-nocapture.rs:26:5 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace testing321 diff --git a/src/test/ui/test-panic-abort.rs b/src/test/ui/test-panic-abort.rs index b7bf5a150ea..21e7dc393f5 100644 --- a/src/test/ui/test-panic-abort.rs +++ b/src/test/ui/test-panic-abort.rs @@ -7,6 +7,7 @@ // ignore-wasm no panic or subprocess support // ignore-emscripten no panic or subprocess support +// ignore-sgx no subprocess support #![cfg(test)] diff --git a/src/test/ui/test-panic-abort.run.stdout b/src/test/ui/test-panic-abort.run.stdout index 2f4bc32ed6a..33ddd519030 100644 --- a/src/test/ui/test-panic-abort.run.stdout +++ b/src/test/ui/test-panic-abort.run.stdout @@ -18,7 +18,7 @@ testing123 testing321 thread 'main' panicked at 'assertion failed: `(left == right)` left: `2`, - right: `5`', $DIR/test-panic-abort.rs:32:5 + right: `5`', $DIR/test-panic-abort.rs:33:5 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace diff --git a/src/test/ui/type-alias-enum-variants/enum-variant-generic-args.stderr b/src/test/ui/type-alias-enum-variants/enum-variant-generic-args.stderr index 412b4dbda4f..caea791e653 100644 --- a/src/test/ui/type-alias-enum-variants/enum-variant-generic-args.stderr +++ b/src/test/ui/type-alias-enum-variants/enum-variant-generic-args.stderr @@ -9,8 +9,6 @@ LL | Self::TSVariant(()); | = note: expected type parameter `T` found unit type `()` - = help: type parameters must be constrained to match other types - = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters error[E0109]: type arguments are not allowed for this type --> $DIR/enum-variant-generic-args.rs:15:27 @@ -35,8 +33,6 @@ LL | Self::<()>::TSVariant(()); | = note: expected type parameter `T` found unit type `()` - = help: type parameters must be constrained to match other types - = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters error[E0109]: type arguments are not allowed for this type --> $DIR/enum-variant-generic-args.rs:20:16 @@ -61,8 +57,6 @@ LL | Self::SVariant { v: () }; | = note: expected type parameter `T` found unit type `()` - = help: type parameters must be constrained to match other types - = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters error[E0109]: type arguments are not allowed for this type --> $DIR/enum-variant-generic-args.rs:28:26 @@ -81,8 +75,6 @@ LL | Self::SVariant::<()> { v: () }; | = note: expected type parameter `T` found unit type `()` - = help: type parameters must be constrained to match other types - = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters error[E0109]: type arguments are not allowed for this type --> $DIR/enum-variant-generic-args.rs:31:16 @@ -101,8 +93,6 @@ LL | Self::<()>::SVariant { v: () }; | = note: expected type parameter `T` found unit type `()` - = help: type parameters must be constrained to match other types - = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters error[E0109]: type arguments are not allowed for this type --> $DIR/enum-variant-generic-args.rs:34:16 @@ -127,8 +117,6 @@ LL | Self::<()>::SVariant::<()> { v: () }; | = note: expected type parameter `T` found unit type `()` - = help: type parameters must be constrained to match other types - = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters error[E0109]: type arguments are not allowed for this type --> $DIR/enum-variant-generic-args.rs:41:26 diff --git a/src/test/ui/type/type-check/missing_trait_impl.stderr b/src/test/ui/type/type-check/missing_trait_impl.stderr index 7186d6a542d..30df1261cef 100644 --- a/src/test/ui/type/type-check/missing_trait_impl.stderr +++ b/src/test/ui/type/type-check/missing_trait_impl.stderr @@ -6,7 +6,10 @@ LL | let z = x + y; | | | T | - = note: `T` might need a bound for `std::ops::Add` +help: consider restricting type parameter `T` + | +LL | fn foo<T: std::ops::Add<Output = T>>(x: T, y: T) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0368]: binary assignment operation `+=` cannot be applied to type `T` --> $DIR/missing_trait_impl.rs:9:5 @@ -16,7 +19,10 @@ LL | x += x; | | | cannot use `+=` on type `T` | - = note: `T` might need a bound for `std::ops::AddAssign` +help: consider restricting type parameter `T` + | +LL | fn bar<T: std::ops::AddAssign>(x: T) { + | ^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/typeck/issue-67971.rs b/src/test/ui/typeck/issue-67971.rs new file mode 100644 index 00000000000..8bf725cb5ee --- /dev/null +++ b/src/test/ui/typeck/issue-67971.rs @@ -0,0 +1,9 @@ +struct S {} + +fn foo(ctx: &mut S) -> String { //~ ERROR mismatched types + // Don't suggest to remove semicolon as it won't fix anything + ctx.sleep = 0; + //~^ ERROR no field `sleep` on type `&mut S` +} + +fn main() {} diff --git a/src/test/ui/typeck/issue-67971.stderr b/src/test/ui/typeck/issue-67971.stderr new file mode 100644 index 00000000000..36ad3fcb342 --- /dev/null +++ b/src/test/ui/typeck/issue-67971.stderr @@ -0,0 +1,18 @@ +error[E0609]: no field `sleep` on type `&mut S` + --> $DIR/issue-67971.rs:5:9 + | +LL | ctx.sleep = 0; + | ^^^^^ unknown field + +error[E0308]: mismatched types + --> $DIR/issue-67971.rs:3:24 + | +LL | fn foo(ctx: &mut S) -> String { + | --- ^^^^^^ expected struct `std::string::String`, found `()` + | | + | implicitly returns `()` as its body has no tail or `return` expression + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0308, E0609. +For more information about an error, try `rustc --explain E0308`. diff --git a/src/test/ui/unsized-locals/issue-30276-feature-flagged.rs b/src/test/ui/unsized-locals/issue-30276-feature-flagged.rs new file mode 100644 index 00000000000..4193210b8bd --- /dev/null +++ b/src/test/ui/unsized-locals/issue-30276-feature-flagged.rs @@ -0,0 +1,7 @@ +#![feature(unsized_locals)] + +struct Test([i32]); + +fn main() { + let _x: fn(_) -> Test = Test; +} //~^the size for values of type `[i32]` cannot be known at compilation time diff --git a/src/test/ui/unsized-locals/issue-30276-feature-flagged.stderr b/src/test/ui/unsized-locals/issue-30276-feature-flagged.stderr new file mode 100644 index 00000000000..35f63a91b2b --- /dev/null +++ b/src/test/ui/unsized-locals/issue-30276-feature-flagged.stderr @@ -0,0 +1,14 @@ +error[E0277]: the size for values of type `[i32]` cannot be known at compilation time + --> $DIR/issue-30276-feature-flagged.rs:6:29 + | +LL | let _x: fn(_) -> Test = Test; + | ^^^^ doesn't have a size known at compile-time + | + = help: within `Test`, the trait `std::marker::Sized` is not implemented for `[i32]` + = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait> + = note: required because it appears within the type `Test` + = note: the return type of a function must have a statically known size + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/unsized-locals/issue-30276.rs b/src/test/ui/unsized-locals/issue-30276.rs new file mode 100644 index 00000000000..9c4bf062a40 --- /dev/null +++ b/src/test/ui/unsized-locals/issue-30276.rs @@ -0,0 +1,5 @@ +struct Test([i32]); + +fn main() { + let _x: fn(_) -> Test = Test; +} //~^the size for values of type `[i32]` cannot be known at compilation time diff --git a/src/test/ui/unsized-locals/issue-30276.stderr b/src/test/ui/unsized-locals/issue-30276.stderr new file mode 100644 index 00000000000..d42fddb3a4a --- /dev/null +++ b/src/test/ui/unsized-locals/issue-30276.stderr @@ -0,0 +1,14 @@ +error[E0277]: the size for values of type `[i32]` cannot be known at compilation time + --> $DIR/issue-30276.rs:4:29 + | +LL | let _x: fn(_) -> Test = Test; + | ^^^^ doesn't have a size known at compile-time + | + = help: the trait `std::marker::Sized` is not implemented for `[i32]` + = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait> + = note: all function arguments must have a statically known size + = help: unsized locals are gated as an unstable feature + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/use/use-super-global-path.stderr b/src/test/ui/use/use-super-global-path.stderr index 7f98ac7cd0f..edde26c1fc1 100644 --- a/src/test/ui/use/use-super-global-path.stderr +++ b/src/test/ui/use/use-super-global-path.stderr @@ -22,7 +22,7 @@ error[E0425]: cannot find function `main` in this scope LL | main(); | ^^^^ not found in this scope | -help: possible candidate is found in another module, you can import it into scope +help: consider importing this function | LL | use main; | diff --git a/src/tools/cargo b/src/tools/cargo -Subproject 258c89644c4587273a3ed3ee9522d2640facba4 +Subproject f534844c25cacc5e004404cea835ac85e35ca3f diff --git a/src/tools/miri b/src/tools/miri -Subproject 6ded8aadabda9530a4a7abb6fbbfe09a8e6aa64 +Subproject 7f3366288d126408815eeafa8d7cd6e9f3ea56b diff --git a/src/tools/publish_toolstate.py b/src/tools/publish_toolstate.py index 2da62b6bd99..988a226706d 100755 --- a/src/tools/publish_toolstate.py +++ b/src/tools/publish_toolstate.py @@ -25,10 +25,6 @@ except ImportError: # read privileges on it). CI will fail otherwise. MAINTAINERS = { 'miri': {'oli-obk', 'RalfJung', 'eddyb'}, - 'clippy-driver': { - 'Manishearth', 'llogiq', 'mcarton', 'oli-obk', 'phansch', 'flip1995', - 'yaahc', - }, 'rls': {'Xanewok'}, 'rustfmt': {'topecongiro'}, 'book': {'carols10cents', 'steveklabnik'}, @@ -45,7 +41,6 @@ MAINTAINERS = { REPOS = { 'miri': 'https://github.com/rust-lang/miri', - 'clippy-driver': 'https://github.com/rust-lang/rust-clippy', 'rls': 'https://github.com/rust-lang/rls', 'rustfmt': 'https://github.com/rust-lang/rustfmt', 'book': 'https://github.com/rust-lang/book', diff --git a/src/tools/rls b/src/tools/rls -Subproject 75491db0bff74a14dc6392b1491043bc7c924c6 +Subproject 1cb7c09eb245454648bdecd61fa93bace3041b6 diff --git a/src/tools/rustc-workspace-hack/Cargo.toml b/src/tools/rustc-workspace-hack/Cargo.toml index 7e70b52da4d..cbf7d09f2e4 100644 --- a/src/tools/rustc-workspace-hack/Cargo.toml +++ b/src/tools/rustc-workspace-hack/Cargo.toml @@ -17,6 +17,8 @@ path = "lib.rs" [target.'cfg(windows)'.dependencies.winapi] version = "0.3" features = [ + "aclapi", + "accctrl", "basetsd", "consoleapi", "errhandlingapi", @@ -60,16 +62,18 @@ features = [ [dependencies] curl-sys = { version = "0.4.13", features = ["http2", "libnghttp2-sys"], optional = true } crossbeam-utils = { version = "0.7.2", features = ["nightly"] } +proc-macro2 = { version = "1", features = ["default"] } +quote = { version = "1", features = ["default"] } serde = { version = "1.0.82", features = ['derive'] } serde_json = { version = "1.0.31", features = ["raw_value"] } smallvec-0_6 = { package = "smallvec", version = "0.6", features = ['union', 'may_dangle'] } smallvec = { version = "1.0", features = ['union', 'may_dangle'] } -url = { version = "2.0", features = ['serde'] } syn = { version = "0.15", features = ['full', 'extra-traits'] } +syn-1 = { package = "syn", version = "1", features = ['fold', 'full', 'extra-traits', 'visit'] } +url = { version = "2.0", features = ['serde'] } [target.'cfg(not(windows))'.dependencies] openssl = { version = "0.10.12", optional = true } - [features] all-static = ['openssl/vendored', 'curl-sys/static-curl', 'curl-sys/force-system-lib-on-osx'] diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index 8d38404d31b..1423f1db385 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -131,6 +131,7 @@ const WHITELIST: &[&str] = &[ "polonius-engine", "ppv-lite86", "proc-macro2", + "psm", "punycode", "quick-error", "quote", @@ -160,6 +161,7 @@ const WHITELIST: &[&str] = &[ "sha-1", "smallvec", "stable_deref_trait", + "stacker", "syn", "synstructure", "tempfile", |
