diff options
Diffstat (limited to 'compiler')
360 files changed, 4239 insertions, 4157 deletions
diff --git a/compiler/rustc_apfloat/src/ieee.rs b/compiler/rustc_apfloat/src/ieee.rs index 71bcb8f090d..96277950cfe 100644 --- a/compiler/rustc_apfloat/src/ieee.rs +++ b/compiler/rustc_apfloat/src/ieee.rs @@ -2273,6 +2273,7 @@ impl Loss { mod sig { use super::{limbs_for_bits, ExpInt, Limb, Loss, LIMB_BITS}; use core::cmp::Ordering; + use core::iter; use core::mem; pub(super) fn is_all_zeros(limbs: &[Limb]) -> bool { @@ -2483,7 +2484,7 @@ mod sig { pub(super) fn add(a: &mut [Limb], b: &[Limb], mut c: Limb) -> Limb { assert!(c <= 1); - for (a, &b) in a.iter_mut().zip(b) { + for (a, &b) in iter::zip(a, b) { let (r, overflow) = a.overflowing_add(b); let (r, overflow2) = r.overflowing_add(c); *a = r; @@ -2497,7 +2498,7 @@ mod sig { pub(super) fn sub(a: &mut [Limb], b: &[Limb], mut c: Limb) -> Limb { assert!(c <= 1); - for (a, &b) in a.iter_mut().zip(b) { + for (a, &b) in iter::zip(a, b) { let (r, overflow) = a.overflowing_sub(b); let (r, overflow2) = r.overflowing_sub(c); *a = r; diff --git a/compiler/rustc_apfloat/src/lib.rs b/compiler/rustc_apfloat/src/lib.rs index c1aa74029f5..c648147d108 100644 --- a/compiler/rustc_apfloat/src/lib.rs +++ b/compiler/rustc_apfloat/src/lib.rs @@ -33,6 +33,7 @@ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![no_std] #![forbid(unsafe_code)] +#![feature(iter_zip)] #![feature(nll)] #![cfg_attr(bootstrap, feature(or_patterns))] diff --git a/compiler/rustc_arena/src/lib.rs b/compiler/rustc_arena/src/lib.rs index c3198fb1043..c3e4945c446 100644 --- a/compiler/rustc_arena/src/lib.rs +++ b/compiler/rustc_arena/src/lib.rs @@ -236,26 +236,6 @@ impl<T> TypedArena<T> { start_ptr } - /// Allocates a slice of objects that are copied into the `TypedArena`, returning a mutable - /// reference to it. Will panic if passed a zero-sized types. - /// - /// Panics: - /// - /// - Zero-sized types - /// - Zero-length slices - #[inline] - pub fn alloc_slice(&self, slice: &[T]) -> &mut [T] - where - T: Copy, - { - unsafe { - let len = slice.len(); - let start_ptr = self.alloc_raw_slice(len); - slice.as_ptr().copy_to_nonoverlapping(start_ptr, len); - slice::from_raw_parts_mut(start_ptr, len) - } - } - #[inline] pub fn alloc_from_iter<I: IntoIterator<Item = T>>(&self, iter: I) -> &mut [T] { assert!(mem::size_of::<T>() != 0); diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 7e82d7ff77d..2cffddfcd0b 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -762,14 +762,6 @@ pub enum Mutability { } impl Mutability { - /// Returns `MutMutable` only if both `self` and `other` are mutable. - pub fn and(self, other: Self) -> Self { - match self { - Mutability::Mut => other, - Mutability::Not => Mutability::Not, - } - } - pub fn invert(self) -> Self { match self { Mutability::Mut => Mutability::Not, @@ -1722,13 +1714,6 @@ impl FloatTy { FloatTy::F64 => sym::f64, } } - - pub fn bit_width(self) -> u64 { - match self { - FloatTy::F32 => 32, - FloatTy::F64 => 64, - } - } } #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] @@ -1764,29 +1749,6 @@ impl IntTy { IntTy::I128 => sym::i128, } } - - pub fn bit_width(&self) -> Option<u64> { - Some(match *self { - IntTy::Isize => return None, - IntTy::I8 => 8, - IntTy::I16 => 16, - IntTy::I32 => 32, - IntTy::I64 => 64, - IntTy::I128 => 128, - }) - } - - pub fn normalize(&self, target_width: u32) -> Self { - match self { - IntTy::Isize => match target_width { - 16 => IntTy::I16, - 32 => IntTy::I32, - 64 => IntTy::I64, - _ => unreachable!(), - }, - _ => *self, - } - } } #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, Debug)] @@ -1822,29 +1784,6 @@ impl UintTy { UintTy::U128 => sym::u128, } } - - pub fn bit_width(&self) -> Option<u64> { - Some(match *self { - UintTy::Usize => return None, - UintTy::U8 => 8, - UintTy::U16 => 16, - UintTy::U32 => 32, - UintTy::U64 => 64, - UintTy::U128 => 128, - }) - } - - pub fn normalize(&self, target_width: u32) -> Self { - match self { - UintTy::Usize => match target_width { - 16 => UintTy::U16, - 32 => UintTy::U32, - 64 => UintTy::U64, - _ => unreachable!(), - }, - _ => *self, - } - } } /// A constraint on an associated type (e.g., `A = Bar` in `Foo<A = Bar>` or @@ -2215,9 +2154,6 @@ pub struct FnDecl { } impl FnDecl { - pub fn get_self(&self) -> Option<ExplicitSelf> { - self.inputs.get(0).and_then(Param::to_self) - } pub fn has_self(&self) -> bool { self.inputs.get(0).map_or(false, Param::is_self) } diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs index 2c5e180f80d..0fbe4d0120c 100644 --- a/compiler/rustc_ast/src/attr/mod.rs +++ b/compiler/rustc_ast/src/attr/mod.rs @@ -100,16 +100,7 @@ impl NestedMetaItem { self.meta_item().map_or(false, |meta_item| meta_item.is_word()) } - /// Returns `true` if `self` is a `MetaItem` and the meta item is a `ValueString`. - pub fn is_value_str(&self) -> bool { - self.value_str().is_some() - } - - /// Returns `true` if `self` is a `MetaItem` and the meta item is a list. - pub fn is_meta_item_list(&self) -> bool { - self.meta_item_list().is_some() - } - + /// See [`MetaItem::name_value_literal_span`]. pub fn name_value_literal_span(&self) -> Option<Span> { self.meta_item()?.name_value_literal_span() } @@ -165,31 +156,6 @@ impl Attribute { false } } - - pub fn is_meta_item_list(&self) -> bool { - self.meta_item_list().is_some() - } - - /// Indicates if the attribute is a `ValueString`. - pub fn is_value_str(&self) -> bool { - self.value_str().is_some() - } - - /// This is used in case you want the value span instead of the whole attribute. Example: - /// - /// ```text - /// #[doc(alias = "foo")] - /// ``` - /// - /// In here, it'll return a span for `"foo"`. - pub fn name_value_literal_span(&self) -> Option<Span> { - match self.kind { - AttrKind::Normal(ref item, _) => { - item.meta(self.span).and_then(|meta| meta.name_value_literal_span()) - } - AttrKind::DocComment(..) => None, - } - } } impl MetaItem { @@ -236,10 +202,6 @@ impl MetaItem { self.path == name } - pub fn is_value_str(&self) -> bool { - self.value_str().is_some() - } - /// This is used in case you want the value span instead of the whole attribute. Example: /// /// ```text diff --git a/compiler/rustc_ast/src/lib.rs b/compiler/rustc_ast/src/lib.rs index a823d375fcf..032a4e6c782 100644 --- a/compiler/rustc_ast/src/lib.rs +++ b/compiler/rustc_ast/src/lib.rs @@ -14,6 +14,7 @@ #![feature(const_fn_transmute)] #![feature(const_panic)] #![feature(crate_visibility_modifier)] +#![feature(iter_zip)] #![feature(label_break_value)] #![feature(nll)] #![cfg_attr(bootstrap, feature(or_patterns))] diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs index c5c3142602b..06d49c7524a 100644 --- a/compiler/rustc_ast/src/tokenstream.rs +++ b/compiler/rustc_ast/src/tokenstream.rs @@ -89,10 +89,6 @@ impl TokenTree { } } - pub fn joint(self) -> TokenStream { - TokenStream::new(vec![(self, Spacing::Joint)]) - } - pub fn token(kind: TokenKind, span: Span) -> TokenTree { TokenTree::Token(Token::new(kind, span)) } @@ -278,14 +274,6 @@ impl TokenStream { self.0.len() } - pub fn span(&self) -> Option<Span> { - match &**self.0 { - [] => None, - [(tt, _)] => Some(tt.span()), - [(tt_start, _), .., (tt_end, _)] => Some(tt_start.span().to(tt_end.span())), - } - } - pub fn from_streams(mut streams: SmallVec<[TokenStream; 2]>) -> TokenStream { match streams.len() { 0 => TokenStream::default(), @@ -325,10 +313,6 @@ impl TokenStream { } } - pub fn trees_ref(&self) -> CursorRef<'_> { - CursorRef::new(self) - } - pub fn trees(&self) -> Cursor { self.clone().into_trees() } @@ -341,7 +325,7 @@ impl TokenStream { pub fn eq_unspanned(&self, other: &TokenStream) -> bool { let mut t1 = self.trees(); let mut t2 = other.trees(); - for (t1, t2) in t1.by_ref().zip(t2.by_ref()) { + for (t1, t2) in iter::zip(&mut t1, &mut t2) { if !t1.eq_unspanned(&t2) { return false; } @@ -427,10 +411,6 @@ pub struct CursorRef<'t> { } impl<'t> CursorRef<'t> { - fn new(stream: &TokenStream) -> CursorRef<'_> { - CursorRef { stream, index: 0 } - } - fn next_with_spacing(&mut self) -> Option<&'t TreeAndSpacing> { self.stream.0.get(self.index).map(|tree| { self.index += 1; diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index edd0c5fb964..ea01632d75d 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -18,6 +18,7 @@ use rustc_target::spec::abi; use smallvec::{smallvec, SmallVec}; use tracing::debug; +use std::iter; use std::mem; pub(super) struct ItemLowerer<'a, 'lowering, 'hir> { @@ -206,7 +207,7 @@ impl<'hir> LoweringContext<'_, 'hir> { UseTreeKind::Glob => {} UseTreeKind::Simple(_, id1, id2) => { for (_, &id) in - self.expect_full_res_from_use(base_id).skip(1).zip([id1, id2].iter()) + iter::zip(self.expect_full_res_from_use(base_id).skip(1), &[id1, id2]) { vec.push(id); } @@ -537,7 +538,7 @@ impl<'hir> LoweringContext<'_, 'hir> { // won't be dealing with macros in the rest of the compiler. // Essentially a single `use` which imports two names is desugared into // two imports. - for (res, &new_node_id) in resolutions.zip([id1, id2].iter()) { + for (res, &new_node_id) in iter::zip(resolutions, &[id1, id2]) { let ident = *ident; let mut path = path.clone(); for seg in &mut path.segments { diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 046e7fc70fc..4e375e00682 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -33,6 +33,7 @@ #![feature(crate_visibility_modifier)] #![cfg_attr(bootstrap, feature(or_patterns))] #![feature(box_patterns)] +#![feature(iter_zip)] #![recursion_limit = "256"] use rustc_ast::node_id::NodeMap; @@ -568,7 +569,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } hir::Crate { - item: hir::CrateItem { module, span: c.span }, + item: module, exported_macros: self.arena.alloc_from_iter(self.exported_macros), non_exported_macro_attrs: self.arena.alloc_from_iter(self.non_exported_macro_attrs), items: self.items, diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 2f73e44faf6..3724438cc6e 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -313,7 +313,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { include => external_doc cfg => doc_cfg masked => doc_masked - spotlight => doc_spotlight + notable_trait => doc_notable_trait keyword => doc_keyword ); } diff --git a/compiler/rustc_ast_pretty/src/pprust/mod.rs b/compiler/rustc_ast_pretty/src/pprust/mod.rs index b88699f6ee1..976725b308e 100644 --- a/compiler/rustc_ast_pretty/src/pprust/mod.rs +++ b/compiler/rustc_ast_pretty/src/pprust/mod.rs @@ -22,10 +22,6 @@ 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) } @@ -50,18 +46,10 @@ 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) } @@ -74,26 +62,14 @@ 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/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index 84f8ce5706a..627c0584b61 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -2292,10 +2292,6 @@ impl<'a> State<'a> { } } - pub fn print_usize(&mut self, i: usize) { - self.s.word(i.to_string()) - } - crate fn print_name(&mut self, name: Symbol) { self.s.word(name.to_string()); self.ann.post(self, AnnNode::Name(&name)) diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs index da85cc73ffd..04753926c3e 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs @@ -1034,7 +1034,7 @@ impl<'a> MethodDef<'a> { // make a series of nested matches, to destructure the // structs. This is actually right-to-left, but it shouldn't // matter. - for (arg_expr, pat) in self_args.iter().zip(patterns) { + for (arg_expr, pat) in iter::zip(self_args, patterns) { body = cx.expr_match( trait_.span, arg_expr.clone(), @@ -1351,7 +1351,7 @@ impl<'a> MethodDef<'a> { let mut discriminant_test = cx.expr_bool(sp, true); let mut first_ident = None; - for (&ident, self_arg) in vi_idents.iter().zip(&self_args) { + for (&ident, self_arg) in iter::zip(&vi_idents, &self_args) { let self_addr = cx.expr_addr_of(sp, self_arg.clone()); let variant_value = deriving::call_intrinsic(cx, sp, sym::discriminant_value, vec![self_addr]); @@ -1571,9 +1571,7 @@ impl<'a> TraitDef<'a> { let subpats = self.create_subpatterns(cx, paths, mutbl, use_temporaries); let pattern = match *struct_def { VariantData::Struct(..) => { - let field_pats = subpats - .into_iter() - .zip(&ident_exprs) + let field_pats = iter::zip(subpats, &ident_exprs) .map(|(pat, &(sp, ident, ..))| { if ident.is_none() { cx.span_bug(sp, "a braced struct with unnamed fields in `derive`"); diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs index fe4bede6a48..d7926ed0e0b 100644 --- a/compiler/rustc_builtin_macros/src/lib.rs +++ b/compiler/rustc_builtin_macros/src/lib.rs @@ -7,6 +7,7 @@ #![feature(bool_to_option)] #![feature(crate_visibility_modifier)] #![feature(decl_macro)] +#![feature(iter_zip)] #![feature(nll)] #![cfg_attr(bootstrap, feature(or_patterns))] #![feature(proc_macro_internals)] diff --git a/compiler/rustc_codegen_cranelift/.github/workflows/bootstrap_rustc.yml b/compiler/rustc_codegen_cranelift/.github/workflows/bootstrap_rustc.yml deleted file mode 100644 index 8c94a0aa5e6..00000000000 --- a/compiler/rustc_codegen_cranelift/.github/workflows/bootstrap_rustc.yml +++ /dev/null @@ -1,44 +0,0 @@ -name: Bootstrap rustc using cg_clif - -on: - - push - -jobs: - bootstrap_rustc: - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v2 - - - name: Cache cargo installed crates - uses: actions/cache@v2 - with: - path: ~/.cargo/bin - key: ${{ runner.os }}-cargo-installed-crates - - - name: Cache cargo registry and index - uses: actions/cache@v2 - with: - path: | - ~/.cargo/registry - ~/.cargo/git - key: ${{ runner.os }}-cargo-registry-and-index-${{ hashFiles('**/Cargo.lock') }} - - - name: Cache cargo target dir - uses: actions/cache@v2 - with: - path: target - key: ${{ runner.os }}-cargo-build-target-${{ hashFiles('rust-toolchain', '**/Cargo.lock') }} - - - name: Prepare dependencies - run: | - git config --global user.email "user@example.com" - git config --global user.name "User" - ./prepare.sh - - - name: Test - run: | - # Enable backtraces for easier debugging - export RUST_BACKTRACE=1 - - ./scripts/test_bootstrap.sh diff --git a/compiler/rustc_codegen_cranelift/.github/workflows/main.yml b/compiler/rustc_codegen_cranelift/.github/workflows/main.yml index e6d3375fb1b..2ac516381cf 100644 --- a/compiler/rustc_codegen_cranelift/.github/workflows/main.yml +++ b/compiler/rustc_codegen_cranelift/.github/workflows/main.yml @@ -7,11 +7,18 @@ on: jobs: build: runs-on: ${{ matrix.os }} + timeout-minutes: 60 strategy: fail-fast: false matrix: - os: [ubuntu-latest, macos-latest] + include: + - os: ubuntu-latest + - os: macos-latest + # cross-compile from Linux to Windows using mingw + - os: ubuntu-latest + env: + TARGET_TRIPLE: x86_64-pc-windows-gnu steps: - uses: actions/checkout@v2 @@ -36,6 +43,12 @@ jobs: path: target key: ${{ runner.os }}-cargo-build-target-${{ hashFiles('rust-toolchain', '**/Cargo.lock') }} + - name: Install MinGW toolchain and wine + if: matrix.os == 'ubuntu-latest' && matrix.env.TARGET_TRIPLE == 'x86_64-pc-windows-gnu' + run: | + sudo apt-get install -y gcc-mingw-w64-x86-64 wine-stable + rustup target add x86_64-pc-windows-gnu + - name: Prepare dependencies run: | git config --global user.email "user@example.com" @@ -43,6 +56,8 @@ jobs: ./prepare.sh - name: Test + env: + TARGET_TRIPLE: ${{ matrix.env.TARGET_TRIPLE }} run: | # Enable backtraces for easier debugging export RUST_BACKTRACE=1 @@ -51,12 +66,16 @@ jobs: export COMPILE_RUNS=2 export RUN_RUNS=2 + # Enable extra checks + export CG_CLIF_ENABLE_VERIFIER=1 + ./test.sh - name: Package prebuilt cg_clif run: tar cvfJ cg_clif.tar.xz build - name: Upload prebuilt cg_clif + if: matrix.env.TARGET_TRIPLE != 'x86_64-pc-windows-gnu' uses: actions/upload-artifact@v2 with: name: cg_clif-${{ runner.os }} diff --git a/compiler/rustc_codegen_cranelift/.github/workflows/rustc.yml b/compiler/rustc_codegen_cranelift/.github/workflows/rustc.yml new file mode 100644 index 00000000000..e01a92598ba --- /dev/null +++ b/compiler/rustc_codegen_cranelift/.github/workflows/rustc.yml @@ -0,0 +1,82 @@ +name: Various rustc tests + +on: + - push + +jobs: + bootstrap_rustc: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + + - name: Cache cargo installed crates + uses: actions/cache@v2 + with: + path: ~/.cargo/bin + key: ${{ runner.os }}-cargo-installed-crates + + - name: Cache cargo registry and index + uses: actions/cache@v2 + with: + path: | + ~/.cargo/registry + ~/.cargo/git + key: ${{ runner.os }}-cargo-registry-and-index-${{ hashFiles('**/Cargo.lock') }} + + - name: Cache cargo target dir + uses: actions/cache@v2 + with: + path: target + key: ${{ runner.os }}-cargo-build-target-${{ hashFiles('rust-toolchain', '**/Cargo.lock') }} + + - name: Prepare dependencies + run: | + git config --global user.email "user@example.com" + git config --global user.name "User" + ./prepare.sh + + - name: Test + run: | + # Enable backtraces for easier debugging + export RUST_BACKTRACE=1 + + ./scripts/test_bootstrap.sh + rustc_test_suite: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + + - name: Cache cargo installed crates + uses: actions/cache@v2 + with: + path: ~/.cargo/bin + key: ${{ runner.os }}-cargo-installed-crates + + - name: Cache cargo registry and index + uses: actions/cache@v2 + with: + path: | + ~/.cargo/registry + ~/.cargo/git + key: ${{ runner.os }}-cargo-registry-and-index-${{ hashFiles('**/Cargo.lock') }} + + - name: Cache cargo target dir + uses: actions/cache@v2 + with: + path: target + key: ${{ runner.os }}-cargo-build-target-${{ hashFiles('rust-toolchain', '**/Cargo.lock') }} + + - name: Prepare dependencies + run: | + git config --global user.email "user@example.com" + git config --global user.name "User" + ./prepare.sh + + - name: Test + run: | + # Enable backtraces for easier debugging + export RUST_BACKTRACE=1 + + ./scripts/test_rustc_tests.sh diff --git a/compiler/rustc_codegen_cranelift/.vscode/settings.json b/compiler/rustc_codegen_cranelift/.vscode/settings.json index a13d5931ffa..0cd576e160f 100644 --- a/compiler/rustc_codegen_cranelift/.vscode/settings.json +++ b/compiler/rustc_codegen_cranelift/.vscode/settings.json @@ -2,7 +2,7 @@ // source for rustc_* is not included in the rust-src component; disable the errors about this "rust-analyzer.diagnostics.disabled": ["unresolved-extern-crate", "macro-error"], "rust-analyzer.assist.importMergeBehavior": "last", - "rust-analyzer.cargo.loadOutDirsFromCheck": true, + "rust-analyzer.cargo.runBuildScripts": true, "rust-analyzer.linkedProjects": [ "./Cargo.toml", //"./build_sysroot/sysroot_src/src/libstd/Cargo.toml", diff --git a/compiler/rustc_codegen_cranelift/Cargo.lock b/compiler/rustc_codegen_cranelift/Cargo.lock index 76d9f0d27ce..3cb67032aaa 100644 --- a/compiler/rustc_codegen_cranelift/Cargo.lock +++ b/compiler/rustc_codegen_cranelift/Cargo.lock @@ -39,16 +39,16 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "cranelift-bforest" -version = "0.70.0" -source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#cdb60ec5a9df087262ae8960a31067e88cd80058" +version = "0.72.0" +source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#8e43e96410a14143d368273cf1e708f8094bb8e0" dependencies = [ "cranelift-entity", ] [[package]] name = "cranelift-codegen" -version = "0.70.0" -source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#cdb60ec5a9df087262ae8960a31067e88cd80058" +version = "0.72.0" +source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#8e43e96410a14143d368273cf1e708f8094bb8e0" dependencies = [ "byteorder", "cranelift-bforest", @@ -65,8 +65,8 @@ dependencies = [ [[package]] name = "cranelift-codegen-meta" -version = "0.70.0" -source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#cdb60ec5a9df087262ae8960a31067e88cd80058" +version = "0.72.0" +source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#8e43e96410a14143d368273cf1e708f8094bb8e0" dependencies = [ "cranelift-codegen-shared", "cranelift-entity", @@ -74,18 +74,18 @@ dependencies = [ [[package]] name = "cranelift-codegen-shared" -version = "0.70.0" -source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#cdb60ec5a9df087262ae8960a31067e88cd80058" +version = "0.72.0" +source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#8e43e96410a14143d368273cf1e708f8094bb8e0" [[package]] name = "cranelift-entity" -version = "0.70.0" -source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#cdb60ec5a9df087262ae8960a31067e88cd80058" +version = "0.72.0" +source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#8e43e96410a14143d368273cf1e708f8094bb8e0" [[package]] name = "cranelift-frontend" -version = "0.70.0" -source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#cdb60ec5a9df087262ae8960a31067e88cd80058" +version = "0.72.0" +source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#8e43e96410a14143d368273cf1e708f8094bb8e0" dependencies = [ "cranelift-codegen", "log", @@ -95,8 +95,8 @@ dependencies = [ [[package]] name = "cranelift-jit" -version = "0.70.0" -source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#cdb60ec5a9df087262ae8960a31067e88cd80058" +version = "0.72.0" +source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#8e43e96410a14143d368273cf1e708f8094bb8e0" dependencies = [ "anyhow", "cranelift-codegen", @@ -113,8 +113,8 @@ dependencies = [ [[package]] name = "cranelift-module" -version = "0.70.0" -source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#cdb60ec5a9df087262ae8960a31067e88cd80058" +version = "0.72.0" +source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#8e43e96410a14143d368273cf1e708f8094bb8e0" dependencies = [ "anyhow", "cranelift-codegen", @@ -125,8 +125,8 @@ dependencies = [ [[package]] name = "cranelift-native" -version = "0.70.0" -source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#cdb60ec5a9df087262ae8960a31067e88cd80058" +version = "0.72.0" +source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#8e43e96410a14143d368273cf1e708f8094bb8e0" dependencies = [ "cranelift-codegen", "target-lexicon", @@ -134,8 +134,8 @@ dependencies = [ [[package]] name = "cranelift-object" -version = "0.70.0" -source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#cdb60ec5a9df087262ae8960a31067e88cd80058" +version = "0.72.0" +source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#8e43e96410a14143d368273cf1e708f8094bb8e0" dependencies = [ "anyhow", "cranelift-codegen", @@ -241,6 +241,15 @@ dependencies = [ ] [[package]] +name = "memmap2" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04e3e85b970d650e2ae6d70592474087051c11c54da7f7b4949725c5735fbcc6" +dependencies = [ + "libc", +] + +[[package]] name = "object" version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -310,6 +319,7 @@ dependencies = [ "gimli", "indexmap", "libloading", + "memmap2", "object", "smallvec", "target-lexicon", diff --git a/compiler/rustc_codegen_cranelift/Cargo.toml b/compiler/rustc_codegen_cranelift/Cargo.toml index 9861af1f8ea..59542c414fa 100644 --- a/compiler/rustc_codegen_cranelift/Cargo.toml +++ b/compiler/rustc_codegen_cranelift/Cargo.toml @@ -16,12 +16,13 @@ cranelift-jit = { git = "https://github.com/bytecodealliance/wasmtime/", branch cranelift-object = { git = "https://github.com/bytecodealliance/wasmtime/", branch = "main" } target-lexicon = "0.11.0" gimli = { version = "0.23.0", default-features = false, features = ["write"]} -object = { version = "0.23.0", default-features = false, features = ["std", "read_core", "write", "coff", "elf", "macho", "pe"] } +object = { version = "0.23.0", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] } ar = { git = "https://github.com/bjorn3/rust-ar.git", branch = "do_not_remove_cg_clif_ranlib" } indexmap = "1.0.2" libloading = { version = "0.6.0", optional = true } smallvec = "1.6.1" +memmap2 = "0.2.1" # Uncomment to use local checkout of cranelift #[patch."https://github.com/bytecodealliance/wasmtime/"] @@ -75,3 +76,6 @@ debug = false [profile.release.package.syn] opt-level = 0 debug = false + +[package.metadata.rust-analyzer] +rustc_private = true diff --git a/compiler/rustc_codegen_cranelift/Readme.md b/compiler/rustc_codegen_cranelift/Readme.md index 6fa5eebdc2f..ffe1d9a1e65 100644 --- a/compiler/rustc_codegen_cranelift/Readme.md +++ b/compiler/rustc_codegen_cranelift/Readme.md @@ -34,70 +34,19 @@ rustc_codegen_cranelift can be used as a near-drop-in replacement for `cargo bui Assuming `$cg_clif_dir` is the directory you cloned this repo into and you followed the instructions (`prepare.sh` and `build.sh` or `test.sh`). -### Cargo - In the directory with your project (where you can do the usual `cargo build`), run: ```bash -$ $cg_clif_dir/build/cargo.sh run -``` - -This should build and run your project with rustc_codegen_cranelift instead of the usual LLVM backend. - -### Rustc - -> You should prefer using the Cargo method. - -```bash -$ $cg_clif_dir/build/bin/cg_clif my_crate.rs -``` - -### Jit mode - -In jit mode cg_clif will immediately execute your code without creating an executable file. - -> This requires all dependencies to be available as dynamic library. -> The jit mode will probably need cargo integration to make this possible. - -```bash -$ $cg_clif_dir/build/cargo.sh jit -``` - -or - -```bash -$ $cg_clif_dir/build/bin/cg_clif -Cllvm-args=mode=jit -Cprefer-dynamic my_crate.rs -``` - -There is also an experimental lazy jit mode. In this mode functions are only compiled once they are -first called. It currently does not work with multi-threaded programs. When a not yet compiled -function is called from another thread than the main thread, you will get an ICE. - -```bash -$ $cg_clif_dir/build/cargo.sh lazy-jit +$ $cg_clif_dir/build/cargo.sh build ``` -### Shell - -These are a few functions that allow you to easily run rust code from the shell using cg_clif as jit. - -```bash -function jit_naked() { - echo "$@" | $cg_clif_dir/build/bin/cg_clif - -Cllvm-args=mode=jit -Cprefer-dynamic -} - -function jit() { - jit_naked "fn main() { $@ }" -} +This will build your project with rustc_codegen_cranelift instead of the usual LLVM backend. -function jit_calc() { - jit 'println!("0x{:x}", ' $@ ');'; -} -``` +For additional ways to use rustc_codegen_cranelift like the JIT mode see [usage.md](docs/usage.md). ## Env vars -[see env_vars.md](docs/env_vars.md) +See [env_vars.md](docs/env_vars.md) for all env vars used by rustc_codegen_cranelift. ## Not yet supported @@ -106,3 +55,20 @@ function jit_calc() { `llvm_asm!` will remain unimplemented forever. `asm!` doesn't yet support reg classes. You have to specify specific registers instead. * SIMD ([tracked here](https://github.com/bjorn3/rustc_codegen_cranelift/issues/171), some basic things work) + +## License + +Licensed under either of + + * Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or + http://www.apache.org/licenses/LICENSE-2.0) + * MIT license ([LICENSE-MIT](LICENSE-MIT) or + http://opensource.org/licenses/MIT) + +at your option. + +### Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in the work by you shall be dual licensed as above, without any +additional terms or conditions. diff --git a/compiler/rustc_codegen_cranelift/build.sh b/compiler/rustc_codegen_cranelift/build.sh index 090349e54b1..76bc1884334 100755 --- a/compiler/rustc_codegen_cranelift/build.sh +++ b/compiler/rustc_codegen_cranelift/build.sh @@ -55,6 +55,7 @@ ln target/$CHANNEL/*rustc_codegen_cranelift* "$target_dir"/lib ln rust-toolchain scripts/config.sh scripts/cargo.sh "$target_dir" mkdir -p "$target_dir/lib/rustlib/$TARGET_TRIPLE/lib/" +mkdir -p "$target_dir/lib/rustlib/$HOST_TRIPLE/lib/" if [[ "$TARGET_TRIPLE" == "x86_64-pc-windows-gnu" ]]; then cp $(rustc --print sysroot)/lib/rustlib/$TARGET_TRIPLE/lib/*.o "$target_dir/lib/rustlib/$TARGET_TRIPLE/lib/" fi @@ -64,12 +65,18 @@ case "$build_sysroot" in ;; "llvm") cp -r $(rustc --print sysroot)/lib/rustlib/$TARGET_TRIPLE/lib "$target_dir/lib/rustlib/$TARGET_TRIPLE/" + if [[ "$HOST_TRIPLE" != "$TARGET_TRIPLE" ]]; then + cp -r $(rustc --print sysroot)/lib/rustlib/$HOST_TRIPLE/lib "$target_dir/lib/rustlib/$HOST_TRIPLE/" + fi ;; "clif") echo "[BUILD] sysroot" dir=$(pwd) cd "$target_dir" time "$dir/build_sysroot/build_sysroot.sh" + if [[ "$HOST_TRIPLE" != "$TARGET_TRIPLE" ]]; then + time TARGET_TRIPLE="$HOST_TRIPLE" "$dir/build_sysroot/build_sysroot.sh" + fi cp lib/rustlib/*/lib/libstd-* lib/ ;; *) diff --git a/compiler/rustc_codegen_cranelift/build_sysroot/Cargo.lock b/compiler/rustc_codegen_cranelift/build_sysroot/Cargo.lock index a7650ab995b..09c5d7590ab 100644 --- a/compiler/rustc_codegen_cranelift/build_sysroot/Cargo.lock +++ b/compiler/rustc_codegen_cranelift/build_sysroot/Cargo.lock @@ -16,9 +16,9 @@ dependencies = [ [[package]] name = "adler" -version = "0.2.3" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee2a4ec343196209d6594e19543ae87a39f96d5534d7174822a3ad825dd6ed7e" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" dependencies = [ "compiler_builtins", "rustc-std-workspace-core", @@ -110,9 +110,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.9.1" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04" +checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" dependencies = [ "compiler_builtins", "rustc-std-workspace-alloc", @@ -132,18 +132,18 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.86" +version = "0.2.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7282d924be3275cec7f6756ff4121987bc6481325397dde6ba3e7802b1a8b1c" +checksum = "8916b1f6ca17130ec6568feccee27c156ad12037880833a3b842a823236502e7" dependencies = [ "rustc-std-workspace-core", ] [[package]] name = "miniz_oxide" -version = "0.4.3" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f2d26ec3309788e423cfbf68ad1800f061638098d76a83681af979dc4eda19d" +checksum = "a92518e98c078586bc6c934028adcca4c92a53d6a958196de835170a01d84e4b" dependencies = [ "adler", "autocfg", diff --git a/compiler/rustc_codegen_cranelift/build_sysroot/build_sysroot.sh b/compiler/rustc_codegen_cranelift/build_sysroot/build_sysroot.sh index 636aa5f3f3d..0354304e55b 100755 --- a/compiler/rustc_codegen_cranelift/build_sysroot/build_sysroot.sh +++ b/compiler/rustc_codegen_cranelift/build_sysroot/build_sysroot.sh @@ -28,7 +28,7 @@ export __CARGO_DEFAULT_LIB_METADATA="cg_clif" if [[ "$1" != "--debug" ]]; then sysroot_channel='release' # FIXME Enable incremental again once rust-lang/rust#74946 is fixed - CARGO_INCREMENTAL=0 RUSTFLAGS="$RUSTFLAGS -Zmir-opt-level=2" cargo build --target "$TARGET_TRIPLE" --release + CARGO_INCREMENTAL=0 RUSTFLAGS="$RUSTFLAGS -Zmir-opt-level=3" cargo build --target "$TARGET_TRIPLE" --release else sysroot_channel='debug' cargo build --target "$TARGET_TRIPLE" diff --git a/compiler/rustc_codegen_cranelift/docs/env_vars.md b/compiler/rustc_codegen_cranelift/docs/env_vars.md index f0a0a6ad42e..f7fde1b4f3a 100644 --- a/compiler/rustc_codegen_cranelift/docs/env_vars.md +++ b/compiler/rustc_codegen_cranelift/docs/env_vars.md @@ -8,5 +8,8 @@ to make it possible to use incremental mode for all analyses performed by rustc without caching object files when their content should have been changed by a change to cg_clif.</dd> <dt>CG_CLIF_DISPLAY_CG_TIME</dt> - <dd>If "1", display the time it took to perform codegen for a crate</dd> + <dd>If "1", display the time it took to perform codegen for a crate.</dd> + <dt>CG_CLIF_ENABLE_VERIFIER</dt> + <dd>Enable the Cranelift ir verifier for all compilation passes. If not set it will only run once + before passing the clif ir to Cranelift for compilation.</dt> </dl> diff --git a/compiler/rustc_codegen_cranelift/docs/usage.md b/compiler/rustc_codegen_cranelift/docs/usage.md new file mode 100644 index 00000000000..3eee3b554e3 --- /dev/null +++ b/compiler/rustc_codegen_cranelift/docs/usage.md @@ -0,0 +1,66 @@ +# Usage + +rustc_codegen_cranelift can be used as a near-drop-in replacement for `cargo build` or `cargo run` for existing projects. + +Assuming `$cg_clif_dir` is the directory you cloned this repo into and you followed the instructions (`prepare.sh` and `build.sh` or `test.sh`). + +## Cargo + +In the directory with your project (where you can do the usual `cargo build`), run: + +```bash +$ $cg_clif_dir/build/cargo.sh build +``` + +This will build your project with rustc_codegen_cranelift instead of the usual LLVM backend. + +## Rustc + +> You should prefer using the Cargo method. + +```bash +$ $cg_clif_dir/build/bin/cg_clif my_crate.rs +``` + +## Jit mode + +In jit mode cg_clif will immediately execute your code without creating an executable file. + +> This requires all dependencies to be available as dynamic library. +> The jit mode will probably need cargo integration to make this possible. + +```bash +$ $cg_clif_dir/build/cargo.sh jit +``` + +or + +```bash +$ $cg_clif_dir/build/bin/cg_clif -Cllvm-args=mode=jit -Cprefer-dynamic my_crate.rs +``` + +There is also an experimental lazy jit mode. In this mode functions are only compiled once they are +first called. It currently does not work with multi-threaded programs. When a not yet compiled +function is called from another thread than the main thread, you will get an ICE. + +```bash +$ $cg_clif_dir/build/cargo.sh lazy-jit +``` + +## Shell + +These are a few functions that allow you to easily run rust code from the shell using cg_clif as jit. + +```bash +function jit_naked() { + echo "$@" | $cg_clif_dir/build/bin/cg_clif - -Cllvm-args=mode=jit -Cprefer-dynamic +} + +function jit() { + jit_naked "fn main() { $@ }" +} + +function jit_calc() { + jit 'println!("0x{:x}", ' $@ ');'; +} +``` diff --git a/compiler/rustc_codegen_cranelift/example/mini_core.rs b/compiler/rustc_codegen_cranelift/example/mini_core.rs index 7c6d7fc106d..c4834c80408 100644 --- a/compiler/rustc_codegen_cranelift/example/mini_core.rs +++ b/compiler/rustc_codegen_cranelift/example/mini_core.rs @@ -621,6 +621,7 @@ struct PanicLocation { } #[no_mangle] +#[cfg(not(windows))] pub fn get_tls() -> u8 { #[thread_local] static A: u8 = 42; diff --git a/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs b/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs index 237f4d11d57..ea37ca98b59 100644 --- a/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs +++ b/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs @@ -1,7 +1,4 @@ -#![feature( - no_core, start, lang_items, box_syntax, never_type, linkage, - extern_types, thread_local -)] +#![feature(no_core, lang_items, box_syntax, never_type, linkage, extern_types, thread_local)] #![no_core] #![allow(dead_code, non_camel_case_types)] @@ -239,7 +236,7 @@ fn main() { assert_eq!(((|()| 42u8) as fn(()) -> u8)(()), 42); - #[cfg(not(jit))] + #[cfg(not(any(jit, windows)))] { extern { #[linkage = "extern_weak"] @@ -292,7 +289,7 @@ fn main() { from_decimal_string(); - #[cfg(not(jit))] + #[cfg(not(any(jit, windows)))] test_tls(); #[cfg(all(not(jit), target_os = "linux"))] diff --git a/compiler/rustc_codegen_cranelift/prepare.sh b/compiler/rustc_codegen_cranelift/prepare.sh index ee995ffcfa9..64c097261c9 100755 --- a/compiler/rustc_codegen_cranelift/prepare.sh +++ b/compiler/rustc_codegen_cranelift/prepare.sh @@ -1,7 +1,6 @@ #!/usr/bin/env bash set -e -rustup component add rust-src rustc-dev llvm-tools-preview ./build_sysroot/prepare_sysroot_src.sh cargo install hyperfine || echo "Skipping hyperfine install" diff --git a/compiler/rustc_codegen_cranelift/rust-toolchain b/compiler/rustc_codegen_cranelift/rust-toolchain index 908ca52135b..2917fc7ee39 100644 --- a/compiler/rustc_codegen_cranelift/rust-toolchain +++ b/compiler/rustc_codegen_cranelift/rust-toolchain @@ -1 +1,3 @@ -nightly-2021-03-05 +[toolchain] +channel = "nightly-2021-03-29" +components = ["rust-src", "rustc-dev", "llvm-tools-preview"] diff --git a/compiler/rustc_codegen_cranelift/scripts/cargo.sh b/compiler/rustc_codegen_cranelift/scripts/cargo.sh index 669d2d45b71..1daa5a78f7b 100755 --- a/compiler/rustc_codegen_cranelift/scripts/cargo.sh +++ b/compiler/rustc_codegen_cranelift/scripts/cargo.sh @@ -4,7 +4,7 @@ dir=$(dirname "$0") source "$dir/config.sh" # read nightly compiler from rust-toolchain file -TOOLCHAIN=$(cat "$dir/rust-toolchain") +TOOLCHAIN=$(cat "$dir/rust-toolchain" | grep channel | sed "s/channel = \"\(.*\)\"/\1/") cmd=$1 shift || true diff --git a/compiler/rustc_codegen_cranelift/scripts/config.sh b/compiler/rustc_codegen_cranelift/scripts/config.sh index c2ed2bf256d..99b302ee1d9 100644 --- a/compiler/rustc_codegen_cranelift/scripts/config.sh +++ b/compiler/rustc_codegen_cranelift/scripts/config.sh @@ -2,15 +2,7 @@ set -e -unamestr=$(uname) -if [[ "$unamestr" == 'Linux' || "$unamestr" == 'FreeBSD' ]]; then - dylib_ext='so' -elif [[ "$unamestr" == 'Darwin' ]]; then - dylib_ext='dylib' -else - echo "Unsupported os" - exit 1 -fi +dylib=$(echo "" | rustc --print file-names --crate-type dylib --crate-name rustc_codegen_cranelift -) if echo "$RUSTC_WRAPPER" | grep sccache; then echo @@ -24,10 +16,10 @@ dir=$(cd "$(dirname "${BASH_SOURCE[0]}")"; pwd) export RUSTC=$dir"/bin/cg_clif" export RUSTDOCFLAGS=$linker' -Cpanic=abort -Zpanic-abort-tests '\ -'-Zcodegen-backend='$dir'/lib/librustc_codegen_cranelift.'$dylib_ext' --sysroot '$dir +'-Zcodegen-backend='$dir'/lib/'$dylib' --sysroot '$dir # FIXME fix `#[linkage = "extern_weak"]` without this -if [[ "$unamestr" == 'Darwin' ]]; then +if [[ "$(uname)" == 'Darwin' ]]; then export RUSTFLAGS="$RUSTFLAGS -Clink-arg=-undefined -Clink-arg=dynamic_lookup" fi diff --git a/compiler/rustc_codegen_cranelift/scripts/rustup.sh b/compiler/rustc_codegen_cranelift/scripts/rustup.sh index 694945a87c2..fa7557653d8 100755 --- a/compiler/rustc_codegen_cranelift/scripts/rustup.sh +++ b/compiler/rustc_codegen_cranelift/scripts/rustup.sh @@ -8,7 +8,7 @@ case $1 in echo "=> Installing new nightly" rustup toolchain install --profile minimal "nightly-${TOOLCHAIN}" # Sanity check to see if the nightly exists - echo "nightly-${TOOLCHAIN}" > rust-toolchain + sed -i "s/\"nightly-.*\"/\"nightly-${TOOLCHAIN}\"/" rust-toolchain rustup component add rustfmt || true echo "=> Uninstalling all old nighlies" diff --git a/compiler/rustc_codegen_cranelift/scripts/setup_rust_fork.sh b/compiler/rustc_codegen_cranelift/scripts/setup_rust_fork.sh new file mode 100644 index 00000000000..e8bedf625f7 --- /dev/null +++ b/compiler/rustc_codegen_cranelift/scripts/setup_rust_fork.sh @@ -0,0 +1,68 @@ +#!/bin/bash +set -e + +./build.sh +source build/config.sh + +echo "[SETUP] Rust fork" +git clone https://github.com/rust-lang/rust.git || true +pushd rust +git fetch +git checkout -- . +git checkout "$(rustc -V | cut -d' ' -f3 | tr -d '(')" + +git apply - <<EOF +diff --git a/Cargo.toml b/Cargo.toml +index 5bd1147cad5..10d68a2ff14 100644 +--- a/Cargo.toml ++++ b/Cargo.toml +@@ -111,5 +111,7 @@ rustc-std-workspace-std = { path = 'library/rustc-std-workspace-std' } + rustc-std-workspace-alloc = { path = 'library/rustc-std-workspace-alloc' } + rustc-std-workspace-std = { path = 'library/rustc-std-workspace-std' } + ++compiler_builtins = { path = "../build_sysroot/compiler-builtins" } ++ + [patch."https://github.com/rust-lang/rust-clippy"] + clippy_lints = { path = "src/tools/clippy/clippy_lints" } +diff --git a/compiler/rustc_data_structures/Cargo.toml b/compiler/rustc_data_structures/Cargo.toml +index 23e689fcae7..5f077b765b6 100644 +--- a/compiler/rustc_data_structures/Cargo.toml ++++ b/compiler/rustc_data_structures/Cargo.toml +@@ -32,7 +32,6 @@ tempfile = "3.0.5" + + [dependencies.parking_lot] + version = "0.11" +-features = ["nightly"] + + [target.'cfg(windows)'.dependencies] + winapi = { version = "0.3", features = ["fileapi", "psapi"] } +diff --git a/library/alloc/Cargo.toml b/library/alloc/Cargo.toml +index d95b5b7f17f..00b6f0e3635 100644 +--- a/library/alloc/Cargo.toml ++++ b/library/alloc/Cargo.toml +@@ -8,7 +8,7 @@ edition = "2018" + + [dependencies] + core = { path = "../core" } +-compiler_builtins = { version = "0.1.39", features = ['rustc-dep-of-std'] } ++compiler_builtins = { version = "0.1.39", features = ['rustc-dep-of-std', 'no-asm'] } + + [dev-dependencies] + rand = "0.7" +EOF + +cat > config.toml <<EOF +[llvm] +ninja = false + +[build] +rustc = "$(pwd)/../build/bin/cg_clif" +cargo = "$(rustup which cargo)" +full-bootstrap = true +local-rebuild = true + +[rust] +codegen-backends = ["cranelift"] +deny-warnings = false +EOF +popd diff --git a/compiler/rustc_codegen_cranelift/scripts/test_bootstrap.sh b/compiler/rustc_codegen_cranelift/scripts/test_bootstrap.sh index 6473c6ad67d..791d457993d 100755 --- a/compiler/rustc_codegen_cranelift/scripts/test_bootstrap.sh +++ b/compiler/rustc_codegen_cranelift/scripts/test_bootstrap.sh @@ -3,70 +3,10 @@ set -e cd "$(dirname "$0")/../" -./build.sh -source build/config.sh +source ./scripts/setup_rust_fork.sh echo "[TEST] Bootstrap of rustc" -git clone https://github.com/rust-lang/rust.git || true pushd rust -git fetch -git checkout -- . -git checkout "$(rustc -V | cut -d' ' -f3 | tr -d '(')" - -git apply - <<EOF -diff --git a/Cargo.toml b/Cargo.toml -index 5bd1147cad5..10d68a2ff14 100644 ---- a/Cargo.toml -+++ b/Cargo.toml -@@ -111,5 +111,7 @@ rustc-std-workspace-std = { path = 'library/rustc-std-workspace-std' } - rustc-std-workspace-alloc = { path = 'library/rustc-std-workspace-alloc' } - rustc-std-workspace-std = { path = 'library/rustc-std-workspace-std' } - -+compiler_builtins = { path = "../build_sysroot/compiler-builtins" } -+ - [patch."https://github.com/rust-lang/rust-clippy"] - clippy_lints = { path = "src/tools/clippy/clippy_lints" } -diff --git a/compiler/rustc_data_structures/Cargo.toml b/compiler/rustc_data_structures/Cargo.toml -index 23e689fcae7..5f077b765b6 100644 ---- a/compiler/rustc_data_structures/Cargo.toml -+++ b/compiler/rustc_data_structures/Cargo.toml -@@ -32,7 +32,6 @@ tempfile = "3.0.5" - - [dependencies.parking_lot] - version = "0.11" --features = ["nightly"] - - [target.'cfg(windows)'.dependencies] - winapi = { version = "0.3", features = ["fileapi", "psapi"] } -diff --git a/library/alloc/Cargo.toml b/library/alloc/Cargo.toml -index d95b5b7f17f..00b6f0e3635 100644 ---- a/library/alloc/Cargo.toml -+++ b/library/alloc/Cargo.toml -@@ -8,7 +8,7 @@ edition = "2018" - - [dependencies] - core = { path = "../core" } --compiler_builtins = { version = "0.1.39", features = ['rustc-dep-of-std'] } -+compiler_builtins = { version = "0.1.39", features = ['rustc-dep-of-std', 'no-asm'] } - - [dev-dependencies] - rand = "0.7" -EOF - -cat > config.toml <<EOF -[llvm] -ninja = false - -[build] -rustc = "$(pwd)/../build/bin/cg_clif" -cargo = "$(rustup which cargo)" -full-bootstrap = true -local-rebuild = true - -[rust] -codegen-backends = ["cranelift"] -EOF - rm -r compiler/rustc_codegen_cranelift/{Cargo.*,src} cp ../Cargo.* compiler/rustc_codegen_cranelift/ cp -r ../src compiler/rustc_codegen_cranelift/src diff --git a/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh b/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh new file mode 100755 index 00000000000..fbc3feceec7 --- /dev/null +++ b/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh @@ -0,0 +1,87 @@ +#!/bin/bash +set -e + +cd $(dirname "$0")/../ + +source ./scripts/setup_rust_fork.sh + +echo "[TEST] Test suite of rustc" +pushd rust + +cargo install ripgrep + +rm -r src/test/ui/{extern/,panics/,unsized-locals/,thinlto/,simd*,*lto*.rs,linkage*,unwind-*.rs} || true +for test in $(rg --files-with-matches "asm!|catch_unwind|should_panic|lto" src/test/ui); do + rm $test +done + +for test in $(rg -i --files-with-matches "//(\[\w+\])?~|// error-pattern:|// build-fail|// run-fail|-Cllvm-args" src/test/ui); do + rm $test +done + +git checkout -- src/test/ui/issues/auxiliary/issue-3136-a.rs # contains //~ERROR, but shouldn't be removed + +# these all depend on unwinding support +rm src/test/ui/backtrace.rs +rm src/test/ui/array-slice-vec/box-of-array-of-drop-*.rs +rm src/test/ui/array-slice-vec/slice-panic-*.rs +rm src/test/ui/array-slice-vec/nested-vec-3.rs +rm src/test/ui/cleanup-rvalue-temp-during-incomplete-alloc.rs +rm src/test/ui/issues/issue-26655.rs +rm src/test/ui/issues/issue-29485.rs +rm src/test/ui/issues/issue-30018-panic.rs +rm src/test/ui/multi-panic.rs +rm src/test/ui/sepcomp/sepcomp-unwind.rs +rm src/test/ui/structs-enums/unit-like-struct-drop-run.rs +rm src/test/ui/terminate-in-initializer.rs +rm src/test/ui/threads-sendsync/task-stderr.rs +rm src/test/ui/numbers-arithmetic/int-abs-overflow.rs +rm src/test/ui/drop/drop-trait-enum.rs +rm src/test/ui/numbers-arithmetic/issue-8460.rs + +rm src/test/ui/issues/issue-28950.rs # depends on stack size optimizations +rm src/test/ui/init-large-type.rs # same +rm src/test/ui/sse2.rs # cpuid not supported, so sse2 not detected +rm src/test/ui/issues/issue-33992.rs # unsupported linkages +rm src/test/ui/issues/issue-51947.rs # same +rm src/test/ui/numbers-arithmetic/saturating-float-casts.rs # intrinsic gives different but valid result +rm src/test/ui/mir/mir_misc_casts.rs # depends on deduplication of constants +rm src/test/ui/mir/mir_raw_fat_ptr.rs # same +rm src/test/ui/async-await/async-fn-size-moved-locals.rs # -Cpanic=abort shrinks some generator by one byte +rm src/test/ui/async-await/async-fn-size-uninit-locals.rs # same +rm src/test/ui/generator/size-moved-locals.rs # same +rm src/test/ui/fn/dyn-fn-alignment.rs # wants a 256 byte alignment +rm src/test/ui/test-attrs/test-fn-signature-verification-for-explicit-return-type.rs # "Cannot run dynamic test fn out-of-process" +rm src/test/ui/intrinsics/intrinsic-nearby.rs # unimplemented nearbyintf32 and nearbyintf64 intrinsics + +rm src/test/incremental/hashes/inline_asm.rs # inline asm +rm src/test/incremental/issue-72386.rs # same +rm src/test/incremental/change_crate_dep_kind.rs # requires -Cpanic=unwind +rm src/test/incremental/issue-49482.rs # same +rm src/test/incremental/issue-54059.rs # same +rm src/test/incremental/lto.rs # requires lto + +rm src/test/pretty/asm.rs # inline asm +rm src/test/pretty/raw-str-nonexpr.rs # same + +rm -r src/test/run-pass-valgrind/unsized-locals + +rm src/test/ui/json-bom-plus-crlf-multifile.rs # differing warning +rm src/test/ui/json-bom-plus-crlf.rs # same +rm src/test/ui/type-alias-impl-trait/cross_crate_ice*.rs # requires removed aux dep + +rm src/test/ui/allocator/no_std-alloc-error-handler-default.rs # missing rust_oom definition +rm src/test/ui/cfg/cfg-panic.rs +rm src/test/ui/default-alloc-error-hook.rs +rm -r src/test/ui/hygiene/ + +rm -r src/test/ui/polymorphization/ # polymorphization not yet supported +rm src/test/codegen-units/polymorphization/unused_type_parameters.rs # same + +rm -r src/test/run-make/fmt-write-bloat/ # tests an optimization +rm src/test/ui/abi/mir/mir_codegen_calls_variadic.rs # requires float varargs +rm src/test/ui/abi/variadic-ffi.rs # requires callee side vararg support + +echo "[TEST] rustc test suite" +RUST_TEST_NOCAPTURE=1 COMPILETEST_FORCE_STAGE0=1 ./x.py test --stage 0 src/test/{codegen-units,run-make,run-pass-valgrind,ui} +popd diff --git a/compiler/rustc_codegen_cranelift/scripts/tests.sh b/compiler/rustc_codegen_cranelift/scripts/tests.sh index f9a9fb091fb..3afcea8f06b 100755 --- a/compiler/rustc_codegen_cranelift/scripts/tests.sh +++ b/compiler/rustc_codegen_cranelift/scripts/tests.sh @@ -71,14 +71,20 @@ function base_sysroot_tests() { echo "[AOT] mod_bench" $MY_RUSTC example/mod_bench.rs --crate-type bin --target "$TARGET_TRIPLE" $RUN_WRAPPER ./target/out/mod_bench +} +function extended_sysroot_tests() { pushd rand - rm -r ./target || true - ../build/cargo.sh test --workspace + cargo clean + if [[ "$HOST_TRIPLE" = "$TARGET_TRIPLE" ]]; then + echo "[TEST] rust-random/rand" + ../build/cargo.sh test --workspace + else + echo "[AOT] rust-random/rand" + ../build/cargo.sh build --workspace --target $TARGET_TRIPLE --tests + fi popd -} -function extended_sysroot_tests() { pushd simple-raytracer if [[ "$HOST_TRIPLE" = "$TARGET_TRIPLE" ]]; then echo "[BENCH COMPILE] ebobby/simple-raytracer" @@ -92,27 +98,40 @@ function extended_sysroot_tests() { else echo "[BENCH COMPILE] ebobby/simple-raytracer (skipped)" echo "[COMPILE] ebobby/simple-raytracer" - ../cargo.sh build + ../build/cargo.sh build --target $TARGET_TRIPLE echo "[BENCH RUN] ebobby/simple-raytracer (skipped)" fi popd pushd build_sysroot/sysroot_src/library/core/tests echo "[TEST] libcore" - rm -r ./target || true - ../../../../../build/cargo.sh test + cargo clean + if [[ "$HOST_TRIPLE" = "$TARGET_TRIPLE" ]]; then + ../../../../../build/cargo.sh test + else + ../../../../../build/cargo.sh build --target $TARGET_TRIPLE --tests + fi popd pushd regex echo "[TEST] rust-lang/regex example shootout-regex-dna" - ../build/cargo.sh clean + cargo clean # Make sure `[codegen mono items] start` doesn't poison the diff - ../build/cargo.sh build --example shootout-regex-dna - cat examples/regexdna-input.txt | ../build/cargo.sh run --example shootout-regex-dna | grep -v "Spawned thread" > res.txt - diff -u res.txt examples/regexdna-output.txt + ../build/cargo.sh build --example shootout-regex-dna --target $TARGET_TRIPLE + if [[ "$HOST_TRIPLE" = "$TARGET_TRIPLE" ]]; then + cat examples/regexdna-input.txt \ + | ../build/cargo.sh run --example shootout-regex-dna --target $TARGET_TRIPLE \ + | grep -v "Spawned thread" > res.txt + diff -u res.txt examples/regexdna-output.txt + fi - echo "[TEST] rust-lang/regex tests" - ../build/cargo.sh test --tests -- --exclude-should-panic --test-threads 1 -Zunstable-options -q + if [[ "$HOST_TRIPLE" = "$TARGET_TRIPLE" ]]; then + echo "[TEST] rust-lang/regex tests" + ../build/cargo.sh test --tests -- --exclude-should-panic --test-threads 1 -Zunstable-options -q + else + echo "[AOT] rust-lang/regex tests" + ../build/cargo.sh build --tests --target $TARGET_TRIPLE + fi popd } diff --git a/compiler/rustc_codegen_cranelift/src/abi/comments.rs b/compiler/rustc_codegen_cranelift/src/abi/comments.rs index c3cf90e1e70..5fbaed7283a 100644 --- a/compiler/rustc_codegen_cranelift/src/abi/comments.rs +++ b/compiler/rustc_codegen_cranelift/src/abi/comments.rs @@ -11,9 +11,11 @@ use cranelift_codegen::entity::EntityRef; use crate::prelude::*; pub(super) fn add_args_header_comment(fx: &mut FunctionCx<'_, '_, '_>) { - fx.add_global_comment( - "kind loc.idx param pass mode ty".to_string(), - ); + if fx.clif_comments.enabled() { + fx.add_global_comment( + "kind loc.idx param pass mode ty".to_string(), + ); + } } pub(super) fn add_arg_comment<'tcx>( @@ -25,6 +27,10 @@ pub(super) fn add_arg_comment<'tcx>( arg_abi_mode: PassMode, arg_layout: TyAndLayout<'tcx>, ) { + if !fx.clif_comments.enabled() { + return; + } + let local = if let Some(local) = local { Cow::Owned(format!("{:?}", local)) } else { @@ -59,10 +65,12 @@ pub(super) fn add_arg_comment<'tcx>( } pub(super) fn add_locals_header_comment(fx: &mut FunctionCx<'_, '_, '_>) { - fx.add_global_comment(String::new()); - fx.add_global_comment( - "kind local ty size align (abi,pref)".to_string(), - ); + if fx.clif_comments.enabled() { + fx.add_global_comment(String::new()); + fx.add_global_comment( + "kind local ty size align (abi,pref)".to_string(), + ); + } } pub(super) fn add_local_place_comments<'tcx>( @@ -70,6 +78,9 @@ pub(super) fn add_local_place_comments<'tcx>( place: CPlace<'tcx>, local: Local, ) { + if !fx.clif_comments.enabled() { + return; + } let TyAndLayout { ty, layout } = place.layout(); let rustc_target::abi::Layout { size, align, abi: _, variants: _, fields: _, largest_niche: _ } = layout; @@ -90,7 +101,7 @@ pub(super) fn add_local_place_comments<'tcx>( } else { Cow::Borrowed("") }; - match ptr.base_and_offset() { + match ptr.debug_base_and_offset() { (crate::pointer::PointerBase::Addr(addr), offset) => { ("reuse", format!("storage={}{}{}", addr, offset, meta).into()) } diff --git a/compiler/rustc_codegen_cranelift/src/abi/mod.rs b/compiler/rustc_codegen_cranelift/src/abi/mod.rs index b158d73f3a1..0e7829eaa26 100644 --- a/compiler/rustc_codegen_cranelift/src/abi/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/abi/mod.rs @@ -1,6 +1,5 @@ //! Handling of everything related to the calling convention. Also fills `fx.local_map`. -#[cfg(debug_assertions)] mod comments; mod pass_mode; mod returning; @@ -75,8 +74,9 @@ impl<'tcx> FunctionCx<'_, '_, 'tcx> { let func_id = import_function(self.tcx, self.cx.module, inst); let func_ref = self.cx.module.declare_func_in_func(func_id, &mut self.bcx.func); - #[cfg(debug_assertions)] - self.add_comment(func_ref, format!("{:?}", inst)); + if self.clif_comments.enabled() { + self.add_comment(func_ref, format!("{:?}", inst)); + } func_ref } @@ -92,8 +92,7 @@ impl<'tcx> FunctionCx<'_, '_, 'tcx> { let func_id = self.cx.module.declare_function(&name, Linkage::Import, &sig).unwrap(); let func_ref = self.cx.module.declare_func_in_func(func_id, &mut self.bcx.func); let call_inst = self.bcx.ins().call(func_ref, args); - #[cfg(debug_assertions)] - { + if self.clif_comments.enabled() { self.add_comment(call_inst, format!("easy_call {}", name)); } let results = self.bcx.inst_results(call_inst); @@ -149,7 +148,6 @@ fn make_local_place<'tcx>( CPlace::new_stack_slot(fx, layout) }; - #[cfg(debug_assertions)] self::comments::add_local_place_comments(fx, place, local); place @@ -163,7 +161,6 @@ pub(crate) fn codegen_fn_prelude<'tcx>(fx: &mut FunctionCx<'_, '_, 'tcx>, start_ let ssa_analyzed = crate::analyze::analyze(fx); - #[cfg(debug_assertions)] self::comments::add_args_header_comment(fx); let mut block_params_iter = fx.bcx.func.dfg.block_params(start_block).to_vec().into_iter(); @@ -228,7 +225,6 @@ pub(crate) fn codegen_fn_prelude<'tcx>(fx: &mut FunctionCx<'_, '_, 'tcx>, start_ fx.fn_abi = Some(fn_abi); assert!(block_params_iter.next().is_none(), "arg_value left behind"); - #[cfg(debug_assertions)] self::comments::add_locals_header_comment(fx); for (local, arg_kind, ty) in func_params { @@ -256,7 +252,6 @@ pub(crate) fn codegen_fn_prelude<'tcx>(fx: &mut FunctionCx<'_, '_, 'tcx>, start_ CPlace::for_ptr(addr, val.layout()) }; - #[cfg(debug_assertions)] self::comments::add_local_place_comments(fx, place, local); assert_eq!(fx.local_map.push(place), local); @@ -392,8 +387,7 @@ pub(crate) fn codegen_terminator_call<'tcx>( let (func_ref, first_arg) = match instance { // Trait object call Some(Instance { def: InstanceDef::Virtual(_, idx), .. }) => { - #[cfg(debug_assertions)] - { + if fx.clif_comments.enabled() { let nop_inst = fx.bcx.ins().nop(); fx.add_comment( nop_inst, @@ -414,8 +408,7 @@ pub(crate) fn codegen_terminator_call<'tcx>( // Indirect call None => { - #[cfg(debug_assertions)] - { + if fx.clif_comments.enabled() { let nop_inst = fx.bcx.ins().nop(); fx.add_comment(nop_inst, "indirect call"); } @@ -477,10 +470,7 @@ pub(crate) fn codegen_terminator_call<'tcx>( // FIXME find a cleaner way to support varargs if fn_sig.c_variadic { if !matches!(fn_sig.abi, Abi::C { .. }) { - fx.tcx.sess.span_fatal( - span, - &format!("Variadic call for non-C abi {:?}", fn_sig.abi), - ); + fx.tcx.sess.span_fatal(span, &format!("Variadic call for non-C abi {:?}", fn_sig.abi)); } let sig_ref = fx.bcx.func.dfg.call_signature(call_inst).unwrap(); let abi_params = call_args diff --git a/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs b/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs index d58f952f53c..7c275965199 100644 --- a/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs +++ b/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs @@ -208,7 +208,7 @@ pub(super) fn from_casted_value<'tcx>( }); let ptr = Pointer::new(fx.bcx.ins().stack_addr(pointer_ty(fx.tcx), stack_slot, 0)); let mut offset = 0; - let mut block_params_iter = block_params.into_iter().copied(); + let mut block_params_iter = block_params.iter().copied(); for param in abi_params { let val = ptr.offset_i64(fx, offset).store( fx, @@ -248,8 +248,8 @@ pub(super) fn adjust_arg_for_abi<'tcx>( /// as necessary. pub(super) fn cvalue_for_param<'tcx>( fx: &mut FunctionCx<'_, '_, 'tcx>, - #[cfg_attr(not(debug_assertions), allow(unused_variables))] local: Option<mir::Local>, - #[cfg_attr(not(debug_assertions), allow(unused_variables))] local_field: Option<usize>, + local: Option<mir::Local>, + local_field: Option<usize>, arg_abi: &ArgAbi<'tcx, Ty<'tcx>>, block_params_iter: &mut impl Iterator<Item = Value>, ) -> Option<CValue<'tcx>> { @@ -263,7 +263,6 @@ pub(super) fn cvalue_for_param<'tcx>( }) .collect::<SmallVec<[_; 2]>>(); - #[cfg(debug_assertions)] crate::abi::comments::add_arg_comment( fx, "arg", diff --git a/compiler/rustc_codegen_cranelift/src/abi/returning.rs b/compiler/rustc_codegen_cranelift/src/abi/returning.rs index 9fa066df69b..e1c53224b4f 100644 --- a/compiler/rustc_codegen_cranelift/src/abi/returning.rs +++ b/compiler/rustc_codegen_cranelift/src/abi/returning.rs @@ -84,10 +84,6 @@ pub(super) fn codegen_return_param<'tcx>( } }; - #[cfg(not(debug_assertions))] - let _ = ret_param; - - #[cfg(debug_assertions)] crate::abi::comments::add_arg_comment( fx, "ret", @@ -146,7 +142,7 @@ pub(super) fn codegen_with_call_return_arg<'tcx, T>( let results = fx .bcx .inst_results(call_inst) - .into_iter() + .iter() .copied() .collect::<SmallVec<[Value; 2]>>(); let result = diff --git a/compiler/rustc_codegen_cranelift/src/allocator.rs b/compiler/rustc_codegen_cranelift/src/allocator.rs index efb64233ef2..f60645a9f97 100644 --- a/compiler/rustc_codegen_cranelift/src/allocator.rs +++ b/compiler/rustc_codegen_cranelift/src/allocator.rs @@ -3,6 +3,7 @@ use crate::prelude::*; +use cranelift_codegen::binemit::{NullStackMapSink, NullTrapSink}; use rustc_ast::expand::allocator::{AllocatorKind, AllocatorTy, ALLOCATOR_METHODS}; use rustc_span::symbol::sym; @@ -92,7 +93,7 @@ fn codegen_inner( bcx.finalize(); } module - .define_function(func_id, &mut ctx, &mut cranelift_codegen::binemit::NullTrapSink {}) + .define_function(func_id, &mut ctx, &mut NullTrapSink {}, &mut NullStackMapSink {}) .unwrap(); unwind_context.add_function(func_id, &ctx, module.isa()); } @@ -132,7 +133,7 @@ fn codegen_inner( bcx.finalize(); } module - .define_function(func_id, &mut ctx, &mut cranelift_codegen::binemit::NullTrapSink {}) + .define_function(func_id, &mut ctx, &mut NullTrapSink {}, &mut NullStackMapSink {}) .unwrap(); unwind_context.add_function(func_id, &ctx, module.isa()); } diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs index 8b5ae9e0541..b34a29c25b9 100644 --- a/compiler/rustc_codegen_cranelift/src/base.rs +++ b/compiler/rustc_codegen_cranelift/src/base.rs @@ -1,5 +1,6 @@ //! Codegen of a single function +use cranelift_codegen::binemit::{NullStackMapSink, NullTrapSink}; use rustc_index::vec::IndexVec; use rustc_middle::ty::adjustment::PointerCast; use rustc_middle::ty::layout::FnAbiExt; @@ -7,11 +8,7 @@ use rustc_target::abi::call::FnAbi; use crate::prelude::*; -pub(crate) fn codegen_fn<'tcx>( - cx: &mut crate::CodegenCx<'_, 'tcx>, - instance: Instance<'tcx>, - linkage: Linkage, -) { +pub(crate) fn codegen_fn<'tcx>(cx: &mut crate::CodegenCx<'_, 'tcx>, instance: Instance<'tcx>) { let tcx = cx.tcx; let _inst_guard = @@ -23,7 +20,7 @@ pub(crate) fn codegen_fn<'tcx>( // Declare function let name = tcx.symbol_name(instance).name.to_string(); let sig = get_function_sig(tcx, cx.module.isa().triple(), instance); - let func_id = cx.module.declare_function(&name, linkage, &sig).unwrap(); + let func_id = cx.module.declare_function(&name, Linkage::Local, &sig).unwrap(); cx.cached_context.clear(); @@ -131,7 +128,7 @@ pub(crate) fn codegen_fn<'tcx>( let module = &mut cx.module; tcx.sess.time("define function", || { module - .define_function(func_id, context, &mut cranelift_codegen::binemit::NullTrapSink {}) + .define_function(func_id, context, &mut NullTrapSink {}, &mut NullStackMapSink {}) .unwrap() }); @@ -219,8 +216,7 @@ fn codegen_fn_content(fx: &mut FunctionCx<'_, '_, '_>) { codegen_stmt(fx, block, stmt); } - #[cfg(debug_assertions)] - { + if fx.clif_comments.enabled() { let mut terminator_head = "\n".to_string(); bb_data.terminator().kind.fmt_head(&mut terminator_head).unwrap(); let inst = fx.bcx.func.layout.last_inst(block).unwrap(); @@ -433,12 +429,14 @@ fn codegen_stmt<'tcx>( fx.set_debug_loc(stmt.source_info); - #[cfg(false_debug_assertions)] + #[cfg(disabled)] match &stmt.kind { StatementKind::StorageLive(..) | StatementKind::StorageDead(..) => {} // Those are not very useful _ => { - let inst = fx.bcx.func.layout.last_inst(cur_block).unwrap(); - fx.add_comment(inst, format!("{:?}", stmt)); + if fx.clif_comments.enabled() { + let inst = fx.bcx.func.layout.last_inst(cur_block).unwrap(); + fx.add_comment(inst, format!("{:?}", stmt)); + } } } @@ -464,16 +462,16 @@ fn codegen_stmt<'tcx>( let val = crate::constant::codegen_tls_ref(fx, def_id, lval.layout()); lval.write_cvalue(fx, val); } - Rvalue::BinaryOp(bin_op, box (ref lhs, ref rhs)) => { - let lhs = codegen_operand(fx, lhs); - let rhs = codegen_operand(fx, rhs); + Rvalue::BinaryOp(bin_op, ref lhs_rhs) => { + let lhs = codegen_operand(fx, &lhs_rhs.0); + let rhs = codegen_operand(fx, &lhs_rhs.1); let res = crate::num::codegen_binop(fx, bin_op, lhs, rhs); lval.write_cvalue(fx, res); } - Rvalue::CheckedBinaryOp(bin_op, box (ref lhs, ref rhs)) => { - let lhs = codegen_operand(fx, lhs); - let rhs = codegen_operand(fx, rhs); + Rvalue::CheckedBinaryOp(bin_op, ref lhs_rhs) => { + let lhs = codegen_operand(fx, &lhs_rhs.0); + let rhs = codegen_operand(fx, &lhs_rhs.1); let res = if !fx.tcx.sess.overflow_checks() { let val = @@ -659,7 +657,9 @@ fn codegen_stmt<'tcx>( .val .try_to_bits(fx.tcx.data_layout.pointer_size) .unwrap(); - if fx.clif_type(operand.layout().ty) == Some(types::I8) { + if operand.layout().size.bytes() == 0 { + // Do nothing for ZST's + } else if fx.clif_type(operand.layout().ty) == Some(types::I8) { let times = fx.bcx.ins().iconst(fx.pointer_type, times as i64); // FIXME use emit_small_memset where possible let addr = lval.to_ptr().get_addr(fx); @@ -832,25 +832,18 @@ fn codegen_stmt<'tcx>( } } StatementKind::Coverage { .. } => fx.tcx.sess.fatal("-Zcoverage is unimplemented"), - StatementKind::CopyNonOverlapping(box rustc_middle::mir::CopyNonOverlapping { - src, - dst, - count, - }) => { - let dst = codegen_operand(fx, dst); + StatementKind::CopyNonOverlapping(inner) => { + let dst = codegen_operand(fx, &inner.dst); let pointee = dst - .layout() - .pointee_info_at(fx, rustc_target::abi::Size::ZERO) - .expect("Expected pointer"); + .layout() + .pointee_info_at(fx, rustc_target::abi::Size::ZERO) + .expect("Expected pointer"); let dst = dst.load_scalar(fx); - let src = codegen_operand(fx, src).load_scalar(fx); - let count = codegen_operand(fx, count).load_scalar(fx); + let src = codegen_operand(fx, &inner.src).load_scalar(fx); + let count = codegen_operand(fx, &inner.count).load_scalar(fx); let elem_size: u64 = pointee.size.bytes(); - let bytes = if elem_size != 1 { - fx.bcx.ins().imul_imm(count, elem_size as i64) - } else { - count - }; + let bytes = + if elem_size != 1 { fx.bcx.ins().imul_imm(count, elem_size as i64) } else { count }; fx.bcx.call_memcpy(fx.cx.module.target_config(), dst, src, bytes); } } diff --git a/compiler/rustc_codegen_cranelift/src/codegen_i128.rs b/compiler/rustc_codegen_cranelift/src/codegen_i128.rs index ae75e6508cb..ffe1922ab90 100644 --- a/compiler/rustc_codegen_cranelift/src/codegen_i128.rs +++ b/compiler/rustc_codegen_cranelift/src/codegen_i128.rs @@ -32,18 +32,56 @@ pub(crate) fn maybe_codegen<'tcx>( BinOp::Add | BinOp::Sub if !checked => None, BinOp::Mul if !checked => { let val_ty = if is_signed { fx.tcx.types.i128 } else { fx.tcx.types.u128 }; - Some(fx.easy_call("__multi3", &[lhs, rhs], val_ty)) + if fx.tcx.sess.target.is_like_windows { + let ret_place = CPlace::new_stack_slot(fx, lhs.layout()); + let (lhs_ptr, lhs_extra) = lhs.force_stack(fx); + let (rhs_ptr, rhs_extra) = rhs.force_stack(fx); + assert!(lhs_extra.is_none()); + assert!(rhs_extra.is_none()); + let args = + [ret_place.to_ptr().get_addr(fx), lhs_ptr.get_addr(fx), rhs_ptr.get_addr(fx)]; + fx.lib_call( + "__multi3", + vec![ + AbiParam::special(pointer_ty(fx.tcx), ArgumentPurpose::StructReturn), + AbiParam::new(pointer_ty(fx.tcx)), + AbiParam::new(pointer_ty(fx.tcx)), + ], + vec![], + &args, + ); + Some(ret_place.to_cvalue(fx)) + } else { + Some(fx.easy_call("__multi3", &[lhs, rhs], val_ty)) + } } BinOp::Add | BinOp::Sub | BinOp::Mul => { assert!(checked); let out_ty = fx.tcx.mk_tup([lhs.layout().ty, fx.tcx.types.bool].iter()); let out_place = CPlace::new_stack_slot(fx, fx.layout_of(out_ty)); - let param_types = vec![ - AbiParam::special(pointer_ty(fx.tcx), ArgumentPurpose::StructReturn), - AbiParam::new(types::I128), - AbiParam::new(types::I128), - ]; - let args = [out_place.to_ptr().get_addr(fx), lhs.load_scalar(fx), rhs.load_scalar(fx)]; + let (param_types, args) = if fx.tcx.sess.target.is_like_windows { + let (lhs_ptr, lhs_extra) = lhs.force_stack(fx); + let (rhs_ptr, rhs_extra) = rhs.force_stack(fx); + assert!(lhs_extra.is_none()); + assert!(rhs_extra.is_none()); + ( + vec![ + AbiParam::special(pointer_ty(fx.tcx), ArgumentPurpose::StructReturn), + AbiParam::new(pointer_ty(fx.tcx)), + AbiParam::new(pointer_ty(fx.tcx)), + ], + [out_place.to_ptr().get_addr(fx), lhs_ptr.get_addr(fx), rhs_ptr.get_addr(fx)], + ) + } else { + ( + vec![ + AbiParam::special(pointer_ty(fx.tcx), ArgumentPurpose::StructReturn), + AbiParam::new(types::I128), + AbiParam::new(types::I128), + ], + [out_place.to_ptr().get_addr(fx), lhs.load_scalar(fx), rhs.load_scalar(fx)], + ) + }; let name = match (bin_op, is_signed) { (BinOp::Add, false) => "__rust_u128_addo", (BinOp::Add, true) => "__rust_i128_addo", @@ -57,20 +95,33 @@ pub(crate) fn maybe_codegen<'tcx>( Some(out_place.to_cvalue(fx)) } BinOp::Offset => unreachable!("offset should only be used on pointers, not 128bit ints"), - BinOp::Div => { + BinOp::Div | BinOp::Rem => { assert!(!checked); - if is_signed { - Some(fx.easy_call("__divti3", &[lhs, rhs], fx.tcx.types.i128)) - } else { - Some(fx.easy_call("__udivti3", &[lhs, rhs], fx.tcx.types.u128)) - } - } - BinOp::Rem => { - assert!(!checked); - if is_signed { - Some(fx.easy_call("__modti3", &[lhs, rhs], fx.tcx.types.i128)) + let name = match (bin_op, is_signed) { + (BinOp::Div, false) => "__udivti3", + (BinOp::Div, true) => "__divti3", + (BinOp::Rem, false) => "__umodti3", + (BinOp::Rem, true) => "__modti3", + _ => unreachable!(), + }; + if fx.tcx.sess.target.is_like_windows { + let (lhs_ptr, lhs_extra) = lhs.force_stack(fx); + let (rhs_ptr, rhs_extra) = rhs.force_stack(fx); + assert!(lhs_extra.is_none()); + assert!(rhs_extra.is_none()); + let args = [lhs_ptr.get_addr(fx), rhs_ptr.get_addr(fx)]; + let ret = fx.lib_call( + name, + vec![AbiParam::new(pointer_ty(fx.tcx)), AbiParam::new(pointer_ty(fx.tcx))], + vec![AbiParam::new(types::I64X2)], + &args, + )[0]; + // FIXME use bitcast instead of store to get from i64x2 to i128 + let ret_place = CPlace::new_stack_slot(fx, lhs.layout()); + ret_place.to_ptr().store(fx, ret, MemFlags::trusted()); + Some(ret_place.to_cvalue(fx)) } else { - Some(fx.easy_call("__umodti3", &[lhs, rhs], fx.tcx.types.u128)) + Some(fx.easy_call(name, &[lhs, rhs], lhs.layout().ty)) } } BinOp::Lt | BinOp::Le | BinOp::Eq | BinOp::Ge | BinOp::Gt | BinOp::Ne => { diff --git a/compiler/rustc_codegen_cranelift/src/common.rs b/compiler/rustc_codegen_cranelift/src/common.rs index 6a4a6744a5c..b5874f62535 100644 --- a/compiler/rustc_codegen_cranelift/src/common.rs +++ b/compiler/rustc_codegen_cranelift/src/common.rs @@ -361,8 +361,7 @@ impl<'tcx> FunctionCx<'_, '_, 'tcx> { let _ = self.cx.module.define_data(msg_id, &data_ctx); let local_msg_id = self.cx.module.declare_data_in_func(msg_id, self.bcx.func); - #[cfg(debug_assertions)] - { + if self.clif_comments.enabled() { self.add_comment(local_msg_id, msg); } self.bcx.ins().global_value(self.pointer_type, local_msg_id) diff --git a/compiler/rustc_codegen_cranelift/src/compiler_builtins.rs b/compiler/rustc_codegen_cranelift/src/compiler_builtins.rs new file mode 100644 index 00000000000..177f850afb3 --- /dev/null +++ b/compiler/rustc_codegen_cranelift/src/compiler_builtins.rs @@ -0,0 +1,41 @@ +macro builtin_functions($register:ident; $(fn $name:ident($($arg_name:ident: $arg_ty:ty),*) -> $ret_ty:ty;)*) { + #[cfg(feature = "jit")] + #[allow(improper_ctypes)] + extern "C" { + $(fn $name($($arg_name: $arg_ty),*) -> $ret_ty;)* + } + + #[cfg(feature = "jit")] + pub(crate) fn $register(builder: &mut cranelift_jit::JITBuilder) { + for &(name, val) in &[$((stringify!($name), $name as *const u8)),*] { + builder.symbol(name, val); + } + } +} + +builtin_functions! { + register_functions_for_jit; + + // integers + fn __multi3(a: i128, b: i128) -> i128; + fn __udivti3(n: u128, d: u128) -> u128; + fn __divti3(n: i128, d: i128) -> i128; + fn __umodti3(n: u128, d: u128) -> u128; + fn __modti3(n: i128, d: i128) -> i128; + fn __rust_u128_addo(a: u128, b: u128) -> (u128, bool); + fn __rust_i128_addo(a: i128, b: i128) -> (i128, bool); + fn __rust_u128_subo(a: u128, b: u128) -> (u128, bool); + fn __rust_i128_subo(a: i128, b: i128) -> (i128, bool); + fn __rust_u128_mulo(a: u128, b: u128) -> (u128, bool); + fn __rust_i128_mulo(a: i128, b: i128) -> (i128, bool); + + // floats + fn __floattisf(i: i128) -> f32; + fn __floattidf(i: i128) -> f64; + fn __floatuntisf(i: u128) -> f32; + fn __floatuntidf(i: u128) -> f64; + fn __fixsfti(f: f32) -> i128; + fn __fixdfti(f: f64) -> i128; + fn __fixunssfti(f: f32) -> u128; + fn __fixunsdfti(f: f64) -> u128; +} diff --git a/compiler/rustc_codegen_cranelift/src/constant.rs b/compiler/rustc_codegen_cranelift/src/constant.rs index f4cbfb6967f..fcd41c84465 100644 --- a/compiler/rustc_codegen_cranelift/src/constant.rs +++ b/compiler/rustc_codegen_cranelift/src/constant.rs @@ -85,8 +85,9 @@ pub(crate) fn codegen_tls_ref<'tcx>( ) -> CValue<'tcx> { let data_id = data_id_for_static(fx.tcx, fx.cx.module, def_id, false); let local_data_id = fx.cx.module.declare_data_in_func(data_id, &mut fx.bcx.func); - #[cfg(debug_assertions)] - fx.add_comment(local_data_id, format!("tls {:?}", def_id)); + if fx.clif_comments.enabled() { + fx.add_comment(local_data_id, format!("tls {:?}", def_id)); + } let tls_ptr = fx.bcx.ins().tls_value(fx.pointer_type, local_data_id); CValue::by_val(tls_ptr, layout) } @@ -98,8 +99,9 @@ fn codegen_static_ref<'tcx>( ) -> CPlace<'tcx> { let data_id = data_id_for_static(fx.tcx, fx.cx.module, def_id, false); let local_data_id = fx.cx.module.declare_data_in_func(data_id, &mut fx.bcx.func); - #[cfg(debug_assertions)] - fx.add_comment(local_data_id, format!("{:?}", def_id)); + if fx.clif_comments.enabled() { + fx.add_comment(local_data_id, format!("{:?}", def_id)); + } let global_ptr = fx.bcx.ins().global_value(fx.pointer_type, local_data_id); assert!(!layout.is_unsized(), "unsized statics aren't supported"); assert!( @@ -122,7 +124,9 @@ pub(crate) fn codegen_constant<'tcx>( }; let const_val = match const_.val { ConstKind::Value(const_val) => const_val, - ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted }) if fx.tcx.is_static(def.did) => { + ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted }) + if fx.tcx.is_static(def.did) => + { assert!(substs.is_empty()); assert!(promoted.is_none()); @@ -183,8 +187,9 @@ pub(crate) fn codegen_const_value<'tcx>( data_id_for_alloc_id(fx.cx.module, ptr.alloc_id, alloc.mutability); let local_data_id = fx.cx.module.declare_data_in_func(data_id, &mut fx.bcx.func); - #[cfg(debug_assertions)] - fx.add_comment(local_data_id, format!("{:?}", ptr.alloc_id)); + if fx.clif_comments.enabled() { + fx.add_comment(local_data_id, format!("{:?}", ptr.alloc_id)); + } fx.bcx.ins().global_value(fx.pointer_type, local_data_id) } Some(GlobalAlloc::Function(instance)) => { @@ -199,8 +204,9 @@ pub(crate) fn codegen_const_value<'tcx>( let data_id = data_id_for_static(fx.tcx, fx.cx.module, def_id, false); let local_data_id = fx.cx.module.declare_data_in_func(data_id, &mut fx.bcx.func); - #[cfg(debug_assertions)] - fx.add_comment(local_data_id, format!("{:?}", def_id)); + if fx.clif_comments.enabled() { + fx.add_comment(local_data_id, format!("{:?}", def_id)); + } fx.bcx.ins().global_value(fx.pointer_type, local_data_id) } None => bug!("missing allocation {:?}", ptr.alloc_id), @@ -241,8 +247,9 @@ fn pointer_for_allocation<'tcx>( let data_id = data_id_for_alloc_id(fx.cx.module, alloc_id, alloc.mutability); let local_data_id = fx.cx.module.declare_data_in_func(data_id, &mut fx.bcx.func); - #[cfg(debug_assertions)] - fx.add_comment(local_data_id, format!("{:?}", alloc_id)); + if fx.clif_comments.enabled() { + fx.add_comment(local_data_id, format!("{:?}", alloc_id)); + } let global_ptr = fx.bcx.ins().global_value(fx.pointer_type, local_data_id); crate::pointer::Pointer::new(global_ptr) } diff --git a/compiler/rustc_codegen_cranelift/src/debuginfo/line_info.rs b/compiler/rustc_codegen_cranelift/src/debuginfo/line_info.rs index 30ed356c762..8578ab33ced 100644 --- a/compiler/rustc_codegen_cranelift/src/debuginfo/line_info.rs +++ b/compiler/rustc_codegen_cranelift/src/debuginfo/line_info.rs @@ -39,11 +39,11 @@ fn osstr_as_utf8_bytes(path: &OsStr) -> &[u8] { #[cfg(unix)] { use std::os::unix::ffi::OsStrExt; - return path.as_bytes(); + path.as_bytes() } #[cfg(not(unix))] { - return path.to_str().unwrap().as_bytes(); + path.to_str().unwrap().as_bytes() } } diff --git a/compiler/rustc_codegen_cranelift/src/driver/aot.rs b/compiler/rustc_codegen_cranelift/src/driver/aot.rs index b87dcc41928..ed3bdedddce 100644 --- a/compiler/rustc_codegen_cranelift/src/driver/aot.rs +++ b/compiler/rustc_codegen_cranelift/src/driver/aot.rs @@ -119,11 +119,10 @@ fn module_codegen( tcx.sess.opts.debuginfo != DebugInfo::None, ); super::predefine_mono_items(&mut cx, &mono_items); - for (mono_item, (linkage, visibility)) in mono_items { - let linkage = crate::linkage::get_clif_linkage(mono_item, linkage, visibility); + for (mono_item, _) in mono_items { match mono_item { MonoItem::Fn(inst) => { - cx.tcx.sess.time("codegen fn", || crate::base::codegen_fn(&mut cx, inst, linkage)); + cx.tcx.sess.time("codegen fn", || crate::base::codegen_fn(&mut cx, inst)); } MonoItem::Static(def_id) => { crate::constant::codegen_static(&mut cx.constants_cx, def_id) @@ -163,6 +162,21 @@ pub(super) fn run_aot( metadata: EncodedMetadata, need_metadata_module: bool, ) -> Box<(CodegenResults, FxHashMap<WorkProductId, WorkProduct>)> { + use rustc_span::symbol::sym; + + let crate_attrs = tcx.hir().attrs(rustc_hir::CRATE_HIR_ID); + let subsystem = tcx.sess.first_attr_value_str_by_name(crate_attrs, sym::windows_subsystem); + let windows_subsystem = subsystem.map(|subsystem| { + if subsystem != sym::windows && subsystem != sym::console { + tcx.sess.fatal(&format!( + "invalid windows subsystem `{}`, only \ + `windows` and `console` are allowed", + subsystem + )); + } + subsystem.to_string() + }); + let mut work_products = FxHashMap::default(); let cgus = if tcx.sess.opts.output_types.should_codegen() { @@ -280,7 +294,7 @@ pub(super) fn run_aot( allocator_module, metadata_module, metadata, - windows_subsystem: None, // Windows is not yet supported + windows_subsystem, linker_info: LinkerInfo::new(tcx), crate_info: CrateInfo::new(tcx), }, diff --git a/compiler/rustc_codegen_cranelift/src/driver/jit.rs b/compiler/rustc_codegen_cranelift/src/driver/jit.rs index 245df03ffb8..dbe1ff083f0 100644 --- a/compiler/rustc_codegen_cranelift/src/driver/jit.rs +++ b/compiler/rustc_codegen_cranelift/src/driver/jit.rs @@ -5,8 +5,10 @@ use std::cell::RefCell; use std::ffi::CString; use std::os::raw::{c_char, c_int}; +use cranelift_codegen::binemit::{NullStackMapSink, NullTrapSink}; use rustc_codegen_ssa::CrateInfo; use rustc_middle::mir::mono::MonoItem; +use rustc_session::config::EntryFnType; use cranelift_jit::{JITBuilder, JITModule}; @@ -28,20 +30,11 @@ pub(super) fn run_jit(tcx: TyCtxt<'_>, backend_config: BackendConfig) -> ! { let mut jit_builder = JITBuilder::with_isa(crate::build_isa(tcx.sess), cranelift_module::default_libcall_names()); jit_builder.hotswap(matches!(backend_config.codegen_mode, CodegenMode::JitLazy)); + crate::compiler_builtins::register_functions_for_jit(&mut jit_builder); jit_builder.symbols(imported_symbols); let mut jit_module = JITModule::new(jit_builder); assert_eq!(pointer_ty(tcx), jit_module.target_config().pointer_type()); - let sig = Signature { - params: vec![ - AbiParam::new(jit_module.target_config().pointer_type()), - AbiParam::new(jit_module.target_config().pointer_type()), - ], - returns: vec![AbiParam::new(jit_module.target_config().pointer_type() /*isize*/)], - call_conv: CallConv::triple_default(&crate::target_triple(tcx.sess)), - }; - let main_func_id = jit_module.declare_function("main", Linkage::Import, &sig).unwrap(); - let (_, cgus) = tcx.collect_and_partition_mono_items(LOCAL_CRATE); let mono_items = cgus .iter() @@ -55,15 +48,12 @@ pub(super) fn run_jit(tcx: TyCtxt<'_>, backend_config: BackendConfig) -> ! { super::time(tcx, "codegen mono items", || { super::predefine_mono_items(&mut cx, &mono_items); - for (mono_item, (linkage, visibility)) in mono_items { - let linkage = crate::linkage::get_clif_linkage(mono_item, linkage, visibility); + for (mono_item, _) in mono_items { match mono_item { MonoItem::Fn(inst) => match backend_config.codegen_mode { CodegenMode::Aot => unreachable!(), CodegenMode::Jit => { - cx.tcx - .sess - .time("codegen fn", || crate::base::codegen_fn(&mut cx, inst, linkage)); + cx.tcx.sess.time("codegen fn", || crate::base::codegen_fn(&mut cx, inst)); } CodegenMode::JitLazy => codegen_shim(&mut cx, inst), }, @@ -86,24 +76,17 @@ pub(super) fn run_jit(tcx: TyCtxt<'_>, backend_config: BackendConfig) -> ! { tcx.sess.fatal("Inline asm is not supported in JIT mode"); } - crate::main_shim::maybe_create_entry_wrapper(tcx, &mut jit_module, &mut unwind_context); crate::allocator::codegen(tcx, &mut jit_module, &mut unwind_context); tcx.sess.abort_if_errors(); jit_module.finalize_definitions(); - let _unwind_register_guard = unsafe { unwind_context.register_jit(&jit_module) }; - let finalized_main: *const u8 = jit_module.get_finalized_function(main_func_id); - println!( "Rustc codegen cranelift will JIT run the executable, because -Cllvm-args=mode=jit was passed" ); - let f: extern "C" fn(c_int, *const *const c_char) -> c_int = - unsafe { ::std::mem::transmute(finalized_main) }; - let args = ::std::env::var("CG_CLIF_JIT_ARGS").unwrap_or_else(|_| String::new()); let args = std::iter::once(&*tcx.crate_name(LOCAL_CRATE).as_str().to_string()) .chain(args.split(' ')) @@ -118,12 +101,58 @@ pub(super) fn run_jit(tcx: TyCtxt<'_>, backend_config: BackendConfig) -> ! { BACKEND_CONFIG.with(|tls_backend_config| { assert!(tls_backend_config.borrow_mut().replace(backend_config).is_none()) }); - CURRENT_MODULE - .with(|current_module| assert!(current_module.borrow_mut().replace(jit_module).is_none())); - let ret = f(args.len() as c_int, argv.as_ptr()); + let (main_def_id, entry_ty) = tcx.entry_fn(LOCAL_CRATE).unwrap(); + let instance = Instance::mono(tcx, main_def_id.to_def_id()).polymorphize(tcx); + + match entry_ty { + EntryFnType::Main => { + // FIXME set program arguments somehow - std::process::exit(ret); + let main_sig = Signature { + params: vec![], + returns: vec![], + call_conv: CallConv::triple_default(&crate::target_triple(tcx.sess)), + }; + let main_func_id = jit_module + .declare_function(tcx.symbol_name(instance).name, Linkage::Import, &main_sig) + .unwrap(); + let finalized_main: *const u8 = jit_module.get_finalized_function(main_func_id); + + CURRENT_MODULE.with(|current_module| { + assert!(current_module.borrow_mut().replace(jit_module).is_none()) + }); + + let f: extern "C" fn() = unsafe { ::std::mem::transmute(finalized_main) }; + f(); + std::process::exit(0); + } + EntryFnType::Start => { + let start_sig = Signature { + params: vec![ + AbiParam::new(jit_module.target_config().pointer_type()), + AbiParam::new(jit_module.target_config().pointer_type()), + ], + returns: vec![AbiParam::new( + jit_module.target_config().pointer_type(), /*isize*/ + )], + call_conv: CallConv::triple_default(&crate::target_triple(tcx.sess)), + }; + let start_func_id = jit_module + .declare_function(tcx.symbol_name(instance).name, Linkage::Import, &start_sig) + .unwrap(); + let finalized_start: *const u8 = jit_module.get_finalized_function(start_func_id); + + CURRENT_MODULE.with(|current_module| { + assert!(current_module.borrow_mut().replace(jit_module).is_none()) + }); + + let f: extern "C" fn(c_int, *const *const c_char) -> c_int = + unsafe { ::std::mem::transmute(finalized_start) }; + let ret = f(args.len() as c_int, argv.as_ptr()); + std::process::exit(ret); + } + } } #[no_mangle] @@ -144,8 +173,7 @@ extern "C" fn __clif_jit_fn(instance_ptr: *const Instance<'static>) -> *const u8 jit_module.prepare_for_function_redefine(func_id).unwrap(); let mut cx = crate::CodegenCx::new(tcx, backend_config, jit_module, false); - tcx.sess - .time("codegen fn", || crate::base::codegen_fn(&mut cx, instance, Linkage::Export)); + tcx.sess.time("codegen fn", || crate::base::codegen_fn(&mut cx, instance)); let (global_asm, _debug_context, unwind_context) = cx.finalize(); assert!(global_asm.is_empty()); @@ -220,7 +248,7 @@ fn load_imported_symbols_for_jit(tcx: TyCtxt<'_>) -> Vec<(String, *const u8)> { imported_symbols } -pub(super) fn codegen_shim<'tcx>(cx: &mut CodegenCx<'_, 'tcx>, inst: Instance<'tcx>) { +fn codegen_shim<'tcx>(cx: &mut CodegenCx<'_, 'tcx>, inst: Instance<'tcx>) { let tcx = cx.tcx; let pointer_type = cx.module.target_config().pointer_type(); @@ -267,7 +295,8 @@ pub(super) fn codegen_shim<'tcx>(cx: &mut CodegenCx<'_, 'tcx>, inst: Instance<'t .define_function( func_id, &mut Context::for_function(trampoline), - &mut cranelift_codegen::binemit::NullTrapSink {}, + &mut NullTrapSink {}, + &mut NullStackMapSink {}, ) .unwrap(); } diff --git a/compiler/rustc_codegen_cranelift/src/driver/mod.rs b/compiler/rustc_codegen_cranelift/src/driver/mod.rs index b994f28ffef..d49182a07b7 100644 --- a/compiler/rustc_codegen_cranelift/src/driver/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/driver/mod.rs @@ -44,13 +44,19 @@ fn predefine_mono_items<'tcx>( mono_items: &[(MonoItem<'tcx>, (RLinkage, Visibility))], ) { cx.tcx.sess.time("predefine functions", || { + let is_compiler_builtins = cx.tcx.is_compiler_builtins(LOCAL_CRATE); for &(mono_item, (linkage, visibility)) in mono_items { match mono_item { MonoItem::Fn(instance) => { let name = cx.tcx.symbol_name(instance).name.to_string(); let _inst_guard = crate::PrintOnPanic(|| format!("{:?} {}", instance, name)); let sig = get_function_sig(cx.tcx, cx.module.isa().triple(), instance); - let linkage = crate::linkage::get_clif_linkage(mono_item, linkage, visibility); + let linkage = crate::linkage::get_clif_linkage( + mono_item, + linkage, + visibility, + is_compiler_builtins, + ); cx.module.declare_function(&name, linkage, &sig).unwrap(); } MonoItem::Static(_) | MonoItem::GlobalAsm(_) => {} diff --git a/compiler/rustc_codegen_cranelift/src/inline_asm.rs b/compiler/rustc_codegen_cranelift/src/inline_asm.rs index 5b3df2bd382..1fb5e86aed7 100644 --- a/compiler/rustc_codegen_cranelift/src/inline_asm.rs +++ b/compiler/rustc_codegen_cranelift/src/inline_asm.rs @@ -20,6 +20,10 @@ pub(crate) fn codegen_inline_asm<'tcx>( if template.is_empty() { // Black box return; + } else if template[0] == InlineAsmTemplatePiece::String("int $$0x29".to_string()) { + let true_ = fx.bcx.ins().iconst(types::I32, 1); + fx.bcx.ins().trapnz(true_, TrapCode::User(1)); + return; } let mut slot_size = Size::from_bytes(0); @@ -193,8 +197,9 @@ fn call_inline_asm<'tcx>( offset: None, size: u32::try_from(slot_size.bytes()).unwrap(), }); - #[cfg(debug_assertions)] - fx.add_comment(stack_slot, "inline asm scratch slot"); + if fx.clif_comments.enabled() { + fx.add_comment(stack_slot, "inline asm scratch slot"); + } let inline_asm_func = fx .cx @@ -210,8 +215,9 @@ fn call_inline_asm<'tcx>( ) .unwrap(); let inline_asm_func = fx.cx.module.declare_func_in_func(inline_asm_func, &mut fx.bcx.func); - #[cfg(debug_assertions)] - fx.add_comment(inline_asm_func, asm_name); + if fx.clif_comments.enabled() { + fx.add_comment(inline_asm_func, asm_name); + } for (_reg, offset, value) in inputs { fx.bcx.ins().stack_store(value, stack_slot, i32::try_from(offset.bytes()).unwrap()); diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs index 86df71a0dfc..c7ce32b385e 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs @@ -88,7 +88,7 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( let idx_bytes = match idx_const { ConstValue::ByRef { alloc, offset } => { let ptr = Pointer::new(AllocId(0 /* dummy */), offset); - let size = Size::from_bytes(4 * u64::from(ret_lane_count) /* size_of([u32; ret_lane_count]) */); + let size = Size::from_bytes(4 * ret_lane_count /* size_of([u32; ret_lane_count]) */); alloc.get_bytes(fx, ptr, size).unwrap() } _ => unreachable!("{:?}", idx_const), diff --git a/compiler/rustc_codegen_cranelift/src/lib.rs b/compiler/rustc_codegen_cranelift/src/lib.rs index 8edb883ccb5..720d2a12534 100644 --- a/compiler/rustc_codegen_cranelift/src/lib.rs +++ b/compiler/rustc_codegen_cranelift/src/lib.rs @@ -1,13 +1,4 @@ -#![feature( - rustc_private, - decl_macro, - type_alias_impl_trait, - associated_type_bounds, - never_type, - try_blocks, - box_patterns, - hash_drain_filter -)] +#![feature(rustc_private, decl_macro, never_type, hash_drain_filter)] #![warn(rust_2018_idioms)] #![warn(unused_lifetimes)] #![warn(unreachable_pub)] @@ -57,6 +48,7 @@ mod base; mod cast; mod codegen_i128; mod common; +mod compiler_builtins; mod constant; mod debuginfo; mod discriminant; @@ -224,8 +216,10 @@ pub struct CraneliftCodegenBackend { impl CodegenBackend for CraneliftCodegenBackend { fn init(&self, sess: &Session) { - if sess.lto() != rustc_session::config::Lto::No && sess.opts.cg.embed_bitcode { - sess.warn("LTO is not supported. You may get a linker error."); + use rustc_session::config::Lto; + match sess.lto() { + Lto::No | Lto::ThinLocal => {} + Lto::Thin | Lto::Fat => sess.warn("LTO is not supported. You may get a linker error."), } } @@ -240,9 +234,9 @@ impl CodegenBackend for CraneliftCodegenBackend { vec![] } - fn codegen_crate<'tcx>( + fn codegen_crate( &self, - tcx: TyCtxt<'tcx>, + tcx: TyCtxt<'_>, metadata: EncodedMetadata, need_metadata_module: bool, ) -> Box<dyn Any> { @@ -252,9 +246,7 @@ impl CodegenBackend for CraneliftCodegenBackend { BackendConfig::from_opts(&tcx.sess.opts.cg.llvm_args) .unwrap_or_else(|err| tcx.sess.fatal(&err)) }; - let res = driver::codegen_crate(tcx, metadata, need_metadata_module, config); - - res + driver::codegen_crate(tcx, metadata, need_metadata_module, config) } fn join_codegen( @@ -300,9 +292,9 @@ fn build_isa(sess: &Session) -> Box<dyn isa::TargetIsa + 'static> { let mut flags_builder = settings::builder(); flags_builder.enable("is_pic").unwrap(); flags_builder.set("enable_probestack", "false").unwrap(); // __cranelift_probestack is not provided - flags_builder - .set("enable_verifier", if cfg!(debug_assertions) { "true" } else { "false" }) - .unwrap(); + let enable_verifier = + cfg!(debug_assertions) || std::env::var("CG_CLIF_ENABLE_VERIFIER").is_ok(); + flags_builder.set("enable_verifier", if enable_verifier { "true" } else { "false" }).unwrap(); let tls_model = match target_triple.binary_format { BinaryFormat::Elf => "elf_gd", @@ -314,18 +306,17 @@ fn build_isa(sess: &Session) -> Box<dyn isa::TargetIsa + 'static> { flags_builder.set("enable_simd", "true").unwrap(); + flags_builder.set("enable_llvm_abi_extensions", "true").unwrap(); + use rustc_session::config::OptLevel; match sess.opts.optimize { OptLevel::No => { flags_builder.set("opt_level", "none").unwrap(); } OptLevel::Less | OptLevel::Default => {} - OptLevel::Aggressive => { + OptLevel::Size | OptLevel::SizeMin | OptLevel::Aggressive => { flags_builder.set("opt_level", "speed_and_size").unwrap(); } - OptLevel::Size | OptLevel::SizeMin => { - sess.warn("Optimizing for size is not supported. Just ignoring the request"); - } } let flags = settings::Flags::new(flags_builder); diff --git a/compiler/rustc_codegen_cranelift/src/linkage.rs b/compiler/rustc_codegen_cranelift/src/linkage.rs index dc1e2107ce7..a564a59f725 100644 --- a/compiler/rustc_codegen_cranelift/src/linkage.rs +++ b/compiler/rustc_codegen_cranelift/src/linkage.rs @@ -6,8 +6,10 @@ pub(crate) fn get_clif_linkage( mono_item: MonoItem<'_>, linkage: RLinkage, visibility: Visibility, + is_compiler_builtins: bool, ) -> Linkage { match (linkage, visibility) { + (RLinkage::External, Visibility::Default) if is_compiler_builtins => Linkage::Hidden, (RLinkage::External, Visibility::Default) => Linkage::Export, (RLinkage::Internal, Visibility::Default) => Linkage::Local, (RLinkage::External, Visibility::Hidden) => Linkage::Hidden, diff --git a/compiler/rustc_codegen_cranelift/src/main_shim.rs b/compiler/rustc_codegen_cranelift/src/main_shim.rs index 62e551b186f..a6266f50776 100644 --- a/compiler/rustc_codegen_cranelift/src/main_shim.rs +++ b/compiler/rustc_codegen_cranelift/src/main_shim.rs @@ -1,3 +1,4 @@ +use cranelift_codegen::binemit::{NullStackMapSink, NullTrapSink}; use rustc_hir::LangItem; use rustc_session::config::EntryFnType; @@ -100,12 +101,8 @@ pub(crate) fn maybe_create_entry_wrapper( bcx.seal_all_blocks(); bcx.finalize(); } - m.define_function( - cmain_func_id, - &mut ctx, - &mut cranelift_codegen::binemit::NullTrapSink {}, - ) - .unwrap(); + m.define_function(cmain_func_id, &mut ctx, &mut NullTrapSink {}, &mut NullStackMapSink {}) + .unwrap(); unwind_context.add_function(cmain_func_id, &ctx, m.isa()); } } diff --git a/compiler/rustc_codegen_cranelift/src/metadata.rs b/compiler/rustc_codegen_cranelift/src/metadata.rs index 190c4f45cca..c5189c972cd 100644 --- a/compiler/rustc_codegen_cranelift/src/metadata.rs +++ b/compiler/rustc_codegen_cranelift/src/metadata.rs @@ -1,11 +1,11 @@ //! Reading and writing of the rustc metadata for rlibs and dylibs -use std::convert::TryFrom; use std::fs::File; +use std::ops::Deref; use std::path::Path; use rustc_codegen_ssa::METADATA_FILENAME; -use rustc_data_structures::owning_ref::OwningRef; +use rustc_data_structures::owning_ref::{OwningRef, StableAddress}; use rustc_data_structures::rustc_erase_owner; use rustc_data_structures::sync::MetadataRef; use rustc_middle::middle::cstore::{EncodedMetadata, MetadataLoader}; @@ -17,38 +17,56 @@ use crate::backend::WriteMetadata; pub(crate) struct CraneliftMetadataLoader; +struct StableMmap(memmap2::Mmap); + +impl Deref for StableMmap { + type Target = [u8]; + + fn deref(&self) -> &[u8] { + &*self.0 + } +} + +unsafe impl StableAddress for StableMmap {} + +fn load_metadata_with( + path: &Path, + f: impl for<'a> FnOnce(&'a [u8]) -> Result<&'a [u8], String>, +) -> Result<MetadataRef, String> { + let file = File::open(path).map_err(|e| format!("{:?}", e))?; + let data = unsafe { memmap2::MmapOptions::new().map_copy_read_only(&file) } + .map_err(|e| format!("{:?}", e))?; + let metadata = OwningRef::new(StableMmap(data)).try_map(f)?; + return Ok(rustc_erase_owner!(metadata.map_owner_box())); +} + impl MetadataLoader for CraneliftMetadataLoader { fn get_rlib_metadata(&self, _target: &Target, path: &Path) -> Result<MetadataRef, String> { - let mut archive = ar::Archive::new(File::open(path).map_err(|e| format!("{:?}", e))?); - // Iterate over all entries in the archive: - while let Some(entry_result) = archive.next_entry() { - let mut entry = entry_result.map_err(|e| format!("{:?}", e))?; - if entry.header().identifier() == METADATA_FILENAME.as_bytes() { - let mut buf = Vec::with_capacity( - usize::try_from(entry.header().size()) - .expect("Rlib metadata file too big to load into memory."), - ); - ::std::io::copy(&mut entry, &mut buf).map_err(|e| format!("{:?}", e))?; - let buf: OwningRef<Vec<u8>, [u8]> = OwningRef::new(buf); - return Ok(rustc_erase_owner!(buf.map_owner_box())); + load_metadata_with(path, |data| { + let archive = object::read::archive::ArchiveFile::parse(&*data) + .map_err(|e| format!("{:?}", e))?; + + for entry_result in archive.members() { + let entry = entry_result.map_err(|e| format!("{:?}", e))?; + if entry.name() == METADATA_FILENAME.as_bytes() { + return Ok(entry.data()); + } } - } - Err("couldn't find metadata entry".to_string()) + Err("couldn't find metadata entry".to_string()) + }) } fn get_dylib_metadata(&self, _target: &Target, path: &Path) -> Result<MetadataRef, String> { use object::{Object, ObjectSection}; - let file = std::fs::read(path).map_err(|e| format!("read:{:?}", e))?; - let file = object::File::parse(&file).map_err(|e| format!("parse: {:?}", e))?; - let buf = file - .section_by_name(".rustc") - .ok_or("no .rustc section")? - .data() - .map_err(|e| format!("failed to read .rustc section: {:?}", e))? - .to_owned(); - let buf: OwningRef<Vec<u8>, [u8]> = OwningRef::new(buf); - Ok(rustc_erase_owner!(buf.map_owner_box())) + + load_metadata_with(path, |data| { + let file = object::File::parse(&data).map_err(|e| format!("parse: {:?}", e))?; + file.section_by_name(".rustc") + .ok_or("no .rustc section")? + .data() + .map_err(|e| format!("failed to read .rustc section: {:?}", e)) + }) } } diff --git a/compiler/rustc_codegen_cranelift/src/num.rs b/compiler/rustc_codegen_cranelift/src/num.rs index da49e1c6c91..2ebf30da2d8 100644 --- a/compiler/rustc_codegen_cranelift/src/num.rs +++ b/compiler/rustc_codegen_cranelift/src/num.rs @@ -166,13 +166,11 @@ pub(crate) fn codegen_int_binop<'tcx>( BinOp::Shl => { let lhs_ty = fx.bcx.func.dfg.value_type(lhs); let actual_shift = fx.bcx.ins().band_imm(rhs, i64::from(lhs_ty.bits() - 1)); - let actual_shift = clif_intcast(fx, actual_shift, types::I8, false); fx.bcx.ins().ishl(lhs, actual_shift) } BinOp::Shr => { let lhs_ty = fx.bcx.func.dfg.value_type(lhs); let actual_shift = fx.bcx.ins().band_imm(rhs, i64::from(lhs_ty.bits() - 1)); - let actual_shift = clif_intcast(fx, actual_shift, types::I8, false); if signed { fx.bcx.ins().sshr(lhs, actual_shift) } else { @@ -387,7 +385,7 @@ pub(crate) fn codegen_ptr_binop<'tcx>( let lhs = in_lhs.load_scalar(fx); let rhs = in_rhs.load_scalar(fx); - return codegen_compare_bin_op(fx, bin_op, false, lhs, rhs); + codegen_compare_bin_op(fx, bin_op, false, lhs, rhs) } BinOp::Offset => { let pointee_ty = in_lhs.layout().ty.builtin_deref(true).unwrap().ty; @@ -396,10 +394,10 @@ pub(crate) fn codegen_ptr_binop<'tcx>( let ptr_diff = fx.bcx.ins().imul_imm(offset, pointee_size as i64); let base_val = base.load_scalar(fx); let res = fx.bcx.ins().iadd(base_val, ptr_diff); - return CValue::by_val(res, base.layout()); + CValue::by_val(res, base.layout()) } _ => unreachable!("{:?}({:?}, {:?})", bin_op, in_lhs, in_rhs), - }; + } } else { let (lhs_ptr, lhs_extra) = in_lhs.load_scalar_pair(fx); let (rhs_ptr, rhs_extra) = in_rhs.load_scalar_pair(fx); diff --git a/compiler/rustc_codegen_cranelift/src/optimize/stack2reg.rs b/compiler/rustc_codegen_cranelift/src/optimize/stack2reg.rs index d111f37f5e4..8bb02a3e558 100644 --- a/compiler/rustc_codegen_cranelift/src/optimize/stack2reg.rs +++ b/compiler/rustc_codegen_cranelift/src/optimize/stack2reg.rs @@ -181,7 +181,6 @@ impl<'a> OptimizeContext<'a> { pub(super) fn optimize_function( ctx: &mut Context, - #[cfg_attr(not(debug_assertions), allow(unused_variables))] clif_comments: &mut crate::pretty_clif::CommentWriter, ) { combine_stack_addr_with_load_store(&mut ctx.func); @@ -192,8 +191,7 @@ pub(super) fn optimize_function( remove_unused_stack_addr_and_stack_load(&mut opt_ctx); - #[cfg(debug_assertions)] - { + if clif_comments.enabled() { for (&OrdStackSlot(stack_slot), usage) in &opt_ctx.stack_slot_usage_map { clif_comments.add_comment(stack_slot, format!("used by: {:?}", usage)); } @@ -209,25 +207,27 @@ pub(super) fn optimize_function( for load in users.stack_load.clone().into_iter() { let potential_stores = users.potential_stores_for_load(&opt_ctx.ctx, load); - #[cfg(debug_assertions)] - for &store in &potential_stores { - clif_comments.add_comment( - load, - format!( - "Potential store -> load forwarding {} -> {} ({:?}, {:?})", - opt_ctx.ctx.func.dfg.display_inst(store, None), - opt_ctx.ctx.func.dfg.display_inst(load, None), - spatial_overlap(&opt_ctx.ctx.func, store, load), - temporal_order(&opt_ctx.ctx, store, load), - ), - ); + if clif_comments.enabled() { + for &store in &potential_stores { + clif_comments.add_comment( + load, + format!( + "Potential store -> load forwarding {} -> {} ({:?}, {:?})", + opt_ctx.ctx.func.dfg.display_inst(store, None), + opt_ctx.ctx.func.dfg.display_inst(load, None), + spatial_overlap(&opt_ctx.ctx.func, store, load), + temporal_order(&opt_ctx.ctx, store, load), + ), + ); + } } match *potential_stores { [] => { - #[cfg(debug_assertions)] - clif_comments - .add_comment(load, "[BUG?] Reading uninitialized memory".to_string()); + if clif_comments.enabled() { + clif_comments + .add_comment(load, "[BUG?] Reading uninitialized memory".to_string()); + } } [store] if spatial_overlap(&opt_ctx.ctx.func, store, load) == SpatialOverlap::Full @@ -237,9 +237,12 @@ pub(super) fn optimize_function( // Only one store could have been the origin of the value. let stored_value = opt_ctx.ctx.func.dfg.inst_args(store)[0]; - #[cfg(debug_assertions)] - clif_comments - .add_comment(load, format!("Store to load forward {} -> {}", store, load)); + if clif_comments.enabled() { + clif_comments.add_comment( + load, + format!("Store to load forward {} -> {}", store, load), + ); + } users.change_load_to_alias(&mut opt_ctx.ctx.func, load, stored_value); } @@ -250,33 +253,35 @@ pub(super) fn optimize_function( for store in users.stack_store.clone().into_iter() { let potential_loads = users.potential_loads_of_store(&opt_ctx.ctx, store); - #[cfg(debug_assertions)] - for &load in &potential_loads { - clif_comments.add_comment( - store, - format!( - "Potential load from store {} <- {} ({:?}, {:?})", - opt_ctx.ctx.func.dfg.display_inst(load, None), - opt_ctx.ctx.func.dfg.display_inst(store, None), - spatial_overlap(&opt_ctx.ctx.func, store, load), - temporal_order(&opt_ctx.ctx, store, load), - ), - ); + if clif_comments.enabled() { + for &load in &potential_loads { + clif_comments.add_comment( + store, + format!( + "Potential load from store {} <- {} ({:?}, {:?})", + opt_ctx.ctx.func.dfg.display_inst(load, None), + opt_ctx.ctx.func.dfg.display_inst(store, None), + spatial_overlap(&opt_ctx.ctx.func, store, load), + temporal_order(&opt_ctx.ctx, store, load), + ), + ); + } } if potential_loads.is_empty() { // Never loaded; can safely remove all stores and the stack slot. // FIXME also remove stores when there is always a next store before a load. - #[cfg(debug_assertions)] - clif_comments.add_comment( - store, - format!( - "Remove dead stack store {} of {}", - opt_ctx.ctx.func.dfg.display_inst(store, None), - stack_slot.0 - ), - ); + if clif_comments.enabled() { + clif_comments.add_comment( + store, + format!( + "Remove dead stack store {} of {}", + opt_ctx.ctx.func.dfg.display_inst(store, None), + stack_slot.0 + ), + ); + } users.remove_dead_store(&mut opt_ctx.ctx.func, store); } diff --git a/compiler/rustc_codegen_cranelift/src/pointer.rs b/compiler/rustc_codegen_cranelift/src/pointer.rs index 88a78f3214d..31d827f83bf 100644 --- a/compiler/rustc_codegen_cranelift/src/pointer.rs +++ b/compiler/rustc_codegen_cranelift/src/pointer.rs @@ -39,8 +39,7 @@ impl Pointer { Pointer { base: PointerBase::Dangling(align), offset: Offset32::new(0) } } - #[cfg(debug_assertions)] - pub(crate) fn base_and_offset(self) -> (PointerBase, Offset32) { + pub(crate) fn debug_base_and_offset(self) -> (PointerBase, Offset32) { (self.base, self.offset) } diff --git a/compiler/rustc_codegen_cranelift/src/pretty_clif.rs b/compiler/rustc_codegen_cranelift/src/pretty_clif.rs index 9c91b92e515..d22ea3772ee 100644 --- a/compiler/rustc_codegen_cranelift/src/pretty_clif.rs +++ b/compiler/rustc_codegen_cranelift/src/pretty_clif.rs @@ -69,13 +69,15 @@ use crate::prelude::*; #[derive(Debug)] pub(crate) struct CommentWriter { + enabled: bool, global_comments: Vec<String>, entity_comments: FxHashMap<AnyEntity, String>, } impl CommentWriter { pub(crate) fn new<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) -> Self { - let global_comments = if cfg!(debug_assertions) { + let enabled = should_write_ir(tcx); + let global_comments = if enabled { vec![ format!("symbol {}", tcx.symbol_name(instance).name), format!("instance {:?}", instance), @@ -86,13 +88,17 @@ impl CommentWriter { vec![] }; - CommentWriter { global_comments, entity_comments: FxHashMap::default() } + CommentWriter { enabled, global_comments, entity_comments: FxHashMap::default() } } } -#[cfg(debug_assertions)] impl CommentWriter { + pub(crate) fn enabled(&self) -> bool { + self.enabled + } + pub(crate) fn add_global_comment<S: Into<String>>(&mut self, comment: S) { + debug_assert!(self.enabled); self.global_comments.push(comment.into()); } @@ -101,6 +107,8 @@ impl CommentWriter { entity: E, comment: S, ) { + debug_assert!(self.enabled); + use std::collections::hash_map::Entry; match self.entity_comments.entry(entity.into()) { Entry::Occupied(mut occ) => { @@ -179,7 +187,6 @@ impl FuncWriter for &'_ CommentWriter { } } -#[cfg(debug_assertions)] impl FunctionCx<'_, '_, '_> { pub(crate) fn add_global_comment<S: Into<String>>(&mut self, comment: S) { self.clif_comments.add_global_comment(comment); @@ -198,8 +205,8 @@ pub(crate) fn should_write_ir(tcx: TyCtxt<'_>) -> bool { tcx.sess.opts.output_types.contains_key(&OutputType::LlvmAssembly) } -pub(crate) fn write_ir_file<'tcx>( - tcx: TyCtxt<'tcx>, +pub(crate) fn write_ir_file( + tcx: TyCtxt<'_>, name: &str, write: impl FnOnce(&mut dyn Write) -> std::io::Result<()>, ) { @@ -217,10 +224,7 @@ pub(crate) fn write_ir_file<'tcx>( let clif_file_name = clif_output_dir.join(name); - let res: std::io::Result<()> = try { - let mut file = std::fs::File::create(clif_file_name)?; - write(&mut file)?; - }; + let res = std::fs::File::create(clif_file_name).and_then(|mut file| write(&mut file)); if let Err(err) = res { tcx.sess.warn(&format!("error writing ir file: {}", err)); } diff --git a/compiler/rustc_codegen_cranelift/src/trap.rs b/compiler/rustc_codegen_cranelift/src/trap.rs index bb63d72addf..1ab0703e981 100644 --- a/compiler/rustc_codegen_cranelift/src/trap.rs +++ b/compiler/rustc_codegen_cranelift/src/trap.rs @@ -17,8 +17,7 @@ fn codegen_print(fx: &mut FunctionCx<'_, '_, '_>, msg: &str) { ) .unwrap(); let puts = fx.cx.module.declare_func_in_func(puts, &mut fx.bcx.func); - #[cfg(debug_assertions)] - { + if fx.clif_comments.enabled() { fx.add_comment(puts, "puts"); } diff --git a/compiler/rustc_codegen_cranelift/src/value_and_place.rs b/compiler/rustc_codegen_cranelift/src/value_and_place.rs index cffaf79ded1..b97d3900984 100644 --- a/compiler/rustc_codegen_cranelift/src/value_and_place.rs +++ b/compiler/rustc_codegen_cranelift/src/value_and_place.rs @@ -2,7 +2,6 @@ use crate::prelude::*; -use cranelift_codegen::entity::EntityRef; use cranelift_codegen::ir::immediates::Offset32; fn codegen_field<'tcx>( @@ -414,7 +413,7 @@ impl<'tcx> CPlace<'tcx> { self, fx: &mut FunctionCx<'_, '_, 'tcx>, from: CValue<'tcx>, - #[cfg_attr(not(debug_assertions), allow(unused_variables))] method: &'static str, + method: &'static str, ) { fn transmute_value<'tcx>( fx: &mut FunctionCx<'_, '_, 'tcx>, @@ -462,8 +461,7 @@ impl<'tcx> CPlace<'tcx> { assert_eq!(self.layout().size, from.layout().size); - #[cfg(debug_assertions)] - { + if fx.clif_comments.enabled() { use cranelift_codegen::cursor::{Cursor, CursorPosition}; let cur_block = match fx.bcx.cursor().position() { CursorPosition::After(block) => block, @@ -707,6 +705,19 @@ pub(crate) fn assert_assignable<'tcx>( } // dyn for<'r> Trait<'r> -> dyn Trait<'_> is allowed } + (&ty::Adt(adt_def_a, substs_a), &ty::Adt(adt_def_b, substs_b)) + if adt_def_a.did == adt_def_b.did => + { + let mut types_a = substs_a.types(); + let mut types_b = substs_b.types(); + loop { + match (types_a.next(), types_b.next()) { + (Some(a), Some(b)) => assert_assignable(fx, a, b), + (None, None) => return, + (Some(_), None) | (None, Some(_)) => panic!("{:#?}/{:#?}", from_ty, to_ty), + } + } + } _ => { assert_eq!( from_ty, to_ty, diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs index 5effe687528..4226ed7d99b 100644 --- a/compiler/rustc_codegen_llvm/src/back/lto.rs +++ b/compiler/rustc_codegen_llvm/src/back/lto.rs @@ -24,6 +24,7 @@ use tracing::{debug, info}; use std::ffi::{CStr, CString}; use std::fs::File; use std::io; +use std::iter; use std::path::Path; use std::ptr; use std::slice; @@ -916,9 +917,7 @@ impl ThinLTOKeysMap { modules: &[llvm::ThinLTOModule], names: &[CString], ) -> Self { - let keys = modules - .iter() - .zip(names.iter()) + let keys = iter::zip(modules, names) .map(|(module, name)| { let key = build_string(|rust_str| unsafe { llvm::LLVMRustComputeLTOCacheKey(rust_str, module.identifier, data.0); diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index 388dd7ce81b..085935b94df 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -548,6 +548,15 @@ pub(crate) unsafe fn optimize( llvm::LLVMRustAddPass(fpm, find_pass("lint").unwrap()); continue; } + if pass_name == "insert-gcov-profiling" || pass_name == "instrprof" { + // Instrumentation must be inserted before optimization, + // otherwise LLVM may optimize some functions away which + // breaks llvm-cov. + // + // This mirrors what Clang does in lib/CodeGen/BackendUtil.cpp. + llvm::LLVMRustAddPass(mpm, find_pass(pass_name).unwrap()); + continue; + } if let Some(pass) = find_pass(pass_name) { extra_passes.push(pass); diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index f4852c91e53..896e56a9a1e 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -21,6 +21,7 @@ use rustc_target::abi::{self, Align, Size}; use rustc_target::spec::{HasTargetSpec, Target}; use std::borrow::Cow; use std::ffi::CStr; +use std::iter; use std::ops::{Deref, Range}; use std::ptr; use tracing::debug; @@ -1352,18 +1353,14 @@ impl Builder<'a, 'll, 'tcx> { let param_tys = self.cx.func_params_types(fn_ty); - let all_args_match = param_tys - .iter() - .zip(args.iter().map(|&v| self.val_ty(v))) + let all_args_match = iter::zip(¶m_tys, args.iter().map(|&v| self.val_ty(v))) .all(|(expected_ty, actual_ty)| *expected_ty == actual_ty); if all_args_match { return Cow::Borrowed(args); } - let casted_args: Vec<_> = param_tys - .into_iter() - .zip(args.iter()) + let casted_args: Vec<_> = iter::zip(param_tys, args) .enumerate() .map(|(i, (expected_ty, &actual_val))| { let actual_ty = self.val_ty(actual_val); diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index d5b32e58cc3..d90e93f116c 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -1962,9 +1962,7 @@ fn prepare_enum_metadata( let discriminant_type_metadata = |discr: Primitive| { let enumerators_metadata: Vec<_> = match enum_type.kind() { - ty::Adt(def, _) => def - .discriminants(tcx) - .zip(&def.variants) + ty::Adt(def, _) => iter::zip(def.discriminants(tcx), &def.variants) .map(|((_, discr), v)| { let name = v.ident.as_str(); let is_unsigned = match discr.ty.kind() { @@ -2336,9 +2334,7 @@ fn compute_type_parameters(cx: &CodegenCx<'ll, 'tcx>, ty: Ty<'tcx>) -> &'ll DIAr if substs.types().next().is_some() { let generics = cx.tcx.generics_of(def.did); let names = get_parameter_names(cx, generics); - let template_params: Vec<_> = substs - .iter() - .zip(names) + let template_params: Vec<_> = iter::zip(substs, names) .filter_map(|(kind, name)| { if let GenericArgKind::Type(ty) = kind.unpack() { let actual_type = diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs index abb87cb3656..e157a38aa03 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs @@ -37,6 +37,7 @@ use rustc_target::abi::{LayoutOf, Primitive, Size}; use libc::c_uint; use smallvec::SmallVec; use std::cell::RefCell; +use std::iter; use tracing::debug; mod create_scope_map; @@ -448,9 +449,7 @@ impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { // Again, only create type information if full debuginfo is enabled let template_params: Vec<_> = if cx.sess().opts.debuginfo == DebugInfo::Full { let names = get_parameter_names(cx, generics); - substs - .iter() - .zip(names) + iter::zip(substs, names) .filter_map(|(kind, name)| { if let GenericArgKind::Type(ty) = kind.unpack() { let actual_type = diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index de7f5fc6e29..5ca4b226c38 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -11,6 +11,7 @@ #![feature(extended_key_value_attributes)] #![feature(extern_types)] #![feature(in_band_lifetimes)] +#![feature(iter_zip)] #![feature(nll)] #![cfg_attr(bootstrap, feature(or_patterns))] #![recursion_limit = "256"] diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 82cd1be3b3b..af9d3d2dc26 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -190,33 +190,6 @@ pub enum RealPredicate { RealPredicateTrue = 15, } -impl RealPredicate { - pub fn from_generic(realpred: rustc_codegen_ssa::common::RealPredicate) -> Self { - match realpred { - rustc_codegen_ssa::common::RealPredicate::RealPredicateFalse => { - RealPredicate::RealPredicateFalse - } - rustc_codegen_ssa::common::RealPredicate::RealOEQ => RealPredicate::RealOEQ, - rustc_codegen_ssa::common::RealPredicate::RealOGT => RealPredicate::RealOGT, - rustc_codegen_ssa::common::RealPredicate::RealOGE => RealPredicate::RealOGE, - rustc_codegen_ssa::common::RealPredicate::RealOLT => RealPredicate::RealOLT, - rustc_codegen_ssa::common::RealPredicate::RealOLE => RealPredicate::RealOLE, - rustc_codegen_ssa::common::RealPredicate::RealONE => RealPredicate::RealONE, - rustc_codegen_ssa::common::RealPredicate::RealORD => RealPredicate::RealORD, - rustc_codegen_ssa::common::RealPredicate::RealUNO => RealPredicate::RealUNO, - rustc_codegen_ssa::common::RealPredicate::RealUEQ => RealPredicate::RealUEQ, - rustc_codegen_ssa::common::RealPredicate::RealUGT => RealPredicate::RealUGT, - rustc_codegen_ssa::common::RealPredicate::RealUGE => RealPredicate::RealUGE, - rustc_codegen_ssa::common::RealPredicate::RealULT => RealPredicate::RealULT, - rustc_codegen_ssa::common::RealPredicate::RealULE => RealPredicate::RealULE, - rustc_codegen_ssa::common::RealPredicate::RealUNE => RealPredicate::RealUNE, - rustc_codegen_ssa::common::RealPredicate::RealPredicateTrue => { - RealPredicate::RealPredicateTrue - } - } - } -} - /// LLVMTypeKind #[derive(Copy, Clone, PartialEq, Debug)] #[repr(C)] @@ -711,7 +684,7 @@ pub mod coverageinfo { } impl CounterMappingRegion { - pub fn code_region( + crate fn code_region( counter: coverage_map::Counter, file_id: u32, start_line: u32, @@ -731,7 +704,10 @@ pub mod coverageinfo { } } - pub fn expansion_region( + // This function might be used in the future; the LLVM API is still evolving, as is coverage + // support. + #[allow(dead_code)] + crate fn expansion_region( file_id: u32, expanded_file_id: u32, start_line: u32, @@ -751,7 +727,10 @@ pub mod coverageinfo { } } - pub fn skipped_region( + // This function might be used in the future; the LLVM API is still evolving, as is coverage + // support. + #[allow(dead_code)] + crate fn skipped_region( file_id: u32, start_line: u32, start_col: u32, @@ -770,7 +749,10 @@ pub mod coverageinfo { } } - pub fn gap_region( + // This function might be used in the future; the LLVM API is still evolving, as is coverage + // support. + #[allow(dead_code)] + crate fn gap_region( counter: coverage_map::Counter, file_id: u32, start_line: u32, diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 4d6bc838130..686ebc13ea3 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -1651,6 +1651,16 @@ fn linker_with_args<'a, B: ArchiveBuilder<'a>>( cmd.add_eh_frame_header(); } + // NO-OPT-OUT, OBJECT-FILES-NO, AUDIT-ORDER + // Make the binary compatible with data execution prevention schemes. + cmd.add_no_exec(); + + // NO-OPT-OUT, OBJECT-FILES-NO + // Avoid linking to dynamic libraries unless they satisfy some undefined symbols + // at the point at which they are specified on the command line. + // Must be passed before any dynamic libraries. + cmd.add_as_needed(); + // NO-OPT-OUT, OBJECT-FILES-NO if crt_objects_fallback { cmd.no_crt_objects(); diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs index bb35e7ec894..e19274e579b 100644 --- a/compiler/rustc_codegen_ssa/src/back/linker.rs +++ b/compiler/rustc_codegen_ssa/src/back/linker.rs @@ -130,6 +130,8 @@ pub trait Linker { fn group_end(&mut self); fn linker_plugin_lto(&mut self); fn add_eh_frame_header(&mut self) {} + fn add_no_exec(&mut self) {} + fn add_as_needed(&mut self) {} fn finalize(&mut self); } @@ -641,6 +643,20 @@ impl<'a> Linker for GccLinker<'a> { fn add_eh_frame_header(&mut self) { self.linker_arg("--eh-frame-hdr"); } + + fn add_no_exec(&mut self) { + if self.sess.target.is_like_windows { + self.linker_arg("--nxcompat"); + } else if self.sess.target.linker_is_gnu { + self.linker_arg("-znoexecstack"); + } + } + + fn add_as_needed(&mut self) { + if self.sess.target.linker_is_gnu { + self.linker_arg("--as-needed"); + } + } } pub struct MsvcLinker<'a> { @@ -878,6 +894,10 @@ impl<'a> Linker for MsvcLinker<'a> { fn linker_plugin_lto(&mut self) { // Do nothing } + + fn add_no_exec(&mut self) { + self.cmd.arg("/NXCOMPAT"); + } } pub struct EmLinker<'a> { diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs index 6eead2812ba..56b4ef79383 100644 --- a/compiler/rustc_codegen_ssa/src/lib.rs +++ b/compiler/rustc_codegen_ssa/src/lib.rs @@ -8,6 +8,7 @@ #![feature(nll)] #![cfg_attr(bootstrap, feature(or_patterns))] #![feature(associated_type_bounds)] +#![feature(iter_zip)] #![recursion_limit = "256"] #![feature(box_syntax)] diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs index 3f945478213..91df67b53d2 100644 --- a/compiler/rustc_codegen_ssa/src/mir/mod.rs +++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs @@ -282,9 +282,7 @@ fn create_funclets<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( IndexVec<mir::BasicBlock, Option<Bx::BasicBlock>>, IndexVec<mir::BasicBlock, Option<Bx::Funclet>>, ) { - block_bxs - .iter_enumerated() - .zip(cleanup_kinds) + iter::zip(block_bxs.iter_enumerated(), cleanup_kinds) .map(|((bb, &llbb), cleanup_kind)| { match *cleanup_kind { CleanupKind::Funclet if base::wants_msvc_seh(bx.sess()) => {} diff --git a/compiler/rustc_data_structures/src/tagged_ptr/drop.rs b/compiler/rustc_data_structures/src/tagged_ptr/drop.rs index 63f64beae5a..d44ccd368b3 100644 --- a/compiler/rustc_data_structures/src/tagged_ptr/drop.rs +++ b/compiler/rustc_data_structures/src/tagged_ptr/drop.rs @@ -42,18 +42,9 @@ where pub fn pointer_ref(&self) -> &P::Target { self.raw.pointer_ref() } - pub fn pointer_mut(&mut self) -> &mut P::Target - where - P: std::ops::DerefMut, - { - self.raw.pointer_mut() - } pub fn tag(&self) -> T { self.raw.tag() } - pub fn set_tag(&mut self, tag: T) { - self.raw.set_tag(tag); - } } impl<P, T, const COMPARE_PACKED: bool> std::ops::Deref for TaggedPtr<P, T, COMPARE_PACKED> diff --git a/compiler/rustc_data_structures/src/work_queue.rs b/compiler/rustc_data_structures/src/work_queue.rs index cc562bc1e4d..10317f1afff 100644 --- a/compiler/rustc_data_structures/src/work_queue.rs +++ b/compiler/rustc_data_structures/src/work_queue.rs @@ -41,10 +41,4 @@ impl<T: Idx> WorkQueue<T> { None } } - - /// Returns `true` if nothing is enqueued. - #[inline] - pub fn is_empty(&self) -> bool { - self.deque.is_empty() - } } diff --git a/compiler/rustc_driver/src/lib.rs b/compiler/rustc_driver/src/lib.rs index e527d55fc2a..c8891734cce 100644 --- a/compiler/rustc_driver/src/lib.rs +++ b/compiler/rustc_driver/src/lib.rs @@ -146,6 +146,7 @@ impl<'a, 'b> RunCompiler<'a, 'b> { pub fn new(at_args: &'a [String], callbacks: &'b mut (dyn Callbacks + Send)) -> Self { Self { at_args, callbacks, file_loader: None, emitter: None, make_codegen_backend: None } } + /// Used by cg_clif. pub fn set_make_codegen_backend( &mut self, make_codegen_backend: Option< @@ -155,10 +156,12 @@ impl<'a, 'b> RunCompiler<'a, 'b> { self.make_codegen_backend = make_codegen_backend; self } + /// Used by RLS. pub fn set_emitter(&mut self, emitter: Option<Box<dyn Write + Send>>) -> &mut Self { self.emitter = emitter; self } + /// Used by RLS. pub fn set_file_loader( &mut self, file_loader: Option<Box<dyn FileLoader + Send + Sync>>, diff --git a/compiler/rustc_driver/src/pretty.rs b/compiler/rustc_driver/src/pretty.rs index 1544c975838..e0c140b143b 100644 --- a/compiler/rustc_driver/src/pretty.rs +++ b/compiler/rustc_driver/src/pretty.rs @@ -108,13 +108,6 @@ trait HirPrinterSupport<'hir>: pprust_hir::PpAnn { /// (Rust does not yet support upcasting from a trait object to /// an object for one of its super-traits.) fn pp_ann(&self) -> &dyn pprust_hir::PpAnn; - - /// Computes an user-readable representation of a path, if possible. - fn node_path(&self, id: hir::HirId) -> Option<String> { - self.hir_map().and_then(|map| map.def_path_from_hir_id(id)).map(|path| { - path.data.into_iter().map(|elem| elem.data.to_string()).collect::<Vec<_>>().join("::") - }) - } } struct NoAnn<'hir> { @@ -327,10 +320,6 @@ impl<'tcx> HirPrinterSupport<'tcx> for TypedAnnotation<'tcx> { fn pp_ann(&self) -> &dyn pprust_hir::PpAnn { self } - - fn node_path(&self, id: hir::HirId) -> Option<String> { - Some(self.tcx.def_path_str(self.tcx.hir().local_def_id(id).to_def_id())) - } } impl<'tcx> pprust_hir::PpAnn for TypedAnnotation<'tcx> { diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs index ce5b130dd97..b2f6a0c1014 100644 --- a/compiler/rustc_errors/src/diagnostic.rs +++ b/compiler/rustc_errors/src/diagnostic.rs @@ -69,10 +69,6 @@ impl DiagnosticStyledString { pub fn highlighted<S: Into<String>>(t: S) -> DiagnosticStyledString { DiagnosticStyledString(vec![StringPart::Highlighted(t.into())]) } - - pub fn content(&self) -> String { - self.0.iter().map(|x| x.content()).collect::<String>() - } } #[derive(Debug, PartialEq, Eq)] @@ -81,14 +77,6 @@ pub enum StringPart { Highlighted(String), } -impl StringPart { - pub fn content(&self) -> &str { - match self { - &StringPart::Normal(ref s) | &StringPart::Highlighted(ref s) => s, - } - } -} - impl Diagnostic { pub fn new(level: Level, message: &str) -> Self { Diagnostic::new_with_code(level, None, message) @@ -156,7 +144,7 @@ impl Diagnostic { self } - pub fn note_expected_found( + crate fn note_expected_found( &mut self, expected_label: &dyn fmt::Display, expected: DiagnosticStyledString, @@ -166,7 +154,7 @@ impl Diagnostic { self.note_expected_found_extra(expected_label, expected, found_label, found, &"", &"") } - pub fn note_unsuccessful_coercion( + crate fn note_unsuccessful_coercion( &mut self, expected: DiagnosticStyledString, found: DiagnosticStyledString, @@ -256,33 +244,33 @@ impl Diagnostic { /// Prints the span with a note above it. /// This is like [`Diagnostic::note()`], but it gets its own span. - pub fn span_note<S: Into<MultiSpan>>(&mut self, sp: S, msg: &str) -> &mut Self { + crate fn span_note<S: Into<MultiSpan>>(&mut self, sp: S, msg: &str) -> &mut Self { self.sub(Level::Note, msg, sp.into(), None); self } /// Add a warning attached to this diagnostic. - pub fn warn(&mut self, msg: &str) -> &mut Self { + crate fn warn(&mut self, msg: &str) -> &mut Self { self.sub(Level::Warning, msg, MultiSpan::new(), None); self } /// Prints the span with a warning above it. /// This is like [`Diagnostic::warn()`], but it gets its own span. - pub fn span_warn<S: Into<MultiSpan>>(&mut self, sp: S, msg: &str) -> &mut Self { + crate fn span_warn<S: Into<MultiSpan>>(&mut self, sp: S, msg: &str) -> &mut Self { self.sub(Level::Warning, msg, sp.into(), None); self } /// Add a help message attached to this diagnostic. - pub fn help(&mut self, msg: &str) -> &mut Self { + crate fn help(&mut self, msg: &str) -> &mut Self { self.sub(Level::Help, msg, MultiSpan::new(), None); self } /// Prints the span with some help above it. /// This is like [`Diagnostic::help()`], but it gets its own span. - pub fn span_help<S: Into<MultiSpan>>(&mut self, sp: S, msg: &str) -> &mut Self { + crate fn span_help<S: Into<MultiSpan>>(&mut self, sp: S, msg: &str) -> &mut Self { self.sub(Level::Help, msg, sp.into(), None); self } @@ -311,36 +299,6 @@ impl Diagnostic { self } - /// Show multiple suggestions that have multiple parts. - /// See also [`Diagnostic::multipart_suggestion()`]. - pub fn multipart_suggestions( - &mut self, - msg: &str, - suggestions: Vec<Vec<(Span, String)>>, - applicability: Applicability, - ) -> &mut Self { - assert!(!suggestions.is_empty()); - for s in &suggestions { - assert!(!s.is_empty()); - } - self.suggestions.push(CodeSuggestion { - substitutions: suggestions - .into_iter() - .map(|suggestion| Substitution { - parts: suggestion - .into_iter() - .map(|(span, snippet)| SubstitutionPart { snippet, span }) - .collect(), - }) - .collect(), - msg: msg.to_owned(), - style: SuggestionStyle::ShowCode, - applicability, - tool_metadata: Default::default(), - }); - self - } - /// Prints out a message with for a multipart suggestion without showing the suggested code. /// /// This is intended to be used for suggestions that are obvious in what the changes need to @@ -567,7 +525,7 @@ impl Diagnostic { self.code.clone() } - pub fn set_primary_message<M: Into<String>>(&mut self, msg: M) -> &mut Self { + crate fn set_primary_message<M: Into<String>>(&mut self, msg: M) -> &mut Self { self.message[0] = (msg.into(), Style::NoStyle); self } @@ -582,6 +540,8 @@ impl Diagnostic { /// Convenience function for internal use, clients should use one of the /// public methods above. + /// + /// Used by `proc_macro_server` for implementing `server::Diagnostic`. pub fn sub( &mut self, level: Level, diff --git a/compiler/rustc_errors/src/diagnostic_builder.rs b/compiler/rustc_errors/src/diagnostic_builder.rs index 79507e61522..3fc63b4e50c 100644 --- a/compiler/rustc_errors/src/diagnostic_builder.rs +++ b/compiler/rustc_errors/src/diagnostic_builder.rs @@ -45,6 +45,9 @@ macro_rules! forward { pub fn $n:ident(&self, $($name:ident: $ty:ty),* $(,)?) -> &Self ) => { $(#[$attrs])* + // we always document with --document-private-items + #[cfg_attr(not(bootstrap), allow(rustdoc::private_intra_doc_links))] + #[cfg_attr(bootstrap, allow(private_intra_doc_links))] #[doc = concat!("See [`Diagnostic::", stringify!($n), "()`].")] pub fn $n(&self, $($name: $ty),*) -> &Self { self.diagnostic.$n($($name),*); @@ -59,6 +62,9 @@ macro_rules! forward { ) => { $(#[$attrs])* #[doc = concat!("See [`Diagnostic::", stringify!($n), "()`].")] + // we always document with --document-private-items + #[cfg_attr(not(bootstrap), allow(rustdoc::private_intra_doc_links))] + #[cfg_attr(bootstrap, allow(private_intra_doc_links))] pub fn $n(&mut self, $($name: $ty),*) -> &mut Self { self.0.diagnostic.$n($($name),*); self @@ -76,6 +82,9 @@ macro_rules! forward { ) => { $(#[$attrs])* #[doc = concat!("See [`Diagnostic::", stringify!($n), "()`].")] + // we always document with --document-private-items + #[cfg_attr(not(bootstrap), allow(rustdoc::private_intra_doc_links))] + #[cfg_attr(bootstrap, allow(private_intra_doc_links))] pub fn $n<$($generic: $bound),*>(&mut self, $($name: $ty),*) -> &mut Self { self.0.diagnostic.$n($($name),*); self @@ -157,19 +166,6 @@ impl<'a> DiagnosticBuilder<'a> { buffered_diagnostics.extend(self.into_diagnostic().map(|(diag, _)| diag)); } - /// Convenience function for internal use, clients should use one of the - /// span_* methods instead. - pub fn sub<S: Into<MultiSpan>>( - &mut self, - level: Level, - message: &str, - span: Option<S>, - ) -> &mut Self { - let span = span.map(|s| s.into()).unwrap_or_else(MultiSpan::new); - self.0.diagnostic.sub(level, message, span, None); - self - } - /// Delay emission of this diagnostic as a bug. /// /// This can be useful in contexts where an error indicates a bug but @@ -270,20 +266,6 @@ impl<'a> DiagnosticBuilder<'a> { self } - /// See [`Diagnostic::multipart_suggestions()`]. - pub fn multipart_suggestions( - &mut self, - msg: &str, - suggestions: Vec<Vec<(Span, String)>>, - applicability: Applicability, - ) -> &mut Self { - if !self.0.allow_suggestions { - return self; - } - self.0.diagnostic.multipart_suggestions(msg, suggestions, applicability); - self - } - /// See [`Diagnostic::tool_only_multipart_suggestion()`]. pub fn tool_only_multipart_suggestion( &mut self, diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index 66499fbb8da..8ec06feb5bf 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -1258,7 +1258,7 @@ impl EmitterWriter { buffer.append(0, ": ", header_style); } for &(ref text, _) in msg.iter() { - buffer.append(0, text, header_style); + buffer.append(0, &replace_tabs(text), header_style); } } @@ -2214,9 +2214,7 @@ pub fn is_case_difference(sm: &SourceMap, suggested: &str, sp: Span) -> bool { }; let ascii_confusables = &['c', 'f', 'i', 'k', 'o', 's', 'u', 'v', 'w', 'x', 'y', 'z']; // All the chars that differ in capitalization are confusable (above): - let confusable = found - .chars() - .zip(suggested.chars()) + let confusable = iter::zip(found.chars(), suggested.chars()) .filter(|(f, s)| f != s) .all(|(f, s)| (ascii_confusables.contains(&f) || ascii_confusables.contains(&s))); confusable && found.to_lowercase() == suggested.to_lowercase() diff --git a/compiler/rustc_errors/src/json.rs b/compiler/rustc_errors/src/json.rs index c27b39a9d62..2bce1ac3c0a 100644 --- a/compiler/rustc_errors/src/json.rs +++ b/compiler/rustc_errors/src/json.rs @@ -493,7 +493,7 @@ impl DiagnosticSpanLine { h_end: usize, ) -> DiagnosticSpanLine { DiagnosticSpanLine { - text: sf.get_line(index).map_or(String::new(), |l| l.into_owned()), + text: sf.get_line(index).map_or_else(String::new, |l| l.into_owned()), highlight_start: h_start, highlight_end: h_end, } diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index fa855f544e8..ac7353730ad 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -6,6 +6,7 @@ #![feature(crate_visibility_modifier)] #![feature(backtrace)] #![feature(extended_key_value_attributes)] +#![feature(iter_zip)] #![feature(nll)] #[macro_use] @@ -690,10 +691,6 @@ impl Handler { db } - pub fn failure(&self, msg: &str) { - self.inner.borrow_mut().failure(msg); - } - pub fn fatal(&self, msg: &str) -> FatalError { self.inner.borrow_mut().fatal(msg) } diff --git a/compiler/rustc_errors/src/registry.rs b/compiler/rustc_errors/src/registry.rs index b1d770d5bd5..da764d993bb 100644 --- a/compiler/rustc_errors/src/registry.rs +++ b/compiler/rustc_errors/src/registry.rs @@ -13,10 +13,6 @@ impl Registry { Registry { long_descriptions: long_descriptions.iter().copied().collect() } } - /// This will panic if an invalid error code is passed in - pub fn find_description(&self, code: &str) -> Option<&'static str> { - self.long_descriptions[code] - } /// Returns `InvalidErrorCode` if the code requested does not exist in the /// registry. Otherwise, returns an `Option` where `None` means the error /// code is valid but has no extended information. diff --git a/compiler/rustc_errors/src/snippet.rs b/compiler/rustc_errors/src/snippet.rs index acb88e57db5..3fe02bd0cee 100644 --- a/compiler/rustc_errors/src/snippet.rs +++ b/compiler/rustc_errors/src/snippet.rs @@ -121,16 +121,6 @@ impl Annotation { matches!(self.annotation_type, AnnotationType::MultilineLine(_)) } - pub fn is_multiline(&self) -> bool { - matches!( - self.annotation_type, - AnnotationType::Multiline(_) - | AnnotationType::MultilineStart(_) - | AnnotationType::MultilineLine(_) - | AnnotationType::MultilineEnd(_) - ) - } - pub fn len(&self) -> usize { // Account for usize underflows if self.end_col > self.start_col { diff --git a/compiler/rustc_errors/src/styled_buffer.rs b/compiler/rustc_errors/src/styled_buffer.rs index ef71ee36ea3..ec122e7be6e 100644 --- a/compiler/rustc_errors/src/styled_buffer.rs +++ b/compiler/rustc_errors/src/styled_buffer.rs @@ -1,6 +1,7 @@ // Code for creating styled buffers use crate::snippet::{Style, StyledString}; +use std::iter; #[derive(Debug)] pub struct StyledBuffer { @@ -20,11 +21,11 @@ impl StyledBuffer { let mut output: Vec<Vec<StyledString>> = vec![]; let mut styled_vec: Vec<StyledString> = vec![]; - for (row, row_style) in self.text.iter().zip(&self.styles) { + for (row, row_style) in iter::zip(&self.text, &self.styles) { let mut current_style = Style::NoStyle; let mut current_text = String::new(); - for (&c, &s) in row.iter().zip(row_style) { + for (&c, &s) in iter::zip(row, row_style) { if s != current_style { if !current_text.is_empty() { styled_vec.push(StyledString { text: current_text, style: current_style }); diff --git a/compiler/rustc_expand/src/build.rs b/compiler/rustc_expand/src/build.rs index 3664ff3ae8a..cb8b9398283 100644 --- a/compiler/rustc_expand/src/build.rs +++ b/compiler/rustc_expand/src/build.rs @@ -253,17 +253,6 @@ impl<'a> ExtCtxt<'a> { let pathexpr = self.expr_path(self.path_global(sp, fn_path)); self.expr_call(sp, pathexpr, args) } - pub fn expr_method_call( - &self, - span: Span, - expr: P<ast::Expr>, - ident: Ident, - mut args: Vec<P<ast::Expr>>, - ) -> P<ast::Expr> { - args.insert(0, expr); - let segment = ast::PathSegment::from_ident(ident.with_span_pos(span)); - self.expr(span, ast::ExprKind::MethodCall(segment, args, span)) - } pub fn expr_block(&self, b: P<ast::Block>) -> P<ast::Expr> { self.expr(b.span, ast::ExprKind::Block(b, None)) } diff --git a/compiler/rustc_expand/src/lib.rs b/compiler/rustc_expand/src/lib.rs index 14f04dcb51a..5fb85867501 100644 --- a/compiler/rustc_expand/src/lib.rs +++ b/compiler/rustc_expand/src/lib.rs @@ -2,6 +2,7 @@ #![feature(crate_visibility_modifier)] #![feature(decl_macro)] #![feature(destructuring_assignment)] +#![feature(iter_zip)] #![cfg_attr(bootstrap, feature(or_patterns))] #![feature(proc_macro_diagnostic)] #![feature(proc_macro_internals)] diff --git a/compiler/rustc_expand/src/mbe/macro_check.rs b/compiler/rustc_expand/src/mbe/macro_check.rs index 91add4f9218..3497e5ad543 100644 --- a/compiler/rustc_expand/src/mbe/macro_check.rs +++ b/compiler/rustc_expand/src/mbe/macro_check.rs @@ -116,6 +116,8 @@ use rustc_span::{symbol::MacroRulesNormalizedIdent, MultiSpan, Span}; use smallvec::SmallVec; +use std::iter; + /// Stack represented as linked list. /// /// Those are used for environments because they grow incrementally and are not mutable. @@ -204,7 +206,7 @@ pub(super) fn check_meta_variables( sess.span_diagnostic.span_bug(span, "length mismatch between LHSes and RHSes") } let mut valid = true; - for (lhs, rhs) in lhses.iter().zip(rhses.iter()) { + for (lhs, rhs) in iter::zip(lhses, rhses) { let mut binders = Binders::default(); check_binders(sess, node_id, lhs, &Stack::Empty, &mut binders, &Stack::Empty, &mut valid); check_occurrences(sess, node_id, rhs, &Stack::Empty, &binders, &Stack::Empty, &mut valid); diff --git a/compiler/rustc_expand/src/tokenstream/tests.rs b/compiler/rustc_expand/src/tokenstream/tests.rs index 4e818e9feb0..8b546e7e4a3 100644 --- a/compiler/rustc_expand/src/tokenstream/tests.rs +++ b/compiler/rustc_expand/src/tokenstream/tests.rs @@ -1,7 +1,7 @@ use crate::tests::string_to_stream; use rustc_ast::token; -use rustc_ast::tokenstream::{TokenStream, TokenStreamBuilder, TokenTree}; +use rustc_ast::tokenstream::{Spacing, TokenStream, TokenStreamBuilder, TokenTree}; use rustc_span::with_default_session_globals; use rustc_span::{BytePos, Span, Symbol}; use smallvec::smallvec; @@ -14,6 +14,10 @@ fn sp(a: u32, b: u32) -> Span { Span::with_root_ctxt(BytePos(a), BytePos(b)) } +fn joint(tree: TokenTree) -> TokenStream { + TokenStream::new(vec![(tree, Spacing::Joint)]) +} + #[test] fn test_concat() { with_default_session_globals(|| { @@ -99,8 +103,8 @@ fn test_is_empty() { fn test_dotdotdot() { with_default_session_globals(|| { let mut builder = TokenStreamBuilder::new(); - builder.push(TokenTree::token(token::Dot, sp(0, 1)).joint()); - builder.push(TokenTree::token(token::Dot, sp(1, 2)).joint()); + builder.push(joint(TokenTree::token(token::Dot, sp(0, 1)))); + builder.push(joint(TokenTree::token(token::Dot, sp(1, 2)))); builder.push(TokenTree::token(token::Dot, sp(2, 3))); let stream = builder.build(); assert!(stream.eq_unspanned(&string_to_ts("..."))); diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs index ce9f711b27e..f006351647e 100644 --- a/compiler/rustc_feature/src/accepted.rs +++ b/compiler/rustc_feature/src/accepted.rs @@ -276,7 +276,7 @@ declare_features! ( /// The smallest useful subset of `const_generics`. (accepted, min_const_generics, "1.51.0", Some(74878), None), /// The `unsafe_op_in_unsafe_fn` lint (allowed by default): no longer treat an unsafe function as an unsafe block. - (accepted, unsafe_block_in_unsafe_fn, "1.51.0", Some(71668), None), + (accepted, unsafe_block_in_unsafe_fn, "1.52.0", Some(71668), None), /// Allows the use of or-patterns (e.g., `0 | 1`). (accepted, or_patterns, "1.53.0", Some(54883), None), diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index fb08a7b8cea..040260f5cf5 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -216,6 +216,10 @@ declare_features! ( /// Renamed from `optin_builtin_traits`. (active, auto_traits, "1.50.0", Some(13231), None), + /// Allows `#[doc(notable_trait)]`. + /// Renamed from `doc_spotlight`. + (active, doc_notable_trait, "1.52.0", Some(45040), None), + // no-tracking-issue-end // ------------------------------------------------------------------------- @@ -374,9 +378,6 @@ declare_features! ( /// Allows `#[doc(masked)]`. (active, doc_masked, "1.21.0", Some(44027), None), - /// Allows `#[doc(spotlight)]`. - (active, doc_spotlight, "1.22.0", Some(45040), None), - /// Allows `#[doc(include = "some-file")]`. (active, external_doc, "1.22.0", Some(44732), None), diff --git a/compiler/rustc_feature/src/removed.rs b/compiler/rustc_feature/src/removed.rs index aff66053c93..8ba67a00f8d 100644 --- a/compiler/rustc_feature/src/removed.rs +++ b/compiler/rustc_feature/src/removed.rs @@ -80,6 +80,11 @@ declare_features! ( Some("subsumed by `#![feature(allocator_internals)]`")), /// Allows identifying crates that contain sanitizer runtimes. (removed, sanitizer_runtime, "1.17.0", None, None, None), + /// Allows `#[doc(spotlight)]`. + /// The attribute was renamed to `#[doc(notable_trait)]` + /// and the feature to `doc_notable_trait`. + (removed, doc_spotlight, "1.22.0", Some(45040), None, + Some("renamed to `doc_notable_trait`")), (removed, proc_macro_mod, "1.27.0", Some(54727), None, Some("subsumed by `#![feature(proc_macro_hygiene)]`")), (removed, proc_macro_expr, "1.27.0", Some(54727), None, diff --git a/compiler/rustc_graphviz/src/lib.rs b/compiler/rustc_graphviz/src/lib.rs index 9653ff022f1..db70beb5914 100644 --- a/compiler/rustc_graphviz/src/lib.rs +++ b/compiler/rustc_graphviz/src/lib.rs @@ -413,10 +413,6 @@ impl<'a> Id<'a> { pub fn as_slice(&'a self) -> &'a str { &*self.name } - - pub fn name(self) -> Cow<'a, str> { - self.name - } } /// Each instance of a type that implements `Label<C>` maps to a @@ -484,10 +480,6 @@ impl<'a> LabelText<'a> { LabelStr(s.into()) } - pub fn escaped<S: Into<Cow<'a, str>>>(s: S) -> LabelText<'a> { - EscStr(s.into()) - } - pub fn html<S: Into<Cow<'a, str>>>(s: S) -> LabelText<'a> { HtmlStr(s.into()) } @@ -543,11 +535,6 @@ impl<'a> LabelText<'a> { } } - /// Puts `prefix` on a line above this label, with a blank line separator. - pub fn prefix_line(self, prefix: LabelText<'_>) -> LabelText<'static> { - prefix.suffix_line(self) - } - /// Puts `suffix` on a line below this label, with a blank line separator. pub fn suffix_line(self, suffix: LabelText<'_>) -> LabelText<'static> { let mut prefix = self.pre_escaped_content().into_owned(); @@ -602,11 +589,6 @@ pub enum RenderOption { DarkTheme, } -/// Returns vec holding all the default render options. -pub fn default_options() -> Vec<RenderOption> { - vec![] -} - /// Renders directed graph `g` into the writer `w` in DOT syntax. /// (Simple wrapper around `render_opts` that passes a default set of options.) pub fn render<'a, N, E, G, W>(g: &'a G, w: &mut W) -> io::Result<()> diff --git a/compiler/rustc_graphviz/src/tests.rs b/compiler/rustc_graphviz/src/tests.rs index 70b8197f5ef..a297bac86c4 100644 --- a/compiler/rustc_graphviz/src/tests.rs +++ b/compiler/rustc_graphviz/src/tests.rs @@ -111,7 +111,7 @@ impl<'a> Labeller<'a> for LabelledGraph { fn node_label(&'a self, n: &Node) -> LabelText<'a> { match self.node_labels[*n] { Some(l) => LabelStr(l.into()), - None => LabelStr(id_name(n).name()), + None => LabelStr(id_name(n).name), } } fn edge_label(&'a self, e: &&'a Edge) -> LabelText<'a> { diff --git a/compiler/rustc_hir/src/definitions.rs b/compiler/rustc_hir/src/definitions.rs index 3266dfac702..0f77de9fb25 100644 --- a/compiler/rustc_hir/src/definitions.rs +++ b/compiler/rustc_hir/src/definitions.rs @@ -87,6 +87,7 @@ impl DefPathTable { hash } + /// Used by librustdoc for fake DefIds. pub fn num_def_ids(&self) -> usize { self.index_to_key.len() } @@ -319,12 +320,6 @@ impl Definitions { self.table.def_path_hash(id.local_def_index) } - #[inline] - pub fn def_path_hash_to_def_id(&self, def_path_hash: DefPathHash) -> LocalDefId { - let local_def_index = self.table.def_path_hash_to_index[&def_path_hash]; - LocalDefId { local_def_index } - } - /// Returns the path from the crate root to `index`. The root /// nodes are not included in the path (i.e., this will be an /// empty vector for the crate root). For an inlined item, this diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index d03584d49a5..6317808e7fb 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1,5 +1,5 @@ // ignore-tidy-filelength -use crate::def::{CtorKind, DefKind, Namespace, Res}; +use crate::def::{CtorKind, DefKind, Res}; use crate::def_id::DefId; crate use crate::hir_id::HirId; use crate::{itemlikevisit, LangItem}; @@ -402,7 +402,7 @@ pub enum TraitBoundModifier { /// `typeck::collect::compute_bounds` matches these against /// the "special" built-in traits (see `middle::lang_items`) and /// detects `Copy`, `Send` and `Sync`. -#[derive(Debug, HashStable_Generic)] +#[derive(Clone, Debug, HashStable_Generic)] pub enum GenericBound<'hir> { Trait(PolyTraitRef<'hir>, TraitBoundModifier), // FIXME(davidtwco): Introduce `PolyTraitRef::LangItem` @@ -625,13 +625,6 @@ pub struct ModuleItems { pub foreign_items: BTreeSet<ForeignItemId>, } -/// A type representing only the top-level module. -#[derive(Encodable, Debug, HashStable_Generic)] -pub struct CrateItem<'hir> { - pub module: Mod<'hir>, - pub span: Span, -} - /// The top-level data structure that stores the entire contents of /// the crate currently being compiled. /// @@ -640,7 +633,7 @@ pub struct CrateItem<'hir> { /// [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/hir.html #[derive(Debug)] pub struct Crate<'hir> { - pub item: CrateItem<'hir>, + pub item: Mod<'hir>, pub exported_macros: &'hir [MacroDef<'hir>], // Attributes from non-exported macros, kept only for collecting the library feature list. pub non_exported_macro_attrs: &'hir [Attribute], @@ -2118,15 +2111,6 @@ pub enum ImplItemKind<'hir> { TyAlias(&'hir Ty<'hir>), } -impl ImplItemKind<'_> { - pub fn namespace(&self) -> Namespace { - match self { - ImplItemKind::TyAlias(..) => Namespace::TypeNS, - ImplItemKind::Const(..) | ImplItemKind::Fn(..) => Namespace::ValueNS, - } - } -} - // The name of the associated type for `Fn` return types. pub const FN_OUTPUT_NAME: Symbol = sym::Output; @@ -2215,6 +2199,9 @@ impl PrimTy { Self::Str, ]; + /// Like [`PrimTy::name`], but returns a &str instead of a symbol. + /// + /// Used by rustdoc. pub fn name_str(self) -> &'static str { match self { PrimTy::Int(i) => i.name_str(), @@ -2569,7 +2556,7 @@ pub enum UseKind { /// that the `ref_id` is for. Note that `ref_id`'s value is not the `HirId` of the /// trait being referred to but just a unique `HirId` that serves as a key /// within the resolution map. -#[derive(Debug, HashStable_Generic)] +#[derive(Clone, Debug, HashStable_Generic)] pub struct TraitRef<'hir> { pub path: &'hir Path<'hir>, // Don't hash the `ref_id`. It is tracked via the thing it is used to access. @@ -2588,7 +2575,7 @@ impl TraitRef<'_> { } } -#[derive(Debug, HashStable_Generic)] +#[derive(Clone, Debug, HashStable_Generic)] pub struct PolyTraitRef<'hir> { /// The `'a` in `for<'a> Foo<&'a T>`. pub bound_generic_params: &'hir [GenericParam<'hir>], @@ -2989,7 +2976,7 @@ pub enum Node<'hir> { GenericParam(&'hir GenericParam<'hir>), Visibility(&'hir Visibility<'hir>), - Crate(&'hir CrateItem<'hir>), + Crate(&'hir Mod<'hir>), } impl<'hir> Node<'hir> { diff --git a/compiler/rustc_hir/src/hir_id.rs b/compiler/rustc_hir/src/hir_id.rs index e0b3d9026a0..0b25ebc27bd 100644 --- a/compiler/rustc_hir/src/hir_id.rs +++ b/compiler/rustc_hir/src/hir_id.rs @@ -63,6 +63,7 @@ pub const CRATE_HIR_ID: HirId = HirId { local_id: ItemLocalId::from_u32(0), }; +/// N.B. This collection is currently unused, but will be used by #72015 and future PRs. #[derive(Clone, Default, Debug, Encodable, Decodable)] pub struct HirIdVec<T> { map: IndexVec<LocalDefId, IndexVec<ItemLocalId, T>>, diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 9b908b141af..d766a68e194 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -478,7 +478,7 @@ pub trait Visitor<'v>: Sized { /// Walks the contents of a crate. See also `Crate::visit_all_items`. pub fn walk_crate<'v, V: Visitor<'v>>(visitor: &mut V, krate: &'v Crate<'v>) { - visitor.visit_mod(&krate.item.module, krate.item.span, CRATE_HIR_ID); + visitor.visit_mod(&krate.item, krate.item.inner, CRATE_HIR_ID); walk_list!(visitor, visit_macro_def, krate.exported_macros); for (&id, attrs) in krate.attrs.iter() { for a in *attrs { diff --git a/compiler/rustc_hir/src/pat_util.rs b/compiler/rustc_hir/src/pat_util.rs index 9e0a6aae242..28529affd5d 100644 --- a/compiler/rustc_hir/src/pat_util.rs +++ b/compiler/rustc_hir/src/pat_util.rs @@ -89,26 +89,6 @@ impl hir::Pat<'_> { }) } - /// Checks if the pattern contains any patterns that bind something to - /// an ident, e.g., `foo`, or `Foo(foo)` or `foo @ Bar(..)`. - pub fn contains_bindings(&self) -> bool { - self.satisfies(|p| matches!(p.kind, PatKind::Binding(..))) - } - - /// 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; - self.walk_short(|p| { - if pred(p) { - satisfies = true; - false // Found one, can short circuit now. - } else { - true - } - }); - satisfies - } - pub fn simple_ident(&self) -> Option<Ident> { match self.kind { PatKind::Binding( diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 7eeda6013ed..2d499e194e1 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -170,7 +170,7 @@ pub fn print_crate<'a>( // When printing the AST, we sometimes need to inject `#[no_std]` here. // Since you can't compile the HIR, it's not necessary. - s.print_mod(&krate.item.module, s.attrs(hir::CRATE_HIR_ID)); + s.print_mod(&krate.item, s.attrs(hir::CRATE_HIR_ID)); s.print_remaining_comments(); s.s.eof() } @@ -221,10 +221,6 @@ pub fn bounds_to_string<'b>(bounds: impl IntoIterator<Item = &'b hir::GenericBou to_string(NO_ANN, |s| s.print_bounds("", bounds)) } -pub fn param_to_string(arg: &hir::Param<'_>) -> String { - to_string(NO_ANN, |s| s.print_param(arg)) -} - pub fn ty_to_string(ty: &hir::Ty<'_>) -> String { to_string(NO_ANN, |s| s.print_type(ty)) } @@ -1701,21 +1697,10 @@ impl<'a> State<'a> { } } - pub fn print_usize(&mut self, i: usize) { - self.s.word(i.to_string()) - } - pub fn print_name(&mut self, name: Symbol) { self.print_ident(Ident::with_dummy_span(name)) } - pub fn print_for_decl(&mut self, loc: &hir::Local<'_>, coll: &hir::Expr<'_>) { - self.print_local_decl(loc); - self.s.space(); - self.word_space("in"); - self.print_expr(coll) - } - pub fn print_path(&mut self, path: &hir::Path<'_>, colons_before_params: bool) { self.maybe_print_comment(path.span.lo()); @@ -2430,24 +2415,6 @@ impl<'a> State<'a> { } } - pub fn print_opt_abi_and_extern_if_nondefault(&mut self, opt_abi: Option<Abi>) { - match opt_abi { - Some(Abi::Rust) => {} - Some(abi) => { - self.word_nbsp("extern"); - self.word_nbsp(abi.to_string()) - } - None => {} - } - } - - pub fn print_extern_opt_abi(&mut self, opt_abi: Option<Abi>) { - if let Some(abi) = opt_abi { - self.word_nbsp("extern"); - self.word_nbsp(abi.to_string()) - } - } - pub fn print_fn_header_info(&mut self, header: hir::FnHeader, vis: &hir::Visibility<'_>) { self.s.word(visibility_qualified(vis, "")); diff --git a/compiler/rustc_incremental/src/assert_dep_graph.rs b/compiler/rustc_incremental/src/assert_dep_graph.rs index a080b0ce339..b5680beae14 100644 --- a/compiler/rustc_incremental/src/assert_dep_graph.rs +++ b/compiler/rustc_incremental/src/assert_dep_graph.rs @@ -40,8 +40,9 @@ use rustc_graphviz as dot; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; -use rustc_middle::dep_graph::debug::{DepNodeFilter, EdgeFilter}; -use rustc_middle::dep_graph::{DepGraphQuery, DepKind, DepNode, DepNodeExt}; +use rustc_middle::dep_graph::{ + DepGraphQuery, DepKind, DepNode, DepNodeExt, DepNodeFilter, EdgeFilter, +}; use rustc_middle::hir::map::Map; use rustc_middle::ty::TyCtxt; use rustc_span::symbol::{sym, Symbol}; @@ -54,7 +55,7 @@ use std::io::{BufWriter, Write}; pub fn assert_dep_graph(tcx: TyCtxt<'_>) { tcx.dep_graph.with_ignore(|| { if tcx.sess.opts.debugging_opts.dump_dep_graph { - dump_graph(tcx); + tcx.dep_graph.with_query(dump_graph); } if !tcx.sess.opts.debugging_opts.query_dep_graph { @@ -200,29 +201,29 @@ fn check_paths<'tcx>(tcx: TyCtxt<'tcx>, if_this_changed: &Sources, then_this_wou } return; } - let query = tcx.dep_graph.query(); - for &(_, source_def_id, ref source_dep_node) in if_this_changed { - let dependents = query.transitive_predecessors(source_dep_node); - for &(target_span, ref target_pass, _, ref target_dep_node) in then_this_would_need { - if !dependents.contains(&target_dep_node) { - tcx.sess.span_err( - target_span, - &format!( - "no path from `{}` to `{}`", - tcx.def_path_str(source_def_id), - target_pass - ), - ); - } else { - tcx.sess.span_err(target_span, "OK"); + tcx.dep_graph.with_query(|query| { + for &(_, source_def_id, ref source_dep_node) in if_this_changed { + let dependents = query.transitive_predecessors(source_dep_node); + for &(target_span, ref target_pass, _, ref target_dep_node) in then_this_would_need { + if !dependents.contains(&target_dep_node) { + tcx.sess.span_err( + target_span, + &format!( + "no path from `{}` to `{}`", + tcx.def_path_str(source_def_id), + target_pass + ), + ); + } else { + tcx.sess.span_err(target_span, "OK"); + } } } - } + }); } -fn dump_graph(tcx: TyCtxt<'_>) { +fn dump_graph(query: &DepGraphQuery) { let path: String = env::var("RUST_DEP_GRAPH").unwrap_or_else(|_| "dep_graph".to_string()); - let query = tcx.dep_graph.query(); let nodes = match env::var("RUST_DEP_GRAPH_FILTER") { Ok(string) => { diff --git a/compiler/rustc_incremental/src/lib.rs b/compiler/rustc_incremental/src/lib.rs index 95456c07b10..f089cbcfca6 100644 --- a/compiler/rustc_incremental/src/lib.rs +++ b/compiler/rustc_incremental/src/lib.rs @@ -14,7 +14,7 @@ mod assert_dep_graph; pub mod assert_module_sources; mod persist; -pub use assert_dep_graph::assert_dep_graph; +use assert_dep_graph::assert_dep_graph; pub use persist::copy_cgu_workproduct_to_incr_comp_cache_dir; pub use persist::delete_workproduct_files; pub use persist::finalize_session_directory; @@ -26,4 +26,4 @@ pub use persist::prepare_session_directory; pub use persist::save_dep_graph; pub use persist::save_work_product_index; pub use persist::LoadResult; -pub use persist::{load_dep_graph, DepGraphFuture}; +pub use persist::{build_dep_graph, load_dep_graph, DepGraphFuture}; diff --git a/compiler/rustc_incremental/src/persist/dirty_clean.rs b/compiler/rustc_incremental/src/persist/dirty_clean.rs index cb089a728ee..e7bd488af8e 100644 --- a/compiler/rustc_incremental/src/persist/dirty_clean.rs +++ b/compiler/rustc_incremental/src/persist/dirty_clean.rs @@ -14,7 +14,6 @@ //! the required condition is not met. use rustc_ast::{self as ast, Attribute, NestedMetaItem}; -use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::FxHashSet; use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; @@ -74,16 +73,6 @@ const BASE_STRUCT: &[&str] = &[label_strs::generics_of, label_strs::predicates_of, label_strs::type_of]; /// Trait definition `DepNode`s. -const BASE_TRAIT_DEF: &[&str] = &[ - label_strs::associated_item_def_ids, - label_strs::generics_of, - label_strs::object_safety_violations, - label_strs::predicates_of, - label_strs::specialization_graph_of, - label_strs::trait_def, - label_strs::trait_impls_of, -]; - /// Extra `DepNode`s for functions and methods. const EXTRA_ASSOCIATED: &[&str] = &[label_strs::associated_item]; @@ -118,10 +107,6 @@ const LABELS_IMPL: &[&[&str]] = &[BASE_HIR, BASE_IMPL]; /// Abstract data type (struct, enum, union) `DepNode`s. const LABELS_ADT: &[&[&str]] = &[BASE_HIR, BASE_STRUCT]; -/// Trait definition `DepNode`s. -#[allow(dead_code)] -const LABELS_TRAIT: &[&[&str]] = &[BASE_HIR, BASE_TRAIT_DEF]; - // FIXME: Struct/Enum/Unions Fields (there is currently no way to attach these) // // Fields are kind of separate from their containers, as they can change independently from @@ -395,10 +380,7 @@ impl DirtyCleanVisitor<'tcx> { fn assert_dirty(&self, item_span: Span, dep_node: DepNode) { debug!("assert_dirty({:?})", dep_node); - let current_fingerprint = self.get_fingerprint(&dep_node); - let prev_fingerprint = self.tcx.dep_graph.prev_fingerprint_of(&dep_node); - - if current_fingerprint == prev_fingerprint { + if self.tcx.dep_graph.is_green(&dep_node) { let dep_node_str = self.dep_node_str(&dep_node); self.tcx .sess @@ -406,28 +388,10 @@ impl DirtyCleanVisitor<'tcx> { } } - fn get_fingerprint(&self, dep_node: &DepNode) -> Option<Fingerprint> { - if self.tcx.dep_graph.dep_node_exists(dep_node) { - let dep_node_index = self.tcx.dep_graph.dep_node_index_of(dep_node); - Some(self.tcx.dep_graph.fingerprint_of(dep_node_index)) - } else { - None - } - } - fn assert_clean(&self, item_span: Span, dep_node: DepNode) { debug!("assert_clean({:?})", dep_node); - let current_fingerprint = self.get_fingerprint(&dep_node); - let prev_fingerprint = self.tcx.dep_graph.prev_fingerprint_of(&dep_node); - - // if the node wasn't previously evaluated and now is (or vice versa), - // then the node isn't actually clean or dirty. - if (current_fingerprint == None) ^ (prev_fingerprint == None) { - return; - } - - if current_fingerprint != prev_fingerprint { + if self.tcx.dep_graph.is_red(&dep_node) { let dep_node_str = self.dep_node_str(&dep_node); self.tcx .sess diff --git a/compiler/rustc_incremental/src/persist/fs.rs b/compiler/rustc_incremental/src/persist/fs.rs index c7a6c1195c5..30c6c408bc7 100644 --- a/compiler/rustc_incremental/src/persist/fs.rs +++ b/compiler/rustc_incremental/src/persist/fs.rs @@ -122,6 +122,7 @@ mod tests; const LOCK_FILE_EXT: &str = ".lock"; const DEP_GRAPH_FILENAME: &str = "dep-graph.bin"; +const STAGING_DEP_GRAPH_FILENAME: &str = "dep-graph.part.bin"; const WORK_PRODUCTS_FILENAME: &str = "work-products.bin"; const QUERY_CACHE_FILENAME: &str = "query-cache.bin"; @@ -134,6 +135,9 @@ const INT_ENCODE_BASE: usize = base_n::CASE_INSENSITIVE; pub fn dep_graph_path(sess: &Session) -> PathBuf { in_incr_comp_dir_sess(sess, DEP_GRAPH_FILENAME) } +pub fn staging_dep_graph_path(sess: &Session) -> PathBuf { + in_incr_comp_dir_sess(sess, STAGING_DEP_GRAPH_FILENAME) +} pub fn dep_graph_path_from(incr_comp_session_dir: &Path) -> PathBuf { in_incr_comp_dir(incr_comp_session_dir, DEP_GRAPH_FILENAME) } diff --git a/compiler/rustc_incremental/src/persist/load.rs b/compiler/rustc_incremental/src/persist/load.rs index 2b5649bb059..259e540c612 100644 --- a/compiler/rustc_incremental/src/persist/load.rs +++ b/compiler/rustc_incremental/src/persist/load.rs @@ -5,7 +5,7 @@ use rustc_hir::definitions::Definitions; use rustc_middle::dep_graph::{PreviousDepGraph, SerializedDepGraph, WorkProduct, WorkProductId}; use rustc_middle::ty::query::OnDiskCache; use rustc_serialize::opaque::Decoder; -use rustc_serialize::Decodable as RustcDecodable; +use rustc_serialize::Decodable; use rustc_session::Session; use std::path::Path; @@ -120,7 +120,7 @@ pub fn load_dep_graph(sess: &Session) -> DepGraphFuture { // Decode the list of work_products let mut work_product_decoder = Decoder::new(&work_products_data[..], start_pos); let work_products: Vec<SerializedWorkProduct> = - RustcDecodable::decode(&mut work_product_decoder).unwrap_or_else(|e| { + Decodable::decode(&mut work_product_decoder).unwrap_or_else(|e| { let msg = format!( "Error decoding `work-products` from incremental \ compilation session directory: {}", diff --git a/compiler/rustc_incremental/src/persist/mod.rs b/compiler/rustc_incremental/src/persist/mod.rs index 8821b34b502..1336189bc0d 100644 --- a/compiler/rustc_incremental/src/persist/mod.rs +++ b/compiler/rustc_incremental/src/persist/mod.rs @@ -18,6 +18,7 @@ pub use fs::prepare_session_directory; pub use load::load_query_result_cache; pub use load::LoadResult; pub use load::{load_dep_graph, DepGraphFuture}; +pub use save::build_dep_graph; pub use save::save_dep_graph; pub use save::save_work_product_index; pub use work_product::copy_cgu_workproduct_to_incr_comp_cache_dir; diff --git a/compiler/rustc_incremental/src/persist/save.rs b/compiler/rustc_incremental/src/persist/save.rs index 45d474b89b8..d558af3c1d5 100644 --- a/compiler/rustc_incremental/src/persist/save.rs +++ b/compiler/rustc_incremental/src/persist/save.rs @@ -1,6 +1,6 @@ use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sync::join; -use rustc_middle::dep_graph::{DepGraph, WorkProduct, WorkProductId}; +use rustc_middle::dep_graph::{DepGraph, PreviousDepGraph, WorkProduct, WorkProductId}; use rustc_middle::ty::TyCtxt; use rustc_serialize::opaque::{FileEncodeResult, FileEncoder}; use rustc_serialize::Encodable as RustcEncodable; @@ -15,6 +15,9 @@ use super::file_format; use super::fs::*; use super::work_product; +/// Save and dump the DepGraph. +/// +/// No query must be invoked after this function. pub fn save_dep_graph(tcx: TyCtxt<'_>) { debug!("save_dep_graph()"); tcx.dep_graph.with_ignore(|| { @@ -29,6 +32,14 @@ pub fn save_dep_graph(tcx: TyCtxt<'_>) { let query_cache_path = query_cache_path(sess); let dep_graph_path = dep_graph_path(sess); + let staging_dep_graph_path = staging_dep_graph_path(sess); + + sess.time("assert_dep_graph", || crate::assert_dep_graph(tcx)); + sess.time("check_dirty_clean", || dirty_clean::check_dirty_clean_annotations(tcx)); + + if sess.opts.debugging_opts.incremental_info { + tcx.dep_graph.print_incremental_info() + } join( move || { @@ -36,16 +47,26 @@ pub fn save_dep_graph(tcx: TyCtxt<'_>) { save_in(sess, query_cache_path, "query cache", |e| encode_query_cache(tcx, e)); }); }, - || { + move || { sess.time("incr_comp_persist_dep_graph", || { - save_in(sess, dep_graph_path, "dependency graph", |e| { - sess.time("incr_comp_encode_dep_graph", || encode_dep_graph(tcx, e)) - }); + if let Err(err) = tcx.dep_graph.encode(&tcx.sess.prof) { + sess.err(&format!( + "failed to write dependency graph to `{}`: {}", + staging_dep_graph_path.display(), + err + )); + } + if let Err(err) = fs::rename(&staging_dep_graph_path, &dep_graph_path) { + sess.err(&format!( + "failed to move dependency graph from `{}` to `{}`: {}", + staging_dep_graph_path.display(), + dep_graph_path.display(), + err + )); + } }); }, ); - - dirty_clean::check_dirty_clean_annotations(tcx); }) } @@ -92,7 +113,7 @@ pub fn save_work_product_index( }); } -fn save_in<F>(sess: &Session, path_buf: PathBuf, name: &str, encode: F) +pub(crate) fn save_in<F>(sess: &Session, path_buf: PathBuf, name: &str, encode: F) where F: FnOnce(&mut FileEncoder) -> FileEncodeResult, { @@ -144,21 +165,6 @@ where debug!("save: data written to disk successfully"); } -fn encode_dep_graph(tcx: TyCtxt<'_>, encoder: &mut FileEncoder) -> FileEncodeResult { - // First encode the commandline arguments hash - tcx.sess.opts.dep_tracking_hash().encode(encoder)?; - - if tcx.sess.opts.debugging_opts.incremental_info { - tcx.dep_graph.print_incremental_info(); - } - - // There is a tiny window between printing the incremental info above and encoding the dep - // graph below in which the dep graph could change, thus making the printed incremental info - // slightly out of date. If this matters to you, please feel free to submit a patch. :) - - tcx.sess.time("incr_comp_encode_serialized_dep_graph", || tcx.dep_graph.encode(encoder)) -} - fn encode_work_product_index( work_products: &FxHashMap<WorkProductId, WorkProduct>, encoder: &mut FileEncoder, @@ -177,3 +183,56 @@ fn encode_work_product_index( fn encode_query_cache(tcx: TyCtxt<'_>, encoder: &mut FileEncoder) -> FileEncodeResult { tcx.sess.time("incr_comp_serialize_result_cache", || tcx.serialize_query_result_cache(encoder)) } + +pub fn build_dep_graph( + sess: &Session, + prev_graph: PreviousDepGraph, + prev_work_products: FxHashMap<WorkProductId, WorkProduct>, +) -> Option<DepGraph> { + if sess.opts.incremental.is_none() { + // No incremental compilation. + return None; + } + + // Stream the dep-graph to an alternate file, to avoid overwriting anything in case of errors. + let path_buf = staging_dep_graph_path(sess); + + let mut encoder = match FileEncoder::new(&path_buf) { + Ok(encoder) => encoder, + Err(err) => { + sess.err(&format!( + "failed to create dependency graph at `{}`: {}", + path_buf.display(), + err + )); + return None; + } + }; + + if let Err(err) = file_format::write_file_header(&mut encoder, sess.is_nightly_build()) { + sess.err(&format!( + "failed to write dependency graph header to `{}`: {}", + path_buf.display(), + err + )); + return None; + } + + // First encode the commandline arguments hash + if let Err(err) = sess.opts.dep_tracking_hash().encode(&mut encoder) { + sess.err(&format!( + "failed to write dependency graph hash `{}`: {}", + path_buf.display(), + err + )); + return None; + } + + Some(DepGraph::new( + prev_graph, + prev_work_products, + encoder, + sess.opts.debugging_opts.query_dep_graph, + sess.opts.debugging_opts.incremental_info, + )) +} diff --git a/compiler/rustc_index/src/bit_set.rs b/compiler/rustc_index/src/bit_set.rs index 100824f4b94..cfea5092bc3 100644 --- a/compiler/rustc_index/src/bit_set.rs +++ b/compiler/rustc_index/src/bit_set.rs @@ -356,7 +356,7 @@ where { assert_eq!(out_vec.len(), in_vec.len()); let mut changed = false; - for (out_elem, in_elem) in out_vec.iter_mut().zip(in_vec.iter()) { + for (out_elem, in_elem) in iter::zip(out_vec, in_vec) { let old_val = *out_elem; let new_val = op(old_val, *in_elem); *out_elem = new_val; @@ -842,7 +842,7 @@ impl<R: Idx, C: Idx> BitMatrix<R, C> { let (write_start, write_end) = self.range(write); let words = &mut self.words[..]; let mut changed = false; - for (read_index, write_index) in (read_start..read_end).zip(write_start..write_end) { + for (read_index, write_index) in iter::zip(read_start..read_end, write_start..write_end) { let word = words[write_index]; let new_word = word | words[read_index]; words[write_index] = new_word; @@ -858,7 +858,7 @@ impl<R: Idx, C: Idx> BitMatrix<R, C> { assert_eq!(with.domain_size(), self.num_columns); let (write_start, write_end) = self.range(write); let mut changed = false; - for (read_index, write_index) in (0..with.words().len()).zip(write_start..write_end) { + for (read_index, write_index) in iter::zip(0..with.words().len(), write_start..write_end) { let word = self.words[write_index]; let new_word = word | with.words()[read_index]; self.words[write_index] = new_word; diff --git a/compiler/rustc_index/src/lib.rs b/compiler/rustc_index/src/lib.rs index 995034e81da..3ced3920cfd 100644 --- a/compiler/rustc_index/src/lib.rs +++ b/compiler/rustc_index/src/lib.rs @@ -2,6 +2,7 @@ #![feature(const_fn)] #![feature(const_panic)] #![feature(extend_one)] +#![feature(iter_zip)] #![feature(unboxed_closures)] #![feature(test)] #![feature(fn_traits)] diff --git a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs index aa4fd055d5e..c68705da413 100644 --- a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs +++ b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs @@ -293,7 +293,7 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Canonicalizer<'cx, 'tcx> { self.tcx } - fn fold_binder<T>(&mut self, t: ty::Binder<T>) -> ty::Binder<T> + fn fold_binder<T>(&mut self, t: ty::Binder<'tcx, T>) -> ty::Binder<'tcx, T> where T: TypeFoldable<'tcx>, { @@ -621,7 +621,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> { r: ty::Region<'tcx>, ) -> ty::Region<'tcx> { let var = self.canonical_var(info, r.into()); - let br = ty::BoundRegion { kind: ty::BrAnon(var.as_u32()) }; + let br = ty::BoundRegion { var, kind: ty::BrAnon(var.as_u32()) }; let region = ty::ReLateBound(self.binder_index, br); self.tcx().mk_region(region) } diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs index 2ec9b9e0be4..b8ecc949588 100644 --- a/compiler/rustc_infer/src/infer/canonical/query_response.rs +++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs @@ -27,6 +27,7 @@ use rustc_middle::ty::relate::TypeRelation; use rustc_middle::ty::subst::{GenericArg, GenericArgKind}; use rustc_middle::ty::{self, BoundVar, Const, ToPredicate, Ty, TyCtxt}; use std::fmt::Debug; +use std::iter; impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { /// This method is meant to be invoked as the final step of a canonical query @@ -418,7 +419,8 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { // In terms of our example above, we are iterating over pairs like: // [(?A, Vec<?0>), ('static, '?1), (?B, ?0)] - for (original_value, result_value) in original_values.var_values.iter().zip(result_values) { + for (original_value, result_value) in iter::zip(&original_values.var_values, result_values) + { match result_value.unpack() { GenericArgKind::Type(result_value) => { // e.g., here `result_value` might be `?0` in the example above... @@ -437,7 +439,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { // We only allow a `ty::INNERMOST` index in substitutions. assert_eq!(debruijn, ty::INNERMOST); - opt_values[br.assert_bound_var()] = Some(*original_value); + opt_values[br.var] = Some(*original_value); } } GenericArgKind::Const(result_value) => { diff --git a/compiler/rustc_infer/src/infer/canonical/substitute.rs b/compiler/rustc_infer/src/infer/canonical/substitute.rs index 387f480814a..553a11d4393 100644 --- a/compiler/rustc_infer/src/infer/canonical/substitute.rs +++ b/compiler/rustc_infer/src/infer/canonical/substitute.rs @@ -71,11 +71,10 @@ where if var_values.var_values.is_empty() { value } else { - let fld_r = - |br: ty::BoundRegion| match var_values.var_values[br.assert_bound_var()].unpack() { - GenericArgKind::Lifetime(l) => l, - r => bug!("{:?} is a region but value is {:?}", br, r), - }; + let fld_r = |br: ty::BoundRegion| match var_values.var_values[br.var].unpack() { + GenericArgKind::Lifetime(l) => l, + r => bug!("{:?} is a region but value is {:?}", br, r), + }; let fld_t = |bound_ty: ty::BoundTy| match var_values.var_values[bound_ty.var].unpack() { GenericArgKind::Type(ty) => ty, diff --git a/compiler/rustc_infer/src/infer/combine.rs b/compiler/rustc_infer/src/infer/combine.rs index 5e11932eafc..debf1082537 100644 --- a/compiler/rustc_infer/src/infer/combine.rs +++ b/compiler/rustc_infer/src/infer/combine.rs @@ -543,15 +543,11 @@ impl TypeRelation<'tcx> for Generalizer<'_, 'tcx> { true } - fn visit_ct_substs(&self) -> bool { - true - } - fn binders<T>( &mut self, - a: ty::Binder<T>, - b: ty::Binder<T>, - ) -> RelateResult<'tcx, ty::Binder<T>> + a: ty::Binder<'tcx, T>, + b: ty::Binder<'tcx, T>, + ) -> RelateResult<'tcx, ty::Binder<'tcx, T>> where T: Relate<'tcx>, { @@ -737,6 +733,16 @@ impl TypeRelation<'tcx> for Generalizer<'_, 'tcx> { } } } + ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted }) + if self.tcx().lazy_normalization() => + { + assert_eq!(promoted, None); + let substs = self.relate_with_variance(ty::Variance::Invariant, substs, substs)?; + Ok(self.tcx().mk_const(ty::Const { + ty: c.ty, + val: ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted }), + })) + } _ => relate::super_relate_consts(self, c, c), } } @@ -822,10 +828,6 @@ impl TypeRelation<'tcx> for ConstInferUnifier<'_, 'tcx> { true } - fn visit_ct_substs(&self) -> bool { - true - } - fn relate_with_variance<T: Relate<'tcx>>( &mut self, _variance: ty::Variance, @@ -838,9 +840,9 @@ impl TypeRelation<'tcx> for ConstInferUnifier<'_, 'tcx> { fn binders<T>( &mut self, - a: ty::Binder<T>, - b: ty::Binder<T>, - ) -> RelateResult<'tcx, ty::Binder<T>> + a: ty::Binder<'tcx, T>, + b: ty::Binder<'tcx, T>, + ) -> RelateResult<'tcx, ty::Binder<'tcx, T>> where T: Relate<'tcx>, { @@ -959,6 +961,16 @@ impl TypeRelation<'tcx> for ConstInferUnifier<'_, 'tcx> { } } } + ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted }) + if self.tcx().lazy_normalization() => + { + assert_eq!(promoted, None); + let substs = self.relate_with_variance(ty::Variance::Invariant, substs, substs)?; + Ok(self.tcx().mk_const(ty::Const { + ty: c.ty, + val: ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted }), + })) + } _ => relate::super_relate_consts(self, c, c), } } diff --git a/compiler/rustc_infer/src/infer/equate.rs b/compiler/rustc_infer/src/infer/equate.rs index 7c388b5503e..45ba50bb634 100644 --- a/compiler/rustc_infer/src/infer/equate.rs +++ b/compiler/rustc_infer/src/infer/equate.rs @@ -124,9 +124,9 @@ impl TypeRelation<'tcx> for Equate<'combine, 'infcx, 'tcx> { fn binders<T>( &mut self, - a: ty::Binder<T>, - b: ty::Binder<T>, - ) -> RelateResult<'tcx, ty::Binder<T>> + a: ty::Binder<'tcx, T>, + b: ty::Binder<'tcx, T>, + ) -> RelateResult<'tcx, ty::Binder<'tcx, T>> where T: Relate<'tcx>, { diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index c171b11e3ff..a91bd9ce2ff 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -73,7 +73,7 @@ use rustc_middle::ty::{ use rustc_span::{sym, BytePos, DesugaringKind, Pos, Span}; use rustc_target::spec::abi; use std::ops::ControlFlow; -use std::{cmp, fmt}; +use std::{cmp, fmt, iter}; mod note; @@ -514,7 +514,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { fn print_dyn_existential( self, - _predicates: &'tcx ty::List<ty::Binder<ty::ExistentialPredicate<'tcx>>>, + _predicates: &'tcx ty::List<ty::Binder<'tcx, ty::ExistentialPredicate<'tcx>>>, ) -> Result<Self::DynExistential, Self::Error> { Err(NonTrivialPath) } @@ -963,7 +963,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { ty::GenericParamDefKind::Const { has_default: true } => Some(param.def_id), _ => None, }); - for (def_id, actual) in default_params.zip(substs.iter().rev()) { + for (def_id, actual) in iter::zip(default_params, substs.iter().rev()) { match actual.unpack() { GenericArgKind::Const(c) => { if self.tcx.const_param_default(def_id).subst(self.tcx, substs) != c { @@ -1040,7 +1040,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { let len1 = sig1.inputs().len(); let len2 = sig2.inputs().len(); if len1 == len2 { - for (i, (l, r)) in sig1.inputs().iter().zip(sig2.inputs().iter()).enumerate() { + for (i, (l, r)) in iter::zip(sig1.inputs(), sig2.inputs()).enumerate() { let (x1, x2) = self.cmp(l, r); (values.0).0.extend(x1.0); (values.1).0.extend(x2.0); @@ -1161,12 +1161,10 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { let common_len = cmp::min(len1, len2); let remainder1: Vec<_> = sub1.types().skip(common_len).collect(); let remainder2: Vec<_> = sub2.types().skip(common_len).collect(); - let common_default_params = remainder1 - .iter() - .rev() - .zip(remainder2.iter().rev()) - .filter(|(a, b)| a == b) - .count(); + let common_default_params = + iter::zip(remainder1.iter().rev(), remainder2.iter().rev()) + .filter(|(a, b)| a == b) + .count(); let len = sub1.len() - common_default_params; let consts_offset = len - sub1.consts().count(); @@ -1297,12 +1295,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { const SEPARATOR: &str = "::"; let separator_len = SEPARATOR.len(); - let split_idx: usize = t1_str - .split(SEPARATOR) - .zip(t2_str.split(SEPARATOR)) - .take_while(|(mod1_str, mod2_str)| mod1_str == mod2_str) - .map(|(mod_str, _)| mod_str.len() + separator_len) - .sum(); + let split_idx: usize = + iter::zip(t1_str.split(SEPARATOR), t2_str.split(SEPARATOR)) + .take_while(|(mod1_str, mod2_str)| mod1_str == mod2_str) + .map(|(mod_str, _)| mod_str.len() + separator_len) + .sum(); debug!( "cmp: separator_len={}, split_idx={}, min_len={}", @@ -1907,7 +1904,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { .find_map(|(path, msg)| (&path_str == path).then_some(msg)) { let mut show_suggestion = true; - for (exp_ty, found_ty) in exp_substs.types().zip(found_substs.types()) { + for (exp_ty, found_ty) in + iter::zip(exp_substs.types(), found_substs.types()) + { match *exp_ty.kind() { ty::Ref(_, exp_ty, _) => { match (exp_ty.kind(), found_ty.kind()) { diff --git a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs index d533e267fd7..d9a1193aac4 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs @@ -287,6 +287,7 @@ pub struct InferenceDiagnosticsData { pub struct InferenceDiagnosticsParentData { pub prefix: &'static str, pub name: String, + pub def_id: DefId, } pub enum UnderspecifiedArgKind { @@ -328,6 +329,7 @@ impl InferenceDiagnosticsParentData { Some(InferenceDiagnosticsParentData { prefix: tcx.def_kind(parent_def_id).descr(parent_def_id), name: parent_name, + def_id: parent_def_id, }) } } @@ -754,12 +756,30 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { if let (UnderspecifiedArgKind::Const { .. }, Some(parent_data)) = (&arg_data.kind, &arg_data.parent) { - err.span_suggestion_verbose( - span, - "consider specifying the const argument", - format!("{}::<{}>", parent_data.name, arg_data.name), - Applicability::MaybeIncorrect, - ); + let has_impl_trait = + self.tcx.generics_of(parent_data.def_id).params.iter().any(|param| { + matches!( + param.kind, + ty::GenericParamDefKind::Type { + synthetic: Some( + hir::SyntheticTyParamKind::ImplTrait + | hir::SyntheticTyParamKind::FromAttr, + ), + .. + } + ) + }); + + // (#83606): Do not emit a suggestion if the parent has an `impl Trait` + // as an argument otherwise it will cause the E0282 error. + if !has_impl_trait { + err.span_suggestion_verbose( + span, + "consider specifying the const argument", + format!("{}::<{}>", parent_data.name, arg_data.name), + Applicability::MaybeIncorrect, + ); + } } err.span_label( diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs index 35b9bc96f13..58eb1e9aa12 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs @@ -115,7 +115,7 @@ impl Visitor<'tcx> for FindNestedTypeVisitor<'tcx> { // error. We will then search the function parameters for a bound // region at the right depth with the same index ( - Some(rl::Region::LateBoundAnon(debruijn_index, anon_index)), + Some(rl::Region::LateBoundAnon(debruijn_index, _, anon_index)), ty::BrAnon(br_index), ) => { debug!( @@ -143,7 +143,7 @@ impl Visitor<'tcx> for FindNestedTypeVisitor<'tcx> { // error. We will then search the function parameters for a bound // region at the right depth with the same index ( - Some(rl::Region::LateBound(debruijn_index, id, _)), + Some(rl::Region::LateBound(debruijn_index, _, id, _)), ty::BrNamed(def_id, _), ) => { debug!( @@ -162,8 +162,8 @@ impl Visitor<'tcx> for FindNestedTypeVisitor<'tcx> { rl::Region::Static | rl::Region::Free(_, _) | rl::Region::EarlyBound(_, _, _) - | rl::Region::LateBound(_, _, _) - | rl::Region::LateBoundAnon(_, _), + | rl::Region::LateBound(_, _, _, _) + | rl::Region::LateBoundAnon(_, _, _), ) | None, _, @@ -217,7 +217,10 @@ impl Visitor<'tcx> for TyPathVisitor<'tcx> { fn visit_lifetime(&mut self, lifetime: &hir::Lifetime) { match (self.tcx.named_region(lifetime.hir_id), self.bound_region) { // the lifetime of the TyPath! - (Some(rl::Region::LateBoundAnon(debruijn_index, anon_index)), ty::BrAnon(br_index)) => { + ( + Some(rl::Region::LateBoundAnon(debruijn_index, _, anon_index)), + ty::BrAnon(br_index), + ) => { if debruijn_index == self.current_index && anon_index == br_index { self.found_it = true; return; @@ -232,7 +235,7 @@ impl Visitor<'tcx> for TyPathVisitor<'tcx> { } } - (Some(rl::Region::LateBound(debruijn_index, id, _)), ty::BrNamed(def_id, _)) => { + (Some(rl::Region::LateBound(debruijn_index, _, id, _)), ty::BrNamed(def_id, _)) => { debug!("FindNestedTypeVisitor::visit_ty: LateBound depth = {:?}", debruijn_index,); debug!("id={:?}", id); debug!("def_id={:?}", def_id); @@ -246,8 +249,8 @@ impl Visitor<'tcx> for TyPathVisitor<'tcx> { Some( rl::Region::Static | rl::Region::EarlyBound(_, _, _) - | rl::Region::LateBound(_, _, _) - | rl::Region::LateBoundAnon(_, _) + | rl::Region::LateBound(_, _, _, _) + | rl::Region::LateBoundAnon(_, _, _) | rl::Region::Free(_, _), ) | None, diff --git a/compiler/rustc_infer/src/infer/glb.rs b/compiler/rustc_infer/src/infer/glb.rs index ccba904df9e..02662043dba 100644 --- a/compiler/rustc_infer/src/infer/glb.rs +++ b/compiler/rustc_infer/src/infer/glb.rs @@ -85,9 +85,9 @@ impl TypeRelation<'tcx> for Glb<'combine, 'infcx, 'tcx> { fn binders<T>( &mut self, - a: ty::Binder<T>, - b: ty::Binder<T>, - ) -> RelateResult<'tcx, ty::Binder<T>> + a: ty::Binder<'tcx, T>, + b: ty::Binder<'tcx, T>, + ) -> RelateResult<'tcx, ty::Binder<'tcx, T>> where T: Relate<'tcx>, { diff --git a/compiler/rustc_infer/src/infer/higher_ranked/mod.rs b/compiler/rustc_infer/src/infer/higher_ranked/mod.rs index e794903fca3..d460222df8a 100644 --- a/compiler/rustc_infer/src/infer/higher_ranked/mod.rs +++ b/compiler/rustc_infer/src/infer/higher_ranked/mod.rs @@ -11,10 +11,10 @@ use rustc_middle::ty::{self, Binder, TypeFoldable}; impl<'a, 'tcx> CombineFields<'a, 'tcx> { pub fn higher_ranked_sub<T>( &mut self, - a: Binder<T>, - b: Binder<T>, + a: Binder<'tcx, T>, + b: Binder<'tcx, T>, a_is_expected: bool, - ) -> RelateResult<'tcx, Binder<T>> + ) -> RelateResult<'tcx, Binder<'tcx, T>> where T: Relate<'tcx>, { @@ -50,7 +50,10 @@ impl<'a, 'tcx> CombineFields<'a, 'tcx> { debug!("higher_ranked_sub: OK result={:?}", result); - Ok(ty::Binder::bind(result)) + // We related `a_prime` and `b_prime`, which just had any bound vars + // replaced with placeholders or infer vars, respectively. Relating + // them should not introduce new bound vars. + Ok(ty::Binder::dummy(result)) }) } } @@ -66,7 +69,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { /// the [rustc dev guide]. /// /// [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/traits/hrtb.html - pub fn replace_bound_vars_with_placeholders<T>(&self, binder: ty::Binder<T>) -> T + pub fn replace_bound_vars_with_placeholders<T>(&self, binder: ty::Binder<'tcx, T>) -> T where T: TypeFoldable<'tcx>, { diff --git a/compiler/rustc_infer/src/infer/lub.rs b/compiler/rustc_infer/src/infer/lub.rs index 9f43fac0916..4fa8f2f1a6a 100644 --- a/compiler/rustc_infer/src/infer/lub.rs +++ b/compiler/rustc_infer/src/infer/lub.rs @@ -85,9 +85,9 @@ impl TypeRelation<'tcx> for Lub<'combine, 'infcx, 'tcx> { fn binders<T>( &mut self, - a: ty::Binder<T>, - b: ty::Binder<T>, - ) -> RelateResult<'tcx, ty::Binder<T>> + a: ty::Binder<'tcx, T>, + b: ty::Binder<'tcx, T>, + ) -> RelateResult<'tcx, ty::Binder<'tcx, T>> where T: Relate<'tcx>, { diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 7b18f4d0ff6..eaec6b46bcd 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -1266,15 +1266,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { self.resolve_vars_if_possible(t).to_string() } - pub fn tys_to_string(&self, ts: &[Ty<'tcx>]) -> String { - let tstrs: Vec<String> = ts.iter().map(|t| self.ty_to_string(*t)).collect(); - format!("({})", tstrs.join(", ")) - } - - pub fn trait_ref_to_string(&self, t: ty::TraitRef<'tcx>) -> String { - self.resolve_vars_if_possible(t).print_only_trait_path().to_string() - } - /// If `TyVar(vid)` resolves to a type, return that type. Else, return the /// universe index of `TyVar(vid)`. pub fn probe_ty_var(&self, vid: TyVid) -> Result<Ty<'tcx>, ty::UniverseIndex> { @@ -1415,7 +1406,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { &self, span: Span, lbrct: LateBoundRegionConversionTime, - value: ty::Binder<T>, + value: ty::Binder<'tcx, T>, ) -> (T, BTreeMap<ty::BoundRegion, ty::Region<'tcx>>) where T: TypeFoldable<'tcx>, @@ -1704,14 +1695,6 @@ impl<'tcx> TypeTrace<'tcx> { ) -> TypeTrace<'tcx> { TypeTrace { cause: cause.clone(), values: Consts(ExpectedFound::new(a_is_expected, a, b)) } } - - pub fn dummy(tcx: TyCtxt<'tcx>) -> TypeTrace<'tcx> { - let err = tcx.ty_error(); - TypeTrace { - cause: ObligationCause::dummy(), - values: Types(ExpectedFound { expected: err, found: err }), - } - } } impl<'tcx> SubregionOrigin<'tcx> { diff --git a/compiler/rustc_infer/src/infer/nll_relate/mod.rs b/compiler/rustc_infer/src/infer/nll_relate/mod.rs index e5eb771603c..fc9ea07866c 100644 --- a/compiler/rustc_infer/src/infer/nll_relate/mod.rs +++ b/compiler/rustc_infer/src/infer/nll_relate/mod.rs @@ -157,7 +157,7 @@ where fn create_scope( &mut self, - value: ty::Binder<impl Relate<'tcx>>, + value: ty::Binder<'tcx, impl Relate<'tcx>>, universally_quantified: UniversallyQuantified, ) -> BoundRegionScope<'tcx> { let mut scope = BoundRegionScope::default(); @@ -608,9 +608,9 @@ where fn binders<T>( &mut self, - a: ty::Binder<T>, - b: ty::Binder<T>, - ) -> RelateResult<'tcx, ty::Binder<T>> + a: ty::Binder<'tcx, T>, + b: ty::Binder<'tcx, T>, + ) -> RelateResult<'tcx, ty::Binder<'tcx, T>> where T: Relate<'tcx>, { @@ -744,7 +744,7 @@ struct ScopeInstantiator<'me, 'tcx> { impl<'me, 'tcx> TypeVisitor<'tcx> for ScopeInstantiator<'me, 'tcx> { fn visit_binder<T: TypeFoldable<'tcx>>( &mut self, - t: &ty::Binder<T>, + t: &ty::Binder<'tcx, T>, ) -> ControlFlow<Self::BreakTy> { self.target_index.shift_in(1); t.super_visit_with(self); @@ -997,9 +997,9 @@ where fn binders<T>( &mut self, - a: ty::Binder<T>, - _: ty::Binder<T>, - ) -> RelateResult<'tcx, ty::Binder<T>> + a: ty::Binder<'tcx, T>, + _: ty::Binder<'tcx, T>, + ) -> RelateResult<'tcx, ty::Binder<'tcx, T>> where T: Relate<'tcx>, { diff --git a/compiler/rustc_infer/src/infer/outlives/env.rs b/compiler/rustc_infer/src/infer/outlives/env.rs index 1a9e20e79fe..9e04773c5fa 100644 --- a/compiler/rustc_infer/src/infer/outlives/env.rs +++ b/compiler/rustc_infer/src/infer/outlives/env.rs @@ -92,11 +92,6 @@ impl<'a, 'tcx> OutlivesEnvironment<'tcx> { &self.region_bound_pairs_map } - /// Returns ownership of the `free_region_map`. - pub fn into_free_region_map(self) -> FreeRegionMap<'tcx> { - self.free_region_map - } - /// This is a hack to support the old-skool regionck, which /// processes region constraints from the main function and the /// closure together. In that context, when we enter a closure, we diff --git a/compiler/rustc_infer/src/infer/outlives/obligations.rs b/compiler/rustc_infer/src/infer/outlives/obligations.rs index 16d86e6243d..3e2978fd170 100644 --- a/compiler/rustc_infer/src/infer/outlives/obligations.rs +++ b/compiler/rustc_infer/src/infer/outlives/obligations.rs @@ -186,28 +186,6 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { } } } - - /// Processes a single ad-hoc region obligation that was not - /// registered in advance. - pub fn type_must_outlive( - &self, - region_bound_pairs: &RegionBoundPairs<'tcx>, - implicit_region_bound: Option<ty::Region<'tcx>>, - param_env: ty::ParamEnv<'tcx>, - origin: infer::SubregionOrigin<'tcx>, - ty: Ty<'tcx>, - region: ty::Region<'tcx>, - ) { - let outlives = &mut TypeOutlives::new( - self, - self.tcx, - region_bound_pairs, - implicit_region_bound, - param_env, - ); - let ty = self.resolve_vars_if_possible(ty); - outlives.type_must_outlive(origin, ty, region); - } } /// The `TypeOutlives` struct has the job of "lowering" a `T: 'a` diff --git a/compiler/rustc_infer/src/infer/region_constraints/mod.rs b/compiler/rustc_infer/src/infer/region_constraints/mod.rs index 2902c41a6bc..9ffcddfae99 100644 --- a/compiler/rustc_infer/src/infer/region_constraints/mod.rs +++ b/compiler/rustc_infer/src/infer/region_constraints/mod.rs @@ -309,31 +309,6 @@ pub struct RegionSnapshot { any_unifications: bool, } -/// When working with placeholder regions, we often wish to find all of -/// the regions that are either reachable from a placeholder region, or -/// which can reach a placeholder region, or both. We call such regions -/// *tainted* regions. This struct allows you to decide what set of -/// tainted regions you want. -#[derive(Debug)] -pub struct TaintDirections { - incoming: bool, - outgoing: bool, -} - -impl TaintDirections { - pub fn incoming() -> Self { - TaintDirections { incoming: true, outgoing: false } - } - - pub fn outgoing() -> Self { - TaintDirections { incoming: false, outgoing: true } - } - - pub fn both() -> Self { - TaintDirections { incoming: true, outgoing: true } - } -} - impl<'tcx> RegionConstraintStorage<'tcx> { pub fn new() -> Self { Self::default() @@ -472,11 +447,6 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> { self.var_infos[vid].universe } - /// Returns the origin for the given variable. - pub fn var_origin(&self, vid: RegionVid) -> RegionVariableOrigin { - self.var_infos[vid].origin - } - fn add_constraint(&mut self, constraint: Constraint<'tcx>, origin: SubregionOrigin<'tcx>) { // cannot add constraints once regions are resolved debug!("RegionConstraintCollector: add_constraint({:?})", constraint); @@ -795,16 +765,6 @@ impl<'tcx> VerifyBound<'tcx> { VerifyBound::AnyBound(vec![self, vb]) } } - - pub fn and(self, vb: VerifyBound<'tcx>) -> VerifyBound<'tcx> { - if self.must_hold() && vb.must_hold() { - self - } else if self.cannot_hold() && vb.cannot_hold() { - self - } else { - VerifyBound::AllBounds(vec![self, vb]) - } - } } impl<'tcx> RegionConstraintData<'tcx> { diff --git a/compiler/rustc_infer/src/infer/sub.rs b/compiler/rustc_infer/src/infer/sub.rs index 66871985158..bf5f328233d 100644 --- a/compiler/rustc_infer/src/infer/sub.rs +++ b/compiler/rustc_infer/src/infer/sub.rs @@ -162,9 +162,9 @@ impl TypeRelation<'tcx> for Sub<'combine, 'infcx, 'tcx> { fn binders<T>( &mut self, - a: ty::Binder<T>, - b: ty::Binder<T>, - ) -> RelateResult<'tcx, ty::Binder<T>> + a: ty::Binder<'tcx, T>, + b: ty::Binder<'tcx, T>, + ) -> RelateResult<'tcx, ty::Binder<'tcx, T>> where T: Relate<'tcx>, { diff --git a/compiler/rustc_infer/src/infer/type_variable.rs b/compiler/rustc_infer/src/infer/type_variable.rs index 35b97fff3da..683c1df783e 100644 --- a/compiler/rustc_infer/src/infer/type_variable.rs +++ b/compiler/rustc_infer/src/infer/type_variable.rs @@ -146,9 +146,7 @@ impl<'tcx> TypeVariableValue<'tcx> { } } -pub(crate) struct Instantiate { - vid: ty::TyVid, -} +pub(crate) struct Instantiate; pub(crate) struct Delegate; @@ -224,7 +222,7 @@ impl<'tcx> TypeVariableTable<'_, 'tcx> { // Hack: we only need this so that `types_escaping_snapshot` // can see what has been unified; see the Delegate impl for // more details. - self.undo_log.push(Instantiate { vid }); + self.undo_log.push(Instantiate); } /// Creates a new type variable. @@ -346,56 +344,6 @@ impl<'tcx> TypeVariableTable<'_, 'tcx> { ) } - /// Finds the set of type variables that existed *before* `s` - /// but which have only been unified since `s` started, and - /// return the types with which they were unified. So if we had - /// a type variable `V0`, then we started the snapshot, then we - /// created a type variable `V1`, unified `V0` with `T0`, and - /// unified `V1` with `T1`, this function would return `{T0}`. - pub fn types_escaping_snapshot(&mut self, s: &super::Snapshot<'tcx>) -> Vec<Ty<'tcx>> { - let mut new_elem_threshold = u32::MAX; - let mut escaping_types = Vec::new(); - let actions_since_snapshot = self.undo_log.actions_since_snapshot(s); - debug!("actions_since_snapshot.len() = {}", actions_since_snapshot.len()); - for i in 0..actions_since_snapshot.len() { - let actions_since_snapshot = self.undo_log.actions_since_snapshot(s); - match actions_since_snapshot[i] { - super::UndoLog::TypeVariables(UndoLog::Values(sv::UndoLog::NewElem(index))) => { - // if any new variables were created during the - // snapshot, remember the lower index (which will - // always be the first one we see). Note that this - // action must precede those variables being - // specified. - new_elem_threshold = cmp::min(new_elem_threshold, index as u32); - debug!("NewElem({}) new_elem_threshold={}", index, new_elem_threshold); - } - - super::UndoLog::TypeVariables(UndoLog::Values(sv::UndoLog::Other( - Instantiate { vid, .. }, - ))) => { - if vid.index < new_elem_threshold { - // quick check to see if this variable was - // created since the snapshot started or not. - let mut eq_relations = ut::UnificationTable::with_log( - &mut self.storage.eq_relations, - &mut *self.undo_log, - ); - let escaping_type = match eq_relations.probe_value(vid) { - TypeVariableValue::Unknown { .. } => bug!(), - TypeVariableValue::Known { value } => value, - }; - escaping_types.push(escaping_type); - } - debug!("SpecifyVar({:?}) new_elem_threshold={}", vid, new_elem_threshold); - } - - _ => {} - } - } - - escaping_types - } - /// Returns indices of all variables that are not yet /// instantiated. pub fn unsolved_variables(&mut self) -> Vec<ty::TyVid> { diff --git a/compiler/rustc_infer/src/infer/undo_log.rs b/compiler/rustc_infer/src/infer/undo_log.rs index 4be0e7948f7..f41e872e004 100644 --- a/compiler/rustc_infer/src/infer/undo_log.rs +++ b/compiler/rustc_infer/src/infer/undo_log.rs @@ -165,10 +165,6 @@ impl<'tcx> InferCtxtInner<'tcx> { } impl<'tcx> InferCtxtUndoLogs<'tcx> { - pub fn actions_since_snapshot(&self, snapshot: &Snapshot<'tcx>) -> &[UndoLog<'tcx>] { - &self.logs[snapshot.undo_len..] - } - pub fn start_snapshot(&mut self) -> Snapshot<'tcx> { self.num_open_snapshots += 1; Snapshot { undo_len: self.logs.len(), _marker: PhantomData } diff --git a/compiler/rustc_infer/src/lib.rs b/compiler/rustc_infer/src/lib.rs index 4ec229ebcf5..d352214b579 100644 --- a/compiler/rustc_infer/src/lib.rs +++ b/compiler/rustc_infer/src/lib.rs @@ -19,6 +19,7 @@ #![feature(const_fn)] #![feature(const_panic)] #![feature(extend_one)] +#![feature(iter_zip)] #![feature(never_type)] #![cfg_attr(bootstrap, feature(or_patterns))] #![feature(in_band_lifetimes)] diff --git a/compiler/rustc_infer/src/traits/error_reporting/mod.rs b/compiler/rustc_infer/src/traits/error_reporting/mod.rs index ad15af9ab3f..0ac4b6b25bb 100644 --- a/compiler/rustc_infer/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/traits/error_reporting/mod.rs @@ -9,6 +9,7 @@ use rustc_middle::ty::TyCtxt; use rustc_span::symbol::Symbol; use rustc_span::{MultiSpan, Span}; use std::fmt; +use std::iter; impl<'a, 'tcx> InferCtxt<'a, 'tcx> { pub fn report_extra_impl_obligation( @@ -94,7 +95,7 @@ pub fn report_object_safety_error( note_span .push_span_label(trait_span, "this trait cannot be made into an object...".to_string()); } - for (span, msg) in multi_span.into_iter().zip(messages.into_iter()) { + for (span, msg) in iter::zip(multi_span, messages) { note_span.push_span_label(span, msg); } err.span_note( diff --git a/compiler/rustc_infer/src/traits/mod.rs b/compiler/rustc_infer/src/traits/mod.rs index 0882d682e15..a33234a91fa 100644 --- a/compiler/rustc_infer/src/traits/mod.rs +++ b/compiler/rustc_infer/src/traits/mod.rs @@ -128,7 +128,7 @@ impl<'tcx> FulfillmentError<'tcx> { } impl<'tcx> TraitObligation<'tcx> { - pub fn self_ty(&self) -> ty::Binder<Ty<'tcx>> { + pub fn self_ty(&self) -> ty::Binder<'tcx, Ty<'tcx>> { self.predicate.map_bound(|p| p.self_ty()) } } diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 94be7a03a93..c693155994f 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -15,7 +15,6 @@ use rustc_expand::base::ExtCtxt; use rustc_hir::def_id::{CrateNum, LOCAL_CRATE}; use rustc_hir::definitions::Definitions; use rustc_hir::Crate; -use rustc_index::vec::IndexVec; use rustc_lint::LintStore; use rustc_middle::arena::Arena; use rustc_middle::dep_graph::DepGraph; @@ -788,13 +787,7 @@ pub fn create_global_ctxt<'tcx>( callback(sess, &mut local_providers, &mut extern_providers); } - let queries = { - let crates = resolver_outputs.cstore.crates_untracked(); - let max_cnum = crates.iter().map(|c| c.as_usize()).max().unwrap_or(0); - let mut providers = IndexVec::from_elem_n(extern_providers, max_cnum + 1); - providers[LOCAL_CRATE] = local_providers; - queries.get_or_init(|| TcxQueries::new(providers, extern_providers)) - }; + let queries = queries.get_or_init(|| TcxQueries::new(local_providers, extern_providers)); let gcx = sess.time("setup_global_ctxt", || { global_ctxt.get_or_init(|| { @@ -1028,9 +1021,6 @@ pub fn start_codegen<'tcx>( rustc_symbol_mangling::test::report_symbol_names(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)); - info!("Post-codegen\n{:?}", tcx.debug_stats()); if tcx.sess.opts.output_types.contains_key(&OutputType::Mir) { diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs index 9c38d2b91ab..01853eab530 100644 --- a/compiler/rustc_interface/src/queries.rs +++ b/compiler/rustc_interface/src/queries.rs @@ -207,7 +207,13 @@ impl<'tcx> Queries<'tcx> { }) .open(self.session()) }); - DepGraph::new(prev_graph, prev_work_products) + + rustc_incremental::build_dep_graph( + self.session(), + prev_graph, + prev_work_products, + ) + .unwrap_or_else(DepGraph::new_disabled) } }) }) @@ -435,6 +441,9 @@ impl Compiler { if self.session().opts.debugging_opts.query_stats { gcx.enter(rustc_query_impl::print_stats); } + + self.session() + .time("serialize_dep_graph", || gcx.enter(rustc_incremental::save_dep_graph)); } _timer = Some(self.session().timer("free_global_ctxt")); diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index 8e6a1ec5095..1653d3bdba1 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -471,7 +471,6 @@ fn test_debugging_options_tracking_hash() { untracked!(ast_json, true); untracked!(ast_json_noexpand, true); untracked!(borrowck, String::from("other")); - untracked!(borrowck_stats, true); untracked!(deduplicate_diagnostics, true); untracked!(dep_tasks, true); untracked!(dont_buffer_diagnostics, true); diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 1a8bbb67cfe..3f16bb9f442 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -481,7 +481,7 @@ fn has_doc(sess: &Session, attr: &ast::Attribute) -> bool { return false; } - if attr.is_value_str() { + if attr.value_str().is_some() { return true; } @@ -565,7 +565,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc { } fn check_crate(&mut self, cx: &LateContext<'_>, krate: &hir::Crate<'_>) { - self.check_missing_docs_attrs(cx, hir::CRATE_HIR_ID, krate.item.span, "the", "crate"); + self.check_missing_docs_attrs(cx, hir::CRATE_HIR_ID, krate.item.inner, "the", "crate"); for macro_def in krate.exported_macros { let attrs = cx.tcx.hir().attrs(macro_def.hir_id()); diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index c9de85a2f18..14bd823ea22 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -45,6 +45,7 @@ use rustc_target::abi::LayoutOf; use tracing::debug; use std::cell::Cell; +use std::iter; use std::slice; /// Information about the registered lints. @@ -176,6 +177,7 @@ impl LintStore { self.early_passes.push(Box::new(pass)); } + /// Used by clippy. pub fn register_pre_expansion_pass( &mut self, pass: impl Fn() -> EarlyLintPassObject + 'static + sync::Send + sync::Sync, @@ -861,10 +863,12 @@ impl<'tcx> LateContext<'tcx> { /// // The given `def_id` is that of an `Option` type /// } /// ``` + /// + /// Used by clippy, but should be replaced by diagnostic items eventually. pub fn match_def_path(&self, def_id: DefId, path: &[Symbol]) -> bool { let names = self.get_def_path(def_id); - names.len() == path.len() && names.into_iter().zip(path.iter()).all(|(a, &b)| a == b) + names.len() == path.len() && iter::zip(names, path).all(|(a, &b)| a == b) } /// Gets the absolute path of `def_id` as a vector of `Symbol`. @@ -905,7 +909,7 @@ impl<'tcx> LateContext<'tcx> { fn print_dyn_existential( self, - _predicates: &'tcx ty::List<ty::Binder<ty::ExistentialPredicate<'tcx>>>, + _predicates: &'tcx ty::List<ty::Binder<'tcx, ty::ExistentialPredicate<'tcx>>>, ) -> Result<Self::DynExistential, Self::Error> { Ok(()) } diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs index a332c300787..863023fa7b5 100644 --- a/compiler/rustc_lint/src/levels.rs +++ b/compiler/rustc_lint/src/levels.rs @@ -564,10 +564,6 @@ impl<'s> LintLevelsBuilder<'s> { self.id_to_set.insert(id, self.cur); } - pub fn build(self) -> LintLevelSets { - self.sets - } - pub fn build_map(self) -> LintLevelMap { LintLevelMap { sets: self.sets, id_to_set: self.id_to_set } } diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index cacdf260548..e2724b52453 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -33,6 +33,7 @@ #![feature(box_patterns)] #![feature(crate_visibility_modifier)] #![feature(iter_order_by)] +#![feature(iter_zip)] #![feature(never_type)] #![feature(nll)] #![cfg_attr(bootstrap, feature(or_patterns))] @@ -325,6 +326,7 @@ fn register_builtins(store: &mut LintStore, no_interleave_lints: bool) { store.register_renamed("exceeding_bitshifts", "arithmetic_overflow"); store.register_renamed("redundant_semicolon", "redundant_semicolons"); store.register_renamed("overlapping_patterns", "overlapping_range_endpoints"); + store.register_renamed("safe_packed_borrows", "unaligned_references"); // These were moved to tool lints, but rustc still sees them when compiling normally, before // tool lints are registered, so `check_tool_name_for_backwards_compat` doesn't work. Use diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index 2d311cc32f8..9c94bab04e9 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -17,6 +17,7 @@ use rustc_target::abi::{Integer, LayoutOf, TagEncoding, VariantIdx, Variants}; use rustc_target::spec::abi::Abi as SpecAbi; use std::cmp; +use std::iter; use std::ops::ControlFlow; use tracing::debug; @@ -1255,7 +1256,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { let sig = self.cx.tcx.fn_sig(def_id); let sig = self.cx.tcx.erase_late_bound_regions(sig); - for (input_ty, input_hir) in sig.inputs().iter().zip(decl.inputs) { + for (input_ty, input_hir) in iter::zip(sig.inputs(), decl.inputs) { self.check_type_for_ffi_and_report_errors(input_hir.span, input_ty, false, false); } @@ -1355,10 +1356,7 @@ impl<'tcx> LateLintPass<'tcx> for VariantSizeDifferences { layout ); - let (largest, slargest, largest_index) = enum_definition - .variants - .iter() - .zip(variants) + let (largest, slargest, largest_index) = iter::zip(enum_definition.variants, variants) .map(|(variant, variant_layout)| { // Subtract the size of the enum tag. let bytes = variant_layout.size.bytes().saturating_sub(tag_size); diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index cd4d01ddc05..4eaee7bf6e8 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -1057,6 +1057,7 @@ declare_lint! { /// unsafe { /// let foo = Foo { field1: 0, field2: 0 }; /// let _ = &foo.field1; + /// println!("{}", foo.field1); // An implicit `&` is added here, triggering the lint. /// } /// } /// ``` @@ -1065,20 +1066,20 @@ declare_lint! { /// /// ### Explanation /// - /// Creating a reference to an insufficiently aligned packed field is - /// [undefined behavior] and should be disallowed. - /// - /// This lint is "allow" by default because there is no stable - /// alternative, and it is not yet certain how widespread existing code - /// will trigger this lint. - /// - /// See [issue #27060] for more discussion. + /// Creating a reference to an insufficiently aligned packed field is [undefined behavior] and + /// should be disallowed. Using an `unsafe` block does not change anything about this. Instead, + /// the code should do a copy of the data in the packed field or use raw pointers and unaligned + /// accesses. See [issue #82523] for more information. /// /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html - /// [issue #27060]: https://github.com/rust-lang/rust/issues/27060 + /// [issue #82523]: https://github.com/rust-lang/rust/issues/82523 pub UNALIGNED_REFERENCES, - Allow, + Warn, "detects unaligned references to fields of packed structs", + @future_incompatible = FutureIncompatibleInfo { + reference: "issue #82523 <https://github.com/rust-lang/rust/issues/82523>", + edition: None, + }; report_in_external_macro } @@ -1151,49 +1152,6 @@ declare_lint! { } declare_lint! { - /// The `safe_packed_borrows` lint detects borrowing a field in the - /// interior of a packed structure with alignment other than 1. - /// - /// ### Example - /// - /// ```rust - /// #[repr(packed)] - /// pub struct Unaligned<T>(pub T); - /// - /// pub struct Foo { - /// start: u8, - /// data: Unaligned<u32>, - /// } - /// - /// fn main() { - /// let x = Foo { start: 0, data: Unaligned(1) }; - /// let y = &x.data.0; - /// } - /// ``` - /// - /// {{produces}} - /// - /// ### Explanation - /// - /// This type of borrow is unsafe and can cause errors on some platforms - /// and violates some assumptions made by the compiler. This was - /// previously allowed unintentionally. This is a [future-incompatible] - /// lint to transition this to a hard error in the future. See [issue - /// #46043] for more details, including guidance on how to solve the - /// problem. - /// - /// [issue #46043]: https://github.com/rust-lang/rust/issues/46043 - /// [future-incompatible]: ../index.md#future-incompatible-lints - pub SAFE_PACKED_BORROWS, - Warn, - "safe borrows of fields of packed structs were erroneously allowed", - @future_incompatible = FutureIncompatibleInfo { - reference: "issue #46043 <https://github.com/rust-lang/rust/issues/46043>", - edition: None, - }; -} - -declare_lint! { /// The `patterns_in_fns_without_body` lint detects `mut` identifier /// patterns as a parameter in functions without a body. /// @@ -1977,7 +1935,7 @@ declare_lint! { Warn, "detects proc macro derives using inaccessible names from parent modules", @future_incompatible = FutureIncompatibleInfo { - reference: "issue #50504 <https://github.com/rust-lang/rust/issues/50504>", + reference: "issue #83583 <https://github.com/rust-lang/rust/issues/83583>", edition: None, }; } @@ -2953,7 +2911,6 @@ declare_lint_pass! { RENAMED_AND_REMOVED_LINTS, UNALIGNED_REFERENCES, CONST_ITEM_MUTATION, - SAFE_PACKED_BORROWS, PATTERNS_IN_FNS_WITHOUT_BODY, MISSING_FRAGMENT_SPECIFIER, LATE_BOUND_LIFETIME_ARGUMENTS, diff --git a/compiler/rustc_macros/src/symbols/tests.rs b/compiler/rustc_macros/src/symbols/tests.rs index 82b4b876978..842d2a97718 100644 --- a/compiler/rustc_macros/src/symbols/tests.rs +++ b/compiler/rustc_macros/src/symbols/tests.rs @@ -43,7 +43,7 @@ fn test_symbols_macro(input: TokenStream, expected_errors: &[&str]) { "Macro generated a different number of errors than expected" ); - for (found_error, &expected_error) in found_errors.iter().zip(expected_errors.iter()) { + for (found_error, &expected_error) in found_errors.iter().zip(expected_errors) { let found_error_str = format!("{}", found_error); assert_eq!(found_error_str, expected_error); } diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index d055c275299..a5157854e15 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -427,7 +427,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { fn encode_info_for_items(&mut self) { let krate = self.tcx.hir().krate(); - self.encode_info_for_mod(CRATE_DEF_ID, &krate.item.module); + self.encode_info_for_mod(CRATE_DEF_ID, &krate.item); // Proc-macro crates only export proc-macro items, which are looked // up using `proc_macro_data` diff --git a/compiler/rustc_middle/src/dep_graph/mod.rs b/compiler/rustc_middle/src/dep_graph/mod.rs index c688b23be1d..d2fe9af34fb 100644 --- a/compiler/rustc_middle/src/dep_graph/mod.rs +++ b/compiler/rustc_middle/src/dep_graph/mod.rs @@ -8,8 +8,8 @@ use rustc_session::Session; mod dep_node; pub use rustc_query_system::dep_graph::{ - debug, hash_result, DepContext, DepNodeColor, DepNodeIndex, SerializedDepNodeIndex, - WorkProduct, WorkProductId, + debug::DepNodeFilter, hash_result, DepContext, DepNodeColor, DepNodeIndex, + SerializedDepNodeIndex, WorkProduct, WorkProductId, }; crate use dep_node::make_compile_codegen_unit; @@ -20,6 +20,7 @@ pub type TaskDeps = rustc_query_system::dep_graph::TaskDeps<DepKind>; pub type DepGraphQuery = rustc_query_system::dep_graph::DepGraphQuery<DepKind>; pub type PreviousDepGraph = rustc_query_system::dep_graph::PreviousDepGraph<DepKind>; pub type SerializedDepGraph = rustc_query_system::dep_graph::SerializedDepGraph<DepKind>; +pub type EdgeFilter = rustc_query_system::dep_graph::debug::EdgeFilter<DepKind>; impl rustc_query_system::dep_graph::DepKind for DepKind { const NULL: Self = DepKind::Null; diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index 9d00f0715a0..d155276051e 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -459,7 +459,7 @@ impl<'hir> Map<'hir> { let hir_id = self.local_def_id_to_hir_id(module); match self.get_entry(hir_id).node { Node::Item(&Item { span, kind: ItemKind::Mod(ref m), .. }) => (m, span, hir_id), - Node::Crate(item) => (&item.module, item.span, hir_id), + Node::Crate(item) => (&item, item.inner, hir_id), node => panic!("not a module: {:?}", node), } } @@ -550,24 +550,6 @@ impl<'hir> Map<'hir> { ParentHirIterator { current_id, map: self } } - /// Checks if the node is an argument. An argument is a local variable whose - /// immediate parent is an item or a closure. - pub fn is_argument(&self, id: HirId) -> bool { - match self.find(id) { - Some(Node::Binding(_)) => (), - _ => return false, - } - matches!( - self.find(self.get_parent_node(id)), - Some( - Node::Item(_) - | Node::TraitItem(_) - | Node::ImplItem(_) - | Node::Expr(Expr { kind: ExprKind::Closure(..), .. }), - ) - ) - } - /// Checks if the node is left-hand side of an assignment. pub fn is_lhs(&self, id: HirId) -> bool { match self.find(self.get_parent_node(id)) { @@ -779,17 +761,6 @@ impl<'hir> Map<'hir> { } } - pub fn expect_variant_data(&self, id: HirId) -> &'hir VariantData<'hir> { - match self.find(id) { - Some( - Node::Ctor(vd) - | Node::Item(Item { kind: ItemKind::Struct(vd, _) | ItemKind::Union(vd, _), .. }), - ) => vd, - Some(Node::Variant(variant)) => &variant.data, - _ => bug!("expected struct or variant, found {}", self.node_to_string(id)), - } - } - pub fn expect_variant(&self, id: HirId) -> &'hir Variant<'hir> { match self.find(id) { Some(Node::Variant(variant)) => variant, @@ -897,7 +868,7 @@ impl<'hir> Map<'hir> { Node::Visibility(v) => bug!("unexpected Visibility {:?}", v), Node::Local(local) => local.span, Node::MacroDef(macro_def) => macro_def.span, - Node::Crate(item) => item.span, + Node::Crate(item) => item.inner, }; Some(span) } diff --git a/compiler/rustc_middle/src/ich/hcx.rs b/compiler/rustc_middle/src/ich/hcx.rs index cf29d21927c..b2fef731b7e 100644 --- a/compiler/rustc_middle/src/ich/hcx.rs +++ b/compiler/rustc_middle/src/ich/hcx.rs @@ -120,11 +120,6 @@ impl<'a> StableHashingContext<'a> { } #[inline] - pub fn sess(&self) -> &'a Session { - self.sess - } - - #[inline] pub fn while_hashing_hir_bodies<F: FnOnce(&mut Self)>(&mut self, hash_bodies: bool, f: F) { let prev_hash_bodies = self.hash_bodies; self.hash_bodies = hash_bodies; diff --git a/compiler/rustc_middle/src/ich/impls_ty.rs b/compiler/rustc_middle/src/ich/impls_ty.rs index 573b514e844..8e53e4ba948 100644 --- a/compiler/rustc_middle/src/ich/impls_ty.rs +++ b/compiler/rustc_middle/src/ich/impls_ty.rs @@ -70,16 +70,16 @@ impl<'a> HashStable<StableHashingContext<'a>> for ty::RegionKind { ty::ReEmpty(universe) => { universe.hash_stable(hcx, hasher); } - ty::ReLateBound(db, ty::BoundRegion { kind: ty::BrAnon(i) }) => { + ty::ReLateBound(db, ty::BoundRegion { kind: ty::BrAnon(i), .. }) => { db.hash_stable(hcx, hasher); i.hash_stable(hcx, hasher); } - ty::ReLateBound(db, ty::BoundRegion { kind: ty::BrNamed(def_id, name) }) => { + ty::ReLateBound(db, ty::BoundRegion { kind: ty::BrNamed(def_id, name), .. }) => { db.hash_stable(hcx, hasher); def_id.hash_stable(hcx, hasher); name.hash_stable(hcx, hasher); } - ty::ReLateBound(db, ty::BoundRegion { kind: ty::BrEnv }) => { + ty::ReLateBound(db, ty::BoundRegion { kind: ty::BrEnv, .. }) => { db.hash_stable(hcx, hasher); } ty::ReEarlyBound(ty::EarlyBoundRegion { def_id, index, name }) => { @@ -118,12 +118,13 @@ impl<'tcx> HashStable<StableHashingContext<'tcx>> for ty::BoundVar { } } -impl<'a, T> HashStable<StableHashingContext<'a>> for ty::Binder<T> +impl<'a, 'tcx, T> HashStable<StableHashingContext<'a>> for ty::Binder<'tcx, T> where T: HashStable<StableHashingContext<'a>>, { fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { self.as_ref().skip_binder().hash_stable(hcx, hasher); + self.bound_vars().hash_stable(hcx, hasher); } } diff --git a/compiler/rustc_middle/src/infer/canonical.rs b/compiler/rustc_middle/src/infer/canonical.rs index e106db38b2c..5df2f91f09f 100644 --- a/compiler/rustc_middle/src/infer/canonical.rs +++ b/compiler/rustc_middle/src/infer/canonical.rs @@ -27,6 +27,7 @@ use crate::ty::{self, BoundVar, List, Region, TyCtxt}; use rustc_index::vec::IndexVec; use rustc_macros::HashStable; use smallvec::SmallVec; +use std::iter; use std::ops::Index; /// A "canonicalized" type `V` is one where all free inference @@ -227,20 +228,12 @@ impl Certainty { Certainty::Ambiguous => false, } } - - pub fn is_ambiguous(&self) -> bool { - !self.is_proven() - } } impl<'tcx, R> QueryResponse<'tcx, R> { pub fn is_proven(&self) -> bool { self.certainty.is_proven() } - - pub fn is_ambiguous(&self) -> bool { - !self.is_proven() - } } impl<'tcx, R> Canonical<'tcx, QueryResponse<'tcx, R>> { @@ -284,7 +277,7 @@ impl<'tcx, V> Canonical<'tcx, V> { } pub type QueryOutlivesConstraint<'tcx> = - ty::Binder<ty::OutlivesPredicate<GenericArg<'tcx>, Region<'tcx>>>; + ty::Binder<'tcx, ty::OutlivesPredicate<GenericArg<'tcx>, Region<'tcx>>>; TrivialTypeFoldableAndLiftImpls! { for <'tcx> { @@ -315,16 +308,14 @@ impl<'tcx> CanonicalVarValues<'tcx> { use crate::ty::subst::GenericArgKind; CanonicalVarValues { - var_values: self - .var_values - .iter() - .zip(0..) + var_values: iter::zip(&self.var_values, 0..) .map(|(kind, i)| match kind.unpack() { GenericArgKind::Type(..) => { tcx.mk_ty(ty::Bound(ty::INNERMOST, ty::BoundVar::from_u32(i).into())).into() } GenericArgKind::Lifetime(..) => { - let br = ty::BoundRegion { kind: ty::BrAnon(i) }; + let br = + ty::BoundRegion { var: ty::BoundVar::from_u32(i), kind: ty::BrAnon(i) }; tcx.mk_region(ty::ReLateBound(ty::INNERMOST, br)).into() } GenericArgKind::Const(ct) => tcx diff --git a/compiler/rustc_middle/src/infer/unify_key.rs b/compiler/rustc_middle/src/infer/unify_key.rs index 8318bdefc8e..641cf23781e 100644 --- a/compiler/rustc_middle/src/infer/unify_key.rs +++ b/compiler/rustc_middle/src/infer/unify_key.rs @@ -97,13 +97,6 @@ impl<'tcx> ConstVariableValue<'tcx> { ConstVariableValue::Known { value } => Some(value), } } - - pub fn is_unknown(&self) -> bool { - match *self { - ConstVariableValue::Unknown { .. } => true, - ConstVariableValue::Known { .. } => false, - } - } } #[derive(Copy, Clone, Debug)] diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs index 1561b3d7d29..bd0749792db 100644 --- a/compiler/rustc_middle/src/lib.rs +++ b/compiler/rustc_middle/src/lib.rs @@ -51,6 +51,7 @@ #![feature(exclusive_range_pattern)] #![feature(control_flow_enum)] #![feature(associated_type_defaults)] +#![feature(iter_zip)] #![recursion_limit = "512"] #[macro_use] diff --git a/compiler/rustc_middle/src/middle/region.rs b/compiler/rustc_middle/src/middle/region.rs index eb48198991c..5440e63543d 100644 --- a/compiler/rustc_middle/src/middle/region.rs +++ b/compiler/rustc_middle/src/middle/region.rs @@ -430,6 +430,8 @@ impl ScopeTree { /// Returns `true` if `subscope` is equal to or is lexically nested inside `superscope`, and /// `false` otherwise. + /// + /// Used by clippy. pub fn is_subscope_of(&self, subscope: Scope, superscope: Scope) -> bool { let mut s = subscope; debug!("is_subscope_of({:?}, {:?})", subscope, superscope); diff --git a/compiler/rustc_middle/src/middle/resolve_lifetime.rs b/compiler/rustc_middle/src/middle/resolve_lifetime.rs index 32615f6c410..aa6488b329e 100644 --- a/compiler/rustc_middle/src/middle/resolve_lifetime.rs +++ b/compiler/rustc_middle/src/middle/resolve_lifetime.rs @@ -39,8 +39,13 @@ impl LifetimeDefOrigin { pub enum Region { Static, EarlyBound(/* index */ u32, /* lifetime decl */ DefId, LifetimeDefOrigin), - LateBound(ty::DebruijnIndex, /* lifetime decl */ DefId, LifetimeDefOrigin), - LateBoundAnon(ty::DebruijnIndex, /* anon index */ u32), + LateBound( + ty::DebruijnIndex, + /* late-bound index */ u32, + /* lifetime decl */ DefId, + LifetimeDefOrigin, + ), + LateBoundAnon(ty::DebruijnIndex, /* late-bound index */ u32, /* anon index */ u32), Free(DefId, /* lifetime decl */ DefId), } @@ -78,4 +83,6 @@ pub struct ResolveLifetimes { /// be late-bound if (a) it does NOT appear in a where-clause and /// (b) it DOES appear in the arguments. pub late_bound: FxHashMap<LocalDefId, FxHashSet<ItemLocalId>>, + + pub late_bound_vars: FxHashMap<LocalDefId, FxHashMap<ItemLocalId, Vec<ty::BoundVariableKind>>>, } diff --git a/compiler/rustc_middle/src/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs index 89ca8eed39a..fc9a2970e00 100644 --- a/compiler/rustc_middle/src/middle/stability.rs +++ b/compiler/rustc_middle/src/middle/stability.rs @@ -29,12 +29,6 @@ pub enum StabilityLevel { Stable, } -impl StabilityLevel { - pub fn from_attr_level(level: &attr::StabilityLevel) -> Self { - if level.is_stable() { Stable } else { Unstable } - } -} - /// An entry in the `depr_map`. #[derive(Clone, HashStable, Debug)] pub struct DeprecationEntry { diff --git a/compiler/rustc_middle/src/mir/coverage.rs b/compiler/rustc_middle/src/mir/coverage.rs index eae02a8cbfc..ad48b236a9a 100644 --- a/compiler/rustc_middle/src/mir/coverage.rs +++ b/compiler/rustc_middle/src/mir/coverage.rs @@ -117,17 +117,9 @@ impl CoverageKind { } } - pub fn is_counter(&self) -> bool { - matches!(self, Self::Counter { .. }) - } - pub fn is_expression(&self) -> bool { matches!(self, Self::Expression { .. }) } - - pub fn is_unreachable(&self) -> bool { - *self == Self::Unreachable - } } impl Debug for CoverageKind { diff --git a/compiler/rustc_middle/src/mir/interpret/value.rs b/compiler/rustc_middle/src/mir/interpret/value.rs index 5172dfd041a..888777a9418 100644 --- a/compiler/rustc_middle/src/mir/interpret/value.rs +++ b/compiler/rustc_middle/src/mir/interpret/value.rs @@ -308,16 +308,6 @@ impl<'tcx, Tag> Scalar<Tag> { } #[inline] - pub fn from_i8(i: i8) -> Self { - Self::from_int(i, Size::from_bits(8)) - } - - #[inline] - pub fn from_i16(i: i16) -> Self { - Self::from_int(i, Size::from_bits(16)) - } - - #[inline] pub fn from_i32(i: i32) -> Self { Self::from_int(i, Size::from_bits(32)) } diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index d05269913eb..abca2ecdb06 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -379,24 +379,6 @@ impl<'tcx> Body<'tcx> { } } - /// Returns an iterator over all temporaries. - #[inline] - pub fn temps_iter<'a>(&'a self) -> impl Iterator<Item = Local> + 'a { - (self.arg_count + 1..self.local_decls.len()).filter_map(move |index| { - let local = Local::new(index); - if self.local_decls[local].is_user_variable() { None } else { Some(local) } - }) - } - - /// Returns an iterator over all user-declared locals. - #[inline] - pub fn vars_iter<'a>(&'a self) -> impl Iterator<Item = Local> + 'a { - (self.arg_count + 1..self.local_decls.len()).filter_map(move |index| { - let local = Local::new(index); - self.local_decls[local].is_user_variable().then_some(local) - }) - } - /// Returns an iterator over all user-declared mutable locals. #[inline] pub fn mut_vars_iter<'a>(&'a self) -> impl Iterator<Item = Local> + 'a { @@ -2329,7 +2311,7 @@ impl<'tcx> Debug for Rvalue<'tcx> { CtorKind::Fn => fmt_tuple(fmt, &name), CtorKind::Fictive => { let mut struct_fmt = fmt.debug_struct(&name); - for (field, place) in variant_def.fields.iter().zip(places) { + for (field, place) in iter::zip(&variant_def.fields, places) { struct_fmt.field(&field.ident.as_str(), place); } struct_fmt.finish() @@ -2353,7 +2335,7 @@ impl<'tcx> Debug for Rvalue<'tcx> { let mut struct_fmt = fmt.debug_struct(&name); if let Some(upvars) = tcx.upvars_mentioned(def_id) { - for (&var_id, place) in upvars.keys().zip(places) { + for (&var_id, place) in iter::zip(upvars.keys(), places) { let var_name = tcx.hir().name(var_id); struct_fmt.field(&var_name.as_str(), place); } @@ -2372,7 +2354,7 @@ impl<'tcx> Debug for Rvalue<'tcx> { let mut struct_fmt = fmt.debug_struct(&name); if let Some(upvars) = tcx.upvars_mentioned(def_id) { - for (&var_id, place) in upvars.keys().zip(places) { + for (&var_id, place) in iter::zip(upvars.keys(), places) { let var_name = tcx.hir().name(var_id); struct_fmt.field(&var_name.as_str(), place); } diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs index 0167655bee5..6c2468b9ffe 100644 --- a/compiler/rustc_middle/src/mir/mono.rs +++ b/compiler/rustc_middle/src/mir/mono.rs @@ -84,14 +84,7 @@ impl<'tcx> MonoItem<'tcx> { .debugging_opts .inline_in_all_cgus .unwrap_or_else(|| tcx.sess.opts.optimize != OptLevel::No) - && !tcx.sess.link_dead_code() - && !tcx.sess.instrument_coverage(); - // Disabled for `-Z instrument-coverage` because some LLVM optimizations can sometimes - // break coverage results. A test that failed at certain optimization levels is now - // validated at that optimization level (via `compile-flags` directive): - // * `src/test/run-make-fulldeps/coverage/closure.rs` broke with `-C opt-level=2`, and - // also required disabling `internalize_symbols` in - // `rustc_mir/monomorphize/partitioning/mod.rs` + && !tcx.sess.link_dead_code(); match *self { MonoItem::Fn(ref instance) => { diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs index bde48018013..ad3baccf154 100644 --- a/compiler/rustc_middle/src/mir/query.rs +++ b/compiler/rustc_middle/src/mir/query.rs @@ -23,15 +23,9 @@ pub enum UnsafetyViolationKind { General, /// Permitted both in `const fn`s and regular `fn`s. GeneralAndConstFn, - /// Borrow of packed field. - /// Has to be handled as a lint for backwards compatibility. - BorrowPacked, /// Unsafe operation in an `unsafe fn` but outside an `unsafe` block. /// Has to be handled as a lint for backwards compatibility. UnsafeFn, - /// Borrow of packed field in an `unsafe fn` but outside an `unsafe` block. - /// Has to be handled as a lint for backwards compatibility. - UnsafeFnBorrowPacked, } #[derive(Copy, Clone, PartialEq, TyEncodable, TyDecodable, HashStable, Debug)] diff --git a/compiler/rustc_middle/src/mir/terminator.rs b/compiler/rustc_middle/src/mir/terminator.rs index 887dbefa9f2..c8db4aeb449 100644 --- a/compiler/rustc_middle/src/mir/terminator.rs +++ b/compiler/rustc_middle/src/mir/terminator.rs @@ -67,7 +67,7 @@ impl SwitchTargets { /// /// 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()) } + SwitchTargetsIter { inner: iter::zip(&self.values, &self.targets) } } /// Returns a slice with all possible jump targets (including the fallback target). diff --git a/compiler/rustc_middle/src/mir/traversal.rs b/compiler/rustc_middle/src/mir/traversal.rs index 36e277d1a88..725448584dd 100644 --- a/compiler/rustc_middle/src/mir/traversal.rs +++ b/compiler/rustc_middle/src/mir/traversal.rs @@ -264,10 +264,6 @@ impl<'a, 'tcx> ReversePostorder<'a, 'tcx> { ReversePostorder { body, blocks, idx: len } } - - pub fn reset(&mut self) { - self.idx = self.blocks.len(); - } } pub fn reverse_postorder<'a, 'tcx>(body: &'a Body<'tcx>) -> ReversePostorder<'a, 'tcx> { diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index be248ccabda..32b4cd665d0 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -1247,12 +1247,6 @@ impl PlaceContext { matches!(self, PlaceContext::MutatingUse(..)) } - /// Returns `true` if this place context represents a use that does not change the value. - #[inline] - pub fn is_nonmutating_use(&self) -> bool { - matches!(self, PlaceContext::NonMutatingUse(..)) - } - /// Returns `true` if this place context represents a use. #[inline] pub fn is_use(&self) -> bool { diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index fbd5af9d0a9..99d063c7eea 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1290,6 +1290,10 @@ rustc_queries! { -> Option<Vec<ObjectLifetimeDefault>> { desc { "looking up lifetime defaults for a region on an item" } } + query late_bound_vars_map(_: LocalDefId) + -> Option<&'tcx FxHashMap<ItemLocalId, Vec<ty::BoundVariableKind>>> { + desc { "looking up late bound vars" } + } query visibility(def_id: DefId) -> ty::Visibility { eval_always diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index 90b82020551..00dec3b355f 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -323,6 +323,9 @@ pub enum ObligationCauseCode<'tcx> { /// #[feature(trivial_bounds)] is not enabled TrivialBound, + + /// If `X` is the concrete type of an opaque type `impl Y`, then `X` must implement `Y` + OpaqueType, } impl ObligationCauseCode<'_> { @@ -341,7 +344,7 @@ impl ObligationCauseCode<'_> { // `ObligationCauseCode` is used a lot. Make sure it doesn't unintentionally get bigger. #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] -static_assert_size!(ObligationCauseCode<'_>, 32); +static_assert_size!(ObligationCauseCode<'_>, 40); #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] pub enum StatementAsExpression { diff --git a/compiler/rustc_middle/src/traits/query.rs b/compiler/rustc_middle/src/traits/query.rs index f9cadb3bb2d..eac3ab7282f 100644 --- a/compiler/rustc_middle/src/traits/query.rs +++ b/compiler/rustc_middle/src/traits/query.rs @@ -44,24 +44,12 @@ pub mod type_op { pub b: Ty<'tcx>, } - impl<'tcx> Eq<'tcx> { - pub fn new(a: Ty<'tcx>, b: Ty<'tcx>) -> Self { - Self { a, b } - } - } - #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, TypeFoldable, Lift)] pub struct Subtype<'tcx> { pub sub: Ty<'tcx>, pub sup: Ty<'tcx>, } - impl<'tcx> Subtype<'tcx> { - pub fn new(sub: Ty<'tcx>, sup: Ty<'tcx>) -> Self { - Self { sub, sup } - } - } - #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, TypeFoldable, Lift)] pub struct ProvePredicate<'tcx> { pub predicate: Predicate<'tcx>, diff --git a/compiler/rustc_middle/src/ty/_match.rs b/compiler/rustc_middle/src/ty/_match.rs index a5962e3b3ba..8e2c79701af 100644 --- a/compiler/rustc_middle/src/ty/_match.rs +++ b/compiler/rustc_middle/src/ty/_match.rs @@ -112,9 +112,9 @@ impl TypeRelation<'tcx> for Match<'tcx> { fn binders<T>( &mut self, - a: ty::Binder<T>, - b: ty::Binder<T>, - ) -> RelateResult<'tcx, ty::Binder<T>> + a: ty::Binder<'tcx, T>, + b: ty::Binder<'tcx, T>, + ) -> RelateResult<'tcx, ty::Binder<'tcx, T>> where T: Relate<'tcx>, { diff --git a/compiler/rustc_middle/src/ty/closure.rs b/compiler/rustc_middle/src/ty/closure.rs index c31a882c272..52cb6b301b0 100644 --- a/compiler/rustc_middle/src/ty/closure.rs +++ b/compiler/rustc_middle/src/ty/closure.rs @@ -6,7 +6,6 @@ use crate::ty; use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; -use rustc_hir::lang_items::LangItem; use rustc_span::Span; use super::{Ty, TyCtxt}; @@ -113,14 +112,6 @@ impl<'tcx> ClosureKind { // This is the initial value used when doing upvar inference. pub const LATTICE_BOTTOM: ClosureKind = ClosureKind::Fn; - pub fn trait_did(&self, tcx: TyCtxt<'tcx>) -> DefId { - match *self { - ClosureKind::Fn => tcx.require_lang_item(LangItem::Fn, None), - ClosureKind::FnMut => tcx.require_lang_item(LangItem::FnMut, None), - ClosureKind::FnOnce => tcx.require_lang_item(LangItem::FnOnce, None), - } - } - /// Returns `true` if a type that impls this closure kind /// must also implement `other`. pub fn extends(self, other: ty::ClosureKind) -> bool { @@ -377,12 +368,4 @@ impl BorrowKind { UniqueImmBorrow => hir::Mutability::Mut, } } - - pub fn to_user_str(&self) -> &'static str { - match *self { - MutBorrow => "mutable", - ImmBorrow => "immutable", - UniqueImmBorrow => "uniquely immutable", - } - } } diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs index 3225efd05e4..d7767dc39cb 100644 --- a/compiler/rustc_middle/src/ty/codec.rs +++ b/compiler/rustc_middle/src/ty/codec.rs @@ -120,8 +120,9 @@ impl<'tcx, E: TyEncoder<'tcx>> Encodable<E> for Ty<'tcx> { } } -impl<'tcx, E: TyEncoder<'tcx>> Encodable<E> for ty::Binder<ty::PredicateKind<'tcx>> { +impl<'tcx, E: TyEncoder<'tcx>> Encodable<E> for ty::Binder<'tcx, ty::PredicateKind<'tcx>> { fn encode(&self, e: &mut E) -> Result<(), E::Error> { + self.bound_vars().encode(e)?; encode_with_shorthand(e, &self.skip_binder(), TyEncoder::predicate_shorthands) } } @@ -188,7 +189,7 @@ pub trait TyDecoder<'tcx>: Decoder { } #[inline] -pub fn decode_arena_allocable<'tcx, D, T: ArenaAllocatable<'tcx> + Decodable<D>>( +fn decode_arena_allocable<'tcx, D, T: ArenaAllocatable<'tcx> + Decodable<D>>( decoder: &mut D, ) -> Result<&'tcx T, D::Error> where @@ -198,7 +199,7 @@ where } #[inline] -pub fn decode_arena_allocable_slice<'tcx, D, T: ArenaAllocatable<'tcx> + Decodable<D>>( +fn decode_arena_allocable_slice<'tcx, D, T: ArenaAllocatable<'tcx> + Decodable<D>>( decoder: &mut D, ) -> Result<&'tcx [T], D::Error> where @@ -226,18 +227,22 @@ impl<'tcx, D: TyDecoder<'tcx>> Decodable<D> for Ty<'tcx> { } } -impl<'tcx, D: TyDecoder<'tcx>> Decodable<D> for ty::Binder<ty::PredicateKind<'tcx>> { - fn decode(decoder: &mut D) -> Result<ty::Binder<ty::PredicateKind<'tcx>>, D::Error> { +impl<'tcx, D: TyDecoder<'tcx>> Decodable<D> for ty::Binder<'tcx, ty::PredicateKind<'tcx>> { + fn decode(decoder: &mut D) -> Result<ty::Binder<'tcx, ty::PredicateKind<'tcx>>, D::Error> { + let bound_vars = Decodable::decode(decoder)?; // Handle shorthands first, if we have an usize > 0x80. - Ok(ty::Binder::bind(if decoder.positioned_at_shorthand() { - let pos = decoder.read_usize()?; - assert!(pos >= SHORTHAND_OFFSET); - let shorthand = pos - SHORTHAND_OFFSET; - - decoder.with_position(shorthand, ty::PredicateKind::decode)? - } else { - ty::PredicateKind::decode(decoder)? - })) + Ok(ty::Binder::bind_with_vars( + if decoder.positioned_at_shorthand() { + let pos = decoder.read_usize()?; + assert!(pos >= SHORTHAND_OFFSET); + let shorthand = pos - SHORTHAND_OFFSET; + + decoder.with_position(shorthand, ty::PredicateKind::decode)? + } else { + ty::PredicateKind::decode(decoder)? + }, + bound_vars, + )) } } @@ -319,7 +324,7 @@ impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for ty::List<Ty<'tcx>> { } impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> - for ty::List<ty::Binder<ty::ExistentialPredicate<'tcx>>> + for ty::List<ty::Binder<'tcx, ty::ExistentialPredicate<'tcx>>> { fn decode(decoder: &mut D) -> Result<&'tcx Self, D::Error> { let len = decoder.read_usize()?; @@ -379,15 +384,23 @@ impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for [mir::abstract_const::N } } +impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for ty::List<ty::BoundVariableKind> { + fn decode(decoder: &mut D) -> Result<&'tcx Self, D::Error> { + let len = decoder.read_usize()?; + Ok(decoder.tcx().mk_bound_variable_kinds((0..len).map(|_| Decodable::decode(decoder)))?) + } +} + impl_decodable_via_ref! { &'tcx ty::TypeckResults<'tcx>, &'tcx ty::List<Ty<'tcx>>, - &'tcx ty::List<ty::Binder<ty::ExistentialPredicate<'tcx>>>, + &'tcx ty::List<ty::Binder<'tcx, ty::ExistentialPredicate<'tcx>>>, &'tcx Allocation, &'tcx mir::Body<'tcx>, &'tcx mir::UnsafetyCheckResult, &'tcx mir::BorrowCheckResult<'tcx>, - &'tcx mir::coverage::CodeRegion + &'tcx mir::coverage::CodeRegion, + &'tcx ty::List<ty::BoundVariableKind> } #[macro_export] @@ -488,14 +501,16 @@ macro_rules! implement_ty_decoder { macro_rules! impl_binder_encode_decode { ($($t:ty),+ $(,)?) => { $( - impl<'tcx, E: TyEncoder<'tcx>> Encodable<E> for ty::Binder<$t> { + impl<'tcx, E: TyEncoder<'tcx>> Encodable<E> for ty::Binder<'tcx, $t> { fn encode(&self, e: &mut E) -> Result<(), E::Error> { + self.bound_vars().encode(e)?; self.as_ref().skip_binder().encode(e) } } - impl<'tcx, D: TyDecoder<'tcx>> Decodable<D> for ty::Binder<$t> { + impl<'tcx, D: TyDecoder<'tcx>> Decodable<D> for ty::Binder<'tcx, $t> { fn decode(decoder: &mut D) -> Result<Self, D::Error> { - Ok(ty::Binder::bind(Decodable::decode(decoder)?)) + let bound_vars = Decodable::decode(decoder)?; + Ok(ty::Binder::bind_with_vars(Decodable::decode(decoder)?, bound_vars)) } } )* diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 57225b7abf7..bb2b00cbaea 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -87,7 +87,8 @@ pub struct CtxtInterners<'tcx> { substs: InternedSet<'tcx, InternalSubsts<'tcx>>, canonical_var_infos: InternedSet<'tcx, List<CanonicalVarInfo<'tcx>>>, region: InternedSet<'tcx, RegionKind>, - poly_existential_predicates: InternedSet<'tcx, List<ty::Binder<ExistentialPredicate<'tcx>>>>, + poly_existential_predicates: + InternedSet<'tcx, List<ty::Binder<'tcx, ExistentialPredicate<'tcx>>>>, predicate: InternedSet<'tcx, PredicateInner<'tcx>>, predicates: InternedSet<'tcx, List<Predicate<'tcx>>>, projs: InternedSet<'tcx, List<ProjectionKind>>, @@ -95,6 +96,7 @@ pub struct CtxtInterners<'tcx> { const_: InternedSet<'tcx, Const<'tcx>>, /// Const allocations. allocation: InternedSet<'tcx, Allocation>, + bound_variable_kinds: InternedSet<'tcx, List<ty::BoundVariableKind>>, } impl<'tcx> CtxtInterners<'tcx> { @@ -113,6 +115,7 @@ impl<'tcx> CtxtInterners<'tcx> { place_elems: Default::default(), const_: Default::default(), allocation: Default::default(), + bound_variable_kinds: Default::default(), } } @@ -136,7 +139,10 @@ impl<'tcx> CtxtInterners<'tcx> { } #[inline(never)] - fn intern_predicate(&self, kind: Binder<PredicateKind<'tcx>>) -> &'tcx PredicateInner<'tcx> { + fn intern_predicate( + &self, + kind: Binder<'tcx, PredicateKind<'tcx>>, + ) -> &'tcx PredicateInner<'tcx> { self.predicate .intern(kind, |kind| { let flags = super::flags::FlagComputation::for_predicate(kind); @@ -449,7 +455,7 @@ pub struct TypeckResults<'tcx> { /// Stores the type, expression, span and optional scope span of all types /// that are live across the yield of this generator (if a generator). - pub generator_interior_types: ty::Binder<Vec<GeneratorInteriorTypeCause<'tcx>>>, + pub generator_interior_types: ty::Binder<'tcx, Vec<GeneratorInteriorTypeCause<'tcx>>>, /// We sometimes treat byte string literals (which are of type `&[u8; N]`) /// as `&[u8]`, depending on the pattern in which they are used. @@ -789,7 +795,7 @@ impl CanonicalUserType<'tcx> { return false; } - user_substs.substs.iter().zip(BoundVar::new(0)..).all(|(kind, cvar)| { + iter::zip(user_substs.substs, BoundVar::new(0)..).all(|(kind, cvar)| { match kind.unpack() { GenericArgKind::Type(ty) => match ty.kind() { ty::Bound(debruijn, b) => { @@ -804,7 +810,7 @@ impl CanonicalUserType<'tcx> { ty::ReLateBound(debruijn, br) => { // We only allow a `ty::INNERMOST` index in substitutions. assert_eq!(*debruijn, ty::INNERMOST); - cvar == br.assert_bound_var() + cvar == br.var } _ => false, }, @@ -1616,10 +1622,11 @@ nop_lift! {allocation; &'a Allocation => &'tcx Allocation} nop_lift! {predicate; &'a PredicateInner<'a> => &'tcx PredicateInner<'tcx>} nop_list_lift! {type_list; Ty<'a> => Ty<'tcx>} -nop_list_lift! {poly_existential_predicates; ty::Binder<ExistentialPredicate<'a>> => ty::Binder<ExistentialPredicate<'tcx>>} +nop_list_lift! {poly_existential_predicates; ty::Binder<'a, ExistentialPredicate<'a>> => ty::Binder<'tcx, ExistentialPredicate<'tcx>>} nop_list_lift! {predicates; Predicate<'a> => Predicate<'tcx>} nop_list_lift! {canonical_var_infos; CanonicalVarInfo<'a> => CanonicalVarInfo<'tcx>} nop_list_lift! {projs; ProjectionKind => ProjectionKind} +nop_list_lift! {bound_variable_kinds; ty::BoundVariableKind => ty::BoundVariableKind} // This is the impl for `&'a InternalSubsts<'a>`. nop_list_lift! {substs; GenericArg<'a> => GenericArg<'tcx>} @@ -1965,8 +1972,8 @@ impl<'tcx> Hash for Interned<'tcx, PredicateInner<'tcx>> { } } -impl<'tcx> Borrow<Binder<PredicateKind<'tcx>>> for Interned<'tcx, PredicateInner<'tcx>> { - fn borrow<'a>(&'a self) -> &'a Binder<PredicateKind<'tcx>> { +impl<'tcx> Borrow<Binder<'tcx, PredicateKind<'tcx>>> for Interned<'tcx, PredicateInner<'tcx>> { + fn borrow<'a>(&'a self) -> &'a Binder<'tcx, PredicateKind<'tcx>> { &self.0.kind } } @@ -2072,10 +2079,11 @@ slice_interners!( substs: _intern_substs(GenericArg<'tcx>), canonical_var_infos: _intern_canonical_var_infos(CanonicalVarInfo<'tcx>), poly_existential_predicates: - _intern_poly_existential_predicates(ty::Binder<ExistentialPredicate<'tcx>>), + _intern_poly_existential_predicates(ty::Binder<'tcx, ExistentialPredicate<'tcx>>), predicates: _intern_predicates(Predicate<'tcx>), projs: _intern_projs(ProjectionKind), place_elems: _intern_place_elems(PlaceElem<'tcx>), + bound_variable_kinds: _intern_bound_variable_kinds(ty::BoundVariableKind), ); impl<'tcx> TyCtxt<'tcx> { @@ -2158,7 +2166,7 @@ impl<'tcx> TyCtxt<'tcx> { } #[inline] - pub fn mk_predicate(self, binder: Binder<PredicateKind<'tcx>>) -> Predicate<'tcx> { + pub fn mk_predicate(self, binder: Binder<'tcx, PredicateKind<'tcx>>) -> Predicate<'tcx> { let inner = self.interners.intern_predicate(binder); Predicate { inner } } @@ -2167,7 +2175,7 @@ impl<'tcx> TyCtxt<'tcx> { pub fn reuse_or_mk_predicate( self, pred: Predicate<'tcx>, - binder: Binder<PredicateKind<'tcx>>, + binder: Binder<'tcx, PredicateKind<'tcx>>, ) -> Predicate<'tcx> { if pred.kind() != binder { self.mk_predicate(binder) } else { pred } } @@ -2289,11 +2297,6 @@ impl<'tcx> TyCtxt<'tcx> { } #[inline] - pub fn mk_nil_ptr(self) -> Ty<'tcx> { - self.mk_imm_ptr(self.mk_unit()) - } - - #[inline] pub fn mk_array(self, ty: Ty<'tcx>, n: u64) -> Ty<'tcx> { self.mk_ty(Array(ty, ty::Const::from_usize(self, n))) } @@ -2339,7 +2342,7 @@ impl<'tcx> TyCtxt<'tcx> { #[inline] pub fn mk_dynamic( self, - obj: &'tcx List<ty::Binder<ExistentialPredicate<'tcx>>>, + obj: &'tcx List<ty::Binder<'tcx, ExistentialPredicate<'tcx>>>, reg: ty::Region<'tcx>, ) -> Ty<'tcx> { self.mk_ty(Dynamic(obj, reg)) @@ -2366,7 +2369,7 @@ impl<'tcx> TyCtxt<'tcx> { } #[inline] - pub fn mk_generator_witness(self, types: ty::Binder<&'tcx List<Ty<'tcx>>>) -> Ty<'tcx> { + pub fn mk_generator_witness(self, types: ty::Binder<'tcx, &'tcx List<Ty<'tcx>>>) -> Ty<'tcx> { self.mk_ty(GeneratorWitness(types)) } @@ -2471,8 +2474,8 @@ impl<'tcx> TyCtxt<'tcx> { pub fn intern_poly_existential_predicates( self, - eps: &[ty::Binder<ExistentialPredicate<'tcx>>], - ) -> &'tcx List<ty::Binder<ExistentialPredicate<'tcx>>> { + eps: &[ty::Binder<'tcx, ExistentialPredicate<'tcx>>], + ) -> &'tcx List<ty::Binder<'tcx, ExistentialPredicate<'tcx>>> { assert!(!eps.is_empty()); assert!( eps.array_windows() @@ -2517,6 +2520,13 @@ impl<'tcx> TyCtxt<'tcx> { if ts.is_empty() { List::empty() } else { self._intern_canonical_var_infos(ts) } } + pub fn intern_bound_variable_kinds( + self, + ts: &[ty::BoundVariableKind], + ) -> &'tcx List<ty::BoundVariableKind> { + if ts.is_empty() { List::empty() } else { self._intern_bound_variable_kinds(ts) } + } + pub fn mk_fn_sig<I>( self, inputs: I, @@ -2538,8 +2548,8 @@ impl<'tcx> TyCtxt<'tcx> { pub fn mk_poly_existential_predicates< I: InternAs< - [ty::Binder<ExistentialPredicate<'tcx>>], - &'tcx List<ty::Binder<ExistentialPredicate<'tcx>>>, + [ty::Binder<'tcx, ExistentialPredicate<'tcx>>], + &'tcx List<ty::Binder<'tcx, ExistentialPredicate<'tcx>>>, >, >( self, @@ -2577,6 +2587,15 @@ impl<'tcx> TyCtxt<'tcx> { self.mk_substs(iter::once(self_ty.into()).chain(rest.iter().cloned())) } + pub fn mk_bound_variable_kinds< + I: InternAs<[ty::BoundVariableKind], &'tcx List<ty::BoundVariableKind>>, + >( + self, + iter: I, + ) -> I::Output { + iter.intern_with(|xs| self.intern_bound_variable_kinds(xs)) + } + /// Walks upwards from `id` to find a node which might change lint levels with attributes. /// It stops at `bound` and just returns it if reached. pub fn maybe_lint_level_root_bounded(self, mut id: HirId, bound: HirId) -> HirId { @@ -2653,6 +2672,17 @@ impl<'tcx> TyCtxt<'tcx> { pub fn object_lifetime_defaults(self, id: HirId) -> Option<Vec<ObjectLifetimeDefault>> { self.object_lifetime_defaults_map(id.owner) } + + pub fn late_bound_vars(self, id: HirId) -> &'tcx List<ty::BoundVariableKind> { + self.mk_bound_variable_kinds( + self.late_bound_vars_map(id.owner) + .and_then(|map| map.get(&id.local_id).cloned()) + .unwrap_or_else(|| { + bug!("No bound vars found for {:?} ({:?})", self.hir().node_to_string(id), id) + }) + .iter(), + ) + } } impl TyCtxtAt<'tcx> { diff --git a/compiler/rustc_middle/src/ty/erase_regions.rs b/compiler/rustc_middle/src/ty/erase_regions.rs index 4412ba9408c..79e88662f65 100644 --- a/compiler/rustc_middle/src/ty/erase_regions.rs +++ b/compiler/rustc_middle/src/ty/erase_regions.rs @@ -43,7 +43,7 @@ impl TypeFolder<'tcx> for RegionEraserVisitor<'tcx> { if ty.needs_infer() { ty.super_fold_with(self) } else { self.tcx.erase_regions_ty(ty) } } - fn fold_binder<T>(&mut self, t: ty::Binder<T>) -> ty::Binder<T> + fn fold_binder<T>(&mut self, t: ty::Binder<'tcx, T>) -> ty::Binder<'tcx, T> where T: TypeFoldable<'tcx>, { diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs index f19cc998449..d295b17d902 100644 --- a/compiler/rustc_middle/src/ty/error.rs +++ b/compiler/rustc_middle/src/ty/error.rs @@ -57,7 +57,9 @@ pub enum TypeError<'tcx> { CyclicTy(Ty<'tcx>), CyclicConst(&'tcx ty::Const<'tcx>), ProjectionMismatched(ExpectedFound<DefId>), - ExistentialMismatch(ExpectedFound<&'tcx ty::List<ty::Binder<ty::ExistentialPredicate<'tcx>>>>), + ExistentialMismatch( + ExpectedFound<&'tcx ty::List<ty::Binder<'tcx, ty::ExistentialPredicate<'tcx>>>>, + ), ObjectUnsafeCoercion(DefId), ConstMismatch(ExpectedFound<&'tcx ty::Const<'tcx>>), @@ -509,13 +511,18 @@ impl<T> Trait<T> for X { "consider constraining the associated type `{}` to `{}`", values.found, values.expected, ); - if !self.suggest_constraint( + if !(self.suggest_constraining_opaque_associated_type( + db, + &msg, + proj_ty, + values.expected, + ) || self.suggest_constraint( db, &msg, body_owner_def_id, proj_ty, values.expected, - ) { + )) { db.help(&msg); db.note( "for more information, visit \ @@ -699,20 +706,7 @@ impl<T> Trait<T> for X { } } - if let ty::Opaque(def_id, _) = *proj_ty.self_ty().kind() { - // When the expected `impl Trait` is not defined in the current item, it will come from - // a return type. This can occur when dealing with `TryStream` (#71035). - if self.constrain_associated_type_structured_suggestion( - db, - self.def_span(def_id), - &assoc, - proj_ty.trait_ref_and_own_substs(self).1, - values.found, - &msg, - ) { - return; - } - } + self.suggest_constraining_opaque_associated_type(db, &msg, proj_ty, values.found); if self.point_at_associated_type(db, body_owner_def_id, values.found) { return; @@ -750,6 +744,30 @@ fn foo(&self) -> Self::T { String::new() } } } + /// When the expected `impl Trait` is not defined in the current item, it will come from + /// a return type. This can occur when dealing with `TryStream` (#71035). + fn suggest_constraining_opaque_associated_type( + self, + db: &mut DiagnosticBuilder<'_>, + msg: &str, + proj_ty: &ty::ProjectionTy<'tcx>, + ty: Ty<'tcx>, + ) -> bool { + let assoc = self.associated_item(proj_ty.item_def_id); + if let ty::Opaque(def_id, _) = *proj_ty.self_ty().kind() { + self.constrain_associated_type_structured_suggestion( + db, + self.def_span(def_id), + &assoc, + proj_ty.trait_ref_and_own_substs(self).1, + ty, + &msg, + ) + } else { + false + } + } + fn point_at_methods_that_satisfy_associated_type( self, db: &mut DiagnosticBuilder<'_>, diff --git a/compiler/rustc_middle/src/ty/flags.rs b/compiler/rustc_middle/src/ty/flags.rs index d6dc81c5b78..01bc5cc761c 100644 --- a/compiler/rustc_middle/src/ty/flags.rs +++ b/compiler/rustc_middle/src/ty/flags.rs @@ -22,7 +22,7 @@ impl FlagComputation { result } - pub fn for_predicate(binder: ty::Binder<ty::PredicateKind<'_>>) -> FlagComputation { + pub fn for_predicate(binder: ty::Binder<'tcx, ty::PredicateKind<'_>>) -> FlagComputation { let mut result = FlagComputation::new(); result.add_predicate(binder); result @@ -53,7 +53,7 @@ impl FlagComputation { /// Adds the flags/depth from a set of types that appear within the current type, but within a /// region binder. - fn bound_computation<T, F>(&mut self, value: ty::Binder<T>, f: F) + fn bound_computation<T, F>(&mut self, value: ty::Binder<'_, T>, f: F) where F: FnOnce(&mut Self, T), { @@ -204,7 +204,7 @@ impl FlagComputation { } } - fn add_predicate(&mut self, binder: ty::Binder<ty::PredicateKind<'_>>) { + fn add_predicate(&mut self, binder: ty::Binder<'tcx, ty::PredicateKind<'_>>) { self.bound_computation(binder, |computation, atom| computation.add_predicate_atom(atom)); } diff --git a/compiler/rustc_middle/src/ty/fold.rs b/compiler/rustc_middle/src/ty/fold.rs index a6a1d1f73bb..70f3ac30040 100644 --- a/compiler/rustc_middle/src/ty/fold.rs +++ b/compiler/rustc_middle/src/ty/fold.rs @@ -35,6 +35,7 @@ use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::sso::SsoHashSet; use std::collections::BTreeMap; use std::fmt; use std::ops::ControlFlow; @@ -161,7 +162,7 @@ impl TypeFoldable<'tcx> for hir::Constness { pub trait TypeFolder<'tcx>: Sized { fn tcx<'a>(&'a self) -> TyCtxt<'tcx>; - fn fold_binder<T>(&mut self, t: Binder<T>) -> Binder<T> + fn fold_binder<T>(&mut self, t: Binder<'tcx, T>) -> Binder<'tcx, T> where T: TypeFoldable<'tcx>, { @@ -184,7 +185,10 @@ pub trait TypeFolder<'tcx>: Sized { pub trait TypeVisitor<'tcx>: Sized { type BreakTy = !; - fn visit_binder<T: TypeFoldable<'tcx>>(&mut self, t: &Binder<T>) -> ControlFlow<Self::BreakTy> { + fn visit_binder<T: TypeFoldable<'tcx>>( + &mut self, + t: &Binder<'tcx, T>, + ) -> ControlFlow<Self::BreakTy> { t.super_visit_with(self) } @@ -322,7 +326,7 @@ impl<'tcx> TyCtxt<'tcx> { fn visit_binder<T: TypeFoldable<'tcx>>( &mut self, - t: &Binder<T>, + t: &Binder<'tcx, T>, ) -> ControlFlow<Self::BreakTy> { self.outer_index.shift_in(1); let result = t.as_ref().skip_binder().visit_with(self); @@ -400,7 +404,10 @@ impl<'a, 'tcx> TypeFolder<'tcx> for RegionFolder<'a, 'tcx> { self.tcx } - fn fold_binder<T: TypeFoldable<'tcx>>(&mut self, t: ty::Binder<T>) -> ty::Binder<T> { + fn fold_binder<T: TypeFoldable<'tcx>>( + &mut self, + t: ty::Binder<'tcx, T>, + ) -> ty::Binder<'tcx, T> { self.current_index.shift_in(1); let t = t.super_fold_with(self); self.current_index.shift_out(1); @@ -460,7 +467,10 @@ impl<'a, 'tcx> TypeFolder<'tcx> for BoundVarReplacer<'a, 'tcx> { self.tcx } - fn fold_binder<T: TypeFoldable<'tcx>>(&mut self, t: ty::Binder<T>) -> ty::Binder<T> { + fn fold_binder<T: TypeFoldable<'tcx>>( + &mut self, + t: ty::Binder<'tcx, T>, + ) -> ty::Binder<'tcx, T> { self.current_index.shift_in(1); let t = t.super_fold_with(self); self.current_index.shift_out(1); @@ -538,7 +548,7 @@ impl<'tcx> TyCtxt<'tcx> { /// contain escaping bound types. pub fn replace_late_bound_regions<T, F>( self, - value: Binder<T>, + value: Binder<'tcx, T>, mut fld_r: F, ) -> (T, BTreeMap<ty::BoundRegion, ty::Region<'tcx>>) where @@ -588,7 +598,7 @@ impl<'tcx> TyCtxt<'tcx> { /// types. pub fn replace_bound_vars<T, F, G, H>( self, - value: Binder<T>, + value: Binder<'tcx, T>, mut fld_r: F, fld_t: G, fld_c: H, @@ -607,7 +617,11 @@ impl<'tcx> TyCtxt<'tcx> { /// Replaces any late-bound regions bound in `value` with /// free variants attached to `all_outlive_scope`. - pub fn liberate_late_bound_regions<T>(self, all_outlive_scope: DefId, value: ty::Binder<T>) -> T + pub fn liberate_late_bound_regions<T>( + self, + all_outlive_scope: DefId, + value: ty::Binder<'tcx, T>, + ) -> T where T: TypeFoldable<'tcx>, { @@ -620,13 +634,49 @@ impl<'tcx> TyCtxt<'tcx> { .0 } + pub fn shift_bound_var_indices<T>(self, bound_vars: usize, value: T) -> T + where + T: TypeFoldable<'tcx>, + { + self.replace_escaping_bound_vars( + value, + |r| { + self.mk_region(ty::ReLateBound( + ty::INNERMOST, + ty::BoundRegion { + var: ty::BoundVar::from_usize(r.var.as_usize() + bound_vars), + kind: r.kind, + }, + )) + }, + |t| { + self.mk_ty(ty::Bound( + ty::INNERMOST, + ty::BoundTy { + var: ty::BoundVar::from_usize(t.var.as_usize() + bound_vars), + kind: t.kind, + }, + )) + }, + |c, ty| { + self.mk_const(ty::Const { + val: ty::ConstKind::Bound( + ty::INNERMOST, + ty::BoundVar::from_usize(c.as_usize() + bound_vars), + ), + ty, + }) + }, + ) + } + /// Returns a set of all late-bound regions that are constrained /// by `value`, meaning that if we instantiate those LBR with /// variables and equate `value` with something else, those /// variables will also be equated. pub fn collect_constrained_late_bound_regions<T>( self, - value: &Binder<T>, + value: &Binder<'tcx, T>, ) -> FxHashSet<ty::BoundRegionKind> where T: TypeFoldable<'tcx>, @@ -637,7 +687,7 @@ impl<'tcx> TyCtxt<'tcx> { /// Returns a set of all late-bound regions that appear in `value` anywhere. pub fn collect_referenced_late_bound_regions<T>( self, - value: &Binder<T>, + value: &Binder<'tcx, T>, ) -> FxHashSet<ty::BoundRegionKind> where T: TypeFoldable<'tcx>, @@ -647,7 +697,7 @@ impl<'tcx> TyCtxt<'tcx> { fn collect_late_bound_regions<T>( self, - value: &Binder<T>, + value: &Binder<'tcx, T>, just_constraint: bool, ) -> FxHashSet<ty::BoundRegionKind> where @@ -661,7 +711,7 @@ impl<'tcx> TyCtxt<'tcx> { /// Replaces any late-bound regions bound in `value` with `'erased`. Useful in codegen but also /// method lookup and a few other places where precise region relationships are not required. - pub fn erase_late_bound_regions<T>(self, value: Binder<T>) -> T + pub fn erase_late_bound_regions<T>(self, value: Binder<'tcx, T>) -> T where T: TypeFoldable<'tcx>, { @@ -676,20 +726,205 @@ impl<'tcx> TyCtxt<'tcx> { /// `FnSig`s or `TraitRef`s which are equivalent up to region naming will become /// structurally identical. For example, `for<'a, 'b> fn(&'a isize, &'b isize)` and /// `for<'a, 'b> fn(&'b isize, &'a isize)` will become identical after anonymization. - pub fn anonymize_late_bound_regions<T>(self, sig: Binder<T>) -> Binder<T> + pub fn anonymize_late_bound_regions<T>(self, sig: Binder<'tcx, T>) -> Binder<'tcx, T> where T: TypeFoldable<'tcx>, { let mut counter = 0; - Binder::bind( - self.replace_late_bound_regions(sig, |_| { - let br = ty::BoundRegion { kind: ty::BrAnon(counter) }; + let inner = self + .replace_late_bound_regions(sig, |_| { + let br = ty::BoundRegion { + var: ty::BoundVar::from_u32(counter), + kind: ty::BrAnon(counter), + }; let r = self.mk_region(ty::ReLateBound(ty::INNERMOST, br)); counter += 1; r }) - .0, - ) + .0; + let bound_vars = self.mk_bound_variable_kinds( + (0..counter).map(|i| ty::BoundVariableKind::Region(ty::BrAnon(i))), + ); + Binder::bind_with_vars(inner, bound_vars) + } +} + +pub struct BoundVarsCollector<'tcx> { + binder_index: ty::DebruijnIndex, + vars: BTreeMap<u32, ty::BoundVariableKind>, + // We may encounter the same variable at different levels of binding, so + // this can't just be `Ty` + visited: SsoHashSet<(ty::DebruijnIndex, Ty<'tcx>)>, +} + +impl<'tcx> BoundVarsCollector<'tcx> { + pub fn new() -> Self { + BoundVarsCollector { + binder_index: ty::INNERMOST, + vars: BTreeMap::new(), + visited: SsoHashSet::default(), + } + } + + pub fn into_vars(self, tcx: TyCtxt<'tcx>) -> &'tcx ty::List<ty::BoundVariableKind> { + let max = self.vars.iter().map(|(k, _)| *k).max().unwrap_or_else(|| 0); + for i in 0..max { + if let None = self.vars.get(&i) { + panic!("Unknown variable: {:?}", i); + } + } + + tcx.mk_bound_variable_kinds(self.vars.into_iter().map(|(_, v)| v)) + } +} + +impl<'tcx> TypeVisitor<'tcx> for BoundVarsCollector<'tcx> { + type BreakTy = (); + + fn visit_binder<T: TypeFoldable<'tcx>>( + &mut self, + t: &Binder<'tcx, T>, + ) -> ControlFlow<Self::BreakTy> { + self.binder_index.shift_in(1); + let result = t.super_visit_with(self); + self.binder_index.shift_out(1); + result + } + + fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> { + if t.outer_exclusive_binder < self.binder_index + || !self.visited.insert((self.binder_index, t)) + { + return ControlFlow::CONTINUE; + } + use std::collections::btree_map::Entry; + match *t.kind() { + ty::Bound(debruijn, bound_ty) if debruijn == self.binder_index => { + match self.vars.entry(bound_ty.var.as_u32()) { + Entry::Vacant(entry) => { + entry.insert(ty::BoundVariableKind::Ty(bound_ty.kind)); + } + Entry::Occupied(entry) => match entry.get() { + ty::BoundVariableKind::Ty(_) => {} + _ => bug!("Conflicting bound vars"), + }, + } + } + + _ => (), + }; + + t.super_visit_with(self) + } + + fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> { + match r { + ty::ReLateBound(index, _br) if *index == self.binder_index => { + // If you hit this, you should be using `Binder::bind_with_vars` or `Binder::rebind` + bug!("Trying to collect bound vars with a bound region: {:?} {:?}", index, _br) + } + + _ => (), + }; + + r.super_visit_with(self) + } +} + +pub struct ValidateBoundVars<'tcx> { + bound_vars: &'tcx ty::List<ty::BoundVariableKind>, + binder_index: ty::DebruijnIndex, + // We may encounter the same variable at different levels of binding, so + // this can't just be `Ty` + visited: SsoHashSet<(ty::DebruijnIndex, Ty<'tcx>)>, +} + +impl<'tcx> ValidateBoundVars<'tcx> { + pub fn new(bound_vars: &'tcx ty::List<ty::BoundVariableKind>) -> Self { + ValidateBoundVars { + bound_vars, + binder_index: ty::INNERMOST, + visited: SsoHashSet::default(), + } + } +} + +impl<'tcx> TypeVisitor<'tcx> for ValidateBoundVars<'tcx> { + type BreakTy = (); + + fn visit_binder<T: TypeFoldable<'tcx>>( + &mut self, + t: &Binder<'tcx, T>, + ) -> ControlFlow<Self::BreakTy> { + self.binder_index.shift_in(1); + let result = t.super_visit_with(self); + self.binder_index.shift_out(1); + result + } + + fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> { + if t.outer_exclusive_binder < self.binder_index + || !self.visited.insert((self.binder_index, t)) + { + return ControlFlow::BREAK; + } + match *t.kind() { + ty::Bound(debruijn, bound_ty) if debruijn == self.binder_index => { + if self.bound_vars.len() <= bound_ty.var.as_usize() { + bug!("Not enough bound vars: {:?} not found in {:?}", t, self.bound_vars); + } + let list_var = self.bound_vars[bound_ty.var.as_usize()]; + match list_var { + ty::BoundVariableKind::Ty(kind) => { + if kind != bound_ty.kind { + bug!( + "Mismatched type kinds: {:?} doesn't var in list {:?}", + bound_ty.kind, + list_var + ); + } + } + _ => { + bug!("Mismatched bound variable kinds! Expected type, found {:?}", list_var) + } + } + } + + _ => (), + }; + + t.super_visit_with(self) + } + + fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> { + match r { + ty::ReLateBound(index, br) if *index == self.binder_index => { + if self.bound_vars.len() <= br.var.as_usize() { + bug!("Not enough bound vars: {:?} not found in {:?}", *br, self.bound_vars); + } + let list_var = self.bound_vars[br.var.as_usize()]; + match list_var { + ty::BoundVariableKind::Region(kind) => { + if kind != br.kind { + bug!( + "Mismatched region kinds: {:?} doesn't match var ({:?}) in list ({:?})", + br.kind, + list_var, + self.bound_vars + ); + } + } + _ => bug!( + "Mismatched bound variable kinds! Expected region, found {:?}", + list_var + ), + } + } + + _ => (), + }; + + r.super_visit_with(self) } } @@ -719,7 +954,10 @@ impl TypeFolder<'tcx> for Shifter<'tcx> { self.tcx } - fn fold_binder<T: TypeFoldable<'tcx>>(&mut self, t: ty::Binder<T>) -> ty::Binder<T> { + fn fold_binder<T: TypeFoldable<'tcx>>( + &mut self, + t: ty::Binder<'tcx, T>, + ) -> ty::Binder<'tcx, T> { self.current_index.shift_in(1); let t = t.super_fold_with(self); self.current_index.shift_out(1); @@ -828,7 +1066,10 @@ struct HasEscapingVarsVisitor { impl<'tcx> TypeVisitor<'tcx> for HasEscapingVarsVisitor { type BreakTy = FoundEscapingVars; - fn visit_binder<T: TypeFoldable<'tcx>>(&mut self, t: &Binder<T>) -> ControlFlow<Self::BreakTy> { + fn visit_binder<T: TypeFoldable<'tcx>>( + &mut self, + t: &Binder<'tcx, T>, + ) -> ControlFlow<Self::BreakTy> { self.outer_index.shift_in(1); let result = t.super_visit_with(self); self.outer_index.shift_out(1); @@ -974,7 +1215,10 @@ impl LateBoundRegionsCollector { } impl<'tcx> TypeVisitor<'tcx> for LateBoundRegionsCollector { - fn visit_binder<T: TypeFoldable<'tcx>>(&mut self, t: &Binder<T>) -> ControlFlow<Self::BreakTy> { + fn visit_binder<T: TypeFoldable<'tcx>>( + &mut self, + t: &Binder<'tcx, T>, + ) -> ControlFlow<Self::BreakTy> { self.current_index.shift_in(1); let result = t.super_visit_with(self); self.current_index.shift_out(1); diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index f61b6946985..a753c4ab6ce 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -216,9 +216,10 @@ impl<'tcx> InstanceDef<'tcx> { // drops of `Option::None` before LTO. We also respect the intent of // `#[inline]` on `Drop::drop` implementations. return ty.ty_adt_def().map_or(true, |adt_def| { - adt_def.destructor(tcx).map_or(adt_def.is_enum(), |dtor| { - tcx.codegen_fn_attrs(dtor.did).requests_inline() - }) + adt_def.destructor(tcx).map_or_else( + || adt_def.is_enum(), + |dtor| tcx.codegen_fn_attrs(dtor.did).requests_inline(), + ) }); } tcx.codegen_fn_attrs(self.def_id()).requests_inline() diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index 3a75a6d907d..e7bbdc3cceb 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -1,3 +1,4 @@ +// ignore-tidy-filelength use crate::ich::StableHashingContext; use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags; use crate::mir::{GeneratorLayout, GeneratorSavedLocal}; @@ -1251,13 +1252,13 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { } else { // Try to use a ScalarPair for all tagged enums. let mut common_prim = None; - for (field_layouts, layout_variant) in variants.iter().zip(&layout_variants) { + for (field_layouts, layout_variant) in iter::zip(&variants, &layout_variants) { let offsets = match layout_variant.fields { FieldsShape::Arbitrary { ref offsets, .. } => offsets, _ => bug!(), }; let mut fields = - field_layouts.iter().zip(offsets).filter(|p| !p.0.is_zst()); + iter::zip(field_layouts, offsets).filter(|p| !p.0.is_zst()); let (field, offset) = match (fields.next(), fields.next()) { (None, None) => continue, (Some(pair), None) => pair, @@ -1626,7 +1627,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { const INVALID_FIELD_IDX: u32 = !0; let mut combined_inverse_memory_index = vec![INVALID_FIELD_IDX; promoted_memory_index.len() + memory_index.len()]; - let mut offsets_and_memory_index = offsets.into_iter().zip(memory_index); + let mut offsets_and_memory_index = iter::zip(offsets, memory_index); let combined_offsets = variant_fields .iter() .enumerate() @@ -2481,21 +2482,42 @@ impl<'tcx> ty::Instance<'tcx> { ty::Closure(def_id, substs) => { let sig = substs.as_closure().sig(); - let env_ty = tcx.closure_env_ty(def_id, substs).unwrap(); - sig.map_bound(|sig| { + let bound_vars = tcx.mk_bound_variable_kinds( + sig.bound_vars() + .iter() + .chain(iter::once(ty::BoundVariableKind::Region(ty::BrEnv))), + ); + let br = ty::BoundRegion { + var: ty::BoundVar::from_usize(bound_vars.len() - 1), + kind: ty::BoundRegionKind::BrEnv, + }; + let env_region = ty::ReLateBound(ty::INNERMOST, br); + let env_ty = tcx.closure_env_ty(def_id, substs, env_region).unwrap(); + + let sig = sig.skip_binder(); + ty::Binder::bind_with_vars( tcx.mk_fn_sig( - iter::once(env_ty.skip_binder()).chain(sig.inputs().iter().cloned()), + iter::once(env_ty).chain(sig.inputs().iter().cloned()), sig.output(), sig.c_variadic, sig.unsafety, sig.abi, - ) - }) + ), + bound_vars, + ) } ty::Generator(_, substs, _) => { let sig = substs.as_generator().poly_sig(); - let br = ty::BoundRegion { kind: ty::BrEnv }; + let bound_vars = tcx.mk_bound_variable_kinds( + sig.bound_vars() + .iter() + .chain(iter::once(ty::BoundVariableKind::Region(ty::BrEnv))), + ); + let br = ty::BoundRegion { + var: ty::BoundVar::from_usize(bound_vars.len() - 1), + kind: ty::BoundRegionKind::BrEnv, + }; let env_region = ty::ReLateBound(ty::INNERMOST, br); let env_ty = tcx.mk_mut_ref(tcx.mk_region(env_region), ty); @@ -2504,21 +2526,21 @@ impl<'tcx> ty::Instance<'tcx> { let pin_substs = tcx.intern_substs(&[env_ty.into()]); let env_ty = tcx.mk_adt(pin_adt_ref, pin_substs); - sig.map_bound(|sig| { - let state_did = tcx.require_lang_item(LangItem::GeneratorState, None); - let state_adt_ref = tcx.adt_def(state_did); - let state_substs = - tcx.intern_substs(&[sig.yield_ty.into(), sig.return_ty.into()]); - let ret_ty = tcx.mk_adt(state_adt_ref, state_substs); - + let sig = sig.skip_binder(); + let state_did = tcx.require_lang_item(LangItem::GeneratorState, None); + let state_adt_ref = tcx.adt_def(state_did); + let state_substs = tcx.intern_substs(&[sig.yield_ty.into(), sig.return_ty.into()]); + let ret_ty = tcx.mk_adt(state_adt_ref, state_substs); + ty::Binder::bind_with_vars( tcx.mk_fn_sig( [env_ty, sig.resume_ty].iter(), &ret_ty, false, hir::Unsafety::Normal, rustc_target::spec::abi::Abi::Rust, - ) - }) + ), + bound_vars, + ) } _ => bug!("unexpected type {:?} in Instance::fn_sig", ty), } diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index ed10a156622..6574c938260 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -67,12 +67,12 @@ pub use self::sty::BoundRegionKind::*; pub use self::sty::RegionKind::*; pub use self::sty::TyKind::*; pub use self::sty::{ - Binder, BoundRegion, BoundRegionKind, BoundTy, BoundTyKind, BoundVar, CanonicalPolyFnSig, - ClosureSubsts, ClosureSubstsParts, ConstVid, EarlyBoundRegion, ExistentialPredicate, - ExistentialProjection, ExistentialTraitRef, FnSig, FreeRegion, GenSig, GeneratorSubsts, - GeneratorSubstsParts, ParamConst, ParamTy, PolyExistentialProjection, PolyExistentialTraitRef, - PolyFnSig, PolyGenSig, PolyTraitRef, ProjectionTy, Region, RegionKind, RegionVid, TraitRef, - TyKind, TypeAndMut, UpvarSubsts, + Binder, BoundRegion, BoundRegionKind, BoundTy, BoundTyKind, BoundVar, BoundVariableKind, + CanonicalPolyFnSig, ClosureSubsts, ClosureSubstsParts, ConstVid, EarlyBoundRegion, + ExistentialPredicate, ExistentialProjection, ExistentialTraitRef, FnSig, FreeRegion, GenSig, + GeneratorSubsts, GeneratorSubstsParts, ParamConst, ParamTy, PolyExistentialProjection, + PolyExistentialTraitRef, PolyFnSig, PolyGenSig, PolyTraitRef, ProjectionTy, Region, RegionKind, + RegionVid, TraitRef, TyKind, TypeAndMut, UpvarSubsts, }; pub use self::trait_def::TraitDef; @@ -302,7 +302,7 @@ impl<'tcx> TyS<'tcx> { // `TyS` is used a lot. Make sure it doesn't unintentionally get bigger. #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] -static_assert_size!(TyS<'_>, 32); +static_assert_size!(TyS<'_>, 40); impl<'tcx> Ord for TyS<'tcx> { fn cmp(&self, other: &TyS<'tcx>) -> Ordering { @@ -359,14 +359,14 @@ impl ty::EarlyBoundRegion { #[derive(Debug)] crate struct PredicateInner<'tcx> { - kind: Binder<PredicateKind<'tcx>>, + kind: Binder<'tcx, PredicateKind<'tcx>>, flags: TypeFlags, /// See the comment for the corresponding field of [TyS]. outer_exclusive_binder: ty::DebruijnIndex, } #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] -static_assert_size!(PredicateInner<'_>, 40); +static_assert_size!(PredicateInner<'_>, 48); #[derive(Clone, Copy, Lift)] pub struct Predicate<'tcx> { @@ -389,9 +389,9 @@ impl Hash for Predicate<'_> { impl<'tcx> Eq for Predicate<'tcx> {} impl<'tcx> Predicate<'tcx> { - /// Gets the inner `Binder<PredicateKind<'tcx>>`. + /// Gets the inner `Binder<'tcx, PredicateKind<'tcx>>`. #[inline] - pub fn kind(self) -> Binder<PredicateKind<'tcx>> { + pub fn kind(self) -> Binder<'tcx, PredicateKind<'tcx>> { self.inner.kind } } @@ -543,10 +543,33 @@ impl<'tcx> Predicate<'tcx> { // substitution code expects equal binding levels in the values // from the substitution and the value being substituted into, and // this trick achieves that). - let substs = trait_ref.skip_binder().substs; - let pred = self.kind().skip_binder(); - let new = pred.subst(tcx, substs); - tcx.reuse_or_mk_predicate(self, ty::Binder::bind(new)) + + // Working through the second example: + // trait_ref: for<'x> T: Foo1<'^0.0>; substs: [T, '^0.0] + // predicate: for<'b> Self: Bar1<'a, '^0.0>; substs: [Self, 'a, '^0.0] + // We want to end up with: + // for<'x, 'b> T: Bar1<'^0.0, '^0.1> + // To do this: + // 1) We must shift all bound vars in predicate by the length + // of trait ref's bound vars. So, we would end up with predicate like + // Self: Bar1<'a, '^0.1> + // 2) We can then apply the trait substs to this, ending up with + // T: Bar1<'^0.0, '^0.1> + // 3) Finally, to create the final bound vars, we concatenate the bound + // vars of the trait ref with those of the predicate: + // ['x, 'b] + let bound_pred = self.kind(); + let pred_bound_vars = bound_pred.bound_vars(); + let trait_bound_vars = trait_ref.bound_vars(); + // 1) Self: Bar1<'a, '^0.0> -> Self: Bar1<'a, '^0.1> + let shifted_pred = + tcx.shift_bound_var_indices(trait_bound_vars.len(), bound_pred.skip_binder()); + // 2) Self: Bar1<'a, '^0.1> -> T: Bar1<'^0.0, '^0.1> + let new = shifted_pred.subst(tcx, trait_ref.skip_binder().substs); + // 3) ['x] + ['b] -> ['x, 'b] + let bound_vars = + tcx.mk_bound_variable_kinds(trait_bound_vars.iter().chain(pred_bound_vars)); + tcx.reuse_or_mk_predicate(self, ty::Binder::bind_with_vars(new, bound_vars)) } } @@ -556,7 +579,7 @@ pub struct TraitPredicate<'tcx> { pub trait_ref: TraitRef<'tcx>, } -pub type PolyTraitPredicate<'tcx> = ty::Binder<TraitPredicate<'tcx>>; +pub type PolyTraitPredicate<'tcx> = ty::Binder<'tcx, TraitPredicate<'tcx>>; impl<'tcx> TraitPredicate<'tcx> { pub fn def_id(self) -> DefId { @@ -574,7 +597,7 @@ impl<'tcx> PolyTraitPredicate<'tcx> { self.skip_binder().def_id() } - pub fn self_ty(self) -> ty::Binder<Ty<'tcx>> { + pub fn self_ty(self) -> ty::Binder<'tcx, Ty<'tcx>> { self.map_bound(|trait_ref| trait_ref.self_ty()) } } @@ -584,8 +607,8 @@ impl<'tcx> PolyTraitPredicate<'tcx> { pub struct OutlivesPredicate<A, B>(pub A, pub B); // `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>>; -pub type PolyTypeOutlivesPredicate<'tcx> = ty::Binder<TypeOutlivesPredicate<'tcx>>; +pub type PolyRegionOutlivesPredicate<'tcx> = ty::Binder<'tcx, RegionOutlivesPredicate<'tcx>>; +pub type PolyTypeOutlivesPredicate<'tcx> = ty::Binder<'tcx, TypeOutlivesPredicate<'tcx>>; #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, TyEncodable, TyDecodable)] #[derive(HashStable, TypeFoldable)] @@ -594,7 +617,7 @@ pub struct SubtypePredicate<'tcx> { pub a: Ty<'tcx>, pub b: Ty<'tcx>, } -pub type PolySubtypePredicate<'tcx> = ty::Binder<SubtypePredicate<'tcx>>; +pub type PolySubtypePredicate<'tcx> = ty::Binder<'tcx, SubtypePredicate<'tcx>>; /// This kind of predicate has no *direct* correspondent in the /// syntax, but it roughly corresponds to the syntactic forms: @@ -615,25 +638,15 @@ pub struct ProjectionPredicate<'tcx> { pub ty: Ty<'tcx>, } -pub type PolyProjectionPredicate<'tcx> = Binder<ProjectionPredicate<'tcx>>; +pub type PolyProjectionPredicate<'tcx> = Binder<'tcx, ProjectionPredicate<'tcx>>; impl<'tcx> PolyProjectionPredicate<'tcx> { - /// Returns the `DefId` of the associated item being projected. - pub fn item_def_id(&self) -> DefId { - self.skip_binder().projection_ty.item_def_id - } - /// Returns the `DefId` of the trait of the associated item being projected. #[inline] pub fn trait_def_id(&self, tcx: TyCtxt<'tcx>) -> DefId { self.skip_binder().projection_ty.trait_def_id(tcx) } - #[inline] - pub fn projection_self_ty(&self) -> Binder<Ty<'tcx>> { - self.map_bound(|predicate| predicate.projection_ty.self_ty()) - } - /// Get the [PolyTraitRef] required for this projection to be well formed. /// Note that for generic associated types the predicates of the associated /// type also need to be checked. @@ -647,7 +660,7 @@ impl<'tcx> PolyProjectionPredicate<'tcx> { self.map_bound(|predicate| predicate.projection_ty.trait_ref(tcx)) } - pub fn ty(&self) -> Binder<Ty<'tcx>> { + pub fn ty(&self) -> Binder<'tcx, Ty<'tcx>> { self.map_bound(|predicate| predicate.ty) } @@ -681,7 +694,7 @@ pub trait ToPredicate<'tcx> { fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx>; } -impl ToPredicate<'tcx> for Binder<PredicateKind<'tcx>> { +impl ToPredicate<'tcx> for Binder<'tcx, PredicateKind<'tcx>> { #[inline(always)] fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { tcx.mk_predicate(self) @@ -704,11 +717,11 @@ impl<'tcx> ToPredicate<'tcx> for ConstnessAnd<TraitRef<'tcx>> { impl<'tcx> ToPredicate<'tcx> for ConstnessAnd<PolyTraitRef<'tcx>> { fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { - ConstnessAnd { - value: self.value.map_bound(|trait_ref| ty::TraitPredicate { trait_ref }), - constness: self.constness, - } - .to_predicate(tcx) + self.value + .map_bound(|trait_ref| { + PredicateKind::Trait(ty::TraitPredicate { trait_ref }, self.constness) + }) + .to_predicate(tcx) } } @@ -1039,10 +1052,6 @@ impl WithOptConstParam<DefId> { None } - pub fn expect_local(self) -> WithOptConstParam<LocalDefId> { - self.as_local().unwrap() - } - pub fn is_local(self) -> bool { self.did.is_local() } diff --git a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs index 9d97815a5f1..3b0cb8d4215 100644 --- a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs +++ b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs @@ -38,7 +38,7 @@ impl<'tcx> TyCtxt<'tcx> { } } - /// If you have a `Binder<T>`, you can do this to strip out the + /// If you have a `Binder<'tcx, T>`, you can do this to strip out the /// late-bound regions and then normalize the result, yielding up /// a `T` (with regions erased). This is appropriate when the /// binder is being instantiated at the call site. @@ -49,7 +49,7 @@ impl<'tcx> TyCtxt<'tcx> { pub fn normalize_erasing_late_bound_regions<T>( self, param_env: ty::ParamEnv<'tcx>, - value: ty::Binder<T>, + value: ty::Binder<'tcx, T>, ) -> T where T: TypeFoldable<'tcx>, diff --git a/compiler/rustc_middle/src/ty/print/mod.rs b/compiler/rustc_middle/src/ty/print/mod.rs index a47846828bd..13e2122a619 100644 --- a/compiler/rustc_middle/src/ty/print/mod.rs +++ b/compiler/rustc_middle/src/ty/print/mod.rs @@ -63,7 +63,7 @@ pub trait Printer<'tcx>: Sized { fn print_dyn_existential( self, - predicates: &'tcx ty::List<ty::Binder<ty::ExistentialPredicate<'tcx>>>, + predicates: &'tcx ty::List<ty::Binder<'tcx, ty::ExistentialPredicate<'tcx>>>, ) -> Result<Self::DynExistential, Self::Error>; fn print_const(self, ct: &'tcx ty::Const<'tcx>) -> Result<Self::Const, Self::Error>; @@ -346,7 +346,7 @@ impl<'tcx, P: Printer<'tcx>> Print<'tcx, P> for Ty<'tcx> { } impl<'tcx, P: Printer<'tcx>> Print<'tcx, P> - for &'tcx ty::List<ty::Binder<ty::ExistentialPredicate<'tcx>>> + for &'tcx ty::List<ty::Binder<'tcx, ty::ExistentialPredicate<'tcx>>> { type Output = P::DynExistential; type Error = P::Error; diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 3b72cc011d6..b8f39fce21d 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -19,6 +19,7 @@ use std::char; use std::collections::BTreeMap; use std::convert::TryFrom; use std::fmt::{self, Write as _}; +use std::iter; use std::ops::{ControlFlow, Deref, DerefMut}; // `pretty` is a separate module only for organization. @@ -201,7 +202,7 @@ pub trait PrettyPrinter<'tcx>: self.print_def_path(def_id, substs) } - fn in_binder<T>(self, value: &ty::Binder<T>) -> Result<Self, Self::Error> + fn in_binder<T>(self, value: &ty::Binder<'tcx, T>) -> Result<Self, Self::Error> where T: Print<'tcx, Self, Output = Self, Error = Self::Error> + TypeFoldable<'tcx>, { @@ -210,7 +211,7 @@ pub trait PrettyPrinter<'tcx>: fn wrap_binder<T, F: Fn(&T, Self) -> Result<Self, fmt::Error>>( self, - value: &ty::Binder<T>, + value: &ty::Binder<'tcx, T>, f: F, ) -> Result<Self, Self::Error> where @@ -764,7 +765,7 @@ pub trait PrettyPrinter<'tcx>: fn pretty_print_dyn_existential( mut self, - predicates: &'tcx ty::List<ty::Binder<ty::ExistentialPredicate<'tcx>>>, + predicates: &'tcx ty::List<ty::Binder<'tcx, ty::ExistentialPredicate<'tcx>>>, ) -> Result<Self::DynExistential, Self::Error> { // Generate the main trait ref, including associated types. let mut first = true; @@ -1223,7 +1224,7 @@ pub trait PrettyPrinter<'tcx>: CtorKind::Fictive => { p!(" {{ "); let mut first = true; - for (field_def, field) in variant_def.fields.iter().zip(fields) { + for (field_def, field) in iter::zip(&variant_def.fields, fields) { if !first { p!(", "); } @@ -1431,7 +1432,7 @@ impl<F: fmt::Write> Printer<'tcx> for FmtPrinter<'_, 'tcx, F> { fn print_dyn_existential( self, - predicates: &'tcx ty::List<ty::Binder<ty::ExistentialPredicate<'tcx>>>, + predicates: &'tcx ty::List<ty::Binder<'tcx, ty::ExistentialPredicate<'tcx>>>, ) -> Result<Self::DynExistential, Self::Error> { self.pretty_print_dyn_existential(predicates) } @@ -1570,7 +1571,7 @@ impl<F: fmt::Write> PrettyPrinter<'tcx> for FmtPrinter<'_, 'tcx, F> { Ok(self) } - fn in_binder<T>(self, value: &ty::Binder<T>) -> Result<Self, Self::Error> + fn in_binder<T>(self, value: &ty::Binder<'tcx, T>) -> Result<Self, Self::Error> where T: Print<'tcx, Self, Output = Self, Error = Self::Error> + TypeFoldable<'tcx>, { @@ -1579,7 +1580,7 @@ impl<F: fmt::Write> PrettyPrinter<'tcx> for FmtPrinter<'_, 'tcx, F> { fn wrap_binder<T, C: Fn(&T, Self) -> Result<Self, Self::Error>>( self, - value: &ty::Binder<T>, + value: &ty::Binder<'tcx, T>, f: C, ) -> Result<Self, Self::Error> where @@ -1635,7 +1636,7 @@ impl<F: fmt::Write> PrettyPrinter<'tcx> for FmtPrinter<'_, 'tcx, F> { data.name != kw::Empty && data.name != kw::UnderscoreLifetime } - ty::ReLateBound(_, ty::BoundRegion { kind: br }) + ty::ReLateBound(_, ty::BoundRegion { kind: br, .. }) | ty::ReFree(ty::FreeRegion { bound_region: br, .. }) | ty::RePlaceholder(ty::Placeholder { name: br, .. }) => { if let ty::BrNamed(_, name) = br { @@ -1714,7 +1715,7 @@ impl<F: fmt::Write> FmtPrinter<'_, '_, F> { return Ok(self); } } - ty::ReLateBound(_, ty::BoundRegion { kind: br }) + ty::ReLateBound(_, ty::BoundRegion { kind: br, .. }) | ty::ReFree(ty::FreeRegion { bound_region: br, .. }) | ty::RePlaceholder(ty::Placeholder { name: br, .. }) => { if let ty::BrNamed(_, name) = br { @@ -1762,7 +1763,7 @@ impl<F: fmt::Write> FmtPrinter<'_, '_, F> { impl<F: fmt::Write> FmtPrinter<'_, 'tcx, F> { pub fn name_all_regions<T>( mut self, - value: &ty::Binder<T>, + value: &ty::Binder<'tcx, T>, ) -> Result<(Self, (T, BTreeMap<ty::BoundRegion, ty::Region<'tcx>>)), fmt::Error> where T: Print<'tcx, Self, Output = Self, Error = fmt::Error> + TypeFoldable<'tcx>, @@ -1820,7 +1821,8 @@ impl<F: fmt::Write> FmtPrinter<'_, 'tcx, F> { ty::BrNamed(DefId::local(CRATE_DEF_INDEX), name) } }; - self.tcx.mk_region(ty::ReLateBound(ty::INNERMOST, ty::BoundRegion { kind })) + self.tcx + .mk_region(ty::ReLateBound(ty::INNERMOST, ty::BoundRegion { var: br.var, kind })) }); start_or_continue(&mut self, "", "> ")?; @@ -1829,7 +1831,7 @@ impl<F: fmt::Write> FmtPrinter<'_, 'tcx, F> { Ok((self, new_value)) } - pub fn pretty_in_binder<T>(self, value: &ty::Binder<T>) -> Result<Self, fmt::Error> + pub fn pretty_in_binder<T>(self, value: &ty::Binder<'tcx, T>) -> Result<Self, fmt::Error> where T: Print<'tcx, Self, Output = Self, Error = fmt::Error> + TypeFoldable<'tcx>, { @@ -1843,7 +1845,7 @@ impl<F: fmt::Write> FmtPrinter<'_, 'tcx, F> { pub fn pretty_wrap_binder<T, C: Fn(&T, Self) -> Result<Self, fmt::Error>>( self, - value: &ty::Binder<T>, + value: &ty::Binder<'tcx, T>, f: C, ) -> Result<Self, fmt::Error> where @@ -1857,14 +1859,14 @@ impl<F: fmt::Write> FmtPrinter<'_, 'tcx, F> { Ok(inner) } - fn prepare_late_bound_region_info<T>(&mut self, value: &ty::Binder<T>) + fn prepare_late_bound_region_info<T>(&mut self, value: &ty::Binder<'tcx, T>) where T: TypeFoldable<'tcx>, { struct LateBoundRegionNameCollector<'a>(&'a mut FxHashSet<Symbol>); impl<'tcx> ty::fold::TypeVisitor<'tcx> for LateBoundRegionNameCollector<'_> { fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> { - if let ty::ReLateBound(_, ty::BoundRegion { kind: ty::BrNamed(_, name) }) = *r { + if let ty::ReLateBound(_, ty::BoundRegion { kind: ty::BrNamed(_, name), .. }) = *r { self.0.insert(name); } r.super_visit_with(self) @@ -1878,7 +1880,7 @@ impl<F: fmt::Write> FmtPrinter<'_, 'tcx, F> { } } -impl<'tcx, T, P: PrettyPrinter<'tcx>> Print<'tcx, P> for ty::Binder<T> +impl<'tcx, T, P: PrettyPrinter<'tcx>> Print<'tcx, P> for ty::Binder<'tcx, T> where T: Print<'tcx, P, Output = P, Error = P::Error> + TypeFoldable<'tcx>, { @@ -1965,28 +1967,28 @@ impl ty::TraitRef<'tcx> { } } -impl ty::Binder<ty::TraitRef<'tcx>> { - pub fn print_only_trait_path(self) -> ty::Binder<TraitRefPrintOnlyTraitPath<'tcx>> { +impl ty::Binder<'tcx, ty::TraitRef<'tcx>> { + pub fn print_only_trait_path(self) -> ty::Binder<'tcx, TraitRefPrintOnlyTraitPath<'tcx>> { self.map_bound(|tr| tr.print_only_trait_path()) } } forward_display_to_print! { Ty<'tcx>, - &'tcx ty::List<ty::Binder<ty::ExistentialPredicate<'tcx>>>, + &'tcx ty::List<ty::Binder<'tcx, ty::ExistentialPredicate<'tcx>>>, &'tcx ty::Const<'tcx>, // HACK(eddyb) these are exhaustive instead of generic, // because `for<'tcx>` isn't possible yet. - ty::Binder<ty::ExistentialPredicate<'tcx>>, - ty::Binder<ty::TraitRef<'tcx>>, - ty::Binder<TraitRefPrintOnlyTraitPath<'tcx>>, - ty::Binder<ty::FnSig<'tcx>>, - ty::Binder<ty::TraitPredicate<'tcx>>, - ty::Binder<ty::SubtypePredicate<'tcx>>, - ty::Binder<ty::ProjectionPredicate<'tcx>>, - ty::Binder<ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>>, - ty::Binder<ty::OutlivesPredicate<ty::Region<'tcx>, ty::Region<'tcx>>>, + ty::Binder<'tcx, ty::ExistentialPredicate<'tcx>>, + ty::Binder<'tcx, ty::TraitRef<'tcx>>, + ty::Binder<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>, + ty::Binder<'tcx, ty::FnSig<'tcx>>, + ty::Binder<'tcx, ty::TraitPredicate<'tcx>>, + ty::Binder<'tcx, ty::SubtypePredicate<'tcx>>, + ty::Binder<'tcx, ty::ProjectionPredicate<'tcx>>, + ty::Binder<'tcx, ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>>, + ty::Binder<'tcx, ty::OutlivesPredicate<ty::Region<'tcx>, ty::Region<'tcx>>>, ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>, ty::OutlivesPredicate<ty::Region<'tcx>, ty::Region<'tcx>> 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 ff11314d2ff..416199b3840 100644 --- a/compiler/rustc_middle/src/ty/query/on_disk_cache.rs +++ b/compiler/rustc_middle/src/ty/query/on_disk_cache.rs @@ -525,7 +525,7 @@ impl<'sess> OnDiskCache<'sess> { ) { let mut current_diagnostics = self.current_diagnostics.borrow_mut(); - let x = current_diagnostics.entry(dep_node_index).or_insert(Vec::new()); + let x = current_diagnostics.entry(dep_node_index).or_default(); x.extend(Into::<Vec<_>>::into(diagnostics)); } diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs index c936c30f456..ca60339da0d 100644 --- a/compiler/rustc_middle/src/ty/relate.rs +++ b/compiler/rustc_middle/src/ty/relate.rs @@ -33,15 +33,6 @@ pub trait TypeRelation<'tcx>: Sized { /// relation. Just affects error messages. fn a_is_expected(&self) -> bool; - /// Whether we should look into the substs of unevaluated constants - /// even if `feature(const_evaluatable_checked)` is active. - /// - /// This is needed in `combine` to prevent accidentially creating - /// infinite types as we abuse `TypeRelation` to walk a type there. - fn visit_ct_substs(&self) -> bool { - false - } - fn with_cause<F, R>(&mut self, _cause: Cause, f: F) -> R where F: FnOnce(&mut Self) -> R, @@ -102,9 +93,9 @@ pub trait TypeRelation<'tcx>: Sized { fn binders<T>( &mut self, - a: ty::Binder<T>, - b: ty::Binder<T>, - ) -> RelateResult<'tcx, ty::Binder<T>> + a: ty::Binder<'tcx, T>, + b: ty::Binder<'tcx, T>, + ) -> RelateResult<'tcx, ty::Binder<'tcx, T>> where T: Relate<'tcx>; } @@ -149,7 +140,7 @@ pub fn relate_substs<R: TypeRelation<'tcx>>( ) -> RelateResult<'tcx, SubstsRef<'tcx>> { let tcx = relation.tcx(); - let params = a_subst.iter().zip(b_subst).enumerate().map(|(i, (a, b))| { + let params = iter::zip(a_subst, b_subst).enumerate().map(|(i, (a, b))| { let variance = variances.map_or(ty::Invariant, |v| v[i]); relation.relate_with_variance(variance, a, b) }); @@ -179,12 +170,8 @@ impl<'tcx> Relate<'tcx> for ty::FnSig<'tcx> { return Err(TypeError::ArgCount); } - let inputs_and_output = a - .inputs() - .iter() - .cloned() - .zip(b.inputs().iter().cloned()) - .map(|x| (x, false)) + let inputs_and_output = iter::zip(a.inputs(), b.inputs()) + .map(|(&a, &b)| ((a, b), false)) .chain(iter::once(((a.output(), b.output()), true))) .map(|((a, b), is_output)| { if is_output { @@ -308,7 +295,7 @@ impl<'tcx> Relate<'tcx> for GeneratorWitness<'tcx> { ) -> RelateResult<'tcx, GeneratorWitness<'tcx>> { assert_eq!(a.0.len(), b.0.len()); let tcx = relation.tcx(); - let types = tcx.mk_type_list(a.0.iter().zip(b.0).map(|(a, b)| relation.relate(a, b)))?; + let types = tcx.mk_type_list(iter::zip(a.0, b.0).map(|(a, b)| relation.relate(a, b)))?; Ok(GeneratorWitness(types)) } } @@ -432,9 +419,9 @@ pub fn super_relate_tys<R: TypeRelation<'tcx>>( let sz_a = sz_a.try_eval_usize(tcx, relation.param_env()); let sz_b = sz_b.try_eval_usize(tcx, relation.param_env()); match (sz_a, sz_b) { - (Some(sz_a_val), Some(sz_b_val)) => Err(TypeError::FixedArraySize( - expected_found(relation, sz_a_val, sz_b_val), - )), + (Some(sz_a_val), Some(sz_b_val)) if sz_a_val != sz_b_val => Err( + TypeError::FixedArraySize(expected_found(relation, sz_a_val, sz_b_val)), + ), _ => Err(err), } } @@ -449,7 +436,7 @@ pub fn super_relate_tys<R: TypeRelation<'tcx>>( (&ty::Tuple(as_), &ty::Tuple(bs)) => { if as_.len() == bs.len() { Ok(tcx.mk_tup( - as_.iter().zip(bs).map(|(a, b)| relation.relate(a.expect_ty(), b.expect_ty())), + iter::zip(as_, bs).map(|(a, b)| relation.relate(a.expect_ty(), b.expect_ty())), )?) } else if !(as_.is_empty() || bs.is_empty()) { Err(TypeError::TupleSize(expected_found(relation, as_.len(), bs.len()))) @@ -532,7 +519,7 @@ pub fn super_relate_consts<R: TypeRelation<'tcx>>( } (ty::ConstKind::Unevaluated(au), ty::ConstKind::Unevaluated(bu)) - if tcx.features().const_evaluatable_checked && !relation.visit_ct_substs() => + if tcx.features().const_evaluatable_checked => { tcx.try_unify_abstract_consts(((au.def, au.substs), (bu.def, bu.substs))) } @@ -593,9 +580,7 @@ fn check_const_value_eq<R: TypeRelation<'tcx>>( // Both the variant and each field have to be equal. if a_destructured.variant == b_destructured.variant { - for (a_field, b_field) in - a_destructured.fields.iter().zip(b_destructured.fields.iter()) - { + for (a_field, b_field) in iter::zip(a_destructured.fields, b_destructured.fields) { relation.consts(a_field, b_field)?; } @@ -609,7 +594,7 @@ fn check_const_value_eq<R: TypeRelation<'tcx>>( }) } -impl<'tcx> Relate<'tcx> for &'tcx ty::List<ty::Binder<ty::ExistentialPredicate<'tcx>>> { +impl<'tcx> Relate<'tcx> for &'tcx ty::List<ty::Binder<'tcx, ty::ExistentialPredicate<'tcx>>> { fn relate<R: TypeRelation<'tcx>>( relation: &mut R, a: Self, @@ -631,13 +616,12 @@ impl<'tcx> Relate<'tcx> for &'tcx ty::List<ty::Binder<ty::ExistentialPredicate<' return Err(TypeError::ExistentialMismatch(expected_found(relation, a, b))); } - let v = a_v.into_iter().zip(b_v.into_iter()).map(|(ep_a, ep_b)| { + let v = iter::zip(a_v, b_v).map(|(ep_a, ep_b)| { use crate::ty::ExistentialPredicate::*; match (ep_a.skip_binder(), ep_b.skip_binder()) { - (Trait(a), Trait(b)) => Ok(ty::Binder::bind(Trait( - relation.relate(ep_a.rebind(a), ep_b.rebind(b))?.skip_binder(), - ))), - (Projection(a), Projection(b)) => Ok(ty::Binder::bind(Projection( + (Trait(a), Trait(b)) => Ok(ep_a + .rebind(Trait(relation.relate(ep_a.rebind(a), ep_b.rebind(b))?.skip_binder()))), + (Projection(a), Projection(b)) => Ok(ep_a.rebind(Projection( relation.relate(ep_a.rebind(a), ep_b.rebind(b))?.skip_binder(), ))), (AutoTrait(a), AutoTrait(b)) if a == b => Ok(ep_a.rebind(AutoTrait(a))), @@ -700,12 +684,12 @@ impl<'tcx> Relate<'tcx> for &'tcx ty::Const<'tcx> { } } -impl<'tcx, T: Relate<'tcx>> Relate<'tcx> for ty::Binder<T> { +impl<'tcx, T: Relate<'tcx>> Relate<'tcx> for ty::Binder<'tcx, T> { fn relate<R: TypeRelation<'tcx>>( relation: &mut R, - a: ty::Binder<T>, - b: ty::Binder<T>, - ) -> RelateResult<'tcx, ty::Binder<T>> { + a: ty::Binder<'tcx, T>, + b: ty::Binder<'tcx, T>, + ) -> RelateResult<'tcx, ty::Binder<'tcx, T>> { relation.binders(a, b) } } diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index 2da23b331e0..a969626b370 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -454,10 +454,16 @@ impl<'a, 'tcx> Lift<'tcx> for ty::PredicateKind<'a> { } } -impl<'tcx, T: Lift<'tcx>> Lift<'tcx> for ty::Binder<T> { - type Lifted = ty::Binder<T::Lifted>; +impl<'a, 'tcx, T: Lift<'tcx>> Lift<'tcx> for ty::Binder<'a, T> +where + <T as Lift<'tcx>>::Lifted: TypeFoldable<'tcx>, +{ + type Lifted = ty::Binder<'tcx, T::Lifted>; fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> { - self.map_bound(|v| tcx.lift(v)).transpose() + let bound_vars = tcx.lift(self.bound_vars()); + tcx.lift(self.skip_binder()) + .zip(bound_vars) + .map(|(value, vars)| ty::Binder::bind_with_vars(value, vars)) } } @@ -749,7 +755,7 @@ impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Box<[T]> { } } -impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for ty::Binder<T> { +impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for ty::Binder<'tcx, T> { fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self { self.map_bound(|ty| ty.fold_with(folder)) } @@ -767,7 +773,7 @@ impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for ty::Binder<T> { } } -impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<ty::Binder<ty::ExistentialPredicate<'tcx>>> { +impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<ty::Binder<'tcx, ty::ExistentialPredicate<'tcx>>> { fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self { ty::util::fold_list(self, folder, |tcx, v| tcx.intern_poly_existential_predicates(v)) } diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index e78e928398f..e352d0bc756 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -5,6 +5,8 @@ use self::TyKind::*; use crate::infer::canonical::Canonical; +use crate::ty::fold::BoundVarsCollector; +use crate::ty::fold::ValidateBoundVars; use crate::ty::subst::{GenericArg, InternalSubsts, Subst, SubstsRef}; use crate::ty::InferTy::{self, *}; use crate::ty::{ @@ -62,22 +64,10 @@ pub enum BoundRegionKind { #[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable, Debug, PartialOrd, Ord)] #[derive(HashStable)] pub struct BoundRegion { + pub var: BoundVar, pub kind: BoundRegionKind, } -impl BoundRegion { - /// When canonicalizing, we replace unbound inference variables and free - /// regions with anonymous late bound regions. This method asserts that - /// we have an anonymous late bound region, which hence may refer to - /// a canonical variable. - pub fn assert_bound_var(&self) -> BoundVar { - match self.kind { - BoundRegionKind::BrAnon(var) => BoundVar::from_u32(var), - _ => bug!("bound region is not anonymous"), - } - } -} - impl BoundRegionKind { pub fn is_named(&self) -> bool { match *self { @@ -161,7 +151,7 @@ pub enum TyKind<'tcx> { FnPtr(PolyFnSig<'tcx>), /// A trait object. Written as `dyn for<'b> Trait<'b, Assoc = u32> + Send + 'a`. - Dynamic(&'tcx List<Binder<ExistentialPredicate<'tcx>>>, ty::Region<'tcx>), + Dynamic(&'tcx List<Binder<'tcx, ExistentialPredicate<'tcx>>>, ty::Region<'tcx>), /// The anonymous type of a closure. Used to represent the type of /// `|a| a`. @@ -173,7 +163,7 @@ pub enum TyKind<'tcx> { /// A type representing the types stored inside a generator. /// This should only appear in GeneratorInteriors. - GeneratorWitness(Binder<&'tcx List<Ty<'tcx>>>), + GeneratorWitness(Binder<'tcx, &'tcx List<Ty<'tcx>>>), /// The never type `!`. Never, @@ -232,7 +222,7 @@ impl TyKind<'tcx> { // `TyKind` is used a lot. Make sure it doesn't unintentionally get bigger. #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] -static_assert_size!(TyKind<'_>, 24); +static_assert_size!(TyKind<'_>, 32); /// A closure can be modeled as a struct that looks like: /// @@ -747,7 +737,7 @@ impl<'tcx> ExistentialPredicate<'tcx> { } } -impl<'tcx> Binder<ExistentialPredicate<'tcx>> { +impl<'tcx> Binder<'tcx, ExistentialPredicate<'tcx>> { pub fn with_self_ty(&self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> ty::Predicate<'tcx> { use crate::ty::ToPredicate; match self.skip_binder() { @@ -768,7 +758,7 @@ impl<'tcx> Binder<ExistentialPredicate<'tcx>> { } } -impl<'tcx> List<ty::Binder<ExistentialPredicate<'tcx>>> { +impl<'tcx> List<ty::Binder<'tcx, ExistentialPredicate<'tcx>>> { /// Returns the "principal `DefId`" of this set of existential predicates. /// /// A Rust trait object type consists (in addition to a lifetime bound) @@ -794,7 +784,7 @@ impl<'tcx> List<ty::Binder<ExistentialPredicate<'tcx>>> { /// is `{Send, Sync}`, while there is no principal. These trait objects /// have a "trivial" vtable consisting of just the size, alignment, /// and destructor. - pub fn principal(&self) -> Option<ty::Binder<ExistentialTraitRef<'tcx>>> { + pub fn principal(&self) -> Option<ty::Binder<'tcx, ExistentialTraitRef<'tcx>>> { self[0] .map_bound(|this| match this { ExistentialPredicate::Trait(tr) => Some(tr), @@ -810,7 +800,7 @@ impl<'tcx> List<ty::Binder<ExistentialPredicate<'tcx>>> { #[inline] pub fn projection_bounds<'a>( &'a self, - ) -> impl Iterator<Item = ty::Binder<ExistentialProjection<'tcx>>> + 'a { + ) -> impl Iterator<Item = ty::Binder<'tcx, ExistentialProjection<'tcx>>> + 'a { self.iter().filter_map(|predicate| { predicate .map_bound(|pred| match pred { @@ -875,10 +865,10 @@ impl<'tcx> TraitRef<'tcx> { } } -pub type PolyTraitRef<'tcx> = Binder<TraitRef<'tcx>>; +pub type PolyTraitRef<'tcx> = Binder<'tcx, TraitRef<'tcx>>; impl<'tcx> PolyTraitRef<'tcx> { - pub fn self_ty(&self) -> Binder<Ty<'tcx>> { + pub fn self_ty(&self) -> Binder<'tcx, Ty<'tcx>> { self.map_bound_ref(|tr| tr.self_ty()) } @@ -931,7 +921,7 @@ impl<'tcx> ExistentialTraitRef<'tcx> { } } -pub type PolyExistentialTraitRef<'tcx> = Binder<ExistentialTraitRef<'tcx>>; +pub type PolyExistentialTraitRef<'tcx> = Binder<'tcx, ExistentialTraitRef<'tcx>>; impl<'tcx> PolyExistentialTraitRef<'tcx> { pub fn def_id(&self) -> DefId { @@ -947,52 +937,56 @@ impl<'tcx> PolyExistentialTraitRef<'tcx> { } } +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, TyEncodable, TyDecodable)] +#[derive(HashStable)] +pub enum BoundVariableKind { + Ty(BoundTyKind), + Region(BoundRegionKind), + Const, +} + /// Binder is a binder for higher-ranked lifetimes or types. It is part of the /// compiler's representation for things like `for<'a> Fn(&'a isize)` /// (which would be represented by the type `PolyTraitRef == -/// Binder<TraitRef>`). Note that when we instantiate, +/// Binder<'tcx, TraitRef>`). Note that when we instantiate, /// erase, or otherwise "discharge" these bound vars, we change the -/// type from `Binder<T>` to just `T` (see +/// type from `Binder<'tcx, T>` to just `T` (see /// e.g., `liberate_late_bound_regions`). /// /// `Decodable` and `Encodable` are implemented for `Binder<T>` using the `impl_binder_encode_decode!` macro. #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] -pub struct Binder<T>(T); +pub struct Binder<'tcx, T>(T, &'tcx List<BoundVariableKind>); -impl<T> Binder<T> { +impl<'tcx, T> Binder<'tcx, T> +where + T: TypeFoldable<'tcx>, +{ /// Wraps `value` in a binder, asserting that `value` does not /// contain any bound vars that would be bound by the /// binder. This is commonly used to 'inject' a value T into a /// different binding level. - pub fn dummy<'tcx>(value: T) -> Binder<T> - where - T: TypeFoldable<'tcx>, - { + pub fn dummy(value: T) -> Binder<'tcx, T> { debug_assert!(!value.has_escaping_bound_vars()); - Binder(value) + Binder(value, ty::List::empty()) } /// Wraps `value` in a binder, binding higher-ranked vars (if any). - pub fn bind(value: T) -> Binder<T> { - Binder(value) + pub fn bind(value: T, tcx: TyCtxt<'tcx>) -> Binder<'tcx, T> { + let mut collector = BoundVarsCollector::new(); + value.visit_with(&mut collector); + Binder(value, collector.into_vars(tcx)) } - /// Wraps `value` in a binder without actually binding any currently - /// unbound variables. - /// - /// Note that this will shift all debrujin indices of escaping bound variables - /// by 1 to avoid accidential captures. - pub fn wrap_nonbinding(tcx: TyCtxt<'tcx>, value: T) -> Binder<T> - where - T: TypeFoldable<'tcx>, - { - if value.has_escaping_bound_vars() { - Binder::bind(super::fold::shift_vars(tcx, value, 1)) - } else { - Binder::dummy(value) + pub fn bind_with_vars(value: T, vars: &'tcx List<BoundVariableKind>) -> Binder<'tcx, T> { + if cfg!(debug_assertions) { + let mut validator = ValidateBoundVars::new(vars); + value.visit_with(&mut validator); } + Binder(value, vars) } +} +impl<'tcx, T> Binder<'tcx, T> { /// Skips the binder and returns the "bound" value. This is a /// risky thing to do because it's easy to get confused about /// De Bruijn indices and the like. It is usually better to @@ -1013,22 +1007,39 @@ impl<T> Binder<T> { self.0 } - pub fn as_ref(&self) -> Binder<&T> { - Binder(&self.0) + pub fn bound_vars(&self) -> &'tcx List<BoundVariableKind> { + self.1 } - pub fn map_bound_ref<F, U>(&self, f: F) -> Binder<U> + pub fn as_ref(&self) -> Binder<'tcx, &T> { + Binder(&self.0, self.1) + } + + pub fn map_bound_ref_unchecked<F, U>(&self, f: F) -> Binder<'tcx, U> + where + F: FnOnce(&T) -> U, + { + let value = f(&self.0); + Binder(value, self.1) + } + + pub fn map_bound_ref<F, U: TypeFoldable<'tcx>>(&self, f: F) -> Binder<'tcx, U> where F: FnOnce(&T) -> U, { self.as_ref().map_bound(f) } - pub fn map_bound<F, U>(self, f: F) -> Binder<U> + pub fn map_bound<F, U: TypeFoldable<'tcx>>(self, f: F) -> Binder<'tcx, U> where F: FnOnce(T) -> U, { - Binder(f(self.0)) + let value = f(self.0); + if cfg!(debug_assertions) { + let mut validator = ValidateBoundVars::new(self.1); + value.visit_with(&mut validator); + } + Binder(value, self.1) } /// Wraps a `value` in a binder, using the same bound variables as the @@ -1040,8 +1051,15 @@ impl<T> Binder<T> { /// 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) + pub fn rebind<U>(&self, value: U) -> Binder<'tcx, U> + where + U: TypeFoldable<'tcx>, + { + if cfg!(debug_assertions) { + let mut validator = ValidateBoundVars::new(self.bound_vars()); + value.visit_with(&mut validator); + } + Binder(value, self.1) } /// Unwraps and returns the value within, but only if it contains @@ -1054,45 +1072,32 @@ impl<T> Binder<T> { /// binders, but that would require adjusting the debruijn /// indices, and given the shallow binding structure we often use, /// would not be that useful.) - pub fn no_bound_vars<'tcx>(self) -> Option<T> + pub fn no_bound_vars(self) -> Option<T> where T: TypeFoldable<'tcx>, { if self.0.has_escaping_bound_vars() { None } else { Some(self.skip_binder()) } } - /// Given two things that have the same binder level, - /// and an operation that wraps on their contents, executes the operation - /// and then wraps its result. - /// - /// `f` should consider bound regions at depth 1 to be free, and - /// anything it produces with bound regions at depth 1 will be - /// bound in the resulting return value. - pub fn fuse<U, F, R>(self, u: Binder<U>, f: F) -> Binder<R> - where - F: FnOnce(T, U) -> R, - { - Binder(f(self.0, u.0)) - } - /// Splits the contents into two things that share the same binder /// level as the original, returning two distinct binders. /// /// `f` should consider bound regions at depth 1 to be free, and /// anything it produces with bound regions at depth 1 will be /// bound in the resulting return values. - pub fn split<U, V, F>(self, f: F) -> (Binder<U>, Binder<V>) + pub fn split<U, V, F>(self, f: F) -> (Binder<'tcx, U>, Binder<'tcx, V>) where F: FnOnce(T) -> (U, V), { let (u, v) = f(self.0); - (Binder(u), Binder(v)) + (Binder(u, self.1), Binder(v, self.1)) } } -impl<T> Binder<Option<T>> { - pub fn transpose(self) -> Option<Binder<T>> { - self.0.map(Binder) +impl<'tcx, T> Binder<'tcx, Option<T>> { + pub fn transpose(self) -> Option<Binder<'tcx, T>> { + let bound_vars = self.1; + self.0.map(|v| Binder(v, bound_vars)) } } @@ -1155,19 +1160,7 @@ pub struct GenSig<'tcx> { pub return_ty: Ty<'tcx>, } -pub type PolyGenSig<'tcx> = Binder<GenSig<'tcx>>; - -impl<'tcx> PolyGenSig<'tcx> { - pub fn resume_ty(&self) -> ty::Binder<Ty<'tcx>> { - self.map_bound_ref(|sig| sig.resume_ty) - } - pub fn yield_ty(&self) -> ty::Binder<Ty<'tcx>> { - self.map_bound_ref(|sig| sig.yield_ty) - } - pub fn return_ty(&self) -> ty::Binder<Ty<'tcx>> { - self.map_bound_ref(|sig| sig.return_ty) - } -} +pub type PolyGenSig<'tcx> = Binder<'tcx, GenSig<'tcx>>; /// Signature of a function type, which we have arbitrarily /// decided to use to refer to the input/output types. @@ -1205,22 +1198,22 @@ impl<'tcx> FnSig<'tcx> { } } -pub type PolyFnSig<'tcx> = Binder<FnSig<'tcx>>; +pub type PolyFnSig<'tcx> = Binder<'tcx, FnSig<'tcx>>; impl<'tcx> PolyFnSig<'tcx> { #[inline] - pub fn inputs(&self) -> Binder<&'tcx [Ty<'tcx>]> { - self.map_bound_ref(|fn_sig| fn_sig.inputs()) + pub fn inputs(&self) -> Binder<'tcx, &'tcx [Ty<'tcx>]> { + self.map_bound_ref_unchecked(|fn_sig| fn_sig.inputs()) } #[inline] - pub fn input(&self, index: usize) -> ty::Binder<Ty<'tcx>> { + pub fn input(&self, index: usize) -> ty::Binder<'tcx, Ty<'tcx>> { self.map_bound_ref(|fn_sig| fn_sig.inputs()[index]) } - pub fn inputs_and_output(&self) -> ty::Binder<&'tcx List<Ty<'tcx>>> { + pub fn inputs_and_output(&self) -> ty::Binder<'tcx, &'tcx List<Ty<'tcx>>> { self.map_bound_ref(|fn_sig| fn_sig.inputs_and_output) } #[inline] - pub fn output(&self) -> ty::Binder<Ty<'tcx>> { + pub fn output(&self) -> ty::Binder<'tcx, Ty<'tcx>> { self.map_bound_ref(|fn_sig| fn_sig.output()) } pub fn c_variadic(&self) -> bool { @@ -1234,7 +1227,7 @@ impl<'tcx> PolyFnSig<'tcx> { } } -pub type CanonicalPolyFnSig<'tcx> = Canonical<'tcx, Binder<FnSig<'tcx>>>; +pub type CanonicalPolyFnSig<'tcx> = Canonical<'tcx, Binder<'tcx, FnSig<'tcx>>>; #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, TyEncodable, TyDecodable)] #[derive(HashStable)] @@ -1248,10 +1241,6 @@ impl<'tcx> ParamTy { ParamTy { index, name } } - pub fn for_self() -> ParamTy { - ParamTy::new(0, kw::SelfUpper) - } - pub fn for_def(def: &ty::GenericParamDef) -> ParamTy { ParamTy::new(def.index, def.name) } @@ -1269,7 +1258,7 @@ pub struct ParamConst { pub name: Symbol, } -impl<'tcx> ParamConst { +impl ParamConst { pub fn new(index: u32, name: Symbol) -> ParamConst { ParamConst { index, name } } @@ -1277,10 +1266,6 @@ impl<'tcx> ParamConst { pub fn for_def(def: &ty::GenericParamDef) -> ParamConst { ParamConst::new(def.index, def.name) } - - pub fn to_const(self, tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> &'tcx ty::Const<'tcx> { - tcx.mk_const_param(self.index, self.name, ty) - } } pub type Region<'tcx> = &'tcx RegionKind; @@ -1486,7 +1471,7 @@ pub struct ExistentialProjection<'tcx> { pub ty: Ty<'tcx>, } -pub type PolyExistentialProjection<'tcx> = Binder<ExistentialProjection<'tcx>>; +pub type PolyExistentialProjection<'tcx> = Binder<'tcx, ExistentialProjection<'tcx>>; impl<'tcx> ExistentialProjection<'tcx> { /// Extracts the underlying existential trait reference from this projection. @@ -1580,35 +1565,6 @@ impl RegionKind { } } - /// Adjusts any De Bruijn indices so as to make `to_binder` the - /// innermost binder. That is, if we have something bound at `to_binder`, - /// it will now be bound at INNERMOST. This is an appropriate thing to do - /// when moving a region out from inside binders: - /// - /// ``` - /// for<'a> fn(for<'b> for<'c> fn(&'a u32), _) - /// // Binder: D3 D2 D1 ^^ - /// ``` - /// - /// Here, the region `'a` would have the De Bruijn index D3, - /// because it is the bound 3 binders out. However, if we wanted - /// to refer to that region `'a` in the second argument (the `_`), - /// those two binders would not be in scope. In that case, we - /// might invoke `shift_out_to_binder(D3)`. This would adjust the - /// De Bruijn index of `'a` to D1 (the innermost binder). - /// - /// If we invoke `shift_out_to_binder` and the region is in fact - /// bound by one of the binders we are shifting out of, that is an - /// error (and should fail an assertion failure). - pub fn shifted_out_to_binder(&self, to_binder: ty::DebruijnIndex) -> RegionKind { - match *self { - ty::ReLateBound(debruijn, r) => { - ty::ReLateBound(debruijn.shifted_out_to_binder(to_binder), r) - } - r => r, - } - } - pub fn type_flags(&self) -> TypeFlags { let mut flags = TypeFlags::empty(); diff --git a/compiler/rustc_middle/src/ty/subst.rs b/compiler/rustc_middle/src/ty/subst.rs index 5d1b976ae97..8352e8b4918 100644 --- a/compiler/rustc_middle/src/ty/subst.rs +++ b/compiler/rustc_middle/src/ty/subst.rs @@ -448,7 +448,10 @@ impl<'a, 'tcx> TypeFolder<'tcx> for SubstFolder<'a, 'tcx> { self.tcx } - fn fold_binder<T: TypeFoldable<'tcx>>(&mut self, t: ty::Binder<T>) -> ty::Binder<T> { + fn fold_binder<T: TypeFoldable<'tcx>>( + &mut self, + t: ty::Binder<'tcx, T>, + ) -> ty::Binder<'tcx, T> { self.binders_passed += 1; let t = t.super_fold_with(self); self.binders_passed -= 1; diff --git a/compiler/rustc_middle/src/ty/trait_def.rs b/compiler/rustc_middle/src/ty/trait_def.rs index ce17a724e25..33065bc3a7b 100644 --- a/compiler/rustc_middle/src/ty/trait_def.rs +++ b/compiler/rustc_middle/src/ty/trait_def.rs @@ -69,6 +69,12 @@ pub struct TraitImpls { non_blanket_impls: FxHashMap<fast_reject::SimplifiedType, Vec<DefId>>, } +impl TraitImpls { + pub fn blanket_impls(&self) -> &[DefId] { + self.blanket_impls.as_slice() + } +} + impl<'tcx> TraitDef { pub fn new( def_id: DefId, diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index cff8166974a..7d09ca5152f 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -21,7 +21,7 @@ use rustc_macros::HashStable; use rustc_span::{Span, DUMMY_SP}; use rustc_target::abi::{Integer, Size, TargetDataLayout}; use smallvec::SmallVec; -use std::{cmp, fmt}; +use std::{cmp, fmt, iter}; #[derive(Copy, Clone, Debug)] pub struct Discr<'tcx> { @@ -414,9 +414,7 @@ impl<'tcx> TyCtxt<'tcx> { _ => bug!(), }; - let result = item_substs - .iter() - .zip(impl_substs.iter()) + let result = iter::zip(item_substs, impl_substs) .filter(|&(_, k)| { match k.unpack() { GenericArgKind::Lifetime(&ty::RegionKind::ReEarlyBound(ref ebr)) => { @@ -501,10 +499,9 @@ impl<'tcx> TyCtxt<'tcx> { self, closure_def_id: DefId, closure_substs: SubstsRef<'tcx>, - ) -> Option<ty::Binder<Ty<'tcx>>> { + env_region: ty::RegionKind, + ) -> Option<Ty<'tcx>> { let closure_ty = self.mk_closure(closure_def_id, closure_substs); - let br = ty::BoundRegion { kind: ty::BrEnv }; - let env_region = ty::ReLateBound(ty::INNERMOST, br); let closure_kind_ty = closure_substs.as_closure().kind_ty(); let closure_kind = closure_kind_ty.to_opt_closure_kind()?; let env_ty = match closure_kind { @@ -512,7 +509,7 @@ impl<'tcx> TyCtxt<'tcx> { ty::ClosureKind::FnMut => self.mk_mut_ref(self.mk_region(env_region), closure_ty), ty::ClosureKind::FnOnce => closure_ty, }; - Some(ty::Binder::bind(env_ty)) + Some(env_ty) } /// Returns `true` if the node pointed to by `def_id` is a `static` item. @@ -701,7 +698,6 @@ impl<'tcx> ty::TyS<'tcx> { /// optimization as well as the rules around static values. Note /// that the `Freeze` trait is not exposed to end users and is /// effectively an implementation detail. - // FIXME: use `TyCtxtAt` instead of separate `Span`. pub fn is_freeze(&'tcx self, tcx_at: TyCtxtAt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> bool { self.is_trivially_freeze() || tcx_at.is_freeze_raw(param_env.and(self)) } diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs index ec561fa3858..6ea0ba0a8e1 100644 --- a/compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs +++ b/compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs @@ -18,6 +18,7 @@ use rustc_span::{ Span, }; use rustc_target::abi::VariantIdx; +use std::iter; use super::borrow_set::BorrowData; use super::MirBorrowckCtxt; @@ -501,7 +502,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { // lifetimes without names with the value `'0`. match ty.kind() { ty::Ref( - ty::RegionKind::ReLateBound(_, ty::BoundRegion { kind: br }) + ty::RegionKind::ReLateBound(_, ty::BoundRegion { kind: br, .. }) | ty::RegionKind::RePlaceholder(ty::PlaceholderRegion { name: br, .. }), _, _, @@ -522,7 +523,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let region = match ty.kind() { ty::Ref(region, _, _) => { match region { - ty::RegionKind::ReLateBound(_, ty::BoundRegion { kind: br }) + ty::RegionKind::ReLateBound(_, ty::BoundRegion { kind: br, .. }) | ty::RegionKind::RePlaceholder(ty::PlaceholderRegion { name: br, .. }) => { printer.region_highlight_mode.highlighting_bound_region(*br, counter) } @@ -970,13 +971,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let expr = &self.infcx.tcx.hir().expect_expr(hir_id).kind; debug!("closure_span: hir_id={:?} expr={:?}", hir_id, expr); if let hir::ExprKind::Closure(.., body_id, args_span, _) = expr { - for (captured_place, place) in self - .infcx - .tcx - .typeck(def_id.expect_local()) - .closure_min_captures_flattened(def_id) - .zip(places) - { + for (captured_place, place) in iter::zip( + self.infcx.tcx.typeck(def_id.expect_local()).closure_min_captures_flattened(def_id), + places, + ) { let upvar_hir_id = captured_place.get_root_variable(); //FIXME(project-rfc-2229#8): Use better span from captured_place let span = self.infcx.tcx.upvars_mentioned(local_did)?[&upvar_hir_id].span; diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/outlives_suggestion.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/outlives_suggestion.rs index 7505e6e2dd1..3629c813bc7 100644 --- a/compiler/rustc_mir/src/borrow_check/diagnostics/outlives_suggestion.rs +++ b/compiler/rustc_mir/src/borrow_check/diagnostics/outlives_suggestion.rs @@ -157,7 +157,7 @@ impl OutlivesSuggestionBuilder { debug!("Collected {:?}: {:?}", fr, outlived_fr); // Add to set of constraints for final help note. - self.constraints_to_add.entry(fr).or_insert(Vec::new()).push(outlived_fr); + self.constraints_to_add.entry(fr).or_default().push(outlived_fr); } /// Emit an intermediate note on the given `Diagnostic` if the involved regions are diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/region_name.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/region_name.rs index 03738f1b40a..1f168c612f1 100644 --- a/compiler/rustc_mir/src/borrow_check/diagnostics/region_name.rs +++ b/compiler/rustc_mir/src/borrow_check/diagnostics/region_name.rs @@ -1,4 +1,5 @@ use std::fmt::{self, Display}; +use std::iter; use rustc_errors::DiagnosticBuilder; use rustc_hir as hir; @@ -536,7 +537,8 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { // just worry about trying to match up the rustc type // with the HIR types: (ty::Tuple(elem_tys), hir::TyKind::Tup(elem_hir_tys)) => { - search_stack.extend(elem_tys.iter().map(|k| k.expect_ty()).zip(*elem_hir_tys)); + search_stack + .extend(iter::zip(elem_tys.iter().map(|k| k.expect_ty()), *elem_hir_tys)); } (ty::Slice(elem_ty), hir::TyKind::Slice(elem_hir_ty)) @@ -611,7 +613,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { args: &'hir hir::GenericArgs<'hir>, search_stack: &mut Vec<(Ty<'tcx>, &'hir hir::Ty<'hir>)>, ) -> Option<&'hir hir::Lifetime> { - for (kind, hir_arg) in substs.iter().zip(args.args) { + for (kind, hir_arg) in iter::zip(substs, args.args) { match (kind.unpack(), hir_arg) { (GenericArgKind::Lifetime(r), hir::GenericArg::Lifetime(lt)) => { if r.to_region_vid() == needle_fr { diff --git a/compiler/rustc_mir/src/borrow_check/invalidation.rs b/compiler/rustc_mir/src/borrow_check/invalidation.rs index 17c4f3c6494..1055e30a3a4 100644 --- a/compiler/rustc_mir/src/borrow_check/invalidation.rs +++ b/compiler/rustc_mir/src/borrow_check/invalidation.rs @@ -5,6 +5,7 @@ use rustc_middle::mir::{BorrowKind, Mutability, Operand}; use rustc_middle::mir::{InlineAsmOperand, Terminator, TerminatorKind}; use rustc_middle::mir::{Statement, StatementKind}; use rustc_middle::ty::TyCtxt; +use std::iter; use crate::dataflow::indexes::BorrowIndex; @@ -69,7 +70,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> { self.mutate_place(location, **place, Shallow(None), JustWrite); } StatementKind::LlvmInlineAsm(asm) => { - for (o, output) in asm.asm.outputs.iter().zip(asm.outputs.iter()) { + for (o, output) in iter::zip(&asm.asm.outputs, &*asm.outputs) { if o.is_indirect { // FIXME(eddyb) indirect inline asm outputs should // be encoded through MIR place derefs instead. diff --git a/compiler/rustc_mir/src/borrow_check/mod.rs b/compiler/rustc_mir/src/borrow_check/mod.rs index 5b8bb7257e2..583f73d5775 100644 --- a/compiler/rustc_mir/src/borrow_check/mod.rs +++ b/compiler/rustc_mir/src/borrow_check/mod.rs @@ -25,6 +25,7 @@ use either::Either; use smallvec::SmallVec; use std::cell::RefCell; use std::collections::BTreeMap; +use std::iter; use std::mem; use std::rc::Rc; @@ -595,7 +596,7 @@ impl<'cx, 'tcx> dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtxt<'cx, 'tc self.mutate_place(location, (**place, span), Shallow(None), JustWrite, flow_state); } StatementKind::LlvmInlineAsm(ref asm) => { - for (o, output) in asm.asm.outputs.iter().zip(asm.outputs.iter()) { + for (o, output) in iter::zip(&asm.asm.outputs, &*asm.outputs) { if o.is_indirect { // FIXME(eddyb) indirect inline asm outputs should // be encoded through MIR place derefs instead. diff --git a/compiler/rustc_mir/src/borrow_check/places_conflict.rs b/compiler/rustc_mir/src/borrow_check/places_conflict.rs index 02c7b7dc200..3654b51949e 100644 --- a/compiler/rustc_mir/src/borrow_check/places_conflict.rs +++ b/compiler/rustc_mir/src/borrow_check/places_conflict.rs @@ -5,6 +5,7 @@ use rustc_hir as hir; use rustc_middle::mir::{Body, BorrowKind, Local, Place, PlaceElem, PlaceRef, ProjectionElem}; use rustc_middle::ty::{self, TyCtxt}; use std::cmp::max; +use std::iter; /// When checking if a place conflicts with another place, this enum is used to influence decisions /// where a place might be equal or disjoint with another place, such as if `a[i] == a[j]`. @@ -139,7 +140,7 @@ fn place_components_conflict<'tcx>( // loop invariant: borrow_c is always either equal to access_c or disjoint from it. for (i, (borrow_c, &access_c)) in - borrow_place.projection.iter().zip(access_place.projection.iter()).enumerate() + iter::zip(borrow_place.projection, access_place.projection).enumerate() { debug!("borrow_conflicts_with_place: borrow_c = {:?}", borrow_c); let borrow_proj_base = &borrow_place.projection[..i]; 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 77d91366224..1bb447d1057 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 @@ -70,6 +70,12 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { // Equate expected input tys with those in the MIR. for (argument_index, &normalized_input_ty) in normalized_input_tys.iter().enumerate() { + if argument_index + 1 >= body.local_decls.len() { + self.tcx() + .sess + .delay_span_bug(body.span, "found more normalized_input_ty than local_decls"); + break; + } // In MIR, argument N is stored in local N+1. let local = Local::new(argument_index + 1); 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 aaa2bf4ff1b..3248554e204 100644 --- a/compiler/rustc_mir/src/borrow_check/type_check/mod.rs +++ b/compiler/rustc_mir/src/borrow_check/type_check/mod.rs @@ -1770,7 +1770,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { if args.len() < sig.inputs().len() || (args.len() > sig.inputs().len() && !sig.c_variadic) { span_mirbug!(self, term, "call to {:?} with wrong # of args", sig); } - for (n, (fn_arg, op_arg)) in sig.inputs().iter().zip(args).enumerate() { + for (n, (fn_arg, op_arg)) in iter::zip(sig.inputs(), args).enumerate() { let op_arg_ty = op_arg.ty(body, self.tcx()); let op_arg_ty = self.normalize(op_arg_ty, term_location); let category = if from_hir_call { @@ -2028,7 +2028,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { traits::ObligationCauseCode::RepeatVec(is_const_fn), ), self.param_env, - ty::Binder::bind(ty::TraitRef::new( + ty::Binder::dummy(ty::TraitRef::new( self.tcx().require_lang_item( LangItem::Copy, Some(self.last_span), diff --git a/compiler/rustc_mir/src/borrow_check/universal_regions.rs b/compiler/rustc_mir/src/borrow_check/universal_regions.rs index 4b1acc1cd10..c2ac1e289ce 100644 --- a/compiler/rustc_mir/src/borrow_check/universal_regions.rs +++ b/compiler/rustc_mir/src/borrow_check/universal_regions.rs @@ -580,7 +580,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { let global_mapping = iter::once((tcx.lifetimes.re_static, fr_static)); let subst_mapping = - identity_substs.regions().zip(fr_substs.regions().map(|r| r.to_region_vid())); + iter::zip(identity_substs.regions(), fr_substs.regions().map(|r| r.to_region_vid())); UniversalRegionIndices { indices: global_mapping.chain(subst_mapping).collect() } } @@ -589,31 +589,45 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { &self, indices: &UniversalRegionIndices<'tcx>, defining_ty: DefiningTy<'tcx>, - ) -> ty::Binder<&'tcx ty::List<Ty<'tcx>>> { + ) -> ty::Binder<'tcx, &'tcx ty::List<Ty<'tcx>>> { let tcx = self.infcx.tcx; match defining_ty { DefiningTy::Closure(def_id, substs) => { assert_eq!(self.mir_def.did.to_def_id(), def_id); let closure_sig = substs.as_closure().sig(); let inputs_and_output = closure_sig.inputs_and_output(); - let closure_ty = tcx.closure_env_ty(def_id, substs).unwrap(); - ty::Binder::fuse(closure_ty, inputs_and_output, |closure_ty, inputs_and_output| { - // The "inputs" of the closure in the - // signature appear as a tuple. The MIR side - // flattens this tuple. - let (&output, tuplized_inputs) = inputs_and_output.split_last().unwrap(); - assert_eq!(tuplized_inputs.len(), 1, "multiple closure inputs"); - let inputs = match tuplized_inputs[0].kind() { - ty::Tuple(inputs) => inputs, - _ => bug!("closure inputs not a tuple: {:?}", tuplized_inputs[0]), - }; + let bound_vars = tcx.mk_bound_variable_kinds( + inputs_and_output + .bound_vars() + .iter() + .chain(iter::once(ty::BoundVariableKind::Region(ty::BrEnv))), + ); + let br = ty::BoundRegion { + var: ty::BoundVar::from_usize(bound_vars.len() - 1), + kind: ty::BrEnv, + }; + let env_region = ty::ReLateBound(ty::INNERMOST, br); + let closure_ty = tcx.closure_env_ty(def_id, substs, env_region).unwrap(); + + // The "inputs" of the closure in the + // signature appear as a tuple. The MIR side + // flattens this tuple. + let (&output, tuplized_inputs) = + inputs_and_output.skip_binder().split_last().unwrap(); + assert_eq!(tuplized_inputs.len(), 1, "multiple closure inputs"); + let inputs = match tuplized_inputs[0].kind() { + ty::Tuple(inputs) => inputs, + _ => bug!("closure inputs not a tuple: {:?}", tuplized_inputs[0]), + }; + ty::Binder::bind_with_vars( tcx.mk_type_list( iter::once(closure_ty) .chain(inputs.iter().map(|k| k.expect_ty())) .chain(iter::once(output)), - ) - }) + ), + bound_vars, + ) } DefiningTy::Generator(def_id, substs, movability) => { @@ -657,7 +671,7 @@ trait InferCtxtExt<'tcx> { &self, origin: NllRegionVariableOrigin, all_outlive_scope: LocalDefId, - value: ty::Binder<T>, + value: ty::Binder<'tcx, T>, indices: &mut UniversalRegionIndices<'tcx>, ) -> T where @@ -686,7 +700,7 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> { &self, origin: NllRegionVariableOrigin, all_outlive_scope: LocalDefId, - value: ty::Binder<T>, + value: ty::Binder<'tcx, T>, indices: &mut UniversalRegionIndices<'tcx>, ) -> T where diff --git a/compiler/rustc_mir/src/dataflow/framework/cursor.rs b/compiler/rustc_mir/src/dataflow/framework/cursor.rs index 4942bed656c..c000e49c14b 100644 --- a/compiler/rustc_mir/src/dataflow/framework/cursor.rs +++ b/compiler/rustc_mir/src/dataflow/framework/cursor.rs @@ -64,10 +64,6 @@ where } } - pub fn body(&self) -> &'mir mir::Body<'tcx> { - self.body - } - /// Returns the underlying `Results`. pub fn results(&self) -> &Results<'tcx, A> { &self.results.borrow() diff --git a/compiler/rustc_mir/src/dataflow/framework/lattice.rs b/compiler/rustc_mir/src/dataflow/framework/lattice.rs index e7ef9267db5..f937b31f4cf 100644 --- a/compiler/rustc_mir/src/dataflow/framework/lattice.rs +++ b/compiler/rustc_mir/src/dataflow/framework/lattice.rs @@ -40,6 +40,7 @@ use rustc_index::bit_set::BitSet; use rustc_index::vec::{Idx, IndexVec}; +use std::iter; /// A [partially ordered set][poset] that has a [least upper bound][lub] for any pair of elements /// in the set. @@ -110,7 +111,7 @@ impl<I: Idx, T: JoinSemiLattice> JoinSemiLattice for IndexVec<I, T> { assert_eq!(self.len(), other.len()); let mut changed = false; - for (a, b) in self.iter_mut().zip(other.iter()) { + for (a, b) in iter::zip(self, other) { changed |= a.join(b); } changed @@ -122,7 +123,7 @@ impl<I: Idx, T: MeetSemiLattice> MeetSemiLattice for IndexVec<I, T> { assert_eq!(self.len(), other.len()); let mut changed = false; - for (a, b) in self.iter_mut().zip(other.iter()) { + for (a, b) in iter::zip(self, other) { changed |= a.meet(b); } changed diff --git a/compiler/rustc_mir/src/dataflow/impls/borrows.rs b/compiler/rustc_mir/src/dataflow/impls/borrows.rs index f24d0f0266d..c92cff1433f 100644 --- a/compiler/rustc_mir/src/dataflow/impls/borrows.rs +++ b/compiler/rustc_mir/src/dataflow/impls/borrows.rs @@ -11,6 +11,7 @@ use crate::borrow_check::{ use crate::dataflow::{self, fmt::DebugWithContext, GenKill}; use std::fmt; +use std::iter; rustc_index::newtype_index! { pub struct BorrowIndex { @@ -292,7 +293,7 @@ impl<'tcx> dataflow::GenKillAnalysis<'tcx> for Borrows<'_, 'tcx> { } mir::StatementKind::LlvmInlineAsm(ref asm) => { - for (output, kind) in asm.outputs.iter().zip(&asm.asm.outputs) { + for (output, kind) in iter::zip(&*asm.outputs, &asm.asm.outputs) { if !kind.is_indirect && !kind.is_rw { self.kill_borrows_on_place(trans, *output); } diff --git a/compiler/rustc_mir/src/dataflow/move_paths/builder.rs b/compiler/rustc_mir/src/dataflow/move_paths/builder.rs index 1ddd81e779b..52b6e9f3753 100644 --- a/compiler/rustc_mir/src/dataflow/move_paths/builder.rs +++ b/compiler/rustc_mir/src/dataflow/move_paths/builder.rs @@ -4,6 +4,7 @@ use rustc_middle::mir::*; use rustc_middle::ty::{self, TyCtxt}; use smallvec::{smallvec, SmallVec}; +use std::iter; use std::mem; use super::abs_domain::Lift; @@ -296,7 +297,7 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> { self.create_move_path(**place); } StatementKind::LlvmInlineAsm(ref asm) => { - for (output, kind) in asm.outputs.iter().zip(&asm.asm.outputs) { + for (output, kind) in iter::zip(&*asm.outputs, &asm.asm.outputs) { if !kind.is_indirect { self.gather_init(output.as_ref(), InitKind::Deep); } diff --git a/compiler/rustc_mir/src/interpret/eval_context.rs b/compiler/rustc_mir/src/interpret/eval_context.rs index 149a9f81ea0..18d4d71e517 100644 --- a/compiler/rustc_mir/src/interpret/eval_context.rs +++ b/compiler/rustc_mir/src/interpret/eval_context.rs @@ -232,6 +232,8 @@ impl<'mir, 'tcx, Tag, Extra> Frame<'mir, 'tcx, Tag, Extra> { /// this frame (can happen e.g. during frame initialization, and during unwinding on /// frames without cleanup code). /// We basically abuse `Result` as `Either`. + /// + /// Used by priroda. pub fn current_loc(&self) -> Result<mir::Location, Span> { self.loc } @@ -460,11 +462,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } #[inline] - pub fn type_is_sized(&self, ty: Ty<'tcx>) -> bool { - ty.is_sized(self.tcx, self.param_env) - } - - #[inline] pub fn type_is_freeze(&self, ty: Ty<'tcx>) -> bool { ty.is_freeze(self.tcx, self.param_env) } diff --git a/compiler/rustc_mir/src/interpret/intrinsics/type_name.rs b/compiler/rustc_mir/src/interpret/intrinsics/type_name.rs index e1ec4cc5e97..ae5e78ee33f 100644 --- a/compiler/rustc_mir/src/interpret/intrinsics/type_name.rs +++ b/compiler/rustc_mir/src/interpret/intrinsics/type_name.rs @@ -74,7 +74,7 @@ impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'tcx> { fn print_dyn_existential( mut self, - predicates: &'tcx ty::List<ty::Binder<ty::ExistentialPredicate<'tcx>>>, + predicates: &'tcx ty::List<ty::Binder<'tcx, ty::ExistentialPredicate<'tcx>>>, ) -> Result<Self::DynExistential, Self::Error> { let mut first = true; for p in predicates { diff --git a/compiler/rustc_mir/src/interpret/operand.rs b/compiler/rustc_mir/src/interpret/operand.rs index c70b57e631a..0f436fb3b03 100644 --- a/compiler/rustc_mir/src/interpret/operand.rs +++ b/compiler/rustc_mir/src/interpret/operand.rs @@ -77,14 +77,6 @@ impl<'tcx, Tag> Immediate<Tag> { pub fn to_scalar(self) -> InterpResult<'tcx, Scalar<Tag>> { self.to_scalar_or_uninit().check_init() } - - #[inline] - pub fn to_scalar_pair(self) -> InterpResult<'tcx, (Scalar<Tag>, Scalar<Tag>)> { - match self { - Immediate::Scalar(..) => bug!("Got a thin pointer where a scalar pair was expected"), - Immediate::ScalarPair(a, b) => Ok((a.check_init()?, b.check_init()?)), - } - } } // ScalarPair needs a type to interpret, so we often have an immediate and a type together diff --git a/compiler/rustc_mir/src/lib.rs b/compiler/rustc_mir/src/lib.rs index 32354641412..b0db4f9e649 100644 --- a/compiler/rustc_mir/src/lib.rs +++ b/compiler/rustc_mir/src/lib.rs @@ -18,6 +18,7 @@ Rust MIR: a lowered representation of Rust. #![feature(decl_macro)] #![feature(exact_size_is_empty)] #![feature(exhaustive_patterns)] +#![feature(iter_zip)] #![feature(never_type)] #![feature(map_try_insert)] #![feature(min_specialization)] diff --git a/compiler/rustc_mir/src/monomorphize/mod.rs b/compiler/rustc_mir/src/monomorphize/mod.rs index d2586f0f84d..9ca4b6687f1 100644 --- a/compiler/rustc_mir/src/monomorphize/mod.rs +++ b/compiler/rustc_mir/src/monomorphize/mod.rs @@ -8,14 +8,14 @@ pub mod collector; pub mod partitioning; pub mod polymorphize; -pub fn custom_coerce_unsize_info<'tcx>( +fn custom_coerce_unsize_info<'tcx>( tcx: TyCtxt<'tcx>, source_ty: Ty<'tcx>, target_ty: Ty<'tcx>, ) -> CustomCoerceUnsized { let def_id = tcx.require_lang_item(LangItem::CoerceUnsized, None); - let trait_ref = ty::Binder::bind(ty::TraitRef { + let trait_ref = ty::Binder::dummy(ty::TraitRef { def_id, substs: tcx.mk_substs_trait(source_ty, &[target_ty.into()]), }); diff --git a/compiler/rustc_mir/src/monomorphize/partitioning/mod.rs b/compiler/rustc_mir/src/monomorphize/partitioning/mod.rs index 04f31ec3a33..dc2379fd92b 100644 --- a/compiler/rustc_mir/src/monomorphize/partitioning/mod.rs +++ b/compiler/rustc_mir/src/monomorphize/partitioning/mod.rs @@ -196,13 +196,7 @@ pub fn partition<'tcx>( // Next we try to make as many symbols "internal" as possible, so LLVM has // more freedom to optimize. - if !tcx.sess.link_dead_code() && !tcx.sess.instrument_coverage() { - // Disabled for `-Z instrument-coverage` because some LLVM optimizations can sometimes - // break coverage results. Tests that failed at certain optimization levels are now - // validated at those optimization levels (via `compile-flags` directive); for example: - // * `src/test/run-make-fulldeps/coverage/async.rs` broke with `-C opt-level=1` - // * `src/test/run-make-fulldeps/coverage/closure.rs` broke with `-C opt-level=2`, and - // also required disabling `generate_gcu_internal_copies` in `rustc_middle/mir/mono.rs` + if !tcx.sess.link_dead_code() { let _prof_timer = tcx.prof.generic_activity("cgu_partitioning_internalize_symbols"); partitioner.internalize_symbols(cx, &mut post_inlining); } diff --git a/compiler/rustc_mir/src/transform/check_consts/validation.rs b/compiler/rustc_mir/src/transform/check_consts/validation.rs index 1ad7b8fbbd5..ce5e41d3e7c 100644 --- a/compiler/rustc_mir/src/transform/check_consts/validation.rs +++ b/compiler/rustc_mir/src/transform/check_consts/validation.rs @@ -850,9 +850,12 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> { let obligation = Obligation::new( ObligationCause::dummy(), param_env, - Binder::bind(TraitPredicate { - trait_ref: TraitRef::from_method(tcx, trait_id, substs), - }), + Binder::bind( + TraitPredicate { + trait_ref: TraitRef::from_method(tcx, trait_id, substs), + }, + tcx, + ), ); let implsrc = tcx.infer_ctxt().enter(|infcx| { diff --git a/compiler/rustc_mir/src/transform/check_packed_ref.rs b/compiler/rustc_mir/src/transform/check_packed_ref.rs index ee88daa83e7..13b7221046b 100644 --- a/compiler/rustc_mir/src/transform/check_packed_ref.rs +++ b/compiler/rustc_mir/src/transform/check_packed_ref.rs @@ -1,11 +1,18 @@ +use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_middle::mir::visit::{PlaceContext, Visitor}; use rustc_middle::mir::*; +use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, TyCtxt}; use rustc_session::lint::builtin::UNALIGNED_REFERENCES; +use rustc_span::symbol::sym; use crate::transform::MirPass; use crate::util; +pub(crate) fn provide(providers: &mut Providers) { + *providers = Providers { unsafe_derive_on_repr_packed, ..*providers }; +} + pub struct CheckPackedRef; impl<'tcx> MirPass<'tcx> for CheckPackedRef { @@ -24,6 +31,41 @@ struct PackedRefChecker<'a, 'tcx> { source_info: SourceInfo, } +fn unsafe_derive_on_repr_packed(tcx: TyCtxt<'_>, def_id: LocalDefId) { + let lint_hir_id = tcx.hir().local_def_id_to_hir_id(def_id); + + tcx.struct_span_lint_hir(UNALIGNED_REFERENCES, lint_hir_id, tcx.def_span(def_id), |lint| { + // FIXME: when we make this a hard error, this should have its + // own error code. + let message = if tcx.generics_of(def_id).own_requires_monomorphization() { + "`#[derive]` can't be used on a `#[repr(packed)]` struct with \ + type or const parameters (error E0133)" + .to_string() + } else { + "`#[derive]` can't be used on a `#[repr(packed)]` struct that \ + does not derive Copy (error E0133)" + .to_string() + }; + lint.build(&message).emit() + }); +} + +fn builtin_derive_def_id(tcx: TyCtxt<'_>, def_id: DefId) -> Option<DefId> { + debug!("builtin_derive_def_id({:?})", def_id); + if let Some(impl_def_id) = tcx.impl_of_method(def_id) { + if tcx.has_attr(impl_def_id, sym::automatically_derived) { + debug!("builtin_derive_def_id({:?}) - is {:?}", def_id, impl_def_id); + Some(impl_def_id) + } else { + debug!("builtin_derive_def_id({:?}) - not automatically derived", def_id); + None + } + } else { + debug!("builtin_derive_def_id({:?}) - not a method", def_id); + None + } +} + impl<'a, 'tcx> Visitor<'tcx> for PackedRefChecker<'a, 'tcx> { fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) { // Make sure we know where in the MIR we are. @@ -40,26 +82,33 @@ impl<'a, 'tcx> Visitor<'tcx> for PackedRefChecker<'a, 'tcx> { fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, _location: Location) { if context.is_borrow() { if util::is_disaligned(self.tcx, self.body, self.param_env, *place) { - let source_info = self.source_info; - let lint_root = self.body.source_scopes[source_info.scope] - .local_data - .as_ref() - .assert_crate_local() - .lint_root; - self.tcx.struct_span_lint_hir( - UNALIGNED_REFERENCES, - lint_root, - source_info.span, - |lint| { - lint.build("reference to packed field is unaligned") - .note( - "fields of packed structs are not properly aligned, and creating \ - a misaligned reference is undefined behavior (even if that \ - reference is never dereferenced)", - ) - .emit() - }, - ); + let def_id = self.body.source.instance.def_id(); + if let Some(impl_def_id) = builtin_derive_def_id(self.tcx, def_id) { + // If a method is defined in the local crate, + // the impl containing that method should also be. + self.tcx.ensure().unsafe_derive_on_repr_packed(impl_def_id.expect_local()); + } else { + let source_info = self.source_info; + let lint_root = self.body.source_scopes[source_info.scope] + .local_data + .as_ref() + .assert_crate_local() + .lint_root; + self.tcx.struct_span_lint_hir( + UNALIGNED_REFERENCES, + lint_root, + source_info.span, + |lint| { + lint.build("reference to packed field is unaligned") + .note( + "fields of packed structs are not properly aligned, and creating \ + a misaligned reference is undefined behavior (even if that \ + reference is never dereferenced)", + ) + .emit() + }, + ); + } } } } diff --git a/compiler/rustc_mir/src/transform/check_unsafety.rs b/compiler/rustc_mir/src/transform/check_unsafety.rs index 532d201e056..09da9b2e4d6 100644 --- a/compiler/rustc_mir/src/transform/check_unsafety.rs +++ b/compiler/rustc_mir/src/transform/check_unsafety.rs @@ -10,14 +10,12 @@ use rustc_middle::mir::*; use rustc_middle::ty::cast::CastTy; use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, TyCtxt}; -use rustc_session::lint::builtin::{SAFE_PACKED_BORROWS, UNSAFE_OP_IN_UNSAFE_FN, UNUSED_UNSAFE}; +use rustc_session::lint::builtin::{UNSAFE_OP_IN_UNSAFE_FN, UNUSED_UNSAFE}; use rustc_session::lint::Level; -use rustc_span::symbol::sym; use std::ops::Bound; use crate::const_eval::is_min_const_fn; -use crate::util; pub struct UnsafetyChecker<'a, 'tcx> { body: &'a Body<'tcx>, @@ -182,18 +180,6 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> { self.check_mut_borrowing_layout_constrained_field(*place, context.is_mutating_use()); } - // Check for borrows to packed fields. - // `is_disaligned` already traverses the place to consider all projections after the last - // `Deref`, so this only needs to be called once at the top level. - if context.is_borrow() { - if util::is_disaligned(self.tcx, self.body, self.param_env, *place) { - self.require_unsafe( - UnsafetyViolationKind::BorrowPacked, - UnsafetyViolationDetails::BorrowOfPackedField, - ); - } - } - // Some checks below need the extra metainfo of the local declaration. let decl = &self.body.local_decls[place.local]; @@ -317,25 +303,15 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> { // `unsafe` blocks are required in safe code Safety::Safe => { for violation in violations { - let mut violation = *violation; match violation.kind { UnsafetyViolationKind::GeneralAndConstFn | UnsafetyViolationKind::General => {} - UnsafetyViolationKind::BorrowPacked => { - if self.min_const_fn { - // const fns don't need to be backwards compatible and can - // emit these violations as a hard error instead of a backwards - // compat lint - violation.kind = UnsafetyViolationKind::General; - } - } - UnsafetyViolationKind::UnsafeFn - | UnsafetyViolationKind::UnsafeFnBorrowPacked => { + UnsafetyViolationKind::UnsafeFn => { bug!("`UnsafetyViolationKind::UnsafeFn` in an `Safe` context") } } - if !self.violations.contains(&violation) { - self.violations.push(violation) + if !self.violations.contains(violation) { + self.violations.push(*violation) } } false @@ -345,11 +321,7 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> { for violation in violations { let mut violation = *violation; - if violation.kind == UnsafetyViolationKind::BorrowPacked { - violation.kind = UnsafetyViolationKind::UnsafeFnBorrowPacked; - } else { - violation.kind = UnsafetyViolationKind::UnsafeFn; - } + violation.kind = UnsafetyViolationKind::UnsafeFn; if !self.violations.contains(&violation) { self.violations.push(violation) } @@ -369,8 +341,7 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> { // these unsafe things are stable in const fn UnsafetyViolationKind::GeneralAndConstFn => {} // these things are forbidden in const fns - UnsafetyViolationKind::General - | UnsafetyViolationKind::BorrowPacked => { + UnsafetyViolationKind::General => { let mut violation = *violation; // const fns don't need to be backwards compatible and can // emit these violations as a hard error instead of a backwards @@ -380,8 +351,7 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> { self.violations.push(violation) } } - UnsafetyViolationKind::UnsafeFn - | UnsafetyViolationKind::UnsafeFnBorrowPacked => bug!( + UnsafetyViolationKind::UnsafeFn => bug!( "`UnsafetyViolationKind::UnsafeFn` in an `ExplicitUnsafe` context" ), } @@ -464,7 +434,6 @@ pub(crate) fn provide(providers: &mut Providers) { ty::WithOptConstParam { did, const_param_did: Some(param_did) }, ) }, - unsafe_derive_on_repr_packed, ..*providers }; } @@ -544,25 +513,6 @@ fn unsafety_check_result<'tcx>( }) } -fn unsafe_derive_on_repr_packed(tcx: TyCtxt<'_>, def_id: LocalDefId) { - let lint_hir_id = tcx.hir().local_def_id_to_hir_id(def_id); - - tcx.struct_span_lint_hir(SAFE_PACKED_BORROWS, lint_hir_id, tcx.def_span(def_id), |lint| { - // FIXME: when we make this a hard error, this should have its - // own error code. - let message = if tcx.generics_of(def_id).own_requires_monomorphization() { - "`#[derive]` can't be used on a `#[repr(packed)]` struct with \ - type or const parameters (error E0133)" - .to_string() - } else { - "`#[derive]` can't be used on a `#[repr(packed)]` struct that \ - does not derive Copy (error E0133)" - .to_string() - }; - lint.build(&message).emit() - }); -} - /// Returns the `HirId` for an enclosing scope that is also `unsafe`. fn is_enclosed( tcx: TyCtxt<'_>, @@ -609,22 +559,6 @@ fn report_unused_unsafe(tcx: TyCtxt<'_>, used_unsafe: &FxHashSet<hir::HirId>, id }); } -fn builtin_derive_def_id(tcx: TyCtxt<'_>, def_id: DefId) -> Option<DefId> { - debug!("builtin_derive_def_id({:?})", def_id); - if let Some(impl_def_id) = tcx.impl_of_method(def_id) { - if tcx.has_attr(impl_def_id, sym::automatically_derived) { - debug!("builtin_derive_def_id({:?}) - is {:?}", def_id, impl_def_id); - Some(impl_def_id) - } else { - debug!("builtin_derive_def_id({:?}) - not automatically derived", def_id); - None - } - } else { - debug!("builtin_derive_def_id({:?}) - not a method", def_id); - None - } -} - pub fn check_unsafety(tcx: TyCtxt<'_>, def_id: LocalDefId) { debug!("check_unsafety({:?})", def_id); @@ -657,27 +591,6 @@ pub fn check_unsafety(tcx: TyCtxt<'_>, def_id: LocalDefId) { .note(note) .emit(); } - UnsafetyViolationKind::BorrowPacked => { - if let Some(impl_def_id) = builtin_derive_def_id(tcx, def_id.to_def_id()) { - // If a method is defined in the local crate, - // the impl containing that method should also be. - tcx.ensure().unsafe_derive_on_repr_packed(impl_def_id.expect_local()); - } else { - tcx.struct_span_lint_hir( - SAFE_PACKED_BORROWS, - lint_root, - source_info.span, - |lint| { - lint.build(&format!( - "{} is unsafe and requires unsafe{} block (error E0133)", - description, unsafe_fn_msg, - )) - .note(note) - .emit() - }, - ) - } - } UnsafetyViolationKind::UnsafeFn => tcx.struct_span_lint_hir( UNSAFE_OP_IN_UNSAFE_FN, lint_root, @@ -692,35 +605,6 @@ pub fn check_unsafety(tcx: TyCtxt<'_>, def_id: LocalDefId) { .emit(); }, ), - UnsafetyViolationKind::UnsafeFnBorrowPacked => { - // When `unsafe_op_in_unsafe_fn` is disallowed, the behavior of safe and unsafe functions - // should be the same in terms of warnings and errors. Therefore, with `#[warn(safe_packed_borrows)]`, - // a safe packed borrow should emit a warning *but not an error* in an unsafe function, - // just like in a safe function, even if `unsafe_op_in_unsafe_fn` is `deny`. - // - // Also, `#[warn(unsafe_op_in_unsafe_fn)]` can't cause any new errors. Therefore, with - // `#[deny(safe_packed_borrows)]` and `#[warn(unsafe_op_in_unsafe_fn)]`, a packed borrow - // should only issue a warning for the sake of backwards compatibility. - // - // The solution those 2 expectations is to always take the minimum of both lints. - // This prevent any new errors (unless both lints are explicitly set to `deny`). - let lint = if tcx.lint_level_at_node(SAFE_PACKED_BORROWS, lint_root).0 - <= tcx.lint_level_at_node(UNSAFE_OP_IN_UNSAFE_FN, lint_root).0 - { - SAFE_PACKED_BORROWS - } else { - UNSAFE_OP_IN_UNSAFE_FN - }; - tcx.struct_span_lint_hir(&lint, lint_root, source_info.span, |lint| { - lint.build(&format!( - "{} is unsafe and requires unsafe block (error E0133)", - description, - )) - .span_label(source_info.span, description) - .note(note) - .emit(); - }) - } } } diff --git a/compiler/rustc_mir/src/transform/coverage/debug.rs b/compiler/rustc_mir/src/transform/coverage/debug.rs index aabfee53acb..0e9728df73c 100644 --- a/compiler/rustc_mir/src/transform/coverage/debug.rs +++ b/compiler/rustc_mir/src/transform/coverage/debug.rs @@ -121,6 +121,7 @@ use rustc_middle::mir::coverage::*; use rustc_middle::mir::{self, BasicBlock, TerminatorKind}; use rustc_middle::ty::TyCtxt; +use std::iter; use std::lazy::SyncOnceCell; pub const NESTED_INDENT: &str = " "; @@ -703,9 +704,7 @@ pub(super) fn dump_coverage_graphviz( let edge_counters = from_terminator .successors() .map(|&successor_bb| graphviz_data.get_edge_counter(from_bcb, successor_bb)); - edge_labels - .iter() - .zip(edge_counters) + iter::zip(&edge_labels, edge_counters) .map(|(label, some_counter)| { if let Some(counter) = some_counter { format!("{}\n{}", label, debug_counters.format_counter(counter)) diff --git a/compiler/rustc_mir/src/transform/deduplicate_blocks.rs b/compiler/rustc_mir/src/transform/deduplicate_blocks.rs index e102512e1f3..c41e71e09a4 100644 --- a/compiler/rustc_mir/src/transform/deduplicate_blocks.rs +++ b/compiler/rustc_mir/src/transform/deduplicate_blocks.rs @@ -1,7 +1,7 @@ //! This pass finds basic blocks that are completely equal, //! and replaces all uses with just one of them. -use std::{collections::hash_map::Entry, hash::Hash, hash::Hasher}; +use std::{collections::hash_map::Entry, hash::Hash, hash::Hasher, iter}; use crate::transform::MirPass; @@ -115,11 +115,7 @@ impl<'tcx, 'a> PartialEq for BasicBlockHashable<'tcx, 'a> { fn eq(&self, other: &Self) -> bool { self.basic_block_data.statements.len() == other.basic_block_data.statements.len() && &self.basic_block_data.terminator().kind == &other.basic_block_data.terminator().kind - && self - .basic_block_data - .statements - .iter() - .zip(&other.basic_block_data.statements) + && iter::zip(&self.basic_block_data.statements, &other.basic_block_data.statements) .all(|(x, y)| statement_eq(&x.kind, &y.kind)) } } diff --git a/compiler/rustc_mir/src/transform/match_branches.rs b/compiler/rustc_mir/src/transform/match_branches.rs index d04a7011ab0..f7a9835353e 100644 --- a/compiler/rustc_mir/src/transform/match_branches.rs +++ b/compiler/rustc_mir/src/transform/match_branches.rs @@ -1,6 +1,7 @@ use crate::transform::MirPass; use rustc_middle::mir::*; use rustc_middle::ty::TyCtxt; +use std::iter; use super::simplify::simplify_cfg; @@ -83,7 +84,7 @@ impl<'tcx> MirPass<'tcx> for MatchBranchSimplification { if first_stmts.len() != scnd_stmts.len() { continue; } - for (f, s) in first_stmts.iter().zip(scnd_stmts.iter()) { + for (f, s) in iter::zip(first_stmts, scnd_stmts) { match (&f.kind, &s.kind) { // If two statements are exactly the same, we can optimize. (f_s, s_s) if f_s == s_s => {} @@ -113,7 +114,7 @@ impl<'tcx> MirPass<'tcx> for MatchBranchSimplification { // and bb_idx has a different terminator from both of them. let (from, first, second) = bbs.pick3_mut(bb_idx, first, second); - let new_stmts = first.statements.iter().zip(second.statements.iter()).map(|(f, s)| { + let new_stmts = iter::zip(&first.statements, &second.statements).map(|(f, s)| { match (&f.kind, &s.kind) { (f_s, s_s) if f_s == s_s => (*f).clone(), diff --git a/compiler/rustc_mir/src/transform/mod.rs b/compiler/rustc_mir/src/transform/mod.rs index 66d2ab8a3f1..5c49ee69edc 100644 --- a/compiler/rustc_mir/src/transform/mod.rs +++ b/compiler/rustc_mir/src/transform/mod.rs @@ -59,6 +59,7 @@ pub use rustc_middle::mir::MirSource; pub(crate) fn provide(providers: &mut Providers) { self::check_unsafety::provide(providers); + self::check_packed_ref::provide(providers); *providers = Providers { mir_keys, mir_const, diff --git a/compiler/rustc_mir/src/util/alignment.rs b/compiler/rustc_mir/src/util/alignment.rs index f567c9cfaab..5d4ca871faa 100644 --- a/compiler/rustc_mir/src/util/alignment.rs +++ b/compiler/rustc_mir/src/util/alignment.rs @@ -1,5 +1,6 @@ use rustc_middle::mir::*; use rustc_middle::ty::{self, TyCtxt}; +use rustc_target::abi::Align; /// Returns `true` if this place is allowed to be less aligned /// than its containing struct (because it is within a packed @@ -14,17 +15,25 @@ where L: HasLocalDecls<'tcx>, { debug!("is_disaligned({:?})", place); - if !is_within_packed(tcx, local_decls, place) { - debug!("is_disaligned({:?}) - not within packed", place); - return false; - } + let pack = match is_within_packed(tcx, local_decls, place) { + None => { + debug!("is_disaligned({:?}) - not within packed", place); + return false; + } + Some(pack) => pack, + }; let ty = place.ty(local_decls, tcx).ty; match tcx.layout_raw(param_env.and(ty)) { - Ok(layout) if layout.align.abi.bytes() == 1 => { - // if the alignment is 1, the type can't be further - // disaligned. - debug!("is_disaligned({:?}) - align = 1", place); + Ok(layout) if layout.align.abi <= pack => { + // If the packed alignment is greater or equal to the field alignment, the type won't be + // further disaligned. + debug!( + "is_disaligned({:?}) - align = {}, packed = {}; not disaligned", + place, + layout.align.abi.bytes(), + pack.bytes() + ); false } _ => { @@ -34,7 +43,11 @@ where } } -fn is_within_packed<'tcx, L>(tcx: TyCtxt<'tcx>, local_decls: &L, place: Place<'tcx>) -> bool +fn is_within_packed<'tcx, L>( + tcx: TyCtxt<'tcx>, + local_decls: &L, + place: Place<'tcx>, +) -> Option<Align> where L: HasLocalDecls<'tcx>, { @@ -45,7 +58,7 @@ where ProjectionElem::Field(..) => { let ty = place_base.ty(local_decls, tcx).ty; match ty.kind() { - ty::Adt(def, _) if def.repr.packed() => return true, + ty::Adt(def, _) => return def.repr.pack, _ => {} } } @@ -53,5 +66,5 @@ where } } - false + None } diff --git a/compiler/rustc_mir/src/util/generic_graphviz.rs b/compiler/rustc_mir/src/util/generic_graphviz.rs index fd41e282266..21c18b28e25 100644 --- a/compiler/rustc_mir/src/util/generic_graphviz.rs +++ b/compiler/rustc_mir/src/util/generic_graphviz.rs @@ -40,22 +40,6 @@ impl< } } - pub fn new_subgraph( - graph: &'a G, - graphviz_name: &str, - node_content_fn: NodeContentFn, - edge_labels_fn: EdgeLabelsFn, - ) -> Self { - Self { - graph, - is_subgraph: true, - graphviz_name: graphviz_name.to_owned(), - graph_label: None, - node_content_fn, - edge_labels_fn, - } - } - pub fn set_graph_label(&mut self, graph_label: &str) { self.graph_label = Some(graph_label.to_owned()); } diff --git a/compiler/rustc_mir/src/util/patch.rs b/compiler/rustc_mir/src/util/patch.rs index 6566a996fe4..d09195f53ae 100644 --- a/compiler/rustc_mir/src/util/patch.rs +++ b/compiler/rustc_mir/src/util/patch.rs @@ -13,7 +13,6 @@ pub struct MirPatch<'tcx> { new_locals: Vec<LocalDecl<'tcx>>, resume_block: BasicBlock, next_local: usize, - make_nop: Vec<Location>, } impl<'tcx> MirPatch<'tcx> { @@ -25,7 +24,6 @@ impl<'tcx> MirPatch<'tcx> { new_locals: vec![], next_local: body.local_decls.len(), resume_block: START_BLOCK, - make_nop: vec![], }; // make sure the MIR we create has a resume block. It is @@ -117,15 +115,7 @@ impl<'tcx> MirPatch<'tcx> { self.add_statement(loc, StatementKind::Assign(box (place, rv))); } - pub fn make_nop(&mut self, loc: Location) { - self.make_nop.push(loc); - } - pub fn apply(self, body: &mut Body<'tcx>) { - debug!("MirPatch: make nops at: {:?}", self.make_nop); - for loc in self.make_nop { - body.make_statement_nop(loc); - } debug!( "MirPatch: {:?} new temps, starting from index {}: {:?}", self.new_locals.len(), 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 fbc9c30fe53..589a4467dca 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_place.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_place.rs @@ -17,6 +17,8 @@ use rustc_target::abi::VariantIdx; use rustc_index::vec::Idx; +use std::iter; + /// The "outermost" place that holds this value. #[derive(Copy, Clone, Debug, PartialEq)] crate enum PlaceBase { @@ -140,7 +142,7 @@ fn is_ancestor_or_same_capture( return false; } - proj_possible_ancestor.iter().zip(proj_capture).all(|(a, b)| a == b) + iter::zip(proj_possible_ancestor, proj_capture).all(|(a, b)| a == b) } /// Computes the index of a capture within the desugared closure provided the closure's diff --git a/compiler/rustc_mir_build/src/build/expr/into.rs b/compiler/rustc_mir_build/src/build/expr/into.rs index fc92e8019c2..80a5bff8cad 100644 --- a/compiler/rustc_mir_build/src/build/expr/into.rs +++ b/compiler/rustc_mir_build/src/build/expr/into.rs @@ -10,6 +10,7 @@ use rustc_hir as hir; use rustc_index::vec::Idx; use rustc_middle::mir::*; use rustc_middle::ty::{self, CanonicalUserTypeAnnotation}; +use std::iter; impl<'a, 'tcx> Builder<'a, 'tcx> { /// Compile `expr`, storing the result into `destination`, which @@ -110,18 +111,17 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ExprKind::LogicalOp { op, lhs, rhs } => { // And: // - // [block: If(lhs)] -true-> [else_block: If(rhs)] -true-> [true_block] - // | | (false) - // +----------false-----------+------------------> [false_block] + // [block: If(lhs)] -true-> [else_block: dest = (rhs)] + // | (false) + // [shortcurcuit_block: dest = false] // // Or: // - // [block: If(lhs)] -false-> [else_block: If(rhs)] -true-> [true_block] - // | (true) | (false) - // [true_block] [false_block] + // [block: If(lhs)] -false-> [else_block: dest = (rhs)] + // | (true) + // [shortcurcuit_block: dest = true] - let (true_block, false_block, mut else_block, join_block) = ( - this.cfg.start_new_block(), + let (shortcircuit_block, mut else_block, join_block) = ( this.cfg.start_new_block(), this.cfg.start_new_block(), this.cfg.start_new_block(), @@ -129,41 +129,31 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let lhs = unpack!(block = this.as_local_operand(block, lhs)); let blocks = match op { - LogicalOp::And => (else_block, false_block), - LogicalOp::Or => (true_block, else_block), + LogicalOp::And => (else_block, shortcircuit_block), + LogicalOp::Or => (shortcircuit_block, else_block), }; let term = TerminatorKind::if_(this.tcx, lhs, blocks.0, blocks.1); this.cfg.terminate(block, source_info, term); - let rhs = unpack!(else_block = this.as_local_operand(else_block, rhs)); - let term = TerminatorKind::if_(this.tcx, rhs, true_block, false_block); - this.cfg.terminate(else_block, source_info, term); - this.cfg.push_assign_constant( - true_block, + shortcircuit_block, source_info, destination, Constant { span: expr_span, user_ty: None, - literal: ty::Const::from_bool(this.tcx, true).into(), + literal: match op { + LogicalOp::And => ty::Const::from_bool(this.tcx, false).into(), + LogicalOp::Or => ty::Const::from_bool(this.tcx, true).into(), + }, }, ); + this.cfg.goto(shortcircuit_block, source_info, join_block); - this.cfg.push_assign_constant( - false_block, - source_info, - destination, - Constant { - span: expr_span, - user_ty: None, - literal: ty::Const::from_bool(this.tcx, false).into(), - }, - ); + let rhs = unpack!(else_block = this.as_local_operand(else_block, rhs)); + this.cfg.push_assign(else_block, source_info, destination, Rvalue::Use(rhs)); + this.cfg.goto(else_block, source_info, join_block); - // Link up both branches: - this.cfg.goto(true_block, source_info, join_block); - this.cfg.goto(false_block, source_info, join_block); join_block.unit() } ExprKind::Loop { body } => { @@ -286,9 +276,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // MIR does not natively support FRU, so for each // base-supplied field, generate an operand that // reads it from the base. - field_names - .into_iter() - .zip(field_types.into_iter()) + iter::zip(field_names, *field_types) .map(|(n, ty)| match fields_map.get(&n) { Some(v) => v.clone(), None => { diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs index 9f1de3349a5..c90f94c6d63 100644 --- a/compiler/rustc_mir_build/src/build/mod.rs +++ b/compiler/rustc_mir_build/src/build/mod.rs @@ -252,8 +252,13 @@ fn liberated_closure_env_ty( _ => bug!("closure expr does not have closure type: {:?}", closure_ty), }; - let closure_env_ty = tcx.closure_env_ty(closure_def_id, closure_substs).unwrap(); - tcx.erase_late_bound_regions(closure_env_ty) + let bound_vars = + tcx.mk_bound_variable_kinds(std::iter::once(ty::BoundVariableKind::Region(ty::BrEnv))); + let br = + ty::BoundRegion { var: ty::BoundVar::from_usize(bound_vars.len() - 1), kind: ty::BrEnv }; + let env_region = ty::ReLateBound(ty::INNERMOST, br); + let closure_env_ty = tcx.closure_env_ty(closure_def_id, closure_substs, env_region).unwrap(); + tcx.erase_late_bound_regions(ty::Binder::bind_with_vars(closure_env_ty, bound_vars)) } #[derive(Debug, PartialEq, Eq)] diff --git a/compiler/rustc_mir_build/src/lib.rs b/compiler/rustc_mir_build/src/lib.rs index 9aca005ae91..23bc1da09b5 100644 --- a/compiler/rustc_mir_build/src/lib.rs +++ b/compiler/rustc_mir_build/src/lib.rs @@ -9,6 +9,7 @@ #![feature(control_flow_enum)] #![feature(crate_visibility_modifier)] #![feature(bool_to_option)] +#![feature(iter_zip)] #![feature(once_cell)] #![cfg_attr(bootstrap, feature(or_patterns))] #![recursion_limit = "256"] diff --git a/compiler/rustc_parse/src/parser/attr_wrapper.rs b/compiler/rustc_parse/src/parser/attr_wrapper.rs index 7512f46988c..36a0fda6458 100644 --- a/compiler/rustc_parse/src/parser/attr_wrapper.rs +++ b/compiler/rustc_parse/src/parser/attr_wrapper.rs @@ -98,21 +98,46 @@ impl<'a> Parser<'a> { } impl CreateTokenStream for LazyTokenStreamImpl { fn create_token_stream(&self) -> TokenStream { - // The token produced by the final call to `next` or `next_desugared` - // was not actually consumed by the callback. The combination - // of chaining the initial token and using `take` produces the desired - // result - we produce an empty `TokenStream` if no calls were made, - // and omit the final token otherwise. + if self.num_calls == 0 { + return TokenStream::new(vec![]); + } + let mut cursor_snapshot = self.cursor_snapshot.clone(); - let tokens = std::iter::once(self.start_token.clone()) - .chain((0..self.num_calls).map(|_| { - if self.desugar_doc_comments { + // Don't skip `None` delimiters, since we want to pass them to + // proc macros. Normally, we'll end up capturing `TokenKind::Interpolated`, + // which gets converted to a `None`-delimited group when we invoke + // a proc-macro. However, it's possible to already have a `None`-delimited + // group in the stream (such as when parsing the output of a proc-macro, + // or in certain unusual cases with cross-crate `macro_rules!` macros). + cursor_snapshot.skip_none_delims = false; + + // The token produced by the final call to `next` or `next_desugared` + // was not actually consumed by the callback. + let num_calls = self.num_calls - 1; + let mut i = 0; + let tokens = + std::iter::once(self.start_token.clone()).chain(std::iter::from_fn(|| { + if i >= num_calls { + return None; + } + + let token = if self.desugar_doc_comments { cursor_snapshot.next_desugared() } else { cursor_snapshot.next() + }; + + // When the `LazyTokenStreamImpl` was original produced, we did *not* + // include `NoDelim` tokens in `num_calls`, since they are normally ignored + // by the parser. Therefore, we only increment our counter for other types of tokens. + if !matches!( + token.0.kind, + token::OpenDelim(token::NoDelim) | token::CloseDelim(token::NoDelim) + ) { + i += 1; } - })) - .take(self.num_calls); + Some(token) + })); make_token_stream(tokens, self.append_unglued_token.clone()) } diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index f0ee76d328c..748a8e2bb49 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -172,6 +172,13 @@ struct TokenCursor { // appended to the captured stream when // we evaluate a `LazyTokenStream` append_unglued_token: Option<TreeAndSpacing>, + // If `true`, skip the delimiters for `None`-delimited groups, + // and just yield the inner tokens. This is `true` during + // normal parsing, since the parser code is not currently prepared + // to handle `None` delimiters. When capturing a `TokenStream`, + // however, we want to handle `None`-delimiters, since + // proc-macros always see `None`-delimited groups. + skip_none_delims: bool, } #[derive(Clone)] @@ -184,13 +191,13 @@ struct TokenCursorFrame { } impl TokenCursorFrame { - fn new(span: DelimSpan, delim: DelimToken, tts: TokenStream) -> Self { + fn new(span: DelimSpan, delim: DelimToken, tts: TokenStream, skip_none_delims: bool) -> Self { TokenCursorFrame { delim, span, - open_delim: delim == token::NoDelim, + open_delim: delim == token::NoDelim && skip_none_delims, tree_cursor: tts.into_trees(), - close_delim: delim == token::NoDelim, + close_delim: delim == token::NoDelim && skip_none_delims, } } } @@ -218,7 +225,7 @@ impl TokenCursor { return (token, spacing); } TokenTree::Delimited(sp, delim, tts) => { - let frame = TokenCursorFrame::new(sp, delim, tts); + let frame = TokenCursorFrame::new(sp, delim, tts, self.skip_none_delims); self.stack.push(mem::replace(&mut self.frame, frame)); } } @@ -276,6 +283,7 @@ impl TokenCursor { .cloned() .collect::<TokenStream>() }, + self.skip_none_delims, ), )); @@ -371,12 +379,19 @@ impl<'a> Parser<'a> { prev_token: Token::dummy(), restrictions: Restrictions::empty(), expected_tokens: Vec::new(), + // Skip over the delimiters for `None`-delimited groups token_cursor: TokenCursor { - frame: TokenCursorFrame::new(DelimSpan::dummy(), token::NoDelim, tokens), + frame: TokenCursorFrame::new( + DelimSpan::dummy(), + token::NoDelim, + tokens, + /* skip_none_delims */ true, + ), stack: Vec::new(), num_next_calls: 0, desugar_doc_comments, append_unglued_token: None, + skip_none_delims: true, }, desugar_doc_comments, unmatched_angle_bracket_count: 0, diff --git a/compiler/rustc_parse_format/src/lib.rs b/compiler/rustc_parse_format/src/lib.rs index a5fdf064e94..50db69f4209 100644 --- a/compiler/rustc_parse_format/src/lib.rs +++ b/compiler/rustc_parse_format/src/lib.rs @@ -213,11 +213,13 @@ impl<'a> Iterator for Parser<'a> { Some(String(self.string(pos + 1))) } else { let arg = self.argument(); - if let Some(end) = self.must_consume('}') { - let start = self.to_span_index(pos); - let end = self.to_span_index(end + 1); + if let Some(rbrace_byte_idx) = self.must_consume('}') { + let lbrace_inner_offset = self.to_span_index(pos); + let rbrace_inner_offset = self.to_span_index(rbrace_byte_idx); if self.is_literal { - self.arg_places.push(start.to(end)); + self.arg_places.push( + lbrace_inner_offset.to(InnerOffset(rbrace_inner_offset.0 + 1)), + ); } } Some(NextArgument(arg)) diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 85add83f88b..d1a3971f569 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -9,7 +9,7 @@ use rustc_middle::ty::query::Providers; use rustc_middle::ty::TyCtxt; use rustc_ast::{Attribute, Lit, LitKind, NestedMetaItem}; -use rustc_errors::{pluralize, struct_span_err}; +use rustc_errors::{pluralize, struct_span_err, Applicability}; use rustc_hir as hir; use rustc_hir::def_id::LocalDefId; use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; @@ -648,10 +648,10 @@ impl CheckAttrVisitor<'tcx> { | sym::masked | sym::no_default_passes | sym::no_inline + | sym::notable_trait | sym::passes | sym::plugins | sym::primitive - | sym::spotlight | sym::test => {} _ => { @@ -660,11 +660,23 @@ impl CheckAttrVisitor<'tcx> { hir_id, i_meta.span, |lint| { - let msg = format!( + let mut diag = lint.build(&format!( "unknown `doc` attribute `{}`", rustc_ast_pretty::pprust::path_to_string(&i_meta.path), - ); - lint.build(&msg).emit(); + )); + if i_meta.has_name(sym::spotlight) { + diag.note( + "`doc(spotlight)` was renamed to `doc(notable_trait)`", + ); + diag.span_suggestion_short( + i_meta.span, + "use `notable_trait` instead", + String::from("notable_trait"), + Applicability::MachineApplicable, + ); + diag.note("`doc(spotlight)` is now a no-op"); + } + diag.emit(); }, ); is_valid = false; diff --git a/compiler/rustc_passes/src/entry.rs b/compiler/rustc_passes/src/entry.rs index 57848208f94..e53f821e6da 100644 --- a/compiler/rustc_passes/src/entry.rs +++ b/compiler/rustc_passes/src/entry.rs @@ -171,7 +171,7 @@ fn configure_main( } fn no_main_err(tcx: TyCtxt<'_>, visitor: &EntryContext<'_, '_>) { - let sp = tcx.hir().krate().item.span; + let sp = tcx.hir().krate().item.inner; if *tcx.sess.parse_sess.reached_eof.borrow() { // There's an unclosed brace that made the parser reach `Eof`, we shouldn't complain about // the missing `fn main()` then as it might have been hidden inside an unclosed block. diff --git a/compiler/rustc_passes/src/lib.rs b/compiler/rustc_passes/src/lib.rs index 7ad6bd2bb36..933e8ad1d72 100644 --- a/compiler/rustc_passes/src/lib.rs +++ b/compiler/rustc_passes/src/lib.rs @@ -9,6 +9,7 @@ #![feature(const_panic)] #![feature(crate_visibility_modifier)] #![feature(in_band_lifetimes)] +#![feature(iter_zip)] #![feature(nll)] #![cfg_attr(bootstrap, feature(or_patterns))] #![recursion_limit = "256"] diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs index 9aef49df7b4..f24309fa950 100644 --- a/compiler/rustc_passes/src/liveness.rs +++ b/compiler/rustc_passes/src/liveness.rs @@ -103,6 +103,7 @@ use rustc_span::Span; use std::collections::VecDeque; use std::io; use std::io::prelude::*; +use std::iter; use std::rc::Rc; mod rwu_table; @@ -1093,7 +1094,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { let ia = &asm.inner; let outputs = asm.outputs_exprs; let inputs = asm.inputs_exprs; - let succ = ia.outputs.iter().zip(outputs).rev().fold(succ, |succ, (o, output)| { + let succ = iter::zip(&ia.outputs, outputs).rev().fold(succ, |succ, (o, output)| { // see comment on places // in propagate_through_place_components() if o.is_indirect { @@ -1344,7 +1345,7 @@ fn check_expr<'tcx>(this: &mut Liveness<'_, 'tcx>, expr: &'tcx Expr<'tcx>) { } // Output operands must be places - for (o, output) in asm.inner.outputs.iter().zip(asm.outputs_exprs) { + for (o, output) in iter::zip(&asm.inner.outputs, asm.outputs_exprs) { if !o.is_indirect { this.check_place(output); } diff --git a/compiler/rustc_passes/src/liveness/rwu_table.rs b/compiler/rustc_passes/src/liveness/rwu_table.rs index a1a6f27398e..6d5983f53dc 100644 --- a/compiler/rustc_passes/src/liveness/rwu_table.rs +++ b/compiler/rustc_passes/src/liveness/rwu_table.rs @@ -1,4 +1,5 @@ use crate::liveness::{LiveNode, Variable}; +use std::iter; #[derive(Clone, Copy)] pub(super) struct RWU { @@ -91,7 +92,7 @@ impl RWUTable { let mut changed = false; let (dst_row, src_row) = self.pick2_rows_mut(dst, src); - for (dst_word, src_word) in dst_row.iter_mut().zip(src_row.iter()) { + for (dst_word, src_word) in iter::zip(dst_row, &*src_row) { let old = *dst_word; let new = *dst_word | src_word; *dst_word = new; diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index 8a6ac843534..9c4f9b1198c 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -22,6 +22,7 @@ use rustc_span::symbol::{sym, Symbol}; use rustc_span::{Span, DUMMY_SP}; use std::cmp::Ordering; +use std::iter; use std::mem::replace; use std::num::NonZeroU32; @@ -214,7 +215,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { { // Explicit version of iter::order::lt to handle parse errors properly for (dep_v, stab_v) in - dep_since.as_str().split('.').zip(stab_since.as_str().split('.')) + iter::zip(dep_since.as_str().split('.'), stab_since.as_str().split('.')) { match stab_v.parse::<u64>() { Err(_) => { @@ -685,7 +686,7 @@ fn new_index(tcx: TyCtxt<'tcx>) -> Index<'tcx> { annotator.annotate( hir::CRATE_HIR_ID, - krate.item.span, + krate.item.inner, AnnotationKind::Required, InheritDeprecation::Yes, InheritConstStability::No, @@ -884,7 +885,7 @@ pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) { if tcx.stability().staged_api[&LOCAL_CRATE] { let krate = tcx.hir().krate(); let mut missing = MissingStabilityAnnotations { tcx, access_levels }; - missing.check_missing_stability(hir::CRATE_HIR_ID, krate.item.span); + missing.check_missing_stability(hir::CRATE_HIR_ID, krate.item.inner); intravisit::walk_crate(&mut missing, krate); krate.visit_all_item_likes(&mut missing.as_deep_visitor()); } diff --git a/compiler/rustc_query_impl/src/lib.rs b/compiler/rustc_query_impl/src/lib.rs index e9314797fbd..00d886000fa 100644 --- a/compiler/rustc_query_impl/src/lib.rs +++ b/compiler/rustc_query_impl/src/lib.rs @@ -19,8 +19,7 @@ extern crate tracing; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_errors::{DiagnosticBuilder, Handler}; -use rustc_hir::def_id::CrateNum; -use rustc_index::vec::IndexVec; +use rustc_hir::def_id::LOCAL_CRATE; use rustc_middle::dep_graph; use rustc_middle::ich::StableHashingContext; use rustc_middle::ty::query::{query_keys, query_storage, query_stored, query_values}; diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs index 37a176de941..4194b28dc7d 100644 --- a/compiler/rustc_query_impl/src/plumbing.rs +++ b/compiler/rustc_query_impl/src/plumbing.rs @@ -390,13 +390,12 @@ macro_rules! define_queries { #[inline] fn compute(tcx: QueryCtxt<'tcx>, key: Self::Key) -> Self::Value { - let provider = tcx.queries.providers.get(key.query_crate()) - // HACK(eddyb) it's possible crates may be loaded after - // the query engine is created, and because crate loading - // is not yet integrated with the query engine, such crates - // would be missing appropriate entries in `providers`. - .unwrap_or(&tcx.queries.fallback_extern_providers) - .$name; + let is_local = key.query_crate() == LOCAL_CRATE; + let provider = if is_local { + tcx.queries.local_providers.$name + } else { + tcx.queries.extern_providers.$name + }; provider(*tcx, key) } @@ -478,10 +477,7 @@ macro_rules! define_queries { return } - debug_assert!(tcx.dep_graph - .node_color(dep_node) - .map(|c| c.is_green()) - .unwrap_or(false)); + debug_assert!(tcx.dep_graph.is_green(dep_node)); let key = recover(*tcx, dep_node).unwrap_or_else(|| panic!("Failed to recover key for {:?} with hash {}", dep_node, dep_node.hash)); if queries::$name::cache_on_disk(tcx, &key, None) { @@ -507,8 +503,8 @@ macro_rules! define_queries_struct { (tcx: $tcx:tt, input: ($(([$($modifiers:tt)*] [$($attr:tt)*] [$name:ident]))*)) => { pub struct Queries<$tcx> { - providers: IndexVec<CrateNum, Providers>, - fallback_extern_providers: Box<Providers>, + local_providers: Box<Providers>, + extern_providers: Box<Providers>, $($(#[$attr])* $name: QueryState< crate::dep_graph::DepKind, @@ -518,12 +514,12 @@ macro_rules! define_queries_struct { impl<$tcx> Queries<$tcx> { pub fn new( - providers: IndexVec<CrateNum, Providers>, - fallback_extern_providers: Providers, + local_providers: Providers, + extern_providers: Providers, ) -> Self { Queries { - providers, - fallback_extern_providers: Box::new(fallback_extern_providers), + local_providers: Box::new(local_providers), + extern_providers: Box::new(extern_providers), $($name: Default::default()),* } } diff --git a/compiler/rustc_query_system/src/cache.rs b/compiler/rustc_query_system/src/cache.rs index c6dc7b4fe28..d592812f79b 100644 --- a/compiler/rustc_query_system/src/cache.rs +++ b/compiler/rustc_query_system/src/cache.rs @@ -3,7 +3,6 @@ use crate::dep_graph::{DepContext, DepNodeIndex}; use rustc_data_structures::fx::FxHashMap; -use rustc_data_structures::sync::HashMapExt; use rustc_data_structures::sync::Lock; use std::hash::Hash; @@ -34,13 +33,6 @@ impl<Key: Eq + Hash, Value: Clone> Cache<Key, Value> { pub fn insert(&self, key: Key, dep_node: DepNodeIndex, value: Value) { self.hashmap.borrow_mut().insert(key, WithDepNode::new(dep_node, value)); } - - pub fn insert_same(&self, key: Key, dep_node: DepNodeIndex, value: Value) - where - Value: Eq, - { - self.hashmap.borrow_mut().insert_same(key, WithDepNode::new(dep_node, value)); - } } #[derive(Clone, Eq, PartialEq)] diff --git a/compiler/rustc_query_system/src/dep_graph/debug.rs b/compiler/rustc_query_system/src/dep_graph/debug.rs index 718a2f1039a..a544ac2c343 100644 --- a/compiler/rustc_query_system/src/dep_graph/debug.rs +++ b/compiler/rustc_query_system/src/dep_graph/debug.rs @@ -1,6 +1,8 @@ //! Code for debugging the dep-graph. -use super::{DepKind, DepNode}; +use super::{DepKind, DepNode, DepNodeIndex}; +use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::sync::Lock; use std::error::Error; /// A dep-node filter goes from a user-defined string to a query over @@ -34,13 +36,14 @@ impl DepNodeFilter { /// A filter like `F -> G` where `F` and `G` are valid dep-node /// filters. This can be used to test the source/target independently. -pub struct EdgeFilter { +pub struct EdgeFilter<K: DepKind> { pub source: DepNodeFilter, pub target: DepNodeFilter, + pub index_to_node: Lock<FxHashMap<DepNodeIndex, DepNode<K>>>, } -impl EdgeFilter { - pub fn new(test: &str) -> Result<EdgeFilter, Box<dyn Error>> { +impl<K: DepKind> EdgeFilter<K> { + pub fn new(test: &str) -> Result<EdgeFilter<K>, Box<dyn Error>> { let parts: Vec<_> = test.split("->").collect(); if parts.len() != 2 { Err(format!("expected a filter like `a&b -> c&d`, not `{}`", test).into()) @@ -48,11 +51,13 @@ impl EdgeFilter { Ok(EdgeFilter { source: DepNodeFilter::new(parts[0]), target: DepNodeFilter::new(parts[1]), + index_to_node: Lock::new(FxHashMap::default()), }) } } - pub fn test<K: DepKind>(&self, source: &DepNode<K>, target: &DepNode<K>) -> bool { + #[cfg(debug_assertions)] + pub fn test(&self, source: &DepNode<K>, target: &DepNode<K>) -> bool { self.source.test(source) && self.target.test(target) } } diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs index 0f25572170f..7a0fc320663 100644 --- a/compiler/rustc_query_system/src/dep_graph/graph.rs +++ b/compiler/rustc_query_system/src/dep_graph/graph.rs @@ -1,31 +1,33 @@ use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::profiling::QueryInvocationId; +use rustc_data_structures::profiling::SelfProfilerRef; use rustc_data_structures::sharded::{self, Sharded}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; -use rustc_data_structures::sync::{AtomicU32, AtomicU64, Lock, LockGuard, Lrc, Ordering}; +use rustc_data_structures::steal::Steal; +use rustc_data_structures::sync::{AtomicU32, AtomicU64, Lock, Lrc, Ordering}; use rustc_data_structures::unlikely; use rustc_errors::Diagnostic; -use rustc_index::vec::{Idx, IndexVec}; -use rustc_serialize::{Encodable, Encoder}; +use rustc_index::vec::IndexVec; +use rustc_serialize::opaque::{FileEncodeResult, FileEncoder}; use parking_lot::{Condvar, Mutex}; use smallvec::{smallvec, SmallVec}; use std::collections::hash_map::Entry; -use std::env; use std::hash::Hash; use std::marker::PhantomData; use std::mem; -use std::ops::Range; use std::sync::atomic::Ordering::Relaxed; -use super::debug::EdgeFilter; use super::prev::PreviousDepGraph; use super::query::DepGraphQuery; -use super::serialized::SerializedDepNodeIndex; +use super::serialized::{GraphEncoder, SerializedDepNodeIndex}; use super::{DepContext, DepKind, DepNode, HasDepContext, WorkProductId}; use crate::query::QueryContext; +#[cfg(debug_assertions)] +use {super::debug::EdgeFilter, std::env}; + #[derive(Clone)] pub struct DepGraph<K: DepKind> { data: Option<Lrc<DepGraphData<K>>>, @@ -109,6 +111,9 @@ impl<K: DepKind> DepGraph<K> { pub fn new( prev_graph: PreviousDepGraph<K>, prev_work_products: FxHashMap<WorkProductId, WorkProduct>, + encoder: FileEncoder, + record_graph: bool, + record_stats: bool, ) -> DepGraph<K> { let prev_graph_node_count = prev_graph.node_count(); @@ -116,7 +121,12 @@ impl<K: DepKind> DepGraph<K> { data: Some(Lrc::new(DepGraphData { previous_work_products: prev_work_products, dep_node_debug: Default::default(), - current: CurrentDepGraph::new(prev_graph_node_count), + current: CurrentDepGraph::new( + prev_graph_node_count, + encoder, + record_graph, + record_stats, + ), emitting_diagnostics: Default::default(), emitting_diagnostics_cond_var: Condvar::new(), previous: prev_graph, @@ -136,62 +146,10 @@ impl<K: DepKind> DepGraph<K> { self.data.is_some() } - pub fn query(&self) -> DepGraphQuery<K> { - let data = self.data.as_ref().unwrap(); - let previous = &data.previous; - - // Note locking order: `prev_index_to_index`, then `data`. - let prev_index_to_index = data.current.prev_index_to_index.lock(); - let data = data.current.data.lock(); - let node_count = data.hybrid_indices.len(); - let edge_count = self.edge_count(&data); - - let mut nodes = Vec::with_capacity(node_count); - let mut edge_list_indices = Vec::with_capacity(node_count); - let mut edge_list_data = Vec::with_capacity(edge_count); - - // See `DepGraph`'s `Encodable` implementation for notes on the approach used here. - - edge_list_data.extend(data.unshared_edges.iter().map(|i| i.index())); - - for &hybrid_index in data.hybrid_indices.iter() { - match hybrid_index.into() { - HybridIndex::New(new_index) => { - nodes.push(data.new.nodes[new_index]); - let edges = &data.new.edges[new_index]; - edge_list_indices.push((edges.start.index(), edges.end.index())); - } - HybridIndex::Red(red_index) => { - nodes.push(previous.index_to_node(data.red.node_indices[red_index])); - let edges = &data.red.edges[red_index]; - edge_list_indices.push((edges.start.index(), edges.end.index())); - } - HybridIndex::LightGreen(lg_index) => { - nodes.push(previous.index_to_node(data.light_green.node_indices[lg_index])); - let edges = &data.light_green.edges[lg_index]; - edge_list_indices.push((edges.start.index(), edges.end.index())); - } - HybridIndex::DarkGreen(prev_index) => { - nodes.push(previous.index_to_node(prev_index)); - - let edges_iter = previous - .edge_targets_from(prev_index) - .iter() - .map(|&dst| prev_index_to_index[dst].unwrap().index()); - - let start = edge_list_data.len(); - edge_list_data.extend(edges_iter); - let end = edge_list_data.len(); - edge_list_indices.push((start, end)); - } - } + pub fn with_query(&self, f: impl Fn(&DepGraphQuery<K>)) { + if let Some(data) = &self.data { + data.current.encoder.borrow().with_query(f) } - - debug_assert_eq!(nodes.len(), node_count); - debug_assert_eq!(edge_list_indices.len(), node_count); - debug_assert_eq!(edge_list_data.len(), edge_count); - - DepGraphQuery::new(&nodes[..], &edge_list_indices[..], &edge_list_data[..]) } pub fn assert_ignored(&self) { @@ -283,56 +241,16 @@ impl<K: DepKind> DepGraph<K> { let print_status = cfg!(debug_assertions) && dcx.sess().opts.debugging_opts.dep_tasks; // Intern the new `DepNode`. - let dep_node_index = if let Some(prev_index) = data.previous.node_to_index_opt(&key) { - // Determine the color and index of the new `DepNode`. - let (color, dep_node_index) = if let Some(current_fingerprint) = current_fingerprint - { - if current_fingerprint == data.previous.fingerprint_by_index(prev_index) { - if print_status { - eprintln!("[task::green] {:?}", key); - } - - // This is a light green node: it existed in the previous compilation, - // its query was re-executed, and it has the same result as before. - let dep_node_index = - data.current.intern_light_green_node(&data.previous, prev_index, edges); - - (DepNodeColor::Green(dep_node_index), dep_node_index) - } else { - if print_status { - eprintln!("[task::red] {:?}", key); - } - - // This is a red node: it existed in the previous compilation, its query - // was re-executed, but it has a different result from before. - let dep_node_index = data.current.intern_red_node( - &data.previous, - prev_index, - edges, - current_fingerprint, - ); - - (DepNodeColor::Red, dep_node_index) - } - } else { - if print_status { - eprintln!("[task::unknown] {:?}", key); - } - - // This is a red node, effectively: it existed in the previous compilation - // session, its query was re-executed, but it doesn't compute a result hash - // (i.e. it represents a `no_hash` query), so we have no way of determining - // whether or not the result was the same as before. - let dep_node_index = data.current.intern_red_node( - &data.previous, - prev_index, - edges, - Fingerprint::ZERO, - ); - - (DepNodeColor::Red, dep_node_index) - }; + let (dep_node_index, prev_and_color) = data.current.intern_node( + dcx.profiler(), + &data.previous, + key, + edges, + current_fingerprint, + print_status, + ); + if let Some((prev_index, color)) = prev_and_color { debug_assert!( data.colors.get(prev_index).is_none(), "DepGraph::with_task() - Duplicate DepNodeColor \ @@ -341,20 +259,7 @@ impl<K: DepKind> DepGraph<K> { ); data.colors.insert(prev_index, color); - dep_node_index - } else { - if print_status { - eprintln!("[task::new] {:?}", key); - } - - // This is a new node: it didn't exist in the previous compilation session. - data.current.intern_new_node( - &data.previous, - key, - edges, - current_fingerprint.unwrap_or(Fingerprint::ZERO), - ) - }; + } (result, dep_node_index) } else { @@ -368,7 +273,12 @@ impl<K: DepKind> DepGraph<K> { /// Executes something within an "anonymous" task, that is, a task the /// `DepNode` of which is determined by the list of inputs it read from. - pub fn with_anon_task<OP, R>(&self, dep_kind: K, op: OP) -> (R, DepNodeIndex) + pub fn with_anon_task<Ctxt: DepContext<DepKind = K>, OP, R>( + &self, + cx: Ctxt, + dep_kind: K, + op: OP, + ) -> (R, DepNodeIndex) where OP: FnOnce() -> R, { @@ -396,7 +306,7 @@ impl<K: DepKind> DepGraph<K> { }; let dep_node_index = data.current.intern_new_node( - &data.previous, + cx.profiler(), target_dep_node, task_deps.reads, Fingerprint::ZERO, @@ -451,7 +361,7 @@ impl<K: DepKind> DepGraph<K> { { if let Some(target) = task_deps.node { if let Some(ref forbidden_edge) = data.current.forbidden_edge { - let src = self.dep_node_of(dep_node_index); + let src = forbidden_edge.index_to_node.lock()[&dep_node_index]; if forbidden_edge.test(&src, &target) { panic!("forbidden edge {:?} -> {:?} created", src, target) } @@ -488,38 +398,6 @@ impl<K: DepKind> DepGraph<K> { self.data.is_some() && self.dep_node_index_of_opt(dep_node).is_some() } - #[inline] - pub fn dep_node_of(&self, dep_node_index: DepNodeIndex) -> DepNode<K> { - let data = self.data.as_ref().unwrap(); - let previous = &data.previous; - let data = data.current.data.lock(); - - match data.hybrid_indices[dep_node_index].into() { - HybridIndex::New(new_index) => data.new.nodes[new_index], - HybridIndex::Red(red_index) => previous.index_to_node(data.red.node_indices[red_index]), - HybridIndex::LightGreen(light_green_index) => { - previous.index_to_node(data.light_green.node_indices[light_green_index]) - } - HybridIndex::DarkGreen(prev_index) => previous.index_to_node(prev_index), - } - } - - #[inline] - pub fn fingerprint_of(&self, dep_node_index: DepNodeIndex) -> Fingerprint { - let data = self.data.as_ref().unwrap(); - let previous = &data.previous; - let data = data.current.data.lock(); - - match data.hybrid_indices[dep_node_index].into() { - HybridIndex::New(new_index) => data.new.fingerprints[new_index], - HybridIndex::Red(red_index) => data.red.fingerprints[red_index], - HybridIndex::LightGreen(light_green_index) => { - previous.fingerprint_by_index(data.light_green.node_indices[light_green_index]) - } - HybridIndex::DarkGreen(prev_index) => previous.fingerprint_by_index(prev_index), - } - } - pub fn prev_fingerprint_of(&self, dep_node: &DepNode<K>) -> Option<Fingerprint> { self.data.as_ref().unwrap().previous.fingerprint_of(dep_node) } @@ -554,29 +432,13 @@ impl<K: DepKind> DepGraph<K> { self.data.as_ref()?.dep_node_debug.borrow().get(&dep_node).cloned() } - fn edge_count(&self, node_data: &LockGuard<'_, DepNodeData<K>>) -> usize { - let data = self.data.as_ref().unwrap(); - let previous = &data.previous; - - let mut edge_count = node_data.unshared_edges.len(); - - for &hybrid_index in node_data.hybrid_indices.iter() { - if let HybridIndex::DarkGreen(prev_index) = hybrid_index.into() { - edge_count += previous.edge_targets_from(prev_index).len() - } - } - - edge_count - } - - pub fn node_color(&self, dep_node: &DepNode<K>) -> Option<DepNodeColor> { + fn node_color(&self, dep_node: &DepNode<K>) -> Option<DepNodeColor> { if let Some(ref data) = self.data { if let Some(prev_index) = data.previous.node_to_index_opt(dep_node) { return data.colors.get(prev_index); } else { - // This is a node that did not exist in the previous compilation - // session, so we consider it to be red. - return Some(DepNodeColor::Red); + // This is a node that did not exist in the previous compilation session. + return None; } } @@ -775,11 +637,13 @@ impl<K: DepKind> DepGraph<K> { // There may be multiple threads trying to mark the same dep node green concurrently - let dep_node_index = { - // We allocating an entry for the node in the current dependency graph and - // adding all the appropriate edges imported from the previous graph - data.current.intern_dark_green_node(&data.previous, prev_dep_node_index) - }; + // We allocating an entry for the node in the current dependency graph and + // adding all the appropriate edges imported from the previous graph + let dep_node_index = data.current.promote_node_and_deps_to_current( + tcx.dep_context().profiler(), + &data.previous, + prev_dep_node_index, + ); // ... emitting any stored diagnostic ... @@ -862,6 +726,12 @@ impl<K: DepKind> DepGraph<K> { } } + // Returns true if the given node has been marked as red during the + // current compilation session. Used in various assertions + pub fn is_red(&self, dep_node: &DepNode<K>) -> bool { + self.node_color(dep_node) == Some(DepNodeColor::Red) + } + // Returns true if the given node has been marked as green during the // current compilation session. Used in various assertions pub fn is_green(&self, dep_node: &DepNode<K>) -> bool { @@ -911,106 +781,20 @@ impl<K: DepKind> DepGraph<K> { } pub fn print_incremental_info(&self) { - #[derive(Clone)] - struct Stat<Kind: DepKind> { - kind: Kind, - node_counter: u64, - edge_counter: u64, + if let Some(data) = &self.data { + data.current.encoder.borrow().print_incremental_info( + data.current.total_read_count.load(Relaxed), + data.current.total_duplicate_read_count.load(Relaxed), + ) } + } - let data = self.data.as_ref().unwrap(); - let prev = &data.previous; - let current = &data.current; - let data = current.data.lock(); - - let mut stats: FxHashMap<_, Stat<K>> = FxHashMap::with_hasher(Default::default()); - - for &hybrid_index in data.hybrid_indices.iter() { - let (kind, edge_count) = match hybrid_index.into() { - HybridIndex::New(new_index) => { - let kind = data.new.nodes[new_index].kind; - let edge_range = &data.new.edges[new_index]; - (kind, edge_range.end.as_usize() - edge_range.start.as_usize()) - } - HybridIndex::Red(red_index) => { - let kind = prev.index_to_node(data.red.node_indices[red_index]).kind; - let edge_range = &data.red.edges[red_index]; - (kind, edge_range.end.as_usize() - edge_range.start.as_usize()) - } - HybridIndex::LightGreen(lg_index) => { - let kind = prev.index_to_node(data.light_green.node_indices[lg_index]).kind; - let edge_range = &data.light_green.edges[lg_index]; - (kind, edge_range.end.as_usize() - edge_range.start.as_usize()) - } - HybridIndex::DarkGreen(prev_index) => { - let kind = prev.index_to_node(prev_index).kind; - let edge_count = prev.edge_targets_from(prev_index).len(); - (kind, edge_count) - } - }; - - let stat = stats.entry(kind).or_insert(Stat { kind, node_counter: 0, edge_counter: 0 }); - stat.node_counter += 1; - stat.edge_counter += edge_count as u64; - } - - let total_node_count = data.hybrid_indices.len(); - let total_edge_count = self.edge_count(&data); - - // Drop the lock guard. - std::mem::drop(data); - - let mut stats: Vec<_> = stats.values().cloned().collect(); - stats.sort_by_key(|s| -(s.node_counter as i64)); - - const SEPARATOR: &str = "[incremental] --------------------------------\ - ----------------------------------------------\ - ------------"; - - eprintln!("[incremental]"); - eprintln!("[incremental] DepGraph Statistics"); - eprintln!("{}", SEPARATOR); - eprintln!("[incremental]"); - eprintln!("[incremental] Total Node Count: {}", total_node_count); - eprintln!("[incremental] Total Edge Count: {}", total_edge_count); - - if cfg!(debug_assertions) { - let total_edge_reads = current.total_read_count.load(Relaxed); - let total_duplicate_edge_reads = current.total_duplicate_read_count.load(Relaxed); - - eprintln!("[incremental] Total Edge Reads: {}", total_edge_reads); - eprintln!("[incremental] Total Duplicate Edge Reads: {}", total_duplicate_edge_reads); - } - - eprintln!("[incremental]"); - - eprintln!( - "[incremental] {:<36}| {:<17}| {:<12}| {:<17}|", - "Node Kind", "Node Frequency", "Node Count", "Avg. Edge Count" - ); - - eprintln!( - "[incremental] -------------------------------------\ - |------------------\ - |-------------\ - |------------------|" - ); - - for stat in stats { - let node_kind_ratio = (100.0 * (stat.node_counter as f64)) / (total_node_count as f64); - let node_kind_avg_edges = (stat.edge_counter as f64) / (stat.node_counter as f64); - - eprintln!( - "[incremental] {:<36}|{:>16.1}% |{:>12} |{:>17.1} |", - format!("{:?}", stat.kind), - node_kind_ratio, - stat.node_counter, - node_kind_avg_edges, - ); + pub fn encode(&self, profiler: &SelfProfilerRef) -> FileEncodeResult { + if let Some(data) = &self.data { + data.current.encoder.steal().finish(profiler) + } else { + Ok(()) } - - eprintln!("{}", SEPARATOR); - eprintln!("[incremental]"); } fn next_virtual_depnode_index(&self) -> DepNodeIndex { @@ -1019,142 +803,6 @@ impl<K: DepKind> DepGraph<K> { } } -impl<E: Encoder, K: DepKind + Encodable<E>> Encodable<E> for DepGraph<K> { - fn encode(&self, e: &mut E) -> Result<(), E::Error> { - // We used to serialize the dep graph by creating and serializing a `SerializedDepGraph` - // using data copied from the `DepGraph`. But copying created a large memory spike, so we - // now serialize directly from the `DepGraph` as if it's a `SerializedDepGraph`. Because we - // deserialize that data into a `SerializedDepGraph` in the next compilation session, we - // need `DepGraph`'s `Encodable` and `SerializedDepGraph`'s `Decodable` implementations to - // be in sync. If you update this encoding, be sure to update the decoding, and vice-versa. - - let data = self.data.as_ref().unwrap(); - let prev = &data.previous; - - // Note locking order: `prev_index_to_index`, then `data`. - let prev_index_to_index = data.current.prev_index_to_index.lock(); - let data = data.current.data.lock(); - let new = &data.new; - let red = &data.red; - let lg = &data.light_green; - - let node_count = data.hybrid_indices.len(); - let edge_count = self.edge_count(&data); - - // `rustc_middle::ty::query::OnDiskCache` expects nodes to be encoded in `DepNodeIndex` - // order. The edges in `edge_list_data` don't need to be in a particular order, as long as - // each node references its edges as a contiguous range within it. Therefore, we can encode - // `edge_list_data` directly from `unshared_edges`. It meets the above requirements, as - // each non-dark-green node already knows the range of edges to reference within it, which - // they'll encode in `edge_list_indices`. Dark green nodes, however, don't have their edges - // in `unshared_edges`, so need to add them to `edge_list_data`. - - use HybridIndex::*; - - // Encoded values (nodes, etc.) are explicitly typed below to avoid inadvertently - // serializing data in the wrong format (i.e. one incompatible with `SerializedDepGraph`). - e.emit_struct("SerializedDepGraph", 4, |e| { - e.emit_struct_field("nodes", 0, |e| { - // `SerializedDepGraph` expects this to be encoded as a sequence of `DepNode`s. - e.emit_seq(node_count, |e| { - for (seq_index, &hybrid_index) in data.hybrid_indices.iter().enumerate() { - let node: DepNode<K> = match hybrid_index.into() { - New(i) => new.nodes[i], - Red(i) => prev.index_to_node(red.node_indices[i]), - LightGreen(i) => prev.index_to_node(lg.node_indices[i]), - DarkGreen(prev_index) => prev.index_to_node(prev_index), - }; - - e.emit_seq_elt(seq_index, |e| node.encode(e))?; - } - - Ok(()) - }) - })?; - - e.emit_struct_field("fingerprints", 1, |e| { - // `SerializedDepGraph` expects this to be encoded as a sequence of `Fingerprints`s. - e.emit_seq(node_count, |e| { - for (seq_index, &hybrid_index) in data.hybrid_indices.iter().enumerate() { - let fingerprint: Fingerprint = match hybrid_index.into() { - New(i) => new.fingerprints[i], - Red(i) => red.fingerprints[i], - LightGreen(i) => prev.fingerprint_by_index(lg.node_indices[i]), - DarkGreen(prev_index) => prev.fingerprint_by_index(prev_index), - }; - - e.emit_seq_elt(seq_index, |e| fingerprint.encode(e))?; - } - - Ok(()) - }) - })?; - - e.emit_struct_field("edge_list_indices", 2, |e| { - // `SerializedDepGraph` expects this to be encoded as a sequence of `(u32, u32)`s. - e.emit_seq(node_count, |e| { - // Dark green node edges start after the unshared (all other nodes') edges. - let mut dark_green_edge_index = data.unshared_edges.len(); - - for (seq_index, &hybrid_index) in data.hybrid_indices.iter().enumerate() { - let edge_indices: (u32, u32) = match hybrid_index.into() { - New(i) => (new.edges[i].start.as_u32(), new.edges[i].end.as_u32()), - Red(i) => (red.edges[i].start.as_u32(), red.edges[i].end.as_u32()), - LightGreen(i) => (lg.edges[i].start.as_u32(), lg.edges[i].end.as_u32()), - DarkGreen(prev_index) => { - let edge_count = prev.edge_targets_from(prev_index).len(); - let start = dark_green_edge_index as u32; - dark_green_edge_index += edge_count; - let end = dark_green_edge_index as u32; - (start, end) - } - }; - - e.emit_seq_elt(seq_index, |e| edge_indices.encode(e))?; - } - - assert_eq!(dark_green_edge_index, edge_count); - - Ok(()) - }) - })?; - - e.emit_struct_field("edge_list_data", 3, |e| { - // `SerializedDepGraph` expects this to be encoded as a sequence of - // `SerializedDepNodeIndex`. - e.emit_seq(edge_count, |e| { - for (seq_index, &edge) in data.unshared_edges.iter().enumerate() { - let serialized_edge = SerializedDepNodeIndex::new(edge.index()); - e.emit_seq_elt(seq_index, |e| serialized_edge.encode(e))?; - } - - let mut seq_index = data.unshared_edges.len(); - - for &hybrid_index in data.hybrid_indices.iter() { - if let DarkGreen(prev_index) = hybrid_index.into() { - for &edge in prev.edge_targets_from(prev_index) { - // Dark green node edges are stored in the previous graph - // and must be converted to edges in the current graph, - // and then serialized as `SerializedDepNodeIndex`. - let serialized_edge = SerializedDepNodeIndex::new( - prev_index_to_index[edge].as_ref().unwrap().index(), - ); - - e.emit_seq_elt(seq_index, |e| serialized_edge.encode(e))?; - seq_index += 1; - } - } - } - - assert_eq!(seq_index, edge_count); - - Ok(()) - }) - }) - }) - } -} - /// A "work product" is an intermediate result that we save into the /// incremental directory for later re-use. The primary example are /// the object files that we save for each partition at code @@ -1193,216 +841,20 @@ pub struct WorkProduct { pub saved_file: Option<String>, } -// The maximum value of the follow index types leaves the upper two bits unused -// so that we can store multiple index types in `CompressedHybridIndex`, and use -// those bits to encode which index type it contains. - -// Index type for `NewDepNodeData`. -rustc_index::newtype_index! { - struct NewDepNodeIndex { - MAX = 0x7FFF_FFFF - } -} - -// Index type for `RedDepNodeData`. -rustc_index::newtype_index! { - struct RedDepNodeIndex { - MAX = 0x7FFF_FFFF - } -} - -// Index type for `LightGreenDepNodeData`. -rustc_index::newtype_index! { - struct LightGreenDepNodeIndex { - MAX = 0x7FFF_FFFF - } -} - -/// Compressed representation of `HybridIndex` enum. Bits unused by the -/// contained index types are used to encode which index type it contains. -#[derive(Copy, Clone)] -struct CompressedHybridIndex(u32); - -impl CompressedHybridIndex { - const NEW_TAG: u32 = 0b0000_0000_0000_0000_0000_0000_0000_0000; - const RED_TAG: u32 = 0b0100_0000_0000_0000_0000_0000_0000_0000; - const LIGHT_GREEN_TAG: u32 = 0b1000_0000_0000_0000_0000_0000_0000_0000; - const DARK_GREEN_TAG: u32 = 0b1100_0000_0000_0000_0000_0000_0000_0000; - - const TAG_MASK: u32 = 0b1100_0000_0000_0000_0000_0000_0000_0000; - const INDEX_MASK: u32 = !Self::TAG_MASK; -} - -impl From<NewDepNodeIndex> for CompressedHybridIndex { - #[inline] - fn from(index: NewDepNodeIndex) -> Self { - CompressedHybridIndex(Self::NEW_TAG | index.as_u32()) - } -} - -impl From<RedDepNodeIndex> for CompressedHybridIndex { - #[inline] - fn from(index: RedDepNodeIndex) -> Self { - CompressedHybridIndex(Self::RED_TAG | index.as_u32()) - } -} - -impl From<LightGreenDepNodeIndex> for CompressedHybridIndex { - #[inline] - fn from(index: LightGreenDepNodeIndex) -> Self { - CompressedHybridIndex(Self::LIGHT_GREEN_TAG | index.as_u32()) - } -} - -impl From<SerializedDepNodeIndex> for CompressedHybridIndex { - #[inline] - fn from(index: SerializedDepNodeIndex) -> Self { - CompressedHybridIndex(Self::DARK_GREEN_TAG | index.as_u32()) - } -} - -/// Contains an index into one of several node data collections. Elsewhere, we -/// store `CompressedHyridIndex` instead of this to save space, but convert to -/// this type during processing to take advantage of the enum match ergonomics. -enum HybridIndex { - New(NewDepNodeIndex), - Red(RedDepNodeIndex), - LightGreen(LightGreenDepNodeIndex), - DarkGreen(SerializedDepNodeIndex), -} - -impl From<CompressedHybridIndex> for HybridIndex { - #[inline] - fn from(hybrid_index: CompressedHybridIndex) -> Self { - let index = hybrid_index.0 & CompressedHybridIndex::INDEX_MASK; - - match hybrid_index.0 & CompressedHybridIndex::TAG_MASK { - CompressedHybridIndex::NEW_TAG => HybridIndex::New(NewDepNodeIndex::from_u32(index)), - CompressedHybridIndex::RED_TAG => HybridIndex::Red(RedDepNodeIndex::from_u32(index)), - CompressedHybridIndex::LIGHT_GREEN_TAG => { - HybridIndex::LightGreen(LightGreenDepNodeIndex::from_u32(index)) - } - CompressedHybridIndex::DARK_GREEN_TAG => { - HybridIndex::DarkGreen(SerializedDepNodeIndex::from_u32(index)) - } - _ => unreachable!(), - } - } -} - // Index type for `DepNodeData`'s edges. rustc_index::newtype_index! { struct EdgeIndex { .. } } -/// Data for nodes in the current graph, divided into different collections -/// based on their presence in the previous graph, and if present, their color. -/// We divide nodes this way because different types of nodes are able to share -/// more or less data with the previous graph. -/// -/// To enable more sharing, we distinguish between two kinds of green nodes. -/// Light green nodes are nodes in the previous graph that have been marked -/// green because we re-executed their queries and the results were the same as -/// in the previous session. Dark green nodes are nodes in the previous graph -/// that have been marked green because we were able to mark all of their -/// dependencies green. -/// -/// Both light and dark green nodes can share the dep node and fingerprint with -/// the previous graph, but for light green nodes, we can't be sure that the -/// edges may be shared without comparing them against the previous edges, so we -/// store them directly (an approach in which we compare edges with the previous -/// edges to see if they can be shared was evaluated, but was not found to be -/// very profitable). -/// -/// For dark green nodes, we can share everything with the previous graph, which -/// is why the `HybridIndex::DarkGreen` enum variant contains the index of the -/// node in the previous graph, and why we don't have a separate collection for -/// dark green node data--the collection is the `PreviousDepGraph` itself. -/// -/// (Note that for dark green nodes, the edges in the previous graph -/// (`SerializedDepNodeIndex`s) must be converted to edges in the current graph -/// (`DepNodeIndex`s). `CurrentDepGraph` contains `prev_index_to_index`, which -/// can perform this conversion. It should always be possible, as by definition, -/// a dark green node is one whose dependencies from the previous session have -/// all been marked green--which means `prev_index_to_index` contains them.) -/// -/// Node data is stored in parallel vectors to eliminate the padding between -/// elements that would be needed to satisfy alignment requirements of the -/// structure that would contain all of a node's data. We could group tightly -/// packing subsets of node data together and use fewer vectors, but for -/// consistency's sake, we use separate vectors for each piece of data. -struct DepNodeData<K> { - /// Data for nodes not in previous graph. - new: NewDepNodeData<K>, - - /// Data for nodes in previous graph that have been marked red. - red: RedDepNodeData, - - /// Data for nodes in previous graph that have been marked light green. - light_green: LightGreenDepNodeData, - - // Edges for all nodes other than dark-green ones. Edges for each node - // occupy a contiguous region of this collection, which a node can reference - // using two indices. Storing edges this way rather than using an `EdgesVec` - // for each node reduces memory consumption by a not insignificant amount - // when compiling large crates. The downside is that we have to copy into - // this collection the edges from the `EdgesVec`s that are built up during - // query execution. But this is mostly balanced out by the more efficient - // implementation of `DepGraph::serialize` enabled by this representation. - unshared_edges: IndexVec<EdgeIndex, DepNodeIndex>, - - /// Mapping from `DepNodeIndex` to an index into a collection above. - /// Indicates which of the above collections contains a node's data. - /// - /// This collection is wasteful in time and space during incr-full builds, - /// because for those, all nodes are new. However, the waste is relatively - /// small, and the maintenance cost of avoiding using this for incr-full - /// builds is somewhat high and prone to bugginess. It does not seem worth - /// it at the time of this writing, but we may want to revisit the idea. - hybrid_indices: IndexVec<DepNodeIndex, CompressedHybridIndex>, -} - -/// Data for nodes not in previous graph. Since we cannot share any data with -/// the previous graph, so we must store all of such a node's data here. -struct NewDepNodeData<K> { - nodes: IndexVec<NewDepNodeIndex, DepNode<K>>, - edges: IndexVec<NewDepNodeIndex, Range<EdgeIndex>>, - fingerprints: IndexVec<NewDepNodeIndex, Fingerprint>, -} - -/// Data for nodes in previous graph that have been marked red. We can share the -/// dep node with the previous graph, but the edges may be different, and the -/// fingerprint is known to be different, so we store the latter two directly. -struct RedDepNodeData { - node_indices: IndexVec<RedDepNodeIndex, SerializedDepNodeIndex>, - edges: IndexVec<RedDepNodeIndex, Range<EdgeIndex>>, - fingerprints: IndexVec<RedDepNodeIndex, Fingerprint>, -} - -/// Data for nodes in previous graph that have been marked green because we -/// re-executed their queries and the results were the same as in the previous -/// session. We can share the dep node and the fingerprint with the previous -/// graph, but the edges may be different, so we store them directly. -struct LightGreenDepNodeData { - node_indices: IndexVec<LightGreenDepNodeIndex, SerializedDepNodeIndex>, - edges: IndexVec<LightGreenDepNodeIndex, Range<EdgeIndex>>, -} - /// `CurrentDepGraph` stores the dependency graph for the current session. It /// will be populated as we run queries or tasks. We never remove nodes from the /// graph: they are only added. /// -/// The nodes in it are identified by a `DepNodeIndex`. Internally, this maps to -/// a `HybridIndex`, which identifies which collection in the `data` field -/// contains a node's data. Which collection is used for a node depends on -/// whether the node was present in the `PreviousDepGraph`, and if so, the color -/// of the node. Each type of node can share more or less data with the previous -/// graph. When possible, we can store just the index of the node in the -/// previous graph, rather than duplicating its data in our own collections. -/// This is important, because these graph structures are some of the largest in -/// the compiler. +/// The nodes in it are identified by a `DepNodeIndex`. We avoid keeping the nodes +/// in memory. This is important, because these graph structures are some of the +/// largest in the compiler. /// -/// For the same reason, we also avoid storing `DepNode`s more than once as map +/// For this reason, we avoid storing `DepNode`s more than once as map /// keys. The `new_node_to_index` map only contains nodes not in the previous /// graph, and we map nodes in the previous graph to indices via a two-step /// mapping. `PreviousDepGraph` maps from `DepNode` to `SerializedDepNodeIndex`, @@ -1417,15 +869,15 @@ struct LightGreenDepNodeData { /// `new_node_to_index` and `data`, or `prev_index_to_index` and `data`. When /// manipulating both, we acquire `new_node_to_index` or `prev_index_to_index` /// first, and `data` second. -pub(super) struct CurrentDepGraph<K> { - data: Lock<DepNodeData<K>>, +pub(super) struct CurrentDepGraph<K: DepKind> { + encoder: Steal<GraphEncoder<K>>, new_node_to_index: Sharded<FxHashMap<DepNode<K>, DepNodeIndex>>, prev_index_to_index: Lock<IndexVec<SerializedDepNodeIndex, Option<DepNodeIndex>>>, /// Used to trap when a specific edge is added to the graph. /// This is used for debug purposes and is only active with `debug_assertions`. - #[allow(dead_code)] - forbidden_edge: Option<EdgeFilter>, + #[cfg(debug_assertions)] + forbidden_edge: Option<EdgeFilter<K>>, /// Anonymous `DepNode`s are nodes whose IDs we compute from the list of /// their edges. This has the beneficial side-effect that multiple anonymous @@ -1447,7 +899,12 @@ pub(super) struct CurrentDepGraph<K> { } impl<K: DepKind> CurrentDepGraph<K> { - fn new(prev_graph_node_count: usize) -> CurrentDepGraph<K> { + fn new( + prev_graph_node_count: usize, + encoder: FileEncoder, + record_graph: bool, + record_stats: bool, + ) -> CurrentDepGraph<K> { use std::time::{SystemTime, UNIX_EPOCH}; let duration = SystemTime::now().duration_since(UNIX_EPOCH).unwrap(); @@ -1455,70 +912,29 @@ impl<K: DepKind> CurrentDepGraph<K> { let mut stable_hasher = StableHasher::new(); nanos.hash(&mut stable_hasher); - let forbidden_edge = if cfg!(debug_assertions) { - match env::var("RUST_FORBID_DEP_GRAPH_EDGE") { - Ok(s) => match EdgeFilter::new(&s) { - Ok(f) => Some(f), - Err(err) => panic!("RUST_FORBID_DEP_GRAPH_EDGE invalid: {}", err), - }, - Err(_) => None, - } - } else { - None + #[cfg(debug_assertions)] + let forbidden_edge = match env::var("RUST_FORBID_DEP_GRAPH_EDGE") { + Ok(s) => match EdgeFilter::new(&s) { + Ok(f) => Some(f), + Err(err) => panic!("RUST_FORBID_DEP_GRAPH_EDGE invalid: {}", err), + }, + Err(_) => None, }; - // Pre-allocate the dep node structures. We over-allocate a little so - // that we hopefully don't have to re-allocate during this compilation - // session. The over-allocation for new nodes is 2% plus a small - // constant to account for the fact that in very small crates 2% might - // not be enough. The allocation for red and green node data doesn't - // include a constant, as we don't want to allocate anything for these - // structures during full incremental builds, where they aren't used. - // - // These estimates are based on the distribution of node and edge counts - // seen in rustc-perf benchmarks, adjusted somewhat to account for the - // fact that these benchmarks aren't perfectly representative. - // - // FIXME Use a collection type that doesn't copy node and edge data and - // grow multiplicatively on reallocation. Without such a collection or - // solution having the same effect, there is a performance hazard here - // in both time and space, as growing these collections means copying a - // large amount of data and doubling already large buffer capacities. A - // solution for this will also mean that it's less important to get - // these estimates right. - let new_node_count_estimate = (prev_graph_node_count * 2) / 100 + 200; - let red_node_count_estimate = (prev_graph_node_count * 3) / 100; - let light_green_node_count_estimate = (prev_graph_node_count * 25) / 100; - let total_node_count_estimate = prev_graph_node_count + new_node_count_estimate; - - let average_edges_per_node_estimate = 6; - let unshared_edge_count_estimate = average_edges_per_node_estimate - * (new_node_count_estimate + red_node_count_estimate + light_green_node_count_estimate); - // We store a large collection of these in `prev_index_to_index` during // non-full incremental builds, and want to ensure that the element size // doesn't inadvertently increase. static_assert_size!(Option<DepNodeIndex>, 4); + let new_node_count_estimate = 102 * prev_graph_node_count / 100 + 200; + CurrentDepGraph { - data: Lock::new(DepNodeData { - new: NewDepNodeData { - nodes: IndexVec::with_capacity(new_node_count_estimate), - edges: IndexVec::with_capacity(new_node_count_estimate), - fingerprints: IndexVec::with_capacity(new_node_count_estimate), - }, - red: RedDepNodeData { - node_indices: IndexVec::with_capacity(red_node_count_estimate), - edges: IndexVec::with_capacity(red_node_count_estimate), - fingerprints: IndexVec::with_capacity(red_node_count_estimate), - }, - light_green: LightGreenDepNodeData { - node_indices: IndexVec::with_capacity(light_green_node_count_estimate), - edges: IndexVec::with_capacity(light_green_node_count_estimate), - }, - unshared_edges: IndexVec::with_capacity(unshared_edge_count_estimate), - hybrid_indices: IndexVec::with_capacity(total_node_count_estimate), - }), + encoder: Steal::new(GraphEncoder::new( + encoder, + prev_graph_node_count, + record_graph, + record_stats, + )), new_node_to_index: Sharded::new(|| { FxHashMap::with_capacity_and_hasher( new_node_count_estimate / sharded::SHARDS, @@ -1527,89 +943,143 @@ impl<K: DepKind> CurrentDepGraph<K> { }), prev_index_to_index: Lock::new(IndexVec::from_elem_n(None, prev_graph_node_count)), anon_id_seed: stable_hasher.finish(), + #[cfg(debug_assertions)] forbidden_edge, total_read_count: AtomicU64::new(0), total_duplicate_read_count: AtomicU64::new(0), } } + #[cfg(debug_assertions)] + fn record_edge(&self, dep_node_index: DepNodeIndex, key: DepNode<K>) { + if let Some(forbidden_edge) = &self.forbidden_edge { + forbidden_edge.index_to_node.lock().insert(dep_node_index, key); + } + } + + /// Writes the node to the current dep-graph and allocates a `DepNodeIndex` for it. + /// Assumes that this is a node that has no equivalent in the previous dep-graph. fn intern_new_node( &self, - prev_graph: &PreviousDepGraph<K>, - dep_node: DepNode<K>, + profiler: &SelfProfilerRef, + key: DepNode<K>, edges: EdgesVec, - fingerprint: Fingerprint, + current_fingerprint: Fingerprint, ) -> DepNodeIndex { - debug_assert!( - prev_graph.node_to_index_opt(&dep_node).is_none(), - "node in previous graph should be interned using one \ - of `intern_red_node`, `intern_light_green_node`, etc." - ); - - match self.new_node_to_index.get_shard_by_value(&dep_node).lock().entry(dep_node) { + match self.new_node_to_index.get_shard_by_value(&key).lock().entry(key) { Entry::Occupied(entry) => *entry.get(), Entry::Vacant(entry) => { - let data = &mut *self.data.lock(); - let new_index = data.new.nodes.push(dep_node); - add_edges(&mut data.unshared_edges, &mut data.new.edges, edges); - data.new.fingerprints.push(fingerprint); - let dep_node_index = data.hybrid_indices.push(new_index.into()); + let dep_node_index = + self.encoder.borrow().send(profiler, key, current_fingerprint, edges); entry.insert(dep_node_index); + #[cfg(debug_assertions)] + self.record_edge(dep_node_index, key); dep_node_index } } } - fn intern_red_node( + fn intern_node( &self, + profiler: &SelfProfilerRef, prev_graph: &PreviousDepGraph<K>, - prev_index: SerializedDepNodeIndex, + key: DepNode<K>, edges: EdgesVec, - fingerprint: Fingerprint, - ) -> DepNodeIndex { - self.debug_assert_not_in_new_nodes(prev_graph, prev_index); + fingerprint: Option<Fingerprint>, + print_status: bool, + ) -> (DepNodeIndex, Option<(SerializedDepNodeIndex, DepNodeColor)>) { + let print_status = cfg!(debug_assertions) && print_status; + + if let Some(prev_index) = prev_graph.node_to_index_opt(&key) { + // Determine the color and index of the new `DepNode`. + if let Some(fingerprint) = fingerprint { + if fingerprint == prev_graph.fingerprint_by_index(prev_index) { + if print_status { + eprintln!("[task::green] {:?}", key); + } - let mut prev_index_to_index = self.prev_index_to_index.lock(); + // This is a green node: it existed in the previous compilation, + // its query was re-executed, and it has the same result as before. + let mut prev_index_to_index = self.prev_index_to_index.lock(); + + let dep_node_index = match prev_index_to_index[prev_index] { + Some(dep_node_index) => dep_node_index, + None => { + let dep_node_index = + self.encoder.borrow().send(profiler, key, fingerprint, edges); + prev_index_to_index[prev_index] = Some(dep_node_index); + dep_node_index + } + }; - match prev_index_to_index[prev_index] { - Some(dep_node_index) => dep_node_index, - None => { - let data = &mut *self.data.lock(); - let red_index = data.red.node_indices.push(prev_index); - add_edges(&mut data.unshared_edges, &mut data.red.edges, edges); - data.red.fingerprints.push(fingerprint); - let dep_node_index = data.hybrid_indices.push(red_index.into()); - prev_index_to_index[prev_index] = Some(dep_node_index); - dep_node_index - } - } - } + #[cfg(debug_assertions)] + self.record_edge(dep_node_index, key); + (dep_node_index, Some((prev_index, DepNodeColor::Green(dep_node_index)))) + } else { + if print_status { + eprintln!("[task::red] {:?}", key); + } - fn intern_light_green_node( - &self, - prev_graph: &PreviousDepGraph<K>, - prev_index: SerializedDepNodeIndex, - edges: EdgesVec, - ) -> DepNodeIndex { - self.debug_assert_not_in_new_nodes(prev_graph, prev_index); + // This is a red node: it existed in the previous compilation, its query + // was re-executed, but it has a different result from before. + let mut prev_index_to_index = self.prev_index_to_index.lock(); + + let dep_node_index = match prev_index_to_index[prev_index] { + Some(dep_node_index) => dep_node_index, + None => { + let dep_node_index = + self.encoder.borrow().send(profiler, key, fingerprint, edges); + prev_index_to_index[prev_index] = Some(dep_node_index); + dep_node_index + } + }; - let mut prev_index_to_index = self.prev_index_to_index.lock(); + #[cfg(debug_assertions)] + self.record_edge(dep_node_index, key); + (dep_node_index, Some((prev_index, DepNodeColor::Red))) + } + } else { + if print_status { + eprintln!("[task::unknown] {:?}", key); + } - match prev_index_to_index[prev_index] { - Some(dep_node_index) => dep_node_index, - None => { - let data = &mut *self.data.lock(); - let light_green_index = data.light_green.node_indices.push(prev_index); - add_edges(&mut data.unshared_edges, &mut data.light_green.edges, edges); - let dep_node_index = data.hybrid_indices.push(light_green_index.into()); - prev_index_to_index[prev_index] = Some(dep_node_index); - dep_node_index + // This is a red node, effectively: it existed in the previous compilation + // session, its query was re-executed, but it doesn't compute a result hash + // (i.e. it represents a `no_hash` query), so we have no way of determining + // whether or not the result was the same as before. + let mut prev_index_to_index = self.prev_index_to_index.lock(); + + let dep_node_index = match prev_index_to_index[prev_index] { + Some(dep_node_index) => dep_node_index, + None => { + let dep_node_index = + self.encoder.borrow().send(profiler, key, Fingerprint::ZERO, edges); + prev_index_to_index[prev_index] = Some(dep_node_index); + dep_node_index + } + }; + + #[cfg(debug_assertions)] + self.record_edge(dep_node_index, key); + (dep_node_index, Some((prev_index, DepNodeColor::Red))) + } + } else { + if print_status { + eprintln!("[task::new] {:?}", key); } + + let fingerprint = fingerprint.unwrap_or(Fingerprint::ZERO); + + // This is a new node: it didn't exist in the previous compilation session. + let dep_node_index = self.intern_new_node(profiler, key, edges, fingerprint); + + (dep_node_index, None) } } - fn intern_dark_green_node( + fn promote_node_and_deps_to_current( &self, + profiler: &SelfProfilerRef, prev_graph: &PreviousDepGraph<K>, prev_index: SerializedDepNodeIndex, ) -> DepNodeIndex { @@ -1620,9 +1090,20 @@ impl<K: DepKind> CurrentDepGraph<K> { match prev_index_to_index[prev_index] { Some(dep_node_index) => dep_node_index, None => { - let mut data = self.data.lock(); - let dep_node_index = data.hybrid_indices.push(prev_index.into()); + let key = prev_graph.index_to_node(prev_index); + let dep_node_index = self.encoder.borrow().send( + profiler, + key, + prev_graph.fingerprint_by_index(prev_index), + prev_graph + .edge_targets_from(prev_index) + .iter() + .map(|i| prev_index_to_index[*i].unwrap()) + .collect(), + ); prev_index_to_index[prev_index] = Some(dep_node_index); + #[cfg(debug_assertions)] + self.record_edge(dep_node_index, key); dep_node_index } } @@ -1642,18 +1123,6 @@ impl<K: DepKind> CurrentDepGraph<K> { } } -#[inline] -fn add_edges<I: Idx>( - edges: &mut IndexVec<EdgeIndex, DepNodeIndex>, - edge_indices: &mut IndexVec<I, Range<EdgeIndex>>, - new_edges: EdgesVec, -) { - let start = edges.next_index(); - edges.extend(new_edges); - let end = edges.next_index(); - edge_indices.push(start..end); -} - /// The capacity of the `reads` field `SmallVec` const TASK_DEPS_READS_CAP: usize = 8; type EdgesVec = SmallVec<[DepNodeIndex; TASK_DEPS_READS_CAP]>; diff --git a/compiler/rustc_query_system/src/dep_graph/mod.rs b/compiler/rustc_query_system/src/dep_graph/mod.rs index e8fb71be3e0..1b6ecf3e637 100644 --- a/compiler/rustc_query_system/src/dep_graph/mod.rs +++ b/compiler/rustc_query_system/src/dep_graph/mod.rs @@ -13,6 +13,7 @@ pub use serialized::{SerializedDepGraph, SerializedDepNodeIndex}; use rustc_data_structures::profiling::SelfProfilerRef; use rustc_data_structures::sync::Lock; +use rustc_serialize::{opaque::FileEncoder, Encodable}; use rustc_session::Session; use std::fmt; @@ -59,7 +60,7 @@ impl<T: DepContext> HasDepContext for T { } /// Describe the different families of dependency nodes. -pub trait DepKind: Copy + fmt::Debug + Eq + Hash { +pub trait DepKind: Copy + fmt::Debug + Eq + Hash + Send + Encodable<FileEncoder> + 'static { const NULL: Self; /// Return whether this kind always require evaluation. diff --git a/compiler/rustc_query_system/src/dep_graph/prev.rs b/compiler/rustc_query_system/src/dep_graph/prev.rs index c3d0f795255..6303bbf53b9 100644 --- a/compiler/rustc_query_system/src/dep_graph/prev.rs +++ b/compiler/rustc_query_system/src/dep_graph/prev.rs @@ -36,11 +36,6 @@ impl<K: DepKind> PreviousDepGraph<K> { } #[inline] - pub fn node_to_index(&self, dep_node: &DepNode<K>) -> SerializedDepNodeIndex { - self.index[dep_node] - } - - #[inline] pub fn node_to_index_opt(&self, dep_node: &DepNode<K>) -> Option<SerializedDepNodeIndex> { self.index.get(dep_node).cloned() } diff --git a/compiler/rustc_query_system/src/dep_graph/query.rs b/compiler/rustc_query_system/src/dep_graph/query.rs index cc25d08cb54..27b3b5e1366 100644 --- a/compiler/rustc_query_system/src/dep_graph/query.rs +++ b/compiler/rustc_query_system/src/dep_graph/query.rs @@ -1,38 +1,43 @@ use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::graph::implementation::{Direction, Graph, NodeIndex, INCOMING}; +use rustc_index::vec::IndexVec; -use super::{DepKind, DepNode}; +use super::{DepKind, DepNode, DepNodeIndex}; pub struct DepGraphQuery<K> { pub graph: Graph<DepNode<K>, ()>, pub indices: FxHashMap<DepNode<K>, NodeIndex>, + pub dep_index_to_index: IndexVec<DepNodeIndex, Option<NodeIndex>>, } impl<K: DepKind> DepGraphQuery<K> { - pub fn new( - nodes: &[DepNode<K>], - edge_list_indices: &[(usize, usize)], - edge_list_data: &[usize], - ) -> DepGraphQuery<K> { - let mut graph = Graph::with_capacity(nodes.len(), edge_list_data.len()); - let mut indices = FxHashMap::default(); - for node in nodes { - indices.insert(*node, graph.add_node(*node)); - } + pub fn new(prev_node_count: usize) -> DepGraphQuery<K> { + let node_count = prev_node_count + prev_node_count / 4; + let edge_count = 6 * node_count; - for (source, &(start, end)) in edge_list_indices.iter().enumerate() { - for &target in &edge_list_data[start..end] { - let source = indices[&nodes[source]]; - let target = indices[&nodes[target]]; - graph.add_edge(source, target, ()); - } - } + let graph = Graph::with_capacity(node_count, edge_count); + let indices = FxHashMap::default(); + let dep_index_to_index = IndexVec::new(); - DepGraphQuery { graph, indices } + DepGraphQuery { graph, indices, dep_index_to_index } } - pub fn contains_node(&self, node: &DepNode<K>) -> bool { - self.indices.contains_key(&node) + pub fn push(&mut self, index: DepNodeIndex, node: DepNode<K>, edges: &[DepNodeIndex]) { + let source = self.graph.add_node(node); + if index.index() >= self.dep_index_to_index.len() { + self.dep_index_to_index.resize(index.index() + 1, None); + } + self.dep_index_to_index[index] = Some(source); + self.indices.insert(node, source); + + for &target in edges.iter() { + let target = self.dep_index_to_index[target]; + // We may miss the edges that are pushed while the `DepGraphQuery` is being accessed. + // Skip them to issues. + if let Some(target) = target { + self.graph.add_edge(source, target, ()); + } + } } pub fn nodes(&self) -> Vec<&DepNode<K>> { diff --git a/compiler/rustc_query_system/src/dep_graph/serialized.rs b/compiler/rustc_query_system/src/dep_graph/serialized.rs index 9bb922b0a90..6f3d1fb7199 100644 --- a/compiler/rustc_query_system/src/dep_graph/serialized.rs +++ b/compiler/rustc_query_system/src/dep_graph/serialized.rs @@ -1,9 +1,28 @@ //! The data that we will serialize and deserialize. +//! +//! The dep-graph is serialized as a sequence of NodeInfo, with the dependencies +//! specified inline. The total number of nodes and edges are stored as the last +//! 16 bytes of the file, so we can find them easily at decoding time. +//! +//! The serialisation is performed on-demand when each node is emitted. Using this +//! scheme, we do not need to keep the current graph in memory. +//! +//! The deserisalisation is performed manually, in order to convert from the stored +//! sequence of NodeInfos to the different arrays in SerializedDepGraph. Since the +//! node and edge count are stored at the end of the file, all the arrays can be +//! pre-allocated with the right length. -use super::{DepKind, DepNode}; +use super::query::DepGraphQuery; +use super::{DepKind, DepNode, DepNodeIndex}; use rustc_data_structures::fingerprint::Fingerprint; -use rustc_index::vec::IndexVec; -use rustc_serialize::{Decodable, Decoder}; +use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::profiling::SelfProfilerRef; +use rustc_data_structures::sync::Lock; +use rustc_index::vec::{Idx, IndexVec}; +use rustc_serialize::opaque::{self, FileEncodeResult, FileEncoder, IntEncodedWithFixedSize}; +use rustc_serialize::{Decodable, Decoder, Encodable}; +use smallvec::SmallVec; +use std::convert::TryInto; // The maximum value of `SerializedDepNodeIndex` leaves the upper two bits // unused so that we can store multiple index types in `CompressedHybridIndex`, @@ -50,78 +69,239 @@ impl<K: DepKind> SerializedDepGraph<K> { } } -impl<D: Decoder, K: DepKind + Decodable<D>> Decodable<D> for SerializedDepGraph<K> { - fn decode(d: &mut D) -> Result<SerializedDepGraph<K>, D::Error> { - // We used to serialize the dep graph by creating and serializing a `SerializedDepGraph` - // using data copied from the `DepGraph`. But copying created a large memory spike, so we - // now serialize directly from the `DepGraph` as if it's a `SerializedDepGraph`. Because we - // deserialize that data into a `SerializedDepGraph` in the next compilation session, we - // need `DepGraph`'s `Encodable` and `SerializedDepGraph`'s `Decodable` implementations to - // be in sync. If you update this decoding, be sure to update the encoding, and vice-versa. - // - // We mimic the sequence of `Encode` and `Encodable` method calls used by the `DepGraph`'s - // `Encodable` implementation with the corresponding sequence of `Decode` and `Decodable` - // method calls. E.g. `Decode::read_struct` pairs with `Encode::emit_struct`, `DepNode`'s - // `decode` pairs with `DepNode`'s `encode`, and so on. Any decoding methods not associated - // with corresponding encoding methods called in `DepGraph`'s `Encodable` implementation - // are off limits, because we'd be relying on their implementation details. - // - // For example, because we know it happens to do the right thing, its tempting to just use - // `IndexVec`'s `Decodable` implementation to decode into some of the collections below, - // even though `DepGraph` doesn't use its `Encodable` implementation. But the `IndexVec` - // implementation could change, and we'd have a bug. - // - // Variables below are explicitly typed so that anyone who changes the `SerializedDepGraph` - // representation without updating this function will encounter a compilation error, and - // know to update this and possibly the `DepGraph` `Encodable` implementation accordingly - // (the latter should serialize data in a format compatible with our representation). - - d.read_struct("SerializedDepGraph", 4, |d| { - let nodes: IndexVec<SerializedDepNodeIndex, DepNode<K>> = - d.read_struct_field("nodes", 0, |d| { - d.read_seq(|d, len| { - let mut v = IndexVec::with_capacity(len); - for i in 0..len { - v.push(d.read_seq_elt(i, |d| Decodable::decode(d))?); - } - Ok(v) - }) - })?; +impl<'a, K: DepKind + Decodable<opaque::Decoder<'a>>> Decodable<opaque::Decoder<'a>> + for SerializedDepGraph<K> +{ + #[instrument(skip(d))] + fn decode(d: &mut opaque::Decoder<'a>) -> Result<SerializedDepGraph<K>, String> { + let start_position = d.position(); - let fingerprints: IndexVec<SerializedDepNodeIndex, Fingerprint> = - d.read_struct_field("fingerprints", 1, |d| { - d.read_seq(|d, len| { - let mut v = IndexVec::with_capacity(len); - for i in 0..len { - v.push(d.read_seq_elt(i, |d| Decodable::decode(d))?); - } - Ok(v) - }) - })?; + // The last 16 bytes are the node count and edge count. + debug!("position: {:?}", d.position()); + d.set_position(d.data.len() - 2 * IntEncodedWithFixedSize::ENCODED_SIZE); + debug!("position: {:?}", d.position()); - let edge_list_indices: IndexVec<SerializedDepNodeIndex, (u32, u32)> = d - .read_struct_field("edge_list_indices", 2, |d| { - d.read_seq(|d, len| { - let mut v = IndexVec::with_capacity(len); - for i in 0..len { - v.push(d.read_seq_elt(i, |d| Decodable::decode(d))?); - } - Ok(v) - }) - })?; + let node_count = IntEncodedWithFixedSize::decode(d)?.0 as usize; + let edge_count = IntEncodedWithFixedSize::decode(d)?.0 as usize; + debug!(?node_count, ?edge_count); + + debug!("position: {:?}", d.position()); + d.set_position(start_position); + debug!("position: {:?}", d.position()); + + let mut nodes = IndexVec::with_capacity(node_count); + let mut fingerprints = IndexVec::with_capacity(node_count); + let mut edge_list_indices = IndexVec::with_capacity(node_count); + let mut edge_list_data = Vec::with_capacity(edge_count); + + for _index in 0..node_count { + d.read_struct("NodeInfo", 3, |d| { + let dep_node: DepNode<K> = d.read_struct_field("node", 0, Decodable::decode)?; + let _i: SerializedDepNodeIndex = nodes.push(dep_node); + debug_assert_eq!(_i.index(), _index); - let edge_list_data: Vec<SerializedDepNodeIndex> = - d.read_struct_field("edge_list_data", 3, |d| { + let fingerprint: Fingerprint = + d.read_struct_field("fingerprint", 1, Decodable::decode)?; + let _i: SerializedDepNodeIndex = fingerprints.push(fingerprint); + debug_assert_eq!(_i.index(), _index); + + d.read_struct_field("edges", 2, |d| { d.read_seq(|d, len| { - let mut v = Vec::with_capacity(len); - for i in 0..len { - v.push(d.read_seq_elt(i, |d| Decodable::decode(d))?); + let start = edge_list_data.len().try_into().unwrap(); + for e in 0..len { + let edge = d.read_seq_elt(e, Decodable::decode)?; + edge_list_data.push(edge); } - Ok(v) + let end = edge_list_data.len().try_into().unwrap(); + let _i: SerializedDepNodeIndex = edge_list_indices.push((start, end)); + debug_assert_eq!(_i.index(), _index); + Ok(()) }) - })?; + }) + })?; + } + + Ok(SerializedDepGraph { nodes, fingerprints, edge_list_indices, edge_list_data }) + } +} + +#[derive(Debug, Encodable, Decodable)] +pub struct NodeInfo<K: DepKind> { + node: DepNode<K>, + fingerprint: Fingerprint, + edges: SmallVec<[DepNodeIndex; 8]>, +} + +struct Stat<K: DepKind> { + kind: K, + node_counter: u64, + edge_counter: u64, +} + +struct EncoderState<K: DepKind> { + encoder: FileEncoder, + total_node_count: usize, + total_edge_count: usize, + result: FileEncodeResult, + stats: Option<FxHashMap<K, Stat<K>>>, +} + +impl<K: DepKind> EncoderState<K> { + fn new(encoder: FileEncoder, record_stats: bool) -> Self { + Self { + encoder, + total_edge_count: 0, + total_node_count: 0, + result: Ok(()), + stats: if record_stats { Some(FxHashMap::default()) } else { None }, + } + } + + #[instrument(skip(self, record_graph))] + fn encode_node( + &mut self, + node: &NodeInfo<K>, + record_graph: &Option<Lock<DepGraphQuery<K>>>, + ) -> DepNodeIndex { + let index = DepNodeIndex::new(self.total_node_count); + self.total_node_count += 1; + + let edge_count = node.edges.len(); + self.total_edge_count += edge_count; + + if let Some(record_graph) = &record_graph { + // Do not ICE when a query is called from within `with_query`. + if let Some(record_graph) = &mut record_graph.try_lock() { + record_graph.push(index, node.node, &node.edges); + } + } + + if let Some(stats) = &mut self.stats { + let kind = node.node.kind; + + let stat = stats.entry(kind).or_insert(Stat { kind, node_counter: 0, edge_counter: 0 }); + stat.node_counter += 1; + stat.edge_counter += edge_count as u64; + } + + debug!(?index, ?node); + let encoder = &mut self.encoder; + if self.result.is_ok() { + self.result = node.encode(encoder); + } + index + } + + fn finish(self) -> FileEncodeResult { + let Self { mut encoder, total_node_count, total_edge_count, result, stats: _ } = self; + let () = result?; + + let node_count = total_node_count.try_into().unwrap(); + let edge_count = total_edge_count.try_into().unwrap(); + + debug!(?node_count, ?edge_count); + debug!("position: {:?}", encoder.position()); + IntEncodedWithFixedSize(node_count).encode(&mut encoder)?; + IntEncodedWithFixedSize(edge_count).encode(&mut encoder)?; + debug!("position: {:?}", encoder.position()); + // Drop the encoder so that nothing is written after the counts. + encoder.flush() + } +} + +pub struct GraphEncoder<K: DepKind> { + status: Lock<EncoderState<K>>, + record_graph: Option<Lock<DepGraphQuery<K>>>, +} + +impl<K: DepKind + Encodable<FileEncoder>> GraphEncoder<K> { + pub fn new( + encoder: FileEncoder, + prev_node_count: usize, + record_graph: bool, + record_stats: bool, + ) -> Self { + let record_graph = + if record_graph { Some(Lock::new(DepGraphQuery::new(prev_node_count))) } else { None }; + let status = Lock::new(EncoderState::new(encoder, record_stats)); + GraphEncoder { status, record_graph } + } + + pub(crate) fn with_query(&self, f: impl Fn(&DepGraphQuery<K>)) { + if let Some(record_graph) = &self.record_graph { + f(&record_graph.lock()) + } + } + + pub(crate) fn print_incremental_info( + &self, + total_read_count: u64, + total_duplicate_read_count: u64, + ) { + let status = self.status.lock(); + if let Some(record_stats) = &status.stats { + let mut stats: Vec<_> = record_stats.values().collect(); + stats.sort_by_key(|s| -(s.node_counter as i64)); + + const SEPARATOR: &str = "[incremental] --------------------------------\ + ----------------------------------------------\ + ------------"; + + eprintln!("[incremental]"); + eprintln!("[incremental] DepGraph Statistics"); + eprintln!("{}", SEPARATOR); + eprintln!("[incremental]"); + eprintln!("[incremental] Total Node Count: {}", status.total_node_count); + eprintln!("[incremental] Total Edge Count: {}", status.total_edge_count); + + if cfg!(debug_assertions) { + eprintln!("[incremental] Total Edge Reads: {}", total_read_count); + eprintln!( + "[incremental] Total Duplicate Edge Reads: {}", + total_duplicate_read_count + ); + } + + eprintln!("[incremental]"); + eprintln!( + "[incremental] {:<36}| {:<17}| {:<12}| {:<17}|", + "Node Kind", "Node Frequency", "Node Count", "Avg. Edge Count" + ); + eprintln!("{}", SEPARATOR); + + for stat in stats { + let node_kind_ratio = + (100.0 * (stat.node_counter as f64)) / (status.total_node_count as f64); + let node_kind_avg_edges = (stat.edge_counter as f64) / (stat.node_counter as f64); + + eprintln!( + "[incremental] {:<36}|{:>16.1}% |{:>12} |{:>17.1} |", + format!("{:?}", stat.kind), + node_kind_ratio, + stat.node_counter, + node_kind_avg_edges, + ); + } + + eprintln!("{}", SEPARATOR); + eprintln!("[incremental]"); + } + } + + pub(crate) fn send( + &self, + profiler: &SelfProfilerRef, + node: DepNode<K>, + fingerprint: Fingerprint, + edges: SmallVec<[DepNodeIndex; 8]>, + ) -> DepNodeIndex { + let _prof_timer = profiler.generic_activity("incr_comp_encode_dep_graph"); + let node = NodeInfo { node, fingerprint, edges }; + self.status.lock().encode_node(&node, &self.record_graph) + } - Ok(SerializedDepGraph { nodes, fingerprints, edge_list_indices, edge_list_data }) - }) + pub fn finish(self, profiler: &SelfProfilerRef) -> FileEncodeResult { + let _prof_timer = profiler.generic_activity("incr_comp_encode_dep_graph"); + self.status.into_inner().finish() } } diff --git a/compiler/rustc_query_system/src/lib.rs b/compiler/rustc_query_system/src/lib.rs index 26b76a9c006..071144f38e7 100644 --- a/compiler/rustc_query_system/src/lib.rs +++ b/compiler/rustc_query_system/src/lib.rs @@ -2,7 +2,9 @@ #![feature(const_fn)] #![feature(const_panic)] #![feature(core_intrinsics)] +#![feature(drain_filter)] #![feature(hash_raw_entry)] +#![feature(iter_zip)] #![feature(min_specialization)] #![feature(stmt_expr_attributes)] diff --git a/compiler/rustc_query_system/src/query/job.rs b/compiler/rustc_query_system/src/query/job.rs index 35a2ac865f2..21f580db04f 100644 --- a/compiler/rustc_query_system/src/query/job.rs +++ b/compiler/rustc_query_system/src/query/job.rs @@ -22,7 +22,7 @@ use { rustc_data_structures::{jobserver, OnDrop}, rustc_rayon_core as rayon_core, rustc_span::DUMMY_SP, - std::iter::FromIterator, + std::iter::{self, FromIterator}, std::{mem, process}, }; @@ -463,7 +463,7 @@ fn remove_cycle<D: DepKind>( spans.rotate_right(1); // Zip them back together - let mut stack: Vec<_> = spans.into_iter().zip(queries).collect(); + let mut stack: Vec<_> = iter::zip(spans, queries).collect(); // Remove the queries in our cycle from the list of jobs to look at for r in &stack { diff --git a/compiler/rustc_query_system/src/query/plumbing.rs b/compiler/rustc_query_system/src/query/plumbing.rs index 77267489a75..fb8a53048fa 100644 --- a/compiler/rustc_query_system/src/query/plumbing.rs +++ b/compiler/rustc_query_system/src/query/plumbing.rs @@ -449,9 +449,11 @@ where let ((result, dep_node_index), diagnostics) = with_diagnostics(|diagnostics| { tcx.start_query(job.id, diagnostics, || { - tcx.dep_context() - .dep_graph() - .with_anon_task(query.dep_kind, || query.compute(tcx, key)) + tcx.dep_context().dep_graph().with_anon_task( + *tcx.dep_context(), + query.dep_kind, + || query.compute(tcx, key), + ) }) }); @@ -537,7 +539,7 @@ where // If `-Zincremental-verify-ich` is specified, re-hash results from // the cache and make sure that they have the expected fingerprint. if unlikely!(tcx.dep_context().sess().opts.debugging_opts.incremental_verify_ich) { - incremental_verify_ich(*tcx.dep_context(), &result, dep_node, dep_node_index, query); + incremental_verify_ich(*tcx.dep_context(), &result, dep_node, query); } result @@ -560,7 +562,7 @@ where // // See issue #82920 for an example of a miscompilation that would get turned into // an ICE by this check - incremental_verify_ich(*tcx.dep_context(), &result, dep_node, dep_node_index, query); + incremental_verify_ich(*tcx.dep_context(), &result, dep_node, query); result } @@ -570,14 +572,12 @@ fn incremental_verify_ich<CTX, K, V: Debug>( tcx: CTX::DepContext, result: &V, dep_node: &DepNode<CTX::DepKind>, - dep_node_index: DepNodeIndex, query: &QueryVtable<CTX, K, V>, ) where CTX: QueryContext, { assert!( - Some(tcx.dep_graph().fingerprint_of(dep_node_index)) - == tcx.dep_graph().prev_fingerprint_of(dep_node), + tcx.dep_graph().is_green(dep_node), "fingerprint for green query instance not loaded from cache: {:?}", dep_node, ); @@ -588,9 +588,15 @@ fn incremental_verify_ich<CTX, K, V: Debug>( let new_hash = query.hash_result(&mut hcx, result).unwrap_or(Fingerprint::ZERO); debug!("END verify_ich({:?})", dep_node); - let old_hash = tcx.dep_graph().fingerprint_of(dep_node_index); + let old_hash = tcx.dep_graph().prev_fingerprint_of(dep_node); - assert!(new_hash == old_hash, "found unstable fingerprints for {:?}: {:?}", dep_node, result); + assert_eq!( + Some(new_hash), + old_hash, + "found unstable fingerprints for {:?}: {:?}", + dep_node, + result + ); } fn force_query_with_job<C, CTX>( diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index d402fa4f849..327beca218e 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -606,7 +606,7 @@ impl<'a> Resolver<'a> { /// Lookup typo candidate in scope for a macro or import. fn early_lookup_typo_candidate( &mut self, - scope_set: ScopeSet, + scope_set: ScopeSet<'a>, parent_scope: &ParentScope<'a>, ident: Ident, filter_fn: &impl Fn(Res) -> bool, @@ -662,7 +662,7 @@ impl<'a> Resolver<'a> { let root_module = this.resolve_crate_root(root_ident); this.add_module_candidates(root_module, &mut suggestions, filter_fn); } - Scope::Module(module) => { + Scope::Module(module, _) => { this.add_module_candidates(module, &mut suggestions, filter_fn); } Scope::RegisteredAttrs => { diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index f9f33492a1e..1377bb781d0 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -2327,7 +2327,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { ExprKind::Call(ref callee, ref arguments) => { self.resolve_expr(callee, Some(expr)); - let const_args = self.r.legacy_const_generic_args(callee).unwrap_or(Vec::new()); + let const_args = self.r.legacy_const_generic_args(callee).unwrap_or_default(); for (idx, argument) in arguments.iter().enumerate() { // Constant arguments need to be treated as AnonConst since // that is how they will be later lowered to HIR. diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index e85d78db22c..1fb07bdae9d 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -22,6 +22,8 @@ use rustc_span::lev_distance::find_best_match_for_name; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{BytePos, MultiSpan, Span, DUMMY_SP}; +use std::iter; + use tracing::debug; type Res = def::Res<ast::NodeId>; @@ -184,7 +186,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { PathResult::Module(ModuleOrUniformRoot::Module(module)) => module.res(), _ => None, } - .map_or(String::new(), |res| format!("{} ", res.descr())); + .map_or_else(String::new, |res| format!("{} ", res.descr())); (mod_prefix, format!("`{}`", Segment::names_to_string(mod_path))) }; ( @@ -1004,9 +1006,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { if let Some(spans) = field_spans.filter(|spans| spans.len() > 0 && fields.len() == spans.len()) { - let non_visible_spans: Vec<Span> = fields - .iter() - .zip(spans.iter()) + let non_visible_spans: Vec<Span> = iter::zip(&fields, &spans) .filter(|(vis, _)| { !self.r.is_accessible_from(**vis, self.parent_scope.module) }) @@ -1042,10 +1042,10 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { if let Some(span) = self.def_span(def_id) { err.span_label(span, &format!("`{}` defined here", path_str)); } - let fields = - self.r.field_names.get(&def_id).map_or("/* fields */".to_string(), |fields| { - vec!["_"; fields.len()].join(", ") - }); + let fields = self.r.field_names.get(&def_id).map_or_else( + || "/* fields */".to_string(), + |fields| vec!["_"; fields.len()].join(", "), + ); err.span_suggestion( span, "use the tuple variant pattern syntax instead", diff --git a/compiler/rustc_resolve/src/late/lifetimes.rs b/compiler/rustc_resolve/src/late/lifetimes.rs index 698e5048f7b..b89ad867f46 100644 --- a/compiler/rustc_resolve/src/late/lifetimes.rs +++ b/compiler/rustc_resolve/src/late/lifetimes.rs @@ -30,7 +30,7 @@ use std::cell::Cell; use std::fmt; use std::mem::take; -use tracing::debug; +use tracing::{debug, span, Level}; // This counts the no of times a lifetime is used #[derive(Clone, Copy, Debug)] @@ -42,9 +42,9 @@ pub enum LifetimeUseSet<'tcx> { trait RegionExt { fn early(hir_map: &Map<'_>, index: &mut u32, param: &GenericParam<'_>) -> (ParamName, Region); - fn late(hir_map: &Map<'_>, param: &GenericParam<'_>) -> (ParamName, Region); + fn late(index: u32, hir_map: &Map<'_>, param: &GenericParam<'_>) -> (ParamName, Region); - fn late_anon(index: &Cell<u32>) -> Region; + fn late_anon(named_late_bound_vars: u32, index: &Cell<u32>) -> Region; fn id(&self) -> Option<DefId>; @@ -67,7 +67,7 @@ impl RegionExt for Region { (param.name.normalize_to_macros_2_0(), Region::EarlyBound(i, def_id.to_def_id(), origin)) } - fn late(hir_map: &Map<'_>, param: &GenericParam<'_>) -> (ParamName, Region) { + fn late(idx: u32, hir_map: &Map<'_>, param: &GenericParam<'_>) -> (ParamName, Region) { let depth = ty::INNERMOST; let def_id = hir_map.local_def_id(param.hir_id); let origin = LifetimeDefOrigin::from_param(param); @@ -75,21 +75,24 @@ impl RegionExt for Region { "Region::late: param={:?} depth={:?} def_id={:?} origin={:?}", param, depth, def_id, origin, ); - (param.name.normalize_to_macros_2_0(), Region::LateBound(depth, def_id.to_def_id(), origin)) + ( + param.name.normalize_to_macros_2_0(), + Region::LateBound(depth, idx, def_id.to_def_id(), origin), + ) } - fn late_anon(index: &Cell<u32>) -> Region { + fn late_anon(named_late_bound_vars: u32, index: &Cell<u32>) -> Region { let i = index.get(); index.set(i + 1); let depth = ty::INNERMOST; - Region::LateBoundAnon(depth, i) + Region::LateBoundAnon(depth, named_late_bound_vars + i, i) } fn id(&self) -> Option<DefId> { match *self { Region::Static | Region::LateBoundAnon(..) => None, - Region::EarlyBound(_, id, _) | Region::LateBound(_, id, _) | Region::Free(_, id) => { + Region::EarlyBound(_, id, _) | Region::LateBound(_, _, id, _) | Region::Free(_, id) => { Some(id) } } @@ -97,11 +100,11 @@ impl RegionExt for Region { fn shifted(self, amount: u32) -> Region { match self { - Region::LateBound(debruijn, id, origin) => { - Region::LateBound(debruijn.shifted_in(amount), id, origin) + Region::LateBound(debruijn, idx, id, origin) => { + Region::LateBound(debruijn.shifted_in(amount), idx, id, origin) } - Region::LateBoundAnon(debruijn, index) => { - Region::LateBoundAnon(debruijn.shifted_in(amount), index) + Region::LateBoundAnon(debruijn, index, anon_index) => { + Region::LateBoundAnon(debruijn.shifted_in(amount), index, anon_index) } _ => self, } @@ -109,11 +112,11 @@ impl RegionExt for Region { fn shifted_out_to_binder(self, binder: ty::DebruijnIndex) -> Region { match self { - Region::LateBound(debruijn, id, origin) => { - Region::LateBound(debruijn.shifted_out_to_binder(binder), id, origin) + Region::LateBound(debruijn, index, id, origin) => { + Region::LateBound(debruijn.shifted_out_to_binder(binder), index, id, origin) } - Region::LateBoundAnon(debruijn, index) => { - Region::LateBoundAnon(debruijn.shifted_out_to_binder(binder), index) + Region::LateBoundAnon(debruijn, index, anon_index) => { + Region::LateBoundAnon(debruijn.shifted_out_to_binder(binder), index, anon_index) } _ => self, } @@ -147,6 +150,14 @@ struct NamedRegionMap { // be late-bound if (a) it does NOT appear in a where-clause and // (b) it DOES appear in the arguments. late_bound: HirIdSet, + + // Maps relevant hir items to the bound vars on them. These include: + // - function defs + // - function pointers + // - closures + // - trait refs + // - bound types (like `T` in `for<'a> T<'a>: Foo`) + late_bound_vars: HirIdMap<Vec<ty::BoundVariableKind>>, } crate struct LifetimeContext<'a, 'tcx> { @@ -161,13 +172,21 @@ crate struct LifetimeContext<'a, 'tcx> { /// correct when representing these constraints, we should only introduce one /// scope. However, we want to support both locations for the quantifier and /// during lifetime resolution we want precise information (so we can't - /// desugar in an earlier phase). + /// desugar in an earlier phase). Moreso, an error here doesn't cause a bail + /// from type checking, so we need to be extra careful that we don't lose + /// any bound var information. /// /// So, if we encounter a quantifier at the outer scope, we set - /// `trait_ref_hack` to `true` (and introduce a scope), and then if we encounter - /// a quantifier at the inner scope, we error. If `trait_ref_hack` is `false`, - /// then we introduce the scope at the inner quantifier. - trait_ref_hack: bool, + /// `trait_ref_hack` to the hir id of the bounded type (and introduce a scope). + /// Then, if we encounter a quantifier at the inner scope, then we know to + /// emit an error. Importantly though, we do have to track the lifetimes + /// defined on the outer scope (i.e. the bounded ty), since we continue + /// to type check after emitting an error; we therefore assume that the bound + /// vars on the inner trait refs come from both quantifiers. + /// + /// If we encounter a quantifier in the inner scope `trait_ref_hack` being + /// `None`, then we just introduce the scope at the inner quantifier as normal. + trait_ref_hack: Option<hir::HirId>, /// Used to disallow the use of in-band lifetimes in `fn` or `Fn` syntax. is_in_fn_syntax: bool, @@ -225,6 +244,17 @@ enum Scope<'a> { /// of the resulting opaque type. opaque_type_parent: bool, + /// True only if this `Binder` scope is from the quantifiers on a + /// `PolyTraitRef`. This is necessary for `assocated_type_bounds`, which + /// requires binders of nested trait refs to be merged. + from_poly_trait_ref: bool, + + /// The late bound vars for a given item are stored by `HirId` to be + /// queried later. However, if we enter an elision scope, we have to + /// later append the elided bound vars to the list and need to know what + /// to append to. + hir_id: hir::HirId, + s: ScopeRef<'a>, }, @@ -252,6 +282,50 @@ enum Scope<'a> { s: ScopeRef<'a>, }, + /// This is a particularly interesting consequence of how we handle poly + /// trait refs. See `trait_ref_hack` for additional info. This bit is + /// important w.r.t. querying late-bound vars. + /// + /// To completely understand why this is necessary, first it's important to + /// realize that `T: for<'a> U + for<'a, 'b> V` is actually two separate + /// trait refs: `T: for<'a> U` and `T: for<'b> V` and as such, the late + /// bound vars on each needs to be tracked separately. Also, in this case, + /// are *three* relevant `HirId`s: one for the entire bound and one + /// for each separate one. + /// + /// Next, imagine three different poly trait refs: + /// 1) `for<'a, 'b> T: U<'a, 'b>` + /// 2) `T: for<'a, 'b> U<'a, 'b>` + /// 3) `for<'a> T: for<'b> U<'a, 'b>` + /// + /// First, note that the third example is semantically invalid and an error, + /// but we *must* handle it as valid, since type checking isn't bailed out + /// of. Other than that, if ask for bound vars for each, we expect + /// `['a, 'b]`. If we *didn't* allow binders before `T`, then we would + /// always introduce a binder scope at the inner trait ref. This is great, + /// becauase later on during type-checking, we will ask "what are the late + /// bound vars on this trait ref". However, because we allow bound vars on + /// the bound itself, we have to have some way of keeping track of the fact + /// that we actually want to store the late bound vars as being associated + /// with the trait ref; this is that. + /// + /// One alternative way to handle this would be to just introduce a new + /// `Binder` scope, but that's semantically a bit different, since bound + /// vars from both `for<...>`s *do* share the same binder level. + TraitRefHackInner { + hir_id: hir::HirId, + s: ScopeRef<'a>, + }, + + /// When we have nested trait refs, we concanetate late bound vars for inner + /// trait refs from outer ones. But we also need to include any HRTB + /// lifetimes encountered when identifying the trait that an associated type + /// is declared on. + Supertrait { + lifetimes: Vec<ty::BoundVariableKind>, + s: ScopeRef<'a>, + }, + Root, } @@ -266,6 +340,8 @@ impl<'a> fmt::Debug for TruncatedScopeDebug<'a> { next_early_index, track_lifetime_uses, opaque_type_parent, + from_poly_trait_ref, + hir_id, s: _, } => f .debug_struct("Binder") @@ -273,6 +349,8 @@ impl<'a> fmt::Debug for TruncatedScopeDebug<'a> { .field("next_early_index", next_early_index) .field("track_lifetime_uses", track_lifetime_uses) .field("opaque_type_parent", opaque_type_parent) + .field("from_poly_trait_ref", from_poly_trait_ref) + .field("hir_id", hir_id) .field("s", &"..") .finish(), Scope::Body { id, s: _ } => { @@ -286,6 +364,16 @@ impl<'a> fmt::Debug for TruncatedScopeDebug<'a> { .field("lifetime", lifetime) .field("s", &"..") .finish(), + Scope::TraitRefHackInner { hir_id, s: _ } => f + .debug_struct("TraitRefHackInner") + .field("hir_id", hir_id) + .field("s", &"..") + .finish(), + Scope::Supertrait { lifetimes, s: _ } => f + .debug_struct("Supertrait") + .field("lifetimes", lifetimes) + .field("s", &"..") + .finish(), Scope::Root => f.debug_struct("Root").finish(), } } @@ -294,8 +382,9 @@ impl<'a> fmt::Debug for TruncatedScopeDebug<'a> { #[derive(Clone, Debug)] enum Elide { /// Use a fresh anonymous late-bound lifetime each time, by - /// incrementing the counter to generate sequential indices. - FreshLateAnon(Cell<u32>), + /// incrementing the counter to generate sequential indices. All + /// anonymous lifetimes must start *after* named bound vars. + FreshLateAnon(u32, Cell<u32>), /// Always use this one lifetime. Exact(Region), /// Less or more than one lifetime were found, error on unspecified. @@ -334,6 +423,7 @@ pub fn provide(providers: &mut ty::query::Providers) { _ => None, } }, + late_bound_vars_map: |tcx, id| resolve_lifetimes_for(tcx, id).late_bound_vars.get(&id), ..*providers }; @@ -391,13 +481,16 @@ fn do_resolve( trait_definition_only: bool, ) -> ResolveLifetimes { let item = tcx.hir().expect_item(tcx.hir().local_def_id_to_hir_id(local_def_id)); - let mut named_region_map = - NamedRegionMap { defs: Default::default(), late_bound: Default::default() }; + let mut named_region_map = NamedRegionMap { + defs: Default::default(), + late_bound: Default::default(), + late_bound_vars: Default::default(), + }; let mut visitor = LifetimeContext { tcx, map: &mut named_region_map, scope: ROOT_SCOPE, - trait_ref_hack: false, + trait_ref_hack: None, is_in_fn_syntax: false, is_in_const_generic: false, trait_definition_only, @@ -418,6 +511,10 @@ fn do_resolve( let map = rl.late_bound.entry(hir_id.owner).or_default(); map.insert(hir_id.local_id); } + for (hir_id, v) in named_region_map.late_bound_vars { + let map = rl.late_bound_vars.entry(hir_id.owner).or_default(); + map.insert(hir_id.local_id, v); + } debug!(?rl.defs); rl @@ -503,6 +600,19 @@ fn sub_items_have_self_param(node: &hir::ItemKind<'_>) -> bool { matches!(*node, hir::ItemKind::Trait(..) | hir::ItemKind::TraitAlias(..)) } +fn late_region_as_bound_region<'tcx>(tcx: TyCtxt<'tcx>, region: &Region) -> ty::BoundVariableKind { + match region { + Region::LateBound(_, _, def_id, _) => { + let name = tcx.hir().name(tcx.hir().local_def_id_to_hir_id(def_id.expect_local())); + ty::BoundVariableKind::Region(ty::BrNamed(*def_id, name)) + } + Region::LateBoundAnon(_, _, anon_idx) => { + ty::BoundVariableKind::Region(ty::BrAnon(*anon_idx)) + } + _ => bug!("{:?} is not a late region", region), + } +} + impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { type Map = Map<'tcx>; @@ -530,11 +640,58 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { self.labels_in_fn = saved; } + fn visit_fn( + &mut self, + fk: intravisit::FnKind<'tcx>, + fd: &'tcx hir::FnDecl<'tcx>, + b: hir::BodyId, + s: rustc_span::Span, + hir_id: hir::HirId, + ) { + let name = match fk { + intravisit::FnKind::ItemFn(id, _, _, _) => id.as_str(), + intravisit::FnKind::Method(id, _, _) => id.as_str(), + intravisit::FnKind::Closure => Symbol::intern("closure").as_str(), + }; + let name: &str = &name; + let span = span!(Level::DEBUG, "visit_fn", name); + let _enter = span.enter(); + match fk { + // Any `Binders` are handled elsewhere + intravisit::FnKind::ItemFn(..) | intravisit::FnKind::Method(..) => { + intravisit::walk_fn(self, fk, fd, b, s, hir_id) + } + intravisit::FnKind::Closure => { + self.map.late_bound_vars.insert(hir_id, vec![]); + let scope = Scope::Binder { + hir_id, + lifetimes: FxHashMap::default(), + next_early_index: self.next_early_index(), + s: self.scope, + track_lifetime_uses: true, + opaque_type_parent: false, + from_poly_trait_ref: false, + }; + self.with(scope, move |_old_scope, this| { + intravisit::walk_fn(this, fk, fd, b, s, hir_id) + }); + } + } + } + fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) { + match &item.kind { + hir::ItemKind::Impl(hir::Impl { of_trait, .. }) => { + if let Some(of_trait) = of_trait { + self.map.late_bound_vars.insert(of_trait.hir_ref_id, Vec::default()); + } + } + _ => {} + } match item.kind { hir::ItemKind::Fn(ref sig, ref generics, _) => { self.missing_named_lifetime_spots.push(generics.into()); - self.visit_early_late(None, &sig.decl, generics, |this| { + self.visit_early_late(None, item.hir_id(), &sig.decl, generics, |this| { intravisit::walk_item(this, item); }); self.missing_named_lifetime_spots.pop(); @@ -582,6 +739,16 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { self.map.late_bound.insert(hir::HirId { owner, local_id }); }); } + for (&owner, late_bound_vars) in + resolved_lifetimes.late_bound_vars.iter() + { + late_bound_vars.iter().for_each(|(&local_id, late_bound_vars)| { + self.map.late_bound_vars.insert( + hir::HirId { owner, local_id }, + late_bound_vars.clone(), + ); + }); + } break; } hir::Node::Crate(_) => bug!("No Item about an OpaqueTy"), @@ -621,11 +788,14 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { } }) .collect(); + self.map.late_bound_vars.insert(item.hir_id(), vec![]); let scope = Scope::Binder { + hir_id: item.hir_id(), lifetimes, next_early_index: index + non_lifetime_count, opaque_type_parent: true, track_lifetime_uses, + from_poly_trait_ref: false, s: ROOT_SCOPE, }; self.with(scope, |old_scope, this| { @@ -640,7 +810,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem<'tcx>) { match item.kind { hir::ForeignItemKind::Fn(ref decl, _, ref generics) => { - self.visit_early_late(None, decl, generics, |this| { + self.visit_early_late(None, item.hir_id(), decl, generics, |this| { intravisit::walk_foreign_item(this, item); }) } @@ -672,21 +842,29 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { }; self.missing_named_lifetime_spots .push(MissingLifetimeSpot::HigherRanked { span, span_type }); + let (lifetimes, binders): (FxHashMap<hir::ParamName, Region>, Vec<_>) = c + .generic_params + .iter() + .filter_map(|param| match param.kind { + GenericParamKind::Lifetime { .. } => Some(param), + _ => None, + }) + .enumerate() + .map(|(late_bound_idx, param)| { + let pair = Region::late(late_bound_idx as u32, &self.tcx.hir(), param); + let r = late_region_as_bound_region(self.tcx, &pair.1); + (pair, r) + }) + .unzip(); + self.map.late_bound_vars.insert(ty.hir_id, binders); let scope = Scope::Binder { - lifetimes: c - .generic_params - .iter() - .filter_map(|param| match param.kind { - GenericParamKind::Lifetime { .. } => { - Some(Region::late(&self.tcx.hir(), param)) - } - _ => None, - }) - .collect(), + hir_id: ty.hir_id, + lifetimes, s: self.scope, next_early_index, track_lifetime_uses: true, opaque_type_parent: false, + from_poly_trait_ref: false, }; self.with(scope, |old_scope, this| { // a bare fn has no bounds, so everything @@ -721,7 +899,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { // resolved the same as the `'_` in `&'_ Foo`. // // cc #48468 - self.resolve_elided_lifetimes(vec![lifetime]) + self.resolve_elided_lifetimes(&[lifetime]) } LifetimeName::Param(_) | LifetimeName::Static => { // If the user wrote an explicit name, use that. @@ -784,7 +962,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { // well-supported at the moment, so this doesn't work. // In the future, this should be fixed and this error should be removed. let def = self.map.defs.get(&lifetime.hir_id).cloned(); - if let Some(Region::LateBound(_, def_id, _)) = def { + if let Some(Region::LateBound(_, _, def_id, _)) = def { if let Some(def_id) = def_id.as_local() { let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id); // Ensure that the parent of the def is an item, not HRTB @@ -863,17 +1041,20 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { } } let next_early_index = index + non_lifetime_count; + self.map.late_bound_vars.insert(ty.hir_id, vec![]); if let Some(elision_region) = elision { let scope = Scope::Elision { elide: Elide::Exact(elision_region), s: self.scope }; self.with(scope, |_old_scope, this| { let scope = Scope::Binder { + hir_id: ty.hir_id, lifetimes, next_early_index, s: this.scope, track_lifetime_uses: true, opaque_type_parent: false, + from_poly_trait_ref: false, }; this.with(scope, |_old_scope, this| { this.visit_generics(generics); @@ -884,11 +1065,13 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { }); } else { let scope = Scope::Binder { + hir_id: ty.hir_id, lifetimes, next_early_index, s: self.scope, track_lifetime_uses: true, opaque_type_parent: false, + from_poly_trait_ref: false, }; self.with(scope, |_old_scope, this| { this.visit_generics(generics); @@ -910,6 +1093,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { let tcx = self.tcx; self.visit_early_late( Some(tcx.hir().get_parent_item(trait_item.hir_id())), + trait_item.hir_id(), &sig.decl, &trait_item.generics, |this| intravisit::walk_trait_item(this, trait_item), @@ -935,12 +1119,15 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { } }) .collect(); + self.map.late_bound_vars.insert(trait_item.hir_id(), vec![]); let scope = Scope::Binder { + hir_id: trait_item.hir_id(), lifetimes, next_early_index: index + non_lifetime_count, s: self.scope, track_lifetime_uses: true, opaque_type_parent: true, + from_poly_trait_ref: false, }; self.with(scope, |old_scope, this| { this.check_lifetime_params(old_scope, &generics.params); @@ -972,6 +1159,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { let tcx = self.tcx; self.visit_early_late( Some(tcx.hir().get_parent_item(impl_item.hir_id())), + impl_item.hir_id(), &sig.decl, &impl_item.generics, |this| intravisit::walk_impl_item(this, impl_item), @@ -984,7 +1172,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { let mut index = self.next_early_index(); let mut non_lifetime_count = 0; debug!("visit_ty: index = {}", index); - let lifetimes = generics + let lifetimes: FxHashMap<hir::ParamName, Region> = generics .params .iter() .filter_map(|param| match param.kind { @@ -997,12 +1185,15 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { } }) .collect(); + self.map.late_bound_vars.insert(ty.hir_id, vec![]); let scope = Scope::Binder { + hir_id: ty.hir_id, lifetimes, next_early_index: index + non_lifetime_count, s: self.scope, track_lifetime_uses: true, opaque_type_parent: true, + from_poly_trait_ref: false, }; self.with(scope, |old_scope, this| { this.check_lifetime_params(old_scope, &generics.params); @@ -1024,7 +1215,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { #[tracing::instrument(level = "debug", skip(self))] fn visit_lifetime(&mut self, lifetime_ref: &'tcx hir::Lifetime) { if lifetime_ref.is_elided() { - self.resolve_elided_lifetimes(vec![lifetime_ref]); + self.resolve_elided_lifetimes(&[lifetime_ref]); return; } if lifetime_ref.is_static() { @@ -1085,30 +1276,39 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { ref bound_generic_params, .. }) => { - let lifetimes: FxHashMap<_, _> = bound_generic_params - .iter() - .filter_map(|param| match param.kind { - GenericParamKind::Lifetime { .. } => { - Some(Region::late(&self.tcx.hir(), param)) - } - _ => None, - }) - .collect(); + let (lifetimes, binders): (FxHashMap<hir::ParamName, Region>, Vec<_>) = + bound_generic_params + .iter() + .filter_map(|param| match param.kind { + GenericParamKind::Lifetime { .. } => Some(param), + _ => None, + }) + .enumerate() + .map(|(late_bound_idx, param)| { + let pair = + Region::late(late_bound_idx as u32, &self.tcx.hir(), param); + let r = late_region_as_bound_region(self.tcx, &pair.1); + (pair, r) + }) + .unzip(); + self.map.late_bound_vars.insert(bounded_ty.hir_id, binders.clone()); if !lifetimes.is_empty() { let next_early_index = self.next_early_index(); let scope = Scope::Binder { + hir_id: bounded_ty.hir_id, lifetimes, s: self.scope, next_early_index, track_lifetime_uses: true, opaque_type_parent: false, + from_poly_trait_ref: true, }; let result = self.with(scope, |old_scope, this| { this.check_lifetime_params(old_scope, &bound_generic_params); this.visit_ty(&bounded_ty); - this.trait_ref_hack = true; + this.trait_ref_hack = Some(bounded_ty.hir_id); walk_list!(this, visit_param_bound, bounds); - this.trait_ref_hack = false; + this.trait_ref_hack = None; }); result } else { @@ -1138,13 +1338,16 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { fn visit_param_bound(&mut self, bound: &'tcx hir::GenericBound<'tcx>) { match bound { - hir::GenericBound::LangItemTrait { .. } if !self.trait_ref_hack => { + hir::GenericBound::LangItemTrait(_, _, hir_id, _) if self.trait_ref_hack.is_none() => { + self.map.late_bound_vars.insert(*hir_id, vec![]); let scope = Scope::Binder { + hir_id: *hir_id, lifetimes: FxHashMap::default(), s: self.scope, next_early_index: self.next_early_index(), track_lifetime_uses: true, opaque_type_parent: false, + from_poly_trait_ref: false, }; self.with(scope, |_, this| { intravisit::walk_param_bound(this, bound); @@ -1163,38 +1366,128 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { let should_pop_missing_lt = self.is_trait_ref_fn_scope(trait_ref); - let trait_ref_hack = take(&mut self.trait_ref_hack); - if !trait_ref_hack - || trait_ref + let trait_ref_hack = self.trait_ref_hack.take(); + let next_early_index = self.next_early_index(); + // See note on `trait_ref_hack`. If `for<..>` has been defined in both + // the outer and inner part of the trait ref, emit an error. + let has_lifetimes = trait_ref.bound_generic_params.iter().any(|param| match param.kind { + GenericParamKind::Lifetime { .. } => true, + _ => false, + }); + if trait_ref_hack.is_some() && has_lifetimes { + struct_span_err!( + self.tcx.sess, + trait_ref.span, + E0316, + "nested quantification of lifetimes" + ) + .emit(); + } + + let (binders, lifetimes) = if let Some(hir_id) = trait_ref_hack { + let mut binders = self.map.late_bound_vars.entry(hir_id).or_default().clone(); + let initial_bound_vars = binders.len() as u32; + let mut lifetimes: FxHashMap<hir::ParamName, Region> = FxHashMap::default(); + let binders_iter = trait_ref .bound_generic_params .iter() - .any(|param| matches!(param.kind, GenericParamKind::Lifetime { .. })) - { - if trait_ref_hack { - struct_span_err!( - self.tcx.sess, - trait_ref.span, - E0316, - "nested quantification of lifetimes" - ) - .emit(); - } - let next_early_index = self.next_early_index(); - let scope = Scope::Binder { - lifetimes: trait_ref - .bound_generic_params - .iter() - .filter_map(|param| match param.kind { - GenericParamKind::Lifetime { .. } => { - Some(Region::late(&self.tcx.hir(), param)) + .filter_map(|param| match param.kind { + GenericParamKind::Lifetime { .. } => Some(param), + _ => None, + }) + .enumerate() + .map(|(late_bound_idx, param)| { + let pair = Region::late( + initial_bound_vars + late_bound_idx as u32, + &self.tcx.hir(), + param, + ); + let r = late_region_as_bound_region(self.tcx, &pair.1); + lifetimes.insert(pair.0, pair.1); + r + }); + binders.extend(binders_iter); + + (binders, lifetimes) + } else { + let mut supertrait_lifetimes = vec![]; + let mut scope = self.scope; + let mut outer_binders = loop { + match scope { + Scope::Body { .. } | Scope::Root => { + break vec![]; + } + + Scope::Elision { s, .. } | Scope::ObjectLifetimeDefault { s, .. } => { + scope = s; + } + + Scope::TraitRefHackInner { hir_id, .. } => { + // Nested poly trait refs have the binders concatenated + // If we reach `TraitRefHackInner`, then there is only one more `Binder` above us, + // over all the bounds. We don't want this, since all the lifetimes we care about + // are here anyways. + let mut full_binders = + self.map.late_bound_vars.entry(*hir_id).or_default().clone(); + full_binders.extend(supertrait_lifetimes.into_iter()); + break full_binders; + } + + Scope::Supertrait { s, lifetimes } => { + supertrait_lifetimes = lifetimes.clone(); + scope = s; + } + + Scope::Binder { hir_id, from_poly_trait_ref, .. } => { + if !from_poly_trait_ref { + // We should only see super trait lifetimes if there is a `Binder` above + assert!(supertrait_lifetimes.is_empty()); + break vec![]; } - _ => None, - }) - .collect(), + // Nested poly trait refs have the binders concatenated + let mut full_binders = + self.map.late_bound_vars.entry(*hir_id).or_default().clone(); + full_binders.extend(supertrait_lifetimes.into_iter()); + break full_binders; + } + } + }; + let (lifetimes, local_binders): (FxHashMap<hir::ParamName, Region>, Vec<_>) = trait_ref + .bound_generic_params + .iter() + .filter_map(|param| match param.kind { + GenericParamKind::Lifetime { .. } => Some(param), + _ => None, + }) + .enumerate() + .map(|(late_bound_idx, param)| { + let pair = Region::late( + outer_binders.len() as u32 + late_bound_idx as u32, + &self.tcx.hir(), + param, + ); + let r = late_region_as_bound_region(self.tcx, &pair.1); + (pair, r) + }) + .unzip(); + + outer_binders.extend(local_binders.into_iter()); + + (outer_binders, lifetimes) + }; + + debug!(?binders); + self.map.late_bound_vars.insert(trait_ref.trait_ref.hir_ref_id, binders); + + if trait_ref_hack.is_none() || has_lifetimes { + let scope = Scope::Binder { + hir_id: trait_ref.trait_ref.hir_ref_id, + lifetimes, s: self.scope, next_early_index, track_lifetime_uses: true, opaque_type_parent: false, + from_poly_trait_ref: true, }; self.with(scope, |old_scope, this| { this.check_lifetime_params(old_scope, &trait_ref.bound_generic_params); @@ -1202,7 +1495,11 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { this.visit_trait_ref(&trait_ref.trait_ref); }); } else { - self.visit_trait_ref(&trait_ref.trait_ref); + let scope = + Scope::TraitRefHackInner { hir_id: trait_ref.trait_ref.hir_ref_id, s: self.scope }; + self.with(scope, |_old_scope, this| { + this.visit_trait_ref(&trait_ref.trait_ref); + }); } self.trait_ref_hack = trait_ref_hack; if should_pop_missing_lt { @@ -1354,7 +1651,9 @@ fn extract_labels(ctxt: &mut LifetimeContext<'_, '_>, body: &hir::Body<'_>) { match *scope { Scope::Body { s, .. } | Scope::Elision { s, .. } - | Scope::ObjectLifetimeDefault { s, .. } => { + | Scope::ObjectLifetimeDefault { s, .. } + | Scope::TraitRefHackInner { s, .. } + | Scope::Supertrait { s, .. } => { scope = s; } @@ -1543,11 +1842,12 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { let labels_in_fn = take(&mut self.labels_in_fn); let xcrate_object_lifetime_defaults = take(&mut self.xcrate_object_lifetime_defaults); let missing_named_lifetime_spots = take(&mut self.missing_named_lifetime_spots); + let trait_ref_hack = take(&mut self.trait_ref_hack); let mut this = LifetimeContext { tcx: *tcx, map, scope: &wrap_scope, - trait_ref_hack: self.trait_ref_hack, + trait_ref_hack, is_in_fn_syntax: self.is_in_fn_syntax, is_in_const_generic: self.is_in_const_generic, trait_definition_only: self.trait_definition_only, @@ -1567,6 +1867,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { self.labels_in_fn = this.labels_in_fn; self.xcrate_object_lifetime_defaults = this.xcrate_object_lifetime_defaults; self.missing_named_lifetime_spots = this.missing_named_lifetime_spots; + self.trait_ref_hack = this.trait_ref_hack; } /// helper method to determine the span to remove when suggesting the @@ -1715,7 +2016,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { .values() .flat_map(|region| match region { Region::EarlyBound(_, def_id, _) - | Region::LateBound(_, def_id, _) + | Region::LateBound(_, _, def_id, _) | Region::Free(_, def_id) => Some(*def_id), Region::LateBoundAnon(..) | Region::Static => None, @@ -1861,6 +2162,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { fn visit_early_late<F>( &mut self, parent_id: Option<hir::HirId>, + hir_id: hir::HirId, decl: &'tcx hir::FnDecl<'tcx>, generics: &'tcx hir::Generics<'tcx>, walk: F, @@ -1870,31 +2172,34 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { insert_late_bound_lifetimes(self.map, decl, generics); // Find the start of nested early scopes, e.g., in methods. - let mut index = 0; + let mut next_early_index = 0; if let Some(parent_id) = parent_id { let parent = self.tcx.hir().expect_item(parent_id); if sub_items_have_self_param(&parent.kind) { - index += 1; // Self comes before lifetimes + next_early_index += 1; // Self comes before lifetimes } match parent.kind { hir::ItemKind::Trait(_, _, ref generics, ..) | hir::ItemKind::Impl(hir::Impl { ref generics, .. }) => { - index += generics.params.len() as u32; + next_early_index += generics.params.len() as u32; } _ => {} } } let mut non_lifetime_count = 0; - let lifetimes = generics + let mut named_late_bound_vars = 0; + let lifetimes: FxHashMap<hir::ParamName, Region> = generics .params .iter() .filter_map(|param| match param.kind { GenericParamKind::Lifetime { .. } => { if self.map.late_bound.contains(¶m.hir_id) { - Some(Region::late(&self.tcx.hir(), param)) + let late_bound_idx = named_late_bound_vars; + named_late_bound_vars += 1; + Some(Region::late(late_bound_idx, &self.tcx.hir(), param)) } else { - Some(Region::early(&self.tcx.hir(), &mut index, param)) + Some(Region::early(&self.tcx.hir(), &mut next_early_index, param)) } } GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => { @@ -1903,14 +2208,35 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { } }) .collect(); - let next_early_index = index + non_lifetime_count; + let next_early_index = next_early_index + non_lifetime_count; + let binders: Vec<_> = generics + .params + .iter() + .filter_map(|param| match param.kind { + GenericParamKind::Lifetime { .. } + if self.map.late_bound.contains(¶m.hir_id) => + { + Some(param) + } + _ => None, + }) + .enumerate() + .map(|(late_bound_idx, param)| { + let pair = Region::late(late_bound_idx as u32, &self.tcx.hir(), param); + let r = late_region_as_bound_region(self.tcx, &pair.1); + r + }) + .collect(); + self.map.late_bound_vars.insert(hir_id, binders); let scope = Scope::Binder { + hir_id, lifetimes, next_early_index, s: self.scope, opaque_type_parent: true, track_lifetime_uses: false, + from_poly_trait_ref: false, }; self.with(scope, move |old_scope, this| { this.check_lifetime_params(old_scope, &generics.params); @@ -1933,7 +2259,9 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { Scope::Binder { s, .. } | Scope::Body { s, .. } | Scope::Elision { s, .. } - | Scope::ObjectLifetimeDefault { s, .. } => scope = s, + | Scope::ObjectLifetimeDefault { s, .. } + | Scope::TraitRefHackInner { s, .. } + | Scope::Supertrait { s, .. } => scope = s, } } } @@ -1965,6 +2293,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { // given name or we run out of scopes. // search. let mut late_depth = 0; + let mut in_poly_trait_ref = false; let mut scope = self.scope; let mut outermost_body = None; let result = loop { @@ -1982,7 +2311,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { break None; } - Scope::Binder { ref lifetimes, s, .. } => { + Scope::Binder { ref lifetimes, from_poly_trait_ref, s, .. } => { match lifetime_ref.name { LifetimeName::Param(param_name) => { if let Some(&def) = lifetimes.get(¶m_name.normalize_to_macros_2_0()) @@ -1993,11 +2322,35 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { _ => bug!("expected LifetimeName::Param"), } - late_depth += 1; + match (from_poly_trait_ref, in_poly_trait_ref) { + // This is the first binder we see that is a poly trait ref; add one to the + // late depth and mark that we're potentially in nested trait refs. + (true, false) => { + in_poly_trait_ref = true; + late_depth += 1; + } + // We've already seen a binder that is a poly trait ref and this one is too, + // that means that they are nested and we are concatenating the bound vars; + // don't increase the late depth. + (true, true) => {} + // We've exited nested poly trait refs; add one to the late depth and mark + // that we are no longer in nested trait refs + (false, true) => { + in_poly_trait_ref = false; + late_depth += 1; + } + // Any other kind of nested binders: just increase late depth. + (false, false) => { + late_depth += 1; + } + } scope = s; } - Scope::Elision { s, .. } | Scope::ObjectLifetimeDefault { s, .. } => { + Scope::Elision { s, .. } + | Scope::ObjectLifetimeDefault { s, .. } + | Scope::TraitRefHackInner { s, .. } + | Scope::Supertrait { s, .. } => { scope = s; } } @@ -2025,7 +2378,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { if !self.trait_definition_only && self.is_in_fn_syntax { match def { Region::EarlyBound(_, _, LifetimeDefOrigin::InBand) - | Region::LateBound(_, _, LifetimeDefOrigin::InBand) => { + | Region::LateBound(_, _, _, LifetimeDefOrigin::InBand) => { struct_span_err!( self.tcx.sess, lifetime_ref.span, @@ -2046,6 +2399,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { | Region::LateBound( _, _, + _, LifetimeDefOrigin::ExplicitOrElided | LifetimeDefOrigin::Error, ) | Region::LateBoundAnon(..) @@ -2079,7 +2433,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { } let mut elide_lifetimes = true; - let lifetimes = generic_args + let lifetimes: Vec<_> = generic_args .args .iter() .filter_map(|arg| match arg { @@ -2092,8 +2446,10 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { _ => None, }) .collect(); + // We short-circuit here if all are elided in order to pluralize + // possible errors if elide_lifetimes { - self.resolve_elided_lifetimes(lifetimes); + self.resolve_elided_lifetimes(&lifetimes); } else { lifetimes.iter().for_each(|lt| self.visit_lifetime(lt)); } @@ -2146,7 +2502,9 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { Scope::Binder { s, .. } | Scope::Elision { s, .. } - | Scope::ObjectLifetimeDefault { s, .. } => { + | Scope::ObjectLifetimeDefault { s, .. } + | Scope::TraitRefHackInner { s, .. } + | Scope::Supertrait { s, .. } => { scope = s; } } @@ -2245,13 +2603,84 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { let has_lifetime_parameter = generic_args.args.iter().any(|arg| matches!(arg, GenericArg::Lifetime(_))); - // Resolve lifetimes found in the type `XX` from `Item = XX` bindings. - for b in generic_args.bindings { + // Resolve lifetimes found in the bindings, so either in the type `XX` in `Item = XX` or + // in the trait ref `YY<...>` in `Item: YY<...>`. + for binding in generic_args.bindings { let scope = Scope::ObjectLifetimeDefault { lifetime: if has_lifetime_parameter { None } else { Some(Region::Static) }, s: self.scope, }; - self.with(scope, |_, this| this.visit_assoc_type_binding(b)); + if let Some(type_def_id) = type_def_id { + let lifetimes = LifetimeContext::supertrait_hrtb_lifetimes( + self.tcx, + type_def_id, + binding.ident, + ); + self.with(scope, |_, this| { + let scope = + Scope::Supertrait { lifetimes: lifetimes.unwrap_or(vec![]), s: this.scope }; + this.with(scope, |_, this| this.visit_assoc_type_binding(binding)); + }); + } else { + self.with(scope, |_, this| this.visit_assoc_type_binding(binding)); + } + } + } + + /// Returns all the late-bound vars that come into scope from supertrait HRTBs, based on the + /// associated type name and starting trait. + /// For example, imagine we have + /// ```rust + /// trait Foo<'a, 'b> { + /// type As; + /// } + /// trait Bar<'b>: for<'a> Foo<'a, 'b> {} + /// trait Bar: for<'b> Bar<'b> {} + /// ``` + /// In this case, if we wanted to the supertrait HRTB lifetimes for `As` on + /// the starting trait `Bar`, we would return `Some(['b, 'a])`. + fn supertrait_hrtb_lifetimes( + tcx: TyCtxt<'tcx>, + def_id: DefId, + assoc_name: Ident, + ) -> Option<Vec<ty::BoundVariableKind>> { + let trait_defines_associated_type_named = |trait_def_id: DefId| { + tcx.associated_items(trait_def_id) + .find_by_name_and_kind(tcx, assoc_name, ty::AssocKind::Type, trait_def_id) + .is_some() + }; + + use smallvec::{smallvec, SmallVec}; + let mut stack: SmallVec<[(DefId, SmallVec<[ty::BoundVariableKind; 8]>); 8]> = + smallvec![(def_id, smallvec![])]; + let mut visited: FxHashSet<DefId> = FxHashSet::default(); + loop { + let (def_id, bound_vars) = match stack.pop() { + Some(next) => next, + None => break None, + }; + if trait_defines_associated_type_named(def_id) { + break Some(bound_vars.into_iter().collect()); + } + let predicates = + tcx.super_predicates_that_define_assoc_type((def_id, Some(assoc_name))); + let obligations = predicates.predicates.iter().filter_map(|&(pred, _)| { + let bound_predicate = pred.kind(); + match bound_predicate.skip_binder() { + ty::PredicateKind::Trait(data, _) => { + // The order here needs to match what we would get from `subst_supertrait` + let pred_bound_vars = bound_predicate.bound_vars(); + let mut all_bound_vars = bound_vars.clone(); + all_bound_vars.extend(pred_bound_vars.iter()); + let super_def_id = data.trait_ref.def_id; + Some((super_def_id, all_bound_vars)) + } + _ => None, + } + }); + + let obligations = obligations.filter(|o| visited.insert(o.0)); + stack.extend(obligations); } } @@ -2261,7 +2690,37 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { inputs: &'tcx [hir::Ty<'tcx>], output: Option<&'tcx hir::Ty<'tcx>>, ) { - let arg_scope = Scope::Elision { elide: Elide::FreshLateAnon(Cell::new(0)), s: self.scope }; + debug!("visit_fn_like_elision: enter"); + let mut scope = &*self.scope; + let hir_id = loop { + match scope { + Scope::Binder { hir_id, .. } | Scope::TraitRefHackInner { hir_id, .. } => { + break *hir_id; + } + Scope::Body { id, .. } => break id.hir_id, + Scope::ObjectLifetimeDefault { ref s, .. } + | Scope::Elision { ref s, .. } + | Scope::Supertrait { ref s, .. } => { + scope = *s; + } + Scope::Root => bug!("In fn_like_elision without appropriate scope above"), + } + }; + // While not strictly necessary, we gather anon lifetimes *before* actually + // visiting the argument types. + let mut gather = GatherAnonLifetimes { anon_count: 0 }; + for input in inputs { + gather.visit_ty(input); + } + let late_bound_vars = self.map.late_bound_vars.entry(hir_id).or_default(); + let named_late_bound_vars = late_bound_vars.len() as u32; + late_bound_vars.extend( + (0..gather.anon_count).map(|var| ty::BoundVariableKind::Region(ty::BrAnon(var))), + ); + let arg_scope = Scope::Elision { + elide: Elide::FreshLateAnon(named_late_bound_vars, Cell::new(0)), + s: self.scope, + }; self.with(arg_scope, |_, this| { for input in inputs { this.visit_ty(input); @@ -2516,7 +2975,8 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { fn visit_lifetime(&mut self, lifetime_ref: &hir::Lifetime) { if let Some(&lifetime) = self.map.defs.get(&lifetime_ref.hir_id) { match lifetime { - Region::LateBound(debruijn, _, _) | Region::LateBoundAnon(debruijn, _) + Region::LateBound(debruijn, _, _, _) + | Region::LateBoundAnon(debruijn, _, _) if debruijn < self.outer_index => { self.have_bound_regions = true; @@ -2528,9 +2988,46 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { } } } + + struct GatherAnonLifetimes { + anon_count: u32, + } + impl<'v> Visitor<'v> for GatherAnonLifetimes { + type Map = intravisit::ErasedMap<'v>; + + fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> { + NestedVisitorMap::None + } + + fn visit_ty(&mut self, ty: &hir::Ty<'_>) { + // If we enter a `BareFn`, then we enter a *new* binding scope + if let hir::TyKind::BareFn(_) = ty.kind { + return; + } + intravisit::walk_ty(self, ty); + } + + fn visit_generic_args( + &mut self, + path_span: Span, + generic_args: &'v hir::GenericArgs<'v>, + ) { + // parenthesized args enter a new elison scope + if generic_args.parenthesized { + return; + } + intravisit::walk_generic_args(self, path_span, generic_args) + } + + fn visit_lifetime(&mut self, lifetime_ref: &hir::Lifetime) { + if lifetime_ref.is_elided() { + self.anon_count += 1; + } + } + } } - fn resolve_elided_lifetimes(&mut self, lifetime_refs: Vec<&'tcx hir::Lifetime>) { + fn resolve_elided_lifetimes(&mut self, lifetime_refs: &[&'tcx hir::Lifetime]) { debug!("resolve_elided_lifetimes(lifetime_refs={:?})", lifetime_refs); if lifetime_refs.is_empty() { @@ -2539,6 +3036,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { let span = lifetime_refs[0].span; let mut late_depth = 0; + let mut in_poly_trait_ref = false; let mut scope = self.scope; let mut lifetime_names = FxHashSet::default(); let mut lifetime_spans = vec![]; @@ -2549,7 +3047,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { Scope::Root => break None, - Scope::Binder { s, ref lifetimes, .. } => { + Scope::Binder { s, ref lifetimes, from_poly_trait_ref, .. } => { // collect named lifetimes for suggestions for name in lifetimes.keys() { if let hir::ParamName::Plain(name) = name { @@ -2557,15 +3055,31 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { lifetime_spans.push(name.span); } } - late_depth += 1; + // See comments in `resolve_lifetime_ref` + match (from_poly_trait_ref, in_poly_trait_ref) { + (true, false) => { + in_poly_trait_ref = true; + late_depth += 1; + } + (true, true) => {} + (false, true) => { + in_poly_trait_ref = false; + late_depth += 1; + } + (false, false) => { + late_depth += 1; + } + } scope = s; } Scope::Elision { ref elide, ref s, .. } => { let lifetime = match *elide { - Elide::FreshLateAnon(ref counter) => { + Elide::FreshLateAnon(named_late_bound_vars, ref counter) => { for lifetime_ref in lifetime_refs { - let lifetime = Region::late_anon(counter).shifted(late_depth); + let lifetime = Region::late_anon(named_late_bound_vars, counter) + .shifted(late_depth); + self.insert_lifetime(lifetime_ref, lifetime); } return; @@ -2602,7 +3116,9 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { return; } - Scope::ObjectLifetimeDefault { s, .. } => { + Scope::ObjectLifetimeDefault { s, .. } + | Scope::TraitRefHackInner { s, .. } + | Scope::Supertrait { s, .. } => { scope = s; } } @@ -2708,11 +3224,25 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { fn resolve_object_lifetime_default(&mut self, lifetime_ref: &'tcx hir::Lifetime) { debug!("resolve_object_lifetime_default(lifetime_ref={:?})", lifetime_ref); let mut late_depth = 0; + let mut in_poly_trait_ref = false; let mut scope = self.scope; let lifetime = loop { match *scope { - Scope::Binder { s, .. } => { - late_depth += 1; + Scope::Binder { s, from_poly_trait_ref, .. } => { + match (from_poly_trait_ref, in_poly_trait_ref) { + (true, false) => { + in_poly_trait_ref = true; + late_depth += 1; + } + (true, true) => {} + (false, true) => { + in_poly_trait_ref = false; + late_depth += 1; + } + (false, false) => { + late_depth += 1; + } + } scope = s; } @@ -2721,6 +3251,10 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { Scope::Body { .. } | Scope::ObjectLifetimeDefault { lifetime: None, .. } => return, Scope::ObjectLifetimeDefault { lifetime: Some(l), .. } => break l, + + Scope::TraitRefHackInner { s, .. } | Scope::Supertrait { s, .. } => { + scope = s; + } } }; self.insert_lifetime(lifetime_ref, lifetime.shifted(late_depth)); @@ -2844,7 +3378,9 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { match *old_scope { Scope::Body { s, .. } | Scope::Elision { s, .. } - | Scope::ObjectLifetimeDefault { s, .. } => { + | Scope::ObjectLifetimeDefault { s, .. } + | Scope::TraitRefHackInner { s, .. } + | Scope::Supertrait { s, .. } => { old_scope = s; } @@ -2890,7 +3426,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { // A lifetime only used in a fn argument could as well // be replaced with `'_`, as that would generate a // fresh name, too. - Scope::Elision { elide: Elide::FreshLateAnon(_), .. } => break true, + Scope::Elision { elide: Elide::FreshLateAnon(..), .. } => break true, // In the return type or other such place, `'_` is not // going to make a fresh name, so we cannot @@ -2900,7 +3436,9 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { elide: Elide::Exact(_) | Elide::Error(_) | Elide::Forbid, .. } => break false, - Scope::ObjectLifetimeDefault { s, .. } => scope = s, + Scope::ObjectLifetimeDefault { s, .. } + | Scope::TraitRefHackInner { s, .. } + | Scope::Supertrait { s, .. } => scope = s, } } } @@ -2919,7 +3457,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { } Region::Free(_, def_id) - | Region::LateBound(_, def_id, _) + | Region::LateBound(_, _, def_id, _) | Region::EarlyBound(_, def_id, _) => { // A lifetime declared by the user. let track_lifetime_uses = self.track_lifetime_uses(); diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 14e3d8498b0..fe5078f26bd 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -14,6 +14,7 @@ #![feature(control_flow_enum)] #![feature(crate_visibility_modifier)] #![feature(format_args_capture)] +#![feature(iter_zip)] #![feature(nll)] #![cfg_attr(bootstrap, feature(or_patterns))] #![recursion_limit = "256"] @@ -25,7 +26,6 @@ use Determinacy::*; use rustc_arena::{DroplessArena, TypedArena}; use rustc_ast::node_id::NodeMap; use rustc_ast::ptr::P; -use rustc_ast::unwrap_or; use rustc_ast::visit::{self, Visitor}; use rustc_ast::{self as ast, NodeId}; use rustc_ast::{Crate, CRATE_NODE_ID}; @@ -42,7 +42,7 @@ use rustc_hir::def::Namespace::*; use rustc_hir::def::{self, CtorOf, DefKind, NonMacroAttrKind, PartialRes}; use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, CRATE_DEF_INDEX}; use rustc_hir::definitions::{DefKey, DefPathData, Definitions}; -use rustc_hir::{PrimTy, TraitCandidate}; +use rustc_hir::TraitCandidate; use rustc_index::vec::IndexVec; use rustc_metadata::creader::{CStore, CrateLoader}; use rustc_middle::hir::exports::ExportMap; @@ -108,7 +108,9 @@ enum Scope<'a> { DeriveHelpersCompat, MacroRules(MacroRulesScopeRef<'a>), CrateRoot, - Module(Module<'a>), + // The node ID is for reporting the `PROC_MACRO_DERIVE_RESOLUTION_FALLBACK` + // lint if it should be reported. + Module(Module<'a>, Option<NodeId>), RegisteredAttrs, MacroUsePrelude, BuiltinAttrs, @@ -122,13 +124,17 @@ enum Scope<'a> { /// with different restrictions when looking up the resolution. /// This enum is currently used only for early resolution (imports and macros), /// but not for late resolution yet. -enum ScopeSet { +#[derive(Clone, Copy)] +enum ScopeSet<'a> { /// All scopes with the given namespace. All(Namespace, /*is_import*/ bool), /// Crate root, then extern prelude (used for mixed 2015-2018 mode in macros). AbsolutePath(Namespace), /// All scopes with macro namespace and the given macro kind restriction. Macro(MacroKind), + /// All scopes with the given namespace, used for partially performing late resolution. + /// The node id enables lints and is used for reporting them. + Late(Namespace, Module<'a>, Option<NodeId>), } /// Everything you need to know about a name's location to resolve it. @@ -1466,7 +1472,7 @@ impl<'a> Resolver<'a> { self.visit_scopes(ScopeSet::All(TypeNS, false), parent_scope, ctxt, |this, scope, _, _| { match scope { - Scope::Module(module) => { + Scope::Module(module, _) => { this.traits_in_module(module, assoc_item, &mut found_traits); } Scope::StdLibPrelude => { @@ -1630,7 +1636,7 @@ impl<'a> Resolver<'a> { /// If the callback returns `Some` result, we stop visiting scopes and return it. fn visit_scopes<T>( &mut self, - scope_set: ScopeSet, + scope_set: ScopeSet<'a>, parent_scope: &ParentScope<'a>, ctxt: SyntaxContext, mut visitor: impl FnMut( @@ -1686,12 +1692,17 @@ impl<'a> Resolver<'a> { ScopeSet::All(ns, _) => (ns, None, false), ScopeSet::AbsolutePath(ns) => (ns, None, true), ScopeSet::Macro(macro_kind) => (MacroNS, Some(macro_kind), false), + ScopeSet::Late(ns, ..) => (ns, None, false), + }; + let module = match scope_set { + // Start with the specified module. + ScopeSet::Late(_, module, _) => module, + // Jump out of trait or enum modules, they do not act as scopes. + _ => parent_scope.module.nearest_item_scope(), }; - // Jump out of trait or enum modules, they do not act as scopes. - let module = parent_scope.module.nearest_item_scope(); let mut scope = match ns { _ if is_absolute_path => Scope::CrateRoot, - TypeNS | ValueNS => Scope::Module(module), + TypeNS | ValueNS => Scope::Module(module, None), MacroNS => Scope::DeriveHelpers(parent_scope.expansion), }; let mut ctxt = ctxt.normalize_to_macros_2_0(); @@ -1756,7 +1767,7 @@ impl<'a> Resolver<'a> { MacroRulesScope::Invocation(invoc_id) => { Scope::MacroRules(self.invocation_parent_scopes[&invoc_id].macro_rules) } - MacroRulesScope::Empty => Scope::Module(module), + MacroRulesScope::Empty => Scope::Module(module, None), }, Scope::CrateRoot => match ns { TypeNS => { @@ -1765,10 +1776,16 @@ impl<'a> Resolver<'a> { } ValueNS | MacroNS => break, }, - Scope::Module(module) => { + Scope::Module(module, prev_lint_id) => { use_prelude = !module.no_implicit_prelude; - match self.hygienic_lexical_parent(module, &mut ctxt) { - Some(parent_module) => Scope::Module(parent_module), + let derive_fallback_lint_id = match scope_set { + ScopeSet::Late(.., lint_id) => lint_id, + _ => None, + }; + match self.hygienic_lexical_parent(module, &mut ctxt, derive_fallback_lint_id) { + Some((parent_module, lint_id)) => { + Scope::Module(parent_module, lint_id.or(prev_lint_id)) + } None => { ctxt.adjust(ExpnId::root()); match ns { @@ -1824,6 +1841,7 @@ impl<'a> Resolver<'a> { ribs: &[Rib<'a>], ) -> Option<LexicalScopeBinding<'a>> { assert!(ns == TypeNS || ns == ValueNS); + let orig_ident = ident; if ident.name == kw::Empty { return Some(LexicalScopeBinding::Res(Res::Err)); } @@ -1873,135 +1891,49 @@ impl<'a> Resolver<'a> { _ => continue, }; - let item = self.resolve_ident_in_module_unadjusted( - ModuleOrUniformRoot::Module(module), - ident, - ns, - parent_scope, - record_used, - path_span, - ); - if let Ok(binding) = item { - // The ident resolves to an item. - return Some(LexicalScopeBinding::Item(binding)); - } - match module.kind { ModuleKind::Block(..) => {} // We can see through blocks _ => break, } - } - ident = normalized_ident; - let mut poisoned = None; - loop { - let mut span_data = ident.span.data(); - let opt_module = if let Some(node_id) = record_used_id { - self.hygienic_lexical_parent_with_compatibility_fallback( - module, - &mut span_data.ctxt, - node_id, - &mut poisoned, - ) - } else { - self.hygienic_lexical_parent(module, &mut span_data.ctxt) - }; - ident.span = span_data.span(); - module = unwrap_or!(opt_module, break); - let adjusted_parent_scope = &ParentScope { module, ..*parent_scope }; - let result = self.resolve_ident_in_module_unadjusted( + let item = self.resolve_ident_in_module_unadjusted( ModuleOrUniformRoot::Module(module), ident, ns, - adjusted_parent_scope, + parent_scope, record_used, path_span, ); - - match result { - Ok(binding) => { - if let Some(node_id) = poisoned { - self.lint_buffer.buffer_lint_with_diagnostic( - lint::builtin::PROC_MACRO_DERIVE_RESOLUTION_FALLBACK, - node_id, - ident.span, - &format!("cannot find {} `{}` in this scope", ns.descr(), ident), - BuiltinLintDiagnostics::ProcMacroDeriveResolutionFallback(ident.span), - ); - } - return Some(LexicalScopeBinding::Item(binding)); - } - Err(Determined) => continue, - Err(Undetermined) => { - span_bug!(ident.span, "undetermined resolution during main resolution pass") - } - } - } - - if !module.no_implicit_prelude { - ident.span.adjust(ExpnId::root()); - if ns == TypeNS { - if let Some(binding) = self.extern_prelude_get(ident, !record_used) { - return Some(LexicalScopeBinding::Item(binding)); - } - if let Some(ident) = self.registered_tools.get(&ident) { - let binding = - (Res::ToolMod, ty::Visibility::Public, ident.span, ExpnId::root()) - .to_name_binding(self.arenas); - return Some(LexicalScopeBinding::Item(binding)); - } - } - if let Some(prelude) = self.prelude { - if let Ok(binding) = self.resolve_ident_in_module_unadjusted( - ModuleOrUniformRoot::Module(prelude), - ident, - ns, - parent_scope, - false, - path_span, - ) { - return Some(LexicalScopeBinding::Item(binding)); - } - } - } - - if ns == TypeNS { - if let Some(prim_ty) = PrimTy::from_name(ident.name) { - let binding = - (Res::PrimTy(prim_ty), ty::Visibility::Public, DUMMY_SP, ExpnId::root()) - .to_name_binding(self.arenas); + if let Ok(binding) = item { + // The ident resolves to an item. return Some(LexicalScopeBinding::Item(binding)); } } - None + self.early_resolve_ident_in_lexical_scope( + orig_ident, + ScopeSet::Late(ns, module, record_used_id), + parent_scope, + record_used, + record_used, + path_span, + ) + .ok() + .map(LexicalScopeBinding::Item) } fn hygienic_lexical_parent( &mut self, module: Module<'a>, ctxt: &mut SyntaxContext, - ) -> Option<Module<'a>> { + derive_fallback_lint_id: Option<NodeId>, + ) -> Option<(Module<'a>, Option<NodeId>)> { if !module.expansion.outer_expn_is_descendant_of(*ctxt) { - return Some(self.macro_def_scope(ctxt.remove_mark())); + return Some((self.macro_def_scope(ctxt.remove_mark()), None)); } if let ModuleKind::Block(..) = module.kind { - return Some(module.parent.unwrap().nearest_item_scope()); - } - - None - } - - fn hygienic_lexical_parent_with_compatibility_fallback( - &mut self, - module: Module<'a>, - ctxt: &mut SyntaxContext, - node_id: NodeId, - poisoned: &mut Option<NodeId>, - ) -> Option<Module<'a>> { - if let module @ Some(..) = self.hygienic_lexical_parent(module, ctxt) { - return module; + return Some((module.parent.unwrap().nearest_item_scope(), None)); } // We need to support the next case under a deprecation warning @@ -2015,20 +1947,21 @@ impl<'a> Resolver<'a> { // ---- end // ``` // So we have to fall back to the module's parent during lexical resolution in this case. - if let Some(parent) = module.parent { - // Inner module is inside the macro, parent module is outside of the macro. - if module.expansion != parent.expansion - && module.expansion.is_descendant_of(parent.expansion) - { - // The macro is a proc macro derive - if let Some(def_id) = module.expansion.expn_data().macro_def_id { - let ext = self.get_macro_by_def_id(def_id); - if ext.builtin_name.is_none() - && ext.macro_kind() == MacroKind::Derive - && parent.expansion.outer_expn_is_descendant_of(*ctxt) - { - *poisoned = Some(node_id); - return module.parent; + if derive_fallback_lint_id.is_some() { + if let Some(parent) = module.parent { + // Inner module is inside the macro, parent module is outside of the macro. + if module.expansion != parent.expansion + && module.expansion.is_descendant_of(parent.expansion) + { + // The macro is a proc macro derive + if let Some(def_id) = module.expansion.expn_data().macro_def_id { + let ext = self.get_macro_by_def_id(def_id); + if ext.builtin_name.is_none() + && ext.macro_kind() == MacroKind::Derive + && parent.expansion.outer_expn_is_descendant_of(*ctxt) + { + return Some((parent, derive_fallback_lint_id)); + } } } } diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index 2efce1e1984..d238f65c941 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -24,7 +24,8 @@ use rustc_hir::def_id; use rustc_hir::PrimTy; use rustc_middle::middle::stability; use rustc_middle::ty; -use rustc_session::lint::builtin::{LEGACY_DERIVE_HELPERS, SOFT_UNSTABLE, UNUSED_MACROS}; +use rustc_session::lint::builtin::{LEGACY_DERIVE_HELPERS, PROC_MACRO_DERIVE_RESOLUTION_FALLBACK}; +use rustc_session::lint::builtin::{SOFT_UNSTABLE, UNUSED_MACROS}; use rustc_session::lint::BuiltinLintDiagnostics; use rustc_session::parse::feature_err; use rustc_session::Session; @@ -642,7 +643,7 @@ impl<'a> Resolver<'a> { crate fn early_resolve_ident_in_lexical_scope( &mut self, orig_ident: Ident, - scope_set: ScopeSet, + scope_set: ScopeSet<'a>, parent_scope: &ParentScope<'a>, record_used: bool, force: bool, @@ -669,6 +670,7 @@ impl<'a> Resolver<'a> { ScopeSet::All(ns, is_import) => (ns, None, is_import), ScopeSet::AbsolutePath(ns) => (ns, None, false), ScopeSet::Macro(macro_kind) => (MacroNS, Some(macro_kind), false), + ScopeSet::Late(ns, ..) => (ns, None, false), }; // This is *the* result, resolution from the scope closest to the resolved identifier. @@ -777,19 +779,34 @@ impl<'a> Resolver<'a> { Err((Determinacy::Determined, _)) => Err(Determinacy::Determined), } } - Scope::Module(module) => { + Scope::Module(module, derive_fallback_lint_id) => { let adjusted_parent_scope = &ParentScope { module, ..*parent_scope }; let binding = this.resolve_ident_in_module_unadjusted_ext( ModuleOrUniformRoot::Module(module), ident, ns, adjusted_parent_scope, - true, + !matches!(scope_set, ScopeSet::Late(..)), record_used, path_span, ); match binding { Ok(binding) => { + if let Some(lint_id) = derive_fallback_lint_id { + this.lint_buffer.buffer_lint_with_diagnostic( + PROC_MACRO_DERIVE_RESOLUTION_FALLBACK, + lint_id, + orig_ident.span, + &format!( + "cannot find {} `{}` in this scope", + ns.descr(), + ident + ), + BuiltinLintDiagnostics::ProcMacroDeriveResolutionFallback( + orig_ident.span, + ), + ); + } let misc_flags = if ptr::eq(module, this.graph_root) { Flags::MISC_SUGGEST_CRATE } else if module.is_normal() { @@ -873,7 +890,7 @@ impl<'a> Resolver<'a> { Ok((binding, flags)) if sub_namespace_match(binding.macro_kind(), macro_kind) => { - if !record_used { + if !record_used || matches!(scope_set, ScopeSet::Late(..)) { return Some(Ok(binding)); } diff --git a/compiler/rustc_save_analysis/src/dump_visitor.rs b/compiler/rustc_save_analysis/src/dump_visitor.rs index 65f16ff45a1..12c77e0c8a6 100644 --- a/compiler/rustc_save_analysis/src/dump_visitor.rs +++ b/compiler/rustc_save_analysis/src/dump_visitor.rs @@ -151,7 +151,7 @@ impl<'tcx> DumpVisitor<'tcx> { }, crate_root: crate_root.unwrap_or_else(|| "<no source>".to_owned()), external_crates: self.save_ctxt.get_external_crates(), - span: self.span_from_span(krate.item.span), + span: self.span_from_span(krate.item.inner), }; self.dumper.crate_prelude(data); @@ -1097,16 +1097,11 @@ impl<'tcx> DumpVisitor<'tcx> { format!("::{}", self.tcx.def_path_str(self.tcx.hir().local_def_id(id).to_def_id())); let sm = self.tcx.sess.source_map(); - let filename = sm.span_to_filename(krate.item.span); + let filename = sm.span_to_filename(krate.item.inner); let data_id = id_from_hir_id(id, &self.save_ctxt); - let children = krate - .item - .module - .item_ids - .iter() - .map(|i| id_from_def_id(i.def_id.to_def_id())) - .collect(); - let span = self.span_from_span(krate.item.span); + let children = + krate.item.item_ids.iter().map(|i| id_from_def_id(i.def_id.to_def_id())).collect(); + let span = self.span_from_span(krate.item.inner); let attrs = self.tcx.hir().attrs(id); self.dumper.dump_def( diff --git a/compiler/rustc_save_analysis/src/lib.rs b/compiler/rustc_save_analysis/src/lib.rs index 13d613132c0..c19c16b88a7 100644 --- a/compiler/rustc_save_analysis/src/lib.rs +++ b/compiler/rustc_save_analysis/src/lib.rs @@ -516,19 +516,6 @@ impl<'tcx> SaveContext<'tcx> { }) } - pub fn get_trait_ref_data(&self, trait_ref: &hir::TraitRef<'_>) -> Option<Ref> { - self.lookup_def_id(trait_ref.hir_ref_id).and_then(|def_id| { - let span = trait_ref.path.span; - if generated_code(span) { - return None; - } - let sub_span = trait_ref.path.segments.last().unwrap().ident.span; - filter!(self.span_utils, sub_span); - let span = self.span_from_span(sub_span); - Some(Ref { kind: RefKind::Type, span, ref_id: id_from_def_id(def_id) }) - }) - } - pub fn get_expr_data(&self, expr: &hir::Expr<'_>) -> Option<Data> { let ty = self.typeck_results().expr_ty_adjusted_opt(expr)?; if matches!(ty.kind(), ty::Error(_)) { @@ -784,7 +771,10 @@ impl<'tcx> SaveContext<'tcx> { /// For a given piece of AST defined by the supplied Span and NodeId, /// returns `None` if the node is not macro-generated or the span is malformed, /// else uses the expansion callsite and callee to return some MacroRef. - pub fn get_macro_use_data(&self, span: Span) -> Option<MacroRef> { + /// + /// FIXME: [`DumpVisitor::process_macro_use`] should actually dump this data + #[allow(dead_code)] + fn get_macro_use_data(&self, span: Span) -> Option<MacroRef> { if !generated_code(span) { return None; } diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 3d69943e889..3692219cb6d 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -505,6 +505,7 @@ impl<'a> From<&'a ExternDepSpec> for rustc_lint_defs::ExternDepSpec { } impl Externs { + /// Used for testing. pub fn new(data: BTreeMap<String, ExternEntry>) -> Externs { Externs(data) } @@ -604,13 +605,6 @@ impl Input { } } - pub fn get_input(&mut self) -> Option<&mut String> { - match *self { - Input::File(_) => None, - Input::Str { ref mut input, .. } => Some(input), - } - } - pub fn source_name(&self) -> FileName { match *self { Input::File(ref ifile) => ifile.clone().into(), @@ -778,12 +772,6 @@ impl Options { || self.debugging_opts.query_dep_graph } - #[inline(always)] - pub fn enable_dep_node_debug_strs(&self) -> bool { - cfg!(debug_assertions) - && (self.debugging_opts.query_dep_graph || self.debugging_opts.incremental_info) - } - pub fn file_path_mapping(&self) -> FilePathMapping { FilePathMapping::new(self.remap_path_prefix.clone()) } @@ -965,7 +953,7 @@ pub fn build_target_config(opts: &Options, target_override: Option<Target>) -> T opts.error_format, &format!( "Error loading target specification: {}. \ - Use `--print target-list` for a list of built-in targets", + Run `rustc --print target-list` for a list of built-in targets", e ), ) @@ -1060,9 +1048,6 @@ mod opt { pub fn flag_s(a: S, b: S, c: S) -> R { stable(longer(a, b), move |opts| opts.optflag(a, b, c)) } - pub fn flagopt_s(a: S, b: S, c: S, d: S) -> R { - stable(longer(a, b), move |opts| opts.optflagopt(a, b, c, d)) - } pub fn flagmulti_s(a: S, b: S, c: S) -> R { stable(longer(a, b), move |opts| opts.optflagmulti(a, b, c)) } @@ -1073,15 +1058,6 @@ mod opt { pub fn multi(a: S, b: S, c: S, d: S) -> R { unstable(longer(a, b), move |opts| opts.optmulti(a, b, c, d)) } - pub fn flag(a: S, b: S, c: S) -> R { - unstable(longer(a, b), move |opts| opts.optflag(a, b, c)) - } - pub fn flagopt(a: S, b: S, c: S, d: S) -> R { - unstable(longer(a, b), move |opts| opts.optflagopt(a, b, c, d)) - } - pub fn flagmulti(a: S, b: S, c: S) -> R { - unstable(longer(a, b), move |opts| opts.optflagmulti(a, b, c)) - } } /// Returns the "short" subset of the rustc command line options, @@ -2459,7 +2435,7 @@ crate mod dep_tracking { } // This is a stable hash because BTreeMap is a sorted container - pub fn stable_hash( + crate fn stable_hash( sub_hashes: BTreeMap<&'static str, &dyn DepTrackingHash>, hasher: &mut DefaultHasher, error_format: ErrorOutputType, diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index e071c58d1cd..e50972e59a7 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -906,8 +906,6 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, (default: no)"), borrowck: String = ("migrate".to_string(), parse_string, [UNTRACKED], "select which borrowck is used (`mir` or `migrate`) (default: `migrate`)"), - borrowck_stats: bool = (false, parse_bool, [UNTRACKED], - "gather borrowck statistics (default: no)"), cgu_partitioning_strategy: Option<String> = (None, parse_opt_string, [TRACKED], "the codegen unit partitioning strategy to use"), chalk: bool = (false, parse_bool, [TRACKED], diff --git a/compiler/rustc_session/src/parse.rs b/compiler/rustc_session/src/parse.rs index 592773bfe1b..65d5d96aba1 100644 --- a/compiler/rustc_session/src/parse.rs +++ b/compiler/rustc_session/src/parse.rs @@ -140,6 +140,7 @@ pub struct ParseSess { } impl ParseSess { + /// Used for testing. pub fn new(file_path_mapping: FilePathMapping) -> Self { let sm = Lrc::new(SourceMap::new(file_path_mapping)); let handler = Handler::with_tty_emitter(ColorConfig::Auto, true, None, Some(sm.clone())); diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index ca9214c03a8..693f427d7af 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -20,7 +20,7 @@ use rustc_errors::annotate_snippet_emitter_writer::AnnotateSnippetEmitterWriter; use rustc_errors::emitter::{Emitter, EmitterWriter, HumanReadableErrorType}; use rustc_errors::json::JsonEmitter; use rustc_errors::registry::Registry; -use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, DiagnosticId, ErrorReported}; +use rustc_errors::{Diagnostic, DiagnosticBuilder, DiagnosticId, ErrorReported}; use rustc_lint_defs::FutureBreakage; pub use rustc_span::crate_disambiguator::CrateDisambiguator; use rustc_span::edition::Edition; @@ -241,8 +241,7 @@ pub struct PerfStats { enum DiagnosticBuilderMethod { Note, SpanNote, - SpanSuggestion(String), // suggestion - // Add more variants as needed to support one-time diagnostics. + // Add more variants as needed to support one-time diagnostics. } /// Trait implemented by error types. This should not be implemented manually. Instead, use @@ -551,15 +550,6 @@ impl Session { let span = span_maybe.expect("`span_note` needs a span"); diag_builder.span_note(span, message); } - DiagnosticBuilderMethod::SpanSuggestion(suggestion) => { - let span = span_maybe.expect("`span_suggestion_*` needs a span"); - diag_builder.span_suggestion( - span, - message, - suggestion, - Applicability::Unspecified, - ); - } } } } @@ -589,23 +579,6 @@ impl Session { self.diag_once(diag_builder, DiagnosticBuilderMethod::Note, msg_id, message, None); } - pub fn diag_span_suggestion_once<'a, 'b>( - &'a self, - diag_builder: &'b mut DiagnosticBuilder<'a>, - msg_id: DiagnosticMessageId, - span: Span, - message: &str, - suggestion: String, - ) { - self.diag_once( - diag_builder, - DiagnosticBuilderMethod::SpanSuggestion(suggestion), - msg_id, - message, - Some(span), - ); - } - #[inline] pub fn source_map(&self) -> &SourceMap { self.parse_sess.source_map() @@ -631,9 +604,6 @@ impl Session { pub fn verify_llvm_ir(&self) -> bool { self.opts.debugging_opts.verify_llvm_ir || option_env!("RUSTC_VERIFY_LLVM_IR").is_some() } - pub fn borrowck_stats(&self) -> bool { - self.opts.debugging_opts.borrowck_stats - } pub fn print_llvm_passes(&self) -> bool { self.opts.debugging_opts.print_llvm_passes } @@ -890,22 +860,6 @@ impl Session { ) } - pub fn set_incr_session_load_dep_graph(&self, load: bool) { - let mut incr_comp_session = self.incr_comp_session.borrow_mut(); - - if let IncrCompSession::Active { ref mut load_dep_graph, .. } = *incr_comp_session { - *load_dep_graph = load; - } - } - - pub fn incr_session_load_dep_graph(&self) -> bool { - let incr_comp_session = self.incr_comp_session.borrow(); - match *incr_comp_session { - IncrCompSession::Active { load_dep_graph, .. } => load_dep_graph, - _ => false, - } - } - pub fn init_incr_comp_session( &self, session_dir: PathBuf, diff --git a/compiler/rustc_span/src/def_id.rs b/compiler/rustc_span/src/def_id.rs index 885f30ebb4e..95bb0ad7ba2 100644 --- a/compiler/rustc_span/src/def_id.rs +++ b/compiler/rustc_span/src/def_id.rs @@ -160,6 +160,8 @@ impl DefPathHash { } /// Returns the crate-local part of the [DefPathHash]. + /// + /// Used for tests. #[inline] pub fn local_hash(&self) -> u64 { self.0.as_value().1 diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs index eb5b7c4a74a..6805d4f2890 100644 --- a/compiler/rustc_span/src/hygiene.rs +++ b/compiler/rustc_span/src/hygiene.rs @@ -413,7 +413,7 @@ pub fn update_dollar_crate_names(mut get_name: impl FnMut(SyntaxContext) -> Symb let names: Vec<_> = range_to_update.clone().map(|idx| get_name(SyntaxContext::from_u32(idx as u32))).collect(); HygieneData::with(|data| { - range_to_update.zip(names.into_iter()).for_each(|(idx, name)| { + range_to_update.zip(names).for_each(|(idx, name)| { data.syntax_context_data[idx].dollar_crate_name = name; }) }) @@ -1176,11 +1176,7 @@ pub fn decode_syntax_context< Ok(new_ctxt) } -pub fn num_syntax_ctxts() -> usize { - HygieneData::with(|data| data.syntax_context_data.len()) -} - -pub fn for_all_ctxts_in<E, F: FnMut((u32, SyntaxContext, &SyntaxContextData)) -> Result<(), E>>( +fn for_all_ctxts_in<E, F: FnMut((u32, SyntaxContext, &SyntaxContextData)) -> Result<(), E>>( ctxts: impl Iterator<Item = SyntaxContext>, mut f: F, ) -> Result<(), E> { @@ -1193,7 +1189,7 @@ pub fn for_all_ctxts_in<E, F: FnMut((u32, SyntaxContext, &SyntaxContextData)) -> Ok(()) } -pub fn for_all_expns_in<E, F: FnMut(u32, ExpnId, &ExpnData) -> Result<(), E>>( +fn for_all_expns_in<E, F: FnMut(u32, ExpnId, &ExpnData) -> Result<(), E>>( expns: impl Iterator<Item = ExpnId>, mut f: F, ) -> Result<(), E> { @@ -1206,16 +1202,6 @@ pub fn for_all_expns_in<E, F: FnMut(u32, ExpnId, &ExpnData) -> Result<(), E>>( Ok(()) } -pub fn for_all_data<E, F: FnMut((u32, SyntaxContext, &SyntaxContextData)) -> Result<(), E>>( - mut f: F, -) -> Result<(), E> { - let all_data = HygieneData::with(|data| data.syntax_context_data.clone()); - for (i, data) in all_data.into_iter().enumerate() { - f((i as u32, SyntaxContext(i as u32), &data))?; - } - Ok(()) -} - impl<E: Encoder> Encodable<E> for ExpnId { default fn encode(&self, _: &mut E) -> Result<(), E::Error> { panic!("cannot encode `ExpnId` with `{}`", std::any::type_name::<E>()); @@ -1228,14 +1214,6 @@ impl<D: Decoder> Decodable<D> for ExpnId { } } -pub fn for_all_expn_data<E, F: FnMut(u32, &ExpnData) -> Result<(), E>>(mut f: F) -> Result<(), E> { - let all_data = HygieneData::with(|data| data.expn_data.clone()); - for (i, data) in all_data.into_iter().enumerate() { - f(i as u32, &data.unwrap_or_else(|| panic!("Missing ExpnData!")))?; - } - Ok(()) -} - pub fn raw_encode_syntax_context<E: Encoder>( ctxt: SyntaxContext, context: &HygieneEncodeContext, diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index d2790335b5a..6f6ff37c525 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -1037,10 +1037,6 @@ pub enum ExternalSourceKind { } impl ExternalSource { - pub fn is_absent(&self) -> bool { - !matches!(self, ExternalSource::Foreign { kind: ExternalSourceKind::Present(_), .. }) - } - pub fn get_source(&self) -> Option<&Lrc<String>> { match self { ExternalSource::Foreign { kind: ExternalSourceKind::Present(ref src), .. } => Some(src), @@ -1433,9 +1429,6 @@ impl SourceFile { self.src.is_none() } - pub fn byte_length(&self) -> u32 { - self.end_pos.0 - self.start_pos.0 - } pub fn count_lines(&self) -> usize { self.lines.len() } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 116519855d7..c5f929ab183 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -477,6 +477,7 @@ symbols! { doc_cfg, doc_keyword, doc_masked, + doc_notable_trait, doc_spotlight, doctest, document_private_items, @@ -801,6 +802,7 @@ symbols! { noreturn, nostack, not, + notable_trait, note, object_safe_for_dispatch, of, diff --git a/compiler/rustc_symbol_mangling/src/legacy.rs b/compiler/rustc_symbol_mangling/src/legacy.rs index b0d5f340902..7d186c330ba 100644 --- a/compiler/rustc_symbol_mangling/src/legacy.rs +++ b/compiler/rustc_symbol_mangling/src/legacy.rs @@ -230,7 +230,7 @@ impl Printer<'tcx> for SymbolPrinter<'tcx> { fn print_dyn_existential( mut self, - predicates: &'tcx ty::List<ty::Binder<ty::ExistentialPredicate<'tcx>>>, + predicates: &'tcx ty::List<ty::Binder<'tcx, ty::ExistentialPredicate<'tcx>>>, ) -> Result<Self::DynExistential, Self::Error> { let mut first = true; for p in predicates { diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index 12c0a147990..37a834043f6 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -181,7 +181,7 @@ impl SymbolMangler<'tcx> { fn in_binder<T>( mut self, - value: &ty::Binder<T>, + value: &ty::Binder<'tcx, T>, print_value: impl FnOnce(Self, &T) -> Result<Self, !>, ) -> Result<Self, !> where @@ -318,7 +318,7 @@ impl Printer<'tcx> for SymbolMangler<'tcx> { // Late-bound lifetimes use indices starting at 1, // see `BinderLevel` for more details. - ty::ReLateBound(debruijn, ty::BoundRegion { kind: ty::BrAnon(i) }) => { + ty::ReLateBound(debruijn, ty::BoundRegion { kind: ty::BrAnon(i), .. }) => { let binder = &self.binders[self.binders.len() - 1 - debruijn.index()]; let depth = binder.lifetime_depths.start + i; @@ -483,7 +483,7 @@ impl Printer<'tcx> for SymbolMangler<'tcx> { fn print_dyn_existential( mut self, - predicates: &'tcx ty::List<ty::Binder<ty::ExistentialPredicate<'tcx>>>, + predicates: &'tcx ty::List<ty::Binder<'tcx, ty::ExistentialPredicate<'tcx>>>, ) -> Result<Self::DynExistential, Self::Error> { for predicate in predicates { self = self.in_binder(&predicate, |mut cx, predicate| { diff --git a/compiler/rustc_target/src/spec/android_base.rs b/compiler/rustc_target/src/spec/android_base.rs index c7d2f2329ee..aaf81648c51 100644 --- a/compiler/rustc_target/src/spec/android_base.rs +++ b/compiler/rustc_target/src/spec/android_base.rs @@ -6,8 +6,8 @@ pub fn opts() -> TargetOptions { // Many of the symbols defined in compiler-rt are also defined in libgcc. // Android's linker doesn't like that by default. base.pre_link_args - .get_mut(&LinkerFlavor::Gcc) - .unwrap() + .entry(LinkerFlavor::Gcc) + .or_default() .push("-Wl,--allow-multiple-definition".to_string()); base.dwarf_version = Some(2); base.position_independent_executables = true; diff --git a/compiler/rustc_target/src/spec/armv7_linux_androideabi.rs b/compiler/rustc_target/src/spec/armv7_linux_androideabi.rs index 9aa378a8018..02a1191463e 100644 --- a/compiler/rustc_target/src/spec/armv7_linux_androideabi.rs +++ b/compiler/rustc_target/src/spec/armv7_linux_androideabi.rs @@ -12,7 +12,7 @@ pub fn target() -> Target { let mut base = super::android_base::opts(); base.features = "+v7,+thumb-mode,+thumb2,+vfp3,-d32,-neon".to_string(); base.max_atomic_width = Some(64); - base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-march=armv7-a".to_string()); + base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-march=armv7-a".to_string()); Target { llvm_target: "armv7-none-linux-android".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 67a7684da2c..df4389b8165 100644 --- a/compiler/rustc_target/src/spec/avr_gnu_base.rs +++ b/compiler/rustc_target/src/spec/avr_gnu_base.rs @@ -21,22 +21,9 @@ pub fn target(target_cpu: String) -> Target { has_rpath: false, position_independent_executables: false, eh_frame_header: false, - pre_link_args: vec![( - LinkerFlavor::Gcc, - vec![ - format!("-mmcu={}", target_cpu), - // We want to be able to strip as much executable code as possible - // from the linker command line, and this flag indicates to the - // linker that it can avoid linking in dynamic libraries that don't - // actually satisfy any symbols up to that point (as with many other - // resolutions the linker does). This option only applies to all - // following libraries so we're sure to pass it as one of the first - // arguments. - "-Wl,--as-needed".to_string(), - ], - )] - .into_iter() - .collect(), + pre_link_args: vec![(LinkerFlavor::Gcc, vec![format!("-mmcu={}", target_cpu)])] + .into_iter() + .collect(), late_link_args: vec![(LinkerFlavor::Gcc, vec!["-lgcc".to_owned()])] .into_iter() .collect(), diff --git a/compiler/rustc_target/src/spec/dragonfly_base.rs b/compiler/rustc_target/src/spec/dragonfly_base.rs index b96de7ab1ed..dd017098782 100644 --- a/compiler/rustc_target/src/spec/dragonfly_base.rs +++ b/compiler/rustc_target/src/spec/dragonfly_base.rs @@ -1,20 +1,6 @@ -use crate::spec::{LinkArgs, LinkerFlavor, RelroLevel, TargetOptions}; +use crate::spec::{RelroLevel, TargetOptions}; pub fn opts() -> TargetOptions { - let mut args = LinkArgs::new(); - args.insert( - LinkerFlavor::Gcc, - vec![ - // GNU-style linkers will use this to omit linking to libraries - // which don't actually fulfill any relocations, but only for - // libraries which follow this flag. Thus, use it before - // specifying libraries to link to. - "-Wl,--as-needed".to_string(), - // Always enable NX protection when it is available - "-Wl,-z,noexecstack".to_string(), - ], - ); - TargetOptions { os: "dragonfly".to_string(), dynamic_linking: true, @@ -22,7 +8,6 @@ pub fn opts() -> TargetOptions { os_family: Some("unix".to_string()), linker_is_gnu: true, has_rpath: true, - pre_link_args: args, position_independent_executables: true, relro_level: RelroLevel::Full, dwarf_version: Some(2), diff --git a/compiler/rustc_target/src/spec/freebsd_base.rs b/compiler/rustc_target/src/spec/freebsd_base.rs index c70c492716b..ad3383cc5f2 100644 --- a/compiler/rustc_target/src/spec/freebsd_base.rs +++ b/compiler/rustc_target/src/spec/freebsd_base.rs @@ -1,20 +1,6 @@ -use crate::spec::{LinkArgs, LinkerFlavor, RelroLevel, TargetOptions}; +use crate::spec::{RelroLevel, TargetOptions}; pub fn opts() -> TargetOptions { - let mut args = LinkArgs::new(); - args.insert( - LinkerFlavor::Gcc, - vec![ - // GNU-style linkers will use this to omit linking to libraries - // which don't actually fulfill any relocations, but only for - // libraries which follow this flag. Thus, use it before - // specifying libraries to link to. - "-Wl,--as-needed".to_string(), - // Always enable NX protection when it is available - "-Wl,-z,noexecstack".to_string(), - ], - ); - TargetOptions { os: "freebsd".to_string(), dynamic_linking: true, @@ -22,7 +8,6 @@ pub fn opts() -> TargetOptions { os_family: Some("unix".to_string()), linker_is_gnu: true, has_rpath: true, - pre_link_args: args, position_independent_executables: true, eliminate_frame_pointer: false, // FIXME 43575 relro_level: RelroLevel::Full, 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 4979a5b3bc8..7002d88c512 100644 --- a/compiler/rustc_target/src/spec/i686_pc_windows_gnu.rs +++ b/compiler/rustc_target/src/spec/i686_pc_windows_gnu.rs @@ -12,8 +12,8 @@ pub fn target() -> Target { // Mark all dynamic libraries and executables as compatible with the larger 4GiB address // space available to x86 Windows binaries on x86_64. base.pre_link_args - .get_mut(&LinkerFlavor::Gcc) - .unwrap() + .entry(LinkerFlavor::Gcc) + .or_default() .push("-Wl,--large-address-aware".to_string()); Target { 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 e7a5643eaaa..74074cfb5dd 100644 --- a/compiler/rustc_target/src/spec/i686_pc_windows_msvc.rs +++ b/compiler/rustc_target/src/spec/i686_pc_windows_msvc.rs @@ -14,10 +14,10 @@ pub fn target() -> Target { // https://docs.microsoft.com/en-us/cpp/build/reference/safeseh-image-has-safe-exception-handlers "/SAFESEH".to_string(), ]; - base.pre_link_args.get_mut(&LinkerFlavor::Msvc).unwrap().extend(pre_link_args_msvc.clone()); + base.pre_link_args.entry(LinkerFlavor::Msvc).or_default().extend(pre_link_args_msvc.clone()); base.pre_link_args - .get_mut(&LinkerFlavor::Lld(LldFlavor::Link)) - .unwrap() + .entry(LinkerFlavor::Lld(LldFlavor::Link)) + .or_default() .extend(pre_link_args_msvc); Target { diff --git a/compiler/rustc_target/src/spec/i686_unknown_freebsd.rs b/compiler/rustc_target/src/spec/i686_unknown_freebsd.rs index fc425babb69..a26cabdc90a 100644 --- a/compiler/rustc_target/src/spec/i686_unknown_freebsd.rs +++ b/compiler/rustc_target/src/spec/i686_unknown_freebsd.rs @@ -4,7 +4,7 @@ pub fn target() -> Target { let mut base = super::freebsd_base::opts(); base.cpu = "pentium4".to_string(); base.max_atomic_width = Some(64); - let pre_link_args = base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap(); + let pre_link_args = base.pre_link_args.entry(LinkerFlavor::Gcc).or_default(); pre_link_args.push("-m32".to_string()); pre_link_args.push("-Wl,-znotext".to_string()); base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) }; 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 fe1e6a4299d..633e8da0ccb 100644 --- a/compiler/rustc_target/src/spec/i686_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/i686_unknown_linux_gnu.rs @@ -4,7 +4,7 @@ pub fn target() -> Target { let mut base = super::linux_gnu_base::opts(); base.cpu = "pentium4".to_string(); base.max_atomic_width = Some(64); - base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m32".to_string()); + base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m32".to_string()); base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) }; Target { 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 623fd1b9ae8..8bcd261e4df 100644 --- a/compiler/rustc_target/src/spec/i686_unknown_linux_musl.rs +++ b/compiler/rustc_target/src/spec/i686_unknown_linux_musl.rs @@ -4,8 +4,8 @@ pub fn target() -> Target { let mut base = super::linux_musl_base::opts(); base.cpu = "pentium4".to_string(); base.max_atomic_width = Some(64); - base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m32".to_string()); - base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-Wl,-melf_i386".to_string()); + base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m32".to_string()); + base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-Wl,-melf_i386".to_string()); base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) }; // The unwinder used by i686-unknown-linux-musl, the LLVM libunwind diff --git a/compiler/rustc_target/src/spec/i686_unknown_netbsd.rs b/compiler/rustc_target/src/spec/i686_unknown_netbsd.rs index c4d11bfb13e..e020264ad7a 100644 --- a/compiler/rustc_target/src/spec/i686_unknown_netbsd.rs +++ b/compiler/rustc_target/src/spec/i686_unknown_netbsd.rs @@ -4,7 +4,7 @@ pub fn target() -> Target { let mut base = super::netbsd_base::opts(); base.cpu = "pentium4".to_string(); base.max_atomic_width = Some(64); - base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m32".to_string()); + base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m32".to_string()); base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) }; Target { diff --git a/compiler/rustc_target/src/spec/i686_unknown_openbsd.rs b/compiler/rustc_target/src/spec/i686_unknown_openbsd.rs index fdaaf6c741e..86448cb9115 100644 --- a/compiler/rustc_target/src/spec/i686_unknown_openbsd.rs +++ b/compiler/rustc_target/src/spec/i686_unknown_openbsd.rs @@ -4,8 +4,8 @@ pub fn target() -> Target { let mut base = super::openbsd_base::opts(); base.cpu = "pentium4".to_string(); base.max_atomic_width = Some(64); - base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m32".to_string()); - base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-fuse-ld=lld".to_string()); + base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m32".to_string()); + base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-fuse-ld=lld".to_string()); base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) }; Target { 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 a3de93efb78..426df59882d 100644 --- a/compiler/rustc_target/src/spec/i686_uwp_windows_gnu.rs +++ b/compiler/rustc_target/src/spec/i686_uwp_windows_gnu.rs @@ -11,8 +11,8 @@ pub fn target() -> Target { // Mark all dynamic libraries and executables as compatible with the larger 4GiB address // space available to x86 Windows binaries on x86_64. base.pre_link_args - .get_mut(&LinkerFlavor::Gcc) - .unwrap() + .entry(LinkerFlavor::Gcc) + .or_default() .push("-Wl,--large-address-aware".to_string()); Target { diff --git a/compiler/rustc_target/src/spec/i686_wrs_vxworks.rs b/compiler/rustc_target/src/spec/i686_wrs_vxworks.rs index ec8a2493b4e..e596eca86b0 100644 --- a/compiler/rustc_target/src/spec/i686_wrs_vxworks.rs +++ b/compiler/rustc_target/src/spec/i686_wrs_vxworks.rs @@ -4,7 +4,7 @@ pub fn target() -> Target { let mut base = super::vxworks_base::opts(); base.cpu = "pentium4".to_string(); base.max_atomic_width = Some(64); - base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m32".to_string()); + base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m32".to_string()); base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) }; Target { diff --git a/compiler/rustc_target/src/spec/linux_base.rs b/compiler/rustc_target/src/spec/linux_base.rs index 0631644ad63..eeefd056e4b 100644 --- a/compiler/rustc_target/src/spec/linux_base.rs +++ b/compiler/rustc_target/src/spec/linux_base.rs @@ -1,23 +1,6 @@ -use crate::spec::{LinkArgs, LinkerFlavor, RelroLevel, TargetOptions}; +use crate::spec::{RelroLevel, TargetOptions}; pub fn opts() -> TargetOptions { - let mut args = LinkArgs::new(); - args.insert( - LinkerFlavor::Gcc, - vec![ - // We want to be able to strip as much executable code as possible - // from the linker command line, and this flag indicates to the - // linker that it can avoid linking in dynamic libraries that don't - // actually satisfy any symbols up to that point (as with many other - // resolutions the linker does). This option only applies to all - // following libraries so we're sure to pass it as one of the first - // arguments. - "-Wl,--as-needed".to_string(), - // Always enable NX protection when it is available - "-Wl,-z,noexecstack".to_string(), - ], - ); - TargetOptions { os: "linux".to_string(), dynamic_linking: true, @@ -25,7 +8,6 @@ pub fn opts() -> TargetOptions { os_family: Some("unix".to_string()), linker_is_gnu: true, has_rpath: true, - pre_link_args: args, position_independent_executables: true, relro_level: RelroLevel::Full, has_elf_tls: true, diff --git a/compiler/rustc_target/src/spec/linux_kernel_base.rs b/compiler/rustc_target/src/spec/linux_kernel_base.rs index 52201568953..d17d729c289 100644 --- a/compiler/rustc_target/src/spec/linux_kernel_base.rs +++ b/compiler/rustc_target/src/spec/linux_kernel_base.rs @@ -1,14 +1,6 @@ -use crate::spec::{ - LinkArgs, LinkerFlavor, PanicStrategy, RelocModel, RelroLevel, StackProbeType, TargetOptions, -}; +use crate::spec::{PanicStrategy, RelocModel, RelroLevel, StackProbeType, TargetOptions}; pub fn opts() -> TargetOptions { - let mut pre_link_args = LinkArgs::new(); - pre_link_args.insert( - LinkerFlavor::Gcc, - vec!["-Wl,--as-needed".to_string(), "-Wl,-z,noexecstack".to_string()], - ); - TargetOptions { env: "gnu".to_string(), disable_redzone: true, @@ -20,7 +12,6 @@ pub fn opts() -> TargetOptions { needs_plt: true, relro_level: RelroLevel::Full, relocation_model: RelocModel::Static, - pre_link_args, ..Default::default() } diff --git a/compiler/rustc_target/src/spec/msvc_base.rs b/compiler/rustc_target/src/spec/msvc_base.rs index 39c0d5f0bb4..4ed7685ca07 100644 --- a/compiler/rustc_target/src/spec/msvc_base.rs +++ b/compiler/rustc_target/src/spec/msvc_base.rs @@ -5,13 +5,6 @@ pub fn opts() -> TargetOptions { // Suppress the verbose logo and authorship debugging output, which would needlessly // clog any log files. "/NOLOGO".to_string(), - // Tell the compiler that non-code sections can be marked as non-executable, - // including stack pages. - // UEFI is fully compatible to non-executable data pages. - // In fact, firmware might enforce this, so we better let the linker know about this, - // so it will fail if the compiler ever tries placing code on the stack - // (e.g., trampoline constructs and alike). - "/NXCOMPAT".to_string(), ]; let mut pre_link_args = LinkArgs::new(); pre_link_args.insert(LinkerFlavor::Msvc, pre_link_args_msvc.clone()); diff --git a/compiler/rustc_target/src/spec/netbsd_base.rs b/compiler/rustc_target/src/spec/netbsd_base.rs index a77d60bd9d7..680cd60788b 100644 --- a/compiler/rustc_target/src/spec/netbsd_base.rs +++ b/compiler/rustc_target/src/spec/netbsd_base.rs @@ -1,18 +1,6 @@ -use crate::spec::{LinkArgs, LinkerFlavor, RelroLevel, TargetOptions}; +use crate::spec::{RelroLevel, TargetOptions}; pub fn opts() -> TargetOptions { - let mut args = LinkArgs::new(); - args.insert( - LinkerFlavor::Gcc, - vec![ - // GNU-style linkers will use this to omit linking to libraries - // which don't actually fulfill any relocations, but only for - // libraries which follow this flag. Thus, use it before - // specifying libraries to link to. - "-Wl,--as-needed".to_string(), - ], - ); - TargetOptions { os: "netbsd".to_string(), dynamic_linking: true, @@ -21,7 +9,6 @@ pub fn opts() -> TargetOptions { linker_is_gnu: true, no_default_libraries: false, has_rpath: true, - pre_link_args: args, position_independent_executables: true, relro_level: RelroLevel::Full, use_ctors_section: true, diff --git a/compiler/rustc_target/src/spec/openbsd_base.rs b/compiler/rustc_target/src/spec/openbsd_base.rs index 2b40a1ed945..a6fd01ab110 100644 --- a/compiler/rustc_target/src/spec/openbsd_base.rs +++ b/compiler/rustc_target/src/spec/openbsd_base.rs @@ -1,20 +1,6 @@ -use crate::spec::{LinkArgs, LinkerFlavor, RelroLevel, TargetOptions}; +use crate::spec::{RelroLevel, TargetOptions}; pub fn opts() -> TargetOptions { - let mut args = LinkArgs::new(); - args.insert( - LinkerFlavor::Gcc, - vec![ - // GNU-style linkers will use this to omit linking to libraries - // which don't actually fulfill any relocations, but only for - // libraries which follow this flag. Thus, use it before - // specifying libraries to link to. - "-Wl,--as-needed".to_string(), - // Always enable NX protection when it is available - "-Wl,-z,noexecstack".to_string(), - ], - ); - TargetOptions { os: "openbsd".to_string(), dynamic_linking: true, @@ -23,7 +9,6 @@ pub fn opts() -> TargetOptions { linker_is_gnu: true, has_rpath: true, abi_return_struct_as_int: true, - pre_link_args: args, position_independent_executables: true, eliminate_frame_pointer: false, // FIXME 43575 relro_level: RelroLevel::Full, diff --git a/compiler/rustc_target/src/spec/powerpc64_unknown_freebsd.rs b/compiler/rustc_target/src/spec/powerpc64_unknown_freebsd.rs index 3dddeb1129c..b3d6b7c6107 100644 --- a/compiler/rustc_target/src/spec/powerpc64_unknown_freebsd.rs +++ b/compiler/rustc_target/src/spec/powerpc64_unknown_freebsd.rs @@ -4,7 +4,7 @@ use crate::spec::{LinkerFlavor, Target, TargetOptions}; pub fn target() -> Target { let mut base = super::freebsd_base::opts(); base.cpu = "ppc64".to_string(); - base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string()); + base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m64".to_string()); base.max_atomic_width = Some(64); Target { 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 9db880b0e53..559a1a40868 100644 --- a/compiler/rustc_target/src/spec/powerpc64_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/powerpc64_unknown_linux_gnu.rs @@ -4,7 +4,7 @@ use crate::spec::{LinkerFlavor, RelroLevel, Target, TargetOptions}; pub fn target() -> Target { let mut base = super::linux_gnu_base::opts(); base.cpu = "ppc64".to_string(); - base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string()); + base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m64".to_string()); base.max_atomic_width = Some(64); // ld.so in at least RHEL6 on ppc64 has a bug related to BIND_NOW, so only enable partial RELRO 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 8767f86b00b..f1190b159ab 100644 --- a/compiler/rustc_target/src/spec/powerpc64_unknown_linux_musl.rs +++ b/compiler/rustc_target/src/spec/powerpc64_unknown_linux_musl.rs @@ -4,7 +4,7 @@ use crate::spec::{LinkerFlavor, Target, TargetOptions}; pub fn target() -> Target { let mut base = super::linux_musl_base::opts(); base.cpu = "ppc64".to_string(); - base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string()); + base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m64".to_string()); base.max_atomic_width = Some(64); Target { diff --git a/compiler/rustc_target/src/spec/powerpc64_wrs_vxworks.rs b/compiler/rustc_target/src/spec/powerpc64_wrs_vxworks.rs index 2f28a856247..3ebc5469e0a 100644 --- a/compiler/rustc_target/src/spec/powerpc64_wrs_vxworks.rs +++ b/compiler/rustc_target/src/spec/powerpc64_wrs_vxworks.rs @@ -4,7 +4,7 @@ use crate::spec::{LinkerFlavor, Target, TargetOptions}; pub fn target() -> Target { let mut base = super::vxworks_base::opts(); base.cpu = "ppc64".to_string(); - base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string()); + base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m64".to_string()); base.max_atomic_width = Some(64); Target { 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 4cbd9976508..76f70e474f0 100644 --- a/compiler/rustc_target/src/spec/powerpc64le_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/powerpc64le_unknown_linux_gnu.rs @@ -3,7 +3,7 @@ use crate::spec::{LinkerFlavor, Target, TargetOptions}; pub fn target() -> Target { let mut base = super::linux_gnu_base::opts(); base.cpu = "ppc64le".to_string(); - base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string()); + base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m64".to_string()); base.max_atomic_width = Some(64); Target { 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 efdc9ad7517..42c49103b3b 100644 --- a/compiler/rustc_target/src/spec/powerpc64le_unknown_linux_musl.rs +++ b/compiler/rustc_target/src/spec/powerpc64le_unknown_linux_musl.rs @@ -3,7 +3,7 @@ use crate::spec::{LinkerFlavor, Target, TargetOptions}; pub fn target() -> Target { let mut base = super::linux_musl_base::opts(); base.cpu = "ppc64le".to_string(); - base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string()); + base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m64".to_string()); base.max_atomic_width = Some(64); Target { 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 70dd0b2aee6..21ffdd2d160 100644 --- a/compiler/rustc_target/src/spec/powerpc_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/powerpc_unknown_linux_gnu.rs @@ -3,7 +3,7 @@ use crate::spec::{LinkerFlavor, Target, TargetOptions}; pub fn target() -> Target { let mut base = super::linux_gnu_base::opts(); - base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m32".to_string()); + base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m32".to_string()); base.max_atomic_width = Some(32); Target { 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 66118b74955..8d8f746f97f 100644 --- a/compiler/rustc_target/src/spec/powerpc_unknown_linux_gnuspe.rs +++ b/compiler/rustc_target/src/spec/powerpc_unknown_linux_gnuspe.rs @@ -3,7 +3,7 @@ use crate::spec::{LinkerFlavor, Target, TargetOptions}; pub fn target() -> Target { let mut base = super::linux_gnu_base::opts(); - base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-mspe".to_string()); + base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-mspe".to_string()); base.max_atomic_width = Some(32); Target { 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 679a3a2f6aa..9633705db6d 100644 --- a/compiler/rustc_target/src/spec/powerpc_unknown_linux_musl.rs +++ b/compiler/rustc_target/src/spec/powerpc_unknown_linux_musl.rs @@ -3,7 +3,7 @@ use crate::spec::{LinkerFlavor, Target, TargetOptions}; pub fn target() -> Target { let mut base = super::linux_musl_base::opts(); - base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m32".to_string()); + base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m32".to_string()); base.max_atomic_width = Some(32); Target { diff --git a/compiler/rustc_target/src/spec/powerpc_unknown_netbsd.rs b/compiler/rustc_target/src/spec/powerpc_unknown_netbsd.rs index 1245098329a..4cc5224fae3 100644 --- a/compiler/rustc_target/src/spec/powerpc_unknown_netbsd.rs +++ b/compiler/rustc_target/src/spec/powerpc_unknown_netbsd.rs @@ -3,7 +3,7 @@ use crate::spec::{LinkerFlavor, Target, TargetOptions}; pub fn target() -> Target { let mut base = super::netbsd_base::opts(); - base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m32".to_string()); + base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m32".to_string()); base.max_atomic_width = Some(32); Target { diff --git a/compiler/rustc_target/src/spec/powerpc_wrs_vxworks.rs b/compiler/rustc_target/src/spec/powerpc_wrs_vxworks.rs index bb943a8825c..2f0a6ca44a0 100644 --- a/compiler/rustc_target/src/spec/powerpc_wrs_vxworks.rs +++ b/compiler/rustc_target/src/spec/powerpc_wrs_vxworks.rs @@ -3,8 +3,8 @@ use crate::spec::{LinkerFlavor, Target, TargetOptions}; pub fn target() -> Target { let mut base = super::vxworks_base::opts(); - base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m32".to_string()); - base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("--secure-plt".to_string()); + base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m32".to_string()); + base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("--secure-plt".to_string()); base.max_atomic_width = Some(32); Target { 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 4b4f118ba49..215f1a36227 100644 --- a/compiler/rustc_target/src/spec/powerpc_wrs_vxworks_spe.rs +++ b/compiler/rustc_target/src/spec/powerpc_wrs_vxworks_spe.rs @@ -3,8 +3,8 @@ use crate::spec::{LinkerFlavor, Target, TargetOptions}; pub fn target() -> Target { let mut base = super::vxworks_base::opts(); - base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-mspe".to_string()); - base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("--secure-plt".to_string()); + base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-mspe".to_string()); + base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("--secure-plt".to_string()); base.max_atomic_width = Some(32); Target { diff --git a/compiler/rustc_target/src/spec/redox_base.rs b/compiler/rustc_target/src/spec/redox_base.rs index 5ef705878a8..0afb4a72ac1 100644 --- a/compiler/rustc_target/src/spec/redox_base.rs +++ b/compiler/rustc_target/src/spec/redox_base.rs @@ -1,23 +1,6 @@ -use crate::spec::{LinkArgs, LinkerFlavor, RelroLevel, TargetOptions}; +use crate::spec::{RelroLevel, TargetOptions}; pub fn opts() -> TargetOptions { - let mut args = LinkArgs::new(); - args.insert( - LinkerFlavor::Gcc, - vec![ - // We want to be able to strip as much executable code as possible - // from the linker command line, and this flag indicates to the - // linker that it can avoid linking in dynamic libraries that don't - // actually satisfy any symbols up to that point (as with many other - // resolutions the linker does). This option only applies to all - // following libraries so we're sure to pass it as one of the first - // arguments. - "-Wl,--as-needed".to_string(), - // Always enable NX protection when it is available - "-Wl,-z,noexecstack".to_string(), - ], - ); - TargetOptions { os: "redox".to_string(), env: "relibc".to_string(), @@ -26,7 +9,6 @@ pub fn opts() -> TargetOptions { os_family: Some("unix".to_string()), linker_is_gnu: true, has_rpath: true, - pre_link_args: args, position_independent_executables: true, relro_level: RelroLevel::Full, has_elf_tls: true, diff --git a/compiler/rustc_target/src/spec/sparc64_unknown_netbsd.rs b/compiler/rustc_target/src/spec/sparc64_unknown_netbsd.rs index 7d685c83100..b4286dfd88f 100644 --- a/compiler/rustc_target/src/spec/sparc64_unknown_netbsd.rs +++ b/compiler/rustc_target/src/spec/sparc64_unknown_netbsd.rs @@ -4,7 +4,7 @@ use crate::spec::{LinkerFlavor, Target, TargetOptions}; pub fn target() -> Target { let mut base = super::netbsd_base::opts(); base.cpu = "v9".to_string(); - base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string()); + base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m64".to_string()); base.max_atomic_width = Some(64); Target { diff --git a/compiler/rustc_target/src/spec/sparc64_unknown_openbsd.rs b/compiler/rustc_target/src/spec/sparc64_unknown_openbsd.rs index 63b13fad4f7..9732983161f 100644 --- a/compiler/rustc_target/src/spec/sparc64_unknown_openbsd.rs +++ b/compiler/rustc_target/src/spec/sparc64_unknown_openbsd.rs @@ -5,7 +5,7 @@ pub fn target() -> Target { let mut base = super::openbsd_base::opts(); base.endian = Endian::Big; base.cpu = "v9".to_string(); - base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string()); + base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m64".to_string()); base.max_atomic_width = Some(64); Target { 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 9e8fbff81c5..1fd4cadfffc 100644 --- a/compiler/rustc_target/src/spec/sparc_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/sparc_unknown_linux_gnu.rs @@ -6,7 +6,7 @@ pub fn target() -> Target { base.endian = Endian::Big; base.cpu = "v9".to_string(); base.max_atomic_width = Some(64); - base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-mv8plus".to_string()); + base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-mv8plus".to_string()); Target { llvm_target: "sparc-unknown-linux-gnu".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 8131a6e2ea4..975fd81d9c3 100644 --- a/compiler/rustc_target/src/spec/thumbv7a_pc_windows_msvc.rs +++ b/compiler/rustc_target/src/spec/thumbv7a_pc_windows_msvc.rs @@ -11,10 +11,10 @@ pub fn target() -> Target { // where necessary, but this is not the observed behavior. // Disabling the LBR optimization works around the issue. let pre_link_args_msvc = "/OPT:NOLBR".to_string(); - base.pre_link_args.get_mut(&LinkerFlavor::Msvc).unwrap().push(pre_link_args_msvc.clone()); + base.pre_link_args.entry(LinkerFlavor::Msvc).or_default().push(pre_link_args_msvc.clone()); base.pre_link_args - .get_mut(&LinkerFlavor::Lld(LldFlavor::Link)) - .unwrap() + .entry(LinkerFlavor::Lld(LldFlavor::Link)) + .or_default() .push(pre_link_args_msvc); // FIXME(jordanrh): use PanicStrategy::Unwind when SEH is diff --git a/compiler/rustc_target/src/spec/thumbv7neon_linux_androideabi.rs b/compiler/rustc_target/src/spec/thumbv7neon_linux_androideabi.rs index 41fdbc2f0a0..58b0a9d2202 100644 --- a/compiler/rustc_target/src/spec/thumbv7neon_linux_androideabi.rs +++ b/compiler/rustc_target/src/spec/thumbv7neon_linux_androideabi.rs @@ -12,7 +12,7 @@ pub fn target() -> Target { let mut base = super::android_base::opts(); base.features = "+v7,+thumb-mode,+thumb2,+vfp3,+neon".to_string(); base.max_atomic_width = Some(64); - base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-march=armv7-a".to_string()); + base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-march=armv7-a".to_string()); Target { llvm_target: "armv7-none-linux-android".to_string(), diff --git a/compiler/rustc_target/src/spec/uefi_msvc_base.rs b/compiler/rustc_target/src/spec/uefi_msvc_base.rs index b9ff16bd19f..6b6b6018601 100644 --- a/compiler/rustc_target/src/spec/uefi_msvc_base.rs +++ b/compiler/rustc_target/src/spec/uefi_msvc_base.rs @@ -30,10 +30,10 @@ pub fn opts() -> TargetOptions { // exit (default for applications). "/subsystem:efi_application".to_string(), ]; - base.pre_link_args.get_mut(&LinkerFlavor::Msvc).unwrap().extend(pre_link_args_msvc.clone()); + base.pre_link_args.entry(LinkerFlavor::Msvc).or_default().extend(pre_link_args_msvc.clone()); base.pre_link_args - .get_mut(&LinkerFlavor::Lld(LldFlavor::Link)) - .unwrap() + .entry(LinkerFlavor::Lld(LldFlavor::Link)) + .or_default() .extend(pre_link_args_msvc); TargetOptions { diff --git a/compiler/rustc_target/src/spec/vxworks_base.rs b/compiler/rustc_target/src/spec/vxworks_base.rs index 70bc9ce3e0e..8396d0463d9 100644 --- a/compiler/rustc_target/src/spec/vxworks_base.rs +++ b/compiler/rustc_target/src/spec/vxworks_base.rs @@ -1,21 +1,6 @@ -use crate::spec::{LinkArgs, LinkerFlavor, TargetOptions}; +use crate::spec::TargetOptions; pub fn opts() -> TargetOptions { - let mut args = LinkArgs::new(); - args.insert( - LinkerFlavor::Gcc, - vec![ - // We want to be able to strip as much executable code as possible - // from the linker command line, and this flag indicates to the - // linker that it can avoid linking in dynamic libraries that don't - // actually satisfy any symbols up to that point (as with many other - // resolutions the linker does). This option only applies to all - // following libraries so we're sure to pass it as one of the first - // arguments. - "-Wl,--as-needed".to_string(), - ], - ); - TargetOptions { os: "vxworks".to_string(), env: "gnu".to_string(), @@ -27,7 +12,6 @@ pub fn opts() -> TargetOptions { os_family: Some("unix".to_string()), linker_is_gnu: true, has_rpath: true, - pre_link_args: args, position_independent_executables: false, has_elf_tls: true, crt_static_default: true, diff --git a/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs b/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs index 9f69ce16c21..58d7633fa62 100644 --- a/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs +++ b/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs @@ -4,7 +4,7 @@ use super::{LinkArgs, LinkerFlavor, PanicStrategy, Target, TargetOptions}; pub fn target() -> Target { let mut options = wasm32_base::options(); - let clang_args = options.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap(); + let clang_args = options.pre_link_args.entry(LinkerFlavor::Gcc).or_default(); // Rust really needs a way for users to specify exports and imports in // the source code. --export-dynamic isn't the right tool for this job, diff --git a/compiler/rustc_target/src/spec/wasm32_unknown_unknown.rs b/compiler/rustc_target/src/spec/wasm32_unknown_unknown.rs index 5e89ba2520b..73a5e16c82b 100644 --- a/compiler/rustc_target/src/spec/wasm32_unknown_unknown.rs +++ b/compiler/rustc_target/src/spec/wasm32_unknown_unknown.rs @@ -17,7 +17,7 @@ pub fn target() -> Target { let mut options = wasm32_base::options(); options.os = "unknown".to_string(); options.linker_flavor = LinkerFlavor::Lld(LldFlavor::Wasm); - let clang_args = options.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap(); + let clang_args = options.pre_link_args.entry(LinkerFlavor::Gcc).or_default(); // Make sure clang uses LLD as its linker and is configured appropriately // otherwise @@ -35,7 +35,7 @@ pub fn target() -> Target { clang_args.push("-Wl,--export-dynamic".to_string()); // Add the flags to wasm-ld's args too. - let lld_args = options.pre_link_args.get_mut(&LinkerFlavor::Lld(LldFlavor::Wasm)).unwrap(); + let lld_args = options.pre_link_args.entry(LinkerFlavor::Lld(LldFlavor::Wasm)).or_default(); lld_args.push("--no-entry".to_string()); lld_args.push("--export-dynamic".to_string()); diff --git a/compiler/rustc_target/src/spec/windows_gnu_base.rs b/compiler/rustc_target/src/spec/windows_gnu_base.rs index f556a13a519..7036f338150 100644 --- a/compiler/rustc_target/src/spec/windows_gnu_base.rs +++ b/compiler/rustc_target/src/spec/windows_gnu_base.rs @@ -9,8 +9,6 @@ pub fn opts() -> TargetOptions { // Tell GCC to avoid linker plugins, because we are not bundling // them with Windows installer, and Rust does its own LTO anyways. "-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 diff --git a/compiler/rustc_target/src/spec/windows_uwp_msvc_base.rs b/compiler/rustc_target/src/spec/windows_uwp_msvc_base.rs index 700ee5ec646..b3fa5c22f98 100644 --- a/compiler/rustc_target/src/spec/windows_uwp_msvc_base.rs +++ b/compiler/rustc_target/src/spec/windows_uwp_msvc_base.rs @@ -5,10 +5,10 @@ pub fn opts() -> TargetOptions { opts.vendor = "uwp".to_string(); let pre_link_args_msvc = vec!["/APPCONTAINER".to_string(), "mincore.lib".to_string()]; - opts.pre_link_args.get_mut(&LinkerFlavor::Msvc).unwrap().extend(pre_link_args_msvc.clone()); + opts.pre_link_args.entry(LinkerFlavor::Msvc).or_default().extend(pre_link_args_msvc.clone()); opts.pre_link_args - .get_mut(&LinkerFlavor::Lld(LldFlavor::Link)) - .unwrap() + .entry(LinkerFlavor::Lld(LldFlavor::Link)) + .or_default() .extend(pre_link_args_msvc); opts 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 74fb6f0a834..6365e5650e4 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 @@ -4,9 +4,6 @@ use super::{LinkerFlavor, LldFlavor, PanicStrategy, Target, TargetOptions}; pub fn target() -> Target { const PRE_LINK_ARGS: &[&str] = &[ - "--as-needed", - "-z", - "noexecstack", "-e", "elf_entry", "-Bstatic", 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 d436242e62b..0945a9f5c59 100644 --- a/compiler/rustc_target/src/spec/x86_64_linux_android.rs +++ b/compiler/rustc_target/src/spec/x86_64_linux_android.rs @@ -6,7 +6,7 @@ pub fn target() -> Target { // https://developer.android.com/ndk/guides/abis.html#86-64 base.features = "+mmx,+sse,+sse2,+sse3,+ssse3,+sse4.1,+sse4.2,+popcnt".to_string(); base.max_atomic_width = Some(64); - base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string()); + base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m64".to_string()); base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) }; Target { 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 36726ab4aed..26a81a484b9 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,7 @@ use crate::spec::{LinkerFlavor, LldFlavor, Target}; pub fn target() -> Target { let mut base = super::windows_gnu_base::opts(); base.cpu = "x86-64".to_string(); - let gcc_pre_link_args = base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap(); + let gcc_pre_link_args = base.pre_link_args.entry(LinkerFlavor::Gcc).or_default(); 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()); 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 d86b0d67acd..295f9c837c3 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_dragonfly.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_dragonfly.rs @@ -4,7 +4,7 @@ pub fn target() -> Target { let mut base = super::dragonfly_base::opts(); base.cpu = "x86-64".to_string(); base.max_atomic_width = Some(64); - base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string()); + base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m64".to_string()); base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) }; Target { 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 c7d3b3feed5..aac01445917 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_freebsd.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_freebsd.rs @@ -4,7 +4,7 @@ pub fn target() -> Target { let mut base = super::freebsd_base::opts(); base.cpu = "x86-64".to_string(); base.max_atomic_width = Some(64); - base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string()); + base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m64".to_string()); base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) }; Target { 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 99906764dfc..dfda49b9c33 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 @@ -4,7 +4,7 @@ pub fn target() -> Target { let mut base = super::linux_gnu_base::opts(); base.cpu = "x86-64".to_string(); base.max_atomic_width = Some(64); - base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string()); + base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m64".to_string()); base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) }; Target { 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 4b2bce37470..5f87534fe95 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 @@ -4,7 +4,7 @@ pub fn target() -> Target { let mut base = super::linux_gnu_base::opts(); base.cpu = "x86-64".to_string(); base.max_atomic_width = Some(64); - base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-mx32".to_string()); + base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-mx32".to_string()); base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) }; base.has_elf_tls = false; // BUG(GabrielMajeri): disabling the PLT on x86_64 Linux with x32 ABI 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 fa9fdf5aa09..da79bc2f338 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 @@ -4,7 +4,7 @@ pub fn target() -> Target { let mut base = super::linux_musl_base::opts(); base.cpu = "x86-64".to_string(); base.max_atomic_width = Some(64); - base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string()); + base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m64".to_string()); base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) }; base.static_position_independent_executables = true; 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 6d19dec00b4..54e7ceee82e 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_netbsd.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_netbsd.rs @@ -4,7 +4,7 @@ pub fn target() -> Target { let mut base = super::netbsd_base::opts(); base.cpu = "x86-64".to_string(); base.max_atomic_width = Some(64); - base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string()); + base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m64".to_string()); base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) }; Target { diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_none_linuxkernel.rs b/compiler/rustc_target/src/spec/x86_64_unknown_none_linuxkernel.rs index 68d80205e14..fa6f255d4d9 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_none_linuxkernel.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_none_linuxkernel.rs @@ -11,7 +11,7 @@ pub fn target() -> Target { "-mmx,-sse,-sse2,-sse3,-ssse3,-sse4.1,-sse4.2,-3dnow,-3dnowa,-avx,-avx2,+soft-float" .to_string(); base.code_model = Some(CodeModel::Kernel); - base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string()); + base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m64".to_string()); Target { // FIXME: Some dispute, the linux-on-clang folks think this should use 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 ac5939bcb3c..530e63966aa 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_openbsd.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_openbsd.rs @@ -4,7 +4,7 @@ pub fn target() -> Target { let mut base = super::openbsd_base::opts(); base.cpu = "x86-64".to_string(); base.max_atomic_width = Some(64); - base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string()); + base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m64".to_string()); base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) }; Target { 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 ddabe95ab83..934f8de8ecc 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_redox.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_redox.rs @@ -4,7 +4,7 @@ pub fn target() -> Target { let mut base = super::redox_base::opts(); base.cpu = "x86-64".to_string(); base.max_atomic_width = Some(64); - base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string()); + base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m64".to_string()); base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) }; Target { 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 57913ba0dab..a5425e1c129 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,7 @@ 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(); - let gcc_pre_link_args = base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap(); + let gcc_pre_link_args = base.pre_link_args.entry(LinkerFlavor::Gcc).or_default(); 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()); 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 1b35e813fcd..f9fa9d93843 100644 --- a/compiler/rustc_target/src/spec/x86_64_wrs_vxworks.rs +++ b/compiler/rustc_target/src/spec/x86_64_wrs_vxworks.rs @@ -4,7 +4,7 @@ pub fn target() -> Target { let mut base = super::vxworks_base::opts(); base.cpu = "x86-64".to_string(); base.max_atomic_width = Some(64); - base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string()); + base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m64".to_string()); base.stack_probes = StackProbeType::InlineOrCall { min_llvm_version_for_inline: (11, 0, 1) }; base.disable_redzone = true; diff --git a/compiler/rustc_trait_selection/src/lib.rs b/compiler/rustc_trait_selection/src/lib.rs index aeb7b149786..4097e1577e1 100644 --- a/compiler/rustc_trait_selection/src/lib.rs +++ b/compiler/rustc_trait_selection/src/lib.rs @@ -15,6 +15,7 @@ #![feature(box_patterns)] #![feature(drain_filter)] #![feature(in_band_lifetimes)] +#![feature(iter_zip)] #![feature(never_type)] #![feature(crate_visibility_modifier)] #![cfg_attr(bootstrap, feature(or_patterns))] diff --git a/compiler/rustc_trait_selection/src/opaque_types.rs b/compiler/rustc_trait_selection/src/opaque_types.rs index d6a585e626c..fb4a8ce687c 100644 --- a/compiler/rustc_trait_selection/src/opaque_types.rs +++ b/compiler/rustc_trait_selection/src/opaque_types.rs @@ -697,7 +697,7 @@ where { fn visit_binder<T: TypeFoldable<'tcx>>( &mut self, - t: &ty::Binder<T>, + t: &ty::Binder<'tcx, T>, ) -> ControlFlow<Self::BreakTy> { t.as_ref().skip_binder().visit_with(self); ControlFlow::CONTINUE @@ -1171,7 +1171,7 @@ impl<'a, 'tcx> Instantiator<'a, 'tcx> { // This also instantiates nested instances of `impl Trait`. let predicate = self.instantiate_opaque_types_in_map(predicate); - let cause = traits::ObligationCause::new(span, self.body_id, traits::MiscObligation); + let cause = traits::ObligationCause::new(span, self.body_id, traits::OpaqueType); // Require that the predicate holds for the concrete type. debug!("instantiate_opaque_types: predicate={:?}", predicate); diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs index 0d71fc57e39..f54eb0914a5 100644 --- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs +++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs @@ -12,6 +12,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use std::collections::hash_map::Entry; use std::collections::VecDeque; +use std::iter; // FIXME(twk): this is obviously not nice to duplicate like that #[derive(Eq, PartialEq, Hash, Copy, Clone, Debug)] @@ -83,7 +84,7 @@ impl<'tcx> AutoTraitFinder<'tcx> { let trait_ref = ty::TraitRef { def_id: trait_did, substs: tcx.mk_substs_trait(ty, &[]) }; - let trait_pred = ty::Binder::bind(trait_ref); + let trait_pred = ty::Binder::dummy(trait_ref); let bail_out = tcx.infer_ctxt().enter(|infcx| { let mut selcx = SelectionContext::with_negative(&infcx, true); @@ -279,7 +280,7 @@ impl AutoTraitFinder<'tcx> { let mut already_visited = FxHashSet::default(); let mut predicates = VecDeque::new(); - predicates.push_back(ty::Binder::bind(ty::TraitPredicate { + predicates.push_back(ty::Binder::dummy(ty::TraitPredicate { trait_ref: ty::TraitRef { def_id: trait_did, substs: infcx.tcx.mk_substs_trait(ty, &[]), @@ -428,7 +429,9 @@ impl AutoTraitFinder<'tcx> { return true; } - for (new_region, old_region) in new_substs.regions().zip(old_substs.regions()) { + for (new_region, old_region) in + iter::zip(new_substs.regions(), old_substs.regions()) + { match (new_region, old_region) { // If both predicates have an `ReLateBound` (a HRTB) in the // same spot, we do nothing. diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index e8ae1f44a36..38cb4ee66ca 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -74,23 +74,22 @@ where let impl2_ref = tcx.impl_trait_ref(impl2_def_id); // Check if any of the input types definitely do not unify. - if impl1_ref - .iter() - .flat_map(|tref| tref.substs.types()) - .zip(impl2_ref.iter().flat_map(|tref| tref.substs.types())) - .any(|(ty1, ty2)| { - let t1 = fast_reject::simplify_type(tcx, ty1, false); - let t2 = fast_reject::simplify_type(tcx, ty2, false); - if let (Some(t1), Some(t2)) = (t1, t2) { - // Simplified successfully - // Types cannot unify if they differ in their reference mutability or simplify to different types - t1 != t2 || ty1.ref_mutability() != ty2.ref_mutability() - } else { - // Types might unify - false - } - }) - { + if iter::zip( + impl1_ref.iter().flat_map(|tref| tref.substs.types()), + impl2_ref.iter().flat_map(|tref| tref.substs.types()), + ) + .any(|(ty1, ty2)| { + let t1 = fast_reject::simplify_type(tcx, ty1, false); + let t2 = fast_reject::simplify_type(tcx, ty2, false); + if let (Some(t1), Some(t2)) = (t1, t2) { + // Simplified successfully + // Types cannot unify if they differ in their reference mutability or simplify to different types + t1 != t2 || ty1.ref_mutability() != ty2.ref_mutability() + } else { + // Types might unify + false + } + }) { // Some types involved are definitely different, so the impls couldn't possibly overlap. debug!("overlapping_impls: fast_reject early-exit"); return no_overlap(); diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index ac987a9f7b3..8961cdaebf3 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -23,6 +23,7 @@ use rustc_span::def_id::{DefId, LocalDefId}; use rustc_span::Span; use std::cmp; +use std::iter; use std::ops::ControlFlow; /// Check if a given constant can be evaluated. @@ -672,9 +673,7 @@ pub(super) fn try_unify<'tcx>( if a_args.len() == b_args.len() => { try_unify(tcx, a.subtree(a_f), b.subtree(b_f)) - && a_args - .iter() - .zip(b_args) + && iter::zip(a_args, b_args) .all(|(&an, &bn)| try_unify(tcx, a.subtree(an), b.subtree(bn))) } _ => false, 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 060e4e36dfe..15a3d3ddd8d 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -28,6 +28,7 @@ use rustc_session::DiagnosticMessageId; use rustc_span::symbol::{kw, sym}; use rustc_span::{ExpnKind, MultiSpan, Span, DUMMY_SP}; use std::fmt; +use std::iter; use crate::traits::query::evaluate_obligation::InferCtxtExt as _; use crate::traits::query::normalize::AtExt as _; @@ -161,7 +162,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { } } - for (error, suppressed) in errors.iter().zip(is_suppressed) { + for (error, suppressed) in iter::zip(errors, is_suppressed) { if !suppressed { self.report_fulfillment_error(error, body_id, fallback_has_occurred); } @@ -1225,10 +1226,11 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> { ); let is_normalized_ty_expected = !matches!( - obligation.cause.code, + obligation.cause.code.peel_derives(), ObligationCauseCode::ItemObligation(_) | ObligationCauseCode::BindingObligation(_, _) | ObligationCauseCode::ObjectCastObligation(_) + | ObligationCauseCode::OpaqueType ); if let Err(error) = self.at(&obligation.cause, obligation.param_env).eq_exp( diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs index cecdcc97896..1ea34e5814e 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs @@ -7,6 +7,7 @@ use rustc_hir::def_id::DefId; use rustc_middle::ty::subst::Subst; use rustc_middle::ty::{self, GenericParamDefKind}; use rustc_span::symbol::sym; +use std::iter; use super::InferCtxtPrivExt; @@ -51,12 +52,11 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { if let Ok(..) = self.can_eq(param_env, trait_self_ty, impl_self_ty) { self_match_impls.push(def_id); - if trait_ref - .substs - .types() - .skip(1) - .zip(impl_trait_ref.substs.types().skip(1)) - .all(|(u, v)| self.fuzzy_match_tys(u, v)) + if iter::zip( + trait_ref.substs.types().skip(1), + impl_trait_ref.substs.types().skip(1), + ) + .all(|(u, v)| self.fuzzy_match_tys(u, v)) { fuzzy_match_impls.push(def_id); } @@ -163,61 +163,65 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { flags.push((sym::from_desugaring, None)); flags.push((sym::from_desugaring, Some(format!("{:?}", k)))); } - let generics = self.tcx.generics_of(def_id); - let self_ty = trait_ref.self_ty(); - // This is also included through the generics list as `Self`, - // but the parser won't allow you to use it - flags.push((sym::_Self, Some(self_ty.to_string()))); - if let Some(def) = self_ty.ty_adt_def() { - // We also want to be able to select self's original - // signature with no type arguments resolved - flags.push((sym::_Self, Some(self.tcx.type_of(def.did).to_string()))); - } - for param in generics.params.iter() { - let value = match param.kind { - GenericParamDefKind::Type { .. } | GenericParamDefKind::Const { .. } => { - trait_ref.substs[param.index as usize].to_string() - } - GenericParamDefKind::Lifetime => continue, - }; - let name = param.name; - flags.push((name, Some(value))); - } + // Add all types without trimmed paths. + ty::print::with_no_trimmed_paths(|| { + let generics = self.tcx.generics_of(def_id); + let self_ty = trait_ref.self_ty(); + // This is also included through the generics list as `Self`, + // but the parser won't allow you to use it + flags.push((sym::_Self, Some(self_ty.to_string()))); + if let Some(def) = self_ty.ty_adt_def() { + // We also want to be able to select self's original + // signature with no type arguments resolved + flags.push((sym::_Self, Some(self.tcx.type_of(def.did).to_string()))); + } - if let Some(true) = self_ty.ty_adt_def().map(|def| def.did.is_local()) { - flags.push((sym::crate_local, None)); - } + for param in generics.params.iter() { + let value = match param.kind { + GenericParamDefKind::Type { .. } | GenericParamDefKind::Const { .. } => { + trait_ref.substs[param.index as usize].to_string() + } + GenericParamDefKind::Lifetime => continue, + }; + let name = param.name; + flags.push((name, Some(value))); + } - // Allow targeting all integers using `{integral}`, even if the exact type was resolved - if self_ty.is_integral() { - flags.push((sym::_Self, Some("{integral}".to_owned()))); - } + if let Some(true) = self_ty.ty_adt_def().map(|def| def.did.is_local()) { + flags.push((sym::crate_local, None)); + } - if let ty::Array(aty, len) = self_ty.kind() { - flags.push((sym::_Self, Some("[]".to_owned()))); - flags.push((sym::_Self, Some(format!("[{}]", aty)))); - if let Some(def) = aty.ty_adt_def() { - // We also want to be able to select the array's type's original - // signature with no type arguments resolved - let type_string = self.tcx.type_of(def.did).to_string(); - flags.push((sym::_Self, Some(format!("[{}]", type_string)))); + // Allow targeting all integers using `{integral}`, even if the exact type was resolved + if self_ty.is_integral() { + flags.push((sym::_Self, Some("{integral}".to_owned()))); + } - let len = len.val.try_to_value().and_then(|v| v.try_to_machine_usize(self.tcx)); - let string = match len { - Some(n) => format!("[{}; {}]", type_string, n), - None => format!("[{}; _]", type_string), - }; - flags.push((sym::_Self, Some(string))); + if let ty::Array(aty, len) = self_ty.kind() { + flags.push((sym::_Self, Some("[]".to_owned()))); + flags.push((sym::_Self, Some(format!("[{}]", aty)))); + if let Some(def) = aty.ty_adt_def() { + // We also want to be able to select the array's type's original + // signature with no type arguments resolved + let type_string = self.tcx.type_of(def.did).to_string(); + flags.push((sym::_Self, Some(format!("[{}]", type_string)))); + + let len = len.val.try_to_value().and_then(|v| v.try_to_machine_usize(self.tcx)); + let string = match len { + Some(n) => format!("[{}; {}]", type_string, n), + None => format!("[{}; _]", type_string), + }; + flags.push((sym::_Self, Some(string))); + } } - } - if let ty::Dynamic(traits, _) = self_ty.kind() { - for t in traits.iter() { - if let ty::ExistentialPredicate::Trait(trait_ref) = t.skip_binder() { - flags.push((sym::_Self, Some(self.tcx.def_path_str(trait_ref.def_id)))) + if let ty::Dynamic(traits, _) = self_ty.kind() { + for t in traits.iter() { + if let ty::ExistentialPredicate::Trait(trait_ref) = t.skip_binder() { + flags.push((sym::_Self, Some(self.tcx.def_path_str(trait_ref.def_id)))) + } } } - } + }); if let Ok(Some(command)) = OnUnimplementedDirective::of_item(self.tcx, trait_ref.def_id, def_id) 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 c1b105f1d84..0549db06806 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -65,7 +65,7 @@ pub trait InferCtxtExt<'tcx> { &self, obligation: &PredicateObligation<'tcx>, err: &mut DiagnosticBuilder<'_>, - trait_ref: ty::Binder<ty::TraitRef<'tcx>>, + trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>, points_at_arg: bool, ); @@ -73,7 +73,7 @@ pub trait InferCtxtExt<'tcx> { &self, obligation: &PredicateObligation<'tcx>, err: &mut DiagnosticBuilder<'_>, - trait_ref: &ty::Binder<ty::TraitRef<'tcx>>, + trait_ref: &ty::Binder<'tcx, ty::TraitRef<'tcx>>, points_at_arg: bool, has_custom_message: bool, ) -> bool; @@ -82,14 +82,14 @@ pub trait InferCtxtExt<'tcx> { &self, obligation: &PredicateObligation<'tcx>, err: &mut DiagnosticBuilder<'_>, - trait_ref: ty::Binder<ty::TraitRef<'tcx>>, + trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>, ); fn suggest_change_mut( &self, obligation: &PredicateObligation<'tcx>, err: &mut DiagnosticBuilder<'_>, - trait_ref: ty::Binder<ty::TraitRef<'tcx>>, + trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>, points_at_arg: bool, ); @@ -98,7 +98,7 @@ pub trait InferCtxtExt<'tcx> { obligation: &PredicateObligation<'tcx>, err: &mut DiagnosticBuilder<'_>, span: Span, - trait_ref: ty::Binder<ty::TraitRef<'tcx>>, + trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>, ); fn return_type_span(&self, obligation: &PredicateObligation<'tcx>) -> Option<Span>; @@ -108,7 +108,7 @@ pub trait InferCtxtExt<'tcx> { err: &mut DiagnosticBuilder<'_>, span: Span, obligation: &PredicateObligation<'tcx>, - trait_ref: ty::Binder<ty::TraitRef<'tcx>>, + trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>, ) -> bool; fn point_at_returns_when_relevant( @@ -170,7 +170,7 @@ pub trait InferCtxtExt<'tcx> { &self, err: &mut DiagnosticBuilder<'_>, obligation: &PredicateObligation<'tcx>, - trait_ref: ty::Binder<ty::TraitRef<'tcx>>, + trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>, span: Span, ); } @@ -583,7 +583,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { &self, obligation: &PredicateObligation<'tcx>, err: &mut DiagnosticBuilder<'_>, - trait_ref: ty::Binder<ty::TraitRef<'tcx>>, + trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>, points_at_arg: bool, ) { let self_ty = match trait_ref.self_ty().no_bound_vars() { @@ -676,7 +676,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { &self, obligation: &PredicateObligation<'tcx>, err: &mut DiagnosticBuilder<'_>, - trait_ref: &ty::Binder<ty::TraitRef<'tcx>>, + trait_ref: &ty::Binder<'tcx, ty::TraitRef<'tcx>>, points_at_arg: bool, has_custom_message: bool, ) -> bool { @@ -761,7 +761,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { &self, obligation: &PredicateObligation<'tcx>, err: &mut DiagnosticBuilder<'_>, - trait_ref: ty::Binder<ty::TraitRef<'tcx>>, + trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>, ) { let span = obligation.cause.span; @@ -824,7 +824,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { &self, obligation: &PredicateObligation<'tcx>, err: &mut DiagnosticBuilder<'_>, - trait_ref: ty::Binder<ty::TraitRef<'tcx>>, + trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>, points_at_arg: bool, ) { let span = obligation.cause.span; @@ -896,10 +896,10 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { obligation: &PredicateObligation<'tcx>, err: &mut DiagnosticBuilder<'_>, span: Span, - trait_ref: ty::Binder<ty::TraitRef<'tcx>>, + trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>, ) { let is_empty_tuple = - |ty: ty::Binder<Ty<'_>>| *ty.skip_binder().kind() == ty::Tuple(ty::List::empty()); + |ty: ty::Binder<'tcx, Ty<'_>>| *ty.skip_binder().kind() == ty::Tuple(ty::List::empty()); let hir = self.tcx.hir(); let parent_node = hir.get_parent_node(obligation.cause.body_id); @@ -948,7 +948,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { err: &mut DiagnosticBuilder<'_>, span: Span, obligation: &PredicateObligation<'tcx>, - trait_ref: ty::Binder<ty::TraitRef<'tcx>>, + trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>, ) -> bool { match obligation.cause.code.peel_derives() { // Only suggest `impl Trait` if the return type is unsized because it is `dyn Trait`. @@ -1840,6 +1840,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { | ObligationCauseCode::MethodReceiver | ObligationCauseCode::ReturnNoExpression | ObligationCauseCode::UnifyReceiver(..) + | ObligationCauseCode::OpaqueType | ObligationCauseCode::MiscObligation => {} ObligationCauseCode::SliceOrArrayElem => { err.note("slice and array elements must have `Sized` type"); @@ -2190,7 +2191,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { &self, err: &mut DiagnosticBuilder<'_>, obligation: &PredicateObligation<'tcx>, - trait_ref: ty::Binder<ty::TraitRef<'tcx>>, + trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>, span: Span, ) { debug!( diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index 79f65669479..fc9739f70d4 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -684,7 +684,7 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> { /// Returns the set of inference variables contained in `substs`. fn substs_infer_vars<'a, 'tcx>( selcx: &mut SelectionContext<'a, 'tcx>, - substs: ty::Binder<SubstsRef<'tcx>>, + substs: ty::Binder<'tcx, SubstsRef<'tcx>>, ) -> impl Iterator<Item = TyOrConstInferVar<'tcx>> { selcx .infcx() diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs index 7de20e477fe..b5a458db607 100644 --- a/compiler/rustc_trait_selection/src/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -757,7 +757,7 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeFoldable<'tcx>>( struct IllegalSelfTypeVisitor<'tcx> { tcx: TyCtxt<'tcx>, trait_def_id: DefId, - supertraits: Option<Vec<ty::PolyTraitRef<'tcx>>>, + supertraits: Option<Vec<DefId>>, } impl<'tcx> TypeVisitor<'tcx> for IllegalSelfTypeVisitor<'tcx> { @@ -778,8 +778,10 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeFoldable<'tcx>>( // Compute supertraits of current trait lazily. if self.supertraits.is_none() { let trait_ref = - ty::Binder::bind(ty::TraitRef::identity(self.tcx, self.trait_def_id)); - self.supertraits = Some(traits::supertraits(self.tcx, trait_ref).collect()); + ty::Binder::dummy(ty::TraitRef::identity(self.tcx, self.trait_def_id)); + self.supertraits = Some( + traits::supertraits(self.tcx, trait_ref).map(|t| t.def_id()).collect(), + ); } // Determine whether the trait reference `Foo as @@ -790,9 +792,11 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeFoldable<'tcx>>( // direct equality here because all of these types // are part of the formal parameter listing, and // hence there should be no inference variables. - let projection_trait_ref = ty::Binder::bind(data.trait_ref(self.tcx)); - let is_supertrait_of_current_trait = - self.supertraits.as_ref().unwrap().contains(&projection_trait_ref); + let is_supertrait_of_current_trait = self + .supertraits + .as_ref() + .unwrap() + .contains(&data.trait_ref(self.tcx).def_id); if is_supertrait_of_current_trait { ControlFlow::CONTINUE // do not walk contained types, do not report error, do collect $200 diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 0af6d645915..b3e5df4da0a 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -1275,6 +1275,9 @@ fn confirm_discriminant_kind_candidate<'cx, 'tcx>( let tcx = selcx.tcx(); let self_ty = selcx.infcx().shallow_resolve(obligation.predicate.self_ty()); + // We get here from `poly_project_and_unify_type` which replaces bound vars + // with placeholders + debug_assert!(!self_ty.has_escaping_bound_vars()); let substs = tcx.mk_substs([self_ty.into()].iter()); let discriminant_def_id = tcx.require_lang_item(LangItem::Discriminant, None); @@ -1306,7 +1309,7 @@ fn confirm_pointee_candidate<'cx, 'tcx>( ty: self_ty.ptr_metadata_ty(tcx), }; - confirm_param_env_candidate(selcx, obligation, ty::Binder::bind(predicate), false) + confirm_param_env_candidate(selcx, obligation, ty::Binder::bind(predicate, tcx), false) } fn confirm_fn_pointer_candidate<'cx, 'tcx>( diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs index cf7f0a553c7..b351af44e94 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs @@ -8,12 +8,6 @@ pub struct ImpliedOutlivesBounds<'tcx> { pub ty: Ty<'tcx>, } -impl<'tcx> ImpliedOutlivesBounds<'tcx> { - pub fn new(ty: Ty<'tcx>) -> Self { - ImpliedOutlivesBounds { ty } - } -} - impl<'tcx> super::QueryTypeOp<'tcx> for ImpliedOutlivesBounds<'tcx> { type QueryResponse = Vec<OutlivesBound<'tcx>>; diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 272930f6bb9..31685a012ca 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -272,7 +272,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { &mut self, obligation: &TraitObligation<'tcx>, trait_def_id: DefId, - nested: ty::Binder<Vec<Ty<'tcx>>>, + nested: ty::Binder<'tcx, Vec<Ty<'tcx>>>, ) -> ImplSourceAutoImplData<PredicateObligation<'tcx>> { debug!(?nested, "vtable_auto_impl"); ensure_sufficient_stack(|| { @@ -748,7 +748,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { cause, obligation.recursion_depth + 1, obligation.param_env, - ty::Binder::bind(outlives).to_predicate(tcx), + obligation.predicate.rebind(outlives).to_predicate(tcx), )); } diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index bc8a0eae0e0..f441246909b 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -204,7 +204,7 @@ struct EvaluatedCandidate<'tcx> { /// When does the builtin impl for `T: Trait` apply? enum BuiltinImplConditions<'tcx> { /// The impl is conditional on `T1, T2, ...: Trait`. - Where(ty::Binder<Vec<Ty<'tcx>>>), + Where(ty::Binder<'tcx, Vec<Ty<'tcx>>>), /// There is no built-in impl. There may be some other /// candidate (a where-clause or user-defined impl). None, @@ -981,7 +981,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { OP: FnOnce(&mut Self) -> R, { let (result, dep_node) = - self.tcx().dep_graph.with_anon_task(DepKind::TraitSelect, || op(self)); + self.tcx().dep_graph.with_anon_task(self.tcx(), DepKind::TraitSelect, || op(self)); self.tcx().dep_graph.read_index(dep_node); (result, dep_node) } @@ -1673,7 +1673,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { /// Bar<i32> where struct Bar<T> { x: T, y: u32 } -> [i32, u32] /// Zed<i32> where enum Zed { A(T), B(u32) } -> [i32, u32] /// ``` - fn constituent_types_for_ty(&self, t: ty::Binder<Ty<'tcx>>) -> ty::Binder<Vec<Ty<'tcx>>> { + fn constituent_types_for_ty( + &self, + t: ty::Binder<'tcx, Ty<'tcx>>, + ) -> ty::Binder<'tcx, Vec<Ty<'tcx>>> { match *t.skip_binder().kind() { ty::Uint(_) | ty::Int(_) @@ -1746,7 +1749,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { cause: ObligationCause<'tcx>, recursion_depth: usize, trait_def_id: DefId, - types: ty::Binder<Vec<Ty<'tcx>>>, + types: ty::Binder<'tcx, Vec<Ty<'tcx>>>, ) -> Vec<PredicateObligation<'tcx>> { // Because the types were potentially derived from // higher-ranked obligations they may reference late-bound @@ -1767,7 +1770,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { .skip_binder() // binder moved -\ .iter() .flat_map(|ty| { - let ty: ty::Binder<Ty<'tcx>> = types.rebind(ty); // <----/ + let ty: ty::Binder<'tcx, Ty<'tcx>> = types.rebind(ty); // <----/ self.infcx.commit_unconditionally(|_| { let placeholder_ty = self.infcx.replace_bound_vars_with_placeholders(ty); @@ -1887,7 +1890,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // substitution if we find that any of the input types, when // simplified, do not match. - obligation.predicate.skip_binder().trait_ref.substs.iter().zip(impl_trait_ref.substs).any( + iter::zip(obligation.predicate.skip_binder().trait_ref.substs, impl_trait_ref.substs).any( |(obligation_arg, impl_arg)| { match (obligation_arg.unpack(), impl_arg.unpack()) { (GenericArgKind::Type(obligation_ty), GenericArgKind::Type(impl_ty)) => { diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs index 8888ea2c849..fd94f9f7998 100644 --- a/compiler/rustc_trait_selection/src/traits/util.rs +++ b/compiler/rustc_trait_selection/src/traits/util.rs @@ -328,7 +328,7 @@ pub fn closure_trait_ref_and_return_type( self_ty: Ty<'tcx>, sig: ty::PolyFnSig<'tcx>, tuple_arguments: TupleArgumentsFlag, -) -> ty::Binder<(ty::TraitRef<'tcx>, Ty<'tcx>)> { +) -> ty::Binder<'tcx, (ty::TraitRef<'tcx>, Ty<'tcx>)> { let arguments_tuple = match tuple_arguments { TupleArgumentsFlag::No => sig.skip_binder().inputs()[0], TupleArgumentsFlag::Yes => tcx.intern_tup(sig.skip_binder().inputs()), @@ -346,7 +346,7 @@ pub fn generator_trait_ref_and_outputs( fn_trait_def_id: DefId, self_ty: Ty<'tcx>, sig: ty::PolyGenSig<'tcx>, -) -> ty::Binder<(ty::TraitRef<'tcx>, Ty<'tcx>, Ty<'tcx>)> { +) -> ty::Binder<'tcx, (ty::TraitRef<'tcx>, Ty<'tcx>, Ty<'tcx>)> { debug_assert!(!self_ty.has_escaping_bound_vars()); let trait_ref = ty::TraitRef { def_id: fn_trait_def_id, diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index aee128dec7d..f592cf1cd24 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -692,11 +692,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { let predicates = predicates.instantiate(self.infcx.tcx, substs); debug_assert_eq!(predicates.predicates.len(), origins.len()); - predicates - .predicates - .into_iter() - .zip(predicates.spans.into_iter()) - .zip(origins.into_iter().rev()) + iter::zip(iter::zip(predicates.predicates, predicates.spans), origins.into_iter().rev()) .map(|((pred, span), origin_def_id)| { let cause = self.cause(traits::BindingObligation(origin_def_id, span)); traits::Obligation::with_depth(cause, self.recursion_depth, self.param_env, pred) @@ -708,7 +704,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { fn from_object_ty( &mut self, ty: Ty<'tcx>, - data: &'tcx ty::List<ty::Binder<ty::ExistentialPredicate<'tcx>>>, + data: &'tcx ty::List<ty::Binder<'tcx, ty::ExistentialPredicate<'tcx>>>, region: ty::Region<'tcx>, ) { // Imagine a type like this: @@ -771,7 +767,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { /// `infer::required_region_bounds`, see that for more information. pub fn object_region_bounds<'tcx>( tcx: TyCtxt<'tcx>, - existential_predicates: &'tcx ty::List<ty::Binder<ty::ExistentialPredicate<'tcx>>>, + existential_predicates: &'tcx ty::List<ty::Binder<'tcx, ty::ExistentialPredicate<'tcx>>>, ) -> Vec<ty::Region<'tcx>> { // Since we don't actually *know* the self type for an object, // this "open(err)" serves as a kind of dummy standin -- basically diff --git a/compiler/rustc_traits/src/chalk/db.rs b/compiler/rustc_traits/src/chalk/db.rs index 5c0cb2fb835..8c97e606c56 100644 --- a/compiler/rustc_traits/src/chalk/db.rs +++ b/compiler/rustc_traits/src/chalk/db.rs @@ -735,7 +735,10 @@ fn bound_vars_for_item(tcx: TyCtxt<'tcx>, def_id: DefId) -> SubstsRef<'tcx> { .into(), ty::GenericParamDefKind::Lifetime => { - let br = ty::BoundRegion { kind: ty::BrAnon(substs.len() as u32) }; + let br = ty::BoundRegion { + var: ty::BoundVar::from_usize(substs.len()), + kind: ty::BrAnon(substs.len() as u32), + }; tcx.mk_region(ty::RegionKind::ReLateBound(ty::INNERMOST, br)).into() } diff --git a/compiler/rustc_traits/src/chalk/lowering.rs b/compiler/rustc_traits/src/chalk/lowering.rs index fdf5f697e61..39890fd5b05 100644 --- a/compiler/rustc_traits/src/chalk/lowering.rs +++ b/compiler/rustc_traits/src/chalk/lowering.rs @@ -434,17 +434,11 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::Lifetime<RustInterner<'tcx>>> for Region<'t ReEarlyBound(_) => { panic!("Should have already been substituted."); } - ReLateBound(db, br) => match br.kind { - ty::BoundRegionKind::BrAnon(var) => { - chalk_ir::LifetimeData::BoundVar(chalk_ir::BoundVar::new( - chalk_ir::DebruijnIndex::new(db.as_u32()), - var as usize, - )) - .intern(interner) - } - ty::BoundRegionKind::BrNamed(_def_id, _name) => unimplemented!(), - ty::BrEnv => unimplemented!(), - }, + ReLateBound(db, br) => chalk_ir::LifetimeData::BoundVar(chalk_ir::BoundVar::new( + chalk_ir::DebruijnIndex::new(db.as_u32()), + br.var.as_usize(), + )) + .intern(interner), ReFree(_) => unimplemented!(), ReStatic => chalk_ir::LifetimeData::Static.intern(interner), ReVar(_) => unimplemented!(), @@ -467,7 +461,10 @@ impl<'tcx> LowerInto<'tcx, Region<'tcx>> for &chalk_ir::Lifetime<RustInterner<'t let kind = match self.data(interner) { chalk_ir::LifetimeData::BoundVar(var) => ty::RegionKind::ReLateBound( ty::DebruijnIndex::from_u32(var.debruijn.depth()), - ty::BoundRegion { kind: ty::BrAnon(var.index as u32) }, + ty::BoundRegion { + var: ty::BoundVar::from_usize(var.index), + kind: ty::BrAnon(var.index as u32), + }, ), chalk_ir::LifetimeData::InferenceVar(_var) => unimplemented!(), chalk_ir::LifetimeData::Placeholder(p) => { @@ -606,7 +603,7 @@ impl<'tcx> LowerInto<'tcx, Option<chalk_ir::QuantifiedWhereClause<RustInterner<' } impl<'tcx> LowerInto<'tcx, chalk_ir::Binders<chalk_ir::QuantifiedWhereClauses<RustInterner<'tcx>>>> - for &'tcx ty::List<ty::Binder<ty::ExistentialPredicate<'tcx>>> + for &'tcx ty::List<ty::Binder<'tcx, ty::ExistentialPredicate<'tcx>>> { fn lower_into( self, @@ -677,7 +674,9 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::Binders<chalk_ir::QuantifiedWhereClauses<Ru } } -impl<'tcx> LowerInto<'tcx, chalk_ir::FnSig<RustInterner<'tcx>>> for ty::Binder<ty::FnSig<'tcx>> { +impl<'tcx> LowerInto<'tcx, chalk_ir::FnSig<RustInterner<'tcx>>> + for ty::Binder<'tcx, ty::FnSig<'tcx>> +{ fn lower_into(self, _interner: &RustInterner<'_>) -> FnSig<RustInterner<'tcx>> { chalk_ir::FnSig { abi: self.abi(), @@ -801,7 +800,7 @@ impl<'tcx> LowerInto<'tcx, chalk_solve::rust_ir::AliasEqBound<RustInterner<'tcx> crate fn collect_bound_vars<'tcx, T: TypeFoldable<'tcx>>( interner: &RustInterner<'tcx>, tcx: TyCtxt<'tcx>, - ty: Binder<T>, + ty: Binder<'tcx, T>, ) -> (T, chalk_ir::VariableKinds<RustInterner<'tcx>>, BTreeMap<DefId, u32>) { let mut bound_vars_collector = BoundVarsCollector::new(); ty.as_ref().skip_binder().visit_with(&mut bound_vars_collector); @@ -849,7 +848,10 @@ impl<'tcx> BoundVarsCollector<'tcx> { } impl<'tcx> TypeVisitor<'tcx> for BoundVarsCollector<'tcx> { - fn visit_binder<T: TypeFoldable<'tcx>>(&mut self, t: &Binder<T>) -> ControlFlow<Self::BreakTy> { + fn visit_binder<T: TypeFoldable<'tcx>>( + &mut self, + t: &Binder<'tcx, T>, + ) -> ControlFlow<Self::BreakTy> { self.binder_index.shift_in(1); let result = t.super_visit_with(self); self.binder_index.shift_out(1); @@ -895,7 +897,7 @@ impl<'tcx> TypeVisitor<'tcx> for BoundVarsCollector<'tcx> { }, }, - ty::BrEnv => unimplemented!(), + ty::BoundRegionKind::BrEnv => unimplemented!(), }, ty::ReEarlyBound(_re) => { @@ -931,7 +933,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for NamedBoundVarSubstitutor<'a, 'tcx> { self.tcx } - fn fold_binder<T: TypeFoldable<'tcx>>(&mut self, t: Binder<T>) -> Binder<T> { + fn fold_binder<T: TypeFoldable<'tcx>>(&mut self, t: Binder<'tcx, T>) -> Binder<'tcx, T> { self.binder_index.shift_in(1); let result = t.super_fold_with(self); self.binder_index.shift_out(1); @@ -943,7 +945,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for NamedBoundVarSubstitutor<'a, 'tcx> { ty::ReLateBound(index, br) if *index == self.binder_index => match br.kind { ty::BrNamed(def_id, _name) => match self.named_parameters.get(&def_id) { Some(idx) => { - let new_br = ty::BoundRegion { kind: ty::BrAnon(*idx) }; + let new_br = ty::BoundRegion { var: br.var, kind: ty::BrAnon(*idx) }; return self.tcx.mk_region(RegionKind::ReLateBound(*index, new_br)); } None => panic!("Missing `BrNamed`."), @@ -987,7 +989,7 @@ impl<'tcx> TypeFolder<'tcx> for ParamsSubstitutor<'tcx> { self.tcx } - fn fold_binder<T: TypeFoldable<'tcx>>(&mut self, t: Binder<T>) -> Binder<T> { + fn fold_binder<T: TypeFoldable<'tcx>>(&mut self, t: Binder<'tcx, T>) -> Binder<'tcx, T> { self.binder_index.shift_in(1); let result = t.super_fold_with(self); self.binder_index.shift_out(1); @@ -1026,12 +1028,16 @@ impl<'tcx> TypeFolder<'tcx> for ParamsSubstitutor<'tcx> { // This covers any region variables in a goal, right? ty::ReEarlyBound(_re) => match self.named_regions.get(&_re.def_id) { Some(idx) => { - let br = ty::BoundRegion { kind: ty::BrAnon(*idx) }; + let br = ty::BoundRegion { + var: ty::BoundVar::from_u32(*idx), + kind: ty::BrAnon(*idx), + }; self.tcx.mk_region(RegionKind::ReLateBound(self.binder_index, br)) } None => { let idx = self.named_regions.len() as u32; - let br = ty::BoundRegion { kind: ty::BrAnon(idx) }; + let br = + ty::BoundRegion { var: ty::BoundVar::from_u32(idx), kind: ty::BrAnon(idx) }; self.named_regions.insert(_re.def_id, idx); self.tcx.mk_region(RegionKind::ReLateBound(self.binder_index, br)) } diff --git a/compiler/rustc_ty_utils/src/instance.rs b/compiler/rustc_ty_utils/src/instance.rs index 6b9d46ee0af..874289d0293 100644 --- a/compiler/rustc_ty_utils/src/instance.rs +++ b/compiler/rustc_ty_utils/src/instance.rs @@ -115,7 +115,7 @@ fn resolve_associated_item<'tcx>( ); let trait_ref = ty::TraitRef::from_method(tcx, trait_id, rcvr_substs); - let vtbl = tcx.codegen_fulfill_obligation((param_env, ty::Binder::bind(trait_ref)))?; + let vtbl = tcx.codegen_fulfill_obligation((param_env, ty::Binder::bind(trait_ref, tcx)))?; // Now that we know which impl is being used, we can dispatch to // the actual function: diff --git a/compiler/rustc_typeck/src/astconv/errors.rs b/compiler/rustc_typeck/src/astconv/errors.rs index b5404c3a15c..695132281c6 100644 --- a/compiler/rustc_typeck/src/astconv/errors.rs +++ b/compiler/rustc_typeck/src/astconv/errors.rs @@ -10,6 +10,7 @@ use rustc_span::symbol::{sym, Ident}; use rustc_span::{Span, DUMMY_SP}; use std::collections::BTreeSet; +use std::iter; impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { /// On missing type parameters, emit an E0393 error and provide a structured suggestion using @@ -309,7 +310,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // that the user forgot to give the associtated type's name. The canonical // example would be trying to use `Iterator<isize>` instead of // `Iterator<Item = isize>`. - for (potential, item) in potential_assoc_types.iter().zip(assoc_items.iter()) { + for (potential, item) in iter::zip(&potential_assoc_types, assoc_items) { if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(*potential) { suggestions.push((*potential, format!("{} = {}", item.ident, snippet))); } diff --git a/compiler/rustc_typeck/src/astconv/generics.rs b/compiler/rustc_typeck/src/astconv/generics.rs index 9625211109d..845375f3e32 100644 --- a/compiler/rustc_typeck/src/astconv/generics.rs +++ b/compiler/rustc_typeck/src/astconv/generics.rs @@ -166,7 +166,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { parent_substs: &[subst::GenericArg<'tcx>], has_self: bool, self_ty: Option<Ty<'tcx>>, - arg_count: GenericArgCountResult, + arg_count: &GenericArgCountResult, ctx: &mut impl CreateSubstsForGenericArgsCtxt<'a, 'tcx>, ) -> SubstsRef<'tcx> { // Collect the segments of the path; we need to substitute arguments diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs index dbc518da8c8..b6de491911a 100644 --- a/compiler/rustc_typeck/src/astconv/mod.rs +++ b/compiler/rustc_typeck/src/astconv/mod.rs @@ -210,14 +210,20 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let r = match tcx.named_region(lifetime.hir_id) { Some(rl::Region::Static) => tcx.lifetimes.re_static, - Some(rl::Region::LateBound(debruijn, id, _)) => { - let name = lifetime_name(id.expect_local()); - let br = ty::BoundRegion { kind: ty::BrNamed(id, name) }; + Some(rl::Region::LateBound(debruijn, index, def_id, _)) => { + let name = lifetime_name(def_id.expect_local()); + let br = ty::BoundRegion { + var: ty::BoundVar::from_u32(index), + kind: ty::BrNamed(def_id, name), + }; tcx.mk_region(ty::ReLateBound(debruijn, br)) } - Some(rl::Region::LateBoundAnon(debruijn, index)) => { - let br = ty::BoundRegion { kind: ty::BrAnon(index) }; + Some(rl::Region::LateBoundAnon(debruijn, index, anon_index)) => { + let br = ty::BoundRegion { + var: ty::BoundVar::from_u32(index), + kind: ty::BrAnon(anon_index), + }; tcx.mk_region(ty::ReLateBound(debruijn, br)) } @@ -266,7 +272,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { def_id: DefId, item_segment: &hir::PathSegment<'_>, ) -> SubstsRef<'tcx> { - let (substs, assoc_bindings, _) = self.create_substs_for_ast_path( + let (substs, _) = self.create_substs_for_ast_path( span, def_id, &[], @@ -275,6 +281,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { item_segment.infer_args, None, ); + let assoc_bindings = self.create_assoc_bindings_for_generic_args(item_segment.args()); if let Some(b) = assoc_bindings.first() { Self::prohibit_assoc_ty_binding(self.tcx(), b.span); @@ -314,6 +321,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { /// `[Vec<u8>, u8]` and `generic_args` are the arguments for the associated /// type itself: `['a]`. The returned `SubstsRef` concatenates these two /// lists: `[Vec<u8>, u8, 'a]`. + #[tracing::instrument(level = "debug", skip(self, span))] fn create_substs_for_ast_path<'a>( &self, span: Span, @@ -323,15 +331,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { generic_args: &'a hir::GenericArgs<'_>, infer_args: bool, self_ty: Option<Ty<'tcx>>, - ) -> (SubstsRef<'tcx>, Vec<ConvertedBinding<'a, 'tcx>>, GenericArgCountResult) { + ) -> (SubstsRef<'tcx>, GenericArgCountResult) { // If the type is parameterized by this region, then replace this // region with the current anon region binding (in other words, // whatever & would get replaced with). - debug!( - "create_substs_for_ast_path(def_id={:?}, self_ty={:?}, \ - generic_args={:?})", - def_id, self_ty, generic_args - ); let tcx = self.tcx(); let generics = tcx.generics_of(def_id); @@ -367,7 +370,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // here and so associated type bindings will be handled regardless of whether there are any // non-`Self` generic parameters. if generics.params.len() == 0 { - return (tcx.intern_substs(&[]), vec![], arg_count); + return (tcx.intern_substs(&[]), arg_count); } let is_object = self_ty.map_or(false, |ty| ty == self.tcx().types.trait_object_dummy_self); @@ -540,7 +543,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { parent_substs, self_ty.is_some(), self_ty, - arg_count.clone(), + &arg_count, &mut substs_ctx, ); @@ -551,6 +554,18 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { generic_args.args.is_empty(), ); + debug!( + "create_substs_for_ast_path(generic_params={:?}, self_ty={:?}) -> {:?}", + generics, self_ty, substs + ); + + (substs, arg_count) + } + + fn create_assoc_bindings_for_generic_args<'a>( + &self, + generic_args: &'a hir::GenericArgs<'_>, + ) -> Vec<ConvertedBinding<'a, 'tcx>> { // Convert associated-type bindings or constraints into a separate vector. // Example: Given this: // @@ -581,12 +596,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { }) .collect(); - debug!( - "create_substs_for_ast_path(generic_params={:?}, self_ty={:?}) -> {:?}", - generics, self_ty, substs - ); - - (substs, assoc_bindings, arg_count) + assoc_bindings } crate fn create_substs_for_associated_item( @@ -636,8 +646,27 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { ) } - /// The given trait-ref must actually be a trait. - pub(super) fn instantiate_poly_trait_ref_inner( + /// Given a trait bound like `Debug`, applies that trait bound the given self-type to construct + /// a full trait reference. The resulting trait reference is returned. This may also generate + /// auxiliary bounds, which are added to `bounds`. + /// + /// Example: + /// + /// ``` + /// poly_trait_ref = Iterator<Item = u32> + /// self_ty = Foo + /// ``` + /// + /// this would return `Foo: Iterator` and add `<Foo as Iterator>::Item = u32` into `bounds`. + /// + /// **A note on binders:** against our usual convention, there is an implied bounder around + /// the `self_ty` and `poly_trait_ref` parameters here. So they may reference bound regions. + /// If for example you had `for<'a> Foo<'a>: Bar<'a>`, then the `self_ty` would be `Foo<'a>` + /// where `'a` is a bound region at depth 0. Similarly, the `poly_trait_ref` would be + /// `Bar<'a>`. The returned poly-trait-ref will have this binder instantiated explicitly, + /// however. + #[tracing::instrument(level = "debug", skip(self, span, constness, bounds, speculative))] + pub fn instantiate_poly_trait_ref( &self, trait_ref: &hir::TraitRef<'_>, span: Span, @@ -648,18 +677,25 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { ) -> GenericArgCountResult { let trait_def_id = trait_ref.trait_def_id().unwrap_or_else(|| FatalError.raise()); - debug!("instantiate_poly_trait_ref({:?}, def_id={:?})", trait_ref, trait_def_id); - self.prohibit_generics(trait_ref.path.segments.split_last().unwrap().1); - let (substs, assoc_bindings, arg_count) = self.create_substs_for_ast_trait_ref( + let tcx = self.tcx(); + let bound_vars = tcx.late_bound_vars(trait_ref.hir_ref_id); + debug!(?bound_vars); + + let (substs, arg_count) = self.create_substs_for_ast_trait_ref( trait_ref.path.span, trait_def_id, self_ty, trait_ref.path.segments.last().unwrap(), ); - let poly_trait_ref = ty::Binder::bind(ty::TraitRef::new(trait_def_id, substs)); + let assoc_bindings = self + .create_assoc_bindings_for_generic_args(trait_ref.path.segments.last().unwrap().args()); + let poly_trait_ref = + ty::Binder::bind_with_vars(ty::TraitRef::new(trait_def_id, substs), bound_vars); + + debug!(?poly_trait_ref, ?assoc_bindings); bounds.trait_bounds.push((poly_trait_ref, span, constness)); let mut dup_bindings = FxHashMap::default(); @@ -677,50 +713,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // Okay to ignore `Err` because of `ErrorReported` (see above). } - debug!( - "instantiate_poly_trait_ref({:?}, bounds={:?}) -> {:?}", - trait_ref, bounds, poly_trait_ref - ); - arg_count } - /// Given a trait bound like `Debug`, applies that trait bound the given self-type to construct - /// a full trait reference. The resulting trait reference is returned. This may also generate - /// auxiliary bounds, which are added to `bounds`. - /// - /// Example: - /// - /// ``` - /// poly_trait_ref = Iterator<Item = u32> - /// self_ty = Foo - /// ``` - /// - /// this would return `Foo: Iterator` and add `<Foo as Iterator>::Item = u32` into `bounds`. - /// - /// **A note on binders:** against our usual convention, there is an implied bounder around - /// the `self_ty` and `poly_trait_ref` parameters here. So they may reference bound regions. - /// If for example you had `for<'a> Foo<'a>: Bar<'a>`, then the `self_ty` would be `Foo<'a>` - /// where `'a` is a bound region at depth 0. Similarly, the `poly_trait_ref` would be - /// `Bar<'a>`. The returned poly-trait-ref will have this binder instantiated explicitly, - /// however. - pub fn instantiate_poly_trait_ref( - &self, - poly_trait_ref: &hir::PolyTraitRef<'_>, - constness: Constness, - self_ty: Ty<'tcx>, - bounds: &mut Bounds<'tcx>, - ) -> GenericArgCountResult { - self.instantiate_poly_trait_ref_inner( - &poly_trait_ref.trait_ref, - poly_trait_ref.span, - constness, - self_ty, - bounds, - false, - ) - } - pub fn instantiate_lang_item_trait_ref( &self, lang_item: hir::LangItem, @@ -732,7 +727,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { ) { let trait_def_id = self.tcx().require_lang_item(lang_item, Some(span)); - let (substs, assoc_bindings, _) = self.create_substs_for_ast_path( + let (substs, _) = self.create_substs_for_ast_path( span, trait_def_id, &[], @@ -741,7 +736,11 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { false, Some(self_ty), ); - let poly_trait_ref = ty::Binder::bind(ty::TraitRef::new(trait_def_id, substs)); + let assoc_bindings = self.create_assoc_bindings_for_generic_args(args); + let tcx = self.tcx(); + let bound_vars = tcx.late_bound_vars(hir_id); + let poly_trait_ref = + ty::Binder::bind_with_vars(ty::TraitRef::new(trait_def_id, substs), bound_vars); bounds.trait_bounds.push((poly_trait_ref, span, Constness::NotConst)); let mut dup_bindings = FxHashMap::default(); @@ -765,23 +764,23 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { self_ty: Ty<'tcx>, trait_segment: &hir::PathSegment<'_>, ) -> ty::TraitRef<'tcx> { - let (substs, assoc_bindings, _) = + let (substs, _) = self.create_substs_for_ast_trait_ref(span, trait_def_id, self_ty, trait_segment); + let assoc_bindings = self.create_assoc_bindings_for_generic_args(trait_segment.args()); if let Some(b) = assoc_bindings.first() { Self::prohibit_assoc_ty_binding(self.tcx(), b.span); } ty::TraitRef::new(trait_def_id, substs) } + #[tracing::instrument(level = "debug", skip(self, span))] fn create_substs_for_ast_trait_ref<'a>( &self, span: Span, trait_def_id: DefId, self_ty: Ty<'tcx>, trait_segment: &'a hir::PathSegment<'a>, - ) -> (SubstsRef<'tcx>, Vec<ConvertedBinding<'a, 'tcx>>, GenericArgCountResult) { - debug!("create_substs_for_ast_trait_ref(trait_segment={:?})", trait_segment); - + ) -> (SubstsRef<'tcx>, GenericArgCountResult) { self.complain_about_internal_fn_trait(span, trait_def_id, trait_segment); self.create_substs_for_ast_path( @@ -803,7 +802,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { } // Returns `true` if a bounds list includes `?Sized`. - pub fn is_unsized(&self, ast_bounds: &[&hir::GenericBound<'_>], span: Span) -> bool { + pub fn is_unsized(&self, ast_bounds: &[hir::GenericBound<'_>], span: Span) -> bool { let tcx = self.tcx(); // Try to find an unbound in bounds. @@ -858,29 +857,46 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { /// **A note on binders:** there is an implied binder around /// `param_ty` and `ast_bounds`. See `instantiate_poly_trait_ref` /// for more details. + #[tracing::instrument(level = "debug", skip(self, bounds))] fn add_bounds( &self, param_ty: Ty<'tcx>, - ast_bounds: &[&hir::GenericBound<'_>], + ast_bounds: &[hir::GenericBound<'_>], bounds: &mut Bounds<'tcx>, + bound_vars: &'tcx ty::List<ty::BoundVariableKind>, ) { let constness = self.default_constness_for_trait_bounds(); for ast_bound in ast_bounds { match *ast_bound { hir::GenericBound::Trait(ref b, hir::TraitBoundModifier::None) => { - self.instantiate_poly_trait_ref(b, constness, param_ty, bounds); + self.instantiate_poly_trait_ref( + &b.trait_ref, + b.span, + constness, + param_ty, + bounds, + false, + ); } hir::GenericBound::Trait(ref b, hir::TraitBoundModifier::MaybeConst) => { - self.instantiate_poly_trait_ref(b, Constness::NotConst, param_ty, bounds); + self.instantiate_poly_trait_ref( + &b.trait_ref, + b.span, + Constness::NotConst, + param_ty, + bounds, + false, + ); } hir::GenericBound::Trait(_, hir::TraitBoundModifier::Maybe) => {} hir::GenericBound::LangItemTrait(lang_item, span, hir_id, args) => self .instantiate_lang_item_trait_ref( - *lang_item, *span, *hir_id, args, param_ty, bounds, + lang_item, span, hir_id, args, param_ty, bounds, ), - hir::GenericBound::Outlives(ref l) => bounds - .region_bounds - .push((ty::Binder::bind(self.ast_region_to_region(l, None)), l.span)), + hir::GenericBound::Outlives(ref l) => bounds.region_bounds.push(( + ty::Binder::bind_with_vars(self.ast_region_to_region(l, None), bound_vars), + l.span, + )), } } } @@ -908,7 +924,6 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { sized_by_default: SizedByDefault, span: Span, ) -> Bounds<'tcx> { - let ast_bounds: Vec<_> = ast_bounds.iter().collect(); self.compute_bounds_inner(param_ty, &ast_bounds, sized_by_default, span) } @@ -928,7 +943,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { if let Some(trait_ref) = ast_bound.trait_ref() { if let Some(trait_did) = trait_ref.trait_def_id() { if self.tcx().trait_may_define_assoc_type(trait_did, assoc_name) { - result.push(ast_bound); + result.push(ast_bound.clone()); } } } @@ -940,13 +955,13 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { fn compute_bounds_inner( &self, param_ty: Ty<'tcx>, - ast_bounds: &[&hir::GenericBound<'_>], + ast_bounds: &[hir::GenericBound<'_>], sized_by_default: SizedByDefault, span: Span, ) -> Bounds<'tcx> { let mut bounds = Bounds::default(); - self.add_bounds(param_ty, ast_bounds, &mut bounds); + self.add_bounds(param_ty, ast_bounds, &mut bounds, ty::List::empty()); bounds.implicitly_sized = if let SizedByDefault::Yes = sized_by_default { if !self.is_unsized(ast_bounds, span) { Some(span) } else { None } @@ -963,6 +978,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { /// **A note on binders:** given something like `T: for<'a> Iterator<Item = &'a u32>`, the /// `trait_ref` here will be `for<'a> T: Iterator`. The `binding` data however is from *inside* /// the binder (e.g., `&'a u32`) and hence may reference bound regions. + #[tracing::instrument( + level = "debug", + skip(self, bounds, speculative, dup_bindings, path_span) + )] fn add_predicates_for_ast_type_binding( &self, hir_ref_id: hir::HirId, @@ -989,7 +1008,6 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // // We want to produce `<B as SuperTrait<i32>>::T == foo`. - debug!(?hir_ref_id, ?trait_ref, ?binding, ?bounds, "add_predicates_for_ast_type_binding",); let tcx = self.tcx(); let candidate = @@ -1090,7 +1108,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let late_bound_in_trait_ref = tcx.collect_constrained_late_bound_regions(&projection_ty); let late_bound_in_ty = - tcx.collect_referenced_late_bound_regions(&ty::Binder::bind(ty)); + tcx.collect_referenced_late_bound_regions(&trait_ref.rebind(ty)); debug!("late_bound_in_trait_ref = {:?}", late_bound_in_trait_ref); debug!("late_bound_in_ty = {:?}", late_bound_in_ty); @@ -1139,10 +1157,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // // Calling `skip_binder` is okay, because `add_bounds` expects the `param_ty` // parameter to have a skipped binder. - let param_ty = - tcx.mk_projection(assoc_ty.def_id, projection_ty.skip_binder().substs); - let ast_bounds: Vec<_> = ast_bounds.iter().collect(); - self.add_bounds(param_ty, &ast_bounds, bounds); + let param_ty = tcx.mk_ty(ty::Projection(projection_ty.skip_binder())); + self.add_bounds(param_ty, ast_bounds, bounds, candidate.bound_vars()); } } Ok(()) @@ -1176,10 +1192,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { Err(GenericArgCountMismatch { invalid_args: cur_potential_assoc_types, .. }), .. } = self.instantiate_poly_trait_ref( - trait_bound, + &trait_bound.trait_ref, + trait_bound.span, Constness::NotConst, dummy_self, &mut bounds, + false, ) { potential_assoc_types.extend(cur_potential_assoc_types); } @@ -1664,7 +1682,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { }; self.one_bound_for_assoc_type( - || traits::supertraits(tcx, ty::Binder::bind(trait_ref)), + || traits::supertraits(tcx, ty::Binder::bind(trait_ref, tcx)), || "Self".to_string(), assoc_ident, span, @@ -2199,6 +2217,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { require_c_abi_if_c_variadic(tcx, &bf.decl, bf.abi, ast_ty.span); tcx.mk_fn_ptr(self.ty_of_fn( + ast_ty.hir_id, bf.unsafety, bf.abi, &bf.decl, @@ -2241,7 +2260,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { } hir::TyKind::Path(hir::QPath::LangItem(lang_item, span)) => { let def_id = tcx.require_lang_item(lang_item, Some(span)); - let (substs, _, _) = self.create_substs_for_ast_path( + let (substs, _) = self.create_substs_for_ast_path( span, def_id, &[], @@ -2278,7 +2297,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { result_ty } - pub fn impl_trait_ty_to_ty( + fn impl_trait_ty_to_ty( &self, def_id: DefId, lifetimes: &[hir::GenericArg<'_>], @@ -2339,6 +2358,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { pub fn ty_of_fn( &self, + hir_id: hir::HirId, unsafety: hir::Unsafety, abi: abi::Abi, decl: &hir::FnDecl<'_>, @@ -2349,6 +2369,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { debug!("ty_of_fn"); let tcx = self.tcx(); + let bound_vars = tcx.late_bound_vars(hir_id); + debug!(?bound_vars); // We proactively collect all the inferred type params to emit a single error per fn def. let mut visitor = PlaceholderHirTyCollector::default(); @@ -2368,8 +2390,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { debug!("ty_of_fn: output_ty={:?}", output_ty); - let bare_fn_ty = - ty::Binder::bind(tcx.mk_fn_sig(input_tys, output_ty, decl.c_variadic, unsafety, abi)); + let fn_ty = tcx.mk_fn_sig(input_tys, output_ty, decl.c_variadic, unsafety, abi); + let bare_fn_ty = ty::Binder::bind_with_vars(fn_ty, bound_vars); if !self.allow_ty_infer() { // We always collect the spans for placeholder types when evaluating `fn`s, but we @@ -2450,7 +2472,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { fn compute_object_lifetime_bound( &self, span: Span, - existential_predicates: &'tcx ty::List<ty::Binder<ty::ExistentialPredicate<'tcx>>>, + existential_predicates: &'tcx ty::List<ty::Binder<'tcx, ty::ExistentialPredicate<'tcx>>>, ) -> Option<ty::Region<'tcx>> // if None, use the default { let tcx = self.tcx(); diff --git a/compiler/rustc_typeck/src/bounds.rs b/compiler/rustc_typeck/src/bounds.rs index 7ba90ad8819..5d200640722 100644 --- a/compiler/rustc_typeck/src/bounds.rs +++ b/compiler/rustc_typeck/src/bounds.rs @@ -26,7 +26,7 @@ pub struct Bounds<'tcx> { /// A list of region bounds on the (implicit) self type. So if you /// had `T: 'a + 'b` this might would be a list `['a, 'b]` (but /// the `T` is not explicitly included). - pub region_bounds: Vec<(ty::Binder<ty::Region<'tcx>>, Span)>, + pub region_bounds: Vec<(ty::Binder<'tcx, ty::Region<'tcx>>, Span)>, /// A list of trait bounds. So if you had `T: Debug` this would be /// `T: Debug`. Note that the self-type is explicit here. @@ -57,7 +57,7 @@ impl<'tcx> Bounds<'tcx> { // If it could be sized, and is, add the `Sized` predicate. let sized_predicate = self.implicitly_sized.and_then(|span| { tcx.lang_items().sized_trait().map(|sized| { - let trait_ref = ty::Binder::bind(ty::TraitRef { + let trait_ref = ty::Binder::dummy(ty::TraitRef { def_id: sized, substs: tcx.mk_substs_trait(param_ty, &[]), }); diff --git a/compiler/rustc_typeck/src/check/callee.rs b/compiler/rustc_typeck/src/check/callee.rs index a29f5518009..b48102e0fc9 100644 --- a/compiler/rustc_typeck/src/check/callee.rs +++ b/compiler/rustc_typeck/src/check/callee.rs @@ -17,6 +17,7 @@ use rustc_span::symbol::{sym, Ident}; use rustc_span::Span; use rustc_target::spec::abi; use rustc_trait_selection::autoderef::Autoderef; +use std::iter; /// Checks that it is legal to call methods of the trait corresponding /// to `trait_id` (this only cares about the trait, not the specific @@ -539,7 +540,7 @@ impl<'a, 'tcx> DeferredCallResolution<'tcx> { debug!("attempt_resolution: method_callee={:?}", method_callee); for (method_arg_ty, self_arg_ty) in - method_sig.inputs().iter().skip(1).zip(self.fn_sig.inputs()) + iter::zip(method_sig.inputs().iter().skip(1), self.fn_sig.inputs()) { fcx.demand_eqtype(self.call_expr.span, &self_arg_ty, &method_arg_ty); } diff --git a/compiler/rustc_typeck/src/check/check.rs b/compiler/rustc_typeck/src/check/check.rs index e2fc1da5c78..892abb5a344 100644 --- a/compiler/rustc_typeck/src/check/check.rs +++ b/compiler/rustc_typeck/src/check/check.rs @@ -26,6 +26,7 @@ use rustc_trait_selection::opaque_types::InferCtxtExt as _; use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _; use rustc_trait_selection::traits::{self, ObligationCauseCode}; +use std::iter; use std::ops::ControlFlow; pub fn check_wf_new(tcx: TyCtxt<'_>) { @@ -1472,7 +1473,7 @@ fn check_enum<'tcx>( } let mut disr_vals: Vec<Discr<'tcx>> = Vec::with_capacity(vs.len()); - for ((_, discr), v) in def.discriminants(tcx).zip(vs) { + for ((_, discr), v) in iter::zip(def.discriminants(tcx), vs) { // Check for duplicate discriminant values if let Some(i) = disr_vals.iter().position(|&x| x.val == discr.val) { let variant_did = def.variants[VariantIdx::new(i)].def_id; diff --git a/compiler/rustc_typeck/src/check/closure.rs b/compiler/rustc_typeck/src/check/closure.rs index 431e6d70ff3..22d3dc6bdc0 100644 --- a/compiler/rustc_typeck/src/check/closure.rs +++ b/compiler/rustc_typeck/src/check/closure.rs @@ -69,7 +69,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let expr_def_id = self.tcx.hir().local_def_id(expr.hir_id); let ClosureSignatures { bound_sig, liberated_sig } = - self.sig_of_closure(expr_def_id.to_def_id(), decl, body, expected_sig); + self.sig_of_closure(expr.hir_id, expr_def_id.to_def_id(), decl, body, expected_sig); debug!("check_closure: ty_of_closure returns {:?}", liberated_sig); @@ -288,15 +288,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn sig_of_closure( &self, + hir_id: hir::HirId, expr_def_id: DefId, decl: &hir::FnDecl<'_>, body: &hir::Body<'_>, expected_sig: Option<ExpectedSig<'tcx>>, ) -> ClosureSignatures<'tcx> { if let Some(e) = expected_sig { - self.sig_of_closure_with_expectation(expr_def_id, decl, body, e) + self.sig_of_closure_with_expectation(hir_id, expr_def_id, decl, body, e) } else { - self.sig_of_closure_no_expectation(expr_def_id, decl, body) + self.sig_of_closure_no_expectation(hir_id, expr_def_id, decl, body) } } @@ -304,13 +305,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// types that the user gave into a signature. fn sig_of_closure_no_expectation( &self, + hir_id: hir::HirId, expr_def_id: DefId, decl: &hir::FnDecl<'_>, body: &hir::Body<'_>, ) -> ClosureSignatures<'tcx> { debug!("sig_of_closure_no_expectation()"); - let bound_sig = self.supplied_sig_of_closure(expr_def_id, decl, body); + let bound_sig = self.supplied_sig_of_closure(hir_id, expr_def_id, decl, body); self.closure_sigs(expr_def_id, body, bound_sig) } @@ -364,6 +366,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// regions with depth 1, which are bound then by the closure. fn sig_of_closure_with_expectation( &self, + hir_id: hir::HirId, expr_def_id: DefId, decl: &hir::FnDecl<'_>, body: &hir::Body<'_>, @@ -375,7 +378,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // expectation if things don't see to match up with what we // expect. if expected_sig.sig.c_variadic() != decl.c_variadic { - return self.sig_of_closure_no_expectation(expr_def_id, decl, body); + return self.sig_of_closure_no_expectation(hir_id, expr_def_id, decl, body); } else if expected_sig.sig.skip_binder().inputs_and_output.len() != decl.inputs.len() + 1 { return self.sig_of_closure_with_mismatched_number_of_arguments( expr_def_id, @@ -411,9 +414,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Along the way, it also writes out entries for types that the user // wrote into our typeck results, which are then later used by the privacy // check. - match self.check_supplied_sig_against_expectation(expr_def_id, decl, body, &closure_sigs) { + match self.check_supplied_sig_against_expectation( + hir_id, + expr_def_id, + decl, + body, + &closure_sigs, + ) { Ok(infer_ok) => self.register_infer_ok_obligations(infer_ok), - Err(_) => return self.sig_of_closure_no_expectation(expr_def_id, decl, body), + Err(_) => return self.sig_of_closure_no_expectation(hir_id, expr_def_id, decl, body), } closure_sigs @@ -460,6 +469,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// strategy. fn check_supplied_sig_against_expectation( &self, + hir_id: hir::HirId, expr_def_id: DefId, decl: &hir::FnDecl<'_>, body: &hir::Body<'_>, @@ -469,7 +479,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // // (See comment on `sig_of_closure_with_expectation` for the // meaning of these letters.) - let supplied_sig = self.supplied_sig_of_closure(expr_def_id, decl, body); + let supplied_sig = self.supplied_sig_of_closure(hir_id, expr_def_id, decl, body); debug!("check_supplied_sig_against_expectation: supplied_sig={:?}", supplied_sig); @@ -492,13 +502,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // The liberated version of this signature should be a subtype // of the liberated form of the expectation. - for ((hir_ty, &supplied_ty), expected_ty) in decl - .inputs - .iter() - .zip(supplied_sig.inputs().skip_binder()) // binder moved to (*) below - .zip(expected_sigs.liberated_sig.inputs()) - // `liberated_sig` is E'. - { + for ((hir_ty, &supplied_ty), expected_ty) in iter::zip( + iter::zip( + decl.inputs, + supplied_sig.inputs().skip_binder(), // binder moved to (*) below + ), + expected_sigs.liberated_sig.inputs(), // `liberated_sig` is E'. + ) { // Instantiate (this part of..) S to S', i.e., with fresh variables. let (supplied_ty, _) = self.infcx.replace_bound_vars_with_fresh_vars( hir_ty.span, @@ -534,6 +544,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Also, record this closure signature for later. fn supplied_sig_of_closure( &self, + hir_id: hir::HirId, expr_def_id: DefId, decl: &hir::FnDecl<'_>, body: &hir::Body<'_>, @@ -545,6 +556,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { decl, body.generator_kind, ); + let bound_vars = self.tcx.late_bound_vars(hir_id); + // First, convert the types that the user supplied (if any). let supplied_arguments = decl.inputs.iter().map(|a| astconv.ast_ty_to_ty(a)); let supplied_return = match decl.output { @@ -571,13 +584,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }, }; - let result = ty::Binder::bind(self.tcx.mk_fn_sig( - supplied_arguments, - supplied_return, - decl.c_variadic, - hir::Unsafety::Normal, - Abi::RustCall, - )); + let result = ty::Binder::bind_with_vars( + self.tcx.mk_fn_sig( + supplied_arguments, + supplied_return, + decl.c_variadic, + hir::Unsafety::Normal, + Abi::RustCall, + ), + bound_vars, + ); debug!("supplied_sig_of_closure: result={:?}", result); diff --git a/compiler/rustc_typeck/src/check/coercion.rs b/compiler/rustc_typeck/src/check/coercion.rs index 94aee87364a..68a923a55eb 100644 --- a/compiler/rustc_typeck/src/check/coercion.rs +++ b/compiler/rustc_typeck/src/check/coercion.rs @@ -1487,7 +1487,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { if let (Some((expr, _)), Some((fn_decl, _, _))) = (expression, fcx.get_node_fn_decl(parent_item)) { - fcx.suggest_missing_return_expr(&mut err, expr, fn_decl, expected, found); + fcx.suggest_missing_return_expr(&mut err, expr, fn_decl, expected, found, parent_id); } if let (Some(sp), Some(fn_output)) = (fcx.ret_coercion_span.get(), fn_output) { diff --git a/compiler/rustc_typeck/src/check/compare_method.rs b/compiler/rustc_typeck/src/check/compare_method.rs index ddb11b9f3b1..f044daa4509 100644 --- a/compiler/rustc_typeck/src/check/compare_method.rs +++ b/compiler/rustc_typeck/src/check/compare_method.rs @@ -14,6 +14,7 @@ use rustc_middle::ty::{GenericParamDefKind, ToPredicate, TyCtxt}; use rustc_span::Span; use rustc_trait_selection::traits::error_reporting::InferCtxtExt; use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode, Reveal}; +use std::iter; use super::{potentially_plural_count, FnCtxt, Inherited}; @@ -224,7 +225,7 @@ fn compare_predicate_entailment<'tcx>( let (impl_m_own_bounds, _) = infcx.replace_bound_vars_with_fresh_vars( impl_m_span, infer::HigherRankedType, - ty::Binder::bind(impl_m_own_bounds.predicates), + ty::Binder::bind(impl_m_own_bounds.predicates, tcx), ); for predicate in impl_m_own_bounds { let traits::Normalized { value: predicate, obligations } = @@ -257,14 +258,14 @@ fn compare_predicate_entailment<'tcx>( ); let impl_sig = inh.normalize_associated_types_in(impl_m_span, impl_m_hir_id, param_env, impl_sig); - let impl_fty = tcx.mk_fn_ptr(ty::Binder::bind(impl_sig)); + let impl_fty = tcx.mk_fn_ptr(ty::Binder::bind(impl_sig, tcx)); debug!("compare_impl_method: impl_fty={:?}", impl_fty); let trait_sig = tcx.liberate_late_bound_regions(impl_m.def_id, tcx.fn_sig(trait_m.def_id)); let trait_sig = trait_sig.subst(tcx, trait_to_placeholder_substs); let trait_sig = inh.normalize_associated_types_in(impl_m_span, impl_m_hir_id, param_env, trait_sig); - let trait_fty = tcx.mk_fn_ptr(ty::Binder::bind(trait_sig)); + let trait_fty = tcx.mk_fn_ptr(ty::Binder::bind(trait_sig, tcx)); debug!("compare_impl_method: trait_fty={:?}", trait_fty); @@ -410,8 +411,7 @@ fn extract_spans_for_error_reporting<'a, 'tcx>( _ => bug!("{:?} is not a TraitItemKind::Fn", trait_m), }; - impl_m_iter - .zip(trait_m_iter) + iter::zip(impl_m_iter, trait_m_iter) .find(|&(ref impl_arg, ref trait_arg)| { match (&impl_arg.kind, &trait_arg.kind) { ( @@ -443,11 +443,8 @@ fn extract_spans_for_error_reporting<'a, 'tcx>( let impl_iter = impl_sig.inputs().iter(); let trait_iter = trait_sig.inputs().iter(); - impl_iter - .zip(trait_iter) - .zip(impl_m_iter) - .zip(trait_m_iter) - .find_map(|(((&impl_arg_ty, &trait_arg_ty), impl_arg), trait_arg)| match infcx + iter::zip(iter::zip(impl_iter, trait_iter), iter::zip(impl_m_iter, trait_m_iter)) + .find_map(|((&impl_arg_ty, &trait_arg_ty), (impl_arg, trait_arg))| match infcx .at(&cause, param_env) .sub(trait_arg_ty, impl_arg_ty) { @@ -799,7 +796,7 @@ fn compare_synthetic_generics<'tcx>( GenericParamDefKind::Lifetime | GenericParamDefKind::Const { .. } => None, }); for ((impl_def_id, impl_synthetic), (trait_def_id, trait_synthetic)) in - impl_m_type_params.zip(trait_m_type_params) + iter::zip(impl_m_type_params, trait_m_type_params) { if impl_synthetic != trait_synthetic { let impl_hir_id = tcx.hir().local_def_id_to_hir_id(impl_def_id.expect_local()); diff --git a/compiler/rustc_typeck/src/check/dropck.rs b/compiler/rustc_typeck/src/check/dropck.rs index 4d74962d28e..de6336b254b 100644 --- a/compiler/rustc_typeck/src/check/dropck.rs +++ b/compiler/rustc_typeck/src/check/dropck.rs @@ -354,9 +354,9 @@ impl TypeRelation<'tcx> for SimpleEqRelation<'tcx> { fn binders<T>( &mut self, - a: ty::Binder<T>, - b: ty::Binder<T>, - ) -> RelateResult<'tcx, ty::Binder<T>> + a: ty::Binder<'tcx, T>, + b: ty::Binder<'tcx, T>, + ) -> RelateResult<'tcx, ty::Binder<'tcx, T>> where T: Relate<'tcx>, { diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs index 8951c08bd33..30d60514063 100644 --- a/compiler/rustc_typeck/src/check/expr.rs +++ b/compiler/rustc_typeck/src/check/expr.rs @@ -6,7 +6,7 @@ use crate::astconv::AstConv as _; use crate::check::cast; use crate::check::coercion::CoerceMany; use crate::check::fatally_break_rust; -use crate::check::method::{probe, MethodError, SelfSource}; +use crate::check::method::SelfSource; use crate::check::report_unexpected_variant_res; use crate::check::BreakableCtxt; use crate::check::Diverges; @@ -30,7 +30,6 @@ use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder, use rustc_hir as hir; use rustc_hir::def::{CtorKind, DefKind, Res}; use rustc_hir::def_id::DefId; -use rustc_hir::lang_items::LangItem; use rustc_hir::{ExprKind, QPath}; use rustc_infer::infer; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; @@ -461,7 +460,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.resolve_lang_item_path(lang_item, expr.span, expr.hir_id).1 } - fn check_expr_path(&self, qpath: &hir::QPath<'_>, expr: &'tcx hir::Expr<'tcx>) -> Ty<'tcx> { + fn check_expr_path( + &self, + qpath: &'tcx hir::QPath<'tcx>, + expr: &'tcx hir::Expr<'tcx>, + ) -> Ty<'tcx> { let tcx = self.tcx; let (res, opt_ty, segs) = self.resolve_ty_and_res_ufcs(qpath, expr.hir_id, expr.span); let ty = match res { @@ -947,7 +950,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } Err(error) => { if segment.ident.name != kw::Empty { - self.report_extended_method_error(segment, span, args, rcvr_t, error); + if let Some(mut err) = self.report_method_error( + span, + rcvr_t, + segment.ident, + SelfSource::MethodCall(&args[0]), + error, + Some(args), + ) { + err.emit(); + } } Err(()) } @@ -964,59 +976,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) } - fn report_extended_method_error( - &self, - segment: &hir::PathSegment<'_>, - span: Span, - args: &'tcx [hir::Expr<'tcx>], - rcvr_t: Ty<'tcx>, - error: MethodError<'tcx>, - ) { - let rcvr = &args[0]; - let try_alt_rcvr = |err: &mut DiagnosticBuilder<'_>, new_rcvr_t| { - if let Some(new_rcvr_t) = new_rcvr_t { - if let Ok(pick) = self.lookup_probe( - span, - segment.ident, - new_rcvr_t, - rcvr, - probe::ProbeScope::AllTraits, - ) { - debug!("try_alt_rcvr: pick candidate {:?}", pick); - // Make sure the method is defined for the *actual* receiver: - // we don't want to treat `Box<Self>` as a receiver if - // it only works because of an autoderef to `&self` - if pick.autoderefs == 0 { - err.span_label( - pick.item.ident.span, - &format!("the method is available for `{}` here", new_rcvr_t), - ); - } - } - } - }; - - if let Some(mut err) = self.report_method_error( - span, - rcvr_t, - segment.ident, - SelfSource::MethodCall(rcvr), - error, - Some(args), - ) { - if let ty::Adt(..) = rcvr_t.kind() { - // Try alternative arbitrary self types that could fulfill this call. - // FIXME: probe for all types that *could* be arbitrary self-types, not - // just this list. - try_alt_rcvr(&mut err, self.tcx.mk_lang_item(rcvr_t, LangItem::OwnedBox)); - try_alt_rcvr(&mut err, self.tcx.mk_lang_item(rcvr_t, LangItem::Pin)); - try_alt_rcvr(&mut err, self.tcx.mk_diagnostic_item(rcvr_t, sym::Arc)); - try_alt_rcvr(&mut err, self.tcx.mk_diagnostic_item(rcvr_t, sym::Rc)); - } - err.emit(); - } - } - fn check_expr_cast( &self, e: &'tcx hir::Expr<'tcx>, diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs index 56ff9293dd8..9ace4550421 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs @@ -42,6 +42,7 @@ use rustc_trait_selection::traits::{ }; use std::collections::hash_map::Entry; +use std::iter; use std::slice; impl<'a, 'tcx> FnCtxt<'a, 'tcx> { @@ -904,12 +905,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// 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>( + pub fn resolve_ty_and_res_ufcs( &self, - qpath: &'b QPath<'b>, + qpath: &'tcx QPath<'tcx>, hir_id: hir::HirId, span: Span, - ) -> (Res, Option<Ty<'tcx>>, &'b [hir::PathSegment<'b>]) { + ) -> (Res, Option<Ty<'tcx>>, &'tcx [hir::PathSegment<'tcx>]) { 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) => { @@ -1146,7 +1147,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ( hir::ItemKind::OpaqueTy(hir::OpaqueTy { bounds: last_bounds, .. }), hir::ItemKind::OpaqueTy(hir::OpaqueTy { bounds: exp_bounds, .. }), - ) if last_bounds.iter().zip(exp_bounds.iter()).all(|(left, right)| { + ) if iter::zip(*last_bounds, *exp_bounds).all(|(left, right)| { match (left, right) { ( hir::GenericBound::Trait(tl, ml), @@ -1461,7 +1462,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &[][..], has_self, self_ty, - arg_count, + &arg_count, &mut CreateCtorSubstsContext { fcx: self, span, diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs index c92c7f7ad0b..80b5a9d4e62 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs @@ -23,6 +23,7 @@ use rustc_span::{self, MultiSpan, Span}; use rustc_trait_selection::traits::{self, ObligationCauseCode, StatementAsExpression}; use crate::structured_errors::StructuredDiagnostic; +use std::iter; use std::slice; impl<'a, 'tcx> FnCtxt<'a, 'tcx> { @@ -108,7 +109,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // 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()) { + for (&fn_input_ty, arg_expr) in iter::zip(fn_inputs, args) { self.register_wf_obligation(fn_input_ty.into(), arg_expr.span, traits::MiscObligation); } diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs index f90159efb5c..6112a5fdc91 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs @@ -55,7 +55,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { 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); - self.suggest_missing_return_expr(err, expr, &fn_decl, expected, found); + let fn_id = self.tcx.hir().get_return_block(blk_id).unwrap(); + self.suggest_missing_return_expr(err, expr, &fn_decl, expected, found, fn_id); } pointing_at_return_type } @@ -218,8 +219,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { 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()) + let mut suggestions = iter::zip(iter::repeat(&expr_text), &methods) .filter_map(|(receiver, method)| { let method_call = format!(".{}()", method.ident); if receiver.ends_with(&method_call) { @@ -480,6 +480,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn_decl: &hir::FnDecl<'_>, expected: Ty<'tcx>, found: Ty<'tcx>, + id: hir::HirId, ) { if !expected.is_unit() { return; @@ -487,7 +488,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let found = self.resolve_vars_with_obligations(found); if let hir::FnRetTy::Return(ty) = fn_decl.output { let ty = <dyn AstConv<'_>>::ast_ty_to_ty(self, ty); - let ty = self.tcx.erase_late_bound_regions(Binder::bind(ty)); + let bound_vars = self.tcx.late_bound_vars(id); + let ty = self.tcx.erase_late_bound_regions(Binder::bind_with_vars(ty, bound_vars)); let ty = self.normalize_associated_types_in(expr.span, ty); if self.can_coerce(found, ty) { err.multipart_suggestion( diff --git a/compiler/rustc_typeck/src/check/generator_interior.rs b/compiler/rustc_typeck/src/check/generator_interior.rs index 91708465b3f..e40aa914858 100644 --- a/compiler/rustc_typeck/src/check/generator_interior.rs +++ b/compiler/rustc_typeck/src/check/generator_interior.rs @@ -186,7 +186,10 @@ pub fn resolve_interior<'a, 'tcx>( // which means that none of the regions inside relate to any other, even if // typeck had previously found constraints that would cause them to be related. let folded = fcx.tcx.fold_regions(erased, &mut false, |_, current_depth| { - let br = ty::BoundRegion { kind: ty::BrAnon(counter) }; + let br = ty::BoundRegion { + var: ty::BoundVar::from_u32(counter), + kind: ty::BrAnon(counter), + }; let r = fcx.tcx.mk_region(ty::ReLateBound(current_depth, br)); counter += 1; r @@ -202,11 +205,15 @@ pub fn resolve_interior<'a, 'tcx>( // Extract type components to build the witness type. let type_list = fcx.tcx.mk_type_list(type_causes.iter().map(|cause| cause.ty)); - let witness = fcx.tcx.mk_generator_witness(ty::Binder::bind(type_list)); + let bound_vars = fcx.tcx.mk_bound_variable_kinds( + (0..counter).map(|i| ty::BoundVariableKind::Region(ty::BrAnon(i))), + ); + let witness = + fcx.tcx.mk_generator_witness(ty::Binder::bind_with_vars(type_list, bound_vars.clone())); // Store the generator types and spans into the typeck results for this generator. visitor.fcx.inh.typeck_results.borrow_mut().generator_interior_types = - ty::Binder::bind(type_causes); + ty::Binder::bind_with_vars(type_causes, bound_vars); debug!( "types in generator after region replacement {:?}, span = {:?}", diff --git a/compiler/rustc_typeck/src/check/intrinsic.rs b/compiler/rustc_typeck/src/check/intrinsic.rs index 990ed5abdbf..303a77507cf 100644 --- a/compiler/rustc_typeck/src/check/intrinsic.rs +++ b/compiler/rustc_typeck/src/check/intrinsic.rs @@ -101,12 +101,21 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) { let intrinsic_name = tcx.item_name(it.def_id.to_def_id()); let name_str = intrinsic_name.as_str(); + let bound_vars = tcx.mk_bound_variable_kinds( + [ty::BoundVariableKind::Region(ty::BrAnon(0)), ty::BoundVariableKind::Region(ty::BrEnv)] + .iter() + .copied(), + ); let mk_va_list_ty = |mutbl| { tcx.lang_items().va_list().map(|did| { - let region = tcx - .mk_region(ty::ReLateBound(ty::INNERMOST, ty::BoundRegion { kind: ty::BrAnon(0) })); - let env_region = - tcx.mk_region(ty::ReLateBound(ty::INNERMOST, ty::BoundRegion { kind: ty::BrEnv })); + let region = tcx.mk_region(ty::ReLateBound( + ty::INNERMOST, + ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind: ty::BrAnon(0) }, + )); + let env_region = tcx.mk_region(ty::ReLateBound( + ty::INNERMOST, + ty::BoundRegion { var: ty::BoundVar::from_u32(1), kind: ty::BrEnv }, + )); let va_list_ty = tcx.type_of(did).subst(tcx, &[region.into()]); (tcx.mk_ref(env_region, ty::TypeAndMut { ty: va_list_ty, mutbl }), va_list_ty) }) @@ -305,7 +314,7 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) { tcx.associated_items(tcx.lang_items().discriminant_kind_trait().unwrap()); let discriminant_def_id = assoc_items.in_definition_order().next().unwrap().def_id; - let br = ty::BoundRegion { kind: ty::BrAnon(0) }; + let br = ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind: ty::BrAnon(0) }; ( 1, vec![ @@ -366,7 +375,7 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) { (n_tps, inputs, output, unsafety) }; let sig = tcx.mk_fn_sig(inputs.into_iter(), output, false, unsafety, Abi::RustIntrinsic); - let sig = ty::Binder::bind(sig); + let sig = ty::Binder::bind_with_vars(sig, bound_vars); equate_intrinsic_type(tcx, it, n_tps, sig) } diff --git a/compiler/rustc_typeck/src/check/method/confirm.rs b/compiler/rustc_typeck/src/check/method/confirm.rs index 731a72ff024..f546a0d8963 100644 --- a/compiler/rustc_typeck/src/check/method/confirm.rs +++ b/compiler/rustc_typeck/src/check/method/confirm.rs @@ -15,6 +15,7 @@ use rustc_middle::ty::{self, GenericParamDefKind, Ty}; use rustc_span::Span; use rustc_trait_selection::traits; +use std::iter; use std::ops::Deref; struct ConfirmContext<'a, 'tcx> { @@ -118,7 +119,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { // We won't add these if we encountered an illegal sized bound, so that we can use // a custom error in that case. if illegal_sized_bound.is_none() { - let method_ty = self.tcx.mk_fn_ptr(ty::Binder::bind(method_sig)); + let method_ty = self.tcx.mk_fn_ptr(ty::Binder::bind(method_sig, self.tcx)); self.add_obligations(method_ty, all_substs, method_predicates); } @@ -380,7 +381,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { parent_substs, false, None, - arg_count_correct, + &arg_count_correct, &mut MethodSubstsCtxt { cfcx: self, pick, seg }, ) } @@ -496,10 +497,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { // We don't care about regions here. .filter_map(|obligation| match obligation.predicate.kind().skip_binder() { ty::PredicateKind::Trait(trait_pred, _) if trait_pred.def_id() == sized_def_id => { - let span = predicates - .predicates - .iter() - .zip(predicates.spans.iter()) + let span = iter::zip(&predicates.predicates, &predicates.spans) .find_map( |(p, span)| { if *p == obligation.predicate { Some(*span) } else { None } @@ -552,7 +550,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { upcast_trait_refs.into_iter().next().unwrap() } - fn replace_bound_vars_with_fresh_vars<T>(&self, value: ty::Binder<T>) -> T + fn replace_bound_vars_with_fresh_vars<T>(&self, value: ty::Binder<'tcx, T>) -> T where T: TypeFoldable<'tcx>, { diff --git a/compiler/rustc_typeck/src/check/method/mod.rs b/compiler/rustc_typeck/src/check/method/mod.rs index d6fa6bf0067..bd7ffd057b4 100644 --- a/compiler/rustc_typeck/src/check/method/mod.rs +++ b/compiler/rustc_typeck/src/check/method/mod.rs @@ -45,6 +45,7 @@ pub struct MethodCallee<'tcx> { pub sig: ty::FnSig<'tcx>, } +#[derive(Debug)] pub enum MethodError<'tcx> { // Did not find an applicable method, but we did find various near-misses that may work. NoMatch(NoMatchData<'tcx>), @@ -66,6 +67,7 @@ pub enum MethodError<'tcx> { // Contains a list of static methods that may apply, a list of unsatisfied trait predicates which // could lead to matches if satisfied, and a list of not-in-scope traits which may work. +#[derive(Debug)] pub struct NoMatchData<'tcx> { pub static_candidates: Vec<CandidateSource>, pub unsatisfied_predicates: Vec<(ty::Predicate<'tcx>, Option<ty::Predicate<'tcx>>)>, @@ -397,7 +399,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { obligations.extend(traits::predicates_for_generics(cause.clone(), self.param_env, bounds)); // Also add an obligation for the method type being well-formed. - let method_ty = tcx.mk_fn_ptr(ty::Binder::bind(fn_sig)); + let method_ty = tcx.mk_fn_ptr(ty::Binder::bind(fn_sig, tcx)); debug!( "lookup_in_trait_adjusted: matched method method_ty={:?} obligation={:?}", method_ty, obligation diff --git a/compiler/rustc_typeck/src/check/method/probe.rs b/compiler/rustc_typeck/src/check/method/probe.rs index 0742549f890..bfaf36e702f 100644 --- a/compiler/rustc_typeck/src/check/method/probe.rs +++ b/compiler/rustc_typeck/src/check/method/probe.rs @@ -1753,7 +1753,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { /// region got replaced with the same variable, which requires a bit more coordination /// and/or tracking the substitution and /// so forth. - fn erase_late_bound_regions<T>(&self, value: ty::Binder<T>) -> T + fn erase_late_bound_regions<T>(&self, value: ty::Binder<'tcx, T>) -> T where T: TypeFoldable<'tcx>, { diff --git a/compiler/rustc_typeck/src/check/method/suggest.rs b/compiler/rustc_typeck/src/check/method/suggest.rs index 13757ac4132..72eff009473 100644 --- a/compiler/rustc_typeck/src/check/method/suggest.rs +++ b/compiler/rustc_typeck/src/check/method/suggest.rs @@ -68,12 +68,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - pub fn report_method_error<'b>( + pub fn report_method_error( &self, span: Span, rcvr_ty: Ty<'tcx>, item_name: Ident, - source: SelfSource<'b>, + source: SelfSource<'tcx>, error: MethodError<'tcx>, args: Option<&'tcx [hir::Expr<'tcx>]>, ) -> Option<DiagnosticBuilder<'_>> { @@ -323,8 +323,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { err.span_suggestion( lit.span, &format!( - "you must specify a concrete type for \ - this numeric value, like `{}`", + "you must specify a concrete type for this numeric value, \ + like `{}`", concrete_type ), format!("{}_{}", snippet, concrete_type), @@ -975,17 +975,78 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - fn suggest_traits_to_import<'b>( + fn suggest_traits_to_import( &self, err: &mut DiagnosticBuilder<'_>, span: Span, rcvr_ty: Ty<'tcx>, item_name: Ident, - source: SelfSource<'b>, + source: SelfSource<'tcx>, valid_out_of_scope_traits: Vec<DefId>, unsatisfied_predicates: &[(ty::Predicate<'tcx>, Option<ty::Predicate<'tcx>>)], ) { - if self.suggest_valid_traits(err, valid_out_of_scope_traits) { + let mut alt_rcvr_sugg = false; + if let SelfSource::MethodCall(rcvr) = source { + info!(?span, ?item_name, ?rcvr_ty, ?rcvr); + if let ty::Adt(..) = rcvr_ty.kind() { + // Try alternative arbitrary self types that could fulfill this call. + // FIXME: probe for all types that *could* be arbitrary self-types, not + // just this list. + for (rcvr_ty, post) in &[ + (rcvr_ty, ""), + (self.tcx.mk_mut_ref(&ty::ReErased, rcvr_ty), "&mut "), + (self.tcx.mk_imm_ref(&ty::ReErased, rcvr_ty), "&"), + ] { + for (rcvr_ty, pre) in &[ + (self.tcx.mk_lang_item(rcvr_ty, LangItem::OwnedBox), "Box::new"), + (self.tcx.mk_lang_item(rcvr_ty, LangItem::Pin), "Pin::new"), + (self.tcx.mk_diagnostic_item(rcvr_ty, sym::Arc), "Arc::new"), + (self.tcx.mk_diagnostic_item(rcvr_ty, sym::Rc), "Rc::new"), + ] { + if let Some(new_rcvr_t) = *rcvr_ty { + if let Ok(pick) = self.lookup_probe( + span, + item_name, + new_rcvr_t, + rcvr, + crate::check::method::probe::ProbeScope::AllTraits, + ) { + debug!("try_alt_rcvr: pick candidate {:?}", pick); + // Make sure the method is defined for the *actual* receiver: + // we don't want to treat `Box<Self>` as a receiver if + // it only works because of an autoderef to `&self` + if pick.autoderefs == 0 + // We don't want to suggest a container type when the missing method is + // `.clone()`, otherwise we'd suggest `Arc::new(foo).clone()`, which is + // far from what the user really wants. + && Some(pick.item.container.id()) != self.tcx.lang_items().clone_trait() + { + err.span_label( + pick.item.ident.span, + &format!( + "the method is available for `{}` here", + new_rcvr_t + ), + ); + err.multipart_suggestion( + "consider wrapping the receiver expression with the \ + appropriate type", + vec![ + (rcvr.span.shrink_to_lo(), format!("{}({}", pre, post)), + (rcvr.span.shrink_to_hi(), ")".to_string()), + ], + Applicability::MaybeIncorrect, + ); + // We don't care about the other suggestions. + alt_rcvr_sugg = true; + } + } + } + } + } + } + } + if !alt_rcvr_sugg && self.suggest_valid_traits(err, valid_out_of_scope_traits) { return; } @@ -1075,6 +1136,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { "the method might not be found because of this arbitrary self type", ); } + if alt_rcvr_sugg { + return; + } if !candidates.is_empty() { // Sort from most relevant to least relevant. @@ -1284,7 +1348,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Checks whether there is a local type somewhere in the chain of /// autoderefs of `rcvr_ty`. - fn type_derefs_to_local(&self, span: Span, rcvr_ty: Ty<'tcx>, source: SelfSource<'_>) -> bool { + fn type_derefs_to_local( + &self, + span: Span, + rcvr_ty: Ty<'tcx>, + source: SelfSource<'tcx>, + ) -> bool { fn is_local(ty: Ty<'_>) -> bool { match ty.kind() { ty::Adt(def, _) => def.did.is_local(), @@ -1310,7 +1379,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } -#[derive(Copy, Clone)] +#[derive(Copy, Clone, Debug)] pub enum SelfSource<'a> { QPath(&'a hir::Ty<'a>), MethodCall(&'a hir::Expr<'a> /* rcvr */), diff --git a/compiler/rustc_typeck/src/check/mod.rs b/compiler/rustc_typeck/src/check/mod.rs index ad9bb703779..0760d59875c 100644 --- a/compiler/rustc_typeck/src/check/mod.rs +++ b/compiler/rustc_typeck/src/check/mod.rs @@ -497,6 +497,7 @@ fn typeck_with_fallback<'tcx>( let fcx = FnCtxt::new(&inh, param_env, body.value.hir_id); <dyn AstConv<'_>>::ty_of_fn( &fcx, + id, header.unsafety, header.abi, decl, diff --git a/compiler/rustc_typeck/src/check/pat.rs b/compiler/rustc_typeck/src/check/pat.rs index 79c544bd386..53593b9bab4 100644 --- a/compiler/rustc_typeck/src/check/pat.rs +++ b/compiler/rustc_typeck/src/check/pat.rs @@ -861,7 +861,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn check_pat_tuple_struct( &self, pat: &'tcx Pat<'tcx>, - qpath: &hir::QPath<'_>, + qpath: &'tcx hir::QPath<'tcx>, subpats: &'tcx [&'tcx Pat<'tcx>], ddpos: Option<usize>, expected: Ty<'tcx>, diff --git a/compiler/rustc_typeck/src/check/upvar.rs b/compiler/rustc_typeck/src/check/upvar.rs index 5a939cc24f5..91021b3f6f5 100644 --- a/compiler/rustc_typeck/src/check/upvar.rs +++ b/compiler/rustc_typeck/src/check/upvar.rs @@ -49,6 +49,8 @@ use rustc_span::{MultiSpan, Span, Symbol}; use rustc_index::vec::Idx; use rustc_target::abi::VariantIdx; +use std::iter; + /// Describe the relationship between the paths of two places /// eg: /// - `foo` is ancestor of `foo.bar.baz` @@ -1631,7 +1633,7 @@ fn determine_place_ancestry_relation( let projections_b = &place_b.projections; let same_initial_projections = - projections_a.iter().zip(projections_b.iter()).all(|(proj_a, proj_b)| proj_a == proj_b); + iter::zip(projections_a, projections_b).all(|(proj_a, proj_b)| proj_a == proj_b); if same_initial_projections { // First min(n, m) projections are the same diff --git a/compiler/rustc_typeck/src/check/wfcheck.rs b/compiler/rustc_typeck/src/check/wfcheck.rs index 5f302f7d0a9..887cc42a1dd 100644 --- a/compiler/rustc_typeck/src/check/wfcheck.rs +++ b/compiler/rustc_typeck/src/check/wfcheck.rs @@ -24,6 +24,7 @@ use rustc_trait_selection::opaque_types::may_define_opaque_type; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode}; +use std::iter; use std::ops::ControlFlow; /// Helper type of a temporary returned by `.for_item(...)`. @@ -863,7 +864,7 @@ fn check_where_clauses<'tcx, 'fcx>( debug!("check_where_clauses: predicates={:?}", predicates.predicates); assert_eq!(predicates.predicates.len(), predicates.spans.len()); let wf_obligations = - predicates.predicates.iter().zip(predicates.spans.iter()).flat_map(|(&p, &sp)| { + iter::zip(&predicates.predicates, &predicates.spans).flat_map(|(&p, &sp)| { traits::wf::predicate_obligations(fcx, fcx.param_env, fcx.body_id, p, sp) }); @@ -885,8 +886,8 @@ fn check_fn_or_method<'fcx, 'tcx>( let sig = fcx.normalize_associated_types_in(span, sig); let sig = fcx.tcx.liberate_late_bound_regions(def_id, sig); - for (&input_ty, span) in sig.inputs().iter().zip(hir_decl.inputs.iter().map(|t| t.span)) { - fcx.register_wf_obligation(input_ty.into(), span, ObligationCauseCode::MiscObligation); + for (&input_ty, ty) in iter::zip(sig.inputs(), hir_decl.inputs) { + fcx.register_wf_obligation(input_ty.into(), ty.span, ObligationCauseCode::MiscObligation); } implied_bounds.extend(sig.inputs()); @@ -1066,13 +1067,14 @@ fn check_method_receiver<'fcx, 'tcx>( debug!("check_method_receiver: sig={:?}", sig); let self_ty = fcx.normalize_associated_types_in(span, self_ty); - let self_ty = fcx.tcx.liberate_late_bound_regions(method.def_id, ty::Binder::bind(self_ty)); + let self_ty = + fcx.tcx.liberate_late_bound_regions(method.def_id, ty::Binder::bind(self_ty, fcx.tcx)); let receiver_ty = sig.inputs()[0]; let receiver_ty = fcx.normalize_associated_types_in(span, receiver_ty); let receiver_ty = - fcx.tcx.liberate_late_bound_regions(method.def_id, ty::Binder::bind(receiver_ty)); + fcx.tcx.liberate_late_bound_regions(method.def_id, ty::Binder::bind(receiver_ty, fcx.tcx)); if fcx.tcx.features().arbitrary_self_types { if !receiver_is_valid(fcx, span, receiver_ty, self_ty, true) { diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index 631f2c7a69a..afe52c97733 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -50,6 +50,7 @@ use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{Span, DUMMY_SP}; use rustc_target::spec::abi; use rustc_trait_selection::traits::error_reporting::suggestions::NextTypeParamName; +use std::iter; mod item_bounds; mod type_of; @@ -1243,7 +1244,8 @@ fn has_late_bound_regions<'tcx>(tcx: TyCtxt<'tcx>, node: Node<'tcx>) -> Option<S match self.tcx.named_region(lt.hir_id) { Some(rl::Region::Static | rl::Region::EarlyBound(..)) => {} Some( - rl::Region::LateBound(debruijn, _, _) | rl::Region::LateBoundAnon(debruijn, _), + rl::Region::LateBound(debruijn, _, _, _) + | rl::Region::LateBoundAnon(debruijn, _, _), ) if debruijn < self.outer_index => {} Some( rl::Region::LateBound(..) @@ -1706,10 +1708,11 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: DefId) -> ty::PolyFnSig<'_> { } diag.emit(); - ty::Binder::bind(fn_sig) + ty::Binder::bind(fn_sig, tcx) } None => <dyn AstConv<'_>>::ty_of_fn( &icx, + hir_id, sig.header.unsafety, sig.header.abi, &sig.decl, @@ -1727,6 +1730,7 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: DefId) -> ty::PolyFnSig<'_> { .. }) => <dyn AstConv<'_>>::ty_of_fn( &icx, + hir_id, header.unsafety, header.abi, decl, @@ -1748,13 +1752,10 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: DefId) -> ty::PolyFnSig<'_> { let ty = tcx.type_of(tcx.hir().get_parent_did(hir_id).to_def_id()); let inputs = data.fields().iter().map(|f| tcx.type_of(tcx.hir().local_def_id(f.hir_id))); - ty::Binder::bind(tcx.mk_fn_sig( - inputs, - ty, - false, - hir::Unsafety::Normal, - abi::Abi::Rust, - )) + ty::Binder::bind( + tcx.mk_fn_sig(inputs, ty, false, hir::Unsafety::Normal, abi::Abi::Rust), + tcx, + ) } Expr(&hir::Expr { kind: hir::ExprKind::Closure(..), .. }) => { @@ -2038,7 +2039,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP param.bounds.iter().for_each(|bound| match bound { hir::GenericBound::Outlives(lt) => { let bound = <dyn AstConv<'_>>::ast_region_to_region(&icx, <, None); - let outlives = ty::Binder::bind(ty::OutlivesPredicate(region, bound)); + let outlives = ty::Binder::bind(ty::OutlivesPredicate(region, bound), tcx); predicates.insert((outlives.to_predicate(tcx), lt.span)); } _ => bug!(), @@ -2083,6 +2084,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP match predicate { hir::WherePredicate::BoundPredicate(bound_pred) => { let ty = icx.to_ty(&bound_pred.bounded_ty); + let bound_vars = icx.tcx.late_bound_vars(bound_pred.bounded_ty.hir_id); // Keep the type around in a dummy predicate, in case of no bounds. // That way, `where Ty:` is not a complete noop (see #53696) and `Ty` @@ -2098,9 +2100,13 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP } else { let span = bound_pred.bounded_ty.span; let re_root_empty = tcx.lifetimes.re_root_empty; - let predicate = ty::Binder::bind(ty::PredicateKind::TypeOutlives( - ty::OutlivesPredicate(ty, re_root_empty), - )); + let predicate = ty::Binder::bind_with_vars( + ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate( + ty, + re_root_empty, + )), + bound_vars, + ); predicates.insert((predicate.to_predicate(tcx), span)); } } @@ -2117,10 +2123,12 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP let mut bounds = Bounds::default(); let _ = <dyn AstConv<'_>>::instantiate_poly_trait_ref( &icx, - &poly_trait_ref, + &poly_trait_ref.trait_ref, + poly_trait_ref.span, constness, ty, &mut bounds, + false, ); predicates.extend(bounds.predicates(tcx, ty)); } @@ -2143,9 +2151,12 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP let region = <dyn AstConv<'_>>::ast_region_to_region(&icx, lifetime, None); predicates.insert(( - ty::Binder::bind(ty::PredicateKind::TypeOutlives( - ty::OutlivesPredicate(ty, region), - )) + ty::Binder::bind_with_vars( + ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate( + ty, region, + )), + bound_vars, + ) .to_predicate(tcx), lifetime.span, )); @@ -2367,7 +2378,14 @@ fn predicates_from_bound<'tcx>( }; let mut bounds = Bounds::default(); - let _ = astconv.instantiate_poly_trait_ref(tr, constness, param_ty, &mut bounds); + let _ = astconv.instantiate_poly_trait_ref( + &tr.trait_ref, + tr.span, + constness, + param_ty, + &mut bounds, + false, + ); bounds.predicates(astconv.tcx(), param_ty) } hir::GenericBound::LangItemTrait(lang_item, span, hir_id, args) => { @@ -2403,8 +2421,10 @@ fn compute_sig_of_foreign_fn_decl<'tcx>( } else { hir::Unsafety::Unsafe }; + let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local()); let fty = <dyn AstConv<'_>>::ty_of_fn( &ItemCtxt::new(tcx, def_id), + hir_id, unsafety, abi, decl, @@ -2439,7 +2459,7 @@ fn compute_sig_of_foreign_fn_decl<'tcx>( .emit(); } }; - for (input, ty) in decl.inputs.iter().zip(fty.inputs().skip_binder()) { + for (input, ty) in iter::zip(decl.inputs, fty.inputs().skip_binder()) { check(&input, ty) } if let hir::FnRetTy::Return(ref ty) = decl.output { @@ -2889,17 +2909,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs { .emit(); InlineAttr::None } else if list_contains_name(&items[..], sym::always) { - if tcx.sess.instrument_coverage() { - // Fixes Issue #82875. Forced inlining allows LLVM to discard functions - // marked with `#[inline(always)]`, which can break coverage reporting if - // that function was referenced from a coverage map. - // - // FIXME(#83429): Is there a better place, e.g., in codegen, to check and - // convert `Always` to `Hint`? - InlineAttr::Hint - } else { - InlineAttr::Always - } + InlineAttr::Always } else if list_contains_name(&items[..], sym::never) { InlineAttr::Never } else { diff --git a/compiler/rustc_typeck/src/expr_use_visitor.rs b/compiler/rustc_typeck/src/expr_use_visitor.rs index b172cb9c44b..ab286bacd81 100644 --- a/compiler/rustc_typeck/src/expr_use_visitor.rs +++ b/compiler/rustc_typeck/src/expr_use_visitor.rs @@ -18,6 +18,7 @@ use rustc_middle::hir::place::ProjectionKind; use rustc_middle::mir::FakeReadCause; use rustc_middle::ty::{self, adjustment, TyCtxt}; use rustc_target::abi::VariantIdx; +use std::iter; use crate::mem_categorization as mc; @@ -333,7 +334,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { } hir::ExprKind::LlvmInlineAsm(ref ia) => { - for (o, output) in ia.inner.outputs.iter().zip(ia.outputs_exprs) { + for (o, output) in iter::zip(&ia.inner.outputs, ia.outputs_exprs) { if o.is_indirect { self.consume_expr(output); } else { diff --git a/compiler/rustc_typeck/src/lib.rs b/compiler/rustc_typeck/src/lib.rs index c270a236811..190744fe6f1 100644 --- a/compiler/rustc_typeck/src/lib.rs +++ b/compiler/rustc_typeck/src/lib.rs @@ -63,6 +63,7 @@ This API is completely unstable and subject to change. #![feature(format_args_capture)] #![feature(in_band_lifetimes)] #![feature(is_sorted)] +#![feature(iter_zip)] #![feature(nll)] #![cfg_attr(bootstrap, feature(or_patterns))] #![feature(try_blocks)] @@ -429,7 +430,7 @@ pub fn hir_ty_to_ty<'tcx>(tcx: TyCtxt<'tcx>, hir_ty: &hir::Ty<'_>) -> Ty<'tcx> { let env_node_id = tcx.hir().get_parent_item(hir_ty.hir_id); let env_def_id = tcx.hir().local_def_id(env_node_id); let item_cx = self::collect::ItemCtxt::new(tcx, env_def_id.to_def_id()); - item_cx.to_ty(hir_ty) + <dyn AstConv<'_>>::ast_ty_to_ty(&item_cx, hir_ty) } pub fn hir_trait_to_predicates<'tcx>( @@ -444,7 +445,7 @@ pub fn hir_trait_to_predicates<'tcx>( let env_def_id = tcx.hir().local_def_id(env_hir_id); let item_cx = self::collect::ItemCtxt::new(tcx, env_def_id.to_def_id()); let mut bounds = Bounds::default(); - let _ = <dyn AstConv<'_>>::instantiate_poly_trait_ref_inner( + let _ = <dyn AstConv<'_>>::instantiate_poly_trait_ref( &item_cx, hir_trait, DUMMY_SP, |
