From db303c1d63636ad64223291e2c568005a94c08c9 Mon Sep 17 00:00:00 2001 From: ljedrz Date: Thu, 26 Jul 2018 11:44:05 +0200 Subject: [PATCH 01/17] Minor improvements to bootstrap --- src/bootstrap/compile.rs | 9 ++++----- src/bootstrap/dist.rs | 9 ++++----- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index 04e8e133b03a1..6ed926e9875ec 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -305,8 +305,8 @@ impl Step for StartupObjects { t!(fs::create_dir_all(dst_dir)); for file in &["rsbegin", "rsend"] { - let src_file = &src_dir.join(file.to_string() + ".rs"); - let dst_file = &dst_dir.join(file.to_string() + ".o"); + let src_file = &src_dir.join(file).with_extension("rs"); + let dst_file = &dst_dir.join(file).with_extension("o"); if !up_to_date(src_file, dst_file) { let mut cmd = Command::new(&builder.initial_rustc); builder.run(cmd.env("RUSTC_BOOTSTRAP", "1") @@ -317,7 +317,7 @@ impl Step for StartupObjects { .arg(src_file)); } - builder.copy(dst_file, &sysroot_dir.join(file.to_string() + ".o")); + builder.copy(dst_file, &sysroot_dir.join(file).with_extension("o")); } for obj in ["crt2.o", "dllcrt2.o"].iter() { @@ -1141,8 +1141,7 @@ pub fn run_cargo(builder: &Builder, cargo: &mut Command, stamp: &Path, is_check: None => panic!("no output generated for {:?} {:?}", prefix, extension), }; if is_dylib(path_to_add) { - let candidate = format!("{}.lib", path_to_add); - let candidate = PathBuf::from(candidate); + let candidate = PathBuf::from(path_to_add).with_extension("lib"); if candidate.exists() { deps.push(candidate); } diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index 7b4808ef018f7..ac5964c2b60d4 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -892,7 +892,7 @@ impl Step for Src { builder.run(&mut cmd); builder.remove_dir(&image); - distdir(builder).join(&format!("{}.tar.gz", name)) + distdir(builder).join(PathBuf::from(name).with_extension("tar.gz")) } } @@ -992,9 +992,8 @@ impl Step for PlainSourceTarball { // Create plain source tarball let plain_name = format!("rustc-{}-src", builder.rust_package_vers()); - let mut tarball = distdir(builder).join(&format!("{}.tar.gz", plain_name)); - tarball.set_extension(""); // strip .gz - tarball.set_extension(""); // strip .tar + let tarball_name = PathBuf::from(&plain_name).with_extension("tar.gz"); + let tarball = distdir(builder).join(&plain_name); if let Some(dir) = tarball.parent() { builder.create_dir(&dir); } @@ -1006,7 +1005,7 @@ impl Step for PlainSourceTarball { .arg("--work-dir=.") .current_dir(tmpdir(builder)); builder.run(&mut cmd); - distdir(builder).join(&format!("{}.tar.gz", plain_name)) + distdir(builder).join(&tarball_name) } } From 20151ca7169e9f94d9efe682eee4719d4b4ccdf3 Mon Sep 17 00:00:00 2001 From: csmoe <35686186+csmoe@users.noreply.github.com> Date: Wed, 25 Jul 2018 20:46:10 +0800 Subject: [PATCH 02/17] Suggest on method signature diff between impl and trait --- src/librustc_typeck/check/compare_method.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs index 220dd122b2679..55aa38d942efb 100644 --- a/src/librustc_typeck/check/compare_method.rs +++ b/src/librustc_typeck/check/compare_method.rs @@ -319,6 +319,17 @@ fn compare_predicate_entailment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, E0053, "method `{}` has an incompatible type for trait", trait_m.ident); + if let TypeError::Mutability = terr { + if let Some(trait_err_span) = trait_err_span { + if let Ok(trait_err_str) = tcx.sess.codemap().span_to_snippet(trait_err_span) { + diag.span_suggestion( + impl_err_span, + "consider change the type to match the mutability in trait", + format!("{}", trait_err_str), + ); + } + } + } infcx.note_type_err(&mut diag, &cause, From d5347ff9c909af1c977dbb064c10cecea084d9d7 Mon Sep 17 00:00:00 2001 From: csmoe <35686186+csmoe@users.noreply.github.com> Date: Thu, 26 Jul 2018 21:08:56 +0800 Subject: [PATCH 03/17] Fix ui test --- src/test/ui/issue-13033.stderr | 4 ++++ src/test/ui/mismatched_types/E0053.stderr | 4 ++++ .../ui/mismatched_types/trait-impl-fn-incompatibility.stderr | 4 ++++ 3 files changed, 12 insertions(+) diff --git a/src/test/ui/issue-13033.stderr b/src/test/ui/issue-13033.stderr index 2db3cb80a819e..f06d7360d85b0 100644 --- a/src/test/ui/issue-13033.stderr +++ b/src/test/ui/issue-13033.stderr @@ -9,6 +9,10 @@ LL | fn bar(&mut self, other: &Foo) {} | = note: expected type `fn(&mut Baz, &mut dyn Foo)` found type `fn(&mut Baz, &dyn Foo)` +help: consider change the type to match the mutability in trait + | +LL | fn bar(&mut self, other: &mut Foo) {} + | ^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/mismatched_types/E0053.stderr b/src/test/ui/mismatched_types/E0053.stderr index 1b16694bf2c4d..f707a600f29e3 100644 --- a/src/test/ui/mismatched_types/E0053.stderr +++ b/src/test/ui/mismatched_types/E0053.stderr @@ -21,6 +21,10 @@ LL | fn bar(&mut self) { } | = note: expected type `fn(&Bar)` found type `fn(&mut Bar)` +help: consider change the type to match the mutability in trait + | +LL | fn bar(&self) { } + | ^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/mismatched_types/trait-impl-fn-incompatibility.stderr b/src/test/ui/mismatched_types/trait-impl-fn-incompatibility.stderr index 28b16641e4dd5..631af21cac5ca 100644 --- a/src/test/ui/mismatched_types/trait-impl-fn-incompatibility.stderr +++ b/src/test/ui/mismatched_types/trait-impl-fn-incompatibility.stderr @@ -21,6 +21,10 @@ LL | fn bar(&mut self, bar: &Bar) { } //~ ERROR incompatible type | = note: expected type `fn(&mut Bar, &mut Bar)` found type `fn(&mut Bar, &Bar)` +help: consider change the type to match the mutability in trait + | +LL | fn bar(&mut self, bar: &mut Bar) { } //~ ERROR incompatible type + | ^^^^^^^^ error: aborting due to 2 previous errors From 70cb75c31e5d084da3a06457484096330ca72a61 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 26 Jul 2018 18:29:38 +0200 Subject: [PATCH 04/17] make memrchr use align_offset --- src/libcore/slice/memchr.rs | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/libcore/slice/memchr.rs b/src/libcore/slice/memchr.rs index 7b62e7b0620fd..dbbe1c07c2338 100644 --- a/src/libcore/slice/memchr.rs +++ b/src/libcore/slice/memchr.rs @@ -102,8 +102,24 @@ pub fn memrchr(x: u8, text: &[u8]) -> Option { let ptr = text.as_ptr(); let usize_bytes = mem::size_of::(); + // a version of align_offset that says how much must be *subtracted* + // from a pointer to be aligned. + #[inline(always)] + fn align_offset_down(ptr: *const u8, align: usize) -> usize { + let align_offset = ptr.align_offset(align); + if align_offset > align { + // Not possible to align + usize::max_value() + } else if align_offset == 0 { + 0 + } else { + // E.g. if align=8 and we have to add 1, then we can also subtract 7. + align - align_offset + } + } + // search to an aligned boundary - let end_align = (ptr as usize + len) & (usize_bytes - 1); + let end_align = align_offset_down(unsafe { ptr.offset(len as isize) }, usize_bytes); let mut offset; if end_align > 0 { offset = if end_align >= len { 0 } else { len - end_align }; From 0db4317709cdd84c8a4cc1dc01d1f8af673bdd21 Mon Sep 17 00:00:00 2001 From: QuietMisdreavus Date: Thu, 26 Jul 2018 15:33:25 -0500 Subject: [PATCH 05/17] rustdoc: rework how default passes are chosen --- src/librustdoc/lib.rs | 49 +++++++++++++++++------------------- src/librustdoc/passes/mod.rs | 27 ++++++++++++++++++++ 2 files changed, 50 insertions(+), 26 deletions(-) diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 9ebefdabbb410..00cad5e376a40 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -373,6 +373,10 @@ pub fn main_args(args: &[String]) -> isize { for &name in passes::DEFAULT_PASSES { println!("{:>20}", name); } + println!("\nPasses run with `--document-private-items`:"); + for &name in passes::DEFAULT_PRIVATE_PASSES { + println!("{:>20}", name); + } return 0; } @@ -623,20 +627,16 @@ fn rust_input(cratefile: PathBuf, where R: 'static + Send, F: 'static + Send + FnOnce(Output) -> R { - let mut default_passes = !matches.opt_present("no-defaults"); - let mut passes = matches.opt_strs("passes"); - let mut plugins = matches.opt_strs("plugins"); - - // We hardcode in the passes here, as this is a new flag and we - // are generally deprecating passes. - if matches.opt_present("document-private-items") { - default_passes = false; + let mut default_passes = if matches.opt_present("no-defaults") { + passes::DefaultPassOption::None + } else if matches.opt_present("document-private-items") { + passes::DefaultPassOption::Private + } else { + passes::DefaultPassOption::Default + }; - passes = vec![ - String::from("collapse-docs"), - String::from("unindent-comments"), - ]; - } + let mut manual_passes = matches.opt_strs("passes"); + let mut plugins = matches.opt_strs("plugins"); // First, parse the crate and extract all relevant information. let mut paths = SearchPaths::new(); @@ -706,13 +706,15 @@ where R: 'static + Send, if attr.is_word() { if name == Some("no_default_passes") { report_deprecated_attr("no_default_passes", &diag); - default_passes = false; + if default_passes == passes::DefaultPassOption::Default { + default_passes = passes::DefaultPassOption::None; + } } } else if let Some(value) = attr.value_str() { let sink = match name { Some("passes") => { report_deprecated_attr("passes = \"...\"", &diag); - &mut passes + &mut manual_passes }, Some("plugins") => { report_deprecated_attr("plugins = \"...\"", &diag); @@ -726,20 +728,15 @@ where R: 'static + Send, } if attr.is_word() && name == Some("document_private_items") { - default_passes = false; - - passes = vec![ - String::from("collapse-docs"), - String::from("unindent-comments"), - ]; + if default_passes == passes::DefaultPassOption::Default { + default_passes = passes::DefaultPassOption::Private; + } } } - if default_passes { - for name in passes::DEFAULT_PASSES.iter().rev() { - passes.insert(0, name.to_string()); - } - } + let mut passes: Vec = + passes::defaults(default_passes).iter().map(|p| p.to_string()).collect(); + passes.extend(manual_passes); if !plugins.is_empty() { eprintln!("WARNING: --plugins no longer functions; see CVE-2018-1000622"); diff --git a/src/librustdoc/passes/mod.rs b/src/librustdoc/passes/mod.rs index 63b74ceafacb4..8de4fed5bf0c0 100644 --- a/src/librustdoc/passes/mod.rs +++ b/src/librustdoc/passes/mod.rs @@ -63,6 +63,33 @@ pub const DEFAULT_PASSES: &'static [&'static str] = &[ "propagate-doc-cfg", ]; +pub const DEFAULT_PRIVATE_PASSES: &'static [&'static str] = &[ + "strip-priv-imports", + "collapse-docs", + "unindent-comments", + "propagate-doc-cfg", +]; + +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +pub enum DefaultPassOption { + Default, + Private, + None, +} + +pub fn defaults(default_set: DefaultPassOption) -> &'static [&'static str] { + match default_set { + DefaultPassOption::Default => { + DEFAULT_PASSES + }, + DefaultPassOption::Private => { + DEFAULT_PRIVATE_PASSES + }, + DefaultPassOption::None => { + &[] + }, + } +} struct Stripper<'a> { retained: &'a mut DefIdSet, From 89a81625f4e4e0a065524e1a6c5b4d03289347ea Mon Sep 17 00:00:00 2001 From: Stjepan Glavina Date: Fri, 27 Jul 2018 01:08:13 +0200 Subject: [PATCH 06/17] Impl Send & Sync for JoinHandle --- src/libstd/thread/mod.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/libstd/thread/mod.rs b/src/libstd/thread/mod.rs index 90f054186d161..fcb7fc87cb267 100644 --- a/src/libstd/thread/mod.rs +++ b/src/libstd/thread/mod.rs @@ -1276,6 +1276,9 @@ impl JoinInner { #[stable(feature = "rust1", since = "1.0.0")] pub struct JoinHandle(JoinInner); +unsafe impl Send for JoinHandle {} +unsafe impl Sync for JoinHandle {} + impl JoinHandle { /// Extracts a handle to the underlying thread. /// From efa11da26a882aaf57f7eae747e48d128c474bf3 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Thu, 26 Jul 2018 17:20:02 -0700 Subject: [PATCH 07/17] rustc_metadata: test loading atoi instead of cos Some platforms don't actually have `libm` already linked in the test infrastructure, and then `dynamic_lib::tests::test_loading_cosine` would fail to find the "cos" symbol. Every platform running this test should have `libc` and "atoi" though, so try to use that symbol instead. Fixes #45410. --- src/librustc_metadata/dynamic_lib.rs | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/src/librustc_metadata/dynamic_lib.rs b/src/librustc_metadata/dynamic_lib.rs index d7da0d00012e1..182a071277ece 100644 --- a/src/librustc_metadata/dynamic_lib.rs +++ b/src/librustc_metadata/dynamic_lib.rs @@ -90,30 +90,29 @@ mod tests { use std::mem; #[test] - fn test_loading_cosine() { + fn test_loading_atoi() { if cfg!(windows) { return } - // The math library does not need to be loaded since it is already - // statically linked in - let libm = match DynamicLibrary::open(None) { + // The C library does not need to be loaded since it is already linked in + let lib = match DynamicLibrary::open(None) { Err(error) => panic!("Could not load self as module: {}", error), - Ok(libm) => libm + Ok(lib) => lib }; - let cosine: extern fn(libc::c_double) -> libc::c_double = unsafe { - match libm.symbol("cos") { - Err(error) => panic!("Could not load function cos: {}", error), - Ok(cosine) => mem::transmute::<*mut u8, _>(cosine) + let atoi: extern fn(*const libc::c_char) -> libc::c_int = unsafe { + match lib.symbol("atoi") { + Err(error) => panic!("Could not load function atoi: {}", error), + Ok(atoi) => mem::transmute::<*mut u8, _>(atoi) } }; - let argument = 0.0; - let expected_result = 1.0; - let result = cosine(argument); + let argument = CString::new("1383428980").unwrap(); + let expected_result = 0x52757374; + let result = atoi(argument.as_ptr()); if result != expected_result { - panic!("cos({}) != {} but equaled {} instead", argument, + panic!("atoi({:?}) != {} but equaled {} instead", argument, expected_result, result) } } From e950d22fbf6895b812a120d31a2bdf2515ee16f0 Mon Sep 17 00:00:00 2001 From: Petr Hosek Date: Thu, 26 Jul 2018 17:57:20 -0700 Subject: [PATCH 08/17] Omit the vendor component in Fuchsia triple Previously, using unknown as the vendor value would lead to the same result, but with the multiarch runtimes support in Clang, the target is now used to locate the runtime libraries and so the format is important. The denormalized format with omitted vendor component is the format we use with Clang and should be using for Rust as well. --- src/ci/docker/dist-various-2/Dockerfile | 16 ++++++++-------- .../dist-various-2/build-fuchsia-toolchain.sh | 10 +++++----- ...h64_unknown_fuchsia.rs => aarch64_fuchsia.rs} | 4 ++-- src/librustc_target/spec/fuchsia_base.rs | 2 +- src/librustc_target/spec/mod.rs | 4 ++-- ...6_64_unknown_fuchsia.rs => x86_64_fuchsia.rs} | 4 ++-- src/tools/build-manifest/src/main.rs | 4 ++-- 7 files changed, 22 insertions(+), 22 deletions(-) rename src/librustc_target/spec/{aarch64_unknown_fuchsia.rs => aarch64_fuchsia.rs} (91%) rename src/librustc_target/spec/{x86_64_unknown_fuchsia.rs => x86_64_fuchsia.rs} (91%) diff --git a/src/ci/docker/dist-various-2/Dockerfile b/src/ci/docker/dist-various-2/Dockerfile index e8d6c12de4474..7adb32efa1d41 100644 --- a/src/ci/docker/dist-various-2/Dockerfile +++ b/src/ci/docker/dist-various-2/Dockerfile @@ -34,12 +34,12 @@ COPY scripts/sccache.sh /scripts/ RUN sh /scripts/sccache.sh ENV \ - AR_x86_64_unknown_fuchsia=x86_64-unknown-fuchsia-ar \ - CC_x86_64_unknown_fuchsia=x86_64-unknown-fuchsia-clang \ - CXX_x86_64_unknown_fuchsia=x86_64-unknown-fuchsia-clang++ \ - AR_aarch64_unknown_fuchsia=aarch64-unknown-fuchsia-ar \ - CC_aarch64_unknown_fuchsia=aarch64-unknown-fuchsia-clang \ - CXX_aarch64_unknown_fuchsia=aarch64-unknown-fuchsia-clang++ \ + AR_x86_64_fuchsia=x86_64-fuchsia-ar \ + CC_x86_64_fuchsia=x86_64-fuchsia-clang \ + CXX_x86_64_fuchsia=x86_64-fuchsia-clang++ \ + AR_aarch64_fuchsia=aarch64-fuchsia-ar \ + CC_aarch64_fuchsia=aarch64-fuchsia-clang \ + CXX_aarch64_fuchsia=aarch64-fuchsia-clang++ \ AR_sparcv9_sun_solaris=sparcv9-sun-solaris2.10-ar \ CC_sparcv9_sun_solaris=sparcv9-sun-solaris2.10-gcc \ CXX_sparcv9_sun_solaris=sparcv9-sun-solaris2.10-g++ \ @@ -47,8 +47,8 @@ ENV \ CC_x86_64_sun_solaris=x86_64-sun-solaris2.10-gcc \ CXX_x86_64_sun_solaris=x86_64-sun-solaris2.10-g++ -ENV TARGETS=x86_64-unknown-fuchsia -ENV TARGETS=$TARGETS,aarch64-unknown-fuchsia +ENV TARGETS=x86_64-fuchsia +ENV TARGETS=$TARGETS,aarch64-fuchsia ENV TARGETS=$TARGETS,sparcv9-sun-solaris ENV TARGETS=$TARGETS,wasm32-unknown-unknown ENV TARGETS=$TARGETS,x86_64-sun-solaris diff --git a/src/ci/docker/dist-various-2/build-fuchsia-toolchain.sh b/src/ci/docker/dist-various-2/build-fuchsia-toolchain.sh index ef8f0c37f8c37..ec19f7c4f45d9 100755 --- a/src/ci/docker/dist-various-2/build-fuchsia-toolchain.sh +++ b/src/ci/docker/dist-various-2/build-fuchsia-toolchain.sh @@ -39,7 +39,7 @@ build() { esac hide_output make -j$(getconf _NPROCESSORS_ONLN) $tgt - dst=/usr/local/${arch}-unknown-fuchsia + dst=/usr/local/${arch}-fuchsia mkdir -p $dst cp -a build-${tgt}/sysroot/include $dst/ cp -a build-${tgt}/sysroot/lib $dst/ @@ -55,11 +55,11 @@ rm -rf zircon for arch in x86_64 aarch64; do for tool in clang clang++; do - cat >/usr/local/bin/${arch}-unknown-fuchsia-${tool} </usr/local/bin/${arch}-fuchsia-${tool} < TargetResult { base.max_atomic_width = Some(128); Ok(Target { - llvm_target: "aarch64-unknown-fuchsia".to_string(), + llvm_target: "aarch64-fuchsia".to_string(), target_endian: "little".to_string(), target_pointer_width: "64".to_string(), target_c_int_width: "32".to_string(), @@ -23,7 +23,7 @@ pub fn target() -> TargetResult { arch: "aarch64".to_string(), target_os: "fuchsia".to_string(), target_env: "".to_string(), - target_vendor: "unknown".to_string(), + target_vendor: "".to_string(), linker_flavor: LinkerFlavor::Gcc, options: TargetOptions { abi_blacklist: super::arm_base::abi_blacklist(), diff --git a/src/librustc_target/spec/fuchsia_base.rs b/src/librustc_target/spec/fuchsia_base.rs index 19a66b693f256..b593b83532614 100644 --- a/src/librustc_target/spec/fuchsia_base.rs +++ b/src/librustc_target/spec/fuchsia_base.rs @@ -33,7 +33,7 @@ pub fn opts() -> TargetOptions { executables: true, target_family: Some("unix".to_string()), linker_is_gnu: true, - has_rpath: true, + has_rpath: false, pre_link_args: args, position_independent_executables: true, has_elf_tls: true, diff --git a/src/librustc_target/spec/mod.rs b/src/librustc_target/spec/mod.rs index 9ac6e9835f06f..c5d21cdc46adb 100644 --- a/src/librustc_target/spec/mod.rs +++ b/src/librustc_target/spec/mod.rs @@ -332,8 +332,8 @@ supported_targets! { ("x86_64-apple-darwin", x86_64_apple_darwin), ("i686-apple-darwin", i686_apple_darwin), - ("aarch64-unknown-fuchsia", aarch64_unknown_fuchsia), - ("x86_64-unknown-fuchsia", x86_64_unknown_fuchsia), + ("aarch64-fuchsia", aarch64_fuchsia), + ("x86_64-fuchsia", x86_64_fuchsia), ("x86_64-unknown-l4re-uclibc", x86_64_unknown_l4re_uclibc), diff --git a/src/librustc_target/spec/x86_64_unknown_fuchsia.rs b/src/librustc_target/spec/x86_64_fuchsia.rs similarity index 91% rename from src/librustc_target/spec/x86_64_unknown_fuchsia.rs rename to src/librustc_target/spec/x86_64_fuchsia.rs index a510ec8eb3426..e8fa179887c87 100644 --- a/src/librustc_target/spec/x86_64_unknown_fuchsia.rs +++ b/src/librustc_target/spec/x86_64_fuchsia.rs @@ -18,7 +18,7 @@ pub fn target() -> TargetResult { base.stack_probes = true; Ok(Target { - llvm_target: "x86_64-unknown-fuchsia".to_string(), + llvm_target: "x86_64-fuchsia".to_string(), target_endian: "little".to_string(), target_pointer_width: "64".to_string(), target_c_int_width: "32".to_string(), @@ -26,7 +26,7 @@ pub fn target() -> TargetResult { arch: "x86_64".to_string(), target_os: "fuchsia".to_string(), target_env: "".to_string(), - target_vendor: "unknown".to_string(), + target_vendor: "".to_string(), linker_flavor: LinkerFlavor::Gcc, options: base, }) diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs index bb20678d4a11b..83b2895e1d65d 100644 --- a/src/tools/build-manifest/src/main.rs +++ b/src/tools/build-manifest/src/main.rs @@ -46,9 +46,9 @@ static HOSTS: &'static [&'static str] = &[ static TARGETS: &'static [&'static str] = &[ "aarch64-apple-ios", + "aarch64-fuchsia", "aarch64-linux-android", "aarch64-unknown-cloudabi", - "aarch64-unknown-fuchsia", "aarch64-unknown-linux-gnu", "aarch64-unknown-linux-musl", "arm-linux-androideabi", @@ -101,6 +101,7 @@ static TARGETS: &'static [&'static str] = &[ "wasm32-unknown-unknown", "x86_64-apple-darwin", "x86_64-apple-ios", + "x86_64-fuchsia", "x86_64-linux-android", "x86_64-pc-windows-gnu", "x86_64-pc-windows-msvc", @@ -108,7 +109,6 @@ static TARGETS: &'static [&'static str] = &[ "x86_64-sun-solaris", "x86_64-unknown-cloudabi", "x86_64-unknown-freebsd", - "x86_64-unknown-fuchsia", "x86_64-unknown-linux-gnu", "x86_64-unknown-linux-gnux32", "x86_64-unknown-linux-musl", From 688db1df80b9754c28b79abb141e381861402fca Mon Sep 17 00:00:00 2001 From: Stjepan Glavina Date: Fri, 27 Jul 2018 10:08:02 +0200 Subject: [PATCH 09/17] Add stability attributes --- src/libstd/thread/mod.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libstd/thread/mod.rs b/src/libstd/thread/mod.rs index fcb7fc87cb267..ebd9e8ba73196 100644 --- a/src/libstd/thread/mod.rs +++ b/src/libstd/thread/mod.rs @@ -1276,7 +1276,9 @@ impl JoinInner { #[stable(feature = "rust1", since = "1.0.0")] pub struct JoinHandle(JoinInner); +#[stable(feature = "joinhandle_impl_send_sync", since = "1.29.0")] unsafe impl Send for JoinHandle {} +#[stable(feature = "joinhandle_impl_send_sync", since = "1.29.0")] unsafe impl Sync for JoinHandle {} impl JoinHandle { From 31709562766494d301d372cd7066743c6b79d4d4 Mon Sep 17 00:00:00 2001 From: Shotaro Yamada Date: Fri, 20 Apr 2018 19:53:55 +0900 Subject: [PATCH 10/17] Remove unused option flag --- src/librustc/session/config.rs | 6 ------ src/librustc/session/mod.rs | 3 --- 2 files changed, 9 deletions(-) diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 54d9e24bbc0e2..9d25d1cad6f53 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -1233,8 +1233,6 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "for every macro invocation, print its name and arguments"), debug_macros: bool = (false, parse_bool, [TRACKED], "emit line numbers debug info inside macros"), - enable_nonzeroing_move_hints: bool = (false, parse_bool, [TRACKED], - "force nonzeroing move optimization on"), keep_hygiene_data: bool = (false, parse_bool, [UNTRACKED], "don't clear the hygiene data after analysis"), keep_ast: bool = (false, parse_bool, [UNTRACKED], @@ -3153,10 +3151,6 @@ mod tests { opts.debugging_opts.force_overflow_checks = Some(true); assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash()); - opts = reference.clone(); - opts.debugging_opts.enable_nonzeroing_move_hints = true; - assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash()); - opts = reference.clone(); opts.debugging_opts.show_span = Some(String::from("abc")); assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash()); diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index 77a1129f66d27..7b8bbbf4a10e0 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -624,9 +624,6 @@ impl Session { pub fn unstable_options(&self) -> bool { self.opts.debugging_opts.unstable_options } - pub fn nonzeroing_move_hints(&self) -> bool { - self.opts.debugging_opts.enable_nonzeroing_move_hints - } pub fn overflow_checks(&self) -> bool { self.opts .cg From b326e71b7967f5c67d7bd3d07b690bc1c17d055c Mon Sep 17 00:00:00 2001 From: Shotaro Yamada Date: Sun, 29 Apr 2018 01:19:06 +0900 Subject: [PATCH 11/17] Incorporate a stray test --- src/liballoc/repeat-generic-slice.rs | 19 ------------------- src/liballoc/tests/lib.rs | 1 + src/liballoc/tests/slice.rs | 11 +++++++++++ 3 files changed, 12 insertions(+), 19 deletions(-) delete mode 100644 src/liballoc/repeat-generic-slice.rs diff --git a/src/liballoc/repeat-generic-slice.rs b/src/liballoc/repeat-generic-slice.rs deleted file mode 100644 index 5c14ee4fd83b4..0000000000000 --- a/src/liballoc/repeat-generic-slice.rs +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![feature(repeat_generic_slice)] - -fn main() { - assert_eq!([1, 2].repeat(2), vec![1, 2, 1, 2]); - assert_eq!([1, 2, 3, 4].repeat(0), vec![]); - assert_eq!([1, 2, 3, 4].repeat(1), vec![1, 2, 3, 4]); - assert_eq!([1, 2, 3, 4].repeat(3), - vec![1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4]); -} diff --git a/src/liballoc/tests/lib.rs b/src/liballoc/tests/lib.rs index 2c361598e8928..d3cbad0284b46 100644 --- a/src/liballoc/tests/lib.rs +++ b/src/liballoc/tests/lib.rs @@ -24,6 +24,7 @@ #![feature(try_reserve)] #![feature(unboxed_closures)] #![feature(exact_chunks)] +#![feature(repeat_generic_slice)] extern crate alloc_system; extern crate core; diff --git a/src/liballoc/tests/slice.rs b/src/liballoc/tests/slice.rs index 3b7eec38609d0..df5e18a9a184e 100644 --- a/src/liballoc/tests/slice.rs +++ b/src/liballoc/tests/slice.rs @@ -1529,3 +1529,14 @@ fn panic_safe() { } } } + +#[test] +fn repeat_generic_slice() { + assert_eq!([1, 2].repeat(2), vec![1, 2, 1, 2]); + assert_eq!([1, 2, 3, 4].repeat(0), vec![]); + assert_eq!([1, 2, 3, 4].repeat(1), vec![1, 2, 3, 4]); + assert_eq!( + [1, 2, 3, 4].repeat(3), + vec![1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4] + ); +} From 3bc59b5205410b229eb66236b4aafbb90487fa34 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 27 Jul 2018 11:54:38 +0200 Subject: [PATCH 12/17] use slice::align_to --- src/libcore/slice/memchr.rs | 33 +++++++-------------------------- 1 file changed, 7 insertions(+), 26 deletions(-) diff --git a/src/libcore/slice/memchr.rs b/src/libcore/slice/memchr.rs index dbbe1c07c2338..72e7b57a6cb3c 100644 --- a/src/libcore/slice/memchr.rs +++ b/src/libcore/slice/memchr.rs @@ -102,32 +102,13 @@ pub fn memrchr(x: u8, text: &[u8]) -> Option { let ptr = text.as_ptr(); let usize_bytes = mem::size_of::(); - // a version of align_offset that says how much must be *subtracted* - // from a pointer to be aligned. - #[inline(always)] - fn align_offset_down(ptr: *const u8, align: usize) -> usize { - let align_offset = ptr.align_offset(align); - if align_offset > align { - // Not possible to align - usize::max_value() - } else if align_offset == 0 { - 0 - } else { - // E.g. if align=8 and we have to add 1, then we can also subtract 7. - align - align_offset - } - } - - // search to an aligned boundary - let end_align = align_offset_down(unsafe { ptr.offset(len as isize) }, usize_bytes); - let mut offset; - if end_align > 0 { - offset = if end_align >= len { 0 } else { len - end_align }; - if let Some(index) = text[offset..].iter().rposition(|elt| *elt == x) { - return Some(offset + index); - } - } else { - offset = len; + let mut offset = { + // We call this just to obtain the length of the suffix + let (_, _, suffix) = unsafe { text.align_to::() }; + len - suffix.len() + }; + if let Some(index) = text[offset..].iter().rposition(|elt| *elt == x) { + return Some(offset + index); } // search the body of the text From b2b697ebb92597419ef23fb4489c25bbedfbf65f Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Mon, 4 Jun 2018 18:32:06 +0200 Subject: [PATCH 13/17] Sanity-check all constants --- src/librustc/lib.rs | 1 + src/librustc/mir/interpret/error.rs | 2 +- src/librustc/ty/layout.rs | 25 +- src/librustc_lint/builtin.rs | 75 +++- src/librustc_mir/interpret/const_eval.rs | 36 +- src/librustc_mir/interpret/eval_context.rs | 410 +++++++++++++++--- src/librustc_mir/interpret/memory.rs | 1 + src/librustc_mir/interpret/mod.rs | 1 + src/librustc_mir/interpret/place.rs | 27 +- src/librustc_mir/interpret/terminator/mod.rs | 6 +- src/librustc_mir/transform/const_prop.rs | 68 +-- src/librustc_target/abi/mod.rs | 2 + src/test/compile-fail/issue-26548.rs | 3 +- src/test/ui/const-eval/double_check.rs | 32 ++ src/test/ui/const-eval/double_check2.rs | 30 ++ src/test/ui/const-eval/double_check2.stderr | 14 + src/test/ui/const-eval/index_out_of_bounds.rs | 5 +- .../ui/const-eval/index_out_of_bounds.stderr | 10 +- .../index_out_of_bounds_propagated.rs | 14 + .../index_out_of_bounds_propagated.stderr | 10 + src/test/ui/const-eval/ub-enum-ptr.rs | 27 ++ src/test/ui/const-eval/ub-enum-ptr.stderr | 11 + src/test/ui/const-eval/ub-ptr-in-usize.rs | 22 + src/test/ui/const-eval/ub-uninhabit.rs | 23 + src/test/ui/const-eval/ub-uninhabit.stderr | 11 + src/test/ui/const-eval/ub-usize-in-ref.rs | 22 + .../ui/const-eval/union-const-eval-field.rs | 45 ++ .../const-eval/union-const-eval-field.stderr | 11 + src/test/ui/const-eval/union-ice.rs | 51 +++ src/test/ui/const-eval/union-ice.stderr | 36 ++ src/test/ui/const-eval/union-ub-fat-ptr.rs | 89 ++++ .../ui/const-eval/union-ub-fat-ptr.stderr | 43 ++ src/test/ui/const-eval/union-ub.rs | 45 ++ src/test/ui/const-eval/union-ub.stderr | 11 + src/tools/miri | 2 +- 35 files changed, 1050 insertions(+), 171 deletions(-) create mode 100644 src/test/ui/const-eval/double_check.rs create mode 100644 src/test/ui/const-eval/double_check2.rs create mode 100644 src/test/ui/const-eval/double_check2.stderr create mode 100644 src/test/ui/const-eval/index_out_of_bounds_propagated.rs create mode 100644 src/test/ui/const-eval/index_out_of_bounds_propagated.stderr create mode 100644 src/test/ui/const-eval/ub-enum-ptr.rs create mode 100644 src/test/ui/const-eval/ub-enum-ptr.stderr create mode 100644 src/test/ui/const-eval/ub-ptr-in-usize.rs create mode 100644 src/test/ui/const-eval/ub-uninhabit.rs create mode 100644 src/test/ui/const-eval/ub-uninhabit.stderr create mode 100644 src/test/ui/const-eval/ub-usize-in-ref.rs create mode 100644 src/test/ui/const-eval/union-const-eval-field.rs create mode 100644 src/test/ui/const-eval/union-const-eval-field.stderr create mode 100644 src/test/ui/const-eval/union-ice.rs create mode 100644 src/test/ui/const-eval/union-ice.stderr create mode 100644 src/test/ui/const-eval/union-ub-fat-ptr.rs create mode 100644 src/test/ui/const-eval/union-ub-fat-ptr.stderr create mode 100644 src/test/ui/const-eval/union-ub.rs create mode 100644 src/test/ui/const-eval/union-ub.stderr diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index d709a4debd1d3..a8c6ede1a8028 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -75,6 +75,7 @@ #![feature(in_band_lifetimes)] #![feature(macro_at_most_once_rep)] #![feature(inclusive_range_methods)] +#![feature(crate_in_paths)] #![recursion_limit="512"] diff --git a/src/librustc/mir/interpret/error.rs b/src/librustc/mir/interpret/error.rs index 9125597a7273e..1e9584bc55bdf 100644 --- a/src/librustc/mir/interpret/error.rs +++ b/src/librustc/mir/interpret/error.rs @@ -47,7 +47,7 @@ impl<'a, 'gcx, 'tcx> ConstEvalErr<'tcx> { tcx: TyCtxtAt<'a, 'gcx, 'tcx>, message: &str ) { - let err = self.struct_generic(tcx, message, None); + let err = self.struct_error(tcx, message); if let Some(mut err) = err { err.emit(); } diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index faad32a5d994e..81cc897232ab0 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -1599,7 +1599,7 @@ impl<'a, 'tcx, C> TyLayoutMethods<'tcx, C> for Ty<'tcx> // Potentially-fat pointers. ty::TyRef(_, pointee, _) | ty::TyRawPtr(ty::TypeAndMut { ty: pointee, .. }) => { - assert!(i < 2); + assert!(i < this.fields.count()); // Reuse the fat *T type as its own thin pointer data field. // This provides information about e.g. DST struct pointees @@ -1621,10 +1621,25 @@ impl<'a, 'tcx, C> TyLayoutMethods<'tcx, C> for Ty<'tcx> match tcx.struct_tail(pointee).sty { ty::TySlice(_) | ty::TyStr => tcx.types.usize, - ty::TyDynamic(..) => { - // FIXME(eddyb) use an usize/fn() array with - // the correct number of vtables slots. - tcx.mk_imm_ref(tcx.types.re_static, tcx.mk_nil()) + ty::TyDynamic(data, _) => { + let trait_def_id = data.principal().unwrap().def_id(); + let num_fns: u64 = crate::traits::supertrait_def_ids(tcx, trait_def_id) + .map(|trait_def_id| { + tcx.associated_items(trait_def_id) + .filter(|item| item.kind == ty::AssociatedKind::Method) + .count() as u64 + }) + .sum(); + tcx.mk_imm_ref( + tcx.types.re_static, + tcx.mk_array(tcx.types.usize, 3 + num_fns), + ) + /* FIXME use actual fn pointers + tcx.mk_tup(&[ + tcx.mk_array(tcx.types.usize, 3), + tcx.mk_array(Option), + ]) + */ } _ => bug!("TyLayout::field_type({:?}): not applicable", this) } diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index e6aa7c0d16c6a..a763820fa25ea 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -40,6 +40,7 @@ use lint::{LateContext, LintContext, LintArray}; use lint::{LintPass, LateLintPass, EarlyLintPass, EarlyContext}; use std::collections::HashSet; +use rustc::util::nodemap::FxHashSet; use syntax::tokenstream::{TokenTree, TokenStream}; use syntax::ast; @@ -1576,6 +1577,57 @@ impl LintPass for UnusedBrokenConst { } } +fn validate_const<'a, 'tcx>( + tcx: ty::TyCtxt<'a, 'tcx, 'tcx>, + constant: &ty::Const<'tcx>, + param_env: ty::ParamEnv<'tcx>, + gid: ::rustc::mir::interpret::GlobalId<'tcx>, + what: &str, +) { + let mut ecx = ::rustc_mir::interpret::mk_eval_cx(tcx, gid.instance, param_env).unwrap(); + let result = (|| { + let val = ecx.const_to_value(constant.val)?; + use rustc_target::abi::LayoutOf; + let layout = ecx.layout_of(constant.ty)?; + let place = ecx.allocate_place_for_value(val, layout, None)?; + let ptr = place.to_ptr()?; + let mut todo = vec![(ptr, layout.ty, String::new())]; + let mut seen = FxHashSet(); + seen.insert((ptr, layout.ty)); + while let Some((ptr, ty, path)) = todo.pop() { + let layout = ecx.layout_of(ty)?; + ecx.validate_ptr_target( + ptr, + layout.align, + layout, + path, + &mut seen, + &mut todo, + )?; + } + Ok(()) + })(); + if let Err(err) = result { + let (trace, span) = ecx.generate_stacktrace(None); + let err = ::rustc::mir::interpret::ConstEvalErr { + error: err, + stacktrace: trace, + span, + }; + let err = err.struct_error( + tcx.at(span), + &format!("this {} likely exhibits undefined behavior", what), + ); + if let Some(mut err) = err { + err.note("The rules on what exactly is undefined behavior aren't clear, \ + so this check might be overzealous. Please open an issue on the rust compiler \ + repository if you believe it should not be considered undefined behavior", + ); + err.emit(); + } + } +} + fn check_const(cx: &LateContext, body_id: hir::BodyId, what: &str) { let def_id = cx.tcx.hir.body_owner_def_id(body_id); let param_env = cx.tcx.param_env(def_id); @@ -1583,13 +1635,19 @@ fn check_const(cx: &LateContext, body_id: hir::BodyId, what: &str) { instance: ty::Instance::mono(cx.tcx, def_id), promoted: None }; - if let Err(err) = cx.tcx.const_eval(param_env.and(cid)) { - let span = cx.tcx.def_span(def_id); - err.report_as_lint( - cx.tcx.at(span), - &format!("this {} cannot be used", what), - cx.current_lint_root(), - ); + match cx.tcx.const_eval(param_env.and(cid)) { + Ok(val) => validate_const(cx.tcx, val, param_env, cid, what), + Err(err) => { + // errors for statics are already reported directly in the query + if cx.tcx.is_static(def_id).is_none() { + let span = cx.tcx.def_span(def_id); + err.report_as_lint( + cx.tcx.at(span), + &format!("this {} cannot be used", what), + cx.current_lint_root(), + ); + } + }, } } @@ -1610,6 +1668,9 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedBrokenConst { hir::ItemKind::Const(_, body_id) => { check_const(cx, body_id, "constant"); }, + hir::ItemKind::Static(_, _, body_id) => { + check_const(cx, body_id, "static"); + }, hir::ItemKind::Ty(ref ty, _) => hir::intravisit::walk_ty( &mut UnusedBrokenConstVisitor(cx), ty diff --git a/src/librustc_mir/interpret/const_eval.rs b/src/librustc_mir/interpret/const_eval.rs index 3c92f3f623581..873fef75bb9eb 100644 --- a/src/librustc_mir/interpret/const_eval.rs +++ b/src/librustc_mir/interpret/const_eval.rs @@ -5,7 +5,7 @@ use rustc::hir; use rustc::mir::interpret::{ConstEvalErr}; use rustc::mir; use rustc::ty::{self, TyCtxt, Ty, Instance}; -use rustc::ty::layout::{self, LayoutOf, Primitive}; +use rustc::ty::layout::{self, LayoutOf, Primitive, TyLayout}; use rustc::ty::subst::Subst; use syntax::ast::Mutability; @@ -16,7 +16,7 @@ use rustc::mir::interpret::{ EvalResult, EvalError, EvalErrorKind, GlobalId, Value, Scalar, AllocId, Allocation, ConstValue, }; -use super::{Place, EvalContext, StackPopCleanup, ValTy, PlaceExtra, Memory, MemoryKind}; +use super::{Place, EvalContext, StackPopCleanup, ValTy, Memory, MemoryKind}; pub fn mk_borrowck_eval_cx<'a, 'mir, 'tcx>( tcx: TyCtxt<'a, 'tcx, 'tcx>, @@ -63,7 +63,7 @@ pub fn eval_promoted<'a, 'mir, 'tcx>( cid: GlobalId<'tcx>, mir: &'mir mir::Mir<'tcx>, param_env: ty::ParamEnv<'tcx>, -) -> EvalResult<'tcx, (Value, Scalar, Ty<'tcx>)> { +) -> EvalResult<'tcx, (Value, Scalar, TyLayout<'tcx>)> { ecx.with_fresh_body(|ecx| { eval_body_using_ecx(ecx, cid, Some(mir), param_env) }) @@ -121,7 +121,7 @@ fn eval_body_and_ecx<'a, 'mir, 'tcx>( cid: GlobalId<'tcx>, mir: Option<&'mir mir::Mir<'tcx>>, param_env: ty::ParamEnv<'tcx>, -) -> (EvalResult<'tcx, (Value, Scalar, Ty<'tcx>)>, EvalContext<'a, 'mir, 'tcx, CompileTimeEvaluator>) { +) -> (EvalResult<'tcx, (Value, Scalar, TyLayout<'tcx>)>, EvalContext<'a, 'mir, 'tcx, CompileTimeEvaluator>) { debug!("eval_body_and_ecx: {:?}, {:?}", cid, param_env); // we start out with the best span we have // and try improving it down the road when more information is available @@ -137,7 +137,7 @@ fn eval_body_using_ecx<'a, 'mir, 'tcx>( cid: GlobalId<'tcx>, mir: Option<&'mir mir::Mir<'tcx>>, param_env: ty::ParamEnv<'tcx>, -) -> EvalResult<'tcx, (Value, Scalar, Ty<'tcx>)> { +) -> EvalResult<'tcx, (Value, Scalar, TyLayout<'tcx>)> { debug!("eval_body: {:?}, {:?}", cid, param_env); let tcx = ecx.tcx.tcx; let mut mir = match mir { @@ -182,7 +182,7 @@ fn eval_body_using_ecx<'a, 'mir, 'tcx>( // point at the allocation _ => Value::ByRef(ptr, layout.align), }; - Ok((value, ptr, layout.ty)) + Ok((value, ptr, layout)) } #[derive(Debug, Clone, Eq, PartialEq, Hash)] @@ -434,19 +434,7 @@ pub fn const_val_field<'a, 'tcx>( let ty = value.ty; let value = ecx.const_to_value(value.val)?; let layout = ecx.layout_of(ty)?; - let (ptr, align) = match value { - Value::ByRef(ptr, align) => (ptr, align), - Value::ScalarPair(..) | Value::Scalar(_) => { - let ptr = ecx.alloc_ptr(ty)?.into(); - ecx.write_value_to_ptr(value, ptr, layout.align, ty)?; - (ptr, layout.align) - }, - }; - let place = Place::Ptr { - ptr, - align, - extra: variant.map_or(PlaceExtra::None, PlaceExtra::DowncastVariant), - }; + let place = ecx.allocate_place_for_value(value, layout, variant)?; let (place, layout) = ecx.place_field(place, field, layout)?; let (ptr, align) = place.to_ptr_align(); let mut new_value = Value::ByRef(ptr, align); @@ -484,9 +472,9 @@ pub fn const_variant_index<'a, 'tcx>( trace!("const_variant_index: {:?}, {:?}", instance, val); let mut ecx = mk_eval_cx(tcx, instance, param_env).unwrap(); let value = ecx.const_to_value(val.val)?; + let layout = ecx.layout_of(val.ty)?; let (ptr, align) = match value { Value::ScalarPair(..) | Value::Scalar(_) => { - let layout = ecx.layout_of(val.ty)?; let ptr = ecx.memory.allocate(layout.size, layout.align, MemoryKind::Stack)?.into(); ecx.write_value_to_ptr(value, ptr, layout.align, val.ty)?; (ptr, layout.align) @@ -494,7 +482,7 @@ pub fn const_variant_index<'a, 'tcx>( Value::ByRef(ptr, align) => (ptr, align), }; let place = Place::from_scalar_ptr(ptr, align); - ecx.read_discriminant_as_variant_index(place, val.ty) + ecx.read_discriminant_as_variant_index(place, layout) } pub fn const_value_to_allocation_provider<'a, 'tcx>( @@ -560,11 +548,11 @@ pub fn const_eval_provider<'a, 'tcx>( }; let (res, ecx) = eval_body_and_ecx(tcx, cid, None, key.param_env); - res.and_then(|(mut val, _, miri_ty)| { + res.and_then(|(mut val, _, layout)| { if tcx.is_static(def_id).is_none() && cid.promoted.is_none() { - val = ecx.try_read_by_ref(val, miri_ty)?; + val = ecx.try_read_by_ref(val, layout.ty)?; } - Ok(value_to_const_value(&ecx, val, miri_ty)) + Ok(value_to_const_value(&ecx, val, layout.ty)) }).map_err(|err| { let (trace, span) = ecx.generate_stacktrace(None); let err = ConstEvalErr { diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index 10d3af85337e8..c6c1a1d1ebb22 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -6,14 +6,14 @@ use rustc::hir::def_id::DefId; use rustc::hir::def::Def; use rustc::hir::map::definitions::DefPathData; use rustc::mir; -use rustc::ty::layout::{self, Size, Align, HasDataLayout, IntegerExt, LayoutOf, TyLayout}; +use rustc::ty::layout::{self, Size, Align, HasDataLayout, IntegerExt, LayoutOf, TyLayout, Primitive}; use rustc::ty::subst::{Subst, Substs}; use rustc::ty::{self, Ty, TyCtxt, TypeAndMut}; use rustc::ty::query::TyCtxtAt; use rustc_data_structures::fx::{FxHashSet, FxHasher}; use rustc_data_structures::indexed_vec::{IndexVec, Idx}; use rustc::mir::interpret::{ - FrameInfo, GlobalId, Value, Scalar, + GlobalId, Value, Scalar, FrameInfo, AllocType, EvalResult, EvalErrorKind, Pointer, ConstValue, }; @@ -24,6 +24,31 @@ use super::{Place, PlaceExtra, Memory, HasMemory, MemoryKind, Machine}; +macro_rules! validation_failure{ + ($what:expr, $where:expr, $details:expr) => {{ + let where_ = if $where.is_empty() { + String::new() + } else { + format!(" at {}", $where) + }; + err!(ValidationFailure(format!( + "encountered {}{}, but expected {}", + $what, where_, $details, + ))) + }}; + ($what:expr, $where:expr) => {{ + let where_ = if $where.is_empty() { + String::new() + } else { + format!(" at {}", $where) + }; + err!(ValidationFailure(format!( + "encountered {}{}", + $what, where_, + ))) + }}; +} + pub struct EvalContext<'a, 'mir, 'tcx: 'a + 'mir, M: Machine<'mir, 'tcx>> { /// Stores the `Machine` instance. pub machine: M, @@ -324,8 +349,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M r } - pub fn alloc_ptr(&mut self, ty: Ty<'tcx>) -> EvalResult<'tcx, Pointer> { - let layout = self.layout_of(ty)?; + pub fn alloc_ptr(&mut self, layout: TyLayout<'tcx>) -> EvalResult<'tcx, Pointer> { assert!(!layout.is_unsized(), "cannot alloc memory for unsized type"); self.memory.allocate(layout.size, layout.align, MemoryKind::Stack) @@ -776,8 +800,9 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M Discriminant(ref place) => { let ty = self.place_ty(place); + let layout = self.layout_of(ty)?; let place = self.eval_place(place)?; - let discr_val = self.read_discriminant_value(place, ty)?; + let discr_val = self.read_discriminant_value(place, layout)?; let defined = self.layout_of(dest_ty).unwrap().size.bits() as u8; self.write_scalar(dest, Scalar::Bits { bits: discr_val, @@ -843,16 +868,16 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M /// reads a tag and produces the corresponding variant index pub fn read_discriminant_as_variant_index( - &mut self, + &self, place: Place, - ty: Ty<'tcx>, + layout: TyLayout<'tcx>, ) -> EvalResult<'tcx, usize> { - let layout = self.layout_of(ty)?; match layout.variants { ty::layout::Variants::Single { index } => Ok(index), ty::layout::Variants::Tagged { .. } => { - let discr_val = self.read_discriminant_value(place, ty)?; - ty + let discr_val = self.read_discriminant_value(place, layout)?; + layout + .ty .ty_adt_def() .expect("tagged layout for non adt") .discriminants(self.tcx.tcx) @@ -860,7 +885,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M .ok_or_else(|| EvalErrorKind::InvalidDiscriminant.into()) } ty::layout::Variants::NicheFilling { .. } => { - let discr_val = self.read_discriminant_value(place, ty)?; + let discr_val = self.read_discriminant_value(place, layout)?; assert_eq!(discr_val as usize as u128, discr_val); Ok(discr_val as usize) }, @@ -868,11 +893,10 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M } pub fn read_discriminant_value( - &mut self, + &self, place: Place, - ty: Ty<'tcx>, + layout: TyLayout<'tcx>, ) -> EvalResult<'tcx, u128> { - let layout = self.layout_of(ty)?; trace!("read_discriminant_value {:#?}", layout); if layout.abi == layout::Abi::Uninhabited { return Ok(0); @@ -880,7 +904,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M match layout.variants { layout::Variants::Single { index } => { - let discr_val = ty.ty_adt_def().map_or( + let discr_val = layout.ty.ty_adt_def().map_or( index as u128, |def| def.discriminant_for_variant(*self.tcx, index).val); return Ok(discr_val); @@ -888,11 +912,11 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M layout::Variants::Tagged { .. } | layout::Variants::NicheFilling { .. } => {}, } - - let (discr_place, discr) = self.place_field(place, mir::Field::new(0), layout)?; - trace!("discr place: {:?}, {:?}", discr_place, discr); + let discr_place_val = self.read_place(place)?; + let (discr_val, discr) = self.read_field(discr_place_val, None, mir::Field::new(0), layout)?; + trace!("discr value: {:?}, {:?}", discr_val, discr); let raw_discr = self.value_to_scalar(ValTy { - value: self.read_place(discr_place)?, + value: discr_val, ty: discr.ty })?; let discr_val = match layout.variants { @@ -906,7 +930,8 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M let shift = 128 - discr.size.bits(); let sexted = (i << shift) >> shift; // and then zeroing with the typeck discriminant type - let discr_ty = ty + let discr_ty = layout + .ty .ty_adt_def().expect("tagged layout corresponds to adt") .repr .discr_type(); @@ -1023,6 +1048,27 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M self.tcx.const_eval(param_env.and(gid)).map_err(|err| EvalErrorKind::ReferencedConstant(err).into()) } + pub fn allocate_place_for_value( + &mut self, + value: Value, + layout: TyLayout<'tcx>, + variant: Option, + ) -> EvalResult<'tcx, Place> { + let (ptr, align) = match value { + Value::ByRef(ptr, align) => (ptr, align), + Value::ScalarPair(..) | Value::Scalar(_) => { + let ptr = self.alloc_ptr(layout)?.into(); + self.write_value_to_ptr(value, ptr, layout.align, layout.ty)?; + (ptr, layout.align) + }, + }; + Ok(Place::Ptr { + ptr, + align, + extra: variant.map_or(PlaceExtra::None, PlaceExtra::DowncastVariant), + }) + } + pub fn force_allocation(&mut self, place: Place) -> EvalResult<'tcx, Place> { let new_place = match place { Place::Local { frame, local } => { @@ -1039,7 +1085,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M let ty = self.stack[frame].mir.local_decls[local].ty; let ty = self.monomorphize(ty, self.stack[frame].instance.substs); let layout = self.layout_of(ty)?; - let ptr = self.alloc_ptr(ty)?; + let ptr = self.alloc_ptr(layout)?; self.stack[frame].locals[local] = Some(Value::ByRef(ptr.into(), layout.align)); // it stays live let place = Place::from_ptr(ptr, layout.align); @@ -1074,11 +1120,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M match self.follow_by_ref_value(value, ty)? { Value::ByRef { .. } => bug!("follow_by_ref_value can't result in `ByRef`"), - Value::Scalar(scalar) => { - // TODO: Do we really want insta-UB here? - self.ensure_valid_value(scalar, ty)?; - Ok(scalar) - } + Value::Scalar(scalar) => Ok(scalar), Value::ScalarPair(..) => bug!("value_to_scalar can't work with fat pointers"), } @@ -1165,8 +1207,8 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M if let Ok(Some(src_val)) = self.try_read_value(src_ptr, align, dest_ty) { write_dest(self, src_val)?; } else { - let dest_ptr = self.alloc_ptr(dest_ty)?.into(); let layout = self.layout_of(dest_ty)?; + let dest_ptr = self.alloc_ptr(layout)?.into(); self.memory.copy(src_ptr, align.min(layout.align), dest_ptr, layout.align, layout.size, false)?; write_dest(self, Value::ByRef(dest_ptr, layout.align))?; } @@ -1221,18 +1263,6 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M } } - fn ensure_valid_value(&self, val: Scalar, ty: Ty<'tcx>) -> EvalResult<'tcx> { - match ty.sty { - ty::TyBool => val.to_bool().map(|_| ()), - - ty::TyChar if ::std::char::from_u32(val.to_bits(Size::from_bytes(4))? as u32).is_none() => { - err!(InvalidChar(val.to_bits(Size::from_bytes(4))? as u32 as u128)) - } - - _ => Ok(()), - } - } - pub fn read_value(&self, ptr: Scalar, align: Align, ty: Ty<'tcx>) -> EvalResult<'tcx, Value> { if let Some(val) = self.try_read_value(ptr, align, ty)? { Ok(val) @@ -1270,47 +1300,223 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M } } - pub fn validate_ptr_target( + fn validate_scalar( &self, - ptr: Pointer, - ptr_align: Align, - ty: Ty<'tcx> + value: Scalar, + size: Size, + scalar: &layout::Scalar, + path: &str, + ty: Ty, ) -> EvalResult<'tcx> { + trace!("validate scalar: {:#?}, {:#?}, {:#?}, {}", value, size, scalar, ty); + let (lo, hi) = scalar.valid_range.clone().into_inner(); + + let (bits, defined) = match value { + Scalar::Bits { bits, defined } => (bits, defined), + Scalar::Ptr(_) => { + let ptr_size = self.memory.pointer_size(); + let ptr_max = u128::max_value() >> (128 - ptr_size.bits()); + return if lo > hi { + if lo - hi == 1 { + // no gap, all values are ok + Ok(()) + } else if hi < ptr_max || lo > 1 { + let max = u128::max_value() >> (128 - size.bits()); + validation_failure!( + "pointer", + path, + format!("something in the range {:?} or {:?}", 0..=lo, hi..=max) + ) + } else { + Ok(()) + } + } else if hi < ptr_max || lo > 1 { + validation_failure!( + "pointer", + path, + format!("something in the range {:?}", scalar.valid_range) + ) + } else { + Ok(()) + }; + }, + }; + + // char gets a special treatment, because its number space is not contiguous so `TyLayout` + // has no special checks for chars match ty.sty { - ty::TyBool => { - self.memory.read_scalar(ptr, ptr_align, Size::from_bytes(1))?.to_bool()?; - } ty::TyChar => { - let c = self.memory.read_scalar(ptr, ptr_align, Size::from_bytes(4))?.to_bits(Size::from_bytes(4))? as u32; - match ::std::char::from_u32(c) { - Some(..) => (), - None => return err!(InvalidChar(c as u128)), + assert_eq!(size.bytes(), 4); + if ::std::char::from_u32(bits as u32).is_none() { + return err!(InvalidChar(bits)); } } + _ => {}, + } - ty::TyFnPtr(_) => { - self.memory.read_ptr_sized(ptr, ptr_align)?; - }, - ty::TyRef(_, rty, _) | - ty::TyRawPtr(ty::TypeAndMut { ty: rty, .. }) => { - self.read_ptr(ptr, ptr_align, rty)?; + use std::ops::RangeInclusive; + let in_range = |bound: RangeInclusive| { + defined as u64 >= size.bits() && bound.contains(&bits) + }; + if lo > hi { + if in_range(0..=hi) || in_range(lo..=u128::max_value()) { + Ok(()) + } else if defined as u64 >= size.bits() { + validation_failure!( + bits, + path, + format!("something in the range {:?} or {:?}", ..=hi, lo..) + ) + } else { + validation_failure!("undefined bytes", path) } + } else { + if in_range(scalar.valid_range.clone()) { + Ok(()) + } else if defined as u64 >= size.bits() { + validation_failure!( + bits, + path, + format!("something in the range {:?}", scalar.valid_range) + ) + } else { + validation_failure!("undefined bytes", path) + } + } + } - ty::TyAdt(def, _) => { - if def.is_box() { - self.read_ptr(ptr, ptr_align, ty.boxed_ty())?; - return Ok(()); - } + /// This function checks the memory where `ptr` points to. + /// It will error if the bits at the destination do not match the ones described by the layout. + pub fn validate_ptr_target( + &self, + ptr: Pointer, + ptr_align: Align, + mut layout: TyLayout<'tcx>, + path: String, + seen: &mut FxHashSet<(Pointer, Ty<'tcx>)>, + todo: &mut Vec<(Pointer, Ty<'tcx>, String)>, + ) -> EvalResult<'tcx> { + self.memory.dump_alloc(ptr.alloc_id); + trace!("validate_ptr_target: {:?}, {:#?}", ptr, layout); - if let layout::Abi::Scalar(ref scalar) = self.layout_of(ty)?.abi { - let size = scalar.value.size(self); - self.memory.read_scalar(ptr, ptr_align, size)?; + let variant; + match layout.variants { + layout::Variants::NicheFilling { niche: ref tag, .. } | + layout::Variants::Tagged { ref tag, .. } => { + let size = tag.value.size(self); + let (tag_value, tag_layout) = self.read_field( + Value::ByRef(ptr.into(), ptr_align), + None, + mir::Field::new(0), + layout, + )?; + let tag_value = self.value_to_scalar(ValTy { + value: tag_value, + ty: tag_layout.ty, + })?; + let path = format!("{}.TAG", path); + self.validate_scalar(tag_value, size, tag, &path, tag_layout.ty)?; + let variant_index = self.read_discriminant_as_variant_index( + Place::from_ptr(ptr, ptr_align), + layout, + )?; + variant = variant_index; + layout = layout.for_variant(self, variant_index); + trace!("variant layout: {:#?}", layout); + }, + layout::Variants::Single { index } => variant = index, + } + match layout.fields { + // primitives are unions with zero fields + layout::FieldPlacement::Union(0) => { + match layout.abi { + // nothing to do, whatever the pointer points to, it is never going to be read + layout::Abi::Uninhabited => validation_failure!("a value of an uninhabited type", path), + // check that the scalar is a valid pointer or that its bit range matches the + // expectation. + layout::Abi::Scalar(ref scalar) => { + let size = scalar.value.size(self); + let value = self.memory.read_scalar(ptr, ptr_align, size)?; + self.validate_scalar(value, size, scalar, &path, layout.ty)?; + if scalar.value == Primitive::Pointer { + // ignore integer pointers, we can't reason about the final hardware + if let Scalar::Ptr(ptr) = value { + let alloc_kind = self.tcx.alloc_map.lock().get(ptr.alloc_id); + if let Some(AllocType::Static(did)) = alloc_kind { + // statics from other crates are already checked + // extern statics should not be validated as they have no body + if !did.is_local() || self.tcx.is_foreign_item(did) { + return Ok(()); + } + } + if let Some(tam) = layout.ty.builtin_deref(false) { + // we have not encountered this pointer+layout combination before + if seen.insert((ptr, tam.ty)) { + todo.push((ptr, tam.ty, format!("(*{})", path))) + } + } + } + } + Ok(()) + }, + _ => bug!("bad abi for FieldPlacement::Union(0): {:#?}", layout.abi), } } - - _ => (), + layout::FieldPlacement::Union(_) => { + // We can't check unions, their bits are allowed to be anything. + // The fields don't need to correspond to any bit pattern of the union's fields. + // See https://github.com/rust-lang/rust/issues/32836#issuecomment-406875389 + Ok(()) + }, + layout::FieldPlacement::Array { stride, count } => { + let elem_layout = layout.field(self, 0)?; + for i in 0..count { + let mut path = path.clone(); + self.write_field_name(&mut path, layout.ty, i as usize, variant).unwrap(); + self.validate_ptr_target(ptr.offset(stride * i, self)?, ptr_align, elem_layout, path, seen, todo)?; + } + Ok(()) + }, + layout::FieldPlacement::Arbitrary { ref offsets, .. } => { + + // check length field and vtable field + match layout.ty.builtin_deref(false).map(|tam| &tam.ty.sty) { + | Some(ty::TyStr) + | Some(ty::TySlice(_)) => { + let (len, len_layout) = self.read_field( + Value::ByRef(ptr.into(), ptr_align), + None, + mir::Field::new(1), + layout, + )?; + let len = self.value_to_scalar(ValTy { value: len, ty: len_layout.ty })?; + if len.to_bits(len_layout.size).is_err() { + return validation_failure!("length is not a valid integer", path); + } + }, + Some(ty::TyDynamic(..)) => { + let (vtable, vtable_layout) = self.read_field( + Value::ByRef(ptr.into(), ptr_align), + None, + mir::Field::new(1), + layout, + )?; + let vtable = self.value_to_scalar(ValTy { value: vtable, ty: vtable_layout.ty })?; + if vtable.to_ptr().is_err() { + return validation_failure!("vtable address is not a pointer", path); + } + } + _ => {}, + } + for (i, &offset) in offsets.iter().enumerate() { + let field_layout = layout.field(self, i)?; + let mut path = path.clone(); + self.write_field_name(&mut path, layout.ty, i, variant).unwrap(); + self.validate_ptr_target(ptr.offset(offset, self)?, ptr_align, field_layout, path, seen, todo)?; + } + Ok(()) + } } - Ok(()) } pub fn try_read_by_ref(&self, mut val: Value, ty: Ty<'tcx>) -> EvalResult<'tcx, Value> { @@ -1333,9 +1539,6 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M let ptr = ptr.to_ptr()?; - // Not the right place to do this - //self.validate_ptr_target(ptr, ptr_align, ty)?; - match layout.abi { layout::Abi::Scalar(..) => { let scalar = self.memory.read_scalar(ptr, ptr_align, layout.size)?; @@ -1623,6 +1826,73 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M pub fn truncate(&self, value: u128, ty: Ty<'tcx>) -> EvalResult<'tcx, u128> { super::truncate(self.tcx.tcx, value, ty) } + + fn write_field_name(&self, s: &mut String, ty: Ty<'tcx>, i: usize, variant: usize) -> ::std::fmt::Result { + match ty.sty { + ty::TyBool | + ty::TyChar | + ty::TyInt(_) | + ty::TyUint(_) | + ty::TyFloat(_) | + ty::TyFnPtr(_) | + ty::TyNever | + ty::TyFnDef(..) | + ty::TyGeneratorWitness(..) | + ty::TyForeign(..) | + ty::TyDynamic(..) => { + bug!("field_name({:?}): not applicable", ty) + } + + // Potentially-fat pointers. + ty::TyRef(_, pointee, _) | + ty::TyRawPtr(ty::TypeAndMut { ty: pointee, .. }) => { + assert!(i < 2); + + // Reuse the fat *T type as its own thin pointer data field. + // This provides information about e.g. DST struct pointees + // (which may have no non-DST form), and will work as long + // as the `Abi` or `FieldPlacement` is checked by users. + if i == 0 { + return write!(s, ".data_ptr"); + } + + match self.tcx.struct_tail(pointee).sty { + ty::TySlice(_) | + ty::TyStr => write!(s, ".len"), + ty::TyDynamic(..) => write!(s, ".vtable_ptr"), + _ => bug!("field_name({:?}): not applicable", ty) + } + } + + // Arrays and slices. + ty::TyArray(_, _) | + ty::TySlice(_) | + ty::TyStr => write!(s, "[{}]", i), + + // generators and closures. + ty::TyClosure(def_id, _) | ty::TyGenerator(def_id, _, _) => { + let node_id = self.tcx.hir.as_local_node_id(def_id).unwrap(); + let freevar = self.tcx.with_freevars(node_id, |fv| fv[i]); + write!(s, ".upvar({})", self.tcx.hir.name(freevar.var_id())) + } + + ty::TyTuple(_) => write!(s, ".{}", i), + + // enums + ty::TyAdt(def, ..) if def.is_enum() => { + let variant = &def.variants[variant]; + write!(s, ".{}::{}", variant.name, variant.fields[i].ident) + } + + // other ADTs. + ty::TyAdt(def, _) => write!(s, ".{}", def.non_enum_variant().fields[i].ident), + + ty::TyProjection(_) | ty::TyAnon(..) | ty::TyParam(_) | + ty::TyInfer(_) | ty::TyError => { + bug!("write_field_name: unexpected type `{}`", ty) + } + } + } } impl<'mir, 'tcx> Frame<'mir, 'tcx> { diff --git a/src/librustc_mir/interpret/memory.rs b/src/librustc_mir/interpret/memory.rs index ac4d1c74b8cc1..2765feb23f1b9 100644 --- a/src/librustc_mir/interpret/memory.rs +++ b/src/librustc_mir/interpret/memory.rs @@ -763,6 +763,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { // Undef check happens *after* we established that the alignment is correct. // We must not return Ok() for unaligned pointers! if self.check_defined(ptr, size).is_err() { + // this inflates undefined bytes to the entire scalar, even if only a few bytes are undefined return Ok(Scalar::undef().into()); } // Now we do the actual reading diff --git a/src/librustc_mir/interpret/mod.rs b/src/librustc_mir/interpret/mod.rs index 3afcd6f2d9bb5..0c921f66198eb 100644 --- a/src/librustc_mir/interpret/mod.rs +++ b/src/librustc_mir/interpret/mod.rs @@ -21,6 +21,7 @@ pub use self::memory::{Memory, MemoryKind, HasMemory}; pub use self::const_eval::{ eval_promoted, mk_borrowck_eval_cx, + mk_eval_cx, CompileTimeEvaluator, const_value_to_allocation_provider, const_eval_provider, diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs index 28373741c2f58..59bf2ae6c0fe7 100644 --- a/src/librustc_mir/interpret/place.rs +++ b/src/librustc_mir/interpret/place.rs @@ -98,7 +98,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> { /// Reads a value from the place without going through the intermediate step of obtaining /// a `miri::Place` pub fn try_read_place( - &mut self, + &self, place: &mir::Place<'tcx>, ) -> EvalResult<'tcx, Option> { use rustc::mir::Place::*; @@ -120,19 +120,18 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> { base: Value, variant: Option, field: mir::Field, - base_ty: Ty<'tcx>, - ) -> EvalResult<'tcx, ValTy<'tcx>> { - let mut base_layout = self.layout_of(base_ty)?; + mut base_layout: TyLayout<'tcx>, + ) -> EvalResult<'tcx, (Value, TyLayout<'tcx>)> { if let Some(variant_index) = variant { base_layout = base_layout.for_variant(self, variant_index); } let field_index = field.index(); let field = base_layout.field(self, field_index)?; if field.size.bytes() == 0 { - return Ok(ValTy { - value: Value::Scalar(Scalar::undef()), - ty: field.ty, - }); + return Ok(( + Value::Scalar(Scalar::undef()), + field, + )); } let offset = base_layout.fields.offset(field_index); let value = match base { @@ -151,16 +150,13 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> { assert!(!field.is_unsized()); Value::ByRef(ptr, align) }, - Value::Scalar(val) => bug!("field access on non aggregate {:?}, {:?}", val, base_ty), + Value::Scalar(val) => bug!("field access on non aggregate {:#?}, {:#?}", val, base_layout), }; - Ok(ValTy { - value, - ty: field.ty, - }) + Ok((value, field)) } fn try_read_place_projection( - &mut self, + &self, proj: &mir::PlaceProjection<'tcx>, ) -> EvalResult<'tcx, Option> { use rustc::mir::ProjectionElem::*; @@ -169,8 +165,9 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> { None => return Ok(None), }; let base_ty = self.place_ty(&proj.base); + let base_layout = self.layout_of(base_ty)?; match proj.elem { - Field(field, _) => Ok(Some(self.read_field(base, None, field, base_ty)?.value)), + Field(field, _) => Ok(Some(self.read_field(base, None, field, base_layout)?.0)), // The NullablePointer cases should work fine, need to take care for normal enums Downcast(..) | Subslice { .. } | diff --git a/src/librustc_mir/interpret/terminator/mod.rs b/src/librustc_mir/interpret/terminator/mod.rs index e281ba7963979..56dd3f603b692 100644 --- a/src/librustc_mir/interpret/terminator/mod.rs +++ b/src/librustc_mir/interpret/terminator/mod.rs @@ -351,8 +351,12 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> { if self.frame().mir.args_iter().count() == layout.fields.count() + 1 { for (i, arg_local) in arg_locals.enumerate() { let field = mir::Field::new(i); - let valty = self.read_field(args[1].value, None, field, args[1].ty)?; + let (value, layout) = self.read_field(args[1].value, None, field, layout)?; let dest = self.eval_place(&mir::Place::Local(arg_local))?; + let valty = ValTy { + value, + ty: layout.ty, + }; self.write_value(valty, dest)?; } } else { diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index c8d4ce88f27c1..9902fe98cc011 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -65,7 +65,7 @@ impl MirPass for ConstProp { } } -type Const<'tcx> = (Value, ty::Ty<'tcx>, Span); +type Const<'tcx> = (Value, TyLayout<'tcx>, Span); /// Finds optimization opportunities on the MIR. struct ConstPropagator<'b, 'a, 'tcx:'a+'b> { @@ -258,7 +258,10 @@ impl<'b, 'a, 'tcx:'b> ConstPropagator<'b, 'a, 'tcx> { ) -> Option> { self.ecx.tcx.span = source_info.span; match self.ecx.const_to_value(c.literal.val) { - Ok(val) => Some((val, c.literal.ty, c.span)), + Ok(val) => { + let layout = self.tcx.layout_of(self.param_env.and(c.literal.ty)).ok()?; + Some((val, layout, c.span)) + }, Err(error) => { let (stacktrace, span) = self.ecx.generate_stacktrace(None); let err = ConstEvalErr { @@ -281,11 +284,11 @@ impl<'b, 'a, 'tcx:'b> ConstPropagator<'b, 'a, 'tcx> { Place::Projection(ref proj) => match proj.elem { ProjectionElem::Field(field, _) => { trace!("field proj on {:?}", proj.base); - let (base, ty, span) = self.eval_place(&proj.base, source_info)?; + let (base, layout, span) = self.eval_place(&proj.base, source_info)?; let valty = self.use_ecx(source_info, |this| { - this.ecx.read_field(base, None, field, ty) + this.ecx.read_field(base, None, field, layout) })?; - Some((valty.value, valty.ty, span)) + Some((valty.0, valty.1, span)) }, _ => None, }, @@ -325,14 +328,14 @@ impl<'b, 'a, 'tcx:'b> ConstPropagator<'b, 'a, 'tcx> { fn const_prop( &mut self, rvalue: &Rvalue<'tcx>, - place_ty: ty::Ty<'tcx>, + place_layout: TyLayout<'tcx>, source_info: SourceInfo, ) -> Option> { let span = source_info.span; match *rvalue { // This branch exists for the sanity type check Rvalue::Use(Operand::Constant(ref c)) => { - assert_eq!(c.ty, place_ty); + assert_eq!(c.ty, place_layout.ty); self.eval_constant(c, source_info) }, Rvalue::Use(ref op) => { @@ -345,15 +348,15 @@ impl<'b, 'a, 'tcx:'b> ConstPropagator<'b, 'a, 'tcx> { Rvalue::Discriminant(..) => None, Rvalue::Cast(kind, ref operand, _) => { - let (value, ty, span) = self.eval_operand(operand, source_info)?; + let (value, layout, span) = self.eval_operand(operand, source_info)?; self.use_ecx(source_info, |this| { - let dest_ptr = this.ecx.alloc_ptr(place_ty)?; - let place_align = this.ecx.layout_of(place_ty)?.align; + let dest_ptr = this.ecx.alloc_ptr(place_layout)?; + let place_align = place_layout.align; let dest = ::interpret::Place::from_ptr(dest_ptr, place_align); - this.ecx.cast(ValTy { value, ty }, kind, place_ty, dest)?; + this.ecx.cast(ValTy { value, ty: layout.ty }, kind, place_layout.ty, dest)?; Ok(( Value::ByRef(dest_ptr.into(), place_align), - place_ty, + place_layout, span, )) }) @@ -362,15 +365,14 @@ impl<'b, 'a, 'tcx:'b> ConstPropagator<'b, 'a, 'tcx> { // FIXME(oli-obk): evaluate static/constant slice lengths Rvalue::Len(_) => None, Rvalue::NullaryOp(NullOp::SizeOf, ty) => { - let param_env = self.tcx.param_env(self.source.def_id); - type_size_of(self.tcx, param_env, ty).map(|n| ( + type_size_of(self.tcx, self.param_env, ty).and_then(|n| Some(( Value::Scalar(Scalar::Bits { bits: n as u128, defined: self.tcx.data_layout.pointer_size.bits() as u8, }), - self.tcx.types.usize, + self.tcx.layout_of(self.param_env.and(self.tcx.types.usize)).ok()?, span, - )) + ))) } Rvalue::UnaryOp(op, ref arg) => { let def_id = if self.tcx.is_closure(self.source.def_id) { @@ -386,10 +388,10 @@ impl<'b, 'a, 'tcx:'b> ConstPropagator<'b, 'a, 'tcx> { let val = self.eval_operand(arg, source_info)?; let prim = self.use_ecx(source_info, |this| { - this.ecx.value_to_scalar(ValTy { value: val.0, ty: val.1 }) + this.ecx.value_to_scalar(ValTy { value: val.0, ty: val.1.ty }) })?; - let val = self.use_ecx(source_info, |this| this.ecx.unary_op(op, prim, val.1))?; - Some((Value::Scalar(val), place_ty, span)) + let val = self.use_ecx(source_info, |this| this.ecx.unary_op(op, prim, val.1.ty))?; + Some((Value::Scalar(val), place_layout, span)) } Rvalue::CheckedBinaryOp(op, ref left, ref right) | Rvalue::BinaryOp(op, ref left, ref right) => { @@ -407,7 +409,7 @@ impl<'b, 'a, 'tcx:'b> ConstPropagator<'b, 'a, 'tcx> { } let r = self.use_ecx(source_info, |this| { - this.ecx.value_to_scalar(ValTy { value: right.0, ty: right.1 }) + this.ecx.value_to_scalar(ValTy { value: right.0, ty: right.1.ty }) })?; if op == BinOp::Shr || op == BinOp::Shl { let left_ty = left.ty(self.mir, self.tcx); @@ -417,7 +419,7 @@ impl<'b, 'a, 'tcx:'b> ConstPropagator<'b, 'a, 'tcx> { .unwrap() .size .bits(); - let right_size = self.tcx.layout_of(self.param_env.and(right.1)).unwrap().size; + let right_size = right.1.size; if r.to_bits(right_size).ok().map_or(false, |b| b >= left_bits as u128) { let source_scope_local_data = match self.mir.source_scope_local_data { ClearCrossCrate::Set(ref data) => data, @@ -439,11 +441,11 @@ impl<'b, 'a, 'tcx:'b> ConstPropagator<'b, 'a, 'tcx> { } let left = self.eval_operand(left, source_info)?; let l = self.use_ecx(source_info, |this| { - this.ecx.value_to_scalar(ValTy { value: left.0, ty: left.1 }) + this.ecx.value_to_scalar(ValTy { value: left.0, ty: left.1.ty }) })?; trace!("const evaluating {:?} for {:?} and {:?}", op, left, right); let (val, overflow) = self.use_ecx(source_info, |this| { - this.ecx.binary_op(op, l, left.1, r, right.1) + this.ecx.binary_op(op, l, left.1.ty, r, right.1.ty) })?; let val = if let Rvalue::CheckedBinaryOp(..) = *rvalue { Value::ScalarPair( @@ -458,7 +460,7 @@ impl<'b, 'a, 'tcx:'b> ConstPropagator<'b, 'a, 'tcx> { } Value::Scalar(val) }; - Some((val, place_ty, span)) + Some((val, place_layout, span)) }, } } @@ -544,16 +546,18 @@ impl<'b, 'a, 'tcx> Visitor<'tcx> for ConstPropagator<'b, 'a, 'tcx> { ) { trace!("visit_statement: {:?}", statement); if let StatementKind::Assign(ref place, ref rval) = statement.kind { - let place_ty = place + let place_ty: ty::Ty<'tcx> = place .ty(&self.mir.local_decls, self.tcx) .to_ty(self.tcx); - if let Some(value) = self.const_prop(rval, place_ty, statement.source_info) { - if let Place::Local(local) = *place { - trace!("checking whether {:?} can be stored to {:?}", value, local); - if self.can_const_prop[local] { - trace!("storing {:?} to {:?}", value, local); - assert!(self.places[local].is_none()); - self.places[local] = Some(value); + if let Ok(place_layout) = self.tcx.layout_of(self.param_env.and(place_ty)) { + if let Some(value) = self.const_prop(rval, place_layout, statement.source_info) { + if let Place::Local(local) = *place { + trace!("checking whether {:?} can be stored to {:?}", value, local); + if self.can_const_prop[local] { + trace!("storing {:?} to {:?}", value, local); + assert!(self.places[local].is_none()); + self.places[local] = Some(value); + } } } } diff --git a/src/librustc_target/abi/mod.rs b/src/librustc_target/abi/mod.rs index df09be00c342f..dac4738e2b4bf 100644 --- a/src/librustc_target/abi/mod.rs +++ b/src/librustc_target/abi/mod.rs @@ -634,6 +634,8 @@ impl Scalar { #[derive(PartialEq, Eq, Hash, Debug)] pub enum FieldPlacement { /// All fields start at no offset. The `usize` is the field count. + /// + /// In the case of primitives the number of fields is `0`. Union(usize), /// Array/vector-like placement, with all fields of identical types. diff --git a/src/test/compile-fail/issue-26548.rs b/src/test/compile-fail/issue-26548.rs index fc4f3d1fb53de..85ddf8d9493d5 100644 --- a/src/test/compile-fail/issue-26548.rs +++ b/src/test/compile-fail/issue-26548.rs @@ -11,12 +11,11 @@ //~^^^^^^^^^^ ERROR cycle detected when computing layout of //~| NOTE ...which requires computing layout of //~| NOTE ...which again requires computing layout of -//~| NOTE cycle used when compile_codegen_unit trait Mirror { type It: ?Sized; } impl Mirror for T { type It = Self; } struct S(Option<::It>); -fn main() { +fn main() { //~ NOTE cycle used when processing `main` let _s = S(None); } diff --git a/src/test/ui/const-eval/double_check.rs b/src/test/ui/const-eval/double_check.rs new file mode 100644 index 0000000000000..81f6e7ddd2de2 --- /dev/null +++ b/src/test/ui/const-eval/double_check.rs @@ -0,0 +1,32 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-pass + +enum Foo { + A = 5, + B = 42, +} +enum Bar { + C = 42, + D = 99, +} +union Union { + foo: &'static Foo, + bar: &'static Bar, + usize: &'static usize, +} +static BAR: usize = 42; +static FOO: (&Foo, &Bar) = unsafe {( + Union { usize: &BAR }.foo, + Union { usize: &BAR }.bar, +)}; + +fn main() {} diff --git a/src/test/ui/const-eval/double_check2.rs b/src/test/ui/const-eval/double_check2.rs new file mode 100644 index 0000000000000..b661ee92475e6 --- /dev/null +++ b/src/test/ui/const-eval/double_check2.rs @@ -0,0 +1,30 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +enum Foo { + A = 5, + B = 42, +} +enum Bar { + C = 42, + D = 99, +} +union Union { + foo: &'static Foo, + bar: &'static Bar, + usize: &'static usize, +} +static BAR: usize = 5; +static FOO: (&Foo, &Bar) = unsafe {( //~ undefined behavior + Union { usize: &BAR }.foo, + Union { usize: &BAR }.bar, +)}; + +fn main() {} diff --git a/src/test/ui/const-eval/double_check2.stderr b/src/test/ui/const-eval/double_check2.stderr new file mode 100644 index 0000000000000..2a0a674e237fe --- /dev/null +++ b/src/test/ui/const-eval/double_check2.stderr @@ -0,0 +1,14 @@ +error[E0080]: this static likely exhibits undefined behavior + --> $DIR/double_check2.rs:25:1 + | +LL | / static FOO: (&Foo, &Bar) = unsafe {( //~ undefined behavior +LL | | Union { usize: &BAR }.foo, +LL | | Union { usize: &BAR }.bar, +LL | | )}; + | |___^ type validation failed: encountered 5 at (*.1).TAG, but expected something in the range 42..=99 + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/ui/const-eval/index_out_of_bounds.rs b/src/test/ui/const-eval/index_out_of_bounds.rs index f3578bcef6e41..e7ffbe81b9ae7 100644 --- a/src/test/ui/const-eval/index_out_of_bounds.rs +++ b/src/test/ui/const-eval/index_out_of_bounds.rs @@ -11,7 +11,4 @@ static FOO: i32 = [][0]; //~^ ERROR E0080 -fn main() { - let array = [std::env::args().len()]; - array[1]; //~ ERROR index out of bounds -} +fn main() {} diff --git a/src/test/ui/const-eval/index_out_of_bounds.stderr b/src/test/ui/const-eval/index_out_of_bounds.stderr index 464ba8ff92723..a08d405d4494d 100644 --- a/src/test/ui/const-eval/index_out_of_bounds.stderr +++ b/src/test/ui/const-eval/index_out_of_bounds.stderr @@ -4,14 +4,6 @@ error[E0080]: could not evaluate static initializer LL | static FOO: i32 = [][0]; | ^^^^^ index out of bounds: the len is 0 but the index is 0 -error: index out of bounds: the len is 1 but the index is 1 - --> $DIR/index_out_of_bounds.rs:16:5 - | -LL | array[1]; //~ ERROR index out of bounds - | ^^^^^^^^ - | - = note: #[deny(const_err)] on by default - -error: aborting due to 2 previous errors +error: aborting due to previous error For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/ui/const-eval/index_out_of_bounds_propagated.rs b/src/test/ui/const-eval/index_out_of_bounds_propagated.rs new file mode 100644 index 0000000000000..7a7e2ef0b6b55 --- /dev/null +++ b/src/test/ui/const-eval/index_out_of_bounds_propagated.rs @@ -0,0 +1,14 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn main() { + let array = [std::env::args().len()]; + array[1]; //~ ERROR index out of bounds +} diff --git a/src/test/ui/const-eval/index_out_of_bounds_propagated.stderr b/src/test/ui/const-eval/index_out_of_bounds_propagated.stderr new file mode 100644 index 0000000000000..97badc19c9498 --- /dev/null +++ b/src/test/ui/const-eval/index_out_of_bounds_propagated.stderr @@ -0,0 +1,10 @@ +error: index out of bounds: the len is 1 but the index is 1 + --> $DIR/index_out_of_bounds_propagated.rs:13:5 + | +LL | array[1]; //~ ERROR index out of bounds + | ^^^^^^^^ + | + = note: #[deny(const_err)] on by default + +error: aborting due to previous error + diff --git a/src/test/ui/const-eval/ub-enum-ptr.rs b/src/test/ui/const-eval/ub-enum-ptr.rs new file mode 100644 index 0000000000000..8538dd14afed1 --- /dev/null +++ b/src/test/ui/const-eval/ub-enum-ptr.rs @@ -0,0 +1,27 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#[repr(usize)] +#[derive(Copy, Clone)] +enum Enum { + A = 0, +} + +union Foo { + a: &'static u8, + b: Enum, +} + +// A pointer is guaranteed non-null +const BAD_ENUM: Enum = unsafe { Foo { a: &1 }.b}; +//~^ ERROR this constant likely exhibits undefined behavior + +fn main() { +} diff --git a/src/test/ui/const-eval/ub-enum-ptr.stderr b/src/test/ui/const-eval/ub-enum-ptr.stderr new file mode 100644 index 0000000000000..4b7ccc25c6c01 --- /dev/null +++ b/src/test/ui/const-eval/ub-enum-ptr.stderr @@ -0,0 +1,11 @@ +error[E0080]: this constant likely exhibits undefined behavior + --> $DIR/ub-enum-ptr.rs:23:1 + | +LL | const BAD_ENUM: Enum = unsafe { Foo { a: &1 }.b}; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer at .TAG, but expected something in the range 0..=0 + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/ui/const-eval/ub-ptr-in-usize.rs b/src/test/ui/const-eval/ub-ptr-in-usize.rs new file mode 100644 index 0000000000000..b405f766f9132 --- /dev/null +++ b/src/test/ui/const-eval/ub-ptr-in-usize.rs @@ -0,0 +1,22 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-pass + +union Foo { + a: &'static u8, + b: usize, +} + +// a usize's value may be a pointer, that's fine +const PTR_AS_USIZE: usize = unsafe { Foo { a: &1 }.b}; + +fn main() { +} diff --git a/src/test/ui/const-eval/ub-uninhabit.rs b/src/test/ui/const-eval/ub-uninhabit.rs new file mode 100644 index 0000000000000..a5e341524bc73 --- /dev/null +++ b/src/test/ui/const-eval/ub-uninhabit.rs @@ -0,0 +1,23 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +union Foo { + a: u8, + b: Bar, +} + +#[derive(Copy, Clone)] +enum Bar {} + +const BAD_BAD_BAD: Bar = unsafe { Foo { a: 1 }.b}; +//~^ ERROR this constant likely exhibits undefined behavior + +fn main() { +} diff --git a/src/test/ui/const-eval/ub-uninhabit.stderr b/src/test/ui/const-eval/ub-uninhabit.stderr new file mode 100644 index 0000000000000..623b98dc4531b --- /dev/null +++ b/src/test/ui/const-eval/ub-uninhabit.stderr @@ -0,0 +1,11 @@ +error[E0080]: this constant likely exhibits undefined behavior + --> $DIR/ub-uninhabit.rs:19:1 + | +LL | const BAD_BAD_BAD: Bar = unsafe { Foo { a: 1 }.b}; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of an uninhabited type + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/ui/const-eval/ub-usize-in-ref.rs b/src/test/ui/const-eval/ub-usize-in-ref.rs new file mode 100644 index 0000000000000..aaff2f233815b --- /dev/null +++ b/src/test/ui/const-eval/ub-usize-in-ref.rs @@ -0,0 +1,22 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-pass + +union Foo { + a: &'static u8, + b: usize, +} + +// This might point to an invalid address, but that's the user's problem +const USIZE_AS_STATIC_REF: &'static u8 = unsafe { Foo { b: 1337 }.a}; + +fn main() { +} diff --git a/src/test/ui/const-eval/union-const-eval-field.rs b/src/test/ui/const-eval/union-const-eval-field.rs new file mode 100644 index 0000000000000..41981e1256791 --- /dev/null +++ b/src/test/ui/const-eval/union-const-eval-field.rs @@ -0,0 +1,45 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(const_fn)] + +type Field1 = i32; +type Field2 = f32; +type Field3 = i64; + +union DummyUnion { + field1: Field1, + field2: Field2, + field3: Field3, +} + +const FLOAT1_AS_I32: i32 = 1065353216; +const UNION: DummyUnion = DummyUnion { field1: FLOAT1_AS_I32 }; + +const fn read_field1() -> Field1 { + const FIELD1: Field1 = unsafe { UNION.field1 }; + FIELD1 +} + +const fn read_field2() -> Field2 { + const FIELD2: Field2 = unsafe { UNION.field2 }; + FIELD2 +} + +const fn read_field3() -> Field3 { + const FIELD3: Field3 = unsafe { UNION.field3 }; //~ ERROR exhibits undefined behavior + FIELD3 +} + +fn main() { + assert_eq!(read_field1(), FLOAT1_AS_I32); + assert_eq!(read_field2(), 1.0); + assert_eq!(read_field3(), unsafe { UNION.field3 }); +} diff --git a/src/test/ui/const-eval/union-const-eval-field.stderr b/src/test/ui/const-eval/union-const-eval-field.stderr new file mode 100644 index 0000000000000..94896d6c22577 --- /dev/null +++ b/src/test/ui/const-eval/union-const-eval-field.stderr @@ -0,0 +1,11 @@ +error[E0080]: this constant likely exhibits undefined behavior + --> $DIR/union-const-eval-field.rs:37:5 + | +LL | const FIELD3: Field3 = unsafe { UNION.field3 }; //~ ERROR exhibits undefined behavior + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered undefined bytes + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/ui/const-eval/union-ice.rs b/src/test/ui/const-eval/union-ice.rs new file mode 100644 index 0000000000000..426710389eb29 --- /dev/null +++ b/src/test/ui/const-eval/union-ice.rs @@ -0,0 +1,51 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(const_fn)] + +type Field1 = i32; +type Field3 = i64; + +union DummyUnion { + field1: Field1, + field3: Field3, +} + +const UNION: DummyUnion = DummyUnion { field1: 1065353216 }; + +const FIELD3: Field3 = unsafe { UNION.field3 }; //~ ERROR this constant likely exhibits undefined + +const FIELD_PATH: Struct = Struct { //~ ERROR this constant likely exhibits undefined behavior + a: 42, + b: unsafe { UNION.field3 }, +}; + +struct Struct { + a: u8, + b: Field3, +} + +const FIELD_PATH2: Struct2 = Struct2 { //~ ERROR this constant likely exhibits undefined behavior + b: [ + 21, + unsafe { UNION.field3 }, + 23, + 24, + ], + a: 42, +}; + +struct Struct2 { + b: [Field3; 4], + a: u8, +} + +fn main() { +} diff --git a/src/test/ui/const-eval/union-ice.stderr b/src/test/ui/const-eval/union-ice.stderr new file mode 100644 index 0000000000000..58e9033a071a1 --- /dev/null +++ b/src/test/ui/const-eval/union-ice.stderr @@ -0,0 +1,36 @@ +error[E0080]: this constant likely exhibits undefined behavior + --> $DIR/union-ice.rs:23:1 + | +LL | const FIELD3: Field3 = unsafe { UNION.field3 }; //~ ERROR this constant likely exhibits undefined + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered undefined bytes + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior + +error[E0080]: this constant likely exhibits undefined behavior + --> $DIR/union-ice.rs:25:1 + | +LL | / const FIELD_PATH: Struct = Struct { //~ ERROR this constant likely exhibits undefined behavior +LL | | a: 42, +LL | | b: unsafe { UNION.field3 }, +LL | | }; + | |__^ type validation failed: encountered undefined bytes at .b + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior + +error[E0080]: this constant likely exhibits undefined behavior + --> $DIR/union-ice.rs:35:1 + | +LL | / const FIELD_PATH2: Struct2 = Struct2 { //~ ERROR this constant likely exhibits undefined behavior +LL | | b: [ +LL | | 21, +LL | | unsafe { UNION.field3 }, +... | +LL | | a: 42, +LL | | }; + | |__^ type validation failed: encountered undefined bytes at .b[1] + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/ui/const-eval/union-ub-fat-ptr.rs b/src/test/ui/const-eval/union-ub-fat-ptr.rs new file mode 100644 index 0000000000000..935e69d2e2230 --- /dev/null +++ b/src/test/ui/const-eval/union-ub-fat-ptr.rs @@ -0,0 +1,89 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#[repr(C)] +#[derive(Copy, Clone)] +struct SliceRepr { + ptr: *const u8, + len: usize, +} + +#[repr(C)] +#[derive(Copy, Clone)] +struct BadSliceRepr { + ptr: *const u8, + len: &'static u8, +} + +union SliceTransmute { + repr: SliceRepr, + bad: BadSliceRepr, + slice: &'static [u8], + str: &'static str, +} + +#[repr(C)] +#[derive(Copy, Clone)] +struct DynRepr { + ptr: *const u8, + vtable: *const u8, +} + +#[repr(C)] +#[derive(Copy, Clone)] +struct DynRepr2 { + ptr: *const u8, + vtable: *const u64, +} + +#[repr(C)] +#[derive(Copy, Clone)] +struct BadDynRepr { + ptr: *const u8, + vtable: usize, +} + +union DynTransmute { + repr: DynRepr, + repr2: DynRepr2, + bad: BadDynRepr, + rust: &'static Trait, +} + +trait Trait {} + +// OK +const A: &str = unsafe { SliceTransmute { repr: SliceRepr { ptr: &42, len: 1 } }.str}; +// should lint +const B: &str = unsafe { SliceTransmute { repr: SliceRepr { ptr: &42, len: 999 } }.str}; +// bad +const C: &str = unsafe { SliceTransmute { bad: BadSliceRepr { ptr: &42, len: &3 } }.str}; +//~^ ERROR this constant likely exhibits undefined behavior + +// OK +const A2: &[u8] = unsafe { SliceTransmute { repr: SliceRepr { ptr: &42, len: 1 } }.slice}; +// should lint +const B2: &[u8] = unsafe { SliceTransmute { repr: SliceRepr { ptr: &42, len: 999 } }.slice}; +// bad +const C2: &[u8] = unsafe { SliceTransmute { bad: BadSliceRepr { ptr: &42, len: &3 } }.slice}; +//~^ ERROR this constant likely exhibits undefined behavior + +// bad +const D: &Trait = unsafe { DynTransmute { repr: DynRepr { ptr: &92, vtable: &3 } }.rust}; +//~^ ERROR this constant likely exhibits undefined behavior +// bad +const E: &Trait = unsafe { DynTransmute { repr2: DynRepr2 { ptr: &92, vtable: &3 } }.rust}; +//~^ ERROR this constant likely exhibits undefined behavior +// bad +const F: &Trait = unsafe { DynTransmute { bad: BadDynRepr { ptr: &92, vtable: 3 } }.rust}; +//~^ ERROR this constant likely exhibits undefined behavior + +fn main() { +} diff --git a/src/test/ui/const-eval/union-ub-fat-ptr.stderr b/src/test/ui/const-eval/union-ub-fat-ptr.stderr new file mode 100644 index 0000000000000..3a52db3c1a31d --- /dev/null +++ b/src/test/ui/const-eval/union-ub-fat-ptr.stderr @@ -0,0 +1,43 @@ +error[E0080]: this constant likely exhibits undefined behavior + --> $DIR/union-ub-fat-ptr.rs:67:1 + | +LL | const C: &str = unsafe { SliceTransmute { bad: BadSliceRepr { ptr: &42, len: &3 } }.str}; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered length is not a valid integer + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior + +error[E0080]: this constant likely exhibits undefined behavior + --> $DIR/union-ub-fat-ptr.rs:75:1 + | +LL | const C2: &[u8] = unsafe { SliceTransmute { bad: BadSliceRepr { ptr: &42, len: &3 } }.slice}; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered length is not a valid integer + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior + +error[E0080]: this constant likely exhibits undefined behavior + --> $DIR/union-ub-fat-ptr.rs:79:1 + | +LL | const D: &Trait = unsafe { DynTransmute { repr: DynRepr { ptr: &92, vtable: &3 } }.rust}; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ tried to access memory with alignment 1, but alignment 8 is required + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior + +error[E0080]: this constant likely exhibits undefined behavior + --> $DIR/union-ub-fat-ptr.rs:82:1 + | +LL | const E: &Trait = unsafe { DynTransmute { repr2: DynRepr2 { ptr: &92, vtable: &3 } }.rust}; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access at offset 16, outside bounds of allocation 40 which has size 8 + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior + +error[E0080]: this constant likely exhibits undefined behavior + --> $DIR/union-ub-fat-ptr.rs:85:1 + | +LL | const F: &Trait = unsafe { DynTransmute { bad: BadDynRepr { ptr: &92, vtable: 3 } }.rust}; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered vtable address is not a 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 rust compiler repository if you believe it should not be considered undefined behavior + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/ui/const-eval/union-ub.rs b/src/test/ui/const-eval/union-ub.rs new file mode 100644 index 0000000000000..db36764c4a306 --- /dev/null +++ b/src/test/ui/const-eval/union-ub.rs @@ -0,0 +1,45 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +union DummyUnion { + u8: u8, + bool: bool, +} + +#[repr(C)] +#[derive(Copy, Clone)] +enum Enum { + A, + B, + C, +} + +#[derive(Copy, Clone)] +union Foo { + a: bool, + b: Enum, +} + +union Bar { + foo: Foo, + u8: u8, +} + +// the value is not valid for bools +const BAD_BOOL: bool = unsafe { DummyUnion { u8: 42 }.bool}; +//~^ ERROR this constant likely exhibits undefined behavior + +// The value is not valid for any union variant, but that's fine +// unions are just a convenient way to transmute bits around +const BAD_UNION: Foo = unsafe { Bar { u8: 42 }.foo }; + + +fn main() { +} diff --git a/src/test/ui/const-eval/union-ub.stderr b/src/test/ui/const-eval/union-ub.stderr new file mode 100644 index 0000000000000..2a04dae337b27 --- /dev/null +++ b/src/test/ui/const-eval/union-ub.stderr @@ -0,0 +1,11 @@ +error[E0080]: this constant likely exhibits undefined behavior + --> $DIR/union-ub.rs:36:1 + | +LL | const BAD_BOOL: bool = unsafe { DummyUnion { u8: 42 }.bool}; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 42, but expected something in the range 0..=1 + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/src/tools/miri b/src/tools/miri index 911aedf736992..062cf07d98822 160000 --- a/src/tools/miri +++ b/src/tools/miri @@ -1 +1 @@ -Subproject commit 911aedf736992e907d11cb494167f41f28d02368 +Subproject commit 062cf07d98822beb4c5b1132f47b4397275f403a From 35371b5d9892bf0284d16f727011bbcd65bef8d4 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Thu, 26 Jul 2018 14:38:41 +0200 Subject: [PATCH 14/17] Update miri submodule --- src/Cargo.lock | 17 ++++++++++------- src/tools/miri | 2 +- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/src/Cargo.lock b/src/Cargo.lock index 09baaeadaee43..f0a565f5cbf86 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -321,7 +321,7 @@ dependencies = [ "cargo_metadata 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)", "clippy-mini-macro-test 0.2.0", "clippy_lints 0.0.212", - "compiletest_rs 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)", + "compiletest_rs 0.3.12 (registry+https://github.com/rust-lang/crates.io-index)", "derive-new 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -419,7 +419,7 @@ dependencies = [ [[package]] name = "compiletest_rs" -version = "0.3.11" +version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "diff 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1239,7 +1239,7 @@ dependencies = [ "byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "cargo_metadata 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "colored 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "compiletest_rs 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)", + "compiletest_rs 0.3.12 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1383,7 +1383,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2497,8 +2497,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "smallvec" -version = "0.6.2" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] name = "socket2" @@ -3076,7 +3079,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum colored 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b0aa3473e85a3161b59845d6096b289bb577874cafeaf75ea1b1beaa6572c7fc" "checksum commoncrypto 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d056a8586ba25a1e4d61cb090900e495952c7886786fc55f909ab2f819b69007" "checksum commoncrypto-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1fed34f46747aa73dfaa578069fd8279d2818ade2b55f38f22a9401c7f4083e2" -"checksum compiletest_rs 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)" = "04cea0fe8b8aaca8143af607ad69076866c9f08b83c4b7faca0e993e5486831b" +"checksum compiletest_rs 0.3.12 (registry+https://github.com/rust-lang/crates.io-index)" = "51a2709709e55b8e365c58bb41b5446e417d24baa9817fa8760175f6822ec81d" "checksum core-foundation 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cc3532ec724375c7cb7ff0a097b714fde180bb1f6ed2ab27cfcd99ffca873cd2" "checksum core-foundation-sys 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a3fb15cdbdd9cf8b82d97d0296bb5cd3631bba58d6e31650a002a8e7fb5721f9" "checksum crossbeam 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "24ce9782d4d5c53674646a6a4c1863a21a8fc0cb649b3c94dfc16e45071dea19" @@ -3237,7 +3240,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum shell-escape 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "170a13e64f2a51b77a45702ba77287f5c6829375b04a69cf2222acd17d0cfab9" "checksum shlex 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7fdf1b9db47230893d76faad238fd6097fd6d6a9245cd7a4d90dbd639536bbd2" "checksum siphasher 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0df90a788073e8d0235a67e50441d47db7c8ad9debd91cbf43736a2a92d36537" -"checksum smallvec 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "312a7df010092e73d6bbaf141957e868d4f30efd2bfd9bb1028ad91abec58514" +"checksum smallvec 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "26df3bb03ca5eac2e64192b723d51f56c1b1e0860e7c766281f4598f181acdc8" "checksum socket2 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "962a516af4d3a7c272cb3a1d50a8cc4e5b41802e4ad54cfb7bee8ba61d37d703" "checksum stable_deref_trait 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ffbc596e092fe5f598b12ef46cc03754085ac2f4d8c739ad61c4ae266cc3b3fa" "checksum string_cache 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "25d70109977172b127fe834e5449e5ab1740b9ba49fa18a2020f509174f25423" diff --git a/src/tools/miri b/src/tools/miri index 062cf07d98822..e6f1e15676c26 160000 --- a/src/tools/miri +++ b/src/tools/miri @@ -1 +1 @@ -Subproject commit 062cf07d98822beb4c5b1132f47b4397275f403a +Subproject commit e6f1e15676c26fdc7c4713647fe007b26f361a8e From fd616eb2898177bd90728a6895441fdd751cc499 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Thu, 26 Jul 2018 17:46:09 +0200 Subject: [PATCH 15/17] Move a test that depends on the arch bitwidth to compile-fail --- .../union-ub-fat-ptr.rs | 0 .../ui/const-eval/union-ub-fat-ptr.stderr | 43 ------------------- 2 files changed, 43 deletions(-) rename src/test/{ui/const-eval => compile-fail}/union-ub-fat-ptr.rs (100%) delete mode 100644 src/test/ui/const-eval/union-ub-fat-ptr.stderr diff --git a/src/test/ui/const-eval/union-ub-fat-ptr.rs b/src/test/compile-fail/union-ub-fat-ptr.rs similarity index 100% rename from src/test/ui/const-eval/union-ub-fat-ptr.rs rename to src/test/compile-fail/union-ub-fat-ptr.rs diff --git a/src/test/ui/const-eval/union-ub-fat-ptr.stderr b/src/test/ui/const-eval/union-ub-fat-ptr.stderr deleted file mode 100644 index 3a52db3c1a31d..0000000000000 --- a/src/test/ui/const-eval/union-ub-fat-ptr.stderr +++ /dev/null @@ -1,43 +0,0 @@ -error[E0080]: this constant likely exhibits undefined behavior - --> $DIR/union-ub-fat-ptr.rs:67:1 - | -LL | const C: &str = unsafe { SliceTransmute { bad: BadSliceRepr { ptr: &42, len: &3 } }.str}; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered length is not a valid integer - | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior - -error[E0080]: this constant likely exhibits undefined behavior - --> $DIR/union-ub-fat-ptr.rs:75:1 - | -LL | const C2: &[u8] = unsafe { SliceTransmute { bad: BadSliceRepr { ptr: &42, len: &3 } }.slice}; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered length is not a valid integer - | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior - -error[E0080]: this constant likely exhibits undefined behavior - --> $DIR/union-ub-fat-ptr.rs:79:1 - | -LL | const D: &Trait = unsafe { DynTransmute { repr: DynRepr { ptr: &92, vtable: &3 } }.rust}; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ tried to access memory with alignment 1, but alignment 8 is required - | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior - -error[E0080]: this constant likely exhibits undefined behavior - --> $DIR/union-ub-fat-ptr.rs:82:1 - | -LL | const E: &Trait = unsafe { DynTransmute { repr2: DynRepr2 { ptr: &92, vtable: &3 } }.rust}; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access at offset 16, outside bounds of allocation 40 which has size 8 - | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior - -error[E0080]: this constant likely exhibits undefined behavior - --> $DIR/union-ub-fat-ptr.rs:85:1 - | -LL | const F: &Trait = unsafe { DynTransmute { bad: BadDynRepr { ptr: &92, vtable: 3 } }.rust}; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered vtable address is not a 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 rust compiler repository if you believe it should not be considered undefined behavior - -error: aborting due to 5 previous errors - -For more information about this error, try `rustc --explain E0080`. From e25c3e2f16ca89bda5d785cce41b1472003edbae Mon Sep 17 00:00:00 2001 From: Zakarum Date: Fri, 27 Jul 2018 15:26:57 +0300 Subject: [PATCH 16/17] Fix doc comment for 'ptr::copy_to' method --- src/libcore/ptr.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index be82ab44cd1fc..fe5914c72e1ac 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -1162,8 +1162,8 @@ impl *const T { /// /// Care must be taken with the ownership of `self` and `dest`. /// This method semantically moves the values of `self` into `dest`. - /// However it does not drop the contents of `self`, or prevent the contents - /// of `dest` from being dropped or used. + /// However it does not drop the contents of `dest`, or prevent the contents + /// of `self` from being dropped or used. /// /// # Examples /// From a171ed2164cfce1301842495c509df01951b8282 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 27 Jul 2018 15:10:52 +0200 Subject: [PATCH 17/17] revert accidental atty downgrade --- src/Cargo.lock | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/Cargo.lock b/src/Cargo.lock index 09baaeadaee43..8594e4ff1306d 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -87,7 +87,7 @@ dependencies = [ [[package]] name = "atty" -version = "0.2.10" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", @@ -187,7 +187,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "cargo" version = "0.30.0" dependencies = [ - "atty 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", + "atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "bufstream 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)", "core-foundation 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -303,7 +303,7 @@ version = "2.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "atty 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", + "atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "textwrap 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -622,7 +622,7 @@ name = "env_logger" version = "0.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "atty 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", + "atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "humantime 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "regex 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1844,7 +1844,7 @@ name = "rustc-ap-rustc_errors" version = "182.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "atty 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", + "atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-ap-rustc_data_structures 182.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-ap-serialize 182.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-ap-syntax_pos 182.0.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2097,7 +2097,7 @@ dependencies = [ name = "rustc_errors" version = "0.0.0" dependencies = [ - "atty 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", + "atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_data_structures 0.0.0", "serialize 0.0.0", "syntax_pos 0.0.0", @@ -3056,7 +3056,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" "checksum arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "a1e964f9e24d588183fcb43503abda40d288c8657dfc27311516ce2f05675aef" "checksum assert_cli 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "98589b0e465a6c510d95fceebd365bb79bedece7f6e18a480897f2015f85ec51" -"checksum atty 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "2fc4a1aa4c24c0718a250f0681885c1af91419d242f29eb8f2ab28502d80dbd1" +"checksum atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652" "checksum backtrace 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "89a47830402e9981c5c41223151efcced65a0510c13097c769cede7efb34782a" "checksum backtrace-sys 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)" = "bff67d0c06556c0b8e6b5f090f0eac52d950d9dfd1d35ba04e4ca3543eaf6a7e" "checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d"