diff options
1009 files changed, 14473 insertions, 16237 deletions
diff --git a/.github/ISSUE_TEMPLATE/regression.md b/.github/ISSUE_TEMPLATE/regression.md new file mode 100644 index 00000000000..ffab883987c --- /dev/null +++ b/.github/ISSUE_TEMPLATE/regression.md @@ -0,0 +1,68 @@ +--- +name: Regression +about: Report something that unexpectedly changed between Rust versions. +labels: C-bug regression-untriaged +--- +<!-- +Thank you for filing a regression report! 🐛 A regression is something that changed between versions of Rust but was not supposed to. + +Please provide a short summary of the regression, along with any information you feel is relevant to replicate it. +--> + +### Code + +I tried this code: + +```rust +<code> +``` + +I expected to see this happen: *explanation* + +Instead, this happened: *explanation* + +### Version it worked on + +<!-- +Provide the most recent version this worked on, for example: + +It most recently worked on: Rust 1.47 +--> + +It most recently worked on: <!-- version --> + +### Version with regression + +<!-- +Provide the version you are using that has the regression. +--> + +`rustc --version --verbose`: +``` +<version> +``` + +<!-- +Did the compiler crash? If so, please provide a backtrace. +--> + +### Backtrace +<!-- +Include a backtrace in the code block by setting `RUST_BACKTRACE=1` in your +environment. E.g. `RUST_BACKTRACE=1 cargo build`. +--> +<details><summary>Backtrace</summary> +<p> + +``` +<backtrace> +``` + +</p> +</details> + +<!-- +If you know when this regression occurred, please add a line like below, replacing `{channel}` with one of stable, beta, or nightly. + +@rustbot modify labels: +regression-from-stable-to-{channel} -regression-untriaged +--> diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 23058b7a808..6025808eb61 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -89,6 +89,9 @@ jobs: - name: install sccache run: src/ci/scripts/install-sccache.sh if: success() && !env.SKIP_JOB + - name: select Xcode + run: src/ci/scripts/select-xcode.sh + if: success() && !env.SKIP_JOB - name: install clang run: src/ci/scripts/install-clang.sh if: success() && !env.SKIP_JOB @@ -300,6 +303,20 @@ jobs: NO_LLVM_ASSERTIONS: 1 NO_DEBUG_ASSERTIONS: 1 os: macos-latest + - name: dist-aarch64-apple + env: + SCRIPT: "./x.py dist --stage 2" + RUST_CONFIGURE_ARGS: "--build=x86_64-apple-darwin --host=aarch64-apple-darwin --target=aarch64-apple-darwin --enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false" + RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 + SELECT_XCODE: /Applications/Xcode_12.2.app + USE_XCODE_CLANG: 1 + MACOSX_DEPLOYMENT_TARGET: 11.0 + MACOSX_STD_DEPLOYMENT_TARGET: 11.0 + NO_LLVM_ASSERTIONS: 1 + NO_DEBUG_ASSERTIONS: 1 + DIST_REQUIRE_ALL_TOOLS: 1 + JEMALLOC_SYS_WITH_LG_PAGE: 14 + os: macos-latest - name: x86_64-msvc-1 env: RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-msvc --enable-profiler" @@ -369,7 +386,7 @@ jobs: os: windows-latest-xl - name: dist-x86_64-msvc env: - RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-msvc --host=x86_64-pc-windows-msvc --target=x86_64-pc-windows-msvc,aarch64-pc-windows-msvc --enable-full-tools --enable-profiler" + RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-msvc --host=x86_64-pc-windows-msvc --target=x86_64-pc-windows-msvc --enable-full-tools --enable-profiler" SCRIPT: python x.py dist DIST_REQUIRE_ALL_TOOLS: 1 os: windows-latest-xl @@ -379,6 +396,12 @@ jobs: SCRIPT: python x.py dist DIST_REQUIRE_ALL_TOOLS: 1 os: windows-latest-xl + - name: dist-aarch64-msvc + env: + RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-msvc --host=aarch64-pc-windows-msvc --enable-full-tools --enable-profiler" + SCRIPT: python x.py dist + DIST_REQUIRE_ALL_TOOLS: 0 + os: windows-latest-xl - name: dist-i686-mingw env: RUST_CONFIGURE_ARGS: "--build=i686-pc-windows-gnu --enable-full-tools --enable-profiler" @@ -437,6 +460,9 @@ jobs: - name: install sccache run: src/ci/scripts/install-sccache.sh if: success() && !env.SKIP_JOB + - name: select Xcode + run: src/ci/scripts/select-xcode.sh + if: success() && !env.SKIP_JOB - name: install clang run: src/ci/scripts/install-clang.sh if: success() && !env.SKIP_JOB @@ -544,6 +570,9 @@ jobs: - name: install sccache run: src/ci/scripts/install-sccache.sh if: success() && !env.SKIP_JOB + - name: select Xcode + run: src/ci/scripts/select-xcode.sh + if: success() && !env.SKIP_JOB - name: install clang run: src/ci/scripts/install-clang.sh if: success() && !env.SKIP_JOB @@ -648,6 +677,9 @@ jobs: - name: install sccache run: src/ci/scripts/install-sccache.sh if: success() && !env.SKIP_JOB + - name: select Xcode + run: src/ci/scripts/select-xcode.sh + if: success() && !env.SKIP_JOB - name: install clang run: src/ci/scripts/install-clang.sh if: success() && !env.SKIP_JOB diff --git a/.gitmodules b/.gitmodules index d460b6508f6..984113151de 100644 --- a/.gitmodules +++ b/.gitmodules @@ -37,7 +37,7 @@ [submodule "src/llvm-project"] path = src/llvm-project url = https://github.com/rust-lang/llvm-project.git - branch = rustc/11.0-2020-09-22 + branch = rustc/11.0-2020-10-12 [submodule "src/doc/embedded-book"] path = src/doc/embedded-book url = https://github.com/rust-embedded/book.git diff --git a/Cargo.lock b/Cargo.lock index ea160ba2733..0d2170a9927 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -243,6 +243,7 @@ dependencies = [ "anyhow", "flate2", "hex 0.4.2", + "num_cpus", "rayon", "serde", "serde_json", @@ -294,7 +295,7 @@ checksum = "81a18687293a1546b67c246452202bbbf143d239cb43494cc163da14979082da" [[package]] name = "cargo" -version = "0.49.0" +version = "0.50.0" dependencies = [ "anyhow", "atty", @@ -305,7 +306,7 @@ dependencies = [ "clap", "core-foundation", "crates-io", - "crossbeam-utils 0.7.2", + "crossbeam-utils 0.8.0", "crypto-hash", "curl", "curl-sys", @@ -676,6 +677,12 @@ dependencies = [ ] [[package]] +name = "const_fn" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce90df4c658c62f12d78f7508cf92f9173e5184a539c10bfe54a3107b3ffd0f2" + +[[package]] name = "constant_time_eq" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -733,12 +740,12 @@ dependencies = [ [[package]] name = "crossbeam-channel" -version = "0.4.3" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09ee0cc8804d5393478d743b035099520087a5186f3b93fa58cec08fa62407b6" +checksum = "b153fe7cbef478c567df0f972e02e6d736db11affe43dfc9c56a9374d1adfb87" dependencies = [ - "cfg-if 0.1.10", "crossbeam-utils 0.7.2", + "maybe-uninit", ] [[package]] @@ -809,6 +816,18 @@ dependencies = [ ] [[package]] +name = "crossbeam-utils" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec91540d98355f690a86367e566ecad2e9e579f230230eb7c21398372be73ea5" +dependencies = [ + "autocfg", + "cfg-if 1.0.0", + "const_fn", + "lazy_static", +] + +[[package]] name = "crypto-hash" version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1254,9 +1273,9 @@ dependencies = [ [[package]] name = "git2" -version = "0.13.8" +version = "0.13.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6ac22e49b7d886b6802c66662b12609452248b1bc9e87d6d83ecea3db96f557" +checksum = "ca6f1a0238d7f8f8fd5ee642f4ebac4dbc03e03d1f78fbe7a3ede35dcf7e2224" dependencies = [ "bitflags", "libc", @@ -1674,9 +1693,9 @@ dependencies = [ [[package]] name = "libgit2-sys" -version = "0.12.9+1.0.1" +version = "0.12.14+1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b33bf3d9d4c45b48ae1ea7c334be69994624dc0a69f833d5d9f7605f24b552b" +checksum = "8f25af58e6495f7caf2919d08f212de550cfa3ed2f5e744988938ea292b9f549" dependencies = [ "cc", "libc", @@ -1698,9 +1717,9 @@ dependencies = [ [[package]] name = "libssh2-sys" -version = "0.2.18" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eafa907407504b0e683786d4aba47acf250f114d37357d56608333fd167dd0fc" +checksum = "ca46220853ba1c512fc82826d0834d87b06bcd3c2a42241b7de72f3d2fe17056" dependencies = [ "cc", "libc", @@ -1725,6 +1744,10 @@ dependencies = [ [[package]] name = "linkchecker" version = "0.1.0" +dependencies = [ + "once_cell", + "regex", +] [[package]] name = "linked-hash-map" @@ -2191,9 +2214,9 @@ checksum = "77af24da69f9d9341038eba93a073b1fdaaa1b788221b00a69bce9e762cb32de" [[package]] name = "openssl-src" -version = "111.10.2+1.1.1g" +version = "111.12.0+1.1.1h" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a287fdb22e32b5b60624d4a5a7a02dbe82777f730ec0dbc42a0554326fef5a70" +checksum = "858a4132194f8570a7ee9eb8629e85b23cbc4565f2d4a162e87556e5956abf61" dependencies = [ "cc", ] @@ -3349,7 +3372,6 @@ dependencies = [ name = "rustc_arena" version = "0.0.0" dependencies = [ - "rustc_data_structures", "smallvec 1.4.2", ] @@ -5079,9 +5101,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.5.6" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffc92d160b1eef40665be3a05630d003936a3bc7da7421277846c2613e92c71a" +checksum = "75cf45bb0bef80604d001caaec0d09da99611b3c0fd39d3080468875cdb65645" dependencies = [ "serde", ] diff --git a/README.md b/README.md index d445bbdf6e8..07c09604664 100644 --- a/README.md +++ b/README.md @@ -9,8 +9,7 @@ standard library, and documentation. **Note: this README is for _users_ rather than _contributors_. If you wish to _contribute_ to the compiler, you should read the -[Getting Started][gettingstarted] of the rustc-dev-guide instead of this -section.** +[Getting Started][gettingstarted] section of the rustc-dev-guide instead.** ## Quick Start diff --git a/compiler/rustc_arena/Cargo.toml b/compiler/rustc_arena/Cargo.toml index 41701f3255f..29caa852ed4 100644 --- a/compiler/rustc_arena/Cargo.toml +++ b/compiler/rustc_arena/Cargo.toml @@ -5,5 +5,4 @@ version = "0.0.0" edition = "2018" [dependencies] -rustc_data_structures = { path = "../rustc_data_structures" } smallvec = { version = "1.0", features = ["union", "may_dangle"] } diff --git a/compiler/rustc_arena/src/lib.rs b/compiler/rustc_arena/src/lib.rs index 166f7f53c41..34736b820e9 100644 --- a/compiler/rustc_arena/src/lib.rs +++ b/compiler/rustc_arena/src/lib.rs @@ -16,7 +16,6 @@ #![feature(maybe_uninit_slice)] #![cfg_attr(test, feature(test))] -use rustc_data_structures::cold_path; use smallvec::SmallVec; use std::alloc::Layout; @@ -27,6 +26,12 @@ use std::mem::{self, MaybeUninit}; use std::ptr; use std::slice; +#[inline(never)] +#[cold] +pub fn cold_path<F: FnOnce() -> R, R>(f: F) -> R { + f() +} + /// An arena that can hold objects of only one type. pub struct TypedArena<T> { /// A pointer to the next object to be allocated. @@ -218,10 +223,8 @@ impl<T> TypedArena<T> { // If the previous chunk's len is less than HUGE_PAGE // bytes, then this chunk will be least double the previous // chunk's size. - new_cap = last_chunk.storage.len(); - if new_cap < HUGE_PAGE / elem_size { - new_cap = new_cap.checked_mul(2).unwrap(); - } + new_cap = last_chunk.storage.len().min(HUGE_PAGE / elem_size / 2); + new_cap = new_cap * 2; } else { new_cap = PAGE / elem_size; } @@ -338,10 +341,8 @@ impl DroplessArena { // If the previous chunk's len is less than HUGE_PAGE // bytes, then this chunk will be least double the previous // chunk's size. - new_cap = last_chunk.storage.len(); - if new_cap < HUGE_PAGE { - new_cap = new_cap.checked_mul(2).unwrap(); - } + new_cap = last_chunk.storage.len().min(HUGE_PAGE / 2); + new_cap = new_cap * 2; } else { new_cap = PAGE; } diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 245353c2e07..ea84fc0095f 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -167,13 +167,6 @@ pub enum GenericArgs { } impl GenericArgs { - pub fn is_parenthesized(&self) -> bool { - match *self { - Parenthesized(..) => true, - _ => false, - } - } - pub fn is_angle_bracketed(&self) -> bool { match *self { AngleBracketed(..) => true, @@ -857,13 +850,6 @@ impl BinOpKind { } } - pub fn is_shift(&self) -> bool { - match *self { - BinOpKind::Shl | BinOpKind::Shr => true, - _ => false, - } - } - pub fn is_comparison(&self) -> bool { use BinOpKind::*; // Note for developers: please keep this as is; @@ -873,11 +859,6 @@ impl BinOpKind { And | Or | Add | Sub | Mul | Div | Rem | BitXor | BitAnd | BitOr | Shl | Shr => false, } } - - /// Returns `true` if the binary operator takes its arguments by value - pub fn is_by_value(&self) -> bool { - !self.is_comparison() - } } pub type BinOp = Spanned<BinOpKind>; @@ -896,14 +877,6 @@ pub enum UnOp { } impl UnOp { - /// Returns `true` if the unary operator takes its argument by value - pub fn is_by_value(u: UnOp) -> bool { - match u { - UnOp::Neg | UnOp::Not => true, - _ => false, - } - } - pub fn to_string(op: UnOp) -> &'static str { match op { UnOp::Deref => "*", @@ -1179,6 +1152,7 @@ impl Expr { match self.kind { ExprKind::Box(_) => ExprPrecedence::Box, ExprKind::Array(_) => ExprPrecedence::Array, + ExprKind::ConstBlock(_) => ExprPrecedence::ConstBlock, ExprKind::Call(..) => ExprPrecedence::Call, ExprKind::MethodCall(..) => ExprPrecedence::MethodCall, ExprKind::Tup(_) => ExprPrecedence::Tup, @@ -1234,6 +1208,8 @@ pub enum ExprKind { Box(P<Expr>), /// An array (`[a, b, c, d]`) Array(Vec<P<Expr>>), + /// Allow anonymous constants from an inline `const` block + ConstBlock(AnonConst), /// A function call /// /// The first field resolves to the function itself, @@ -1753,13 +1729,6 @@ impl IntTy { } } - pub fn val_to_string(&self, val: i128) -> String { - // Cast to a `u128` so we can correctly print `INT128_MIN`. All integral types - // are parsed as `u128`, so we wouldn't want to print an extra negative - // sign. - format!("{}{}", val as u128, self.name_str()) - } - pub fn bit_width(&self) -> Option<u64> { Some(match *self { IntTy::Isize => return None, @@ -1818,10 +1787,6 @@ impl UintTy { } } - pub fn val_to_string(&self, val: u128) -> String { - format!("{}{}", val, self.name_str()) - } - pub fn bit_width(&self) -> Option<u64> { Some(match *self { UintTy::Usize => return None, diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs index 2782869fb88..8351be222f6 100644 --- a/compiler/rustc_ast/src/attr/mod.rs +++ b/compiler/rustc_ast/src/attr/mod.rs @@ -101,11 +101,6 @@ impl NestedMetaItem { self.meta_item().is_some() } - /// Returns `true` if the variant is `Literal`. - pub fn is_literal(&self) -> bool { - self.literal().is_some() - } - /// Returns `true` if `self` is a `MetaItem` and the meta item is a word. pub fn is_word(&self) -> bool { self.meta_item().map_or(false, |meta_item| meta_item.is_word()) @@ -232,10 +227,6 @@ impl MetaItem { pub fn is_value_str(&self) -> bool { self.value_str().is_some() } - - pub fn is_meta_item_list(&self) -> bool { - self.meta_item_list().is_some() - } } impl AttrItem { diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index 425ef83b57a..382003c834e 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -1106,6 +1106,9 @@ pub fn noop_visit_expr<T: MutVisitor>( match kind { ExprKind::Box(expr) => vis.visit_expr(expr), ExprKind::Array(exprs) => visit_exprs(exprs, vis), + ExprKind::ConstBlock(anon_const) => { + vis.visit_anon_const(anon_const); + } ExprKind::Repeat(expr, count) => { vis.visit_expr(expr); vis.visit_anon_const(count); diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs index d5b3e87adc3..d991027cb45 100644 --- a/compiler/rustc_ast/src/token.rs +++ b/compiler/rustc_ast/src/token.rs @@ -54,16 +54,6 @@ pub enum DelimToken { NoDelim, } -impl DelimToken { - pub fn len(self) -> usize { - if self == NoDelim { 0 } else { 1 } - } - - pub fn is_empty(self) -> bool { - self == NoDelim - } -} - #[derive(Clone, Copy, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)] pub enum LitKind { Bool, // AST only, must never appear in a `Token` @@ -163,6 +153,7 @@ pub fn ident_can_begin_expr(name: Symbol, span: Span, is_raw: bool) -> bool { kw::Do, kw::Box, kw::Break, + kw::Const, kw::Continue, kw::False, kw::For, @@ -810,10 +801,10 @@ impl Nonterminal { if let ExpnKind::Macro(_, macro_name) = orig_span.ctxt().outer_expn_data().kind { let filename = source_map.span_to_filename(orig_span); if let FileName::Real(RealFileName::Named(path)) = filename { - let matches_prefix = |prefix| { - // Check for a path that ends with 'prefix*/src/lib.rs' + let matches_prefix = |prefix, filename| { + // Check for a path that ends with 'prefix*/src/<filename>' let mut iter = path.components().rev(); - iter.next().and_then(|p| p.as_os_str().to_str()) == Some("lib.rs") + iter.next().and_then(|p| p.as_os_str().to_str()) == Some(filename) && iter.next().and_then(|p| p.as_os_str().to_str()) == Some("src") && iter .next() @@ -821,14 +812,25 @@ impl Nonterminal { .map_or(false, |p| p.starts_with(prefix)) }; - if (macro_name == sym::impl_macros && matches_prefix("time-macros-impl")) - || (macro_name == sym::arrays && matches_prefix("js-sys")) + if (macro_name == sym::impl_macros + && matches_prefix("time-macros-impl", "lib.rs")) + || (macro_name == sym::arrays && matches_prefix("js-sys", "lib.rs")) { let snippet = source_map.span_to_snippet(orig_span); if snippet.as_deref() == Ok("$name") { return Some((*ident, *is_raw)); } } + + if macro_name == sym::tuple_from_req + && (matches_prefix("actix-web", "extract.rs") + || matches_prefix("actori-web", "extract.rs")) + { + let snippet = source_map.span_to_snippet(orig_span); + if snippet.as_deref() == Ok("$T") { + return Some((*ident, *is_raw)); + } + } } } } diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs index f201f0b5c66..8acb6b2f375 100644 --- a/compiler/rustc_ast/src/tokenstream.rs +++ b/compiler/rustc_ast/src/tokenstream.rs @@ -295,12 +295,6 @@ impl TokenStream { .collect(), )) } - - pub fn map<F: FnMut(TokenTree) -> TokenTree>(self, mut f: F) -> TokenStream { - TokenStream(Lrc::new( - self.0.iter().map(|(tree, is_joint)| (f(tree.clone()), *is_joint)).collect(), - )) - } } // 99.5%+ of the time we have 1 or 2 elements in this vector. diff --git a/compiler/rustc_ast/src/util/lev_distance.rs b/compiler/rustc_ast/src/util/lev_distance.rs index 754b1f13381..21c2c925bc4 100644 --- a/compiler/rustc_ast/src/util/lev_distance.rs +++ b/compiler/rustc_ast/src/util/lev_distance.rs @@ -54,7 +54,7 @@ where T: Iterator<Item = &'a Symbol>, { let lookup = &lookup.as_str(); - let max_dist = dist.map_or_else(|| cmp::max(lookup.len(), 3) / 3, |d| d); + let max_dist = dist.unwrap_or_else(|| cmp::max(lookup.len(), 3) / 3); let name_vec: Vec<&Symbol> = iter_names.collect(); let (case_insensitive_match, levenshtein_match) = name_vec diff --git a/compiler/rustc_ast/src/util/parser.rs b/compiler/rustc_ast/src/util/parser.rs index 2ee94965756..078dd4bd6e6 100644 --- a/compiler/rustc_ast/src/util/parser.rs +++ b/compiler/rustc_ast/src/util/parser.rs @@ -231,7 +231,6 @@ impl AssocOp { } } -pub const PREC_RESET: i8 = -100; pub const PREC_CLOSURE: i8 = -40; pub const PREC_JUMP: i8 = -30; pub const PREC_RANGE: i8 = -10; @@ -283,6 +282,7 @@ pub enum ExprPrecedence { ForLoop, Loop, Match, + ConstBlock, Block, TryBlock, Struct, @@ -347,6 +347,7 @@ impl ExprPrecedence { ExprPrecedence::ForLoop | ExprPrecedence::Loop | ExprPrecedence::Match | + ExprPrecedence::ConstBlock | ExprPrecedence::Block | ExprPrecedence::TryBlock | ExprPrecedence::Async | diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index 86fd87f6c42..507b49616ea 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -200,11 +200,7 @@ pub trait Visitor<'ast>: Sized { walk_generic_args(self, path_span, generic_args) } fn visit_generic_arg(&mut self, generic_arg: &'ast GenericArg) { - match generic_arg { - GenericArg::Lifetime(lt) => self.visit_lifetime(lt), - GenericArg::Type(ty) => self.visit_ty(ty), - GenericArg::Const(ct) => self.visit_anon_const(ct), - } + walk_generic_arg(self, generic_arg) } fn visit_assoc_ty_constraint(&mut self, constraint: &'ast AssocTyConstraint) { walk_assoc_ty_constraint(self, constraint) @@ -486,6 +482,17 @@ where } } +pub fn walk_generic_arg<'a, V>(visitor: &mut V, generic_arg: &'a GenericArg) +where + V: Visitor<'a>, +{ + match generic_arg { + GenericArg::Lifetime(lt) => visitor.visit_lifetime(lt), + GenericArg::Type(ty) => visitor.visit_ty(ty), + GenericArg::Const(ct) => visitor.visit_anon_const(ct), + } +} + pub fn walk_assoc_ty_constraint<'a, V: Visitor<'a>>( visitor: &mut V, constraint: &'a AssocTyConstraint, @@ -717,6 +724,7 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) { ExprKind::Array(ref subexpressions) => { walk_list!(visitor, visit_expr, subexpressions); } + ExprKind::ConstBlock(ref anon_const) => visitor.visit_anon_const(anon_const), ExprKind::Repeat(ref element, ref count) => { visitor.visit_expr(element); visitor.visit_anon_const(count) diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 4676ad5c31f..c49fd76a313 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -30,6 +30,10 @@ impl<'hir> LoweringContext<'_, 'hir> { let kind = match e.kind { ExprKind::Box(ref inner) => hir::ExprKind::Box(self.lower_expr(inner)), ExprKind::Array(ref exprs) => hir::ExprKind::Array(self.lower_exprs(exprs)), + ExprKind::ConstBlock(ref anon_const) => { + let anon_const = self.lower_anon_const(anon_const); + hir::ExprKind::ConstBlock(anon_const) + } ExprKind::Repeat(ref expr, ref count) => { let expr = self.lower_expr(expr); let count = self.lower_anon_const(count); @@ -985,7 +989,7 @@ impl<'hir> LoweringContext<'_, 'hir> { asm::InlineAsmReg::parse( sess.asm_arch?, |feature| sess.target_features.contains(&Symbol::intern(feature)), - &sess.target.target, + &sess.target, s, ) .map_err(|e| { @@ -1186,52 +1190,47 @@ impl<'hir> LoweringContext<'_, 'hir> { input| { match used_regs.entry(r) { Entry::Occupied(o) => { - if !skip { - skip = true; - - let idx2 = *o.get(); - let op2 = &operands[idx2]; - let op_sp2 = asm.operands[idx2].1; - let reg2 = match op2.reg() { - Some(asm::InlineAsmRegOrRegClass::Reg(r)) => r, - _ => unreachable!(), - }; - - let msg = format!( - "register `{}` conflicts with register `{}`", - reg.name(), - reg2.name() - ); - let mut err = sess.struct_span_err(op_sp, &msg); - err.span_label( - op_sp, - &format!("register `{}`", reg.name()), - ); - err.span_label( - op_sp2, - &format!("register `{}`", reg2.name()), - ); - - match (op, op2) { - ( - hir::InlineAsmOperand::In { .. }, - hir::InlineAsmOperand::Out { late, .. }, - ) - | ( - hir::InlineAsmOperand::Out { late, .. }, - hir::InlineAsmOperand::In { .. }, - ) => { - assert!(!*late); - let out_op_sp = if input { op_sp2 } else { op_sp }; - let msg = "use `lateout` instead of \ - `out` to avoid conflict"; - err.span_help(out_op_sp, msg); - } - _ => {} + if skip { + return; + } + skip = true; + + let idx2 = *o.get(); + let op2 = &operands[idx2]; + let op_sp2 = asm.operands[idx2].1; + let reg2 = match op2.reg() { + Some(asm::InlineAsmRegOrRegClass::Reg(r)) => r, + _ => unreachable!(), + }; + + let msg = format!( + "register `{}` conflicts with register `{}`", + reg.name(), + reg2.name() + ); + let mut err = sess.struct_span_err(op_sp, &msg); + err.span_label(op_sp, &format!("register `{}`", reg.name())); + err.span_label(op_sp2, &format!("register `{}`", reg2.name())); + + match (op, op2) { + ( + hir::InlineAsmOperand::In { .. }, + hir::InlineAsmOperand::Out { late, .. }, + ) + | ( + hir::InlineAsmOperand::Out { late, .. }, + hir::InlineAsmOperand::In { .. }, + ) => { + assert!(!*late); + let out_op_sp = if input { op_sp2 } else { op_sp }; + let msg = "use `lateout` instead of \ + `out` to avoid conflict"; + err.span_help(out_op_sp, msg); } - - err.emit(); + _ => {} } + + err.emit(); } Entry::Vacant(v) => { v.insert(idx); diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 232ee35c4f7..b1c8e0ee727 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -287,7 +287,7 @@ impl<'a> AstValidator<'a> { // ``` fn check_expr_within_pat(&self, expr: &Expr, allow_paths: bool) { match expr.kind { - ExprKind::Lit(..) | ExprKind::Err => {} + ExprKind::Lit(..) | ExprKind::ConstBlock(..) | ExprKind::Err => {} ExprKind::Path(..) if allow_paths => {} ExprKind::Unary(UnOp::Neg, ref inner) if matches!(inner.kind, ExprKind::Lit(_)) => {} _ => self.err_handler().span_err( @@ -796,7 +796,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { fn visit_expr(&mut self, expr: &'a Expr) { match &expr.kind { - ExprKind::LlvmInlineAsm(..) if !self.session.target.target.options.allow_asm => { + ExprKind::LlvmInlineAsm(..) if !self.session.target.options.allow_asm => { struct_span_err!( self.session, expr.span, diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 00d3db73766..f2008449767 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -629,6 +629,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session) { gate_all!(const_trait_bound_opt_out, "`?const` on trait bounds is experimental"); gate_all!(const_trait_impl, "const trait impls are experimental"); gate_all!(half_open_range_patterns, "half-open range patterns are unstable"); + gate_all!(inline_const, "inline-const is experimental"); // All uses of `gate_all!` below this point were added in #65742, // and subsequently disabled (with the non-early gating readded). diff --git a/compiler/rustc_ast_pretty/src/pp.rs b/compiler/rustc_ast_pretty/src/pp.rs index ca7f127ced6..95f969d7691 100644 --- a/compiler/rustc_ast_pretty/src/pp.rs +++ b/compiler/rustc_ast_pretty/src/pp.rs @@ -170,17 +170,11 @@ pub enum Token { impl Token { crate fn is_eof(&self) -> bool { - match *self { - Token::Eof => true, - _ => false, - } + matches!(self, Token::Eof) } pub fn is_hardbreak_tok(&self) -> bool { - match *self { - Token::Break(BreakToken { offset: 0, blank_space: bs }) if bs == SIZE_INFINITY => true, - _ => false, - } + matches!(self, Token::Break(BreakToken { offset: 0, blank_space: SIZE_INFINITY })) } } @@ -491,12 +485,9 @@ impl Printer { } fn get_top(&mut self) -> PrintStackElem { - match self.print_stack.last() { - Some(el) => *el, - None => { - PrintStackElem { offset: 0, pbreak: PrintStackBreak::Broken(Breaks::Inconsistent) } - } - } + *self.print_stack.last().unwrap_or({ + &PrintStackElem { offset: 0, pbreak: PrintStackBreak::Broken(Breaks::Inconsistent) } + }) } fn print_begin(&mut self, b: BeginToken, l: isize) { diff --git a/compiler/rustc_ast_pretty/src/pprust/mod.rs b/compiler/rustc_ast_pretty/src/pprust/mod.rs new file mode 100644 index 00000000000..b34ea41ab55 --- /dev/null +++ b/compiler/rustc_ast_pretty/src/pprust/mod.rs @@ -0,0 +1,104 @@ +#[cfg(test)] +mod tests; + +pub mod state; +pub use state::{print_crate, AnnNode, Comments, PpAnn, PrintState, State}; + +use rustc_ast as ast; +use rustc_ast::token::{Nonterminal, Token, TokenKind}; +use rustc_ast::tokenstream::{TokenStream, TokenTree}; + +pub fn nonterminal_to_string_no_extra_parens(nt: &Nonterminal) -> String { + let state = State::without_insert_extra_parens(); + state.nonterminal_to_string(nt) +} + +pub fn nonterminal_to_string(nt: &Nonterminal) -> String { + State::new().nonterminal_to_string(nt) +} + +/// Print the token kind precisely, without converting `$crate` into its respective crate name. +pub fn token_kind_to_string(tok: &TokenKind) -> String { + State::new().token_kind_to_string(tok) +} + +/// Print the token precisely, without converting `$crate` into its respective crate name. +pub fn token_to_string(token: &Token) -> String { + State::new().token_to_string(token) +} + +pub fn token_to_string_ext(token: &Token, convert_dollar_crate: bool) -> String { + State::new().token_to_string_ext(token, convert_dollar_crate) +} + +pub fn ty_to_string(ty: &ast::Ty) -> String { + State::new().ty_to_string(ty) +} + +pub fn bounds_to_string(bounds: &[ast::GenericBound]) -> String { + State::new().bounds_to_string(bounds) +} + +pub fn pat_to_string(pat: &ast::Pat) -> String { + State::new().pat_to_string(pat) +} + +pub fn expr_to_string(e: &ast::Expr) -> String { + State::new().expr_to_string(e) +} + +pub fn tt_to_string(tt: &TokenTree) -> String { + State::new().tt_to_string(tt) +} + +pub fn tts_to_string(tokens: &TokenStream) -> String { + State::new().tts_to_string(tokens) +} + +pub fn stmt_to_string(stmt: &ast::Stmt) -> String { + State::new().stmt_to_string(stmt) +} + +pub fn item_to_string(i: &ast::Item) -> String { + State::new().item_to_string(i) +} + +pub fn generic_params_to_string(generic_params: &[ast::GenericParam]) -> String { + State::new().generic_params_to_string(generic_params) +} + +pub fn path_to_string(p: &ast::Path) -> String { + State::new().path_to_string(p) +} + +pub fn path_segment_to_string(p: &ast::PathSegment) -> String { + State::new().path_segment_to_string(p) +} + +pub fn vis_to_string(v: &ast::Visibility) -> String { + State::new().vis_to_string(v) +} + +pub fn block_to_string(blk: &ast::Block) -> String { + State::new().block_to_string(blk) +} + +pub fn meta_list_item_to_string(li: &ast::NestedMetaItem) -> String { + State::new().meta_list_item_to_string(li) +} + +pub fn attr_item_to_string(ai: &ast::AttrItem) -> String { + State::new().attr_item_to_string(ai) +} + +pub fn attribute_to_string(attr: &ast::Attribute) -> String { + State::new().attribute_to_string(attr) +} + +pub fn param_to_string(arg: &ast::Param) -> String { + State::new().param_to_string(arg) +} + +pub fn to_string(f: impl FnOnce(&mut State<'_>)) -> String { + State::new().to_string(f) +} diff --git a/compiler/rustc_ast_pretty/src/pprust.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index d16b541c699..af8f8132780 100644 --- a/compiler/rustc_ast_pretty/src/pprust.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -20,9 +20,6 @@ use rustc_span::{BytePos, FileName, Span}; use std::borrow::Cow; -#[cfg(test)] -mod tests; - pub enum MacHeader<'a> { Path(&'a ast::Path), Keyword(&'static str), @@ -91,6 +88,13 @@ pub struct State<'a> { comments: Option<Comments<'a>>, ann: &'a (dyn PpAnn + 'a), is_expanded: bool, + // If `true`, additional parenthesis (separate from `ExprKind::Paren`) + // are inserted to ensure that proper precedence is preserved + // in the pretty-printed output. + // + // This is usually `true`, except when performing the pretty-print/reparse + // check in `nt_to_tokenstream` + insert_extra_parens: bool, } crate const INDENT_UNIT: usize = 4; @@ -112,6 +116,7 @@ pub fn print_crate<'a>( comments: Some(Comments::new(sm, filename, input)), ann, is_expanded, + insert_extra_parens: true, }; if is_expanded && has_injected_crate { @@ -142,13 +147,6 @@ pub fn print_crate<'a>( s.s.eof() } -pub fn to_string(f: impl FnOnce(&mut State<'_>)) -> String { - let mut printer = - State { s: pp::mk_printer(), comments: None, ann: &NoAnn, is_expanded: false }; - f(&mut printer); - printer.s.eof() -} - // This makes printed token streams look slightly nicer, // and also addresses some specific regressions described in #63896 and #73345. fn tt_prepend_space(tt: &TokenTree, prev: &TokenTree) -> bool { @@ -231,173 +229,8 @@ pub fn literal_to_string(lit: token::Lit) -> String { out } -/// Print the token kind precisely, without converting `$crate` into its respective crate name. -pub fn token_kind_to_string(tok: &TokenKind) -> String { - token_kind_to_string_ext(tok, None) -} - -fn token_kind_to_string_ext(tok: &TokenKind, convert_dollar_crate: Option<Span>) -> String { - match *tok { - token::Eq => "=".to_string(), - token::Lt => "<".to_string(), - token::Le => "<=".to_string(), - token::EqEq => "==".to_string(), - token::Ne => "!=".to_string(), - token::Ge => ">=".to_string(), - token::Gt => ">".to_string(), - token::Not => "!".to_string(), - token::Tilde => "~".to_string(), - token::OrOr => "||".to_string(), - token::AndAnd => "&&".to_string(), - token::BinOp(op) => binop_to_string(op).to_string(), - token::BinOpEq(op) => format!("{}=", binop_to_string(op)), - - /* Structural symbols */ - token::At => "@".to_string(), - token::Dot => ".".to_string(), - token::DotDot => "..".to_string(), - token::DotDotDot => "...".to_string(), - token::DotDotEq => "..=".to_string(), - token::Comma => ",".to_string(), - token::Semi => ";".to_string(), - token::Colon => ":".to_string(), - token::ModSep => "::".to_string(), - token::RArrow => "->".to_string(), - token::LArrow => "<-".to_string(), - token::FatArrow => "=>".to_string(), - token::OpenDelim(token::Paren) => "(".to_string(), - token::CloseDelim(token::Paren) => ")".to_string(), - token::OpenDelim(token::Bracket) => "[".to_string(), - token::CloseDelim(token::Bracket) => "]".to_string(), - token::OpenDelim(token::Brace) => "{".to_string(), - token::CloseDelim(token::Brace) => "}".to_string(), - token::OpenDelim(token::NoDelim) | token::CloseDelim(token::NoDelim) => "".to_string(), - token::Pound => "#".to_string(), - token::Dollar => "$".to_string(), - token::Question => "?".to_string(), - token::SingleQuote => "'".to_string(), - - /* Literals */ - token::Literal(lit) => literal_to_string(lit), - - /* Name components */ - token::Ident(s, is_raw) => IdentPrinter::new(s, is_raw, convert_dollar_crate).to_string(), - token::Lifetime(s) => s.to_string(), - - /* Other */ - token::DocComment(comment_kind, attr_style, data) => { - doc_comment_to_string(comment_kind, attr_style, data) - } - token::Eof => "<eof>".to_string(), - - token::Interpolated(ref nt) => nonterminal_to_string(nt), - } -} - -/// Print the token precisely, without converting `$crate` into its respective crate name. -pub fn token_to_string(token: &Token) -> String { - token_to_string_ext(token, false) -} - -fn token_to_string_ext(token: &Token, convert_dollar_crate: bool) -> String { - let convert_dollar_crate = convert_dollar_crate.then_some(token.span); - token_kind_to_string_ext(&token.kind, convert_dollar_crate) -} - -pub fn nonterminal_to_string(nt: &Nonterminal) -> String { - match *nt { - token::NtExpr(ref e) => expr_to_string(e), - token::NtMeta(ref e) => attr_item_to_string(e), - token::NtTy(ref e) => ty_to_string(e), - token::NtPath(ref e) => path_to_string(e), - token::NtItem(ref e) => item_to_string(e), - token::NtBlock(ref e) => block_to_string(e), - token::NtStmt(ref e) => stmt_to_string(e), - token::NtPat(ref e) => pat_to_string(e), - token::NtIdent(e, is_raw) => IdentPrinter::for_ast_ident(e, is_raw).to_string(), - token::NtLifetime(e) => e.to_string(), - token::NtLiteral(ref e) => expr_to_string(e), - token::NtTT(ref tree) => tt_to_string(tree), - token::NtVis(ref e) => vis_to_string(e), - } -} - -pub fn ty_to_string(ty: &ast::Ty) -> String { - to_string(|s| s.print_type(ty)) -} - -pub fn bounds_to_string(bounds: &[ast::GenericBound]) -> String { - to_string(|s| s.print_type_bounds("", bounds)) -} - -pub fn pat_to_string(pat: &ast::Pat) -> String { - to_string(|s| s.print_pat(pat)) -} - -pub fn expr_to_string(e: &ast::Expr) -> String { - to_string(|s| s.print_expr(e)) -} - -pub fn tt_to_string(tt: &TokenTree) -> String { - to_string(|s| s.print_tt(tt, false)) -} - -pub fn tts_to_string(tokens: &TokenStream) -> String { - to_string(|s| s.print_tts(tokens, false)) -} - -pub fn stmt_to_string(stmt: &ast::Stmt) -> String { - to_string(|s| s.print_stmt(stmt)) -} - -pub fn item_to_string(i: &ast::Item) -> String { - to_string(|s| s.print_item(i)) -} - -pub fn generic_params_to_string(generic_params: &[ast::GenericParam]) -> String { - to_string(|s| s.print_generic_params(generic_params)) -} - -pub fn path_to_string(p: &ast::Path) -> String { - to_string(|s| s.print_path(p, false, 0)) -} - -pub fn path_segment_to_string(p: &ast::PathSegment) -> String { - to_string(|s| s.print_path_segment(p, false)) -} - -pub fn vis_to_string(v: &ast::Visibility) -> String { - to_string(|s| s.print_visibility(v)) -} - -fn block_to_string(blk: &ast::Block) -> String { - to_string(|s| { - // Containing cbox, will be closed by `print_block` at `}`. - s.cbox(INDENT_UNIT); - // Head-ibox, will be closed by `print_block` after `{`. - s.ibox(0); - s.print_block(blk) - }) -} - -pub fn meta_list_item_to_string(li: &ast::NestedMetaItem) -> String { - to_string(|s| s.print_meta_list_item(li)) -} - -fn attr_item_to_string(ai: &ast::AttrItem) -> String { - to_string(|s| s.print_attr_item(ai, ai.path.span)) -} - -pub fn attribute_to_string(attr: &ast::Attribute) -> String { - to_string(|s| s.print_attribute(attr)) -} - -pub fn param_to_string(arg: &ast::Param) -> String { - to_string(|s| s.print_param(arg, false)) -} - fn visibility_qualified(vis: &ast::Visibility, s: &str) -> String { - format!("{}{}", to_string(|s| s.print_visibility(vis)), s) + format!("{}{}", State::new().to_string(|s| s.print_visibility(vis)), s) } impl std::ops::Deref for State<'_> { @@ -414,6 +247,7 @@ impl std::ops::DerefMut for State<'_> { } pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::DerefMut { + fn insert_extra_parens(&self) -> bool; fn comments(&mut self) -> &mut Option<Comments<'a>>; fn print_ident(&mut self, ident: Ident); fn print_generic_args(&mut self, args: &ast::GenericArgs, colons_before_params: bool); @@ -679,7 +513,8 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere fn print_tt(&mut self, tt: &TokenTree, convert_dollar_crate: bool) { match tt { TokenTree::Token(token) => { - self.word(token_to_string_ext(&token, convert_dollar_crate)); + let token_str = self.token_to_string_ext(&token, convert_dollar_crate); + self.word(token_str); if let token::DocComment(..) = token.kind { self.hardbreak() } @@ -745,14 +580,20 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere self.space(); } } - _ => self.word(token_kind_to_string(&token::OpenDelim(delim))), + _ => { + let token_str = self.token_kind_to_string(&token::OpenDelim(delim)); + self.word(token_str) + } } self.ibox(0); self.print_tts(tts, convert_dollar_crate); self.end(); match delim { DelimToken::Brace => self.bclose(span), - _ => self.word(token_kind_to_string(&token::CloseDelim(delim))), + _ => { + let token_str = self.token_kind_to_string(&token::CloseDelim(delim)); + self.word(token_str) + } } } @@ -818,9 +659,190 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere } } } + + fn nonterminal_to_string(&self, nt: &Nonterminal) -> String { + match *nt { + token::NtExpr(ref e) => self.expr_to_string(e), + token::NtMeta(ref e) => self.attr_item_to_string(e), + token::NtTy(ref e) => self.ty_to_string(e), + token::NtPath(ref e) => self.path_to_string(e), + token::NtItem(ref e) => self.item_to_string(e), + token::NtBlock(ref e) => self.block_to_string(e), + token::NtStmt(ref e) => self.stmt_to_string(e), + token::NtPat(ref e) => self.pat_to_string(e), + token::NtIdent(e, is_raw) => IdentPrinter::for_ast_ident(e, is_raw).to_string(), + token::NtLifetime(e) => e.to_string(), + token::NtLiteral(ref e) => self.expr_to_string(e), + token::NtTT(ref tree) => self.tt_to_string(tree), + token::NtVis(ref e) => self.vis_to_string(e), + } + } + + /// Print the token kind precisely, without converting `$crate` into its respective crate name. + fn token_kind_to_string(&self, tok: &TokenKind) -> String { + self.token_kind_to_string_ext(tok, None) + } + + fn token_kind_to_string_ext( + &self, + tok: &TokenKind, + convert_dollar_crate: Option<Span>, + ) -> String { + match *tok { + token::Eq => "=".to_string(), + token::Lt => "<".to_string(), + token::Le => "<=".to_string(), + token::EqEq => "==".to_string(), + token::Ne => "!=".to_string(), + token::Ge => ">=".to_string(), + token::Gt => ">".to_string(), + token::Not => "!".to_string(), + token::Tilde => "~".to_string(), + token::OrOr => "||".to_string(), + token::AndAnd => "&&".to_string(), + token::BinOp(op) => binop_to_string(op).to_string(), + token::BinOpEq(op) => format!("{}=", binop_to_string(op)), + + /* Structural symbols */ + token::At => "@".to_string(), + token::Dot => ".".to_string(), + token::DotDot => "..".to_string(), + token::DotDotDot => "...".to_string(), + token::DotDotEq => "..=".to_string(), + token::Comma => ",".to_string(), + token::Semi => ";".to_string(), + token::Colon => ":".to_string(), + token::ModSep => "::".to_string(), + token::RArrow => "->".to_string(), + token::LArrow => "<-".to_string(), + token::FatArrow => "=>".to_string(), + token::OpenDelim(token::Paren) => "(".to_string(), + token::CloseDelim(token::Paren) => ")".to_string(), + token::OpenDelim(token::Bracket) => "[".to_string(), + token::CloseDelim(token::Bracket) => "]".to_string(), + token::OpenDelim(token::Brace) => "{".to_string(), + token::CloseDelim(token::Brace) => "}".to_string(), + token::OpenDelim(token::NoDelim) | token::CloseDelim(token::NoDelim) => "".to_string(), + token::Pound => "#".to_string(), + token::Dollar => "$".to_string(), + token::Question => "?".to_string(), + token::SingleQuote => "'".to_string(), + + /* Literals */ + token::Literal(lit) => literal_to_string(lit), + + /* Name components */ + token::Ident(s, is_raw) => { + IdentPrinter::new(s, is_raw, convert_dollar_crate).to_string() + } + token::Lifetime(s) => s.to_string(), + + /* Other */ + token::DocComment(comment_kind, attr_style, data) => { + doc_comment_to_string(comment_kind, attr_style, data) + } + token::Eof => "<eof>".to_string(), + + token::Interpolated(ref nt) => self.nonterminal_to_string(nt), + } + } + + /// Print the token precisely, without converting `$crate` into its respective crate name. + fn token_to_string(&self, token: &Token) -> String { + self.token_to_string_ext(token, false) + } + + fn token_to_string_ext(&self, token: &Token, convert_dollar_crate: bool) -> String { + let convert_dollar_crate = convert_dollar_crate.then_some(token.span); + self.token_kind_to_string_ext(&token.kind, convert_dollar_crate) + } + + fn ty_to_string(&self, ty: &ast::Ty) -> String { + self.to_string(|s| s.print_type(ty)) + } + + fn bounds_to_string(&self, bounds: &[ast::GenericBound]) -> String { + self.to_string(|s| s.print_type_bounds("", bounds)) + } + + fn pat_to_string(&self, pat: &ast::Pat) -> String { + self.to_string(|s| s.print_pat(pat)) + } + + fn expr_to_string(&self, e: &ast::Expr) -> String { + self.to_string(|s| s.print_expr(e)) + } + + fn tt_to_string(&self, tt: &TokenTree) -> String { + self.to_string(|s| s.print_tt(tt, false)) + } + + fn tts_to_string(&self, tokens: &TokenStream) -> String { + self.to_string(|s| s.print_tts(tokens, false)) + } + + fn stmt_to_string(&self, stmt: &ast::Stmt) -> String { + self.to_string(|s| s.print_stmt(stmt)) + } + + fn item_to_string(&self, i: &ast::Item) -> String { + self.to_string(|s| s.print_item(i)) + } + + fn generic_params_to_string(&self, generic_params: &[ast::GenericParam]) -> String { + self.to_string(|s| s.print_generic_params(generic_params)) + } + + fn path_to_string(&self, p: &ast::Path) -> String { + self.to_string(|s| s.print_path(p, false, 0)) + } + + fn path_segment_to_string(&self, p: &ast::PathSegment) -> String { + self.to_string(|s| s.print_path_segment(p, false)) + } + + fn vis_to_string(&self, v: &ast::Visibility) -> String { + self.to_string(|s| s.print_visibility(v)) + } + + fn block_to_string(&self, blk: &ast::Block) -> String { + self.to_string(|s| { + // Containing cbox, will be closed by `print_block` at `}`. + s.cbox(INDENT_UNIT); + // Head-ibox, will be closed by `print_block` after `{`. + s.ibox(0); + s.print_block(blk) + }) + } + + fn meta_list_item_to_string(&self, li: &ast::NestedMetaItem) -> String { + self.to_string(|s| s.print_meta_list_item(li)) + } + + fn attr_item_to_string(&self, ai: &ast::AttrItem) -> String { + self.to_string(|s| s.print_attr_item(ai, ai.path.span)) + } + + fn attribute_to_string(&self, attr: &ast::Attribute) -> String { + self.to_string(|s| s.print_attribute(attr)) + } + + fn param_to_string(&self, arg: &ast::Param) -> String { + self.to_string(|s| s.print_param(arg, false)) + } + + fn to_string(&self, f: impl FnOnce(&mut State<'_>)) -> String { + let mut printer = State::new(); + printer.insert_extra_parens = self.insert_extra_parens(); + f(&mut printer); + printer.s.eof() + } } impl<'a> PrintState<'a> for State<'a> { + fn insert_extra_parens(&self) -> bool { + self.insert_extra_parens + } fn comments(&mut self) -> &mut Option<Comments<'a>> { &mut self.comments } @@ -856,6 +878,20 @@ impl<'a> PrintState<'a> for State<'a> { } impl<'a> State<'a> { + pub fn new() -> State<'a> { + State { + s: pp::mk_printer(), + comments: None, + ann: &NoAnn, + is_expanded: false, + insert_extra_parens: true, + } + } + + pub(super) fn without_insert_extra_parens() -> State<'a> { + State { insert_extra_parens: false, ..State::new() } + } + // Synthesizes a comment that was not textually present in the original source // file. pub fn synth_comment(&mut self, text: String) { @@ -1139,7 +1175,7 @@ impl<'a> State<'a> { self.print_fn_full(sig, item.ident, gen, &item.vis, def, body, &item.attrs); } ast::ItemKind::Mod(ref _mod) => { - self.head(to_string(|s| { + self.head(self.to_string(|s| { s.print_visibility(&item.vis); s.print_unsafety(_mod.unsafety); s.word("mod"); @@ -1158,7 +1194,7 @@ impl<'a> State<'a> { } } ast::ItemKind::ForeignMod(ref nmod) => { - self.head(to_string(|s| { + self.head(self.to_string(|s| { s.print_unsafety(nmod.unsafety); s.word("extern"); })); @@ -1366,7 +1402,7 @@ impl<'a> State<'a> { ast::CrateSugar::JustCrate => self.word_nbsp("crate"), }, ast::VisibilityKind::Restricted { ref path, .. } => { - let path = to_string(|s| s.print_path(path, false, 0)); + let path = self.to_string(|s| s.print_path(path, false, 0)); if path == "self" || path == "super" { self.word_nbsp(format!("pub({})", path)) } else { @@ -1658,7 +1694,8 @@ impl<'a> State<'a> { } /// Prints `expr` or `(expr)` when `needs_par` holds. - fn print_expr_cond_paren(&mut self, expr: &ast::Expr, needs_par: bool) { + fn print_expr_cond_paren(&mut self, expr: &ast::Expr, mut needs_par: bool) { + needs_par &= self.insert_extra_parens; if needs_par { self.popen(); } @@ -1677,6 +1714,14 @@ impl<'a> State<'a> { self.end(); } + fn print_expr_anon_const(&mut self, expr: &ast::AnonConst, attrs: &[ast::Attribute]) { + self.ibox(INDENT_UNIT); + self.s.word("const"); + self.print_inner_attributes_inline(attrs); + self.print_expr(&expr.value); + self.end(); + } + fn print_expr_repeat( &mut self, element: &ast::Expr, @@ -1853,6 +1898,9 @@ impl<'a> State<'a> { ast::ExprKind::Array(ref exprs) => { self.print_expr_vec(&exprs[..], attrs); } + ast::ExprKind::ConstBlock(ref anon_const) => { + self.print_expr_anon_const(anon_const, attrs); + } ast::ExprKind::Repeat(ref element, ref count) => { self.print_expr_repeat(element, count, attrs); } diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs index 325af56f3cd..9c309345000 100644 --- a/compiler/rustc_attr/src/builtin.rs +++ b/compiler/rustc_attr/src/builtin.rs @@ -154,7 +154,7 @@ pub struct ConstStability { } /// The available stability levels. -#[derive(Encodable, Decodable, PartialEq, PartialOrd, Copy, Clone, Debug, Eq, Hash)] +#[derive(Encodable, Decodable, PartialEq, Copy, Clone, Debug, Eq, Hash)] #[derive(HashStable_Generic)] pub enum StabilityLevel { // Reason for the current stability level and the relevant rust-lang issue diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs index f4924997d1a..2e52d2a3923 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs @@ -1137,12 +1137,9 @@ impl<'a> MethodDef<'a> { /// for each of the self-args, carried in precomputed variables. /// ```{.text} - /// let __self0_vi = unsafe { - /// std::intrinsics::discriminant_value(&self) }; - /// let __self1_vi = unsafe { - /// std::intrinsics::discriminant_value(&arg1) }; - /// let __self2_vi = unsafe { - /// std::intrinsics::discriminant_value(&arg2) }; + /// let __self0_vi = std::intrinsics::discriminant_value(&self); + /// let __self1_vi = std::intrinsics::discriminant_value(&arg1); + /// let __self2_vi = std::intrinsics::discriminant_value(&arg2); /// /// if __self0_vi == __self1_vi && __self0_vi == __self2_vi && ... { /// match (...) { @@ -1325,7 +1322,7 @@ impl<'a> MethodDef<'a> { // Since we know that all the arguments will match if we reach // the match expression we add the unreachable intrinsics as the // result of the catch all which should help llvm in optimizing it - Some(deriving::call_intrinsic(cx, sp, sym::unreachable, vec![])) + Some(deriving::call_unreachable(cx, sp)) } _ => None, }; @@ -1356,12 +1353,9 @@ impl<'a> MethodDef<'a> { // with three Self args, builds three statements: // // ``` - // let __self0_vi = unsafe { - // std::intrinsics::discriminant_value(&self) }; - // let __self1_vi = unsafe { - // std::intrinsics::discriminant_value(&arg1) }; - // let __self2_vi = unsafe { - // std::intrinsics::discriminant_value(&arg2) }; + // let __self0_vi = std::intrinsics::discriminant_value(&self); + // let __self1_vi = std::intrinsics::discriminant_value(&arg1); + // let __self2_vi = std::intrinsics::discriminant_value(&arg2); // ``` let mut index_let_stmts: Vec<ast::Stmt> = Vec::with_capacity(vi_idents.len() + 1); @@ -1474,7 +1468,7 @@ impl<'a> MethodDef<'a> { // derive Debug on such a type could here generate code // that needs the feature gate enabled.) - deriving::call_intrinsic(cx, sp, sym::unreachable, vec![]) + deriving::call_unreachable(cx, sp) } else { // Final wrinkle: the self_args are expressions that deref // down to desired places, but we cannot actually deref diff --git a/compiler/rustc_builtin_macros/src/deriving/mod.rs b/compiler/rustc_builtin_macros/src/deriving/mod.rs index 9c8e0fc2f01..bf950934928 100644 --- a/compiler/rustc_builtin_macros/src/deriving/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/mod.rs @@ -68,7 +68,14 @@ fn call_intrinsic( ) -> P<ast::Expr> { let span = cx.with_def_site_ctxt(span); let path = cx.std_path(&[sym::intrinsics, intrinsic]); - let call = cx.expr_call_global(span, path, args); + cx.expr_call_global(span, path, args) +} + +/// Constructs an expression that calls the `unreachable` intrinsic. +fn call_unreachable(cx: &ExtCtxt<'_>, span: Span) -> P<ast::Expr> { + let span = cx.with_def_site_ctxt(span); + let path = cx.std_path(&[sym::intrinsics, sym::unreachable]); + let call = cx.expr_call_global(span, path, vec![]); cx.expr_block(P(ast::Block { stmts: vec![cx.stmt_expr(call)], diff --git a/compiler/rustc_builtin_macros/src/format_foreign.rs b/compiler/rustc_builtin_macros/src/format_foreign.rs index ff81b5eca13..b69b00d65f2 100644 --- a/compiler/rustc_builtin_macros/src/format_foreign.rs +++ b/compiler/rustc_builtin_macros/src/format_foreign.rs @@ -385,7 +385,7 @@ pub mod printf { if let Start = state { match c { '1'..='9' => { - let end = at_next_cp_while(next, is_digit); + let end = at_next_cp_while(next, char::is_ascii_digit); match end.next_cp() { // Yes, this *is* the parameter. Some(('$', end2)) => { @@ -427,7 +427,7 @@ pub mod printf { move_to!(next); } '1'..='9' => { - let end = at_next_cp_while(next, is_digit); + let end = at_next_cp_while(next, char::is_ascii_digit); state = Prec; width = Some(Num::from_str(at.slice_between(end).unwrap(), None)); move_to!(end); @@ -441,7 +441,7 @@ pub mod printf { } if let WidthArg = state { - let end = at_next_cp_while(at, is_digit); + let end = at_next_cp_while(at, char::is_ascii_digit); match end.next_cp() { Some(('$', end2)) => { state = Prec; @@ -473,7 +473,7 @@ pub mod printf { if let PrecInner = state { match c { '*' => { - let end = at_next_cp_while(next, is_digit); + let end = at_next_cp_while(next, char::is_ascii_digit); match end.next_cp() { Some(('$', end2)) => { state = Length; @@ -488,7 +488,7 @@ pub mod printf { } } '0'..='9' => { - let end = at_next_cp_while(next, is_digit); + let end = at_next_cp_while(next, char::is_ascii_digit); state = Length; precision = Some(Num::from_str(at.slice_between(end).unwrap(), None)); move_to!(end); @@ -563,12 +563,12 @@ pub mod printf { fn at_next_cp_while<F>(mut cur: Cur<'_>, mut pred: F) -> Cur<'_> where - F: FnMut(char) -> bool, + F: FnMut(&char) -> bool, { loop { match cur.next_cp() { Some((c, next)) => { - if pred(c) { + if pred(&c) { cur = next; } else { return cur; @@ -579,14 +579,7 @@ pub mod printf { } } - fn is_digit(c: char) -> bool { - match c { - '0'..='9' => true, - _ => false, - } - } - - fn is_flag(c: char) -> bool { + fn is_flag(c: &char) -> bool { match c { '0' | '-' | '+' | ' ' | '#' | '\'' => true, _ => false, @@ -723,17 +716,11 @@ pub mod shell { } fn is_ident_head(c: char) -> bool { - match c { - 'a'..='z' | 'A'..='Z' | '_' => true, - _ => false, - } + c.is_ascii_alphabetic() || c == '_' } fn is_ident_tail(c: char) -> bool { - match c { - '0'..='9' => true, - c => is_ident_head(c), - } + c.is_ascii_alphanumeric() || c == '_' } #[cfg(test)] diff --git a/compiler/rustc_builtin_macros/src/test_harness.rs b/compiler/rustc_builtin_macros/src/test_harness.rs index 0a60ca8faaa..da74f0aeaa1 100644 --- a/compiler/rustc_builtin_macros/src/test_harness.rs +++ b/compiler/rustc_builtin_macros/src/test_harness.rs @@ -37,7 +37,7 @@ struct TestCtxt<'a> { pub fn inject(sess: &Session, resolver: &mut dyn ResolverExpand, krate: &mut ast::Crate) { let span_diagnostic = sess.diagnostic(); let panic_strategy = sess.panic_strategy(); - let platform_panic_strategy = sess.target.target.options.panic_strategy; + let platform_panic_strategy = sess.target.options.panic_strategy; // Check for #![reexport_test_harness_main = "some_name"] which gives the // main test function the name `some_name` without hygiene. This needs to be diff --git a/compiler/rustc_codegen_llvm/src/allocator.rs b/compiler/rustc_codegen_llvm/src/allocator.rs index e028b2c2dc7..d02bc41f4af 100644 --- a/compiler/rustc_codegen_llvm/src/allocator.rs +++ b/compiler/rustc_codegen_llvm/src/allocator.rs @@ -16,10 +16,10 @@ pub(crate) unsafe fn codegen( ) { let llcx = &*mods.llcx; let llmod = mods.llmod(); - let usize = match &tcx.sess.target.target.target_pointer_width[..] { - "16" => llvm::LLVMInt16TypeInContext(llcx), - "32" => llvm::LLVMInt32TypeInContext(llcx), - "64" => llvm::LLVMInt64TypeInContext(llcx), + let usize = match tcx.sess.target.pointer_width { + 16 => llvm::LLVMInt16TypeInContext(llcx), + 32 => llvm::LLVMInt32TypeInContext(llcx), + 64 => llvm::LLVMInt64TypeInContext(llcx), tws => bug!("Unsupported target word size for int: {}", tws), }; let i8 = llvm::LLVMInt8TypeInContext(llcx); @@ -57,7 +57,7 @@ pub(crate) unsafe fn codegen( let name = format!("__rust_{}", method.name); let llfn = llvm::LLVMRustGetOrInsertFunction(llmod, name.as_ptr().cast(), name.len(), ty); - if tcx.sess.target.target.options.default_hidden_visibility { + if tcx.sess.target.options.default_hidden_visibility { llvm::LLVMRustSetVisibility(llfn, llvm::Visibility::Hidden); } if tcx.sess.must_emit_unwind_tables() { @@ -98,7 +98,7 @@ pub(crate) unsafe fn codegen( // -> ! DIFlagNoReturn llvm::Attribute::NoReturn.apply_llfn(llvm::AttributePlace::Function, llfn); - if tcx.sess.target.target.options.default_hidden_visibility { + if tcx.sess.target.options.default_hidden_visibility { llvm::LLVMRustSetVisibility(llfn, llvm::Visibility::Hidden); } if tcx.sess.must_emit_unwind_tables() { diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs index 1eb852e6b01..b096664bc74 100644 --- a/compiler/rustc_codegen_llvm/src/asm.rs +++ b/compiler/rustc_codegen_llvm/src/asm.rs @@ -60,7 +60,7 @@ impl AsmBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> { // Default per-arch clobbers // Basically what clang does - let arch_clobbers = match &self.sess().target.target.arch[..] { + let arch_clobbers = match &self.sess().target.arch[..] { "x86" | "x86_64" => vec!["~{dirflag}", "~{fpsr}", "~{flags}"], "mips" | "mips64" => vec!["~{$1}"], _ => Vec::new(), diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs index f02c30c3ee3..2075c2e1911 100644 --- a/compiler/rustc_codegen_llvm/src/attributes.rs +++ b/compiler/rustc_codegen_llvm/src/attributes.rs @@ -6,7 +6,7 @@ use rustc_codegen_ssa::traits::*; use rustc_data_structures::const_cstr; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::small_c_str::SmallCStr; -use rustc_hir::def_id::{DefId, LOCAL_CRATE}; +use rustc_hir::def_id::DefId; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::ty::layout::HasTyCtxt; use rustc_middle::ty::query::Providers; @@ -31,7 +31,7 @@ fn inline(cx: &CodegenCx<'ll, '_>, val: &'ll Value, inline: InlineAttr) { Hint => Attribute::InlineHint.apply_llfn(Function, val), Always => Attribute::AlwaysInline.apply_llfn(Function, val), Never => { - if cx.tcx().sess.target.target.arch != "amdgpu" { + if cx.tcx().sess.target.arch != "amdgpu" { Attribute::NoInline.apply_llfn(Function, val); } } @@ -91,8 +91,7 @@ fn set_instrument_function(cx: &CodegenCx<'ll, '_>, llfn: &'ll Value) { // The function name varies on platforms. // See test/CodeGen/mcount.c in clang. let mcount_name = - CString::new(cx.sess().target.target.options.target_mcount.as_str().as_bytes()) - .unwrap(); + CString::new(cx.sess().target.options.target_mcount.as_str().as_bytes()).unwrap(); llvm::AddFunctionAttrStringValue( llfn, @@ -106,7 +105,7 @@ fn set_instrument_function(cx: &CodegenCx<'ll, '_>, llfn: &'ll Value) { fn set_probestack(cx: &CodegenCx<'ll, '_>, llfn: &'ll Value) { // Only use stack probes if the target specification indicates that we // should be using stack probes - if !cx.sess().target.target.options.stack_probes { + if !cx.sess().target.options.stack_probes { return; } @@ -175,7 +174,6 @@ pub fn llvm_target_features(sess: &Session) -> impl Iterator<Item = &str> { .split(',') .filter(|f| !RUSTC_SPECIFIC_FEATURES.iter().any(|s| f.contains(s))); sess.target - .target .options .features .split(',') @@ -194,6 +192,18 @@ pub fn apply_target_cpu_attr(cx: &CodegenCx<'ll, '_>, llfn: &'ll Value) { ); } +pub fn apply_tune_cpu_attr(cx: &CodegenCx<'ll, '_>, llfn: &'ll Value) { + if let Some(tune) = llvm_util::tune_cpu(cx.tcx.sess) { + let tune_cpu = SmallCStr::new(tune); + llvm::AddFunctionAttrStringValue( + llfn, + llvm::AttributePlace::Function, + const_cstr!("tune-cpu"), + tune_cpu.as_c_str(), + ); + } +} + /// Sets the `NonLazyBind` LLVM attribute on a given function, /// assuming the codegen options allow skipping the PLT. pub fn non_lazy_bind(sess: &Session, llfn: &'ll Value) { @@ -303,6 +313,9 @@ pub fn from_fn_attrs(cx: &CodegenCx<'ll, 'tcx>, llfn: &'ll Value, instance: ty:: // Without this, ThinLTO won't inline Rust functions into Clang generated // functions (because Clang annotates functions this way too). apply_target_cpu_attr(cx, llfn); + // tune-cpu is only conveyed through the attribute for our purpose. + // The target doesn't care; the subtarget reads our attribute. + apply_tune_cpu_attr(cx, llfn); let features = llvm_target_features(cx.tcx.sess) .map(|s| s.to_string()) @@ -330,7 +343,7 @@ pub fn from_fn_attrs(cx: &CodegenCx<'ll, 'tcx>, llfn: &'ll Value, instance: ty:: // Note that currently the `wasm-import-module` doesn't do anything, but // eventually LLVM 7 should read this and ferry the appropriate import // module to the output file. - if cx.tcx.sess.target.target.arch == "wasm32" { + if cx.tcx.sess.target.arch == "wasm32" { if let Some(module) = wasm_import_module(cx.tcx, instance.def_id()) { llvm::AddFunctionAttrStringValue( llfn, @@ -352,23 +365,7 @@ pub fn from_fn_attrs(cx: &CodegenCx<'ll, 'tcx>, llfn: &'ll Value, instance: ty:: } } -pub fn provide(providers: &mut Providers) { - use rustc_codegen_ssa::target_features::{all_known_features, supported_target_features}; - providers.supported_target_features = |tcx, cnum| { - assert_eq!(cnum, LOCAL_CRATE); - if tcx.sess.opts.actually_rustdoc { - // rustdoc needs to be able to document functions that use all the features, so - // provide them all. - all_known_features().map(|(a, b)| (a.to_string(), b)).collect() - } else { - supported_target_features(tcx.sess).iter().map(|&(a, b)| (a.to_string(), b)).collect() - } - }; - - provide_extern(providers); -} - -pub fn provide_extern(providers: &mut Providers) { +pub fn provide_both(providers: &mut Providers) { providers.wasm_import_module_map = |tcx, cnum| { // Build up a map from DefId to a `NativeLib` structure, where // `NativeLib` internally contains information about diff --git a/compiler/rustc_codegen_llvm/src/back/archive.rs b/compiler/rustc_codegen_llvm/src/back/archive.rs index a115a1e9516..595655b2ca2 100644 --- a/compiler/rustc_codegen_llvm/src/back/archive.rs +++ b/compiler/rustc_codegen_llvm/src/back/archive.rs @@ -206,7 +206,7 @@ impl<'a> LlvmArchiveBuilder<'a> { } fn llvm_archive_kind(&self) -> Result<ArchiveKind, &str> { - let kind = &*self.config.sess.target.target.options.archive_format; + let kind = &*self.config.sess.target.options.archive_format; kind.parse().map_err(|_| kind) } diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs index 4b2d5907a02..ff312bade25 100644 --- a/compiler/rustc_codegen_llvm/src/back/lto.rs +++ b/compiler/rustc_codegen_llvm/src/back/lto.rs @@ -2,14 +2,14 @@ use crate::back::write::{ self, save_temp_bitcode, to_llvm_opt_settings, with_llvm_pmb, DiagnosticHandlers, }; use crate::llvm::archive_ro::ArchiveRO; -use crate::llvm::{self, False, True}; +use crate::llvm::{self, build_string, False, True}; use crate::{LlvmCodegenBackend, ModuleLlvm}; use rustc_codegen_ssa::back::lto::{LtoModuleCodegen, SerializedModule, ThinModule, ThinShared}; use rustc_codegen_ssa::back::symbol_export; use rustc_codegen_ssa::back::write::{CodegenContext, FatLTOInput, ModuleConfig}; use rustc_codegen_ssa::traits::*; use rustc_codegen_ssa::{looks_like_rust_object_file, ModuleCodegen, ModuleKind}; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::fx::FxHashMap; use rustc_errors::{FatalError, Handler}; use rustc_hir::def_id::LOCAL_CRATE; use rustc_middle::bug; @@ -22,16 +22,14 @@ use tracing::{debug, info}; use std::ffi::{CStr, CString}; use std::fs::File; use std::io; -use std::mem; use std::path::Path; use std::ptr; use std::slice; use std::sync::Arc; -/// We keep track of past LTO imports that were used to produce the current set -/// of compiled object files that we might choose to reuse during this -/// compilation session. -pub const THIN_LTO_IMPORTS_INCR_COMP_FILE_NAME: &str = "thin-lto-past-imports.bin"; +/// We keep track of the computed LTO cache keys from the previous +/// session to determine which CGUs we can reuse. +pub const THIN_LTO_KEYS_INCR_COMP_FILE_NAME: &str = "thin-lto-past-keys.bin"; pub fn crate_type_allows_lto(crate_type: CrateType) -> bool { match crate_type { @@ -485,31 +483,31 @@ fn thin_lto( ) .ok_or_else(|| write::llvm_err(&diag_handler, "failed to prepare thin LTO context"))?; - info!("thin LTO data created"); + let data = ThinData(data); - let (import_map_path, prev_import_map, curr_import_map) = - if let Some(ref incr_comp_session_dir) = cgcx.incr_comp_session_dir { - let path = incr_comp_session_dir.join(THIN_LTO_IMPORTS_INCR_COMP_FILE_NAME); - // If previous imports have been deleted, or we get an IO error - // reading the file storing them, then we'll just use `None` as the - // prev_import_map, which will force the code to be recompiled. - let prev = if path.exists() { - ThinLTOImportMaps::load_from_file(&path).ok() - } else { - None - }; - let curr = ThinLTOImportMaps::from_thin_lto_data(data); - (Some(path), prev, curr) - } else { - // If we don't compile incrementally, we don't need to load the - // import data from LLVM. - assert!(green_modules.is_empty()); - let curr = ThinLTOImportMaps::default(); - (None, None, curr) - }; - info!("thin LTO import map loaded"); + info!("thin LTO data created"); - let data = ThinData(data); + let (key_map_path, prev_key_map, curr_key_map) = if let Some(ref incr_comp_session_dir) = + cgcx.incr_comp_session_dir + { + let path = incr_comp_session_dir.join(THIN_LTO_KEYS_INCR_COMP_FILE_NAME); + // If the previous file was deleted, or we get an IO error + // reading the file, then we'll just use `None` as the + // prev_key_map, which will force the code to be recompiled. + let prev = + if path.exists() { ThinLTOKeysMap::load_from_file(&path).ok() } else { None }; + let curr = ThinLTOKeysMap::from_thin_lto_modules(&data, &thin_modules, &module_names); + (Some(path), prev, curr) + } else { + // If we don't compile incrementally, we don't need to load the + // import data from LLVM. + assert!(green_modules.is_empty()); + let curr = ThinLTOKeysMap::default(); + (None, None, curr) + }; + info!("thin LTO cache key map loaded"); + info!("prev_key_map: {:#?}", prev_key_map); + info!("curr_key_map: {:#?}", curr_key_map); // Throw our data in an `Arc` as we'll be sharing it across threads. We // also put all memory referenced by the C++ data (buffers, ids, etc) @@ -528,60 +526,14 @@ fn thin_lto( info!("checking which modules can be-reused and which have to be re-optimized."); for (module_index, module_name) in shared.module_names.iter().enumerate() { let module_name = module_name_to_str(module_name); - - // If (1.) the module hasn't changed, and (2.) none of the modules - // it imports from have changed, *and* (3.) the import and export - // sets themselves have not changed from the previous compile when - // it was last ThinLTO'ed, then we can re-use the post-ThinLTO - // version of the module. Otherwise, freshly perform LTO - // optimization. - // - // (Note that globally, the export set is just the inverse of the - // import set.) - // - // For further justification of why the above is necessary and sufficient, - // see the LLVM blog post on ThinLTO: - // - // http://blog.llvm.org/2016/06/thinlto-scalable-and-incremental-lto.html - // - // which states the following: - // - // ```quote - // any particular ThinLTO backend must be redone iff: - // - // 1. The corresponding (primary) module’s bitcode changed - // 2. The list of imports into or exports from the module changed - // 3. The bitcode for any module being imported from has changed - // 4. Any global analysis result affecting either the primary module - // or anything it imports has changed. - // ``` - // - // This strategy means we can always save the computed imports as - // canon: when we reuse the post-ThinLTO version, condition (3.) - // ensures that the current import set is the same as the previous - // one. (And of course, when we don't reuse the post-ThinLTO - // version, the current import set *is* the correct one, since we - // are doing the ThinLTO in this current compilation cycle.) - // - // For more discussion, see rust-lang/rust#59535 (where the import - // issue was discovered) and rust-lang/rust#69798 (where the - // analogous export issue was discovered). - if let (Some(prev_import_map), true) = - (prev_import_map.as_ref(), green_modules.contains_key(module_name)) + if let (Some(prev_key_map), true) = + (prev_key_map.as_ref(), green_modules.contains_key(module_name)) { assert!(cgcx.incr_comp_session_dir.is_some()); - let prev_imports = prev_import_map.imports_of(module_name); - let curr_imports = curr_import_map.imports_of(module_name); - let prev_exports = prev_import_map.exports_of(module_name); - let curr_exports = curr_import_map.exports_of(module_name); - let imports_all_green = curr_imports - .iter() - .all(|imported_module| green_modules.contains_key(imported_module)); - if imports_all_green - && equivalent_as_sets(prev_imports, curr_imports) - && equivalent_as_sets(prev_exports, curr_exports) - { + // If a module exists in both the current and the previous session, + // and has the same LTO cache key in both sessions, then we can re-use it + if prev_key_map.keys.get(module_name) == curr_key_map.keys.get(module_name) { let work_product = green_modules[module_name].clone(); copy_jobs.push(work_product); info!(" - {}: re-used", module_name); @@ -599,10 +551,10 @@ fn thin_lto( } // Save the current ThinLTO import information for the next compilation - // session, overwriting the previous serialized imports (if any). - if let Some(path) = import_map_path { - if let Err(err) = curr_import_map.save_to_file(&path) { - let msg = format!("Error while writing ThinLTO import data: {}", err); + // session, overwriting the previous serialized data (if any). + if let Some(path) = key_map_path { + if let Err(err) = curr_key_map.save_to_file(&path) { + let msg = format!("Error while writing ThinLTO key data: {}", err); return Err(write::llvm_err(&diag_handler, &msg)); } } @@ -611,24 +563,6 @@ fn thin_lto( } } -/// Given two slices, each with no repeat elements. returns true if and only if -/// the two slices have the same contents when considered as sets (i.e. when -/// element order is disregarded). -fn equivalent_as_sets(a: &[String], b: &[String]) -> bool { - // cheap path: unequal lengths means cannot possibly be set equivalent. - if a.len() != b.len() { - return false; - } - // fast path: before building new things, check if inputs are equivalent as is. - if a == b { - return true; - } - // slow path: general set comparison. - let a: FxHashSet<&str> = a.iter().map(|s| s.as_str()).collect(); - let b: FxHashSet<&str> = b.iter().map(|s| s.as_str()).collect(); - a == b -} - pub(crate) fn run_pass_manager( cgcx: &CodegenContext<LlvmCodegenBackend>, module: &ModuleCodegen<ModuleLlvm>, @@ -942,113 +876,56 @@ pub unsafe fn optimize_thin_module( Ok(module) } -/// Summarizes module import/export relationships used by LLVM's ThinLTO pass. -/// -/// Note that we tend to have two such instances of `ThinLTOImportMaps` in use: -/// one loaded from a file that represents the relationships used during the -/// compilation associated with the incremetnal build artifacts we are -/// attempting to reuse, and another constructed via `from_thin_lto_data`, which -/// captures the relationships of ThinLTO in the current compilation. +/// Maps LLVM module identifiers to their corresponding LLVM LTO cache keys #[derive(Debug, Default)] -pub struct ThinLTOImportMaps { - // key = llvm name of importing module, value = list of modules it imports from - imports: FxHashMap<String, Vec<String>>, - // key = llvm name of exporting module, value = list of modules it exports to - exports: FxHashMap<String, Vec<String>>, +pub struct ThinLTOKeysMap { + // key = llvm name of importing module, value = LLVM cache key + keys: FxHashMap<String, String>, } -impl ThinLTOImportMaps { - /// Returns modules imported by `llvm_module_name` during some ThinLTO pass. - fn imports_of(&self, llvm_module_name: &str) -> &[String] { - self.imports.get(llvm_module_name).map(|v| &v[..]).unwrap_or(&[]) - } - - /// Returns modules exported by `llvm_module_name` during some ThinLTO pass. - fn exports_of(&self, llvm_module_name: &str) -> &[String] { - self.exports.get(llvm_module_name).map(|v| &v[..]).unwrap_or(&[]) - } - +impl ThinLTOKeysMap { fn save_to_file(&self, path: &Path) -> io::Result<()> { use std::io::Write; let file = File::create(path)?; let mut writer = io::BufWriter::new(file); - for (importing_module_name, imported_modules) in &self.imports { - writeln!(writer, "{}", importing_module_name)?; - for imported_module in imported_modules { - writeln!(writer, " {}", imported_module)?; - } - writeln!(writer)?; + for (module, key) in &self.keys { + writeln!(writer, "{} {}", module, key)?; } Ok(()) } - fn load_from_file(path: &Path) -> io::Result<ThinLTOImportMaps> { + fn load_from_file(path: &Path) -> io::Result<Self> { use std::io::BufRead; - let mut imports = FxHashMap::default(); - let mut exports: FxHashMap<_, Vec<_>> = FxHashMap::default(); - let mut current_module: Option<String> = None; - let mut current_imports: Vec<String> = vec![]; + let mut keys = FxHashMap::default(); let file = File::open(path)?; for line in io::BufReader::new(file).lines() { let line = line?; - if line.is_empty() { - let importing_module = current_module.take().expect("Importing module not set"); - for imported in ¤t_imports { - exports.entry(imported.clone()).or_default().push(importing_module.clone()); - } - imports.insert(importing_module, mem::replace(&mut current_imports, vec![])); - } else if line.starts_with(' ') { - // Space marks an imported module - assert_ne!(current_module, None); - current_imports.push(line.trim().to_string()); - } else { - // Otherwise, beginning of a new module (must be start or follow empty line) - assert_eq!(current_module, None); - current_module = Some(line.trim().to_string()); - } + let mut split = line.split(" "); + let module = split.next().unwrap(); + let key = split.next().unwrap(); + assert_eq!(split.next(), None, "Expected two space-separated values, found {:?}", line); + keys.insert(module.to_string(), key.to_string()); } - Ok(ThinLTOImportMaps { imports, exports }) + Ok(Self { keys }) } - /// Loads the ThinLTO import map from ThinLTOData. - unsafe fn from_thin_lto_data(data: *const llvm::ThinLTOData) -> ThinLTOImportMaps { - unsafe extern "C" fn imported_module_callback( - payload: *mut libc::c_void, - importing_module_name: *const libc::c_char, - imported_module_name: *const libc::c_char, - ) { - let map = &mut *(payload as *mut ThinLTOImportMaps); - let importing_module_name = CStr::from_ptr(importing_module_name); - let importing_module_name = module_name_to_str(&importing_module_name); - let imported_module_name = CStr::from_ptr(imported_module_name); - let imported_module_name = module_name_to_str(&imported_module_name); - - if !map.imports.contains_key(importing_module_name) { - map.imports.insert(importing_module_name.to_owned(), vec![]); - } - - map.imports - .get_mut(importing_module_name) - .unwrap() - .push(imported_module_name.to_owned()); - - if !map.exports.contains_key(imported_module_name) { - map.exports.insert(imported_module_name.to_owned(), vec![]); - } - - map.exports - .get_mut(imported_module_name) - .unwrap() - .push(importing_module_name.to_owned()); - } - - let mut map = ThinLTOImportMaps::default(); - llvm::LLVMRustGetThinLTOModuleImports( - data, - imported_module_callback, - &mut map as *mut _ as *mut libc::c_void, - ); - map + fn from_thin_lto_modules( + data: &ThinData, + modules: &[llvm::ThinLTOModule], + names: &[CString], + ) -> Self { + let keys = modules + .iter() + .zip(names.iter()) + .map(|(module, name)| { + let key = build_string(|rust_str| unsafe { + llvm::LLVMRustComputeLTOCacheKey(rust_str, module.identifier, data.0); + }) + .expect("Invalid ThinLTO module key"); + (name.clone().into_string().unwrap(), key) + }) + .collect(); + Self { keys } } } diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index f35c1016f86..092d1cea295 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -128,40 +128,40 @@ pub fn target_machine_factory( let (opt_level, _) = to_llvm_opt_settings(optlvl); let use_softfp = sess.opts.cg.soft_float; - let ffunction_sections = sess.target.target.options.function_sections; + let ffunction_sections = sess.target.options.function_sections; let fdata_sections = ffunction_sections; let code_model = to_llvm_code_model(sess.code_model()); let features = attributes::llvm_target_features(sess).collect::<Vec<_>>(); - let mut singlethread = sess.target.target.options.singlethread; + let mut singlethread = sess.target.options.singlethread; // On the wasm target once the `atomics` feature is enabled that means that // we're no longer single-threaded, or otherwise we don't want LLVM to // lower atomic operations to single-threaded operations. if singlethread - && sess.target.target.llvm_target.contains("wasm32") + && sess.target.llvm_target.contains("wasm32") && sess.target_features.contains(&sym::atomics) { singlethread = false; } - let triple = SmallCStr::new(&sess.target.target.llvm_target); + let triple = SmallCStr::new(&sess.target.llvm_target); let cpu = SmallCStr::new(llvm_util::target_cpu(sess)); let features = features.join(","); let features = CString::new(features).unwrap(); - let abi = SmallCStr::new(&sess.target.target.options.llvm_abiname); - let trap_unreachable = sess.target.target.options.trap_unreachable; + let abi = SmallCStr::new(&sess.target.options.llvm_abiname); + let trap_unreachable = sess.target.options.trap_unreachable; let emit_stack_size_section = sess.opts.debugging_opts.emit_stack_sizes; let asm_comments = sess.asm_comments(); - let relax_elf_relocations = sess.target.target.options.relax_elf_relocations; + let relax_elf_relocations = sess.target.options.relax_elf_relocations; let use_init_array = !sess .opts .debugging_opts .use_ctors_section - .unwrap_or(sess.target.target.options.use_ctors_section); + .unwrap_or(sess.target.options.use_ctors_section); Arc::new(move || { let tm = unsafe { @@ -936,8 +936,8 @@ unsafe fn embed_bitcode( llvm::LLVMRustAppendModuleInlineAsm(llmod, asm.as_ptr().cast(), asm.len()); } else { let asm = " - .section .llvmbc,\"e\" - .section .llvmcmd,\"e\" + .section .llvmbc,\"a\" + .section .llvmcmd,\"a\" "; llvm::LLVMRustAppendModuleInlineAsm(llmod, asm.as_ptr().cast(), asm.len()); } diff --git a/compiler/rustc_codegen_llvm/src/base.rs b/compiler/rustc_codegen_llvm/src/base.rs index f35708b1d09..1090d4a25c7 100644 --- a/compiler/rustc_codegen_llvm/src/base.rs +++ b/compiler/rustc_codegen_llvm/src/base.rs @@ -60,7 +60,7 @@ pub fn write_compressed_metadata<'tcx>( unsafe { llvm::LLVMAddGlobal(metadata_llmod, common::val_ty(llconst), buf.as_ptr()) }; unsafe { llvm::LLVMSetInitializer(llglobal, llconst); - let section_name = metadata::metadata_section_name(&tcx.sess.target.target); + let section_name = metadata::metadata_section_name(&tcx.sess.target); let name = SmallCStr::new(section_name); llvm::LLVMSetSection(llglobal, name.as_ptr()); diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index f496f3283da..491191d058c 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -139,7 +139,7 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { unsafe { llvm::LLVMGetInsertBlock(self.llbuilder) } } - fn set_span(&self, _span: Span) {} + fn set_span(&mut self, _span: Span) {} fn position_at_end(&mut self, llbb: &'ll BasicBlock) { unsafe { @@ -308,8 +308,8 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { use rustc_middle::ty::{Int, Uint}; let new_kind = match ty.kind() { - Int(t @ Isize) => Int(t.normalize(self.tcx.sess.target.ptr_width)), - Uint(t @ Usize) => Uint(t.normalize(self.tcx.sess.target.ptr_width)), + Int(t @ Isize) => Int(t.normalize(self.tcx.sess.target.pointer_width)), + Uint(t @ Usize) => Uint(t.normalize(self.tcx.sess.target.pointer_width)), t @ (Uint(_) | Int(_)) => t.clone(), _ => panic!("tried to get overflow intrinsic for op applied to non-int type"), }; @@ -541,7 +541,7 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { } fn range_metadata(&mut self, load: &'ll Value, range: Range<u128>) { - if self.sess().target.target.arch == "amdgpu" { + if self.sess().target.arch == "amdgpu" { // amdgpu/LLVM does something weird and thinks a i64 value is // split into a v2i32, halving the bitwidth LLVM expects, // tripping an assertion. So, for now, just disable this @@ -671,7 +671,7 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { // WebAssembly has saturating floating point to integer casts if the // `nontrapping-fptoint` target feature is activated. We'll use those if // they are available. - if self.sess().target.target.arch == "wasm32" + if self.sess().target.arch == "wasm32" && self.sess().target_features.contains(&sym::nontrapping_dash_fptoint) { let src_ty = self.cx.val_ty(val); @@ -696,7 +696,7 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { // WebAssembly has saturating floating point to integer casts if the // `nontrapping-fptoint` target feature is activated. We'll use those if // they are available. - if self.sess().target.target.arch == "wasm32" + if self.sess().target.arch == "wasm32" && self.sess().target_features.contains(&sym::nontrapping_dash_fptoint) { let src_ty = self.cx.val_ty(val); @@ -1427,7 +1427,7 @@ impl Builder<'a, 'll, 'tcx> { } fn wasm_and_missing_nontrapping_fptoint(&self) -> bool { - self.sess().target.target.arch == "wasm32" + self.sess().target.arch == "wasm32" && !self.sess().target_features.contains(&sym::nontrapping_dash_fptoint) } } diff --git a/compiler/rustc_codegen_llvm/src/callee.rs b/compiler/rustc_codegen_llvm/src/callee.rs index 4afd906fce7..e2003472d12 100644 --- a/compiler/rustc_codegen_llvm/src/callee.rs +++ b/compiler/rustc_codegen_llvm/src/callee.rs @@ -176,7 +176,7 @@ pub fn get_fn(cx: &CodegenCx<'ll, 'tcx>, instance: Instance<'tcx>) -> &'ll Value // should use dllimport for functions. if cx.use_dll_storage_attrs && tcx.is_dllimport_foreign_item(instance_def_id) - && tcx.sess.target.target.target_env != "gnu" + && tcx.sess.target.target_env != "gnu" { unsafe { llvm::LLVMSetDLLStorageClass(llfn, llvm::DLLStorageClass::DllImport); diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs index 6d3582d3027..b57a23328b6 100644 --- a/compiler/rustc_codegen_llvm/src/consts.rs +++ b/compiler/rustc_codegen_llvm/src/consts.rs @@ -92,7 +92,7 @@ fn set_global_alignment(cx: &CodegenCx<'ll, '_>, gv: &'ll Value, mut align: Alig // The target may require greater alignment for globals than the type does. // Note: GCC and Clang also allow `__attribute__((aligned))` on variables, // which can force it to be smaller. Rust doesn't support this yet. - if let Some(min) = cx.sess().target.target.options.min_global_align { + if let Some(min) = cx.sess().target.options.min_global_align { match Align::from_bits(min) { Ok(min) => align = align.max(min), Err(err) => { @@ -283,7 +283,7 @@ impl CodegenCx<'ll, 'tcx> { // argument validation. debug_assert!( !(self.tcx.sess.opts.cg.linker_plugin_lto.enabled() - && self.tcx.sess.target.target.options.is_like_windows + && self.tcx.sess.target.options.is_like_windows && self.tcx.sess.opts.cg.prefer_dynamic) ); @@ -437,7 +437,7 @@ impl StaticMethods for CodegenCx<'ll, 'tcx> { // will use load-unaligned instructions instead, and thus avoiding the crash. // // We could remove this hack whenever we decide to drop macOS 10.10 support. - if self.tcx.sess.target.target.options.is_like_osx { + if self.tcx.sess.target.options.is_like_osx { // The `inspect` method is okay here because we checked relocations, and // because we are doing this access to inspect the final interpreter state // (not as part of the interpreter execution). diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index 1696f35563d..150cedde7e8 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -118,18 +118,18 @@ pub unsafe fn create_module( let mod_name = SmallCStr::new(mod_name); let llmod = llvm::LLVMModuleCreateWithNameInContext(mod_name.as_ptr(), llcx); - let mut target_data_layout = sess.target.target.data_layout.clone(); + let mut target_data_layout = sess.target.data_layout.clone(); if llvm_util::get_major_version() < 9 { target_data_layout = strip_function_ptr_alignment(target_data_layout); } if llvm_util::get_major_version() < 10 { - if sess.target.target.arch == "x86" || sess.target.target.arch == "x86_64" { + if sess.target.arch == "x86" || sess.target.arch == "x86_64" { target_data_layout = strip_x86_address_spaces(target_data_layout); } } // Ensure the data-layout values hardcoded remain the defaults. - if sess.target.target.options.is_builtin { + if sess.target.options.is_builtin { let tm = crate::back::write::create_informational_target_machine(tcx.sess); llvm::LLVMRustSetDataLayoutFromTargetMachine(llmod, tm); llvm::LLVMRustDisposeTargetMachine(tm); @@ -160,7 +160,7 @@ pub unsafe fn create_module( bug!( "data-layout for builtin `{}` target, `{}`, \ differs from LLVM default, `{}`", - sess.target.target.llvm_target, + sess.target.llvm_target, target_data_layout, llvm_data_layout ); @@ -170,7 +170,7 @@ pub unsafe fn create_module( let data_layout = SmallCStr::new(&target_data_layout); llvm::LLVMSetDataLayout(llmod, data_layout.as_ptr()); - let llvm_target = SmallCStr::new(&sess.target.target.llvm_target); + let llvm_target = SmallCStr::new(&sess.target.llvm_target); llvm::LLVMRustSetNormalizedTarget(llmod, llvm_target.as_ptr()); if sess.relocation_model() == RelocModel::Pic { @@ -190,7 +190,7 @@ pub unsafe fn create_module( } // Control Flow Guard is currently only supported by the MSVC linker on Windows. - if sess.target.target.options.is_like_msvc { + if sess.target.options.is_like_msvc { match sess.opts.cg.control_flow_guard { CFGuard::Disabled => {} CFGuard::NoChecks => { @@ -265,7 +265,7 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { // linker will take care of everything. Fixing this problem will likely // require adding a few attributes to Rust itself (feature gated at the // start) and then strongly recommending static linkage on Windows! - let use_dll_storage_attrs = tcx.sess.target.target.options.is_like_windows; + let use_dll_storage_attrs = tcx.sess.target.options.is_like_windows; let check_overflow = tcx.sess.overflow_checks(); @@ -417,7 +417,8 @@ impl MiscMethods<'tcx> for CodegenCx<'ll, 'tcx> { } fn apply_target_cpu_attr(&self, llfn: &'ll Value) { - attributes::apply_target_cpu_attr(self, llfn) + attributes::apply_target_cpu_attr(self, llfn); + attributes::apply_tune_cpu_attr(self, llfn); } fn create_used_variable(&self) { @@ -838,7 +839,7 @@ impl CodegenCx<'b, 'tcx> { return eh_catch_typeinfo; } let tcx = self.tcx; - assert!(self.sess().target.target.options.is_like_emscripten); + assert!(self.sess().target.options.is_like_emscripten); let eh_catch_typeinfo = match tcx.lang_items().eh_catch_typeinfo() { Some(def_id) => self.get_static(def_id), _ => { @@ -877,7 +878,7 @@ impl HasDataLayout for CodegenCx<'ll, 'tcx> { impl HasTargetSpec for CodegenCx<'ll, 'tcx> { fn target_spec(&self) -> &Target { - &self.tcx.sess.target.target + &self.tcx.sess.target } } diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs b/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs index 29edd66049c..79721ff7e2d 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs @@ -67,5 +67,5 @@ pub fn needs_gdb_debug_scripts_section(cx: &CodegenCx<'_, '_>) -> bool { !omit_gdb_pretty_printer_section && cx.sess().opts.debuginfo != DebugInfo::None - && cx.sess().target.target.options.emit_debug_gdb_scripts + && cx.sess().target.options.emit_debug_gdb_scripts } diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index 987149cb4c2..5587e6ead1d 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -874,7 +874,7 @@ fn basic_type_metadata(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>) -> &'ll DIType { // When targeting MSVC, emit MSVC style type names for compatibility with // .natvis visualizers (and perhaps other existing native debuggers?) - let msvc_like_names = cx.tcx.sess.target.target.options.is_like_msvc; + let msvc_like_names = cx.tcx.sess.target.options.is_like_msvc; let (name, encoding) = match t.kind() { ty::Never => ("!", DW_ATE_unsigned), @@ -985,7 +985,7 @@ pub fn compile_unit_metadata( // if multiple object files with the same `DW_AT_name` are linked together. // As a workaround we generate unique names for each object file. Those do // not correspond to an actual source file but that should be harmless. - if tcx.sess.target.target.options.is_like_osx { + if tcx.sess.target.options.is_like_osx { name_in_debuginfo.push("@"); name_in_debuginfo.push(codegen_unit_name); } @@ -1401,7 +1401,7 @@ fn prepare_union_metadata( /// on MSVC we have to use the fallback mode, because LLVM doesn't /// lower variant parts to PDB. fn use_enum_fallback(cx: &CodegenCx<'_, '_>) -> bool { - cx.sess().target.target.options.is_like_msvc + cx.sess().target.options.is_like_msvc } // FIXME(eddyb) maybe precompute this? Right now it's computed once diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs index 7cdd366175d..80e0e7bf2e0 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs @@ -120,14 +120,12 @@ pub fn finalize(cx: &CodegenCx<'_, '_>) { // for macOS to understand. For more info see #11352 // This can be overridden using --llvm-opts -dwarf-version,N. // Android has the same issue (#22398) - if cx.sess().target.target.options.is_like_osx - || cx.sess().target.target.options.is_like_android - { - llvm::LLVMRustAddModuleFlag(cx.llmod, "Dwarf Version\0".as_ptr().cast(), 2) + if let Some(version) = cx.sess().target.options.dwarf_version { + llvm::LLVMRustAddModuleFlag(cx.llmod, "Dwarf Version\0".as_ptr().cast(), version) } // Indicate that we want CodeView debug information on MSVC - if cx.sess().target.target.options.is_like_msvc { + if cx.sess().target.options.is_like_msvc { llvm::LLVMRustAddModuleFlag(cx.llmod, "CodeView\0".as_ptr().cast(), 1) } @@ -348,7 +346,7 @@ impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { }); // Arguments types - if cx.sess().target.target.options.is_like_msvc { + if cx.sess().target.options.is_like_msvc { // FIXME(#42800): // There is a bug in MSDIA that leads to a crash when it encounters // a fixed-size array of `u8` or something zero-sized in a diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/source_loc.rs b/compiler/rustc_codegen_llvm/src/debuginfo/source_loc.rs index 66ae9d72c3e..517246cd0b2 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/source_loc.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/source_loc.rs @@ -38,7 +38,7 @@ impl CodegenCx<'ll, '_> { // For MSVC, omit the column number. // Otherwise, emit it. This mimics clang behaviour. // See discussion in https://github.com/rust-lang/rust/issues/42921 - if self.sess().target.target.options.is_like_msvc { + if self.sess().target.options.is_like_msvc { DebugLoc { file, line, col: None } } else { DebugLoc { file, line, col } diff --git a/compiler/rustc_codegen_llvm/src/declare.rs b/compiler/rustc_codegen_llvm/src/declare.rs index a3d6882940a..9face778322 100644 --- a/compiler/rustc_codegen_llvm/src/declare.rs +++ b/compiler/rustc_codegen_llvm/src/declare.rs @@ -42,7 +42,7 @@ fn declare_raw_fn( // be merged. llvm::SetUnnamedAddress(llfn, llvm::UnnamedAddr::Global); - if cx.tcx.sess.opts.cg.no_redzone.unwrap_or(cx.tcx.sess.target.target.options.disable_redzone) { + if cx.tcx.sess.opts.cg.no_redzone.unwrap_or(cx.tcx.sess.target.options.disable_redzone) { llvm::Attribute::NoRedZone.apply_llfn(Function, llfn); } diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index e76e86f5651..e9900e8bc10 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -334,8 +334,8 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { self.call(expect, &[cond, self.const_bool(expected)], None) } - fn sideeffect(&mut self) { - if self.tcx.sess.opts.debugging_opts.insert_sideeffect { + fn sideeffect(&mut self, unconditional: bool) { + if unconditional || self.tcx.sess.opts.debugging_opts.insert_sideeffect { let fnname = self.get_intrinsic(&("llvm.sideeffect")); self.call(fnname, &[], None); } @@ -367,7 +367,7 @@ fn try_intrinsic( bx.store(bx.const_i32(0), dest, ret_align); } else if wants_msvc_seh(bx.sess()) { codegen_msvc_try(bx, try_func, data, catch_func, dest); - } else if bx.sess().target.target.options.is_like_emscripten { + } else if bx.sess().target.options.is_like_emscripten { codegen_emcc_try(bx, try_func, data, catch_func, dest); } else { codegen_gnu_try(bx, try_func, data, catch_func, dest); @@ -390,7 +390,7 @@ fn codegen_msvc_try( ) { let llfn = get_rust_try_fn(bx, &mut |mut bx| { bx.set_personality_fn(bx.eh_personality()); - bx.sideeffect(); + bx.sideeffect(false); let mut normal = bx.build_sibling_block("normal"); let mut catchswitch = bx.build_sibling_block("catchswitch"); @@ -553,7 +553,7 @@ fn codegen_gnu_try( // call %catch_func(%data, %ptr) // ret 1 - bx.sideeffect(); + bx.sideeffect(false); let mut then = bx.build_sibling_block("then"); let mut catch = bx.build_sibling_block("catch"); @@ -615,7 +615,7 @@ fn codegen_emcc_try( // call %catch_func(%data, %catch_data) // ret 1 - bx.sideeffect(); + bx.sideeffect(false); let mut then = bx.build_sibling_block("then"); let mut catch = bx.build_sibling_block("catch"); @@ -673,17 +673,9 @@ fn codegen_emcc_try( fn gen_fn<'ll, 'tcx>( cx: &CodegenCx<'ll, 'tcx>, name: &str, - inputs: Vec<Ty<'tcx>>, - output: Ty<'tcx>, + rust_fn_sig: ty::PolyFnSig<'tcx>, codegen: &mut dyn FnMut(Builder<'_, 'll, 'tcx>), ) -> &'ll Value { - let rust_fn_sig = ty::Binder::bind(cx.tcx.mk_fn_sig( - inputs.into_iter(), - output, - false, - hir::Unsafety::Unsafe, - Abi::Rust, - )); let fn_abi = FnAbi::of_fn_ptr(cx, rust_fn_sig, &[]); let llfn = cx.declare_fn(name, &fn_abi); cx.set_frame_pointer_elimination(llfn); @@ -710,22 +702,31 @@ fn get_rust_try_fn<'ll, 'tcx>( // Define the type up front for the signature of the rust_try function. let tcx = cx.tcx; let i8p = tcx.mk_mut_ptr(tcx.types.i8); - let try_fn_ty = tcx.mk_fn_ptr(ty::Binder::bind(tcx.mk_fn_sig( + // `unsafe fn(*mut i8) -> ()` + let try_fn_ty = tcx.mk_fn_ptr(ty::Binder::dummy(tcx.mk_fn_sig( iter::once(i8p), tcx.mk_unit(), false, hir::Unsafety::Unsafe, Abi::Rust, ))); - let catch_fn_ty = tcx.mk_fn_ptr(ty::Binder::bind(tcx.mk_fn_sig( + // `unsafe fn(*mut i8, *mut i8) -> ()` + let catch_fn_ty = tcx.mk_fn_ptr(ty::Binder::dummy(tcx.mk_fn_sig( [i8p, i8p].iter().cloned(), tcx.mk_unit(), false, hir::Unsafety::Unsafe, Abi::Rust, ))); - let output = tcx.types.i32; - let rust_try = gen_fn(cx, "__rust_try", vec![try_fn_ty, i8p, catch_fn_ty], output, codegen); + // `unsafe fn(unsafe fn(*mut i8) -> (), *mut i8, unsafe fn(*mut i8, *mut i8) -> ()) -> i32` + let rust_fn_sig = ty::Binder::dummy(cx.tcx.mk_fn_sig( + vec![try_fn_ty, i8p, catch_fn_ty].into_iter(), + tcx.types.i32, + false, + hir::Unsafety::Unsafe, + Abi::Rust, + )); + let rust_try = gen_fn(cx, "__rust_try", rust_fn_sig, codegen); cx.rust_try_fn.set(Some(rust_try)); rust_try } @@ -1722,10 +1723,10 @@ unsupported {} from `{}` with element `{}` of size `{}` to `{}`"#, fn int_type_width_signed(ty: Ty<'_>, cx: &CodegenCx<'_, '_>) -> Option<(u64, bool)> { match ty.kind() { ty::Int(t) => { - Some((t.bit_width().unwrap_or(u64::from(cx.tcx.sess.target.ptr_width)), true)) + Some((t.bit_width().unwrap_or(u64::from(cx.tcx.sess.target.pointer_width)), true)) } ty::Uint(t) => { - Some((t.bit_width().unwrap_or(u64::from(cx.tcx.sess.target.ptr_width)), false)) + Some((t.bit_width().unwrap_or(u64::from(cx.tcx.sess.target.pointer_width)), false)) } _ => None, } diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index 1237b39b300..5974b59d39e 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -23,18 +23,17 @@ use rustc_codegen_ssa::back::write::{CodegenContext, FatLTOInput, ModuleConfig}; use rustc_codegen_ssa::traits::*; use rustc_codegen_ssa::ModuleCodegen; use rustc_codegen_ssa::{CodegenResults, CompiledModule}; +use rustc_data_structures::fx::FxHashMap; use rustc_errors::{ErrorReported, FatalError, Handler}; -use rustc_middle::dep_graph::{DepGraph, WorkProduct}; +use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; use rustc_middle::middle::cstore::{EncodedMetadata, MetadataLoaderDyn}; use rustc_middle::ty::{self, TyCtxt}; -use rustc_serialize::json; -use rustc_session::config::{self, OptLevel, OutputFilenames, PrintRequest}; +use rustc_session::config::{OptLevel, OutputFilenames, PrintRequest}; use rustc_session::Session; use rustc_span::symbol::Symbol; use std::any::Any; use std::ffi::CStr; -use std::fs; use std::sync::Arc; mod back { @@ -116,6 +115,9 @@ impl ExtraBackendMethods for LlvmCodegenBackend { fn target_cpu<'b>(&self, sess: &'b Session) -> &'b str { llvm_util::target_cpu(sess) } + fn tune_cpu<'b>(&self, sess: &'b Session) -> Option<&'b str> { + llvm_util::tune_cpu(sess) + } } impl WriteBackendMethods for LlvmCodegenBackend { @@ -249,11 +251,11 @@ impl CodegenBackend for LlvmCodegenBackend { } fn provide(&self, providers: &mut ty::query::Providers) { - attributes::provide(providers); + attributes::provide_both(providers); } fn provide_extern(&self, providers: &mut ty::query::Providers) { - attributes::provide_extern(providers); + attributes::provide_both(providers); } fn codegen_crate<'tcx>( @@ -274,47 +276,27 @@ impl CodegenBackend for LlvmCodegenBackend { &self, ongoing_codegen: Box<dyn Any>, sess: &Session, - dep_graph: &DepGraph, - ) -> Result<Box<dyn Any>, ErrorReported> { + ) -> Result<(CodegenResults, FxHashMap<WorkProductId, WorkProduct>), ErrorReported> { let (codegen_results, work_products) = ongoing_codegen .downcast::<rustc_codegen_ssa::back::write::OngoingCodegen<LlvmCodegenBackend>>() .expect("Expected LlvmCodegenBackend's OngoingCodegen, found Box<Any>") .join(sess); - if sess.opts.debugging_opts.incremental_info { - rustc_codegen_ssa::back::write::dump_incremental_data(&codegen_results); - } - sess.time("serialize_work_products", move || { - rustc_incremental::save_work_product_index(sess, &dep_graph, work_products) + sess.time("llvm_dump_timing_file", || { + if sess.opts.debugging_opts.llvm_time_trace { + llvm_util::time_trace_profiler_finish("llvm_timings.json"); + } }); - sess.compile_status()?; - - Ok(Box::new(codegen_results)) + Ok((codegen_results, work_products)) } fn link( &self, sess: &Session, - codegen_results: Box<dyn Any>, + codegen_results: CodegenResults, outputs: &OutputFilenames, ) -> Result<(), ErrorReported> { - let codegen_results = codegen_results - .downcast::<CodegenResults>() - .expect("Expected CodegenResults, found Box<Any>"); - - if sess.opts.debugging_opts.no_link { - // FIXME: use a binary format to encode the `.rlink` file - let rlink_data = json::encode(&codegen_results).map_err(|err| { - sess.fatal(&format!("failed to encode rlink: {}", err)); - })?; - let rlink_file = outputs.with_extension(config::RLINK_EXT); - fs::write(&rlink_file, rlink_data).map_err(|err| { - sess.fatal(&format!("failed to write file {}: {}", rlink_file.display(), err)); - })?; - return Ok(()); - } - // Run the linker on any artifacts that resulted from the LLVM run. // This should produce either a finished executable or library. sess.time("link_crate", || { @@ -331,16 +313,6 @@ impl CodegenBackend for LlvmCodegenBackend { ); }); - // Now that we won't touch anything in the incremental compilation directory - // any more, we can finalize it (which involves renaming it) - rustc_incremental::finalize_session_directory(sess, codegen_results.crate_hash); - - sess.time("llvm_dump_timing_file", || { - if sess.opts.debugging_opts.llvm_time_trace { - llvm_util::time_trace_profiler_finish("llvm_timings.json"); - } - }); - Ok(()) } } diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index af3f3e7aa03..4c1fee0106a 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -2362,4 +2362,10 @@ extern "C" { bytecode_len: usize, ) -> bool; pub fn LLVMRustLinkerFree(linker: &'a mut Linker<'a>); + #[allow(improper_ctypes)] + pub fn LLVMRustComputeLTOCacheKey( + key_out: &RustString, + mod_id: *const c_char, + data: &ThinLTOData, + ); } diff --git a/compiler/rustc_codegen_llvm/src/llvm/mod.rs b/compiler/rustc_codegen_llvm/src/llvm/mod.rs index ed9b99188bb..53a404ee019 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/mod.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/mod.rs @@ -118,11 +118,6 @@ pub fn SetUnnamedAddress(global: &'a Value, unnamed: UnnamedAddr) { } } -pub fn set_thread_local(global: &'a Value, is_thread_local: bool) { - unsafe { - LLVMSetThreadLocal(global, is_thread_local as Bool); - } -} pub fn set_thread_local_mode(global: &'a Value, mode: ThreadLocalMode) { unsafe { LLVMSetThreadLocalMode(global, mode); diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index d42020047fd..9c1e1b8fac0 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -46,7 +46,7 @@ fn require_inited() { } unsafe fn configure_llvm(sess: &Session) { - let n_args = sess.opts.cg.llvm_args.len() + sess.target.target.options.llvm_args.len(); + let n_args = sess.opts.cg.llvm_args.len() + sess.target.options.llvm_args.len(); let mut llvm_c_strs = Vec::with_capacity(n_args + 1); let mut llvm_args = Vec::with_capacity(n_args + 1); @@ -57,7 +57,7 @@ unsafe fn configure_llvm(sess: &Session) { } let cg_opts = sess.opts.cg.llvm_args.iter(); - let tg_opts = sess.target.target.options.llvm_args.iter(); + let tg_opts = sess.target.options.llvm_args.iter(); let sess_args = cg_opts.chain(tg_opts); let user_specified_args: FxHashSet<_> = @@ -88,7 +88,7 @@ unsafe fn configure_llvm(sess: &Session) { .opts .debugging_opts .merge_functions - .unwrap_or(sess.target.target.options.merge_functions) + .unwrap_or(sess.target.options.merge_functions) { MergeFunctions::Disabled | MergeFunctions::Trampolines => {} MergeFunctions::Aliases => { @@ -96,9 +96,7 @@ unsafe fn configure_llvm(sess: &Session) { } } - if sess.target.target.target_os == "emscripten" - && sess.panic_strategy() == PanicStrategy::Unwind - { + if sess.target.target_os == "emscripten" && sess.panic_strategy() == PanicStrategy::Unwind { add("-enable-emscripten-cxx-exceptions", false); } @@ -122,7 +120,7 @@ unsafe fn configure_llvm(sess: &Session) { llvm::LLVMInitializePasses(); - ::rustc_llvm::initialize_available_targets(); + rustc_llvm::initialize_available_targets(); llvm::LLVMRustSetLLVMOptions(llvm_args.len() as c_int, llvm_args.as_ptr()); } @@ -140,7 +138,7 @@ pub fn time_trace_profiler_finish(file_name: &str) { // to LLVM or the feature detection code will walk past the end of the feature // array, leading to crashes. pub fn to_llvm_feature<'a>(sess: &Session, s: &'a str) -> &'a str { - let arch = if sess.target.target.arch == "x86_64" { "x86" } else { &*sess.target.target.arch }; + let arch = if sess.target.arch == "x86_64" { "x86" } else { &*sess.target.arch }; match (arch, s) { ("x86", "pclmulqdq") => "pclmul", ("x86", "rdrand") => "rdrnd", @@ -202,11 +200,7 @@ pub(crate) fn print(req: PrintRequest, sess: &Session) { } } -pub fn target_cpu(sess: &Session) -> &str { - let name = match sess.opts.cg.target_cpu { - Some(ref s) => &**s, - None => &*sess.target.target.options.cpu, - }; +fn handle_native(name: &str) -> &str { if name != "native" { return name; } @@ -217,3 +211,19 @@ pub fn target_cpu(sess: &Session) -> &str { str::from_utf8(slice::from_raw_parts(ptr as *const u8, len)).unwrap() } } + +pub fn target_cpu(sess: &Session) -> &str { + let name = match sess.opts.cg.target_cpu { + Some(ref s) => &**s, + None => &*sess.target.options.cpu, + }; + + handle_native(name) +} + +pub fn tune_cpu(sess: &Session) -> Option<&str> { + match sess.opts.debugging_opts.tune_cpu { + Some(ref s) => Some(handle_native(&**s)), + None => None, + } +} diff --git a/compiler/rustc_codegen_llvm/src/va_arg.rs b/compiler/rustc_codegen_llvm/src/va_arg.rs index 22ed4dd7576..5f820f83a94 100644 --- a/compiler/rustc_codegen_llvm/src/va_arg.rs +++ b/compiler/rustc_codegen_llvm/src/va_arg.rs @@ -52,7 +52,7 @@ fn emit_direct_ptr_va_arg( let next = bx.inbounds_gep(addr, &[full_direct_size]); bx.store(next, va_list_addr, bx.tcx().data_layout.pointer_align.abi); - if size.bytes() < slot_size.bytes() && &*bx.tcx().sess.target.target.target_endian == "big" { + if size.bytes() < slot_size.bytes() && &*bx.tcx().sess.target.target_endian == "big" { let adjusted_size = bx.cx().const_i32((slot_size.bytes() - size.bytes()) as i32); let adjusted = bx.inbounds_gep(addr, &[adjusted_size]); (bx.bitcast(adjusted, bx.cx().type_ptr_to(llty)), addr_align) @@ -105,7 +105,7 @@ fn emit_aapcs_va_arg( let mut end = bx.build_sibling_block("va_arg.end"); let zero = bx.const_i32(0); let offset_align = Align::from_bytes(4).unwrap(); - assert!(&*bx.tcx().sess.target.target.target_endian == "little"); + assert!(&*bx.tcx().sess.target.target_endian == "little"); let gr_type = target_ty.is_any_ptr() || target_ty.is_integral(); let (reg_off, reg_top_index, slot_size) = if gr_type { @@ -171,8 +171,8 @@ pub(super) fn emit_va_arg( ) -> &'ll Value { // Determine the va_arg implementation to use. The LLVM va_arg instruction // is lacking in some instances, so we should only use it as a fallback. - let target = &bx.cx.tcx.sess.target.target; - let arch = &bx.cx.tcx.sess.target.target.arch; + let target = &bx.cx.tcx.sess.target; + let arch = &bx.cx.tcx.sess.target.arch; match (&**arch, target.options.is_like_windows) { // Windows x86 ("x86", true) => { diff --git a/compiler/rustc_codegen_ssa/src/back/archive.rs b/compiler/rustc_codegen_ssa/src/back/archive.rs index f83b4b2b0c0..ef722ecb599 100644 --- a/compiler/rustc_codegen_ssa/src/back/archive.rs +++ b/compiler/rustc_codegen_ssa/src/back/archive.rs @@ -9,9 +9,7 @@ pub fn find_library(name: Symbol, search_paths: &[PathBuf], sess: &Session) -> P // times show up as foo.lib let oslibname = format!( "{}{}{}", - sess.target.target.options.staticlib_prefix, - name, - sess.target.target.options.staticlib_suffix + sess.target.options.staticlib_prefix, name, sess.target.options.staticlib_suffix ); let unixlibname = format!("lib{}.a", name); diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 010fd4e9c5a..63d0a88858e 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -15,7 +15,7 @@ use rustc_session::{filesearch, Session}; use rustc_span::symbol::Symbol; use rustc_target::spec::crt_objects::{CrtObjects, CrtObjectsFallback}; use rustc_target::spec::{LinkOutputKind, LinkerFlavor, LldFlavor}; -use rustc_target::spec::{PanicStrategy, RelocModel, RelroLevel}; +use rustc_target::spec::{PanicStrategy, RelocModel, RelroLevel, Target}; use super::archive::ArchiveBuilder; use super::command::Command; @@ -152,7 +152,7 @@ fn get_linker( _ => match flavor { LinkerFlavor::Lld(f) => Command::lld(linker, f), LinkerFlavor::Msvc - if sess.opts.cg.linker.is_none() && sess.target.target.options.linker.is_none() => + if sess.opts.cg.linker.is_none() && sess.target.options.linker.is_none() => { Command::new(msvc_tool.as_ref().map(|t| t.path()).unwrap_or(linker)) } @@ -163,7 +163,7 @@ fn get_linker( // UWP apps have API restrictions enforced during Store submissions. // To comply with the Windows App Certification Kit, // MSVC needs to link with the Store versions of the runtime libraries (vcruntime, msvcrt, etc). - let t = &sess.target.target; + let t = &sess.target; if (flavor == LinkerFlavor::Msvc || flavor == LinkerFlavor::Lld(LldFlavor::Link)) && t.target_vendor == "uwp" { @@ -197,7 +197,7 @@ fn get_linker( // PATH for the child. let mut new_path = sess.host_filesearch(PathKind::All).get_tools_search_paths(self_contained); let mut msvc_changed_path = false; - if sess.target.target.options.is_like_msvc { + if sess.target.options.is_like_msvc { if let Some(ref tool) = msvc_tool { cmd.args(tool.args()); for &(ref k, ref v) in tool.env() { @@ -365,7 +365,7 @@ fn link_rlib<'a, B: ArchiveBuilder<'a>>( // After adding all files to the archive, we need to update the // symbol table of the archive. This currently dies on macOS (see // #11162), and isn't necessary there anyway - if !sess.target.target.options.is_like_osx { + if !sess.target.options.is_like_osx { ab.update_symbols(); } } @@ -476,10 +476,10 @@ fn link_natively<'a, B: ArchiveBuilder<'a>>( linker::disable_localization(&mut cmd); - for &(ref k, ref v) in &sess.target.target.options.link_env { + for &(ref k, ref v) in &sess.target.options.link_env { cmd.env(k, v); } - for k in &sess.target.target.options.link_env_remove { + for k in &sess.target.options.link_env_remove { cmd.env_remove(k); } @@ -515,7 +515,7 @@ fn link_natively<'a, B: ArchiveBuilder<'a>>( // if the linker doesn't support -no-pie then it should not default to // linking executables as pie. Different versions of gcc seem to use // different quotes in the error message so don't check for them. - if sess.target.target.options.linker_is_gnu + if sess.target.options.linker_is_gnu && flavor != LinkerFlavor::Ld && (out.contains("unrecognized command line option") || out.contains("unknown argument")) @@ -535,7 +535,7 @@ fn link_natively<'a, B: ArchiveBuilder<'a>>( // Detect '-static-pie' used with an older version of gcc or clang not supporting it. // Fallback from '-static-pie' to '-static' in that case. - if sess.target.target.options.linker_is_gnu + if sess.target.options.linker_is_gnu && flavor != LinkerFlavor::Ld && (out.contains("unrecognized command line option") || out.contains("unknown argument")) @@ -548,7 +548,7 @@ fn link_natively<'a, B: ArchiveBuilder<'a>>( ); // Mirror `add_(pre,post)_link_objects` to replace CRT objects. let self_contained = crt_objects_fallback(sess, crate_type); - let opts = &sess.target.target.options; + let opts = &sess.target.options; let pre_objects = if self_contained { &opts.pre_link_objects_fallback } else { @@ -670,7 +670,7 @@ fn link_natively<'a, B: ArchiveBuilder<'a>>( // is not a Microsoft LNK error then suggest a way to fix or // install the Visual Studio build tools. if let Some(code) = prog.status.code() { - if sess.target.target.options.is_like_msvc + if sess.target.options.is_like_msvc && flavor == LinkerFlavor::Msvc // Respect the command line override && sess.opts.cg.linker.is_none() @@ -741,7 +741,7 @@ fn link_natively<'a, B: ArchiveBuilder<'a>>( linker_error.emit(); - if sess.target.target.options.is_like_msvc && linker_not_found { + if sess.target.options.is_like_msvc && linker_not_found { sess.note_without_error( "the msvc targets depend on the msvc linker \ but `link.exe` was not found", @@ -758,7 +758,7 @@ fn link_natively<'a, B: ArchiveBuilder<'a>>( // On macOS, debuggers need this utility to get run to do some munging of // the symbols. Note, though, that if the object files are being preserved // for their debug information there's no need for us to run dsymutil. - if sess.target.target.options.is_like_osx + if sess.target.options.is_like_osx && sess.opts.debuginfo != DebugInfo::None && !preserve_objects_for_their_debuginfo(sess) { @@ -776,7 +776,7 @@ fn link_sanitizers(sess: &Session, crate_type: CrateType, linker: &mut dyn Linke let needs_runtime = match crate_type { CrateType::Executable => true, CrateType::Dylib | CrateType::Cdylib | CrateType::ProcMacro => { - sess.target.target.options.is_like_osx + sess.target.options.is_like_osx } CrateType::Rlib | CrateType::Staticlib => false, }; @@ -846,7 +846,7 @@ pub fn ignored_for_lto(sess: &Session, info: &CrateInfo, cnum: CrateNum) -> bool // If our target enables builtin function lowering in LLVM then the // crates providing these functions don't participate in LTO (e.g. // no_builtins or compiler builtins crates). - !sess.target.target.options.no_builtins + !sess.target.options.no_builtins && (info.compiler_builtins == Some(cnum) || info.is_no_builtins.contains(&cnum)) } @@ -906,10 +906,10 @@ fn linker_and_flavor(sess: &Session) -> (PathBuf, LinkerFlavor) { } else if stem == "link" || stem == "lld-link" { LinkerFlavor::Msvc } else if stem == "lld" || stem == "rust-lld" { - LinkerFlavor::Lld(sess.target.target.options.lld_flavor) + LinkerFlavor::Lld(sess.target.options.lld_flavor) } else { // fall back to the value in the target spec - sess.target.target.linker_flavor + sess.target.linker_flavor }; Some((linker, flavor)) @@ -926,8 +926,8 @@ fn linker_and_flavor(sess: &Session) -> (PathBuf, LinkerFlavor) { if let Some(ret) = infer_from( sess, - sess.target.target.options.linker.clone().map(PathBuf::from), - Some(sess.target.target.linker_flavor), + sess.target.options.linker.clone().map(PathBuf::from), + Some(sess.target.linker_flavor), ) { return ret; } @@ -962,7 +962,7 @@ fn preserve_objects_for_their_debuginfo(sess: &Session) -> bool { // Basically as a result this just means that if we're on OSX and we're // *not* running dsymutil then the object files are the only source of truth // for debug information, so we must preserve them. - if sess.target.target.options.is_like_osx { + if sess.target.options.is_like_osx { return !sess.opts.debugging_opts.run_dsymutil; } @@ -988,7 +988,7 @@ fn print_native_static_libs(sess: &Session, all_native_libs: &[NativeLib]) { NativeLibKind::StaticNoBundle | NativeLibKind::Dylib | NativeLibKind::Unspecified => { - if sess.target.target.options.is_like_msvc { + if sess.target.options.is_like_msvc { Some(format!("{}.lib", name)) } else { Some(format!("-l{}", name)) @@ -1070,16 +1070,13 @@ fn exec_linker( let mut args = String::new(); for arg in cmd2.take_args() { args.push_str( - &Escape { - arg: arg.to_str().unwrap(), - is_like_msvc: sess.target.target.options.is_like_msvc, - } - .to_string(), + &Escape { arg: arg.to_str().unwrap(), is_like_msvc: sess.target.options.is_like_msvc } + .to_string(), ); args.push('\n'); } let file = tmpdir.join("linker-arguments"); - let bytes = if sess.target.target.options.is_like_msvc { + let bytes = if sess.target.options.is_like_msvc { let mut out = Vec::with_capacity((1 + args.len()) * 2); // start the stream with a UTF-16 BOM for c in std::iter::once(0xFEFF).chain(args.encode_utf16()) { @@ -1195,7 +1192,7 @@ fn link_output_kind(sess: &Session, crate_type: CrateType) -> LinkOutputKind { }; // Adjust the output kind to target capabilities. - let opts = &sess.target.target.options; + let opts = &sess.target.options; let pic_exe_supported = opts.position_independent_executables; let static_pic_exe_supported = opts.static_position_independent_executables; let static_dylib_supported = opts.crt_static_allows_dylibs; @@ -1236,14 +1233,14 @@ fn crt_objects_fallback(sess: &Session, crate_type: CrateType) -> bool { return self_contained; } - match sess.target.target.options.crt_objects_fallback { + match sess.target.options.crt_objects_fallback { // FIXME: Find a better heuristic for "native musl toolchain is available", // based on host and linker path, for example. // (https://github.com/rust-lang/rust/pull/71769#issuecomment-626330237). Some(CrtObjectsFallback::Musl) => sess.crt_static(Some(crate_type)), Some(CrtObjectsFallback::Mingw) => { - sess.host == sess.target.target - && sess.target.target.target_vendor != "uwp" + sess.host == sess.target + && sess.target.target_vendor != "uwp" && detect_self_contained_mingw(&sess) } // FIXME: Figure out cases in which WASM needs to link with a native toolchain. @@ -1259,7 +1256,7 @@ fn add_pre_link_objects( link_output_kind: LinkOutputKind, self_contained: bool, ) { - let opts = &sess.target.target.options; + let opts = &sess.target.options; let objects = if self_contained { &opts.pre_link_objects_fallback } else { &opts.pre_link_objects }; for obj in objects.get(&link_output_kind).iter().copied().flatten() { @@ -1274,7 +1271,7 @@ fn add_post_link_objects( link_output_kind: LinkOutputKind, self_contained: bool, ) { - let opts = &sess.target.target.options; + let opts = &sess.target.options; let objects = if self_contained { &opts.post_link_objects_fallback } else { &opts.post_link_objects }; for obj in objects.get(&link_output_kind).iter().copied().flatten() { @@ -1285,7 +1282,7 @@ fn add_post_link_objects( /// Add arbitrary "pre-link" args defined by the target spec or from command line. /// FIXME: Determine where exactly these args need to be inserted. fn add_pre_link_args(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) { - if let Some(args) = sess.target.target.options.pre_link_args.get(&flavor) { + if let Some(args) = sess.target.options.pre_link_args.get(&flavor) { cmd.args(args); } cmd.args(&sess.opts.debugging_opts.pre_link_args); @@ -1293,13 +1290,13 @@ fn add_pre_link_args(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) /// Add a link script embedded in the target, if applicable. fn add_link_script(cmd: &mut dyn Linker, sess: &Session, tmpdir: &Path, crate_type: CrateType) { - match (crate_type, &sess.target.target.options.link_script) { + match (crate_type, &sess.target.options.link_script) { (CrateType::Cdylib | CrateType::Executable, Some(script)) => { - if !sess.target.target.options.linker_is_gnu { + if !sess.target.options.linker_is_gnu { sess.fatal("can only use link script when linking with GNU-like linker"); } - let file_name = ["rustc", &sess.target.target.llvm_target, "linkfile.ld"].join("-"); + let file_name = ["rustc", &sess.target.llvm_target, "linkfile.ld"].join("-"); let path = tmpdir.join(file_name); if let Err(e) = fs::write(&path, script) { @@ -1338,15 +1335,15 @@ fn add_late_link_args( *ty == crate_type && list.iter().any(|&linkage| linkage == Linkage::Dynamic) }); if any_dynamic_crate { - if let Some(args) = sess.target.target.options.late_link_args_dynamic.get(&flavor) { + if let Some(args) = sess.target.options.late_link_args_dynamic.get(&flavor) { cmd.args(args); } } else { - if let Some(args) = sess.target.target.options.late_link_args_static.get(&flavor) { + if let Some(args) = sess.target.options.late_link_args_static.get(&flavor) { cmd.args(args); } } - if let Some(args) = sess.target.target.options.late_link_args.get(&flavor) { + if let Some(args) = sess.target.options.late_link_args.get(&flavor) { cmd.args(args); } } @@ -1354,7 +1351,7 @@ fn add_late_link_args( /// Add arbitrary "post-link" args defined by the target spec. /// FIXME: Determine where exactly these args need to be inserted. fn add_post_link_args(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) { - if let Some(args) = sess.target.target.options.post_link_args.get(&flavor) { + if let Some(args) = sess.target.options.post_link_args.get(&flavor) { cmd.args(args); } } @@ -1456,7 +1453,7 @@ fn add_library_search_dirs(cmd: &mut dyn Linker, sess: &Session, self_contained: /// Add options making relocation sections in the produced ELF files read-only /// and suppressing lazy binding. fn add_relro_args(cmd: &mut dyn Linker, sess: &Session) { - match sess.opts.debugging_opts.relro_level.unwrap_or(sess.target.target.options.relro_level) { + match sess.opts.debugging_opts.relro_level.unwrap_or(sess.target.options.relro_level) { RelroLevel::Full => cmd.full_relro(), RelroLevel::Partial => cmd.partial_relro(), RelroLevel::Off => cmd.no_relro(), @@ -1487,9 +1484,9 @@ fn add_rpath_args( let mut rpath_config = RPathConfig { used_crates: &codegen_results.crate_info.used_crates_dynamic, out_filename: out_filename.to_path_buf(), - has_rpath: sess.target.target.options.has_rpath, - is_like_osx: sess.target.target.options.is_like_osx, - linker_is_gnu: sess.target.target.options.linker_is_gnu, + has_rpath: sess.target.options.has_rpath, + is_like_osx: sess.target.options.is_like_osx, + linker_is_gnu: sess.target.options.linker_is_gnu, get_install_prefix_lib_path: &mut get_install_prefix_lib_path, }; cmd.args(&rpath::get_rpath_flags(&mut rpath_config)); @@ -1517,7 +1514,7 @@ fn linker_with_args<'a, B: ArchiveBuilder<'a>>( let base_cmd = get_linker(sess, path, flavor, crt_objects_fallback); // FIXME: Move `/LIBPATH` addition for uwp targets from the linker construction // to the linker args construction. - assert!(base_cmd.get_args().is_empty() || sess.target.target.target_vendor == "uwp"); + assert!(base_cmd.get_args().is_empty() || sess.target.target_vendor == "uwp"); let cmd = &mut *codegen_results.linker_info.to_linker(base_cmd, &sess, flavor, target_cpu); let link_output_kind = link_output_kind(sess, crate_type); @@ -1531,7 +1528,7 @@ fn linker_with_args<'a, B: ArchiveBuilder<'a>>( add_link_script(cmd, sess, tmpdir, crate_type); // NO-OPT-OUT, OBJECT-FILES-NO, AUDIT-ORDER - if sess.target.target.options.is_like_fuchsia && crate_type == CrateType::Executable { + if sess.target.options.is_like_fuchsia && crate_type == CrateType::Executable { let prefix = if sess.opts.debugging_opts.sanitizer.contains(SanitizerSet::ADDRESS) { "asan/" } else { @@ -1541,7 +1538,7 @@ fn linker_with_args<'a, B: ArchiveBuilder<'a>>( } // NO-OPT-OUT, OBJECT-FILES-NO, AUDIT-ORDER - if sess.target.target.options.eh_frame_header { + if sess.target.options.eh_frame_header { cmd.add_eh_frame_header(); } @@ -1554,7 +1551,7 @@ fn linker_with_args<'a, B: ArchiveBuilder<'a>>( add_pre_link_objects(cmd, sess, link_output_kind, crt_objects_fallback); // NO-OPT-OUT, OBJECT-FILES-NO, AUDIT-ORDER - if sess.target.target.options.is_like_emscripten { + if sess.target.options.is_like_emscripten { cmd.arg("-s"); cmd.arg(if sess.panic_strategy() == PanicStrategy::Abort { "DISABLE_EXCEPTION_CATCHING=1" @@ -1582,7 +1579,7 @@ fn linker_with_args<'a, B: ArchiveBuilder<'a>>( cmd.output_filename(out_filename); // OBJECT-FILES-NO, AUDIT-ORDER - if crate_type == CrateType::Executable && sess.target.target.options.is_like_windows { + if crate_type == CrateType::Executable && sess.target.options.is_like_windows { if let Some(ref s) = codegen_results.windows_subsystem { cmd.subsystem(s); } @@ -1626,7 +1623,7 @@ fn linker_with_args<'a, B: ArchiveBuilder<'a>>( // OBJECT-FILES-NO, AUDIT-ORDER // We want to prevent the compiler from accidentally leaking in any system libraries, // so by default we tell linkers not to link to any default libraries. - if !sess.opts.cg.default_linker_libraries && sess.target.target.options.no_default_libraries { + if !sess.opts.cg.default_linker_libraries && sess.target.options.no_default_libraries { cmd.no_default_libraries(); } @@ -1845,12 +1842,8 @@ fn add_upstream_rust_crates<'a, B: ArchiveBuilder<'a>>( } // Converts a library file-stem into a cc -l argument - fn unlib<'a>(config: &config::Config, stem: &'a str) -> &'a str { - if stem.starts_with("lib") && !config.target.options.is_like_windows { - &stem[3..] - } else { - stem - } + fn unlib<'a>(target: &Target, stem: &'a str) -> &'a str { + if stem.starts_with("lib") && !target.options.is_like_windows { &stem[3..] } else { stem } } // Adds the static "rlib" versions of all crates to the command line. @@ -1945,7 +1938,7 @@ fn add_upstream_rust_crates<'a, B: ArchiveBuilder<'a>>( // though, so we let that object file slide. let skip_because_lto = are_upstream_rust_objects_already_included(sess) && is_rust_object - && (sess.target.target.options.no_builtins + && (sess.target.options.no_builtins || !codegen_results.crate_info.is_no_builtins.contains(&cnum)); if skip_because_cfg_say_so || skip_because_lto { @@ -2088,10 +2081,10 @@ fn are_upstream_rust_objects_already_included(sess: &Session) -> bool { } fn add_apple_sdk(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) { - let arch = &sess.target.target.arch; - let os = &sess.target.target.target_os; - let llvm_target = &sess.target.target.llvm_target; - if sess.target.target.target_vendor != "apple" + let arch = &sess.target.arch; + let os = &sess.target.target_os; + let llvm_target = &sess.target.llvm_target; + if sess.target.target_vendor != "apple" || !matches!(os.as_str(), "ios" | "tvos") || flavor != LinkerFlavor::Gcc { diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs index 0ddf8bd316f..3e13a1daecd 100644 --- a/compiler/rustc_codegen_ssa/src/back/linker.rs +++ b/compiler/rustc_codegen_ssa/src/back/linker.rs @@ -184,7 +184,7 @@ impl<'a> GccLinker<'a> { // * On OSX they have their own linker, not binutils' // * For WebAssembly the only functional linker is LLD, which doesn't // support hint flags - !self.sess.target.target.options.is_like_osx && self.sess.target.target.arch != "wasm32" + !self.sess.target.options.is_like_osx && self.sess.target.arch != "wasm32" } // Some platforms take hints about whether a library is static or dynamic. @@ -221,10 +221,8 @@ impl<'a> GccLinker<'a> { let opt_level = match self.sess.opts.optimize { config::OptLevel::No => "O0", config::OptLevel::Less => "O1", - config::OptLevel::Default => "O2", + config::OptLevel::Default | config::OptLevel::Size | config::OptLevel::SizeMin => "O2", config::OptLevel::Aggressive => "O3", - config::OptLevel::Size => "Os", - config::OptLevel::SizeMin => "Oz", }; self.linker_arg(&format!("-plugin-opt={}", opt_level)); @@ -234,7 +232,7 @@ impl<'a> GccLinker<'a> { fn build_dylib(&mut self, out_filename: &Path) { // On mac we need to tell the linker to let this library be rpathed - if self.sess.target.target.options.is_like_osx { + if self.sess.target.options.is_like_osx { self.cmd.arg("-dynamiclib"); self.linker_arg("-dylib"); @@ -250,7 +248,7 @@ impl<'a> GccLinker<'a> { } } else { self.cmd.arg("-shared"); - if self.sess.target.target.options.is_like_windows { + if self.sess.target.options.is_like_windows { // The output filename already contains `dll_suffix` so // the resulting import library will have a name in the // form of libfoo.dll.a @@ -258,9 +256,9 @@ impl<'a> GccLinker<'a> { out_filename.file_name().and_then(|file| file.to_str()).map(|file| { format!( "{}{}{}", - self.sess.target.target.options.staticlib_prefix, + self.sess.target.options.staticlib_prefix, file, - self.sess.target.target.options.staticlib_suffix + self.sess.target.options.staticlib_suffix ) }); if let Some(implib_name) = implib_name { @@ -282,7 +280,7 @@ impl<'a> Linker for GccLinker<'a> { fn set_output_kind(&mut self, output_kind: LinkOutputKind, out_filename: &Path) { match output_kind { LinkOutputKind::DynamicNoPicExe => { - if !self.is_ld && self.sess.target.target.options.linker_is_gnu { + if !self.is_ld && self.sess.target.options.linker_is_gnu { self.cmd.arg("-no-pie"); } } @@ -293,7 +291,7 @@ impl<'a> Linker for GccLinker<'a> { LinkOutputKind::StaticNoPicExe => { // `-static` works for both gcc wrapper and ld. self.cmd.arg("-static"); - if !self.is_ld && self.sess.target.target.options.linker_is_gnu { + if !self.is_ld && self.sess.target.options.linker_is_gnu { self.cmd.arg("-no-pie"); } } @@ -322,7 +320,7 @@ impl<'a> Linker for GccLinker<'a> { // any `#[link]` attributes in the `libc` crate, see #72782 for details. // FIXME: Switch to using `#[link]` attributes in the `libc` crate // similarly to other targets. - if self.sess.target.target.target_os == "vxworks" + if self.sess.target.target_os == "vxworks" && matches!( output_kind, LinkOutputKind::StaticNoPicExe @@ -387,7 +385,7 @@ impl<'a> Linker for GccLinker<'a> { // functions, etc. fn link_whole_staticlib(&mut self, lib: Symbol, search_path: &[PathBuf]) { self.hint_static(); - let target = &self.sess.target.target; + let target = &self.sess.target; if !target.options.is_like_osx { self.linker_arg("--whole-archive").cmd.arg(format!("-l{}", lib)); self.linker_arg("--no-whole-archive"); @@ -402,7 +400,7 @@ impl<'a> Linker for GccLinker<'a> { fn link_whole_rlib(&mut self, lib: &Path) { self.hint_static(); - if self.sess.target.target.options.is_like_osx { + if self.sess.target.options.is_like_osx { self.linker_arg("-force_load"); self.linker_arg(&lib); } else { @@ -426,9 +424,9 @@ impl<'a> Linker for GccLinker<'a> { // -dead_strip can't be part of the pre_link_args because it's also used // for partial linking when using multiple codegen units (-r). So we // insert it here. - if self.sess.target.target.options.is_like_osx { + if self.sess.target.options.is_like_osx { self.linker_arg("-dead_strip"); - } else if self.sess.target.target.options.is_like_solaris { + } else if self.sess.target.options.is_like_solaris { self.linker_arg("-zignore"); // If we're building a dylib, we don't use --gc-sections because LLVM @@ -442,7 +440,7 @@ impl<'a> Linker for GccLinker<'a> { } fn optimize(&mut self) { - if !self.sess.target.target.options.linker_is_gnu { + if !self.sess.target.options.linker_is_gnu { return; } @@ -456,7 +454,7 @@ impl<'a> Linker for GccLinker<'a> { } fn pgo_gen(&mut self) { - if !self.sess.target.target.options.linker_is_gnu { + if !self.sess.target.options.linker_is_gnu { return; } @@ -506,7 +504,7 @@ impl<'a> Linker for GccLinker<'a> { fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType) { // Symbol visibility in object files typically takes care of this. if crate_type == CrateType::Executable - && self.sess.target.target.options.override_export_symbols.is_none() + && self.sess.target.options.override_export_symbols.is_none() { return; } @@ -515,7 +513,7 @@ impl<'a> Linker for GccLinker<'a> { // The object files have far more public symbols than we actually want to export, // so we hide them all here. - if !self.sess.target.target.options.limit_rdylib_exports { + if !self.sess.target.options.limit_rdylib_exports { return; } @@ -523,13 +521,13 @@ impl<'a> Linker for GccLinker<'a> { return; } - let is_windows = self.sess.target.target.options.is_like_windows; + let is_windows = self.sess.target.options.is_like_windows; let mut arg = OsString::new(); let path = tmpdir.join(if is_windows { "list.def" } else { "list" }); debug!("EXPORTED SYMBOLS:"); - if self.sess.target.target.options.is_like_osx { + if self.sess.target.options.is_like_osx { // Write a plain, newline-separated list of symbols let res: io::Result<()> = try { let mut f = BufWriter::new(File::create(&path)?); @@ -575,12 +573,12 @@ impl<'a> Linker for GccLinker<'a> { } } - if self.sess.target.target.options.is_like_osx { + if self.sess.target.options.is_like_osx { if !self.is_ld { arg.push("-Wl,") } arg.push("-exported_symbols_list,"); - } else if self.sess.target.target.options.is_like_solaris { + } else if self.sess.target.options.is_like_solaris { if !self.is_ld { arg.push("-Wl,") } @@ -1205,7 +1203,7 @@ impl<'a> Linker for WasmLd<'a> { } fn exported_symbols(tcx: TyCtxt<'_>, crate_type: CrateType) -> Vec<String> { - if let Some(ref exports) = tcx.sess.target.target.options.override_export_symbols { + if let Some(ref exports) = tcx.sess.target.options.override_export_symbols { return exports.clone(); } @@ -1295,7 +1293,7 @@ impl<'a> Linker for PtxLinker<'a> { // Provide the linker with fallback to internal `target-cpu`. self.cmd.arg("--fallback-arch").arg(match self.sess.opts.cg.target_cpu { Some(ref s) => s, - None => &self.sess.target.target.options.cpu, + None => &self.sess.target.options.cpu, }); } diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs index 51cc1ada432..dd8d751d045 100644 --- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs +++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs @@ -229,8 +229,8 @@ fn exported_symbols_provider_local( // needs to be exported. // However, on platforms that don't allow for Rust dylibs, having // external linkage is enough for monomorphization to be linked to. - let need_visibility = tcx.sess.target.target.options.dynamic_linking - && !tcx.sess.target.target.options.only_cdylib; + let need_visibility = + tcx.sess.target.options.dynamic_linking && !tcx.sess.target.options.only_cdylib; let (_, cgus) = tcx.collect_and_partition_mono_items(LOCAL_CRATE); @@ -391,7 +391,7 @@ fn symbol_export_level(tcx: TyCtxt<'_>, sym_def_id: DefId) -> SymbolExportLevel codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL); if is_extern && !std_internal { - let target = &tcx.sess.target.target.llvm_target; + let target = &tcx.sess.target.llvm_target; // WebAssembly cannot export data symbols, so reduce their export level if target.contains("emscripten") { if let Some(Node::Item(&hir::Item { kind: hir::ItemKind::Static(..), .. })) = diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index 0edf0fcd1a2..4d2cea18dcc 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -13,7 +13,6 @@ use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::profiling::SelfProfilerRef; use rustc_data_structures::profiling::TimingGuard; use rustc_data_structures::profiling::VerboseTimingGuard; -use rustc_data_structures::svh::Svh; use rustc_data_structures::sync::Lrc; use rustc_errors::emitter::Emitter; use rustc_errors::{DiagnosticId, FatalError, Handler, Level}; @@ -140,7 +139,7 @@ impl ModuleConfig { let emit_obj = if !should_emit_obj { EmitObj::None - } else if sess.target.target.options.obj_is_bitcode + } else if sess.target.options.obj_is_bitcode || (sess.opts.cg.linker_plugin_lto.enabled() && !no_builtins) { // This case is selected if the target uses objects as bitcode, or @@ -222,11 +221,11 @@ impl ModuleConfig { false ), emit_obj, - bc_cmdline: sess.target.target.options.bitcode_llvm_cmdline.clone(), + bc_cmdline: sess.target.options.bitcode_llvm_cmdline.clone(), verify_llvm_ir: sess.verify_llvm_ir(), no_prepopulate_passes: sess.opts.cg.no_prepopulate_passes, - no_builtins: no_builtins || sess.target.target.options.no_builtins, + no_builtins: no_builtins || sess.target.options.no_builtins, // Exclude metadata and allocator modules from time_passes output, // since they throw off the "LLVM passes" measurement. @@ -253,7 +252,7 @@ impl ModuleConfig { .opts .debugging_opts .merge_functions - .unwrap_or(sess.target.target.options.merge_functions) + .unwrap_or(sess.target.options.merge_functions) { MergeFunctions::Disabled => false, MergeFunctions::Trampolines | MergeFunctions::Aliases => { @@ -308,7 +307,7 @@ pub struct CodegenContext<B: WriteBackendMethods> { pub allocator_module_config: Arc<ModuleConfig>, pub tm_factory: TargetMachineFactory<B>, pub msvc_imps_needed: bool, - pub target_pointer_width: String, + pub target_pointer_width: u32, pub target_arch: String, pub debuginfo: config::DebugInfo, @@ -389,7 +388,7 @@ fn need_bitcode_in_object(sess: &Session) -> bool { let requested_for_rlib = sess.opts.cg.embed_bitcode && sess.crate_types().contains(&CrateType::Rlib) && sess.opts.output_types.contains_key(&OutputType::Exe); - let forced_by_target = sess.target.target.options.forces_embed_bitcode; + let forced_by_target = sess.target.options.forces_embed_bitcode; requested_for_rlib || forced_by_target } @@ -414,7 +413,6 @@ pub fn start_async_codegen<B: ExtraBackendMethods>( let sess = tcx.sess; let crate_name = tcx.crate_name(LOCAL_CRATE); - let crate_hash = tcx.crate_hash(LOCAL_CRATE); let no_builtins = tcx.sess.contains_name(&tcx.hir().krate().item.attrs, sym::no_builtins); let is_compiler_builtins = tcx.sess.contains_name(&tcx.hir().krate().item.attrs, sym::compiler_builtins); @@ -463,7 +461,6 @@ pub fn start_async_codegen<B: ExtraBackendMethods>( OngoingCodegen { backend, crate_name, - crate_hash, metadata, windows_subsystem, linker_info, @@ -658,15 +655,6 @@ fn produce_final_output_artifacts( // These are used in linking steps and will be cleaned up afterward. } -pub fn dump_incremental_data(_codegen_results: &CodegenResults) { - // FIXME(mw): This does not work at the moment because the situation has - // become more complicated due to incremental LTO. Now a CGU - // can have more than two caching states. - // println!("[incremental] Re-using {} out of {} modules", - // codegen_results.modules.iter().filter(|m| m.pre_existing).count(), - // codegen_results.modules.len()); -} - pub enum WorkItem<B: WriteBackendMethods> { /// Optimize a newly codegened, totally unoptimized module. Optimize(ModuleCodegen<B::Module>), @@ -1034,8 +1022,8 @@ fn start_executing_work<B: ExtraBackendMethods>( tm_factory: TargetMachineFactory(backend.target_machine_factory(tcx.sess, ol)), total_cgus, msvc_imps_needed: msvc_imps_needed(tcx), - target_pointer_width: tcx.sess.target.target.target_pointer_width.clone(), - target_arch: tcx.sess.target.target.arch.clone(), + target_pointer_width: tcx.sess.target.pointer_width, + target_arch: tcx.sess.target.arch.clone(), debuginfo: tcx.sess.opts.debuginfo, }; @@ -1175,7 +1163,7 @@ fn start_executing_work<B: ExtraBackendMethods>( // necessary. There's already optimizations in place to avoid sending work // back to the coordinator if LTO isn't requested. return thread::spawn(move || { - let max_workers = ::num_cpus::get(); + let max_workers = num_cpus::get(); let mut worker_id_counter = 0; let mut free_worker_ids = Vec::new(); let mut get_worker_id = |free_worker_ids: &mut Vec<usize>| { @@ -1531,8 +1519,6 @@ fn start_executing_work<B: ExtraBackendMethods>( } } -pub const CODEGEN_WORKER_ID: usize = usize::MAX; - /// `FatalError` is explicitly not `Send`. #[must_use] pub struct WorkerFatalError; @@ -1720,7 +1706,6 @@ impl SharedEmitterMain { pub struct OngoingCodegen<B: ExtraBackendMethods> { pub backend: B, pub crate_name: Symbol, - pub crate_hash: Svh, pub metadata: EncodedMetadata, pub windows_subsystem: Option<String>, pub linker_info: LinkerInfo, @@ -1766,7 +1751,6 @@ impl<B: ExtraBackendMethods> OngoingCodegen<B> { ( CodegenResults { crate_name: self.crate_name, - crate_hash: self.crate_hash, metadata: self.metadata, windows_subsystem: self.windows_subsystem, linker_info: self.linker_info, @@ -1881,11 +1865,11 @@ fn msvc_imps_needed(tcx: TyCtxt<'_>) -> bool { // something is wrong with commandline arg validation. assert!( !(tcx.sess.opts.cg.linker_plugin_lto.enabled() - && tcx.sess.target.target.options.is_like_windows + && tcx.sess.target.options.is_like_windows && tcx.sess.opts.cg.prefer_dynamic) ); - tcx.sess.target.target.options.is_like_windows && + tcx.sess.target.options.is_like_windows && tcx.sess.crate_types().iter().any(|ct| *ct == CrateType::Rlib) && // ThinLTO can't handle this workaround in all cases, so we don't // emit the `__imp_` symbols. Instead we make them unnecessary by disallowing diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index 8e6f8e193c0..4d937609132 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -327,7 +327,7 @@ fn cast_shift_rhs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( /// currently uses SEH-ish unwinding with DWARF info tables to the side (same as /// 64-bit MinGW) instead of "full SEH". pub fn wants_msvc_seh(sess: &Session) -> bool { - sess.target.target.options.is_like_msvc + sess.target.options.is_like_msvc } pub fn memcpy_ty<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( @@ -393,7 +393,7 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( ) -> Bx::Function { // The entry function is either `int main(void)` or `int main(int argc, char **argv)`, // depending on whether the target needs `argc` and `argv` to be passed in. - let llfty = if cx.sess().target.target.options.main_needs_argc_argv { + let llfty = if cx.sess().target.options.main_needs_argc_argv { cx.type_func(&[cx.type_int(), cx.type_ptr_to(cx.type_i8p())], cx.type_int()) } else { cx.type_func(&[], cx.type_int()) @@ -464,7 +464,7 @@ fn get_argc_argv<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( cx: &'a Bx::CodegenCx, bx: &mut Bx, ) -> (Bx::Value, Bx::Value) { - if cx.sess().target.target.options.main_needs_argc_argv { + if cx.sess().target.options.main_needs_argc_argv { // Params from native `main()` used as args for rust start function let param_argc = bx.get_param(0); let param_argv = bx.get_param(1); @@ -479,8 +479,6 @@ fn get_argc_argv<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( } } -pub const CODEGEN_WORKER_ID: usize = usize::MAX; - pub fn codegen_crate<B: ExtraBackendMethods>( backend: B, tcx: TyCtxt<'tcx>, @@ -695,7 +693,7 @@ pub fn codegen_crate<B: ExtraBackendMethods>( total_codegen_time.into_inner(), ); - ::rustc_incremental::assert_module_sources::assert_module_sources(tcx); + rustc_incremental::assert_module_sources::assert_module_sources(tcx); symbol_names_test::report_symbol_names(tcx); @@ -754,8 +752,8 @@ impl<B: ExtraBackendMethods> Drop for AbortCodegenOnDrop<B> { } fn finalize_tcx(tcx: TyCtxt<'_>) { - tcx.sess.time("assert_dep_graph", || ::rustc_incremental::assert_dep_graph(tcx)); - tcx.sess.time("serialize_dep_graph", || ::rustc_incremental::save_dep_graph(tcx)); + tcx.sess.time("assert_dep_graph", || rustc_incremental::assert_dep_graph(tcx)); + tcx.sess.time("serialize_dep_graph", || rustc_incremental::save_dep_graph(tcx)); // We assume that no queries are run past here. If there are new queries // after this point, they'll show up as "<unknown>" in self-profiling data. diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs index 45ecb793387..c4c51d146a6 100644 --- a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs +++ b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs @@ -33,7 +33,7 @@ pub fn push_debuginfo_type_name<'tcx>( ) { // When targeting MSVC, emit C++ style type names for compatibility with // .natvis visualizers (and perhaps other existing native debuggers?) - let cpp_like_names = tcx.sess.target.target.options.is_like_msvc; + let cpp_like_names = tcx.sess.target.options.is_like_msvc; match *t.kind() { ty::Bool => output.push_str("bool"), diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs index e34371ef59a..70b92b234e9 100644 --- a/compiler/rustc_codegen_ssa/src/lib.rs +++ b/compiler/rustc_codegen_ssa/src/lib.rs @@ -21,7 +21,6 @@ extern crate tracing; extern crate rustc_middle; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_data_structures::svh::Svh; use rustc_data_structures::sync::Lrc; use rustc_hir::def_id::CrateNum; use rustc_hir::LangItem; @@ -134,7 +133,6 @@ pub struct CodegenResults { pub modules: Vec<CompiledModule>, pub allocator_module: Option<CompiledModule>, pub metadata_module: Option<CompiledModule>, - pub crate_hash: Svh, pub metadata: rustc_middle::middle::cstore::EncodedMetadata, pub windows_subsystem: Option<String>, pub linker_info: back::linker::LinkerInfo, @@ -144,6 +142,7 @@ pub struct CodegenResults { pub fn provide(providers: &mut Providers) { crate::back::symbol_export::provide(providers); crate::base::provide_both(providers); + crate::target_features::provide(providers); } pub fn provide_extern(providers: &mut Providers) { diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index 703a17b200a..bec0a84cac0 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -12,9 +12,9 @@ use crate::MemFlags; use rustc_ast as ast; use rustc_hir::lang_items::LangItem; use rustc_index::vec::Idx; -use rustc_middle::mir; use rustc_middle::mir::interpret::ConstValue; use rustc_middle::mir::AssertKind; +use rustc_middle::mir::{self, SwitchTargets}; use rustc_middle::ty::layout::{FnAbiExt, HasTyCtxt}; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{self, Instance, Ty, TypeFoldable}; @@ -24,8 +24,6 @@ use rustc_target::abi::call::{ArgAbi, FnAbi, PassMode}; use rustc_target::abi::{self, LayoutOf}; use rustc_target::spec::abi::Abi; -use std::borrow::Cow; - /// Used by `FunctionCx::codegen_terminator` for emitting common patterns /// e.g., creating a basic block, calling a function, etc. struct TerminatorCodegenHelper<'tcx> { @@ -165,7 +163,7 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> { target <= self.bb && target.start_location().is_predecessor_of(self.bb.start_location(), mir) }) { - bx.sideeffect(); + bx.sideeffect(false); } } } @@ -198,42 +196,37 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { mut bx: Bx, discr: &mir::Operand<'tcx>, switch_ty: Ty<'tcx>, - values: &Cow<'tcx, [u128]>, - targets: &Vec<mir::BasicBlock>, + targets: &SwitchTargets, ) { let discr = self.codegen_operand(&mut bx, &discr); // `switch_ty` is redundant, sanity-check that. assert_eq!(discr.layout.ty, switch_ty); - if targets.len() == 2 { - // If there are two targets, emit br instead of switch - let lltrue = helper.llblock(self, targets[0]); - let llfalse = helper.llblock(self, targets[1]); + helper.maybe_sideeffect(self.mir, &mut bx, targets.all_targets()); + + let mut target_iter = targets.iter(); + if target_iter.len() == 1 { + // If there are two targets (one conditional, one fallback), emit br instead of switch + let (test_value, target) = target_iter.next().unwrap(); + let lltrue = helper.llblock(self, target); + let llfalse = helper.llblock(self, targets.otherwise()); if switch_ty == bx.tcx().types.bool { - helper.maybe_sideeffect(self.mir, &mut bx, targets.as_slice()); // Don't generate trivial icmps when switching on bool - if let [0] = values[..] { - bx.cond_br(discr.immediate(), llfalse, lltrue); - } else { - assert_eq!(&values[..], &[1]); - bx.cond_br(discr.immediate(), lltrue, llfalse); + match test_value { + 0 => bx.cond_br(discr.immediate(), llfalse, lltrue), + 1 => bx.cond_br(discr.immediate(), lltrue, llfalse), + _ => bug!(), } } else { let switch_llty = bx.immediate_backend_type(bx.layout_of(switch_ty)); - let llval = bx.const_uint_big(switch_llty, values[0]); + let llval = bx.const_uint_big(switch_llty, test_value); let cmp = bx.icmp(IntPredicate::IntEQ, discr.immediate(), llval); - helper.maybe_sideeffect(self.mir, &mut bx, targets.as_slice()); bx.cond_br(cmp, lltrue, llfalse); } } else { - helper.maybe_sideeffect(self.mir, &mut bx, targets.as_slice()); - let (otherwise, targets) = targets.split_last().unwrap(); bx.switch( discr.immediate(), - helper.llblock(self, *otherwise), - values - .iter() - .zip(targets) - .map(|(&value, target)| (value, helper.llblock(self, *target))), + helper.llblock(self, targets.otherwise()), + target_iter.map(|(value, target)| (value, helper.llblock(self, target))), ); } } @@ -879,7 +872,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let string = match ty.kind() { ty::Uint(_) => value.to_string(), ty::Int(int_ty) => { - match int_ty.normalize(bx.tcx().sess.target.ptr_width) { + match int_ty.normalize(bx.tcx().sess.target.pointer_width) { ast::IntTy::I8 => (value as i8).to_string(), ast::IntTy::I16 => (value as i16).to_string(), ast::IntTy::I32 => (value as i32).to_string(), @@ -971,12 +964,28 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } mir::TerminatorKind::Goto { target } => { - helper.maybe_sideeffect(self.mir, &mut bx, &[target]); + if bb == target { + // This is an unconditional branch back to this same basic + // block. That means we have something like a `loop {}` + // statement. Currently LLVM miscompiles this because it + // assumes forward progress. We want to prevent this in all + // cases, but that has a fairly high cost to compile times + // currently. Instead, try to handle this specific case + // which comes up commonly in practice (e.g., in embedded + // code). + // + // The `true` here means we insert side effects regardless + // of -Zinsert-sideeffect being passed on unconditional + // branching to the same basic block. + bx.sideeffect(true); + } else { + helper.maybe_sideeffect(self.mir, &mut bx, &[target]); + } helper.funclet_br(self, &mut bx, target); } - mir::TerminatorKind::SwitchInt { ref discr, switch_ty, ref values, ref targets } => { - self.codegen_switchint_terminator(helper, bx, discr, switch_ty, values, targets); + mir::TerminatorKind::SwitchInt { ref discr, switch_ty, ref targets } => { + self.codegen_switchint_terminator(helper, bx, discr, switch_ty, targets); } mir::TerminatorKind::Return => { diff --git a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs index 14f1ed59a67..2bf1ee43c73 100644 --- a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs +++ b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs @@ -580,8 +580,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // stuffs. fn int_type_width_signed(ty: Ty<'_>, tcx: TyCtxt<'_>) -> Option<(u64, bool)> { match ty.kind() { - ty::Int(t) => Some((t.bit_width().unwrap_or(u64::from(tcx.sess.target.ptr_width)), true)), - ty::Uint(t) => Some((t.bit_width().unwrap_or(u64::from(tcx.sess.target.ptr_width)), false)), + ty::Int(t) => { + Some((t.bit_width().unwrap_or(u64::from(tcx.sess.target.pointer_width)), true)) + } + ty::Uint(t) => { + Some((t.bit_width().unwrap_or(u64::from(tcx.sess.target.pointer_width)), false)) + } _ => None, } } diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs index 64d456fb7aa..bff263567bf 100644 --- a/compiler/rustc_codegen_ssa/src/mir/mod.rs +++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs @@ -153,7 +153,7 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( bx.set_personality_fn(cx.eh_personality()); } - bx.sideeffect(); + bx.sideeffect(false); let cleanup_kinds = analyze::cleanup_kinds(&mir); // Allocate a `Block` for every basic block, except diff --git a/compiler/rustc_codegen_ssa/src/mir/place.rs b/compiler/rustc_codegen_ssa/src/mir/place.rs index 91609b22615..e1cc0268723 100644 --- a/compiler/rustc_codegen_ssa/src/mir/place.rs +++ b/compiler/rustc_codegen_ssa/src/mir/place.rs @@ -346,8 +346,8 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> { .. } => { if variant_index != dataful_variant { - if bx.cx().sess().target.target.arch == "arm" - || bx.cx().sess().target.target.arch == "aarch64" + if bx.cx().sess().target.arch == "arm" + || bx.cx().sess().target.arch == "aarch64" { // FIXME(#34427): as workaround for LLVM bug on ARM, // use memset of 0 before assigning niche value. diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs index 4c61e21901b..a8d88a95f7a 100644 --- a/compiler/rustc_codegen_ssa/src/target_features.rs +++ b/compiler/rustc_codegen_ssa/src/target_features.rs @@ -1,3 +1,5 @@ +use rustc_hir::def_id::LOCAL_CRATE; +use rustc_middle::ty::query::Providers; use rustc_session::Session; use rustc_span::symbol::sym; use rustc_span::symbol::Symbol; @@ -136,7 +138,7 @@ pub fn all_known_features() -> impl Iterator<Item = (&'static str, Option<Symbol } pub fn supported_target_features(sess: &Session) -> &'static [(&'static str, Option<Symbol>)] { - match &*sess.target.target.arch { + match &*sess.target.arch { "arm" => ARM_ALLOWED_FEATURES, "aarch64" => AARCH64_ALLOWED_FEATURES, "x86" | "x86_64" => X86_ALLOWED_FEATURES, @@ -148,3 +150,16 @@ pub fn supported_target_features(sess: &Session) -> &'static [(&'static str, Opt _ => &[], } } + +pub(crate) fn provide(providers: &mut Providers) { + providers.supported_target_features = |tcx, cnum| { + assert_eq!(cnum, LOCAL_CRATE); + if tcx.sess.opts.actually_rustdoc { + // rustdoc needs to be able to document functions that use all the features, so + // whitelist them all + all_known_features().map(|(a, b)| (a.to_string(), b)).collect() + } else { + supported_target_features(tcx.sess).iter().map(|&(a, b)| (a.to_string(), b)).collect() + } + }; +} diff --git a/compiler/rustc_codegen_ssa/src/traits/backend.rs b/compiler/rustc_codegen_ssa/src/traits/backend.rs index 48c07b00894..3fb189e1984 100644 --- a/compiler/rustc_codegen_ssa/src/traits/backend.rs +++ b/compiler/rustc_codegen_ssa/src/traits/backend.rs @@ -1,10 +1,11 @@ use super::write::WriteBackendMethods; use super::CodegenObject; -use crate::ModuleCodegen; +use crate::{CodegenResults, ModuleCodegen}; use rustc_ast::expand::allocator::AllocatorKind; +use rustc_data_structures::fx::FxHashMap; use rustc_errors::ErrorReported; -use rustc_middle::dep_graph::DepGraph; +use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; use rustc_middle::middle::cstore::{EncodedMetadata, MetadataLoaderDyn}; use rustc_middle::ty::layout::{HasTyCtxt, TyAndLayout}; use rustc_middle::ty::query::Providers; @@ -80,8 +81,7 @@ pub trait CodegenBackend { &self, ongoing_codegen: Box<dyn Any>, sess: &Session, - dep_graph: &DepGraph, - ) -> Result<Box<dyn Any>, ErrorReported>; + ) -> Result<(CodegenResults, FxHashMap<WorkProductId, WorkProduct>), ErrorReported>; /// This is called on the returned `Box<dyn Any>` from `join_codegen` /// @@ -91,7 +91,7 @@ pub trait CodegenBackend { fn link( &self, sess: &Session, - codegen_results: Box<dyn Any>, + codegen_results: CodegenResults, outputs: &OutputFilenames, ) -> Result<(), ErrorReported>; } @@ -124,4 +124,5 @@ pub trait ExtraBackendMethods: CodegenBackend + WriteBackendMethods + Sized + Se opt_level: config::OptLevel, ) -> Arc<dyn Fn() -> Result<Self::TargetMachine, String> + Send + Sync>; fn target_cpu<'b>(&self, sess: &'b Session) -> &'b str; + fn tune_cpu<'b>(&self, sess: &'b Session) -> Option<&'b str>; } diff --git a/compiler/rustc_codegen_ssa/src/traits/builder.rs b/compiler/rustc_codegen_ssa/src/traits/builder.rs index 0b8289a8dd9..d5bd2780388 100644 --- a/compiler/rustc_codegen_ssa/src/traits/builder.rs +++ b/compiler/rustc_codegen_ssa/src/traits/builder.rs @@ -45,7 +45,7 @@ pub trait BuilderMethods<'a, 'tcx>: fn build_sibling_block(&self, name: &str) -> Self; fn cx(&self) -> &Self::CodegenCx; fn llbb(&self) -> Self::BasicBlock; - fn set_span(&self, span: Span); + fn set_span(&mut self, span: Span); fn position_at_end(&mut self, llbb: Self::BasicBlock); fn ret_void(&mut self); diff --git a/compiler/rustc_codegen_ssa/src/traits/intrinsic.rs b/compiler/rustc_codegen_ssa/src/traits/intrinsic.rs index ccd294d92b2..ac3c99f9c90 100644 --- a/compiler/rustc_codegen_ssa/src/traits/intrinsic.rs +++ b/compiler/rustc_codegen_ssa/src/traits/intrinsic.rs @@ -20,7 +20,9 @@ pub trait IntrinsicCallMethods<'tcx>: BackendTypes { fn abort(&mut self); fn assume(&mut self, val: Self::Value); fn expect(&mut self, cond: Self::Value, expected: bool) -> Self::Value; - fn sideeffect(&mut self); + /// Normally, sideeffect is only emitted if -Zinsert-sideeffect is passed; + /// in some cases though we want to emit it regardless. + fn sideeffect(&mut self, unconditional: bool); /// Trait method used to inject `va_start` on the "spoofed" `VaListImpl` in /// Rust defined C-variadic functions. fn va_start(&mut self, val: Self::Value) -> Self::Value; diff --git a/compiler/rustc_codegen_ssa/src/traits/mod.rs b/compiler/rustc_codegen_ssa/src/traits/mod.rs index 698ef6083e6..82518b7f0c3 100644 --- a/compiler/rustc_codegen_ssa/src/traits/mod.rs +++ b/compiler/rustc_codegen_ssa/src/traits/mod.rs @@ -85,7 +85,7 @@ impl<'tcx, T> CodegenMethods<'tcx> for T where } pub trait HasCodegen<'tcx>: - Backend<'tcx> + ::std::ops::Deref<Target = <Self as HasCodegen<'tcx>>::CodegenCx> + Backend<'tcx> + std::ops::Deref<Target = <Self as HasCodegen<'tcx>>::CodegenCx> { type CodegenCx: CodegenMethods<'tcx> + BackendTypes< diff --git a/compiler/rustc_codegen_ssa/src/traits/type_.rs b/compiler/rustc_codegen_ssa/src/traits/type_.rs index cec07b977e6..43bc0c83155 100644 --- a/compiler/rustc_codegen_ssa/src/traits/type_.rs +++ b/compiler/rustc_codegen_ssa/src/traits/type_.rs @@ -51,7 +51,7 @@ pub trait DerivedTypeMethods<'tcx>: BaseTypeMethods<'tcx> + MiscMethods<'tcx> { } fn type_int(&self) -> Self::Type { - match &self.sess().target.target.target_c_int_width[..] { + match &self.sess().target.target_c_int_width[..] { "16" => self.type_i16(), "32" => self.type_i32(), "64" => self.type_i64(), diff --git a/compiler/rustc_data_structures/src/fingerprint.rs b/compiler/rustc_data_structures/src/fingerprint.rs index aba0bbbac80..ec2f9597b18 100644 --- a/compiler/rustc_data_structures/src/fingerprint.rs +++ b/compiler/rustc_data_structures/src/fingerprint.rs @@ -71,8 +71,8 @@ impl Fingerprint { } } -impl ::std::fmt::Display for Fingerprint { - fn fmt(&self, formatter: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { +impl std::fmt::Display for Fingerprint { + fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(formatter, "{:x}-{:x}", self.0, self.1) } } diff --git a/compiler/rustc_data_structures/src/obligation_forest/mod.rs b/compiler/rustc_data_structures/src/obligation_forest/mod.rs index 7cf5202d919..a5b2df1da5d 100644 --- a/compiler/rustc_data_structures/src/obligation_forest/mod.rs +++ b/compiler/rustc_data_structures/src/obligation_forest/mod.rs @@ -129,7 +129,7 @@ pub enum ProcessResult<O, E> { struct ObligationTreeId(usize); type ObligationTreeIdGenerator = - ::std::iter::Map<::std::ops::RangeFrom<usize>, fn(usize) -> ObligationTreeId>; + std::iter::Map<std::ops::RangeFrom<usize>, fn(usize) -> ObligationTreeId>; pub struct ObligationForest<O: ForestObligation> { /// The list of obligations. In between calls to `process_obligations`, @@ -149,8 +149,8 @@ pub struct ObligationForest<O: ForestObligation> { /// comments in `process_obligation` for details. active_cache: FxHashMap<O::CacheKey, usize>, - /// A vector reused in compress(), to avoid allocating new vectors. - node_rewrites: Vec<usize>, + /// A vector reused in compress() and find_cycles_from_node(), to avoid allocating new vectors. + reused_node_vec: Vec<usize>, obligation_tree_id_generator: ObligationTreeIdGenerator, @@ -251,12 +251,22 @@ enum NodeState { Error, } +/// This trait allows us to have two different Outcome types: +/// - the normal one that does as little as possible +/// - one for tests that does some additional work and checking +pub trait OutcomeTrait { + type Error; + type Obligation; + + fn new() -> Self; + fn mark_not_stalled(&mut self); + fn is_stalled(&self) -> bool; + fn record_completed(&mut self, outcome: &Self::Obligation); + fn record_error(&mut self, error: Self::Error); +} + #[derive(Debug)] pub struct Outcome<O, E> { - /// Obligations that were completely evaluated, including all - /// (transitive) subobligations. Only computed if requested. - pub completed: Option<Vec<O>>, - /// Backtrace of obligations that were found to be in error. pub errors: Vec<Error<O, E>>, @@ -269,12 +279,29 @@ pub struct Outcome<O, E> { pub stalled: bool, } -/// Should `process_obligations` compute the `Outcome::completed` field of its -/// result? -#[derive(PartialEq)] -pub enum DoCompleted { - No, - Yes, +impl<O, E> OutcomeTrait for Outcome<O, E> { + type Error = Error<O, E>; + type Obligation = O; + + fn new() -> Self { + Self { stalled: true, errors: vec![] } + } + + fn mark_not_stalled(&mut self) { + self.stalled = false; + } + + fn is_stalled(&self) -> bool { + self.stalled + } + + fn record_completed(&mut self, _outcome: &Self::Obligation) { + // do nothing + } + + fn record_error(&mut self, error: Self::Error) { + self.errors.push(error) + } } #[derive(Debug, PartialEq, Eq)] @@ -289,7 +316,7 @@ impl<O: ForestObligation> ObligationForest<O> { nodes: vec![], done_cache: Default::default(), active_cache: Default::default(), - node_rewrites: vec![], + reused_node_vec: vec![], obligation_tree_id_generator: (0..).map(ObligationTreeId), error_cache: Default::default(), } @@ -363,8 +390,7 @@ impl<O: ForestObligation> ObligationForest<O> { .map(|(index, _node)| Error { error: error.clone(), backtrace: self.error_at(index) }) .collect(); - let successful_obligations = self.compress(DoCompleted::Yes); - assert!(successful_obligations.unwrap().is_empty()); + self.compress(|_| assert!(false)); errors } @@ -392,16 +418,12 @@ impl<O: ForestObligation> ObligationForest<O> { /// be called in a loop until `outcome.stalled` is false. /// /// This _cannot_ be unrolled (presently, at least). - pub fn process_obligations<P>( - &mut self, - processor: &mut P, - do_completed: DoCompleted, - ) -> Outcome<O, P::Error> + pub fn process_obligations<P, OUT>(&mut self, processor: &mut P) -> OUT where P: ObligationProcessor<Obligation = O>, + OUT: OutcomeTrait<Obligation = O, Error = Error<O, P::Error>>, { - let mut errors = vec![]; - let mut stalled = true; + let mut outcome = OUT::new(); // Note that the loop body can append new nodes, and those new nodes // will then be processed by subsequent iterations of the loop. @@ -429,7 +451,7 @@ impl<O: ForestObligation> ObligationForest<O> { } ProcessResult::Changed(children) => { // We are not (yet) stalled. - stalled = false; + outcome.mark_not_stalled(); node.state.set(NodeState::Success); for child in children { @@ -442,28 +464,22 @@ impl<O: ForestObligation> ObligationForest<O> { } } ProcessResult::Error(err) => { - stalled = false; - errors.push(Error { error: err, backtrace: self.error_at(index) }); + outcome.mark_not_stalled(); + outcome.record_error(Error { error: err, backtrace: self.error_at(index) }); } } index += 1; } - if stalled { - // There's no need to perform marking, cycle processing and compression when nothing - // changed. - return Outcome { - completed: if do_completed == DoCompleted::Yes { Some(vec![]) } else { None }, - errors, - stalled, - }; + // There's no need to perform marking, cycle processing and compression when nothing + // changed. + if !outcome.is_stalled() { + self.mark_successes(); + self.process_cycles(processor); + self.compress(|obl| outcome.record_completed(obl)); } - self.mark_successes(); - self.process_cycles(processor); - let completed = self.compress(do_completed); - - Outcome { completed, errors, stalled } + outcome } /// Returns a vector of obligations for `p` and all of its @@ -526,7 +542,6 @@ impl<O: ForestObligation> ObligationForest<O> { let node = &self.nodes[index]; let state = node.state.get(); if state == NodeState::Success { - node.state.set(NodeState::Waiting); // This call site is cold. self.uninlined_mark_dependents_as_waiting(node); } else { @@ -538,17 +553,18 @@ impl<O: ForestObligation> ObligationForest<O> { // This never-inlined function is for the cold call site. #[inline(never)] fn uninlined_mark_dependents_as_waiting(&self, node: &Node<O>) { + // Mark node Waiting in the cold uninlined code instead of the hot inlined + node.state.set(NodeState::Waiting); self.inlined_mark_dependents_as_waiting(node) } /// Report cycles between all `Success` nodes, and convert all `Success` /// nodes to `Done`. This must be called after `mark_successes`. - fn process_cycles<P>(&self, processor: &mut P) + fn process_cycles<P>(&mut self, processor: &mut P) where P: ObligationProcessor<Obligation = O>, { - let mut stack = vec![]; - + let mut stack = std::mem::take(&mut self.reused_node_vec); for (index, node) in self.nodes.iter().enumerate() { // For some benchmarks this state test is extremely hot. It's a win // to handle the no-op cases immediately to avoid the cost of the @@ -559,6 +575,7 @@ impl<O: ForestObligation> ObligationForest<O> { } debug_assert!(stack.is_empty()); + self.reused_node_vec = stack; } fn find_cycles_from_node<P>(&self, stack: &mut Vec<usize>, processor: &mut P, index: usize) @@ -591,13 +608,12 @@ impl<O: ForestObligation> ObligationForest<O> { /// indices and hence invalidates any outstanding indices. `process_cycles` /// must be run beforehand to remove any cycles on `Success` nodes. #[inline(never)] - fn compress(&mut self, do_completed: DoCompleted) -> Option<Vec<O>> { + fn compress(&mut self, mut outcome_cb: impl FnMut(&O)) { let orig_nodes_len = self.nodes.len(); - let mut node_rewrites: Vec<_> = std::mem::take(&mut self.node_rewrites); + let mut node_rewrites: Vec<_> = std::mem::take(&mut self.reused_node_vec); debug_assert!(node_rewrites.is_empty()); node_rewrites.extend(0..orig_nodes_len); let mut dead_nodes = 0; - let mut removed_done_obligations: Vec<O> = vec![]; // Move removable nodes to the end, preserving the order of the // remaining nodes. @@ -627,10 +643,8 @@ impl<O: ForestObligation> ObligationForest<O> { } else { self.done_cache.insert(node.obligation.as_cache_key().clone()); } - if do_completed == DoCompleted::Yes { - // Extract the success stories. - removed_done_obligations.push(node.obligation.clone()); - } + // Extract the success stories. + outcome_cb(&node.obligation); node_rewrites[index] = orig_nodes_len; dead_nodes += 1; } @@ -654,9 +668,7 @@ impl<O: ForestObligation> ObligationForest<O> { } node_rewrites.truncate(0); - self.node_rewrites = node_rewrites; - - if do_completed == DoCompleted::Yes { Some(removed_done_obligations) } else { None } + self.reused_node_vec = node_rewrites; } fn apply_rewrites(&mut self, node_rewrites: &[usize]) { diff --git a/compiler/rustc_data_structures/src/obligation_forest/tests.rs b/compiler/rustc_data_structures/src/obligation_forest/tests.rs index 01652465eea..371c62c063f 100644 --- a/compiler/rustc_data_structures/src/obligation_forest/tests.rs +++ b/compiler/rustc_data_structures/src/obligation_forest/tests.rs @@ -17,6 +17,40 @@ struct ClosureObligationProcessor<OF, BF, O, E> { marker: PhantomData<(O, E)>, } +struct TestOutcome<O, E> { + pub completed: Vec<O>, + pub errors: Vec<Error<O, E>>, + pub stalled: bool, +} + +impl<O, E> OutcomeTrait for TestOutcome<O, E> +where + O: Clone, +{ + type Error = Error<O, E>; + type Obligation = O; + + fn new() -> Self { + Self { errors: vec![], stalled: false, completed: vec![] } + } + + fn mark_not_stalled(&mut self) { + self.stalled = false; + } + + fn is_stalled(&self) -> bool { + self.stalled + } + + fn record_completed(&mut self, outcome: &Self::Obligation) { + self.completed.push(outcome.clone()) + } + + fn record_error(&mut self, error: Self::Error) { + self.errors.push(error) + } +} + #[allow(non_snake_case)] fn C<OF, BF, O>(of: OF, bf: BF) -> ClosureObligationProcessor<OF, BF, O, &'static str> where @@ -65,20 +99,17 @@ fn push_pop() { // A |-> A.1 // |-> A.2 // |-> A.3 - let Outcome { completed: ok, errors: err, .. } = forest.process_obligations( - &mut C( - |obligation| match *obligation { - "A" => ProcessResult::Changed(vec!["A.1", "A.2", "A.3"]), - "B" => ProcessResult::Error("B is for broken"), - "C" => ProcessResult::Changed(vec![]), - "A.1" | "A.2" | "A.3" => ProcessResult::Unchanged, - _ => unreachable!(), - }, - |_| {}, - ), - DoCompleted::Yes, - ); - assert_eq!(ok.unwrap(), vec!["C"]); + let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C( + |obligation| match *obligation { + "A" => ProcessResult::Changed(vec!["A.1", "A.2", "A.3"]), + "B" => ProcessResult::Error("B is for broken"), + "C" => ProcessResult::Changed(vec![]), + "A.1" | "A.2" | "A.3" => ProcessResult::Unchanged, + _ => unreachable!(), + }, + |_| {}, + )); + assert_eq!(ok, vec!["C"]); assert_eq!(err, vec![Error { error: "B is for broken", backtrace: vec!["B"] }]); // second round: two delays, one success, creating an uneven set of subtasks: @@ -88,60 +119,51 @@ fn push_pop() { // D |-> D.1 // |-> D.2 forest.register_obligation("D"); - let Outcome { completed: ok, errors: err, .. } = forest.process_obligations( - &mut C( - |obligation| match *obligation { - "A.1" => ProcessResult::Unchanged, - "A.2" => ProcessResult::Unchanged, - "A.3" => ProcessResult::Changed(vec!["A.3.i"]), - "D" => ProcessResult::Changed(vec!["D.1", "D.2"]), - "A.3.i" | "D.1" | "D.2" => ProcessResult::Unchanged, - _ => unreachable!(), - }, - |_| {}, - ), - DoCompleted::Yes, - ); - assert_eq!(ok.unwrap(), Vec::<&'static str>::new()); + let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C( + |obligation| match *obligation { + "A.1" => ProcessResult::Unchanged, + "A.2" => ProcessResult::Unchanged, + "A.3" => ProcessResult::Changed(vec!["A.3.i"]), + "D" => ProcessResult::Changed(vec!["D.1", "D.2"]), + "A.3.i" | "D.1" | "D.2" => ProcessResult::Unchanged, + _ => unreachable!(), + }, + |_| {}, + )); + assert_eq!(ok, Vec::<&'static str>::new()); assert_eq!(err, Vec::new()); // third round: ok in A.1 but trigger an error in A.2. Check that it // propagates to A, but not D.1 or D.2. // D |-> D.1 |-> D.1.i // |-> D.2 |-> D.2.i - let Outcome { completed: ok, errors: err, .. } = forest.process_obligations( - &mut C( - |obligation| match *obligation { - "A.1" => ProcessResult::Changed(vec![]), - "A.2" => ProcessResult::Error("A is for apple"), - "A.3.i" => ProcessResult::Changed(vec![]), - "D.1" => ProcessResult::Changed(vec!["D.1.i"]), - "D.2" => ProcessResult::Changed(vec!["D.2.i"]), - "D.1.i" | "D.2.i" => ProcessResult::Unchanged, - _ => unreachable!(), - }, - |_| {}, - ), - DoCompleted::Yes, - ); - let mut ok = ok.unwrap(); + let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C( + |obligation| match *obligation { + "A.1" => ProcessResult::Changed(vec![]), + "A.2" => ProcessResult::Error("A is for apple"), + "A.3.i" => ProcessResult::Changed(vec![]), + "D.1" => ProcessResult::Changed(vec!["D.1.i"]), + "D.2" => ProcessResult::Changed(vec!["D.2.i"]), + "D.1.i" | "D.2.i" => ProcessResult::Unchanged, + _ => unreachable!(), + }, + |_| {}, + )); + let mut ok = ok; ok.sort(); assert_eq!(ok, vec!["A.1", "A.3", "A.3.i"]); assert_eq!(err, vec![Error { error: "A is for apple", backtrace: vec!["A.2", "A"] }]); // fourth round: error in D.1.i - let Outcome { completed: ok, errors: err, .. } = forest.process_obligations( - &mut C( - |obligation| match *obligation { - "D.1.i" => ProcessResult::Error("D is for dumb"), - "D.2.i" => ProcessResult::Changed(vec![]), - _ => panic!("unexpected obligation {:?}", obligation), - }, - |_| {}, - ), - DoCompleted::Yes, - ); - let mut ok = ok.unwrap(); + let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C( + |obligation| match *obligation { + "D.1.i" => ProcessResult::Error("D is for dumb"), + "D.2.i" => ProcessResult::Changed(vec![]), + _ => panic!("unexpected obligation {:?}", obligation), + }, + |_| {}, + )); + let mut ok = ok; ok.sort(); assert_eq!(ok, vec!["D.2", "D.2.i"]); assert_eq!(err, vec![Error { error: "D is for dumb", backtrace: vec!["D.1.i", "D.1", "D"] }]); @@ -160,72 +182,60 @@ fn success_in_grandchildren() { let mut forest = ObligationForest::new(); forest.register_obligation("A"); - let Outcome { completed: ok, errors: err, .. } = forest.process_obligations( - &mut C( - |obligation| match *obligation { - "A" => ProcessResult::Changed(vec!["A.1", "A.2", "A.3"]), - "A.1" => ProcessResult::Changed(vec![]), - "A.2" => ProcessResult::Changed(vec!["A.2.i", "A.2.ii"]), - "A.3" => ProcessResult::Changed(vec![]), - "A.2.i" | "A.2.ii" => ProcessResult::Unchanged, - _ => unreachable!(), - }, - |_| {}, - ), - DoCompleted::Yes, - ); - let mut ok = ok.unwrap(); + let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C( + |obligation| match *obligation { + "A" => ProcessResult::Changed(vec!["A.1", "A.2", "A.3"]), + "A.1" => ProcessResult::Changed(vec![]), + "A.2" => ProcessResult::Changed(vec!["A.2.i", "A.2.ii"]), + "A.3" => ProcessResult::Changed(vec![]), + "A.2.i" | "A.2.ii" => ProcessResult::Unchanged, + _ => unreachable!(), + }, + |_| {}, + )); + let mut ok = ok; ok.sort(); assert_eq!(ok, vec!["A.1", "A.3"]); assert!(err.is_empty()); - let Outcome { completed: ok, errors: err, .. } = forest.process_obligations( - &mut C( - |obligation| match *obligation { - "A.2.i" => ProcessResult::Unchanged, - "A.2.ii" => ProcessResult::Changed(vec![]), - _ => unreachable!(), - }, - |_| {}, - ), - DoCompleted::Yes, - ); - assert_eq!(ok.unwrap(), vec!["A.2.ii"]); + let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C( + |obligation| match *obligation { + "A.2.i" => ProcessResult::Unchanged, + "A.2.ii" => ProcessResult::Changed(vec![]), + _ => unreachable!(), + }, + |_| {}, + )); + assert_eq!(ok, vec!["A.2.ii"]); assert!(err.is_empty()); - let Outcome { completed: ok, errors: err, .. } = forest.process_obligations( - &mut C( - |obligation| match *obligation { - "A.2.i" => ProcessResult::Changed(vec!["A.2.i.a"]), - "A.2.i.a" => ProcessResult::Unchanged, - _ => unreachable!(), - }, - |_| {}, - ), - DoCompleted::Yes, - ); - assert!(ok.unwrap().is_empty()); + let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C( + |obligation| match *obligation { + "A.2.i" => ProcessResult::Changed(vec!["A.2.i.a"]), + "A.2.i.a" => ProcessResult::Unchanged, + _ => unreachable!(), + }, + |_| {}, + )); + assert!(ok.is_empty()); assert!(err.is_empty()); - let Outcome { completed: ok, errors: err, .. } = forest.process_obligations( - &mut C( - |obligation| match *obligation { - "A.2.i.a" => ProcessResult::Changed(vec![]), - _ => unreachable!(), - }, - |_| {}, - ), - DoCompleted::Yes, - ); - let mut ok = ok.unwrap(); + let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C( + |obligation| match *obligation { + "A.2.i.a" => ProcessResult::Changed(vec![]), + _ => unreachable!(), + }, + |_| {}, + )); + let mut ok = ok; ok.sort(); assert_eq!(ok, vec!["A", "A.2", "A.2.i", "A.2.i.a"]); assert!(err.is_empty()); - let Outcome { completed: ok, errors: err, .. } = - forest.process_obligations(&mut C(|_| unreachable!(), |_| {}), DoCompleted::Yes); + let TestOutcome { completed: ok, errors: err, .. } = + forest.process_obligations(&mut C(|_| unreachable!(), |_| {})); - assert!(ok.unwrap().is_empty()); + assert!(ok.is_empty()); assert!(err.is_empty()); } @@ -235,18 +245,15 @@ fn to_errors_no_throw() { // yields to correct errors (and does not panic, in particular). let mut forest = ObligationForest::new(); forest.register_obligation("A"); - let Outcome { completed: ok, errors: err, .. } = forest.process_obligations( - &mut C( - |obligation| match *obligation { - "A" => ProcessResult::Changed(vec!["A.1", "A.2", "A.3"]), - "A.1" | "A.2" | "A.3" => ProcessResult::Unchanged, - _ => unreachable!(), - }, - |_| {}, - ), - DoCompleted::Yes, - ); - assert_eq!(ok.unwrap().len(), 0); + let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C( + |obligation| match *obligation { + "A" => ProcessResult::Changed(vec!["A.1", "A.2", "A.3"]), + "A.1" | "A.2" | "A.3" => ProcessResult::Unchanged, + _ => unreachable!(), + }, + |_| {}, + )); + assert_eq!(ok.len(), 0); assert_eq!(err.len(), 0); let errors = forest.to_errors(()); assert_eq!(errors[0].backtrace, vec!["A.1", "A"]); @@ -260,51 +267,42 @@ fn diamond() { // check that diamond dependencies are handled correctly let mut forest = ObligationForest::new(); forest.register_obligation("A"); - let Outcome { completed: ok, errors: err, .. } = forest.process_obligations( - &mut C( - |obligation| match *obligation { - "A" => ProcessResult::Changed(vec!["A.1", "A.2"]), - "A.1" | "A.2" => ProcessResult::Unchanged, - _ => unreachable!(), - }, - |_| {}, - ), - DoCompleted::Yes, - ); - assert_eq!(ok.unwrap().len(), 0); + let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C( + |obligation| match *obligation { + "A" => ProcessResult::Changed(vec!["A.1", "A.2"]), + "A.1" | "A.2" => ProcessResult::Unchanged, + _ => unreachable!(), + }, + |_| {}, + )); + assert_eq!(ok.len(), 0); assert_eq!(err.len(), 0); - let Outcome { completed: ok, errors: err, .. } = forest.process_obligations( - &mut C( - |obligation| match *obligation { - "A.1" => ProcessResult::Changed(vec!["D"]), - "A.2" => ProcessResult::Changed(vec!["D"]), - "D" => ProcessResult::Unchanged, - _ => unreachable!(), - }, - |_| {}, - ), - DoCompleted::Yes, - ); - assert_eq!(ok.unwrap().len(), 0); + let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C( + |obligation| match *obligation { + "A.1" => ProcessResult::Changed(vec!["D"]), + "A.2" => ProcessResult::Changed(vec!["D"]), + "D" => ProcessResult::Unchanged, + _ => unreachable!(), + }, + |_| {}, + )); + assert_eq!(ok.len(), 0); assert_eq!(err.len(), 0); let mut d_count = 0; - let Outcome { completed: ok, errors: err, .. } = forest.process_obligations( - &mut C( - |obligation| match *obligation { - "D" => { - d_count += 1; - ProcessResult::Changed(vec![]) - } - _ => unreachable!(), - }, - |_| {}, - ), - DoCompleted::Yes, - ); + let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C( + |obligation| match *obligation { + "D" => { + d_count += 1; + ProcessResult::Changed(vec![]) + } + _ => unreachable!(), + }, + |_| {}, + )); assert_eq!(d_count, 1); - let mut ok = ok.unwrap(); + let mut ok = ok; ok.sort(); assert_eq!(ok, vec!["A", "A.1", "A.2", "D"]); assert_eq!(err.len(), 0); @@ -313,51 +311,42 @@ fn diamond() { assert_eq!(errors.len(), 0); forest.register_obligation("A'"); - let Outcome { completed: ok, errors: err, .. } = forest.process_obligations( - &mut C( - |obligation| match *obligation { - "A'" => ProcessResult::Changed(vec!["A'.1", "A'.2"]), - "A'.1" | "A'.2" => ProcessResult::Unchanged, - _ => unreachable!(), - }, - |_| {}, - ), - DoCompleted::Yes, - ); - assert_eq!(ok.unwrap().len(), 0); + let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C( + |obligation| match *obligation { + "A'" => ProcessResult::Changed(vec!["A'.1", "A'.2"]), + "A'.1" | "A'.2" => ProcessResult::Unchanged, + _ => unreachable!(), + }, + |_| {}, + )); + assert_eq!(ok.len(), 0); assert_eq!(err.len(), 0); - let Outcome { completed: ok, errors: err, .. } = forest.process_obligations( - &mut C( - |obligation| match *obligation { - "A'.1" => ProcessResult::Changed(vec!["D'", "A'"]), - "A'.2" => ProcessResult::Changed(vec!["D'"]), - "D'" | "A'" => ProcessResult::Unchanged, - _ => unreachable!(), - }, - |_| {}, - ), - DoCompleted::Yes, - ); - assert_eq!(ok.unwrap().len(), 0); + let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C( + |obligation| match *obligation { + "A'.1" => ProcessResult::Changed(vec!["D'", "A'"]), + "A'.2" => ProcessResult::Changed(vec!["D'"]), + "D'" | "A'" => ProcessResult::Unchanged, + _ => unreachable!(), + }, + |_| {}, + )); + assert_eq!(ok.len(), 0); assert_eq!(err.len(), 0); let mut d_count = 0; - let Outcome { completed: ok, errors: err, .. } = forest.process_obligations( - &mut C( - |obligation| match *obligation { - "D'" => { - d_count += 1; - ProcessResult::Error("operation failed") - } - _ => unreachable!(), - }, - |_| {}, - ), - DoCompleted::Yes, - ); + let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C( + |obligation| match *obligation { + "D'" => { + d_count += 1; + ProcessResult::Error("operation failed") + } + _ => unreachable!(), + }, + |_| {}, + )); assert_eq!(d_count, 1); - assert_eq!(ok.unwrap().len(), 0); + assert_eq!(ok.len(), 0); assert_eq!( err, vec![super::Error { error: "operation failed", backtrace: vec!["D'", "A'.1", "A'"] }] @@ -375,35 +364,27 @@ fn done_dependency() { forest.register_obligation("B: Sized"); forest.register_obligation("C: Sized"); - let Outcome { completed: ok, errors: err, .. } = forest.process_obligations( - &mut C( - |obligation| match *obligation { - "A: Sized" | "B: Sized" | "C: Sized" => ProcessResult::Changed(vec![]), - _ => unreachable!(), - }, - |_| {}, - ), - DoCompleted::Yes, - ); - let mut ok = ok.unwrap(); + let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C( + |obligation| match *obligation { + "A: Sized" | "B: Sized" | "C: Sized" => ProcessResult::Changed(vec![]), + _ => unreachable!(), + }, + |_| {}, + )); + let mut ok = ok; ok.sort(); assert_eq!(ok, vec!["A: Sized", "B: Sized", "C: Sized"]); assert_eq!(err.len(), 0); forest.register_obligation("(A,B,C): Sized"); - let Outcome { completed: ok, errors: err, .. } = forest.process_obligations( - &mut C( - |obligation| match *obligation { - "(A,B,C): Sized" => { - ProcessResult::Changed(vec!["A: Sized", "B: Sized", "C: Sized"]) - } - _ => unreachable!(), - }, - |_| {}, - ), - DoCompleted::Yes, - ); - assert_eq!(ok.unwrap(), vec!["(A,B,C): Sized"]); + let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C( + |obligation| match *obligation { + "(A,B,C): Sized" => ProcessResult::Changed(vec!["A: Sized", "B: Sized", "C: Sized"]), + _ => unreachable!(), + }, + |_| {}, + )); + assert_eq!(ok, vec!["(A,B,C): Sized"]); assert_eq!(err.len(), 0); } @@ -416,64 +397,52 @@ fn orphan() { forest.register_obligation("C1"); forest.register_obligation("C2"); - let Outcome { completed: ok, errors: err, .. } = forest.process_obligations( - &mut C( - |obligation| match *obligation { - "A" => ProcessResult::Changed(vec!["D", "E"]), - "B" => ProcessResult::Unchanged, - "C1" => ProcessResult::Changed(vec![]), - "C2" => ProcessResult::Changed(vec![]), - "D" | "E" => ProcessResult::Unchanged, - _ => unreachable!(), - }, - |_| {}, - ), - DoCompleted::Yes, - ); - let mut ok = ok.unwrap(); + let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C( + |obligation| match *obligation { + "A" => ProcessResult::Changed(vec!["D", "E"]), + "B" => ProcessResult::Unchanged, + "C1" => ProcessResult::Changed(vec![]), + "C2" => ProcessResult::Changed(vec![]), + "D" | "E" => ProcessResult::Unchanged, + _ => unreachable!(), + }, + |_| {}, + )); + let mut ok = ok; ok.sort(); assert_eq!(ok, vec!["C1", "C2"]); assert_eq!(err.len(), 0); - let Outcome { completed: ok, errors: err, .. } = forest.process_obligations( - &mut C( - |obligation| match *obligation { - "D" | "E" => ProcessResult::Unchanged, - "B" => ProcessResult::Changed(vec!["D"]), - _ => unreachable!(), - }, - |_| {}, - ), - DoCompleted::Yes, - ); - assert_eq!(ok.unwrap().len(), 0); + let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C( + |obligation| match *obligation { + "D" | "E" => ProcessResult::Unchanged, + "B" => ProcessResult::Changed(vec!["D"]), + _ => unreachable!(), + }, + |_| {}, + )); + assert_eq!(ok.len(), 0); assert_eq!(err.len(), 0); - let Outcome { completed: ok, errors: err, .. } = forest.process_obligations( - &mut C( - |obligation| match *obligation { - "D" => ProcessResult::Unchanged, - "E" => ProcessResult::Error("E is for error"), - _ => unreachable!(), - }, - |_| {}, - ), - DoCompleted::Yes, - ); - assert_eq!(ok.unwrap().len(), 0); + let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C( + |obligation| match *obligation { + "D" => ProcessResult::Unchanged, + "E" => ProcessResult::Error("E is for error"), + _ => unreachable!(), + }, + |_| {}, + )); + assert_eq!(ok.len(), 0); assert_eq!(err, vec![super::Error { error: "E is for error", backtrace: vec!["E", "A"] }]); - let Outcome { completed: ok, errors: err, .. } = forest.process_obligations( - &mut C( - |obligation| match *obligation { - "D" => ProcessResult::Error("D is dead"), - _ => unreachable!(), - }, - |_| {}, - ), - DoCompleted::Yes, - ); - assert_eq!(ok.unwrap().len(), 0); + let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C( + |obligation| match *obligation { + "D" => ProcessResult::Error("D is dead"), + _ => unreachable!(), + }, + |_| {}, + )); + assert_eq!(ok.len(), 0); assert_eq!(err, vec![super::Error { error: "D is dead", backtrace: vec!["D"] }]); let errors = forest.to_errors(()); @@ -487,35 +456,29 @@ fn simultaneous_register_and_error() { forest.register_obligation("A"); forest.register_obligation("B"); - let Outcome { completed: ok, errors: err, .. } = forest.process_obligations( - &mut C( - |obligation| match *obligation { - "A" => ProcessResult::Error("An error"), - "B" => ProcessResult::Changed(vec!["A"]), - _ => unreachable!(), - }, - |_| {}, - ), - DoCompleted::Yes, - ); - assert_eq!(ok.unwrap().len(), 0); + let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C( + |obligation| match *obligation { + "A" => ProcessResult::Error("An error"), + "B" => ProcessResult::Changed(vec!["A"]), + _ => unreachable!(), + }, + |_| {}, + )); + assert_eq!(ok.len(), 0); assert_eq!(err, vec![super::Error { error: "An error", backtrace: vec!["A"] }]); let mut forest = ObligationForest::new(); forest.register_obligation("B"); forest.register_obligation("A"); - let Outcome { completed: ok, errors: err, .. } = forest.process_obligations( - &mut C( - |obligation| match *obligation { - "A" => ProcessResult::Error("An error"), - "B" => ProcessResult::Changed(vec!["A"]), - _ => unreachable!(), - }, - |_| {}, - ), - DoCompleted::Yes, - ); - assert_eq!(ok.unwrap().len(), 0); + let TestOutcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C( + |obligation| match *obligation { + "A" => ProcessResult::Error("An error"), + "B" => ProcessResult::Changed(vec!["A"]), + _ => unreachable!(), + }, + |_| {}, + )); + assert_eq!(ok.len(), 0); assert_eq!(err, vec![super::Error { error: "An error", backtrace: vec!["A"] }]); } diff --git a/compiler/rustc_data_structures/src/sorted_map.rs b/compiler/rustc_data_structures/src/sorted_map.rs index 4807380595d..9a28f8f4e21 100644 --- a/compiler/rustc_data_structures/src/sorted_map.rs +++ b/compiler/rustc_data_structures/src/sorted_map.rs @@ -93,7 +93,7 @@ impl<K: Ord, V> SortedMap<K, V> { /// Iterate over elements, sorted by key #[inline] - pub fn iter(&self) -> ::std::slice::Iter<'_, (K, V)> { + pub fn iter(&self) -> std::slice::Iter<'_, (K, V)> { self.data.iter() } @@ -134,7 +134,7 @@ impl<K: Ord, V> SortedMap<K, V> { R: RangeBounds<K>, { let (start, end) = self.range_slice_indices(range); - self.data.splice(start..end, ::std::iter::empty()); + self.data.splice(start..end, std::iter::empty()); } /// Mutate all keys with the given function `f`. This mutation must not @@ -241,7 +241,7 @@ impl<K: Ord, V> SortedMap<K, V> { impl<K: Ord, V> IntoIterator for SortedMap<K, V> { type Item = (K, V); - type IntoIter = ::std::vec::IntoIter<(K, V)>; + type IntoIter = std::vec::IntoIter<(K, V)>; fn into_iter(self) -> Self::IntoIter { self.data.into_iter() diff --git a/compiler/rustc_data_structures/src/stable_hasher.rs b/compiler/rustc_data_structures/src/stable_hasher.rs index 68875b3fbde..579eb1cb7da 100644 --- a/compiler/rustc_data_structures/src/stable_hasher.rs +++ b/compiler/rustc_data_structures/src/stable_hasher.rs @@ -20,7 +20,7 @@ pub struct StableHasher { } impl ::std::fmt::Debug for StableHasher { - fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "{:?}", self.state) } } diff --git a/compiler/rustc_data_structures/src/work_queue.rs b/compiler/rustc_data_structures/src/work_queue.rs index 0c848eb144d..cc562bc1e4d 100644 --- a/compiler/rustc_data_structures/src/work_queue.rs +++ b/compiler/rustc_data_structures/src/work_queue.rs @@ -14,12 +14,6 @@ pub struct WorkQueue<T: Idx> { } impl<T: Idx> WorkQueue<T> { - /// Creates a new work queue with all the elements from (0..len). - #[inline] - pub fn with_all(len: usize) -> Self { - WorkQueue { deque: (0..len).map(T::new).collect(), set: BitSet::new_filled(len) } - } - /// Creates a new work queue that starts empty, where elements range from (0..len). #[inline] pub fn with_none(len: usize) -> Self { diff --git a/compiler/rustc_driver/src/lib.rs b/compiler/rustc_driver/src/lib.rs index 575c2e627ed..d99e335a77a 100644 --- a/compiler/rustc_driver/src/lib.rs +++ b/compiler/rustc_driver/src/lib.rs @@ -642,7 +642,7 @@ impl RustcDefaultCalls { let codegen_results: CodegenResults = json::decode(&rlink_data).unwrap_or_else(|err| { sess.fatal(&format!("failed to decode rlink: {}", err)); }); - compiler.codegen_backend().link(&sess, Box::new(codegen_results), &outputs) + compiler.codegen_backend().link(&sess, codegen_results, &outputs) } else { sess.fatal("rlink must be a file") } @@ -670,7 +670,7 @@ impl RustcDefaultCalls { Input::File(ref ifile) => { let path = &(*ifile); let mut v = Vec::new(); - locator::list_file_metadata(&sess.target.target, path, metadata_loader, &mut v) + locator::list_file_metadata(&sess.target, path, metadata_loader, &mut v) .unwrap(); println!("{}", String::from_utf8(v).unwrap()); } @@ -724,7 +724,7 @@ impl RustcDefaultCalls { "{}", sess.target_tlib_path.as_ref().unwrap_or(&sess.host_tlib_path).dir.display() ), - TargetSpec => println!("{}", sess.target.target.to_json().pretty()), + TargetSpec => println!("{}", sess.target.to_json().pretty()), FileNames | CrateName => { let input = input.unwrap_or_else(|| { early_error(ErrorOutputType::default(), "no input file provided") @@ -1258,9 +1258,9 @@ pub fn report_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str) { // If backtraces are enabled, also print the query stack let backtrace = env::var_os("RUST_BACKTRACE").map(|x| &x != "0").unwrap_or(false); - if backtrace { - TyCtxt::try_print_query_stack(&handler); - } + let num_frames = if backtrace { None } else { Some(2) }; + + TyCtxt::try_print_query_stack(&handler, num_frames); #[cfg(windows)] unsafe { diff --git a/compiler/rustc_error_codes/src/error_codes/E0007.md b/compiler/rustc_error_codes/src/error_codes/E0007.md index 2be7870d5ae..2c22b86af92 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0007.md +++ b/compiler/rustc_error_codes/src/error_codes/E0007.md @@ -1,3 +1,5 @@ +#### Note: this error code is no longer emitted by the compiler. + This error indicates that the bindings in a match arm would require a value to be moved into more than one location, thus violating unique ownership. Code like the following is invalid as it requires the entire `Option<String>` to be @@ -6,11 +8,13 @@ inner `String` to be moved into a variable called `s`. Erroneous code example: -```compile_fail,E0007 +```compile_fail,E0382 +#![feature(bindings_after_at)] + let x = Some("s".to_string()); match x { - op_string @ Some(s) => {}, // error: cannot bind by-move with sub-bindings + op_string @ Some(s) => {}, // error: use of moved value None => {}, } ``` diff --git a/compiler/rustc_error_codes/src/error_codes/E0660.md b/compiler/rustc_error_codes/src/error_codes/E0660.md index fccd1b96f60..26d35f2620c 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0660.md +++ b/compiler/rustc_error_codes/src/error_codes/E0660.md @@ -9,4 +9,4 @@ llvm_asm!("nop" "nop"); Considering that this would be a long explanation, we instead recommend you take a look at the [`llvm_asm`] chapter of the Unstable book: -[llvm_asm]: https://doc.rust-lang.org/stable/unstable-book/library-features/llvm-asm.html +[`llvm_asm`]: https://doc.rust-lang.org/stable/unstable-book/library-features/llvm-asm.html diff --git a/compiler/rustc_error_codes/src/error_codes/E0661.md b/compiler/rustc_error_codes/src/error_codes/E0661.md index f1debee7a18..0b8ba7fbbed 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0661.md +++ b/compiler/rustc_error_codes/src/error_codes/E0661.md @@ -10,4 +10,4 @@ llvm_asm!("nop" : "r"(a)); Considering that this would be a long explanation, we instead recommend you take a look at the [`llvm_asm`] chapter of the Unstable book: -[llvm_asm]: https://doc.rust-lang.org/stable/unstable-book/library-features/llvm-asm.html +[`llvm_asm`]: https://doc.rust-lang.org/stable/unstable-book/library-features/llvm-asm.html diff --git a/compiler/rustc_error_codes/src/error_codes/E0662.md b/compiler/rustc_error_codes/src/error_codes/E0662.md index d4765f078b0..8c1bab8d041 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0662.md +++ b/compiler/rustc_error_codes/src/error_codes/E0662.md @@ -13,4 +13,4 @@ llvm_asm!("xor %eax, %eax" Considering that this would be a long explanation, we instead recommend you take a look at the [`llvm_asm`] chapter of the Unstable book: -[llvm_asm]: https://doc.rust-lang.org/stable/unstable-book/library-features/llvm-asm.html +[`llvm_asm`]: https://doc.rust-lang.org/stable/unstable-book/library-features/llvm-asm.html diff --git a/compiler/rustc_error_codes/src/error_codes/E0663.md b/compiler/rustc_error_codes/src/error_codes/E0663.md index d5a85b275db..53ffd3373a5 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0663.md +++ b/compiler/rustc_error_codes/src/error_codes/E0663.md @@ -13,4 +13,4 @@ llvm_asm!("xor %eax, %eax" Considering that this would be a long explanation, we instead recommend you take a look at the [`llvm_asm`] chapter of the Unstable book: -[llvm_asm]: https://doc.rust-lang.org/stable/unstable-book/library-features/llvm-asm.html +[`llvm_asm`]: https://doc.rust-lang.org/stable/unstable-book/library-features/llvm-asm.html diff --git a/compiler/rustc_error_codes/src/error_codes/E0664.md b/compiler/rustc_error_codes/src/error_codes/E0664.md index ce9c9491df3..f8e72cd330a 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0664.md +++ b/compiler/rustc_error_codes/src/error_codes/E0664.md @@ -13,4 +13,4 @@ llvm_asm!("mov $$0x200, %eax" Considering that this would be a long explanation, we instead recommend you take a look at the [`llvm_asm`] chapter of the Unstable book: -[llvm_asm]: https://doc.rust-lang.org/stable/unstable-book/library-features/llvm-asm.html +[`llvm_asm`]: https://doc.rust-lang.org/stable/unstable-book/library-features/llvm-asm.html diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs index 870f7b81e21..91bfc6296b1 100644 --- a/compiler/rustc_errors/src/diagnostic.rs +++ b/compiler/rustc_errors/src/diagnostic.rs @@ -121,11 +121,6 @@ impl Diagnostic { self.level == Level::Cancelled } - /// Set the sorting span. - pub fn set_sort_span(&mut self, sp: Span) { - self.sort_span = sp; - } - /// Adds a span/label to be included in the resulting snippet. /// /// This is pushed onto the [`MultiSpan`] that was created when the diagnostic @@ -535,14 +530,6 @@ impl Diagnostic { &self.message } - /// Used by a lint. Copies over all details *but* the "main - /// message". - pub fn copy_details_not_message(&mut self, from: &Diagnostic) { - self.span = from.span.clone(); - self.code = from.code.clone(); - self.children.extend(from.children.iter().cloned()) - } - /// Convenience function for internal use, clients should use one of the /// public methods above. pub fn sub( diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index 98cbf98df92..b5155f8e910 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -510,8 +510,6 @@ impl Emitter for SilentEmitter { fn emit_diagnostic(&mut self, _: &Diagnostic) {} } -/// Maximum number of lines we will print for each error; arbitrary. -pub const MAX_HIGHLIGHT_LINES: usize = 6; /// Maximum number of lines we will print for a multiline suggestion; arbitrary. /// /// This should be replaced with a more involved mechanism to output multiline suggestions that diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index f7651ca0ba6..b0e43a260e9 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -148,17 +148,6 @@ impl Annotatable { } } - pub fn map_item_or<F, G>(self, mut f: F, mut or: G) -> Annotatable - where - F: FnMut(P<ast::Item>) -> P<ast::Item>, - G: FnMut(Annotatable) -> Annotatable, - { - match self { - Annotatable::Item(i) => Annotatable::Item(f(i)), - _ => or(self), - } - } - pub fn expect_trait_item(self) -> P<ast::AssocItem> { match self { Annotatable::TraitItem(i) => i, @@ -1052,9 +1041,6 @@ impl<'a> ExtCtxt<'a> { .chain(components.iter().map(|&s| Ident::with_dummy_span(s))) .collect() } - pub fn name_of(&self, st: &str) -> Symbol { - Symbol::intern(st) - } pub fn check_unused_macros(&mut self) { self.resolver.check_unused_macros(); diff --git a/compiler/rustc_expand/src/build.rs b/compiler/rustc_expand/src/build.rs index a5a7ee6c9a3..1c9bfb902d6 100644 --- a/compiler/rustc_expand/src/build.rs +++ b/compiler/rustc_expand/src/build.rs @@ -139,24 +139,6 @@ impl<'a> ExtCtxt<'a> { ast::Lifetime { id: ast::DUMMY_NODE_ID, ident: ident.with_span_pos(span) } } - pub fn lifetime_def( - &self, - span: Span, - ident: Ident, - attrs: Vec<ast::Attribute>, - bounds: ast::GenericBounds, - ) -> ast::GenericParam { - let lifetime = self.lifetime(span, ident); - ast::GenericParam { - ident: lifetime.ident, - id: lifetime.id, - attrs: attrs.into(), - bounds, - kind: ast::GenericParamKind::Lifetime, - is_placeholder: false, - } - } - pub fn stmt_expr(&self, expr: P<ast::Expr>) -> ast::Stmt { ast::Stmt { id: ast::DUMMY_NODE_ID, @@ -465,24 +447,6 @@ impl<'a> ExtCtxt<'a> { self.pat_tuple_struct(span, path, vec![pat]) } - pub fn pat_none(&self, span: Span) -> P<ast::Pat> { - let some = self.std_path(&[sym::option, sym::Option, sym::None]); - let path = self.path_global(span, some); - self.pat_path(span, path) - } - - pub fn pat_ok(&self, span: Span, pat: P<ast::Pat>) -> P<ast::Pat> { - let some = self.std_path(&[sym::result, sym::Result, sym::Ok]); - let path = self.path_global(span, some); - self.pat_tuple_struct(span, path, vec![pat]) - } - - pub fn pat_err(&self, span: Span, pat: P<ast::Pat>) -> P<ast::Pat> { - let some = self.std_path(&[sym::result, sym::Result, sym::Err]); - let path = self.path_global(span, some); - self.pat_tuple_struct(span, path, vec![pat]) - } - pub fn arm(&self, span: Span, pat: P<ast::Pat>, expr: P<ast::Expr>) -> ast::Arm { ast::Arm { attrs: vec![], @@ -514,26 +478,6 @@ impl<'a> ExtCtxt<'a> { self.expr(span, ast::ExprKind::If(cond, self.block_expr(then), els)) } - pub fn lambda_fn_decl( - &self, - span: Span, - fn_decl: P<ast::FnDecl>, - body: P<ast::Expr>, - fn_decl_span: Span, - ) -> P<ast::Expr> { - self.expr( - span, - ast::ExprKind::Closure( - ast::CaptureBy::Ref, - ast::Async::No, - ast::Movability::Movable, - fn_decl, - body, - fn_decl_span, - ), - ) - } - pub fn lambda(&self, span: Span, ids: Vec<Ident>, body: P<ast::Expr>) -> P<ast::Expr> { let fn_decl = self.fn_decl( ids.iter().map(|id| self.param(span, *id, self.ty(span, ast::TyKind::Infer))).collect(), @@ -610,47 +554,6 @@ impl<'a> ExtCtxt<'a> { }) } - pub fn variant(&self, span: Span, ident: Ident, tys: Vec<P<ast::Ty>>) -> ast::Variant { - let vis_span = span.shrink_to_lo(); - let fields: Vec<_> = tys - .into_iter() - .map(|ty| ast::StructField { - span: ty.span, - ty, - ident: None, - vis: ast::Visibility { - span: vis_span, - kind: ast::VisibilityKind::Inherited, - tokens: None, - }, - attrs: Vec::new(), - id: ast::DUMMY_NODE_ID, - is_placeholder: false, - }) - .collect(); - - let vdata = if fields.is_empty() { - ast::VariantData::Unit(ast::DUMMY_NODE_ID) - } else { - ast::VariantData::Tuple(fields, ast::DUMMY_NODE_ID) - }; - - ast::Variant { - attrs: Vec::new(), - data: vdata, - disr_expr: None, - id: ast::DUMMY_NODE_ID, - ident, - vis: ast::Visibility { - span: vis_span, - kind: ast::VisibilityKind::Inherited, - tokens: None, - }, - span, - is_placeholder: false, - } - } - pub fn item_static( &self, span: Span, diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs index e2492efb9d7..4401ec0a04e 100644 --- a/compiler/rustc_feature/src/accepted.rs +++ b/compiler/rustc_feature/src/accepted.rs @@ -270,6 +270,9 @@ declare_features! ( (accepted, track_caller, "1.46.0", Some(47809), None), /// Allows `#[doc(alias = "...")]`. (accepted, doc_alias, "1.48.0", Some(50146), None), + /// Allows patterns with concurrent by-move and by-ref bindings. + /// For example, you can write `Foo(a, ref b)` where `a` is by-move and `b` is by-ref. + (accepted, move_ref_pattern, "1.48.0", Some(68354), None), // ------------------------------------------------------------------------- // feature-group-end: accepted features diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index 8a7f0517e73..c13fe2ae280 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -526,10 +526,6 @@ declare_features! ( /// For example, you can write `x @ Some(y)`. (active, bindings_after_at, "1.41.0", Some(65490), None), - /// Allows patterns with concurrent by-move and by-ref bindings. - /// For example, you can write `Foo(a, ref b)` where `a` is by-move and `b` is by-ref. - (active, move_ref_pattern, "1.42.0", Some(68354), None), - /// Allows `impl const Trait for T` syntax. (active, const_trait_impl, "1.42.0", Some(67792), None), @@ -602,6 +598,9 @@ declare_features! ( /// Allows `#[instruction_set(_)]` attribute (active, isa_attribute, "1.48.0", Some(74727), None), + /// Allow anonymous constants from an inline `const` block + (active, inline_const, "1.49.0", Some(76001), None), + // ------------------------------------------------------------------------- // feature-group-end: actual feature gates // ------------------------------------------------------------------------- @@ -622,6 +621,7 @@ pub const INCOMPLETE_FEATURES: &[Symbol] = &[ sym::const_trait_bound_opt_out, sym::lazy_normalization_consts, sym::specialization, + sym::inline_const, ]; /// Some features are not allowed to be used together at the same time, if diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 527a49b0538..83aa1f62106 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -598,7 +598,7 @@ pub fn is_builtin_attr_name(name: Symbol) -> bool { BUILTIN_ATTRIBUTE_MAP.get(&name).is_some() } -pub static BUILTIN_ATTRIBUTE_MAP: SyncLazy<FxHashMap<Symbol, &'static BuiltinAttribute>> = +pub static BUILTIN_ATTRIBUTE_MAP: SyncLazy<FxHashMap<Symbol, &BuiltinAttribute>> = SyncLazy::new(|| { let mut map = FxHashMap::default(); for attr in BUILTIN_ATTRIBUTES.iter() { diff --git a/compiler/rustc_fs_util/src/lib.rs b/compiler/rustc_fs_util/src/lib.rs index 289b9f30c3b..7742961e65d 100644 --- a/compiler/rustc_fs_util/src/lib.rs +++ b/compiler/rustc_fs_util/src/lib.rs @@ -75,33 +75,6 @@ pub fn link_or_copy<P: AsRef<Path>, Q: AsRef<Path>>(p: P, q: Q) -> io::Result<Li } } -#[derive(Debug)] -pub enum RenameOrCopyRemove { - Rename, - CopyRemove, -} - -/// Rename `p` into `q`, preferring to use `rename` if possible. -/// If `rename` fails (rename may fail for reasons such as crossing -/// filesystem), fallback to copy & remove -pub fn rename_or_copy_remove<P: AsRef<Path>, Q: AsRef<Path>>( - p: P, - q: Q, -) -> io::Result<RenameOrCopyRemove> { - let p = p.as_ref(); - let q = q.as_ref(); - match fs::rename(p, q) { - Ok(()) => Ok(RenameOrCopyRemove::Rename), - Err(_) => match fs::copy(p, q) { - Ok(_) => { - fs::remove_file(p)?; - Ok(RenameOrCopyRemove::CopyRemove) - } - Err(e) => Err(e), - }, - } -} - #[cfg(unix)] pub fn path_to_c_string(p: &Path) -> CString { use std::ffi::OsStr; diff --git a/compiler/rustc_hir/src/definitions.rs b/compiler/rustc_hir/src/definitions.rs index afefde07f92..3f109376a3e 100644 --- a/compiler/rustc_hir/src/definitions.rs +++ b/compiler/rustc_hir/src/definitions.rs @@ -118,7 +118,7 @@ impl DefKey { let DisambiguatedDefPathData { ref data, disambiguator } = self.disambiguated_data; - ::std::mem::discriminant(data).hash(&mut hasher); + std::mem::discriminant(data).hash(&mut hasher); if let Some(name) = data.get_opt_name() { // Get a stable hash by considering the symbol chars rather than // the symbol index. @@ -188,10 +188,6 @@ pub struct DefPath { } impl DefPath { - pub fn is_local(&self) -> bool { - self.krate == LOCAL_CRATE - } - pub fn make<FN>(krate: CrateNum, start_index: DefIndex, mut get_key: FN) -> DefPath where FN: FnMut(DefIndex) -> DefKey, diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 636f67a77c8..0ebed5c3480 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -3,7 +3,6 @@ use crate::def_id::DefId; crate use crate::hir_id::HirId; use crate::{itemlikevisit, LangItem}; -use rustc_ast::node_id::NodeMap; use rustc_ast::util::parser::ExprPrecedence; use rustc_ast::{self as ast, CrateSugar, LlvmAsmDialect}; use rustc_ast::{AttrVec, Attribute, FloatTy, IntTy, Label, LitKind, StrStyle, UintTy}; @@ -306,10 +305,6 @@ impl GenericArgs<'_> { Self { args: &[], bindings: &[], parenthesized: false } } - pub fn is_empty(&self) -> bool { - self.args.is_empty() && self.bindings.is_empty() && !self.parenthesized - } - pub fn inputs(&self) -> &[Ty<'_>] { if self.parenthesized { for arg in self.args { @@ -467,23 +462,6 @@ impl Generics<'hir> { } } - pub fn own_counts(&self) -> GenericParamCount { - // We could cache this as a property of `GenericParamCount`, but - // the aim is to refactor this away entirely eventually and the - // presence of this method will be a constant reminder. - let mut own_counts: GenericParamCount = Default::default(); - - for param in self.params { - match param.kind { - GenericParamKind::Lifetime { .. } => own_counts.lifetimes += 1, - GenericParamKind::Type { .. } => own_counts.types += 1, - GenericParamKind::Const { .. } => own_counts.consts += 1, - }; - } - - own_counts - } - pub fn get_named(&self, name: Symbol) -> Option<&GenericParam<'_>> { for param in self.params { if name == param.name.ident().name { @@ -1383,6 +1361,7 @@ impl Expr<'_> { pub fn precedence(&self) -> ExprPrecedence { match self.kind { ExprKind::Box(_) => ExprPrecedence::Box, + ExprKind::ConstBlock(_) => ExprPrecedence::ConstBlock, ExprKind::Array(_) => ExprPrecedence::Array, ExprKind::Call(..) => ExprPrecedence::Call, ExprKind::MethodCall(..) => ExprPrecedence::MethodCall, @@ -1468,6 +1447,7 @@ impl Expr<'_> { | ExprKind::LlvmInlineAsm(..) | ExprKind::AssignOp(..) | ExprKind::Lit(_) + | ExprKind::ConstBlock(..) | ExprKind::Unary(..) | ExprKind::Box(..) | ExprKind::AddrOf(..) @@ -1523,6 +1503,8 @@ pub fn is_range_literal(expr: &Expr<'_>) -> bool { pub enum ExprKind<'hir> { /// A `box x` expression. Box(&'hir Expr<'hir>), + /// Allow anonymous constants from an inline `const` block + ConstBlock(AnonConst), /// An array (e.g., `[a, b, c, d]`). Array(&'hir [Expr<'hir>]), /// A function call. @@ -2679,8 +2661,6 @@ pub struct Upvar { pub span: Span, } -pub type CaptureModeMap = NodeMap<CaptureBy>; - // The TraitCandidate's import_ids is empty if the trait is defined in the same module, and // has length > 0 if the trait is found through an chain of imports, starting with the // import/use statement in the scope where the trait is used. diff --git a/compiler/rustc_hir/src/hir_id.rs b/compiler/rustc_hir/src/hir_id.rs index fea850c12d9..cc8ac4cf5be 100644 --- a/compiler/rustc_hir/src/hir_id.rs +++ b/compiler/rustc_hir/src/hir_id.rs @@ -45,5 +45,3 @@ pub const CRATE_HIR_ID: HirId = HirId { owner: LocalDefId { local_def_index: CRATE_DEF_INDEX }, local_id: ItemLocalId::from_u32(0), }; - -pub const DUMMY_ITEM_LOCAL_ID: ItemLocalId = ItemLocalId::MAX; diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 820d664c07d..35615af0fc7 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -1068,6 +1068,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>) ExprKind::Array(subexpressions) => { walk_list!(visitor, visit_expr, subexpressions); } + ExprKind::ConstBlock(ref anon_const) => visitor.visit_anon_const(anon_const), ExprKind::Repeat(ref element, ref count) => { visitor.visit_expr(element); visitor.visit_anon_const(count) diff --git a/compiler/rustc_hir/src/pat_util.rs b/compiler/rustc_hir/src/pat_util.rs index 2f1b5da8e13..c05d3e44423 100644 --- a/compiler/rustc_hir/src/pat_util.rs +++ b/compiler/rustc_hir/src/pat_util.rs @@ -58,25 +58,6 @@ impl<T: ExactSizeIterator> EnumerateAndAdjustIterator for T { } impl hir::Pat<'_> { - pub fn is_refutable(&self) -> bool { - match self.kind { - PatKind::Lit(_) - | PatKind::Range(..) - | PatKind::Path(hir::QPath::Resolved(Some(..), _) | hir::QPath::TypeRelative(..)) => { - true - } - - PatKind::Path(hir::QPath::Resolved(_, ref path)) - | PatKind::TupleStruct(hir::QPath::Resolved(_, ref path), ..) - | PatKind::Struct(hir::QPath::Resolved(_, ref path), ..) => match path.res { - Res::Def(DefKind::Variant, _) => true, - _ => false, - }, - PatKind::Slice(..) => true, - _ => false, - } - } - /// Call `f` on every "binding" in a pattern, e.g., on `a` in /// `match foo() { Some(a) => (), None => () }` pub fn each_binding(&self, mut f: impl FnMut(hir::BindingAnnotation, HirId, Span, Ident)) { @@ -117,15 +98,6 @@ impl hir::Pat<'_> { }) } - /// Checks if the pattern contains any patterns that bind something to - /// an ident or wildcard, e.g., `foo`, or `Foo(_)`, `foo @ Bar(..)`, - pub fn contains_bindings_or_wild(&self) -> bool { - self.satisfies(|p| match p.kind { - PatKind::Binding(..) | PatKind::Wild => true, - _ => false, - }) - } - /// Checks if the pattern satisfies the given predicate on some sub-pattern. fn satisfies(&self, pred: impl Fn(&hir::Pat<'_>) -> bool) -> bool { let mut satisfies = false; diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index f6e4b1fb418..4686b4989ae 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -44,9 +44,6 @@ pub trait PpAnn { fn nested(&self, _state: &mut State<'_>, _nested: Nested) {} fn pre(&self, _state: &mut State<'_>, _node: AnnNode<'_>) {} fn post(&self, _state: &mut State<'_>, _node: AnnNode<'_>) {} - fn try_fetch_item(&self, _: hir::HirId) -> Option<&hir::Item<'_>> { - None - } } pub struct NoAnn; @@ -54,9 +51,6 @@ impl PpAnn for NoAnn {} pub const NO_ANN: &dyn PpAnn = &NoAnn; impl PpAnn for hir::Crate<'_> { - fn try_fetch_item(&self, item: hir::HirId) -> Option<&hir::Item<'_>> { - Some(self.item(item)) - } fn nested(&self, state: &mut State<'_>, nested: Nested) { match nested { Nested::Item(id) => state.print_item(self.item(id.id)), @@ -141,6 +135,9 @@ impl std::ops::DerefMut for State<'_> { } impl<'a> PrintState<'a> for State<'a> { + fn insert_extra_parens(&self) -> bool { + true + } fn comments(&mut self) -> &mut Option<Comments<'a>> { &mut self.comments } @@ -1138,6 +1135,15 @@ impl<'a> State<'a> { self.end() } + fn print_expr_anon_const(&mut self, anon_const: &hir::AnonConst) { + self.ibox(INDENT_UNIT); + self.s.word_space("const"); + self.s.word("{"); + self.print_anon_const(anon_const); + self.s.word("}"); + self.end() + } + fn print_expr_repeat(&mut self, element: &hir::Expr<'_>, count: &hir::AnonConst) { self.ibox(INDENT_UNIT); self.s.word("["); @@ -1290,6 +1296,9 @@ impl<'a> State<'a> { hir::ExprKind::Array(ref exprs) => { self.print_expr_vec(exprs); } + hir::ExprKind::ConstBlock(ref anon_const) => { + self.print_expr_anon_const(anon_const); + } hir::ExprKind::Repeat(ref element, ref count) => { self.print_expr_repeat(&element, count); } diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 9742f5e2346..ff7bbf0562f 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -113,13 +113,6 @@ impl Default for RegionckMode { } impl RegionckMode { - pub fn suppressed(self) -> bool { - match self { - Self::Solve => false, - Self::Erase { suppress_errors } => suppress_errors, - } - } - /// Indicates that the MIR borrowck will repeat these region /// checks, so we should ignore errors if NLL is (unconditionally) /// enabled. @@ -420,15 +413,6 @@ pub enum SubregionOrigin<'tcx> { #[cfg(target_arch = "x86_64")] static_assert_size!(SubregionOrigin<'_>, 32); -/// Places that type/region parameters can appear. -#[derive(Clone, Copy, Debug)] -pub enum ParameterOrigin { - Path, // foo::bar - MethodCall, // foo.bar() <-- parameters on impl providing bar() - OverloadedOperator, // a + b when overloaded - OverloadedDeref, // *a when overloaded -} - /// Times when we replace late-bound regions with variables: #[derive(Clone, Copy, Debug)] pub enum LateBoundRegionConversionTime { @@ -508,21 +492,6 @@ pub enum NLLRegionVariableOrigin { }, } -impl NLLRegionVariableOrigin { - pub fn is_universal(self) -> bool { - match self { - NLLRegionVariableOrigin::FreeRegion => true, - NLLRegionVariableOrigin::Placeholder(..) => true, - NLLRegionVariableOrigin::Existential { .. } => false, - NLLRegionVariableOrigin::RootEmptyRegion => false, - } - } - - pub fn is_existential(self) -> bool { - !self.is_universal() - } -} - // FIXME(eddyb) investigate overlap between this and `TyOrConstInferVar`. #[derive(Copy, Clone, Debug)] pub enum FixupError<'tcx> { diff --git a/compiler/rustc_infer/src/infer/nll_relate/mod.rs b/compiler/rustc_infer/src/infer/nll_relate/mod.rs index 839891f322c..abdd6edea90 100644 --- a/compiler/rustc_infer/src/infer/nll_relate/mod.rs +++ b/compiler/rustc_infer/src/infer/nll_relate/mod.rs @@ -28,7 +28,6 @@ use rustc_data_structures::fx::FxHashMap; use rustc_middle::ty::error::TypeError; use rustc_middle::ty::fold::{TypeFoldable, TypeVisitor}; use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation}; -use rustc_middle::ty::subst::GenericArg; use rustc_middle::ty::{self, InferConst, Ty, TyCtxt}; use std::fmt::Debug; @@ -119,12 +118,6 @@ pub trait TypeRelatingDelegate<'tcx> { fn forbid_inference_vars() -> bool; } -#[derive(Clone, Debug)] -struct ScopesAndKind<'tcx> { - scopes: Vec<BoundRegionScope<'tcx>>, - kind: GenericArg<'tcx>, -} - #[derive(Clone, Debug, Default)] struct BoundRegionScope<'tcx> { map: FxHashMap<ty::BoundRegion, ty::Region<'tcx>>, @@ -341,7 +334,7 @@ where // been fully instantiated and hence the set of scopes we have // doesn't matter -- just to be sure, put an empty vector // in there. - let old_a_scopes = ::std::mem::take(pair.vid_scopes(self)); + let old_a_scopes = std::mem::take(pair.vid_scopes(self)); // Relate the generalized kind to the original one. let result = pair.relate_generalized_ty(self, generalized_ty); @@ -643,7 +636,7 @@ where if let (Some(a), Some(b)) = (a.no_bound_vars(), b.no_bound_vars()) { // Fast path for the common case. self.relate(a, b)?; - return Ok(ty::Binder::bind(a)); + return Ok(ty::Binder::dummy(a)); } if self.ambient_covariance() { @@ -680,7 +673,7 @@ where // itself occurs. Note that `'b` and `'c` must both // include P. At the point, the call works because of // subtyping (i.e., `&'b u32 <: &{P} u32`). - let variance = ::std::mem::replace(&mut self.ambient_variance, ty::Variance::Covariant); + let variance = std::mem::replace(&mut self.ambient_variance, ty::Variance::Covariant); self.relate(a.skip_binder(), b.skip_binder())?; @@ -709,7 +702,7 @@ where // Reset ambient variance to contravariance. See the // covariant case above for an explanation. let variance = - ::std::mem::replace(&mut self.ambient_variance, ty::Variance::Contravariant); + std::mem::replace(&mut self.ambient_variance, ty::Variance::Contravariant); self.relate(a.skip_binder(), b.skip_binder())?; diff --git a/compiler/rustc_infer/src/infer/outlives/obligations.rs b/compiler/rustc_infer/src/infer/outlives/obligations.rs index 2851da89ab2..eb1a7806256 100644 --- a/compiler/rustc_infer/src/infer/outlives/obligations.rs +++ b/compiler/rustc_infer/src/infer/outlives/obligations.rs @@ -110,7 +110,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { /// Trait queries just want to pass back type obligations "as is" pub fn take_registered_region_obligations(&self) -> Vec<(hir::HirId, RegionObligation<'tcx>)> { - ::std::mem::take(&mut self.inner.borrow_mut().region_obligations) + std::mem::take(&mut self.inner.borrow_mut().region_obligations) } /// Process the region obligations that must be proven (during diff --git a/compiler/rustc_infer/src/traits/mod.rs b/compiler/rustc_infer/src/traits/mod.rs index a3c4920fa8a..aaf5e958c26 100644 --- a/compiler/rustc_infer/src/traits/mod.rs +++ b/compiler/rustc_infer/src/traits/mod.rs @@ -59,9 +59,7 @@ pub type TraitObligation<'tcx> = Obligation<'tcx, ty::PolyTraitPredicate<'tcx>>; #[cfg(target_arch = "x86_64")] static_assert_size!(PredicateObligation<'_>, 32); -pub type Obligations<'tcx, O> = Vec<Obligation<'tcx, O>>; pub type PredicateObligations<'tcx> = Vec<PredicateObligation<'tcx>>; -pub type TraitObligations<'tcx> = Vec<TraitObligation<'tcx>>; pub type Selection<'tcx> = ImplSource<'tcx, PredicateObligation<'tcx>>; diff --git a/compiler/rustc_infer/src/traits/util.rs b/compiler/rustc_infer/src/traits/util.rs index 1b7269706a7..f6ef9840788 100644 --- a/compiler/rustc_infer/src/traits/util.rs +++ b/compiler/rustc_infer/src/traits/util.rs @@ -126,14 +126,15 @@ impl Elaborator<'tcx> { fn elaborate(&mut self, obligation: &PredicateObligation<'tcx>) { let tcx = self.visited.tcx; - match obligation.predicate.skip_binders() { + let bound_predicate = obligation.predicate.bound_atom(); + match bound_predicate.skip_binder() { ty::PredicateAtom::Trait(data, _) => { // Get predicates declared on the trait. let predicates = tcx.super_predicates_of(data.def_id()); let obligations = predicates.predicates.iter().map(|&(pred, _)| { predicate_obligation( - pred.subst_supertrait(tcx, &ty::Binder::bind(data.trait_ref)), + pred.subst_supertrait(tcx, &bound_predicate.rebind(data.trait_ref)), obligation.param_env, obligation.cause.clone(), ) diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs index 8b82217a91a..1de7350a3e2 100644 --- a/compiler/rustc_interface/src/queries.rs +++ b/compiler/rustc_interface/src/queries.rs @@ -3,6 +3,7 @@ use crate::passes::{self, BoxedResolver, QueryContext}; use rustc_ast as ast; use rustc_codegen_ssa::traits::CodegenBackend; +use rustc_data_structures::svh::Svh; use rustc_data_structures::sync::{Lrc, OnceCell, WorkerLocal}; use rustc_errors::ErrorReported; use rustc_hir::def_id::LOCAL_CRATE; @@ -13,7 +14,8 @@ use rustc_middle::arena::Arena; use rustc_middle::dep_graph::DepGraph; use rustc_middle::ty::steal::Steal; use rustc_middle::ty::{GlobalCtxt, ResolverOutputs, TyCtxt}; -use rustc_session::config::{OutputFilenames, OutputType}; +use rustc_serialize::json; +use rustc_session::config::{self, OutputFilenames, OutputType}; use rustc_session::{output::find_crate_name, Session}; use rustc_span::symbol::sym; use std::any::Any; @@ -331,6 +333,7 @@ impl<'tcx> Queries<'tcx> { pub fn linker(&'tcx self) -> Result<Linker> { let dep_graph = self.dep_graph()?; let prepare_outputs = self.prepare_outputs()?; + let crate_hash = self.global_ctxt()?.peek_mut().enter(|tcx| tcx.crate_hash(LOCAL_CRATE)); let ongoing_codegen = self.ongoing_codegen()?; let sess = self.session().clone(); @@ -340,6 +343,7 @@ impl<'tcx> Queries<'tcx> { sess, dep_graph: dep_graph.peek().clone(), prepare_outputs: prepare_outputs.take(), + crate_hash, ongoing_codegen: ongoing_codegen.take(), codegen_backend, }) @@ -350,18 +354,31 @@ pub struct Linker { sess: Lrc<Session>, dep_graph: DepGraph, prepare_outputs: OutputFilenames, + crate_hash: Svh, ongoing_codegen: Box<dyn Any>, codegen_backend: Lrc<Box<dyn CodegenBackend>>, } impl Linker { pub fn link(self) -> Result<()> { - let codegen_results = - self.codegen_backend.join_codegen(self.ongoing_codegen, &self.sess, &self.dep_graph)?; - let prof = self.sess.prof.clone(); + let (codegen_results, work_products) = + self.codegen_backend.join_codegen(self.ongoing_codegen, &self.sess)?; + + self.sess.compile_status()?; + + let sess = &self.sess; let dep_graph = self.dep_graph; + sess.time("serialize_work_products", || { + rustc_incremental::save_work_product_index(&sess, &dep_graph, work_products) + }); + + let prof = self.sess.prof.clone(); prof.generic_activity("drop_dep_graph").run(move || drop(dep_graph)); + // Now that we won't touch anything in the incremental compilation directory + // any more, we can finalize it (which involves renaming it) + rustc_incremental::finalize_session_directory(&self.sess, self.crate_hash); + if !self .sess .opts @@ -371,6 +388,19 @@ impl Linker { { return Ok(()); } + + if sess.opts.debugging_opts.no_link { + // FIXME: use a binary format to encode the `.rlink` file + let rlink_data = json::encode(&codegen_results).map_err(|err| { + sess.fatal(&format!("failed to encode rlink: {}", err)); + })?; + let rlink_file = self.prepare_outputs.with_extension(config::RLINK_EXT); + std::fs::write(&rlink_file, rlink_data).map_err(|err| { + sess.fatal(&format!("failed to write file {}: {}", rlink_file.display(), err)); + })?; + return Ok(()); + } + self.codegen_backend.link(&self.sess, codegen_results, &self.prepare_outputs) } } diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index 07ce9d0cd94..6553d0ecfdb 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -585,6 +585,7 @@ fn test_debugging_options_tracking_hash() { tracked!(symbol_mangling_version, SymbolManglingVersion::V0); tracked!(teach, true); tracked!(thinlto, Some(true)); + tracked!(tune_cpu, Some(String::from("abc"))); tracked!(tls_model, Some(TlsModel::GeneralDynamic)); tracked!(treat_err_as_bug, Some(1)); tracked!(unleash_the_miri_inside_of_you, true); diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index abd899e8db4..a964950f1df 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -968,7 +968,7 @@ fn warn_if_doc(cx: &EarlyContext<'_>, node_span: Span, node_kind: &str, attrs: & while let Some(attr) = attrs.next() { if attr.is_doc_comment() { sugared_span = - Some(sugared_span.map_or_else(|| attr.span, |span| span.with_hi(attr.span.hi()))); + Some(sugared_span.map_or(attr.span, |span| span.with_hi(attr.span.hi()))); } if attrs.peek().map(|next_attr| next_attr.is_doc_comment()).unwrap_or_default() { @@ -2288,12 +2288,20 @@ impl EarlyLintPass for IncompleteFeatures { n, n, )); } + if HAS_MIN_FEATURES.contains(&name) { + builder.help(&format!( + "consider using `min_{}` instead, which is more stable and complete", + name, + )); + } builder.emit(); }) }); } } +const HAS_MIN_FEATURES: &[Symbol] = &[sym::const_generics, sym::specialization]; + declare_lint! { /// The `invalid_value` lint detects creating a value that is not valid, /// such as a NULL reference. diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index 7a3035e5b46..48270eb59a0 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -711,10 +711,6 @@ impl<'tcx> LateContext<'tcx> { } } - pub fn current_lint_root(&self) -> hir::HirId { - self.last_node_with_lint_attrs - } - /// Check if a `DefId`'s path matches the given absolute type path usage. /// /// Anonymous scopes such as `extern` imports are matched with `kw::Invalid`; diff --git a/compiler/rustc_lint/src/early.rs b/compiler/rustc_lint/src/early.rs index 998676d44d2..4c8baa49edf 100644 --- a/compiler/rustc_lint/src/early.rs +++ b/compiler/rustc_lint/src/early.rs @@ -195,6 +195,11 @@ impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T> run_early_pass!(self, check_expr_post, e); } + fn visit_generic_arg(&mut self, arg: &'a ast::GenericArg) { + run_early_pass!(self, check_generic_arg, arg); + ast_visit::walk_generic_arg(self, arg); + } + fn visit_generic_param(&mut self, param: &'a ast::GenericParam) { run_early_pass!(self, check_generic_param, param); ast_visit::walk_generic_param(self, param); diff --git a/compiler/rustc_lint/src/passes.rs b/compiler/rustc_lint/src/passes.rs index 159286c13a4..828f283d2a9 100644 --- a/compiler/rustc_lint/src/passes.rs +++ b/compiler/rustc_lint/src/passes.rs @@ -33,6 +33,7 @@ macro_rules! late_lint_methods { fn check_expr(a: &$hir hir::Expr<$hir>); fn check_expr_post(a: &$hir hir::Expr<$hir>); fn check_ty(a: &$hir hir::Ty<$hir>); + fn check_generic_arg(a: &$hir hir::GenericArg<$hir>); fn check_generic_param(a: &$hir hir::GenericParam<$hir>); fn check_generics(a: &$hir hir::Generics<$hir>); fn check_where_predicate(a: &$hir hir::WherePredicate<$hir>); @@ -176,6 +177,7 @@ macro_rules! early_lint_methods { fn check_expr(a: &ast::Expr); fn check_expr_post(a: &ast::Expr); fn check_ty(a: &ast::Ty); + fn check_generic_arg(a: &ast::GenericArg); fn check_generic_param(a: &ast::GenericParam); fn check_generics(a: &ast::Generics); fn check_where_predicate(a: &ast::WherePredicate); diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index 9925444b869..af14f28ff9f 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -304,7 +304,7 @@ fn lint_int_literal<'tcx>( t: ast::IntTy, v: u128, ) { - let int_type = t.normalize(cx.sess().target.ptr_width); + let int_type = t.normalize(cx.sess().target.pointer_width); let (min, max) = int_ty_range(int_type); let max = max as u128; let negative = type_limits.negated_expr_id == Some(e.hir_id); @@ -352,7 +352,7 @@ fn lint_uint_literal<'tcx>( lit: &hir::Lit, t: ast::UintTy, ) { - let uint_type = t.normalize(cx.sess().target.ptr_width); + let uint_type = t.normalize(cx.sess().target.pointer_width); let (min, max) = uint_ty_range(uint_type); let lit_val: u128 = match lit.node { // _v is u8, within range by definition diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index 3abd9a6325d..4bff7f317cb 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -839,10 +839,6 @@ impl EarlyLintPass for UnusedParens { } } - fn check_anon_const(&mut self, cx: &EarlyContext<'_>, c: &ast::AnonConst) { - self.check_unused_delims_expr(cx, &c.value, UnusedDelimsCtx::AnonConst, false, None, None); - } - fn check_stmt(&mut self, cx: &EarlyContext<'_>, s: &ast::Stmt) { if let StmtKind::Local(ref local) = s.kind { self.check_unused_parens_pat(cx, &local.pat, false, false); @@ -965,13 +961,6 @@ impl UnusedDelimLint for UnusedBraces { if !Self::is_expr_delims_necessary(expr, followed_by_block) && (ctx != UnusedDelimsCtx::AnonConst || matches!(expr.kind, ast::ExprKind::Lit(_))) - // array length expressions are checked during `check_anon_const` and `check_ty`, - // once as `ArrayLenExpr` and once as `AnonConst`. - // - // As we do not want to lint this twice, we do not emit an error for - // `ArrayLenExpr` if `AnonConst` would do the same. - && (ctx != UnusedDelimsCtx::ArrayLenExpr - || !matches!(expr.kind, ast::ExprKind::Lit(_))) && !cx.sess().source_map().is_multiline(value.span) && value.attrs.is_empty() && !value.span.from_expansion() @@ -999,21 +988,54 @@ impl UnusedDelimLint for UnusedBraces { } impl EarlyLintPass for UnusedBraces { + fn check_stmt(&mut self, cx: &EarlyContext<'_>, s: &ast::Stmt) { + <Self as UnusedDelimLint>::check_stmt(self, cx, s) + } + fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) { - <Self as UnusedDelimLint>::check_expr(self, cx, e) + <Self as UnusedDelimLint>::check_expr(self, cx, e); + + if let ExprKind::Repeat(_, ref anon_const) = e.kind { + self.check_unused_delims_expr( + cx, + &anon_const.value, + UnusedDelimsCtx::AnonConst, + false, + None, + None, + ); + } } - fn check_anon_const(&mut self, cx: &EarlyContext<'_>, c: &ast::AnonConst) { - self.check_unused_delims_expr(cx, &c.value, UnusedDelimsCtx::AnonConst, false, None, None); + fn check_generic_arg(&mut self, cx: &EarlyContext<'_>, arg: &ast::GenericArg) { + if let ast::GenericArg::Const(ct) = arg { + self.check_unused_delims_expr( + cx, + &ct.value, + UnusedDelimsCtx::AnonConst, + false, + None, + None, + ); + } } - fn check_stmt(&mut self, cx: &EarlyContext<'_>, s: &ast::Stmt) { - <Self as UnusedDelimLint>::check_stmt(self, cx, s) + fn check_variant(&mut self, cx: &EarlyContext<'_>, v: &ast::Variant) { + if let Some(anon_const) = &v.disr_expr { + self.check_unused_delims_expr( + cx, + &anon_const.value, + UnusedDelimsCtx::AnonConst, + false, + None, + None, + ); + } } fn check_ty(&mut self, cx: &EarlyContext<'_>, ty: &ast::Ty) { - if let &ast::TyKind::Paren(ref r) = &ty.kind { - if let ast::TyKind::Array(_, ref len) = r.kind { + match ty.kind { + ast::TyKind::Array(_, ref len) => { self.check_unused_delims_expr( cx, &len.value, @@ -1023,6 +1045,19 @@ impl EarlyLintPass for UnusedBraces { None, ); } + + ast::TyKind::Typeof(ref anon_const) => { + self.check_unused_delims_expr( + cx, + &anon_const.value, + UnusedDelimsCtx::AnonConst, + false, + None, + None, + ); + } + + _ => {} } } diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp index 7b1c3f9ba2c..71ca4f23bbb 100644 --- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp @@ -1212,6 +1212,7 @@ struct LLVMRustThinLTOData { StringMap<FunctionImporter::ImportMapTy> ImportLists; StringMap<FunctionImporter::ExportSetTy> ExportLists; StringMap<GVSummaryMapTy> ModuleToDefinedGVSummaries; + StringMap<std::map<GlobalValue::GUID, GlobalValue::LinkageTypes>> ResolvedODR; LLVMRustThinLTOData() : Index(/* HaveGVs = */ false) {} }; @@ -1308,7 +1309,6 @@ LLVMRustCreateThinLTOData(LLVMRustThinLTOModule *modules, // // This is copied from `lib/LTO/ThinLTOCodeGenerator.cpp` with some of this // being lifted from `lib/LTO/LTO.cpp` as well - StringMap<std::map<GlobalValue::GUID, GlobalValue::LinkageTypes>> ResolvedODR; DenseMap<GlobalValue::GUID, const GlobalValueSummary *> PrevailingCopy; for (auto &I : Ret->Index) { if (I.second.SummaryList.size() > 1) @@ -1323,7 +1323,7 @@ LLVMRustCreateThinLTOData(LLVMRustThinLTOModule *modules, auto recordNewLinkage = [&](StringRef ModuleIdentifier, GlobalValue::GUID GUID, GlobalValue::LinkageTypes NewLinkage) { - ResolvedODR[ModuleIdentifier][GUID] = NewLinkage; + Ret->ResolvedODR[ModuleIdentifier][GUID] = NewLinkage; }; #if LLVM_VERSION_GE(9, 0) thinLTOResolvePrevailingInIndex(Ret->Index, isPrevailing, recordNewLinkage, @@ -1491,7 +1491,7 @@ extern "C" typedef void (*LLVMRustModuleNameCallback)(void*, // payload // Calls `module_name_callback` for each module import done by ThinLTO. // The callback is provided with regular null-terminated C strings. extern "C" void -LLVMRustGetThinLTOModuleImports(const LLVMRustThinLTOData *data, +LLVMRustGetThinLTOModules(const LLVMRustThinLTOData *data, LLVMRustModuleNameCallback module_name_callback, void* callback_payload) { for (const auto& importing_module : data->ImportLists) { @@ -1653,3 +1653,36 @@ LLVMRustThinLTOPatchDICompileUnit(LLVMModuleRef Mod, DICompileUnit *Unit) { MD->clearOperands(); MD->addOperand(Unit); } + +// Computes the LTO cache key for the provided 'ModId' in the given 'Data', +// storing the result in 'KeyOut'. +// Currently, this cache key is a SHA-1 hash of anything that could affect +// the result of optimizing this module (e.g. module imports, exports, liveness +// of access globals, etc). +// The precise details are determined by LLVM in `computeLTOCacheKey`, which is +// used during the normal linker-plugin incremental thin-LTO process. +extern "C" void +LLVMRustComputeLTOCacheKey(RustStringRef KeyOut, const char *ModId, LLVMRustThinLTOData *Data) { + SmallString<40> Key; + llvm::lto::Config conf; + const auto &ImportList = Data->ImportLists.lookup(ModId); + const auto &ExportList = Data->ExportLists.lookup(ModId); + const auto &ResolvedODR = Data->ResolvedODR.lookup(ModId); + const auto &DefinedGlobals = Data->ModuleToDefinedGVSummaries.lookup(ModId); + std::set<GlobalValue::GUID> CfiFunctionDefs; + std::set<GlobalValue::GUID> CfiFunctionDecls; + + // Based on the 'InProcessThinBackend' constructor in LLVM + for (auto &Name : Data->Index.cfiFunctionDefs()) + CfiFunctionDefs.insert( + GlobalValue::getGUID(GlobalValue::dropLLVMManglingEscape(Name))); + for (auto &Name : Data->Index.cfiFunctionDecls()) + CfiFunctionDecls.insert( + GlobalValue::getGUID(GlobalValue::dropLLVMManglingEscape(Name))); + + llvm::computeLTOCacheKey(Key, conf, Data->Index, ModId, + ImportList, ExportList, ResolvedODR, DefinedGlobals, CfiFunctionDefs, CfiFunctionDecls + ); + + LLVMRustStringWriteImpl(KeyOut, Key.c_str(), Key.size()); +} diff --git a/compiler/rustc_metadata/src/dependency_format.rs b/compiler/rustc_metadata/src/dependency_format.rs index f7454da90a3..44f57cfbe28 100644 --- a/compiler/rustc_metadata/src/dependency_format.rs +++ b/compiler/rustc_metadata/src/dependency_format.rs @@ -127,7 +127,7 @@ fn calculate_type(tcx: TyCtxt<'_>, ty: CrateType) -> DependencyList { if ty == CrateType::Staticlib || (ty == CrateType::Executable && sess.crt_static(Some(ty)) - && !sess.target.target.options.crt_static_allows_dylibs) + && !sess.target.options.crt_static_allows_dylibs) { for &cnum in tcx.crates().iter() { if tcx.dep_kind(cnum).macros_only() { diff --git a/compiler/rustc_metadata/src/locator.rs b/compiler/rustc_metadata/src/locator.rs index 0869ec28367..f225f8acc89 100644 --- a/compiler/rustc_metadata/src/locator.rs +++ b/compiler/rustc_metadata/src/locator.rs @@ -325,7 +325,7 @@ impl<'a> CrateLocator<'a> { hash, host_hash, extra_filename, - target: if is_host { &sess.host } else { &sess.target.target }, + target: if is_host { &sess.host } else { &sess.target }, triple: if is_host { TargetTriple::from_triple(config::host_triple()) } else { diff --git a/compiler/rustc_metadata/src/native_libs.rs b/compiler/rustc_metadata/src/native_libs.rs index e76c2cb356f..5e65f075ea4 100644 --- a/compiler/rustc_metadata/src/native_libs.rs +++ b/compiler/rustc_metadata/src/native_libs.rs @@ -149,7 +149,7 @@ impl Collector<'tcx> { } return; } - let is_osx = self.tcx.sess.target.target.options.is_like_osx; + let is_osx = self.tcx.sess.target.options.is_like_osx; if lib.kind == NativeLibKind::Framework && !is_osx { let msg = "native frameworks are only available on macOS targets"; match span { diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index 2662f6b6ed6..b01a55b48da 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -313,27 +313,6 @@ impl<'a, 'tcx> TyDecoder<'tcx> for DecodeContext<'a, 'tcx> { Ok(ty) } - fn cached_predicate_for_shorthand<F>( - &mut self, - shorthand: usize, - or_insert_with: F, - ) -> Result<ty::Predicate<'tcx>, Self::Error> - where - F: FnOnce(&mut Self) -> Result<ty::Predicate<'tcx>, Self::Error>, - { - let tcx = self.tcx(); - - let key = ty::CReaderCacheKey { cnum: self.cdata().cnum, pos: shorthand }; - - if let Some(&pred) = tcx.pred_rcache.borrow().get(&key) { - return Ok(pred); - } - - let pred = or_insert_with(self)?; - tcx.pred_rcache.borrow_mut().insert(key, pred); - Ok(pred) - } - fn with_position<F, R>(&mut self, pos: usize, f: F) -> R where F: FnOnce(&mut Self) -> R, diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index 60705f68681..05b8dad3097 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -94,7 +94,7 @@ provide! { <'tcx> tcx, def_id, other, cdata, adt_def => { cdata.get_adt_def(def_id.index, tcx) } adt_destructor => { let _ = cdata; - tcx.calculate_dtor(def_id, &mut |_,_| Ok(())) + tcx.calculate_dtor(def_id, |_,_| Ok(())) } variances_of => { tcx.arena.alloc_from_iter(cdata.get_item_variances(def_id.index)) } associated_item_def_ids => { diff --git a/compiler/rustc_middle/src/hir/place.rs b/compiler/rustc_middle/src/hir/place.rs index bcb56fae170..5da4be4e982 100644 --- a/compiler/rustc_middle/src/hir/place.rs +++ b/compiler/rustc_middle/src/hir/place.rs @@ -103,7 +103,7 @@ impl<'tcx> Place<'tcx> { /// Returns the type of this `Place` after all projections have been applied. pub fn ty(&self) -> Ty<'tcx> { - self.projections.last().map_or_else(|| self.base_ty, |proj| proj.ty) + self.projections.last().map_or(self.base_ty, |proj| proj.ty) } /// Returns the type of this `Place` immediately before `projection_index`th projection diff --git a/compiler/rustc_middle/src/ich/impls_syntax.rs b/compiler/rustc_middle/src/ich/impls_syntax.rs index e3d4655831b..7aba4fc64a9 100644 --- a/compiler/rustc_middle/src/ich/impls_syntax.rs +++ b/compiler/rustc_middle/src/ich/impls_syntax.rs @@ -5,7 +5,7 @@ use crate::ich::StableHashingContext; use rustc_ast as ast; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; -use rustc_span::SourceFile; +use rustc_span::{BytePos, NormalizedPos, SourceFile}; use smallvec::SmallVec; @@ -102,22 +102,19 @@ impl<'a> HashStable<StableHashingContext<'a>> for SourceFile { } } -fn stable_byte_pos(pos: ::rustc_span::BytePos, source_file_start: ::rustc_span::BytePos) -> u32 { +fn stable_byte_pos(pos: BytePos, source_file_start: BytePos) -> u32 { pos.0 - source_file_start.0 } -fn stable_multibyte_char( - mbc: ::rustc_span::MultiByteChar, - source_file_start: ::rustc_span::BytePos, -) -> (u32, u32) { - let ::rustc_span::MultiByteChar { pos, bytes } = mbc; +fn stable_multibyte_char(mbc: rustc_span::MultiByteChar, source_file_start: BytePos) -> (u32, u32) { + let rustc_span::MultiByteChar { pos, bytes } = mbc; (pos.0 - source_file_start.0, bytes as u32) } fn stable_non_narrow_char( - swc: ::rustc_span::NonNarrowChar, - source_file_start: ::rustc_span::BytePos, + swc: rustc_span::NonNarrowChar, + source_file_start: BytePos, ) -> (u32, u32) { let pos = swc.pos(); let width = swc.width(); @@ -125,11 +122,8 @@ fn stable_non_narrow_char( (pos.0 - source_file_start.0, width as u32) } -fn stable_normalized_pos( - np: ::rustc_span::NormalizedPos, - source_file_start: ::rustc_span::BytePos, -) -> (u32, u32) { - let ::rustc_span::NormalizedPos { pos, diff } = np; +fn stable_normalized_pos(np: NormalizedPos, source_file_start: BytePos) -> (u32, u32) { + let NormalizedPos { pos, diff } = np; (pos.0 - source_file_start.0, diff) } diff --git a/compiler/rustc_middle/src/middle/privacy.rs b/compiler/rustc_middle/src/middle/privacy.rs index 4756e83b5e9..254b57a005e 100644 --- a/compiler/rustc_middle/src/middle/privacy.rs +++ b/compiler/rustc_middle/src/middle/privacy.rs @@ -3,7 +3,6 @@ //! which are available for use externally when compiled as a library. use rustc_data_structures::fx::FxHashMap; -use rustc_hir::def_id::DefIdSet; use rustc_hir::HirId; use rustc_macros::HashStable; use std::fmt; @@ -59,7 +58,3 @@ impl<Id: Hash + Eq + fmt::Debug> fmt::Debug for AccessLevels<Id> { fmt::Debug::fmt(&self.map, f) } } - -/// A set containing all exported definitions from external crates. -/// The set does not contain any entries from local crates. -pub type ExternalExports = DefIdSet; diff --git a/compiler/rustc_middle/src/middle/region.rs b/compiler/rustc_middle/src/middle/region.rs index 4c6ac820604..38cb3c1701f 100644 --- a/compiler/rustc_middle/src/middle/region.rs +++ b/compiler/rustc_middle/src/middle/region.rs @@ -283,23 +283,27 @@ pub struct ScopeTree { /// To see that this method works, consider: /// /// Let `D` be our binding/temporary and `U` be our other HIR node, with - /// `HIR-postorder(U) < HIR-postorder(D)` (in our example, U would be - /// the yield and D would be one of the calls). Let's show that - /// `D` is storage-dead at `U`. + /// `HIR-postorder(U) < HIR-postorder(D)`. Suppose, as in our example, + /// U is the yield and D is one of the calls. + /// Let's show that `D` is storage-dead at `U`. /// /// Remember that storage-live/storage-dead refers to the state of /// the *storage*, and does not consider moves/drop flags. /// /// Then: + /// /// 1. From the ordering guarantee of HIR visitors (see /// `rustc_hir::intravisit`), `D` does not dominate `U`. + /// /// 2. Therefore, `D` is *potentially* storage-dead at `U` (because /// we might visit `U` without ever getting to `D`). + /// /// 3. However, we guarantee that at each HIR point, each /// binding/temporary is always either always storage-live /// or always storage-dead. This is what is being guaranteed /// by `terminating_scopes` including all blocks where the /// count of executions is not guaranteed. + /// /// 4. By `2.` and `3.`, `D` is *statically* storage-dead at `U`, /// QED. /// diff --git a/compiler/rustc_middle/src/mir/interpret/allocation.rs b/compiler/rustc_middle/src/mir/interpret/allocation.rs index ee1ea816e01..5ebe38b2d7e 100644 --- a/compiler/rustc_middle/src/mir/interpret/allocation.rs +++ b/compiler/rustc_middle/src/mir/interpret/allocation.rs @@ -40,7 +40,7 @@ pub struct Allocation<Tag = (), Extra = ()> { pub extra: Extra, } -pub trait AllocationExtra<Tag>: ::std::fmt::Debug + Clone { +pub trait AllocationExtra<Tag>: std::fmt::Debug + Clone { // There is no constructor in here because the constructor's type depends // on `MemoryKind`, and making things sufficiently generic leads to painful // inference failure. diff --git a/compiler/rustc_middle/src/mir/interpret/value.rs b/compiler/rustc_middle/src/mir/interpret/value.rs index 3751249853f..cb8782ce817 100644 --- a/compiler/rustc_middle/src/mir/interpret/value.rs +++ b/compiler/rustc_middle/src/mir/interpret/value.rs @@ -56,15 +56,6 @@ impl<'tcx> ConstValue<'tcx> { } } - pub fn try_to_str_slice(&self) -> Option<&'tcx str> { - if let ConstValue::Slice { data, start, end } = *self { - ::std::str::from_utf8(data.inspect_with_uninit_and_ptr_outside_interpreter(start..end)) - .ok() - } else { - None - } - } - pub fn try_to_bits(&self, size: Size) -> Option<u128> { self.try_to_scalar()?.to_bits(size).ok() } @@ -465,7 +456,7 @@ impl<'tcx, Tag> Scalar<Tag> { pub fn to_char(self) -> InterpResult<'tcx, char> { let val = self.to_u32()?; - match ::std::char::from_u32(val) { + match std::char::from_u32(val) { Some(c) => Ok(c), None => throw_ub!(InvalidChar(val)), } diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 92a2baa30ee..b38efedbf60 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -3,7 +3,7 @@ //! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/mir/index.html use crate::mir::coverage::{CodeRegion, CoverageKind}; -use crate::mir::interpret::{Allocation, ConstValue, GlobalAlloc, Scalar}; +use crate::mir::interpret::{Allocation, GlobalAlloc, Scalar}; use crate::mir::visit::MirVisitable; use crate::ty::adjustment::PointerCast; use crate::ty::codec::{TyDecoder, TyEncoder}; @@ -146,7 +146,7 @@ impl<'tcx> MirSource<'tcx> { /// The lowered representation of a single function. #[derive(Clone, TyEncodable, TyDecodable, Debug, HashStable, TypeFoldable)] pub struct Body<'tcx> { - /// A list of basic blocks. References to basic block use a newtyped index type `BasicBlock` + /// A list of basic blocks. References to basic block use a newtyped index type [`BasicBlock`] /// that indexes into this vector. basic_blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>, @@ -460,17 +460,6 @@ impl<'tcx> Body<'tcx> { } } - /// Checks if `sub` is a sub scope of `sup` - pub fn is_sub_scope(&self, mut sub: SourceScope, sup: SourceScope) -> bool { - while sub != sup { - match self.source_scopes[sub].parent_scope { - None => return false, - Some(p) => sub = p, - } - } - true - } - /// Returns the return type; it always return first element from `local_decls` array. #[inline] pub fn return_ty(&self) -> Ty<'tcx> { @@ -775,7 +764,7 @@ mod binding_form_impl { impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for super::BindingForm<'tcx> { fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { use super::BindingForm::*; - ::std::mem::discriminant(self).hash_stable(hcx, hasher); + std::mem::discriminant(self).hash_stable(hcx, hasher); match self { Var(binding) => binding.hash_stable(hcx, hasher), @@ -1117,6 +1106,9 @@ rustc_index::newtype_index! { /// are edges that go from a multi-successor node to a multi-predecessor node. This pass is /// needed because some analyses require that there are no critical edges in the CFG. /// + /// Note that this type is just an index into [`Body.basic_blocks`](Body::basic_blocks); + /// the actual data that a basic block holds is in [`BasicBlockData`]. + /// /// Read more about basic blocks in the [rustc-dev-guide][guide-mir]. /// /// [CFG]: https://rustc-dev-guide.rust-lang.org/appendix/background.html#cfg @@ -1978,45 +1970,6 @@ impl<'tcx> Operand<'tcx> { }) } - /// Convenience helper to make a `Scalar` from the given `Operand`, assuming that `Operand` - /// wraps a constant literal value. Panics if this is not the case. - pub fn scalar_from_const(operand: &Operand<'tcx>) -> Scalar { - match operand { - Operand::Constant(constant) => match constant.literal.val.try_to_scalar() { - Some(scalar) => scalar, - _ => panic!("{:?}: Scalar value expected", constant.literal.val), - }, - _ => panic!("{:?}: Constant expected", operand), - } - } - - /// Convenience helper to make a literal-like constant from a given `&str` slice. - /// Since this is used to synthesize MIR, assumes `user_ty` is None. - pub fn const_from_str(tcx: TyCtxt<'tcx>, val: &str, span: Span) -> Operand<'tcx> { - let tcx = tcx; - let allocation = Allocation::from_byte_aligned_bytes(val.as_bytes()); - let allocation = tcx.intern_const_alloc(allocation); - let const_val = ConstValue::Slice { data: allocation, start: 0, end: val.len() }; - let ty = tcx.mk_imm_ref(tcx.lifetimes.re_erased, tcx.types.str_); - Operand::Constant(box Constant { - span, - user_ty: None, - literal: ty::Const::from_value(tcx, const_val, ty), - }) - } - - /// Convenience helper to make a `ConstValue` from the given `Operand`, assuming that `Operand` - /// wraps a constant value (such as a `&str` slice). Panics if this is not the case. - pub fn value_from_const(operand: &Operand<'tcx>) -> ConstValue<'tcx> { - match operand { - Operand::Constant(constant) => match constant.literal.val.try_to_value() { - Some(const_value) => const_value, - _ => panic!("{:?}: ConstValue expected", constant.literal.val), - }, - _ => panic!("{:?}: Constant expected", operand), - } - } - pub fn to_copy(&self) -> Self { match *self { Operand::Copy(_) | Operand::Constant(_) => self.clone(), @@ -2413,10 +2366,6 @@ impl<'tcx> UserTypeProjections { self.contents.is_empty() } - pub fn from_projections(projs: impl Iterator<Item = (UserTypeProjection, Span)>) -> Self { - UserTypeProjections { contents: projs.collect() } - } - pub fn projections_and_spans( &self, ) -> impl Iterator<Item = &(UserTypeProjection, Span)> + ExactSizeIterator { diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs index 0878e9313d8..6022194342d 100644 --- a/compiler/rustc_middle/src/mir/query.rs +++ b/compiler/rustc_middle/src/mir/query.rs @@ -1,9 +1,10 @@ //! Values computed by queries that use MIR. -use crate::mir::{Body, Promoted}; +use crate::mir::{abstract_const, Body, Promoted}; use crate::ty::{self, Ty, TyCtxt}; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sync::Lrc; +use rustc_errors::ErrorReported; use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_index::bit_set::BitMatrix; @@ -407,18 +408,12 @@ pub struct CoverageInfo { pub num_expressions: u32, } +/// Shims which make dealing with `WithOptConstParam` easier. +/// +/// For more information on why this is needed, consider looking +/// at the docs for `WithOptConstParam` itself. impl<'tcx> TyCtxt<'tcx> { - pub fn mir_borrowck_opt_const_arg( - self, - def: ty::WithOptConstParam<LocalDefId>, - ) -> &'tcx BorrowCheckResult<'tcx> { - if let Some(param_did) = def.const_param_did { - self.mir_borrowck_const_arg((def.did, param_did)) - } else { - self.mir_borrowck(def.did) - } - } - + #[inline] pub fn mir_const_qualif_opt_const_arg( self, def: ty::WithOptConstParam<LocalDefId>, @@ -430,7 +425,8 @@ impl<'tcx> TyCtxt<'tcx> { } } - pub fn promoted_mir_of_opt_const_arg( + #[inline] + pub fn promoted_mir_opt_const_arg( self, def: ty::WithOptConstParam<DefId>, ) -> &'tcx IndexVec<Promoted, Body<'tcx>> { @@ -440,4 +436,28 @@ impl<'tcx> TyCtxt<'tcx> { self.promoted_mir(def.did) } } + + #[inline] + pub fn optimized_mir_opt_const_arg( + self, + def: ty::WithOptConstParam<DefId>, + ) -> &'tcx Body<'tcx> { + if let Some((did, param_did)) = def.as_const_arg() { + self.optimized_mir_of_const_arg((did, param_did)) + } else { + self.optimized_mir(def.did) + } + } + + #[inline] + pub fn mir_abstract_const_opt_const_arg( + self, + def: ty::WithOptConstParam<DefId>, + ) -> Result<Option<&'tcx [abstract_const::Node<'tcx>]>, ErrorReported> { + if let Some((did, param_did)) = def.as_const_arg() { + self.mir_abstract_const_of_const_arg((did, param_did)) + } else { + self.mir_abstract_const(def.did) + } + } } diff --git a/compiler/rustc_middle/src/mir/terminator/mod.rs b/compiler/rustc_middle/src/mir/terminator/mod.rs index 8909f02270c..e1071454e65 100644 --- a/compiler/rustc_middle/src/mir/terminator/mod.rs +++ b/compiler/rustc_middle/src/mir/terminator/mod.rs @@ -1,6 +1,7 @@ use crate::mir::interpret::Scalar; use crate::ty::{self, Ty, TyCtxt}; use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece}; +use smallvec::{smallvec, SmallVec}; use super::{ AssertMessage, BasicBlock, InlineAsmOperand, Operand, Place, SourceInfo, Successors, @@ -16,6 +17,87 @@ use std::slice; pub use super::query::*; +#[derive(Debug, Clone, TyEncodable, TyDecodable, HashStable, PartialEq)] +pub struct SwitchTargets { + /// Possible values. The locations to branch to in each case + /// are found in the corresponding indices from the `targets` vector. + values: SmallVec<[u128; 1]>, + + /// Possible branch sites. The last element of this vector is used + /// for the otherwise branch, so targets.len() == values.len() + 1 + /// should hold. + // + // This invariant is quite non-obvious and also could be improved. + // One way to make this invariant is to have something like this instead: + // + // branches: Vec<(ConstInt, BasicBlock)>, + // otherwise: Option<BasicBlock> // exhaustive if None + // + // However we’ve decided to keep this as-is until we figure a case + // where some other approach seems to be strictly better than other. + targets: SmallVec<[BasicBlock; 2]>, +} + +impl SwitchTargets { + /// Creates switch targets from an iterator of values and target blocks. + /// + /// The iterator may be empty, in which case the `SwitchInt` instruction is equivalent to + /// `goto otherwise;`. + pub fn new(targets: impl Iterator<Item = (u128, BasicBlock)>, otherwise: BasicBlock) -> Self { + let (values, mut targets): (SmallVec<_>, SmallVec<_>) = targets.unzip(); + targets.push(otherwise); + Self { values: values.into(), targets } + } + + /// Builds a switch targets definition that jumps to `then` if the tested value equals `value`, + /// and to `else_` if not. + pub fn static_if(value: u128, then: BasicBlock, else_: BasicBlock) -> Self { + Self { values: smallvec![value], targets: smallvec![then, else_] } + } + + /// Returns the fallback target that is jumped to when none of the values match the operand. + pub fn otherwise(&self) -> BasicBlock { + *self.targets.last().unwrap() + } + + /// Returns an iterator over the switch targets. + /// + /// The iterator will yield tuples containing the value and corresponding target to jump to, not + /// including the `otherwise` fallback target. + /// + /// Note that this may yield 0 elements. Only the `otherwise` branch is mandatory. + pub fn iter(&self) -> SwitchTargetsIter<'_> { + SwitchTargetsIter { inner: self.values.iter().zip(self.targets.iter()) } + } + + /// Returns a slice with all possible jump targets (including the fallback target). + pub fn all_targets(&self) -> &[BasicBlock] { + &self.targets + } + + pub fn all_targets_mut(&mut self) -> &mut [BasicBlock] { + &mut self.targets + } +} + +pub struct SwitchTargetsIter<'a> { + inner: iter::Zip<slice::Iter<'a, u128>, slice::Iter<'a, BasicBlock>>, +} + +impl<'a> Iterator for SwitchTargetsIter<'a> { + type Item = (u128, BasicBlock); + + fn next(&mut self) -> Option<Self::Item> { + self.inner.next().map(|(val, bb)| (*val, *bb)) + } + + fn size_hint(&self) -> (usize, Option<usize>) { + self.inner.size_hint() + } +} + +impl<'a> ExactSizeIterator for SwitchTargetsIter<'a> {} + #[derive(Clone, TyEncodable, TyDecodable, HashStable, PartialEq)] pub enum TerminatorKind<'tcx> { /// Block should have one successor in the graph; we jump there. @@ -32,23 +114,7 @@ pub enum TerminatorKind<'tcx> { /// FIXME: remove this redundant information. Currently, it is relied on by pretty-printing. switch_ty: Ty<'tcx>, - /// Possible values. The locations to branch to in each case - /// are found in the corresponding indices from the `targets` vector. - values: Cow<'tcx, [u128]>, - - /// Possible branch sites. The last element of this vector is used - /// for the otherwise branch, so targets.len() == values.len() + 1 - /// should hold. - // - // This invariant is quite non-obvious and also could be improved. - // One way to make this invariant is to have something like this instead: - // - // branches: Vec<(ConstInt, BasicBlock)>, - // otherwise: Option<BasicBlock> // exhaustive if None - // - // However we’ve decided to keep this as-is until we figure a case - // where some other approach seems to be strictly better than other. - targets: Vec<BasicBlock>, + targets: SwitchTargets, }, /// Indicates that the landing pad is finished and unwinding should @@ -227,12 +293,10 @@ impl<'tcx> TerminatorKind<'tcx> { t: BasicBlock, f: BasicBlock, ) -> TerminatorKind<'tcx> { - static BOOL_SWITCH_FALSE: &[u128] = &[0]; TerminatorKind::SwitchInt { discr: cond, switch_ty: tcx.types.bool, - values: From::from(BOOL_SWITCH_FALSE), - targets: vec![f, t], + targets: SwitchTargets::static_if(0, f, t), } } @@ -263,7 +327,7 @@ impl<'tcx> TerminatorKind<'tcx> { | FalseUnwind { real_target: ref t, unwind: Some(ref u) } => { Some(t).into_iter().chain(slice::from_ref(u)) } - SwitchInt { ref targets, .. } => None.into_iter().chain(&targets[..]), + SwitchInt { ref targets, .. } => None.into_iter().chain(&targets.targets[..]), FalseEdge { ref real_target, ref imaginary_target } => { Some(real_target).into_iter().chain(slice::from_ref(imaginary_target)) } @@ -297,7 +361,7 @@ impl<'tcx> TerminatorKind<'tcx> { | FalseUnwind { real_target: ref mut t, unwind: Some(ref mut u) } => { Some(t).into_iter().chain(slice::from_mut(u)) } - SwitchInt { ref mut targets, .. } => None.into_iter().chain(&mut targets[..]), + SwitchInt { ref mut targets, .. } => None.into_iter().chain(&mut targets.targets[..]), FalseEdge { ref mut real_target, ref mut imaginary_target } => { Some(real_target).into_iter().chain(slice::from_mut(imaginary_target)) } @@ -469,11 +533,12 @@ impl<'tcx> TerminatorKind<'tcx> { match *self { Return | Resume | Abort | Unreachable | GeneratorDrop => vec![], Goto { .. } => vec!["".into()], - SwitchInt { ref values, switch_ty, .. } => ty::tls::with(|tcx| { + SwitchInt { ref targets, switch_ty, .. } => ty::tls::with(|tcx| { let param_env = ty::ParamEnv::empty(); let switch_ty = tcx.lift(&switch_ty).unwrap(); let size = tcx.layout_of(param_env.and(switch_ty)).unwrap().size; - values + targets + .values .iter() .map(|&u| { ty::Const::from_scalar(tcx, Scalar::from_uint(u, size), switch_ty) diff --git a/compiler/rustc_middle/src/mir/type_foldable.rs b/compiler/rustc_middle/src/mir/type_foldable.rs index ad2eae0298c..9297aed66a4 100644 --- a/compiler/rustc_middle/src/mir/type_foldable.rs +++ b/compiler/rustc_middle/src/mir/type_foldable.rs @@ -21,10 +21,9 @@ impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> { let kind = match self.kind { Goto { target } => Goto { target }, - SwitchInt { ref discr, switch_ty, ref values, ref targets } => SwitchInt { + SwitchInt { ref discr, switch_ty, ref targets } => SwitchInt { discr: discr.fold_with(folder), switch_ty: switch_ty.fold_with(folder), - values: values.clone(), targets: targets.clone(), }, Drop { ref place, target, unwind } => { diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index 9a6bfa10189..58dd0bc00d2 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -453,7 +453,6 @@ macro_rules! make_mir_visitor { TerminatorKind::SwitchInt { discr, switch_ty, - values: _, targets: _ } => { self.visit_operand(discr, location); @@ -1187,16 +1186,6 @@ impl PlaceContext { ) } - /// Returns `true` if this place context represents a storage live marker. - pub fn is_storage_live_marker(&self) -> bool { - matches!(self, PlaceContext::NonUse(NonUseContext::StorageLive)) - } - - /// Returns `true` if this place context represents a storage dead marker. - pub fn is_storage_dead_marker(&self) -> bool { - matches!(self, PlaceContext::NonUse(NonUseContext::StorageDead)) - } - /// Returns `true` if this place context represents a use that potentially changes the value. pub fn is_mutating_use(&self) -> bool { matches!(self, PlaceContext::MutatingUse(..)) diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs index 8ea34f9161a..aaf6a857043 100644 --- a/compiler/rustc_middle/src/ty/codec.rs +++ b/compiler/rustc_middle/src/ty/codec.rs @@ -182,14 +182,6 @@ pub trait TyDecoder<'tcx>: Decoder { where F: FnOnce(&mut Self) -> Result<Ty<'tcx>, Self::Error>; - fn cached_predicate_for_shorthand<F>( - &mut self, - shorthand: usize, - or_insert_with: F, - ) -> Result<ty::Predicate<'tcx>, Self::Error> - where - F: FnOnce(&mut Self) -> Result<ty::Predicate<'tcx>, Self::Error>; - fn with_position<F, R>(&mut self, pos: usize, f: F) -> R where F: FnOnce(&mut Self) -> R; diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index e67a76f0111..e24ba6d7a1e 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -534,10 +534,6 @@ impl<'tcx> TypeckResults<'tcx> { self.node_type(pat.hir_id) } - pub fn pat_ty_opt(&self, pat: &hir::Pat<'_>) -> Option<Ty<'tcx>> { - self.node_type_opt(pat.hir_id) - } - // Returns the type of an expression as a monotype. // // NB (1): This is the PRE-ADJUSTMENT TYPE for the expression. That is, in @@ -1083,7 +1079,7 @@ impl<'tcx> TyCtxt<'tcx> { crate_name: &str, output_filenames: &OutputFilenames, ) -> GlobalCtxt<'tcx> { - let data_layout = TargetDataLayout::parse(&s.target.target).unwrap_or_else(|err| { + let data_layout = TargetDataLayout::parse(&s.target).unwrap_or_else(|err| { s.fatal(&err); }); let interners = CtxtInterners::new(arena); @@ -1526,7 +1522,7 @@ impl<'tcx> TyCtxt<'tcx> { /// Determines whether identifiers in the assembly have strict naming rules. /// Currently, only NVPTX* targets need it. pub fn has_strict_asm_symbol_naming(self) -> bool { - self.sess.target.target.arch.contains("nvptx") + self.sess.target.arch.contains("nvptx") } /// Returns `&'static core::panic::Location<'static>`. diff --git a/compiler/rustc_middle/src/ty/fold.rs b/compiler/rustc_middle/src/ty/fold.rs index 84134bedef0..5524d91a6d5 100644 --- a/compiler/rustc_middle/src/ty/fold.rs +++ b/compiler/rustc_middle/src/ty/fold.rs @@ -97,9 +97,6 @@ pub trait TypeFoldable<'tcx>: fmt::Debug + Clone { fn has_infer_types_or_consts(&self) -> bool { self.has_type_flags(TypeFlags::HAS_TY_INFER | TypeFlags::HAS_CT_INFER) } - fn has_infer_consts(&self) -> bool { - self.has_type_flags(TypeFlags::HAS_CT_INFER) - } fn needs_infer(&self) -> bool { self.has_type_flags(TypeFlags::NEEDS_INFER) } @@ -113,9 +110,6 @@ pub trait TypeFoldable<'tcx>: fmt::Debug + Clone { fn needs_subst(&self) -> bool { self.has_type_flags(TypeFlags::NEEDS_SUBST) } - fn has_re_placeholders(&self) -> bool { - self.has_type_flags(TypeFlags::HAS_RE_PLACEHOLDER) - } /// "Free" regions in this context means that it has any region /// that is not (a) erased or (b) late-bound. fn has_free_regions(&self) -> bool { @@ -719,21 +713,15 @@ impl<'tcx> TyCtxt<'tcx> { // vars. See comment on `shift_vars_through_binders` method in // `subst.rs` for more details. -enum Direction { - In, - Out, -} - struct Shifter<'tcx> { tcx: TyCtxt<'tcx>, current_index: ty::DebruijnIndex, amount: u32, - direction: Direction, } impl Shifter<'tcx> { - pub fn new(tcx: TyCtxt<'tcx>, amount: u32, direction: Direction) -> Self { - Shifter { tcx, current_index: ty::INNERMOST, amount, direction } + pub fn new(tcx: TyCtxt<'tcx>, amount: u32) -> Self { + Shifter { tcx, current_index: ty::INNERMOST, amount } } } @@ -755,13 +743,7 @@ impl TypeFolder<'tcx> for Shifter<'tcx> { if self.amount == 0 || debruijn < self.current_index { r } else { - let debruijn = match self.direction { - Direction::In => debruijn.shifted_in(self.amount), - Direction::Out => { - assert!(debruijn.as_u32() >= self.amount); - debruijn.shifted_out(self.amount) - } - }; + let debruijn = debruijn.shifted_in(self.amount); let shifted = ty::ReLateBound(debruijn, br); self.tcx.mk_region(shifted) } @@ -776,13 +758,7 @@ impl TypeFolder<'tcx> for Shifter<'tcx> { if self.amount == 0 || debruijn < self.current_index { ty } else { - let debruijn = match self.direction { - Direction::In => debruijn.shifted_in(self.amount), - Direction::Out => { - assert!(debruijn.as_u32() >= self.amount); - debruijn.shifted_out(self.amount) - } - }; + let debruijn = debruijn.shifted_in(self.amount); self.tcx.mk_ty(ty::Bound(debruijn, bound_ty)) } } @@ -796,13 +772,7 @@ impl TypeFolder<'tcx> for Shifter<'tcx> { if self.amount == 0 || debruijn < self.current_index { ct } else { - let debruijn = match self.direction { - Direction::In => debruijn.shifted_in(self.amount), - Direction::Out => { - assert!(debruijn.as_u32() >= self.amount); - debruijn.shifted_out(self.amount) - } - }; + let debruijn = debruijn.shifted_in(self.amount); self.tcx.mk_const(ty::Const { val: ty::ConstKind::Bound(debruijn, bound_ct), ty }) } } else { @@ -830,16 +800,7 @@ where { debug!("shift_vars(value={:?}, amount={})", value, amount); - value.fold_with(&mut Shifter::new(tcx, amount, Direction::In)) -} - -pub fn shift_out_vars<'tcx, T>(tcx: TyCtxt<'tcx>, value: &T, amount: u32) -> T -where - T: TypeFoldable<'tcx>, -{ - debug!("shift_out_vars(value={:?}, amount={})", value, amount); - - value.fold_with(&mut Shifter::new(tcx, amount, Direction::Out)) + value.fold_with(&mut Shifter::new(tcx, amount)) } /// An "escaping var" is a bound var whose binder is not part of `t`. A bound var can be a diff --git a/compiler/rustc_middle/src/ty/inhabitedness/mod.rs b/compiler/rustc_middle/src/ty/inhabitedness/mod.rs index 2c1179c21fb..bf1f5b81c9f 100644 --- a/compiler/rustc_middle/src/ty/inhabitedness/mod.rs +++ b/compiler/rustc_middle/src/ty/inhabitedness/mod.rs @@ -104,14 +104,6 @@ impl<'tcx> TyCtxt<'tcx> { // ``` ty.uninhabited_from(self, param_env).contains(self, module) } - - pub fn is_ty_uninhabited_from_any_module( - self, - ty: Ty<'tcx>, - param_env: ty::ParamEnv<'tcx>, - ) -> bool { - !ty.uninhabited_from(self, param_env).is_empty() - } } impl<'tcx> AdtDef { diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index f8e8c209d37..4a2c97b4a40 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -291,7 +291,17 @@ impl<'tcx> Instance<'tcx> { } pub fn mono(tcx: TyCtxt<'tcx>, def_id: DefId) -> Instance<'tcx> { - Instance::new(def_id, tcx.empty_substs_for_def_id(def_id)) + let substs = InternalSubsts::for_item(tcx, def_id, |param, _| match param.kind { + ty::GenericParamDefKind::Lifetime => tcx.lifetimes.re_erased.into(), + ty::GenericParamDefKind::Type { .. } => { + bug!("Instance::mono: {:?} has type parameters", def_id) + } + ty::GenericParamDefKind::Const { .. } => { + bug!("Instance::mono: {:?} has const parameters", def_id) + } + }); + + Instance::new(def_id, substs) } #[inline] diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index f6f71d002a8..91c3dcbfa81 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -106,7 +106,7 @@ impl IntegerExt for Integer { } if repr.c() { - match &tcx.sess.target.target.arch[..] { + match &tcx.sess.target.arch[..] { // WARNING: the ARM EABI has two variants; the one corresponding // to `at_least == I32` appears to be used on Linux and NetBSD, // but some systems may use the variant corresponding to no @@ -1894,7 +1894,7 @@ impl<'tcx, T: HasTyCtxt<'tcx>> HasTyCtxt<'tcx> for LayoutCx<'tcx, T> { } } -pub type TyAndLayout<'tcx> = ::rustc_target::abi::TyAndLayout<'tcx, Ty<'tcx>>; +pub type TyAndLayout<'tcx> = rustc_target::abi::TyAndLayout<'tcx, Ty<'tcx>>; impl<'tcx> LayoutOf for LayoutCx<'tcx, TyCtxt<'tcx>> { type Ty = Ty<'tcx>; @@ -2548,7 +2548,7 @@ where let sig = cx.tcx().normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig); use rustc_target::spec::abi::Abi::*; - let conv = match cx.tcx().sess.target.target.adjust_abi(sig.abi) { + let conv = match cx.tcx().sess.target.adjust_abi(sig.abi) { RustIntrinsic | PlatformIntrinsic | Rust | RustCall => Conv::Rust, // It's the ABI's job to select this, not ours. @@ -2600,7 +2600,7 @@ where extra_args.to_vec() }; - let target = &cx.tcx().sess.target.target; + let target = &cx.tcx().sess.target; let target_env_gnu_like = matches!(&target.target_env[..], "gnu" | "musl"); let win_x64_gnu = target.target_os == "windows" && target.arch == "x86_64" && target.target_env == "gnu"; @@ -2775,7 +2775,7 @@ where // anyway, we control all calls to it in libstd. Abi::Vector { .. } if abi != SpecAbi::PlatformIntrinsic - && cx.tcx().sess.target.target.options.simd_types_indirect => + && cx.tcx().sess.target.options.simd_types_indirect => { arg.make_indirect(); return; diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index f069faed9e2..cc378f1ea47 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -7,7 +7,6 @@ pub use self::Variance::*; use crate::hir::exports::ExportMap; use crate::ich::StableHashingContext; -use crate::infer::canonical::Canonical; use crate::middle::cstore::CrateStoreDyn; use crate::middle::resolve_lifetime::ObjectLifetimeDefault; use crate::mir::interpret::ErrorHandled; @@ -656,8 +655,6 @@ impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for TyS<'tcx> { #[rustc_diagnostic_item = "Ty"] pub type Ty<'tcx> = &'tcx TyS<'tcx>; -pub type CanonicalTy<'tcx> = Canonical<'tcx, Ty<'tcx>>; - #[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable, HashStable)] pub struct UpvarPath { pub hir_id: hir::HirId, @@ -767,10 +764,6 @@ pub enum IntVarValue { pub struct FloatVarValue(pub ast::FloatTy); impl ty::EarlyBoundRegion { - pub fn to_bound_region(&self) -> ty::BoundRegion { - ty::BoundRegion::BrNamed(self.def_id, self.name) - } - /// Does this early bound region have a name? Early bound regions normally /// always have names except when using anonymous lifetimes (`'_`). pub fn has_name(&self) -> bool { @@ -821,14 +814,6 @@ impl GenericParamDef { bug!("cannot convert a non-lifetime parameter def to an early bound region") } } - - pub fn to_bound_region(&self) -> ty::BoundRegion { - if let GenericParamDefKind::Lifetime = self.kind { - self.to_early_bound_region_data().to_bound_region() - } else { - bug!("cannot convert a non-lifetime parameter def to an early bound region") - } - } } #[derive(Default)] @@ -1003,22 +988,6 @@ impl<'tcx> GenericPredicates<'tcx> { instantiated.predicates.extend(self.predicates.iter().map(|(p, _)| p)); instantiated.spans.extend(self.predicates.iter().map(|(_, s)| s)); } - - pub fn instantiate_supertrait( - &self, - tcx: TyCtxt<'tcx>, - poly_trait_ref: &ty::PolyTraitRef<'tcx>, - ) -> InstantiatedPredicates<'tcx> { - assert_eq!(self.parent, None); - InstantiatedPredicates { - predicates: self - .predicates - .iter() - .map(|(pred, _)| pred.subst_supertrait(tcx, poly_trait_ref)) - .collect(), - spans: self.predicates.iter().map(|(_, sp)| *sp).collect(), - } - } } #[derive(Debug)] @@ -1087,9 +1056,21 @@ impl<'tcx> Predicate<'tcx> { } } + /// Converts this to a `Binder<PredicateAtom<'tcx>>`. If the value was an + /// `Atom`, then it is not allowed to contain escaping bound vars. + pub fn bound_atom(self) -> Binder<PredicateAtom<'tcx>> { + match self.kind() { + &PredicateKind::ForAll(binder) => binder, + &PredicateKind::Atom(atom) => { + debug_assert!(!atom.has_escaping_bound_vars()); + Binder::dummy(atom) + } + } + } + /// Allows using a `Binder<PredicateAtom<'tcx>>` even if the given predicate previously /// contained unbound variables by shifting these variables outwards. - pub fn bound_atom(self, tcx: TyCtxt<'tcx>) -> Binder<PredicateAtom<'tcx>> { + pub fn bound_atom_with_opt_escaping(self, tcx: TyCtxt<'tcx>) -> Binder<PredicateAtom<'tcx>> { match self.kind() { &PredicateKind::ForAll(binder) => binder, &PredicateKind::Atom(atom) => Binder::wrap_nonbinding(tcx, atom), @@ -1303,7 +1284,6 @@ impl<'tcx> PolyTraitPredicate<'tcx> { #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, TyEncodable, TyDecodable)] #[derive(HashStable, TypeFoldable)] pub struct OutlivesPredicate<A, B>(pub A, pub B); // `A: B` -pub type PolyOutlivesPredicate<A, B> = ty::Binder<OutlivesPredicate<A, B>>; pub type RegionOutlivesPredicate<'tcx> = OutlivesPredicate<ty::Region<'tcx>, ty::Region<'tcx>>; pub type TypeOutlivesPredicate<'tcx> = OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>; pub type PolyRegionOutlivesPredicate<'tcx> = ty::Binder<RegionOutlivesPredicate<'tcx>>; @@ -2468,8 +2448,10 @@ impl<'tcx> AdtDef { self.variants.iter().flat_map(|v| v.fields.iter()) } + /// Whether the ADT lacks fields. Note that this includes uninhabited enums, + /// e.g., `enum Void {}` is considered payload free as well. pub fn is_payloadfree(&self) -> bool { - !self.variants.is_empty() && self.variants.iter().all(|v| v.fields.is_empty()) + self.variants.iter().all(|v| v.fields.is_empty()) } /// Return a `VariantDef` given a variant id. @@ -2953,13 +2935,7 @@ impl<'tcx> TyCtxt<'tcx> { /// Returns the possibly-auto-generated MIR of a `(DefId, Subst)` pair. pub fn instance_mir(self, instance: ty::InstanceDef<'tcx>) -> &'tcx Body<'tcx> { match instance { - ty::InstanceDef::Item(def) => { - if let Some((did, param_did)) = def.as_const_arg() { - self.optimized_mir_of_const_arg((did, param_did)) - } else { - self.optimized_mir(def.did) - } - } + ty::InstanceDef::Item(def) => self.optimized_mir_opt_const_arg(def), ty::InstanceDef::VtableShim(..) | ty::InstanceDef::ReifyShim(..) | ty::InstanceDef::Intrinsic(..) diff --git a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs index 48a62b64604..a594a8ad512 100644 --- a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs +++ b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs @@ -23,7 +23,7 @@ impl<'tcx> TyCtxt<'tcx> { { debug!( "normalize_erasing_regions::<{}>(value={:?}, param_env={:?})", - ::std::any::type_name::<T>(), + std::any::type_name::<T>(), value, param_env, ); diff --git a/compiler/rustc_middle/src/ty/outlives.rs b/compiler/rustc_middle/src/ty/outlives.rs index 4c20141bbe6..86750d5c081 100644 --- a/compiler/rustc_middle/src/ty/outlives.rs +++ b/compiler/rustc_middle/src/ty/outlives.rs @@ -96,16 +96,14 @@ fn compute_components( } ty::Closure(_, ref substs) => { - for upvar_ty in substs.as_closure().upvar_tys() { - compute_components(tcx, upvar_ty, out, visited); - } + let tupled_ty = substs.as_closure().tupled_upvars_ty(); + compute_components(tcx, tupled_ty, out, visited); } ty::Generator(_, ref substs, _) => { // Same as the closure case - for upvar_ty in substs.as_generator().upvar_tys() { - compute_components(tcx, upvar_ty, out, visited); - } + let tupled_ty = substs.as_generator().tupled_upvars_ty(); + compute_components(tcx, tupled_ty, out, visited); // We ignore regions in the generator interior as we don't // want these to affect region inference diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index e1f02d0f704..acdf1f642ab 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -618,10 +618,9 @@ pub trait PrettyPrinter<'tcx>: // may contain unbound variables. We therefore do this manually. // // FIXME(lcnr): Find out why exactly this is the case :) - if let ty::PredicateAtom::Trait(pred, _) = - predicate.bound_atom(self.tcx()).skip_binder() - { - let trait_ref = ty::Binder::bind(pred.trait_ref); + let bound_predicate = predicate.bound_atom_with_opt_escaping(self.tcx()); + if let ty::PredicateAtom::Trait(pred, _) = bound_predicate.skip_binder() { + let trait_ref = bound_predicate.rebind(pred.trait_ref); // Don't print +Sized, but rather +?Sized if absent. if Some(trait_ref.def_id()) == self.tcx().lang_items().sized_trait() { is_sized = true; @@ -663,18 +662,13 @@ pub trait PrettyPrinter<'tcx>: } } else { p!(print_def_path(did, substs)); - if substs.as_generator().is_valid() { - // Search for the first inference variable - p!(" upvar_tys=("); - let mut uninferred_ty = - substs.as_generator().upvar_tys().filter(|ty| ty.is_ty_infer()); - if uninferred_ty.next().is_some() { - p!(write("unavailable")); - } else { - self = self.comma_sep(substs.as_generator().upvar_tys())?; - } - p!(")"); + p!(" upvar_tys=("); + if !substs.as_generator().is_valid() { + p!("unavailable"); + } else { + self = self.comma_sep(substs.as_generator().upvar_tys())?; } + p!(")"); } if substs.as_generator().is_valid() { @@ -704,24 +698,17 @@ pub trait PrettyPrinter<'tcx>: } } else { p!(print_def_path(did, substs)); - if substs.as_closure().is_valid() { - // Search for the first inference variable - let mut uninferred_ty = - substs.as_closure().upvar_tys().filter(|ty| ty.is_ty_infer()); - if uninferred_ty.next().is_some() { - // If the upvar substs contain an inference variable we haven't - // finished capture analysis. - p!(" closure_substs=(unavailable)"); - } else { - p!(" closure_kind_ty=", print(substs.as_closure().kind_ty())); - p!( - " closure_sig_as_fn_ptr_ty=", - print(substs.as_closure().sig_as_fn_ptr_ty()) - ); - p!(" upvar_tys=("); - self = self.comma_sep(substs.as_closure().upvar_tys())?; - p!(")"); - } + if !substs.as_closure().is_valid() { + p!(" closure_substs=(unavailable)"); + } else { + p!(" closure_kind_ty=", print(substs.as_closure().kind_ty())); + p!( + " closure_sig_as_fn_ptr_ty=", + print(substs.as_closure().sig_as_fn_ptr_ty()) + ); + p!(" upvar_tys=("); + self = self.comma_sep(substs.as_closure().upvar_tys())?; + p!(")"); } } p!("]"); @@ -1142,7 +1129,7 @@ pub trait PrettyPrinter<'tcx>: // relocations (we have an active `str` reference here). We don't use this // result to affect interpreter execution. let slice = data.inspect_with_uninit_and_ptr_outside_interpreter(start..end); - let s = ::std::str::from_utf8(slice).expect("non utf8 str from miri"); + let s = std::str::from_utf8(slice).expect("non utf8 str from miri"); p!(write("{:?}", s)); Ok(self) } diff --git a/compiler/rustc_middle/src/ty/query/on_disk_cache.rs b/compiler/rustc_middle/src/ty/query/on_disk_cache.rs index b0c48a860eb..173e9a31928 100644 --- a/compiler/rustc_middle/src/ty/query/on_disk_cache.rs +++ b/compiler/rustc_middle/src/ty/query/on_disk_cache.rs @@ -543,7 +543,7 @@ impl<'a, 'tcx> DecoderWithPosition for CacheDecoder<'a, 'tcx> { // tag matches and the correct amount of bytes was read. fn decode_tagged<D, T, V>(decoder: &mut D, expected_tag: T) -> Result<V, D::Error> where - T: Decodable<D> + Eq + ::std::fmt::Debug, + T: Decodable<D> + Eq + std::fmt::Debug, V: Decodable<D>, D: DecoderWithPosition, { @@ -601,29 +601,6 @@ impl<'a, 'tcx> TyDecoder<'tcx> for CacheDecoder<'a, 'tcx> { Ok(ty) } - fn cached_predicate_for_shorthand<F>( - &mut self, - shorthand: usize, - or_insert_with: F, - ) -> Result<ty::Predicate<'tcx>, Self::Error> - where - F: FnOnce(&mut Self) -> Result<ty::Predicate<'tcx>, Self::Error>, - { - let tcx = self.tcx(); - - let cache_key = - ty::CReaderCacheKey { cnum: CrateNum::ReservedForIncrCompCache, pos: shorthand }; - - if let Some(&pred) = tcx.pred_rcache.borrow().get(&cache_key) { - return Ok(pred); - } - - let pred = or_insert_with(self)?; - // This may overwrite the entry, but it should overwrite with the same value. - tcx.pred_rcache.borrow_mut().insert_same(cache_key, pred); - Ok(pred) - } - fn with_position<F, R>(&mut self, pos: usize, f: F) -> R where F: FnOnce(&mut Self) -> R, @@ -1023,7 +1000,7 @@ where let _timer = tcx .sess .prof - .extra_verbose_generic_activity("encode_query_results_for", ::std::any::type_name::<Q>()); + .extra_verbose_generic_activity("encode_query_results_for", std::any::type_name::<Q>()); let state = Q::query_state(tcx); assert!(state.all_inactive()); diff --git a/compiler/rustc_middle/src/ty/query/plumbing.rs b/compiler/rustc_middle/src/ty/query/plumbing.rs index f3fa3634026..27bf22dac75 100644 --- a/compiler/rustc_middle/src/ty/query/plumbing.rs +++ b/compiler/rustc_middle/src/ty/query/plumbing.rs @@ -124,20 +124,23 @@ impl<'tcx> TyCtxt<'tcx> { }) } - pub fn try_print_query_stack(handler: &Handler) { + pub fn try_print_query_stack(handler: &Handler, num_frames: Option<usize>) { eprintln!("query stack during panic:"); // Be careful reyling on global state here: this code is called from // a panic hook, which means that the global `Handler` may be in a weird // state if it was responsible for triggering the panic. + let mut i = 0; ty::tls::with_context_opt(|icx| { if let Some(icx) = icx { let query_map = icx.tcx.queries.try_collect_active_jobs(); let mut current_query = icx.query; - let mut i = 0; while let Some(query) = current_query { + if Some(i) == num_frames { + break; + } let query_info = if let Some(info) = query_map.as_ref().and_then(|map| map.get(&query)) { info @@ -163,7 +166,11 @@ impl<'tcx> TyCtxt<'tcx> { } }); - eprintln!("end of query stack"); + if num_frames == None || num_frames >= Some(i) { + eprintln!("end of query stack"); + } else { + eprintln!("we're just showing a limited slice of the query stack"); + } } } diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index 597ceac9386..15803dbd842 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -549,7 +549,7 @@ impl<'a, 'tcx> Lift<'tcx> for ty::PredicateAtom<'a> { impl<'tcx, T: Lift<'tcx>> Lift<'tcx> for ty::Binder<T> { type Lifted = ty::Binder<T::Lifted>; fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> { - tcx.lift(self.as_ref().skip_binder()).map(ty::Binder::bind) + tcx.lift(self.as_ref().skip_binder()).map(|v| self.rebind(v)) } } diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 1af56972ad0..0fd48d09282 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -210,6 +210,18 @@ impl TyKind<'tcx> { _ => false, } } + + /// Get the article ("a" or "an") to use with this type. + pub fn article(&self) -> &'static str { + match self { + Int(_) | Float(_) | Array(_, _) => "an", + Adt(def, _) if def.is_enum() => "an", + // This should never happen, but ICEing and causing the user's code + // to not compile felt too harsh. + Error(_) => "a", + _ => "a", + } + } } // `TyKind` is used a lot. Make sure it doesn't unintentionally get bigger. @@ -656,6 +668,14 @@ impl<'tcx> UpvarSubsts<'tcx> { }; tupled_upvars_ty.expect_ty().tuple_fields() } + + #[inline] + pub fn tupled_upvars_ty(self) -> Ty<'tcx> { + match self { + UpvarSubsts::Closure(substs) => substs.as_closure().tupled_upvars_ty(), + UpvarSubsts::Generator(substs) => substs.as_generator().tupled_upvars_ty(), + } + } } #[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Ord, Eq, Hash, TyEncodable, TyDecodable)] @@ -695,14 +715,16 @@ impl<'tcx> Binder<ExistentialPredicate<'tcx>> { use crate::ty::ToPredicate; match self.skip_binder() { ExistentialPredicate::Trait(tr) => { - Binder(tr).with_self_ty(tcx, self_ty).without_const().to_predicate(tcx) + self.rebind(tr).with_self_ty(tcx, self_ty).without_const().to_predicate(tcx) } ExistentialPredicate::Projection(p) => { - Binder(p.with_self_ty(tcx, self_ty)).to_predicate(tcx) + self.rebind(p.with_self_ty(tcx, self_ty)).to_predicate(tcx) } ExistentialPredicate::AutoTrait(did) => { - let trait_ref = - Binder(ty::TraitRef { def_id: did, substs: tcx.mk_substs_trait(self_ty, &[]) }); + let trait_ref = self.rebind(ty::TraitRef { + def_id: did, + substs: tcx.mk_substs_trait(self_ty, &[]), + }); trait_ref.without_const().to_predicate(tcx) } } @@ -767,7 +789,7 @@ impl<'tcx> List<ExistentialPredicate<'tcx>> { impl<'tcx> Binder<&'tcx List<ExistentialPredicate<'tcx>>> { pub fn principal(&self) -> Option<ty::Binder<ExistentialTraitRef<'tcx>>> { - self.skip_binder().principal().map(Binder::bind) + self.map_bound(|b| b.principal()).transpose() } pub fn principal_def_id(&self) -> Option<DefId> { @@ -850,8 +872,7 @@ impl<'tcx> PolyTraitRef<'tcx> { } pub fn to_poly_trait_predicate(&self) -> ty::PolyTraitPredicate<'tcx> { - // Note that we preserve binding levels - Binder(ty::TraitPredicate { trait_ref: self.skip_binder() }) + self.map_bound(|trait_ref| ty::TraitPredicate { trait_ref }) } } @@ -993,6 +1014,19 @@ impl<T> Binder<T> { Binder(f(self.0)) } + /// Wraps a `value` in a binder, using the same bound variables as the + /// current `Binder`. This should not be used if the new value *changes* + /// the bound variables. Note: the (old or new) value itself does not + /// necessarily need to *name* all the bound variables. + /// + /// This currently doesn't do anything different than `bind`, because we + /// don't actually track bound vars. However, semantically, it is different + /// because bound vars aren't allowed to change here, whereas they are + /// in `bind`. This may be (debug) asserted in the future. + pub fn rebind<U>(&self, value: U) -> Binder<U> { + Binder(value) + } + /// Unwraps and returns the value within, but only if it contains /// no bound vars at all. (In other words, if this binder -- /// and indeed any enclosing binder -- doesn't bind anything at diff --git a/compiler/rustc_middle/src/ty/subst.rs b/compiler/rustc_middle/src/ty/subst.rs index 1bd3bcb6a4d..7d96adb7c8b 100644 --- a/compiler/rustc_middle/src/ty/subst.rs +++ b/compiler/rustc_middle/src/ty/subst.rs @@ -1,6 +1,5 @@ // Type substitutions. -use crate::infer::canonical::Canonical; use crate::ty::codec::{TyDecoder, TyEncoder}; use crate::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; use crate::ty::sty::{ClosureSubsts, GeneratorSubsts}; @@ -648,8 +647,6 @@ impl<'a, 'tcx> SubstFolder<'a, 'tcx> { } } -pub type CanonicalUserSubsts<'tcx> = Canonical<'tcx, UserSubsts<'tcx>>; - /// Stores the user-given substs to reach some fully qualified path /// (e.g., `<T>::Item` or `<T as Trait>::Item`). #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable)] diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index d8ea2f67393..b0f0f0ba57f 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -6,9 +6,9 @@ use crate::mir::interpret::{sign_extend, truncate}; use crate::ty::fold::TypeFolder; use crate::ty::layout::IntegerExt; use crate::ty::query::TyCtxtAt; -use crate::ty::subst::{GenericArgKind, InternalSubsts, Subst, SubstsRef}; +use crate::ty::subst::{GenericArgKind, Subst, SubstsRef}; use crate::ty::TyKind::*; -use crate::ty::{self, DefIdTree, GenericParamDefKind, List, Ty, TyCtxt, TypeFoldable}; +use crate::ty::{self, DefIdTree, List, Ty, TyCtxt, TypeFoldable}; use rustc_apfloat::Float as _; use rustc_ast as ast; use rustc_attr::{self as attr, SignedInt, UnsignedInt}; @@ -341,7 +341,7 @@ impl<'tcx> TyCtxt<'tcx> { pub fn calculate_dtor( self, adt_did: DefId, - validate: &mut dyn FnMut(Self, DefId) -> Result<(), ErrorReported>, + validate: impl Fn(Self, DefId) -> Result<(), ErrorReported>, ) -> Option<ty::Destructor> { let drop_trait = self.lang_items().drop_trait()?; self.ensure().coherent_trait(drop_trait); @@ -509,20 +509,6 @@ impl<'tcx> TyCtxt<'tcx> { Some(ty::Binder::bind(env_ty)) } - /// Given the `DefId` of some item that has no type or const parameters, make - /// a suitable "empty substs" for it. - pub fn empty_substs_for_def_id(self, item_def_id: DefId) -> SubstsRef<'tcx> { - InternalSubsts::for_item(self, item_def_id, |param, _| match param.kind { - GenericParamDefKind::Lifetime => self.lifetimes.re_erased.into(), - GenericParamDefKind::Type { .. } => { - bug!("empty_substs_for_def_id: {:?} has type parameters", item_def_id) - } - GenericParamDefKind::Const { .. } => { - bug!("empty_substs_for_def_id: {:?} has const parameters", item_def_id) - } - }) - } - /// Returns `true` if the node pointed to by `def_id` is a `static` item. pub fn is_static(self, def_id: DefId) -> bool { self.static_mutability(def_id).is_some() @@ -646,8 +632,8 @@ impl<'tcx> ty::TyS<'tcx> { } ty::Char => Some(std::char::MAX as u128), ty::Float(fty) => Some(match fty { - ast::FloatTy::F32 => ::rustc_apfloat::ieee::Single::INFINITY.to_bits(), - ast::FloatTy::F64 => ::rustc_apfloat::ieee::Double::INFINITY.to_bits(), + ast::FloatTy::F32 => rustc_apfloat::ieee::Single::INFINITY.to_bits(), + ast::FloatTy::F64 => rustc_apfloat::ieee::Double::INFINITY.to_bits(), }), _ => None, }; diff --git a/compiler/rustc_mir/src/borrow_check/invalidation.rs b/compiler/rustc_mir/src/borrow_check/invalidation.rs index c84ccafaff5..8c05e6fd5d0 100644 --- a/compiler/rustc_mir/src/borrow_check/invalidation.rs +++ b/compiler/rustc_mir/src/borrow_check/invalidation.rs @@ -117,7 +117,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> { self.check_activations(location); match &terminator.kind { - TerminatorKind::SwitchInt { ref discr, switch_ty: _, values: _, targets: _ } => { + TerminatorKind::SwitchInt { ref discr, switch_ty: _, targets: _ } => { self.consume_operand(location, discr); } TerminatorKind::Drop { place: drop_place, target: _, unwind: _ } => { diff --git a/compiler/rustc_mir/src/borrow_check/mod.rs b/compiler/rustc_mir/src/borrow_check/mod.rs index 9b34db1de40..4b7af271bae 100644 --- a/compiler/rustc_mir/src/borrow_check/mod.rs +++ b/compiler/rustc_mir/src/borrow_check/mod.rs @@ -671,7 +671,7 @@ impl<'cx, 'tcx> dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtxt<'cx, 'tc self.check_activations(loc, span, flow_state); match term.kind { - TerminatorKind::SwitchInt { ref discr, switch_ty: _, values: _, targets: _ } => { + TerminatorKind::SwitchInt { ref discr, switch_ty: _, targets: _ } => { self.consume_operand(loc, (discr, span), flow_state); } TerminatorKind::Drop { place: ref drop_place, target: _, unwind: _ } => { diff --git a/compiler/rustc_mir/src/borrow_check/type_check/input_output.rs b/compiler/rustc_mir/src/borrow_check/type_check/input_output.rs index 3c8cbeeca38..444f9fe8d0a 100644 --- a/compiler/rustc_mir/src/borrow_check/type_check/input_output.rs +++ b/compiler/rustc_mir/src/borrow_check/type_check/input_output.rs @@ -73,7 +73,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { ); // Equate expected input tys with those in the MIR. - for (&normalized_input_ty, argument_index) in normalized_input_tys.iter().zip(0..) { + for (argument_index, &normalized_input_ty) in normalized_input_tys.iter().enumerate() { // In MIR, argument N is stored in local N+1. let local = Local::new(argument_index + 1); @@ -87,8 +87,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } if let Some(user_provided_sig) = user_provided_sig { - for (&user_provided_input_ty, argument_index) in - user_provided_sig.inputs().iter().zip(0..) + for (argument_index, &user_provided_input_ty) in + user_provided_sig.inputs().iter().enumerate() { // In MIR, closures begin an implicit `self`, so // argument N is stored in local N+2. diff --git a/compiler/rustc_mir/src/borrow_check/type_check/mod.rs b/compiler/rustc_mir/src/borrow_check/type_check/mod.rs index f8a8801595a..4fc1c570e46 100644 --- a/compiler/rustc_mir/src/borrow_check/type_check/mod.rs +++ b/compiler/rustc_mir/src/borrow_check/type_check/mod.rs @@ -1777,7 +1777,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { self.assert_iscleanup(body, block_data, target, is_cleanup) } TerminatorKind::SwitchInt { ref targets, .. } => { - for target in targets { + for target in targets.all_targets() { self.assert_iscleanup(body, block_data, *target, is_cleanup); } } diff --git a/compiler/rustc_mir/src/const_eval/eval_queries.rs b/compiler/rustc_mir/src/const_eval/eval_queries.rs index 57aa216850a..6ef73b04238 100644 --- a/compiler/rustc_mir/src/const_eval/eval_queries.rs +++ b/compiler/rustc_mir/src/const_eval/eval_queries.rs @@ -343,7 +343,7 @@ pub fn eval_to_allocation_raw_provider<'tcx>( // deny-by-default lint _ => { if let Some(p) = cid.promoted { - let span = tcx.promoted_mir_of_opt_const_arg(def.to_global())[p].span; + let span = tcx.promoted_mir_opt_const_arg(def.to_global())[p].span; if let err_inval!(ReferencedConstant) = err.error { Err(err.report_as_error( tcx.at(span), diff --git a/compiler/rustc_mir/src/const_eval/mod.rs b/compiler/rustc_mir/src/const_eval/mod.rs index 978d2fe0004..4b235e1aa4a 100644 --- a/compiler/rustc_mir/src/const_eval/mod.rs +++ b/compiler/rustc_mir/src/const_eval/mod.rs @@ -50,7 +50,7 @@ pub(crate) fn destructure_const<'tcx>( let (field_count, variant, down) = match val.ty.kind() { ty::Array(_, len) => (usize::try_from(len.eval_usize(tcx, param_env)).unwrap(), None, op), ty::Adt(def, _) if def.variants.is_empty() => { - return mir::DestructuredConst { variant: None, fields: tcx.arena.alloc_slice(&[]) }; + return mir::DestructuredConst { variant: None, fields: &[] }; } ty::Adt(def, _) => { let variant = ecx.read_discriminant(op).unwrap().1; diff --git a/compiler/rustc_mir/src/dataflow/framework/direction.rs b/compiler/rustc_mir/src/dataflow/framework/direction.rs index ca2bb6e0bf7..8a9ced91eb3 100644 --- a/compiler/rustc_mir/src/dataflow/framework/direction.rs +++ b/compiler/rustc_mir/src/dataflow/framework/direction.rs @@ -1,5 +1,5 @@ use rustc_index::bit_set::BitSet; -use rustc_middle::mir::{self, BasicBlock, Location}; +use rustc_middle::mir::{self, BasicBlock, Location, SwitchTargets}; use rustc_middle::ty::TyCtxt; use std::ops::RangeInclusive; @@ -488,11 +488,10 @@ impl Direction for Forward { } } - SwitchInt { ref targets, ref values, ref discr, switch_ty: _ } => { + SwitchInt { ref targets, ref discr, switch_ty: _ } => { let mut applier = SwitchIntEdgeEffectApplier { exit_state, - targets: targets.as_ref(), - values: values.as_ref(), + targets, propagate, effects_applied: false, }; @@ -504,8 +503,8 @@ impl Direction for Forward { } = applier; if !effects_applied { - for &target in targets.iter() { - propagate(target, exit_state); + for target in targets.all_targets() { + propagate(*target, exit_state); } } } @@ -515,8 +514,7 @@ impl Direction for Forward { struct SwitchIntEdgeEffectApplier<'a, D, F> { exit_state: &'a mut D, - values: &'a [u128], - targets: &'a [BasicBlock], + targets: &'a SwitchTargets, propagate: F, effects_applied: bool, @@ -531,7 +529,7 @@ where assert!(!self.effects_applied); let mut tmp = None; - for (&value, &target) in self.values.iter().zip(self.targets.iter()) { + for (value, target) in self.targets.iter() { let tmp = opt_clone_from_or_clone(&mut tmp, self.exit_state); apply_edge_effect(tmp, SwitchIntTarget { value: Some(value), target }); (self.propagate)(target, tmp); @@ -539,7 +537,7 @@ where // Once we get to the final, "otherwise" branch, there is no need to preserve `exit_state`, // so pass it directly to `apply_edge_effect` to save a clone of the dataflow state. - let otherwise = self.targets.last().copied().unwrap(); + let otherwise = self.targets.otherwise(); apply_edge_effect(self.exit_state, SwitchIntTarget { value: None, target: otherwise }); (self.propagate)(otherwise, self.exit_state); diff --git a/compiler/rustc_mir/src/dataflow/framework/engine.rs b/compiler/rustc_mir/src/dataflow/framework/engine.rs index c1e500d01b1..1b7264f86a2 100644 --- a/compiler/rustc_mir/src/dataflow/framework/engine.rs +++ b/compiler/rustc_mir/src/dataflow/framework/engine.rs @@ -62,15 +62,6 @@ where let blocks = mir::traversal::reachable(body); visit_results(body, blocks.map(|(bb, _)| bb), self, vis) } - - pub fn visit_in_rpo_with( - &self, - body: &'mir mir::Body<'tcx>, - vis: &mut impl ResultsVisitor<'mir, 'tcx, FlowState = A::Domain>, - ) { - let blocks = mir::traversal::reverse_postorder(body); - visit_results(body, blocks.map(|(bb, _)| bb), self, vis) - } } /// A solver for dataflow problems. diff --git a/compiler/rustc_mir/src/interpret/cast.rs b/compiler/rustc_mir/src/interpret/cast.rs index 0e16b0caefa..affeae546b2 100644 --- a/compiler/rustc_mir/src/interpret/cast.rs +++ b/compiler/rustc_mir/src/interpret/cast.rs @@ -139,9 +139,14 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // # First handle non-scalar source values. - // Handle cast from a univariant (ZST) enum. + // Handle cast from a ZST enum (0 or 1 variants). match src.layout.variants { Variants::Single { index } => { + if src.layout.abi.is_uninhabited() { + // This is dead code, because an uninhabited enum is UB to + // instantiate. + throw_ub!(Unreachable); + } if let Some(discr) = src.layout.ty.discriminant_for_variant(*self.tcx, index) { assert!(src.layout.is_zst()); let discr_layout = self.layout_of(discr.ty)?; diff --git a/compiler/rustc_mir/src/interpret/eval_context.rs b/compiler/rustc_mir/src/interpret/eval_context.rs index 93da6e3d38a..ec1195d3703 100644 --- a/compiler/rustc_mir/src/interpret/eval_context.rs +++ b/compiler/rustc_mir/src/interpret/eval_context.rs @@ -477,16 +477,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } trace!("load mir(instance={:?}, promoted={:?})", instance, promoted); if let Some(promoted) = promoted { - return Ok(&self.tcx.promoted_mir_of_opt_const_arg(def)[promoted]); + return Ok(&self.tcx.promoted_mir_opt_const_arg(def)[promoted]); } match instance { ty::InstanceDef::Item(def) => { if self.tcx.is_mir_available(def.did) { - if let Some((did, param_did)) = def.as_const_arg() { - Ok(self.tcx.optimized_mir_of_const_arg((did, param_did))) - } else { - Ok(self.tcx.optimized_mir(def.did)) - } + Ok(self.tcx.optimized_mir_opt_const_arg(def)) } else { throw_unsup!(NoMirFor(def.did)) } diff --git a/compiler/rustc_mir/src/interpret/machine.rs b/compiler/rustc_mir/src/interpret/machine.rs index 3718da1723b..66dbacb2f9d 100644 --- a/compiler/rustc_mir/src/interpret/machine.rs +++ b/compiler/rustc_mir/src/interpret/machine.rs @@ -3,6 +3,7 @@ //! interpreting common C functions leak into CTFE. use std::borrow::{Borrow, Cow}; +use std::fmt::Debug; use std::hash::Hash; use rustc_middle::mir; @@ -79,19 +80,19 @@ pub trait AllocMap<K: Hash + Eq, V> { /// and some use case dependent behaviour can instead be applied. pub trait Machine<'mir, 'tcx>: Sized { /// Additional memory kinds a machine wishes to distinguish from the builtin ones - type MemoryKind: ::std::fmt::Debug + ::std::fmt::Display + MayLeak + Eq + 'static; + type MemoryKind: Debug + std::fmt::Display + MayLeak + Eq + 'static; /// Tag tracked alongside every pointer. This is used to implement "Stacked Borrows" /// <https://www.ralfj.de/blog/2018/08/07/stacked-borrows.html>. /// The `default()` is used for pointers to consts, statics, vtables and functions. /// The `Debug` formatting is used for displaying pointers; we cannot use `Display` /// as `()` does not implement that, but it should be "nice" output. - type PointerTag: ::std::fmt::Debug + Copy + Eq + Hash + 'static; + type PointerTag: Debug + Copy + Eq + Hash + 'static; /// Machines can define extra (non-instance) things that represent values of function pointers. /// For example, Miri uses this to return a function pointer from `dlsym` /// that can later be called to execute the right thing. - type ExtraFnVal: ::std::fmt::Debug + Copy; + type ExtraFnVal: Debug + Copy; /// Extra data stored in every call frame. type FrameExtra; diff --git a/compiler/rustc_mir/src/interpret/operand.rs b/compiler/rustc_mir/src/interpret/operand.rs index 735f890a33b..d8f27ec9545 100644 --- a/compiler/rustc_mir/src/interpret/operand.rs +++ b/compiler/rustc_mir/src/interpret/operand.rs @@ -133,7 +133,7 @@ impl<Tag: Copy> std::fmt::Display for ImmTy<'tcx, Tag> { } } -impl<'tcx, Tag> ::std::ops::Deref for ImmTy<'tcx, Tag> { +impl<'tcx, Tag> std::ops::Deref for ImmTy<'tcx, Tag> { type Target = Immediate<Tag>; #[inline(always)] fn deref(&self) -> &Immediate<Tag> { @@ -156,7 +156,7 @@ pub struct OpTy<'tcx, Tag = ()> { pub layout: TyAndLayout<'tcx>, } -impl<'tcx, Tag> ::std::ops::Deref for OpTy<'tcx, Tag> { +impl<'tcx, Tag> std::ops::Deref for OpTy<'tcx, Tag> { type Target = Operand<Tag>; #[inline(always)] fn deref(&self) -> &Operand<Tag> { @@ -340,7 +340,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { pub fn read_str(&self, mplace: MPlaceTy<'tcx, M::PointerTag>) -> InterpResult<'tcx, &str> { let len = mplace.len(self)?; let bytes = self.memory.read_bytes(mplace.ptr, Size::from_bytes(len))?; - let str = ::std::str::from_utf8(bytes).map_err(|err| err_ub!(InvalidStr(err)))?; + let str = std::str::from_utf8(bytes).map_err(|err| err_ub!(InvalidStr(err)))?; Ok(str) } diff --git a/compiler/rustc_mir/src/interpret/place.rs b/compiler/rustc_mir/src/interpret/place.rs index 72551b23370..fe25f8ce962 100644 --- a/compiler/rustc_mir/src/interpret/place.rs +++ b/compiler/rustc_mir/src/interpret/place.rs @@ -3,6 +3,7 @@ //! All high-level functions to write to memory work on places as destinations. use std::convert::TryFrom; +use std::fmt::Debug; use std::hash::Hash; use rustc_macros::HashStable; @@ -86,7 +87,7 @@ pub struct PlaceTy<'tcx, Tag = ()> { pub layout: TyAndLayout<'tcx>, } -impl<'tcx, Tag> ::std::ops::Deref for PlaceTy<'tcx, Tag> { +impl<'tcx, Tag> std::ops::Deref for PlaceTy<'tcx, Tag> { type Target = Place<Tag>; #[inline(always)] fn deref(&self) -> &Place<Tag> { @@ -101,7 +102,7 @@ pub struct MPlaceTy<'tcx, Tag = ()> { pub layout: TyAndLayout<'tcx>, } -impl<'tcx, Tag> ::std::ops::Deref for MPlaceTy<'tcx, Tag> { +impl<'tcx, Tag> std::ops::Deref for MPlaceTy<'tcx, Tag> { type Target = MemPlace<Tag>; #[inline(always)] fn deref(&self) -> &MemPlace<Tag> { @@ -226,7 +227,7 @@ impl<'tcx, Tag> MPlaceTy<'tcx, Tag> { } // These are defined here because they produce a place. -impl<'tcx, Tag: ::std::fmt::Debug + Copy> OpTy<'tcx, Tag> { +impl<'tcx, Tag: Debug + Copy> OpTy<'tcx, Tag> { #[inline(always)] /// Note: do not call `as_ref` on the resulting place. This function should only be used to /// read from the resulting mplace, not to get its address back. @@ -251,7 +252,7 @@ impl<'tcx, Tag: ::std::fmt::Debug + Copy> OpTy<'tcx, Tag> { } } -impl<Tag: ::std::fmt::Debug> Place<Tag> { +impl<Tag: Debug> Place<Tag> { #[inline] pub fn assert_mem_place(self) -> MemPlace<Tag> { match self { @@ -261,7 +262,7 @@ impl<Tag: ::std::fmt::Debug> Place<Tag> { } } -impl<'tcx, Tag: ::std::fmt::Debug> PlaceTy<'tcx, Tag> { +impl<'tcx, Tag: Debug> PlaceTy<'tcx, Tag> { #[inline] pub fn assert_mem_place(self) -> MPlaceTy<'tcx, Tag> { MPlaceTy { mplace: self.place.assert_mem_place(), layout: self.layout } @@ -272,7 +273,7 @@ impl<'tcx, Tag: ::std::fmt::Debug> PlaceTy<'tcx, Tag> { impl<'mir, 'tcx: 'mir, Tag, M> InterpCx<'mir, 'tcx, M> where // FIXME: Working around https://github.com/rust-lang/rust/issues/54385 - Tag: ::std::fmt::Debug + Copy + Eq + Hash + 'static, + Tag: Debug + Copy + Eq + Hash + 'static, M: Machine<'mir, 'tcx, PointerTag = Tag>, // FIXME: Working around https://github.com/rust-lang/rust/issues/24159 M::MemoryMap: AllocMap<AllocId, (MemoryKind<M::MemoryKind>, Allocation<Tag, M::AllocExtra>)>, diff --git a/compiler/rustc_mir/src/interpret/terminator.rs b/compiler/rustc_mir/src/interpret/terminator.rs index 9f200ca62b8..bb11c2a23bd 100644 --- a/compiler/rustc_mir/src/interpret/terminator.rs +++ b/compiler/rustc_mir/src/interpret/terminator.rs @@ -24,16 +24,16 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Goto { target } => self.go_to_block(target), - SwitchInt { ref discr, ref values, ref targets, switch_ty } => { + SwitchInt { ref discr, ref targets, switch_ty } => { let discr = self.read_immediate(self.eval_operand(discr, None)?)?; trace!("SwitchInt({:?})", *discr); assert_eq!(discr.layout.ty, switch_ty); // Branch to the `otherwise` case by default, if no match is found. - assert!(!targets.is_empty()); - let mut target_block = targets[targets.len() - 1]; + assert!(!targets.iter().is_empty()); + let mut target_block = targets.otherwise(); - for (index, &const_int) in values.iter().enumerate() { + for (const_int, target) in targets.iter() { // Compare using binary_op, to also support pointer values let res = self .overflowing_binary_op( @@ -43,7 +43,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { )? .0; if res.to_bool()? { - target_block = targets[index]; + target_block = target; break; } } diff --git a/compiler/rustc_mir/src/monomorphize/collector.rs b/compiler/rustc_mir/src/monomorphize/collector.rs index 7e12cc9176e..417176564b9 100644 --- a/compiler/rustc_mir/src/monomorphize/collector.rs +++ b/compiler/rustc_mir/src/monomorphize/collector.rs @@ -197,6 +197,7 @@ use rustc_session::config::EntryFnType; use rustc_span::source_map::{dummy_spanned, respan, Span, Spanned, DUMMY_SP}; use smallvec::SmallVec; use std::iter; +use std::ops::Range; use std::path::PathBuf; #[derive(PartialEq)] @@ -210,9 +211,8 @@ pub enum MonoItemCollectionMode { pub struct InliningMap<'tcx> { // Maps a source mono item to the range of mono items // accessed by it. - // The two numbers in the tuple are the start (inclusive) and - // end index (exclusive) within the `targets` vecs. - index: FxHashMap<MonoItem<'tcx>, (usize, usize)>, + // The range selects elements within the `targets` vecs. + index: FxHashMap<MonoItem<'tcx>, Range<usize>>, targets: Vec<MonoItem<'tcx>>, // Contains one bit per mono item in the `targets` field. That bit @@ -245,7 +245,7 @@ impl<'tcx> InliningMap<'tcx> { } let end_index = self.targets.len(); - assert!(self.index.insert(source, (start_index, end_index)).is_none()); + assert!(self.index.insert(source, start_index..end_index).is_none()); } // Internally iterate over all items referenced by `source` which will be @@ -254,9 +254,9 @@ impl<'tcx> InliningMap<'tcx> { where F: FnMut(MonoItem<'tcx>), { - if let Some(&(start_index, end_index)) = self.index.get(&source) { - for (i, candidate) in self.targets[start_index..end_index].iter().enumerate() { - if self.inlines.contains(start_index + i) { + if let Some(range) = self.index.get(&source) { + for (i, candidate) in self.targets[range.clone()].iter().enumerate() { + if self.inlines.contains(range.start + i) { f(*candidate); } } @@ -268,8 +268,8 @@ impl<'tcx> InliningMap<'tcx> { where F: FnMut(MonoItem<'tcx>, &[MonoItem<'tcx>]), { - for (&accessor, &(start_index, end_index)) in &self.index { - f(accessor, &self.targets[start_index..end_index]) + for (&accessor, range) in &self.index { + f(accessor, &self.targets[range.clone()]) } } } diff --git a/compiler/rustc_mir/src/monomorphize/partitioning/default.rs b/compiler/rustc_mir/src/monomorphize/partitioning/default.rs index 3c89111a659..5083a45b539 100644 --- a/compiler/rustc_mir/src/monomorphize/partitioning/default.rs +++ b/compiler/rustc_mir/src/monomorphize/partitioning/default.rs @@ -532,7 +532,7 @@ fn mono_item_visibility( } fn default_visibility(tcx: TyCtxt<'_>, id: DefId, is_generic: bool) -> Visibility { - if !tcx.sess.target.target.options.default_hidden_visibility { + if !tcx.sess.target.options.default_hidden_visibility { return Visibility::Default; } diff --git a/compiler/rustc_mir/src/transform/check_const_item_mutation.rs b/compiler/rustc_mir/src/transform/check_const_item_mutation.rs index 26993a6b941..fb89b36060a 100644 --- a/compiler/rustc_mir/src/transform/check_const_item_mutation.rs +++ b/compiler/rustc_mir/src/transform/check_const_item_mutation.rs @@ -53,7 +53,7 @@ impl<'a, 'tcx> ConstMutationChecker<'a, 'tcx> { // // #[const_mutation_allowed] // pub const LOG: Log = Log { msg: "" }; - match self.tcx.calculate_dtor(def_id, &mut |_, _| Ok(())) { + match self.tcx.calculate_dtor(def_id, |_, _| Ok(())) { Some(_) => None, None => Some(def_id), } diff --git a/compiler/rustc_mir/src/transform/copy_prop.rs b/compiler/rustc_mir/src/transform/copy_prop.rs deleted file mode 100644 index 4f44bb7b204..00000000000 --- a/compiler/rustc_mir/src/transform/copy_prop.rs +++ /dev/null @@ -1,384 +0,0 @@ -//! Trivial copy propagation pass. -//! -//! This uses def-use analysis to remove values that have exactly one def and one use, which must -//! be an assignment. -//! -//! To give an example, we look for patterns that look like: -//! -//! DEST = SRC -//! ... -//! USE(DEST) -//! -//! where `DEST` and `SRC` are both locals of some form. We replace that with: -//! -//! NOP -//! ... -//! USE(SRC) -//! -//! The assignment `DEST = SRC` must be (a) the only mutation of `DEST` and (b) the only -//! (non-mutating) use of `SRC`. These restrictions are conservative and may be relaxed in the -//! future. - -use crate::transform::MirPass; -use crate::util::def_use::DefUseAnalysis; -use rustc_middle::mir::visit::MutVisitor; -use rustc_middle::mir::{ - Body, Constant, Local, LocalKind, Location, Operand, Place, Rvalue, StatementKind, -}; -use rustc_middle::ty::TyCtxt; - -pub struct CopyPropagation; - -impl<'tcx> MirPass<'tcx> for CopyPropagation { - fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - let opts = &tcx.sess.opts.debugging_opts; - // We only run when the MIR optimization level is > 1. - // This avoids a slow pass, and messing up debug info. - // FIXME(76740): This optimization is buggy and can cause unsoundness. - if opts.mir_opt_level <= 1 || !opts.unsound_mir_opts { - return; - } - - let mut def_use_analysis = DefUseAnalysis::new(body); - loop { - def_use_analysis.analyze(body); - - if eliminate_self_assignments(body, &def_use_analysis) { - def_use_analysis.analyze(body); - } - - let mut changed = false; - for dest_local in body.local_decls.indices() { - debug!("considering destination local: {:?}", dest_local); - - let action; - let location; - { - // The destination must have exactly one def. - let dest_use_info = def_use_analysis.local_info(dest_local); - let dest_def_count = dest_use_info.def_count_not_including_drop(); - if dest_def_count == 0 { - debug!(" Can't copy-propagate local: dest {:?} undefined", dest_local); - continue; - } - if dest_def_count > 1 { - debug!( - " Can't copy-propagate local: dest {:?} defined {} times", - dest_local, - dest_use_info.def_count() - ); - continue; - } - if dest_use_info.use_count() == 0 { - debug!(" Can't copy-propagate local: dest {:?} unused", dest_local); - continue; - } - // Conservatively gives up if the dest is an argument, - // because there may be uses of the original argument value. - // Also gives up on the return place, as we cannot propagate into its implicit - // use by `return`. - if matches!( - body.local_kind(dest_local), - LocalKind::Arg | LocalKind::ReturnPointer - ) { - debug!(" Can't copy-propagate local: dest {:?} (argument)", dest_local); - continue; - } - let dest_place_def = dest_use_info.defs_not_including_drop().next().unwrap(); - location = dest_place_def.location; - - let basic_block = &body[location.block]; - let statement_index = location.statement_index; - let statement = match basic_block.statements.get(statement_index) { - Some(statement) => statement, - None => { - debug!(" Can't copy-propagate local: used in terminator"); - continue; - } - }; - - // That use of the source must be an assignment. - match &statement.kind { - StatementKind::Assign(box (place, Rvalue::Use(operand))) => { - if let Some(local) = place.as_local() { - if local == dest_local { - let maybe_action = match operand { - Operand::Copy(src_place) | Operand::Move(src_place) => { - Action::local_copy(&body, &def_use_analysis, *src_place) - } - Operand::Constant(ref src_constant) => { - Action::constant(src_constant) - } - }; - match maybe_action { - Some(this_action) => action = this_action, - None => continue, - } - } else { - debug!( - " Can't copy-propagate local: source use is not an \ - assignment" - ); - continue; - } - } else { - debug!( - " Can't copy-propagate local: source use is not an \ - assignment" - ); - continue; - } - } - _ => { - debug!( - " Can't copy-propagate local: source use is not an \ - assignment" - ); - continue; - } - } - } - - changed = - action.perform(body, &def_use_analysis, dest_local, location, tcx) || changed; - // FIXME(pcwalton): Update the use-def chains to delete the instructions instead of - // regenerating the chains. - break; - } - if !changed { - break; - } - } - } -} - -fn eliminate_self_assignments(body: &mut Body<'_>, def_use_analysis: &DefUseAnalysis) -> bool { - let mut changed = false; - - for dest_local in body.local_decls.indices() { - let dest_use_info = def_use_analysis.local_info(dest_local); - - for def in dest_use_info.defs_not_including_drop() { - let location = def.location; - if let Some(stmt) = body[location.block].statements.get(location.statement_index) { - match &stmt.kind { - StatementKind::Assign(box ( - place, - Rvalue::Use(Operand::Copy(src_place) | Operand::Move(src_place)), - )) => { - if let (Some(local), Some(src_local)) = - (place.as_local(), src_place.as_local()) - { - if local == dest_local && dest_local == src_local { - } else { - continue; - } - } else { - continue; - } - } - _ => { - continue; - } - } - } else { - continue; - } - debug!("deleting a self-assignment for {:?}", dest_local); - body.make_statement_nop(location); - changed = true; - } - } - - changed -} - -enum Action<'tcx> { - PropagateLocalCopy(Local), - PropagateConstant(Constant<'tcx>), -} - -impl<'tcx> Action<'tcx> { - fn local_copy( - body: &Body<'tcx>, - def_use_analysis: &DefUseAnalysis, - src_place: Place<'tcx>, - ) -> Option<Action<'tcx>> { - // The source must be a local. - let src_local = if let Some(local) = src_place.as_local() { - local - } else { - debug!(" Can't copy-propagate local: source is not a local"); - return None; - }; - - // We're trying to copy propagate a local. - // There must be exactly one use of the source used in a statement (not in a terminator). - let src_use_info = def_use_analysis.local_info(src_local); - let src_use_count = src_use_info.use_count(); - if src_use_count == 0 { - debug!(" Can't copy-propagate local: no uses"); - return None; - } - if src_use_count != 1 { - debug!(" Can't copy-propagate local: {} uses", src_use_info.use_count()); - return None; - } - - // Verify that the source doesn't change in between. This is done conservatively for now, - // by ensuring that the source has exactly one mutation. The goal is to prevent things - // like: - // - // DEST = SRC; - // SRC = X; - // USE(DEST); - // - // From being misoptimized into: - // - // SRC = X; - // USE(SRC); - let src_def_count = src_use_info.def_count_not_including_drop(); - // allow function arguments to be propagated - let is_arg = body.local_kind(src_local) == LocalKind::Arg; - if (is_arg && src_def_count != 0) || (!is_arg && src_def_count != 1) { - debug!( - " Can't copy-propagate local: {} defs of src{}", - src_def_count, - if is_arg { " (argument)" } else { "" }, - ); - return None; - } - - Some(Action::PropagateLocalCopy(src_local)) - } - - fn constant(src_constant: &Constant<'tcx>) -> Option<Action<'tcx>> { - Some(Action::PropagateConstant(*src_constant)) - } - - fn perform( - self, - body: &mut Body<'tcx>, - def_use_analysis: &DefUseAnalysis, - dest_local: Local, - location: Location, - tcx: TyCtxt<'tcx>, - ) -> bool { - match self { - Action::PropagateLocalCopy(src_local) => { - // Eliminate the destination and the assignment. - // - // First, remove all markers. - // - // FIXME(pcwalton): Don't do this. Merge live ranges instead. - debug!(" Replacing all uses of {:?} with {:?} (local)", dest_local, src_local); - for place_use in &def_use_analysis.local_info(dest_local).defs_and_uses { - if place_use.context.is_storage_marker() { - body.make_statement_nop(place_use.location) - } - } - for place_use in &def_use_analysis.local_info(src_local).defs_and_uses { - if place_use.context.is_storage_marker() { - body.make_statement_nop(place_use.location) - } - } - - // Replace all uses of the destination local with the source local. - def_use_analysis.replace_all_defs_and_uses_with(dest_local, body, src_local, tcx); - - // Finally, zap the now-useless assignment instruction. - debug!(" Deleting assignment"); - body.make_statement_nop(location); - - true - } - Action::PropagateConstant(src_constant) => { - // First, remove all markers. - // - // FIXME(pcwalton): Don't do this. Merge live ranges instead. - debug!( - " Replacing all uses of {:?} with {:?} (constant)", - dest_local, src_constant - ); - let dest_local_info = def_use_analysis.local_info(dest_local); - for place_use in &dest_local_info.defs_and_uses { - if place_use.context.is_storage_marker() { - body.make_statement_nop(place_use.location) - } - } - - // Replace all uses of the destination local with the constant. - let mut visitor = ConstantPropagationVisitor::new(dest_local, src_constant, tcx); - for dest_place_use in &dest_local_info.defs_and_uses { - visitor.visit_location(body, dest_place_use.location) - } - - // Zap the assignment instruction if we eliminated all the uses. We won't have been - // able to do that if the destination was used in a projection, because projections - // must have places on their LHS. - let use_count = dest_local_info.use_count(); - if visitor.uses_replaced == use_count { - debug!( - " {} of {} use(s) replaced; deleting assignment", - visitor.uses_replaced, use_count - ); - body.make_statement_nop(location); - true - } else if visitor.uses_replaced == 0 { - debug!(" No uses replaced; not deleting assignment"); - false - } else { - debug!( - " {} of {} use(s) replaced; not deleting assignment", - visitor.uses_replaced, use_count - ); - true - } - } - } - } -} - -struct ConstantPropagationVisitor<'tcx> { - dest_local: Local, - constant: Constant<'tcx>, - tcx: TyCtxt<'tcx>, - uses_replaced: usize, -} - -impl<'tcx> ConstantPropagationVisitor<'tcx> { - fn new( - dest_local: Local, - constant: Constant<'tcx>, - tcx: TyCtxt<'tcx>, - ) -> ConstantPropagationVisitor<'tcx> { - ConstantPropagationVisitor { dest_local, constant, tcx, uses_replaced: 0 } - } -} - -impl<'tcx> MutVisitor<'tcx> for ConstantPropagationVisitor<'tcx> { - fn tcx(&self) -> TyCtxt<'tcx> { - self.tcx - } - - fn visit_operand(&mut self, operand: &mut Operand<'tcx>, location: Location) { - self.super_operand(operand, location); - - match operand { - Operand::Copy(place) | Operand::Move(place) => { - if let Some(local) = place.as_local() { - if local == self.dest_local { - } else { - return; - } - } else { - return; - } - } - _ => return, - } - - *operand = Operand::Constant(box self.constant); - self.uses_replaced += 1 - } -} diff --git a/compiler/rustc_mir/src/transform/early_otherwise_branch.rs b/compiler/rustc_mir/src/transform/early_otherwise_branch.rs index 237a5c7864b..f97dcf4852d 100644 --- a/compiler/rustc_mir/src/transform/early_otherwise_branch.rs +++ b/compiler/rustc_mir/src/transform/early_otherwise_branch.rs @@ -1,7 +1,7 @@ use crate::{transform::MirPass, util::patch::MirPatch}; use rustc_middle::mir::*; use rustc_middle::ty::{Ty, TyCtxt}; -use std::{borrow::Cow, fmt::Debug}; +use std::fmt::Debug; use super::simplify::simplify_cfg; @@ -95,15 +95,17 @@ impl<'tcx> MirPass<'tcx> for EarlyOtherwiseBranch { StatementKind::Assign(box (Place::from(not_equal_temp), not_equal_rvalue)), ); - let (mut targets_to_jump_to, values_to_jump_to): (Vec<_>, Vec<_>) = opt_to_apply + let new_targets = opt_to_apply .infos .iter() .flat_map(|x| x.second_switch_info.targets_with_values.iter()) - .cloned() - .unzip(); + .cloned(); + + let targets = SwitchTargets::new( + new_targets, + opt_to_apply.infos[0].first_switch_info.otherwise_bb, + ); - // add otherwise case in the end - targets_to_jump_to.push(opt_to_apply.infos[0].first_switch_info.otherwise_bb); // new block that jumps to the correct discriminant case. This block is switched to if the discriminants are equal let new_switch_data = BasicBlockData::new(Some(Terminator { source_info: opt_to_apply.infos[0].second_switch_info.discr_source_info, @@ -111,8 +113,7 @@ impl<'tcx> MirPass<'tcx> for EarlyOtherwiseBranch { // the first and second discriminants are equal, so just pick one discr: Operand::Copy(first_descriminant_place), switch_ty: discr_type, - values: Cow::from(values_to_jump_to), - targets: targets_to_jump_to, + targets, }, })); @@ -176,7 +177,7 @@ struct SwitchDiscriminantInfo<'tcx> { /// The basic block that the otherwise branch points to otherwise_bb: BasicBlock, /// Target along with the value being branched from. Otherwise is not included - targets_with_values: Vec<(BasicBlock, u128)>, + targets_with_values: Vec<(u128, BasicBlock)>, discr_source_info: SourceInfo, /// The place of the discriminant used in the switch discr_used_in_switch: Place<'tcx>, @@ -211,7 +212,7 @@ impl<'a, 'tcx> Helper<'a, 'tcx> { let discr = self.find_switch_discriminant_info(bb, switch)?; // go through each target, finding a discriminant read, and a switch - let results = discr.targets_with_values.iter().map(|(target, value)| { + let results = discr.targets_with_values.iter().map(|(value, target)| { self.find_discriminant_switch_pairing(&discr, target.clone(), value.clone()) }); @@ -253,7 +254,7 @@ impl<'a, 'tcx> Helper<'a, 'tcx> { } // check that the value being matched on is the same. The - if this_bb_discr_info.targets_with_values.iter().find(|x| x.1 == value).is_none() { + if this_bb_discr_info.targets_with_values.iter().find(|x| x.0 == value).is_none() { trace!("NO: values being matched on are not the same"); return None; } @@ -270,7 +271,7 @@ impl<'a, 'tcx> Helper<'a, 'tcx> { // ``` // We check this by seeing that the value of the first discriminant is the only other discriminant value being used as a target in the second switch if !(this_bb_discr_info.targets_with_values.len() == 1 - && this_bb_discr_info.targets_with_values[0].1 == value) + && this_bb_discr_info.targets_with_values[0].0 == value) { trace!( "NO: The second switch did not have only 1 target (besides otherwise) that had the same value as the value from the first switch that got us here" @@ -296,18 +297,14 @@ impl<'a, 'tcx> Helper<'a, 'tcx> { switch: &Terminator<'tcx>, ) -> Option<SwitchDiscriminantInfo<'tcx>> { match &switch.kind { - TerminatorKind::SwitchInt { discr, targets, values, .. } => { + TerminatorKind::SwitchInt { discr, targets, .. } => { let discr_local = discr.place()?.as_local()?; // the declaration of the discriminant read. Place of this read is being used in the switch let discr_decl = &self.body.local_decls()[discr_local]; let discr_ty = discr_decl.ty; // the otherwise target lies as the last element - let otherwise_bb = targets.get(values.len())?.clone(); - let targets_with_values = targets - .iter() - .zip(values.iter()) - .map(|(t, v)| (t.clone(), v.clone())) - .collect(); + let otherwise_bb = targets.otherwise(); + let targets_with_values = targets.iter().collect(); // find the place of the adt where the discriminant is being read from // assume this is the last statement of the block diff --git a/compiler/rustc_mir/src/transform/generator.rs b/compiler/rustc_mir/src/transform/generator.rs index 924bb4996fc..039d4753a8c 100644 --- a/compiler/rustc_mir/src/transform/generator.rs +++ b/compiler/rustc_mir/src/transform/generator.rs @@ -71,7 +71,6 @@ use rustc_middle::ty::GeneratorSubsts; use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt}; use rustc_target::abi::VariantIdx; use rustc_target::spec::PanicStrategy; -use std::borrow::Cow; use std::{iter, ops}; pub struct StateTransform; @@ -839,11 +838,12 @@ fn insert_switch<'tcx>( ) { let default_block = insert_term_block(body, default); let (assign, discr) = transform.get_discr(body); + let switch_targets = + SwitchTargets::new(cases.iter().map(|(i, bb)| ((*i) as u128, *bb)), default_block); let switch = TerminatorKind::SwitchInt { discr: Operand::Move(discr), switch_ty: transform.discr_ty, - values: Cow::from(cases.iter().map(|&(i, _)| i as u128).collect::<Vec<_>>()), - targets: cases.iter().map(|&(_, d)| d).chain(iter::once(default_block)).collect(), + targets: switch_targets, }; let source_info = SourceInfo::outermost(body.span); diff --git a/compiler/rustc_mir/src/transform/inline.rs b/compiler/rustc_mir/src/transform/inline.rs index bec1eb79047..796ad6c9c29 100644 --- a/compiler/rustc_mir/src/transform/inline.rs +++ b/compiler/rustc_mir/src/transform/inline.rs @@ -201,9 +201,13 @@ impl Inliner<'tcx> { let terminator = bb_data.terminator(); if let TerminatorKind::Call { func: ref op, .. } = terminator.kind { if let ty::FnDef(callee_def_id, substs) = *op.ty(caller_body, self.tcx).kind() { - let instance = Instance::resolve(self.tcx, self.param_env, callee_def_id, substs) - .ok() - .flatten()?; + // To resolve an instance its substs have to be fully normalized, so + // we do this here. + let normalized_substs = self.tcx.normalize_erasing_regions(self.param_env, substs); + let instance = + Instance::resolve(self.tcx, self.param_env, callee_def_id, normalized_substs) + .ok() + .flatten()?; if let InstanceDef::Virtual(..) = instance.def { return None; @@ -771,7 +775,7 @@ impl<'a, 'tcx> MutVisitor<'tcx> for Integrator<'a, 'tcx> { *target = self.update_target(*target); } TerminatorKind::SwitchInt { ref mut targets, .. } => { - for tgt in targets { + for tgt in targets.all_targets_mut() { *tgt = self.update_target(*tgt); } } diff --git a/compiler/rustc_mir/src/transform/instrument_coverage.rs b/compiler/rustc_mir/src/transform/instrument_coverage.rs index babe10a0f14..6824c73ab60 100644 --- a/compiler/rustc_mir/src/transform/instrument_coverage.rs +++ b/compiler/rustc_mir/src/transform/instrument_coverage.rs @@ -22,9 +22,7 @@ use rustc_middle::ty::query::Providers; use rustc_middle::ty::TyCtxt; use rustc_span::def_id::DefId; use rustc_span::source_map::original_sp; -use rustc_span::{ - BytePos, CharPos, FileName, Pos, RealFileName, SourceFile, Span, Symbol, SyntaxContext, -}; +use rustc_span::{BytePos, CharPos, Pos, SourceFile, Span, Symbol, SyntaxContext}; use std::cmp::Ordering; @@ -549,13 +547,7 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> { let mir_body = &self.mir_body; let body_span = self.body_span(); let source_file = source_map.lookup_source_file(body_span.lo()); - let file_name = match &source_file.name { - FileName::Real(RealFileName::Named(path)) => Symbol::intern(&path.to_string_lossy()), - _ => bug!( - "source_file.name should be a RealFileName, but it was: {:?}", - source_file.name - ), - }; + let file_name = Symbol::intern(&source_file.name.to_string()); debug!("instrumenting {:?}, span: {}", def_id, source_map.span_to_string(body_span)); diff --git a/compiler/rustc_mir/src/transform/match_branches.rs b/compiler/rustc_mir/src/transform/match_branches.rs index dad3812c5cd..8b2d6b09aa8 100644 --- a/compiler/rustc_mir/src/transform/match_branches.rs +++ b/compiler/rustc_mir/src/transform/match_branches.rs @@ -46,10 +46,13 @@ impl<'tcx> MirPass<'tcx> for MatchBranchSimplification { discr: Operand::Copy(ref place) | Operand::Move(ref place), switch_ty, ref targets, - ref values, .. - } if targets.len() == 2 && values.len() == 1 && targets[0] != targets[1] => { - (place, values[0], switch_ty, targets[0], targets[1]) + } if targets.iter().len() == 1 => { + let (value, target) = targets.iter().next().unwrap(); + if target == targets.otherwise() { + continue; + } + (place, value, switch_ty, target, targets.otherwise()) } // Only optimize switch int statements _ => continue, diff --git a/compiler/rustc_mir/src/transform/mod.rs b/compiler/rustc_mir/src/transform/mod.rs index b4f5947f5a3..20b8c90a9dc 100644 --- a/compiler/rustc_mir/src/transform/mod.rs +++ b/compiler/rustc_mir/src/transform/mod.rs @@ -22,7 +22,6 @@ pub mod check_packed_ref; pub mod check_unsafety; pub mod cleanup_post_borrowck; pub mod const_prop; -pub mod copy_prop; pub mod deaggregator; pub mod dest_prop; pub mod dump_mir; @@ -137,7 +136,7 @@ fn mir_keys(tcx: TyCtxt<'_>, krate: CrateNum) -> FxHashSet<LocalDefId> { /// Generates a default name for the pass based on the name of the /// type `T`. pub fn default_name<T: ?Sized>() -> Cow<'static, str> { - let name = ::std::any::type_name::<T>(); + let name = std::any::type_name::<T>(); if let Some(tail) = name.rfind(':') { Cow::from(&name[tail + 1..]) } else { Cow::from(name) } } @@ -287,11 +286,7 @@ fn mir_promoted( // this point, before we steal the mir-const result. // Also this means promotion can rely on all const checks having been done. let _ = tcx.mir_const_qualif_opt_const_arg(def); - let _ = if let Some(param_did) = def.const_param_did { - tcx.mir_abstract_const_of_const_arg((def.did, param_did)) - } else { - tcx.mir_abstract_const(def.did.to_def_id()) - }; + let _ = tcx.mir_abstract_const_opt_const_arg(def.to_global()); let mut body = tcx.mir_const(def).steal(); let mut required_consts = Vec::new(); @@ -405,8 +400,7 @@ fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { &simplify_try::SimplifyArmIdentity, &simplify_try::SimplifyBranchSame, &dest_prop::DestinationPropagation, - ©_prop::CopyPropagation, - &simplify_branches::SimplifyBranches::new("after-copy-prop"), + &simplify_branches::SimplifyBranches::new("final"), &remove_noop_landing_pads::RemoveNoopLandingPads, &simplify::SimplifyCfg::new("final"), &nrvo::RenameReturnPlace, diff --git a/compiler/rustc_mir/src/transform/promote_consts.rs b/compiler/rustc_mir/src/transform/promote_consts.rs index 7abc998d388..7373abcc820 100644 --- a/compiler/rustc_mir/src/transform/promote_consts.rs +++ b/compiler/rustc_mir/src/transform/promote_consts.rs @@ -124,6 +124,15 @@ impl Candidate { Candidate::Argument { .. } | Candidate::InlineAsm { .. } => true, } } + + fn source_info(&self, body: &Body<'_>) -> SourceInfo { + match self { + Candidate::Ref(location) | Candidate::Repeat(location) => *body.source_info(*location), + Candidate::Argument { bb, .. } | Candidate::InlineAsm { bb, .. } => { + *body.source_info(body.terminator_loc(*bb)) + } + } + } } fn args_required_const(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Vec<usize>> { @@ -953,6 +962,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { from_hir_call, fn_span, }, + source_info: SourceInfo::outermost(terminator.source_info.span), ..terminator }; } @@ -1163,12 +1173,13 @@ pub fn promote_candidates<'tcx>( // Declare return place local so that `mir::Body::new` doesn't complain. let initial_locals = iter::once(LocalDecl::new(tcx.types.never, body.span)).collect(); + let mut scope = body.source_scopes[candidate.source_info(body).scope].clone(); + scope.parent_scope = None; + let mut promoted = Body::new( body.source, // `promoted` gets filled in below IndexVec::new(), - // FIXME: maybe try to filter this to avoid blowing up - // memory usage? - body.source_scopes.clone(), + IndexVec::from_elem_n(scope, 1), initial_locals, IndexVec::new(), 0, diff --git a/compiler/rustc_mir/src/transform/simplify_branches.rs b/compiler/rustc_mir/src/transform/simplify_branches.rs index 161856a38ee..5f63c03993d 100644 --- a/compiler/rustc_mir/src/transform/simplify_branches.rs +++ b/compiler/rustc_mir/src/transform/simplify_branches.rs @@ -29,17 +29,16 @@ impl<'tcx> MirPass<'tcx> for SimplifyBranches { TerminatorKind::SwitchInt { discr: Operand::Constant(ref c), switch_ty, - ref values, ref targets, .. } => { let constant = c.literal.try_eval_bits(tcx, param_env, switch_ty); if let Some(constant) = constant { - let (otherwise, targets) = targets.split_last().unwrap(); - let mut ret = TerminatorKind::Goto { target: *otherwise }; - for (&v, t) in values.iter().zip(targets.iter()) { + let otherwise = targets.otherwise(); + let mut ret = TerminatorKind::Goto { target: otherwise }; + for (v, t) in targets.iter() { if v == constant { - ret = TerminatorKind::Goto { target: *t }; + ret = TerminatorKind::Goto { target: t }; break; } } diff --git a/compiler/rustc_mir/src/transform/simplify_comparison_integral.rs b/compiler/rustc_mir/src/transform/simplify_comparison_integral.rs index 9f837cf78a6..6372f8960dd 100644 --- a/compiler/rustc_mir/src/transform/simplify_comparison_integral.rs +++ b/compiler/rustc_mir/src/transform/simplify_comparison_integral.rs @@ -1,8 +1,10 @@ +use std::iter; + use super::MirPass; use rustc_middle::{ mir::{ interpret::Scalar, BasicBlock, BinOp, Body, Operand, Place, Rvalue, Statement, - StatementKind, TerminatorKind, + StatementKind, SwitchTargets, TerminatorKind, }, ty::{Ty, TyCtxt}, }; @@ -43,19 +45,21 @@ impl<'tcx> MirPass<'tcx> for SimplifyComparisonIntegral { Scalar::Ptr(_) => continue, }; const FALSE: u128 = 0; - let mut new_targets = opt.targets.clone(); - let first_is_false_target = opt.values[0] == FALSE; + + let mut new_targets = opt.targets; + let first_value = new_targets.iter().next().unwrap().0; + let first_is_false_target = first_value == FALSE; match opt.op { BinOp::Eq => { // if the assignment was Eq we want the true case to be first if first_is_false_target { - new_targets.swap(0, 1); + new_targets.all_targets_mut().swap(0, 1); } } BinOp::Ne => { // if the assignment was Ne we want the false case to be first if !first_is_false_target { - new_targets.swap(0, 1); + new_targets.all_targets_mut().swap(0, 1); } } _ => unreachable!(), @@ -96,7 +100,7 @@ impl<'tcx> MirPass<'tcx> for SimplifyComparisonIntegral { } storage_deads_to_remove.push((stmt_idx, opt.bb_idx)); // if we have StorageDeads to remove then make sure to insert them at the top of each target - for bb_idx in new_targets.iter() { + for bb_idx in new_targets.all_targets() { storage_deads_to_insert.push(( *bb_idx, Statement { @@ -107,13 +111,18 @@ impl<'tcx> MirPass<'tcx> for SimplifyComparisonIntegral { } } - let terminator = bb.terminator_mut(); + let [bb_cond, bb_otherwise] = match new_targets.all_targets() { + [a, b] => [*a, *b], + e => bug!("expected 2 switch targets, got: {:?}", e), + }; + + let targets = SwitchTargets::new(iter::once((new_value, bb_cond)), bb_otherwise); + let terminator = bb.terminator_mut(); terminator.kind = TerminatorKind::SwitchInt { discr: Operand::Move(opt.to_switch_on), switch_ty: opt.branch_value_ty, - values: vec![new_value].into(), - targets: new_targets, + targets, }; } @@ -138,15 +147,13 @@ impl<'a, 'tcx> OptimizationFinder<'a, 'tcx> { .iter_enumerated() .filter_map(|(bb_idx, bb)| { // find switch - let (place_switched_on, values, targets, place_switched_on_moved) = match &bb - .terminator() - .kind - { - rustc_middle::mir::TerminatorKind::SwitchInt { - discr, values, targets, .. - } => Some((discr.place()?, values, targets, discr.is_move())), - _ => None, - }?; + let (place_switched_on, targets, place_switched_on_moved) = + match &bb.terminator().kind { + rustc_middle::mir::TerminatorKind::SwitchInt { discr, targets, .. } => { + Some((discr.place()?, targets, discr.is_move())) + } + _ => None, + }?; // find the statement that assigns the place being switched on bb.statements.iter().enumerate().rev().find_map(|(stmt_idx, stmt)| { @@ -167,7 +174,6 @@ impl<'a, 'tcx> OptimizationFinder<'a, 'tcx> { branch_value_scalar, branch_value_ty, op: *op, - values: values.clone().into_owned(), targets: targets.clone(), }) } @@ -220,8 +226,6 @@ struct OptimizationInfo<'tcx> { branch_value_ty: Ty<'tcx>, /// Either Eq or Ne op: BinOp, - /// Current values used in the switch target. This needs to be replaced with the branch_value - values: Vec<u128>, /// Current targets used in the switch - targets: Vec<BasicBlock>, + targets: SwitchTargets, } diff --git a/compiler/rustc_mir/src/transform/simplify_try.rs b/compiler/rustc_mir/src/transform/simplify_try.rs index a4e7a5a9453..27bb1def726 100644 --- a/compiler/rustc_mir/src/transform/simplify_try.rs +++ b/compiler/rustc_mir/src/transform/simplify_try.rs @@ -576,15 +576,13 @@ impl<'a, 'tcx> SimplifyBranchSameOptimizationFinder<'a, 'tcx> { .iter_enumerated() .filter_map(|(bb_idx, bb)| { let (discr_switched_on, targets_and_values) = match &bb.terminator().kind { - TerminatorKind::SwitchInt { targets, discr, values, .. } => { - // if values.len() == targets.len() - 1, we need to include None where no value is present - // such that the zip does not throw away targets. If no `otherwise` case is in targets, the zip will simply throw away the added None - let values_extended = values.iter().map(|x|Some(*x)).chain(once(None)); - let targets_and_values:Vec<_> = targets.iter().zip(values_extended) - .map(|(target, value)| SwitchTargetAndValue{target:*target, value}) + TerminatorKind::SwitchInt { targets, discr, .. } => { + let targets_and_values: Vec<_> = targets.iter() + .map(|(val, target)| SwitchTargetAndValue { target, value: Some(val) }) + .chain(once(SwitchTargetAndValue { target: targets.otherwise(), value: None })) .collect(); - assert_eq!(targets.len(), targets_and_values.len()); - (discr, targets_and_values)}, + (discr, targets_and_values) + }, _ => return None, }; diff --git a/compiler/rustc_mir/src/transform/uninhabited_enum_branching.rs b/compiler/rustc_mir/src/transform/uninhabited_enum_branching.rs index 87906e83ed5..465832c89fd 100644 --- a/compiler/rustc_mir/src/transform/uninhabited_enum_branching.rs +++ b/compiler/rustc_mir/src/transform/uninhabited_enum_branching.rs @@ -3,7 +3,8 @@ use crate::transform::MirPass; use rustc_data_structures::stable_set::FxHashSet; use rustc_middle::mir::{ - BasicBlock, BasicBlockData, Body, Local, Operand, Rvalue, StatementKind, TerminatorKind, + BasicBlock, BasicBlockData, Body, Local, Operand, Rvalue, StatementKind, SwitchTargets, + TerminatorKind, }; use rustc_middle::ty::layout::TyAndLayout; use rustc_middle::ty::{Ty, TyCtxt}; @@ -101,21 +102,15 @@ impl<'tcx> MirPass<'tcx> for UninhabitedEnumBranching { trace!("allowed_variants = {:?}", allowed_variants); - if let TerminatorKind::SwitchInt { values, targets, .. } = + if let TerminatorKind::SwitchInt { targets, .. } = &mut body.basic_blocks_mut()[bb].terminator_mut().kind { - // take otherwise out early - let otherwise = targets.pop().unwrap(); - assert_eq!(targets.len(), values.len()); - let mut i = 0; - targets.retain(|_| { - let keep = allowed_variants.contains(&values[i]); - i += 1; - keep - }); - targets.push(otherwise); - - values.to_mut().retain(|var| allowed_variants.contains(var)); + let new_targets = SwitchTargets::new( + targets.iter().filter(|(val, _)| allowed_variants.contains(val)), + targets.otherwise(), + ); + + *targets = new_targets; } else { unreachable!() } diff --git a/compiler/rustc_mir/src/transform/unreachable_prop.rs b/compiler/rustc_mir/src/transform/unreachable_prop.rs index c6426a06ea1..f6d39dae342 100644 --- a/compiler/rustc_mir/src/transform/unreachable_prop.rs +++ b/compiler/rustc_mir/src/transform/unreachable_prop.rs @@ -7,7 +7,6 @@ use crate::transform::MirPass; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_middle::mir::*; use rustc_middle::ty::TyCtxt; -use std::borrow::Cow; pub struct UnreachablePropagation; @@ -69,14 +68,15 @@ where { let terminator = match *terminator_kind { TerminatorKind::Goto { target } if predicate(target) => TerminatorKind::Unreachable, - TerminatorKind::SwitchInt { ref discr, switch_ty, ref values, ref targets } => { - let original_targets_len = targets.len(); - let (otherwise, targets) = targets.split_last().unwrap(); + TerminatorKind::SwitchInt { ref discr, switch_ty, ref targets } => { + let otherwise = targets.otherwise(); + + let original_targets_len = targets.iter().len() + 1; let (mut values, mut targets): (Vec<_>, Vec<_>) = - values.iter().zip(targets.iter()).filter(|(_, &t)| !predicate(t)).unzip(); + targets.iter().filter(|(_, bb)| !predicate(*bb)).unzip(); - if !predicate(*otherwise) { - targets.push(*otherwise); + if !predicate(otherwise) { + targets.push(otherwise); } else { values.pop(); } @@ -91,8 +91,10 @@ where TerminatorKind::SwitchInt { discr: discr.clone(), switch_ty, - values: Cow::from(values), - targets, + targets: SwitchTargets::new( + values.iter().copied().zip(targets.iter().copied()), + *targets.last().unwrap(), + ), } } else { return None; diff --git a/compiler/rustc_mir/src/transform/validate.rs b/compiler/rustc_mir/src/transform/validate.rs index cf51e86c5bc..beffffa727e 100644 --- a/compiler/rustc_mir/src/transform/validate.rs +++ b/compiler/rustc_mir/src/transform/validate.rs @@ -8,7 +8,7 @@ use super::MirPass; use rustc_middle::mir::visit::{PlaceContext, Visitor}; use rustc_middle::mir::{ AggregateKind, BasicBlock, Body, BorrowKind, Local, Location, MirPhase, Operand, Rvalue, - Statement, StatementKind, Terminator, TerminatorKind, VarDebugInfo, + SourceScope, Statement, StatementKind, Terminator, TerminatorKind, VarDebugInfo, }; use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation}; use rustc_middle::ty::{self, ParamEnv, Ty, TyCtxt}; @@ -229,9 +229,10 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { } } - fn visit_var_debug_info(&mut self, _var_debug_info: &VarDebugInfo<'tcx>) { + fn visit_var_debug_info(&mut self, var_debug_info: &VarDebugInfo<'tcx>) { // Debuginfo can contain field projections, which count as a use of the base local. Skip // debuginfo so that we avoid the storage liveness assertion in that case. + self.visit_source_info(&var_debug_info.source_info); } fn visit_operand(&mut self, operand: &Operand<'tcx>, location: Location) { @@ -334,7 +335,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { TerminatorKind::Goto { target } => { self.check_edge(location, *target, EdgeKind::Normal); } - TerminatorKind::SwitchInt { targets, values, switch_ty, discr } => { + TerminatorKind::SwitchInt { targets, switch_ty, discr } => { let ty = discr.ty(&self.body.local_decls, self.tcx); if ty != *switch_ty { self.fail( @@ -345,19 +346,10 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { ), ); } - if targets.len() != values.len() + 1 { - self.fail( - location, - format!( - "encountered `SwitchInt` terminator with {} values, but {} targets (should be values+1)", - values.len(), - targets.len(), - ), - ); - } - for target in targets { - self.check_edge(location, *target, EdgeKind::Normal); + for (_, target) in targets.iter() { + self.check_edge(location, target, EdgeKind::Normal); } + self.check_edge(location, targets.otherwise(), EdgeKind::Normal); } TerminatorKind::Drop { target, unwind, .. } => { self.check_edge(location, *target, EdgeKind::Normal); @@ -441,4 +433,16 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { | TerminatorKind::GeneratorDrop => {} } } + + fn visit_source_scope(&mut self, scope: &SourceScope) { + if self.body.source_scopes.get(*scope).is_none() { + self.tcx.sess.diagnostic().delay_span_bug( + self.body.span, + &format!( + "broken MIR in {:?} ({}):\ninvalid source scope {:?}", + self.body.source.instance, self.when, scope, + ), + ); + } + } } diff --git a/compiler/rustc_mir/src/util/def_use.rs b/compiler/rustc_mir/src/util/def_use.rs deleted file mode 100644 index b4448ead8eb..00000000000 --- a/compiler/rustc_mir/src/util/def_use.rs +++ /dev/null @@ -1,158 +0,0 @@ -//! Def-use analysis. - -use rustc_index::vec::IndexVec; -use rustc_middle::mir::visit::{MutVisitor, PlaceContext, Visitor}; -use rustc_middle::mir::{Body, Local, Location, VarDebugInfo}; -use rustc_middle::ty::TyCtxt; -use std::mem; - -pub struct DefUseAnalysis { - info: IndexVec<Local, Info>, -} - -#[derive(Clone)] -pub struct Info { - // FIXME(eddyb) use smallvec where possible. - pub defs_and_uses: Vec<Use>, - var_debug_info_indices: Vec<usize>, -} - -#[derive(Clone)] -pub struct Use { - pub context: PlaceContext, - pub location: Location, -} - -impl DefUseAnalysis { - pub fn new(body: &Body<'_>) -> DefUseAnalysis { - DefUseAnalysis { info: IndexVec::from_elem_n(Info::new(), body.local_decls.len()) } - } - - pub fn analyze(&mut self, body: &Body<'_>) { - self.clear(); - - let mut finder = DefUseFinder { - info: mem::take(&mut self.info), - var_debug_info_index: 0, - in_var_debug_info: false, - }; - finder.visit_body(&body); - self.info = finder.info - } - - fn clear(&mut self) { - for info in &mut self.info { - info.clear(); - } - } - - pub fn local_info(&self, local: Local) -> &Info { - &self.info[local] - } - - fn mutate_defs_and_uses( - &self, - local: Local, - body: &mut Body<'tcx>, - new_local: Local, - tcx: TyCtxt<'tcx>, - ) { - let mut visitor = MutateUseVisitor::new(local, new_local, tcx); - let info = &self.info[local]; - for place_use in &info.defs_and_uses { - visitor.visit_location(body, place_use.location) - } - // Update debuginfo as well, alongside defs/uses. - for &i in &info.var_debug_info_indices { - visitor.visit_var_debug_info(&mut body.var_debug_info[i]); - } - } - - // FIXME(pcwalton): this should update the def-use chains. - pub fn replace_all_defs_and_uses_with( - &self, - local: Local, - body: &mut Body<'tcx>, - new_local: Local, - tcx: TyCtxt<'tcx>, - ) { - self.mutate_defs_and_uses(local, body, new_local, tcx) - } -} - -struct DefUseFinder { - info: IndexVec<Local, Info>, - var_debug_info_index: usize, - in_var_debug_info: bool, -} - -impl Visitor<'_> for DefUseFinder { - fn visit_local(&mut self, &local: &Local, context: PlaceContext, location: Location) { - let info = &mut self.info[local]; - if self.in_var_debug_info { - info.var_debug_info_indices.push(self.var_debug_info_index); - } else { - info.defs_and_uses.push(Use { context, location }); - } - } - fn visit_var_debug_info(&mut self, var_debug_info: &VarDebugInfo<'tcx>) { - assert!(!self.in_var_debug_info); - self.in_var_debug_info = true; - self.super_var_debug_info(var_debug_info); - self.in_var_debug_info = false; - self.var_debug_info_index += 1; - } -} - -impl Info { - fn new() -> Info { - Info { defs_and_uses: vec![], var_debug_info_indices: vec![] } - } - - fn clear(&mut self) { - self.defs_and_uses.clear(); - self.var_debug_info_indices.clear(); - } - - pub fn def_count(&self) -> usize { - self.defs_and_uses.iter().filter(|place_use| place_use.context.is_mutating_use()).count() - } - - pub fn def_count_not_including_drop(&self) -> usize { - self.defs_not_including_drop().count() - } - - pub fn defs_not_including_drop(&self) -> impl Iterator<Item = &Use> { - self.defs_and_uses - .iter() - .filter(|place_use| place_use.context.is_mutating_use() && !place_use.context.is_drop()) - } - - pub fn use_count(&self) -> usize { - self.defs_and_uses.iter().filter(|place_use| place_use.context.is_nonmutating_use()).count() - } -} - -struct MutateUseVisitor<'tcx> { - query: Local, - new_local: Local, - tcx: TyCtxt<'tcx>, -} - -impl MutateUseVisitor<'tcx> { - fn new(query: Local, new_local: Local, tcx: TyCtxt<'tcx>) -> MutateUseVisitor<'tcx> { - MutateUseVisitor { query, new_local, tcx } - } -} - -impl MutVisitor<'tcx> for MutateUseVisitor<'tcx> { - fn tcx(&self) -> TyCtxt<'tcx> { - self.tcx - } - - fn visit_local(&mut self, local: &mut Local, _context: PlaceContext, _location: Location) { - if *local == self.query { - *local = self.new_local; - } - } -} diff --git a/compiler/rustc_mir/src/util/elaborate_drops.rs b/compiler/rustc_mir/src/util/elaborate_drops.rs index 43fa15d7e49..0e2d8e5495b 100644 --- a/compiler/rustc_mir/src/util/elaborate_drops.rs +++ b/compiler/rustc_mir/src/util/elaborate_drops.rs @@ -588,8 +588,10 @@ where kind: TerminatorKind::SwitchInt { discr: Operand::Move(discr), switch_ty: discr_ty, - values: From::from(values.to_owned()), - targets: blocks, + targets: SwitchTargets::new( + values.iter().copied().zip(blocks.iter().copied()), + *blocks.last().unwrap(), + ), }, }), is_cleanup: unwind.is_cleanup(), @@ -758,8 +760,6 @@ where let elem_size = Place::from(self.new_temp(tcx.types.usize)); let len = Place::from(self.new_temp(tcx.types.usize)); - static USIZE_SWITCH_ZERO: &[u128] = &[0]; - let base_block = BasicBlockData { statements: vec![ self.assign(elem_size, Rvalue::NullaryOp(NullOp::SizeOf, ety)), @@ -771,11 +771,11 @@ where kind: TerminatorKind::SwitchInt { discr: move_(elem_size), switch_ty: tcx.types.usize, - values: From::from(USIZE_SWITCH_ZERO), - targets: vec![ + targets: SwitchTargets::static_if( + 0, self.drop_loop_pair(ety, false, len), self.drop_loop_pair(ety, true, len), - ], + ), }, }), }; diff --git a/compiler/rustc_mir/src/util/mod.rs b/compiler/rustc_mir/src/util/mod.rs index 699f3bcf014..7da2f4ffe08 100644 --- a/compiler/rustc_mir/src/util/mod.rs +++ b/compiler/rustc_mir/src/util/mod.rs @@ -1,6 +1,5 @@ pub mod aggregate; pub mod borrowck_errors; -pub mod def_use; pub mod elaborate_drops; pub mod patch; pub mod storage; diff --git a/compiler/rustc_mir_build/src/build/expr/as_constant.rs b/compiler/rustc_mir_build/src/build/expr/as_constant.rs index 244a70f83b0..3a36ad590c5 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_constant.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_constant.rs @@ -33,6 +33,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { Constant { span, user_ty, literal } } ExprKind::StaticRef { literal, .. } => Constant { span, user_ty: None, literal }, + ExprKind::ConstBlock { value } => Constant { span, user_ty: None, literal: value }, _ => span_bug!(span, "expression is not a valid constant {:?}", kind), } } diff --git a/compiler/rustc_mir_build/src/build/expr/as_place.rs b/compiler/rustc_mir_build/src/build/expr/as_place.rs index 39dbb6dd3ff..443025c4f84 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_place.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_place.rs @@ -254,6 +254,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { | ExprKind::Continue { .. } | ExprKind::Return { .. } | ExprKind::Literal { .. } + | ExprKind::ConstBlock { .. } | ExprKind::StaticRef { .. } | ExprKind::InlineAsm { .. } | ExprKind::LlvmInlineAsm { .. } diff --git a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs index 9c5fddc6b77..4033cc6cf46 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs @@ -234,6 +234,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } ExprKind::Yield { .. } | ExprKind::Literal { .. } + | ExprKind::ConstBlock { .. } | ExprKind::StaticRef { .. } | ExprKind::Block { .. } | ExprKind::Match { .. } diff --git a/compiler/rustc_mir_build/src/build/expr/category.rs b/compiler/rustc_mir_build/src/build/expr/category.rs index 9cabd186d84..ac5cf187aa0 100644 --- a/compiler/rustc_mir_build/src/build/expr/category.rs +++ b/compiler/rustc_mir_build/src/build/expr/category.rs @@ -68,7 +68,9 @@ impl Category { | ExprKind::ThreadLocalRef(_) | ExprKind::LlvmInlineAsm { .. } => Some(Category::Rvalue(RvalueFunc::AsRvalue)), - ExprKind::Literal { .. } | ExprKind::StaticRef { .. } => Some(Category::Constant), + ExprKind::ConstBlock { .. } | ExprKind::Literal { .. } | ExprKind::StaticRef { .. } => { + Some(Category::Constant) + } ExprKind::Loop { .. } | ExprKind::Block { .. } diff --git a/compiler/rustc_mir_build/src/build/expr/into.rs b/compiler/rustc_mir_build/src/build/expr/into.rs index a12c22fb850..a268b0b46ff 100644 --- a/compiler/rustc_mir_build/src/build/expr/into.rs +++ b/compiler/rustc_mir_build/src/build/expr/into.rs @@ -454,6 +454,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { | ExprKind::Array { .. } | ExprKind::Tuple { .. } | ExprKind::Closure { .. } + | ExprKind::ConstBlock { .. } | ExprKind::Literal { .. } | ExprKind::ThreadLocalRef(_) | ExprKind::StaticRef { .. } => { diff --git a/compiler/rustc_mir_build/src/build/matches/simplify.rs b/compiler/rustc_mir_build/src/build/matches/simplify.rs index a28a181e935..e46274770be 100644 --- a/compiler/rustc_mir_build/src/build/matches/simplify.rs +++ b/compiler/rustc_mir_build/src/build/matches/simplify.rs @@ -28,8 +28,9 @@ use std::mem; impl<'a, 'tcx> Builder<'a, 'tcx> { /// Simplify a candidate so that all match pairs require a test. /// - /// This method will also split a candidate where the only match-pair is an - /// or-pattern into multiple candidates. This is so that + /// This method will also split a candidate, in which the only + /// match-pair is an or-pattern, into multiple candidates. + /// This is so that /// /// match x { /// 0 | 1 => { ... }, diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs index 02dcf0394f6..c4191900147 100644 --- a/compiler/rustc_mir_build/src/build/matches/test.rs +++ b/compiler/rustc_mir_build/src/build/matches/test.rs @@ -167,48 +167,42 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let target_blocks = make_target_blocks(self); // Variants is a BitVec of indexes into adt_def.variants. let num_enum_variants = adt_def.variants.len(); - let used_variants = variants.count(); debug_assert_eq!(target_blocks.len(), num_enum_variants + 1); let otherwise_block = *target_blocks.last().unwrap(); - let mut targets = Vec::with_capacity(used_variants + 1); - let mut values = Vec::with_capacity(used_variants); let tcx = self.hir.tcx(); - for (idx, discr) in adt_def.discriminants(tcx) { - if variants.contains(idx) { - debug_assert_ne!( - target_blocks[idx.index()], - otherwise_block, - "no canididates for tested discriminant: {:?}", - discr, - ); - values.push(discr.val); - targets.push(target_blocks[idx.index()]); - } else { - debug_assert_eq!( - target_blocks[idx.index()], - otherwise_block, - "found canididates for untested discriminant: {:?}", - discr, - ); - } - } - targets.push(otherwise_block); - debug!( - "num_enum_variants: {}, tested variants: {:?}, variants: {:?}", - num_enum_variants, values, variants + let switch_targets = SwitchTargets::new( + adt_def.discriminants(tcx).filter_map(|(idx, discr)| { + if variants.contains(idx) { + debug_assert_ne!( + target_blocks[idx.index()], + otherwise_block, + "no canididates for tested discriminant: {:?}", + discr, + ); + Some((discr.val, target_blocks[idx.index()])) + } else { + debug_assert_eq!( + target_blocks[idx.index()], + otherwise_block, + "found canididates for untested discriminant: {:?}", + discr, + ); + None + } + }), + otherwise_block, ); + debug!("num_enum_variants: {}, variants: {:?}", num_enum_variants, variants); let discr_ty = adt_def.repr.discr_type().to_ty(tcx); let discr = self.temp(discr_ty, test.span); self.cfg.push_assign(block, source_info, discr, Rvalue::Discriminant(place)); - assert_eq!(values.len() + 1, targets.len()); self.cfg.terminate( block, source_info, TerminatorKind::SwitchInt { discr: Operand::Move(discr), switch_ty: discr_ty, - values: From::from(values), - targets, + targets: switch_targets, }, ); } @@ -230,11 +224,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } else { // The switch may be inexhaustive so we have a catch all block debug_assert_eq!(options.len() + 1, target_blocks.len()); + let otherwise_block = *target_blocks.last().unwrap(); + let switch_targets = SwitchTargets::new( + options.values().copied().zip(target_blocks), + otherwise_block, + ); TerminatorKind::SwitchInt { discr: Operand::Copy(place), switch_ty, - values: options.values().copied().collect(), - targets: target_blocks, + targets: switch_targets, } }; self.cfg.terminate(block, source_info, terminator); diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs index 220e3b11a6a..899fc647493 100644 --- a/compiler/rustc_mir_build/src/build/mod.rs +++ b/compiler/rustc_mir_build/src/build/mod.rs @@ -351,9 +351,6 @@ struct Builder<'a, 'tcx> { unit_temp: Option<Place<'tcx>>, var_debug_info: Vec<VarDebugInfo<'tcx>>, - - /// Cached block with the `UNREACHABLE` terminator. - cached_unreachable_block: Option<BasicBlock>, } impl<'a, 'tcx> Builder<'a, 'tcx> { @@ -634,10 +631,6 @@ where builder.cfg.terminate(return_block, source_info, TerminatorKind::Return); let should_abort = should_abort_on_panic(tcx, fn_def_id, abi); builder.build_drop_trees(should_abort); - // Attribute any unreachable codepaths to the function's closing brace - if let Some(unreachable_block) = builder.cached_unreachable_block { - builder.cfg.terminate(unreachable_block, source_info, TerminatorKind::Unreachable); - } return_block.unit() })); @@ -676,12 +669,6 @@ fn construct_const<'a, 'tcx>( builder.build_drop_trees(false); - // Constants may be match expressions in which case an unreachable block may - // be created, so terminate it properly. - if let Some(unreachable_block) = builder.cached_unreachable_block { - builder.cfg.terminate(unreachable_block, source_info, TerminatorKind::Unreachable); - } - builder.finish() } @@ -757,7 +744,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { var_indices: Default::default(), unit_temp: None, var_debug_info: vec![], - cached_unreachable_block: None, }; assert_eq!(builder.cfg.start_new_block(), START_BLOCK); diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index 13e69474cfb..731bd954246 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -511,6 +511,12 @@ fn make_mirror_unadjusted<'a, 'tcx>( inputs: asm.inputs_exprs.to_ref(), }, + hir::ExprKind::ConstBlock(ref anon_const) => { + let anon_const_def_id = cx.tcx.hir().local_def_id(anon_const.hir_id); + let value = ty::Const::from_anon_const(cx.tcx, anon_const_def_id); + + ExprKind::ConstBlock { value } + } // Now comes the rote stuff: hir::ExprKind::Repeat(ref v, ref count) => { let count_def_id = cx.tcx.hir().local_def_id(count.hir_id); diff --git a/compiler/rustc_mir_build/src/thir/mod.rs b/compiler/rustc_mir_build/src/thir/mod.rs index 4d57fd5c64f..f2a2ef0d8f2 100644 --- a/compiler/rustc_mir_build/src/thir/mod.rs +++ b/compiler/rustc_mir_build/src/thir/mod.rs @@ -232,6 +232,9 @@ crate enum ExprKind<'tcx> { Return { value: Option<ExprRef<'tcx>>, }, + ConstBlock { + value: &'tcx Const<'tcx>, + }, Repeat { value: ExprRef<'tcx>, count: &'tcx Const<'tcx>, diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs index 047bf7db4c8..69de7c7e2ee 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -71,13 +71,13 @@ impl<'tcx> Visitor<'tcx> for MatchVisitor<'_, 'tcx> { hir::LocalSource::AwaitDesugar => ("`await` future binding", None), }; self.check_irrefutable(&loc.pat, msg, sp); - self.check_patterns(false, &loc.pat); + self.check_patterns(&loc.pat); } fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) { intravisit::walk_param(self, param); self.check_irrefutable(¶m.pat, "function argument", None); - self.check_patterns(false, ¶m.pat); + self.check_patterns(¶m.pat); } } @@ -96,14 +96,14 @@ impl PatCtxt<'_, '_> { } PatternError::FloatBug => { // FIXME(#31407) this is only necessary because float parsing is buggy - ::rustc_middle::mir::interpret::struct_error( + rustc_middle::mir::interpret::struct_error( self.tcx.at(pat_span), "could not evaluate float literal (see issue #31407)", ) .emit(); } PatternError::NonConstPath(span) => { - ::rustc_middle::mir::interpret::struct_error( + rustc_middle::mir::interpret::struct_error( self.tcx.at(span), "runtime values cannot be referenced in patterns", ) @@ -119,10 +119,7 @@ impl PatCtxt<'_, '_> { } impl<'tcx> MatchVisitor<'_, 'tcx> { - fn check_patterns(&mut self, has_guard: bool, pat: &Pat<'_>) { - if !self.tcx.features().move_ref_pattern { - check_legality_of_move_bindings(self, has_guard, pat); - } + fn check_patterns(&mut self, pat: &Pat<'_>) { pat.walk_always(|pat| check_borrow_conflicts_in_at_patterns(self, pat)); if !self.tcx.features().bindings_after_at { check_legality_of_bindings_in_at_patterns(self, pat); @@ -165,7 +162,7 @@ impl<'tcx> MatchVisitor<'_, 'tcx> { ) { for arm in arms { // Check the arm for some things unrelated to exhaustiveness. - self.check_patterns(arm.guard.is_some(), &arm.pat); + self.check_patterns(&arm.pat); } let mut cx = self.new_cx(scrut.hir_id); @@ -601,65 +598,6 @@ fn is_binding_by_move(cx: &MatchVisitor<'_, '_>, hir_id: HirId, span: Span) -> b !cx.typeck_results.node_type(hir_id).is_copy_modulo_regions(cx.tcx.at(span), cx.param_env) } -/// Check the legality of legality of by-move bindings. -fn check_legality_of_move_bindings(cx: &mut MatchVisitor<'_, '_>, has_guard: bool, pat: &Pat<'_>) { - let sess = cx.tcx.sess; - let typeck_results = cx.typeck_results; - - // Find all by-ref spans. - let mut by_ref_spans = Vec::new(); - pat.each_binding(|_, hir_id, span, _| { - if let Some(ty::BindByReference(_)) = - typeck_results.extract_binding_mode(sess, hir_id, span) - { - by_ref_spans.push(span); - } - }); - - // Find bad by-move spans: - let by_move_spans = &mut Vec::new(); - let mut check_move = |p: &Pat<'_>, sub: Option<&Pat<'_>>| { - // Check legality of moving out of the enum. - // - // `x @ Foo(..)` is legal, but `x @ Foo(y)` isn't. - if sub.map_or(false, |p| p.contains_bindings()) { - struct_span_err!(sess, p.span, E0007, "cannot bind by-move with sub-bindings") - .span_label(p.span, "binds an already bound by-move value by moving it") - .emit(); - } else if !has_guard && !by_ref_spans.is_empty() { - by_move_spans.push(p.span); - } - }; - pat.walk_always(|p| { - if let hir::PatKind::Binding(.., sub) = &p.kind { - if let Some(ty::BindByValue(_)) = - typeck_results.extract_binding_mode(sess, p.hir_id, p.span) - { - if is_binding_by_move(cx, p.hir_id, p.span) { - check_move(p, sub.as_deref()); - } - } - } - }); - - // Found some bad by-move spans, error! - if !by_move_spans.is_empty() { - let mut err = feature_err( - &sess.parse_sess, - sym::move_ref_pattern, - by_move_spans.clone(), - "binding by-move and by-ref in the same pattern is unstable", - ); - for span in by_ref_spans.iter() { - err.span_label(*span, "by-ref pattern here"); - } - for span in by_move_spans.iter() { - err.span_label(*span, "by-move pattern here"); - } - err.emit(); - } -} - /// Check that there are no borrow or move conflicts in `binding @ subpat` patterns. /// /// For example, this would reject: diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index 718ed78889f..b05ddb3b464 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -856,6 +856,11 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { *self.lower_path(qpath, expr.hir_id, expr.span).kind } else { let (lit, neg) = match expr.kind { + hir::ExprKind::ConstBlock(ref anon_const) => { + let anon_const_def_id = self.tcx.hir().local_def_id(anon_const.hir_id); + let value = ty::Const::from_anon_const(self.tcx, anon_const_def_id); + return *self.const_to_pat(value, expr.hir_id, expr.span, false).kind; + } hir::ExprKind::Lit(ref lit) => (lit, false), hir::ExprKind::Unary(hir::UnOp::UnNeg, ref expr) => { let lit = match expr.kind { @@ -1060,13 +1065,13 @@ crate fn compare_const_vals<'tcx>( use rustc_apfloat::Float; return match *ty.kind() { ty::Float(ast::FloatTy::F32) => { - let l = ::rustc_apfloat::ieee::Single::from_bits(a); - let r = ::rustc_apfloat::ieee::Single::from_bits(b); + let l = rustc_apfloat::ieee::Single::from_bits(a); + let r = rustc_apfloat::ieee::Single::from_bits(b); l.partial_cmp(&r) } ty::Float(ast::FloatTy::F64) => { - let l = ::rustc_apfloat::ieee::Double::from_bits(a); - let r = ::rustc_apfloat::ieee::Double::from_bits(b); + let l = rustc_apfloat::ieee::Double::from_bits(a); + let r = rustc_apfloat::ieee::Double::from_bits(b); l.partial_cmp(&r) } ty::Int(ity) => { diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs index b68d36c9a8e..9a187c6285e 100644 --- a/compiler/rustc_parse/src/lib.rs +++ b/compiler/rustc_parse/src/lib.rs @@ -7,7 +7,7 @@ #![feature(or_patterns)] use rustc_ast as ast; -use rustc_ast::token::{self, Nonterminal, Token, TokenKind}; +use rustc_ast::token::{self, DelimToken, Nonterminal, Token, TokenKind}; use rustc_ast::tokenstream::{self, TokenStream, TokenTree}; use rustc_ast_pretty::pprust; use rustc_data_structures::sync::Lrc; @@ -22,7 +22,7 @@ use std::str; use tracing::{debug, info}; -pub const MACRO_ARGUMENTS: Option<&'static str> = Some("macro arguments"); +pub const MACRO_ARGUMENTS: Option<&str> = Some("macro arguments"); #[macro_use] pub mod parser; @@ -114,16 +114,6 @@ pub fn new_parser_from_file<'a>(sess: &'a ParseSess, path: &Path, sp: Option<Spa source_file_to_parser(sess, file_to_source_file(sess, path, sp)) } -/// Creates a new parser, returning buffered diagnostics if the file doesn't exist, -/// or from lexing the initial token stream. -pub fn maybe_new_parser_from_file<'a>( - sess: &'a ParseSess, - path: &Path, -) -> Result<Parser<'a>, Vec<Diagnostic>> { - let file = try_file_to_source_file(sess, path, None).map_err(|db| vec![db])?; - maybe_source_file_to_parser(sess, file) -} - /// Given a `source_file` and config, returns a parser. fn source_file_to_parser(sess: &ParseSess, source_file: Lrc<SourceFile>) -> Parser<'_> { panictry_buffer!(&sess.span_diagnostic, maybe_source_file_to_parser(sess, source_file)) @@ -146,12 +136,6 @@ fn maybe_source_file_to_parser( Ok(parser) } -// Must preserve old name for now, because `quote!` from the *existing* -// compiler expands into it. -pub fn new_parser_from_tts(sess: &ParseSess, tts: Vec<TokenTree>) -> Parser<'_> { - stream_to_parser(sess, tts.into_iter().collect(), crate::MACRO_ARGUMENTS) -} - // Base abstractions /// Given a session and a path and an optional span (for error reporting), @@ -297,7 +281,11 @@ pub fn nt_to_tokenstream(nt: &Nonterminal, sess: &ParseSess, span: Span) -> Toke }; // FIXME(#43081): Avoid this pretty-print + reparse hack - let source = pprust::nonterminal_to_string(nt); + // Pretty-print the AST struct without inserting any parenthesis + // beyond those explicitly written by the user (e.g. `ExpnKind::Paren`). + // The resulting stream may have incorrect precedence, but it's only + // ever used for a comparison against the capture tokenstream. + let source = pprust::nonterminal_to_string_no_extra_parens(nt); let filename = FileName::macro_expansion_source_code(&source); let reparsed_tokens = parse_stream_from_source_str(filename, source, sess, Some(span)); @@ -325,15 +313,43 @@ pub fn nt_to_tokenstream(nt: &Nonterminal, sess: &ParseSess, span: Span) -> Toke // modifications, including adding/removing typically non-semantic // tokens such as extra braces and commas, don't happen. if let Some(tokens) = tokens { - if tokenstream_probably_equal_for_proc_macro(&tokens, &reparsed_tokens, sess) { + // Compare with a non-relaxed delim match to start. + if tokenstream_probably_equal_for_proc_macro(&tokens, &reparsed_tokens, sess, false) { return tokens; } + + // The check failed. This time, we pretty-print the AST struct with parenthesis + // inserted to preserve precedence. This may cause `None`-delimiters in the captured + // token stream to match up with inserted parenthesis in the reparsed stream. + let source_with_parens = pprust::nonterminal_to_string(nt); + let filename_with_parens = FileName::macro_expansion_source_code(&source_with_parens); + let reparsed_tokens_with_parens = parse_stream_from_source_str( + filename_with_parens, + source_with_parens, + sess, + Some(span), + ); + + // Compare with a relaxed delim match - we want inserted parenthesis in the + // reparsed stream to match `None`-delimiters in the original stream. + if tokenstream_probably_equal_for_proc_macro( + &tokens, + &reparsed_tokens_with_parens, + sess, + true, + ) { + return tokens; + } + info!( "cached tokens found, but they're not \"probably equal\", \ going with stringified version" ); - info!("cached tokens: {:?}", tokens); - info!("reparsed tokens: {:?}", reparsed_tokens); + info!("cached tokens: {}", pprust::tts_to_string(&tokens)); + info!("reparsed tokens: {}", pprust::tts_to_string(&reparsed_tokens_with_parens)); + + info!("cached tokens debug: {:?}", tokens); + info!("reparsed tokens debug: {:?}", reparsed_tokens_with_parens); } reparsed_tokens } @@ -347,6 +363,7 @@ pub fn tokenstream_probably_equal_for_proc_macro( tokens: &TokenStream, reparsed_tokens: &TokenStream, sess: &ParseSess, + relaxed_delim_match: bool, ) -> bool { // When checking for `probably_eq`, we ignore certain tokens that aren't // preserved in the AST. Because they are not preserved, the pretty @@ -472,7 +489,9 @@ pub fn tokenstream_probably_equal_for_proc_macro( let tokens = tokens.trees().flat_map(|t| expand_token(t, sess)); let reparsed_tokens = reparsed_tokens.trees().flat_map(|t| expand_token(t, sess)); - tokens.eq_by(reparsed_tokens, |t, rt| tokentree_probably_equal_for_proc_macro(&t, &rt, sess)) + tokens.eq_by(reparsed_tokens, |t, rt| { + tokentree_probably_equal_for_proc_macro(&t, &rt, sess, relaxed_delim_match) + }) } // See comments in `Nonterminal::to_tokenstream` for why we care about @@ -484,6 +503,7 @@ pub fn tokentree_probably_equal_for_proc_macro( token: &TokenTree, reparsed_token: &TokenTree, sess: &ParseSess, + relaxed_delim_match: bool, ) -> bool { match (token, reparsed_token) { (TokenTree::Token(token), TokenTree::Token(reparsed_token)) => { @@ -492,9 +512,33 @@ pub fn tokentree_probably_equal_for_proc_macro( ( TokenTree::Delimited(_, delim, tokens), TokenTree::Delimited(_, reparsed_delim, reparsed_tokens), - ) => { - delim == reparsed_delim - && tokenstream_probably_equal_for_proc_macro(tokens, reparsed_tokens, sess) + ) if delim == reparsed_delim => tokenstream_probably_equal_for_proc_macro( + tokens, + reparsed_tokens, + sess, + relaxed_delim_match, + ), + (TokenTree::Delimited(_, DelimToken::NoDelim, tokens), reparsed_token) => { + if relaxed_delim_match { + if let TokenTree::Delimited(_, DelimToken::Paren, reparsed_tokens) = reparsed_token + { + if tokenstream_probably_equal_for_proc_macro( + tokens, + reparsed_tokens, + sess, + relaxed_delim_match, + ) { + return true; + } + } + } + tokens.len() == 1 + && tokentree_probably_equal_for_proc_macro( + &tokens.trees().next().unwrap(), + reparsed_token, + sess, + relaxed_delim_match, + ) } _ => false, } diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index a6df41f47ce..fb05f8791a5 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -246,11 +246,7 @@ impl<'a> Parser<'a> { this.parse_assoc_expr_with(prec + prec_adjustment, LhsExpr::NotYetParsed) })?; - // Make sure that the span of the parent node is larger than the span of lhs and rhs, - // including the attributes. - let lhs_span = - lhs.attrs.iter().find(|a| a.style == AttrStyle::Outer).map_or(lhs_span, |a| a.span); - let span = lhs_span.to(rhs.span); + let span = self.mk_expr_sp(&lhs, lhs_span, rhs.span); lhs = match op { AssocOp::Add | AssocOp::Subtract @@ -411,7 +407,7 @@ impl<'a> Parser<'a> { None }; let rhs_span = rhs.as_ref().map_or(cur_op_span, |x| x.span); - let span = lhs.span.to(rhs_span); + let span = self.mk_expr_sp(&lhs, lhs.span, rhs_span); let limits = if op == AssocOp::DotDot { RangeLimits::HalfOpen } else { RangeLimits::Closed }; Ok(self.mk_expr(span, self.mk_range(Some(lhs), rhs, limits)?, AttrVec::new())) @@ -571,7 +567,11 @@ impl<'a> Parser<'a> { expr_kind: fn(P<Expr>, P<Ty>) -> ExprKind, ) -> PResult<'a, P<Expr>> { let mk_expr = |this: &mut Self, rhs: P<Ty>| { - this.mk_expr(lhs_span.to(rhs.span), expr_kind(lhs, rhs), AttrVec::new()) + this.mk_expr( + this.mk_expr_sp(&lhs, lhs_span, rhs.span), + expr_kind(lhs, rhs), + AttrVec::new(), + ) }; // Save the state of the parser before parsing type normally, in case there is a @@ -1060,6 +1060,8 @@ impl<'a> Parser<'a> { }) } else if self.eat_keyword(kw::Unsafe) { self.parse_block_expr(None, lo, BlockCheckMode::Unsafe(ast::UserProvided), attrs) + } else if self.check_inline_const() { + self.parse_const_expr(lo.to(self.token.span)) } else if self.is_do_catch_block() { self.recover_do_catch(attrs) } else if self.is_try_block() { @@ -2324,4 +2326,14 @@ impl<'a> Parser<'a> { pub(super) fn mk_expr_err(&self, span: Span) -> P<Expr> { self.mk_expr(span, ExprKind::Err, AttrVec::new()) } + + /// Create expression span ensuring the span of the parent node + /// is larger than the span of lhs and rhs, including the attributes. + fn mk_expr_sp(&self, lhs: &P<Expr>, lhs_span: Span, rhs_span: Span) -> Span { + lhs.attrs + .iter() + .find(|a| a.style == AttrStyle::Outer) + .map_or(lhs_span, |a| a.span) + .to(rhs_span) + } } diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 26ca9980127..48341f71d33 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -1744,7 +1744,7 @@ impl<'a> Parser<'a> { } }; - let span = lo.to(self.token.span); + let span = lo.until(self.token.span); Ok(Param { attrs: attrs.into(), diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index c1094681221..7970ad36456 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -18,8 +18,9 @@ use rustc_ast::ptr::P; use rustc_ast::token::{self, DelimToken, Token, TokenKind}; use rustc_ast::tokenstream::{self, DelimSpan, TokenStream, TokenTree, TreeAndSpacing}; use rustc_ast::DUMMY_NODE_ID; -use rustc_ast::{self as ast, AttrStyle, AttrVec, Const, CrateSugar, Extern, Unsafe}; -use rustc_ast::{Async, MacArgs, MacDelimiter, Mutability, StrLit, Visibility, VisibilityKind}; +use rustc_ast::{self as ast, AnonConst, AttrStyle, AttrVec, Const, CrateSugar, Extern, Unsafe}; +use rustc_ast::{Async, Expr, ExprKind, MacArgs, MacDelimiter, Mutability, StrLit}; +use rustc_ast::{Visibility, VisibilityKind}; use rustc_ast_pretty::pprust; use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, FatalError, PResult}; use rustc_session::parse::ParseSess; @@ -545,6 +546,11 @@ impl<'a> Parser<'a> { self.check_or_expected(self.token.can_begin_const_arg(), TokenType::Const) } + fn check_inline_const(&mut self) -> bool { + self.check_keyword(kw::Const) + && self.look_ahead(1, |t| t == &token::OpenDelim(DelimToken::Brace)) + } + /// Checks to see if the next token is either `+` or `+=`. /// Otherwise returns `false`. fn check_plus(&mut self) -> bool { @@ -864,13 +870,28 @@ impl<'a> Parser<'a> { /// Parses constness: `const` or nothing. fn parse_constness(&mut self) -> Const { - if self.eat_keyword(kw::Const) { + // Avoid const blocks to be parsed as const items + if self.look_ahead(1, |t| t != &token::OpenDelim(DelimToken::Brace)) + && self.eat_keyword(kw::Const) + { Const::Yes(self.prev_token.uninterpolated_span()) } else { Const::No } } + /// Parses inline const expressions. + fn parse_const_expr(&mut self, span: Span) -> PResult<'a, P<Expr>> { + self.sess.gated_spans.gate(sym::inline_const, span); + self.eat_keyword(kw::Const); + let blk = self.parse_block()?; + let anon_const = AnonConst { + id: DUMMY_NODE_ID, + value: self.mk_expr(blk.span, ExprKind::Block(blk, None), AttrVec::new()), + }; + Ok(self.mk_expr(span, ExprKind::ConstBlock(anon_const), AttrVec::new())) + } + /// Parses mutability (`mut` or nothing). fn parse_mutability(&mut self) -> Mutability { if self.eat_keyword(kw::Mut) { Mutability::Mut } else { Mutability::Not } diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index 5aced9dc37c..15db2066a30 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -313,6 +313,9 @@ impl<'a> Parser<'a> { let pat = self.parse_pat_with_range_pat(false, None)?; self.sess.gated_spans.gate(sym::box_patterns, lo.to(self.prev_token.span)); PatKind::Box(pat) + } else if self.check_inline_const() { + // Parse `const pat` + PatKind::Lit(self.parse_const_expr(lo.to(self.token.span))?) } else if self.can_be_ident_pat() { // Parse `ident @ pat` // This can give false positives and parse nullary enums, diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 59955b27334..1acaa4c6eff 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -287,8 +287,9 @@ impl CheckAttrVisitor<'tcx> { self.doc_alias_str_error(meta); return false; } - if let Some(c) = - doc_alias.chars().find(|&c| c == '"' || c == '\'' || c.is_whitespace()) + if let Some(c) = doc_alias + .chars() + .find(|&c| c == '"' || c == '\'' || (c.is_whitespace() && c != ' ')) { self.tcx .sess @@ -302,6 +303,16 @@ impl CheckAttrVisitor<'tcx> { .emit(); return false; } + if doc_alias.starts_with(' ') || doc_alias.ends_with(' ') { + self.tcx + .sess + .struct_span_err( + meta.span(), + "`#[doc(alias = \"...\")]` cannot start or end with ' '", + ) + .emit(); + return false; + } if let Some(err) = match target { Target::Impl => Some("implementation block"), Target::ForeignMod => Some("extern block"), diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index 98ded4189cf..f567dd83bc1 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -458,8 +458,8 @@ fn create_and_seed_worklist<'tcx>( .map .iter() .filter_map( - |(&id, level)| { - if level >= &privacy::AccessLevel::Reachable { Some(id) } else { None } + |(&id, &level)| { + if level >= privacy::AccessLevel::Reachable { Some(id) } else { None } }, ) .chain( @@ -547,7 +547,7 @@ impl DeadVisitor<'tcx> { let def_id = self.tcx.hir().local_def_id(id); let inherent_impls = self.tcx.inherent_impls(def_id); for &impl_did in inherent_impls.iter() { - for &item_did in &self.tcx.associated_item_def_ids(impl_did)[..] { + for item_did in self.tcx.associated_item_def_ids(impl_did) { if let Some(did) = item_did.as_local() { let item_hir_id = self.tcx.hir().local_def_id_to_hir_id(did); if self.live_symbols.contains(&item_hir_id) { diff --git a/compiler/rustc_passes/src/intrinsicck.rs b/compiler/rustc_passes/src/intrinsicck.rs index 79f1c2b9da8..956be925be8 100644 --- a/compiler/rustc_passes/src/intrinsicck.rs +++ b/compiler/rustc_passes/src/intrinsicck.rs @@ -143,7 +143,7 @@ impl ExprVisitor<'tcx> { ) -> Option<InlineAsmType> { // Check the type against the allowed types for inline asm. let ty = self.typeck_results.expr_ty_adjusted(expr); - let asm_ty_isize = match self.tcx.sess.target.ptr_width { + let asm_ty_isize = match self.tcx.sess.target.pointer_width { 16 => InlineAsmType::I16, 32 => InlineAsmType::I32, 64 => InlineAsmType::I64, @@ -184,7 +184,7 @@ impl ExprVisitor<'tcx> { Some(InlineAsmType::VecI128(fields.len() as u64)) } ty::Int(IntTy::Isize) | ty::Uint(UintTy::Usize) => { - Some(match self.tcx.sess.target.ptr_width { + Some(match self.tcx.sess.target.pointer_width { 16 => InlineAsmType::VecI16(fields.len() as u64), 32 => InlineAsmType::VecI32(fields.len() as u64), 64 => InlineAsmType::VecI64(fields.len() as u64), diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs index e8b97d7dc7d..ae810b9e79a 100644 --- a/compiler/rustc_passes/src/liveness.rs +++ b/compiler/rustc_passes/src/liveness.rs @@ -432,6 +432,7 @@ impl<'tcx> Visitor<'tcx> for IrMaps<'tcx> { | hir::ExprKind::Break(..) | hir::ExprKind::Continue(_) | hir::ExprKind::Lit(_) + | hir::ExprKind::ConstBlock(..) | hir::ExprKind::Ret(..) | hir::ExprKind::Block(..) | hir::ExprKind::Assign(..) @@ -1232,6 +1233,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { } hir::ExprKind::Lit(..) + | hir::ExprKind::ConstBlock(..) | hir::ExprKind::Err | hir::ExprKind::Path(hir::QPath::TypeRelative(..)) | hir::ExprKind::Path(hir::QPath::LangItem(..)) => succ, @@ -1478,6 +1480,7 @@ fn check_expr<'tcx>(this: &mut Liveness<'_, 'tcx>, expr: &'tcx Expr<'tcx>) { | hir::ExprKind::Break(..) | hir::ExprKind::Continue(..) | hir::ExprKind::Lit(_) + | hir::ExprKind::ConstBlock(..) | hir::ExprKind::Block(..) | hir::ExprKind::AddrOf(..) | hir::ExprKind::Struct(..) diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index 1378b0d5705..c9497f2a5b2 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -13,15 +13,13 @@ use rustc_hir::{Generics, HirId, Item, StructField, TraitRef, Ty, TyKind, Varian use rustc_middle::hir::map::Map; use rustc_middle::middle::privacy::AccessLevels; use rustc_middle::middle::stability::{DeprecationEntry, Index}; -use rustc_middle::ty::query::Providers; -use rustc_middle::ty::TyCtxt; +use rustc_middle::ty::{self, query::Providers, TyCtxt}; use rustc_session::lint; use rustc_session::lint::builtin::INEFFECTIVE_UNSTABLE_TRAIT_IMPL; use rustc_session::parse::feature_err; use rustc_session::Session; use rustc_span::symbol::{sym, Symbol}; -use rustc_span::Span; -use rustc_trait_selection::traits::misc::can_type_implement_copy; +use rustc_span::{Span, DUMMY_SP}; use std::cmp::Ordering; use std::mem::replace; @@ -711,27 +709,35 @@ impl Visitor<'tcx> for Checker<'tcx> { // so semi-randomly perform it here in stability.rs hir::ItemKind::Union(..) if !self.tcx.features().untagged_unions => { let def_id = self.tcx.hir().local_def_id(item.hir_id); - let adt_def = self.tcx.adt_def(def_id); let ty = self.tcx.type_of(def_id); + let (adt_def, substs) = match ty.kind() { + ty::Adt(adt_def, substs) => (adt_def, substs), + _ => bug!(), + }; - if adt_def.has_dtor(self.tcx) { - feature_err( - &self.tcx.sess.parse_sess, - sym::untagged_unions, - item.span, - "unions with `Drop` implementations are unstable", - ) - .emit(); - } else { - let param_env = self.tcx.param_env(def_id); - if can_type_implement_copy(self.tcx, param_env, ty).is_err() { - feature_err( - &self.tcx.sess.parse_sess, - sym::untagged_unions, - item.span, - "unions with non-`Copy` fields are unstable", - ) - .emit(); + // Non-`Copy` fields are unstable, except for `ManuallyDrop`. + let param_env = self.tcx.param_env(def_id); + for field in &adt_def.non_enum_variant().fields { + let field_ty = field.ty(self.tcx, substs); + if !field_ty.ty_adt_def().map_or(false, |adt_def| adt_def.is_manually_drop()) + && !field_ty.is_copy_modulo_regions(self.tcx.at(DUMMY_SP), param_env) + { + if field_ty.needs_drop(self.tcx, param_env) { + // Avoid duplicate error: This will error later anyway because fields + // that need drop are not allowed. + self.tcx.sess.delay_span_bug( + item.span, + "union should have been rejected due to potentially dropping field", + ); + } else { + feature_err( + &self.tcx.sess.parse_sess, + sym::untagged_unions, + self.tcx.def_span(field.did), + "unions with non-`Copy` fields other than `ManuallyDrop<T>` are unstable", + ) + .emit(); + } } } } diff --git a/compiler/rustc_passes/src/weak_lang_items.rs b/compiler/rustc_passes/src/weak_lang_items.rs index effb25b0224..8650ee05d37 100644 --- a/compiler/rustc_passes/src/weak_lang_items.rs +++ b/compiler/rustc_passes/src/weak_lang_items.rs @@ -26,7 +26,7 @@ pub fn check_crate<'tcx>(tcx: TyCtxt<'tcx>, items: &mut lang_items::LanguageItem if items.eh_personality().is_none() { items.missing.push(LangItem::EhPersonality); } - if tcx.sess.target.target.options.is_like_emscripten && items.eh_catch_typeinfo().is_none() { + if tcx.sess.target.options.is_like_emscripten && items.eh_catch_typeinfo().is_none() { items.missing.push(LangItem::EhCatchTypeinfo); } diff --git a/compiler/rustc_query_system/src/dep_graph/dep_node.rs b/compiler/rustc_query_system/src/dep_graph/dep_node.rs index e302784cc3e..7808a28dff0 100644 --- a/compiler/rustc_query_system/src/dep_graph/dep_node.rs +++ b/compiler/rustc_query_system/src/dep_graph/dep_node.rs @@ -165,10 +165,6 @@ impl WorkProductId { cgu_name.hash(&mut hasher); WorkProductId { hash: hasher.finish() } } - - pub fn from_fingerprint(fingerprint: Fingerprint) -> WorkProductId { - WorkProductId { hash: fingerprint } - } } impl<HCX> HashStable<HCX> for WorkProductId { diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs index d70306b4869..85335f0ba50 100644 --- a/compiler/rustc_query_system/src/dep_graph/graph.rs +++ b/compiler/rustc_query_system/src/dep_graph/graph.rs @@ -402,11 +402,6 @@ impl<K: DepKind> DepGraph<K> { self.data.as_ref().unwrap().previous.fingerprint_of(dep_node) } - #[inline] - pub fn prev_dep_node_index_of(&self, dep_node: &DepNode<K>) -> SerializedDepNodeIndex { - self.data.as_ref().unwrap().previous.node_to_index(dep_node) - } - /// Checks whether a previous work product exists for `v` and, if /// so, return the path that leads to it. Used to skip doing work. pub fn previous_work_product(&self, v: &WorkProductId) -> Option<WorkProduct> { diff --git a/compiler/rustc_query_system/src/dep_graph/query.rs b/compiler/rustc_query_system/src/dep_graph/query.rs index fb313d2658f..a27b716b95a 100644 --- a/compiler/rustc_query_system/src/dep_graph/query.rs +++ b/compiler/rustc_query_system/src/dep_graph/query.rs @@ -1,7 +1,5 @@ use rustc_data_structures::fx::FxHashMap; -use rustc_data_structures::graph::implementation::{ - Direction, Graph, NodeIndex, INCOMING, OUTGOING, -}; +use rustc_data_structures::graph::implementation::{Direction, Graph, NodeIndex, INCOMING}; use super::{DepKind, DepNode}; @@ -52,23 +50,8 @@ impl<K: DepKind> DepGraphQuery<K> { } } - /// All nodes reachable from `node`. In other words, things that - /// will have to be recomputed if `node` changes. - pub fn transitive_successors(&self, node: &DepNode<K>) -> Vec<&DepNode<K>> { - self.reachable_nodes(node, OUTGOING) - } - /// All nodes that can reach `node`. pub fn transitive_predecessors(&self, node: &DepNode<K>) -> Vec<&DepNode<K>> { self.reachable_nodes(node, INCOMING) } - - /// Just the outgoing edges from `node`. - pub fn immediate_successors(&self, node: &DepNode<K>) -> Vec<&DepNode<K>> { - if let Some(&index) = self.indices.get(&node) { - self.graph.successor_nodes(index).map(|s| self.graph.node_data(s)).collect() - } else { - vec![] - } - } } diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index e3cf6d12bd5..33ab09a8f42 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -469,24 +469,17 @@ impl<'a> Resolver<'a> { ResolutionError::ParamInNonTrivialAnonConst { name, is_type } => { let mut err = self.session.struct_span_err( span, - "generic parameters must not be used inside of non-trivial constant values", - ); - err.span_label( - span, - &format!( - "non-trivial anonymous constants must not depend on the parameter `{}`", - name - ), + "generic parameters may not be used in const operations", ); + err.span_label(span, &format!("cannot perform const operation using `{}`", name)); if is_type { - err.note("type parameters are currently not permitted in anonymous constants"); + err.note("type parameters may not be used in const expressions"); } else { - err.help( - &format!("it is currently only allowed to use either `{0}` or `{{ {0} }}` as generic constants", - name - ) - ); + err.help(&format!( + "const parameters may only be used as standalone arguments, i.e. `{}`", + name + )); } err @@ -929,6 +922,17 @@ impl<'a> Resolver<'a> { ); self.add_typo_suggestion(err, suggestion, ident.span); + let import_suggestions = self.lookup_import_candidates( + ident, + Namespace::MacroNS, + parent_scope, + |res| match res { + Res::Def(DefKind::Macro(MacroKind::Bang), _) => true, + _ => false, + }, + ); + show_candidates(err, None, &import_suggestions, false, true); + if macro_kind == MacroKind::Derive && (ident.name == sym::Send || ident.name == sym::Sync) { let msg = format!("unsafe traits like `{}` should be implemented explicitly", ident); err.span_note(ident.span, &msg); diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 219517b4ab2..7517ab66170 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -369,7 +369,7 @@ struct DiagnosticMetadata<'ast> { /// param. currently_processing_generics: bool, - /// The current enclosing function (used for better errors). + /// The current enclosing (non-closure) function (used for better errors). current_function: Option<(FnKind<'ast>, Span)>, /// A list of labels as of yet unused. Labels will be removed from this map when @@ -515,8 +515,10 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { FnKind::Fn(FnCtxt::Assoc(_), ..) => NormalRibKind, FnKind::Closure(..) => ClosureOrAsyncRibKind, }; - let previous_value = - replace(&mut self.diagnostic_metadata.current_function, Some((fn_kind, sp))); + let previous_value = self.diagnostic_metadata.current_function; + if matches!(fn_kind, FnKind::Fn(..)) { + self.diagnostic_metadata.current_function = Some((fn_kind, sp)); + } debug!("(resolving function) entering function"); let declaration = fn_kind.decl(); diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index bee05e77382..c24b383f3b8 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -1330,58 +1330,17 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { let suggest_only_tuple_variants = matches!(source, PathSource::TupleStruct(..)) || source.is_call(); - let mut suggestable_variants = if suggest_only_tuple_variants { + if suggest_only_tuple_variants { // Suggest only tuple variants regardless of whether they have fields and do not // suggest path with added parenthesis. - variants + let mut suggestable_variants = variants .iter() .filter(|(.., kind)| *kind == CtorKind::Fn) .map(|(variant, ..)| path_names_to_string(variant)) - .collect::<Vec<_>>() - } else { - variants - .iter() - .filter(|(_, def_id, kind)| { - // Suggest only variants that have no fields (these can definitely - // be constructed). - let has_fields = - self.r.field_names.get(&def_id).map(|f| f.is_empty()).unwrap_or(false); - match kind { - CtorKind::Const => true, - CtorKind::Fn | CtorKind::Fictive if has_fields => true, - _ => false, - } - }) - .map(|(variant, _, kind)| (path_names_to_string(variant), kind)) - .map(|(variant_str, kind)| { - // Add constructor syntax where appropriate. - match kind { - CtorKind::Const => variant_str, - CtorKind::Fn => format!("({}())", variant_str), - CtorKind::Fictive => format!("({} {{}})", variant_str), - } - }) - .collect::<Vec<_>>() - }; - - let non_suggestable_variant_count = variants.len() - suggestable_variants.len(); + .collect::<Vec<_>>(); - if !suggestable_variants.is_empty() { - let msg = if non_suggestable_variant_count == 0 && suggestable_variants.len() == 1 { - "try using the enum's variant" - } else { - "try using one of the enum's variants" - }; + let non_suggestable_variant_count = variants.len() - suggestable_variants.len(); - err.span_suggestions( - span, - msg, - suggestable_variants.drain(..), - Applicability::MaybeIncorrect, - ); - } - - if suggest_only_tuple_variants { let source_msg = if source.is_call() { "to construct" } else if matches!(source, PathSource::TupleStruct(..)) { @@ -1390,6 +1349,21 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { unreachable!() }; + if !suggestable_variants.is_empty() { + let msg = if non_suggestable_variant_count == 0 && suggestable_variants.len() == 1 { + format!("try {} the enum's variant", source_msg) + } else { + format!("try {} one of the enum's variants", source_msg) + }; + + err.span_suggestions( + span, + &msg, + suggestable_variants.drain(..), + Applicability::MaybeIncorrect, + ); + } + // If the enum has no tuple variants.. if non_suggestable_variant_count == variants.len() { err.help(&format!("the enum has no tuple variants {}", source_msg)); @@ -1408,24 +1382,76 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { )); } } else { - let made_suggestion = non_suggestable_variant_count != variants.len(); - if made_suggestion { - if non_suggestable_variant_count == 1 { - err.help( - "you might have meant to use the enum's other variant that has fields", - ); - } else if non_suggestable_variant_count >= 1 { - err.help( - "you might have meant to use one of the enum's other variants that \ - have fields", - ); - } - } else { - if non_suggestable_variant_count == 1 { - err.help("you might have meant to use the enum's variant"); - } else if non_suggestable_variant_count >= 1 { - err.help("you might have meant to use one of the enum's variants"); + let needs_placeholder = |def_id: DefId, kind: CtorKind| { + let has_no_fields = + self.r.field_names.get(&def_id).map(|f| f.is_empty()).unwrap_or(false); + match kind { + CtorKind::Const => false, + CtorKind::Fn | CtorKind::Fictive if has_no_fields => false, + _ => true, } + }; + + let mut suggestable_variants = variants + .iter() + .filter(|(_, def_id, kind)| !needs_placeholder(*def_id, *kind)) + .map(|(variant, _, kind)| (path_names_to_string(variant), kind)) + .map(|(variant, kind)| match kind { + CtorKind::Const => variant, + CtorKind::Fn => format!("({}())", variant), + CtorKind::Fictive => format!("({} {{}})", variant), + }) + .collect::<Vec<_>>(); + + if !suggestable_variants.is_empty() { + let msg = if suggestable_variants.len() == 1 { + "you might have meant to use the following enum variant" + } else { + "you might have meant to use one of the following enum variants" + }; + + err.span_suggestions( + span, + msg, + suggestable_variants.drain(..), + Applicability::MaybeIncorrect, + ); + } + + let mut suggestable_variants_with_placeholders = variants + .iter() + .filter(|(_, def_id, kind)| needs_placeholder(*def_id, *kind)) + .map(|(variant, _, kind)| (path_names_to_string(variant), kind)) + .filter_map(|(variant, kind)| match kind { + CtorKind::Fn => Some(format!("({}(/* fields */))", variant)), + CtorKind::Fictive => Some(format!("({} {{ /* fields */ }})", variant)), + _ => None, + }) + .collect::<Vec<_>>(); + + if !suggestable_variants_with_placeholders.is_empty() { + let msg = match ( + suggestable_variants.is_empty(), + suggestable_variants_with_placeholders.len(), + ) { + (true, 1) => "the following enum variant is available", + (true, _) => "the following enum variants are available", + (false, 1) => "alternatively, the following enum variant is available", + (false, _) => "alternatively, the following enum variants are also available", + }; + + err.span_suggestions( + span, + msg, + suggestable_variants_with_placeholders.drain(..), + Applicability::HasPlaceholders, + ); + } + }; + + if def_id.is_local() { + if let Some(span) = self.def_span(def_id) { + err.span_note(span, "the enum is defined here"); } } } diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index fe8f5926385..e7486db4deb 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -218,7 +218,7 @@ enum ResolutionError<'a> { ParamInTyOfConstParam(Symbol), /// constant values inside of type parameter defaults must not depend on generic parameters. ParamInAnonConstInTyDefault(Symbol), - /// generic parameters must not be used inside of non-trivial constant values. + /// generic parameters must not be used inside const evaluations. /// /// This error is only emitted when using `min_const_generics`. ParamInNonTrivialAnonConst { name: Symbol, is_type: bool }, @@ -1240,9 +1240,6 @@ impl<'a> Resolver<'a> { extern_prelude.insert(Ident::with_dummy_span(sym::core), Default::default()); if !session.contains_name(&krate.attrs, sym::no_std) { extern_prelude.insert(Ident::with_dummy_span(sym::std), Default::default()); - if session.rust_2018() { - extern_prelude.insert(Ident::with_dummy_span(sym::meta), Default::default()); - } } } diff --git a/compiler/rustc_serialize/src/opaque.rs b/compiler/rustc_serialize/src/opaque.rs index fa4423e261d..8b79c93e760 100644 --- a/compiler/rustc_serialize/src/opaque.rs +++ b/compiler/rustc_serialize/src/opaque.rs @@ -107,7 +107,7 @@ impl serialize::Encoder for Encoder { #[inline] fn emit_i8(&mut self, v: i8) -> EncodeResult { - let as_u8: u8 = unsafe { ::std::mem::transmute(v) }; + let as_u8: u8 = unsafe { std::mem::transmute(v) }; self.emit_u8(as_u8) } @@ -300,13 +300,13 @@ impl<'a> serialize::Decoder for Decoder<'a> { #[inline] fn read_char(&mut self) -> Result<char, Self::Error> { let bits = self.read_u32()?; - Ok(::std::char::from_u32(bits).unwrap()) + Ok(std::char::from_u32(bits).unwrap()) } #[inline] fn read_str(&mut self) -> Result<Cow<'_, str>, Self::Error> { let len = self.read_usize()?; - let s = ::std::str::from_utf8(&self.data[self.position..self.position + len]).unwrap(); + let s = std::str::from_utf8(&self.data[self.position..self.position + len]).unwrap(); self.position += len; Ok(Cow::Borrowed(s)) } diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 231e315a22f..f33bebf99d6 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -34,11 +34,6 @@ use std::iter::{self, FromIterator}; use std::path::{Path, PathBuf}; use std::str::{self, FromStr}; -pub struct Config { - pub target: Target, - pub ptr_width: u32, -} - bitflags! { #[derive(Default, Encodable, Decodable)] pub struct SanitizerSet: u8 { @@ -740,16 +735,16 @@ pub const fn default_lib_output() -> CrateType { } pub fn default_configuration(sess: &Session) -> CrateConfig { - let end = &sess.target.target.target_endian; - let arch = &sess.target.target.arch; - let wordsz = &sess.target.target.target_pointer_width; - let os = &sess.target.target.target_os; - let env = &sess.target.target.target_env; - let vendor = &sess.target.target.target_vendor; - let min_atomic_width = sess.target.target.min_atomic_width(); - let max_atomic_width = sess.target.target.max_atomic_width(); - let atomic_cas = sess.target.target.options.atomic_cas; - let layout = TargetDataLayout::parse(&sess.target.target).unwrap_or_else(|err| { + let end = &sess.target.target_endian; + let arch = &sess.target.arch; + let wordsz = sess.target.pointer_width.to_string(); + let os = &sess.target.target_os; + let env = &sess.target.target_env; + let vendor = &sess.target.target_vendor; + let min_atomic_width = sess.target.min_atomic_width(); + let max_atomic_width = sess.target.max_atomic_width(); + let atomic_cas = sess.target.options.atomic_cas; + let layout = TargetDataLayout::parse(&sess.target).unwrap_or_else(|err| { sess.fatal(&err); }); @@ -757,7 +752,7 @@ pub fn default_configuration(sess: &Session) -> CrateConfig { ret.reserve(6); // the minimum number of insertions // Target bindings. ret.insert((sym::target_os, Some(Symbol::intern(os)))); - if let Some(ref fam) = sess.target.target.options.target_family { + if let Some(ref fam) = sess.target.options.target_family { ret.insert((sym::target_family, Some(Symbol::intern(fam)))); if fam == "windows" { ret.insert((sym::windows, None)); @@ -767,10 +762,10 @@ pub fn default_configuration(sess: &Session) -> CrateConfig { } ret.insert((sym::target_arch, Some(Symbol::intern(arch)))); ret.insert((sym::target_endian, Some(Symbol::intern(end)))); - ret.insert((sym::target_pointer_width, Some(Symbol::intern(wordsz)))); + ret.insert((sym::target_pointer_width, Some(Symbol::intern(&wordsz)))); ret.insert((sym::target_env, Some(Symbol::intern(env)))); ret.insert((sym::target_vendor, Some(Symbol::intern(vendor)))); - if sess.target.target.options.has_elf_tls { + if sess.target.options.has_elf_tls { ret.insert((sym::target_thread_local, None)); } for &(i, align) in &[ @@ -792,7 +787,7 @@ pub fn default_configuration(sess: &Session) -> CrateConfig { }; let s = i.to_string(); insert_atomic(&s, align); - if &s == wordsz { + if s == wordsz { insert_atomic("ptr", layout.pointer_align.abi); } } @@ -831,7 +826,7 @@ pub fn build_configuration(sess: &Session, mut user_cfg: CrateConfig) -> CrateCo user_cfg } -pub fn build_target_config(opts: &Options, target_override: Option<Target>) -> Config { +pub fn build_target_config(opts: &Options, target_override: Option<Target>) -> Target { let target_result = target_override.map_or_else(|| Target::search(&opts.target_triple), Ok); let target = target_result.unwrap_or_else(|e| { early_error( @@ -844,21 +839,18 @@ pub fn build_target_config(opts: &Options, target_override: Option<Target>) -> C ) }); - let ptr_width = match &target.target_pointer_width[..] { - "16" => 16, - "32" => 32, - "64" => 64, - w => early_error( + if !matches!(target.pointer_width, 16 | 32 | 64) { + early_error( opts.error_format, &format!( "target specification was invalid: \ unrecognized target-pointer-width {}", - w + target.pointer_width ), - ), - }; + ) + } - Config { target, ptr_width } + target } #[derive(Copy, Clone, PartialEq, Eq, Debug)] diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index a106007c274..627adcceb3f 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -1078,6 +1078,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "show extended diagnostic help (default: no)"), terminal_width: Option<usize> = (None, parse_opt_uint, [UNTRACKED], "set the current terminal width"), + tune_cpu: Option<String> = (None, parse_opt_string, [TRACKED], + "select processor to schedule for (`rustc --print target-cpus` for details)"), thinlto: Option<bool> = (None, parse_opt_bool, [TRACKED], "enable ThinLTO when possible"), // We default to 1 here since we want to behave like diff --git a/compiler/rustc_session/src/output.rs b/compiler/rustc_session/src/output.rs index bf9c96c6c94..0766c55da74 100644 --- a/compiler/rustc_session/src/output.rs +++ b/compiler/rustc_session/src/output.rs @@ -151,18 +151,16 @@ pub fn filename_for_input( CrateType::Rlib => outputs.out_directory.join(&format!("lib{}.rlib", libname)), CrateType::Cdylib | CrateType::ProcMacro | CrateType::Dylib => { let (prefix, suffix) = - (&sess.target.target.options.dll_prefix, &sess.target.target.options.dll_suffix); + (&sess.target.options.dll_prefix, &sess.target.options.dll_suffix); outputs.out_directory.join(&format!("{}{}{}", prefix, libname, suffix)) } CrateType::Staticlib => { - let (prefix, suffix) = ( - &sess.target.target.options.staticlib_prefix, - &sess.target.target.options.staticlib_suffix, - ); + let (prefix, suffix) = + (&sess.target.options.staticlib_prefix, &sess.target.options.staticlib_suffix); outputs.out_directory.join(&format!("{}{}{}", prefix, libname, suffix)) } CrateType::Executable => { - let suffix = &sess.target.target.options.exe_suffix; + let suffix = &sess.target.options.exe_suffix; let out_filename = outputs.path(OutputType::Exe); if suffix.is_empty() { out_filename } else { out_filename.with_extension(&suffix[1..]) } } @@ -179,35 +177,29 @@ pub fn filename_for_input( /// interaction with Rust code through static library is the only /// option for now pub fn default_output_for_target(sess: &Session) -> CrateType { - if !sess.target.target.options.executables { - CrateType::Staticlib - } else { - CrateType::Executable - } + if !sess.target.options.executables { CrateType::Staticlib } else { CrateType::Executable } } /// Checks if target supports crate_type as output pub fn invalid_output_for_target(sess: &Session, crate_type: CrateType) -> bool { match crate_type { CrateType::Cdylib | CrateType::Dylib | CrateType::ProcMacro => { - if !sess.target.target.options.dynamic_linking { + if !sess.target.options.dynamic_linking { return true; } - if sess.crt_static(Some(crate_type)) - && !sess.target.target.options.crt_static_allows_dylibs - { + if sess.crt_static(Some(crate_type)) && !sess.target.options.crt_static_allows_dylibs { return true; } } _ => {} } - if sess.target.target.options.only_cdylib { + if sess.target.options.only_cdylib { match crate_type { CrateType::ProcMacro | CrateType::Dylib => return true, _ => {} } } - if !sess.target.target.options.executables { + if !sess.target.options.executables { if crate_type == CrateType::Executable { return true; } diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index ff5e6156d84..8312f89b271 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -102,7 +102,7 @@ impl Mul<usize> for Limit { /// Represents the data associated with a compilation /// session for a single crate. pub struct Session { - pub target: config::Config, + pub target: Target, pub host: Target, pub opts: config::Options, pub host_tlib_path: SearchPath, @@ -614,7 +614,7 @@ impl Session { /// Calculates the flavor of LTO to use for this compilation. pub fn lto(&self) -> config::Lto { // If our target has codegen requirements ignore the command line - if self.target.target.options.requires_lto { + if self.target.options.requires_lto { return config::Lto::Fat; } @@ -682,7 +682,7 @@ impl Session { /// Returns the panic strategy for this compile session. If the user explicitly selected one /// using '-C panic', use that, otherwise use the panic strategy defined by the target. pub fn panic_strategy(&self) -> PanicStrategy { - self.opts.cg.panic.unwrap_or(self.target.target.options.panic_strategy) + self.opts.cg.panic.unwrap_or(self.target.options.panic_strategy) } pub fn fewer_names(&self) -> bool { let more_names = self.opts.output_types.contains_key(&OutputType::LlvmAssembly) @@ -706,9 +706,9 @@ impl Session { /// Check whether this compile session and crate type use static crt. pub fn crt_static(&self, crate_type: Option<CrateType>) -> bool { - if !self.target.target.options.crt_static_respected { + if !self.target.options.crt_static_respected { // If the target does not opt in to crt-static support, use its default. - return self.target.target.options.crt_static_default; + return self.target.options.crt_static_default; } let requested_features = self.opts.cg.target_feature.split(','); @@ -725,20 +725,20 @@ impl Session { // We can't check `#![crate_type = "proc-macro"]` here. false } else { - self.target.target.options.crt_static_default + self.target.options.crt_static_default } } pub fn relocation_model(&self) -> RelocModel { - self.opts.cg.relocation_model.unwrap_or(self.target.target.options.relocation_model) + self.opts.cg.relocation_model.unwrap_or(self.target.options.relocation_model) } pub fn code_model(&self) -> Option<CodeModel> { - self.opts.cg.code_model.or(self.target.target.options.code_model) + self.opts.cg.code_model.or(self.target.options.code_model) } pub fn tls_model(&self) -> TlsModel { - self.opts.debugging_opts.tls_model.unwrap_or(self.target.target.options.tls_model) + self.opts.debugging_opts.tls_model.unwrap_or(self.target.options.tls_model) } pub fn must_not_eliminate_frame_pointers(&self) -> bool { @@ -749,7 +749,7 @@ impl Session { } else if let Some(x) = self.opts.cg.force_frame_pointers { x } else { - !self.target.target.options.eliminate_frame_pointer + !self.target.options.eliminate_frame_pointer } } @@ -773,7 +773,7 @@ impl Session { // value, if it is provided, or disable them, if not. if self.panic_strategy() == PanicStrategy::Unwind { true - } else if self.target.target.options.requires_uwtable { + } else if self.target.options.requires_uwtable { true } else { self.opts.cg.force_unwind_tables.unwrap_or(false) @@ -944,7 +944,7 @@ impl Session { if let Some(n) = self.opts.cli_forced_codegen_units { return n; } - if let Some(n) = self.target.target.options.default_codegen_units { + if let Some(n) = self.target.options.default_codegen_units { return n as usize; } @@ -1029,11 +1029,11 @@ impl Session { pub fn needs_plt(&self) -> bool { // Check if the current target usually needs PLT to be enabled. // The user can use the command line flag to override it. - let needs_plt = self.target.target.options.needs_plt; + let needs_plt = self.target.options.needs_plt; let dbg_opts = &self.opts.debugging_opts; - let relro_level = dbg_opts.relro_level.unwrap_or(self.target.target.options.relro_level); + let relro_level = dbg_opts.relro_level.unwrap_or(self.target.options.relro_level); // Only enable this optimization by default if full relro is also enabled. // In this case, lazy binding was already unavailable, so nothing is lost. @@ -1057,8 +1057,7 @@ impl Session { match self.opts.cg.link_dead_code { Some(explicitly_set) => explicitly_set, None => { - self.opts.debugging_opts.instrument_coverage - && !self.target.target.options.is_like_msvc + self.opts.debugging_opts.instrument_coverage && !self.target.options.is_like_msvc // Issue #76038: (rustc `-Clink-dead-code` causes MSVC linker to produce invalid // binaries when LLVM InstrProf counters are enabled). As described by this issue, // the "link dead code" option produces incorrect binaries when compiled and linked @@ -1259,7 +1258,7 @@ pub fn build_session( let loader = file_loader.unwrap_or(Box::new(RealFileLoader)); let hash_kind = sopts.debugging_opts.src_hash_algorithm.unwrap_or_else(|| { - if target_cfg.target.options.is_like_msvc { + if target_cfg.options.is_like_msvc { SourceFileHashAlgorithm::Sha1 } else { SourceFileHashAlgorithm::Md5 @@ -1369,8 +1368,8 @@ pub fn build_session( if candidate.join("library/std/src/lib.rs").is_file() { Some(candidate) } else { None } }; - let asm_arch = if target_cfg.target.options.allow_asm { - InlineAsmArch::from_str(&target_cfg.target.arch).ok() + let asm_arch = if target_cfg.options.allow_asm { + InlineAsmArch::from_str(&target_cfg.arch).ok() } else { None }; @@ -1438,7 +1437,7 @@ fn validate_commandline_args_with_session_available(sess: &Session) { // the `dllimport` attributes and `__imp_` symbols in that case. if sess.opts.cg.linker_plugin_lto.enabled() && sess.opts.cg.prefer_dynamic - && sess.target.target.options.is_like_windows + && sess.target.options.is_like_windows { sess.err( "Linker plugin based LTO is not supported together with \ @@ -1466,7 +1465,7 @@ fn validate_commandline_args_with_session_available(sess: &Session) { ); } - if sess.target.target.options.requires_uwtable && !include_uwtables { + if sess.target.options.requires_uwtable && !include_uwtables { sess.err( "target requires unwind tables, they cannot be disabled with \ `-C force-unwind-tables=no`.", @@ -1481,7 +1480,7 @@ fn validate_commandline_args_with_session_available(sess: &Session) { // We should only display this error if we're actually going to run PGO. // If we're just supposed to print out some data, don't show the error (#61002). if sess.opts.cg.profile_generate.enabled() - && sess.target.target.options.is_like_msvc + && sess.target.options.is_like_msvc && sess.panic_strategy() == PanicStrategy::Unwind && sess.opts.prints.iter().all(|&p| p == PrintRequest::NativeStaticLibs) { @@ -1586,5 +1585,3 @@ pub fn early_warn(output: config::ErrorOutputType, msg: &str) { let handler = rustc_errors::Handler::with_emitter(true, None, emitter); handler.struct_warn(msg).emit(); } - -pub type CompileResult = Result<(), ErrorReported>; diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs index fb80dcb7561..31f3d8e3791 100644 --- a/compiler/rustc_span/src/hygiene.rs +++ b/compiler/rustc_span/src/hygiene.rs @@ -619,14 +619,6 @@ impl SyntaxContext { HygieneData::with(|data| data.outer_mark(self)) } - #[inline] - pub fn outer_mark_with_data(self) -> (ExpnId, Transparency, ExpnData) { - HygieneData::with(|data| { - let (expn_id, transparency) = data.outer_mark(self); - (expn_id, transparency, data.expn_data(expn_id).clone()) - }) - } - pub fn dollar_crate_name(self) -> Symbol { HygieneData::with(|data| data.syntax_context_data[self.0 as usize].dollar_crate_name) } diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index 925f1bd33cb..d036c078049 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -223,12 +223,6 @@ impl FileName { } } - pub fn quote_expansion_source_code(src: &str) -> FileName { - let mut hasher = StableHasher::new(); - src.hash(&mut hasher); - FileName::QuoteExpansion(hasher.finish()) - } - pub fn macro_expansion_source_code(src: &str) -> FileName { let mut hasher = StableHasher::new(); src.hash(&mut hasher); diff --git a/compiler/rustc_span/src/source_map.rs b/compiler/rustc_span/src/source_map.rs index fdb031fd9b3..3b929c4acb9 100644 --- a/compiler/rustc_span/src/source_map.rs +++ b/compiler/rustc_span/src/source_map.rs @@ -451,15 +451,6 @@ impl SourceMap { } } - /// Returns a new `Span` covering the start and end `BytePos`s of the file containing the given - /// `pos`. This can be used to quickly determine if another `BytePos` or `Span` is from the same - /// file. - pub fn lookup_file_span(&self, pos: BytePos) -> Span { - let idx = self.lookup_source_file_idx(pos); - let SourceFile { start_pos, end_pos, .. } = *(*self.files.borrow().source_files)[idx]; - Span::with_root_ctxt(start_pos, end_pos) - } - /// Returns `Some(span)`, a union of the LHS and RHS span. The LHS must precede the RHS. If /// there are gaps between LHS and RHS, the resulting union will cross these gaps. /// For this to work, diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 223a0758f00..9cf530d57c0 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -593,6 +593,7 @@ symbols! { infer_static_outlives_requirements, inlateout, inline, + inline_const, inout, instruction_set, intel, @@ -1114,6 +1115,7 @@ symbols! { try_trait, tt, tuple, + tuple_from_req, tuple_indexing, two_phase, ty, diff --git a/compiler/rustc_symbol_mangling/src/legacy.rs b/compiler/rustc_symbol_mangling/src/legacy.rs index b96e318bd3e..2c9caf73b8e 100644 --- a/compiler/rustc_symbol_mangling/src/legacy.rs +++ b/compiler/rustc_symbol_mangling/src/legacy.rs @@ -115,7 +115,6 @@ fn get_symbol_hash<'tcx>( } // also include any type parameters (for generic items) - assert!(!substs.has_erasable_regions()); substs.hash_stable(&mut hcx, &mut hasher); if let Some(instantiating_crate) = instantiating_crate { diff --git a/compiler/rustc_symbol_mangling/src/lib.rs b/compiler/rustc_symbol_mangling/src/lib.rs index 75150a56c43..28b4a78929e 100644 --- a/compiler/rustc_symbol_mangling/src/lib.rs +++ b/compiler/rustc_symbol_mangling/src/lib.rs @@ -201,7 +201,7 @@ fn compute_symbol_name( // // [1]: https://bugs.llvm.org/show_bug.cgi?id=44316 if is_foreign { - if tcx.sess.target.target.arch != "wasm32" + if tcx.sess.target.arch != "wasm32" || !tcx.wasm_import_module_map(def_id.krate).contains_key(&def_id) { if let Some(name) = attrs.link_name { diff --git a/compiler/rustc_symbol_mangling/src/test.rs b/compiler/rustc_symbol_mangling/src/test.rs index d2c9b05c560..822a8352934 100644 --- a/compiler/rustc_symbol_mangling/src/test.rs +++ b/compiler/rustc_symbol_mangling/src/test.rs @@ -6,7 +6,7 @@ use rustc_hir as hir; use rustc_middle::ty::print::with_no_trimmed_paths; -use rustc_middle::ty::{Instance, TyCtxt}; +use rustc_middle::ty::{subst::InternalSubsts, Instance, TyCtxt}; use rustc_span::symbol::{sym, Symbol}; const SYMBOL_NAME: Symbol = sym::rustc_symbol_name; @@ -36,8 +36,11 @@ impl SymbolNamesTest<'tcx> { let def_id = tcx.hir().local_def_id(hir_id); for attr in tcx.get_attrs(def_id.to_def_id()).iter() { if tcx.sess.check_name(attr, SYMBOL_NAME) { - // for now, can only use on monomorphic names - let instance = Instance::mono(tcx, def_id.to_def_id()); + let def_id = def_id.to_def_id(); + let instance = Instance::new( + def_id, + tcx.erase_regions(&InternalSubsts::identity_for_item(tcx, def_id)), + ); let mangled = tcx.symbol_name(instance); tcx.sess.span_err(attr.span, &format!("symbol-name({})", mangled)); if let Ok(demangling) = rustc_demangle::try_demangle(mangled.name) { diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index da9c93143bf..16d0b86903e 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -132,7 +132,7 @@ impl SymbolMangler<'tcx> { self.push("u"); // FIXME(eddyb) we should probably roll our own punycode implementation. - let mut punycode_bytes = match ::punycode::encode(ident) { + let mut punycode_bytes = match punycode::encode(ident) { Ok(s) => s.into_bytes(), Err(()) => bug!("symbol_names: punycode encoding failed for ident {:?}", ident), }; @@ -259,7 +259,7 @@ impl Printer<'tcx> for SymbolMangler<'tcx> { } fn print_impl_path( - self, + mut self, impl_def_id: DefId, substs: &'tcx [GenericArg<'tcx>], mut self_ty: Ty<'tcx>, @@ -284,12 +284,37 @@ impl Printer<'tcx> for SymbolMangler<'tcx> { } } - self.path_append_impl( - |cx| cx.print_def_path(parent_def_id, &[]), - &key.disambiguated_data, - self_ty, - impl_trait_ref, - ) + self.push(match impl_trait_ref { + Some(_) => "X", + None => "M", + }); + + // Encode impl generic params if the substitutions contain parameters (implying + // polymorphization is enabled) and this isn't an inherent impl. + if impl_trait_ref.is_some() && substs.iter().any(|a| a.has_param_types_or_consts()) { + self = self.path_generic_args( + |this| { + this.path_append_ns( + |cx| cx.print_def_path(parent_def_id, &[]), + 'I', + key.disambiguated_data.disambiguator as u64, + "", + ) + }, + substs, + )?; + } else { + self.push_disambiguator(key.disambiguated_data.disambiguator as u64); + self = self.print_def_path(parent_def_id, &[])?; + } + + self = self_ty.print(self)?; + + if let Some(trait_ref) = impl_trait_ref { + self = self.print_def_path(trait_ref.def_id, trait_ref.substs)?; + } + + Ok(self) } fn print_region(mut self, region: ty::Region<'_>) -> Result<Self::Region, Self::Error> { @@ -538,6 +563,7 @@ impl Printer<'tcx> for SymbolMangler<'tcx> { self.push_ident(&name); Ok(self) } + fn path_qualified( mut self, self_ty: Ty<'tcx>, @@ -552,24 +578,16 @@ impl Printer<'tcx> for SymbolMangler<'tcx> { } fn path_append_impl( - mut self, - print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>, - disambiguated_data: &DisambiguatedDefPathData, - self_ty: Ty<'tcx>, - trait_ref: Option<ty::TraitRef<'tcx>>, + self, + _: impl FnOnce(Self) -> Result<Self::Path, Self::Error>, + _: &DisambiguatedDefPathData, + _: Ty<'tcx>, + _: Option<ty::TraitRef<'tcx>>, ) -> Result<Self::Path, Self::Error> { - self.push(match trait_ref { - Some(_) => "X", - None => "M", - }); - self.push_disambiguator(disambiguated_data.disambiguator as u64); - self = print_prefix(self)?; - self = self_ty.print(self)?; - if let Some(trait_ref) = trait_ref { - self = self.print_def_path(trait_ref.def_id, trait_ref.substs)?; - } - Ok(self) + // Inlined into `print_impl_path` + unreachable!() } + fn path_append( self, print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>, @@ -603,6 +621,7 @@ impl Printer<'tcx> for SymbolMangler<'tcx> { name.as_ref().map_or("", |s| &s[..]), ) } + fn path_generic_args( mut self, print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>, diff --git a/compiler/rustc_target/src/abi/mod.rs b/compiler/rustc_target/src/abi/mod.rs index 3c1a2ea39d3..047b8cf5cdb 100644 --- a/compiler/rustc_target/src/abi/mod.rs +++ b/compiler/rustc_target/src/abi/mod.rs @@ -164,12 +164,12 @@ impl TargetDataLayout { )); } - if dl.pointer_size.bits().to_string() != target.target_pointer_width { + if dl.pointer_size.bits() != target.pointer_width.into() { return Err(format!( "inconsistent target specification: \"data-layout\" claims \ pointers are {}-bit, while \"target-pointer-width\" is `{}`", dl.pointer_size.bits(), - target.target_pointer_width + target.pointer_width )); } diff --git a/compiler/rustc_target/src/spec/aarch64_apple_darwin.rs b/compiler/rustc_target/src/spec/aarch64_apple_darwin.rs index b24518beae2..c15bd9a08fc 100644 --- a/compiler/rustc_target/src/spec/aarch64_apple_darwin.rs +++ b/compiler/rustc_target/src/spec/aarch64_apple_darwin.rs @@ -17,7 +17,7 @@ pub fn target() -> Target { Target { llvm_target, target_endian: "little".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), data_layout: "e-m:o-i64:64-i128:128-n32:64-S128".to_string(), arch: arch.to_string(), diff --git a/compiler/rustc_target/src/spec/aarch64_apple_ios.rs b/compiler/rustc_target/src/spec/aarch64_apple_ios.rs index ab20ec041ab..0019fc4492d 100644 --- a/compiler/rustc_target/src/spec/aarch64_apple_ios.rs +++ b/compiler/rustc_target/src/spec/aarch64_apple_ios.rs @@ -6,7 +6,7 @@ pub fn target() -> Target { Target { llvm_target: "arm64-apple-ios".to_string(), target_endian: "little".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), data_layout: "e-m:o-i64:64-i128:128-n32:64-S128".to_string(), arch: "aarch64".to_string(), diff --git a/compiler/rustc_target/src/spec/aarch64_apple_tvos.rs b/compiler/rustc_target/src/spec/aarch64_apple_tvos.rs index 4619197fc69..276682c591d 100644 --- a/compiler/rustc_target/src/spec/aarch64_apple_tvos.rs +++ b/compiler/rustc_target/src/spec/aarch64_apple_tvos.rs @@ -6,7 +6,7 @@ pub fn target() -> Target { Target { llvm_target: "arm64-apple-tvos".to_string(), target_endian: "little".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), data_layout: "e-m:o-i64:64-i128:128-n32:64-S128".to_string(), arch: "aarch64".to_string(), diff --git a/compiler/rustc_target/src/spec/aarch64_fuchsia.rs b/compiler/rustc_target/src/spec/aarch64_fuchsia.rs index beb2a0912e6..1f81a03c4a5 100644 --- a/compiler/rustc_target/src/spec/aarch64_fuchsia.rs +++ b/compiler/rustc_target/src/spec/aarch64_fuchsia.rs @@ -7,7 +7,7 @@ pub fn target() -> Target { Target { llvm_target: "aarch64-fuchsia".to_string(), target_endian: "little".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".to_string(), arch: "aarch64".to_string(), diff --git a/compiler/rustc_target/src/spec/aarch64_linux_android.rs b/compiler/rustc_target/src/spec/aarch64_linux_android.rs index 519fd98d200..1ed4f0da79c 100644 --- a/compiler/rustc_target/src/spec/aarch64_linux_android.rs +++ b/compiler/rustc_target/src/spec/aarch64_linux_android.rs @@ -12,7 +12,7 @@ pub fn target() -> Target { Target { llvm_target: "aarch64-linux-android".to_string(), target_endian: "little".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".to_string(), arch: "aarch64".to_string(), diff --git a/compiler/rustc_target/src/spec/aarch64_pc_windows_msvc.rs b/compiler/rustc_target/src/spec/aarch64_pc_windows_msvc.rs index 09df41d3360..32fa2d69540 100644 --- a/compiler/rustc_target/src/spec/aarch64_pc_windows_msvc.rs +++ b/compiler/rustc_target/src/spec/aarch64_pc_windows_msvc.rs @@ -9,7 +9,7 @@ pub fn target() -> Target { Target { llvm_target: "aarch64-pc-windows-msvc".to_string(), target_endian: "little".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), data_layout: "e-m:w-p:64:64-i32:32-i64:64-i128:128-n32:64-S128".to_string(), arch: "aarch64".to_string(), diff --git a/compiler/rustc_target/src/spec/aarch64_unknown_cloudabi.rs b/compiler/rustc_target/src/spec/aarch64_unknown_cloudabi.rs index cecf3860fa5..f9d62519bd9 100644 --- a/compiler/rustc_target/src/spec/aarch64_unknown_cloudabi.rs +++ b/compiler/rustc_target/src/spec/aarch64_unknown_cloudabi.rs @@ -9,7 +9,7 @@ pub fn target() -> Target { Target { llvm_target: "aarch64-unknown-cloudabi".to_string(), target_endian: "little".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".to_string(), arch: "aarch64".to_string(), diff --git a/compiler/rustc_target/src/spec/aarch64_unknown_freebsd.rs b/compiler/rustc_target/src/spec/aarch64_unknown_freebsd.rs index 78e9f990de2..3d008290240 100644 --- a/compiler/rustc_target/src/spec/aarch64_unknown_freebsd.rs +++ b/compiler/rustc_target/src/spec/aarch64_unknown_freebsd.rs @@ -7,7 +7,7 @@ pub fn target() -> Target { Target { llvm_target: "aarch64-unknown-freebsd".to_string(), target_endian: "little".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".to_string(), arch: "aarch64".to_string(), diff --git a/compiler/rustc_target/src/spec/aarch64_unknown_hermit.rs b/compiler/rustc_target/src/spec/aarch64_unknown_hermit.rs index c0532925fb9..a7050cbee9e 100644 --- a/compiler/rustc_target/src/spec/aarch64_unknown_hermit.rs +++ b/compiler/rustc_target/src/spec/aarch64_unknown_hermit.rs @@ -7,7 +7,7 @@ pub fn target() -> Target { Target { llvm_target: "aarch64-unknown-hermit".to_string(), target_endian: "little".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".to_string(), arch: "aarch64".to_string(), diff --git a/compiler/rustc_target/src/spec/aarch64_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/aarch64_unknown_linux_gnu.rs index 67ee463c178..10255012e41 100644 --- a/compiler/rustc_target/src/spec/aarch64_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/aarch64_unknown_linux_gnu.rs @@ -7,7 +7,7 @@ pub fn target() -> Target { Target { llvm_target: "aarch64-unknown-linux-gnu".to_string(), target_endian: "little".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), target_env: "gnu".to_string(), data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".to_string(), diff --git a/compiler/rustc_target/src/spec/aarch64_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/aarch64_unknown_linux_musl.rs index cb566c84ed7..f530163faf7 100644 --- a/compiler/rustc_target/src/spec/aarch64_unknown_linux_musl.rs +++ b/compiler/rustc_target/src/spec/aarch64_unknown_linux_musl.rs @@ -7,7 +7,7 @@ pub fn target() -> Target { Target { llvm_target: "aarch64-unknown-linux-musl".to_string(), target_endian: "little".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), target_env: "musl".to_string(), data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".to_string(), diff --git a/compiler/rustc_target/src/spec/aarch64_unknown_netbsd.rs b/compiler/rustc_target/src/spec/aarch64_unknown_netbsd.rs index d6990f7430f..dcb157d7aab 100644 --- a/compiler/rustc_target/src/spec/aarch64_unknown_netbsd.rs +++ b/compiler/rustc_target/src/spec/aarch64_unknown_netbsd.rs @@ -8,7 +8,7 @@ pub fn target() -> Target { Target { llvm_target: "aarch64-unknown-netbsd".to_string(), target_endian: "little".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".to_string(), arch: "aarch64".to_string(), diff --git a/compiler/rustc_target/src/spec/aarch64_unknown_none.rs b/compiler/rustc_target/src/spec/aarch64_unknown_none.rs index fd45acb332a..6d3e72906d5 100644 --- a/compiler/rustc_target/src/spec/aarch64_unknown_none.rs +++ b/compiler/rustc_target/src/spec/aarch64_unknown_none.rs @@ -24,7 +24,7 @@ pub fn target() -> Target { Target { llvm_target: "aarch64-unknown-none".to_string(), target_endian: "little".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), target_os: "none".to_string(), target_env: String::new(), diff --git a/compiler/rustc_target/src/spec/aarch64_unknown_none_softfloat.rs b/compiler/rustc_target/src/spec/aarch64_unknown_none_softfloat.rs index 666f417036e..784cd7eb3c9 100644 --- a/compiler/rustc_target/src/spec/aarch64_unknown_none_softfloat.rs +++ b/compiler/rustc_target/src/spec/aarch64_unknown_none_softfloat.rs @@ -24,7 +24,7 @@ pub fn target() -> Target { Target { llvm_target: "aarch64-unknown-none".to_string(), target_endian: "little".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), target_os: "none".to_string(), target_env: String::new(), diff --git a/compiler/rustc_target/src/spec/aarch64_unknown_openbsd.rs b/compiler/rustc_target/src/spec/aarch64_unknown_openbsd.rs index 2b7dbc0ebdb..e03690e86b8 100644 --- a/compiler/rustc_target/src/spec/aarch64_unknown_openbsd.rs +++ b/compiler/rustc_target/src/spec/aarch64_unknown_openbsd.rs @@ -8,7 +8,7 @@ pub fn target() -> Target { Target { llvm_target: "aarch64-unknown-openbsd".to_string(), target_endian: "little".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".to_string(), arch: "aarch64".to_string(), diff --git a/compiler/rustc_target/src/spec/aarch64_unknown_redox.rs b/compiler/rustc_target/src/spec/aarch64_unknown_redox.rs index 5f151473e0f..13adec9d4c4 100644 --- a/compiler/rustc_target/src/spec/aarch64_unknown_redox.rs +++ b/compiler/rustc_target/src/spec/aarch64_unknown_redox.rs @@ -7,7 +7,7 @@ pub fn target() -> Target { Target { llvm_target: "aarch64-unknown-redox".to_string(), target_endian: "little".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".to_string(), arch: "aarch64".to_string(), diff --git a/compiler/rustc_target/src/spec/aarch64_uwp_windows_msvc.rs b/compiler/rustc_target/src/spec/aarch64_uwp_windows_msvc.rs index 7dfcc1c065f..d6af5dd3628 100644 --- a/compiler/rustc_target/src/spec/aarch64_uwp_windows_msvc.rs +++ b/compiler/rustc_target/src/spec/aarch64_uwp_windows_msvc.rs @@ -8,7 +8,7 @@ pub fn target() -> Target { Target { llvm_target: "aarch64-pc-windows-msvc".to_string(), target_endian: "little".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), data_layout: "e-m:w-p:64:64-i32:32-i64:64-i128:128-n32:64-S128".to_string(), arch: "aarch64".to_string(), diff --git a/compiler/rustc_target/src/spec/aarch64_wrs_vxworks.rs b/compiler/rustc_target/src/spec/aarch64_wrs_vxworks.rs index fc2d192ef12..6fce200a96e 100644 --- a/compiler/rustc_target/src/spec/aarch64_wrs_vxworks.rs +++ b/compiler/rustc_target/src/spec/aarch64_wrs_vxworks.rs @@ -7,7 +7,7 @@ pub fn target() -> Target { Target { llvm_target: "aarch64-unknown-linux-gnu".to_string(), target_endian: "little".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".to_string(), arch: "aarch64".to_string(), diff --git a/compiler/rustc_target/src/spec/android_base.rs b/compiler/rustc_target/src/spec/android_base.rs index bb11ce8ef28..0824bc30358 100644 --- a/compiler/rustc_target/src/spec/android_base.rs +++ b/compiler/rustc_target/src/spec/android_base.rs @@ -9,6 +9,7 @@ pub fn opts() -> TargetOptions { .unwrap() .push("-Wl,--allow-multiple-definition".to_string()); base.is_like_android = true; + base.dwarf_version = Some(2); base.position_independent_executables = true; base.has_elf_tls = false; base.requires_uwtable = true; diff --git a/compiler/rustc_target/src/spec/apple_base.rs b/compiler/rustc_target/src/spec/apple_base.rs index e7b565ae9ca..2e3c835c0e5 100644 --- a/compiler/rustc_target/src/spec/apple_base.rs +++ b/compiler/rustc_target/src/spec/apple_base.rs @@ -23,6 +23,7 @@ pub fn opts() -> TargetOptions { executables: true, target_family: Some("unix".to_string()), is_like_osx: true, + dwarf_version: Some(2), has_rpath: true, dll_prefix: "lib".to_string(), dll_suffix: ".dylib".to_string(), diff --git a/compiler/rustc_target/src/spec/arm_linux_androideabi.rs b/compiler/rustc_target/src/spec/arm_linux_androideabi.rs index 7ea00800562..f9c69217460 100644 --- a/compiler/rustc_target/src/spec/arm_linux_androideabi.rs +++ b/compiler/rustc_target/src/spec/arm_linux_androideabi.rs @@ -9,7 +9,7 @@ pub fn target() -> Target { Target { llvm_target: "arm-linux-androideabi".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(), arch: "arm".to_string(), diff --git a/compiler/rustc_target/src/spec/arm_unknown_linux_gnueabi.rs b/compiler/rustc_target/src/spec/arm_unknown_linux_gnueabi.rs index 0573cf5ba9d..96a444fc465 100644 --- a/compiler/rustc_target/src/spec/arm_unknown_linux_gnueabi.rs +++ b/compiler/rustc_target/src/spec/arm_unknown_linux_gnueabi.rs @@ -6,7 +6,7 @@ pub fn target() -> Target { Target { llvm_target: "arm-unknown-linux-gnueabi".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(), arch: "arm".to_string(), diff --git a/compiler/rustc_target/src/spec/arm_unknown_linux_gnueabihf.rs b/compiler/rustc_target/src/spec/arm_unknown_linux_gnueabihf.rs index dbd68e366a1..534b98cc607 100644 --- a/compiler/rustc_target/src/spec/arm_unknown_linux_gnueabihf.rs +++ b/compiler/rustc_target/src/spec/arm_unknown_linux_gnueabihf.rs @@ -6,7 +6,7 @@ pub fn target() -> Target { Target { llvm_target: "arm-unknown-linux-gnueabihf".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(), arch: "arm".to_string(), diff --git a/compiler/rustc_target/src/spec/arm_unknown_linux_musleabi.rs b/compiler/rustc_target/src/spec/arm_unknown_linux_musleabi.rs index cd5c181ec61..e5fa3e3a1cb 100644 --- a/compiler/rustc_target/src/spec/arm_unknown_linux_musleabi.rs +++ b/compiler/rustc_target/src/spec/arm_unknown_linux_musleabi.rs @@ -13,7 +13,7 @@ pub fn target() -> Target { // support the "musleabi" value. llvm_target: "arm-unknown-linux-gnueabi".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(), arch: "arm".to_string(), diff --git a/compiler/rustc_target/src/spec/arm_unknown_linux_musleabihf.rs b/compiler/rustc_target/src/spec/arm_unknown_linux_musleabihf.rs index 2b99cd01e59..b631a0010a0 100644 --- a/compiler/rustc_target/src/spec/arm_unknown_linux_musleabihf.rs +++ b/compiler/rustc_target/src/spec/arm_unknown_linux_musleabihf.rs @@ -13,7 +13,7 @@ pub fn target() -> Target { // doesn't support the "musleabihf" value. llvm_target: "arm-unknown-linux-gnueabihf".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(), arch: "arm".to_string(), diff --git a/compiler/rustc_target/src/spec/armebv7r_none_eabi.rs b/compiler/rustc_target/src/spec/armebv7r_none_eabi.rs index c414810dab2..86d0cd57af3 100644 --- a/compiler/rustc_target/src/spec/armebv7r_none_eabi.rs +++ b/compiler/rustc_target/src/spec/armebv7r_none_eabi.rs @@ -7,7 +7,7 @@ pub fn target() -> Target { Target { llvm_target: "armebv7r-unknown-none-eabi".to_string(), target_endian: "big".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "E-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(), arch: "arm".to_string(), diff --git a/compiler/rustc_target/src/spec/armebv7r_none_eabihf.rs b/compiler/rustc_target/src/spec/armebv7r_none_eabihf.rs index 608095db197..9ea44b3b25e 100644 --- a/compiler/rustc_target/src/spec/armebv7r_none_eabihf.rs +++ b/compiler/rustc_target/src/spec/armebv7r_none_eabihf.rs @@ -7,7 +7,7 @@ pub fn target() -> Target { Target { llvm_target: "armebv7r-unknown-none-eabihf".to_string(), target_endian: "big".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "E-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(), arch: "arm".to_string(), diff --git a/compiler/rustc_target/src/spec/armv4t_unknown_linux_gnueabi.rs b/compiler/rustc_target/src/spec/armv4t_unknown_linux_gnueabi.rs index 3ebf60f855e..be32731a869 100644 --- a/compiler/rustc_target/src/spec/armv4t_unknown_linux_gnueabi.rs +++ b/compiler/rustc_target/src/spec/armv4t_unknown_linux_gnueabi.rs @@ -5,7 +5,7 @@ pub fn target() -> Target { Target { llvm_target: "armv4t-unknown-linux-gnueabi".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(), arch: "arm".to_string(), diff --git a/compiler/rustc_target/src/spec/armv5te_unknown_linux_gnueabi.rs b/compiler/rustc_target/src/spec/armv5te_unknown_linux_gnueabi.rs index ff7d7e6c087..4ea4b650623 100644 --- a/compiler/rustc_target/src/spec/armv5te_unknown_linux_gnueabi.rs +++ b/compiler/rustc_target/src/spec/armv5te_unknown_linux_gnueabi.rs @@ -5,7 +5,7 @@ pub fn target() -> Target { Target { llvm_target: "armv5te-unknown-linux-gnueabi".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(), arch: "arm".to_string(), diff --git a/compiler/rustc_target/src/spec/armv5te_unknown_linux_musleabi.rs b/compiler/rustc_target/src/spec/armv5te_unknown_linux_musleabi.rs index da9855bbe55..a41a5409ac9 100644 --- a/compiler/rustc_target/src/spec/armv5te_unknown_linux_musleabi.rs +++ b/compiler/rustc_target/src/spec/armv5te_unknown_linux_musleabi.rs @@ -8,7 +8,7 @@ pub fn target() -> Target { // doesn't support the "musleabihf" value. llvm_target: "armv5te-unknown-linux-gnueabi".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(), arch: "arm".to_string(), diff --git a/compiler/rustc_target/src/spec/armv6_unknown_freebsd.rs b/compiler/rustc_target/src/spec/armv6_unknown_freebsd.rs index 902dac30b51..68f6502133a 100644 --- a/compiler/rustc_target/src/spec/armv6_unknown_freebsd.rs +++ b/compiler/rustc_target/src/spec/armv6_unknown_freebsd.rs @@ -5,7 +5,7 @@ pub fn target() -> Target { Target { llvm_target: "armv6-unknown-freebsd-gnueabihf".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(), arch: "arm".to_string(), diff --git a/compiler/rustc_target/src/spec/armv6_unknown_netbsd_eabihf.rs b/compiler/rustc_target/src/spec/armv6_unknown_netbsd_eabihf.rs index 7f611defe90..23a20ca1c9f 100644 --- a/compiler/rustc_target/src/spec/armv6_unknown_netbsd_eabihf.rs +++ b/compiler/rustc_target/src/spec/armv6_unknown_netbsd_eabihf.rs @@ -6,7 +6,7 @@ pub fn target() -> Target { Target { llvm_target: "armv6-unknown-netbsdelf-eabihf".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(), arch: "arm".to_string(), diff --git a/compiler/rustc_target/src/spec/armv7_apple_ios.rs b/compiler/rustc_target/src/spec/armv7_apple_ios.rs index ac24e872a9a..24a47dd56a9 100644 --- a/compiler/rustc_target/src/spec/armv7_apple_ios.rs +++ b/compiler/rustc_target/src/spec/armv7_apple_ios.rs @@ -6,7 +6,7 @@ pub fn target() -> Target { Target { llvm_target: "armv7-apple-ios".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "e-m:o-p:32:32-Fi8-f64:32:64-v64:32:64-v128:32:128-a:0:32-n32-S32".to_string(), arch: "arm".to_string(), diff --git a/compiler/rustc_target/src/spec/armv7_linux_androideabi.rs b/compiler/rustc_target/src/spec/armv7_linux_androideabi.rs index ebaef615ac3..342959883cb 100644 --- a/compiler/rustc_target/src/spec/armv7_linux_androideabi.rs +++ b/compiler/rustc_target/src/spec/armv7_linux_androideabi.rs @@ -17,7 +17,7 @@ pub fn target() -> Target { Target { llvm_target: "armv7-none-linux-android".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(), arch: "arm".to_string(), diff --git a/compiler/rustc_target/src/spec/armv7_unknown_cloudabi_eabihf.rs b/compiler/rustc_target/src/spec/armv7_unknown_cloudabi_eabihf.rs index 5a1391ccedd..d4bb4e963fb 100644 --- a/compiler/rustc_target/src/spec/armv7_unknown_cloudabi_eabihf.rs +++ b/compiler/rustc_target/src/spec/armv7_unknown_cloudabi_eabihf.rs @@ -11,7 +11,7 @@ pub fn target() -> Target { Target { llvm_target: "armv7-unknown-cloudabi-eabihf".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(), arch: "arm".to_string(), diff --git a/compiler/rustc_target/src/spec/armv7_unknown_freebsd.rs b/compiler/rustc_target/src/spec/armv7_unknown_freebsd.rs index 08d7d268148..c32e2d4376e 100644 --- a/compiler/rustc_target/src/spec/armv7_unknown_freebsd.rs +++ b/compiler/rustc_target/src/spec/armv7_unknown_freebsd.rs @@ -5,7 +5,7 @@ pub fn target() -> Target { Target { llvm_target: "armv7-unknown-freebsd-gnueabihf".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(), arch: "arm".to_string(), diff --git a/compiler/rustc_target/src/spec/armv7_unknown_linux_gnueabi.rs b/compiler/rustc_target/src/spec/armv7_unknown_linux_gnueabi.rs index 02abd02f3b2..66d3b3e5d07 100644 --- a/compiler/rustc_target/src/spec/armv7_unknown_linux_gnueabi.rs +++ b/compiler/rustc_target/src/spec/armv7_unknown_linux_gnueabi.rs @@ -8,7 +8,7 @@ pub fn target() -> Target { Target { llvm_target: "armv7-unknown-linux-gnueabi".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(), arch: "arm".to_string(), diff --git a/compiler/rustc_target/src/spec/armv7_unknown_linux_gnueabihf.rs b/compiler/rustc_target/src/spec/armv7_unknown_linux_gnueabihf.rs index d63c728fe4b..c1ef540a01d 100644 --- a/compiler/rustc_target/src/spec/armv7_unknown_linux_gnueabihf.rs +++ b/compiler/rustc_target/src/spec/armv7_unknown_linux_gnueabihf.rs @@ -8,7 +8,7 @@ pub fn target() -> Target { Target { llvm_target: "armv7-unknown-linux-gnueabihf".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(), arch: "arm".to_string(), diff --git a/compiler/rustc_target/src/spec/armv7_unknown_linux_musleabi.rs b/compiler/rustc_target/src/spec/armv7_unknown_linux_musleabi.rs index 93a004fa002..d4d26b14556 100644 --- a/compiler/rustc_target/src/spec/armv7_unknown_linux_musleabi.rs +++ b/compiler/rustc_target/src/spec/armv7_unknown_linux_musleabi.rs @@ -13,7 +13,7 @@ pub fn target() -> Target { // support the "musleabi" value. llvm_target: "armv7-unknown-linux-gnueabi".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(), arch: "arm".to_string(), diff --git a/compiler/rustc_target/src/spec/armv7_unknown_linux_musleabihf.rs b/compiler/rustc_target/src/spec/armv7_unknown_linux_musleabihf.rs index 93a87ff44ef..88db04a74e2 100644 --- a/compiler/rustc_target/src/spec/armv7_unknown_linux_musleabihf.rs +++ b/compiler/rustc_target/src/spec/armv7_unknown_linux_musleabihf.rs @@ -10,7 +10,7 @@ pub fn target() -> Target { // doesn't support the "musleabihf" value. llvm_target: "armv7-unknown-linux-gnueabihf".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(), arch: "arm".to_string(), diff --git a/compiler/rustc_target/src/spec/armv7_unknown_netbsd_eabihf.rs b/compiler/rustc_target/src/spec/armv7_unknown_netbsd_eabihf.rs index c3a2324130c..fe2471ab0d0 100644 --- a/compiler/rustc_target/src/spec/armv7_unknown_netbsd_eabihf.rs +++ b/compiler/rustc_target/src/spec/armv7_unknown_netbsd_eabihf.rs @@ -5,7 +5,7 @@ pub fn target() -> Target { Target { llvm_target: "armv7-unknown-netbsdelf-eabihf".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(), arch: "arm".to_string(), diff --git a/compiler/rustc_target/src/spec/armv7_wrs_vxworks_eabihf.rs b/compiler/rustc_target/src/spec/armv7_wrs_vxworks_eabihf.rs index 4d95a279218..9b8cefdfa9e 100644 --- a/compiler/rustc_target/src/spec/armv7_wrs_vxworks_eabihf.rs +++ b/compiler/rustc_target/src/spec/armv7_wrs_vxworks_eabihf.rs @@ -5,7 +5,7 @@ pub fn target() -> Target { Target { llvm_target: "armv7-unknown-linux-gnueabihf".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(), arch: "arm".to_string(), diff --git a/compiler/rustc_target/src/spec/armv7a_none_eabi.rs b/compiler/rustc_target/src/spec/armv7a_none_eabi.rs index dfd60601f4d..4199ac4569a 100644 --- a/compiler/rustc_target/src/spec/armv7a_none_eabi.rs +++ b/compiler/rustc_target/src/spec/armv7a_none_eabi.rs @@ -35,7 +35,7 @@ pub fn target() -> Target { Target { llvm_target: "armv7a-none-eabi".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), target_os: "none".to_string(), target_env: String::new(), diff --git a/compiler/rustc_target/src/spec/armv7a_none_eabihf.rs b/compiler/rustc_target/src/spec/armv7a_none_eabihf.rs index 340d9788d23..99a06590097 100644 --- a/compiler/rustc_target/src/spec/armv7a_none_eabihf.rs +++ b/compiler/rustc_target/src/spec/armv7a_none_eabihf.rs @@ -23,7 +23,7 @@ pub fn target() -> Target { Target { llvm_target: "armv7a-none-eabihf".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), target_os: "none".to_string(), target_env: String::new(), diff --git a/compiler/rustc_target/src/spec/armv7r_none_eabi.rs b/compiler/rustc_target/src/spec/armv7r_none_eabi.rs index a3994e72490..f0e79072bc1 100644 --- a/compiler/rustc_target/src/spec/armv7r_none_eabi.rs +++ b/compiler/rustc_target/src/spec/armv7r_none_eabi.rs @@ -7,7 +7,7 @@ pub fn target() -> Target { Target { llvm_target: "armv7r-unknown-none-eabi".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(), arch: "arm".to_string(), diff --git a/compiler/rustc_target/src/spec/armv7r_none_eabihf.rs b/compiler/rustc_target/src/spec/armv7r_none_eabihf.rs index 3248679dc45..4c464d2b256 100644 --- a/compiler/rustc_target/src/spec/armv7r_none_eabihf.rs +++ b/compiler/rustc_target/src/spec/armv7r_none_eabihf.rs @@ -7,7 +7,7 @@ pub fn target() -> Target { Target { llvm_target: "armv7r-unknown-none-eabihf".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(), arch: "arm".to_string(), diff --git a/compiler/rustc_target/src/spec/armv7s_apple_ios.rs b/compiler/rustc_target/src/spec/armv7s_apple_ios.rs index 54f1b1a2ac2..4c2d70ae34b 100644 --- a/compiler/rustc_target/src/spec/armv7s_apple_ios.rs +++ b/compiler/rustc_target/src/spec/armv7s_apple_ios.rs @@ -6,7 +6,7 @@ pub fn target() -> Target { Target { llvm_target: "armv7s-apple-ios".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "e-m:o-p:32:32-Fi8-f64:32:64-v64:32:64-v128:32:128-a:0:32-n32-S32".to_string(), arch: "arm".to_string(), diff --git a/compiler/rustc_target/src/spec/avr_gnu_base.rs b/compiler/rustc_target/src/spec/avr_gnu_base.rs index 83a048b06ba..01445dc3898 100644 --- a/compiler/rustc_target/src/spec/avr_gnu_base.rs +++ b/compiler/rustc_target/src/spec/avr_gnu_base.rs @@ -9,7 +9,7 @@ pub fn target(target_cpu: String) -> Target { data_layout: "e-P1-p:16:8-i8:8-i16:8-i32:8-i64:8-f32:8-f64:8-n8-a:8".to_string(), llvm_target: "avr-unknown-unknown".to_string(), target_endian: "little".to_string(), - target_pointer_width: "16".to_string(), + pointer_width: 16, linker_flavor: LinkerFlavor::Gcc, target_os: "unknown".to_string(), target_env: "".to_string(), diff --git a/compiler/rustc_target/src/spec/dragonfly_base.rs b/compiler/rustc_target/src/spec/dragonfly_base.rs index c7062e1ca51..82dc5f54659 100644 --- a/compiler/rustc_target/src/spec/dragonfly_base.rs +++ b/compiler/rustc_target/src/spec/dragonfly_base.rs @@ -24,6 +24,7 @@ pub fn opts() -> TargetOptions { pre_link_args: args, position_independent_executables: true, relro_level: RelroLevel::Full, + dwarf_version: Some(2), ..Default::default() } } diff --git a/compiler/rustc_target/src/spec/freebsd_base.rs b/compiler/rustc_target/src/spec/freebsd_base.rs index d2a087ab62f..051325a8df6 100644 --- a/compiler/rustc_target/src/spec/freebsd_base.rs +++ b/compiler/rustc_target/src/spec/freebsd_base.rs @@ -26,6 +26,7 @@ pub fn opts() -> TargetOptions { eliminate_frame_pointer: false, // FIXME 43575 relro_level: RelroLevel::Full, abi_return_struct_as_int: true, + dwarf_version: Some(2), ..Default::default() } } diff --git a/compiler/rustc_target/src/spec/hexagon_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/hexagon_unknown_linux_musl.rs index 65b305aa84b..143b93dfeef 100644 --- a/compiler/rustc_target/src/spec/hexagon_unknown_linux_musl.rs +++ b/compiler/rustc_target/src/spec/hexagon_unknown_linux_musl.rs @@ -20,7 +20,7 @@ pub fn target() -> Target { Target { llvm_target: "hexagon-unknown-linux-musl".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: concat!( "e-m:e-p:32:32:32-a:0-n16:32-i64:64:64-i32:32", diff --git a/compiler/rustc_target/src/spec/i386_apple_ios.rs b/compiler/rustc_target/src/spec/i386_apple_ios.rs index 4f6b8b25842..21421497965 100644 --- a/compiler/rustc_target/src/spec/i386_apple_ios.rs +++ b/compiler/rustc_target/src/spec/i386_apple_ios.rs @@ -6,7 +6,7 @@ pub fn target() -> Target { Target { llvm_target: "i386-apple-ios".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "e-m:o-p:32:32-p270:32:32-p271:32:32-p272:64:64-\ f64:32:64-f80:128-n8:16:32-S128" diff --git a/compiler/rustc_target/src/spec/i686_apple_darwin.rs b/compiler/rustc_target/src/spec/i686_apple_darwin.rs index 62a0e415094..9c7e7241b57 100644 --- a/compiler/rustc_target/src/spec/i686_apple_darwin.rs +++ b/compiler/rustc_target/src/spec/i686_apple_darwin.rs @@ -18,7 +18,7 @@ pub fn target() -> Target { Target { llvm_target, target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "e-m:o-p:32:32-p270:32:32-p271:32:32-p272:64:64-\ f64:32:64-f80:128-n8:16:32-S128" diff --git a/compiler/rustc_target/src/spec/i686_linux_android.rs b/compiler/rustc_target/src/spec/i686_linux_android.rs index 529e0d39290..d116ae62e0f 100644 --- a/compiler/rustc_target/src/spec/i686_linux_android.rs +++ b/compiler/rustc_target/src/spec/i686_linux_android.rs @@ -16,7 +16,7 @@ pub fn target() -> Target { Target { llvm_target: "i686-linux-android".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-\ f64:32:64-f80:32-n8:16:32-S128" diff --git a/compiler/rustc_target/src/spec/i686_pc_windows_gnu.rs b/compiler/rustc_target/src/spec/i686_pc_windows_gnu.rs index 64a975ee1bc..84585bd515a 100644 --- a/compiler/rustc_target/src/spec/i686_pc_windows_gnu.rs +++ b/compiler/rustc_target/src/spec/i686_pc_windows_gnu.rs @@ -19,7 +19,7 @@ pub fn target() -> Target { Target { llvm_target: "i686-pc-windows-gnu".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "e-m:x-p:32:32-p270:32:32-p271:32:32-p272:64:64-\ i64:64-f80:32-n8:16:32-a:0:32-S32" diff --git a/compiler/rustc_target/src/spec/i686_pc_windows_msvc.rs b/compiler/rustc_target/src/spec/i686_pc_windows_msvc.rs index 2de1f07844e..db20b6094b7 100644 --- a/compiler/rustc_target/src/spec/i686_pc_windows_msvc.rs +++ b/compiler/rustc_target/src/spec/i686_pc_windows_msvc.rs @@ -23,7 +23,7 @@ pub fn target() -> Target { Target { llvm_target: "i686-pc-windows-msvc".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "e-m:x-p:32:32-p270:32:32-p271:32:32-p272:64:64-\ i64:64-f80:32-n8:16:32-a:0:32-S32" diff --git a/compiler/rustc_target/src/spec/i686_unknown_cloudabi.rs b/compiler/rustc_target/src/spec/i686_unknown_cloudabi.rs index 6cd34f38c57..d9365d59e0e 100644 --- a/compiler/rustc_target/src/spec/i686_unknown_cloudabi.rs +++ b/compiler/rustc_target/src/spec/i686_unknown_cloudabi.rs @@ -11,7 +11,7 @@ pub fn target() -> Target { Target { llvm_target: "i686-unknown-cloudabi".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-\ f64:32:64-f80:32-n8:16:32-S128" diff --git a/compiler/rustc_target/src/spec/i686_unknown_freebsd.rs b/compiler/rustc_target/src/spec/i686_unknown_freebsd.rs index 691820a3010..ba379a40f50 100644 --- a/compiler/rustc_target/src/spec/i686_unknown_freebsd.rs +++ b/compiler/rustc_target/src/spec/i686_unknown_freebsd.rs @@ -12,7 +12,7 @@ pub fn target() -> Target { Target { llvm_target: "i686-unknown-freebsd".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-\ f64:32:64-f80:32-n8:16:32-S128" diff --git a/compiler/rustc_target/src/spec/i686_unknown_haiku.rs b/compiler/rustc_target/src/spec/i686_unknown_haiku.rs index cfc3a74104b..02754b39fa7 100644 --- a/compiler/rustc_target/src/spec/i686_unknown_haiku.rs +++ b/compiler/rustc_target/src/spec/i686_unknown_haiku.rs @@ -10,7 +10,7 @@ pub fn target() -> Target { Target { llvm_target: "i686-unknown-haiku".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-\ f64:32:64-f80:32-n8:16:32-S128" diff --git a/compiler/rustc_target/src/spec/i686_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/i686_unknown_linux_gnu.rs index 1e0efca8eed..b7ceaefef93 100644 --- a/compiler/rustc_target/src/spec/i686_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/i686_unknown_linux_gnu.rs @@ -10,7 +10,7 @@ pub fn target() -> Target { Target { llvm_target: "i686-unknown-linux-gnu".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-\ f64:32:64-f80:32-n8:16:32-S128" diff --git a/compiler/rustc_target/src/spec/i686_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/i686_unknown_linux_musl.rs index 6e4259176cf..9240b56aeaf 100644 --- a/compiler/rustc_target/src/spec/i686_unknown_linux_musl.rs +++ b/compiler/rustc_target/src/spec/i686_unknown_linux_musl.rs @@ -25,7 +25,7 @@ pub fn target() -> Target { Target { llvm_target: "i686-unknown-linux-musl".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-\ f64:32:64-f80:32-n8:16:32-S128" diff --git a/compiler/rustc_target/src/spec/i686_unknown_netbsd.rs b/compiler/rustc_target/src/spec/i686_unknown_netbsd.rs index 7305578ab6a..a4421924a7b 100644 --- a/compiler/rustc_target/src/spec/i686_unknown_netbsd.rs +++ b/compiler/rustc_target/src/spec/i686_unknown_netbsd.rs @@ -10,7 +10,7 @@ pub fn target() -> Target { Target { llvm_target: "i686-unknown-netbsdelf".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-\ f64:32:64-f80:32-n8:16:32-S128" diff --git a/compiler/rustc_target/src/spec/i686_unknown_openbsd.rs b/compiler/rustc_target/src/spec/i686_unknown_openbsd.rs index f5b292685fa..fe5030f661b 100644 --- a/compiler/rustc_target/src/spec/i686_unknown_openbsd.rs +++ b/compiler/rustc_target/src/spec/i686_unknown_openbsd.rs @@ -11,7 +11,7 @@ pub fn target() -> Target { Target { llvm_target: "i686-unknown-openbsd".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-\ f64:32:64-f80:32-n8:16:32-S128" diff --git a/compiler/rustc_target/src/spec/i686_unknown_uefi.rs b/compiler/rustc_target/src/spec/i686_unknown_uefi.rs index bb3b0b70744..676a8ca0acc 100644 --- a/compiler/rustc_target/src/spec/i686_unknown_uefi.rs +++ b/compiler/rustc_target/src/spec/i686_unknown_uefi.rs @@ -79,7 +79,7 @@ pub fn target() -> Target { Target { llvm_target: "i686-unknown-windows-gnu".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "e-m:x-p:32:32-p270:32:32-p271:32:32-p272:64:64-\ i64:64-f80:32-n8:16:32-a:0:32-S32" diff --git a/compiler/rustc_target/src/spec/i686_uwp_windows_gnu.rs b/compiler/rustc_target/src/spec/i686_uwp_windows_gnu.rs index 100e0706bc1..ec5a9cc68ce 100644 --- a/compiler/rustc_target/src/spec/i686_uwp_windows_gnu.rs +++ b/compiler/rustc_target/src/spec/i686_uwp_windows_gnu.rs @@ -18,7 +18,7 @@ pub fn target() -> Target { Target { llvm_target: "i686-pc-windows-gnu".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "e-m:x-p:32:32-p270:32:32-p271:32:32-p272:64:64-\ i64:64-f80:32-n8:16:32-a:0:32-S32" diff --git a/compiler/rustc_target/src/spec/i686_uwp_windows_msvc.rs b/compiler/rustc_target/src/spec/i686_uwp_windows_msvc.rs index d4426a4eb9e..d960a130351 100644 --- a/compiler/rustc_target/src/spec/i686_uwp_windows_msvc.rs +++ b/compiler/rustc_target/src/spec/i686_uwp_windows_msvc.rs @@ -9,7 +9,7 @@ pub fn target() -> Target { Target { llvm_target: "i686-pc-windows-msvc".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "e-m:x-p:32:32-p270:32:32-p271:32:32-p272:64:64-\ i64:64-f80:32-n8:16:32-a:0:32-S32" diff --git a/compiler/rustc_target/src/spec/i686_wrs_vxworks.rs b/compiler/rustc_target/src/spec/i686_wrs_vxworks.rs index 8320beefb27..0e5c7b6143e 100644 --- a/compiler/rustc_target/src/spec/i686_wrs_vxworks.rs +++ b/compiler/rustc_target/src/spec/i686_wrs_vxworks.rs @@ -10,7 +10,7 @@ pub fn target() -> Target { Target { llvm_target: "i686-unknown-linux-gnu".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-\ f64:32:64-f80:32-n8:16:32-S128" diff --git a/compiler/rustc_target/src/spec/mips64_unknown_linux_gnuabi64.rs b/compiler/rustc_target/src/spec/mips64_unknown_linux_gnuabi64.rs index f20d337931e..5cbd6bcd3d8 100644 --- a/compiler/rustc_target/src/spec/mips64_unknown_linux_gnuabi64.rs +++ b/compiler/rustc_target/src/spec/mips64_unknown_linux_gnuabi64.rs @@ -4,7 +4,7 @@ pub fn target() -> Target { Target { llvm_target: "mips64-unknown-linux-gnuabi64".to_string(), target_endian: "big".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), data_layout: "E-m:e-i8:8:32-i16:16:32-i64:64-n32:64-S128".to_string(), arch: "mips64".to_string(), diff --git a/compiler/rustc_target/src/spec/mips64_unknown_linux_muslabi64.rs b/compiler/rustc_target/src/spec/mips64_unknown_linux_muslabi64.rs index edddcd616bf..3ca92dd1d04 100644 --- a/compiler/rustc_target/src/spec/mips64_unknown_linux_muslabi64.rs +++ b/compiler/rustc_target/src/spec/mips64_unknown_linux_muslabi64.rs @@ -9,7 +9,7 @@ pub fn target() -> Target { // LLVM doesn't recognize "muslabi64" yet. llvm_target: "mips64-unknown-linux-musl".to_string(), target_endian: "big".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), data_layout: "E-m:e-i8:8:32-i16:16:32-i64:64-n32:64-S128".to_string(), arch: "mips64".to_string(), diff --git a/compiler/rustc_target/src/spec/mips64el_unknown_linux_gnuabi64.rs b/compiler/rustc_target/src/spec/mips64el_unknown_linux_gnuabi64.rs index 031c5229f7e..4761be5b7ef 100644 --- a/compiler/rustc_target/src/spec/mips64el_unknown_linux_gnuabi64.rs +++ b/compiler/rustc_target/src/spec/mips64el_unknown_linux_gnuabi64.rs @@ -4,7 +4,7 @@ pub fn target() -> Target { Target { llvm_target: "mips64el-unknown-linux-gnuabi64".to_string(), target_endian: "little".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-n32:64-S128".to_string(), arch: "mips64".to_string(), diff --git a/compiler/rustc_target/src/spec/mips64el_unknown_linux_muslabi64.rs b/compiler/rustc_target/src/spec/mips64el_unknown_linux_muslabi64.rs index d76d0d3930b..d87170b6868 100644 --- a/compiler/rustc_target/src/spec/mips64el_unknown_linux_muslabi64.rs +++ b/compiler/rustc_target/src/spec/mips64el_unknown_linux_muslabi64.rs @@ -9,7 +9,7 @@ pub fn target() -> Target { // LLVM doesn't recognize "muslabi64" yet. llvm_target: "mips64el-unknown-linux-musl".to_string(), target_endian: "little".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-n32:64-S128".to_string(), arch: "mips64".to_string(), diff --git a/compiler/rustc_target/src/spec/mips_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/mips_unknown_linux_gnu.rs index ebead1ce64f..e51cf3c59f6 100644 --- a/compiler/rustc_target/src/spec/mips_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/mips_unknown_linux_gnu.rs @@ -4,7 +4,7 @@ pub fn target() -> Target { Target { llvm_target: "mips-unknown-linux-gnu".to_string(), target_endian: "big".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "E-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64".to_string(), arch: "mips".to_string(), diff --git a/compiler/rustc_target/src/spec/mips_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/mips_unknown_linux_musl.rs index 0042244569a..44d136ee7e9 100644 --- a/compiler/rustc_target/src/spec/mips_unknown_linux_musl.rs +++ b/compiler/rustc_target/src/spec/mips_unknown_linux_musl.rs @@ -9,7 +9,7 @@ pub fn target() -> Target { Target { llvm_target: "mips-unknown-linux-musl".to_string(), target_endian: "big".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "E-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64".to_string(), arch: "mips".to_string(), diff --git a/compiler/rustc_target/src/spec/mips_unknown_linux_uclibc.rs b/compiler/rustc_target/src/spec/mips_unknown_linux_uclibc.rs index bdb9be4a027..7e168836dc7 100644 --- a/compiler/rustc_target/src/spec/mips_unknown_linux_uclibc.rs +++ b/compiler/rustc_target/src/spec/mips_unknown_linux_uclibc.rs @@ -4,7 +4,7 @@ pub fn target() -> Target { Target { llvm_target: "mips-unknown-linux-uclibc".to_string(), target_endian: "big".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "E-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64".to_string(), arch: "mips".to_string(), diff --git a/compiler/rustc_target/src/spec/mipsel_sony_psp.rs b/compiler/rustc_target/src/spec/mipsel_sony_psp.rs index 5d8ad510d60..9897b0093fc 100644 --- a/compiler/rustc_target/src/spec/mipsel_sony_psp.rs +++ b/compiler/rustc_target/src/spec/mipsel_sony_psp.rs @@ -11,7 +11,7 @@ pub fn target() -> Target { Target { llvm_target: "mipsel-sony-psp".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "e-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64".to_string(), arch: "mips".to_string(), diff --git a/compiler/rustc_target/src/spec/mipsel_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/mipsel_unknown_linux_gnu.rs index ef585a4bc37..509f3e04ba7 100644 --- a/compiler/rustc_target/src/spec/mipsel_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/mipsel_unknown_linux_gnu.rs @@ -4,7 +4,7 @@ pub fn target() -> Target { Target { llvm_target: "mipsel-unknown-linux-gnu".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "e-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64".to_string(), arch: "mips".to_string(), diff --git a/compiler/rustc_target/src/spec/mipsel_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/mipsel_unknown_linux_musl.rs index 3552abd0968..0d3691dd5b9 100644 --- a/compiler/rustc_target/src/spec/mipsel_unknown_linux_musl.rs +++ b/compiler/rustc_target/src/spec/mipsel_unknown_linux_musl.rs @@ -9,7 +9,7 @@ pub fn target() -> Target { Target { llvm_target: "mipsel-unknown-linux-musl".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "e-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64".to_string(), arch: "mips".to_string(), diff --git a/compiler/rustc_target/src/spec/mipsel_unknown_linux_uclibc.rs b/compiler/rustc_target/src/spec/mipsel_unknown_linux_uclibc.rs index b52ae5cc016..6d50d9ba81e 100644 --- a/compiler/rustc_target/src/spec/mipsel_unknown_linux_uclibc.rs +++ b/compiler/rustc_target/src/spec/mipsel_unknown_linux_uclibc.rs @@ -4,7 +4,7 @@ pub fn target() -> Target { Target { llvm_target: "mipsel-unknown-linux-uclibc".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "e-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64".to_string(), arch: "mips".to_string(), diff --git a/compiler/rustc_target/src/spec/mipsisa32r6_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/mipsisa32r6_unknown_linux_gnu.rs index 10ec589ef20..d6e71d2922f 100644 --- a/compiler/rustc_target/src/spec/mipsisa32r6_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/mipsisa32r6_unknown_linux_gnu.rs @@ -4,7 +4,7 @@ pub fn target() -> Target { Target { llvm_target: "mipsisa32r6-unknown-linux-gnu".to_string(), target_endian: "big".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "E-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64".to_string(), arch: "mips".to_string(), diff --git a/compiler/rustc_target/src/spec/mipsisa32r6el_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/mipsisa32r6el_unknown_linux_gnu.rs index 8157cac4170..67e97fd2f0f 100644 --- a/compiler/rustc_target/src/spec/mipsisa32r6el_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/mipsisa32r6el_unknown_linux_gnu.rs @@ -4,7 +4,7 @@ pub fn target() -> Target { Target { llvm_target: "mipsisa32r6el-unknown-linux-gnu".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "e-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64".to_string(), arch: "mips".to_string(), diff --git a/compiler/rustc_target/src/spec/mipsisa64r6_unknown_linux_gnuabi64.rs b/compiler/rustc_target/src/spec/mipsisa64r6_unknown_linux_gnuabi64.rs index e5d565f653c..c3a7ae8b11f 100644 --- a/compiler/rustc_target/src/spec/mipsisa64r6_unknown_linux_gnuabi64.rs +++ b/compiler/rustc_target/src/spec/mipsisa64r6_unknown_linux_gnuabi64.rs @@ -4,7 +4,7 @@ pub fn target() -> Target { Target { llvm_target: "mipsisa64r6-unknown-linux-gnuabi64".to_string(), target_endian: "big".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), data_layout: "E-m:e-i8:8:32-i16:16:32-i64:64-n32:64-S128".to_string(), arch: "mips64".to_string(), diff --git a/compiler/rustc_target/src/spec/mipsisa64r6el_unknown_linux_gnuabi64.rs b/compiler/rustc_target/src/spec/mipsisa64r6el_unknown_linux_gnuabi64.rs index 5f68c6484c0..467e05a00d4 100644 --- a/compiler/rustc_target/src/spec/mipsisa64r6el_unknown_linux_gnuabi64.rs +++ b/compiler/rustc_target/src/spec/mipsisa64r6el_unknown_linux_gnuabi64.rs @@ -4,7 +4,7 @@ pub fn target() -> Target { Target { llvm_target: "mipsisa64r6el-unknown-linux-gnuabi64".to_string(), target_endian: "little".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-n32:64-S128".to_string(), arch: "mips64".to_string(), diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 0cb072f387f..1d3e61c4992 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -665,8 +665,8 @@ pub struct Target { pub llvm_target: String, /// String to use as the `target_endian` `cfg` variable. pub target_endian: String, - /// String to use as the `target_pointer_width` `cfg` variable. - pub target_pointer_width: String, + /// Number of bits in a pointer. Influences the `target_pointer_width` `cfg` variable. + pub pointer_width: u32, /// Width of c_int type pub target_c_int_width: String, /// OS name to use for conditional compilation. @@ -816,6 +816,9 @@ pub struct TargetOptions { pub is_like_emscripten: bool, /// Whether the target toolchain is like Fuchsia's. pub is_like_fuchsia: bool, + /// Version of DWARF to use if not using the default. + /// Useful because some platforms (osx, bsd) only want up to DWARF2. + pub dwarf_version: Option<u32>, /// Whether the linker support GNU-like arguments such as -O. Defaults to false. pub linker_is_gnu: bool, /// The MinGW toolchain has a known issue that prevents it from correctly @@ -1012,6 +1015,7 @@ impl Default for TargetOptions { is_like_emscripten: false, is_like_msvc: false, is_like_fuchsia: false, + dwarf_version: None, linker_is_gnu: false, allows_weak_linkage: true, has_rpath: false, @@ -1107,7 +1111,7 @@ impl Target { /// Maximum integer size in bits that this target can perform atomic /// operations on. pub fn max_atomic_width(&self) -> u64 { - self.options.max_atomic_width.unwrap_or_else(|| self.target_pointer_width.parse().unwrap()) + self.options.max_atomic_width.unwrap_or_else(|| self.pointer_width.into()) } pub fn is_abi_supported(&self, abi: Abi) -> bool { @@ -1140,7 +1144,9 @@ impl Target { let mut base = Target { llvm_target: get_req_field("llvm-target")?, target_endian: get_req_field("target-endian")?, - target_pointer_width: get_req_field("target-pointer-width")?, + pointer_width: get_req_field("target-pointer-width")? + .parse::<u32>() + .map_err(|_| "target-pointer-width must be an integer".to_string())?, target_c_int_width: get_req_field("target-c-int-width")?, data_layout: get_req_field("data-layout")?, arch: get_req_field("arch")?, @@ -1165,6 +1171,15 @@ impl Target { base.options.$key_name = s; } } ); + ($key_name:ident, Option<u32>) => ( { + let name = (stringify!($key_name)).replace("_", "-"); + if let Some(s) = obj.find(&name).and_then(Json::as_u64) { + if s < 1 || s > 5 { + return Err("Not a valid DWARF version number".to_string()); + } + base.options.$key_name = Some(s as u32); + } + } ); ($key_name:ident, Option<u64>) => ( { let name = (stringify!($key_name)).replace("_", "-"); if let Some(s) = obj.find(&name).and_then(Json::as_u64) { @@ -1417,6 +1432,7 @@ impl Target { key!(is_like_emscripten, bool); key!(is_like_android, bool); key!(is_like_fuchsia, bool); + key!(dwarf_version, Option<u32>); key!(linker_is_gnu, bool); key!(allows_weak_linkage, bool); key!(has_rpath, bool); @@ -1603,7 +1619,7 @@ impl ToJson for Target { target_val!(llvm_target); target_val!(target_endian); - target_val!(target_pointer_width); + d.insert("target-pointer-width".to_string(), self.pointer_width.to_string().to_json()); target_val!(target_c_int_width); target_val!(arch); target_val!(target_os, "os"); @@ -1654,6 +1670,7 @@ impl ToJson for Target { target_option_val!(is_like_emscripten); target_option_val!(is_like_android); target_option_val!(is_like_fuchsia); + target_option_val!(dwarf_version); target_option_val!(linker_is_gnu); target_option_val!(allows_weak_linkage); target_option_val!(has_rpath); diff --git a/compiler/rustc_target/src/spec/msp430_none_elf.rs b/compiler/rustc_target/src/spec/msp430_none_elf.rs index 9274d750c7c..5bb8109ce26 100644 --- a/compiler/rustc_target/src/spec/msp430_none_elf.rs +++ b/compiler/rustc_target/src/spec/msp430_none_elf.rs @@ -4,7 +4,7 @@ pub fn target() -> Target { Target { llvm_target: "msp430-none-elf".to_string(), target_endian: "little".to_string(), - target_pointer_width: "16".to_string(), + pointer_width: 16, target_c_int_width: "16".to_string(), data_layout: "e-m:e-p:16:16-i32:16-i64:16-f32:16-f64:16-a:8-n8:16-S16".to_string(), arch: "msp430".to_string(), diff --git a/compiler/rustc_target/src/spec/netbsd_base.rs b/compiler/rustc_target/src/spec/netbsd_base.rs index 988346af2d7..d7baf81fce3 100644 --- a/compiler/rustc_target/src/spec/netbsd_base.rs +++ b/compiler/rustc_target/src/spec/netbsd_base.rs @@ -24,6 +24,7 @@ pub fn opts() -> TargetOptions { position_independent_executables: true, relro_level: RelroLevel::Full, use_ctors_section: true, + dwarf_version: Some(2), ..Default::default() } } diff --git a/compiler/rustc_target/src/spec/nvptx64_nvidia_cuda.rs b/compiler/rustc_target/src/spec/nvptx64_nvidia_cuda.rs index e44534a288d..86360c181d1 100644 --- a/compiler/rustc_target/src/spec/nvptx64_nvidia_cuda.rs +++ b/compiler/rustc_target/src/spec/nvptx64_nvidia_cuda.rs @@ -14,7 +14,7 @@ pub fn target() -> Target { linker_flavor: LinkerFlavor::PtxLinker, target_endian: "little".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), options: TargetOptions { diff --git a/compiler/rustc_target/src/spec/openbsd_base.rs b/compiler/rustc_target/src/spec/openbsd_base.rs index cadd14df693..92a382e826b 100644 --- a/compiler/rustc_target/src/spec/openbsd_base.rs +++ b/compiler/rustc_target/src/spec/openbsd_base.rs @@ -26,6 +26,7 @@ pub fn opts() -> TargetOptions { position_independent_executables: true, eliminate_frame_pointer: false, // FIXME 43575 relro_level: RelroLevel::Full, + dwarf_version: Some(2), ..Default::default() } } diff --git a/compiler/rustc_target/src/spec/powerpc64_unknown_freebsd.rs b/compiler/rustc_target/src/spec/powerpc64_unknown_freebsd.rs index ab889387e2b..563ff96a403 100644 --- a/compiler/rustc_target/src/spec/powerpc64_unknown_freebsd.rs +++ b/compiler/rustc_target/src/spec/powerpc64_unknown_freebsd.rs @@ -9,7 +9,7 @@ pub fn target() -> Target { Target { llvm_target: "powerpc64-unknown-freebsd".to_string(), target_endian: "big".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), data_layout: "E-m:e-i64:64-n32:64".to_string(), arch: "powerpc64".to_string(), diff --git a/compiler/rustc_target/src/spec/powerpc64_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/powerpc64_unknown_linux_gnu.rs index 84a19e8a047..7d37670e5b0 100644 --- a/compiler/rustc_target/src/spec/powerpc64_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/powerpc64_unknown_linux_gnu.rs @@ -13,7 +13,7 @@ pub fn target() -> Target { Target { llvm_target: "powerpc64-unknown-linux-gnu".to_string(), target_endian: "big".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), data_layout: "E-m:e-i64:64-n32:64".to_string(), arch: "powerpc64".to_string(), diff --git a/compiler/rustc_target/src/spec/powerpc64_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/powerpc64_unknown_linux_musl.rs index c320d10e6c1..e108d75f337 100644 --- a/compiler/rustc_target/src/spec/powerpc64_unknown_linux_musl.rs +++ b/compiler/rustc_target/src/spec/powerpc64_unknown_linux_musl.rs @@ -9,7 +9,7 @@ pub fn target() -> Target { Target { llvm_target: "powerpc64-unknown-linux-musl".to_string(), target_endian: "big".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), data_layout: "E-m:e-i64:64-n32:64".to_string(), arch: "powerpc64".to_string(), diff --git a/compiler/rustc_target/src/spec/powerpc64_wrs_vxworks.rs b/compiler/rustc_target/src/spec/powerpc64_wrs_vxworks.rs index 257a0932080..9784c637c7e 100644 --- a/compiler/rustc_target/src/spec/powerpc64_wrs_vxworks.rs +++ b/compiler/rustc_target/src/spec/powerpc64_wrs_vxworks.rs @@ -9,7 +9,7 @@ pub fn target() -> Target { Target { llvm_target: "powerpc64-unknown-linux-gnu".to_string(), target_endian: "big".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), data_layout: "E-m:e-i64:64-n32:64".to_string(), arch: "powerpc64".to_string(), diff --git a/compiler/rustc_target/src/spec/powerpc64le_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/powerpc64le_unknown_linux_gnu.rs index 5d501f840b6..46d847f6e5f 100644 --- a/compiler/rustc_target/src/spec/powerpc64le_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/powerpc64le_unknown_linux_gnu.rs @@ -9,7 +9,7 @@ pub fn target() -> Target { Target { llvm_target: "powerpc64le-unknown-linux-gnu".to_string(), target_endian: "little".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), data_layout: "e-m:e-i64:64-n32:64".to_string(), arch: "powerpc64".to_string(), diff --git a/compiler/rustc_target/src/spec/powerpc64le_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/powerpc64le_unknown_linux_musl.rs index 847e8abf299..e04ee013701 100644 --- a/compiler/rustc_target/src/spec/powerpc64le_unknown_linux_musl.rs +++ b/compiler/rustc_target/src/spec/powerpc64le_unknown_linux_musl.rs @@ -9,7 +9,7 @@ pub fn target() -> Target { Target { llvm_target: "powerpc64le-unknown-linux-musl".to_string(), target_endian: "little".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), data_layout: "e-m:e-i64:64-n32:64".to_string(), arch: "powerpc64".to_string(), diff --git a/compiler/rustc_target/src/spec/powerpc_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/powerpc_unknown_linux_gnu.rs index 5f55a233fc4..80fc63e78e4 100644 --- a/compiler/rustc_target/src/spec/powerpc_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/powerpc_unknown_linux_gnu.rs @@ -8,7 +8,7 @@ pub fn target() -> Target { Target { llvm_target: "powerpc-unknown-linux-gnu".to_string(), target_endian: "big".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "E-m:e-p:32:32-i64:64-n32".to_string(), arch: "powerpc".to_string(), diff --git a/compiler/rustc_target/src/spec/powerpc_unknown_linux_gnuspe.rs b/compiler/rustc_target/src/spec/powerpc_unknown_linux_gnuspe.rs index b3c3a2fe242..612d2967ee0 100644 --- a/compiler/rustc_target/src/spec/powerpc_unknown_linux_gnuspe.rs +++ b/compiler/rustc_target/src/spec/powerpc_unknown_linux_gnuspe.rs @@ -8,7 +8,7 @@ pub fn target() -> Target { Target { llvm_target: "powerpc-unknown-linux-gnuspe".to_string(), target_endian: "big".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "E-m:e-p:32:32-i64:64-n32".to_string(), arch: "powerpc".to_string(), diff --git a/compiler/rustc_target/src/spec/powerpc_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/powerpc_unknown_linux_musl.rs index 804f223ba6e..fd89262e464 100644 --- a/compiler/rustc_target/src/spec/powerpc_unknown_linux_musl.rs +++ b/compiler/rustc_target/src/spec/powerpc_unknown_linux_musl.rs @@ -8,7 +8,7 @@ pub fn target() -> Target { Target { llvm_target: "powerpc-unknown-linux-musl".to_string(), target_endian: "big".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "E-m:e-p:32:32-i64:64-n32".to_string(), arch: "powerpc".to_string(), diff --git a/compiler/rustc_target/src/spec/powerpc_unknown_netbsd.rs b/compiler/rustc_target/src/spec/powerpc_unknown_netbsd.rs index 5be35dbdc89..d33258d1859 100644 --- a/compiler/rustc_target/src/spec/powerpc_unknown_netbsd.rs +++ b/compiler/rustc_target/src/spec/powerpc_unknown_netbsd.rs @@ -8,7 +8,7 @@ pub fn target() -> Target { Target { llvm_target: "powerpc-unknown-netbsd".to_string(), target_endian: "big".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "E-m:e-p:32:32-i64:64-n32".to_string(), arch: "powerpc".to_string(), diff --git a/compiler/rustc_target/src/spec/powerpc_wrs_vxworks.rs b/compiler/rustc_target/src/spec/powerpc_wrs_vxworks.rs index 44338c066e6..6a12f4c59f6 100644 --- a/compiler/rustc_target/src/spec/powerpc_wrs_vxworks.rs +++ b/compiler/rustc_target/src/spec/powerpc_wrs_vxworks.rs @@ -9,7 +9,7 @@ pub fn target() -> Target { Target { llvm_target: "powerpc-unknown-linux-gnu".to_string(), target_endian: "big".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "E-m:e-p:32:32-i64:64-n32".to_string(), arch: "powerpc".to_string(), diff --git a/compiler/rustc_target/src/spec/powerpc_wrs_vxworks_spe.rs b/compiler/rustc_target/src/spec/powerpc_wrs_vxworks_spe.rs index e2dc7858d2c..5fee61fa0bd 100644 --- a/compiler/rustc_target/src/spec/powerpc_wrs_vxworks_spe.rs +++ b/compiler/rustc_target/src/spec/powerpc_wrs_vxworks_spe.rs @@ -9,7 +9,7 @@ pub fn target() -> Target { Target { llvm_target: "powerpc-unknown-linux-gnuspe".to_string(), target_endian: "big".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "E-m:e-p:32:32-i64:64-n32".to_string(), arch: "powerpc".to_string(), diff --git a/compiler/rustc_target/src/spec/riscv32gc_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/riscv32gc_unknown_linux_gnu.rs index bce690662b8..415d7c5607d 100644 --- a/compiler/rustc_target/src/spec/riscv32gc_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/riscv32gc_unknown_linux_gnu.rs @@ -4,7 +4,7 @@ pub fn target() -> Target { Target { llvm_target: "riscv32-unknown-linux-gnu".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), target_env: "gnu".to_string(), data_layout: "e-m:e-p:32:32-i64:64-n32-S128".to_string(), diff --git a/compiler/rustc_target/src/spec/riscv32i_unknown_none_elf.rs b/compiler/rustc_target/src/spec/riscv32i_unknown_none_elf.rs index 83e27c4d838..022768f6ab8 100644 --- a/compiler/rustc_target/src/spec/riscv32i_unknown_none_elf.rs +++ b/compiler/rustc_target/src/spec/riscv32i_unknown_none_elf.rs @@ -6,7 +6,7 @@ pub fn target() -> Target { data_layout: "e-m:e-p:32:32-i64:64-n32-S128".to_string(), llvm_target: "riscv32".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), target_os: "none".to_string(), target_env: String::new(), diff --git a/compiler/rustc_target/src/spec/riscv32imac_unknown_none_elf.rs b/compiler/rustc_target/src/spec/riscv32imac_unknown_none_elf.rs index e2154f58494..13f0d42d6fd 100644 --- a/compiler/rustc_target/src/spec/riscv32imac_unknown_none_elf.rs +++ b/compiler/rustc_target/src/spec/riscv32imac_unknown_none_elf.rs @@ -6,7 +6,7 @@ pub fn target() -> Target { data_layout: "e-m:e-p:32:32-i64:64-n32-S128".to_string(), llvm_target: "riscv32".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), target_os: "none".to_string(), target_env: String::new(), diff --git a/compiler/rustc_target/src/spec/riscv32imc_unknown_none_elf.rs b/compiler/rustc_target/src/spec/riscv32imc_unknown_none_elf.rs index 845a80a06c7..86189c27bbd 100644 --- a/compiler/rustc_target/src/spec/riscv32imc_unknown_none_elf.rs +++ b/compiler/rustc_target/src/spec/riscv32imc_unknown_none_elf.rs @@ -6,7 +6,7 @@ pub fn target() -> Target { data_layout: "e-m:e-p:32:32-i64:64-n32-S128".to_string(), llvm_target: "riscv32".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), target_os: "none".to_string(), target_env: String::new(), diff --git a/compiler/rustc_target/src/spec/riscv64gc_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/riscv64gc_unknown_linux_gnu.rs index 2cd3b952618..808d7159f82 100644 --- a/compiler/rustc_target/src/spec/riscv64gc_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/riscv64gc_unknown_linux_gnu.rs @@ -4,7 +4,7 @@ pub fn target() -> Target { Target { llvm_target: "riscv64-unknown-linux-gnu".to_string(), target_endian: "little".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), target_env: "gnu".to_string(), data_layout: "e-m:e-p:64:64-i64:64-i128:128-n64-S128".to_string(), diff --git a/compiler/rustc_target/src/spec/riscv64gc_unknown_none_elf.rs b/compiler/rustc_target/src/spec/riscv64gc_unknown_none_elf.rs index 1f857159f0c..0211bc02d2d 100644 --- a/compiler/rustc_target/src/spec/riscv64gc_unknown_none_elf.rs +++ b/compiler/rustc_target/src/spec/riscv64gc_unknown_none_elf.rs @@ -6,7 +6,7 @@ pub fn target() -> Target { data_layout: "e-m:e-p:64:64-i64:64-i128:128-n64-S128".to_string(), llvm_target: "riscv64".to_string(), target_endian: "little".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), target_os: "none".to_string(), target_env: String::new(), diff --git a/compiler/rustc_target/src/spec/riscv64imac_unknown_none_elf.rs b/compiler/rustc_target/src/spec/riscv64imac_unknown_none_elf.rs index c407fd9557d..1050ce5ba74 100644 --- a/compiler/rustc_target/src/spec/riscv64imac_unknown_none_elf.rs +++ b/compiler/rustc_target/src/spec/riscv64imac_unknown_none_elf.rs @@ -6,7 +6,7 @@ pub fn target() -> Target { data_layout: "e-m:e-p:64:64-i64:64-i128:128-n64-S128".to_string(), llvm_target: "riscv64".to_string(), target_endian: "little".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), target_os: "none".to_string(), target_env: String::new(), diff --git a/compiler/rustc_target/src/spec/s390x_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/s390x_unknown_linux_gnu.rs index ed1c96f1d7b..653b83646ce 100644 --- a/compiler/rustc_target/src/spec/s390x_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/s390x_unknown_linux_gnu.rs @@ -14,7 +14,7 @@ pub fn target() -> Target { Target { llvm_target: "s390x-unknown-linux-gnu".to_string(), target_endian: "big".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), data_layout: "E-m:e-i1:8:16-i8:8:16-i64:64-f128:64-a:8:16-n32:64".to_string(), arch: "s390x".to_string(), diff --git a/compiler/rustc_target/src/spec/sparc64_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/sparc64_unknown_linux_gnu.rs index 8b540a717ce..e50c114fcfa 100644 --- a/compiler/rustc_target/src/spec/sparc64_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/sparc64_unknown_linux_gnu.rs @@ -8,7 +8,7 @@ pub fn target() -> Target { Target { llvm_target: "sparc64-unknown-linux-gnu".to_string(), target_endian: "big".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), data_layout: "E-m:e-i64:64-n32:64-S128".to_string(), arch: "sparc64".to_string(), diff --git a/compiler/rustc_target/src/spec/sparc64_unknown_netbsd.rs b/compiler/rustc_target/src/spec/sparc64_unknown_netbsd.rs index cfdc43547ff..6d8e433949b 100644 --- a/compiler/rustc_target/src/spec/sparc64_unknown_netbsd.rs +++ b/compiler/rustc_target/src/spec/sparc64_unknown_netbsd.rs @@ -9,7 +9,7 @@ pub fn target() -> Target { Target { llvm_target: "sparc64-unknown-netbsd".to_string(), target_endian: "big".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), data_layout: "E-m:e-i64:64-n32:64-S128".to_string(), arch: "sparc64".to_string(), diff --git a/compiler/rustc_target/src/spec/sparc64_unknown_openbsd.rs b/compiler/rustc_target/src/spec/sparc64_unknown_openbsd.rs index 6f2eaeee32a..45700e14c53 100644 --- a/compiler/rustc_target/src/spec/sparc64_unknown_openbsd.rs +++ b/compiler/rustc_target/src/spec/sparc64_unknown_openbsd.rs @@ -9,7 +9,7 @@ pub fn target() -> Target { Target { llvm_target: "sparc64-unknown-openbsd".to_string(), target_endian: "big".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), data_layout: "E-m:e-i64:64-n32:64-S128".to_string(), arch: "sparc64".to_string(), diff --git a/compiler/rustc_target/src/spec/sparc_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/sparc_unknown_linux_gnu.rs index ea02db7e5bb..fc400dd3446 100644 --- a/compiler/rustc_target/src/spec/sparc_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/sparc_unknown_linux_gnu.rs @@ -9,7 +9,7 @@ pub fn target() -> Target { Target { llvm_target: "sparc-unknown-linux-gnu".to_string(), target_endian: "big".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "E-m:e-p:32:32-i64:64-f128:64-n32-S64".to_string(), arch: "sparc".to_string(), diff --git a/compiler/rustc_target/src/spec/sparcv9_sun_solaris.rs b/compiler/rustc_target/src/spec/sparcv9_sun_solaris.rs index 747f70e65c5..0878e7fd21e 100644 --- a/compiler/rustc_target/src/spec/sparcv9_sun_solaris.rs +++ b/compiler/rustc_target/src/spec/sparcv9_sun_solaris.rs @@ -10,7 +10,7 @@ pub fn target() -> Target { Target { llvm_target: "sparcv9-sun-solaris".to_string(), target_endian: "big".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), data_layout: "E-m:e-i64:64-n32:64-S128".to_string(), // Use "sparc64" instead of "sparcv9" here, since the former is already diff --git a/compiler/rustc_target/src/spec/thumbv4t_none_eabi.rs b/compiler/rustc_target/src/spec/thumbv4t_none_eabi.rs index d1fd0fea604..d5ce62d8c1c 100644 --- a/compiler/rustc_target/src/spec/thumbv4t_none_eabi.rs +++ b/compiler/rustc_target/src/spec/thumbv4t_none_eabi.rs @@ -14,7 +14,7 @@ pub fn target() -> Target { Target { llvm_target: "thumbv4t-none-eabi".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), target_os: "none".to_string(), target_env: "".to_string(), diff --git a/compiler/rustc_target/src/spec/thumbv6m_none_eabi.rs b/compiler/rustc_target/src/spec/thumbv6m_none_eabi.rs index bd1367ddb42..407fa6116c5 100644 --- a/compiler/rustc_target/src/spec/thumbv6m_none_eabi.rs +++ b/compiler/rustc_target/src/spec/thumbv6m_none_eabi.rs @@ -6,7 +6,7 @@ pub fn target() -> Target { Target { llvm_target: "thumbv6m-none-eabi".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(), arch: "arm".to_string(), diff --git a/compiler/rustc_target/src/spec/thumbv7a_pc_windows_msvc.rs b/compiler/rustc_target/src/spec/thumbv7a_pc_windows_msvc.rs index 01a3598572d..d34f42cdc61 100644 --- a/compiler/rustc_target/src/spec/thumbv7a_pc_windows_msvc.rs +++ b/compiler/rustc_target/src/spec/thumbv7a_pc_windows_msvc.rs @@ -24,7 +24,7 @@ pub fn target() -> Target { Target { llvm_target: "thumbv7a-pc-windows-msvc".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "e-m:w-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(), arch: "arm".to_string(), diff --git a/compiler/rustc_target/src/spec/thumbv7a_uwp_windows_msvc.rs b/compiler/rustc_target/src/spec/thumbv7a_uwp_windows_msvc.rs index af4741c77ab..143a9a48a4a 100644 --- a/compiler/rustc_target/src/spec/thumbv7a_uwp_windows_msvc.rs +++ b/compiler/rustc_target/src/spec/thumbv7a_uwp_windows_msvc.rs @@ -12,7 +12,7 @@ pub fn target() -> Target { Target { llvm_target: "thumbv7a-pc-windows-msvc".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "e-m:w-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(), arch: "arm".to_string(), diff --git a/compiler/rustc_target/src/spec/thumbv7em_none_eabi.rs b/compiler/rustc_target/src/spec/thumbv7em_none_eabi.rs index 10e1050fbf5..e0b00460e08 100644 --- a/compiler/rustc_target/src/spec/thumbv7em_none_eabi.rs +++ b/compiler/rustc_target/src/spec/thumbv7em_none_eabi.rs @@ -15,7 +15,7 @@ pub fn target() -> Target { Target { llvm_target: "thumbv7em-none-eabi".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(), arch: "arm".to_string(), diff --git a/compiler/rustc_target/src/spec/thumbv7em_none_eabihf.rs b/compiler/rustc_target/src/spec/thumbv7em_none_eabihf.rs index 17a5b70bc09..eecd75e4614 100644 --- a/compiler/rustc_target/src/spec/thumbv7em_none_eabihf.rs +++ b/compiler/rustc_target/src/spec/thumbv7em_none_eabihf.rs @@ -14,7 +14,7 @@ pub fn target() -> Target { Target { llvm_target: "thumbv7em-none-eabihf".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(), arch: "arm".to_string(), diff --git a/compiler/rustc_target/src/spec/thumbv7m_none_eabi.rs b/compiler/rustc_target/src/spec/thumbv7m_none_eabi.rs index c21cb5d03d4..a02100ee199 100644 --- a/compiler/rustc_target/src/spec/thumbv7m_none_eabi.rs +++ b/compiler/rustc_target/src/spec/thumbv7m_none_eabi.rs @@ -6,7 +6,7 @@ pub fn target() -> Target { Target { llvm_target: "thumbv7m-none-eabi".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(), arch: "arm".to_string(), diff --git a/compiler/rustc_target/src/spec/thumbv7neon_linux_androideabi.rs b/compiler/rustc_target/src/spec/thumbv7neon_linux_androideabi.rs index 8c4750d7731..35e7d480f3f 100644 --- a/compiler/rustc_target/src/spec/thumbv7neon_linux_androideabi.rs +++ b/compiler/rustc_target/src/spec/thumbv7neon_linux_androideabi.rs @@ -17,7 +17,7 @@ pub fn target() -> Target { Target { llvm_target: "armv7-none-linux-android".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(), arch: "arm".to_string(), diff --git a/compiler/rustc_target/src/spec/thumbv7neon_unknown_linux_gnueabihf.rs b/compiler/rustc_target/src/spec/thumbv7neon_unknown_linux_gnueabihf.rs index 85bdc16727b..946b0db4c22 100644 --- a/compiler/rustc_target/src/spec/thumbv7neon_unknown_linux_gnueabihf.rs +++ b/compiler/rustc_target/src/spec/thumbv7neon_unknown_linux_gnueabihf.rs @@ -11,7 +11,7 @@ pub fn target() -> Target { Target { llvm_target: "armv7-unknown-linux-gnueabihf".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(), arch: "arm".to_string(), diff --git a/compiler/rustc_target/src/spec/thumbv7neon_unknown_linux_musleabihf.rs b/compiler/rustc_target/src/spec/thumbv7neon_unknown_linux_musleabihf.rs index b97b5270d42..91945f9dcdc 100644 --- a/compiler/rustc_target/src/spec/thumbv7neon_unknown_linux_musleabihf.rs +++ b/compiler/rustc_target/src/spec/thumbv7neon_unknown_linux_musleabihf.rs @@ -14,7 +14,7 @@ pub fn target() -> Target { // doesn't support the "musleabihf" value. llvm_target: "armv7-unknown-linux-gnueabihf".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(), arch: "arm".to_string(), diff --git a/compiler/rustc_target/src/spec/thumbv8m_base_none_eabi.rs b/compiler/rustc_target/src/spec/thumbv8m_base_none_eabi.rs index 9eb33f5ef66..383346400b5 100644 --- a/compiler/rustc_target/src/spec/thumbv8m_base_none_eabi.rs +++ b/compiler/rustc_target/src/spec/thumbv8m_base_none_eabi.rs @@ -6,7 +6,7 @@ pub fn target() -> Target { Target { llvm_target: "thumbv8m.base-none-eabi".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(), arch: "arm".to_string(), diff --git a/compiler/rustc_target/src/spec/thumbv8m_main_none_eabi.rs b/compiler/rustc_target/src/spec/thumbv8m_main_none_eabi.rs index 55b8b545e79..3d0fb664cf6 100644 --- a/compiler/rustc_target/src/spec/thumbv8m_main_none_eabi.rs +++ b/compiler/rustc_target/src/spec/thumbv8m_main_none_eabi.rs @@ -7,7 +7,7 @@ pub fn target() -> Target { Target { llvm_target: "thumbv8m.main-none-eabi".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(), arch: "arm".to_string(), diff --git a/compiler/rustc_target/src/spec/thumbv8m_main_none_eabihf.rs b/compiler/rustc_target/src/spec/thumbv8m_main_none_eabihf.rs index f17d48e8523..82368cb59b2 100644 --- a/compiler/rustc_target/src/spec/thumbv8m_main_none_eabihf.rs +++ b/compiler/rustc_target/src/spec/thumbv8m_main_none_eabihf.rs @@ -7,7 +7,7 @@ pub fn target() -> Target { Target { llvm_target: "thumbv8m.main-none-eabihf".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(), arch: "arm".to_string(), diff --git a/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs b/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs index 4f99967f21b..aea06412aa2 100644 --- a/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs +++ b/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs @@ -31,7 +31,7 @@ pub fn target() -> Target { Target { llvm_target: "wasm32-unknown-emscripten".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), target_os: "emscripten".to_string(), target_env: String::new(), diff --git a/compiler/rustc_target/src/spec/wasm32_unknown_unknown.rs b/compiler/rustc_target/src/spec/wasm32_unknown_unknown.rs index f0b6979ce11..19609b0d496 100644 --- a/compiler/rustc_target/src/spec/wasm32_unknown_unknown.rs +++ b/compiler/rustc_target/src/spec/wasm32_unknown_unknown.rs @@ -33,7 +33,7 @@ pub fn target() -> Target { Target { llvm_target: "wasm32-unknown-unknown".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), target_os: "unknown".to_string(), target_env: String::new(), diff --git a/compiler/rustc_target/src/spec/wasm32_wasi.rs b/compiler/rustc_target/src/spec/wasm32_wasi.rs index f8fdbf44b19..26e0722fcf0 100644 --- a/compiler/rustc_target/src/spec/wasm32_wasi.rs +++ b/compiler/rustc_target/src/spec/wasm32_wasi.rs @@ -107,7 +107,7 @@ pub fn target() -> Target { Target { llvm_target: "wasm32-wasi".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), target_os: "wasi".to_string(), target_env: String::new(), diff --git a/compiler/rustc_target/src/spec/windows_gnu_base.rs b/compiler/rustc_target/src/spec/windows_gnu_base.rs index 0234ff55f01..98e42f6c37c 100644 --- a/compiler/rustc_target/src/spec/windows_gnu_base.rs +++ b/compiler/rustc_target/src/spec/windows_gnu_base.rs @@ -11,6 +11,10 @@ pub fn opts() -> TargetOptions { "-fno-use-linker-plugin".to_string(), // Always enable DEP (NX bit) when it is available "-Wl,--nxcompat".to_string(), + // Enable ASLR + "-Wl,--dynamicbase".to_string(), + // ASLR will rebase it anyway so leaving that option enabled only leads to confusion + "-Wl,--disable-auto-image-base".to_string(), ], ); diff --git a/compiler/rustc_target/src/spec/x86_64_apple_darwin.rs b/compiler/rustc_target/src/spec/x86_64_apple_darwin.rs index 45e8ddd6137..2b39fec594a 100644 --- a/compiler/rustc_target/src/spec/x86_64_apple_darwin.rs +++ b/compiler/rustc_target/src/spec/x86_64_apple_darwin.rs @@ -21,7 +21,7 @@ pub fn target() -> Target { Target { llvm_target, target_endian: "little".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), data_layout: "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" .to_string(), diff --git a/compiler/rustc_target/src/spec/x86_64_apple_ios.rs b/compiler/rustc_target/src/spec/x86_64_apple_ios.rs index b4590f7aed2..685e046b64b 100644 --- a/compiler/rustc_target/src/spec/x86_64_apple_ios.rs +++ b/compiler/rustc_target/src/spec/x86_64_apple_ios.rs @@ -6,7 +6,7 @@ pub fn target() -> Target { Target { llvm_target: "x86_64-apple-ios".to_string(), target_endian: "little".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), data_layout: "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" .to_string(), diff --git a/compiler/rustc_target/src/spec/x86_64_apple_ios_macabi.rs b/compiler/rustc_target/src/spec/x86_64_apple_ios_macabi.rs index 85cc4e6db6f..ff7331560ed 100644 --- a/compiler/rustc_target/src/spec/x86_64_apple_ios_macabi.rs +++ b/compiler/rustc_target/src/spec/x86_64_apple_ios_macabi.rs @@ -6,7 +6,7 @@ pub fn target() -> Target { Target { llvm_target: "x86_64-apple-ios13.0-macabi".to_string(), target_endian: "little".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), data_layout: "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" .to_string(), diff --git a/compiler/rustc_target/src/spec/x86_64_apple_tvos.rs b/compiler/rustc_target/src/spec/x86_64_apple_tvos.rs index db466400562..7c0a819f5dd 100644 --- a/compiler/rustc_target/src/spec/x86_64_apple_tvos.rs +++ b/compiler/rustc_target/src/spec/x86_64_apple_tvos.rs @@ -6,7 +6,7 @@ pub fn target() -> Target { Target { llvm_target: "x86_64-apple-tvos".to_string(), target_endian: "little".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), data_layout: "e-m:o-i64:64-f80:128-n8:16:32:64-S128".to_string(), arch: "x86_64".to_string(), diff --git a/compiler/rustc_target/src/spec/x86_64_fortanix_unknown_sgx.rs b/compiler/rustc_target/src/spec/x86_64_fortanix_unknown_sgx.rs index cc27d88bff1..8f1627d4a29 100644 --- a/compiler/rustc_target/src/spec/x86_64_fortanix_unknown_sgx.rs +++ b/compiler/rustc_target/src/spec/x86_64_fortanix_unknown_sgx.rs @@ -77,7 +77,7 @@ pub fn target() -> Target { Target { llvm_target: "x86_64-elf".into(), target_endian: "little".into(), - target_pointer_width: "64".into(), + pointer_width: 64, target_c_int_width: "32".into(), target_os: "unknown".into(), target_env: "sgx".into(), diff --git a/compiler/rustc_target/src/spec/x86_64_fuchsia.rs b/compiler/rustc_target/src/spec/x86_64_fuchsia.rs index 887b3b67edd..71add0a6c0a 100644 --- a/compiler/rustc_target/src/spec/x86_64_fuchsia.rs +++ b/compiler/rustc_target/src/spec/x86_64_fuchsia.rs @@ -9,7 +9,7 @@ pub fn target() -> Target { Target { llvm_target: "x86_64-fuchsia".to_string(), target_endian: "little".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" .to_string(), diff --git a/compiler/rustc_target/src/spec/x86_64_linux_android.rs b/compiler/rustc_target/src/spec/x86_64_linux_android.rs index 44c869d1e30..aa5e48cee07 100644 --- a/compiler/rustc_target/src/spec/x86_64_linux_android.rs +++ b/compiler/rustc_target/src/spec/x86_64_linux_android.rs @@ -12,7 +12,7 @@ pub fn target() -> Target { Target { llvm_target: "x86_64-linux-android".to_string(), target_endian: "little".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" .to_string(), diff --git a/compiler/rustc_target/src/spec/x86_64_linux_kernel.rs b/compiler/rustc_target/src/spec/x86_64_linux_kernel.rs index b9507ad9c8e..243167558be 100644 --- a/compiler/rustc_target/src/spec/x86_64_linux_kernel.rs +++ b/compiler/rustc_target/src/spec/x86_64_linux_kernel.rs @@ -17,7 +17,7 @@ pub fn target() -> Target { // FIXME: Some dispute, the linux-on-clang folks think this should use "Linux" llvm_target: "x86_64-elf".to_string(), target_endian: "little".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" .to_string(), diff --git a/compiler/rustc_target/src/spec/x86_64_pc_windows_gnu.rs b/compiler/rustc_target/src/spec/x86_64_pc_windows_gnu.rs index e93755d1aa4..3b2edc91bc2 100644 --- a/compiler/rustc_target/src/spec/x86_64_pc_windows_gnu.rs +++ b/compiler/rustc_target/src/spec/x86_64_pc_windows_gnu.rs @@ -3,7 +3,10 @@ use crate::spec::{LinkerFlavor, LldFlavor, Target}; pub fn target() -> Target { let mut base = super::windows_gnu_base::opts(); base.cpu = "x86-64".to_string(); - base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string()); + let gcc_pre_link_args = base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap(); + gcc_pre_link_args.push("-m64".to_string()); + // Use high-entropy 64 bit address space for ASLR + gcc_pre_link_args.push("-Wl,--high-entropy-va".to_string()); base.pre_link_args .insert(LinkerFlavor::Lld(LldFlavor::Ld), vec!["-m".to_string(), "i386pep".to_string()]); base.max_atomic_width = Some(64); @@ -12,7 +15,7 @@ pub fn target() -> Target { Target { llvm_target: "x86_64-pc-windows-gnu".to_string(), target_endian: "little".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), data_layout: "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" .to_string(), diff --git a/compiler/rustc_target/src/spec/x86_64_pc_windows_msvc.rs b/compiler/rustc_target/src/spec/x86_64_pc_windows_msvc.rs index ffb0eb43beb..f21b059551d 100644 --- a/compiler/rustc_target/src/spec/x86_64_pc_windows_msvc.rs +++ b/compiler/rustc_target/src/spec/x86_64_pc_windows_msvc.rs @@ -9,7 +9,7 @@ pub fn target() -> Target { Target { llvm_target: "x86_64-pc-windows-msvc".to_string(), target_endian: "little".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), data_layout: "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" .to_string(), diff --git a/compiler/rustc_target/src/spec/x86_64_rumprun_netbsd.rs b/compiler/rustc_target/src/spec/x86_64_rumprun_netbsd.rs index 3d97f4315ec..2e009d7abbf 100644 --- a/compiler/rustc_target/src/spec/x86_64_rumprun_netbsd.rs +++ b/compiler/rustc_target/src/spec/x86_64_rumprun_netbsd.rs @@ -16,7 +16,7 @@ pub fn target() -> Target { Target { llvm_target: "x86_64-rumprun-netbsd".to_string(), target_endian: "little".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" .to_string(), diff --git a/compiler/rustc_target/src/spec/x86_64_sun_solaris.rs b/compiler/rustc_target/src/spec/x86_64_sun_solaris.rs index 5c6be285360..aef06157cdd 100644 --- a/compiler/rustc_target/src/spec/x86_64_sun_solaris.rs +++ b/compiler/rustc_target/src/spec/x86_64_sun_solaris.rs @@ -10,7 +10,7 @@ pub fn target() -> Target { Target { llvm_target: "x86_64-pc-solaris".to_string(), target_endian: "little".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" .to_string(), diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_cloudabi.rs b/compiler/rustc_target/src/spec/x86_64_unknown_cloudabi.rs index c002671552f..bdaab883d90 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_cloudabi.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_cloudabi.rs @@ -11,7 +11,7 @@ pub fn target() -> Target { Target { llvm_target: "x86_64-unknown-cloudabi".to_string(), target_endian: "little".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" .to_string(), diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_dragonfly.rs b/compiler/rustc_target/src/spec/x86_64_unknown_dragonfly.rs index 1390926ed3f..13a62d5081c 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_dragonfly.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_dragonfly.rs @@ -10,7 +10,7 @@ pub fn target() -> Target { Target { llvm_target: "x86_64-unknown-dragonfly".to_string(), target_endian: "little".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" .to_string(), diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_freebsd.rs b/compiler/rustc_target/src/spec/x86_64_unknown_freebsd.rs index 424f0343ec9..145983022e8 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_freebsd.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_freebsd.rs @@ -10,7 +10,7 @@ pub fn target() -> Target { Target { llvm_target: "x86_64-unknown-freebsd".to_string(), target_endian: "little".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" .to_string(), diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_haiku.rs b/compiler/rustc_target/src/spec/x86_64_unknown_haiku.rs index 2f9be167b9b..d88812e4248 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_haiku.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_haiku.rs @@ -12,7 +12,7 @@ pub fn target() -> Target { Target { llvm_target: "x86_64-unknown-haiku".to_string(), target_endian: "little".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" .to_string(), diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_hermit.rs b/compiler/rustc_target/src/spec/x86_64_unknown_hermit.rs index 0da92f035a5..a5002091d07 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_hermit.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_hermit.rs @@ -10,7 +10,7 @@ pub fn target() -> Target { Target { llvm_target: "x86_64-unknown-hermit".to_string(), target_endian: "little".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" .to_string(), diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_hermit_kernel.rs b/compiler/rustc_target/src/spec/x86_64_unknown_hermit_kernel.rs index ea955e758bb..91d7b0eaefc 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_hermit_kernel.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_hermit_kernel.rs @@ -12,7 +12,7 @@ pub fn target() -> Target { Target { llvm_target: "x86_64-unknown-hermit".to_string(), target_endian: "little".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" .to_string(), diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_illumos.rs b/compiler/rustc_target/src/spec/x86_64_unknown_illumos.rs index 482748f5b3d..e49f009be0f 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_illumos.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_illumos.rs @@ -11,7 +11,7 @@ pub fn target() -> Target { // so we still pass Solaris to it llvm_target: "x86_64-pc-solaris".to_string(), target_endian: "little".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" .to_string(), diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_l4re_uclibc.rs b/compiler/rustc_target/src/spec/x86_64_unknown_l4re_uclibc.rs index 65e080d3066..fc5b1ba60ec 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_l4re_uclibc.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_l4re_uclibc.rs @@ -8,7 +8,7 @@ pub fn target() -> Target { Target { llvm_target: "x86_64-unknown-l4re-uclibc".to_string(), target_endian: "little".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" .to_string(), diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnu.rs index 66df76cad69..9d9f99c9b59 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnu.rs @@ -10,7 +10,7 @@ pub fn target() -> Target { Target { llvm_target: "x86_64-unknown-linux-gnu".to_string(), target_endian: "little".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" .to_string(), diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnux32.rs b/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnux32.rs index 81dae46b8a3..e4a0d913bab 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnux32.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnux32.rs @@ -14,7 +14,7 @@ pub fn target() -> Target { Target { llvm_target: "x86_64-unknown-linux-gnux32".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-\ i64:64-f80:128-n8:16:32:64-S128" diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/x86_64_unknown_linux_musl.rs index e513df790be..a7d3324b2c7 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_linux_musl.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_linux_musl.rs @@ -11,7 +11,7 @@ pub fn target() -> Target { Target { llvm_target: "x86_64-unknown-linux-musl".to_string(), target_endian: "little".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" .to_string(), diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_netbsd.rs b/compiler/rustc_target/src/spec/x86_64_unknown_netbsd.rs index 9c984f169a6..a8106c0c770 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_netbsd.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_netbsd.rs @@ -10,7 +10,7 @@ pub fn target() -> Target { Target { llvm_target: "x86_64-unknown-netbsd".to_string(), target_endian: "little".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" .to_string(), diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_openbsd.rs b/compiler/rustc_target/src/spec/x86_64_unknown_openbsd.rs index d9110c882c1..5afe73ea713 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_openbsd.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_openbsd.rs @@ -10,7 +10,7 @@ pub fn target() -> Target { Target { llvm_target: "x86_64-unknown-openbsd".to_string(), target_endian: "little".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" .to_string(), diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_redox.rs b/compiler/rustc_target/src/spec/x86_64_unknown_redox.rs index 42af9c799bd..e21148887d9 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_redox.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_redox.rs @@ -10,7 +10,7 @@ pub fn target() -> Target { Target { llvm_target: "x86_64-unknown-redox".to_string(), target_endian: "little".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" .to_string(), diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_uefi.rs b/compiler/rustc_target/src/spec/x86_64_unknown_uefi.rs index 17d75a96713..894bd334169 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_uefi.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_uefi.rs @@ -31,7 +31,7 @@ pub fn target() -> Target { Target { llvm_target: "x86_64-unknown-windows".to_string(), target_endian: "little".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), data_layout: "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" .to_string(), diff --git a/compiler/rustc_target/src/spec/x86_64_uwp_windows_gnu.rs b/compiler/rustc_target/src/spec/x86_64_uwp_windows_gnu.rs index b288271406c..a4fa0d03546 100644 --- a/compiler/rustc_target/src/spec/x86_64_uwp_windows_gnu.rs +++ b/compiler/rustc_target/src/spec/x86_64_uwp_windows_gnu.rs @@ -3,7 +3,10 @@ use crate::spec::{LinkerFlavor, LldFlavor, Target}; pub fn target() -> Target { let mut base = super::windows_uwp_gnu_base::opts(); base.cpu = "x86-64".to_string(); - base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string()); + let gcc_pre_link_args = base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap(); + gcc_pre_link_args.push("-m64".to_string()); + // Use high-entropy 64 bit address space for ASLR + gcc_pre_link_args.push("-Wl,--high-entropy-va".to_string()); base.pre_link_args .insert(LinkerFlavor::Lld(LldFlavor::Ld), vec!["-m".to_string(), "i386pep".to_string()]); base.max_atomic_width = Some(64); @@ -11,7 +14,7 @@ pub fn target() -> Target { Target { llvm_target: "x86_64-pc-windows-gnu".to_string(), target_endian: "little".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), data_layout: "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" .to_string(), diff --git a/compiler/rustc_target/src/spec/x86_64_uwp_windows_msvc.rs b/compiler/rustc_target/src/spec/x86_64_uwp_windows_msvc.rs index 41beab91536..aaf85bbce81 100644 --- a/compiler/rustc_target/src/spec/x86_64_uwp_windows_msvc.rs +++ b/compiler/rustc_target/src/spec/x86_64_uwp_windows_msvc.rs @@ -9,7 +9,7 @@ pub fn target() -> Target { Target { llvm_target: "x86_64-pc-windows-msvc".to_string(), target_endian: "little".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), data_layout: "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" .to_string(), diff --git a/compiler/rustc_target/src/spec/x86_64_wrs_vxworks.rs b/compiler/rustc_target/src/spec/x86_64_wrs_vxworks.rs index 96927660a3c..5edf7e7af51 100644 --- a/compiler/rustc_target/src/spec/x86_64_wrs_vxworks.rs +++ b/compiler/rustc_target/src/spec/x86_64_wrs_vxworks.rs @@ -11,7 +11,7 @@ pub fn target() -> Target { Target { llvm_target: "x86_64-unknown-linux-gnu".to_string(), target_endian: "little".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" .to_string(), diff --git a/compiler/rustc_trait_selection/src/opaque_types.rs b/compiler/rustc_trait_selection/src/opaque_types.rs index 610c6fd7e35..ecaafee77e2 100644 --- a/compiler/rustc_trait_selection/src/opaque_types.rs +++ b/compiler/rustc_trait_selection/src/opaque_types.rs @@ -717,6 +717,8 @@ where ty::Closure(_, ref substs) => { // Skip lifetime parameters of the enclosing item(s) + substs.as_closure().tupled_upvars_ty().visit_with(self); + for upvar_ty in substs.as_closure().upvar_tys() { upvar_ty.visit_with(self); } @@ -728,6 +730,8 @@ where // Skip lifetime parameters of the enclosing item(s) // Also skip the witness type, because that has no free regions. + substs.as_generator().tupled_upvars_ty().visit_with(self); + for upvar_ty in substs.as_generator().upvar_tys() { upvar_ty.visit_with(self); } diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs index e40067202e1..93a0073588e 100644 --- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs +++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs @@ -642,7 +642,8 @@ impl AutoTraitFinder<'tcx> { // We check this by calling is_of_param on the relevant types // from the various possible predicates - match predicate.skip_binders() { + let bound_predicate = predicate.bound_atom(); + match bound_predicate.skip_binder() { ty::PredicateAtom::Trait(p, _) => { if self.is_param_no_infer(p.trait_ref.substs) && !only_projections @@ -650,10 +651,10 @@ impl AutoTraitFinder<'tcx> { { self.add_user_pred(computed_preds, predicate); } - predicates.push_back(ty::Binder::bind(p)); + predicates.push_back(bound_predicate.rebind(p)); } ty::PredicateAtom::Projection(p) => { - let p = ty::Binder::bind(p); + let p = bound_predicate.rebind(p); debug!( "evaluate_nested_obligations: examining projection predicate {:?}", predicate @@ -783,13 +784,13 @@ impl AutoTraitFinder<'tcx> { } } ty::PredicateAtom::RegionOutlives(binder) => { - let binder = ty::Binder::bind(binder); + let binder = bound_predicate.rebind(binder); if select.infcx().region_outlives_predicate(&dummy_cause, binder).is_err() { return false; } } ty::PredicateAtom::TypeOutlives(binder) => { - let binder = ty::Binder::bind(binder); + let binder = bound_predicate.rebind(binder); match ( binder.no_bound_vars(), binder.map_bound_ref(|pred| pred.0).no_bound_vars(), diff --git a/compiler/rustc_trait_selection/src/traits/codegen/mod.rs b/compiler/rustc_trait_selection/src/traits/codegen/mod.rs index dd7ea55cc10..05e6c4804ff 100644 --- a/compiler/rustc_trait_selection/src/traits/codegen/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/codegen/mod.rs @@ -17,14 +17,17 @@ use rustc_middle::ty::{self, TyCtxt}; /// (necessarily) resolve all nested obligations on the impl. Note /// that type check should guarantee to us that all nested /// obligations *could be* resolved if we wanted to. +/// /// Assumes that this is run after the entire crate has been successfully type-checked. +/// This also expects that `trait_ref` is fully normalized. pub fn codegen_fulfill_obligation<'tcx>( - ty: TyCtxt<'tcx>, + tcx: TyCtxt<'tcx>, (param_env, trait_ref): (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>), ) -> Result<ImplSource<'tcx, ()>, ErrorReported> { // Remove any references to regions; this helps improve caching. - let trait_ref = ty.erase_regions(&trait_ref); - + let trait_ref = tcx.erase_regions(&trait_ref); + // We expect the input to be fully normalized. + debug_assert_eq!(trait_ref, tcx.normalize_erasing_regions(param_env, trait_ref)); debug!( "codegen_fulfill_obligation(trait_ref={:?}, def_id={:?})", (param_env, trait_ref), @@ -33,7 +36,7 @@ pub fn codegen_fulfill_obligation<'tcx>( // Do the initial selection for the obligation. This yields the // shallow result we are looking for -- that is, what specific impl. - ty.infer_ctxt().enter(|infcx| { + tcx.infer_ctxt().enter(|infcx| { let mut selcx = SelectionContext::new(&infcx); let obligation_cause = ObligationCause::dummy(); diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index 3828cf4d302..1e1eb16faf4 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -147,11 +147,7 @@ pub fn is_const_evaluatable<'cx, 'tcx>( if concrete.is_ok() && substs.has_param_types_or_consts() { match infcx.tcx.def_kind(def.did) { DefKind::AnonConst => { - let mir_body = if let Some(def) = def.as_const_arg() { - infcx.tcx.optimized_mir_of_const_arg(def) - } else { - infcx.tcx.optimized_mir(def.did) - }; + let mir_body = infcx.tcx.optimized_mir_opt_const_arg(def); if mir_body.is_polymorphic { future_compat_lint(); @@ -212,13 +208,7 @@ impl AbstractConst<'tcx> { def: ty::WithOptConstParam<DefId>, substs: SubstsRef<'tcx>, ) -> Result<Option<AbstractConst<'tcx>>, ErrorReported> { - let inner = match (def.did.as_local(), def.const_param_did) { - (Some(did), Some(param_did)) => { - tcx.mir_abstract_const_of_const_arg((did, param_did))? - } - _ => tcx.mir_abstract_const(def.did)?, - }; - + let inner = tcx.mir_abstract_const_opt_const_arg(def)?; Ok(inner.map(|inner| AbstractConst { inner, substs })) } diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index 05e3ed34351..f53465266d2 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -255,9 +255,10 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { return; } - match obligation.predicate.skip_binders() { + let bound_predicate = obligation.predicate.bound_atom(); + match bound_predicate.skip_binder() { ty::PredicateAtom::Trait(trait_predicate, _) => { - let trait_predicate = ty::Binder::bind(trait_predicate); + let trait_predicate = bound_predicate.rebind(trait_predicate); let trait_predicate = self.resolve_vars_if_possible(&trait_predicate); if self.tcx.sess.has_errors() && trait_predicate.references_error() { @@ -531,7 +532,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { } ty::PredicateAtom::RegionOutlives(predicate) => { - let predicate = ty::Binder::bind(predicate); + let predicate = bound_predicate.rebind(predicate); let predicate = self.resolve_vars_if_possible(&predicate); let err = self .region_outlives_predicate(&obligation.cause, predicate) @@ -1078,9 +1079,10 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> { } // FIXME: It should be possible to deal with `ForAll` in a cleaner way. - let (cond, error) = match (cond.skip_binders(), error.skip_binders()) { + let bound_error = error.bound_atom(); + let (cond, error) = match (cond.skip_binders(), bound_error.skip_binder()) { (ty::PredicateAtom::Trait(..), ty::PredicateAtom::Trait(error, _)) => { - (cond, ty::Binder::bind(error)) + (cond, bound_error.rebind(error)) } _ => { // FIXME: make this work in other cases too. @@ -1089,9 +1091,10 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> { }; for obligation in super::elaborate_predicates(self.tcx, std::iter::once(cond)) { - if let ty::PredicateAtom::Trait(implication, _) = obligation.predicate.skip_binders() { + let bound_predicate = obligation.predicate.bound_atom(); + if let ty::PredicateAtom::Trait(implication, _) = bound_predicate.skip_binder() { let error = error.to_poly_trait_ref(); - let implication = ty::Binder::bind(implication.trait_ref); + let implication = bound_predicate.rebind(implication.trait_ref); // FIXME: I'm just not taking associated types at all here. // Eventually I'll need to implement param-env-aware // `Γ₁ ⊦ φ₁ => Γ₂ ⊦ φ₂` logic. @@ -1169,12 +1172,13 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> { // // this can fail if the problem was higher-ranked, in which // cause I have no idea for a good error message. - if let ty::PredicateAtom::Projection(data) = predicate.skip_binders() { + let bound_predicate = predicate.bound_atom(); + if let ty::PredicateAtom::Projection(data) = bound_predicate.skip_binder() { let mut selcx = SelectionContext::new(self); let (data, _) = self.replace_bound_vars_with_fresh_vars( obligation.cause.span, infer::LateBoundRegionConversionTime::HigherRankedType, - &ty::Binder::bind(data), + &bound_predicate.rebind(data), ); let mut obligations = vec![]; let normalized_ty = super::normalize_projection_type( @@ -1455,10 +1459,11 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> { return; } - let mut err = match predicate.skip_binders() { + let bound_predicate = predicate.bound_atom(); + let mut err = match bound_predicate.skip_binder() { ty::PredicateAtom::Trait(data, _) => { - let trait_ref = ty::Binder::bind(data.trait_ref); - let self_ty = trait_ref.skip_binder().self_ty(); + let self_ty = data.trait_ref.self_ty(); + let trait_ref = bound_predicate.rebind(data.trait_ref); debug!("self_ty {:?} {:?} trait_ref {:?}", self_ty, self_ty.kind(), trait_ref); if predicate.references_error() { @@ -1582,7 +1587,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> { self.emit_inference_failure_err(body_id, span, a.into(), ErrorCode::E0282) } ty::PredicateAtom::Projection(data) => { - let trait_ref = ty::Binder::bind(data).to_poly_trait_ref(self.tcx); + let trait_ref = bound_predicate.rebind(data).to_poly_trait_ref(self.tcx); let self_ty = trait_ref.skip_binder().self_ty(); let ty = data.ty; if predicate.references_error() { diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 967374ffdc2..efa9bd633ba 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -22,6 +22,7 @@ use rustc_middle::ty::{ use rustc_middle::ty::{TypeAndMut, TypeckResults}; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{MultiSpan, Span, DUMMY_SP}; +use rustc_target::spec::abi; use std::fmt; use super::InferCtxtPrivExt; @@ -1157,15 +1158,15 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { tcx.mk_ty_infer(ty::TyVar(ty::TyVid { index: 0 })), false, hir::Unsafety::Normal, - ::rustc_target::spec::abi::Abi::Rust, + abi::Abi::Rust, ) } else { tcx.mk_fn_sig( - ::std::iter::once(inputs), + std::iter::once(inputs), tcx.mk_ty_infer(ty::TyVar(ty::TyVid { index: 0 })), false, hir::Unsafety::Normal, - ::rustc_target::spec::abi::Abi::Rust, + abi::Abi::Rust, ) }; ty::Binder::bind(sig).to_string() @@ -1307,6 +1308,9 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { let mut generator = None; let mut outer_generator = None; let mut next_code = Some(&obligation.cause.code); + + let mut seen_upvar_tys_infer_tuple = false; + while let Some(code) = next_code { debug!("maybe_note_obligation_cause_for_async_await: code={:?}", code); match code { @@ -1327,6 +1331,13 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { outer_generator = Some(did); } ty::GeneratorWitness(..) => {} + ty::Tuple(_) if !seen_upvar_tys_infer_tuple => { + // By introducing a tuple of upvar types into the chain of obligations + // of a generator, the first non-generator item is now the tuple itself, + // we shall ignore this. + + seen_upvar_tys_infer_tuple = true; + } _ if generator.is_none() => { trait_ref = Some(derived_obligation.parent_trait_ref.skip_binder()); target_ty = Some(ty); @@ -1912,7 +1923,29 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { return; } - err.note(&format!("required because it appears within the type `{}`", ty)); + // If the obligation for a tuple is set directly by a Generator or Closure, + // then the tuple must be the one containing capture types. + let is_upvar_tys_infer_tuple = if !matches!(ty.kind(), ty::Tuple(..)) { + false + } else { + if let ObligationCauseCode::BuiltinDerivedObligation(ref data) = + *data.parent_code + { + let parent_trait_ref = + self.resolve_vars_if_possible(&data.parent_trait_ref); + let ty = parent_trait_ref.skip_binder().self_ty(); + matches!(ty.kind(), ty::Generator(..)) + || matches!(ty.kind(), ty::Closure(..)) + } else { + false + } + }; + + // Don't print the tuple of capture types + if !is_upvar_tys_infer_tuple { + err.note(&format!("required because it appears within the type `{}`", ty)); + } + obligated_types.push(ty); let parent_predicate = parent_trait_ref.without_const().to_predicate(tcx); diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index 27751eb554d..9a8b5534dfe 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -1,6 +1,6 @@ use crate::infer::{InferCtxt, TyOrConstInferVar}; use rustc_data_structures::obligation_forest::ProcessResult; -use rustc_data_structures::obligation_forest::{DoCompleted, Error, ForestObligation}; +use rustc_data_structures::obligation_forest::{Error, ForestObligation, Outcome}; use rustc_data_structures::obligation_forest::{ObligationForest, ObligationProcessor}; use rustc_errors::ErrorReported; use rustc_infer::traits::{TraitEngine, TraitEngineExt as _, TraitObligation}; @@ -120,7 +120,8 @@ impl<'a, 'tcx> FulfillmentContext<'tcx> { &mut self, selcx: &mut SelectionContext<'a, 'tcx>, ) -> Result<(), Vec<FulfillmentError<'tcx>>> { - debug!("select(obligation-forest-size={})", self.predicates.len()); + let span = debug_span!("select", obligation_forest_size = ?self.predicates.len()); + let _enter = span.enter(); let mut errors = Vec::new(); @@ -128,13 +129,11 @@ impl<'a, 'tcx> FulfillmentContext<'tcx> { debug!("select: starting another iteration"); // Process pending obligations. - let outcome = self.predicates.process_obligations( - &mut FulfillProcessor { + let outcome: Outcome<_, _> = + self.predicates.process_obligations(&mut FulfillProcessor { selcx, register_region_obligations: self.register_region_obligations, - }, - DoCompleted::No, - ); + }); debug!("select: outcome={:#?}", outcome); // FIXME: if we kept the original cache key, we could mark projection @@ -173,7 +172,7 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> { projection_ty: ty::ProjectionTy<'tcx>, cause: ObligationCause<'tcx>, ) -> Ty<'tcx> { - debug!("normalize_projection_type(projection_ty={:?})", projection_ty); + debug!(?projection_ty, "normalize_projection_type"); debug_assert!(!projection_ty.has_escaping_bound_vars()); @@ -191,7 +190,7 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> { ); self.register_predicate_obligations(infcx, obligations); - debug!("normalize_projection_type: result={:?}", normalized_ty); + debug!(?normalized_ty); normalized_ty } @@ -205,7 +204,7 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> { // debug output much nicer to read and so on. let obligation = infcx.resolve_vars_if_possible(&obligation); - debug!("register_predicate_obligation(obligation={:?})", obligation); + debug!(?obligation, "register_predicate_obligation"); assert!(!infcx.is_in_snapshot() || self.usable_in_snapshot); @@ -342,7 +341,7 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> { self.selcx.infcx().resolve_vars_if_possible(&obligation.predicate); } - debug!("process_obligation: obligation = {:?} cause = {:?}", obligation, obligation.cause); + debug!(?obligation, ?obligation.cause, "process_obligation"); let infcx = self.selcx.infcx(); @@ -352,7 +351,7 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> { // This means we need to pass it the bound version of our // predicate. ty::PredicateAtom::Trait(trait_ref, _constness) => { - let trait_obligation = obligation.with(Binder::bind(trait_ref)); + let trait_obligation = obligation.with(binder.rebind(trait_ref)); self.process_trait_obligation( obligation, @@ -361,7 +360,7 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> { ) } ty::PredicateAtom::Projection(data) => { - let project_obligation = obligation.with(Binder::bind(data)); + let project_obligation = obligation.with(binder.rebind(data)); self.process_projection_obligation( project_obligation, @@ -509,7 +508,7 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> { } ty::PredicateAtom::ConstEquate(c1, c2) => { - debug!("equating consts: c1={:?} c2={:?}", c1, c2); + debug!(?c1, ?c2, "equating consts"); if self.selcx.tcx().features().const_evaluatable_checked { // FIXME: we probably should only try to unify abstract constants // if the constants depend on generic parameters. @@ -601,6 +600,7 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> { } } + #[instrument(level = "debug", skip(self, obligation, stalled_on))] fn process_trait_obligation( &mut self, obligation: &PredicateObligation<'tcx>, @@ -613,8 +613,8 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> { // FIXME: consider caching errors too. if infcx.predicate_must_hold_considering_regions(obligation) { debug!( - "selecting trait `{:?}` at depth {} evaluated to holds", - obligation.predicate, obligation.recursion_depth + "selecting trait at depth {} evaluated to holds", + obligation.recursion_depth ); return ProcessResult::Changed(vec![]); } @@ -622,17 +622,11 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> { match self.selcx.select(&trait_obligation) { Ok(Some(impl_source)) => { - debug!( - "selecting trait `{:?}` at depth {} yielded Ok(Some)", - trait_obligation.predicate, obligation.recursion_depth - ); + debug!("selecting trait at depth {} yielded Ok(Some)", obligation.recursion_depth); ProcessResult::Changed(mk_pending(impl_source.nested_obligations())) } Ok(None) => { - debug!( - "selecting trait `{:?}` at depth {} yielded Ok(None)", - trait_obligation.predicate, obligation.recursion_depth - ); + debug!("selecting trait at depth {} yielded Ok(None)", obligation.recursion_depth); // This is a bit subtle: for the most part, the // only reason we can fail to make progress on @@ -652,10 +646,7 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> { ProcessResult::Unchanged } Err(selection_err) => { - info!( - "selecting trait `{:?}` at depth {} yielded Err", - trait_obligation.predicate, obligation.recursion_depth - ); + info!("selecting trait at depth {} yielded Err", obligation.recursion_depth); ProcessResult::Error(CodeSelectionError(selection_err)) } diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index de42aa0e6b7..827b1d35f1c 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -157,6 +157,7 @@ impl<'tcx> ProjectionTyCandidateSet<'tcx> { /// the given obligations. If the projection cannot be normalized because /// the required trait bound doesn't hold this returned with `obligations` /// being a predicate that cannot be proven. +#[instrument(level = "debug", skip(selcx))] pub(super) fn poly_project_and_unify_type<'cx, 'tcx>( selcx: &mut SelectionContext<'cx, 'tcx>, obligation: &PolyProjectionObligation<'tcx>, @@ -164,8 +165,6 @@ pub(super) fn poly_project_and_unify_type<'cx, 'tcx>( Result<Option<Vec<PredicateObligation<'tcx>>>, InProgress>, MismatchedProjectionTypes<'tcx>, > { - debug!("poly_project_and_unify_type(obligation={:?})", obligation); - let infcx = selcx.infcx(); infcx.commit_if_ok(|_snapshot| { let placeholder_predicate = @@ -191,7 +190,7 @@ fn project_and_unify_type<'cx, 'tcx>( Result<Option<Vec<PredicateObligation<'tcx>>>, InProgress>, MismatchedProjectionTypes<'tcx>, > { - debug!("project_and_unify_type(obligation={:?})", obligation); + debug!(?obligation, "project_and_unify_type"); let mut obligations = vec![]; let normalized_ty = match opt_normalize_projection_type( @@ -207,10 +206,7 @@ fn project_and_unify_type<'cx, 'tcx>( Err(InProgress) => return Ok(Err(InProgress)), }; - debug!( - "project_and_unify_type: normalized_ty={:?} obligations={:?}", - normalized_ty, obligations - ); + debug!(?normalized_ty, ?obligations, "project_and_unify_type result"); let infcx = selcx.infcx(); match infcx @@ -275,6 +271,7 @@ where Normalized { value, obligations } } +#[instrument(level = "debug", skip(selcx, param_env, cause, obligations))] pub fn normalize_with_depth_to<'a, 'b, 'tcx, T>( selcx: &'a mut SelectionContext<'b, 'tcx>, param_env: ty::ParamEnv<'tcx>, @@ -286,16 +283,10 @@ pub fn normalize_with_depth_to<'a, 'b, 'tcx, T>( where T: TypeFoldable<'tcx>, { - debug!("normalize_with_depth(depth={}, value={:?})", depth, value); let mut normalizer = AssocTypeNormalizer::new(selcx, param_env, cause, depth, obligations); let result = ensure_sufficient_stack(|| normalizer.fold(value)); - debug!( - "normalize_with_depth: depth={} result={:?} with {} obligations", - depth, - result, - normalizer.obligations.len() - ); - debug!("normalize_with_depth: depth={} obligations={:?}", depth, normalizer.obligations); + debug!(?result, obligations.len = normalizer.obligations.len()); + debug!(?normalizer.obligations,); result } @@ -396,12 +387,11 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> { &mut self.obligations, ); debug!( - "AssocTypeNormalizer: depth={} normalized {:?} to {:?}, \ - now with {} obligations", - self.depth, - ty, - normalized_ty, - self.obligations.len() + ?self.depth, + ?ty, + ?normalized_ty, + obligations.len = ?self.obligations.len(), + "AssocTypeNormalizer: normalized type" ); normalized_ty } @@ -473,6 +463,7 @@ pub fn normalize_projection_type<'a, 'b, 'tcx>( /// often immediately appended to another obligations vector. So now this /// function takes an obligations vector and appends to it directly, which is /// slightly uglier but avoids the need for an extra short-lived allocation. +#[instrument(level = "debug", skip(selcx, param_env, cause, obligations))] fn opt_normalize_projection_type<'a, 'b, 'tcx>( selcx: &'a mut SelectionContext<'b, 'tcx>, param_env: ty::ParamEnv<'tcx>, @@ -486,13 +477,6 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>( let projection_ty = infcx.resolve_vars_if_possible(&projection_ty); let cache_key = ProjectionCacheKey::new(projection_ty); - debug!( - "opt_normalize_projection_type(\ - projection_ty={:?}, \ - depth={})", - projection_ty, depth - ); - // FIXME(#20304) For now, I am caching here, which is good, but it // means we don't capture the type variables that are created in // the case of ambiguity. Which means we may create a large stream @@ -508,10 +492,7 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>( // If we found ambiguity the last time, that means we will continue // to do so until some type in the key changes (and we know it // hasn't, because we just fully resolved it). - debug!( - "opt_normalize_projection_type: \ - found cache entry: ambiguous" - ); + debug!("found cache entry: ambiguous"); return Ok(None); } Err(ProjectionCacheEntry::InProgress) => { @@ -529,10 +510,7 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>( // with `A::B`, which can trigger a recursive // normalization. - debug!( - "opt_normalize_projection_type: \ - found cache entry: in-progress" - ); + debug!("found cache entry: in-progress"); return Err(InProgress); } @@ -548,11 +526,7 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>( // discarded as duplicated). But when doing trait // evaluation this is not the case, and dropping the trait // evaluations can causes ICEs (e.g., #43132). - debug!( - "opt_normalize_projection_type: \ - found normalized ty `{:?}`", - ty - ); + debug!(?ty, "found normalized ty"); // Once we have inferred everything we need to know, we // can ignore the `obligations` from that point on. @@ -565,10 +539,7 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>( return Ok(Some(ty.value)); } Err(ProjectionCacheEntry::Error) => { - debug!( - "opt_normalize_projection_type: \ - found error" - ); + debug!("opt_normalize_projection_type: found error"); let result = normalize_to_error(selcx, param_env, projection_ty, cause, depth); obligations.extend(result.obligations); return Ok(Some(result.value)); @@ -586,13 +557,7 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>( // an impl, where-clause etc) and hence we must // re-normalize it - debug!( - "opt_normalize_projection_type: \ - projected_ty={:?} \ - depth={} \ - projected_obligations={:?}", - projected_ty, depth, projected_obligations - ); + debug!(?projected_ty, ?depth, ?projected_obligations); let result = if projected_ty.has_projections() { let mut normalizer = AssocTypeNormalizer::new( @@ -604,11 +569,7 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>( ); let normalized_ty = normalizer.fold(&projected_ty); - debug!( - "opt_normalize_projection_type: \ - normalized_ty={:?} depth={}", - normalized_ty, depth - ); + debug!(?normalized_ty, ?depth); Normalized { value: normalized_ty, obligations: projected_obligations } } else { @@ -621,21 +582,14 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>( Ok(Some(result.value)) } Ok(ProjectedTy::NoProgress(projected_ty)) => { - debug!( - "opt_normalize_projection_type: \ - projected_ty={:?} no progress", - projected_ty - ); + debug!(?projected_ty, "opt_normalize_projection_type: no progress"); let result = Normalized { value: projected_ty, obligations: vec![] }; infcx.inner.borrow_mut().projection_cache().insert_ty(cache_key, result.clone()); // No need to extend `obligations`. Ok(Some(result.value)) } Err(ProjectionTyError::TooManyCandidates) => { - debug!( - "opt_normalize_projection_type: \ - too many candidates" - ); + debug!("opt_normalize_projection_type: too many candidates"); infcx.inner.borrow_mut().projection_cache().ambiguous(cache_key); Ok(None) } @@ -669,7 +623,8 @@ fn prune_cache_value_obligations<'a, 'tcx>( .obligations .iter() .filter(|obligation| { - match obligation.predicate.skip_binders() { + let bound_predicate = obligation.predicate.bound_atom(); + match bound_predicate.skip_binder() { // We found a `T: Foo<X = U>` predicate, let's check // if `U` references any unresolved type // variables. In principle, we only care if this @@ -680,7 +635,7 @@ fn prune_cache_value_obligations<'a, 'tcx>( // but we have `T: Foo<X = ?1>` and `?1: Bar<X = // ?0>`). ty::PredicateAtom::Projection(data) => { - infcx.unresolved_type_vars(&ty::Binder::bind(data.ty)).is_some() + infcx.unresolved_type_vars(&bound_predicate.rebind(data.ty)).is_some() } // We are only interested in `T: Foo<X = U>` predicates, whre @@ -755,15 +710,12 @@ impl<'tcx> Progress<'tcx> { fn with_addl_obligations(mut self, mut obligations: Vec<PredicateObligation<'tcx>>) -> Self { debug!( - "with_addl_obligations: self.obligations.len={} obligations.len={}", - self.obligations.len(), - obligations.len() + self.obligations.len = ?self.obligations.len(), + obligations.len = obligations.len(), + "with_addl_obligations" ); - debug!( - "with_addl_obligations: self.obligations={:?} obligations={:?}", - self.obligations, obligations - ); + debug!(?self.obligations, ?obligations, "with_addl_obligations"); self.obligations.append(&mut obligations); self @@ -778,7 +730,7 @@ fn project_type<'cx, 'tcx>( selcx: &mut SelectionContext<'cx, 'tcx>, obligation: &ProjectionTyObligation<'tcx>, ) -> Result<ProjectedTy<'tcx>, ProjectionTyError<'tcx>> { - debug!("project(obligation={:?})", obligation); + debug!(?obligation, "project_type"); if !selcx.tcx().sess.recursion_limit().value_within_limit(obligation.recursion_depth) { debug!("project: overflow!"); @@ -787,7 +739,7 @@ fn project_type<'cx, 'tcx>( let obligation_trait_ref = &obligation.predicate.trait_ref(selcx.tcx()); - debug!("project: obligation_trait_ref={:?}", obligation_trait_ref); + debug!(?obligation_trait_ref); if obligation_trait_ref.references_error() { return Ok(ProjectedTy::Progress(Progress::error(selcx.tcx()))); @@ -951,12 +903,14 @@ fn assemble_candidates_from_predicates<'cx, 'tcx>( env_predicates: impl Iterator<Item = ty::Predicate<'tcx>>, potentially_unnormalized_candidates: bool, ) { - debug!("assemble_candidates_from_predicates(obligation={:?})", obligation); + debug!(?obligation, "assemble_candidates_from_predicates"); + let infcx = selcx.infcx(); for predicate in env_predicates { - debug!("assemble_candidates_from_predicates: predicate={:?}", predicate); + debug!(?predicate); + let bound_predicate = predicate.bound_atom(); if let ty::PredicateAtom::Projection(data) = predicate.skip_binders() { - let data = ty::Binder::bind(data); + let data = bound_predicate.rebind(data); let same_def_id = data.projection_def_id() == obligation.predicate.item_def_id; let is_match = same_def_id @@ -969,11 +923,7 @@ fn assemble_candidates_from_predicates<'cx, 'tcx>( ) }); - debug!( - "assemble_candidates_from_predicates: candidate={:?} \ - is_match={} same_def_id={}", - data, is_match, same_def_id - ); + debug!(?data, ?is_match, ?same_def_id); if is_match { candidate_set.push_candidate(ctor(data)); @@ -997,6 +947,8 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( obligation_trait_ref: &ty::TraitRef<'tcx>, candidate_set: &mut ProjectionTyCandidateSet<'tcx>, ) { + debug!("assemble_candidates_from_impls"); + // If we are resolving `<T as TraitRef<...>>::Item == Type`, // start out by selecting the predicate `T as TraitRef<...>`: let poly_trait_ref = obligation_trait_ref.to_poly_trait_ref(); @@ -1009,7 +961,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( return Err(()); } Err(e) => { - debug!("assemble_candidates_from_impls: selection error {:?}", e); + debug!(error = ?e, "selection error"); candidate_set.mark_error(e); return Err(()); } @@ -1020,7 +972,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( | super::ImplSource::Generator(_) | super::ImplSource::FnPointer(_) | super::ImplSource::TraitAlias(_) => { - debug!("assemble_candidates_from_impls: impl_source={:?}", impl_source); + debug!(?impl_source); true } super::ImplSource::UserDefined(impl_data) => { @@ -1066,10 +1018,9 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( !poly_trait_ref.still_further_specializable() } else { debug!( - "assemble_candidates_from_impls: not eligible due to default: \ - assoc_ty={} predicate={}", - selcx.tcx().def_path_str(node_item.item.def_id), - obligation.predicate, + assoc_ty = ?selcx.tcx().def_path_str(node_item.item.def_id), + ?obligation.predicate, + "assemble_candidates_from_impls: not eligible due to default", ); false } @@ -1176,8 +1127,7 @@ fn confirm_candidate<'cx, 'tcx>( obligation: &ProjectionTyObligation<'tcx>, candidate: ProjectionTyCandidate<'tcx>, ) -> Progress<'tcx> { - debug!("confirm_candidate(candidate={:?}, obligation={:?})", candidate, obligation); - + debug!(?obligation, ?candidate, "confirm_candidate"); let mut progress = match candidate { ProjectionTyCandidate::ParamEnv(poly_projection) | ProjectionTyCandidate::Object(poly_projection) => { @@ -1220,9 +1170,8 @@ fn confirm_select_candidate<'cx, 'tcx>( | super::ImplSource::AutoImpl(..) | super::ImplSource::Param(..) | super::ImplSource::Builtin(..) - | super::ImplSource::TraitAlias(..) => - // we don't create Select candidates with this kind of resolution - { + | super::ImplSource::TraitAlias(..) => { + // we don't create Select candidates with this kind of resolution span_bug!( obligation.cause.span, "Cannot project an associated type from `{:?}`", @@ -1246,10 +1195,7 @@ fn confirm_generator_candidate<'cx, 'tcx>( &gen_sig, ); - debug!( - "confirm_generator_candidate: obligation={:?},gen_sig={:?},obligations={:?}", - obligation, gen_sig, obligations - ); + debug!(?obligation, ?gen_sig, ?obligations, "confirm_generator_candidate"); let tcx = selcx.tcx(); @@ -1339,10 +1285,7 @@ fn confirm_closure_candidate<'cx, 'tcx>( &closure_sig, ); - debug!( - "confirm_closure_candidate: obligation={:?},closure_sig={:?},obligations={:?}", - obligation, closure_sig, obligations - ); + debug!(?obligation, ?closure_sig, ?obligations, "confirm_closure_candidate"); confirm_callable_candidate(selcx, obligation, closure_sig, util::TupleArgumentsFlag::No) .with_addl_obligations(impl_source.nested) @@ -1357,7 +1300,7 @@ fn confirm_callable_candidate<'cx, 'tcx>( ) -> Progress<'tcx> { let tcx = selcx.tcx(); - debug!("confirm_callable_candidate({:?},{:?})", obligation, fn_sig); + debug!(?obligation, ?fn_sig, "confirm_callable_candidate"); let fn_once_def_id = tcx.require_lang_item(LangItem::FnOnce, None); let fn_once_output_def_id = tcx.require_lang_item(LangItem::FnOnceOutput, None); diff --git a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs index 424b3bd67ff..8212823a6db 100644 --- a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs +++ b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs @@ -110,7 +110,7 @@ pub fn trivial_dropck_outlives<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool { // check if *any* of those are trivial. ty::Tuple(ref tys) => tys.iter().all(|t| trivial_dropck_outlives(tcx, t.expect_ty())), ty::Closure(_, ref substs) => { - substs.as_closure().upvar_tys().all(|t| trivial_dropck_outlives(tcx, t)) + trivial_dropck_outlives(tcx, substs.as_closure().tupled_upvars_ty()) } ty::Adt(def, _) => { diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs index bdbf45f78a2..d748fc8235e 100644 --- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs @@ -44,7 +44,7 @@ impl<'cx, 'tcx> AtExt<'tcx> for At<'cx, 'tcx> { { debug!( "normalize::<{}>(value={:?}, param_env={:?})", - ::std::any::type_name::<T>(), + std::any::type_name::<T>(), value, self.param_env, ); @@ -65,13 +65,13 @@ impl<'cx, 'tcx> AtExt<'tcx> for At<'cx, 'tcx> { let result = value.fold_with(&mut normalizer); debug!( "normalize::<{}>: result={:?} with {} obligations", - ::std::any::type_name::<T>(), + std::any::type_name::<T>(), result, normalizer.obligations.len(), ); debug!( "normalize::<{}>: obligations={:?}", - ::std::any::type_name::<T>(), + std::any::type_name::<T>(), normalizer.obligations, ); if normalizer.error { diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index 038ba431c47..fdf1641c986 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -22,6 +22,7 @@ use super::SelectionCandidate::{self, *}; use super::{EvaluatedCandidate, SelectionCandidateSet, SelectionContext, TraitObligationStack}; impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { + #[instrument(level = "debug", skip(self))] pub(super) fn candidate_from_obligation<'o>( &mut self, stack: &TraitObligationStack<'o, 'tcx>, @@ -35,16 +36,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // this is because we want the unbound variables to be // replaced with fresh types starting from index 0. let cache_fresh_trait_pred = self.infcx.freshen(stack.obligation.predicate); - debug!( - "candidate_from_obligation(cache_fresh_trait_pred={:?}, obligation={:?})", - cache_fresh_trait_pred, stack - ); + debug!(?cache_fresh_trait_pred); debug_assert!(!stack.obligation.predicate.has_escaping_bound_vars()); if let Some(c) = self.check_candidate_cache(stack.obligation.param_env, cache_fresh_trait_pred) { - debug!("CACHE HIT: SELECT({:?})={:?}", cache_fresh_trait_pred, c); + debug!(candidate = ?c, "CACHE HIT"); return c; } @@ -57,7 +55,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let (candidate, dep_node) = self.in_task(|this| this.candidate_from_obligation_no_cache(stack)); - debug!("CACHE MISS: SELECT({:?})={:?}", cache_fresh_trait_pred, candidate); + debug!(?candidate, "CACHE MISS"); self.insert_candidate_cache( stack.obligation.param_env, cache_fresh_trait_pred, @@ -103,7 +101,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } else { IntercrateAmbiguityCause::DownstreamCrate { trait_desc, self_desc } }; - debug!("evaluate_stack: pushing cause = {:?}", cause); + debug!(?cause, "evaluate_stack: pushing cause"); self.intercrate_ambiguity_causes.as_mut().unwrap().push(cause); } } @@ -120,7 +118,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let mut candidates = candidate_set.vec; - debug!("assembled {} candidates for {:?}: {:?}", candidates.len(), stack, candidates); + debug!(?stack, ?candidates, "assembled {} candidates", candidates.len()); // At this point, we know that each of the entries in the // candidate set is *individually* applicable. Now we have to @@ -163,7 +161,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { .flat_map(Result::transpose) .collect::<Result<Vec<_>, _>>()?; - debug!("winnowed to {} candidates for {:?}: {:?}", candidates.len(), stack, candidates); + debug!(?stack, ?candidates, "winnowed to {} candidates", candidates.len()); let needs_infer = stack.obligation.predicate.has_infer_types_or_consts(); @@ -181,10 +179,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ) }); if is_dup { - debug!("Dropping candidate #{}/{}: {:?}", i, candidates.len(), candidates[i]); + debug!(candidate = ?candidates[i], "Dropping candidate #{}/{}", i, candidates.len()); candidates.swap_remove(i); } else { - debug!("Retaining candidate #{}/{}: {:?}", i, candidates.len(), candidates[i]); + debug!(candidate = ?candidates[i], "Retaining candidate #{}/{}", i, candidates.len()); i += 1; // If there are *STILL* multiple candidates, give up @@ -257,7 +255,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let lang_items = self.tcx().lang_items(); if lang_items.copy_trait() == Some(def_id) { - debug!("obligation self ty is {:?}", obligation.predicate.skip_binder().self_ty()); + debug!(obligation_self_ty = ?obligation.predicate.skip_binder().self_ty()); // User-defined copy impls are permitted, but only for // structs and enums. @@ -308,7 +306,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation: &TraitObligation<'tcx>, candidates: &mut SelectionCandidateSet<'tcx>, ) { - debug!("assemble_candidates_for_projected_tys({:?})", obligation); + debug!(?obligation, "assemble_candidates_from_projected_tys"); // Before we go into the whole placeholder thing, just // quickly check if the self-type is a projection at all. @@ -341,7 +339,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { stack: &TraitObligationStack<'o, 'tcx>, candidates: &mut SelectionCandidateSet<'tcx>, ) -> Result<(), SelectionError<'tcx>> { - debug!("assemble_candidates_from_caller_bounds({:?})", stack.obligation); + debug!(?stack.obligation, "assemble_candidates_from_caller_bounds"); let all_bounds = stack .obligation @@ -383,10 +381,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let self_ty = obligation.self_ty().skip_binder(); match self_ty.kind() { ty::Generator(..) => { - debug!( - "assemble_generator_candidates: self_ty={:?} obligation={:?}", - self_ty, obligation - ); + debug!(?self_ty, ?obligation, "assemble_generator_candidates",); candidates.vec.push(GeneratorCandidate); } @@ -423,10 +418,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // type/region parameters match *obligation.self_ty().skip_binder().kind() { ty::Closure(_, closure_substs) => { - debug!("assemble_unboxed_candidates: kind={:?} obligation={:?}", kind, obligation); + debug!(?kind, ?obligation, "assemble_unboxed_candidates"); match self.infcx.closure_kind(closure_substs) { Some(closure_kind) => { - debug!("assemble_unboxed_candidates: closure_kind = {:?}", closure_kind); + debug!(?closure_kind, "assemble_unboxed_candidates"); if closure_kind.extends(kind) { candidates.vec.push(ClosureCandidate); } @@ -503,7 +498,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation: &TraitObligation<'tcx>, candidates: &mut SelectionCandidateSet<'tcx>, ) -> Result<(), SelectionError<'tcx>> { - debug!("assemble_candidates_from_impls(obligation={:?})", obligation); + debug!(?obligation, "assemble_candidates_from_impls"); // Essentially any user-written impl will match with an error type, // so creating `ImplCandidates` isn't useful. However, we might @@ -537,7 +532,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ) -> Result<(), SelectionError<'tcx>> { // Okay to skip binder here because the tests we do below do not involve bound regions. let self_ty = obligation.self_ty().skip_binder(); - debug!("assemble_candidates_from_auto_impls(self_ty={:?})", self_ty); + debug!(?self_ty, "assemble_candidates_from_auto_impls"); let def_id = obligation.predicate.def_id(); @@ -604,8 +599,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { candidates: &mut SelectionCandidateSet<'tcx>, ) { debug!( - "assemble_candidates_from_object_ty(self_ty={:?})", - obligation.self_ty().skip_binder() + self_ty = ?obligation.self_ty().skip_binder(), + "assemble_candidates_from_object_ty", ); self.infcx.probe(|_snapshot| { @@ -645,7 +640,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { _ => return, }; - debug!("assemble_candidates_from_object_ty: poly_trait_ref={:?}", poly_trait_ref); + debug!(?poly_trait_ref, "assemble_candidates_from_object_ty"); // Count only those upcast versions that match the trait-ref // we are looking for. Specifically, do not only check for the @@ -697,7 +692,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { }; let target = obligation.predicate.skip_binder().trait_ref.substs.type_at(1); - debug!("assemble_candidates_for_unsizing(source={:?}, target={:?})", source, target); + debug!(?source, ?target, "assemble_candidates_for_unsizing"); let may_apply = match (source.kind(), target.kind()) { // Trait+Kx+'a -> Trait+Ky+'b (upcasts). @@ -758,7 +753,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ) -> Result<(), SelectionError<'tcx>> { // Okay to skip binder here because the tests we do below do not involve bound regions. let self_ty = obligation.self_ty().skip_binder(); - debug!("assemble_candidates_for_trait_alias(self_ty={:?})", self_ty); + debug!(?self_ty, "assemble_candidates_for_trait_alias"); let def_id = obligation.predicate.def_id(); @@ -778,7 +773,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ) -> Result<(), SelectionError<'tcx>> { match conditions { BuiltinImplConditions::Where(nested) => { - debug!("builtin_bound: nested={:?}", nested); + debug!(?nested, "builtin_bound"); candidates .vec .push(BuiltinCandidate { has_nested: !nested.skip_binder().is_empty() }); diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 96f0bedf6f1..37d619d5942 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -42,13 +42,12 @@ use super::SelectionContext; use std::iter; impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { + #[instrument(level = "debug", skip(self))] pub(super) fn confirm_candidate( &mut self, obligation: &TraitObligation<'tcx>, candidate: SelectionCandidate<'tcx>, ) -> Result<Selection<'tcx>, SelectionError<'tcx>> { - debug!("confirm_candidate({:?}, {:?})", obligation, candidate); - match candidate { BuiltinCandidate { has_nested } => { let data = self.confirm_builtin_candidate(obligation, has_nested); @@ -191,7 +190,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation: &TraitObligation<'tcx>, param: ty::PolyTraitRef<'tcx>, ) -> Vec<PredicateObligation<'tcx>> { - debug!("confirm_param_candidate({:?},{:?})", obligation, param); + debug!(?obligation, ?param, "confirm_param_candidate"); // During evaluation, we already checked that this // where-clause trait-ref could be unified with the obligation @@ -214,7 +213,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation: &TraitObligation<'tcx>, has_nested: bool, ) -> ImplSourceBuiltinData<PredicateObligation<'tcx>> { - debug!("confirm_builtin_candidate({:?}, {:?})", obligation, has_nested); + debug!(?obligation, ?has_nested, "confirm_builtin_candidate"); let lang_items = self.tcx().lang_items(); let obligations = if has_nested { @@ -247,7 +246,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { vec![] }; - debug!("confirm_builtin_candidate: obligations={:?}", obligations); + debug!(?obligations); ImplSourceBuiltinData { nested: obligations } } @@ -262,7 +261,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation: &TraitObligation<'tcx>, trait_def_id: DefId, ) -> ImplSourceAutoImplData<PredicateObligation<'tcx>> { - debug!("confirm_auto_impl_candidate({:?}, {:?})", obligation, trait_def_id); + debug!(?obligation, ?trait_def_id, "confirm_auto_impl_candidate"); let types = obligation.predicate.map_bound(|inner| { let self_ty = self.infcx.shallow_resolve(inner.self_ty()); @@ -278,7 +277,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { trait_def_id: DefId, nested: ty::Binder<Vec<Ty<'tcx>>>, ) -> ImplSourceAutoImplData<PredicateObligation<'tcx>> { - debug!("vtable_auto_impl: nested={:?}", nested); + debug!(?nested, "vtable_auto_impl"); ensure_sufficient_stack(|| { let cause = obligation.derived_cause(BuiltinDerivedObligation); let mut obligations = self.collect_predicates_for_types( @@ -308,7 +307,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // predicate as usual. It won't have any effect since auto traits are coinductive. obligations.extend(trait_obligations); - debug!("vtable_auto_impl: obligations={:?}", obligations); + debug!(?obligations, "vtable_auto_impl"); ImplSourceAutoImplData { trait_def_id, nested: obligations } }) @@ -319,13 +318,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation: &TraitObligation<'tcx>, impl_def_id: DefId, ) -> ImplSourceUserDefinedData<'tcx, PredicateObligation<'tcx>> { - debug!("confirm_impl_candidate({:?},{:?})", obligation, impl_def_id); + debug!(?obligation, ?impl_def_id, "confirm_impl_candidate"); // First, create the substitutions by matching the impl again, // this time not in a probe. self.infcx.commit_unconditionally(|_| { let substs = self.rematch_impl(impl_def_id, obligation); - debug!("confirm_impl_candidate: substs={:?}", substs); + debug!(?substs, "impl substs"); let cause = obligation.derived_cause(ImplDerivedObligation); ensure_sufficient_stack(|| { self.vtable_impl( @@ -347,10 +346,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { recursion_depth: usize, param_env: ty::ParamEnv<'tcx>, ) -> ImplSourceUserDefinedData<'tcx, PredicateObligation<'tcx>> { - debug!( - "vtable_impl(impl_def_id={:?}, substs={:?}, recursion_depth={})", - impl_def_id, substs, recursion_depth, - ); + debug!(?impl_def_id, ?substs, ?recursion_depth, "vtable_impl"); let mut impl_obligations = self.impl_or_trait_obligations( cause, @@ -360,10 +356,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { &substs.value, ); - debug!( - "vtable_impl: impl_def_id={:?} impl_obligations={:?}", - impl_def_id, impl_obligations - ); + debug!(?impl_obligations, "vtable_impl"); // Because of RFC447, the impl-trait-ref and obligations // are sufficient to determine the impl substs, without @@ -379,8 +372,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { &mut self, obligation: &TraitObligation<'tcx>, ) -> ImplSourceObjectData<'tcx, PredicateObligation<'tcx>> { + debug!(?obligation, "confirm_object_candidate"); let tcx = self.tcx(); - debug!("confirm_object_candidate({:?})", obligation); let trait_predicate = self.infcx.replace_bound_vars_with_placeholders(&obligation.predicate); @@ -507,7 +500,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } - debug!("confirm_object_candidate: nested: {:?}", nested); + debug!(?nested, "object nested obligations"); ImplSourceObjectData { upcast_trait_ref, vtable_base, nested } } @@ -516,7 +509,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation: &TraitObligation<'tcx>, ) -> Result<ImplSourceFnPointerData<'tcx, PredicateObligation<'tcx>>, SelectionError<'tcx>> { - debug!("confirm_fn_pointer_candidate({:?})", obligation); + debug!(?obligation, "confirm_fn_pointer_candidate"); // Okay to skip binder; it is reintroduced below. let self_ty = self.infcx.shallow_resolve(obligation.self_ty().skip_binder()); @@ -554,7 +547,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation: &TraitObligation<'tcx>, alias_def_id: DefId, ) -> ImplSourceTraitAliasData<'tcx, PredicateObligation<'tcx>> { - debug!("confirm_trait_alias_candidate({:?}, {:?})", obligation, alias_def_id); + debug!(?obligation, ?alias_def_id, "confirm_trait_alias_candidate"); self.infcx.commit_unconditionally(|_| { let predicate = @@ -571,10 +564,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { &substs, ); - debug!( - "confirm_trait_alias_candidate: trait_def_id={:?} trait_obligations={:?}", - trait_def_id, trait_obligations - ); + debug!(?trait_def_id, ?trait_obligations, "trait alias obligations"); ImplSourceTraitAliasData { alias_def_id, substs, nested: trait_obligations } }) @@ -594,7 +584,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { _ => bug!("closure candidate for non-closure {:?}", obligation), }; - debug!("confirm_generator_candidate({:?},{:?},{:?})", obligation, generator_def_id, substs); + debug!(?obligation, ?generator_def_id, ?substs, "confirm_generator_candidate"); let trait_ref = self.generator_trait_ref_unnormalized(obligation, substs); let Normalized { value: trait_ref, mut obligations } = ensure_sufficient_stack(|| { @@ -607,11 +597,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ) }); - debug!( - "confirm_generator_candidate(generator_def_id={:?}, \ - trait_ref={:?}, obligations={:?})", - generator_def_id, trait_ref, obligations - ); + debug!(?trait_ref, ?obligations, "generator candidate obligations"); obligations.extend(self.confirm_poly_trait_refs( obligation.cause.clone(), @@ -627,7 +613,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { &mut self, obligation: &TraitObligation<'tcx>, ) -> Result<ImplSourceClosureData<'tcx, PredicateObligation<'tcx>>, SelectionError<'tcx>> { - debug!("confirm_closure_candidate({:?})", obligation); + debug!(?obligation, "confirm_closure_candidate"); let kind = self .tcx() @@ -654,10 +640,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ) }); - debug!( - "confirm_closure_candidate(closure_def_id={:?}, trait_ref={:?}, obligations={:?})", - closure_def_id, trait_ref, obligations - ); + debug!(?closure_def_id, ?trait_ref, ?obligations, "confirm closure candidate obligations"); obligations.extend(self.confirm_poly_trait_refs( obligation.cause.clone(), @@ -731,7 +714,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let target = obligation.predicate.skip_binder().trait_ref.substs.type_at(1); let target = self.infcx.shallow_resolve(target); - debug!("confirm_builtin_unsize_candidate(source={:?}, target={:?})", source, target); + debug!(?source, ?target, "confirm_builtin_unsize_candidate"); let mut nested = vec![]; match (source.kind(), target.kind()) { diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index a142ba58a69..b838602e76c 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -236,7 +236,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { infcx: &'cx InferCtxt<'cx, 'tcx>, allow_negative_impls: bool, ) -> SelectionContext<'cx, 'tcx> { - debug!("with_negative({:?})", allow_negative_impls); + debug!(?allow_negative_impls, "with_negative"); SelectionContext { infcx, freshener: infcx.freshener(), @@ -251,7 +251,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { infcx: &'cx InferCtxt<'cx, 'tcx>, query_mode: TraitQueryMode, ) -> SelectionContext<'cx, 'tcx> { - debug!("with_query_mode({:?})", query_mode); + debug!(?query_mode, "with_query_mode"); SelectionContext { infcx, freshener: infcx.freshener(), @@ -290,10 +290,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { self.infcx.tcx } - pub fn closure_typer(&self) -> &'cx InferCtxt<'cx, 'tcx> { - self.infcx - } - /////////////////////////////////////////////////////////////////////////// // Selection // @@ -311,11 +307,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { /// Attempts to satisfy the obligation. If successful, this will affect the surrounding /// type environment by performing unification. + #[instrument(level = "debug", skip(self))] pub fn select( &mut self, obligation: &TraitObligation<'tcx>, ) -> SelectionResult<'tcx, Selection<'tcx>> { - debug!("select({:?})", obligation); debug_assert!(!obligation.predicate.has_escaping_bound_vars()); let pec = &ProvisionalEvaluationCache::default(); @@ -344,7 +340,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } Err(e) => Err(e), Ok(candidate) => { - debug!("select: candidate = {:?}", candidate); + debug!(?candidate); Ok(Some(candidate)) } } @@ -362,7 +358,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { /// Evaluates whether the obligation `obligation` can be satisfied (by any means). pub fn predicate_may_hold_fatal(&mut self, obligation: &PredicateObligation<'tcx>) -> bool { - debug!("predicate_may_hold_fatal({:?})", obligation); + debug!(?obligation, "predicate_may_hold_fatal"); // This fatal query is a stopgap that should only be used in standard mode, // where we do not expect overflow to be propagated. @@ -419,10 +415,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { I: IntoIterator<Item = PredicateObligation<'tcx>> + std::fmt::Debug, { let mut result = EvaluatedToOk; - debug!("evaluate_predicates_recursively({:?})", predicates); + debug!(?predicates, "evaluate_predicates_recursively"); for obligation in predicates { let eval = self.evaluate_predicate_recursively(stack, obligation.clone())?; - debug!("evaluate_predicate_recursively({:?}) = {:?}", obligation, eval); if let EvaluatedToErr = eval { // fast-path - EvaluatedToErr is the top of the lattice, // so we don't need to look on the other predicates. @@ -434,17 +429,16 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { Ok(result) } + #[instrument( + level = "debug", + skip(self, previous_stack), + fields(previous_stack = ?previous_stack.head()) + )] fn evaluate_predicate_recursively<'o>( &mut self, previous_stack: TraitObligationStackList<'o, 'tcx>, obligation: PredicateObligation<'tcx>, ) -> Result<EvaluationResult, OverflowError> { - debug!( - "evaluate_predicate_recursively(obligation={:?}, previous_stack={:?})", - obligation, - previous_stack.head() - ); - // `previous_stack` stores a `TraitObligation`, while `obligation` is // a `PredicateObligation`. These are distinct types, so we can't // use any `Option` combinator method that would force them to be @@ -454,17 +448,18 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { None => self.check_recursion_limit(&obligation, &obligation)?, } - ensure_sufficient_stack(|| { - match obligation.predicate.skip_binders() { + let result = ensure_sufficient_stack(|| { + let bound_predicate = obligation.predicate.bound_atom(); + match bound_predicate.skip_binder() { ty::PredicateAtom::Trait(t, _) => { - let t = ty::Binder::bind(t); + let t = bound_predicate.rebind(t); debug_assert!(!t.has_escaping_bound_vars()); let obligation = obligation.with(t); self.evaluate_trait_predicate_recursively(previous_stack, obligation) } ty::PredicateAtom::Subtype(p) => { - let p = ty::Binder::bind(p); + let p = bound_predicate.rebind(p); // Does this code ever run? match self.infcx.subtype_predicate(&obligation.cause, obligation.param_env, p) { Some(Ok(InferOk { mut obligations, .. })) => { @@ -508,7 +503,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } ty::PredicateAtom::Projection(data) => { - let data = ty::Binder::bind(data); + let data = bound_predicate.rebind(data); let project_obligation = obligation.with(data); match project::poly_project_and_unify_type(self, &project_obligation) { Ok(Ok(Some(mut subobligations))) => { @@ -561,10 +556,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } ty::PredicateAtom::ConstEquate(c1, c2) => { - debug!( - "evaluate_predicate_recursively: equating consts c1={:?} c2={:?}", - c1, c2 - ); + debug!(?c1, ?c2, "evaluate_predicate_recursively: equating consts"); let evaluate = |c: &'tcx ty::Const<'tcx>| { if let ty::ConstKind::Unevaluated(def, substs, promoted) = c.val { @@ -610,7 +602,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { bug!("TypeWellFormedFromEnv is only used for chalk") } } - }) + }); + + debug!(?result); + + result } fn evaluate_trait_predicate_recursively<'o>( @@ -618,7 +614,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { previous_stack: TraitObligationStackList<'o, 'tcx>, mut obligation: TraitObligation<'tcx>, ) -> Result<EvaluationResult, OverflowError> { - debug!("evaluate_trait_predicate_recursively({:?})", obligation); + debug!(?obligation, "evaluate_trait_predicate_recursively"); if !self.intercrate && obligation.is_global() @@ -627,19 +623,22 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // If a param env has no global bounds, global obligations do not // depend on its particular value in order to work, so we can clear // out the param env and get better caching. - debug!("evaluate_trait_predicate_recursively({:?}) - in global", obligation); + debug!("evaluate_trait_predicate_recursively - in global"); obligation.param_env = obligation.param_env.without_caller_bounds(); } let stack = self.push_stack(previous_stack, &obligation); let fresh_trait_ref = stack.fresh_trait_ref; + + debug!(?fresh_trait_ref); + if let Some(result) = self.check_evaluation_cache(obligation.param_env, fresh_trait_ref) { - debug!("CACHE HIT: EVAL({:?})={:?}", fresh_trait_ref, result); + debug!(?result, "CACHE HIT"); return Ok(result); } if let Some(result) = stack.cache().get_provisional(fresh_trait_ref) { - debug!("PROVISIONAL CACHE HIT: EVAL({:?})={:?}", fresh_trait_ref, result); + debug!(?result, "PROVISIONAL CACHE HIT"); stack.update_reached_depth(stack.cache().current_reached_depth()); return Ok(result); } @@ -662,7 +661,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let reached_depth = stack.reached_depth.get(); if reached_depth >= stack.depth { - debug!("CACHE MISS: EVAL({:?})={:?}", fresh_trait_ref, result); + debug!(?result, "CACHE MISS"); self.insert_evaluation_cache(obligation.param_env, fresh_trait_ref, dep_node, result); stack.cache().on_completion(stack.depth, |fresh_trait_ref, provisional_result| { @@ -674,7 +673,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ); }); } else { - debug!("PROVISIONAL: {:?}={:?}", fresh_trait_ref, result); + debug!(?result, "PROVISIONAL"); debug!( "evaluate_trait_predicate_recursively: caching provisionally because {:?} \ is a cycle participant (at depth {}, reached depth {})", @@ -719,10 +718,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { }) .map(|stack| stack.depth) { - debug!( - "evaluate_stack({:?}) --> recursive at depth {}", - stack.fresh_trait_ref, cycle_depth, - ); + debug!("evaluate_stack --> recursive at depth {}", cycle_depth); // If we have a stack like `A B C D E A`, where the top of // the stack is the final `A`, then this will iterate over @@ -742,10 +738,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let cycle = cycle.map(|stack| stack.obligation.predicate.without_const().to_predicate(tcx)); if self.coinductive_match(cycle) { - debug!("evaluate_stack({:?}) --> recursive, coinductive", stack.fresh_trait_ref); + debug!("evaluate_stack --> recursive, coinductive"); Some(EvaluatedToOk) } else { - debug!("evaluate_stack({:?}) --> recursive, inductive", stack.fresh_trait_ref); + debug!("evaluate_stack --> recursive, inductive"); Some(EvaluatedToRecur) } } else { @@ -786,10 +782,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // This check was an imperfect workaround for a bug in the old // intercrate mode; it should be removed when that goes away. if unbound_input_types && self.intercrate { - debug!( - "evaluate_stack({:?}) --> unbound argument, intercrate --> ambiguous", - stack.fresh_trait_ref - ); + debug!("evaluate_stack --> unbound argument, intercrate --> ambiguous",); // Heuristics: show the diagnostics when there are no candidates in crate. if self.intercrate_ambiguity_causes.is_some() { debug!("evaluate_stack: intercrate_ambiguity_causes is some"); @@ -807,7 +800,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { }, }); - debug!("evaluate_stack: pushing cause = {:?}", cause); + debug!(?cause, "evaluate_stack: pushing cause"); self.intercrate_ambiguity_causes.as_mut().unwrap().push(cause); } } @@ -824,10 +817,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ) }) { - debug!( - "evaluate_stack({:?}) --> unbound argument, recursive --> giving up", - stack.fresh_trait_ref - ); + debug!("evaluate_stack --> unbound argument, recursive --> giving up",); return Ok(EvaluatedToUnknown); } @@ -860,27 +850,28 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ty::PredicateAtom::Trait(ref data, _) => self.tcx().trait_is_auto(data.def_id()), _ => false, }; - debug!("coinductive_predicate({:?}) = {:?}", predicate, result); + debug!(?predicate, ?result, "coinductive_predicate"); result } /// Further evaluates `candidate` to decide whether all type parameters match and whether nested /// obligations are met. Returns whether `candidate` remains viable after this further /// scrutiny. + #[instrument( + level = "debug", + skip(self, stack), + fields(depth = stack.obligation.recursion_depth) + )] fn evaluate_candidate<'o>( &mut self, stack: &TraitObligationStack<'o, 'tcx>, candidate: &SelectionCandidate<'tcx>, ) -> Result<EvaluationResult, OverflowError> { - debug!( - "evaluate_candidate: depth={} candidate={:?}", - stack.obligation.recursion_depth, candidate - ); let result = self.evaluation_probe(|this| { let candidate = (*candidate).clone(); match this.confirm_candidate(stack.obligation, candidate) { Ok(selection) => { - debug!("evaluate_candidate: selection = {:?}", selection); + debug!(?selection); this.evaluate_predicates_recursively( stack.list(), selection.nested_obligations().into_iter(), @@ -889,10 +880,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { Err(..) => Ok(EvaluatedToErr), } })?; - debug!( - "evaluate_candidate: depth={} result={:?}", - stack.obligation.recursion_depth, result - ); + debug!(?result); Ok(result) } @@ -925,10 +913,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { if self.can_use_global_caches(param_env) { if !trait_ref.needs_infer() { - debug!( - "insert_evaluation_cache(trait_ref={:?}, candidate={:?}) global", - trait_ref, result, - ); + debug!(?trait_ref, ?result, "insert_evaluation_cache global"); // This may overwrite the cache with the same value // FIXME: Due to #50507 this overwrites the different values // This should be changed to use HashMapExt::insert_same @@ -938,7 +923,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } - debug!("insert_evaluation_cache(trait_ref={:?}, candidate={:?})", trait_ref, result,); + debug!(?trait_ref, ?result, "insert_evaluation_cache"); self.infcx.evaluation_cache.insert(param_env.and(trait_ref), dep_node, result); } @@ -1127,11 +1112,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let trait_ref = cache_fresh_trait_pred.skip_binder().trait_ref; if !self.can_cache_candidate(&candidate) { - debug!( - "insert_candidate_cache(trait_ref={:?}, candidate={:?} -\ - candidate is not cacheable", - trait_ref, candidate - ); + debug!(?trait_ref, ?candidate, "insert_candidate_cache - candidate is not cacheable"); return; } @@ -1140,10 +1121,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // Don't cache overflow globally; we only produce this in certain modes. } else if !trait_ref.needs_infer() { if !candidate.needs_infer() { - debug!( - "insert_candidate_cache(trait_ref={:?}, candidate={:?}) global", - trait_ref, candidate, - ); + debug!(?trait_ref, ?candidate, "insert_candidate_cache global"); // This may overwrite the cache with the same value. tcx.selection_cache.insert(param_env.and(trait_ref), dep_node, candidate); return; @@ -1151,10 +1129,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } - debug!( - "insert_candidate_cache(trait_ref={:?}, candidate={:?}) local", - trait_ref, candidate, - ); + debug!(?trait_ref, ?candidate, "insert_candidate_cache local"); self.infcx.selection_cache.insert(param_env.and(trait_ref), dep_node, candidate); } @@ -1172,9 +1147,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let placeholder_trait_predicate = self.infcx().replace_bound_vars_with_placeholders(&poly_trait_predicate); debug!( - "match_projection_obligation_against_definition_bounds: \ - placeholder_trait_predicate={:?}", - placeholder_trait_predicate, + ?placeholder_trait_predicate, + "match_projection_obligation_against_definition_bounds" ); let tcx = self.infcx.tcx; @@ -1201,8 +1175,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { .iter() .enumerate() .filter_map(|(idx, bound)| { - if let ty::PredicateAtom::Trait(pred, _) = bound.skip_binders() { - let bound = ty::Binder::bind(pred.trait_ref); + let bound_predicate = bound.bound_atom(); + if let ty::PredicateAtom::Trait(pred, _) = bound_predicate.skip_binder() { + let bound = bound_predicate.rebind(pred.trait_ref); if self.infcx.probe(|_| { match self.match_projection( obligation, @@ -1225,11 +1200,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { }) .collect(); - debug!( - "match_projection_obligation_against_definition_bounds: \ - matching_bounds={:?}", - matching_bounds - ); + debug!(?matching_bounds, "match_projection_obligation_against_definition_bounds"); matching_bounds } @@ -1560,16 +1531,20 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ty::Str | ty::Slice(_) | ty::Dynamic(..) | ty::Foreign(..) => None, - ty::Tuple(tys) => { - Where(ty::Binder::bind(tys.last().into_iter().map(|k| k.expect_ty()).collect())) - } + ty::Tuple(tys) => Where( + obligation + .predicate + .rebind(tys.last().into_iter().map(|k| k.expect_ty()).collect()), + ), ty::Adt(def, substs) => { let sized_crit = def.sized_constraint(self.tcx()); // (*) binder moved here - Where(ty::Binder::bind( - sized_crit.iter().map(|ty| ty.subst(self.tcx(), substs)).collect(), - )) + Where( + obligation.predicate.rebind({ + sized_crit.iter().map(|ty| ty.subst(self.tcx(), substs)).collect() + }), + ) } ty::Projection(_) | ty::Param(_) | ty::Opaque(..) => None, @@ -1592,7 +1567,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { use self::BuiltinImplConditions::{Ambiguous, None, Where}; - match self_ty.kind() { + match *self_ty.kind() { ty::Infer(ty::IntVar(_)) | ty::Infer(ty::FloatVar(_)) | ty::FnDef(..) @@ -1621,17 +1596,23 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ty::Array(element_ty, _) => { // (*) binder moved here - Where(ty::Binder::bind(vec![element_ty])) + Where(obligation.predicate.rebind(vec![element_ty])) } ty::Tuple(tys) => { // (*) binder moved here - Where(ty::Binder::bind(tys.iter().map(|k| k.expect_ty()).collect())) + Where(obligation.predicate.rebind(tys.iter().map(|k| k.expect_ty()).collect())) } ty::Closure(_, substs) => { // (*) binder moved here - Where(ty::Binder::bind(substs.as_closure().upvar_tys().collect())) + let ty = self.infcx.shallow_resolve(substs.as_closure().tupled_upvars_ty()); + if let ty::Infer(ty::TyVar(_)) = ty.kind() { + // Not yet resolved. + Ambiguous + } else { + Where(obligation.predicate.rebind(substs.as_closure().upvar_tys().collect())) + } } ty::Adt(..) | ty::Projection(..) | ty::Param(..) | ty::Opaque(..) => { @@ -1700,11 +1681,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { tys.iter().map(|k| k.expect_ty()).collect() } - ty::Closure(_, ref substs) => substs.as_closure().upvar_tys().collect(), + ty::Closure(_, ref substs) => { + let ty = self.infcx.shallow_resolve(substs.as_closure().tupled_upvars_ty()); + vec![ty] + } ty::Generator(_, ref substs, _) => { + let ty = self.infcx.shallow_resolve(substs.as_generator().tupled_upvars_ty()); let witness = substs.as_generator().witness(); - substs.as_generator().upvar_tys().chain(iter::once(witness)).collect() + vec![ty].into_iter().chain(iter::once(witness)).collect() } ty::GeneratorWitness(types) => { @@ -1816,6 +1801,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { impl_def_id: DefId, obligation: &TraitObligation<'tcx>, ) -> Result<Normalized<'tcx, SubstsRef<'tcx>>, ()> { + debug!(?impl_def_id, ?obligation, "match_impl"); let impl_trait_ref = self.tcx().impl_trait_ref(impl_def_id).unwrap(); // Before we create the substitutions and everything, first @@ -1844,11 +1830,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ) }); - debug!( - "match_impl(impl_def_id={:?}, obligation={:?}, \ - impl_trait_ref={:?}, placeholder_obligation_trait_ref={:?})", - impl_def_id, obligation, impl_trait_ref, placeholder_obligation_trait_ref - ); + debug!(?impl_trait_ref, ?placeholder_obligation_trait_ref); let InferOk { obligations, .. } = self .infcx @@ -1864,7 +1846,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { return Err(()); } - debug!("match_impl: success impl_substs={:?}", impl_substs); + debug!(?impl_substs, "match_impl: success"); Ok(Normalized { value: impl_substs, obligations: nested_obligations }) } @@ -1926,10 +1908,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation: &TraitObligation<'tcx>, poly_trait_ref: ty::PolyTraitRef<'tcx>, ) -> Result<Vec<PredicateObligation<'tcx>>, ()> { - debug!( - "match_poly_trait_ref: obligation={:?} poly_trait_ref={:?}", - obligation, poly_trait_ref - ); + debug!(?obligation, ?poly_trait_ref, "match_poly_trait_ref"); self.infcx .at(&obligation.cause, obligation.param_env) @@ -1976,10 +1955,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation: &TraitObligation<'tcx>, substs: SubstsRef<'tcx>, ) -> ty::PolyTraitRef<'tcx> { - debug!("closure_trait_ref_unnormalized(obligation={:?}, substs={:?})", obligation, substs); + debug!(?obligation, ?substs, "closure_trait_ref_unnormalized"); let closure_sig = substs.as_closure().sig(); - debug!("closure_trait_ref_unnormalized: closure_sig = {:?}", closure_sig); + debug!(?closure_sig); // (1) Feels icky to skip the binder here, but OTOH we know // that the self-type is an unboxed closure type and hence is @@ -2030,7 +2009,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { def_id: DefId, // of impl or trait substs: SubstsRef<'tcx>, // for impl or trait ) -> Vec<PredicateObligation<'tcx>> { - debug!("impl_or_trait_obligations(def_id={:?})", def_id); + debug!(?def_id, "impl_or_trait_obligations"); let tcx = self.tcx(); // To allow for one-pass evaluation of the nested obligation, @@ -2152,10 +2131,10 @@ impl<'o, 'tcx> TraitObligationStack<'o, 'tcx> { self.depth, reached_depth, ); - debug!("update_reached_depth(reached_depth={})", reached_depth); + debug!(reached_depth, "update_reached_depth"); let mut p = self; while reached_depth < p.depth { - debug!("update_reached_depth: marking {:?} as cycle participant", p.fresh_trait_ref); + debug!(?p.fresh_trait_ref, "update_reached_depth: marking as cycle participant"); p.reached_depth.set(p.reached_depth.get().min(reached_depth)); p = p.previous.head.unwrap(); } @@ -2282,10 +2261,10 @@ impl<'tcx> ProvisionalEvaluationCache<'tcx> { /// `self.current_reached_depth()` and above. fn get_provisional(&self, fresh_trait_ref: ty::PolyTraitRef<'tcx>) -> Option<EvaluationResult> { debug!( - "get_provisional(fresh_trait_ref={:?}) = {:#?} with reached-depth {}", - fresh_trait_ref, + ?fresh_trait_ref, + reached_depth = ?self.reached_depth.get(), + "get_provisional = {:#?}", self.map.borrow().get(&fresh_trait_ref), - self.reached_depth.get(), ); Some(self.map.borrow().get(&fresh_trait_ref)?.result) } @@ -2308,14 +2287,11 @@ impl<'tcx> ProvisionalEvaluationCache<'tcx> { fresh_trait_ref: ty::PolyTraitRef<'tcx>, result: EvaluationResult, ) { - debug!( - "insert_provisional(from_dfn={}, reached_depth={}, fresh_trait_ref={:?}, result={:?})", - from_dfn, reached_depth, fresh_trait_ref, result, - ); + debug!(?from_dfn, ?reached_depth, ?fresh_trait_ref, ?result, "insert_provisional"); let r_d = self.reached_depth.get(); self.reached_depth.set(r_d.min(reached_depth)); - debug!("insert_provisional: reached_depth={:?}", self.reached_depth.get()); + debug!(reached_depth = self.reached_depth.get()); self.map.borrow_mut().insert(fresh_trait_ref, ProvisionalEvaluation { from_dfn, result }); } @@ -2329,7 +2305,7 @@ impl<'tcx> ProvisionalEvaluationCache<'tcx> { /// these provisional entries must either depend on it or some /// ancestor of it. fn on_failure(&self, dfn: usize) { - debug!("on_failure(dfn={:?})", dfn,); + debug!(?dfn, "on_failure"); self.map.borrow_mut().retain(|key, eval| { if !eval.from_dfn >= dfn { debug!("on_failure: removing {:?}", key); @@ -2350,7 +2326,7 @@ impl<'tcx> ProvisionalEvaluationCache<'tcx> { depth: usize, mut op: impl FnMut(ty::PolyTraitRef<'tcx>, EvaluationResult), ) { - debug!("on_completion(depth={}, reached_depth={})", depth, self.reached_depth.get(),); + debug!(?depth, reached_depth = ?self.reached_depth.get(), "on_completion"); if self.reached_depth.get() < depth { debug!("on_completion: did not yet reach depth to complete"); @@ -2358,7 +2334,7 @@ impl<'tcx> ProvisionalEvaluationCache<'tcx> { } for (fresh_trait_ref, eval) in self.map.borrow_mut().drain() { - debug!("on_completion: fresh_trait_ref={:?} eval={:?}", fresh_trait_ref, eval,); + debug!(?fresh_trait_ref, ?eval, "on_completion"); op(fresh_trait_ref, eval.result); } diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index d66bfd48206..496dff6c5b2 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -592,10 +592,8 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { // anyway, except via auto trait matching (which // only inspects the upvar types). walker.skip_current_subtree(); // subtree handled below - for upvar_ty in substs.as_closure().upvar_tys() { - // FIXME(eddyb) add the type to `walker` instead of recursing. - self.compute(upvar_ty.into()); - } + // FIXME(eddyb) add the type to `walker` instead of recursing. + self.compute(substs.as_closure().tupled_upvars_ty().into()); } ty::FnPtr(_) => { diff --git a/compiler/rustc_traits/src/chalk/lowering.rs b/compiler/rustc_traits/src/chalk/lowering.rs index 391251b6fa5..5ca0fc0c88b 100644 --- a/compiler/rustc_traits/src/chalk/lowering.rs +++ b/compiler/rustc_traits/src/chalk/lowering.rs @@ -81,8 +81,11 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::InEnvironment<chalk_ir::Goal<RustInterner<' interner: &RustInterner<'tcx>, ) -> chalk_ir::InEnvironment<chalk_ir::Goal<RustInterner<'tcx>>> { let clauses = self.environment.into_iter().map(|predicate| { - let (predicate, binders, _named_regions) = - collect_bound_vars(interner, interner.tcx, &predicate.bound_atom(interner.tcx)); + let (predicate, binders, _named_regions) = collect_bound_vars( + interner, + interner.tcx, + &predicate.bound_atom_with_opt_escaping(interner.tcx), + ); let consequence = match predicate { ty::PredicateAtom::TypeWellFormedFromEnv(ty) => { chalk_ir::DomainGoal::FromEnv(chalk_ir::FromEnv::Ty(ty.lower_into(interner))) @@ -133,8 +136,11 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::InEnvironment<chalk_ir::Goal<RustInterner<' impl<'tcx> LowerInto<'tcx, chalk_ir::GoalData<RustInterner<'tcx>>> for ty::Predicate<'tcx> { fn lower_into(self, interner: &RustInterner<'tcx>) -> chalk_ir::GoalData<RustInterner<'tcx>> { - let (predicate, binders, _named_regions) = - collect_bound_vars(interner, interner.tcx, &self.bound_atom(interner.tcx)); + let (predicate, binders, _named_regions) = collect_bound_vars( + interner, + interner.tcx, + &self.bound_atom_with_opt_escaping(interner.tcx), + ); let value = match predicate { ty::PredicateAtom::Trait(predicate, _) => { @@ -653,8 +659,11 @@ impl<'tcx> LowerInto<'tcx, Option<chalk_ir::QuantifiedWhereClause<RustInterner<' self, interner: &RustInterner<'tcx>, ) -> Option<chalk_ir::QuantifiedWhereClause<RustInterner<'tcx>>> { - let (predicate, binders, _named_regions) = - collect_bound_vars(interner, interner.tcx, &self.bound_atom(interner.tcx)); + let (predicate, binders, _named_regions) = collect_bound_vars( + interner, + interner.tcx, + &self.bound_atom_with_opt_escaping(interner.tcx), + ); let value = match predicate { ty::PredicateAtom::Trait(predicate, _) => { Some(chalk_ir::WhereClause::Implemented(predicate.trait_ref.lower_into(interner))) @@ -762,27 +771,22 @@ impl<'tcx> LowerInto<'tcx, Option<chalk_solve::rust_ir::QuantifiedInlineBound<Ru self, interner: &RustInterner<'tcx>, ) -> Option<chalk_solve::rust_ir::QuantifiedInlineBound<RustInterner<'tcx>>> { - match self.bound_atom(interner.tcx).skip_binder() { - ty::PredicateAtom::Trait(predicate, _) => { - let (predicate, binders, _named_regions) = - collect_bound_vars(interner, interner.tcx, &ty::Binder::bind(predicate)); - - Some(chalk_ir::Binders::new( - binders, - chalk_solve::rust_ir::InlineBound::TraitBound( - predicate.trait_ref.lower_into(interner), - ), - )) - } - ty::PredicateAtom::Projection(predicate) => { - let (predicate, binders, _named_regions) = - collect_bound_vars(interner, interner.tcx, &ty::Binder::bind(predicate)); - - Some(chalk_ir::Binders::new( - binders, - chalk_solve::rust_ir::InlineBound::AliasEqBound(predicate.lower_into(interner)), - )) - } + let (predicate, binders, _named_regions) = collect_bound_vars( + interner, + interner.tcx, + &self.bound_atom_with_opt_escaping(interner.tcx), + ); + match predicate { + ty::PredicateAtom::Trait(predicate, _) => Some(chalk_ir::Binders::new( + binders, + chalk_solve::rust_ir::InlineBound::TraitBound( + predicate.trait_ref.lower_into(interner), + ), + )), + ty::PredicateAtom::Projection(predicate) => Some(chalk_ir::Binders::new( + binders, + chalk_solve::rust_ir::InlineBound::AliasEqBound(predicate.lower_into(interner)), + )), ty::PredicateAtom::TypeOutlives(_predicate) => None, ty::PredicateAtom::WellFormed(_ty) => None, diff --git a/compiler/rustc_traits/src/dropck_outlives.rs b/compiler/rustc_traits/src/dropck_outlives.rs index 3ee391d6dc7..6cffa6d02a4 100644 --- a/compiler/rustc_traits/src/dropck_outlives.rs +++ b/compiler/rustc_traits/src/dropck_outlives.rs @@ -210,12 +210,25 @@ fn dtorck_constraint_for_ty<'tcx>( Ok::<_, NoSolution>(()) })?, - ty::Closure(_, substs) => rustc_data_structures::stack::ensure_sufficient_stack(|| { - for ty in substs.as_closure().upvar_tys() { - dtorck_constraint_for_ty(tcx, span, for_ty, depth + 1, ty, constraints)?; + ty::Closure(_, substs) => { + if !substs.as_closure().is_valid() { + // By the time this code runs, all type variables ought to + // be fully resolved. + + tcx.sess.delay_span_bug( + span, + &format!("upvar_tys for closure not found. Expected capture information for closure {}", ty,), + ); + return Err(NoSolution); } - Ok::<_, NoSolution>(()) - })?, + + rustc_data_structures::stack::ensure_sufficient_stack(|| { + for ty in substs.as_closure().upvar_tys() { + dtorck_constraint_for_ty(tcx, span, for_ty, depth + 1, ty, constraints)?; + } + Ok::<_, NoSolution>(()) + })? + } ty::Generator(_, substs, _movability) => { // rust-lang/rust#49918: types can be constructed, stored @@ -241,6 +254,16 @@ fn dtorck_constraint_for_ty<'tcx>( // derived from lifetimes attached to the upvars and resume // argument, and we *do* incorporate those here. + if !substs.as_generator().is_valid() { + // By the time this code runs, all type variables ought to + // be fully resolved. + tcx.sess.delay_span_bug( + span, + &format!("upvar_tys for generator not found. Expected capture information for generator {}", ty,), + ); + return Err(NoSolution); + } + constraints.outlives.extend( substs .as_generator() diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs index 170ca2ce744..07e523af3eb 100644 --- a/compiler/rustc_typeck/src/astconv/mod.rs +++ b/compiler/rustc_typeck/src/astconv/mod.rs @@ -1095,9 +1095,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { obligation.predicate ); - match obligation.predicate.skip_binders() { + let bound_predicate = obligation.predicate.bound_atom(); + match bound_predicate.skip_binder() { ty::PredicateAtom::Trait(pred, _) => { - let pred = ty::Binder::bind(pred); + let pred = bound_predicate.rebind(pred); associated_types.entry(span).or_default().extend( tcx.associated_items(pred.def_id()) .in_definition_order() @@ -1106,7 +1107,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { ); } ty::PredicateAtom::Projection(pred) => { - let pred = ty::Binder::bind(pred); + let pred = bound_predicate.rebind(pred); // A `Self` within the original bound will be substituted with a // `trait_object_dummy_self`, so check for that. let references_self = diff --git a/compiler/rustc_typeck/src/bounds.rs b/compiler/rustc_typeck/src/bounds.rs index 80f39051c58..683707470f4 100644 --- a/compiler/rustc_typeck/src/bounds.rs +++ b/compiler/rustc_typeck/src/bounds.rs @@ -72,7 +72,7 @@ impl<'tcx> Bounds<'tcx> { .iter() .map(|&(region_bound, span)| { let outlives = ty::OutlivesPredicate(param_ty, region_bound); - (ty::Binder::dummy(outlives).to_predicate(tcx), span) + (ty::Binder::bind(outlives).to_predicate(tcx), span) }) .chain(self.trait_bounds.iter().map(|&(bound_trait_ref, span, constness)| { let predicate = bound_trait_ref.with_constness(constness).to_predicate(tcx); diff --git a/compiler/rustc_typeck/src/check/callee.rs b/compiler/rustc_typeck/src/check/callee.rs index 740783aeb9d..a38fb9642b9 100644 --- a/compiler/rustc_typeck/src/check/callee.rs +++ b/compiler/rustc_typeck/src/check/callee.rs @@ -285,10 +285,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { arg_exprs: &'tcx [hir::Expr<'tcx>], expected: Expectation<'tcx>, ) -> Ty<'tcx> { - let (fn_sig, def_span) = match *callee_ty.kind() { - ty::FnDef(def_id, _) => { - (callee_ty.fn_sig(self.tcx), self.tcx.hir().span_if_local(def_id)) - } + let (fn_sig, def_id) = match *callee_ty.kind() { + ty::FnDef(def_id, _) => (callee_ty.fn_sig(self.tcx), Some(def_id)), ty::FnPtr(sig) => (sig, None), ref t => { let mut unit_variant = None; @@ -427,7 +425,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { arg_exprs, fn_sig.c_variadic, TupleArgumentsFlag::DontTupleArguments, - def_span, + def_id, ); fn_sig.output() diff --git a/compiler/rustc_typeck/src/check/check.rs b/compiler/rustc_typeck/src/check/check.rs index d319ac2cba6..3d8653b4a6a 100644 --- a/compiler/rustc_typeck/src/check/check.rs +++ b/compiler/rustc_typeck/src/check/check.rs @@ -29,7 +29,7 @@ pub fn check_wf_new(tcx: TyCtxt<'_>) { } pub(super) fn check_abi(tcx: TyCtxt<'_>, span: Span, abi: Abi) { - if !tcx.sess.target.target.is_abi_supported(abi) { + if !tcx.sess.target.is_abi_supported(abi) { struct_span_err!( tcx.sess, span, @@ -348,8 +348,7 @@ pub(super) fn check_union(tcx: TyCtxt<'_>, id: hir::HirId, span: Span) { check_packed(tcx, span, def); } -/// When the `#![feature(untagged_unions)]` gate is active, -/// check that the fields of the `union` does not contain fields that need dropping. +/// Check that the fields of the `union` do not need dropping. pub(super) fn check_union_fields(tcx: TyCtxt<'_>, span: Span, item_def_id: LocalDefId) -> bool { let item_type = tcx.type_of(item_def_id); if let ty::Adt(def, substs) = item_type.kind() { diff --git a/compiler/rustc_typeck/src/check/closure.rs b/compiler/rustc_typeck/src/check/closure.rs index 8898a545228..8cd83c39f9e 100644 --- a/compiler/rustc_typeck/src/check/closure.rs +++ b/compiler/rustc_typeck/src/check/closure.rs @@ -81,19 +81,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.tcx.closure_base_def_id(expr_def_id.to_def_id()), ); - let tupled_upvars_ty = - self.tcx.mk_tup(self.tcx.upvars_mentioned(expr_def_id).iter().flat_map(|upvars| { - upvars.iter().map(|(&var_hir_id, _)| { - // Create type variables (for now) to represent the transformed - // types of upvars. These will be unified during the upvar - // inference phase (`upvar.rs`). - self.infcx.next_ty_var(TypeVariableOrigin { - // FIXME(eddyb) distinguish upvar inference variables from the rest. - kind: TypeVariableOriginKind::ClosureSynthetic, - span: self.tcx.hir().span(var_hir_id), - }) - }) - })); + let tupled_upvars_ty = self.infcx.next_ty_var(TypeVariableOrigin { + kind: TypeVariableOriginKind::ClosureSynthetic, + span: self.tcx.hir().span(expr.hir_id), + }); if let Some(GeneratorTypes { resume_ty, yield_ty, interior, movability }) = generator_types { @@ -201,6 +192,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { obligation.predicate ); + let bound_predicate = obligation.predicate.bound_atom(); if let ty::PredicateAtom::Projection(proj_predicate) = obligation.predicate.skip_binders() { @@ -208,7 +200,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // the complete signature. self.deduce_sig_from_projection( Some(obligation.cause.span), - ty::Binder::bind(proj_predicate), + bound_predicate.rebind(proj_predicate), ) } else { None diff --git a/compiler/rustc_typeck/src/check/coercion.rs b/compiler/rustc_typeck/src/check/coercion.rs index 4addee1a4c9..c1485e3baf6 100644 --- a/compiler/rustc_typeck/src/check/coercion.rs +++ b/compiler/rustc_typeck/src/check/coercion.rs @@ -39,6 +39,7 @@ use crate::astconv::AstConv; use crate::check::FnCtxt; use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder}; use rustc_hir as hir; +use rustc_hir::def_id::DefId; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_infer::infer::{Coercion, InferOk, InferResult}; use rustc_middle::ty::adjustment::{ @@ -221,11 +222,11 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { // unsafe qualifier. self.coerce_from_fn_pointer(a, a_f, b) } - ty::Closure(_, substs_a) => { + ty::Closure(closure_def_id_a, substs_a) => { // Non-capturing closures are coercible to // function pointers or unsafe function pointers. // It cannot convert closures that require unsafe. - self.coerce_closure_to_fn(a, substs_a, b) + self.coerce_closure_to_fn(a, closure_def_id_a, substs_a, b) } _ => { // Otherwise, just use unification rules. @@ -582,7 +583,8 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { while !queue.is_empty() { let obligation = queue.remove(0); debug!("coerce_unsized resolve step: {:?}", obligation); - let trait_pred = match obligation.predicate.skip_binders() { + let bound_predicate = obligation.predicate.bound_atom(); + let trait_pred = match bound_predicate.skip_binder() { ty::PredicateAtom::Trait(trait_pred, _) if traits.contains(&trait_pred.def_id()) => { @@ -593,7 +595,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { has_unsized_tuple_coercion = true; } } - ty::Binder::bind(trait_pred) + bound_predicate.rebind(trait_pred) } _ => { coercion.obligations.push(obligation); @@ -762,6 +764,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { fn coerce_closure_to_fn( &self, a: Ty<'tcx>, + closure_def_id_a: DefId, substs_a: SubstsRef<'tcx>, b: Ty<'tcx>, ) -> CoerceResult<'tcx> { @@ -772,7 +775,18 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { let b = self.shallow_resolve(b); match b.kind() { - ty::FnPtr(fn_ty) if substs_a.as_closure().upvar_tys().next().is_none() => { + // At this point we haven't done capture analysis, which means + // that the ClosureSubsts just contains an inference variable instead + // of tuple of captured types. + // + // All we care here is if any variable is being captured and not the exact paths, + // so we check `upvars_mentioned` for root variables being captured. + ty::FnPtr(fn_ty) + if self + .tcx + .upvars_mentioned(closure_def_id_a.expect_local()) + .map_or(true, |u| u.is_empty()) => + { // We coerce the closure, which has fn type // `extern "rust-call" fn((arg0,arg1,...)) -> _` // to @@ -906,8 +920,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Function items or non-capturing closures of differing IDs or InternalSubsts. let (a_sig, b_sig) = { let is_capturing_closure = |ty| { - if let &ty::Closure(_, substs) = ty { - substs.as_closure().upvar_tys().next().is_some() + if let &ty::Closure(closure_def_id, _substs) = ty { + self.tcx.upvars_mentioned(closure_def_id.expect_local()).is_some() } else { false } diff --git a/compiler/rustc_typeck/src/check/demand.rs b/compiler/rustc_typeck/src/check/demand.rs index 3e66885448b..b8143787a2d 100644 --- a/compiler/rustc_typeck/src/check/demand.rs +++ b/compiler/rustc_typeck/src/check/demand.rs @@ -751,8 +751,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - let msg = format!("you can convert an `{}` to `{}`", checked_ty, expected_ty); - let cast_msg = format!("you can cast an `{} to `{}`", checked_ty, expected_ty); + let msg = format!( + "you can convert {} `{}` to {} `{}`", + checked_ty.kind().article(), + checked_ty, + expected_ty.kind().article(), + expected_ty, + ); + let cast_msg = format!( + "you can cast {} `{}` to {} `{}`", + checked_ty.kind().article(), + checked_ty, + expected_ty.kind().article(), + expected_ty, + ); let lit_msg = format!( "change the type of the numeric literal from `{}` to `{}`", checked_ty, expected_ty, @@ -814,7 +826,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let suggestion = format!("{}::from({})", checked_ty, lhs_src); (lhs_expr.span, msg, suggestion) } else { - let msg = format!("{} and panic if the converted value wouldn't fit", msg); + let msg = format!("{} and panic if the converted value doesn't fit", msg); let suggestion = format!("{}{}.try_into().unwrap()", prefix, with_opt_paren(&src)); (expr.span, msg, suggestion) diff --git a/compiler/rustc_typeck/src/check/dropck.rs b/compiler/rustc_typeck/src/check/dropck.rs index ae94a6df5fd..5650b2cdd3c 100644 --- a/compiler/rustc_typeck/src/check/dropck.rs +++ b/compiler/rustc_typeck/src/check/dropck.rs @@ -226,12 +226,14 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>( // could be extended easily also to the other `Predicate`. let predicate_matches_closure = |p: Predicate<'tcx>| { let mut relator: SimpleEqRelation<'tcx> = SimpleEqRelation::new(tcx, self_param_env); - match (predicate.skip_binders(), p.skip_binders()) { + let predicate = predicate.bound_atom(); + let p = p.bound_atom(); + match (predicate.skip_binder(), p.skip_binder()) { (ty::PredicateAtom::Trait(a, _), ty::PredicateAtom::Trait(b, _)) => { - relator.relate(ty::Binder::bind(a), ty::Binder::bind(b)).is_ok() + relator.relate(predicate.rebind(a), p.rebind(b)).is_ok() } (ty::PredicateAtom::Projection(a), ty::PredicateAtom::Projection(b)) => { - relator.relate(ty::Binder::bind(a), ty::Binder::bind(b)).is_ok() + relator.relate(predicate.rebind(a), p.rebind(b)).is_ok() } _ => predicate == p, } diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs index 179e383be2e..9990f86a36b 100644 --- a/compiler/rustc_typeck/src/check/expr.rs +++ b/compiler/rustc_typeck/src/check/expr.rs @@ -286,6 +286,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } ExprKind::DropTemps(ref e) => self.check_expr_with_expectation(e, expected), ExprKind::Array(ref args) => self.check_expr_array(args, expected, expr), + ExprKind::ConstBlock(ref anon_const) => self.to_const(anon_const).ty, ExprKind::Repeat(ref element, ref count) => { self.check_expr_repeat(element, count, expected, expr) } diff --git a/compiler/rustc_typeck/src/check/fn_ctxt.rs b/compiler/rustc_typeck/src/check/fn_ctxt.rs deleted file mode 100644 index 79d6c7dbfda..00000000000 --- a/compiler/rustc_typeck/src/check/fn_ctxt.rs +++ /dev/null @@ -1,3200 +0,0 @@ -// ignore-tidy-filelength -// FIXME: This file seems to have too much functionality wrapped into it, -// leading to it being too long. -// Splitting this file may involve abstracting functionality into other files. - -use super::callee::{self, DeferredCallResolution}; -use super::coercion::{CoerceMany, DynamicCoerceMany}; -use super::method::{self, MethodCallee, SelfSource}; -use super::Expectation::*; -use super::TupleArgumentsFlag::*; -use super::{ - potentially_plural_count, struct_span_err, BreakableCtxt, Diverges, EnclosingBreakables, - Expectation, FallbackMode, Inherited, LocalTy, Needs, TupleArgumentsFlag, UnsafetyState, -}; -use crate::astconv::{ - AstConv, ExplicitLateBound, GenericArgCountMismatch, GenericArgCountResult, PathSeg, -}; - -use rustc_ast as ast; -use rustc_ast::util::parser::ExprPrecedence; -use rustc_data_structures::captures::Captures; -use rustc_data_structures::fx::FxHashSet; -use rustc_errors::ErrorReported; -use rustc_errors::{Applicability, DiagnosticBuilder, DiagnosticId}; -use rustc_hir as hir; -use rustc_hir::def::{CtorOf, DefKind, Res}; -use rustc_hir::def_id::DefId; -use rustc_hir::lang_items::LangItem; -use rustc_hir::{ExprKind, GenericArg, ItemKind, Node, QPath}; -use rustc_infer::infer::canonical::{Canonical, OriginalQueryValues, QueryResponse}; -use rustc_infer::infer::error_reporting::TypeAnnotationNeeded::E0282; -use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; -use rustc_infer::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind}; -use rustc_infer::infer::{self, InferOk, InferResult}; -use rustc_middle::hir::map::blocks::FnLikeNode; -use rustc_middle::ty::adjustment::{ - Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability, -}; -use rustc_middle::ty::fold::TypeFoldable; -use rustc_middle::ty::subst::{ - self, GenericArgKind, InternalSubsts, Subst, SubstsRef, UserSelfTy, UserSubsts, -}; -use rustc_middle::ty::{ - self, AdtKind, CanonicalUserType, Const, DefIdTree, GenericParamDefKind, ToPolyTraitRef, - ToPredicate, Ty, TyCtxt, UserType, -}; -use rustc_session::{lint, Session}; -use rustc_span::hygiene::DesugaringKind; -use rustc_span::source_map::{original_sp, DUMMY_SP}; -use rustc_span::symbol::{kw, sym, Ident}; -use rustc_span::{self, BytePos, MultiSpan, Span}; -use rustc_trait_selection::infer::InferCtxtExt as _; -use rustc_trait_selection::opaque_types::InferCtxtExt as _; -use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _; -use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _; -use rustc_trait_selection::traits::{ - self, ObligationCause, ObligationCauseCode, TraitEngine, TraitEngineExt, -}; - -use std::cell::{Cell, RefCell}; -use std::collections::hash_map::Entry; -use std::iter; -use std::mem::replace; -use std::ops::Deref; -use std::slice; - -pub struct FnCtxt<'a, 'tcx> { - pub(super) body_id: hir::HirId, - - /// The parameter environment used for proving trait obligations - /// in this function. This can change when we descend into - /// closures (as they bring new things into scope), hence it is - /// not part of `Inherited` (as of the time of this writing, - /// closures do not yet change the environment, but they will - /// eventually). - pub(super) param_env: ty::ParamEnv<'tcx>, - - /// Number of errors that had been reported when we started - /// checking this function. On exit, if we find that *more* errors - /// have been reported, we will skip regionck and other work that - /// expects the types within the function to be consistent. - // FIXME(matthewjasper) This should not exist, and it's not correct - // if type checking is run in parallel. - err_count_on_creation: usize, - - /// If `Some`, this stores coercion information for returned - /// expressions. If `None`, this is in a context where return is - /// inappropriate, such as a const expression. - /// - /// This is a `RefCell<DynamicCoerceMany>`, which means that we - /// can track all the return expressions and then use them to - /// compute a useful coercion from the set, similar to a match - /// expression or other branching context. You can use methods - /// like `expected_ty` to access the declared return type (if - /// any). - pub(super) ret_coercion: Option<RefCell<DynamicCoerceMany<'tcx>>>, - - pub(super) ret_coercion_impl_trait: Option<Ty<'tcx>>, - - pub(super) ret_type_span: Option<Span>, - - /// Used exclusively to reduce cost of advanced evaluation used for - /// more helpful diagnostics. - pub(super) in_tail_expr: bool, - - /// First span of a return site that we find. Used in error messages. - pub(super) ret_coercion_span: RefCell<Option<Span>>, - - pub(super) resume_yield_tys: Option<(Ty<'tcx>, Ty<'tcx>)>, - - pub(super) ps: RefCell<UnsafetyState>, - - /// Whether the last checked node generates a divergence (e.g., - /// `return` will set this to `Always`). In general, when entering - /// an expression or other node in the tree, the initial value - /// indicates whether prior parts of the containing expression may - /// have diverged. It is then typically set to `Maybe` (and the - /// old value remembered) for processing the subparts of the - /// current expression. As each subpart is processed, they may set - /// the flag to `Always`, etc. Finally, at the end, we take the - /// result and "union" it with the original value, so that when we - /// return the flag indicates if any subpart of the parent - /// expression (up to and including this part) has diverged. So, - /// if you read it after evaluating a subexpression `X`, the value - /// you get indicates whether any subexpression that was - /// evaluating up to and including `X` diverged. - /// - /// We currently use this flag only for diagnostic purposes: - /// - /// - To warn about unreachable code: if, after processing a - /// sub-expression but before we have applied the effects of the - /// current node, we see that the flag is set to `Always`, we - /// can issue a warning. This corresponds to something like - /// `foo(return)`; we warn on the `foo()` expression. (We then - /// update the flag to `WarnedAlways` to suppress duplicate - /// reports.) Similarly, if we traverse to a fresh statement (or - /// tail expression) from a `Always` setting, we will issue a - /// warning. This corresponds to something like `{return; - /// foo();}` or `{return; 22}`, where we would warn on the - /// `foo()` or `22`. - /// - /// An expression represents dead code if, after checking it, - /// the diverges flag is set to something other than `Maybe`. - pub(super) diverges: Cell<Diverges>, - - /// Whether any child nodes have any type errors. - pub(super) has_errors: Cell<bool>, - - pub(super) enclosing_breakables: RefCell<EnclosingBreakables<'tcx>>, - - pub(super) inh: &'a Inherited<'a, 'tcx>, -} - -impl<'a, 'tcx> FnCtxt<'a, 'tcx> { - pub fn new( - inh: &'a Inherited<'a, 'tcx>, - param_env: ty::ParamEnv<'tcx>, - body_id: hir::HirId, - ) -> FnCtxt<'a, 'tcx> { - FnCtxt { - body_id, - param_env, - err_count_on_creation: inh.tcx.sess.err_count(), - ret_coercion: None, - ret_coercion_impl_trait: None, - ret_type_span: None, - in_tail_expr: false, - ret_coercion_span: RefCell::new(None), - resume_yield_tys: None, - ps: RefCell::new(UnsafetyState::function(hir::Unsafety::Normal, hir::CRATE_HIR_ID)), - diverges: Cell::new(Diverges::Maybe), - has_errors: Cell::new(false), - enclosing_breakables: RefCell::new(EnclosingBreakables { - stack: Vec::new(), - by_id: Default::default(), - }), - inh, - } - } - - pub fn sess(&self) -> &Session { - &self.tcx.sess - } - - pub fn errors_reported_since_creation(&self) -> bool { - self.tcx.sess.err_count() > self.err_count_on_creation - } - - /// Produces warning on the given node, if the current point in the - /// function is unreachable, and there hasn't been another warning. - pub(super) fn warn_if_unreachable(&self, id: hir::HirId, span: Span, kind: &str) { - // FIXME: Combine these two 'if' expressions into one once - // let chains are implemented - if let Diverges::Always { span: orig_span, custom_note } = self.diverges.get() { - // If span arose from a desugaring of `if` or `while`, then it is the condition itself, - // which diverges, that we are about to lint on. This gives suboptimal diagnostics. - // Instead, stop here so that the `if`- or `while`-expression's block is linted instead. - if !span.is_desugaring(DesugaringKind::CondTemporary) - && !span.is_desugaring(DesugaringKind::Async) - && !orig_span.is_desugaring(DesugaringKind::Await) - { - self.diverges.set(Diverges::WarnedAlways); - - debug!("warn_if_unreachable: id={:?} span={:?} kind={}", id, span, kind); - - self.tcx().struct_span_lint_hir(lint::builtin::UNREACHABLE_CODE, id, span, |lint| { - let msg = format!("unreachable {}", kind); - lint.build(&msg) - .span_label(span, &msg) - .span_label( - orig_span, - custom_note - .unwrap_or("any code following this expression is unreachable"), - ) - .emit(); - }) - } - } - } - - pub fn cause(&self, span: Span, code: ObligationCauseCode<'tcx>) -> ObligationCause<'tcx> { - ObligationCause::new(span, self.body_id, code) - } - - pub fn misc(&self, span: Span) -> ObligationCause<'tcx> { - self.cause(span, ObligationCauseCode::MiscObligation) - } - - /// Resolves type and const variables in `ty` if possible. Unlike the infcx - /// version (resolve_vars_if_possible), this version will - /// also select obligations if it seems useful, in an effort - /// to get more type information. - pub(super) fn resolve_vars_with_obligations(&self, mut ty: Ty<'tcx>) -> Ty<'tcx> { - debug!("resolve_vars_with_obligations(ty={:?})", ty); - - // No Infer()? Nothing needs doing. - if !ty.has_infer_types_or_consts() { - debug!("resolve_vars_with_obligations: ty={:?}", ty); - return ty; - } - - // If `ty` is a type variable, see whether we already know what it is. - ty = self.resolve_vars_if_possible(&ty); - if !ty.has_infer_types_or_consts() { - debug!("resolve_vars_with_obligations: ty={:?}", ty); - return ty; - } - - // If not, try resolving pending obligations as much as - // possible. This can help substantially when there are - // indirect dependencies that don't seem worth tracking - // precisely. - self.select_obligations_where_possible(false, |_| {}); - ty = self.resolve_vars_if_possible(&ty); - - debug!("resolve_vars_with_obligations: ty={:?}", ty); - ty - } - - pub(super) fn record_deferred_call_resolution( - &self, - closure_def_id: DefId, - r: DeferredCallResolution<'tcx>, - ) { - let mut deferred_call_resolutions = self.deferred_call_resolutions.borrow_mut(); - deferred_call_resolutions.entry(closure_def_id).or_default().push(r); - } - - pub(super) fn remove_deferred_call_resolutions( - &self, - closure_def_id: DefId, - ) -> Vec<DeferredCallResolution<'tcx>> { - let mut deferred_call_resolutions = self.deferred_call_resolutions.borrow_mut(); - deferred_call_resolutions.remove(&closure_def_id).unwrap_or(vec![]) - } - - pub fn tag(&self) -> String { - format!("{:p}", self) - } - - pub fn local_ty(&self, span: Span, nid: hir::HirId) -> LocalTy<'tcx> { - self.locals.borrow().get(&nid).cloned().unwrap_or_else(|| { - span_bug!(span, "no type for local variable {}", self.tcx.hir().node_to_string(nid)) - }) - } - - #[inline] - pub fn write_ty(&self, id: hir::HirId, ty: Ty<'tcx>) { - debug!( - "write_ty({:?}, {:?}) in fcx {}", - id, - self.resolve_vars_if_possible(&ty), - self.tag() - ); - self.typeck_results.borrow_mut().node_types_mut().insert(id, ty); - - if ty.references_error() { - self.has_errors.set(true); - self.set_tainted_by_errors(); - } - } - - pub fn write_field_index(&self, hir_id: hir::HirId, index: usize) { - self.typeck_results.borrow_mut().field_indices_mut().insert(hir_id, index); - } - - fn write_resolution(&self, hir_id: hir::HirId, r: Result<(DefKind, DefId), ErrorReported>) { - self.typeck_results.borrow_mut().type_dependent_defs_mut().insert(hir_id, r); - } - - pub fn write_method_call(&self, hir_id: hir::HirId, method: MethodCallee<'tcx>) { - debug!("write_method_call(hir_id={:?}, method={:?})", hir_id, method); - self.write_resolution(hir_id, Ok((DefKind::AssocFn, method.def_id))); - self.write_substs(hir_id, method.substs); - - // When the method is confirmed, the `method.substs` includes - // parameters from not just the method, but also the impl of - // the method -- in particular, the `Self` type will be fully - // resolved. However, those are not something that the "user - // specified" -- i.e., those types come from the inferred type - // of the receiver, not something the user wrote. So when we - // create the user-substs, we want to replace those earlier - // types with just the types that the user actually wrote -- - // that is, those that appear on the *method itself*. - // - // As an example, if the user wrote something like - // `foo.bar::<u32>(...)` -- the `Self` type here will be the - // type of `foo` (possibly adjusted), but we don't want to - // include that. We want just the `[_, u32]` part. - if !method.substs.is_noop() { - let method_generics = self.tcx.generics_of(method.def_id); - if !method_generics.params.is_empty() { - let user_type_annotation = self.infcx.probe(|_| { - let user_substs = UserSubsts { - substs: InternalSubsts::for_item(self.tcx, method.def_id, |param, _| { - let i = param.index as usize; - if i < method_generics.parent_count { - self.infcx.var_for_def(DUMMY_SP, param) - } else { - method.substs[i] - } - }), - user_self_ty: None, // not relevant here - }; - - self.infcx.canonicalize_user_type_annotation(&UserType::TypeOf( - method.def_id, - user_substs, - )) - }); - - debug!("write_method_call: user_type_annotation={:?}", user_type_annotation); - self.write_user_type_annotation(hir_id, user_type_annotation); - } - } - } - - pub fn write_substs(&self, node_id: hir::HirId, substs: SubstsRef<'tcx>) { - if !substs.is_noop() { - debug!("write_substs({:?}, {:?}) in fcx {}", node_id, substs, self.tag()); - - self.typeck_results.borrow_mut().node_substs_mut().insert(node_id, substs); - } - } - - /// Given the substs that we just converted from the HIR, try to - /// canonicalize them and store them as user-given substitutions - /// (i.e., substitutions that must be respected by the NLL check). - /// - /// This should be invoked **before any unifications have - /// occurred**, so that annotations like `Vec<_>` are preserved - /// properly. - pub fn write_user_type_annotation_from_substs( - &self, - hir_id: hir::HirId, - def_id: DefId, - substs: SubstsRef<'tcx>, - user_self_ty: Option<UserSelfTy<'tcx>>, - ) { - debug!( - "write_user_type_annotation_from_substs: hir_id={:?} def_id={:?} substs={:?} \ - user_self_ty={:?} in fcx {}", - hir_id, - def_id, - substs, - user_self_ty, - self.tag(), - ); - - if Self::can_contain_user_lifetime_bounds((substs, user_self_ty)) { - let canonicalized = self.infcx.canonicalize_user_type_annotation(&UserType::TypeOf( - def_id, - UserSubsts { substs, user_self_ty }, - )); - debug!("write_user_type_annotation_from_substs: canonicalized={:?}", canonicalized); - self.write_user_type_annotation(hir_id, canonicalized); - } - } - - pub fn write_user_type_annotation( - &self, - hir_id: hir::HirId, - canonical_user_type_annotation: CanonicalUserType<'tcx>, - ) { - debug!( - "write_user_type_annotation: hir_id={:?} canonical_user_type_annotation={:?} tag={}", - hir_id, - canonical_user_type_annotation, - self.tag(), - ); - - if !canonical_user_type_annotation.is_identity() { - self.typeck_results - .borrow_mut() - .user_provided_types_mut() - .insert(hir_id, canonical_user_type_annotation); - } else { - debug!("write_user_type_annotation: skipping identity substs"); - } - } - - pub fn apply_adjustments(&self, expr: &hir::Expr<'_>, adj: Vec<Adjustment<'tcx>>) { - debug!("apply_adjustments(expr={:?}, adj={:?})", expr, adj); - - if adj.is_empty() { - return; - } - - let autoborrow_mut = adj.iter().any(|adj| { - matches!(adj, &Adjustment { - kind: Adjust::Borrow(AutoBorrow::Ref(_, AutoBorrowMutability::Mut { .. })), - .. - }) - }); - - match self.typeck_results.borrow_mut().adjustments_mut().entry(expr.hir_id) { - Entry::Vacant(entry) => { - entry.insert(adj); - } - Entry::Occupied(mut entry) => { - debug!(" - composing on top of {:?}", entry.get()); - match (&entry.get()[..], &adj[..]) { - // Applying any adjustment on top of a NeverToAny - // is a valid NeverToAny adjustment, because it can't - // be reached. - (&[Adjustment { kind: Adjust::NeverToAny, .. }], _) => return, - (&[ - Adjustment { kind: Adjust::Deref(_), .. }, - Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(..)), .. }, - ], &[ - Adjustment { kind: Adjust::Deref(_), .. }, - .. // Any following adjustments are allowed. - ]) => { - // A reborrow has no effect before a dereference. - } - // FIXME: currently we never try to compose autoderefs - // and ReifyFnPointer/UnsafeFnPointer, but we could. - _ => - bug!("while adjusting {:?}, can't compose {:?} and {:?}", - expr, entry.get(), adj) - }; - *entry.get_mut() = adj; - } - } - - // If there is an mutable auto-borrow, it is equivalent to `&mut <expr>`. - // In this case implicit use of `Deref` and `Index` within `<expr>` should - // instead be `DerefMut` and `IndexMut`, so fix those up. - if autoborrow_mut { - self.convert_place_derefs_to_mutable(expr); - } - } - - /// Basically whenever we are converting from a type scheme into - /// the fn body space, we always want to normalize associated - /// types as well. This function combines the two. - fn instantiate_type_scheme<T>(&self, span: Span, substs: SubstsRef<'tcx>, value: &T) -> T - where - T: TypeFoldable<'tcx>, - { - let value = value.subst(self.tcx, substs); - let result = self.normalize_associated_types_in(span, &value); - debug!("instantiate_type_scheme(value={:?}, substs={:?}) = {:?}", value, substs, result); - result - } - - /// As `instantiate_type_scheme`, but for the bounds found in a - /// generic type scheme. - fn instantiate_bounds( - &self, - span: Span, - def_id: DefId, - substs: SubstsRef<'tcx>, - ) -> (ty::InstantiatedPredicates<'tcx>, Vec<Span>) { - let bounds = self.tcx.predicates_of(def_id); - let spans: Vec<Span> = bounds.predicates.iter().map(|(_, span)| *span).collect(); - let result = bounds.instantiate(self.tcx, substs); - let result = self.normalize_associated_types_in(span, &result); - debug!( - "instantiate_bounds(bounds={:?}, substs={:?}) = {:?}, {:?}", - bounds, substs, result, spans, - ); - (result, spans) - } - - /// Replaces the opaque types from the given value with type variables, - /// and records the `OpaqueTypeMap` for later use during writeback. See - /// `InferCtxt::instantiate_opaque_types` for more details. - pub(super) fn instantiate_opaque_types_from_value<T: TypeFoldable<'tcx>>( - &self, - parent_id: hir::HirId, - value: &T, - value_span: Span, - ) -> T { - let parent_def_id = self.tcx.hir().local_def_id(parent_id); - debug!( - "instantiate_opaque_types_from_value(parent_def_id={:?}, value={:?})", - parent_def_id, value - ); - - let (value, opaque_type_map) = - self.register_infer_ok_obligations(self.instantiate_opaque_types( - parent_def_id, - self.body_id, - self.param_env, - value, - value_span, - )); - - let mut opaque_types = self.opaque_types.borrow_mut(); - let mut opaque_types_vars = self.opaque_types_vars.borrow_mut(); - for (ty, decl) in opaque_type_map { - let _ = opaque_types.insert(ty, decl); - let _ = opaque_types_vars.insert(decl.concrete_ty, decl.opaque_type); - } - - value - } - - pub(super) fn normalize_associated_types_in<T>(&self, span: Span, value: &T) -> T - where - T: TypeFoldable<'tcx>, - { - self.inh.normalize_associated_types_in(span, self.body_id, self.param_env, value) - } - - pub(super) fn normalize_associated_types_in_as_infer_ok<T>( - &self, - span: Span, - value: &T, - ) -> InferOk<'tcx, T> - where - T: TypeFoldable<'tcx>, - { - self.inh.partially_normalize_associated_types_in(span, self.body_id, self.param_env, value) - } - - pub fn require_type_meets( - &self, - ty: Ty<'tcx>, - span: Span, - code: traits::ObligationCauseCode<'tcx>, - def_id: DefId, - ) { - self.register_bound(ty, def_id, traits::ObligationCause::new(span, self.body_id, code)); - } - - pub fn require_type_is_sized( - &self, - ty: Ty<'tcx>, - span: Span, - code: traits::ObligationCauseCode<'tcx>, - ) { - if !ty.references_error() { - let lang_item = self.tcx.require_lang_item(LangItem::Sized, None); - self.require_type_meets(ty, span, code, lang_item); - } - } - - pub fn require_type_is_sized_deferred( - &self, - ty: Ty<'tcx>, - span: Span, - code: traits::ObligationCauseCode<'tcx>, - ) { - if !ty.references_error() { - self.deferred_sized_obligations.borrow_mut().push((ty, span, code)); - } - } - - pub fn register_bound( - &self, - ty: Ty<'tcx>, - def_id: DefId, - cause: traits::ObligationCause<'tcx>, - ) { - if !ty.references_error() { - self.fulfillment_cx.borrow_mut().register_bound( - self, - self.param_env, - ty, - def_id, - cause, - ); - } - } - - pub fn to_ty(&self, ast_t: &hir::Ty<'_>) -> Ty<'tcx> { - let t = AstConv::ast_ty_to_ty(self, ast_t); - self.register_wf_obligation(t.into(), ast_t.span, traits::MiscObligation); - t - } - - pub fn to_ty_saving_user_provided_ty(&self, ast_ty: &hir::Ty<'_>) -> Ty<'tcx> { - let ty = self.to_ty(ast_ty); - debug!("to_ty_saving_user_provided_ty: ty={:?}", ty); - - if Self::can_contain_user_lifetime_bounds(ty) { - let c_ty = self.infcx.canonicalize_response(&UserType::Ty(ty)); - debug!("to_ty_saving_user_provided_ty: c_ty={:?}", c_ty); - self.typeck_results.borrow_mut().user_provided_types_mut().insert(ast_ty.hir_id, c_ty); - } - - ty - } - - pub fn to_const(&self, ast_c: &hir::AnonConst) -> &'tcx ty::Const<'tcx> { - let const_def_id = self.tcx.hir().local_def_id(ast_c.hir_id); - let c = ty::Const::from_anon_const(self.tcx, const_def_id); - self.register_wf_obligation( - c.into(), - self.tcx.hir().span(ast_c.hir_id), - ObligationCauseCode::MiscObligation, - ); - c - } - - pub fn const_arg_to_const( - &self, - ast_c: &hir::AnonConst, - param_def_id: DefId, - ) -> &'tcx ty::Const<'tcx> { - let const_def = ty::WithOptConstParam { - did: self.tcx.hir().local_def_id(ast_c.hir_id), - const_param_did: Some(param_def_id), - }; - let c = ty::Const::from_opt_const_arg_anon_const(self.tcx, const_def); - self.register_wf_obligation( - c.into(), - self.tcx.hir().span(ast_c.hir_id), - ObligationCauseCode::MiscObligation, - ); - c - } - - // If the type given by the user has free regions, save it for later, since - // NLL would like to enforce those. Also pass in types that involve - // projections, since those can resolve to `'static` bounds (modulo #54940, - // which hopefully will be fixed by the time you see this comment, dear - // reader, although I have my doubts). Also pass in types with inference - // types, because they may be repeated. Other sorts of things are already - // sufficiently enforced with erased regions. =) - fn can_contain_user_lifetime_bounds<T>(t: T) -> bool - where - T: TypeFoldable<'tcx>, - { - t.has_free_regions() || t.has_projections() || t.has_infer_types() - } - - pub fn node_ty(&self, id: hir::HirId) -> Ty<'tcx> { - match self.typeck_results.borrow().node_types().get(id) { - Some(&t) => t, - None if self.is_tainted_by_errors() => self.tcx.ty_error(), - None => { - bug!( - "no type for node {}: {} in fcx {}", - id, - self.tcx.hir().node_to_string(id), - self.tag() - ); - } - } - } - - /// Registers an obligation for checking later, during regionck, that `arg` is well-formed. - pub fn register_wf_obligation( - &self, - arg: subst::GenericArg<'tcx>, - span: Span, - code: traits::ObligationCauseCode<'tcx>, - ) { - // WF obligations never themselves fail, so no real need to give a detailed cause: - let cause = traits::ObligationCause::new(span, self.body_id, code); - self.register_predicate(traits::Obligation::new( - cause, - self.param_env, - ty::PredicateAtom::WellFormed(arg).to_predicate(self.tcx), - )); - } - - /// Registers obligations that all `substs` are well-formed. - pub fn add_wf_bounds(&self, substs: SubstsRef<'tcx>, expr: &hir::Expr<'_>) { - for arg in substs.iter().filter(|arg| { - matches!(arg.unpack(), GenericArgKind::Type(..) | GenericArgKind::Const(..)) - }) { - self.register_wf_obligation(arg, expr.span, traits::MiscObligation); - } - } - - /// Given a fully substituted set of bounds (`generic_bounds`), and the values with which each - /// type/region parameter was instantiated (`substs`), creates and registers suitable - /// trait/region obligations. - /// - /// For example, if there is a function: - /// - /// ``` - /// fn foo<'a,T:'a>(...) - /// ``` - /// - /// and a reference: - /// - /// ``` - /// let f = foo; - /// ``` - /// - /// Then we will create a fresh region variable `'$0` and a fresh type variable `$1` for `'a` - /// and `T`. This routine will add a region obligation `$1:'$0` and register it locally. - pub fn add_obligations_for_parameters( - &self, - cause: traits::ObligationCause<'tcx>, - predicates: ty::InstantiatedPredicates<'tcx>, - ) { - assert!(!predicates.has_escaping_bound_vars()); - - debug!("add_obligations_for_parameters(predicates={:?})", predicates); - - for obligation in traits::predicates_for_generics(cause, self.param_env, predicates) { - self.register_predicate(obligation); - } - } - - // FIXME(arielb1): use this instead of field.ty everywhere - // Only for fields! Returns <none> for methods> - // Indifferent to privacy flags - pub fn field_ty( - &self, - span: Span, - field: &'tcx ty::FieldDef, - substs: SubstsRef<'tcx>, - ) -> Ty<'tcx> { - self.normalize_associated_types_in(span, &field.ty(self.tcx, substs)) - } - - pub(super) fn check_casts(&self) { - let mut deferred_cast_checks = self.deferred_cast_checks.borrow_mut(); - for cast in deferred_cast_checks.drain(..) { - cast.check(self); - } - } - - pub(super) fn resolve_generator_interiors(&self, def_id: DefId) { - let mut generators = self.deferred_generator_interiors.borrow_mut(); - for (body_id, interior, kind) in generators.drain(..) { - self.select_obligations_where_possible(false, |_| {}); - super::generator_interior::resolve_interior(self, def_id, body_id, interior, kind); - } - } - - // Tries to apply a fallback to `ty` if it is an unsolved variable. - // - // - Unconstrained ints are replaced with `i32`. - // - // - Unconstrained floats are replaced with with `f64`. - // - // - Non-numerics get replaced with `!` when `#![feature(never_type_fallback)]` - // is enabled. Otherwise, they are replaced with `()`. - // - // Fallback becomes very dubious if we have encountered type-checking errors. - // In that case, fallback to Error. - // The return value indicates whether fallback has occurred. - pub(super) fn fallback_if_possible(&self, ty: Ty<'tcx>, mode: FallbackMode) -> bool { - use rustc_middle::ty::error::UnconstrainedNumeric::Neither; - use rustc_middle::ty::error::UnconstrainedNumeric::{UnconstrainedFloat, UnconstrainedInt}; - - assert!(ty.is_ty_infer()); - let fallback = match self.type_is_unconstrained_numeric(ty) { - _ if self.is_tainted_by_errors() => self.tcx().ty_error(), - UnconstrainedInt => self.tcx.types.i32, - UnconstrainedFloat => self.tcx.types.f64, - Neither if self.type_var_diverges(ty) => self.tcx.mk_diverging_default(), - Neither => { - // This type variable was created from the instantiation of an opaque - // type. The fact that we're attempting to perform fallback for it - // means that the function neither constrained it to a concrete - // type, nor to the opaque type itself. - // - // For example, in this code: - // - //``` - // type MyType = impl Copy; - // fn defining_use() -> MyType { true } - // fn other_use() -> MyType { defining_use() } - // ``` - // - // `defining_use` will constrain the instantiated inference - // variable to `bool`, while `other_use` will constrain - // the instantiated inference variable to `MyType`. - // - // When we process opaque types during writeback, we - // will handle cases like `other_use`, and not count - // them as defining usages - // - // However, we also need to handle cases like this: - // - // ```rust - // pub type Foo = impl Copy; - // fn produce() -> Option<Foo> { - // None - // } - // ``` - // - // In the above snippet, the inference variable created by - // instantiating `Option<Foo>` will be completely unconstrained. - // We treat this as a non-defining use by making the inference - // variable fall back to the opaque type itself. - if let FallbackMode::All = mode { - if let Some(opaque_ty) = self.opaque_types_vars.borrow().get(ty) { - debug!( - "fallback_if_possible: falling back opaque type var {:?} to {:?}", - ty, opaque_ty - ); - *opaque_ty - } else { - return false; - } - } else { - return false; - } - } - }; - debug!("fallback_if_possible: defaulting `{:?}` to `{:?}`", ty, fallback); - self.demand_eqtype(rustc_span::DUMMY_SP, ty, fallback); - true - } - - pub(super) fn select_all_obligations_or_error(&self) { - debug!("select_all_obligations_or_error"); - if let Err(errors) = self.fulfillment_cx.borrow_mut().select_all_or_error(&self) { - self.report_fulfillment_errors(&errors, self.inh.body_id, false); - } - } - - /// Select as many obligations as we can at present. - pub(super) fn select_obligations_where_possible( - &self, - fallback_has_occurred: bool, - mutate_fullfillment_errors: impl Fn(&mut Vec<traits::FulfillmentError<'tcx>>), - ) { - let result = self.fulfillment_cx.borrow_mut().select_where_possible(self); - if let Err(mut errors) = result { - mutate_fullfillment_errors(&mut errors); - self.report_fulfillment_errors(&errors, self.inh.body_id, fallback_has_occurred); - } - } - - /// For the overloaded place expressions (`*x`, `x[3]`), the trait - /// returns a type of `&T`, but the actual type we assign to the - /// *expression* is `T`. So this function just peels off the return - /// type by one layer to yield `T`. - pub(super) fn make_overloaded_place_return_type( - &self, - method: MethodCallee<'tcx>, - ) -> ty::TypeAndMut<'tcx> { - // extract method return type, which will be &T; - let ret_ty = method.sig.output(); - - // method returns &T, but the type as visible to user is T, so deref - ret_ty.builtin_deref(true).unwrap() - } - - pub(super) fn check_method_argument_types( - &self, - sp: Span, - expr: &'tcx hir::Expr<'tcx>, - method: Result<MethodCallee<'tcx>, ()>, - args_no_rcvr: &'tcx [hir::Expr<'tcx>], - tuple_arguments: TupleArgumentsFlag, - expected: Expectation<'tcx>, - ) -> Ty<'tcx> { - let has_error = match method { - Ok(method) => method.substs.references_error() || method.sig.references_error(), - Err(_) => true, - }; - if has_error { - let err_inputs = self.err_args(args_no_rcvr.len()); - - let err_inputs = match tuple_arguments { - DontTupleArguments => err_inputs, - TupleArguments => vec![self.tcx.intern_tup(&err_inputs[..])], - }; - - self.check_argument_types( - sp, - expr, - &err_inputs[..], - &[], - args_no_rcvr, - false, - tuple_arguments, - None, - ); - return self.tcx.ty_error(); - } - - let method = method.unwrap(); - // HACK(eddyb) ignore self in the definition (see above). - let expected_arg_tys = self.expected_inputs_for_expected_output( - sp, - expected, - method.sig.output(), - &method.sig.inputs()[1..], - ); - self.check_argument_types( - sp, - expr, - &method.sig.inputs()[1..], - &expected_arg_tys[..], - args_no_rcvr, - method.sig.c_variadic, - tuple_arguments, - self.tcx.hir().span_if_local(method.def_id), - ); - method.sig.output() - } - - fn self_type_matches_expected_vid( - &self, - trait_ref: ty::PolyTraitRef<'tcx>, - expected_vid: ty::TyVid, - ) -> bool { - let self_ty = self.shallow_resolve(trait_ref.skip_binder().self_ty()); - debug!( - "self_type_matches_expected_vid(trait_ref={:?}, self_ty={:?}, expected_vid={:?})", - trait_ref, self_ty, expected_vid - ); - match *self_ty.kind() { - ty::Infer(ty::TyVar(found_vid)) => { - // FIXME: consider using `sub_root_var` here so we - // can see through subtyping. - let found_vid = self.root_var(found_vid); - debug!("self_type_matches_expected_vid - found_vid={:?}", found_vid); - expected_vid == found_vid - } - _ => false, - } - } - - pub(super) fn obligations_for_self_ty<'b>( - &'b self, - self_ty: ty::TyVid, - ) -> impl Iterator<Item = (ty::PolyTraitRef<'tcx>, traits::PredicateObligation<'tcx>)> - + Captures<'tcx> - + 'b { - // FIXME: consider using `sub_root_var` here so we - // can see through subtyping. - let ty_var_root = self.root_var(self_ty); - debug!( - "obligations_for_self_ty: self_ty={:?} ty_var_root={:?} pending_obligations={:?}", - self_ty, - ty_var_root, - self.fulfillment_cx.borrow().pending_obligations() - ); - - self.fulfillment_cx - .borrow() - .pending_obligations() - .into_iter() - .filter_map(move |obligation| { - match obligation.predicate.skip_binders() { - ty::PredicateAtom::Projection(data) => { - Some((ty::Binder::bind(data).to_poly_trait_ref(self.tcx), obligation)) - } - ty::PredicateAtom::Trait(data, _) => { - Some((ty::Binder::bind(data).to_poly_trait_ref(), obligation)) - } - ty::PredicateAtom::Subtype(..) => None, - ty::PredicateAtom::RegionOutlives(..) => None, - ty::PredicateAtom::TypeOutlives(..) => None, - ty::PredicateAtom::WellFormed(..) => None, - ty::PredicateAtom::ObjectSafe(..) => None, - ty::PredicateAtom::ConstEvaluatable(..) => None, - ty::PredicateAtom::ConstEquate(..) => None, - // N.B., this predicate is created by breaking down a - // `ClosureType: FnFoo()` predicate, where - // `ClosureType` represents some `Closure`. It can't - // possibly be referring to the current closure, - // because we haven't produced the `Closure` for - // this closure yet; this is exactly why the other - // code is looking for a self type of a unresolved - // inference variable. - ty::PredicateAtom::ClosureKind(..) => None, - ty::PredicateAtom::TypeWellFormedFromEnv(..) => None, - } - }) - .filter(move |(tr, _)| self.self_type_matches_expected_vid(*tr, ty_var_root)) - } - - pub(super) fn type_var_is_sized(&self, self_ty: ty::TyVid) -> bool { - self.obligations_for_self_ty(self_ty) - .any(|(tr, _)| Some(tr.def_id()) == self.tcx.lang_items().sized_trait()) - } - - /// Generic function that factors out common logic from function calls, - /// method calls and overloaded operators. - pub(super) fn check_argument_types( - &self, - sp: Span, - expr: &'tcx hir::Expr<'tcx>, - fn_inputs: &[Ty<'tcx>], - expected_arg_tys: &[Ty<'tcx>], - args: &'tcx [hir::Expr<'tcx>], - c_variadic: bool, - tuple_arguments: TupleArgumentsFlag, - def_span: Option<Span>, - ) { - let tcx = self.tcx; - // Grab the argument types, supplying fresh type variables - // if the wrong number of arguments were supplied - let supplied_arg_count = if tuple_arguments == DontTupleArguments { args.len() } else { 1 }; - - // All the input types from the fn signature must outlive the call - // so as to validate implied bounds. - for (&fn_input_ty, arg_expr) in fn_inputs.iter().zip(args.iter()) { - self.register_wf_obligation(fn_input_ty.into(), arg_expr.span, traits::MiscObligation); - } - - let expected_arg_count = fn_inputs.len(); - - let param_count_error = |expected_count: usize, - arg_count: usize, - error_code: &str, - c_variadic: bool, - sugg_unit: bool| { - let (span, start_span, args) = match &expr.kind { - hir::ExprKind::Call(hir::Expr { span, .. }, args) => (*span, *span, &args[..]), - hir::ExprKind::MethodCall(path_segment, span, args, _) => ( - *span, - // `sp` doesn't point at the whole `foo.bar()`, only at `bar`. - path_segment - .args - .and_then(|args| args.args.iter().last()) - // Account for `foo.bar::<T>()`. - .map(|arg| { - // Skip the closing `>`. - tcx.sess - .source_map() - .next_point(tcx.sess.source_map().next_point(arg.span())) - }) - .unwrap_or(*span), - &args[1..], // Skip the receiver. - ), - k => span_bug!(sp, "checking argument types on a non-call: `{:?}`", k), - }; - let arg_spans = if args.is_empty() { - // foo() - // ^^^-- supplied 0 arguments - // | - // expected 2 arguments - vec![tcx.sess.source_map().next_point(start_span).with_hi(sp.hi())] - } else { - // foo(1, 2, 3) - // ^^^ - - - supplied 3 arguments - // | - // expected 2 arguments - args.iter().map(|arg| arg.span).collect::<Vec<Span>>() - }; - - let mut err = tcx.sess.struct_span_err_with_code( - span, - &format!( - "this function takes {}{} but {} {} supplied", - if c_variadic { "at least " } else { "" }, - potentially_plural_count(expected_count, "argument"), - potentially_plural_count(arg_count, "argument"), - if arg_count == 1 { "was" } else { "were" } - ), - DiagnosticId::Error(error_code.to_owned()), - ); - let label = format!("supplied {}", potentially_plural_count(arg_count, "argument")); - for (i, span) in arg_spans.into_iter().enumerate() { - err.span_label( - span, - if arg_count == 0 || i + 1 == arg_count { &label } else { "" }, - ); - } - - if let Some(def_s) = def_span.map(|sp| tcx.sess.source_map().guess_head_span(sp)) { - err.span_label(def_s, "defined here"); - } - if sugg_unit { - let sugg_span = tcx.sess.source_map().end_point(expr.span); - // remove closing `)` from the span - let sugg_span = sugg_span.shrink_to_lo(); - err.span_suggestion( - sugg_span, - "expected the unit value `()`; create it with empty parentheses", - String::from("()"), - Applicability::MachineApplicable, - ); - } else { - err.span_label( - span, - format!( - "expected {}{}", - if c_variadic { "at least " } else { "" }, - potentially_plural_count(expected_count, "argument") - ), - ); - } - err.emit(); - }; - - let mut expected_arg_tys = expected_arg_tys.to_vec(); - - let formal_tys = if tuple_arguments == TupleArguments { - let tuple_type = self.structurally_resolved_type(sp, fn_inputs[0]); - match tuple_type.kind() { - ty::Tuple(arg_types) if arg_types.len() != args.len() => { - param_count_error(arg_types.len(), args.len(), "E0057", false, false); - expected_arg_tys = vec![]; - self.err_args(args.len()) - } - ty::Tuple(arg_types) => { - expected_arg_tys = match expected_arg_tys.get(0) { - Some(&ty) => match ty.kind() { - ty::Tuple(ref tys) => tys.iter().map(|k| k.expect_ty()).collect(), - _ => vec![], - }, - None => vec![], - }; - arg_types.iter().map(|k| k.expect_ty()).collect() - } - _ => { - struct_span_err!( - tcx.sess, - sp, - E0059, - "cannot use call notation; the first type parameter \ - for the function trait is neither a tuple nor unit" - ) - .emit(); - expected_arg_tys = vec![]; - self.err_args(args.len()) - } - } - } else if expected_arg_count == supplied_arg_count { - fn_inputs.to_vec() - } else if c_variadic { - if supplied_arg_count >= expected_arg_count { - fn_inputs.to_vec() - } else { - param_count_error(expected_arg_count, supplied_arg_count, "E0060", true, false); - expected_arg_tys = vec![]; - self.err_args(supplied_arg_count) - } - } else { - // is the missing argument of type `()`? - let sugg_unit = if expected_arg_tys.len() == 1 && supplied_arg_count == 0 { - self.resolve_vars_if_possible(&expected_arg_tys[0]).is_unit() - } else if fn_inputs.len() == 1 && supplied_arg_count == 0 { - self.resolve_vars_if_possible(&fn_inputs[0]).is_unit() - } else { - false - }; - param_count_error(expected_arg_count, supplied_arg_count, "E0061", false, sugg_unit); - - expected_arg_tys = vec![]; - self.err_args(supplied_arg_count) - }; - - debug!( - "check_argument_types: formal_tys={:?}", - formal_tys.iter().map(|t| self.ty_to_string(*t)).collect::<Vec<String>>() - ); - - // If there is no expectation, expect formal_tys. - let expected_arg_tys = - if !expected_arg_tys.is_empty() { expected_arg_tys } else { formal_tys.clone() }; - - let mut final_arg_types: Vec<(usize, Ty<'_>, Ty<'_>)> = vec![]; - - // Check the arguments. - // We do this in a pretty awful way: first we type-check any arguments - // that are not closures, then we type-check the closures. This is so - // that we have more information about the types of arguments when we - // type-check the functions. This isn't really the right way to do this. - for &check_closures in &[false, true] { - debug!("check_closures={}", check_closures); - - // More awful hacks: before we check argument types, try to do - // an "opportunistic" trait resolution of any trait bounds on - // the call. This helps coercions. - if check_closures { - self.select_obligations_where_possible(false, |errors| { - self.point_at_type_arg_instead_of_call_if_possible(errors, expr); - self.point_at_arg_instead_of_call_if_possible( - errors, - &final_arg_types[..], - sp, - &args, - ); - }) - } - - // For C-variadic functions, we don't have a declared type for all of - // the arguments hence we only do our usual type checking with - // the arguments who's types we do know. - let t = if c_variadic { - expected_arg_count - } else if tuple_arguments == TupleArguments { - args.len() - } else { - supplied_arg_count - }; - for (i, arg) in args.iter().take(t).enumerate() { - // Warn only for the first loop (the "no closures" one). - // Closure arguments themselves can't be diverging, but - // a previous argument can, e.g., `foo(panic!(), || {})`. - if !check_closures { - self.warn_if_unreachable(arg.hir_id, arg.span, "expression"); - } - - let is_closure = match arg.kind { - ExprKind::Closure(..) => true, - _ => false, - }; - - if is_closure != check_closures { - continue; - } - - debug!("checking the argument"); - let formal_ty = formal_tys[i]; - - // The special-cased logic below has three functions: - // 1. Provide as good of an expected type as possible. - let expected = Expectation::rvalue_hint(self, expected_arg_tys[i]); - - let checked_ty = self.check_expr_with_expectation(&arg, expected); - - // 2. Coerce to the most detailed type that could be coerced - // to, which is `expected_ty` if `rvalue_hint` returns an - // `ExpectHasType(expected_ty)`, or the `formal_ty` otherwise. - let coerce_ty = expected.only_has_type(self).unwrap_or(formal_ty); - // We're processing function arguments so we definitely want to use - // two-phase borrows. - self.demand_coerce(&arg, checked_ty, coerce_ty, None, AllowTwoPhase::Yes); - final_arg_types.push((i, checked_ty, coerce_ty)); - - // 3. Relate the expected type and the formal one, - // if the expected type was used for the coercion. - self.demand_suptype(arg.span, formal_ty, coerce_ty); - } - } - - // We also need to make sure we at least write the ty of the other - // arguments which we skipped above. - if c_variadic { - fn variadic_error<'tcx>(s: &Session, span: Span, t: Ty<'tcx>, cast_ty: &str) { - use crate::structured_errors::{StructuredDiagnostic, VariadicError}; - VariadicError::new(s, span, t, cast_ty).diagnostic().emit(); - } - - for arg in args.iter().skip(expected_arg_count) { - let arg_ty = self.check_expr(&arg); - - // There are a few types which get autopromoted when passed via varargs - // in C but we just error out instead and require explicit casts. - let arg_ty = self.structurally_resolved_type(arg.span, arg_ty); - match arg_ty.kind() { - ty::Float(ast::FloatTy::F32) => { - variadic_error(tcx.sess, arg.span, arg_ty, "c_double"); - } - ty::Int(ast::IntTy::I8 | ast::IntTy::I16) | ty::Bool => { - variadic_error(tcx.sess, arg.span, arg_ty, "c_int"); - } - ty::Uint(ast::UintTy::U8 | ast::UintTy::U16) => { - variadic_error(tcx.sess, arg.span, arg_ty, "c_uint"); - } - ty::FnDef(..) => { - let ptr_ty = self.tcx.mk_fn_ptr(arg_ty.fn_sig(self.tcx)); - let ptr_ty = self.resolve_vars_if_possible(&ptr_ty); - variadic_error(tcx.sess, arg.span, arg_ty, &ptr_ty.to_string()); - } - _ => {} - } - } - } - } - - pub(super) fn err_args(&self, len: usize) -> Vec<Ty<'tcx>> { - vec![self.tcx.ty_error(); len] - } - - /// Given a vec of evaluated `FulfillmentError`s and an `fn` call argument expressions, we walk - /// the checked and coerced types for each argument to see if any of the `FulfillmentError`s - /// reference a type argument. The reason to walk also the checked type is that the coerced type - /// can be not easily comparable with predicate type (because of coercion). If the types match - /// for either checked or coerced type, and there's only *one* argument that does, we point at - /// the corresponding argument's expression span instead of the `fn` call path span. - fn point_at_arg_instead_of_call_if_possible( - &self, - errors: &mut Vec<traits::FulfillmentError<'tcx>>, - final_arg_types: &[(usize, Ty<'tcx>, Ty<'tcx>)], - call_sp: Span, - args: &'tcx [hir::Expr<'tcx>], - ) { - // We *do not* do this for desugared call spans to keep good diagnostics when involving - // the `?` operator. - if call_sp.desugaring_kind().is_some() { - return; - } - - for error in errors { - // Only if the cause is somewhere inside the expression we want try to point at arg. - // Otherwise, it means that the cause is somewhere else and we should not change - // anything because we can break the correct span. - if !call_sp.contains(error.obligation.cause.span) { - continue; - } - - if let ty::PredicateAtom::Trait(predicate, _) = - error.obligation.predicate.skip_binders() - { - // Collect the argument position for all arguments that could have caused this - // `FulfillmentError`. - let mut referenced_in = final_arg_types - .iter() - .map(|&(i, checked_ty, _)| (i, checked_ty)) - .chain(final_arg_types.iter().map(|&(i, _, coerced_ty)| (i, coerced_ty))) - .flat_map(|(i, ty)| { - let ty = self.resolve_vars_if_possible(&ty); - // We walk the argument type because the argument's type could have - // been `Option<T>`, but the `FulfillmentError` references `T`. - if ty.walk().any(|arg| arg == predicate.self_ty().into()) { - Some(i) - } else { - None - } - }) - .collect::<Vec<usize>>(); - - // Both checked and coerced types could have matched, thus we need to remove - // duplicates. - - // We sort primitive type usize here and can use unstable sort - referenced_in.sort_unstable(); - referenced_in.dedup(); - - if let (Some(ref_in), None) = (referenced_in.pop(), referenced_in.pop()) { - // We make sure that only *one* argument matches the obligation failure - // and we assign the obligation's span to its expression's. - error.obligation.cause.make_mut().span = args[ref_in].span; - error.points_at_arg_span = true; - } - } - } - } - - /// Given a vec of evaluated `FulfillmentError`s and an `fn` call expression, we walk the - /// `PathSegment`s and resolve their type parameters to see if any of the `FulfillmentError`s - /// were caused by them. If they were, we point at the corresponding type argument's span - /// instead of the `fn` call path span. - fn point_at_type_arg_instead_of_call_if_possible( - &self, - errors: &mut Vec<traits::FulfillmentError<'tcx>>, - call_expr: &'tcx hir::Expr<'tcx>, - ) { - if let hir::ExprKind::Call(path, _) = &call_expr.kind { - if let hir::ExprKind::Path(qpath) = &path.kind { - if let hir::QPath::Resolved(_, path) = &qpath { - for error in errors { - if let ty::PredicateAtom::Trait(predicate, _) = - error.obligation.predicate.skip_binders() - { - // If any of the type arguments in this path segment caused the - // `FullfillmentError`, point at its span (#61860). - for arg in path - .segments - .iter() - .filter_map(|seg| seg.args.as_ref()) - .flat_map(|a| a.args.iter()) - { - if let hir::GenericArg::Type(hir_ty) = &arg { - if let hir::TyKind::Path(hir::QPath::TypeRelative(..)) = - &hir_ty.kind - { - // Avoid ICE with associated types. As this is best - // effort only, it's ok to ignore the case. It - // would trigger in `is_send::<T::AssocType>();` - // from `typeck-default-trait-impl-assoc-type.rs`. - } else { - let ty = AstConv::ast_ty_to_ty(self, hir_ty); - let ty = self.resolve_vars_if_possible(&ty); - if ty == predicate.self_ty() { - error.obligation.cause.make_mut().span = hir_ty.span; - } - } - } - } - } - } - } - } - } - } - - // AST fragment checking - pub(super) fn check_lit(&self, lit: &hir::Lit, expected: Expectation<'tcx>) -> Ty<'tcx> { - let tcx = self.tcx; - - match lit.node { - ast::LitKind::Str(..) => tcx.mk_static_str(), - ast::LitKind::ByteStr(ref v) => { - tcx.mk_imm_ref(tcx.lifetimes.re_static, tcx.mk_array(tcx.types.u8, v.len() as u64)) - } - ast::LitKind::Byte(_) => tcx.types.u8, - ast::LitKind::Char(_) => tcx.types.char, - ast::LitKind::Int(_, ast::LitIntType::Signed(t)) => tcx.mk_mach_int(t), - ast::LitKind::Int(_, ast::LitIntType::Unsigned(t)) => tcx.mk_mach_uint(t), - ast::LitKind::Int(_, ast::LitIntType::Unsuffixed) => { - let opt_ty = expected.to_option(self).and_then(|ty| match ty.kind() { - ty::Int(_) | ty::Uint(_) => Some(ty), - ty::Char => Some(tcx.types.u8), - ty::RawPtr(..) => Some(tcx.types.usize), - ty::FnDef(..) | ty::FnPtr(_) => Some(tcx.types.usize), - _ => None, - }); - opt_ty.unwrap_or_else(|| self.next_int_var()) - } - ast::LitKind::Float(_, ast::LitFloatType::Suffixed(t)) => tcx.mk_mach_float(t), - ast::LitKind::Float(_, ast::LitFloatType::Unsuffixed) => { - let opt_ty = expected.to_option(self).and_then(|ty| match ty.kind() { - ty::Float(_) => Some(ty), - _ => None, - }); - opt_ty.unwrap_or_else(|| self.next_float_var()) - } - ast::LitKind::Bool(_) => tcx.types.bool, - ast::LitKind::Err(_) => tcx.ty_error(), - } - } - - /// Unifies the output type with the expected type early, for more coercions - /// and forward type information on the input expressions. - pub(super) fn expected_inputs_for_expected_output( - &self, - call_span: Span, - expected_ret: Expectation<'tcx>, - formal_ret: Ty<'tcx>, - formal_args: &[Ty<'tcx>], - ) -> Vec<Ty<'tcx>> { - let formal_ret = self.resolve_vars_with_obligations(formal_ret); - let ret_ty = match expected_ret.only_has_type(self) { - Some(ret) => ret, - None => return Vec::new(), - }; - let expect_args = self - .fudge_inference_if_ok(|| { - // Attempt to apply a subtyping relationship between the formal - // return type (likely containing type variables if the function - // is polymorphic) and the expected return type. - // No argument expectations are produced if unification fails. - let origin = self.misc(call_span); - let ures = self.at(&origin, self.param_env).sup(ret_ty, &formal_ret); - - // FIXME(#27336) can't use ? here, Try::from_error doesn't default - // to identity so the resulting type is not constrained. - match ures { - Ok(ok) => { - // Process any obligations locally as much as - // we can. We don't care if some things turn - // out unconstrained or ambiguous, as we're - // just trying to get hints here. - self.save_and_restore_in_snapshot_flag(|_| { - let mut fulfill = TraitEngine::new(self.tcx); - for obligation in ok.obligations { - fulfill.register_predicate_obligation(self, obligation); - } - fulfill.select_where_possible(self) - }) - .map_err(|_| ())?; - } - Err(_) => return Err(()), - } - - // Record all the argument types, with the substitutions - // produced from the above subtyping unification. - Ok(formal_args.iter().map(|ty| self.resolve_vars_if_possible(ty)).collect()) - }) - .unwrap_or_default(); - debug!( - "expected_inputs_for_expected_output(formal={:?} -> {:?}, expected={:?} -> {:?})", - formal_args, formal_ret, expect_args, expected_ret - ); - expect_args - } - - pub fn check_struct_path( - &self, - qpath: &QPath<'_>, - hir_id: hir::HirId, - ) -> Option<(&'tcx ty::VariantDef, Ty<'tcx>)> { - let path_span = qpath.qself_span(); - let (def, ty) = self.finish_resolving_struct_path(qpath, path_span, hir_id); - let variant = match def { - Res::Err => { - self.set_tainted_by_errors(); - return None; - } - Res::Def(DefKind::Variant, _) => match ty.kind() { - ty::Adt(adt, substs) => Some((adt.variant_of_res(def), adt.did, substs)), - _ => bug!("unexpected type: {:?}", ty), - }, - Res::Def(DefKind::Struct | DefKind::Union | DefKind::TyAlias | DefKind::AssocTy, _) - | Res::SelfTy(..) => match ty.kind() { - ty::Adt(adt, substs) if !adt.is_enum() => { - Some((adt.non_enum_variant(), adt.did, substs)) - } - _ => None, - }, - _ => bug!("unexpected definition: {:?}", def), - }; - - if let Some((variant, did, substs)) = variant { - debug!("check_struct_path: did={:?} substs={:?}", did, substs); - self.write_user_type_annotation_from_substs(hir_id, did, substs, None); - - // Check bounds on type arguments used in the path. - let (bounds, _) = self.instantiate_bounds(path_span, did, substs); - let cause = - traits::ObligationCause::new(path_span, self.body_id, traits::ItemObligation(did)); - self.add_obligations_for_parameters(cause, bounds); - - Some((variant, ty)) - } else { - struct_span_err!( - self.tcx.sess, - path_span, - E0071, - "expected struct, variant or union type, found {}", - ty.sort_string(self.tcx) - ) - .span_label(path_span, "not a struct") - .emit(); - None - } - } - - // Finish resolving a path in a struct expression or pattern `S::A { .. }` if necessary. - // The newly resolved definition is written into `type_dependent_defs`. - fn finish_resolving_struct_path( - &self, - qpath: &QPath<'_>, - path_span: Span, - hir_id: hir::HirId, - ) -> (Res, Ty<'tcx>) { - match *qpath { - QPath::Resolved(ref maybe_qself, ref path) => { - let self_ty = maybe_qself.as_ref().map(|qself| self.to_ty(qself)); - let ty = AstConv::res_to_ty(self, self_ty, path, true); - (path.res, ty) - } - QPath::TypeRelative(ref qself, ref segment) => { - let ty = self.to_ty(qself); - - let res = if let hir::TyKind::Path(QPath::Resolved(_, ref path)) = qself.kind { - path.res - } else { - Res::Err - }; - let result = - AstConv::associated_path_to_ty(self, hir_id, path_span, ty, res, segment, true); - let ty = result.map(|(ty, _, _)| ty).unwrap_or_else(|_| self.tcx().ty_error()); - let result = result.map(|(_, kind, def_id)| (kind, def_id)); - - // Write back the new resolution. - self.write_resolution(hir_id, result); - - (result.map(|(kind, def_id)| Res::Def(kind, def_id)).unwrap_or(Res::Err), ty) - } - QPath::LangItem(lang_item, span) => { - self.resolve_lang_item_path(lang_item, span, hir_id) - } - } - } - - pub(super) fn resolve_lang_item_path( - &self, - lang_item: hir::LangItem, - span: Span, - hir_id: hir::HirId, - ) -> (Res, Ty<'tcx>) { - let def_id = self.tcx.require_lang_item(lang_item, Some(span)); - let def_kind = self.tcx.def_kind(def_id); - - let item_ty = if let DefKind::Variant = def_kind { - self.tcx.type_of(self.tcx.parent(def_id).expect("variant w/out parent")) - } else { - self.tcx.type_of(def_id) - }; - let substs = self.infcx.fresh_substs_for_item(span, def_id); - let ty = item_ty.subst(self.tcx, substs); - - self.write_resolution(hir_id, Ok((def_kind, def_id))); - self.add_required_obligations(span, def_id, &substs); - (Res::Def(def_kind, def_id), ty) - } - - /// Resolves an associated value path into a base type and associated constant, or method - /// resolution. The newly resolved definition is written into `type_dependent_defs`. - pub fn resolve_ty_and_res_ufcs<'b>( - &self, - qpath: &'b QPath<'b>, - hir_id: hir::HirId, - span: Span, - ) -> (Res, Option<Ty<'tcx>>, &'b [hir::PathSegment<'b>]) { - debug!("resolve_ty_and_res_ufcs: qpath={:?} hir_id={:?} span={:?}", qpath, hir_id, span); - let (ty, qself, item_segment) = match *qpath { - QPath::Resolved(ref opt_qself, ref path) => { - return ( - path.res, - opt_qself.as_ref().map(|qself| self.to_ty(qself)), - &path.segments[..], - ); - } - QPath::TypeRelative(ref qself, ref segment) => (self.to_ty(qself), qself, segment), - QPath::LangItem(..) => bug!("`resolve_ty_and_res_ufcs` called on `LangItem`"), - }; - if let Some(&cached_result) = self.typeck_results.borrow().type_dependent_defs().get(hir_id) - { - // Return directly on cache hit. This is useful to avoid doubly reporting - // errors with default match binding modes. See #44614. - let def = - cached_result.map(|(kind, def_id)| Res::Def(kind, def_id)).unwrap_or(Res::Err); - return (def, Some(ty), slice::from_ref(&**item_segment)); - } - let item_name = item_segment.ident; - let result = self.resolve_ufcs(span, item_name, ty, hir_id).or_else(|error| { - let result = match error { - method::MethodError::PrivateMatch(kind, def_id, _) => Ok((kind, def_id)), - _ => Err(ErrorReported), - }; - if item_name.name != kw::Invalid { - if let Some(mut e) = self.report_method_error( - span, - ty, - item_name, - SelfSource::QPath(qself), - error, - None, - ) { - e.emit(); - } - } - result - }); - - // Write back the new resolution. - self.write_resolution(hir_id, result); - ( - result.map(|(kind, def_id)| Res::Def(kind, def_id)).unwrap_or(Res::Err), - Some(ty), - slice::from_ref(&**item_segment), - ) - } - - pub fn check_decl_initializer( - &self, - local: &'tcx hir::Local<'tcx>, - init: &'tcx hir::Expr<'tcx>, - ) -> Ty<'tcx> { - // FIXME(tschottdorf): `contains_explicit_ref_binding()` must be removed - // for #42640 (default match binding modes). - // - // See #44848. - let ref_bindings = local.pat.contains_explicit_ref_binding(); - - let local_ty = self.local_ty(init.span, local.hir_id).revealed_ty; - if let Some(m) = ref_bindings { - // Somewhat subtle: if we have a `ref` binding in the pattern, - // we want to avoid introducing coercions for the RHS. This is - // both because it helps preserve sanity and, in the case of - // ref mut, for soundness (issue #23116). In particular, in - // the latter case, we need to be clear that the type of the - // referent for the reference that results is *equal to* the - // type of the place it is referencing, and not some - // supertype thereof. - let init_ty = self.check_expr_with_needs(init, Needs::maybe_mut_place(m)); - self.demand_eqtype(init.span, local_ty, init_ty); - init_ty - } else { - self.check_expr_coercable_to_type(init, local_ty, None) - } - } - - /// Type check a `let` statement. - pub fn check_decl_local(&self, local: &'tcx hir::Local<'tcx>) { - // Determine and write the type which we'll check the pattern against. - let ty = self.local_ty(local.span, local.hir_id).decl_ty; - self.write_ty(local.hir_id, ty); - - // Type check the initializer. - if let Some(ref init) = local.init { - let init_ty = self.check_decl_initializer(local, &init); - self.overwrite_local_ty_if_err(local, ty, init_ty); - } - - // Does the expected pattern type originate from an expression and what is the span? - let (origin_expr, ty_span) = match (local.ty, local.init) { - (Some(ty), _) => (false, Some(ty.span)), // Bias towards the explicit user type. - (_, Some(init)) => (true, Some(init.span)), // No explicit type; so use the scrutinee. - _ => (false, None), // We have `let $pat;`, so the expected type is unconstrained. - }; - - // Type check the pattern. Override if necessary to avoid knock-on errors. - self.check_pat_top(&local.pat, ty, ty_span, origin_expr); - let pat_ty = self.node_ty(local.pat.hir_id); - self.overwrite_local_ty_if_err(local, ty, pat_ty); - } - - fn overwrite_local_ty_if_err( - &self, - local: &'tcx hir::Local<'tcx>, - decl_ty: Ty<'tcx>, - ty: Ty<'tcx>, - ) { - if ty.references_error() { - // Override the types everywhere with `err()` to avoid knock on errors. - self.write_ty(local.hir_id, ty); - self.write_ty(local.pat.hir_id, ty); - let local_ty = LocalTy { decl_ty, revealed_ty: ty }; - self.locals.borrow_mut().insert(local.hir_id, local_ty); - self.locals.borrow_mut().insert(local.pat.hir_id, local_ty); - } - } - - pub(super) fn suggest_semicolon_at_end(&self, span: Span, err: &mut DiagnosticBuilder<'_>) { - err.span_suggestion_short( - span.shrink_to_hi(), - "consider using a semicolon here", - ";".to_string(), - Applicability::MachineApplicable, - ); - } - - pub fn check_stmt(&self, stmt: &'tcx hir::Stmt<'tcx>) { - // Don't do all the complex logic below for `DeclItem`. - match stmt.kind { - hir::StmtKind::Item(..) => return, - hir::StmtKind::Local(..) | hir::StmtKind::Expr(..) | hir::StmtKind::Semi(..) => {} - } - - self.warn_if_unreachable(stmt.hir_id, stmt.span, "statement"); - - // Hide the outer diverging and `has_errors` flags. - let old_diverges = self.diverges.replace(Diverges::Maybe); - let old_has_errors = self.has_errors.replace(false); - - match stmt.kind { - hir::StmtKind::Local(ref l) => { - self.check_decl_local(&l); - } - // Ignore for now. - hir::StmtKind::Item(_) => {} - hir::StmtKind::Expr(ref expr) => { - // Check with expected type of `()`. - self.check_expr_has_type_or_error(&expr, self.tcx.mk_unit(), |err| { - self.suggest_semicolon_at_end(expr.span, err); - }); - } - hir::StmtKind::Semi(ref expr) => { - self.check_expr(&expr); - } - } - - // Combine the diverging and `has_error` flags. - self.diverges.set(self.diverges.get() | old_diverges); - self.has_errors.set(self.has_errors.get() | old_has_errors); - } - - pub fn check_block_no_value(&self, blk: &'tcx hir::Block<'tcx>) { - let unit = self.tcx.mk_unit(); - let ty = self.check_block_with_expected(blk, ExpectHasType(unit)); - - // if the block produces a `!` value, that can always be - // (effectively) coerced to unit. - if !ty.is_never() { - self.demand_suptype(blk.span, unit, ty); - } - } - - /// If `expr` is a `match` expression that has only one non-`!` arm, use that arm's tail - /// expression's `Span`, otherwise return `expr.span`. This is done to give better errors - /// when given code like the following: - /// ```text - /// if false { return 0i32; } else { 1u32 } - /// // ^^^^ point at this instead of the whole `if` expression - /// ``` - fn get_expr_coercion_span(&self, expr: &hir::Expr<'_>) -> rustc_span::Span { - if let hir::ExprKind::Match(_, arms, _) = &expr.kind { - let arm_spans: Vec<Span> = arms - .iter() - .filter_map(|arm| { - self.in_progress_typeck_results - .and_then(|typeck_results| { - typeck_results.borrow().node_type_opt(arm.body.hir_id) - }) - .and_then(|arm_ty| { - if arm_ty.is_never() { - None - } else { - Some(match &arm.body.kind { - // Point at the tail expression when possible. - hir::ExprKind::Block(block, _) => { - block.expr.as_ref().map(|e| e.span).unwrap_or(block.span) - } - _ => arm.body.span, - }) - } - }) - }) - .collect(); - if arm_spans.len() == 1 { - return arm_spans[0]; - } - } - expr.span - } - - pub(super) fn check_block_with_expected( - &self, - blk: &'tcx hir::Block<'tcx>, - expected: Expectation<'tcx>, - ) -> Ty<'tcx> { - let prev = { - let mut fcx_ps = self.ps.borrow_mut(); - let unsafety_state = fcx_ps.recurse(blk); - replace(&mut *fcx_ps, unsafety_state) - }; - - // In some cases, blocks have just one exit, but other blocks - // can be targeted by multiple breaks. This can happen both - // with labeled blocks as well as when we desugar - // a `try { ... }` expression. - // - // Example 1: - // - // 'a: { if true { break 'a Err(()); } Ok(()) } - // - // Here we would wind up with two coercions, one from - // `Err(())` and the other from the tail expression - // `Ok(())`. If the tail expression is omitted, that's a - // "forced unit" -- unless the block diverges, in which - // case we can ignore the tail expression (e.g., `'a: { - // break 'a 22; }` would not force the type of the block - // to be `()`). - let tail_expr = blk.expr.as_ref(); - let coerce_to_ty = expected.coercion_target_type(self, blk.span); - let coerce = if blk.targeted_by_break { - CoerceMany::new(coerce_to_ty) - } else { - let tail_expr: &[&hir::Expr<'_>] = match tail_expr { - Some(e) => slice::from_ref(e), - None => &[], - }; - CoerceMany::with_coercion_sites(coerce_to_ty, tail_expr) - }; - - let prev_diverges = self.diverges.get(); - let ctxt = BreakableCtxt { coerce: Some(coerce), may_break: false }; - - let (ctxt, ()) = self.with_breakable_ctxt(blk.hir_id, ctxt, || { - for s in blk.stmts { - self.check_stmt(s); - } - - // check the tail expression **without** holding the - // `enclosing_breakables` lock below. - let tail_expr_ty = tail_expr.map(|t| self.check_expr_with_expectation(t, expected)); - - let mut enclosing_breakables = self.enclosing_breakables.borrow_mut(); - let ctxt = enclosing_breakables.find_breakable(blk.hir_id); - let coerce = ctxt.coerce.as_mut().unwrap(); - if let Some(tail_expr_ty) = tail_expr_ty { - let tail_expr = tail_expr.unwrap(); - let span = self.get_expr_coercion_span(tail_expr); - let cause = self.cause(span, ObligationCauseCode::BlockTailExpression(blk.hir_id)); - coerce.coerce(self, &cause, tail_expr, tail_expr_ty); - } else { - // Subtle: if there is no explicit tail expression, - // that is typically equivalent to a tail expression - // of `()` -- except if the block diverges. In that - // case, there is no value supplied from the tail - // expression (assuming there are no other breaks, - // this implies that the type of the block will be - // `!`). - // - // #41425 -- label the implicit `()` as being the - // "found type" here, rather than the "expected type". - if !self.diverges.get().is_always() { - // #50009 -- Do not point at the entire fn block span, point at the return type - // span, as it is the cause of the requirement, and - // `consider_hint_about_removing_semicolon` will point at the last expression - // if it were a relevant part of the error. This improves usability in editors - // that highlight errors inline. - let mut sp = blk.span; - let mut fn_span = None; - if let Some((decl, ident)) = self.get_parent_fn_decl(blk.hir_id) { - let ret_sp = decl.output.span(); - if let Some(block_sp) = self.parent_item_span(blk.hir_id) { - // HACK: on some cases (`ui/liveness/liveness-issue-2163.rs`) the - // output would otherwise be incorrect and even misleading. Make sure - // the span we're aiming at correspond to a `fn` body. - if block_sp == blk.span { - sp = ret_sp; - fn_span = Some(ident.span); - } - } - } - coerce.coerce_forced_unit( - self, - &self.misc(sp), - &mut |err| { - if let Some(expected_ty) = expected.only_has_type(self) { - self.consider_hint_about_removing_semicolon(blk, expected_ty, err); - } - if let Some(fn_span) = fn_span { - err.span_label( - fn_span, - "implicitly returns `()` as its body has no tail or `return` \ - expression", - ); - } - }, - false, - ); - } - } - }); - - if ctxt.may_break { - // If we can break from the block, then the block's exit is always reachable - // (... as long as the entry is reachable) - regardless of the tail of the block. - self.diverges.set(prev_diverges); - } - - let mut ty = ctxt.coerce.unwrap().complete(self); - - if self.has_errors.get() || ty.references_error() { - ty = self.tcx.ty_error() - } - - self.write_ty(blk.hir_id, ty); - - *self.ps.borrow_mut() = prev; - ty - } - - fn parent_item_span(&self, id: hir::HirId) -> Option<Span> { - let node = self.tcx.hir().get(self.tcx.hir().get_parent_item(id)); - match node { - Node::Item(&hir::Item { kind: hir::ItemKind::Fn(_, _, body_id), .. }) - | Node::ImplItem(&hir::ImplItem { kind: hir::ImplItemKind::Fn(_, body_id), .. }) => { - let body = self.tcx.hir().body(body_id); - if let ExprKind::Block(block, _) = &body.value.kind { - return Some(block.span); - } - } - _ => {} - } - None - } - - /// Given a function block's `HirId`, returns its `FnDecl` if it exists, or `None` otherwise. - fn get_parent_fn_decl(&self, blk_id: hir::HirId) -> Option<(&'tcx hir::FnDecl<'tcx>, Ident)> { - let parent = self.tcx.hir().get(self.tcx.hir().get_parent_item(blk_id)); - self.get_node_fn_decl(parent).map(|(fn_decl, ident, _)| (fn_decl, ident)) - } - - /// Given a function `Node`, return its `FnDecl` if it exists, or `None` otherwise. - pub(super) fn get_node_fn_decl( - &self, - node: Node<'tcx>, - ) -> Option<(&'tcx hir::FnDecl<'tcx>, Ident, bool)> { - match node { - Node::Item(&hir::Item { ident, kind: hir::ItemKind::Fn(ref sig, ..), .. }) => { - // This is less than ideal, it will not suggest a return type span on any - // method called `main`, regardless of whether it is actually the entry point, - // but it will still present it as the reason for the expected type. - Some((&sig.decl, ident, ident.name != sym::main)) - } - Node::TraitItem(&hir::TraitItem { - ident, - kind: hir::TraitItemKind::Fn(ref sig, ..), - .. - }) => Some((&sig.decl, ident, true)), - Node::ImplItem(&hir::ImplItem { - ident, - kind: hir::ImplItemKind::Fn(ref sig, ..), - .. - }) => Some((&sig.decl, ident, false)), - _ => None, - } - } - - /// Given a `HirId`, return the `FnDecl` of the method it is enclosed by and whether a - /// suggestion can be made, `None` otherwise. - pub fn get_fn_decl(&self, blk_id: hir::HirId) -> Option<(&'tcx hir::FnDecl<'tcx>, bool)> { - // Get enclosing Fn, if it is a function or a trait method, unless there's a `loop` or - // `while` before reaching it, as block tail returns are not available in them. - self.tcx.hir().get_return_block(blk_id).and_then(|blk_id| { - let parent = self.tcx.hir().get(blk_id); - self.get_node_fn_decl(parent).map(|(fn_decl, _, is_main)| (fn_decl, is_main)) - }) - } - - /// On implicit return expressions with mismatched types, provides the following suggestions: - /// - /// - Points out the method's return type as the reason for the expected type. - /// - Possible missing semicolon. - /// - Possible missing return type if the return type is the default, and not `fn main()`. - pub fn suggest_mismatched_types_on_tail( - &self, - err: &mut DiagnosticBuilder<'_>, - expr: &'tcx hir::Expr<'tcx>, - expected: Ty<'tcx>, - found: Ty<'tcx>, - cause_span: Span, - blk_id: hir::HirId, - ) -> bool { - let expr = expr.peel_drop_temps(); - self.suggest_missing_semicolon(err, expr, expected, cause_span); - let mut pointing_at_return_type = false; - if let Some((fn_decl, can_suggest)) = self.get_fn_decl(blk_id) { - pointing_at_return_type = - self.suggest_missing_return_type(err, &fn_decl, expected, found, can_suggest); - } - pointing_at_return_type - } - - /// When encountering an fn-like ctor that needs to unify with a value, check whether calling - /// the ctor would successfully solve the type mismatch and if so, suggest it: - /// ``` - /// fn foo(x: usize) -> usize { x } - /// let x: usize = foo; // suggest calling the `foo` function: `foo(42)` - /// ``` - fn suggest_fn_call( - &self, - err: &mut DiagnosticBuilder<'_>, - expr: &hir::Expr<'_>, - expected: Ty<'tcx>, - found: Ty<'tcx>, - ) -> bool { - let hir = self.tcx.hir(); - let (def_id, sig) = match *found.kind() { - ty::FnDef(def_id, _) => (def_id, found.fn_sig(self.tcx)), - ty::Closure(def_id, substs) => (def_id, substs.as_closure().sig()), - _ => return false, - }; - - let sig = self.replace_bound_vars_with_fresh_vars(expr.span, infer::FnCall, &sig).0; - let sig = self.normalize_associated_types_in(expr.span, &sig); - if self.can_coerce(sig.output(), expected) { - let (mut sugg_call, applicability) = if sig.inputs().is_empty() { - (String::new(), Applicability::MachineApplicable) - } else { - ("...".to_string(), Applicability::HasPlaceholders) - }; - let mut msg = "call this function"; - match hir.get_if_local(def_id) { - Some( - Node::Item(hir::Item { kind: ItemKind::Fn(.., body_id), .. }) - | Node::ImplItem(hir::ImplItem { - kind: hir::ImplItemKind::Fn(_, body_id), .. - }) - | Node::TraitItem(hir::TraitItem { - kind: hir::TraitItemKind::Fn(.., hir::TraitFn::Provided(body_id)), - .. - }), - ) => { - let body = hir.body(*body_id); - sugg_call = body - .params - .iter() - .map(|param| match ¶m.pat.kind { - hir::PatKind::Binding(_, _, ident, None) - if ident.name != kw::SelfLower => - { - ident.to_string() - } - _ => "_".to_string(), - }) - .collect::<Vec<_>>() - .join(", "); - } - Some(Node::Expr(hir::Expr { - kind: ExprKind::Closure(_, _, body_id, _, _), - span: full_closure_span, - .. - })) => { - if *full_closure_span == expr.span { - return false; - } - msg = "call this closure"; - let body = hir.body(*body_id); - sugg_call = body - .params - .iter() - .map(|param| match ¶m.pat.kind { - hir::PatKind::Binding(_, _, ident, None) - if ident.name != kw::SelfLower => - { - ident.to_string() - } - _ => "_".to_string(), - }) - .collect::<Vec<_>>() - .join(", "); - } - Some(Node::Ctor(hir::VariantData::Tuple(fields, _))) => { - sugg_call = fields.iter().map(|_| "_").collect::<Vec<_>>().join(", "); - match def_id.as_local().map(|def_id| hir.def_kind(def_id)) { - Some(DefKind::Ctor(hir::def::CtorOf::Variant, _)) => { - msg = "instantiate this tuple variant"; - } - Some(DefKind::Ctor(CtorOf::Struct, _)) => { - msg = "instantiate this tuple struct"; - } - _ => {} - } - } - Some(Node::ForeignItem(hir::ForeignItem { - kind: hir::ForeignItemKind::Fn(_, idents, _), - .. - })) => { - sugg_call = idents - .iter() - .map(|ident| { - if ident.name != kw::SelfLower { - ident.to_string() - } else { - "_".to_string() - } - }) - .collect::<Vec<_>>() - .join(", ") - } - Some(Node::TraitItem(hir::TraitItem { - kind: hir::TraitItemKind::Fn(.., hir::TraitFn::Required(idents)), - .. - })) => { - sugg_call = idents - .iter() - .map(|ident| { - if ident.name != kw::SelfLower { - ident.to_string() - } else { - "_".to_string() - } - }) - .collect::<Vec<_>>() - .join(", ") - } - _ => {} - } - err.span_suggestion_verbose( - expr.span.shrink_to_hi(), - &format!("use parentheses to {}", msg), - format!("({})", sugg_call), - applicability, - ); - return true; - } - false - } - - pub fn suggest_deref_ref_or_into( - &self, - err: &mut DiagnosticBuilder<'_>, - expr: &hir::Expr<'_>, - expected: Ty<'tcx>, - found: Ty<'tcx>, - expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>, - ) { - if let Some((sp, msg, suggestion, applicability)) = self.check_ref(expr, found, expected) { - err.span_suggestion(sp, msg, suggestion, applicability); - } else if let (ty::FnDef(def_id, ..), true) = - (&found.kind(), self.suggest_fn_call(err, expr, expected, found)) - { - if let Some(sp) = self.tcx.hir().span_if_local(*def_id) { - let sp = self.sess().source_map().guess_head_span(sp); - err.span_label(sp, &format!("{} defined here", found)); - } - } else if !self.check_for_cast(err, expr, found, expected, expected_ty_expr) { - let is_struct_pat_shorthand_field = - self.is_hir_id_from_struct_pattern_shorthand_field(expr.hir_id, expr.span); - let methods = self.get_conversion_methods(expr.span, expected, found, expr.hir_id); - if let Ok(expr_text) = self.sess().source_map().span_to_snippet(expr.span) { - let mut suggestions = iter::repeat(&expr_text) - .zip(methods.iter()) - .filter_map(|(receiver, method)| { - let method_call = format!(".{}()", method.ident); - if receiver.ends_with(&method_call) { - None // do not suggest code that is already there (#53348) - } else { - let method_call_list = [".to_vec()", ".to_string()"]; - let sugg = if receiver.ends_with(".clone()") - && method_call_list.contains(&method_call.as_str()) - { - let max_len = receiver.rfind('.').unwrap(); - format!("{}{}", &receiver[..max_len], method_call) - } else { - if expr.precedence().order() < ExprPrecedence::MethodCall.order() { - format!("({}){}", receiver, method_call) - } else { - format!("{}{}", receiver, method_call) - } - }; - Some(if is_struct_pat_shorthand_field { - format!("{}: {}", receiver, sugg) - } else { - sugg - }) - } - }) - .peekable(); - if suggestions.peek().is_some() { - err.span_suggestions( - expr.span, - "try using a conversion method", - suggestions, - Applicability::MaybeIncorrect, - ); - } - } - } - } - - /// When encountering the expected boxed value allocated in the stack, suggest allocating it - /// in the heap by calling `Box::new()`. - pub(super) fn suggest_boxing_when_appropriate( - &self, - err: &mut DiagnosticBuilder<'_>, - expr: &hir::Expr<'_>, - expected: Ty<'tcx>, - found: Ty<'tcx>, - ) { - if self.tcx.hir().is_inside_const_context(expr.hir_id) { - // Do not suggest `Box::new` in const context. - return; - } - if !expected.is_box() || found.is_box() { - return; - } - let boxed_found = self.tcx.mk_box(found); - if let (true, Ok(snippet)) = ( - self.can_coerce(boxed_found, expected), - self.sess().source_map().span_to_snippet(expr.span), - ) { - err.span_suggestion( - expr.span, - "store this in the heap by calling `Box::new`", - format!("Box::new({})", snippet), - Applicability::MachineApplicable, - ); - err.note( - "for more on the distinction between the stack and the heap, read \ - https://doc.rust-lang.org/book/ch15-01-box.html, \ - https://doc.rust-lang.org/rust-by-example/std/box.html, and \ - https://doc.rust-lang.org/std/boxed/index.html", - ); - } - } - - pub(super) fn note_internal_mutation_in_method( - &self, - err: &mut DiagnosticBuilder<'_>, - expr: &hir::Expr<'_>, - expected: Ty<'tcx>, - found: Ty<'tcx>, - ) { - if found != self.tcx.types.unit { - return; - } - if let ExprKind::MethodCall(path_segment, _, [rcvr, ..], _) = expr.kind { - if self - .typeck_results - .borrow() - .expr_ty_adjusted_opt(rcvr) - .map_or(true, |ty| expected.peel_refs() != ty.peel_refs()) - { - return; - } - let mut sp = MultiSpan::from_span(path_segment.ident.span); - sp.push_span_label( - path_segment.ident.span, - format!( - "this call modifies {} in-place", - match rcvr.kind { - ExprKind::Path(QPath::Resolved( - None, - hir::Path { segments: [segment], .. }, - )) => format!("`{}`", segment.ident), - _ => "its receiver".to_string(), - } - ), - ); - sp.push_span_label( - rcvr.span, - "you probably want to use this value after calling the method...".to_string(), - ); - err.span_note( - sp, - &format!("method `{}` modifies its receiver in-place", path_segment.ident), - ); - err.note(&format!("...instead of the `()` output of method `{}`", path_segment.ident)); - } - } - - /// When encountering an `impl Future` where `BoxFuture` is expected, suggest `Box::pin`. - pub(super) fn suggest_calling_boxed_future_when_appropriate( - &self, - err: &mut DiagnosticBuilder<'_>, - expr: &hir::Expr<'_>, - expected: Ty<'tcx>, - found: Ty<'tcx>, - ) -> bool { - // Handle #68197. - - if self.tcx.hir().is_inside_const_context(expr.hir_id) { - // Do not suggest `Box::new` in const context. - return false; - } - let pin_did = self.tcx.lang_items().pin_type(); - match expected.kind() { - ty::Adt(def, _) if Some(def.did) != pin_did => return false, - // This guards the `unwrap` and `mk_box` below. - _ if pin_did.is_none() || self.tcx.lang_items().owned_box().is_none() => return false, - _ => {} - } - let boxed_found = self.tcx.mk_box(found); - let new_found = self.tcx.mk_lang_item(boxed_found, LangItem::Pin).unwrap(); - if let (true, Ok(snippet)) = ( - self.can_coerce(new_found, expected), - self.sess().source_map().span_to_snippet(expr.span), - ) { - match found.kind() { - ty::Adt(def, _) if def.is_box() => { - err.help("use `Box::pin`"); - } - _ => { - err.span_suggestion( - expr.span, - "you need to pin and box this expression", - format!("Box::pin({})", snippet), - Applicability::MachineApplicable, - ); - } - } - true - } else { - false - } - } - - /// A common error is to forget to add a semicolon at the end of a block, e.g., - /// - /// ``` - /// fn foo() { - /// bar_that_returns_u32() - /// } - /// ``` - /// - /// This routine checks if the return expression in a block would make sense on its own as a - /// statement and the return type has been left as default or has been specified as `()`. If so, - /// it suggests adding a semicolon. - fn suggest_missing_semicolon( - &self, - err: &mut DiagnosticBuilder<'_>, - expression: &'tcx hir::Expr<'tcx>, - expected: Ty<'tcx>, - cause_span: Span, - ) { - if expected.is_unit() { - // `BlockTailExpression` only relevant if the tail expr would be - // useful on its own. - match expression.kind { - ExprKind::Call(..) - | ExprKind::MethodCall(..) - | ExprKind::Loop(..) - | ExprKind::Match(..) - | ExprKind::Block(..) => { - err.span_suggestion( - cause_span.shrink_to_hi(), - "try adding a semicolon", - ";".to_string(), - Applicability::MachineApplicable, - ); - } - _ => (), - } - } - } - - /// A possible error is to forget to add a return type that is needed: - /// - /// ``` - /// fn foo() { - /// bar_that_returns_u32() - /// } - /// ``` - /// - /// This routine checks if the return type is left as default, the method is not part of an - /// `impl` block and that it isn't the `main` method. If so, it suggests setting the return - /// type. - pub(super) fn suggest_missing_return_type( - &self, - err: &mut DiagnosticBuilder<'_>, - fn_decl: &hir::FnDecl<'_>, - expected: Ty<'tcx>, - found: Ty<'tcx>, - can_suggest: bool, - ) -> bool { - // Only suggest changing the return type for methods that - // haven't set a return type at all (and aren't `fn main()` or an impl). - match (&fn_decl.output, found.is_suggestable(), can_suggest, expected.is_unit()) { - (&hir::FnRetTy::DefaultReturn(span), true, true, true) => { - err.span_suggestion( - span, - "try adding a return type", - format!("-> {} ", self.resolve_vars_with_obligations(found)), - Applicability::MachineApplicable, - ); - true - } - (&hir::FnRetTy::DefaultReturn(span), false, true, true) => { - err.span_label(span, "possibly return type missing here?"); - true - } - (&hir::FnRetTy::DefaultReturn(span), _, false, true) => { - // `fn main()` must return `()`, do not suggest changing return type - err.span_label(span, "expected `()` because of default return type"); - true - } - // expectation was caused by something else, not the default return - (&hir::FnRetTy::DefaultReturn(_), _, _, false) => false, - (&hir::FnRetTy::Return(ref ty), _, _, _) => { - // Only point to return type if the expected type is the return type, as if they - // are not, the expectation must have been caused by something else. - debug!("suggest_missing_return_type: return type {:?} node {:?}", ty, ty.kind); - let sp = ty.span; - let ty = AstConv::ast_ty_to_ty(self, ty); - debug!("suggest_missing_return_type: return type {:?}", ty); - debug!("suggest_missing_return_type: expected type {:?}", ty); - if ty.kind() == expected.kind() { - err.span_label(sp, format!("expected `{}` because of return type", expected)); - return true; - } - false - } - } - } - - /// A possible error is to forget to add `.await` when using futures: - /// - /// ``` - /// async fn make_u32() -> u32 { - /// 22 - /// } - /// - /// fn take_u32(x: u32) {} - /// - /// async fn foo() { - /// let x = make_u32(); - /// take_u32(x); - /// } - /// ``` - /// - /// This routine checks if the found type `T` implements `Future<Output=U>` where `U` is the - /// expected type. If this is the case, and we are inside of an async body, it suggests adding - /// `.await` to the tail of the expression. - pub(super) fn suggest_missing_await( - &self, - err: &mut DiagnosticBuilder<'_>, - expr: &hir::Expr<'_>, - expected: Ty<'tcx>, - found: Ty<'tcx>, - ) { - debug!("suggest_missing_await: expr={:?} expected={:?}, found={:?}", expr, expected, found); - // `.await` is not permitted outside of `async` bodies, so don't bother to suggest if the - // body isn't `async`. - let item_id = self.tcx().hir().get_parent_node(self.body_id); - if let Some(body_id) = self.tcx().hir().maybe_body_owned_by(item_id) { - let body = self.tcx().hir().body(body_id); - if let Some(hir::GeneratorKind::Async(_)) = body.generator_kind { - let sp = expr.span; - // Check for `Future` implementations by constructing a predicate to - // prove: `<T as Future>::Output == U` - let future_trait = self.tcx.require_lang_item(LangItem::Future, Some(sp)); - let item_def_id = self - .tcx - .associated_items(future_trait) - .in_definition_order() - .next() - .unwrap() - .def_id; - // `<T as Future>::Output` - let projection_ty = ty::ProjectionTy { - // `T` - substs: self - .tcx - .mk_substs_trait(found, self.fresh_substs_for_item(sp, item_def_id)), - // `Future::Output` - item_def_id, - }; - - let predicate = ty::PredicateAtom::Projection(ty::ProjectionPredicate { - projection_ty, - ty: expected, - }) - .potentially_quantified(self.tcx, ty::PredicateKind::ForAll); - let obligation = traits::Obligation::new(self.misc(sp), self.param_env, predicate); - - debug!("suggest_missing_await: trying obligation {:?}", obligation); - - if self.infcx.predicate_may_hold(&obligation) { - debug!("suggest_missing_await: obligation held: {:?}", obligation); - if let Ok(code) = self.sess().source_map().span_to_snippet(sp) { - err.span_suggestion( - sp, - "consider using `.await` here", - format!("{}.await", code), - Applicability::MaybeIncorrect, - ); - } else { - debug!("suggest_missing_await: no snippet for {:?}", sp); - } - } else { - debug!("suggest_missing_await: obligation did not hold: {:?}", obligation) - } - } - } - } - - pub(super) fn suggest_missing_parentheses( - &self, - err: &mut DiagnosticBuilder<'_>, - expr: &hir::Expr<'_>, - ) { - let sp = self.tcx.sess.source_map().start_point(expr.span); - if let Some(sp) = self.tcx.sess.parse_sess.ambiguous_block_expr_parse.borrow().get(&sp) { - // `{ 42 } &&x` (#61475) or `{ 42 } && if x { 1 } else { 0 }` - self.tcx.sess.parse_sess.expr_parentheses_needed(err, *sp, None); - } - } - - pub(super) fn note_need_for_fn_pointer( - &self, - err: &mut DiagnosticBuilder<'_>, - expected: Ty<'tcx>, - found: Ty<'tcx>, - ) { - let (sig, did, substs) = match (&expected.kind(), &found.kind()) { - (ty::FnDef(did1, substs1), ty::FnDef(did2, substs2)) => { - let sig1 = self.tcx.fn_sig(*did1).subst(self.tcx, substs1); - let sig2 = self.tcx.fn_sig(*did2).subst(self.tcx, substs2); - if sig1 != sig2 { - return; - } - err.note( - "different `fn` items always have unique types, even if their signatures are \ - the same", - ); - (sig1, *did1, substs1) - } - (ty::FnDef(did, substs), ty::FnPtr(sig2)) => { - let sig1 = self.tcx.fn_sig(*did).subst(self.tcx, substs); - if sig1 != *sig2 { - return; - } - (sig1, *did, substs) - } - _ => return, - }; - err.help(&format!("change the expected type to be function pointer `{}`", sig)); - err.help(&format!( - "if the expected type is due to type inference, cast the expected `fn` to a function \ - pointer: `{} as {}`", - self.tcx.def_path_str_with_substs(did, substs), - sig - )); - } - - /// A common error is to add an extra semicolon: - /// - /// ``` - /// fn foo() -> usize { - /// 22; - /// } - /// ``` - /// - /// This routine checks if the final statement in a block is an - /// expression with an explicit semicolon whose type is compatible - /// with `expected_ty`. If so, it suggests removing the semicolon. - fn consider_hint_about_removing_semicolon( - &self, - blk: &'tcx hir::Block<'tcx>, - expected_ty: Ty<'tcx>, - err: &mut DiagnosticBuilder<'_>, - ) { - if let Some(span_semi) = self.could_remove_semicolon(blk, expected_ty) { - err.span_suggestion( - span_semi, - "consider removing this semicolon", - String::new(), - Applicability::MachineApplicable, - ); - } - } - - pub(super) fn could_remove_semicolon( - &self, - blk: &'tcx hir::Block<'tcx>, - expected_ty: Ty<'tcx>, - ) -> Option<Span> { - // Be helpful when the user wrote `{... expr;}` and - // taking the `;` off is enough to fix the error. - let last_stmt = blk.stmts.last()?; - let last_expr = match last_stmt.kind { - hir::StmtKind::Semi(ref e) => e, - _ => return None, - }; - let last_expr_ty = self.node_ty(last_expr.hir_id); - if matches!(last_expr_ty.kind(), ty::Error(_)) - || self.can_sub(self.param_env, last_expr_ty, expected_ty).is_err() - { - return None; - } - let original_span = original_sp(last_stmt.span, blk.span); - Some(original_span.with_lo(original_span.hi() - BytePos(1))) - } - - // Instantiates the given path, which must refer to an item with the given - // number of type parameters and type. - pub fn instantiate_value_path( - &self, - segments: &[hir::PathSegment<'_>], - self_ty: Option<Ty<'tcx>>, - res: Res, - span: Span, - hir_id: hir::HirId, - ) -> (Ty<'tcx>, Res) { - debug!( - "instantiate_value_path(segments={:?}, self_ty={:?}, res={:?}, hir_id={})", - segments, self_ty, res, hir_id, - ); - - let tcx = self.tcx; - - let path_segs = match res { - Res::Local(_) | Res::SelfCtor(_) => vec![], - Res::Def(kind, def_id) => { - AstConv::def_ids_for_value_path_segments(self, segments, self_ty, kind, def_id) - } - _ => bug!("instantiate_value_path on {:?}", res), - }; - - let mut user_self_ty = None; - let mut is_alias_variant_ctor = false; - match res { - Res::Def(DefKind::Ctor(CtorOf::Variant, _), _) => { - if let Some(self_ty) = self_ty { - let adt_def = self_ty.ty_adt_def().unwrap(); - user_self_ty = Some(UserSelfTy { impl_def_id: adt_def.did, self_ty }); - is_alias_variant_ctor = true; - } - } - Res::Def(DefKind::AssocFn | DefKind::AssocConst, def_id) => { - let container = tcx.associated_item(def_id).container; - debug!("instantiate_value_path: def_id={:?} container={:?}", def_id, container); - match container { - ty::TraitContainer(trait_did) => { - callee::check_legal_trait_for_method_call(tcx, span, None, trait_did) - } - ty::ImplContainer(impl_def_id) => { - if segments.len() == 1 { - // `<T>::assoc` will end up here, and so - // can `T::assoc`. It this came from an - // inherent impl, we need to record the - // `T` for posterity (see `UserSelfTy` for - // details). - let self_ty = self_ty.expect("UFCS sugared assoc missing Self"); - user_self_ty = Some(UserSelfTy { impl_def_id, self_ty }); - } - } - } - } - _ => {} - } - - // Now that we have categorized what space the parameters for each - // segment belong to, let's sort out the parameters that the user - // provided (if any) into their appropriate spaces. We'll also report - // errors if type parameters are provided in an inappropriate place. - - let generic_segs: FxHashSet<_> = path_segs.iter().map(|PathSeg(_, index)| index).collect(); - let generics_has_err = AstConv::prohibit_generics( - self, - segments.iter().enumerate().filter_map(|(index, seg)| { - if !generic_segs.contains(&index) || is_alias_variant_ctor { - Some(seg) - } else { - None - } - }), - ); - - if let Res::Local(hid) = res { - let ty = self.local_ty(span, hid).decl_ty; - let ty = self.normalize_associated_types_in(span, &ty); - self.write_ty(hir_id, ty); - return (ty, res); - } - - if generics_has_err { - // Don't try to infer type parameters when prohibited generic arguments were given. - user_self_ty = None; - } - - // Now we have to compare the types that the user *actually* - // provided against the types that were *expected*. If the user - // did not provide any types, then we want to substitute inference - // variables. If the user provided some types, we may still need - // to add defaults. If the user provided *too many* types, that's - // a problem. - - let mut infer_args_for_err = FxHashSet::default(); - for &PathSeg(def_id, index) in &path_segs { - let seg = &segments[index]; - let generics = tcx.generics_of(def_id); - // Argument-position `impl Trait` is treated as a normal generic - // parameter internally, but we don't allow users to specify the - // parameter's value explicitly, so we have to do some error- - // checking here. - if let GenericArgCountResult { - correct: Err(GenericArgCountMismatch { reported: Some(ErrorReported), .. }), - .. - } = AstConv::check_generic_arg_count_for_call( - tcx, span, &generics, &seg, false, // `is_method_call` - ) { - infer_args_for_err.insert(index); - self.set_tainted_by_errors(); // See issue #53251. - } - } - - let has_self = path_segs - .last() - .map(|PathSeg(def_id, _)| tcx.generics_of(*def_id).has_self) - .unwrap_or(false); - - let (res, self_ctor_substs) = if let Res::SelfCtor(impl_def_id) = res { - let ty = self.normalize_ty(span, tcx.at(span).type_of(impl_def_id)); - match *ty.kind() { - ty::Adt(adt_def, substs) if adt_def.has_ctor() => { - let variant = adt_def.non_enum_variant(); - let ctor_def_id = variant.ctor_def_id.unwrap(); - ( - Res::Def(DefKind::Ctor(CtorOf::Struct, variant.ctor_kind), ctor_def_id), - Some(substs), - ) - } - _ => { - let mut err = tcx.sess.struct_span_err( - span, - "the `Self` constructor can only be used with tuple or unit structs", - ); - if let Some(adt_def) = ty.ty_adt_def() { - match adt_def.adt_kind() { - AdtKind::Enum => { - err.help("did you mean to use one of the enum's variants?"); - } - AdtKind::Struct | AdtKind::Union => { - err.span_suggestion( - span, - "use curly brackets", - String::from("Self { /* fields */ }"), - Applicability::HasPlaceholders, - ); - } - } - } - err.emit(); - - return (tcx.ty_error(), res); - } - } - } else { - (res, None) - }; - let def_id = res.def_id(); - - // The things we are substituting into the type should not contain - // escaping late-bound regions, and nor should the base type scheme. - let ty = tcx.type_of(def_id); - - let arg_count = GenericArgCountResult { - explicit_late_bound: ExplicitLateBound::No, - correct: if infer_args_for_err.is_empty() { - Ok(()) - } else { - Err(GenericArgCountMismatch::default()) - }, - }; - - let substs = self_ctor_substs.unwrap_or_else(|| { - AstConv::create_substs_for_generic_args( - tcx, - def_id, - &[][..], - has_self, - self_ty, - arg_count, - // Provide the generic args, and whether types should be inferred. - |def_id| { - if let Some(&PathSeg(_, index)) = - path_segs.iter().find(|&PathSeg(did, _)| *did == def_id) - { - // If we've encountered an `impl Trait`-related error, we're just - // going to infer the arguments for better error messages. - if !infer_args_for_err.contains(&index) { - // Check whether the user has provided generic arguments. - if let Some(ref data) = segments[index].args { - return (Some(data), segments[index].infer_args); - } - } - return (None, segments[index].infer_args); - } - - (None, true) - }, - // Provide substitutions for parameters for which (valid) arguments have been provided. - |param, arg| match (¶m.kind, arg) { - (GenericParamDefKind::Lifetime, GenericArg::Lifetime(lt)) => { - AstConv::ast_region_to_region(self, lt, Some(param)).into() - } - (GenericParamDefKind::Type { .. }, GenericArg::Type(ty)) => { - self.to_ty(ty).into() - } - (GenericParamDefKind::Const, GenericArg::Const(ct)) => { - self.const_arg_to_const(&ct.value, param.def_id).into() - } - _ => unreachable!(), - }, - // Provide substitutions for parameters for which arguments are inferred. - |substs, param, infer_args| { - match param.kind { - GenericParamDefKind::Lifetime => { - self.re_infer(Some(param), span).unwrap().into() - } - GenericParamDefKind::Type { has_default, .. } => { - if !infer_args && has_default { - // If we have a default, then we it doesn't matter that we're not - // inferring the type arguments: we provide the default where any - // is missing. - let default = tcx.type_of(param.def_id); - self.normalize_ty( - span, - default.subst_spanned(tcx, substs.unwrap(), Some(span)), - ) - .into() - } else { - // If no type arguments were provided, we have to infer them. - // This case also occurs as a result of some malformed input, e.g. - // a lifetime argument being given instead of a type parameter. - // Using inference instead of `Error` gives better error messages. - self.var_for_def(span, param) - } - } - GenericParamDefKind::Const => { - // FIXME(const_generics:defaults) - // No const parameters were provided, we have to infer them. - self.var_for_def(span, param) - } - } - }, - ) - }); - assert!(!substs.has_escaping_bound_vars()); - assert!(!ty.has_escaping_bound_vars()); - - // First, store the "user substs" for later. - self.write_user_type_annotation_from_substs(hir_id, def_id, substs, user_self_ty); - - self.add_required_obligations(span, def_id, &substs); - - // Substitute the values for the type parameters into the type of - // the referenced item. - let ty_substituted = self.instantiate_type_scheme(span, &substs, &ty); - - if let Some(UserSelfTy { impl_def_id, self_ty }) = user_self_ty { - // In the case of `Foo<T>::method` and `<Foo<T>>::method`, if `method` - // is inherent, there is no `Self` parameter; instead, the impl needs - // type parameters, which we can infer by unifying the provided `Self` - // with the substituted impl type. - // This also occurs for an enum variant on a type alias. - let ty = tcx.type_of(impl_def_id); - - let impl_ty = self.instantiate_type_scheme(span, &substs, &ty); - match self.at(&self.misc(span), self.param_env).sup(impl_ty, self_ty) { - Ok(ok) => self.register_infer_ok_obligations(ok), - Err(_) => { - self.tcx.sess.delay_span_bug( - span, - &format!( - "instantiate_value_path: (UFCS) {:?} was a subtype of {:?} but now is not?", - self_ty, - impl_ty, - ), - ); - } - } - } - - self.check_rustc_args_require_const(def_id, hir_id, span); - - debug!("instantiate_value_path: type of {:?} is {:?}", hir_id, ty_substituted); - self.write_substs(hir_id, substs); - - (ty_substituted, res) - } - - /// Add all the obligations that are required, substituting and normalized appropriately. - fn add_required_obligations(&self, span: Span, def_id: DefId, substs: &SubstsRef<'tcx>) { - let (bounds, spans) = self.instantiate_bounds(span, def_id, &substs); - - for (i, mut obligation) in traits::predicates_for_generics( - traits::ObligationCause::new(span, self.body_id, traits::ItemObligation(def_id)), - self.param_env, - bounds, - ) - .enumerate() - { - // This makes the error point at the bound, but we want to point at the argument - if let Some(span) = spans.get(i) { - obligation.cause.make_mut().code = traits::BindingObligation(def_id, *span); - } - self.register_predicate(obligation); - } - } - - fn check_rustc_args_require_const(&self, def_id: DefId, hir_id: hir::HirId, span: Span) { - // We're only interested in functions tagged with - // #[rustc_args_required_const], so ignore anything that's not. - if !self.tcx.has_attr(def_id, sym::rustc_args_required_const) { - return; - } - - // If our calling expression is indeed the function itself, we're good! - // If not, generate an error that this can only be called directly. - if let Node::Expr(expr) = self.tcx.hir().get(self.tcx.hir().get_parent_node(hir_id)) { - if let ExprKind::Call(ref callee, ..) = expr.kind { - if callee.hir_id == hir_id { - return; - } - } - } - - self.tcx.sess.span_err( - span, - "this function can only be invoked directly, not through a function pointer", - ); - } - - /// Resolves `typ` by a single level if `typ` is a type variable. - /// If no resolution is possible, then an error is reported. - /// Numeric inference variables may be left unresolved. - pub fn structurally_resolved_type(&self, sp: Span, ty: Ty<'tcx>) -> Ty<'tcx> { - let ty = self.resolve_vars_with_obligations(ty); - if !ty.is_ty_var() { - ty - } else { - if !self.is_tainted_by_errors() { - self.emit_inference_failure_err((**self).body_id, sp, ty.into(), E0282) - .note("type must be known at this point") - .emit(); - } - let err = self.tcx.ty_error(); - self.demand_suptype(sp, err, ty); - err - } - } - - pub(super) fn with_breakable_ctxt<F: FnOnce() -> R, R>( - &self, - id: hir::HirId, - ctxt: BreakableCtxt<'tcx>, - f: F, - ) -> (BreakableCtxt<'tcx>, R) { - let index; - { - let mut enclosing_breakables = self.enclosing_breakables.borrow_mut(); - index = enclosing_breakables.stack.len(); - enclosing_breakables.by_id.insert(id, index); - enclosing_breakables.stack.push(ctxt); - } - let result = f(); - let ctxt = { - let mut enclosing_breakables = self.enclosing_breakables.borrow_mut(); - debug_assert!(enclosing_breakables.stack.len() == index + 1); - enclosing_breakables.by_id.remove(&id).expect("missing breakable context"); - enclosing_breakables.stack.pop().expect("missing breakable context") - }; - (ctxt, result) - } - - /// Instantiate a QueryResponse in a probe context, without a - /// good ObligationCause. - pub(super) fn probe_instantiate_query_response( - &self, - span: Span, - original_values: &OriginalQueryValues<'tcx>, - query_result: &Canonical<'tcx, QueryResponse<'tcx, Ty<'tcx>>>, - ) -> InferResult<'tcx, Ty<'tcx>> { - self.instantiate_query_response_and_region_obligations( - &traits::ObligationCause::misc(span, self.body_id), - self.param_env, - original_values, - query_result, - ) - } - - /// Returns `true` if an expression is contained inside the LHS of an assignment expression. - pub(super) fn expr_in_place(&self, mut expr_id: hir::HirId) -> bool { - let mut contained_in_place = false; - - while let hir::Node::Expr(parent_expr) = - self.tcx.hir().get(self.tcx.hir().get_parent_node(expr_id)) - { - match &parent_expr.kind { - hir::ExprKind::Assign(lhs, ..) | hir::ExprKind::AssignOp(_, lhs, ..) => { - if lhs.hir_id == expr_id { - contained_in_place = true; - break; - } - } - _ => (), - } - expr_id = parent_expr.hir_id; - } - - contained_in_place - } -} -impl<'a, 'tcx> Deref for FnCtxt<'a, 'tcx> { - type Target = Inherited<'a, 'tcx>; - fn deref(&self) -> &Self::Target { - &self.inh - } -} - -impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> { - fn tcx<'b>(&'b self) -> TyCtxt<'tcx> { - self.tcx - } - - fn item_def_id(&self) -> Option<DefId> { - None - } - - fn default_constness_for_trait_bounds(&self) -> hir::Constness { - // FIXME: refactor this into a method - let node = self.tcx.hir().get(self.body_id); - if let Some(fn_like) = FnLikeNode::from_node(node) { - fn_like.constness() - } else { - hir::Constness::NotConst - } - } - - fn get_type_parameter_bounds(&self, _: Span, def_id: DefId) -> ty::GenericPredicates<'tcx> { - let tcx = self.tcx; - let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local()); - let item_id = tcx.hir().ty_param_owner(hir_id); - let item_def_id = tcx.hir().local_def_id(item_id); - let generics = tcx.generics_of(item_def_id); - let index = generics.param_def_id_to_index[&def_id]; - ty::GenericPredicates { - parent: None, - predicates: tcx.arena.alloc_from_iter( - self.param_env.caller_bounds().iter().filter_map(|predicate| { - match predicate.skip_binders() { - ty::PredicateAtom::Trait(data, _) if data.self_ty().is_param(index) => { - // HACK(eddyb) should get the original `Span`. - let span = tcx.def_span(def_id); - Some((predicate, span)) - } - _ => None, - } - }), - ), - } - } - - fn re_infer(&self, def: Option<&ty::GenericParamDef>, span: Span) -> Option<ty::Region<'tcx>> { - let v = match def { - Some(def) => infer::EarlyBoundRegion(span, def.name), - None => infer::MiscVariable(span), - }; - Some(self.next_region_var(v)) - } - - fn allow_ty_infer(&self) -> bool { - true - } - - fn ty_infer(&self, param: Option<&ty::GenericParamDef>, span: Span) -> Ty<'tcx> { - if let Some(param) = param { - if let GenericArgKind::Type(ty) = self.var_for_def(span, param).unpack() { - return ty; - } - unreachable!() - } else { - self.next_ty_var(TypeVariableOrigin { - kind: TypeVariableOriginKind::TypeInference, - span, - }) - } - } - - fn ct_infer( - &self, - ty: Ty<'tcx>, - param: Option<&ty::GenericParamDef>, - span: Span, - ) -> &'tcx Const<'tcx> { - if let Some(param) = param { - if let GenericArgKind::Const(ct) = self.var_for_def(span, param).unpack() { - return ct; - } - unreachable!() - } else { - self.next_const_var( - ty, - ConstVariableOrigin { kind: ConstVariableOriginKind::ConstInference, span }, - ) - } - } - - fn projected_ty_from_poly_trait_ref( - &self, - span: Span, - item_def_id: DefId, - item_segment: &hir::PathSegment<'_>, - poly_trait_ref: ty::PolyTraitRef<'tcx>, - ) -> Ty<'tcx> { - let (trait_ref, _) = self.replace_bound_vars_with_fresh_vars( - span, - infer::LateBoundRegionConversionTime::AssocTypeProjection(item_def_id), - &poly_trait_ref, - ); - - let item_substs = <dyn AstConv<'tcx>>::create_substs_for_associated_item( - self, - self.tcx, - span, - item_def_id, - item_segment, - trait_ref.substs, - ); - - self.tcx().mk_projection(item_def_id, item_substs) - } - - fn normalize_ty(&self, span: Span, ty: Ty<'tcx>) -> Ty<'tcx> { - if ty.has_escaping_bound_vars() { - ty // FIXME: normalization and escaping regions - } else { - self.normalize_associated_types_in(span, &ty) - } - } - - fn set_tainted_by_errors(&self) { - self.infcx.set_tainted_by_errors() - } - - fn record_ty(&self, hir_id: hir::HirId, ty: Ty<'tcx>, _span: Span) { - self.write_ty(hir_id, ty) - } -} diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs new file mode 100644 index 00000000000..017b0abd1d6 --- /dev/null +++ b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs @@ -0,0 +1,1469 @@ +use crate::astconv::{ + AstConv, ExplicitLateBound, GenericArgCountMismatch, GenericArgCountResult, PathSeg, +}; +use crate::check::callee::{self, DeferredCallResolution}; +use crate::check::method::{self, MethodCallee, SelfSource}; +use crate::check::{BreakableCtxt, Diverges, Expectation, FallbackMode, FnCtxt, LocalTy}; + +use rustc_data_structures::captures::Captures; +use rustc_data_structures::fx::FxHashSet; +use rustc_errors::{Applicability, DiagnosticBuilder, ErrorReported}; +use rustc_hir as hir; +use rustc_hir::def::{CtorOf, DefKind, Res}; +use rustc_hir::def_id::DefId; +use rustc_hir::lang_items::LangItem; +use rustc_hir::{ExprKind, GenericArg, Node, QPath}; +use rustc_infer::infer::canonical::{Canonical, OriginalQueryValues, QueryResponse}; +use rustc_infer::infer::error_reporting::TypeAnnotationNeeded::E0282; +use rustc_infer::infer::{InferOk, InferResult}; +use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability}; +use rustc_middle::ty::fold::TypeFoldable; +use rustc_middle::ty::subst::{ + self, GenericArgKind, InternalSubsts, Subst, SubstsRef, UserSelfTy, UserSubsts, +}; +use rustc_middle::ty::{ + self, AdtKind, CanonicalUserType, DefIdTree, GenericParamDefKind, ToPolyTraitRef, ToPredicate, + Ty, UserType, +}; +use rustc_session::lint; +use rustc_span::hygiene::DesugaringKind; +use rustc_span::source_map::{original_sp, DUMMY_SP}; +use rustc_span::symbol::{kw, sym, Ident}; +use rustc_span::{self, BytePos, MultiSpan, Span}; +use rustc_trait_selection::infer::InferCtxtExt as _; +use rustc_trait_selection::opaque_types::InferCtxtExt as _; +use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _; +use rustc_trait_selection::traits::{self, ObligationCauseCode, TraitEngine, TraitEngineExt}; + +use std::collections::hash_map::Entry; +use std::slice; + +impl<'a, 'tcx> FnCtxt<'a, 'tcx> { + /// Produces warning on the given node, if the current point in the + /// function is unreachable, and there hasn't been another warning. + pub(in super::super) fn warn_if_unreachable(&self, id: hir::HirId, span: Span, kind: &str) { + // FIXME: Combine these two 'if' expressions into one once + // let chains are implemented + if let Diverges::Always { span: orig_span, custom_note } = self.diverges.get() { + // If span arose from a desugaring of `if` or `while`, then it is the condition itself, + // which diverges, that we are about to lint on. This gives suboptimal diagnostics. + // Instead, stop here so that the `if`- or `while`-expression's block is linted instead. + if !span.is_desugaring(DesugaringKind::CondTemporary) + && !span.is_desugaring(DesugaringKind::Async) + && !orig_span.is_desugaring(DesugaringKind::Await) + { + self.diverges.set(Diverges::WarnedAlways); + + debug!("warn_if_unreachable: id={:?} span={:?} kind={}", id, span, kind); + + self.tcx().struct_span_lint_hir(lint::builtin::UNREACHABLE_CODE, id, span, |lint| { + let msg = format!("unreachable {}", kind); + lint.build(&msg) + .span_label(span, &msg) + .span_label( + orig_span, + custom_note + .unwrap_or("any code following this expression is unreachable"), + ) + .emit(); + }) + } + } + } + + /// Resolves type and const variables in `ty` if possible. Unlike the infcx + /// version (resolve_vars_if_possible), this version will + /// also select obligations if it seems useful, in an effort + /// to get more type information. + pub(in super::super) fn resolve_vars_with_obligations(&self, mut ty: Ty<'tcx>) -> Ty<'tcx> { + debug!("resolve_vars_with_obligations(ty={:?})", ty); + + // No Infer()? Nothing needs doing. + if !ty.has_infer_types_or_consts() { + debug!("resolve_vars_with_obligations: ty={:?}", ty); + return ty; + } + + // If `ty` is a type variable, see whether we already know what it is. + ty = self.resolve_vars_if_possible(&ty); + if !ty.has_infer_types_or_consts() { + debug!("resolve_vars_with_obligations: ty={:?}", ty); + return ty; + } + + // If not, try resolving pending obligations as much as + // possible. This can help substantially when there are + // indirect dependencies that don't seem worth tracking + // precisely. + self.select_obligations_where_possible(false, |_| {}); + ty = self.resolve_vars_if_possible(&ty); + + debug!("resolve_vars_with_obligations: ty={:?}", ty); + ty + } + + pub(in super::super) fn record_deferred_call_resolution( + &self, + closure_def_id: DefId, + r: DeferredCallResolution<'tcx>, + ) { + let mut deferred_call_resolutions = self.deferred_call_resolutions.borrow_mut(); + deferred_call_resolutions.entry(closure_def_id).or_default().push(r); + } + + pub(in super::super) fn remove_deferred_call_resolutions( + &self, + closure_def_id: DefId, + ) -> Vec<DeferredCallResolution<'tcx>> { + let mut deferred_call_resolutions = self.deferred_call_resolutions.borrow_mut(); + deferred_call_resolutions.remove(&closure_def_id).unwrap_or(vec![]) + } + + pub fn tag(&self) -> String { + format!("{:p}", self) + } + + pub fn local_ty(&self, span: Span, nid: hir::HirId) -> LocalTy<'tcx> { + self.locals.borrow().get(&nid).cloned().unwrap_or_else(|| { + span_bug!(span, "no type for local variable {}", self.tcx.hir().node_to_string(nid)) + }) + } + + #[inline] + pub fn write_ty(&self, id: hir::HirId, ty: Ty<'tcx>) { + debug!( + "write_ty({:?}, {:?}) in fcx {}", + id, + self.resolve_vars_if_possible(&ty), + self.tag() + ); + self.typeck_results.borrow_mut().node_types_mut().insert(id, ty); + + if ty.references_error() { + self.has_errors.set(true); + self.set_tainted_by_errors(); + } + } + + pub fn write_field_index(&self, hir_id: hir::HirId, index: usize) { + self.typeck_results.borrow_mut().field_indices_mut().insert(hir_id, index); + } + + pub(in super::super) fn write_resolution( + &self, + hir_id: hir::HirId, + r: Result<(DefKind, DefId), ErrorReported>, + ) { + self.typeck_results.borrow_mut().type_dependent_defs_mut().insert(hir_id, r); + } + + pub fn write_method_call(&self, hir_id: hir::HirId, method: MethodCallee<'tcx>) { + debug!("write_method_call(hir_id={:?}, method={:?})", hir_id, method); + self.write_resolution(hir_id, Ok((DefKind::AssocFn, method.def_id))); + self.write_substs(hir_id, method.substs); + + // When the method is confirmed, the `method.substs` includes + // parameters from not just the method, but also the impl of + // the method -- in particular, the `Self` type will be fully + // resolved. However, those are not something that the "user + // specified" -- i.e., those types come from the inferred type + // of the receiver, not something the user wrote. So when we + // create the user-substs, we want to replace those earlier + // types with just the types that the user actually wrote -- + // that is, those that appear on the *method itself*. + // + // As an example, if the user wrote something like + // `foo.bar::<u32>(...)` -- the `Self` type here will be the + // type of `foo` (possibly adjusted), but we don't want to + // include that. We want just the `[_, u32]` part. + if !method.substs.is_noop() { + let method_generics = self.tcx.generics_of(method.def_id); + if !method_generics.params.is_empty() { + let user_type_annotation = self.infcx.probe(|_| { + let user_substs = UserSubsts { + substs: InternalSubsts::for_item(self.tcx, method.def_id, |param, _| { + let i = param.index as usize; + if i < method_generics.parent_count { + self.infcx.var_for_def(DUMMY_SP, param) + } else { + method.substs[i] + } + }), + user_self_ty: None, // not relevant here + }; + + self.infcx.canonicalize_user_type_annotation(&UserType::TypeOf( + method.def_id, + user_substs, + )) + }); + + debug!("write_method_call: user_type_annotation={:?}", user_type_annotation); + self.write_user_type_annotation(hir_id, user_type_annotation); + } + } + } + + pub fn write_substs(&self, node_id: hir::HirId, substs: SubstsRef<'tcx>) { + if !substs.is_noop() { + debug!("write_substs({:?}, {:?}) in fcx {}", node_id, substs, self.tag()); + + self.typeck_results.borrow_mut().node_substs_mut().insert(node_id, substs); + } + } + + /// Given the substs that we just converted from the HIR, try to + /// canonicalize them and store them as user-given substitutions + /// (i.e., substitutions that must be respected by the NLL check). + /// + /// This should be invoked **before any unifications have + /// occurred**, so that annotations like `Vec<_>` are preserved + /// properly. + pub fn write_user_type_annotation_from_substs( + &self, + hir_id: hir::HirId, + def_id: DefId, + substs: SubstsRef<'tcx>, + user_self_ty: Option<UserSelfTy<'tcx>>, + ) { + debug!( + "write_user_type_annotation_from_substs: hir_id={:?} def_id={:?} substs={:?} \ + user_self_ty={:?} in fcx {}", + hir_id, + def_id, + substs, + user_self_ty, + self.tag(), + ); + + if Self::can_contain_user_lifetime_bounds((substs, user_self_ty)) { + let canonicalized = self.infcx.canonicalize_user_type_annotation(&UserType::TypeOf( + def_id, + UserSubsts { substs, user_self_ty }, + )); + debug!("write_user_type_annotation_from_substs: canonicalized={:?}", canonicalized); + self.write_user_type_annotation(hir_id, canonicalized); + } + } + + pub fn write_user_type_annotation( + &self, + hir_id: hir::HirId, + canonical_user_type_annotation: CanonicalUserType<'tcx>, + ) { + debug!( + "write_user_type_annotation: hir_id={:?} canonical_user_type_annotation={:?} tag={}", + hir_id, + canonical_user_type_annotation, + self.tag(), + ); + + if !canonical_user_type_annotation.is_identity() { + self.typeck_results + .borrow_mut() + .user_provided_types_mut() + .insert(hir_id, canonical_user_type_annotation); + } else { + debug!("write_user_type_annotation: skipping identity substs"); + } + } + + pub fn apply_adjustments(&self, expr: &hir::Expr<'_>, adj: Vec<Adjustment<'tcx>>) { + debug!("apply_adjustments(expr={:?}, adj={:?})", expr, adj); + + if adj.is_empty() { + return; + } + + let autoborrow_mut = adj.iter().any(|adj| { + matches!(adj, &Adjustment { + kind: Adjust::Borrow(AutoBorrow::Ref(_, AutoBorrowMutability::Mut { .. })), + .. + }) + }); + + match self.typeck_results.borrow_mut().adjustments_mut().entry(expr.hir_id) { + Entry::Vacant(entry) => { + entry.insert(adj); + } + Entry::Occupied(mut entry) => { + debug!(" - composing on top of {:?}", entry.get()); + match (&entry.get()[..], &adj[..]) { + // Applying any adjustment on top of a NeverToAny + // is a valid NeverToAny adjustment, because it can't + // be reached. + (&[Adjustment { kind: Adjust::NeverToAny, .. }], _) => return, + (&[ + Adjustment { kind: Adjust::Deref(_), .. }, + Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(..)), .. }, + ], &[ + Adjustment { kind: Adjust::Deref(_), .. }, + .. // Any following adjustments are allowed. + ]) => { + // A reborrow has no effect before a dereference. + } + // FIXME: currently we never try to compose autoderefs + // and ReifyFnPointer/UnsafeFnPointer, but we could. + _ => + bug!("while adjusting {:?}, can't compose {:?} and {:?}", + expr, entry.get(), adj) + }; + *entry.get_mut() = adj; + } + } + + // If there is an mutable auto-borrow, it is equivalent to `&mut <expr>`. + // In this case implicit use of `Deref` and `Index` within `<expr>` should + // instead be `DerefMut` and `IndexMut`, so fix those up. + if autoborrow_mut { + self.convert_place_derefs_to_mutable(expr); + } + } + + /// Basically whenever we are converting from a type scheme into + /// the fn body space, we always want to normalize associated + /// types as well. This function combines the two. + fn instantiate_type_scheme<T>(&self, span: Span, substs: SubstsRef<'tcx>, value: &T) -> T + where + T: TypeFoldable<'tcx>, + { + let value = value.subst(self.tcx, substs); + let result = self.normalize_associated_types_in(span, &value); + debug!("instantiate_type_scheme(value={:?}, substs={:?}) = {:?}", value, substs, result); + result + } + + /// As `instantiate_type_scheme`, but for the bounds found in a + /// generic type scheme. + pub(in super::super) fn instantiate_bounds( + &self, + span: Span, + def_id: DefId, + substs: SubstsRef<'tcx>, + ) -> (ty::InstantiatedPredicates<'tcx>, Vec<Span>) { + let bounds = self.tcx.predicates_of(def_id); + let spans: Vec<Span> = bounds.predicates.iter().map(|(_, span)| *span).collect(); + let result = bounds.instantiate(self.tcx, substs); + let result = self.normalize_associated_types_in(span, &result); + debug!( + "instantiate_bounds(bounds={:?}, substs={:?}) = {:?}, {:?}", + bounds, substs, result, spans, + ); + (result, spans) + } + + /// Replaces the opaque types from the given value with type variables, + /// and records the `OpaqueTypeMap` for later use during writeback. See + /// `InferCtxt::instantiate_opaque_types` for more details. + pub(in super::super) fn instantiate_opaque_types_from_value<T: TypeFoldable<'tcx>>( + &self, + parent_id: hir::HirId, + value: &T, + value_span: Span, + ) -> T { + let parent_def_id = self.tcx.hir().local_def_id(parent_id); + debug!( + "instantiate_opaque_types_from_value(parent_def_id={:?}, value={:?})", + parent_def_id, value + ); + + let (value, opaque_type_map) = + self.register_infer_ok_obligations(self.instantiate_opaque_types( + parent_def_id, + self.body_id, + self.param_env, + value, + value_span, + )); + + let mut opaque_types = self.opaque_types.borrow_mut(); + let mut opaque_types_vars = self.opaque_types_vars.borrow_mut(); + for (ty, decl) in opaque_type_map { + let _ = opaque_types.insert(ty, decl); + let _ = opaque_types_vars.insert(decl.concrete_ty, decl.opaque_type); + } + + value + } + + pub(in super::super) fn normalize_associated_types_in<T>(&self, span: Span, value: &T) -> T + where + T: TypeFoldable<'tcx>, + { + self.inh.normalize_associated_types_in(span, self.body_id, self.param_env, value) + } + + pub(in super::super) fn normalize_associated_types_in_as_infer_ok<T>( + &self, + span: Span, + value: &T, + ) -> InferOk<'tcx, T> + where + T: TypeFoldable<'tcx>, + { + self.inh.partially_normalize_associated_types_in(span, self.body_id, self.param_env, value) + } + + pub fn require_type_meets( + &self, + ty: Ty<'tcx>, + span: Span, + code: traits::ObligationCauseCode<'tcx>, + def_id: DefId, + ) { + self.register_bound(ty, def_id, traits::ObligationCause::new(span, self.body_id, code)); + } + + pub fn require_type_is_sized( + &self, + ty: Ty<'tcx>, + span: Span, + code: traits::ObligationCauseCode<'tcx>, + ) { + if !ty.references_error() { + let lang_item = self.tcx.require_lang_item(LangItem::Sized, None); + self.require_type_meets(ty, span, code, lang_item); + } + } + + pub fn require_type_is_sized_deferred( + &self, + ty: Ty<'tcx>, + span: Span, + code: traits::ObligationCauseCode<'tcx>, + ) { + if !ty.references_error() { + self.deferred_sized_obligations.borrow_mut().push((ty, span, code)); + } + } + + pub fn register_bound( + &self, + ty: Ty<'tcx>, + def_id: DefId, + cause: traits::ObligationCause<'tcx>, + ) { + if !ty.references_error() { + self.fulfillment_cx.borrow_mut().register_bound( + self, + self.param_env, + ty, + def_id, + cause, + ); + } + } + + pub fn to_ty(&self, ast_t: &hir::Ty<'_>) -> Ty<'tcx> { + let t = AstConv::ast_ty_to_ty(self, ast_t); + self.register_wf_obligation(t.into(), ast_t.span, traits::MiscObligation); + t + } + + pub fn to_ty_saving_user_provided_ty(&self, ast_ty: &hir::Ty<'_>) -> Ty<'tcx> { + let ty = self.to_ty(ast_ty); + debug!("to_ty_saving_user_provided_ty: ty={:?}", ty); + + if Self::can_contain_user_lifetime_bounds(ty) { + let c_ty = self.infcx.canonicalize_response(&UserType::Ty(ty)); + debug!("to_ty_saving_user_provided_ty: c_ty={:?}", c_ty); + self.typeck_results.borrow_mut().user_provided_types_mut().insert(ast_ty.hir_id, c_ty); + } + + ty + } + + pub fn to_const(&self, ast_c: &hir::AnonConst) -> &'tcx ty::Const<'tcx> { + let const_def_id = self.tcx.hir().local_def_id(ast_c.hir_id); + let c = ty::Const::from_anon_const(self.tcx, const_def_id); + self.register_wf_obligation( + c.into(), + self.tcx.hir().span(ast_c.hir_id), + ObligationCauseCode::MiscObligation, + ); + c + } + + pub fn const_arg_to_const( + &self, + ast_c: &hir::AnonConst, + param_def_id: DefId, + ) -> &'tcx ty::Const<'tcx> { + let const_def = ty::WithOptConstParam { + did: self.tcx.hir().local_def_id(ast_c.hir_id), + const_param_did: Some(param_def_id), + }; + let c = ty::Const::from_opt_const_arg_anon_const(self.tcx, const_def); + self.register_wf_obligation( + c.into(), + self.tcx.hir().span(ast_c.hir_id), + ObligationCauseCode::MiscObligation, + ); + c + } + + // If the type given by the user has free regions, save it for later, since + // NLL would like to enforce those. Also pass in types that involve + // projections, since those can resolve to `'static` bounds (modulo #54940, + // which hopefully will be fixed by the time you see this comment, dear + // reader, although I have my doubts). Also pass in types with inference + // types, because they may be repeated. Other sorts of things are already + // sufficiently enforced with erased regions. =) + fn can_contain_user_lifetime_bounds<T>(t: T) -> bool + where + T: TypeFoldable<'tcx>, + { + t.has_free_regions() || t.has_projections() || t.has_infer_types() + } + + pub fn node_ty(&self, id: hir::HirId) -> Ty<'tcx> { + match self.typeck_results.borrow().node_types().get(id) { + Some(&t) => t, + None if self.is_tainted_by_errors() => self.tcx.ty_error(), + None => { + bug!( + "no type for node {}: {} in fcx {}", + id, + self.tcx.hir().node_to_string(id), + self.tag() + ); + } + } + } + + /// Registers an obligation for checking later, during regionck, that `arg` is well-formed. + pub fn register_wf_obligation( + &self, + arg: subst::GenericArg<'tcx>, + span: Span, + code: traits::ObligationCauseCode<'tcx>, + ) { + // WF obligations never themselves fail, so no real need to give a detailed cause: + let cause = traits::ObligationCause::new(span, self.body_id, code); + self.register_predicate(traits::Obligation::new( + cause, + self.param_env, + ty::PredicateAtom::WellFormed(arg).to_predicate(self.tcx), + )); + } + + /// Registers obligations that all `substs` are well-formed. + pub fn add_wf_bounds(&self, substs: SubstsRef<'tcx>, expr: &hir::Expr<'_>) { + for arg in substs.iter().filter(|arg| { + matches!(arg.unpack(), GenericArgKind::Type(..) | GenericArgKind::Const(..)) + }) { + self.register_wf_obligation(arg, expr.span, traits::MiscObligation); + } + } + + /// Given a fully substituted set of bounds (`generic_bounds`), and the values with which each + /// type/region parameter was instantiated (`substs`), creates and registers suitable + /// trait/region obligations. + /// + /// For example, if there is a function: + /// + /// ``` + /// fn foo<'a,T:'a>(...) + /// ``` + /// + /// and a reference: + /// + /// ``` + /// let f = foo; + /// ``` + /// + /// Then we will create a fresh region variable `'$0` and a fresh type variable `$1` for `'a` + /// and `T`. This routine will add a region obligation `$1:'$0` and register it locally. + pub fn add_obligations_for_parameters( + &self, + cause: traits::ObligationCause<'tcx>, + predicates: ty::InstantiatedPredicates<'tcx>, + ) { + assert!(!predicates.has_escaping_bound_vars()); + + debug!("add_obligations_for_parameters(predicates={:?})", predicates); + + for obligation in traits::predicates_for_generics(cause, self.param_env, predicates) { + self.register_predicate(obligation); + } + } + + // FIXME(arielb1): use this instead of field.ty everywhere + // Only for fields! Returns <none> for methods> + // Indifferent to privacy flags + pub fn field_ty( + &self, + span: Span, + field: &'tcx ty::FieldDef, + substs: SubstsRef<'tcx>, + ) -> Ty<'tcx> { + self.normalize_associated_types_in(span, &field.ty(self.tcx, substs)) + } + + pub(in super::super) fn resolve_generator_interiors(&self, def_id: DefId) { + let mut generators = self.deferred_generator_interiors.borrow_mut(); + for (body_id, interior, kind) in generators.drain(..) { + self.select_obligations_where_possible(false, |_| {}); + crate::check::generator_interior::resolve_interior( + self, def_id, body_id, interior, kind, + ); + } + } + + // Tries to apply a fallback to `ty` if it is an unsolved variable. + // + // - Unconstrained ints are replaced with `i32`. + // + // - Unconstrained floats are replaced with with `f64`. + // + // - Non-numerics get replaced with `!` when `#![feature(never_type_fallback)]` + // is enabled. Otherwise, they are replaced with `()`. + // + // Fallback becomes very dubious if we have encountered type-checking errors. + // In that case, fallback to Error. + // The return value indicates whether fallback has occurred. + pub(in super::super) fn fallback_if_possible(&self, ty: Ty<'tcx>, mode: FallbackMode) -> bool { + use rustc_middle::ty::error::UnconstrainedNumeric::Neither; + use rustc_middle::ty::error::UnconstrainedNumeric::{UnconstrainedFloat, UnconstrainedInt}; + + assert!(ty.is_ty_infer()); + let fallback = match self.type_is_unconstrained_numeric(ty) { + _ if self.is_tainted_by_errors() => self.tcx().ty_error(), + UnconstrainedInt => self.tcx.types.i32, + UnconstrainedFloat => self.tcx.types.f64, + Neither if self.type_var_diverges(ty) => self.tcx.mk_diverging_default(), + Neither => { + // This type variable was created from the instantiation of an opaque + // type. The fact that we're attempting to perform fallback for it + // means that the function neither constrained it to a concrete + // type, nor to the opaque type itself. + // + // For example, in this code: + // + //``` + // type MyType = impl Copy; + // fn defining_use() -> MyType { true } + // fn other_use() -> MyType { defining_use() } + // ``` + // + // `defining_use` will constrain the instantiated inference + // variable to `bool`, while `other_use` will constrain + // the instantiated inference variable to `MyType`. + // + // When we process opaque types during writeback, we + // will handle cases like `other_use`, and not count + // them as defining usages + // + // However, we also need to handle cases like this: + // + // ```rust + // pub type Foo = impl Copy; + // fn produce() -> Option<Foo> { + // None + // } + // ``` + // + // In the above snippet, the inference variable created by + // instantiating `Option<Foo>` will be completely unconstrained. + // We treat this as a non-defining use by making the inference + // variable fall back to the opaque type itself. + if let FallbackMode::All = mode { + if let Some(opaque_ty) = self.opaque_types_vars.borrow().get(ty) { + debug!( + "fallback_if_possible: falling back opaque type var {:?} to {:?}", + ty, opaque_ty + ); + *opaque_ty + } else { + return false; + } + } else { + return false; + } + } + }; + debug!("fallback_if_possible: defaulting `{:?}` to `{:?}`", ty, fallback); + self.demand_eqtype(rustc_span::DUMMY_SP, ty, fallback); + true + } + + pub(in super::super) fn select_all_obligations_or_error(&self) { + debug!("select_all_obligations_or_error"); + if let Err(errors) = self.fulfillment_cx.borrow_mut().select_all_or_error(&self) { + self.report_fulfillment_errors(&errors, self.inh.body_id, false); + } + } + + /// Select as many obligations as we can at present. + pub(in super::super) fn select_obligations_where_possible( + &self, + fallback_has_occurred: bool, + mutate_fullfillment_errors: impl Fn(&mut Vec<traits::FulfillmentError<'tcx>>), + ) { + let result = self.fulfillment_cx.borrow_mut().select_where_possible(self); + if let Err(mut errors) = result { + mutate_fullfillment_errors(&mut errors); + self.report_fulfillment_errors(&errors, self.inh.body_id, fallback_has_occurred); + } + } + + /// For the overloaded place expressions (`*x`, `x[3]`), the trait + /// returns a type of `&T`, but the actual type we assign to the + /// *expression* is `T`. So this function just peels off the return + /// type by one layer to yield `T`. + pub(in super::super) fn make_overloaded_place_return_type( + &self, + method: MethodCallee<'tcx>, + ) -> ty::TypeAndMut<'tcx> { + // extract method return type, which will be &T; + let ret_ty = method.sig.output(); + + // method returns &T, but the type as visible to user is T, so deref + ret_ty.builtin_deref(true).unwrap() + } + + fn self_type_matches_expected_vid( + &self, + trait_ref: ty::PolyTraitRef<'tcx>, + expected_vid: ty::TyVid, + ) -> bool { + let self_ty = self.shallow_resolve(trait_ref.skip_binder().self_ty()); + debug!( + "self_type_matches_expected_vid(trait_ref={:?}, self_ty={:?}, expected_vid={:?})", + trait_ref, self_ty, expected_vid + ); + match *self_ty.kind() { + ty::Infer(ty::TyVar(found_vid)) => { + // FIXME: consider using `sub_root_var` here so we + // can see through subtyping. + let found_vid = self.root_var(found_vid); + debug!("self_type_matches_expected_vid - found_vid={:?}", found_vid); + expected_vid == found_vid + } + _ => false, + } + } + + pub(in super::super) fn obligations_for_self_ty<'b>( + &'b self, + self_ty: ty::TyVid, + ) -> impl Iterator<Item = (ty::PolyTraitRef<'tcx>, traits::PredicateObligation<'tcx>)> + + Captures<'tcx> + + 'b { + // FIXME: consider using `sub_root_var` here so we + // can see through subtyping. + let ty_var_root = self.root_var(self_ty); + debug!( + "obligations_for_self_ty: self_ty={:?} ty_var_root={:?} pending_obligations={:?}", + self_ty, + ty_var_root, + self.fulfillment_cx.borrow().pending_obligations() + ); + + self.fulfillment_cx + .borrow() + .pending_obligations() + .into_iter() + .filter_map(move |obligation| { + match obligation.predicate.skip_binders() { + ty::PredicateAtom::Projection(data) => { + Some((ty::Binder::bind(data).to_poly_trait_ref(self.tcx), obligation)) + } + ty::PredicateAtom::Trait(data, _) => { + Some((ty::Binder::bind(data).to_poly_trait_ref(), obligation)) + } + ty::PredicateAtom::Subtype(..) => None, + ty::PredicateAtom::RegionOutlives(..) => None, + ty::PredicateAtom::TypeOutlives(..) => None, + ty::PredicateAtom::WellFormed(..) => None, + ty::PredicateAtom::ObjectSafe(..) => None, + ty::PredicateAtom::ConstEvaluatable(..) => None, + ty::PredicateAtom::ConstEquate(..) => None, + // N.B., this predicate is created by breaking down a + // `ClosureType: FnFoo()` predicate, where + // `ClosureType` represents some `Closure`. It can't + // possibly be referring to the current closure, + // because we haven't produced the `Closure` for + // this closure yet; this is exactly why the other + // code is looking for a self type of a unresolved + // inference variable. + ty::PredicateAtom::ClosureKind(..) => None, + ty::PredicateAtom::TypeWellFormedFromEnv(..) => None, + } + }) + .filter(move |(tr, _)| self.self_type_matches_expected_vid(*tr, ty_var_root)) + } + + pub(in super::super) fn type_var_is_sized(&self, self_ty: ty::TyVid) -> bool { + self.obligations_for_self_ty(self_ty) + .any(|(tr, _)| Some(tr.def_id()) == self.tcx.lang_items().sized_trait()) + } + + pub(in super::super) fn err_args(&self, len: usize) -> Vec<Ty<'tcx>> { + vec![self.tcx.ty_error(); len] + } + + /// Unifies the output type with the expected type early, for more coercions + /// and forward type information on the input expressions. + pub(in super::super) fn expected_inputs_for_expected_output( + &self, + call_span: Span, + expected_ret: Expectation<'tcx>, + formal_ret: Ty<'tcx>, + formal_args: &[Ty<'tcx>], + ) -> Vec<Ty<'tcx>> { + let formal_ret = self.resolve_vars_with_obligations(formal_ret); + let ret_ty = match expected_ret.only_has_type(self) { + Some(ret) => ret, + None => return Vec::new(), + }; + let expect_args = self + .fudge_inference_if_ok(|| { + // Attempt to apply a subtyping relationship between the formal + // return type (likely containing type variables if the function + // is polymorphic) and the expected return type. + // No argument expectations are produced if unification fails. + let origin = self.misc(call_span); + let ures = self.at(&origin, self.param_env).sup(ret_ty, &formal_ret); + + // FIXME(#27336) can't use ? here, Try::from_error doesn't default + // to identity so the resulting type is not constrained. + match ures { + Ok(ok) => { + // Process any obligations locally as much as + // we can. We don't care if some things turn + // out unconstrained or ambiguous, as we're + // just trying to get hints here. + self.save_and_restore_in_snapshot_flag(|_| { + let mut fulfill = TraitEngine::new(self.tcx); + for obligation in ok.obligations { + fulfill.register_predicate_obligation(self, obligation); + } + fulfill.select_where_possible(self) + }) + .map_err(|_| ())?; + } + Err(_) => return Err(()), + } + + // Record all the argument types, with the substitutions + // produced from the above subtyping unification. + Ok(formal_args.iter().map(|ty| self.resolve_vars_if_possible(ty)).collect()) + }) + .unwrap_or_default(); + debug!( + "expected_inputs_for_expected_output(formal={:?} -> {:?}, expected={:?} -> {:?})", + formal_args, formal_ret, expect_args, expected_ret + ); + expect_args + } + + pub(in super::super) fn resolve_lang_item_path( + &self, + lang_item: hir::LangItem, + span: Span, + hir_id: hir::HirId, + ) -> (Res, Ty<'tcx>) { + let def_id = self.tcx.require_lang_item(lang_item, Some(span)); + let def_kind = self.tcx.def_kind(def_id); + + let item_ty = if let DefKind::Variant = def_kind { + self.tcx.type_of(self.tcx.parent(def_id).expect("variant w/out parent")) + } else { + self.tcx.type_of(def_id) + }; + let substs = self.infcx.fresh_substs_for_item(span, def_id); + let ty = item_ty.subst(self.tcx, substs); + + self.write_resolution(hir_id, Ok((def_kind, def_id))); + self.add_required_obligations(span, def_id, &substs); + (Res::Def(def_kind, def_id), ty) + } + + /// Resolves an associated value path into a base type and associated constant, or method + /// resolution. The newly resolved definition is written into `type_dependent_defs`. + pub fn resolve_ty_and_res_ufcs<'b>( + &self, + qpath: &'b QPath<'b>, + hir_id: hir::HirId, + span: Span, + ) -> (Res, Option<Ty<'tcx>>, &'b [hir::PathSegment<'b>]) { + debug!("resolve_ty_and_res_ufcs: qpath={:?} hir_id={:?} span={:?}", qpath, hir_id, span); + let (ty, qself, item_segment) = match *qpath { + QPath::Resolved(ref opt_qself, ref path) => { + return ( + path.res, + opt_qself.as_ref().map(|qself| self.to_ty(qself)), + &path.segments[..], + ); + } + QPath::TypeRelative(ref qself, ref segment) => (self.to_ty(qself), qself, segment), + QPath::LangItem(..) => bug!("`resolve_ty_and_res_ufcs` called on `LangItem`"), + }; + if let Some(&cached_result) = self.typeck_results.borrow().type_dependent_defs().get(hir_id) + { + // Return directly on cache hit. This is useful to avoid doubly reporting + // errors with default match binding modes. See #44614. + let def = + cached_result.map(|(kind, def_id)| Res::Def(kind, def_id)).unwrap_or(Res::Err); + return (def, Some(ty), slice::from_ref(&**item_segment)); + } + let item_name = item_segment.ident; + let result = self.resolve_ufcs(span, item_name, ty, hir_id).or_else(|error| { + let result = match error { + method::MethodError::PrivateMatch(kind, def_id, _) => Ok((kind, def_id)), + _ => Err(ErrorReported), + }; + if item_name.name != kw::Invalid { + if let Some(mut e) = self.report_method_error( + span, + ty, + item_name, + SelfSource::QPath(qself), + error, + None, + ) { + e.emit(); + } + } + result + }); + + // Write back the new resolution. + self.write_resolution(hir_id, result); + ( + result.map(|(kind, def_id)| Res::Def(kind, def_id)).unwrap_or(Res::Err), + Some(ty), + slice::from_ref(&**item_segment), + ) + } + + /// Given a function `Node`, return its `FnDecl` if it exists, or `None` otherwise. + pub(in super::super) fn get_node_fn_decl( + &self, + node: Node<'tcx>, + ) -> Option<(&'tcx hir::FnDecl<'tcx>, Ident, bool)> { + match node { + Node::Item(&hir::Item { ident, kind: hir::ItemKind::Fn(ref sig, ..), .. }) => { + // This is less than ideal, it will not suggest a return type span on any + // method called `main`, regardless of whether it is actually the entry point, + // but it will still present it as the reason for the expected type. + Some((&sig.decl, ident, ident.name != sym::main)) + } + Node::TraitItem(&hir::TraitItem { + ident, + kind: hir::TraitItemKind::Fn(ref sig, ..), + .. + }) => Some((&sig.decl, ident, true)), + Node::ImplItem(&hir::ImplItem { + ident, + kind: hir::ImplItemKind::Fn(ref sig, ..), + .. + }) => Some((&sig.decl, ident, false)), + _ => None, + } + } + + /// Given a `HirId`, return the `FnDecl` of the method it is enclosed by and whether a + /// suggestion can be made, `None` otherwise. + pub fn get_fn_decl(&self, blk_id: hir::HirId) -> Option<(&'tcx hir::FnDecl<'tcx>, bool)> { + // Get enclosing Fn, if it is a function or a trait method, unless there's a `loop` or + // `while` before reaching it, as block tail returns are not available in them. + self.tcx.hir().get_return_block(blk_id).and_then(|blk_id| { + let parent = self.tcx.hir().get(blk_id); + self.get_node_fn_decl(parent).map(|(fn_decl, _, is_main)| (fn_decl, is_main)) + }) + } + + pub(in super::super) fn note_internal_mutation_in_method( + &self, + err: &mut DiagnosticBuilder<'_>, + expr: &hir::Expr<'_>, + expected: Ty<'tcx>, + found: Ty<'tcx>, + ) { + if found != self.tcx.types.unit { + return; + } + if let ExprKind::MethodCall(path_segment, _, [rcvr, ..], _) = expr.kind { + if self + .typeck_results + .borrow() + .expr_ty_adjusted_opt(rcvr) + .map_or(true, |ty| expected.peel_refs() != ty.peel_refs()) + { + return; + } + let mut sp = MultiSpan::from_span(path_segment.ident.span); + sp.push_span_label( + path_segment.ident.span, + format!( + "this call modifies {} in-place", + match rcvr.kind { + ExprKind::Path(QPath::Resolved( + None, + hir::Path { segments: [segment], .. }, + )) => format!("`{}`", segment.ident), + _ => "its receiver".to_string(), + } + ), + ); + sp.push_span_label( + rcvr.span, + "you probably want to use this value after calling the method...".to_string(), + ); + err.span_note( + sp, + &format!("method `{}` modifies its receiver in-place", path_segment.ident), + ); + err.note(&format!("...instead of the `()` output of method `{}`", path_segment.ident)); + } + } + + pub(in super::super) fn note_need_for_fn_pointer( + &self, + err: &mut DiagnosticBuilder<'_>, + expected: Ty<'tcx>, + found: Ty<'tcx>, + ) { + let (sig, did, substs) = match (&expected.kind(), &found.kind()) { + (ty::FnDef(did1, substs1), ty::FnDef(did2, substs2)) => { + let sig1 = self.tcx.fn_sig(*did1).subst(self.tcx, substs1); + let sig2 = self.tcx.fn_sig(*did2).subst(self.tcx, substs2); + if sig1 != sig2 { + return; + } + err.note( + "different `fn` items always have unique types, even if their signatures are \ + the same", + ); + (sig1, *did1, substs1) + } + (ty::FnDef(did, substs), ty::FnPtr(sig2)) => { + let sig1 = self.tcx.fn_sig(*did).subst(self.tcx, substs); + if sig1 != *sig2 { + return; + } + (sig1, *did, substs) + } + _ => return, + }; + err.help(&format!("change the expected type to be function pointer `{}`", sig)); + err.help(&format!( + "if the expected type is due to type inference, cast the expected `fn` to a function \ + pointer: `{} as {}`", + self.tcx.def_path_str_with_substs(did, substs), + sig + )); + } + + pub(in super::super) fn could_remove_semicolon( + &self, + blk: &'tcx hir::Block<'tcx>, + expected_ty: Ty<'tcx>, + ) -> Option<Span> { + // Be helpful when the user wrote `{... expr;}` and + // taking the `;` off is enough to fix the error. + let last_stmt = blk.stmts.last()?; + let last_expr = match last_stmt.kind { + hir::StmtKind::Semi(ref e) => e, + _ => return None, + }; + let last_expr_ty = self.node_ty(last_expr.hir_id); + if matches!(last_expr_ty.kind(), ty::Error(_)) + || self.can_sub(self.param_env, last_expr_ty, expected_ty).is_err() + { + return None; + } + let original_span = original_sp(last_stmt.span, blk.span); + Some(original_span.with_lo(original_span.hi() - BytePos(1))) + } + + // Instantiates the given path, which must refer to an item with the given + // number of type parameters and type. + pub fn instantiate_value_path( + &self, + segments: &[hir::PathSegment<'_>], + self_ty: Option<Ty<'tcx>>, + res: Res, + span: Span, + hir_id: hir::HirId, + ) -> (Ty<'tcx>, Res) { + debug!( + "instantiate_value_path(segments={:?}, self_ty={:?}, res={:?}, hir_id={})", + segments, self_ty, res, hir_id, + ); + + let tcx = self.tcx; + + let path_segs = match res { + Res::Local(_) | Res::SelfCtor(_) => vec![], + Res::Def(kind, def_id) => { + AstConv::def_ids_for_value_path_segments(self, segments, self_ty, kind, def_id) + } + _ => bug!("instantiate_value_path on {:?}", res), + }; + + let mut user_self_ty = None; + let mut is_alias_variant_ctor = false; + match res { + Res::Def(DefKind::Ctor(CtorOf::Variant, _), _) => { + if let Some(self_ty) = self_ty { + let adt_def = self_ty.ty_adt_def().unwrap(); + user_self_ty = Some(UserSelfTy { impl_def_id: adt_def.did, self_ty }); + is_alias_variant_ctor = true; + } + } + Res::Def(DefKind::AssocFn | DefKind::AssocConst, def_id) => { + let container = tcx.associated_item(def_id).container; + debug!("instantiate_value_path: def_id={:?} container={:?}", def_id, container); + match container { + ty::TraitContainer(trait_did) => { + callee::check_legal_trait_for_method_call(tcx, span, None, trait_did) + } + ty::ImplContainer(impl_def_id) => { + if segments.len() == 1 { + // `<T>::assoc` will end up here, and so + // can `T::assoc`. It this came from an + // inherent impl, we need to record the + // `T` for posterity (see `UserSelfTy` for + // details). + let self_ty = self_ty.expect("UFCS sugared assoc missing Self"); + user_self_ty = Some(UserSelfTy { impl_def_id, self_ty }); + } + } + } + } + _ => {} + } + + // Now that we have categorized what space the parameters for each + // segment belong to, let's sort out the parameters that the user + // provided (if any) into their appropriate spaces. We'll also report + // errors if type parameters are provided in an inappropriate place. + + let generic_segs: FxHashSet<_> = path_segs.iter().map(|PathSeg(_, index)| index).collect(); + let generics_has_err = AstConv::prohibit_generics( + self, + segments.iter().enumerate().filter_map(|(index, seg)| { + if !generic_segs.contains(&index) || is_alias_variant_ctor { + Some(seg) + } else { + None + } + }), + ); + + if let Res::Local(hid) = res { + let ty = self.local_ty(span, hid).decl_ty; + let ty = self.normalize_associated_types_in(span, &ty); + self.write_ty(hir_id, ty); + return (ty, res); + } + + if generics_has_err { + // Don't try to infer type parameters when prohibited generic arguments were given. + user_self_ty = None; + } + + // Now we have to compare the types that the user *actually* + // provided against the types that were *expected*. If the user + // did not provide any types, then we want to substitute inference + // variables. If the user provided some types, we may still need + // to add defaults. If the user provided *too many* types, that's + // a problem. + + let mut infer_args_for_err = FxHashSet::default(); + for &PathSeg(def_id, index) in &path_segs { + let seg = &segments[index]; + let generics = tcx.generics_of(def_id); + // Argument-position `impl Trait` is treated as a normal generic + // parameter internally, but we don't allow users to specify the + // parameter's value explicitly, so we have to do some error- + // checking here. + if let GenericArgCountResult { + correct: Err(GenericArgCountMismatch { reported: Some(ErrorReported), .. }), + .. + } = AstConv::check_generic_arg_count_for_call( + tcx, span, &generics, &seg, false, // `is_method_call` + ) { + infer_args_for_err.insert(index); + self.set_tainted_by_errors(); // See issue #53251. + } + } + + let has_self = path_segs + .last() + .map(|PathSeg(def_id, _)| tcx.generics_of(*def_id).has_self) + .unwrap_or(false); + + let (res, self_ctor_substs) = if let Res::SelfCtor(impl_def_id) = res { + let ty = self.normalize_ty(span, tcx.at(span).type_of(impl_def_id)); + match *ty.kind() { + ty::Adt(adt_def, substs) if adt_def.has_ctor() => { + let variant = adt_def.non_enum_variant(); + let ctor_def_id = variant.ctor_def_id.unwrap(); + ( + Res::Def(DefKind::Ctor(CtorOf::Struct, variant.ctor_kind), ctor_def_id), + Some(substs), + ) + } + _ => { + let mut err = tcx.sess.struct_span_err( + span, + "the `Self` constructor can only be used with tuple or unit structs", + ); + if let Some(adt_def) = ty.ty_adt_def() { + match adt_def.adt_kind() { + AdtKind::Enum => { + err.help("did you mean to use one of the enum's variants?"); + } + AdtKind::Struct | AdtKind::Union => { + err.span_suggestion( + span, + "use curly brackets", + String::from("Self { /* fields */ }"), + Applicability::HasPlaceholders, + ); + } + } + } + err.emit(); + + return (tcx.ty_error(), res); + } + } + } else { + (res, None) + }; + let def_id = res.def_id(); + + // The things we are substituting into the type should not contain + // escaping late-bound regions, and nor should the base type scheme. + let ty = tcx.type_of(def_id); + + let arg_count = GenericArgCountResult { + explicit_late_bound: ExplicitLateBound::No, + correct: if infer_args_for_err.is_empty() { + Ok(()) + } else { + Err(GenericArgCountMismatch::default()) + }, + }; + + let substs = self_ctor_substs.unwrap_or_else(|| { + AstConv::create_substs_for_generic_args( + tcx, + def_id, + &[][..], + has_self, + self_ty, + arg_count, + // Provide the generic args, and whether types should be inferred. + |def_id| { + if let Some(&PathSeg(_, index)) = + path_segs.iter().find(|&PathSeg(did, _)| *did == def_id) + { + // If we've encountered an `impl Trait`-related error, we're just + // going to infer the arguments for better error messages. + if !infer_args_for_err.contains(&index) { + // Check whether the user has provided generic arguments. + if let Some(ref data) = segments[index].args { + return (Some(data), segments[index].infer_args); + } + } + return (None, segments[index].infer_args); + } + + (None, true) + }, + // Provide substitutions for parameters for which (valid) arguments have been provided. + |param, arg| match (¶m.kind, arg) { + (GenericParamDefKind::Lifetime, GenericArg::Lifetime(lt)) => { + AstConv::ast_region_to_region(self, lt, Some(param)).into() + } + (GenericParamDefKind::Type { .. }, GenericArg::Type(ty)) => { + self.to_ty(ty).into() + } + (GenericParamDefKind::Const, GenericArg::Const(ct)) => { + self.const_arg_to_const(&ct.value, param.def_id).into() + } + _ => unreachable!(), + }, + // Provide substitutions for parameters for which arguments are inferred. + |substs, param, infer_args| { + match param.kind { + GenericParamDefKind::Lifetime => { + self.re_infer(Some(param), span).unwrap().into() + } + GenericParamDefKind::Type { has_default, .. } => { + if !infer_args && has_default { + // If we have a default, then we it doesn't matter that we're not + // inferring the type arguments: we provide the default where any + // is missing. + let default = tcx.type_of(param.def_id); + self.normalize_ty( + span, + default.subst_spanned(tcx, substs.unwrap(), Some(span)), + ) + .into() + } else { + // If no type arguments were provided, we have to infer them. + // This case also occurs as a result of some malformed input, e.g. + // a lifetime argument being given instead of a type parameter. + // Using inference instead of `Error` gives better error messages. + self.var_for_def(span, param) + } + } + GenericParamDefKind::Const => { + // FIXME(const_generics:defaults) + // No const parameters were provided, we have to infer them. + self.var_for_def(span, param) + } + } + }, + ) + }); + assert!(!substs.has_escaping_bound_vars()); + assert!(!ty.has_escaping_bound_vars()); + + // First, store the "user substs" for later. + self.write_user_type_annotation_from_substs(hir_id, def_id, substs, user_self_ty); + + self.add_required_obligations(span, def_id, &substs); + + // Substitute the values for the type parameters into the type of + // the referenced item. + let ty_substituted = self.instantiate_type_scheme(span, &substs, &ty); + + if let Some(UserSelfTy { impl_def_id, self_ty }) = user_self_ty { + // In the case of `Foo<T>::method` and `<Foo<T>>::method`, if `method` + // is inherent, there is no `Self` parameter; instead, the impl needs + // type parameters, which we can infer by unifying the provided `Self` + // with the substituted impl type. + // This also occurs for an enum variant on a type alias. + let ty = tcx.type_of(impl_def_id); + + let impl_ty = self.instantiate_type_scheme(span, &substs, &ty); + match self.at(&self.misc(span), self.param_env).sup(impl_ty, self_ty) { + Ok(ok) => self.register_infer_ok_obligations(ok), + Err(_) => { + self.tcx.sess.delay_span_bug( + span, + &format!( + "instantiate_value_path: (UFCS) {:?} was a subtype of {:?} but now is not?", + self_ty, + impl_ty, + ), + ); + } + } + } + + self.check_rustc_args_require_const(def_id, hir_id, span); + + debug!("instantiate_value_path: type of {:?} is {:?}", hir_id, ty_substituted); + self.write_substs(hir_id, substs); + + (ty_substituted, res) + } + + /// Add all the obligations that are required, substituting and normalized appropriately. + fn add_required_obligations(&self, span: Span, def_id: DefId, substs: &SubstsRef<'tcx>) { + let (bounds, spans) = self.instantiate_bounds(span, def_id, &substs); + + for (i, mut obligation) in traits::predicates_for_generics( + traits::ObligationCause::new(span, self.body_id, traits::ItemObligation(def_id)), + self.param_env, + bounds, + ) + .enumerate() + { + // This makes the error point at the bound, but we want to point at the argument + if let Some(span) = spans.get(i) { + obligation.cause.make_mut().code = traits::BindingObligation(def_id, *span); + } + self.register_predicate(obligation); + } + } + + /// Resolves `typ` by a single level if `typ` is a type variable. + /// If no resolution is possible, then an error is reported. + /// Numeric inference variables may be left unresolved. + pub fn structurally_resolved_type(&self, sp: Span, ty: Ty<'tcx>) -> Ty<'tcx> { + let ty = self.resolve_vars_with_obligations(ty); + if !ty.is_ty_var() { + ty + } else { + if !self.is_tainted_by_errors() { + self.emit_inference_failure_err((**self).body_id, sp, ty.into(), E0282) + .note("type must be known at this point") + .emit(); + } + let err = self.tcx.ty_error(); + self.demand_suptype(sp, err, ty); + err + } + } + + pub(in super::super) fn with_breakable_ctxt<F: FnOnce() -> R, R>( + &self, + id: hir::HirId, + ctxt: BreakableCtxt<'tcx>, + f: F, + ) -> (BreakableCtxt<'tcx>, R) { + let index; + { + let mut enclosing_breakables = self.enclosing_breakables.borrow_mut(); + index = enclosing_breakables.stack.len(); + enclosing_breakables.by_id.insert(id, index); + enclosing_breakables.stack.push(ctxt); + } + let result = f(); + let ctxt = { + let mut enclosing_breakables = self.enclosing_breakables.borrow_mut(); + debug_assert!(enclosing_breakables.stack.len() == index + 1); + enclosing_breakables.by_id.remove(&id).expect("missing breakable context"); + enclosing_breakables.stack.pop().expect("missing breakable context") + }; + (ctxt, result) + } + + /// Instantiate a QueryResponse in a probe context, without a + /// good ObligationCause. + pub(in super::super) fn probe_instantiate_query_response( + &self, + span: Span, + original_values: &OriginalQueryValues<'tcx>, + query_result: &Canonical<'tcx, QueryResponse<'tcx, Ty<'tcx>>>, + ) -> InferResult<'tcx, Ty<'tcx>> { + self.instantiate_query_response_and_region_obligations( + &traits::ObligationCause::misc(span, self.body_id), + self.param_env, + original_values, + query_result, + ) + } + + /// Returns `true` if an expression is contained inside the LHS of an assignment expression. + pub(in super::super) fn expr_in_place(&self, mut expr_id: hir::HirId) -> bool { + let mut contained_in_place = false; + + while let hir::Node::Expr(parent_expr) = + self.tcx.hir().get(self.tcx.hir().get_parent_node(expr_id)) + { + match &parent_expr.kind { + hir::ExprKind::Assign(lhs, ..) | hir::ExprKind::AssignOp(_, lhs, ..) => { + if lhs.hir_id == expr_id { + contained_in_place = true; + break; + } + } + _ => (), + } + expr_id = parent_expr.hir_id; + } + + contained_in_place + } +} diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs new file mode 100644 index 00000000000..fd2f5eb5018 --- /dev/null +++ b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs @@ -0,0 +1,996 @@ +use crate::astconv::AstConv; +use crate::check::coercion::CoerceMany; +use crate::check::method::MethodCallee; +use crate::check::Expectation::*; +use crate::check::TupleArgumentsFlag::*; +use crate::check::{ + potentially_plural_count, struct_span_err, BreakableCtxt, Diverges, Expectation, FnCtxt, + LocalTy, Needs, TupleArgumentsFlag, +}; + +use rustc_ast as ast; +use rustc_errors::{Applicability, DiagnosticBuilder, DiagnosticId}; +use rustc_hir as hir; +use rustc_hir::def::{DefKind, Res}; +use rustc_hir::def_id::DefId; +use rustc_hir::{ExprKind, Node, QPath}; +use rustc_middle::ty::adjustment::AllowTwoPhase; +use rustc_middle::ty::fold::TypeFoldable; +use rustc_middle::ty::{self, Ty}; +use rustc_session::Session; +use rustc_span::symbol::{sym, Ident}; +use rustc_span::{self, MultiSpan, Span}; +use rustc_trait_selection::traits::{self, ObligationCauseCode}; + +use std::mem::replace; +use std::slice; + +impl<'a, 'tcx> FnCtxt<'a, 'tcx> { + pub(in super::super) fn check_casts(&self) { + let mut deferred_cast_checks = self.deferred_cast_checks.borrow_mut(); + for cast in deferred_cast_checks.drain(..) { + cast.check(self); + } + } + + pub(in super::super) fn check_method_argument_types( + &self, + sp: Span, + expr: &'tcx hir::Expr<'tcx>, + method: Result<MethodCallee<'tcx>, ()>, + args_no_rcvr: &'tcx [hir::Expr<'tcx>], + tuple_arguments: TupleArgumentsFlag, + expected: Expectation<'tcx>, + ) -> Ty<'tcx> { + let has_error = match method { + Ok(method) => method.substs.references_error() || method.sig.references_error(), + Err(_) => true, + }; + if has_error { + let err_inputs = self.err_args(args_no_rcvr.len()); + + let err_inputs = match tuple_arguments { + DontTupleArguments => err_inputs, + TupleArguments => vec![self.tcx.intern_tup(&err_inputs[..])], + }; + + self.check_argument_types( + sp, + expr, + &err_inputs[..], + &[], + args_no_rcvr, + false, + tuple_arguments, + None, + ); + return self.tcx.ty_error(); + } + + let method = method.unwrap(); + // HACK(eddyb) ignore self in the definition (see above). + let expected_arg_tys = self.expected_inputs_for_expected_output( + sp, + expected, + method.sig.output(), + &method.sig.inputs()[1..], + ); + self.check_argument_types( + sp, + expr, + &method.sig.inputs()[1..], + &expected_arg_tys[..], + args_no_rcvr, + method.sig.c_variadic, + tuple_arguments, + Some(method.def_id), + ); + method.sig.output() + } + + /// Generic function that factors out common logic from function calls, + /// method calls and overloaded operators. + pub(in super::super) fn check_argument_types( + &self, + sp: Span, + expr: &'tcx hir::Expr<'tcx>, + fn_inputs: &[Ty<'tcx>], + expected_arg_tys: &[Ty<'tcx>], + args: &'tcx [hir::Expr<'tcx>], + c_variadic: bool, + tuple_arguments: TupleArgumentsFlag, + def_id: Option<DefId>, + ) { + let tcx = self.tcx; + // Grab the argument types, supplying fresh type variables + // if the wrong number of arguments were supplied + let supplied_arg_count = if tuple_arguments == DontTupleArguments { args.len() } else { 1 }; + + // All the input types from the fn signature must outlive the call + // so as to validate implied bounds. + for (&fn_input_ty, arg_expr) in fn_inputs.iter().zip(args.iter()) { + self.register_wf_obligation(fn_input_ty.into(), arg_expr.span, traits::MiscObligation); + } + + let expected_arg_count = fn_inputs.len(); + + let param_count_error = |expected_count: usize, + arg_count: usize, + error_code: &str, + c_variadic: bool, + sugg_unit: bool| { + let (span, start_span, args) = match &expr.kind { + hir::ExprKind::Call(hir::Expr { span, .. }, args) => (*span, *span, &args[..]), + hir::ExprKind::MethodCall(path_segment, span, args, _) => ( + *span, + // `sp` doesn't point at the whole `foo.bar()`, only at `bar`. + path_segment + .args + .and_then(|args| args.args.iter().last()) + // Account for `foo.bar::<T>()`. + .map(|arg| { + // Skip the closing `>`. + tcx.sess + .source_map() + .next_point(tcx.sess.source_map().next_point(arg.span())) + }) + .unwrap_or(*span), + &args[1..], // Skip the receiver. + ), + k => span_bug!(sp, "checking argument types on a non-call: `{:?}`", k), + }; + let arg_spans = if args.is_empty() { + // foo() + // ^^^-- supplied 0 arguments + // | + // expected 2 arguments + vec![tcx.sess.source_map().next_point(start_span).with_hi(sp.hi())] + } else { + // foo(1, 2, 3) + // ^^^ - - - supplied 3 arguments + // | + // expected 2 arguments + args.iter().map(|arg| arg.span).collect::<Vec<Span>>() + }; + + let mut err = tcx.sess.struct_span_err_with_code( + span, + &format!( + "this function takes {}{} but {} {} supplied", + if c_variadic { "at least " } else { "" }, + potentially_plural_count(expected_count, "argument"), + potentially_plural_count(arg_count, "argument"), + if arg_count == 1 { "was" } else { "were" } + ), + DiagnosticId::Error(error_code.to_owned()), + ); + let label = format!("supplied {}", potentially_plural_count(arg_count, "argument")); + for (i, span) in arg_spans.into_iter().enumerate() { + err.span_label( + span, + if arg_count == 0 || i + 1 == arg_count { &label } else { "" }, + ); + } + + if let Some(def_id) = def_id { + if let Some(node) = tcx.hir().get_if_local(def_id) { + let mut spans: MultiSpan = node + .ident() + .map(|ident| ident.span) + .unwrap_or_else(|| tcx.hir().span(node.hir_id().unwrap())) + .into(); + + if let Some(id) = node.body_id() { + let body = tcx.hir().body(id); + for param in body.params { + spans.push_span_label(param.span, String::new()); + } + } + + let def_kind = tcx.def_kind(def_id); + err.span_note(spans, &format!("{} defined here", def_kind.descr(def_id))); + } + } + + if sugg_unit { + let sugg_span = tcx.sess.source_map().end_point(expr.span); + // remove closing `)` from the span + let sugg_span = sugg_span.shrink_to_lo(); + err.span_suggestion( + sugg_span, + "expected the unit value `()`; create it with empty parentheses", + String::from("()"), + Applicability::MachineApplicable, + ); + } else { + err.span_label( + span, + format!( + "expected {}{}", + if c_variadic { "at least " } else { "" }, + potentially_plural_count(expected_count, "argument") + ), + ); + } + err.emit(); + }; + + let mut expected_arg_tys = expected_arg_tys.to_vec(); + + let formal_tys = if tuple_arguments == TupleArguments { + let tuple_type = self.structurally_resolved_type(sp, fn_inputs[0]); + match tuple_type.kind() { + ty::Tuple(arg_types) if arg_types.len() != args.len() => { + param_count_error(arg_types.len(), args.len(), "E0057", false, false); + expected_arg_tys = vec![]; + self.err_args(args.len()) + } + ty::Tuple(arg_types) => { + expected_arg_tys = match expected_arg_tys.get(0) { + Some(&ty) => match ty.kind() { + ty::Tuple(ref tys) => tys.iter().map(|k| k.expect_ty()).collect(), + _ => vec![], + }, + None => vec![], + }; + arg_types.iter().map(|k| k.expect_ty()).collect() + } + _ => { + struct_span_err!( + tcx.sess, + sp, + E0059, + "cannot use call notation; the first type parameter \ + for the function trait is neither a tuple nor unit" + ) + .emit(); + expected_arg_tys = vec![]; + self.err_args(args.len()) + } + } + } else if expected_arg_count == supplied_arg_count { + fn_inputs.to_vec() + } else if c_variadic { + if supplied_arg_count >= expected_arg_count { + fn_inputs.to_vec() + } else { + param_count_error(expected_arg_count, supplied_arg_count, "E0060", true, false); + expected_arg_tys = vec![]; + self.err_args(supplied_arg_count) + } + } else { + // is the missing argument of type `()`? + let sugg_unit = if expected_arg_tys.len() == 1 && supplied_arg_count == 0 { + self.resolve_vars_if_possible(&expected_arg_tys[0]).is_unit() + } else if fn_inputs.len() == 1 && supplied_arg_count == 0 { + self.resolve_vars_if_possible(&fn_inputs[0]).is_unit() + } else { + false + }; + param_count_error(expected_arg_count, supplied_arg_count, "E0061", false, sugg_unit); + + expected_arg_tys = vec![]; + self.err_args(supplied_arg_count) + }; + + debug!( + "check_argument_types: formal_tys={:?}", + formal_tys.iter().map(|t| self.ty_to_string(*t)).collect::<Vec<String>>() + ); + + // If there is no expectation, expect formal_tys. + let expected_arg_tys = + if !expected_arg_tys.is_empty() { expected_arg_tys } else { formal_tys.clone() }; + + let mut final_arg_types: Vec<(usize, Ty<'_>, Ty<'_>)> = vec![]; + + // Check the arguments. + // We do this in a pretty awful way: first we type-check any arguments + // that are not closures, then we type-check the closures. This is so + // that we have more information about the types of arguments when we + // type-check the functions. This isn't really the right way to do this. + for &check_closures in &[false, true] { + debug!("check_closures={}", check_closures); + + // More awful hacks: before we check argument types, try to do + // an "opportunistic" trait resolution of any trait bounds on + // the call. This helps coercions. + if check_closures { + self.select_obligations_where_possible(false, |errors| { + self.point_at_type_arg_instead_of_call_if_possible(errors, expr); + self.point_at_arg_instead_of_call_if_possible( + errors, + &final_arg_types[..], + sp, + &args, + ); + }) + } + + // For C-variadic functions, we don't have a declared type for all of + // the arguments hence we only do our usual type checking with + // the arguments who's types we do know. + let t = if c_variadic { + expected_arg_count + } else if tuple_arguments == TupleArguments { + args.len() + } else { + supplied_arg_count + }; + for (i, arg) in args.iter().take(t).enumerate() { + // Warn only for the first loop (the "no closures" one). + // Closure arguments themselves can't be diverging, but + // a previous argument can, e.g., `foo(panic!(), || {})`. + if !check_closures { + self.warn_if_unreachable(arg.hir_id, arg.span, "expression"); + } + + let is_closure = match arg.kind { + ExprKind::Closure(..) => true, + _ => false, + }; + + if is_closure != check_closures { + continue; + } + + debug!("checking the argument"); + let formal_ty = formal_tys[i]; + + // The special-cased logic below has three functions: + // 1. Provide as good of an expected type as possible. + let expected = Expectation::rvalue_hint(self, expected_arg_tys[i]); + + let checked_ty = self.check_expr_with_expectation(&arg, expected); + + // 2. Coerce to the most detailed type that could be coerced + // to, which is `expected_ty` if `rvalue_hint` returns an + // `ExpectHasType(expected_ty)`, or the `formal_ty` otherwise. + let coerce_ty = expected.only_has_type(self).unwrap_or(formal_ty); + // We're processing function arguments so we definitely want to use + // two-phase borrows. + self.demand_coerce(&arg, checked_ty, coerce_ty, None, AllowTwoPhase::Yes); + final_arg_types.push((i, checked_ty, coerce_ty)); + + // 3. Relate the expected type and the formal one, + // if the expected type was used for the coercion. + self.demand_suptype(arg.span, formal_ty, coerce_ty); + } + } + + // We also need to make sure we at least write the ty of the other + // arguments which we skipped above. + if c_variadic { + fn variadic_error<'tcx>(s: &Session, span: Span, t: Ty<'tcx>, cast_ty: &str) { + use crate::structured_errors::{StructuredDiagnostic, VariadicError}; + VariadicError::new(s, span, t, cast_ty).diagnostic().emit(); + } + + for arg in args.iter().skip(expected_arg_count) { + let arg_ty = self.check_expr(&arg); + + // There are a few types which get autopromoted when passed via varargs + // in C but we just error out instead and require explicit casts. + let arg_ty = self.structurally_resolved_type(arg.span, arg_ty); + match arg_ty.kind() { + ty::Float(ast::FloatTy::F32) => { + variadic_error(tcx.sess, arg.span, arg_ty, "c_double"); + } + ty::Int(ast::IntTy::I8 | ast::IntTy::I16) | ty::Bool => { + variadic_error(tcx.sess, arg.span, arg_ty, "c_int"); + } + ty::Uint(ast::UintTy::U8 | ast::UintTy::U16) => { + variadic_error(tcx.sess, arg.span, arg_ty, "c_uint"); + } + ty::FnDef(..) => { + let ptr_ty = self.tcx.mk_fn_ptr(arg_ty.fn_sig(self.tcx)); + let ptr_ty = self.resolve_vars_if_possible(&ptr_ty); + variadic_error(tcx.sess, arg.span, arg_ty, &ptr_ty.to_string()); + } + _ => {} + } + } + } + } + + // AST fragment checking + pub(in super::super) fn check_lit( + &self, + lit: &hir::Lit, + expected: Expectation<'tcx>, + ) -> Ty<'tcx> { + let tcx = self.tcx; + + match lit.node { + ast::LitKind::Str(..) => tcx.mk_static_str(), + ast::LitKind::ByteStr(ref v) => { + tcx.mk_imm_ref(tcx.lifetimes.re_static, tcx.mk_array(tcx.types.u8, v.len() as u64)) + } + ast::LitKind::Byte(_) => tcx.types.u8, + ast::LitKind::Char(_) => tcx.types.char, + ast::LitKind::Int(_, ast::LitIntType::Signed(t)) => tcx.mk_mach_int(t), + ast::LitKind::Int(_, ast::LitIntType::Unsigned(t)) => tcx.mk_mach_uint(t), + ast::LitKind::Int(_, ast::LitIntType::Unsuffixed) => { + let opt_ty = expected.to_option(self).and_then(|ty| match ty.kind() { + ty::Int(_) | ty::Uint(_) => Some(ty), + ty::Char => Some(tcx.types.u8), + ty::RawPtr(..) => Some(tcx.types.usize), + ty::FnDef(..) | ty::FnPtr(_) => Some(tcx.types.usize), + _ => None, + }); + opt_ty.unwrap_or_else(|| self.next_int_var()) + } + ast::LitKind::Float(_, ast::LitFloatType::Suffixed(t)) => tcx.mk_mach_float(t), + ast::LitKind::Float(_, ast::LitFloatType::Unsuffixed) => { + let opt_ty = expected.to_option(self).and_then(|ty| match ty.kind() { + ty::Float(_) => Some(ty), + _ => None, + }); + opt_ty.unwrap_or_else(|| self.next_float_var()) + } + ast::LitKind::Bool(_) => tcx.types.bool, + ast::LitKind::Err(_) => tcx.ty_error(), + } + } + + pub fn check_struct_path( + &self, + qpath: &QPath<'_>, + hir_id: hir::HirId, + ) -> Option<(&'tcx ty::VariantDef, Ty<'tcx>)> { + let path_span = qpath.qself_span(); + let (def, ty) = self.finish_resolving_struct_path(qpath, path_span, hir_id); + let variant = match def { + Res::Err => { + self.set_tainted_by_errors(); + return None; + } + Res::Def(DefKind::Variant, _) => match ty.kind() { + ty::Adt(adt, substs) => Some((adt.variant_of_res(def), adt.did, substs)), + _ => bug!("unexpected type: {:?}", ty), + }, + Res::Def(DefKind::Struct | DefKind::Union | DefKind::TyAlias | DefKind::AssocTy, _) + | Res::SelfTy(..) => match ty.kind() { + ty::Adt(adt, substs) if !adt.is_enum() => { + Some((adt.non_enum_variant(), adt.did, substs)) + } + _ => None, + }, + _ => bug!("unexpected definition: {:?}", def), + }; + + if let Some((variant, did, substs)) = variant { + debug!("check_struct_path: did={:?} substs={:?}", did, substs); + self.write_user_type_annotation_from_substs(hir_id, did, substs, None); + + // Check bounds on type arguments used in the path. + let (bounds, _) = self.instantiate_bounds(path_span, did, substs); + let cause = + traits::ObligationCause::new(path_span, self.body_id, traits::ItemObligation(did)); + self.add_obligations_for_parameters(cause, bounds); + + Some((variant, ty)) + } else { + struct_span_err!( + self.tcx.sess, + path_span, + E0071, + "expected struct, variant or union type, found {}", + ty.sort_string(self.tcx) + ) + .span_label(path_span, "not a struct") + .emit(); + None + } + } + + pub fn check_decl_initializer( + &self, + local: &'tcx hir::Local<'tcx>, + init: &'tcx hir::Expr<'tcx>, + ) -> Ty<'tcx> { + // FIXME(tschottdorf): `contains_explicit_ref_binding()` must be removed + // for #42640 (default match binding modes). + // + // See #44848. + let ref_bindings = local.pat.contains_explicit_ref_binding(); + + let local_ty = self.local_ty(init.span, local.hir_id).revealed_ty; + if let Some(m) = ref_bindings { + // Somewhat subtle: if we have a `ref` binding in the pattern, + // we want to avoid introducing coercions for the RHS. This is + // both because it helps preserve sanity and, in the case of + // ref mut, for soundness (issue #23116). In particular, in + // the latter case, we need to be clear that the type of the + // referent for the reference that results is *equal to* the + // type of the place it is referencing, and not some + // supertype thereof. + let init_ty = self.check_expr_with_needs(init, Needs::maybe_mut_place(m)); + self.demand_eqtype(init.span, local_ty, init_ty); + init_ty + } else { + self.check_expr_coercable_to_type(init, local_ty, None) + } + } + + /// Type check a `let` statement. + pub fn check_decl_local(&self, local: &'tcx hir::Local<'tcx>) { + // Determine and write the type which we'll check the pattern against. + let ty = self.local_ty(local.span, local.hir_id).decl_ty; + self.write_ty(local.hir_id, ty); + + // Type check the initializer. + if let Some(ref init) = local.init { + let init_ty = self.check_decl_initializer(local, &init); + self.overwrite_local_ty_if_err(local, ty, init_ty); + } + + // Does the expected pattern type originate from an expression and what is the span? + let (origin_expr, ty_span) = match (local.ty, local.init) { + (Some(ty), _) => (false, Some(ty.span)), // Bias towards the explicit user type. + (_, Some(init)) => (true, Some(init.span)), // No explicit type; so use the scrutinee. + _ => (false, None), // We have `let $pat;`, so the expected type is unconstrained. + }; + + // Type check the pattern. Override if necessary to avoid knock-on errors. + self.check_pat_top(&local.pat, ty, ty_span, origin_expr); + let pat_ty = self.node_ty(local.pat.hir_id); + self.overwrite_local_ty_if_err(local, ty, pat_ty); + } + + pub fn check_stmt(&self, stmt: &'tcx hir::Stmt<'tcx>) { + // Don't do all the complex logic below for `DeclItem`. + match stmt.kind { + hir::StmtKind::Item(..) => return, + hir::StmtKind::Local(..) | hir::StmtKind::Expr(..) | hir::StmtKind::Semi(..) => {} + } + + self.warn_if_unreachable(stmt.hir_id, stmt.span, "statement"); + + // Hide the outer diverging and `has_errors` flags. + let old_diverges = self.diverges.replace(Diverges::Maybe); + let old_has_errors = self.has_errors.replace(false); + + match stmt.kind { + hir::StmtKind::Local(ref l) => { + self.check_decl_local(&l); + } + // Ignore for now. + hir::StmtKind::Item(_) => {} + hir::StmtKind::Expr(ref expr) => { + // Check with expected type of `()`. + self.check_expr_has_type_or_error(&expr, self.tcx.mk_unit(), |err| { + self.suggest_semicolon_at_end(expr.span, err); + }); + } + hir::StmtKind::Semi(ref expr) => { + self.check_expr(&expr); + } + } + + // Combine the diverging and `has_error` flags. + self.diverges.set(self.diverges.get() | old_diverges); + self.has_errors.set(self.has_errors.get() | old_has_errors); + } + + pub fn check_block_no_value(&self, blk: &'tcx hir::Block<'tcx>) { + let unit = self.tcx.mk_unit(); + let ty = self.check_block_with_expected(blk, ExpectHasType(unit)); + + // if the block produces a `!` value, that can always be + // (effectively) coerced to unit. + if !ty.is_never() { + self.demand_suptype(blk.span, unit, ty); + } + } + + pub(in super::super) fn check_block_with_expected( + &self, + blk: &'tcx hir::Block<'tcx>, + expected: Expectation<'tcx>, + ) -> Ty<'tcx> { + let prev = { + let mut fcx_ps = self.ps.borrow_mut(); + let unsafety_state = fcx_ps.recurse(blk); + replace(&mut *fcx_ps, unsafety_state) + }; + + // In some cases, blocks have just one exit, but other blocks + // can be targeted by multiple breaks. This can happen both + // with labeled blocks as well as when we desugar + // a `try { ... }` expression. + // + // Example 1: + // + // 'a: { if true { break 'a Err(()); } Ok(()) } + // + // Here we would wind up with two coercions, one from + // `Err(())` and the other from the tail expression + // `Ok(())`. If the tail expression is omitted, that's a + // "forced unit" -- unless the block diverges, in which + // case we can ignore the tail expression (e.g., `'a: { + // break 'a 22; }` would not force the type of the block + // to be `()`). + let tail_expr = blk.expr.as_ref(); + let coerce_to_ty = expected.coercion_target_type(self, blk.span); + let coerce = if blk.targeted_by_break { + CoerceMany::new(coerce_to_ty) + } else { + let tail_expr: &[&hir::Expr<'_>] = match tail_expr { + Some(e) => slice::from_ref(e), + None => &[], + }; + CoerceMany::with_coercion_sites(coerce_to_ty, tail_expr) + }; + + let prev_diverges = self.diverges.get(); + let ctxt = BreakableCtxt { coerce: Some(coerce), may_break: false }; + + let (ctxt, ()) = self.with_breakable_ctxt(blk.hir_id, ctxt, || { + for s in blk.stmts { + self.check_stmt(s); + } + + // check the tail expression **without** holding the + // `enclosing_breakables` lock below. + let tail_expr_ty = tail_expr.map(|t| self.check_expr_with_expectation(t, expected)); + + let mut enclosing_breakables = self.enclosing_breakables.borrow_mut(); + let ctxt = enclosing_breakables.find_breakable(blk.hir_id); + let coerce = ctxt.coerce.as_mut().unwrap(); + if let Some(tail_expr_ty) = tail_expr_ty { + let tail_expr = tail_expr.unwrap(); + let span = self.get_expr_coercion_span(tail_expr); + let cause = self.cause(span, ObligationCauseCode::BlockTailExpression(blk.hir_id)); + coerce.coerce(self, &cause, tail_expr, tail_expr_ty); + } else { + // Subtle: if there is no explicit tail expression, + // that is typically equivalent to a tail expression + // of `()` -- except if the block diverges. In that + // case, there is no value supplied from the tail + // expression (assuming there are no other breaks, + // this implies that the type of the block will be + // `!`). + // + // #41425 -- label the implicit `()` as being the + // "found type" here, rather than the "expected type". + if !self.diverges.get().is_always() { + // #50009 -- Do not point at the entire fn block span, point at the return type + // span, as it is the cause of the requirement, and + // `consider_hint_about_removing_semicolon` will point at the last expression + // if it were a relevant part of the error. This improves usability in editors + // that highlight errors inline. + let mut sp = blk.span; + let mut fn_span = None; + if let Some((decl, ident)) = self.get_parent_fn_decl(blk.hir_id) { + let ret_sp = decl.output.span(); + if let Some(block_sp) = self.parent_item_span(blk.hir_id) { + // HACK: on some cases (`ui/liveness/liveness-issue-2163.rs`) the + // output would otherwise be incorrect and even misleading. Make sure + // the span we're aiming at correspond to a `fn` body. + if block_sp == blk.span { + sp = ret_sp; + fn_span = Some(ident.span); + } + } + } + coerce.coerce_forced_unit( + self, + &self.misc(sp), + &mut |err| { + if let Some(expected_ty) = expected.only_has_type(self) { + self.consider_hint_about_removing_semicolon(blk, expected_ty, err); + } + if let Some(fn_span) = fn_span { + err.span_label( + fn_span, + "implicitly returns `()` as its body has no tail or `return` \ + expression", + ); + } + }, + false, + ); + } + } + }); + + if ctxt.may_break { + // If we can break from the block, then the block's exit is always reachable + // (... as long as the entry is reachable) - regardless of the tail of the block. + self.diverges.set(prev_diverges); + } + + let mut ty = ctxt.coerce.unwrap().complete(self); + + if self.has_errors.get() || ty.references_error() { + ty = self.tcx.ty_error() + } + + self.write_ty(blk.hir_id, ty); + + *self.ps.borrow_mut() = prev; + ty + } + + pub(in super::super) fn check_rustc_args_require_const( + &self, + def_id: DefId, + hir_id: hir::HirId, + span: Span, + ) { + // We're only interested in functions tagged with + // #[rustc_args_required_const], so ignore anything that's not. + if !self.tcx.has_attr(def_id, sym::rustc_args_required_const) { + return; + } + + // If our calling expression is indeed the function itself, we're good! + // If not, generate an error that this can only be called directly. + if let Node::Expr(expr) = self.tcx.hir().get(self.tcx.hir().get_parent_node(hir_id)) { + if let ExprKind::Call(ref callee, ..) = expr.kind { + if callee.hir_id == hir_id { + return; + } + } + } + + self.tcx.sess.span_err( + span, + "this function can only be invoked directly, not through a function pointer", + ); + } + + /// A common error is to add an extra semicolon: + /// + /// ``` + /// fn foo() -> usize { + /// 22; + /// } + /// ``` + /// + /// This routine checks if the final statement in a block is an + /// expression with an explicit semicolon whose type is compatible + /// with `expected_ty`. If so, it suggests removing the semicolon. + fn consider_hint_about_removing_semicolon( + &self, + blk: &'tcx hir::Block<'tcx>, + expected_ty: Ty<'tcx>, + err: &mut DiagnosticBuilder<'_>, + ) { + if let Some(span_semi) = self.could_remove_semicolon(blk, expected_ty) { + err.span_suggestion( + span_semi, + "consider removing this semicolon", + String::new(), + Applicability::MachineApplicable, + ); + } + } + + fn parent_item_span(&self, id: hir::HirId) -> Option<Span> { + let node = self.tcx.hir().get(self.tcx.hir().get_parent_item(id)); + match node { + Node::Item(&hir::Item { kind: hir::ItemKind::Fn(_, _, body_id), .. }) + | Node::ImplItem(&hir::ImplItem { kind: hir::ImplItemKind::Fn(_, body_id), .. }) => { + let body = self.tcx.hir().body(body_id); + if let ExprKind::Block(block, _) = &body.value.kind { + return Some(block.span); + } + } + _ => {} + } + None + } + + /// Given a function block's `HirId`, returns its `FnDecl` if it exists, or `None` otherwise. + fn get_parent_fn_decl(&self, blk_id: hir::HirId) -> Option<(&'tcx hir::FnDecl<'tcx>, Ident)> { + let parent = self.tcx.hir().get(self.tcx.hir().get_parent_item(blk_id)); + self.get_node_fn_decl(parent).map(|(fn_decl, ident, _)| (fn_decl, ident)) + } + + /// If `expr` is a `match` expression that has only one non-`!` arm, use that arm's tail + /// expression's `Span`, otherwise return `expr.span`. This is done to give better errors + /// when given code like the following: + /// ```text + /// if false { return 0i32; } else { 1u32 } + /// // ^^^^ point at this instead of the whole `if` expression + /// ``` + fn get_expr_coercion_span(&self, expr: &hir::Expr<'_>) -> rustc_span::Span { + if let hir::ExprKind::Match(_, arms, _) = &expr.kind { + let arm_spans: Vec<Span> = arms + .iter() + .filter_map(|arm| { + self.in_progress_typeck_results + .and_then(|typeck_results| { + typeck_results.borrow().node_type_opt(arm.body.hir_id) + }) + .and_then(|arm_ty| { + if arm_ty.is_never() { + None + } else { + Some(match &arm.body.kind { + // Point at the tail expression when possible. + hir::ExprKind::Block(block, _) => { + block.expr.as_ref().map(|e| e.span).unwrap_or(block.span) + } + _ => arm.body.span, + }) + } + }) + }) + .collect(); + if arm_spans.len() == 1 { + return arm_spans[0]; + } + } + expr.span + } + + fn overwrite_local_ty_if_err( + &self, + local: &'tcx hir::Local<'tcx>, + decl_ty: Ty<'tcx>, + ty: Ty<'tcx>, + ) { + if ty.references_error() { + // Override the types everywhere with `err()` to avoid knock on errors. + self.write_ty(local.hir_id, ty); + self.write_ty(local.pat.hir_id, ty); + let local_ty = LocalTy { decl_ty, revealed_ty: ty }; + self.locals.borrow_mut().insert(local.hir_id, local_ty); + self.locals.borrow_mut().insert(local.pat.hir_id, local_ty); + } + } + + // Finish resolving a path in a struct expression or pattern `S::A { .. }` if necessary. + // The newly resolved definition is written into `type_dependent_defs`. + fn finish_resolving_struct_path( + &self, + qpath: &QPath<'_>, + path_span: Span, + hir_id: hir::HirId, + ) -> (Res, Ty<'tcx>) { + match *qpath { + QPath::Resolved(ref maybe_qself, ref path) => { + let self_ty = maybe_qself.as_ref().map(|qself| self.to_ty(qself)); + let ty = AstConv::res_to_ty(self, self_ty, path, true); + (path.res, ty) + } + QPath::TypeRelative(ref qself, ref segment) => { + let ty = self.to_ty(qself); + + let res = if let hir::TyKind::Path(QPath::Resolved(_, ref path)) = qself.kind { + path.res + } else { + Res::Err + }; + let result = + AstConv::associated_path_to_ty(self, hir_id, path_span, ty, res, segment, true); + let ty = result.map(|(ty, _, _)| ty).unwrap_or_else(|_| self.tcx().ty_error()); + let result = result.map(|(_, kind, def_id)| (kind, def_id)); + + // Write back the new resolution. + self.write_resolution(hir_id, result); + + (result.map(|(kind, def_id)| Res::Def(kind, def_id)).unwrap_or(Res::Err), ty) + } + QPath::LangItem(lang_item, span) => { + self.resolve_lang_item_path(lang_item, span, hir_id) + } + } + } + + /// Given a vec of evaluated `FulfillmentError`s and an `fn` call argument expressions, we walk + /// the checked and coerced types for each argument to see if any of the `FulfillmentError`s + /// reference a type argument. The reason to walk also the checked type is that the coerced type + /// can be not easily comparable with predicate type (because of coercion). If the types match + /// for either checked or coerced type, and there's only *one* argument that does, we point at + /// the corresponding argument's expression span instead of the `fn` call path span. + fn point_at_arg_instead_of_call_if_possible( + &self, + errors: &mut Vec<traits::FulfillmentError<'tcx>>, + final_arg_types: &[(usize, Ty<'tcx>, Ty<'tcx>)], + call_sp: Span, + args: &'tcx [hir::Expr<'tcx>], + ) { + // We *do not* do this for desugared call spans to keep good diagnostics when involving + // the `?` operator. + if call_sp.desugaring_kind().is_some() { + return; + } + + for error in errors { + // Only if the cause is somewhere inside the expression we want try to point at arg. + // Otherwise, it means that the cause is somewhere else and we should not change + // anything because we can break the correct span. + if !call_sp.contains(error.obligation.cause.span) { + continue; + } + + if let ty::PredicateAtom::Trait(predicate, _) = + error.obligation.predicate.skip_binders() + { + // Collect the argument position for all arguments that could have caused this + // `FulfillmentError`. + let mut referenced_in = final_arg_types + .iter() + .map(|&(i, checked_ty, _)| (i, checked_ty)) + .chain(final_arg_types.iter().map(|&(i, _, coerced_ty)| (i, coerced_ty))) + .flat_map(|(i, ty)| { + let ty = self.resolve_vars_if_possible(&ty); + // We walk the argument type because the argument's type could have + // been `Option<T>`, but the `FulfillmentError` references `T`. + if ty.walk().any(|arg| arg == predicate.self_ty().into()) { + Some(i) + } else { + None + } + }) + .collect::<Vec<usize>>(); + + // Both checked and coerced types could have matched, thus we need to remove + // duplicates. + + // We sort primitive type usize here and can use unstable sort + referenced_in.sort_unstable(); + referenced_in.dedup(); + + if let (Some(ref_in), None) = (referenced_in.pop(), referenced_in.pop()) { + // We make sure that only *one* argument matches the obligation failure + // and we assign the obligation's span to its expression's. + error.obligation.cause.make_mut().span = args[ref_in].span; + error.points_at_arg_span = true; + } + } + } + } + + /// Given a vec of evaluated `FulfillmentError`s and an `fn` call expression, we walk the + /// `PathSegment`s and resolve their type parameters to see if any of the `FulfillmentError`s + /// were caused by them. If they were, we point at the corresponding type argument's span + /// instead of the `fn` call path span. + fn point_at_type_arg_instead_of_call_if_possible( + &self, + errors: &mut Vec<traits::FulfillmentError<'tcx>>, + call_expr: &'tcx hir::Expr<'tcx>, + ) { + if let hir::ExprKind::Call(path, _) = &call_expr.kind { + if let hir::ExprKind::Path(qpath) = &path.kind { + if let hir::QPath::Resolved(_, path) = &qpath { + for error in errors { + if let ty::PredicateAtom::Trait(predicate, _) = + error.obligation.predicate.skip_binders() + { + // If any of the type arguments in this path segment caused the + // `FullfillmentError`, point at its span (#61860). + for arg in path + .segments + .iter() + .filter_map(|seg| seg.args.as_ref()) + .flat_map(|a| a.args.iter()) + { + if let hir::GenericArg::Type(hir_ty) = &arg { + if let hir::TyKind::Path(hir::QPath::TypeRelative(..)) = + &hir_ty.kind + { + // Avoid ICE with associated types. As this is best + // effort only, it's ok to ignore the case. It + // would trigger in `is_send::<T::AssocType>();` + // from `typeck-default-trait-impl-assoc-type.rs`. + } else { + let ty = AstConv::ast_ty_to_ty(self, hir_ty); + let ty = self.resolve_vars_if_possible(&ty); + if ty == predicate.self_ty() { + error.obligation.cause.make_mut().span = hir_ty.span; + } + } + } + } + } + } + } + } + } + } +} diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs b/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs new file mode 100644 index 00000000000..72c3b233ed9 --- /dev/null +++ b/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs @@ -0,0 +1,295 @@ +mod _impl; +mod checks; +mod suggestions; + +pub use _impl::*; +pub use checks::*; +pub use suggestions::*; + +use crate::astconv::AstConv; +use crate::check::coercion::DynamicCoerceMany; +use crate::check::{Diverges, EnclosingBreakables, Inherited, UnsafetyState}; + +use rustc_hir as hir; +use rustc_hir::def_id::DefId; +use rustc_infer::infer; +use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; +use rustc_infer::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind}; +use rustc_middle::hir::map::blocks::FnLikeNode; +use rustc_middle::ty::fold::TypeFoldable; +use rustc_middle::ty::subst::GenericArgKind; +use rustc_middle::ty::{self, Const, Ty, TyCtxt}; +use rustc_session::Session; +use rustc_span::{self, Span}; +use rustc_trait_selection::traits::{ObligationCause, ObligationCauseCode}; + +use std::cell::{Cell, RefCell}; +use std::ops::Deref; + +pub struct FnCtxt<'a, 'tcx> { + pub(super) body_id: hir::HirId, + + /// The parameter environment used for proving trait obligations + /// in this function. This can change when we descend into + /// closures (as they bring new things into scope), hence it is + /// not part of `Inherited` (as of the time of this writing, + /// closures do not yet change the environment, but they will + /// eventually). + pub(super) param_env: ty::ParamEnv<'tcx>, + + /// Number of errors that had been reported when we started + /// checking this function. On exit, if we find that *more* errors + /// have been reported, we will skip regionck and other work that + /// expects the types within the function to be consistent. + // FIXME(matthewjasper) This should not exist, and it's not correct + // if type checking is run in parallel. + err_count_on_creation: usize, + + /// If `Some`, this stores coercion information for returned + /// expressions. If `None`, this is in a context where return is + /// inappropriate, such as a const expression. + /// + /// This is a `RefCell<DynamicCoerceMany>`, which means that we + /// can track all the return expressions and then use them to + /// compute a useful coercion from the set, similar to a match + /// expression or other branching context. You can use methods + /// like `expected_ty` to access the declared return type (if + /// any). + pub(super) ret_coercion: Option<RefCell<DynamicCoerceMany<'tcx>>>, + + pub(super) ret_coercion_impl_trait: Option<Ty<'tcx>>, + + pub(super) ret_type_span: Option<Span>, + + /// Used exclusively to reduce cost of advanced evaluation used for + /// more helpful diagnostics. + pub(super) in_tail_expr: bool, + + /// First span of a return site that we find. Used in error messages. + pub(super) ret_coercion_span: RefCell<Option<Span>>, + + pub(super) resume_yield_tys: Option<(Ty<'tcx>, Ty<'tcx>)>, + + pub(super) ps: RefCell<UnsafetyState>, + + /// Whether the last checked node generates a divergence (e.g., + /// `return` will set this to `Always`). In general, when entering + /// an expression or other node in the tree, the initial value + /// indicates whether prior parts of the containing expression may + /// have diverged. It is then typically set to `Maybe` (and the + /// old value remembered) for processing the subparts of the + /// current expression. As each subpart is processed, they may set + /// the flag to `Always`, etc. Finally, at the end, we take the + /// result and "union" it with the original value, so that when we + /// return the flag indicates if any subpart of the parent + /// expression (up to and including this part) has diverged. So, + /// if you read it after evaluating a subexpression `X`, the value + /// you get indicates whether any subexpression that was + /// evaluating up to and including `X` diverged. + /// + /// We currently use this flag only for diagnostic purposes: + /// + /// - To warn about unreachable code: if, after processing a + /// sub-expression but before we have applied the effects of the + /// current node, we see that the flag is set to `Always`, we + /// can issue a warning. This corresponds to something like + /// `foo(return)`; we warn on the `foo()` expression. (We then + /// update the flag to `WarnedAlways` to suppress duplicate + /// reports.) Similarly, if we traverse to a fresh statement (or + /// tail expression) from a `Always` setting, we will issue a + /// warning. This corresponds to something like `{return; + /// foo();}` or `{return; 22}`, where we would warn on the + /// `foo()` or `22`. + /// + /// An expression represents dead code if, after checking it, + /// the diverges flag is set to something other than `Maybe`. + pub(super) diverges: Cell<Diverges>, + + /// Whether any child nodes have any type errors. + pub(super) has_errors: Cell<bool>, + + pub(super) enclosing_breakables: RefCell<EnclosingBreakables<'tcx>>, + + pub(super) inh: &'a Inherited<'a, 'tcx>, +} + +impl<'a, 'tcx> FnCtxt<'a, 'tcx> { + pub fn new( + inh: &'a Inherited<'a, 'tcx>, + param_env: ty::ParamEnv<'tcx>, + body_id: hir::HirId, + ) -> FnCtxt<'a, 'tcx> { + FnCtxt { + body_id, + param_env, + err_count_on_creation: inh.tcx.sess.err_count(), + ret_coercion: None, + ret_coercion_impl_trait: None, + ret_type_span: None, + in_tail_expr: false, + ret_coercion_span: RefCell::new(None), + resume_yield_tys: None, + ps: RefCell::new(UnsafetyState::function(hir::Unsafety::Normal, hir::CRATE_HIR_ID)), + diverges: Cell::new(Diverges::Maybe), + has_errors: Cell::new(false), + enclosing_breakables: RefCell::new(EnclosingBreakables { + stack: Vec::new(), + by_id: Default::default(), + }), + inh, + } + } + + pub fn cause(&self, span: Span, code: ObligationCauseCode<'tcx>) -> ObligationCause<'tcx> { + ObligationCause::new(span, self.body_id, code) + } + + pub fn misc(&self, span: Span) -> ObligationCause<'tcx> { + self.cause(span, ObligationCauseCode::MiscObligation) + } + + pub fn sess(&self) -> &Session { + &self.tcx.sess + } + + pub fn errors_reported_since_creation(&self) -> bool { + self.tcx.sess.err_count() > self.err_count_on_creation + } +} + +impl<'a, 'tcx> Deref for FnCtxt<'a, 'tcx> { + type Target = Inherited<'a, 'tcx>; + fn deref(&self) -> &Self::Target { + &self.inh + } +} + +impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> { + fn tcx<'b>(&'b self) -> TyCtxt<'tcx> { + self.tcx + } + + fn item_def_id(&self) -> Option<DefId> { + None + } + + fn default_constness_for_trait_bounds(&self) -> hir::Constness { + // FIXME: refactor this into a method + let node = self.tcx.hir().get(self.body_id); + if let Some(fn_like) = FnLikeNode::from_node(node) { + fn_like.constness() + } else { + hir::Constness::NotConst + } + } + + fn get_type_parameter_bounds(&self, _: Span, def_id: DefId) -> ty::GenericPredicates<'tcx> { + let tcx = self.tcx; + let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local()); + let item_id = tcx.hir().ty_param_owner(hir_id); + let item_def_id = tcx.hir().local_def_id(item_id); + let generics = tcx.generics_of(item_def_id); + let index = generics.param_def_id_to_index[&def_id]; + ty::GenericPredicates { + parent: None, + predicates: tcx.arena.alloc_from_iter( + self.param_env.caller_bounds().iter().filter_map(|predicate| { + match predicate.skip_binders() { + ty::PredicateAtom::Trait(data, _) if data.self_ty().is_param(index) => { + // HACK(eddyb) should get the original `Span`. + let span = tcx.def_span(def_id); + Some((predicate, span)) + } + _ => None, + } + }), + ), + } + } + + fn re_infer(&self, def: Option<&ty::GenericParamDef>, span: Span) -> Option<ty::Region<'tcx>> { + let v = match def { + Some(def) => infer::EarlyBoundRegion(span, def.name), + None => infer::MiscVariable(span), + }; + Some(self.next_region_var(v)) + } + + fn allow_ty_infer(&self) -> bool { + true + } + + fn ty_infer(&self, param: Option<&ty::GenericParamDef>, span: Span) -> Ty<'tcx> { + if let Some(param) = param { + if let GenericArgKind::Type(ty) = self.var_for_def(span, param).unpack() { + return ty; + } + unreachable!() + } else { + self.next_ty_var(TypeVariableOrigin { + kind: TypeVariableOriginKind::TypeInference, + span, + }) + } + } + + fn ct_infer( + &self, + ty: Ty<'tcx>, + param: Option<&ty::GenericParamDef>, + span: Span, + ) -> &'tcx Const<'tcx> { + if let Some(param) = param { + if let GenericArgKind::Const(ct) = self.var_for_def(span, param).unpack() { + return ct; + } + unreachable!() + } else { + self.next_const_var( + ty, + ConstVariableOrigin { kind: ConstVariableOriginKind::ConstInference, span }, + ) + } + } + + fn projected_ty_from_poly_trait_ref( + &self, + span: Span, + item_def_id: DefId, + item_segment: &hir::PathSegment<'_>, + poly_trait_ref: ty::PolyTraitRef<'tcx>, + ) -> Ty<'tcx> { + let (trait_ref, _) = self.replace_bound_vars_with_fresh_vars( + span, + infer::LateBoundRegionConversionTime::AssocTypeProjection(item_def_id), + &poly_trait_ref, + ); + + let item_substs = <dyn AstConv<'tcx>>::create_substs_for_associated_item( + self, + self.tcx, + span, + item_def_id, + item_segment, + trait_ref.substs, + ); + + self.tcx().mk_projection(item_def_id, item_substs) + } + + fn normalize_ty(&self, span: Span, ty: Ty<'tcx>) -> Ty<'tcx> { + if ty.has_escaping_bound_vars() { + ty // FIXME: normalization and escaping regions + } else { + self.normalize_associated_types_in(span, &ty) + } + } + + fn set_tainted_by_errors(&self) { + self.infcx.set_tainted_by_errors() + } + + fn record_ty(&self, hir_id: hir::HirId, ty: Ty<'tcx>, _span: Span) { + self.write_ty(hir_id, ty) + } +} diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs new file mode 100644 index 00000000000..9bad02c41b4 --- /dev/null +++ b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs @@ -0,0 +1,528 @@ +use super::FnCtxt; +use crate::astconv::AstConv; + +use rustc_ast::util::parser::ExprPrecedence; +use rustc_span::{self, Span}; +use rustc_trait_selection::traits; + +use rustc_errors::{Applicability, DiagnosticBuilder}; +use rustc_hir as hir; +use rustc_hir::def::{CtorOf, DefKind}; +use rustc_hir::lang_items::LangItem; +use rustc_hir::{ExprKind, ItemKind, Node}; +use rustc_infer::infer; +use rustc_middle::ty::{self, Ty}; +use rustc_span::symbol::kw; +use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _; + +use std::iter; + +impl<'a, 'tcx> FnCtxt<'a, 'tcx> { + pub(in super::super) fn suggest_semicolon_at_end( + &self, + span: Span, + err: &mut DiagnosticBuilder<'_>, + ) { + err.span_suggestion_short( + span.shrink_to_hi(), + "consider using a semicolon here", + ";".to_string(), + Applicability::MachineApplicable, + ); + } + + /// On implicit return expressions with mismatched types, provides the following suggestions: + /// + /// - Points out the method's return type as the reason for the expected type. + /// - Possible missing semicolon. + /// - Possible missing return type if the return type is the default, and not `fn main()`. + pub fn suggest_mismatched_types_on_tail( + &self, + err: &mut DiagnosticBuilder<'_>, + expr: &'tcx hir::Expr<'tcx>, + expected: Ty<'tcx>, + found: Ty<'tcx>, + cause_span: Span, + blk_id: hir::HirId, + ) -> bool { + let expr = expr.peel_drop_temps(); + self.suggest_missing_semicolon(err, expr, expected, cause_span); + let mut pointing_at_return_type = false; + if let Some((fn_decl, can_suggest)) = self.get_fn_decl(blk_id) { + pointing_at_return_type = + self.suggest_missing_return_type(err, &fn_decl, expected, found, can_suggest); + } + pointing_at_return_type + } + + /// When encountering an fn-like ctor that needs to unify with a value, check whether calling + /// the ctor would successfully solve the type mismatch and if so, suggest it: + /// ``` + /// fn foo(x: usize) -> usize { x } + /// let x: usize = foo; // suggest calling the `foo` function: `foo(42)` + /// ``` + fn suggest_fn_call( + &self, + err: &mut DiagnosticBuilder<'_>, + expr: &hir::Expr<'_>, + expected: Ty<'tcx>, + found: Ty<'tcx>, + ) -> bool { + let hir = self.tcx.hir(); + let (def_id, sig) = match *found.kind() { + ty::FnDef(def_id, _) => (def_id, found.fn_sig(self.tcx)), + ty::Closure(def_id, substs) => (def_id, substs.as_closure().sig()), + _ => return false, + }; + + let sig = self.replace_bound_vars_with_fresh_vars(expr.span, infer::FnCall, &sig).0; + let sig = self.normalize_associated_types_in(expr.span, &sig); + if self.can_coerce(sig.output(), expected) { + let (mut sugg_call, applicability) = if sig.inputs().is_empty() { + (String::new(), Applicability::MachineApplicable) + } else { + ("...".to_string(), Applicability::HasPlaceholders) + }; + let mut msg = "call this function"; + match hir.get_if_local(def_id) { + Some( + Node::Item(hir::Item { kind: ItemKind::Fn(.., body_id), .. }) + | Node::ImplItem(hir::ImplItem { + kind: hir::ImplItemKind::Fn(_, body_id), .. + }) + | Node::TraitItem(hir::TraitItem { + kind: hir::TraitItemKind::Fn(.., hir::TraitFn::Provided(body_id)), + .. + }), + ) => { + let body = hir.body(*body_id); + sugg_call = body + .params + .iter() + .map(|param| match ¶m.pat.kind { + hir::PatKind::Binding(_, _, ident, None) + if ident.name != kw::SelfLower => + { + ident.to_string() + } + _ => "_".to_string(), + }) + .collect::<Vec<_>>() + .join(", "); + } + Some(Node::Expr(hir::Expr { + kind: ExprKind::Closure(_, _, body_id, _, _), + span: full_closure_span, + .. + })) => { + if *full_closure_span == expr.span { + return false; + } + msg = "call this closure"; + let body = hir.body(*body_id); + sugg_call = body + .params + .iter() + .map(|param| match ¶m.pat.kind { + hir::PatKind::Binding(_, _, ident, None) + if ident.name != kw::SelfLower => + { + ident.to_string() + } + _ => "_".to_string(), + }) + .collect::<Vec<_>>() + .join(", "); + } + Some(Node::Ctor(hir::VariantData::Tuple(fields, _))) => { + sugg_call = fields.iter().map(|_| "_").collect::<Vec<_>>().join(", "); + match def_id.as_local().map(|def_id| hir.def_kind(def_id)) { + Some(DefKind::Ctor(hir::def::CtorOf::Variant, _)) => { + msg = "instantiate this tuple variant"; + } + Some(DefKind::Ctor(CtorOf::Struct, _)) => { + msg = "instantiate this tuple struct"; + } + _ => {} + } + } + Some(Node::ForeignItem(hir::ForeignItem { + kind: hir::ForeignItemKind::Fn(_, idents, _), + .. + })) => { + sugg_call = idents + .iter() + .map(|ident| { + if ident.name != kw::SelfLower { + ident.to_string() + } else { + "_".to_string() + } + }) + .collect::<Vec<_>>() + .join(", ") + } + Some(Node::TraitItem(hir::TraitItem { + kind: hir::TraitItemKind::Fn(.., hir::TraitFn::Required(idents)), + .. + })) => { + sugg_call = idents + .iter() + .map(|ident| { + if ident.name != kw::SelfLower { + ident.to_string() + } else { + "_".to_string() + } + }) + .collect::<Vec<_>>() + .join(", ") + } + _ => {} + } + err.span_suggestion_verbose( + expr.span.shrink_to_hi(), + &format!("use parentheses to {}", msg), + format!("({})", sugg_call), + applicability, + ); + return true; + } + false + } + + pub fn suggest_deref_ref_or_into( + &self, + err: &mut DiagnosticBuilder<'_>, + expr: &hir::Expr<'_>, + expected: Ty<'tcx>, + found: Ty<'tcx>, + expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>, + ) { + if let Some((sp, msg, suggestion, applicability)) = self.check_ref(expr, found, expected) { + err.span_suggestion(sp, msg, suggestion, applicability); + } else if let (ty::FnDef(def_id, ..), true) = + (&found.kind(), self.suggest_fn_call(err, expr, expected, found)) + { + if let Some(sp) = self.tcx.hir().span_if_local(*def_id) { + let sp = self.sess().source_map().guess_head_span(sp); + err.span_label(sp, &format!("{} defined here", found)); + } + } else if !self.check_for_cast(err, expr, found, expected, expected_ty_expr) { + let is_struct_pat_shorthand_field = + self.is_hir_id_from_struct_pattern_shorthand_field(expr.hir_id, expr.span); + let methods = self.get_conversion_methods(expr.span, expected, found, expr.hir_id); + if let Ok(expr_text) = self.sess().source_map().span_to_snippet(expr.span) { + let mut suggestions = iter::repeat(&expr_text) + .zip(methods.iter()) + .filter_map(|(receiver, method)| { + let method_call = format!(".{}()", method.ident); + if receiver.ends_with(&method_call) { + None // do not suggest code that is already there (#53348) + } else { + let method_call_list = [".to_vec()", ".to_string()"]; + let sugg = if receiver.ends_with(".clone()") + && method_call_list.contains(&method_call.as_str()) + { + let max_len = receiver.rfind('.').unwrap(); + format!("{}{}", &receiver[..max_len], method_call) + } else { + if expr.precedence().order() < ExprPrecedence::MethodCall.order() { + format!("({}){}", receiver, method_call) + } else { + format!("{}{}", receiver, method_call) + } + }; + Some(if is_struct_pat_shorthand_field { + format!("{}: {}", receiver, sugg) + } else { + sugg + }) + } + }) + .peekable(); + if suggestions.peek().is_some() { + err.span_suggestions( + expr.span, + "try using a conversion method", + suggestions, + Applicability::MaybeIncorrect, + ); + } + } + } + } + + /// When encountering the expected boxed value allocated in the stack, suggest allocating it + /// in the heap by calling `Box::new()`. + pub(in super::super) fn suggest_boxing_when_appropriate( + &self, + err: &mut DiagnosticBuilder<'_>, + expr: &hir::Expr<'_>, + expected: Ty<'tcx>, + found: Ty<'tcx>, + ) { + if self.tcx.hir().is_inside_const_context(expr.hir_id) { + // Do not suggest `Box::new` in const context. + return; + } + if !expected.is_box() || found.is_box() { + return; + } + let boxed_found = self.tcx.mk_box(found); + if let (true, Ok(snippet)) = ( + self.can_coerce(boxed_found, expected), + self.sess().source_map().span_to_snippet(expr.span), + ) { + err.span_suggestion( + expr.span, + "store this in the heap by calling `Box::new`", + format!("Box::new({})", snippet), + Applicability::MachineApplicable, + ); + err.note( + "for more on the distinction between the stack and the heap, read \ + https://doc.rust-lang.org/book/ch15-01-box.html, \ + https://doc.rust-lang.org/rust-by-example/std/box.html, and \ + https://doc.rust-lang.org/std/boxed/index.html", + ); + } + } + + /// When encountering an `impl Future` where `BoxFuture` is expected, suggest `Box::pin`. + pub(in super::super) fn suggest_calling_boxed_future_when_appropriate( + &self, + err: &mut DiagnosticBuilder<'_>, + expr: &hir::Expr<'_>, + expected: Ty<'tcx>, + found: Ty<'tcx>, + ) -> bool { + // Handle #68197. + + if self.tcx.hir().is_inside_const_context(expr.hir_id) { + // Do not suggest `Box::new` in const context. + return false; + } + let pin_did = self.tcx.lang_items().pin_type(); + match expected.kind() { + ty::Adt(def, _) if Some(def.did) != pin_did => return false, + // This guards the `unwrap` and `mk_box` below. + _ if pin_did.is_none() || self.tcx.lang_items().owned_box().is_none() => return false, + _ => {} + } + let boxed_found = self.tcx.mk_box(found); + let new_found = self.tcx.mk_lang_item(boxed_found, LangItem::Pin).unwrap(); + if let (true, Ok(snippet)) = ( + self.can_coerce(new_found, expected), + self.sess().source_map().span_to_snippet(expr.span), + ) { + match found.kind() { + ty::Adt(def, _) if def.is_box() => { + err.help("use `Box::pin`"); + } + _ => { + err.span_suggestion( + expr.span, + "you need to pin and box this expression", + format!("Box::pin({})", snippet), + Applicability::MachineApplicable, + ); + } + } + true + } else { + false + } + } + + /// A common error is to forget to add a semicolon at the end of a block, e.g., + /// + /// ``` + /// fn foo() { + /// bar_that_returns_u32() + /// } + /// ``` + /// + /// This routine checks if the return expression in a block would make sense on its own as a + /// statement and the return type has been left as default or has been specified as `()`. If so, + /// it suggests adding a semicolon. + fn suggest_missing_semicolon( + &self, + err: &mut DiagnosticBuilder<'_>, + expression: &'tcx hir::Expr<'tcx>, + expected: Ty<'tcx>, + cause_span: Span, + ) { + if expected.is_unit() { + // `BlockTailExpression` only relevant if the tail expr would be + // useful on its own. + match expression.kind { + ExprKind::Call(..) + | ExprKind::MethodCall(..) + | ExprKind::Loop(..) + | ExprKind::Match(..) + | ExprKind::Block(..) => { + err.span_suggestion( + cause_span.shrink_to_hi(), + "try adding a semicolon", + ";".to_string(), + Applicability::MachineApplicable, + ); + } + _ => (), + } + } + } + + /// A possible error is to forget to add a return type that is needed: + /// + /// ``` + /// fn foo() { + /// bar_that_returns_u32() + /// } + /// ``` + /// + /// This routine checks if the return type is left as default, the method is not part of an + /// `impl` block and that it isn't the `main` method. If so, it suggests setting the return + /// type. + pub(in super::super) fn suggest_missing_return_type( + &self, + err: &mut DiagnosticBuilder<'_>, + fn_decl: &hir::FnDecl<'_>, + expected: Ty<'tcx>, + found: Ty<'tcx>, + can_suggest: bool, + ) -> bool { + // Only suggest changing the return type for methods that + // haven't set a return type at all (and aren't `fn main()` or an impl). + match (&fn_decl.output, found.is_suggestable(), can_suggest, expected.is_unit()) { + (&hir::FnRetTy::DefaultReturn(span), true, true, true) => { + err.span_suggestion( + span, + "try adding a return type", + format!("-> {} ", self.resolve_vars_with_obligations(found)), + Applicability::MachineApplicable, + ); + true + } + (&hir::FnRetTy::DefaultReturn(span), false, true, true) => { + err.span_label(span, "possibly return type missing here?"); + true + } + (&hir::FnRetTy::DefaultReturn(span), _, false, true) => { + // `fn main()` must return `()`, do not suggest changing return type + err.span_label(span, "expected `()` because of default return type"); + true + } + // expectation was caused by something else, not the default return + (&hir::FnRetTy::DefaultReturn(_), _, _, false) => false, + (&hir::FnRetTy::Return(ref ty), _, _, _) => { + // Only point to return type if the expected type is the return type, as if they + // are not, the expectation must have been caused by something else. + debug!("suggest_missing_return_type: return type {:?} node {:?}", ty, ty.kind); + let sp = ty.span; + let ty = AstConv::ast_ty_to_ty(self, ty); + debug!("suggest_missing_return_type: return type {:?}", ty); + debug!("suggest_missing_return_type: expected type {:?}", ty); + if ty.kind() == expected.kind() { + err.span_label(sp, format!("expected `{}` because of return type", expected)); + return true; + } + false + } + } + } + + /// A possible error is to forget to add `.await` when using futures: + /// + /// ``` + /// async fn make_u32() -> u32 { + /// 22 + /// } + /// + /// fn take_u32(x: u32) {} + /// + /// async fn foo() { + /// let x = make_u32(); + /// take_u32(x); + /// } + /// ``` + /// + /// This routine checks if the found type `T` implements `Future<Output=U>` where `U` is the + /// expected type. If this is the case, and we are inside of an async body, it suggests adding + /// `.await` to the tail of the expression. + pub(in super::super) fn suggest_missing_await( + &self, + err: &mut DiagnosticBuilder<'_>, + expr: &hir::Expr<'_>, + expected: Ty<'tcx>, + found: Ty<'tcx>, + ) { + debug!("suggest_missing_await: expr={:?} expected={:?}, found={:?}", expr, expected, found); + // `.await` is not permitted outside of `async` bodies, so don't bother to suggest if the + // body isn't `async`. + let item_id = self.tcx().hir().get_parent_node(self.body_id); + if let Some(body_id) = self.tcx().hir().maybe_body_owned_by(item_id) { + let body = self.tcx().hir().body(body_id); + if let Some(hir::GeneratorKind::Async(_)) = body.generator_kind { + let sp = expr.span; + // Check for `Future` implementations by constructing a predicate to + // prove: `<T as Future>::Output == U` + let future_trait = self.tcx.require_lang_item(LangItem::Future, Some(sp)); + let item_def_id = self + .tcx + .associated_items(future_trait) + .in_definition_order() + .next() + .unwrap() + .def_id; + // `<T as Future>::Output` + let projection_ty = ty::ProjectionTy { + // `T` + substs: self + .tcx + .mk_substs_trait(found, self.fresh_substs_for_item(sp, item_def_id)), + // `Future::Output` + item_def_id, + }; + + let predicate = ty::PredicateAtom::Projection(ty::ProjectionPredicate { + projection_ty, + ty: expected, + }) + .potentially_quantified(self.tcx, ty::PredicateKind::ForAll); + let obligation = traits::Obligation::new(self.misc(sp), self.param_env, predicate); + + debug!("suggest_missing_await: trying obligation {:?}", obligation); + + if self.infcx.predicate_may_hold(&obligation) { + debug!("suggest_missing_await: obligation held: {:?}", obligation); + if let Ok(code) = self.sess().source_map().span_to_snippet(sp) { + err.span_suggestion( + sp, + "consider using `.await` here", + format!("{}.await", code), + Applicability::MaybeIncorrect, + ); + } else { + debug!("suggest_missing_await: no snippet for {:?}", sp); + } + } else { + debug!("suggest_missing_await: obligation did not hold: {:?}", obligation) + } + } + } + } + + pub(in super::super) fn suggest_missing_parentheses( + &self, + err: &mut DiagnosticBuilder<'_>, + expr: &hir::Expr<'_>, + ) { + let sp = self.tcx.sess.source_map().start_point(expr.span); + if let Some(sp) = self.tcx.sess.parse_sess.ambiguous_block_expr_parse.borrow().get(&sp) { + // `{ 42 } &&x` (#61475) or `{ 42 } && if x { 1 } else { 0 }` + self.tcx.sess.parse_sess.expr_parentheses_needed(err, *sp, None); + } + } +} diff --git a/compiler/rustc_typeck/src/check/generator_interior.rs b/compiler/rustc_typeck/src/check/generator_interior.rs index 93fdf93e9e3..3fc5f02a4a4 100644 --- a/compiler/rustc_typeck/src/check/generator_interior.rs +++ b/compiler/rustc_typeck/src/check/generator_interior.rs @@ -8,11 +8,13 @@ use rustc_data_structures::fx::{FxHashSet, FxIndexSet}; use rustc_hir as hir; use rustc_hir::def::{CtorKind, DefKind, Res}; use rustc_hir::def_id::DefId; +use rustc_hir::hir_id::HirIdSet; use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; -use rustc_hir::{Expr, ExprKind, Pat, PatKind}; +use rustc_hir::{Arm, Expr, ExprKind, Guard, HirId, Pat, PatKind}; use rustc_middle::middle::region::{self, YieldData}; use rustc_middle::ty::{self, Ty}; use rustc_span::Span; +use smallvec::SmallVec; struct InteriorVisitor<'a, 'tcx> { fcx: &'a FnCtxt<'a, 'tcx>, @@ -21,6 +23,13 @@ struct InteriorVisitor<'a, 'tcx> { expr_count: usize, kind: hir::GeneratorKind, prev_unresolved_span: Option<Span>, + /// Match arm guards have temporary borrows from the pattern bindings. + /// In case there is a yield point in a guard with a reference to such bindings, + /// such borrows can span across this yield point. + /// As such, we need to track these borrows and record them despite of the fact + /// that they may succeed the said yield point in the post-order. + guard_bindings: SmallVec<[SmallVec<[HirId; 4]>; 1]>, + guard_bindings_set: HirIdSet, } impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> { @@ -30,6 +39,7 @@ impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> { scope: Option<region::Scope>, expr: Option<&'tcx Expr<'tcx>>, source_span: Span, + guard_borrowing_from_pattern: bool, ) { use rustc_span::DUMMY_SP; @@ -53,7 +63,12 @@ impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> { yield_data.expr_and_pat_count, self.expr_count, source_span ); - if yield_data.expr_and_pat_count >= self.expr_count { + // If it is a borrowing happening in the guard, + // it needs to be recorded regardless because they + // do live across this yield point. + if guard_borrowing_from_pattern + || yield_data.expr_and_pat_count >= self.expr_count + { Some(yield_data) } else { None @@ -134,6 +149,8 @@ pub fn resolve_interior<'a, 'tcx>( expr_count: 0, kind, prev_unresolved_span: None, + guard_bindings: <_>::default(), + guard_bindings_set: <_>::default(), }; intravisit::walk_body(&mut visitor, body); @@ -210,6 +227,38 @@ impl<'a, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'tcx> { NestedVisitorMap::None } + fn visit_arm(&mut self, arm: &'tcx Arm<'tcx>) { + let Arm { guard, pat, body, .. } = arm; + self.visit_pat(pat); + if let Some(ref g) = guard { + self.guard_bindings.push(<_>::default()); + ArmPatCollector { + guard_bindings_set: &mut self.guard_bindings_set, + guard_bindings: self + .guard_bindings + .last_mut() + .expect("should have pushed at least one earlier"), + } + .visit_pat(pat); + + match g { + Guard::If(ref e) => { + self.visit_expr(e); + } + } + + let mut scope_var_ids = + self.guard_bindings.pop().expect("should have pushed at least one earlier"); + for var_id in scope_var_ids.drain(..) { + assert!( + self.guard_bindings_set.remove(&var_id), + "variable should be placed in scope earlier" + ); + } + } + self.visit_expr(body); + } + fn visit_pat(&mut self, pat: &'tcx Pat<'tcx>) { intravisit::walk_pat(self, pat); @@ -218,11 +267,12 @@ impl<'a, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'tcx> { if let PatKind::Binding(..) = pat.kind { let scope = self.region_scope_tree.var_scope(pat.hir_id.local_id); let ty = self.fcx.typeck_results.borrow().pat_ty(pat); - self.record(ty, Some(scope), None, pat.span); + self.record(ty, Some(scope), None, pat.span, false); } } fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) { + let mut guard_borrowing_from_pattern = false; match &expr.kind { ExprKind::Call(callee, args) => match &callee.kind { ExprKind::Path(qpath) => { @@ -249,6 +299,16 @@ impl<'a, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'tcx> { } _ => intravisit::walk_expr(self, expr), }, + ExprKind::Path(qpath) => { + intravisit::walk_expr(self, expr); + let res = self.fcx.typeck_results.borrow().qpath_res(qpath, expr.hir_id); + match res { + Res::Local(id) if self.guard_bindings_set.contains(&id) => { + guard_borrowing_from_pattern = true; + } + _ => {} + } + } _ => intravisit::walk_expr(self, expr), } @@ -259,7 +319,7 @@ impl<'a, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'tcx> { // If there are adjustments, then record the final type -- // this is the actual value that is being produced. if let Some(adjusted_ty) = self.fcx.typeck_results.borrow().expr_ty_adjusted_opt(expr) { - self.record(adjusted_ty, scope, Some(expr), expr.span); + self.record(adjusted_ty, scope, Some(expr), expr.span, guard_borrowing_from_pattern); } // Also record the unadjusted type (which is the only type if @@ -267,10 +327,10 @@ impl<'a, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'tcx> { // unadjusted value is sometimes a "temporary" that would wind // up in a MIR temporary. // - // As an example, consider an expression like `vec![].push()`. + // As an example, consider an expression like `vec![].push(x)`. // Here, the `vec![]` would wind up MIR stored into a // temporary variable `t` which we can borrow to invoke - // `<Vec<_>>::push(&mut t)`. + // `<Vec<_>>::push(&mut t, x)`. // // Note that an expression can have many adjustments, and we // are just ignoring those intermediate types. This is because @@ -287,9 +347,30 @@ impl<'a, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'tcx> { // The type table might not have information for this expression // if it is in a malformed scope. (#66387) if let Some(ty) = self.fcx.typeck_results.borrow().expr_ty_opt(expr) { - self.record(ty, scope, Some(expr), expr.span); + self.record(ty, scope, Some(expr), expr.span, guard_borrowing_from_pattern); } else { self.fcx.tcx.sess.delay_span_bug(expr.span, "no type for node"); } } } + +struct ArmPatCollector<'a> { + guard_bindings_set: &'a mut HirIdSet, + guard_bindings: &'a mut SmallVec<[HirId; 4]>, +} + +impl<'a, 'tcx> Visitor<'tcx> for ArmPatCollector<'a> { + type Map = intravisit::ErasedMap<'tcx>; + + fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> { + NestedVisitorMap::None + } + + fn visit_pat(&mut self, pat: &'tcx Pat<'tcx>) { + intravisit::walk_pat(self, pat); + if let PatKind::Binding(_, id, ..) = pat.kind { + self.guard_bindings.push(id); + self.guard_bindings_set.insert(id); + } + } +} diff --git a/compiler/rustc_typeck/src/check/intrinsic.rs b/compiler/rustc_typeck/src/check/intrinsic.rs index 2ee867c2dd6..f40a250200e 100644 --- a/compiler/rustc_typeck/src/check/intrinsic.rs +++ b/compiler/rustc_typeck/src/check/intrinsic.rs @@ -328,14 +328,14 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) { kw::Try => { let mut_u8 = tcx.mk_mut_ptr(tcx.types.u8); - let try_fn_ty = ty::Binder::bind(tcx.mk_fn_sig( + let try_fn_ty = ty::Binder::dummy(tcx.mk_fn_sig( iter::once(mut_u8), tcx.mk_unit(), false, hir::Unsafety::Normal, Abi::Rust, )); - let catch_fn_ty = ty::Binder::bind(tcx.mk_fn_sig( + let catch_fn_ty = ty::Binder::dummy(tcx.mk_fn_sig( [mut_u8, mut_u8].iter().cloned(), tcx.mk_unit(), false, diff --git a/compiler/rustc_typeck/src/check/method/probe.rs b/compiler/rustc_typeck/src/check/method/probe.rs index c1ba29284da..d403e259398 100644 --- a/compiler/rustc_typeck/src/check/method/probe.rs +++ b/compiler/rustc_typeck/src/check/method/probe.rs @@ -796,29 +796,29 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { // FIXME: do we want to commit to this behavior for param bounds? debug!("assemble_inherent_candidates_from_param(param_ty={:?})", param_ty); - let bounds = - self.param_env.caller_bounds().iter().map(ty::Predicate::skip_binders).filter_map( - |predicate| match predicate { - ty::PredicateAtom::Trait(trait_predicate, _) => { - match trait_predicate.trait_ref.self_ty().kind() { - ty::Param(ref p) if *p == param_ty => { - Some(ty::Binder::bind(trait_predicate.trait_ref)) - } - _ => None, + let bounds = self.param_env.caller_bounds().iter().filter_map(|predicate| { + let bound_predicate = predicate.bound_atom(); + match bound_predicate.skip_binder() { + ty::PredicateAtom::Trait(trait_predicate, _) => { + match *trait_predicate.trait_ref.self_ty().kind() { + ty::Param(p) if p == param_ty => { + Some(bound_predicate.rebind(trait_predicate.trait_ref)) } + _ => None, } - ty::PredicateAtom::Subtype(..) - | ty::PredicateAtom::Projection(..) - | ty::PredicateAtom::RegionOutlives(..) - | ty::PredicateAtom::WellFormed(..) - | ty::PredicateAtom::ObjectSafe(..) - | ty::PredicateAtom::ClosureKind(..) - | ty::PredicateAtom::TypeOutlives(..) - | ty::PredicateAtom::ConstEvaluatable(..) - | ty::PredicateAtom::ConstEquate(..) - | ty::PredicateAtom::TypeWellFormedFromEnv(..) => None, - }, - ); + } + ty::PredicateAtom::Subtype(..) + | ty::PredicateAtom::Projection(..) + | ty::PredicateAtom::RegionOutlives(..) + | ty::PredicateAtom::WellFormed(..) + | ty::PredicateAtom::ObjectSafe(..) + | ty::PredicateAtom::ClosureKind(..) + | ty::PredicateAtom::TypeOutlives(..) + | ty::PredicateAtom::ConstEvaluatable(..) + | ty::PredicateAtom::ConstEquate(..) + | ty::PredicateAtom::TypeWellFormedFromEnv(..) => None, + } + }); self.elaborate_bounds(bounds, |this, poly_trait_ref, item| { let trait_ref = this.erase_late_bound_regions(&poly_trait_ref); diff --git a/compiler/rustc_typeck/src/check/method/suggest.rs b/compiler/rustc_typeck/src/check/method/suggest.rs index e33a4e98c59..6d2ffadc20c 100644 --- a/compiler/rustc_typeck/src/check/method/suggest.rs +++ b/compiler/rustc_typeck/src/check/method/suggest.rs @@ -637,9 +637,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } }; let mut format_pred = |pred: ty::Predicate<'tcx>| { - match pred.skip_binders() { + let bound_predicate = pred.bound_atom(); + match bound_predicate.skip_binder() { ty::PredicateAtom::Projection(pred) => { - let pred = ty::Binder::bind(pred); + let pred = bound_predicate.rebind(pred); // `<Foo as Iterator>::Item = String`. let trait_ref = pred.skip_binder().projection_ty.trait_ref(self.tcx); @@ -658,8 +659,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Some((obligation, trait_ref.self_ty())) } ty::PredicateAtom::Trait(poly_trait_ref, _) => { - let poly_trait_ref = ty::Binder::bind(poly_trait_ref); - let p = poly_trait_ref.skip_binder().trait_ref; + let p = poly_trait_ref.trait_ref; let self_ty = p.self_ty(); let path = p.print_only_trait_path(); let obligation = format!("{}: {}", self_ty, path); diff --git a/compiler/rustc_typeck/src/check/mod.rs b/compiler/rustc_typeck/src/check/mod.rs index 97172d391ba..169ad0df3a5 100644 --- a/compiler/rustc_typeck/src/check/mod.rs +++ b/compiler/rustc_typeck/src/check/mod.rs @@ -96,7 +96,7 @@ use check::{ pub use check::{check_item_type, check_wf_new}; pub use diverges::Diverges; pub use expectation::Expectation; -pub use fn_ctxt::FnCtxt; +pub use fn_ctxt::*; pub use inherited::{Inherited, InheritedBuilder}; use crate::astconv::AstConv; @@ -111,6 +111,7 @@ use rustc_hir::itemlikevisit::ItemLikeVisitor; use rustc_hir::{HirIdMap, Node}; use rustc_index::bit_set::BitSet; use rustc_index::vec::Idx; +use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_middle::ty::fold::{TypeFoldable, TypeFolder}; use rustc_middle::ty::query::Providers; use rustc_middle::ty::subst::GenericArgKind; @@ -264,7 +265,7 @@ pub fn provide(providers: &mut Providers) { } fn adt_destructor(tcx: TyCtxt<'_>, def_id: DefId) -> Option<ty::Destructor> { - tcx.calculate_dtor(def_id, &mut dropck::check_drop_impl) + tcx.calculate_dtor(def_id, dropck::check_drop_impl) } /// If this `DefId` is a "primary tables entry", returns @@ -528,7 +529,20 @@ fn typeck_with_fallback<'tcx>( hir::TyKind::Infer => Some(AstConv::ast_ty_to_ty(&fcx, ty)), _ => None, }) - .unwrap_or_else(fallback); + .unwrap_or_else(|| match tcx.hir().get(id) { + Node::AnonConst(_) => match tcx.hir().get(tcx.hir().get_parent_node(id)) { + Node::Expr(&hir::Expr { + kind: hir::ExprKind::ConstBlock(ref anon_const), + .. + }) if anon_const.hir_id == id => fcx.next_ty_var(TypeVariableOrigin { + kind: TypeVariableOriginKind::TypeInference, + span, + }), + _ => fallback(), + }, + _ => fallback(), + }); + let expected_type = fcx.normalize_associated_types_in(body.value.span, &expected_type); fcx.require_type_is_sized(expected_type, body.value.span, traits::ConstSized); @@ -850,7 +864,8 @@ fn bounds_from_generic_predicates<'tcx>( let mut projections = vec![]; for (predicate, _) in predicates.predicates { debug!("predicate {:?}", predicate); - match predicate.skip_binders() { + let bound_predicate = predicate.bound_atom(); + match bound_predicate.skip_binder() { ty::PredicateAtom::Trait(trait_predicate, _) => { let entry = types.entry(trait_predicate.self_ty()).or_default(); let def_id = trait_predicate.def_id(); @@ -861,7 +876,7 @@ fn bounds_from_generic_predicates<'tcx>( } } ty::PredicateAtom::Projection(projection_pred) => { - projections.push(ty::Binder::bind(projection_pred)); + projections.push(bound_predicate.rebind(projection_pred)); } _ => {} } diff --git a/compiler/rustc_typeck/src/check/upvar.rs b/compiler/rustc_typeck/src/check/upvar.rs index 2c3be0da5dd..1e97bd65a79 100644 --- a/compiler/rustc_typeck/src/check/upvar.rs +++ b/compiler/rustc_typeck/src/check/upvar.rs @@ -202,9 +202,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { "analyze_closure: id={:?} substs={:?} final_upvar_tys={:?}", closure_hir_id, substs, final_upvar_tys ); - for (upvar_ty, final_upvar_ty) in substs.upvar_tys().zip(final_upvar_tys) { - self.demand_suptype(span, upvar_ty, final_upvar_ty); - } + + // Build a tuple (U0..Un) of the final upvar types U0..Un + // and unify the upvar tupe type in the closure with it: + let final_tupled_upvars_type = self.tcx.mk_tup(final_upvar_tys.iter()); + self.demand_suptype(span, substs.tupled_upvars_ty(), final_tupled_upvars_type); // If we are also inferred the closure kind here, // process any deferred resolutions. diff --git a/compiler/rustc_typeck/src/coherence/orphan.rs b/compiler/rustc_typeck/src/coherence/orphan.rs index 917fc5631c4..b2009962aba 100644 --- a/compiler/rustc_typeck/src/coherence/orphan.rs +++ b/compiler/rustc_typeck/src/coherence/orphan.rs @@ -110,7 +110,7 @@ impl ItemLikeVisitor<'v> for OrphanChecker<'tcx> { ) .note( "implementing a foreign trait is only possible if at \ - least one of the types for which is it implemented is local, \ + least one of the types for which it is implemented is local, \ and no uncovered type parameters appear before that first \ local type", ) @@ -135,7 +135,7 @@ impl ItemLikeVisitor<'v> for OrphanChecker<'tcx> { local type", param_ty, )).note("implementing a foreign trait is only possible if at \ - least one of the types for which is it implemented is local" + least one of the types for which it is implemented is local" ).note("only traits defined in the current crate can be \ implemented for a type parameter" ).emit(); diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index b64a1ce7c30..630e80d502e 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -2555,7 +2555,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs { ) .emit(); } - if !tcx.sess.target.target.llvm_target.contains("thumbv8m") { + if !tcx.sess.target.llvm_target.contains("thumbv8m") { struct_span_err!(tcx.sess, attr.span, E0775, "`#[cmse_nonsecure_entry]` is only valid for targets with the TrustZone-M extension") .emit(); } @@ -2655,7 +2655,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs { set.path.segments.iter().map(|x| x.ident.name).collect::<Vec<_>>(); match segments.as_slice() { [sym::arm, sym::a32] | [sym::arm, sym::t32] => { - if !tcx.sess.target.target.options.has_thumb_interworking { + if !tcx.sess.target.options.has_thumb_interworking { struct_span_err!( tcx.sess.diagnostic(), attr.span, diff --git a/compiler/rustc_typeck/src/collect/type_of.rs b/compiler/rustc_typeck/src/collect/type_of.rs index 4b3250a1d44..a754d4dbac7 100644 --- a/compiler/rustc_typeck/src/collect/type_of.rs +++ b/compiler/rustc_typeck/src/collect/type_of.rs @@ -112,12 +112,16 @@ pub(super) fn opt_const_param_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option< tcx.sess.delay_span_bug(tcx.def_span(def_id), "anon const with Res::Err"); return None; } - _ => span_bug!( - DUMMY_SP, - "unexpected anon const res {:?} in path: {:?}", - res, - path, - ), + _ => { + // If the user tries to specify generics on a type that does not take them, + // e.g. `usize<T>`, we may hit this branch, in which case we treat it as if + // no arguments have been passed. An error should already have been emitted. + tcx.sess.delay_span_bug( + tcx.def_span(def_id), + &format!("unexpected anon const res {:?} in path: {:?}", res, path), + ); + return None; + } }; generics @@ -309,6 +313,12 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> { tcx.types.usize } + Node::Expr(&Expr { kind: ExprKind::ConstBlock(ref anon_const), .. }) + if anon_const.hir_id == hir_id => + { + tcx.typeck(def_id).node_type(anon_const.hir_id) + } + Node::Variant(Variant { disr_expr: Some(ref e), .. }) if e.hir_id == hir_id => tcx .adt_def(tcx.hir().get_parent_did(hir_id).to_def_id()) .repr diff --git a/compiler/rustc_typeck/src/expr_use_visitor.rs b/compiler/rustc_typeck/src/expr_use_visitor.rs index e16f26c3304..471909a092f 100644 --- a/compiler/rustc_typeck/src/expr_use_visitor.rs +++ b/compiler/rustc_typeck/src/expr_use_visitor.rs @@ -258,7 +258,10 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { self.consume_exprs(&ia.inputs_exprs); } - hir::ExprKind::Continue(..) | hir::ExprKind::Lit(..) | hir::ExprKind::Err => {} + hir::ExprKind::Continue(..) + | hir::ExprKind::Lit(..) + | hir::ExprKind::ConstBlock(..) + | hir::ExprKind::Err => {} hir::ExprKind::Loop(ref blk, _, _) => { self.walk_block(blk); diff --git a/compiler/rustc_typeck/src/lib.rs b/compiler/rustc_typeck/src/lib.rs index 7efda54fbe0..c1fa39e96eb 100644 --- a/compiler/rustc_typeck/src/lib.rs +++ b/compiler/rustc_typeck/src/lib.rs @@ -317,7 +317,7 @@ fn check_start_fn_ty(tcx: TyCtxt<'_>, start_def_id: LocalDefId) { } } - let se_ty = tcx.mk_fn_ptr(ty::Binder::bind(tcx.mk_fn_sig( + let se_ty = tcx.mk_fn_ptr(ty::Binder::dummy(tcx.mk_fn_sig( [tcx.types.isize, tcx.mk_imm_ptr(tcx.mk_imm_ptr(tcx.types.u8))].iter().cloned(), tcx.types.isize, false, diff --git a/compiler/rustc_typeck/src/mem_categorization.rs b/compiler/rustc_typeck/src/mem_categorization.rs index 04ead74936f..f6ac7aa9155 100644 --- a/compiler/rustc_typeck/src/mem_categorization.rs +++ b/compiler/rustc_typeck/src/mem_categorization.rs @@ -370,6 +370,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { | hir::ExprKind::Loop(..) | hir::ExprKind::Match(..) | hir::ExprKind::Lit(..) + | hir::ExprKind::ConstBlock(..) | hir::ExprKind::Break(..) | hir::ExprKind::Continue(..) | hir::ExprKind::Struct(..) diff --git a/library/alloc/src/alloc.rs b/library/alloc/src/alloc.rs index 4646d4a8335..109c3a0e683 100644 --- a/library/alloc/src/alloc.rs +++ b/library/alloc/src/alloc.rs @@ -14,9 +14,9 @@ mod tests; extern "Rust" { // These are the magic symbols to call the global allocator. rustc generates - // them to call `__rg_alloc` etc if there is a `#[global_allocator]` attribute + // them to call `__rg_alloc` etc. if there is a `#[global_allocator]` attribute // (the code expanding that attribute macro generates those functions), or to call - // the default implementations in libstd (`__rdl_alloc` etc in `src/libstd/alloc.rs`) + // the default implementations in libstd (`__rdl_alloc` etc. in `library/std/src/alloc.rs`) // otherwise. #[rustc_allocator] #[rustc_allocator_nounwind] @@ -36,7 +36,7 @@ extern "Rust" { /// if there is one, or the `std` crate’s default. /// /// Note: while this type is unstable, the functionality it provides can be -/// accessed through the [free functions in `alloc`](index.html#functions). +/// accessed through the [free functions in `alloc`](self#functions). #[unstable(feature = "allocator_api", issue = "32838")] #[derive(Copy, Clone, Default, Debug)] pub struct Global; diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs index 5c8c2c5a5a8..0fc81cb2193 100644 --- a/library/alloc/src/boxed.rs +++ b/library/alloc/src/boxed.rs @@ -815,7 +815,7 @@ impl From<Cow<'_, str>> for Box<str> { #[stable(feature = "boxed_str_conv", since = "1.19.0")] impl From<Box<str>> for Box<[u8]> { - /// Converts a `Box<str>>` into a `Box<[u8]>` + /// Converts a `Box<str>` into a `Box<[u8]>` /// /// This conversion does not allocate on the heap and happens in place. /// diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs index 606bf94f998..92cbce96054 100644 --- a/library/alloc/src/collections/btree/map.rs +++ b/library/alloc/src/collections/btree/map.rs @@ -9,13 +9,16 @@ use core::ops::{Index, RangeBounds}; use core::ptr; use super::borrow::DormantMutRef; -use super::node::{self, marker, ForceResult::*, Handle, InsertResult::*, NodeRef}; +use super::node::{self, marker, ForceResult::*, Handle, NodeRef}; use super::search::{self, SearchResult::*}; use super::unwrap_unchecked; -use Entry::*; use UnderflowResult::*; +mod entry; +pub use entry::{Entry, OccupiedEntry, VacantEntry}; +use Entry::*; + /// A map based on a B-Tree. /// /// B-Trees represent a fundamental compromise between cache-efficiency and actually minimizing @@ -452,69 +455,6 @@ impl<K: fmt::Debug, V: fmt::Debug> fmt::Debug for RangeMut<'_, K, V> { } } -/// A view into a single entry in a map, which may either be vacant or occupied. -/// -/// This `enum` is constructed from the [`entry`] method on [`BTreeMap`]. -/// -/// [`entry`]: BTreeMap::entry -#[stable(feature = "rust1", since = "1.0.0")] -pub enum Entry<'a, K: 'a, V: 'a> { - /// A vacant entry. - #[stable(feature = "rust1", since = "1.0.0")] - Vacant(#[stable(feature = "rust1", since = "1.0.0")] VacantEntry<'a, K, V>), - - /// An occupied entry. - #[stable(feature = "rust1", since = "1.0.0")] - Occupied(#[stable(feature = "rust1", since = "1.0.0")] OccupiedEntry<'a, K, V>), -} - -#[stable(feature = "debug_btree_map", since = "1.12.0")] -impl<K: Debug + Ord, V: Debug> Debug for Entry<'_, K, V> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match *self { - Vacant(ref v) => f.debug_tuple("Entry").field(v).finish(), - Occupied(ref o) => f.debug_tuple("Entry").field(o).finish(), - } - } -} - -/// A view into a vacant entry in a `BTreeMap`. -/// It is part of the [`Entry`] enum. -#[stable(feature = "rust1", since = "1.0.0")] -pub struct VacantEntry<'a, K: 'a, V: 'a> { - key: K, - handle: Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, marker::Edge>, - dormant_map: DormantMutRef<'a, BTreeMap<K, V>>, - - // Be invariant in `K` and `V` - _marker: PhantomData<&'a mut (K, V)>, -} - -#[stable(feature = "debug_btree_map", since = "1.12.0")] -impl<K: Debug + Ord, V> Debug for VacantEntry<'_, K, V> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_tuple("VacantEntry").field(self.key()).finish() - } -} - -/// A view into an occupied entry in a `BTreeMap`. -/// It is part of the [`Entry`] enum. -#[stable(feature = "rust1", since = "1.0.0")] -pub struct OccupiedEntry<'a, K: 'a, V: 'a> { - handle: Handle<NodeRef<marker::Mut<'a>, K, V, marker::LeafOrInternal>, marker::KV>, - dormant_map: DormantMutRef<'a, BTreeMap<K, V>>, - - // Be invariant in `K` and `V` - _marker: PhantomData<&'a mut (K, V)>, -} - -#[stable(feature = "debug_btree_map", since = "1.12.0")] -impl<K: Debug + Ord, V: Debug> Debug for OccupiedEntry<'_, K, V> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("OccupiedEntry").field("key", self.key()).field("value", self.get()).finish() - } -} - // An iterator for merging two sorted sequences into one struct MergeIter<K, V, I: Iterator<Item = (K, V)>> { left: Peekable<I>, @@ -2310,409 +2250,6 @@ impl<K, V> BTreeMap<K, V> { } } -impl<'a, K: Ord, V> Entry<'a, K, V> { - /// Ensures a value is in the entry by inserting the default if empty, and returns - /// a mutable reference to the value in the entry. - /// - /// # Examples - /// - /// ``` - /// use std::collections::BTreeMap; - /// - /// let mut map: BTreeMap<&str, usize> = BTreeMap::new(); - /// map.entry("poneyland").or_insert(12); - /// - /// assert_eq!(map["poneyland"], 12); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn or_insert(self, default: V) -> &'a mut V { - match self { - Occupied(entry) => entry.into_mut(), - Vacant(entry) => entry.insert(default), - } - } - - /// Ensures a value is in the entry by inserting the result of the default function if empty, - /// and returns a mutable reference to the value in the entry. - /// - /// # Examples - /// - /// ``` - /// use std::collections::BTreeMap; - /// - /// let mut map: BTreeMap<&str, String> = BTreeMap::new(); - /// let s = "hoho".to_string(); - /// - /// map.entry("poneyland").or_insert_with(|| s); - /// - /// assert_eq!(map["poneyland"], "hoho".to_string()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn or_insert_with<F: FnOnce() -> V>(self, default: F) -> &'a mut V { - match self { - Occupied(entry) => entry.into_mut(), - Vacant(entry) => entry.insert(default()), - } - } - - #[unstable(feature = "or_insert_with_key", issue = "71024")] - /// Ensures a value is in the entry by inserting, if empty, the result of the default function, - /// which takes the key as its argument, and returns a mutable reference to the value in the - /// entry. - /// - /// # Examples - /// - /// ``` - /// #![feature(or_insert_with_key)] - /// use std::collections::BTreeMap; - /// - /// let mut map: BTreeMap<&str, usize> = BTreeMap::new(); - /// - /// map.entry("poneyland").or_insert_with_key(|key| key.chars().count()); - /// - /// assert_eq!(map["poneyland"], 9); - /// ``` - #[inline] - pub fn or_insert_with_key<F: FnOnce(&K) -> V>(self, default: F) -> &'a mut V { - match self { - Occupied(entry) => entry.into_mut(), - Vacant(entry) => { - let value = default(entry.key()); - entry.insert(value) - } - } - } - - /// Returns a reference to this entry's key. - /// - /// # Examples - /// - /// ``` - /// use std::collections::BTreeMap; - /// - /// let mut map: BTreeMap<&str, usize> = BTreeMap::new(); - /// assert_eq!(map.entry("poneyland").key(), &"poneyland"); - /// ``` - #[stable(feature = "map_entry_keys", since = "1.10.0")] - pub fn key(&self) -> &K { - match *self { - Occupied(ref entry) => entry.key(), - Vacant(ref entry) => entry.key(), - } - } - - /// Provides in-place mutable access to an occupied entry before any - /// potential inserts into the map. - /// - /// # Examples - /// - /// ``` - /// use std::collections::BTreeMap; - /// - /// let mut map: BTreeMap<&str, usize> = BTreeMap::new(); - /// - /// map.entry("poneyland") - /// .and_modify(|e| { *e += 1 }) - /// .or_insert(42); - /// assert_eq!(map["poneyland"], 42); - /// - /// map.entry("poneyland") - /// .and_modify(|e| { *e += 1 }) - /// .or_insert(42); - /// assert_eq!(map["poneyland"], 43); - /// ``` - #[stable(feature = "entry_and_modify", since = "1.26.0")] - pub fn and_modify<F>(self, f: F) -> Self - where - F: FnOnce(&mut V), - { - match self { - Occupied(mut entry) => { - f(entry.get_mut()); - Occupied(entry) - } - Vacant(entry) => Vacant(entry), - } - } -} - -impl<'a, K: Ord, V: Default> Entry<'a, K, V> { - #[stable(feature = "entry_or_default", since = "1.28.0")] - /// Ensures a value is in the entry by inserting the default value if empty, - /// and returns a mutable reference to the value in the entry. - /// - /// # Examples - /// - /// ``` - /// use std::collections::BTreeMap; - /// - /// let mut map: BTreeMap<&str, Option<usize>> = BTreeMap::new(); - /// map.entry("poneyland").or_default(); - /// - /// assert_eq!(map["poneyland"], None); - /// ``` - pub fn or_default(self) -> &'a mut V { - match self { - Occupied(entry) => entry.into_mut(), - Vacant(entry) => entry.insert(Default::default()), - } - } -} - -impl<'a, K: Ord, V> VacantEntry<'a, K, V> { - /// Gets a reference to the key that would be used when inserting a value - /// through the VacantEntry. - /// - /// # Examples - /// - /// ``` - /// use std::collections::BTreeMap; - /// - /// let mut map: BTreeMap<&str, usize> = BTreeMap::new(); - /// assert_eq!(map.entry("poneyland").key(), &"poneyland"); - /// ``` - #[stable(feature = "map_entry_keys", since = "1.10.0")] - pub fn key(&self) -> &K { - &self.key - } - - /// Take ownership of the key. - /// - /// # Examples - /// - /// ``` - /// use std::collections::BTreeMap; - /// use std::collections::btree_map::Entry; - /// - /// let mut map: BTreeMap<&str, usize> = BTreeMap::new(); - /// - /// if let Entry::Vacant(v) = map.entry("poneyland") { - /// v.into_key(); - /// } - /// ``` - #[stable(feature = "map_entry_recover_keys2", since = "1.12.0")] - pub fn into_key(self) -> K { - self.key - } - - /// Sets the value of the entry with the `VacantEntry`'s key, - /// and returns a mutable reference to it. - /// - /// # Examples - /// - /// ``` - /// use std::collections::BTreeMap; - /// use std::collections::btree_map::Entry; - /// - /// let mut map: BTreeMap<&str, u32> = BTreeMap::new(); - /// - /// if let Entry::Vacant(o) = map.entry("poneyland") { - /// o.insert(37); - /// } - /// assert_eq!(map["poneyland"], 37); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn insert(self, value: V) -> &'a mut V { - let out_ptr = match self.handle.insert_recursing(self.key, value) { - (Fit(_), val_ptr) => { - // Safety: We have consumed self.handle and the handle returned. - let map = unsafe { self.dormant_map.awaken() }; - map.length += 1; - val_ptr - } - (Split(ins), val_ptr) => { - drop(ins.left); - // Safety: We have consumed self.handle and the reference returned. - let map = unsafe { self.dormant_map.awaken() }; - let root = map.root.as_mut().unwrap(); - root.push_internal_level().push(ins.k, ins.v, ins.right); - map.length += 1; - val_ptr - } - }; - // Now that we have finished growing the tree using borrowed references, - // dereference the pointer to a part of it, that we picked up along the way. - unsafe { &mut *out_ptr } - } -} - -impl<'a, K: Ord, V> OccupiedEntry<'a, K, V> { - /// Gets a reference to the key in the entry. - /// - /// # Examples - /// - /// ``` - /// use std::collections::BTreeMap; - /// - /// let mut map: BTreeMap<&str, usize> = BTreeMap::new(); - /// map.entry("poneyland").or_insert(12); - /// assert_eq!(map.entry("poneyland").key(), &"poneyland"); - /// ``` - #[stable(feature = "map_entry_keys", since = "1.10.0")] - pub fn key(&self) -> &K { - self.handle.reborrow().into_kv().0 - } - - /// Take ownership of the key and value from the map. - /// - /// # Examples - /// - /// ``` - /// use std::collections::BTreeMap; - /// use std::collections::btree_map::Entry; - /// - /// let mut map: BTreeMap<&str, usize> = BTreeMap::new(); - /// map.entry("poneyland").or_insert(12); - /// - /// if let Entry::Occupied(o) = map.entry("poneyland") { - /// // We delete the entry from the map. - /// o.remove_entry(); - /// } - /// - /// // If now try to get the value, it will panic: - /// // println!("{}", map["poneyland"]); - /// ``` - #[stable(feature = "map_entry_recover_keys2", since = "1.12.0")] - pub fn remove_entry(self) -> (K, V) { - self.remove_kv() - } - - /// Gets a reference to the value in the entry. - /// - /// # Examples - /// - /// ``` - /// use std::collections::BTreeMap; - /// use std::collections::btree_map::Entry; - /// - /// let mut map: BTreeMap<&str, usize> = BTreeMap::new(); - /// map.entry("poneyland").or_insert(12); - /// - /// if let Entry::Occupied(o) = map.entry("poneyland") { - /// assert_eq!(o.get(), &12); - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn get(&self) -> &V { - self.handle.reborrow().into_kv().1 - } - - /// Gets a mutable reference to the value in the entry. - /// - /// If you need a reference to the `OccupiedEntry` that may outlive the - /// destruction of the `Entry` value, see [`into_mut`]. - /// - /// [`into_mut`]: OccupiedEntry::into_mut - /// - /// # Examples - /// - /// ``` - /// use std::collections::BTreeMap; - /// use std::collections::btree_map::Entry; - /// - /// let mut map: BTreeMap<&str, usize> = BTreeMap::new(); - /// map.entry("poneyland").or_insert(12); - /// - /// assert_eq!(map["poneyland"], 12); - /// if let Entry::Occupied(mut o) = map.entry("poneyland") { - /// *o.get_mut() += 10; - /// assert_eq!(*o.get(), 22); - /// - /// // We can use the same Entry multiple times. - /// *o.get_mut() += 2; - /// } - /// assert_eq!(map["poneyland"], 24); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn get_mut(&mut self) -> &mut V { - self.handle.kv_mut().1 - } - - /// Converts the entry into a mutable reference to its value. - /// - /// If you need multiple references to the `OccupiedEntry`, see [`get_mut`]. - /// - /// [`get_mut`]: OccupiedEntry::get_mut - /// - /// # Examples - /// - /// ``` - /// use std::collections::BTreeMap; - /// use std::collections::btree_map::Entry; - /// - /// let mut map: BTreeMap<&str, usize> = BTreeMap::new(); - /// map.entry("poneyland").or_insert(12); - /// - /// assert_eq!(map["poneyland"], 12); - /// if let Entry::Occupied(o) = map.entry("poneyland") { - /// *o.into_mut() += 10; - /// } - /// assert_eq!(map["poneyland"], 22); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn into_mut(self) -> &'a mut V { - self.handle.into_val_mut() - } - - /// Sets the value of the entry with the `OccupiedEntry`'s key, - /// and returns the entry's old value. - /// - /// # Examples - /// - /// ``` - /// use std::collections::BTreeMap; - /// use std::collections::btree_map::Entry; - /// - /// let mut map: BTreeMap<&str, usize> = BTreeMap::new(); - /// map.entry("poneyland").or_insert(12); - /// - /// if let Entry::Occupied(mut o) = map.entry("poneyland") { - /// assert_eq!(o.insert(15), 12); - /// } - /// assert_eq!(map["poneyland"], 15); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn insert(&mut self, value: V) -> V { - mem::replace(self.get_mut(), value) - } - - /// Takes the value of the entry out of the map, and returns it. - /// - /// # Examples - /// - /// ``` - /// use std::collections::BTreeMap; - /// use std::collections::btree_map::Entry; - /// - /// let mut map: BTreeMap<&str, usize> = BTreeMap::new(); - /// map.entry("poneyland").or_insert(12); - /// - /// if let Entry::Occupied(o) = map.entry("poneyland") { - /// assert_eq!(o.remove(), 12); - /// } - /// // If we try to get "poneyland"'s value, it'll panic: - /// // println!("{}", map["poneyland"]); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn remove(self) -> V { - self.remove_kv().1 - } - - // Body of `remove_entry`, separate to keep the above implementations short. - fn remove_kv(self) -> (K, V) { - let mut emptied_internal_root = false; - let (old_kv, _) = self.handle.remove_kv_tracking(|| emptied_internal_root = true); - // SAFETY: we consumed the intermediate root borrow, `self.handle`. - let map = unsafe { self.dormant_map.awaken() }; - map.length -= 1; - if emptied_internal_root { - let root = map.root.as_mut().unwrap(); - root.pop_internal_level(); - } - old_kv - } -} - impl<'a, K: 'a, V: 'a> Handle<NodeRef<marker::Mut<'a>, K, V, marker::LeafOrInternal>, marker::KV> { /// Removes a key/value-pair from the map, and returns that pair, as well as /// the leaf edge corresponding to that former pair. diff --git a/library/alloc/src/collections/btree/map/entry.rs b/library/alloc/src/collections/btree/map/entry.rs new file mode 100644 index 00000000000..73a0ca21f67 --- /dev/null +++ b/library/alloc/src/collections/btree/map/entry.rs @@ -0,0 +1,475 @@ +use core::fmt::{self, Debug}; +use core::marker::PhantomData; +use core::mem; + +use super::super::borrow::DormantMutRef; +use super::super::node::{marker, Handle, InsertResult::*, NodeRef}; +use super::BTreeMap; + +use Entry::*; + +/// A view into a single entry in a map, which may either be vacant or occupied. +/// +/// This `enum` is constructed from the [`entry`] method on [`BTreeMap`]. +/// +/// [`entry`]: BTreeMap::entry +#[stable(feature = "rust1", since = "1.0.0")] +pub enum Entry<'a, K: 'a, V: 'a> { + /// A vacant entry. + #[stable(feature = "rust1", since = "1.0.0")] + Vacant(#[stable(feature = "rust1", since = "1.0.0")] VacantEntry<'a, K, V>), + + /// An occupied entry. + #[stable(feature = "rust1", since = "1.0.0")] + Occupied(#[stable(feature = "rust1", since = "1.0.0")] OccupiedEntry<'a, K, V>), +} + +#[stable(feature = "debug_btree_map", since = "1.12.0")] +impl<K: Debug + Ord, V: Debug> Debug for Entry<'_, K, V> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match *self { + Vacant(ref v) => f.debug_tuple("Entry").field(v).finish(), + Occupied(ref o) => f.debug_tuple("Entry").field(o).finish(), + } + } +} + +/// A view into a vacant entry in a `BTreeMap`. +/// It is part of the [`Entry`] enum. +#[stable(feature = "rust1", since = "1.0.0")] +pub struct VacantEntry<'a, K: 'a, V: 'a> { + pub(super) key: K, + pub(super) handle: Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, marker::Edge>, + pub(super) dormant_map: DormantMutRef<'a, BTreeMap<K, V>>, + + // Be invariant in `K` and `V` + pub(super) _marker: PhantomData<&'a mut (K, V)>, +} + +#[stable(feature = "debug_btree_map", since = "1.12.0")] +impl<K: Debug + Ord, V> Debug for VacantEntry<'_, K, V> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_tuple("VacantEntry").field(self.key()).finish() + } +} + +/// A view into an occupied entry in a `BTreeMap`. +/// It is part of the [`Entry`] enum. +#[stable(feature = "rust1", since = "1.0.0")] +pub struct OccupiedEntry<'a, K: 'a, V: 'a> { + pub(super) handle: Handle<NodeRef<marker::Mut<'a>, K, V, marker::LeafOrInternal>, marker::KV>, + pub(super) dormant_map: DormantMutRef<'a, BTreeMap<K, V>>, + + // Be invariant in `K` and `V` + pub(super) _marker: PhantomData<&'a mut (K, V)>, +} + +#[stable(feature = "debug_btree_map", since = "1.12.0")] +impl<K: Debug + Ord, V: Debug> Debug for OccupiedEntry<'_, K, V> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("OccupiedEntry").field("key", self.key()).field("value", self.get()).finish() + } +} + +impl<'a, K: Ord, V> Entry<'a, K, V> { + /// Ensures a value is in the entry by inserting the default if empty, and returns + /// a mutable reference to the value in the entry. + /// + /// # Examples + /// + /// ``` + /// use std::collections::BTreeMap; + /// + /// let mut map: BTreeMap<&str, usize> = BTreeMap::new(); + /// map.entry("poneyland").or_insert(12); + /// + /// assert_eq!(map["poneyland"], 12); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn or_insert(self, default: V) -> &'a mut V { + match self { + Occupied(entry) => entry.into_mut(), + Vacant(entry) => entry.insert(default), + } + } + + /// Ensures a value is in the entry by inserting the result of the default function if empty, + /// and returns a mutable reference to the value in the entry. + /// + /// # Examples + /// + /// ``` + /// use std::collections::BTreeMap; + /// + /// let mut map: BTreeMap<&str, String> = BTreeMap::new(); + /// let s = "hoho".to_string(); + /// + /// map.entry("poneyland").or_insert_with(|| s); + /// + /// assert_eq!(map["poneyland"], "hoho".to_string()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn or_insert_with<F: FnOnce() -> V>(self, default: F) -> &'a mut V { + match self { + Occupied(entry) => entry.into_mut(), + Vacant(entry) => entry.insert(default()), + } + } + + #[unstable(feature = "or_insert_with_key", issue = "71024")] + /// Ensures a value is in the entry by inserting, if empty, the result of the default function, + /// which takes the key as its argument, and returns a mutable reference to the value in the + /// entry. + /// + /// # Examples + /// + /// ``` + /// #![feature(or_insert_with_key)] + /// use std::collections::BTreeMap; + /// + /// let mut map: BTreeMap<&str, usize> = BTreeMap::new(); + /// + /// map.entry("poneyland").or_insert_with_key(|key| key.chars().count()); + /// + /// assert_eq!(map["poneyland"], 9); + /// ``` + #[inline] + pub fn or_insert_with_key<F: FnOnce(&K) -> V>(self, default: F) -> &'a mut V { + match self { + Occupied(entry) => entry.into_mut(), + Vacant(entry) => { + let value = default(entry.key()); + entry.insert(value) + } + } + } + + /// Returns a reference to this entry's key. + /// + /// # Examples + /// + /// ``` + /// use std::collections::BTreeMap; + /// + /// let mut map: BTreeMap<&str, usize> = BTreeMap::new(); + /// assert_eq!(map.entry("poneyland").key(), &"poneyland"); + /// ``` + #[stable(feature = "map_entry_keys", since = "1.10.0")] + pub fn key(&self) -> &K { + match *self { + Occupied(ref entry) => entry.key(), + Vacant(ref entry) => entry.key(), + } + } + + /// Provides in-place mutable access to an occupied entry before any + /// potential inserts into the map. + /// + /// # Examples + /// + /// ``` + /// use std::collections::BTreeMap; + /// + /// let mut map: BTreeMap<&str, usize> = BTreeMap::new(); + /// + /// map.entry("poneyland") + /// .and_modify(|e| { *e += 1 }) + /// .or_insert(42); + /// assert_eq!(map["poneyland"], 42); + /// + /// map.entry("poneyland") + /// .and_modify(|e| { *e += 1 }) + /// .or_insert(42); + /// assert_eq!(map["poneyland"], 43); + /// ``` + #[stable(feature = "entry_and_modify", since = "1.26.0")] + pub fn and_modify<F>(self, f: F) -> Self + where + F: FnOnce(&mut V), + { + match self { + Occupied(mut entry) => { + f(entry.get_mut()); + Occupied(entry) + } + Vacant(entry) => Vacant(entry), + } + } +} + +impl<'a, K: Ord, V: Default> Entry<'a, K, V> { + #[stable(feature = "entry_or_default", since = "1.28.0")] + /// Ensures a value is in the entry by inserting the default value if empty, + /// and returns a mutable reference to the value in the entry. + /// + /// # Examples + /// + /// ``` + /// use std::collections::BTreeMap; + /// + /// let mut map: BTreeMap<&str, Option<usize>> = BTreeMap::new(); + /// map.entry("poneyland").or_default(); + /// + /// assert_eq!(map["poneyland"], None); + /// ``` + pub fn or_default(self) -> &'a mut V { + match self { + Occupied(entry) => entry.into_mut(), + Vacant(entry) => entry.insert(Default::default()), + } + } +} + +impl<'a, K: Ord, V> VacantEntry<'a, K, V> { + /// Gets a reference to the key that would be used when inserting a value + /// through the VacantEntry. + /// + /// # Examples + /// + /// ``` + /// use std::collections::BTreeMap; + /// + /// let mut map: BTreeMap<&str, usize> = BTreeMap::new(); + /// assert_eq!(map.entry("poneyland").key(), &"poneyland"); + /// ``` + #[stable(feature = "map_entry_keys", since = "1.10.0")] + pub fn key(&self) -> &K { + &self.key + } + + /// Take ownership of the key. + /// + /// # Examples + /// + /// ``` + /// use std::collections::BTreeMap; + /// use std::collections::btree_map::Entry; + /// + /// let mut map: BTreeMap<&str, usize> = BTreeMap::new(); + /// + /// if let Entry::Vacant(v) = map.entry("poneyland") { + /// v.into_key(); + /// } + /// ``` + #[stable(feature = "map_entry_recover_keys2", since = "1.12.0")] + pub fn into_key(self) -> K { + self.key + } + + /// Sets the value of the entry with the `VacantEntry`'s key, + /// and returns a mutable reference to it. + /// + /// # Examples + /// + /// ``` + /// use std::collections::BTreeMap; + /// use std::collections::btree_map::Entry; + /// + /// let mut map: BTreeMap<&str, u32> = BTreeMap::new(); + /// + /// if let Entry::Vacant(o) = map.entry("poneyland") { + /// o.insert(37); + /// } + /// assert_eq!(map["poneyland"], 37); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn insert(self, value: V) -> &'a mut V { + let out_ptr = match self.handle.insert_recursing(self.key, value) { + (Fit(_), val_ptr) => { + // Safety: We have consumed self.handle and the handle returned. + let map = unsafe { self.dormant_map.awaken() }; + map.length += 1; + val_ptr + } + (Split(ins), val_ptr) => { + drop(ins.left); + // Safety: We have consumed self.handle and the reference returned. + let map = unsafe { self.dormant_map.awaken() }; + let root = map.root.as_mut().unwrap(); + root.push_internal_level().push(ins.k, ins.v, ins.right); + map.length += 1; + val_ptr + } + }; + // Now that we have finished growing the tree using borrowed references, + // dereference the pointer to a part of it, that we picked up along the way. + unsafe { &mut *out_ptr } + } +} + +impl<'a, K: Ord, V> OccupiedEntry<'a, K, V> { + /// Gets a reference to the key in the entry. + /// + /// # Examples + /// + /// ``` + /// use std::collections::BTreeMap; + /// + /// let mut map: BTreeMap<&str, usize> = BTreeMap::new(); + /// map.entry("poneyland").or_insert(12); + /// assert_eq!(map.entry("poneyland").key(), &"poneyland"); + /// ``` + #[stable(feature = "map_entry_keys", since = "1.10.0")] + pub fn key(&self) -> &K { + self.handle.reborrow().into_kv().0 + } + + /// Take ownership of the key and value from the map. + /// + /// # Examples + /// + /// ``` + /// use std::collections::BTreeMap; + /// use std::collections::btree_map::Entry; + /// + /// let mut map: BTreeMap<&str, usize> = BTreeMap::new(); + /// map.entry("poneyland").or_insert(12); + /// + /// if let Entry::Occupied(o) = map.entry("poneyland") { + /// // We delete the entry from the map. + /// o.remove_entry(); + /// } + /// + /// // If now try to get the value, it will panic: + /// // println!("{}", map["poneyland"]); + /// ``` + #[stable(feature = "map_entry_recover_keys2", since = "1.12.0")] + pub fn remove_entry(self) -> (K, V) { + self.remove_kv() + } + + /// Gets a reference to the value in the entry. + /// + /// # Examples + /// + /// ``` + /// use std::collections::BTreeMap; + /// use std::collections::btree_map::Entry; + /// + /// let mut map: BTreeMap<&str, usize> = BTreeMap::new(); + /// map.entry("poneyland").or_insert(12); + /// + /// if let Entry::Occupied(o) = map.entry("poneyland") { + /// assert_eq!(o.get(), &12); + /// } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn get(&self) -> &V { + self.handle.reborrow().into_kv().1 + } + + /// Gets a mutable reference to the value in the entry. + /// + /// If you need a reference to the `OccupiedEntry` that may outlive the + /// destruction of the `Entry` value, see [`into_mut`]. + /// + /// [`into_mut`]: OccupiedEntry::into_mut + /// + /// # Examples + /// + /// ``` + /// use std::collections::BTreeMap; + /// use std::collections::btree_map::Entry; + /// + /// let mut map: BTreeMap<&str, usize> = BTreeMap::new(); + /// map.entry("poneyland").or_insert(12); + /// + /// assert_eq!(map["poneyland"], 12); + /// if let Entry::Occupied(mut o) = map.entry("poneyland") { + /// *o.get_mut() += 10; + /// assert_eq!(*o.get(), 22); + /// + /// // We can use the same Entry multiple times. + /// *o.get_mut() += 2; + /// } + /// assert_eq!(map["poneyland"], 24); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn get_mut(&mut self) -> &mut V { + self.handle.kv_mut().1 + } + + /// Converts the entry into a mutable reference to its value. + /// + /// If you need multiple references to the `OccupiedEntry`, see [`get_mut`]. + /// + /// [`get_mut`]: OccupiedEntry::get_mut + /// + /// # Examples + /// + /// ``` + /// use std::collections::BTreeMap; + /// use std::collections::btree_map::Entry; + /// + /// let mut map: BTreeMap<&str, usize> = BTreeMap::new(); + /// map.entry("poneyland").or_insert(12); + /// + /// assert_eq!(map["poneyland"], 12); + /// if let Entry::Occupied(o) = map.entry("poneyland") { + /// *o.into_mut() += 10; + /// } + /// assert_eq!(map["poneyland"], 22); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn into_mut(self) -> &'a mut V { + self.handle.into_val_mut() + } + + /// Sets the value of the entry with the `OccupiedEntry`'s key, + /// and returns the entry's old value. + /// + /// # Examples + /// + /// ``` + /// use std::collections::BTreeMap; + /// use std::collections::btree_map::Entry; + /// + /// let mut map: BTreeMap<&str, usize> = BTreeMap::new(); + /// map.entry("poneyland").or_insert(12); + /// + /// if let Entry::Occupied(mut o) = map.entry("poneyland") { + /// assert_eq!(o.insert(15), 12); + /// } + /// assert_eq!(map["poneyland"], 15); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn insert(&mut self, value: V) -> V { + mem::replace(self.get_mut(), value) + } + + /// Takes the value of the entry out of the map, and returns it. + /// + /// # Examples + /// + /// ``` + /// use std::collections::BTreeMap; + /// use std::collections::btree_map::Entry; + /// + /// let mut map: BTreeMap<&str, usize> = BTreeMap::new(); + /// map.entry("poneyland").or_insert(12); + /// + /// if let Entry::Occupied(o) = map.entry("poneyland") { + /// assert_eq!(o.remove(), 12); + /// } + /// // If we try to get "poneyland"'s value, it'll panic: + /// // println!("{}", map["poneyland"]); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn remove(self) -> V { + self.remove_kv().1 + } + + // Body of `remove_entry`, separate to keep the above implementations short. + pub(super) fn remove_kv(self) -> (K, V) { + let mut emptied_internal_root = false; + let (old_kv, _) = self.handle.remove_kv_tracking(|| emptied_internal_root = true); + // SAFETY: we consumed the intermediate root borrow, `self.handle`. + let map = unsafe { self.dormant_map.awaken() }; + map.length -= 1; + if emptied_internal_root { + let root = map.root.as_mut().unwrap(); + root.pop_internal_level(); + } + old_kv + } +} diff --git a/library/alloc/src/collections/btree/map/tests.rs b/library/alloc/src/collections/btree/map/tests.rs index 118e173bb16..b51b95a635c 100644 --- a/library/alloc/src/collections/btree/map/tests.rs +++ b/library/alloc/src/collections/btree/map/tests.rs @@ -1,4 +1,4 @@ -use super::super::{navigate::Position, node, DeterministicRng}; +use super::super::{node, DeterministicRng}; use super::Entry::{Occupied, Vacant}; use super::*; use crate::boxed::Box; @@ -7,7 +7,7 @@ use crate::rc::Rc; use crate::string::{String, ToString}; use crate::vec::Vec; use std::convert::TryFrom; -use std::iter::FromIterator; +use std::iter::{self, FromIterator}; use std::mem; use std::ops::Bound::{self, Excluded, Included, Unbounded}; use std::ops::RangeBounds; @@ -42,19 +42,6 @@ fn test_all_refs<'a, T: 'a>(dummy: &mut T, iter: impl Iterator<Item = &'a mut T> } } -struct SeriesChecker<T> { - previous: Option<T>, -} - -impl<T: Copy + Debug + Ord> SeriesChecker<T> { - fn is_ascending(&mut self, next: T) { - if let Some(previous) = self.previous { - assert!(previous < next, "{:?} >= {:?}", previous, next); - } - self.previous = Some(next); - } -} - impl<'a, K: 'a, V: 'a> BTreeMap<K, V> { /// Panics if the map (or the code navigating it) is corrupted. fn check(&self) @@ -63,44 +50,10 @@ impl<'a, K: 'a, V: 'a> BTreeMap<K, V> { { if let Some(root) = &self.root { let root_node = root.node_as_ref(); - let mut checker = SeriesChecker { previous: None }; - let mut internal_length = 0; - let mut internal_kv_count = 0; - let mut leaf_length = 0; - root_node.visit_nodes_in_order(|pos| match pos { - Position::Leaf(node) => { - let is_root = root_node.height() == 0; - let min_len = if is_root { 0 } else { node::MIN_LEN }; - assert!(node.len() >= min_len, "{} < {}", node.len(), min_len); - - for idx in 0..node.len() { - let key = *unsafe { node.key_at(idx) }; - checker.is_ascending(key); - } - leaf_length += node.len(); - } - Position::Internal(node) => { - let is_root = root_node.height() == node.height(); - let min_len = if is_root { 1 } else { node::MIN_LEN }; - assert!(node.len() >= min_len, "{} < {}", node.len(), min_len); - - for idx in 0..=node.len() { - let edge = unsafe { node::Handle::new_edge(node, idx) }; - assert!(edge.descend().ascend().ok().unwrap() == edge); - } - - internal_length += node.len(); - } - Position::InternalKV(kv) => { - let key = *kv.into_kv().0; - checker.is_ascending(key); - - internal_kv_count += 1; - } - }); - assert_eq!(internal_length, internal_kv_count); - assert_eq!(root_node.calc_length(), internal_length + leaf_length); - assert_eq!(self.length, internal_length + leaf_length); + assert!(root_node.ascend().is_err()); + root_node.assert_back_pointers(); + root_node.assert_ascending(); + assert_eq!(self.length, root_node.assert_and_add_lengths()); } else { assert_eq!(self.length, 0); } @@ -116,28 +69,7 @@ impl<'a, K: 'a, V: 'a> BTreeMap<K, V> { K: Debug, { if let Some(root) = self.root.as_ref() { - let mut result = String::new(); - let root_node = root.node_as_ref(); - root_node.visit_nodes_in_order(|pos| match pos { - Position::Leaf(leaf) => { - let depth = root_node.height(); - let indent = " ".repeat(depth); - result += &format!("\n{}", indent); - for idx in 0..leaf.len() { - if idx > 0 { - result += ", "; - } - result += &format!("{:?}", unsafe { leaf.key_at(idx) }); - } - } - Position::Internal(_) => {} - Position::InternalKV(kv) => { - let depth = root_node.height() - kv.into_node().height(); - let indent = " ".repeat(depth); - result += &format!("\n{}{:?}", indent, kv.into_kv().0); - } - }); - result + root.node_as_ref().dump_keys() } else { String::from("not yet allocated") } @@ -170,7 +102,6 @@ fn test_levels() { let last_key = *map.last_key_value().unwrap().0; map.insert(last_key + 1, ()); } - println!("{}", map.dump_keys()); map.check(); // Structure: // - 1 element in internal root node with 2 children @@ -372,7 +303,7 @@ fn test_iter_rev() { fn do_test_iter_mut_mutation<T>(size: usize) where T: Copy + Debug + Ord + TryFrom<usize>, - <T as std::convert::TryFrom<usize>>::Error: std::fmt::Debug, + <T as TryFrom<usize>>::Error: Debug, { let zero = T::try_from(0).unwrap(); let mut map: BTreeMap<T, T> = (0..size).map(|i| (T::try_from(i).unwrap(), zero)).collect(); @@ -857,7 +788,7 @@ mod test_drain_filter { fn consuming_nothing() { let pairs = (0..3).map(|i| (i, i)); let mut map: BTreeMap<_, _> = pairs.collect(); - assert!(map.drain_filter(|_, _| false).eq(std::iter::empty())); + assert!(map.drain_filter(|_, _| false).eq(iter::empty())); map.check(); } @@ -878,7 +809,7 @@ mod test_drain_filter { *v += 6; false }) - .eq(std::iter::empty()) + .eq(iter::empty()) ); assert!(map.keys().copied().eq(0..3)); assert!(map.values().copied().eq(6..9)); diff --git a/library/alloc/src/collections/btree/node.rs b/library/alloc/src/collections/btree/node.rs index 880627e94c3..cf7961cbbfc 100644 --- a/library/alloc/src/collections/btree/node.rs +++ b/library/alloc/src/collections/btree/node.rs @@ -87,7 +87,6 @@ impl<K, V> LeafNode<K, V> { #[repr(C)] // gdb_providers.py uses this type name for introspection. struct InternalNode<K, V> { - // gdb_providers.py uses this field name for introspection. data: LeafNode<K, V>, /// The pointers to the children of this node. `len + 1` of these are considered @@ -170,6 +169,22 @@ impl<K, V> Root<K, V> { NodeRef { height: self.height, node: self.node.as_ptr(), _marker: PhantomData } } + /// Borrows and returns a mutable reference to the leaf node owned by the root. + /// # Safety + /// The root node is a leaf. + unsafe fn leaf_node_as_mut(&mut self) -> NodeRef<marker::Mut<'_>, K, V, marker::Leaf> { + debug_assert!(self.height == 0); + NodeRef { height: self.height, node: self.node.as_ptr(), _marker: PhantomData } + } + + /// Borrows and returns a mutable reference to the internal node owned by the root. + /// # Safety + /// The root node is not a leaf. + unsafe fn internal_node_as_mut(&mut self) -> NodeRef<marker::Mut<'_>, K, V, marker::Internal> { + debug_assert!(self.height > 0); + NodeRef { height: self.height, node: self.node.as_ptr(), _marker: PhantomData } + } + pub fn node_as_valmut(&mut self) -> NodeRef<marker::ValMut<'_>, K, V, marker::LeafOrInternal> { NodeRef { height: self.height, node: self.node.as_ptr(), _marker: PhantomData } } @@ -188,14 +203,11 @@ impl<K, V> Root<K, V> { self.node = BoxedNode::from_internal(new_node); self.height += 1; - let mut ret = - NodeRef { height: self.height, node: self.node.as_ptr(), _marker: PhantomData }; - unsafe { + let mut ret = self.internal_node_as_mut(); ret.reborrow_mut().first_edge().correct_parent_link(); + ret } - - ret } /// Removes the internal root node, using its first child as the new root node. @@ -212,11 +224,8 @@ impl<K, V> Root<K, V> { let top = self.node.ptr; - self.node = unsafe { - BoxedNode::from_ptr( - self.node_as_mut().cast_unchecked::<marker::Internal>().first_edge().descend().node, - ) - }; + let internal_node = unsafe { self.internal_node_as_mut() }; + self.node = unsafe { BoxedNode::from_ptr(internal_node.first_edge().descend().node) }; self.height -= 1; self.node_as_mut().as_leaf_mut().parent = None; @@ -247,8 +256,13 @@ impl<K, V> Root<K, V> { /// `NodeRef` points to an internal node, and when this is `LeafOrInternal` the /// `NodeRef` could be pointing to either type of node. pub struct NodeRef<BorrowType, K, V, Type> { - /// The number of levels below the node. + /// The number of levels below the node, a property of the node that cannot be + /// entirely described by `Type` and that the node does not store itself either. + /// Unconstrained if `Type` is `LeafOrInternal`, must be zero if `Type` is `Leaf`, + /// and must be non-zero if `Type` is `Internal`. height: usize, + /// The pointer to the leaf or internal node. The definition of `InternalNode` + /// ensures that the pointer is valid either way. node: NonNull<LeafNode<K, V>>, _marker: PhantomData<(BorrowType, Type)>, } @@ -305,8 +319,8 @@ impl<BorrowType, K, V, Type> NodeRef<BorrowType, K, V, Type> { unsafe { usize::from((*self.as_leaf_ptr()).len) } } - /// Returns the height of this node in the whole tree. Zero height denotes the - /// leaf level. + /// Returns the height of this node with respect to the leaf level. Zero height means the + /// node is a leaf itself. pub fn height(&self) -> usize { self.height } @@ -443,9 +457,9 @@ impl<K, V> NodeRef<marker::Owned, K, V, marker::LeafOrInternal> { } impl<'a, K, V, Type> NodeRef<marker::Mut<'a>, K, V, Type> { - /// Unsafely asserts to the compiler some static information about whether this - /// node is a `Leaf` or an `Internal`. - unsafe fn cast_unchecked<NewType>(self) -> NodeRef<marker::Mut<'a>, K, V, NewType> { + /// Unsafely asserts to the compiler the static information that this node is an `Internal`. + unsafe fn cast_to_internal_unchecked(self) -> NodeRef<marker::Mut<'a>, K, V, marker::Internal> { + debug_assert!(self.height > 0); NodeRef { height: self.height, node: self.node, _marker: PhantomData } } @@ -574,9 +588,11 @@ impl<'a, K, V, Type> NodeRef<marker::ValMut<'a>, K, V, Type> { // to avoid aliasing with outstanding references to other elements, // in particular, those returned to the caller in earlier iterations. let leaf = self.node.as_ptr(); + let keys = unsafe { &raw const (*leaf).keys }; + let vals = unsafe { &raw mut (*leaf).vals }; // We must coerce to unsized array pointers because of Rust issue #74679. - let keys: *const [_] = unsafe { &raw const (*leaf).keys }; - let vals: *mut [_] = unsafe { &raw mut (*leaf).vals }; + let keys: *const [_] = keys; + let vals: *mut [_] = vals; // SAFETY: The keys and values of a node must always be initialized up to length. let key = unsafe { (&*keys.get_unchecked(idx)).assume_init_ref() }; let val = unsafe { (&mut *vals.get_unchecked_mut(idx)).assume_init_mut() }; @@ -807,11 +823,25 @@ impl<BorrowType, K, V, NodeType> Handle<NodeRef<BorrowType, K, V, NodeType>, mar } } +impl<BorrowType, K, V, NodeType> NodeRef<BorrowType, K, V, NodeType> { + /// Could be a public implementation of PartialEq, but only used in this module. + fn eq(&self, other: &Self) -> bool { + let Self { node, height, _marker: _ } = self; + if *node == other.node { + debug_assert_eq!(*height, other.height); + true + } else { + false + } + } +} + impl<BorrowType, K, V, NodeType, HandleType> PartialEq for Handle<NodeRef<BorrowType, K, V, NodeType>, HandleType> { fn eq(&self, other: &Self) -> bool { - self.node.node == other.node.node && self.idx == other.idx + let Self { node, idx, _marker: _ } = self; + node.eq(&other.node) && *idx == other.idx } } @@ -819,7 +849,8 @@ impl<BorrowType, K, V, NodeType, HandleType> PartialOrd for Handle<NodeRef<BorrowType, K, V, NodeType>, HandleType> { fn partial_cmp(&self, other: &Self) -> Option<Ordering> { - if self.node.node == other.node.node { Some(self.idx.cmp(&other.idx)) } else { None } + let Self { node, idx, _marker: _ } = self; + if node.eq(&other.node) { Some(idx.cmp(&other.idx)) } else { None } } } @@ -943,10 +974,7 @@ impl<'a, K: 'a, V: 'a> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, mark Handle::new_edge(left.reborrow_mut(), insert_idx) }, InsertionPlace::Right(insert_idx) => unsafe { - Handle::new_edge( - right.node_as_mut().cast_unchecked::<marker::Leaf>(), - insert_idx, - ) + Handle::new_edge(right.leaf_node_as_mut(), insert_idx) }, }; let val_ptr = insertion_edge.insert_fit(key, val); @@ -1006,10 +1034,7 @@ impl<'a, K: 'a, V: 'a> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Internal>, Handle::new_edge(left.reborrow_mut(), insert_idx) }, InsertionPlace::Right(insert_idx) => unsafe { - Handle::new_edge( - right.node_as_mut().cast_unchecked::<marker::Internal>(), - insert_idx, - ) + Handle::new_edge(right.internal_node_as_mut(), insert_idx) }, }; insertion_edge.insert_fit(key, val, edge); @@ -1205,7 +1230,7 @@ impl<'a, K: 'a, V: 'a> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Internal>, let mut new_root = Root { node: BoxedNode::from_internal(new_node), height }; - new_root.node_as_mut().cast_unchecked().correct_childrens_parent_links(0..=new_len); + new_root.internal_node_as_mut().correct_childrens_parent_links(0..=new_len); (self.node, k, v, new_root) } @@ -1258,8 +1283,8 @@ impl<'a, K: 'a, V: 'a> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Internal>, if self.node.height > 1 { // SAFETY: the height of the nodes being merged is one below the height // of the node of this edge, thus above zero, so they are internal. - let mut left_node = left_node.cast_unchecked::<marker::Internal>(); - let right_node = right_node.cast_unchecked::<marker::Internal>(); + let mut left_node = left_node.cast_to_internal_unchecked(); + let right_node = right_node.cast_to_internal_unchecked(); ptr::copy_nonoverlapping( right_node.edge_at(0), left_node.edges_mut().as_mut_ptr().add(left_len + 1), diff --git a/library/alloc/src/collections/btree/node/tests.rs b/library/alloc/src/collections/btree/node/tests.rs index 54c3709821a..e56fc2aa51e 100644 --- a/library/alloc/src/collections/btree/node/tests.rs +++ b/library/alloc/src/collections/btree/node/tests.rs @@ -1,4 +1,110 @@ +use super::super::navigate; use super::*; +use crate::fmt::Debug; +use crate::string::String; +use core::cmp::Ordering::*; + +impl<'a, K: 'a, V: 'a> NodeRef<marker::Immut<'a>, K, V, marker::LeafOrInternal> { + pub fn assert_back_pointers(self) { + match self.force() { + ForceResult::Leaf(_) => {} + ForceResult::Internal(node) => { + for idx in 0..=node.len() { + let edge = unsafe { Handle::new_edge(node, idx) }; + let child = edge.descend(); + assert!(child.ascend().ok() == Some(edge)); + child.assert_back_pointers(); + } + } + } + } + + pub fn assert_ascending(self) + where + K: Copy + Debug + Ord, + { + struct SeriesChecker<T> { + previous: Option<T>, + } + impl<T: Copy + Debug + Ord> SeriesChecker<T> { + fn is_ascending(&mut self, next: T) { + if let Some(previous) = self.previous { + assert!(previous < next, "{:?} >= {:?}", previous, next); + } + self.previous = Some(next); + } + } + + let mut checker = SeriesChecker { previous: None }; + self.visit_nodes_in_order(|pos| match pos { + navigate::Position::Leaf(node) => { + for idx in 0..node.len() { + let key = *unsafe { node.key_at(idx) }; + checker.is_ascending(key); + } + } + navigate::Position::InternalKV(kv) => { + let key = *kv.into_kv().0; + checker.is_ascending(key); + } + navigate::Position::Internal(_) => {} + }); + } + + pub fn assert_and_add_lengths(self) -> usize { + let mut internal_length = 0; + let mut internal_kv_count = 0; + let mut leaf_length = 0; + self.visit_nodes_in_order(|pos| match pos { + navigate::Position::Leaf(node) => { + let is_root = self.height() == 0; + let min_len = if is_root { 0 } else { MIN_LEN }; + assert!(node.len() >= min_len, "{} < {}", node.len(), min_len); + leaf_length += node.len(); + } + navigate::Position::Internal(node) => { + let is_root = self.height() == node.height(); + let min_len = if is_root { 1 } else { MIN_LEN }; + assert!(node.len() >= min_len, "{} < {}", node.len(), min_len); + internal_length += node.len(); + } + navigate::Position::InternalKV(_) => { + internal_kv_count += 1; + } + }); + assert_eq!(internal_length, internal_kv_count); + let total = internal_length + leaf_length; + assert_eq!(self.calc_length(), total); + total + } + + pub fn dump_keys(self) -> String + where + K: Debug, + { + let mut result = String::new(); + self.visit_nodes_in_order(|pos| match pos { + navigate::Position::Leaf(leaf) => { + let depth = self.height(); + let indent = " ".repeat(depth); + result += &format!("\n{}", indent); + for idx in 0..leaf.len() { + if idx > 0 { + result += ", "; + } + result += &format!("{:?}", unsafe { leaf.key_at(idx) }); + } + } + navigate::Position::Internal(_) => {} + navigate::Position::InternalKV(kv) => { + let depth = self.height() - kv.into_node().height(); + let indent = " ".repeat(depth); + result += &format!("\n{}{:?}", indent, kv.into_kv().0); + } + }); + result + } +} #[test] fn test_splitpoint() { @@ -25,6 +131,38 @@ fn test_splitpoint() { } #[test] +fn test_partial_cmp_eq() { + let mut root1: Root<i32, ()> = Root::new_leaf(); + let mut leaf1 = unsafe { root1.leaf_node_as_mut() }; + leaf1.push(1, ()); + root1.push_internal_level(); + let root2: Root<i32, ()> = Root::new_leaf(); + + let leaf_edge_1a = root1.node_as_ref().first_leaf_edge().forget_node_type(); + let leaf_edge_1b = root1.node_as_ref().last_leaf_edge().forget_node_type(); + let top_edge_1 = root1.node_as_ref().first_edge(); + let top_edge_2 = root2.node_as_ref().first_edge(); + + assert!(leaf_edge_1a == leaf_edge_1a); + assert!(leaf_edge_1a != leaf_edge_1b); + assert!(leaf_edge_1a != top_edge_1); + assert!(leaf_edge_1a != top_edge_2); + assert!(top_edge_1 == top_edge_1); + assert!(top_edge_1 != top_edge_2); + + assert_eq!(leaf_edge_1a.partial_cmp(&leaf_edge_1a), Some(Equal)); + assert_eq!(leaf_edge_1a.partial_cmp(&leaf_edge_1b), Some(Less)); + assert_eq!(leaf_edge_1a.partial_cmp(&top_edge_1), None); + assert_eq!(leaf_edge_1a.partial_cmp(&top_edge_2), None); + assert_eq!(top_edge_1.partial_cmp(&top_edge_1), Some(Equal)); + assert_eq!(top_edge_1.partial_cmp(&top_edge_2), None); + + root1.pop_internal_level(); + unsafe { root1.into_ref().deallocate_and_ascend() }; + unsafe { root2.into_ref().deallocate_and_ascend() }; +} + +#[test] #[cfg(target_arch = "x86_64")] fn test_sizes() { assert_eq!(core::mem::size_of::<LeafNode<(), ()>>(), 16); diff --git a/library/alloc/src/collections/vec_deque.rs b/library/alloc/src/collections/vec_deque.rs index ff9b1553bf2..22b02a4f849 100644 --- a/library/alloc/src/collections/vec_deque.rs +++ b/library/alloc/src/collections/vec_deque.rs @@ -1102,7 +1102,7 @@ impl<T> VecDeque<T> { where R: RangeBounds<usize>, { - let Range { start, end } = slice::check_range(self.len(), range); + let Range { start, end } = range.assert_len(self.len()); let tail = self.wrap_add(self.tail, start); let head = self.wrap_add(self.tail, end); (tail, head) @@ -2181,7 +2181,7 @@ impl<T> VecDeque<T> { /// /// This method does not allocate and does not change the order of the /// inserted elements. As it returns a mutable slice, this can be used to - /// sort or binary search a deque. + /// sort a deque. /// /// Once the internal storage is contiguous, the [`as_slices`] and /// [`as_mut_slices`] methods will return the entire contents of the @@ -2430,6 +2430,143 @@ impl<T> VecDeque<T> { self.wrap_copy(self.tail, self.head, k); } } + + /// Binary searches this sorted `VecDeque` for a given element. + /// + /// If the value is found then [`Result::Ok`] is returned, containing the + /// index of the matching element. If there are multiple matches, then any + /// one of the matches could be returned. If the value is not found then + /// [`Result::Err`] is returned, containing the index where a matching + /// element could be inserted while maintaining sorted order. + /// + /// # Examples + /// + /// Looks up a series of four elements. The first is found, with a + /// uniquely determined position; the second and third are not + /// found; the fourth could match any position in `[1, 4]`. + /// + /// ``` + /// #![feature(vecdeque_binary_search)] + /// use std::collections::VecDeque; + /// + /// let deque: VecDeque<_> = vec![0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55].into(); + /// + /// assert_eq!(deque.binary_search(&13), Ok(9)); + /// assert_eq!(deque.binary_search(&4), Err(7)); + /// assert_eq!(deque.binary_search(&100), Err(13)); + /// let r = deque.binary_search(&1); + /// assert!(matches!(r, Ok(1..=4))); + /// ``` + /// + /// If you want to insert an item to a sorted `VecDeque`, while maintaining + /// sort order: + /// + /// ``` + /// #![feature(vecdeque_binary_search)] + /// use std::collections::VecDeque; + /// + /// let mut deque: VecDeque<_> = vec![0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55].into(); + /// let num = 42; + /// let idx = deque.binary_search(&num).unwrap_or_else(|x| x); + /// deque.insert(idx, num); + /// assert_eq!(deque, &[0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 42, 55]); + /// ``` + #[unstable(feature = "vecdeque_binary_search", issue = "78021")] + #[inline] + pub fn binary_search(&self, x: &T) -> Result<usize, usize> + where + T: Ord, + { + self.binary_search_by(|e| e.cmp(x)) + } + + /// Binary searches this sorted `VecDeque` with a comparator function. + /// + /// The comparator function should implement an order consistent + /// with the sort order of the underlying `VecDeque`, returning an + /// order code that indicates whether its argument is `Less`, + /// `Equal` or `Greater` than the desired target. + /// + /// If the value is found then [`Result::Ok`] is returned, containing the + /// index of the matching element. If there are multiple matches, then any + /// one of the matches could be returned. If the value is not found then + /// [`Result::Err`] is returned, containing the index where a matching + /// element could be inserted while maintaining sorted order. + /// + /// # Examples + /// + /// Looks up a series of four elements. The first is found, with a + /// uniquely determined position; the second and third are not + /// found; the fourth could match any position in `[1, 4]`. + /// + /// ``` + /// #![feature(vecdeque_binary_search)] + /// use std::collections::VecDeque; + /// + /// let deque: VecDeque<_> = vec![0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55].into(); + /// + /// assert_eq!(deque.binary_search_by(|x| x.cmp(&13)), Ok(9)); + /// assert_eq!(deque.binary_search_by(|x| x.cmp(&4)), Err(7)); + /// assert_eq!(deque.binary_search_by(|x| x.cmp(&100)), Err(13)); + /// let r = deque.binary_search_by(|x| x.cmp(&1)); + /// assert!(matches!(r, Ok(1..=4))); + /// ``` + #[unstable(feature = "vecdeque_binary_search", issue = "78021")] + pub fn binary_search_by<'a, F>(&'a self, mut f: F) -> Result<usize, usize> + where + F: FnMut(&'a T) -> Ordering, + { + let (front, back) = self.as_slices(); + + if let Some(Ordering::Less | Ordering::Equal) = back.first().map(|elem| f(elem)) { + back.binary_search_by(f).map(|idx| idx + front.len()).map_err(|idx| idx + front.len()) + } else { + front.binary_search_by(f) + } + } + + /// Binary searches this sorted `VecDeque` with a key extraction function. + /// + /// Assumes that the `VecDeque` is sorted by the key, for instance with + /// [`make_contiguous().sort_by_key()`](#method.make_contiguous) using the same + /// key extraction function. + /// + /// If the value is found then [`Result::Ok`] is returned, containing the + /// index of the matching element. If there are multiple matches, then any + /// one of the matches could be returned. If the value is not found then + /// [`Result::Err`] is returned, containing the index where a matching + /// element could be inserted while maintaining sorted order. + /// + /// # Examples + /// + /// Looks up a series of four elements in a slice of pairs sorted by + /// their second elements. The first is found, with a uniquely + /// determined position; the second and third are not found; the + /// fourth could match any position in `[1, 4]`. + /// + /// ``` + /// #![feature(vecdeque_binary_search)] + /// use std::collections::VecDeque; + /// + /// let deque: VecDeque<_> = vec![(0, 0), (2, 1), (4, 1), (5, 1), + /// (3, 1), (1, 2), (2, 3), (4, 5), (5, 8), (3, 13), + /// (1, 21), (2, 34), (4, 55)].into(); + /// + /// assert_eq!(deque.binary_search_by_key(&13, |&(a,b)| b), Ok(9)); + /// assert_eq!(deque.binary_search_by_key(&4, |&(a,b)| b), Err(7)); + /// assert_eq!(deque.binary_search_by_key(&100, |&(a,b)| b), Err(13)); + /// let r = deque.binary_search_by_key(&1, |&(a,b)| b); + /// assert!(matches!(r, Ok(1..=4))); + /// ``` + #[unstable(feature = "vecdeque_binary_search", issue = "78021")] + #[inline] + pub fn binary_search_by_key<'a, B, F>(&'a self, b: &B, mut f: F) -> Result<usize, usize> + where + F: FnMut(&'a T) -> B, + B: Ord, + { + self.binary_search_by(|k| f(k).cmp(b)) + } } impl<T: Clone> VecDeque<T> { diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 046c3867d84..b69e19072af 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -114,11 +114,11 @@ #![feature(or_patterns)] #![feature(pattern)] #![feature(ptr_internals)] +#![feature(range_bounds_assert_len)] #![feature(raw_ref_op)] #![feature(rustc_attrs)] #![feature(receiver_trait)] #![feature(min_specialization)] -#![feature(slice_check_range)] #![feature(slice_ptr_get)] #![feature(slice_ptr_len)] #![feature(staged_api)] diff --git a/library/alloc/src/slice.rs b/library/alloc/src/slice.rs index 79403cf8687..93501ef4085 100644 --- a/library/alloc/src/slice.rs +++ b/library/alloc/src/slice.rs @@ -91,8 +91,6 @@ use crate::borrow::ToOwned; use crate::boxed::Box; use crate::vec::Vec; -#[unstable(feature = "slice_check_range", issue = "76393")] -pub use core::slice::check_range; #[unstable(feature = "array_chunks", issue = "74985")] pub use core::slice::ArrayChunks; #[unstable(feature = "array_chunks", issue = "74985")] diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs index d3598ccfce8..1bec9e0ff26 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -49,7 +49,6 @@ use core::iter::{FromIterator, FusedIterator}; use core::ops::Bound::{Excluded, Included, Unbounded}; use core::ops::{self, Add, AddAssign, Index, IndexMut, Range, RangeBounds}; use core::ptr; -use core::slice; use core::str::{lossy, pattern::Pattern}; use crate::borrow::{Cow, ToOwned}; @@ -1507,14 +1506,14 @@ impl String { // of the vector version. The data is just plain bytes. // Because the range removal happens in Drop, if the Drain iterator is leaked, // the removal will not happen. - let Range { start, end } = slice::check_range(self.len(), range); + let Range { start, end } = range.assert_len(self.len()); assert!(self.is_char_boundary(start)); assert!(self.is_char_boundary(end)); // Take out two simultaneous borrows. The &mut String won't be accessed // until iteration is over, in Drop. let self_ptr = self as *mut _; - // SAFETY: `check_range` and `is_char_boundary` do the appropriate bounds checks. + // SAFETY: `assert_len` and `is_char_boundary` do the appropriate bounds checks. let chars_iter = unsafe { self.get_unchecked(start..end) }.chars(); Drain { start, end, iter: chars_iter, string: self_ptr } @@ -2200,7 +2199,6 @@ impl<T: fmt::Display + ?Sized> ToString for T { let mut buf = String::new(); buf.write_fmt(format_args!("{}", self)) .expect("a Display implementation returned an error unexpectedly"); - buf.shrink_to_fit(); buf } } diff --git a/library/alloc/src/vec.rs b/library/alloc/src/vec.rs index 5e68f76693f..8526f15288f 100644 --- a/library/alloc/src/vec.rs +++ b/library/alloc/src/vec.rs @@ -1314,7 +1314,7 @@ impl<T> Vec<T> { // the hole, and the vector length is restored to the new length. // let len = self.len(); - let Range { start, end } = slice::check_range(len, range); + let Range { start, end } = range.assert_len(len); unsafe { // set self.vec length's to start, to be safe in case Drain is leaked @@ -1603,50 +1603,6 @@ impl<T: Clone> Vec<T> { } } -impl<T: Default> Vec<T> { - /// Resizes the `Vec` in-place so that `len` is equal to `new_len`. - /// - /// If `new_len` is greater than `len`, the `Vec` is extended by the - /// difference, with each additional slot filled with [`Default::default()`]. - /// If `new_len` is less than `len`, the `Vec` is simply truncated. - /// - /// This method uses [`Default`] to create new values on every push. If - /// you'd rather [`Clone`] a given value, use [`resize`]. - /// - /// # Examples - /// - /// ``` - /// # #![allow(deprecated)] - /// #![feature(vec_resize_default)] - /// - /// let mut vec = vec![1, 2, 3]; - /// vec.resize_default(5); - /// assert_eq!(vec, [1, 2, 3, 0, 0]); - /// - /// let mut vec = vec![1, 2, 3, 4]; - /// vec.resize_default(2); - /// assert_eq!(vec, [1, 2]); - /// ``` - /// - /// [`resize`]: Vec::resize - #[unstable(feature = "vec_resize_default", issue = "41758")] - #[rustc_deprecated( - reason = "This is moving towards being removed in favor \ - of `.resize_with(Default::default)`. If you disagree, please comment \ - in the tracking issue.", - since = "1.33.0" - )] - pub fn resize_default(&mut self, new_len: usize) { - let len = self.len(); - - if new_len > len { - self.extend_with(new_len - len, ExtendDefault); - } else { - self.truncate(new_len); - } - } -} - // This code generalizes `extend_with_{element,default}`. trait ExtendWith<T> { fn next(&mut self) -> T; diff --git a/library/alloc/tests/lib.rs b/library/alloc/tests/lib.rs index cff8ff9ac7a..b7cc03f8eb9 100644 --- a/library/alloc/tests/lib.rs +++ b/library/alloc/tests/lib.rs @@ -20,6 +20,7 @@ #![feature(inplace_iteration)] #![feature(iter_map_while)] #![feature(int_bits_const)] +#![feature(vecdeque_binary_search)] use std::collections::hash_map::DefaultHasher; use std::hash::{Hash, Hasher}; diff --git a/library/alloc/tests/vec_deque.rs b/library/alloc/tests/vec_deque.rs index 46d8a3c4cb4..05cb3a2c03d 100644 --- a/library/alloc/tests/vec_deque.rs +++ b/library/alloc/tests/vec_deque.rs @@ -1659,3 +1659,42 @@ fn test_drain_leak() { drop(v); assert_eq!(unsafe { DROPS }, 7); } + +#[test] +fn test_binary_search() { + // Contiguous (front only) search: + let deque: VecDeque<_> = vec![1, 2, 3, 5, 6].into(); + assert!(deque.as_slices().1.is_empty()); + assert_eq!(deque.binary_search(&3), Ok(2)); + assert_eq!(deque.binary_search(&4), Err(3)); + + // Split search (both front & back non-empty): + let mut deque: VecDeque<_> = vec![5, 6].into(); + deque.push_front(3); + deque.push_front(2); + deque.push_front(1); + deque.push_back(10); + assert!(!deque.as_slices().0.is_empty()); + assert!(!deque.as_slices().1.is_empty()); + assert_eq!(deque.binary_search(&0), Err(0)); + assert_eq!(deque.binary_search(&1), Ok(0)); + assert_eq!(deque.binary_search(&5), Ok(3)); + assert_eq!(deque.binary_search(&7), Err(5)); + assert_eq!(deque.binary_search(&20), Err(6)); +} + +#[test] +fn test_binary_search_by() { + let deque: VecDeque<_> = vec![(1,), (2,), (3,), (5,), (6,)].into(); + + assert_eq!(deque.binary_search_by(|&(v,)| v.cmp(&3)), Ok(2)); + assert_eq!(deque.binary_search_by(|&(v,)| v.cmp(&4)), Err(3)); +} + +#[test] +fn test_binary_search_by_key() { + let deque: VecDeque<_> = vec![(1,), (2,), (3,), (5,), (6,)].into(); + + assert_eq!(deque.binary_search_by_key(&3, |&(v,)| v), Ok(2)); + assert_eq!(deque.binary_search_by_key(&4, |&(v,)| v), Err(3)); +} diff --git a/library/backtrace b/library/backtrace -Subproject 893fbb23688e98376e54c26b59432a2966a8cc9 +Subproject a6dd47bd588c882e735675a1379d2b61719fa38 diff --git a/library/core/benches/ascii.rs b/library/core/benches/ascii.rs index 05dd7adff1f..bc59c378609 100644 --- a/library/core/benches/ascii.rs +++ b/library/core/benches/ascii.rs @@ -253,9 +253,9 @@ macro_rules! repeat { }; } -const SHORT: &'static str = "Alice's"; -const MEDIUM: &'static str = "Alice's Adventures in Wonderland"; -const LONG: &'static str = repeat!( +const SHORT: &str = "Alice's"; +const MEDIUM: &str = "Alice's Adventures in Wonderland"; +const LONG: &str = repeat!( r#" La Guida di Bragia, a Ballad Opera for the Marionette Theatre (around 1850) Alice's Adventures in Wonderland (1865) diff --git a/library/core/src/alloc/mod.rs b/library/core/src/alloc/mod.rs index 6d09b4f0263..c61c19cc7d1 100644 --- a/library/core/src/alloc/mod.rs +++ b/library/core/src/alloc/mod.rs @@ -89,13 +89,11 @@ impl fmt::Display for AllocError { pub unsafe trait AllocRef { /// Attempts to allocate a block of memory. /// - /// On success, returns a [`NonNull<[u8]>`] meeting the size and alignment guarantees of `layout`. + /// On success, returns a [`NonNull<[u8]>`][NonNull] meeting the size and alignment guarantees of `layout`. /// /// The returned block may have a larger size than specified by `layout.size()`, and may or may /// not have its contents initialized. /// - /// [`NonNull<[u8]>`]: NonNull - /// /// # Errors /// /// Returning `Err` indicates that either memory is exhausted or `layout` does not meet @@ -146,7 +144,7 @@ pub unsafe trait AllocRef { /// Attempts to extend the memory block. /// - /// Returns a new [`NonNull<[u8]>`] containing a pointer and the actual size of the allocated + /// Returns a new [`NonNull<[u8]>`][NonNull] containing a pointer and the actual size of the allocated /// memory. The pointer is suitable for holding data described by `new_layout`. To accomplish /// this, the allocator may extend the allocation referenced by `ptr` to fit the new layout. /// @@ -158,8 +156,6 @@ pub unsafe trait AllocRef { /// If this method returns `Err`, then ownership of the memory block has not been transferred to /// this allocator, and the contents of the memory block are unaltered. /// - /// [`NonNull<[u8]>`]: NonNull - /// /// # Safety /// /// * `ptr` must denote a block of memory [*currently allocated*] via this allocator. @@ -271,7 +267,7 @@ pub unsafe trait AllocRef { /// Attempts to shrink the memory block. /// - /// Returns a new [`NonNull<[u8]>`] containing a pointer and the actual size of the allocated + /// Returns a new [`NonNull<[u8]>`][NonNull] containing a pointer and the actual size of the allocated /// memory. The pointer is suitable for holding data described by `new_layout`. To accomplish /// this, the allocator may shrink the allocation referenced by `ptr` to fit the new layout. /// @@ -283,8 +279,6 @@ pub unsafe trait AllocRef { /// If this method returns `Err`, then ownership of the memory block has not been transferred to /// this allocator, and the contents of the memory block are unaltered. /// - /// [`NonNull<[u8]>`]: NonNull - /// /// # Safety /// /// * `ptr` must denote a block of memory [*currently allocated*] via this allocator. diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs index 15ec13ca65a..7140218fa91 100644 --- a/library/core/src/cell.rs +++ b/library/core/src/cell.rs @@ -226,7 +226,7 @@ use crate::ptr; /// assert_eq!(my_struct.special_field.get(), new_value); /// ``` /// -/// See the [module-level documentation](index.html) for more. +/// See the [module-level documentation](self) for more. #[stable(feature = "rust1", since = "1.0.0")] #[repr(transparent)] pub struct Cell<T: ?Sized> { @@ -566,7 +566,7 @@ impl<T> Cell<[T]> { /// A mutable memory location with dynamically checked borrow rules /// -/// See the [module-level documentation](index.html) for more. +/// See the [module-level documentation](self) for more. #[stable(feature = "rust1", since = "1.0.0")] pub struct RefCell<T: ?Sized> { borrow: Cell<BorrowFlag>, @@ -1203,7 +1203,7 @@ impl Clone for BorrowRef<'_> { /// Wraps a borrowed reference to a value in a `RefCell` box. /// A wrapper type for an immutably borrowed value from a `RefCell<T>`. /// -/// See the [module-level documentation](index.html) for more. +/// See the [module-level documentation](self) for more. #[stable(feature = "rust1", since = "1.0.0")] pub struct Ref<'b, T: ?Sized + 'b> { value: &'b T, @@ -1493,7 +1493,7 @@ impl<'b> BorrowRefMut<'b> { /// A wrapper type for a mutably borrowed value from a `RefCell<T>`. /// -/// See the [module-level documentation](index.html) for more. +/// See the [module-level documentation](self) for more. #[stable(feature = "rust1", since = "1.0.0")] pub struct RefMut<'b, T: ?Sized + 'b> { value: &'b mut T, diff --git a/library/core/src/convert/mod.rs b/library/core/src/convert/mod.rs index 2bfeb49b5fa..3f7110b34cc 100644 --- a/library/core/src/convert/mod.rs +++ b/library/core/src/convert/mod.rs @@ -134,6 +134,7 @@ pub const fn identity<T>(x: T) -> T { /// want to accept all references that can be converted to [`&str`] as an argument. /// Since both [`String`] and [`&str`] implement `AsRef<str>` we can accept both as input argument. /// +/// [`&str`]: primitive@str /// [`Option<T>`]: Option /// [`Result<T, E>`]: Result /// [`Borrow`]: crate::borrow::Borrow diff --git a/library/core/src/ffi.rs b/library/core/src/ffi.rs index 4525ba78ba0..e146a97ae94 100644 --- a/library/core/src/ffi.rs +++ b/library/core/src/ffi.rs @@ -280,7 +280,7 @@ impl<'a, 'f: 'a> DerefMut for VaList<'a, 'f> { // within a private module. Once RFC 2145 has been implemented look into // improving this. mod sealed_trait { - /// Trait which permits the allowed types to be used with [VaList::arg]. + /// Trait which permits the allowed types to be used with [super::VaListImpl::arg]. #[unstable( feature = "c_variadic", reason = "the `c_variadic` feature has not been properly tested on \ diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index b2798ea6625..2a7c105e807 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -1082,7 +1082,7 @@ extern "rust-intrinsic" { /// If the actual type neither requires drop glue nor implements /// `Copy`, then the return value of this function is unspecified. /// - /// The stabilized version of this intrinsic is [`needs_drop`]. + /// The stabilized version of this intrinsic is [`mem::needs_drop`](crate::mem::needs_drop). #[rustc_const_stable(feature = "const_needs_drop", since = "1.40.0")] pub fn needs_drop<T>() -> bool; diff --git a/library/core/src/iter/adapters/chain.rs b/library/core/src/iter/adapters/chain.rs index 38fb74372db..2e070d71224 100644 --- a/library/core/src/iter/adapters/chain.rs +++ b/library/core/src/iter/adapters/chain.rs @@ -109,7 +109,7 @@ where acc = b.try_fold(acc, f)?; // we don't fuse the second iterator } - Try::from_ok(acc) + try { acc } } fn fold<Acc, F>(self, mut acc: Acc, mut f: F) -> Acc @@ -292,7 +292,7 @@ where acc = a.try_rfold(acc, f)?; // we don't fuse the second iterator } - Try::from_ok(acc) + try { acc } } fn rfold<Acc, F>(self, mut acc: Acc, mut f: F) -> Acc diff --git a/library/core/src/iter/adapters/flatten.rs b/library/core/src/iter/adapters/flatten.rs index ddb1aaebc1f..35adb4f69d8 100644 --- a/library/core/src/iter/adapters/flatten.rs +++ b/library/core/src/iter/adapters/flatten.rs @@ -317,7 +317,7 @@ where } self.backiter = None; - Try::from_ok(init) + try { init } } #[inline] @@ -397,7 +397,7 @@ where } self.frontiter = None; - Try::from_ok(init) + try { init } } #[inline] diff --git a/library/core/src/iter/adapters/fuse.rs b/library/core/src/iter/adapters/fuse.rs index a78da369c24..60ac3524e66 100644 --- a/library/core/src/iter/adapters/fuse.rs +++ b/library/core/src/iter/adapters/fuse.rs @@ -303,7 +303,7 @@ where acc = iter.try_fold(acc, fold)?; self.iter = None; } - Try::from_ok(acc) + try { acc } } #[inline] @@ -353,7 +353,7 @@ where acc = iter.try_rfold(acc, fold)?; self.iter = None; } - Try::from_ok(acc) + try { acc } } #[inline] diff --git a/library/core/src/iter/adapters/mod.rs b/library/core/src/iter/adapters/mod.rs index 1e520b62f77..bf30dcb7689 100644 --- a/library/core/src/iter/adapters/mod.rs +++ b/library/core/src/iter/adapters/mod.rs @@ -579,7 +579,7 @@ where })?; if is_empty { - return Try::from_ok(acc); + return try { acc }; } loop { @@ -715,7 +715,7 @@ where if self.first_take { self.first_take = false; match self.iter.next() { - None => return Try::from_ok(acc), + None => return try { acc }, Some(x) => acc = f(acc, x)?, } } @@ -792,7 +792,7 @@ where } match self.next_back() { - None => Try::from_ok(init), + None => try { init }, Some(x) => { let acc = f(init, x)?; from_fn(nth_back(&mut self.iter, self.step)).try_fold(acc, f) @@ -1075,7 +1075,7 @@ fn filter_try_fold<'a, T, Acc, R: Try<Ok = Acc>>( predicate: &'a mut impl FnMut(&T) -> bool, mut fold: impl FnMut(Acc, T) -> R + 'a, ) -> impl FnMut(Acc, T) -> R + 'a { - move |acc, item| if predicate(&item) { fold(acc, item) } else { R::from_ok(acc) } + move |acc, item| if predicate(&item) { fold(acc, item) } else { try { acc } } } #[stable(feature = "rust1", since = "1.0.0")] @@ -1229,7 +1229,7 @@ fn filter_map_try_fold<'a, T, B, Acc, R: Try<Ok = Acc>>( ) -> impl FnMut(Acc, T) -> R + 'a { move |acc, item| match f(item) { Some(x) => fold(acc, x), - None => R::from_ok(acc), + None => try { acc }, } } @@ -1660,7 +1660,7 @@ impl<I: Iterator> Iterator for Peekable<I> { R: Try<Ok = B>, { let acc = match self.peeked.take() { - Some(None) => return Try::from_ok(init), + Some(None) => return try { init }, Some(Some(v)) => f(init, v)?, None => init, }; @@ -1703,7 +1703,7 @@ where R: Try<Ok = B>, { match self.peeked.take() { - Some(None) => Try::from_ok(init), + Some(None) => try { init }, Some(Some(v)) => match self.iter.try_rfold(init, &mut f).into_result() { Ok(acc) => f(acc, v), Err(e) => { @@ -1938,7 +1938,7 @@ where if !self.flag { match self.next() { Some(v) => init = fold(init, v)?, - None => return Try::from_ok(init), + None => return try { init }, } } self.iter.try_fold(init, fold) @@ -2065,13 +2065,13 @@ where ControlFlow::from_try(fold(acc, x)) } else { *flag = true; - ControlFlow::Break(Try::from_ok(acc)) + ControlFlow::Break(try { acc }) } } } if self.flag { - Try::from_ok(init) + try { init } } else { let flag = &mut self.flag; let p = &mut self.predicate; @@ -2180,7 +2180,7 @@ where let Self { iter, predicate } = self; iter.try_fold(init, |acc, x| match predicate(x) { Some(item) => ControlFlow::from_try(fold(acc, item)), - None => ControlFlow::Break(Try::from_ok(acc)), + None => ControlFlow::Break(try { acc }), }) .into_try() } @@ -2316,7 +2316,7 @@ where if n > 0 { // nth(n) skips n+1 if self.iter.nth(n - 1).is_none() { - return Try::from_ok(init); + return try { init }; } } self.iter.try_fold(init, fold) @@ -2381,11 +2381,7 @@ where } let n = self.len(); - if n == 0 { - Try::from_ok(init) - } else { - self.iter.try_rfold(init, check(n, fold)).into_try() - } + if n == 0 { try { init } } else { self.iter.try_rfold(init, check(n, fold)).into_try() } } fn rfold<Acc, Fold>(mut self, init: Acc, fold: Fold) -> Acc @@ -2509,7 +2505,7 @@ where } if self.n == 0 { - Try::from_ok(init) + try { init } } else { let n = &mut self.n; self.iter.try_fold(init, check(n, fold)).into_try() @@ -2587,11 +2583,11 @@ where R: Try<Ok = Acc>, { if self.n == 0 { - Try::from_ok(init) + try { init } } else { let len = self.iter.len(); if len > self.n && self.iter.nth_back(len - self.n - 1).is_none() { - Try::from_ok(init) + try { init } } else { self.iter.try_rfold(init, fold) } @@ -2687,7 +2683,7 @@ where mut fold: impl FnMut(Acc, B) -> R + 'a, ) -> impl FnMut(Acc, T) -> ControlFlow<Acc, R> + 'a { move |acc, x| match f(state, x) { - None => ControlFlow::Break(Try::from_ok(acc)), + None => ControlFlow::Break(try { acc }), Some(x) => ControlFlow::from_try(fold(acc, x)), } } @@ -2951,7 +2947,7 @@ where Ok(x) => ControlFlow::from_try(f(acc, x)), Err(e) => { *error = Err(e); - ControlFlow::Break(Try::from_ok(acc)) + ControlFlow::Break(try { acc }) } }) .into_try() diff --git a/library/core/src/iter/range.rs b/library/core/src/iter/range.rs index 9f34aee1947..cd8ab11cb84 100644 --- a/library/core/src/iter/range.rs +++ b/library/core/src/iter/range.rs @@ -713,7 +713,7 @@ impl<A: Step> Iterator for ops::RangeInclusive<A> { R: Try<Ok = B>, { if self.is_empty() { - return Try::from_ok(init); + return try { init }; } let mut accum = init; @@ -731,7 +731,7 @@ impl<A: Step> Iterator for ops::RangeInclusive<A> { accum = f(accum, self.start.clone())?; } - Try::from_ok(accum) + try { accum } } #[inline] @@ -818,7 +818,7 @@ impl<A: Step> DoubleEndedIterator for ops::RangeInclusive<A> { R: Try<Ok = B>, { if self.is_empty() { - return Try::from_ok(init); + return try { init }; } let mut accum = init; @@ -836,7 +836,7 @@ impl<A: Step> DoubleEndedIterator for ops::RangeInclusive<A> { accum = f(accum, self.start.clone())?; } - Try::from_ok(accum) + try { accum } } #[inline] diff --git a/library/core/src/iter/sources.rs b/library/core/src/iter/sources.rs index 97562cf73b8..44da8f4715c 100644 --- a/library/core/src/iter/sources.rs +++ b/library/core/src/iter/sources.rs @@ -501,9 +501,9 @@ pub fn once_with<A, F: FnOnce() -> A>(gen: F) -> OnceWith<F> { /// /// # Examples /// -/// Let’s re-implement the counter iterator from [module-level documentation]: +/// Let’s re-implement the counter iterator from the [module-level documentation]: /// -/// [module-level documentation]: index.html +/// [module-level documentation]: super /// /// ``` /// let mut count = 0; diff --git a/library/core/src/iter/traits/collect.rs b/library/core/src/iter/traits/collect.rs index 41a503c4abb..1ae6d15c12d 100644 --- a/library/core/src/iter/traits/collect.rs +++ b/library/core/src/iter/traits/collect.rs @@ -94,7 +94,7 @@ pub trait FromIterator<A>: Sized { /// /// See the [module-level documentation] for more. /// - /// [module-level documentation]: index.html + /// [module-level documentation]: crate::iter /// /// # Examples /// @@ -120,7 +120,7 @@ pub trait FromIterator<A>: Sized { /// collection of some kind. /// /// One benefit of implementing `IntoIterator` is that your type will [work -/// with Rust's `for` loop syntax](index.html#for-loops-and-intoiterator). +/// with Rust's `for` loop syntax](crate::iter#for-loops-and-intoiterator). /// /// See also: [`FromIterator`]. /// @@ -212,7 +212,7 @@ pub trait IntoIterator { /// /// See the [module-level documentation] for more. /// - /// [module-level documentation]: index.html + /// [module-level documentation]: crate::iter /// /// # Examples /// diff --git a/library/core/src/iter/traits/double_ended.rs b/library/core/src/iter/traits/double_ended.rs index 16bee0e2eee..87fe3c21040 100644 --- a/library/core/src/iter/traits/double_ended.rs +++ b/library/core/src/iter/traits/double_ended.rs @@ -122,6 +122,9 @@ pub trait DoubleEndedIterator: Iterator { /// assert_eq!(iter.advance_back_by(0), Ok(())); /// assert_eq!(iter.advance_back_by(100), Err(1)); // only `&3` was skipped /// ``` + /// + /// [`Ok(())`]: Ok + /// [`Err(k)`]: Err #[inline] #[unstable(feature = "iter_advance_by", reason = "recently added", issue = "77404")] fn advance_back_by(&mut self, n: usize) -> Result<(), usize> { @@ -221,7 +224,7 @@ pub trait DoubleEndedIterator: Iterator { while let Some(x) = self.next_back() { accum = f(accum, x)?; } - Try::from_ok(accum) + try { accum } } /// An iterator method that reduces the iterator's elements to a single, diff --git a/library/core/src/iter/traits/exact_size.rs b/library/core/src/iter/traits/exact_size.rs index 33ace60a274..eadbdf45c7c 100644 --- a/library/core/src/iter/traits/exact_size.rs +++ b/library/core/src/iter/traits/exact_size.rs @@ -26,10 +26,10 @@ /// assert_eq!(5, five.len()); /// ``` /// -/// In the [module level docs][moddocs], we implemented an [`Iterator`], -/// `Counter`. Let's implement `ExactSizeIterator` for it as well: +/// In the [module-level docs], we implemented an [`Iterator`], `Counter`. +/// Let's implement `ExactSizeIterator` for it as well: /// -/// [moddocs]: index.html +/// [module-level docs]: crate::iter /// /// ``` /// # struct Counter { diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index 813afcc0ec6..18b4adc23e8 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -289,12 +289,12 @@ pub trait Iterator { /// This method will eagerly skip `n` elements by calling [`next`] up to `n` /// times until [`None`] is encountered. /// - /// `advance_by(n)` will return [`Ok(())`] if the iterator successfully advances by - /// `n` elements, or [`Err(k)`] if [`None`] is encountered, where `k` is the number + /// `advance_by(n)` will return [`Ok(())`][Ok] if the iterator successfully advances by + /// `n` elements, or [`Err(k)`][Err] if [`None`] is encountered, where `k` is the number /// of elements the iterator is advanced by before running out of elements (i.e. the /// length of the iterator). Note that `k` is always less than `n`. /// - /// Calling `advance_by(0)` does not consume any elements and always returns [`Ok(())`]. + /// Calling `advance_by(0)` does not consume any elements and always returns [`Ok(())`][Ok]. /// /// [`next`]: Iterator::next /// @@ -1887,7 +1887,7 @@ pub trait Iterator { while let Some(x) = self.next() { accum = f(accum, x)?; } - Try::from_ok(accum) + try { accum } } /// An iterator method that applies a fallible function to each item in the diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index c9a80b5bc77..af4b7199397 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -126,10 +126,13 @@ #![feature(staged_api)] #![feature(std_internals)] #![feature(stmt_expr_attributes)] +#![feature(str_split_as_str)] +#![feature(str_split_inclusive_as_str)] #![feature(transparent_unions)] +#![feature(try_blocks)] #![feature(unboxed_closures)] #![feature(unsized_locals)] -#![feature(untagged_unions)] +#![cfg_attr(bootstrap, feature(untagged_unions))] #![feature(unwind_attributes)] #![feature(variant_count)] #![feature(tbm_target_feature)] diff --git a/library/core/src/ops/range.rs b/library/core/src/ops/range.rs index 2eaf7601e54..4423cfc27dd 100644 --- a/library/core/src/ops/range.rs +++ b/library/core/src/ops/range.rs @@ -1,5 +1,9 @@ use crate::fmt; use crate::hash::Hash; +use crate::slice::index::{ + slice_end_index_len_fail, slice_end_index_overflow_fail, slice_index_order_fail, + slice_start_index_overflow_fail, +}; /// An unbounded range (`..`). /// @@ -19,7 +23,7 @@ use crate::hash::Hash; /// /// ```compile_fail,E0277 /// for i in .. { -/// // ... +/// // ... /// } /// ``` /// @@ -27,12 +31,12 @@ use crate::hash::Hash; /// /// ``` /// let arr = [0, 1, 2, 3, 4]; -/// assert_eq!(arr[ .. ], [0,1,2,3,4]); // RangeFull -/// assert_eq!(arr[ .. 3], [0,1,2 ]); -/// assert_eq!(arr[ ..=3], [0,1,2,3 ]); -/// assert_eq!(arr[1.. ], [ 1,2,3,4]); -/// assert_eq!(arr[1.. 3], [ 1,2 ]); -/// assert_eq!(arr[1..=3], [ 1,2,3 ]); +/// assert_eq!(arr[ .. ], [0, 1, 2, 3, 4]); // This is the `RangeFull` +/// assert_eq!(arr[ .. 3], [0, 1, 2 ]); +/// assert_eq!(arr[ ..=3], [0, 1, 2, 3 ]); +/// assert_eq!(arr[1.. ], [ 1, 2, 3, 4]); +/// assert_eq!(arr[1.. 3], [ 1, 2 ]); +/// assert_eq!(arr[1..=3], [ 1, 2, 3 ]); /// ``` /// /// [slicing index]: crate::slice::SliceIndex @@ -52,22 +56,26 @@ impl fmt::Debug for RangeFull { /// A (half-open) range bounded inclusively below and exclusively above /// (`start..end`). /// -/// The `Range` `start..end` contains all values with `x >= start` and -/// `x < end`. It is empty unless `start < end`. +/// The range `start..end` contains all values with `start <= x < end`. +/// It is empty if `start >= end`. /// /// # Examples /// +/// The `start..end` syntax is a `Range`: +/// /// ``` /// assert_eq!((3..5), std::ops::Range { start: 3, end: 5 }); /// assert_eq!(3 + 4 + 5, (3..6).sum()); +/// ``` /// +/// ``` /// let arr = [0, 1, 2, 3, 4]; -/// assert_eq!(arr[ .. ], [0,1,2,3,4]); -/// assert_eq!(arr[ .. 3], [0,1,2 ]); -/// assert_eq!(arr[ ..=3], [0,1,2,3 ]); -/// assert_eq!(arr[1.. ], [ 1,2,3,4]); -/// assert_eq!(arr[1.. 3], [ 1,2 ]); // Range -/// assert_eq!(arr[1..=3], [ 1,2,3 ]); +/// assert_eq!(arr[ .. ], [0, 1, 2, 3, 4]); +/// assert_eq!(arr[ .. 3], [0, 1, 2 ]); +/// assert_eq!(arr[ ..=3], [0, 1, 2, 3 ]); +/// assert_eq!(arr[1.. ], [ 1, 2, 3, 4]); +/// assert_eq!(arr[1.. 3], [ 1, 2 ]); // This is a `Range` +/// assert_eq!(arr[1..=3], [ 1, 2, 3 ]); /// ``` #[lang = "Range"] #[doc(alias = "..")] @@ -160,17 +168,21 @@ impl<Idx: PartialOrd<Idx>> Range<Idx> { /// /// # Examples /// +/// The `start..` syntax is a `RangeFrom`: +/// /// ``` /// assert_eq!((2..), std::ops::RangeFrom { start: 2 }); /// assert_eq!(2 + 3 + 4, (2..).take(3).sum()); +/// ``` /// +/// ``` /// let arr = [0, 1, 2, 3, 4]; -/// assert_eq!(arr[ .. ], [0,1,2,3,4]); -/// assert_eq!(arr[ .. 3], [0,1,2 ]); -/// assert_eq!(arr[ ..=3], [0,1,2,3 ]); -/// assert_eq!(arr[1.. ], [ 1,2,3,4]); // RangeFrom -/// assert_eq!(arr[1.. 3], [ 1,2 ]); -/// assert_eq!(arr[1..=3], [ 1,2,3 ]); +/// assert_eq!(arr[ .. ], [0, 1, 2, 3, 4]); +/// assert_eq!(arr[ .. 3], [0, 1, 2 ]); +/// assert_eq!(arr[ ..=3], [0, 1, 2, 3 ]); +/// assert_eq!(arr[1.. ], [ 1, 2, 3, 4]); // This is a `RangeFrom` +/// assert_eq!(arr[1.. 3], [ 1, 2 ]); +/// assert_eq!(arr[1..=3], [ 1, 2, 3 ]); /// ``` #[lang = "RangeFrom"] #[doc(alias = "..")] @@ -244,12 +256,12 @@ impl<Idx: PartialOrd<Idx>> RangeFrom<Idx> { /// /// ``` /// let arr = [0, 1, 2, 3, 4]; -/// assert_eq!(arr[ .. ], [0,1,2,3,4]); -/// assert_eq!(arr[ .. 3], [0,1,2 ]); // RangeTo -/// assert_eq!(arr[ ..=3], [0,1,2,3 ]); -/// assert_eq!(arr[1.. ], [ 1,2,3,4]); -/// assert_eq!(arr[1.. 3], [ 1,2 ]); -/// assert_eq!(arr[1..=3], [ 1,2,3 ]); +/// assert_eq!(arr[ .. ], [0, 1, 2, 3, 4]); +/// assert_eq!(arr[ .. 3], [0, 1, 2 ]); // This is a `RangeTo` +/// assert_eq!(arr[ ..=3], [0, 1, 2, 3 ]); +/// assert_eq!(arr[1.. ], [ 1, 2, 3, 4]); +/// assert_eq!(arr[1.. 3], [ 1, 2 ]); +/// assert_eq!(arr[1..=3], [ 1, 2, 3 ]); /// ``` /// /// [slicing index]: crate::slice::SliceIndex @@ -310,17 +322,21 @@ impl<Idx: PartialOrd<Idx>> RangeTo<Idx> { /// /// # Examples /// +/// The `start..=end` syntax is a `RangeInclusive`: +/// /// ``` /// assert_eq!((3..=5), std::ops::RangeInclusive::new(3, 5)); /// assert_eq!(3 + 4 + 5, (3..=5).sum()); +/// ``` /// +/// ``` /// let arr = [0, 1, 2, 3, 4]; -/// assert_eq!(arr[ .. ], [0,1,2,3,4]); -/// assert_eq!(arr[ .. 3], [0,1,2 ]); -/// assert_eq!(arr[ ..=3], [0,1,2,3 ]); -/// assert_eq!(arr[1.. ], [ 1,2,3,4]); -/// assert_eq!(arr[1.. 3], [ 1,2 ]); -/// assert_eq!(arr[1..=3], [ 1,2,3 ]); // RangeInclusive +/// assert_eq!(arr[ .. ], [0, 1, 2, 3, 4]); +/// assert_eq!(arr[ .. 3], [0, 1, 2 ]); +/// assert_eq!(arr[ ..=3], [0, 1, 2, 3 ]); +/// assert_eq!(arr[1.. ], [ 1, 2, 3, 4]); +/// assert_eq!(arr[1.. 3], [ 1, 2 ]); +/// assert_eq!(arr[1..=3], [ 1, 2, 3 ]); // This is a `RangeInclusive` /// ``` #[lang = "RangeInclusive"] #[doc(alias = "..=")] @@ -534,12 +550,12 @@ impl<Idx: PartialOrd<Idx>> RangeInclusive<Idx> { /// /// ``` /// let arr = [0, 1, 2, 3, 4]; -/// assert_eq!(arr[ .. ], [0,1,2,3,4]); -/// assert_eq!(arr[ .. 3], [0,1,2 ]); -/// assert_eq!(arr[ ..=3], [0,1,2,3 ]); // RangeToInclusive -/// assert_eq!(arr[1.. ], [ 1,2,3,4]); -/// assert_eq!(arr[1.. 3], [ 1,2 ]); -/// assert_eq!(arr[1..=3], [ 1,2,3 ]); +/// assert_eq!(arr[ .. ], [0, 1, 2, 3, 4]); +/// assert_eq!(arr[ .. 3], [0, 1, 2 ]); +/// assert_eq!(arr[ ..=3], [0, 1, 2, 3 ]); // This is a `RangeToInclusive` +/// assert_eq!(arr[1.. ], [ 1, 2, 3, 4]); +/// assert_eq!(arr[1.. 3], [ 1, 2 ]); +/// assert_eq!(arr[1..=3], [ 1, 2, 3 ]); /// ``` /// /// [slicing index]: crate::slice::SliceIndex @@ -661,9 +677,9 @@ impl<T: Clone> Bound<&T> { } } -#[stable(feature = "collections_range", since = "1.28.0")] /// `RangeBounds` is implemented by Rust's built-in range types, produced /// by range syntax like `..`, `a..`, `..b`, `..=c`, `d..e`, or `f..=g`. +#[stable(feature = "collections_range", since = "1.28.0")] pub trait RangeBounds<T: ?Sized> { /// Start index bound. /// @@ -701,6 +717,92 @@ pub trait RangeBounds<T: ?Sized> { #[stable(feature = "collections_range", since = "1.28.0")] fn end_bound(&self) -> Bound<&T>; + /// Performs bounds-checking of this range. + /// + /// The returned [`Range`] is safe to pass to [`slice::get_unchecked`] and + /// [`slice::get_unchecked_mut`] for slices of the given length. + /// + /// [`slice::get_unchecked`]: ../../std/primitive.slice.html#method.get_unchecked + /// [`slice::get_unchecked_mut`]: ../../std/primitive.slice.html#method.get_unchecked_mut + /// + /// # Panics + /// + /// Panics if the range would be out of bounds. + /// + /// # Examples + /// + /// ``` + /// #![feature(range_bounds_assert_len)] + /// + /// use std::ops::RangeBounds; + /// + /// let v = [10, 40, 30]; + /// assert_eq!(1..2, (1..2).assert_len(v.len())); + /// assert_eq!(0..2, (..2).assert_len(v.len())); + /// assert_eq!(1..3, (1..).assert_len(v.len())); + /// ``` + /// + /// Panics when [`Index::index`] would panic: + /// + /// ```should_panic + /// #![feature(range_bounds_assert_len)] + /// + /// use std::ops::RangeBounds; + /// + /// (2..1).assert_len(3); + /// ``` + /// + /// ```should_panic + /// #![feature(range_bounds_assert_len)] + /// + /// use std::ops::RangeBounds; + /// + /// (1..4).assert_len(3); + /// ``` + /// + /// ```should_panic + /// #![feature(range_bounds_assert_len)] + /// + /// use std::ops::RangeBounds; + /// + /// (1..=usize::MAX).assert_len(3); + /// ``` + /// + /// [`Index::index`]: crate::ops::Index::index + #[track_caller] + #[unstable(feature = "range_bounds_assert_len", issue = "76393")] + fn assert_len(self, len: usize) -> Range<usize> + where + Self: RangeBounds<usize>, + { + let start: Bound<&usize> = self.start_bound(); + let start = match start { + Bound::Included(&start) => start, + Bound::Excluded(start) => { + start.checked_add(1).unwrap_or_else(|| slice_start_index_overflow_fail()) + } + Bound::Unbounded => 0, + }; + + let end: Bound<&usize> = self.end_bound(); + let end = match end { + Bound::Included(end) => { + end.checked_add(1).unwrap_or_else(|| slice_end_index_overflow_fail()) + } + Bound::Excluded(&end) => end, + Bound::Unbounded => len, + }; + + if start > end { + slice_index_order_fail(start, end); + } + if end > len { + slice_end_index_len_fail(end, len); + } + + Range { start, end } + } + /// Returns `true` if `item` is contained in the range. /// /// # Examples diff --git a/library/core/src/option.rs b/library/core/src/option.rs index 9cb20a0afdc..825144e5a6f 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -687,6 +687,7 @@ impl<T> Option<T> { /// assert_eq!(Some(4).filter(is_even), Some(4)); /// ``` /// + /// [`Some(t)`]: Some #[inline] #[stable(feature = "option_filter", since = "1.27.0")] pub fn filter<P: FnOnce(&T) -> bool>(self, predicate: P) -> Self { diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs index 92c4f2ccfe8..bca3be56ba5 100644 --- a/library/core/src/ptr/mod.rs +++ b/library/core/src/ptr/mod.rs @@ -229,6 +229,16 @@ pub(crate) struct FatPtr<T> { pub(crate) len: usize, } +// Manual impl needed to avoid `T: Clone` bound. +impl<T> Clone for FatPtr<T> { + fn clone(&self) -> Self { + *self + } +} + +// Manual impl needed to avoid `T: Copy` bound. +impl<T> Copy for FatPtr<T> {} + /// Forms a raw slice from a pointer and a length. /// /// The `len` argument is the number of **elements**, not the number of bytes. diff --git a/library/core/src/result.rs b/library/core/src/result.rs index 5cec183c237..b6d9f13d881 100644 --- a/library/core/src/result.rs +++ b/library/core/src/result.rs @@ -233,7 +233,7 @@ use crate::{convert, fmt}; /// `Result` is a type that represents either success ([`Ok`]) or failure ([`Err`]). /// -/// See the [`std::result`](index.html) module documentation for details. +/// See the [module documentation](self) for details. #[derive(Copy, PartialEq, PartialOrd, Eq, Ord, Debug, Hash)] #[must_use = "this `Result` may be an `Err` variant, which should be handled"] #[rustc_diagnostic_item = "result_type"] diff --git a/library/core/src/slice/index.rs b/library/core/src/slice/index.rs index 16fcb6231dc..f1f21c1d24b 100644 --- a/library/core/src/slice/index.rs +++ b/library/core/src/slice/index.rs @@ -1,6 +1,6 @@ //! Indexing implementations for `[T]`. -use crate::ops::{self, Bound, Range, RangeBounds}; +use crate::ops; use crate::ptr; #[stable(feature = "rust1", since = "1.0.0")] @@ -37,104 +37,31 @@ fn slice_start_index_len_fail(index: usize, len: usize) -> ! { #[inline(never)] #[cold] #[track_caller] -pub(super) fn slice_end_index_len_fail(index: usize, len: usize) -> ! { +pub(crate) fn slice_end_index_len_fail(index: usize, len: usize) -> ! { panic!("range end index {} out of range for slice of length {}", index, len); } #[inline(never)] #[cold] #[track_caller] -pub(super) fn slice_index_order_fail(index: usize, end: usize) -> ! { +pub(crate) fn slice_index_order_fail(index: usize, end: usize) -> ! { panic!("slice index starts at {} but ends at {}", index, end); } #[inline(never)] #[cold] #[track_caller] -pub(super) fn slice_start_index_overflow_fail() -> ! { +pub(crate) fn slice_start_index_overflow_fail() -> ! { panic!("attempted to index slice from after maximum usize"); } #[inline(never)] #[cold] #[track_caller] -pub(super) fn slice_end_index_overflow_fail() -> ! { +pub(crate) fn slice_end_index_overflow_fail() -> ! { panic!("attempted to index slice up to maximum usize"); } -/// Performs bounds-checking of the given range. -/// The returned [`Range`] is safe to pass to [`get_unchecked`] and [`get_unchecked_mut`] -/// for slices of the given length. -/// -/// [`get_unchecked`]: ../../std/primitive.slice.html#method.get_unchecked -/// [`get_unchecked_mut`]: ../../std/primitive.slice.html#method.get_unchecked_mut -/// -/// # Panics -/// -/// Panics if the range is out of bounds. -/// -/// # Examples -/// -/// ``` -/// #![feature(slice_check_range)] -/// use std::slice; -/// -/// let v = [10, 40, 30]; -/// assert_eq!(1..2, slice::check_range(v.len(), 1..2)); -/// assert_eq!(0..2, slice::check_range(v.len(), ..2)); -/// assert_eq!(1..3, slice::check_range(v.len(), 1..)); -/// ``` -/// -/// Panics when [`Index::index`] would panic: -/// -/// ```should_panic -/// #![feature(slice_check_range)] -/// -/// std::slice::check_range(3, 2..1); -/// ``` -/// -/// ```should_panic -/// #![feature(slice_check_range)] -/// -/// std::slice::check_range(3, 1..4); -/// ``` -/// -/// ```should_panic -/// #![feature(slice_check_range)] -/// -/// std::slice::check_range(3, 1..=usize::MAX); -/// ``` -/// -/// [`Index::index`]: ops::Index::index -#[track_caller] -#[unstable(feature = "slice_check_range", issue = "76393")] -pub fn check_range<R: RangeBounds<usize>>(len: usize, range: R) -> Range<usize> { - let start = match range.start_bound() { - Bound::Included(&start) => start, - Bound::Excluded(start) => { - start.checked_add(1).unwrap_or_else(|| slice_start_index_overflow_fail()) - } - Bound::Unbounded => 0, - }; - - let end = match range.end_bound() { - Bound::Included(end) => { - end.checked_add(1).unwrap_or_else(|| slice_end_index_overflow_fail()) - } - Bound::Excluded(&end) => end, - Bound::Unbounded => len, - }; - - if start > end { - slice_index_order_fail(start, end); - } - if end > len { - slice_end_index_len_fail(end, len); - } - - Range { start, end } -} - mod private_slice_index { use super::ops; #[stable(feature = "slice_get_slice", since = "1.28.0")] diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index d0d88c01f5b..d32e7d43551 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -29,7 +29,7 @@ pub mod memchr; mod ascii; mod cmp; -mod index; +pub(crate) mod index; mod iter; mod raw; mod rotate; @@ -73,9 +73,6 @@ pub use sort::heapsort; #[stable(feature = "slice_get_slice", since = "1.28.0")] pub use index::SliceIndex; -#[unstable(feature = "slice_check_range", issue = "76393")] -pub use index::check_range; - #[lang = "slice"] #[cfg(not(test))] impl<T> [T] { @@ -2035,6 +2032,50 @@ impl<T> [T] { } /// Reorder the slice such that the element at `index` is at its final sorted position. + #[unstable(feature = "slice_partition_at_index", issue = "55300")] + #[rustc_deprecated(since = "1.49.0", reason = "use the select_nth_unstable() instead")] + #[inline] + pub fn partition_at_index(&mut self, index: usize) -> (&mut [T], &mut T, &mut [T]) + where + T: Ord, + { + self.select_nth_unstable(index) + } + + /// Reorder the slice with a comparator function such that the element at `index` is at its + /// final sorted position. + #[unstable(feature = "slice_partition_at_index", issue = "55300")] + #[rustc_deprecated(since = "1.49.0", reason = "use select_nth_unstable_by() instead")] + #[inline] + pub fn partition_at_index_by<F>( + &mut self, + index: usize, + compare: F, + ) -> (&mut [T], &mut T, &mut [T]) + where + F: FnMut(&T, &T) -> Ordering, + { + self.select_nth_unstable_by(index, compare) + } + + /// Reorder the slice with a key extraction function such that the element at `index` is at its + /// final sorted position. + #[unstable(feature = "slice_partition_at_index", issue = "55300")] + #[rustc_deprecated(since = "1.49.0", reason = "use the select_nth_unstable_by_key() instead")] + #[inline] + pub fn partition_at_index_by_key<K, F>( + &mut self, + index: usize, + f: F, + ) -> (&mut [T], &mut T, &mut [T]) + where + F: FnMut(&T) -> K, + K: Ord, + { + self.select_nth_unstable_by_key(index, f) + } + + /// Reorder the slice such that the element at `index` is at its final sorted position. /// /// This reordering has the additional property that any value at position `i < index` will be /// less than or equal to any value at a position `j > index`. Additionally, this reordering is @@ -2058,12 +2099,10 @@ impl<T> [T] { /// # Examples /// /// ``` - /// #![feature(slice_partition_at_index)] - /// /// let mut v = [-5i32, 4, 1, -3, 2]; /// /// // Find the median - /// v.partition_at_index(2); + /// v.select_nth_unstable(2); /// /// // We are only guaranteed the slice will be one of the following, based on the way we sort /// // about the specified index. @@ -2072,9 +2111,9 @@ impl<T> [T] { /// v == [-3, -5, 1, 4, 2] || /// v == [-5, -3, 1, 4, 2]); /// ``` - #[unstable(feature = "slice_partition_at_index", issue = "55300")] + #[stable(feature = "slice_select_nth_unstable", since = "1.49.0")] #[inline] - pub fn partition_at_index(&mut self, index: usize) -> (&mut [T], &mut T, &mut [T]) + pub fn select_nth_unstable(&mut self, index: usize) -> (&mut [T], &mut T, &mut [T]) where T: Ord, { @@ -2108,12 +2147,10 @@ impl<T> [T] { /// # Examples /// /// ``` - /// #![feature(slice_partition_at_index)] - /// /// let mut v = [-5i32, 4, 1, -3, 2]; /// /// // Find the median as if the slice were sorted in descending order. - /// v.partition_at_index_by(2, |a, b| b.cmp(a)); + /// v.select_nth_unstable_by(2, |a, b| b.cmp(a)); /// /// // We are only guaranteed the slice will be one of the following, based on the way we sort /// // about the specified index. @@ -2122,9 +2159,9 @@ impl<T> [T] { /// v == [4, 2, 1, -5, -3] || /// v == [4, 2, 1, -3, -5]); /// ``` - #[unstable(feature = "slice_partition_at_index", issue = "55300")] + #[stable(feature = "slice_select_nth_unstable", since = "1.49.0")] #[inline] - pub fn partition_at_index_by<F>( + pub fn select_nth_unstable_by<F>( &mut self, index: usize, mut compare: F, @@ -2162,12 +2199,10 @@ impl<T> [T] { /// # Examples /// /// ``` - /// #![feature(slice_partition_at_index)] - /// /// let mut v = [-5i32, 4, 1, -3, 2]; /// /// // Return the median as if the array were sorted according to absolute value. - /// v.partition_at_index_by_key(2, |a| a.abs()); + /// v.select_nth_unstable_by_key(2, |a| a.abs()); /// /// // We are only guaranteed the slice will be one of the following, based on the way we sort /// // about the specified index. @@ -2176,9 +2211,9 @@ impl<T> [T] { /// v == [2, 1, -3, 4, -5] || /// v == [2, 1, -3, -5, 4]); /// ``` - #[unstable(feature = "slice_partition_at_index", issue = "55300")] + #[stable(feature = "slice_select_nth_unstable", since = "1.49.0")] #[inline] - pub fn partition_at_index_by_key<K, F>( + pub fn select_nth_unstable_by_key<K, F>( &mut self, index: usize, mut f: F, @@ -2676,7 +2711,7 @@ impl<T> [T] { where T: Copy, { - let Range { start: src_start, end: src_end } = check_range(self.len(), src); + let Range { start: src_start, end: src_end } = src.assert_len(self.len()); let count = src_end - src_start; assert!(dest <= self.len() - count, "dest is out of bounds"); // SAFETY: the conditions for `ptr::copy` have all been checked above, diff --git a/library/core/src/str/iter.rs b/library/core/src/str/iter.rs index 27a67e2b22f..bee86df520c 100644 --- a/library/core/src/str/iter.rs +++ b/library/core/src/str/iter.rs @@ -690,6 +690,17 @@ impl<'a, P: Pattern<'a>> SplitInternal<'a, P> { }, } } + + #[inline] + fn as_str(&self) -> &'a str { + // `Self::get_end` doesn't change `self.start` + if self.finished { + return ""; + } + + // SAFETY: `self.start` and `self.end` always lie on unicode boundaries. + unsafe { self.matcher.haystack().get_unchecked(self.start..self.end) } + } } generate_pattern_iterators! { @@ -710,6 +721,48 @@ generate_pattern_iterators! { delegate double ended; } +impl<'a, P: Pattern<'a>> Split<'a, P> { + /// Returns remainder of the splitted string + /// + /// # Examples + /// + /// ``` + /// #![feature(str_split_as_str)] + /// let mut split = "Mary had a little lamb".split(' '); + /// assert_eq!(split.as_str(), "Mary had a little lamb"); + /// split.next(); + /// assert_eq!(split.as_str(), "had a little lamb"); + /// split.by_ref().for_each(drop); + /// assert_eq!(split.as_str(), ""); + /// ``` + #[inline] + #[unstable(feature = "str_split_as_str", issue = "77998")] + pub fn as_str(&self) -> &'a str { + self.0.as_str() + } +} + +impl<'a, P: Pattern<'a>> RSplit<'a, P> { + /// Returns remainder of the splitted string + /// + /// # Examples + /// + /// ``` + /// #![feature(str_split_as_str)] + /// let mut split = "Mary had a little lamb".rsplit(' '); + /// assert_eq!(split.as_str(), "Mary had a little lamb"); + /// split.next(); + /// assert_eq!(split.as_str(), "Mary had a little"); + /// split.by_ref().for_each(drop); + /// assert_eq!(split.as_str(), ""); + /// ``` + #[inline] + #[unstable(feature = "str_split_as_str", issue = "77998")] + pub fn as_str(&self) -> &'a str { + self.0.as_str() + } +} + generate_pattern_iterators! { forward: /// Created with the method [`split_terminator`]. @@ -728,6 +781,48 @@ generate_pattern_iterators! { delegate double ended; } +impl<'a, P: Pattern<'a>> SplitTerminator<'a, P> { + /// Returns remainder of the splitted string + /// + /// # Examples + /// + /// ``` + /// #![feature(str_split_as_str)] + /// let mut split = "A..B..".split_terminator('.'); + /// assert_eq!(split.as_str(), "A..B.."); + /// split.next(); + /// assert_eq!(split.as_str(), ".B.."); + /// split.by_ref().for_each(drop); + /// assert_eq!(split.as_str(), ""); + /// ``` + #[inline] + #[unstable(feature = "str_split_as_str", issue = "77998")] + pub fn as_str(&self) -> &'a str { + self.0.as_str() + } +} + +impl<'a, P: Pattern<'a>> RSplitTerminator<'a, P> { + /// Returns remainder of the splitted string + /// + /// # Examples + /// + /// ``` + /// #![feature(str_split_as_str)] + /// let mut split = "A..B..".rsplit_terminator('.'); + /// assert_eq!(split.as_str(), "A..B.."); + /// split.next(); + /// assert_eq!(split.as_str(), "A..B"); + /// split.by_ref().for_each(drop); + /// assert_eq!(split.as_str(), ""); + /// ``` + #[inline] + #[unstable(feature = "str_split_as_str", issue = "77998")] + pub fn as_str(&self) -> &'a str { + self.0.as_str() + } +} + derive_pattern_clone! { clone SplitNInternal with |s| SplitNInternal { iter: s.iter.clone(), ..*s } @@ -784,6 +879,11 @@ impl<'a, P: Pattern<'a>> SplitNInternal<'a, P> { } } } + + #[inline] + fn as_str(&self) -> &'a str { + self.iter.as_str() + } } generate_pattern_iterators! { @@ -804,6 +904,48 @@ generate_pattern_iterators! { delegate single ended; } +impl<'a, P: Pattern<'a>> SplitN<'a, P> { + /// Returns remainder of the splitted string + /// + /// # Examples + /// + /// ``` + /// #![feature(str_split_as_str)] + /// let mut split = "Mary had a little lamb".splitn(3, ' '); + /// assert_eq!(split.as_str(), "Mary had a little lamb"); + /// split.next(); + /// assert_eq!(split.as_str(), "had a little lamb"); + /// split.by_ref().for_each(drop); + /// assert_eq!(split.as_str(), ""); + /// ``` + #[inline] + #[unstable(feature = "str_split_as_str", issue = "77998")] + pub fn as_str(&self) -> &'a str { + self.0.as_str() + } +} + +impl<'a, P: Pattern<'a>> RSplitN<'a, P> { + /// Returns remainder of the splitted string + /// + /// # Examples + /// + /// ``` + /// #![feature(str_split_as_str)] + /// let mut split = "Mary had a little lamb".rsplitn(3, ' '); + /// assert_eq!(split.as_str(), "Mary had a little lamb"); + /// split.next(); + /// assert_eq!(split.as_str(), "Mary had a little"); + /// split.by_ref().for_each(drop); + /// assert_eq!(split.as_str(), ""); + /// ``` + #[inline] + #[unstable(feature = "str_split_as_str", issue = "77998")] + pub fn as_str(&self) -> &'a str { + self.0.as_str() + } +} + derive_pattern_clone! { clone MatchIndicesInternal with |s| MatchIndicesInternal(s.0.clone()) @@ -1134,6 +1276,28 @@ impl<'a, P: Pattern<'a, Searcher: ReverseSearcher<'a>>> DoubleEndedIterator #[unstable(feature = "split_inclusive", issue = "72360")] impl<'a, P: Pattern<'a>> FusedIterator for SplitInclusive<'a, P> {} +impl<'a, P: Pattern<'a>> SplitInclusive<'a, P> { + /// Returns remainder of the splitted string + /// + /// # Examples + /// + /// ``` + /// #![feature(str_split_inclusive_as_str)] + /// #![feature(split_inclusive)] + /// let mut split = "Mary had a little lamb".split_inclusive(' '); + /// assert_eq!(split.as_str(), "Mary had a little lamb"); + /// split.next(); + /// assert_eq!(split.as_str(), "had a little lamb"); + /// split.by_ref().for_each(drop); + /// assert_eq!(split.as_str(), ""); + /// ``` + #[inline] + #[unstable(feature = "str_split_inclusive_as_str", issue = "77998")] + pub fn as_str(&self) -> &'a str { + self.0.as_str() + } +} + /// An iterator of [`u16`] over the string encoded as UTF-16. /// /// This struct is created by the [`encode_utf16`] method on [`str`]. diff --git a/library/core/tests/num/int_macros.rs b/library/core/tests/num/int_macros.rs index 27e6760e7cb..fcb0d6031be 100644 --- a/library/core/tests/num/int_macros.rs +++ b/library/core/tests/num/int_macros.rs @@ -204,8 +204,8 @@ macro_rules! int_module { #[test] fn test_from_str() { - fn from_str<T: ::std::str::FromStr>(t: &str) -> Option<T> { - ::std::str::FromStr::from_str(t).ok() + fn from_str<T: std::str::FromStr>(t: &str) -> Option<T> { + std::str::FromStr::from_str(t).ok() } assert_eq!(from_str::<$T>("0"), Some(0 as $T)); assert_eq!(from_str::<$T>("3"), Some(3 as $T)); diff --git a/library/core/tests/slice.rs b/library/core/tests/slice.rs index 5ef30b1a889..ac5c9353ccb 100644 --- a/library/core/tests/slice.rs +++ b/library/core/tests/slice.rs @@ -1571,7 +1571,7 @@ fn sort_unstable() { #[test] #[cfg(not(target_arch = "wasm32"))] #[cfg_attr(miri, ignore)] // Miri is too slow -fn partition_at_index() { +fn select_nth_unstable() { use core::cmp::Ordering::{Equal, Greater, Less}; use rand::rngs::StdRng; use rand::seq::SliceRandom; @@ -1597,7 +1597,7 @@ fn partition_at_index() { // Sort in default order. for pivot in 0..len { let mut v = orig.clone(); - v.partition_at_index(pivot); + v.select_nth_unstable(pivot); assert_eq!(v_sorted[pivot], v[pivot]); for i in 0..pivot { @@ -1610,7 +1610,7 @@ fn partition_at_index() { // Sort in ascending order. for pivot in 0..len { let mut v = orig.clone(); - let (left, pivot, right) = v.partition_at_index_by(pivot, |a, b| a.cmp(b)); + let (left, pivot, right) = v.select_nth_unstable_by(pivot, |a, b| a.cmp(b)); assert_eq!(left.len() + right.len(), len - 1); @@ -1633,7 +1633,7 @@ fn partition_at_index() { for pivot in 0..len { let mut v = orig.clone(); - v.partition_at_index_by(pivot, sort_descending_comparator); + v.select_nth_unstable_by(pivot, sort_descending_comparator); assert_eq!(v_sorted_descending[pivot], v[pivot]); for i in 0..pivot { @@ -1654,7 +1654,7 @@ fn partition_at_index() { } for pivot in 0..v.len() { - v.partition_at_index_by(pivot, |_, _| *[Less, Equal, Greater].choose(&mut rng).unwrap()); + v.select_nth_unstable_by(pivot, |_, _| *[Less, Equal, Greater].choose(&mut rng).unwrap()); v.sort(); for i in 0..v.len() { assert_eq!(v[i], i as i32); @@ -1662,28 +1662,28 @@ fn partition_at_index() { } // Should not panic. - [(); 10].partition_at_index(0); - [(); 10].partition_at_index(5); - [(); 10].partition_at_index(9); - [(); 100].partition_at_index(0); - [(); 100].partition_at_index(50); - [(); 100].partition_at_index(99); + [(); 10].select_nth_unstable(0); + [(); 10].select_nth_unstable(5); + [(); 10].select_nth_unstable(9); + [(); 100].select_nth_unstable(0); + [(); 100].select_nth_unstable(50); + [(); 100].select_nth_unstable(99); let mut v = [0xDEADBEEFu64]; - v.partition_at_index(0); + v.select_nth_unstable(0); assert!(v == [0xDEADBEEF]); } #[test] #[should_panic(expected = "index 0 greater than length of slice")] -fn partition_at_index_zero_length() { - [0i32; 0].partition_at_index(0); +fn select_nth_unstable_zero_length() { + [0i32; 0].select_nth_unstable(0); } #[test] #[should_panic(expected = "index 20 greater than length of slice")] -fn partition_at_index_past_length() { - [0i32; 10].partition_at_index(20); +fn select_nth_unstable_past_length() { + [0i32; 10].select_nth_unstable(20); } pub mod memchr { diff --git a/library/std/src/backtrace.rs b/library/std/src/backtrace.rs index cc29e1c0b05..a9d8a4e2a81 100644 --- a/library/std/src/backtrace.rs +++ b/library/std/src/backtrace.rs @@ -303,7 +303,8 @@ impl Backtrace { // Capture a backtrace which start just before the function addressed by // `ip` fn create(ip: usize) -> Backtrace { - let _lock = lock(); + // SAFETY: We don't attempt to lock this reentrantly. + let _lock = unsafe { lock() }; let mut frames = Vec::new(); let mut actual_start = None; unsafe { @@ -408,7 +409,8 @@ impl Capture { // Use the global backtrace lock to synchronize this as it's a // requirement of the `backtrace` crate, and then actually resolve // everything. - let _lock = lock(); + // SAFETY: We don't attempt to lock this reentrantly. + let _lock = unsafe { lock() }; for frame in self.frames.iter_mut() { let symbols = &mut frame.symbols; let frame = match &frame.frame { diff --git a/library/std/src/ffi/c_str.rs b/library/std/src/ffi/c_str.rs index 13021738af1..6df4eb99259 100644 --- a/library/std/src/ffi/c_str.rs +++ b/library/std/src/ffi/c_str.rs @@ -1383,7 +1383,8 @@ impl CStr { /// [`U+FFFD REPLACEMENT CHARACTER`][U+FFFD] and return a /// [`Cow`]`::`[`Owned`]`(`[`String`]`)` with the result. /// - /// [`str`]: prim@str + /// [`str`]: primitive@str + /// [`&str`]: primitive@str /// [`Borrowed`]: Cow::Borrowed /// [`Owned`]: Cow::Owned /// [U+FFFD]: crate::char::REPLACEMENT_CHARACTER diff --git a/library/std/src/ffi/os_str.rs b/library/std/src/ffi/os_str.rs index 2663f682a1d..7e7a28be2b0 100644 --- a/library/std/src/ffi/os_str.rs +++ b/library/std/src/ffi/os_str.rs @@ -69,7 +69,7 @@ use crate::sys_common::{AsInner, FromInner, IntoInner}; /// [`&OsStr`]: OsStr /// [`&str`]: str /// [`CStr`]: crate::ffi::CStr -/// [conversions]: index.html#conversions +/// [conversions]: super#conversions #[derive(Clone)] #[stable(feature = "rust1", since = "1.0.0")] pub struct OsString { @@ -88,7 +88,7 @@ pub struct OsString { /// the traits which `OsStr` implements for [conversions] from/to native representations. /// /// [`&str`]: str -/// [conversions]: index.html#conversions +/// [conversions]: super#conversions #[stable(feature = "rust1", since = "1.0.0")] // FIXME: // `OsStr::from_inner` current implementation relies diff --git a/library/std/src/io/buffered.rs b/library/std/src/io/buffered.rs deleted file mode 100644 index 97c4b879793..00000000000 --- a/library/std/src/io/buffered.rs +++ /dev/null @@ -1,1438 +0,0 @@ -//! Buffering wrappers for I/O traits - -#[cfg(test)] -mod tests; - -use crate::io::prelude::*; - -use crate::cmp; -use crate::error; -use crate::fmt; -use crate::io::{ - self, Error, ErrorKind, Initializer, IoSlice, IoSliceMut, SeekFrom, DEFAULT_BUF_SIZE, -}; -use crate::memchr; - -/// The `BufReader<R>` struct adds buffering to any reader. -/// -/// It can be excessively inefficient to work directly with a [`Read`] instance. -/// For example, every call to [`read`][`TcpStream::read`] on [`TcpStream`] -/// results in a system call. A `BufReader<R>` performs large, infrequent reads on -/// the underlying [`Read`] and maintains an in-memory buffer of the results. -/// -/// `BufReader<R>` can improve the speed of programs that make *small* and -/// *repeated* read calls to the same file or network socket. It does not -/// help when reading very large amounts at once, or reading just one or a few -/// times. It also provides no advantage when reading from a source that is -/// already in memory, like a [`Vec`]`<u8>`. -/// -/// When the `BufReader<R>` is dropped, the contents of its buffer will be -/// discarded. Creating multiple instances of a `BufReader<R>` on the same -/// stream can cause data loss. Reading from the underlying reader after -/// unwrapping the `BufReader<R>` with [`BufReader::into_inner`] can also cause -/// data loss. -/// -/// [`TcpStream::read`]: Read::read -/// [`TcpStream`]: crate::net::TcpStream -/// -/// # Examples -/// -/// ```no_run -/// use std::io::prelude::*; -/// use std::io::BufReader; -/// use std::fs::File; -/// -/// fn main() -> std::io::Result<()> { -/// let f = File::open("log.txt")?; -/// let mut reader = BufReader::new(f); -/// -/// let mut line = String::new(); -/// let len = reader.read_line(&mut line)?; -/// println!("First line is {} bytes long", len); -/// Ok(()) -/// } -/// ``` -#[stable(feature = "rust1", since = "1.0.0")] -pub struct BufReader<R> { - inner: R, - buf: Box<[u8]>, - pos: usize, - cap: usize, -} - -impl<R: Read> BufReader<R> { - /// Creates a new `BufReader<R>` with a default buffer capacity. The default is currently 8 KB, - /// but may change in the future. - /// - /// # Examples - /// - /// ```no_run - /// use std::io::BufReader; - /// use std::fs::File; - /// - /// fn main() -> std::io::Result<()> { - /// let f = File::open("log.txt")?; - /// let reader = BufReader::new(f); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn new(inner: R) -> BufReader<R> { - BufReader::with_capacity(DEFAULT_BUF_SIZE, inner) - } - - /// Creates a new `BufReader<R>` with the specified buffer capacity. - /// - /// # Examples - /// - /// Creating a buffer with ten bytes of capacity: - /// - /// ```no_run - /// use std::io::BufReader; - /// use std::fs::File; - /// - /// fn main() -> std::io::Result<()> { - /// let f = File::open("log.txt")?; - /// let reader = BufReader::with_capacity(10, f); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn with_capacity(capacity: usize, inner: R) -> BufReader<R> { - unsafe { - let mut buffer = Vec::with_capacity(capacity); - buffer.set_len(capacity); - inner.initializer().initialize(&mut buffer); - BufReader { inner, buf: buffer.into_boxed_slice(), pos: 0, cap: 0 } - } - } -} - -impl<R> BufReader<R> { - /// Gets a reference to the underlying reader. - /// - /// It is inadvisable to directly read from the underlying reader. - /// - /// # Examples - /// - /// ```no_run - /// use std::io::BufReader; - /// use std::fs::File; - /// - /// fn main() -> std::io::Result<()> { - /// let f1 = File::open("log.txt")?; - /// let reader = BufReader::new(f1); - /// - /// let f2 = reader.get_ref(); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn get_ref(&self) -> &R { - &self.inner - } - - /// Gets a mutable reference to the underlying reader. - /// - /// It is inadvisable to directly read from the underlying reader. - /// - /// # Examples - /// - /// ```no_run - /// use std::io::BufReader; - /// use std::fs::File; - /// - /// fn main() -> std::io::Result<()> { - /// let f1 = File::open("log.txt")?; - /// let mut reader = BufReader::new(f1); - /// - /// let f2 = reader.get_mut(); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn get_mut(&mut self) -> &mut R { - &mut self.inner - } - - /// Returns a reference to the internally buffered data. - /// - /// Unlike [`fill_buf`], this will not attempt to fill the buffer if it is empty. - /// - /// [`fill_buf`]: BufRead::fill_buf - /// - /// # Examples - /// - /// ```no_run - /// use std::io::{BufReader, BufRead}; - /// use std::fs::File; - /// - /// fn main() -> std::io::Result<()> { - /// let f = File::open("log.txt")?; - /// let mut reader = BufReader::new(f); - /// assert!(reader.buffer().is_empty()); - /// - /// if reader.fill_buf()?.len() > 0 { - /// assert!(!reader.buffer().is_empty()); - /// } - /// Ok(()) - /// } - /// ``` - #[stable(feature = "bufreader_buffer", since = "1.37.0")] - pub fn buffer(&self) -> &[u8] { - &self.buf[self.pos..self.cap] - } - - /// Returns the number of bytes the internal buffer can hold at once. - /// - /// # Examples - /// - /// ```no_run - /// use std::io::{BufReader, BufRead}; - /// use std::fs::File; - /// - /// fn main() -> std::io::Result<()> { - /// let f = File::open("log.txt")?; - /// let mut reader = BufReader::new(f); - /// - /// let capacity = reader.capacity(); - /// let buffer = reader.fill_buf()?; - /// assert!(buffer.len() <= capacity); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "buffered_io_capacity", since = "1.46.0")] - pub fn capacity(&self) -> usize { - self.buf.len() - } - - /// Unwraps this `BufReader<R>`, returning the underlying reader. - /// - /// Note that any leftover data in the internal buffer is lost. Therefore, - /// a following read from the underlying reader may lead to data loss. - /// - /// # Examples - /// - /// ```no_run - /// use std::io::BufReader; - /// use std::fs::File; - /// - /// fn main() -> std::io::Result<()> { - /// let f1 = File::open("log.txt")?; - /// let reader = BufReader::new(f1); - /// - /// let f2 = reader.into_inner(); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn into_inner(self) -> R { - self.inner - } - - /// Invalidates all data in the internal buffer. - #[inline] - fn discard_buffer(&mut self) { - self.pos = 0; - self.cap = 0; - } -} - -impl<R: Seek> BufReader<R> { - /// Seeks relative to the current position. If the new position lies within the buffer, - /// the buffer will not be flushed, allowing for more efficient seeks. - /// This method does not return the location of the underlying reader, so the caller - /// must track this information themselves if it is required. - #[unstable(feature = "bufreader_seek_relative", issue = "31100")] - pub fn seek_relative(&mut self, offset: i64) -> io::Result<()> { - let pos = self.pos as u64; - if offset < 0 { - if let Some(new_pos) = pos.checked_sub((-offset) as u64) { - self.pos = new_pos as usize; - return Ok(()); - } - } else { - if let Some(new_pos) = pos.checked_add(offset as u64) { - if new_pos <= self.cap as u64 { - self.pos = new_pos as usize; - return Ok(()); - } - } - } - self.seek(SeekFrom::Current(offset)).map(drop) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<R: Read> Read for BufReader<R> { - fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { - // If we don't have any buffered data and we're doing a massive read - // (larger than our internal buffer), bypass our internal buffer - // entirely. - if self.pos == self.cap && buf.len() >= self.buf.len() { - self.discard_buffer(); - return self.inner.read(buf); - } - let nread = { - let mut rem = self.fill_buf()?; - rem.read(buf)? - }; - self.consume(nread); - Ok(nread) - } - - fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> { - let total_len = bufs.iter().map(|b| b.len()).sum::<usize>(); - if self.pos == self.cap && total_len >= self.buf.len() { - self.discard_buffer(); - return self.inner.read_vectored(bufs); - } - let nread = { - let mut rem = self.fill_buf()?; - rem.read_vectored(bufs)? - }; - self.consume(nread); - Ok(nread) - } - - fn is_read_vectored(&self) -> bool { - self.inner.is_read_vectored() - } - - // we can't skip unconditionally because of the large buffer case in read. - unsafe fn initializer(&self) -> Initializer { - self.inner.initializer() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<R: Read> BufRead for BufReader<R> { - fn fill_buf(&mut self) -> io::Result<&[u8]> { - // If we've reached the end of our internal buffer then we need to fetch - // some more data from the underlying reader. - // Branch using `>=` instead of the more correct `==` - // to tell the compiler that the pos..cap slice is always valid. - if self.pos >= self.cap { - debug_assert!(self.pos == self.cap); - self.cap = self.inner.read(&mut self.buf)?; - self.pos = 0; - } - Ok(&self.buf[self.pos..self.cap]) - } - - fn consume(&mut self, amt: usize) { - self.pos = cmp::min(self.pos + amt, self.cap); - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<R> fmt::Debug for BufReader<R> -where - R: fmt::Debug, -{ - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt.debug_struct("BufReader") - .field("reader", &self.inner) - .field("buffer", &format_args!("{}/{}", self.cap - self.pos, self.buf.len())) - .finish() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<R: Seek> Seek for BufReader<R> { - /// Seek to an offset, in bytes, in the underlying reader. - /// - /// The position used for seeking with [`SeekFrom::Current`]`(_)` is the - /// position the underlying reader would be at if the `BufReader<R>` had no - /// internal buffer. - /// - /// Seeking always discards the internal buffer, even if the seek position - /// would otherwise fall within it. This guarantees that calling - /// [`BufReader::into_inner()`] immediately after a seek yields the underlying reader - /// at the same position. - /// - /// To seek without discarding the internal buffer, use [`BufReader::seek_relative`]. - /// - /// See [`std::io::Seek`] for more details. - /// - /// Note: In the edge case where you're seeking with [`SeekFrom::Current`]`(n)` - /// where `n` minus the internal buffer length overflows an `i64`, two - /// seeks will be performed instead of one. If the second seek returns - /// [`Err`], the underlying reader will be left at the same position it would - /// have if you called `seek` with [`SeekFrom::Current`]`(0)`. - /// - /// [`std::io::Seek`]: Seek - fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> { - let result: u64; - if let SeekFrom::Current(n) = pos { - let remainder = (self.cap - self.pos) as i64; - // it should be safe to assume that remainder fits within an i64 as the alternative - // means we managed to allocate 8 exbibytes and that's absurd. - // But it's not out of the realm of possibility for some weird underlying reader to - // support seeking by i64::MIN so we need to handle underflow when subtracting - // remainder. - if let Some(offset) = n.checked_sub(remainder) { - result = self.inner.seek(SeekFrom::Current(offset))?; - } else { - // seek backwards by our remainder, and then by the offset - self.inner.seek(SeekFrom::Current(-remainder))?; - self.discard_buffer(); - result = self.inner.seek(SeekFrom::Current(n))?; - } - } else { - // Seeking with Start/End doesn't care about our buffer length. - result = self.inner.seek(pos)?; - } - self.discard_buffer(); - Ok(result) - } - - /// Returns the current seek position from the start of the stream. - /// - /// The value returned is equivalent to `self.seek(SeekFrom::Current(0))` - /// but does not flush the internal buffer. Due to this optimization the - /// function does not guarantee that calling `.into_inner()` immediately - /// afterwards will yield the underlying reader at the same position. Use - /// [`BufReader::seek`] instead if you require that guarantee. - /// - /// # Panics - /// - /// This function will panic if the position of the inner reader is smaller - /// than the amount of buffered data. That can happen if the inner reader - /// has an incorrect implementation of [`Seek::stream_position`], or if the - /// position has gone out of sync due to calling [`Seek::seek`] directly on - /// the underlying reader. - /// - /// # Example - /// - /// ```no_run - /// #![feature(seek_convenience)] - /// use std::{ - /// io::{self, BufRead, BufReader, Seek}, - /// fs::File, - /// }; - /// - /// fn main() -> io::Result<()> { - /// let mut f = BufReader::new(File::open("foo.txt")?); - /// - /// let before = f.stream_position()?; - /// f.read_line(&mut String::new())?; - /// let after = f.stream_position()?; - /// - /// println!("The first line was {} bytes long", after - before); - /// Ok(()) - /// } - /// ``` - fn stream_position(&mut self) -> io::Result<u64> { - let remainder = (self.cap - self.pos) as u64; - self.inner.stream_position().map(|pos| { - pos.checked_sub(remainder).expect( - "overflow when subtracting remaining buffer size from inner stream position", - ) - }) - } -} - -/// Wraps a writer and buffers its output. -/// -/// It can be excessively inefficient to work directly with something that -/// implements [`Write`]. For example, every call to -/// [`write`][`TcpStream::write`] on [`TcpStream`] results in a system call. A -/// `BufWriter<W>` keeps an in-memory buffer of data and writes it to an underlying -/// writer in large, infrequent batches. -/// -/// `BufWriter<W>` can improve the speed of programs that make *small* and -/// *repeated* write calls to the same file or network socket. It does not -/// help when writing very large amounts at once, or writing just one or a few -/// times. It also provides no advantage when writing to a destination that is -/// in memory, like a [`Vec`]<u8>`. -/// -/// It is critical to call [`flush`] before `BufWriter<W>` is dropped. Though -/// dropping will attempt to flush the contents of the buffer, any errors -/// that happen in the process of dropping will be ignored. Calling [`flush`] -/// ensures that the buffer is empty and thus dropping will not even attempt -/// file operations. -/// -/// # Examples -/// -/// Let's write the numbers one through ten to a [`TcpStream`]: -/// -/// ```no_run -/// use std::io::prelude::*; -/// use std::net::TcpStream; -/// -/// let mut stream = TcpStream::connect("127.0.0.1:34254").unwrap(); -/// -/// for i in 0..10 { -/// stream.write(&[i+1]).unwrap(); -/// } -/// ``` -/// -/// Because we're not buffering, we write each one in turn, incurring the -/// overhead of a system call per byte written. We can fix this with a -/// `BufWriter<W>`: -/// -/// ```no_run -/// use std::io::prelude::*; -/// use std::io::BufWriter; -/// use std::net::TcpStream; -/// -/// let mut stream = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap()); -/// -/// for i in 0..10 { -/// stream.write(&[i+1]).unwrap(); -/// } -/// stream.flush().unwrap(); -/// ``` -/// -/// By wrapping the stream with a `BufWriter<W>`, these ten writes are all grouped -/// together by the buffer and will all be written out in one system call when -/// the `stream` is flushed. -/// -/// [`TcpStream::write`]: Write::write -/// [`TcpStream`]: crate::net::TcpStream -/// [`flush`]: Write::flush -#[stable(feature = "rust1", since = "1.0.0")] -pub struct BufWriter<W: Write> { - inner: Option<W>, - buf: Vec<u8>, - // #30888: If the inner writer panics in a call to write, we don't want to - // write the buffered data a second time in BufWriter's destructor. This - // flag tells the Drop impl if it should skip the flush. - panicked: bool, -} - -/// An error returned by [`BufWriter::into_inner`] which combines an error that -/// happened while writing out the buffer, and the buffered writer object -/// which may be used to recover from the condition. -/// -/// # Examples -/// -/// ```no_run -/// use std::io::BufWriter; -/// use std::net::TcpStream; -/// -/// let mut stream = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap()); -/// -/// // do stuff with the stream -/// -/// // we want to get our `TcpStream` back, so let's try: -/// -/// let stream = match stream.into_inner() { -/// Ok(s) => s, -/// Err(e) => { -/// // Here, e is an IntoInnerError -/// panic!("An error occurred"); -/// } -/// }; -/// ``` -#[derive(Debug)] -#[stable(feature = "rust1", since = "1.0.0")] -pub struct IntoInnerError<W>(W, Error); - -impl<W: Write> BufWriter<W> { - /// Creates a new `BufWriter<W>` with a default buffer capacity. The default is currently 8 KB, - /// but may change in the future. - /// - /// # Examples - /// - /// ```no_run - /// use std::io::BufWriter; - /// use std::net::TcpStream; - /// - /// let mut buffer = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn new(inner: W) -> BufWriter<W> { - BufWriter::with_capacity(DEFAULT_BUF_SIZE, inner) - } - - /// Creates a new `BufWriter<W>` with the specified buffer capacity. - /// - /// # Examples - /// - /// Creating a buffer with a buffer of a hundred bytes. - /// - /// ```no_run - /// use std::io::BufWriter; - /// use std::net::TcpStream; - /// - /// let stream = TcpStream::connect("127.0.0.1:34254").unwrap(); - /// let mut buffer = BufWriter::with_capacity(100, stream); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn with_capacity(capacity: usize, inner: W) -> BufWriter<W> { - BufWriter { inner: Some(inner), buf: Vec::with_capacity(capacity), panicked: false } - } - - /// Send data in our local buffer into the inner writer, looping as - /// necessary until either it's all been sent or an error occurs. - /// - /// Because all the data in the buffer has been reported to our owner as - /// "successfully written" (by returning nonzero success values from - /// `write`), any 0-length writes from `inner` must be reported as i/o - /// errors from this method. - fn flush_buf(&mut self) -> io::Result<()> { - /// Helper struct to ensure the buffer is updated after all the writes - /// are complete. It tracks the number of written bytes and drains them - /// all from the front of the buffer when dropped. - struct BufGuard<'a> { - buffer: &'a mut Vec<u8>, - written: usize, - } - - impl<'a> BufGuard<'a> { - fn new(buffer: &'a mut Vec<u8>) -> Self { - Self { buffer, written: 0 } - } - - /// The unwritten part of the buffer - fn remaining(&self) -> &[u8] { - &self.buffer[self.written..] - } - - /// Flag some bytes as removed from the front of the buffer - fn consume(&mut self, amt: usize) { - self.written += amt; - } - - /// true if all of the bytes have been written - fn done(&self) -> bool { - self.written >= self.buffer.len() - } - } - - impl Drop for BufGuard<'_> { - fn drop(&mut self) { - if self.written > 0 { - self.buffer.drain(..self.written); - } - } - } - - let mut guard = BufGuard::new(&mut self.buf); - let inner = self.inner.as_mut().unwrap(); - while !guard.done() { - self.panicked = true; - let r = inner.write(guard.remaining()); - self.panicked = false; - - match r { - Ok(0) => { - return Err(Error::new( - ErrorKind::WriteZero, - "failed to write the buffered data", - )); - } - Ok(n) => guard.consume(n), - Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {} - Err(e) => return Err(e), - } - } - Ok(()) - } - - /// Buffer some data without flushing it, regardless of the size of the - /// data. Writes as much as possible without exceeding capacity. Returns - /// the number of bytes written. - fn write_to_buf(&mut self, buf: &[u8]) -> usize { - let available = self.buf.capacity() - self.buf.len(); - let amt_to_buffer = available.min(buf.len()); - self.buf.extend_from_slice(&buf[..amt_to_buffer]); - amt_to_buffer - } - - /// Gets a reference to the underlying writer. - /// - /// # Examples - /// - /// ```no_run - /// use std::io::BufWriter; - /// use std::net::TcpStream; - /// - /// let mut buffer = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap()); - /// - /// // we can use reference just like buffer - /// let reference = buffer.get_ref(); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn get_ref(&self) -> &W { - self.inner.as_ref().unwrap() - } - - /// Gets a mutable reference to the underlying writer. - /// - /// It is inadvisable to directly write to the underlying writer. - /// - /// # Examples - /// - /// ```no_run - /// use std::io::BufWriter; - /// use std::net::TcpStream; - /// - /// let mut buffer = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap()); - /// - /// // we can use reference just like buffer - /// let reference = buffer.get_mut(); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn get_mut(&mut self) -> &mut W { - self.inner.as_mut().unwrap() - } - - /// Returns a reference to the internally buffered data. - /// - /// # Examples - /// - /// ```no_run - /// use std::io::BufWriter; - /// use std::net::TcpStream; - /// - /// let buf_writer = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap()); - /// - /// // See how many bytes are currently buffered - /// let bytes_buffered = buf_writer.buffer().len(); - /// ``` - #[stable(feature = "bufreader_buffer", since = "1.37.0")] - pub fn buffer(&self) -> &[u8] { - &self.buf - } - - /// Returns the number of bytes the internal buffer can hold without flushing. - /// - /// # Examples - /// - /// ```no_run - /// use std::io::BufWriter; - /// use std::net::TcpStream; - /// - /// let buf_writer = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap()); - /// - /// // Check the capacity of the inner buffer - /// let capacity = buf_writer.capacity(); - /// // Calculate how many bytes can be written without flushing - /// let without_flush = capacity - buf_writer.buffer().len(); - /// ``` - #[stable(feature = "buffered_io_capacity", since = "1.46.0")] - pub fn capacity(&self) -> usize { - self.buf.capacity() - } - - /// Unwraps this `BufWriter<W>`, returning the underlying writer. - /// - /// The buffer is written out before returning the writer. - /// - /// # Errors - /// - /// An [`Err`] will be returned if an error occurs while flushing the buffer. - /// - /// # Examples - /// - /// ```no_run - /// use std::io::BufWriter; - /// use std::net::TcpStream; - /// - /// let mut buffer = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap()); - /// - /// // unwrap the TcpStream and flush the buffer - /// let stream = buffer.into_inner().unwrap(); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn into_inner(mut self) -> Result<W, IntoInnerError<BufWriter<W>>> { - match self.flush_buf() { - Err(e) => Err(IntoInnerError(self, e)), - Ok(()) => Ok(self.inner.take().unwrap()), - } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<W: Write> Write for BufWriter<W> { - fn write(&mut self, buf: &[u8]) -> io::Result<usize> { - if self.buf.len() + buf.len() > self.buf.capacity() { - self.flush_buf()?; - } - // FIXME: Why no len > capacity? Why not buffer len == capacity? #72919 - if buf.len() >= self.buf.capacity() { - self.panicked = true; - let r = self.get_mut().write(buf); - self.panicked = false; - r - } else { - self.buf.extend_from_slice(buf); - Ok(buf.len()) - } - } - - fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { - // Normally, `write_all` just calls `write` in a loop. We can do better - // by calling `self.get_mut().write_all()` directly, which avoids - // round trips through the buffer in the event of a series of partial - // writes in some circumstances. - if self.buf.len() + buf.len() > self.buf.capacity() { - self.flush_buf()?; - } - // FIXME: Why no len > capacity? Why not buffer len == capacity? #72919 - if buf.len() >= self.buf.capacity() { - self.panicked = true; - let r = self.get_mut().write_all(buf); - self.panicked = false; - r - } else { - self.buf.extend_from_slice(buf); - Ok(()) - } - } - - fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> { - let total_len = bufs.iter().map(|b| b.len()).sum::<usize>(); - if self.buf.len() + total_len > self.buf.capacity() { - self.flush_buf()?; - } - // FIXME: Why no len > capacity? Why not buffer len == capacity? #72919 - if total_len >= self.buf.capacity() { - self.panicked = true; - let r = self.get_mut().write_vectored(bufs); - self.panicked = false; - r - } else { - bufs.iter().for_each(|b| self.buf.extend_from_slice(b)); - Ok(total_len) - } - } - - fn is_write_vectored(&self) -> bool { - self.get_ref().is_write_vectored() - } - - fn flush(&mut self) -> io::Result<()> { - self.flush_buf().and_then(|()| self.get_mut().flush()) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<W: Write> fmt::Debug for BufWriter<W> -where - W: fmt::Debug, -{ - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt.debug_struct("BufWriter") - .field("writer", &self.inner.as_ref().unwrap()) - .field("buffer", &format_args!("{}/{}", self.buf.len(), self.buf.capacity())) - .finish() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<W: Write + Seek> Seek for BufWriter<W> { - /// Seek to the offset, in bytes, in the underlying writer. - /// - /// Seeking always writes out the internal buffer before seeking. - fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> { - self.flush_buf()?; - self.get_mut().seek(pos) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<W: Write> Drop for BufWriter<W> { - fn drop(&mut self) { - if self.inner.is_some() && !self.panicked { - // dtors should not panic, so we ignore a failed flush - let _r = self.flush_buf(); - } - } -} - -impl<W> IntoInnerError<W> { - /// Returns the error which caused the call to [`BufWriter::into_inner()`] - /// to fail. - /// - /// This error was returned when attempting to write the internal buffer. - /// - /// # Examples - /// - /// ```no_run - /// use std::io::BufWriter; - /// use std::net::TcpStream; - /// - /// let mut stream = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap()); - /// - /// // do stuff with the stream - /// - /// // we want to get our `TcpStream` back, so let's try: - /// - /// let stream = match stream.into_inner() { - /// Ok(s) => s, - /// Err(e) => { - /// // Here, e is an IntoInnerError, let's log the inner error. - /// // - /// // We'll just 'log' to stdout for this example. - /// println!("{}", e.error()); - /// - /// panic!("An unexpected error occurred."); - /// } - /// }; - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn error(&self) -> &Error { - &self.1 - } - - /// Returns the buffered writer instance which generated the error. - /// - /// The returned object can be used for error recovery, such as - /// re-inspecting the buffer. - /// - /// # Examples - /// - /// ```no_run - /// use std::io::BufWriter; - /// use std::net::TcpStream; - /// - /// let mut stream = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap()); - /// - /// // do stuff with the stream - /// - /// // we want to get our `TcpStream` back, so let's try: - /// - /// let stream = match stream.into_inner() { - /// Ok(s) => s, - /// Err(e) => { - /// // Here, e is an IntoInnerError, let's re-examine the buffer: - /// let buffer = e.into_inner(); - /// - /// // do stuff to try to recover - /// - /// // afterwards, let's just return the stream - /// buffer.into_inner().unwrap() - /// } - /// }; - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn into_inner(self) -> W { - self.0 - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<W> From<IntoInnerError<W>> for Error { - fn from(iie: IntoInnerError<W>) -> Error { - iie.1 - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<W: Send + fmt::Debug> error::Error for IntoInnerError<W> { - #[allow(deprecated, deprecated_in_future)] - fn description(&self) -> &str { - error::Error::description(self.error()) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<W> fmt::Display for IntoInnerError<W> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.error().fmt(f) - } -} - -/// Private helper struct for implementing the line-buffered writing logic. -/// This shim temporarily wraps a BufWriter, and uses its internals to -/// implement a line-buffered writer (specifically by using the internal -/// methods like write_to_buf and flush_buf). In this way, a more -/// efficient abstraction can be created than one that only had access to -/// `write` and `flush`, without needlessly duplicating a lot of the -/// implementation details of BufWriter. This also allows existing -/// `BufWriters` to be temporarily given line-buffering logic; this is what -/// enables Stdout to be alternately in line-buffered or block-buffered mode. -#[derive(Debug)] -pub(super) struct LineWriterShim<'a, W: Write> { - buffer: &'a mut BufWriter<W>, -} - -impl<'a, W: Write> LineWriterShim<'a, W> { - pub fn new(buffer: &'a mut BufWriter<W>) -> Self { - Self { buffer } - } - - /// Get a mutable reference to the inner writer (that is, the writer - /// wrapped by the BufWriter). Be careful with this writer, as writes to - /// it will bypass the buffer. - fn inner_mut(&mut self) -> &mut W { - self.buffer.get_mut() - } - - /// Get the content currently buffered in self.buffer - fn buffered(&self) -> &[u8] { - self.buffer.buffer() - } - - /// Flush the buffer iff the last byte is a newline (indicating that an - /// earlier write only succeeded partially, and we want to retry flushing - /// the buffered line before continuing with a subsequent write) - fn flush_if_completed_line(&mut self) -> io::Result<()> { - match self.buffered().last().copied() { - Some(b'\n') => self.buffer.flush_buf(), - _ => Ok(()), - } - } -} - -impl<'a, W: Write> Write for LineWriterShim<'a, W> { - /// Write some data into this BufReader with line buffering. This means - /// that, if any newlines are present in the data, the data up to the last - /// newline is sent directly to the underlying writer, and data after it - /// is buffered. Returns the number of bytes written. - /// - /// This function operates on a "best effort basis"; in keeping with the - /// convention of `Write::write`, it makes at most one attempt to write - /// new data to the underlying writer. If that write only reports a partial - /// success, the remaining data will be buffered. - /// - /// Because this function attempts to send completed lines to the underlying - /// writer, it will also flush the existing buffer if it ends with a - /// newline, even if the incoming data does not contain any newlines. - fn write(&mut self, buf: &[u8]) -> io::Result<usize> { - let newline_idx = match memchr::memrchr(b'\n', buf) { - // If there are no new newlines (that is, if this write is less than - // one line), just do a regular buffered write (which may flush if - // we exceed the inner buffer's size) - None => { - self.flush_if_completed_line()?; - return self.buffer.write(buf); - } - // Otherwise, arrange for the lines to be written directly to the - // inner writer. - Some(newline_idx) => newline_idx + 1, - }; - - // Flush existing content to prepare for our write. We have to do this - // before attempting to write `buf` in order to maintain consistency; - // if we add `buf` to the buffer then try to flush it all at once, - // we're obligated to return Ok(), which would mean suppressing any - // errors that occur during flush. - self.buffer.flush_buf()?; - - // This is what we're going to try to write directly to the inner - // writer. The rest will be buffered, if nothing goes wrong. - let lines = &buf[..newline_idx]; - - // Write `lines` directly to the inner writer. In keeping with the - // `write` convention, make at most one attempt to add new (unbuffered) - // data. Because this write doesn't touch the BufWriter state directly, - // and the buffer is known to be empty, we don't need to worry about - // self.buffer.panicked here. - let flushed = self.inner_mut().write(lines)?; - - // If buffer returns Ok(0), propagate that to the caller without - // doing additional buffering; otherwise we're just guaranteeing - // an "ErrorKind::WriteZero" later. - if flushed == 0 { - return Ok(0); - } - - // Now that the write has succeeded, buffer the rest (or as much of - // the rest as possible). If there were any unwritten newlines, we - // only buffer out to the last unwritten newline that fits in the - // buffer; this helps prevent flushing partial lines on subsequent - // calls to LineWriterShim::write. - - // Handle the cases in order of most-common to least-common, under - // the presumption that most writes succeed in totality, and that most - // writes are smaller than the buffer. - // - Is this a partial line (ie, no newlines left in the unwritten tail) - // - If not, does the data out to the last unwritten newline fit in - // the buffer? - // - If not, scan for the last newline that *does* fit in the buffer - let tail = if flushed >= newline_idx { - &buf[flushed..] - } else if newline_idx - flushed <= self.buffer.capacity() { - &buf[flushed..newline_idx] - } else { - let scan_area = &buf[flushed..]; - let scan_area = &scan_area[..self.buffer.capacity()]; - match memchr::memrchr(b'\n', scan_area) { - Some(newline_idx) => &scan_area[..newline_idx + 1], - None => scan_area, - } - }; - - let buffered = self.buffer.write_to_buf(tail); - Ok(flushed + buffered) - } - - fn flush(&mut self) -> io::Result<()> { - self.buffer.flush() - } - - /// Write some vectored data into this BufReader with line buffering. This - /// means that, if any newlines are present in the data, the data up to - /// and including the buffer containing the last newline is sent directly - /// to the inner writer, and the data after it is buffered. Returns the - /// number of bytes written. - /// - /// This function operates on a "best effort basis"; in keeping with the - /// convention of `Write::write`, it makes at most one attempt to write - /// new data to the underlying writer. - /// - /// Because this function attempts to send completed lines to the underlying - /// writer, it will also flush the existing buffer if it contains any - /// newlines. - /// - /// Because sorting through an array of `IoSlice` can be a bit convoluted, - /// This method differs from write in the following ways: - /// - /// - It attempts to write the full content of all the buffers up to and - /// including the one containing the last newline. This means that it - /// may attempt to write a partial line, that buffer has data past the - /// newline. - /// - If the write only reports partial success, it does not attempt to - /// find the precise location of the written bytes and buffer the rest. - /// - /// If the underlying vector doesn't support vectored writing, we instead - /// simply write the first non-empty buffer with `write`. This way, we - /// get the benefits of more granular partial-line handling without losing - /// anything in efficiency - fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> { - // If there's no specialized behavior for write_vectored, just use - // write. This has the benefit of more granular partial-line handling. - if !self.is_write_vectored() { - return match bufs.iter().find(|buf| !buf.is_empty()) { - Some(buf) => self.write(buf), - None => Ok(0), - }; - } - - // Find the buffer containing the last newline - let last_newline_buf_idx = bufs - .iter() - .enumerate() - .rev() - .find_map(|(i, buf)| memchr::memchr(b'\n', buf).map(|_| i)); - - // If there are no new newlines (that is, if this write is less than - // one line), just do a regular buffered write - let last_newline_buf_idx = match last_newline_buf_idx { - // No newlines; just do a normal buffered write - None => { - self.flush_if_completed_line()?; - return self.buffer.write_vectored(bufs); - } - Some(i) => i, - }; - - // Flush existing content to prepare for our write - self.buffer.flush_buf()?; - - // This is what we're going to try to write directly to the inner - // writer. The rest will be buffered, if nothing goes wrong. - let (lines, tail) = bufs.split_at(last_newline_buf_idx + 1); - - // Write `lines` directly to the inner writer. In keeping with the - // `write` convention, make at most one attempt to add new (unbuffered) - // data. Because this write doesn't touch the BufWriter state directly, - // and the buffer is known to be empty, we don't need to worry about - // self.panicked here. - let flushed = self.inner_mut().write_vectored(lines)?; - - // If inner returns Ok(0), propagate that to the caller without - // doing additional buffering; otherwise we're just guaranteeing - // an "ErrorKind::WriteZero" later. - if flushed == 0 { - return Ok(0); - } - - // Don't try to reconstruct the exact amount written; just bail - // in the event of a partial write - let lines_len = lines.iter().map(|buf| buf.len()).sum(); - if flushed < lines_len { - return Ok(flushed); - } - - // Now that the write has succeeded, buffer the rest (or as much of the - // rest as possible) - let buffered: usize = tail - .iter() - .filter(|buf| !buf.is_empty()) - .map(|buf| self.buffer.write_to_buf(buf)) - .take_while(|&n| n > 0) - .sum(); - - Ok(flushed + buffered) - } - - fn is_write_vectored(&self) -> bool { - self.buffer.is_write_vectored() - } - - /// Write some data into this BufReader with line buffering. This means - /// that, if any newlines are present in the data, the data up to the last - /// newline is sent directly to the underlying writer, and data after it - /// is buffered. - /// - /// Because this function attempts to send completed lines to the underlying - /// writer, it will also flush the existing buffer if it contains any - /// newlines, even if the incoming data does not contain any newlines. - fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { - match memchr::memrchr(b'\n', buf) { - // If there are no new newlines (that is, if this write is less than - // one line), just do a regular buffered write (which may flush if - // we exceed the inner buffer's size) - None => { - self.flush_if_completed_line()?; - self.buffer.write_all(buf) - } - Some(newline_idx) => { - let (lines, tail) = buf.split_at(newline_idx + 1); - - if self.buffered().is_empty() { - self.inner_mut().write_all(lines)?; - } else { - // If there is any buffered data, we add the incoming lines - // to that buffer before flushing, which saves us at least - // one write call. We can't really do this with `write`, - // since we can't do this *and* not suppress errors *and* - // report a consistent state to the caller in a return - // value, but here in write_all it's fine. - self.buffer.write_all(lines)?; - self.buffer.flush_buf()?; - } - - self.buffer.write_all(tail) - } - } - } -} - -/// Wraps a writer and buffers output to it, flushing whenever a newline -/// (`0x0a`, `'\n'`) is detected. -/// -/// The [`BufWriter`] struct wraps a writer and buffers its output. -/// But it only does this batched write when it goes out of scope, or when the -/// internal buffer is full. Sometimes, you'd prefer to write each line as it's -/// completed, rather than the entire buffer at once. Enter `LineWriter`. It -/// does exactly that. -/// -/// Like [`BufWriter`], a `LineWriter`’s buffer will also be flushed when the -/// `LineWriter` goes out of scope or when its internal buffer is full. -/// -/// If there's still a partial line in the buffer when the `LineWriter` is -/// dropped, it will flush those contents. -/// -/// # Examples -/// -/// We can use `LineWriter` to write one line at a time, significantly -/// reducing the number of actual writes to the file. -/// -/// ```no_run -/// use std::fs::{self, File}; -/// use std::io::prelude::*; -/// use std::io::LineWriter; -/// -/// fn main() -> std::io::Result<()> { -/// let road_not_taken = b"I shall be telling this with a sigh -/// Somewhere ages and ages hence: -/// Two roads diverged in a wood, and I - -/// I took the one less traveled by, -/// And that has made all the difference."; -/// -/// let file = File::create("poem.txt")?; -/// let mut file = LineWriter::new(file); -/// -/// file.write_all(b"I shall be telling this with a sigh")?; -/// -/// // No bytes are written until a newline is encountered (or -/// // the internal buffer is filled). -/// assert_eq!(fs::read_to_string("poem.txt")?, ""); -/// file.write_all(b"\n")?; -/// assert_eq!( -/// fs::read_to_string("poem.txt")?, -/// "I shall be telling this with a sigh\n", -/// ); -/// -/// // Write the rest of the poem. -/// file.write_all(b"Somewhere ages and ages hence: -/// Two roads diverged in a wood, and I - -/// I took the one less traveled by, -/// And that has made all the difference.")?; -/// -/// // The last line of the poem doesn't end in a newline, so -/// // we have to flush or drop the `LineWriter` to finish -/// // writing. -/// file.flush()?; -/// -/// // Confirm the whole poem was written. -/// assert_eq!(fs::read("poem.txt")?, &road_not_taken[..]); -/// Ok(()) -/// } -/// ``` -#[stable(feature = "rust1", since = "1.0.0")] -pub struct LineWriter<W: Write> { - inner: BufWriter<W>, -} - -impl<W: Write> LineWriter<W> { - /// Creates a new `LineWriter`. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs::File; - /// use std::io::LineWriter; - /// - /// fn main() -> std::io::Result<()> { - /// let file = File::create("poem.txt")?; - /// let file = LineWriter::new(file); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn new(inner: W) -> LineWriter<W> { - // Lines typically aren't that long, don't use a giant buffer - LineWriter::with_capacity(1024, inner) - } - - /// Creates a new `LineWriter` with a specified capacity for the internal - /// buffer. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs::File; - /// use std::io::LineWriter; - /// - /// fn main() -> std::io::Result<()> { - /// let file = File::create("poem.txt")?; - /// let file = LineWriter::with_capacity(100, file); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn with_capacity(capacity: usize, inner: W) -> LineWriter<W> { - LineWriter { inner: BufWriter::with_capacity(capacity, inner) } - } - - /// Gets a reference to the underlying writer. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs::File; - /// use std::io::LineWriter; - /// - /// fn main() -> std::io::Result<()> { - /// let file = File::create("poem.txt")?; - /// let file = LineWriter::new(file); - /// - /// let reference = file.get_ref(); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn get_ref(&self) -> &W { - self.inner.get_ref() - } - - /// Gets a mutable reference to the underlying writer. - /// - /// Caution must be taken when calling methods on the mutable reference - /// returned as extra writes could corrupt the output stream. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs::File; - /// use std::io::LineWriter; - /// - /// fn main() -> std::io::Result<()> { - /// let file = File::create("poem.txt")?; - /// let mut file = LineWriter::new(file); - /// - /// // we can use reference just like file - /// let reference = file.get_mut(); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn get_mut(&mut self) -> &mut W { - self.inner.get_mut() - } - - /// Unwraps this `LineWriter`, returning the underlying writer. - /// - /// The internal buffer is written out before returning the writer. - /// - /// # Errors - /// - /// An [`Err`] will be returned if an error occurs while flushing the buffer. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs::File; - /// use std::io::LineWriter; - /// - /// fn main() -> std::io::Result<()> { - /// let file = File::create("poem.txt")?; - /// - /// let writer: LineWriter<File> = LineWriter::new(file); - /// - /// let file: File = writer.into_inner()?; - /// Ok(()) - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn into_inner(self) -> Result<W, IntoInnerError<LineWriter<W>>> { - self.inner - .into_inner() - .map_err(|IntoInnerError(buf, e)| IntoInnerError(LineWriter { inner: buf }, e)) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<W: Write> Write for LineWriter<W> { - fn write(&mut self, buf: &[u8]) -> io::Result<usize> { - LineWriterShim::new(&mut self.inner).write(buf) - } - - fn flush(&mut self) -> io::Result<()> { - self.inner.flush() - } - - fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> { - LineWriterShim::new(&mut self.inner).write_vectored(bufs) - } - - fn is_write_vectored(&self) -> bool { - self.inner.is_write_vectored() - } - - fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { - LineWriterShim::new(&mut self.inner).write_all(buf) - } - - fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> { - LineWriterShim::new(&mut self.inner).write_all_vectored(bufs) - } - - fn write_fmt(&mut self, fmt: fmt::Arguments<'_>) -> io::Result<()> { - LineWriterShim::new(&mut self.inner).write_fmt(fmt) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<W: Write> fmt::Debug for LineWriter<W> -where - W: fmt::Debug, -{ - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt.debug_struct("LineWriter") - .field("writer", &self.inner.inner) - .field( - "buffer", - &format_args!("{}/{}", self.inner.buf.len(), self.inner.buf.capacity()), - ) - .finish() - } -} diff --git a/library/std/src/io/buffered/bufreader.rs b/library/std/src/io/buffered/bufreader.rs new file mode 100644 index 00000000000..8fe29f08a7b --- /dev/null +++ b/library/std/src/io/buffered/bufreader.rs @@ -0,0 +1,423 @@ +use crate::cmp; +use crate::fmt; +use crate::io::{self, BufRead, Initializer, IoSliceMut, Read, Seek, SeekFrom, DEFAULT_BUF_SIZE}; + +/// The `BufReader<R>` struct adds buffering to any reader. +/// +/// It can be excessively inefficient to work directly with a [`Read`] instance. +/// For example, every call to [`read`][`TcpStream::read`] on [`TcpStream`] +/// results in a system call. A `BufReader<R>` performs large, infrequent reads on +/// the underlying [`Read`] and maintains an in-memory buffer of the results. +/// +/// `BufReader<R>` can improve the speed of programs that make *small* and +/// *repeated* read calls to the same file or network socket. It does not +/// help when reading very large amounts at once, or reading just one or a few +/// times. It also provides no advantage when reading from a source that is +/// already in memory, like a [`Vec`]`<u8>`. +/// +/// When the `BufReader<R>` is dropped, the contents of its buffer will be +/// discarded. Creating multiple instances of a `BufReader<R>` on the same +/// stream can cause data loss. Reading from the underlying reader after +/// unwrapping the `BufReader<R>` with [`BufReader::into_inner`] can also cause +/// data loss. +/// +/// [`TcpStream::read`]: Read::read +/// [`TcpStream`]: crate::net::TcpStream +/// +/// # Examples +/// +/// ```no_run +/// use std::io::prelude::*; +/// use std::io::BufReader; +/// use std::fs::File; +/// +/// fn main() -> std::io::Result<()> { +/// let f = File::open("log.txt")?; +/// let mut reader = BufReader::new(f); +/// +/// let mut line = String::new(); +/// let len = reader.read_line(&mut line)?; +/// println!("First line is {} bytes long", len); +/// Ok(()) +/// } +/// ``` +#[stable(feature = "rust1", since = "1.0.0")] +pub struct BufReader<R> { + inner: R, + buf: Box<[u8]>, + pos: usize, + cap: usize, +} + +impl<R: Read> BufReader<R> { + /// Creates a new `BufReader<R>` with a default buffer capacity. The default is currently 8 KB, + /// but may change in the future. + /// + /// # Examples + /// + /// ```no_run + /// use std::io::BufReader; + /// use std::fs::File; + /// + /// fn main() -> std::io::Result<()> { + /// let f = File::open("log.txt")?; + /// let reader = BufReader::new(f); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn new(inner: R) -> BufReader<R> { + BufReader::with_capacity(DEFAULT_BUF_SIZE, inner) + } + + /// Creates a new `BufReader<R>` with the specified buffer capacity. + /// + /// # Examples + /// + /// Creating a buffer with ten bytes of capacity: + /// + /// ```no_run + /// use std::io::BufReader; + /// use std::fs::File; + /// + /// fn main() -> std::io::Result<()> { + /// let f = File::open("log.txt")?; + /// let reader = BufReader::with_capacity(10, f); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn with_capacity(capacity: usize, inner: R) -> BufReader<R> { + unsafe { + let mut buffer = Vec::with_capacity(capacity); + buffer.set_len(capacity); + inner.initializer().initialize(&mut buffer); + BufReader { inner, buf: buffer.into_boxed_slice(), pos: 0, cap: 0 } + } + } +} + +impl<R> BufReader<R> { + /// Gets a reference to the underlying reader. + /// + /// It is inadvisable to directly read from the underlying reader. + /// + /// # Examples + /// + /// ```no_run + /// use std::io::BufReader; + /// use std::fs::File; + /// + /// fn main() -> std::io::Result<()> { + /// let f1 = File::open("log.txt")?; + /// let reader = BufReader::new(f1); + /// + /// let f2 = reader.get_ref(); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn get_ref(&self) -> &R { + &self.inner + } + + /// Gets a mutable reference to the underlying reader. + /// + /// It is inadvisable to directly read from the underlying reader. + /// + /// # Examples + /// + /// ```no_run + /// use std::io::BufReader; + /// use std::fs::File; + /// + /// fn main() -> std::io::Result<()> { + /// let f1 = File::open("log.txt")?; + /// let mut reader = BufReader::new(f1); + /// + /// let f2 = reader.get_mut(); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn get_mut(&mut self) -> &mut R { + &mut self.inner + } + + /// Returns a reference to the internally buffered data. + /// + /// Unlike [`fill_buf`], this will not attempt to fill the buffer if it is empty. + /// + /// [`fill_buf`]: BufRead::fill_buf + /// + /// # Examples + /// + /// ```no_run + /// use std::io::{BufReader, BufRead}; + /// use std::fs::File; + /// + /// fn main() -> std::io::Result<()> { + /// let f = File::open("log.txt")?; + /// let mut reader = BufReader::new(f); + /// assert!(reader.buffer().is_empty()); + /// + /// if reader.fill_buf()?.len() > 0 { + /// assert!(!reader.buffer().is_empty()); + /// } + /// Ok(()) + /// } + /// ``` + #[stable(feature = "bufreader_buffer", since = "1.37.0")] + pub fn buffer(&self) -> &[u8] { + &self.buf[self.pos..self.cap] + } + + /// Returns the number of bytes the internal buffer can hold at once. + /// + /// # Examples + /// + /// ```no_run + /// use std::io::{BufReader, BufRead}; + /// use std::fs::File; + /// + /// fn main() -> std::io::Result<()> { + /// let f = File::open("log.txt")?; + /// let mut reader = BufReader::new(f); + /// + /// let capacity = reader.capacity(); + /// let buffer = reader.fill_buf()?; + /// assert!(buffer.len() <= capacity); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "buffered_io_capacity", since = "1.46.0")] + pub fn capacity(&self) -> usize { + self.buf.len() + } + + /// Unwraps this `BufReader<R>`, returning the underlying reader. + /// + /// Note that any leftover data in the internal buffer is lost. Therefore, + /// a following read from the underlying reader may lead to data loss. + /// + /// # Examples + /// + /// ```no_run + /// use std::io::BufReader; + /// use std::fs::File; + /// + /// fn main() -> std::io::Result<()> { + /// let f1 = File::open("log.txt")?; + /// let reader = BufReader::new(f1); + /// + /// let f2 = reader.into_inner(); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn into_inner(self) -> R { + self.inner + } + + /// Invalidates all data in the internal buffer. + #[inline] + fn discard_buffer(&mut self) { + self.pos = 0; + self.cap = 0; + } +} + +impl<R: Seek> BufReader<R> { + /// Seeks relative to the current position. If the new position lies within the buffer, + /// the buffer will not be flushed, allowing for more efficient seeks. + /// This method does not return the location of the underlying reader, so the caller + /// must track this information themselves if it is required. + #[unstable(feature = "bufreader_seek_relative", issue = "31100")] + pub fn seek_relative(&mut self, offset: i64) -> io::Result<()> { + let pos = self.pos as u64; + if offset < 0 { + if let Some(new_pos) = pos.checked_sub((-offset) as u64) { + self.pos = new_pos as usize; + return Ok(()); + } + } else { + if let Some(new_pos) = pos.checked_add(offset as u64) { + if new_pos <= self.cap as u64 { + self.pos = new_pos as usize; + return Ok(()); + } + } + } + self.seek(SeekFrom::Current(offset)).map(drop) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<R: Read> Read for BufReader<R> { + fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { + // If we don't have any buffered data and we're doing a massive read + // (larger than our internal buffer), bypass our internal buffer + // entirely. + if self.pos == self.cap && buf.len() >= self.buf.len() { + self.discard_buffer(); + return self.inner.read(buf); + } + let nread = { + let mut rem = self.fill_buf()?; + rem.read(buf)? + }; + self.consume(nread); + Ok(nread) + } + + fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> { + let total_len = bufs.iter().map(|b| b.len()).sum::<usize>(); + if self.pos == self.cap && total_len >= self.buf.len() { + self.discard_buffer(); + return self.inner.read_vectored(bufs); + } + let nread = { + let mut rem = self.fill_buf()?; + rem.read_vectored(bufs)? + }; + self.consume(nread); + Ok(nread) + } + + fn is_read_vectored(&self) -> bool { + self.inner.is_read_vectored() + } + + // we can't skip unconditionally because of the large buffer case in read. + unsafe fn initializer(&self) -> Initializer { + self.inner.initializer() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<R: Read> BufRead for BufReader<R> { + fn fill_buf(&mut self) -> io::Result<&[u8]> { + // If we've reached the end of our internal buffer then we need to fetch + // some more data from the underlying reader. + // Branch using `>=` instead of the more correct `==` + // to tell the compiler that the pos..cap slice is always valid. + if self.pos >= self.cap { + debug_assert!(self.pos == self.cap); + self.cap = self.inner.read(&mut self.buf)?; + self.pos = 0; + } + Ok(&self.buf[self.pos..self.cap]) + } + + fn consume(&mut self, amt: usize) { + self.pos = cmp::min(self.pos + amt, self.cap); + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<R> fmt::Debug for BufReader<R> +where + R: fmt::Debug, +{ + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_struct("BufReader") + .field("reader", &self.inner) + .field("buffer", &format_args!("{}/{}", self.cap - self.pos, self.buf.len())) + .finish() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<R: Seek> Seek for BufReader<R> { + /// Seek to an offset, in bytes, in the underlying reader. + /// + /// The position used for seeking with [`SeekFrom::Current`]`(_)` is the + /// position the underlying reader would be at if the `BufReader<R>` had no + /// internal buffer. + /// + /// Seeking always discards the internal buffer, even if the seek position + /// would otherwise fall within it. This guarantees that calling + /// [`BufReader::into_inner()`] immediately after a seek yields the underlying reader + /// at the same position. + /// + /// To seek without discarding the internal buffer, use [`BufReader::seek_relative`]. + /// + /// See [`std::io::Seek`] for more details. + /// + /// Note: In the edge case where you're seeking with [`SeekFrom::Current`]`(n)` + /// where `n` minus the internal buffer length overflows an `i64`, two + /// seeks will be performed instead of one. If the second seek returns + /// [`Err`], the underlying reader will be left at the same position it would + /// have if you called `seek` with [`SeekFrom::Current`]`(0)`. + /// + /// [`std::io::Seek`]: Seek + fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> { + let result: u64; + if let SeekFrom::Current(n) = pos { + let remainder = (self.cap - self.pos) as i64; + // it should be safe to assume that remainder fits within an i64 as the alternative + // means we managed to allocate 8 exbibytes and that's absurd. + // But it's not out of the realm of possibility for some weird underlying reader to + // support seeking by i64::MIN so we need to handle underflow when subtracting + // remainder. + if let Some(offset) = n.checked_sub(remainder) { + result = self.inner.seek(SeekFrom::Current(offset))?; + } else { + // seek backwards by our remainder, and then by the offset + self.inner.seek(SeekFrom::Current(-remainder))?; + self.discard_buffer(); + result = self.inner.seek(SeekFrom::Current(n))?; + } + } else { + // Seeking with Start/End doesn't care about our buffer length. + result = self.inner.seek(pos)?; + } + self.discard_buffer(); + Ok(result) + } + + /// Returns the current seek position from the start of the stream. + /// + /// The value returned is equivalent to `self.seek(SeekFrom::Current(0))` + /// but does not flush the internal buffer. Due to this optimization the + /// function does not guarantee that calling `.into_inner()` immediately + /// afterwards will yield the underlying reader at the same position. Use + /// [`BufReader::seek`] instead if you require that guarantee. + /// + /// # Panics + /// + /// This function will panic if the position of the inner reader is smaller + /// than the amount of buffered data. That can happen if the inner reader + /// has an incorrect implementation of [`Seek::stream_position`], or if the + /// position has gone out of sync due to calling [`Seek::seek`] directly on + /// the underlying reader. + /// + /// # Example + /// + /// ```no_run + /// #![feature(seek_convenience)] + /// use std::{ + /// io::{self, BufRead, BufReader, Seek}, + /// fs::File, + /// }; + /// + /// fn main() -> io::Result<()> { + /// let mut f = BufReader::new(File::open("foo.txt")?); + /// + /// let before = f.stream_position()?; + /// f.read_line(&mut String::new())?; + /// let after = f.stream_position()?; + /// + /// println!("The first line was {} bytes long", after - before); + /// Ok(()) + /// } + /// ``` + fn stream_position(&mut self) -> io::Result<u64> { + let remainder = (self.cap - self.pos) as u64; + self.inner.stream_position().map(|pos| { + pos.checked_sub(remainder).expect( + "overflow when subtracting remaining buffer size from inner stream position", + ) + }) + } +} diff --git a/library/std/src/io/buffered/bufwriter.rs b/library/std/src/io/buffered/bufwriter.rs new file mode 100644 index 00000000000..8ce795a05ed --- /dev/null +++ b/library/std/src/io/buffered/bufwriter.rs @@ -0,0 +1,387 @@ +use crate::fmt; +use crate::io::{ + self, Error, ErrorKind, IntoInnerError, IoSlice, Seek, SeekFrom, Write, DEFAULT_BUF_SIZE, +}; + +/// Wraps a writer and buffers its output. +/// +/// It can be excessively inefficient to work directly with something that +/// implements [`Write`]. For example, every call to +/// [`write`][`TcpStream::write`] on [`TcpStream`] results in a system call. A +/// `BufWriter<W>` keeps an in-memory buffer of data and writes it to an underlying +/// writer in large, infrequent batches. +/// +/// `BufWriter<W>` can improve the speed of programs that make *small* and +/// *repeated* write calls to the same file or network socket. It does not +/// help when writing very large amounts at once, or writing just one or a few +/// times. It also provides no advantage when writing to a destination that is +/// in memory, like a [`Vec`]<u8>`. +/// +/// It is critical to call [`flush`] before `BufWriter<W>` is dropped. Though +/// dropping will attempt to flush the contents of the buffer, any errors +/// that happen in the process of dropping will be ignored. Calling [`flush`] +/// ensures that the buffer is empty and thus dropping will not even attempt +/// file operations. +/// +/// # Examples +/// +/// Let's write the numbers one through ten to a [`TcpStream`]: +/// +/// ```no_run +/// use std::io::prelude::*; +/// use std::net::TcpStream; +/// +/// let mut stream = TcpStream::connect("127.0.0.1:34254").unwrap(); +/// +/// for i in 0..10 { +/// stream.write(&[i+1]).unwrap(); +/// } +/// ``` +/// +/// Because we're not buffering, we write each one in turn, incurring the +/// overhead of a system call per byte written. We can fix this with a +/// `BufWriter<W>`: +/// +/// ```no_run +/// use std::io::prelude::*; +/// use std::io::BufWriter; +/// use std::net::TcpStream; +/// +/// let mut stream = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap()); +/// +/// for i in 0..10 { +/// stream.write(&[i+1]).unwrap(); +/// } +/// stream.flush().unwrap(); +/// ``` +/// +/// By wrapping the stream with a `BufWriter<W>`, these ten writes are all grouped +/// together by the buffer and will all be written out in one system call when +/// the `stream` is flushed. +/// +/// [`TcpStream::write`]: Write::write +/// [`TcpStream`]: crate::net::TcpStream +/// [`flush`]: Write::flush +#[stable(feature = "rust1", since = "1.0.0")] +pub struct BufWriter<W: Write> { + inner: Option<W>, + buf: Vec<u8>, + // #30888: If the inner writer panics in a call to write, we don't want to + // write the buffered data a second time in BufWriter's destructor. This + // flag tells the Drop impl if it should skip the flush. + panicked: bool, +} + +impl<W: Write> BufWriter<W> { + /// Creates a new `BufWriter<W>` with a default buffer capacity. The default is currently 8 KB, + /// but may change in the future. + /// + /// # Examples + /// + /// ```no_run + /// use std::io::BufWriter; + /// use std::net::TcpStream; + /// + /// let mut buffer = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn new(inner: W) -> BufWriter<W> { + BufWriter::with_capacity(DEFAULT_BUF_SIZE, inner) + } + + /// Creates a new `BufWriter<W>` with the specified buffer capacity. + /// + /// # Examples + /// + /// Creating a buffer with a buffer of a hundred bytes. + /// + /// ```no_run + /// use std::io::BufWriter; + /// use std::net::TcpStream; + /// + /// let stream = TcpStream::connect("127.0.0.1:34254").unwrap(); + /// let mut buffer = BufWriter::with_capacity(100, stream); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn with_capacity(capacity: usize, inner: W) -> BufWriter<W> { + BufWriter { inner: Some(inner), buf: Vec::with_capacity(capacity), panicked: false } + } + + /// Send data in our local buffer into the inner writer, looping as + /// necessary until either it's all been sent or an error occurs. + /// + /// Because all the data in the buffer has been reported to our owner as + /// "successfully written" (by returning nonzero success values from + /// `write`), any 0-length writes from `inner` must be reported as i/o + /// errors from this method. + pub(super) fn flush_buf(&mut self) -> io::Result<()> { + /// Helper struct to ensure the buffer is updated after all the writes + /// are complete. It tracks the number of written bytes and drains them + /// all from the front of the buffer when dropped. + struct BufGuard<'a> { + buffer: &'a mut Vec<u8>, + written: usize, + } + + impl<'a> BufGuard<'a> { + fn new(buffer: &'a mut Vec<u8>) -> Self { + Self { buffer, written: 0 } + } + + /// The unwritten part of the buffer + fn remaining(&self) -> &[u8] { + &self.buffer[self.written..] + } + + /// Flag some bytes as removed from the front of the buffer + fn consume(&mut self, amt: usize) { + self.written += amt; + } + + /// true if all of the bytes have been written + fn done(&self) -> bool { + self.written >= self.buffer.len() + } + } + + impl Drop for BufGuard<'_> { + fn drop(&mut self) { + if self.written > 0 { + self.buffer.drain(..self.written); + } + } + } + + let mut guard = BufGuard::new(&mut self.buf); + let inner = self.inner.as_mut().unwrap(); + while !guard.done() { + self.panicked = true; + let r = inner.write(guard.remaining()); + self.panicked = false; + + match r { + Ok(0) => { + return Err(Error::new( + ErrorKind::WriteZero, + "failed to write the buffered data", + )); + } + Ok(n) => guard.consume(n), + Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {} + Err(e) => return Err(e), + } + } + Ok(()) + } + + /// Buffer some data without flushing it, regardless of the size of the + /// data. Writes as much as possible without exceeding capacity. Returns + /// the number of bytes written. + pub(super) fn write_to_buf(&mut self, buf: &[u8]) -> usize { + let available = self.buf.capacity() - self.buf.len(); + let amt_to_buffer = available.min(buf.len()); + self.buf.extend_from_slice(&buf[..amt_to_buffer]); + amt_to_buffer + } + + /// Gets a reference to the underlying writer. + /// + /// # Examples + /// + /// ```no_run + /// use std::io::BufWriter; + /// use std::net::TcpStream; + /// + /// let mut buffer = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap()); + /// + /// // we can use reference just like buffer + /// let reference = buffer.get_ref(); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn get_ref(&self) -> &W { + self.inner.as_ref().unwrap() + } + + /// Gets a mutable reference to the underlying writer. + /// + /// It is inadvisable to directly write to the underlying writer. + /// + /// # Examples + /// + /// ```no_run + /// use std::io::BufWriter; + /// use std::net::TcpStream; + /// + /// let mut buffer = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap()); + /// + /// // we can use reference just like buffer + /// let reference = buffer.get_mut(); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn get_mut(&mut self) -> &mut W { + self.inner.as_mut().unwrap() + } + + /// Returns a reference to the internally buffered data. + /// + /// # Examples + /// + /// ```no_run + /// use std::io::BufWriter; + /// use std::net::TcpStream; + /// + /// let buf_writer = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap()); + /// + /// // See how many bytes are currently buffered + /// let bytes_buffered = buf_writer.buffer().len(); + /// ``` + #[stable(feature = "bufreader_buffer", since = "1.37.0")] + pub fn buffer(&self) -> &[u8] { + &self.buf + } + + /// Returns the number of bytes the internal buffer can hold without flushing. + /// + /// # Examples + /// + /// ```no_run + /// use std::io::BufWriter; + /// use std::net::TcpStream; + /// + /// let buf_writer = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap()); + /// + /// // Check the capacity of the inner buffer + /// let capacity = buf_writer.capacity(); + /// // Calculate how many bytes can be written without flushing + /// let without_flush = capacity - buf_writer.buffer().len(); + /// ``` + #[stable(feature = "buffered_io_capacity", since = "1.46.0")] + pub fn capacity(&self) -> usize { + self.buf.capacity() + } + + /// Unwraps this `BufWriter<W>`, returning the underlying writer. + /// + /// The buffer is written out before returning the writer. + /// + /// # Errors + /// + /// An [`Err`] will be returned if an error occurs while flushing the buffer. + /// + /// # Examples + /// + /// ```no_run + /// use std::io::BufWriter; + /// use std::net::TcpStream; + /// + /// let mut buffer = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap()); + /// + /// // unwrap the TcpStream and flush the buffer + /// let stream = buffer.into_inner().unwrap(); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn into_inner(mut self) -> Result<W, IntoInnerError<BufWriter<W>>> { + match self.flush_buf() { + Err(e) => Err(IntoInnerError::new(self, e)), + Ok(()) => Ok(self.inner.take().unwrap()), + } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<W: Write> Write for BufWriter<W> { + fn write(&mut self, buf: &[u8]) -> io::Result<usize> { + if self.buf.len() + buf.len() > self.buf.capacity() { + self.flush_buf()?; + } + // FIXME: Why no len > capacity? Why not buffer len == capacity? #72919 + if buf.len() >= self.buf.capacity() { + self.panicked = true; + let r = self.get_mut().write(buf); + self.panicked = false; + r + } else { + self.buf.extend_from_slice(buf); + Ok(buf.len()) + } + } + + fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { + // Normally, `write_all` just calls `write` in a loop. We can do better + // by calling `self.get_mut().write_all()` directly, which avoids + // round trips through the buffer in the event of a series of partial + // writes in some circumstances. + if self.buf.len() + buf.len() > self.buf.capacity() { + self.flush_buf()?; + } + // FIXME: Why no len > capacity? Why not buffer len == capacity? #72919 + if buf.len() >= self.buf.capacity() { + self.panicked = true; + let r = self.get_mut().write_all(buf); + self.panicked = false; + r + } else { + self.buf.extend_from_slice(buf); + Ok(()) + } + } + + fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> { + let total_len = bufs.iter().map(|b| b.len()).sum::<usize>(); + if self.buf.len() + total_len > self.buf.capacity() { + self.flush_buf()?; + } + // FIXME: Why no len > capacity? Why not buffer len == capacity? #72919 + if total_len >= self.buf.capacity() { + self.panicked = true; + let r = self.get_mut().write_vectored(bufs); + self.panicked = false; + r + } else { + bufs.iter().for_each(|b| self.buf.extend_from_slice(b)); + Ok(total_len) + } + } + + fn is_write_vectored(&self) -> bool { + self.get_ref().is_write_vectored() + } + + fn flush(&mut self) -> io::Result<()> { + self.flush_buf().and_then(|()| self.get_mut().flush()) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<W: Write> fmt::Debug for BufWriter<W> +where + W: fmt::Debug, +{ + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_struct("BufWriter") + .field("writer", &self.inner.as_ref().unwrap()) + .field("buffer", &format_args!("{}/{}", self.buf.len(), self.buf.capacity())) + .finish() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<W: Write + Seek> Seek for BufWriter<W> { + /// Seek to the offset, in bytes, in the underlying writer. + /// + /// Seeking always writes out the internal buffer before seeking. + fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> { + self.flush_buf()?; + self.get_mut().seek(pos) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<W: Write> Drop for BufWriter<W> { + fn drop(&mut self) { + if self.inner.is_some() && !self.panicked { + // dtors should not panic, so we ignore a failed flush + let _r = self.flush_buf(); + } + } +} diff --git a/library/std/src/io/buffered/linewriter.rs b/library/std/src/io/buffered/linewriter.rs new file mode 100644 index 00000000000..502c6e3c6c0 --- /dev/null +++ b/library/std/src/io/buffered/linewriter.rs @@ -0,0 +1,232 @@ +use crate::fmt; +use crate::io::{self, buffered::LineWriterShim, BufWriter, IntoInnerError, IoSlice, Write}; + +/// Wraps a writer and buffers output to it, flushing whenever a newline +/// (`0x0a`, `'\n'`) is detected. +/// +/// The [`BufWriter`] struct wraps a writer and buffers its output. +/// But it only does this batched write when it goes out of scope, or when the +/// internal buffer is full. Sometimes, you'd prefer to write each line as it's +/// completed, rather than the entire buffer at once. Enter `LineWriter`. It +/// does exactly that. +/// +/// Like [`BufWriter`], a `LineWriter`’s buffer will also be flushed when the +/// `LineWriter` goes out of scope or when its internal buffer is full. +/// +/// If there's still a partial line in the buffer when the `LineWriter` is +/// dropped, it will flush those contents. +/// +/// # Examples +/// +/// We can use `LineWriter` to write one line at a time, significantly +/// reducing the number of actual writes to the file. +/// +/// ```no_run +/// use std::fs::{self, File}; +/// use std::io::prelude::*; +/// use std::io::LineWriter; +/// +/// fn main() -> std::io::Result<()> { +/// let road_not_taken = b"I shall be telling this with a sigh +/// Somewhere ages and ages hence: +/// Two roads diverged in a wood, and I - +/// I took the one less traveled by, +/// And that has made all the difference."; +/// +/// let file = File::create("poem.txt")?; +/// let mut file = LineWriter::new(file); +/// +/// file.write_all(b"I shall be telling this with a sigh")?; +/// +/// // No bytes are written until a newline is encountered (or +/// // the internal buffer is filled). +/// assert_eq!(fs::read_to_string("poem.txt")?, ""); +/// file.write_all(b"\n")?; +/// assert_eq!( +/// fs::read_to_string("poem.txt")?, +/// "I shall be telling this with a sigh\n", +/// ); +/// +/// // Write the rest of the poem. +/// file.write_all(b"Somewhere ages and ages hence: +/// Two roads diverged in a wood, and I - +/// I took the one less traveled by, +/// And that has made all the difference.")?; +/// +/// // The last line of the poem doesn't end in a newline, so +/// // we have to flush or drop the `LineWriter` to finish +/// // writing. +/// file.flush()?; +/// +/// // Confirm the whole poem was written. +/// assert_eq!(fs::read("poem.txt")?, &road_not_taken[..]); +/// Ok(()) +/// } +/// ``` +#[stable(feature = "rust1", since = "1.0.0")] +pub struct LineWriter<W: Write> { + inner: BufWriter<W>, +} + +impl<W: Write> LineWriter<W> { + /// Creates a new `LineWriter`. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs::File; + /// use std::io::LineWriter; + /// + /// fn main() -> std::io::Result<()> { + /// let file = File::create("poem.txt")?; + /// let file = LineWriter::new(file); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn new(inner: W) -> LineWriter<W> { + // Lines typically aren't that long, don't use a giant buffer + LineWriter::with_capacity(1024, inner) + } + + /// Creates a new `LineWriter` with a specified capacity for the internal + /// buffer. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs::File; + /// use std::io::LineWriter; + /// + /// fn main() -> std::io::Result<()> { + /// let file = File::create("poem.txt")?; + /// let file = LineWriter::with_capacity(100, file); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn with_capacity(capacity: usize, inner: W) -> LineWriter<W> { + LineWriter { inner: BufWriter::with_capacity(capacity, inner) } + } + + /// Gets a reference to the underlying writer. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs::File; + /// use std::io::LineWriter; + /// + /// fn main() -> std::io::Result<()> { + /// let file = File::create("poem.txt")?; + /// let file = LineWriter::new(file); + /// + /// let reference = file.get_ref(); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn get_ref(&self) -> &W { + self.inner.get_ref() + } + + /// Gets a mutable reference to the underlying writer. + /// + /// Caution must be taken when calling methods on the mutable reference + /// returned as extra writes could corrupt the output stream. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs::File; + /// use std::io::LineWriter; + /// + /// fn main() -> std::io::Result<()> { + /// let file = File::create("poem.txt")?; + /// let mut file = LineWriter::new(file); + /// + /// // we can use reference just like file + /// let reference = file.get_mut(); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn get_mut(&mut self) -> &mut W { + self.inner.get_mut() + } + + /// Unwraps this `LineWriter`, returning the underlying writer. + /// + /// The internal buffer is written out before returning the writer. + /// + /// # Errors + /// + /// An [`Err`] will be returned if an error occurs while flushing the buffer. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs::File; + /// use std::io::LineWriter; + /// + /// fn main() -> std::io::Result<()> { + /// let file = File::create("poem.txt")?; + /// + /// let writer: LineWriter<File> = LineWriter::new(file); + /// + /// let file: File = writer.into_inner()?; + /// Ok(()) + /// } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn into_inner(self) -> Result<W, IntoInnerError<LineWriter<W>>> { + self.inner.into_inner().map_err(|err| err.new_wrapped(|inner| LineWriter { inner })) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<W: Write> Write for LineWriter<W> { + fn write(&mut self, buf: &[u8]) -> io::Result<usize> { + LineWriterShim::new(&mut self.inner).write(buf) + } + + fn flush(&mut self) -> io::Result<()> { + self.inner.flush() + } + + fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> { + LineWriterShim::new(&mut self.inner).write_vectored(bufs) + } + + fn is_write_vectored(&self) -> bool { + self.inner.is_write_vectored() + } + + fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { + LineWriterShim::new(&mut self.inner).write_all(buf) + } + + fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> { + LineWriterShim::new(&mut self.inner).write_all_vectored(bufs) + } + + fn write_fmt(&mut self, fmt: fmt::Arguments<'_>) -> io::Result<()> { + LineWriterShim::new(&mut self.inner).write_fmt(fmt) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<W: Write> fmt::Debug for LineWriter<W> +where + W: fmt::Debug, +{ + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_struct("LineWriter") + .field("writer", &self.get_ref()) + .field( + "buffer", + &format_args!("{}/{}", self.inner.buffer().len(), self.inner.capacity()), + ) + .finish() + } +} diff --git a/library/std/src/io/buffered/linewritershim.rs b/library/std/src/io/buffered/linewritershim.rs new file mode 100644 index 00000000000..a80d08db869 --- /dev/null +++ b/library/std/src/io/buffered/linewritershim.rs @@ -0,0 +1,270 @@ +use crate::io::{self, BufWriter, IoSlice, Write}; +use crate::memchr; + +/// Private helper struct for implementing the line-buffered writing logic. +/// This shim temporarily wraps a BufWriter, and uses its internals to +/// implement a line-buffered writer (specifically by using the internal +/// methods like write_to_buf and flush_buf). In this way, a more +/// efficient abstraction can be created than one that only had access to +/// `write` and `flush`, without needlessly duplicating a lot of the +/// implementation details of BufWriter. This also allows existing +/// `BufWriters` to be temporarily given line-buffering logic; this is what +/// enables Stdout to be alternately in line-buffered or block-buffered mode. +#[derive(Debug)] +pub struct LineWriterShim<'a, W: Write> { + buffer: &'a mut BufWriter<W>, +} + +impl<'a, W: Write> LineWriterShim<'a, W> { + pub fn new(buffer: &'a mut BufWriter<W>) -> Self { + Self { buffer } + } + + /// Get a mutable reference to the inner writer (that is, the writer + /// wrapped by the BufWriter). Be careful with this writer, as writes to + /// it will bypass the buffer. + fn inner_mut(&mut self) -> &mut W { + self.buffer.get_mut() + } + + /// Get the content currently buffered in self.buffer + fn buffered(&self) -> &[u8] { + self.buffer.buffer() + } + + /// Flush the buffer iff the last byte is a newline (indicating that an + /// earlier write only succeeded partially, and we want to retry flushing + /// the buffered line before continuing with a subsequent write) + fn flush_if_completed_line(&mut self) -> io::Result<()> { + match self.buffered().last().copied() { + Some(b'\n') => self.buffer.flush_buf(), + _ => Ok(()), + } + } +} + +impl<'a, W: Write> Write for LineWriterShim<'a, W> { + /// Write some data into this BufReader with line buffering. This means + /// that, if any newlines are present in the data, the data up to the last + /// newline is sent directly to the underlying writer, and data after it + /// is buffered. Returns the number of bytes written. + /// + /// This function operates on a "best effort basis"; in keeping with the + /// convention of `Write::write`, it makes at most one attempt to write + /// new data to the underlying writer. If that write only reports a partial + /// success, the remaining data will be buffered. + /// + /// Because this function attempts to send completed lines to the underlying + /// writer, it will also flush the existing buffer if it ends with a + /// newline, even if the incoming data does not contain any newlines. + fn write(&mut self, buf: &[u8]) -> io::Result<usize> { + let newline_idx = match memchr::memrchr(b'\n', buf) { + // If there are no new newlines (that is, if this write is less than + // one line), just do a regular buffered write (which may flush if + // we exceed the inner buffer's size) + None => { + self.flush_if_completed_line()?; + return self.buffer.write(buf); + } + // Otherwise, arrange for the lines to be written directly to the + // inner writer. + Some(newline_idx) => newline_idx + 1, + }; + + // Flush existing content to prepare for our write. We have to do this + // before attempting to write `buf` in order to maintain consistency; + // if we add `buf` to the buffer then try to flush it all at once, + // we're obligated to return Ok(), which would mean suppressing any + // errors that occur during flush. + self.buffer.flush_buf()?; + + // This is what we're going to try to write directly to the inner + // writer. The rest will be buffered, if nothing goes wrong. + let lines = &buf[..newline_idx]; + + // Write `lines` directly to the inner writer. In keeping with the + // `write` convention, make at most one attempt to add new (unbuffered) + // data. Because this write doesn't touch the BufWriter state directly, + // and the buffer is known to be empty, we don't need to worry about + // self.buffer.panicked here. + let flushed = self.inner_mut().write(lines)?; + + // If buffer returns Ok(0), propagate that to the caller without + // doing additional buffering; otherwise we're just guaranteeing + // an "ErrorKind::WriteZero" later. + if flushed == 0 { + return Ok(0); + } + + // Now that the write has succeeded, buffer the rest (or as much of + // the rest as possible). If there were any unwritten newlines, we + // only buffer out to the last unwritten newline that fits in the + // buffer; this helps prevent flushing partial lines on subsequent + // calls to LineWriterShim::write. + + // Handle the cases in order of most-common to least-common, under + // the presumption that most writes succeed in totality, and that most + // writes are smaller than the buffer. + // - Is this a partial line (ie, no newlines left in the unwritten tail) + // - If not, does the data out to the last unwritten newline fit in + // the buffer? + // - If not, scan for the last newline that *does* fit in the buffer + let tail = if flushed >= newline_idx { + &buf[flushed..] + } else if newline_idx - flushed <= self.buffer.capacity() { + &buf[flushed..newline_idx] + } else { + let scan_area = &buf[flushed..]; + let scan_area = &scan_area[..self.buffer.capacity()]; + match memchr::memrchr(b'\n', scan_area) { + Some(newline_idx) => &scan_area[..newline_idx + 1], + None => scan_area, + } + }; + + let buffered = self.buffer.write_to_buf(tail); + Ok(flushed + buffered) + } + + fn flush(&mut self) -> io::Result<()> { + self.buffer.flush() + } + + /// Write some vectored data into this BufReader with line buffering. This + /// means that, if any newlines are present in the data, the data up to + /// and including the buffer containing the last newline is sent directly + /// to the inner writer, and the data after it is buffered. Returns the + /// number of bytes written. + /// + /// This function operates on a "best effort basis"; in keeping with the + /// convention of `Write::write`, it makes at most one attempt to write + /// new data to the underlying writer. + /// + /// Because this function attempts to send completed lines to the underlying + /// writer, it will also flush the existing buffer if it contains any + /// newlines. + /// + /// Because sorting through an array of `IoSlice` can be a bit convoluted, + /// This method differs from write in the following ways: + /// + /// - It attempts to write the full content of all the buffers up to and + /// including the one containing the last newline. This means that it + /// may attempt to write a partial line, that buffer has data past the + /// newline. + /// - If the write only reports partial success, it does not attempt to + /// find the precise location of the written bytes and buffer the rest. + /// + /// If the underlying vector doesn't support vectored writing, we instead + /// simply write the first non-empty buffer with `write`. This way, we + /// get the benefits of more granular partial-line handling without losing + /// anything in efficiency + fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> { + // If there's no specialized behavior for write_vectored, just use + // write. This has the benefit of more granular partial-line handling. + if !self.is_write_vectored() { + return match bufs.iter().find(|buf| !buf.is_empty()) { + Some(buf) => self.write(buf), + None => Ok(0), + }; + } + + // Find the buffer containing the last newline + let last_newline_buf_idx = bufs + .iter() + .enumerate() + .rev() + .find_map(|(i, buf)| memchr::memchr(b'\n', buf).map(|_| i)); + + // If there are no new newlines (that is, if this write is less than + // one line), just do a regular buffered write + let last_newline_buf_idx = match last_newline_buf_idx { + // No newlines; just do a normal buffered write + None => { + self.flush_if_completed_line()?; + return self.buffer.write_vectored(bufs); + } + Some(i) => i, + }; + + // Flush existing content to prepare for our write + self.buffer.flush_buf()?; + + // This is what we're going to try to write directly to the inner + // writer. The rest will be buffered, if nothing goes wrong. + let (lines, tail) = bufs.split_at(last_newline_buf_idx + 1); + + // Write `lines` directly to the inner writer. In keeping with the + // `write` convention, make at most one attempt to add new (unbuffered) + // data. Because this write doesn't touch the BufWriter state directly, + // and the buffer is known to be empty, we don't need to worry about + // self.panicked here. + let flushed = self.inner_mut().write_vectored(lines)?; + + // If inner returns Ok(0), propagate that to the caller without + // doing additional buffering; otherwise we're just guaranteeing + // an "ErrorKind::WriteZero" later. + if flushed == 0 { + return Ok(0); + } + + // Don't try to reconstruct the exact amount written; just bail + // in the event of a partial write + let lines_len = lines.iter().map(|buf| buf.len()).sum(); + if flushed < lines_len { + return Ok(flushed); + } + + // Now that the write has succeeded, buffer the rest (or as much of the + // rest as possible) + let buffered: usize = tail + .iter() + .filter(|buf| !buf.is_empty()) + .map(|buf| self.buffer.write_to_buf(buf)) + .take_while(|&n| n > 0) + .sum(); + + Ok(flushed + buffered) + } + + fn is_write_vectored(&self) -> bool { + self.buffer.is_write_vectored() + } + + /// Write some data into this BufReader with line buffering. This means + /// that, if any newlines are present in the data, the data up to the last + /// newline is sent directly to the underlying writer, and data after it + /// is buffered. + /// + /// Because this function attempts to send completed lines to the underlying + /// writer, it will also flush the existing buffer if it contains any + /// newlines, even if the incoming data does not contain any newlines. + fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { + match memchr::memrchr(b'\n', buf) { + // If there are no new newlines (that is, if this write is less than + // one line), just do a regular buffered write (which may flush if + // we exceed the inner buffer's size) + None => { + self.flush_if_completed_line()?; + self.buffer.write_all(buf) + } + Some(newline_idx) => { + let (lines, tail) = buf.split_at(newline_idx + 1); + + if self.buffered().is_empty() { + self.inner_mut().write_all(lines)?; + } else { + // If there is any buffered data, we add the incoming lines + // to that buffer before flushing, which saves us at least + // one write call. We can't really do this with `write`, + // since we can't do this *and* not suppress errors *and* + // report a consistent state to the caller in a return + // value, but here in write_all it's fine. + self.buffer.write_all(lines)?; + self.buffer.flush_buf()?; + } + + self.buffer.write_all(tail) + } + } + } +} diff --git a/library/std/src/io/buffered/mod.rs b/library/std/src/io/buffered/mod.rs new file mode 100644 index 00000000000..f9caeaf98e2 --- /dev/null +++ b/library/std/src/io/buffered/mod.rs @@ -0,0 +1,151 @@ +//! Buffering wrappers for I/O traits + +mod bufreader; +mod bufwriter; +mod linewriter; +mod linewritershim; + +#[cfg(test)] +mod tests; + +use crate::error; +use crate::fmt; +use crate::io::Error; + +pub use bufreader::BufReader; +pub use bufwriter::BufWriter; +pub use linewriter::LineWriter; +use linewritershim::LineWriterShim; + +/// An error returned by [`BufWriter::into_inner`] which combines an error that +/// happened while writing out the buffer, and the buffered writer object +/// which may be used to recover from the condition. +/// +/// # Examples +/// +/// ```no_run +/// use std::io::BufWriter; +/// use std::net::TcpStream; +/// +/// let mut stream = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap()); +/// +/// // do stuff with the stream +/// +/// // we want to get our `TcpStream` back, so let's try: +/// +/// let stream = match stream.into_inner() { +/// Ok(s) => s, +/// Err(e) => { +/// // Here, e is an IntoInnerError +/// panic!("An error occurred"); +/// } +/// }; +/// ``` +#[derive(Debug)] +#[stable(feature = "rust1", since = "1.0.0")] +pub struct IntoInnerError<W>(W, Error); + +impl<W> IntoInnerError<W> { + /// Construct a new IntoInnerError + fn new(writer: W, error: Error) -> Self { + Self(writer, error) + } + + /// Helper to construct a new IntoInnerError; intended to help with + /// adapters that wrap other adapters + fn new_wrapped<W2>(self, f: impl FnOnce(W) -> W2) -> IntoInnerError<W2> { + let Self(writer, error) = self; + IntoInnerError::new(f(writer), error) + } + + /// Returns the error which caused the call to [`BufWriter::into_inner()`] + /// to fail. + /// + /// This error was returned when attempting to write the internal buffer. + /// + /// # Examples + /// + /// ```no_run + /// use std::io::BufWriter; + /// use std::net::TcpStream; + /// + /// let mut stream = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap()); + /// + /// // do stuff with the stream + /// + /// // we want to get our `TcpStream` back, so let's try: + /// + /// let stream = match stream.into_inner() { + /// Ok(s) => s, + /// Err(e) => { + /// // Here, e is an IntoInnerError, let's log the inner error. + /// // + /// // We'll just 'log' to stdout for this example. + /// println!("{}", e.error()); + /// + /// panic!("An unexpected error occurred."); + /// } + /// }; + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn error(&self) -> &Error { + &self.1 + } + + /// Returns the buffered writer instance which generated the error. + /// + /// The returned object can be used for error recovery, such as + /// re-inspecting the buffer. + /// + /// # Examples + /// + /// ```no_run + /// use std::io::BufWriter; + /// use std::net::TcpStream; + /// + /// let mut stream = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap()); + /// + /// // do stuff with the stream + /// + /// // we want to get our `TcpStream` back, so let's try: + /// + /// let stream = match stream.into_inner() { + /// Ok(s) => s, + /// Err(e) => { + /// // Here, e is an IntoInnerError, let's re-examine the buffer: + /// let buffer = e.into_inner(); + /// + /// // do stuff to try to recover + /// + /// // afterwards, let's just return the stream + /// buffer.into_inner().unwrap() + /// } + /// }; + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn into_inner(self) -> W { + self.0 + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<W> From<IntoInnerError<W>> for Error { + fn from(iie: IntoInnerError<W>) -> Error { + iie.1 + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<W: Send + fmt::Debug> error::Error for IntoInnerError<W> { + #[allow(deprecated, deprecated_in_future)] + fn description(&self) -> &str { + error::Error::description(self.error()) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<W> fmt::Display for IntoInnerError<W> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.error().fmt(f) + } +} diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 5224672adb2..30e7a7f3c3b 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -319,7 +319,7 @@ #![feature(unsafe_block_in_unsafe_fn)] #![feature(unsafe_cell_get_mut)] #![feature(unsafe_cell_raw_get)] -#![feature(untagged_unions)] +#![cfg_attr(bootstrap, feature(untagged_unions))] #![feature(unwind_attributes)] #![feature(vec_into_raw_parts)] #![feature(wake_trait)] diff --git a/library/std/src/net/addr/tests.rs b/library/std/src/net/addr/tests.rs index 43f965de25e..40f5a84bcd5 100644 --- a/library/std/src/net/addr/tests.rs +++ b/library/std/src/net/addr/tests.rs @@ -68,7 +68,7 @@ fn bind_udp_socket_bad() { // returns its own address, it is still an error to bind a UDP socket to // a non-local address, and so we still get an error here in that case. - const INPUT_23076: &'static str = "1200::AB00:1234::2552:7777:1313:34300"; + const INPUT_23076: &str = "1200::AB00:1234::2552:7777:1313:34300"; assert!(crate::net::UdpSocket::bind(INPUT_23076).is_err()) } diff --git a/library/std/src/os/vxworks/fs.rs b/library/std/src/os/vxworks/fs.rs index 5a7e5bcaa76..77e6238ca1f 100644 --- a/library/std/src/os/vxworks/fs.rs +++ b/library/std/src/os/vxworks/fs.rs @@ -26,10 +26,16 @@ pub trait MetadataExt { #[stable(feature = "metadata_ext2", since = "1.8.0")] fn st_atime(&self) -> i64; #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_atime_nsec(&self) -> i64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] fn st_mtime(&self) -> i64; #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_mtime_nsec(&self) -> i64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] fn st_ctime(&self) -> i64; #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_ctime_nsec(&self) -> i64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] fn st_blksize(&self) -> u64; #[stable(feature = "metadata_ext2", since = "1.8.0")] fn st_blocks(&self) -> u64; @@ -66,12 +72,21 @@ impl MetadataExt for Metadata { fn st_atime(&self) -> i64 { self.as_inner().as_inner().st_atime as i64 } + fn st_atime_nsec(&self) -> i64 { + 0 + } fn st_mtime(&self) -> i64 { self.as_inner().as_inner().st_mtime as i64 } + fn st_mtime_nsec(&self) -> i64 { + 0 + } fn st_ctime(&self) -> i64 { self.as_inner().as_inner().st_ctime as i64 } + fn st_ctime_nsec(&self) -> i64 { + 0 + } fn st_blksize(&self) -> u64 { self.as_inner().as_inner().st_blksize as u64 } diff --git a/library/std/src/os/vxworks/raw.rs b/library/std/src/os/vxworks/raw.rs index 29a0af5645e..cb41ddfe2a9 100644 --- a/library/std/src/os/vxworks/raw.rs +++ b/library/std/src/os/vxworks/raw.rs @@ -5,3 +5,6 @@ use crate::os::raw::c_ulong; #[stable(feature = "pthread_t", since = "1.8.0")] pub type pthread_t = c_ulong; + +#[stable(feature = "raw_ext", since = "1.1.0")] +pub use libc::{blkcnt_t, blksize_t, dev_t, ino_t, mode_t, nlink_t, off_t, time_t}; diff --git a/library/std/src/path.rs b/library/std/src/path.rs index 6fa73042a30..50bd2a03b62 100644 --- a/library/std/src/path.rs +++ b/library/std/src/path.rs @@ -1009,7 +1009,7 @@ impl FusedIterator for Ancestors<'_> {} /// [`set_extension`]: PathBuf::set_extension /// /// More details about the overall approach can be found in -/// the [module documentation](index.html). +/// the [module documentation](self). /// /// # Examples /// @@ -1655,7 +1655,7 @@ impl AsRef<OsStr> for PathBuf { /// see [`PathBuf`]. /// /// More details about the overall approach can be found in -/// the [module documentation](index.html). +/// the [module documentation](self). /// /// # Examples /// diff --git a/library/std/src/primitive_docs.rs b/library/std/src/primitive_docs.rs index 81bbf376378..ae678479234 100644 --- a/library/std/src/primitive_docs.rs +++ b/library/std/src/primitive_docs.rs @@ -1118,6 +1118,8 @@ mod prim_ref {} /// For more information and a list of supported ABIs, see [the nomicon's /// section on foreign calling conventions][nomicon-abi]. /// +/// [nomicon-abi]: ../nomicon/ffi.html#foreign-calling-conventions +/// /// ### Variadic functions /// /// Extern function declarations with the "C" or "cdecl" ABIs can also be *variadic*, allowing them diff --git a/library/std/src/process.rs b/library/std/src/process.rs index 3d238b7f764..a1499467744 100644 --- a/library/std/src/process.rs +++ b/library/std/src/process.rs @@ -1184,7 +1184,7 @@ impl Stdio { } /// This stream will be ignored. This is the equivalent of attaching the - /// stream to `/dev/null` + /// stream to `/dev/null`. /// /// # Examples /// diff --git a/library/std/src/sys/cloudabi/condvar.rs b/library/std/src/sys/cloudabi/condvar.rs index 82d89b260fa..f09bc01701b 100644 --- a/library/std/src/sys/cloudabi/condvar.rs +++ b/library/std/src/sys/cloudabi/condvar.rs @@ -1,4 +1,3 @@ -use crate::cell::UnsafeCell; use crate::mem; use crate::sync::atomic::{AtomicU32, Ordering}; use crate::sys::cloudabi::abi; @@ -12,7 +11,7 @@ extern "C" { } pub struct Condvar { - condvar: UnsafeCell<AtomicU32>, + condvar: AtomicU32, } pub type MovableCondvar = Condvar; @@ -20,29 +19,28 @@ pub type MovableCondvar = Condvar; unsafe impl Send for Condvar {} unsafe impl Sync for Condvar {} -const NEW: Condvar = - Condvar { condvar: UnsafeCell::new(AtomicU32::new(abi::CONDVAR_HAS_NO_WAITERS.0)) }; - impl Condvar { pub const fn new() -> Condvar { - NEW + Condvar { condvar: AtomicU32::new(abi::CONDVAR_HAS_NO_WAITERS.0) } } pub unsafe fn init(&mut self) {} pub unsafe fn notify_one(&self) { - let condvar = self.condvar.get(); - if (*condvar).load(Ordering::Relaxed) != abi::CONDVAR_HAS_NO_WAITERS.0 { - let ret = abi::condvar_signal(condvar as *mut abi::condvar, abi::scope::PRIVATE, 1); + if self.condvar.load(Ordering::Relaxed) != abi::CONDVAR_HAS_NO_WAITERS.0 { + let ret = abi::condvar_signal( + &self.condvar as *const AtomicU32 as *mut abi::condvar, + abi::scope::PRIVATE, + 1, + ); assert_eq!(ret, abi::errno::SUCCESS, "Failed to signal on condition variable"); } } pub unsafe fn notify_all(&self) { - let condvar = self.condvar.get(); - if (*condvar).load(Ordering::Relaxed) != abi::CONDVAR_HAS_NO_WAITERS.0 { + if self.condvar.load(Ordering::Relaxed) != abi::CONDVAR_HAS_NO_WAITERS.0 { let ret = abi::condvar_signal( - condvar as *mut abi::condvar, + &self.condvar as *const AtomicU32 as *mut abi::condvar, abi::scope::PRIVATE, abi::nthreads::MAX, ); @@ -53,20 +51,19 @@ impl Condvar { pub unsafe fn wait(&self, mutex: &Mutex) { let mutex = mutex::raw(mutex); assert_eq!( - (*mutex).load(Ordering::Relaxed) & !abi::LOCK_KERNEL_MANAGED.0, + mutex.load(Ordering::Relaxed) & !abi::LOCK_KERNEL_MANAGED.0, __pthread_thread_id.0 | abi::LOCK_WRLOCKED.0, "This lock is not write-locked by this thread" ); // Call into the kernel to wait on the condition variable. - let condvar = self.condvar.get(); let subscription = abi::subscription { type_: abi::eventtype::CONDVAR, union: abi::subscription_union { condvar: abi::subscription_condvar { - condvar: condvar as *mut abi::condvar, + condvar: &self.condvar as *const AtomicU32 as *mut abi::condvar, condvar_scope: abi::scope::PRIVATE, - lock: mutex as *mut abi::lock, + lock: mutex as *const AtomicU32 as *mut abi::lock, lock_scope: abi::scope::PRIVATE, }, }, @@ -86,13 +83,12 @@ impl Condvar { pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool { let mutex = mutex::raw(mutex); assert_eq!( - (*mutex).load(Ordering::Relaxed) & !abi::LOCK_KERNEL_MANAGED.0, + mutex.load(Ordering::Relaxed) & !abi::LOCK_KERNEL_MANAGED.0, __pthread_thread_id.0 | abi::LOCK_WRLOCKED.0, "This lock is not write-locked by this thread" ); // Call into the kernel to wait on the condition variable. - let condvar = self.condvar.get(); let timeout = checked_dur2intervals(&dur).expect("overflow converting duration to nanoseconds"); let subscriptions = [ @@ -100,9 +96,9 @@ impl Condvar { type_: abi::eventtype::CONDVAR, union: abi::subscription_union { condvar: abi::subscription_condvar { - condvar: condvar as *mut abi::condvar, + condvar: &self.condvar as *const AtomicU32 as *mut abi::condvar, condvar_scope: abi::scope::PRIVATE, - lock: mutex as *mut abi::lock, + lock: mutex as *const AtomicU32 as *mut abi::lock, lock_scope: abi::scope::PRIVATE, }, }, @@ -124,7 +120,7 @@ impl Condvar { let mut nevents: mem::MaybeUninit<usize> = mem::MaybeUninit::uninit(); let ret = abi::poll( subscriptions.as_ptr(), - mem::MaybeUninit::first_ptr_mut(&mut events), + mem::MaybeUninit::slice_as_mut_ptr(&mut events), 2, nevents.as_mut_ptr(), ); @@ -144,9 +140,8 @@ impl Condvar { } pub unsafe fn destroy(&self) { - let condvar = self.condvar.get(); assert_eq!( - (*condvar).load(Ordering::Relaxed), + self.condvar.load(Ordering::Relaxed), abi::CONDVAR_HAS_NO_WAITERS.0, "Attempted to destroy a condition variable with blocked threads" ); diff --git a/library/std/src/sys/cloudabi/mutex.rs b/library/std/src/sys/cloudabi/mutex.rs index 66839e05bf0..1203d8de0c5 100644 --- a/library/std/src/sys/cloudabi/mutex.rs +++ b/library/std/src/sys/cloudabi/mutex.rs @@ -1,4 +1,4 @@ -use crate::cell::UnsafeCell; +use crate::cell::Cell; use crate::mem; use crate::mem::MaybeUninit; use crate::sync::atomic::{AtomicU32, Ordering}; @@ -17,7 +17,7 @@ pub struct Mutex(RWLock); pub type MovableMutex = Mutex; -pub unsafe fn raw(m: &Mutex) -> *mut AtomicU32 { +pub unsafe fn raw(m: &Mutex) -> &AtomicU32 { rwlock::raw(&m.0) } @@ -50,28 +50,23 @@ impl Mutex { } pub struct ReentrantMutex { - lock: UnsafeCell<MaybeUninit<AtomicU32>>, - recursion: UnsafeCell<MaybeUninit<u32>>, + lock: AtomicU32, + recursion: Cell<u32>, } +unsafe impl Send for ReentrantMutex {} +unsafe impl Sync for ReentrantMutex {} + impl ReentrantMutex { pub const unsafe fn uninitialized() -> ReentrantMutex { - ReentrantMutex { - lock: UnsafeCell::new(MaybeUninit::uninit()), - recursion: UnsafeCell::new(MaybeUninit::uninit()), - } + ReentrantMutex { lock: AtomicU32::new(abi::LOCK_UNLOCKED.0), recursion: Cell::new(0) } } - pub unsafe fn init(&self) { - *self.lock.get() = MaybeUninit::new(AtomicU32::new(abi::LOCK_UNLOCKED.0)); - *self.recursion.get() = MaybeUninit::new(0); - } + pub unsafe fn init(&self) {} pub unsafe fn try_lock(&self) -> bool { // Attempt to acquire the lock. - let lock = (*self.lock.get()).as_mut_ptr(); - let recursion = (*self.recursion.get()).as_mut_ptr(); - if let Err(old) = (*lock).compare_exchange( + if let Err(old) = self.lock.compare_exchange( abi::LOCK_UNLOCKED.0, __pthread_thread_id.0 | abi::LOCK_WRLOCKED.0, Ordering::Acquire, @@ -80,14 +75,14 @@ impl ReentrantMutex { // If we fail to acquire the lock, it may be the case // that we've already acquired it and may need to recurse. if old & !abi::LOCK_KERNEL_MANAGED.0 == __pthread_thread_id.0 | abi::LOCK_WRLOCKED.0 { - *recursion += 1; + self.recursion.set(self.recursion.get() + 1); true } else { false } } else { // Success. - assert_eq!(*recursion, 0, "Mutex has invalid recursion count"); + assert_eq!(self.recursion.get(), 0, "Mutex has invalid recursion count"); true } } @@ -95,7 +90,7 @@ impl ReentrantMutex { pub unsafe fn lock(&self) { if !self.try_lock() { // Call into the kernel to acquire a write lock. - let lock = self.lock.get(); + let lock = &self.lock as *const AtomicU32; let subscription = abi::subscription { type_: abi::eventtype::LOCK_WRLOCK, union: abi::subscription_union { @@ -116,17 +111,17 @@ impl ReentrantMutex { } pub unsafe fn unlock(&self) { - let lock = (*self.lock.get()).as_mut_ptr(); - let recursion = (*self.recursion.get()).as_mut_ptr(); assert_eq!( - (*lock).load(Ordering::Relaxed) & !abi::LOCK_KERNEL_MANAGED.0, + self.lock.load(Ordering::Relaxed) & !abi::LOCK_KERNEL_MANAGED.0, __pthread_thread_id.0 | abi::LOCK_WRLOCKED.0, "This mutex is locked by a different thread" ); - if *recursion > 0 { - *recursion -= 1; - } else if !(*lock) + let r = self.recursion.get(); + if r > 0 { + self.recursion.set(r - 1); + } else if !self + .lock .compare_exchange( __pthread_thread_id.0 | abi::LOCK_WRLOCKED.0, abi::LOCK_UNLOCKED.0, @@ -137,19 +132,20 @@ impl ReentrantMutex { { // Lock is managed by kernelspace. Call into the kernel // to unblock waiting threads. - let ret = abi::lock_unlock(lock as *mut abi::lock, abi::scope::PRIVATE); + let ret = abi::lock_unlock( + &self.lock as *const AtomicU32 as *mut abi::lock, + abi::scope::PRIVATE, + ); assert_eq!(ret, abi::errno::SUCCESS, "Failed to unlock a mutex"); } } pub unsafe fn destroy(&self) { - let lock = (*self.lock.get()).as_mut_ptr(); - let recursion = (*self.recursion.get()).as_mut_ptr(); assert_eq!( - (*lock).load(Ordering::Relaxed), + self.lock.load(Ordering::Relaxed), abi::LOCK_UNLOCKED.0, "Attempted to destroy locked mutex" ); - assert_eq!(*recursion, 0, "Recursion counter invalid"); + assert_eq!(self.recursion.get(), 0, "Recursion counter invalid"); } } diff --git a/library/std/src/sys/cloudabi/rwlock.rs b/library/std/src/sys/cloudabi/rwlock.rs index b8af5af1d70..508de8ba47c 100644 --- a/library/std/src/sys/cloudabi/rwlock.rs +++ b/library/std/src/sys/cloudabi/rwlock.rs @@ -1,4 +1,3 @@ -use crate::cell::UnsafeCell; use crate::mem; use crate::mem::MaybeUninit; use crate::sync::atomic::{AtomicU32, Ordering}; @@ -13,28 +12,25 @@ extern "C" { static mut RDLOCKS_ACQUIRED: u32 = 0; pub struct RWLock { - lock: UnsafeCell<AtomicU32>, + lock: AtomicU32, } -pub unsafe fn raw(r: &RWLock) -> *mut AtomicU32 { - r.lock.get() +pub unsafe fn raw(r: &RWLock) -> &AtomicU32 { + &r.lock } unsafe impl Send for RWLock {} unsafe impl Sync for RWLock {} -const NEW: RWLock = RWLock { lock: UnsafeCell::new(AtomicU32::new(abi::LOCK_UNLOCKED.0)) }; - impl RWLock { pub const fn new() -> RWLock { - NEW + RWLock { lock: AtomicU32::new(abi::LOCK_UNLOCKED.0) } } pub unsafe fn try_read(&self) -> bool { - let lock = self.lock.get(); let mut old = abi::LOCK_UNLOCKED.0; while let Err(cur) = - (*lock).compare_exchange_weak(old, old + 1, Ordering::Acquire, Ordering::Relaxed) + self.lock.compare_exchange_weak(old, old + 1, Ordering::Acquire, Ordering::Relaxed) { if (cur & abi::LOCK_WRLOCKED.0) != 0 { // Another thread already has a write lock. @@ -61,12 +57,11 @@ impl RWLock { pub unsafe fn read(&self) { if !self.try_read() { // Call into the kernel to acquire a read lock. - let lock = self.lock.get(); let subscription = abi::subscription { type_: abi::eventtype::LOCK_RDLOCK, union: abi::subscription_union { lock: abi::subscription_lock { - lock: lock as *mut abi::lock, + lock: &self.lock as *const AtomicU32 as *mut abi::lock, lock_scope: abi::scope::PRIVATE, }, }, @@ -96,11 +91,10 @@ impl RWLock { assert!(RDLOCKS_ACQUIRED > 0, "Bad lock count"); let mut old = 1; loop { - let lock = self.lock.get(); if old == 1 | abi::LOCK_KERNEL_MANAGED.0 { // Last read lock while threads are waiting. Attempt to upgrade // to a write lock before calling into the kernel to unlock. - if let Err(cur) = (*lock).compare_exchange_weak( + if let Err(cur) = self.lock.compare_exchange_weak( old, __pthread_thread_id.0 | abi::LOCK_WRLOCKED.0 | abi::LOCK_KERNEL_MANAGED.0, Ordering::Acquire, @@ -109,7 +103,10 @@ impl RWLock { old = cur; } else { // Call into the kernel to unlock. - let ret = abi::lock_unlock(lock as *mut abi::lock, abi::scope::PRIVATE); + let ret = abi::lock_unlock( + &self.lock as *const AtomicU32 as *mut abi::lock, + abi::scope::PRIVATE, + ); assert_eq!(ret, abi::errno::SUCCESS, "Failed to write unlock a rwlock"); break; } @@ -122,7 +119,7 @@ impl RWLock { 0, "Attempted to read-unlock a write-locked rwlock" ); - if let Err(cur) = (*lock).compare_exchange_weak( + if let Err(cur) = self.lock.compare_exchange_weak( old, old - 1, Ordering::Acquire, @@ -140,8 +137,7 @@ impl RWLock { pub unsafe fn try_write(&self) -> bool { // Attempt to acquire the lock. - let lock = self.lock.get(); - if let Err(old) = (*lock).compare_exchange( + if let Err(old) = self.lock.compare_exchange( abi::LOCK_UNLOCKED.0, __pthread_thread_id.0 | abi::LOCK_WRLOCKED.0, Ordering::Acquire, @@ -163,12 +159,11 @@ impl RWLock { pub unsafe fn write(&self) { if !self.try_write() { // Call into the kernel to acquire a write lock. - let lock = self.lock.get(); let subscription = abi::subscription { type_: abi::eventtype::LOCK_WRLOCK, union: abi::subscription_union { lock: abi::subscription_lock { - lock: lock as *mut abi::lock, + lock: &self.lock as *const AtomicU32 as *mut abi::lock, lock_scope: abi::scope::PRIVATE, }, }, @@ -184,14 +179,14 @@ impl RWLock { } pub unsafe fn write_unlock(&self) { - let lock = self.lock.get(); assert_eq!( - (*lock).load(Ordering::Relaxed) & !abi::LOCK_KERNEL_MANAGED.0, + self.lock.load(Ordering::Relaxed) & !abi::LOCK_KERNEL_MANAGED.0, __pthread_thread_id.0 | abi::LOCK_WRLOCKED.0, "This rwlock is not write-locked by this thread" ); - if !(*lock) + if !self + .lock .compare_exchange( __pthread_thread_id.0 | abi::LOCK_WRLOCKED.0, abi::LOCK_UNLOCKED.0, @@ -202,15 +197,17 @@ impl RWLock { { // Lock is managed by kernelspace. Call into the kernel // to unblock waiting threads. - let ret = abi::lock_unlock(lock as *mut abi::lock, abi::scope::PRIVATE); + let ret = abi::lock_unlock( + &self.lock as *const AtomicU32 as *mut abi::lock, + abi::scope::PRIVATE, + ); assert_eq!(ret, abi::errno::SUCCESS, "Failed to write unlock a rwlock"); } } pub unsafe fn destroy(&self) { - let lock = self.lock.get(); assert_eq!( - (*lock).load(Ordering::Relaxed), + self.lock.load(Ordering::Relaxed), abi::LOCK_UNLOCKED.0, "Attempted to destroy locked rwlock" ); diff --git a/library/std/src/sys/sgx/env.rs b/library/std/src/sys/sgx/env.rs index 6fa0ed7bcf4..8043b7c5213 100644 --- a/library/std/src/sys/sgx/env.rs +++ b/library/std/src/sys/sgx/env.rs @@ -1,9 +1,9 @@ pub mod os { - pub const FAMILY: &'static str = ""; - pub const OS: &'static str = ""; - pub const DLL_PREFIX: &'static str = ""; - pub const DLL_SUFFIX: &'static str = ".sgxs"; - pub const DLL_EXTENSION: &'static str = "sgxs"; - pub const EXE_SUFFIX: &'static str = ".sgxs"; - pub const EXE_EXTENSION: &'static str = "sgxs"; + pub const FAMILY: &str = ""; + pub const OS: &str = ""; + pub const DLL_PREFIX: &str = ""; + pub const DLL_SUFFIX: &str = ".sgxs"; + pub const DLL_EXTENSION: &str = "sgxs"; + pub const EXE_SUFFIX: &str = ".sgxs"; + pub const EXE_EXTENSION: &str = "sgxs"; } diff --git a/library/std/src/sys/sgx/path.rs b/library/std/src/sys/sgx/path.rs index 06c9df3ff54..840a7ae0426 100644 --- a/library/std/src/sys/sgx/path.rs +++ b/library/std/src/sys/sgx/path.rs @@ -15,5 +15,5 @@ pub fn parse_prefix(_: &OsStr) -> Option<Prefix<'_>> { None } -pub const MAIN_SEP_STR: &'static str = "/"; +pub const MAIN_SEP_STR: &str = "/"; pub const MAIN_SEP: char = '/'; diff --git a/library/std/src/sys/unix/args.rs b/library/std/src/sys/unix/args.rs index f7c3f163718..69676472493 100644 --- a/library/std/src/sys/unix/args.rs +++ b/library/std/src/sys/unix/args.rs @@ -70,7 +70,8 @@ impl DoubleEndedIterator for Args { target_os = "haiku", target_os = "l4re", target_os = "fuchsia", - target_os = "redox" + target_os = "redox", + target_os = "vxworks" ))] mod imp { use super::Args; diff --git a/library/std/src/sys/unix/ext/fs.rs b/library/std/src/sys/unix/ext/fs.rs index 4b9f4ceb29c..66bbc1c5854 100644 --- a/library/std/src/sys/unix/ext/fs.rs +++ b/library/std/src/sys/unix/ext/fs.rs @@ -650,6 +650,9 @@ pub trait MetadataExt { /// ``` #[stable(feature = "metadata_ext", since = "1.1.0")] fn blocks(&self) -> u64; + #[cfg(target_os = "vxworks")] + #[stable(feature = "metadata_ext", since = "1.1.0")] + fn attrib(&self) -> u8; } #[stable(feature = "metadata_ext", since = "1.1.0")] @@ -702,6 +705,10 @@ impl MetadataExt for fs::Metadata { fn blocks(&self) -> u64 { self.st_blocks() } + #[cfg(target_os = "vxworks")] + fn attrib(&self) -> u8 { + self.st_attrib() + } } /// Unix-specific extensions for [`fs::FileType`]. diff --git a/library/std/src/sys/unix/ext/process.rs b/library/std/src/sys/unix/ext/process.rs index 82527c40e91..3615a8a5ee8 100644 --- a/library/std/src/sys/unix/ext/process.rs +++ b/library/std/src/sys/unix/ext/process.rs @@ -16,12 +16,20 @@ pub trait CommandExt { /// `setuid` call in the child process. Failure in the `setuid` /// call will cause the spawn to fail. #[stable(feature = "rust1", since = "1.0.0")] - fn uid(&mut self, id: u32) -> &mut process::Command; + fn uid( + &mut self, + #[cfg(not(target_os = "vxworks"))] id: u32, + #[cfg(target_os = "vxworks")] id: u16, + ) -> &mut process::Command; /// Similar to `uid`, but sets the group ID of the child process. This has /// the same semantics as the `uid` field. #[stable(feature = "rust1", since = "1.0.0")] - fn gid(&mut self, id: u32) -> &mut process::Command; + fn gid( + &mut self, + #[cfg(not(target_os = "vxworks"))] id: u32, + #[cfg(target_os = "vxworks")] id: u16, + ) -> &mut process::Command; /// Schedules a closure to be run just before the `exec` function is /// invoked. @@ -115,12 +123,20 @@ pub trait CommandExt { #[stable(feature = "rust1", since = "1.0.0")] impl CommandExt for process::Command { - fn uid(&mut self, id: u32) -> &mut process::Command { + fn uid( + &mut self, + #[cfg(not(target_os = "vxworks"))] id: u32, + #[cfg(target_os = "vxworks")] id: u16, + ) -> &mut process::Command { self.as_inner_mut().uid(id); self } - fn gid(&mut self, id: u32) -> &mut process::Command { + fn gid( + &mut self, + #[cfg(not(target_os = "vxworks"))] id: u32, + #[cfg(target_os = "vxworks")] id: u16, + ) -> &mut process::Command { self.as_inner_mut().gid(id); self } diff --git a/library/std/src/sys/unix/fd.rs b/library/std/src/sys/unix/fd.rs index 2224a055d6d..d3a279a2355 100644 --- a/library/std/src/sys/unix/fd.rs +++ b/library/std/src/sys/unix/fd.rs @@ -200,7 +200,8 @@ impl FileDesc { target_os = "l4re", target_os = "linux", target_os = "haiku", - target_os = "redox" + target_os = "redox", + target_os = "vxworks" )))] pub fn set_cloexec(&self) -> io::Result<()> { unsafe { @@ -217,7 +218,8 @@ impl FileDesc { target_os = "l4re", target_os = "linux", target_os = "haiku", - target_os = "redox" + target_os = "redox", + target_os = "vxworks" ))] pub fn set_cloexec(&self) -> io::Result<()> { unsafe { diff --git a/library/std/src/sys/unix/fs.rs b/library/std/src/sys/unix/fs.rs index 8184c25afcf..d27d6e2c565 100644 --- a/library/std/src/sys/unix/fs.rs +++ b/library/std/src/sys/unix/fs.rs @@ -297,6 +297,7 @@ impl FileAttr { #[cfg(not(target_os = "netbsd"))] impl FileAttr { + #[cfg(not(target_os = "vxworks"))] pub fn modified(&self) -> io::Result<SystemTime> { Ok(SystemTime::from(libc::timespec { tv_sec: self.stat.st_mtime as libc::time_t, @@ -304,6 +305,15 @@ impl FileAttr { })) } + #[cfg(target_os = "vxworks")] + pub fn modified(&self) -> io::Result<SystemTime> { + Ok(SystemTime::from(libc::timespec { + tv_sec: self.stat.st_mtime as libc::time_t, + tv_nsec: 0, + })) + } + + #[cfg(not(target_os = "vxworks"))] pub fn accessed(&self) -> io::Result<SystemTime> { Ok(SystemTime::from(libc::timespec { tv_sec: self.stat.st_atime as libc::time_t, @@ -311,6 +321,14 @@ impl FileAttr { })) } + #[cfg(target_os = "vxworks")] + pub fn accessed(&self) -> io::Result<SystemTime> { + Ok(SystemTime::from(libc::timespec { + tv_sec: self.stat.st_atime as libc::time_t, + tv_nsec: 0, + })) + } + #[cfg(any( target_os = "freebsd", target_os = "openbsd", @@ -535,12 +553,22 @@ impl DirEntry { lstat(&self.path()) } - #[cfg(any(target_os = "solaris", target_os = "illumos", target_os = "haiku"))] + #[cfg(any( + target_os = "solaris", + target_os = "illumos", + target_os = "haiku", + target_os = "vxworks" + ))] pub fn file_type(&self) -> io::Result<FileType> { lstat(&self.path()).map(|m| m.file_type()) } - #[cfg(not(any(target_os = "solaris", target_os = "illumos", target_os = "haiku")))] + #[cfg(not(any( + target_os = "solaris", + target_os = "illumos", + target_os = "haiku", + target_os = "vxworks" + )))] pub fn file_type(&self) -> io::Result<FileType> { match self.entry.d_type { libc::DT_CHR => Ok(FileType { mode: libc::S_IFCHR }), @@ -565,7 +593,8 @@ impl DirEntry { target_os = "haiku", target_os = "l4re", target_os = "fuchsia", - target_os = "redox" + target_os = "redox", + target_os = "vxworks" ))] pub fn ino(&self) -> u64 { self.entry.d_ino as u64 @@ -603,7 +632,8 @@ impl DirEntry { target_os = "linux", target_os = "emscripten", target_os = "l4re", - target_os = "haiku" + target_os = "haiku", + target_os = "vxworks" ))] fn name_bytes(&self) -> &[u8] { unsafe { CStr::from_ptr(self.entry.d_name.as_ptr()).to_bytes() } @@ -757,11 +787,25 @@ impl File { unsafe fn os_datasync(fd: c_int) -> c_int { libc::fcntl(fd, libc::F_FULLFSYNC) } - #[cfg(target_os = "linux")] + #[cfg(any( + target_os = "freebsd", + target_os = "linux", + target_os = "android", + target_os = "netbsd", + target_os = "openbsd" + ))] unsafe fn os_datasync(fd: c_int) -> c_int { libc::fdatasync(fd) } - #[cfg(not(any(target_os = "macos", target_os = "ios", target_os = "linux")))] + #[cfg(not(any( + target_os = "android", + target_os = "freebsd", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd" + )))] unsafe fn os_datasync(fd: c_int) -> c_int { libc::fsync(fd) } @@ -901,13 +945,25 @@ impl fmt::Debug for File { Some(PathBuf::from(OsString::from_vec(buf))) } - #[cfg(not(any(target_os = "linux", target_os = "macos")))] + #[cfg(target_os = "vxworks")] + fn get_path(fd: c_int) -> Option<PathBuf> { + let mut buf = vec![0; libc::PATH_MAX as usize]; + let n = unsafe { libc::ioctl(fd, libc::FIOGETNAME, buf.as_ptr()) }; + if n == -1 { + return None; + } + let l = buf.iter().position(|&c| c == 0).unwrap(); + buf.truncate(l as usize); + Some(PathBuf::from(OsString::from_vec(buf))) + } + + #[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "vxworks")))] fn get_path(_fd: c_int) -> Option<PathBuf> { // FIXME(#24570): implement this for other Unix platforms None } - #[cfg(any(target_os = "linux", target_os = "macos"))] + #[cfg(any(target_os = "linux", target_os = "macos", target_os = "vxworks"))] fn get_mode(fd: c_int) -> Option<(bool, bool)> { let mode = unsafe { libc::fcntl(fd, libc::F_GETFL) }; if mode == -1 { @@ -921,7 +977,7 @@ impl fmt::Debug for File { } } - #[cfg(not(any(target_os = "linux", target_os = "macos")))] + #[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "vxworks")))] fn get_mode(_fd: c_int) -> Option<(bool, bool)> { // FIXME(#24570): implement this for other Unix platforms None diff --git a/library/std/src/sys/unix/mod.rs b/library/std/src/sys/unix/mod.rs index 776f4f18ecf..b28c6d85b7c 100644 --- a/library/std/src/sys/unix/mod.rs +++ b/library/std/src/sys/unix/mod.rs @@ -220,6 +220,10 @@ where } } +pub fn cvt_nz(error: libc::c_int) -> crate::io::Result<()> { + if error == 0 { Ok(()) } else { Err(crate::io::Error::from_raw_os_error(error)) } +} + // On Unix-like platforms, libc::abort will unregister signal handlers // including the SIGABRT handler, preventing the abort from being blocked, and // fclose streams, with the side effect of flushing them so libc buffered diff --git a/library/std/src/sys/unix/mutex.rs b/library/std/src/sys/unix/mutex.rs index ebc737b75ae..89c55eb859d 100644 --- a/library/std/src/sys/unix/mutex.rs +++ b/library/std/src/sys/unix/mutex.rs @@ -1,5 +1,6 @@ use crate::cell::UnsafeCell; use crate::mem::MaybeUninit; +use crate::sys::cvt_nz; pub struct Mutex { inner: UnsafeCell<libc::pthread_mutex_t>, @@ -51,14 +52,11 @@ impl Mutex { // PTHREAD_MUTEX_NORMAL which is guaranteed to deadlock if we try to // re-lock it from the same thread, thus avoiding undefined behavior. let mut attr = MaybeUninit::<libc::pthread_mutexattr_t>::uninit(); - let r = libc::pthread_mutexattr_init(attr.as_mut_ptr()); - debug_assert_eq!(r, 0); - let r = libc::pthread_mutexattr_settype(attr.as_mut_ptr(), libc::PTHREAD_MUTEX_NORMAL); - debug_assert_eq!(r, 0); - let r = libc::pthread_mutex_init(self.inner.get(), attr.as_ptr()); - debug_assert_eq!(r, 0); - let r = libc::pthread_mutexattr_destroy(attr.as_mut_ptr()); - debug_assert_eq!(r, 0); + cvt_nz(libc::pthread_mutexattr_init(attr.as_mut_ptr())).unwrap(); + let attr = PthreadMutexAttr(&mut attr); + cvt_nz(libc::pthread_mutexattr_settype(attr.0.as_mut_ptr(), libc::PTHREAD_MUTEX_NORMAL)) + .unwrap(); + cvt_nz(libc::pthread_mutex_init(self.inner.get(), attr.0.as_ptr())).unwrap(); } #[inline] pub unsafe fn lock(&self) { @@ -106,15 +104,11 @@ impl ReentrantMutex { pub unsafe fn init(&self) { let mut attr = MaybeUninit::<libc::pthread_mutexattr_t>::uninit(); - let result = libc::pthread_mutexattr_init(attr.as_mut_ptr()); - debug_assert_eq!(result, 0); - let result = - libc::pthread_mutexattr_settype(attr.as_mut_ptr(), libc::PTHREAD_MUTEX_RECURSIVE); - debug_assert_eq!(result, 0); - let result = libc::pthread_mutex_init(self.inner.get(), attr.as_ptr()); - debug_assert_eq!(result, 0); - let result = libc::pthread_mutexattr_destroy(attr.as_mut_ptr()); - debug_assert_eq!(result, 0); + cvt_nz(libc::pthread_mutexattr_init(attr.as_mut_ptr())).unwrap(); + let attr = PthreadMutexAttr(&mut attr); + cvt_nz(libc::pthread_mutexattr_settype(attr.0.as_mut_ptr(), libc::PTHREAD_MUTEX_RECURSIVE)) + .unwrap(); + cvt_nz(libc::pthread_mutex_init(self.inner.get(), attr.0.as_ptr())).unwrap(); } pub unsafe fn lock(&self) { @@ -137,3 +131,14 @@ impl ReentrantMutex { debug_assert_eq!(result, 0); } } + +struct PthreadMutexAttr<'a>(&'a mut MaybeUninit<libc::pthread_mutexattr_t>); + +impl Drop for PthreadMutexAttr<'_> { + fn drop(&mut self) { + unsafe { + let result = libc::pthread_mutexattr_destroy(self.0.as_mut_ptr()); + debug_assert_eq!(result, 0); + } + } +} diff --git a/library/std/src/sys/unix/net.rs b/library/std/src/sys/unix/net.rs index 011325fddc5..74c7db27226 100644 --- a/library/std/src/sys/unix/net.rs +++ b/library/std/src/sys/unix/net.rs @@ -77,6 +77,7 @@ impl Socket { } } + #[cfg(not(target_os = "vxworks"))] pub fn new_pair(fam: c_int, ty: c_int) -> io::Result<(Socket, Socket)> { unsafe { let mut fds = [0, 0]; @@ -98,6 +99,11 @@ impl Socket { } } + #[cfg(target_os = "vxworks")] + pub fn new_pair(_fam: c_int, _ty: c_int) -> io::Result<(Socket, Socket)> { + unimplemented!() + } + pub fn connect_timeout(&self, addr: &SocketAddr, timeout: Duration) -> io::Result<()> { self.set_nonblocking(true)?; let r = unsafe { @@ -366,7 +372,7 @@ impl IntoInner<c_int> for Socket { // res_init unconditionally, we call it only when we detect we're linking // against glibc version < 2.26. (That is, when we both know its needed and // believe it's thread-safe). -#[cfg(target_env = "gnu")] +#[cfg(all(target_env = "gnu", not(target_os = "vxworks")))] fn on_resolver_failure() { use crate::sys; @@ -378,5 +384,5 @@ fn on_resolver_failure() { } } -#[cfg(not(target_env = "gnu"))] +#[cfg(any(not(target_env = "gnu"), target_os = "vxworks"))] fn on_resolver_failure() {} diff --git a/library/std/src/sys/unix/os.rs b/library/std/src/sys/unix/os.rs index c9f9ed01e12..d5e14bec765 100644 --- a/library/std/src/sys/unix/os.rs +++ b/library/std/src/sys/unix/os.rs @@ -37,7 +37,7 @@ cfg_if::cfg_if! { } extern "C" { - #[cfg(not(target_os = "dragonfly"))] + #[cfg(not(any(target_os = "dragonfly", target_os = "vxworks")))] #[cfg_attr( any( target_os = "linux", @@ -67,18 +67,28 @@ extern "C" { } /// Returns the platform-specific value of errno -#[cfg(not(target_os = "dragonfly"))] +#[cfg(not(any(target_os = "dragonfly", target_os = "vxworks")))] pub fn errno() -> i32 { unsafe { (*errno_location()) as i32 } } /// Sets the platform-specific value of errno -#[cfg(all(not(target_os = "linux"), not(target_os = "dragonfly")))] // needed for readdir and syscall! +#[cfg(all(not(target_os = "linux"), not(target_os = "dragonfly"), not(target_os = "vxworks")))] // needed for readdir and syscall! #[allow(dead_code)] // but not all target cfgs actually end up using it pub fn set_errno(e: i32) { unsafe { *errno_location() = e as c_int } } +#[cfg(target_os = "vxworks")] +pub fn errno() -> i32 { + unsafe { libc::errnoGet() } +} + +#[cfg(target_os = "vxworks")] +pub fn set_errno(e: i32) { + unsafe { libc::errnoSet(e as c_int) }; +} + #[cfg(target_os = "dragonfly")] pub fn errno() -> i32 { extern "C" { @@ -439,6 +449,19 @@ pub fn current_exe() -> io::Result<PathBuf> { Err(io::Error::new(ErrorKind::Other, "Not yet implemented!")) } +#[cfg(target_os = "vxworks")] +pub fn current_exe() -> io::Result<PathBuf> { + #[cfg(test)] + use realstd::env; + + #[cfg(not(test))] + use crate::env; + + let exe_path = env::args().next().unwrap(); + let path = path::Path::new(&exe_path); + path.canonicalize() +} + pub struct Env { iter: vec::IntoIter<(OsString, OsString)>, _dont_send_or_sync_me: PhantomData<*mut ()>, @@ -470,7 +493,7 @@ pub unsafe fn environ() -> *mut *const *const c_char { &mut environ } -pub unsafe fn env_lock() -> StaticMutexGuard<'static> { +pub unsafe fn env_lock() -> StaticMutexGuard { // It is UB to attempt to acquire this mutex reentrantly! static ENV_LOCK: StaticMutex = StaticMutex::new(); ENV_LOCK.lock() @@ -568,7 +591,8 @@ pub fn home_dir() -> Option<PathBuf> { target_os = "android", target_os = "ios", target_os = "emscripten", - target_os = "redox" + target_os = "redox", + target_os = "vxworks" ))] unsafe fn fallback() -> Option<OsString> { None @@ -577,7 +601,8 @@ pub fn home_dir() -> Option<PathBuf> { target_os = "android", target_os = "ios", target_os = "emscripten", - target_os = "redox" + target_os = "redox", + target_os = "vxworks" )))] unsafe fn fallback() -> Option<OsString> { let amt = match libc::sysconf(libc::_SC_GETPW_R_SIZE_MAX) { diff --git a/library/std/src/sys/unix/process/process_common.rs b/library/std/src/sys/unix/process/process_common.rs index 9ddd4ad4000..372e5e6a5b3 100644 --- a/library/std/src/sys/unix/process/process_common.rs +++ b/library/std/src/sys/unix/process/process_common.rs @@ -24,6 +24,8 @@ cfg_if::cfg_if! { // fuchsia doesn't have /dev/null } else if #[cfg(target_os = "redox")] { const DEV_NULL: &str = "null:\0"; + } else if #[cfg(target_os = "vxworks")] { + const DEV_NULL: &str = "/null\0"; } else { const DEV_NULL: &str = "/dev/null\0"; } @@ -48,7 +50,7 @@ cfg_if::cfg_if! { raw[bit / 8] |= 1 << (bit % 8); return 0; } - } else { + } else if #[cfg(not(target_os = "vxworks"))] { pub use libc::{sigemptyset, sigaddset}; } } @@ -253,11 +255,17 @@ impl Command { let maybe_env = self.env.capture_if_changed(); maybe_env.map(|env| construct_envp(env, &mut self.saw_nul)) } + #[allow(dead_code)] pub fn env_saw_path(&self) -> bool { self.env.have_changed_path() } + #[allow(dead_code)] + pub fn program_is_path(&self) -> bool { + self.program.to_bytes().contains(&b'/') + } + pub fn setup_io( &self, default: Stdio, diff --git a/library/std/src/sys/unix/process/process_unix.rs b/library/std/src/sys/unix/process/process_unix.rs index 5e55f97705d..a590c744356 100644 --- a/library/std/src/sys/unix/process/process_unix.rs +++ b/library/std/src/sys/unix/process/process_unix.rs @@ -6,6 +6,10 @@ use crate::sys; use crate::sys::cvt; use crate::sys::process::process_common::*; +#[cfg(target_os = "vxworks")] +use libc::RTP_ID as pid_t; + +#[cfg(not(target_os = "vxworks"))] use libc::{c_int, gid_t, pid_t, uid_t}; //////////////////////////////////////////////////////////////////////////////// @@ -277,11 +281,11 @@ impl Command { envp: Option<&CStringArray>, ) -> io::Result<Option<Process>> { use crate::mem::MaybeUninit; - use crate::sys; + use crate::sys::{self, cvt_nz}; if self.get_gid().is_some() || self.get_uid().is_some() - || self.env_saw_path() + || (self.env_saw_path() && !self.program_is_path()) || !self.get_closures().is_empty() { return Ok(None); @@ -339,10 +343,6 @@ impl Command { } } - fn cvt_nz(error: libc::c_int) -> io::Result<()> { - if error == 0 { Ok(()) } else { Err(io::Error::from_raw_os_error(error)) } - } - unsafe { let mut attrs = MaybeUninit::uninit(); cvt_nz(libc::posix_spawnattr_init(attrs.as_mut_ptr()))?; diff --git a/library/std/src/sys/unix/stack_overflow.rs b/library/std/src/sys/unix/stack_overflow.rs index c74fc2b5903..d8474205352 100644 --- a/library/std/src/sys/unix/stack_overflow.rs +++ b/library/std/src/sys/unix/stack_overflow.rs @@ -219,7 +219,7 @@ mod imp { target_os = "solaris", target_os = "illumos", all(target_os = "netbsd", not(target_vendor = "rumprun")), - target_os = "openbsd" + target_os = "openbsd", )))] mod imp { pub unsafe fn init() {} diff --git a/library/std/src/sys/unix/thread.rs b/library/std/src/sys/unix/thread.rs index 652219e28f6..fdf114d6df6 100644 --- a/library/std/src/sys/unix/thread.rs +++ b/library/std/src/sys/unix/thread.rs @@ -6,10 +6,12 @@ use crate::ptr; use crate::sys::{os, stack_overflow}; use crate::time::Duration; -#[cfg(not(target_os = "l4re"))] +#[cfg(not(any(target_os = "l4re", target_os = "vxworks")))] pub const DEFAULT_MIN_STACK_SIZE: usize = 2 * 1024 * 1024; #[cfg(target_os = "l4re")] pub const DEFAULT_MIN_STACK_SIZE: usize = 1024 * 1024; +#[cfg(target_os = "vxworks")] +pub const DEFAULT_MIN_STACK_SIZE: usize = 256 * 1024; pub struct Thread { id: libc::pthread_t, @@ -152,10 +154,11 @@ impl Thread { target_os = "haiku", target_os = "l4re", target_os = "emscripten", - target_os = "redox" + target_os = "redox", + target_os = "vxworks" ))] pub fn set_name(_name: &CStr) { - // Newlib, Haiku, and Emscripten have no way to set a thread name. + // Newlib, Haiku, Emscripten, and VxWorks have no way to set a thread name. } #[cfg(target_os = "fuchsia")] pub fn set_name(_name: &CStr) { diff --git a/library/std/src/sys/unsupported/common.rs b/library/std/src/sys/unsupported/common.rs index 80311d26819..2cdd9c4d19e 100644 --- a/library/std/src/sys/unsupported/common.rs +++ b/library/std/src/sys/unsupported/common.rs @@ -39,10 +39,13 @@ pub fn hashmap_random_keys() -> (u64, u64) { pub enum Void {} pub unsafe fn strlen(mut s: *const c_char) -> usize { - let mut n = 0; - while *s != 0 { - n += 1; - s = s.offset(1); + // SAFETY: The caller must guarantee `s` points to a valid 0-terminated string. + unsafe { + let mut n = 0; + while *s != 0 { + n += 1; + s = s.offset(1); + } + n } - return n; } diff --git a/library/std/src/sys/unsupported/mod.rs b/library/std/src/sys/unsupported/mod.rs index 8ba870c5dbc..d9efdec33d9 100644 --- a/library/std/src/sys/unsupported/mod.rs +++ b/library/std/src/sys/unsupported/mod.rs @@ -1,3 +1,5 @@ +#![deny(unsafe_op_in_unsafe_fn)] + pub mod alloc; pub mod args; pub mod cmath; diff --git a/library/std/src/sys/unsupported/mutex.rs b/library/std/src/sys/unsupported/mutex.rs index 06ea9a1e2c1..b3203c16c50 100644 --- a/library/std/src/sys/unsupported/mutex.rs +++ b/library/std/src/sys/unsupported/mutex.rs @@ -1,7 +1,8 @@ -use crate::cell::UnsafeCell; +use crate::cell::Cell; pub struct Mutex { - locked: UnsafeCell<bool>, + // This platform has no threads, so we can use a Cell here. + locked: Cell<bool>, } pub type MovableMutex = Mutex; @@ -10,9 +11,8 @@ unsafe impl Send for Mutex {} unsafe impl Sync for Mutex {} // no threads on this platform impl Mutex { - #[rustc_const_stable(feature = "const_sys_mutex_new", since = "1.0.0")] pub const fn new() -> Mutex { - Mutex { locked: UnsafeCell::new(false) } + Mutex { locked: Cell::new(false) } } #[inline] @@ -20,25 +20,17 @@ impl Mutex { #[inline] pub unsafe fn lock(&self) { - let locked = self.locked.get(); - assert!(!*locked, "cannot recursively acquire mutex"); - *locked = true; + assert_eq!(self.locked.replace(true), false, "cannot recursively acquire mutex"); } #[inline] pub unsafe fn unlock(&self) { - *self.locked.get() = false; + self.locked.set(false); } #[inline] pub unsafe fn try_lock(&self) -> bool { - let locked = self.locked.get(); - if *locked { - false - } else { - *locked = true; - true - } + self.locked.replace(true) == false } #[inline] diff --git a/library/std/src/sys/unsupported/rwlock.rs b/library/std/src/sys/unsupported/rwlock.rs index d37f34ac935..6982b2b155f 100644 --- a/library/std/src/sys/unsupported/rwlock.rs +++ b/library/std/src/sys/unsupported/rwlock.rs @@ -1,7 +1,8 @@ -use crate::cell::UnsafeCell; +use crate::cell::Cell; pub struct RWLock { - mode: UnsafeCell<isize>, + // This platform has no threads, so we can use a Cell here. + mode: Cell<isize>, } unsafe impl Send for RWLock {} @@ -9,14 +10,14 @@ unsafe impl Sync for RWLock {} // no threads on this platform impl RWLock { pub const fn new() -> RWLock { - RWLock { mode: UnsafeCell::new(0) } + RWLock { mode: Cell::new(0) } } #[inline] pub unsafe fn read(&self) { - let mode = self.mode.get(); - if *mode >= 0 { - *mode += 1; + let m = self.mode.get(); + if m >= 0 { + self.mode.set(m + 1); } else { rtabort!("rwlock locked for writing"); } @@ -24,9 +25,9 @@ impl RWLock { #[inline] pub unsafe fn try_read(&self) -> bool { - let mode = self.mode.get(); - if *mode >= 0 { - *mode += 1; + let m = self.mode.get(); + if m >= 0 { + self.mode.set(m + 1); true } else { false @@ -35,19 +36,15 @@ impl RWLock { #[inline] pub unsafe fn write(&self) { - let mode = self.mode.get(); - if *mode == 0 { - *mode = -1; - } else { + if self.mode.replace(-1) != 0 { rtabort!("rwlock locked for reading") } } #[inline] pub unsafe fn try_write(&self) -> bool { - let mode = self.mode.get(); - if *mode == 0 { - *mode = -1; + if self.mode.get() == 0 { + self.mode.set(-1); true } else { false @@ -56,12 +53,12 @@ impl RWLock { #[inline] pub unsafe fn read_unlock(&self) { - *self.mode.get() -= 1; + self.mode.set(self.mode.get() - 1); } #[inline] pub unsafe fn write_unlock(&self) { - *self.mode.get() += 1; + assert_eq!(self.mode.replace(0), -1); } #[inline] diff --git a/library/std/src/sys/vxworks/alloc.rs b/library/std/src/sys/vxworks/alloc.rs deleted file mode 100644 index 97a191d7232..00000000000 --- a/library/std/src/sys/vxworks/alloc.rs +++ /dev/null @@ -1,49 +0,0 @@ -use crate::alloc::{GlobalAlloc, Layout, System}; -use crate::ptr; -use crate::sys_common::alloc::{realloc_fallback, MIN_ALIGN}; - -#[stable(feature = "alloc_system_type", since = "1.28.0")] -unsafe impl GlobalAlloc for System { - #[inline] - unsafe fn alloc(&self, layout: Layout) -> *mut u8 { - if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() { - libc::malloc(layout.size()) as *mut u8 - } else { - aligned_malloc(&layout) - } - } - - #[inline] - unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 { - if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() { - libc::calloc(layout.size(), 1) as *mut u8 - } else { - let ptr = self.alloc(layout.clone()); - if !ptr.is_null() { - ptr::write_bytes(ptr, 0, layout.size()); - } - ptr - } - } - - #[inline] - unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) { - libc::free(ptr as *mut libc::c_void) - } - - #[inline] - unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 { - if layout.align() <= MIN_ALIGN && layout.align() <= new_size { - libc::realloc(ptr as *mut libc::c_void, new_size) as *mut u8 - } else { - realloc_fallback(self, ptr, layout, new_size) - } - } -} - -#[inline] -unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 { - let mut out = ptr::null_mut(); - let ret = libc::posix_memalign(&mut out, layout.align(), layout.size()); - if ret != 0 { ptr::null_mut() } else { out as *mut u8 } -} diff --git a/library/std/src/sys/vxworks/args.rs b/library/std/src/sys/vxworks/args.rs deleted file mode 100644 index 30cf7a707c7..00000000000 --- a/library/std/src/sys/vxworks/args.rs +++ /dev/null @@ -1,95 +0,0 @@ -#![allow(dead_code)] // runtime init functions not used during testing -use crate::ffi::OsString; -use crate::marker::PhantomData; -use crate::vec; - -/// One-time global initialization. -pub unsafe fn init(argc: isize, argv: *const *const u8) { - imp::init(argc, argv) -} - -/// One-time global cleanup. -pub unsafe fn cleanup() { - imp::cleanup() -} - -/// Returns the command line arguments -pub fn args() -> Args { - imp::args() -} - -pub struct Args { - iter: vec::IntoIter<OsString>, - _dont_send_or_sync_me: PhantomData<*mut ()>, -} - -impl Args { - pub fn inner_debug(&self) -> &[OsString] { - self.iter.as_slice() - } -} - -impl Iterator for Args { - type Item = OsString; - fn next(&mut self) -> Option<OsString> { - self.iter.next() - } - fn size_hint(&self) -> (usize, Option<usize>) { - self.iter.size_hint() - } -} - -impl ExactSizeIterator for Args { - fn len(&self) -> usize { - self.iter.len() - } -} - -impl DoubleEndedIterator for Args { - fn next_back(&mut self) -> Option<OsString> { - self.iter.next_back() - } -} - -mod imp { - use super::Args; - use crate::ffi::{CStr, OsString}; - use crate::marker::PhantomData; - use crate::ptr; - - use crate::sys_common::mutex::StaticMutex; - - static mut ARGC: isize = 0; - static mut ARGV: *const *const u8 = ptr::null(); - static LOCK: StaticMutex = StaticMutex::new(); - - pub unsafe fn init(argc: isize, argv: *const *const u8) { - let _guard = LOCK.lock(); - ARGC = argc; - ARGV = argv; - } - - pub unsafe fn cleanup() { - let _guard = LOCK.lock(); - ARGC = 0; - ARGV = ptr::null(); - } - - pub fn args() -> Args { - Args { iter: clone().into_iter(), _dont_send_or_sync_me: PhantomData } - } - - fn clone() -> Vec<OsString> { - unsafe { - let _guard = LOCK.lock(); - let ret = (0..ARGC) - .map(|i| { - let cstr = CStr::from_ptr(*ARGV.offset(i) as *const libc::c_char); - use crate::sys::vxworks::ext::ffi::OsStringExt; - OsStringExt::from_vec(cstr.to_bytes().to_vec()) - }) - .collect(); - return ret; - } - } -} diff --git a/library/std/src/sys/vxworks/cmath.rs b/library/std/src/sys/vxworks/cmath.rs deleted file mode 100644 index f327b69fc75..00000000000 --- a/library/std/src/sys/vxworks/cmath.rs +++ /dev/null @@ -1,32 +0,0 @@ -#![cfg(not(test))] - -use libc::{c_double, c_float}; - -extern "C" { - pub fn acos(n: c_double) -> c_double; - pub fn acosf(n: c_float) -> c_float; - pub fn asin(n: c_double) -> c_double; - pub fn asinf(n: c_float) -> c_float; - pub fn atan(n: c_double) -> c_double; - pub fn atan2(a: c_double, b: c_double) -> c_double; - pub fn atan2f(a: c_float, b: c_float) -> c_float; - pub fn atanf(n: c_float) -> c_float; - pub fn cbrt(n: c_double) -> c_double; - pub fn cbrtf(n: c_float) -> c_float; - pub fn cosh(n: c_double) -> c_double; - pub fn coshf(n: c_float) -> c_float; - pub fn expm1(n: c_double) -> c_double; - pub fn expm1f(n: c_float) -> c_float; - pub fn fdim(a: c_double, b: c_double) -> c_double; - pub fn fdimf(a: c_float, b: c_float) -> c_float; - pub fn hypot(x: c_double, y: c_double) -> c_double; - pub fn hypotf(x: c_float, y: c_float) -> c_float; - pub fn log1p(n: c_double) -> c_double; - pub fn log1pf(n: c_float) -> c_float; - pub fn sinh(n: c_double) -> c_double; - pub fn sinhf(n: c_float) -> c_float; - pub fn tan(n: c_double) -> c_double; - pub fn tanf(n: c_float) -> c_float; - pub fn tanh(n: c_double) -> c_double; - pub fn tanhf(n: c_float) -> c_float; -} diff --git a/library/std/src/sys/vxworks/condvar.rs b/library/std/src/sys/vxworks/condvar.rs deleted file mode 100644 index b4724be7c7c..00000000000 --- a/library/std/src/sys/vxworks/condvar.rs +++ /dev/null @@ -1,91 +0,0 @@ -use crate::cell::UnsafeCell; -use crate::sys::mutex::{self, Mutex}; -use crate::time::Duration; - -pub struct Condvar { - inner: UnsafeCell<libc::pthread_cond_t>, -} - -pub type MovableCondvar = Box<Condvar>; - -unsafe impl Send for Condvar {} -unsafe impl Sync for Condvar {} - -const TIMESPEC_MAX: libc::timespec = - libc::timespec { tv_sec: <libc::time_t>::MAX, tv_nsec: 1_000_000_000 - 1 }; - -fn saturating_cast_to_time_t(value: u64) -> libc::time_t { - if value > <libc::time_t>::MAX as u64 { <libc::time_t>::MAX } else { value as libc::time_t } -} - -impl Condvar { - pub const fn new() -> Condvar { - // Might be moved and address is changing it is better to avoid - // initialization of potentially opaque OS data before it landed - Condvar { inner: UnsafeCell::new(libc::PTHREAD_COND_INITIALIZER) } - } - - pub unsafe fn init(&mut self) { - use crate::mem::MaybeUninit; - let mut attr = MaybeUninit::<libc::pthread_condattr_t>::uninit(); - let r = libc::pthread_condattr_init(attr.as_mut_ptr()); - assert_eq!(r, 0); - let r = libc::pthread_condattr_setclock(attr.as_mut_ptr(), libc::CLOCK_MONOTONIC); - assert_eq!(r, 0); - let r = libc::pthread_cond_init(self.inner.get(), attr.as_ptr()); - assert_eq!(r, 0); - let r = libc::pthread_condattr_destroy(attr.as_mut_ptr()); - assert_eq!(r, 0); - } - - #[inline] - pub unsafe fn notify_one(&self) { - let r = libc::pthread_cond_signal(self.inner.get()); - debug_assert_eq!(r, 0); - } - - #[inline] - pub unsafe fn notify_all(&self) { - let r = libc::pthread_cond_broadcast(self.inner.get()); - debug_assert_eq!(r, 0); - } - - #[inline] - pub unsafe fn wait(&self, mutex: &Mutex) { - let r = libc::pthread_cond_wait(self.inner.get(), mutex::raw(mutex)); - debug_assert_eq!(r, 0); - } - - // This implementation is used on systems that support pthread_condattr_setclock - // where we configure condition variable to use monotonic clock (instead of - // default system clock). This approach avoids all problems that result - // from changes made to the system time. - pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool { - use crate::mem; - - let mut now: libc::timespec = mem::zeroed(); - let r = libc::clock_gettime(libc::CLOCK_MONOTONIC, &mut now); - assert_eq!(r, 0); - - // Nanosecond calculations can't overflow because both values are below 1e9. - let nsec = dur.subsec_nanos() + now.tv_nsec as u32; - - let sec = saturating_cast_to_time_t(dur.as_secs()) - .checked_add((nsec / 1_000_000_000) as libc::time_t) - .and_then(|s| s.checked_add(now.tv_sec)); - let nsec = nsec % 1_000_000_000; - - let timeout = - sec.map(|s| libc::timespec { tv_sec: s, tv_nsec: nsec as _ }).unwrap_or(TIMESPEC_MAX); - - let r = libc::pthread_cond_timedwait(self.inner.get(), mutex::raw(mutex), &timeout); - assert!(r == libc::ETIMEDOUT || r == 0); - r == 0 - } - - #[inline] - pub unsafe fn destroy(&self) { - let r = libc::pthread_cond_destroy(self.inner.get()); - debug_assert_eq!(r, 0); - } -} diff --git a/library/std/src/sys/vxworks/ext/ffi.rs b/library/std/src/sys/vxworks/ext/ffi.rs deleted file mode 100644 index 76b34a6b5d8..00000000000 --- a/library/std/src/sys/vxworks/ext/ffi.rs +++ /dev/null @@ -1,38 +0,0 @@ -//! Unix-specific extension to the primitives in the `std::ffi` module -//! -//! # Examples -//! -//! ``` -//! use std::ffi::OsString; -//! use std::os::unix::ffi::OsStringExt; -//! -//! let bytes = b"foo".to_vec(); -//! -//! // OsStringExt::from_vec -//! let os_string = OsString::from_vec(bytes); -//! assert_eq!(os_string.to_str(), Some("foo")); -//! -//! // OsStringExt::into_vec -//! let bytes = os_string.into_vec(); -//! assert_eq!(bytes, b"foo"); -//! ``` -//! -//! ``` -//! use std::ffi::OsStr; -//! use std::os::unix::ffi::OsStrExt; -//! -//! let bytes = b"foo"; -//! -//! // OsStrExt::from_bytes -//! let os_str = OsStr::from_bytes(bytes); -//! assert_eq!(os_str.to_str(), Some("foo")); -//! -//! // OsStrExt::as_bytes -//! let bytes = os_str.as_bytes(); -//! assert_eq!(bytes, b"foo"); -//! ``` - -#![stable(feature = "rust1", since = "1.0.0")] - -#[stable(feature = "rust1", since = "1.0.0")] -pub use crate::sys_common::os_str_bytes::*; diff --git a/library/std/src/sys/vxworks/ext/fs.rs b/library/std/src/sys/vxworks/ext/fs.rs deleted file mode 100644 index 68dc21b806c..00000000000 --- a/library/std/src/sys/vxworks/ext/fs.rs +++ /dev/null @@ -1,817 +0,0 @@ -#![stable(feature = "rust1", since = "1.0.0")] - -use crate::fs::{self, Permissions}; -use crate::io; -use crate::path::Path; -use crate::sys; -use crate::sys::platform::fs::MetadataExt as UnixMetadataExt; -use crate::sys_common::{AsInner, AsInnerMut, FromInner}; - -/// Unix-specific extensions to [`fs::File`]. -#[stable(feature = "file_offset", since = "1.15.0")] -pub trait FileExt { - /// Reads a number of bytes starting from a given offset. - /// - /// Returns the number of bytes read. - /// - /// The offset is relative to the start of the file and thus independent - /// from the current cursor. - /// - /// The current file cursor is not affected by this function. - /// - /// Note that similar to [`File::read`], it is not an error to return with a - /// short read. - /// - /// [`File::read`]: fs::File::read - /// - /// # Examples - /// - /// ```no_run - /// use std::io; - /// use std::fs::File; - /// use std::os::unix::prelude::FileExt; - /// - /// fn main() -> io::Result<()> { - /// let mut buf = [0u8; 8]; - /// let file = File::open("foo.txt")?; - /// - /// // We now read 8 bytes from the offset 10. - /// let num_bytes_read = file.read_at(&mut buf, 10)?; - /// println!("read {} bytes: {:?}", num_bytes_read, buf); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "file_offset", since = "1.15.0")] - fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize>; - - /// Reads the exact number of byte required to fill `buf` from the given offset. - /// - /// The offset is relative to the start of the file and thus independent - /// from the current cursor. - /// - /// The current file cursor is not affected by this function. - /// - /// Similar to [`Read::read_exact`] but uses [`read_at`] instead of `read`. - /// - /// [`Read::read_exact`]: io::Read::read_exact - /// [`read_at`]: FileExt::read_at - /// - /// # Errors - /// - /// If this function encounters an error of the kind - /// [`ErrorKind::Interrupted`] then the error is ignored and the operation - /// will continue. - /// - /// If this function encounters an "end of file" before completely filling - /// the buffer, it returns an error of the kind [`ErrorKind::UnexpectedEof`]. - /// The contents of `buf` are unspecified in this case. - /// - /// If any other read error is encountered then this function immediately - /// returns. The contents of `buf` are unspecified in this case. - /// - /// If this function returns an error, it is unspecified how many bytes it - /// has read, but it will never read more than would be necessary to - /// completely fill the buffer. - /// - /// [`ErrorKind::Interrupted`]: io::ErrorKind::Interrupted - /// [`ErrorKind::UnexpectedEof`]: io::ErrorKind::UnexpectedEof - /// - /// # Examples - /// - /// ```no_run - /// #![feature(rw_exact_all_at)] - /// use std::io; - /// use std::fs::File; - /// use std::os::unix::prelude::FileExt; - /// - /// fn main() -> io::Result<()> { - /// let mut buf = [0u8; 8]; - /// let file = File::open("foo.txt")?; - /// - /// // We now read exactly 8 bytes from the offset 10. - /// file.read_exact_at(&mut buf, 10)?; - /// println!("read {} bytes: {:?}", buf.len(), buf); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "rw_exact_all_at", since = "1.33.0")] - fn read_exact_at(&self, mut buf: &mut [u8], mut offset: u64) -> io::Result<()> { - while !buf.is_empty() { - match self.read_at(buf, offset) { - Ok(0) => break, - Ok(n) => { - let tmp = buf; - buf = &mut tmp[n..]; - offset += n as u64; - } - Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {} - Err(e) => return Err(e), - } - } - if !buf.is_empty() { - Err(io::Error::new(io::ErrorKind::UnexpectedEof, "failed to fill whole buffer")) - } else { - Ok(()) - } - } - - /// Writes a number of bytes starting from a given offset. - /// - /// Returns the number of bytes written. - /// - /// The offset is relative to the start of the file and thus independent - /// from the current cursor. - /// - /// The current file cursor is not affected by this function. - /// - /// When writing beyond the end of the file, the file is appropriately - /// extended and the intermediate bytes are initialized with the value 0. - /// - /// Note that similar to [`File::write`], it is not an error to return a - /// short write. - /// - /// [`File::write`]: fs::File::write - /// - /// # Examples - /// - /// ```no_run - /// use std::fs::File; - /// use std::io; - /// use std::os::unix::prelude::FileExt; - /// - /// fn main() -> io::Result<()> { - /// let file = File::open("foo.txt")?; - /// - /// // We now write at the offset 10. - /// file.write_at(b"sushi", 10)?; - /// Ok(()) - /// } - /// ``` - #[stable(feature = "file_offset", since = "1.15.0")] - fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize>; - - /// Attempts to write an entire buffer starting from a given offset. - /// - /// The offset is relative to the start of the file and thus independent - /// from the current cursor. - /// - /// The current file cursor is not affected by this function. - /// - /// This method will continuously call [`write_at`] until there is no more data - /// to be written or an error of non-[`ErrorKind::Interrupted`] kind is - /// returned. This method will not return until the entire buffer has been - /// successfully written or such an error occurs. The first error that is - /// not of [`ErrorKind::Interrupted`] kind generated from this method will be - /// returned. - /// - /// # Errors - /// - /// This function will return the first error of - /// non-[`ErrorKind::Interrupted`] kind that [`write_at`] returns. - /// - /// [`ErrorKind::Interrupted`]: io::ErrorKind::Interrupted - /// [`write_at`]: FileExt::write_at - /// - /// # Examples - /// - /// ```no_run - /// #![feature(rw_exact_all_at)] - /// use std::fs::File; - /// use std::io; - /// use std::os::unix::prelude::FileExt; - /// - /// fn main() -> io::Result<()> { - /// let file = File::open("foo.txt")?; - /// - /// // We now write at the offset 10. - /// file.write_all_at(b"sushi", 10)?; - /// Ok(()) - /// } - /// ``` - #[stable(feature = "rw_exact_all_at", since = "1.33.0")] - fn write_all_at(&self, mut buf: &[u8], mut offset: u64) -> io::Result<()> { - while !buf.is_empty() { - match self.write_at(buf, offset) { - Ok(0) => { - return Err(io::Error::new( - io::ErrorKind::WriteZero, - "failed to write whole buffer", - )); - } - Ok(n) => { - buf = &buf[n..]; - offset += n as u64 - } - Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {} - Err(e) => return Err(e), - } - } - Ok(()) - } -} - -#[stable(feature = "file_offset", since = "1.15.0")] -impl FileExt for fs::File { - fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> { - self.as_inner().read_at(buf, offset) - } - fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> { - self.as_inner().write_at(buf, offset) - } -} - -/// Unix-specific extensions to [`fs::Permissions`]. -#[stable(feature = "fs_ext", since = "1.1.0")] -pub trait PermissionsExt { - /// Returns the underlying raw `st_mode` bits that contain the standard - /// Unix permissions for this file. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs::File; - /// use std::os::unix::fs::PermissionsExt; - /// - /// fn main() -> std::io::Result<()> { - /// let f = File::create("foo.txt")?; - /// let metadata = f.metadata()?; - /// let permissions = metadata.permissions(); - /// - /// println!("permissions: {}", permissions.mode()); - /// Ok(()) } - /// ``` - #[stable(feature = "fs_ext", since = "1.1.0")] - fn mode(&self) -> u32; - - /// Sets the underlying raw bits for this set of permissions. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs::File; - /// use std::os::unix::fs::PermissionsExt; - /// - /// fn main() -> std::io::Result<()> { - /// let f = File::create("foo.txt")?; - /// let metadata = f.metadata()?; - /// let mut permissions = metadata.permissions(); - /// - /// permissions.set_mode(0o644); // Read/write for owner and read for others. - /// assert_eq!(permissions.mode(), 0o644); - /// Ok(()) } - /// ``` - #[stable(feature = "fs_ext", since = "1.1.0")] - fn set_mode(&mut self, mode: u32); - - /// Creates a new instance of `Permissions` from the given set of Unix - /// permission bits. - /// - /// # Examples - /// - /// ``` - /// use std::fs::Permissions; - /// use std::os::unix::fs::PermissionsExt; - /// - /// // Read/write for owner and read for others. - /// let permissions = Permissions::from_mode(0o644); - /// assert_eq!(permissions.mode(), 0o644); - /// ``` - #[stable(feature = "fs_ext", since = "1.1.0")] - fn from_mode(mode: u32) -> Self; -} - -#[stable(feature = "fs_ext", since = "1.1.0")] -impl PermissionsExt for Permissions { - fn mode(&self) -> u32 { - self.as_inner().mode() - } - - fn set_mode(&mut self, mode: u32) { - *self = Permissions::from_inner(FromInner::from_inner(mode)); - } - - fn from_mode(mode: u32) -> Permissions { - Permissions::from_inner(FromInner::from_inner(mode)) - } -} - -/// Unix-specific extensions to [`fs::OpenOptions`]. -#[stable(feature = "fs_ext", since = "1.1.0")] -pub trait OpenOptionsExt { - /// Sets the mode bits that a new file will be created with. - /// - /// If a new file is created as part of an `OpenOptions::open` call then this - /// specified `mode` will be used as the permission bits for the new file. - /// If no `mode` is set, the default of `0o666` will be used. - /// The operating system masks out bits with the system's `umask`, to produce - /// the final permissions. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs::OpenOptions; - /// use std::os::unix::fs::OpenOptionsExt; - /// - /// # fn main() { - /// let mut options = OpenOptions::new(); - /// options.mode(0o644); // Give read/write for owner and read for others. - /// let file = options.open("foo.txt"); - /// # } - /// ``` - #[stable(feature = "fs_ext", since = "1.1.0")] - fn mode(&mut self, mode: u32) -> &mut Self; - - /// Pass custom flags to the `flags` argument of `open`. - /// - /// The bits that define the access mode are masked out with `O_ACCMODE`, to - /// ensure they do not interfere with the access mode set by Rusts options. - /// - /// Custom flags can only set flags, not remove flags set by Rusts options. - /// This options overwrites any previously set custom flags. - /// - /// # Examples - /// - /// ```no_run - /// # #![feature(libc)] - /// extern crate libc; - /// use std::fs::OpenOptions; - /// use std::os::unix::fs::OpenOptionsExt; - /// - /// # fn main() { - /// let mut options = OpenOptions::new(); - /// options.write(true); - /// if cfg!(unix) { - /// options.custom_flags(libc::O_NOFOLLOW); - /// } - /// let file = options.open("foo.txt"); - /// # } - /// ``` - #[stable(feature = "open_options_ext", since = "1.10.0")] - fn custom_flags(&mut self, flags: i32) -> &mut Self; -} - -/*#[stable(feature = "fs_ext", since = "1.1.0")] -impl OpenOptionsExt for OpenOptions { - fn mode(&mut self, mode: u32) -> &mut OpenOptions { - self.as_inner_mut().mode(mode); self - } - - fn custom_flags(&mut self, flags: i32) -> &mut OpenOptions { - self.as_inner_mut().custom_flags(flags); self - } -} -*/ - -/// Unix-specific extensions to [`fs::Metadata`]. -#[stable(feature = "metadata_ext", since = "1.1.0")] -pub trait MetadataExt { - /// Returns the ID of the device containing the file. - /// - /// # Examples - /// - /// ```no_run - /// use std::io; - /// use std::fs; - /// use std::os::unix::fs::MetadataExt; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// let dev_id = meta.dev(); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "metadata_ext", since = "1.1.0")] - fn dev(&self) -> u64; - /// Returns the inode number. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::os::unix::fs::MetadataExt; - /// use std::io; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// let inode = meta.ino(); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "metadata_ext", since = "1.1.0")] - fn ino(&self) -> u64; - /// Returns the rights applied to this file. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::os::unix::fs::MetadataExt; - /// use std::io; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// let mode = meta.mode(); - /// let user_has_write_access = mode & 0o200; - /// let user_has_read_write_access = mode & 0o600; - /// let group_has_read_access = mode & 0o040; - /// let others_have_exec_access = mode & 0o001; - /// Ok(()) - /// } - /// ``` - #[stable(feature = "metadata_ext", since = "1.1.0")] - fn mode(&self) -> u32; - /// Returns the number of hard links pointing to this file. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::os::unix::fs::MetadataExt; - /// use std::io; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// let nb_hard_links = meta.nlink(); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "metadata_ext", since = "1.1.0")] - fn nlink(&self) -> u64; - /// Returns the user ID of the owner of this file. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::os::unix::fs::MetadataExt; - /// use std::io; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// let user_id = meta.uid(); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "metadata_ext", since = "1.1.0")] - fn uid(&self) -> u32; - /// Returns the group ID of the owner of this file. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::os::unix::fs::MetadataExt; - /// use std::io; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// let group_id = meta.gid(); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "metadata_ext", since = "1.1.0")] - fn gid(&self) -> u32; - /// Returns the device ID of this file (if it is a special one). - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::os::unix::fs::MetadataExt; - /// use std::io; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// let device_id = meta.rdev(); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "metadata_ext", since = "1.1.0")] - fn rdev(&self) -> u64; - /// Returns the total size of this file in bytes. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::os::unix::fs::MetadataExt; - /// use std::io; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// let file_size = meta.size(); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "metadata_ext", since = "1.1.0")] - fn size(&self) -> u64; - /// Returns the time of the last access to the file. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::os::unix::fs::MetadataExt; - /// use std::io; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// let last_access_time = meta.atime(); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "metadata_ext", since = "1.1.0")] - fn atime(&self) -> i64; - /// Returns the time of the last access to the file in nanoseconds. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::os::unix::fs::MetadataExt; - /// use std::io; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// let nano_last_access_time = meta.atime_nsec(); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "metadata_ext", since = "1.1.0")] - fn mtime(&self) -> i64; - /// Returns the time of the last modification of the file in nanoseconds. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::os::unix::fs::MetadataExt; - /// use std::io; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// let nano_last_modification_time = meta.mtime_nsec(); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "metadata_ext", since = "1.1.0")] - fn ctime(&self) -> i64; - /// Returns the time of the last status change of the file in nanoseconds. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::os::unix::fs::MetadataExt; - /// use std::io; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// let nano_last_status_change_time = meta.ctime_nsec(); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "metadata_ext", since = "1.1.0")] - fn blksize(&self) -> u64; - /// Returns the number of blocks allocated to the file, in 512-byte units. - /// - /// Please note that this may be smaller than `st_size / 512` when the file has holes. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::os::unix::fs::MetadataExt; - /// use std::io; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// let blocks = meta.blocks(); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "metadata_ext", since = "1.1.0")] - fn blocks(&self) -> u64; - #[stable(feature = "metadata_ext", since = "1.1.0")] - fn attrib(&self) -> u8; -} - -#[stable(feature = "metadata_ext", since = "1.1.0")] -impl MetadataExt for fs::Metadata { - fn dev(&self) -> u64 { - self.st_dev() - } - fn ino(&self) -> u64 { - self.st_ino() - } - fn mode(&self) -> u32 { - self.st_mode() - } - fn nlink(&self) -> u64 { - self.st_nlink() - } - fn uid(&self) -> u32 { - self.st_uid() - } - fn gid(&self) -> u32 { - self.st_gid() - } - fn rdev(&self) -> u64 { - self.st_rdev() - } - fn size(&self) -> u64 { - self.st_size() - } - fn atime(&self) -> i64 { - self.st_atime() - } - fn mtime(&self) -> i64 { - self.st_mtime() - } - fn ctime(&self) -> i64 { - self.st_ctime() - } - fn blksize(&self) -> u64 { - self.st_blksize() - } - fn blocks(&self) -> u64 { - self.st_blocks() - } - fn attrib(&self) -> u8 { - self.st_attrib() - } -} - -/// Unix-specific extensions for [`fs::FileType`]. -/// -/// Adds support for special Unix file types such as block/character devices, -/// pipes, and sockets. -#[stable(feature = "file_type_ext", since = "1.5.0")] -pub trait FileTypeExt { - /// Returns whether this file type is a block device. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::os::unix::fs::FileTypeExt; - /// use std::io; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("block_device_file")?; - /// let file_type = meta.file_type(); - /// assert!(file_type.is_block_device()); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "file_type_ext", since = "1.5.0")] - fn is_block_device(&self) -> bool; - /// Returns whether this file type is a char device. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::os::unix::fs::FileTypeExt; - /// use std::io; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("char_device_file")?; - /// let file_type = meta.file_type(); - /// assert!(file_type.is_char_device()); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "file_type_ext", since = "1.5.0")] - fn is_char_device(&self) -> bool; - /// Returns whether this file type is a fifo. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::os::unix::fs::FileTypeExt; - /// use std::io; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("fifo_file")?; - /// let file_type = meta.file_type(); - /// assert!(file_type.is_fifo()); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "file_type_ext", since = "1.5.0")] - fn is_fifo(&self) -> bool; - /// Returns whether this file type is a socket. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::os::unix::fs::FileTypeExt; - /// use std::io; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("unix.socket")?; - /// let file_type = meta.file_type(); - /// assert!(file_type.is_socket()); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "file_type_ext", since = "1.5.0")] - fn is_socket(&self) -> bool; -} - -#[stable(feature = "file_type_ext", since = "1.5.0")] -impl FileTypeExt for fs::FileType { - fn is_block_device(&self) -> bool { - self.as_inner().is(libc::S_IFBLK) - } - fn is_char_device(&self) -> bool { - self.as_inner().is(libc::S_IFCHR) - } - fn is_fifo(&self) -> bool { - self.as_inner().is(libc::S_IFIFO) - } - fn is_socket(&self) -> bool { - self.as_inner().is(libc::S_IFSOCK) - } -} - -/// Unix-specific extension methods for [`fs::DirEntry`]. -#[stable(feature = "dir_entry_ext", since = "1.1.0")] -pub trait DirEntryExt { - /// Returns the underlying `d_ino` field in the contained `dirent` - /// structure. - /// - /// # Examples - /// - /// ``` - /// use std::fs; - /// use std::os::unix::fs::DirEntryExt; - /// - /// if let Ok(entries) = fs::read_dir(".") { - /// for entry in entries { - /// if let Ok(entry) = entry { - /// // Here, `entry` is a `DirEntry`. - /// println!("{:?}: {}", entry.file_name(), entry.ino()); - /// } - /// } - /// } - /// ``` - #[stable(feature = "dir_entry_ext", since = "1.1.0")] - fn ino(&self) -> u64; -} - -#[stable(feature = "dir_entry_ext", since = "1.1.0")] -impl DirEntryExt for fs::DirEntry { - fn ino(&self) -> u64 { - self.as_inner().ino() - } -} - -/// Creates a new symbolic link on the filesystem. -/// -/// The `dst` path will be a symbolic link pointing to the `src` path. -/// -/// # Examples -/// -/// ```no_run -/// use std::os::unix::fs; -/// -/// fn main() -> std::io::Result<()> { -/// fs::symlink("a.txt", "b.txt")?; -/// Ok(()) -/// } -/// ``` -#[stable(feature = "symlink", since = "1.1.0")] -pub fn symlink<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> io::Result<()> { - sys::fs::symlink(src.as_ref(), dst.as_ref()) -} - -/// Unix-specific extensions to [`fs::DirBuilder`]. -#[stable(feature = "dir_builder", since = "1.6.0")] -pub trait DirBuilderExt { - /// Sets the mode to create new directories with. This option defaults to - /// 0o777. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs::DirBuilder; - /// use std::os::unix::fs::DirBuilderExt; - /// - /// let mut builder = DirBuilder::new(); - /// builder.mode(0o755); - /// ``` - #[stable(feature = "dir_builder", since = "1.6.0")] - fn mode(&mut self, mode: u32) -> &mut Self; -} - -#[stable(feature = "dir_builder", since = "1.6.0")] -impl DirBuilderExt for fs::DirBuilder { - fn mode(&mut self, mode: u32) -> &mut fs::DirBuilder { - self.as_inner_mut().set_mode(mode); - self - } -} diff --git a/library/std/src/sys/vxworks/ext/io.rs b/library/std/src/sys/vxworks/ext/io.rs deleted file mode 100644 index 8b5a2d12af7..00000000000 --- a/library/std/src/sys/vxworks/ext/io.rs +++ /dev/null @@ -1,208 +0,0 @@ -//! Unix-specific extensions to general I/O primitives - -#![stable(feature = "rust1", since = "1.0.0")] - -use crate::fs; -use crate::io; -use crate::net; -use crate::os::raw; -use crate::sys; -use crate::sys_common::{self, AsInner, FromInner, IntoInner}; - -/// Raw file descriptors. -#[stable(feature = "rust1", since = "1.0.0")] -pub type RawFd = raw::c_int; - -/// A trait to extract the raw unix file descriptor from an underlying -/// object. -/// -/// This is only available on unix platforms and must be imported in order -/// to call the method. Windows platforms have a corresponding `AsRawHandle` -/// and `AsRawSocket` set of traits. -#[stable(feature = "rust1", since = "1.0.0")] -pub trait AsRawFd { - /// Extracts the raw file descriptor. - /// - /// This method does **not** pass ownership of the raw file descriptor - /// to the caller. The descriptor is only guaranteed to be valid while - /// the original object has not yet been destroyed. - #[stable(feature = "rust1", since = "1.0.0")] - fn as_raw_fd(&self) -> RawFd; -} - -/// A trait to express the ability to construct an object from a raw file -/// descriptor. -#[stable(feature = "from_raw_os", since = "1.1.0")] -pub trait FromRawFd { - /// Constructs a new instance of `Self` from the given raw file - /// descriptor. - /// - /// This function **consumes ownership** of the specified file - /// descriptor. The returned object will take responsibility for closing - /// it when the object goes out of scope. - /// - /// This function is also unsafe as the primitives currently returned - /// have the contract that they are the sole owner of the file - /// descriptor they are wrapping. Usage of this function could - /// accidentally allow violating this contract which can cause memory - /// unsafety in code that relies on it being true. - #[stable(feature = "from_raw_os", since = "1.1.0")] - unsafe fn from_raw_fd(fd: RawFd) -> Self; -} - -/// A trait to express the ability to consume an object and acquire ownership of -/// its raw file descriptor. -#[stable(feature = "into_raw_os", since = "1.4.0")] -pub trait IntoRawFd { - /// Consumes this object, returning the raw underlying file descriptor. - /// - /// This function **transfers ownership** of the underlying file descriptor - /// to the caller. Callers are then the unique owners of the file descriptor - /// and must close the descriptor once it's no longer needed. - #[stable(feature = "into_raw_os", since = "1.4.0")] - fn into_raw_fd(self) -> RawFd; -} - -#[stable(feature = "raw_fd_reflexive_traits", since = "1.48.0")] -impl AsRawFd for RawFd { - fn as_raw_fd(&self) -> RawFd { - *self - } -} -#[stable(feature = "raw_fd_reflexive_traits", since = "1.48.0")] -impl IntoRawFd for RawFd { - fn into_raw_fd(self) -> RawFd { - self - } -} -#[stable(feature = "raw_fd_reflexive_traits", since = "1.48.0")] -impl FromRawFd for RawFd { - unsafe fn from_raw_fd(fd: RawFd) -> RawFd { - fd - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl AsRawFd for fs::File { - fn as_raw_fd(&self) -> RawFd { - self.as_inner().fd().raw() - } -} -#[stable(feature = "from_raw_os", since = "1.1.0")] -impl FromRawFd for fs::File { - unsafe fn from_raw_fd(fd: RawFd) -> fs::File { - fs::File::from_inner(sys::fs::File::from_inner(fd)) - } -} -#[stable(feature = "into_raw_os", since = "1.4.0")] -impl IntoRawFd for fs::File { - fn into_raw_fd(self) -> RawFd { - self.into_inner().into_fd().into_raw() - } -} - -#[stable(feature = "asraw_stdio", since = "1.21.0")] -impl AsRawFd for io::Stdin { - fn as_raw_fd(&self) -> RawFd { - libc::STDIN_FILENO - } -} - -#[stable(feature = "asraw_stdio", since = "1.21.0")] -impl AsRawFd for io::Stdout { - fn as_raw_fd(&self) -> RawFd { - libc::STDOUT_FILENO - } -} - -#[stable(feature = "asraw_stdio", since = "1.21.0")] -impl AsRawFd for io::Stderr { - fn as_raw_fd(&self) -> RawFd { - libc::STDERR_FILENO - } -} - -#[stable(feature = "asraw_stdio_locks", since = "1.35.0")] -impl<'a> AsRawFd for io::StdinLock<'a> { - fn as_raw_fd(&self) -> RawFd { - libc::STDIN_FILENO - } -} - -#[stable(feature = "asraw_stdio_locks", since = "1.35.0")] -impl<'a> AsRawFd for io::StdoutLock<'a> { - fn as_raw_fd(&self) -> RawFd { - libc::STDOUT_FILENO - } -} - -#[stable(feature = "asraw_stdio_locks", since = "1.35.0")] -impl<'a> AsRawFd for io::StderrLock<'a> { - fn as_raw_fd(&self) -> RawFd { - libc::STDERR_FILENO - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl AsRawFd for net::TcpStream { - fn as_raw_fd(&self) -> RawFd { - *self.as_inner().socket().as_inner() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl AsRawFd for net::TcpListener { - fn as_raw_fd(&self) -> RawFd { - *self.as_inner().socket().as_inner() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl AsRawFd for net::UdpSocket { - fn as_raw_fd(&self) -> RawFd { - *self.as_inner().socket().as_inner() - } -} - -#[stable(feature = "from_raw_os", since = "1.1.0")] -impl FromRawFd for net::TcpStream { - unsafe fn from_raw_fd(fd: RawFd) -> net::TcpStream { - let socket = sys::net::Socket::from_inner(fd); - net::TcpStream::from_inner(sys_common::net::TcpStream::from_inner(socket)) - } -} - -#[stable(feature = "from_raw_os", since = "1.1.0")] -impl FromRawFd for net::TcpListener { - unsafe fn from_raw_fd(fd: RawFd) -> net::TcpListener { - let socket = sys::net::Socket::from_inner(fd); - net::TcpListener::from_inner(sys_common::net::TcpListener::from_inner(socket)) - } -} - -#[stable(feature = "from_raw_os", since = "1.1.0")] -impl FromRawFd for net::UdpSocket { - unsafe fn from_raw_fd(fd: RawFd) -> net::UdpSocket { - let socket = sys::net::Socket::from_inner(fd); - net::UdpSocket::from_inner(sys_common::net::UdpSocket::from_inner(socket)) - } -} - -#[stable(feature = "into_raw_os", since = "1.4.0")] -impl IntoRawFd for net::TcpStream { - fn into_raw_fd(self) -> RawFd { - self.into_inner().into_socket().into_inner() - } -} -#[stable(feature = "into_raw_os", since = "1.4.0")] -impl IntoRawFd for net::TcpListener { - fn into_raw_fd(self) -> RawFd { - self.into_inner().into_socket().into_inner() - } -} -#[stable(feature = "into_raw_os", since = "1.4.0")] -impl IntoRawFd for net::UdpSocket { - fn into_raw_fd(self) -> RawFd { - self.into_inner().into_socket().into_inner() - } -} diff --git a/library/std/src/sys/vxworks/ext/mod.rs b/library/std/src/sys/vxworks/ext/mod.rs deleted file mode 100644 index 8fa9bd9d1e2..00000000000 --- a/library/std/src/sys/vxworks/ext/mod.rs +++ /dev/null @@ -1,24 +0,0 @@ -#![stable(feature = "rust1", since = "1.0.0")] -#![allow(missing_docs)] - -pub mod ffi; -pub mod fs; -pub mod io; -pub mod process; -pub mod raw; - -#[stable(feature = "rust1", since = "1.0.0")] -pub mod prelude { - #[doc(no_inline)] - #[stable(feature = "rust1", since = "1.0.0")] - pub use super::ffi::{OsStrExt, OsStringExt}; - #[doc(no_inline)] - #[stable(feature = "rust1", since = "1.0.0")] - pub use super::fs::{FileTypeExt, MetadataExt, OpenOptionsExt, PermissionsExt}; - #[doc(no_inline)] - #[stable(feature = "rust1", since = "1.0.0")] - pub use super::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; - #[doc(no_inline)] - #[stable(feature = "rust1", since = "1.0.0")] - pub use super::process::ExitStatusExt; -} diff --git a/library/std/src/sys/vxworks/ext/process.rs b/library/std/src/sys/vxworks/ext/process.rs deleted file mode 100644 index 3ffa5be1b3b..00000000000 --- a/library/std/src/sys/vxworks/ext/process.rs +++ /dev/null @@ -1,229 +0,0 @@ -//! Unix-specific extensions to primitives in the `std::process` module. - -#![stable(feature = "rust1", since = "1.0.0")] - -use crate::ffi::OsStr; -use crate::io; -use crate::process; -use crate::sys; -use crate::sys::vxworks::ext::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; -use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner}; - -/// Unix-specific extensions to the [`process::Command`] builder. -#[stable(feature = "rust1", since = "1.0.0")] -pub trait CommandExt { - /// Sets the child process's user ID. This translates to a - /// `setuid` call in the child process. Failure in the `setuid` - /// call will cause the spawn to fail. - #[stable(feature = "rust1", since = "1.0.0")] - fn uid(&mut self, id: u16) -> &mut process::Command; - - /// Similar to `uid`, but sets the group ID of the child process. This has - /// the same semantics as the `uid` field. - #[stable(feature = "rust1", since = "1.0.0")] - fn gid(&mut self, id: u16) -> &mut process::Command; - - /// Schedules a closure to be run just before the `exec` function is - /// invoked. - /// - /// The closure is allowed to return an I/O error whose OS error code will - /// be communicated back to the parent and returned as an error from when - /// the spawn was requested. - /// - /// Multiple closures can be registered and they will be called in order of - /// their registration. If a closure returns `Err` then no further closures - /// will be called and the spawn operation will immediately return with a - /// failure. - /// - /// # Notes and Safety - /// - /// This closure will be run in the context of the child process after a - /// `fork`. This primarily means that any modifications made to memory on - /// behalf of this closure will **not** be visible to the parent process. - /// This is often a very constrained environment where normal operations - /// like `malloc` or acquiring a mutex are not guaranteed to work (due to - /// other threads perhaps still running when the `fork` was run). - /// - /// This also means that all resources such as file descriptors and - /// memory-mapped regions got duplicated. It is your responsibility to make - /// sure that the closure does not violate library invariants by making - /// invalid use of these duplicates. - /// - /// When this closure is run, aspects such as the stdio file descriptors and - /// working directory have successfully been changed, so output to these - /// locations may not appear where intended. - #[stable(feature = "process_pre_exec", since = "1.34.0")] - unsafe fn pre_exec<F>(&mut self, f: F) -> &mut process::Command - where - F: FnMut() -> io::Result<()> + Send + Sync + 'static; - - /// Schedules a closure to be run just before the `exec` function is - /// invoked. - /// - /// This method is stable and usable, but it should be unsafe. To fix - /// that, it got deprecated in favor of the unsafe [`pre_exec`]. - /// - /// [`pre_exec`]: CommandExt::pre_exec - #[stable(feature = "process_exec", since = "1.15.0")] - #[rustc_deprecated(since = "1.37.0", reason = "should be unsafe, use `pre_exec` instead")] - fn before_exec<F>(&mut self, f: F) -> &mut process::Command - where - F: FnMut() -> io::Result<()> + Send + Sync + 'static, - { - unsafe { self.pre_exec(f) } - } - - /// Performs all the required setup by this `Command`, followed by calling - /// the `execvp` syscall. - /// - /// On success this function will not return, and otherwise it will return - /// an error indicating why the exec (or another part of the setup of the - /// `Command`) failed. - /// - /// `exec` not returning has the same implications as calling - /// [`process::exit`] – no destructors on the current stack or any other - /// thread’s stack will be run. Therefore, it is recommended to only call - /// `exec` at a point where it is fine to not run any destructors. Note, - /// that the `execvp` syscall independently guarantees that all memory is - /// freed and all file descriptors with the `CLOEXEC` option (set by default - /// on all file descriptors opened by the standard library) are closed. - /// - /// This function, unlike `spawn`, will **not** `fork` the process to create - /// a new child. Like spawn, however, the default behavior for the stdio - /// descriptors will be to inherited from the current process. - /// - /// - /// # Notes - /// - /// The process may be in a "broken state" if this function returns in - /// error. For example the working directory, environment variables, signal - /// handling settings, various user/group information, or aspects of stdio - /// file descriptors may have changed. If a "transactional spawn" is - /// required to gracefully handle errors it is recommended to use the - /// cross-platform `spawn` instead. - #[stable(feature = "process_exec2", since = "1.9.0")] - fn exec(&mut self) -> io::Error; - - /// Set executable argument - /// - /// Set the first process argument, `argv[0]`, to something other than the - /// default executable path. - #[stable(feature = "process_set_argv0", since = "1.45.0")] - fn arg0<S>(&mut self, arg: S) -> &mut process::Command - where - S: AsRef<OsStr>; -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl CommandExt for process::Command { - fn uid(&mut self, id: u16) -> &mut process::Command { - self.as_inner_mut().uid(id); - self - } - - fn gid(&mut self, id: u16) -> &mut process::Command { - self.as_inner_mut().gid(id); - self - } - - unsafe fn pre_exec<F>(&mut self, f: F) -> &mut process::Command - where - F: FnMut() -> io::Result<()> + Send + Sync + 'static, - { - self.as_inner_mut().pre_exec(Box::new(f)); - self - } - - fn exec(&mut self) -> io::Error { - self.as_inner_mut().exec(sys::process::Stdio::Inherit) - } - - fn arg0<S>(&mut self, arg: S) -> &mut process::Command - where - S: AsRef<OsStr>, - { - self.as_inner_mut().set_arg_0(arg.as_ref()); - self - } -} - -/// Unix-specific extensions to [`process::ExitStatus`]. -#[stable(feature = "rust1", since = "1.0.0")] -pub trait ExitStatusExt { - /// Creates a new `ExitStatus` from the raw underlying `i32` return value of - /// a process. - #[stable(feature = "exit_status_from", since = "1.12.0")] - fn from_raw(raw: i32) -> Self; - - /// If the process was terminated by a signal, returns that signal. - #[stable(feature = "rust1", since = "1.0.0")] - fn signal(&self) -> Option<i32>; -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl ExitStatusExt for process::ExitStatus { - fn from_raw(raw: i32) -> Self { - process::ExitStatus::from_inner(From::from(raw)) - } - - fn signal(&self) -> Option<i32> { - self.as_inner().signal() - } -} - -#[stable(feature = "process_extensions", since = "1.2.0")] -impl FromRawFd for process::Stdio { - unsafe fn from_raw_fd(fd: RawFd) -> process::Stdio { - let fd = sys::fd::FileDesc::new(fd); - let io = sys::process::Stdio::Fd(fd); - process::Stdio::from_inner(io) - } -} - -#[stable(feature = "process_extensions", since = "1.2.0")] -impl AsRawFd for process::ChildStdin { - fn as_raw_fd(&self) -> RawFd { - self.as_inner().fd().raw() - } -} - -#[stable(feature = "process_extensions", since = "1.2.0")] -impl AsRawFd for process::ChildStdout { - fn as_raw_fd(&self) -> RawFd { - self.as_inner().fd().raw() - } -} - -#[stable(feature = "process_extensions", since = "1.2.0")] -impl AsRawFd for process::ChildStderr { - fn as_raw_fd(&self) -> RawFd { - self.as_inner().fd().raw() - } -} - -#[stable(feature = "into_raw_os", since = "1.4.0")] -impl IntoRawFd for process::ChildStdin { - fn into_raw_fd(self) -> RawFd { - self.into_inner().into_fd().into_raw() - } -} - -#[stable(feature = "into_raw_os", since = "1.4.0")] -impl IntoRawFd for process::ChildStdout { - fn into_raw_fd(self) -> RawFd { - self.into_inner().into_fd().into_raw() - } -} - -#[stable(feature = "into_raw_os", since = "1.4.0")] -impl IntoRawFd for process::ChildStderr { - fn into_raw_fd(self) -> RawFd { - self.into_inner().into_fd().into_raw() - } -} - -/// Returns the OS-assigned process identifier associated with this process's parent. -#[stable(feature = "unix_ppid", since = "1.27.0")] -pub fn parent_id() -> u32 { - crate::sys::os::getppid() -} diff --git a/library/std/src/sys/vxworks/ext/raw.rs b/library/std/src/sys/vxworks/ext/raw.rs deleted file mode 100644 index 1f134f4e2d1..00000000000 --- a/library/std/src/sys/vxworks/ext/raw.rs +++ /dev/null @@ -1,5 +0,0 @@ -#![stable(feature = "raw_ext", since = "1.1.0")] - -#[doc(inline)] -#[stable(feature = "pthread_t", since = "1.8.0")] -pub use crate::sys::platform::raw::pthread_t; diff --git a/library/std/src/sys/vxworks/fd.rs b/library/std/src/sys/vxworks/fd.rs deleted file mode 100644 index d58468ad539..00000000000 --- a/library/std/src/sys/vxworks/fd.rs +++ /dev/null @@ -1,201 +0,0 @@ -#![unstable(reason = "not public", issue = "none", feature = "fd")] - -use crate::cmp; -use crate::io::{self, Initializer, IoSlice, IoSliceMut, Read}; -use crate::mem; -use crate::sys::cvt; -use crate::sys_common::AsInner; - -use libc::{self, c_int, c_void, ssize_t}; - -#[derive(Debug)] -pub struct FileDesc { - fd: c_int, -} - -// The maximum read limit on most POSIX-like systems is `SSIZE_MAX`, -// with the man page quoting that if the count of bytes to read is -// greater than `SSIZE_MAX` the result is "unspecified". -const READ_LIMIT: usize = ssize_t::MAX as usize; - -impl FileDesc { - pub fn new(fd: c_int) -> FileDesc { - FileDesc { fd: fd } - } - - pub fn raw(&self) -> c_int { - self.fd - } - - /// Extracts the actual file descriptor without closing it. - pub fn into_raw(self) -> c_int { - let fd = self.fd; - mem::forget(self); - fd - } - - pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> { - let ret = cvt(unsafe { - libc::read(self.fd, buf.as_mut_ptr() as *mut c_void, cmp::min(buf.len(), READ_LIMIT)) - })?; - Ok(ret as usize) - } - - pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> { - let ret = cvt(unsafe { - libc::readv( - self.fd, - bufs.as_ptr() as *const libc::iovec, - cmp::min(bufs.len(), c_int::MAX as usize) as c_int, - ) - })?; - Ok(ret as usize) - } - - #[inline] - pub fn is_read_vectored(&self) -> bool { - true - } - - pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> { - let mut me = self; - (&mut me).read_to_end(buf) - } - - pub fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> { - unsafe fn cvt_pread( - fd: c_int, - buf: *mut c_void, - count: usize, - offset: i64, - ) -> io::Result<isize> { - use libc::pread; - cvt(pread(fd, buf, count, offset)) - } - - unsafe { - cvt_pread( - self.fd, - buf.as_mut_ptr() as *mut c_void, - cmp::min(buf.len(), READ_LIMIT), - offset as i64, - ) - .map(|n| n as usize) - } - } - - pub fn write(&self, buf: &[u8]) -> io::Result<usize> { - let ret = cvt(unsafe { - libc::write(self.fd, buf.as_ptr() as *const c_void, cmp::min(buf.len(), READ_LIMIT)) - })?; - Ok(ret as usize) - } - - pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> { - let ret = cvt(unsafe { - libc::writev( - self.fd, - bufs.as_ptr() as *const libc::iovec, - cmp::min(bufs.len(), c_int::MAX as usize) as c_int, - ) - })?; - Ok(ret as usize) - } - - #[inline] - pub fn is_write_vectored(&self) -> bool { - true - } - - pub fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> { - unsafe fn cvt_pwrite( - fd: c_int, - buf: *const c_void, - count: usize, - offset: i64, - ) -> io::Result<isize> { - use libc::pwrite; - cvt(pwrite(fd, buf, count, offset)) - } - - unsafe { - cvt_pwrite( - self.fd, - buf.as_ptr() as *const c_void, - cmp::min(buf.len(), READ_LIMIT), - offset as i64, - ) - .map(|n| n as usize) - } - } - - pub fn get_cloexec(&self) -> io::Result<bool> { - unsafe { Ok((cvt(libc::fcntl(self.fd, libc::F_GETFD))? & libc::FD_CLOEXEC) != 0) } - } - - pub fn set_cloexec(&self) -> io::Result<()> { - unsafe { - let previous = cvt(libc::fcntl(self.fd, libc::F_GETFD))?; - let new = previous | libc::FD_CLOEXEC; - if new != previous { - cvt(libc::fcntl(self.fd, libc::F_SETFD, new))?; - } - Ok(()) - } - } - - pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { - unsafe { - let v = nonblocking as c_int; - cvt(libc::ioctl(self.fd, libc::FIONBIO, &v))?; - Ok(()) - } - } - - // refer to pxPipeDrv library documentation. - // VxWorks uses fcntl to set O_NONBLOCK to the pipes - pub fn set_nonblocking_pipe(&self, nonblocking: bool) -> io::Result<()> { - unsafe { - let mut flags = cvt(libc::fcntl(self.fd, libc::F_GETFL, 0))?; - flags = if nonblocking { flags | libc::O_NONBLOCK } else { flags & !libc::O_NONBLOCK }; - cvt(libc::fcntl(self.fd, libc::F_SETFL, flags))?; - Ok(()) - } - } - - pub fn duplicate(&self) -> io::Result<FileDesc> { - let fd = self.raw(); - match cvt(unsafe { libc::fcntl(fd, libc::F_DUPFD_CLOEXEC, 0) }) { - Ok(newfd) => Ok(FileDesc::new(newfd)), - Err(e) => return Err(e), - } - } -} - -impl<'a> Read for &'a FileDesc { - fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { - (**self).read(buf) - } - - #[inline] - unsafe fn initializer(&self) -> Initializer { - Initializer::nop() - } -} - -impl AsInner<c_int> for FileDesc { - fn as_inner(&self) -> &c_int { - &self.fd - } -} - -impl Drop for FileDesc { - fn drop(&mut self) { - // Note that errors are ignored when closing a file descriptor. The - // reason for this is that if an error occurs we don't actually know if - // the file descriptor was closed or not, and if we retried (for - // something like EINTR), we might close another valid file descriptor - // (opened after we closed ours. - let _ = unsafe { libc::close(self.fd) }; - } -} diff --git a/library/std/src/sys/vxworks/fs.rs b/library/std/src/sys/vxworks/fs.rs deleted file mode 100644 index cb761af1a25..00000000000 --- a/library/std/src/sys/vxworks/fs.rs +++ /dev/null @@ -1,624 +0,0 @@ -// copies from linuxx -use crate::ffi::{CStr, CString, OsStr, OsString}; -use crate::fmt; -use crate::io::{self, Error, ErrorKind, IoSlice, IoSliceMut, SeekFrom}; -use crate::mem; -use crate::path::{Path, PathBuf}; -use crate::ptr; -use crate::sync::Arc; -use crate::sys::fd::FileDesc; -use crate::sys::time::SystemTime; -use crate::sys::vxworks::ext::ffi::OsStrExt; -use crate::sys::vxworks::ext::ffi::OsStringExt; -use crate::sys::{cvt, cvt_r}; -use crate::sys_common::{AsInner, FromInner}; -use libc::{self, c_int, mode_t, off_t, stat64}; -use libc::{dirent, ftruncate, lseek, open, readdir_r as readdir64_r}; -pub struct File(FileDesc); - -#[derive(Clone)] -pub struct FileAttr { - stat: stat64, -} - -// all DirEntry's will have a reference to this struct -struct InnerReadDir { - dirp: Dir, - root: PathBuf, -} - -pub struct ReadDir { - inner: Arc<InnerReadDir>, - end_of_stream: bool, -} - -struct Dir(*mut libc::DIR); - -unsafe impl Send for Dir {} -unsafe impl Sync for Dir {} - -pub struct DirEntry { - entry: dirent, - dir: Arc<InnerReadDir>, -} - -#[derive(Clone, Debug)] -pub struct OpenOptions { - // generic - read: bool, - write: bool, - append: bool, - truncate: bool, - create: bool, - create_new: bool, - // system-specific - custom_flags: i32, - mode: mode_t, -} - -#[derive(Clone, PartialEq, Eq, Debug)] -pub struct FilePermissions { - mode: mode_t, -} - -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] -pub struct FileType { - mode: mode_t, -} - -#[derive(Debug)] -pub struct DirBuilder { - mode: mode_t, -} - -impl FileAttr { - pub fn size(&self) -> u64 { - self.stat.st_size as u64 - } - pub fn perm(&self) -> FilePermissions { - FilePermissions { mode: (self.stat.st_mode as mode_t) } - } - - pub fn file_type(&self) -> FileType { - FileType { mode: self.stat.st_mode as mode_t } - } - - pub fn modified(&self) -> io::Result<SystemTime> { - Ok(SystemTime::from(libc::timespec { - tv_sec: self.stat.st_mtime as libc::time_t, - tv_nsec: 0, // hack 2.0; - })) - } - - pub fn accessed(&self) -> io::Result<SystemTime> { - Ok(SystemTime::from(libc::timespec { - tv_sec: self.stat.st_atime as libc::time_t, - tv_nsec: 0, // hack - a proper fix would be better - })) - } - - pub fn created(&self) -> io::Result<SystemTime> { - Err(io::Error::new( - io::ErrorKind::Other, - "creation time is not available on this platform currently", - )) - } -} - -impl AsInner<stat64> for FileAttr { - fn as_inner(&self) -> &stat64 { - &self.stat - } -} - -impl FilePermissions { - pub fn readonly(&self) -> bool { - // check if any class (owner, group, others) has write permission - self.mode & 0o222 == 0 - } - - pub fn set_readonly(&mut self, readonly: bool) { - if readonly { - // remove write permission for all classes; equivalent to `chmod a-w <file>` - self.mode &= !0o222; - } else { - // add write permission for all classes; equivalent to `chmod a+w <file>` - self.mode |= 0o222; - } - } - pub fn mode(&self) -> u32 { - self.mode as u32 - } -} - -impl FileType { - pub fn is_dir(&self) -> bool { - self.is(libc::S_IFDIR) - } - pub fn is_file(&self) -> bool { - self.is(libc::S_IFREG) - } - pub fn is_symlink(&self) -> bool { - self.is(libc::S_IFLNK) - } - - pub fn is(&self, mode: mode_t) -> bool { - self.mode & libc::S_IFMT == mode - } -} - -impl FromInner<u32> for FilePermissions { - fn from_inner(mode: u32) -> FilePermissions { - FilePermissions { mode: mode as mode_t } - } -} - -impl fmt::Debug for ReadDir { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - // This will only be called from std::fs::ReadDir, which will add a "ReadDir()" frame. - // Thus the result will be e g 'ReadDir("/home")' - fmt::Debug::fmt(&*self.inner.root, f) - } -} - -impl Iterator for ReadDir { - type Item = io::Result<DirEntry>; - fn next(&mut self) -> Option<io::Result<DirEntry>> { - if self.end_of_stream { - return None; - } - - unsafe { - let mut ret = DirEntry { entry: mem::zeroed(), dir: Arc::clone(&self.inner) }; - let mut entry_ptr = ptr::null_mut(); - loop { - if readdir64_r(self.inner.dirp.0, &mut ret.entry, &mut entry_ptr) != 0 { - if entry_ptr.is_null() { - // We encountered an error (which will be returned in this iteration), but - // we also reached the end of the directory stream. The `end_of_stream` - // flag is enabled to make sure that we return `None` in the next iteration - // (instead of looping forever) - self.end_of_stream = true; - } - return Some(Err(Error::last_os_error())); - } - if entry_ptr.is_null() { - return None; - } - if ret.name_bytes() != b"." && ret.name_bytes() != b".." { - return Some(Ok(ret)); - } - } - } - } -} - -impl Drop for Dir { - fn drop(&mut self) { - let r = unsafe { libc::closedir(self.0) }; - debug_assert_eq!(r, 0); - } -} - -impl DirEntry { - pub fn path(&self) -> PathBuf { - use crate::sys::vxworks::ext::ffi::OsStrExt; - self.dir.root.join(OsStr::from_bytes(self.name_bytes())) - } - - pub fn file_name(&self) -> OsString { - OsStr::from_bytes(self.name_bytes()).to_os_string() - } - - pub fn metadata(&self) -> io::Result<FileAttr> { - lstat(&self.path()) - } - - pub fn file_type(&self) -> io::Result<FileType> { - lstat(&self.path()).map(|m| m.file_type()) - } - - pub fn ino(&self) -> u64 { - self.entry.d_ino as u64 - } - - fn name_bytes(&self) -> &[u8] { - unsafe { - //&*self.name - CStr::from_ptr(self.entry.d_name.as_ptr()).to_bytes() - } - } -} - -impl OpenOptions { - pub fn new() -> OpenOptions { - OpenOptions { - // generic - read: false, - write: false, - append: false, - truncate: false, - create: false, - create_new: false, - // system-specific - custom_flags: 0, - mode: 0o666, - } - } - - pub fn read(&mut self, read: bool) { - self.read = read; - } - pub fn write(&mut self, write: bool) { - self.write = write; - } - pub fn append(&mut self, append: bool) { - self.append = append; - } - pub fn truncate(&mut self, truncate: bool) { - self.truncate = truncate; - } - pub fn create(&mut self, create: bool) { - self.create = create; - } - pub fn create_new(&mut self, create_new: bool) { - self.create_new = create_new; - } - pub fn mode(&mut self, mode: u32) { - self.mode = mode as mode_t; - } - - fn get_access_mode(&self) -> io::Result<c_int> { - match (self.read, self.write, self.append) { - (true, false, false) => Ok(libc::O_RDONLY), - (false, true, false) => Ok(libc::O_WRONLY), - (true, true, false) => Ok(libc::O_RDWR), - (false, _, true) => Ok(libc::O_WRONLY | libc::O_APPEND), - (true, _, true) => Ok(libc::O_RDWR | libc::O_APPEND), - (false, false, false) => Err(Error::from_raw_os_error(libc::EINVAL)), - } - } - - fn get_creation_mode(&self) -> io::Result<c_int> { - match (self.write, self.append) { - (true, false) => {} - (false, false) => { - if self.truncate || self.create || self.create_new { - return Err(Error::from_raw_os_error(libc::EINVAL)); - } - } - (_, true) => { - if self.truncate && !self.create_new { - return Err(Error::from_raw_os_error(libc::EINVAL)); - } - } - } - - Ok(match (self.create, self.truncate, self.create_new) { - (false, false, false) => 0, - (true, false, false) => libc::O_CREAT, - (false, true, false) => libc::O_TRUNC, - (true, true, false) => libc::O_CREAT | libc::O_TRUNC, - (_, _, true) => libc::O_CREAT | libc::O_EXCL, - }) - } -} - -impl File { - pub fn open(path: &Path, opts: &OpenOptions) -> io::Result<File> { - let path = cstr(path)?; - File::open_c(&path, opts) - } - - pub fn open_c(path: &CStr, opts: &OpenOptions) -> io::Result<File> { - let flags = libc::O_CLOEXEC - | opts.get_access_mode()? - | opts.get_creation_mode()? - | (opts.custom_flags as c_int & !libc::O_ACCMODE); - let fd = cvt_r(|| unsafe { open(path.as_ptr(), flags, opts.mode as c_int) })?; - Ok(File(FileDesc::new(fd))) - } - - pub fn file_attr(&self) -> io::Result<FileAttr> { - let mut stat: stat64 = unsafe { mem::zeroed() }; - cvt(unsafe { ::libc::fstat(self.0.raw(), &mut stat) })?; - Ok(FileAttr { stat: stat }) - } - - pub fn fsync(&self) -> io::Result<()> { - cvt_r(|| unsafe { libc::fsync(self.0.raw()) })?; - Ok(()) - } - - pub fn datasync(&self) -> io::Result<()> { - cvt_r(|| unsafe { os_datasync(self.0.raw()) })?; - return Ok(()); - unsafe fn os_datasync(fd: c_int) -> c_int { - libc::fsync(fd) - } //not supported - } - - pub fn truncate(&self, size: u64) -> io::Result<()> { - return cvt_r(|| unsafe { ftruncate(self.0.raw(), size as off_t) }).map(drop); - } - - pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> { - self.0.read(buf) - } - - pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> { - self.0.read_vectored(bufs) - } - - #[inline] - pub fn is_read_vectored(&self) -> bool { - self.0.is_read_vectored() - } - - pub fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> { - self.0.read_at(buf, offset) - } - - pub fn write(&self, buf: &[u8]) -> io::Result<usize> { - self.0.write(buf) - } - - pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> { - self.0.write_vectored(bufs) - } - - #[inline] - pub fn is_write_vectored(&self) -> bool { - self.0.is_write_vectored() - } - - pub fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> { - self.0.write_at(buf, offset) - } - - pub fn flush(&self) -> io::Result<()> { - Ok(()) - } - - pub fn seek(&self, pos: SeekFrom) -> io::Result<u64> { - let (whence, pos) = match pos { - // Casting to `i64` is fine, too large values will end up as - // negative which will cause an error in `"lseek64"`. - SeekFrom::Start(off) => (libc::SEEK_SET, off as i64), - SeekFrom::End(off) => (libc::SEEK_END, off), - SeekFrom::Current(off) => (libc::SEEK_CUR, off), - }; - let n = cvt(unsafe { lseek(self.0.raw(), pos, whence) })?; - Ok(n as u64) - } - - pub fn duplicate(&self) -> io::Result<File> { - self.0.duplicate().map(File) - } - - pub fn fd(&self) -> &FileDesc { - &self.0 - } - - pub fn into_fd(self) -> FileDesc { - self.0 - } - - pub fn set_permissions(&self, perm: FilePermissions) -> io::Result<()> { - cvt_r(|| unsafe { libc::fchmod(self.0.raw(), perm.mode) })?; - Ok(()) - } - - pub fn diverge(&self) -> ! { - panic!() - } -} - -impl DirBuilder { - pub fn new() -> DirBuilder { - DirBuilder { mode: 0o777 } - } - - pub fn mkdir(&self, p: &Path) -> io::Result<()> { - let p = cstr(p)?; - cvt(unsafe { libc::mkdir(p.as_ptr(), self.mode) })?; - Ok(()) - } - - pub fn set_mode(&mut self, mode: u32) { - self.mode = mode as mode_t; - } -} - -fn cstr(path: &Path) -> io::Result<CString> { - use crate::sys::vxworks::ext::ffi::OsStrExt; - Ok(CString::new(path.as_os_str().as_bytes())?) -} - -impl FromInner<c_int> for File { - fn from_inner(fd: c_int) -> File { - File(FileDesc::new(fd)) - } -} - -impl fmt::Debug for File { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fn get_path(fd: c_int) -> Option<PathBuf> { - let mut buf = vec![0; libc::PATH_MAX as usize]; - let n = unsafe { libc::ioctl(fd, libc::FIOGETNAME, buf.as_ptr()) }; - if n == -1 { - return None; - } - let l = buf.iter().position(|&c| c == 0).unwrap(); - buf.truncate(l as usize); - Some(PathBuf::from(OsString::from_vec(buf))) - } - fn get_mode(fd: c_int) -> Option<(bool, bool)> { - let mode = unsafe { libc::fcntl(fd, libc::F_GETFL) }; - if mode == -1 { - return None; - } - match mode & libc::O_ACCMODE { - libc::O_RDONLY => Some((true, false)), - libc::O_RDWR => Some((true, true)), - libc::O_WRONLY => Some((false, true)), - _ => None, - } - } - - let fd = self.0.raw(); - let mut b = f.debug_struct("File"); - b.field("fd", &fd); - if let Some(path) = get_path(fd) { - b.field("path", &path); - } - if let Some((read, write)) = get_mode(fd) { - b.field("read", &read).field("write", &write); - } - b.finish() - } -} - -pub fn readdir(p: &Path) -> io::Result<ReadDir> { - let root = p.to_path_buf(); - let p = cstr(p)?; - unsafe { - let ptr = libc::opendir(p.as_ptr()); - if ptr.is_null() { - Err(Error::last_os_error()) - } else { - let inner = InnerReadDir { dirp: Dir(ptr), root }; - Ok(ReadDir { inner: Arc::new(inner), end_of_stream: false }) - } - } -} - -pub fn unlink(p: &Path) -> io::Result<()> { - let p = cstr(p)?; - cvt(unsafe { libc::unlink(p.as_ptr()) })?; - Ok(()) -} - -pub fn rename(old: &Path, new: &Path) -> io::Result<()> { - let old = cstr(old)?; - let new = cstr(new)?; - cvt(unsafe { libc::rename(old.as_ptr(), new.as_ptr()) })?; - Ok(()) -} - -pub fn set_perm(p: &Path, perm: FilePermissions) -> io::Result<()> { - let p = cstr(p)?; - cvt_r(|| unsafe { libc::chmod(p.as_ptr(), perm.mode) })?; - Ok(()) -} - -pub fn rmdir(p: &Path) -> io::Result<()> { - let p = cstr(p)?; - cvt(unsafe { libc::rmdir(p.as_ptr()) })?; - Ok(()) -} - -pub fn remove_dir_all(path: &Path) -> io::Result<()> { - let filetype = lstat(path)?.file_type(); - if filetype.is_symlink() { unlink(path) } else { remove_dir_all_recursive(path) } -} - -fn remove_dir_all_recursive(path: &Path) -> io::Result<()> { - for child in readdir(path)? { - let child = child?; - if child.file_type()?.is_dir() { - remove_dir_all_recursive(&child.path())?; - } else { - unlink(&child.path())?; - } - } - rmdir(path) -} - -pub fn readlink(p: &Path) -> io::Result<PathBuf> { - let c_path = cstr(p)?; - let p = c_path.as_ptr(); - - let mut buf = Vec::with_capacity(256); - - loop { - let buf_read = - cvt(unsafe { libc::readlink(p, buf.as_mut_ptr() as *mut _, buf.capacity()) })? as usize; - - unsafe { - buf.set_len(buf_read); - } - - if buf_read != buf.capacity() { - buf.shrink_to_fit(); - - return Ok(PathBuf::from(OsString::from_vec(buf))); - } - - // Trigger the internal buffer resizing logic of `Vec` by requiring - // more space than the current capacity. The length is guaranteed to be - // the same as the capacity due to the if statement above. - buf.reserve(1); - } -} - -pub fn symlink(src: &Path, dst: &Path) -> io::Result<()> { - let src = cstr(src)?; - let dst = cstr(dst)?; - cvt(unsafe { libc::symlink(src.as_ptr(), dst.as_ptr()) })?; - Ok(()) -} - -pub fn link(src: &Path, dst: &Path) -> io::Result<()> { - let src = cstr(src)?; - let dst = cstr(dst)?; - cvt(unsafe { libc::link(src.as_ptr(), dst.as_ptr()) })?; - Ok(()) -} - -pub fn stat(p: &Path) -> io::Result<FileAttr> { - let p = cstr(p)?; - let mut stat: stat64 = unsafe { mem::zeroed() }; - cvt(unsafe { libc::stat(p.as_ptr(), &mut stat as *mut _ as *mut _) })?; - Ok(FileAttr { stat }) -} - -pub fn lstat(p: &Path) -> io::Result<FileAttr> { - let p = cstr(p)?; - let mut stat: stat64 = unsafe { mem::zeroed() }; - cvt(unsafe { ::libc::lstat(p.as_ptr(), &mut stat as *mut _ as *mut _) })?; - Ok(FileAttr { stat }) -} - -pub fn canonicalize(p: &Path) -> io::Result<PathBuf> { - use crate::sys::vxworks::ext::ffi::OsStrExt; - let path = CString::new(p.as_os_str().as_bytes())?; - let buf; - unsafe { - let r = libc::realpath(path.as_ptr(), ptr::null_mut()); - if r.is_null() { - return Err(io::Error::last_os_error()); - } - buf = CStr::from_ptr(r).to_bytes().to_vec(); - libc::free(r as *mut _); - } - Ok(PathBuf::from(OsString::from_vec(buf))) -} - -pub fn copy(from: &Path, to: &Path) -> io::Result<u64> { - use crate::fs::File; - if !from.is_file() { - return Err(Error::new( - ErrorKind::InvalidInput, - "the source path is not an existing regular file", - )); - } - - let mut reader = File::open(from)?; - let mut writer = File::create(to)?; - let perm = reader.metadata()?.permissions(); - - let ret = io::copy(&mut reader, &mut writer)?; - writer.set_permissions(perm)?; - Ok(ret) -} diff --git a/library/std/src/sys/vxworks/io.rs b/library/std/src/sys/vxworks/io.rs deleted file mode 100644 index 0f68ebf8da9..00000000000 --- a/library/std/src/sys/vxworks/io.rs +++ /dev/null @@ -1,75 +0,0 @@ -use crate::marker::PhantomData; -use crate::slice; - -use libc::{c_void, iovec}; - -#[derive(Copy, Clone)] -#[repr(transparent)] -pub struct IoSlice<'a> { - vec: iovec, - _p: PhantomData<&'a [u8]>, -} - -impl<'a> IoSlice<'a> { - #[inline] - pub fn new(buf: &'a [u8]) -> IoSlice<'a> { - IoSlice { - vec: iovec { iov_base: buf.as_ptr() as *mut u8 as *mut c_void, iov_len: buf.len() }, - _p: PhantomData, - } - } - - #[inline] - pub fn advance(&mut self, n: usize) { - if self.vec.iov_len < n { - panic!("advancing IoSlice beyond its length"); - } - - unsafe { - self.vec.iov_len -= n; - self.vec.iov_base = self.vec.iov_base.add(n); - } - } - - #[inline] - pub fn as_slice(&self) -> &[u8] { - unsafe { slice::from_raw_parts(self.vec.iov_base as *mut u8, self.vec.iov_len) } - } -} - -pub struct IoSliceMut<'a> { - vec: iovec, - _p: PhantomData<&'a mut [u8]>, -} - -impl<'a> IoSliceMut<'a> { - #[inline] - pub fn new(buf: &'a mut [u8]) -> IoSliceMut<'a> { - IoSliceMut { - vec: iovec { iov_base: buf.as_mut_ptr() as *mut c_void, iov_len: buf.len() }, - _p: PhantomData, - } - } - - #[inline] - pub fn advance(&mut self, n: usize) { - if self.vec.iov_len < n { - panic!("advancing IoSliceMut beyond its length"); - } - - unsafe { - self.vec.iov_len -= n; - self.vec.iov_base = self.vec.iov_base.add(n); - } - } - - #[inline] - pub fn as_slice(&self) -> &[u8] { - unsafe { slice::from_raw_parts(self.vec.iov_base as *mut u8, self.vec.iov_len) } - } - - #[inline] - pub fn as_mut_slice(&mut self) -> &mut [u8] { - unsafe { slice::from_raw_parts_mut(self.vec.iov_base as *mut u8, self.vec.iov_len) } - } -} diff --git a/library/std/src/sys/vxworks/memchr.rs b/library/std/src/sys/vxworks/memchr.rs deleted file mode 100644 index 928100c92ff..00000000000 --- a/library/std/src/sys/vxworks/memchr.rs +++ /dev/null @@ -1,21 +0,0 @@ -// Original implementation taken from rust-memchr. -// Copyright 2015 Andrew Gallant, bluss and Nicolas Koch - -pub fn memchr(needle: u8, haystack: &[u8]) -> Option<usize> { - let p = unsafe { - libc::memchr( - haystack.as_ptr() as *const libc::c_void, - needle as libc::c_int, - haystack.len(), - ) - }; - if p.is_null() { None } else { Some(p as usize - (haystack.as_ptr() as usize)) } -} - -pub fn memrchr(needle: u8, haystack: &[u8]) -> Option<usize> { - fn memrchr_specific(needle: u8, haystack: &[u8]) -> Option<usize> { - core::slice::memchr::memrchr(needle, haystack) - } - - memrchr_specific(needle, haystack) -} diff --git a/library/std/src/sys/vxworks/mod.rs b/library/std/src/sys/vxworks/mod.rs index 1132a849e2f..c20edaa1a47 100644 --- a/library/std/src/sys/vxworks/mod.rs +++ b/library/std/src/sys/vxworks/mod.rs @@ -7,29 +7,53 @@ pub use self::rand::hashmap_random_keys; pub use crate::os::vxworks as platform; pub use libc::strlen; +#[macro_use] +#[path = "../unix/weak.rs"] +pub mod weak; + +#[path = "../unix/alloc.rs"] pub mod alloc; +#[path = "../unix/args.rs"] pub mod args; +#[path = "../unix/cmath.rs"] pub mod cmath; +#[path = "../unix/condvar.rs"] pub mod condvar; pub mod env; +#[path = "../unix/ext/mod.rs"] pub mod ext; +#[path = "../unix/fd.rs"] pub mod fd; +#[path = "../unix/fs.rs"] pub mod fs; +#[path = "../unix/io.rs"] pub mod io; +#[path = "../unix/memchr.rs"] pub mod memchr; +#[path = "../unix/mutex.rs"] pub mod mutex; +#[path = "../unix/net.rs"] pub mod net; +#[path = "../unix/os.rs"] pub mod os; +#[path = "../unix/path.rs"] pub mod path; +#[path = "../unix/pipe.rs"] pub mod pipe; pub mod process; pub mod rand; +#[path = "../unix/rwlock.rs"] pub mod rwlock; +#[path = "../unix/stack_overflow.rs"] pub mod stack_overflow; +#[path = "../unix/stdio.rs"] pub mod stdio; +#[path = "../unix/thread.rs"] pub mod thread; pub mod thread_local_dtor; +#[path = "../unix/thread_local_key.rs"] pub mod thread_local_key; +#[path = "../unix/time.rs"] pub mod time; pub use crate::sys_common::os_str_bytes as os_str; diff --git a/library/std/src/sys/vxworks/mutex.rs b/library/std/src/sys/vxworks/mutex.rs deleted file mode 100644 index dd7582c21a7..00000000000 --- a/library/std/src/sys/vxworks/mutex.rs +++ /dev/null @@ -1,133 +0,0 @@ -use crate::cell::UnsafeCell; -use crate::mem::MaybeUninit; - -pub struct Mutex { - inner: UnsafeCell<libc::pthread_mutex_t>, -} - -pub type MovableMutex = Box<Mutex>; - -#[inline] -pub unsafe fn raw(m: &Mutex) -> *mut libc::pthread_mutex_t { - m.inner.get() -} - -unsafe impl Send for Mutex {} -unsafe impl Sync for Mutex {} - -#[allow(dead_code)] // sys isn't exported yet -impl Mutex { - pub const fn new() -> Mutex { - // Might be moved to a different address, so it is better to avoid - // initialization of potentially opaque OS data before it landed. - // Be very careful using this newly constructed `Mutex`, reentrant - // locking is undefined behavior until `init` is called! - Mutex { inner: UnsafeCell::new(libc::PTHREAD_MUTEX_INITIALIZER) } - } - #[inline] - pub unsafe fn init(&mut self) { - // Issue #33770 - // - // A pthread mutex initialized with PTHREAD_MUTEX_INITIALIZER will have - // a type of PTHREAD_MUTEX_DEFAULT, which has undefined behavior if you - // try to re-lock it from the same thread when you already hold a lock. - // - // In practice, glibc takes advantage of this undefined behavior to - // implement hardware lock elision, which uses hardware transactional - // memory to avoid acquiring the lock. While a transaction is in - // progress, the lock appears to be unlocked. This isn't a problem for - // other threads since the transactional memory will abort if a conflict - // is detected, however no abort is generated if re-locking from the - // same thread. - // - // Since locking the same mutex twice will result in two aliasing &mut - // references, we instead create the mutex with type - // PTHREAD_MUTEX_NORMAL which is guaranteed to deadlock if we try to - // re-lock it from the same thread, thus avoiding undefined behavior. - let mut attr = MaybeUninit::<libc::pthread_mutexattr_t>::uninit(); - let r = libc::pthread_mutexattr_init(attr.as_mut_ptr()); - debug_assert_eq!(r, 0); - let r = libc::pthread_mutexattr_settype(attr.as_mut_ptr(), libc::PTHREAD_MUTEX_NORMAL); - debug_assert_eq!(r, 0); - let r = libc::pthread_mutex_init(self.inner.get(), attr.as_ptr()); - debug_assert_eq!(r, 0); - let r = libc::pthread_mutexattr_destroy(attr.as_mut_ptr()); - debug_assert_eq!(r, 0); - } - #[inline] - pub unsafe fn lock(&self) { - let r = libc::pthread_mutex_lock(self.inner.get()); - debug_assert_eq!(r, 0); - } - #[inline] - pub unsafe fn unlock(&self) { - let r = libc::pthread_mutex_unlock(self.inner.get()); - debug_assert_eq!(r, 0); - } - #[inline] - pub unsafe fn try_lock(&self) -> bool { - libc::pthread_mutex_trylock(self.inner.get()) == 0 - } - #[inline] - #[cfg(not(target_os = "dragonfly"))] - pub unsafe fn destroy(&self) { - let r = libc::pthread_mutex_destroy(self.inner.get()); - debug_assert_eq!(r, 0); - } - #[inline] - #[cfg(target_os = "dragonfly")] - pub unsafe fn destroy(&self) { - let r = libc::pthread_mutex_destroy(self.inner.get()); - // On DragonFly pthread_mutex_destroy() returns EINVAL if called on a - // mutex that was just initialized with libc::PTHREAD_MUTEX_INITIALIZER. - // Once it is used (locked/unlocked) or pthread_mutex_init() is called, - // this behaviour no longer occurs. - debug_assert!(r == 0 || r == libc::EINVAL); - } -} - -pub struct ReentrantMutex { - inner: UnsafeCell<libc::pthread_mutex_t>, -} - -unsafe impl Send for ReentrantMutex {} -unsafe impl Sync for ReentrantMutex {} - -impl ReentrantMutex { - pub const unsafe fn uninitialized() -> ReentrantMutex { - ReentrantMutex { inner: UnsafeCell::new(libc::PTHREAD_MUTEX_INITIALIZER) } - } - - pub unsafe fn init(&self) { - let mut attr = MaybeUninit::<libc::pthread_mutexattr_t>::uninit(); - let result = libc::pthread_mutexattr_init(attr.as_mut_ptr()); - debug_assert_eq!(result, 0); - let result = - libc::pthread_mutexattr_settype(attr.as_mut_ptr(), libc::PTHREAD_MUTEX_RECURSIVE); - debug_assert_eq!(result, 0); - let result = libc::pthread_mutex_init(self.inner.get(), attr.as_ptr()); - debug_assert_eq!(result, 0); - let result = libc::pthread_mutexattr_destroy(attr.as_mut_ptr()); - debug_assert_eq!(result, 0); - } - - pub unsafe fn lock(&self) { - let result = libc::pthread_mutex_lock(self.inner.get()); - debug_assert_eq!(result, 0); - } - - #[inline] - pub unsafe fn try_lock(&self) -> bool { - libc::pthread_mutex_trylock(self.inner.get()) == 0 - } - - pub unsafe fn unlock(&self) { - let result = libc::pthread_mutex_unlock(self.inner.get()); - debug_assert_eq!(result, 0); - } - - pub unsafe fn destroy(&self) { - let result = libc::pthread_mutex_destroy(self.inner.get()); - debug_assert_eq!(result, 0); - } -} diff --git a/library/std/src/sys/vxworks/net.rs b/library/std/src/sys/vxworks/net.rs deleted file mode 100644 index 7613fbec46f..00000000000 --- a/library/std/src/sys/vxworks/net.rs +++ /dev/null @@ -1,335 +0,0 @@ -#[cfg(all(test, taget_env = "gnu"))] -mod tests; - -use crate::cmp; -use crate::ffi::CStr; -use crate::io; -use crate::io::{IoSlice, IoSliceMut}; -use crate::mem; -use crate::net::{Shutdown, SocketAddr}; -use crate::str; -use crate::sys::fd::FileDesc; -use crate::sys_common::net::{getsockopt, setsockopt, sockaddr_to_addr}; -use crate::sys_common::{AsInner, FromInner, IntoInner}; -use crate::time::{Duration, Instant}; -use libc::{self, c_int, c_void, size_t, sockaddr, socklen_t, EAI_SYSTEM, MSG_PEEK}; - -pub use crate::sys::{cvt, cvt_r}; - -#[allow(unused_extern_crates)] -pub extern crate libc as netc; - -pub type wrlen_t = size_t; - -pub struct Socket(FileDesc); - -pub fn init() {} - -pub fn cvt_gai(err: c_int) -> io::Result<()> { - if err == 0 { - return Ok(()); - } - - // We may need to trigger a glibc workaround. See on_resolver_failure() for details. - on_resolver_failure(); - - if err == EAI_SYSTEM { - return Err(io::Error::last_os_error()); - } - - let detail = unsafe { - str::from_utf8(CStr::from_ptr(libc::gai_strerror(err)).to_bytes()).unwrap().to_owned() - }; - Err(io::Error::new( - io::ErrorKind::Other, - &format!("failed to lookup address information: {}", detail)[..], - )) -} - -impl Socket { - pub fn new(addr: &SocketAddr, ty: c_int) -> io::Result<Socket> { - let fam = match *addr { - SocketAddr::V4(..) => libc::AF_INET, - SocketAddr::V6(..) => libc::AF_INET6, - }; - Socket::new_raw(fam, ty) - } - - pub fn new_raw(fam: c_int, ty: c_int) -> io::Result<Socket> { - unsafe { - let fd = cvt(libc::socket(fam, ty, 0))?; - let fd = FileDesc::new(fd); - fd.set_cloexec()?; - let socket = Socket(fd); - Ok(socket) - } - } - - pub fn new_pair(_fam: c_int, _ty: c_int) -> io::Result<(Socket, Socket)> { - unimplemented!(); - } - - pub fn connect_timeout(&self, addr: &SocketAddr, timeout: Duration) -> io::Result<()> { - self.set_nonblocking(true)?; - let r = unsafe { - let (addrp, len) = addr.into_inner(); - cvt(libc::connect(self.0.raw(), addrp, len)) - }; - self.set_nonblocking(false)?; - - match r { - Ok(_) => return Ok(()), - // there's no ErrorKind for EINPROGRESS :( - Err(ref e) if e.raw_os_error() == Some(libc::EINPROGRESS) => {} - Err(e) => return Err(e), - } - - let mut pollfd = libc::pollfd { fd: self.0.raw(), events: libc::POLLOUT, revents: 0 }; - - if timeout.as_secs() == 0 && timeout.subsec_nanos() == 0 { - return Err(io::Error::new( - io::ErrorKind::InvalidInput, - "cannot set a 0 duration timeout", - )); - } - - let start = Instant::now(); - - loop { - let elapsed = start.elapsed(); - if elapsed >= timeout { - return Err(io::Error::new(io::ErrorKind::TimedOut, "connection timed out")); - } - - let timeout = timeout - elapsed; - let mut timeout = timeout - .as_secs() - .saturating_mul(1_000) - .saturating_add(timeout.subsec_nanos() as u64 / 1_000_000); - if timeout == 0 { - timeout = 1; - } - - let timeout = cmp::min(timeout, c_int::MAX as u64) as c_int; - - match unsafe { libc::poll(&mut pollfd, 1, timeout) } { - -1 => { - let err = io::Error::last_os_error(); - if err.kind() != io::ErrorKind::Interrupted { - return Err(err); - } - } - 0 => {} - _ => { - // linux returns POLLOUT|POLLERR|POLLHUP for refused connections (!), so look - // for POLLHUP rather than read readiness - if pollfd.revents & libc::POLLHUP != 0 { - let e = self.take_error()?.unwrap_or_else(|| { - io::Error::new(io::ErrorKind::Other, "no error set after POLLHUP") - }); - return Err(e); - } - - return Ok(()); - } - } - } - } - - pub fn accept(&self, storage: *mut sockaddr, len: *mut socklen_t) -> io::Result<Socket> { - let fd = cvt_r(|| unsafe { libc::accept(self.0.raw(), storage, len) })?; - let fd = FileDesc::new(fd); - fd.set_cloexec()?; - Ok(Socket(fd)) - } - - pub fn duplicate(&self) -> io::Result<Socket> { - self.0.duplicate().map(Socket) - } - - fn recv_with_flags(&self, buf: &mut [u8], flags: c_int) -> io::Result<usize> { - let ret = cvt(unsafe { - libc::recv(self.0.raw(), buf.as_mut_ptr() as *mut c_void, buf.len(), flags) - })?; - Ok(ret as usize) - } - - pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> { - self.recv_with_flags(buf, 0) - } - - pub fn peek(&self, buf: &mut [u8]) -> io::Result<usize> { - self.recv_with_flags(buf, MSG_PEEK) - } - - pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> { - self.0.read_vectored(bufs) - } - - #[inline] - pub fn is_read_vectored(&self) -> bool { - self.0.is_read_vectored() - } - - fn recv_from_with_flags( - &self, - buf: &mut [u8], - flags: c_int, - ) -> io::Result<(usize, SocketAddr)> { - let mut storage: libc::sockaddr_storage = unsafe { mem::zeroed() }; - let mut addrlen = mem::size_of_val(&storage) as libc::socklen_t; - - let n = cvt(unsafe { - libc::recvfrom( - self.0.raw(), - buf.as_mut_ptr() as *mut c_void, - buf.len(), - flags, - &mut storage as *mut _ as *mut _, - &mut addrlen, - ) - })?; - Ok((n as usize, sockaddr_to_addr(&storage, addrlen as usize)?)) - } - - pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> { - self.recv_from_with_flags(buf, 0) - } - - pub fn peek_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> { - self.recv_from_with_flags(buf, MSG_PEEK) - } - - pub fn write(&self, buf: &[u8]) -> io::Result<usize> { - self.0.write(buf) - } - - pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> { - self.0.write_vectored(bufs) - } - - #[inline] - pub fn is_write_vectored(&self) -> bool { - self.0.is_write_vectored() - } - - pub fn set_timeout(&self, dur: Option<Duration>, kind: libc::c_int) -> io::Result<()> { - let timeout = match dur { - Some(dur) => { - if dur.as_secs() == 0 && dur.subsec_nanos() == 0 { - return Err(io::Error::new( - io::ErrorKind::InvalidInput, - "cannot set a 0 duration timeout", - )); - } - - let secs = if dur.as_secs() > libc::time_t::MAX as u64 { - libc::time_t::MAX - } else { - dur.as_secs() as libc::time_t - }; - let mut timeout = libc::timeval { - tv_sec: secs, - tv_usec: (dur.subsec_nanos() / 1000) as libc::suseconds_t, - }; - if timeout.tv_sec == 0 && timeout.tv_usec == 0 { - timeout.tv_usec = 1; - } - timeout - } - None => libc::timeval { tv_sec: 0, tv_usec: 0 }, - }; - setsockopt(self, libc::SOL_SOCKET, kind, timeout) - } - - pub fn timeout(&self, kind: libc::c_int) -> io::Result<Option<Duration>> { - let raw: libc::timeval = getsockopt(self, libc::SOL_SOCKET, kind)?; - if raw.tv_sec == 0 && raw.tv_usec == 0 { - Ok(None) - } else { - let sec = raw.tv_sec as u64; - let nsec = (raw.tv_usec as u32) * 1000; - Ok(Some(Duration::new(sec, nsec))) - } - } - - pub fn shutdown(&self, how: Shutdown) -> io::Result<()> { - let how = match how { - Shutdown::Write => libc::SHUT_WR, - Shutdown::Read => libc::SHUT_RD, - Shutdown::Both => libc::SHUT_RDWR, - }; - cvt(unsafe { libc::shutdown(self.0.raw(), how) })?; - Ok(()) - } - - pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> { - setsockopt(self, libc::IPPROTO_TCP, libc::TCP_NODELAY, nodelay as c_int) - } - - pub fn nodelay(&self) -> io::Result<bool> { - let raw: c_int = getsockopt(self, libc::IPPROTO_TCP, libc::TCP_NODELAY)?; - Ok(raw != 0) - } - - pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { - let mut nonblocking = nonblocking as libc::c_int; - cvt(unsafe { libc::ioctl(*self.as_inner(), libc::FIONBIO, &mut nonblocking) }).map(drop) - } - - pub fn take_error(&self) -> io::Result<Option<io::Error>> { - let raw: c_int = getsockopt(self, libc::SOL_SOCKET, libc::SO_ERROR)?; - if raw == 0 { Ok(None) } else { Ok(Some(io::Error::from_raw_os_error(raw as i32))) } - } -} - -impl AsInner<c_int> for Socket { - fn as_inner(&self) -> &c_int { - self.0.as_inner() - } -} - -impl FromInner<c_int> for Socket { - fn from_inner(fd: c_int) -> Socket { - Socket(FileDesc::new(fd)) - } -} - -impl IntoInner<c_int> for Socket { - fn into_inner(self) -> c_int { - self.0.into_raw() - } -} - -// In versions of glibc prior to 2.26, there's a bug where the DNS resolver -// will cache the contents of /etc/resolv.conf, so changes to that file on disk -// can be ignored by a long-running program. That can break DNS lookups on e.g. -// laptops where the network comes and goes. See -// https://sourceware.org/bugzilla/show_bug.cgi?id=984. Note however that some -// distros including Debian have patched glibc to fix this for a long time. -// -// A workaround for this bug is to call the res_init libc function, to clear -// the cached configs. Unfortunately, while we believe glibc's implementation -// of res_init is thread-safe, we know that other implementations are not -// (https://github.com/rust-lang/rust/issues/43592). Code here in libstd could -// try to synchronize its res_init calls with a Mutex, but that wouldn't -// protect programs that call into libc in other ways. So instead of calling -// res_init unconditionally, we call it only when we detect we're linking -// against glibc version < 2.26. (That is, when we both know its needed and -// believe it's thread-safe). -#[cfg(target_env = "gnu")] -fn on_resolver_failure() { - /* - use crate::sys; - - // If the version fails to parse, we treat it the same as "not glibc". - if let Some(version) = sys::os::glibc_version() { - if version < (2, 26) { - unsafe { libc::res_init() }; - } - } - */ -} - -#[cfg(not(target_env = "gnu"))] -fn on_resolver_failure() {} diff --git a/library/std/src/sys/vxworks/net/tests.rs b/library/std/src/sys/vxworks/net/tests.rs deleted file mode 100644 index e7c6e348f8e..00000000000 --- a/library/std/src/sys/vxworks/net/tests.rs +++ /dev/null @@ -1,23 +0,0 @@ -use super::*; - -#[test] -fn test_res_init() { - // This mostly just tests that the weak linkage doesn't panic wildly... - res_init_if_glibc_before_2_26().unwrap(); -} - -#[test] -fn test_parse_glibc_version() { - let cases = [ - ("0.0", Some((0, 0))), - ("01.+2", Some((1, 2))), - ("3.4.5.six", Some((3, 4))), - ("1", None), - ("1.-2", None), - ("1.foo", None), - ("foo.1", None), - ]; - for &(version_str, parsed) in cases.iter() { - assert_eq!(parsed, parse_glibc_version(version_str)); - } -} diff --git a/library/std/src/sys/vxworks/os.rs b/library/std/src/sys/vxworks/os.rs deleted file mode 100644 index 08394a8d29d..00000000000 --- a/library/std/src/sys/vxworks/os.rs +++ /dev/null @@ -1,315 +0,0 @@ -use crate::error::Error as StdError; -use crate::ffi::{CStr, CString, OsStr, OsString}; -use crate::fmt; -use crate::io; -use crate::iter; -use crate::marker::PhantomData; -use crate::mem; -use crate::memchr; -use crate::path::{self, Path, PathBuf}; -use crate::slice; -use crate::str; -use crate::sys::cvt; -use crate::sys_common::mutex::{StaticMutex, StaticMutexGuard}; -use libc::{self, c_char /*,c_void */, c_int}; -/*use sys::fd; this one is probably important */ -use crate::vec; - -const TMPBUF_SZ: usize = 128; - -// This is a terrible fix -use crate::sys::os_str::Buf; -use crate::sys_common::{AsInner, FromInner, IntoInner}; - -pub trait OsStringExt { - fn from_vec(vec: Vec<u8>) -> Self; - fn into_vec(self) -> Vec<u8>; -} - -impl OsStringExt for OsString { - fn from_vec(vec: Vec<u8>) -> OsString { - FromInner::from_inner(Buf { inner: vec }) - } - fn into_vec(self) -> Vec<u8> { - self.into_inner().inner - } -} - -pub trait OsStrExt { - fn from_bytes(slice: &[u8]) -> &Self; - fn as_bytes(&self) -> &[u8]; -} - -impl OsStrExt for OsStr { - fn from_bytes(slice: &[u8]) -> &OsStr { - unsafe { mem::transmute(slice) } - } - fn as_bytes(&self) -> &[u8] { - &self.as_inner().inner - } -} - -pub fn errno() -> i32 { - unsafe { libc::errnoGet() } -} - -pub fn set_errno(e: i32) { - unsafe { - libc::errnoSet(e as c_int); - } -} - -/// Gets a detailed string description for the given error number. -pub fn error_string(errno: i32) -> String { - let mut buf = [0 as c_char; TMPBUF_SZ]; - extern "C" { - fn strerror_r(errnum: c_int, buf: *mut c_char, buflen: libc::size_t) -> c_int; - } - - let p = buf.as_mut_ptr(); - unsafe { - if strerror_r(errno as c_int, p, buf.len()) < 0 { - panic!("strerror_r failure"); - } - let p = p as *const _; - str::from_utf8(CStr::from_ptr(p).to_bytes()).unwrap().to_owned() - } -} - -pub fn getcwd() -> io::Result<PathBuf> { - let mut buf = Vec::with_capacity(512); - loop { - unsafe { - let ptr = buf.as_mut_ptr() as *mut libc::c_char; - if !libc::getcwd(ptr, buf.capacity() as libc::size_t).is_null() { - let len = CStr::from_ptr(buf.as_ptr() as *const libc::c_char).to_bytes().len(); - buf.set_len(len); - buf.shrink_to_fit(); - return Ok(PathBuf::from(OsString::from_vec(buf))); - } else { - let error = io::Error::last_os_error(); - if error.raw_os_error() != Some(libc::ERANGE) { - return Err(error); - } - } - // Trigger the internal buffer resizing logic of `Vec` by requiring - // more space than the current capacity. - let cap = buf.capacity(); - buf.set_len(cap); - buf.reserve(1); - } - } -} - -pub fn chdir(p: &path::Path) -> io::Result<()> { - let p: &OsStr = p.as_ref(); - let p = CString::new(p.as_bytes())?; - unsafe { - match libc::chdir(p.as_ptr()) == (0 as c_int) { - true => Ok(()), - false => Err(io::Error::last_os_error()), - } - } -} - -pub struct SplitPaths<'a> { - iter: iter::Map<slice::Split<'a, u8, fn(&u8) -> bool>, fn(&'a [u8]) -> PathBuf>, -} - -pub fn split_paths(unparsed: &OsStr) -> SplitPaths<'_> { - fn bytes_to_path(b: &[u8]) -> PathBuf { - PathBuf::from(<OsStr as OsStrExt>::from_bytes(b)) - } - fn is_colon(b: &u8) -> bool { - *b == b':' - } - let unparsed = unparsed.as_bytes(); - SplitPaths { - iter: unparsed - .split(is_colon as fn(&u8) -> bool) - .map(bytes_to_path as fn(&[u8]) -> PathBuf), - } -} - -impl<'a> Iterator for SplitPaths<'a> { - type Item = PathBuf; - fn next(&mut self) -> Option<PathBuf> { - self.iter.next() - } - fn size_hint(&self) -> (usize, Option<usize>) { - self.iter.size_hint() - } -} - -#[derive(Debug)] -pub struct JoinPathsError; - -pub fn join_paths<I, T>(paths: I) -> Result<OsString, JoinPathsError> -where - I: Iterator<Item = T>, - T: AsRef<OsStr>, -{ - let mut joined = Vec::new(); - let sep = b':'; - - for (i, path) in paths.enumerate() { - let path = path.as_ref().as_bytes(); - if i > 0 { - joined.push(sep) - } - if path.contains(&sep) { - return Err(JoinPathsError); - } - joined.extend_from_slice(path); - } - Ok(OsStringExt::from_vec(joined)) -} - -impl fmt::Display for JoinPathsError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - "path segment contains separator `:`".fmt(f) - } -} - -impl StdError for JoinPathsError { - #[allow(deprecated)] - fn description(&self) -> &str { - "failed to join paths" - } -} - -pub fn current_exe() -> io::Result<PathBuf> { - #[cfg(test)] - use realstd::env; - - #[cfg(not(test))] - use crate::env; - - let exe_path = env::args().next().unwrap(); - let path = Path::new(&exe_path); - path.canonicalize() -} - -pub struct Env { - iter: vec::IntoIter<(OsString, OsString)>, - _dont_send_or_sync_me: PhantomData<*mut ()>, -} - -impl Iterator for Env { - type Item = (OsString, OsString); - fn next(&mut self) -> Option<(OsString, OsString)> { - self.iter.next() - } - fn size_hint(&self) -> (usize, Option<usize>) { - self.iter.size_hint() - } -} - -pub unsafe fn environ() -> *mut *const *const c_char { - extern "C" { - static mut environ: *const *const c_char; - } - &mut environ -} - -pub unsafe fn env_lock() -> StaticMutexGuard<'static> { - // It is UB to attempt to acquire this mutex reentrantly! - static ENV_LOCK: StaticMutex = StaticMutex::new(); - ENV_LOCK.lock() -} - -/// Returns a vector of (variable, value) byte-vector pairs for all the -/// environment variables of the current process. -pub fn env() -> Env { - unsafe { - let _guard = env_lock(); - let mut environ = *environ(); - if environ.is_null() { - panic!("os::env() failure getting env string from OS: {}", io::Error::last_os_error()); - } - let mut result = Vec::new(); - while !(*environ).is_null() { - if let Some(key_value) = parse(CStr::from_ptr(*environ).to_bytes()) { - result.push(key_value); - } - environ = environ.add(1); - } - return Env { iter: result.into_iter(), _dont_send_or_sync_me: PhantomData }; - } - - fn parse(input: &[u8]) -> Option<(OsString, OsString)> { - // Strategy (copied from glibc): Variable name and value are separated - // by an ASCII equals sign '='. Since a variable name must not be - // empty, allow variable names starting with an equals sign. Skip all - // malformed lines. - if input.is_empty() { - return None; - } - let pos = memchr::memchr(b'=', &input[1..]).map(|p| p + 1); - pos.map(|p| { - ( - OsStringExt::from_vec(input[..p].to_vec()), - OsStringExt::from_vec(input[p + 1..].to_vec()), - ) - }) - } -} - -pub fn getenv(k: &OsStr) -> io::Result<Option<OsString>> { - // environment variables with a nul byte can't be set, so their value is - // always None as well - let k = CString::new(k.as_bytes())?; - unsafe { - let _guard = env_lock(); - let s = libc::getenv(k.as_ptr()) as *const libc::c_char; - let ret = if s.is_null() { - None - } else { - Some(OsStringExt::from_vec(CStr::from_ptr(s).to_bytes().to_vec())) - }; - Ok(ret) - } -} - -pub fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> { - let k = CString::new(k.as_bytes())?; - let v = CString::new(v.as_bytes())?; - - unsafe { - let _guard = env_lock(); - cvt(libc::setenv(k.as_ptr(), v.as_ptr(), 1)).map(drop) - } -} - -pub fn unsetenv(n: &OsStr) -> io::Result<()> { - let nbuf = CString::new(n.as_bytes())?; - - unsafe { - let _guard = env_lock(); - cvt(libc::unsetenv(nbuf.as_ptr())).map(drop) - } -} - -pub fn page_size() -> usize { - unsafe { libc::sysconf(libc::_SC_PAGESIZE) as usize } -} - -pub fn temp_dir() -> PathBuf { - crate::env::var_os("TMPDIR").map(PathBuf::from).unwrap_or_else(|| PathBuf::from("/tmp")) -} - -pub fn home_dir() -> Option<PathBuf> { - crate::env::var_os("HOME").or_else(|| None).map(PathBuf::from) -} - -pub fn exit(code: i32) -> ! { - unsafe { libc::exit(code as c_int) } -} - -pub fn getpid() -> u32 { - unsafe { libc::getpid() as u32 } -} - -pub fn getppid() -> u32 { - unsafe { libc::getppid() as u32 } -} diff --git a/library/std/src/sys/vxworks/path.rs b/library/std/src/sys/vxworks/path.rs deleted file mode 100644 index 840a7ae0426..00000000000 --- a/library/std/src/sys/vxworks/path.rs +++ /dev/null @@ -1,19 +0,0 @@ -use crate::ffi::OsStr; -use crate::path::Prefix; - -#[inline] -pub fn is_sep_byte(b: u8) -> bool { - b == b'/' -} - -#[inline] -pub fn is_verbatim_sep(b: u8) -> bool { - b == b'/' -} - -pub fn parse_prefix(_: &OsStr) -> Option<Prefix<'_>> { - None -} - -pub const MAIN_SEP_STR: &str = "/"; -pub const MAIN_SEP: char = '/'; diff --git a/library/std/src/sys/vxworks/pipe.rs b/library/std/src/sys/vxworks/pipe.rs deleted file mode 100644 index a18376212af..00000000000 --- a/library/std/src/sys/vxworks/pipe.rs +++ /dev/null @@ -1,107 +0,0 @@ -use crate::io::{self, IoSlice, IoSliceMut}; -use crate::mem; -use crate::sync::atomic::AtomicBool; -use crate::sys::fd::FileDesc; -use crate::sys::{cvt, cvt_r}; -use libc::{self /*, c_int apparently not used? */}; - -pub struct AnonPipe(FileDesc); - -pub fn anon_pipe() -> io::Result<(AnonPipe, AnonPipe)> { - static INVALID: AtomicBool = AtomicBool::new(false); - - let mut fds = [0; 2]; - cvt(unsafe { libc::pipe(fds.as_mut_ptr()) })?; - - let fd0 = FileDesc::new(fds[0]); - let fd1 = FileDesc::new(fds[1]); - fd0.set_cloexec()?; - fd1.set_cloexec()?; - Ok((AnonPipe(fd0), AnonPipe(fd1))) -} - -impl AnonPipe { - pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> { - self.0.read(buf) - } - - pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> { - self.0.read_vectored(bufs) - } - - #[inline] - pub fn is_read_vectored(&self) -> bool { - self.0.is_read_vectored() - } - - pub fn write(&self, buf: &[u8]) -> io::Result<usize> { - self.0.write(buf) - } - - pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> { - self.0.write_vectored(bufs) - } - - #[inline] - pub fn is_write_vectored(&self) -> bool { - self.0.is_write_vectored() - } - - pub fn fd(&self) -> &FileDesc { - &self.0 - } - pub fn into_fd(self) -> FileDesc { - self.0 - } - pub fn diverge(&self) -> ! { - panic!() - } -} - -pub fn read2(p1: AnonPipe, v1: &mut Vec<u8>, p2: AnonPipe, v2: &mut Vec<u8>) -> io::Result<()> { - // Set both pipes into nonblocking mode as we're gonna be reading from both - // in the `select` loop below, and we wouldn't want one to block the other! - let p1 = p1.into_fd(); - let p2 = p2.into_fd(); - p1.set_nonblocking_pipe(true)?; - p2.set_nonblocking_pipe(true)?; - - let mut fds: [libc::pollfd; 2] = unsafe { mem::zeroed() }; - fds[0].fd = p1.raw(); - fds[0].events = libc::POLLIN; - fds[1].fd = p2.raw(); - fds[1].events = libc::POLLIN; - loop { - // wait for either pipe to become readable using `poll` - cvt_r(|| unsafe { libc::poll(fds.as_mut_ptr(), 2, -1) })?; - - if fds[0].revents != 0 && read(&p1, v1)? { - p2.set_nonblocking_pipe(false)?; - return p2.read_to_end(v2).map(drop); - } - if fds[1].revents != 0 && read(&p2, v2)? { - p1.set_nonblocking_pipe(false)?; - return p1.read_to_end(v1).map(drop); - } - } - - // Read as much as we can from each pipe, ignoring EWOULDBLOCK or - // EAGAIN. If we hit EOF, then this will happen because the underlying - // reader will return Ok(0), in which case we'll see `Ok` ourselves. In - // this case we flip the other fd back into blocking mode and read - // whatever's leftover on that file descriptor. - fn read(fd: &FileDesc, dst: &mut Vec<u8>) -> Result<bool, io::Error> { - match fd.read_to_end(dst) { - Ok(_) => Ok(true), - Err(e) => { - if e.raw_os_error() == Some(libc::EWOULDBLOCK) - || e.raw_os_error() == Some(libc::EAGAIN) - { - Ok(false) - } else { - Err(e) - } - } - } - } -} diff --git a/library/std/src/sys/vxworks/process/mod.rs b/library/std/src/sys/vxworks/process/mod.rs index c59782ff44b..dc6130eaa24 100644 --- a/library/std/src/sys/vxworks/process/mod.rs +++ b/library/std/src/sys/vxworks/process/mod.rs @@ -1,7 +1,9 @@ -pub use self::process_common::{Command, ExitCode, ExitStatus, Stdio, StdioPipes}; -pub use self::process_inner::Process; +pub use self::process_common::{Command, CommandArgs, ExitCode, Stdio, StdioPipes}; +pub use self::process_inner::{ExitStatus, Process}; pub use crate::ffi::OsString as EnvKey; +pub use crate::sys_common::process::CommandEnvs; +#[path = "../../unix/process/process_common.rs"] mod process_common; #[path = "process_vxworks.rs"] mod process_inner; diff --git a/library/std/src/sys/vxworks/process/process_common.rs b/library/std/src/sys/vxworks/process/process_common.rs deleted file mode 100644 index 6473a0c3cec..00000000000 --- a/library/std/src/sys/vxworks/process/process_common.rs +++ /dev/null @@ -1,399 +0,0 @@ -use crate::os::unix::prelude::*; - -use crate::collections::BTreeMap; -use crate::ffi::{CStr, CString, OsStr, OsString}; -use crate::fmt; -use crate::io; -use crate::ptr; -use crate::sys::fd::FileDesc; -use crate::sys::fs::{File, OpenOptions}; -use crate::sys::pipe::{self, AnonPipe}; -use crate::sys_common::process::CommandEnv; - -use libc::{c_char, c_int, gid_t, uid_t, EXIT_FAILURE, EXIT_SUCCESS}; - -//////////////////////////////////////////////////////////////////////////////// -// Command -//////////////////////////////////////////////////////////////////////////////// - -pub struct Command { - // Currently we try hard to ensure that the call to `.exec()` doesn't - // actually allocate any memory. While many platforms try to ensure that - // memory allocation works after a fork in a multithreaded process, it's - // been observed to be buggy and somewhat unreliable, so we do our best to - // just not do it at all! - // - // Along those lines, the `argv` and `envp` raw pointers here are exactly - // what's gonna get passed to `execvp`. The `argv` array starts with the - // `program` and ends with a NULL, and the `envp` pointer, if present, is - // also null-terminated. - // - // Right now we don't support removing arguments, so there's no much fancy - // support there, but we support adding and removing environment variables, - // so a side table is used to track where in the `envp` array each key is - // located. Whenever we add a key we update it in place if it's already - // present, and whenever we remove a key we update the locations of all - // other keys. - program: CString, - args: Vec<CString>, - argv: Argv, - env: CommandEnv, - - cwd: Option<CString>, - uid: Option<uid_t>, - gid: Option<gid_t>, - saw_nul: bool, - closures: Vec<Box<dyn FnMut() -> io::Result<()> + Send + Sync>>, - stdin: Option<Stdio>, - stdout: Option<Stdio>, - stderr: Option<Stdio>, -} - -// Create a new type for `Argv`, so that we can make it `Send` and `Sync` -struct Argv(Vec<*const c_char>); - -// It is safe to make `Argv` `Send` and `Sync`, because it contains -// pointers to memory owned by `Command.args` -unsafe impl Send for Argv {} -unsafe impl Sync for Argv {} - -// passed back to std::process with the pipes connected to the child, if any -// were requested -pub struct StdioPipes { - pub stdin: Option<AnonPipe>, - pub stdout: Option<AnonPipe>, - pub stderr: Option<AnonPipe>, -} - -// passed to do_exec() with configuration of what the child stdio should look -// like -pub struct ChildPipes { - pub stdin: ChildStdio, - pub stdout: ChildStdio, - pub stderr: ChildStdio, -} - -pub enum ChildStdio { - Inherit, - Explicit(c_int), - Owned(FileDesc), -} - -pub enum Stdio { - Inherit, - Null, - MakePipe, - Fd(FileDesc), -} - -impl Command { - pub fn new(program: &OsStr) -> Command { - let mut saw_nul = false; - let program = os2c(program, &mut saw_nul); - Command { - argv: Argv(vec![program.as_ptr(), ptr::null()]), - args: vec![program.clone()], - program, - env: Default::default(), - cwd: None, - uid: None, - gid: None, - saw_nul, - closures: Vec::new(), - stdin: None, - stdout: None, - stderr: None, - } - } - - pub fn set_arg_0(&mut self, arg: &OsStr) { - // Set a new arg0 - let arg = os2c(arg, &mut self.saw_nul); - debug_assert!(self.argv.0.len() > 1); - self.argv.0[0] = arg.as_ptr(); - self.args[0] = arg; - } - - pub fn arg(&mut self, arg: &OsStr) { - // Overwrite the trailing NULL pointer in `argv` and then add a new null - // pointer. - let arg = os2c(arg, &mut self.saw_nul); - self.argv.0[self.args.len()] = arg.as_ptr(); - self.argv.0.push(ptr::null()); - - // Also make sure we keep track of the owned value to schedule a - // destructor for this memory. - self.args.push(arg); - } - - pub fn cwd(&mut self, dir: &OsStr) { - self.cwd = Some(os2c(dir, &mut self.saw_nul)); - } - pub fn uid(&mut self, id: uid_t) { - self.uid = Some(id); - } - pub fn gid(&mut self, id: gid_t) { - self.gid = Some(id); - } - - pub fn saw_nul(&self) -> bool { - self.saw_nul - } - pub fn get_argv(&self) -> &Vec<*const c_char> { - &self.argv.0 - } - - pub fn get_program(&self) -> &CStr { - &*self.program - } - - #[allow(dead_code)] - pub fn get_cwd(&self) -> &Option<CString> { - &self.cwd - } - #[allow(dead_code)] - pub fn get_uid(&self) -> Option<uid_t> { - self.uid - } - #[allow(dead_code)] - pub fn get_gid(&self) -> Option<gid_t> { - self.gid - } - - pub fn get_closures(&mut self) -> &mut Vec<Box<dyn FnMut() -> io::Result<()> + Send + Sync>> { - &mut self.closures - } - - pub unsafe fn pre_exec(&mut self, _f: Box<dyn FnMut() -> io::Result<()> + Send + Sync>) { - // Fork() is not supported in vxWorks so no way to run the closure in the new procecss. - unimplemented!(); - } - - pub fn stdin(&mut self, stdin: Stdio) { - self.stdin = Some(stdin); - } - - pub fn stdout(&mut self, stdout: Stdio) { - self.stdout = Some(stdout); - } - - pub fn stderr(&mut self, stderr: Stdio) { - self.stderr = Some(stderr); - } - - pub fn env_mut(&mut self) -> &mut CommandEnv { - &mut self.env - } - - pub fn capture_env(&mut self) -> Option<CStringArray> { - let maybe_env = self.env.capture_if_changed(); - maybe_env.map(|env| construct_envp(env, &mut self.saw_nul)) - } - #[allow(dead_code)] - pub fn env_saw_path(&self) -> bool { - self.env.have_changed_path() - } - - pub fn setup_io( - &self, - default: Stdio, - needs_stdin: bool, - ) -> io::Result<(StdioPipes, ChildPipes)> { - let null = Stdio::Null; - let default_stdin = if needs_stdin { &default } else { &null }; - let stdin = self.stdin.as_ref().unwrap_or(default_stdin); - let stdout = self.stdout.as_ref().unwrap_or(&default); - let stderr = self.stderr.as_ref().unwrap_or(&default); - let (their_stdin, our_stdin) = stdin.to_child_stdio(true)?; - let (their_stdout, our_stdout) = stdout.to_child_stdio(false)?; - let (their_stderr, our_stderr) = stderr.to_child_stdio(false)?; - let ours = StdioPipes { stdin: our_stdin, stdout: our_stdout, stderr: our_stderr }; - let theirs = ChildPipes { stdin: their_stdin, stdout: their_stdout, stderr: their_stderr }; - Ok((ours, theirs)) - } -} - -fn os2c(s: &OsStr, saw_nul: &mut bool) -> CString { - CString::new(s.as_bytes()).unwrap_or_else(|_e| { - *saw_nul = true; - CString::new("<string-with-nul>").unwrap() - }) -} - -// Helper type to manage ownership of the strings within a C-style array. -pub struct CStringArray { - items: Vec<CString>, - ptrs: Vec<*const c_char>, -} - -impl CStringArray { - pub fn with_capacity(capacity: usize) -> Self { - let mut result = CStringArray { - items: Vec::with_capacity(capacity), - ptrs: Vec::with_capacity(capacity + 1), - }; - result.ptrs.push(ptr::null()); - result - } - pub fn push(&mut self, item: CString) { - let l = self.ptrs.len(); - self.ptrs[l - 1] = item.as_ptr(); - self.ptrs.push(ptr::null()); - self.items.push(item); - } - pub fn as_ptr(&self) -> *const *const c_char { - self.ptrs.as_ptr() - } -} - -fn construct_envp(env: BTreeMap<OsString, OsString>, saw_nul: &mut bool) -> CStringArray { - let mut result = CStringArray::with_capacity(env.len()); - for (k, v) in env { - let mut k: OsString = k.into(); - - // Reserve additional space for '=' and null terminator - k.reserve_exact(v.len() + 2); - k.push("="); - k.push(&v); - - // Add the new entry into the array - if let Ok(item) = CString::new(k.into_vec()) { - result.push(item); - } else { - *saw_nul = true; - } - } - - result -} - -impl Stdio { - pub fn to_child_stdio(&self, readable: bool) -> io::Result<(ChildStdio, Option<AnonPipe>)> { - match *self { - Stdio::Inherit => Ok((ChildStdio::Inherit, None)), - - // Make sure that the source descriptors are not an stdio - // descriptor, otherwise the order which we set the child's - // descriptors may blow away a descriptor which we are hoping to - // save. For example, suppose we want the child's stderr to be the - // parent's stdout, and the child's stdout to be the parent's - // stderr. No matter which we dup first, the second will get - // overwritten prematurely. - Stdio::Fd(ref fd) => { - if fd.raw() >= 0 && fd.raw() <= libc::STDERR_FILENO { - Ok((ChildStdio::Owned(fd.duplicate()?), None)) - } else { - Ok((ChildStdio::Explicit(fd.raw()), None)) - } - } - - Stdio::MakePipe => { - let (reader, writer) = pipe::anon_pipe()?; - let (ours, theirs) = if readable { (writer, reader) } else { (reader, writer) }; - Ok((ChildStdio::Owned(theirs.into_fd()), Some(ours))) - } - - Stdio::Null => { - let mut opts = OpenOptions::new(); - opts.read(readable); - opts.write(!readable); - let path = unsafe { CStr::from_ptr("/null\0".as_ptr() as *const _) }; - let fd = File::open_c(&path, &opts)?; - Ok((ChildStdio::Owned(fd.into_fd()), None)) - } - } - } -} - -impl From<AnonPipe> for Stdio { - fn from(pipe: AnonPipe) -> Stdio { - Stdio::Fd(pipe.into_fd()) - } -} - -impl From<File> for Stdio { - fn from(file: File) -> Stdio { - Stdio::Fd(file.into_fd()) - } -} - -impl ChildStdio { - pub fn fd(&self) -> Option<c_int> { - match *self { - ChildStdio::Inherit => None, - ChildStdio::Explicit(fd) => Some(fd), - ChildStdio::Owned(ref fd) => Some(fd.raw()), - } - } -} - -impl fmt::Debug for Command { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - if self.program != self.args[0] { - write!(f, "[{:?}] ", self.program)?; - } - write!(f, "{:?}", self.args[0])?; - - for arg in &self.args[1..] { - write!(f, " {:?}", arg)?; - } - Ok(()) - } -} - -/// Unix exit statuses -#[derive(PartialEq, Eq, Clone, Copy, Debug)] -pub struct ExitStatus(c_int); - -impl ExitStatus { - pub fn new(status: c_int) -> ExitStatus { - ExitStatus(status) - } - - fn exited(&self) -> bool { - libc::WIFEXITED(self.0) - } - - pub fn success(&self) -> bool { - self.code() == Some(0) - } - - pub fn code(&self) -> Option<i32> { - if self.exited() { Some(libc::WEXITSTATUS(self.0)) } else { None } - } - - pub fn signal(&self) -> Option<i32> { - if !self.exited() { Some(libc::WTERMSIG(self.0)) } else { None } - } -} - -/// Converts a raw `c_int` to a type-safe `ExitStatus` by wrapping it without copying. -impl From<c_int> for ExitStatus { - fn from(a: c_int) -> ExitStatus { - ExitStatus(a) - } -} - -impl fmt::Display for ExitStatus { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - if let Some(code) = self.code() { - write!(f, "exit code: {}", code) - } else { - let signal = self.signal().unwrap(); - write!(f, "signal: {}", signal) - } - } -} - -#[derive(PartialEq, Eq, Clone, Copy, Debug)] -pub struct ExitCode(u8); - -impl ExitCode { - pub const SUCCESS: ExitCode = ExitCode(EXIT_SUCCESS as _); - pub const FAILURE: ExitCode = ExitCode(EXIT_FAILURE as _); - - #[inline] - pub fn as_i32(&self) -> i32 { - self.0 as i32 - } -} diff --git a/library/std/src/sys/vxworks/process/process_vxworks.rs b/library/std/src/sys/vxworks/process/process_vxworks.rs index f7e84ae3de9..69adbcdddc9 100644 --- a/library/std/src/sys/vxworks/process/process_vxworks.rs +++ b/library/std/src/sys/vxworks/process/process_vxworks.rs @@ -1,3 +1,4 @@ +use crate::fmt; use crate::io::{self, Error, ErrorKind}; use crate::sys; use crate::sys::cvt; @@ -67,7 +68,7 @@ impl Command { let _lock = sys::os::env_lock(); let ret = libc::rtpSpawn( - self.get_program().as_ptr(), + self.get_program_cstr().as_ptr(), self.get_argv().as_ptr() as *mut *const c_char, // argv c_envp as *mut *const c_char, 100 as c_int, // initial priority @@ -167,3 +168,47 @@ impl Process { } } } + +/// Unix exit statuses +#[derive(PartialEq, Eq, Clone, Copy, Debug)] +pub struct ExitStatus(c_int); + +impl ExitStatus { + pub fn new(status: c_int) -> ExitStatus { + ExitStatus(status) + } + + fn exited(&self) -> bool { + libc::WIFEXITED(self.0) + } + + pub fn success(&self) -> bool { + self.code() == Some(0) + } + + pub fn code(&self) -> Option<i32> { + if self.exited() { Some(libc::WEXITSTATUS(self.0)) } else { None } + } + + pub fn signal(&self) -> Option<i32> { + if !self.exited() { Some(libc::WTERMSIG(self.0)) } else { None } + } +} + +/// Converts a raw `c_int` to a type-safe `ExitStatus` by wrapping it without copying. +impl From<c_int> for ExitStatus { + fn from(a: c_int) -> ExitStatus { + ExitStatus(a) + } +} + +impl fmt::Display for ExitStatus { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + if let Some(code) = self.code() { + write!(f, "exit code: {}", code) + } else { + let signal = self.signal().unwrap(); + write!(f, "signal: {}", signal) + } + } +} diff --git a/library/std/src/sys/vxworks/rwlock.rs b/library/std/src/sys/vxworks/rwlock.rs deleted file mode 100644 index c90304c2b4a..00000000000 --- a/library/std/src/sys/vxworks/rwlock.rs +++ /dev/null @@ -1,114 +0,0 @@ -use crate::cell::UnsafeCell; -use crate::sync::atomic::{AtomicUsize, Ordering}; - -pub struct RWLock { - inner: UnsafeCell<libc::pthread_rwlock_t>, - write_locked: UnsafeCell<bool>, - num_readers: AtomicUsize, -} - -unsafe impl Send for RWLock {} -unsafe impl Sync for RWLock {} - -impl RWLock { - pub const fn new() -> RWLock { - RWLock { - inner: UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER), - write_locked: UnsafeCell::new(false), - num_readers: AtomicUsize::new(0), - } - } - - #[inline] - pub unsafe fn read(&self) { - let r = libc::pthread_rwlock_rdlock(self.inner.get()); - if r == libc::EAGAIN { - panic!("rwlock maximum reader count exceeded"); - } else if r == libc::EDEADLK || (r == 0 && *self.write_locked.get()) { - if r == 0 { - self.raw_unlock(); - } - panic!("rwlock read lock would result in deadlock"); - } else { - debug_assert_eq!(r, 0); - self.num_readers.fetch_add(1, Ordering::Relaxed); - } - } - - #[inline] - pub unsafe fn try_read(&self) -> bool { - let r = libc::pthread_rwlock_tryrdlock(self.inner.get()); - if r == 0 { - if *self.write_locked.get() { - self.raw_unlock(); - false - } else { - self.num_readers.fetch_add(1, Ordering::Relaxed); - true - } - } else { - false - } - } - - #[inline] - pub unsafe fn write(&self) { - let r = libc::pthread_rwlock_wrlock(self.inner.get()); - // See comments above for why we check for EDEADLK and write_locked. We - // also need to check that num_readers is 0. - if r == libc::EDEADLK - || *self.write_locked.get() - || self.num_readers.load(Ordering::Relaxed) != 0 - { - if r == 0 { - self.raw_unlock(); - } - panic!("rwlock write lock would result in deadlock"); - } else { - debug_assert_eq!(r, 0); - } - *self.write_locked.get() = true; - } - - #[inline] - pub unsafe fn try_write(&self) -> bool { - let r = libc::pthread_rwlock_trywrlock(self.inner.get()); - if r == 0 { - if *self.write_locked.get() || self.num_readers.load(Ordering::Relaxed) != 0 { - self.raw_unlock(); - false - } else { - *self.write_locked.get() = true; - true - } - } else { - false - } - } - - #[inline] - unsafe fn raw_unlock(&self) { - let r = libc::pthread_rwlock_unlock(self.inner.get()); - debug_assert_eq!(r, 0); - } - - #[inline] - pub unsafe fn read_unlock(&self) { - debug_assert!(!*self.write_locked.get()); - self.num_readers.fetch_sub(1, Ordering::Relaxed); - self.raw_unlock(); - } - - #[inline] - pub unsafe fn write_unlock(&self) { - debug_assert_eq!(self.num_readers.load(Ordering::Relaxed), 0); - debug_assert!(*self.write_locked.get()); - *self.write_locked.get() = false; - self.raw_unlock(); - } - #[inline] - pub unsafe fn destroy(&self) { - let r = libc::pthread_rwlock_destroy(self.inner.get()); - debug_assert_eq!(r, 0); - } -} diff --git a/library/std/src/sys/vxworks/stack_overflow.rs b/library/std/src/sys/vxworks/stack_overflow.rs deleted file mode 100644 index 7b58c83193b..00000000000 --- a/library/std/src/sys/vxworks/stack_overflow.rs +++ /dev/null @@ -1,38 +0,0 @@ -#![cfg_attr(test, allow(dead_code))] - -use self::imp::{drop_handler, make_handler}; - -pub use self::imp::cleanup; -pub use self::imp::init; - -pub struct Handler { - _data: *mut libc::c_void, -} - -impl Handler { - pub unsafe fn new() -> Handler { - make_handler() - } -} - -impl Drop for Handler { - fn drop(&mut self) { - unsafe { - drop_handler(self); - } - } -} - -mod imp { - use crate::ptr; - - pub unsafe fn init() {} - - pub unsafe fn cleanup() {} - - pub unsafe fn make_handler() -> super::Handler { - super::Handler { _data: ptr::null_mut() } - } - - pub unsafe fn drop_handler(_handler: &mut super::Handler) {} -} diff --git a/library/std/src/sys/vxworks/stdio.rs b/library/std/src/sys/vxworks/stdio.rs deleted file mode 100644 index 92e9f205b4e..00000000000 --- a/library/std/src/sys/vxworks/stdio.rs +++ /dev/null @@ -1,69 +0,0 @@ -use crate::io; -use crate::sys::fd::FileDesc; - -pub struct Stdin(()); -pub struct Stdout(()); -pub struct Stderr(()); - -impl Stdin { - pub const fn new() -> Stdin { - Stdin(()) - } -} - -impl io::Read for Stdin { - fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { - let fd = FileDesc::new(libc::STDIN_FILENO); - let ret = fd.read(buf); - fd.into_raw(); // do not close this FD - ret - } -} - -impl Stdout { - pub const fn new() -> Stdout { - Stdout(()) - } -} - -impl io::Write for Stdout { - fn write(&mut self, buf: &[u8]) -> io::Result<usize> { - let fd = FileDesc::new(libc::STDOUT_FILENO); - let ret = fd.write(buf); - fd.into_raw(); // do not close this FD - ret - } - - fn flush(&mut self) -> io::Result<()> { - Ok(()) - } -} - -impl Stderr { - pub const fn new() -> Stderr { - Stderr(()) - } -} - -impl io::Write for Stderr { - fn write(&mut self, buf: &[u8]) -> io::Result<usize> { - let fd = FileDesc::new(libc::STDERR_FILENO); - let ret = fd.write(buf); - fd.into_raw(); // do not close this FD - ret - } - - fn flush(&mut self) -> io::Result<()> { - Ok(()) - } -} - -pub fn is_ebadf(err: &io::Error) -> bool { - err.raw_os_error() == Some(libc::EBADF as i32) -} - -pub const STDIN_BUF_SIZE: usize = crate::sys_common::io::DEFAULT_BUF_SIZE; - -pub fn panic_output() -> Option<impl io::Write> { - Some(Stderr::new()) -} diff --git a/library/std/src/sys/vxworks/thread.rs b/library/std/src/sys/vxworks/thread.rs deleted file mode 100644 index 24a2e0f965d..00000000000 --- a/library/std/src/sys/vxworks/thread.rs +++ /dev/null @@ -1,155 +0,0 @@ -use crate::cmp; -use crate::ffi::CStr; -use crate::io; -use crate::mem; -use crate::ptr; -use crate::sys::{os, stack_overflow}; -use crate::time::Duration; - -pub const DEFAULT_MIN_STACK_SIZE: usize = 0x40000; // 256K - -pub struct Thread { - id: libc::pthread_t, -} - -// Some platforms may have pthread_t as a pointer in which case we still want -// a thread to be Send/Sync -unsafe impl Send for Thread {} -unsafe impl Sync for Thread {} - -// The pthread_attr_setstacksize symbol doesn't exist in the emscripten libc, -// so we have to not link to it to satisfy emcc's ERROR_ON_UNDEFINED_SYMBOLS. -unsafe fn pthread_attr_setstacksize( - attr: *mut libc::pthread_attr_t, - stack_size: libc::size_t, -) -> libc::c_int { - libc::pthread_attr_setstacksize(attr, stack_size) -} - -impl Thread { - // unsafe: see thread::Builder::spawn_unchecked for safety requirements - pub unsafe fn new(stack: usize, p: Box<dyn FnOnce()>) -> io::Result<Thread> { - let p = Box::into_raw(box p); - let mut native: libc::pthread_t = mem::zeroed(); - let mut attr: libc::pthread_attr_t = mem::zeroed(); - assert_eq!(libc::pthread_attr_init(&mut attr), 0); - - let stack_size = cmp::max(stack, min_stack_size(&attr)); - - match pthread_attr_setstacksize(&mut attr, stack_size) { - 0 => {} - n => { - assert_eq!(n, libc::EINVAL); - // EINVAL means |stack_size| is either too small or not a - // multiple of the system page size. Because it's definitely - // >= PTHREAD_STACK_MIN, it must be an alignment issue. - // Round up to the nearest page and try again. - let page_size = os::page_size(); - let stack_size = - (stack_size + page_size - 1) & (-(page_size as isize - 1) as usize - 1); - assert_eq!(libc::pthread_attr_setstacksize(&mut attr, stack_size), 0); - } - }; - - let ret = libc::pthread_create(&mut native, &attr, thread_start, p as *mut _); - // Note: if the thread creation fails and this assert fails, then p will - // be leaked. However, an alternative design could cause double-free - // which is clearly worse. - assert_eq!(libc::pthread_attr_destroy(&mut attr), 0); - - return if ret != 0 { - // The thread failed to start and as a result p was not consumed. Therefore, it is - // safe to reconstruct the box so that it gets deallocated. - drop(Box::from_raw(p)); - Err(io::Error::from_raw_os_error(ret)) - } else { - Ok(Thread { id: native }) - }; - - extern "C" fn thread_start(main: *mut libc::c_void) -> *mut libc::c_void { - unsafe { - // Next, set up our stack overflow handler which may get triggered if we run - // out of stack. - let _handler = stack_overflow::Handler::new(); - // Finally, let's run some code. - Box::from_raw(main as *mut Box<dyn FnOnce()>)(); - } - ptr::null_mut() - } - } - - pub fn yield_now() { - let ret = unsafe { libc::sched_yield() }; - debug_assert_eq!(ret, 0); - } - - pub fn set_name(_name: &CStr) { - // VxWorks does not provide a way to set the task name except at creation time - } - - pub fn sleep(dur: Duration) { - let mut secs = dur.as_secs(); - let mut nsecs = dur.subsec_nanos() as _; - - // If we're awoken with a signal then the return value will be -1 and - // nanosleep will fill in `ts` with the remaining time. - unsafe { - while secs > 0 || nsecs > 0 { - let mut ts = libc::timespec { - tv_sec: cmp::min(libc::time_t::MAX as u64, secs) as libc::time_t, - tv_nsec: nsecs, - }; - secs -= ts.tv_sec as u64; - if libc::nanosleep(&ts, &mut ts) == -1 { - assert_eq!(os::errno(), libc::EINTR); - secs += ts.tv_sec as u64; - nsecs = ts.tv_nsec; - } else { - nsecs = 0; - } - } - } - } - - pub fn join(self) { - unsafe { - let ret = libc::pthread_join(self.id, ptr::null_mut()); - mem::forget(self); - assert!(ret == 0, "failed to join thread: {}", io::Error::from_raw_os_error(ret)); - } - } - - pub fn id(&self) -> libc::pthread_t { - self.id - } - - pub fn into_id(self) -> libc::pthread_t { - let id = self.id; - mem::forget(self); - id - } -} - -impl Drop for Thread { - fn drop(&mut self) { - let ret = unsafe { libc::pthread_detach(self.id) }; - debug_assert_eq!(ret, 0); - } -} - -#[cfg_attr(test, allow(dead_code))] -pub mod guard { - use crate::ops::Range; - pub type Guard = Range<usize>; - pub unsafe fn current() -> Option<Guard> { - None - } - pub unsafe fn init() -> Option<Guard> { - None - } - pub unsafe fn deinit() {} -} - -fn min_stack_size(_: *const libc::pthread_attr_t) -> usize { - libc::PTHREAD_STACK_MIN -} diff --git a/library/std/src/sys/vxworks/thread_local_key.rs b/library/std/src/sys/vxworks/thread_local_key.rs deleted file mode 100644 index 2c5b94b1e61..00000000000 --- a/library/std/src/sys/vxworks/thread_local_key.rs +++ /dev/null @@ -1,34 +0,0 @@ -#![allow(dead_code)] // not used on all platforms - -use crate::mem; - -pub type Key = libc::pthread_key_t; - -#[inline] -pub unsafe fn create(dtor: Option<unsafe extern "C" fn(*mut u8)>) -> Key { - let mut key = 0; - assert_eq!(libc::pthread_key_create(&mut key, mem::transmute(dtor)), 0); - key -} - -#[inline] -pub unsafe fn set(key: Key, value: *mut u8) { - let r = libc::pthread_setspecific(key, value as *mut _); - debug_assert_eq!(r, 0); -} - -#[inline] -pub unsafe fn get(key: Key) -> *mut u8 { - libc::pthread_getspecific(key) as *mut u8 -} - -#[inline] -pub unsafe fn destroy(key: Key) { - let r = libc::pthread_key_delete(key); - debug_assert_eq!(r, 0); -} - -#[inline] -pub fn requires_synchronized_create() -> bool { - false -} diff --git a/library/std/src/sys/vxworks/time.rs b/library/std/src/sys/vxworks/time.rs deleted file mode 100644 index 8f46f4d284f..00000000000 --- a/library/std/src/sys/vxworks/time.rs +++ /dev/null @@ -1,197 +0,0 @@ -use crate::cmp::Ordering; -use crate::time::Duration; -use core::hash::{Hash, Hasher}; - -pub use self::inner::{Instant, SystemTime, UNIX_EPOCH}; -use crate::convert::TryInto; - -const NSEC_PER_SEC: u64 = 1_000_000_000; - -#[derive(Copy, Clone)] -struct Timespec { - t: libc::timespec, -} - -impl Timespec { - const fn zero() -> Timespec { - Timespec { t: libc::timespec { tv_sec: 0, tv_nsec: 0 } } - } - fn sub_timespec(&self, other: &Timespec) -> Result<Duration, Duration> { - if self >= other { - Ok(if self.t.tv_nsec >= other.t.tv_nsec { - Duration::new( - (self.t.tv_sec - other.t.tv_sec) as u64, - (self.t.tv_nsec - other.t.tv_nsec) as u32, - ) - } else { - Duration::new( - (self.t.tv_sec - 1 - other.t.tv_sec) as u64, - self.t.tv_nsec as u32 + (NSEC_PER_SEC as u32) - other.t.tv_nsec as u32, - ) - }) - } else { - match other.sub_timespec(self) { - Ok(d) => Err(d), - Err(d) => Ok(d), - } - } - } - - fn checked_add_duration(&self, other: &Duration) -> Option<Timespec> { - let mut secs = other - .as_secs() - .try_into() // <- target type would be `libc::time_t` - .ok() - .and_then(|secs| self.t.tv_sec.checked_add(secs))?; - - // Nano calculations can't overflow because nanos are <1B which fit - // in a u32. - let mut nsec = other.subsec_nanos() + self.t.tv_nsec as u32; - if nsec >= NSEC_PER_SEC as u32 { - nsec -= NSEC_PER_SEC as u32; - secs = secs.checked_add(1)?; - } - Some(Timespec { t: libc::timespec { tv_sec: secs, tv_nsec: nsec as _ } }) - } - - fn checked_sub_duration(&self, other: &Duration) -> Option<Timespec> { - let mut secs = other - .as_secs() - .try_into() // <- target type would be `libc::time_t` - .ok() - .and_then(|secs| self.t.tv_sec.checked_sub(secs))?; - - // Similar to above, nanos can't overflow. - let mut nsec = self.t.tv_nsec as i32 - other.subsec_nanos() as i32; - if nsec < 0 { - nsec += NSEC_PER_SEC as i32; - secs = secs.checked_sub(1)?; - } - Some(Timespec { t: libc::timespec { tv_sec: secs, tv_nsec: nsec as _ } }) - } -} - -impl PartialEq for Timespec { - fn eq(&self, other: &Timespec) -> bool { - self.t.tv_sec == other.t.tv_sec && self.t.tv_nsec == other.t.tv_nsec - } -} - -impl Eq for Timespec {} - -impl PartialOrd for Timespec { - fn partial_cmp(&self, other: &Timespec) -> Option<Ordering> { - Some(self.cmp(other)) - } -} - -impl Ord for Timespec { - fn cmp(&self, other: &Timespec) -> Ordering { - let me = (self.t.tv_sec, self.t.tv_nsec); - let other = (other.t.tv_sec, other.t.tv_nsec); - me.cmp(&other) - } -} - -impl Hash for Timespec { - fn hash<H: Hasher>(&self, state: &mut H) { - self.t.tv_sec.hash(state); - self.t.tv_nsec.hash(state); - } -} -mod inner { - use crate::fmt; - use crate::sys::cvt; - use crate::time::Duration; - - use super::Timespec; - - #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] - pub struct Instant { - t: Timespec, - } - - #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] - pub struct SystemTime { - t: Timespec, - } - - pub const UNIX_EPOCH: SystemTime = - SystemTime { t: Timespec { t: libc::timespec { tv_sec: 0, tv_nsec: 0 } } }; - - impl Instant { - pub fn now() -> Instant { - Instant { t: now(libc::CLOCK_MONOTONIC) } - } - - pub const fn zero() -> Instant { - Instant { t: Timespec::zero() } - } - - pub fn actually_monotonic() -> bool { - true - } - - pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> { - self.t.sub_timespec(&other.t).ok() - } - - pub fn checked_add_duration(&self, other: &Duration) -> Option<Instant> { - Some(Instant { t: self.t.checked_add_duration(other)? }) - } - - pub fn checked_sub_duration(&self, other: &Duration) -> Option<Instant> { - Some(Instant { t: self.t.checked_sub_duration(other)? }) - } - } - - impl fmt::Debug for Instant { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Instant") - .field("tv_sec", &self.t.t.tv_sec) - .field("tv_nsec", &self.t.t.tv_nsec) - .finish() - } - } - - impl SystemTime { - pub fn now() -> SystemTime { - SystemTime { t: now(libc::CLOCK_REALTIME) } - } - - pub fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> { - self.t.sub_timespec(&other.t) - } - - pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> { - Some(SystemTime { t: self.t.checked_add_duration(other)? }) - } - - pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> { - Some(SystemTime { t: self.t.checked_sub_duration(other)? }) - } - } - - impl From<libc::timespec> for SystemTime { - fn from(t: libc::timespec) -> SystemTime { - SystemTime { t: Timespec { t: t } } - } - } - - impl fmt::Debug for SystemTime { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("SystemTime") - .field("tv_sec", &self.t.t.tv_sec) - .field("tv_nsec", &self.t.t.tv_nsec) - .finish() - } - } - - pub type clock_t = libc::c_int; - - fn now(clock: clock_t) -> Timespec { - let mut t = Timespec { t: libc::timespec { tv_sec: 0, tv_nsec: 0 } }; - cvt(unsafe { libc::clock_gettime(clock, &mut t.t) }).unwrap(); - t - } -} diff --git a/library/std/src/sys/wasi/ext/io.rs b/library/std/src/sys/wasi/ext/io.rs index 661214e8f4c..81413f39dc1 100644 --- a/library/std/src/sys/wasi/ext/io.rs +++ b/library/std/src/sys/wasi/ext/io.rs @@ -160,3 +160,21 @@ impl AsRawFd for io::Stderr { sys::stdio::Stderr.as_raw_fd() } } + +impl<'a> AsRawFd for io::StdinLock<'a> { + fn as_raw_fd(&self) -> RawFd { + sys::stdio::Stdin.as_raw_fd() + } +} + +impl<'a> AsRawFd for io::StdoutLock<'a> { + fn as_raw_fd(&self) -> RawFd { + sys::stdio::Stdout.as_raw_fd() + } +} + +impl<'a> AsRawFd for io::StderrLock<'a> { + fn as_raw_fd(&self) -> RawFd { + sys::stdio::Stderr.as_raw_fd() + } +} diff --git a/library/std/src/sys/wasi/mod.rs b/library/std/src/sys/wasi/mod.rs index a7a4407ac38..a0a37ef8316 100644 --- a/library/std/src/sys/wasi/mod.rs +++ b/library/std/src/sys/wasi/mod.rs @@ -53,6 +53,7 @@ pub mod thread_local_key; pub mod time; #[path = "../unsupported/common.rs"] +#[deny(unsafe_op_in_unsafe_fn)] #[allow(unused)] mod common; pub use common::*; diff --git a/library/std/src/sys/wasm/futex_atomics.rs b/library/std/src/sys/wasm/futex_atomics.rs new file mode 100644 index 00000000000..3d8bf42f725 --- /dev/null +++ b/library/std/src/sys/wasm/futex_atomics.rs @@ -0,0 +1,17 @@ +use crate::arch::wasm32; +use crate::convert::TryInto; +use crate::sync::atomic::AtomicI32; +use crate::time::Duration; + +pub fn futex_wait(futex: &AtomicI32, expected: i32, timeout: Option<Duration>) { + let timeout = timeout.and_then(|t| t.as_nanos().try_into().ok()).unwrap_or(-1); + unsafe { + wasm32::memory_atomic_wait32(futex as *const AtomicI32 as *mut i32, expected, timeout); + } +} + +pub fn futex_wake(futex: &AtomicI32) { + unsafe { + wasm32::memory_atomic_notify(futex as *const AtomicI32 as *mut i32, 1); + } +} diff --git a/library/std/src/sys/wasm/mod.rs b/library/std/src/sys/wasm/mod.rs index 2934ea59ab5..11c6896f050 100644 --- a/library/std/src/sys/wasm/mod.rs +++ b/library/std/src/sys/wasm/mod.rs @@ -55,6 +55,8 @@ cfg_if::cfg_if! { pub mod mutex; #[path = "rwlock_atomics.rs"] pub mod rwlock; + #[path = "futex_atomics.rs"] + pub mod futex; } else { #[path = "../unsupported/condvar.rs"] pub mod condvar; @@ -66,5 +68,6 @@ cfg_if::cfg_if! { } #[path = "../unsupported/common.rs"] +#[deny(unsafe_op_in_unsafe_fn)] mod common; pub use common::*; diff --git a/library/std/src/sys_common/backtrace.rs b/library/std/src/sys_common/backtrace.rs index 1c5fbf7d701..a549770d8b3 100644 --- a/library/std/src/sys_common/backtrace.rs +++ b/library/std/src/sys_common/backtrace.rs @@ -8,27 +8,15 @@ use crate::io; use crate::io::prelude::*; use crate::path::{self, Path, PathBuf}; use crate::sync::atomic::{self, Ordering}; -use crate::sys::mutex::Mutex; +use crate::sys_common::mutex::StaticMutex; /// Max number of frames to print. const MAX_NB_FRAMES: usize = 100; -pub fn lock() -> impl Drop { - struct Guard; - static LOCK: Mutex = Mutex::new(); - - impl Drop for Guard { - fn drop(&mut self) { - unsafe { - LOCK.unlock(); - } - } - } - - unsafe { - LOCK.lock(); - Guard - } +// SAFETY: Don't attempt to lock this reentrantly. +pub unsafe fn lock() -> impl Drop { + static LOCK: StaticMutex = StaticMutex::new(); + LOCK.lock() } /// Prints the current backtrace. diff --git a/library/std/src/sys_common/mutex.rs b/library/std/src/sys_common/mutex.rs index a1e11d24465..f3e7efb955a 100644 --- a/library/std/src/sys_common/mutex.rs +++ b/library/std/src/sys_common/mutex.rs @@ -3,8 +3,7 @@ use crate::sys::mutex as imp; /// An OS-based mutual exclusion lock, meant for use in static variables. /// /// This mutex has a const constructor ([`StaticMutex::new`]), does not -/// implement `Drop` to cleanup resources, and causes UB when moved or used -/// reentrantly. +/// implement `Drop` to cleanup resources, and causes UB when used reentrantly. /// /// This mutex does not implement poisoning. /// @@ -16,12 +15,6 @@ unsafe impl Sync for StaticMutex {} impl StaticMutex { /// Creates a new mutex for use. - /// - /// Behavior is undefined if the mutex is moved after it is - /// first used with any of the functions below. - /// Also, the behavior is undefined if this mutex is ever used reentrantly, - /// i.e., `lock` is called by the thread currently holding the lock. - #[rustc_const_stable(feature = "const_sys_mutex_new", since = "1.0.0")] pub const fn new() -> Self { Self(imp::Mutex::new()) } @@ -29,19 +22,19 @@ impl StaticMutex { /// Calls raw_lock() and then returns an RAII guard to guarantee the mutex /// will be unlocked. /// - /// It is undefined behaviour to call this function while locked, or if the - /// mutex has been moved since the last time this was called. + /// It is undefined behaviour to call this function while locked by the + /// same thread. #[inline] - pub unsafe fn lock(&self) -> StaticMutexGuard<'_> { + pub unsafe fn lock(&'static self) -> StaticMutexGuard { self.0.lock(); StaticMutexGuard(&self.0) } } #[must_use] -pub struct StaticMutexGuard<'a>(&'a imp::Mutex); +pub struct StaticMutexGuard(&'static imp::Mutex); -impl Drop for StaticMutexGuard<'_> { +impl Drop for StaticMutexGuard { #[inline] fn drop(&mut self) { unsafe { diff --git a/library/std/src/sys_common/thread_parker/mod.rs b/library/std/src/sys_common/thread_parker/mod.rs index 23c17c8e2cf..5e75ac65de4 100644 --- a/library/std/src/sys_common/thread_parker/mod.rs +++ b/library/std/src/sys_common/thread_parker/mod.rs @@ -1,5 +1,9 @@ cfg_if::cfg_if! { - if #[cfg(any(target_os = "linux", target_os = "android"))] { + if #[cfg(any( + target_os = "linux", + target_os = "android", + all(target_arch = "wasm32", target_feature = "atomics"), + ))] { mod futex; pub use futex::Parker; } else { diff --git a/library/std/src/thread/available_concurrency.rs b/library/std/src/thread/available_concurrency.rs new file mode 100644 index 00000000000..4e805e4f599 --- /dev/null +++ b/library/std/src/thread/available_concurrency.rs @@ -0,0 +1,157 @@ +use crate::io; +use crate::num::NonZeroUsize; + +/// Returns the number of hardware threads available to the program. +/// +/// This value should be considered only a hint. +/// +/// # Platform-specific behavior +/// +/// If interpreted as the number of actual hardware threads, it may undercount on +/// Windows systems with more than 64 hardware threads. If interpreted as the +/// available concurrency for that process, it may overcount on Windows systems +/// when limited by a process wide affinity mask or job object limitations, and +/// it may overcount on Linux systems when limited by a process wide affinity +/// mask or affected by cgroups limits. +/// +/// # Errors +/// +/// This function will return an error in the following situations, but is not +/// limited to just these cases: +/// +/// - If the number of hardware threads is not known for the target platform. +/// - The process lacks permissions to view the number of hardware threads +/// available. +/// +/// # Examples +/// +/// ``` +/// # #![allow(dead_code)] +/// #![feature(available_concurrency)] +/// use std::thread; +/// +/// let count = thread::available_concurrency().map(|n| n.get()).unwrap_or(1); +/// ``` +#[unstable(feature = "available_concurrency", issue = "74479")] +pub fn available_concurrency() -> io::Result<NonZeroUsize> { + available_concurrency_internal() +} + +cfg_if::cfg_if! { + if #[cfg(windows)] { + #[allow(nonstandard_style)] + fn available_concurrency_internal() -> io::Result<NonZeroUsize> { + #[repr(C)] + struct SYSTEM_INFO { + wProcessorArchitecture: u16, + wReserved: u16, + dwPageSize: u32, + lpMinimumApplicationAddress: *mut u8, + lpMaximumApplicationAddress: *mut u8, + dwActiveProcessorMask: *mut u8, + dwNumberOfProcessors: u32, + dwProcessorType: u32, + dwAllocationGranularity: u32, + wProcessorLevel: u16, + wProcessorRevision: u16, + } + extern "system" { + fn GetSystemInfo(info: *mut SYSTEM_INFO) -> i32; + } + let res = unsafe { + let mut sysinfo = crate::mem::zeroed(); + GetSystemInfo(&mut sysinfo); + sysinfo.dwNumberOfProcessors as usize + }; + match res { + 0 => Err(io::Error::new(io::ErrorKind::NotFound, "The number of hardware threads is not known for the target platform")), + cpus => Ok(unsafe { NonZeroUsize::new_unchecked(cpus) }), + } + } + } else if #[cfg(any( + target_os = "android", + target_os = "cloudabi", + target_os = "emscripten", + target_os = "fuchsia", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "solaris", + target_os = "illumos", + ))] { + fn available_concurrency_internal() -> io::Result<NonZeroUsize> { + match unsafe { libc::sysconf(libc::_SC_NPROCESSORS_ONLN) } { + -1 => Err(io::Error::last_os_error()), + 0 => Err(io::Error::new(io::ErrorKind::NotFound, "The number of hardware threads is not known for the target platform")), + cpus => Ok(unsafe { NonZeroUsize::new_unchecked(cpus as usize) }), + } + } + } else if #[cfg(any(target_os = "freebsd", target_os = "dragonfly", target_os = "netbsd"))] { + fn available_concurrency_internal() -> io::Result<NonZeroUsize> { + use crate::ptr; + + let mut cpus: libc::c_uint = 0; + let mut cpus_size = crate::mem::size_of_val(&cpus); + + unsafe { + cpus = libc::sysconf(libc::_SC_NPROCESSORS_ONLN) as libc::c_uint; + } + + // Fallback approach in case of errors or no hardware threads. + if cpus < 1 { + let mut mib = [libc::CTL_HW, libc::HW_NCPU, 0, 0]; + let res = unsafe { + libc::sysctl( + mib.as_mut_ptr(), + 2, + &mut cpus as *mut _ as *mut _, + &mut cpus_size as *mut _ as *mut _, + ptr::null_mut(), + 0, + ) + }; + + // Handle errors if any. + if res == -1 { + return Err(io::Error::last_os_error()); + } else if cpus == 0 { + return Err(io::Error::new(io::ErrorKind::NotFound, "The number of hardware threads is not known for the target platform")); + } + } + Ok(unsafe { NonZeroUsize::new_unchecked(cpus as usize) }) + } + } else if #[cfg(target_os = "openbsd")] { + fn available_concurrency_internal() -> io::Result<NonZeroUsize> { + use crate::ptr; + + let mut cpus: libc::c_uint = 0; + let mut cpus_size = crate::mem::size_of_val(&cpus); + let mut mib = [libc::CTL_HW, libc::HW_NCPU, 0, 0]; + + let res = unsafe { + libc::sysctl( + mib.as_mut_ptr(), + 2, + &mut cpus as *mut _ as *mut _, + &mut cpus_size as *mut _ as *mut _, + ptr::null_mut(), + 0, + ) + }; + + // Handle errors if any. + if res == -1 { + return Err(io::Error::last_os_error()); + } else if cpus == 0 { + return Err(io::Error::new(io::ErrorKind::NotFound, "The number of hardware threads is not known for the target platform")); + } + + Ok(unsafe { NonZeroUsize::new_unchecked(cpus as usize) }) + } + } else { + // FIXME: implement on vxWorks, Redox, HermitCore, Haiku, l4re + fn available_concurrency_internal() -> io::Result<NonZeroUsize> { + Err(io::Error::new(io::ErrorKind::NotFound, "The number of hardware threads is not known for the target platform")) + } + } +} diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs index 087175bb92a..45c10266ba2 100644 --- a/library/std/src/thread/mod.rs +++ b/library/std/src/thread/mod.rs @@ -175,9 +175,15 @@ use crate::time::Duration; #[macro_use] mod local; +#[unstable(feature = "available_concurrency", issue = "74479")] +mod available_concurrency; + #[stable(feature = "rust1", since = "1.0.0")] pub use self::local::{AccessError, LocalKey}; +#[unstable(feature = "available_concurrency", issue = "74479")] +pub use available_concurrency::available_concurrency; + // The types used by the thread_local! macro to access TLS keys. Note that there // are two types, the "OS" type and the "fast" type. The OS thread local key // type is accessed via platform-specific API calls and is slow, while the fast diff --git a/library/test/src/formatters/json.rs b/library/test/src/formatters/json.rs index 9ebc991d638..41e7e6adcf1 100644 --- a/library/test/src/formatters/json.rs +++ b/library/test/src/formatters/json.rs @@ -182,8 +182,8 @@ impl<T: Write> OutputFormatter for JsonFormatter<T> { /// Base code taken form `libserialize::json::escape_str` struct EscapedString<S: AsRef<str>>(S); -impl<S: AsRef<str>> ::std::fmt::Display for EscapedString<S> { - fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { +impl<S: AsRef<str>> std::fmt::Display for EscapedString<S> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> ::std::fmt::Result { let mut start = 0; for (i, byte) in self.0.as_ref().bytes().enumerate() { diff --git a/library/test/src/helpers/concurrency.rs b/library/test/src/helpers/concurrency.rs index 7ca27bf0dc1..7e9bd50f556 100644 --- a/library/test/src/helpers/concurrency.rs +++ b/library/test/src/helpers/concurrency.rs @@ -1,6 +1,7 @@ //! Helper module which helps to determine amount of threads to be used //! during tests execution. use std::env; +use std::thread; #[allow(deprecated)] pub fn get_concurrency() -> usize { @@ -12,106 +13,6 @@ pub fn get_concurrency() -> usize { _ => panic!("RUST_TEST_THREADS is `{}`, should be a positive integer.", s), } } - Err(..) => num_cpus(), - } -} - -cfg_if::cfg_if! { - if #[cfg(windows)] { - #[allow(nonstandard_style)] - fn num_cpus() -> usize { - #[repr(C)] - struct SYSTEM_INFO { - wProcessorArchitecture: u16, - wReserved: u16, - dwPageSize: u32, - lpMinimumApplicationAddress: *mut u8, - lpMaximumApplicationAddress: *mut u8, - dwActiveProcessorMask: *mut u8, - dwNumberOfProcessors: u32, - dwProcessorType: u32, - dwAllocationGranularity: u32, - wProcessorLevel: u16, - wProcessorRevision: u16, - } - extern "system" { - fn GetSystemInfo(info: *mut SYSTEM_INFO) -> i32; - } - unsafe { - let mut sysinfo = std::mem::zeroed(); - GetSystemInfo(&mut sysinfo); - sysinfo.dwNumberOfProcessors as usize - } - } - } else if #[cfg(any( - target_os = "android", - target_os = "cloudabi", - target_os = "emscripten", - target_os = "fuchsia", - target_os = "ios", - target_os = "linux", - target_os = "macos", - target_os = "solaris", - target_os = "illumos", - ))] { - fn num_cpus() -> usize { - unsafe { libc::sysconf(libc::_SC_NPROCESSORS_ONLN) as usize } - } - } else if #[cfg(any(target_os = "freebsd", target_os = "dragonfly", target_os = "netbsd"))] { - fn num_cpus() -> usize { - use std::ptr; - - let mut cpus: libc::c_uint = 0; - let mut cpus_size = std::mem::size_of_val(&cpus); - - unsafe { - cpus = libc::sysconf(libc::_SC_NPROCESSORS_ONLN) as libc::c_uint; - } - if cpus < 1 { - let mut mib = [libc::CTL_HW, libc::HW_NCPU, 0, 0]; - unsafe { - libc::sysctl( - mib.as_mut_ptr(), - 2, - &mut cpus as *mut _ as *mut _, - &mut cpus_size as *mut _ as *mut _, - ptr::null_mut(), - 0, - ); - } - if cpus < 1 { - cpus = 1; - } - } - cpus as usize - } - } else if #[cfg(target_os = "openbsd")] { - fn num_cpus() -> usize { - use std::ptr; - - let mut cpus: libc::c_uint = 0; - let mut cpus_size = std::mem::size_of_val(&cpus); - let mut mib = [libc::CTL_HW, libc::HW_NCPU, 0, 0]; - - unsafe { - libc::sysctl( - mib.as_mut_ptr(), - 2, - &mut cpus as *mut _ as *mut _, - &mut cpus_size as *mut _ as *mut _, - ptr::null_mut(), - 0, - ); - } - if cpus < 1 { - cpus = 1; - } - cpus as usize - } - } else { - // FIXME: implement on vxWorks, Redox, HermitCore, Haiku, l4re - fn num_cpus() -> usize { - 1 - } + Err(..) => thread::available_concurrency().map(|n| n.get()).unwrap_or(1), } } diff --git a/library/test/src/lib.rs b/library/test/src/lib.rs index b0b81f85fe0..9c5bb8957b5 100644 --- a/library/test/src/lib.rs +++ b/library/test/src/lib.rs @@ -24,6 +24,7 @@ #![feature(rustc_private)] #![feature(nll)] #![feature(bool_to_option)] +#![feature(available_concurrency)] #![feature(set_stdio)] #![feature(panic_unwind)] #![feature(staged_api)] diff --git a/src/bootstrap/README.md b/src/bootstrap/README.md index bc8bae14b21..84ed9446ae7 100644 --- a/src/bootstrap/README.md +++ b/src/bootstrap/README.md @@ -93,12 +93,12 @@ handled naturally. `./configure` should almost never be used for local installations, and is primarily useful for CI. Prefer to customize behavior using `config.toml`. -Finally, rustbuild makes use of the [gcc-rs crate] which has [its own +Finally, rustbuild makes use of the [cc-rs crate] which has [its own method][env-vars] of configuring C compilers and C flags via environment variables. -[gcc-rs crate]: https://github.com/alexcrichton/gcc-rs -[env-vars]: https://github.com/alexcrichton/gcc-rs#external-configuration-via-environment-variables +[cc-rs crate]: https://github.com/alexcrichton/cc-rs +[env-vars]: https://github.com/alexcrichton/cc-rs#external-configuration-via-environment-variables ## Build stages diff --git a/src/bootstrap/bin/main.rs b/src/bootstrap/bin/main.rs index d31f95ee5e9..07e582d4d29 100644 --- a/src/bootstrap/bin/main.rs +++ b/src/bootstrap/bin/main.rs @@ -7,13 +7,15 @@ use std::env; -use bootstrap::{Build, Config, Subcommand}; +use bootstrap::{Build, Config, Subcommand, VERSION}; fn main() { let args = env::args().skip(1).collect::<Vec<_>>(); let config = Config::parse(&args); - let changelog_suggestion = check_version(&config); + // check_version warnings are not printed during setup + let changelog_suggestion = + if matches!(config.cmd, Subcommand::Setup {..}) { None } else { check_version(&config) }; // NOTE: Since `./configure` generates a `config.toml`, distro maintainers will see the // changelog warning, not the `x.py setup` message. @@ -40,8 +42,6 @@ fn main() { } fn check_version(config: &Config) -> Option<String> { - const VERSION: usize = 2; - let mut msg = String::new(); let suggestion = if let Some(seen) = config.changelog_seen { diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index 5c9184f4506..ce37adeb28c 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -447,7 +447,8 @@ class RustBuild(object): def downloading_llvm(self): opt = self.get_toml('download-ci-llvm', 'llvm') - return opt == "true" + return opt == "true" \ + or (opt == "if-available" and self.build == "x86_64-unknown-linux-gnu") def _download_stage0_helper(self, filename, pattern, tarball_suffix, date=None): if date is None: @@ -892,7 +893,7 @@ class RustBuild(object): submodules_names = [] for module in submodules: if module.endswith("llvm-project"): - if self.get_toml('llvm-config') or self.get_toml('download-ci-llvm') == 'true': + if self.get_toml('llvm-config') or self.downloading_llvm(): if self.get_toml('lld') != 'true': continue check = self.check_submodule(module, slow_submodules) @@ -1003,6 +1004,16 @@ def bootstrap(help_triggered): with open(toml_path) as config: build.config_toml = config.read() + profile = build.get_toml('profile') + if profile is not None: + include_file = 'config.{}.toml'.format(profile) + include_dir = os.path.join(build.rust_root, 'src', 'bootstrap', 'defaults') + include_path = os.path.join(include_dir, include_file) + # HACK: This works because `build.get_toml()` returns the first match it finds for a + # specific key, so appending our defaults at the end allows the user to override them + with open(include_path) as included_toml: + build.config_toml += os.linesep + included_toml.read() + config_verbose = build.get_toml('verbose', 'build') if config_verbose is not None: build.verbose = max(build.verbose, int(config_verbose)) diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index 4bc162abee6..707c1ff3efa 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -193,37 +193,37 @@ impl StepDescription { ); } - if paths.is_empty() { - for (desc, should_run) in v.iter().zip(should_runs) { + if paths.is_empty() || builder.config.include_default_paths { + for (desc, should_run) in v.iter().zip(&should_runs) { if desc.default && should_run.is_really_default { for pathset in &should_run.paths { desc.maybe_run(builder, pathset); } } } - } else { - for path in paths { - // strip CurDir prefix if present - let path = match path.strip_prefix(".") { - Ok(p) => p, - Err(_) => path, - }; + } - let mut attempted_run = false; - for (desc, should_run) in v.iter().zip(&should_runs) { - if let Some(suite) = should_run.is_suite_path(path) { - attempted_run = true; - desc.maybe_run(builder, suite); - } else if let Some(pathset) = should_run.pathset_for_path(path) { - attempted_run = true; - desc.maybe_run(builder, pathset); - } - } + for path in paths { + // strip CurDir prefix if present + let path = match path.strip_prefix(".") { + Ok(p) => p, + Err(_) => path, + }; - if !attempted_run { - panic!("error: no rules matched {}", path.display()); + let mut attempted_run = false; + for (desc, should_run) in v.iter().zip(&should_runs) { + if let Some(suite) = should_run.is_suite_path(path) { + attempted_run = true; + desc.maybe_run(builder, suite); + } else if let Some(pathset) = should_run.pathset_for_path(path) { + attempted_run = true; + desc.maybe_run(builder, pathset); } } + + if !attempted_run { + panic!("error: no rules matched {}", path.display()); + } } } } @@ -462,6 +462,7 @@ impl<'a> Builder<'a> { dist::LlvmTools, dist::RustDev, dist::Extended, + dist::BuildManifest, dist::HashSign ), Kind::Install => describe!( diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index 40bf6c48296..5215ab3dd4f 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -234,14 +234,14 @@ pub fn std_cargo(builder: &Builder<'_>, target: TargetSelection, stage: u32, car // Note that `libprofiler_builtins/build.rs` also computes this so if // you're changing something here please also change that. cargo.env("RUST_COMPILER_RT_ROOT", &compiler_builtins_root); - " compiler-builtins-c".to_string() + " compiler-builtins-c" } else { - String::new() + "" }; if builder.no_std(target) == Some(true) { let mut features = "compiler-builtins-mem".to_string(); - features.push_str(&compiler_builtins_c_feature); + features.push_str(compiler_builtins_c_feature); // for no-std targets we only compile a few no_std crates cargo @@ -249,10 +249,10 @@ pub fn std_cargo(builder: &Builder<'_>, target: TargetSelection, stage: u32, car .arg("--manifest-path") .arg(builder.src.join("library/alloc/Cargo.toml")) .arg("--features") - .arg("compiler-builtins-mem compiler-builtins-c"); + .arg(features); } else { let mut features = builder.std_features(); - features.push_str(&compiler_builtins_c_feature); + features.push_str(compiler_builtins_c_feature); cargo .arg("--features") diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index 6265bbaf5c2..3c1249f8de4 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -61,6 +61,7 @@ pub struct Config { pub profiler: bool, pub ignore_git: bool, pub exclude: Vec<PathBuf>, + pub include_default_paths: bool, pub rustc_error_format: Option<String>, pub json_output: bool, pub test_compare_mode: bool, @@ -390,7 +391,7 @@ struct Llvm { use_libcxx: Option<bool>, use_linker: Option<String>, allow_old_toolchain: Option<bool>, - download_ci_llvm: Option<bool>, + download_ci_llvm: Option<StringOrBool>, } #[derive(Deserialize, Default, Clone, Merge)] @@ -532,6 +533,7 @@ impl Config { let mut config = Config::default_opts(); config.exclude = flags.exclude; + config.include_default_paths = flags.include_default_paths; config.rustc_error_format = flags.rustc_error_format; config.json_output = flags.json_output; config.on_fail = flags.on_fail; @@ -733,7 +735,14 @@ impl Config { set(&mut config.llvm_use_libcxx, llvm.use_libcxx); config.llvm_use_linker = llvm.use_linker.clone(); config.llvm_allow_old_toolchain = llvm.allow_old_toolchain; - config.llvm_from_ci = llvm.download_ci_llvm.unwrap_or(false); + config.llvm_from_ci = match llvm.download_ci_llvm { + Some(StringOrBool::String(s)) => { + assert!(s == "if-available", "unknown option `{}` for download-ci-llvm", s); + config.build.triple == "x86_64-unknown-linux-gnu" + } + Some(StringOrBool::Bool(b)) => b, + None => false, + }; if config.llvm_from_ci { // None of the LLVM options, except assertions, are supported diff --git a/src/bootstrap/defaults/config.compiler.toml b/src/bootstrap/defaults/config.compiler.toml index 4772de8a2cb..0ca928843d5 100644 --- a/src/bootstrap/defaults/config.compiler.toml +++ b/src/bootstrap/defaults/config.compiler.toml @@ -6,3 +6,8 @@ debug-logging = true # This greatly increases the speed of rebuilds, especially when there are only minor changes. However, it makes the initial build slightly slower. incremental = true + +[llvm] +# Will download LLVM from CI if available on your platform (Linux only for now) +# https://github.com/rust-lang/rust/issues/77084 tracks support for more platforms +download-ci-llvm = "if-available" diff --git a/src/bootstrap/defaults/config.library.toml b/src/bootstrap/defaults/config.library.toml index e4316f4d864..9874fdb767f 100644 --- a/src/bootstrap/defaults/config.library.toml +++ b/src/bootstrap/defaults/config.library.toml @@ -8,3 +8,8 @@ bench-stage = 0 [rust] # This greatly increases the speed of rebuilds, especially when there are only minor changes. However, it makes the initial build slightly slower. incremental = true + +[llvm] +# Will download LLVM from CI if available on your platform (Linux only for now) +# https://github.com/rust-lang/rust/issues/77084 tracks support for more platforms +download-ci-llvm = "if-available" diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index 3a0743da7a4..1887b805da1 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -2353,7 +2353,6 @@ impl Step for HashSign { cmd.arg(today.trim()); cmd.arg(addr); cmd.arg(&builder.config.channel); - cmd.arg(&builder.src); cmd.env("BUILD_MANIFEST_LEGACY", "1"); builder.create_dir(&distdir(builder)); @@ -2584,3 +2583,70 @@ impl Step for RustDev { Some(distdir(builder).join(format!("{}-{}.tar.gz", name, target.triple))) } } + +/// Tarball containing a prebuilt version of the build-manifest tool, intented to be used by the +/// release process to avoid cloning the monorepo and building stuff. +/// +/// Should not be considered stable by end users. +#[derive(Clone, Debug, Eq, Hash, PartialEq)] +pub struct BuildManifest { + pub target: TargetSelection, +} + +impl Step for BuildManifest { + type Output = PathBuf; + const DEFAULT: bool = false; + const ONLY_HOSTS: bool = true; + + fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { + run.path("src/tools/build-manifest") + } + + fn make_run(run: RunConfig<'_>) { + run.builder.ensure(BuildManifest { target: run.target }); + } + + fn run(self, builder: &Builder<'_>) -> PathBuf { + let build_manifest = builder.tool_exe(Tool::BuildManifest); + + let name = pkgname(builder, "build-manifest"); + let tmp = tmpdir(builder); + + // Prepare the image. + let image = tmp.join("build-manifest-image"); + let image_bin = image.join("bin"); + let _ = fs::remove_dir_all(&image); + t!(fs::create_dir_all(&image_bin)); + builder.install(&build_manifest, &image_bin, 0o755); + + // Prepare the overlay. + let overlay = tmp.join("build-manifest-overlay"); + let _ = fs::remove_dir_all(&overlay); + builder.create_dir(&overlay); + builder.create(&overlay.join("version"), &builder.rust_version()); + for file in &["COPYRIGHT", "LICENSE-APACHE", "LICENSE-MIT", "README.md"] { + builder.install(&builder.src.join(file), &overlay, 0o644); + } + + // Create the final tarball. + let mut cmd = rust_installer(builder); + cmd.arg("generate") + .arg("--product-name=Rust") + .arg("--rel-manifest-dir=rustlib") + .arg("--success-message=build-manifest installed.") + .arg("--image-dir") + .arg(&image) + .arg("--work-dir") + .arg(&tmpdir(builder)) + .arg("--output-dir") + .arg(&distdir(builder)) + .arg("--non-installed-overlay") + .arg(&overlay) + .arg(format!("--package-name={}-{}", name, self.target.triple)) + .arg("--legacy-manifest-dirs=rustlib,cargo") + .arg("--component-name=build-manifest"); + + builder.run(&mut cmd); + distdir(builder).join(format!("{}-{}.tar.gz", name, self.target.triple)) + } +} diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs index 319a0b4e611..22cfd0c5643 100644 --- a/src/bootstrap/flags.rs +++ b/src/bootstrap/flags.rs @@ -30,6 +30,7 @@ pub struct Flags { pub cmd: Subcommand, pub incremental: bool, pub exclude: Vec<PathBuf>, + pub include_default_paths: bool, pub rustc_error_format: Option<String>, pub json_output: bool, pub dry_run: bool, @@ -124,6 +125,7 @@ Subcommands: dist Build distribution artifacts install Install distribution artifacts run, r Run tools contained in this repository + setup Create a config.toml (making it easier to use `x.py` itself) To learn more about a subcommand, run `./x.py <subcommand> -h`", ); @@ -137,6 +139,11 @@ To learn more about a subcommand, run `./x.py <subcommand> -h`", opts.optmulti("", "host", "host targets to build", "HOST"); opts.optmulti("", "target", "target targets to build", "TARGET"); opts.optmulti("", "exclude", "build paths to exclude", "PATH"); + opts.optflag( + "", + "include-default-paths", + "include default paths in addition to the provided ones", + ); opts.optopt("", "on-fail", "command to run on failure", "CMD"); opts.optflag("", "dry-run", "dry run; don't build anything"); opts.optopt( @@ -466,15 +473,21 @@ Arguments: ); } "setup" => { - subcommand_help.push_str( + subcommand_help.push_str(&format!( "\n +x.py setup creates a `config.toml` which changes the defaults for x.py itself. + Arguments: This subcommand accepts a 'profile' to use for builds. For example: ./x.py setup library - The profile is optional and you will be prompted interactively if it is not given.", - ); + The profile is optional and you will be prompted interactively if it is not given. + The following profiles are available: + +{}", + Profile::all_for_help(" ").trim_end() + )); } _ => {} }; @@ -545,9 +558,7 @@ Arguments: profile_string.parse().unwrap_or_else(|err| { eprintln!("error: {}", err); eprintln!("help: the available profiles are:"); - for choice in Profile::all() { - eprintln!("- {}", choice); - } + eprint!("{}", Profile::all_for_help("- ")); std::process::exit(1); }) } else { @@ -618,6 +629,7 @@ Arguments: .into_iter() .map(|p| p.into()) .collect::<Vec<_>>(), + include_default_paths: matches.opt_present("include-default-paths"), deny_warnings: parse_deny_warnings(&matches), llvm_skip_rebuild: matches.opt_str("llvm-skip-rebuild").map(|s| s.to_lowercase()).map( |s| s.parse::<bool>().expect("`llvm-skip-rebuild` should be either true or false"), diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index bf81c4bf28e..22a8e828862 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -177,8 +177,13 @@ const LLVM_TOOLS: &[&str] = &[ "llvm-size", // used to prints the size of the linker sections of a program "llvm-strip", // used to discard symbols from binary files to reduce their size "llvm-ar", // used for creating and modifying archive files + "llvm-dis", // used to disassemble LLVM bitcode + "llc", // used to compile LLVM bytecode + "opt", // used to optimize LLVM bytecode ]; +pub const VERSION: usize = 2; + /// A structure representing a Rust compiler. /// /// Each compiler has a `stage` that it is associated with and a `host` that diff --git a/src/bootstrap/run.rs b/src/bootstrap/run.rs index 80c093e713e..7c64e5a0aad 100644 --- a/src/bootstrap/run.rs +++ b/src/bootstrap/run.rs @@ -77,7 +77,6 @@ impl Step for BuildManifest { cmd.arg(today.trim()); cmd.arg(addr); cmd.arg(&builder.config.channel); - cmd.arg(&builder.src); builder.create_dir(&distdir(builder)); builder.run(&mut cmd); diff --git a/src/bootstrap/setup.rs b/src/bootstrap/setup.rs index dcfb9fd6734..c6e1c99564c 100644 --- a/src/bootstrap/setup.rs +++ b/src/bootstrap/setup.rs @@ -1,5 +1,7 @@ -use crate::t; +use crate::{t, VERSION}; +use std::fmt::Write as _; use std::path::{Path, PathBuf}; +use std::process::Command; use std::str::FromStr; use std::{ env, fmt, fs, @@ -20,7 +22,28 @@ impl Profile { } pub fn all() -> impl Iterator<Item = Self> { - [Profile::Compiler, Profile::Codegen, Profile::Library, Profile::User].iter().copied() + use Profile::*; + // N.B. these are ordered by how they are displayed, not alphabetically + [Library, Compiler, Codegen, User].iter().copied() + } + + pub fn purpose(&self) -> String { + use Profile::*; + match self { + Library => "Contribute to the standard library", + Compiler => "Contribute to the compiler or rustdoc", + Codegen => "Contribute to the compiler, and also modify LLVM or codegen", + User => "Install Rust from source", + } + .to_string() + } + + pub fn all_for_help(indent: &str) -> String { + let mut out = String::new(); + for choice in Profile::all() { + writeln!(&mut out, "{}{}: {}", indent, choice, choice.purpose()).unwrap(); + } + out } } @@ -29,10 +52,10 @@ impl FromStr for Profile { fn from_str(s: &str) -> Result<Self, Self::Err> { match s { - "a" | "lib" | "library" => Ok(Profile::Library), - "b" | "compiler" => Ok(Profile::Compiler), - "c" | "llvm" | "codegen" => Ok(Profile::Codegen), - "d" | "maintainer" | "user" => Ok(Profile::User), + "lib" | "library" => Ok(Profile::Library), + "compiler" | "rustdoc" => Ok(Profile::Compiler), + "llvm" | "codegen" => Ok(Profile::Codegen), + "maintainer" | "user" => Ok(Profile::User), _ => Err(format!("unknown profile: '{}'", s)), } } @@ -69,8 +92,9 @@ pub fn setup(src_path: &Path, profile: Profile) { let path = cfg_file.unwrap_or_else(|| src_path.join("config.toml")); let settings = format!( "# Includes one of the default files in src/bootstrap/defaults\n\ - profile = \"{}\"\n", - profile + profile = \"{}\"\n\ + changelog-seen = {}\n", + profile, VERSION ); t!(fs::write(path, settings)); @@ -103,19 +127,37 @@ pub fn setup(src_path: &Path, profile: Profile) { // Used to get the path for `Subcommand::Setup` pub fn interactive_path() -> io::Result<Profile> { - let mut input = String::new(); - println!( - "Welcome to the Rust project! What do you want to do with x.py? -a) Contribute to the standard library -b) Contribute to the compiler -c) Contribute to the compiler, and also modify LLVM or codegen -d) Install Rust from source" - ); + fn abbrev_all() -> impl Iterator<Item = (String, Profile)> { + ('a'..).map(|c| c.to_string()).zip(Profile::all()) + } + + fn parse_with_abbrev(input: &str) -> Result<Profile, String> { + let input = input.trim().to_lowercase(); + for (letter, profile) in abbrev_all() { + if input == letter { + return Ok(profile); + } + } + input.parse() + } + + println!("Welcome to the Rust project! What do you want to do with x.py?"); + for (letter, profile) in abbrev_all() { + println!("{}) {}: {}", letter, profile, profile.purpose()); + } let template = loop { - print!("Please choose one (a/b/c/d): "); + print!( + "Please choose one ({}): ", + abbrev_all().map(|(l, _)| l).collect::<Vec<_>>().join("/") + ); io::stdout().flush()?; + let mut input = String::new(); io::stdin().read_line(&mut input)?; - break match input.trim().to_lowercase().parse() { + if input == "" { + eprintln!("EOF on stdin, when expecting answer to question. Giving up."); + std::process::exit(1); + } + break match parse_with_abbrev(&input) { Ok(profile) => profile, Err(err) => { println!("error: {}", err); @@ -155,10 +197,17 @@ simply delete the `pre-commit` file from .git/hooks." Ok(if should_install { let src = src_path.join("src").join("etc").join("pre-commit.sh"); - let dst = src_path.join(".git").join("hooks").join("pre-commit"); - match fs::hard_link(src, dst) { + let git = t!(Command::new("git").args(&["rev-parse", "--git-common-dir"]).output().map( + |output| { + assert!(output.status.success(), "failed to run `git`"); + PathBuf::from(t!(String::from_utf8(output.stdout)).trim()) + } + )); + let dst = git.join("hooks").join("pre-commit"); + match fs::hard_link(src, &dst) { Err(e) => println!( - "x.py encountered an error -- do you already have the git hook installed?\n{}", + "error: could not create hook {}: do you already have the git hook installed?\n{}", + dst.display(), e ), Ok(_) => println!("Linked `src/etc/pre-commit.sh` to `.git/hooks/pre-commit`"), diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index 00522ee6b67..33e85dc5e2a 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -737,6 +737,7 @@ impl Step for Tidy { let mut cmd = builder.tool_cmd(Tool::Tidy); cmd.arg(&builder.src); cmd.arg(&builder.initial_cargo); + cmd.arg(&builder.out); if builder.is_verbose() { cmd.arg("--verbose"); } @@ -966,6 +967,15 @@ impl Step for Compiletest { /// compiletest `mode` and `suite` arguments. For example `mode` can be /// "run-pass" or `suite` can be something like `debuginfo`. fn run(self, builder: &Builder<'_>) { + if builder.top_stage == 0 && env::var("COMPILETEST_FORCE_STAGE0").is_err() { + eprintln!("\ +error: `--stage 0` runs compiletest on the beta compiler, not your local changes, and will almost always cause tests to fail +help: use `--stage 1` instead +note: if you're sure you want to do this, please open an issue as to why. In the meantime, you can override this with `COMPILETEST_FORCE_STAGE0=1`." + ); + std::process::exit(1); + } + let compiler = self.compiler; let target = self.target; let mode = self.mode; diff --git a/src/bootstrap/util.rs b/src/bootstrap/util.rs index a307ef39d03..b35d1b99fa5 100644 --- a/src/bootstrap/util.rs +++ b/src/bootstrap/util.rs @@ -122,7 +122,7 @@ impl Drop for TimeIt { fn drop(&mut self) { let time = self.1.elapsed(); if !self.0 { - println!("\tfinished in {}.{:03}", time.as_secs(), time.subsec_millis()); + println!("\tfinished in {}.{:03} seconds", time.as_secs(), time.subsec_millis()); } } } diff --git a/src/ci/docker/host-x86_64/disabled/riscv64gc-linux/Dockerfile b/src/ci/docker/host-x86_64/disabled/riscv64gc-linux/Dockerfile index 3c39a638496..f3f52ed61d1 100644 --- a/src/ci/docker/host-x86_64/disabled/riscv64gc-linux/Dockerfile +++ b/src/ci/docker/host-x86_64/disabled/riscv64gc-linux/Dockerfile @@ -84,9 +84,9 @@ RUN riscv64-linux-gnu-gcc addentropy.c -o rootfs/addentropy -static # download and build the riscv bootloader RUN git clone https://github.com/riscv/riscv-pk WORKDIR /tmp/riscv-pk -# nothing special about this revision: it is just master at the time of writing -# v1.0.0 doesn't build -RUN git checkout 5d9ed238e1cabfbca3c47f50d32894ce94bfc304 +# This revision fixes a fault in recent QEMU from 64-bit accesses to the PLIC +# commits later than this one should work too +RUN git checkout 7d8b7c0dab72108e3ea7bb7744d3f6cc907c7ef4 RUN mkdir build && cd build && \ ../configure --with-payload=/tmp/vmlinux --host=riscv64-linux-gnu && \ make -j$(nproc) && \ diff --git a/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile index 58e2567a58f..14700aeea05 100644 --- a/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile @@ -98,7 +98,9 @@ ENV RUST_CONFIGURE_ARGS \ --set llvm.thin-lto=true \ --set llvm.ninja=false \ --set rust.jemalloc -ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS +ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS \ + --include-default-paths \ + src/tools/build-manifest ENV CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_LINKER=clang # This is the only builder which will create source tarballs diff --git a/src/ci/github-actions/ci.yml b/src/ci/github-actions/ci.yml index 101716d1601..01f15a82f0f 100644 --- a/src/ci/github-actions/ci.yml +++ b/src/ci/github-actions/ci.yml @@ -149,6 +149,10 @@ x--expand-yaml-anchors--remove: run: src/ci/scripts/install-sccache.sh <<: *step + - name: select Xcode + run: src/ci/scripts/select-xcode.sh + <<: *step + - name: install clang run: src/ci/scripts/install-clang.sh <<: *step @@ -457,6 +461,37 @@ jobs: NO_DEBUG_ASSERTIONS: 1 <<: *job-macos-xl + # This target only needs to support 11.0 and up as nothing else supports the hardware + - name: dist-aarch64-apple + env: + SCRIPT: ./x.py dist --stage 2 + RUST_CONFIGURE_ARGS: >- + --build=x86_64-apple-darwin + --host=aarch64-apple-darwin + --target=aarch64-apple-darwin + --enable-full-tools + --enable-sanitizers + --enable-profiler + --set rust.jemalloc + --set llvm.ninja=false + RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 + SELECT_XCODE: /Applications/Xcode_12.2.app + USE_XCODE_CLANG: 1 + MACOSX_DEPLOYMENT_TARGET: 11.0 + MACOSX_STD_DEPLOYMENT_TARGET: 11.0 + NO_LLVM_ASSERTIONS: 1 + NO_DEBUG_ASSERTIONS: 1 + DIST_REQUIRE_ALL_TOOLS: 1 + # Corresponds to 16K page size + # + # Shouldn't be needed if jemalloc-sys is updated to + # handle this platform like iOS or if we build on + # aarch64-apple-darwin itself. + # + # https://github.com/gnzlbg/jemallocator/blob/c27a859e98e3cb790dc269773d9da71a1e918458/jemalloc-sys/build.rs#L237 + JEMALLOC_SYS_WITH_LG_PAGE: 14 + <<: *job-macos-xl + ###################### # Windows Builders # ###################### @@ -565,7 +600,7 @@ jobs: RUST_CONFIGURE_ARGS: >- --build=x86_64-pc-windows-msvc --host=x86_64-pc-windows-msvc - --target=x86_64-pc-windows-msvc,aarch64-pc-windows-msvc + --target=x86_64-pc-windows-msvc --enable-full-tools --enable-profiler SCRIPT: python x.py dist @@ -584,6 +619,18 @@ jobs: DIST_REQUIRE_ALL_TOOLS: 1 <<: *job-windows-xl + - name: dist-aarch64-msvc + env: + RUST_CONFIGURE_ARGS: >- + --build=x86_64-pc-windows-msvc + --host=aarch64-pc-windows-msvc + --enable-full-tools + --enable-profiler + SCRIPT: python x.py dist + # RLS does not build for aarch64-pc-windows-msvc. See rust-lang/rls#1693 + DIST_REQUIRE_ALL_TOOLS: 0 + <<: *job-windows-xl + - name: dist-i686-mingw env: RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu --enable-full-tools --enable-profiler diff --git a/src/ci/scripts/install-clang.sh b/src/ci/scripts/install-clang.sh index a1481f22f50..8070e90f155 100755 --- a/src/ci/scripts/install-clang.sh +++ b/src/ci/scripts/install-clang.sh @@ -12,10 +12,18 @@ source "$(cd "$(dirname "$0")" && pwd)/../shared.sh" LLVM_VERSION="10.0.0" if isMacOS; then - curl -f "${MIRRORS_BASE}/clang%2Bllvm-${LLVM_VERSION}-x86_64-apple-darwin.tar.xz" | tar xJf - + # If the job selects a specific Xcode version, use that instead of + # downloading our own version. + if [[ ${USE_XCODE_CLANG-0} -eq 1 ]]; then + bindir="$(xcode-select --print-path)/Toolchains/XcodeDefault.xctoolchain/usr/bin" + else + file="${MIRRORS_BASE}/clang%2Bllvm-${LLVM_VERSION}-x86_64-apple-darwin.tar.xz" + curl -f "${file}" | tar xJf - + bindir="$(pwd)/clang+llvm-${LLVM_VERSION}-x86_64-apple-darwin/bin" + fi - ciCommandSetEnv CC "$(pwd)/clang+llvm-${LLVM_VERSION}-x86_64-apple-darwin/bin/clang" - ciCommandSetEnv CXX "$(pwd)/clang+llvm-${LLVM_VERSION}-x86_64-apple-darwin/bin/clang++" + ciCommandSetEnv CC "${bindir}/clang" + ciCommandSetEnv CXX "${bindir}/clang++" # macOS 10.15 onwards doesn't have libraries in /usr/include anymore: those # are now located deep into the filesystem, under Xcode's own files. The diff --git a/src/ci/scripts/install-mingw.sh b/src/ci/scripts/install-mingw.sh index ae85d5cab01..1685fbbbbba 100755 --- a/src/ci/scripts/install-mingw.sh +++ b/src/ci/scripts/install-mingw.sh @@ -42,6 +42,13 @@ if isWindows; then arch=x86_64 mingw_archive="${MINGW_ARCHIVE_64}" ;; + *aarch64*) + # aarch64 is a cross-compiled target. Use the x86_64 + # mingw, since that's the host architecture. + bits=64 + arch=x86_64 + mingw_archive="${MINGW_ARCHIVE_64}" + ;; *) echo "src/ci/scripts/install-mingw.sh can't detect the builder's architecture" echo "please tweak it to recognize the builder named '${CI_JOB_NAME}'" diff --git a/src/ci/scripts/select-xcode.sh b/src/ci/scripts/select-xcode.sh new file mode 100755 index 00000000000..3b9c77d42ba --- /dev/null +++ b/src/ci/scripts/select-xcode.sh @@ -0,0 +1,13 @@ +#!/bin/bash +# This script selects the Xcode instance to use. + +set -euo pipefail +IFS=$'\n\t' + +source "$(cd "$(dirname "$0")" && pwd)/../shared.sh" + +if isMacOS; then + if [[ -s "${SELECT_XCODE-}" ]]; then + sudo xcode-select -s "${SELECT_XCODE}" + fi +fi diff --git a/src/doc/book b/src/doc/book -Subproject cb28dee95e5e50b793e6ba9291c5d1568d3ad72 +Subproject 451a1e30f2dd137aa04e142414eafb8d05f87f8 diff --git a/src/doc/embedded-book b/src/doc/embedded-book -Subproject dd310616308e01f6cf227f46347b744aa56b77d +Subproject ca8169e69b479f615855d0eece7e318138fcfc0 diff --git a/src/doc/reference b/src/doc/reference -Subproject 56a13c082ee90736c08d6abdcd90462517b703d +Subproject 1b78182e71709169dc0f1c3acdc4541b6860e1c diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example -Subproject 7d3ff1c12db08a847a57a054be4a7951ce532d2 +Subproject 152475937a8d8a1f508d8eeb57db79139bc803d diff --git a/src/doc/rustc/src/codegen-options/index.md b/src/doc/rustc/src/codegen-options/index.md index bed10ca16d3..f6493e49c3c 100644 --- a/src/doc/rustc/src/codegen-options/index.md +++ b/src/doc/rustc/src/codegen-options/index.md @@ -497,8 +497,10 @@ point instructions in software. It takes one of the following values: This instructs `rustc` to generate code specifically for a particular processor. You can run `rustc --print target-cpus` to see the valid options to pass -here. Additionally, `native` can be passed to use the processor of the host -machine. Each target has a default base CPU. +here. Each target has a default base CPU. Special values include: + +* `native` can be passed to use the processor of the host machine. +* `generic` refers to an LLVM target with minimal features but modern tuning. ## target-feature @@ -530,6 +532,20 @@ This also supports the feature `+crt-static` and `-crt-static` to control Each target and [`target-cpu`](#target-cpu) has a default set of enabled features. +## tune-cpu + +This instructs `rustc` to schedule code specifically for a particular +processor. This does not affect the compatibility (instruction sets or ABI), +but should make your code slightly more efficient on the selected CPU. + +The valid options are the same as those for [`target-cpu`](#target-cpu). +The default is `None`, which LLVM translates as the `target-cpu`. + +This is an unstable option. Use `-Z tune-cpu=machine` to specify a value. + +Due to limitations in LLVM (12.0.0-git9218f92), this option is currently +effective only for x86 targets. + [option-emit]: ../command-line-arguments.md#option-emit [option-o-optimize]: ../command-line-arguments.md#option-o-optimize [profile-guided optimization]: ../profile-guided-optimization.md diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index 6c605f045e5..ae55297b78c 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -37,7 +37,7 @@ target | std | host | notes `i686-pc-windows-gnu` | ✓ | ✓ | 32-bit MinGW (Windows 7+) `i686-pc-windows-msvc` | ✓ | ✓ | 32-bit MSVC (Windows 7+) `i686-unknown-linux-gnu` | ✓ | ✓ | 32-bit Linux (kernel 2.6.32+, glibc 2.11+) -`x86_64-apple-darwin` | ✓ | ✓ | 64-bit OSX (10.7+, Lion+) +`x86_64-apple-darwin` | ✓ | ✓ | 64-bit macOS (10.7+, Lion+) `x86_64-pc-windows-gnu` | ✓ | ✓ | 64-bit MinGW (Windows 7+) `x86_64-pc-windows-msvc` | ✓ | ✓ | 64-bit MSVC (Windows 7+) `x86_64-unknown-linux-gnu` | ✓ | ✓ | 64-bit Linux (kernel 2.6.32+, glibc 2.11+) @@ -57,10 +57,11 @@ Specifically, these platforms are required to have each of the following: target | std | host | notes -------|-----|------|------- +`aarch64-apple-darwin` | ✓ | ✓ | ARM64 macOS (11.0+, Big Sur+) `aarch64-apple-ios` | ✓ | | ARM64 iOS `aarch64-fuchsia` | ✓ | | ARM64 Fuchsia `aarch64-linux-android` | ✓ | | ARM64 Android -`aarch64-pc-windows-msvc` | ✓ | | ARM64 Windows MSVC +`aarch64-pc-windows-msvc` | ✓ | ✓ | ARM64 Windows MSVC `aarch64-unknown-linux-gnu` | ✓ | ✓ | ARM64 Linux (kernel 4.2, glibc 2.17) `aarch64-unknown-linux-musl` | ✓ | ✓ | ARM64 Linux with MUSL `aarch64-unknown-none` | * | | Bare ARM64, hardfloat @@ -145,7 +146,6 @@ not available. target | std | host | notes -------|-----|------|------- -`aarch64-apple-darwin` | ? | | ARM64 macOS `aarch64-apple-tvos` | * | | ARM64 tvOS `aarch64-unknown-cloudabi` | ✓ | | ARM64 CloudABI `aarch64-unknown-freebsd` | ✓ | ✓ | ARM64 FreeBSD @@ -168,7 +168,7 @@ target | std | host | notes `avr-unknown-gnu-atmega328` | ✗ | | AVR. Requires `-Z build-std=core` `hexagon-unknown-linux-musl` | ? | | `i386-apple-ios` | ✓ | | 32-bit x86 iOS -`i686-apple-darwin` | ✓ | ✓ | 32-bit OSX (10.7+, Lion+) +`i686-apple-darwin` | ✓ | ✓ | 32-bit macOS (10.7+, Lion+) `i686-pc-windows-msvc` | ✓ | | 32-bit Windows XP support `i686-unknown-cloudabi` | ✓ | | 32-bit CloudABI `i686-unknown-uefi` | ? | | 32-bit UEFI diff --git a/src/doc/unstable-book/src/compiler-flags/codegen-backend.md b/src/doc/unstable-book/src/compiler-flags/codegen-backend.md new file mode 100644 index 00000000000..878c894a6ca --- /dev/null +++ b/src/doc/unstable-book/src/compiler-flags/codegen-backend.md @@ -0,0 +1,31 @@ +# `codegen-backend` + +The tracking issue for this feature is: [#77933](https://github.com/rust-lang/rust/issues/77933). + +------------------------ + +This feature allows you to specify a path to a dynamic library to use as rustc's +code generation backend at runtime. + +Set the `-Zcodegen-backend=<path>` compiler flag to specify the location of the +backend. The library must be of crate type `dylib` and must contain a function +named `__rustc_codegen_backend` with a signature of `fn() -> Box<dyn rustc_codegen_ssa::traits::CodegenBackend>`. + +## Example +See also the [`hotplug_codegen_backend`](https://github.com/rust-lang/rust/tree/master/src/test/run-make-fulldeps/hotplug_codegen_backend) test +for a full example. + +```rust,ignore +use rustc_codegen_ssa::traits::CodegenBackend; + +struct MyBackend; + +impl CodegenBackend for MyBackend { + // Implement codegen methods +} + +#[no_mangle] +pub fn __rustc_codegen_backend() -> Box<dyn CodegenBackend> { + Box::new(MyBackend) +} +``` diff --git a/src/doc/unstable-book/src/library-features/default-free-fn.md b/src/doc/unstable-book/src/library-features/default-free-fn.md index 5dff73a94dd..d40a27dddf3 100644 --- a/src/doc/unstable-book/src/library-features/default-free-fn.md +++ b/src/doc/unstable-book/src/library-features/default-free-fn.md @@ -10,6 +10,8 @@ Adds a free `default()` function to the `std::default` module. This function just forwards to [`Default::default()`], but may remove repetition of the word "default" from the call site. +[`Default::default()`]: https://doc.rust-lang.org/nightly/std/default/trait.Default.html#tymethod.default + Here is an example: ```rust diff --git a/src/doc/unstable-book/src/library-features/range-bounds-assert-len.md b/src/doc/unstable-book/src/library-features/range-bounds-assert-len.md new file mode 100644 index 00000000000..0e95d5ded92 --- /dev/null +++ b/src/doc/unstable-book/src/library-features/range-bounds-assert-len.md @@ -0,0 +1,10 @@ +# `range_bounds_assert_len` + +The tracking issue for this feature is: [#76393] + +------------------------ + +This adds [`RangeBounds::assert_len`]. + +[#76393]: https://github.com/rust-lang/rust/issues/76393 +[`RangeBounds::assert_len`]: https://doc.rust-lang.org/nightly/std/ops/trait.RangeBounds.html#method.assert_len diff --git a/src/doc/unstable-book/src/library-features/slice-check-range.md b/src/doc/unstable-book/src/library-features/slice-check-range.md deleted file mode 100644 index 83e5738cf54..00000000000 --- a/src/doc/unstable-book/src/library-features/slice-check-range.md +++ /dev/null @@ -1,10 +0,0 @@ -# `slice_check_range` - -The tracking issue for this feature is: [#76393] - ------------------------- - -This adds [`slice::check_range`]. - -[#76393]: https://github.com/rust-lang/rust/issues/76393 -[`slice::check_range`]: https://doc.rust-lang.org/nightly/std/primitive.slice.html#method.check_range diff --git a/src/etc/gdb_providers.py b/src/etc/gdb_providers.py index bae51e6f9ee..eec3027085c 100644 --- a/src/etc/gdb_providers.py +++ b/src/etc/gdb_providers.py @@ -207,30 +207,43 @@ class StdRefCellProvider: yield "borrow", self.borrow -# Yield each key (and optionally value) from a BoxedNode. -def children_of_node(boxed_node, height, want_values): +# Yields children (in a provider's sense of the word) for a tree headed by a BoxedNode. +# In particular, yields each key/value pair in the node and in any child nodes. +def children_of_node(boxed_node, height): def cast_to_internal(node): - internal_type_name = str(node.type.target()).replace("LeafNode", "InternalNode", 1) + internal_type_name = node.type.target().name.replace("LeafNode", "InternalNode", 1) internal_type = lookup_type(internal_type_name) return node.cast(internal_type.pointer()) node_ptr = unwrap_unique_or_non_null(boxed_node["ptr"]) - node_ptr = cast_to_internal(node_ptr) if height > 0 else node_ptr - leaf = node_ptr["data"] if height > 0 else node_ptr.dereference() + leaf = node_ptr.dereference() keys = leaf["keys"] - values = leaf["vals"] + vals = leaf["vals"] + edges = cast_to_internal(node_ptr)["edges"] if height > 0 else None length = int(leaf["len"]) for i in xrange(0, length + 1): if height > 0: - child_ptr = node_ptr["edges"][i]["value"]["value"] - for child in children_of_node(child_ptr, height - 1, want_values): + boxed_child_node = edges[i]["value"]["value"] + for child in children_of_node(boxed_child_node, height - 1): yield child if i < length: - if want_values: - yield keys[i]["value"]["value"], values[i]["value"]["value"] - else: - yield keys[i]["value"]["value"] + # Avoid "Cannot perform pointer math on incomplete type" on zero-sized arrays. + key = keys[i]["value"]["value"] if keys.type.sizeof > 0 else "()" + val = vals[i]["value"]["value"] if vals.type.sizeof > 0 else "()" + yield key, val + + +# Yields children for a BTreeMap. +def children_of_map(map): + if map["length"] > 0: + root = map["root"] + if root.type.name.startswith("core::option::Option<"): + root = root.cast(gdb.lookup_type(root.type.name[21:-1])) + boxed_root_node = root["node"] + height = root["height"] + for child in children_of_node(boxed_root_node, height): + yield child class StdBTreeSetProvider: @@ -242,15 +255,8 @@ class StdBTreeSetProvider: def children(self): inner_map = self.valobj["map"] - if inner_map["length"] > 0: - root = inner_map["root"] - if "core::option::Option<" in root.type.name: - type_name = str(root.type.name).replace("core::option::Option<", "", 1)[:-1] - root = root.cast(gdb.lookup_type(type_name)) - - node_ptr = root["node"] - for i, child in enumerate(children_of_node(node_ptr, root["height"], False)): - yield "[{}]".format(i), child + for i, (child, _) in enumerate(children_of_map(inner_map)): + yield "[{}]".format(i), child @staticmethod def display_hint(): @@ -265,16 +271,9 @@ class StdBTreeMapProvider: return "BTreeMap(size={})".format(self.valobj["length"]) def children(self): - if self.valobj["length"] > 0: - root = self.valobj["root"] - if "core::option::Option<" in root.type.name: - type_name = str(root.type.name).replace("core::option::Option<", "", 1)[:-1] - root = root.cast(gdb.lookup_type(type_name)) - - node_ptr = root["node"] - for i, child in enumerate(children_of_node(node_ptr, root["height"], True)): - yield "key{}".format(i), child[0] - yield "val{}".format(i), child[1] + for i, (key, val) in enumerate(children_of_map(self.valobj)): + yield "key{}".format(i), key + yield "val{}".format(i), val @staticmethod def display_hint(): diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs index 1ea1a091069..f39b53f3c82 100644 --- a/src/librustdoc/clean/auto_trait.rs +++ b/src/librustdoc/clean/auto_trait.rs @@ -315,12 +315,13 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> { tcx: TyCtxt<'tcx>, pred: ty::Predicate<'tcx>, ) -> FxHashSet<GenericParamDef> { - let regions = match pred.skip_binders() { + let bound_predicate = pred.bound_atom(); + let regions = match bound_predicate.skip_binder() { ty::PredicateAtom::Trait(poly_trait_pred, _) => { - tcx.collect_referenced_late_bound_regions(&ty::Binder::bind(poly_trait_pred)) + tcx.collect_referenced_late_bound_regions(&bound_predicate.rebind(poly_trait_pred)) } ty::PredicateAtom::Projection(poly_proj_pred) => { - tcx.collect_referenced_late_bound_regions(&ty::Binder::bind(poly_proj_pred)) + tcx.collect_referenced_late_bound_regions(&bound_predicate.rebind(poly_proj_pred)) } _ => return FxHashSet::default(), }; diff --git a/src/librustdoc/clean/cfg.rs b/src/librustdoc/clean/cfg.rs index c039b181178..b659f3eab43 100644 --- a/src/librustdoc/clean/cfg.rs +++ b/src/librustdoc/clean/cfg.rs @@ -201,6 +201,37 @@ impl Cfg { _ => false, } } + + /// Attempt to simplify this cfg by assuming that `assume` is already known to be true, will + /// return `None` if simplification managed to completely eliminate any requirements from this + /// `Cfg`. + /// + /// See `tests::test_simplify_with` for examples. + pub(crate) fn simplify_with(&self, assume: &Cfg) -> Option<Cfg> { + if self == assume { + return None; + } + + if let Cfg::All(a) = self { + let mut sub_cfgs: Vec<Cfg> = if let Cfg::All(b) = assume { + a.iter().filter(|a| !b.contains(a)).cloned().collect() + } else { + a.iter().filter(|&a| a != assume).cloned().collect() + }; + let len = sub_cfgs.len(); + return match len { + 0 => None, + 1 => sub_cfgs.pop(), + _ => Some(Cfg::All(sub_cfgs)), + }; + } else if let Cfg::All(b) = assume { + if b.contains(self) { + return None; + } + } + + Some(self.clone()) + } } impl ops::Not for Cfg { diff --git a/src/librustdoc/clean/cfg/tests.rs b/src/librustdoc/clean/cfg/tests.rs index 794a7bcaf1c..3a78269f19a 100644 --- a/src/librustdoc/clean/cfg/tests.rs +++ b/src/librustdoc/clean/cfg/tests.rs @@ -433,3 +433,39 @@ fn test_render_long_html() { ); }) } + +#[test] +fn test_simplify_with() { + // This is a tiny subset of things that could be simplified, but it likely covers 90% of + // real world usecases well. + with_default_session_globals(|| { + let foo = word_cfg("foo"); + let bar = word_cfg("bar"); + let baz = word_cfg("baz"); + let quux = word_cfg("quux"); + + let foobar = Cfg::All(vec![foo.clone(), bar.clone()]); + let barbaz = Cfg::All(vec![bar.clone(), baz.clone()]); + let foobarbaz = Cfg::All(vec![foo.clone(), bar.clone(), baz.clone()]); + let bazquux = Cfg::All(vec![baz.clone(), quux.clone()]); + + // Unrelated cfgs don't affect each other + assert_eq!(foo.simplify_with(&bar).as_ref(), Some(&foo)); + assert_eq!(foobar.simplify_with(&bazquux).as_ref(), Some(&foobar)); + + // Identical cfgs are eliminated + assert_eq!(foo.simplify_with(&foo), None); + assert_eq!(foobar.simplify_with(&foobar), None); + + // Multiple cfgs eliminate a single assumed cfg + assert_eq!(foobar.simplify_with(&foo).as_ref(), Some(&bar)); + assert_eq!(foobar.simplify_with(&bar).as_ref(), Some(&foo)); + + // A single cfg is eliminated by multiple assumed cfg containing it + assert_eq!(foo.simplify_with(&foobar), None); + + // Multiple cfgs eliminate the matching subset of multiple assumed cfg + assert_eq!(foobar.simplify_with(&barbaz).as_ref(), Some(&foo)); + assert_eq!(foobar.simplify_with(&foobarbaz), None); + }); +} diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 79ff7fc62d5..6267b02e5d2 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -130,7 +130,7 @@ pub fn try_inline( attrs, inner, visibility: clean::Public, - stability: cx.tcx.lookup_stability(did).clean(cx), + stability: cx.tcx.lookup_stability(did).cloned(), deprecation: cx.tcx.lookup_deprecation(did).clean(cx), def_id: did, }); @@ -461,7 +461,7 @@ pub fn build_impl( name: None, attrs, visibility: clean::Inherited, - stability: tcx.lookup_stability(did).clean(cx), + stability: tcx.lookup_stability(did).cloned(), deprecation: tcx.lookup_deprecation(did).clean(cx), def_id: did, }); diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 501891da573..91941b00be2 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -19,14 +19,13 @@ use rustc_index::vec::{Idx, IndexVec}; use rustc_infer::infer::region_constraints::{Constraint, RegionConstraintData}; use rustc_middle::bug; use rustc_middle::middle::resolve_lifetime as rl; -use rustc_middle::middle::stability; use rustc_middle::ty::fold::TypeFolder; use rustc_middle::ty::subst::{InternalSubsts, Subst}; use rustc_middle::ty::{self, AdtKind, Lift, Ty, TyCtxt}; use rustc_mir::const_eval::{is_const_fn, is_min_const_fn, is_unstable_const_fn}; -use rustc_span::hygiene::MacroKind; +use rustc_span::hygiene::{AstPass, MacroKind}; use rustc_span::symbol::{kw, sym, Ident, Symbol}; -use rustc_span::{self, Pos}; +use rustc_span::{self, ExpnKind, Pos}; use rustc_typeck::hir_ty_to_ty; use std::collections::hash_map::Entry; @@ -274,7 +273,7 @@ impl Clean<Item> for doctree::Module<'_> { attrs, source: span.clean(cx), visibility: self.vis.clean(cx), - stability: cx.stability(self.id).clean(cx), + stability: cx.stability(self.id), deprecation: cx.deprecation(self.id).clean(cx), def_id: cx.tcx.hir().local_def_id(self.id).to_def_id(), inner: ModuleItem(Module { is_crate: self.is_crate, items }), @@ -914,7 +913,7 @@ impl Clean<Item> for doctree::Function<'_> { attrs: self.attrs.clean(cx), source: self.span.clean(cx), visibility: self.vis.clean(cx), - stability: cx.stability(self.id).clean(cx), + stability: cx.stability(self.id), deprecation: cx.deprecation(self.id).clean(cx), def_id: did.to_def_id(), inner: FunctionItem(Function { @@ -1023,7 +1022,7 @@ impl Clean<Item> for doctree::Trait<'_> { source: self.span.clean(cx), def_id: cx.tcx.hir().local_def_id(self.id).to_def_id(), visibility: self.vis.clean(cx), - stability: cx.stability(self.id).clean(cx), + stability: cx.stability(self.id), deprecation: cx.deprecation(self.id).clean(cx), inner: TraitItem(Trait { auto: self.is_auto.clean(cx), @@ -1047,7 +1046,7 @@ impl Clean<Item> for doctree::TraitAlias<'_> { source: self.span.clean(cx), def_id: cx.tcx.hir().local_def_id(self.id).to_def_id(), visibility: self.vis.clean(cx), - stability: cx.stability(self.id).clean(cx), + stability: cx.stability(self.id), deprecation: cx.deprecation(self.id).clean(cx), inner: TraitAliasItem(TraitAlias { generics: self.generics.clean(cx), @@ -1690,7 +1689,10 @@ impl<'tcx> Clean<Type> for Ty<'tcx> { .filter_map(|bound| { // Note: The substs of opaque types can contain unbound variables, // meaning that we have to use `ignore_quantifiers_with_unbound_vars` here. - let trait_ref = match bound.bound_atom(cx.tcx).skip_binder() { + let trait_ref = match bound + .bound_atom_with_opt_escaping(cx.tcx) + .skip_binder() + { ty::PredicateAtom::Trait(tr, _constness) => { ty::Binder::bind(tr.trait_ref) } @@ -1714,7 +1716,7 @@ impl<'tcx> Clean<Type> for Ty<'tcx> { .iter() .filter_map(|bound| { if let ty::PredicateAtom::Projection(proj) = - bound.bound_atom(cx.tcx).skip_binder() + bound.bound_atom_with_opt_escaping(cx.tcx).skip_binder() { if proj.projection_ty.trait_ref(cx.tcx) == trait_ref.skip_binder() @@ -1832,7 +1834,7 @@ impl Clean<Item> for doctree::Struct<'_> { source: self.span.clean(cx), def_id: cx.tcx.hir().local_def_id(self.id).to_def_id(), visibility: self.vis.clean(cx), - stability: cx.stability(self.id).clean(cx), + stability: cx.stability(self.id), deprecation: cx.deprecation(self.id).clean(cx), inner: StructItem(Struct { struct_type: self.struct_type, @@ -1852,7 +1854,7 @@ impl Clean<Item> for doctree::Union<'_> { source: self.span.clean(cx), def_id: cx.tcx.hir().local_def_id(self.id).to_def_id(), visibility: self.vis.clean(cx), - stability: cx.stability(self.id).clean(cx), + stability: cx.stability(self.id), deprecation: cx.deprecation(self.id).clean(cx), inner: UnionItem(Union { struct_type: self.struct_type, @@ -1882,7 +1884,7 @@ impl Clean<Item> for doctree::Enum<'_> { source: self.span.clean(cx), def_id: cx.tcx.hir().local_def_id(self.id).to_def_id(), visibility: self.vis.clean(cx), - stability: cx.stability(self.id).clean(cx), + stability: cx.stability(self.id), deprecation: cx.deprecation(self.id).clean(cx), inner: EnumItem(Enum { variants: self.variants.iter().map(|v| v.clean(cx)).collect(), @@ -1900,7 +1902,7 @@ impl Clean<Item> for doctree::Variant<'_> { attrs: self.attrs.clean(cx), source: self.span.clean(cx), visibility: Inherited, - stability: cx.stability(self.id).clean(cx), + stability: cx.stability(self.id), deprecation: cx.deprecation(self.id).clean(cx), def_id: cx.tcx.hir().local_def_id(self.id).to_def_id(), inner: VariantItem(Variant { kind: self.def.clean(cx) }), @@ -2049,7 +2051,7 @@ impl Clean<Item> for doctree::Typedef<'_> { source: self.span.clean(cx), def_id: cx.tcx.hir().local_def_id(self.id).to_def_id(), visibility: self.vis.clean(cx), - stability: cx.stability(self.id).clean(cx), + stability: cx.stability(self.id), deprecation: cx.deprecation(self.id).clean(cx), inner: TypedefItem(Typedef { type_, generics: self.gen.clean(cx), item_type }, false), } @@ -2064,7 +2066,7 @@ impl Clean<Item> for doctree::OpaqueTy<'_> { source: self.span.clean(cx), def_id: cx.tcx.hir().local_def_id(self.id).to_def_id(), visibility: self.vis.clean(cx), - stability: cx.stability(self.id).clean(cx), + stability: cx.stability(self.id), deprecation: cx.deprecation(self.id).clean(cx), inner: OpaqueTyItem(OpaqueTy { bounds: self.opaque_ty.bounds.clean(cx), @@ -2092,7 +2094,7 @@ impl Clean<Item> for doctree::Static<'_> { source: self.span.clean(cx), def_id: cx.tcx.hir().local_def_id(self.id).to_def_id(), visibility: self.vis.clean(cx), - stability: cx.stability(self.id).clean(cx), + stability: cx.stability(self.id), deprecation: cx.deprecation(self.id).clean(cx), inner: StaticItem(Static { type_: self.type_.clean(cx), @@ -2113,7 +2115,7 @@ impl Clean<Item> for doctree::Constant<'_> { source: self.span.clean(cx), def_id: def_id.to_def_id(), visibility: self.vis.clean(cx), - stability: cx.stability(self.id).clean(cx), + stability: cx.stability(self.id), deprecation: cx.deprecation(self.id).clean(cx), inner: ConstantItem(Constant { type_: self.type_.clean(cx), @@ -2167,7 +2169,7 @@ impl Clean<Vec<Item>> for doctree::Impl<'_> { source: self.span.clean(cx), def_id: def_id.to_def_id(), visibility: self.vis.clean(cx), - stability: cx.stability(self.id).clean(cx), + stability: cx.stability(self.id), deprecation: cx.deprecation(self.id).clean(cx), inner: ImplItem(Impl { unsafety: self.unsafety, @@ -2232,6 +2234,13 @@ impl Clean<Vec<Item>> for doctree::ExternCrate<'_> { impl Clean<Vec<Item>> for doctree::Import<'_> { fn clean(&self, cx: &DocContext<'_>) -> Vec<Item> { + // We need this comparison because some imports (for std types for example) + // are "inserted" as well but directly by the compiler and they should not be + // taken into account. + if self.span.ctxt().outer_expn_data().kind == ExpnKind::AstPass(AstPass::StdImports) { + return Vec::new(); + } + // We consider inlining the documentation of `pub use` statements, but we // forcefully don't inline if this is not public or if the // #[doc(no_inline)] attribute is present. @@ -2349,7 +2358,7 @@ impl Clean<Item> for doctree::ForeignItem<'_> { source: self.span.clean(cx), def_id: cx.tcx.hir().local_def_id(self.id).to_def_id(), visibility: self.vis.clean(cx), - stability: cx.stability(self.id).clean(cx), + stability: cx.stability(self.id), deprecation: cx.deprecation(self.id).clean(cx), inner, } @@ -2364,7 +2373,7 @@ impl Clean<Item> for doctree::Macro<'_> { attrs: self.attrs.clean(cx), source: self.span.clean(cx), visibility: Public, - stability: cx.stability(self.hid).clean(cx), + stability: cx.stability(self.hid), deprecation: cx.deprecation(self.hid).clean(cx), def_id: self.def_id, inner: MacroItem(Macro { @@ -2389,7 +2398,7 @@ impl Clean<Item> for doctree::ProcMacro<'_> { attrs: self.attrs.clean(cx), source: self.span.clean(cx), visibility: Public, - stability: cx.stability(self.id).clean(cx), + stability: cx.stability(self.id), deprecation: cx.deprecation(self.id).clean(cx), def_id: cx.tcx.hir().local_def_id(self.id).to_def_id(), inner: ProcMacroItem(ProcMacro { kind: self.kind, helpers: self.helpers.clean(cx) }), @@ -2397,27 +2406,6 @@ impl Clean<Item> for doctree::ProcMacro<'_> { } } -impl Clean<Stability> for attr::Stability { - fn clean(&self, _: &DocContext<'_>) -> Stability { - Stability { - level: stability::StabilityLevel::from_attr_level(&self.level), - feature: self.feature.to_string(), - since: match self.level { - attr::Stable { ref since } => since.to_string(), - _ => String::new(), - }, - unstable_reason: match self.level { - attr::Unstable { reason: Some(ref reason), .. } => Some(reason.to_string()), - _ => None, - }, - issue: match self.level { - attr::Unstable { issue, .. } => issue, - _ => None, - }, - } - } -} - impl Clean<Deprecation> for attr::Deprecation { fn clean(&self, _: &DocContext<'_>) -> Deprecation { Deprecation { diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 1e07f8e2eac..32b3f69ecd4 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -4,7 +4,6 @@ use std::fmt; use std::hash::{Hash, Hasher}; use std::iter::FromIterator; use std::lazy::SyncOnceCell as OnceCell; -use std::num::NonZeroU32; use std::rc::Rc; use std::sync::Arc; use std::{slice, vec}; @@ -13,18 +12,19 @@ use rustc_ast::attr; use rustc_ast::util::comments::beautify_doc_string; use rustc_ast::{self as ast, AttrStyle}; use rustc_ast::{FloatTy, IntTy, UintTy}; +use rustc_attr::{Stability, StabilityLevel}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_feature::UnstableFeatures; use rustc_hir as hir; use rustc_hir::def::Res; use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; use rustc_hir::lang_items::LangItem; use rustc_hir::Mutability; use rustc_index::vec::IndexVec; -use rustc_middle::middle::stability; use rustc_middle::ty::{AssocKind, TyCtxt}; use rustc_span::hygiene::MacroKind; use rustc_span::source_map::DUMMY_SP; -use rustc_span::symbol::{kw, sym, Ident, Symbol}; +use rustc_span::symbol::{kw, sym, Ident, Symbol, SymbolStr}; use rustc_span::{self, FileName}; use rustc_target::abi::VariantIdx; use rustc_target::spec::abi::Abi; @@ -197,7 +197,7 @@ impl Item { self.stability.as_ref().and_then(|ref s| { let mut classes = Vec::with_capacity(2); - if s.level == stability::Unstable { + if s.level.is_unstable() { classes.push("unstable"); } @@ -210,8 +210,11 @@ impl Item { }) } - pub fn stable_since(&self) -> Option<&str> { - self.stability.as_ref().map(|s| &s.since[..]) + pub fn stable_since(&self) -> Option<SymbolStr> { + match self.stability?.level { + StabilityLevel::Stable { since, .. } => Some(since.as_str()), + StabilityLevel::Unstable { .. } => None, + } } pub fn is_non_exhaustive(&self) -> bool { @@ -393,24 +396,6 @@ pub enum DocFragmentKind { /// A doc fragment created from a `#[doc(include="filename")]` attribute. Contains both the /// given filename and the file contents. Include { filename: String }, - /// A doc fragment used to distinguish between documentation in different modules. - /// - /// In particular, this prevents `collapse_docs` from turning all documentation comments - /// into a single giant attributes even when the item is re-exported with documentation on the re-export. - Divider, -} - -impl DocFragment { - /// Creates a dummy doc-fragment which divides earlier and later fragments. - fn divider() -> Self { - DocFragment { - line: 0, - span: DUMMY_SP, - parent_module: None, - doc: String::new(), - kind: DocFragmentKind::Divider, - } - } } impl<'a> FromIterator<&'a DocFragment> for String { @@ -551,7 +536,7 @@ impl Attributes { attrs: &[ast::Attribute], additional_attrs: Option<(&[ast::Attribute], DefId)>, ) -> Attributes { - let doc_strings = RefCell::new(vec![]); + let mut doc_strings = vec![]; let mut sp = None; let mut cfg = Cfg::True; let mut doc_line = 0; @@ -568,7 +553,7 @@ impl Attributes { let line = doc_line; doc_line += value.lines().count(); - doc_strings.borrow_mut().push(DocFragment { + doc_strings.push(DocFragment { line, span: attr.span, doc: value, @@ -593,7 +578,7 @@ impl Attributes { { let line = doc_line; doc_line += contents.lines().count(); - doc_strings.borrow_mut().push(DocFragment { + doc_strings.push(DocFragment { line, span: attr.span, doc: contents, @@ -610,10 +595,7 @@ impl Attributes { // Additional documentation should be shown before the original documentation let other_attrs = additional_attrs .into_iter() - .map(|(attrs, id)| { - doc_strings.borrow_mut().push(DocFragment::divider()); - attrs.iter().map(move |attr| (attr, Some(id))) - }) + .map(|(attrs, id)| attrs.iter().map(move |attr| (attr, Some(id)))) .flatten() .chain(attrs.iter().map(|attr| (attr, None))) .filter_map(clean_attr) @@ -642,7 +624,7 @@ impl Attributes { .map_or(true, |a| a.style == AttrStyle::Inner); Attributes { - doc_strings: doc_strings.into_inner(), + doc_strings, other_attrs, cfg: if cfg == Cfg::True { None } else { Some(Arc::new(cfg)) }, span: sp, @@ -698,9 +680,13 @@ impl Attributes { "../".repeat(depth) } Some(&(_, _, ExternalLocation::Remote(ref s))) => s.to_string(), - Some(&(_, _, ExternalLocation::Unknown)) | None => { - String::from("https://doc.rust-lang.org/nightly") - } + Some(&(_, _, ExternalLocation::Unknown)) | None => String::from( + if UnstableFeatures::from_environment().is_nightly_build() { + "https://doc.rust-lang.org/nightly" + } else { + "https://doc.rust-lang.org" + }, + ), }; // This is a primitive so the url is done "by hand". let tail = fragment.find('#').unwrap_or_else(|| fragment.len()); @@ -1720,15 +1706,6 @@ pub struct ProcMacro { } #[derive(Clone, Debug)] -pub struct Stability { - pub level: stability::StabilityLevel, - pub feature: String, - pub since: String, - pub unstable_reason: Option<String>, - pub issue: Option<NonZeroU32>, -} - -#[derive(Clone, Debug)] pub struct Deprecation { pub since: Option<String>, pub note: Option<String>, diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index 913342e2715..9a7f1964a11 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -3,12 +3,13 @@ use crate::clean::blanket_impl::BlanketImplFinder; use crate::clean::{ inline, Clean, Crate, Deprecation, ExternalCrate, FnDecl, FnRetTy, Generic, GenericArg, GenericArgs, GenericBound, Generics, GetDefId, ImportSource, Item, ItemEnum, Lifetime, - MacroKind, Path, PathSegment, Primitive, PrimitiveType, ResolvedPath, Span, Stability, Type, - TypeBinding, TypeKind, Visibility, WherePredicate, + MacroKind, Path, PathSegment, Primitive, PrimitiveType, ResolvedPath, Span, Type, TypeBinding, + TypeKind, Visibility, WherePredicate, }; use crate::core::DocContext; use itertools::Itertools; +use rustc_attr::Stability; use rustc_data_structures::fx::FxHashSet; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; @@ -102,14 +103,14 @@ pub fn krate(mut cx: &mut DocContext<'_>) -> Crate { // extract the stability index for a node from tcx, if possible pub fn get_stability(cx: &DocContext<'_>, def_id: DefId) -> Option<Stability> { - cx.tcx.lookup_stability(def_id).clean(cx) + cx.tcx.lookup_stability(def_id).cloned() } pub fn get_deprecation(cx: &DocContext<'_>, def_id: DefId) -> Option<Deprecation> { cx.tcx.lookup_deprecation(def_id).clean(cx) } -pub fn external_generic_args( +fn external_generic_args( cx: &DocContext<'_>, trait_did: Option<DefId>, has_self: bool, @@ -159,7 +160,7 @@ pub fn external_generic_args( // trait_did should be set to a trait's DefId if called on a TraitRef, in order to sugar // from Fn<(A, B,), C> to Fn(A, B) -> C -pub fn external_path( +pub(super) fn external_path( cx: &DocContext<'_>, name: Symbol, trait_did: Option<DefId>, diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 76334f0213d..91e12e3a135 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -49,6 +49,7 @@ use std::sync::Arc; use itertools::Itertools; use rustc_ast_pretty::pprust; +use rustc_attr::StabilityLevel; use rustc_data_structures::flock; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_feature::UnstableFeatures; @@ -539,11 +540,11 @@ impl FormatRenderer for Context { }; let sidebar = if let Some(ref version) = cache.crate_version { format!( - "<p class='location'>Crate {}</p>\ - <div class='block version'>\ + "<p class=\"location\">Crate {}</p>\ + <div class=\"block version\">\ <p>Version {}</p>\ </div>\ - <a id='all-types' href='index.html'><p>Back to index</p></a>", + <a id=\"all-types\" href=\"index.html\"><p>Back to index</p></a>", crate_name, Escape(version), ) @@ -566,7 +567,7 @@ impl FormatRenderer for Context { page.root_path = "./"; let mut style_files = self.shared.style_files.clone(); - let sidebar = "<p class='location'>Settings</p><div class='sidebar-elems'></div>"; + let sidebar = "<p class=\"location\">Settings</p><div class=\"sidebar-elems\"></div>"; style_files.push(StylePath { path: PathBuf::from("settings.css"), disabled: false }); let v = layout::render( &self.shared.layout, @@ -575,7 +576,8 @@ impl FormatRenderer for Context { settings( self.shared.static_root_path.as_deref().unwrap_or("./"), &self.shared.resource_suffix, - ), + &self.shared.style_files, + )?, &style_files, ); self.shared.fs.write(&settings_file, v.as_bytes())?; @@ -806,10 +808,11 @@ function handleThemeButtonsBlur(e) {{ themePicker.onclick = switchThemeButtonState; themePicker.onblur = handleThemeButtonsBlur; {}.forEach(function(item) {{ - var but = document.createElement('button'); + var but = document.createElement("button"); but.textContent = item; but.onclick = function(el) {{ switchTheme(currentTheme, mainTheme, item, true); + useSystemTheme(false); }}; but.onblur = handleThemeButtonsBlur; themes.appendChild(but); @@ -1061,10 +1064,9 @@ themePicker.onblur = handleThemeButtonsBlur; krates.dedup(); let content = format!( - "<h1 class='fqn'>\ - <span class='in-band'>List of all crates</span>\ - </h1>\ - <ul class='crate mod'>{}</ul>", + "<h1 class=\"fqn\">\ + <span class=\"in-band\">List of all crates</span>\ + </h1><ul class=\"crate mod\">{}</ul>", krates .iter() .map(|s| { @@ -1208,7 +1210,7 @@ impl ItemEntry { impl ItemEntry { crate fn print(&self) -> impl fmt::Display + '_ { crate::html::format::display_fn(move |f| { - write!(f, "<a href='{}'>{}</a>", self.url, Escape(&self.name)) + write!(f, "<a href=\"{}\">{}</a>", self.url, Escape(&self.name)) }) } } @@ -1299,7 +1301,7 @@ fn print_entries(f: &mut Buffer, e: &FxHashSet<ItemEntry>, title: &str, class: & e.sort(); write!( f, - "<h3 id='{}'>{}</h3><ul class='{} docblock'>{}</ul>", + "<h3 id=\"{}\">{}</h3><ul class=\"{} docblock\">{}</ul>", title, Escape(title), class, @@ -1312,16 +1314,16 @@ impl AllTypes { fn print(self, f: &mut Buffer) { write!( f, - "<h1 class='fqn'>\ - <span class='out-of-band'>\ - <span id='render-detail'>\ + "<h1 class=\"fqn\">\ + <span class=\"out-of-band\">\ + <span id=\"render-detail\">\ <a id=\"toggle-all-docs\" href=\"javascript:void(0)\" \ title=\"collapse all docs\">\ - [<span class='inner'>−</span>]\ + [<span class=\"inner\">−</span>]\ </a>\ </span> </span> - <span class='in-band'>List of all items</span>\ + <span class=\"in-band\">List of all items</span>\ </h1>" ); print_entries(f, &self.structs, "Structs", "structs"); @@ -1343,32 +1345,67 @@ impl AllTypes { #[derive(Debug)] enum Setting { - Section { description: &'static str, sub_settings: Vec<Setting> }, - Entry { js_data_name: &'static str, description: &'static str, default_value: bool }, + Section { + description: &'static str, + sub_settings: Vec<Setting>, + }, + Toggle { + js_data_name: &'static str, + description: &'static str, + default_value: bool, + }, + Select { + js_data_name: &'static str, + description: &'static str, + default_value: &'static str, + options: Vec<(String, String)>, + }, } impl Setting { - fn display(&self) -> String { + fn display(&self, root_path: &str, suffix: &str) -> String { match *self { - Setting::Section { ref description, ref sub_settings } => format!( - "<div class='setting-line'>\ - <div class='title'>{}</div>\ - <div class='sub-settings'>{}</div> + Setting::Section { description, ref sub_settings } => format!( + "<div class=\"setting-line\">\ + <div class=\"title\">{}</div>\ + <div class=\"sub-settings\">{}</div> </div>", description, - sub_settings.iter().map(|s| s.display()).collect::<String>() + sub_settings.iter().map(|s| s.display(root_path, suffix)).collect::<String>() ), - Setting::Entry { ref js_data_name, ref description, ref default_value } => format!( - "<div class='setting-line'>\ - <label class='toggle'>\ - <input type='checkbox' id='{}' {}>\ - <span class='slider'></span>\ + Setting::Toggle { js_data_name, description, default_value } => format!( + "<div class=\"setting-line\">\ + <label class=\"toggle\">\ + <input type=\"checkbox\" id=\"{}\" {}>\ + <span class=\"slider\"></span>\ </label>\ <div>{}</div>\ </div>", js_data_name, - if *default_value { " checked" } else { "" }, + if default_value { " checked" } else { "" }, + description, + ), + Setting::Select { js_data_name, description, default_value, ref options } => format!( + "<div class=\"setting-line\">\ + <div>{}</div>\ + <label class=\"select-wrapper\">\ + <select id=\"{}\" autocomplete=\"off\">{}</select>\ + <img src=\"{}down-arrow{}.svg\" alt=\"Select item\">\ + </label>\ + </div>", description, + js_data_name, + options + .iter() + .map(|opt| format!( + "<option value=\"{}\" {}>{}</option>", + opt.0, + if &opt.0 == default_value { "selected" } else { "" }, + opt.1, + )) + .collect::<String>(), + root_path, + suffix, ), } } @@ -1376,7 +1413,7 @@ impl Setting { impl From<(&'static str, &'static str, bool)> for Setting { fn from(values: (&'static str, &'static str, bool)) -> Setting { - Setting::Entry { js_data_name: values.0, description: values.1, default_value: values.2 } + Setting::Toggle { js_data_name: values.0, description: values.1, default_value: values.2 } } } @@ -1389,10 +1426,40 @@ impl<T: Into<Setting>> From<(&'static str, Vec<T>)> for Setting { } } -fn settings(root_path: &str, suffix: &str) -> String { +fn settings(root_path: &str, suffix: &str, themes: &[StylePath]) -> Result<String, Error> { + let theme_names: Vec<(String, String)> = themes + .iter() + .map(|entry| { + let theme = + try_none!(try_none!(entry.path.file_stem(), &entry.path).to_str(), &entry.path) + .to_string(); + + Ok((theme.clone(), theme)) + }) + .collect::<Result<_, Error>>()?; + // (id, explanation, default value) let settings: &[Setting] = &[ ( + "Theme preferences", + vec![ + Setting::from(("use-system-theme", "Use system theme", true)), + Setting::Select { + js_data_name: "preferred-dark-theme", + description: "Preferred dark theme", + default_value: "dark", + options: theme_names.clone(), + }, + Setting::Select { + js_data_name: "preferred-light-theme", + description: "Preferred light theme", + default_value: "light", + options: theme_names, + }, + ], + ) + .into(), + ( "Auto-hide item declarations", vec![ ("auto-hide-struct", "Auto-hide structs declaration", true), @@ -1413,16 +1480,17 @@ fn settings(root_path: &str, suffix: &str) -> String { ("line-numbers", "Show line numbers on code examples", false).into(), ("disable-shortcuts", "Disable keyboard shortcuts", false).into(), ]; - format!( - "<h1 class='fqn'>\ - <span class='in-band'>Rustdoc settings</span>\ -</h1>\ -<div class='settings'>{}</div>\ -<script src='{}settings{}.js'></script>", - settings.iter().map(|s| s.display()).collect::<String>(), + + Ok(format!( + "<h1 class=\"fqn\">\ + <span class=\"in-band\">Rustdoc settings</span>\ + </h1>\ + <div class=\"settings\">{}</div>\ + <script src=\"{}settings{}.js\"></script>", + settings.iter().map(|s| s.display(root_path, suffix)).collect::<String>(), root_path, suffix - ) + )) } impl Context { @@ -1611,20 +1679,20 @@ where fn print_item(cx: &Context, item: &clean::Item, buf: &mut Buffer, cache: &Cache) { debug_assert!(!item.is_stripped()); // Write the breadcrumb trail header for the top - write!(buf, "<h1 class='fqn'><span class='out-of-band'>"); + write!(buf, "<h1 class=\"fqn\"><span class=\"out-of-band\">"); if let Some(version) = item.stable_since() { write!( buf, - "<span class='since' title='Stable since Rust version {0}'>{0}</span>", + "<span class=\"since\" title=\"Stable since Rust version {0}\">{0}</span>", version ); } write!( buf, - "<span id='render-detail'>\ + "<span id=\"render-detail\">\ <a id=\"toggle-all-docs\" href=\"javascript:void(0)\" \ title=\"collapse all docs\">\ - [<span class='inner'>−</span>]\ + [<span class=\"inner\">−</span>]\ </a>\ </span>" ); @@ -1637,12 +1705,16 @@ fn print_item(cx: &Context, item: &clean::Item, buf: &mut Buffer, cache: &Cache) // used to find the link to auto-click. if cx.shared.include_sources && !item.is_primitive() { if let Some(l) = cx.src_href(item, cache) { - write!(buf, "<a class='srclink' href='{}' title='{}'>[src]</a>", l, "goto source code"); + write!( + buf, + "<a class=\"srclink\" href=\"{}\" title=\"{}\">[src]</a>", + l, "goto source code" + ); } } write!(buf, "</span>"); // out-of-band - write!(buf, "<span class='in-band'>"); + write!(buf, "<span class=\"in-band\">"); let name = match item.inner { clean::ModuleItem(ref m) => { if m.is_crate { @@ -1682,13 +1754,13 @@ fn print_item(cx: &Context, item: &clean::Item, buf: &mut Buffer, cache: &Cache) for (i, component) in cur.iter().enumerate().take(amt) { write!( buf, - "<a href='{}index.html'>{}</a>::<wbr>", + "<a href=\"{}index.html\">{}</a>::<wbr>", "../".repeat(cur.len() - i - 1), component ); } } - write!(buf, "<a class=\"{}\" href=''>{}</a>", item.type_(), item.name.as_ref().unwrap()); + write!(buf, "<a class=\"{}\" href=\"\">{}</a>", item.type_(), item.name.as_ref().unwrap()); write!(buf, "</span></h1>"); // in-band @@ -1762,11 +1834,11 @@ crate fn shorten(s: String) -> String { } } -fn document(w: &mut Buffer, cx: &Context, item: &clean::Item) { +fn document(w: &mut Buffer, cx: &Context, item: &clean::Item, parent: Option<&clean::Item>) { if let Some(ref name) = item.name { info!("Documenting {}", name); } - document_stability(w, cx, item, false); + document_stability(w, cx, item, false, parent); document_full(w, item, cx, "", false); } @@ -1782,7 +1854,7 @@ fn render_markdown( let mut ids = cx.id_map.borrow_mut(); write!( w, - "<div class='docblock{}'>{}{}</div>", + "<div class=\"docblock{}\">{}{}</div>", if is_hidden { " hidden" } else { "" }, prefix, Markdown( @@ -1829,7 +1901,7 @@ fn document_short( } else if !prefix.is_empty() { write!( w, - "<div class='docblock{}'>{}</div>", + "<div class=\"docblock{}\">{}</div>", if is_hidden { " hidden" } else { "" }, prefix ); @@ -1843,17 +1915,23 @@ fn document_full(w: &mut Buffer, item: &clean::Item, cx: &Context, prefix: &str, } else if !prefix.is_empty() { write!( w, - "<div class='docblock{}'>{}</div>", + "<div class=\"docblock{}\">{}</div>", if is_hidden { " hidden" } else { "" }, prefix ); } } -fn document_stability(w: &mut Buffer, cx: &Context, item: &clean::Item, is_hidden: bool) { - let stabilities = short_stability(item, cx); +fn document_stability( + w: &mut Buffer, + cx: &Context, + item: &clean::Item, + is_hidden: bool, + parent: Option<&clean::Item>, +) { + let stabilities = short_stability(item, cx, parent); if !stabilities.is_empty() { - write!(w, "<div class='stability{}'>", if is_hidden { " hidden" } else { "" }); + write!(w, "<div class=\"stability{}\">", if is_hidden { " hidden" } else { "" }); for stability in stabilities { write!(w, "{}", stability); } @@ -1867,7 +1945,7 @@ fn document_non_exhaustive_header(item: &clean::Item) -> &str { fn document_non_exhaustive(w: &mut Buffer, item: &clean::Item) { if item.is_non_exhaustive() { - write!(w, "<div class='docblock non-exhaustive non-exhaustive-{}'>", { + write!(w, "<div class=\"docblock non-exhaustive non-exhaustive-{}\">", { if item.is_struct() { "struct" } else if item.is_enum() { @@ -1951,7 +2029,7 @@ pub fn compare_names(mut lhs: &str, mut rhs: &str) -> Ordering { } fn item_module(w: &mut Buffer, cx: &Context, item: &clean::Item, items: &[clean::Item]) { - document(w, cx, item); + document(w, cx, item, None); let mut indices = (0..items.len()).filter(|i| !items[*i].is_stripped()).collect::<Vec<usize>>(); @@ -1983,10 +2061,12 @@ fn item_module(w: &mut Buffer, cx: &Context, item: &clean::Item, items: &[clean: } let s1 = i1.stability.as_ref().map(|s| s.level); let s2 = i2.stability.as_ref().map(|s| s.level); - match (s1, s2) { - (Some(stability::Unstable), Some(stability::Stable)) => return Ordering::Greater, - (Some(stability::Stable), Some(stability::Unstable)) => return Ordering::Less, - _ => {} + if let (Some(a), Some(b)) = (s1, s2) { + match (a.is_stable(), b.is_stable()) { + (true, true) | (false, false) => {} + (false, true) => return Ordering::Less, + (true, false) => return Ordering::Greater, + } } let lhs = i1.name.as_ref().map_or("", |s| &**s); let rhs = i2.name.as_ref().map_or("", |s| &**s); @@ -2044,7 +2124,7 @@ fn item_module(w: &mut Buffer, cx: &Context, item: &clean::Item, items: &[clean: let (short, name) = item_ty_to_strs(&myty.unwrap()); write!( w, - "<h2 id='{id}' class='section-header'>\ + "<h2 id=\"{id}\" class=\"section-header\">\ <a href=\"#{id}\">{name}</a></h2>\n<table>", id = cx.derive_id(short.to_owned()), name = name @@ -2091,7 +2171,7 @@ fn item_module(w: &mut Buffer, cx: &Context, item: &clean::Item, items: &[clean: clean::FunctionItem(ref func) | clean::ForeignFunctionItem(ref func) if func.header.unsafety == hir::Unsafety::Unsafe => { - "<a title='unsafe function' href='#'><sup>⚠</sup></a>" + "<a title=\"unsafe function\" href=\"#\"><sup>⚠</sup></a>" } _ => "", }; @@ -2102,13 +2182,13 @@ fn item_module(w: &mut Buffer, cx: &Context, item: &clean::Item, items: &[clean: let doc_value = myitem.doc_value().unwrap_or(""); write!( w, - "<tr class='{stab}{add}module-item'>\ + "<tr class=\"{stab}{add}module-item\">\ <td><a class=\"{class}\" href=\"{href}\" \ - title='{title}'>{name}</a>{unsafety_flag}</td>\ - <td class='docblock-short'>{stab_tags}{docs}</td>\ + title=\"{title}\">{name}</a>{unsafety_flag}</td>\ + <td class=\"docblock-short\">{stab_tags}{docs}</td>\ </tr>", name = *myitem.name.as_ref().unwrap(), - stab_tags = stability_tags(myitem), + stab_tags = stability_tags(myitem, item), docs = MarkdownSummaryLine(doc_value, &myitem.links()).into_string(), class = myitem.type_(), add = add, @@ -2132,7 +2212,7 @@ fn item_module(w: &mut Buffer, cx: &Context, item: &clean::Item, items: &[clean: /// Render the stability and deprecation tags that are displayed in the item's summary at the /// module level. -fn stability_tags(item: &clean::Item) -> String { +fn stability_tags(item: &clean::Item, parent: &clean::Item) -> String { let mut tags = String::new(); fn tag_html(class: &str, title: &str, contents: &str) -> String { @@ -2150,16 +2230,19 @@ fn stability_tags(item: &clean::Item) -> String { // The "rustc_private" crates are permanently unstable so it makes no sense // to render "unstable" everywhere. - if item - .stability - .as_ref() - .map(|s| s.level == stability::Unstable && s.feature != "rustc_private") + if item.stability.as_ref().map(|s| s.level.is_unstable() && s.feature != sym::rustc_private) == Some(true) { tags += &tag_html("unstable", "", "Experimental"); } - if let Some(ref cfg) = item.attrs.cfg { + let cfg = match (&item.attrs.cfg, parent.attrs.cfg.as_ref()) { + (Some(cfg), Some(parent_cfg)) => cfg.simplify_with(parent_cfg), + (cfg, _) => cfg.as_deref().cloned(), + }; + + debug!("Portability {:?} - {:?} = {:?}", item.attrs.cfg, parent.attrs.cfg, cfg); + if let Some(ref cfg) = cfg { tags += &tag_html("portability", &cfg.render_long_plain(), &cfg.render_short_html()); } @@ -2168,7 +2251,7 @@ fn stability_tags(item: &clean::Item) -> String { /// Render the stability and/or deprecation warning that is displayed at the top of the item's /// documentation. -fn short_stability(item: &clean::Item, cx: &Context) -> Vec<String> { +fn short_stability(item: &clean::Item, cx: &Context, parent: Option<&clean::Item>) -> Vec<String> { let mut stability = vec![]; let error_codes = cx.shared.codes; @@ -2197,23 +2280,24 @@ fn short_stability(item: &clean::Item, cx: &Context) -> Vec<String> { message.push_str(&format!(": {}", html.into_string())); } stability.push(format!( - "<div class='stab deprecated'><span class='emoji'>👎</span> {}</div>", + "<div class=\"stab deprecated\"><span class=\"emoji\">👎</span> {}</div>", message, )); } // Render unstable items. But don't render "rustc_private" crates (internal compiler crates). // Those crates are permanently unstable so it makes no sense to render "unstable" everywhere. - if let Some(stab) = item + if let Some((StabilityLevel::Unstable { reason, issue, .. }, feature)) = item .stability .as_ref() - .filter(|stab| stab.level == stability::Unstable && stab.feature != "rustc_private") + .filter(|stab| stab.feature != sym::rustc_private) + .map(|stab| (stab.level, stab.feature)) { let mut message = - "<span class='emoji'>🔬</span> This is a nightly-only experimental API.".to_owned(); + "<span class=\"emoji\">🔬</span> This is a nightly-only experimental API.".to_owned(); - let mut feature = format!("<code>{}</code>", Escape(&stab.feature)); - if let (Some(url), Some(issue)) = (&cx.shared.issue_tracker_base_url, stab.issue) { + let mut feature = format!("<code>{}</code>", Escape(&feature.as_str())); + if let (Some(url), Some(issue)) = (&cx.shared.issue_tracker_base_url, issue) { feature.push_str(&format!( " <a href=\"{url}{issue}\">#{issue}</a>", url = url, @@ -2223,13 +2307,13 @@ fn short_stability(item: &clean::Item, cx: &Context) -> Vec<String> { message.push_str(&format!(" ({})", feature)); - if let Some(unstable_reason) = &stab.unstable_reason { + if let Some(unstable_reason) = reason { let mut ids = cx.id_map.borrow_mut(); message = format!( "<details><summary>{}</summary>{}</details>", message, MarkdownHtml( - &unstable_reason, + &unstable_reason.as_str(), &mut ids, error_codes, cx.shared.edition, @@ -2239,18 +2323,29 @@ fn short_stability(item: &clean::Item, cx: &Context) -> Vec<String> { ); } - stability.push(format!("<div class='stab unstable'>{}</div>", message)); + stability.push(format!("<div class=\"stab unstable\">{}</div>", message)); } - if let Some(ref cfg) = item.attrs.cfg { - stability.push(format!("<div class='stab portability'>{}</div>", cfg.render_long_html())); + let cfg = match (&item.attrs.cfg, parent.and_then(|p| p.attrs.cfg.as_ref())) { + (Some(cfg), Some(parent_cfg)) => cfg.simplify_with(parent_cfg), + (cfg, _) => cfg.as_deref().cloned(), + }; + + debug!( + "Portability {:?} - {:?} = {:?}", + item.attrs.cfg, + parent.and_then(|p| p.attrs.cfg.as_ref()), + cfg + ); + if let Some(cfg) = cfg { + stability.push(format!("<div class=\"stab portability\">{}</div>", cfg.render_long_html())); } stability } fn item_constant(w: &mut Buffer, cx: &Context, it: &clean::Item, c: &clean::Constant) { - write!(w, "<pre class='rust const'>"); + write!(w, "<pre class=\"rust const\">"); render_attributes(w, it, false); write!( @@ -2281,11 +2376,11 @@ fn item_constant(w: &mut Buffer, cx: &Context, it: &clean::Item, c: &clean::Cons } write!(w, "</pre>"); - document(w, cx, it) + document(w, cx, it, None) } fn item_static(w: &mut Buffer, cx: &Context, it: &clean::Item, s: &clean::Static) { - write!(w, "<pre class='rust static'>"); + write!(w, "<pre class=\"rust static\">"); render_attributes(w, it, false); write!( w, @@ -2295,7 +2390,7 @@ fn item_static(w: &mut Buffer, cx: &Context, it: &clean::Item, s: &clean::Static name = it.name.as_ref().unwrap(), typ = s.type_.print() ); - document(w, cx, it) + document(w, cx, it, None) } fn item_function(w: &mut Buffer, cx: &Context, it: &clean::Item, f: &clean::Function) { @@ -2310,7 +2405,7 @@ fn item_function(w: &mut Buffer, cx: &Context, it: &clean::Item, f: &clean::Func f.generics.print() ) .len(); - write!(w, "<pre class='rust fn'>"); + write!(w, "<pre class=\"rust fn\">"); render_attributes(w, it, false); write!( w, @@ -2328,7 +2423,7 @@ fn item_function(w: &mut Buffer, cx: &Context, it: &clean::Item, f: &clean::Func .print(), spotlight = spotlight_decl(&f.decl), ); - document(w, cx, it) + document(w, cx, it, None) } fn render_implementor( @@ -2353,9 +2448,10 @@ fn render_implementor( w, cx, implementor, + None, AssocItemLink::Anchor(None), RenderMode::Normal, - implementor.impl_item.stable_since(), + implementor.impl_item.stable_since().as_deref(), false, Some(use_absolute), false, @@ -2382,9 +2478,10 @@ fn render_impls( &mut buffer, cx, i, + Some(containing_item), assoc_link, RenderMode::Normal, - containing_item.stable_since(), + containing_item.stable_since().as_deref(), true, None, false, @@ -2432,7 +2529,7 @@ fn item_trait(w: &mut Buffer, cx: &Context, it: &clean::Item, t: &clean::Trait, // Output the trait definition wrap_into_docblock(w, |w| { - write!(w, "<pre class='rust trait'>"); + write!(w, "<pre class=\"rust trait\">"); render_attributes(w, it, true); write!( w, @@ -2475,7 +2572,7 @@ fn item_trait(w: &mut Buffer, cx: &Context, it: &clean::Item, t: &clean::Trait, write!(w, ";\n"); if pos < required.len() - 1 { - write!(w, "<div class='item-spacer'></div>"); + write!(w, "<div class=\"item-spacer\"></div>"); } } if !required.is_empty() && !provided.is_empty() { @@ -2492,7 +2589,7 @@ fn item_trait(w: &mut Buffer, cx: &Context, it: &clean::Item, t: &clean::Trait, } } if pos < provided.len() - 1 { - write!(w, "<div class='item-spacer'></div>"); + write!(w, "<div class=\"item-spacer\"></div>"); } } write!(w, "}}"); @@ -2501,32 +2598,33 @@ fn item_trait(w: &mut Buffer, cx: &Context, it: &clean::Item, t: &clean::Trait, }); // Trait documentation - document(w, cx, it); + document(w, cx, it, None); fn write_small_section_header(w: &mut Buffer, id: &str, title: &str, extra_content: &str) { write!( w, - "<h2 id='{0}' class='small-section-header'>\ - {1}<a href='#{0}' class='anchor'></a>\ + "<h2 id=\"{0}\" class=\"small-section-header\">\ + {1}<a href=\"#{0}\" class=\"anchor\"></a>\ </h2>{2}", id, title, extra_content ) } fn write_loading_content(w: &mut Buffer, extra_content: &str) { - write!(w, "{}<span class='loading-content'>Loading content...</span>", extra_content) + write!(w, "{}<span class=\"loading-content\">Loading content...</span>", extra_content) } fn trait_item(w: &mut Buffer, cx: &Context, m: &clean::Item, t: &clean::Item) { let name = m.name.as_ref().unwrap(); + info!("Documenting {} on {}", name, t.name.as_deref().unwrap_or_default()); let item_type = m.type_(); let id = cx.derive_id(format!("{}.{}", item_type, name)); - write!(w, "<h3 id='{id}' class='method'><code>", id = id,); + write!(w, "<h3 id=\"{id}\" class=\"method\"><code>", id = id,); render_assoc_item(w, m, AssocItemLink::Anchor(Some(&id)), ItemType::Impl); write!(w, "</code>"); render_stability_since(w, m, t); write!(w, "</h3>"); - document(w, cx, m); + document(w, cx, m, Some(t)); } if !types.is_empty() { @@ -2534,7 +2632,7 @@ fn item_trait(w: &mut Buffer, cx: &Context, it: &clean::Item, t: &clean::Trait, w, "associated-types", "Associated Types", - "<div class='methods'>", + "<div class=\"methods\">", ); for t in &types { trait_item(w, cx, *t, it); @@ -2547,7 +2645,7 @@ fn item_trait(w: &mut Buffer, cx: &Context, it: &clean::Item, t: &clean::Trait, w, "associated-const", "Associated Constants", - "<div class='methods'>", + "<div class=\"methods\">", ); for t in &consts { trait_item(w, cx, *t, it); @@ -2561,7 +2659,7 @@ fn item_trait(w: &mut Buffer, cx: &Context, it: &clean::Item, t: &clean::Trait, w, "required-methods", "Required methods", - "<div class='methods'>", + "<div class=\"methods\">", ); for m in &required { trait_item(w, cx, *m, it); @@ -2573,7 +2671,7 @@ fn item_trait(w: &mut Buffer, cx: &Context, it: &clean::Item, t: &clean::Trait, w, "provided-methods", "Provided methods", - "<div class='methods'>", + "<div class=\"methods\">", ); for m in &provided { trait_item(w, cx, *m, it); @@ -2627,9 +2725,10 @@ fn item_trait(w: &mut Buffer, cx: &Context, it: &clean::Item, t: &clean::Trait, w, cx, &implementor, + None, assoc_link, RenderMode::Normal, - implementor.impl_item.stable_since(), + implementor.impl_item.stable_since().as_deref(), false, None, true, @@ -2645,7 +2744,7 @@ fn item_trait(w: &mut Buffer, cx: &Context, it: &clean::Item, t: &clean::Trait, w, "implementors", "Implementors", - "<div class='item-list' id='implementors-list'>", + "<div class=\"item-list\" id=\"implementors-list\">", ); for implementor in concrete { render_implementor(cx, implementor, w, &implementor_dups, &[], cache); @@ -2657,7 +2756,7 @@ fn item_trait(w: &mut Buffer, cx: &Context, it: &clean::Item, t: &clean::Trait, w, "synthetic-implementors", "Auto implementors", - "<div class='item-list' id='synthetic-implementors-list'>", + "<div class=\"item-list\" id=\"synthetic-implementors-list\">", ); for implementor in synthetic { render_implementor( @@ -2678,7 +2777,7 @@ fn item_trait(w: &mut Buffer, cx: &Context, it: &clean::Item, t: &clean::Trait, w, "implementors", "Implementors", - "<div class='item-list' id='implementors-list'>", + "<div class=\"item-list\" id=\"implementors-list\">", ); write_loading_content(w, "</div>"); @@ -2687,7 +2786,7 @@ fn item_trait(w: &mut Buffer, cx: &Context, it: &clean::Item, t: &clean::Trait, w, "synthetic-implementors", "Auto implementors", - "<div class='item-list' id='synthetic-implementors-list'>", + "<div class=\"item-list\" id=\"synthetic-implementors-list\">", ); write_loading_content(w, "</div>"); } @@ -2739,7 +2838,7 @@ fn assoc_const( ) { write!( w, - "{}{}const <a href='{}' class=\"constant\"><b>{}</b></a>: {}", + "{}{}const <a href=\"{}\" class=\"constant\"><b>{}</b></a>: {}", extra, it.visibility.print_with_space(), naive_assoc_href(it, link), @@ -2758,7 +2857,7 @@ fn assoc_type( ) { write!( w, - "{}type <a href='{}' class=\"type\">{}</a>", + "{}type <a href=\"{}\" class=\"type\">{}</a>", extra, naive_assoc_href(it, link), it.name.as_ref().unwrap() @@ -2774,13 +2873,17 @@ fn assoc_type( fn render_stability_since_raw(w: &mut Buffer, ver: Option<&str>, containing_ver: Option<&str>) { if let Some(v) = ver { if containing_ver != ver && !v.is_empty() { - write!(w, "<span class='since' title='Stable since Rust version {0}'>{0}</span>", v) + write!(w, "<span class=\"since\" title=\"Stable since Rust version {0}\">{0}</span>", v) } } } fn render_stability_since(w: &mut Buffer, item: &clean::Item, containing_item: &clean::Item) { - render_stability_since_raw(w, item.stable_since(), containing_item.stable_since()) + render_stability_since_raw( + w, + item.stable_since().as_deref(), + containing_item.stable_since().as_deref(), + ) } fn render_assoc_item( @@ -2836,7 +2939,7 @@ fn render_assoc_item( render_attributes(w, meth, false); write!( w, - "{}{}{}{}{}{}{}fn <a href='{href}' class='fnname'>{name}</a>\ + "{}{}{}{}{}{}{}fn <a href=\"{href}\" class=\"fnname\">{name}</a>\ {generics}{decl}{spotlight}{where_clause}", if parent == ItemType::Trait { " " } else { "" }, meth.visibility.print_with_space(), @@ -2879,13 +2982,13 @@ fn render_assoc_item( fn item_struct(w: &mut Buffer, cx: &Context, it: &clean::Item, s: &clean::Struct, cache: &Cache) { wrap_into_docblock(w, |w| { - write!(w, "<pre class='rust struct'>"); + write!(w, "<pre class=\"rust struct\">"); render_attributes(w, it, true); render_struct(w, it, Some(&s.generics), s.struct_type, &s.fields, "", true); write!(w, "</pre>") }); - document(w, cx, it); + document(w, cx, it, None); let mut fields = s .fields .iter() @@ -2898,8 +3001,8 @@ fn item_struct(w: &mut Buffer, cx: &Context, it: &clean::Item, s: &clean::Struct if fields.peek().is_some() { write!( w, - "<h2 id='fields' class='fields small-section-header'> - Fields{}<a href='#fields' class='anchor'></a></h2>", + "<h2 id=\"fields\" class=\"fields small-section-header\"> + Fields{}<a href=\"#fields\" class=\"anchor\"></a></h2>", document_non_exhaustive_header(it) ); document_non_exhaustive(w, it); @@ -2920,7 +3023,7 @@ fn item_struct(w: &mut Buffer, cx: &Context, it: &clean::Item, s: &clean::Struct name = field.name.as_ref().unwrap(), ty = ty.print() ); - document(w, cx, field); + document(w, cx, field, Some(it)); } } } @@ -2929,13 +3032,13 @@ fn item_struct(w: &mut Buffer, cx: &Context, it: &clean::Item, s: &clean::Struct fn item_union(w: &mut Buffer, cx: &Context, it: &clean::Item, s: &clean::Union, cache: &Cache) { wrap_into_docblock(w, |w| { - write!(w, "<pre class='rust union'>"); + write!(w, "<pre class=\"rust union\">"); render_attributes(w, it, true); render_union(w, it, Some(&s.generics), &s.fields, "", true); write!(w, "</pre>") }); - document(w, cx, it); + document(w, cx, it, None); let mut fields = s .fields .iter() @@ -2947,8 +3050,8 @@ fn item_union(w: &mut Buffer, cx: &Context, it: &clean::Item, s: &clean::Union, if fields.peek().is_some() { write!( w, - "<h2 id='fields' class='fields small-section-header'> - Fields<a href='#fields' class='anchor'></a></h2>" + "<h2 id=\"fields\" class=\"fields small-section-header\"> + Fields<a href=\"#fields\" class=\"anchor\"></a></h2>" ); for (field, ty) in fields { let name = field.name.as_ref().expect("union field name"); @@ -2965,9 +3068,9 @@ fn item_union(w: &mut Buffer, cx: &Context, it: &clean::Item, s: &clean::Union, ty = ty.print() ); if let Some(stability_class) = field.stability_class() { - write!(w, "<span class='stab {stab}'></span>", stab = stability_class); + write!(w, "<span class=\"stab {stab}\"></span>", stab = stability_class); } - document(w, cx, field); + document(w, cx, field, Some(it)); } } render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All, cache) @@ -2975,7 +3078,7 @@ fn item_union(w: &mut Buffer, cx: &Context, it: &clean::Item, s: &clean::Union, fn item_enum(w: &mut Buffer, cx: &Context, it: &clean::Item, e: &clean::Enum, cache: &Cache) { wrap_into_docblock(w, |w| { - write!(w, "<pre class='rust enum'>"); + write!(w, "<pre class=\"rust enum\">"); render_attributes(w, it, true); write!( w, @@ -3022,12 +3125,12 @@ fn item_enum(w: &mut Buffer, cx: &Context, it: &clean::Item, e: &clean::Enum, ca write!(w, "</pre>") }); - document(w, cx, it); + document(w, cx, it, None); if !e.variants.is_empty() { write!( w, - "<h2 id='variants' class='variants small-section-header'> - Variants{}<a href='#variants' class='anchor'></a></h2>\n", + "<h2 id=\"variants\" class=\"variants small-section-header\"> + Variants{}<a href=\"#variants\" class=\"anchor\"></a></h2>\n", document_non_exhaustive_header(it) ); document_non_exhaustive(w, it); @@ -3055,7 +3158,7 @@ fn item_enum(w: &mut Buffer, cx: &Context, it: &clean::Item, e: &clean::Enum, ca } } write!(w, "</code></div>"); - document(w, cx, variant); + document(w, cx, variant, Some(it)); document_non_exhaustive(w, variant); use crate::clean::{Variant, VariantKind}; @@ -3066,7 +3169,7 @@ fn item_enum(w: &mut Buffer, cx: &Context, it: &clean::Item, e: &clean::Enum, ca ItemType::Variant, variant.name.as_ref().unwrap() )); - write!(w, "<div class='autohide sub-variant' id='{id}'>", id = variant_id); + write!(w, "<div class=\"autohide sub-variant\" id=\"{id}\">", id = variant_id); write!( w, "<h3>Fields of <b>{name}</b></h3><div>", @@ -3090,7 +3193,7 @@ fn item_enum(w: &mut Buffer, cx: &Context, it: &clean::Item, e: &clean::Enum, ca f = field.name.as_ref().unwrap(), t = ty.print() ); - document(w, cx, field); + document(w, cx, field, Some(variant)); } } write!(w, "</div></div>"); @@ -3288,6 +3391,10 @@ fn render_assoc_items( what: AssocItemRender<'_>, cache: &Cache, ) { + info!( + "Documenting associated items of {}", + containing_item.name.as_deref().unwrap_or_default() + ); let v = match cache.impls.get(&it) { Some(v) => v, None => return, @@ -3298,8 +3405,8 @@ fn render_assoc_items( AssocItemRender::All => { write!( w, - "<h2 id='implementations' class='small-section-header'>\ - Implementations<a href='#implementations' class='anchor'></a>\ + "<h2 id=\"implementations\" class=\"small-section-header\">\ + Implementations<a href=\"#implementations\" class=\"anchor\"></a>\ </h2>" ); RenderMode::Normal @@ -3307,9 +3414,9 @@ fn render_assoc_items( AssocItemRender::DerefFor { trait_, type_, deref_mut_ } => { write!( w, - "<h2 id='deref-methods' class='small-section-header'>\ + "<h2 id=\"deref-methods\" class=\"small-section-header\">\ Methods from {}<Target = {}>\ - <a href='#deref-methods' class='anchor'></a>\ + <a href=\"#deref-methods\" class=\"anchor\"></a>\ </h2>", trait_.print(), type_.print() @@ -3322,9 +3429,10 @@ fn render_assoc_items( w, cx, i, + Some(containing_item), AssocItemLink::Anchor(None), render_mode, - containing_item.stable_since(), + containing_item.stable_since().as_deref(), true, None, false, @@ -3357,10 +3465,10 @@ fn render_assoc_items( if !impls.is_empty() { write!( w, - "<h2 id='trait-implementations' class='small-section-header'>\ - Trait Implementations<a href='#trait-implementations' class='anchor'></a>\ + "<h2 id=\"trait-implementations\" class=\"small-section-header\">\ + Trait Implementations<a href=\"#trait-implementations\" class=\"anchor\"></a>\ </h2>\ - <div id='trait-implementations-list'>{}</div>", + <div id=\"trait-implementations-list\">{}</div>", impls ); } @@ -3368,11 +3476,11 @@ fn render_assoc_items( if !synthetic.is_empty() { write!( w, - "<h2 id='synthetic-implementations' class='small-section-header'>\ + "<h2 id=\"synthetic-implementations\" class=\"small-section-header\">\ Auto Trait Implementations\ - <a href='#synthetic-implementations' class='anchor'></a>\ + <a href=\"#synthetic-implementations\" class=\"anchor\"></a>\ </h2>\ - <div id='synthetic-implementations-list'>" + <div id=\"synthetic-implementations-list\">" ); render_impls(cx, w, &synthetic, containing_item, cache); write!(w, "</div>"); @@ -3381,11 +3489,11 @@ fn render_assoc_items( if !blanket_impl.is_empty() { write!( w, - "<h2 id='blanket-implementations' class='small-section-header'>\ + "<h2 id=\"blanket-implementations\" class=\"small-section-header\">\ Blanket Implementations\ - <a href='#blanket-implementations' class='anchor'></a>\ + <a href=\"#blanket-implementations\" class=\"anchor\"></a>\ </h2>\ - <div id='blanket-implementations-list'>" + <div id=\"blanket-implementations-list\">" ); render_impls(cx, w, &blanket_impl, containing_item, cache); write!(w, "</div>"); @@ -3500,8 +3608,8 @@ fn spotlight_decl(decl: &clean::FnDecl) -> String { if !out.is_empty() { out.insert_str( 0, - "<span class=\"notable-traits\"><span class=\"notable-traits-tooltip\">ⓘ<div class='notable-traits-tooltiptext'><span class=\"docblock\">" - + "<span class=\"notable-traits\"><span class=\"notable-traits-tooltip\">ⓘ\ + <div class=\"notable-traits-tooltiptext\"><span class=\"docblock\">", ); out.push_str("</code></span></div></span></span>"); } @@ -3513,6 +3621,7 @@ fn render_impl( w: &mut Buffer, cx: &Context, i: &Impl, + parent: Option<&clean::Item>, link: AssocItemLink<'_>, render_mode: RenderMode, outer_version: Option<&str>, @@ -3542,7 +3651,7 @@ fn render_impl( format!(" aliases=\"{}\"", aliases.join(",")) }; if let Some(use_absolute) = use_absolute { - write!(w, "<h3 id='{}' class='impl'{}><code class='in-band'>", id, aliases); + write!(w, "<h3 id=\"{}\" class=\"impl\"{}><code class=\"in-band\">", id, aliases); fmt_impl_for_trait_page(&i.inner_impl(), w, use_absolute); if show_def_docs { for it in &i.inner_impl().items { @@ -3557,24 +3666,31 @@ fn render_impl( } else { write!( w, - "<h3 id='{}' class='impl'{}><code class='in-band'>{}</code>", + "<h3 id=\"{}\" class=\"impl\"{}><code class=\"in-band\">{}</code>", id, aliases, i.inner_impl().print() ); } - write!(w, "<a href='#{}' class='anchor'></a>", id); - let since = i.impl_item.stability.as_ref().map(|s| &s.since[..]); - render_stability_since_raw(w, since, outer_version); + write!(w, "<a href=\"#{}\" class=\"anchor\"></a>", id); + let since = i.impl_item.stability.as_ref().and_then(|s| match s.level { + StabilityLevel::Stable { since } => Some(since.as_str()), + StabilityLevel::Unstable { .. } => None, + }); + render_stability_since_raw(w, since.as_deref(), outer_version); if let Some(l) = cx.src_href(&i.impl_item, cache) { - write!(w, "<a class='srclink' href='{}' title='{}'>[src]</a>", l, "goto source code"); + write!( + w, + "<a class=\"srclink\" href=\"{}\" title=\"{}\">[src]</a>", + l, "goto source code" + ); } write!(w, "</h3>"); if let Some(ref dox) = cx.shared.maybe_collapsed_doc_value(&i.impl_item) { let mut ids = cx.id_map.borrow_mut(); write!( w, - "<div class='docblock'>{}</div>", + "<div class=\"docblock\">{}</div>", Markdown( &*dox, &i.impl_item.links(), @@ -3592,6 +3708,7 @@ fn render_impl( w: &mut Buffer, cx: &Context, item: &clean::Item, + parent: Option<&clean::Item>, link: AssocItemLink<'_>, render_mode: RenderMode, is_default_item: bool, @@ -3622,15 +3739,15 @@ fn render_impl( // Only render when the method is not static or we allow static methods if render_method_item { let id = cx.derive_id(format!("{}.{}", item_type, name)); - write!(w, "<h4 id='{}' class=\"{}{}\">", id, item_type, extra_class); + write!(w, "<h4 id=\"{}\" class=\"{}{}\">", id, item_type, extra_class); write!(w, "<code>"); render_assoc_item(w, item, link.anchor(&id), ItemType::Impl); write!(w, "</code>"); - render_stability_since_raw(w, item.stable_since(), outer_version); + render_stability_since_raw(w, item.stable_since().as_deref(), outer_version); if let Some(l) = cx.src_href(item, cache) { write!( w, - "<a class='srclink' href='{}' title='{}'>[src]</a>", + "<a class=\"srclink\" href=\"{}\" title=\"{}\">[src]</a>", l, "goto source code" ); } @@ -3639,20 +3756,20 @@ fn render_impl( } clean::TypedefItem(ref tydef, _) => { let id = cx.derive_id(format!("{}.{}", ItemType::AssocType, name)); - write!(w, "<h4 id='{}' class=\"{}{}\"><code>", id, item_type, extra_class); + write!(w, "<h4 id=\"{}\" class=\"{}{}\"><code>", id, item_type, extra_class); assoc_type(w, item, &Vec::new(), Some(&tydef.type_), link.anchor(&id), ""); write!(w, "</code></h4>"); } clean::AssocConstItem(ref ty, ref default) => { let id = cx.derive_id(format!("{}.{}", item_type, name)); - write!(w, "<h4 id='{}' class=\"{}{}\"><code>", id, item_type, extra_class); + write!(w, "<h4 id=\"{}\" class=\"{}{}\"><code>", id, item_type, extra_class); assoc_const(w, item, ty, default.as_ref(), link.anchor(&id), ""); write!(w, "</code>"); - render_stability_since_raw(w, item.stable_since(), outer_version); + render_stability_since_raw(w, item.stable_since().as_deref(), outer_version); if let Some(l) = cx.src_href(item, cache) { write!( w, - "<a class='srclink' href='{}' title='{}'>[src]</a>", + "<a class=\"srclink\" href=\"{}\" title=\"{}\">[src]</a>", l, "goto source code" ); } @@ -3660,7 +3777,7 @@ fn render_impl( } clean::AssocTypeItem(ref bounds, ref default) => { let id = cx.derive_id(format!("{}.{}", item_type, name)); - write!(w, "<h4 id='{}' class=\"{}{}\"><code>", id, item_type, extra_class); + write!(w, "<h4 id=\"{}\" class=\"{}{}\"><code>", id, item_type, extra_class); assoc_type(w, item, bounds, default.as_ref(), link.anchor(&id), ""); write!(w, "</code></h4>"); } @@ -3676,7 +3793,7 @@ fn render_impl( if let Some(it) = t.items.iter().find(|i| i.name == item.name) { // We need the stability of the item from the trait // because impls can't have a stability. - document_stability(w, cx, it, is_hidden); + document_stability(w, cx, it, is_hidden, parent); if item.doc_value().is_some() { document_full(w, item, cx, "", is_hidden); } else if show_def_docs { @@ -3686,13 +3803,13 @@ fn render_impl( } } } else { - document_stability(w, cx, item, is_hidden); + document_stability(w, cx, item, is_hidden, parent); if show_def_docs { document_full(w, item, cx, "", is_hidden); } } } else { - document_stability(w, cx, item, is_hidden); + document_stability(w, cx, item, is_hidden, parent); if show_def_docs { document_short(w, item, link, "", is_hidden); } @@ -3703,12 +3820,13 @@ fn render_impl( let traits = &cache.traits; let trait_ = i.trait_did().map(|did| &traits[&did]); - write!(w, "<div class='impl-items'>"); + write!(w, "<div class=\"impl-items\">"); for trait_item in &i.inner_impl().items { doc_impl_item( w, cx, trait_item, + parent, link, render_mode, false, @@ -3724,6 +3842,7 @@ fn render_impl( cx: &Context, t: &clean::Trait, i: &clean::Impl, + parent: Option<&clean::Item>, render_mode: RenderMode, outer_version: Option<&str>, show_def_docs: bool, @@ -3741,6 +3860,7 @@ fn render_impl( w, cx, trait_item, + parent, assoc_link, render_mode, true, @@ -3763,6 +3883,7 @@ fn render_impl( cx, t, &i.inner_impl(), + parent, render_mode, outer_version, show_def_docs, @@ -3780,7 +3901,7 @@ fn item_opaque_ty( t: &clean::OpaqueTy, cache: &Cache, ) { - write!(w, "<pre class='rust opaque'>"); + write!(w, "<pre class=\"rust opaque\">"); render_attributes(w, it, false); write!( w, @@ -3791,7 +3912,7 @@ fn item_opaque_ty( bounds = bounds(&t.bounds, false) ); - document(w, cx, it); + document(w, cx, it, None); // Render any items associated directly to this alias, as otherwise they // won't be visible anywhere in the docs. It would be nice to also show @@ -3807,7 +3928,7 @@ fn item_trait_alias( t: &clean::TraitAlias, cache: &Cache, ) { - write!(w, "<pre class='rust trait-alias'>"); + write!(w, "<pre class=\"rust trait-alias\">"); render_attributes(w, it, false); write!( w, @@ -3818,7 +3939,7 @@ fn item_trait_alias( bounds(&t.bounds, true) ); - document(w, cx, it); + document(w, cx, it, None); // Render any items associated directly to this alias, as otherwise they // won't be visible anywhere in the docs. It would be nice to also show @@ -3828,7 +3949,7 @@ fn item_trait_alias( } fn item_typedef(w: &mut Buffer, cx: &Context, it: &clean::Item, t: &clean::Typedef, cache: &Cache) { - write!(w, "<pre class='rust typedef'>"); + write!(w, "<pre class=\"rust typedef\">"); render_attributes(w, it, false); write!( w, @@ -3839,7 +3960,7 @@ fn item_typedef(w: &mut Buffer, cx: &Context, it: &clean::Item, t: &clean::Typed type_ = t.type_.print() ); - document(w, cx, it); + document(w, cx, it, None); // Render any items associated directly to this alias, as otherwise they // won't be visible anywhere in the docs. It would be nice to also show @@ -3849,7 +3970,7 @@ fn item_typedef(w: &mut Buffer, cx: &Context, it: &clean::Item, t: &clean::Typed } fn item_foreign_type(w: &mut Buffer, cx: &Context, it: &clean::Item, cache: &Cache) { - writeln!(w, "<pre class='rust foreigntype'>extern {{"); + writeln!(w, "<pre class=\"rust foreigntype\">extern {{"); render_attributes(w, it, false); write!( w, @@ -3858,7 +3979,7 @@ fn item_foreign_type(w: &mut Buffer, cx: &Context, it: &clean::Item, cache: &Cac it.name.as_ref().unwrap(), ); - document(w, cx, it); + document(w, cx, it, None); render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All, cache) } @@ -3876,7 +3997,7 @@ fn print_sidebar(cx: &Context, it: &clean::Item, buffer: &mut Buffer, cache: &Ca { write!( buffer, - "<p class='location'>{}{}</p>", + "<p class=\"location\">{}{}</p>", match it.inner { clean::StructItem(..) => "Struct ", clean::TraitItem(..) => "Trait ", @@ -3901,7 +4022,7 @@ fn print_sidebar(cx: &Context, it: &clean::Item, buffer: &mut Buffer, cache: &Ca if let Some(ref version) = cache.crate_version { write!( buffer, - "<div class='block version'>\ + "<div class=\"block version\">\ <p>Version {}</p>\ </div>", Escape(version) @@ -3913,7 +4034,7 @@ fn print_sidebar(cx: &Context, it: &clean::Item, buffer: &mut Buffer, cache: &Ca if it.is_crate() { write!( buffer, - "<a id='all-types' href='all.html'><p>See all {}'s items</p></a>", + "<a id=\"all-types\" href=\"all.html\"><p>See all {}'s items</p></a>", it.name.as_ref().expect("crates always have a name") ); } @@ -3937,14 +4058,14 @@ fn print_sidebar(cx: &Context, it: &clean::Item, buffer: &mut Buffer, cache: &Ca // as much HTML as possible in order to allow non-JS-enabled browsers // to navigate the documentation (though slightly inefficiently). - write!(buffer, "<p class='location'>"); + write!(buffer, "<p class=\"location\">"); for (i, name) in cx.current.iter().take(parentlen).enumerate() { if i > 0 { write!(buffer, "::<wbr>"); } write!( buffer, - "<a href='{}index.html'>{}</a>", + "<a href=\"{}index.html\">{}</a>", &cx.root_path()[..(cx.current.len() - i - 1) * 3], *name ); @@ -3956,9 +4077,9 @@ fn print_sidebar(cx: &Context, it: &clean::Item, buffer: &mut Buffer, cache: &Ca write!( buffer, "<script>window.sidebarCurrent = {{\ - name: '{name}', \ - ty: '{ty}', \ - relpath: '{path}'\ + name: \"{name}\", \ + ty: \"{ty}\", \ + relpath: \"{path}\"\ }};</script>", name = it.name.as_ref().map(|x| &x[..]).unwrap_or(""), ty = it.type_(), @@ -4503,24 +4624,24 @@ fn item_macro(w: &mut Buffer, cx: &Context, it: &clean::Item, t: &clean::Macro) None, )) }); - document(w, cx, it) + document(w, cx, it, None) } fn item_proc_macro(w: &mut Buffer, cx: &Context, it: &clean::Item, m: &clean::ProcMacro) { let name = it.name.as_ref().expect("proc-macros always have names"); match m.kind { MacroKind::Bang => { - write!(w, "<pre class='rust macro'>"); + write!(w, "<pre class=\"rust macro\">"); write!(w, "{}!() {{ /* proc-macro */ }}", name); write!(w, "</pre>"); } MacroKind::Attr => { - write!(w, "<pre class='rust attr'>"); + write!(w, "<pre class=\"rust attr\">"); write!(w, "#[{}]", name); write!(w, "</pre>"); } MacroKind::Derive => { - write!(w, "<pre class='rust derive'>"); + write!(w, "<pre class=\"rust derive\">"); write!(w, "#[derive({})]", name); if !m.helpers.is_empty() { writeln!(w, "\n{{"); @@ -4533,16 +4654,16 @@ fn item_proc_macro(w: &mut Buffer, cx: &Context, it: &clean::Item, m: &clean::Pr write!(w, "</pre>"); } } - document(w, cx, it) + document(w, cx, it, None) } fn item_primitive(w: &mut Buffer, cx: &Context, it: &clean::Item, cache: &Cache) { - document(w, cx, it); + document(w, cx, it, None); render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All, cache) } fn item_keyword(w: &mut Buffer, cx: &Context, it: &clean::Item) { - document(w, cx, it) + document(w, cx, it, None) } crate const BASIC_KEYWORDS: &str = "rust, rustlang, rust-lang"; diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index 1b3eb2011af..e382e5aa234 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -2716,10 +2716,6 @@ function defocusSearchBar() { }; } - window.onresize = function() { - hideSidebar(); - }; - if (main) { onEachLazy(main.getElementsByClassName("loading-content"), function(e) { e.remove(); @@ -2796,6 +2792,10 @@ function defocusSearchBar() { addClass(popup, "hidden"); popup.id = "help"; + var book_info = document.createElement("span"); + book_info.innerHTML = "You can find more information in \ + <a href=\"https://doc.rust-lang.org/rustdoc/\">the rustdoc book</a>."; + var container = document.createElement("div"); var shortcuts = [ ["?", "Show this help dialog"], @@ -2829,6 +2829,7 @@ function defocusSearchBar() { addClass(div_infos, "infos"); div_infos.innerHTML = "<h2>Search Tricks</h2>" + infos; + container.appendChild(book_info); container.appendChild(div_shortcuts); container.appendChild(div_infos); diff --git a/src/librustdoc/html/static/rustdoc.css b/src/librustdoc/html/static/rustdoc.css index 391526f0a30..d7e9496205a 100644 --- a/src/librustdoc/html/static/rustdoc.css +++ b/src/librustdoc/html/static/rustdoc.css @@ -390,17 +390,13 @@ nav.sub { cursor: pointer; } +.docblock-short { + overflow-wrap: anywhere; +} .docblock-short p { display: inline; } -.docblock-short.nowrap { - display: block; - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; -} - .docblock-short p { overflow: hidden; text-overflow: ellipsis; @@ -800,14 +796,22 @@ body.blur > :not(#help) { clear: left; display: block; } +#help > div > span { + text-align: center; + display: block; + margin: 10px 0; + font-size: 18px; + border-bottom: 1px solid #ccc; + padding-bottom: 4px; + margin-bottom: 6px; +} #help dd { margin: 5px 35px; } #help .infos { padding-left: 0; } #help h1, #help h2 { margin-top: 0; } #help > div div { width: 50%; float: left; - padding: 20px; - padding-left: 17px; + padding: 0 20px 20px 17px;; } .stab { @@ -1544,6 +1548,14 @@ h4 > .notable-traits { left: 0; top: 100%; } + + /* We don't display the help button on mobile devices. */ + .help-button { + display: none; + } + .search-container > div { + width: calc(100% - 32px); + } } @media print { @@ -1553,11 +1565,7 @@ h4 > .notable-traits { } @media (max-width: 416px) { - #titles { - height: 73px; - } - - #titles > div { + #titles, #titles > div { height: 73px; } } diff --git a/src/librustdoc/html/static/settings.css b/src/librustdoc/html/static/settings.css index d03cf7fcc45..4bacd7b245b 100644 --- a/src/librustdoc/html/static/settings.css +++ b/src/librustdoc/html/static/settings.css @@ -4,7 +4,6 @@ } .setting-line > div { - max-width: calc(100% - 74px); display: inline-block; vertical-align: top; font-size: 17px; @@ -30,6 +29,38 @@ display: none; } +.select-wrapper { + float: right; + position: relative; + height: 27px; + min-width: 25%; +} + +.select-wrapper select { + appearance: none; + -moz-appearance: none; + -webkit-appearance: none; + background: none; + border: 2px solid #ccc; + padding-right: 28px; + width: 100%; +} + +.select-wrapper img { + pointer-events: none; + position: absolute; + right: 0; + bottom: 0; + background: #ccc; + height: 100%; + width: 28px; + padding: 0px 4px; +} + +.select-wrapper select option { + color: initial; +} + .slider { position: absolute; cursor: pointer; diff --git a/src/librustdoc/html/static/settings.js b/src/librustdoc/html/static/settings.js index 427a74c0c87..00a01ac30bc 100644 --- a/src/librustdoc/html/static/settings.js +++ b/src/librustdoc/html/static/settings.js @@ -1,30 +1,56 @@ // Local js definitions: -/* global getCurrentValue, updateLocalStorage */ +/* global getCurrentValue, updateLocalStorage, updateSystemTheme */ (function () { - function changeSetting(settingName, isEnabled) { - updateLocalStorage('rustdoc-' + settingName, isEnabled); + function changeSetting(settingName, value) { + updateLocalStorage("rustdoc-" + settingName, value); + + switch (settingName) { + case "preferred-dark-theme": + case "preferred-light-theme": + case "use-system-theme": + updateSystemTheme(); + break; + } } function getSettingValue(settingName) { - return getCurrentValue('rustdoc-' + settingName); + return getCurrentValue("rustdoc-" + settingName); } function setEvents() { - var elems = document.getElementsByClassName("slider"); - if (!elems || elems.length === 0) { - return; + var elems = { + toggles: document.getElementsByClassName("slider"), + selects: document.getElementsByClassName("select-wrapper") + }; + var i; + + if (elems.toggles && elems.toggles.length > 0) { + for (i = 0; i < elems.toggles.length; ++i) { + var toggle = elems.toggles[i].previousElementSibling; + var settingId = toggle.id; + var settingValue = getSettingValue(settingId); + if (settingValue !== null) { + toggle.checked = settingValue === "true"; + } + toggle.onchange = function() { + changeSetting(this.id, this.checked); + }; + } } - for (var i = 0; i < elems.length; ++i) { - var toggle = elems[i].previousElementSibling; - var settingId = toggle.id; - var settingValue = getSettingValue(settingId); - if (settingValue !== null) { - toggle.checked = settingValue === "true"; + + if (elems.selects && elems.selects.length > 0) { + for (i = 0; i < elems.selects.length; ++i) { + var select = elems.selects[i].getElementsByTagName("select")[0]; + var settingId = select.id; + var settingValue = getSettingValue(settingId); + if (settingValue !== null) { + select.value = settingValue; + } + select.onchange = function() { + changeSetting(this.id, this.value); + }; } - toggle.onchange = function() { - changeSetting(this.id, this.checked); - }; } } diff --git a/src/librustdoc/html/static/storage.js b/src/librustdoc/html/static/storage.js index 0a2fae274fa..a027d6845ea 100644 --- a/src/librustdoc/html/static/storage.js +++ b/src/librustdoc/html/static/storage.js @@ -1,8 +1,10 @@ // From rust: /* global resourcesSuffix */ +var darkThemes = ["dark", "ayu"]; var currentTheme = document.getElementById("themeStyle"); var mainTheme = document.getElementById("mainThemeStyle"); +var localStoredTheme = getCurrentValue("rustdoc-theme"); var savedHref = []; @@ -110,19 +112,90 @@ function switchTheme(styleElem, mainStyleElem, newTheme, saveTheme) { }); if (found === true) { styleElem.href = newHref; - // If this new value comes from a system setting or from the previously saved theme, no - // need to save it. + // If this new value comes from a system setting or from the previously + // saved theme, no need to save it. if (saveTheme === true) { updateLocalStorage("rustdoc-theme", newTheme); } } } -function getSystemValue() { - var property = getComputedStyle(document.documentElement).getPropertyValue('content'); - return property.replace(/[\"\']/g, ""); +function useSystemTheme(value) { + if (value === undefined) { + value = true; + } + + updateLocalStorage("rustdoc-use-system-theme", value); + + // update the toggle if we're on the settings page + var toggle = document.getElementById("use-system-theme"); + if (toggle && toggle instanceof HTMLInputElement) { + toggle.checked = value; + } } -switchTheme(currentTheme, mainTheme, - getCurrentValue("rustdoc-theme") || getSystemValue() || "light", - false); +var updateSystemTheme = (function() { + if (!window.matchMedia) { + // fallback to the CSS computed value + return function() { + let cssTheme = getComputedStyle(document.documentElement) + .getPropertyValue('content'); + + switchTheme( + currentTheme, + mainTheme, + JSON.parse(cssTheme) || light, + true + ); + }; + } + + // only listen to (prefers-color-scheme: dark) because light is the default + var mql = window.matchMedia("(prefers-color-scheme: dark)"); + + function handlePreferenceChange(mql) { + // maybe the user has disabled the setting in the meantime! + if (getCurrentValue("rustdoc-use-system-theme") !== "false") { + var lightTheme = getCurrentValue("rustdoc-preferred-light-theme") || "light"; + var darkTheme = getCurrentValue("rustdoc-preferred-dark-theme") || "dark"; + + if (mql.matches) { + // prefers a dark theme + switchTheme(currentTheme, mainTheme, darkTheme, true); + } else { + // prefers a light theme, or has no preference + switchTheme(currentTheme, mainTheme, lightTheme, true); + } + + // note: we save the theme so that it doesn't suddenly change when + // the user disables "use-system-theme" and reloads the page or + // navigates to another page + } + } + + mql.addListener(handlePreferenceChange); + + return function() { + handlePreferenceChange(mql); + }; +})(); + +if (getCurrentValue("rustdoc-use-system-theme") !== "false" && window.matchMedia) { + // update the preferred dark theme if the user is already using a dark theme + // See https://github.com/rust-lang/rust/pull/77809#issuecomment-707875732 + if (getCurrentValue("rustdoc-use-system-theme") === null + && getCurrentValue("rustdoc-preferred-dark-theme") === null + && darkThemes.indexOf(localStoredTheme) >= 0) { + updateLocalStorage("rustdoc-preferred-dark-theme", localStoredTheme); + } + + // call the function to initialize the theme at least once! + updateSystemTheme(); +} else { + switchTheme( + currentTheme, + mainTheme, + getCurrentValue("rustdoc-theme") || "light", + false + ); +} diff --git a/src/librustdoc/html/static/themes/ayu.css b/src/librustdoc/html/static/themes/ayu.css index 3b15b21889d..d1cddf0d656 100644 --- a/src/librustdoc/html/static/themes/ayu.css +++ b/src/librustdoc/html/static/themes/ayu.css @@ -219,7 +219,8 @@ a { } .docblock:not(.type-decl) a:not(.srclink):not(.test-arrow), -.docblock-short a:not(.srclink):not(.test-arrow), .stability a { +.docblock-short a:not(.srclink):not(.test-arrow), .stability a, +#help a { color: #39AFD7; } @@ -275,6 +276,10 @@ a { border-radius: 4px; } +#help > div > span { + border-bottom-color: #5c6773; +} + .since { color: grey; } diff --git a/src/librustdoc/html/static/themes/dark.css b/src/librustdoc/html/static/themes/dark.css index f5a85337768..3545943b3fd 100644 --- a/src/librustdoc/html/static/themes/dark.css +++ b/src/librustdoc/html/static/themes/dark.css @@ -177,7 +177,8 @@ a { } .docblock:not(.type-decl) a:not(.srclink):not(.test-arrow), -.docblock-short a:not(.srclink):not(.test-arrow), .stability a { +.docblock-short a:not(.srclink):not(.test-arrow), .stability a, +#help a { color: #D2991D; } @@ -231,6 +232,10 @@ a.test-arrow { border-color: #bfbfbf; } +#help > div > span { + border-bottom-color: #bfbfbf; +} + #help dt { border-color: #bfbfbf; background: rgba(0,0,0,0); diff --git a/src/librustdoc/html/static/themes/light.css b/src/librustdoc/html/static/themes/light.css index 9dea875b877..4ce4b63e2c6 100644 --- a/src/librustdoc/html/static/themes/light.css +++ b/src/librustdoc/html/static/themes/light.css @@ -175,7 +175,8 @@ a { } .docblock:not(.type-decl) a:not(.srclink):not(.test-arrow), -.docblock-short a:not(.srclink):not(.test-arrow), .stability a { +.docblock-short a:not(.srclink):not(.test-arrow), .stability a, +#help a { color: #3873AD; } @@ -229,6 +230,10 @@ a.test-arrow { border-color: #bfbfbf; } +#help > div > span { + border-bottom-color: #bfbfbf; +} + .since { color: grey; } diff --git a/src/librustdoc/passes/calculate_doc_coverage.rs b/src/librustdoc/passes/calculate_doc_coverage.rs index 4bca3996eb4..ced26fcf5b0 100644 --- a/src/librustdoc/passes/calculate_doc_coverage.rs +++ b/src/librustdoc/passes/calculate_doc_coverage.rs @@ -1,10 +1,12 @@ use crate::clean; -use crate::config::OutputFormat; use crate::core::DocContext; use crate::fold::{self, DocFolder}; use crate::html::markdown::{find_testable_code, ErrorCodes}; use crate::passes::doc_test_lints::{should_have_doc_example, Tests}; use crate::passes::Pass; +use rustc_lint::builtin::MISSING_DOCS; +use rustc_middle::lint::LintSource; +use rustc_session::lint; use rustc_span::symbol::sym; use rustc_span::FileName; use serde::Serialize; @@ -19,10 +21,10 @@ pub const CALCULATE_DOC_COVERAGE: Pass = Pass { }; fn calculate_doc_coverage(krate: clean::Crate, ctx: &DocContext<'_>) -> clean::Crate { - let mut calc = CoverageCalculator::new(); + let mut calc = CoverageCalculator::new(ctx); let krate = calc.fold_crate(krate); - calc.print_results(ctx.renderinfo.borrow().output_format); + calc.print_results(); krate } @@ -41,8 +43,11 @@ impl ItemCount { has_docs: bool, has_doc_example: bool, should_have_doc_examples: bool, + should_have_docs: bool, ) { - self.total += 1; + if has_docs || should_have_docs { + self.total += 1; + } if has_docs { self.with_docs += 1; @@ -94,8 +99,9 @@ impl ops::AddAssign for ItemCount { } } -struct CoverageCalculator { +struct CoverageCalculator<'a, 'b> { items: BTreeMap<FileName, ItemCount>, + ctx: &'a DocContext<'b>, } fn limit_filename_len(filename: String) -> String { @@ -108,9 +114,9 @@ fn limit_filename_len(filename: String) -> String { } } -impl CoverageCalculator { - fn new() -> CoverageCalculator { - CoverageCalculator { items: Default::default() } +impl<'a, 'b> CoverageCalculator<'a, 'b> { + fn new(ctx: &'a DocContext<'b>) -> CoverageCalculator<'a, 'b> { + CoverageCalculator { items: Default::default(), ctx } } fn to_json(&self) -> String { @@ -124,7 +130,8 @@ impl CoverageCalculator { .expect("failed to convert JSON data to string") } - fn print_results(&self, output_format: Option<OutputFormat>) { + fn print_results(&self) { + let output_format = self.ctx.renderinfo.borrow().output_format; if output_format.map(|o| o.is_json()).unwrap_or_else(|| false) { println!("{}", self.to_json()); return; @@ -178,7 +185,7 @@ impl CoverageCalculator { } } -impl fold::DocFolder for CoverageCalculator { +impl<'a, 'b> fold::DocFolder for CoverageCalculator<'a, 'b> { fn fold_item(&mut self, i: clean::Item) -> Option<clean::Item> { match i.inner { _ if !i.def_id.is_local() => { @@ -245,11 +252,18 @@ impl fold::DocFolder for CoverageCalculator { ); let has_doc_example = tests.found_tests != 0; + let hir_id = self.ctx.tcx.hir().local_def_id_to_hir_id(i.def_id.expect_local()); + let (level, source) = self.ctx.tcx.lint_level_at_node(MISSING_DOCS, hir_id); + // `missing_docs` is allow-by-default, so don't treat this as ignoring the item + // unless the user had an explicit `allow` + let should_have_docs = + level != lint::Level::Allow || matches!(source, LintSource::Default); debug!("counting {:?} {:?} in {}", i.type_(), i.name, i.source.filename); self.items.entry(i.source.filename.clone()).or_default().count_item( has_docs, has_doc_example, - should_have_doc_example(&i.inner), + should_have_doc_example(self.ctx, &i), + should_have_docs, ); } } diff --git a/src/librustdoc/passes/collapse_docs.rs b/src/librustdoc/passes/collapse_docs.rs index be7250f833f..c2f7f97a673 100644 --- a/src/librustdoc/passes/collapse_docs.rs +++ b/src/librustdoc/passes/collapse_docs.rs @@ -36,7 +36,10 @@ fn collapse(doc_strings: &mut Vec<DocFragment>) { let curr_kind = &curr_frag.kind; let new_kind = &frag.kind; - if matches!(*curr_kind, DocFragmentKind::Include { .. }) || curr_kind != new_kind { + if matches!(*curr_kind, DocFragmentKind::Include { .. }) + || curr_kind != new_kind + || curr_frag.parent_module != frag.parent_module + { if *curr_kind == DocFragmentKind::SugaredDoc || *curr_kind == DocFragmentKind::RawDoc { diff --git a/src/librustdoc/passes/doc_test_lints.rs b/src/librustdoc/passes/doc_test_lints.rs index 78af9f9b856..686ec51fb06 100644 --- a/src/librustdoc/passes/doc_test_lints.rs +++ b/src/librustdoc/passes/doc_test_lints.rs @@ -9,6 +9,7 @@ use crate::clean::*; use crate::core::DocContext; use crate::fold::DocFolder; use crate::html::markdown::{find_testable_code, ErrorCodes, Ignore, LangString}; +use rustc_middle::lint::LintSource; use rustc_session::lint; pub const CHECK_PRIVATE_ITEMS_DOC_TESTS: Pass = Pass { @@ -56,8 +57,8 @@ impl crate::doctest::Tester for Tests { } } -pub fn should_have_doc_example(item_kind: &clean::ItemEnum) -> bool { - !matches!(item_kind, +pub fn should_have_doc_example(cx: &DocContext<'_>, item: &clean::Item) -> bool { + if matches!(item.inner, clean::StructFieldItem(_) | clean::VariantItem(_) | clean::AssocConstItem(_, _) @@ -69,7 +70,13 @@ pub fn should_have_doc_example(item_kind: &clean::ItemEnum) -> bool { | clean::ImportItem(_) | clean::PrimitiveItem(_) | clean::KeywordItem(_) - ) + ) { + return false; + } + let hir_id = cx.tcx.hir().local_def_id_to_hir_id(item.def_id.expect_local()); + let (level, source) = + cx.tcx.lint_level_at_node(lint::builtin::MISSING_DOC_CODE_EXAMPLES, hir_id); + level != lint::Level::Allow || matches!(source, LintSource::Default) } pub fn look_for_tests<'tcx>(cx: &DocContext<'tcx>, dox: &str, item: &Item) { @@ -88,7 +95,7 @@ pub fn look_for_tests<'tcx>(cx: &DocContext<'tcx>, dox: &str, item: &Item) { if tests.found_tests == 0 && rustc_feature::UnstableFeatures::from_environment().is_nightly_build() { - if should_have_doc_example(&item.inner) { + if should_have_doc_example(cx, &item) { debug!("reporting error for {:?} (hir_id={:?})", item, hir_id); let sp = span_of_attrs(&item.attrs).unwrap_or(item.source.span()); cx.tcx.struct_span_lint_hir( diff --git a/src/librustdoc/passes/html_tags.rs b/src/librustdoc/passes/html_tags.rs index ae4eac89b45..1d9be619ec9 100644 --- a/src/librustdoc/passes/html_tags.rs +++ b/src/librustdoc/passes/html_tags.rs @@ -7,6 +7,8 @@ use core::ops::Range; use pulldown_cmark::{Event, Parser}; use rustc_feature::UnstableFeatures; use rustc_session::lint; +use std::iter::Peekable; +use std::str::CharIndices; pub const CHECK_INVALID_HTML_TAGS: Pass = Pass { name: "check-invalid-html-tags", @@ -75,70 +77,97 @@ fn drop_tag( } } -fn extract_tag( +fn extract_html_tag( tags: &mut Vec<(String, Range<usize>)>, text: &str, - range: Range<usize>, + range: &Range<usize>, + start_pos: usize, + iter: &mut Peekable<CharIndices<'_>>, f: &impl Fn(&str, &Range<usize>), ) { - let mut iter = text.char_indices().peekable(); + let mut tag_name = String::new(); + let mut is_closing = false; + let mut prev_pos = start_pos; - while let Some((start_pos, c)) = iter.next() { - if c == '<' { - let mut tag_name = String::new(); - let mut is_closing = false; - let mut prev_pos = start_pos; - loop { - let (pos, c) = match iter.peek() { - Some((pos, c)) => (*pos, *c), - // In case we reached the of the doc comment, we want to check that it's an - // unclosed HTML tag. For example "/// <h3". - None => (prev_pos, '\0'), - }; - prev_pos = pos; - // Checking if this is a closing tag (like `</a>` for `<a>`). - if c == '/' && tag_name.is_empty() { - is_closing = true; - } else if c.is_ascii_alphanumeric() { - tag_name.push(c); - } else { - if !tag_name.is_empty() { - let mut r = - Range { start: range.start + start_pos, end: range.start + pos }; - if c == '>' { - // In case we have a tag without attribute, we can consider the span to - // refer to it fully. - r.end += 1; + loop { + let (pos, c) = match iter.peek() { + Some((pos, c)) => (*pos, *c), + // In case we reached the of the doc comment, we want to check that it's an + // unclosed HTML tag. For example "/// <h3". + None => (prev_pos, '\0'), + }; + prev_pos = pos; + // Checking if this is a closing tag (like `</a>` for `<a>`). + if c == '/' && tag_name.is_empty() { + is_closing = true; + } else if c.is_ascii_alphanumeric() { + tag_name.push(c); + } else { + if !tag_name.is_empty() { + let mut r = Range { start: range.start + start_pos, end: range.start + pos }; + if c == '>' { + // In case we have a tag without attribute, we can consider the span to + // refer to it fully. + r.end += 1; + } + if is_closing { + // In case we have "</div >" or even "</div >". + if c != '>' { + if !c.is_whitespace() { + // It seems like it's not a valid HTML tag. + break; } - if is_closing { - // In case we have "</div >" or even "</div >". - if c != '>' { - if !c.is_whitespace() { - // It seems like it's not a valid HTML tag. - break; - } - let mut found = false; - for (new_pos, c) in text[pos..].char_indices() { - if !c.is_whitespace() { - if c == '>' { - r.end = range.start + new_pos + 1; - found = true; - } - break; - } - } - if !found { - break; + let mut found = false; + for (new_pos, c) in text[pos..].char_indices() { + if !c.is_whitespace() { + if c == '>' { + r.end = range.start + new_pos + 1; + found = true; } + break; } - drop_tag(tags, tag_name, r, f); - } else { - tags.push((tag_name, r)); + } + if !found { + break; } } - break; + drop_tag(tags, tag_name, r, f); + } else { + tags.push((tag_name, r)); } + } + break; + } + iter.next(); + } +} + +fn extract_tags( + tags: &mut Vec<(String, Range<usize>)>, + text: &str, + range: Range<usize>, + is_in_comment: &mut Option<Range<usize>>, + f: &impl Fn(&str, &Range<usize>), +) { + let mut iter = text.char_indices().peekable(); + + while let Some((start_pos, c)) = iter.next() { + if is_in_comment.is_some() { + if text[start_pos..].starts_with("-->") { + *is_in_comment = None; + } + } else if c == '<' { + if text[start_pos..].starts_with("<!--") { + // We skip the "!--" part. (Once `advance_by` is stable, might be nice to use it!) + iter.next(); iter.next(); + iter.next(); + *is_in_comment = Some(Range { + start: range.start + start_pos, + end: range.start + start_pos + 3, + }); + } else { + extract_html_tag(tags, text, &range, start_pos, &mut iter, f); } } } @@ -167,12 +196,15 @@ impl<'a, 'tcx> DocFolder for InvalidHtmlTagsLinter<'a, 'tcx> { }; let mut tags = Vec::new(); + let mut is_in_comment = None; let p = Parser::new_ext(&dox, opts()).into_offset_iter(); for (event, range) in p { match event { - Event::Html(text) => extract_tag(&mut tags, &text, range, &report_diag), + Event::Html(text) | Event::Text(text) => { + extract_tags(&mut tags, &text, range, &mut is_in_comment, &report_diag) + } _ => {} } } @@ -183,6 +215,10 @@ impl<'a, 'tcx> DocFolder for InvalidHtmlTagsLinter<'a, 'tcx> { }) { report_diag(&format!("unclosed HTML tag `{}`", tag), range); } + + if let Some(range) = is_in_comment { + report_diag("Unclosed HTML comment", &range); + } } self.fold_item_recur(item) diff --git a/src/librustdoc/passes/mod.rs b/src/librustdoc/passes/mod.rs index 39c61f7edbe..2591650e3f9 100644 --- a/src/librustdoc/passes/mod.rs +++ b/src/librustdoc/passes/mod.rs @@ -1,16 +1,15 @@ //! Contains information about "passes", used to modify crate information during the documentation //! process. -use rustc_hir::def_id::{DefId, DefIdSet}; -use rustc_middle::middle::privacy::AccessLevels; use rustc_span::{InnerSpan, Span, DUMMY_SP}; -use std::mem; use std::ops::Range; use self::Condition::*; -use crate::clean::{self, DocFragmentKind, GetDefId, Item}; +use crate::clean::{self, DocFragmentKind}; use crate::core::DocContext; -use crate::fold::{DocFolder, StripItem}; + +mod stripper; +pub use stripper::*; mod collapse_docs; pub use self::collapse_docs::COLLAPSE_DOCS; @@ -149,171 +148,6 @@ pub fn find_pass(pass_name: &str) -> Option<Pass> { PASSES.iter().find(|p| p.name == pass_name).copied() } -struct Stripper<'a> { - retained: &'a mut DefIdSet, - access_levels: &'a AccessLevels<DefId>, - update_retained: bool, -} - -impl<'a> DocFolder for Stripper<'a> { - fn fold_item(&mut self, i: Item) -> Option<Item> { - match i.inner { - clean::StrippedItem(..) => { - // We need to recurse into stripped modules to strip things - // like impl methods but when doing so we must not add any - // items to the `retained` set. - debug!("Stripper: recursing into stripped {:?} {:?}", i.type_(), i.name); - let old = mem::replace(&mut self.update_retained, false); - let ret = self.fold_item_recur(i); - self.update_retained = old; - return ret; - } - // These items can all get re-exported - clean::OpaqueTyItem(..) - | clean::TypedefItem(..) - | clean::StaticItem(..) - | clean::StructItem(..) - | clean::EnumItem(..) - | clean::TraitItem(..) - | clean::FunctionItem(..) - | clean::VariantItem(..) - | clean::MethodItem(..) - | clean::ForeignFunctionItem(..) - | clean::ForeignStaticItem(..) - | clean::ConstantItem(..) - | clean::UnionItem(..) - | clean::AssocConstItem(..) - | clean::TraitAliasItem(..) - | clean::ForeignTypeItem => { - if i.def_id.is_local() { - if !self.access_levels.is_exported(i.def_id) { - debug!("Stripper: stripping {:?} {:?}", i.type_(), i.name); - return None; - } - } - } - - clean::StructFieldItem(..) => { - if i.visibility != clean::Public { - return StripItem(i).strip(); - } - } - - clean::ModuleItem(..) => { - if i.def_id.is_local() && i.visibility != clean::Public { - debug!("Stripper: stripping module {:?}", i.name); - let old = mem::replace(&mut self.update_retained, false); - let ret = StripItem(self.fold_item_recur(i).unwrap()).strip(); - self.update_retained = old; - return ret; - } - } - - // handled in the `strip-priv-imports` pass - clean::ExternCrateItem(..) | clean::ImportItem(..) => {} - - clean::ImplItem(..) => {} - - // tymethods/macros have no control over privacy - clean::MacroItem(..) | clean::TyMethodItem(..) => {} - - // Proc-macros are always public - clean::ProcMacroItem(..) => {} - - // Primitives are never stripped - clean::PrimitiveItem(..) => {} - - // Associated types are never stripped - clean::AssocTypeItem(..) => {} - - // Keywords are never stripped - clean::KeywordItem(..) => {} - } - - let fastreturn = match i.inner { - // nothing left to do for traits (don't want to filter their - // methods out, visibility controlled by the trait) - clean::TraitItem(..) => true, - - // implementations of traits are always public. - clean::ImplItem(ref imp) if imp.trait_.is_some() => true, - // Struct variant fields have inherited visibility - clean::VariantItem(clean::Variant { kind: clean::VariantKind::Struct(..) }) => true, - _ => false, - }; - - let i = if fastreturn { - if self.update_retained { - self.retained.insert(i.def_id); - } - return Some(i); - } else { - self.fold_item_recur(i) - }; - - if let Some(ref i) = i { - if self.update_retained { - self.retained.insert(i.def_id); - } - } - i - } -} - -// This stripper discards all impls which reference stripped items -struct ImplStripper<'a> { - retained: &'a DefIdSet, -} - -impl<'a> DocFolder for ImplStripper<'a> { - fn fold_item(&mut self, i: Item) -> Option<Item> { - if let clean::ImplItem(ref imp) = i.inner { - // emptied none trait impls can be stripped - if imp.trait_.is_none() && imp.items.is_empty() { - return None; - } - if let Some(did) = imp.for_.def_id() { - if did.is_local() && !imp.for_.is_generic() && !self.retained.contains(&did) { - debug!("ImplStripper: impl item for stripped type; removing"); - return None; - } - } - if let Some(did) = imp.trait_.def_id() { - if did.is_local() && !self.retained.contains(&did) { - debug!("ImplStripper: impl item for stripped trait; removing"); - return None; - } - } - if let Some(generics) = imp.trait_.as_ref().and_then(|t| t.generics()) { - for typaram in generics { - if let Some(did) = typaram.def_id() { - if did.is_local() && !self.retained.contains(&did) { - debug!( - "ImplStripper: stripped item in trait's generics; removing impl" - ); - return None; - } - } - } - } - } - self.fold_item_recur(i) - } -} - -// This stripper discards all private import statements (`use`, `extern crate`) -struct ImportStripper; -impl DocFolder for ImportStripper { - fn fold_item(&mut self, i: Item) -> Option<Item> { - match i.inner { - clean::ExternCrateItem(..) | clean::ImportItem(..) if i.visibility != clean::Public => { - None - } - _ => self.fold_item_recur(i), - } - } -} - /// Returns a span encompassing all the given attributes. crate fn span_of_attrs(attrs: &clean::Attributes) -> Option<Span> { if attrs.doc_strings.is_empty() { diff --git a/src/librustdoc/passes/stripper.rs b/src/librustdoc/passes/stripper.rs new file mode 100644 index 00000000000..9b4f62235f5 --- /dev/null +++ b/src/librustdoc/passes/stripper.rs @@ -0,0 +1,172 @@ +use rustc_hir::def_id::{DefId, DefIdSet}; +use rustc_middle::middle::privacy::AccessLevels; +use std::mem; + +use crate::clean::{self, GetDefId, Item}; +use crate::fold::{DocFolder, StripItem}; + +pub struct Stripper<'a> { + pub retained: &'a mut DefIdSet, + pub access_levels: &'a AccessLevels<DefId>, + pub update_retained: bool, +} + +impl<'a> DocFolder for Stripper<'a> { + fn fold_item(&mut self, i: Item) -> Option<Item> { + match i.inner { + clean::StrippedItem(..) => { + // We need to recurse into stripped modules to strip things + // like impl methods but when doing so we must not add any + // items to the `retained` set. + debug!("Stripper: recursing into stripped {:?} {:?}", i.type_(), i.name); + let old = mem::replace(&mut self.update_retained, false); + let ret = self.fold_item_recur(i); + self.update_retained = old; + return ret; + } + // These items can all get re-exported + clean::OpaqueTyItem(..) + | clean::TypedefItem(..) + | clean::StaticItem(..) + | clean::StructItem(..) + | clean::EnumItem(..) + | clean::TraitItem(..) + | clean::FunctionItem(..) + | clean::VariantItem(..) + | clean::MethodItem(..) + | clean::ForeignFunctionItem(..) + | clean::ForeignStaticItem(..) + | clean::ConstantItem(..) + | clean::UnionItem(..) + | clean::AssocConstItem(..) + | clean::TraitAliasItem(..) + | clean::ForeignTypeItem => { + if i.def_id.is_local() { + if !self.access_levels.is_exported(i.def_id) { + debug!("Stripper: stripping {:?} {:?}", i.type_(), i.name); + return None; + } + } + } + + clean::StructFieldItem(..) => { + if i.visibility != clean::Public { + return StripItem(i).strip(); + } + } + + clean::ModuleItem(..) => { + if i.def_id.is_local() && i.visibility != clean::Public { + debug!("Stripper: stripping module {:?}", i.name); + let old = mem::replace(&mut self.update_retained, false); + let ret = StripItem(self.fold_item_recur(i).unwrap()).strip(); + self.update_retained = old; + return ret; + } + } + + // handled in the `strip-priv-imports` pass + clean::ExternCrateItem(..) | clean::ImportItem(..) => {} + + clean::ImplItem(..) => {} + + // tymethods/macros have no control over privacy + clean::MacroItem(..) | clean::TyMethodItem(..) => {} + + // Proc-macros are always public + clean::ProcMacroItem(..) => {} + + // Primitives are never stripped + clean::PrimitiveItem(..) => {} + + // Associated types are never stripped + clean::AssocTypeItem(..) => {} + + // Keywords are never stripped + clean::KeywordItem(..) => {} + } + + let fastreturn = match i.inner { + // nothing left to do for traits (don't want to filter their + // methods out, visibility controlled by the trait) + clean::TraitItem(..) => true, + + // implementations of traits are always public. + clean::ImplItem(ref imp) if imp.trait_.is_some() => true, + // Struct variant fields have inherited visibility + clean::VariantItem(clean::Variant { kind: clean::VariantKind::Struct(..) }) => true, + _ => false, + }; + + let i = if fastreturn { + if self.update_retained { + self.retained.insert(i.def_id); + } + return Some(i); + } else { + self.fold_item_recur(i) + }; + + if let Some(ref i) = i { + if self.update_retained { + self.retained.insert(i.def_id); + } + } + i + } +} + +/// This stripper discards all impls which reference stripped items +pub struct ImplStripper<'a> { + pub retained: &'a DefIdSet, +} + +impl<'a> DocFolder for ImplStripper<'a> { + fn fold_item(&mut self, i: Item) -> Option<Item> { + if let clean::ImplItem(ref imp) = i.inner { + // emptied none trait impls can be stripped + if imp.trait_.is_none() && imp.items.is_empty() { + return None; + } + if let Some(did) = imp.for_.def_id() { + if did.is_local() && !imp.for_.is_generic() && !self.retained.contains(&did) { + debug!("ImplStripper: impl item for stripped type; removing"); + return None; + } + } + if let Some(did) = imp.trait_.def_id() { + if did.is_local() && !self.retained.contains(&did) { + debug!("ImplStripper: impl item for stripped trait; removing"); + return None; + } + } + if let Some(generics) = imp.trait_.as_ref().and_then(|t| t.generics()) { + for typaram in generics { + if let Some(did) = typaram.def_id() { + if did.is_local() && !self.retained.contains(&did) { + debug!( + "ImplStripper: stripped item in trait's generics; removing impl" + ); + return None; + } + } + } + } + } + self.fold_item_recur(i) + } +} + +/// This stripper discards all private import statements (`use`, `extern crate`) +pub struct ImportStripper; + +impl DocFolder for ImportStripper { + fn fold_item(&mut self, i: Item) -> Option<Item> { + match i.inner { + clean::ExternCrateItem(..) | clean::ImportItem(..) if i.visibility != clean::Public => { + None + } + _ => self.fold_item_recur(i), + } + } +} diff --git a/src/llvm-project b/src/llvm-project -Subproject 3adf16e0cb1a0d9d7216883ac47857a6d1ee658 +Subproject 655a1467c98741e332b87661a9046877077ef4d diff --git a/src/stage0.txt b/src/stage0.txt index 98b4dfa9c74..9eaa58dd438 100644 --- a/src/stage0.txt +++ b/src/stage0.txt @@ -12,7 +12,7 @@ # source tarball for a stable release you'll likely see `1.x.0` for rustc and # `0.(x+1).0` for Cargo where they were released on `date`. -date: 2020-10-07 +date: 2020-10-16 rustc: beta cargo: beta @@ -20,7 +20,7 @@ cargo: beta # bootstrapping issues with use of new syntax in this repo. If you're looking at # the beta/stable branch, this key should be omitted, as we don't want to depend # on rustfmt from nightly there. -rustfmt: nightly-2020-10-07 +rustfmt: nightly-2020-10-12 # When making a stable release the process currently looks like: # diff --git a/src/test/codegen/loop.rs b/src/test/codegen/loop.rs new file mode 100644 index 00000000000..e54298eed05 --- /dev/null +++ b/src/test/codegen/loop.rs @@ -0,0 +1,15 @@ +// compile-flags: -C opt-level=3 + +#![crate_type = "lib"] + +// CHECK-LABEL: @check_loop +#[no_mangle] +pub fn check_loop() -> u8 { + // CHECK-NOT: unreachable + call_looper() +} + +#[no_mangle] +fn call_looper() -> ! { + loop {} +} diff --git a/src/test/codegen/tune-cpu-on-functions.rs b/src/test/codegen/tune-cpu-on-functions.rs new file mode 100644 index 00000000000..9121799cdbf --- /dev/null +++ b/src/test/codegen/tune-cpu-on-functions.rs @@ -0,0 +1,21 @@ +// This test makes sure that functions get annotated with the proper +// "tune-cpu" attribute in LLVM. + +// no-prefer-dynamic +// ignore-tidy-linelength +// compile-flags: -C no-prepopulate-passes -C panic=abort -C linker-plugin-lto -Cpasses=name-anon-globals -Z tune-cpu=generic + +#![crate_type = "staticlib"] + +// CHECK-LABEL: define {{.*}} @exported() {{.*}} #0 +#[no_mangle] +pub extern fn exported() { + not_exported(); +} + +// CHECK-LABEL: ; tune_cpu_on_functions::not_exported +// CHECK-NEXT: ; Function Attrs: +// CHECK-NEXT: define {{.*}}() {{.*}} #0 +fn not_exported() {} + +// CHECK: attributes #0 = {{.*}} "tune-cpu"="{{.*}}" diff --git a/src/test/debuginfo/pretty-std-collections.rs b/src/test/debuginfo/pretty-std-collections.rs index a4fbff5725c..cc2a3a34510 100644 --- a/src/test/debuginfo/pretty-std-collections.rs +++ b/src/test/debuginfo/pretty-std-collections.rs @@ -34,17 +34,26 @@ // gdb-check:$6 = BTreeMap(size=15) = {[0] = pretty_std_collections::MyLeafNode (0), [...]} // (abbreviated because it's boring but we need enough elements to include internal nodes) +// gdb-command: print zst_key_btree_map +// gdb-check:$7 = BTreeMap(size=1) = {[()] = 1} + +// gdb-command: print zst_val_btree_map +// gdb-check:$8 = BTreeMap(size=1) = {[1] = ()} + +// gdb-command: print zst_key_val_btree_map +// gdb-check:$9 = BTreeMap(size=1) = {[()] = ()} + // gdb-command: print vec_deque -// gdb-check:$7 = VecDeque(size=3) = {5, 3, 7} +// gdb-check:$10 = VecDeque(size=3) = {5, 3, 7} // gdb-command: print vec_deque2 -// gdb-check:$8 = VecDeque(size=7) = {2, 3, 4, 5, 6, 7, 8} +// gdb-check:$11 = VecDeque(size=7) = {2, 3, 4, 5, 6, 7, 8} // gdb-command: print hash_map -// gdb-check:$9 = HashMap(size=4) = {[1] = 10, [2] = 20, [3] = 30, [4] = 40} +// gdb-check:$12 = HashMap(size=4) = {[1] = 10, [2] = 20, [3] = 30, [4] = 40} // gdb-command: print hash_set -// gdb-check:$10 = HashSet(size=4) = {1, 2, 3, 4} +// gdb-check:$13 = HashSet(size=4) = {1, 2, 3, 4} // === LLDB TESTS ================================================================================== @@ -69,9 +78,9 @@ #![allow(unused_variables)] use std::collections::BTreeMap; use std::collections::BTreeSet; -use std::collections::VecDeque; use std::collections::HashMap; use std::collections::HashSet; +use std::collections::VecDeque; use std::hash::{BuildHasherDefault, Hasher}; struct MyLeafNode(i32); // helps to ensure we don't blindly replace substring "LeafNode" @@ -111,6 +120,15 @@ fn main() { nasty_btree_map.insert(i, MyLeafNode(i)); } + let mut zst_key_btree_map: BTreeMap<(), i32> = BTreeMap::new(); + zst_key_btree_map.insert((), 1); + + let mut zst_val_btree_map: BTreeMap<i32, ()> = BTreeMap::new(); + zst_val_btree_map.insert(1, ()); + + let mut zst_key_val_btree_map: BTreeMap<(), ()> = BTreeMap::new(); + zst_key_val_btree_map.insert((), ()); + // VecDeque let mut vec_deque = VecDeque::new(); vec_deque.push_back(5); diff --git a/src/test/incremental/thinlto/cgu_invalidated_via_import.rs b/src/test/incremental/thinlto/cgu_invalidated_via_import.rs index 8160f8f3a99..5fe435d796f 100644 --- a/src/test/incremental/thinlto/cgu_invalidated_via_import.rs +++ b/src/test/incremental/thinlto/cgu_invalidated_via_import.rs @@ -33,7 +33,9 @@ mod foo { #[cfg(not(cfail1))] pub fn inlined_fn() -> u32 { - 1234 + // See `cgu_keeps_identical_fn.rs` for why this is different + // from the other version of this function. + 12345 } } diff --git a/src/test/incremental/thinlto/cgu_keeps_identical_fn.rs b/src/test/incremental/thinlto/cgu_keeps_identical_fn.rs new file mode 100644 index 00000000000..0fd5abee118 --- /dev/null +++ b/src/test/incremental/thinlto/cgu_keeps_identical_fn.rs @@ -0,0 +1,47 @@ +// This test is almost identical to `cgu_invalided_via_import`, except that +// the two versions of `inline_fn` are identical. Neither version of `inlined_fn` +// ends up with any spans in its LLVM bitecode, so LLVM is able to skip +// re-building any modules which import 'inlined_fn' + +// revisions: cfail1 cfail2 cfail3 +// compile-flags: -Z query-dep-graph -O +// build-pass (FIXME(62277): could be check-pass?) + +#![feature(rustc_attrs)] +#![crate_type="rlib"] + +#![rustc_expected_cgu_reuse(module="cgu_keeps_identical_fn-foo", + cfg="cfail2", + kind="no")] +#![rustc_expected_cgu_reuse(module="cgu_keeps_identical_fn-foo", + cfg="cfail3", + kind="post-lto")] + +#![rustc_expected_cgu_reuse(module="cgu_keeps_identical_fn-bar", + cfg="cfail2", + kind="post-lto")] +#![rustc_expected_cgu_reuse(module="cgu_keeps_identical_fn-bar", + cfg="cfail3", + kind="post-lto")] + +mod foo { + + // Trivial functions like this one are imported very reliably by ThinLTO. + #[cfg(cfail1)] + pub fn inlined_fn() -> u32 { + 1234 + } + + #[cfg(not(cfail1))] + pub fn inlined_fn() -> u32 { + 1234 + } +} + +pub mod bar { + use foo::inlined_fn; + + pub fn caller() -> u32 { + inlined_fn() + } +} diff --git a/src/test/incremental/thinlto/independent_cgus_dont_affect_each_other.rs b/src/test/incremental/thinlto/independent_cgus_dont_affect_each_other.rs index 24e5d2438bd..045f2011958 100644 --- a/src/test/incremental/thinlto/independent_cgus_dont_affect_each_other.rs +++ b/src/test/incremental/thinlto/independent_cgus_dont_affect_each_other.rs @@ -37,7 +37,9 @@ mod foo { #[cfg(not(cfail1))] pub fn inlined_fn() -> u32 { - 1234 + // See `cgu_keeps_identical_fn.rs` for why this is different + // from the other version of this function. + 12345 } } diff --git a/src/test/mir-opt/const_promotion_extern_static.FOO-promoted[0].ConstProp.after.mir b/src/test/mir-opt/const_promotion_extern_static.FOO-promoted[0].ConstProp.after.mir index d9c6b4f0029..0d5760b4cd5 100644 --- a/src/test/mir-opt/const_promotion_extern_static.FOO-promoted[0].ConstProp.after.mir +++ b/src/test/mir-opt/const_promotion_extern_static.FOO-promoted[0].ConstProp.after.mir @@ -5,8 +5,6 @@ promoted[0] in FOO: &[&i32; 1] = { let mut _1: [&i32; 1]; // in scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46 let mut _2: &i32; // in scope 0 at $DIR/const-promotion-extern-static.rs:13:32: 13:45 let mut _3: &i32; // in scope 0 at $DIR/const-promotion-extern-static.rs:13:42: 13:43 - scope 1 { - } bb0: { _3 = const {alloc2: &i32}; // scope 0 at $DIR/const-promotion-extern-static.rs:13:42: 13:43 diff --git a/src/test/mir-opt/copy_propagation.rs b/src/test/mir-opt/copy_propagation.rs deleted file mode 100644 index 8283ec73d0f..00000000000 --- a/src/test/mir-opt/copy_propagation.rs +++ /dev/null @@ -1,12 +0,0 @@ -// compile-flags: -Zunsound-mir-opts -// EMIT_MIR copy_propagation.test.CopyPropagation.diff - -fn test(x: u32) -> u32 { - let y = x; - y -} - -fn main() { - // Make sure the function actually gets instantiated. - test(0); -} diff --git a/src/test/mir-opt/copy_propagation.test.CopyPropagation.diff b/src/test/mir-opt/copy_propagation.test.CopyPropagation.diff deleted file mode 100644 index 152d1590630..00000000000 --- a/src/test/mir-opt/copy_propagation.test.CopyPropagation.diff +++ /dev/null @@ -1,20 +0,0 @@ -- // MIR for `test` before CopyPropagation -+ // MIR for `test` after CopyPropagation - - fn test(_1: u32) -> u32 { - debug x => _1; // in scope 0 at $DIR/copy_propagation.rs:4:9: 4:10 - let mut _0: u32; // return place in scope 0 at $DIR/copy_propagation.rs:4:20: 4:23 - let _2: u32; // in scope 0 at $DIR/copy_propagation.rs:5:9: 5:10 - scope 1 { - debug y => _0; // in scope 1 at $DIR/copy_propagation.rs:5:9: 5:10 - } - - bb0: { - nop; // scope 0 at $DIR/copy_propagation.rs:5:9: 5:10 - _0 = _1; // scope 0 at $DIR/copy_propagation.rs:5:13: 5:14 - nop; // scope 1 at $DIR/copy_propagation.rs:6:5: 6:6 - nop; // scope 0 at $DIR/copy_propagation.rs:7:1: 7:2 - return; // scope 0 at $DIR/copy_propagation.rs:7:2: 7:2 - } - } - diff --git a/src/test/mir-opt/copy_propagation_arg.arg_src.CopyPropagation.diff b/src/test/mir-opt/copy_propagation_arg.arg_src.CopyPropagation.diff deleted file mode 100644 index 8aab2299d26..00000000000 --- a/src/test/mir-opt/copy_propagation_arg.arg_src.CopyPropagation.diff +++ /dev/null @@ -1,21 +0,0 @@ -- // MIR for `arg_src` before CopyPropagation -+ // MIR for `arg_src` after CopyPropagation - - fn arg_src(_1: i32) -> i32 { - debug x => _1; // in scope 0 at $DIR/copy_propagation_arg.rs:27:12: 27:17 - let mut _0: i32; // return place in scope 0 at $DIR/copy_propagation_arg.rs:27:27: 27:30 - let _2: i32; // in scope 0 at $DIR/copy_propagation_arg.rs:28:9: 28:10 - scope 1 { - debug y => _0; // in scope 1 at $DIR/copy_propagation_arg.rs:28:9: 28:10 - } - - bb0: { - nop; // scope 0 at $DIR/copy_propagation_arg.rs:28:9: 28:10 - _0 = _1; // scope 0 at $DIR/copy_propagation_arg.rs:28:13: 28:14 - _1 = const 123_i32; // scope 1 at $DIR/copy_propagation_arg.rs:29:5: 29:12 - nop; // scope 1 at $DIR/copy_propagation_arg.rs:30:5: 30:6 - nop; // scope 0 at $DIR/copy_propagation_arg.rs:31:1: 31:2 - return; // scope 0 at $DIR/copy_propagation_arg.rs:31:2: 31:2 - } - } - diff --git a/src/test/mir-opt/copy_propagation_arg.baz.CopyPropagation.diff b/src/test/mir-opt/copy_propagation_arg.baz.CopyPropagation.diff deleted file mode 100644 index 1ea51fec710..00000000000 --- a/src/test/mir-opt/copy_propagation_arg.baz.CopyPropagation.diff +++ /dev/null @@ -1,18 +0,0 @@ -- // MIR for `baz` before CopyPropagation -+ // MIR for `baz` after CopyPropagation - - fn baz(_1: i32) -> () { - debug x => _1; // in scope 0 at $DIR/copy_propagation_arg.rs:21:8: 21:13 - let mut _0: (); // return place in scope 0 at $DIR/copy_propagation_arg.rs:21:20: 21:20 - let mut _2: i32; // in scope 0 at $DIR/copy_propagation_arg.rs:23:9: 23:10 - - bb0: { - nop; // scope 0 at $DIR/copy_propagation_arg.rs:23:9: 23:10 - nop; // scope 0 at $DIR/copy_propagation_arg.rs:23:9: 23:10 - nop; // scope 0 at $DIR/copy_propagation_arg.rs:23:5: 23:10 - nop; // scope 0 at $DIR/copy_propagation_arg.rs:23:9: 23:10 - _0 = const (); // scope 0 at $DIR/copy_propagation_arg.rs:21:20: 24:2 - return; // scope 0 at $DIR/copy_propagation_arg.rs:24:2: 24:2 - } - } - diff --git a/src/test/mir-opt/dest-prop/copy_propagation_arg.arg_src.DestinationPropagation.diff b/src/test/mir-opt/dest-prop/copy_propagation_arg.arg_src.DestinationPropagation.diff new file mode 100644 index 00000000000..a5d80e75053 --- /dev/null +++ b/src/test/mir-opt/dest-prop/copy_propagation_arg.arg_src.DestinationPropagation.diff @@ -0,0 +1,26 @@ +- // MIR for `arg_src` before DestinationPropagation ++ // MIR for `arg_src` after DestinationPropagation + + fn arg_src(_1: i32) -> i32 { + debug x => _1; // in scope 0 at $DIR/copy_propagation_arg.rs:27:12: 27:17 + let mut _0: i32; // return place in scope 0 at $DIR/copy_propagation_arg.rs:27:27: 27:30 + let _2: i32; // in scope 0 at $DIR/copy_propagation_arg.rs:28:9: 28:10 + scope 1 { +- debug y => _2; // in scope 1 at $DIR/copy_propagation_arg.rs:28:9: 28:10 ++ debug y => _0; // in scope 1 at $DIR/copy_propagation_arg.rs:28:9: 28:10 + } + + bb0: { +- StorageLive(_2); // scope 0 at $DIR/copy_propagation_arg.rs:28:9: 28:10 +- _2 = _1; // scope 0 at $DIR/copy_propagation_arg.rs:28:13: 28:14 ++ nop; // scope 0 at $DIR/copy_propagation_arg.rs:28:9: 28:10 ++ _0 = _1; // scope 0 at $DIR/copy_propagation_arg.rs:28:13: 28:14 + _1 = const 123_i32; // scope 1 at $DIR/copy_propagation_arg.rs:29:5: 29:12 +- _0 = _2; // scope 1 at $DIR/copy_propagation_arg.rs:30:5: 30:6 +- StorageDead(_2); // scope 0 at $DIR/copy_propagation_arg.rs:31:1: 31:2 ++ nop; // scope 1 at $DIR/copy_propagation_arg.rs:30:5: 30:6 ++ nop; // scope 0 at $DIR/copy_propagation_arg.rs:31:1: 31:2 + return; // scope 0 at $DIR/copy_propagation_arg.rs:31:2: 31:2 + } + } + diff --git a/src/test/mir-opt/copy_propagation_arg.bar.CopyPropagation.diff b/src/test/mir-opt/dest-prop/copy_propagation_arg.bar.DestinationPropagation.diff index fb793e53ea8..dce8800e986 100644 --- a/src/test/mir-opt/copy_propagation_arg.bar.CopyPropagation.diff +++ b/src/test/mir-opt/dest-prop/copy_propagation_arg.bar.DestinationPropagation.diff @@ -1,5 +1,5 @@ -- // MIR for `bar` before CopyPropagation -+ // MIR for `bar` after CopyPropagation +- // MIR for `bar` before DestinationPropagation ++ // MIR for `bar` after DestinationPropagation fn bar(_1: u8) -> () { debug x => _1; // in scope 0 at $DIR/copy_propagation_arg.rs:15:8: 15:13 diff --git a/src/test/mir-opt/dest-prop/copy_propagation_arg.baz.DestinationPropagation.diff b/src/test/mir-opt/dest-prop/copy_propagation_arg.baz.DestinationPropagation.diff new file mode 100644 index 00000000000..2f8c76eb65a --- /dev/null +++ b/src/test/mir-opt/dest-prop/copy_propagation_arg.baz.DestinationPropagation.diff @@ -0,0 +1,22 @@ +- // MIR for `baz` before DestinationPropagation ++ // MIR for `baz` after DestinationPropagation + + fn baz(_1: i32) -> () { + debug x => _1; // in scope 0 at $DIR/copy_propagation_arg.rs:21:8: 21:13 + let mut _0: (); // return place in scope 0 at $DIR/copy_propagation_arg.rs:21:20: 21:20 + let mut _2: i32; // in scope 0 at $DIR/copy_propagation_arg.rs:23:9: 23:10 + + bb0: { +- StorageLive(_2); // scope 0 at $DIR/copy_propagation_arg.rs:23:9: 23:10 +- _2 = _1; // scope 0 at $DIR/copy_propagation_arg.rs:23:9: 23:10 +- _1 = move _2; // scope 0 at $DIR/copy_propagation_arg.rs:23:5: 23:10 +- StorageDead(_2); // scope 0 at $DIR/copy_propagation_arg.rs:23:9: 23:10 ++ nop; // scope 0 at $DIR/copy_propagation_arg.rs:23:9: 23:10 ++ nop; // scope 0 at $DIR/copy_propagation_arg.rs:23:9: 23:10 ++ nop; // scope 0 at $DIR/copy_propagation_arg.rs:23:5: 23:10 ++ nop; // scope 0 at $DIR/copy_propagation_arg.rs:23:9: 23:10 + _0 = const (); // scope 0 at $DIR/copy_propagation_arg.rs:21:20: 24:2 + return; // scope 0 at $DIR/copy_propagation_arg.rs:24:2: 24:2 + } + } + diff --git a/src/test/mir-opt/copy_propagation_arg.foo.CopyPropagation.diff b/src/test/mir-opt/dest-prop/copy_propagation_arg.foo.DestinationPropagation.diff index 48ab37a239c..2dea530db3d 100644 --- a/src/test/mir-opt/copy_propagation_arg.foo.CopyPropagation.diff +++ b/src/test/mir-opt/dest-prop/copy_propagation_arg.foo.DestinationPropagation.diff @@ -1,5 +1,5 @@ -- // MIR for `foo` before CopyPropagation -+ // MIR for `foo` after CopyPropagation +- // MIR for `foo` before DestinationPropagation ++ // MIR for `foo` after DestinationPropagation fn foo(_1: u8) -> () { debug x => _1; // in scope 0 at $DIR/copy_propagation_arg.rs:9:8: 9:13 @@ -8,10 +8,12 @@ let mut _3: u8; // in scope 0 at $DIR/copy_propagation_arg.rs:11:15: 11:16 bb0: { - nop; // scope 0 at $DIR/copy_propagation_arg.rs:11:9: 11:17 +- StorageLive(_2); // scope 0 at $DIR/copy_propagation_arg.rs:11:9: 11:17 ++ nop; // scope 0 at $DIR/copy_propagation_arg.rs:11:9: 11:17 StorageLive(_3); // scope 0 at $DIR/copy_propagation_arg.rs:11:15: 11:16 _3 = _1; // scope 0 at $DIR/copy_propagation_arg.rs:11:15: 11:16 - _1 = dummy(move _3) -> bb1; // scope 0 at $DIR/copy_propagation_arg.rs:11:9: 11:17 +- _2 = dummy(move _3) -> bb1; // scope 0 at $DIR/copy_propagation_arg.rs:11:9: 11:17 ++ _1 = dummy(move _3) -> bb1; // scope 0 at $DIR/copy_propagation_arg.rs:11:9: 11:17 // mir::Constant // + span: $DIR/copy_propagation_arg.rs:11:9: 11:14 // + literal: Const { ty: fn(u8) -> u8 {dummy}, val: Value(Scalar(<ZST>)) } @@ -19,8 +21,10 @@ bb1: { StorageDead(_3); // scope 0 at $DIR/copy_propagation_arg.rs:11:16: 11:17 - nop; // scope 0 at $DIR/copy_propagation_arg.rs:11:5: 11:17 - nop; // scope 0 at $DIR/copy_propagation_arg.rs:11:16: 11:17 +- _1 = move _2; // scope 0 at $DIR/copy_propagation_arg.rs:11:5: 11:17 +- StorageDead(_2); // scope 0 at $DIR/copy_propagation_arg.rs:11:16: 11:17 ++ nop; // scope 0 at $DIR/copy_propagation_arg.rs:11:5: 11:17 ++ nop; // scope 0 at $DIR/copy_propagation_arg.rs:11:16: 11:17 _0 = const (); // scope 0 at $DIR/copy_propagation_arg.rs:9:19: 12:2 return; // scope 0 at $DIR/copy_propagation_arg.rs:12:2: 12:2 } diff --git a/src/test/mir-opt/copy_propagation_arg.rs b/src/test/mir-opt/dest-prop/copy_propagation_arg.rs index 3a00fc58a4e..b5188a8b4b2 100644 --- a/src/test/mir-opt/copy_propagation_arg.rs +++ b/src/test/mir-opt/dest-prop/copy_propagation_arg.rs @@ -1,29 +1,29 @@ -// Check that CopyPropagation does not propagate an assignment to a function argument +// Check that DestinationPropagation does not propagate an assignment to a function argument // (doing so can break usages of the original argument value) fn dummy(x: u8) -> u8 { x } -// EMIT_MIR copy_propagation_arg.foo.CopyPropagation.diff +// EMIT_MIR copy_propagation_arg.foo.DestinationPropagation.diff fn foo(mut x: u8) { // calling `dummy` to make an use of `x` that copyprop cannot eliminate x = dummy(x); // this will assign a local to `x` } -// EMIT_MIR copy_propagation_arg.bar.CopyPropagation.diff +// EMIT_MIR copy_propagation_arg.bar.DestinationPropagation.diff fn bar(mut x: u8) { dummy(x); x = 5; } -// EMIT_MIR copy_propagation_arg.baz.CopyPropagation.diff +// EMIT_MIR copy_propagation_arg.baz.DestinationPropagation.diff fn baz(mut x: i32) { // self-assignment to a function argument should be eliminated x = x; } -// EMIT_MIR copy_propagation_arg.arg_src.CopyPropagation.diff +// EMIT_MIR copy_propagation_arg.arg_src.DestinationPropagation.diff fn arg_src(mut x: i32) -> i32 { let y = x; x = 123; // Don't propagate this assignment to `y` diff --git a/src/test/mir-opt/early_otherwise_branch_68867.rs b/src/test/mir-opt/early_otherwise_branch_68867.rs index 98a275c18ac..b822c58f550 100644 --- a/src/test/mir-opt/early_otherwise_branch_68867.rs +++ b/src/test/mir-opt/early_otherwise_branch_68867.rs @@ -12,7 +12,7 @@ pub enum ViewportPercentageLength { } // EMIT_MIR early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.diff -// EMIT_MIR early_otherwise_branch_68867.try_sum EarlyOtherwiseBranch.before SimplifyBranches-after-copy-prop.after +// EMIT_MIR early_otherwise_branch_68867.try_sum EarlyOtherwiseBranch.before SimplifyBranches-final.after #[no_mangle] pub extern "C" fn try_sum( x: &ViewportPercentageLength, diff --git a/src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.before-SimplifyBranches-after-copy-prop.after.diff b/src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.before-SimplifyBranches-final.after.diff index 9a5a309fd27..f51a08ed730 100644 --- a/src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.before-SimplifyBranches-after-copy-prop.after.diff +++ b/src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.before-SimplifyBranches-final.after.diff @@ -1,5 +1,5 @@ - // MIR for `try_sum` before EarlyOtherwiseBranch -+ // MIR for `try_sum` after SimplifyBranches-after-copy-prop ++ // MIR for `try_sum` after SimplifyBranches-final fn try_sum(_1: &ViewportPercentageLength, _2: &ViewportPercentageLength) -> std::result::Result<ViewportPercentageLength, ()> { debug x => _1; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:18:5: 18:6 @@ -68,21 +68,17 @@ - StorageLive(_4); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:24 - StorageLive(_5); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:15: 22:16 - _5 = _1; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:15: 22:16 -- StorageLive(_6); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:18: 22:23 -- _6 = _2; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:18: 22:23 -- (_4.0: &ViewportPercentageLength) = move _5; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:24 -- (_4.1: &ViewportPercentageLength) = move _6; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:24 -- StorageDead(_6); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:23: 22:24 -- StorageDead(_5); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:23: 22:24 + nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:8: 28:6 + nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:24 + nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:15: 22:16 + (_4.0: &ViewportPercentageLength) = _1; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:15: 22:16 -+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:18: 22:23 -+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:18: 22:23 + StorageLive(_6); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:18: 22:23 + _6 = _2; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:18: 22:23 +- (_4.0: &ViewportPercentageLength) = move _5; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:24 + nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:24 -+ (_4.1: &ViewportPercentageLength) = move _2; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:24 -+ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:23: 22:24 + (_4.1: &ViewportPercentageLength) = move _6; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:24 + StorageDead(_6); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:23: 22:24 +- StorageDead(_5); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:23: 22:24 + nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:23: 22:24 _11 = discriminant((*(_4.0: &ViewportPercentageLength))); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:11: 23:18 - switchInt(move _11) -> [0_isize: bb1, 1_isize: bb3, 2_isize: bb4, 3_isize: bb5, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:11: 23:18 diff --git a/src/test/run-make-fulldeps/hotplug_codegen_backend/the_backend.rs b/src/test/run-make-fulldeps/hotplug_codegen_backend/the_backend.rs index dd49ca67c67..0e1bef6f68d 100644 --- a/src/test/run-make-fulldeps/hotplug_codegen_backend/the_backend.rs +++ b/src/test/run-make-fulldeps/hotplug_codegen_backend/the_backend.rs @@ -3,7 +3,6 @@ extern crate rustc_codegen_ssa; extern crate rustc_errors; extern crate rustc_middle; -#[macro_use] extern crate rustc_data_structures; extern crate rustc_driver; extern crate rustc_hir; @@ -12,17 +11,19 @@ extern crate rustc_span; extern crate rustc_symbol_mangling; extern crate rustc_target; +use rustc_codegen_ssa::back::linker::LinkerInfo; use rustc_codegen_ssa::traits::CodegenBackend; -use rustc_data_structures::owning_ref::OwningRef; +use rustc_codegen_ssa::{CodegenResults, CrateInfo}; +use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sync::MetadataRef; use rustc_errors::ErrorReported; use rustc_middle::dep_graph::DepGraph; +use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; use rustc_middle::middle::cstore::{EncodedMetadata, MetadataLoader, MetadataLoaderDyn}; use rustc_middle::ty::query::Providers; use rustc_middle::ty::TyCtxt; use rustc_session::config::OutputFilenames; use rustc_session::Session; -use rustc_span::symbol::Symbol; use rustc_target::spec::Target; use std::any::Any; use std::path::Path; @@ -31,14 +32,11 @@ pub struct NoLlvmMetadataLoader; impl MetadataLoader for NoLlvmMetadataLoader { fn get_rlib_metadata(&self, _: &Target, filename: &Path) -> Result<MetadataRef, String> { - let buf = - std::fs::read(filename).map_err(|e| format!("metadata file open err: {:?}", e))?; - let buf: OwningRef<Vec<u8>, [u8]> = OwningRef::new(buf); - Ok(rustc_erase_owner!(buf.map_owner_box())) + unreachable!("some_crate.rs shouldn't depend on any external crates"); } fn get_dylib_metadata(&self, target: &Target, filename: &Path) -> Result<MetadataRef, String> { - self.get_rlib_metadata(target, filename) + unreachable!("some_crate.rs shouldn't depend on any external crates"); } } @@ -49,53 +47,49 @@ impl CodegenBackend for TheBackend { Box::new(NoLlvmMetadataLoader) } - fn provide(&self, providers: &mut Providers) { - rustc_symbol_mangling::provide(providers); - - providers.supported_target_features = |tcx, _cnum| { - Default::default() // Just a dummy - }; - providers.is_reachable_non_generic = |_tcx, _defid| true; - providers.exported_symbols = |_tcx, _crate| &[]; - } - - fn provide_extern(&self, providers: &mut Providers) { - providers.is_reachable_non_generic = |_tcx, _defid| true; - } + fn provide(&self, providers: &mut Providers) {} + fn provide_extern(&self, providers: &mut Providers) {} fn codegen_crate<'a, 'tcx>( &self, tcx: TyCtxt<'tcx>, - _metadata: EncodedMetadata, + metadata: EncodedMetadata, _need_metadata_module: bool, ) -> Box<dyn Any> { use rustc_hir::def_id::LOCAL_CRATE; - Box::new(tcx.crate_name(LOCAL_CRATE) as Symbol) + Box::new(CodegenResults { + crate_name: tcx.crate_name(LOCAL_CRATE), + modules: vec![], + allocator_module: None, + metadata_module: None, + metadata, + windows_subsystem: None, + linker_info: LinkerInfo::new(tcx), + crate_info: CrateInfo::new(tcx), + }) } fn join_codegen( &self, ongoing_codegen: Box<dyn Any>, _sess: &Session, - _dep_graph: &DepGraph, - ) -> Result<Box<dyn Any>, ErrorReported> { - let crate_name = ongoing_codegen - .downcast::<Symbol>() - .expect("in join_codegen: ongoing_codegen is not a Symbol"); - Ok(crate_name) + ) -> Result<(CodegenResults, FxHashMap<WorkProductId, WorkProduct>), ErrorReported> { + let codegen_results = ongoing_codegen + .downcast::<CodegenResults>() + .expect("in join_codegen: ongoing_codegen is not a CodegenResults"); + Ok((*codegen_results, FxHashMap::default())) } fn link( &self, sess: &Session, - codegen_results: Box<dyn Any>, + codegen_results: CodegenResults, outputs: &OutputFilenames, ) -> Result<(), ErrorReported> { use rustc_session::{config::CrateType, output::out_filename}; use std::io::Write; - let crate_name = - codegen_results.downcast::<Symbol>().expect("in link: codegen_results is not a Symbol"); + let crate_name = codegen_results.crate_name; for &crate_type in sess.opts.crate_types.iter() { if crate_type != CrateType::Rlib { sess.fatal(&format!("Crate type is {:?}", crate_type)); diff --git a/src/test/rustdoc-js/doc-alias-whitespace.js b/src/test/rustdoc-js/doc-alias-whitespace.js new file mode 100644 index 00000000000..c9fc0c4311f --- /dev/null +++ b/src/test/rustdoc-js/doc-alias-whitespace.js @@ -0,0 +1,19 @@ +// exact-check + +const QUERY = [ + 'Demon Lord', +]; + +const EXPECTED = [ + { + 'others': [ + { + 'path': 'doc_alias_whitespace', + 'name': 'Struct', + 'alias': 'Demon Lord', + 'href': '../doc_alias_whitespace/struct.Struct.html', + 'is_alias': true + }, + ], + }, +]; diff --git a/src/test/rustdoc-js/doc-alias-whitespace.rs b/src/test/rustdoc-js/doc-alias-whitespace.rs new file mode 100644 index 00000000000..bea3e382ae4 --- /dev/null +++ b/src/test/rustdoc-js/doc-alias-whitespace.rs @@ -0,0 +1,4 @@ +#![feature(doc_alias)] + +#[doc(alias = "Demon Lord")] +pub struct Struct; diff --git a/src/test/rustdoc-ui/check-doc-alias-attr.rs b/src/test/rustdoc-ui/check-doc-alias-attr.rs index c8bec39fad6..0ca2349a43b 100644 --- a/src/test/rustdoc-ui/check-doc-alias-attr.rs +++ b/src/test/rustdoc-ui/check-doc-alias-attr.rs @@ -11,6 +11,7 @@ pub struct Bar; #[doc(alias = "\n")] //~ ERROR #[doc(alias = " ")] //~^ ERROR -#[doc(alias = " ")] //~ ERROR #[doc(alias = "\t")] //~ ERROR +#[doc(alias = " hello")] //~ ERROR +#[doc(alias = "hello ")] //~ ERROR pub struct Foo; diff --git a/src/test/rustdoc-ui/check-doc-alias-attr.stderr b/src/test/rustdoc-ui/check-doc-alias-attr.stderr index be7d7b3dbea..2c417a3bb65 100644 --- a/src/test/rustdoc-ui/check-doc-alias-attr.stderr +++ b/src/test/rustdoc-ui/check-doc-alias-attr.stderr @@ -36,17 +36,23 @@ LL | #[doc(alias = " LL | | ")] | |_^ -error: ' ' character isn't allowed in `#[doc(alias = "...")]` +error: '\t' character isn't allowed in `#[doc(alias = "...")]` --> $DIR/check-doc-alias-attr.rs:14:7 | -LL | #[doc(alias = " ")] - | ^^^^^^^^^^^ +LL | #[doc(alias = "\t")] + | ^^^^^^^^^^^^ -error: '\t' character isn't allowed in `#[doc(alias = "...")]` +error: `#[doc(alias = "...")]` cannot start or end with ' ' --> $DIR/check-doc-alias-attr.rs:15:7 | -LL | #[doc(alias = "\t")] - | ^^^^^^^^^^^^ +LL | #[doc(alias = " hello")] + | ^^^^^^^^^^^^^^^^ + +error: `#[doc(alias = "...")]` cannot start or end with ' ' + --> $DIR/check-doc-alias-attr.rs:16:7 + | +LL | #[doc(alias = "hello ")] + | ^^^^^^^^^^^^^^^^ -error: aborting due to 8 previous errors +error: aborting due to 9 previous errors diff --git a/src/test/rustdoc-ui/coverage/allow_missing_docs.rs b/src/test/rustdoc-ui/coverage/allow_missing_docs.rs new file mode 100644 index 00000000000..c077be31b20 --- /dev/null +++ b/src/test/rustdoc-ui/coverage/allow_missing_docs.rs @@ -0,0 +1,41 @@ +// compile-flags:-Z unstable-options --show-coverage +// check-pass + +//! Make sure to have some docs on your crate root + +#[allow(missing_docs)] +pub mod mod_foo { + pub struct Bar; +} + +/// This is a struct with a `#[allow(missing_docs)]` +pub struct AllowTheMissingDocs { + #[allow(missing_docs)] + pub empty_str: String, + + /// This has + #[allow(missing_docs)] + /// but also has documentation comments + pub hello: usize, + + /// The doc id just to create a boilerplate comment + pub doc_id: Vec<u8>, +} + +/// A function that has a documentation +pub fn this_is_func() {} + +#[allow(missing_docs)] +pub struct DemoStruct { + something: usize, +} + +#[allow(missing_docs)] +pub mod bar { + #[warn(missing_docs)] + pub struct Bar { //~ WARN + pub f: u32, //~ WARN + } + + pub struct NeedsNoDocs; +} diff --git a/src/test/rustdoc-ui/coverage/allow_missing_docs.stderr b/src/test/rustdoc-ui/coverage/allow_missing_docs.stderr new file mode 100644 index 00000000000..3d5b512d14d --- /dev/null +++ b/src/test/rustdoc-ui/coverage/allow_missing_docs.stderr @@ -0,0 +1,20 @@ +warning: missing documentation for a struct + --> $DIR/allow_missing_docs.rs:36:5 + | +LL | pub struct Bar { + | ^^^^^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/allow_missing_docs.rs:35:12 + | +LL | #[warn(missing_docs)] + | ^^^^^^^^^^^^ + +warning: missing documentation for a struct field + --> $DIR/allow_missing_docs.rs:37:9 + | +LL | pub f: u32, + | ^^^^^^^^^^ + +warning: 2 warnings emitted + diff --git a/src/test/rustdoc-ui/coverage/allow_missing_docs.stdout b/src/test/rustdoc-ui/coverage/allow_missing_docs.stdout new file mode 100644 index 00000000000..17e8ee9e23d --- /dev/null +++ b/src/test/rustdoc-ui/coverage/allow_missing_docs.stdout @@ -0,0 +1,7 @@ ++-------------------------------------+------------+------------+------------+------------+ +| File | Documented | Percentage | Examples | Percentage | ++-------------------------------------+------------+------------+------------+------------+ +| ...i/coverage/allow_missing_docs.rs | 5 | 71.4% | 0 | 0.0% | ++-------------------------------------+------------+------------+------------+------------+ +| Total | 5 | 71.4% | 0 | 0.0% | ++-------------------------------------+------------+------------+------------+------------+ diff --git a/src/test/rustdoc-ui/invalid-html-tags.rs b/src/test/rustdoc-ui/invalid-html-tags.rs index d878e390ca3..56ca7e79d43 100644 --- a/src/test/rustdoc-ui/invalid-html-tags.rs +++ b/src/test/rustdoc-ui/invalid-html-tags.rs @@ -73,3 +73,17 @@ pub fn e() {} /// <div></div //~^ ERROR unclosed HTML tag `div` pub fn f() {} + +/// <!----> +/// <!-- --> +/// <!-- <div> --> +/// <!-- <!-- --> +pub fn g() {} + +/// <!-- +/// --> +pub fn h() {} + +/// <!-- +//~^ ERROR Unclosed HTML comment +pub fn i() {} diff --git a/src/test/rustdoc-ui/invalid-html-tags.stderr b/src/test/rustdoc-ui/invalid-html-tags.stderr index 11f176ff05c..aa9ace006bd 100644 --- a/src/test/rustdoc-ui/invalid-html-tags.stderr +++ b/src/test/rustdoc-ui/invalid-html-tags.stderr @@ -76,5 +76,11 @@ error: unclosed HTML tag `div` LL | /// <div></div | ^^^^^ -error: aborting due to 12 previous errors +error: Unclosed HTML comment + --> $DIR/invalid-html-tags.rs:87:5 + | +LL | /// <!-- + | ^^^ + +error: aborting due to 13 previous errors diff --git a/src/test/rustdoc/auxiliary/intra-link-reexport-additional-docs.rs b/src/test/rustdoc/auxiliary/intra-link-reexport-additional-docs.rs new file mode 100644 index 00000000000..fc51995a94e --- /dev/null +++ b/src/test/rustdoc/auxiliary/intra-link-reexport-additional-docs.rs @@ -0,0 +1,6 @@ +#![crate_name = "inner"] + +/// Links to [f()] +pub struct Inner; + +pub fn f() {} diff --git a/src/test/rustdoc/auxiliary/reexport-check.rs b/src/test/rustdoc/auxiliary/reexport-check.rs new file mode 100644 index 00000000000..672ccb1cf0e --- /dev/null +++ b/src/test/rustdoc/auxiliary/reexport-check.rs @@ -0,0 +1,2 @@ +/// Docs in original +pub struct S; diff --git a/src/test/rustdoc/doc-cfg-simplification.rs b/src/test/rustdoc/doc-cfg-simplification.rs new file mode 100644 index 00000000000..633df661be0 --- /dev/null +++ b/src/test/rustdoc/doc-cfg-simplification.rs @@ -0,0 +1,182 @@ +#![crate_name = "globuliferous"] +#![feature(doc_cfg)] + +// @has 'globuliferous/index.html' +// @count - '//*[@class="stab portability"]' 1 +// @matches - '//*[@class="stab portability"]' '^ratel$' + +// @has 'globuliferous/ratel/index.html' +// @count - '//*[@class="stab portability"]' 8 +// @matches - '//*[@class="stab portability"]' 'crate feature ratel' +// @matches - '//*[@class="stab portability"]' '^zoonosology$' +// @matches - '//*[@class="stab portability"]' '^yusho$' +// @matches - '//*[@class="stab portability"]' '^nunciative$' +// @matches - '//*[@class="stab portability"]' '^thionic$' +// @matches - '//*[@class="stab portability"]' '^zincic$' +// @matches - '//*[@class="stab portability"]' '^cosmotellurian$' +// @matches - '//*[@class="stab portability"]' '^aposiopesis$' +#[doc(cfg(feature = "ratel"))] +pub mod ratel { + // @has 'globuliferous/ratel/fn.ovicide.html' + // @count - '//*[@class="stab portability"]' 1 + // @matches - '//*[@class="stab portability"]' 'crate feature ratel' + pub fn ovicide() {} + + // @has 'globuliferous/ratel/fn.zoonosology.html' + // @count - '//*[@class="stab portability"]' 1 + // @matches - '//*[@class="stab portability"]' 'crate features ratel and zoonosology' + #[doc(cfg(feature = "zoonosology"))] + pub fn zoonosology() {} + + // @has 'globuliferous/ratel/constant.DIAGRAPHICS.html' + // @count - '//*[@class="stab portability"]' 1 + // @matches - '//*[@class="stab portability"]' 'crate feature ratel' + pub const DIAGRAPHICS: () = (); + + // @has 'globuliferous/ratel/constant.YUSHO.html' + // @count - '//*[@class="stab portability"]' 1 + // @matches - '//*[@class="stab portability"]' 'crate features ratel and yusho' + #[doc(cfg(feature = "yusho"))] + pub const YUSHO: () = (); + + // @has 'globuliferous/ratel/static.KEYBUGLE.html' + // @count - '//*[@class="stab portability"]' 1 + // @matches - '//*[@class="stab portability"]' 'crate feature ratel' + pub static KEYBUGLE: () = (); + + // @has 'globuliferous/ratel/static.NUNCIATIVE.html' + // @count - '//*[@class="stab portability"]' 1 + // @matches - '//*[@class="stab portability"]' 'crate features ratel and nunciative' + #[doc(cfg(feature = "nunciative"))] + pub static NUNCIATIVE: () = (); + + // @has 'globuliferous/ratel/type.Wrick.html' + // @count - '//*[@class="stab portability"]' 1 + // @matches - '//*[@class="stab portability"]' 'crate feature ratel' + pub type Wrick = (); + + // @has 'globuliferous/ratel/type.Thionic.html' + // @count - '//*[@class="stab portability"]' 1 + // @matches - '//*[@class="stab portability"]' 'crate features ratel and thionic' + #[doc(cfg(feature = "thionic"))] + pub type Thionic = (); + + // @has 'globuliferous/ratel/struct.Eventration.html' + // @count - '//*[@class="stab portability"]' 1 + // @matches - '//*[@class="stab portability"]' 'crate feature ratel' + pub struct Eventration; + + // @has 'globuliferous/ratel/struct.Zincic.html' + // @count - '//*[@class="stab portability"]' 2 + // @matches - '//*[@class="stab portability"]' 'crate features ratel and zincic' + // @matches - '//*[@class="stab portability"]' 'crate feature rutherford' + #[doc(cfg(feature = "zincic"))] + pub struct Zincic { + pub rectigrade: (), + + #[doc(cfg(feature = "rutherford"))] + pub rutherford: (), + } + + // @has 'globuliferous/ratel/enum.Cosmotellurian.html' + // @count - '//*[@class="stab portability"]' 10 + // @matches - '//*[@class="stab portability"]' 'crate features ratel and cosmotellurian' + // @matches - '//*[@class="stab portability"]' 'crate feature biotaxy' + // @matches - '//*[@class="stab portability"]' 'crate feature xiphopagus' + // @matches - '//*[@class="stab portability"]' 'crate feature juxtapositive' + // @matches - '//*[@class="stab portability"]' 'crate feature fuero' + // @matches - '//*[@class="stab portability"]' 'crate feature palaeophile' + // @matches - '//*[@class="stab portability"]' 'crate feature broadcloth' + // @matches - '//*[@class="stab portability"]' 'crate features broadcloth and xanthocomic' + // @matches - '//*[@class="stab portability"]' 'crate feature broadcloth' + // @matches - '//*[@class="stab portability"]' 'crate features broadcloth and whosoever' + #[doc(cfg(feature = "cosmotellurian"))] + pub enum Cosmotellurian { + Groundsel { + jagger: (), + + #[doc(cfg(feature = "xiphopagus"))] + xiphopagus: (), + }, + + #[doc(cfg(feature = "biotaxy"))] + Biotaxy { + glossography: (), + + #[doc(cfg(feature = "juxtapositive"))] + juxtapositive: (), + }, + } + + impl Cosmotellurian { + pub fn uxoricide() {} + + #[doc(cfg(feature = "fuero"))] + pub fn fuero() {} + + pub const MAMELLE: () = (); + + #[doc(cfg(feature = "palaeophile"))] + pub const PALAEOPHILE: () = (); + } + + #[doc(cfg(feature = "broadcloth"))] + impl Cosmotellurian { + pub fn trabeculated() {} + + #[doc(cfg(feature = "xanthocomic"))] + pub fn xanthocomic() {} + + pub const BRACHIFEROUS: () = (); + + #[doc(cfg(feature = "whosoever"))] + pub const WHOSOEVER: () = (); + } + + // @has 'globuliferous/ratel/trait.Gnotobiology.html' + // @count - '//*[@class="stab portability"]' 4 + // @matches - '//*[@class="stab portability"]' 'crate feature ratel' + // @matches - '//*[@class="stab portability"]' 'crate feature unzymotic' + // @matches - '//*[@class="stab portability"]' 'crate feature summate' + // @matches - '//*[@class="stab portability"]' 'crate feature unctuous' + pub trait Gnotobiology { + const XYLOTHERAPY: (); + + #[doc(cfg(feature = "unzymotic"))] + const UNZYMOTIC: (); + + type Lepadoid; + + #[doc(cfg(feature = "summate"))] + type Summate; + + fn decalcomania(); + + #[doc(cfg(feature = "unctuous"))] + fn unctuous(); + } + + // @has 'globuliferous/ratel/trait.Aposiopesis.html' + // @count - '//*[@class="stab portability"]' 4 + // @matches - '//*[@class="stab portability"]' 'crate features ratel and aposiopesis' + // @matches - '//*[@class="stab portability"]' 'crate feature umbracious' + // @matches - '//*[@class="stab portability"]' 'crate feature uakari' + // @matches - '//*[@class="stab portability"]' 'crate feature rotograph' + #[doc(cfg(feature = "aposiopesis"))] + pub trait Aposiopesis { + const REDHIBITION: (); + + #[doc(cfg(feature = "umbracious"))] + const UMBRACIOUS: (); + + type Ophthalmoscope; + + #[doc(cfg(feature = "uakari"))] + type Uakari; + + fn meseems(); + + #[doc(cfg(feature = "rotograph"))] + fn rotograph(); + } +} diff --git a/src/test/rustdoc/doc-cfg.rs b/src/test/rustdoc/doc-cfg.rs index aa407b7e926..d7041ee2f1a 100644 --- a/src/test/rustdoc/doc-cfg.rs +++ b/src/test/rustdoc/doc-cfg.rs @@ -10,9 +10,8 @@ pub struct Portable; // @has doc_cfg/unix_only/index.html \ // '//*[@id="main"]/*[@class="stability"]/*[@class="stab portability"]' \ // 'This is supported on Unix only.' -// @matches - '//*[@class="module-item"]//*[@class="stab portability"]' '\AUnix\Z' -// @matches - '//*[@class="module-item"]//*[@class="stab portability"]' '\AUnix and ARM\Z' -// @count - '//*[@class="stab portability"]' 3 +// @matches - '//*[@class="module-item"]//*[@class="stab portability"]' '\AARM\Z' +// @count - '//*[@class="stab portability"]' 2 #[doc(cfg(unix))] pub mod unix_only { // @has doc_cfg/unix_only/fn.unix_only_function.html \ @@ -26,7 +25,7 @@ pub mod unix_only { // @has doc_cfg/unix_only/trait.ArmOnly.html \ // '//*[@id="main"]/*[@class="stability"]/*[@class="stab portability"]' \ // 'This is supported on Unix and ARM only.' - // @count - '//*[@class="stab portability"]' 3 + // @count - '//*[@class="stab portability"]' 2 #[doc(cfg(target_arch = "arm"))] pub trait ArmOnly { fn unix_and_arm_only_function(); diff --git a/src/test/rustdoc/duplicate-cfg.rs b/src/test/rustdoc/duplicate-cfg.rs index 47ba362c977..7b938af3c7d 100644 --- a/src/test/rustdoc/duplicate-cfg.rs +++ b/src/test/rustdoc/duplicate-cfg.rs @@ -14,45 +14,41 @@ pub struct Foo; // @has 'foo/bar/index.html' -// @matches '-' '//*[@class="module-item"]//*[@class="stab portability"]' '^sync$' -// @has '-' '//*[@class="module-item"]//*[@class="stab portability"]/@title' 'This is supported on crate feature `sync` only' - -// @has 'foo/bar/struct.Bar.html' // @has '-' '//*[@class="stab portability"]' 'This is supported on crate feature sync only.' #[doc(cfg(feature = "sync"))] pub mod bar { + // @has 'foo/bar/struct.Bar.html' + // @has '-' '//*[@class="stab portability"]' 'This is supported on crate feature sync only.' #[doc(cfg(feature = "sync"))] pub struct Bar; } // @has 'foo/baz/index.html' -// @matches '-' '//*[@class="module-item"]//*[@class="stab portability"]' '^sync and send$' -// @has '-' '//*[@class="module-item"]//*[@class="stab portability"]/@title' 'This is supported on crate features `sync` and `send` only' - -// @has 'foo/baz/struct.Baz.html' // @has '-' '//*[@class="stab portability"]' 'This is supported on crate features sync and send only.' #[doc(cfg(all(feature = "sync", feature = "send")))] pub mod baz { + // @has 'foo/baz/struct.Baz.html' + // @has '-' '//*[@class="stab portability"]' 'This is supported on crate features sync and send only.' #[doc(cfg(feature = "sync"))] pub struct Baz; } -// @has 'foo/qux/struct.Qux.html' -// @has '-' '//*[@class="stab portability"]' 'This is supported on crate features sync and send only.' +// @has 'foo/qux/index.html' +// @has '-' '//*[@class="stab portability"]' 'This is supported on crate feature sync only.' #[doc(cfg(feature = "sync"))] pub mod qux { + // @has 'foo/qux/struct.Qux.html' + // @has '-' '//*[@class="stab portability"]' 'This is supported on crate features sync and send only.' #[doc(cfg(all(feature = "sync", feature = "send")))] pub struct Qux; } // @has 'foo/quux/index.html' -// @matches '-' '//*[@class="module-item"]//*[@class="stab portability"]' '^sync and send and foo and bar$' -// @has '-' '//*[@class="module-item"]//*[@class="stab portability"]/@title' 'This is supported on crate feature `sync` and crate feature `send` and `foo` and `bar` only' - -// @has 'foo/quux/struct.Quux.html' -// @has '-' '//*[@class="stab portability"]' 'This is supported on crate feature sync and crate feature send and foo and bar only.' +// @has '-' '//*[@class="stab portability"]' 'This is supported on crate feature sync and crate feature send and foo only.' #[doc(cfg(all(feature = "sync", feature = "send", foo)))] pub mod quux { + // @has 'foo/quux/struct.Quux.html' + // @has '-' '//*[@class="stab portability"]' 'This is supported on crate feature sync and crate feature send and foo and bar only.' #[doc(cfg(all(feature = "send", feature = "sync", bar)))] pub struct Quux; } diff --git a/src/test/rustdoc/intra-link-reexport-additional-docs.rs b/src/test/rustdoc/intra-link-reexport-additional-docs.rs index adb072a7ed5..96f3580f305 100644 --- a/src/test/rustdoc/intra-link-reexport-additional-docs.rs +++ b/src/test/rustdoc/intra-link-reexport-additional-docs.rs @@ -1,6 +1,9 @@ +// aux-build:intra-link-reexport-additional-docs.rs +// build-aux-docs #![crate_name = "foo"] +extern crate inner; -// @has foo/struct.JoinPathsError.html '//a[@href="../foo/fn.with_code.html"]' 'crate::with_code' +// @has foo/struct.Inner.html '//a[@href="../foo/fn.with_code.html"]' 'crate::with_code' /// [crate::with_code] // @has - '//a[@href="../foo/fn.with_code.html"]' 'different text' /// [different text][with_code] @@ -11,7 +14,9 @@ #[doc = "has an attr in the way"] /// /// [reference link]: me_three -pub use std::env::JoinPathsError; +// Should still resolve links from the original module in that scope +// @has - '//a[@href="../inner/fn.f.html"]' 'f()' +pub use inner::Inner; pub fn with_code() {} pub fn me_too() {} diff --git a/src/test/rustdoc/no-compiler-reexport.rs b/src/test/rustdoc/no-compiler-reexport.rs new file mode 100644 index 00000000000..6d50325fed5 --- /dev/null +++ b/src/test/rustdoc/no-compiler-reexport.rs @@ -0,0 +1,7 @@ +// compile-flags: --no-defaults + +#![crate_name = "foo"] + +// @has 'foo/index.html' '//code' 'extern crate std;' +// @!has 'foo/index.html' '//code' 'use std::prelude::v1::*;' +pub struct Foo; diff --git a/src/test/rustdoc/reexport-check.rs b/src/test/rustdoc/reexport-check.rs index dea72b81a57..066b0cfe5e8 100644 --- a/src/test/rustdoc/reexport-check.rs +++ b/src/test/rustdoc/reexport-check.rs @@ -1,5 +1,8 @@ +// aux-build:reexport-check.rs #![crate_name = "foo"] +extern crate reexport_check; + // @!has 'foo/index.html' '//code' 'pub use self::i32;' // @has 'foo/index.html' '//tr[@class="module-item"]' 'i32' // @has 'foo/i32/index.html' @@ -7,3 +10,8 @@ pub use std::i32; // @!has 'foo/index.html' '//code' 'pub use self::string::String;' // @has 'foo/index.html' '//tr[@class="module-item"]' 'String' pub use std::string::String; + +// @has 'foo/index.html' '//td[@class="docblock-short"]' 'Docs in original' +// this is a no-op, but shows what happens if there's an attribute that isn't a doc-comment +#[doc(inline)] +pub use reexport_check::S; diff --git a/src/test/ui/arg-count-mismatch.stderr b/src/test/ui/arg-count-mismatch.stderr index 7bc06134a69..d0577e4864a 100644 --- a/src/test/ui/arg-count-mismatch.stderr +++ b/src/test/ui/arg-count-mismatch.stderr @@ -1,13 +1,16 @@ error[E0061]: this function takes 1 argument but 0 arguments were supplied --> $DIR/arg-count-mismatch.rs:5:28 | -LL | fn f(x: isize) { } - | -------------- defined here -LL | LL | fn main() { let i: (); i = f(); } | ^-- supplied 0 arguments | | | expected 1 argument + | +note: function defined here + --> $DIR/arg-count-mismatch.rs:3:4 + | +LL | fn f(x: isize) { } + | ^ -------- error: aborting due to previous error diff --git a/src/test/ui/array-slice-vec/match_arr_unknown_len.stderr b/src/test/ui/array-slice-vec/match_arr_unknown_len.stderr index 0ad05b3adeb..7c1a92c79d9 100644 --- a/src/test/ui/array-slice-vec/match_arr_unknown_len.stderr +++ b/src/test/ui/array-slice-vec/match_arr_unknown_len.stderr @@ -6,6 +6,7 @@ LL | #![feature(const_generics)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information + = help: consider using `min_const_generics` instead, which is more stable and complete error[E0308]: mismatched types --> $DIR/match_arr_unknown_len.rs:6:9 diff --git a/src/test/ui/associated-type-bounds/issue-70292.rs b/src/test/ui/associated-type-bounds/issue-70292.rs new file mode 100644 index 00000000000..945d7688ce6 --- /dev/null +++ b/src/test/ui/associated-type-bounds/issue-70292.rs @@ -0,0 +1,21 @@ +// check-pass + +#![feature(associated_type_bounds)] + +fn foo<F>(_: F) +where + F: for<'a> Trait<Output: 'a>, +{ +} + +trait Trait { + type Output; +} + +impl<T> Trait for T { + type Output = (); +} + +fn main() { + foo(()); +} diff --git a/src/test/ui/associated-type-bounds/issue-71443-1.rs b/src/test/ui/associated-type-bounds/issue-71443-1.rs new file mode 100644 index 00000000000..5d2a3e6cbad --- /dev/null +++ b/src/test/ui/associated-type-bounds/issue-71443-1.rs @@ -0,0 +1,9 @@ +#![feature(associated_type_bounds)] + +struct Incorrect; + +fn hello<F: for<'a> Iterator<Item: 'a>>() { + Incorrect //~ERROR: mismatched types +} + +fn main() {} diff --git a/src/test/ui/associated-type-bounds/issue-71443-1.stderr b/src/test/ui/associated-type-bounds/issue-71443-1.stderr new file mode 100644 index 00000000000..a9459ee7432 --- /dev/null +++ b/src/test/ui/associated-type-bounds/issue-71443-1.stderr @@ -0,0 +1,11 @@ +error[E0308]: mismatched types + --> $DIR/issue-71443-1.rs:6:5 + | +LL | fn hello<F: for<'a> Iterator<Item: 'a>>() { + | - help: try adding a return type: `-> Incorrect` +LL | Incorrect + | ^^^^^^^^^ expected `()`, found struct `Incorrect` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/associated-type-bounds/issue-71443-2.rs b/src/test/ui/associated-type-bounds/issue-71443-2.rs new file mode 100644 index 00000000000..813dcd60ad1 --- /dev/null +++ b/src/test/ui/associated-type-bounds/issue-71443-2.rs @@ -0,0 +1,11 @@ +// check-pass + +#![feature(associated_type_bounds)] + +fn hello<'b, F>() +where + for<'a> F: Iterator<Item: 'a> + 'b, +{ +} + +fn main() {} diff --git a/src/test/ui/associated-types/associated-types-path-2.stderr b/src/test/ui/associated-types/associated-types-path-2.stderr index b2599410f05..0881258aca1 100644 --- a/src/test/ui/associated-types/associated-types-path-2.stderr +++ b/src/test/ui/associated-types/associated-types-path-2.stderr @@ -47,7 +47,7 @@ LL | let _: i32 = f2(2i32); | | | expected due to this | -help: you can convert an `u32` to `i32` and panic if the converted value wouldn't fit +help: you can convert a `u32` to an `i32` and panic if the converted value doesn't fit | LL | let _: i32 = f2(2i32).try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/associated-types/defaults-specialization.stderr b/src/test/ui/associated-types/defaults-specialization.stderr index 09a8c8f8a88..920f8322813 100644 --- a/src/test/ui/associated-types/defaults-specialization.stderr +++ b/src/test/ui/associated-types/defaults-specialization.stderr @@ -6,6 +6,7 @@ LL | #![feature(associated_type_defaults, specialization)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete error[E0053]: method `make` has an incompatible type for trait --> $DIR/defaults-specialization.rs:19:18 diff --git a/src/test/ui/associated-types/issue-54108.rs b/src/test/ui/associated-types/issue-54108.rs new file mode 100644 index 00000000000..87f67ce4b52 --- /dev/null +++ b/src/test/ui/associated-types/issue-54108.rs @@ -0,0 +1,41 @@ +use std::ops::Add; + +pub trait Encoder { + type Size: Add<Output = Self::Size>; + + fn foo(&self) -> Self::Size; +} + +pub trait SubEncoder: Encoder { + type ActualSize; + + fn bar(&self) -> Self::Size; +} + +impl<T> Encoder for T +where + T: SubEncoder, +{ + type Size = <Self as SubEncoder>::ActualSize; + //~^ ERROR: cannot add `<T as SubEncoder>::ActualSize` to `<T as SubEncoder>::ActualSize` + + fn foo(&self) -> Self::Size { + self.bar() + self.bar() + } +} + +pub struct UnitEncoder; + +impl SubEncoder for UnitEncoder { + type ActualSize = (); + + fn bar(&self) {} +} + +pub fn fun<R: Encoder>(encoder: &R) { + encoder.foo(); +} + +fn main() { + fun(&UnitEncoder {}); +} diff --git a/src/test/ui/associated-types/issue-54108.stderr b/src/test/ui/associated-types/issue-54108.stderr new file mode 100644 index 00000000000..927a2de9965 --- /dev/null +++ b/src/test/ui/associated-types/issue-54108.stderr @@ -0,0 +1,18 @@ +error[E0277]: cannot add `<T as SubEncoder>::ActualSize` to `<T as SubEncoder>::ActualSize` + --> $DIR/issue-54108.rs:19:5 + | +LL | type Size: Add<Output = Self::Size>; + | ------------------------ required by this bound in `Encoder::Size` +... +LL | type Size = <Self as SubEncoder>::ActualSize; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `<T as SubEncoder>::ActualSize + <T as SubEncoder>::ActualSize` + | + = help: the trait `Add` is not implemented for `<T as SubEncoder>::ActualSize` +help: consider further restricting the associated type + | +LL | T: SubEncoder, <T as SubEncoder>::ActualSize: Add + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/associated-types/issue-65934.rs b/src/test/ui/associated-types/issue-65934.rs new file mode 100644 index 00000000000..e17b11c5eae --- /dev/null +++ b/src/test/ui/associated-types/issue-65934.rs @@ -0,0 +1,17 @@ +// check-pass + +trait Trait { + type Assoc; +} + +impl Trait for () { + type Assoc = (); +} + +fn unit() -> impl Into<<() as Trait>::Assoc> {} + +pub fn ice() { + Into::into(unit()); +} + +fn main() {} diff --git a/src/test/ui/binding/const-param.stderr b/src/test/ui/binding/const-param.stderr index 316fac62325..d3d06a2d834 100644 --- a/src/test/ui/binding/const-param.stderr +++ b/src/test/ui/binding/const-param.stderr @@ -6,6 +6,7 @@ LL | #![feature(const_generics)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information + = help: consider using `min_const_generics` instead, which is more stable and complete error[E0158]: const parameters cannot be referenced in patterns --> $DIR/const-param.rs:7:9 diff --git a/src/test/ui/borrowck/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs b/src/test/ui/borrowck/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs index b67d494866b..97f96ab6929 100644 --- a/src/test/ui/borrowck/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs +++ b/src/test/ui/borrowck/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs @@ -3,8 +3,6 @@ #![feature(or_patterns)] #![feature(box_patterns)] -#![feature(move_ref_pattern)] - enum Test { Foo, Bar, diff --git a/src/test/ui/borrowck/bindings-after-at-or-patterns-slice-patterns-box-patterns.stderr b/src/test/ui/borrowck/bindings-after-at-or-patterns-slice-patterns-box-patterns.stderr index 1bf81589275..96e313b39ed 100644 --- a/src/test/ui/borrowck/bindings-after-at-or-patterns-slice-patterns-box-patterns.stderr +++ b/src/test/ui/borrowck/bindings-after-at-or-patterns-slice-patterns-box-patterns.stderr @@ -1,5 +1,5 @@ error: cannot borrow value as mutable because it is also borrowed as immutable - --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:40:9 + --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:38:9 | LL | ref foo @ [.., ref mut bar] => (), | -------^^^^^^^^-----------^ @@ -8,7 +8,7 @@ LL | ref foo @ [.., ref mut bar] => (), | immutable borrow, by `foo`, occurs here error: cannot borrow value as mutable because it is also borrowed as immutable - --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:124:9 + --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:122:9 | LL | ref foo @ Some(box ref mut s) => (), | -------^^^^^^^^^^^^---------^ @@ -17,7 +17,7 @@ LL | ref foo @ Some(box ref mut s) => (), | immutable borrow, by `foo`, occurs here error[E0382]: borrow of moved value: `x` - --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:22:5 + --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:20:5 | LL | fn bindings_after_at_slice_patterns_move_binding(x: [String; 4]) { | - move occurs because `x` has type `[String; 4]`, which does not implement the `Copy` trait @@ -29,7 +29,7 @@ LL | &x; | ^^ value borrowed here after move error[E0502]: cannot borrow `x` as immutable because it is also borrowed as mutable - --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:32:5 + --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:30:5 | LL | ref mut foo @ [.., _] => Some(foo), | --------------------- mutable borrow occurs here @@ -41,7 +41,7 @@ LL | drop(r); | - mutable borrow later used here error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable - --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:54:5 + --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:52:5 | LL | [ref foo @ .., ref bar] => Some(foo), | ------------ immutable borrow occurs here @@ -53,7 +53,7 @@ LL | drop(r); | - immutable borrow later used here error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable - --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:66:5 + --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:64:5 | LL | ref foo @ [.., ref bar] => Some(foo), | ----------------------- immutable borrow occurs here @@ -65,7 +65,7 @@ LL | drop(r); | - immutable borrow later used here error[E0382]: borrow of moved value: `x` - --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:80:5 + --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:78:5 | LL | fn bindings_after_at_or_patterns_move(x: Option<Test>) { | - move occurs because `x` has type `Option<Test>`, which does not implement the `Copy` trait @@ -80,7 +80,7 @@ LL | &x; | ^^ value borrowed here after move error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable - --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:90:5 + --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:88:5 | LL | ref foo @ Some(Test::Foo | Test::Bar) => Some(foo), | ------------------------------------- immutable borrow occurs here @@ -92,7 +92,7 @@ LL | drop(r); | - immutable borrow later used here error[E0502]: cannot borrow `x` as immutable because it is also borrowed as mutable - --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:102:5 + --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:100:5 | LL | ref mut foo @ Some(Test::Foo | Test::Bar) => Some(foo), | ----------------------------------------- mutable borrow occurs here @@ -104,7 +104,7 @@ LL | drop(r); | - mutable borrow later used here error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable - --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:116:5 + --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:114:5 | LL | ref foo @ Some(box ref s) => Some(foo), | ------------------------- immutable borrow occurs here @@ -116,7 +116,7 @@ LL | drop(r); | - immutable borrow later used here error[E0382]: borrow of moved value: `x` - --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:138:5 + --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:136:5 | LL | fn bindings_after_at_slice_patterns_or_patterns_moves(x: [Option<Test>; 4]) { | - move occurs because `x` has type `[Option<Test>; 4]`, which does not implement the `Copy` trait @@ -131,7 +131,7 @@ LL | &x; | ^^ value borrowed here after move error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable - --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:148:5 + --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:146:5 | LL | ref a @ [ref b @ .., Some(Test::Foo | Test::Bar)] => Some(a), | ------------------------------------------------- immutable borrow occurs here @@ -143,7 +143,7 @@ LL | drop(r); | - immutable borrow later used here error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable - --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:160:5 + --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:158:5 | LL | ref a @ [ref b @ .., Some(Test::Foo | Test::Bar)] => Some(b), | ---------- immutable borrow occurs here @@ -155,7 +155,7 @@ LL | drop(r); | - immutable borrow later used here error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable - --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:174:5 + --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:172:5 | LL | [_, ref a @ Some(box ref b), ..] => Some(a), | ----------------------- immutable borrow occurs here @@ -167,7 +167,7 @@ LL | drop(r); | - immutable borrow later used here error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable - --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:190:5 + --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:188:5 | LL | [_, ref a @ Some(box Test::Foo | box Test::Bar), ..] => Some(a), | ------------------------------------------- immutable borrow occurs here @@ -179,7 +179,7 @@ LL | drop(r); | - immutable borrow later used here error[E0502]: cannot borrow `x` as immutable because it is also borrowed as mutable - --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:204:5 + --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:202:5 | LL | [_, ref mut a @ Some(box Test::Foo | box Test::Bar), ..] => Some(a), | ----------------------------------------------- mutable borrow occurs here @@ -191,7 +191,7 @@ LL | drop(r); | - mutable borrow later used here error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable - --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:218:5 + --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:216:5 | LL | ref a @ [_, ref b @ Some(box Test::Foo | box Test::Bar), ..] => Some(a), | ------------------------------------------------------------ immutable borrow occurs here diff --git a/src/test/ui/c-variadic/variadic-ffi-1.stderr b/src/test/ui/c-variadic/variadic-ffi-1.stderr index 89ea65fd43f..6f2a6c359b5 100644 --- a/src/test/ui/c-variadic/variadic-ffi-1.stderr +++ b/src/test/ui/c-variadic/variadic-ffi-1.stderr @@ -7,24 +7,30 @@ LL | fn printf(_: *const u8, ...); error[E0060]: this function takes at least 2 arguments but 0 arguments were supplied --> $DIR/variadic-ffi-1.rs:17:9 | -LL | fn foo(f: isize, x: u8, ...); - | ----------------------------- defined here -... LL | foo(); | ^^^-- supplied 0 arguments | | | expected at least 2 arguments + | +note: function defined here + --> $DIR/variadic-ffi-1.rs:10:8 + | +LL | fn foo(f: isize, x: u8, ...); + | ^^^ error[E0060]: this function takes at least 2 arguments but 1 argument was supplied --> $DIR/variadic-ffi-1.rs:18:9 | -LL | fn foo(f: isize, x: u8, ...); - | ----------------------------- defined here -... LL | foo(1); | ^^^ - supplied 1 argument | | | expected at least 2 arguments + | +note: function defined here + --> $DIR/variadic-ffi-1.rs:10:8 + | +LL | fn foo(f: isize, x: u8, ...); + | ^^^ error[E0308]: mismatched types --> $DIR/variadic-ffi-1.rs:20:56 diff --git a/src/test/ui/c-variadic/variadic-ffi-no-fixed-args.stderr b/src/test/ui/c-variadic/variadic-ffi-no-fixed-args.stderr index 7af38c88f43..e11ba43ca2a 100644 --- a/src/test/ui/c-variadic/variadic-ffi-no-fixed-args.stderr +++ b/src/test/ui/c-variadic/variadic-ffi-no-fixed-args.stderr @@ -2,7 +2,7 @@ error: C-variadic function must be declared with at least one named argument --> $DIR/variadic-ffi-no-fixed-args.rs:2:12 | LL | fn foo(...); - | ^^^^ + | ^^^ error: aborting due to previous error diff --git a/src/test/ui/check-doc-alias-attr.rs b/src/test/ui/check-doc-alias-attr.rs index c8bec39fad6..0ca2349a43b 100644 --- a/src/test/ui/check-doc-alias-attr.rs +++ b/src/test/ui/check-doc-alias-attr.rs @@ -11,6 +11,7 @@ pub struct Bar; #[doc(alias = "\n")] //~ ERROR #[doc(alias = " ")] //~^ ERROR -#[doc(alias = " ")] //~ ERROR #[doc(alias = "\t")] //~ ERROR +#[doc(alias = " hello")] //~ ERROR +#[doc(alias = "hello ")] //~ ERROR pub struct Foo; diff --git a/src/test/ui/check-doc-alias-attr.stderr b/src/test/ui/check-doc-alias-attr.stderr index be7d7b3dbea..2c417a3bb65 100644 --- a/src/test/ui/check-doc-alias-attr.stderr +++ b/src/test/ui/check-doc-alias-attr.stderr @@ -36,17 +36,23 @@ LL | #[doc(alias = " LL | | ")] | |_^ -error: ' ' character isn't allowed in `#[doc(alias = "...")]` +error: '\t' character isn't allowed in `#[doc(alias = "...")]` --> $DIR/check-doc-alias-attr.rs:14:7 | -LL | #[doc(alias = " ")] - | ^^^^^^^^^^^ +LL | #[doc(alias = "\t")] + | ^^^^^^^^^^^^ -error: '\t' character isn't allowed in `#[doc(alias = "...")]` +error: `#[doc(alias = "...")]` cannot start or end with ' ' --> $DIR/check-doc-alias-attr.rs:15:7 | -LL | #[doc(alias = "\t")] - | ^^^^^^^^^^^^ +LL | #[doc(alias = " hello")] + | ^^^^^^^^^^^^^^^^ + +error: `#[doc(alias = "...")]` cannot start or end with ' ' + --> $DIR/check-doc-alias-attr.rs:16:7 + | +LL | #[doc(alias = "hello ")] + | ^^^^^^^^^^^^^^^^ -error: aborting due to 8 previous errors +error: aborting due to 9 previous errors diff --git a/src/test/ui/coherence/coherence-all-remote.stderr b/src/test/ui/coherence/coherence-all-remote.stderr index 6ecfb2c5eb0..7eca4175339 100644 --- a/src/test/ui/coherence/coherence-all-remote.stderr +++ b/src/test/ui/coherence/coherence-all-remote.stderr @@ -4,7 +4,7 @@ error[E0210]: type parameter `T` must be used as the type parameter for some loc LL | impl<T> Remote1<T> for isize { } | ^ type parameter `T` must be used as the type parameter for some local type | - = note: implementing a foreign trait is only possible if at least one of the types for which is it implemented is local + = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local = note: only traits defined in the current crate can be implemented for a type parameter error: aborting due to previous error diff --git a/src/test/ui/coherence/coherence-bigint-param.stderr b/src/test/ui/coherence/coherence-bigint-param.stderr index d431c5f4b52..e8d74c917e4 100644 --- a/src/test/ui/coherence/coherence-bigint-param.stderr +++ b/src/test/ui/coherence/coherence-bigint-param.stderr @@ -4,7 +4,7 @@ error[E0210]: type parameter `T` must be covered by another type when it appears LL | impl<T> Remote1<BigInt> for T { } | ^ type parameter `T` must be covered by another type when it appears before the first local type (`BigInt`) | - = note: implementing a foreign trait is only possible if at least one of the types for which is it implemented is local, and no uncovered type parameters appear before that first local type + = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local, and no uncovered type parameters appear before that first local type = note: in this case, 'before' refers to the following order: `impl<..> ForeignTrait<T1, ..., Tn> for T0`, where `T0` is the first and `Tn` is the last error: aborting due to previous error diff --git a/src/test/ui/coherence/coherence-cross-crate-conflict.stderr b/src/test/ui/coherence/coherence-cross-crate-conflict.stderr index 5381053979f..827d26ab434 100644 --- a/src/test/ui/coherence/coherence-cross-crate-conflict.stderr +++ b/src/test/ui/coherence/coherence-cross-crate-conflict.stderr @@ -13,7 +13,7 @@ error[E0210]: type parameter `A` must be used as the type parameter for some loc LL | impl<A> Foo for A { | ^ type parameter `A` must be used as the type parameter for some local type | - = note: implementing a foreign trait is only possible if at least one of the types for which is it implemented is local + = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local = note: only traits defined in the current crate can be implemented for a type parameter error: aborting due to 2 previous errors diff --git a/src/test/ui/coherence/coherence-inherited-assoc-ty-cycle-err.stderr b/src/test/ui/coherence/coherence-inherited-assoc-ty-cycle-err.stderr index 7e140480b77..f3edf1c350f 100644 --- a/src/test/ui/coherence/coherence-inherited-assoc-ty-cycle-err.stderr +++ b/src/test/ui/coherence/coherence-inherited-assoc-ty-cycle-err.stderr @@ -6,6 +6,7 @@ LL | #![feature(specialization)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete error[E0391]: cycle detected when building specialization graph of trait `Trait` --> $DIR/coherence-inherited-assoc-ty-cycle-err.rs:9:1 diff --git a/src/test/ui/coherence/coherence-lone-type-parameter.stderr b/src/test/ui/coherence/coherence-lone-type-parameter.stderr index 2c3b4fc3ad2..ef5b0883653 100644 --- a/src/test/ui/coherence/coherence-lone-type-parameter.stderr +++ b/src/test/ui/coherence/coherence-lone-type-parameter.stderr @@ -4,7 +4,7 @@ error[E0210]: type parameter `T` must be used as the type parameter for some loc LL | impl<T> Remote for T { } | ^ type parameter `T` must be used as the type parameter for some local type | - = note: implementing a foreign trait is only possible if at least one of the types for which is it implemented is local + = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local = note: only traits defined in the current crate can be implemented for a type parameter error: aborting due to previous error diff --git a/src/test/ui/coherence/impl[t]-foreign-for-fundamental[t].stderr b/src/test/ui/coherence/impl[t]-foreign-for-fundamental[t].stderr index 8a951d407ca..249a5c44c79 100644 --- a/src/test/ui/coherence/impl[t]-foreign-for-fundamental[t].stderr +++ b/src/test/ui/coherence/impl[t]-foreign-for-fundamental[t].stderr @@ -4,7 +4,7 @@ error[E0210]: type parameter `T` must be used as the type parameter for some loc LL | impl<T> Remote for Box<T> { | ^ type parameter `T` must be used as the type parameter for some local type | - = note: implementing a foreign trait is only possible if at least one of the types for which is it implemented is local + = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local = note: only traits defined in the current crate can be implemented for a type parameter error: aborting due to previous error diff --git a/src/test/ui/coherence/impl[t]-foreign[foreign]-for-fundamental[t].stderr b/src/test/ui/coherence/impl[t]-foreign[foreign]-for-fundamental[t].stderr index c5759244eff..95a20cc5b0f 100644 --- a/src/test/ui/coherence/impl[t]-foreign[foreign]-for-fundamental[t].stderr +++ b/src/test/ui/coherence/impl[t]-foreign[foreign]-for-fundamental[t].stderr @@ -4,7 +4,7 @@ error[E0210]: type parameter `T` must be used as the type parameter for some loc LL | impl<T> Remote1<u32> for Box<T> { | ^ type parameter `T` must be used as the type parameter for some local type | - = note: implementing a foreign trait is only possible if at least one of the types for which is it implemented is local + = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local = note: only traits defined in the current crate can be implemented for a type parameter error[E0210]: type parameter `T` must be used as the type parameter for some local type (e.g., `MyStruct<T>`) @@ -13,7 +13,7 @@ error[E0210]: type parameter `T` must be used as the type parameter for some loc LL | impl<'a, T> Remote1<u32> for &'a T { | ^ type parameter `T` must be used as the type parameter for some local type | - = note: implementing a foreign trait is only possible if at least one of the types for which is it implemented is local + = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local = note: only traits defined in the current crate can be implemented for a type parameter error: aborting due to 2 previous errors diff --git a/src/test/ui/coherence/impl[t]-foreign[foreign]-for-t.stderr b/src/test/ui/coherence/impl[t]-foreign[foreign]-for-t.stderr index e8663fd7d82..aed184767a0 100644 --- a/src/test/ui/coherence/impl[t]-foreign[foreign]-for-t.stderr +++ b/src/test/ui/coherence/impl[t]-foreign[foreign]-for-t.stderr @@ -4,7 +4,7 @@ error[E0210]: type parameter `T` must be used as the type parameter for some loc LL | impl<T> Remote1<u32> for T { | ^ type parameter `T` must be used as the type parameter for some local type | - = note: implementing a foreign trait is only possible if at least one of the types for which is it implemented is local + = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local = note: only traits defined in the current crate can be implemented for a type parameter error: aborting due to previous error diff --git a/src/test/ui/coherence/impl[t]-foreign[fundamental[t]]-for-foreign.stderr b/src/test/ui/coherence/impl[t]-foreign[fundamental[t]]-for-foreign.stderr index 639bee2b8ec..73b1e2c6ed2 100644 --- a/src/test/ui/coherence/impl[t]-foreign[fundamental[t]]-for-foreign.stderr +++ b/src/test/ui/coherence/impl[t]-foreign[fundamental[t]]-for-foreign.stderr @@ -4,7 +4,7 @@ error[E0210]: type parameter `T` must be used as the type parameter for some loc LL | impl<T> Remote1<Box<T>> for u32 { | ^ type parameter `T` must be used as the type parameter for some local type | - = note: implementing a foreign trait is only possible if at least one of the types for which is it implemented is local + = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local = note: only traits defined in the current crate can be implemented for a type parameter error[E0210]: type parameter `T` must be used as the type parameter for some local type (e.g., `MyStruct<T>`) @@ -13,7 +13,7 @@ error[E0210]: type parameter `T` must be used as the type parameter for some loc LL | impl<'a, T> Remote1<&'a T> for u32 { | ^ type parameter `T` must be used as the type parameter for some local type | - = note: implementing a foreign trait is only possible if at least one of the types for which is it implemented is local + = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local = note: only traits defined in the current crate can be implemented for a type parameter error: aborting due to 2 previous errors diff --git a/src/test/ui/coherence/impl[t]-foreign[fundamental[t]]-for-fundamental[t].stderr b/src/test/ui/coherence/impl[t]-foreign[fundamental[t]]-for-fundamental[t].stderr index 0b6c81b53cd..5f89a7aa469 100644 --- a/src/test/ui/coherence/impl[t]-foreign[fundamental[t]]-for-fundamental[t].stderr +++ b/src/test/ui/coherence/impl[t]-foreign[fundamental[t]]-for-fundamental[t].stderr @@ -4,7 +4,7 @@ error[E0210]: type parameter `T` must be used as the type parameter for some loc LL | impl<'a, T> Remote1<Box<T>> for &'a T { | ^ type parameter `T` must be used as the type parameter for some local type | - = note: implementing a foreign trait is only possible if at least one of the types for which is it implemented is local + = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local = note: only traits defined in the current crate can be implemented for a type parameter error[E0210]: type parameter `T` must be used as the type parameter for some local type (e.g., `MyStruct<T>`) @@ -13,7 +13,7 @@ error[E0210]: type parameter `T` must be used as the type parameter for some loc LL | impl<'a, T> Remote1<&'a T> for Box<T> { | ^ type parameter `T` must be used as the type parameter for some local type | - = note: implementing a foreign trait is only possible if at least one of the types for which is it implemented is local + = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local = note: only traits defined in the current crate can be implemented for a type parameter error: aborting due to 2 previous errors diff --git a/src/test/ui/coherence/impl[t]-foreign[fundamental[t]]-for-t.stderr b/src/test/ui/coherence/impl[t]-foreign[fundamental[t]]-for-t.stderr index fe40490822e..45559d8b62d 100644 --- a/src/test/ui/coherence/impl[t]-foreign[fundamental[t]]-for-t.stderr +++ b/src/test/ui/coherence/impl[t]-foreign[fundamental[t]]-for-t.stderr @@ -4,7 +4,7 @@ error[E0210]: type parameter `T` must be used as the type parameter for some loc LL | impl<T> Remote1<Box<T>> for T { | ^ type parameter `T` must be used as the type parameter for some local type | - = note: implementing a foreign trait is only possible if at least one of the types for which is it implemented is local + = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local = note: only traits defined in the current crate can be implemented for a type parameter error[E0210]: type parameter `T` must be used as the type parameter for some local type (e.g., `MyStruct<T>`) @@ -13,7 +13,7 @@ error[E0210]: type parameter `T` must be used as the type parameter for some loc LL | impl<'a, T> Remote1<&'a T> for T { | ^ type parameter `T` must be used as the type parameter for some local type | - = note: implementing a foreign trait is only possible if at least one of the types for which is it implemented is local + = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local = note: only traits defined in the current crate can be implemented for a type parameter error: aborting due to 2 previous errors diff --git a/src/test/ui/coherence/impl[t]-foreign[fundamental[t]_local]-for-foreign.stderr b/src/test/ui/coherence/impl[t]-foreign[fundamental[t]_local]-for-foreign.stderr index 1eaef59b3f8..f94f04c8df5 100644 --- a/src/test/ui/coherence/impl[t]-foreign[fundamental[t]_local]-for-foreign.stderr +++ b/src/test/ui/coherence/impl[t]-foreign[fundamental[t]_local]-for-foreign.stderr @@ -4,7 +4,7 @@ error[E0210]: type parameter `T` must be covered by another type when it appears LL | impl<T> Remote2<Box<T>, Local> for u32 { | ^ type parameter `T` must be covered by another type when it appears before the first local type (`Local`) | - = note: implementing a foreign trait is only possible if at least one of the types for which is it implemented is local, and no uncovered type parameters appear before that first local type + = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local, and no uncovered type parameters appear before that first local type = note: in this case, 'before' refers to the following order: `impl<..> ForeignTrait<T1, ..., Tn> for T0`, where `T0` is the first and `Tn` is the last error[E0210]: type parameter `T` must be covered by another type when it appears before the first local type (`Local`) @@ -13,7 +13,7 @@ error[E0210]: type parameter `T` must be covered by another type when it appears LL | impl<'a, T> Remote2<&'a T, Local> for u32 { | ^ type parameter `T` must be covered by another type when it appears before the first local type (`Local`) | - = note: implementing a foreign trait is only possible if at least one of the types for which is it implemented is local, and no uncovered type parameters appear before that first local type + = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local, and no uncovered type parameters appear before that first local type = note: in this case, 'before' refers to the following order: `impl<..> ForeignTrait<T1, ..., Tn> for T0`, where `T0` is the first and `Tn` is the last error: aborting due to 2 previous errors diff --git a/src/test/ui/coherence/impl[t]-foreign[local]-for-fundamental[t].stderr b/src/test/ui/coherence/impl[t]-foreign[local]-for-fundamental[t].stderr index 4d39186d494..e68f2fe5856 100644 --- a/src/test/ui/coherence/impl[t]-foreign[local]-for-fundamental[t].stderr +++ b/src/test/ui/coherence/impl[t]-foreign[local]-for-fundamental[t].stderr @@ -4,7 +4,7 @@ error[E0210]: type parameter `T` must be covered by another type when it appears LL | impl<T> Remote1<Local> for Box<T> { | ^ type parameter `T` must be covered by another type when it appears before the first local type (`Local`) | - = note: implementing a foreign trait is only possible if at least one of the types for which is it implemented is local, and no uncovered type parameters appear before that first local type + = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local, and no uncovered type parameters appear before that first local type = note: in this case, 'before' refers to the following order: `impl<..> ForeignTrait<T1, ..., Tn> for T0`, where `T0` is the first and `Tn` is the last error[E0210]: type parameter `T` must be covered by another type when it appears before the first local type (`Local`) @@ -13,7 +13,7 @@ error[E0210]: type parameter `T` must be covered by another type when it appears LL | impl<T> Remote1<Local> for &T { | ^ type parameter `T` must be covered by another type when it appears before the first local type (`Local`) | - = note: implementing a foreign trait is only possible if at least one of the types for which is it implemented is local, and no uncovered type parameters appear before that first local type + = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local, and no uncovered type parameters appear before that first local type = note: in this case, 'before' refers to the following order: `impl<..> ForeignTrait<T1, ..., Tn> for T0`, where `T0` is the first and `Tn` is the last error: aborting due to 2 previous errors diff --git a/src/test/ui/coherence/impl[t]-foreign[local]-for-t.stderr b/src/test/ui/coherence/impl[t]-foreign[local]-for-t.stderr index d74be4cec72..d97e85dcb3c 100644 --- a/src/test/ui/coherence/impl[t]-foreign[local]-for-t.stderr +++ b/src/test/ui/coherence/impl[t]-foreign[local]-for-t.stderr @@ -4,7 +4,7 @@ error[E0210]: type parameter `T` must be covered by another type when it appears LL | impl<T> Remote1<Local> for T { | ^ type parameter `T` must be covered by another type when it appears before the first local type (`Local`) | - = note: implementing a foreign trait is only possible if at least one of the types for which is it implemented is local, and no uncovered type parameters appear before that first local type + = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local, and no uncovered type parameters appear before that first local type = note: in this case, 'before' refers to the following order: `impl<..> ForeignTrait<T1, ..., Tn> for T0`, where `T0` is the first and `Tn` is the last error: aborting due to previous error diff --git a/src/test/ui/coherence/impl[t]-foreign[t]-for-foreign.stderr b/src/test/ui/coherence/impl[t]-foreign[t]-for-foreign.stderr index b26feb4914c..44e3b7eedb4 100644 --- a/src/test/ui/coherence/impl[t]-foreign[t]-for-foreign.stderr +++ b/src/test/ui/coherence/impl[t]-foreign[t]-for-foreign.stderr @@ -4,7 +4,7 @@ error[E0210]: type parameter `T` must be used as the type parameter for some loc LL | impl<T> Remote1<T> for u32 { | ^ type parameter `T` must be used as the type parameter for some local type | - = note: implementing a foreign trait is only possible if at least one of the types for which is it implemented is local + = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local = note: only traits defined in the current crate can be implemented for a type parameter error: aborting due to previous error diff --git a/src/test/ui/coherence/impl[t]-foreign[t]-for-fundamental.stderr b/src/test/ui/coherence/impl[t]-foreign[t]-for-fundamental.stderr index 5e8cc552c98..80fb5dbec86 100644 --- a/src/test/ui/coherence/impl[t]-foreign[t]-for-fundamental.stderr +++ b/src/test/ui/coherence/impl[t]-foreign[t]-for-fundamental.stderr @@ -4,7 +4,7 @@ error[E0210]: type parameter `T` must be used as the type parameter for some loc LL | impl<T> Remote1<T> for Box<T> { | ^ type parameter `T` must be used as the type parameter for some local type | - = note: implementing a foreign trait is only possible if at least one of the types for which is it implemented is local + = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local = note: only traits defined in the current crate can be implemented for a type parameter error[E0210]: type parameter `B` must be used as the type parameter for some local type (e.g., `MyStruct<B>`) @@ -13,7 +13,7 @@ error[E0210]: type parameter `B` must be used as the type parameter for some loc LL | impl<'a, A, B> Remote1<A> for &'a B { | ^ type parameter `B` must be used as the type parameter for some local type | - = note: implementing a foreign trait is only possible if at least one of the types for which is it implemented is local + = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local = note: only traits defined in the current crate can be implemented for a type parameter error: aborting due to 2 previous errors diff --git a/src/test/ui/coherence/impl[t]-foreign[t]-for-t.stderr b/src/test/ui/coherence/impl[t]-foreign[t]-for-t.stderr index d3226d33bee..ff72969dc52 100644 --- a/src/test/ui/coherence/impl[t]-foreign[t]-for-t.stderr +++ b/src/test/ui/coherence/impl[t]-foreign[t]-for-t.stderr @@ -4,7 +4,7 @@ error[E0210]: type parameter `T` must be used as the type parameter for some loc LL | impl<T> Remote1<T> for T { | ^ type parameter `T` must be used as the type parameter for some local type | - = note: implementing a foreign trait is only possible if at least one of the types for which is it implemented is local + = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local = note: only traits defined in the current crate can be implemented for a type parameter error: aborting due to previous error diff --git a/src/test/ui/const-generics/array-size-in-generic-struct-param.min.stderr b/src/test/ui/const-generics/array-size-in-generic-struct-param.min.stderr index 0fc45513cd7..cfaacf7a5be 100644 --- a/src/test/ui/const-generics/array-size-in-generic-struct-param.min.stderr +++ b/src/test/ui/const-generics/array-size-in-generic-struct-param.min.stderr @@ -1,18 +1,18 @@ -error: generic parameters must not be used inside of non-trivial constant values +error: generic parameters may not be used in const operations --> $DIR/array-size-in-generic-struct-param.rs:9:48 | LL | struct ArithArrayLen<const N: usize>([u32; 0 + N]); - | ^ non-trivial anonymous constants must not depend on the parameter `N` + | ^ cannot perform const operation using `N` | - = help: it is currently only allowed to use either `N` or `{ N }` as generic constants + = help: const parameters may only be used as standalone arguments, i.e. `N` -error: generic parameters must not be used inside of non-trivial constant values +error: generic parameters may not be used in const operations --> $DIR/array-size-in-generic-struct-param.rs:20:15 | LL | arr: [u8; CFG.arr_size], - | ^^^ non-trivial anonymous constants must not depend on the parameter `CFG` + | ^^^ cannot perform const operation using `CFG` | - = help: it is currently only allowed to use either `CFG` or `{ CFG }` as generic constants + = help: const parameters may only be used as standalone arguments, i.e. `CFG` error: `Config` is forbidden as the type of a const generic parameter --> $DIR/array-size-in-generic-struct-param.rs:18:21 diff --git a/src/test/ui/const-generics/array-size-in-generic-struct-param.rs b/src/test/ui/const-generics/array-size-in-generic-struct-param.rs index dd45b6ed278..768180d0813 100644 --- a/src/test/ui/const-generics/array-size-in-generic-struct-param.rs +++ b/src/test/ui/const-generics/array-size-in-generic-struct-param.rs @@ -8,7 +8,7 @@ #[allow(dead_code)] struct ArithArrayLen<const N: usize>([u32; 0 + N]); //[full]~^ ERROR constant expression depends on a generic parameter -//[min]~^^ ERROR generic parameters must not be used inside of non-trivial constant values +//[min]~^^ ERROR generic parameters may not be used in const operations #[derive(PartialEq, Eq)] struct Config { @@ -19,7 +19,7 @@ struct B<const CFG: Config> { //[min]~^ ERROR `Config` is forbidden arr: [u8; CFG.arr_size], //[full]~^ ERROR constant expression depends on a generic parameter - //[min]~^^ ERROR generic parameters must not be used inside of non-trivial + //[min]~^^ ERROR generic parameters may not be used in const operations } const C: Config = Config { arr_size: 5 }; diff --git a/src/test/ui/const-generics/const-argument-if-length.min.stderr b/src/test/ui/const-generics/const-argument-if-length.min.stderr index c666dce479f..bce701ade86 100644 --- a/src/test/ui/const-generics/const-argument-if-length.min.stderr +++ b/src/test/ui/const-generics/const-argument-if-length.min.stderr @@ -1,10 +1,10 @@ -error: generic parameters must not be used inside of non-trivial constant values +error: generic parameters may not be used in const operations --> $DIR/const-argument-if-length.rs:19:24 | LL | pad: [u8; is_zst::<T>()], - | ^ non-trivial anonymous constants must not depend on the parameter `T` + | ^ cannot perform const operation using `T` | - = note: type parameters are currently not permitted in anonymous constants + = note: type parameters may not be used in const expressions error[E0277]: the size for values of type `T` cannot be known at compilation time --> $DIR/const-argument-if-length.rs:17:12 diff --git a/src/test/ui/const-generics/const-argument-if-length.rs b/src/test/ui/const-generics/const-argument-if-length.rs index 481ff97d68d..a8bffd17b91 100644 --- a/src/test/ui/const-generics/const-argument-if-length.rs +++ b/src/test/ui/const-generics/const-argument-if-length.rs @@ -17,7 +17,7 @@ pub struct AtLeastByte<T: ?Sized> { value: T, //~^ ERROR the size for values of type `T` cannot be known at compilation time pad: [u8; is_zst::<T>()], - //[min]~^ ERROR generic parameters must not be used inside of non-trivial constant values + //[min]~^ ERROR generic parameters may not be used in const operations //[full]~^^ ERROR evaluation of constant value failed } diff --git a/src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.min.stderr b/src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.min.stderr index 4b3235fd087..359c2d2a22f 100644 --- a/src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.min.stderr +++ b/src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.min.stderr @@ -1,10 +1,10 @@ -error: generic parameters must not be used inside of non-trivial constant values +error: generic parameters may not be used in const operations --> $DIR/feature-gate-const_evaluatable_checked.rs:6:33 | LL | type Arr<const N: usize> = [u8; N - 1]; - | ^ non-trivial anonymous constants must not depend on the parameter `N` + | ^ cannot perform const operation using `N` | - = help: it is currently only allowed to use either `N` or `{ N }` as generic constants + = help: const parameters may only be used as standalone arguments, i.e. `N` error: aborting due to previous error diff --git a/src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.rs b/src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.rs index d552e0f5430..9746adab29b 100644 --- a/src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.rs +++ b/src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.rs @@ -4,7 +4,7 @@ #![cfg_attr(min, feature(min_const_generics))] type Arr<const N: usize> = [u8; N - 1]; -//[min]~^ ERROR generic parameters must not be used inside of non-trivial constant values +//[min]~^ ERROR generic parameters may not be used in const operations fn test<const N: usize>() -> Arr<N> where Arr<N>: Default { //[full]~^ ERROR constant expression depends diff --git a/src/test/ui/const-generics/const_evaluatable_checked/simple.min.stderr b/src/test/ui/const-generics/const_evaluatable_checked/simple.min.stderr index 85a15b1e75f..46485262cc4 100644 --- a/src/test/ui/const-generics/const_evaluatable_checked/simple.min.stderr +++ b/src/test/ui/const-generics/const_evaluatable_checked/simple.min.stderr @@ -1,18 +1,18 @@ -error: generic parameters must not be used inside of non-trivial constant values +error: generic parameters may not be used in const operations --> $DIR/simple.rs:8:53 | LL | fn test<const N: usize>() -> [u8; N - 1] where [u8; N - 1]: Default { - | ^ non-trivial anonymous constants must not depend on the parameter `N` + | ^ cannot perform const operation using `N` | - = help: it is currently only allowed to use either `N` or `{ N }` as generic constants + = help: const parameters may only be used as standalone arguments, i.e. `N` -error: generic parameters must not be used inside of non-trivial constant values +error: generic parameters may not be used in const operations --> $DIR/simple.rs:8:35 | LL | fn test<const N: usize>() -> [u8; N - 1] where [u8; N - 1]: Default { - | ^ non-trivial anonymous constants must not depend on the parameter `N` + | ^ cannot perform const operation using `N` | - = help: it is currently only allowed to use either `N` or `{ N }` as generic constants + = help: const parameters may only be used as standalone arguments, i.e. `N` error: aborting due to 2 previous errors diff --git a/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.min.stderr b/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.min.stderr index 2eac9505624..981d993f589 100644 --- a/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.min.stderr +++ b/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.min.stderr @@ -1,10 +1,10 @@ -error: generic parameters must not be used inside of non-trivial constant values +error: generic parameters may not be used in const operations --> $DIR/simple_fail.rs:7:33 | LL | type Arr<const N: usize> = [u8; N - 1]; - | ^ non-trivial anonymous constants must not depend on the parameter `N` + | ^ cannot perform const operation using `N` | - = help: it is currently only allowed to use either `N` or `{ N }` as generic constants + = help: const parameters may only be used as standalone arguments, i.e. `N` error: aborting due to previous error diff --git a/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.rs b/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.rs index 637c940f714..5e2c080927f 100644 --- a/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.rs +++ b/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.rs @@ -5,7 +5,7 @@ #![allow(incomplete_features)] type Arr<const N: usize> = [u8; N - 1]; //[full]~ ERROR evaluation of constant -//[min]~^ ERROR generic parameters must not be used inside of non-trivial constant values +//[min]~^ ERROR generic parameters may not be used in const operations fn test<const N: usize>() -> Arr<N> where Arr<N>: Sized { todo!() diff --git a/src/test/ui/const-generics/defaults/wrong-order.full.stderr b/src/test/ui/const-generics/defaults/wrong-order.full.stderr index c51028d5b20..99f46309bf6 100644 --- a/src/test/ui/const-generics/defaults/wrong-order.full.stderr +++ b/src/test/ui/const-generics/defaults/wrong-order.full.stderr @@ -14,6 +14,7 @@ LL | #![cfg_attr(full, feature(const_generics))] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information + = help: consider using `min_const_generics` instead, which is more stable and complete error: aborting due to previous error; 1 warning emitted diff --git a/src/test/ui/const-generics/generic-function-call-in-array-length.min.stderr b/src/test/ui/const-generics/generic-function-call-in-array-length.min.stderr index e7e968e4c2a..84449018e46 100644 --- a/src/test/ui/const-generics/generic-function-call-in-array-length.min.stderr +++ b/src/test/ui/const-generics/generic-function-call-in-array-length.min.stderr @@ -1,18 +1,18 @@ -error: generic parameters must not be used inside of non-trivial constant values +error: generic parameters may not be used in const operations --> $DIR/generic-function-call-in-array-length.rs:9:39 | LL | fn bar<const N: usize>() -> [u32; foo(N)] { - | ^ non-trivial anonymous constants must not depend on the parameter `N` + | ^ cannot perform const operation using `N` | - = help: it is currently only allowed to use either `N` or `{ N }` as generic constants + = help: const parameters may only be used as standalone arguments, i.e. `N` -error: generic parameters must not be used inside of non-trivial constant values +error: generic parameters may not be used in const operations --> $DIR/generic-function-call-in-array-length.rs:12:13 | LL | [0; foo(N)] - | ^ non-trivial anonymous constants must not depend on the parameter `N` + | ^ cannot perform const operation using `N` | - = help: it is currently only allowed to use either `N` or `{ N }` as generic constants + = help: const parameters may only be used as standalone arguments, i.e. `N` error: aborting due to 2 previous errors diff --git a/src/test/ui/const-generics/generic-function-call-in-array-length.rs b/src/test/ui/const-generics/generic-function-call-in-array-length.rs index c8bbae29343..c838070dc95 100644 --- a/src/test/ui/const-generics/generic-function-call-in-array-length.rs +++ b/src/test/ui/const-generics/generic-function-call-in-array-length.rs @@ -7,10 +7,10 @@ const fn foo(n: usize) -> usize { n * 2 } fn bar<const N: usize>() -> [u32; foo(N)] { - //[min]~^ ERROR generic parameters must not be used inside of non-trivial constant values + //[min]~^ ERROR generic parameters may not be used in const operations //[full]~^^ ERROR constant expression depends on a generic parameter [0; foo(N)] - //[min]~^ ERROR generic parameters must not be used inside of non-trivial constant values + //[min]~^ ERROR generic parameters may not be used in const operations } fn main() {} diff --git a/src/test/ui/const-generics/generic-sum-in-array-length.min.stderr b/src/test/ui/const-generics/generic-sum-in-array-length.min.stderr index 6f157fbbbbb..d3f7143327e 100644 --- a/src/test/ui/const-generics/generic-sum-in-array-length.min.stderr +++ b/src/test/ui/const-generics/generic-sum-in-array-length.min.stderr @@ -1,18 +1,18 @@ -error: generic parameters must not be used inside of non-trivial constant values +error: generic parameters may not be used in const operations --> $DIR/generic-sum-in-array-length.rs:7:53 | LL | fn foo<const A: usize, const B: usize>(bar: [usize; A + B]) {} - | ^ non-trivial anonymous constants must not depend on the parameter `A` + | ^ cannot perform const operation using `A` | - = help: it is currently only allowed to use either `A` or `{ A }` as generic constants + = help: const parameters may only be used as standalone arguments, i.e. `A` -error: generic parameters must not be used inside of non-trivial constant values +error: generic parameters may not be used in const operations --> $DIR/generic-sum-in-array-length.rs:7:57 | LL | fn foo<const A: usize, const B: usize>(bar: [usize; A + B]) {} - | ^ non-trivial anonymous constants must not depend on the parameter `B` + | ^ cannot perform const operation using `B` | - = help: it is currently only allowed to use either `B` or `{ B }` as generic constants + = help: const parameters may only be used as standalone arguments, i.e. `B` error: aborting due to 2 previous errors diff --git a/src/test/ui/const-generics/generic-sum-in-array-length.rs b/src/test/ui/const-generics/generic-sum-in-array-length.rs index 810095b384b..84ddfe055dc 100644 --- a/src/test/ui/const-generics/generic-sum-in-array-length.rs +++ b/src/test/ui/const-generics/generic-sum-in-array-length.rs @@ -5,8 +5,8 @@ #![cfg_attr(min, feature(min_const_generics))] fn foo<const A: usize, const B: usize>(bar: [usize; A + B]) {} -//[min]~^ ERROR generic parameters must not be used inside of non-trivial constant values -//[min]~| ERROR generic parameters must not be used inside of non-trivial constant values +//[min]~^ ERROR generic parameters may not be used in const operations +//[min]~| ERROR generic parameters may not be used in const operations //[full]~^^^ ERROR constant expression depends on a generic parameter fn main() {} diff --git a/src/test/ui/const-generics/intrinsics-type_name-as-const-argument.min.stderr b/src/test/ui/const-generics/intrinsics-type_name-as-const-argument.min.stderr index 307db088bf8..20a8d9fdaab 100644 --- a/src/test/ui/const-generics/intrinsics-type_name-as-const-argument.min.stderr +++ b/src/test/ui/const-generics/intrinsics-type_name-as-const-argument.min.stderr @@ -1,10 +1,10 @@ -error: generic parameters must not be used inside of non-trivial constant values +error: generic parameters may not be used in const operations --> $DIR/intrinsics-type_name-as-const-argument.rs:15:44 | LL | T: Trait<{std::intrinsics::type_name::<T>()}> - | ^ non-trivial anonymous constants must not depend on the parameter `T` + | ^ cannot perform const operation using `T` | - = note: type parameters are currently not permitted in anonymous constants + = note: type parameters may not be used in const expressions error: `&'static str` is forbidden as the type of a const generic parameter --> $DIR/intrinsics-type_name-as-const-argument.rs:10:22 diff --git a/src/test/ui/const-generics/intrinsics-type_name-as-const-argument.rs b/src/test/ui/const-generics/intrinsics-type_name-as-const-argument.rs index 37b6cf4bab9..8971c00ed5a 100644 --- a/src/test/ui/const-generics/intrinsics-type_name-as-const-argument.rs +++ b/src/test/ui/const-generics/intrinsics-type_name-as-const-argument.rs @@ -13,7 +13,7 @@ trait Trait<const S: &'static str> {} struct Bug<T> where T: Trait<{std::intrinsics::type_name::<T>()}> - //[min]~^ ERROR generic parameters must not be used inside of non-trivial constant values + //[min]~^ ERROR generic parameters may not be used in const operations //[full]~^^ ERROR constant expression depends on a generic parameter { t: T diff --git a/src/test/ui/const-generics/issue-61522-array-len-succ.min.stderr b/src/test/ui/const-generics/issue-61522-array-len-succ.min.stderr index 2c1bc055b28..526807f0a24 100644 --- a/src/test/ui/const-generics/issue-61522-array-len-succ.min.stderr +++ b/src/test/ui/const-generics/issue-61522-array-len-succ.min.stderr @@ -1,18 +1,18 @@ -error: generic parameters must not be used inside of non-trivial constant values +error: generic parameters may not be used in const operations --> $DIR/issue-61522-array-len-succ.rs:7:45 | LL | pub struct MyArray<const COUNT: usize>([u8; COUNT + 1]); - | ^^^^^ non-trivial anonymous constants must not depend on the parameter `COUNT` + | ^^^^^ cannot perform const operation using `COUNT` | - = help: it is currently only allowed to use either `COUNT` or `{ COUNT }` as generic constants + = help: const parameters may only be used as standalone arguments, i.e. `COUNT` -error: generic parameters must not be used inside of non-trivial constant values +error: generic parameters may not be used in const operations --> $DIR/issue-61522-array-len-succ.rs:12:30 | LL | fn inner(&self) -> &[u8; COUNT + 1] { - | ^^^^^ non-trivial anonymous constants must not depend on the parameter `COUNT` + | ^^^^^ cannot perform const operation using `COUNT` | - = help: it is currently only allowed to use either `COUNT` or `{ COUNT }` as generic constants + = help: const parameters may only be used as standalone arguments, i.e. `COUNT` error: aborting due to 2 previous errors diff --git a/src/test/ui/const-generics/issue-61522-array-len-succ.rs b/src/test/ui/const-generics/issue-61522-array-len-succ.rs index 81443b90d61..8c0a3a03774 100644 --- a/src/test/ui/const-generics/issue-61522-array-len-succ.rs +++ b/src/test/ui/const-generics/issue-61522-array-len-succ.rs @@ -6,12 +6,12 @@ pub struct MyArray<const COUNT: usize>([u8; COUNT + 1]); //[full]~^ ERROR constant expression depends on a generic parameter -//[min]~^^ ERROR generic parameters must not be used +//[min]~^^ ERROR generic parameters may not be used impl<const COUNT: usize> MyArray<COUNT> { fn inner(&self) -> &[u8; COUNT + 1] { //[full]~^ ERROR constant expression depends on a generic parameter - //[min]~^^ ERROR generic parameters must not be used + //[min]~^^ ERROR generic parameters may not be used &self.0 } } diff --git a/src/test/ui/const-generics/issue-67375.min.stderr b/src/test/ui/const-generics/issue-67375.min.stderr index b13d9fdab0d..3c344edbf1d 100644 --- a/src/test/ui/const-generics/issue-67375.min.stderr +++ b/src/test/ui/const-generics/issue-67375.min.stderr @@ -1,10 +1,10 @@ -error: generic parameters must not be used inside of non-trivial constant values +error: generic parameters may not be used in const operations --> $DIR/issue-67375.rs:9:25 | LL | inner: [(); { [|_: &T| {}; 0].len() }], - | ^ non-trivial anonymous constants must not depend on the parameter `T` + | ^ cannot perform const operation using `T` | - = note: type parameters are currently not permitted in anonymous constants + = note: type parameters may not be used in const expressions error[E0392]: parameter `T` is never used --> $DIR/issue-67375.rs:7:12 diff --git a/src/test/ui/const-generics/issue-67375.rs b/src/test/ui/const-generics/issue-67375.rs index 994ec92cfb5..ecc76bcae06 100644 --- a/src/test/ui/const-generics/issue-67375.rs +++ b/src/test/ui/const-generics/issue-67375.rs @@ -7,7 +7,7 @@ struct Bug<T> { //~^ ERROR parameter `T` is never used inner: [(); { [|_: &T| {}; 0].len() }], - //[min]~^ ERROR generic parameters must not be used inside of non-trivial constant values + //[min]~^ ERROR generic parameters may not be used in const operations //[full]~^^ WARN cannot use constants which depend on generic parameters in types //[full]~^^^ WARN this was previously accepted by the compiler } diff --git a/src/test/ui/const-generics/issue-67945-1.min.stderr b/src/test/ui/const-generics/issue-67945-1.min.stderr index 949b5da5920..804236c30bd 100644 --- a/src/test/ui/const-generics/issue-67945-1.min.stderr +++ b/src/test/ui/const-generics/issue-67945-1.min.stderr @@ -1,18 +1,18 @@ -error: generic parameters must not be used inside of non-trivial constant values +error: generic parameters may not be used in const operations --> $DIR/issue-67945-1.rs:14:16 | LL | let x: S = MaybeUninit::uninit(); - | ^ non-trivial anonymous constants must not depend on the parameter `S` + | ^ cannot perform const operation using `S` | - = note: type parameters are currently not permitted in anonymous constants + = note: type parameters may not be used in const expressions -error: generic parameters must not be used inside of non-trivial constant values +error: generic parameters may not be used in const operations --> $DIR/issue-67945-1.rs:17:45 | LL | let b = &*(&x as *const _ as *const S); - | ^ non-trivial anonymous constants must not depend on the parameter `S` + | ^ cannot perform const operation using `S` | - = note: type parameters are currently not permitted in anonymous constants + = note: type parameters may not be used in const expressions error[E0392]: parameter `S` is never used --> $DIR/issue-67945-1.rs:11:12 diff --git a/src/test/ui/const-generics/issue-67945-1.rs b/src/test/ui/const-generics/issue-67945-1.rs index d1a83e978d1..6771603f259 100644 --- a/src/test/ui/const-generics/issue-67945-1.rs +++ b/src/test/ui/const-generics/issue-67945-1.rs @@ -12,10 +12,10 @@ struct Bug<S> { //~^ ERROR parameter `S` is never used A: [(); { let x: S = MaybeUninit::uninit(); - //[min]~^ ERROR generic parameters must not be used inside of non-trivial constant values + //[min]~^ ERROR generic parameters may not be used in const operations //[full]~^^ ERROR mismatched types let b = &*(&x as *const _ as *const S); - //[min]~^ ERROR generic parameters must not be used inside of non-trivial constant values + //[min]~^ ERROR generic parameters may not be used in const operations 0 }], } diff --git a/src/test/ui/const-generics/issue-67945-2.min.stderr b/src/test/ui/const-generics/issue-67945-2.min.stderr index ed445b3e8f7..2de942c1220 100644 --- a/src/test/ui/const-generics/issue-67945-2.min.stderr +++ b/src/test/ui/const-generics/issue-67945-2.min.stderr @@ -1,18 +1,18 @@ -error: generic parameters must not be used inside of non-trivial constant values +error: generic parameters may not be used in const operations --> $DIR/issue-67945-2.rs:12:16 | LL | let x: S = MaybeUninit::uninit(); - | ^ non-trivial anonymous constants must not depend on the parameter `S` + | ^ cannot perform const operation using `S` | - = note: type parameters are currently not permitted in anonymous constants + = note: type parameters may not be used in const expressions -error: generic parameters must not be used inside of non-trivial constant values +error: generic parameters may not be used in const operations --> $DIR/issue-67945-2.rs:15:45 | LL | let b = &*(&x as *const _ as *const S); - | ^ non-trivial anonymous constants must not depend on the parameter `S` + | ^ cannot perform const operation using `S` | - = note: type parameters are currently not permitted in anonymous constants + = note: type parameters may not be used in const expressions error[E0392]: parameter `S` is never used --> $DIR/issue-67945-2.rs:9:12 diff --git a/src/test/ui/const-generics/issue-67945-2.rs b/src/test/ui/const-generics/issue-67945-2.rs index 7f789297df0..72dbb674e66 100644 --- a/src/test/ui/const-generics/issue-67945-2.rs +++ b/src/test/ui/const-generics/issue-67945-2.rs @@ -10,10 +10,10 @@ struct Bug<S> { //~^ ERROR parameter `S` is never used A: [(); { let x: S = MaybeUninit::uninit(); - //[min]~^ ERROR generic parameters must not be used inside of non-trivial constant values + //[min]~^ ERROR generic parameters may not be used in const operations //[full]~^^ ERROR mismatched types let b = &*(&x as *const _ as *const S); - //[min]~^ ERROR generic parameters must not be used inside of non-trivial constant values + //[min]~^ ERROR generic parameters may not be used in const operations 0 }], } diff --git a/src/test/ui/const-generics/issues/issue-56445.full.stderr b/src/test/ui/const-generics/issues/issue-56445.full.stderr index d853ec5015e..50e91418551 100644 --- a/src/test/ui/const-generics/issues/issue-56445.full.stderr +++ b/src/test/ui/const-generics/issues/issue-56445.full.stderr @@ -6,6 +6,7 @@ LL | #![cfg_attr(full, feature(const_generics))] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information + = help: consider using `min_const_generics` instead, which is more stable and complete error[E0771]: use of non-static lifetime `'a` in const generic --> $DIR/issue-56445.rs:9:26 diff --git a/src/test/ui/const-generics/issues/issue-60818-struct-constructors.full.stderr b/src/test/ui/const-generics/issues/issue-60818-struct-constructors.full.stderr index c03b7252a3c..cc014ea429d 100644 --- a/src/test/ui/const-generics/issues/issue-60818-struct-constructors.full.stderr +++ b/src/test/ui/const-generics/issues/issue-60818-struct-constructors.full.stderr @@ -6,6 +6,7 @@ LL | #![cfg_attr(full, feature(const_generics))] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information + = help: consider using `min_const_generics` instead, which is more stable and complete warning: 1 warning emitted diff --git a/src/test/ui/const-generics/issues/issue-61336-1.full.stderr b/src/test/ui/const-generics/issues/issue-61336-1.full.stderr index f18728eabbb..3a9f819a626 100644 --- a/src/test/ui/const-generics/issues/issue-61336-1.full.stderr +++ b/src/test/ui/const-generics/issues/issue-61336-1.full.stderr @@ -6,6 +6,7 @@ LL | #![cfg_attr(full, feature(const_generics))] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information + = help: consider using `min_const_generics` instead, which is more stable and complete warning: 1 warning emitted diff --git a/src/test/ui/const-generics/issues/issue-61336-2.full.stderr b/src/test/ui/const-generics/issues/issue-61336-2.full.stderr index ef6e60084a5..883ebbef3e8 100644 --- a/src/test/ui/const-generics/issues/issue-61336-2.full.stderr +++ b/src/test/ui/const-generics/issues/issue-61336-2.full.stderr @@ -6,6 +6,7 @@ LL | #![cfg_attr(full, feature(const_generics))] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information + = help: consider using `min_const_generics` instead, which is more stable and complete error[E0277]: the trait bound `T: Copy` is not satisfied --> $DIR/issue-61336-2.rs:10:5 diff --git a/src/test/ui/const-generics/issues/issue-61336.full.stderr b/src/test/ui/const-generics/issues/issue-61336.full.stderr index bdfdffd941d..3863da8da05 100644 --- a/src/test/ui/const-generics/issues/issue-61336.full.stderr +++ b/src/test/ui/const-generics/issues/issue-61336.full.stderr @@ -6,6 +6,7 @@ LL | #![cfg_attr(full, feature(const_generics))] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information + = help: consider using `min_const_generics` instead, which is more stable and complete error[E0277]: the trait bound `T: Copy` is not satisfied --> $DIR/issue-61336.rs:10:5 diff --git a/src/test/ui/const-generics/issues/issue-61422.full.stderr b/src/test/ui/const-generics/issues/issue-61422.full.stderr index ac6c378295d..294378a6690 100644 --- a/src/test/ui/const-generics/issues/issue-61422.full.stderr +++ b/src/test/ui/const-generics/issues/issue-61422.full.stderr @@ -6,6 +6,7 @@ LL | #![cfg_attr(full, feature(const_generics))] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information + = help: consider using `min_const_generics` instead, which is more stable and complete warning: 1 warning emitted diff --git a/src/test/ui/const-generics/issues/issue-61432.full.stderr b/src/test/ui/const-generics/issues/issue-61432.full.stderr index 82b36de45a2..eec1b20254e 100644 --- a/src/test/ui/const-generics/issues/issue-61432.full.stderr +++ b/src/test/ui/const-generics/issues/issue-61432.full.stderr @@ -6,6 +6,7 @@ LL | #![cfg_attr(full, feature(const_generics))] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information + = help: consider using `min_const_generics` instead, which is more stable and complete warning: 1 warning emitted diff --git a/src/test/ui/const-generics/issues/issue-61747.full.stderr b/src/test/ui/const-generics/issues/issue-61747.full.stderr index 3ccce5675fc..3a266c8e974 100644 --- a/src/test/ui/const-generics/issues/issue-61747.full.stderr +++ b/src/test/ui/const-generics/issues/issue-61747.full.stderr @@ -6,6 +6,7 @@ LL | #![cfg_attr(full, feature(const_generics))] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information + = help: consider using `min_const_generics` instead, which is more stable and complete error: constant expression depends on a generic parameter --> $DIR/issue-61747.rs:8:23 diff --git a/src/test/ui/const-generics/issues/issue-61747.min.stderr b/src/test/ui/const-generics/issues/issue-61747.min.stderr index fdd9a569748..b176f9d1c75 100644 --- a/src/test/ui/const-generics/issues/issue-61747.min.stderr +++ b/src/test/ui/const-generics/issues/issue-61747.min.stderr @@ -1,10 +1,10 @@ -error: generic parameters must not be used inside of non-trivial constant values +error: generic parameters may not be used in const operations --> $DIR/issue-61747.rs:8:30 | LL | fn successor() -> Const<{C + 1}> { - | ^ non-trivial anonymous constants must not depend on the parameter `C` + | ^ cannot perform const operation using `C` | - = help: it is currently only allowed to use either `C` or `{ C }` as generic constants + = help: const parameters may only be used as standalone arguments, i.e. `C` error: aborting due to previous error diff --git a/src/test/ui/const-generics/issues/issue-61747.rs b/src/test/ui/const-generics/issues/issue-61747.rs index 4e5cde17f39..3a4dd1cdd18 100644 --- a/src/test/ui/const-generics/issues/issue-61747.rs +++ b/src/test/ui/const-generics/issues/issue-61747.rs @@ -7,7 +7,7 @@ struct Const<const N: usize>; impl<const C: usize> Const<{C}> { fn successor() -> Const<{C + 1}> { //[full]~^ ERROR constant expression depends on a generic parameter - //[min]~^^ ERROR generic parameters must not be used + //[min]~^^ ERROR generic parameters may not be used Const } } diff --git a/src/test/ui/const-generics/issues/issue-61935.min.stderr b/src/test/ui/const-generics/issues/issue-61935.min.stderr index f461a31eeae..9e31466259f 100644 --- a/src/test/ui/const-generics/issues/issue-61935.min.stderr +++ b/src/test/ui/const-generics/issues/issue-61935.min.stderr @@ -1,10 +1,10 @@ -error: generic parameters must not be used inside of non-trivial constant values +error: generic parameters may not be used in const operations --> $DIR/issue-61935.rs:10:23 | LL | Self:FooImpl<{N==0}> - | ^ non-trivial anonymous constants must not depend on the parameter `N` + | ^ cannot perform const operation using `N` | - = help: it is currently only allowed to use either `N` or `{ N }` as generic constants + = help: const parameters may only be used as standalone arguments, i.e. `N` error: aborting due to previous error diff --git a/src/test/ui/const-generics/issues/issue-61935.rs b/src/test/ui/const-generics/issues/issue-61935.rs index a181a8dabe5..9fa02329a71 100644 --- a/src/test/ui/const-generics/issues/issue-61935.rs +++ b/src/test/ui/const-generics/issues/issue-61935.rs @@ -9,7 +9,7 @@ impl<const N: usize> Foo for [(); N] where Self:FooImpl<{N==0}> //[full]~^ERROR constant expression depends on a generic parameter -//[min]~^^ERROR generic parameters must not be used inside of non-trivial constant values +//[min]~^^ERROR generic parameters may not be used in const operations {} trait FooImpl<const IS_ZERO: bool>{} diff --git a/src/test/ui/const-generics/issues/issue-62220.min.stderr b/src/test/ui/const-generics/issues/issue-62220.min.stderr index 84975e8f3be..3bd127ee74a 100644 --- a/src/test/ui/const-generics/issues/issue-62220.min.stderr +++ b/src/test/ui/const-generics/issues/issue-62220.min.stderr @@ -1,10 +1,10 @@ -error: generic parameters must not be used inside of non-trivial constant values +error: generic parameters may not be used in const operations --> $DIR/issue-62220.rs:8:59 | LL | pub type TruncatedVector<T, const N: usize> = Vector<T, { N - 1 }>; - | ^ non-trivial anonymous constants must not depend on the parameter `N` + | ^ cannot perform const operation using `N` | - = help: it is currently only allowed to use either `N` or `{ N }` as generic constants + = help: const parameters may only be used as standalone arguments, i.e. `N` error: aborting due to previous error diff --git a/src/test/ui/const-generics/issues/issue-62220.rs b/src/test/ui/const-generics/issues/issue-62220.rs index 5694dc6d04d..2017473fa9e 100644 --- a/src/test/ui/const-generics/issues/issue-62220.rs +++ b/src/test/ui/const-generics/issues/issue-62220.rs @@ -6,7 +6,7 @@ pub struct Vector<T, const N: usize>([T; N]); pub type TruncatedVector<T, const N: usize> = Vector<T, { N - 1 }>; -//[min]~^ ERROR generic parameters must not be used inside of non-trivial constant values +//[min]~^ ERROR generic parameters may not be used in const operations impl<T, const N: usize> Vector<T, { N }> { /// Drop the last component and return the vector with one fewer dimension. diff --git a/src/test/ui/const-generics/issues/issue-62456.min.stderr b/src/test/ui/const-generics/issues/issue-62456.min.stderr index f94ba8c0c9b..c73f62a4a07 100644 --- a/src/test/ui/const-generics/issues/issue-62456.min.stderr +++ b/src/test/ui/const-generics/issues/issue-62456.min.stderr @@ -1,10 +1,10 @@ -error: generic parameters must not be used inside of non-trivial constant values +error: generic parameters may not be used in const operations --> $DIR/issue-62456.rs:7:20 | LL | let _ = [0u64; N + 1]; - | ^ non-trivial anonymous constants must not depend on the parameter `N` + | ^ cannot perform const operation using `N` | - = help: it is currently only allowed to use either `N` or `{ N }` as generic constants + = help: const parameters may only be used as standalone arguments, i.e. `N` error: aborting due to previous error diff --git a/src/test/ui/const-generics/issues/issue-62456.rs b/src/test/ui/const-generics/issues/issue-62456.rs index 338ec42799d..cbb2a11a931 100644 --- a/src/test/ui/const-generics/issues/issue-62456.rs +++ b/src/test/ui/const-generics/issues/issue-62456.rs @@ -6,7 +6,7 @@ fn foo<const N: usize>() { let _ = [0u64; N + 1]; //[full]~^ ERROR constant expression depends on a generic parameter - //[min]~^^ ERROR generic parameters must not be used inside of non-trivial constant values + //[min]~^^ ERROR generic parameters may not be used in const operations } fn main() {} diff --git a/src/test/ui/const-generics/issues/issue-64494.min.stderr b/src/test/ui/const-generics/issues/issue-64494.min.stderr index f712171bbac..8b02fd108bd 100644 --- a/src/test/ui/const-generics/issues/issue-64494.min.stderr +++ b/src/test/ui/const-generics/issues/issue-64494.min.stderr @@ -1,18 +1,18 @@ -error: generic parameters must not be used inside of non-trivial constant values +error: generic parameters may not be used in const operations --> $DIR/issue-64494.rs:16:38 | LL | impl<T: Foo> MyTrait for T where Is<{T::VAL == 5}>: True {} - | ^^^^^^ non-trivial anonymous constants must not depend on the parameter `T` + | ^^^^^^ cannot perform const operation using `T` | - = note: type parameters are currently not permitted in anonymous constants + = note: type parameters may not be used in const expressions -error: generic parameters must not be used inside of non-trivial constant values +error: generic parameters may not be used in const operations --> $DIR/issue-64494.rs:19:38 | LL | impl<T: Foo> MyTrait for T where Is<{T::VAL == 6}>: True {} - | ^^^^^^ non-trivial anonymous constants must not depend on the parameter `T` + | ^^^^^^ cannot perform const operation using `T` | - = note: type parameters are currently not permitted in anonymous constants + = note: type parameters may not be used in const expressions error[E0119]: conflicting implementations of trait `MyTrait`: --> $DIR/issue-64494.rs:19:1 diff --git a/src/test/ui/const-generics/issues/issue-64494.rs b/src/test/ui/const-generics/issues/issue-64494.rs index b62ebf846d5..014742be03d 100644 --- a/src/test/ui/const-generics/issues/issue-64494.rs +++ b/src/test/ui/const-generics/issues/issue-64494.rs @@ -15,10 +15,10 @@ impl True for Is<{true}> {} impl<T: Foo> MyTrait for T where Is<{T::VAL == 5}>: True {} //[full]~^ ERROR constant expression depends on a generic parameter -//[min]~^^ ERROR generic parameters must not be used inside of non-trivial constant values +//[min]~^^ ERROR generic parameters may not be used in const operations impl<T: Foo> MyTrait for T where Is<{T::VAL == 6}>: True {} //[full]~^ ERROR constant expression depends on a generic parameter -//[min]~^^ ERROR generic parameters must not be used inside of non-trivial constant values +//[min]~^^ ERROR generic parameters may not be used in const operations //[min]~| ERROR conflicting implementations of trait `MyTrait` fn main() {} diff --git a/src/test/ui/const-generics/issues/issue-66205.min.stderr b/src/test/ui/const-generics/issues/issue-66205.min.stderr index a18126ccfef..282f72be6da 100644 --- a/src/test/ui/const-generics/issues/issue-66205.min.stderr +++ b/src/test/ui/const-generics/issues/issue-66205.min.stderr @@ -1,10 +1,10 @@ -error: generic parameters must not be used inside of non-trivial constant values +error: generic parameters may not be used in const operations --> $DIR/issue-66205.rs:8:14 | LL | fact::<{ N - 1 }>(); - | ^ non-trivial anonymous constants must not depend on the parameter `N` + | ^ cannot perform const operation using `N` | - = help: it is currently only allowed to use either `N` or `{ N }` as generic constants + = help: const parameters may only be used as standalone arguments, i.e. `N` error: aborting due to previous error diff --git a/src/test/ui/const-generics/issues/issue-66205.rs b/src/test/ui/const-generics/issues/issue-66205.rs index 668f49852e1..4e37c247d00 100644 --- a/src/test/ui/const-generics/issues/issue-66205.rs +++ b/src/test/ui/const-generics/issues/issue-66205.rs @@ -7,7 +7,7 @@ fn fact<const N: usize>() { fact::<{ N - 1 }>(); //[full]~^ ERROR constant expression depends on a generic parameter - //[min]~^^ ERROR generic parameters must not be used inside of non-trivial constant values + //[min]~^^ ERROR generic parameters may not be used in const operations } fn main() {} diff --git a/src/test/ui/const-generics/issues/issue-67739.min.stderr b/src/test/ui/const-generics/issues/issue-67739.min.stderr index ba378de4156..35d97c46248 100644 --- a/src/test/ui/const-generics/issues/issue-67739.min.stderr +++ b/src/test/ui/const-generics/issues/issue-67739.min.stderr @@ -1,10 +1,10 @@ -error: generic parameters must not be used inside of non-trivial constant values +error: generic parameters may not be used in const operations --> $DIR/issue-67739.rs:12:30 | LL | [0u8; mem::size_of::<Self::Associated>()]; - | ^^^^^^^^^^^^^^^^ non-trivial anonymous constants must not depend on the parameter `Self` + | ^^^^^^^^^^^^^^^^ cannot perform const operation using `Self` | - = note: type parameters are currently not permitted in anonymous constants + = note: type parameters may not be used in const expressions error: aborting due to previous error diff --git a/src/test/ui/const-generics/issues/issue-67739.rs b/src/test/ui/const-generics/issues/issue-67739.rs index 296e4d423c4..21d13de22eb 100644 --- a/src/test/ui/const-generics/issues/issue-67739.rs +++ b/src/test/ui/const-generics/issues/issue-67739.rs @@ -11,7 +11,7 @@ pub trait Trait { fn associated_size(&self) -> usize { [0u8; mem::size_of::<Self::Associated>()]; //[full]~^ ERROR constant expression depends on a generic parameter - //[min]~^^ ERROR generic parameters must not be used inside of non-trivial constant values + //[min]~^^ ERROR generic parameters may not be used in const operations 0 } } diff --git a/src/test/ui/const-generics/issues/issue-68366.min.stderr b/src/test/ui/const-generics/issues/issue-68366.min.stderr index 73d6fec6f9b..b900a0d096a 100644 --- a/src/test/ui/const-generics/issues/issue-68366.min.stderr +++ b/src/test/ui/const-generics/issues/issue-68366.min.stderr @@ -1,10 +1,10 @@ -error: generic parameters must not be used inside of non-trivial constant values +error: generic parameters may not be used in const operations --> $DIR/issue-68366.rs:12:37 | LL | impl <const N: usize> Collatz<{Some(N)}> {} - | ^ non-trivial anonymous constants must not depend on the parameter `N` + | ^ cannot perform const operation using `N` | - = help: it is currently only allowed to use either `N` or `{ N }` as generic constants + = help: const parameters may only be used as standalone arguments, i.e. `N` error[E0207]: the const parameter `N` is not constrained by the impl trait, self type, or predicates --> $DIR/issue-68366.rs:12:13 diff --git a/src/test/ui/const-generics/issues/issue-68366.rs b/src/test/ui/const-generics/issues/issue-68366.rs index ac313eb3b2f..474cdb7258d 100644 --- a/src/test/ui/const-generics/issues/issue-68366.rs +++ b/src/test/ui/const-generics/issues/issue-68366.rs @@ -11,7 +11,7 @@ struct Collatz<const N: Option<usize>>; impl <const N: usize> Collatz<{Some(N)}> {} //~^ ERROR the const parameter -//[min]~^^ generic parameters must not be used inside of non-trivial constant values +//[min]~^^ generic parameters may not be used in const operations struct Foo; diff --git a/src/test/ui/const-generics/issues/issue-68977.min.stderr b/src/test/ui/const-generics/issues/issue-68977.min.stderr index 59d2be3ce4b..7828d859394 100644 --- a/src/test/ui/const-generics/issues/issue-68977.min.stderr +++ b/src/test/ui/const-generics/issues/issue-68977.min.stderr @@ -1,18 +1,18 @@ -error: generic parameters must not be used inside of non-trivial constant values +error: generic parameters may not be used in const operations --> $DIR/issue-68977.rs:29:17 | LL | PhantomU8<{(INT_BITS + FRAC_BITS + 7) / 8}>; - | ^^^^^^^^ non-trivial anonymous constants must not depend on the parameter `INT_BITS` + | ^^^^^^^^ cannot perform const operation using `INT_BITS` | - = help: it is currently only allowed to use either `INT_BITS` or `{ INT_BITS }` as generic constants + = help: const parameters may only be used as standalone arguments, i.e. `INT_BITS` -error: generic parameters must not be used inside of non-trivial constant values +error: generic parameters may not be used in const operations --> $DIR/issue-68977.rs:29:28 | LL | PhantomU8<{(INT_BITS + FRAC_BITS + 7) / 8}>; - | ^^^^^^^^^ non-trivial anonymous constants must not depend on the parameter `FRAC_BITS` + | ^^^^^^^^^ cannot perform const operation using `FRAC_BITS` | - = help: it is currently only allowed to use either `FRAC_BITS` or `{ FRAC_BITS }` as generic constants + = help: const parameters may only be used as standalone arguments, i.e. `FRAC_BITS` error: aborting due to 2 previous errors diff --git a/src/test/ui/const-generics/issues/issue-68977.rs b/src/test/ui/const-generics/issues/issue-68977.rs index 49b305a5a78..4fea94cb465 100644 --- a/src/test/ui/const-generics/issues/issue-68977.rs +++ b/src/test/ui/const-generics/issues/issue-68977.rs @@ -27,8 +27,8 @@ fxp_storage_impls! { type FxpStorageHelper<const INT_BITS: u8, const FRAC_BITS: u8> = PhantomU8<{(INT_BITS + FRAC_BITS + 7) / 8}>; - //[min]~^ ERROR generic parameters must not be used inside of non-trivial constant values - //[min]~| ERROR generic parameters must not be used inside of non-trivial constant values + //[min]~^ ERROR generic parameters may not be used in const operations + //[min]~| ERROR generic parameters may not be used in const operations struct Fxp<const INT_BITS: u8, const FRAC_BITS: u8> where diff --git a/src/test/ui/const-generics/issues/issue-72787.min.stderr b/src/test/ui/const-generics/issues/issue-72787.min.stderr index a4c80b1d8c0..d960d9513b7 100644 --- a/src/test/ui/const-generics/issues/issue-72787.min.stderr +++ b/src/test/ui/const-generics/issues/issue-72787.min.stderr @@ -1,34 +1,34 @@ -error: generic parameters must not be used inside of non-trivial constant values +error: generic parameters may not be used in const operations --> $DIR/issue-72787.rs:11:17 | LL | Condition<{ LHS <= RHS }>: True - | ^^^ non-trivial anonymous constants must not depend on the parameter `LHS` + | ^^^ cannot perform const operation using `LHS` | - = help: it is currently only allowed to use either `LHS` or `{ LHS }` as generic constants + = help: const parameters may only be used as standalone arguments, i.e. `LHS` -error: generic parameters must not be used inside of non-trivial constant values +error: generic parameters may not be used in const operations --> $DIR/issue-72787.rs:11:24 | LL | Condition<{ LHS <= RHS }>: True - | ^^^ non-trivial anonymous constants must not depend on the parameter `RHS` + | ^^^ cannot perform const operation using `RHS` | - = help: it is currently only allowed to use either `RHS` or `{ RHS }` as generic constants + = help: const parameters may only be used as standalone arguments, i.e. `RHS` -error: generic parameters must not be used inside of non-trivial constant values +error: generic parameters may not be used in const operations --> $DIR/issue-72787.rs:26:25 | LL | IsLessOrEqual<{ 8 - I }, { 8 - J }>: True, - | ^ non-trivial anonymous constants must not depend on the parameter `I` + | ^ cannot perform const operation using `I` | - = help: it is currently only allowed to use either `I` or `{ I }` as generic constants + = help: const parameters may only be used as standalone arguments, i.e. `I` -error: generic parameters must not be used inside of non-trivial constant values +error: generic parameters may not be used in const operations --> $DIR/issue-72787.rs:26:36 | LL | IsLessOrEqual<{ 8 - I }, { 8 - J }>: True, - | ^ non-trivial anonymous constants must not depend on the parameter `J` + | ^ cannot perform const operation using `J` | - = help: it is currently only allowed to use either `J` or `{ J }` as generic constants + = help: const parameters may only be used as standalone arguments, i.e. `J` error[E0283]: type annotations needed --> $DIR/issue-72787.rs:22:26 diff --git a/src/test/ui/const-generics/issues/issue-72787.rs b/src/test/ui/const-generics/issues/issue-72787.rs index 779c1d2950e..57572e23aa4 100644 --- a/src/test/ui/const-generics/issues/issue-72787.rs +++ b/src/test/ui/const-generics/issues/issue-72787.rs @@ -10,8 +10,8 @@ pub trait True {} impl<const LHS: u32, const RHS: u32> True for IsLessOrEqual<LHS, RHS> where Condition<{ LHS <= RHS }>: True //[full]~^ Error constant expression depends on a generic parameter -//[min]~^^ Error generic parameters must not be used inside of non-trivial constant values -//[min]~| Error generic parameters must not be used inside of non-trivial constant values +//[min]~^^ Error generic parameters may not be used in const operations +//[min]~| Error generic parameters may not be used in const operations { } impl True for Condition<true> {} @@ -28,8 +28,8 @@ where //[full]~| constant expression depends on a generic parameter //[full]~| constant expression depends on a generic parameter //[full]~| constant expression depends on a generic parameter -//[min]~^^^^^ Error generic parameters must not be used inside of non-trivial constant values -//[min]~| Error generic parameters must not be used inside of non-trivial constant values +//[min]~^^^^^ Error generic parameters may not be used in const operations +//[min]~| Error generic parameters may not be used in const operations // Condition<{ 8 - I <= 8 - J }>: True, { fn print() { diff --git a/src/test/ui/const-generics/issues/issue-72819-generic-in-const-eval.min.stderr b/src/test/ui/const-generics/issues/issue-72819-generic-in-const-eval.min.stderr index afc14c7dcff..9fec3eb946d 100644 --- a/src/test/ui/const-generics/issues/issue-72819-generic-in-const-eval.min.stderr +++ b/src/test/ui/const-generics/issues/issue-72819-generic-in-const-eval.min.stderr @@ -1,10 +1,10 @@ -error: generic parameters must not be used inside of non-trivial constant values +error: generic parameters may not be used in const operations --> $DIR/issue-72819-generic-in-const-eval.rs:9:17 | LL | where Assert::<{N < usize::max_value() / 2}>: IsTrue, - | ^ non-trivial anonymous constants must not depend on the parameter `N` + | ^ cannot perform const operation using `N` | - = help: it is currently only allowed to use either `N` or `{ N }` as generic constants + = help: const parameters may only be used as standalone arguments, i.e. `N` error: aborting due to previous error diff --git a/src/test/ui/const-generics/issues/issue-72819-generic-in-const-eval.rs b/src/test/ui/const-generics/issues/issue-72819-generic-in-const-eval.rs index 65c7f00a72a..6182042bde7 100644 --- a/src/test/ui/const-generics/issues/issue-72819-generic-in-const-eval.rs +++ b/src/test/ui/const-generics/issues/issue-72819-generic-in-const-eval.rs @@ -8,7 +8,7 @@ struct Arr<const N: usize> where Assert::<{N < usize::max_value() / 2}>: IsTrue, //[full]~^ ERROR constant expression depends on a generic parameter -//[min]~^^ ERROR generic parameters must not be used inside of non-trivial constant values +//[min]~^^ ERROR generic parameters may not be used in const operations { } diff --git a/src/test/ui/const-generics/issues/issue-76701-ty-param-in-const.min.stderr b/src/test/ui/const-generics/issues/issue-76701-ty-param-in-const.min.stderr index 0db948d0a45..c10db84ea6e 100644 --- a/src/test/ui/const-generics/issues/issue-76701-ty-param-in-const.min.stderr +++ b/src/test/ui/const-generics/issues/issue-76701-ty-param-in-const.min.stderr @@ -1,18 +1,18 @@ -error: generic parameters must not be used inside of non-trivial constant values +error: generic parameters may not be used in const operations --> $DIR/issue-76701-ty-param-in-const.rs:6:46 | LL | fn ty_param<T>() -> [u8; std::mem::size_of::<T>()] { - | ^ non-trivial anonymous constants must not depend on the parameter `T` + | ^ cannot perform const operation using `T` | - = note: type parameters are currently not permitted in anonymous constants + = note: type parameters may not be used in const expressions -error: generic parameters must not be used inside of non-trivial constant values +error: generic parameters may not be used in const operations --> $DIR/issue-76701-ty-param-in-const.rs:12:42 | LL | fn const_param<const N: usize>() -> [u8; N + 1] { - | ^ non-trivial anonymous constants must not depend on the parameter `N` + | ^ cannot perform const operation using `N` | - = help: it is currently only allowed to use either `N` or `{ N }` as generic constants + = help: const parameters may only be used as standalone arguments, i.e. `N` error: aborting due to 2 previous errors diff --git a/src/test/ui/const-generics/issues/issue-76701-ty-param-in-const.rs b/src/test/ui/const-generics/issues/issue-76701-ty-param-in-const.rs index 3c5bfb03f08..9051c36fe81 100644 --- a/src/test/ui/const-generics/issues/issue-76701-ty-param-in-const.rs +++ b/src/test/ui/const-generics/issues/issue-76701-ty-param-in-const.rs @@ -5,13 +5,13 @@ fn ty_param<T>() -> [u8; std::mem::size_of::<T>()] { //[full]~^ ERROR constant expression depends on a generic parameter - //[min]~^^ ERROR generic parameters must not be used inside of non-trivial constant values + //[min]~^^ ERROR generic parameters may not be used in const operations todo!() } fn const_param<const N: usize>() -> [u8; N + 1] { //[full]~^ ERROR constant expression depends on a generic parameter - //[min]~^^ ERROR generic parameters must not be used inside of non-trivial constant values + //[min]~^^ ERROR generic parameters may not be used in const operations todo!() } diff --git a/src/test/ui/const-generics/min_const_generics/complex-expression.rs b/src/test/ui/const-generics/min_const_generics/complex-expression.rs index c6380f6394d..8257ffbf491 100644 --- a/src/test/ui/const-generics/min_const_generics/complex-expression.rs +++ b/src/test/ui/const-generics/min_const_generics/complex-expression.rs @@ -7,19 +7,19 @@ fn ok<const M: usize>() -> [u8; M] { } struct Break0<const N: usize>([u8; { N + 1 }]); -//~^ ERROR generic parameters must not be used inside of non-trivial constant values +//~^ ERROR generic parameters may not be used in const operations struct Break1<const N: usize>([u8; { { N } }]); -//~^ ERROR generic parameters must not be used inside of non-trivial constant values +//~^ ERROR generic parameters may not be used in const operations fn break2<const N: usize>() { let _: [u8; N + 1]; - //~^ ERROR generic parameters must not be used inside of non-trivial constant values + //~^ ERROR generic parameters may not be used in const operations } fn break3<const N: usize>() { let _ = [0; N + 1]; - //~^ ERROR generic parameters must not be used inside of non-trivial constant values + //~^ ERROR generic parameters may not be used in const operations } trait Foo { diff --git a/src/test/ui/const-generics/min_const_generics/complex-expression.stderr b/src/test/ui/const-generics/min_const_generics/complex-expression.stderr index d8897f53d7f..73768ac03a4 100644 --- a/src/test/ui/const-generics/min_const_generics/complex-expression.stderr +++ b/src/test/ui/const-generics/min_const_generics/complex-expression.stderr @@ -1,34 +1,34 @@ -error: generic parameters must not be used inside of non-trivial constant values +error: generic parameters may not be used in const operations --> $DIR/complex-expression.rs:9:38 | LL | struct Break0<const N: usize>([u8; { N + 1 }]); - | ^ non-trivial anonymous constants must not depend on the parameter `N` + | ^ cannot perform const operation using `N` | - = help: it is currently only allowed to use either `N` or `{ N }` as generic constants + = help: const parameters may only be used as standalone arguments, i.e. `N` -error: generic parameters must not be used inside of non-trivial constant values +error: generic parameters may not be used in const operations --> $DIR/complex-expression.rs:12:40 | LL | struct Break1<const N: usize>([u8; { { N } }]); - | ^ non-trivial anonymous constants must not depend on the parameter `N` + | ^ cannot perform const operation using `N` | - = help: it is currently only allowed to use either `N` or `{ N }` as generic constants + = help: const parameters may only be used as standalone arguments, i.e. `N` -error: generic parameters must not be used inside of non-trivial constant values +error: generic parameters may not be used in const operations --> $DIR/complex-expression.rs:16:17 | LL | let _: [u8; N + 1]; - | ^ non-trivial anonymous constants must not depend on the parameter `N` + | ^ cannot perform const operation using `N` | - = help: it is currently only allowed to use either `N` or `{ N }` as generic constants + = help: const parameters may only be used as standalone arguments, i.e. `N` -error: generic parameters must not be used inside of non-trivial constant values +error: generic parameters may not be used in const operations --> $DIR/complex-expression.rs:21:17 | LL | let _ = [0; N + 1]; - | ^ non-trivial anonymous constants must not depend on the parameter `N` + | ^ cannot perform const operation using `N` | - = help: it is currently only allowed to use either `N` or `{ N }` as generic constants + = help: const parameters may only be used as standalone arguments, i.e. `N` error: aborting due to 4 previous errors diff --git a/src/test/ui/const-generics/min_const_generics/self-ty-in-const-1.stderr b/src/test/ui/const-generics/min_const_generics/self-ty-in-const-1.stderr index 7dc81bf45af..64da5e07df2 100644 --- a/src/test/ui/const-generics/min_const_generics/self-ty-in-const-1.stderr +++ b/src/test/ui/const-generics/min_const_generics/self-ty-in-const-1.stderr @@ -1,10 +1,10 @@ -error: generic parameters must not be used inside of non-trivial constant values +error: generic parameters may not be used in const operations --> $DIR/self-ty-in-const-1.rs:4:41 | LL | fn t1() -> [u8; std::mem::size_of::<Self>()]; - | ^^^^ non-trivial anonymous constants must not depend on the parameter `Self` + | ^^^^ cannot perform const operation using `Self` | - = note: type parameters are currently not permitted in anonymous constants + = note: type parameters may not be used in const expressions error: generic `Self` types are currently not permitted in anonymous constants --> $DIR/self-ty-in-const-1.rs:14:41 diff --git a/src/test/ui/const-generics/occurs-check/unify-fixpoint.stderr b/src/test/ui/const-generics/occurs-check/unify-fixpoint.stderr index 671f1103dcc..8a1462c59e8 100644 --- a/src/test/ui/const-generics/occurs-check/unify-fixpoint.stderr +++ b/src/test/ui/const-generics/occurs-check/unify-fixpoint.stderr @@ -6,6 +6,7 @@ LL | #![feature(const_generics)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information + = help: consider using `min_const_generics` instead, which is more stable and complete error: constant expression depends on a generic parameter --> $DIR/unify-fixpoint.rs:9:32 diff --git a/src/test/ui/const-generics/params-in-ct-in-ty-param-lazy-norm.min.stderr b/src/test/ui/const-generics/params-in-ct-in-ty-param-lazy-norm.min.stderr index 0dd591d891f..39aa8087cec 100644 --- a/src/test/ui/const-generics/params-in-ct-in-ty-param-lazy-norm.min.stderr +++ b/src/test/ui/const-generics/params-in-ct-in-ty-param-lazy-norm.min.stderr @@ -6,13 +6,13 @@ LL | struct Bar<T = [u8; N], const N: usize>(T); | = note: using type defaults and const parameters in the same parameter list is currently not permitted -error: generic parameters must not be used inside of non-trivial constant values +error: generic parameters may not be used in const operations --> $DIR/params-in-ct-in-ty-param-lazy-norm.rs:7:44 | LL | struct Foo<T, U = [u8; std::mem::size_of::<T>()]>(T, U); - | ^ non-trivial anonymous constants must not depend on the parameter `T` + | ^ cannot perform const operation using `T` | - = note: type parameters are currently not permitted in anonymous constants + = note: type parameters may not be used in const expressions error: constant values inside of type parameter defaults must not depend on generic parameters --> $DIR/params-in-ct-in-ty-param-lazy-norm.rs:12:21 diff --git a/src/test/ui/const-generics/params-in-ct-in-ty-param-lazy-norm.rs b/src/test/ui/const-generics/params-in-ct-in-ty-param-lazy-norm.rs index b9d74850f37..51f0cff3f21 100644 --- a/src/test/ui/const-generics/params-in-ct-in-ty-param-lazy-norm.rs +++ b/src/test/ui/const-generics/params-in-ct-in-ty-param-lazy-norm.rs @@ -6,7 +6,7 @@ struct Foo<T, U = [u8; std::mem::size_of::<T>()]>(T, U); //[full]~^ ERROR constant values inside of type parameter defaults -//[min]~^^ ERROR generic parameters must not be used inside of non-trivial +//[min]~^^ ERROR generic parameters may not be used in const operations // FIXME(const_generics:defaults): We still don't know how to we deal with type defaults. struct Bar<T = [u8; N], const N: usize>(T); diff --git a/src/test/ui/const-generics/wf-misc.min.stderr b/src/test/ui/const-generics/wf-misc.min.stderr index 1c52d601749..935f12dd2c3 100644 --- a/src/test/ui/const-generics/wf-misc.min.stderr +++ b/src/test/ui/const-generics/wf-misc.min.stderr @@ -1,18 +1,18 @@ -error: generic parameters must not be used inside of non-trivial constant values +error: generic parameters may not be used in const operations --> $DIR/wf-misc.rs:9:17 | LL | let _: [u8; N + 1]; - | ^ non-trivial anonymous constants must not depend on the parameter `N` + | ^ cannot perform const operation using `N` | - = help: it is currently only allowed to use either `N` or `{ N }` as generic constants + = help: const parameters may only be used as standalone arguments, i.e. `N` -error: generic parameters must not be used inside of non-trivial constant values +error: generic parameters may not be used in const operations --> $DIR/wf-misc.rs:17:21 | LL | let _: Const::<{N + 1}>; - | ^ non-trivial anonymous constants must not depend on the parameter `N` + | ^ cannot perform const operation using `N` | - = help: it is currently only allowed to use either `N` or `{ N }` as generic constants + = help: const parameters may only be used as standalone arguments, i.e. `N` error: aborting due to 2 previous errors diff --git a/src/test/ui/const-generics/wf-misc.rs b/src/test/ui/const-generics/wf-misc.rs index f8c41404c46..103c580f28f 100644 --- a/src/test/ui/const-generics/wf-misc.rs +++ b/src/test/ui/const-generics/wf-misc.rs @@ -8,7 +8,7 @@ pub fn arr_len<const N: usize>() { let _: [u8; N + 1]; //[full]~^ ERROR constant expression depends on a generic parameter - //[min]~^^ ERROR generic parameters must not be used inside of non-trivial + //[min]~^^ ERROR generic parameters may not be used in const operations } struct Const<const N: usize>; @@ -16,7 +16,7 @@ struct Const<const N: usize>; pub fn func_call<const N: usize>() { let _: Const::<{N + 1}>; //[full]~^ ERROR constant expression depends on a generic parameter - //[min]~^^ ERROR generic parameters must not be used inside of non-trivial + //[min]~^^ ERROR generic parameters may not be used in const operations } fn main() {} diff --git a/src/test/ui/consts/trait_specialization.stderr b/src/test/ui/consts/trait_specialization.stderr index 03da7d512e5..e80821cf46a 100644 --- a/src/test/ui/consts/trait_specialization.stderr +++ b/src/test/ui/consts/trait_specialization.stderr @@ -6,6 +6,7 @@ LL | #![feature(specialization)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete warning: 1 warning emitted diff --git a/src/test/ui/did_you_mean/bad-assoc-ty.rs b/src/test/ui/did_you_mean/bad-assoc-ty.rs index e66b432ede2..99ebe84cd9d 100644 --- a/src/test/ui/did_you_mean/bad-assoc-ty.rs +++ b/src/test/ui/did_you_mean/bad-assoc-ty.rs @@ -68,7 +68,6 @@ enum N<F> where F: Fn() -> _ { union O<F> where F: Fn() -> _ { //~^ ERROR the type placeholder `_` is not allowed within types on item signatures -//~| ERROR unions with non-`Copy` fields are unstable foo: F, } diff --git a/src/test/ui/did_you_mean/bad-assoc-ty.stderr b/src/test/ui/did_you_mean/bad-assoc-ty.stderr index 4835d9ab107..ebc0883370b 100644 --- a/src/test/ui/did_you_mean/bad-assoc-ty.stderr +++ b/src/test/ui/did_you_mean/bad-assoc-ty.stderr @@ -57,19 +57,6 @@ LL | type J = ty!(u8); | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0658]: unions with non-`Copy` fields are unstable - --> $DIR/bad-assoc-ty.rs:69:1 - | -LL | / union O<F> where F: Fn() -> _ { -LL | | -LL | | -LL | | foo: F, -LL | | } - | |_^ - | - = note: see issue #55149 <https://github.com/rust-lang/rust/issues/55149> for more information - = help: add `#![feature(untagged_unions)]` to the crate attributes to enable - error[E0223]: ambiguous associated type --> $DIR/bad-assoc-ty.rs:1:10 | @@ -215,7 +202,7 @@ LL | union O<F, T> where F: Fn() -> T { | ^^^ ^ error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/bad-assoc-ty.rs:75:29 + --> $DIR/bad-assoc-ty.rs:74:29 | LL | trait P<F> where F: Fn() -> _ { | ^ not allowed in type signatures @@ -226,7 +213,7 @@ LL | trait P<F, T> where F: Fn() -> T { | ^^^ ^ error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/bad-assoc-ty.rs:80:38 + --> $DIR/bad-assoc-ty.rs:79:38 | LL | fn foo<F>(_: F) where F: Fn() -> _ {} | ^ not allowed in type signatures @@ -236,7 +223,7 @@ help: use type parameters instead LL | fn foo<F, T>(_: F) where F: Fn() -> T {} | ^^^ ^ -error: aborting due to 29 previous errors +error: aborting due to 28 previous errors -Some errors have detailed explanations: E0121, E0223, E0658. +Some errors have detailed explanations: E0121, E0223. For more information about an error, try `rustc --explain E0121`. diff --git a/src/test/ui/did_you_mean/issue-43871-enum-instead-of-variant.stderr b/src/test/ui/did_you_mean/issue-43871-enum-instead-of-variant.stderr index e1325b789d2..bca493e67d5 100644 --- a/src/test/ui/did_you_mean/issue-43871-enum-instead-of-variant.stderr +++ b/src/test/ui/did_you_mean/issue-43871-enum-instead-of-variant.stderr @@ -2,7 +2,7 @@ error[E0423]: expected function, tuple struct or tuple variant, found enum `Opti --> $DIR/issue-43871-enum-instead-of-variant.rs:19:13 | LL | let x = Option(1); - | ^^^^^^ help: try using one of the enum's variants: `std::option::Option::Some` + | ^^^^^^ help: try to construct one of the enum's variants: `std::option::Option::Some` | = help: you might have meant to construct the enum's non-tuple variant @@ -10,7 +10,7 @@ error[E0532]: expected tuple struct or tuple variant, found enum `Option` --> $DIR/issue-43871-enum-instead-of-variant.rs:21:12 | LL | if let Option(_) = x { - | ^^^^^^ help: try using one of the enum's variants: `std::option::Option::Some` + | ^^^^^^ help: try to match against one of the enum's variants: `std::option::Option::Some` | = help: you might have meant to match against the enum's non-tuple variant @@ -18,9 +18,14 @@ error[E0532]: expected tuple struct or tuple variant, found enum `Example` --> $DIR/issue-43871-enum-instead-of-variant.rs:27:12 | LL | if let Example(_) = y { - | ^^^^^^^ help: try using one of the enum's variants: `Example::Ex` + | ^^^^^^^ help: try to match against one of the enum's variants: `Example::Ex` | = help: you might have meant to match against the enum's non-tuple variant +note: the enum is defined here + --> $DIR/issue-43871-enum-instead-of-variant.rs:1:1 + | +LL | enum Example { Ex(String), NotEx } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0423]: expected function, tuple struct or tuple variant, found enum `Void` --> $DIR/issue-43871-enum-instead-of-variant.rs:31:13 @@ -29,6 +34,11 @@ LL | let y = Void(); | ^^^^ | = help: the enum has no tuple variants to construct +note: the enum is defined here + --> $DIR/issue-43871-enum-instead-of-variant.rs:3:1 + | +LL | enum Void {} + | ^^^^^^^^^^^^ error[E0423]: expected function, tuple struct or tuple variant, found enum `ManyVariants` --> $DIR/issue-43871-enum-instead-of-variant.rs:33:13 @@ -38,6 +48,17 @@ LL | let z = ManyVariants(); | = help: the enum has no tuple variants to construct = help: you might have meant to construct one of the enum's non-tuple variants +note: the enum is defined here + --> $DIR/issue-43871-enum-instead-of-variant.rs:5:1 + | +LL | / enum ManyVariants { +LL | | One, +LL | | Two, +LL | | Three, +... | +LL | | Ten, +LL | | } + | |_^ error: aborting due to 5 previous errors diff --git a/src/test/ui/drop/dynamic-drop-async.rs b/src/test/ui/drop/dynamic-drop-async.rs index 88d36ab6aa6..b027faa9d7c 100644 --- a/src/test/ui/drop/dynamic-drop-async.rs +++ b/src/test/ui/drop/dynamic-drop-async.rs @@ -7,8 +7,6 @@ // edition:2018 // ignore-wasm32-bare compiled with panic=abort by default -#![feature(move_ref_pattern)] - #![allow(unused)] use std::{ diff --git a/src/test/ui/drop/dynamic-drop.rs b/src/test/ui/drop/dynamic-drop.rs index d31736f142c..6d0cd101dbc 100644 --- a/src/test/ui/drop/dynamic-drop.rs +++ b/src/test/ui/drop/dynamic-drop.rs @@ -1,8 +1,7 @@ // run-pass // ignore-wasm32-bare compiled with panic=abort by default -#![feature(generators, generator_trait, untagged_unions)] -#![feature(move_ref_pattern)] +#![feature(generators, generator_trait)] #![feature(bindings_after_at)] #![allow(unused_assignments)] diff --git a/src/test/ui/dropck/dropck-union.rs b/src/test/ui/dropck/dropck-union.rs index ef4d1b360b8..5a9965db5ed 100644 --- a/src/test/ui/dropck/dropck-union.rs +++ b/src/test/ui/dropck/dropck-union.rs @@ -1,5 +1,3 @@ -#![feature(untagged_unions)] - use std::cell::Cell; use std::ops::Deref; use std::mem::ManuallyDrop; diff --git a/src/test/ui/dropck/dropck-union.stderr b/src/test/ui/dropck/dropck-union.stderr index 228744326f9..854e29385a8 100644 --- a/src/test/ui/dropck/dropck-union.stderr +++ b/src/test/ui/dropck/dropck-union.stderr @@ -1,5 +1,5 @@ error[E0597]: `v` does not live long enough - --> $DIR/dropck-union.rs:39:18 + --> $DIR/dropck-union.rs:37:18 | LL | v.0.set(Some(&v)); | ^^ borrowed value does not live long enough diff --git a/src/test/ui/empty/empty-macro-use.stderr b/src/test/ui/empty/empty-macro-use.stderr index 8e3e06896ee..700f6616af4 100644 --- a/src/test/ui/empty/empty-macro-use.stderr +++ b/src/test/ui/empty/empty-macro-use.stderr @@ -3,6 +3,9 @@ error: cannot find macro `macro_two` in this scope | LL | macro_two!(); | ^^^^^^^^^ + | + = note: consider importing this macro: + two_macros::macro_two error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0007.rs b/src/test/ui/error-codes/E0007.rs deleted file mode 100644 index 022ac5fc113..00000000000 --- a/src/test/ui/error-codes/E0007.rs +++ /dev/null @@ -1,11 +0,0 @@ -#![feature(bindings_after_at)] - -fn main() { - let x = Some("s".to_string()); - match x { - op_string @ Some(s) => {}, - //~^ ERROR E0007 - //~| ERROR E0382 - None => {}, - } -} diff --git a/src/test/ui/error-codes/E0007.stderr b/src/test/ui/error-codes/E0007.stderr deleted file mode 100644 index 89c10516194..00000000000 --- a/src/test/ui/error-codes/E0007.stderr +++ /dev/null @@ -1,22 +0,0 @@ -error[E0007]: cannot bind by-move with sub-bindings - --> $DIR/E0007.rs:6:9 - | -LL | op_string @ Some(s) => {}, - | ^^^^^^^^^^^^^^^^^^^ binds an already bound by-move value by moving it - -error[E0382]: use of moved value - --> $DIR/E0007.rs:6:26 - | -LL | let x = Some("s".to_string()); - | - move occurs because `x` has type `Option<String>`, which does not implement the `Copy` trait -LL | match x { -LL | op_string @ Some(s) => {}, - | -----------------^- - | | | - | | value used here after move - | value moved here - -error: aborting due to 2 previous errors - -Some errors have detailed explanations: E0007, E0382. -For more information about an error, try `rustc --explain E0007`. diff --git a/src/test/ui/error-codes/E0060.stderr b/src/test/ui/error-codes/E0060.stderr index a600592c6c2..c80014d1476 100644 --- a/src/test/ui/error-codes/E0060.stderr +++ b/src/test/ui/error-codes/E0060.stderr @@ -1,13 +1,16 @@ error[E0060]: this function takes at least 1 argument but 0 arguments were supplied --> $DIR/E0060.rs:6:14 | -LL | fn printf(_: *const u8, ...) -> u32; - | ------------------------------------ defined here -... LL | unsafe { printf(); } | ^^^^^^-- supplied 0 arguments | | | expected at least 1 argument + | +note: function defined here + --> $DIR/E0060.rs:2:8 + | +LL | fn printf(_: *const u8, ...) -> u32; + | ^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0061.stderr b/src/test/ui/error-codes/E0061.stderr index dfefa0df313..98488a2d298 100644 --- a/src/test/ui/error-codes/E0061.stderr +++ b/src/test/ui/error-codes/E0061.stderr @@ -1,24 +1,30 @@ error[E0061]: this function takes 2 arguments but 1 argument was supplied --> $DIR/E0061.rs:6:5 | -LL | fn f(a: u16, b: &str) {} - | --------------------- defined here -... LL | f(0); | ^ - supplied 1 argument | | | expected 2 arguments + | +note: function defined here + --> $DIR/E0061.rs:1:4 + | +LL | fn f(a: u16, b: &str) {} + | ^ ------ ------- error[E0061]: this function takes 1 argument but 0 arguments were supplied --> $DIR/E0061.rs:10:5 | -LL | fn f2(a: u16) {} - | ------------- defined here -... LL | f2(); | ^^-- supplied 0 arguments | | | expected 1 argument + | +note: function defined here + --> $DIR/E0061.rs:3:4 + | +LL | fn f2(a: u16) {} + | ^^ ------ error: aborting due to 2 previous errors diff --git a/src/test/ui/error-codes/E0424.rs b/src/test/ui/error-codes/E0424.rs index fa0c86ecf48..6e531942cad 100644 --- a/src/test/ui/error-codes/E0424.rs +++ b/src/test/ui/error-codes/E0424.rs @@ -10,6 +10,10 @@ impl Foo { fn baz(_: i32) { self.bar(); //~ ERROR E0424 } + + fn qux() { + let _ = || self.bar(); //~ ERROR E0424 + } } fn main () { diff --git a/src/test/ui/error-codes/E0424.stderr b/src/test/ui/error-codes/E0424.stderr index 9b8a29e8272..20b7a4cb6ec 100644 --- a/src/test/ui/error-codes/E0424.stderr +++ b/src/test/ui/error-codes/E0424.stderr @@ -24,14 +24,27 @@ help: add a `self` receiver parameter to make the associated `fn` a method LL | fn baz(&self, _: i32) { | ^^^^^^ +error[E0424]: expected value, found module `self` + --> $DIR/E0424.rs:15:20 + | +LL | fn qux() { + | --- this function doesn't have a `self` parameter +LL | let _ = || self.bar(); + | ^^^^ `self` value is a keyword only available in methods with a `self` parameter + | +help: add a `self` receiver parameter to make the associated `fn` a method + | +LL | fn qux(&self) { + | ^^^^^ + error[E0424]: expected unit struct, unit variant or constant, found module `self` - --> $DIR/E0424.rs:16:9 + --> $DIR/E0424.rs:20:9 | LL | fn main () { | ---- this function can't have a `self` parameter LL | let self = "self"; | ^^^^ `self` value is a keyword and may not be bound to variables or shadowed -error: aborting due to 3 previous errors +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0424`. diff --git a/src/test/ui/error-codes/E0520.stderr b/src/test/ui/error-codes/E0520.stderr index 1041ccee937..be7b95465a5 100644 --- a/src/test/ui/error-codes/E0520.stderr +++ b/src/test/ui/error-codes/E0520.stderr @@ -6,6 +6,7 @@ LL | #![feature(specialization)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete error[E0520]: `fly` specializes an item from a parent `impl`, but that item is not marked `default` --> $DIR/E0520.rs:17:5 diff --git a/src/test/ui/error-codes/E0730.stderr b/src/test/ui/error-codes/E0730.stderr index f915f6edef5..356e4f36042 100644 --- a/src/test/ui/error-codes/E0730.stderr +++ b/src/test/ui/error-codes/E0730.stderr @@ -6,6 +6,7 @@ LL | #![feature(const_generics)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information + = help: consider using `min_const_generics` instead, which is more stable and complete error[E0730]: cannot pattern-match on an array without a fixed length --> $DIR/E0730.rs:6:9 diff --git a/src/test/ui/error-codes/E0771.stderr b/src/test/ui/error-codes/E0771.stderr index 60220be6b57..b184b599817 100644 --- a/src/test/ui/error-codes/E0771.stderr +++ b/src/test/ui/error-codes/E0771.stderr @@ -6,6 +6,7 @@ LL | #![feature(const_generics)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information + = help: consider using `min_const_generics` instead, which is more stable and complete error[E0771]: use of non-static lifetime `'a` in const generic --> $DIR/E0771.rs:4:41 diff --git a/src/test/ui/error-codes/e0119/issue-28981.stderr b/src/test/ui/error-codes/e0119/issue-28981.stderr index c22cc65c87f..e12dd762331 100644 --- a/src/test/ui/error-codes/e0119/issue-28981.stderr +++ b/src/test/ui/error-codes/e0119/issue-28981.stderr @@ -14,7 +14,7 @@ error[E0210]: type parameter `Foo` must be used as the type parameter for some l LL | impl<Foo> Deref for Foo { } | ^^^ type parameter `Foo` must be used as the type parameter for some local type | - = note: implementing a foreign trait is only possible if at least one of the types for which is it implemented is local + = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local = note: only traits defined in the current crate can be implemented for a type parameter error: aborting due to 2 previous errors diff --git a/src/test/ui/feature-gate-inline_const.rs b/src/test/ui/feature-gate-inline_const.rs new file mode 100644 index 00000000000..43ff90d234c --- /dev/null +++ b/src/test/ui/feature-gate-inline_const.rs @@ -0,0 +1,6 @@ +fn main() { + let _ = const { + //~^ ERROR inline-const is experimental [E0658] + true + }; +} diff --git a/src/test/ui/feature-gate-inline_const.stderr b/src/test/ui/feature-gate-inline_const.stderr new file mode 100644 index 00000000000..be2f567155c --- /dev/null +++ b/src/test/ui/feature-gate-inline_const.stderr @@ -0,0 +1,12 @@ +error[E0658]: inline-const is experimental + --> $DIR/feature-gate-inline_const.rs:2:13 + | +LL | let _ = const { + | ^^^^^ + | + = note: see issue #76001 <https://github.com/rust-lang/rust/issues/76001> for more information + = help: add `#![feature(inline_const)]` to the crate attributes to enable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/feature-gates/feature-gate-untagged_unions.rs b/src/test/ui/feature-gates/feature-gate-untagged_unions.rs index 9ee0e6f681d..f5f9631c3bc 100644 --- a/src/test/ui/feature-gates/feature-gate-untagged_unions.rs +++ b/src/test/ui/feature-gates/feature-gate-untagged_unions.rs @@ -1,3 +1,5 @@ +// ignore-tidy-linelength + union U1 { // OK a: u8, } @@ -6,15 +8,23 @@ union U2<T: Copy> { // OK a: T, } -union U3 { //~ ERROR unions with non-`Copy` fields are unstable +union U22<T> { // OK + a: std::mem::ManuallyDrop<T>, +} + +union U3 { a: String, //~ ERROR unions may not contain fields that need dropping } -union U4<T> { //~ ERROR unions with non-`Copy` fields are unstable +union U32 { // field that does not drop but is not `Copy`, either -- this is the real feature gate test! + a: std::cell::RefCell<i32>, //~ ERROR unions with non-`Copy` fields other than `ManuallyDrop<T>` are unstable +} + +union U4<T> { a: T, //~ ERROR unions may not contain fields that need dropping } -union U5 { //~ ERROR unions with `Drop` implementations are unstable +union U5 { // Having a drop impl is OK a: u8, } diff --git a/src/test/ui/feature-gates/feature-gate-untagged_unions.stderr b/src/test/ui/feature-gates/feature-gate-untagged_unions.stderr index 3a123ea1c93..ed973871b3f 100644 --- a/src/test/ui/feature-gates/feature-gate-untagged_unions.stderr +++ b/src/test/ui/feature-gates/feature-gate-untagged_unions.stderr @@ -1,61 +1,37 @@ -error[E0658]: unions with non-`Copy` fields are unstable - --> $DIR/feature-gate-untagged_unions.rs:9:1 +error[E0658]: unions with non-`Copy` fields other than `ManuallyDrop<T>` are unstable + --> $DIR/feature-gate-untagged_unions.rs:20:5 | -LL | / union U3 { -LL | | a: String, -LL | | } - | |_^ - | - = note: see issue #55149 <https://github.com/rust-lang/rust/issues/55149> for more information - = help: add `#![feature(untagged_unions)]` to the crate attributes to enable - -error[E0658]: unions with non-`Copy` fields are unstable - --> $DIR/feature-gate-untagged_unions.rs:13:1 - | -LL | / union U4<T> { -LL | | a: T, -LL | | } - | |_^ - | - = note: see issue #55149 <https://github.com/rust-lang/rust/issues/55149> for more information - = help: add `#![feature(untagged_unions)]` to the crate attributes to enable - -error[E0658]: unions with `Drop` implementations are unstable - --> $DIR/feature-gate-untagged_unions.rs:17:1 - | -LL | / union U5 { -LL | | a: u8, -LL | | } - | |_^ +LL | a: std::cell::RefCell<i32>, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #55149 <https://github.com/rust-lang/rust/issues/55149> for more information = help: add `#![feature(untagged_unions)]` to the crate attributes to enable error[E0740]: unions may not contain fields that need dropping - --> $DIR/feature-gate-untagged_unions.rs:10:5 + --> $DIR/feature-gate-untagged_unions.rs:16:5 | LL | a: String, | ^^^^^^^^^ | note: `std::mem::ManuallyDrop` can be used to wrap the type - --> $DIR/feature-gate-untagged_unions.rs:10:5 + --> $DIR/feature-gate-untagged_unions.rs:16:5 | LL | a: String, | ^^^^^^^^^ error[E0740]: unions may not contain fields that need dropping - --> $DIR/feature-gate-untagged_unions.rs:14:5 + --> $DIR/feature-gate-untagged_unions.rs:24:5 | LL | a: T, | ^^^^ | note: `std::mem::ManuallyDrop` can be used to wrap the type - --> $DIR/feature-gate-untagged_unions.rs:14:5 + --> $DIR/feature-gate-untagged_unions.rs:24:5 | LL | a: T, | ^^^^ -error: aborting due to 5 previous errors +error: aborting due to 3 previous errors Some errors have detailed explanations: E0658, E0740. For more information about an error, try `rustc --explain E0658`. diff --git a/src/test/ui/generator/generator-yielding-or-returning-itself.stderr b/src/test/ui/generator/generator-yielding-or-returning-itself.stderr index 16a5ab2cc86..5043a3be91d 100644 --- a/src/test/ui/generator/generator-yielding-or-returning-itself.stderr +++ b/src/test/ui/generator/generator-yielding-or-returning-itself.stderr @@ -1,4 +1,4 @@ -error[E0271]: type mismatch resolving `<[generator@$DIR/generator-yielding-or-returning-itself.rs:15:34: 19:6 _] as Generator>::Return == [generator@$DIR/generator-yielding-or-returning-itself.rs:15:34: 19:6 _]` +error[E0271]: type mismatch resolving `<[generator@$DIR/generator-yielding-or-returning-itself.rs:15:34: 19:6] as Generator>::Return == [generator@$DIR/generator-yielding-or-returning-itself.rs:15:34: 19:6]` --> $DIR/generator-yielding-or-returning-itself.rs:15:5 | LL | pub fn want_cyclic_generator_return<T>(_: T) @@ -14,7 +14,7 @@ LL | want_cyclic_generator_return(|| { see issue #46062 <https://github.com/rust-lang/rust/issues/46062> for more information -error[E0271]: type mismatch resolving `<[generator@$DIR/generator-yielding-or-returning-itself.rs:28:33: 32:6 _] as Generator>::Yield == [generator@$DIR/generator-yielding-or-returning-itself.rs:28:33: 32:6 _]` +error[E0271]: type mismatch resolving `<[generator@$DIR/generator-yielding-or-returning-itself.rs:28:33: 32:6] as Generator>::Yield == [generator@$DIR/generator-yielding-or-returning-itself.rs:28:33: 32:6]` --> $DIR/generator-yielding-or-returning-itself.rs:28:5 | LL | pub fn want_cyclic_generator_yield<T>(_: T) diff --git a/src/test/ui/generator/print/generator-print-verbose-2.stderr b/src/test/ui/generator/print/generator-print-verbose-2.stderr index cc45d5631cb..f23949091d9 100644 --- a/src/test/ui/generator/print/generator-print-verbose-2.stderr +++ b/src/test/ui/generator/print/generator-print-verbose-2.stderr @@ -9,7 +9,7 @@ LL | assert_send(|| { | = help: the trait `Sync` is not implemented for `Cell<i32>` = note: required because of the requirements on the impl of `Send` for `&'_#3r Cell<i32>` - = note: required because it appears within the type `[main::{closure#1} upvar_tys=(&'_#3r Cell<i32>) _#16t]` + = note: required because it appears within the type `[main::{closure#1} upvar_tys=(&'_#3r Cell<i32>) _#17t]` error: generator cannot be shared between threads safely --> $DIR/generator-print-verbose-2.rs:12:5 diff --git a/src/test/ui/generator/print/generator-print-verbose-3.stderr b/src/test/ui/generator/print/generator-print-verbose-3.stderr index 0ce108dfd62..d15646259b2 100644 --- a/src/test/ui/generator/print/generator-print-verbose-3.stderr +++ b/src/test/ui/generator/print/generator-print-verbose-3.stderr @@ -12,7 +12,7 @@ LL | | }; | |_____^ expected `()`, found generator | = note: expected unit type `()` - found generator `[main::{closure#0} upvar_tys=(unavailable) _#5t]` + found generator `[main::{closure#0} upvar_tys=(unavailable)]` error: aborting due to previous error diff --git a/src/test/ui/generator/static-not-unpin.stderr b/src/test/ui/generator/static-not-unpin.stderr index 216b707bb16..881064d2f84 100644 --- a/src/test/ui/generator/static-not-unpin.stderr +++ b/src/test/ui/generator/static-not-unpin.stderr @@ -1,11 +1,11 @@ -error[E0277]: `[static generator@$DIR/static-not-unpin.rs:11:25: 13:6 _]` cannot be unpinned +error[E0277]: `[static generator@$DIR/static-not-unpin.rs:11:25: 13:6]` cannot be unpinned --> $DIR/static-not-unpin.rs:14:18 | LL | fn assert_unpin<T: Unpin>(_: T) { | ----- required by this bound in `assert_unpin` ... LL | assert_unpin(generator); - | ^^^^^^^^^ the trait `Unpin` is not implemented for `[static generator@$DIR/static-not-unpin.rs:11:25: 13:6 _]` + | ^^^^^^^^^ the trait `Unpin` is not implemented for `[static generator@$DIR/static-not-unpin.rs:11:25: 13:6]` error: aborting due to previous error diff --git a/src/test/ui/generator/type-mismatch-signature-deduction.stderr b/src/test/ui/generator/type-mismatch-signature-deduction.stderr index 8f6f87f78de..9e111d68a55 100644 --- a/src/test/ui/generator/type-mismatch-signature-deduction.stderr +++ b/src/test/ui/generator/type-mismatch-signature-deduction.stderr @@ -7,7 +7,7 @@ LL | 5 = note: expected type `std::result::Result<{integer}, _>` found type `{integer}` -error[E0271]: type mismatch resolving `<[generator@$DIR/type-mismatch-signature-deduction.rs:6:5: 14:6 _] as Generator>::Return == i32` +error[E0271]: type mismatch resolving `<[generator@$DIR/type-mismatch-signature-deduction.rs:6:5: 14:6] as Generator>::Return == i32` --> $DIR/type-mismatch-signature-deduction.rs:5:13 | LL | fn foo() -> impl Generator<Return = i32> { diff --git a/src/test/ui/generator/yielding-in-match-guards.rs b/src/test/ui/generator/yielding-in-match-guards.rs new file mode 100644 index 00000000000..d8aa354b1c6 --- /dev/null +++ b/src/test/ui/generator/yielding-in-match-guards.rs @@ -0,0 +1,24 @@ +// check-pass +// edition:2018 + +// This test is derived from +// https://github.com/rust-lang/rust/issues/72651#issuecomment-668720468 + +// This test demonstrates that, in `async fn g()`, +// indeed a temporary borrow `y` from `x` is live +// while `f().await` is being evaluated. +// Thus, `&'_ u8` should be included in type signature +// of the underlying generator. + +async fn f() -> u8 { 1 } + +pub async fn g(x: u8) { + match x { + y if f().await == y => (), + _ => (), + } +} + +fn main() { + let _ = g(10); +} diff --git a/src/test/ui/generic-associated-types/issue-74816.rs b/src/test/ui/generic-associated-types/issue-74816.rs new file mode 100644 index 00000000000..754397229a6 --- /dev/null +++ b/src/test/ui/generic-associated-types/issue-74816.rs @@ -0,0 +1,23 @@ +#![feature(associated_type_defaults)] +#![feature(generic_associated_types)] +#![allow(incomplete_features)] + +trait Trait1 { + fn foo(); +} + +trait Trait2 { + type Associated: Trait1 = Self; + //~^ ERROR: the trait bound `Self: Trait1` is not satisfied + //~| the size for values of type `Self` cannot be known +} + +impl Trait2 for () {} + +fn call_foo<T: Trait2>() { + T::Associated::foo() +} + +fn main() { + call_foo::<()>() +} diff --git a/src/test/ui/generic-associated-types/issue-74816.stderr b/src/test/ui/generic-associated-types/issue-74816.stderr new file mode 100644 index 00000000000..64bc94d601b --- /dev/null +++ b/src/test/ui/generic-associated-types/issue-74816.stderr @@ -0,0 +1,31 @@ +error[E0277]: the trait bound `Self: Trait1` is not satisfied + --> $DIR/issue-74816.rs:10:5 + | +LL | type Associated: Trait1 = Self; + | ^^^^^^^^^^^^^^^^^------^^^^^^^^ + | | | + | | required by this bound in `Trait2::Associated` + | the trait `Trait1` is not implemented for `Self` + | +help: consider further restricting `Self` + | +LL | trait Trait2: Trait1 { + | ^^^^^^^^ + +error[E0277]: the size for values of type `Self` cannot be known at compilation time + --> $DIR/issue-74816.rs:10:5 + | +LL | type Associated: Trait1 = Self; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | doesn't have a size known at compile-time + | required by this bound in `Trait2::Associated` + | +help: consider further restricting `Self` + | +LL | trait Trait2: Sized { + | ^^^^^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/glob-resolve1.stderr b/src/test/ui/glob-resolve1.stderr index 3c818f3ae48..cd128c1ea0b 100644 --- a/src/test/ui/glob-resolve1.stderr +++ b/src/test/ui/glob-resolve1.stderr @@ -24,7 +24,17 @@ error[E0423]: expected value, found enum `B` --> $DIR/glob-resolve1.rs:24:5 | LL | B; - | ^ help: try using the enum's variant: `B::B1` + | ^ + | +note: the enum is defined here + --> $DIR/glob-resolve1.rs:12:5 + | +LL | pub enum B { B1 } + | ^^^^^^^^^^^^^^^^^ +help: you might have meant to use the following enum variant + | +LL | B::B1; + | ^^^^^ error[E0425]: cannot find value `C` in this scope --> $DIR/glob-resolve1.rs:25:5 diff --git a/src/test/ui/hrtb/issue-58451.stderr b/src/test/ui/hrtb/issue-58451.stderr index bd08fc1bfae..2cc1c7a2e72 100644 --- a/src/test/ui/hrtb/issue-58451.stderr +++ b/src/test/ui/hrtb/issue-58451.stderr @@ -1,16 +1,16 @@ error[E0061]: this function takes 1 argument but 0 arguments were supplied --> $DIR/issue-58451.rs:12:9 | -LL | / fn f<I>(i: I) -LL | | where -LL | | I: IntoIterator, -LL | | I::Item: for<'a> Into<&'a ()>, - | |__________________________________- defined here -... -LL | f(&[f()]); - | ^-- supplied 0 arguments - | | - | expected 1 argument +LL | f(&[f()]); + | ^-- supplied 0 arguments + | | + | expected 1 argument + | +note: function defined here + --> $DIR/issue-58451.rs:5:4 + | +LL | fn f<I>(i: I) + | ^ ---- error: aborting due to previous error diff --git a/src/test/ui/hygiene/generic_params.stderr b/src/test/ui/hygiene/generic_params.stderr index 4ca6d199835..6de36deb597 100644 --- a/src/test/ui/hygiene/generic_params.stderr +++ b/src/test/ui/hygiene/generic_params.stderr @@ -6,6 +6,7 @@ LL | #![feature(decl_macro, rustc_attrs, const_generics)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information + = help: consider using `min_const_generics` instead, which is more stable and complete warning: 1 warning emitted diff --git a/src/test/ui/hygiene/issue-61574-const-parameters.stderr b/src/test/ui/hygiene/issue-61574-const-parameters.stderr index b351b8b73a0..3f85383eb33 100644 --- a/src/test/ui/hygiene/issue-61574-const-parameters.stderr +++ b/src/test/ui/hygiene/issue-61574-const-parameters.stderr @@ -6,6 +6,7 @@ LL | #![feature(const_generics)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information + = help: consider using `min_const_generics` instead, which is more stable and complete warning: 1 warning emitted diff --git a/src/test/ui/hygiene/no_implicit_prelude-2018.stderr b/src/test/ui/hygiene/no_implicit_prelude-2018.stderr index f31b75238df..02ddc391f6e 100644 --- a/src/test/ui/hygiene/no_implicit_prelude-2018.stderr +++ b/src/test/ui/hygiene/no_implicit_prelude-2018.stderr @@ -3,6 +3,9 @@ error: cannot find macro `print` in this scope | LL | print!(); | ^^^^^ + | + = note: consider importing this macro: + std::print error: aborting due to previous error diff --git a/src/test/ui/hygiene/no_implicit_prelude.stderr b/src/test/ui/hygiene/no_implicit_prelude.stderr index 3c0c0450774..843dee2478b 100644 --- a/src/test/ui/hygiene/no_implicit_prelude.stderr +++ b/src/test/ui/hygiene/no_implicit_prelude.stderr @@ -4,6 +4,9 @@ error: cannot find macro `panic` in this scope LL | assert_eq!(0, 0); | ^^^^^^^^^^^^^^^^^ | + = note: consider importing one of these items: + core::panic + std::panic = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error[E0433]: failed to resolve: use of undeclared type `Vec` diff --git a/src/test/ui/impl-trait/equality-rpass.stderr b/src/test/ui/impl-trait/equality-rpass.stderr index 1abf05dca82..11eeceba0ee 100644 --- a/src/test/ui/impl-trait/equality-rpass.stderr +++ b/src/test/ui/impl-trait/equality-rpass.stderr @@ -6,6 +6,7 @@ LL | #![feature(specialization)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete warning: 1 warning emitted diff --git a/src/test/ui/impl-trait/equality.stderr b/src/test/ui/impl-trait/equality.stderr index cdaa61ac323..536a4726c6d 100644 --- a/src/test/ui/impl-trait/equality.stderr +++ b/src/test/ui/impl-trait/equality.stderr @@ -6,6 +6,7 @@ LL | #![feature(specialization)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete error[E0308]: mismatched types --> $DIR/equality.rs:15:5 diff --git a/src/test/ui/impl-trait/equality2.stderr b/src/test/ui/impl-trait/equality2.stderr index 1780931efc5..1443b76048b 100644 --- a/src/test/ui/impl-trait/equality2.stderr +++ b/src/test/ui/impl-trait/equality2.stderr @@ -6,6 +6,7 @@ LL | #![feature(specialization)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete error[E0308]: mismatched types --> $DIR/equality2.rs:25:18 diff --git a/src/test/ui/impl-trait/issues/issue-65581.rs b/src/test/ui/impl-trait/issues/issue-65581.rs new file mode 100644 index 00000000000..af65b79d3e8 --- /dev/null +++ b/src/test/ui/impl-trait/issues/issue-65581.rs @@ -0,0 +1,33 @@ +// check-pass + +#![allow(dead_code)] + +trait Trait1<T, U> { + fn f1(self) -> U; +} + +trait Trait2 { + type T; + type U: Trait2<T = Self::T>; + fn f2(f: impl FnOnce(&Self::U)); +} + +fn f3<T: Trait2>() -> impl Trait1<T, T::T> { + Struct1 +} + +struct Struct1; + +impl<T: Trait2> Trait1<T, T::T> for Struct1 { + fn f1(self) -> T::T { + unimplemented!() + } +} + +fn f4<T: Trait2>() { + T::f2(|_| { + f3::<T::U>().f1(); + }); +} + +fn main() {} diff --git a/src/test/ui/impl-trait/issues/issue-70877.rs b/src/test/ui/impl-trait/issues/issue-70877.rs new file mode 100644 index 00000000000..a4a59f98fd8 --- /dev/null +++ b/src/test/ui/impl-trait/issues/issue-70877.rs @@ -0,0 +1,38 @@ +#![feature(type_alias_impl_trait)] +#![feature(impl_trait_in_bindings)] +#![allow(incomplete_features)] + +type FooArg<'a> = &'a dyn ToString; +type FooRet = impl std::fmt::Debug; + +type FooItem = Box<dyn Fn(FooArg) -> FooRet>; +type Foo = impl Iterator<Item = FooItem>; //~ ERROR: type mismatch + +#[repr(C)] +struct Bar(u8); + +impl Iterator for Bar { + type Item = FooItem; + + fn next(&mut self) -> Option<Self::Item> { + Some(Box::new(quux)) + } +} + +fn quux(st: FooArg) -> FooRet { + Some(st.to_string()) +} + +fn ham() -> Foo { + Bar(1) +} + +fn oof() -> impl std::fmt::Debug { + let mut bar = ham(); + let func = bar.next().unwrap(); + return func(&"oof"); +} + +fn main() { + let _ = oof(); +} diff --git a/src/test/ui/impl-trait/issues/issue-70877.stderr b/src/test/ui/impl-trait/issues/issue-70877.stderr new file mode 100644 index 00000000000..3ef7087b08a --- /dev/null +++ b/src/test/ui/impl-trait/issues/issue-70877.stderr @@ -0,0 +1,15 @@ +error[E0271]: type mismatch resolving `<Bar as Iterator>::Item == Box<(dyn for<'r> Fn(&'r (dyn ToString + 'r)) -> Option<String> + 'static)>` + --> $DIR/issue-70877.rs:9:12 + | +LL | type FooRet = impl std::fmt::Debug; + | -------------------- the expected opaque type +... +LL | type Foo = impl Iterator<Item = FooItem>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected opaque type, found enum `Option` + | + = note: expected struct `Box<(dyn for<'r> Fn(&'r (dyn ToString + 'r)) -> impl Debug + 'static)>` + found struct `Box<(dyn for<'r> Fn(&'r (dyn ToString + 'r)) -> Option<String> + 'static)>` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0271`. diff --git a/src/test/ui/indexing-requires-a-uint.stderr b/src/test/ui/indexing-requires-a-uint.stderr index 31fcd4b1c2e..3152dec30a0 100644 --- a/src/test/ui/indexing-requires-a-uint.stderr +++ b/src/test/ui/indexing-requires-a-uint.stderr @@ -13,7 +13,7 @@ error[E0308]: mismatched types LL | bar::<isize>(i); // i should not be re-coerced back to an isize | ^ expected `isize`, found `usize` | -help: you can convert an `usize` to `isize` and panic if the converted value wouldn't fit +help: you can convert a `usize` to an `isize` and panic if the converted value doesn't fit | LL | bar::<isize>(i.try_into().unwrap()); // i should not be re-coerced back to an isize | ^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/inline-const/const-expr-array-init.rs b/src/test/ui/inline-const/const-expr-array-init.rs new file mode 100644 index 00000000000..8bb5dab1fa0 --- /dev/null +++ b/src/test/ui/inline-const/const-expr-array-init.rs @@ -0,0 +1,10 @@ +// build-pass + +#![allow(incomplete_features)] +#![feature(inline_const)] + +use std::cell::Cell; + +fn main() { + let _x = [const { Cell::new(0) }; 20]; +} diff --git a/src/test/ui/inline-const/const-expr-basic.rs b/src/test/ui/inline-const/const-expr-basic.rs new file mode 100644 index 00000000000..9254c96a1e7 --- /dev/null +++ b/src/test/ui/inline-const/const-expr-basic.rs @@ -0,0 +1,14 @@ +// run-pass + +#![allow(incomplete_features)] +#![feature(inline_const)] +fn foo() -> i32 { + const { + let x = 5 + 10; + x / 3 + } +} + +fn main() { + assert_eq!(5, foo()); +} diff --git a/src/test/ui/inline-const/const-expr-reference.rs b/src/test/ui/inline-const/const-expr-reference.rs new file mode 100644 index 00000000000..747f14e4bd0 --- /dev/null +++ b/src/test/ui/inline-const/const-expr-reference.rs @@ -0,0 +1,15 @@ +// run-pass + +#![allow(incomplete_features)] +#![feature(inline_const)] + +const fn bar() -> i32 { + const { + 2 + 3 + } +} + +fn main() { + let x: &'static i32 = &const{bar()}; + assert_eq!(&5, x); +} diff --git a/src/test/ui/inline-const/const-match-pat.rs b/src/test/ui/inline-const/const-match-pat.rs new file mode 100644 index 00000000000..c0dc90d971a --- /dev/null +++ b/src/test/ui/inline-const/const-match-pat.rs @@ -0,0 +1,21 @@ +// run-pass + +#![allow(incomplete_features)] +#![feature(inline_const)] +const MMIO_BIT1: u8 = 4; +const MMIO_BIT2: u8 = 5; + +fn main() { + let s = match read_mmio() { + 0 => "FOO", + const { 1 << MMIO_BIT1 } => "BAR", + const { 1 << MMIO_BIT2 } => "BAZ", + _ => unreachable!(), + }; + + assert_eq!("BAZ", s); +} + +fn read_mmio() -> i32 { + 1 << 5 +} diff --git a/src/test/ui/integer-literal-suffix-inference.stderr b/src/test/ui/integer-literal-suffix-inference.stderr index b8502768e1d..bfb47515823 100644 --- a/src/test/ui/integer-literal-suffix-inference.stderr +++ b/src/test/ui/integer-literal-suffix-inference.stderr @@ -4,7 +4,7 @@ error[E0308]: mismatched types LL | id_i8(a16); | ^^^ expected `i8`, found `i16` | -help: you can convert an `i16` to `i8` and panic if the converted value wouldn't fit +help: you can convert an `i16` to an `i8` and panic if the converted value doesn't fit | LL | id_i8(a16.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -15,7 +15,7 @@ error[E0308]: mismatched types LL | id_i8(a32); | ^^^ expected `i8`, found `i32` | -help: you can convert an `i32` to `i8` and panic if the converted value wouldn't fit +help: you can convert an `i32` to an `i8` and panic if the converted value doesn't fit | LL | id_i8(a32.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -26,7 +26,7 @@ error[E0308]: mismatched types LL | id_i8(a64); | ^^^ expected `i8`, found `i64` | -help: you can convert an `i64` to `i8` and panic if the converted value wouldn't fit +help: you can convert an `i64` to an `i8` and panic if the converted value doesn't fit | LL | id_i8(a64.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -37,7 +37,7 @@ error[E0308]: mismatched types LL | id_i8(asize); | ^^^^^ expected `i8`, found `isize` | -help: you can convert an `isize` to `i8` and panic if the converted value wouldn't fit +help: you can convert an `isize` to an `i8` and panic if the converted value doesn't fit | LL | id_i8(asize.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -49,7 +49,7 @@ LL | id_i16(a8); | ^^ | | | expected `i16`, found `i8` - | help: you can convert an `i8` to `i16`: `a8.into()` + | help: you can convert an `i8` to an `i16`: `a8.into()` error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:55:12 @@ -57,7 +57,7 @@ error[E0308]: mismatched types LL | id_i16(a32); | ^^^ expected `i16`, found `i32` | -help: you can convert an `i32` to `i16` and panic if the converted value wouldn't fit +help: you can convert an `i32` to an `i16` and panic if the converted value doesn't fit | LL | id_i16(a32.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -68,7 +68,7 @@ error[E0308]: mismatched types LL | id_i16(a64); | ^^^ expected `i16`, found `i64` | -help: you can convert an `i64` to `i16` and panic if the converted value wouldn't fit +help: you can convert an `i64` to an `i16` and panic if the converted value doesn't fit | LL | id_i16(a64.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -79,7 +79,7 @@ error[E0308]: mismatched types LL | id_i16(asize); | ^^^^^ expected `i16`, found `isize` | -help: you can convert an `isize` to `i16` and panic if the converted value wouldn't fit +help: you can convert an `isize` to an `i16` and panic if the converted value doesn't fit | LL | id_i16(asize.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -91,7 +91,7 @@ LL | id_i32(a8); | ^^ | | | expected `i32`, found `i8` - | help: you can convert an `i8` to `i32`: `a8.into()` + | help: you can convert an `i8` to an `i32`: `a8.into()` error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:68:12 @@ -100,7 +100,7 @@ LL | id_i32(a16); | ^^^ | | | expected `i32`, found `i16` - | help: you can convert an `i16` to `i32`: `a16.into()` + | help: you can convert an `i16` to an `i32`: `a16.into()` error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:72:12 @@ -108,7 +108,7 @@ error[E0308]: mismatched types LL | id_i32(a64); | ^^^ expected `i32`, found `i64` | -help: you can convert an `i64` to `i32` and panic if the converted value wouldn't fit +help: you can convert an `i64` to an `i32` and panic if the converted value doesn't fit | LL | id_i32(a64.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -119,7 +119,7 @@ error[E0308]: mismatched types LL | id_i32(asize); | ^^^^^ expected `i32`, found `isize` | -help: you can convert an `isize` to `i32` and panic if the converted value wouldn't fit +help: you can convert an `isize` to an `i32` and panic if the converted value doesn't fit | LL | id_i32(asize.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -131,7 +131,7 @@ LL | id_i64(a8); | ^^ | | | expected `i64`, found `i8` - | help: you can convert an `i8` to `i64`: `a8.into()` + | help: you can convert an `i8` to an `i64`: `a8.into()` error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:82:12 @@ -140,7 +140,7 @@ LL | id_i64(a16); | ^^^ | | | expected `i64`, found `i16` - | help: you can convert an `i16` to `i64`: `a16.into()` + | help: you can convert an `i16` to an `i64`: `a16.into()` error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:85:12 @@ -149,7 +149,7 @@ LL | id_i64(a32); | ^^^ | | | expected `i64`, found `i32` - | help: you can convert an `i32` to `i64`: `a32.into()` + | help: you can convert an `i32` to an `i64`: `a32.into()` error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:89:12 @@ -157,7 +157,7 @@ error[E0308]: mismatched types LL | id_i64(asize); | ^^^^^ expected `i64`, found `isize` | -help: you can convert an `isize` to `i64` and panic if the converted value wouldn't fit +help: you can convert an `isize` to an `i64` and panic if the converted value doesn't fit | LL | id_i64(asize.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -169,7 +169,7 @@ LL | id_isize(a8); | ^^ | | | expected `isize`, found `i8` - | help: you can convert an `i8` to `isize`: `a8.into()` + | help: you can convert an `i8` to an `isize`: `a8.into()` error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:96:14 @@ -178,7 +178,7 @@ LL | id_isize(a16); | ^^^ | | | expected `isize`, found `i16` - | help: you can convert an `i16` to `isize`: `a16.into()` + | help: you can convert an `i16` to an `isize`: `a16.into()` error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:99:14 @@ -186,7 +186,7 @@ error[E0308]: mismatched types LL | id_isize(a32); | ^^^ expected `isize`, found `i32` | -help: you can convert an `i32` to `isize` and panic if the converted value wouldn't fit +help: you can convert an `i32` to an `isize` and panic if the converted value doesn't fit | LL | id_isize(a32.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -197,7 +197,7 @@ error[E0308]: mismatched types LL | id_isize(a64); | ^^^ expected `isize`, found `i64` | -help: you can convert an `i64` to `isize` and panic if the converted value wouldn't fit +help: you can convert an `i64` to an `isize` and panic if the converted value doesn't fit | LL | id_isize(a64.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -208,7 +208,7 @@ error[E0308]: mismatched types LL | id_i8(c16); | ^^^ expected `i8`, found `i16` | -help: you can convert an `i16` to `i8` and panic if the converted value wouldn't fit +help: you can convert an `i16` to an `i8` and panic if the converted value doesn't fit | LL | id_i8(c16.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -219,7 +219,7 @@ error[E0308]: mismatched types LL | id_i8(c32); | ^^^ expected `i8`, found `i32` | -help: you can convert an `i32` to `i8` and panic if the converted value wouldn't fit +help: you can convert an `i32` to an `i8` and panic if the converted value doesn't fit | LL | id_i8(c32.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -230,7 +230,7 @@ error[E0308]: mismatched types LL | id_i8(c64); | ^^^ expected `i8`, found `i64` | -help: you can convert an `i64` to `i8` and panic if the converted value wouldn't fit +help: you can convert an `i64` to an `i8` and panic if the converted value doesn't fit | LL | id_i8(c64.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -242,7 +242,7 @@ LL | id_i16(c8); | ^^ | | | expected `i16`, found `i8` - | help: you can convert an `i8` to `i16`: `c8.into()` + | help: you can convert an `i8` to an `i16`: `c8.into()` error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:122:12 @@ -250,7 +250,7 @@ error[E0308]: mismatched types LL | id_i16(c32); | ^^^ expected `i16`, found `i32` | -help: you can convert an `i32` to `i16` and panic if the converted value wouldn't fit +help: you can convert an `i32` to an `i16` and panic if the converted value doesn't fit | LL | id_i16(c32.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -261,7 +261,7 @@ error[E0308]: mismatched types LL | id_i16(c64); | ^^^ expected `i16`, found `i64` | -help: you can convert an `i64` to `i16` and panic if the converted value wouldn't fit +help: you can convert an `i64` to an `i16` and panic if the converted value doesn't fit | LL | id_i16(c64.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -273,7 +273,7 @@ LL | id_i32(c8); | ^^ | | | expected `i32`, found `i8` - | help: you can convert an `i8` to `i32`: `c8.into()` + | help: you can convert an `i8` to an `i32`: `c8.into()` error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:132:12 @@ -282,7 +282,7 @@ LL | id_i32(c16); | ^^^ | | | expected `i32`, found `i16` - | help: you can convert an `i16` to `i32`: `c16.into()` + | help: you can convert an `i16` to an `i32`: `c16.into()` error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:136:12 @@ -290,7 +290,7 @@ error[E0308]: mismatched types LL | id_i32(c64); | ^^^ expected `i32`, found `i64` | -help: you can convert an `i64` to `i32` and panic if the converted value wouldn't fit +help: you can convert an `i64` to an `i32` and panic if the converted value doesn't fit | LL | id_i32(c64.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -302,7 +302,7 @@ LL | id_i64(a8); | ^^ | | | expected `i64`, found `i8` - | help: you can convert an `i8` to `i64`: `a8.into()` + | help: you can convert an `i8` to an `i64`: `a8.into()` error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:143:12 @@ -311,7 +311,7 @@ LL | id_i64(a16); | ^^^ | | | expected `i64`, found `i16` - | help: you can convert an `i16` to `i64`: `a16.into()` + | help: you can convert an `i16` to an `i64`: `a16.into()` error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:146:12 @@ -320,7 +320,7 @@ LL | id_i64(a32); | ^^^ | | | expected `i64`, found `i32` - | help: you can convert an `i32` to `i64`: `a32.into()` + | help: you can convert an `i32` to an `i64`: `a32.into()` error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:152:11 @@ -328,7 +328,7 @@ error[E0308]: mismatched types LL | id_u8(b16); | ^^^ expected `u8`, found `u16` | -help: you can convert an `u16` to `u8` and panic if the converted value wouldn't fit +help: you can convert a `u16` to a `u8` and panic if the converted value doesn't fit | LL | id_u8(b16.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -339,7 +339,7 @@ error[E0308]: mismatched types LL | id_u8(b32); | ^^^ expected `u8`, found `u32` | -help: you can convert an `u32` to `u8` and panic if the converted value wouldn't fit +help: you can convert a `u32` to a `u8` and panic if the converted value doesn't fit | LL | id_u8(b32.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -350,7 +350,7 @@ error[E0308]: mismatched types LL | id_u8(b64); | ^^^ expected `u8`, found `u64` | -help: you can convert an `u64` to `u8` and panic if the converted value wouldn't fit +help: you can convert a `u64` to a `u8` and panic if the converted value doesn't fit | LL | id_u8(b64.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -361,7 +361,7 @@ error[E0308]: mismatched types LL | id_u8(bsize); | ^^^^^ expected `u8`, found `usize` | -help: you can convert an `usize` to `u8` and panic if the converted value wouldn't fit +help: you can convert a `usize` to a `u8` and panic if the converted value doesn't fit | LL | id_u8(bsize.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -373,7 +373,7 @@ LL | id_u16(b8); | ^^ | | | expected `u16`, found `u8` - | help: you can convert an `u8` to `u16`: `b8.into()` + | help: you can convert a `u8` to a `u16`: `b8.into()` error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:169:12 @@ -381,7 +381,7 @@ error[E0308]: mismatched types LL | id_u16(b32); | ^^^ expected `u16`, found `u32` | -help: you can convert an `u32` to `u16` and panic if the converted value wouldn't fit +help: you can convert a `u32` to a `u16` and panic if the converted value doesn't fit | LL | id_u16(b32.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -392,7 +392,7 @@ error[E0308]: mismatched types LL | id_u16(b64); | ^^^ expected `u16`, found `u64` | -help: you can convert an `u64` to `u16` and panic if the converted value wouldn't fit +help: you can convert a `u64` to a `u16` and panic if the converted value doesn't fit | LL | id_u16(b64.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -403,7 +403,7 @@ error[E0308]: mismatched types LL | id_u16(bsize); | ^^^^^ expected `u16`, found `usize` | -help: you can convert an `usize` to `u16` and panic if the converted value wouldn't fit +help: you can convert a `usize` to a `u16` and panic if the converted value doesn't fit | LL | id_u16(bsize.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -415,7 +415,7 @@ LL | id_u32(b8); | ^^ | | | expected `u32`, found `u8` - | help: you can convert an `u8` to `u32`: `b8.into()` + | help: you can convert a `u8` to a `u32`: `b8.into()` error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:182:12 @@ -424,7 +424,7 @@ LL | id_u32(b16); | ^^^ | | | expected `u32`, found `u16` - | help: you can convert an `u16` to `u32`: `b16.into()` + | help: you can convert a `u16` to a `u32`: `b16.into()` error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:186:12 @@ -432,7 +432,7 @@ error[E0308]: mismatched types LL | id_u32(b64); | ^^^ expected `u32`, found `u64` | -help: you can convert an `u64` to `u32` and panic if the converted value wouldn't fit +help: you can convert a `u64` to a `u32` and panic if the converted value doesn't fit | LL | id_u32(b64.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -443,7 +443,7 @@ error[E0308]: mismatched types LL | id_u32(bsize); | ^^^^^ expected `u32`, found `usize` | -help: you can convert an `usize` to `u32` and panic if the converted value wouldn't fit +help: you can convert a `usize` to a `u32` and panic if the converted value doesn't fit | LL | id_u32(bsize.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -455,7 +455,7 @@ LL | id_u64(b8); | ^^ | | | expected `u64`, found `u8` - | help: you can convert an `u8` to `u64`: `b8.into()` + | help: you can convert a `u8` to a `u64`: `b8.into()` error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:196:12 @@ -464,7 +464,7 @@ LL | id_u64(b16); | ^^^ | | | expected `u64`, found `u16` - | help: you can convert an `u16` to `u64`: `b16.into()` + | help: you can convert a `u16` to a `u64`: `b16.into()` error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:199:12 @@ -473,7 +473,7 @@ LL | id_u64(b32); | ^^^ | | | expected `u64`, found `u32` - | help: you can convert an `u32` to `u64`: `b32.into()` + | help: you can convert a `u32` to a `u64`: `b32.into()` error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:203:12 @@ -481,7 +481,7 @@ error[E0308]: mismatched types LL | id_u64(bsize); | ^^^^^ expected `u64`, found `usize` | -help: you can convert an `usize` to `u64` and panic if the converted value wouldn't fit +help: you can convert a `usize` to a `u64` and panic if the converted value doesn't fit | LL | id_u64(bsize.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -493,7 +493,7 @@ LL | id_usize(b8); | ^^ | | | expected `usize`, found `u8` - | help: you can convert an `u8` to `usize`: `b8.into()` + | help: you can convert a `u8` to a `usize`: `b8.into()` error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:210:14 @@ -502,7 +502,7 @@ LL | id_usize(b16); | ^^^ | | | expected `usize`, found `u16` - | help: you can convert an `u16` to `usize`: `b16.into()` + | help: you can convert a `u16` to a `usize`: `b16.into()` error[E0308]: mismatched types --> $DIR/integer-literal-suffix-inference.rs:213:14 @@ -510,7 +510,7 @@ error[E0308]: mismatched types LL | id_usize(b32); | ^^^ expected `usize`, found `u32` | -help: you can convert an `u32` to `usize` and panic if the converted value wouldn't fit +help: you can convert a `u32` to a `usize` and panic if the converted value doesn't fit | LL | id_usize(b32.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -521,7 +521,7 @@ error[E0308]: mismatched types LL | id_usize(b64); | ^^^ expected `usize`, found `u64` | -help: you can convert an `u64` to `usize` and panic if the converted value wouldn't fit +help: you can convert a `u64` to a `usize` and panic if the converted value doesn't fit | LL | id_usize(b64.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/issues/issue-13359.stderr b/src/test/ui/issues/issue-13359.stderr index 68258a8888a..115b471e96b 100644 --- a/src/test/ui/issues/issue-13359.stderr +++ b/src/test/ui/issues/issue-13359.stderr @@ -4,7 +4,7 @@ error[E0308]: mismatched types LL | foo(1*(1 as isize)); | ^^^^^^^^^^^^^^ expected `i16`, found `isize` | -help: you can convert an `isize` to `i16` and panic if the converted value wouldn't fit +help: you can convert an `isize` to an `i16` and panic if the converted value doesn't fit | LL | foo((1*(1 as isize)).try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -15,7 +15,7 @@ error[E0308]: mismatched types LL | bar(1*(1 as usize)); | ^^^^^^^^^^^^^^ expected `u32`, found `usize` | -help: you can convert an `usize` to `u32` and panic if the converted value wouldn't fit +help: you can convert a `usize` to a `u32` and panic if the converted value doesn't fit | LL | bar((1*(1 as usize)).try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/issues/issue-18819.stderr b/src/test/ui/issues/issue-18819.stderr index a952c9b46c9..b10d26abe34 100644 --- a/src/test/ui/issues/issue-18819.stderr +++ b/src/test/ui/issues/issue-18819.stderr @@ -1,13 +1,16 @@ error[E0061]: this function takes 2 arguments but 1 argument was supplied --> $DIR/issue-18819.rs:16:5 | -LL | fn print_x(_: &dyn Foo<Item=bool>, extra: &str) { - | ----------------------------------------------- defined here -... LL | print_x(X); | ^^^^^^^ - supplied 1 argument | | | expected 2 arguments + | +note: function defined here + --> $DIR/issue-18819.rs:11:4 + | +LL | fn print_x(_: &dyn Foo<Item=bool>, extra: &str) { + | ^^^^^^^ ---------------------- ----------- error: aborting due to previous error diff --git a/src/test/ui/issues/issue-26094.stderr b/src/test/ui/issues/issue-26094.stderr index 2038d88bf46..a6f1ac9286c 100644 --- a/src/test/ui/issues/issue-26094.stderr +++ b/src/test/ui/issues/issue-26094.stderr @@ -4,11 +4,14 @@ error[E0061]: this function takes 0 arguments but 1 argument was supplied LL | $other(None) | ---- supplied 1 argument ... -LL | fn some_function() {} - | ------------------ defined here -... LL | some_macro!(some_function); | ^^^^^^^^^^^^^ expected 0 arguments + | +note: function defined here + --> $DIR/issue-26094.rs:7:4 + | +LL | fn some_function() {} + | ^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-35376.stderr b/src/test/ui/issues/issue-35376.stderr index 06c31f3bae0..835277d408e 100644 --- a/src/test/ui/issues/issue-35376.stderr +++ b/src/test/ui/issues/issue-35376.stderr @@ -6,6 +6,7 @@ LL | #![feature(specialization)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete warning: 1 warning emitted diff --git a/src/test/ui/issues/issue-41974.stderr b/src/test/ui/issues/issue-41974.stderr index f1342181b37..a092c94b9d5 100644 --- a/src/test/ui/issues/issue-41974.stderr +++ b/src/test/ui/issues/issue-41974.stderr @@ -21,7 +21,7 @@ error[E0210]: type parameter `T` must be used as the type parameter for some loc LL | impl<T> Drop for T where T: A { | ^ type parameter `T` must be used as the type parameter for some local type | - = note: implementing a foreign trait is only possible if at least one of the types for which is it implemented is local + = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local = note: only traits defined in the current crate can be implemented for a type parameter error: aborting due to 3 previous errors diff --git a/src/test/ui/issues/issue-4935.stderr b/src/test/ui/issues/issue-4935.stderr index 0cc686e1cf8..03b9b91edef 100644 --- a/src/test/ui/issues/issue-4935.stderr +++ b/src/test/ui/issues/issue-4935.stderr @@ -1,13 +1,16 @@ error[E0061]: this function takes 1 argument but 2 arguments were supplied --> $DIR/issue-4935.rs:5:13 | -LL | fn foo(a: usize) {} - | ---------------- defined here -LL | LL | fn main() { foo(5, 6) } | ^^^ - - supplied 2 arguments | | | expected 1 argument + | +note: function defined here + --> $DIR/issue-4935.rs:3:4 + | +LL | fn foo(a: usize) {} + | ^^^ -------- error: aborting due to previous error diff --git a/src/test/ui/issues/issue-5099.rs b/src/test/ui/issues/issue-5099.rs index ee134835c37..b5abccb4b19 100644 --- a/src/test/ui/issues/issue-5099.rs +++ b/src/test/ui/issues/issue-5099.rs @@ -5,6 +5,9 @@ trait B <A> { fn b(x: i32) { this.b(x); //~ ERROR cannot find value `this` in this scope } + fn c() { + let _ = || this.a; //~ ERROR cannot find value `this` in this scope + } } fn main() {} diff --git a/src/test/ui/issues/issue-5099.stderr b/src/test/ui/issues/issue-5099.stderr index b52fd28b2b5..b39c4a9f272 100644 --- a/src/test/ui/issues/issue-5099.stderr +++ b/src/test/ui/issues/issue-5099.stderr @@ -28,6 +28,21 @@ help: if you meant to use `self`, you are also missing a `self` receiver argumen LL | fn b(&self, x: i32) { | ^^^^^^ -error: aborting due to 2 previous errors +error[E0425]: cannot find value `this` in this scope + --> $DIR/issue-5099.rs:9:20 + | +LL | let _ = || this.a; + | ^^^^ not found in this scope + | +help: you might have meant to use `self` here instead + | +LL | let _ = || self.a; + | ^^^^ +help: if you meant to use `self`, you are also missing a `self` receiver argument + | +LL | fn c(&self) { + | ^^^^^ + +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0425`. diff --git a/src/test/ui/issues/issue-55380.stderr b/src/test/ui/issues/issue-55380.stderr index 451beebd106..65e94d79670 100644 --- a/src/test/ui/issues/issue-55380.stderr +++ b/src/test/ui/issues/issue-55380.stderr @@ -6,6 +6,7 @@ LL | #![feature(specialization)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete warning: 1 warning emitted diff --git a/src/test/ui/issues/issue-59508-1.stderr b/src/test/ui/issues/issue-59508-1.stderr index 5e97339f148..2a4ccda8929 100644 --- a/src/test/ui/issues/issue-59508-1.stderr +++ b/src/test/ui/issues/issue-59508-1.stderr @@ -12,6 +12,7 @@ LL | #![feature(const_generics)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information + = help: consider using `min_const_generics` instead, which is more stable and complete error: aborting due to previous error; 1 warning emitted diff --git a/src/test/ui/issues/issue-73427.stderr b/src/test/ui/issues/issue-73427.stderr index 88d19943f02..4b5f65b3461 100644 --- a/src/test/ui/issues/issue-73427.stderr +++ b/src/test/ui/issues/issue-73427.stderr @@ -4,8 +4,18 @@ error[E0423]: expected value, found enum `A` LL | A.foo(); | ^ | - = help: you might have meant to use one of the enum's other variants that have fields -help: try using one of the enum's variants +note: the enum is defined here + --> $DIR/issue-73427.rs:1:1 + | +LL | / enum A { +LL | | StructWithFields { x: () }, +LL | | TupleWithFields(()), +LL | | Struct {}, +LL | | Tuple(), +LL | | Unit, +LL | | } + | |_^ +help: you might have meant to use one of the following enum variants | LL | (A::Struct {}).foo(); | ^^^^^^^^^^^^^^ @@ -13,6 +23,12 @@ LL | (A::Tuple()).foo(); | ^^^^^^^^^^^^ LL | A::Unit.foo(); | ^^^^^^^ +help: the following enum variants are available + | +LL | (A::StructWithFields { /* fields */ }).foo(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | (A::TupleWithFields(/* fields */)).foo(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0423]: expected value, found enum `B` --> $DIR/issue-73427.rs:31:5 @@ -20,23 +36,69 @@ error[E0423]: expected value, found enum `B` LL | B.foo(); | ^ | - = help: you might have meant to use one of the enum's variants +note: the enum is defined here + --> $DIR/issue-73427.rs:9:1 + | +LL | / enum B { +LL | | StructWithFields { x: () }, +LL | | TupleWithFields(()), +LL | | } + | |_^ +help: the following enum variants are available + | +LL | (B::StructWithFields { /* fields */ }).foo(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | (B::TupleWithFields(/* fields */)).foo(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0423]: expected value, found enum `C` --> $DIR/issue-73427.rs:33:5 | LL | C.foo(); - | ^ help: try using one of the enum's variants: `C::Unit` + | ^ + | +note: the enum is defined here + --> $DIR/issue-73427.rs:14:1 + | +LL | / enum C { +LL | | StructWithFields { x: () }, +LL | | TupleWithFields(()), +LL | | Unit, +LL | | } + | |_^ +help: you might have meant to use the following enum variant + | +LL | C::Unit.foo(); + | ^^^^^^^ +help: the following enum variants are available | - = help: you might have meant to use one of the enum's other variants that have fields +LL | (C::StructWithFields { /* fields */ }).foo(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | (C::TupleWithFields(/* fields */)).foo(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0423]: expected value, found enum `D` --> $DIR/issue-73427.rs:35:5 | LL | D.foo(); - | ^ help: try using one of the enum's variants: `D::Unit` + | ^ + | +note: the enum is defined here + --> $DIR/issue-73427.rs:20:1 + | +LL | / enum D { +LL | | TupleWithFields(()), +LL | | Unit, +LL | | } + | |_^ +help: you might have meant to use the following enum variant | - = help: you might have meant to use the enum's other variant that has fields +LL | D::Unit.foo(); + | ^^^^^^^ +help: the following enum variant is available + | +LL | (D::TupleWithFields(/* fields */)).foo(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0423]: expected function, tuple struct or tuple variant, found enum `A` --> $DIR/issue-73427.rs:40:13 @@ -45,7 +107,18 @@ LL | let x = A(3); | ^ | = help: you might have meant to construct one of the enum's non-tuple variants -help: try using one of the enum's variants +note: the enum is defined here + --> $DIR/issue-73427.rs:1:1 + | +LL | / enum A { +LL | | StructWithFields { x: () }, +LL | | TupleWithFields(()), +LL | | Struct {}, +LL | | Tuple(), +LL | | Unit, +LL | | } + | |_^ +help: try to construct one of the enum's variants | LL | let x = A::TupleWithFields(3); | ^^^^^^^^^^^^^^^^^^ @@ -59,7 +132,18 @@ LL | if let A(3) = x { } | ^ | = help: you might have meant to match against one of the enum's non-tuple variants -help: try using one of the enum's variants +note: the enum is defined here + --> $DIR/issue-73427.rs:1:1 + | +LL | / enum A { +LL | | StructWithFields { x: () }, +LL | | TupleWithFields(()), +LL | | Struct {}, +LL | | Tuple(), +LL | | Unit, +LL | | } + | |_^ +help: try to match against one of the enum's variants | LL | if let A::TupleWithFields(3) = x { } | ^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/lto-opt-level-s.rs b/src/test/ui/lto-opt-level-s.rs new file mode 100644 index 00000000000..a7d9d5024d3 --- /dev/null +++ b/src/test/ui/lto-opt-level-s.rs @@ -0,0 +1,7 @@ +// compile-flags: -Clinker-plugin-lto -Copt-level=s +// build-pass +// no-prefer-dynamic + +#![crate_type = "rlib"] + +pub fn foo() {} diff --git a/src/test/ui/lto-opt-level-z.rs b/src/test/ui/lto-opt-level-z.rs new file mode 100644 index 00000000000..bf1f5e2b263 --- /dev/null +++ b/src/test/ui/lto-opt-level-z.rs @@ -0,0 +1,7 @@ +// compile-flags: -Clinker-plugin-lto -Copt-level=z +// build-pass +// no-prefer-dynamic + +#![crate_type = "rlib"] + +pub fn foo() {} diff --git a/src/test/ui/macros/macro-use-wrong-name.stderr b/src/test/ui/macros/macro-use-wrong-name.stderr index 74fb519cc82..888fb913fb7 100644 --- a/src/test/ui/macros/macro-use-wrong-name.stderr +++ b/src/test/ui/macros/macro-use-wrong-name.stderr @@ -8,6 +8,9 @@ LL | macro_two!(); | LL | macro_rules! macro_one { () => ("one") } | ---------------------- similarly named macro `macro_one` defined here + | + = note: consider importing this macro: + two_macros::macro_two error: aborting due to previous error diff --git a/src/test/ui/methods/method-ambig-one-trait-unknown-int-type.stderr b/src/test/ui/methods/method-ambig-one-trait-unknown-int-type.stderr index 33e8282c9d2..82660a7c416 100644 --- a/src/test/ui/methods/method-ambig-one-trait-unknown-int-type.stderr +++ b/src/test/ui/methods/method-ambig-one-trait-unknown-int-type.stderr @@ -14,7 +14,7 @@ LL | let y: usize = x.foo(); | | | expected due to this | -help: you can convert an `isize` to `usize` and panic if the converted value wouldn't fit +help: you can convert an `isize` to a `usize` and panic if the converted value doesn't fit | LL | let y: usize = x.foo().try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/methods/method-call-err-msg.stderr b/src/test/ui/methods/method-call-err-msg.stderr index b0d1bb9823b..60f9eeeca27 100644 --- a/src/test/ui/methods/method-call-err-msg.stderr +++ b/src/test/ui/methods/method-call-err-msg.stderr @@ -1,35 +1,44 @@ error[E0061]: this function takes 0 arguments but 1 argument was supplied --> $DIR/method-call-err-msg.rs:13:7 | -LL | fn zero(self) -> Foo { self } - | -------------------- defined here -... LL | x.zero(0) | ^^^^ - supplied 1 argument | | | expected 0 arguments + | +note: associated function defined here + --> $DIR/method-call-err-msg.rs:5:8 + | +LL | fn zero(self) -> Foo { self } + | ^^^^ ---- error[E0061]: this function takes 1 argument but 0 arguments were supplied --> $DIR/method-call-err-msg.rs:14:7 | -LL | fn one(self, _: isize) -> Foo { self } - | ----------------------------- defined here -... LL | .one() | ^^^- supplied 0 arguments | | | expected 1 argument + | +note: associated function defined here + --> $DIR/method-call-err-msg.rs:6:8 + | +LL | fn one(self, _: isize) -> Foo { self } + | ^^^ ---- -------- error[E0061]: this function takes 2 arguments but 1 argument was supplied --> $DIR/method-call-err-msg.rs:15:7 | -LL | fn two(self, _: isize, _: isize) -> Foo { self } - | --------------------------------------- defined here -... LL | .two(0); | ^^^ - supplied 1 argument | | | expected 2 arguments + | +note: associated function defined here + --> $DIR/method-call-err-msg.rs:7:8 + | +LL | fn two(self, _: isize, _: isize) -> Foo { self } + | ^^^ ---- -------- -------- error[E0599]: no method named `take` found for struct `Foo` in the current scope --> $DIR/method-call-err-msg.rs:19:7 @@ -53,13 +62,16 @@ LL | .take() error[E0061]: this function takes 3 arguments but 0 arguments were supplied --> $DIR/method-call-err-msg.rs:21:7 | -LL | fn three<T>(self, _: T, _: T, _: T) -> Foo { self } - | ------------------------------------------ defined here -... LL | y.three::<usize>(); | ^^^^^--------- supplied 0 arguments | | | expected 3 arguments + | +note: associated function defined here + --> $DIR/method-call-err-msg.rs:8:8 + | +LL | fn three<T>(self, _: T, _: T, _: T) -> Foo { self } + | ^^^^^ ---- ---- ---- ---- error: aborting due to 5 previous errors diff --git a/src/test/ui/mir/mir-inlining/ice-issue-68347.rs b/src/test/ui/mir/mir-inlining/ice-issue-68347.rs new file mode 100644 index 00000000000..88b80bc3333 --- /dev/null +++ b/src/test/ui/mir/mir-inlining/ice-issue-68347.rs @@ -0,0 +1,28 @@ +// run-pass +// compile-flags:-Zmir-opt-level=2 +pub fn main() { + let _x: fn() = handle_debug_column; +} + +fn handle_debug_column() { + let sampler = sample_columns(); + + let foo = || { + sampler.get(17); + }; + foo(); +} + +fn sample_columns() -> impl Sampler { + ColumnGen {} +} + +struct ColumnGen {} + +trait Sampler { + fn get(&self, index: i32); +} + +impl Sampler for ColumnGen { + fn get(&self, _index: i32) {} +} diff --git a/src/test/ui/mir/mir-inlining/ice-issue-77306-1.rs b/src/test/ui/mir/mir-inlining/ice-issue-77306-1.rs new file mode 100644 index 00000000000..4d083bf2321 --- /dev/null +++ b/src/test/ui/mir/mir-inlining/ice-issue-77306-1.rs @@ -0,0 +1,17 @@ +// run-pass +// compile-flags:-Zmir-opt-level=2 + +// Previously ICEd because we did not normalize during inlining, +// see https://github.com/rust-lang/rust/pull/77306 for more discussion. + +pub fn write() { + create()() +} + +pub fn create() -> impl FnOnce() { + || () +} + +fn main() { + write(); +} diff --git a/src/test/ui/mir/mir-inlining/ice-issue-77306-2.rs b/src/test/ui/mir/mir-inlining/ice-issue-77306-2.rs new file mode 100644 index 00000000000..a346d450586 --- /dev/null +++ b/src/test/ui/mir/mir-inlining/ice-issue-77306-2.rs @@ -0,0 +1,32 @@ +// run-pass +// compile-flags:-Zmir-opt-level=2 + +struct Cursor {} +struct TokenTree {} + +impl Iterator for Cursor { + type Item = TokenTree; + + fn next(&mut self) -> Option<TokenTree> { + None + } +} + +fn tokenstream_probably_equal_for_proc_macro() { + fn break_tokens(_tree: TokenTree) -> impl Iterator<Item = TokenTree> { + let token_trees: Vec<TokenTree> = vec![]; + token_trees.into_iter() + } + + let c1 = Cursor {}; + let c2 = Cursor {}; + + let mut t1 = c1.flat_map(break_tokens); + let mut t2 = c2.flat_map(break_tokens); + + for (_t1, _t2) in t1.by_ref().zip(t2.by_ref()) {} +} + +fn main() { + tokenstream_probably_equal_for_proc_macro(); +} diff --git a/src/test/ui/mismatched_types/issue-26480.stderr b/src/test/ui/mismatched_types/issue-26480.stderr index d39b0a32077..e608cd99af2 100644 --- a/src/test/ui/mismatched_types/issue-26480.stderr +++ b/src/test/ui/mismatched_types/issue-26480.stderr @@ -8,7 +8,7 @@ LL | write!(hello); | -------------- in this macro invocation | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -help: you can convert an `usize` to `u64` and panic if the converted value wouldn't fit +help: you can convert a `usize` to a `u64` and panic if the converted value doesn't fit | LL | ($arr.len() * size_of($arr[0])).try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/mismatched_types/issue-36053-2.stderr b/src/test/ui/mismatched_types/issue-36053-2.stderr index 63c04bcd7ba..0b1fcf58e2e 100644 --- a/src/test/ui/mismatched_types/issue-36053-2.stderr +++ b/src/test/ui/mismatched_types/issue-36053-2.stderr @@ -1,3 +1,11 @@ +error[E0631]: type mismatch in closure arguments + --> $DIR/issue-36053-2.rs:7:32 + | +LL | once::<&str>("str").fuse().filter(|a: &str| true).count(); + | ^^^^^^ -------------- found signature of `for<'r> fn(&'r str) -> _` + | | + | expected signature of `for<'r> fn(&'r &str) -> _` + error[E0599]: no method named `count` found for struct `Filter<Fuse<std::iter::Once<&str>>, [closure@$DIR/issue-36053-2.rs:7:39: 7:53]>` in the current scope --> $DIR/issue-36053-2.rs:7:55 | @@ -20,14 +28,6 @@ LL | pub struct Filter<I, P> { `Filter<Fuse<std::iter::Once<&str>>, [closure@$DIR/issue-36053-2.rs:7:39: 7:53]>: Iterator` which is required by `&mut Filter<Fuse<std::iter::Once<&str>>, [closure@$DIR/issue-36053-2.rs:7:39: 7:53]>: Iterator` -error[E0631]: type mismatch in closure arguments - --> $DIR/issue-36053-2.rs:7:32 - | -LL | once::<&str>("str").fuse().filter(|a: &str| true).count(); - | ^^^^^^ -------------- found signature of `for<'r> fn(&'r str) -> _` - | | - | expected signature of `for<'r> fn(&'r &str) -> _` - error: aborting due to 2 previous errors Some errors have detailed explanations: E0599, E0631. diff --git a/src/test/ui/mismatched_types/issue-38371.stderr b/src/test/ui/mismatched_types/issue-38371.stderr index c2bce305877..5d2ce9302ec 100644 --- a/src/test/ui/mismatched_types/issue-38371.stderr +++ b/src/test/ui/mismatched_types/issue-38371.stderr @@ -2,7 +2,7 @@ error[E0308]: mismatched types --> $DIR/issue-38371.rs:4:8 | LL | fn foo(&foo: Foo) { - | ^^^^------ + | ^^^^----- | | | | | expected due to this | expected struct `Foo`, found reference diff --git a/src/test/ui/missing/missing-macro-use.stderr b/src/test/ui/missing/missing-macro-use.stderr index 711e249d2bc..ced062269df 100644 --- a/src/test/ui/missing/missing-macro-use.stderr +++ b/src/test/ui/missing/missing-macro-use.stderr @@ -3,6 +3,9 @@ error: cannot find macro `macro_two` in this scope | LL | macro_two!(); | ^^^^^^^^^ + | + = note: consider importing this macro: + two_macros::macro_two error: aborting due to previous error diff --git a/src/test/ui/not-enough-arguments.rs b/src/test/ui/not-enough-arguments.rs index 631bb1dd274..42476255188 100644 --- a/src/test/ui/not-enough-arguments.rs +++ b/src/test/ui/not-enough-arguments.rs @@ -6,7 +6,26 @@ fn foo(a: isize, b: isize, c: isize, d:isize) { panic!(); } +// Check that all arguments are shown in the error message, even if they're across multiple lines. +fn bar( + a: i32, + b: i32, + c: i32, + d: i32, + e: i32, + f: i32, +) { + println!("{}", a); + println!("{}", b); + println!("{}", c); + println!("{}", d); + println!("{}", e); + println!("{}", f); +} + fn main() { foo(1, 2, 3); //~^ ERROR this function takes 4 arguments but 3 + bar(1, 2, 3); + //~^ ERROR this function takes 6 arguments but 3 } diff --git a/src/test/ui/not-enough-arguments.stderr b/src/test/ui/not-enough-arguments.stderr index f2b57f71400..df957837241 100644 --- a/src/test/ui/not-enough-arguments.stderr +++ b/src/test/ui/not-enough-arguments.stderr @@ -1,14 +1,43 @@ error[E0061]: this function takes 4 arguments but 3 arguments were supplied - --> $DIR/not-enough-arguments.rs:10:3 + --> $DIR/not-enough-arguments.rs:27:3 | -LL | fn foo(a: isize, b: isize, c: isize, d:isize) { - | --------------------------------------------- defined here -... LL | foo(1, 2, 3); | ^^^ - - - supplied 3 arguments | | | expected 4 arguments + | +note: function defined here + --> $DIR/not-enough-arguments.rs:5:4 + | +LL | fn foo(a: isize, b: isize, c: isize, d:isize) { + | ^^^ -------- -------- -------- ------- + +error[E0061]: this function takes 6 arguments but 3 arguments were supplied + --> $DIR/not-enough-arguments.rs:29:3 + | +LL | bar(1, 2, 3); + | ^^^ - - - supplied 3 arguments + | | + | expected 6 arguments + | +note: function defined here + --> $DIR/not-enough-arguments.rs:10:4 + | +LL | fn bar( + | ^^^ +LL | a: i32, + | ------ +LL | b: i32, + | ------ +LL | c: i32, + | ------ +LL | d: i32, + | ------ +LL | e: i32, + | ------ +LL | f: i32, + | ------ -error: aborting due to previous error +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0061`. diff --git a/src/test/ui/numeric/const-scope.stderr b/src/test/ui/numeric/const-scope.stderr index d7f18e19b41..5a275d5d089 100644 --- a/src/test/ui/numeric/const-scope.stderr +++ b/src/test/ui/numeric/const-scope.stderr @@ -57,7 +57,7 @@ LL | let d: i8 = c; | | | expected due to this | -help: you can convert an `i32` to `i8` and panic if the converted value wouldn't fit +help: you can convert an `i32` to an `i8` and panic if the converted value doesn't fit | LL | let d: i8 = c.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/numeric/len.stderr b/src/test/ui/numeric/len.stderr index dba6c723829..79b38b06986 100644 --- a/src/test/ui/numeric/len.stderr +++ b/src/test/ui/numeric/len.stderr @@ -4,7 +4,7 @@ error[E0308]: mismatched types LL | test(array.len()); | ^^^^^^^^^^^ expected `u32`, found `usize` | -help: you can convert an `usize` to `u32` and panic if the converted value wouldn't fit +help: you can convert a `usize` to a `u32` and panic if the converted value doesn't fit | LL | test(array.len().try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/numeric/numeric-cast-2.stderr b/src/test/ui/numeric/numeric-cast-2.stderr index 3f900062cbb..858990fe59b 100644 --- a/src/test/ui/numeric/numeric-cast-2.stderr +++ b/src/test/ui/numeric/numeric-cast-2.stderr @@ -6,7 +6,7 @@ LL | let x: u16 = foo(); | | | expected due to this | -help: you can convert an `i32` to `u16` and panic if the converted value wouldn't fit +help: you can convert an `i32` to a `u16` and panic if the converted value doesn't fit | LL | let x: u16 = foo().try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -18,7 +18,7 @@ LL | let y: i64 = x + x; | --- ^^^^^ | | | | | expected `i64`, found `u16` - | | help: you can convert an `u16` to `i64`: `(x + x).into()` + | | help: you can convert a `u16` to an `i64`: `(x + x).into()` | expected due to this error[E0308]: mismatched types @@ -28,7 +28,7 @@ LL | let z: i32 = x + x; | --- ^^^^^ | | | | | expected `i32`, found `u16` - | | help: you can convert an `u16` to `i32`: `(x + x).into()` + | | help: you can convert a `u16` to an `i32`: `(x + x).into()` | expected due to this error: aborting due to 3 previous errors diff --git a/src/test/ui/numeric/numeric-cast-binop.stderr b/src/test/ui/numeric/numeric-cast-binop.stderr index 47be817b789..cb051aa1230 100644 --- a/src/test/ui/numeric/numeric-cast-binop.stderr +++ b/src/test/ui/numeric/numeric-cast-binop.stderr @@ -60,7 +60,7 @@ LL | x_u16 > x_u8; | ^^^^ | | | expected `u16`, found `u8` - | help: you can convert an `u8` to `u16`: `x_u8.into()` + | help: you can convert a `u8` to a `u16`: `x_u8.into()` error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:36:17 @@ -113,7 +113,7 @@ LL | x_u32 > x_u8; | ^^^^ | | | expected `u32`, found `u8` - | help: you can convert an `u8` to `u32`: `x_u8.into()` + | help: you can convert a `u8` to a `u32`: `x_u8.into()` error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:47:17 @@ -122,7 +122,7 @@ LL | x_u32 > x_u16; | ^^^^^ | | | expected `u32`, found `u16` - | help: you can convert an `u16` to `u32`: `x_u16.into()` + | help: you can convert a `u16` to a `u32`: `x_u16.into()` error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:49:17 @@ -152,7 +152,7 @@ error[E0308]: mismatched types LL | x_u32 > x_usize; | ^^^^^^^ expected `u32`, found `usize` | -help: you can convert an `usize` to `u32` and panic if the converted value wouldn't fit +help: you can convert a `usize` to a `u32` and panic if the converted value doesn't fit | LL | x_u32 > x_usize.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -164,7 +164,7 @@ LL | x_u64 > x_u8; | ^^^^ | | | expected `u64`, found `u8` - | help: you can convert an `u8` to `u64`: `x_u8.into()` + | help: you can convert a `u8` to a `u64`: `x_u8.into()` error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:58:17 @@ -173,7 +173,7 @@ LL | x_u64 > x_u16; | ^^^^^ | | | expected `u64`, found `u16` - | help: you can convert an `u16` to `u64`: `x_u16.into()` + | help: you can convert a `u16` to a `u64`: `x_u16.into()` error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:60:17 @@ -182,7 +182,7 @@ LL | x_u64 > x_u32; | ^^^^^ | | | expected `u64`, found `u32` - | help: you can convert an `u32` to `u64`: `x_u32.into()` + | help: you can convert a `u32` to a `u64`: `x_u32.into()` error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:62:17 @@ -201,7 +201,7 @@ error[E0308]: mismatched types LL | x_u64 > x_usize; | ^^^^^^^ expected `u64`, found `usize` | -help: you can convert an `usize` to `u64` and panic if the converted value wouldn't fit +help: you can convert a `usize` to a `u64` and panic if the converted value doesn't fit | LL | x_u64 > x_usize.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -213,7 +213,7 @@ LL | x_u128 > x_u8; | ^^^^ | | | expected `u128`, found `u8` - | help: you can convert an `u8` to `u128`: `x_u8.into()` + | help: you can convert a `u8` to a `u128`: `x_u8.into()` error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:69:18 @@ -222,7 +222,7 @@ LL | x_u128 > x_u16; | ^^^^^ | | | expected `u128`, found `u16` - | help: you can convert an `u16` to `u128`: `x_u16.into()` + | help: you can convert a `u16` to a `u128`: `x_u16.into()` error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:71:18 @@ -231,7 +231,7 @@ LL | x_u128 > x_u32; | ^^^^^ | | | expected `u128`, found `u32` - | help: you can convert an `u32` to `u128`: `x_u32.into()` + | help: you can convert a `u32` to a `u128`: `x_u32.into()` error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:73:18 @@ -240,7 +240,7 @@ LL | x_u128 > x_u64; | ^^^^^ | | | expected `u128`, found `u64` - | help: you can convert an `u64` to `u128`: `x_u64.into()` + | help: you can convert a `u64` to a `u128`: `x_u64.into()` error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:75:18 @@ -248,7 +248,7 @@ error[E0308]: mismatched types LL | x_u128 > x_usize; | ^^^^^^^ expected `u128`, found `usize` | -help: you can convert an `usize` to `u128` and panic if the converted value wouldn't fit +help: you can convert a `usize` to a `u128` and panic if the converted value doesn't fit | LL | x_u128 > x_usize.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -260,7 +260,7 @@ LL | x_usize > x_u8; | ^^^^ | | | expected `usize`, found `u8` - | help: you can convert an `u8` to `usize`: `x_u8.into()` + | help: you can convert a `u8` to a `usize`: `x_u8.into()` error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:80:19 @@ -269,7 +269,7 @@ LL | x_usize > x_u16; | ^^^^^ | | | expected `usize`, found `u16` - | help: you can convert an `u16` to `usize`: `x_u16.into()` + | help: you can convert a `u16` to a `usize`: `x_u16.into()` error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:82:19 @@ -277,7 +277,7 @@ error[E0308]: mismatched types LL | x_usize > x_u32; | ^^^^^ expected `usize`, found `u32` | -help: you can convert an `u32` to `usize` and panic if the converted value wouldn't fit +help: you can convert a `u32` to a `usize` and panic if the converted value doesn't fit | LL | x_usize > x_u32.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -288,7 +288,7 @@ error[E0308]: mismatched types LL | x_usize > x_u64; | ^^^^^ expected `usize`, found `u64` | -help: you can convert an `u64` to `usize` and panic if the converted value wouldn't fit +help: you can convert a `u64` to a `usize` and panic if the converted value doesn't fit | LL | x_usize > x_u64.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -299,7 +299,7 @@ error[E0308]: mismatched types LL | x_usize > x_u128; | ^^^^^^ expected `usize`, found `u128` | -help: you can convert an `u128` to `usize` and panic if the converted value wouldn't fit +help: you can convert a `u128` to a `usize` and panic if the converted value doesn't fit | LL | x_usize > x_u128.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -366,7 +366,7 @@ LL | x_i16 > x_i8; | ^^^^ | | | expected `i16`, found `i8` - | help: you can convert an `i8` to `i16`: `x_i8.into()` + | help: you can convert an `i8` to an `i16`: `x_i8.into()` error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:105:17 @@ -419,7 +419,7 @@ LL | x_i32 > x_i8; | ^^^^ | | | expected `i32`, found `i8` - | help: you can convert an `i8` to `i32`: `x_i8.into()` + | help: you can convert an `i8` to an `i32`: `x_i8.into()` error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:116:17 @@ -428,7 +428,7 @@ LL | x_i32 > x_i16; | ^^^^^ | | | expected `i32`, found `i16` - | help: you can convert an `i16` to `i32`: `x_i16.into()` + | help: you can convert an `i16` to an `i32`: `x_i16.into()` error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:118:17 @@ -458,7 +458,7 @@ error[E0308]: mismatched types LL | x_i32 > x_isize; | ^^^^^^^ expected `i32`, found `isize` | -help: you can convert an `isize` to `i32` and panic if the converted value wouldn't fit +help: you can convert an `isize` to an `i32` and panic if the converted value doesn't fit | LL | x_i32 > x_isize.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -470,7 +470,7 @@ LL | x_i64 > x_i8; | ^^^^ | | | expected `i64`, found `i8` - | help: you can convert an `i8` to `i64`: `x_i8.into()` + | help: you can convert an `i8` to an `i64`: `x_i8.into()` error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:127:17 @@ -479,7 +479,7 @@ LL | x_i64 > x_i16; | ^^^^^ | | | expected `i64`, found `i16` - | help: you can convert an `i16` to `i64`: `x_i16.into()` + | help: you can convert an `i16` to an `i64`: `x_i16.into()` error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:129:17 @@ -488,7 +488,7 @@ LL | x_i64 > x_i32; | ^^^^^ | | | expected `i64`, found `i32` - | help: you can convert an `i32` to `i64`: `x_i32.into()` + | help: you can convert an `i32` to an `i64`: `x_i32.into()` error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:131:17 @@ -507,7 +507,7 @@ error[E0308]: mismatched types LL | x_i64 > x_isize; | ^^^^^^^ expected `i64`, found `isize` | -help: you can convert an `isize` to `i64` and panic if the converted value wouldn't fit +help: you can convert an `isize` to an `i64` and panic if the converted value doesn't fit | LL | x_i64 > x_isize.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -519,7 +519,7 @@ LL | x_i128 > x_i8; | ^^^^ | | | expected `i128`, found `i8` - | help: you can convert an `i8` to `i128`: `x_i8.into()` + | help: you can convert an `i8` to an `i128`: `x_i8.into()` error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:138:18 @@ -528,7 +528,7 @@ LL | x_i128 > x_i16; | ^^^^^ | | | expected `i128`, found `i16` - | help: you can convert an `i16` to `i128`: `x_i16.into()` + | help: you can convert an `i16` to an `i128`: `x_i16.into()` error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:140:18 @@ -537,7 +537,7 @@ LL | x_i128 > x_i32; | ^^^^^ | | | expected `i128`, found `i32` - | help: you can convert an `i32` to `i128`: `x_i32.into()` + | help: you can convert an `i32` to an `i128`: `x_i32.into()` error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:142:18 @@ -546,7 +546,7 @@ LL | x_i128 > x_i64; | ^^^^^ | | | expected `i128`, found `i64` - | help: you can convert an `i64` to `i128`: `x_i64.into()` + | help: you can convert an `i64` to an `i128`: `x_i64.into()` error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:144:18 @@ -554,7 +554,7 @@ error[E0308]: mismatched types LL | x_i128 > x_isize; | ^^^^^^^ expected `i128`, found `isize` | -help: you can convert an `isize` to `i128` and panic if the converted value wouldn't fit +help: you can convert an `isize` to an `i128` and panic if the converted value doesn't fit | LL | x_i128 > x_isize.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -566,7 +566,7 @@ LL | x_isize > x_i8; | ^^^^ | | | expected `isize`, found `i8` - | help: you can convert an `i8` to `isize`: `x_i8.into()` + | help: you can convert an `i8` to an `isize`: `x_i8.into()` error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:149:19 @@ -575,7 +575,7 @@ LL | x_isize > x_i16; | ^^^^^ | | | expected `isize`, found `i16` - | help: you can convert an `i16` to `isize`: `x_i16.into()` + | help: you can convert an `i16` to an `isize`: `x_i16.into()` error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:151:19 @@ -583,7 +583,7 @@ error[E0308]: mismatched types LL | x_isize > x_i32; | ^^^^^ expected `isize`, found `i32` | -help: you can convert an `i32` to `isize` and panic if the converted value wouldn't fit +help: you can convert an `i32` to an `isize` and panic if the converted value doesn't fit | LL | x_isize > x_i32.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -594,7 +594,7 @@ error[E0308]: mismatched types LL | x_isize > x_i64; | ^^^^^ expected `isize`, found `i64` | -help: you can convert an `i64` to `isize` and panic if the converted value wouldn't fit +help: you can convert an `i64` to an `isize` and panic if the converted value doesn't fit | LL | x_isize > x_i64.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -605,7 +605,7 @@ error[E0308]: mismatched types LL | x_isize > x_i128; | ^^^^^^ expected `isize`, found `i128` | -help: you can convert an `i128` to `isize` and panic if the converted value wouldn't fit +help: you can convert an `i128` to an `isize` and panic if the converted value doesn't fit | LL | x_isize > x_i128.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -616,7 +616,7 @@ error[E0308]: mismatched types LL | x_u8 > x_i8; | ^^^^ expected `u8`, found `i8` | -help: you can convert an `i8` to `u8` and panic if the converted value wouldn't fit +help: you can convert an `i8` to a `u8` and panic if the converted value doesn't fit | LL | x_u8 > x_i8.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -682,7 +682,7 @@ error[E0308]: mismatched types LL | x_u16 > x_i8; | ^^^^ expected `u16`, found `i8` | -help: you can convert an `i8` to `u16` and panic if the converted value wouldn't fit +help: you can convert an `i8` to a `u16` and panic if the converted value doesn't fit | LL | x_u16 > x_i8.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -693,7 +693,7 @@ error[E0308]: mismatched types LL | x_u16 > x_i16; | ^^^^^ expected `u16`, found `i16` | -help: you can convert an `i16` to `u16` and panic if the converted value wouldn't fit +help: you can convert an `i16` to a `u16` and panic if the converted value doesn't fit | LL | x_u16 > x_i16.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -737,7 +737,7 @@ error[E0308]: mismatched types LL | x_u16 > x_isize; | ^^^^^^^ expected `u16`, found `isize` | -help: you can convert an `isize` to `u16` and panic if the converted value wouldn't fit +help: you can convert an `isize` to a `u16` and panic if the converted value doesn't fit | LL | x_u16 > x_isize.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -748,7 +748,7 @@ error[E0308]: mismatched types LL | x_u32 > x_i8; | ^^^^ expected `u32`, found `i8` | -help: you can convert an `i8` to `u32` and panic if the converted value wouldn't fit +help: you can convert an `i8` to a `u32` and panic if the converted value doesn't fit | LL | x_u32 > x_i8.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -759,7 +759,7 @@ error[E0308]: mismatched types LL | x_u32 > x_i16; | ^^^^^ expected `u32`, found `i16` | -help: you can convert an `i16` to `u32` and panic if the converted value wouldn't fit +help: you can convert an `i16` to a `u32` and panic if the converted value doesn't fit | LL | x_u32 > x_i16.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -770,7 +770,7 @@ error[E0308]: mismatched types LL | x_u32 > x_i32; | ^^^^^ expected `u32`, found `i32` | -help: you can convert an `i32` to `u32` and panic if the converted value wouldn't fit +help: you can convert an `i32` to a `u32` and panic if the converted value doesn't fit | LL | x_u32 > x_i32.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -803,7 +803,7 @@ error[E0308]: mismatched types LL | x_u32 > x_isize; | ^^^^^^^ expected `u32`, found `isize` | -help: you can convert an `isize` to `u32` and panic if the converted value wouldn't fit +help: you can convert an `isize` to a `u32` and panic if the converted value doesn't fit | LL | x_u32 > x_isize.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -814,7 +814,7 @@ error[E0308]: mismatched types LL | x_u64 > x_i8; | ^^^^ expected `u64`, found `i8` | -help: you can convert an `i8` to `u64` and panic if the converted value wouldn't fit +help: you can convert an `i8` to a `u64` and panic if the converted value doesn't fit | LL | x_u64 > x_i8.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -825,7 +825,7 @@ error[E0308]: mismatched types LL | x_u64 > x_i16; | ^^^^^ expected `u64`, found `i16` | -help: you can convert an `i16` to `u64` and panic if the converted value wouldn't fit +help: you can convert an `i16` to a `u64` and panic if the converted value doesn't fit | LL | x_u64 > x_i16.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -836,7 +836,7 @@ error[E0308]: mismatched types LL | x_u64 > x_i32; | ^^^^^ expected `u64`, found `i32` | -help: you can convert an `i32` to `u64` and panic if the converted value wouldn't fit +help: you can convert an `i32` to a `u64` and panic if the converted value doesn't fit | LL | x_u64 > x_i32.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -847,7 +847,7 @@ error[E0308]: mismatched types LL | x_u64 > x_i64; | ^^^^^ expected `u64`, found `i64` | -help: you can convert an `i64` to `u64` and panic if the converted value wouldn't fit +help: you can convert an `i64` to a `u64` and panic if the converted value doesn't fit | LL | x_u64 > x_i64.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -869,7 +869,7 @@ error[E0308]: mismatched types LL | x_u64 > x_isize; | ^^^^^^^ expected `u64`, found `isize` | -help: you can convert an `isize` to `u64` and panic if the converted value wouldn't fit +help: you can convert an `isize` to a `u64` and panic if the converted value doesn't fit | LL | x_u64 > x_isize.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -880,7 +880,7 @@ error[E0308]: mismatched types LL | x_u128 > x_i8; | ^^^^ expected `u128`, found `i8` | -help: you can convert an `i8` to `u128` and panic if the converted value wouldn't fit +help: you can convert an `i8` to a `u128` and panic if the converted value doesn't fit | LL | x_u128 > x_i8.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -891,7 +891,7 @@ error[E0308]: mismatched types LL | x_u128 > x_i16; | ^^^^^ expected `u128`, found `i16` | -help: you can convert an `i16` to `u128` and panic if the converted value wouldn't fit +help: you can convert an `i16` to a `u128` and panic if the converted value doesn't fit | LL | x_u128 > x_i16.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -902,7 +902,7 @@ error[E0308]: mismatched types LL | x_u128 > x_i32; | ^^^^^ expected `u128`, found `i32` | -help: you can convert an `i32` to `u128` and panic if the converted value wouldn't fit +help: you can convert an `i32` to a `u128` and panic if the converted value doesn't fit | LL | x_u128 > x_i32.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -913,7 +913,7 @@ error[E0308]: mismatched types LL | x_u128 > x_i64; | ^^^^^ expected `u128`, found `i64` | -help: you can convert an `i64` to `u128` and panic if the converted value wouldn't fit +help: you can convert an `i64` to a `u128` and panic if the converted value doesn't fit | LL | x_u128 > x_i64.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -924,7 +924,7 @@ error[E0308]: mismatched types LL | x_u128 > x_i128; | ^^^^^^ expected `u128`, found `i128` | -help: you can convert an `i128` to `u128` and panic if the converted value wouldn't fit +help: you can convert an `i128` to a `u128` and panic if the converted value doesn't fit | LL | x_u128 > x_i128.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -935,7 +935,7 @@ error[E0308]: mismatched types LL | x_u128 > x_isize; | ^^^^^^^ expected `u128`, found `isize` | -help: you can convert an `isize` to `u128` and panic if the converted value wouldn't fit +help: you can convert an `isize` to a `u128` and panic if the converted value doesn't fit | LL | x_u128 > x_isize.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -946,7 +946,7 @@ error[E0308]: mismatched types LL | x_usize > x_i8; | ^^^^ expected `usize`, found `i8` | -help: you can convert an `i8` to `usize` and panic if the converted value wouldn't fit +help: you can convert an `i8` to a `usize` and panic if the converted value doesn't fit | LL | x_usize > x_i8.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -957,7 +957,7 @@ error[E0308]: mismatched types LL | x_usize > x_i16; | ^^^^^ expected `usize`, found `i16` | -help: you can convert an `i16` to `usize` and panic if the converted value wouldn't fit +help: you can convert an `i16` to a `usize` and panic if the converted value doesn't fit | LL | x_usize > x_i16.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -968,7 +968,7 @@ error[E0308]: mismatched types LL | x_usize > x_i32; | ^^^^^ expected `usize`, found `i32` | -help: you can convert an `i32` to `usize` and panic if the converted value wouldn't fit +help: you can convert an `i32` to a `usize` and panic if the converted value doesn't fit | LL | x_usize > x_i32.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -979,7 +979,7 @@ error[E0308]: mismatched types LL | x_usize > x_i64; | ^^^^^ expected `usize`, found `i64` | -help: you can convert an `i64` to `usize` and panic if the converted value wouldn't fit +help: you can convert an `i64` to a `usize` and panic if the converted value doesn't fit | LL | x_usize > x_i64.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -990,7 +990,7 @@ error[E0308]: mismatched types LL | x_usize > x_i128; | ^^^^^^ expected `usize`, found `i128` | -help: you can convert an `i128` to `usize` and panic if the converted value wouldn't fit +help: you can convert an `i128` to a `usize` and panic if the converted value doesn't fit | LL | x_usize > x_i128.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1001,7 +1001,7 @@ error[E0308]: mismatched types LL | x_usize > x_isize; | ^^^^^^^ expected `usize`, found `isize` | -help: you can convert an `isize` to `usize` and panic if the converted value wouldn't fit +help: you can convert an `isize` to a `usize` and panic if the converted value doesn't fit | LL | x_usize > x_isize.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1012,7 +1012,7 @@ error[E0308]: mismatched types LL | x_i8 > x_u8; | ^^^^ expected `i8`, found `u8` | -help: you can convert an `u8` to `i8` and panic if the converted value wouldn't fit +help: you can convert a `u8` to an `i8` and panic if the converted value doesn't fit | LL | x_i8 > x_u8.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1023,7 +1023,7 @@ error[E0308]: mismatched types LL | x_i8 > x_u16; | ^^^^^ expected `i8`, found `u16` | -help: you can convert an `u16` to `i8` and panic if the converted value wouldn't fit +help: you can convert a `u16` to an `i8` and panic if the converted value doesn't fit | LL | x_i8 > x_u16.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1034,7 +1034,7 @@ error[E0308]: mismatched types LL | x_i8 > x_u32; | ^^^^^ expected `i8`, found `u32` | -help: you can convert an `u32` to `i8` and panic if the converted value wouldn't fit +help: you can convert a `u32` to an `i8` and panic if the converted value doesn't fit | LL | x_i8 > x_u32.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1045,7 +1045,7 @@ error[E0308]: mismatched types LL | x_i8 > x_u64; | ^^^^^ expected `i8`, found `u64` | -help: you can convert an `u64` to `i8` and panic if the converted value wouldn't fit +help: you can convert a `u64` to an `i8` and panic if the converted value doesn't fit | LL | x_i8 > x_u64.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1056,7 +1056,7 @@ error[E0308]: mismatched types LL | x_i8 > x_u128; | ^^^^^^ expected `i8`, found `u128` | -help: you can convert an `u128` to `i8` and panic if the converted value wouldn't fit +help: you can convert a `u128` to an `i8` and panic if the converted value doesn't fit | LL | x_i8 > x_u128.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1067,7 +1067,7 @@ error[E0308]: mismatched types LL | x_i8 > x_usize; | ^^^^^^^ expected `i8`, found `usize` | -help: you can convert an `usize` to `i8` and panic if the converted value wouldn't fit +help: you can convert a `usize` to an `i8` and panic if the converted value doesn't fit | LL | x_i8 > x_usize.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1079,7 +1079,7 @@ LL | x_i16 > x_u8; | ^^^^ | | | expected `i16`, found `u8` - | help: you can convert an `u8` to `i16`: `x_u8.into()` + | help: you can convert a `u8` to an `i16`: `x_u8.into()` error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:257:17 @@ -1087,7 +1087,7 @@ error[E0308]: mismatched types LL | x_i16 > x_u16; | ^^^^^ expected `i16`, found `u16` | -help: you can convert an `u16` to `i16` and panic if the converted value wouldn't fit +help: you can convert a `u16` to an `i16` and panic if the converted value doesn't fit | LL | x_i16 > x_u16.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1098,7 +1098,7 @@ error[E0308]: mismatched types LL | x_i16 > x_u32; | ^^^^^ expected `i16`, found `u32` | -help: you can convert an `u32` to `i16` and panic if the converted value wouldn't fit +help: you can convert a `u32` to an `i16` and panic if the converted value doesn't fit | LL | x_i16 > x_u32.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1109,7 +1109,7 @@ error[E0308]: mismatched types LL | x_i16 > x_u64; | ^^^^^ expected `i16`, found `u64` | -help: you can convert an `u64` to `i16` and panic if the converted value wouldn't fit +help: you can convert a `u64` to an `i16` and panic if the converted value doesn't fit | LL | x_i16 > x_u64.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1120,7 +1120,7 @@ error[E0308]: mismatched types LL | x_i16 > x_u128; | ^^^^^^ expected `i16`, found `u128` | -help: you can convert an `u128` to `i16` and panic if the converted value wouldn't fit +help: you can convert a `u128` to an `i16` and panic if the converted value doesn't fit | LL | x_i16 > x_u128.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1131,7 +1131,7 @@ error[E0308]: mismatched types LL | x_i16 > x_usize; | ^^^^^^^ expected `i16`, found `usize` | -help: you can convert an `usize` to `i16` and panic if the converted value wouldn't fit +help: you can convert a `usize` to an `i16` and panic if the converted value doesn't fit | LL | x_i16 > x_usize.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1143,7 +1143,7 @@ LL | x_i32 > x_u8; | ^^^^ | | | expected `i32`, found `u8` - | help: you can convert an `u8` to `i32`: `x_u8.into()` + | help: you can convert a `u8` to an `i32`: `x_u8.into()` error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:270:17 @@ -1152,7 +1152,7 @@ LL | x_i32 > x_u16; | ^^^^^ | | | expected `i32`, found `u16` - | help: you can convert an `u16` to `i32`: `x_u16.into()` + | help: you can convert a `u16` to an `i32`: `x_u16.into()` error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:272:17 @@ -1160,7 +1160,7 @@ error[E0308]: mismatched types LL | x_i32 > x_u32; | ^^^^^ expected `i32`, found `u32` | -help: you can convert an `u32` to `i32` and panic if the converted value wouldn't fit +help: you can convert a `u32` to an `i32` and panic if the converted value doesn't fit | LL | x_i32 > x_u32.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1171,7 +1171,7 @@ error[E0308]: mismatched types LL | x_i32 > x_u64; | ^^^^^ expected `i32`, found `u64` | -help: you can convert an `u64` to `i32` and panic if the converted value wouldn't fit +help: you can convert a `u64` to an `i32` and panic if the converted value doesn't fit | LL | x_i32 > x_u64.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1182,7 +1182,7 @@ error[E0308]: mismatched types LL | x_i32 > x_u128; | ^^^^^^ expected `i32`, found `u128` | -help: you can convert an `u128` to `i32` and panic if the converted value wouldn't fit +help: you can convert a `u128` to an `i32` and panic if the converted value doesn't fit | LL | x_i32 > x_u128.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1193,7 +1193,7 @@ error[E0308]: mismatched types LL | x_i32 > x_usize; | ^^^^^^^ expected `i32`, found `usize` | -help: you can convert an `usize` to `i32` and panic if the converted value wouldn't fit +help: you can convert a `usize` to an `i32` and panic if the converted value doesn't fit | LL | x_i32 > x_usize.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1205,7 +1205,7 @@ LL | x_i64 > x_u8; | ^^^^ | | | expected `i64`, found `u8` - | help: you can convert an `u8` to `i64`: `x_u8.into()` + | help: you can convert a `u8` to an `i64`: `x_u8.into()` error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:283:17 @@ -1214,7 +1214,7 @@ LL | x_i64 > x_u16; | ^^^^^ | | | expected `i64`, found `u16` - | help: you can convert an `u16` to `i64`: `x_u16.into()` + | help: you can convert a `u16` to an `i64`: `x_u16.into()` error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:285:17 @@ -1223,7 +1223,7 @@ LL | x_i64 > x_u32; | ^^^^^ | | | expected `i64`, found `u32` - | help: you can convert an `u32` to `i64`: `x_u32.into()` + | help: you can convert a `u32` to an `i64`: `x_u32.into()` error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:287:17 @@ -1231,7 +1231,7 @@ error[E0308]: mismatched types LL | x_i64 > x_u64; | ^^^^^ expected `i64`, found `u64` | -help: you can convert an `u64` to `i64` and panic if the converted value wouldn't fit +help: you can convert a `u64` to an `i64` and panic if the converted value doesn't fit | LL | x_i64 > x_u64.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1242,7 +1242,7 @@ error[E0308]: mismatched types LL | x_i64 > x_u128; | ^^^^^^ expected `i64`, found `u128` | -help: you can convert an `u128` to `i64` and panic if the converted value wouldn't fit +help: you can convert a `u128` to an `i64` and panic if the converted value doesn't fit | LL | x_i64 > x_u128.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1253,7 +1253,7 @@ error[E0308]: mismatched types LL | x_i64 > x_usize; | ^^^^^^^ expected `i64`, found `usize` | -help: you can convert an `usize` to `i64` and panic if the converted value wouldn't fit +help: you can convert a `usize` to an `i64` and panic if the converted value doesn't fit | LL | x_i64 > x_usize.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1265,7 +1265,7 @@ LL | x_i128 > x_u8; | ^^^^ | | | expected `i128`, found `u8` - | help: you can convert an `u8` to `i128`: `x_u8.into()` + | help: you can convert a `u8` to an `i128`: `x_u8.into()` error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:296:18 @@ -1274,7 +1274,7 @@ LL | x_i128 > x_u16; | ^^^^^ | | | expected `i128`, found `u16` - | help: you can convert an `u16` to `i128`: `x_u16.into()` + | help: you can convert a `u16` to an `i128`: `x_u16.into()` error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:298:18 @@ -1283,7 +1283,7 @@ LL | x_i128 > x_u32; | ^^^^^ | | | expected `i128`, found `u32` - | help: you can convert an `u32` to `i128`: `x_u32.into()` + | help: you can convert a `u32` to an `i128`: `x_u32.into()` error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:300:18 @@ -1292,7 +1292,7 @@ LL | x_i128 > x_u64; | ^^^^^ | | | expected `i128`, found `u64` - | help: you can convert an `u64` to `i128`: `x_u64.into()` + | help: you can convert a `u64` to an `i128`: `x_u64.into()` error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:302:18 @@ -1300,7 +1300,7 @@ error[E0308]: mismatched types LL | x_i128 > x_u128; | ^^^^^^ expected `i128`, found `u128` | -help: you can convert an `u128` to `i128` and panic if the converted value wouldn't fit +help: you can convert a `u128` to an `i128` and panic if the converted value doesn't fit | LL | x_i128 > x_u128.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1311,7 +1311,7 @@ error[E0308]: mismatched types LL | x_i128 > x_usize; | ^^^^^^^ expected `i128`, found `usize` | -help: you can convert an `usize` to `i128` and panic if the converted value wouldn't fit +help: you can convert a `usize` to an `i128` and panic if the converted value doesn't fit | LL | x_i128 > x_usize.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1323,7 +1323,7 @@ LL | x_isize > x_u8; | ^^^^ | | | expected `isize`, found `u8` - | help: you can convert an `u8` to `isize`: `x_u8.into()` + | help: you can convert a `u8` to an `isize`: `x_u8.into()` error[E0308]: mismatched types --> $DIR/numeric-cast-binop.rs:309:19 @@ -1331,7 +1331,7 @@ error[E0308]: mismatched types LL | x_isize > x_u16; | ^^^^^ expected `isize`, found `u16` | -help: you can convert an `u16` to `isize` and panic if the converted value wouldn't fit +help: you can convert a `u16` to an `isize` and panic if the converted value doesn't fit | LL | x_isize > x_u16.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1342,7 +1342,7 @@ error[E0308]: mismatched types LL | x_isize > x_u32; | ^^^^^ expected `isize`, found `u32` | -help: you can convert an `u32` to `isize` and panic if the converted value wouldn't fit +help: you can convert a `u32` to an `isize` and panic if the converted value doesn't fit | LL | x_isize > x_u32.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1353,7 +1353,7 @@ error[E0308]: mismatched types LL | x_isize > x_u64; | ^^^^^ expected `isize`, found `u64` | -help: you can convert an `u64` to `isize` and panic if the converted value wouldn't fit +help: you can convert a `u64` to an `isize` and panic if the converted value doesn't fit | LL | x_isize > x_u64.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1364,7 +1364,7 @@ error[E0308]: mismatched types LL | x_isize > x_u128; | ^^^^^^ expected `isize`, found `u128` | -help: you can convert an `u128` to `isize` and panic if the converted value wouldn't fit +help: you can convert a `u128` to an `isize` and panic if the converted value doesn't fit | LL | x_isize > x_u128.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1375,7 +1375,7 @@ error[E0308]: mismatched types LL | x_isize > x_usize; | ^^^^^^^ expected `isize`, found `usize` | -help: you can convert an `usize` to `isize` and panic if the converted value wouldn't fit +help: you can convert a `usize` to an `isize` and panic if the converted value doesn't fit | LL | x_isize > x_usize.try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/numeric/numeric-cast.stderr b/src/test/ui/numeric/numeric-cast.stderr index cc1aa72d214..ffd6368bac1 100644 --- a/src/test/ui/numeric/numeric-cast.stderr +++ b/src/test/ui/numeric/numeric-cast.stderr @@ -4,7 +4,7 @@ error[E0308]: mismatched types LL | foo::<usize>(x_u64); | ^^^^^ expected `usize`, found `u64` | -help: you can convert an `u64` to `usize` and panic if the converted value wouldn't fit +help: you can convert a `u64` to a `usize` and panic if the converted value doesn't fit | LL | foo::<usize>(x_u64.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -15,7 +15,7 @@ error[E0308]: mismatched types LL | foo::<usize>(x_u32); | ^^^^^ expected `usize`, found `u32` | -help: you can convert an `u32` to `usize` and panic if the converted value wouldn't fit +help: you can convert a `u32` to a `usize` and panic if the converted value doesn't fit | LL | foo::<usize>(x_u32.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -27,7 +27,7 @@ LL | foo::<usize>(x_u16); | ^^^^^ | | | expected `usize`, found `u16` - | help: you can convert an `u16` to `usize`: `x_u16.into()` + | help: you can convert a `u16` to a `usize`: `x_u16.into()` error[E0308]: mismatched types --> $DIR/numeric-cast.rs:29:18 @@ -36,7 +36,7 @@ LL | foo::<usize>(x_u8); | ^^^^ | | | expected `usize`, found `u8` - | help: you can convert an `u8` to `usize`: `x_u8.into()` + | help: you can convert a `u8` to a `usize`: `x_u8.into()` error[E0308]: mismatched types --> $DIR/numeric-cast.rs:31:18 @@ -44,7 +44,7 @@ error[E0308]: mismatched types LL | foo::<usize>(x_isize); | ^^^^^^^ expected `usize`, found `isize` | -help: you can convert an `isize` to `usize` and panic if the converted value wouldn't fit +help: you can convert an `isize` to a `usize` and panic if the converted value doesn't fit | LL | foo::<usize>(x_isize.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -55,7 +55,7 @@ error[E0308]: mismatched types LL | foo::<usize>(x_i64); | ^^^^^ expected `usize`, found `i64` | -help: you can convert an `i64` to `usize` and panic if the converted value wouldn't fit +help: you can convert an `i64` to a `usize` and panic if the converted value doesn't fit | LL | foo::<usize>(x_i64.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -66,7 +66,7 @@ error[E0308]: mismatched types LL | foo::<usize>(x_i32); | ^^^^^ expected `usize`, found `i32` | -help: you can convert an `i32` to `usize` and panic if the converted value wouldn't fit +help: you can convert an `i32` to a `usize` and panic if the converted value doesn't fit | LL | foo::<usize>(x_i32.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -77,7 +77,7 @@ error[E0308]: mismatched types LL | foo::<usize>(x_i16); | ^^^^^ expected `usize`, found `i16` | -help: you can convert an `i16` to `usize` and panic if the converted value wouldn't fit +help: you can convert an `i16` to a `usize` and panic if the converted value doesn't fit | LL | foo::<usize>(x_i16.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -88,7 +88,7 @@ error[E0308]: mismatched types LL | foo::<usize>(x_i8); | ^^^^ expected `usize`, found `i8` | -help: you can convert an `i8` to `usize` and panic if the converted value wouldn't fit +help: you can convert an `i8` to a `usize` and panic if the converted value doesn't fit | LL | foo::<usize>(x_i8.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -99,7 +99,7 @@ error[E0308]: mismatched types LL | foo::<isize>(x_usize); | ^^^^^^^ expected `isize`, found `usize` | -help: you can convert an `usize` to `isize` and panic if the converted value wouldn't fit +help: you can convert a `usize` to an `isize` and panic if the converted value doesn't fit | LL | foo::<isize>(x_usize.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -110,7 +110,7 @@ error[E0308]: mismatched types LL | foo::<isize>(x_u64); | ^^^^^ expected `isize`, found `u64` | -help: you can convert an `u64` to `isize` and panic if the converted value wouldn't fit +help: you can convert a `u64` to an `isize` and panic if the converted value doesn't fit | LL | foo::<isize>(x_u64.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -121,7 +121,7 @@ error[E0308]: mismatched types LL | foo::<isize>(x_u32); | ^^^^^ expected `isize`, found `u32` | -help: you can convert an `u32` to `isize` and panic if the converted value wouldn't fit +help: you can convert a `u32` to an `isize` and panic if the converted value doesn't fit | LL | foo::<isize>(x_u32.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -132,7 +132,7 @@ error[E0308]: mismatched types LL | foo::<isize>(x_u16); | ^^^^^ expected `isize`, found `u16` | -help: you can convert an `u16` to `isize` and panic if the converted value wouldn't fit +help: you can convert a `u16` to an `isize` and panic if the converted value doesn't fit | LL | foo::<isize>(x_u16.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -144,7 +144,7 @@ LL | foo::<isize>(x_u8); | ^^^^ | | | expected `isize`, found `u8` - | help: you can convert an `u8` to `isize`: `x_u8.into()` + | help: you can convert a `u8` to an `isize`: `x_u8.into()` error[E0308]: mismatched types --> $DIR/numeric-cast.rs:55:18 @@ -152,7 +152,7 @@ error[E0308]: mismatched types LL | foo::<isize>(x_i64); | ^^^^^ expected `isize`, found `i64` | -help: you can convert an `i64` to `isize` and panic if the converted value wouldn't fit +help: you can convert an `i64` to an `isize` and panic if the converted value doesn't fit | LL | foo::<isize>(x_i64.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -163,7 +163,7 @@ error[E0308]: mismatched types LL | foo::<isize>(x_i32); | ^^^^^ expected `isize`, found `i32` | -help: you can convert an `i32` to `isize` and panic if the converted value wouldn't fit +help: you can convert an `i32` to an `isize` and panic if the converted value doesn't fit | LL | foo::<isize>(x_i32.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -175,7 +175,7 @@ LL | foo::<isize>(x_i16); | ^^^^^ | | | expected `isize`, found `i16` - | help: you can convert an `i16` to `isize`: `x_i16.into()` + | help: you can convert an `i16` to an `isize`: `x_i16.into()` error[E0308]: mismatched types --> $DIR/numeric-cast.rs:61:18 @@ -184,7 +184,7 @@ LL | foo::<isize>(x_i8); | ^^^^ | | | expected `isize`, found `i8` - | help: you can convert an `i8` to `isize`: `x_i8.into()` + | help: you can convert an `i8` to an `isize`: `x_i8.into()` error[E0308]: mismatched types --> $DIR/numeric-cast.rs:66:16 @@ -192,7 +192,7 @@ error[E0308]: mismatched types LL | foo::<u64>(x_usize); | ^^^^^^^ expected `u64`, found `usize` | -help: you can convert an `usize` to `u64` and panic if the converted value wouldn't fit +help: you can convert a `usize` to a `u64` and panic if the converted value doesn't fit | LL | foo::<u64>(x_usize.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -204,7 +204,7 @@ LL | foo::<u64>(x_u32); | ^^^^^ | | | expected `u64`, found `u32` - | help: you can convert an `u32` to `u64`: `x_u32.into()` + | help: you can convert a `u32` to a `u64`: `x_u32.into()` error[E0308]: mismatched types --> $DIR/numeric-cast.rs:71:16 @@ -213,7 +213,7 @@ LL | foo::<u64>(x_u16); | ^^^^^ | | | expected `u64`, found `u16` - | help: you can convert an `u16` to `u64`: `x_u16.into()` + | help: you can convert a `u16` to a `u64`: `x_u16.into()` error[E0308]: mismatched types --> $DIR/numeric-cast.rs:73:16 @@ -222,7 +222,7 @@ LL | foo::<u64>(x_u8); | ^^^^ | | | expected `u64`, found `u8` - | help: you can convert an `u8` to `u64`: `x_u8.into()` + | help: you can convert a `u8` to a `u64`: `x_u8.into()` error[E0308]: mismatched types --> $DIR/numeric-cast.rs:75:16 @@ -230,7 +230,7 @@ error[E0308]: mismatched types LL | foo::<u64>(x_isize); | ^^^^^^^ expected `u64`, found `isize` | -help: you can convert an `isize` to `u64` and panic if the converted value wouldn't fit +help: you can convert an `isize` to a `u64` and panic if the converted value doesn't fit | LL | foo::<u64>(x_isize.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -241,7 +241,7 @@ error[E0308]: mismatched types LL | foo::<u64>(x_i64); | ^^^^^ expected `u64`, found `i64` | -help: you can convert an `i64` to `u64` and panic if the converted value wouldn't fit +help: you can convert an `i64` to a `u64` and panic if the converted value doesn't fit | LL | foo::<u64>(x_i64.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -252,7 +252,7 @@ error[E0308]: mismatched types LL | foo::<u64>(x_i32); | ^^^^^ expected `u64`, found `i32` | -help: you can convert an `i32` to `u64` and panic if the converted value wouldn't fit +help: you can convert an `i32` to a `u64` and panic if the converted value doesn't fit | LL | foo::<u64>(x_i32.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -263,7 +263,7 @@ error[E0308]: mismatched types LL | foo::<u64>(x_i16); | ^^^^^ expected `u64`, found `i16` | -help: you can convert an `i16` to `u64` and panic if the converted value wouldn't fit +help: you can convert an `i16` to a `u64` and panic if the converted value doesn't fit | LL | foo::<u64>(x_i16.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -274,7 +274,7 @@ error[E0308]: mismatched types LL | foo::<u64>(x_i8); | ^^^^ expected `u64`, found `i8` | -help: you can convert an `i8` to `u64` and panic if the converted value wouldn't fit +help: you can convert an `i8` to a `u64` and panic if the converted value doesn't fit | LL | foo::<u64>(x_i8.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -285,7 +285,7 @@ error[E0308]: mismatched types LL | foo::<i64>(x_usize); | ^^^^^^^ expected `i64`, found `usize` | -help: you can convert an `usize` to `i64` and panic if the converted value wouldn't fit +help: you can convert a `usize` to an `i64` and panic if the converted value doesn't fit | LL | foo::<i64>(x_usize.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -296,7 +296,7 @@ error[E0308]: mismatched types LL | foo::<i64>(x_u64); | ^^^^^ expected `i64`, found `u64` | -help: you can convert an `u64` to `i64` and panic if the converted value wouldn't fit +help: you can convert a `u64` to an `i64` and panic if the converted value doesn't fit | LL | foo::<i64>(x_u64.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -308,7 +308,7 @@ LL | foo::<i64>(x_u32); | ^^^^^ | | | expected `i64`, found `u32` - | help: you can convert an `u32` to `i64`: `x_u32.into()` + | help: you can convert a `u32` to an `i64`: `x_u32.into()` error[E0308]: mismatched types --> $DIR/numeric-cast.rs:94:16 @@ -317,7 +317,7 @@ LL | foo::<i64>(x_u16); | ^^^^^ | | | expected `i64`, found `u16` - | help: you can convert an `u16` to `i64`: `x_u16.into()` + | help: you can convert a `u16` to an `i64`: `x_u16.into()` error[E0308]: mismatched types --> $DIR/numeric-cast.rs:96:16 @@ -326,7 +326,7 @@ LL | foo::<i64>(x_u8); | ^^^^ | | | expected `i64`, found `u8` - | help: you can convert an `u8` to `i64`: `x_u8.into()` + | help: you can convert a `u8` to an `i64`: `x_u8.into()` error[E0308]: mismatched types --> $DIR/numeric-cast.rs:98:16 @@ -334,7 +334,7 @@ error[E0308]: mismatched types LL | foo::<i64>(x_isize); | ^^^^^^^ expected `i64`, found `isize` | -help: you can convert an `isize` to `i64` and panic if the converted value wouldn't fit +help: you can convert an `isize` to an `i64` and panic if the converted value doesn't fit | LL | foo::<i64>(x_isize.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -346,7 +346,7 @@ LL | foo::<i64>(x_i32); | ^^^^^ | | | expected `i64`, found `i32` - | help: you can convert an `i32` to `i64`: `x_i32.into()` + | help: you can convert an `i32` to an `i64`: `x_i32.into()` error[E0308]: mismatched types --> $DIR/numeric-cast.rs:103:16 @@ -355,7 +355,7 @@ LL | foo::<i64>(x_i16); | ^^^^^ | | | expected `i64`, found `i16` - | help: you can convert an `i16` to `i64`: `x_i16.into()` + | help: you can convert an `i16` to an `i64`: `x_i16.into()` error[E0308]: mismatched types --> $DIR/numeric-cast.rs:105:16 @@ -364,7 +364,7 @@ LL | foo::<i64>(x_i8); | ^^^^ | | | expected `i64`, found `i8` - | help: you can convert an `i8` to `i64`: `x_i8.into()` + | help: you can convert an `i8` to an `i64`: `x_i8.into()` error[E0308]: mismatched types --> $DIR/numeric-cast.rs:110:16 @@ -372,7 +372,7 @@ error[E0308]: mismatched types LL | foo::<u32>(x_usize); | ^^^^^^^ expected `u32`, found `usize` | -help: you can convert an `usize` to `u32` and panic if the converted value wouldn't fit +help: you can convert a `usize` to a `u32` and panic if the converted value doesn't fit | LL | foo::<u32>(x_usize.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -383,7 +383,7 @@ error[E0308]: mismatched types LL | foo::<u32>(x_u64); | ^^^^^ expected `u32`, found `u64` | -help: you can convert an `u64` to `u32` and panic if the converted value wouldn't fit +help: you can convert a `u64` to a `u32` and panic if the converted value doesn't fit | LL | foo::<u32>(x_u64.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -395,7 +395,7 @@ LL | foo::<u32>(x_u16); | ^^^^^ | | | expected `u32`, found `u16` - | help: you can convert an `u16` to `u32`: `x_u16.into()` + | help: you can convert a `u16` to a `u32`: `x_u16.into()` error[E0308]: mismatched types --> $DIR/numeric-cast.rs:117:16 @@ -404,7 +404,7 @@ LL | foo::<u32>(x_u8); | ^^^^ | | | expected `u32`, found `u8` - | help: you can convert an `u8` to `u32`: `x_u8.into()` + | help: you can convert a `u8` to a `u32`: `x_u8.into()` error[E0308]: mismatched types --> $DIR/numeric-cast.rs:119:16 @@ -412,7 +412,7 @@ error[E0308]: mismatched types LL | foo::<u32>(x_isize); | ^^^^^^^ expected `u32`, found `isize` | -help: you can convert an `isize` to `u32` and panic if the converted value wouldn't fit +help: you can convert an `isize` to a `u32` and panic if the converted value doesn't fit | LL | foo::<u32>(x_isize.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -423,7 +423,7 @@ error[E0308]: mismatched types LL | foo::<u32>(x_i64); | ^^^^^ expected `u32`, found `i64` | -help: you can convert an `i64` to `u32` and panic if the converted value wouldn't fit +help: you can convert an `i64` to a `u32` and panic if the converted value doesn't fit | LL | foo::<u32>(x_i64.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -434,7 +434,7 @@ error[E0308]: mismatched types LL | foo::<u32>(x_i32); | ^^^^^ expected `u32`, found `i32` | -help: you can convert an `i32` to `u32` and panic if the converted value wouldn't fit +help: you can convert an `i32` to a `u32` and panic if the converted value doesn't fit | LL | foo::<u32>(x_i32.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -445,7 +445,7 @@ error[E0308]: mismatched types LL | foo::<u32>(x_i16); | ^^^^^ expected `u32`, found `i16` | -help: you can convert an `i16` to `u32` and panic if the converted value wouldn't fit +help: you can convert an `i16` to a `u32` and panic if the converted value doesn't fit | LL | foo::<u32>(x_i16.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -456,7 +456,7 @@ error[E0308]: mismatched types LL | foo::<u32>(x_i8); | ^^^^ expected `u32`, found `i8` | -help: you can convert an `i8` to `u32` and panic if the converted value wouldn't fit +help: you can convert an `i8` to a `u32` and panic if the converted value doesn't fit | LL | foo::<u32>(x_i8.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -467,7 +467,7 @@ error[E0308]: mismatched types LL | foo::<i32>(x_usize); | ^^^^^^^ expected `i32`, found `usize` | -help: you can convert an `usize` to `i32` and panic if the converted value wouldn't fit +help: you can convert a `usize` to an `i32` and panic if the converted value doesn't fit | LL | foo::<i32>(x_usize.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -478,7 +478,7 @@ error[E0308]: mismatched types LL | foo::<i32>(x_u64); | ^^^^^ expected `i32`, found `u64` | -help: you can convert an `u64` to `i32` and panic if the converted value wouldn't fit +help: you can convert a `u64` to an `i32` and panic if the converted value doesn't fit | LL | foo::<i32>(x_u64.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -489,7 +489,7 @@ error[E0308]: mismatched types LL | foo::<i32>(x_u32); | ^^^^^ expected `i32`, found `u32` | -help: you can convert an `u32` to `i32` and panic if the converted value wouldn't fit +help: you can convert a `u32` to an `i32` and panic if the converted value doesn't fit | LL | foo::<i32>(x_u32.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -501,7 +501,7 @@ LL | foo::<i32>(x_u16); | ^^^^^ | | | expected `i32`, found `u16` - | help: you can convert an `u16` to `i32`: `x_u16.into()` + | help: you can convert a `u16` to an `i32`: `x_u16.into()` error[E0308]: mismatched types --> $DIR/numeric-cast.rs:140:16 @@ -510,7 +510,7 @@ LL | foo::<i32>(x_u8); | ^^^^ | | | expected `i32`, found `u8` - | help: you can convert an `u8` to `i32`: `x_u8.into()` + | help: you can convert a `u8` to an `i32`: `x_u8.into()` error[E0308]: mismatched types --> $DIR/numeric-cast.rs:142:16 @@ -518,7 +518,7 @@ error[E0308]: mismatched types LL | foo::<i32>(x_isize); | ^^^^^^^ expected `i32`, found `isize` | -help: you can convert an `isize` to `i32` and panic if the converted value wouldn't fit +help: you can convert an `isize` to an `i32` and panic if the converted value doesn't fit | LL | foo::<i32>(x_isize.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -529,7 +529,7 @@ error[E0308]: mismatched types LL | foo::<i32>(x_i64); | ^^^^^ expected `i32`, found `i64` | -help: you can convert an `i64` to `i32` and panic if the converted value wouldn't fit +help: you can convert an `i64` to an `i32` and panic if the converted value doesn't fit | LL | foo::<i32>(x_i64.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -541,7 +541,7 @@ LL | foo::<i32>(x_i16); | ^^^^^ | | | expected `i32`, found `i16` - | help: you can convert an `i16` to `i32`: `x_i16.into()` + | help: you can convert an `i16` to an `i32`: `x_i16.into()` error[E0308]: mismatched types --> $DIR/numeric-cast.rs:149:16 @@ -550,7 +550,7 @@ LL | foo::<i32>(x_i8); | ^^^^ | | | expected `i32`, found `i8` - | help: you can convert an `i8` to `i32`: `x_i8.into()` + | help: you can convert an `i8` to an `i32`: `x_i8.into()` error[E0308]: mismatched types --> $DIR/numeric-cast.rs:154:16 @@ -558,7 +558,7 @@ error[E0308]: mismatched types LL | foo::<u16>(x_usize); | ^^^^^^^ expected `u16`, found `usize` | -help: you can convert an `usize` to `u16` and panic if the converted value wouldn't fit +help: you can convert a `usize` to a `u16` and panic if the converted value doesn't fit | LL | foo::<u16>(x_usize.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -569,7 +569,7 @@ error[E0308]: mismatched types LL | foo::<u16>(x_u64); | ^^^^^ expected `u16`, found `u64` | -help: you can convert an `u64` to `u16` and panic if the converted value wouldn't fit +help: you can convert a `u64` to a `u16` and panic if the converted value doesn't fit | LL | foo::<u16>(x_u64.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -580,7 +580,7 @@ error[E0308]: mismatched types LL | foo::<u16>(x_u32); | ^^^^^ expected `u16`, found `u32` | -help: you can convert an `u32` to `u16` and panic if the converted value wouldn't fit +help: you can convert a `u32` to a `u16` and panic if the converted value doesn't fit | LL | foo::<u16>(x_u32.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -592,7 +592,7 @@ LL | foo::<u16>(x_u8); | ^^^^ | | | expected `u16`, found `u8` - | help: you can convert an `u8` to `u16`: `x_u8.into()` + | help: you can convert a `u8` to a `u16`: `x_u8.into()` error[E0308]: mismatched types --> $DIR/numeric-cast.rs:163:16 @@ -600,7 +600,7 @@ error[E0308]: mismatched types LL | foo::<u16>(x_isize); | ^^^^^^^ expected `u16`, found `isize` | -help: you can convert an `isize` to `u16` and panic if the converted value wouldn't fit +help: you can convert an `isize` to a `u16` and panic if the converted value doesn't fit | LL | foo::<u16>(x_isize.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -611,7 +611,7 @@ error[E0308]: mismatched types LL | foo::<u16>(x_i64); | ^^^^^ expected `u16`, found `i64` | -help: you can convert an `i64` to `u16` and panic if the converted value wouldn't fit +help: you can convert an `i64` to a `u16` and panic if the converted value doesn't fit | LL | foo::<u16>(x_i64.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -622,7 +622,7 @@ error[E0308]: mismatched types LL | foo::<u16>(x_i32); | ^^^^^ expected `u16`, found `i32` | -help: you can convert an `i32` to `u16` and panic if the converted value wouldn't fit +help: you can convert an `i32` to a `u16` and panic if the converted value doesn't fit | LL | foo::<u16>(x_i32.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -633,7 +633,7 @@ error[E0308]: mismatched types LL | foo::<u16>(x_i16); | ^^^^^ expected `u16`, found `i16` | -help: you can convert an `i16` to `u16` and panic if the converted value wouldn't fit +help: you can convert an `i16` to a `u16` and panic if the converted value doesn't fit | LL | foo::<u16>(x_i16.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -644,7 +644,7 @@ error[E0308]: mismatched types LL | foo::<u16>(x_i8); | ^^^^ expected `u16`, found `i8` | -help: you can convert an `i8` to `u16` and panic if the converted value wouldn't fit +help: you can convert an `i8` to a `u16` and panic if the converted value doesn't fit | LL | foo::<u16>(x_i8.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -655,7 +655,7 @@ error[E0308]: mismatched types LL | foo::<i16>(x_usize); | ^^^^^^^ expected `i16`, found `usize` | -help: you can convert an `usize` to `i16` and panic if the converted value wouldn't fit +help: you can convert a `usize` to an `i16` and panic if the converted value doesn't fit | LL | foo::<i16>(x_usize.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -666,7 +666,7 @@ error[E0308]: mismatched types LL | foo::<i16>(x_u64); | ^^^^^ expected `i16`, found `u64` | -help: you can convert an `u64` to `i16` and panic if the converted value wouldn't fit +help: you can convert a `u64` to an `i16` and panic if the converted value doesn't fit | LL | foo::<i16>(x_u64.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -677,7 +677,7 @@ error[E0308]: mismatched types LL | foo::<i16>(x_u32); | ^^^^^ expected `i16`, found `u32` | -help: you can convert an `u32` to `i16` and panic if the converted value wouldn't fit +help: you can convert a `u32` to an `i16` and panic if the converted value doesn't fit | LL | foo::<i16>(x_u32.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -688,7 +688,7 @@ error[E0308]: mismatched types LL | foo::<i16>(x_u16); | ^^^^^ expected `i16`, found `u16` | -help: you can convert an `u16` to `i16` and panic if the converted value wouldn't fit +help: you can convert a `u16` to an `i16` and panic if the converted value doesn't fit | LL | foo::<i16>(x_u16.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -700,7 +700,7 @@ LL | foo::<i16>(x_u8); | ^^^^ | | | expected `i16`, found `u8` - | help: you can convert an `u8` to `i16`: `x_u8.into()` + | help: you can convert a `u8` to an `i16`: `x_u8.into()` error[E0308]: mismatched types --> $DIR/numeric-cast.rs:186:16 @@ -708,7 +708,7 @@ error[E0308]: mismatched types LL | foo::<i16>(x_isize); | ^^^^^^^ expected `i16`, found `isize` | -help: you can convert an `isize` to `i16` and panic if the converted value wouldn't fit +help: you can convert an `isize` to an `i16` and panic if the converted value doesn't fit | LL | foo::<i16>(x_isize.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -719,7 +719,7 @@ error[E0308]: mismatched types LL | foo::<i16>(x_i64); | ^^^^^ expected `i16`, found `i64` | -help: you can convert an `i64` to `i16` and panic if the converted value wouldn't fit +help: you can convert an `i64` to an `i16` and panic if the converted value doesn't fit | LL | foo::<i16>(x_i64.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -730,7 +730,7 @@ error[E0308]: mismatched types LL | foo::<i16>(x_i32); | ^^^^^ expected `i16`, found `i32` | -help: you can convert an `i32` to `i16` and panic if the converted value wouldn't fit +help: you can convert an `i32` to an `i16` and panic if the converted value doesn't fit | LL | foo::<i16>(x_i32.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -742,7 +742,7 @@ LL | foo::<i16>(x_i8); | ^^^^ | | | expected `i16`, found `i8` - | help: you can convert an `i8` to `i16`: `x_i8.into()` + | help: you can convert an `i8` to an `i16`: `x_i8.into()` error[E0308]: mismatched types --> $DIR/numeric-cast.rs:198:15 @@ -750,7 +750,7 @@ error[E0308]: mismatched types LL | foo::<u8>(x_usize); | ^^^^^^^ expected `u8`, found `usize` | -help: you can convert an `usize` to `u8` and panic if the converted value wouldn't fit +help: you can convert a `usize` to a `u8` and panic if the converted value doesn't fit | LL | foo::<u8>(x_usize.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -761,7 +761,7 @@ error[E0308]: mismatched types LL | foo::<u8>(x_u64); | ^^^^^ expected `u8`, found `u64` | -help: you can convert an `u64` to `u8` and panic if the converted value wouldn't fit +help: you can convert a `u64` to a `u8` and panic if the converted value doesn't fit | LL | foo::<u8>(x_u64.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -772,7 +772,7 @@ error[E0308]: mismatched types LL | foo::<u8>(x_u32); | ^^^^^ expected `u8`, found `u32` | -help: you can convert an `u32` to `u8` and panic if the converted value wouldn't fit +help: you can convert a `u32` to a `u8` and panic if the converted value doesn't fit | LL | foo::<u8>(x_u32.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -783,7 +783,7 @@ error[E0308]: mismatched types LL | foo::<u8>(x_u16); | ^^^^^ expected `u8`, found `u16` | -help: you can convert an `u16` to `u8` and panic if the converted value wouldn't fit +help: you can convert a `u16` to a `u8` and panic if the converted value doesn't fit | LL | foo::<u8>(x_u16.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -794,7 +794,7 @@ error[E0308]: mismatched types LL | foo::<u8>(x_isize); | ^^^^^^^ expected `u8`, found `isize` | -help: you can convert an `isize` to `u8` and panic if the converted value wouldn't fit +help: you can convert an `isize` to a `u8` and panic if the converted value doesn't fit | LL | foo::<u8>(x_isize.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -805,7 +805,7 @@ error[E0308]: mismatched types LL | foo::<u8>(x_i64); | ^^^^^ expected `u8`, found `i64` | -help: you can convert an `i64` to `u8` and panic if the converted value wouldn't fit +help: you can convert an `i64` to a `u8` and panic if the converted value doesn't fit | LL | foo::<u8>(x_i64.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -816,7 +816,7 @@ error[E0308]: mismatched types LL | foo::<u8>(x_i32); | ^^^^^ expected `u8`, found `i32` | -help: you can convert an `i32` to `u8` and panic if the converted value wouldn't fit +help: you can convert an `i32` to a `u8` and panic if the converted value doesn't fit | LL | foo::<u8>(x_i32.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -827,7 +827,7 @@ error[E0308]: mismatched types LL | foo::<u8>(x_i16); | ^^^^^ expected `u8`, found `i16` | -help: you can convert an `i16` to `u8` and panic if the converted value wouldn't fit +help: you can convert an `i16` to a `u8` and panic if the converted value doesn't fit | LL | foo::<u8>(x_i16.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -838,7 +838,7 @@ error[E0308]: mismatched types LL | foo::<u8>(x_i8); | ^^^^ expected `u8`, found `i8` | -help: you can convert an `i8` to `u8` and panic if the converted value wouldn't fit +help: you can convert an `i8` to a `u8` and panic if the converted value doesn't fit | LL | foo::<u8>(x_i8.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -849,7 +849,7 @@ error[E0308]: mismatched types LL | foo::<i8>(x_usize); | ^^^^^^^ expected `i8`, found `usize` | -help: you can convert an `usize` to `i8` and panic if the converted value wouldn't fit +help: you can convert a `usize` to an `i8` and panic if the converted value doesn't fit | LL | foo::<i8>(x_usize.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -860,7 +860,7 @@ error[E0308]: mismatched types LL | foo::<i8>(x_u64); | ^^^^^ expected `i8`, found `u64` | -help: you can convert an `u64` to `i8` and panic if the converted value wouldn't fit +help: you can convert a `u64` to an `i8` and panic if the converted value doesn't fit | LL | foo::<i8>(x_u64.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -871,7 +871,7 @@ error[E0308]: mismatched types LL | foo::<i8>(x_u32); | ^^^^^ expected `i8`, found `u32` | -help: you can convert an `u32` to `i8` and panic if the converted value wouldn't fit +help: you can convert a `u32` to an `i8` and panic if the converted value doesn't fit | LL | foo::<i8>(x_u32.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -882,7 +882,7 @@ error[E0308]: mismatched types LL | foo::<i8>(x_u16); | ^^^^^ expected `i8`, found `u16` | -help: you can convert an `u16` to `i8` and panic if the converted value wouldn't fit +help: you can convert a `u16` to an `i8` and panic if the converted value doesn't fit | LL | foo::<i8>(x_u16.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -893,7 +893,7 @@ error[E0308]: mismatched types LL | foo::<i8>(x_u8); | ^^^^ expected `i8`, found `u8` | -help: you can convert an `u8` to `i8` and panic if the converted value wouldn't fit +help: you can convert a `u8` to an `i8` and panic if the converted value doesn't fit | LL | foo::<i8>(x_u8.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -904,7 +904,7 @@ error[E0308]: mismatched types LL | foo::<i8>(x_isize); | ^^^^^^^ expected `i8`, found `isize` | -help: you can convert an `isize` to `i8` and panic if the converted value wouldn't fit +help: you can convert an `isize` to an `i8` and panic if the converted value doesn't fit | LL | foo::<i8>(x_isize.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -915,7 +915,7 @@ error[E0308]: mismatched types LL | foo::<i8>(x_i64); | ^^^^^ expected `i8`, found `i64` | -help: you can convert an `i64` to `i8` and panic if the converted value wouldn't fit +help: you can convert an `i64` to an `i8` and panic if the converted value doesn't fit | LL | foo::<i8>(x_i64.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -926,7 +926,7 @@ error[E0308]: mismatched types LL | foo::<i8>(x_i32); | ^^^^^ expected `i8`, found `i32` | -help: you can convert an `i32` to `i8` and panic if the converted value wouldn't fit +help: you can convert an `i32` to an `i8` and panic if the converted value doesn't fit | LL | foo::<i8>(x_i32.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -937,7 +937,7 @@ error[E0308]: mismatched types LL | foo::<i8>(x_i16); | ^^^^^ expected `i8`, found `i16` | -help: you can convert an `i16` to `i8` and panic if the converted value wouldn't fit +help: you can convert an `i16` to an `i8` and panic if the converted value doesn't fit | LL | foo::<i8>(x_i16.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -948,7 +948,7 @@ error[E0308]: mismatched types LL | foo::<f64>(x_usize); | ^^^^^^^ expected `f64`, found `usize` | -help: you can cast an `usize to `f64`, producing the floating point representation of the integer, +help: you can cast a `usize` to an `f64`, producing the floating point representation of the integer, | rounded if necessary LL | foo::<f64>(x_usize as f64); | ^^^^^^^^^^^^^^ @@ -959,7 +959,7 @@ error[E0308]: mismatched types LL | foo::<f64>(x_u64); | ^^^^^ expected `f64`, found `u64` | -help: you can cast an `u64 to `f64`, producing the floating point representation of the integer, +help: you can cast a `u64` to an `f64`, producing the floating point representation of the integer, | rounded if necessary LL | foo::<f64>(x_u64 as f64); | ^^^^^^^^^^^^ @@ -970,7 +970,7 @@ error[E0308]: mismatched types LL | foo::<f64>(x_u32); | ^^^^^ expected `f64`, found `u32` | -help: you can convert an `u32` to `f64`, producing the floating point representation of the integer +help: you can convert a `u32` to an `f64`, producing the floating point representation of the integer | LL | foo::<f64>(x_u32.into()); | ^^^^^^^^^^^^ @@ -981,7 +981,7 @@ error[E0308]: mismatched types LL | foo::<f64>(x_u16); | ^^^^^ expected `f64`, found `u16` | -help: you can convert an `u16` to `f64`, producing the floating point representation of the integer +help: you can convert a `u16` to an `f64`, producing the floating point representation of the integer | LL | foo::<f64>(x_u16.into()); | ^^^^^^^^^^^^ @@ -992,7 +992,7 @@ error[E0308]: mismatched types LL | foo::<f64>(x_u8); | ^^^^ expected `f64`, found `u8` | -help: you can convert an `u8` to `f64`, producing the floating point representation of the integer +help: you can convert a `u8` to an `f64`, producing the floating point representation of the integer | LL | foo::<f64>(x_u8.into()); | ^^^^^^^^^^^ @@ -1003,7 +1003,7 @@ error[E0308]: mismatched types LL | foo::<f64>(x_isize); | ^^^^^^^ expected `f64`, found `isize` | -help: you can convert an `isize` to `f64`, producing the floating point representation of the integer, rounded if necessary +help: you can convert an `isize` to an `f64`, producing the floating point representation of the integer, rounded if necessary | LL | foo::<f64>(x_isize as f64); | ^^^^^^^^^^^^^^ @@ -1014,7 +1014,7 @@ error[E0308]: mismatched types LL | foo::<f64>(x_i64); | ^^^^^ expected `f64`, found `i64` | -help: you can convert an `i64` to `f64`, producing the floating point representation of the integer, rounded if necessary +help: you can convert an `i64` to an `f64`, producing the floating point representation of the integer, rounded if necessary | LL | foo::<f64>(x_i64 as f64); | ^^^^^^^^^^^^ @@ -1025,7 +1025,7 @@ error[E0308]: mismatched types LL | foo::<f64>(x_i32); | ^^^^^ expected `f64`, found `i32` | -help: you can convert an `i32` to `f64`, producing the floating point representation of the integer +help: you can convert an `i32` to an `f64`, producing the floating point representation of the integer | LL | foo::<f64>(x_i32.into()); | ^^^^^^^^^^^^ @@ -1036,7 +1036,7 @@ error[E0308]: mismatched types LL | foo::<f64>(x_i16); | ^^^^^ expected `f64`, found `i16` | -help: you can convert an `i16` to `f64`, producing the floating point representation of the integer +help: you can convert an `i16` to an `f64`, producing the floating point representation of the integer | LL | foo::<f64>(x_i16.into()); | ^^^^^^^^^^^^ @@ -1047,7 +1047,7 @@ error[E0308]: mismatched types LL | foo::<f64>(x_i8); | ^^^^ expected `f64`, found `i8` | -help: you can convert an `i8` to `f64`, producing the floating point representation of the integer +help: you can convert an `i8` to an `f64`, producing the floating point representation of the integer | LL | foo::<f64>(x_i8.into()); | ^^^^^^^^^^^ @@ -1059,7 +1059,7 @@ LL | foo::<f64>(x_f32); | ^^^^^ | | | expected `f64`, found `f32` - | help: you can convert an `f32` to `f64`: `x_f32.into()` + | help: you can convert an `f32` to an `f64`: `x_f32.into()` error[E0308]: mismatched types --> $DIR/numeric-cast.rs:266:16 @@ -1067,7 +1067,7 @@ error[E0308]: mismatched types LL | foo::<f32>(x_usize); | ^^^^^^^ expected `f32`, found `usize` | -help: you can cast an `usize to `f32`, producing the floating point representation of the integer, +help: you can cast a `usize` to an `f32`, producing the floating point representation of the integer, | rounded if necessary LL | foo::<f32>(x_usize as f32); | ^^^^^^^^^^^^^^ @@ -1078,7 +1078,7 @@ error[E0308]: mismatched types LL | foo::<f32>(x_u64); | ^^^^^ expected `f32`, found `u64` | -help: you can cast an `u64 to `f32`, producing the floating point representation of the integer, +help: you can cast a `u64` to an `f32`, producing the floating point representation of the integer, | rounded if necessary LL | foo::<f32>(x_u64 as f32); | ^^^^^^^^^^^^ @@ -1089,7 +1089,7 @@ error[E0308]: mismatched types LL | foo::<f32>(x_u32); | ^^^^^ expected `f32`, found `u32` | -help: you can cast an `u32 to `f32`, producing the floating point representation of the integer, +help: you can cast a `u32` to an `f32`, producing the floating point representation of the integer, | rounded if necessary LL | foo::<f32>(x_u32 as f32); | ^^^^^^^^^^^^ @@ -1100,7 +1100,7 @@ error[E0308]: mismatched types LL | foo::<f32>(x_u16); | ^^^^^ expected `f32`, found `u16` | -help: you can convert an `u16` to `f32`, producing the floating point representation of the integer +help: you can convert a `u16` to an `f32`, producing the floating point representation of the integer | LL | foo::<f32>(x_u16.into()); | ^^^^^^^^^^^^ @@ -1111,7 +1111,7 @@ error[E0308]: mismatched types LL | foo::<f32>(x_u8); | ^^^^ expected `f32`, found `u8` | -help: you can convert an `u8` to `f32`, producing the floating point representation of the integer +help: you can convert a `u8` to an `f32`, producing the floating point representation of the integer | LL | foo::<f32>(x_u8.into()); | ^^^^^^^^^^^ @@ -1122,7 +1122,7 @@ error[E0308]: mismatched types LL | foo::<f32>(x_isize); | ^^^^^^^ expected `f32`, found `isize` | -help: you can convert an `isize` to `f32`, producing the floating point representation of the integer, rounded if necessary +help: you can convert an `isize` to an `f32`, producing the floating point representation of the integer, rounded if necessary | LL | foo::<f32>(x_isize as f32); | ^^^^^^^^^^^^^^ @@ -1133,7 +1133,7 @@ error[E0308]: mismatched types LL | foo::<f32>(x_i64); | ^^^^^ expected `f32`, found `i64` | -help: you can convert an `i64` to `f32`, producing the floating point representation of the integer, rounded if necessary +help: you can convert an `i64` to an `f32`, producing the floating point representation of the integer, rounded if necessary | LL | foo::<f32>(x_i64 as f32); | ^^^^^^^^^^^^ @@ -1144,7 +1144,7 @@ error[E0308]: mismatched types LL | foo::<f32>(x_i32); | ^^^^^ expected `f32`, found `i32` | -help: you can convert an `i32` to `f32`, producing the floating point representation of the integer, rounded if necessary +help: you can convert an `i32` to an `f32`, producing the floating point representation of the integer, rounded if necessary | LL | foo::<f32>(x_i32 as f32); | ^^^^^^^^^^^^ @@ -1155,7 +1155,7 @@ error[E0308]: mismatched types LL | foo::<f32>(x_i16); | ^^^^^ expected `f32`, found `i16` | -help: you can convert an `i16` to `f32`, producing the floating point representation of the integer +help: you can convert an `i16` to an `f32`, producing the floating point representation of the integer | LL | foo::<f32>(x_i16.into()); | ^^^^^^^^^^^^ @@ -1166,7 +1166,7 @@ error[E0308]: mismatched types LL | foo::<f32>(x_i8); | ^^^^ expected `f32`, found `i8` | -help: you can convert an `i8` to `f32`, producing the floating point representation of the integer +help: you can convert an `i8` to an `f32`, producing the floating point representation of the integer | LL | foo::<f32>(x_i8.into()); | ^^^^^^^^^^^ @@ -1178,7 +1178,7 @@ LL | foo::<u32>(x_u8 as u16); | ^^^^^^^^^^^ | | | expected `u32`, found `u16` - | help: you can convert an `u16` to `u32`: `(x_u8 as u16).into()` + | help: you can convert a `u16` to a `u32`: `(x_u8 as u16).into()` error[E0308]: mismatched types --> $DIR/numeric-cast.rs:291:16 @@ -1187,7 +1187,7 @@ LL | foo::<i32>(-x_i8); | ^^^^^ | | | expected `i32`, found `i8` - | help: you can convert an `i8` to `i32`: `(-x_i8).into()` + | help: you can convert an `i8` to an `i32`: `(-x_i8).into()` error: aborting due to 113 previous errors diff --git a/src/test/ui/numeric/numeric-suffix.stderr b/src/test/ui/numeric/numeric-suffix.stderr index 00f6e1abe43..a62956ee8da 100644 --- a/src/test/ui/numeric/numeric-suffix.stderr +++ b/src/test/ui/numeric/numeric-suffix.stderr @@ -1236,7 +1236,7 @@ error[E0308]: mismatched types LL | foo::<f64>(42_u32); | ^^^^^^ expected `f64`, found `u32` | -help: you can convert an `u32` to `f64`, producing the floating point representation of the integer +help: you can convert a `u32` to an `f64`, producing the floating point representation of the integer | LL | foo::<f64>(42_u32.into()); | ^^^^^^^^^^^^^ @@ -1247,7 +1247,7 @@ error[E0308]: mismatched types LL | foo::<f64>(42_u16); | ^^^^^^ expected `f64`, found `u16` | -help: you can convert an `u16` to `f64`, producing the floating point representation of the integer +help: you can convert a `u16` to an `f64`, producing the floating point representation of the integer | LL | foo::<f64>(42_u16.into()); | ^^^^^^^^^^^^^ @@ -1258,7 +1258,7 @@ error[E0308]: mismatched types LL | foo::<f64>(42_u8); | ^^^^^ expected `f64`, found `u8` | -help: you can convert an `u8` to `f64`, producing the floating point representation of the integer +help: you can convert a `u8` to an `f64`, producing the floating point representation of the integer | LL | foo::<f64>(42_u8.into()); | ^^^^^^^^^^^^ @@ -1291,7 +1291,7 @@ error[E0308]: mismatched types LL | foo::<f64>(42_i32); | ^^^^^^ expected `f64`, found `i32` | -help: you can convert an `i32` to `f64`, producing the floating point representation of the integer +help: you can convert an `i32` to an `f64`, producing the floating point representation of the integer | LL | foo::<f64>(42_i32.into()); | ^^^^^^^^^^^^^ @@ -1302,7 +1302,7 @@ error[E0308]: mismatched types LL | foo::<f64>(42_i16); | ^^^^^^ expected `f64`, found `i16` | -help: you can convert an `i16` to `f64`, producing the floating point representation of the integer +help: you can convert an `i16` to an `f64`, producing the floating point representation of the integer | LL | foo::<f64>(42_i16.into()); | ^^^^^^^^^^^^^ @@ -1313,7 +1313,7 @@ error[E0308]: mismatched types LL | foo::<f64>(42_i8); | ^^^^^ expected `f64`, found `i8` | -help: you can convert an `i8` to `f64`, producing the floating point representation of the integer +help: you can convert an `i8` to an `f64`, producing the floating point representation of the integer | LL | foo::<f64>(42_i8.into()); | ^^^^^^^^^^^^ @@ -1368,7 +1368,7 @@ error[E0308]: mismatched types LL | foo::<f32>(42_u16); | ^^^^^^ expected `f32`, found `u16` | -help: you can convert an `u16` to `f32`, producing the floating point representation of the integer +help: you can convert a `u16` to an `f32`, producing the floating point representation of the integer | LL | foo::<f32>(42_u16.into()); | ^^^^^^^^^^^^^ @@ -1379,7 +1379,7 @@ error[E0308]: mismatched types LL | foo::<f32>(42_u8); | ^^^^^ expected `f32`, found `u8` | -help: you can convert an `u8` to `f32`, producing the floating point representation of the integer +help: you can convert a `u8` to an `f32`, producing the floating point representation of the integer | LL | foo::<f32>(42_u8.into()); | ^^^^^^^^^^^^ @@ -1423,7 +1423,7 @@ error[E0308]: mismatched types LL | foo::<f32>(42_i16); | ^^^^^^ expected `f32`, found `i16` | -help: you can convert an `i16` to `f32`, producing the floating point representation of the integer +help: you can convert an `i16` to an `f32`, producing the floating point representation of the integer | LL | foo::<f32>(42_i16.into()); | ^^^^^^^^^^^^^ @@ -1434,7 +1434,7 @@ error[E0308]: mismatched types LL | foo::<f32>(42_i8); | ^^^^^ expected `f32`, found `i8` | -help: you can convert an `i8` to `f32`, producing the floating point representation of the integer +help: you can convert an `i8` to an `f32`, producing the floating point representation of the integer | LL | foo::<f32>(42_i8.into()); | ^^^^^^^^^^^^ @@ -1457,7 +1457,7 @@ LL | foo::<u32>(42_u8 as u16); | ^^^^^^^^^^^^ | | | expected `u32`, found `u16` - | help: you can convert an `u16` to `u32`: `(42_u8 as u16).into()` + | help: you can convert a `u16` to a `u32`: `(42_u8 as u16).into()` error[E0308]: mismatched types --> $DIR/numeric-suffix.rs:296:16 @@ -1466,7 +1466,7 @@ LL | foo::<i32>(-42_i8); | ^^^^^^ | | | expected `i32`, found `i8` - | help: you can convert an `i8` to `i32`: `(-42_i8).into()` + | help: you can convert an `i8` to an `i32`: `(-42_i8).into()` error: aborting due to 134 previous errors diff --git a/src/test/ui/orphan-check-diagnostics.stderr b/src/test/ui/orphan-check-diagnostics.stderr index c84d401898c..7a7cea56307 100644 --- a/src/test/ui/orphan-check-diagnostics.stderr +++ b/src/test/ui/orphan-check-diagnostics.stderr @@ -4,7 +4,7 @@ error[E0210]: type parameter `T` must be used as the type parameter for some loc LL | impl<T> RemoteTrait for T where T: LocalTrait {} | ^ type parameter `T` must be used as the type parameter for some local type | - = note: implementing a foreign trait is only possible if at least one of the types for which is it implemented is local + = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local = note: only traits defined in the current crate can be implemented for a type parameter error: aborting due to previous error diff --git a/src/test/ui/overlap-doesnt-conflict-with-specialization.stderr b/src/test/ui/overlap-doesnt-conflict-with-specialization.stderr index 16df31ba2a8..fca98662708 100644 --- a/src/test/ui/overlap-doesnt-conflict-with-specialization.stderr +++ b/src/test/ui/overlap-doesnt-conflict-with-specialization.stderr @@ -6,6 +6,7 @@ LL | #![feature(specialization)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete warning: 1 warning emitted diff --git a/src/test/ui/parser/assoc-static-semantic-fail.stderr b/src/test/ui/parser/assoc-static-semantic-fail.stderr index bc3054c3e30..7ae092cee67 100644 --- a/src/test/ui/parser/assoc-static-semantic-fail.stderr +++ b/src/test/ui/parser/assoc-static-semantic-fail.stderr @@ -170,6 +170,7 @@ LL | #![feature(specialization)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete error: aborting due to 24 previous errors; 1 warning emitted diff --git a/src/test/ui/parser/default.stderr b/src/test/ui/parser/default.stderr index dea35666f37..5b763ae72f5 100644 --- a/src/test/ui/parser/default.stderr +++ b/src/test/ui/parser/default.stderr @@ -31,6 +31,7 @@ LL | #![feature(specialization)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete error[E0046]: not all trait items implemented, missing: `foo` --> $DIR/default.rs:22:1 diff --git a/src/test/ui/parser/issue-66357-unexpected-unreachable.rs b/src/test/ui/parser/issue-66357-unexpected-unreachable.rs index 5ec143fae23..7b95bc775ba 100644 --- a/src/test/ui/parser/issue-66357-unexpected-unreachable.rs +++ b/src/test/ui/parser/issue-66357-unexpected-unreachable.rs @@ -13,4 +13,4 @@ fn f() { |[](* } //~^ ERROR expected one of `,` or `:`, found `(` -//~| ERROR expected one of `&`, `(`, `)`, `-`, `...`, `..=`, `..`, `[`, `_`, `box`, `mut`, `ref`, `|`, identifier, or path, found `*` +//~| ERROR expected one of `&`, `(`, `)`, `-`, `...`, `..=`, `..`, `[`, `_`, `box`, `const`, `mut`, `ref`, `|`, identifier, or path, found `*` diff --git a/src/test/ui/parser/issue-66357-unexpected-unreachable.stderr b/src/test/ui/parser/issue-66357-unexpected-unreachable.stderr index c3810999d23..5549f73920d 100644 --- a/src/test/ui/parser/issue-66357-unexpected-unreachable.stderr +++ b/src/test/ui/parser/issue-66357-unexpected-unreachable.stderr @@ -4,7 +4,7 @@ error: expected one of `,` or `:`, found `(` LL | fn f() { |[](* } | ^ expected one of `,` or `:` -error: expected one of `&`, `(`, `)`, `-`, `...`, `..=`, `..`, `[`, `_`, `box`, `mut`, `ref`, `|`, identifier, or path, found `*` +error: expected one of `&`, `(`, `)`, `-`, `...`, `..=`, `..`, `[`, `_`, `box`, `const`, `mut`, `ref`, `|`, identifier, or path, found `*` --> $DIR/issue-66357-unexpected-unreachable.rs:14:14 | LL | fn f() { |[](* } diff --git a/src/test/ui/parser/trait-item-with-defaultness-fail-semantic.stderr b/src/test/ui/parser/trait-item-with-defaultness-fail-semantic.stderr index e8ff93f6323..cdc9ee8d9e7 100644 --- a/src/test/ui/parser/trait-item-with-defaultness-fail-semantic.stderr +++ b/src/test/ui/parser/trait-item-with-defaultness-fail-semantic.stderr @@ -54,6 +54,7 @@ LL | #![feature(specialization)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete error: aborting due to 6 previous errors; 1 warning emitted diff --git a/src/test/ui/parser/variadic-ffi-semantic-restrictions.stderr b/src/test/ui/parser/variadic-ffi-semantic-restrictions.stderr index 21992a29670..3f3ddfed14a 100644 --- a/src/test/ui/parser/variadic-ffi-semantic-restrictions.stderr +++ b/src/test/ui/parser/variadic-ffi-semantic-restrictions.stderr @@ -2,205 +2,205 @@ error: only foreign or `unsafe extern "C" functions may be C-variadic --> $DIR/variadic-ffi-semantic-restrictions.rs:5:19 | LL | fn f1_1(x: isize, ...) {} - | ^^^^ + | ^^^ error: C-variadic function must be declared with at least one named argument --> $DIR/variadic-ffi-semantic-restrictions.rs:8:9 | LL | fn f1_2(...) {} - | ^^^^ + | ^^^ error: only foreign or `unsafe extern "C" functions may be C-variadic --> $DIR/variadic-ffi-semantic-restrictions.rs:8:9 | LL | fn f1_2(...) {} - | ^^^^ + | ^^^ error: only foreign or `unsafe extern "C" functions may be C-variadic --> $DIR/variadic-ffi-semantic-restrictions.rs:12:30 | LL | extern "C" fn f2_1(x: isize, ...) {} - | ^^^^ + | ^^^ error: C-variadic function must be declared with at least one named argument --> $DIR/variadic-ffi-semantic-restrictions.rs:15:20 | LL | extern "C" fn f2_2(...) {} - | ^^^^ + | ^^^ error: only foreign or `unsafe extern "C" functions may be C-variadic --> $DIR/variadic-ffi-semantic-restrictions.rs:15:20 | LL | extern "C" fn f2_2(...) {} - | ^^^^ + | ^^^ error: `...` must be the last argument of a C-variadic function --> $DIR/variadic-ffi-semantic-restrictions.rs:19:20 | LL | extern "C" fn f2_3(..., x: isize) {} - | ^^^^ + | ^^^ error: only foreign or `unsafe extern "C" functions may be C-variadic --> $DIR/variadic-ffi-semantic-restrictions.rs:19:20 | LL | extern "C" fn f2_3(..., x: isize) {} - | ^^^^ + | ^^^ error: only foreign or `unsafe extern "C" functions may be C-variadic --> $DIR/variadic-ffi-semantic-restrictions.rs:23:26 | LL | extern fn f3_1(x: isize, ...) {} - | ^^^^ + | ^^^ error: C-variadic function must be declared with at least one named argument --> $DIR/variadic-ffi-semantic-restrictions.rs:26:16 | LL | extern fn f3_2(...) {} - | ^^^^ + | ^^^ error: only foreign or `unsafe extern "C" functions may be C-variadic --> $DIR/variadic-ffi-semantic-restrictions.rs:26:16 | LL | extern fn f3_2(...) {} - | ^^^^ + | ^^^ error: `...` must be the last argument of a C-variadic function --> $DIR/variadic-ffi-semantic-restrictions.rs:30:16 | LL | extern fn f3_3(..., x: isize) {} - | ^^^^ + | ^^^ error: only foreign or `unsafe extern "C" functions may be C-variadic --> $DIR/variadic-ffi-semantic-restrictions.rs:30:16 | LL | extern fn f3_3(..., x: isize) {} - | ^^^^ + | ^^^ error: C-variadic function must be declared with at least one named argument --> $DIR/variadic-ffi-semantic-restrictions.rs:35:13 | LL | fn e_f1(...); - | ^^^^ + | ^^^ error: `...` must be the last argument of a C-variadic function --> $DIR/variadic-ffi-semantic-restrictions.rs:37:13 | LL | fn e_f2(..., x: isize); - | ^^^^ + | ^^^ error: only foreign or `unsafe extern "C" functions may be C-variadic --> $DIR/variadic-ffi-semantic-restrictions.rs:44:23 | LL | fn i_f1(x: isize, ...) {} - | ^^^^ + | ^^^ error: C-variadic function must be declared with at least one named argument --> $DIR/variadic-ffi-semantic-restrictions.rs:46:13 | LL | fn i_f2(...) {} - | ^^^^ + | ^^^ error: only foreign or `unsafe extern "C" functions may be C-variadic --> $DIR/variadic-ffi-semantic-restrictions.rs:46:13 | LL | fn i_f2(...) {} - | ^^^^ + | ^^^ error: `...` must be the last argument of a C-variadic function --> $DIR/variadic-ffi-semantic-restrictions.rs:49:13 | LL | fn i_f3(..., x: isize, ...) {} - | ^^^^ + | ^^^ error: only foreign or `unsafe extern "C" functions may be C-variadic --> $DIR/variadic-ffi-semantic-restrictions.rs:49:13 | LL | fn i_f3(..., x: isize, ...) {} - | ^^^^ + | ^^^ error: only foreign or `unsafe extern "C" functions may be C-variadic --> $DIR/variadic-ffi-semantic-restrictions.rs:49:28 | LL | fn i_f3(..., x: isize, ...) {} - | ^^^^ + | ^^^ error: `...` must be the last argument of a C-variadic function --> $DIR/variadic-ffi-semantic-restrictions.rs:53:13 | LL | fn i_f4(..., x: isize, ...) {} - | ^^^^ + | ^^^ error: only foreign or `unsafe extern "C" functions may be C-variadic --> $DIR/variadic-ffi-semantic-restrictions.rs:53:13 | LL | fn i_f4(..., x: isize, ...) {} - | ^^^^ + | ^^^ error: only foreign or `unsafe extern "C" functions may be C-variadic --> $DIR/variadic-ffi-semantic-restrictions.rs:53:28 | LL | fn i_f4(..., x: isize, ...) {} - | ^^^^ + | ^^^ error: only foreign or `unsafe extern "C" functions may be C-variadic --> $DIR/variadic-ffi-semantic-restrictions.rs:60:23 | LL | fn t_f1(x: isize, ...) {} - | ^^^^ + | ^^^ error: only foreign or `unsafe extern "C" functions may be C-variadic --> $DIR/variadic-ffi-semantic-restrictions.rs:62:23 | LL | fn t_f2(x: isize, ...); - | ^^^^ + | ^^^ error: C-variadic function must be declared with at least one named argument --> $DIR/variadic-ffi-semantic-restrictions.rs:64:13 | LL | fn t_f3(...) {} - | ^^^^ + | ^^^ error: only foreign or `unsafe extern "C" functions may be C-variadic --> $DIR/variadic-ffi-semantic-restrictions.rs:64:13 | LL | fn t_f3(...) {} - | ^^^^ + | ^^^ error: C-variadic function must be declared with at least one named argument --> $DIR/variadic-ffi-semantic-restrictions.rs:67:13 | LL | fn t_f4(...); - | ^^^^ + | ^^^ error: only foreign or `unsafe extern "C" functions may be C-variadic --> $DIR/variadic-ffi-semantic-restrictions.rs:67:13 | LL | fn t_f4(...); - | ^^^^ + | ^^^ error: `...` must be the last argument of a C-variadic function --> $DIR/variadic-ffi-semantic-restrictions.rs:70:13 | LL | fn t_f5(..., x: isize) {} - | ^^^^ + | ^^^ error: only foreign or `unsafe extern "C" functions may be C-variadic --> $DIR/variadic-ffi-semantic-restrictions.rs:70:13 | LL | fn t_f5(..., x: isize) {} - | ^^^^ + | ^^^ error: `...` must be the last argument of a C-variadic function --> $DIR/variadic-ffi-semantic-restrictions.rs:73:13 | LL | fn t_f6(..., x: isize); - | ^^^^ + | ^^^ error: only foreign or `unsafe extern "C" functions may be C-variadic --> $DIR/variadic-ffi-semantic-restrictions.rs:73:13 | LL | fn t_f6(..., x: isize); - | ^^^^ + | ^^^ error: aborting due to 34 previous errors diff --git a/src/test/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.rs b/src/test/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.rs index c00296c34c4..ba9543bf738 100644 --- a/src/test/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.rs +++ b/src/test/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.rs @@ -3,7 +3,6 @@ // where one side is by-ref and the other is by-move. #![feature(bindings_after_at)] -#![feature(move_ref_pattern)] struct X { x: (), diff --git a/src/test/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.stderr b/src/test/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.stderr index 8a6ea8e91a2..44dbcb9a754 100644 --- a/src/test/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.stderr +++ b/src/test/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.stderr @@ -1,5 +1,5 @@ error: cannot move out of value because it is borrowed - --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:15:14 + --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:14:14 | LL | Some(ref _y @ _z) => {} | ------^^^-- @@ -8,7 +8,7 @@ LL | Some(ref _y @ _z) => {} | value borrowed, by `_y`, here error: borrow of moved value - --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:21:14 + --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:20:14 | LL | Some(_z @ ref _y) => {} | --^^^------ @@ -18,7 +18,7 @@ LL | Some(_z @ ref _y) => {} | move occurs because `_z` has type `X` which does not implement the `Copy` trait error: cannot move out of value because it is borrowed - --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:29:14 + --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:28:14 | LL | Some(ref mut _y @ _z) => {} | ----------^^^-- @@ -27,7 +27,7 @@ LL | Some(ref mut _y @ _z) => {} | value borrowed, by `_y`, here error: borrow of moved value - --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:35:14 + --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:34:14 | LL | Some(_z @ ref mut _y) => {} | --^^^---------- @@ -37,7 +37,7 @@ LL | Some(_z @ ref mut _y) => {} | move occurs because `_z` has type `X` which does not implement the `Copy` trait error[E0382]: borrow of moved value - --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:21:19 + --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:20:19 | LL | Some(_z @ ref _y) => {} | -----^^^^^^ @@ -52,7 +52,7 @@ LL | Some(ref _z @ ref _y) => {} | ^^^ error[E0382]: borrow of moved value - --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:35:19 + --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:34:19 | LL | Some(_z @ ref mut _y) => {} | -----^^^^^^^^^^ diff --git a/src/test/ui/pattern/bindings-after-at/bind-by-move-no-subbindings-fun-param.rs b/src/test/ui/pattern/bindings-after-at/bind-by-move-no-subbindings-fun-param.rs index 7a2e5128b85..3ab6f40725c 100644 --- a/src/test/ui/pattern/bindings-after-at/bind-by-move-no-subbindings-fun-param.rs +++ b/src/test/ui/pattern/bindings-after-at/bind-by-move-no-subbindings-fun-param.rs @@ -1,7 +1,6 @@ // See issue #12534. #![feature(bindings_after_at)] -#![feature(move_ref_pattern)] fn main() {} diff --git a/src/test/ui/pattern/bindings-after-at/bind-by-move-no-subbindings-fun-param.stderr b/src/test/ui/pattern/bindings-after-at/bind-by-move-no-subbindings-fun-param.stderr index cfd978e1327..f25d5a2d9b8 100644 --- a/src/test/ui/pattern/bindings-after-at/bind-by-move-no-subbindings-fun-param.stderr +++ b/src/test/ui/pattern/bindings-after-at/bind-by-move-no-subbindings-fun-param.stderr @@ -1,5 +1,5 @@ error[E0382]: use of moved value - --> $DIR/bind-by-move-no-subbindings-fun-param.rs:10:12 + --> $DIR/bind-by-move-no-subbindings-fun-param.rs:9:12 | LL | fn f(a @ A(u): A) -> Box<u8> { | ------^- diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-move-and-move.rs b/src/test/ui/pattern/bindings-after-at/borrowck-move-and-move.rs index 10865b92393..d014c9828da 100644 --- a/src/test/ui/pattern/bindings-after-at/borrowck-move-and-move.rs +++ b/src/test/ui/pattern/bindings-after-at/borrowck-move-and-move.rs @@ -1,7 +1,6 @@ // Test that moving on both sides of an `@` pattern is not allowed. #![feature(bindings_after_at)] -#![feature(move_ref_pattern)] fn main() { struct U; // Not copy! diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-move-and-move.stderr b/src/test/ui/pattern/bindings-after-at/borrowck-move-and-move.stderr index d28edd11e12..5039f580ff6 100644 --- a/src/test/ui/pattern/bindings-after-at/borrowck-move-and-move.stderr +++ b/src/test/ui/pattern/bindings-after-at/borrowck-move-and-move.stderr @@ -1,5 +1,5 @@ error[E0382]: use of moved value - --> $DIR/borrowck-move-and-move.rs:14:13 + --> $DIR/borrowck-move-and-move.rs:13:13 | LL | let a @ b = U; | ----^ - move occurs because value has type `U`, which does not implement the `Copy` trait @@ -8,7 +8,7 @@ LL | let a @ b = U; | value moved here error[E0382]: use of moved value - --> $DIR/borrowck-move-and-move.rs:16:17 + --> $DIR/borrowck-move-and-move.rs:15:17 | LL | let a @ (b, c) = (U, U); | --------^- ------ move occurs because value has type `(U, U)`, which does not implement the `Copy` trait @@ -17,7 +17,7 @@ LL | let a @ (b, c) = (U, U); | value moved here error[E0382]: use of moved value - --> $DIR/borrowck-move-and-move.rs:18:17 + --> $DIR/borrowck-move-and-move.rs:17:17 | LL | let a @ (b, c) = (u(), u()); | --------^- ---------- move occurs because value has type `(U, U)`, which does not implement the `Copy` trait @@ -26,7 +26,7 @@ LL | let a @ (b, c) = (u(), u()); | value moved here error[E0382]: use of moved value - --> $DIR/borrowck-move-and-move.rs:21:16 + --> $DIR/borrowck-move-and-move.rs:20:16 | LL | match Ok(U) { | ----- move occurs because value has type `std::result::Result<U, U>`, which does not implement the `Copy` trait @@ -37,7 +37,7 @@ LL | a @ Ok(b) | a @ Err(b) => {} | value moved here error[E0382]: use of moved value - --> $DIR/borrowck-move-and-move.rs:21:29 + --> $DIR/borrowck-move-and-move.rs:20:29 | LL | match Ok(U) { | ----- move occurs because value has type `std::result::Result<U, U>`, which does not implement the `Copy` trait @@ -48,7 +48,7 @@ LL | a @ Ok(b) | a @ Err(b) => {} | value moved here error[E0382]: use of moved value - --> $DIR/borrowck-move-and-move.rs:28:22 + --> $DIR/borrowck-move-and-move.rs:27:22 | LL | match [u(), u(), u(), u()] { | -------------------- move occurs because value has type `[U; 4]`, which does not implement the `Copy` trait @@ -59,7 +59,7 @@ LL | xs @ [a, .., b] => {} | value moved here error[E0382]: use of moved value - --> $DIR/borrowck-move-and-move.rs:32:18 + --> $DIR/borrowck-move-and-move.rs:31:18 | LL | match [u(), u(), u(), u()] { | -------------------- move occurs because value has type `[U; 4]`, which does not implement the `Copy` trait @@ -70,7 +70,7 @@ LL | xs @ [_, ys @ .., _] => {} | value moved here error[E0382]: use of moved value - --> $DIR/borrowck-move-and-move.rs:25:16 + --> $DIR/borrowck-move-and-move.rs:24:16 | LL | fn fun(a @ b: U) {} | ----^ diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-at-and-box-pass.rs b/src/test/ui/pattern/bindings-after-at/borrowck-pat-at-and-box-pass.rs index 271f4bca0fc..f1ee87bc9c6 100644 --- a/src/test/ui/pattern/bindings-after-at/borrowck-pat-at-and-box-pass.rs +++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-at-and-box-pass.rs @@ -3,7 +3,6 @@ // Test `@` patterns combined with `box` patterns. #![feature(bindings_after_at)] -#![feature(move_ref_pattern)] #![feature(box_patterns)] #[derive(Copy, Clone)] diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-at-and-box.rs b/src/test/ui/pattern/bindings-after-at/borrowck-pat-at-and-box.rs index f1680e9e888..236710ed854 100644 --- a/src/test/ui/pattern/bindings-after-at/borrowck-pat-at-and-box.rs +++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-at-and-box.rs @@ -1,7 +1,6 @@ // Test `@` patterns combined with `box` patterns. #![feature(bindings_after_at)] -#![feature(move_ref_pattern)] #![feature(box_patterns)] #[derive(Copy, Clone)] diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-at-and-box.stderr b/src/test/ui/pattern/bindings-after-at/borrowck-pat-at-and-box.stderr index 44888369ab2..d9a8bbfb6b1 100644 --- a/src/test/ui/pattern/bindings-after-at/borrowck-pat-at-and-box.stderr +++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-at-and-box.stderr @@ -1,5 +1,5 @@ error: cannot move out of value because it is borrowed - --> $DIR/borrowck-pat-at-and-box.rs:37:9 + --> $DIR/borrowck-pat-at-and-box.rs:36:9 | LL | let ref a @ box b = Box::new(NC); | -----^^^^^^^- @@ -8,7 +8,7 @@ LL | let ref a @ box b = Box::new(NC); | value borrowed, by `a`, here error: cannot borrow value as mutable because it is also borrowed as immutable - --> $DIR/borrowck-pat-at-and-box.rs:39:9 + --> $DIR/borrowck-pat-at-and-box.rs:38:9 | LL | let ref a @ box ref mut b = Box::new(nc()); | -----^^^^^^^--------- @@ -17,7 +17,7 @@ LL | let ref a @ box ref mut b = Box::new(nc()); | immutable borrow, by `a`, occurs here error: cannot borrow value as mutable because it is also borrowed as immutable - --> $DIR/borrowck-pat-at-and-box.rs:41:9 + --> $DIR/borrowck-pat-at-and-box.rs:40:9 | LL | let ref a @ box ref mut b = Box::new(NC); | -----^^^^^^^--------- @@ -26,7 +26,7 @@ LL | let ref a @ box ref mut b = Box::new(NC); | immutable borrow, by `a`, occurs here error: cannot borrow value as mutable because it is also borrowed as immutable - --> $DIR/borrowck-pat-at-and-box.rs:43:9 + --> $DIR/borrowck-pat-at-and-box.rs:42:9 | LL | let ref a @ box ref mut b = Box::new(NC); | -----^^^^^^^--------- @@ -35,7 +35,7 @@ LL | let ref a @ box ref mut b = Box::new(NC); | immutable borrow, by `a`, occurs here error: cannot borrow value as mutable because it is also borrowed as immutable - --> $DIR/borrowck-pat-at-and-box.rs:46:9 + --> $DIR/borrowck-pat-at-and-box.rs:45:9 | LL | let ref a @ box ref mut b = Box::new(NC); | -----^^^^^^^--------- @@ -44,7 +44,7 @@ LL | let ref a @ box ref mut b = Box::new(NC); | immutable borrow, by `a`, occurs here error: cannot borrow value as immutable because it is also borrowed as mutable - --> $DIR/borrowck-pat-at-and-box.rs:52:9 + --> $DIR/borrowck-pat-at-and-box.rs:51:9 | LL | let ref mut a @ box ref b = Box::new(NC); | ---------^^^^^^^----- @@ -53,7 +53,7 @@ LL | let ref mut a @ box ref b = Box::new(NC); | mutable borrow, by `a`, occurs here error: cannot borrow value as immutable because it is also borrowed as mutable - --> $DIR/borrowck-pat-at-and-box.rs:66:9 + --> $DIR/borrowck-pat-at-and-box.rs:65:9 | LL | ref mut a @ box ref b => { | ---------^^^^^^^----- @@ -62,7 +62,7 @@ LL | ref mut a @ box ref b => { | mutable borrow, by `a`, occurs here error: cannot borrow value as immutable because it is also borrowed as mutable - --> $DIR/borrowck-pat-at-and-box.rs:58:11 + --> $DIR/borrowck-pat-at-and-box.rs:57:11 | LL | fn f5(ref mut a @ box ref b: Box<NC>) { | ---------^^^^^^^----- @@ -71,7 +71,7 @@ LL | fn f5(ref mut a @ box ref b: Box<NC>) { | mutable borrow, by `a`, occurs here error[E0382]: use of moved value - --> $DIR/borrowck-pat-at-and-box.rs:21:18 + --> $DIR/borrowck-pat-at-and-box.rs:20:18 | LL | let a @ box &b = Box::new(&C); | ---------^ ------------ move occurs because value has type `Box<&C>`, which does not implement the `Copy` trait @@ -80,7 +80,7 @@ LL | let a @ box &b = Box::new(&C); | value moved here error[E0382]: use of moved value - --> $DIR/borrowck-pat-at-and-box.rs:24:17 + --> $DIR/borrowck-pat-at-and-box.rs:23:17 | LL | let a @ box b = Box::new(C); | --------^ ----------- move occurs because value has type `Box<C>`, which does not implement the `Copy` trait @@ -89,7 +89,7 @@ LL | let a @ box b = Box::new(C); | value moved here error[E0382]: use of moved value - --> $DIR/borrowck-pat-at-and-box.rs:34:17 + --> $DIR/borrowck-pat-at-and-box.rs:33:17 | LL | match Box::new(C) { | ----------- move occurs because value has type `Box<C>`, which does not implement the `Copy` trait @@ -100,7 +100,7 @@ LL | a @ box b => {} | value moved here error[E0502]: cannot borrow value as mutable because it is also borrowed as immutable - --> $DIR/borrowck-pat-at-and-box.rs:46:21 + --> $DIR/borrowck-pat-at-and-box.rs:45:21 | LL | let ref a @ box ref mut b = Box::new(NC); | ------------^^^^^^^^^ @@ -112,7 +112,7 @@ LL | drop(a); | - immutable borrow later used here error[E0502]: cannot borrow value as immutable because it is also borrowed as mutable - --> $DIR/borrowck-pat-at-and-box.rs:52:25 + --> $DIR/borrowck-pat-at-and-box.rs:51:25 | LL | let ref mut a @ box ref b = Box::new(NC); | ----------------^^^^^ @@ -124,7 +124,7 @@ LL | *a = Box::new(NC); | -- mutable borrow later used here error[E0502]: cannot borrow value as immutable because it is also borrowed as mutable - --> $DIR/borrowck-pat-at-and-box.rs:66:25 + --> $DIR/borrowck-pat-at-and-box.rs:65:25 | LL | ref mut a @ box ref b => { | ----------------^^^^^ @@ -136,7 +136,7 @@ LL | *a = Box::new(NC); | -- mutable borrow later used here error[E0382]: use of moved value - --> $DIR/borrowck-pat-at-and-box.rs:27:20 + --> $DIR/borrowck-pat-at-and-box.rs:26:20 | LL | fn f1(a @ box &b: Box<&C>) {} | ---------^ @@ -146,7 +146,7 @@ LL | fn f1(a @ box &b: Box<&C>) {} | move occurs because value has type `Box<&C>`, which does not implement the `Copy` trait error[E0382]: use of moved value - --> $DIR/borrowck-pat-at-and-box.rs:30:19 + --> $DIR/borrowck-pat-at-and-box.rs:29:19 | LL | fn f2(a @ box b: Box<C>) {} | --------^ @@ -156,7 +156,7 @@ LL | fn f2(a @ box b: Box<C>) {} | move occurs because value has type `Box<C>`, which does not implement the `Copy` trait error[E0502]: cannot borrow value as immutable because it is also borrowed as mutable - --> $DIR/borrowck-pat-at-and-box.rs:58:27 + --> $DIR/borrowck-pat-at-and-box.rs:57:27 | LL | fn f5(ref mut a @ box ref b: Box<NC>) { | ----------------^^^^^ diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse-promotion.rs b/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse-promotion.rs index 993954b450e..a22d27763d2 100644 --- a/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse-promotion.rs +++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse-promotion.rs @@ -2,7 +2,6 @@ // Currently this logic exists in THIR match checking as opposed to borrowck. #![feature(bindings_after_at)] -#![feature(move_ref_pattern)] fn main() { struct U; diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse-promotion.stderr b/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse-promotion.stderr index dacf23f9ded..0e09d478e3a 100644 --- a/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse-promotion.stderr +++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse-promotion.stderr @@ -1,5 +1,5 @@ error: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse-promotion.rs:9:9 + --> $DIR/borrowck-pat-by-move-and-ref-inverse-promotion.rs:8:9 | LL | let a @ ref b = U; | -^^^----- diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.rs b/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.rs index 7d9618c8df7..3e5a543c4c3 100644 --- a/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.rs +++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.rs @@ -1,7 +1,6 @@ // Test that `by_move_binding @ pat_with_by_ref_bindings` is prevented. #![feature(bindings_after_at)] -#![feature(move_ref_pattern)] fn main() { struct U; diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.stderr b/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.stderr index 86e09e55585..282031aeb07 100644 --- a/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.stderr +++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.stderr @@ -1,5 +1,5 @@ error: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:29:9 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:28:9 | LL | let a @ ref b = U; | -^^^----- @@ -9,7 +9,7 @@ LL | let a @ ref b = U; | move occurs because `a` has type `U` which does not implement the `Copy` trait error: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:31:9 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:30:9 | LL | let a @ (mut b @ ref mut c, d @ ref e) = (U, U); | -^^^^^^^^^^^^---------^^^^^^-----^ @@ -20,7 +20,7 @@ LL | let a @ (mut b @ ref mut c, d @ ref e) = (U, U); | move occurs because `a` has type `(U, U)` which does not implement the `Copy` trait error: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:31:14 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:30:14 | LL | let a @ (mut b @ ref mut c, d @ ref e) = (U, U); | -----^^^--------- @@ -30,7 +30,7 @@ LL | let a @ (mut b @ ref mut c, d @ ref e) = (U, U); | move occurs because `b` has type `U` which does not implement the `Copy` trait error: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:31:33 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:30:33 | LL | let a @ (mut b @ ref mut c, d @ ref e) = (U, U); | -^^^----- @@ -40,7 +40,7 @@ LL | let a @ (mut b @ ref mut c, d @ ref e) = (U, U); | move occurs because `d` has type `U` which does not implement the `Copy` trait error: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:38:9 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:37:9 | LL | let a @ [ref mut b, ref c] = [U, U]; | -^^^^---------^^-----^ @@ -51,7 +51,7 @@ LL | let a @ [ref mut b, ref c] = [U, U]; | move occurs because `a` has type `[U; 2]` which does not implement the `Copy` trait error: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:41:9 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:40:9 | LL | let a @ ref b = u(); | -^^^----- @@ -61,7 +61,7 @@ LL | let a @ ref b = u(); | move occurs because `a` has type `U` which does not implement the `Copy` trait error: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:44:9 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:43:9 | LL | let a @ (mut b @ ref mut c, d @ ref e) = (u(), u()); | -^^^^^^^^^^^^---------^^^^^^-----^ @@ -72,7 +72,7 @@ LL | let a @ (mut b @ ref mut c, d @ ref e) = (u(), u()); | move occurs because `a` has type `(U, U)` which does not implement the `Copy` trait error: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:44:14 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:43:14 | LL | let a @ (mut b @ ref mut c, d @ ref e) = (u(), u()); | -----^^^--------- @@ -82,7 +82,7 @@ LL | let a @ (mut b @ ref mut c, d @ ref e) = (u(), u()); | move occurs because `b` has type `U` which does not implement the `Copy` trait error: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:44:33 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:43:33 | LL | let a @ (mut b @ ref mut c, d @ ref e) = (u(), u()); | -^^^----- @@ -92,7 +92,7 @@ LL | let a @ (mut b @ ref mut c, d @ ref e) = (u(), u()); | move occurs because `d` has type `U` which does not implement the `Copy` trait error: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:51:9 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:50:9 | LL | let a @ [ref mut b, ref c] = [u(), u()]; | -^^^^---------^^-----^ @@ -103,7 +103,7 @@ LL | let a @ [ref mut b, ref c] = [u(), u()]; | move occurs because `a` has type `[U; 2]` which does not implement the `Copy` trait error: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:56:9 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:55:9 | LL | a @ Some(ref b) => {} | -^^^^^^^^-----^ @@ -113,7 +113,7 @@ LL | a @ Some(ref b) => {} | move occurs because `a` has type `Option<U>` which does not implement the `Copy` trait error: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:61:9 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:60:9 | LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {} | -^^^^^^^^^^^^^^^^^---------^^^^^^-----^^ @@ -124,7 +124,7 @@ LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {} | move occurs because `a` has type `Option<(U, U)>` which does not implement the `Copy` trait error: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:61:19 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:60:19 | LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {} | -----^^^--------- @@ -134,7 +134,7 @@ LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {} | move occurs because `b` has type `U` which does not implement the `Copy` trait error: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:61:38 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:60:38 | LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {} | -^^^----- @@ -144,7 +144,7 @@ LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {} | move occurs because `d` has type `U` which does not implement the `Copy` trait error: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:71:9 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:70:9 | LL | mut a @ Some([ref b, ref mut c]) => {} | -----^^^^^^^^^-----^^---------^^ @@ -155,7 +155,7 @@ LL | mut a @ Some([ref b, ref mut c]) => {} | move occurs because `a` has type `Option<[U; 2]>` which does not implement the `Copy` trait error: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:77:9 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:76:9 | LL | a @ Some(ref b) => {} | -^^^^^^^^-----^ @@ -165,7 +165,7 @@ LL | a @ Some(ref b) => {} | move occurs because `a` has type `Option<U>` which does not implement the `Copy` trait error: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:83:9 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:82:9 | LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {} | -^^^^^^^^^^^^^^^^^---------^^^^^^-----^^ @@ -176,7 +176,7 @@ LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {} | move occurs because `a` has type `Option<(U, U)>` which does not implement the `Copy` trait error: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:83:19 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:82:19 | LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {} | -----^^^--------- @@ -186,7 +186,7 @@ LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {} | move occurs because `b` has type `U` which does not implement the `Copy` trait error: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:83:38 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:82:38 | LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {} | -^^^----- @@ -196,7 +196,7 @@ LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {} | move occurs because `d` has type `U` which does not implement the `Copy` trait error: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:93:9 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:92:9 | LL | mut a @ Some([ref b, ref mut c]) => {} | -----^^^^^^^^^-----^^---------^^ @@ -207,7 +207,7 @@ LL | mut a @ Some([ref b, ref mut c]) => {} | move occurs because `a` has type `Option<[U; 2]>` which does not implement the `Copy` trait error: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:14:11 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:13:11 | LL | fn f1(a @ ref b: U) {} | -^^^----- @@ -217,7 +217,7 @@ LL | fn f1(a @ ref b: U) {} | move occurs because `a` has type `U` which does not implement the `Copy` trait error: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:18:11 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:17:11 | LL | fn f2(mut a @ (b @ ref c, mut d @ ref e): (U, U)) {} | -----^^^^^^^^-----^^^^^^^^^^-----^ @@ -228,7 +228,7 @@ LL | fn f2(mut a @ (b @ ref c, mut d @ ref e): (U, U)) {} | move occurs because `a` has type `(U, U)` which does not implement the `Copy` trait error: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:18:20 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:17:20 | LL | fn f2(mut a @ (b @ ref c, mut d @ ref e): (U, U)) {} | -^^^----- @@ -238,7 +238,7 @@ LL | fn f2(mut a @ (b @ ref c, mut d @ ref e): (U, U)) {} | move occurs because `b` has type `U` which does not implement the `Copy` trait error: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:18:31 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:17:31 | LL | fn f2(mut a @ (b @ ref c, mut d @ ref e): (U, U)) {} | -----^^^----- @@ -248,7 +248,7 @@ LL | fn f2(mut a @ (b @ ref c, mut d @ ref e): (U, U)) {} | move occurs because `d` has type `U` which does not implement the `Copy` trait error: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:25:11 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:24:11 | LL | fn f3(a @ [ref mut b, ref c]: [U; 2]) {} | -^^^^---------^^-----^ @@ -259,7 +259,7 @@ LL | fn f3(a @ [ref mut b, ref c]: [U; 2]) {} | move occurs because `a` has type `[U; 2]` which does not implement the `Copy` trait error[E0382]: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:31:22 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:30:22 | LL | let a @ (mut b @ ref mut c, d @ ref e) = (U, U); | --------^^^^^^^^^ @@ -270,7 +270,7 @@ LL | let a @ (mut b @ ref mut c, d @ ref e) = (U, U); = note: move occurs because value has type `U`, which does not implement the `Copy` trait error[E0382]: use of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:31:33 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:30:33 | LL | let a @ (mut b @ ref mut c, d @ ref e) = (U, U); | ------------------------^^^^^^^^^- ------ move occurs because value has type `(U, U)`, which does not implement the `Copy` trait @@ -279,7 +279,7 @@ LL | let a @ (mut b @ ref mut c, d @ ref e) = (U, U); | value moved here error[E0382]: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:31:37 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:30:37 | LL | let a @ (mut b @ ref mut c, d @ ref e) = (U, U); | ----^^^^^ @@ -290,7 +290,7 @@ LL | let a @ (mut b @ ref mut c, d @ ref e) = (U, U); = note: move occurs because value has type `U`, which does not implement the `Copy` trait error[E0382]: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:38:25 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:37:25 | LL | let a @ [ref mut b, ref c] = [U, U]; | ----------------^^^^^- ------ move occurs because value has type `[U; 2]`, which does not implement the `Copy` trait @@ -299,7 +299,7 @@ LL | let a @ [ref mut b, ref c] = [U, U]; | value moved here error[E0382]: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:41:13 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:40:13 | LL | let a @ ref b = u(); | ----^^^^^ --- move occurs because value has type `U`, which does not implement the `Copy` trait @@ -308,7 +308,7 @@ LL | let a @ ref b = u(); | value moved here error[E0382]: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:44:22 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:43:22 | LL | let a @ (mut b @ ref mut c, d @ ref e) = (u(), u()); | --------^^^^^^^^^ @@ -319,7 +319,7 @@ LL | let a @ (mut b @ ref mut c, d @ ref e) = (u(), u()); = note: move occurs because value has type `U`, which does not implement the `Copy` trait error[E0382]: use of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:44:33 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:43:33 | LL | let a @ (mut b @ ref mut c, d @ ref e) = (u(), u()); | ------------------------^^^^^^^^^- ---------- move occurs because value has type `(U, U)`, which does not implement the `Copy` trait @@ -328,7 +328,7 @@ LL | let a @ (mut b @ ref mut c, d @ ref e) = (u(), u()); | value moved here error[E0382]: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:44:37 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:43:37 | LL | let a @ (mut b @ ref mut c, d @ ref e) = (u(), u()); | ----^^^^^ @@ -339,7 +339,7 @@ LL | let a @ (mut b @ ref mut c, d @ ref e) = (u(), u()); = note: move occurs because value has type `U`, which does not implement the `Copy` trait error[E0382]: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:51:25 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:50:25 | LL | let a @ [ref mut b, ref c] = [u(), u()]; | ----------------^^^^^- ---------- move occurs because value has type `[U; 2]`, which does not implement the `Copy` trait @@ -348,7 +348,7 @@ LL | let a @ [ref mut b, ref c] = [u(), u()]; | value moved here error[E0382]: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:61:27 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:60:27 | LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {} | --------^^^^^^^^^ @@ -363,7 +363,7 @@ LL | a @ Some((ref mut b @ ref mut c, d @ ref e)) => {} | ^^^ error[E0382]: use of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:61:38 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:60:38 | LL | match Some((U, U)) { | ------------ move occurs because value has type `Option<(U, U)>`, which does not implement the `Copy` trait @@ -374,7 +374,7 @@ LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {} | value moved here error[E0382]: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:61:42 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:60:42 | LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {} | ----^^^^^ @@ -389,7 +389,7 @@ LL | a @ Some((mut b @ ref mut c, ref d @ ref e)) => {} | ^^^ error[E0382]: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:71:30 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:70:30 | LL | match Some([U, U]) { | ------------ move occurs because value has type `Option<[U; 2]>`, which does not implement the `Copy` trait @@ -400,7 +400,7 @@ LL | mut a @ Some([ref b, ref mut c]) => {} | value moved here error[E0382]: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:77:18 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:76:18 | LL | match Some(u()) { | --------- move occurs because value has type `Option<U>`, which does not implement the `Copy` trait @@ -411,7 +411,7 @@ LL | a @ Some(ref b) => {} | value moved here error[E0382]: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:83:27 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:82:27 | LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {} | --------^^^^^^^^^ @@ -426,7 +426,7 @@ LL | a @ Some((ref mut b @ ref mut c, d @ ref e)) => {} | ^^^ error[E0382]: use of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:83:38 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:82:38 | LL | match Some((u(), u())) { | ---------------- move occurs because value has type `Option<(U, U)>`, which does not implement the `Copy` trait @@ -437,7 +437,7 @@ LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {} | value moved here error[E0382]: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:83:42 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:82:42 | LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {} | ----^^^^^ @@ -452,7 +452,7 @@ LL | a @ Some((mut b @ ref mut c, ref d @ ref e)) => {} | ^^^ error[E0382]: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:93:30 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:92:30 | LL | match Some([u(), u()]) { | ---------------- move occurs because value has type `Option<[U; 2]>`, which does not implement the `Copy` trait @@ -463,7 +463,7 @@ LL | mut a @ Some([ref b, ref mut c]) => {} | value moved here error[E0382]: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:14:15 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:13:15 | LL | fn f1(a @ ref b: U) {} | ----^^^^^ @@ -473,7 +473,7 @@ LL | fn f1(a @ ref b: U) {} | move occurs because value has type `U`, which does not implement the `Copy` trait error[E0382]: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:18:24 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:17:24 | LL | fn f2(mut a @ (b @ ref c, mut d @ ref e): (U, U)) {} | ----^^^^^ @@ -484,7 +484,7 @@ LL | fn f2(mut a @ (b @ ref c, mut d @ ref e): (U, U)) {} = note: move occurs because value has type `U`, which does not implement the `Copy` trait error[E0382]: use of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:18:31 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:17:31 | LL | fn f2(mut a @ (b @ ref c, mut d @ ref e): (U, U)) {} | --------------------^^^^^^^^^^^^^- @@ -494,7 +494,7 @@ LL | fn f2(mut a @ (b @ ref c, mut d @ ref e): (U, U)) {} | move occurs because value has type `(U, U)`, which does not implement the `Copy` trait error[E0382]: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:18:39 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:17:39 | LL | fn f2(mut a @ (b @ ref c, mut d @ ref e): (U, U)) {} | --------^^^^^ @@ -505,7 +505,7 @@ LL | fn f2(mut a @ (b @ ref c, mut d @ ref e): (U, U)) {} = note: move occurs because value has type `U`, which does not implement the `Copy` trait error[E0382]: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:25:27 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:24:27 | LL | fn f3(a @ [ref mut b, ref c]: [U; 2]) {} | ----------------^^^^^- diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref.rs b/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref.rs index b7c8c8766c0..42c3290ddfb 100644 --- a/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref.rs +++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref.rs @@ -1,7 +1,6 @@ // Test that `ref mut? @ pat_with_by_move_bindings` is prevented. #![feature(bindings_after_at)] -#![feature(move_ref_pattern)] fn main() { struct U; diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref.stderr b/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref.stderr index e5419efa00b..a275705b193 100644 --- a/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref.stderr +++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref.stderr @@ -1,5 +1,5 @@ error: cannot move out of value because it is borrowed - --> $DIR/borrowck-pat-by-move-and-ref.rs:23:9 + --> $DIR/borrowck-pat-by-move-and-ref.rs:22:9 | LL | let ref a @ b = U; | -----^^^- @@ -8,7 +8,7 @@ LL | let ref a @ b = U; | value borrowed, by `a`, here error: cannot move out of value because it is borrowed - --> $DIR/borrowck-pat-by-move-and-ref.rs:25:9 + --> $DIR/borrowck-pat-by-move-and-ref.rs:24:9 | LL | let ref a @ (ref b @ mut c, ref d @ e) = (U, U); | -----^^^^^^^^^^^^-----^^^^^^^^^^-^ @@ -18,7 +18,7 @@ LL | let ref a @ (ref b @ mut c, ref d @ e) = (U, U); | value borrowed, by `a`, here error: cannot move out of value because it is borrowed - --> $DIR/borrowck-pat-by-move-and-ref.rs:25:18 + --> $DIR/borrowck-pat-by-move-and-ref.rs:24:18 | LL | let ref a @ (ref b @ mut c, ref d @ e) = (U, U); | -----^^^----- @@ -27,7 +27,7 @@ LL | let ref a @ (ref b @ mut c, ref d @ e) = (U, U); | value borrowed, by `b`, here error: cannot move out of value because it is borrowed - --> $DIR/borrowck-pat-by-move-and-ref.rs:25:33 + --> $DIR/borrowck-pat-by-move-and-ref.rs:24:33 | LL | let ref a @ (ref b @ mut c, ref d @ e) = (U, U); | -----^^^- @@ -36,7 +36,7 @@ LL | let ref a @ (ref b @ mut c, ref d @ e) = (U, U); | value borrowed, by `d`, here error: cannot move out of value because it is borrowed - --> $DIR/borrowck-pat-by-move-and-ref.rs:29:9 + --> $DIR/borrowck-pat-by-move-and-ref.rs:28:9 | LL | let ref mut a @ [b, mut c] = [U, U]; | ---------^^^^-^^-----^ @@ -46,7 +46,7 @@ LL | let ref mut a @ [b, mut c] = [U, U]; | value borrowed, by `a`, here error: cannot move out of value because it is borrowed - --> $DIR/borrowck-pat-by-move-and-ref.rs:31:9 + --> $DIR/borrowck-pat-by-move-and-ref.rs:30:9 | LL | let ref a @ b = u(); | -----^^^- @@ -55,7 +55,7 @@ LL | let ref a @ b = u(); | value borrowed, by `a`, here error: cannot move out of value because it is borrowed - --> $DIR/borrowck-pat-by-move-and-ref.rs:33:9 + --> $DIR/borrowck-pat-by-move-and-ref.rs:32:9 | LL | let ref a @ (ref b @ mut c, ref d @ e) = (u(), u()); | -----^^^^^^^^^^^^-----^^^^^^^^^^-^ @@ -65,7 +65,7 @@ LL | let ref a @ (ref b @ mut c, ref d @ e) = (u(), u()); | value borrowed, by `a`, here error: cannot move out of value because it is borrowed - --> $DIR/borrowck-pat-by-move-and-ref.rs:33:18 + --> $DIR/borrowck-pat-by-move-and-ref.rs:32:18 | LL | let ref a @ (ref b @ mut c, ref d @ e) = (u(), u()); | -----^^^----- @@ -74,7 +74,7 @@ LL | let ref a @ (ref b @ mut c, ref d @ e) = (u(), u()); | value borrowed, by `b`, here error: cannot move out of value because it is borrowed - --> $DIR/borrowck-pat-by-move-and-ref.rs:33:33 + --> $DIR/borrowck-pat-by-move-and-ref.rs:32:33 | LL | let ref a @ (ref b @ mut c, ref d @ e) = (u(), u()); | -----^^^- @@ -83,7 +83,7 @@ LL | let ref a @ (ref b @ mut c, ref d @ e) = (u(), u()); | value borrowed, by `d`, here error: cannot move out of value because it is borrowed - --> $DIR/borrowck-pat-by-move-and-ref.rs:37:9 + --> $DIR/borrowck-pat-by-move-and-ref.rs:36:9 | LL | let ref mut a @ [b, mut c] = [u(), u()]; | ---------^^^^-^^-----^ @@ -93,7 +93,7 @@ LL | let ref mut a @ [b, mut c] = [u(), u()]; | value borrowed, by `a`, here error: cannot move out of value because it is borrowed - --> $DIR/borrowck-pat-by-move-and-ref.rs:41:9 + --> $DIR/borrowck-pat-by-move-and-ref.rs:40:9 | LL | ref a @ Some(b) => {} | -----^^^^^^^^-^ @@ -102,7 +102,7 @@ LL | ref a @ Some(b) => {} | value borrowed, by `a`, here error: cannot move out of value because it is borrowed - --> $DIR/borrowck-pat-by-move-and-ref.rs:46:9 + --> $DIR/borrowck-pat-by-move-and-ref.rs:45:9 | LL | ref a @ Some((ref b @ mut c, ref d @ e)) => {} | -----^^^^^^^^^^^^^^^^^-----^^^^^^^^^^-^^ @@ -112,7 +112,7 @@ LL | ref a @ Some((ref b @ mut c, ref d @ e)) => {} | value borrowed, by `a`, here error: cannot move out of value because it is borrowed - --> $DIR/borrowck-pat-by-move-and-ref.rs:46:23 + --> $DIR/borrowck-pat-by-move-and-ref.rs:45:23 | LL | ref a @ Some((ref b @ mut c, ref d @ e)) => {} | -----^^^----- @@ -121,7 +121,7 @@ LL | ref a @ Some((ref b @ mut c, ref d @ e)) => {} | value borrowed, by `b`, here error: cannot move out of value because it is borrowed - --> $DIR/borrowck-pat-by-move-and-ref.rs:46:38 + --> $DIR/borrowck-pat-by-move-and-ref.rs:45:38 | LL | ref a @ Some((ref b @ mut c, ref d @ e)) => {} | -----^^^- @@ -130,7 +130,7 @@ LL | ref a @ Some((ref b @ mut c, ref d @ e)) => {} | value borrowed, by `d`, here error: cannot move out of value because it is borrowed - --> $DIR/borrowck-pat-by-move-and-ref.rs:53:9 + --> $DIR/borrowck-pat-by-move-and-ref.rs:52:9 | LL | ref mut a @ Some([b, mut c]) => {} | ---------^^^^^^^^^-^^-----^^ @@ -140,7 +140,7 @@ LL | ref mut a @ Some([b, mut c]) => {} | value borrowed, by `a`, here error: cannot move out of value because it is borrowed - --> $DIR/borrowck-pat-by-move-and-ref.rs:58:9 + --> $DIR/borrowck-pat-by-move-and-ref.rs:57:9 | LL | ref a @ Some(b) => {} | -----^^^^^^^^-^ @@ -149,7 +149,7 @@ LL | ref a @ Some(b) => {} | value borrowed, by `a`, here error: cannot move out of value because it is borrowed - --> $DIR/borrowck-pat-by-move-and-ref.rs:63:9 + --> $DIR/borrowck-pat-by-move-and-ref.rs:62:9 | LL | ref a @ Some((ref b @ mut c, ref d @ e)) => {} | -----^^^^^^^^^^^^^^^^^-----^^^^^^^^^^-^^ @@ -159,7 +159,7 @@ LL | ref a @ Some((ref b @ mut c, ref d @ e)) => {} | value borrowed, by `a`, here error: cannot move out of value because it is borrowed - --> $DIR/borrowck-pat-by-move-and-ref.rs:63:23 + --> $DIR/borrowck-pat-by-move-and-ref.rs:62:23 | LL | ref a @ Some((ref b @ mut c, ref d @ e)) => {} | -----^^^----- @@ -168,7 +168,7 @@ LL | ref a @ Some((ref b @ mut c, ref d @ e)) => {} | value borrowed, by `b`, here error: cannot move out of value because it is borrowed - --> $DIR/borrowck-pat-by-move-and-ref.rs:63:38 + --> $DIR/borrowck-pat-by-move-and-ref.rs:62:38 | LL | ref a @ Some((ref b @ mut c, ref d @ e)) => {} | -----^^^- @@ -177,7 +177,7 @@ LL | ref a @ Some((ref b @ mut c, ref d @ e)) => {} | value borrowed, by `d`, here error: cannot move out of value because it is borrowed - --> $DIR/borrowck-pat-by-move-and-ref.rs:70:9 + --> $DIR/borrowck-pat-by-move-and-ref.rs:69:9 | LL | ref mut a @ Some([b, mut c]) => {} | ---------^^^^^^^^^-^^-----^^ @@ -187,7 +187,7 @@ LL | ref mut a @ Some([b, mut c]) => {} | value borrowed, by `a`, here error: cannot move out of value because it is borrowed - --> $DIR/borrowck-pat-by-move-and-ref.rs:14:11 + --> $DIR/borrowck-pat-by-move-and-ref.rs:13:11 | LL | fn f1(ref a @ b: U) {} | -----^^^- @@ -196,7 +196,7 @@ LL | fn f1(ref a @ b: U) {} | value borrowed, by `a`, here error: cannot move out of value because it is borrowed - --> $DIR/borrowck-pat-by-move-and-ref.rs:16:11 + --> $DIR/borrowck-pat-by-move-and-ref.rs:15:11 | LL | fn f2(ref a @ (ref b @ mut c, ref d @ e): (U, U)) {} | -----^^^^^^^^^^^^-----^^^^^^^^^^-^ @@ -206,7 +206,7 @@ LL | fn f2(ref a @ (ref b @ mut c, ref d @ e): (U, U)) {} | value borrowed, by `a`, here error: cannot move out of value because it is borrowed - --> $DIR/borrowck-pat-by-move-and-ref.rs:16:20 + --> $DIR/borrowck-pat-by-move-and-ref.rs:15:20 | LL | fn f2(ref a @ (ref b @ mut c, ref d @ e): (U, U)) {} | -----^^^----- @@ -215,7 +215,7 @@ LL | fn f2(ref a @ (ref b @ mut c, ref d @ e): (U, U)) {} | value borrowed, by `b`, here error: cannot move out of value because it is borrowed - --> $DIR/borrowck-pat-by-move-and-ref.rs:16:35 + --> $DIR/borrowck-pat-by-move-and-ref.rs:15:35 | LL | fn f2(ref a @ (ref b @ mut c, ref d @ e): (U, U)) {} | -----^^^- @@ -224,7 +224,7 @@ LL | fn f2(ref a @ (ref b @ mut c, ref d @ e): (U, U)) {} | value borrowed, by `d`, here error: cannot move out of value because it is borrowed - --> $DIR/borrowck-pat-by-move-and-ref.rs:20:11 + --> $DIR/borrowck-pat-by-move-and-ref.rs:19:11 | LL | fn f3(ref mut a @ [b, mut c]: [U; 2]) {} | ---------^^^^-^^-----^ diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.rs b/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.rs index 2b5e339c639..f67cd45ca95 100644 --- a/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.rs +++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.rs @@ -1,5 +1,4 @@ #![feature(bindings_after_at)] -#![feature(move_ref_pattern)] enum Option<T> { None, diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.stderr b/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.stderr index 695da9639af..e6231dd49ba 100644 --- a/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.stderr +++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.stderr @@ -1,5 +1,5 @@ error: cannot borrow value as immutable because it is also borrowed as mutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:11:9 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:10:9 | LL | ref mut z @ &mut Some(ref a) => { | ---------^^^^^^^^^^^^^-----^ @@ -8,7 +8,7 @@ LL | ref mut z @ &mut Some(ref a) => { | mutable borrow, by `z`, occurs here error: cannot borrow value as mutable more than once at a time - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:35:9 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:34:9 | LL | let ref mut a @ (ref b @ ref mut c) = u(); // sub-in-sub | ---------^^^^-----------------^ @@ -18,7 +18,7 @@ LL | let ref mut a @ (ref b @ ref mut c) = u(); // sub-in-sub | first mutable borrow, by `a`, occurs here error: cannot borrow value as mutable because it is also borrowed as immutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:35:22 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:34:22 | LL | let ref mut a @ (ref b @ ref mut c) = u(); // sub-in-sub | -----^^^--------- @@ -27,7 +27,7 @@ LL | let ref mut a @ (ref b @ ref mut c) = u(); // sub-in-sub | immutable borrow, by `b`, occurs here error: cannot borrow value as mutable because it is also borrowed as immutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:39:9 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:38:9 | LL | let ref a @ ref mut b = U; | -----^^^--------- @@ -36,7 +36,7 @@ LL | let ref a @ ref mut b = U; | immutable borrow, by `a`, occurs here error: cannot borrow value as immutable because it is also borrowed as mutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:41:9 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:40:9 | LL | let ref mut a @ ref b = U; | ---------^^^----- @@ -45,7 +45,7 @@ LL | let ref mut a @ ref b = U; | mutable borrow, by `a`, occurs here error: cannot borrow value as mutable because it is also borrowed as immutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:43:9 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:42:9 | LL | let ref a @ (ref mut b, ref mut c) = (U, U); | -----^^^^---------^^---------^ @@ -55,7 +55,7 @@ LL | let ref a @ (ref mut b, ref mut c) = (U, U); | immutable borrow, by `a`, occurs here error: cannot borrow value as immutable because it is also borrowed as mutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:45:9 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:44:9 | LL | let ref mut a @ (ref b, ref c) = (U, U); | ---------^^^^-----^^-----^ @@ -65,7 +65,7 @@ LL | let ref mut a @ (ref b, ref c) = (U, U); | mutable borrow, by `a`, occurs here error: cannot borrow value as immutable because it is also borrowed as mutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:48:9 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:47:9 | LL | let ref mut a @ ref b = u(); | ---------^^^----- @@ -74,7 +74,7 @@ LL | let ref mut a @ ref b = u(); | mutable borrow, by `a`, occurs here error: cannot borrow value as mutable because it is also borrowed as immutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:53:9 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:52:9 | LL | let ref a @ ref mut b = u(); | -----^^^--------- @@ -83,7 +83,7 @@ LL | let ref a @ ref mut b = u(); | immutable borrow, by `a`, occurs here error: cannot borrow value as immutable because it is also borrowed as mutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:59:9 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:58:9 | LL | let ref mut a @ ref b = U; | ---------^^^----- @@ -92,7 +92,7 @@ LL | let ref mut a @ ref b = U; | mutable borrow, by `a`, occurs here error: cannot borrow value as mutable because it is also borrowed as immutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:63:9 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:62:9 | LL | let ref a @ ref mut b = U; | -----^^^--------- @@ -101,7 +101,7 @@ LL | let ref a @ ref mut b = U; | immutable borrow, by `a`, occurs here error: cannot borrow value as immutable because it is also borrowed as mutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:69:9 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:68:9 | LL | ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) => { | ---------^^^^^^-----^ @@ -110,7 +110,7 @@ LL | ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) => { | mutable borrow, by `a`, occurs here error: cannot borrow value as immutable because it is also borrowed as mutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:69:33 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:68:33 | LL | ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) => { | ---------^^^^^^^-----^ @@ -119,7 +119,7 @@ LL | ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) => { | mutable borrow, by `a`, occurs here error: cannot borrow value as mutable because it is also borrowed as immutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:78:9 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:77:9 | LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) => { | -----^^^^^^---------^ @@ -128,7 +128,7 @@ LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) => { | immutable borrow, by `a`, occurs here error: cannot borrow value as mutable because it is also borrowed as immutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:78:33 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:77:33 | LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) => { | -----^^^^^^^---------^ @@ -137,7 +137,7 @@ LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) => { | immutable borrow, by `a`, occurs here error: cannot borrow value as mutable because it is also borrowed as immutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:89:9 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:88:9 | LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { *b = U; false } => {} | -----^^^^^^---------^ @@ -146,7 +146,7 @@ LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { *b = U; false } | immutable borrow, by `a`, occurs here error: cannot borrow value as mutable because it is also borrowed as immutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:89:33 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:88:33 | LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { *b = U; false } => {} | -----^^^^^^^---------^ @@ -155,7 +155,7 @@ LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { *b = U; false } | immutable borrow, by `a`, occurs here error: cannot borrow value as immutable because it is also borrowed as mutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:96:9 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:95:9 | LL | ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { *a = Err(U); false } => {} | ---------^^^^^^-----^ @@ -164,7 +164,7 @@ LL | ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { *a = Err(U); fa | mutable borrow, by `a`, occurs here error: cannot borrow value as immutable because it is also borrowed as mutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:96:33 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:95:33 | LL | ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { *a = Err(U); false } => {} | ---------^^^^^^^-----^ @@ -173,7 +173,7 @@ LL | ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { *a = Err(U); fa | mutable borrow, by `a`, occurs here error: cannot borrow value as mutable because it is also borrowed as immutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:103:9 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:102:9 | LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { drop(b); false } => {} | -----^^^^^^---------^ @@ -182,7 +182,7 @@ LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { drop(b); false | immutable borrow, by `a`, occurs here error: cannot borrow value as mutable because it is also borrowed as immutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:103:33 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:102:33 | LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { drop(b); false } => {} | -----^^^^^^^---------^ @@ -191,7 +191,7 @@ LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { drop(b); false | immutable borrow, by `a`, occurs here error: cannot borrow value as immutable because it is also borrowed as mutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:111:9 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:110:9 | LL | ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { drop(a); false } => {} | ---------^^^^^^-----^ @@ -200,7 +200,7 @@ LL | ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { drop(a); false | mutable borrow, by `a`, occurs here error: cannot borrow value as immutable because it is also borrowed as mutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:111:33 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:110:33 | LL | ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { drop(a); false } => {} | ---------^^^^^^^-----^ @@ -209,7 +209,7 @@ LL | ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { drop(a); false | mutable borrow, by `a`, occurs here error: cannot borrow value as mutable because it is also borrowed as immutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:119:9 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:118:9 | LL | let ref a @ (ref mut b, ref mut c) = (U, U); | -----^^^^---------^^---------^ @@ -219,7 +219,7 @@ LL | let ref a @ (ref mut b, ref mut c) = (U, U); | immutable borrow, by `a`, occurs here error: cannot borrow value as mutable because it is also borrowed as immutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:124:9 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:123:9 | LL | let ref a @ (ref mut b, ref mut c) = (U, U); | -----^^^^---------^^---------^ @@ -229,7 +229,7 @@ LL | let ref a @ (ref mut b, ref mut c) = (U, U); | immutable borrow, by `a`, occurs here error: cannot borrow value as mutable because it is also borrowed as immutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:131:9 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:130:9 | LL | let ref a @ (ref mut b, ref mut c) = (U, U); | -----^^^^---------^^---------^ @@ -239,7 +239,7 @@ LL | let ref a @ (ref mut b, ref mut c) = (U, U); | immutable borrow, by `a`, occurs here error: cannot borrow value as immutable because it is also borrowed as mutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:136:9 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:135:9 | LL | let ref mut a @ (ref b, ref c) = (U, U); | ---------^^^^-----^^-----^ @@ -249,7 +249,7 @@ LL | let ref mut a @ (ref b, ref c) = (U, U); | mutable borrow, by `a`, occurs here error: cannot borrow value as mutable because it is also borrowed as immutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:25:11 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:24:11 | LL | fn f1(ref a @ ref mut b: U) {} | -----^^^--------- @@ -258,7 +258,7 @@ LL | fn f1(ref a @ ref mut b: U) {} | immutable borrow, by `a`, occurs here error: cannot borrow value as immutable because it is also borrowed as mutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:27:11 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:26:11 | LL | fn f2(ref mut a @ ref b: U) {} | ---------^^^----- @@ -267,7 +267,7 @@ LL | fn f2(ref mut a @ ref b: U) {} | mutable borrow, by `a`, occurs here error: cannot borrow value as mutable because it is also borrowed as immutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:29:11 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:28:11 | LL | fn f3(ref a @ [ref b, ref mut mid @ .., ref c]: [U; 4]) {} | -----^^^^^^^^^^^----------------^^^^^^^^ @@ -276,7 +276,7 @@ LL | fn f3(ref a @ [ref b, ref mut mid @ .., ref c]: [U; 4]) {} | immutable borrow, by `a`, occurs here error: cannot borrow value as mutable because it is also borrowed as immutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:31:22 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:30:22 | LL | fn f4_also_moved(ref a @ ref mut b @ c: U) {} | -----^^^------------- @@ -286,7 +286,7 @@ LL | fn f4_also_moved(ref a @ ref mut b @ c: U) {} | immutable borrow, by `a`, occurs here error: cannot move out of value because it is borrowed - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:31:30 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:30:30 | LL | fn f4_also_moved(ref a @ ref mut b @ c: U) {} | ---------^^^- @@ -295,7 +295,7 @@ LL | fn f4_also_moved(ref a @ ref mut b @ c: U) {} | value borrowed, by `b`, here error[E0502]: cannot borrow value as immutable because it is also borrowed as mutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:11:31 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:10:31 | LL | ref mut z @ &mut Some(ref a) => { | ----------------------^^^^^- @@ -307,7 +307,7 @@ LL | **z = None; | ---------- mutable borrow later used here error[E0502]: cannot borrow value as immutable because it is also borrowed as mutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:48:21 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:47:21 | LL | let ref mut a @ ref b = u(); | ------------^^^^^ @@ -319,7 +319,7 @@ LL | *a = u(); | -------- mutable borrow later used here error[E0502]: cannot borrow value as mutable because it is also borrowed as immutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:53:17 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:52:17 | LL | let ref a @ ref mut b = u(); | --------^^^^^^^^^ @@ -331,7 +331,7 @@ LL | drop(a); | - immutable borrow later used here error[E0502]: cannot borrow value as mutable because it is also borrowed as immutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:78:20 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:77:20 | LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) => { | -----------^^^^^^^^^- @@ -343,7 +343,7 @@ LL | drop(a); | - immutable borrow later used here error[E0502]: cannot borrow value as mutable because it is also borrowed as immutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:78:45 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:77:45 | LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) => { | ------------^^^^^^^^^- @@ -355,7 +355,7 @@ LL | drop(a); | - immutable borrow later used here error[E0594]: cannot assign to `*b`, as it is immutable for the pattern guard - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:89:61 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:88:61 | LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { *b = U; false } => {} | ^^^^^^ cannot assign @@ -363,7 +363,7 @@ LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { *b = U; false } = note: variables bound in patterns are immutable until the end of the pattern guard error[E0594]: cannot assign to `*a`, as it is immutable for the pattern guard - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:96:61 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:95:61 | LL | ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { *a = Err(U); false } => {} | ^^^^^^^^^^^ cannot assign @@ -371,7 +371,7 @@ LL | ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { *a = Err(U); fa = note: variables bound in patterns are immutable until the end of the pattern guard error[E0507]: cannot move out of `b` in pattern guard - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:103:66 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:102:66 | LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { drop(b); false } => {} | ^ move occurs because `b` has type `&mut U`, which does not implement the `Copy` trait @@ -379,7 +379,7 @@ LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { drop(b); false = note: variables bound in patterns cannot be moved from until after the end of the pattern guard error[E0507]: cannot move out of `b` in pattern guard - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:103:66 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:102:66 | LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { drop(b); false } => {} | ^ move occurs because `b` has type `&mut U`, which does not implement the `Copy` trait @@ -387,7 +387,7 @@ LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { drop(b); false = note: variables bound in patterns cannot be moved from until after the end of the pattern guard error[E0507]: cannot move out of `a` in pattern guard - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:111:66 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:110:66 | LL | ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { drop(a); false } => {} | ^ move occurs because `a` has type `&mut std::result::Result<U, U>`, which does not implement the `Copy` trait @@ -395,7 +395,7 @@ LL | ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { drop(a); false = note: variables bound in patterns cannot be moved from until after the end of the pattern guard error[E0507]: cannot move out of `a` in pattern guard - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:111:66 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:110:66 | LL | ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { drop(a); false } => {} | ^ move occurs because `a` has type `&mut std::result::Result<U, U>`, which does not implement the `Copy` trait @@ -403,7 +403,7 @@ LL | ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { drop(a); false = note: variables bound in patterns cannot be moved from until after the end of the pattern guard error[E0502]: cannot borrow value as mutable because it is also borrowed as immutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:124:18 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:123:18 | LL | let ref a @ (ref mut b, ref mut c) = (U, U); | ---------^^^^^^^^^------------ @@ -415,7 +415,7 @@ LL | drop(a); | - immutable borrow later used here error[E0502]: cannot borrow value as mutable because it is also borrowed as immutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:124:29 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:123:29 | LL | let ref a @ (ref mut b, ref mut c) = (U, U); | --------------------^^^^^^^^^- @@ -427,7 +427,7 @@ LL | drop(a); | - immutable borrow later used here error[E0502]: cannot borrow value as mutable because it is also borrowed as immutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:131:18 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:130:18 | LL | let ref a @ (ref mut b, ref mut c) = (U, U); | ---------^^^^^^^^^------------ @@ -439,7 +439,7 @@ LL | drop(a); | - immutable borrow later used here error[E0502]: cannot borrow value as mutable because it is also borrowed as immutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:131:29 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:130:29 | LL | let ref a @ (ref mut b, ref mut c) = (U, U); | --------------------^^^^^^^^^- diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.rs b/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.rs index a208d0087ff..8faaa1c881f 100644 --- a/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.rs +++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.rs @@ -1,7 +1,6 @@ // Test that `ref mut x @ ref mut y` and varieties of that are not allowed. #![feature(bindings_after_at)] -#![feature(move_ref_pattern)] fn main() { struct U; diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.stderr b/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.stderr index 1cd3e267b99..2e0f5fcabdd 100644 --- a/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.stderr +++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.stderr @@ -1,5 +1,5 @@ error: cannot borrow value as mutable more than once at a time - --> $DIR/borrowck-pat-ref-mut-twice.rs:28:9 + --> $DIR/borrowck-pat-ref-mut-twice.rs:27:9 | LL | let ref mut a @ ref mut b = U; | ---------^^^--------- @@ -8,7 +8,7 @@ LL | let ref mut a @ ref mut b = U; | first mutable borrow, by `a`, occurs here error: cannot borrow value as mutable more than once at a time - --> $DIR/borrowck-pat-ref-mut-twice.rs:32:9 + --> $DIR/borrowck-pat-ref-mut-twice.rs:31:9 | LL | let ref mut a @ ref mut b = U; | ---------^^^--------- @@ -17,7 +17,7 @@ LL | let ref mut a @ ref mut b = U; | first mutable borrow, by `a`, occurs here error: cannot borrow value as mutable more than once at a time - --> $DIR/borrowck-pat-ref-mut-twice.rs:35:9 + --> $DIR/borrowck-pat-ref-mut-twice.rs:34:9 | LL | let ref mut a @ ref mut b = U; | ---------^^^--------- @@ -26,7 +26,7 @@ LL | let ref mut a @ ref mut b = U; | first mutable borrow, by `a`, occurs here error: cannot borrow value as mutable more than once at a time - --> $DIR/borrowck-pat-ref-mut-twice.rs:38:9 + --> $DIR/borrowck-pat-ref-mut-twice.rs:37:9 | LL | let ref mut a @ ref mut b = U; | ---------^^^--------- @@ -35,7 +35,7 @@ LL | let ref mut a @ ref mut b = U; | first mutable borrow, by `a`, occurs here error: cannot borrow value as mutable more than once at a time - --> $DIR/borrowck-pat-ref-mut-twice.rs:42:9 + --> $DIR/borrowck-pat-ref-mut-twice.rs:41:9 | LL | let ref mut a @ ref mut b = U; | ---------^^^--------- @@ -44,7 +44,7 @@ LL | let ref mut a @ ref mut b = U; | first mutable borrow, by `a`, occurs here error: cannot borrow value as mutable more than once at a time - --> $DIR/borrowck-pat-ref-mut-twice.rs:46:9 + --> $DIR/borrowck-pat-ref-mut-twice.rs:45:9 | LL | let ref mut a @ ( | ^-------- @@ -66,7 +66,7 @@ LL | | ) = (U, [U, U, U]); | |_____^ error: cannot borrow value as mutable more than once at a time - --> $DIR/borrowck-pat-ref-mut-twice.rs:56:9 + --> $DIR/borrowck-pat-ref-mut-twice.rs:55:9 | LL | let ref mut a @ ( | ^-------- @@ -88,7 +88,7 @@ LL | | ) = (u(), [u(), u(), u()]); | |_________^ error: borrow of moved value - --> $DIR/borrowck-pat-ref-mut-twice.rs:66:9 + --> $DIR/borrowck-pat-ref-mut-twice.rs:65:9 | LL | let a @ (ref mut b, ref mut c) = (U, U); | -^^^^---------^^---------^ @@ -99,7 +99,7 @@ LL | let a @ (ref mut b, ref mut c) = (U, U); | move occurs because `a` has type `(U, U)` which does not implement the `Copy` trait error: borrow of moved value - --> $DIR/borrowck-pat-ref-mut-twice.rs:70:9 + --> $DIR/borrowck-pat-ref-mut-twice.rs:69:9 | LL | let a @ (b, [c, d]) = &mut val; // Same as ^-- | -^^^^-^^^-^^-^^ @@ -111,7 +111,7 @@ LL | let a @ (b, [c, d]) = &mut val; // Same as ^-- | move occurs because `a` has type `&mut (U, [U; 2])` which does not implement the `Copy` trait error: borrow of moved value - --> $DIR/borrowck-pat-ref-mut-twice.rs:74:9 + --> $DIR/borrowck-pat-ref-mut-twice.rs:73:9 | LL | let a @ &mut ref mut b = &mut U; | -^^^^^^^^--------- @@ -121,7 +121,7 @@ LL | let a @ &mut ref mut b = &mut U; | move occurs because `a` has type `&mut U` which does not implement the `Copy` trait error: borrow of moved value - --> $DIR/borrowck-pat-ref-mut-twice.rs:77:9 + --> $DIR/borrowck-pat-ref-mut-twice.rs:76:9 | LL | let a @ &mut (ref mut b, ref mut c) = &mut (U, U); | -^^^^^^^^^---------^^---------^ @@ -132,7 +132,7 @@ LL | let a @ &mut (ref mut b, ref mut c) = &mut (U, U); | move occurs because `a` has type `&mut (U, U)` which does not implement the `Copy` trait error: cannot borrow value as mutable more than once at a time - --> $DIR/borrowck-pat-ref-mut-twice.rs:82:9 + --> $DIR/borrowck-pat-ref-mut-twice.rs:81:9 | LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => { | ---------^^^^^^---------^ @@ -141,7 +141,7 @@ LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => { | first mutable borrow, by `a`, occurs here error: cannot borrow value as mutable more than once at a time - --> $DIR/borrowck-pat-ref-mut-twice.rs:82:37 + --> $DIR/borrowck-pat-ref-mut-twice.rs:81:37 | LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => { | ---------^^^^^^^---------^ @@ -150,7 +150,7 @@ LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => { | first mutable borrow, by `a`, occurs here error: cannot borrow value as mutable more than once at a time - --> $DIR/borrowck-pat-ref-mut-twice.rs:88:9 + --> $DIR/borrowck-pat-ref-mut-twice.rs:87:9 | LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => { | ---------^^^^^^---------^ @@ -159,7 +159,7 @@ LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => { | first mutable borrow, by `a`, occurs here error: cannot borrow value as mutable more than once at a time - --> $DIR/borrowck-pat-ref-mut-twice.rs:88:37 + --> $DIR/borrowck-pat-ref-mut-twice.rs:87:37 | LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => { | ---------^^^^^^^---------^ @@ -168,7 +168,7 @@ LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => { | first mutable borrow, by `a`, occurs here error: cannot borrow value as mutable more than once at a time - --> $DIR/borrowck-pat-ref-mut-twice.rs:95:9 + --> $DIR/borrowck-pat-ref-mut-twice.rs:94:9 | LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => { | ---------^^^^^^---------^ @@ -177,7 +177,7 @@ LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => { | first mutable borrow, by `a`, occurs here error: cannot borrow value as mutable more than once at a time - --> $DIR/borrowck-pat-ref-mut-twice.rs:95:37 + --> $DIR/borrowck-pat-ref-mut-twice.rs:94:37 | LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => { | ---------^^^^^^^---------^ @@ -186,7 +186,7 @@ LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => { | first mutable borrow, by `a`, occurs here error: cannot borrow value as mutable more than once at a time - --> $DIR/borrowck-pat-ref-mut-twice.rs:107:9 + --> $DIR/borrowck-pat-ref-mut-twice.rs:106:9 | LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => { | ---------^^^^^^---------^ @@ -195,7 +195,7 @@ LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => { | first mutable borrow, by `a`, occurs here error: cannot borrow value as mutable more than once at a time - --> $DIR/borrowck-pat-ref-mut-twice.rs:107:37 + --> $DIR/borrowck-pat-ref-mut-twice.rs:106:37 | LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => { | ---------^^^^^^^---------^ @@ -204,7 +204,7 @@ LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => { | first mutable borrow, by `a`, occurs here error: cannot borrow value as mutable more than once at a time - --> $DIR/borrowck-pat-ref-mut-twice.rs:11:11 + --> $DIR/borrowck-pat-ref-mut-twice.rs:10:11 | LL | fn f1(ref mut a @ ref mut b: U) {} | ---------^^^--------- @@ -213,7 +213,7 @@ LL | fn f1(ref mut a @ ref mut b: U) {} | first mutable borrow, by `a`, occurs here error: cannot borrow value as mutable more than once at a time - --> $DIR/borrowck-pat-ref-mut-twice.rs:13:11 + --> $DIR/borrowck-pat-ref-mut-twice.rs:12:11 | LL | fn f2(ref mut a @ ref mut b: U) {} | ---------^^^--------- @@ -222,7 +222,7 @@ LL | fn f2(ref mut a @ ref mut b: U) {} | first mutable borrow, by `a`, occurs here error: cannot borrow value as mutable more than once at a time - --> $DIR/borrowck-pat-ref-mut-twice.rs:16:9 + --> $DIR/borrowck-pat-ref-mut-twice.rs:15:9 | LL | ref mut a @ [ | ^-------- @@ -240,7 +240,7 @@ LL | | ] : [[U; 4]; 5] | |_________^ error: cannot borrow value as mutable more than once at a time - --> $DIR/borrowck-pat-ref-mut-twice.rs:24:22 + --> $DIR/borrowck-pat-ref-mut-twice.rs:23:22 | LL | fn f4_also_moved(ref mut a @ ref mut b @ c: U) {} | ---------^^^------------- @@ -250,7 +250,7 @@ LL | fn f4_also_moved(ref mut a @ ref mut b @ c: U) {} | first mutable borrow, by `a`, occurs here error: cannot move out of value because it is borrowed - --> $DIR/borrowck-pat-ref-mut-twice.rs:24:34 + --> $DIR/borrowck-pat-ref-mut-twice.rs:23:34 | LL | fn f4_also_moved(ref mut a @ ref mut b @ c: U) {} | ---------^^^- @@ -259,7 +259,7 @@ LL | fn f4_also_moved(ref mut a @ ref mut b @ c: U) {} | value borrowed, by `b`, here error[E0499]: cannot borrow value as mutable more than once at a time - --> $DIR/borrowck-pat-ref-mut-twice.rs:28:21 + --> $DIR/borrowck-pat-ref-mut-twice.rs:27:21 | LL | let ref mut a @ ref mut b = U; | ------------^^^^^^^^^ @@ -271,7 +271,7 @@ LL | drop(a); | - first borrow later used here error[E0499]: cannot borrow value as mutable more than once at a time - --> $DIR/borrowck-pat-ref-mut-twice.rs:38:21 + --> $DIR/borrowck-pat-ref-mut-twice.rs:37:21 | LL | let ref mut a @ ref mut b = U; | ------------^^^^^^^^^ @@ -283,7 +283,7 @@ LL | *a = U; | ------ first borrow later used here error[E0382]: borrow of moved value - --> $DIR/borrowck-pat-ref-mut-twice.rs:66:25 + --> $DIR/borrowck-pat-ref-mut-twice.rs:65:25 | LL | let a @ (ref mut b, ref mut c) = (U, U); | ----------------^^^^^^^^^- ------ move occurs because value has type `(U, U)`, which does not implement the `Copy` trait @@ -292,7 +292,7 @@ LL | let a @ (ref mut b, ref mut c) = (U, U); | value moved here error[E0382]: borrow of moved value - --> $DIR/borrowck-pat-ref-mut-twice.rs:70:21 + --> $DIR/borrowck-pat-ref-mut-twice.rs:69:21 | LL | let a @ (b, [c, d]) = &mut val; // Same as ^-- | ------------^-- -------- move occurs because value has type `&mut (U, [U; 2])`, which does not implement the `Copy` trait @@ -301,7 +301,7 @@ LL | let a @ (b, [c, d]) = &mut val; // Same as ^-- | value moved here error[E0382]: borrow of moved value - --> $DIR/borrowck-pat-ref-mut-twice.rs:74:18 + --> $DIR/borrowck-pat-ref-mut-twice.rs:73:18 | LL | let a @ &mut ref mut b = &mut U; | ---------^^^^^^^^^ ------ move occurs because value has type `&mut U`, which does not implement the `Copy` trait @@ -310,7 +310,7 @@ LL | let a @ &mut ref mut b = &mut U; | value moved here error[E0382]: borrow of moved value - --> $DIR/borrowck-pat-ref-mut-twice.rs:77:30 + --> $DIR/borrowck-pat-ref-mut-twice.rs:76:30 | LL | let a @ &mut (ref mut b, ref mut c) = &mut (U, U); | ---------------------^^^^^^^^^- ----------- move occurs because value has type `&mut (U, U)`, which does not implement the `Copy` trait @@ -319,7 +319,7 @@ LL | let a @ &mut (ref mut b, ref mut c) = &mut (U, U); | value moved here error[E0499]: cannot borrow value as mutable more than once at a time - --> $DIR/borrowck-pat-ref-mut-twice.rs:95:24 + --> $DIR/borrowck-pat-ref-mut-twice.rs:94:24 | LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => { | ---------------^^^^^^^^^- @@ -331,7 +331,7 @@ LL | *a = Err(U); | ----------- first borrow later used here error[E0499]: cannot borrow value as mutable more than once at a time - --> $DIR/borrowck-pat-ref-mut-twice.rs:95:53 + --> $DIR/borrowck-pat-ref-mut-twice.rs:94:53 | LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => { | ----------------^^^^^^^^^- @@ -343,7 +343,7 @@ LL | *a = Err(U); | ----------- first borrow later used here error[E0499]: cannot borrow value as mutable more than once at a time - --> $DIR/borrowck-pat-ref-mut-twice.rs:107:24 + --> $DIR/borrowck-pat-ref-mut-twice.rs:106:24 | LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => { | ---------------^^^^^^^^^- @@ -355,7 +355,7 @@ LL | drop(a); | - first borrow later used here error[E0499]: cannot borrow value as mutable more than once at a time - --> $DIR/borrowck-pat-ref-mut-twice.rs:107:53 + --> $DIR/borrowck-pat-ref-mut-twice.rs:106:53 | LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => { | ----------------^^^^^^^^^- diff --git a/src/test/ui/pattern/bindings-after-at/copy-and-move-mixed.rs b/src/test/ui/pattern/bindings-after-at/copy-and-move-mixed.rs index 821d4b42962..3954d17e1c2 100644 --- a/src/test/ui/pattern/bindings-after-at/copy-and-move-mixed.rs +++ b/src/test/ui/pattern/bindings-after-at/copy-and-move-mixed.rs @@ -1,7 +1,6 @@ // Test that mixing `Copy` and non-`Copy` types in `@` patterns is forbidden. #![feature(bindings_after_at)] -#![feature(move_ref_pattern)] #[derive(Copy, Clone)] struct C; diff --git a/src/test/ui/pattern/bindings-after-at/copy-and-move-mixed.stderr b/src/test/ui/pattern/bindings-after-at/copy-and-move-mixed.stderr index 7e89008a604..cc2786a13f4 100644 --- a/src/test/ui/pattern/bindings-after-at/copy-and-move-mixed.stderr +++ b/src/test/ui/pattern/bindings-after-at/copy-and-move-mixed.stderr @@ -1,5 +1,5 @@ error[E0382]: use of moved value - --> $DIR/copy-and-move-mixed.rs:12:19 + --> $DIR/copy-and-move-mixed.rs:11:19 | LL | let a @ NC(b, c) = NC(C, C); | ----------^- -------- move occurs because value has type `NC<C, C>`, which does not implement the `Copy` trait @@ -8,7 +8,7 @@ LL | let a @ NC(b, c) = NC(C, C); | value moved here error[E0382]: use of moved value - --> $DIR/copy-and-move-mixed.rs:15:19 + --> $DIR/copy-and-move-mixed.rs:14:19 | LL | let a @ NC(b, c @ NC(d, e)) = NC(C, NC(C, C)); | ----------^^^^^^^^^^^^- --------------- move occurs because value has type `NC<C, NC<C, C>>`, which does not implement the `Copy` trait @@ -17,7 +17,7 @@ LL | let a @ NC(b, c @ NC(d, e)) = NC(C, NC(C, C)); | value moved here error[E0382]: use of moved value - --> $DIR/copy-and-move-mixed.rs:15:29 + --> $DIR/copy-and-move-mixed.rs:14:29 | LL | let a @ NC(b, c @ NC(d, e)) = NC(C, NC(C, C)); | ----------^- diff --git a/src/test/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.rs b/src/test/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.rs index a45497229ac..276088b9a9e 100644 --- a/src/test/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.rs +++ b/src/test/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.rs @@ -8,7 +8,6 @@ // this would create problems for the generalization aforementioned. #![feature(bindings_after_at)] -#![feature(move_ref_pattern)] fn main() { struct NotCopy; diff --git a/src/test/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.stderr b/src/test/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.stderr index a63a5a1e6c7..11d5e24f34e 100644 --- a/src/test/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.stderr +++ b/src/test/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.stderr @@ -1,5 +1,5 @@ error: cannot move out of value because it is borrowed - --> $DIR/default-binding-modes-both-sides-independent.rs:28:9 + --> $DIR/default-binding-modes-both-sides-independent.rs:27:9 | LL | let ref a @ b = NotCopy; | -----^^^- @@ -8,7 +8,7 @@ LL | let ref a @ b = NotCopy; | value borrowed, by `a`, here error: cannot move out of value because it is borrowed - --> $DIR/default-binding-modes-both-sides-independent.rs:31:9 + --> $DIR/default-binding-modes-both-sides-independent.rs:30:9 | LL | let ref mut a @ b = NotCopy; | ---------^^^- @@ -17,7 +17,7 @@ LL | let ref mut a @ b = NotCopy; | value borrowed, by `a`, here error: cannot move out of value because it is borrowed - --> $DIR/default-binding-modes-both-sides-independent.rs:36:12 + --> $DIR/default-binding-modes-both-sides-independent.rs:35:12 | LL | Ok(ref a @ b) | Err(b @ ref a) => { | -----^^^- @@ -26,7 +26,7 @@ LL | Ok(ref a @ b) | Err(b @ ref a) => { | value borrowed, by `a`, here error: borrow of moved value - --> $DIR/default-binding-modes-both-sides-independent.rs:36:29 + --> $DIR/default-binding-modes-both-sides-independent.rs:35:29 | LL | Ok(ref a @ b) | Err(b @ ref a) => { | -^^^----- @@ -36,7 +36,7 @@ LL | Ok(ref a @ b) | Err(b @ ref a) => { | move occurs because `b` has type `NotCopy` which does not implement the `Copy` trait error: cannot move out of value because it is borrowed - --> $DIR/default-binding-modes-both-sides-independent.rs:44:9 + --> $DIR/default-binding-modes-both-sides-independent.rs:43:9 | LL | ref a @ b => { | -----^^^- @@ -45,7 +45,7 @@ LL | ref a @ b => { | value borrowed, by `a`, here error[E0505]: cannot move out of value because it is borrowed - --> $DIR/default-binding-modes-both-sides-independent.rs:31:21 + --> $DIR/default-binding-modes-both-sides-independent.rs:30:21 | LL | let ref mut a @ b = NotCopy; | ------------^ diff --git a/src/test/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern-pass.rs b/src/test/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern-pass.rs index d2d4e61e049..5445696fdff 100644 --- a/src/test/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern-pass.rs +++ b/src/test/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern-pass.rs @@ -1,7 +1,5 @@ // check-pass -#![feature(move_ref_pattern)] - fn main() {} struct U; diff --git a/src/test/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.rs b/src/test/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.rs index 3ee008fd84f..9c320edc4dc 100644 --- a/src/test/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.rs +++ b/src/test/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.rs @@ -1,5 +1,3 @@ -#![feature(move_ref_pattern)] - fn main() {} struct U; diff --git a/src/test/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.stderr b/src/test/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.stderr index d718ee29cf9..285c203f382 100644 --- a/src/test/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.stderr +++ b/src/test/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.stderr @@ -1,5 +1,5 @@ error[E0505]: cannot move out of `arr[..]` because it is borrowed - --> $DIR/borrowck-move-ref-pattern.rs:10:24 + --> $DIR/borrowck-move-ref-pattern.rs:8:24 | LL | let hold_all = &arr; | ---- borrow of `arr` occurs here @@ -10,7 +10,7 @@ LL | drop(hold_all); | -------- borrow later used here error[E0384]: cannot assign twice to immutable variable `_x1` - --> $DIR/borrowck-move-ref-pattern.rs:11:5 + --> $DIR/borrowck-move-ref-pattern.rs:9:5 | LL | let [ref _x0_hold, _x1, ref xs_hold @ ..] = arr; | --- @@ -21,7 +21,7 @@ LL | _x1 = U; | ^^^^^^^ cannot assign twice to immutable variable error[E0505]: cannot move out of `arr[..]` because it is borrowed - --> $DIR/borrowck-move-ref-pattern.rs:13:10 + --> $DIR/borrowck-move-ref-pattern.rs:11:10 | LL | let [ref _x0_hold, _x1, ref xs_hold @ ..] = arr; | ------------ borrow of `arr[..]` occurs here @@ -32,7 +32,7 @@ LL | drop(_x0_hold); | -------- borrow later used here error[E0502]: cannot borrow `arr[..]` as mutable because it is also borrowed as immutable - --> $DIR/borrowck-move-ref-pattern.rs:15:16 + --> $DIR/borrowck-move-ref-pattern.rs:13:16 | LL | let [ref _x0_hold, _x1, ref xs_hold @ ..] = arr; | ---------------- immutable borrow occurs here @@ -44,7 +44,7 @@ LL | drop(xs_hold); | ------- immutable borrow later used here error[E0505]: cannot move out of `arr[..]` because it is borrowed - --> $DIR/borrowck-move-ref-pattern.rs:15:29 + --> $DIR/borrowck-move-ref-pattern.rs:13:29 | LL | let [ref _x0_hold, _x1, ref xs_hold @ ..] = arr; | ---------------- borrow of `arr[..]` occurs here @@ -56,7 +56,7 @@ LL | drop(xs_hold); | ------- borrow later used here error[E0505]: cannot move out of `arr[..]` because it is borrowed - --> $DIR/borrowck-move-ref-pattern.rs:15:34 + --> $DIR/borrowck-move-ref-pattern.rs:13:34 | LL | let [ref _x0_hold, _x1, ref xs_hold @ ..] = arr; | ---------------- borrow of `arr[..]` occurs here @@ -68,7 +68,7 @@ LL | drop(xs_hold); | ------- borrow later used here error[E0384]: cannot assign twice to immutable variable `_x1` - --> $DIR/borrowck-move-ref-pattern.rs:25:5 + --> $DIR/borrowck-move-ref-pattern.rs:23:5 | LL | let (ref _x0, _x1, ref _x2, ..) = tup; | --- @@ -79,7 +79,7 @@ LL | _x1 = U; | ^^^^^^^ cannot assign twice to immutable variable error[E0502]: cannot borrow `tup.0` as mutable because it is also borrowed as immutable - --> $DIR/borrowck-move-ref-pattern.rs:26:20 + --> $DIR/borrowck-move-ref-pattern.rs:24:20 | LL | let (ref _x0, _x1, ref _x2, ..) = tup; | ------- immutable borrow occurs here @@ -91,7 +91,7 @@ LL | *_x0 = U; | -------- immutable borrow later used here error[E0502]: cannot borrow `tup.0` as mutable because it is also borrowed as immutable - --> $DIR/borrowck-move-ref-pattern.rs:27:10 + --> $DIR/borrowck-move-ref-pattern.rs:25:10 | LL | let (ref _x0, _x1, ref _x2, ..) = tup; | ------- immutable borrow occurs here @@ -102,7 +102,7 @@ LL | *_x0 = U; | -------- immutable borrow later used here error[E0594]: cannot assign to `*_x0` which is behind a `&` reference - --> $DIR/borrowck-move-ref-pattern.rs:28:5 + --> $DIR/borrowck-move-ref-pattern.rs:26:5 | LL | let (ref _x0, _x1, ref _x2, ..) = tup; | ------- help: consider changing this to be a mutable reference: `ref mut _x0` @@ -111,7 +111,7 @@ LL | *_x0 = U; | ^^^^^^^^ `_x0` is a `&` reference, so the data it refers to cannot be written error[E0594]: cannot assign to `*_x2` which is behind a `&` reference - --> $DIR/borrowck-move-ref-pattern.rs:29:5 + --> $DIR/borrowck-move-ref-pattern.rs:27:5 | LL | let (ref _x0, _x1, ref _x2, ..) = tup; | ------- help: consider changing this to be a mutable reference: `ref mut _x2` @@ -120,7 +120,7 @@ LL | *_x2 = U; | ^^^^^^^^ `_x2` is a `&` reference, so the data it refers to cannot be written error[E0382]: use of moved value: `tup.1` - --> $DIR/borrowck-move-ref-pattern.rs:30:10 + --> $DIR/borrowck-move-ref-pattern.rs:28:10 | LL | let (ref _x0, _x1, ref _x2, ..) = tup; | --- value moved here @@ -131,7 +131,7 @@ LL | drop(tup.1); = note: move occurs because `tup.1` has type `U`, which does not implement the `Copy` trait error[E0382]: borrow of moved value: `tup.1` - --> $DIR/borrowck-move-ref-pattern.rs:31:20 + --> $DIR/borrowck-move-ref-pattern.rs:29:20 | LL | drop(tup.1); | ----- value moved here @@ -141,7 +141,7 @@ LL | let _x1_hold = &tup.1; = note: move occurs because `tup.1` has type `U`, which does not implement the `Copy` trait error[E0502]: cannot borrow `tup.3` as immutable because it is also borrowed as mutable - --> $DIR/borrowck-move-ref-pattern.rs:33:20 + --> $DIR/borrowck-move-ref-pattern.rs:31:20 | LL | let (.., ref mut _x3) = tup; | ----------- mutable borrow occurs here @@ -152,7 +152,7 @@ LL | drop(_x3); | --- mutable borrow later used here error[E0499]: cannot borrow `tup.3` as mutable more than once at a time - --> $DIR/borrowck-move-ref-pattern.rs:34:20 + --> $DIR/borrowck-move-ref-pattern.rs:32:20 | LL | let (.., ref mut _x3) = tup; | ----------- first mutable borrow occurs here @@ -164,7 +164,7 @@ LL | drop(_x3); | --- first borrow later used here error[E0499]: cannot borrow `tup.3` as mutable more than once at a time - --> $DIR/borrowck-move-ref-pattern.rs:35:14 + --> $DIR/borrowck-move-ref-pattern.rs:33:14 | LL | let (.., ref mut _x3) = tup; | ----------- first mutable borrow occurs here @@ -176,7 +176,7 @@ LL | drop(_x3); | --- first borrow later used here error[E0502]: cannot borrow `tup.3` as immutable because it is also borrowed as mutable - --> $DIR/borrowck-move-ref-pattern.rs:36:14 + --> $DIR/borrowck-move-ref-pattern.rs:34:14 | LL | let (.., ref mut _x3) = tup; | ----------- mutable borrow occurs here @@ -187,7 +187,7 @@ LL | drop(_x3); | --- mutable borrow later used here error[E0382]: use of moved value: `tup` - --> $DIR/borrowck-move-ref-pattern.rs:45:14 + --> $DIR/borrowck-move-ref-pattern.rs:43:14 | LL | let mut tup = (U, U, U); | ------- move occurs because `tup` has type `(U, U, U)`, which does not implement the `Copy` trait diff --git a/src/test/ui/pattern/move-ref-patterns/by-move-sub-pat-unreachable.rs b/src/test/ui/pattern/move-ref-patterns/by-move-sub-pat-unreachable.rs index 08fb5cd2e16..18663c3fe3f 100644 --- a/src/test/ui/pattern/move-ref-patterns/by-move-sub-pat-unreachable.rs +++ b/src/test/ui/pattern/move-ref-patterns/by-move-sub-pat-unreachable.rs @@ -4,7 +4,6 @@ // check-pass -#![feature(move_ref_pattern)] #![feature(bindings_after_at)] fn main() { diff --git a/src/test/ui/pattern/move-ref-patterns/feature-gate-move_ref_pattern.rs b/src/test/ui/pattern/move-ref-patterns/feature-gate-move_ref_pattern.rs deleted file mode 100644 index fb92eb1ba32..00000000000 --- a/src/test/ui/pattern/move-ref-patterns/feature-gate-move_ref_pattern.rs +++ /dev/null @@ -1,23 +0,0 @@ -fn main() { - #[derive(Clone)] - struct X { - x: (), - } - let mut tup = (X { x: () }, X { x: () }); - match Some(tup.clone()) { - Some((y, ref z)) => {} - //~^ ERROR binding by-move and by-ref in the same pattern is unstable - None => panic!(), - } - - let (ref a, b) = tup.clone(); - //~^ ERROR binding by-move and by-ref in the same pattern is unstable - - let (a, mut b) = &tup; - //~^ ERROR binding by-move and by-ref in the same pattern is unstable - //~| ERROR cannot move out of a shared reference - - let (mut a, b) = &mut tup; - //~^ ERROR binding by-move and by-ref in the same pattern is unstable - //~| ERROR cannot move out of a mutable reference -} diff --git a/src/test/ui/pattern/move-ref-patterns/feature-gate-move_ref_pattern.stderr b/src/test/ui/pattern/move-ref-patterns/feature-gate-move_ref_pattern.stderr deleted file mode 100644 index 5335569a972..00000000000 --- a/src/test/ui/pattern/move-ref-patterns/feature-gate-move_ref_pattern.stderr +++ /dev/null @@ -1,66 +0,0 @@ -error[E0658]: binding by-move and by-ref in the same pattern is unstable - --> $DIR/feature-gate-move_ref_pattern.rs:8:15 - | -LL | Some((y, ref z)) => {} - | ^ ----- by-ref pattern here - | | - | by-move pattern here - | - = note: see issue #68354 <https://github.com/rust-lang/rust/issues/68354> for more information - = help: add `#![feature(move_ref_pattern)]` to the crate attributes to enable - -error[E0658]: binding by-move and by-ref in the same pattern is unstable - --> $DIR/feature-gate-move_ref_pattern.rs:13:17 - | -LL | let (ref a, b) = tup.clone(); - | ----- ^ by-move pattern here - | | - | by-ref pattern here - | - = note: see issue #68354 <https://github.com/rust-lang/rust/issues/68354> for more information - = help: add `#![feature(move_ref_pattern)]` to the crate attributes to enable - -error[E0658]: binding by-move and by-ref in the same pattern is unstable - --> $DIR/feature-gate-move_ref_pattern.rs:16:13 - | -LL | let (a, mut b) = &tup; - | - ^^^^^ by-move pattern here - | | - | by-ref pattern here - | - = note: see issue #68354 <https://github.com/rust-lang/rust/issues/68354> for more information - = help: add `#![feature(move_ref_pattern)]` to the crate attributes to enable - -error[E0658]: binding by-move and by-ref in the same pattern is unstable - --> $DIR/feature-gate-move_ref_pattern.rs:20:10 - | -LL | let (mut a, b) = &mut tup; - | ^^^^^ - by-ref pattern here - | | - | by-move pattern here - | - = note: see issue #68354 <https://github.com/rust-lang/rust/issues/68354> for more information - = help: add `#![feature(move_ref_pattern)]` to the crate attributes to enable - -error[E0507]: cannot move out of a shared reference - --> $DIR/feature-gate-move_ref_pattern.rs:16:22 - | -LL | let (a, mut b) = &tup; - | ----- ^^^^ - | | - | data moved here - | move occurs because `b` has type `X`, which does not implement the `Copy` trait - -error[E0507]: cannot move out of a mutable reference - --> $DIR/feature-gate-move_ref_pattern.rs:20:22 - | -LL | let (mut a, b) = &mut tup; - | ----- ^^^^^^^^ - | | - | data moved here - | move occurs because `a` has type `X`, which does not implement the `Copy` trait - -error: aborting due to 6 previous errors - -Some errors have detailed explanations: E0507, E0658. -For more information about an error, try `rustc --explain E0507`. diff --git a/src/test/ui/pattern/move-ref-patterns/issue-53840.rs b/src/test/ui/pattern/move-ref-patterns/issue-53840.rs index ab7d10d9f83..80effc497ed 100644 --- a/src/test/ui/pattern/move-ref-patterns/issue-53840.rs +++ b/src/test/ui/pattern/move-ref-patterns/issue-53840.rs @@ -1,7 +1,5 @@ // check-pass -#![feature(move_ref_pattern)] - enum E { Foo(String, String, String), } diff --git a/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures-inside.rs b/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures-inside.rs index 4c3ca62e165..ebb1683af7d 100644 --- a/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures-inside.rs +++ b/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures-inside.rs @@ -1,5 +1,3 @@ -#![feature(move_ref_pattern)] - fn main() { struct S; // Not `Copy`. diff --git a/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures-inside.stderr b/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures-inside.stderr index 9ad84879595..f19fed08917 100644 --- a/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures-inside.stderr +++ b/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures-inside.stderr @@ -1,5 +1,5 @@ error[E0382]: borrow of moved value: `tup0` - --> $DIR/move-ref-patterns-closure-captures-inside.rs:33:10 + --> $DIR/move-ref-patterns-closure-captures-inside.rs:31:10 | LL | let mut tup0 = (S, S); | -------- move occurs because `tup0` has type `(S, S)`, which does not implement the `Copy` trait @@ -14,7 +14,7 @@ LL | drop(&tup0); | ^^^^^ value borrowed here after move error[E0382]: borrow of moved value: `tup1` - --> $DIR/move-ref-patterns-closure-captures-inside.rs:34:10 + --> $DIR/move-ref-patterns-closure-captures-inside.rs:32:10 | LL | let mut tup1 = (S, S, S); | -------- move occurs because `tup1` has type `(S, S, S)`, which does not implement the `Copy` trait @@ -29,7 +29,7 @@ LL | drop(&tup1); | ^^^^^ value borrowed here after move error[E0382]: borrow of moved value: `tup2` - --> $DIR/move-ref-patterns-closure-captures-inside.rs:35:10 + --> $DIR/move-ref-patterns-closure-captures-inside.rs:33:10 | LL | let tup2 = (S, S); | ---- move occurs because `tup2` has type `(S, S)`, which does not implement the `Copy` trait @@ -44,7 +44,7 @@ LL | drop(&tup2); | ^^^^^ value borrowed here after move error[E0382]: borrow of moved value: `tup3` - --> $DIR/move-ref-patterns-closure-captures-inside.rs:36:10 + --> $DIR/move-ref-patterns-closure-captures-inside.rs:34:10 | LL | let tup3 = (S, S, S); | ---- move occurs because `tup3` has type `(S, S, S)`, which does not implement the `Copy` trait @@ -59,7 +59,7 @@ LL | drop(&tup3); | ^^^^^ value borrowed here after move error[E0382]: borrow of moved value: `tup4` - --> $DIR/move-ref-patterns-closure-captures-inside.rs:41:10 + --> $DIR/move-ref-patterns-closure-captures-inside.rs:39:10 | LL | let tup4 = (S, S); | ---- move occurs because `tup4` has type `(S, S)`, which does not implement the `Copy` trait @@ -74,7 +74,7 @@ LL | drop(&tup4.0); | ^^^^^^^ value borrowed here after move error[E0382]: borrow of moved value: `arr0` - --> $DIR/move-ref-patterns-closure-captures-inside.rs:43:10 + --> $DIR/move-ref-patterns-closure-captures-inside.rs:41:10 | LL | let mut arr0 = [S, S, S]; | -------- move occurs because `arr0` has type `[S; 3]`, which does not implement the `Copy` trait @@ -89,7 +89,7 @@ LL | drop(&arr0); | ^^^^^ value borrowed here after move error[E0382]: borrow of moved value: `arr1` - --> $DIR/move-ref-patterns-closure-captures-inside.rs:44:36 + --> $DIR/move-ref-patterns-closure-captures-inside.rs:42:36 | LL | let mut arr1 = [S, S, S, S, S]; | -------- move occurs because `arr1` has type `[S; 5]`, which does not implement the `Copy` trait @@ -104,7 +104,7 @@ LL | let [_, mov1, mov2, mov3, _] = &arr1; | ^^^^^ value borrowed here after move error[E0382]: borrow of moved value: `arr2` - --> $DIR/move-ref-patterns-closure-captures-inside.rs:45:10 + --> $DIR/move-ref-patterns-closure-captures-inside.rs:43:10 | LL | let arr2 = [S, S, S]; | ---- move occurs because `arr2` has type `[S; 3]`, which does not implement the `Copy` trait @@ -119,7 +119,7 @@ LL | drop(&arr2); | ^^^^^ value borrowed here after move error[E0382]: borrow of moved value: `arr3` - --> $DIR/move-ref-patterns-closure-captures-inside.rs:46:36 + --> $DIR/move-ref-patterns-closure-captures-inside.rs:44:36 | LL | let arr3 = [S, S, S, S, S]; | ---- move occurs because `arr3` has type `[S; 5]`, which does not implement the `Copy` trait @@ -134,7 +134,7 @@ LL | let [_, mov1, mov2, mov3, _] = &arr3; | ^^^^^ value borrowed here after move error[E0382]: borrow of moved value: `tup0` - --> $DIR/move-ref-patterns-closure-captures-inside.rs:77:10 + --> $DIR/move-ref-patterns-closure-captures-inside.rs:75:10 | LL | let mut tup0: Option<(S, S)> = None; | -------- move occurs because `tup0` has type `Option<(S, S)>`, which does not implement the `Copy` trait @@ -148,7 +148,7 @@ LL | drop(&tup0); | ^^^^^ value borrowed here after move error[E0382]: borrow of moved value: `tup1` - --> $DIR/move-ref-patterns-closure-captures-inside.rs:78:10 + --> $DIR/move-ref-patterns-closure-captures-inside.rs:76:10 | LL | let mut tup1: Option<(S, S, S)> = None; | -------- move occurs because `tup1` has type `Option<(S, S, S)>`, which does not implement the `Copy` trait @@ -163,7 +163,7 @@ LL | drop(&tup1); | ^^^^^ value borrowed here after move error[E0382]: borrow of moved value: `tup2` - --> $DIR/move-ref-patterns-closure-captures-inside.rs:79:10 + --> $DIR/move-ref-patterns-closure-captures-inside.rs:77:10 | LL | let tup2: Option<(S, S)> = None; | ---- move occurs because `tup2` has type `Option<(S, S)>`, which does not implement the `Copy` trait @@ -178,7 +178,7 @@ LL | drop(&tup2); | ^^^^^ value borrowed here after move error[E0382]: borrow of moved value: `tup3` - --> $DIR/move-ref-patterns-closure-captures-inside.rs:80:10 + --> $DIR/move-ref-patterns-closure-captures-inside.rs:78:10 | LL | let tup3: Option<(S, S, S)> = None; | ---- move occurs because `tup3` has type `Option<(S, S, S)>`, which does not implement the `Copy` trait @@ -193,7 +193,7 @@ LL | drop(&tup3); | ^^^^^ value borrowed here after move error[E0382]: borrow of moved value: `tup4` - --> $DIR/move-ref-patterns-closure-captures-inside.rs:81:21 + --> $DIR/move-ref-patterns-closure-captures-inside.rs:79:21 | LL | let tup4: Option<(S, S)> = None; | ---- move occurs because `tup4` has type `Option<(S, S)>`, which does not implement the `Copy` trait @@ -208,7 +208,7 @@ LL | m!((ref x, _) = &tup4); | ^^^^^ value borrowed here after move error[E0382]: borrow of moved value: `arr0` - --> $DIR/move-ref-patterns-closure-captures-inside.rs:82:10 + --> $DIR/move-ref-patterns-closure-captures-inside.rs:80:10 | LL | let mut arr0: Option<[S; 3]> = None; | -------- move occurs because `arr0` has type `Option<[S; 3]>`, which does not implement the `Copy` trait @@ -223,7 +223,7 @@ LL | drop(&arr0); | ^^^^^ value borrowed here after move error[E0382]: borrow of moved value: `arr1` - --> $DIR/move-ref-patterns-closure-captures-inside.rs:83:35 + --> $DIR/move-ref-patterns-closure-captures-inside.rs:81:35 | LL | let mut arr1: Option<[S; 5]> = None; | -------- move occurs because `arr1` has type `Option<[S; 5]>`, which does not implement the `Copy` trait @@ -238,7 +238,7 @@ LL | m!([_, mov1, mov2, mov3, _] = &arr1); | ^^^^^ value borrowed here after move error[E0382]: borrow of moved value: `arr2` - --> $DIR/move-ref-patterns-closure-captures-inside.rs:84:10 + --> $DIR/move-ref-patterns-closure-captures-inside.rs:82:10 | LL | let arr2: Option<[S; 3]> = None; | ---- move occurs because `arr2` has type `Option<[S; 3]>`, which does not implement the `Copy` trait @@ -253,7 +253,7 @@ LL | drop(&arr2); | ^^^^^ value borrowed here after move error[E0382]: borrow of moved value: `arr3` - --> $DIR/move-ref-patterns-closure-captures-inside.rs:85:35 + --> $DIR/move-ref-patterns-closure-captures-inside.rs:83:35 | LL | let arr3: Option<[S; 5]> = None; | ---- move occurs because `arr3` has type `Option<[S; 5]>`, which does not implement the `Copy` trait @@ -267,7 +267,7 @@ LL | m!([_, mov1, mov2, mov3, _] = &arr3); | ^^^^^ value borrowed here after move error[E0382]: borrow of moved value: `tup0` - --> $DIR/move-ref-patterns-closure-captures-inside.rs:113:10 + --> $DIR/move-ref-patterns-closure-captures-inside.rs:111:10 | LL | let mut tup0: Option<(S, S)> = None; | -------- move occurs because `tup0` has type `Option<(S, S)>`, which does not implement the `Copy` trait @@ -281,7 +281,7 @@ LL | drop(&tup0); | ^^^^^ value borrowed here after move error[E0382]: borrow of moved value: `tup1` - --> $DIR/move-ref-patterns-closure-captures-inside.rs:114:10 + --> $DIR/move-ref-patterns-closure-captures-inside.rs:112:10 | LL | let mut tup1: Option<(S, S, S)> = None; | -------- move occurs because `tup1` has type `Option<(S, S, S)>`, which does not implement the `Copy` trait @@ -296,7 +296,7 @@ LL | drop(&tup1); | ^^^^^ value borrowed here after move error[E0382]: borrow of moved value: `tup2` - --> $DIR/move-ref-patterns-closure-captures-inside.rs:115:10 + --> $DIR/move-ref-patterns-closure-captures-inside.rs:113:10 | LL | let tup2: Option<(S, S)> = None; | ---- move occurs because `tup2` has type `Option<(S, S)>`, which does not implement the `Copy` trait @@ -311,7 +311,7 @@ LL | drop(&tup2); | ^^^^^ value borrowed here after move error[E0382]: borrow of moved value: `tup3` - --> $DIR/move-ref-patterns-closure-captures-inside.rs:116:10 + --> $DIR/move-ref-patterns-closure-captures-inside.rs:114:10 | LL | let tup3: Option<(S, S, S)> = None; | ---- move occurs because `tup3` has type `Option<(S, S, S)>`, which does not implement the `Copy` trait @@ -326,7 +326,7 @@ LL | drop(&tup3); | ^^^^^ value borrowed here after move error[E0382]: borrow of moved value: `tup4` - --> $DIR/move-ref-patterns-closure-captures-inside.rs:117:21 + --> $DIR/move-ref-patterns-closure-captures-inside.rs:115:21 | LL | let tup4: Option<(S, S)> = None; | ---- move occurs because `tup4` has type `Option<(S, S)>`, which does not implement the `Copy` trait @@ -341,7 +341,7 @@ LL | m!((ref x, _) = &tup4); | ^^^^^ value borrowed here after move error[E0382]: borrow of moved value: `arr0` - --> $DIR/move-ref-patterns-closure-captures-inside.rs:118:10 + --> $DIR/move-ref-patterns-closure-captures-inside.rs:116:10 | LL | let mut arr0: Option<[S; 3]> = None; | -------- move occurs because `arr0` has type `Option<[S; 3]>`, which does not implement the `Copy` trait @@ -356,7 +356,7 @@ LL | drop(&arr0); | ^^^^^ value borrowed here after move error[E0382]: borrow of moved value: `arr1` - --> $DIR/move-ref-patterns-closure-captures-inside.rs:119:35 + --> $DIR/move-ref-patterns-closure-captures-inside.rs:117:35 | LL | let mut arr1: Option<[S; 5]> = None; | -------- move occurs because `arr1` has type `Option<[S; 5]>`, which does not implement the `Copy` trait @@ -371,7 +371,7 @@ LL | m!([_, mov1, mov2, mov3, _] = &arr1); | ^^^^^ value borrowed here after move error[E0382]: borrow of moved value: `arr2` - --> $DIR/move-ref-patterns-closure-captures-inside.rs:120:10 + --> $DIR/move-ref-patterns-closure-captures-inside.rs:118:10 | LL | let arr2: Option<[S; 3]> = None; | ---- move occurs because `arr2` has type `Option<[S; 3]>`, which does not implement the `Copy` trait @@ -386,7 +386,7 @@ LL | drop(&arr2); | ^^^^^ value borrowed here after move error[E0382]: borrow of moved value: `arr3` - --> $DIR/move-ref-patterns-closure-captures-inside.rs:121:35 + --> $DIR/move-ref-patterns-closure-captures-inside.rs:119:35 | LL | let arr3: Option<[S; 5]> = None; | ---- move occurs because `arr3` has type `Option<[S; 5]>`, which does not implement the `Copy` trait diff --git a/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures-pass.rs b/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures-pass.rs index e1844d36e4a..583f70f41aa 100644 --- a/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures-pass.rs +++ b/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures-pass.rs @@ -1,7 +1,5 @@ // check-pass -#![feature(move_ref_pattern)] - fn main() { struct U; fn accept_fn_once(_: impl FnOnce()) {} diff --git a/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures.rs b/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures.rs index 7f1c02c05cb..cd619cc41eb 100644 --- a/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures.rs +++ b/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures.rs @@ -1,5 +1,3 @@ -#![feature(move_ref_pattern)] - fn main() { struct U; fn accept_fn_once(_: &impl FnOnce()) {} diff --git a/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures.stderr b/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures.stderr index ca82353c1c9..d96e863939c 100644 --- a/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures.stderr +++ b/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures.stderr @@ -1,5 +1,5 @@ error[E0525]: expected a closure that implements the `FnMut` trait, but this closure only implements `FnOnce` - --> $DIR/move-ref-patterns-closure-captures.rs:11:14 + --> $DIR/move-ref-patterns-closure-captures.rs:9:14 | LL | let c1 = || { | ^^ this closure implements `FnOnce`, not `FnMut` @@ -11,7 +11,7 @@ LL | accept_fn_mut(&c1); | ------------- the requirement to implement `FnMut` derives from here error[E0525]: expected a closure that implements the `Fn` trait, but this closure only implements `FnOnce` - --> $DIR/move-ref-patterns-closure-captures.rs:11:14 + --> $DIR/move-ref-patterns-closure-captures.rs:9:14 | LL | let c1 = || { | ^^ this closure implements `FnOnce`, not `Fn` @@ -23,7 +23,7 @@ LL | accept_fn(&c1); | --------- the requirement to implement `Fn` derives from here error[E0525]: expected a closure that implements the `Fn` trait, but this closure only implements `FnMut` - --> $DIR/move-ref-patterns-closure-captures.rs:22:14 + --> $DIR/move-ref-patterns-closure-captures.rs:20:14 | LL | let c2 = || { | ^^ this closure implements `FnMut`, not `Fn` diff --git a/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes.rs b/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes.rs index 5c51c47d979..1dd66aad57a 100644 --- a/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes.rs +++ b/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes.rs @@ -1,5 +1,3 @@ -#![feature(move_ref_pattern)] - fn main() { struct U; diff --git a/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes.stderr b/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes.stderr index f92699f5c3c..6952c743a30 100644 --- a/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes.stderr +++ b/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes.stderr @@ -1,5 +1,5 @@ error[E0507]: cannot move out of a shared reference - --> $DIR/move-ref-patterns-default-binding-modes.rs:10:22 + --> $DIR/move-ref-patterns-default-binding-modes.rs:8:22 | LL | let (a, mut b) = &p; | ----- ^^ @@ -8,7 +8,7 @@ LL | let (a, mut b) = &p; | move occurs because `b` has type `U`, which does not implement the `Copy` trait error[E0507]: cannot move out of a mutable reference - --> $DIR/move-ref-patterns-default-binding-modes.rs:14:22 + --> $DIR/move-ref-patterns-default-binding-modes.rs:12:22 | LL | let (a, mut b) = &mut p; | ----- ^^^^^^ diff --git a/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-dynamic-semantics.rs b/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-dynamic-semantics.rs index c78695390b5..1d6d9acead1 100644 --- a/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-dynamic-semantics.rs +++ b/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-dynamic-semantics.rs @@ -3,8 +3,6 @@ // This test checks the dynamic semantics and drop order of pattern matching // where a product pattern has both a by-move and by-ref binding. -#![feature(move_ref_pattern)] - use std::cell::RefCell; use std::rc::Rc; diff --git a/src/test/ui/polymorphization/const_parameters/closures.stderr b/src/test/ui/polymorphization/const_parameters/closures.stderr index 266b6e62afd..63335586b76 100644 --- a/src/test/ui/polymorphization/const_parameters/closures.stderr +++ b/src/test/ui/polymorphization/const_parameters/closures.stderr @@ -6,6 +6,7 @@ LL | #![feature(const_generics, rustc_attrs)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information + = help: consider using `min_const_generics` instead, which is more stable and complete error: item has unused generic parameters --> $DIR/closures.rs:19:19 diff --git a/src/test/ui/polymorphization/const_parameters/functions.stderr b/src/test/ui/polymorphization/const_parameters/functions.stderr index e379e32c1fc..c976a5b62aa 100644 --- a/src/test/ui/polymorphization/const_parameters/functions.stderr +++ b/src/test/ui/polymorphization/const_parameters/functions.stderr @@ -6,6 +6,7 @@ LL | #![feature(const_generics, rustc_attrs)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information + = help: consider using `min_const_generics` instead, which is more stable and complete error: item has unused generic parameters --> $DIR/functions.rs:15:8 diff --git a/src/test/ui/polymorphization/generators.stderr b/src/test/ui/polymorphization/generators.stderr index c59055ba9d6..b2b32db045d 100644 --- a/src/test/ui/polymorphization/generators.stderr +++ b/src/test/ui/polymorphization/generators.stderr @@ -6,6 +6,7 @@ LL | #![feature(const_generics, generators, generator_trait, rustc_attrs)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information + = help: consider using `min_const_generics` instead, which is more stable and complete error: item has unused generic parameters --> $DIR/generators.rs:36:5 diff --git a/src/test/ui/proc-macro/group-compat-hack/actix-web-2.0.0/src/extract.rs b/src/test/ui/proc-macro/group-compat-hack/actix-web-2.0.0/src/extract.rs new file mode 100644 index 00000000000..2d4f6010012 --- /dev/null +++ b/src/test/ui/proc-macro/group-compat-hack/actix-web-2.0.0/src/extract.rs @@ -0,0 +1,7 @@ +// ignore-test this is not a test + +macro_rules! tuple_from_req { + ($T:ident) => { + #[my_macro] struct Three($T); + } +} diff --git a/src/test/ui/proc-macro/group-compat-hack/actix-web/src/extract.rs b/src/test/ui/proc-macro/group-compat-hack/actix-web/src/extract.rs new file mode 100644 index 00000000000..2d4f6010012 --- /dev/null +++ b/src/test/ui/proc-macro/group-compat-hack/actix-web/src/extract.rs @@ -0,0 +1,7 @@ +// ignore-test this is not a test + +macro_rules! tuple_from_req { + ($T:ident) => { + #[my_macro] struct Three($T); + } +} diff --git a/src/test/ui/proc-macro/group-compat-hack/actori-web-2.0.0/src/extract.rs b/src/test/ui/proc-macro/group-compat-hack/actori-web-2.0.0/src/extract.rs new file mode 100644 index 00000000000..9ec6aba63f3 --- /dev/null +++ b/src/test/ui/proc-macro/group-compat-hack/actori-web-2.0.0/src/extract.rs @@ -0,0 +1,7 @@ +// ignore-test this is not a test + +macro_rules! tuple_from_req { + ($T:ident) => { + #[my_macro] struct Four($T); + } +} diff --git a/src/test/ui/proc-macro/group-compat-hack/actori-web/src/extract.rs b/src/test/ui/proc-macro/group-compat-hack/actori-web/src/extract.rs new file mode 100644 index 00000000000..9ec6aba63f3 --- /dev/null +++ b/src/test/ui/proc-macro/group-compat-hack/actori-web/src/extract.rs @@ -0,0 +1,7 @@ +// ignore-test this is not a test + +macro_rules! tuple_from_req { + ($T:ident) => { + #[my_macro] struct Four($T); + } +} diff --git a/src/test/ui/proc-macro/group-compat-hack/group-compat-hack.rs b/src/test/ui/proc-macro/group-compat-hack/group-compat-hack.rs index bc82a2ff196..652fabf34ac 100644 --- a/src/test/ui/proc-macro/group-compat-hack/group-compat-hack.rs +++ b/src/test/ui/proc-macro/group-compat-hack/group-compat-hack.rs @@ -45,5 +45,33 @@ mod with_version { other!(Foo); } +mod actix_web_test { + include!("actix-web/src/extract.rs"); + + struct Foo; + tuple_from_req!(Foo); +} + +mod actix_web_version_test { + include!("actix-web-2.0.0/src/extract.rs"); + + struct Foo; + tuple_from_req!(Foo); +} + +mod actori_web_test { + include!("actori-web/src/extract.rs"); + + struct Foo; + tuple_from_req!(Foo); +} + +mod actori_web_version_test { + include!("actori-web-2.0.0/src/extract.rs"); + + struct Foo; + tuple_from_req!(Foo); +} + fn main() {} diff --git a/src/test/ui/proc-macro/group-compat-hack/group-compat-hack.stdout b/src/test/ui/proc-macro/group-compat-hack/group-compat-hack.stdout index e83bc9f8fca..c6b18ab674b 100644 --- a/src/test/ui/proc-macro/group-compat-hack/group-compat-hack.stdout +++ b/src/test/ui/proc-macro/group-compat-hack/group-compat-hack.stdout @@ -4,3 +4,7 @@ Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/gro Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/time-macros-impl-0.1.0/src/lib.rs:5:21: 5:27 (#20) }, Ident { ident: "One", span: $DIR/time-macros-impl-0.1.0/src/lib.rs:5:28: 5:31 (#20) }, Group { delimiter: Parenthesis, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:43:18: 43:21 (#0) }], span: $DIR/time-macros-impl-0.1.0/src/lib.rs:5:31: 5:38 (#20) }, Punct { ch: ';', spacing: Alone, span: $DIR/time-macros-impl-0.1.0/src/lib.rs:5:38: 5:39 (#20) }] Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/js-sys-0.3.17/src/lib.rs:5:21: 5:27 (#24) }, Ident { ident: "Two", span: $DIR/js-sys-0.3.17/src/lib.rs:5:28: 5:31 (#24) }, Group { delimiter: Parenthesis, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:44:13: 44:16 (#0) }], span: $DIR/js-sys-0.3.17/src/lib.rs:5:31: 5:38 (#24) }, Punct { ch: ';', spacing: Alone, span: $DIR/js-sys-0.3.17/src/lib.rs:5:38: 5:39 (#24) }] Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/group-compat-hack.rs:38:25: 38:31 (#28) }, Ident { ident: "Three", span: $DIR/group-compat-hack.rs:38:32: 38:37 (#28) }, Group { delimiter: Parenthesis, stream: TokenStream [Group { delimiter: None, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:45:12: 45:15 (#0) }], span: $DIR/group-compat-hack.rs:38:38: 38:43 (#28) }], span: $DIR/group-compat-hack.rs:38:37: 38:44 (#28) }, Punct { ch: ';', spacing: Alone, span: $DIR/group-compat-hack.rs:38:44: 38:45 (#28) }] +Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/actix-web/src/extract.rs:5:21: 5:27 (#33) }, Ident { ident: "Three", span: $DIR/actix-web/src/extract.rs:5:28: 5:33 (#33) }, Group { delimiter: Parenthesis, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:52:21: 52:24 (#0) }], span: $DIR/actix-web/src/extract.rs:5:33: 5:37 (#33) }, Punct { ch: ';', spacing: Alone, span: $DIR/actix-web/src/extract.rs:5:37: 5:38 (#33) }] +Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/actix-web-2.0.0/src/extract.rs:5:21: 5:27 (#38) }, Ident { ident: "Three", span: $DIR/actix-web-2.0.0/src/extract.rs:5:28: 5:33 (#38) }, Group { delimiter: Parenthesis, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:59:21: 59:24 (#0) }], span: $DIR/actix-web-2.0.0/src/extract.rs:5:33: 5:37 (#38) }, Punct { ch: ';', spacing: Alone, span: $DIR/actix-web-2.0.0/src/extract.rs:5:37: 5:38 (#38) }] +Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/actori-web/src/extract.rs:5:21: 5:27 (#43) }, Ident { ident: "Four", span: $DIR/actori-web/src/extract.rs:5:28: 5:32 (#43) }, Group { delimiter: Parenthesis, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:66:21: 66:24 (#0) }], span: $DIR/actori-web/src/extract.rs:5:32: 5:36 (#43) }, Punct { ch: ';', spacing: Alone, span: $DIR/actori-web/src/extract.rs:5:36: 5:37 (#43) }] +Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/actori-web-2.0.0/src/extract.rs:5:21: 5:27 (#48) }, Ident { ident: "Four", span: $DIR/actori-web-2.0.0/src/extract.rs:5:28: 5:32 (#48) }, Group { delimiter: Parenthesis, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:73:21: 73:24 (#0) }], span: $DIR/actori-web-2.0.0/src/extract.rs:5:32: 5:36 (#48) }, Punct { ch: ';', spacing: Alone, span: $DIR/actori-web-2.0.0/src/extract.rs:5:36: 5:37 (#48) }] diff --git a/src/test/ui/proc-macro/invalid-punct-ident-1.rs b/src/test/ui/proc-macro/invalid-punct-ident-1.rs index 3f78dea917b..a3133a1a790 100644 --- a/src/test/ui/proc-macro/invalid-punct-ident-1.rs +++ b/src/test/ui/proc-macro/invalid-punct-ident-1.rs @@ -9,6 +9,9 @@ // normalize-stderr-test "note: we would appreciate a bug report.*\n\n" -> "" // normalize-stderr-test "note: compiler flags.*\n\n" -> "" // normalize-stderr-test "note: rustc.*running on.*\n\n" -> "" +// normalize-stderr-test "query stack during panic:\n" -> "" +// normalize-stderr-test "we're just showing a limited slice of the query stack\n" -> "" +// normalize-stderr-test "end of query stack\n" -> "" #[macro_use] extern crate invalid_punct_ident; diff --git a/src/test/ui/proc-macro/invalid-punct-ident-1.stderr b/src/test/ui/proc-macro/invalid-punct-ident-1.stderr index fc821d29d5a..5ef22709cb3 100644 --- a/src/test/ui/proc-macro/invalid-punct-ident-1.stderr +++ b/src/test/ui/proc-macro/invalid-punct-ident-1.stderr @@ -1,5 +1,5 @@ error: proc macro panicked - --> $DIR/invalid-punct-ident-1.rs:16:1 + --> $DIR/invalid-punct-ident-1.rs:19:1 | LL | invalid_punct!(); | ^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/proc-macro/invalid-punct-ident-2.rs b/src/test/ui/proc-macro/invalid-punct-ident-2.rs index 4e89e80ae7c..04a0a873311 100644 --- a/src/test/ui/proc-macro/invalid-punct-ident-2.rs +++ b/src/test/ui/proc-macro/invalid-punct-ident-2.rs @@ -9,6 +9,9 @@ // normalize-stderr-test "note: we would appreciate a bug report.*\n\n" -> "" // normalize-stderr-test "note: compiler flags.*\n\n" -> "" // normalize-stderr-test "note: rustc.*running on.*\n\n" -> "" +// normalize-stderr-test "query stack during panic:\n" -> "" +// normalize-stderr-test "we're just showing a limited slice of the query stack\n" -> "" +// normalize-stderr-test "end of query stack\n" -> "" #[macro_use] extern crate invalid_punct_ident; diff --git a/src/test/ui/proc-macro/invalid-punct-ident-2.stderr b/src/test/ui/proc-macro/invalid-punct-ident-2.stderr index 8b30edaf85c..4bd7a5351d3 100644 --- a/src/test/ui/proc-macro/invalid-punct-ident-2.stderr +++ b/src/test/ui/proc-macro/invalid-punct-ident-2.stderr @@ -1,5 +1,5 @@ error: proc macro panicked - --> $DIR/invalid-punct-ident-2.rs:16:1 + --> $DIR/invalid-punct-ident-2.rs:19:1 | LL | invalid_ident!(); | ^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/proc-macro/invalid-punct-ident-3.rs b/src/test/ui/proc-macro/invalid-punct-ident-3.rs index 8d8ce8f932e..aebba341625 100644 --- a/src/test/ui/proc-macro/invalid-punct-ident-3.rs +++ b/src/test/ui/proc-macro/invalid-punct-ident-3.rs @@ -9,6 +9,9 @@ // normalize-stderr-test "note: we would appreciate a bug report.*\n\n" -> "" // normalize-stderr-test "note: compiler flags.*\n\n" -> "" // normalize-stderr-test "note: rustc.*running on.*\n\n" -> "" +// normalize-stderr-test "query stack during panic:\n" -> "" +// normalize-stderr-test "we're just showing a limited slice of the query stack\n" -> "" +// normalize-stderr-test "end of query stack\n" -> "" #[macro_use] extern crate invalid_punct_ident; diff --git a/src/test/ui/proc-macro/invalid-punct-ident-3.stderr b/src/test/ui/proc-macro/invalid-punct-ident-3.stderr index d46fab08e14..072d13956ac 100644 --- a/src/test/ui/proc-macro/invalid-punct-ident-3.stderr +++ b/src/test/ui/proc-macro/invalid-punct-ident-3.stderr @@ -1,5 +1,5 @@ error: proc macro panicked - --> $DIR/invalid-punct-ident-3.rs:16:1 + --> $DIR/invalid-punct-ident-3.rs:19:1 | LL | invalid_raw_ident!(); | ^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/proc-macro/issue-75734-pp-paren.rs b/src/test/ui/proc-macro/issue-75734-pp-paren.rs new file mode 100644 index 00000000000..faa93787d13 --- /dev/null +++ b/src/test/ui/proc-macro/issue-75734-pp-paren.rs @@ -0,0 +1,26 @@ +// Regression test for issue #75734 +// Ensures that we don't lose tokens when pretty-printing would +// normally insert extra parentheses. + +// check-pass +// aux-build:test-macros.rs +// compile-flags: -Z span-debug + +#![no_std] // Don't load unnecessary hygiene information from std +extern crate std; + +#[macro_use] +extern crate test_macros; + +macro_rules! mul_2 { + ($val:expr) => { + print_bang!($val * 2); + }; +} + + +#[print_attr] +fn main() { + &|_: u8| {}; + mul_2!(1 + 1); +} diff --git a/src/test/ui/proc-macro/issue-75734-pp-paren.stdout b/src/test/ui/proc-macro/issue-75734-pp-paren.stdout new file mode 100644 index 00000000000..b33b85f1705 --- /dev/null +++ b/src/test/ui/proc-macro/issue-75734-pp-paren.stdout @@ -0,0 +1,134 @@ +PRINT-ATTR INPUT (DISPLAY): fn main() { & | _ : u8 | { } ; mul_2 ! (1 + 1) ; } +PRINT-ATTR INPUT (DEBUG): TokenStream [ + Ident { + ident: "fn", + span: $DIR/issue-75734-pp-paren.rs:23:1: 23:3 (#0), + }, + Ident { + ident: "main", + span: $DIR/issue-75734-pp-paren.rs:23:4: 23:8 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [], + span: $DIR/issue-75734-pp-paren.rs:23:8: 23:10 (#0), + }, + Group { + delimiter: Brace, + stream: TokenStream [ + Punct { + ch: '&', + spacing: Joint, + span: $DIR/issue-75734-pp-paren.rs:24:5: 24:6 (#0), + }, + Punct { + ch: '|', + spacing: Alone, + span: $DIR/issue-75734-pp-paren.rs:24:6: 24:7 (#0), + }, + Ident { + ident: "_", + span: $DIR/issue-75734-pp-paren.rs:24:7: 24:8 (#0), + }, + Punct { + ch: ':', + spacing: Alone, + span: $DIR/issue-75734-pp-paren.rs:24:8: 24:9 (#0), + }, + Ident { + ident: "u8", + span: $DIR/issue-75734-pp-paren.rs:24:10: 24:12 (#0), + }, + Punct { + ch: '|', + spacing: Alone, + span: $DIR/issue-75734-pp-paren.rs:24:12: 24:13 (#0), + }, + Group { + delimiter: Brace, + stream: TokenStream [], + span: $DIR/issue-75734-pp-paren.rs:24:14: 24:16 (#0), + }, + Punct { + ch: ';', + spacing: Alone, + span: $DIR/issue-75734-pp-paren.rs:24:16: 24:17 (#0), + }, + Ident { + ident: "mul_2", + span: $DIR/issue-75734-pp-paren.rs:25:5: 25:10 (#0), + }, + Punct { + ch: '!', + spacing: Alone, + span: $DIR/issue-75734-pp-paren.rs:25:10: 25:11 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Literal { + kind: Integer, + symbol: "1", + suffix: None, + span: $DIR/issue-75734-pp-paren.rs:25:12: 25:13 (#0), + }, + Punct { + ch: '+', + spacing: Alone, + span: $DIR/issue-75734-pp-paren.rs:25:14: 25:15 (#0), + }, + Literal { + kind: Integer, + symbol: "1", + suffix: None, + span: $DIR/issue-75734-pp-paren.rs:25:16: 25:17 (#0), + }, + ], + span: $DIR/issue-75734-pp-paren.rs:25:11: 25:18 (#0), + }, + Punct { + ch: ';', + spacing: Alone, + span: $DIR/issue-75734-pp-paren.rs:25:18: 25:19 (#0), + }, + ], + span: $DIR/issue-75734-pp-paren.rs:23:11: 26:2 (#0), + }, +] +PRINT-BANG INPUT (DISPLAY): 1 + 1 * 2 +PRINT-BANG INPUT (DEBUG): TokenStream [ + Group { + delimiter: None, + stream: TokenStream [ + Literal { + kind: Integer, + symbol: "1", + suffix: None, + span: $DIR/issue-75734-pp-paren.rs:25:12: 25:13 (#0), + }, + Punct { + ch: '+', + spacing: Alone, + span: $DIR/issue-75734-pp-paren.rs:25:14: 25:15 (#0), + }, + Literal { + kind: Integer, + symbol: "1", + suffix: None, + span: $DIR/issue-75734-pp-paren.rs:25:16: 25:17 (#0), + }, + ], + span: $DIR/issue-75734-pp-paren.rs:17:21: 17:25 (#7), + }, + Punct { + ch: '*', + spacing: Alone, + span: $DIR/issue-75734-pp-paren.rs:17:26: 17:27 (#7), + }, + Literal { + kind: Integer, + symbol: "2", + suffix: None, + span: $DIR/issue-75734-pp-paren.rs:17:28: 17:29 (#7), + }, +] diff --git a/src/test/ui/proc-macro/load-panic-backtrace.rs b/src/test/ui/proc-macro/load-panic-backtrace.rs index 90fe109abb8..4a3ba9aee74 100644 --- a/src/test/ui/proc-macro/load-panic-backtrace.rs +++ b/src/test/ui/proc-macro/load-panic-backtrace.rs @@ -10,6 +10,9 @@ // normalize-stderr-test "note: we would appreciate a bug report.*\n\n" -> "" // normalize-stderr-test "note: compiler flags.*\n\n" -> "" // normalize-stderr-test "note: rustc.*running on.*\n\n" -> "" +// normalize-stderr-test "query stack during panic:\n" -> "" +// normalize-stderr-test "we're just showing a limited slice of the query stack\n" -> "" +// normalize-stderr-test "end of query stack\n" -> "" #[macro_use] extern crate test_macros; diff --git a/src/test/ui/proc-macro/load-panic-backtrace.stderr b/src/test/ui/proc-macro/load-panic-backtrace.stderr index 63378b5735a..f825047e331 100644 --- a/src/test/ui/proc-macro/load-panic-backtrace.stderr +++ b/src/test/ui/proc-macro/load-panic-backtrace.stderr @@ -1,6 +1,6 @@ at 'panic-derive', $DIR/auxiliary/test-macros.rs:43:5 error: proc-macro derive panicked - --> $DIR/load-panic-backtrace.rs:17:10 + --> $DIR/load-panic-backtrace.rs:20:10 | LL | #[derive(Panic)] | ^^^^^ diff --git a/src/test/ui/proc-macro/span-preservation.stderr b/src/test/ui/proc-macro/span-preservation.stderr index 70e992a4f70..4064c5b3819 100644 --- a/src/test/ui/proc-macro/span-preservation.stderr +++ b/src/test/ui/proc-macro/span-preservation.stderr @@ -15,7 +15,7 @@ LL | match x { LL | Some(x) => { return x }, | ^ expected `usize`, found `isize` | -help: you can convert an `isize` to `usize` and panic if the converted value wouldn't fit +help: you can convert an `isize` to a `usize` and panic if the converted value doesn't fit | LL | Some(x) => { return x.try_into().unwrap() }, | ^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/reject-specialized-drops-8142.stderr b/src/test/ui/reject-specialized-drops-8142.stderr index f819faa2789..eac24617533 100644 --- a/src/test/ui/reject-specialized-drops-8142.stderr +++ b/src/test/ui/reject-specialized-drops-8142.stderr @@ -1,15 +1,3 @@ -error[E0367]: `Drop` impl requires `AddsBnd: Bound` but the union it is implemented for does not - --> $DIR/reject-specialized-drops-8142.rs:67:21 - | -LL | impl<AddsBnd:Copy + Bound> Drop for Union<AddsBnd> { fn drop(&mut self) { } } // REJECT - | ^^^^^ - | -note: the implementor must specify the same requirement - --> $DIR/reject-specialized-drops-8142.rs:21:1 - | -LL | union Union<T: Copy> { f: T } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - error[E0367]: `Drop` impl requires `'adds_bnd: 'al` but the struct it is implemented for does not --> $DIR/reject-specialized-drops-8142.rs:23:20 | @@ -145,6 +133,18 @@ note: the implementor must specify the same requirement LL | struct TupleStruct<T>(T); | ^^^^^^^^^^^^^^^^^^^^^^^^^ +error[E0367]: `Drop` impl requires `AddsBnd: Bound` but the union it is implemented for does not + --> $DIR/reject-specialized-drops-8142.rs:67:21 + | +LL | impl<AddsBnd:Copy + Bound> Drop for Union<AddsBnd> { fn drop(&mut self) { } } // REJECT + | ^^^^^ + | +note: the implementor must specify the same requirement + --> $DIR/reject-specialized-drops-8142.rs:21:1 + | +LL | union Union<T: Copy> { f: T } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + error: aborting due to 11 previous errors Some errors have detailed explanations: E0308, E0366, E0367, E0495. diff --git a/src/test/ui/resolve/issue-65035-static-with-parent-generics.stderr b/src/test/ui/resolve/issue-65035-static-with-parent-generics.stderr index 7f8151db06f..5de8eb21582 100644 --- a/src/test/ui/resolve/issue-65035-static-with-parent-generics.stderr +++ b/src/test/ui/resolve/issue-65035-static-with-parent-generics.stderr @@ -48,6 +48,7 @@ LL | #![feature(const_generics)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information + = help: consider using `min_const_generics` instead, which is more stable and complete error: aborting due to 5 previous errors; 1 warning emitted diff --git a/src/test/ui/resolve/privacy-enum-ctor.stderr b/src/test/ui/resolve/privacy-enum-ctor.stderr index 77429f800f1..807dadf417b 100644 --- a/src/test/ui/resolve/privacy-enum-ctor.stderr +++ b/src/test/ui/resolve/privacy-enum-ctor.stderr @@ -2,17 +2,57 @@ error[E0423]: expected value, found enum `n::Z` --> $DIR/privacy-enum-ctor.rs:23:9 | LL | n::Z; - | ^^^^ help: try using one of the enum's variants: `m::Z::Unit` + | ^^^^ | - = help: you might have meant to use one of the enum's other variants that have fields +note: the enum is defined here + --> $DIR/privacy-enum-ctor.rs:11:9 + | +LL | / pub(in m) enum Z { +LL | | Fn(u8), +LL | | Struct { +LL | | s: u8, +LL | | }, +LL | | Unit, +LL | | } + | |_________^ +help: you might have meant to use the following enum variant + | +LL | m::Z::Unit; + | ^^^^^^^^^^ +help: the following enum variants are available + | +LL | (m::Z::Fn(/* fields */)); + | ^^^^^^^^^^^^^^^^^^^^^^^^ +LL | (m::Z::Struct { /* fields */ }); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0423]: expected value, found enum `Z` --> $DIR/privacy-enum-ctor.rs:25:9 | LL | Z; - | ^ help: try using one of the enum's variants: `m::Z::Unit` + | ^ + | +note: the enum is defined here + --> $DIR/privacy-enum-ctor.rs:11:9 | - = help: you might have meant to use one of the enum's other variants that have fields +LL | / pub(in m) enum Z { +LL | | Fn(u8), +LL | | Struct { +LL | | s: u8, +LL | | }, +LL | | Unit, +LL | | } + | |_________^ +help: you might have meant to use the following enum variant + | +LL | m::Z::Unit; + | ^^^^^^^^^^ +help: the following enum variants are available + | +LL | (m::Z::Fn(/* fields */)); + | ^^^^^^^^^^^^^^^^^^^^^^^^ +LL | (m::Z::Struct { /* fields */ }); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0423]: expected value, found struct variant `Z::Struct` --> $DIR/privacy-enum-ctor.rs:29:20 @@ -34,11 +74,27 @@ LL | fn f() { LL | let _: E = m::E; | ^^^^ | - = help: you might have meant to use one of the enum's other variants that have fields -help: try using one of the enum's variants +note: the enum is defined here + --> $DIR/privacy-enum-ctor.rs:2:5 + | +LL | / pub enum E { +LL | | Fn(u8), +LL | | Struct { +LL | | s: u8, +LL | | }, +LL | | Unit, +LL | | } + | |_____^ +help: you might have meant to use the following enum variant | LL | let _: E = E::Unit; | ^^^^^^^ +help: the following enum variants are available + | +LL | let _: E = (E::Fn(/* fields */)); + | ^^^^^^^^^^^^^^^^^^^^^ +LL | let _: E = (E::Struct { /* fields */ }); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: a function with a similar name exists | LL | let _: E = m::f; @@ -67,11 +123,27 @@ error[E0423]: expected value, found enum `E` LL | let _: E = E; | ^ | - = help: you might have meant to use one of the enum's other variants that have fields -help: try using one of the enum's variants +note: the enum is defined here + --> $DIR/privacy-enum-ctor.rs:2:5 + | +LL | / pub enum E { +LL | | Fn(u8), +LL | | Struct { +LL | | s: u8, +LL | | }, +LL | | Unit, +LL | | } + | |_____^ +help: you might have meant to use the following enum variant | LL | let _: E = E::Unit; | ^^^^^^^ +help: the following enum variants are available + | +LL | let _: E = (E::Fn(/* fields */)); + | ^^^^^^^^^^^^^^^^^^^^^ +LL | let _: E = (E::Struct { /* fields */ }); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider importing one of these items instead | LL | use std::f32::consts::E; @@ -112,9 +184,29 @@ error[E0423]: expected value, found enum `m::n::Z` --> $DIR/privacy-enum-ctor.rs:57:16 | LL | let _: Z = m::n::Z; - | ^^^^^^^ help: try using one of the enum's variants: `m::Z::Unit` + | ^^^^^^^ + | +note: the enum is defined here + --> $DIR/privacy-enum-ctor.rs:11:9 + | +LL | / pub(in m) enum Z { +LL | | Fn(u8), +LL | | Struct { +LL | | s: u8, +LL | | }, +LL | | Unit, +LL | | } + | |_________^ +help: you might have meant to use the following enum variant + | +LL | let _: Z = m::Z::Unit; + | ^^^^^^^^^^ +help: the following enum variants are available | - = help: you might have meant to use one of the enum's other variants that have fields +LL | let _: Z = (m::Z::Fn(/* fields */)); + | ^^^^^^^^^^^^^^^^^^^^^^^^ +LL | let _: Z = (m::Z::Struct { /* fields */ }); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0412]: cannot find type `Z` in this scope --> $DIR/privacy-enum-ctor.rs:61:12 diff --git a/src/test/ui/rfc-2005-default-binding-mode/for.rs b/src/test/ui/rfc-2005-default-binding-mode/for.rs index aa42c7bb9c2..d6c5a13b1bd 100644 --- a/src/test/ui/rfc-2005-default-binding-mode/for.rs +++ b/src/test/ui/rfc-2005-default-binding-mode/for.rs @@ -1,5 +1,3 @@ -#![feature(move_ref_pattern)] - struct Foo {} pub fn main() { diff --git a/src/test/ui/rfc-2005-default-binding-mode/for.stderr b/src/test/ui/rfc-2005-default-binding-mode/for.stderr index ef624313880..9cc20a7bf31 100644 --- a/src/test/ui/rfc-2005-default-binding-mode/for.stderr +++ b/src/test/ui/rfc-2005-default-binding-mode/for.stderr @@ -1,5 +1,5 @@ error[E0507]: cannot move out of a shared reference - --> $DIR/for.rs:8:23 + --> $DIR/for.rs:6:23 | LL | for (n, mut m) in &tups { | ----- ^^^^^ diff --git a/src/test/ui/rfc-2126-extern-absolute-paths/meta.rs b/src/test/ui/rfc-2126-extern-absolute-paths/meta.rs deleted file mode 100644 index 1fb5878ca2a..00000000000 --- a/src/test/ui/rfc-2126-extern-absolute-paths/meta.rs +++ /dev/null @@ -1,7 +0,0 @@ -// edition:2018 - -// Tests that `meta` is allowed, even if the crate doesn't exist -// yet (i.e., it causes a different error than `not-allowed.rs`). -use meta; //~ ERROR can't find crate for `meta` - -fn main() {} diff --git a/src/test/ui/rfc-2126-extern-absolute-paths/meta.stderr b/src/test/ui/rfc-2126-extern-absolute-paths/meta.stderr deleted file mode 100644 index eb4b9dea41b..00000000000 --- a/src/test/ui/rfc-2126-extern-absolute-paths/meta.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0463]: can't find crate for `meta` - --> $DIR/meta.rs:5:5 - | -LL | use meta; - | ^^^^ can't find crate - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0463`. diff --git a/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr b/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr index d38a3aba46f..bd39650702c 100644 --- a/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr +++ b/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr @@ -507,6 +507,7 @@ LL | #![feature(const_generics)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information + = help: consider using `min_const_generics` instead, which is more stable and complete warning: the feature `let_chains` is incomplete and may not be safe to use and/or cause compiler crashes --> $DIR/disallowed-positions.rs:22:12 diff --git a/src/test/ui/self/self-in-typedefs.rs b/src/test/ui/self/self-in-typedefs.rs index 3b1eb9e1dfa..81e557d53a6 100644 --- a/src/test/ui/self/self-in-typedefs.rs +++ b/src/test/ui/self/self-in-typedefs.rs @@ -1,7 +1,4 @@ // build-pass (FIXME(62277): could be check-pass?) - -#![feature(untagged_unions)] - #![allow(dead_code)] use std::mem::ManuallyDrop; diff --git a/src/test/ui/shift-various-bad-types.stderr b/src/test/ui/shift-various-bad-types.stderr index c27bdf09a8d..63b70f7fcd9 100644 --- a/src/test/ui/shift-various-bad-types.stderr +++ b/src/test/ui/shift-various-bad-types.stderr @@ -30,7 +30,7 @@ LL | let _: i32 = 22_i64 >> 1_i32; | | | expected due to this | -help: you can convert an `i64` to `i32` and panic if the converted value wouldn't fit +help: you can convert an `i64` to an `i32` and panic if the converted value doesn't fit | LL | let _: i32 = (22_i64 >> 1_i32).try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/span/issue-34264.stderr b/src/test/ui/span/issue-34264.stderr index 40c3219bf27..5cda17fd6a1 100644 --- a/src/test/ui/span/issue-34264.stderr +++ b/src/test/ui/span/issue-34264.stderr @@ -53,13 +53,16 @@ LL | fn bar(_: x, y: usize) {} error[E0061]: this function takes 2 arguments but 3 arguments were supplied --> $DIR/issue-34264.rs:7:5 | -LL | fn foo(Option<i32>, String) {} - | --------------------------- defined here -... LL | foo(Some(42), 2, ""); | ^^^ -------- - -- supplied 3 arguments | | | expected 2 arguments + | +note: function defined here + --> $DIR/issue-34264.rs:1:4 + | +LL | fn foo(Option<i32>, String) {} + | ^^^ ----------- ------ error[E0308]: mismatched types --> $DIR/issue-34264.rs:8:13 @@ -70,13 +73,16 @@ LL | bar("", ""); error[E0061]: this function takes 2 arguments but 3 arguments were supplied --> $DIR/issue-34264.rs:10:5 | -LL | fn bar(x, y: usize) {} - | ------------------- defined here -... LL | bar(1, 2, 3); | ^^^ - - - supplied 3 arguments | | | expected 2 arguments + | +note: function defined here + --> $DIR/issue-34264.rs:3:4 + | +LL | fn bar(x, y: usize) {} + | ^^^ - -------- error: aborting due to 6 previous errors diff --git a/src/test/ui/span/missing-unit-argument.stderr b/src/test/ui/span/missing-unit-argument.stderr index f6344fba3d3..b15da2cb479 100644 --- a/src/test/ui/span/missing-unit-argument.stderr +++ b/src/test/ui/span/missing-unit-argument.stderr @@ -12,34 +12,42 @@ LL | let _: Result<(), String> = Ok(()); error[E0061]: this function takes 2 arguments but 0 arguments were supplied --> $DIR/missing-unit-argument.rs:12:5 | -LL | fn foo(():(), ():()) {} - | -------------------- defined here -... LL | foo(); | ^^^-- supplied 0 arguments | | | expected 2 arguments + | +note: function defined here + --> $DIR/missing-unit-argument.rs:1:4 + | +LL | fn foo(():(), ():()) {} + | ^^^ ----- ----- error[E0061]: this function takes 2 arguments but 1 argument was supplied --> $DIR/missing-unit-argument.rs:13:5 | -LL | fn foo(():(), ():()) {} - | -------------------- defined here -... LL | foo(()); | ^^^ -- supplied 1 argument | | | expected 2 arguments + | +note: function defined here + --> $DIR/missing-unit-argument.rs:1:4 + | +LL | fn foo(():(), ():()) {} + | ^^^ ----- ----- error[E0061]: this function takes 1 argument but 0 arguments were supplied --> $DIR/missing-unit-argument.rs:14:5 | -LL | fn bar(():()) {} - | ------------- defined here -... LL | bar(); | ^^^-- supplied 0 arguments | +note: function defined here + --> $DIR/missing-unit-argument.rs:2:4 + | +LL | fn bar(():()) {} + | ^^^ ----- help: expected the unit value `()`; create it with empty parentheses | LL | bar(()); @@ -48,12 +56,14 @@ LL | bar(()); error[E0061]: this function takes 1 argument but 0 arguments were supplied --> $DIR/missing-unit-argument.rs:15:7 | -LL | fn baz(self, (): ()) { } - | -------------------- defined here -... LL | S.baz(); | ^^^- supplied 0 arguments | +note: associated function defined here + --> $DIR/missing-unit-argument.rs:6:8 + | +LL | fn baz(self, (): ()) { } + | ^^^ ---- ------ help: expected the unit value `()`; create it with empty parentheses | LL | S.baz(()); @@ -62,12 +72,14 @@ LL | S.baz(()); error[E0061]: this function takes 1 argument but 0 arguments were supplied --> $DIR/missing-unit-argument.rs:16:7 | -LL | fn generic<T>(self, _: T) { } - | ------------------------- defined here -... LL | S.generic::<()>(); | ^^^^^^^------ supplied 0 arguments | +note: associated function defined here + --> $DIR/missing-unit-argument.rs:7:8 + | +LL | fn generic<T>(self, _: T) { } + | ^^^^^^^ ---- ---- help: expected the unit value `()`; create it with empty parentheses | LL | S.generic::<()>(()); diff --git a/src/test/ui/specialization/assoc-ty-graph-cycle.stderr b/src/test/ui/specialization/assoc-ty-graph-cycle.stderr index 250f48f8e59..17da34caa70 100644 --- a/src/test/ui/specialization/assoc-ty-graph-cycle.stderr +++ b/src/test/ui/specialization/assoc-ty-graph-cycle.stderr @@ -6,6 +6,7 @@ LL | #![feature(specialization)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete warning: 1 warning emitted diff --git a/src/test/ui/specialization/cross-crate-defaults.stderr b/src/test/ui/specialization/cross-crate-defaults.stderr index f18bc99d739..e368c2e73b6 100644 --- a/src/test/ui/specialization/cross-crate-defaults.stderr +++ b/src/test/ui/specialization/cross-crate-defaults.stderr @@ -6,6 +6,7 @@ LL | #![feature(specialization)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete warning: 1 warning emitted diff --git a/src/test/ui/specialization/deafult-associated-type-bound-1.stderr b/src/test/ui/specialization/deafult-associated-type-bound-1.stderr index 337972ea2b7..4ca3d831198 100644 --- a/src/test/ui/specialization/deafult-associated-type-bound-1.stderr +++ b/src/test/ui/specialization/deafult-associated-type-bound-1.stderr @@ -6,6 +6,7 @@ LL | #![feature(specialization)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete error[E0277]: the trait bound `str: Clone` is not satisfied --> $DIR/deafult-associated-type-bound-1.rs:19:5 diff --git a/src/test/ui/specialization/deafult-associated-type-bound-2.stderr b/src/test/ui/specialization/deafult-associated-type-bound-2.stderr index 8c9da81d277..2bc14dbe3b2 100644 --- a/src/test/ui/specialization/deafult-associated-type-bound-2.stderr +++ b/src/test/ui/specialization/deafult-associated-type-bound-2.stderr @@ -6,6 +6,7 @@ LL | #![feature(specialization)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete error[E0277]: can't compare `&'static B` with `B` --> $DIR/deafult-associated-type-bound-2.rs:16:5 diff --git a/src/test/ui/specialization/deafult-generic-associated-type-bound.stderr b/src/test/ui/specialization/deafult-generic-associated-type-bound.stderr index f145b90f216..b5a1877ea19 100644 --- a/src/test/ui/specialization/deafult-generic-associated-type-bound.stderr +++ b/src/test/ui/specialization/deafult-generic-associated-type-bound.stderr @@ -6,6 +6,7 @@ LL | #![feature(specialization)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes --> $DIR/deafult-generic-associated-type-bound.rs:4:12 diff --git a/src/test/ui/specialization/defaultimpl/allowed-cross-crate.stderr b/src/test/ui/specialization/defaultimpl/allowed-cross-crate.stderr index 1b50329719d..d8b9c48c72e 100644 --- a/src/test/ui/specialization/defaultimpl/allowed-cross-crate.stderr +++ b/src/test/ui/specialization/defaultimpl/allowed-cross-crate.stderr @@ -6,6 +6,7 @@ LL | #![feature(specialization)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete warning: 1 warning emitted diff --git a/src/test/ui/specialization/defaultimpl/out-of-order.stderr b/src/test/ui/specialization/defaultimpl/out-of-order.stderr index deae021a891..9ca915686e8 100644 --- a/src/test/ui/specialization/defaultimpl/out-of-order.stderr +++ b/src/test/ui/specialization/defaultimpl/out-of-order.stderr @@ -6,6 +6,7 @@ LL | #![feature(specialization)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete warning: 1 warning emitted diff --git a/src/test/ui/specialization/defaultimpl/overlap-projection.stderr b/src/test/ui/specialization/defaultimpl/overlap-projection.stderr index 46899ca9954..31d0e6e3882 100644 --- a/src/test/ui/specialization/defaultimpl/overlap-projection.stderr +++ b/src/test/ui/specialization/defaultimpl/overlap-projection.stderr @@ -6,6 +6,7 @@ LL | #![feature(specialization)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete warning: 1 warning emitted diff --git a/src/test/ui/specialization/defaultimpl/projection.stderr b/src/test/ui/specialization/defaultimpl/projection.stderr index 8629c6c52d4..2d5c80d05f0 100644 --- a/src/test/ui/specialization/defaultimpl/projection.stderr +++ b/src/test/ui/specialization/defaultimpl/projection.stderr @@ -6,6 +6,7 @@ LL | #![feature(specialization)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete warning: 1 warning emitted diff --git a/src/test/ui/specialization/defaultimpl/specialization-no-default.stderr b/src/test/ui/specialization/defaultimpl/specialization-no-default.stderr index 7958eddbeba..3f1a5495e21 100644 --- a/src/test/ui/specialization/defaultimpl/specialization-no-default.stderr +++ b/src/test/ui/specialization/defaultimpl/specialization-no-default.stderr @@ -6,6 +6,7 @@ LL | #![feature(specialization)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete error[E0520]: `foo` specializes an item from a parent `impl`, but that item is not marked `default` --> $DIR/specialization-no-default.rs:20:5 diff --git a/src/test/ui/specialization/defaultimpl/specialization-trait-item-not-implemented-rpass.stderr b/src/test/ui/specialization/defaultimpl/specialization-trait-item-not-implemented-rpass.stderr index dc377dd10c8..163c93550fb 100644 --- a/src/test/ui/specialization/defaultimpl/specialization-trait-item-not-implemented-rpass.stderr +++ b/src/test/ui/specialization/defaultimpl/specialization-trait-item-not-implemented-rpass.stderr @@ -6,6 +6,7 @@ LL | #![feature(specialization)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete warning: 1 warning emitted diff --git a/src/test/ui/specialization/defaultimpl/specialization-trait-item-not-implemented.stderr b/src/test/ui/specialization/defaultimpl/specialization-trait-item-not-implemented.stderr index 9d1eca1d6af..250f0017bea 100644 --- a/src/test/ui/specialization/defaultimpl/specialization-trait-item-not-implemented.stderr +++ b/src/test/ui/specialization/defaultimpl/specialization-trait-item-not-implemented.stderr @@ -6,6 +6,7 @@ LL | #![feature(specialization)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete error[E0046]: not all trait items implemented, missing: `foo_two` --> $DIR/specialization-trait-item-not-implemented.rs:18:1 diff --git a/src/test/ui/specialization/defaultimpl/specialization-trait-not-implemented.stderr b/src/test/ui/specialization/defaultimpl/specialization-trait-not-implemented.stderr index 6b8e559bc36..fb623c97f42 100644 --- a/src/test/ui/specialization/defaultimpl/specialization-trait-not-implemented.stderr +++ b/src/test/ui/specialization/defaultimpl/specialization-trait-not-implemented.stderr @@ -6,6 +6,7 @@ LL | #![feature(specialization)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete error[E0599]: no method named `foo_one` found for struct `MyStruct` in the current scope --> $DIR/specialization-trait-not-implemented.rs:22:29 diff --git a/src/test/ui/specialization/defaultimpl/specialization-wfcheck.stderr b/src/test/ui/specialization/defaultimpl/specialization-wfcheck.stderr index dcac310ed06..57b90c457cb 100644 --- a/src/test/ui/specialization/defaultimpl/specialization-wfcheck.stderr +++ b/src/test/ui/specialization/defaultimpl/specialization-wfcheck.stderr @@ -6,6 +6,7 @@ LL | #![feature(specialization)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete error[E0277]: the trait bound `U: Eq` is not satisfied --> $DIR/specialization-wfcheck.rs:7:17 diff --git a/src/test/ui/specialization/defaultimpl/validation.stderr b/src/test/ui/specialization/defaultimpl/validation.stderr index 2449849725f..cbf0cef5e74 100644 --- a/src/test/ui/specialization/defaultimpl/validation.stderr +++ b/src/test/ui/specialization/defaultimpl/validation.stderr @@ -16,6 +16,7 @@ LL | #![feature(specialization)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete error: impls of auto traits cannot be default --> $DIR/validation.rs:9:21 diff --git a/src/test/ui/specialization/issue-36804.stderr b/src/test/ui/specialization/issue-36804.stderr index 744d8820424..783a38e6bdc 100644 --- a/src/test/ui/specialization/issue-36804.stderr +++ b/src/test/ui/specialization/issue-36804.stderr @@ -6,6 +6,7 @@ LL | #![feature(specialization)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete warning: 1 warning emitted diff --git a/src/test/ui/specialization/issue-38091-2.stderr b/src/test/ui/specialization/issue-38091-2.stderr index a314c26ad14..bd5ed498d92 100644 --- a/src/test/ui/specialization/issue-38091-2.stderr +++ b/src/test/ui/specialization/issue-38091-2.stderr @@ -6,6 +6,7 @@ LL | #![feature(specialization)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete error[E0275]: overflow evaluating the requirement `i32: Check` | diff --git a/src/test/ui/specialization/issue-38091.stderr b/src/test/ui/specialization/issue-38091.stderr index 6be0f26849f..97e5775ab54 100644 --- a/src/test/ui/specialization/issue-38091.stderr +++ b/src/test/ui/specialization/issue-38091.stderr @@ -6,6 +6,7 @@ LL | #![feature(specialization)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete error[E0277]: the trait bound `(): Valid` is not satisfied --> $DIR/issue-38091.rs:12:5 diff --git a/src/test/ui/specialization/issue-39448.stderr b/src/test/ui/specialization/issue-39448.stderr index f3bb69b8f71..98e49b1bab3 100644 --- a/src/test/ui/specialization/issue-39448.stderr +++ b/src/test/ui/specialization/issue-39448.stderr @@ -6,6 +6,7 @@ LL | #![feature(specialization)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete error[E0275]: overflow evaluating the requirement `T: FromA<U>` --> $DIR/issue-39448.rs:45:13 diff --git a/src/test/ui/specialization/issue-39618.stderr b/src/test/ui/specialization/issue-39618.stderr index d40d17d8f71..77a45806edb 100644 --- a/src/test/ui/specialization/issue-39618.stderr +++ b/src/test/ui/specialization/issue-39618.stderr @@ -6,6 +6,7 @@ LL | #![feature(specialization)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete warning: 1 warning emitted diff --git a/src/test/ui/specialization/issue-50452.stderr b/src/test/ui/specialization/issue-50452.stderr index c01817e0b27..2f05c41346f 100644 --- a/src/test/ui/specialization/issue-50452.stderr +++ b/src/test/ui/specialization/issue-50452.stderr @@ -6,6 +6,7 @@ LL | #![feature(specialization)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete warning: 1 warning emitted diff --git a/src/test/ui/specialization/issue-52050.stderr b/src/test/ui/specialization/issue-52050.stderr index a7564ced055..27070f8e4a1 100644 --- a/src/test/ui/specialization/issue-52050.stderr +++ b/src/test/ui/specialization/issue-52050.stderr @@ -6,6 +6,7 @@ LL | #![feature(specialization)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete error[E0119]: conflicting implementations of trait `IntoPyDictPointer` for type `()`: --> $DIR/issue-52050.rs:28:1 diff --git a/src/test/ui/specialization/issue-63716-parse-async.stderr b/src/test/ui/specialization/issue-63716-parse-async.stderr index 43620e1ba51..cde17872d6b 100644 --- a/src/test/ui/specialization/issue-63716-parse-async.stderr +++ b/src/test/ui/specialization/issue-63716-parse-async.stderr @@ -6,6 +6,7 @@ LL | #![feature(specialization)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete warning: 1 warning emitted diff --git a/src/test/ui/specialization/issue-70442.stderr b/src/test/ui/specialization/issue-70442.stderr index f71e4c7dd1c..5ee82e9915b 100644 --- a/src/test/ui/specialization/issue-70442.stderr +++ b/src/test/ui/specialization/issue-70442.stderr @@ -6,6 +6,7 @@ LL | #![feature(specialization)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete warning: 1 warning emitted diff --git a/src/test/ui/specialization/non-defaulted-item-fail.stderr b/src/test/ui/specialization/non-defaulted-item-fail.stderr index eae045b92c0..85ccbd809b0 100644 --- a/src/test/ui/specialization/non-defaulted-item-fail.stderr +++ b/src/test/ui/specialization/non-defaulted-item-fail.stderr @@ -6,6 +6,7 @@ LL | #![feature(specialization, associated_type_defaults)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete error[E0520]: `Ty` specializes an item from a parent `impl`, but that item is not marked `default` --> $DIR/non-defaulted-item-fail.rs:30:5 diff --git a/src/test/ui/specialization/specialization-allowed-cross-crate.stderr b/src/test/ui/specialization/specialization-allowed-cross-crate.stderr index 7d087545725..9605bd08935 100644 --- a/src/test/ui/specialization/specialization-allowed-cross-crate.stderr +++ b/src/test/ui/specialization/specialization-allowed-cross-crate.stderr @@ -6,6 +6,7 @@ LL | #![feature(specialization)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete warning: 1 warning emitted diff --git a/src/test/ui/specialization/specialization-assoc-fns.stderr b/src/test/ui/specialization/specialization-assoc-fns.stderr index b12738604ea..a7c0661a825 100644 --- a/src/test/ui/specialization/specialization-assoc-fns.stderr +++ b/src/test/ui/specialization/specialization-assoc-fns.stderr @@ -6,6 +6,7 @@ LL | #![feature(specialization)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete warning: 1 warning emitted diff --git a/src/test/ui/specialization/specialization-basics.stderr b/src/test/ui/specialization/specialization-basics.stderr index ad00cd81df1..afb2af3803f 100644 --- a/src/test/ui/specialization/specialization-basics.stderr +++ b/src/test/ui/specialization/specialization-basics.stderr @@ -6,6 +6,7 @@ LL | #![feature(specialization)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete warning: 1 warning emitted diff --git a/src/test/ui/specialization/specialization-cross-crate.stderr b/src/test/ui/specialization/specialization-cross-crate.stderr index 7481eed796d..c69130c0aef 100644 --- a/src/test/ui/specialization/specialization-cross-crate.stderr +++ b/src/test/ui/specialization/specialization-cross-crate.stderr @@ -6,6 +6,7 @@ LL | #![feature(specialization)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete warning: 1 warning emitted diff --git a/src/test/ui/specialization/specialization-default-methods.stderr b/src/test/ui/specialization/specialization-default-methods.stderr index 4fa19adad06..ef6365ed31f 100644 --- a/src/test/ui/specialization/specialization-default-methods.stderr +++ b/src/test/ui/specialization/specialization-default-methods.stderr @@ -6,6 +6,7 @@ LL | #![feature(specialization)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete warning: 1 warning emitted diff --git a/src/test/ui/specialization/specialization-default-projection.stderr b/src/test/ui/specialization/specialization-default-projection.stderr index 456eb6d5ca5..445bc1646f0 100644 --- a/src/test/ui/specialization/specialization-default-projection.stderr +++ b/src/test/ui/specialization/specialization-default-projection.stderr @@ -6,6 +6,7 @@ LL | #![feature(specialization)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete error[E0308]: mismatched types --> $DIR/specialization-default-projection.rs:21:5 diff --git a/src/test/ui/specialization/specialization-default-types.stderr b/src/test/ui/specialization/specialization-default-types.stderr index 5acfb53e206..5ba38facee0 100644 --- a/src/test/ui/specialization/specialization-default-types.stderr +++ b/src/test/ui/specialization/specialization-default-types.stderr @@ -6,6 +6,7 @@ LL | #![feature(specialization)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete error[E0308]: mismatched types --> $DIR/specialization-default-types.rs:15:9 diff --git a/src/test/ui/specialization/specialization-no-default.stderr b/src/test/ui/specialization/specialization-no-default.stderr index bb8b2a6c98e..711c1fda149 100644 --- a/src/test/ui/specialization/specialization-no-default.stderr +++ b/src/test/ui/specialization/specialization-no-default.stderr @@ -6,6 +6,7 @@ LL | #![feature(specialization)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete error[E0520]: `foo` specializes an item from a parent `impl`, but that item is not marked `default` --> $DIR/specialization-no-default.rs:20:5 diff --git a/src/test/ui/specialization/specialization-on-projection.stderr b/src/test/ui/specialization/specialization-on-projection.stderr index d91668d10c5..d051ffe0a02 100644 --- a/src/test/ui/specialization/specialization-on-projection.stderr +++ b/src/test/ui/specialization/specialization-on-projection.stderr @@ -6,6 +6,7 @@ LL | #![feature(specialization)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete warning: 1 warning emitted diff --git a/src/test/ui/specialization/specialization-out-of-order.stderr b/src/test/ui/specialization/specialization-out-of-order.stderr index a17f9f11a3f..785ec29239b 100644 --- a/src/test/ui/specialization/specialization-out-of-order.stderr +++ b/src/test/ui/specialization/specialization-out-of-order.stderr @@ -6,6 +6,7 @@ LL | #![feature(specialization)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete warning: 1 warning emitted diff --git a/src/test/ui/specialization/specialization-overlap-negative.stderr b/src/test/ui/specialization/specialization-overlap-negative.stderr index 6141174ba8c..552b04a6019 100644 --- a/src/test/ui/specialization/specialization-overlap-negative.stderr +++ b/src/test/ui/specialization/specialization-overlap-negative.stderr @@ -6,6 +6,7 @@ LL | #![feature(specialization)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete error[E0751]: found both positive and negative implementation of trait `std::marker::Send` for type `TestType<_>`: --> $DIR/specialization-overlap-negative.rs:9:1 diff --git a/src/test/ui/specialization/specialization-overlap-projection.stderr b/src/test/ui/specialization/specialization-overlap-projection.stderr index 6f1a594bacb..c92db73074d 100644 --- a/src/test/ui/specialization/specialization-overlap-projection.stderr +++ b/src/test/ui/specialization/specialization-overlap-projection.stderr @@ -6,6 +6,7 @@ LL | #![feature(specialization)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete warning: 1 warning emitted diff --git a/src/test/ui/specialization/specialization-overlap.stderr b/src/test/ui/specialization/specialization-overlap.stderr index cf0f186a183..7e5c96ac1c8 100644 --- a/src/test/ui/specialization/specialization-overlap.stderr +++ b/src/test/ui/specialization/specialization-overlap.stderr @@ -6,6 +6,7 @@ LL | #![feature(specialization)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete error[E0119]: conflicting implementations of trait `Foo` for type `std::vec::Vec<_>`: --> $DIR/specialization-overlap.rs:5:1 diff --git a/src/test/ui/specialization/specialization-polarity.stderr b/src/test/ui/specialization/specialization-polarity.stderr index c44af22b8e6..be013552f5d 100644 --- a/src/test/ui/specialization/specialization-polarity.stderr +++ b/src/test/ui/specialization/specialization-polarity.stderr @@ -6,6 +6,7 @@ LL | #![feature(specialization)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete error[E0751]: found both positive and negative implementation of trait `Foo` for type `u8`: --> $DIR/specialization-polarity.rs:10:1 diff --git a/src/test/ui/specialization/specialization-projection-alias.stderr b/src/test/ui/specialization/specialization-projection-alias.stderr index 0c3659a8f7a..6d2bca5d2df 100644 --- a/src/test/ui/specialization/specialization-projection-alias.stderr +++ b/src/test/ui/specialization/specialization-projection-alias.stderr @@ -6,6 +6,7 @@ LL | #![feature(specialization)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete warning: 1 warning emitted diff --git a/src/test/ui/specialization/specialization-projection.stderr b/src/test/ui/specialization/specialization-projection.stderr index c5c86f5108e..0f1ecf5e379 100644 --- a/src/test/ui/specialization/specialization-projection.stderr +++ b/src/test/ui/specialization/specialization-projection.stderr @@ -6,6 +6,7 @@ LL | #![feature(specialization)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete warning: 1 warning emitted diff --git a/src/test/ui/specialization/specialization-super-traits.stderr b/src/test/ui/specialization/specialization-super-traits.stderr index 05bdfd40136..165703d6365 100644 --- a/src/test/ui/specialization/specialization-super-traits.stderr +++ b/src/test/ui/specialization/specialization-super-traits.stderr @@ -6,6 +6,7 @@ LL | #![feature(specialization)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete warning: 1 warning emitted diff --git a/src/test/ui/specialization/specialization-translate-projections-with-lifetimes.stderr b/src/test/ui/specialization/specialization-translate-projections-with-lifetimes.stderr index 6284dd8f3f7..d30f7af2cbd 100644 --- a/src/test/ui/specialization/specialization-translate-projections-with-lifetimes.stderr +++ b/src/test/ui/specialization/specialization-translate-projections-with-lifetimes.stderr @@ -6,6 +6,7 @@ LL | #![feature(specialization)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete warning: 1 warning emitted diff --git a/src/test/ui/specialization/specialization-translate-projections-with-params.stderr b/src/test/ui/specialization/specialization-translate-projections-with-params.stderr index b17794173c5..1762248f695 100644 --- a/src/test/ui/specialization/specialization-translate-projections-with-params.stderr +++ b/src/test/ui/specialization/specialization-translate-projections-with-params.stderr @@ -6,6 +6,7 @@ LL | #![feature(specialization)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete warning: 1 warning emitted diff --git a/src/test/ui/specialization/specialization-translate-projections.stderr b/src/test/ui/specialization/specialization-translate-projections.stderr index fbb28e60640..94a0e79dd56 100644 --- a/src/test/ui/specialization/specialization-translate-projections.stderr +++ b/src/test/ui/specialization/specialization-translate-projections.stderr @@ -6,6 +6,7 @@ LL | #![feature(specialization)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete warning: 1 warning emitted diff --git a/src/test/ui/suggestions/mut-borrow-needed-by-trait.stderr b/src/test/ui/suggestions/mut-borrow-needed-by-trait.stderr index c1eea56f70d..8a9a1e57935 100644 --- a/src/test/ui/suggestions/mut-borrow-needed-by-trait.stderr +++ b/src/test/ui/suggestions/mut-borrow-needed-by-trait.stderr @@ -13,7 +13,7 @@ error[E0277]: the trait bound `&dyn std::io::Write: std::io::Write` is not satis LL | let fp = BufWriter::new(fp); | ^^^^^^^^^^^^^^ the trait `std::io::Write` is not implemented for `&dyn std::io::Write` | - ::: $SRC_DIR/std/src/io/buffered.rs:LL:COL + ::: $SRC_DIR/std/src/io/buffered/bufwriter.rs:LL:COL | LL | pub struct BufWriter<W: Write> { | ----- required by this bound in `BufWriter` @@ -26,7 +26,7 @@ error[E0277]: the trait bound `&dyn std::io::Write: std::io::Write` is not satis LL | let fp = BufWriter::new(fp); | ^^^^^^^^^^^^^^^^^^ the trait `std::io::Write` is not implemented for `&dyn std::io::Write` | - ::: $SRC_DIR/std/src/io/buffered.rs:LL:COL + ::: $SRC_DIR/std/src/io/buffered/bufwriter.rs:LL:COL | LL | pub struct BufWriter<W: Write> { | ----- required by this bound in `BufWriter` @@ -39,7 +39,7 @@ error[E0599]: no method named `write_fmt` found for struct `BufWriter<&dyn std:: LL | writeln!(fp, "hello world").unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ method not found in `BufWriter<&dyn std::io::Write>` | - ::: $SRC_DIR/std/src/io/buffered.rs:LL:COL + ::: $SRC_DIR/std/src/io/buffered/bufwriter.rs:LL:COL | LL | pub struct BufWriter<W: Write> { | ------------------------------ doesn't satisfy `BufWriter<&dyn std::io::Write>: std::io::Write` diff --git a/src/test/ui/suggestions/type-mismatch-struct-field-shorthand-2.stderr b/src/test/ui/suggestions/type-mismatch-struct-field-shorthand-2.stderr index f717cc7addb..b391cd4beb4 100644 --- a/src/test/ui/suggestions/type-mismatch-struct-field-shorthand-2.stderr +++ b/src/test/ui/suggestions/type-mismatch-struct-field-shorthand-2.stderr @@ -5,7 +5,7 @@ LL | let _ = RGB { r, g, c }; | ^ | | | expected `f64`, found `f32` - | help: you can convert an `f32` to `f64`: `r: r.into()` + | help: you can convert an `f32` to an `f64`: `r: r.into()` error[E0308]: mismatched types --> $DIR/type-mismatch-struct-field-shorthand-2.rs:5:22 @@ -14,7 +14,7 @@ LL | let _ = RGB { r, g, c }; | ^ | | | expected `f64`, found `f32` - | help: you can convert an `f32` to `f64`: `g: g.into()` + | help: you can convert an `f32` to an `f64`: `g: g.into()` error[E0560]: struct `RGB` has no field named `c` --> $DIR/type-mismatch-struct-field-shorthand-2.rs:5:25 diff --git a/src/test/ui/suggestions/type-mismatch-struct-field-shorthand.stderr b/src/test/ui/suggestions/type-mismatch-struct-field-shorthand.stderr index 7521c253545..61ea852a8c4 100644 --- a/src/test/ui/suggestions/type-mismatch-struct-field-shorthand.stderr +++ b/src/test/ui/suggestions/type-mismatch-struct-field-shorthand.stderr @@ -5,7 +5,7 @@ LL | let _ = RGB { r, g, b }; | ^ | | | expected `f64`, found `f32` - | help: you can convert an `f32` to `f64`: `r: r.into()` + | help: you can convert an `f32` to an `f64`: `r: r.into()` error[E0308]: mismatched types --> $DIR/type-mismatch-struct-field-shorthand.rs:8:22 @@ -14,7 +14,7 @@ LL | let _ = RGB { r, g, b }; | ^ | | | expected `f64`, found `f32` - | help: you can convert an `f32` to `f64`: `g: g.into()` + | help: you can convert an `f32` to an `f64`: `g: g.into()` error[E0308]: mismatched types --> $DIR/type-mismatch-struct-field-shorthand.rs:8:25 @@ -23,7 +23,7 @@ LL | let _ = RGB { r, g, b }; | ^ | | | expected `f64`, found `f32` - | help: you can convert an `f32` to `f64`: `b: b.into()` + | help: you can convert an `f32` to an `f64`: `b: b.into()` error: aborting due to 3 previous errors diff --git a/src/test/ui/symbol-names/issue-75326.legacy.stderr b/src/test/ui/symbol-names/issue-75326.legacy.stderr new file mode 100644 index 00000000000..5f822f6660c --- /dev/null +++ b/src/test/ui/symbol-names/issue-75326.legacy.stderr @@ -0,0 +1,20 @@ +error: symbol-name(_ZN72_$LT$issue_75326..Foo$LT$I$C$E$GT$$u20$as$u20$issue_75326..Iterator2$GT$4next17SYMBOL_HASH) + --> $DIR/issue-75326.rs:43:5 + | +LL | #[rustc_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^ + +error: demangling(<issue_75326::Foo<I,E> as issue_75326::Iterator2>::next::SYMBOL_HASH) + --> $DIR/issue-75326.rs:43:5 + | +LL | #[rustc_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^ + +error: demangling-alt(<issue_75326::Foo<I,E> as issue_75326::Iterator2>::next) + --> $DIR/issue-75326.rs:43:5 + | +LL | #[rustc_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 3 previous errors + diff --git a/src/test/ui/symbol-names/issue-75326.rs b/src/test/ui/symbol-names/issue-75326.rs new file mode 100644 index 00000000000..ce315164cef --- /dev/null +++ b/src/test/ui/symbol-names/issue-75326.rs @@ -0,0 +1,58 @@ +// build-fail +// ignore-tidy-linelength +// revisions: legacy v0 +//[legacy]compile-flags: -Z symbol-mangling-version=legacy +//[v0]compile-flags: -Z symbol-mangling-version=v0 +//[legacy]normalize-stderr-32bit: "h[\d\w]+" -> "SYMBOL_HASH" +//[legacy]normalize-stderr-64bit: "h[\d\w]+" -> "SYMBOL_HASH" + +#![feature(rustc_attrs)] + +pub(crate) struct Foo<I, E>(I, E); + +pub trait Iterator2 { + type Item; + + fn next(&mut self) -> Option<Self::Item>; + + fn find<P>(&mut self, predicate: P) -> Option<Self::Item> + where + Self: Sized, + P: FnMut(&Self::Item) -> bool, + { + unimplemented!() + } +} + +struct Bar; + +impl Iterator2 for Bar { + type Item = (u32, u16); + + fn next(&mut self) -> Option<Self::Item> { + unimplemented!() + } +} + +impl<I, T, E> Iterator2 for Foo<I, E> +where + I: Iterator2<Item = (T, E)>, +{ + type Item = T; + + #[rustc_symbol_name] + //[legacy]~^ ERROR symbol-name(_ZN72_$LT$issue_75326..Foo$LT$I$C$E$GT$$u20$as$u20$issue_75326..Iterator2$GT$4next + //[legacy]~| ERROR demangling(<issue_75326::Foo<I,E> as issue_75326::Iterator2>::next + //[legacy]~| ERROR demangling-alt(<issue_75326::Foo<I,E> as issue_75326::Iterator2>::next) + //[v0]~^^^^ ERROR symbol-name(_RNvXINICs4fqI2P2rA04_11issue_75326s_0pppEINtB5_3FooppENtB5_9Iterator24nextB5_) + //[v0]~| ERROR demangling(<issue_75326[317d481089b8c8fe]::Foo<_, _> as issue_75326[317d481089b8c8fe]::Iterator2>::next) + //[v0]~| ERROR demangling-alt(<issue_75326::Foo<_, _> as issue_75326::Iterator2>::next) + fn next(&mut self) -> Option<Self::Item> { + self.find(|_| true) + } +} + +fn main() { + let mut a = Foo(Bar, 1u16); + let _ = a.next(); +} diff --git a/src/test/ui/symbol-names/issue-75326.v0.stderr b/src/test/ui/symbol-names/issue-75326.v0.stderr new file mode 100644 index 00000000000..59bdfa8ca36 --- /dev/null +++ b/src/test/ui/symbol-names/issue-75326.v0.stderr @@ -0,0 +1,20 @@ +error: symbol-name(_RNvXINICs4fqI2P2rA04_11issue_75326s_0pppEINtB5_3FooppENtB5_9Iterator24nextB5_) + --> $DIR/issue-75326.rs:43:5 + | +LL | #[rustc_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^ + +error: demangling(<issue_75326[317d481089b8c8fe]::Foo<_, _> as issue_75326[317d481089b8c8fe]::Iterator2>::next) + --> $DIR/issue-75326.rs:43:5 + | +LL | #[rustc_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^ + +error: demangling-alt(<issue_75326::Foo<_, _> as issue_75326::Iterator2>::next) + --> $DIR/issue-75326.rs:43:5 + | +LL | #[rustc_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 3 previous errors + diff --git a/src/test/ui/tail-typeck.stderr b/src/test/ui/tail-typeck.stderr index 69f8ffa581b..cff09910721 100644 --- a/src/test/ui/tail-typeck.stderr +++ b/src/test/ui/tail-typeck.stderr @@ -6,7 +6,7 @@ LL | fn f() -> isize { return g(); } | | | expected `isize` because of return type | -help: you can convert an `usize` to `isize` and panic if the converted value wouldn't fit +help: you can convert a `usize` to an `isize` and panic if the converted value doesn't fit | LL | fn f() -> isize { return g().try_into().unwrap(); } | ^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/traits/issue-70944.rs b/src/test/ui/traits/issue-70944.rs new file mode 100644 index 00000000000..3286de9d5b8 --- /dev/null +++ b/src/test/ui/traits/issue-70944.rs @@ -0,0 +1,23 @@ +// check-pass +// Regression test of #70944, should compile fine. + +use std::ops::Index; + +pub struct KeyA; +pub struct KeyB; +pub struct KeyC; + +pub trait Foo: Index<KeyA> + Index<KeyB> + Index<KeyC> {} +pub trait FooBuilder { + type Inner: Foo; + fn inner(&self) -> &Self::Inner; +} + +pub fn do_stuff(foo: &impl FooBuilder) { + let inner = foo.inner(); + &inner[KeyA]; + &inner[KeyB]; + &inner[KeyC]; +} + +fn main() {} diff --git a/src/test/ui/traits/negative-impls/negative-default-impls.stderr b/src/test/ui/traits/negative-impls/negative-default-impls.stderr index 50e74373b53..ceb86559d85 100644 --- a/src/test/ui/traits/negative-impls/negative-default-impls.stderr +++ b/src/test/ui/traits/negative-impls/negative-default-impls.stderr @@ -6,6 +6,7 @@ LL | #![feature(specialization)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete error[E0750]: negative impls cannot be default impls --> $DIR/negative-default-impls.rs:9:1 diff --git a/src/test/ui/traits/negative-impls/negative-specializes-negative.stderr b/src/test/ui/traits/negative-impls/negative-specializes-negative.stderr index 8b536de3786..9a846143d3d 100644 --- a/src/test/ui/traits/negative-impls/negative-specializes-negative.stderr +++ b/src/test/ui/traits/negative-impls/negative-specializes-negative.stderr @@ -6,6 +6,7 @@ LL | #![feature(specialization)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete warning: 1 warning emitted diff --git a/src/test/ui/traits/negative-impls/negative-specializes-positive-item.stderr b/src/test/ui/traits/negative-impls/negative-specializes-positive-item.stderr index 89ef15e89ac..77b4373a273 100644 --- a/src/test/ui/traits/negative-impls/negative-specializes-positive-item.stderr +++ b/src/test/ui/traits/negative-impls/negative-specializes-positive-item.stderr @@ -6,6 +6,7 @@ LL | #![feature(specialization)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete error[E0751]: found both positive and negative implementation of trait `MyTrait` for type `u32`: --> $DIR/negative-specializes-positive-item.rs:11:1 diff --git a/src/test/ui/traits/negative-impls/negative-specializes-positive.stderr b/src/test/ui/traits/negative-impls/negative-specializes-positive.stderr index e45d5a251ab..e5dc81b3eb7 100644 --- a/src/test/ui/traits/negative-impls/negative-specializes-positive.stderr +++ b/src/test/ui/traits/negative-impls/negative-specializes-positive.stderr @@ -6,6 +6,7 @@ LL | #![feature(specialization)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete error[E0751]: found both positive and negative implementation of trait `MyTrait` for type `u32`: --> $DIR/negative-specializes-positive.rs:7:1 diff --git a/src/test/ui/traits/negative-impls/positive-specializes-negative.stderr b/src/test/ui/traits/negative-impls/positive-specializes-negative.stderr index 49c16d47404..c091bc81da3 100644 --- a/src/test/ui/traits/negative-impls/positive-specializes-negative.stderr +++ b/src/test/ui/traits/negative-impls/positive-specializes-negative.stderr @@ -6,6 +6,7 @@ LL | #![feature(specialization)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete error[E0751]: found both positive and negative implementation of trait `MyTrait` for type `u32`: --> $DIR/positive-specializes-negative.rs:7:1 diff --git a/src/test/ui/traits/trait-alias/issue-75983.rs b/src/test/ui/traits/trait-alias/issue-75983.rs new file mode 100644 index 00000000000..f9a7f36de43 --- /dev/null +++ b/src/test/ui/traits/trait-alias/issue-75983.rs @@ -0,0 +1,17 @@ +// check-pass + +#![feature(trait_alias)] + +struct Bar; +trait Foo {} +impl Foo for Bar {} + +trait Baz = Foo where Bar: Foo; + +fn new() -> impl Baz { + Bar +} + +fn main() { + let _ = new(); +} diff --git a/src/test/ui/transmute-specialization.stderr b/src/test/ui/transmute-specialization.stderr index 02315051d30..a0ea72415a1 100644 --- a/src/test/ui/transmute-specialization.stderr +++ b/src/test/ui/transmute-specialization.stderr @@ -6,6 +6,7 @@ LL | #![feature(specialization)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete warning: 1 warning emitted diff --git a/src/test/ui/transmute/main.rs b/src/test/ui/transmute/main.rs index ea233a47a78..cb46fc5ec46 100644 --- a/src/test/ui/transmute/main.rs +++ b/src/test/ui/transmute/main.rs @@ -1,9 +1,6 @@ // normalize-stderr-32bit: "`&str` \(64 bits\)" -> "`&str` ($$STR bits)" // normalize-stderr-64bit: "`&str` \(128 bits\)" -> "`&str` ($$STR bits)" - - -#![feature(untagged_unions)] use std::mem::transmute; pub trait TypeConstructor<'a> { diff --git a/src/test/ui/transmute/main.stderr b/src/test/ui/transmute/main.stderr index 4e781318329..f48562094a4 100644 --- a/src/test/ui/transmute/main.stderr +++ b/src/test/ui/transmute/main.stderr @@ -1,5 +1,5 @@ error[E0512]: cannot transmute between types of different sizes, or dependently-sized types - --> $DIR/main.rs:16:5 + --> $DIR/main.rs:13:5 | LL | transmute(x) | ^^^^^^^^^ @@ -7,7 +7,7 @@ LL | transmute(x) = note: `<C as TypeConstructor>::T` does not have a fixed size error[E0512]: cannot transmute between types of different sizes, or dependently-sized types - --> $DIR/main.rs:20:17 + --> $DIR/main.rs:17:17 | LL | let x: u8 = transmute(10u16); | ^^^^^^^^^ @@ -16,7 +16,7 @@ LL | let x: u8 = transmute(10u16); = note: target type: `u8` (8 bits) error[E0512]: cannot transmute between types of different sizes, or dependently-sized types - --> $DIR/main.rs:24:17 + --> $DIR/main.rs:21:17 | LL | let x: u8 = transmute("test"); | ^^^^^^^^^ @@ -25,7 +25,7 @@ LL | let x: u8 = transmute("test"); = note: target type: `u8` (8 bits) error[E0512]: cannot transmute between types of different sizes, or dependently-sized types - --> $DIR/main.rs:29:18 + --> $DIR/main.rs:26:18 | LL | let x: Foo = transmute(10); | ^^^^^^^^^ diff --git a/src/test/ui/trivial-bounds/trivial-bounds-inconsistent-projection-error.stderr b/src/test/ui/trivial-bounds/trivial-bounds-inconsistent-projection-error.stderr index 08c79519dfe..edb48b6625e 100644 --- a/src/test/ui/trivial-bounds/trivial-bounds-inconsistent-projection-error.stderr +++ b/src/test/ui/trivial-bounds/trivial-bounds-inconsistent-projection-error.stderr @@ -7,7 +7,7 @@ LL | fn global_bound_is_hidden() -> u8 LL | B::get_x() | ^^^^^^^^^^ expected `u8`, found `i32` | -help: you can convert an `i32` to `u8` and panic if the converted value wouldn't fit +help: you can convert an `i32` to a `u8` and panic if the converted value doesn't fit | LL | B::get_x().try_into().unwrap() | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/tutorial-suffix-inference-test.stderr b/src/test/ui/tutorial-suffix-inference-test.stderr index c6c7ba26794..f9974acfb70 100644 --- a/src/test/ui/tutorial-suffix-inference-test.stderr +++ b/src/test/ui/tutorial-suffix-inference-test.stderr @@ -5,7 +5,7 @@ LL | identity_u16(x); | ^ | | | expected `u16`, found `u8` - | help: you can convert an `u8` to `u16`: `x.into()` + | help: you can convert a `u8` to a `u16`: `x.into()` error[E0308]: mismatched types --> $DIR/tutorial-suffix-inference-test.rs:12:18 @@ -13,7 +13,7 @@ error[E0308]: mismatched types LL | identity_u16(y); | ^ expected `u16`, found `i32` | -help: you can convert an `i32` to `u16` and panic if the converted value wouldn't fit +help: you can convert an `i32` to a `u16` and panic if the converted value doesn't fit | LL | identity_u16(y.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^ @@ -24,7 +24,7 @@ error[E0308]: mismatched types LL | identity_u16(a); | ^ expected `u16`, found `isize` | -help: you can convert an `isize` to `u16` and panic if the converted value wouldn't fit +help: you can convert an `isize` to a `u16` and panic if the converted value doesn't fit | LL | identity_u16(a.try_into().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/type-alias-enum-variants/enum-variant-priority-higher-than-other-inherent.stderr b/src/test/ui/type-alias-enum-variants/enum-variant-priority-higher-than-other-inherent.stderr index 46e7dd0c517..20e26058451 100644 --- a/src/test/ui/type-alias-enum-variants/enum-variant-priority-higher-than-other-inherent.stderr +++ b/src/test/ui/type-alias-enum-variants/enum-variant-priority-higher-than-other-inherent.stderr @@ -1,13 +1,16 @@ error[E0061]: this function takes 1 argument but 0 arguments were supplied --> $DIR/enum-variant-priority-higher-than-other-inherent.rs:21:5 | -LL | V(u8) - | ----- defined here -... LL | <E>::V(); | ^^^^^^-- supplied 0 arguments | | | expected 1 argument + | +note: tuple variant defined here + --> $DIR/enum-variant-priority-higher-than-other-inherent.rs:5:5 + | +LL | V(u8) + | ^^^^^ error[E0308]: mismatched types --> $DIR/enum-variant-priority-higher-than-other-inherent.rs:22:17 diff --git a/src/test/ui/type-alias-impl-trait/assoc-type-const.stderr b/src/test/ui/type-alias-impl-trait/assoc-type-const.stderr index e0c1b023861..c5b22f0026d 100644 --- a/src/test/ui/type-alias-impl-trait/assoc-type-const.stderr +++ b/src/test/ui/type-alias-impl-trait/assoc-type-const.stderr @@ -6,6 +6,7 @@ LL | #![feature(const_generics)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information + = help: consider using `min_const_generics` instead, which is more stable and complete warning: 1 warning emitted diff --git a/src/test/ui/type-alias-impl-trait/incoherent-assoc-imp-trait.stderr b/src/test/ui/type-alias-impl-trait/incoherent-assoc-imp-trait.stderr index cb893c40c32..eafbd2ad072 100644 --- a/src/test/ui/type-alias-impl-trait/incoherent-assoc-imp-trait.stderr +++ b/src/test/ui/type-alias-impl-trait/incoherent-assoc-imp-trait.stderr @@ -14,7 +14,7 @@ error[E0210]: type parameter `F` must be used as the type parameter for some loc LL | impl<F> FnOnce<()> for &F { | ^ type parameter `F` must be used as the type parameter for some local type | - = note: implementing a foreign trait is only possible if at least one of the types for which is it implemented is local + = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local = note: only traits defined in the current crate can be implemented for a type parameter error: aborting due to 2 previous errors diff --git a/src/test/ui/type-alias-impl-trait/issue-52843.rs b/src/test/ui/type-alias-impl-trait/issue-52843.rs new file mode 100644 index 00000000000..b24959d7207 --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/issue-52843.rs @@ -0,0 +1,15 @@ +#![feature(type_alias_impl_trait)] + +type Foo<T> = impl Default; +//~^ ERROR: the trait bound `T: Default` is not satisfied + +#[allow(unused)] +fn foo<T: Default>(t: T) -> Foo<T> { + t +} + +struct NotDefault; + +fn main() { + let _ = Foo::<NotDefault>::default(); +} diff --git a/src/test/ui/type-alias-impl-trait/issue-52843.stderr b/src/test/ui/type-alias-impl-trait/issue-52843.stderr new file mode 100644 index 00000000000..25db8dfabfc --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/issue-52843.stderr @@ -0,0 +1,14 @@ +error[E0277]: the trait bound `T: Default` is not satisfied + --> $DIR/issue-52843.rs:3:15 + | +LL | type Foo<T> = impl Default; + | ^^^^^^^^^^^^ the trait `Default` is not implemented for `T` + | +help: consider restricting type parameter `T` + | +LL | type Foo<T: Default> = impl Default; + | ^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/unboxed-closures/issue-53448.rs b/src/test/ui/unboxed-closures/issue-53448.rs new file mode 100644 index 00000000000..5c82a56e77e --- /dev/null +++ b/src/test/ui/unboxed-closures/issue-53448.rs @@ -0,0 +1,15 @@ +#![feature(unboxed_closures)] + +trait Lt<'a> { + type T; +} +impl<'a> Lt<'a> for () { + type T = (); +} + +fn main() { + let v: <() as Lt<'_>>::T = (); + let f: &mut dyn FnMut<(_,), Output = ()> = &mut |_: <() as Lt<'_>>::T| {}; + //~^ ERROR: the size for values of type `<() as Lt<'_>>::T` cannot be known + f(v); +} diff --git a/src/test/ui/unboxed-closures/issue-53448.stderr b/src/test/ui/unboxed-closures/issue-53448.stderr new file mode 100644 index 00000000000..bece9eedc7f --- /dev/null +++ b/src/test/ui/unboxed-closures/issue-53448.stderr @@ -0,0 +1,20 @@ +error[E0277]: the size for values of type `<() as Lt<'_>>::T` cannot be known at compilation time + --> $DIR/issue-53448.rs:12:54 + | +LL | let f: &mut dyn FnMut<(_,), Output = ()> = &mut |_: <() as Lt<'_>>::T| {}; + | ^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `<() as Lt<'_>>::T` + = help: unsized locals are gated as an unstable feature +help: consider further restricting the associated type + | +LL | fn main() where <() as Lt<'_>>::T: Sized { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: function arguments must have a statically known size, borrowed types always have a known size + | +LL | let f: &mut dyn FnMut<(_,), Output = ()> = &mut |_: &<() as Lt<'_>>::T| {}; + | ^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/uninhabited/uninhabited-enum-cast.rs b/src/test/ui/uninhabited/uninhabited-enum-cast.rs index 7e178e054cc..5a75c94c42f 100644 --- a/src/test/ui/uninhabited/uninhabited-enum-cast.rs +++ b/src/test/ui/uninhabited/uninhabited-enum-cast.rs @@ -1,7 +1,9 @@ +// check-pass + enum E {} fn f(e: E) { - println!("{}", (e as isize).to_string()); //~ ERROR non-primitive cast + println!("{}", (e as isize).to_string()); } fn main() {} diff --git a/src/test/ui/uninhabited/uninhabited-enum-cast.stderr b/src/test/ui/uninhabited/uninhabited-enum-cast.stderr deleted file mode 100644 index a9f10dfec99..00000000000 --- a/src/test/ui/uninhabited/uninhabited-enum-cast.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0605]: non-primitive cast: `E` as `isize` - --> $DIR/uninhabited-enum-cast.rs:4:20 - | -LL | println!("{}", (e as isize).to_string()); - | ^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0605`. diff --git a/src/test/ui/union/union-align.rs b/src/test/ui/union/union-align.rs index edd83a51169..1340ae43cd6 100644 --- a/src/test/ui/union/union-align.rs +++ b/src/test/ui/union/union-align.rs @@ -1,8 +1,6 @@ // run-pass #![allow(dead_code)] -#![feature(untagged_unions)] - use std::mem::{size_of, size_of_val, align_of, align_of_val}; #[repr(align(16))] @@ -35,6 +33,7 @@ mod hybrid { use std::mem::{size_of, align_of}; #[repr(align(16))] + #[derive(Copy, Clone)] struct S1 { a: u16, b: u8, diff --git a/src/test/ui/union/union-copy.rs b/src/test/ui/union/union-copy.rs index 8318f96940e..5c3f8d90898 100644 --- a/src/test/ui/union/union-copy.rs +++ b/src/test/ui/union/union-copy.rs @@ -1,5 +1,3 @@ -#![feature(untagged_unions)] - #[derive(Clone)] union U { a: u8 @@ -7,7 +5,7 @@ union U { #[derive(Clone)] union W { - a: String + a: std::mem::ManuallyDrop<String> } impl Copy for U {} // OK diff --git a/src/test/ui/union/union-copy.stderr b/src/test/ui/union/union-copy.stderr index a875ff660f9..0f47bae7f0f 100644 --- a/src/test/ui/union/union-copy.stderr +++ b/src/test/ui/union/union-copy.stderr @@ -1,8 +1,8 @@ error[E0204]: the trait `Copy` may not be implemented for this type - --> $DIR/union-copy.rs:14:6 + --> $DIR/union-copy.rs:12:6 | -LL | a: String - | --------- this field does not implement `Copy` +LL | a: std::mem::ManuallyDrop<String> + | --------------------------------- this field does not implement `Copy` ... LL | impl Copy for W {} | ^^^^ diff --git a/src/test/ui/union/union-derive-clone.rs b/src/test/ui/union/union-derive-clone.rs index 8126980604a..753a9f74d03 100644 --- a/src/test/ui/union/union-derive-clone.rs +++ b/src/test/ui/union/union-derive-clone.rs @@ -1,5 +1,3 @@ -#![feature(untagged_unions)] - use std::mem::ManuallyDrop; #[derive(Clone)] //~ ERROR the trait bound `U1: Copy` is not satisfied diff --git a/src/test/ui/union/union-derive-clone.stderr b/src/test/ui/union/union-derive-clone.stderr index 7a59f539c37..e18f457a8b6 100644 --- a/src/test/ui/union/union-derive-clone.stderr +++ b/src/test/ui/union/union-derive-clone.stderr @@ -1,5 +1,5 @@ error[E0277]: the trait bound `U1: Copy` is not satisfied - --> $DIR/union-derive-clone.rs:5:10 + --> $DIR/union-derive-clone.rs:3:10 | LL | #[derive(Clone)] | ^^^^^ the trait `Copy` is not implemented for `U1` @@ -12,7 +12,7 @@ LL | pub struct AssertParamIsCopy<T: Copy + ?Sized> { = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) error[E0599]: no method named `clone` found for union `U5<CloneNoCopy>` in the current scope - --> $DIR/union-derive-clone.rs:37:15 + --> $DIR/union-derive-clone.rs:35:15 | LL | union U5<T> { | ----------- diff --git a/src/test/ui/union/union-derive-eq.rs b/src/test/ui/union/union-derive-eq.rs index ac5808e4361..e689f8c27d7 100644 --- a/src/test/ui/union/union-derive-eq.rs +++ b/src/test/ui/union/union-derive-eq.rs @@ -1,5 +1,3 @@ -#![feature(untagged_unions)] - #[derive(Eq)] // OK union U1 { a: u8, @@ -7,7 +5,7 @@ union U1 { impl PartialEq for U1 { fn eq(&self, rhs: &Self) -> bool { true } } -#[derive(PartialEq)] +#[derive(PartialEq, Copy, Clone)] struct PartialEqNotEq; #[derive(Eq)] diff --git a/src/test/ui/union/union-derive-eq.stderr b/src/test/ui/union/union-derive-eq.stderr index c4d437c6cdd..0591d12d598 100644 --- a/src/test/ui/union/union-derive-eq.stderr +++ b/src/test/ui/union/union-derive-eq.stderr @@ -1,5 +1,5 @@ error[E0277]: the trait bound `PartialEqNotEq: Eq` is not satisfied - --> $DIR/union-derive-eq.rs:15:5 + --> $DIR/union-derive-eq.rs:13:5 | LL | a: PartialEqNotEq, | ^^^^^^^^^^^^^^^^^ the trait `Eq` is not implemented for `PartialEqNotEq` diff --git a/src/test/ui/union/union-derive-rpass.rs b/src/test/ui/union/union-derive-rpass.rs index b2f7ae679fd..db18a81c1f6 100644 --- a/src/test/ui/union/union-derive-rpass.rs +++ b/src/test/ui/union/union-derive-rpass.rs @@ -4,8 +4,6 @@ // Some traits can be derived for unions. -#![feature(untagged_unions)] - #[derive( Copy, Clone, diff --git a/src/test/ui/union/union-drop-assign.rs b/src/test/ui/union/union-drop-assign.rs index f1511b0a601..215666bdd9d 100644 --- a/src/test/ui/union/union-drop-assign.rs +++ b/src/test/ui/union/union-drop-assign.rs @@ -3,8 +3,6 @@ // Drop works for union itself. -#![feature(untagged_unions)] - use std::mem::ManuallyDrop; struct S; diff --git a/src/test/ui/union/union-drop.rs b/src/test/ui/union/union-drop.rs index 4df3ed50282..9edf5827511 100644 --- a/src/test/ui/union/union-drop.rs +++ b/src/test/ui/union/union-drop.rs @@ -4,8 +4,7 @@ // Drop works for union itself. -#![feature(untagged_unions)] - +#[derive(Copy, Clone)] struct S; union U { diff --git a/src/test/ui/union/union-generic-rpass.rs b/src/test/ui/union/union-generic-rpass.rs index eb169c516d2..69837f31cab 100644 --- a/src/test/ui/union/union-generic-rpass.rs +++ b/src/test/ui/union/union-generic-rpass.rs @@ -1,8 +1,6 @@ // run-pass #![allow(dead_code)] -#![feature(untagged_unions)] - use std::mem::ManuallyDrop; union MaybeItem<T: Iterator> { @@ -16,7 +14,7 @@ union U<A, B> where A: Copy, B: Copy { } unsafe fn union_transmute<A, B>(a: A) -> B where A: Copy, B: Copy { - U { a: a }.b + U { a }.b } fn main() { diff --git a/src/test/ui/union/union-manuallydrop-rpass.rs b/src/test/ui/union/union-manuallydrop-rpass.rs index a43a5050865..977d12f1086 100644 --- a/src/test/ui/union/union-manuallydrop-rpass.rs +++ b/src/test/ui/union/union-manuallydrop-rpass.rs @@ -1,4 +1,3 @@ -#![feature(untagged_unions)] #![allow(dead_code)] // run-pass diff --git a/src/test/ui/union/union-nodrop.rs b/src/test/ui/union/union-nodrop.rs index 59282bec59b..bc58c5995cb 100644 --- a/src/test/ui/union/union-nodrop.rs +++ b/src/test/ui/union/union-nodrop.rs @@ -1,7 +1,5 @@ // run-pass -#![feature(untagged_unions)] - #![allow(dead_code)] use std::mem::needs_drop; diff --git a/src/test/ui/union/union-overwrite.rs b/src/test/ui/union/union-overwrite.rs index 8234beb74a8..399ed9ae458 100644 --- a/src/test/ui/union/union-overwrite.rs +++ b/src/test/ui/union/union-overwrite.rs @@ -1,5 +1,4 @@ // run-pass -#![feature(untagged_unions)] #[repr(C)] #[derive(Copy, Clone)] diff --git a/src/test/ui/union/union-packed.rs b/src/test/ui/union/union-packed.rs index ceb35d94656..9cde44c06bd 100644 --- a/src/test/ui/union/union-packed.rs +++ b/src/test/ui/union/union-packed.rs @@ -2,8 +2,6 @@ #![allow(dead_code)] #![allow(non_snake_case)] -#![feature(untagged_unions)] - use std::mem::{size_of, size_of_val, align_of, align_of_val}; struct S { @@ -118,6 +116,7 @@ mod hybrid { use std::mem::{size_of, align_of}; #[repr(packed)] + #[derive(Copy, Clone)] struct S1 { a: u16, b: u8, diff --git a/src/test/ui/union/union-unsafe.rs b/src/test/ui/union/union-unsafe.rs index 8535cbd019c..10f0c467560 100644 --- a/src/test/ui/union/union-unsafe.rs +++ b/src/test/ui/union/union-unsafe.rs @@ -1,4 +1,3 @@ -#![feature(untagged_unions)] use std::mem::ManuallyDrop; union U1 { diff --git a/src/test/ui/union/union-unsafe.stderr b/src/test/ui/union/union-unsafe.stderr index e020dab63f8..b50d9e17506 100644 --- a/src/test/ui/union/union-unsafe.stderr +++ b/src/test/ui/union/union-unsafe.stderr @@ -1,5 +1,5 @@ error[E0133]: assignment to non-`Copy` union field is unsafe and requires unsafe function or block - --> $DIR/union-unsafe.rs:22:5 + --> $DIR/union-unsafe.rs:21:5 | LL | u3.a = ManuallyDrop::new(T::default()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to non-`Copy` union field @@ -7,7 +7,7 @@ LL | u3.a = ManuallyDrop::new(T::default()); = note: the previous content of the field will be dropped, which causes undefined behavior if the field was not properly initialized error[E0133]: access to union field is unsafe and requires unsafe function or block - --> $DIR/union-unsafe.rs:23:6 + --> $DIR/union-unsafe.rs:22:6 | LL | *u3.a = T::default(); | ^^^^ access to union field @@ -15,7 +15,7 @@ LL | *u3.a = T::default(); = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior error[E0133]: access to union field is unsafe and requires unsafe function or block - --> $DIR/union-unsafe.rs:29:6 + --> $DIR/union-unsafe.rs:28:6 | LL | *u3.a = T::default(); | ^^^^ access to union field @@ -23,7 +23,7 @@ LL | *u3.a = T::default(); = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior error[E0133]: access to union field is unsafe and requires unsafe function or block - --> $DIR/union-unsafe.rs:37:13 + --> $DIR/union-unsafe.rs:36:13 | LL | let a = u1.a; | ^^^^ access to union field @@ -31,7 +31,7 @@ LL | let a = u1.a; = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior error[E0133]: access to union field is unsafe and requires unsafe function or block - --> $DIR/union-unsafe.rs:40:14 + --> $DIR/union-unsafe.rs:39:14 | LL | let U1 { a } = u1; | ^ access to union field @@ -39,7 +39,7 @@ LL | let U1 { a } = u1; = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior error[E0133]: access to union field is unsafe and requires unsafe function or block - --> $DIR/union-unsafe.rs:41:20 + --> $DIR/union-unsafe.rs:40:20 | LL | if let U1 { a: 12 } = u1 {} | ^^ access to union field @@ -47,7 +47,7 @@ LL | if let U1 { a: 12 } = u1 {} = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior error[E0133]: assignment to non-`Copy` union field is unsafe and requires unsafe function or block - --> $DIR/union-unsafe.rs:45:5 + --> $DIR/union-unsafe.rs:44:5 | LL | u2.a = ManuallyDrop::new(String::from("new")); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to non-`Copy` union field @@ -55,7 +55,7 @@ LL | u2.a = ManuallyDrop::new(String::from("new")); = note: the previous content of the field will be dropped, which causes undefined behavior if the field was not properly initialized error[E0133]: access to union field is unsafe and requires unsafe function or block - --> $DIR/union-unsafe.rs:46:6 + --> $DIR/union-unsafe.rs:45:6 | LL | *u2.a = String::from("new"); | ^^^^ access to union field @@ -63,7 +63,7 @@ LL | *u2.a = String::from("new"); = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior error[E0133]: access to union field is unsafe and requires unsafe function or block - --> $DIR/union-unsafe.rs:50:6 + --> $DIR/union-unsafe.rs:49:6 | LL | *u3.a = 1; | ^^^^ access to union field @@ -71,7 +71,7 @@ LL | *u3.a = 1; = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior error[E0133]: assignment to non-`Copy` union field is unsafe and requires unsafe function or block - --> $DIR/union-unsafe.rs:53:5 + --> $DIR/union-unsafe.rs:52:5 | LL | u3.a = ManuallyDrop::new(String::from("new")); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to non-`Copy` union field @@ -79,7 +79,7 @@ LL | u3.a = ManuallyDrop::new(String::from("new")); = note: the previous content of the field will be dropped, which causes undefined behavior if the field was not properly initialized error[E0133]: access to union field is unsafe and requires unsafe function or block - --> $DIR/union-unsafe.rs:54:6 + --> $DIR/union-unsafe.rs:53:6 | LL | *u3.a = String::from("new"); | ^^^^ access to union field diff --git a/src/test/ui/unsized/issue-71659.rs b/src/test/ui/unsized/issue-71659.rs new file mode 100644 index 00000000000..3524ca02bbf --- /dev/null +++ b/src/test/ui/unsized/issue-71659.rs @@ -0,0 +1,32 @@ +#![feature(unsize)] + +use std::marker::Unsize; + +pub trait CastTo<T: ?Sized>: Unsize<T> { + fn cast_to(&self) -> &T; +} + +impl<T: ?Sized, U: ?Sized + Unsize<T>> CastTo<T> for U { + fn cast_to(&self) -> &T { + self + } +} + +impl<T: ?Sized> Cast for T {} +pub trait Cast { + fn cast<T: ?Sized>(&self) -> &T + where + Self: CastTo<T>, + { + self + } +} + +pub trait Foo: CastTo<[i32]> {} +impl Foo for [i32; 0] {} + +fn main() { + let x: &dyn Foo = &[]; + let x = x.cast::<[i32]>(); + //~^ ERROR: the trait bound `dyn Foo: CastTo<[i32]>` is not satisfied +} diff --git a/src/test/ui/unsized/issue-71659.stderr b/src/test/ui/unsized/issue-71659.stderr new file mode 100644 index 00000000000..be2df8c85e1 --- /dev/null +++ b/src/test/ui/unsized/issue-71659.stderr @@ -0,0 +1,9 @@ +error[E0277]: the trait bound `dyn Foo: CastTo<[i32]>` is not satisfied + --> $DIR/issue-71659.rs:30:15 + | +LL | let x = x.cast::<[i32]>(); + | ^^^^ the trait `CastTo<[i32]>` is not implemented for `dyn Foo` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/unsized/issue-75707.rs b/src/test/ui/unsized/issue-75707.rs new file mode 100644 index 00000000000..9f04cdbb922 --- /dev/null +++ b/src/test/ui/unsized/issue-75707.rs @@ -0,0 +1,17 @@ +pub trait Callback { + fn cb(); +} + +pub trait Processing { + type Call: Callback; +} + +fn f<P: Processing + ?Sized>() { + P::Call::cb(); +} + +fn main() { + struct MyCall; + f::<dyn Processing<Call = MyCall>>(); + //~^ ERROR: the trait bound `MyCall: Callback` is not satisfied +} diff --git a/src/test/ui/unsized/issue-75707.stderr b/src/test/ui/unsized/issue-75707.stderr new file mode 100644 index 00000000000..6e557a25f95 --- /dev/null +++ b/src/test/ui/unsized/issue-75707.stderr @@ -0,0 +1,12 @@ +error[E0277]: the trait bound `MyCall: Callback` is not satisfied + --> $DIR/issue-75707.rs:15:5 + | +LL | fn f<P: Processing + ?Sized>() { + | ---------- required by this bound in `f` +... +LL | f::<dyn Processing<Call = MyCall>>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Callback` is not implemented for `MyCall` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/usize-generic-argument-parent.rs b/src/test/ui/usize-generic-argument-parent.rs new file mode 100644 index 00000000000..46b06e2b366 --- /dev/null +++ b/src/test/ui/usize-generic-argument-parent.rs @@ -0,0 +1,5 @@ +fn foo() { + let x: usize<foo>; //~ ERROR const arguments are not allowed for this type +} + +fn main() {} diff --git a/src/test/ui/usize-generic-argument-parent.stderr b/src/test/ui/usize-generic-argument-parent.stderr new file mode 100644 index 00000000000..f1eae3b5008 --- /dev/null +++ b/src/test/ui/usize-generic-argument-parent.stderr @@ -0,0 +1,9 @@ +error[E0109]: const arguments are not allowed for this type + --> $DIR/usize-generic-argument-parent.rs:2:18 + | +LL | let x: usize<foo>; + | ^^^ const argument not allowed + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0109`. diff --git a/src/test/ui/wrong-ret-type.stderr b/src/test/ui/wrong-ret-type.stderr index c1274bd0ea6..5498dae718f 100644 --- a/src/test/ui/wrong-ret-type.stderr +++ b/src/test/ui/wrong-ret-type.stderr @@ -6,7 +6,7 @@ LL | fn mk_int() -> usize { let i: isize = 3; return i; } | | | expected `usize` because of return type | -help: you can convert an `isize` to `usize` and panic if the converted value wouldn't fit +help: you can convert an `isize` to a `usize` and panic if the converted value doesn't fit | LL | fn mk_int() -> usize { let i: isize = 3; return i.try_into().unwrap(); } | ^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/build-manifest/Cargo.toml b/src/tools/build-manifest/Cargo.toml index 4ae4dbfc06e..4a2c710811f 100644 --- a/src/tools/build-manifest/Cargo.toml +++ b/src/tools/build-manifest/Cargo.toml @@ -14,3 +14,4 @@ tar = "0.4.29" sha2 = "0.9.1" rayon = "1.3.1" hex = "0.4.2" +num_cpus = "1.13.0" diff --git a/src/tools/build-manifest/README.md b/src/tools/build-manifest/README.md index 26e96c9fd8f..b77c5a907c1 100644 --- a/src/tools/build-manifest/README.md +++ b/src/tools/build-manifest/README.md @@ -21,8 +21,8 @@ Then, you can generate the manifest and all the packages from `path/to/dist` to ``` $ cargo +nightly run path/to/dist path/to/output 1970-01-01 http://example.com \ - CHANNEL path/to/rust/repo + CHANNEL VERSION ``` Remember to replace `CHANNEL` with the channel you produced dist artifacts of -and `path/to/rust/repo` with the path to your checkout of the Rust repository. +and `VERSION` with the current Rust version. diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs index b35f3a595fb..1b780110456 100644 --- a/src/tools/build-manifest/src/main.rs +++ b/src/tools/build-manifest/src/main.rs @@ -22,6 +22,8 @@ use std::sync::Mutex; use std::time::Instant; static HOSTS: &[&str] = &[ + "aarch64-apple-darwin", + "aarch64-pc-windows-msvc", "aarch64-unknown-linux-gnu", "aarch64-unknown-linux-musl", "arm-unknown-linux-gnueabi", @@ -55,6 +57,7 @@ static HOSTS: &[&str] = &[ ]; static TARGETS: &[&str] = &[ + "aarch64-apple-darwin", "aarch64-apple-ios", "aarch64-fuchsia", "aarch64-linux-android", @@ -205,15 +208,20 @@ fn main() { // // Once the old release process is fully decommissioned, the environment variable, all the // related code in this tool and ./x.py dist hash-and-sign can be removed. - let legacy = env::var("BUILD_MANIFEST_LEGACY").is_ok(); - - // Avoid overloading the old server in legacy mode. - if legacy { - rayon::ThreadPoolBuilder::new() - .num_threads(1) - .build_global() - .expect("failed to initialize Rayon"); - } + let legacy = env::var_os("BUILD_MANIFEST_LEGACY").is_some(); + + let num_threads = if legacy { + // Avoid overloading the old server in legacy mode. + 1 + } else if let Some(num) = env::var_os("BUILD_MANIFEST_NUM_THREADS") { + num.to_str().unwrap().parse().expect("invalid number for BUILD_MANIFEST_NUM_THREADS") + } else { + num_cpus::get() + }; + rayon::ThreadPoolBuilder::new() + .num_threads(num_threads) + .build_global() + .expect("failed to initialize Rayon"); let mut args = env::args().skip(1); let input = PathBuf::from(args.next().unwrap()); @@ -221,7 +229,6 @@ fn main() { let date = args.next().unwrap(); let s3_address = args.next().unwrap(); let channel = args.next().unwrap(); - let monorepo_path = args.next().unwrap(); // Do not ask for a passphrase while manually testing let mut passphrase = String::new(); @@ -231,7 +238,7 @@ fn main() { } Builder { - versions: Versions::new(&channel, &input, Path::new(&monorepo_path)).unwrap(), + versions: Versions::new(&channel, &input).unwrap(), input, output, @@ -252,12 +259,13 @@ impl Builder { } let manifest = self.build_manifest(); - let rust_version = self.versions.rustc_version(); self.write_channel_files(self.versions.channel(), &manifest); - if self.versions.channel() != rust_version { - self.write_channel_files(&rust_version, &manifest); - } if self.versions.channel() == "stable" { + // channel-rust-1.XX.YY.toml + let rust_version = self.versions.rustc_version(); + self.write_channel_files(rust_version, &manifest); + + // channel-rust-1.XX.toml let major_minor = rust_version.split('.').take(2).collect::<Vec<_>>().join("."); self.write_channel_files(&major_minor, &manifest); } diff --git a/src/tools/build-manifest/src/versions.rs b/src/tools/build-manifest/src/versions.rs index 75b6979b54a..79f2ef8dfc4 100644 --- a/src/tools/build-manifest/src/versions.rs +++ b/src/tools/build-manifest/src/versions.rs @@ -1,4 +1,4 @@ -use anyhow::{Context, Error}; +use anyhow::Error; use flate2::read::GzDecoder; use std::collections::HashMap; use std::fs::File; @@ -7,6 +7,7 @@ use std::path::{Path, PathBuf}; use tar::Archive; const DEFAULT_TARGET: &str = "x86_64-unknown-linux-gnu"; +const RUSTC_VERSION: &str = include_str!("../../../version"); #[derive(Debug, Hash, Eq, PartialEq, Clone)] pub(crate) enum PkgType { @@ -87,26 +88,13 @@ pub(crate) struct VersionInfo { pub(crate) struct Versions { channel: String, - rustc_version: String, dist_path: PathBuf, versions: HashMap<PkgType, VersionInfo>, } impl Versions { - pub(crate) fn new( - channel: &str, - dist_path: &Path, - monorepo_root: &Path, - ) -> Result<Self, Error> { - Ok(Self { - channel: channel.into(), - rustc_version: std::fs::read_to_string(monorepo_root.join("src").join("version")) - .context("failed to read the rustc version from src/version")? - .trim() - .to_string(), - dist_path: dist_path.into(), - versions: HashMap::new(), - }) + pub(crate) fn new(channel: &str, dist_path: &Path) -> Result<Self, Error> { + Ok(Self { channel: channel.into(), dist_path: dist_path.into(), versions: HashMap::new() }) } pub(crate) fn channel(&self) -> &str { @@ -184,10 +172,10 @@ impl Versions { ) -> Result<String, Error> { let component_name = package.tarball_component_name(); let version = match self.channel.as_str() { - "stable" => self.rustc_version.clone(), + "stable" => RUSTC_VERSION.into(), "beta" => "beta".into(), "nightly" => "nightly".into(), - _ => format!("{}-dev", self.rustc_version), + _ => format!("{}-dev", RUSTC_VERSION), }; if package.target_independent() { @@ -198,6 +186,6 @@ impl Versions { } pub(crate) fn rustc_version(&self) -> &str { - &self.rustc_version + RUSTC_VERSION } } diff --git a/src/tools/cargo b/src/tools/cargo -Subproject 9d1a4863abd9237dbf9d1b74c78632b6a205f6b +Subproject 79b397d72c557eb6444a2ba0dc00a211a226a35 diff --git a/src/tools/clippy/clippy_lints/src/loops.rs b/src/tools/clippy/clippy_lints/src/loops.rs index 61b63597b16..4fdcaca8f60 100644 --- a/src/tools/clippy/clippy_lints/src/loops.rs +++ b/src/tools/clippy/clippy_lints/src/loops.rs @@ -742,6 +742,7 @@ fn never_loop_expr(expr: &Expr<'_>, main_loop_id: HirId) -> NeverLoopResult { | ExprKind::Closure(_, _, _, _, _) | ExprKind::LlvmInlineAsm(_) | ExprKind::Path(_) + | ExprKind::ConstBlock(_) | ExprKind::Lit(_) | ExprKind::Err => NeverLoopResult::Otherwise, } diff --git a/src/tools/clippy/clippy_lints/src/trivially_copy_pass_by_ref.rs b/src/tools/clippy/clippy_lints/src/trivially_copy_pass_by_ref.rs index 1f06d2dbe91..d92eb86fb2e 100644 --- a/src/tools/clippy/clippy_lints/src/trivially_copy_pass_by_ref.rs +++ b/src/tools/clippy/clippy_lints/src/trivially_copy_pass_by_ref.rs @@ -9,10 +9,10 @@ use rustc_hir::intravisit::FnKind; use rustc_hir::{Body, FnDecl, HirId, ItemKind, MutTy, Mutability, Node}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; -use rustc_session::config::Config as SessionConfig; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::Span; use rustc_target::abi::LayoutOf; +use rustc_target::spec::Target; use rustc_target::spec::abi::Abi; declare_clippy_lint! { @@ -60,9 +60,9 @@ pub struct TriviallyCopyPassByRef { } impl<'tcx> TriviallyCopyPassByRef { - pub fn new(limit: Option<u64>, target: &SessionConfig) -> Self { + pub fn new(limit: Option<u64>, target: &Target) -> Self { let limit = limit.unwrap_or_else(|| { - let bit_width = u64::from(target.ptr_width); + let bit_width = u64::from(target.pointer_width); // Cap the calculated bit width at 32-bits to reduce // portability problems between 32 and 64-bit targets let bit_width = cmp::min(bit_width, 32); diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs index 6eda6d1fa83..89425437eee 100644 --- a/src/tools/clippy/clippy_lints/src/utils/author.rs +++ b/src/tools/clippy/clippy_lints/src/utils/author.rs @@ -506,6 +506,11 @@ impl<'tcx> Visitor<'tcx> for PrintVisitor { println!(" if {}.len() == {};", fields_pat, fields.len()); println!(" // unimplemented: field checks"); }, + ExprKind::ConstBlock(_) => { + let value_pat = self.next("value"); + println!("Const({})", value_pat); + self.current = value_pat; + }, // FIXME: compute length (needs type info) ExprKind::Repeat(ref value, _) => { let value_pat = self.next("value"); diff --git a/src/tools/clippy/clippy_lints/src/utils/eager_or_lazy.rs b/src/tools/clippy/clippy_lints/src/utils/eager_or_lazy.rs index 6938d9971d9..27e9567740d 100644 --- a/src/tools/clippy/clippy_lints/src/utils/eager_or_lazy.rs +++ b/src/tools/clippy/clippy_lints/src/utils/eager_or_lazy.rs @@ -23,7 +23,7 @@ use rustc_middle::hir::map::Map; /// This function is named so to stress that it isn't exhaustive and returns FNs. fn identify_some_pure_patterns(expr: &Expr<'_>) -> bool { match expr.kind { - ExprKind::Lit(..) | ExprKind::Path(..) | ExprKind::Field(..) => true, + ExprKind::Lit(..) | ExprKind::ConstBlock(..) | ExprKind::Path(..) | ExprKind::Field(..) => true, ExprKind::AddrOf(_, _, addr_of_expr) => identify_some_pure_patterns(addr_of_expr), ExprKind::Tup(tup_exprs) => tup_exprs.iter().all(|expr| identify_some_pure_patterns(expr)), ExprKind::Struct(_, fields, expr) => { diff --git a/src/tools/clippy/clippy_lints/src/utils/hir_utils.rs b/src/tools/clippy/clippy_lints/src/utils/hir_utils.rs index c7263f48965..c9e639e8728 100644 --- a/src/tools/clippy/clippy_lints/src/utils/hir_utils.rs +++ b/src/tools/clippy/clippy_lints/src/utils/hir_utils.rs @@ -559,6 +559,9 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { self.hash_name(path.ident.name); self.hash_exprs(args); }, + ExprKind::ConstBlock(ref l_id) => { + self.hash_body(l_id.body); + }, ExprKind::Repeat(ref e, ref l_id) => { self.hash_expr(e); self.hash_body(l_id.body); diff --git a/src/tools/clippy/clippy_lints/src/utils/inspector.rs b/src/tools/clippy/clippy_lints/src/utils/inspector.rs index 4701a3f26e6..93bd8299446 100644 --- a/src/tools/clippy/clippy_lints/src/utils/inspector.rs +++ b/src/tools/clippy/clippy_lints/src/utils/inspector.rs @@ -338,6 +338,11 @@ fn print_expr(cx: &LateContext<'_>, expr: &hir::Expr<'_>, indent: usize) { print_expr(cx, base, indent + 1); } }, + hir::ExprKind::ConstBlock(ref anon_const) => { + println!("{}ConstBlock", ind); + println!("{}anon_const:", ind); + print_expr(cx, &cx.tcx.hir().body(anon_const.body).value, indent + 1); + }, hir::ExprKind::Repeat(ref val, ref anon_const) => { println!("{}Repeat", ind); println!("{}value:", ind); diff --git a/src/tools/clippy/clippy_lints/src/utils/paths.rs b/src/tools/clippy/clippy_lints/src/utils/paths.rs index 277da9d3f3a..5e769c690a6 100644 --- a/src/tools/clippy/clippy_lints/src/utils/paths.rs +++ b/src/tools/clippy/clippy_lints/src/utils/paths.rs @@ -14,7 +14,7 @@ pub const BINARY_HEAP: [&str; 4] = ["alloc", "collections", "binary_heap", "Bina pub const BORROW_TRAIT: [&str; 3] = ["core", "borrow", "Borrow"]; pub const BOX: [&str; 3] = ["alloc", "boxed", "Box"]; pub const BTREEMAP: [&str; 5] = ["alloc", "collections", "btree", "map", "BTreeMap"]; -pub const BTREEMAP_ENTRY: [&str; 5] = ["alloc", "collections", "btree", "map", "Entry"]; +pub const BTREEMAP_ENTRY: [&str; 6] = ["alloc", "collections", "btree", "map", "entry", "Entry"]; pub const BTREESET: [&str; 5] = ["alloc", "collections", "btree", "set", "BTreeSet"]; pub const CLONE_TRAIT: [&str; 3] = ["core", "clone", "Clone"]; pub const CLONE_TRAIT_METHOD: [&str; 4] = ["core", "clone", "Clone", "clone"]; diff --git a/src/tools/clippy/clippy_lints/src/utils/qualify_min_const_fn.rs b/src/tools/clippy/clippy_lints/src/utils/qualify_min_const_fn.rs index 1b4f2034272..7cb7d0a26b6 100644 --- a/src/tools/clippy/clippy_lints/src/utils/qualify_min_const_fn.rs +++ b/src/tools/clippy/clippy_lints/src/utils/qualify_min_const_fn.rs @@ -282,7 +282,6 @@ fn check_terminator(tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, terminator: &Termin TerminatorKind::SwitchInt { discr, switch_ty: _, - values: _, targets: _, } => check_operand(tcx, discr, span, body), diff --git a/src/tools/clippy/clippy_lints/src/utils/sugg.rs b/src/tools/clippy/clippy_lints/src/utils/sugg.rs index ec8b7e59b59..a2a1d109c9a 100644 --- a/src/tools/clippy/clippy_lints/src/utils/sugg.rs +++ b/src/tools/clippy/clippy_lints/src/utils/sugg.rs @@ -110,6 +110,7 @@ impl<'a> Sugg<'a> { | hir::ExprKind::Index(..) | hir::ExprKind::InlineAsm(..) | hir::ExprKind::LlvmInlineAsm(..) + | hir::ExprKind::ConstBlock(..) | hir::ExprKind::Lit(..) | hir::ExprKind::Loop(..) | hir::ExprKind::MethodCall(..) @@ -157,6 +158,7 @@ impl<'a> Sugg<'a> { | ast::ExprKind::Index(..) | ast::ExprKind::InlineAsm(..) | ast::ExprKind::LlvmInlineAsm(..) + | ast::ExprKind::ConstBlock(..) | ast::ExprKind::Lit(..) | ast::ExprKind::Loop(..) | ast::ExprKind::MacCall(..) diff --git a/src/tools/clippy/src/driver.rs b/src/tools/clippy/src/driver.rs index 377f6d22446..805828eece1 100644 --- a/src/tools/clippy/src/driver.rs +++ b/src/tools/clippy/src/driver.rs @@ -277,9 +277,9 @@ fn report_clippy_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str) { // If backtraces are enabled, also print the query stack let backtrace = env::var_os("RUST_BACKTRACE").map_or(false, |x| &x != "0"); - if backtrace { - TyCtxt::try_print_query_stack(&handler); - } + let num_frames = if backtrace { None } else { Some(2) }; + + TyCtxt::try_print_query_stack(&handler, num_frames); } fn toolchain_path(home: Option<String>, toolchain: Option<String>) -> Option<PathBuf> { diff --git a/src/tools/clippy/tests/ui/custom_ice_message.stderr b/src/tools/clippy/tests/ui/custom_ice_message.stderr index a9a65a38c10..a1b8e2ee162 100644 --- a/src/tools/clippy/tests/ui/custom_ice_message.stderr +++ b/src/tools/clippy/tests/ui/custom_ice_message.stderr @@ -9,3 +9,5 @@ note: we would appreciate a bug report: https://github.com/rust-lang/rust-clippy note: Clippy version: foo +query stack during panic: +end of query stack diff --git a/src/tools/linkchecker/Cargo.toml b/src/tools/linkchecker/Cargo.toml index 0994cd20662..e5d870c039d 100644 --- a/src/tools/linkchecker/Cargo.toml +++ b/src/tools/linkchecker/Cargo.toml @@ -7,3 +7,7 @@ edition = "2018" [[bin]] name = "linkchecker" path = "main.rs" + +[dependencies] +regex = "1" +once_cell = "1" diff --git a/src/tools/linkchecker/linkcheck.sh b/src/tools/linkchecker/linkcheck.sh index bbccc17e494..b68053c76be 100755 --- a/src/tools/linkchecker/linkcheck.sh +++ b/src/tools/linkchecker/linkcheck.sh @@ -34,6 +34,9 @@ then exit 1 fi +# Avoid failure caused by newer mdbook. +export MDBOOK_OUTPUT__HTML__INPUT_404="" + book_name="" # Iterative will avoid cleaning up, so you can quickly run it repeatedly. iterative=0 diff --git a/src/tools/linkchecker/main.rs b/src/tools/linkchecker/main.rs index 4fe493a850d..f213944e0ab 100644 --- a/src/tools/linkchecker/main.rs +++ b/src/tools/linkchecker/main.rs @@ -21,6 +21,9 @@ use std::fs; use std::path::{Component, Path, PathBuf}; use std::rc::Rc; +use once_cell::sync::Lazy; +use regex::Regex; + use crate::Redirect::*; // Add linkcheck exceptions here @@ -50,6 +53,44 @@ const LINKCHECK_EXCEPTIONS: &[(&str, &[&str])] = &[ ("alloc/collections/btree_set/struct.BTreeSet.html", &["#insert-and-complex-keys"]), ]; +#[rustfmt::skip] +const INTRA_DOC_LINK_EXCEPTIONS: &[(&str, &[&str])] = &[ + // This will never have links that are not in other pages. + // To avoid repeating the exceptions twice, an empty list means all broken links are allowed. + ("reference/print.html", &[]), + // All the reference 'links' are actually ENBF highlighted as code + ("reference/comments.html", &[ + "/</code> <code>!", + "*</code> <code>!", + ]), + ("reference/identifiers.html", &[ + "a</code>-<code>z</code> <code>A</code>-<code>Z", + "a</code>-<code>z</code> <code>A</code>-<code>Z</code> <code>0</code>-<code>9</code> <code>_", + "a</code>-<code>z</code> <code>A</code>-<code>Z</code>] [<code>a</code>-<code>z</code> <code>A</code>-<code>Z</code> <code>0</code>-<code>9</code> <code>_", + ]), + ("reference/tokens.html", &[ + "0</code>-<code>1", + "0</code>-<code>7", + "0</code>-<code>9", + "0</code>-<code>9", + "0</code>-<code>9</code> <code>a</code>-<code>f</code> <code>A</code>-<code>F", + ]), + ("reference/notation.html", &[ + "b</code> <code>B", + "a</code>-<code>z", + ]), + // This is being used in the sense of 'inclusive range', not a markdown link + ("core/ops/struct.RangeInclusive.html", &["begin</code>, <code>end"]), + ("std/ops/struct.RangeInclusive.html", &["begin</code>, <code>end"]), + ("core/slice/trait.SliceIndex.html", &["begin</code>, <code>end"]), + ("alloc/slice/trait.SliceIndex.html", &["begin</code>, <code>end"]), + ("std/slice/trait.SliceIndex.html", &["begin</code>, <code>end"]), + +]; + +static BROKEN_INTRA_DOC_LINK: Lazy<Regex> = + Lazy::new(|| Regex::new(r#"\[<code>(.*)</code>\]"#).unwrap()); + macro_rules! t { ($e:expr) => { match $e { @@ -138,6 +179,14 @@ fn walk(cache: &mut Cache, root: &Path, dir: &Path, errors: &mut bool) { } } +fn is_intra_doc_exception(file: &Path, link: &str) -> bool { + if let Some(entry) = INTRA_DOC_LINK_EXCEPTIONS.iter().find(|&(f, _)| file.ends_with(f)) { + entry.1.is_empty() || entry.1.contains(&link) + } else { + false + } +} + fn is_exception(file: &Path, link: &str) -> bool { if let Some(entry) = LINKCHECK_EXCEPTIONS.iter().find(|&(f, _)| file.ends_with(f)) { entry.1.contains(&link) @@ -292,6 +341,19 @@ fn check(cache: &mut Cache, root: &Path, file: &Path, errors: &mut bool) -> Opti } } }); + + // Search for intra-doc links that rustdoc didn't warn about + // FIXME(#77199, 77200) Rustdoc should just warn about these directly. + // NOTE: only looks at one line at a time; in practice this should find most links + for (i, line) in contents.lines().enumerate() { + for broken_link in BROKEN_INTRA_DOC_LINK.captures_iter(line) { + if !is_intra_doc_exception(file, &broken_link[1]) { + *errors = true; + print!("{}:{}: broken intra-doc link - ", pretty_file.display(), i + 1); + println!("{}", &broken_link[0]); + } + } + } Some(pretty_file) } diff --git a/src/tools/miri b/src/tools/miri -Subproject 3fafb835ea42e6e3af27f5dc8f26bda590cb49e +Subproject 1b3a27c4298ebed55851657934483366a02abc3 diff --git a/src/tools/publish_toolstate.py b/src/tools/publish_toolstate.py index 33613e2dc10..7586f5aa3b5 100755 --- a/src/tools/publish_toolstate.py +++ b/src/tools/publish_toolstate.py @@ -33,7 +33,7 @@ MAINTAINERS = { 'rust-by-example': {'steveklabnik', 'marioidival'}, 'embedded-book': {'adamgreig', 'andre-richter', 'jamesmunns', 'therealprof'}, 'edition-guide': {'ehuss', 'steveklabnik'}, - 'rustc-dev-guide': {'mark-i-m', 'spastorino', 'amanjeev', 'JohnTitor'}, + 'rustc-dev-guide': {'spastorino', 'amanjeev', 'JohnTitor'}, } LABELS = { diff --git a/src/tools/rls b/src/tools/rls -Subproject 9bfb47a79299d52f45304367762c9bfc96d9ed7 +Subproject 1f686d5f707269b1086f6afcdced36225c0c5ff diff --git a/src/tools/tidy/src/bins.rs b/src/tools/tidy/src/bins.rs index 589be26dc27..62cfa85577f 100644 --- a/src/tools/tidy/src/bins.rs +++ b/src/tools/tidy/src/bins.rs @@ -9,19 +9,56 @@ use std::path::Path; // All files are executable on Windows, so just check on Unix. #[cfg(windows)] -pub fn check(_path: &Path, _bad: &mut bool) {} +pub fn check(_path: &Path, _output: &Path, _bad: &mut bool) {} #[cfg(unix)] -pub fn check(path: &Path, bad: &mut bool) { +pub fn check(path: &Path, output: &Path, bad: &mut bool) { use std::fs; use std::os::unix::prelude::*; use std::process::{Command, Stdio}; - if let Ok(contents) = fs::read_to_string("/proc/version") { - // Probably on Windows Linux Subsystem or Docker via VirtualBox, - // all files will be marked as executable, so skip checking. - if contents.contains("Microsoft") || contents.contains("boot2docker") { - return; + fn is_executable(path: &Path) -> std::io::Result<bool> { + Ok(path.metadata()?.mode() & 0o111 != 0) + } + + // We want to avoid false positives on filesystems that do not support the + // executable bit. This occurs on some versions of Window's linux subsystem, + // for example. + // + // We try to create the temporary file first in the src directory, which is + // the preferred location as it's most likely to be on the same filesystem, + // and then in the output (`build`) directory if that fails. Sometimes we + // see the source directory mounted as read-only which means we can't + // readily create a file there to test. + // + // See #36706 and #74753 for context. + let mut temp_path = path.join("tidy-test-file"); + match fs::File::create(&temp_path).or_else(|_| { + temp_path = output.join("tidy-test-file"); + fs::File::create(&temp_path) + }) { + Ok(file) => { + let exec = is_executable(&temp_path).unwrap_or(false); + std::mem::drop(file); + std::fs::remove_file(&temp_path).expect("Deleted temp file"); + if exec { + // If the file is executable, then we assume that this + // filesystem does not track executability, so skip this check. + return; + } + } + Err(e) => { + // If the directory is read-only or we otherwise don't have rights, + // just don't run this check. + // + // 30 is the "Read-only filesystem" code at least in one CI + // environment. + if e.raw_os_error() == Some(30) { + eprintln!("tidy: Skipping binary file check, read-only filesystem"); + return; + } + + panic!("unable to create temporary file `{:?}`: {:?}", temp_path, e); } } @@ -36,8 +73,7 @@ pub fn check(path: &Path, bad: &mut bool) { return; } - let metadata = t!(entry.metadata(), file); - if metadata.mode() & 0o111 != 0 { + if t!(is_executable(&file), file) { let rel_path = file.strip_prefix(path).unwrap(); let git_friendly_path = rel_path.to_str().unwrap().replace("\\", "/"); let output = Command::new("git") diff --git a/src/tools/tidy/src/main.rs b/src/tools/tidy/src/main.rs index 36c9e58eb9a..e1525f8e1bf 100644 --- a/src/tools/tidy/src/main.rs +++ b/src/tools/tidy/src/main.rs @@ -13,6 +13,8 @@ use std::process; fn main() { let root_path: PathBuf = env::args_os().nth(1).expect("need path to root of repo").into(); let cargo: PathBuf = env::args_os().nth(2).expect("need path to cargo").into(); + let output_directory: PathBuf = + env::args_os().nth(3).expect("need path to output directory").into(); let src_path = root_path.join("src"); let library_path = root_path.join("library"); @@ -36,9 +38,9 @@ fn main() { unit_tests::check(&library_path, &mut bad); // Checks that need to be done for both the compiler and std libraries. - bins::check(&src_path, &mut bad); - bins::check(&compiler_path, &mut bad); - bins::check(&library_path, &mut bad); + bins::check(&src_path, &output_directory, &mut bad); + bins::check(&compiler_path, &output_directory, &mut bad); + bins::check(&library_path, &output_directory, &mut bad); style::check(&src_path, &mut bad); style::check(&compiler_path, &mut bad); |
