diff --git a/src/Cargo.lock b/src/Cargo.lock index 09baaeadaee43..a146078572c15 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)", @@ -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)", @@ -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)", @@ -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)", ] @@ -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", @@ -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" @@ -3056,7 +3059,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" @@ -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/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) } } 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} < *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 /// diff --git a/src/libcore/slice/memchr.rs b/src/libcore/slice/memchr.rs index 7b62e7b0620fd..72e7b57a6cb3c 100644 --- a/src/libcore/slice/memchr.rs +++ b/src/libcore/slice/memchr.rs @@ -102,16 +102,13 @@ pub fn memrchr(x: u8, text: &[u8]) -> Option { let ptr = text.as_ptr(); let usize_bytes = mem::size_of::(); - // search to an aligned boundary - let end_align = (ptr as usize + len) & (usize_bytes - 1); - 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 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/session/config.rs b/src/librustc/session/config.rs index 4490b2f3fa91a..9fbf4e7c6a0f4 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -1247,8 +1247,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], @@ -3168,10 +3166,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 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_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) } } 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/librustc_target/spec/aarch64_unknown_fuchsia.rs b/src/librustc_target/spec/aarch64_fuchsia.rs similarity index 91% rename from src/librustc_target/spec/aarch64_unknown_fuchsia.rs rename to src/librustc_target/spec/aarch64_fuchsia.rs index 4da6724ef6286..28baf6f66e7a1 100644 --- a/src/librustc_target/spec/aarch64_unknown_fuchsia.rs +++ b/src/librustc_target/spec/aarch64_fuchsia.rs @@ -15,7 +15,7 @@ pub fn target() -> 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/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, 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, diff --git a/src/libstd/thread/mod.rs b/src/libstd/thread/mod.rs index 90f054186d161..ebd9e8ba73196 100644 --- a/src/libstd/thread/mod.rs +++ b/src/libstd/thread/mod.rs @@ -1276,6 +1276,11 @@ 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 { /// Extracts a handle to the underlying thread. /// 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/compile-fail/union-ub-fat-ptr.rs b/src/test/compile-fail/union-ub-fat-ptr.rs new file mode 100644 index 0000000000000..935e69d2e2230 --- /dev/null +++ b/src/test/compile-fail/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/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/liballoc/repeat-generic-slice.rs b/src/test/ui/const-eval/ub-enum-ptr.rs similarity index 62% rename from src/liballoc/repeat-generic-slice.rs rename to src/test/ui/const-eval/ub-enum-ptr.rs index 5c14ee4fd83b4..8538dd14afed1 100644 --- a/src/liballoc/repeat-generic-slice.rs +++ b/src/test/ui/const-eval/ub-enum-ptr.rs @@ -8,12 +8,20 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(repeat_generic_slice)] +#[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() { - 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/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.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/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 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", diff --git a/src/tools/miri b/src/tools/miri index 911aedf736992..e6f1e15676c26 160000 --- a/src/tools/miri +++ b/src/tools/miri @@ -1 +1 @@ -Subproject commit 911aedf736992e907d11cb494167f41f28d02368 +Subproject commit e6f1e15676c26fdc7c4713647fe007b26f361a8e