From ad6432c8ef9e27a37bdb440f8deba0e3e36a58f8 Mon Sep 17 00:00:00 2001 From: klensy Date: Tue, 23 Jan 2024 11:12:24 +0300 Subject: [PATCH 01/56] compiletest: reduce useless regex rebuilds before: ==8812== Total: 2,374,977,159 bytes in 6,840,026 blocks ==8812== At t-gmax: 8,090,486 bytes in 3,389 blocks ==8812== At t-end: 3,185,454 bytes in 757 blocks ==8812== Reads: 1,873,472,286 bytes ==8812== Writes: 1,249,411,589 bytes ==11212== I refs: 6,370,244,180 after: ==18725== Total: 429,769,246 bytes in 957,259 blocks ==18725== At t-gmax: 8,058,316 bytes in 3,502 blocks ==18725== At t-end: 3,045,261 bytes in 1,097 blocks ==18725== Reads: 431,872,599 bytes ==18725== Writes: 214,738,653 bytes ==20839== I refs: 1,873,010,089 --- src/tools/compiletest/src/runtest.rs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 8be4def15de..ca7efea07ca 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -4315,10 +4315,11 @@ impl<'test> TestCx<'test> { let mut seen_allocs = indexmap::IndexSet::new(); // The alloc-id appears in pretty-printed allocations. - let re = + static ALLOC_ID_PP_RE: Lazy = Lazy::new(|| { Regex::new(r"╾─*a(lloc)?([0-9]+)(\+0x[0-9]+)?()?( \([0-9]+ ptr bytes\))?─*╼") - .unwrap(); - normalized = re + .unwrap() + }); + normalized = ALLOC_ID_PP_RE .replace_all(&normalized, |caps: &Captures<'_>| { // Renumber the captured index. let index = caps.get(2).unwrap().as_str().to_string(); @@ -4331,8 +4332,9 @@ impl<'test> TestCx<'test> { .into_owned(); // The alloc-id appears in a sentence. - let re = Regex::new(r"\balloc([0-9]+)\b").unwrap(); - normalized = re + static ALLOC_ID_RE: Lazy = + Lazy::new(|| Regex::new(r"\balloc([0-9]+)\b").unwrap()); + normalized = ALLOC_ID_RE .replace_all(&normalized, |caps: &Captures<'_>| { let index = caps.get(1).unwrap().as_str().to_string(); let (index, _) = seen_allocs.insert_full(index); From e78d6859f7001b859bf7bacdc87c8da31f2f89e4 Mon Sep 17 00:00:00 2001 From: klensy Date: Tue, 23 Jan 2024 11:46:19 +0300 Subject: [PATCH 02/56] reduce bufreader size from default(8kb) to 1kb Headers WAY less than 1kb anyway, so this can be improved more? before ==18725== Total: 429,769,246 bytes in 957,259 blocks ==18725== At t-gmax: 8,058,316 bytes in 3,502 blocks ==18725== At t-end: 3,045,261 bytes in 1,097 blocks ==18725== Reads: 431,872,599 bytes ==18725== Writes: 214,738,653 bytes after ==49344== Total: 201,418,575 bytes in 957,174 blocks ==49344== At t-gmax: 7,937,250 bytes in 3,310 blocks ==49344== At t-end: 3,035,637 bytes in 1,076 blocks ==49344== Reads: 431,607,448 bytes ==49344== Writes: 210,731,540 bytes --- src/tools/compiletest/src/header.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index e70e01e8757..7c65e37119d 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -650,7 +650,7 @@ fn iter_header_extra( let comment = if testfile.extension().is_some_and(|e| e == "rs") { "//" } else { "#" }; - let mut rdr = BufReader::new(rdr); + let mut rdr = BufReader::with_capacity(1024, rdr); let mut ln = String::new(); let mut line_number = 0; From 0710ebb999dd633bd536e66fcaab3d2a4b1739e8 Mon Sep 17 00:00:00 2001 From: klensy Date: Tue, 23 Jan 2024 19:36:07 +0300 Subject: [PATCH 03/56] don't collect found paths into BTreeSet: keeping order of inserted Paths having high cost on hot path, collect into HashSet instead and sort afterward. from 1,858,963,938 to 1,448,975,825 I refs. --- src/tools/compiletest/src/lib.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/tools/compiletest/src/lib.rs b/src/tools/compiletest/src/lib.rs index 60dd15841b7..543304694f6 100644 --- a/src/tools/compiletest/src/lib.rs +++ b/src/tools/compiletest/src/lib.rs @@ -25,7 +25,7 @@ use build_helper::git::{get_git_modified_files, get_git_untracked_files}; use core::panic; use getopts::Options; use lazycell::AtomicLazyCell; -use std::collections::BTreeSet; +use std::collections::HashSet; use std::ffi::OsString; use std::fs; use std::io::{self, ErrorKind}; @@ -415,7 +415,7 @@ pub fn run_tests(config: Arc) { let mut tests = Vec::new(); for c in configs { - let mut found_paths = BTreeSet::new(); + let mut found_paths = HashSet::new(); make_tests(c, &mut tests, &mut found_paths); check_overlapping_tests(&found_paths); } @@ -550,7 +550,7 @@ pub fn test_opts(config: &Config) -> test::TestOpts { pub fn make_tests( config: Arc, tests: &mut Vec, - found_paths: &mut BTreeSet, + found_paths: &mut HashSet, ) { debug!("making tests from {:?}", config.src_base.display()); let inputs = common_inputs_stamp(&config); @@ -646,7 +646,7 @@ fn collect_tests_from_dir( relative_dir_path: &Path, inputs: &Stamp, tests: &mut Vec, - found_paths: &mut BTreeSet, + found_paths: &mut HashSet, modified_tests: &Vec, poisoned: &mut bool, ) -> io::Result<()> { @@ -1128,7 +1128,7 @@ fn not_a_digit(c: char) -> bool { !c.is_digit(10) } -fn check_overlapping_tests(found_paths: &BTreeSet) { +fn check_overlapping_tests(found_paths: &HashSet) { let mut collisions = Vec::new(); for path in found_paths { for ancestor in path.ancestors().skip(1) { @@ -1138,6 +1138,7 @@ fn check_overlapping_tests(found_paths: &BTreeSet) { } } if !collisions.is_empty() { + collisions.sort(); let collisions: String = collisions .into_iter() .map(|(path, check_parent)| format!("test {path:?} clashes with {check_parent:?}\n")) From bcfdf3307bcc0246dbe6ac709ed695a0a809c2ea Mon Sep 17 00:00:00 2001 From: klensy Date: Wed, 24 Jan 2024 14:58:59 +0300 Subject: [PATCH 04/56] add fixme about walking tests tree --- src/tools/compiletest/src/lib.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/tools/compiletest/src/lib.rs b/src/tools/compiletest/src/lib.rs index 543304694f6..667358b1a6e 100644 --- a/src/tools/compiletest/src/lib.rs +++ b/src/tools/compiletest/src/lib.rs @@ -675,6 +675,8 @@ fn collect_tests_from_dir( // Add each `.rs` file as a test, and recurse further on any // subdirectories we find, except for `aux` directories. + // FIXME: this walks full tests tree, even if we have something to ignore + // use walkdir/ignore like in tidy? for file in fs::read_dir(dir)? { let file = file?; let file_path = file.path(); From cb3ce6645f09929d2e9419aa0a45134db87ab991 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Wed, 24 Jan 2024 23:08:36 +0100 Subject: [PATCH 05/56] Move usefulness-specific pattern computations to `usefulness` --- compiler/rustc_pattern_analysis/src/pat.rs | 39 ++++++------------- .../rustc_pattern_analysis/src/usefulness.rs | 37 +++++++++++++++--- 2 files changed, 42 insertions(+), 34 deletions(-) diff --git a/compiler/rustc_pattern_analysis/src/pat.rs b/compiler/rustc_pattern_analysis/src/pat.rs index 9bde23c7bf1..2314da7149b 100644 --- a/compiler/rustc_pattern_analysis/src/pat.rs +++ b/compiler/rustc_pattern_analysis/src/pat.rs @@ -29,7 +29,7 @@ pub struct DeconstructedPat { /// correspond to a user-supplied pattern. data: Option, /// Whether removing this arm would change the behavior of the match expression. - useful: Cell, + pub(crate) useful: Cell, } impl DeconstructedPat { @@ -112,34 +112,17 @@ impl DeconstructedPat { pub(crate) fn set_useful(&self) { self.useful.set(true) } - pub(crate) fn is_useful(&self) -> bool { - if self.useful.get() { - true - } else if self.is_or_pat() && self.iter_fields().any(|f| f.is_useful()) { - // We always expand or patterns in the matrix, so we will never see the actual - // or-pattern (the one with constructor `Or`) in the column. As such, it will not be - // marked as useful itself, only its children will. We recover this information here. - self.set_useful(); - true - } else { - false - } - } - /// Report the subpatterns that were not useful, if any. - pub(crate) fn redundant_subpatterns(&self) -> Vec<&Self> { - let mut subpats = Vec::new(); - self.collect_redundant_subpatterns(&mut subpats); - subpats - } - fn collect_redundant_subpatterns<'a>(&'a self, subpats: &mut Vec<&'a Self>) { - // We don't look at subpatterns if we already reported the whole pattern as redundant. - if !self.is_useful() { - subpats.push(self); - } else { - for p in self.iter_fields() { - p.collect_redundant_subpatterns(subpats); - } + /// Walk top-down and call `it` in each place where a pattern occurs + /// starting with the root pattern `walk` is called on. If `it` returns + /// false then we will descend no further but siblings will be processed. + pub fn walk<'a>(&'a self, it: &mut impl FnMut(&'a Self) -> bool) { + if !it(self) { + return; + } + + for p in self.iter_fields() { + p.walk(it) } } } diff --git a/compiler/rustc_pattern_analysis/src/usefulness.rs b/compiler/rustc_pattern_analysis/src/usefulness.rs index 576005b2c7f..219d774513d 100644 --- a/compiler/rustc_pattern_analysis/src/usefulness.rs +++ b/compiler/rustc_pattern_analysis/src/usefulness.rs @@ -1599,6 +1599,36 @@ pub enum Usefulness<'p, Cx: TypeCx> { Redundant, } +/// Report whether this pattern was found useful, and its subpatterns that were not useful if any. +fn collect_pattern_usefulness<'p, Cx: TypeCx>(pat: &'p DeconstructedPat) -> Usefulness<'p, Cx> { + fn pat_is_useful<'p, Cx: TypeCx>(pat: &'p DeconstructedPat) -> bool { + if pat.useful.get() { + true + } else if pat.is_or_pat() && pat.iter_fields().any(|f| pat_is_useful(f)) { + // We always expand or patterns in the matrix, so we will never see the actual + // or-pattern (the one with constructor `Or`) in the column. As such, it will not be + // marked as useful itself, only its children will. We recover this information here. + true + } else { + false + } + } + + let mut redundant_subpats = Vec::new(); + pat.walk(&mut |p| { + if pat_is_useful(p) { + // The pattern is useful, so we recurse to find redundant subpatterns. + true + } else { + // The pattern is redundant. + redundant_subpats.push(p); + false // stop recursing + } + }); + + if pat_is_useful(pat) { Usefulness::Useful(redundant_subpats) } else { Usefulness::Redundant } +} + /// The output of checking a match for exhaustiveness and arm usefulness. pub struct UsefulnessReport<'p, Cx: TypeCx> { /// For each arm of the input, whether that arm is useful after the arms above it. @@ -1626,12 +1656,7 @@ pub fn compute_match_usefulness<'p, Cx: TypeCx>( .copied() .map(|arm| { debug!(?arm); - // We warn when a pattern is not useful. - let usefulness = if arm.pat.is_useful() { - Usefulness::Useful(arm.pat.redundant_subpatterns()) - } else { - Usefulness::Redundant - }; + let usefulness = collect_pattern_usefulness(arm.pat); (arm, usefulness) }) .collect(); From 9715df3f4459a0e0f68eec64c75a5d5e626ed673 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Wed, 7 Feb 2024 04:26:54 +0100 Subject: [PATCH 06/56] Track redundant subpatterns without interior mutability --- .../rustc_pattern_analysis/src/usefulness.rs | 76 ++++++++++++++----- 1 file changed, 55 insertions(+), 21 deletions(-) diff --git a/compiler/rustc_pattern_analysis/src/usefulness.rs b/compiler/rustc_pattern_analysis/src/usefulness.rs index 219d774513d..092e752e977 100644 --- a/compiler/rustc_pattern_analysis/src/usefulness.rs +++ b/compiler/rustc_pattern_analysis/src/usefulness.rs @@ -713,9 +713,11 @@ //! I (Nadrieril) prefer to put new tests in `ui/pattern/usefulness` unless there's a specific //! reason not to, for example if they crucially depend on a particular feature like `or_patterns`. +use rustc_hash::FxHashSet; use rustc_index::bit_set::BitSet; use smallvec::{smallvec, SmallVec}; use std::fmt; +use std::ops::Deref; use crate::constructor::{Constructor, ConstructorSet, IntRange}; use crate::pat::{DeconstructedPat, PatOrWild, WitnessPat}; @@ -730,18 +732,37 @@ pub fn ensure_sufficient_stack(f: impl FnOnce() -> R) -> R { f() } -/// Context that provides information for usefulness checking. -pub struct UsefulnessCtxt<'a, Cx: TypeCx> { - /// The context for type information. - pub tycx: &'a Cx, -} +/// Wrapper type for by-address hashing. Comparison and hashing of the wrapped pointer type will be +/// based on the address of its contents, rather than their value. +struct ByAddress(T); -impl<'a, Cx: TypeCx> Copy for UsefulnessCtxt<'a, Cx> {} -impl<'a, Cx: TypeCx> Clone for UsefulnessCtxt<'a, Cx> { - fn clone(&self) -> Self { - Self { tycx: self.tycx } +impl ByAddress { + fn addr(&self) -> *const T::Target { + (&*self.0) as *const _ } } +/// Raw pointer hashing and comparison. +impl std::hash::Hash for ByAddress { + fn hash(&self, state: &mut H) { + self.addr().hash(state) + } +} +impl PartialEq for ByAddress { + fn eq(&self, other: &Self) -> bool { + std::ptr::eq(self.addr(), other.addr()) + } +} +impl Eq for ByAddress {} + +/// Context that provides information for usefulness checking. +struct UsefulnessCtxt<'a, 'p, Cx: TypeCx> { + /// The context for type information. + tycx: &'a Cx, + /// Collect the patterns found useful during usefulness checking. This is used to lint + /// unreachable (sub)patterns. We distinguish patterns by their address to avoid needing to + /// inspect the contents. They'll all be distinct anyway since they carry a `Span`. + useful_subpatterns: FxHashSet>>, +} /// Context that provides information local to a place under investigation. struct PlaceCtxt<'a, Cx: TypeCx> { @@ -1381,7 +1402,7 @@ impl WitnessMatrix { /// We can however get false negatives because exhaustiveness does not explore all cases. See the /// section on relevancy at the top of the file. fn collect_overlapping_range_endpoints<'p, Cx: TypeCx>( - mcx: UsefulnessCtxt<'_, Cx>, + mcx: &mut UsefulnessCtxt<'_, 'p, Cx>, overlap_range: IntRange, matrix: &Matrix<'p, Cx>, specialized_matrix: &Matrix<'p, Cx>, @@ -1454,7 +1475,7 @@ fn collect_overlapping_range_endpoints<'p, Cx: TypeCx>( /// This is all explained at the top of the file. #[instrument(level = "debug", skip(mcx), ret)] fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: TypeCx>( - mcx: UsefulnessCtxt<'a, Cx>, + mcx: &mut UsefulnessCtxt<'a, 'p, Cx>, matrix: &mut Matrix<'p, Cx>, ) -> Result, Cx::Error> { debug_assert!(matrix.rows().all(|r| r.len() == matrix.column_count())); @@ -1580,7 +1601,9 @@ fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: TypeCx>( // Record usefulness in the patterns. for row in matrix.rows() { if row.useful { - row.head().set_useful(); + if let PatOrWild::Pat(pat) = row.head() { + mcx.useful_subpatterns.insert(ByAddress(pat)); + } } } @@ -1600,11 +1623,18 @@ pub enum Usefulness<'p, Cx: TypeCx> { } /// Report whether this pattern was found useful, and its subpatterns that were not useful if any. -fn collect_pattern_usefulness<'p, Cx: TypeCx>(pat: &'p DeconstructedPat) -> Usefulness<'p, Cx> { - fn pat_is_useful<'p, Cx: TypeCx>(pat: &'p DeconstructedPat) -> bool { - if pat.useful.get() { +fn collect_pattern_usefulness<'p, Cx: TypeCx>( + useful_subpatterns: &FxHashSet>>, + pat: &'p DeconstructedPat, +) -> Usefulness<'p, Cx> { + fn pat_is_useful<'p, Cx: TypeCx>( + useful_subpatterns: &FxHashSet>>, + pat: &'p DeconstructedPat, + ) -> bool { + if useful_subpatterns.contains(&ByAddress(pat)) { true - } else if pat.is_or_pat() && pat.iter_fields().any(|f| pat_is_useful(f)) { + } else if pat.is_or_pat() && pat.iter_fields().any(|f| pat_is_useful(useful_subpatterns, f)) + { // We always expand or patterns in the matrix, so we will never see the actual // or-pattern (the one with constructor `Or`) in the column. As such, it will not be // marked as useful itself, only its children will. We recover this information here. @@ -1616,7 +1646,7 @@ fn collect_pattern_usefulness<'p, Cx: TypeCx>(pat: &'p DeconstructedPat) -> let mut redundant_subpats = Vec::new(); pat.walk(&mut |p| { - if pat_is_useful(p) { + if pat_is_useful(useful_subpatterns, p) { // The pattern is useful, so we recurse to find redundant subpatterns. true } else { @@ -1626,7 +1656,11 @@ fn collect_pattern_usefulness<'p, Cx: TypeCx>(pat: &'p DeconstructedPat) -> } }); - if pat_is_useful(pat) { Usefulness::Useful(redundant_subpats) } else { Usefulness::Redundant } + if pat_is_useful(useful_subpatterns, pat) { + Usefulness::Useful(redundant_subpats) + } else { + Usefulness::Redundant + } } /// The output of checking a match for exhaustiveness and arm usefulness. @@ -1646,9 +1680,9 @@ pub fn compute_match_usefulness<'p, Cx: TypeCx>( scrut_ty: Cx::Ty, scrut_validity: ValidityConstraint, ) -> Result, Cx::Error> { - let cx = UsefulnessCtxt { tycx }; + let mut cx = UsefulnessCtxt { tycx, useful_subpatterns: FxHashSet::default() }; let mut matrix = Matrix::new(arms, scrut_ty, scrut_validity); - let non_exhaustiveness_witnesses = compute_exhaustiveness_and_usefulness(cx, &mut matrix)?; + let non_exhaustiveness_witnesses = compute_exhaustiveness_and_usefulness(&mut cx, &mut matrix)?; let non_exhaustiveness_witnesses: Vec<_> = non_exhaustiveness_witnesses.single_column(); let arm_usefulness: Vec<_> = arms @@ -1656,7 +1690,7 @@ pub fn compute_match_usefulness<'p, Cx: TypeCx>( .copied() .map(|arm| { debug!(?arm); - let usefulness = collect_pattern_usefulness(arm.pat); + let usefulness = collect_pattern_usefulness(&cx.useful_subpatterns, arm.pat); (arm, usefulness) }) .collect(); From 8465c82b64501a70d3f9ae967987473efb4f151c Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Wed, 24 Jan 2024 23:23:14 +0100 Subject: [PATCH 07/56] Cleanup comments and dead code --- compiler/rustc_pattern_analysis/src/pat.rs | 32 +++---------------- .../rustc_pattern_analysis/src/usefulness.rs | 14 +++----- 2 files changed, 9 insertions(+), 37 deletions(-) diff --git a/compiler/rustc_pattern_analysis/src/pat.rs b/compiler/rustc_pattern_analysis/src/pat.rs index 2314da7149b..04a77faad74 100644 --- a/compiler/rustc_pattern_analysis/src/pat.rs +++ b/compiler/rustc_pattern_analysis/src/pat.rs @@ -1,6 +1,5 @@ //! As explained in [`crate::usefulness`], values and patterns are made from constructors applied to //! fields. This file defines types that represent patterns in this way. -use std::cell::Cell; use std::fmt; use smallvec::{smallvec, SmallVec}; @@ -11,11 +10,8 @@ use crate::TypeCx; use self::Constructor::*; /// Values and patterns can be represented as a constructor applied to some fields. This represents -/// a pattern in this form. -/// This also uses interior mutability to keep track of whether the pattern has been found reachable -/// during analysis. For this reason they cannot be cloned. -/// A `DeconstructedPat` will almost always come from user input; the only exception are some -/// `Wildcard`s introduced during specialization. +/// a pattern in this form. A `DeconstructedPat` will almost always come from user input; the only +/// exception are some `Wildcard`s introduced during pattern lowering. /// /// Note that the number of fields may not match the fields declared in the original struct/variant. /// This happens if a private or `non_exhaustive` field is uninhabited, because the code mustn't @@ -28,19 +24,11 @@ pub struct DeconstructedPat { /// Extra data to store in a pattern. `None` if the pattern is a wildcard that does not /// correspond to a user-supplied pattern. data: Option, - /// Whether removing this arm would change the behavior of the match expression. - pub(crate) useful: Cell, } impl DeconstructedPat { pub fn wildcard(ty: Cx::Ty) -> Self { - DeconstructedPat { - ctor: Wildcard, - fields: Vec::new(), - ty, - data: None, - useful: Cell::new(false), - } + DeconstructedPat { ctor: Wildcard, fields: Vec::new(), ty, data: None } } pub fn new( @@ -49,7 +37,7 @@ impl DeconstructedPat { ty: Cx::Ty, data: Cx::PatData, ) -> Self { - DeconstructedPat { ctor, fields, ty, data: Some(data), useful: Cell::new(false) } + DeconstructedPat { ctor, fields, ty, data: Some(data) } } pub(crate) fn is_or_pat(&self) -> bool { @@ -107,12 +95,6 @@ impl DeconstructedPat { } } - /// We keep track for each pattern if it was ever useful during the analysis. This is used with - /// `redundant_subpatterns` to report redundant subpatterns arising from or patterns. - pub(crate) fn set_useful(&self) { - self.useful.set(true) - } - /// Walk top-down and call `it` in each place where a pattern occurs /// starting with the root pattern `walk` is called on. If `it` returns /// false then we will descend no further but siblings will be processed. @@ -267,12 +249,6 @@ impl<'p, Cx: TypeCx> PatOrWild<'p, Cx> { PatOrWild::Pat(pat) => pat.specialize(other_ctor, ctor_arity), } } - - pub(crate) fn set_useful(&self) { - if let PatOrWild::Pat(pat) = self { - pat.set_useful() - } - } } impl<'p, Cx: TypeCx> fmt::Debug for PatOrWild<'p, Cx> { diff --git a/compiler/rustc_pattern_analysis/src/usefulness.rs b/compiler/rustc_pattern_analysis/src/usefulness.rs index 092e752e977..bcc734dc81c 100644 --- a/compiler/rustc_pattern_analysis/src/usefulness.rs +++ b/compiler/rustc_pattern_analysis/src/usefulness.rs @@ -466,13 +466,9 @@ //! first pattern of a row in the matrix is an or-pattern, we expand it by duplicating the rest of //! the row as necessary. This is handled automatically in [`Matrix`]. //! -//! This makes usefulness tracking subtle, because we also want to compute whether an alternative -//! of an or-pattern is redundant, e.g. in `Some(_) | Some(0)`. We track usefulness of each -//! subpattern by interior mutability in [`DeconstructedPat`] with `set_useful`/`is_useful`. -//! -//! It's unfortunate that we have to use interior mutability, but believe me (Nadrieril), I have -//! tried [other](https://github.com/rust-lang/rust/pull/80104) -//! [solutions](https://github.com/rust-lang/rust/pull/80632) and nothing is remotely as simple. +//! This makes usefulness tracking subtle, because we also want to compute whether an alternative of +//! an or-pattern is redundant, e.g. in `Some(_) | Some(0)`. We therefore track usefulness of each +//! subpattern of the match. //! //! //! @@ -1462,8 +1458,8 @@ fn collect_overlapping_range_endpoints<'p, Cx: TypeCx>( /// The core of the algorithm. /// /// This recursively computes witnesses of the non-exhaustiveness of `matrix` (if any). Also tracks -/// usefulness of each row in the matrix (in `row.useful`). We track usefulness of each -/// subpattern using interior mutability in `DeconstructedPat`. +/// usefulness of each row in the matrix (in `row.useful`). We track usefulness of each subpattern +/// in `mcx.useful_subpatterns`. /// /// The input `Matrix` and the output `WitnessMatrix` together match the type exhaustively. /// From be29cd173a87a7d4a87ec6db62f26c3b7666d14a Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Wed, 7 Feb 2024 18:59:40 +0100 Subject: [PATCH 08/56] Use a unique id instead of by-address indexing --- compiler/rustc_pattern_analysis/src/pat.rs | 17 ++++++- .../rustc_pattern_analysis/src/usefulness.rs | 44 +++++-------------- 2 files changed, 25 insertions(+), 36 deletions(-) diff --git a/compiler/rustc_pattern_analysis/src/pat.rs b/compiler/rustc_pattern_analysis/src/pat.rs index 04a77faad74..d9b2b31643d 100644 --- a/compiler/rustc_pattern_analysis/src/pat.rs +++ b/compiler/rustc_pattern_analysis/src/pat.rs @@ -9,6 +9,17 @@ use crate::TypeCx; use self::Constructor::*; +/// A globally unique id to distinguish patterns. +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +pub(crate) struct PatId(u32); +impl PatId { + fn new() -> Self { + use std::sync::atomic::{AtomicU32, Ordering}; + static PAT_ID: AtomicU32 = AtomicU32::new(0); + PatId(PAT_ID.fetch_add(1, Ordering::SeqCst)) + } +} + /// Values and patterns can be represented as a constructor applied to some fields. This represents /// a pattern in this form. A `DeconstructedPat` will almost always come from user input; the only /// exception are some `Wildcard`s introduced during pattern lowering. @@ -24,11 +35,13 @@ pub struct DeconstructedPat { /// Extra data to store in a pattern. `None` if the pattern is a wildcard that does not /// correspond to a user-supplied pattern. data: Option, + /// Globally-unique id used to track usefulness at the level of subpatterns. + pub(crate) uid: PatId, } impl DeconstructedPat { pub fn wildcard(ty: Cx::Ty) -> Self { - DeconstructedPat { ctor: Wildcard, fields: Vec::new(), ty, data: None } + DeconstructedPat { ctor: Wildcard, fields: Vec::new(), ty, data: None, uid: PatId::new() } } pub fn new( @@ -37,7 +50,7 @@ impl DeconstructedPat { ty: Cx::Ty, data: Cx::PatData, ) -> Self { - DeconstructedPat { ctor, fields, ty, data: Some(data) } + DeconstructedPat { ctor, fields, ty, data: Some(data), uid: PatId::new() } } pub(crate) fn is_or_pat(&self) -> bool { diff --git a/compiler/rustc_pattern_analysis/src/usefulness.rs b/compiler/rustc_pattern_analysis/src/usefulness.rs index bcc734dc81c..0cbf6203ada 100644 --- a/compiler/rustc_pattern_analysis/src/usefulness.rs +++ b/compiler/rustc_pattern_analysis/src/usefulness.rs @@ -713,10 +713,9 @@ use rustc_hash::FxHashSet; use rustc_index::bit_set::BitSet; use smallvec::{smallvec, SmallVec}; use std::fmt; -use std::ops::Deref; use crate::constructor::{Constructor, ConstructorSet, IntRange}; -use crate::pat::{DeconstructedPat, PatOrWild, WitnessPat}; +use crate::pat::{DeconstructedPat, PatId, PatOrWild, WitnessPat}; use crate::{Captures, MatchArm, TypeCx}; use self::ValidityConstraint::*; @@ -728,36 +727,13 @@ pub fn ensure_sufficient_stack(f: impl FnOnce() -> R) -> R { f() } -/// Wrapper type for by-address hashing. Comparison and hashing of the wrapped pointer type will be -/// based on the address of its contents, rather than their value. -struct ByAddress(T); - -impl ByAddress { - fn addr(&self) -> *const T::Target { - (&*self.0) as *const _ - } -} -/// Raw pointer hashing and comparison. -impl std::hash::Hash for ByAddress { - fn hash(&self, state: &mut H) { - self.addr().hash(state) - } -} -impl PartialEq for ByAddress { - fn eq(&self, other: &Self) -> bool { - std::ptr::eq(self.addr(), other.addr()) - } -} -impl Eq for ByAddress {} - /// Context that provides information for usefulness checking. -struct UsefulnessCtxt<'a, 'p, Cx: TypeCx> { +struct UsefulnessCtxt<'a, Cx: TypeCx> { /// The context for type information. tycx: &'a Cx, /// Collect the patterns found useful during usefulness checking. This is used to lint - /// unreachable (sub)patterns. We distinguish patterns by their address to avoid needing to - /// inspect the contents. They'll all be distinct anyway since they carry a `Span`. - useful_subpatterns: FxHashSet>>, + /// unreachable (sub)patterns. + useful_subpatterns: FxHashSet, } /// Context that provides information local to a place under investigation. @@ -1398,7 +1374,7 @@ impl WitnessMatrix { /// We can however get false negatives because exhaustiveness does not explore all cases. See the /// section on relevancy at the top of the file. fn collect_overlapping_range_endpoints<'p, Cx: TypeCx>( - mcx: &mut UsefulnessCtxt<'_, 'p, Cx>, + mcx: &mut UsefulnessCtxt<'_, Cx>, overlap_range: IntRange, matrix: &Matrix<'p, Cx>, specialized_matrix: &Matrix<'p, Cx>, @@ -1471,7 +1447,7 @@ fn collect_overlapping_range_endpoints<'p, Cx: TypeCx>( /// This is all explained at the top of the file. #[instrument(level = "debug", skip(mcx), ret)] fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: TypeCx>( - mcx: &mut UsefulnessCtxt<'a, 'p, Cx>, + mcx: &mut UsefulnessCtxt<'a, Cx>, matrix: &mut Matrix<'p, Cx>, ) -> Result, Cx::Error> { debug_assert!(matrix.rows().all(|r| r.len() == matrix.column_count())); @@ -1598,7 +1574,7 @@ fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: TypeCx>( for row in matrix.rows() { if row.useful { if let PatOrWild::Pat(pat) = row.head() { - mcx.useful_subpatterns.insert(ByAddress(pat)); + mcx.useful_subpatterns.insert(pat.uid); } } } @@ -1620,14 +1596,14 @@ pub enum Usefulness<'p, Cx: TypeCx> { /// Report whether this pattern was found useful, and its subpatterns that were not useful if any. fn collect_pattern_usefulness<'p, Cx: TypeCx>( - useful_subpatterns: &FxHashSet>>, + useful_subpatterns: &FxHashSet, pat: &'p DeconstructedPat, ) -> Usefulness<'p, Cx> { fn pat_is_useful<'p, Cx: TypeCx>( - useful_subpatterns: &FxHashSet>>, + useful_subpatterns: &FxHashSet, pat: &'p DeconstructedPat, ) -> bool { - if useful_subpatterns.contains(&ByAddress(pat)) { + if useful_subpatterns.contains(&pat.uid) { true } else if pat.is_or_pat() && pat.iter_fields().any(|f| pat_is_useful(useful_subpatterns, f)) { From 5461fd4250c5e535ae653bd6f0f8392dede5b484 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 10 Feb 2024 23:49:16 +0000 Subject: [PATCH 09/56] Gracefully handle non-WF alias in assemble_alias_bound_candidates_recur --- .../src/solve/assembly/mod.rs | 8 ++++++-- .../in-trait/alias-bounds-when-not-wf.rs | 19 +++++++++++++++++++ .../in-trait/alias-bounds-when-not-wf.stderr | 17 +++++++++++++++++ 3 files changed, 42 insertions(+), 2 deletions(-) create mode 100644 tests/ui/impl-trait/in-trait/alias-bounds-when-not-wf.rs create mode 100644 tests/ui/impl-trait/in-trait/alias-bounds-when-not-wf.stderr diff --git a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs index 81c0cfea85a..6833d2ae330 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs @@ -15,7 +15,7 @@ use rustc_middle::ty::fast_reject::{SimplifiedType, TreatParams}; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::ty::{fast_reject, TypeFoldable}; use rustc_middle::ty::{ToPredicate, TypeVisitableExt}; -use rustc_span::ErrorGuaranteed; +use rustc_span::{ErrorGuaranteed, DUMMY_SP}; use std::fmt::Debug; pub(super) mod structural_traits; @@ -612,7 +612,11 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { ty::Alias(kind @ (ty::Projection | ty::Opaque), alias_ty) => (kind, alias_ty), ty::Alias(ty::Inherent | ty::Weak, _) => { - unreachable!("Weak and Inherent aliases should have been normalized away already") + self.tcx().sess.dcx().span_delayed_bug( + DUMMY_SP, + format!("could not normalize {self_ty}, it is not WF"), + ); + return; } }; diff --git a/tests/ui/impl-trait/in-trait/alias-bounds-when-not-wf.rs b/tests/ui/impl-trait/in-trait/alias-bounds-when-not-wf.rs new file mode 100644 index 00000000000..229a918cdd2 --- /dev/null +++ b/tests/ui/impl-trait/in-trait/alias-bounds-when-not-wf.rs @@ -0,0 +1,19 @@ +// compile-flags: -Znext-solver + +#![feature(lazy_type_alias)] +//~^ WARN the feature `lazy_type_alias` is incomplete + +trait Foo {} + +type A = T; + +struct W(T); + +// For `W>` to be WF, `A: Sized` must hold. However, when assembling +// alias bounds for `A`, we try to normalize it, but it doesn't hold because +// `usize: Foo` doesn't hold. Therefore we ICE, because we don't expect to still +// encounter weak types in `assemble_alias_bound_candidates_recur`. +fn hello(_: W>) {} +//~^ ERROR the type `W>` is not well-formed + +fn main() {} diff --git a/tests/ui/impl-trait/in-trait/alias-bounds-when-not-wf.stderr b/tests/ui/impl-trait/in-trait/alias-bounds-when-not-wf.stderr new file mode 100644 index 00000000000..5df27ac3bc6 --- /dev/null +++ b/tests/ui/impl-trait/in-trait/alias-bounds-when-not-wf.stderr @@ -0,0 +1,17 @@ +warning: the feature `lazy_type_alias` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/alias-bounds-when-not-wf.rs:3:12 + | +LL | #![feature(lazy_type_alias)] + | ^^^^^^^^^^^^^^^ + | + = note: see issue #112792 for more information + = note: `#[warn(incomplete_features)]` on by default + +error: the type `W>` is not well-formed + --> $DIR/alias-bounds-when-not-wf.rs:16:13 + | +LL | fn hello(_: W>) {} + | ^^^^^^^^^^^ + +error: aborting due to 1 previous error; 1 warning emitted + From 1fa75af1737e9bb08d8d9e4b919a93370364ebc5 Mon Sep 17 00:00:00 2001 From: Caio Date: Sun, 11 Feb 2024 08:02:32 -0300 Subject: [PATCH 10/56] Add test --- tests/ui/typeck/issue-116864.rs | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 tests/ui/typeck/issue-116864.rs diff --git a/tests/ui/typeck/issue-116864.rs b/tests/ui/typeck/issue-116864.rs new file mode 100644 index 00000000000..88c3f786608 --- /dev/null +++ b/tests/ui/typeck/issue-116864.rs @@ -0,0 +1,31 @@ +// compile-flags: -Znext-solver +// check-pass +// edition: 2021 + +use std::future::Future; + +trait Baz { + type Param; +} + +trait FnMutFut: FnMut(P) -> Self::Future { + type Future: Future; +} + +impl FnMutFut for F +where + F: FnMut(P) -> FUT, + FUT: Future, +{ + type Future = FUT; +} + +async fn foo(_: BAZ, mut cb: impl for<'any> FnMutFut<&'any BAZ::Param, ()>) +where + BAZ: Baz, +{ + cb(&1i32).await; +} + +fn main() { +} From 89abbb0b4048cc45cb39aafd759a9625bb843dd8 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Sun, 11 Feb 2024 09:12:35 -0300 Subject: [PATCH 11/56] Add ChrisDenton to review queue --- triagebot.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/triagebot.toml b/triagebot.toml index ef3f3693e61..ed2ea7798fd 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -811,7 +811,7 @@ project-stable-mir = [ "/library/panic_abort" = ["libs"] "/library/panic_unwind" = ["libs"] "/library/proc_macro" = ["@petrochenkov"] -"/library/std" = ["libs"] +"/library/std" = ["libs", "@ChrisDenton"] "/library/std/src/sys/pal/windows" = ["@ChrisDenton"] "/library/stdarch" = ["libs"] "/library/test" = ["libs"] From d5de9a610556642da338e62c53f04ce4cc7f02b6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 11 Feb 2024 14:46:20 +0100 Subject: [PATCH 12/56] check_consts: fix some duplicate errors by not calling check_static unnecessarily --- .../src/transform/check_consts/check.rs | 8 +++-- .../ui/consts/issue-17718-const-bad-values.rs | 1 - .../issue-17718-const-bad-values.stderr | 15 +------- .../const_refers_to_static.32bit.stderr | 5 --- .../const_refers_to_static.64bit.stderr | 5 --- ..._refers_to_static_cross_crate.32bit.stderr | 35 ------------------- ..._refers_to_static_cross_crate.64bit.stderr | 35 ------------------- .../mutable_references_err.32bit.stderr | 15 -------- .../mutable_references_err.64bit.stderr | 15 -------- .../feature-gate-const-refs-to-static.rs | 1 - .../feature-gate-const-refs-to-static.stderr | 15 +------- tests/ui/thread-local/thread-local-static.rs | 1 - .../thread-local/thread-local-static.stderr | 14 +------- 13 files changed, 8 insertions(+), 157 deletions(-) diff --git a/compiler/rustc_const_eval/src/transform/check_consts/check.rs b/compiler/rustc_const_eval/src/transform/check_consts/check.rs index 28dc69859fd..43048dc41d3 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs @@ -619,9 +619,11 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { if base_ty.is_unsafe_ptr() { if place_ref.projection.is_empty() { let decl = &self.body.local_decls[place_ref.local]; - if let LocalInfo::StaticRef { def_id, .. } = *decl.local_info() { - let span = decl.source_info.span; - self.check_static(def_id, span); + // If this is a static, then this is not really dereferencing a pointer, + // just directly accessing a static. That is not subject to any feature + // gates (except for the one about whether statics can even be used, but + // that is checked already by `visit_operand`). + if let LocalInfo::StaticRef { .. } = *decl.local_info() { return; } } diff --git a/tests/ui/consts/issue-17718-const-bad-values.rs b/tests/ui/consts/issue-17718-const-bad-values.rs index af50fed972d..2b593a192ee 100644 --- a/tests/ui/consts/issue-17718-const-bad-values.rs +++ b/tests/ui/consts/issue-17718-const-bad-values.rs @@ -4,7 +4,6 @@ const C1: &'static mut [usize] = &mut []; static mut S: usize = 3; const C2: &'static mut usize = unsafe { &mut S }; //~^ ERROR: referencing statics in constants -//~| ERROR: referencing statics in constants //~| WARN mutable reference of mutable static is discouraged [static_mut_ref] fn main() {} diff --git a/tests/ui/consts/issue-17718-const-bad-values.stderr b/tests/ui/consts/issue-17718-const-bad-values.stderr index cda94490155..92bab1ab53e 100644 --- a/tests/ui/consts/issue-17718-const-bad-values.stderr +++ b/tests/ui/consts/issue-17718-const-bad-values.stderr @@ -31,20 +31,7 @@ LL | const C2: &'static mut usize = unsafe { &mut S }; = note: `static` and `const` variables can refer to other `const` variables. A `const` variable, however, cannot refer to a `static` variable. = help: to fix this, the value can be extracted to a `const` and then used. -error[E0658]: referencing statics in constants is unstable - --> $DIR/issue-17718-const-bad-values.rs:5:46 - | -LL | const C2: &'static mut usize = unsafe { &mut S }; - | ^ - | - = note: see issue #119618 for more information - = help: add `#![feature(const_refs_to_static)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - = note: `static` and `const` variables can refer to other `const` variables. A `const` variable, however, cannot refer to a `static` variable. - = help: to fix this, the value can be extracted to a `const` and then used. - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: aborting due to 3 previous errors; 1 warning emitted +error: aborting due to 2 previous errors; 1 warning emitted Some errors have detailed explanations: E0658, E0764. For more information about an error, try `rustc --explain E0658`. diff --git a/tests/ui/consts/miri_unleashed/const_refers_to_static.32bit.stderr b/tests/ui/consts/miri_unleashed/const_refers_to_static.32bit.stderr index 35b9ed6735e..9e76b873858 100644 --- a/tests/ui/consts/miri_unleashed/const_refers_to_static.32bit.stderr +++ b/tests/ui/consts/miri_unleashed/const_refers_to_static.32bit.stderr @@ -49,11 +49,6 @@ help: skipping check for `const_refs_to_static` feature | LL | const READ_MUT: u32 = unsafe { MUTABLE }; | ^^^^^^^ -help: skipping check for `const_refs_to_static` feature - --> $DIR/const_refers_to_static.rs:18:32 - | -LL | const READ_MUT: u32 = unsafe { MUTABLE }; - | ^^^^^^^ help: skipping check for `const_refs_to_static` feature --> $DIR/const_refers_to_static.rs:24:18 | diff --git a/tests/ui/consts/miri_unleashed/const_refers_to_static.64bit.stderr b/tests/ui/consts/miri_unleashed/const_refers_to_static.64bit.stderr index 8511673b684..989d3c75cd6 100644 --- a/tests/ui/consts/miri_unleashed/const_refers_to_static.64bit.stderr +++ b/tests/ui/consts/miri_unleashed/const_refers_to_static.64bit.stderr @@ -49,11 +49,6 @@ help: skipping check for `const_refs_to_static` feature | LL | const READ_MUT: u32 = unsafe { MUTABLE }; | ^^^^^^^ -help: skipping check for `const_refs_to_static` feature - --> $DIR/const_refers_to_static.rs:18:32 - | -LL | const READ_MUT: u32 = unsafe { MUTABLE }; - | ^^^^^^^ help: skipping check for `const_refs_to_static` feature --> $DIR/const_refers_to_static.rs:24:18 | diff --git a/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.32bit.stderr b/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.32bit.stderr index a2c9034c831..e280fe622ec 100644 --- a/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.32bit.stderr +++ b/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.32bit.stderr @@ -83,21 +83,6 @@ help: skipping check for `const_refs_to_static` feature | LL | unsafe { &static_cross_crate::ZERO } | ^^^^^^^^^^^^^^^^^^^^^^^^ -help: skipping check for `const_refs_to_static` feature - --> $DIR/const_refers_to_static_cross_crate.rs:12:15 - | -LL | unsafe { &static_cross_crate::ZERO } - | ^^^^^^^^^^^^^^^^^^^^^^^^ -help: skipping check for `const_refs_to_static` feature - --> $DIR/const_refers_to_static_cross_crate.rs:18:15 - | -LL | unsafe { &static_cross_crate::ZERO[0] } - | ^^^^^^^^^^^^^^^^^^^^^^^^ -help: skipping check for `const_refs_to_static` feature - --> $DIR/const_refers_to_static_cross_crate.rs:18:15 - | -LL | unsafe { &static_cross_crate::ZERO[0] } - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: skipping check for `const_refs_to_static` feature --> $DIR/const_refers_to_static_cross_crate.rs:18:15 | @@ -113,26 +98,6 @@ help: skipping check for `const_refs_to_static` feature | LL | match static_cross_crate::OPT_ZERO { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -help: skipping check for `const_refs_to_static` feature - --> $DIR/const_refers_to_static_cross_crate.rs:28:15 - | -LL | match static_cross_crate::OPT_ZERO { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -help: skipping check for `const_refs_to_static` feature - --> $DIR/const_refers_to_static_cross_crate.rs:28:15 - | -LL | match static_cross_crate::OPT_ZERO { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -help: skipping check for `const_refs_to_static` feature - --> $DIR/const_refers_to_static_cross_crate.rs:28:15 - | -LL | match static_cross_crate::OPT_ZERO { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -help: skipping check for `const_refs_to_static` feature - --> $DIR/const_refers_to_static_cross_crate.rs:28:15 - | -LL | match static_cross_crate::OPT_ZERO { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 8 previous errors; 2 warnings emitted diff --git a/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.64bit.stderr b/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.64bit.stderr index 2b44a8b12fa..9bca60485c0 100644 --- a/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.64bit.stderr +++ b/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.64bit.stderr @@ -83,21 +83,6 @@ help: skipping check for `const_refs_to_static` feature | LL | unsafe { &static_cross_crate::ZERO } | ^^^^^^^^^^^^^^^^^^^^^^^^ -help: skipping check for `const_refs_to_static` feature - --> $DIR/const_refers_to_static_cross_crate.rs:12:15 - | -LL | unsafe { &static_cross_crate::ZERO } - | ^^^^^^^^^^^^^^^^^^^^^^^^ -help: skipping check for `const_refs_to_static` feature - --> $DIR/const_refers_to_static_cross_crate.rs:18:15 - | -LL | unsafe { &static_cross_crate::ZERO[0] } - | ^^^^^^^^^^^^^^^^^^^^^^^^ -help: skipping check for `const_refs_to_static` feature - --> $DIR/const_refers_to_static_cross_crate.rs:18:15 - | -LL | unsafe { &static_cross_crate::ZERO[0] } - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: skipping check for `const_refs_to_static` feature --> $DIR/const_refers_to_static_cross_crate.rs:18:15 | @@ -113,26 +98,6 @@ help: skipping check for `const_refs_to_static` feature | LL | match static_cross_crate::OPT_ZERO { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -help: skipping check for `const_refs_to_static` feature - --> $DIR/const_refers_to_static_cross_crate.rs:28:15 - | -LL | match static_cross_crate::OPT_ZERO { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -help: skipping check for `const_refs_to_static` feature - --> $DIR/const_refers_to_static_cross_crate.rs:28:15 - | -LL | match static_cross_crate::OPT_ZERO { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -help: skipping check for `const_refs_to_static` feature - --> $DIR/const_refers_to_static_cross_crate.rs:28:15 - | -LL | match static_cross_crate::OPT_ZERO { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -help: skipping check for `const_refs_to_static` feature - --> $DIR/const_refers_to_static_cross_crate.rs:28:15 - | -LL | match static_cross_crate::OPT_ZERO { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 8 previous errors; 2 warnings emitted diff --git a/tests/ui/consts/miri_unleashed/mutable_references_err.32bit.stderr b/tests/ui/consts/miri_unleashed/mutable_references_err.32bit.stderr index b60f9a24f8c..401cf46710a 100644 --- a/tests/ui/consts/miri_unleashed/mutable_references_err.32bit.stderr +++ b/tests/ui/consts/miri_unleashed/mutable_references_err.32bit.stderr @@ -114,11 +114,6 @@ help: skipping check for `const_refs_to_static` feature | LL | const SUBTLE: &mut i32 = unsafe { &mut FOO }; | ^^^ -help: skipping check for `const_refs_to_static` feature - --> $DIR/mutable_references_err.rs:32:40 - | -LL | const SUBTLE: &mut i32 = unsafe { &mut FOO }; - | ^^^ help: skipping check that does not even have a feature gate --> $DIR/mutable_references_err.rs:32:35 | @@ -144,16 +139,6 @@ help: skipping check for `const_refs_to_static` feature | LL | const POINTS_TO_MUTABLE1: &i32 = unsafe { &MUTABLE }; | ^^^^^^^ -help: skipping check for `const_refs_to_static` feature - --> $DIR/mutable_references_err.rs:47:44 - | -LL | const POINTS_TO_MUTABLE1: &i32 = unsafe { &MUTABLE }; - | ^^^^^^^ -help: skipping check for `const_refs_to_static` feature - --> $DIR/mutable_references_err.rs:51:45 - | -LL | const POINTS_TO_MUTABLE2: &i32 = unsafe { &*MUTABLE_REF }; - | ^^^^^^^^^^^ help: skipping check for `const_refs_to_static` feature --> $DIR/mutable_references_err.rs:51:45 | diff --git a/tests/ui/consts/miri_unleashed/mutable_references_err.64bit.stderr b/tests/ui/consts/miri_unleashed/mutable_references_err.64bit.stderr index 1e5d4bd890b..0eb01f5b773 100644 --- a/tests/ui/consts/miri_unleashed/mutable_references_err.64bit.stderr +++ b/tests/ui/consts/miri_unleashed/mutable_references_err.64bit.stderr @@ -114,11 +114,6 @@ help: skipping check for `const_refs_to_static` feature | LL | const SUBTLE: &mut i32 = unsafe { &mut FOO }; | ^^^ -help: skipping check for `const_refs_to_static` feature - --> $DIR/mutable_references_err.rs:32:40 - | -LL | const SUBTLE: &mut i32 = unsafe { &mut FOO }; - | ^^^ help: skipping check that does not even have a feature gate --> $DIR/mutable_references_err.rs:32:35 | @@ -144,16 +139,6 @@ help: skipping check for `const_refs_to_static` feature | LL | const POINTS_TO_MUTABLE1: &i32 = unsafe { &MUTABLE }; | ^^^^^^^ -help: skipping check for `const_refs_to_static` feature - --> $DIR/mutable_references_err.rs:47:44 - | -LL | const POINTS_TO_MUTABLE1: &i32 = unsafe { &MUTABLE }; - | ^^^^^^^ -help: skipping check for `const_refs_to_static` feature - --> $DIR/mutable_references_err.rs:51:45 - | -LL | const POINTS_TO_MUTABLE2: &i32 = unsafe { &*MUTABLE_REF }; - | ^^^^^^^^^^^ help: skipping check for `const_refs_to_static` feature --> $DIR/mutable_references_err.rs:51:45 | diff --git a/tests/ui/feature-gates/feature-gate-const-refs-to-static.rs b/tests/ui/feature-gates/feature-gate-const-refs-to-static.rs index c020bb37a99..008b754dc6c 100644 --- a/tests/ui/feature-gates/feature-gate-const-refs-to-static.rs +++ b/tests/ui/feature-gates/feature-gate-const-refs-to-static.rs @@ -6,7 +6,6 @@ const C1_READ: () = { assert!(*C1 == 0); }; const C2: *const i32 = unsafe { std::ptr::addr_of!(S_MUT) }; //~ERROR: referencing statics in constants is unstable -//~^ERROR: referencing statics in constants is unstable fn main() { } diff --git a/tests/ui/feature-gates/feature-gate-const-refs-to-static.stderr b/tests/ui/feature-gates/feature-gate-const-refs-to-static.stderr index f94cff5b550..5af48471250 100644 --- a/tests/ui/feature-gates/feature-gate-const-refs-to-static.stderr +++ b/tests/ui/feature-gates/feature-gate-const-refs-to-static.stderr @@ -22,19 +22,6 @@ LL | const C2: *const i32 = unsafe { std::ptr::addr_of!(S_MUT) }; = note: `static` and `const` variables can refer to other `const` variables. A `const` variable, however, cannot refer to a `static` variable. = help: to fix this, the value can be extracted to a `const` and then used. -error[E0658]: referencing statics in constants is unstable - --> $DIR/feature-gate-const-refs-to-static.rs:8:52 - | -LL | const C2: *const i32 = unsafe { std::ptr::addr_of!(S_MUT) }; - | ^^^^^ - | - = note: see issue #119618 for more information - = help: add `#![feature(const_refs_to_static)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - = note: `static` and `const` variables can refer to other `const` variables. A `const` variable, however, cannot refer to a `static` variable. - = help: to fix this, the value can be extracted to a `const` and then used. - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/thread-local/thread-local-static.rs b/tests/ui/thread-local/thread-local-static.rs index 7b69ffed197..dac9259a6a6 100644 --- a/tests/ui/thread-local/thread-local-static.rs +++ b/tests/ui/thread-local/thread-local-static.rs @@ -12,7 +12,6 @@ const fn g(x: &mut [u32; 8]) { //~^^ ERROR thread-local statics cannot be accessed //~| ERROR mutable references are not allowed //~| ERROR use of mutable static is unsafe - //~| referencing statics } fn main() {} diff --git a/tests/ui/thread-local/thread-local-static.stderr b/tests/ui/thread-local/thread-local-static.stderr index d91742686c6..3dd1e2d4000 100644 --- a/tests/ui/thread-local/thread-local-static.stderr +++ b/tests/ui/thread-local/thread-local-static.stderr @@ -37,18 +37,6 @@ error[E0625]: thread-local statics cannot be accessed at compile-time LL | std::mem::swap(x, &mut STATIC_VAR_2) | ^^^^^^^^^^^^ -error[E0658]: referencing statics in constant functions is unstable - --> $DIR/thread-local-static.rs:10:28 - | -LL | std::mem::swap(x, &mut STATIC_VAR_2) - | ^^^^^^^^^^^^ - | - = note: see issue #119618 for more information - = help: add `#![feature(const_refs_to_static)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - = note: `static` and `const` variables can refer to other `const` variables. A `const` variable, however, cannot refer to a `static` variable. - = help: to fix this, the value can be extracted to a `const` and then used. - error[E0658]: mutable references are not allowed in constant functions --> $DIR/thread-local-static.rs:10:23 | @@ -59,7 +47,7 @@ LL | std::mem::swap(x, &mut STATIC_VAR_2) = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error: aborting due to 5 previous errors; 1 warning emitted +error: aborting due to 4 previous errors; 1 warning emitted Some errors have detailed explanations: E0133, E0625, E0658. For more information about an error, try `rustc --explain E0133`. From e13de311d58467a61ca1b33adedeec5f62fd1cad Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 11 Feb 2024 14:59:38 +0100 Subject: [PATCH 13/56] make Primary/Secondary importance consistent between CellBorrow and MutBorrow --- .../src/transform/check_consts/ops.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs index a9d472d377c..0c93cfaa546 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs @@ -409,11 +409,6 @@ impl<'tcx> NonConstOp<'tcx> for TransientCellBorrow { fn status_in_item(&self, _: &ConstCx<'_, 'tcx>) -> Status { Status::Unstable(sym::const_refs_to_cell) } - fn importance(&self) -> DiagnosticImportance { - // The cases that cannot possibly work will already emit a `CellBorrow`, so we should - // not additionally emit a feature gate error if activating the feature gate won't work. - DiagnosticImportance::Secondary - } fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { ccx.tcx .sess @@ -427,6 +422,11 @@ impl<'tcx> NonConstOp<'tcx> for TransientCellBorrow { /// it in the future for static items. pub struct CellBorrow; impl<'tcx> NonConstOp<'tcx> for CellBorrow { + fn importance(&self) -> DiagnosticImportance { + // Most likely the code will try to do mutation with these borrows, which + // triggers its own errors. Only show this one if that does not happen. + DiagnosticImportance::Secondary + } fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { // FIXME: Maybe a more elegant solution to this if else case if let hir::ConstContext::Static(_) = ccx.const_kind() { @@ -459,8 +459,8 @@ impl<'tcx> NonConstOp<'tcx> for MutBorrow { } fn importance(&self) -> DiagnosticImportance { - // If there were primary errors (like non-const function calls), do not emit further - // errors about mutable references. + // Most likely the code will try to do mutation with these borrows, which + // triggers its own errors. Only show this one if that does not happen. DiagnosticImportance::Secondary } From 792fa24595c9a65249dd8de815549f3641548ad3 Mon Sep 17 00:00:00 2001 From: ripytide Date: Sun, 11 Feb 2024 15:21:58 +0000 Subject: [PATCH 14/56] improve `btree_cursors` functions documentation --- library/alloc/src/collections/btree/map.rs | 217 ++++++++++++--------- 1 file changed, 130 insertions(+), 87 deletions(-) diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs index b585e2082f1..724a070818d 100644 --- a/library/alloc/src/collections/btree/map.rs +++ b/library/alloc/src/collections/btree/map.rs @@ -2522,10 +2522,17 @@ impl BTreeMap { self.len() == 0 } - /// Returns a [`Cursor`] pointing to the first gap above the given bound. + /// Returns a [`Cursor`] pointing at the gap before the smallest key + /// greater than the given bound. /// - /// Passing [`Bound::Unbounded`] will return a cursor pointing to the start - /// of the map. + /// Passing [`Bound::Included(x)`] will return a cursor pointing to the + /// gap before the smallest key greater than or equal to `x`. + /// + /// Passing [`Bound::Excluded(x)`] will return a cursor pointing to the + /// gap before the smallest key greater than `x`. + /// + /// Passing [`Bound::Unbounded`] will return a cursor pointing to the + /// gap before the smallest key in the map. /// /// # Examples /// @@ -2535,17 +2542,24 @@ impl BTreeMap { /// use std::collections::BTreeMap; /// use std::ops::Bound; /// - /// let mut a = BTreeMap::new(); - /// a.insert(1, "a"); - /// a.insert(2, "b"); - /// a.insert(3, "c"); - /// a.insert(4, "d"); - /// let cursor = a.lower_bound(Bound::Included(&2)); + /// let map = BTreeMap::from([ + /// (1, "a"), + /// (2, "b"), + /// (3, "c"), + /// (4, "d"), + /// ]); + /// + /// let cursor = map.lower_bound(Bound::Included(&2)); /// assert_eq!(cursor.peek_prev(), Some((&1, &"a"))); /// assert_eq!(cursor.peek_next(), Some((&2, &"b"))); - /// let cursor = a.lower_bound(Bound::Excluded(&2)); + /// + /// let cursor = map.lower_bound(Bound::Excluded(&2)); /// assert_eq!(cursor.peek_prev(), Some((&2, &"b"))); /// assert_eq!(cursor.peek_next(), Some((&3, &"c"))); + /// + /// let cursor = map.lower_bound(Bound::Unbounded); + /// assert_eq!(cursor.peek_prev(), None); + /// assert_eq!(cursor.peek_next(), Some((&1, &"a"))); /// ``` #[unstable(feature = "btree_cursors", issue = "107540")] pub fn lower_bound(&self, bound: Bound<&Q>) -> Cursor<'_, K, V> @@ -2561,11 +2575,17 @@ impl BTreeMap { Cursor { current: Some(edge), root: self.root.as_ref() } } - /// Returns a [`CursorMut`] pointing to the first gap above the given bound. + /// Returns a [`CursorMut`] pointing at the gap before the smallest key + /// greater than the given bound. /// + /// Passing [`Bound::Included(x)`] will return a cursor pointing to the + /// gap before the smallest key greater than or equal to `x`. /// - /// Passing [`Bound::Unbounded`] will return a cursor pointing to the start - /// of the map. + /// Passing [`Bound::Excluded(x)`] will return a cursor pointing to the + /// gap before the smallest key greater than `x`. + /// + /// Passing [`Bound::Unbounded`] will return a cursor pointing to the + /// gap before the smallest key in the map. /// /// # Examples /// @@ -2575,17 +2595,24 @@ impl BTreeMap { /// use std::collections::BTreeMap; /// use std::ops::Bound; /// - /// let mut a = BTreeMap::new(); - /// a.insert(1, "a"); - /// a.insert(2, "b"); - /// a.insert(3, "c"); - /// a.insert(4, "d"); - /// let mut cursor = a.lower_bound_mut(Bound::Included(&2)); + /// let mut map = BTreeMap::from([ + /// (1, "a"), + /// (2, "b"), + /// (3, "c"), + /// (4, "d"), + /// ]); + /// + /// let mut cursor = map.lower_bound_mut(Bound::Included(&2)); /// assert_eq!(cursor.peek_prev(), Some((&1, &mut "a"))); /// assert_eq!(cursor.peek_next(), Some((&2, &mut "b"))); - /// let mut cursor = a.lower_bound_mut(Bound::Excluded(&2)); + /// + /// let mut cursor = map.lower_bound_mut(Bound::Excluded(&2)); /// assert_eq!(cursor.peek_prev(), Some((&2, &mut "b"))); /// assert_eq!(cursor.peek_next(), Some((&3, &mut "c"))); + /// + /// let mut cursor = map.lower_bound_mut(Bound::Unbounded); + /// assert_eq!(cursor.peek_prev(), None); + /// assert_eq!(cursor.peek_next(), Some((&1, &mut "a"))); /// ``` #[unstable(feature = "btree_cursors", issue = "107540")] pub fn lower_bound_mut(&mut self, bound: Bound<&Q>) -> CursorMut<'_, K, V, A> @@ -2618,10 +2645,17 @@ impl BTreeMap { } } - /// Returns a [`Cursor`] pointing at the last gap below the given bound. + /// Returns a [`Cursor`] pointing at the gap after the greatest key + /// smaller than the given bound. /// - /// Passing [`Bound::Unbounded`] will return a cursor pointing to the end - /// of the map. + /// Passing [`Bound::Included(x)`] will return a cursor pointing to the + /// gap after the greatest key smaller than or equal to `x`. + /// + /// Passing [`Bound::Excluded(x)`] will return a cursor pointing to the + /// gap after the greatest key smaller than `x`. + /// + /// Passing [`Bound::Unbounded`] will return a cursor pointing to the + /// gap after the greatest key in the map. /// /// # Examples /// @@ -2631,17 +2665,24 @@ impl BTreeMap { /// use std::collections::BTreeMap; /// use std::ops::Bound; /// - /// let mut a = BTreeMap::new(); - /// a.insert(1, "a"); - /// a.insert(2, "b"); - /// a.insert(3, "c"); - /// a.insert(4, "d"); - /// let cursor = a.upper_bound(Bound::Included(&3)); - /// assert_eq!(cursor.peek_prev(), Some((&3, &"c"))); - /// assert_eq!(cursor.peek_next(), Some((&4, &"d"))); - /// let cursor = a.upper_bound(Bound::Excluded(&3)); + /// let map = BTreeMap::from([ + /// (1, "a"), + /// (2, "b"), + /// (3, "c"), + /// (4, "d"), + /// ]); + /// + /// let cursor = map.upper_bound(Bound::Included(&3)); + /// assert_eq!(cursor.peek_prev(), Some((&3, &"d"))); + /// assert_eq!(cursor.peek_next(), Some((&4, &"c"))); + /// + /// let cursor = map.upper_bound(Bound::Excluded(&3)); /// assert_eq!(cursor.peek_prev(), Some((&2, &"b"))); /// assert_eq!(cursor.peek_next(), Some((&3, &"c"))); + /// + /// let cursor = map.upper_bound(Bound::Unbounded); + /// assert_eq!(cursor.peek_prev(), Some((&4, &"d"))); + /// assert_eq!(cursor.peek_next(), None); /// ``` #[unstable(feature = "btree_cursors", issue = "107540")] pub fn upper_bound(&self, bound: Bound<&Q>) -> Cursor<'_, K, V> @@ -2657,10 +2698,17 @@ impl BTreeMap { Cursor { current: Some(edge), root: self.root.as_ref() } } - /// Returns a [`CursorMut`] pointing at the last gap below the given bound. + /// Returns a [`CursorMut`] pointing at the gap after the greatest key + /// smaller than the given bound. /// - /// Passing [`Bound::Unbounded`] will return a cursor pointing to the end - /// of the map. + /// Passing [`Bound::Included(x)`] will return a cursor pointing to the + /// gap after the greatest key smaller than or equal to `x`. + /// + /// Passing [`Bound::Excluded(x)`] will return a cursor pointing to the + /// gap after the greatest key smaller than `x`. + /// + /// Passing [`Bound::Unbounded`] will return a cursor pointing to the + /// gap after the greatest key in the map. /// /// # Examples /// @@ -2670,17 +2718,24 @@ impl BTreeMap { /// use std::collections::BTreeMap; /// use std::ops::Bound; /// - /// let mut a = BTreeMap::new(); - /// a.insert(1, "a"); - /// a.insert(2, "b"); - /// a.insert(3, "c"); - /// a.insert(4, "d"); - /// let mut cursor = a.upper_bound_mut(Bound::Included(&3)); + /// let mut map = BTreeMap::from([ + /// (1, "a"), + /// (2, "b"), + /// (3, "c"), + /// (4, "d"), + /// ]); + /// + /// let mut cursor = map.upper_bound_mut(Bound::Included(&3)); /// assert_eq!(cursor.peek_prev(), Some((&3, &mut "c"))); /// assert_eq!(cursor.peek_next(), Some((&4, &mut "d"))); - /// let mut cursor = a.upper_bound_mut(Bound::Excluded(&3)); + /// + /// let mut cursor = map.upper_bound_mut(Bound::Excluded(&3)); /// assert_eq!(cursor.peek_prev(), Some((&2, &mut "b"))); /// assert_eq!(cursor.peek_next(), Some((&3, &mut "c"))); + /// + /// let mut cursor = map.upper_bound_mut(Bound::Unbounded); + /// assert_eq!(cursor.peek_prev(), Some((&4, &mut "d"))); + /// assert_eq!(cursor.peek_next(), None); /// ``` #[unstable(feature = "btree_cursors", issue = "107540")] pub fn upper_bound_mut(&mut self, bound: Bound<&Q>) -> CursorMut<'_, K, V, A> @@ -3040,8 +3095,8 @@ impl<'a, K, V, A> CursorMutKey<'a, K, V, A> { // Now the tree editing operations impl<'a, K: Ord, V, A: Allocator + Clone> CursorMutKey<'a, K, V, A> { - /// Inserts a new element into the `BTreeMap` in the gap that the - /// `CursorMutKey` is currently pointing to. + /// Inserts a new key-value pair into the map in the gap that the + /// cursor is currently pointing to. /// /// After the insertion the cursor will be pointing at the gap before the /// newly inserted element. @@ -3083,8 +3138,8 @@ impl<'a, K: Ord, V, A: Allocator + Clone> CursorMutKey<'a, K, V, A> { *self.length += 1; } - /// Inserts a new element into the `BTreeMap` in the gap that the - /// `CursorMutKey` is currently pointing to. + /// Inserts a new key-value pair into the map in the gap that the + /// cursor is currently pointing to. /// /// After the insertion the cursor will be pointing at the gap after the /// newly inserted element. @@ -3129,19 +3184,16 @@ impl<'a, K: Ord, V, A: Allocator + Clone> CursorMutKey<'a, K, V, A> { *self.length += 1; } - /// Inserts a new element into the `BTreeMap` in the gap that the - /// `CursorMutKey` is currently pointing to. + /// Inserts a new key-value pair into the map in the gap that the + /// cursor is currently pointing to. /// /// After the insertion the cursor will be pointing at the gap before the /// newly inserted element. /// - /// # Panics - /// - /// This function panics if: - /// - the given key compares less than or equal to the current element (if - /// any). - /// - the given key compares greater than or equal to the next element (if - /// any). + /// If the inserted key is not greater than the key before the cursor + /// (if any), or if it not less than the key after the cursor (if any), + /// then an [`UnorderedKeyError`] is returned since this would + /// invalidate the [`Ord`] invariant between the keys of the map. #[unstable(feature = "btree_cursors", issue = "107540")] pub fn insert_after(&mut self, key: K, value: V) -> Result<(), UnorderedKeyError> { if let Some((prev, _)) = self.peek_prev() { @@ -3160,19 +3212,16 @@ impl<'a, K: Ord, V, A: Allocator + Clone> CursorMutKey<'a, K, V, A> { Ok(()) } - /// Inserts a new element into the `BTreeMap` in the gap that the - /// `CursorMutKey` is currently pointing to. + /// Inserts a new key-value pair into the map in the gap that the + /// cursor is currently pointing to. /// /// After the insertion the cursor will be pointing at the gap after the /// newly inserted element. /// - /// # Panics - /// - /// This function panics if: - /// - the given key compares greater than or equal to the current element - /// (if any). - /// - the given key compares less than or equal to the previous element (if - /// any). + /// If the inserted key is not greater than the key before the cursor + /// (if any), or if it not less than the key after the cursor (if any), + /// then an [`UnorderedKeyError`] is returned since this would + /// invalidate the [`Ord`] invariant between the keys of the map. #[unstable(feature = "btree_cursors", issue = "107540")] pub fn insert_before(&mut self, key: K, value: V) -> Result<(), UnorderedKeyError> { if let Some((prev, _)) = self.peek_prev() { @@ -3239,10 +3288,10 @@ impl<'a, K: Ord, V, A: Allocator + Clone> CursorMutKey<'a, K, V, A> { } impl<'a, K: Ord, V, A: Allocator + Clone> CursorMut<'a, K, V, A> { - /// Inserts a new element into the `BTreeMap` in the gap that the - /// `CursorMut` is currently pointing to. + /// Inserts a new key-value pair into the map in the gap that the + /// cursor is currently pointing to. /// - /// After the insertion the cursor will be pointing at the gap before the + /// After the insertion the cursor will be pointing at the gap after the /// newly inserted element. /// /// # Safety @@ -3257,8 +3306,8 @@ impl<'a, K: Ord, V, A: Allocator + Clone> CursorMut<'a, K, V, A> { unsafe { self.inner.insert_after_unchecked(key, value) } } - /// Inserts a new element into the `BTreeMap` in the gap that the - /// `CursorMut` is currently pointing to. + /// Inserts a new key-value pair into the map in the gap that the + /// cursor is currently pointing to. /// /// After the insertion the cursor will be pointing at the gap after the /// newly inserted element. @@ -3275,37 +3324,31 @@ impl<'a, K: Ord, V, A: Allocator + Clone> CursorMut<'a, K, V, A> { unsafe { self.inner.insert_before_unchecked(key, value) } } - /// Inserts a new element into the `BTreeMap` in the gap that the - /// `CursorMut` is currently pointing to. + /// Inserts a new key-value pair into the map in the gap that the + /// cursor is currently pointing to. /// /// After the insertion the cursor will be pointing at the gap before the /// newly inserted element. /// - /// # Panics - /// - /// This function panics if: - /// - the given key compares less than or equal to the current element (if - /// any). - /// - the given key compares greater than or equal to the next element (if - /// any). + /// If the inserted key is not greater than the key before the cursor + /// (if any), or if it not less than the key after the cursor (if any), + /// then an [`UnorderedKeyError`] is returned since this would + /// invalidate the [`Ord`] invariant between the keys of the map. #[unstable(feature = "btree_cursors", issue = "107540")] pub fn insert_after(&mut self, key: K, value: V) -> Result<(), UnorderedKeyError> { self.inner.insert_after(key, value) } - /// Inserts a new element into the `BTreeMap` in the gap that the - /// `CursorMut` is currently pointing to. + /// Inserts a new key-value pair into the map in the gap that the + /// cursor is currently pointing to. /// /// After the insertion the cursor will be pointing at the gap after the /// newly inserted element. /// - /// # Panics - /// - /// This function panics if: - /// - the given key compares greater than or equal to the current element - /// (if any). - /// - the given key compares less than or equal to the previous element (if - /// any). + /// If the inserted key is not greater than the key before the cursor + /// (if any), or if it not less than the key after the cursor (if any), + /// then an [`UnorderedKeyError`] is returned since this would + /// invalidate the [`Ord`] invariant between the keys of the map. #[unstable(feature = "btree_cursors", issue = "107540")] pub fn insert_before(&mut self, key: K, value: V) -> Result<(), UnorderedKeyError> { self.inner.insert_before(key, value) From f4153390527cc6396d19f68097d34a7a3a1e7edb Mon Sep 17 00:00:00 2001 From: ripytide Date: Sun, 11 Feb 2024 16:18:40 +0000 Subject: [PATCH 15/56] fix incorrect doctest --- library/alloc/src/collections/btree/map.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs index 724a070818d..770b68c3dde 100644 --- a/library/alloc/src/collections/btree/map.rs +++ b/library/alloc/src/collections/btree/map.rs @@ -2673,8 +2673,8 @@ impl BTreeMap { /// ]); /// /// let cursor = map.upper_bound(Bound::Included(&3)); - /// assert_eq!(cursor.peek_prev(), Some((&3, &"d"))); - /// assert_eq!(cursor.peek_next(), Some((&4, &"c"))); + /// assert_eq!(cursor.peek_prev(), Some((&3, &"c"))); + /// assert_eq!(cursor.peek_next(), Some((&4, &"d"))); /// /// let cursor = map.upper_bound(Bound::Excluded(&3)); /// assert_eq!(cursor.peek_prev(), Some((&2, &"b"))); From 4a2939bcd24f6bf81bd8e1e82f349c783bca89e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Sat, 30 Dec 2023 19:47:31 +0100 Subject: [PATCH 16/56] Gate PR CI on clippy correctness lints --- src/ci/docker/host-x86_64/mingw-check/Dockerfile | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/ci/docker/host-x86_64/mingw-check/Dockerfile b/src/ci/docker/host-x86_64/mingw-check/Dockerfile index f8fcda5070f..30d3a52d82b 100644 --- a/src/ci/docker/host-x86_64/mingw-check/Dockerfile +++ b/src/ci/docker/host-x86_64/mingw-check/Dockerfile @@ -40,13 +40,9 @@ COPY host-x86_64/mingw-check/validate-error-codes.sh /scripts/ ENV RUN_CHECK_WITH_PARALLEL_QUERIES 1 -# Run clippy just to make sure it doesn't error out; we don't actually want to gate on the warnings -# though. -# Ideally we'd use stage 1, but that ICEs: https://github.com/rust-lang/rust-clippy/issues/11230 - ENV SCRIPT python3 ../x.py --stage 2 test src/tools/expand-yaml-anchors && \ python3 ../x.py check --target=i686-pc-windows-gnu --host=i686-pc-windows-gnu && \ - python3 ../x.py clippy --stage 0 -Awarnings && \ + python3 ../x.py clippy compiler -Aclippy::all -Dclippy::correctness && \ python3 ../x.py build --stage 0 src/tools/build-manifest && \ python3 ../x.py test --stage 0 src/tools/compiletest && \ python3 ../x.py test --stage 0 core alloc std test proc_macro && \ From 9789e88cfe7f50ac46d04175e32df4329d75024e Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 11 Feb 2024 19:17:42 +0000 Subject: [PATCH 17/56] Check that the ABI of the instance we are inlining is correct --- compiler/rustc_mir_transform/src/inline.rs | 12 ++++++++ tests/ui/mir/inline-wrong-abi.rs | 32 ++++++++++++++++++++++ tests/ui/mir/inline-wrong-abi.stderr | 12 ++++++++ 3 files changed, 56 insertions(+) create mode 100644 tests/ui/mir/inline-wrong-abi.rs create mode 100644 tests/ui/mir/inline-wrong-abi.stderr diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs index be19bd8349e..956d855ab81 100644 --- a/compiler/rustc_mir_transform/src/inline.rs +++ b/compiler/rustc_mir_transform/src/inline.rs @@ -2,6 +2,7 @@ use crate::deref_separator::deref_finder; use rustc_attr::InlineAttr; use rustc_const_eval::transform::validate::validate_types; +use rustc_hir::def::DefKind; use rustc_hir::def_id::DefId; use rustc_index::bit_set::BitSet; use rustc_index::Idx; @@ -384,6 +385,17 @@ impl<'tcx> Inliner<'tcx> { } let fn_sig = self.tcx.fn_sig(def_id).instantiate(self.tcx, args); + + // Additionally, check that the body that we're inlining actually agrees + // with the ABI of the trait that the item comes from. + if let InstanceDef::Item(instance_def_id) = callee.def + && self.tcx.def_kind(instance_def_id) == DefKind::AssocFn + && let instance_fn_sig = self.tcx.fn_sig(instance_def_id).skip_binder() + && instance_fn_sig.abi() != fn_sig.abi() + { + return None; + } + let source_info = SourceInfo { span: fn_span, ..terminator.source_info }; return Some(CallSite { callee, fn_sig, block: bb, source_info }); diff --git a/tests/ui/mir/inline-wrong-abi.rs b/tests/ui/mir/inline-wrong-abi.rs new file mode 100644 index 00000000000..1f61a5dcfbe --- /dev/null +++ b/tests/ui/mir/inline-wrong-abi.rs @@ -0,0 +1,32 @@ +// compile-flags: -Zpolymorphize=on -Zinline-mir=yes -Zmir-opt-level=0 + +#![feature(fn_traits, unboxed_closures)] +struct Foo(T); + +impl Fn<()> for Foo { + extern "C" fn call(&self, _: ()) -> T { + //~^ ERROR method `call` has an incompatible type for trait + match *self { + Foo(t) => t, + } + } +} + +impl FnMut<()> for Foo { + extern "rust-call" fn call_mut(&mut self, _: ()) -> T { + self.call(()) + } +} + +impl FnOnce<()> for Foo { + type Output = T; + + extern "rust-call" fn call_once(self, _: ()) -> T { + self.call(()) + } +} + +fn main() { + let t: u8 = 1; + println!("{}", Foo(t)()); +} diff --git a/tests/ui/mir/inline-wrong-abi.stderr b/tests/ui/mir/inline-wrong-abi.stderr new file mode 100644 index 00000000000..e44899eb92a --- /dev/null +++ b/tests/ui/mir/inline-wrong-abi.stderr @@ -0,0 +1,12 @@ +error[E0053]: method `call` has an incompatible type for trait + --> $DIR/inline-wrong-abi.rs:7:5 + | +LL | extern "C" fn call(&self, _: ()) -> T { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected "rust-call" fn, found "C" fn + | + = note: expected signature `extern "rust-call" fn(&Foo<_>, ()) -> _` + found signature `extern "C" fn(&Foo<_>, ()) -> _` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0053`. From f34d9da7db8447e5616f964bfa65b09a7b45ba3a Mon Sep 17 00:00:00 2001 From: ripytide Date: Sun, 11 Feb 2024 17:15:43 +0000 Subject: [PATCH 18/56] fix intra-doc links --- library/alloc/src/collections/btree/map.rs | 24 +++++++++++----------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs index 770b68c3dde..2b8ddf14ff3 100644 --- a/library/alloc/src/collections/btree/map.rs +++ b/library/alloc/src/collections/btree/map.rs @@ -2525,13 +2525,13 @@ impl BTreeMap { /// Returns a [`Cursor`] pointing at the gap before the smallest key /// greater than the given bound. /// - /// Passing [`Bound::Included(x)`] will return a cursor pointing to the + /// Passing `Bound::Included(x)` will return a cursor pointing to the /// gap before the smallest key greater than or equal to `x`. /// - /// Passing [`Bound::Excluded(x)`] will return a cursor pointing to the + /// Passing `Bound::Excluded(x)` will return a cursor pointing to the /// gap before the smallest key greater than `x`. /// - /// Passing [`Bound::Unbounded`] will return a cursor pointing to the + /// Passing `Bound::Unbounded` will return a cursor pointing to the /// gap before the smallest key in the map. /// /// # Examples @@ -2578,13 +2578,13 @@ impl BTreeMap { /// Returns a [`CursorMut`] pointing at the gap before the smallest key /// greater than the given bound. /// - /// Passing [`Bound::Included(x)`] will return a cursor pointing to the + /// Passing `Bound::Included(x)` will return a cursor pointing to the /// gap before the smallest key greater than or equal to `x`. /// - /// Passing [`Bound::Excluded(x)`] will return a cursor pointing to the + /// Passing `Bound::Excluded(x)` will return a cursor pointing to the /// gap before the smallest key greater than `x`. /// - /// Passing [`Bound::Unbounded`] will return a cursor pointing to the + /// Passing `Bound::Unbounded` will return a cursor pointing to the /// gap before the smallest key in the map. /// /// # Examples @@ -2648,13 +2648,13 @@ impl BTreeMap { /// Returns a [`Cursor`] pointing at the gap after the greatest key /// smaller than the given bound. /// - /// Passing [`Bound::Included(x)`] will return a cursor pointing to the + /// Passing `Bound::Included(x)` will return a cursor pointing to the /// gap after the greatest key smaller than or equal to `x`. /// - /// Passing [`Bound::Excluded(x)`] will return a cursor pointing to the + /// Passing `Bound::Excluded(x)` will return a cursor pointing to the /// gap after the greatest key smaller than `x`. /// - /// Passing [`Bound::Unbounded`] will return a cursor pointing to the + /// Passing `Bound::Unbounded` will return a cursor pointing to the /// gap after the greatest key in the map. /// /// # Examples @@ -2701,13 +2701,13 @@ impl BTreeMap { /// Returns a [`CursorMut`] pointing at the gap after the greatest key /// smaller than the given bound. /// - /// Passing [`Bound::Included(x)`] will return a cursor pointing to the + /// Passing `Bound::Included(x)` will return a cursor pointing to the /// gap after the greatest key smaller than or equal to `x`. /// - /// Passing [`Bound::Excluded(x)`] will return a cursor pointing to the + /// Passing `Bound::Excluded(x)` will return a cursor pointing to the /// gap after the greatest key smaller than `x`. /// - /// Passing [`Bound::Unbounded`] will return a cursor pointing to the + /// Passing `Bound::Unbounded` will return a cursor pointing to the /// gap after the greatest key in the map. /// /// # Examples From cb024ba6e386242c5bea20fcc613c7edbc48f290 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 11 Feb 2024 21:36:12 +0000 Subject: [PATCH 19/56] is_closure_like --- .../src/diagnostics/conflict_errors.rs | 4 ++-- .../src/diagnostics/mutability_errors.rs | 11 +++++------ .../src/type_check/input_output.rs | 2 +- compiler/rustc_codegen_llvm/src/attributes.rs | 2 +- compiler/rustc_codegen_ssa/src/codegen_attrs.rs | 6 +++--- .../src/transform/check_consts/mod.rs | 2 +- compiler/rustc_hir/src/def.rs | 6 ++++++ compiler/rustc_hir_typeck/src/check.rs | 3 +-- compiler/rustc_hir_typeck/src/gather_locals.rs | 2 +- compiler/rustc_middle/src/mir/pretty.rs | 2 +- compiler/rustc_middle/src/ty/closure.rs | 4 ++-- compiler/rustc_middle/src/ty/instance.rs | 7 ++----- compiler/rustc_middle/src/ty/util.rs | 16 +++++++++------- .../src/coverage/spans/from_mir.rs | 4 ++-- compiler/rustc_monomorphize/src/collector.rs | 2 +- compiler/rustc_passes/src/upvars.rs | 2 +- .../clippy/clippy_lints/src/redundant_locals.rs | 2 +- 17 files changed, 40 insertions(+), 37 deletions(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index f87269960bc..c6d312c922c 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -3161,7 +3161,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { ) -> Option> { // Define a fallback for when we can't match a closure. let fallback = || { - let is_closure = self.infcx.tcx.is_closure_or_coroutine(self.mir_def_id().to_def_id()); + let is_closure = self.infcx.tcx.is_closure_like(self.mir_def_id().to_def_id()); if is_closure { None } else { @@ -3372,7 +3372,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { sig: ty::PolyFnSig<'tcx>, ) -> Option> { debug!("annotate_fn_sig: did={:?} sig={:?}", did, sig); - let is_closure = self.infcx.tcx.is_closure_or_coroutine(did.to_def_id()); + let is_closure = self.infcx.tcx.is_closure_like(did.to_def_id()); let fn_hir_id = self.infcx.tcx.local_def_id_to_hir_id(did); let fn_decl = self.infcx.tcx.hir().fn_decl_by_hir_id(fn_hir_id)?; diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index 9e7fd45ec19..350645e0734 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -67,7 +67,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { local, projection: [proj_base @ .., ProjectionElem::Field(upvar_index, _)], } => { - debug_assert!(is_closure_or_coroutine( + debug_assert!(is_closure_like( Place::ty_from(local, proj_base, self.body, self.infcx.tcx).ty )); @@ -126,9 +126,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { { item_msg = access_place_desc; debug_assert!(self.body.local_decls[ty::CAPTURE_STRUCT_LOCAL].ty.is_ref()); - debug_assert!(is_closure_or_coroutine( - the_place_err.ty(self.body, self.infcx.tcx).ty - )); + debug_assert!(is_closure_like(the_place_err.ty(self.body, self.infcx.tcx).ty)); reason = if self.is_upvar_field_projection(access_place.as_ref()).is_some() { ", as it is a captured variable in a `Fn` closure".to_string() @@ -389,7 +387,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { local, projection: [proj_base @ .., ProjectionElem::Field(upvar_index, _)], } => { - debug_assert!(is_closure_or_coroutine( + debug_assert!(is_closure_like( Place::ty_from(local, proj_base, self.body, self.infcx.tcx).ty )); @@ -1474,7 +1472,8 @@ fn suggest_ampmut<'tcx>( } } -fn is_closure_or_coroutine(ty: Ty<'_>) -> bool { +/// If the type is a `Coroutine`, `Closure`, or `CoroutineClosure` +fn is_closure_like(ty: Ty<'_>) -> bool { ty.is_closure() || ty.is_coroutine() || ty.is_coroutine_closure() } diff --git a/compiler/rustc_borrowck/src/type_check/input_output.rs b/compiler/rustc_borrowck/src/type_check/input_output.rs index a5a7ce4ea3e..af5b635ae66 100644 --- a/compiler/rustc_borrowck/src/type_check/input_output.rs +++ b/compiler/rustc_borrowck/src/type_check/input_output.rs @@ -29,7 +29,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { pub(super) fn check_signature_annotation(&mut self, body: &Body<'tcx>) { let mir_def_id = body.source.def_id().expect_local(); - if !self.tcx().is_closure_or_coroutine(mir_def_id.to_def_id()) { + if !self.tcx().is_closure_like(mir_def_id.to_def_id()) { return; } diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs index 07c83f1aa08..f9eaa0d94cb 100644 --- a/compiler/rustc_codegen_llvm/src/attributes.rs +++ b/compiler/rustc_codegen_llvm/src/attributes.rs @@ -479,7 +479,7 @@ pub fn from_fn_attrs<'ll, 'tcx>( // `+multivalue` feature because the purpose of the wasm abi is to match // the WebAssembly specification, which has this feature. This won't be // needed when LLVM enables this `multivalue` feature by default. - if !cx.tcx.is_closure_or_coroutine(instance.def_id()) { + if !cx.tcx.is_closure_like(instance.def_id()) { let abi = cx.tcx.fn_sig(instance.def_id()).skip_binder().abi(); if abi == Abi::Wasm { function_features.push("+multivalue".to_string()); diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index b387d0b2258..9e23757fcee 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -229,7 +229,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { } sym::thread_local => codegen_fn_attrs.flags |= CodegenFnAttrFlags::THREAD_LOCAL, sym::track_caller => { - let is_closure = tcx.is_closure_or_coroutine(did.to_def_id()); + let is_closure = tcx.is_closure_like(did.to_def_id()); if !is_closure && let Some(fn_sig) = fn_sig() @@ -274,7 +274,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { } } sym::target_feature => { - if !tcx.is_closure_or_coroutine(did.to_def_id()) + if !tcx.is_closure_like(did.to_def_id()) && let Some(fn_sig) = fn_sig() && fn_sig.skip_binder().unsafety() == hir::Unsafety::Normal { @@ -529,7 +529,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { // would result in this closure being compiled without the inherited target features, but this // is probably a poor usage of `#[inline(always)]` and easily avoided by not using the attribute. if tcx.features().target_feature_11 - && tcx.is_closure_or_coroutine(did.to_def_id()) + && tcx.is_closure_like(did.to_def_id()) && codegen_fn_attrs.inline != InlineAttr::Always { let owner_id = tcx.parent(did.to_def_id()); diff --git a/compiler/rustc_const_eval/src/transform/check_consts/mod.rs b/compiler/rustc_const_eval/src/transform/check_consts/mod.rs index 98276ff2e68..0eaeb8b8089 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/mod.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/mod.rs @@ -72,7 +72,7 @@ impl<'mir, 'tcx> ConstCx<'mir, 'tcx> { pub fn fn_sig(&self) -> PolyFnSig<'tcx> { let did = self.def_id().to_def_id(); - if self.tcx.is_closure_or_coroutine(did) { + if self.tcx.is_closure_like(did) { let ty = self.tcx.type_of(did).instantiate_identity(); let ty::Closure(_, args) = ty.kind() else { bug!("type_of closure not ty::Closure") }; args.as_closure().sig() diff --git a/compiler/rustc_hir/src/def.rs b/compiler/rustc_hir/src/def.rs index 81ec7ddb629..a0f7a30c2c3 100644 --- a/compiler/rustc_hir/src/def.rs +++ b/compiler/rustc_hir/src/def.rs @@ -115,6 +115,12 @@ pub enum DefKind { Impl { of_trait: bool, }, + /// A closure, coroutine, or coroutine-closure. + /// + /// These are all represented with the same `ExprKind::Closure` in the AST and HIR, + /// which makes it difficult to distinguish these during def collection. Therefore, + /// we treat them all the same, and code which needs to distinguish them can match + /// or `hir::ClosureKind` or `type_of`. Closure, } diff --git a/compiler/rustc_hir_typeck/src/check.rs b/compiler/rustc_hir_typeck/src/check.rs index aab78465f8c..be68b598e76 100644 --- a/compiler/rustc_hir_typeck/src/check.rs +++ b/compiler/rustc_hir_typeck/src/check.rs @@ -90,8 +90,7 @@ pub(super) fn check_fn<'a, 'tcx>( // ty.span == binding_span iff this is a closure parameter with no type ascription, // or if it's an implicit `self` parameter traits::SizedArgumentType( - if ty_span == Some(param.span) && tcx.is_closure_or_coroutine(fn_def_id.into()) - { + if ty_span == Some(param.span) && tcx.is_closure_like(fn_def_id.into()) { None } else { ty.map(|ty| ty.hir_id) diff --git a/compiler/rustc_hir_typeck/src/gather_locals.rs b/compiler/rustc_hir_typeck/src/gather_locals.rs index f9af357f0e7..4d37f725c94 100644 --- a/compiler/rustc_hir_typeck/src/gather_locals.rs +++ b/compiler/rustc_hir_typeck/src/gather_locals.rs @@ -153,7 +153,7 @@ impl<'a, 'tcx> Visitor<'tcx> for GatherLocalsVisitor<'a, 'tcx> { // ascription, or if it's an implicit `self` parameter traits::SizedArgumentType( if ty_span == ident.span - && self.fcx.tcx.is_closure_or_coroutine(self.fcx.body_id.into()) + && self.fcx.tcx.is_closure_like(self.fcx.body_id.into()) { None } else { diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index b601b465668..a011f6114de 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -491,7 +491,7 @@ fn write_mir_sig(tcx: TyCtxt<'_>, body: &Body<'_>, w: &mut dyn io::Write) -> io: let kind = tcx.def_kind(def_id); let is_function = match kind { DefKind::Fn | DefKind::AssocFn | DefKind::Ctor(..) => true, - _ => tcx.is_closure_or_coroutine(def_id), + _ => tcx.is_closure_like(def_id), }; match (kind, body.source.promoted) { (_, Some(i)) => write!(w, "{i:?} in ")?, diff --git a/compiler/rustc_middle/src/ty/closure.rs b/compiler/rustc_middle/src/ty/closure.rs index 8ff5b135aca..7db64504f85 100644 --- a/compiler/rustc_middle/src/ty/closure.rs +++ b/compiler/rustc_middle/src/ty/closure.rs @@ -197,7 +197,7 @@ pub struct ClosureTypeInfo<'tcx> { } fn closure_typeinfo<'tcx>(tcx: TyCtxt<'tcx>, def: LocalDefId) -> ClosureTypeInfo<'tcx> { - debug_assert!(tcx.is_closure_or_coroutine(def.to_def_id())); + debug_assert!(tcx.is_closure_like(def.to_def_id())); let typeck_results = tcx.typeck(def); let user_provided_sig = typeck_results.user_provided_sigs[&def]; let captures = typeck_results.closure_min_captures_flattened(def); @@ -217,7 +217,7 @@ impl<'tcx> TyCtxt<'tcx> { } pub fn closure_captures(self, def_id: LocalDefId) -> &'tcx [&'tcx ty::CapturedPlace<'tcx>] { - if !self.is_closure_or_coroutine(def_id.to_def_id()) { + if !self.is_closure_like(def_id.to_def_id()) { return &[]; }; self.closure_typeinfo(def_id).captures diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index 8848d216f5b..01b7be98b18 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -465,10 +465,7 @@ impl<'tcx> Instance<'tcx> { ) -> Option> { debug!("resolve(def_id={:?}, args={:?})", def_id, args); // Use either `resolve_closure` or `resolve_for_vtable` - assert!( - !tcx.is_closure_or_coroutine(def_id), - "Called `resolve_for_fn_ptr` on closure: {def_id:?}" - ); + assert!(!tcx.is_closure_like(def_id), "Called `resolve_for_fn_ptr` on closure: {def_id:?}"); Instance::resolve(tcx, param_env, def_id, args).ok().flatten().map(|mut resolved| { match resolved.def { InstanceDef::Item(def) if resolved.def.requires_caller_location(tcx) => { @@ -530,7 +527,7 @@ impl<'tcx> Instance<'tcx> { }) ) { - if tcx.is_closure_or_coroutine(def) { + if tcx.is_closure_like(def) { debug!(" => vtable fn pointer created for closure with #[track_caller]: {:?} for method {:?} {:?}", def, def_id, args); diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index 4feaeb0dd05..c674a868d9f 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -541,13 +541,15 @@ impl<'tcx> TyCtxt<'tcx> { Ok(()) } - /// Returns `true` if `def_id` refers to a closure (e.g., `|x| x * 2`). Note - /// that closures have a `DefId`, but the closure *expression* also - /// has a `HirId` that is located within the context where the - /// closure appears (and, sadly, a corresponding `NodeId`, since - /// those are not yet phased out). The parent of the closure's - /// `DefId` will also be the context where it appears. - pub fn is_closure_or_coroutine(self, def_id: DefId) -> bool { + /// Returns `true` if `def_id` refers to a closure, coroutine, or coroutine-closure + /// (i.e. an async closure). These are all represented by `hir::Closure`, and all + /// have the same `DefKind`. + /// + /// Note that closures have a `DefId`, but the closure *expression* also has a + // `HirId` that is located within the context where the closure appears (and, sadly, + // a corresponding `NodeId`, since those are not yet phased out). The parent of + // the closure's `DefId` will also be the context where it appears. + pub fn is_closure_like(self, def_id: DefId) -> bool { matches!(self.def_kind(def_id), DefKind::Closure) } diff --git a/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs b/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs index 01fae7c0bec..4ac8dde03a6 100644 --- a/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs +++ b/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs @@ -138,7 +138,7 @@ fn bcb_to_initial_coverage_spans<'a, 'tcx>( let (span, visible_macro) = unexpand_into_body_span_with_visible_macro(expn_span, body_span)?; - Some(SpanFromMir::new(span, visible_macro, bcb, is_closure_or_coroutine(statement))) + Some(SpanFromMir::new(span, visible_macro, bcb, is_closure_like(statement))) }); let terminator_span = Some(data.terminator()).into_iter().filter_map(move |terminator| { @@ -153,7 +153,7 @@ fn bcb_to_initial_coverage_spans<'a, 'tcx>( }) } -fn is_closure_or_coroutine(statement: &Statement<'_>) -> bool { +fn is_closure_like(statement: &Statement<'_>) -> bool { match statement.kind { StatementKind::Assign(box (_, Rvalue::Aggregate(box ref agg_kind, _))) => match agg_kind { AggregateKind::Closure(_, _) diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 3376af98653..a771fa86eb7 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -1154,7 +1154,7 @@ fn create_fn_mono_item<'tcx>( let def_id = instance.def_id(); if tcx.sess.opts.unstable_opts.profile_closures && def_id.is_local() - && tcx.is_closure_or_coroutine(def_id) + && tcx.is_closure_like(def_id) { crate::util::dump_closure_profile(tcx, instance); } diff --git a/compiler/rustc_passes/src/upvars.rs b/compiler/rustc_passes/src/upvars.rs index ded20c38543..4d44e8762b0 100644 --- a/compiler/rustc_passes/src/upvars.rs +++ b/compiler/rustc_passes/src/upvars.rs @@ -11,7 +11,7 @@ use rustc_span::Span; pub fn provide(providers: &mut Providers) { providers.upvars_mentioned = |tcx, def_id| { - if !tcx.is_closure_or_coroutine(def_id) { + if !tcx.is_closure_like(def_id) { return None; } diff --git a/src/tools/clippy/clippy_lints/src/redundant_locals.rs b/src/tools/clippy/clippy_lints/src/redundant_locals.rs index 700a5dd4a85..6528a7b369f 100644 --- a/src/tools/clippy/clippy_lints/src/redundant_locals.rs +++ b/src/tools/clippy/clippy_lints/src/redundant_locals.rs @@ -101,7 +101,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantLocals { fn is_by_value_closure_capture(cx: &LateContext<'_>, redefinition: HirId, root_variable: HirId) -> bool { let closure_def_id = cx.tcx.hir().enclosing_body_owner(redefinition); - cx.tcx.is_closure_or_coroutine(closure_def_id.to_def_id()) + cx.tcx.is_closure_like(closure_def_id.to_def_id()) && cx.tcx.closure_captures(closure_def_id).iter().any(|c| { matches!(c.info.capture_kind, UpvarCapture::ByValue) && matches!(c.place.base, PlaceBase::Upvar(upvar) if upvar.var_path.hir_id == root_variable) From 87816378ab4190583df1b74bcfeacb8bc5dd4d70 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 11 Feb 2024 22:09:28 +0000 Subject: [PATCH 20/56] Fix async closures in CTFE --- .../rustc_const_eval/src/interpret/util.rs | 1 + .../src/interpret/validity.rs | 4 +- src/tools/miri/tests/pass/async-closure.rs | 40 +++++++++++++++++++ .../miri/tests/pass/async-closure.stdout | 3 ++ 4 files changed, 46 insertions(+), 2 deletions(-) create mode 100644 src/tools/miri/tests/pass/async-closure.rs create mode 100644 src/tools/miri/tests/pass/async-closure.stdout diff --git a/compiler/rustc_const_eval/src/interpret/util.rs b/compiler/rustc_const_eval/src/interpret/util.rs index 416443f5f4d..52b79203d2b 100644 --- a/compiler/rustc_const_eval/src/interpret/util.rs +++ b/compiler/rustc_const_eval/src/interpret/util.rs @@ -34,6 +34,7 @@ where match *ty.kind() { ty::Param(_) => ControlFlow::Break(FoundParam), ty::Closure(def_id, args) + | ty::CoroutineClosure(def_id, args, ..) | ty::Coroutine(def_id, args, ..) | ty::FnDef(def_id, args) => { let instance = ty::InstanceDef::Item(def_id); diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs index 38aeace02ba..dd14542ad8f 100644 --- a/compiler/rustc_const_eval/src/interpret/validity.rs +++ b/compiler/rustc_const_eval/src/interpret/validity.rs @@ -236,8 +236,8 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' // Now we know we are projecting to a field, so figure out which one. match layout.ty.kind() { - // coroutines and closures. - ty::Closure(def_id, _) | ty::Coroutine(def_id, _) => { + // coroutines, closures, and coroutine-closures all have upvars that may be named. + ty::Closure(def_id, _) | ty::Coroutine(def_id, _) | ty::CoroutineClosure(def_id, _) => { let mut name = None; // FIXME this should be more descriptive i.e. CapturePlace instead of CapturedVar // https://github.com/rust-lang/project-rfc-2229/issues/46 diff --git a/src/tools/miri/tests/pass/async-closure.rs b/src/tools/miri/tests/pass/async-closure.rs new file mode 100644 index 00000000000..9b2fc2948bf --- /dev/null +++ b/src/tools/miri/tests/pass/async-closure.rs @@ -0,0 +1,40 @@ +#![feature(async_closure, noop_waker, async_fn_traits)] + +use std::future::Future; +use std::pin::pin; +use std::task::*; + +pub fn block_on(fut: impl Future) -> T { + let mut fut = pin!(fut); + let ctx = &mut Context::from_waker(Waker::noop()); + + loop { + match fut.as_mut().poll(ctx) { + Poll::Pending => {} + Poll::Ready(t) => break t, + } + } +} + +async fn call_once(f: impl async FnOnce(DropMe)) { + f(DropMe("world")).await; +} + +#[derive(Debug)] +struct DropMe(&'static str); + +impl Drop for DropMe { + fn drop(&mut self) { + println!("{}", self.0); + } +} + +pub fn main() { + block_on(async { + let b = DropMe("hello"); + let async_closure = async move |a: DropMe| { + println!("{a:?} {b:?}"); + }; + call_once(async_closure).await; + }); +} diff --git a/src/tools/miri/tests/pass/async-closure.stdout b/src/tools/miri/tests/pass/async-closure.stdout new file mode 100644 index 00000000000..34cfdedc44a --- /dev/null +++ b/src/tools/miri/tests/pass/async-closure.stdout @@ -0,0 +1,3 @@ +DropMe("world") DropMe("hello") +world +hello From c35983a74817599ab363adf2a6ef6b4cf2e7c5b6 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 8 Feb 2024 16:02:20 +1100 Subject: [PATCH 21/56] Reorder the diagnostic API methods. The current order is almost perfectly random. This commit puts them into a predictable order in their own impl block, going from the highest level (`Block`) to the lowest (`Expect`). Within each level this is the order: - struct_err, err - struct_span_err, span_err - create_err, emit_err The first one in each pair creates a diagnostic, the second one creates *and* emits a diagnostic. Not every method is present for every level. The diff is messy, but other than moving methods around, the only thing it does is create the new `impl DiagCtxt` block with its own comment. --- compiler/rustc_errors/src/lib.rs | 583 ++++++++++++++++--------------- 1 file changed, 294 insertions(+), 289 deletions(-) diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index ab3ad0e9d68..4c0bb763dc1 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -718,217 +718,6 @@ impl DiagCtxt { self.inner.borrow_mut().emit_stashed_diagnostics() } - /// Construct a builder at the `Warning` level at the given `span` and with the `msg`. - /// - /// An `emit` call on the builder will only emit if `can_emit_warnings` is `true`. - #[rustc_lint_diagnostics] - #[track_caller] - pub fn struct_span_warn( - &self, - span: impl Into, - msg: impl Into, - ) -> DiagnosticBuilder<'_, ()> { - self.struct_warn(msg).with_span(span) - } - - /// Construct a builder at the `Warning` level with the `msg`. - /// - /// An `emit` call on the builder will only emit if `can_emit_warnings` is `true`. - #[rustc_lint_diagnostics] - #[track_caller] - pub fn struct_warn(&self, msg: impl Into) -> DiagnosticBuilder<'_, ()> { - DiagnosticBuilder::new(self, Warning, msg) - } - - /// Construct a builder at the `Allow` level with the `msg`. - #[rustc_lint_diagnostics] - #[track_caller] - pub fn struct_allow(&self, msg: impl Into) -> DiagnosticBuilder<'_, ()> { - DiagnosticBuilder::new(self, Allow, msg) - } - - /// Construct a builder at the `Expect` level with the `msg`. - #[rustc_lint_diagnostics] - #[track_caller] - pub fn struct_expect( - &self, - msg: impl Into, - id: LintExpectationId, - ) -> DiagnosticBuilder<'_, ()> { - DiagnosticBuilder::new(self, Expect(id), msg) - } - - /// Construct a builder at the `Error` level at the given `span` and with the `msg`. - #[rustc_lint_diagnostics] - #[track_caller] - pub fn struct_span_err( - &self, - span: impl Into, - msg: impl Into, - ) -> DiagnosticBuilder<'_> { - self.struct_err(msg).with_span(span) - } - - /// Construct a builder at the `Error` level with the `msg`. - // FIXME: This method should be removed (every error should have an associated error code). - #[rustc_lint_diagnostics] - #[track_caller] - pub fn struct_err(&self, msg: impl Into) -> DiagnosticBuilder<'_> { - DiagnosticBuilder::new(self, Error, msg) - } - - /// Construct a builder at the `Fatal` level at the given `span` and with the `msg`. - #[rustc_lint_diagnostics] - #[track_caller] - pub fn struct_span_fatal( - &self, - span: impl Into, - msg: impl Into, - ) -> DiagnosticBuilder<'_, FatalAbort> { - self.struct_fatal(msg).with_span(span) - } - - /// Construct a builder at the `Fatal` level with the `msg`. - #[rustc_lint_diagnostics] - #[track_caller] - pub fn struct_fatal( - &self, - msg: impl Into, - ) -> DiagnosticBuilder<'_, FatalAbort> { - DiagnosticBuilder::new(self, Fatal, msg) - } - - /// Construct a builder at the `Help` level with the `msg`. - #[rustc_lint_diagnostics] - pub fn struct_help(&self, msg: impl Into) -> DiagnosticBuilder<'_, ()> { - DiagnosticBuilder::new(self, Help, msg) - } - - /// Construct a builder at the `Note` level with the `msg`. - #[rustc_lint_diagnostics] - #[track_caller] - pub fn struct_note(&self, msg: impl Into) -> DiagnosticBuilder<'_, ()> { - DiagnosticBuilder::new(self, Note, msg) - } - - /// Construct a builder at the `Bug` level with the `msg`. - #[rustc_lint_diagnostics] - #[track_caller] - pub fn struct_bug(&self, msg: impl Into) -> DiagnosticBuilder<'_, BugAbort> { - DiagnosticBuilder::new(self, Bug, msg) - } - - /// Construct a builder at the `Bug` level at the given `span` with the `msg`. - #[rustc_lint_diagnostics] - #[track_caller] - pub fn struct_span_bug( - &self, - span: impl Into, - msg: impl Into, - ) -> DiagnosticBuilder<'_, BugAbort> { - self.struct_bug(msg).with_span(span) - } - - #[rustc_lint_diagnostics] - #[track_caller] - pub fn span_fatal(&self, span: impl Into, msg: impl Into) -> ! { - self.struct_span_fatal(span, msg).emit() - } - - #[rustc_lint_diagnostics] - #[track_caller] - pub fn span_err( - &self, - span: impl Into, - msg: impl Into, - ) -> ErrorGuaranteed { - self.struct_span_err(span, msg).emit() - } - - #[rustc_lint_diagnostics] - #[track_caller] - pub fn span_warn(&self, span: impl Into, msg: impl Into) { - self.struct_span_warn(span, msg).emit() - } - - #[track_caller] - pub fn span_bug(&self, span: impl Into, msg: impl Into) -> ! { - self.struct_span_bug(span, msg).emit() - } - - /// Ensures that compilation cannot succeed. - /// - /// If this function has been called but no errors have been emitted and - /// compilation succeeds, it will cause an internal compiler error (ICE). - /// - /// This can be used in code paths that should never run on successful compilations. - /// For example, it can be used to create an [`ErrorGuaranteed`] - /// (but you should prefer threading through the [`ErrorGuaranteed`] from an error emission - /// directly). - #[track_caller] - pub fn delayed_bug(&self, msg: impl Into) -> ErrorGuaranteed { - DiagnosticBuilder::::new(self, DelayedBug, msg).emit() - } - - /// Like `delayed_bug`, but takes an additional span. - /// - /// Note: this function used to be called `delay_span_bug`. It was renamed - /// to match similar functions like `span_err`, `span_warn`, etc. - #[track_caller] - pub fn span_delayed_bug( - &self, - sp: impl Into, - msg: impl Into, - ) -> ErrorGuaranteed { - DiagnosticBuilder::::new(self, DelayedBug, msg).with_span(sp).emit() - } - - /// Ensures that a diagnostic is printed. See `Level::GoodPathDelayedBug`. - pub fn good_path_delayed_bug(&self, msg: impl Into) { - DiagnosticBuilder::<()>::new(self, GoodPathDelayedBug, msg).emit() - } - - #[track_caller] - #[rustc_lint_diagnostics] - pub fn span_note(&self, span: impl Into, msg: impl Into) { - self.struct_span_note(span, msg).emit() - } - - #[track_caller] - #[rustc_lint_diagnostics] - pub fn struct_span_note( - &self, - span: impl Into, - msg: impl Into, - ) -> DiagnosticBuilder<'_, ()> { - DiagnosticBuilder::new(self, Note, msg).with_span(span) - } - - #[rustc_lint_diagnostics] - pub fn fatal(&self, msg: impl Into) -> ! { - self.struct_fatal(msg).emit() - } - - #[rustc_lint_diagnostics] - pub fn err(&self, msg: impl Into) -> ErrorGuaranteed { - self.struct_err(msg).emit() - } - - #[rustc_lint_diagnostics] - pub fn warn(&self, msg: impl Into) { - self.struct_warn(msg).emit() - } - - #[rustc_lint_diagnostics] - pub fn note(&self, msg: impl Into) { - self.struct_note(msg).emit() - } - - #[rustc_lint_diagnostics] - pub fn bug(&self, msg: impl Into) -> ! { - self.struct_bug(msg).emit() - } - /// This excludes lint errors, delayed bugs, and stashed errors. #[inline] pub fn err_count(&self) -> usize { @@ -1077,84 +866,6 @@ impl DiagCtxt { self.inner.borrow_mut().emit_diagnostic(diagnostic) } - #[track_caller] - pub fn emit_err<'a>(&'a self, err: impl IntoDiagnostic<'a>) -> ErrorGuaranteed { - self.create_err(err).emit() - } - - #[track_caller] - pub fn create_err<'a>(&'a self, err: impl IntoDiagnostic<'a>) -> DiagnosticBuilder<'a> { - err.into_diagnostic(self, Error) - } - - #[track_caller] - pub fn create_warn<'a>( - &'a self, - warning: impl IntoDiagnostic<'a, ()>, - ) -> DiagnosticBuilder<'a, ()> { - warning.into_diagnostic(self, Warning) - } - - #[track_caller] - pub fn emit_warn<'a>(&'a self, warning: impl IntoDiagnostic<'a, ()>) { - self.create_warn(warning).emit() - } - - #[track_caller] - pub fn create_almost_fatal<'a>( - &'a self, - fatal: impl IntoDiagnostic<'a, FatalError>, - ) -> DiagnosticBuilder<'a, FatalError> { - fatal.into_diagnostic(self, Fatal) - } - - #[track_caller] - pub fn emit_almost_fatal<'a>( - &'a self, - fatal: impl IntoDiagnostic<'a, FatalError>, - ) -> FatalError { - self.create_almost_fatal(fatal).emit() - } - - #[track_caller] - pub fn create_fatal<'a>( - &'a self, - fatal: impl IntoDiagnostic<'a, FatalAbort>, - ) -> DiagnosticBuilder<'a, FatalAbort> { - fatal.into_diagnostic(self, Fatal) - } - - #[track_caller] - pub fn emit_fatal<'a>(&'a self, fatal: impl IntoDiagnostic<'a, FatalAbort>) -> ! { - self.create_fatal(fatal).emit() - } - - #[track_caller] - pub fn create_bug<'a>( - &'a self, - bug: impl IntoDiagnostic<'a, BugAbort>, - ) -> DiagnosticBuilder<'a, BugAbort> { - bug.into_diagnostic(self, Bug) - } - - #[track_caller] - pub fn emit_bug<'a>(&'a self, bug: impl IntoDiagnostic<'a, diagnostic_builder::BugAbort>) -> ! { - self.create_bug(bug).emit() - } - - #[track_caller] - pub fn emit_note<'a>(&'a self, note: impl IntoDiagnostic<'a, ()>) { - self.create_note(note).emit() - } - - #[track_caller] - pub fn create_note<'a>( - &'a self, - note: impl IntoDiagnostic<'a, ()>, - ) -> DiagnosticBuilder<'a, ()> { - note.into_diagnostic(self, Note) - } - pub fn emit_artifact_notification(&self, path: &Path, artifact_type: &str) { self.inner.borrow_mut().emitter.emit_artifact_notification(path, artifact_type); } @@ -1229,6 +940,300 @@ impl DiagCtxt { } } +// This `impl` block contains only the public diagnostic creation/emission API. +// +// Functions beginning with `struct_`/`create_` create a diagnostic. Other +// functions create and emit a diagnostic all in one go. +impl DiagCtxt { + /// Construct a builder at the `Bug` level with the `msg`. + #[rustc_lint_diagnostics] + #[track_caller] + pub fn struct_bug(&self, msg: impl Into) -> DiagnosticBuilder<'_, BugAbort> { + DiagnosticBuilder::new(self, Bug, msg) + } + + #[rustc_lint_diagnostics] + pub fn bug(&self, msg: impl Into) -> ! { + self.struct_bug(msg).emit() + } + + /// Construct a builder at the `Bug` level at the given `span` with the `msg`. + #[rustc_lint_diagnostics] + #[track_caller] + pub fn struct_span_bug( + &self, + span: impl Into, + msg: impl Into, + ) -> DiagnosticBuilder<'_, BugAbort> { + self.struct_bug(msg).with_span(span) + } + + pub fn span_bug(&self, span: impl Into, msg: impl Into) -> ! { + self.struct_span_bug(span, msg).emit() + } + + #[track_caller] + pub fn create_bug<'a>( + &'a self, + bug: impl IntoDiagnostic<'a, BugAbort>, + ) -> DiagnosticBuilder<'a, BugAbort> { + bug.into_diagnostic(self, Bug) + } + + #[track_caller] + pub fn emit_bug<'a>(&'a self, bug: impl IntoDiagnostic<'a, diagnostic_builder::BugAbort>) -> ! { + self.create_bug(bug).emit() + } + + /// Construct a builder at the `Fatal` level with the `msg`. + #[rustc_lint_diagnostics] + #[track_caller] + pub fn struct_fatal( + &self, + msg: impl Into, + ) -> DiagnosticBuilder<'_, FatalAbort> { + DiagnosticBuilder::new(self, Fatal, msg) + } + + #[rustc_lint_diagnostics] + pub fn fatal(&self, msg: impl Into) -> ! { + self.struct_fatal(msg).emit() + } + + /// Construct a builder at the `Fatal` level at the given `span` and with the `msg`. + #[rustc_lint_diagnostics] + #[track_caller] + pub fn struct_span_fatal( + &self, + span: impl Into, + msg: impl Into, + ) -> DiagnosticBuilder<'_, FatalAbort> { + self.struct_fatal(msg).with_span(span) + } + + #[rustc_lint_diagnostics] + #[track_caller] + pub fn span_fatal(&self, span: impl Into, msg: impl Into) -> ! { + self.struct_span_fatal(span, msg).emit() + } + + #[track_caller] + pub fn create_fatal<'a>( + &'a self, + fatal: impl IntoDiagnostic<'a, FatalAbort>, + ) -> DiagnosticBuilder<'a, FatalAbort> { + fatal.into_diagnostic(self, Fatal) + } + + #[track_caller] + pub fn emit_fatal<'a>(&'a self, fatal: impl IntoDiagnostic<'a, FatalAbort>) -> ! { + self.create_fatal(fatal).emit() + } + + #[track_caller] + pub fn create_almost_fatal<'a>( + &'a self, + fatal: impl IntoDiagnostic<'a, FatalError>, + ) -> DiagnosticBuilder<'a, FatalError> { + fatal.into_diagnostic(self, Fatal) + } + + #[track_caller] + pub fn emit_almost_fatal<'a>( + &'a self, + fatal: impl IntoDiagnostic<'a, FatalError>, + ) -> FatalError { + self.create_almost_fatal(fatal).emit() + } + + /// Construct a builder at the `Error` level with the `msg`. + // FIXME: This method should be removed (every error should have an associated error code). + #[rustc_lint_diagnostics] + #[track_caller] + pub fn struct_err(&self, msg: impl Into) -> DiagnosticBuilder<'_> { + DiagnosticBuilder::new(self, Error, msg) + } + + #[rustc_lint_diagnostics] + pub fn err(&self, msg: impl Into) -> ErrorGuaranteed { + self.struct_err(msg).emit() + } + + /// Construct a builder at the `Error` level at the given `span` and with the `msg`. + #[rustc_lint_diagnostics] + #[track_caller] + pub fn struct_span_err( + &self, + span: impl Into, + msg: impl Into, + ) -> DiagnosticBuilder<'_> { + self.struct_err(msg).with_span(span) + } + + #[rustc_lint_diagnostics] + #[track_caller] + pub fn span_err( + &self, + span: impl Into, + msg: impl Into, + ) -> ErrorGuaranteed { + self.struct_span_err(span, msg).emit() + } + + #[track_caller] + pub fn create_err<'a>(&'a self, err: impl IntoDiagnostic<'a>) -> DiagnosticBuilder<'a> { + err.into_diagnostic(self, Error) + } + + #[track_caller] + pub fn emit_err<'a>(&'a self, err: impl IntoDiagnostic<'a>) -> ErrorGuaranteed { + self.create_err(err).emit() + } + + /// Ensures that compilation cannot succeed. + /// + /// If this function has been called but no errors have been emitted and + /// compilation succeeds, it will cause an internal compiler error (ICE). + /// + /// This can be used in code paths that should never run on successful compilations. + /// For example, it can be used to create an [`ErrorGuaranteed`] + /// (but you should prefer threading through the [`ErrorGuaranteed`] from an error emission + /// directly). + #[track_caller] + pub fn delayed_bug(&self, msg: impl Into) -> ErrorGuaranteed { + DiagnosticBuilder::::new(self, DelayedBug, msg).emit() + } + + /// Like `delayed_bug`, but takes an additional span. + /// + /// Note: this function used to be called `delay_span_bug`. It was renamed + /// to match similar functions like `span_err`, `span_warn`, etc. + #[track_caller] + pub fn span_delayed_bug( + &self, + sp: impl Into, + msg: impl Into, + ) -> ErrorGuaranteed { + DiagnosticBuilder::::new(self, DelayedBug, msg).with_span(sp).emit() + } + + /// Ensures that a diagnostic is printed. See `Level::GoodPathDelayedBug`. + pub fn good_path_delayed_bug(&self, msg: impl Into) { + DiagnosticBuilder::<()>::new(self, GoodPathDelayedBug, msg).emit() + } + + /// Construct a builder at the `Warning` level with the `msg`. + /// + /// An `emit` call on the builder will only emit if `can_emit_warnings` is `true`. + #[rustc_lint_diagnostics] + #[track_caller] + pub fn struct_warn(&self, msg: impl Into) -> DiagnosticBuilder<'_, ()> { + DiagnosticBuilder::new(self, Warning, msg) + } + + #[rustc_lint_diagnostics] + pub fn warn(&self, msg: impl Into) { + self.struct_warn(msg).emit() + } + + /// Construct a builder at the `Warning` level at the given `span` and with the `msg`. + /// + /// An `emit` call on the builder will only emit if `can_emit_warnings` is `true`. + #[rustc_lint_diagnostics] + #[track_caller] + pub fn struct_span_warn( + &self, + span: impl Into, + msg: impl Into, + ) -> DiagnosticBuilder<'_, ()> { + self.struct_warn(msg).with_span(span) + } + + #[rustc_lint_diagnostics] + #[track_caller] + pub fn span_warn(&self, span: impl Into, msg: impl Into) { + self.struct_span_warn(span, msg).emit() + } + + #[track_caller] + pub fn create_warn<'a>( + &'a self, + warning: impl IntoDiagnostic<'a, ()>, + ) -> DiagnosticBuilder<'a, ()> { + warning.into_diagnostic(self, Warning) + } + + #[track_caller] + pub fn emit_warn<'a>(&'a self, warning: impl IntoDiagnostic<'a, ()>) { + self.create_warn(warning).emit() + } + + /// Construct a builder at the `Note` level with the `msg`. + #[rustc_lint_diagnostics] + #[track_caller] + pub fn struct_note(&self, msg: impl Into) -> DiagnosticBuilder<'_, ()> { + DiagnosticBuilder::new(self, Note, msg) + } + + #[rustc_lint_diagnostics] + pub fn note(&self, msg: impl Into) { + self.struct_note(msg).emit() + } + + #[track_caller] + #[rustc_lint_diagnostics] + pub fn struct_span_note( + &self, + span: impl Into, + msg: impl Into, + ) -> DiagnosticBuilder<'_, ()> { + DiagnosticBuilder::new(self, Note, msg).with_span(span) + } + + #[track_caller] + #[rustc_lint_diagnostics] + pub fn span_note(&self, span: impl Into, msg: impl Into) { + self.struct_span_note(span, msg).emit() + } + + #[track_caller] + pub fn create_note<'a>( + &'a self, + note: impl IntoDiagnostic<'a, ()>, + ) -> DiagnosticBuilder<'a, ()> { + note.into_diagnostic(self, Note) + } + + #[track_caller] + pub fn emit_note<'a>(&'a self, note: impl IntoDiagnostic<'a, ()>) { + self.create_note(note).emit() + } + + /// Construct a builder at the `Help` level with the `msg`. + #[rustc_lint_diagnostics] + pub fn struct_help(&self, msg: impl Into) -> DiagnosticBuilder<'_, ()> { + DiagnosticBuilder::new(self, Help, msg) + } + + /// Construct a builder at the `Allow` level with the `msg`. + #[rustc_lint_diagnostics] + #[track_caller] + pub fn struct_allow(&self, msg: impl Into) -> DiagnosticBuilder<'_, ()> { + DiagnosticBuilder::new(self, Allow, msg) + } + + /// Construct a builder at the `Expect` level with the `msg`. + #[rustc_lint_diagnostics] + #[track_caller] + pub fn struct_expect( + &self, + msg: impl Into, + id: LintExpectationId, + ) -> DiagnosticBuilder<'_, ()> { + DiagnosticBuilder::new(self, Expect(id), msg) + } +} + // Note: we prefer implementing operations on `DiagCtxt`, rather than // `DiagCtxtInner`, whenever possible. This minimizes functions where // `DiagCtxt::foo()` just borrows `inner` and forwards a call to From b7b6ebca0c0fb38575ae7a48cd324a6008cba3d4 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 8 Feb 2024 16:09:30 +1100 Subject: [PATCH 22/56] Fix inconsistencies in the diagnostic API methods. - Remove low-value comments about functionality that is obvious. - Add missing `track_caller` attributes -- every method should have one. - Adjust `rustc_lint_diagnostic` attributes. Every method involving a `impl Into` or `impl Into` argument should have one, except for those producing bugs, which aren't user-facing. --- compiler/rustc_errors/src/lib.rs | 53 +++++++++++++------------------- 1 file changed, 21 insertions(+), 32 deletions(-) diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 4c0bb763dc1..192df36248e 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -945,20 +945,19 @@ impl DiagCtxt { // Functions beginning with `struct_`/`create_` create a diagnostic. Other // functions create and emit a diagnostic all in one go. impl DiagCtxt { - /// Construct a builder at the `Bug` level with the `msg`. - #[rustc_lint_diagnostics] + // No `#[rustc_lint_diagnostics]` because bug messages aren't user-facing. #[track_caller] pub fn struct_bug(&self, msg: impl Into) -> DiagnosticBuilder<'_, BugAbort> { DiagnosticBuilder::new(self, Bug, msg) } - #[rustc_lint_diagnostics] + // No `#[rustc_lint_diagnostics]` because bug messages aren't user-facing. + #[track_caller] pub fn bug(&self, msg: impl Into) -> ! { self.struct_bug(msg).emit() } - /// Construct a builder at the `Bug` level at the given `span` with the `msg`. - #[rustc_lint_diagnostics] + // No `#[rustc_lint_diagnostics]` because bug messages aren't user-facing. #[track_caller] pub fn struct_span_bug( &self, @@ -968,6 +967,8 @@ impl DiagCtxt { self.struct_bug(msg).with_span(span) } + // No `#[rustc_lint_diagnostics]` because bug messages aren't user-facing. + #[track_caller] pub fn span_bug(&self, span: impl Into, msg: impl Into) -> ! { self.struct_span_bug(span, msg).emit() } @@ -981,11 +982,10 @@ impl DiagCtxt { } #[track_caller] - pub fn emit_bug<'a>(&'a self, bug: impl IntoDiagnostic<'a, diagnostic_builder::BugAbort>) -> ! { + pub fn emit_bug<'a>(&'a self, bug: impl IntoDiagnostic<'a, BugAbort>) -> ! { self.create_bug(bug).emit() } - /// Construct a builder at the `Fatal` level with the `msg`. #[rustc_lint_diagnostics] #[track_caller] pub fn struct_fatal( @@ -996,11 +996,11 @@ impl DiagCtxt { } #[rustc_lint_diagnostics] + #[track_caller] pub fn fatal(&self, msg: impl Into) -> ! { self.struct_fatal(msg).emit() } - /// Construct a builder at the `Fatal` level at the given `span` and with the `msg`. #[rustc_lint_diagnostics] #[track_caller] pub fn struct_span_fatal( @@ -1046,7 +1046,6 @@ impl DiagCtxt { self.create_almost_fatal(fatal).emit() } - /// Construct a builder at the `Error` level with the `msg`. // FIXME: This method should be removed (every error should have an associated error code). #[rustc_lint_diagnostics] #[track_caller] @@ -1055,11 +1054,11 @@ impl DiagCtxt { } #[rustc_lint_diagnostics] + #[track_caller] pub fn err(&self, msg: impl Into) -> ErrorGuaranteed { self.struct_err(msg).emit() } - /// Construct a builder at the `Error` level at the given `span` and with the `msg`. #[rustc_lint_diagnostics] #[track_caller] pub fn struct_span_err( @@ -1090,24 +1089,18 @@ impl DiagCtxt { self.create_err(err).emit() } - /// Ensures that compilation cannot succeed. - /// - /// If this function has been called but no errors have been emitted and - /// compilation succeeds, it will cause an internal compiler error (ICE). - /// - /// This can be used in code paths that should never run on successful compilations. - /// For example, it can be used to create an [`ErrorGuaranteed`] - /// (but you should prefer threading through the [`ErrorGuaranteed`] from an error emission - /// directly). + /// Ensures that an error is printed. See `Level::DelayedBug`. + // No `#[rustc_lint_diagnostics]` because bug messages aren't user-facing. #[track_caller] pub fn delayed_bug(&self, msg: impl Into) -> ErrorGuaranteed { DiagnosticBuilder::::new(self, DelayedBug, msg).emit() } - /// Like `delayed_bug`, but takes an additional span. + /// Ensures that an error is printed. See `Level::DelayedBug`. /// /// Note: this function used to be called `delay_span_bug`. It was renamed /// to match similar functions like `span_err`, `span_warn`, etc. + // No `#[rustc_lint_diagnostics]` because bug messages aren't user-facing. #[track_caller] pub fn span_delayed_bug( &self, @@ -1118,13 +1111,12 @@ impl DiagCtxt { } /// Ensures that a diagnostic is printed. See `Level::GoodPathDelayedBug`. + // No `#[rustc_lint_diagnostics]` because bug messages aren't user-facing. + #[track_caller] pub fn good_path_delayed_bug(&self, msg: impl Into) { DiagnosticBuilder::<()>::new(self, GoodPathDelayedBug, msg).emit() } - /// Construct a builder at the `Warning` level with the `msg`. - /// - /// An `emit` call on the builder will only emit if `can_emit_warnings` is `true`. #[rustc_lint_diagnostics] #[track_caller] pub fn struct_warn(&self, msg: impl Into) -> DiagnosticBuilder<'_, ()> { @@ -1132,13 +1124,11 @@ impl DiagCtxt { } #[rustc_lint_diagnostics] + #[track_caller] pub fn warn(&self, msg: impl Into) { self.struct_warn(msg).emit() } - /// Construct a builder at the `Warning` level at the given `span` and with the `msg`. - /// - /// An `emit` call on the builder will only emit if `can_emit_warnings` is `true`. #[rustc_lint_diagnostics] #[track_caller] pub fn struct_span_warn( @@ -1168,7 +1158,6 @@ impl DiagCtxt { self.create_warn(warning).emit() } - /// Construct a builder at the `Note` level with the `msg`. #[rustc_lint_diagnostics] #[track_caller] pub fn struct_note(&self, msg: impl Into) -> DiagnosticBuilder<'_, ()> { @@ -1176,12 +1165,13 @@ impl DiagCtxt { } #[rustc_lint_diagnostics] + #[track_caller] pub fn note(&self, msg: impl Into) { self.struct_note(msg).emit() } - #[track_caller] #[rustc_lint_diagnostics] + #[track_caller] pub fn struct_span_note( &self, span: impl Into, @@ -1190,8 +1180,8 @@ impl DiagCtxt { DiagnosticBuilder::new(self, Note, msg).with_span(span) } - #[track_caller] #[rustc_lint_diagnostics] + #[track_caller] pub fn span_note(&self, span: impl Into, msg: impl Into) { self.struct_span_note(span, msg).emit() } @@ -1209,20 +1199,18 @@ impl DiagCtxt { self.create_note(note).emit() } - /// Construct a builder at the `Help` level with the `msg`. #[rustc_lint_diagnostics] + #[track_caller] pub fn struct_help(&self, msg: impl Into) -> DiagnosticBuilder<'_, ()> { DiagnosticBuilder::new(self, Help, msg) } - /// Construct a builder at the `Allow` level with the `msg`. #[rustc_lint_diagnostics] #[track_caller] pub fn struct_allow(&self, msg: impl Into) -> DiagnosticBuilder<'_, ()> { DiagnosticBuilder::new(self, Allow, msg) } - /// Construct a builder at the `Expect` level with the `msg`. #[rustc_lint_diagnostics] #[track_caller] pub fn struct_expect( @@ -1589,6 +1577,7 @@ pub enum Level { ForceWarning(Option), /// A warning about the code being compiled. Does not prevent compilation from finishing. + /// Will be skipped if `can_emit_warnings` is false. Warning, /// A message giving additional context. From 2bcbc16caf17351ef3f8d5e9faee98b48387d589 Mon Sep 17 00:00:00 2001 From: yukang Date: Sun, 11 Feb 2024 14:47:30 +0800 Subject: [PATCH 23/56] remove a bunch of dead parameters in fn --- .../src/diagnostics/conflict_errors.rs | 1 - compiler/rustc_borrowck/src/lib.rs | 3 +-- compiler/rustc_borrowck/src/path_utils.rs | 1 - .../src/polonius/loan_invalidations.rs | 1 - .../rustc_borrowck/src/region_infer/mod.rs | 6 +++--- .../src/transform/check_consts/resolver.rs | 8 +++----- .../rustc_hir_analysis/src/check/region.rs | 9 ++------- .../src/impl_wf_check/min_specialization.rs | 6 +----- compiler/rustc_hir_typeck/src/expr.rs | 3 +-- .../rustc_hir_typeck/src/expr_use_visitor.rs | 2 +- .../rustc_hir_typeck/src/mem_categorization.rs | 18 ++++++------------ compiler/rustc_mir_transform/src/coroutine.rs | 4 ++-- .../rustc_mir_transform/src/instsimplify.rs | 15 ++++----------- compiler/rustc_passes/src/check_attr.rs | 4 ++-- .../src/typeid/typeid_itanium_cxx_abi.rs | 14 ++++---------- .../error_reporting/type_err_ctxt_ext.rs | 6 ------ 16 files changed, 30 insertions(+), 71 deletions(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index f87269960bc..d764374a5c9 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -3020,7 +3020,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { /// assignment to `x.f`). pub(crate) fn report_illegal_reassignment( &mut self, - _location: Location, (place, span): (Place<'tcx>, Span), assigned_span: Span, err_place: Place<'tcx>, diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 4dba34c11f9..e8ffab9307e 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -1036,7 +1036,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { self, self.infcx.tcx, self.body, - location, (sd, place_span.0), &borrow_set, |borrow_index| borrows_in_scope.contains(borrow_index), @@ -2174,7 +2173,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { // report the error as an illegal reassignment let init = &self.move_data.inits[init_index]; let assigned_span = init.span(self.body); - self.report_illegal_reassignment(location, (place, span), assigned_span, place); + self.report_illegal_reassignment((place, span), assigned_span, place); } else { self.report_mutability_error(place, span, the_place_err, error_access, location) } diff --git a/compiler/rustc_borrowck/src/path_utils.rs b/compiler/rustc_borrowck/src/path_utils.rs index adafad7fa2f..88b20bba9fb 100644 --- a/compiler/rustc_borrowck/src/path_utils.rs +++ b/compiler/rustc_borrowck/src/path_utils.rs @@ -27,7 +27,6 @@ pub(super) fn each_borrow_involving_path<'tcx, F, I, S>( s: &mut S, tcx: TyCtxt<'tcx>, body: &Body<'tcx>, - _location: Location, access_place: (AccessDepth, Place<'tcx>), borrow_set: &BorrowSet<'tcx>, is_candidate: I, diff --git a/compiler/rustc_borrowck/src/polonius/loan_invalidations.rs b/compiler/rustc_borrowck/src/polonius/loan_invalidations.rs index 93aae1a7f97..10941cadcbb 100644 --- a/compiler/rustc_borrowck/src/polonius/loan_invalidations.rs +++ b/compiler/rustc_borrowck/src/polonius/loan_invalidations.rs @@ -340,7 +340,6 @@ impl<'cx, 'tcx> LoanInvalidationsGenerator<'cx, 'tcx> { self, self.tcx, self.body, - location, (sd, place), self.borrow_set, |_| true, diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index 3153b709ffe..34d60fc8f6e 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -662,7 +662,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { polonius_output: Option>, ) -> (Option>, RegionErrors<'tcx>) { let mir_def_id = body.source.def_id(); - self.propagate_constraints(body); + self.propagate_constraints(); let mut errors_buffer = RegionErrors::new(infcx.tcx); @@ -716,8 +716,8 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// for each region variable until all the constraints are /// satisfied. Note that some values may grow **too** large to be /// feasible, but we check this later. - #[instrument(skip(self, _body), level = "debug")] - fn propagate_constraints(&mut self, _body: &Body<'tcx>) { + #[instrument(skip(self), level = "debug")] + fn propagate_constraints(&mut self) { debug!("constraints={:#?}", { let mut constraints: Vec<_> = self.outlives_constraints().collect(); constraints.sort_by_key(|c| (c.sup, c.sub)); diff --git a/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs b/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs index a23922c778f..2c835f6750f 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs @@ -96,7 +96,7 @@ where }); } - fn address_of_allows_mutation(&self, _mt: mir::Mutability, _place: mir::Place<'tcx>) -> bool { + fn address_of_allows_mutation(&self) -> bool { // Exact set of permissions granted by AddressOf is undecided. Conservatively assume that // it might allow mutation until resolution of #56604. true @@ -171,10 +171,8 @@ where self.super_rvalue(rvalue, location); match rvalue { - mir::Rvalue::AddressOf(mt, borrowed_place) => { - if !borrowed_place.is_indirect() - && self.address_of_allows_mutation(*mt, *borrowed_place) - { + mir::Rvalue::AddressOf(_mt, borrowed_place) => { + if !borrowed_place.is_indirect() && self.address_of_allows_mutation() { let place_ty = borrowed_place.ty(self.ccx.body, self.ccx.tcx).ty; if Q::in_any_value_of_ty(self.ccx, place_ty) { self.state.qualif.insert(borrowed_place.local); diff --git a/compiler/rustc_hir_analysis/src/check/region.rs b/compiler/rustc_hir_analysis/src/check/region.rs index 1c0a1a69513..0f5fd7e99b7 100644 --- a/compiler/rustc_hir_analysis/src/check/region.rs +++ b/compiler/rustc_hir_analysis/src/check/region.rs @@ -16,7 +16,6 @@ use rustc_index::Idx; use rustc_middle::middle::region::*; use rustc_middle::ty::TyCtxt; use rustc_span::source_map; -use rustc_span::Span; use super::errs::{maybe_expr_static_mut, maybe_stmt_static_mut}; @@ -72,11 +71,7 @@ struct RegionResolutionVisitor<'tcx> { } /// Records the lifetime of a local variable as `cx.var_parent` -fn record_var_lifetime( - visitor: &mut RegionResolutionVisitor<'_>, - var_id: hir::ItemLocalId, - _sp: Span, -) { +fn record_var_lifetime(visitor: &mut RegionResolutionVisitor<'_>, var_id: hir::ItemLocalId) { match visitor.cx.var_parent { None => { // this can happen in extern fn declarations like @@ -210,7 +205,7 @@ fn resolve_pat<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, pat: &'tcx hir // If this is a binding then record the lifetime of that binding. if let PatKind::Binding(..) = pat.kind { - record_var_lifetime(visitor, pat.hir_id.local_id, pat.span); + record_var_lifetime(visitor, pat.hir_id.local_id); } debug!("resolve_pat - pre-increment {} pat = {:?}", visitor.expr_and_pat_count, pat); diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs index 1b6a39d8162..ec8ea77b749 100644 --- a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs +++ b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs @@ -425,9 +425,7 @@ fn check_predicates<'tcx>( let mut res = Ok(()); for (clause, span) in impl1_predicates { - if !impl2_predicates - .iter() - .any(|pred2| trait_predicates_eq(tcx, clause.as_predicate(), *pred2, span)) + if !impl2_predicates.iter().any(|pred2| trait_predicates_eq(clause.as_predicate(), *pred2)) { res = res.and(check_specialization_on(tcx, clause, span)) } @@ -459,10 +457,8 @@ fn check_predicates<'tcx>( /// /// So we make that check in this function and try to raise a helpful error message. fn trait_predicates_eq<'tcx>( - _tcx: TyCtxt<'tcx>, predicate1: ty::Predicate<'tcx>, predicate2: ty::Predicate<'tcx>, - _span: Span, ) -> bool { // FIXME(effects) predicate1 == predicate2 diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 292b85eb97f..71d1cef3c9b 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -346,7 +346,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } ExprKind::DropTemps(e) => self.check_expr_with_expectation(e, expected), ExprKind::Array(args) => self.check_expr_array(args, expected, expr), - ExprKind::ConstBlock(ref block) => self.check_expr_const_block(block, expected, expr), + ExprKind::ConstBlock(ref block) => self.check_expr_const_block(block, expected), ExprKind::Repeat(element, ref count) => { self.check_expr_repeat(element, count, expected, expr) } @@ -1493,7 +1493,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &self, block: &'tcx hir::ConstBlock, expected: Expectation<'tcx>, - _expr: &'tcx hir::Expr<'tcx>, ) -> Ty<'tcx> { let body = self.tcx.hir().body(block.body); diff --git a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs index 3ecf6c5e428..04fb7bcf4f3 100644 --- a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs +++ b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs @@ -142,7 +142,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { let param_ty = return_if_err!(self.mc.pat_ty_adjusted(param.pat)); debug!("consume_body: param_ty = {:?}", param_ty); - let param_place = self.mc.cat_rvalue(param.hir_id, param.pat.span, param_ty); + let param_place = self.mc.cat_rvalue(param.hir_id, param_ty); self.walk_irrefutable_pat(¶m_place, param.pat); } diff --git a/compiler/rustc_hir_typeck/src/mem_categorization.rs b/compiler/rustc_hir_typeck/src/mem_categorization.rs index f9297550c57..fefaf996725 100644 --- a/compiler/rustc_hir_typeck/src/mem_categorization.rs +++ b/compiler/rustc_hir_typeck/src/mem_categorization.rs @@ -273,7 +273,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { deref.region, ty::TypeAndMut { ty: target, mutbl: deref.mutbl }, ); - self.cat_rvalue(expr.hir_id, expr.span, ref_ty) + self.cat_rvalue(expr.hir_id, ref_ty) } else { previous()? }; @@ -285,7 +285,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { | adjustment::Adjust::Borrow(_) | adjustment::Adjust::DynStar => { // Result is an rvalue. - Ok(self.cat_rvalue(expr.hir_id, expr.span, target)) + Ok(self.cat_rvalue(expr.hir_id, target)) } } } @@ -374,7 +374,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { | hir::ExprKind::Repeat(..) | hir::ExprKind::InlineAsm(..) | hir::ExprKind::OffsetOf(..) - | hir::ExprKind::Err(_) => Ok(self.cat_rvalue(expr.hir_id, expr.span, expr_ty)), + | hir::ExprKind::Err(_) => Ok(self.cat_rvalue(expr.hir_id, expr_ty)), } } @@ -396,7 +396,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { | DefKind::AssocFn, _, ) - | Res::SelfCtor(..) => Ok(self.cat_rvalue(hir_id, span, expr_ty)), + | Res::SelfCtor(..) => Ok(self.cat_rvalue(hir_id, expr_ty)), Res::Def(DefKind::Static(_), _) => { Ok(PlaceWithHirId::new(hir_id, expr_ty, PlaceBase::StaticItem, Vec::new())) @@ -433,13 +433,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { } #[instrument(level = "debug", skip(self), ret)] - pub(crate) fn cat_rvalue( - &self, - hir_id: hir::HirId, - // FIXME: remove - _span: Span, - expr_ty: Ty<'tcx>, - ) -> PlaceWithHirId<'tcx> { + pub(crate) fn cat_rvalue(&self, hir_id: hir::HirId, expr_ty: Ty<'tcx>) -> PlaceWithHirId<'tcx> { PlaceWithHirId::new(hir_id, expr_ty, PlaceBase::Rvalue, Vec::new()) } @@ -487,7 +481,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { }; let ref_ty = Ty::new_ref(self.tcx(), region, ty::TypeAndMut { ty: place_ty, mutbl }); - let base = self.cat_rvalue(expr.hir_id, expr.span, ref_ty); + let base = self.cat_rvalue(expr.hir_id, ref_ty); self.cat_deref(expr, base) } diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs index 297b2fa143d..a0851aa557b 100644 --- a/compiler/rustc_mir_transform/src/coroutine.rs +++ b/compiler/rustc_mir_transform/src/coroutine.rs @@ -726,7 +726,7 @@ fn replace_resume_ty_local<'tcx>( /// The async lowering step and the type / lifetime inference / checking are /// still using the `resume` argument for the time being. After this transform, /// the coroutine body doesn't have the `resume` argument. -fn transform_gen_context<'tcx>(_tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { +fn transform_gen_context<'tcx>(body: &mut Body<'tcx>) { // This leaves the local representing the `resume` argument in place, // but turns it into a regular local variable. This is cheaper than // adjusting all local references in the body after removing it. @@ -1733,7 +1733,7 @@ impl<'tcx> MirPass<'tcx> for StateTransform { // Remove the context argument within generator bodies. if matches!(coroutine_kind, CoroutineKind::Desugared(CoroutineDesugaring::Gen, _)) { - transform_gen_context(tcx, body); + transform_gen_context(body); } // The original arguments to the function are no longer arguments, mark them as such. diff --git a/compiler/rustc_mir_transform/src/instsimplify.rs b/compiler/rustc_mir_transform/src/instsimplify.rs index f65eb5cbea9..06df89c1037 100644 --- a/compiler/rustc_mir_transform/src/instsimplify.rs +++ b/compiler/rustc_mir_transform/src/instsimplify.rs @@ -29,17 +29,14 @@ impl<'tcx> MirPass<'tcx> for InstSimplify { ctx.simplify_bool_cmp(&statement.source_info, rvalue); ctx.simplify_ref_deref(&statement.source_info, rvalue); ctx.simplify_len(&statement.source_info, rvalue); - ctx.simplify_cast(&statement.source_info, rvalue); + ctx.simplify_cast(rvalue); } _ => {} } } ctx.simplify_primitive_clone(block.terminator.as_mut().unwrap(), &mut block.statements); - ctx.simplify_intrinsic_assert( - block.terminator.as_mut().unwrap(), - &mut block.statements, - ); + ctx.simplify_intrinsic_assert(block.terminator.as_mut().unwrap()); ctx.simplify_nounwind_call(block.terminator.as_mut().unwrap()); simplify_duplicate_switch_targets(block.terminator.as_mut().unwrap()); } @@ -143,7 +140,7 @@ impl<'tcx> InstSimplifyContext<'tcx, '_> { } } - fn simplify_cast(&self, _source_info: &SourceInfo, rvalue: &mut Rvalue<'tcx>) { + fn simplify_cast(&self, rvalue: &mut Rvalue<'tcx>) { if let Rvalue::Cast(kind, operand, cast_ty) = rvalue { let operand_ty = operand.ty(self.local_decls, self.tcx); if operand_ty == *cast_ty { @@ -277,11 +274,7 @@ impl<'tcx> InstSimplifyContext<'tcx, '_> { } } - fn simplify_intrinsic_assert( - &self, - terminator: &mut Terminator<'tcx>, - _statements: &mut Vec>, - ) { + fn simplify_intrinsic_assert(&self, terminator: &mut Terminator<'tcx>) { let TerminatorKind::Call { func, target, .. } = &mut terminator.kind else { return; }; diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index ec704dec352..d771a97ec59 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -197,7 +197,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | sym::unstable | sym::stable | sym::rustc_allowed_through_unstable_modules - | sym::rustc_promotable => self.check_stability_promotable(attr, span, target), + | sym::rustc_promotable => self.check_stability_promotable(attr, target), sym::link_ordinal => self.check_link_ordinal(attr, span, target), sym::rustc_confusables => self.check_confusables(attr, target), sym::rustc_safe_intrinsic => { @@ -2102,7 +2102,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } - fn check_stability_promotable(&self, attr: &Attribute, _span: Span, target: Target) -> bool { + fn check_stability_promotable(&self, attr: &Attribute, target: Target) -> bool { match target { Target::Expression => { self.dcx().emit_err(errors::StabilityPromotable { attr_span: attr.span }); diff --git a/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs b/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs index 9d1b92e1068..1a1aed61fed 100644 --- a/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs +++ b/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs @@ -261,12 +261,7 @@ fn encode_predicates<'tcx>( } /// Encodes a region using the Itanium C++ ABI as a vendor extended type. -fn encode_region<'tcx>( - _tcx: TyCtxt<'tcx>, - region: Region<'tcx>, - dict: &mut FxHashMap, usize>, - _options: EncodeTyOptions, -) -> String { +fn encode_region<'tcx>(region: Region<'tcx>, dict: &mut FxHashMap, usize>) -> String { // u6region[I[][]E] as vendor extended type let mut s = String::new(); match region.kind() { @@ -314,7 +309,7 @@ fn encode_args<'tcx>( for arg in args { match arg.unpack() { GenericArgKind::Lifetime(region) => { - s.push_str(&encode_region(tcx, region, dict, options)); + s.push_str(&encode_region(region, dict)); } GenericArgKind::Type(ty) => { s.push_str(&encode_ty(tcx, ty, dict, options)); @@ -703,7 +698,7 @@ fn encode_ty<'tcx>( ty::DynStar => "u7dynstarI", }); s.push_str(&encode_predicates(tcx, predicates, dict, options)); - s.push_str(&encode_region(tcx, *region, dict, options)); + s.push_str(&encode_region(*region, dict)); s.push('E'); compress(dict, DictKey::Ty(ty, TyQ::None), &mut s); typeid.push_str(&s); @@ -735,7 +730,6 @@ fn encode_ty<'tcx>( fn transform_predicates<'tcx>( tcx: TyCtxt<'tcx>, predicates: &List>, - _options: EncodeTyOptions, ) -> &'tcx List> { let predicates: Vec> = predicates .iter() @@ -967,7 +961,7 @@ fn transform_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, options: TransformTyOptio ty::Dynamic(predicates, _region, kind) => { ty = Ty::new_dynamic( tcx, - transform_predicates(tcx, predicates, options), + transform_predicates(tcx, predicates), tcx.lifetimes.re_erased, *kind, ); diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs index 07e4fef9dd4..2e824060d1b 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs @@ -615,8 +615,6 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { let UnsatisfiedConst(unsatisfied_const) = self .maybe_add_note_for_unsatisfied_const( - &obligation, - trait_ref, &trait_predicate, &mut err, span, @@ -1480,8 +1478,6 @@ pub(super) trait InferCtxtPrivExt<'tcx> { fn maybe_add_note_for_unsatisfied_const( &self, - obligation: &PredicateObligation<'tcx>, - trait_ref: ty::PolyTraitRef<'tcx>, trait_predicate: &ty::PolyTraitPredicate<'tcx>, err: &mut Diagnostic, span: Span, @@ -3359,8 +3355,6 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { fn maybe_add_note_for_unsatisfied_const( &self, - _obligation: &PredicateObligation<'tcx>, - _trait_ref: ty::PolyTraitRef<'tcx>, _trait_predicate: &ty::PolyTraitPredicate<'tcx>, _err: &mut Diagnostic, _span: Span, From 879a1e571305a0fb35ef6cc4297f9230fca95be5 Mon Sep 17 00:00:00 2001 From: Frank King Date: Thu, 4 Jan 2024 21:53:06 +0800 Subject: [PATCH 24/56] Lower anonymous structs or unions to HIR --- compiler/rustc_ast/src/ast.rs | 4 +- compiler/rustc_ast/src/mut_visit.rs | 3 +- compiler/rustc_ast/src/visit.rs | 2 +- compiler/rustc_ast_lowering/src/item.rs | 5 +- compiler/rustc_ast_lowering/src/lib.rs | 54 +++++++++--- .../rustc_ast_passes/src/ast_validation.rs | 2 +- compiler/rustc_ast_pretty/src/pprust/state.rs | 4 +- compiler/rustc_hir/src/def.rs | 2 + compiler/rustc_hir/src/definitions.rs | 6 +- compiler/rustc_hir/src/hir.rs | 2 + compiler/rustc_hir/src/intravisit.rs | 3 + .../rustc_hir_analysis/src/astconv/mod.rs | 13 +++ compiler/rustc_hir_analysis/src/collect.rs | 82 +++++++++++++++++-- compiler/rustc_hir_pretty/src/lib.rs | 37 +++++---- compiler/rustc_metadata/src/rmeta/decoder.rs | 3 + compiler/rustc_middle/src/hir/map/mod.rs | 7 ++ compiler/rustc_middle/src/ty/adt.rs | 17 +++- compiler/rustc_middle/src/ty/context.rs | 10 ++- compiler/rustc_middle/src/ty/mod.rs | 19 ++++- compiler/rustc_parse/src/parser/ty.rs | 5 +- compiler/rustc_passes/src/hir_stats.rs | 1 + compiler/rustc_span/src/symbol.rs | 1 + .../src/typeid/typeid_itanium_cxx_abi.rs | 3 +- compiler/rustc_symbol_mangling/src/v0.rs | 3 +- .../src/solve/assembly/structural_traits.rs | 5 ++ .../src/traits/select/mod.rs | 10 +++ .../rustc_ty_utils/src/representability.rs | 3 +- src/librustdoc/clean/mod.rs | 10 +++ src/librustdoc/clean/types.rs | 4 + .../clippy/clippy_lints/src/dereference.rs | 1 + .../clippy/clippy_utils/src/hir_utils.rs | 3 +- src/tools/rustfmt/src/types.rs | 4 +- .../feature-gate-unnamed_fields.rs | 2 - .../feature-gate-unnamed_fields.stderr | 34 +------- .../restrict_anonymous_structs.rs | 5 -- .../restrict_anonymous_structs.stderr | 44 ++-------- .../restrict_anonymous_unions.rs | 5 -- .../restrict_anonymous_unions.stderr | 44 ++-------- 38 files changed, 288 insertions(+), 174 deletions(-) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 296a570de6b..e41228bd501 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -2107,9 +2107,9 @@ pub enum TyKind { /// A tuple (`(A, B, C, D,...)`). Tup(ThinVec>), /// An anonymous struct type i.e. `struct { foo: Type }` - AnonStruct(ThinVec), + AnonStruct(NodeId, ThinVec), /// An anonymous union type i.e. `union { bar: Type }` - AnonUnion(ThinVec), + AnonUnion(NodeId, ThinVec), /// A path (`module::module::...::Type`), optionally /// "qualified", e.g., ` as SomeTrait>::SomeType`. /// diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index 90677151d25..d482ada170e 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -514,7 +514,8 @@ pub fn noop_visit_ty(ty: &mut P, vis: &mut T) { visit_vec(bounds, |bound| vis.visit_param_bound(bound)); } TyKind::MacCall(mac) => vis.visit_mac_call(mac), - TyKind::AnonStruct(fields) | TyKind::AnonUnion(fields) => { + TyKind::AnonStruct(id, fields) | TyKind::AnonUnion(id, fields) => { + vis.visit_id(id); fields.flat_map_in_place(|field| vis.flat_map_field_def(field)); } } diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index 8d084ee29a7..4aaaa0ba424 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -450,7 +450,7 @@ pub fn walk_ty<'a, V: Visitor<'a>>(visitor: &mut V, typ: &'a Ty) { TyKind::Infer | TyKind::ImplicitSelf | TyKind::Err => {} TyKind::MacCall(mac) => visitor.visit_mac_call(mac), TyKind::Never | TyKind::CVarArgs => {} - TyKind::AnonStruct(ref fields, ..) | TyKind::AnonUnion(ref fields, ..) => { + TyKind::AnonStruct(_, ref fields) | TyKind::AnonUnion(_, ref fields) => { walk_list!(visitor, visit_field_def, fields) } } diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index fb52f9cf58f..933372fae4e 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -720,7 +720,10 @@ impl<'hir> LoweringContext<'_, 'hir> { } } - fn lower_field_def(&mut self, (index, f): (usize, &FieldDef)) -> hir::FieldDef<'hir> { + pub(super) fn lower_field_def( + &mut self, + (index, f): (usize, &FieldDef), + ) -> hir::FieldDef<'hir> { let ty = if let TyKind::Path(qself, path) = &f.ty.kind { let t = self.lower_path_ty( &f.ty, diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 5f7439060b3..7a071242256 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -1288,17 +1288,49 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { TyKind::Err => { hir::TyKind::Err(self.dcx().span_delayed_bug(t.span, "TyKind::Err lowered")) } - // FIXME(unnamed_fields): IMPLEMENTATION IN PROGRESS - #[allow(rustc::untranslatable_diagnostic)] - #[allow(rustc::diagnostic_outside_of_impl)] - TyKind::AnonStruct(ref _fields) => { - hir::TyKind::Err(self.dcx().span_err(t.span, "anonymous structs are unimplemented")) - } - // FIXME(unnamed_fields): IMPLEMENTATION IN PROGRESS - #[allow(rustc::untranslatable_diagnostic)] - #[allow(rustc::diagnostic_outside_of_impl)] - TyKind::AnonUnion(ref _fields) => { - hir::TyKind::Err(self.dcx().span_err(t.span, "anonymous unions are unimplemented")) + // Lower the anonymous structs or unions in a nested lowering context. + // + // ``` + // struct Foo { + // _: union { + // // ^__________________ <-- within the nested lowering context, + // /* fields */ // | we lower all fields defined into an + // } // | owner node of struct or union item + // // ^_____________________| + // } + // ``` + TyKind::AnonStruct(def_node_id, fields) | TyKind::AnonUnion(def_node_id, fields) => { + let (def_kind, item_kind): (DefKind, fn(_, _) -> _) = match t.kind { + TyKind::AnonStruct(..) => (DefKind::Struct, hir::ItemKind::Struct), + TyKind::AnonUnion(..) => (DefKind::Union, hir::ItemKind::Union), + _ => unreachable!(), + }; + let def_id = self.create_def( + self.current_hir_id_owner.def_id, + *def_node_id, + kw::Empty, + def_kind, + t.span, + ); + debug!(?def_id); + let owner_id = hir::OwnerId { def_id }; + self.with_hir_id_owner(*def_node_id, |this| { + let fields = this.arena.alloc_from_iter( + fields.iter().enumerate().map(|f| this.lower_field_def(f)), + ); + let span = t.span; + let variant_data = hir::VariantData::Struct(fields, false); + // FIXME: capture the generics from the outer adt. + let generics = hir::Generics::empty(); + hir::OwnerNode::Item(this.arena.alloc(hir::Item { + ident: Ident::new(kw::Empty, span), + owner_id, + kind: item_kind(variant_data, generics), + span: this.lower_span(span), + vis_span: this.lower_span(span.shrink_to_lo()), + })) + }); + hir::TyKind::AnonAdt(hir::ItemId { owner_id }) } TyKind::Slice(ty) => hir::TyKind::Slice(self.lower_ty(ty, itctx)), TyKind::Ptr(mt) => hir::TyKind::Ptr(self.lower_mt(mt, itctx)), diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 9ea5d1ed5fa..86597d20c19 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -219,7 +219,7 @@ impl<'a> AstValidator<'a> { } } } - TyKind::AnonStruct(ref fields, ..) | TyKind::AnonUnion(ref fields, ..) => { + TyKind::AnonStruct(_, ref fields) | TyKind::AnonUnion(_, ref fields) => { walk_list!(self, visit_field_def, fields) } _ => visit::walk_ty(self, t), diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index 731232bce65..cda746894e8 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -1003,11 +1003,11 @@ impl<'a> State<'a> { } self.pclose(); } - ast::TyKind::AnonStruct(fields) => { + ast::TyKind::AnonStruct(_, fields) => { self.head("struct"); self.print_record_struct_body(fields, ty.span); } - ast::TyKind::AnonUnion(fields) => { + ast::TyKind::AnonUnion(_, fields) => { self.head("union"); self.print_record_struct_body(fields, ty.span); } diff --git a/compiler/rustc_hir/src/def.rs b/compiler/rustc_hir/src/def.rs index 81ec7ddb629..f08ab4bfc09 100644 --- a/compiler/rustc_hir/src/def.rs +++ b/compiler/rustc_hir/src/def.rs @@ -8,6 +8,7 @@ use rustc_data_structures::unord::UnordMap; use rustc_macros::HashStable_Generic; use rustc_span::def_id::{DefId, LocalDefId}; use rustc_span::hygiene::MacroKind; +use rustc_span::symbol::kw; use rustc_span::Symbol; use std::array::IntoIter; @@ -225,6 +226,7 @@ impl DefKind { pub fn def_path_data(self, name: Symbol) -> DefPathData { match self { + DefKind::Struct | DefKind::Union if name == kw::Empty => DefPathData::AnonAdt, DefKind::Mod | DefKind::Struct | DefKind::Union diff --git a/compiler/rustc_hir/src/definitions.rs b/compiler/rustc_hir/src/definitions.rs index 9fb1fc19bf4..b81ad8b1946 100644 --- a/compiler/rustc_hir/src/definitions.rs +++ b/compiler/rustc_hir/src/definitions.rs @@ -287,6 +287,8 @@ pub enum DefPathData { /// An existential `impl Trait` type node. /// Argument position `impl Trait` have a `TypeNs` with their pretty-printed name. OpaqueTy, + /// An anonymous struct or union type i.e. `struct { foo: Type }` or `union { bar: Type }` + AnonAdt, } impl Definitions { @@ -409,8 +411,9 @@ impl DefPathData { match *self { TypeNs(name) if name == kw::Empty => None, TypeNs(name) | ValueNs(name) | MacroNs(name) | LifetimeNs(name) => Some(name), + Impl | ForeignMod | CrateRoot | Use | GlobalAsm | Closure | Ctor | AnonConst - | OpaqueTy => None, + | OpaqueTy | AnonAdt => None, } } @@ -431,6 +434,7 @@ impl DefPathData { Ctor => DefPathDataName::Anon { namespace: sym::constructor }, AnonConst => DefPathDataName::Anon { namespace: sym::constant }, OpaqueTy => DefPathDataName::Anon { namespace: sym::opaque }, + AnonAdt => DefPathDataName::Anon { namespace: sym::anon_adt }, } } } diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index a7a1c69b9be..00b2f984483 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -2587,6 +2587,8 @@ pub enum TyKind<'hir> { Never, /// A tuple (`(A, B, C, D, ...)`). Tup(&'hir [Ty<'hir>]), + /// An anonymous struct or union type i.e. `struct { foo: Type }` or `union { foo: Type }` + AnonAdt(ItemId), /// A path to a type definition (`module::module::...::Type`), or an /// associated type (e.g., ` as Trait>::Type` or `::Target`). /// diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 52e1109ff92..e9337dd3586 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -852,6 +852,9 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty<'v>) { } TyKind::Typeof(ref expression) => visitor.visit_anon_const(expression), TyKind::Infer | TyKind::InferDelegation(..) | TyKind::Err(_) => {} + TyKind::AnonAdt(item_id) => { + visitor.visit_nested_item(item_id); + } } } diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs index 1ae3ebaebbb..a643614d33d 100644 --- a/compiler/rustc_hir_analysis/src/astconv/mod.rs +++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs @@ -2457,6 +2457,19 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { hir::TyKind::Tup(fields) => { Ty::new_tup_from_iter(tcx, fields.iter().map(|t| self.ast_ty_to_ty(t))) } + hir::TyKind::AnonAdt(item_id) => { + let did = item_id.owner_id.def_id; + let adt_def = tcx.adt_def(did); + let generics = tcx.generics_of(did); + + debug!("ast_ty_to_ty_inner(AnonAdt): generics={:?}", generics); + let args = ty::GenericArgs::for_item(tcx, did.to_def_id(), |param, _| { + tcx.mk_param_from_def(param) + }); + debug!("ast_ty_to_ty_inner(AnonAdt): args={:?}", args); + + Ty::new_adt(tcx, adt_def, tcx.mk_args(args)) + } hir::TyKind::BareFn(bf) => { require_c_abi_if_c_variadic(tcx, bf.decl, bf.abi, ast_ty.span); diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index f458ff01c10..768b07069c8 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -789,6 +789,65 @@ fn convert_enum_variant_types(tcx: TyCtxt<'_>, def_id: DefId) { } } +/* +/// In a type definition, we check that unnamed field names are distinct. +fn check_unnamed_fields_defn<'tcx>(tcx: TyCtxt<'tcx>, item: &hir::Item<'tcx>) { + let mut seen_fields: FxHashMap> = Default::default(); + fn check_fields_anon_adt_defn<'tcx>(tcx: TyCtxt<'tcx>, item: &hir::Item<'tcx>, seen_fields: &mut FxHashMap>) { + let fields = match &item.kind { + hir::ItemKind::Struct(fields, _) | hir::ItemKind::Union(fields, _) => fields, + _ => return, + }; + for field in fields.fields() { + if field.ident.name == kw::Underscore { + if let hir::TyKind::AnonAdt(item_id) = field.ty.kind() { + let item = tcx.hir().item(item_id); + check_fields_anon_adt_defn(tcx, item, &mut *seen_fields); + } else { + let field_ty = match tcx.type_of(field.def_id).instantiate_identity().ty_adt_def() { + Some(adt_ty) => adt_ty, + None => { + tcx.sess.emit_err(err); + return; + } + }; + if let Some(def_id) = field_ty.did().as_local() { + let item = tcx.hir().item(hir::ItemId { owner_id: hir::OwnerId { def_id }}); + check_fields_anon_adt_defn(tcx, item, &mut *seen_fields); + } + } + field_ty.flags() + let inner_adt_def = field_ty.ty_adt_def().expect("expect an adt"); + check_fields_anon_adt_defn(tcx, adt_def, &mut *seen_fields); + } else { + let span = field.did.as_local().map(|did| { + let hir_id = tcx.hir().local_def_id_to_hir_id(did); + tcx.hir().span(hir_id) + }); + match seen_fields.get(&ident.normalize_to_macros_2_0()).cloned() { + Some(Some(prev_span)) => { + tcx.sess.emit_err(errors::FieldAlreadyDeclared { + field_name: ident, + span: f.span, + prev_span, + }); + } + Some(None) => { + tcx.sess.emit_err(errors::FieldAlreadyDeclared { + field_name: f.ident, + span: f.span, + prev_span, + }); + } + None => + seen_fields.insert(f.ident.normalize_to_macros_2_0(), f.span); + } + } + } + } +} + */ + fn convert_variant( tcx: TyCtxt<'_>, variant_did: Option, @@ -798,11 +857,17 @@ fn convert_variant( adt_kind: ty::AdtKind, parent_did: LocalDefId, ) -> ty::VariantDef { + let mut has_unnamed_fields = false; let mut seen_fields: FxHashMap = Default::default(); let fields = def .fields() .iter() - .map(|f| { + .inspect(|f| { + // Skip the unnamed field here, we will check it later. + if f.ident.name == kw::Underscore { + has_unnamed_fields = true; + return; + } let dup_span = seen_fields.get(&f.ident.normalize_to_macros_2_0()).cloned(); if let Some(prev_span) = dup_span { tcx.dcx().emit_err(errors::FieldAlreadyDeclared { @@ -813,12 +878,11 @@ fn convert_variant( } else { seen_fields.insert(f.ident.normalize_to_macros_2_0(), f.span); } - - ty::FieldDef { - did: f.def_id.to_def_id(), - name: f.ident.name, - vis: tcx.visibility(f.def_id), - } + }) + .map(|f| ty::FieldDef { + did: f.def_id.to_def_id(), + name: f.ident.name, + vis: tcx.visibility(f.def_id), }) .collect(); let recovered = match def { @@ -837,6 +901,7 @@ fn convert_variant( adt_kind == AdtKind::Struct && tcx.has_attr(parent_did, sym::non_exhaustive) || variant_did .is_some_and(|variant_did| tcx.has_attr(variant_did, sym::non_exhaustive)), + has_unnamed_fields, ) } @@ -847,6 +912,7 @@ fn adt_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::AdtDef<'_> { bug!("expected ADT to be an item"); }; + let is_anonymous = item.ident.name == kw::Empty; let repr = tcx.repr_options_of_def(def_id.to_def_id()); let (kind, variants) = match &item.kind { ItemKind::Enum(def, _) => { @@ -897,7 +963,7 @@ fn adt_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::AdtDef<'_> { } _ => bug!("{:?} is not an ADT", item.owner_id.def_id), }; - tcx.mk_adt_def(def_id.to_def_id(), kind, variants, repr) + tcx.mk_adt_def(def_id.to_def_id(), kind, variants, repr, is_anonymous) } fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef { diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index b90fa03a3dc..8f8f747339b 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -328,6 +328,7 @@ impl<'a> State<'a> { hir::TyKind::Infer | hir::TyKind::InferDelegation(..) => { self.word("_"); } + hir::TyKind::AnonAdt(..) => self.word("/* anonymous adt */"), } self.end() } @@ -728,26 +729,30 @@ impl<'a> State<'a> { } hir::VariantData::Struct { .. } => { self.print_where_clause(generics); - self.nbsp(); - self.bopen(); - self.hardbreak_if_not_bol(); - - for field in struct_def.fields() { - self.hardbreak_if_not_bol(); - self.maybe_print_comment(field.span.lo()); - self.print_outer_attributes(self.attrs(field.hir_id)); - self.print_ident(field.ident); - self.word_nbsp(":"); - self.print_type(field.ty); - self.word(","); - } - - self.bclose(span) + self.print_variant_struct(span, struct_def.fields()) } } } - fn print_variant(&mut self, v: &hir::Variant<'_>) { + fn print_variant_struct(&mut self, span: rustc_span::Span, fields: &[hir::FieldDef<'_>]) { + self.nbsp(); + self.bopen(); + self.hardbreak_if_not_bol(); + + for field in fields { + self.hardbreak_if_not_bol(); + self.maybe_print_comment(field.span.lo()); + self.print_outer_attributes(self.attrs(field.hir_id)); + self.print_ident(field.ident); + self.word_nbsp(":"); + self.print_type(field.ty); + self.word(","); + } + + self.bclose(span) + } + + pub fn print_variant(&mut self, v: &hir::Variant<'_>) { self.head(""); let generics = hir::Generics::empty(); self.print_struct(&v.data, generics, v.ident.name, v.span, false); diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index 11cb1bb6d9e..72e9744295b 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -1084,6 +1084,8 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { parent_did, false, data.is_non_exhaustive, + // FIXME: unnamed fields in crate metadata is unimplemented yet. + false, ), ) } @@ -1126,6 +1128,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { adt_kind, variants.into_iter().map(|(_, variant)| variant).collect(), repr, + false, ) } diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index 50817dd0a80..8e1cb6a514f 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -756,6 +756,13 @@ impl<'hir> Map<'hir> { } } + pub fn expect_field(self, id: HirId) -> &'hir FieldDef<'hir> { + match self.tcx.hir_node(id) { + Node::Field(field) => field, + _ => bug!("expected field, found {}", self.node_to_string(id)), + } + } + pub fn expect_foreign_item(self, id: OwnerId) -> &'hir ForeignItem<'hir> { match self.tcx.hir_owner_node(id) { OwnerNode::ForeignItem(item) => item, diff --git a/compiler/rustc_middle/src/ty/adt.rs b/compiler/rustc_middle/src/ty/adt.rs index 685c3e87dac..854046c9ceb 100644 --- a/compiler/rustc_middle/src/ty/adt.rs +++ b/compiler/rustc_middle/src/ty/adt.rs @@ -50,6 +50,8 @@ bitflags! { const IS_VARIANT_LIST_NON_EXHAUSTIVE = 1 << 8; /// Indicates whether the type is `UnsafeCell`. const IS_UNSAFE_CELL = 1 << 9; + /// Indicates whether the type is anonymous. + const IS_ANONYMOUS = 1 << 10; } } rustc_data_structures::external_bitflags_debug! { AdtFlags } @@ -233,8 +235,12 @@ impl AdtDefData { kind: AdtKind, variants: IndexVec, repr: ReprOptions, + is_anonymous: bool, ) -> Self { - debug!("AdtDef::new({:?}, {:?}, {:?}, {:?})", did, kind, variants, repr); + debug!( + "AdtDef::new({:?}, {:?}, {:?}, {:?}, {:?})", + did, kind, variants, repr, is_anonymous + ); let mut flags = AdtFlags::NO_ADT_FLAGS; if kind == AdtKind::Enum && tcx.has_attr(did, sym::non_exhaustive) { @@ -267,6 +273,9 @@ impl AdtDefData { if Some(did) == tcx.lang_items().unsafe_cell_type() { flags |= AdtFlags::IS_UNSAFE_CELL; } + if is_anonymous { + flags |= AdtFlags::IS_ANONYMOUS; + } AdtDefData { did, variants, flags, repr } } @@ -365,6 +374,12 @@ impl<'tcx> AdtDef<'tcx> { self.flags().contains(AdtFlags::IS_MANUALLY_DROP) } + /// Returns `true` if this is an anonymous adt + #[inline] + pub fn is_anonymous(self) -> bool { + self.flags().contains(AdtFlags::IS_ANONYMOUS) + } + /// Returns `true` if this type has a destructor. pub fn has_dtor(self, tcx: TyCtxt<'tcx>) -> bool { self.destructor(tcx).is_some() diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index b747f0a4fb6..9a0eea6592f 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -715,8 +715,16 @@ impl<'tcx> TyCtxt<'tcx> { kind: AdtKind, variants: IndexVec, repr: ReprOptions, + is_anonymous: bool, ) -> ty::AdtDef<'tcx> { - self.mk_adt_def_from_data(ty::AdtDefData::new(self, did, kind, variants, repr)) + self.mk_adt_def_from_data(ty::AdtDefData::new( + self, + did, + kind, + variants, + repr, + is_anonymous, + )) } /// Allocates a read-only byte or string literal for `mir::interpret`. diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index c9137f374a2..3cbe8f287e1 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -1130,6 +1130,8 @@ bitflags! { /// Indicates whether this variant was obtained as part of recovering from /// a syntactic error. May be incomplete or bogus. const IS_RECOVERED = 1 << 1; + /// Indicates whether this variant has unnamed fields. + const HAS_UNNAMED_FIELDS = 1 << 2; } } rustc_data_structures::external_bitflags_debug! { VariantFlags } @@ -1143,7 +1145,7 @@ pub struct VariantDef { /// `DefId` that identifies the variant's constructor. /// If this variant is a struct variant, then this is `None`. pub ctor: Option<(CtorKind, DefId)>, - /// Variant or struct name. + /// Variant or struct name, maybe empty for anonymous adt (struct or union). pub name: Symbol, /// Discriminant of this variant. pub discr: VariantDiscr, @@ -1180,11 +1182,12 @@ impl VariantDef { parent_did: DefId, recovered: bool, is_field_list_non_exhaustive: bool, + has_unnamed_fields: bool, ) -> Self { debug!( "VariantDef::new(name = {:?}, variant_did = {:?}, ctor = {:?}, discr = {:?}, - fields = {:?}, adt_kind = {:?}, parent_did = {:?})", - name, variant_did, ctor, discr, fields, adt_kind, parent_did, + fields = {:?}, adt_kind = {:?}, parent_did = {:?}, has_unnamed_fields = {:?})", + name, variant_did, ctor, discr, fields, adt_kind, parent_did, has_unnamed_fields, ); let mut flags = VariantFlags::NO_VARIANT_FLAGS; @@ -1196,6 +1199,10 @@ impl VariantDef { flags |= VariantFlags::IS_RECOVERED; } + if has_unnamed_fields { + flags |= VariantFlags::HAS_UNNAMED_FIELDS; + } + VariantDef { def_id: variant_did.unwrap_or(parent_did), ctor, name, discr, fields, flags } } @@ -1211,6 +1218,12 @@ impl VariantDef { self.flags.intersects(VariantFlags::IS_RECOVERED) } + /// Does this variant contains unnamed fields + #[inline] + pub fn has_unnamed_fields(&self) -> bool { + self.flags.intersects(VariantFlags::HAS_UNNAMED_FIELDS) + } + /// Computes the `Ident` of this variant by looking up the `Span` pub fn ident(&self, tcx: TyCtxt<'_>) -> Ident { Ident::new(self.name, tcx.def_ident_span(self.def_id).unwrap()) diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index 5fe54a536a7..157fb9e505a 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -396,8 +396,9 @@ impl<'a> Parser<'a> { self.parse_record_struct_body(if is_union { "union" } else { "struct" }, lo, false)?; let span = lo.to(self.prev_token.span); self.sess.gated_spans.gate(sym::unnamed_fields, span); - // These can be rejected during AST validation in `deny_anon_struct_or_union`. - let kind = if is_union { TyKind::AnonUnion(fields) } else { TyKind::AnonStruct(fields) }; + let id = ast::DUMMY_NODE_ID; + let kind = + if is_union { TyKind::AnonUnion(id, fields) } else { TyKind::AnonStruct(id, fields) }; Ok(self.mk_ty(span, kind)) } diff --git a/compiler/rustc_passes/src/hir_stats.rs b/compiler/rustc_passes/src/hir_stats.rs index e94d8c4c932..d02e86dd456 100644 --- a/compiler/rustc_passes/src/hir_stats.rs +++ b/compiler/rustc_passes/src/hir_stats.rs @@ -345,6 +345,7 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> { BareFn, Never, Tup, + AnonAdt, Path, OpaqueDef, TraitObject, diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index aa912c93c08..c2d02665ef5 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -382,6 +382,7 @@ symbols! { and, and_then, anon, + anon_adt, anonymous_lifetime_in_impl_trait, any, append_const_msg, diff --git a/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs b/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs index 9d1b92e1068..011d52bc65b 100644 --- a/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs +++ b/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs @@ -387,7 +387,8 @@ fn encode_ty_name(tcx: TyCtxt<'_>, def_id: DefId) -> String { | hir::definitions::DefPathData::Use | hir::definitions::DefPathData::GlobalAsm | hir::definitions::DefPathData::MacroNs(..) - | hir::definitions::DefPathData::LifetimeNs(..) => { + | hir::definitions::DefPathData::LifetimeNs(..) + | hir::definitions::DefPathData::AnonAdt => { bug!("encode_ty_name: unexpected `{:?}`", disambiguated_data.data); } }); diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index 530221555c5..ce065efb4c6 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -748,7 +748,8 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> { | DefPathData::GlobalAsm | DefPathData::Impl | DefPathData::MacroNs(_) - | DefPathData::LifetimeNs(_) => { + | DefPathData::LifetimeNs(_) + | DefPathData::AnonAdt => { bug!("symbol_names: unexpected DefPathData: {:?}", disambiguated_data.data) } }; diff --git a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs index 819b070cf8b..b320ded40a7 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs @@ -181,6 +181,11 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_copy_clone_trait<'tcx>( | ty::Ref(_, _, Mutability::Not) | ty::Array(..) => Err(NoSolution), + // Check for anonymous adts. + ty::Adt(adt, generics) if adt.is_anonymous() => { + Ok(adt.all_fields().map(|f| f.ty(ecx.tcx(), generics)).collect()) + } + ty::Dynamic(..) | ty::Str | ty::Slice(_) diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index ac6cfcdeb59..c2f7d5160f6 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -2212,6 +2212,16 @@ impl<'tcx> SelectionContext<'_, 'tcx> { // FIXME(async_closures): These are never clone, for now. ty::CoroutineClosure(_, _) => None, + // `Copy` and `Clone` are automatically impelemented for an anonymous adt + // if all of its fields are `Copy` and `Clone` + ty::Adt(adt, args) if adt.is_anonymous() => { + // (*) binder moved here + Where( + obligation + .predicate + .rebind(adt.all_fields().map(|f| f.ty(self.tcx(), args)).collect()), + ) + } ty::Adt(..) | ty::Alias(..) | ty::Param(..) | ty::Placeholder(..) => { // Fallback to whatever user-defined impls exist in this case. diff --git a/compiler/rustc_ty_utils/src/representability.rs b/compiler/rustc_ty_utils/src/representability.rs index 70f1f099688..ade509123ac 100644 --- a/compiler/rustc_ty_utils/src/representability.rs +++ b/compiler/rustc_ty_utils/src/representability.rs @@ -21,8 +21,7 @@ macro_rules! rtry { fn representability(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Representability { match tcx.def_kind(def_id) { DefKind::Struct | DefKind::Union | DefKind::Enum => { - let adt_def = tcx.adt_def(def_id); - for variant in adt_def.variants() { + for variant in tcx.adt_def(def_id).variants() { for field in variant.fields.iter() { rtry!(tcx.representability(field.did.expect_local())); } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 89977934cde..b697f945f20 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1892,6 +1892,16 @@ pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> T TyKind::BareFn(barefn) => BareFunction(Box::new(clean_bare_fn_ty(barefn, cx))), // Rustdoc handles `TyKind::Err`s by turning them into `Type::Infer`s. TyKind::Infer | TyKind::Err(_) | TyKind::Typeof(..) | TyKind::InferDelegation(..) => Infer, + TyKind::AnonAdt(item_id) => { + let path = external_path( + cx, + item_id.owner_id.def_id.to_def_id(), + false, + ThinVec::new(), + ty::Binder::dummy(ty::GenericArgs::empty()), + ); + Type::Path { path } + } } } diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 6710193f961..324ce03dcfd 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -1511,6 +1511,10 @@ pub(crate) enum Type { /// An `impl Trait`: `impl TraitA + TraitB + ...` ImplTrait(Vec), + // /// An anonymous struct type i.e. `struct { foo: Type }` + // AnonStruct(VariantStruct), + // /// An anonymous union type i.e. `union { bar: Type }` + // AnonUnion(VariantStruct), } impl Type { diff --git a/src/tools/clippy/clippy_lints/src/dereference.rs b/src/tools/clippy/clippy_lints/src/dereference.rs index cdbb52f497b..0ddfeaa0ae0 100644 --- a/src/tools/clippy/clippy_lints/src/dereference.rs +++ b/src/tools/clippy/clippy_lints/src/dereference.rs @@ -831,6 +831,7 @@ impl TyCoercionStability { | TyKind::Typeof(..) | TyKind::TraitObject(..) | TyKind::InferDelegation(..) + | TyKind::AnonAdt(..) | TyKind::Err(_) => Self::Reborrow, }; } diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs index 4fa93ad23c3..d50332e82da 100644 --- a/src/tools/clippy/clippy_utils/src/hir_utils.rs +++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs @@ -515,6 +515,7 @@ impl HirEqInterExpr<'_, '_, '_> { (TyKind::Path(l), TyKind::Path(r)) => self.eq_qpath(l, r), (&TyKind::Tup(l), &TyKind::Tup(r)) => over(l, r, |l, r| self.eq_ty(l, r)), (&TyKind::Infer, &TyKind::Infer) => true, + (TyKind::AnonAdt(l_item_id), TyKind::AnonAdt(r_item_id)) => l_item_id == r_item_id, _ => false, } } @@ -1108,7 +1109,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { TyKind::Typeof(anon_const) => { self.hash_body(anon_const.body); }, - TyKind::Err(_) | TyKind::Infer | TyKind::Never | TyKind::InferDelegation(..) => {}, + TyKind::Err(_) | TyKind::Infer | TyKind::Never | TyKind::InferDelegation(..) | TyKind::AnonAdt(_) => {}, } } diff --git a/src/tools/rustfmt/src/types.rs b/src/tools/rustfmt/src/types.rs index cd2582e66be..aaef80f4aef 100644 --- a/src/tools/rustfmt/src/types.rs +++ b/src/tools/rustfmt/src/types.rs @@ -806,8 +806,8 @@ impl Rewrite for ast::Ty { ast::TyKind::Tup(ref items) => { rewrite_tuple(context, items.iter(), self.span, shape, items.len() == 1) } - ast::TyKind::AnonStruct(_) => Some(context.snippet(self.span).to_owned()), - ast::TyKind::AnonUnion(_) => Some(context.snippet(self.span).to_owned()), + ast::TyKind::AnonStruct(..) => Some(context.snippet(self.span).to_owned()), + ast::TyKind::AnonUnion(..) => Some(context.snippet(self.span).to_owned()), ast::TyKind::Path(ref q_self, ref path) => { rewrite_path(context, PathContext::Type, q_self, path, shape) } diff --git a/tests/ui/feature-gates/feature-gate-unnamed_fields.rs b/tests/ui/feature-gates/feature-gate-unnamed_fields.rs index 4bbd0c83bfb..6ee8de89564 100644 --- a/tests/ui/feature-gates/feature-gate-unnamed_fields.rs +++ b/tests/ui/feature-gates/feature-gate-unnamed_fields.rs @@ -2,7 +2,6 @@ struct Foo { foo: u8, _: union { //~ ERROR unnamed fields are not yet fully implemented [E0658] //~^ ERROR unnamed fields are not yet fully implemented [E0658] - //~| ERROR anonymous unions are unimplemented bar: u8, baz: u16 } @@ -12,7 +11,6 @@ union Bar { foobar: u8, _: struct { //~ ERROR unnamed fields are not yet fully implemented [E0658] //~^ ERROR unnamed fields are not yet fully implemented [E0658] - //~| ERROR anonymous structs are unimplemented foobaz: u8, barbaz: u16 } diff --git a/tests/ui/feature-gates/feature-gate-unnamed_fields.stderr b/tests/ui/feature-gates/feature-gate-unnamed_fields.stderr index 82f08912bc8..8fa342c08ae 100644 --- a/tests/ui/feature-gates/feature-gate-unnamed_fields.stderr +++ b/tests/ui/feature-gates/feature-gate-unnamed_fields.stderr @@ -14,7 +14,6 @@ error[E0658]: unnamed fields are not yet fully implemented LL | _: union { | ________^ LL | | -LL | | LL | | bar: u8, LL | | baz: u16 LL | | } @@ -25,7 +24,7 @@ LL | | } = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: unnamed fields are not yet fully implemented - --> $DIR/feature-gate-unnamed_fields.rs:13:5 + --> $DIR/feature-gate-unnamed_fields.rs:12:5 | LL | _: struct { | ^ @@ -35,12 +34,11 @@ LL | _: struct { = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: unnamed fields are not yet fully implemented - --> $DIR/feature-gate-unnamed_fields.rs:13:8 + --> $DIR/feature-gate-unnamed_fields.rs:12:8 | LL | _: struct { | ________^ LL | | -LL | | LL | | foobaz: u8, LL | | barbaz: u16 LL | | } @@ -51,7 +49,7 @@ LL | | } = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: unnamed fields are not yet fully implemented - --> $DIR/feature-gate-unnamed_fields.rs:23:5 + --> $DIR/feature-gate-unnamed_fields.rs:21:5 | LL | _: S | ^ @@ -60,30 +58,6 @@ LL | _: S = help: add `#![feature(unnamed_fields)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error: anonymous unions are unimplemented - --> $DIR/feature-gate-unnamed_fields.rs:3:8 - | -LL | _: union { - | ________^ -LL | | -LL | | -LL | | bar: u8, -LL | | baz: u16 -LL | | } - | |_____^ - -error: anonymous structs are unimplemented - --> $DIR/feature-gate-unnamed_fields.rs:13:8 - | -LL | _: struct { - | ________^ -LL | | -LL | | -LL | | foobaz: u8, -LL | | barbaz: u16 -LL | | } - | |_____^ - -error: aborting due to 7 previous errors +error: aborting due to 5 previous errors For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/union/unnamed-fields/restrict_anonymous_structs.rs b/tests/ui/union/unnamed-fields/restrict_anonymous_structs.rs index 192bbba5a5b..76525ec0bb1 100644 --- a/tests/ui/union/unnamed-fields/restrict_anonymous_structs.rs +++ b/tests/ui/union/unnamed-fields/restrict_anonymous_structs.rs @@ -3,9 +3,7 @@ struct F { field: struct { field: u8 }, //~ ERROR anonymous structs are not allowed outside of unnamed struct or union fields - //~^ ERROR anonymous structs are unimplemented _: struct { field: u8 }, - //~^ ERROR anonymous structs are unimplemented } struct G { @@ -14,9 +12,7 @@ struct G { union H { field: struct { field: u8 }, //~ ERROR anonymous structs are not allowed outside of unnamed struct or union fields - //~^ ERROR anonymous structs are unimplemented _: struct { field: u8 }, - //~^ ERROR anonymous structs are unimplemented } union I { @@ -27,7 +23,6 @@ enum K { M { _ : struct { field: u8 }, //~ ERROR anonymous structs are not allowed outside of unnamed struct or union fields //~^ ERROR unnamed fields are not allowed outside of structs or unions - //~| ERROR anonymous structs are unimplemented }, N { _ : u8, //~ ERROR unnamed fields are not allowed outside of structs or unions diff --git a/tests/ui/union/unnamed-fields/restrict_anonymous_structs.stderr b/tests/ui/union/unnamed-fields/restrict_anonymous_structs.stderr index fd731766c01..846e3451a71 100644 --- a/tests/ui/union/unnamed-fields/restrict_anonymous_structs.stderr +++ b/tests/ui/union/unnamed-fields/restrict_anonymous_structs.stderr @@ -5,25 +5,25 @@ LL | field: struct { field: u8 }, | ^^^^^^^^^^^^^^^^^^^^ anonymous struct declared here error: unnamed fields can only have struct or union types - --> $DIR/restrict_anonymous_structs.rs:12:5 + --> $DIR/restrict_anonymous_structs.rs:10:5 | LL | _: (u8, u8), | ^ -------- not a struct or union error: anonymous structs are not allowed outside of unnamed struct or union fields - --> $DIR/restrict_anonymous_structs.rs:16:12 + --> $DIR/restrict_anonymous_structs.rs:14:12 | LL | field: struct { field: u8 }, | ^^^^^^^^^^^^^^^^^^^^ anonymous struct declared here error: unnamed fields can only have struct or union types - --> $DIR/restrict_anonymous_structs.rs:23:5 + --> $DIR/restrict_anonymous_structs.rs:19:5 | LL | _: (u8, u8), | ^ -------- not a struct or union error: unnamed fields are not allowed outside of structs or unions - --> $DIR/restrict_anonymous_structs.rs:28:9 + --> $DIR/restrict_anonymous_structs.rs:24:9 | LL | _ : struct { field: u8 }, | -^^^^^^^^^^^^^^^^^^^^^^^ @@ -31,48 +31,18 @@ LL | _ : struct { field: u8 }, | unnamed field declared here error: anonymous structs are not allowed outside of unnamed struct or union fields - --> $DIR/restrict_anonymous_structs.rs:28:13 + --> $DIR/restrict_anonymous_structs.rs:24:13 | LL | _ : struct { field: u8 }, | ^^^^^^^^^^^^^^^^^^^^ anonymous struct declared here error: unnamed fields are not allowed outside of structs or unions - --> $DIR/restrict_anonymous_structs.rs:33:9 + --> $DIR/restrict_anonymous_structs.rs:28:9 | LL | _ : u8, | -^^^^^ | | | unnamed field declared here -error: anonymous structs are unimplemented - --> $DIR/restrict_anonymous_structs.rs:5:12 - | -LL | field: struct { field: u8 }, - | ^^^^^^^^^^^^^^^^^^^^ - -error: anonymous structs are unimplemented - --> $DIR/restrict_anonymous_structs.rs:7:8 - | -LL | _: struct { field: u8 }, - | ^^^^^^^^^^^^^^^^^^^^ - -error: anonymous structs are unimplemented - --> $DIR/restrict_anonymous_structs.rs:16:12 - | -LL | field: struct { field: u8 }, - | ^^^^^^^^^^^^^^^^^^^^ - -error: anonymous structs are unimplemented - --> $DIR/restrict_anonymous_structs.rs:18:8 - | -LL | _: struct { field: u8 }, - | ^^^^^^^^^^^^^^^^^^^^ - -error: anonymous structs are unimplemented - --> $DIR/restrict_anonymous_structs.rs:28:13 - | -LL | _ : struct { field: u8 }, - | ^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 12 previous errors +error: aborting due to 7 previous errors diff --git a/tests/ui/union/unnamed-fields/restrict_anonymous_unions.rs b/tests/ui/union/unnamed-fields/restrict_anonymous_unions.rs index c69266089bb..c049ba92ed2 100644 --- a/tests/ui/union/unnamed-fields/restrict_anonymous_unions.rs +++ b/tests/ui/union/unnamed-fields/restrict_anonymous_unions.rs @@ -3,9 +3,7 @@ struct F { field: union { field: u8 }, //~ ERROR anonymous unions are not allowed outside of unnamed struct or union fields - //~^ ERROR anonymous unions are unimplemented _: union { field: u8 }, - //~^ ERROR anonymous unions are unimplemented } struct G { @@ -14,9 +12,7 @@ struct G { union H { field: union { field: u8 }, //~ ERROR anonymous unions are not allowed outside of unnamed struct or union fields - //~^ ERROR anonymous unions are unimplemented _: union { field: u8 }, - //~^ ERROR anonymous unions are unimplemented } union I { @@ -27,7 +23,6 @@ enum K { M { _ : union { field: u8 }, //~ ERROR anonymous unions are not allowed outside of unnamed struct or union fields //~^ ERROR unnamed fields are not allowed outside of structs or unions - //~| ERROR anonymous unions are unimplemented }, N { _ : u8, //~ ERROR unnamed fields are not allowed outside of structs or unions diff --git a/tests/ui/union/unnamed-fields/restrict_anonymous_unions.stderr b/tests/ui/union/unnamed-fields/restrict_anonymous_unions.stderr index c65cad775a9..c916e37a3e9 100644 --- a/tests/ui/union/unnamed-fields/restrict_anonymous_unions.stderr +++ b/tests/ui/union/unnamed-fields/restrict_anonymous_unions.stderr @@ -5,25 +5,25 @@ LL | field: union { field: u8 }, | ^^^^^^^^^^^^^^^^^^^ anonymous union declared here error: unnamed fields can only have struct or union types - --> $DIR/restrict_anonymous_unions.rs:12:5 + --> $DIR/restrict_anonymous_unions.rs:10:5 | LL | _: (u8, u8), | ^ -------- not a struct or union error: anonymous unions are not allowed outside of unnamed struct or union fields - --> $DIR/restrict_anonymous_unions.rs:16:12 + --> $DIR/restrict_anonymous_unions.rs:14:12 | LL | field: union { field: u8 }, | ^^^^^^^^^^^^^^^^^^^ anonymous union declared here error: unnamed fields can only have struct or union types - --> $DIR/restrict_anonymous_unions.rs:23:5 + --> $DIR/restrict_anonymous_unions.rs:19:5 | LL | _: (u8, u8), | ^ -------- not a struct or union error: unnamed fields are not allowed outside of structs or unions - --> $DIR/restrict_anonymous_unions.rs:28:9 + --> $DIR/restrict_anonymous_unions.rs:24:9 | LL | _ : union { field: u8 }, | -^^^^^^^^^^^^^^^^^^^^^^ @@ -31,48 +31,18 @@ LL | _ : union { field: u8 }, | unnamed field declared here error: anonymous unions are not allowed outside of unnamed struct or union fields - --> $DIR/restrict_anonymous_unions.rs:28:13 + --> $DIR/restrict_anonymous_unions.rs:24:13 | LL | _ : union { field: u8 }, | ^^^^^^^^^^^^^^^^^^^ anonymous union declared here error: unnamed fields are not allowed outside of structs or unions - --> $DIR/restrict_anonymous_unions.rs:33:9 + --> $DIR/restrict_anonymous_unions.rs:28:9 | LL | _ : u8, | -^^^^^ | | | unnamed field declared here -error: anonymous unions are unimplemented - --> $DIR/restrict_anonymous_unions.rs:5:12 - | -LL | field: union { field: u8 }, - | ^^^^^^^^^^^^^^^^^^^ - -error: anonymous unions are unimplemented - --> $DIR/restrict_anonymous_unions.rs:7:8 - | -LL | _: union { field: u8 }, - | ^^^^^^^^^^^^^^^^^^^ - -error: anonymous unions are unimplemented - --> $DIR/restrict_anonymous_unions.rs:16:12 - | -LL | field: union { field: u8 }, - | ^^^^^^^^^^^^^^^^^^^ - -error: anonymous unions are unimplemented - --> $DIR/restrict_anonymous_unions.rs:18:8 - | -LL | _: union { field: u8 }, - | ^^^^^^^^^^^^^^^^^^^ - -error: anonymous unions are unimplemented - --> $DIR/restrict_anonymous_unions.rs:28:13 - | -LL | _ : union { field: u8 }, - | ^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 12 previous errors +error: aborting due to 7 previous errors From 36d7e7fd3fee2a2e3e19f103d9595329093ab68e Mon Sep 17 00:00:00 2001 From: Frank King Date: Thu, 4 Jan 2024 21:56:45 +0800 Subject: [PATCH 25/56] check uniqueness of nested fields --- .../rustc_ast_passes/src/ast_validation.rs | 2 +- compiler/rustc_hir_analysis/messages.ftl | 19 + compiler/rustc_hir_analysis/src/collect.rs | 206 ++- compiler/rustc_hir_analysis/src/errors.rs | 53 +- compiler/rustc_middle/src/ty/adt.rs | 2 +- compiler/rustc_middle/src/ty/mod.rs | 5 + .../unnamed-fields/field_uniqueness_check.rs | 328 +++++ .../field_uniqueness_check.stderr | 1284 +++++++++++++++++ .../restrict_anonymous_structs.rs | 8 +- .../restrict_anonymous_structs.stderr | 12 +- .../restrict_anonymous_unions.rs | 8 +- .../restrict_anonymous_unions.stderr | 12 +- 12 files changed, 1842 insertions(+), 97 deletions(-) create mode 100644 tests/ui/union/unnamed-fields/field_uniqueness_check.rs create mode 100644 tests/ui/union/unnamed-fields/field_uniqueness_check.stderr diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 86597d20c19..d24dc44d2c5 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -220,7 +220,7 @@ impl<'a> AstValidator<'a> { } } TyKind::AnonStruct(_, ref fields) | TyKind::AnonUnion(_, ref fields) => { - walk_list!(self, visit_field_def, fields) + walk_list!(self, visit_struct_field_def, fields) } _ => visit::walk_ty(self, t), } diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl index d6f604c180b..662d859e993 100644 --- a/compiler/rustc_hir_analysis/messages.ftl +++ b/compiler/rustc_hir_analysis/messages.ftl @@ -123,6 +123,25 @@ hir_analysis_field_already_declared = .label = field already declared .previous_decl_label = `{$field_name}` first declared here +hir_analysis_field_already_declared_both_nested = + field `{$field_name}` is already declared + .label = field `{$field_name}` declared in this unnamed field + .nested_field_decl_note = field `{$field_name}` declared here + .previous_decl_label = `{$field_name}` first declared here in this unnamed field + .previous_nested_field_decl_note = field `{$field_name}` first declared here + +hir_analysis_field_already_declared_current_nested = + field `{$field_name}` is already declared + .label = field `{$field_name}` declared in this unnamed field + .nested_field_decl_note = field `{$field_name}` declared here + .previous_decl_label = `{$field_name}` first declared here + +hir_analysis_field_already_declared_previous_nested = + field `{$field_name}` is already declared + .label = field already declared + .previous_decl_label = `{$field_name}` first declared here in this unnamed field + .previous_nested_field_decl_note = field `{$field_name}` first declared here + hir_analysis_function_not_found_in_trait = function not found in this trait hir_analysis_function_not_have_default_implementation = function doesn't have a default implementation diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 768b07069c8..12e7b5dbfce 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -789,64 +789,100 @@ fn convert_enum_variant_types(tcx: TyCtxt<'_>, def_id: DefId) { } } -/* -/// In a type definition, we check that unnamed field names are distinct. -fn check_unnamed_fields_defn<'tcx>(tcx: TyCtxt<'tcx>, item: &hir::Item<'tcx>) { - let mut seen_fields: FxHashMap> = Default::default(); - fn check_fields_anon_adt_defn<'tcx>(tcx: TyCtxt<'tcx>, item: &hir::Item<'tcx>, seen_fields: &mut FxHashMap>) { - let fields = match &item.kind { - hir::ItemKind::Struct(fields, _) | hir::ItemKind::Union(fields, _) => fields, - _ => return, - }; - for field in fields.fields() { - if field.ident.name == kw::Underscore { - if let hir::TyKind::AnonAdt(item_id) = field.ty.kind() { - let item = tcx.hir().item(item_id); - check_fields_anon_adt_defn(tcx, item, &mut *seen_fields); - } else { - let field_ty = match tcx.type_of(field.def_id).instantiate_identity().ty_adt_def() { - Some(adt_ty) => adt_ty, - None => { - tcx.sess.emit_err(err); - return; - } - }; - if let Some(def_id) = field_ty.did().as_local() { - let item = tcx.hir().item(hir::ItemId { owner_id: hir::OwnerId { def_id }}); - check_fields_anon_adt_defn(tcx, item, &mut *seen_fields); - } - } - field_ty.flags() - let inner_adt_def = field_ty.ty_adt_def().expect("expect an adt"); - check_fields_anon_adt_defn(tcx, adt_def, &mut *seen_fields); - } else { - let span = field.did.as_local().map(|did| { - let hir_id = tcx.hir().local_def_id_to_hir_id(did); - tcx.hir().span(hir_id) - }); - match seen_fields.get(&ident.normalize_to_macros_2_0()).cloned() { - Some(Some(prev_span)) => { - tcx.sess.emit_err(errors::FieldAlreadyDeclared { - field_name: ident, - span: f.span, - prev_span, - }); - } - Some(None) => { - tcx.sess.emit_err(errors::FieldAlreadyDeclared { - field_name: f.ident, - span: f.span, - prev_span, - }); - } - None => - seen_fields.insert(f.ident.normalize_to_macros_2_0(), f.span); +#[derive(Clone, Copy)] +struct NestedSpan { + span: Span, + nested_field_span: Span, +} + +#[derive(Clone, Copy)] +enum FieldDeclSpan { + NotNested(Span), + Nested(NestedSpan), +} + +impl From for FieldDeclSpan { + fn from(span: Span) -> Self { + Self::NotNested(span) + } +} + +impl From for FieldDeclSpan { + fn from(span: NestedSpan) -> Self { + Self::Nested(span) + } +} + +/// Check the uniqueness of fields across adt where there are +/// nested fields imported from an unnamed field. +fn check_field_uniqueness_in_nested_adt( + tcx: TyCtxt<'_>, + adt_def: ty::AdtDef<'_>, + check: &mut impl FnMut(Ident, /* nested_field_span */ Span), +) { + for field in adt_def.all_fields() { + if field.is_unnamed() { + // Here we don't care about the generic parameters, so `instantiate_identity` is enough. + match tcx.type_of(field.did).instantiate_identity().kind() { + ty::Adt(adt_def, _) => { + check_field_uniqueness_in_nested_adt(tcx, *adt_def, &mut *check); } + ty_kind => bug!( + "Unexpected ty kind in check_field_uniqueness_in_nested_adt(): {ty_kind:?}" + ), } + } else { + check(field.ident(tcx), tcx.def_span(field.did)); } } } - */ + +/// Check the uniqueness of fields in a struct variant, and recursively +/// check the nested fields if it is an unnamed field with type of an +/// annoymous adt. +fn check_field_uniqueness( + tcx: TyCtxt<'_>, + field: &hir::FieldDef<'_>, + check: &mut impl FnMut(Ident, FieldDeclSpan), +) { + if field.ident.name == kw::Underscore { + let ty_span = field.ty.span; + match &field.ty.kind { + hir::TyKind::AnonAdt(item_id) => { + match &tcx.hir_node(item_id.hir_id()).expect_item().kind { + hir::ItemKind::Struct(variant_data, ..) + | hir::ItemKind::Union(variant_data, ..) => { + variant_data + .fields() + .iter() + .for_each(|f| check_field_uniqueness(tcx, f, &mut *check)); + } + item_kind => span_bug!( + ty_span, + "Unexpected item kind in check_field_uniqueness(): {item_kind:?}" + ), + } + } + hir::TyKind::Path(hir::QPath::Resolved(_, hir::Path { res, .. })) => { + check_field_uniqueness_in_nested_adt( + tcx, + tcx.adt_def(res.def_id()), + &mut |ident, nested_field_span| { + check(ident, NestedSpan { span: field.span, nested_field_span }.into()) + }, + ); + } + // Abort due to errors (there must be an error if an unnamed field + // has any type kind other than an anonymous adt or a named adt) + _ => { + debug_assert!(tcx.sess.has_errors().is_some()); + tcx.sess.abort_if_errors() + } + } + return; + } + check(field.ident, field.span.into()); +} fn convert_variant( tcx: TyCtxt<'_>, @@ -856,27 +892,61 @@ fn convert_variant( def: &hir::VariantData<'_>, adt_kind: ty::AdtKind, parent_did: LocalDefId, + is_anonymous: bool, ) -> ty::VariantDef { let mut has_unnamed_fields = false; - let mut seen_fields: FxHashMap = Default::default(); + let mut seen_fields: FxHashMap = Default::default(); let fields = def .fields() .iter() .inspect(|f| { - // Skip the unnamed field here, we will check it later. - if f.ident.name == kw::Underscore { - has_unnamed_fields = true; - return; - } - let dup_span = seen_fields.get(&f.ident.normalize_to_macros_2_0()).cloned(); - if let Some(prev_span) = dup_span { - tcx.dcx().emit_err(errors::FieldAlreadyDeclared { - field_name: f.ident, - span: f.span, - prev_span, + has_unnamed_fields |= f.ident.name == kw::Underscore; + if !is_anonymous { + check_field_uniqueness(tcx, f, &mut |ident, field_decl| { + use FieldDeclSpan::*; + let field_name = ident.name; + let ident = ident.normalize_to_macros_2_0(); + match (field_decl, seen_fields.get(&ident).copied()) { + (NotNested(span), Some(NotNested(prev_span))) => { + tcx.sess.emit_err(errors::FieldAlreadyDeclared::NotNested { + field_name, + span, + prev_span, + }); + } + (NotNested(span), Some(Nested(prev))) => { + tcx.sess.emit_err(errors::FieldAlreadyDeclared::PreviousNested { + field_name, + span, + prev_span: prev.span, + prev_nested_field_span: prev.nested_field_span, + }); + } + ( + Nested(NestedSpan { span, nested_field_span }), + Some(NotNested(prev_span)), + ) => { + tcx.sess.emit_err(errors::FieldAlreadyDeclared::CurrentNested { + field_name, + span, + nested_field_span, + prev_span, + }); + } + (Nested(NestedSpan { span, nested_field_span }), Some(Nested(prev))) => { + tcx.sess.emit_err(errors::FieldAlreadyDeclared::BothNested { + field_name, + span, + nested_field_span, + prev_span: prev.span, + prev_nested_field_span: prev.nested_field_span, + }); + } + (field_decl, None) => { + seen_fields.insert(ident, field_decl); + } + } }); - } else { - seen_fields.insert(f.ident.normalize_to_macros_2_0(), f.span); } }) .map(|f| ty::FieldDef { @@ -937,6 +1007,7 @@ fn adt_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::AdtDef<'_> { &v.data, AdtKind::Enum, def_id, + is_anonymous, ) }) .collect(); @@ -956,6 +1027,7 @@ fn adt_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::AdtDef<'_> { def, adt_kind, def_id, + is_anonymous, )) .collect(); diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index bec53693d6c..1e172f1d9f0 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -175,14 +175,51 @@ pub struct DropImplOnWrongItem { } #[derive(Diagnostic)] -#[diag(hir_analysis_field_already_declared, code = E0124)] -pub struct FieldAlreadyDeclared { - pub field_name: Ident, - #[primary_span] - #[label] - pub span: Span, - #[label(hir_analysis_previous_decl_label)] - pub prev_span: Span, +pub enum FieldAlreadyDeclared { + #[diag(hir_analysis_field_already_declared, code = E0124)] + NotNested { + field_name: Symbol, + #[primary_span] + #[label] + span: Span, + #[label(hir_analysis_previous_decl_label)] + prev_span: Span, + }, + #[diag(hir_analysis_field_already_declared_current_nested)] + CurrentNested { + field_name: Symbol, + #[primary_span] + #[label] + span: Span, + #[note(hir_analysis_nested_field_decl_note)] + nested_field_span: Span, + #[label(hir_analysis_previous_decl_label)] + prev_span: Span, + }, + #[diag(hir_analysis_field_already_declared_previous_nested)] + PreviousNested { + field_name: Symbol, + #[primary_span] + #[label] + span: Span, + #[label(hir_analysis_previous_decl_label)] + prev_span: Span, + #[note(hir_analysis_previous_nested_field_decl_note)] + prev_nested_field_span: Span, + }, + #[diag(hir_analysis_field_already_declared_both_nested)] + BothNested { + field_name: Symbol, + #[primary_span] + #[label] + span: Span, + #[note(hir_analysis_nested_field_decl_note)] + nested_field_span: Span, + #[label(hir_analysis_previous_decl_label)] + prev_span: Span, + #[note(hir_analysis_previous_nested_field_decl_note)] + prev_nested_field_span: Span, + }, } #[derive(Diagnostic)] diff --git a/compiler/rustc_middle/src/ty/adt.rs b/compiler/rustc_middle/src/ty/adt.rs index 854046c9ceb..d07a53ee679 100644 --- a/compiler/rustc_middle/src/ty/adt.rs +++ b/compiler/rustc_middle/src/ty/adt.rs @@ -401,7 +401,7 @@ impl<'tcx> AdtDef<'tcx> { } /// Returns an iterator over all fields contained - /// by this ADT. + /// by this ADT (nested unnamed fields are not expanded). #[inline] pub fn all_fields(self) -> impl Iterator + Clone { self.variants().iter().flat_map(|v| v.fields.iter()) diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 3cbe8f287e1..e73b9836174 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -1387,6 +1387,11 @@ impl<'tcx> FieldDef { pub fn ident(&self, tcx: TyCtxt<'_>) -> Ident { Ident::new(self.name, tcx.def_ident_span(self.did).unwrap()) } + + /// Returns whether the field is unnamed + pub fn is_unnamed(&self) -> bool { + self.name == rustc_span::symbol::kw::Underscore + } } #[derive(Debug, PartialEq, Eq)] diff --git a/tests/ui/union/unnamed-fields/field_uniqueness_check.rs b/tests/ui/union/unnamed-fields/field_uniqueness_check.rs new file mode 100644 index 00000000000..3cc36211875 --- /dev/null +++ b/tests/ui/union/unnamed-fields/field_uniqueness_check.rs @@ -0,0 +1,328 @@ +#![allow(incomplete_features)] +#![feature(unnamed_fields)] + +#[repr(C)] +struct Foo { + a: u8, +} + +#[repr(C)] +struct Bar { + _: union { + a: u8, + }, +} + + +// duplicated with a normal field +#[repr(C)] +union A { + // referent field + a: u8, + + // normal field + a: u8, //~ ERROR field `a` is already declared [E0124] + // nested field + _: struct { + a: u8, //~ ERROR field `a` is already declared [E0124] + a: u8, //~ ERROR field `a` is already declared [E0124] + }, + // more nested field + _: union { + _: struct { + a: u8, //~ ERROR field `a` is already declared [E0124] + }, + }, + // nested field in a named adt + _: Foo, //~ ERROR field `a` is already declared + _: Bar, //~ ERROR field `a` is already declared + // nested field in a named adt in an anoymous adt + _: struct { + _: Foo, //~ ERROR field `a` is already declared + _: Bar, //~ ERROR field `a` is already declared + }, +} + +// duplicated with a nested field +#[repr(C)] +struct B { + _: union { + // referent field + a: u8, + + // normal field (within the same anonymous adt) + a: u8, //~ ERROR field `a` is already declared [E0124] + // nested field (within the same anonymous adt) + _: struct { + a: u8, //~ ERROR field `a` is already declared [E0124] + }, + // more nested field (within the same anonymous adt) + _: union { + _: struct { + a: u8, //~ ERROR field `a` is already declared [E0124] + }, + }, + // nested field in a named adt (within the same anonymous adt) + _: Foo, //~ ERROR field `a` is already declared + _: Bar, //~ ERROR field `a` is already declared + // nested field in a named adt in an anoymous adt (within the same anonymous adt) + _: struct { + _: Foo, //~ ERROR field `a` is already declared + _: Bar, //~ ERROR field `a` is already declared + }, + }, + + // normal field + a: u8, //~ ERROR field `a` is already declared [E0124] + // nested field + _: struct { + a: u8, //~ ERROR field `a` is already declared [E0124] + }, + // more nested field + _: union { + _: struct { + a: u8, //~ ERROR field `a` is already declared [E0124] + }, + }, + // nested field in a named adt + _: Foo, //~ ERROR field `a` is already declared + _: Bar, //~ ERROR field `a` is already declared + // nested field in a named adt in an anoymous adt + _: struct { + _: Foo, //~ ERROR field `a` is already declared + _: Bar, //~ ERROR field `a` is already declared + }, +} + +// duplicated with a more nested field +#[repr(C)] +union C { + _: struct { + _: union { + // referent field + a: u8, + + // normal field (within the same anonymous adt) + a: u8, //~ ERROR field `a` is already declared [E0124] + // nested field (within the same anonymous adt) + _: struct { + a: u8, //~ ERROR field `a` is already declared [E0124] + }, + // more nested field (within the same anonymous adt) + _: union { + _: struct { + a: u8, //~ ERROR field `a` is already declared [E0124] + }, + }, + // nested field in a named adt (within the same anonymous adt) + _: Foo, //~ ERROR field `a` is already declared + _: Bar, //~ ERROR field `a` is already declared + // nested field in a named adt in an anoymous adt (within the same anonymous adt) + _: struct { + _: Foo, //~ ERROR field `a` is already declared + _: Bar, //~ ERROR field `a` is already declared + }, + }, + + // normal field (within the direct outer anonymous adt) + a: u8, //~ ERROR field `a` is already declared [E0124] + // nested field (within the direct outer anonymous adt) + _: struct { + a: u8, //~ ERROR field `a` is already declared [E0124] + }, + // more nested field (within the direct outer anonymous adt) + _: union { + _: struct { + a: u8, //~ ERROR field `a` is already declared [E0124] + }, + }, + // nested field in a named adt (within the direct outer anonymous adt) + _: Foo, //~ ERROR field `a` is already declared + _: Bar, //~ ERROR field `a` is already declared + // nested field in a named adt in an anoymous adt (within the direct outer anonymous adt) + _: struct { + _: Foo, //~ ERROR field `a` is already declared + _: Bar, //~ ERROR field `a` is already declared + }, + }, + // normal field + a: u8, //~ ERROR field `a` is already declared [E0124] + // nested field + _: union { + a: u8, //~ ERROR field `a` is already declared [E0124] + }, + // more nested field + _: struct { + _: union { + a: u8, //~ ERROR field `a` is already declared [E0124] + }, + }, + // nested field in a named adt + _: Foo, //~ ERROR field `a` is already declared + _: Bar, //~ ERROR field `a` is already declared + // nested field in a named adt in an anoymous adt + _: union { + _: Foo, //~ ERROR field `a` is already declared + _: Bar, //~ ERROR field `a` is already declared + }, +} + +// duplicated with a nested field in a named adt +#[repr(C)] +struct D { + // referent field `a` + _: Foo, + + // normal field + a: u8, //~ ERROR field `a` is already declared + // nested field + _: union { + a: u8, //~ ERROR field `a` is already declared + }, + // more nested field + _: struct { + _: union { + a: u8, //~ ERROR field `a` is already declared + }, + }, + // nested field in another named adt + _: Foo, //~ ERROR field `a` is already declared + _: Bar, //~ ERROR field `a` is already declared + // nested field in a named adt in an anoymous adt + _: union { + _: Foo, //~ ERROR field `a` is already declared + _: Bar, //~ ERROR field `a` is already declared + }, +} + +// duplicated with a nested field in a nested field of a named adt +#[repr(C)] +union D2 { + // referent field `a` + _: Bar, + + // normal field + a: u8, //~ ERROR field `a` is already declared + // nested field + _: union { + a: u8, //~ ERROR field `a` is already declared + }, + // more nested field + _: struct { + _: union { + a: u8, //~ ERROR field `a` is already declared + }, + }, + // nested field in another named adt + _: Foo, //~ ERROR field `a` is already declared + _: Bar, //~ ERROR field `a` is already declared + // nested field in a named adt in an anoymous adt + _: union { + _: Foo, //~ ERROR field `a` is already declared + _: Bar, //~ ERROR field `a` is already declared + }, +} + +// duplicated with a nested field in a named adt in an anonymous adt +#[repr(C)] +struct E { + _: struct { + // referent field `a` + _: Foo, + + // normal field (within the same anonymous adt) + a: u8, //~ ERROR field `a` is already declared + // nested field (within the same anonymous adt) + _: struct { + a: u8, //~ ERROR field `a` is already declared + }, + // more nested field (within the same anonymous adt) + _: union { + _: struct { + a: u8, //~ ERROR field `a` is already declared + }, + }, + // nested field in a named adt (within the same anonymous adt) + _: Foo, //~ ERROR field `a` is already declared + _: Bar, //~ ERROR field `a` is already declared + // nested field in a named adt in an anoymous adt (within the same anonymous adt) + _: struct { + _: Foo, //~ ERROR field `a` is already declared + _: Bar, //~ ERROR field `a` is already declared + }, + }, + + // normal field + a: u8, //~ ERROR field `a` is already declared + // nested field + _: union { + a: u8, //~ ERROR field `a` is already declared + }, + // more nested field + _: struct { + _: union { + a: u8, //~ ERROR field `a` is already declared + }, + }, + // nested field in another named adt + _: Foo, //~ ERROR field `a` is already declared + _: Bar, //~ ERROR field `a` is already declared + // nested field in a named adt in an anoymous adt + _: union { + _: Foo, //~ ERROR field `a` is already declared + _: Bar, //~ ERROR field `a` is already declared + }, +} + +// duplicated with a nested field in a named adt in an anonymous adt +#[repr(C)] +union E2 { + _: struct { + // referent field `a` + _: Bar, + + // normal field (within the same anonymous adt) + a: u8, //~ ERROR field `a` is already declared + // nested field (within the same anonymous adt) + _: struct { + a: u8, //~ ERROR field `a` is already declared + }, + // more nested field (within the same anonymous adt) + _: union { + _: struct { + a: u8, //~ ERROR field `a` is already declared + }, + }, + // nested field in a named adt (within the same anonymous adt) + _: Foo, //~ ERROR field `a` is already declared + _: Bar, //~ ERROR field `a` is already declared + // nested field in a named adt in an anoymous adt (within the same anonymous adt) + _: struct { + _: Foo, //~ ERROR field `a` is already declared + _: Bar, //~ ERROR field `a` is already declared + }, + }, + + // normal field + a: u8, //~ ERROR field `a` is already declared + // nested field + _: union { + a: u8, //~ ERROR field `a` is already declared + }, + // more nested field + _: struct { + _: union { + a: u8, //~ ERROR field `a` is already declared + }, + }, + // nested field in another named adt + _: Foo, //~ ERROR field `a` is already declared + _: Bar, //~ ERROR field `a` is already declared + // nested field in a named adt in an anoymous adt + _: union { + _: Foo, //~ ERROR field `a` is already declared + _: Bar, //~ ERROR field `a` is already declared + }, +} + +fn main() {} diff --git a/tests/ui/union/unnamed-fields/field_uniqueness_check.stderr b/tests/ui/union/unnamed-fields/field_uniqueness_check.stderr new file mode 100644 index 00000000000..4dea0aa4233 --- /dev/null +++ b/tests/ui/union/unnamed-fields/field_uniqueness_check.stderr @@ -0,0 +1,1284 @@ +error[E0124]: field `a` is already declared + --> $DIR/field_uniqueness_check.rs:24:5 + | +LL | a: u8, + | ----- `a` first declared here +... +LL | a: u8, + | ^^^^^ field already declared + +error[E0124]: field `a` is already declared + --> $DIR/field_uniqueness_check.rs:27:9 + | +LL | a: u8, + | ----- `a` first declared here +... +LL | a: u8, + | ^^^^^ field already declared + +error[E0124]: field `a` is already declared + --> $DIR/field_uniqueness_check.rs:28:9 + | +LL | a: u8, + | ----- `a` first declared here +... +LL | a: u8, + | ^^^^^ field already declared + +error[E0124]: field `a` is already declared + --> $DIR/field_uniqueness_check.rs:33:13 + | +LL | a: u8, + | ----- `a` first declared here +... +LL | a: u8, + | ^^^^^ field already declared + +error: field `a` is already declared + --> $DIR/field_uniqueness_check.rs:37:5 + | +LL | a: u8, + | ----- `a` first declared here +... +LL | _: Foo, + | ^^^^^^ field `a` declared in this unnamed field + | +note: field `a` declared here + --> $DIR/field_uniqueness_check.rs:6:5 + | +LL | a: u8, + | ^^^^^ + +error: field `a` is already declared + --> $DIR/field_uniqueness_check.rs:38:5 + | +LL | a: u8, + | ----- `a` first declared here +... +LL | _: Bar, + | ^^^^^^ field `a` declared in this unnamed field + | +note: field `a` declared here + --> $DIR/field_uniqueness_check.rs:12:9 + | +LL | a: u8, + | ^^^^^ + +error: field `a` is already declared + --> $DIR/field_uniqueness_check.rs:41:9 + | +LL | a: u8, + | ----- `a` first declared here +... +LL | _: Foo, + | ^^^^^^ field `a` declared in this unnamed field + | +note: field `a` declared here + --> $DIR/field_uniqueness_check.rs:6:5 + | +LL | a: u8, + | ^^^^^ + +error: field `a` is already declared + --> $DIR/field_uniqueness_check.rs:42:9 + | +LL | a: u8, + | ----- `a` first declared here +... +LL | _: Bar, + | ^^^^^^ field `a` declared in this unnamed field + | +note: field `a` declared here + --> $DIR/field_uniqueness_check.rs:12:9 + | +LL | a: u8, + | ^^^^^ + +error[E0124]: field `a` is already declared + --> $DIR/field_uniqueness_check.rs:54:9 + | +LL | a: u8, + | ----- `a` first declared here +... +LL | a: u8, + | ^^^^^ field already declared + +error[E0124]: field `a` is already declared + --> $DIR/field_uniqueness_check.rs:57:13 + | +LL | a: u8, + | ----- `a` first declared here +... +LL | a: u8, + | ^^^^^ field already declared + +error[E0124]: field `a` is already declared + --> $DIR/field_uniqueness_check.rs:62:17 + | +LL | a: u8, + | ----- `a` first declared here +... +LL | a: u8, + | ^^^^^ field already declared + +error: field `a` is already declared + --> $DIR/field_uniqueness_check.rs:66:9 + | +LL | a: u8, + | ----- `a` first declared here +... +LL | _: Foo, + | ^^^^^^ field `a` declared in this unnamed field + | +note: field `a` declared here + --> $DIR/field_uniqueness_check.rs:6:5 + | +LL | a: u8, + | ^^^^^ + +error: field `a` is already declared + --> $DIR/field_uniqueness_check.rs:67:9 + | +LL | a: u8, + | ----- `a` first declared here +... +LL | _: Bar, + | ^^^^^^ field `a` declared in this unnamed field + | +note: field `a` declared here + --> $DIR/field_uniqueness_check.rs:12:9 + | +LL | a: u8, + | ^^^^^ + +error: field `a` is already declared + --> $DIR/field_uniqueness_check.rs:70:13 + | +LL | a: u8, + | ----- `a` first declared here +... +LL | _: Foo, + | ^^^^^^ field `a` declared in this unnamed field + | +note: field `a` declared here + --> $DIR/field_uniqueness_check.rs:6:5 + | +LL | a: u8, + | ^^^^^ + +error: field `a` is already declared + --> $DIR/field_uniqueness_check.rs:71:13 + | +LL | a: u8, + | ----- `a` first declared here +... +LL | _: Bar, + | ^^^^^^ field `a` declared in this unnamed field + | +note: field `a` declared here + --> $DIR/field_uniqueness_check.rs:12:9 + | +LL | a: u8, + | ^^^^^ + +error[E0124]: field `a` is already declared + --> $DIR/field_uniqueness_check.rs:76:5 + | +LL | a: u8, + | ----- `a` first declared here +... +LL | a: u8, + | ^^^^^ field already declared + +error[E0124]: field `a` is already declared + --> $DIR/field_uniqueness_check.rs:79:9 + | +LL | a: u8, + | ----- `a` first declared here +... +LL | a: u8, + | ^^^^^ field already declared + +error[E0124]: field `a` is already declared + --> $DIR/field_uniqueness_check.rs:84:13 + | +LL | a: u8, + | ----- `a` first declared here +... +LL | a: u8, + | ^^^^^ field already declared + +error: field `a` is already declared + --> $DIR/field_uniqueness_check.rs:88:5 + | +LL | a: u8, + | ----- `a` first declared here +... +LL | _: Foo, + | ^^^^^^ field `a` declared in this unnamed field + | +note: field `a` declared here + --> $DIR/field_uniqueness_check.rs:6:5 + | +LL | a: u8, + | ^^^^^ + +error: field `a` is already declared + --> $DIR/field_uniqueness_check.rs:89:5 + | +LL | a: u8, + | ----- `a` first declared here +... +LL | _: Bar, + | ^^^^^^ field `a` declared in this unnamed field + | +note: field `a` declared here + --> $DIR/field_uniqueness_check.rs:12:9 + | +LL | a: u8, + | ^^^^^ + +error: field `a` is already declared + --> $DIR/field_uniqueness_check.rs:92:9 + | +LL | a: u8, + | ----- `a` first declared here +... +LL | _: Foo, + | ^^^^^^ field `a` declared in this unnamed field + | +note: field `a` declared here + --> $DIR/field_uniqueness_check.rs:6:5 + | +LL | a: u8, + | ^^^^^ + +error: field `a` is already declared + --> $DIR/field_uniqueness_check.rs:93:9 + | +LL | a: u8, + | ----- `a` first declared here +... +LL | _: Bar, + | ^^^^^^ field `a` declared in this unnamed field + | +note: field `a` declared here + --> $DIR/field_uniqueness_check.rs:12:9 + | +LL | a: u8, + | ^^^^^ + +error[E0124]: field `a` is already declared + --> $DIR/field_uniqueness_check.rs:106:13 + | +LL | a: u8, + | ----- `a` first declared here +... +LL | a: u8, + | ^^^^^ field already declared + +error[E0124]: field `a` is already declared + --> $DIR/field_uniqueness_check.rs:109:17 + | +LL | a: u8, + | ----- `a` first declared here +... +LL | a: u8, + | ^^^^^ field already declared + +error[E0124]: field `a` is already declared + --> $DIR/field_uniqueness_check.rs:114:21 + | +LL | a: u8, + | ----- `a` first declared here +... +LL | a: u8, + | ^^^^^ field already declared + +error: field `a` is already declared + --> $DIR/field_uniqueness_check.rs:118:13 + | +LL | a: u8, + | ----- `a` first declared here +... +LL | _: Foo, + | ^^^^^^ field `a` declared in this unnamed field + | +note: field `a` declared here + --> $DIR/field_uniqueness_check.rs:6:5 + | +LL | a: u8, + | ^^^^^ + +error: field `a` is already declared + --> $DIR/field_uniqueness_check.rs:119:13 + | +LL | a: u8, + | ----- `a` first declared here +... +LL | _: Bar, + | ^^^^^^ field `a` declared in this unnamed field + | +note: field `a` declared here + --> $DIR/field_uniqueness_check.rs:12:9 + | +LL | a: u8, + | ^^^^^ + +error: field `a` is already declared + --> $DIR/field_uniqueness_check.rs:122:17 + | +LL | a: u8, + | ----- `a` first declared here +... +LL | _: Foo, + | ^^^^^^ field `a` declared in this unnamed field + | +note: field `a` declared here + --> $DIR/field_uniqueness_check.rs:6:5 + | +LL | a: u8, + | ^^^^^ + +error: field `a` is already declared + --> $DIR/field_uniqueness_check.rs:123:17 + | +LL | a: u8, + | ----- `a` first declared here +... +LL | _: Bar, + | ^^^^^^ field `a` declared in this unnamed field + | +note: field `a` declared here + --> $DIR/field_uniqueness_check.rs:12:9 + | +LL | a: u8, + | ^^^^^ + +error[E0124]: field `a` is already declared + --> $DIR/field_uniqueness_check.rs:128:9 + | +LL | a: u8, + | ----- `a` first declared here +... +LL | a: u8, + | ^^^^^ field already declared + +error[E0124]: field `a` is already declared + --> $DIR/field_uniqueness_check.rs:131:13 + | +LL | a: u8, + | ----- `a` first declared here +... +LL | a: u8, + | ^^^^^ field already declared + +error[E0124]: field `a` is already declared + --> $DIR/field_uniqueness_check.rs:136:17 + | +LL | a: u8, + | ----- `a` first declared here +... +LL | a: u8, + | ^^^^^ field already declared + +error: field `a` is already declared + --> $DIR/field_uniqueness_check.rs:140:9 + | +LL | a: u8, + | ----- `a` first declared here +... +LL | _: Foo, + | ^^^^^^ field `a` declared in this unnamed field + | +note: field `a` declared here + --> $DIR/field_uniqueness_check.rs:6:5 + | +LL | a: u8, + | ^^^^^ + +error: field `a` is already declared + --> $DIR/field_uniqueness_check.rs:141:9 + | +LL | a: u8, + | ----- `a` first declared here +... +LL | _: Bar, + | ^^^^^^ field `a` declared in this unnamed field + | +note: field `a` declared here + --> $DIR/field_uniqueness_check.rs:12:9 + | +LL | a: u8, + | ^^^^^ + +error: field `a` is already declared + --> $DIR/field_uniqueness_check.rs:144:13 + | +LL | a: u8, + | ----- `a` first declared here +... +LL | _: Foo, + | ^^^^^^ field `a` declared in this unnamed field + | +note: field `a` declared here + --> $DIR/field_uniqueness_check.rs:6:5 + | +LL | a: u8, + | ^^^^^ + +error: field `a` is already declared + --> $DIR/field_uniqueness_check.rs:145:13 + | +LL | a: u8, + | ----- `a` first declared here +... +LL | _: Bar, + | ^^^^^^ field `a` declared in this unnamed field + | +note: field `a` declared here + --> $DIR/field_uniqueness_check.rs:12:9 + | +LL | a: u8, + | ^^^^^ + +error[E0124]: field `a` is already declared + --> $DIR/field_uniqueness_check.rs:149:5 + | +LL | a: u8, + | ----- `a` first declared here +... +LL | a: u8, + | ^^^^^ field already declared + +error[E0124]: field `a` is already declared + --> $DIR/field_uniqueness_check.rs:152:9 + | +LL | a: u8, + | ----- `a` first declared here +... +LL | a: u8, + | ^^^^^ field already declared + +error[E0124]: field `a` is already declared + --> $DIR/field_uniqueness_check.rs:157:13 + | +LL | a: u8, + | ----- `a` first declared here +... +LL | a: u8, + | ^^^^^ field already declared + +error: field `a` is already declared + --> $DIR/field_uniqueness_check.rs:161:5 + | +LL | a: u8, + | ----- `a` first declared here +... +LL | _: Foo, + | ^^^^^^ field `a` declared in this unnamed field + | +note: field `a` declared here + --> $DIR/field_uniqueness_check.rs:6:5 + | +LL | a: u8, + | ^^^^^ + +error: field `a` is already declared + --> $DIR/field_uniqueness_check.rs:162:5 + | +LL | a: u8, + | ----- `a` first declared here +... +LL | _: Bar, + | ^^^^^^ field `a` declared in this unnamed field + | +note: field `a` declared here + --> $DIR/field_uniqueness_check.rs:12:9 + | +LL | a: u8, + | ^^^^^ + +error: field `a` is already declared + --> $DIR/field_uniqueness_check.rs:165:9 + | +LL | a: u8, + | ----- `a` first declared here +... +LL | _: Foo, + | ^^^^^^ field `a` declared in this unnamed field + | +note: field `a` declared here + --> $DIR/field_uniqueness_check.rs:6:5 + | +LL | a: u8, + | ^^^^^ + +error: field `a` is already declared + --> $DIR/field_uniqueness_check.rs:166:9 + | +LL | a: u8, + | ----- `a` first declared here +... +LL | _: Bar, + | ^^^^^^ field `a` declared in this unnamed field + | +note: field `a` declared here + --> $DIR/field_uniqueness_check.rs:12:9 + | +LL | a: u8, + | ^^^^^ + +error: field `a` is already declared + --> $DIR/field_uniqueness_check.rs:177:5 + | +LL | _: Foo, + | ------ `a` first declared here in this unnamed field +... +LL | a: u8, + | ^^^^^ field already declared + | +note: field `a` first declared here + --> $DIR/field_uniqueness_check.rs:6:5 + | +LL | a: u8, + | ^^^^^ + +error: field `a` is already declared + --> $DIR/field_uniqueness_check.rs:180:9 + | +LL | _: Foo, + | ------ `a` first declared here in this unnamed field +... +LL | a: u8, + | ^^^^^ field already declared + | +note: field `a` first declared here + --> $DIR/field_uniqueness_check.rs:6:5 + | +LL | a: u8, + | ^^^^^ + +error: field `a` is already declared + --> $DIR/field_uniqueness_check.rs:185:13 + | +LL | _: Foo, + | ------ `a` first declared here in this unnamed field +... +LL | a: u8, + | ^^^^^ field already declared + | +note: field `a` first declared here + --> $DIR/field_uniqueness_check.rs:6:5 + | +LL | a: u8, + | ^^^^^ + +error: field `a` is already declared + --> $DIR/field_uniqueness_check.rs:189:5 + | +LL | _: Foo, + | ------ `a` first declared here in this unnamed field +... +LL | _: Foo, + | ^^^^^^ field `a` declared in this unnamed field + | +note: field `a` declared here + --> $DIR/field_uniqueness_check.rs:6:5 + | +LL | a: u8, + | ^^^^^ +note: field `a` first declared here + --> $DIR/field_uniqueness_check.rs:6:5 + | +LL | a: u8, + | ^^^^^ + +error: field `a` is already declared + --> $DIR/field_uniqueness_check.rs:190:5 + | +LL | _: Foo, + | ------ `a` first declared here in this unnamed field +... +LL | _: Bar, + | ^^^^^^ field `a` declared in this unnamed field + | +note: field `a` declared here + --> $DIR/field_uniqueness_check.rs:12:9 + | +LL | a: u8, + | ^^^^^ +note: field `a` first declared here + --> $DIR/field_uniqueness_check.rs:6:5 + | +LL | a: u8, + | ^^^^^ + +error: field `a` is already declared + --> $DIR/field_uniqueness_check.rs:193:9 + | +LL | _: Foo, + | ------ `a` first declared here in this unnamed field +... +LL | _: Foo, + | ^^^^^^ field `a` declared in this unnamed field + | +note: field `a` declared here + --> $DIR/field_uniqueness_check.rs:6:5 + | +LL | a: u8, + | ^^^^^ +note: field `a` first declared here + --> $DIR/field_uniqueness_check.rs:6:5 + | +LL | a: u8, + | ^^^^^ + +error: field `a` is already declared + --> $DIR/field_uniqueness_check.rs:194:9 + | +LL | _: Foo, + | ------ `a` first declared here in this unnamed field +... +LL | _: Bar, + | ^^^^^^ field `a` declared in this unnamed field + | +note: field `a` declared here + --> $DIR/field_uniqueness_check.rs:12:9 + | +LL | a: u8, + | ^^^^^ +note: field `a` first declared here + --> $DIR/field_uniqueness_check.rs:6:5 + | +LL | a: u8, + | ^^^^^ + +error: field `a` is already declared + --> $DIR/field_uniqueness_check.rs:205:5 + | +LL | _: Bar, + | ------ `a` first declared here in this unnamed field +... +LL | a: u8, + | ^^^^^ field already declared + | +note: field `a` first declared here + --> $DIR/field_uniqueness_check.rs:12:9 + | +LL | a: u8, + | ^^^^^ + +error: field `a` is already declared + --> $DIR/field_uniqueness_check.rs:208:9 + | +LL | _: Bar, + | ------ `a` first declared here in this unnamed field +... +LL | a: u8, + | ^^^^^ field already declared + | +note: field `a` first declared here + --> $DIR/field_uniqueness_check.rs:12:9 + | +LL | a: u8, + | ^^^^^ + +error: field `a` is already declared + --> $DIR/field_uniqueness_check.rs:213:13 + | +LL | _: Bar, + | ------ `a` first declared here in this unnamed field +... +LL | a: u8, + | ^^^^^ field already declared + | +note: field `a` first declared here + --> $DIR/field_uniqueness_check.rs:12:9 + | +LL | a: u8, + | ^^^^^ + +error: field `a` is already declared + --> $DIR/field_uniqueness_check.rs:217:5 + | +LL | _: Bar, + | ------ `a` first declared here in this unnamed field +... +LL | _: Foo, + | ^^^^^^ field `a` declared in this unnamed field + | +note: field `a` declared here + --> $DIR/field_uniqueness_check.rs:6:5 + | +LL | a: u8, + | ^^^^^ +note: field `a` first declared here + --> $DIR/field_uniqueness_check.rs:12:9 + | +LL | a: u8, + | ^^^^^ + +error: field `a` is already declared + --> $DIR/field_uniqueness_check.rs:218:5 + | +LL | _: Bar, + | ------ `a` first declared here in this unnamed field +... +LL | _: Bar, + | ^^^^^^ field `a` declared in this unnamed field + | +note: field `a` declared here + --> $DIR/field_uniqueness_check.rs:12:9 + | +LL | a: u8, + | ^^^^^ +note: field `a` first declared here + --> $DIR/field_uniqueness_check.rs:12:9 + | +LL | a: u8, + | ^^^^^ + +error: field `a` is already declared + --> $DIR/field_uniqueness_check.rs:221:9 + | +LL | _: Bar, + | ------ `a` first declared here in this unnamed field +... +LL | _: Foo, + | ^^^^^^ field `a` declared in this unnamed field + | +note: field `a` declared here + --> $DIR/field_uniqueness_check.rs:6:5 + | +LL | a: u8, + | ^^^^^ +note: field `a` first declared here + --> $DIR/field_uniqueness_check.rs:12:9 + | +LL | a: u8, + | ^^^^^ + +error: field `a` is already declared + --> $DIR/field_uniqueness_check.rs:222:9 + | +LL | _: Bar, + | ------ `a` first declared here in this unnamed field +... +LL | _: Bar, + | ^^^^^^ field `a` declared in this unnamed field + | +note: field `a` declared here + --> $DIR/field_uniqueness_check.rs:12:9 + | +LL | a: u8, + | ^^^^^ +note: field `a` first declared here + --> $DIR/field_uniqueness_check.rs:12:9 + | +LL | a: u8, + | ^^^^^ + +error: field `a` is already declared + --> $DIR/field_uniqueness_check.rs:234:9 + | +LL | _: Foo, + | ------ `a` first declared here in this unnamed field +... +LL | a: u8, + | ^^^^^ field already declared + | +note: field `a` first declared here + --> $DIR/field_uniqueness_check.rs:6:5 + | +LL | a: u8, + | ^^^^^ + +error: field `a` is already declared + --> $DIR/field_uniqueness_check.rs:237:13 + | +LL | _: Foo, + | ------ `a` first declared here in this unnamed field +... +LL | a: u8, + | ^^^^^ field already declared + | +note: field `a` first declared here + --> $DIR/field_uniqueness_check.rs:6:5 + | +LL | a: u8, + | ^^^^^ + +error: field `a` is already declared + --> $DIR/field_uniqueness_check.rs:242:17 + | +LL | _: Foo, + | ------ `a` first declared here in this unnamed field +... +LL | a: u8, + | ^^^^^ field already declared + | +note: field `a` first declared here + --> $DIR/field_uniqueness_check.rs:6:5 + | +LL | a: u8, + | ^^^^^ + +error: field `a` is already declared + --> $DIR/field_uniqueness_check.rs:246:9 + | +LL | _: Foo, + | ------ `a` first declared here in this unnamed field +... +LL | _: Foo, + | ^^^^^^ field `a` declared in this unnamed field + | +note: field `a` declared here + --> $DIR/field_uniqueness_check.rs:6:5 + | +LL | a: u8, + | ^^^^^ +note: field `a` first declared here + --> $DIR/field_uniqueness_check.rs:6:5 + | +LL | a: u8, + | ^^^^^ + +error: field `a` is already declared + --> $DIR/field_uniqueness_check.rs:247:9 + | +LL | _: Foo, + | ------ `a` first declared here in this unnamed field +... +LL | _: Bar, + | ^^^^^^ field `a` declared in this unnamed field + | +note: field `a` declared here + --> $DIR/field_uniqueness_check.rs:12:9 + | +LL | a: u8, + | ^^^^^ +note: field `a` first declared here + --> $DIR/field_uniqueness_check.rs:6:5 + | +LL | a: u8, + | ^^^^^ + +error: field `a` is already declared + --> $DIR/field_uniqueness_check.rs:250:13 + | +LL | _: Foo, + | ------ `a` first declared here in this unnamed field +... +LL | _: Foo, + | ^^^^^^ field `a` declared in this unnamed field + | +note: field `a` declared here + --> $DIR/field_uniqueness_check.rs:6:5 + | +LL | a: u8, + | ^^^^^ +note: field `a` first declared here + --> $DIR/field_uniqueness_check.rs:6:5 + | +LL | a: u8, + | ^^^^^ + +error: field `a` is already declared + --> $DIR/field_uniqueness_check.rs:251:13 + | +LL | _: Foo, + | ------ `a` first declared here in this unnamed field +... +LL | _: Bar, + | ^^^^^^ field `a` declared in this unnamed field + | +note: field `a` declared here + --> $DIR/field_uniqueness_check.rs:12:9 + | +LL | a: u8, + | ^^^^^ +note: field `a` first declared here + --> $DIR/field_uniqueness_check.rs:6:5 + | +LL | a: u8, + | ^^^^^ + +error: field `a` is already declared + --> $DIR/field_uniqueness_check.rs:256:5 + | +LL | _: Foo, + | ------ `a` first declared here in this unnamed field +... +LL | a: u8, + | ^^^^^ field already declared + | +note: field `a` first declared here + --> $DIR/field_uniqueness_check.rs:6:5 + | +LL | a: u8, + | ^^^^^ + +error: field `a` is already declared + --> $DIR/field_uniqueness_check.rs:259:9 + | +LL | _: Foo, + | ------ `a` first declared here in this unnamed field +... +LL | a: u8, + | ^^^^^ field already declared + | +note: field `a` first declared here + --> $DIR/field_uniqueness_check.rs:6:5 + | +LL | a: u8, + | ^^^^^ + +error: field `a` is already declared + --> $DIR/field_uniqueness_check.rs:264:13 + | +LL | _: Foo, + | ------ `a` first declared here in this unnamed field +... +LL | a: u8, + | ^^^^^ field already declared + | +note: field `a` first declared here + --> $DIR/field_uniqueness_check.rs:6:5 + | +LL | a: u8, + | ^^^^^ + +error: field `a` is already declared + --> $DIR/field_uniqueness_check.rs:268:5 + | +LL | _: Foo, + | ------ `a` first declared here in this unnamed field +... +LL | _: Foo, + | ^^^^^^ field `a` declared in this unnamed field + | +note: field `a` declared here + --> $DIR/field_uniqueness_check.rs:6:5 + | +LL | a: u8, + | ^^^^^ +note: field `a` first declared here + --> $DIR/field_uniqueness_check.rs:6:5 + | +LL | a: u8, + | ^^^^^ + +error: field `a` is already declared + --> $DIR/field_uniqueness_check.rs:269:5 + | +LL | _: Foo, + | ------ `a` first declared here in this unnamed field +... +LL | _: Bar, + | ^^^^^^ field `a` declared in this unnamed field + | +note: field `a` declared here + --> $DIR/field_uniqueness_check.rs:12:9 + | +LL | a: u8, + | ^^^^^ +note: field `a` first declared here + --> $DIR/field_uniqueness_check.rs:6:5 + | +LL | a: u8, + | ^^^^^ + +error: field `a` is already declared + --> $DIR/field_uniqueness_check.rs:272:9 + | +LL | _: Foo, + | ------ `a` first declared here in this unnamed field +... +LL | _: Foo, + | ^^^^^^ field `a` declared in this unnamed field + | +note: field `a` declared here + --> $DIR/field_uniqueness_check.rs:6:5 + | +LL | a: u8, + | ^^^^^ +note: field `a` first declared here + --> $DIR/field_uniqueness_check.rs:6:5 + | +LL | a: u8, + | ^^^^^ + +error: field `a` is already declared + --> $DIR/field_uniqueness_check.rs:273:9 + | +LL | _: Foo, + | ------ `a` first declared here in this unnamed field +... +LL | _: Bar, + | ^^^^^^ field `a` declared in this unnamed field + | +note: field `a` declared here + --> $DIR/field_uniqueness_check.rs:12:9 + | +LL | a: u8, + | ^^^^^ +note: field `a` first declared here + --> $DIR/field_uniqueness_check.rs:6:5 + | +LL | a: u8, + | ^^^^^ + +error: field `a` is already declared + --> $DIR/field_uniqueness_check.rs:285:9 + | +LL | _: Bar, + | ------ `a` first declared here in this unnamed field +... +LL | a: u8, + | ^^^^^ field already declared + | +note: field `a` first declared here + --> $DIR/field_uniqueness_check.rs:12:9 + | +LL | a: u8, + | ^^^^^ + +error: field `a` is already declared + --> $DIR/field_uniqueness_check.rs:288:13 + | +LL | _: Bar, + | ------ `a` first declared here in this unnamed field +... +LL | a: u8, + | ^^^^^ field already declared + | +note: field `a` first declared here + --> $DIR/field_uniqueness_check.rs:12:9 + | +LL | a: u8, + | ^^^^^ + +error: field `a` is already declared + --> $DIR/field_uniqueness_check.rs:293:17 + | +LL | _: Bar, + | ------ `a` first declared here in this unnamed field +... +LL | a: u8, + | ^^^^^ field already declared + | +note: field `a` first declared here + --> $DIR/field_uniqueness_check.rs:12:9 + | +LL | a: u8, + | ^^^^^ + +error: field `a` is already declared + --> $DIR/field_uniqueness_check.rs:297:9 + | +LL | _: Bar, + | ------ `a` first declared here in this unnamed field +... +LL | _: Foo, + | ^^^^^^ field `a` declared in this unnamed field + | +note: field `a` declared here + --> $DIR/field_uniqueness_check.rs:6:5 + | +LL | a: u8, + | ^^^^^ +note: field `a` first declared here + --> $DIR/field_uniqueness_check.rs:12:9 + | +LL | a: u8, + | ^^^^^ + +error: field `a` is already declared + --> $DIR/field_uniqueness_check.rs:298:9 + | +LL | _: Bar, + | ------ `a` first declared here in this unnamed field +... +LL | _: Bar, + | ^^^^^^ field `a` declared in this unnamed field + | +note: field `a` declared here + --> $DIR/field_uniqueness_check.rs:12:9 + | +LL | a: u8, + | ^^^^^ +note: field `a` first declared here + --> $DIR/field_uniqueness_check.rs:12:9 + | +LL | a: u8, + | ^^^^^ + +error: field `a` is already declared + --> $DIR/field_uniqueness_check.rs:301:13 + | +LL | _: Bar, + | ------ `a` first declared here in this unnamed field +... +LL | _: Foo, + | ^^^^^^ field `a` declared in this unnamed field + | +note: field `a` declared here + --> $DIR/field_uniqueness_check.rs:6:5 + | +LL | a: u8, + | ^^^^^ +note: field `a` first declared here + --> $DIR/field_uniqueness_check.rs:12:9 + | +LL | a: u8, + | ^^^^^ + +error: field `a` is already declared + --> $DIR/field_uniqueness_check.rs:302:13 + | +LL | _: Bar, + | ------ `a` first declared here in this unnamed field +... +LL | _: Bar, + | ^^^^^^ field `a` declared in this unnamed field + | +note: field `a` declared here + --> $DIR/field_uniqueness_check.rs:12:9 + | +LL | a: u8, + | ^^^^^ +note: field `a` first declared here + --> $DIR/field_uniqueness_check.rs:12:9 + | +LL | a: u8, + | ^^^^^ + +error: field `a` is already declared + --> $DIR/field_uniqueness_check.rs:307:5 + | +LL | _: Bar, + | ------ `a` first declared here in this unnamed field +... +LL | a: u8, + | ^^^^^ field already declared + | +note: field `a` first declared here + --> $DIR/field_uniqueness_check.rs:12:9 + | +LL | a: u8, + | ^^^^^ + +error: field `a` is already declared + --> $DIR/field_uniqueness_check.rs:310:9 + | +LL | _: Bar, + | ------ `a` first declared here in this unnamed field +... +LL | a: u8, + | ^^^^^ field already declared + | +note: field `a` first declared here + --> $DIR/field_uniqueness_check.rs:12:9 + | +LL | a: u8, + | ^^^^^ + +error: field `a` is already declared + --> $DIR/field_uniqueness_check.rs:315:13 + | +LL | _: Bar, + | ------ `a` first declared here in this unnamed field +... +LL | a: u8, + | ^^^^^ field already declared + | +note: field `a` first declared here + --> $DIR/field_uniqueness_check.rs:12:9 + | +LL | a: u8, + | ^^^^^ + +error: field `a` is already declared + --> $DIR/field_uniqueness_check.rs:319:5 + | +LL | _: Bar, + | ------ `a` first declared here in this unnamed field +... +LL | _: Foo, + | ^^^^^^ field `a` declared in this unnamed field + | +note: field `a` declared here + --> $DIR/field_uniqueness_check.rs:6:5 + | +LL | a: u8, + | ^^^^^ +note: field `a` first declared here + --> $DIR/field_uniqueness_check.rs:12:9 + | +LL | a: u8, + | ^^^^^ + +error: field `a` is already declared + --> $DIR/field_uniqueness_check.rs:320:5 + | +LL | _: Bar, + | ------ `a` first declared here in this unnamed field +... +LL | _: Bar, + | ^^^^^^ field `a` declared in this unnamed field + | +note: field `a` declared here + --> $DIR/field_uniqueness_check.rs:12:9 + | +LL | a: u8, + | ^^^^^ +note: field `a` first declared here + --> $DIR/field_uniqueness_check.rs:12:9 + | +LL | a: u8, + | ^^^^^ + +error: field `a` is already declared + --> $DIR/field_uniqueness_check.rs:323:9 + | +LL | _: Bar, + | ------ `a` first declared here in this unnamed field +... +LL | _: Foo, + | ^^^^^^ field `a` declared in this unnamed field + | +note: field `a` declared here + --> $DIR/field_uniqueness_check.rs:6:5 + | +LL | a: u8, + | ^^^^^ +note: field `a` first declared here + --> $DIR/field_uniqueness_check.rs:12:9 + | +LL | a: u8, + | ^^^^^ + +error: field `a` is already declared + --> $DIR/field_uniqueness_check.rs:324:9 + | +LL | _: Bar, + | ------ `a` first declared here in this unnamed field +... +LL | _: Bar, + | ^^^^^^ field `a` declared in this unnamed field + | +note: field `a` declared here + --> $DIR/field_uniqueness_check.rs:12:9 + | +LL | a: u8, + | ^^^^^ +note: field `a` first declared here + --> $DIR/field_uniqueness_check.rs:12:9 + | +LL | a: u8, + | ^^^^^ + +error: aborting due to 85 previous errors + +For more information about this error, try `rustc --explain E0124`. diff --git a/tests/ui/union/unnamed-fields/restrict_anonymous_structs.rs b/tests/ui/union/unnamed-fields/restrict_anonymous_structs.rs index 76525ec0bb1..03545ed7b18 100644 --- a/tests/ui/union/unnamed-fields/restrict_anonymous_structs.rs +++ b/tests/ui/union/unnamed-fields/restrict_anonymous_structs.rs @@ -2,8 +2,8 @@ #![feature(unnamed_fields)] struct F { - field: struct { field: u8 }, //~ ERROR anonymous structs are not allowed outside of unnamed struct or union fields - _: struct { field: u8 }, + field1: struct { field2: u8 }, //~ ERROR anonymous structs are not allowed outside of unnamed struct or union fields + _: struct { field3: u8 }, } struct G { @@ -11,8 +11,8 @@ struct G { } union H { - field: struct { field: u8 }, //~ ERROR anonymous structs are not allowed outside of unnamed struct or union fields - _: struct { field: u8 }, + field1: struct { field2: u8 }, //~ ERROR anonymous structs are not allowed outside of unnamed struct or union fields + _: struct { field3: u8 }, } union I { diff --git a/tests/ui/union/unnamed-fields/restrict_anonymous_structs.stderr b/tests/ui/union/unnamed-fields/restrict_anonymous_structs.stderr index 846e3451a71..3b3890af771 100644 --- a/tests/ui/union/unnamed-fields/restrict_anonymous_structs.stderr +++ b/tests/ui/union/unnamed-fields/restrict_anonymous_structs.stderr @@ -1,8 +1,8 @@ error: anonymous structs are not allowed outside of unnamed struct or union fields - --> $DIR/restrict_anonymous_structs.rs:5:12 + --> $DIR/restrict_anonymous_structs.rs:5:13 | -LL | field: struct { field: u8 }, - | ^^^^^^^^^^^^^^^^^^^^ anonymous struct declared here +LL | field1: struct { field2: u8 }, + | ^^^^^^^^^^^^^^^^^^^^^ anonymous struct declared here error: unnamed fields can only have struct or union types --> $DIR/restrict_anonymous_structs.rs:10:5 @@ -11,10 +11,10 @@ LL | _: (u8, u8), | ^ -------- not a struct or union error: anonymous structs are not allowed outside of unnamed struct or union fields - --> $DIR/restrict_anonymous_structs.rs:14:12 + --> $DIR/restrict_anonymous_structs.rs:14:13 | -LL | field: struct { field: u8 }, - | ^^^^^^^^^^^^^^^^^^^^ anonymous struct declared here +LL | field1: struct { field2: u8 }, + | ^^^^^^^^^^^^^^^^^^^^^ anonymous struct declared here error: unnamed fields can only have struct or union types --> $DIR/restrict_anonymous_structs.rs:19:5 diff --git a/tests/ui/union/unnamed-fields/restrict_anonymous_unions.rs b/tests/ui/union/unnamed-fields/restrict_anonymous_unions.rs index c049ba92ed2..9ffe71b28c2 100644 --- a/tests/ui/union/unnamed-fields/restrict_anonymous_unions.rs +++ b/tests/ui/union/unnamed-fields/restrict_anonymous_unions.rs @@ -2,8 +2,8 @@ #![feature(unnamed_fields)] struct F { - field: union { field: u8 }, //~ ERROR anonymous unions are not allowed outside of unnamed struct or union fields - _: union { field: u8 }, + field1: union { field2: u8 }, //~ ERROR anonymous unions are not allowed outside of unnamed struct or union fields + _: union { field3: u8 }, } struct G { @@ -11,8 +11,8 @@ struct G { } union H { - field: union { field: u8 }, //~ ERROR anonymous unions are not allowed outside of unnamed struct or union fields - _: union { field: u8 }, + field1: union { field2: u8 }, //~ ERROR anonymous unions are not allowed outside of unnamed struct or union fields + _: union { field3: u8 }, } union I { diff --git a/tests/ui/union/unnamed-fields/restrict_anonymous_unions.stderr b/tests/ui/union/unnamed-fields/restrict_anonymous_unions.stderr index c916e37a3e9..f8679aad2d7 100644 --- a/tests/ui/union/unnamed-fields/restrict_anonymous_unions.stderr +++ b/tests/ui/union/unnamed-fields/restrict_anonymous_unions.stderr @@ -1,8 +1,8 @@ error: anonymous unions are not allowed outside of unnamed struct or union fields - --> $DIR/restrict_anonymous_unions.rs:5:12 + --> $DIR/restrict_anonymous_unions.rs:5:13 | -LL | field: union { field: u8 }, - | ^^^^^^^^^^^^^^^^^^^ anonymous union declared here +LL | field1: union { field2: u8 }, + | ^^^^^^^^^^^^^^^^^^^^ anonymous union declared here error: unnamed fields can only have struct or union types --> $DIR/restrict_anonymous_unions.rs:10:5 @@ -11,10 +11,10 @@ LL | _: (u8, u8), | ^ -------- not a struct or union error: anonymous unions are not allowed outside of unnamed struct or union fields - --> $DIR/restrict_anonymous_unions.rs:14:12 + --> $DIR/restrict_anonymous_unions.rs:14:13 | -LL | field: union { field: u8 }, - | ^^^^^^^^^^^^^^^^^^^ anonymous union declared here +LL | field1: union { field2: u8 }, + | ^^^^^^^^^^^^^^^^^^^^ anonymous union declared here error: unnamed fields can only have struct or union types --> $DIR/restrict_anonymous_unions.rs:19:5 From 0c0df4efe09072013067fc5829996cc53f5c9bd3 Mon Sep 17 00:00:00 2001 From: Frank King Date: Thu, 4 Jan 2024 21:45:06 +0800 Subject: [PATCH 26/56] Lowering field access for anonymous adts --- compiler/rustc_ast_lowering/src/lib.rs | 27 +++--- compiler/rustc_hir_analysis/src/collect.rs | 26 ++++-- compiler/rustc_hir_typeck/src/expr.rs | 56 ++++++++---- .../rustc_hir_typeck/src/fn_ctxt/_impl.rs | 10 ++- compiler/rustc_hir_typeck/src/pat.rs | 3 +- compiler/rustc_hir_typeck/src/writeback.rs | 5 ++ compiler/rustc_middle/src/query/erase.rs | 1 + compiler/rustc_middle/src/query/mod.rs | 4 + .../rustc_middle/src/ty/typeck_results.rs | 19 ++++ compiler/rustc_mir_build/src/thir/cx/expr.rs | 20 +++-- .../rustc_resolve/src/build_reduced_graph.rs | 88 ++++++++++++++----- compiler/rustc_resolve/src/def_collector.rs | 15 +++- compiler/rustc_resolve/src/lib.rs | 6 ++ .../src/solve/assembly/structural_traits.rs | 2 +- .../src/traits/select/mod.rs | 4 +- ...d_access.bar.SimplifyCfg-initial.after.mir | 61 +++++++++++++ ...d_access.foo.SimplifyCfg-initial.after.mir | 59 +++++++++++++ tests/mir-opt/unnamed-fields/field_access.rs | 56 ++++++++++++ 18 files changed, 391 insertions(+), 71 deletions(-) create mode 100644 tests/mir-opt/unnamed-fields/field_access.bar.SimplifyCfg-initial.after.mir create mode 100644 tests/mir-opt/unnamed-fields/field_access.foo.SimplifyCfg-initial.after.mir create mode 100644 tests/mir-opt/unnamed-fields/field_access.rs diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 7a071242256..480072ce705 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -1299,33 +1299,28 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // // ^_____________________| // } // ``` - TyKind::AnonStruct(def_node_id, fields) | TyKind::AnonUnion(def_node_id, fields) => { - let (def_kind, item_kind): (DefKind, fn(_, _) -> _) = match t.kind { - TyKind::AnonStruct(..) => (DefKind::Struct, hir::ItemKind::Struct), - TyKind::AnonUnion(..) => (DefKind::Union, hir::ItemKind::Union), - _ => unreachable!(), - }; - let def_id = self.create_def( - self.current_hir_id_owner.def_id, - *def_node_id, - kw::Empty, - def_kind, - t.span, - ); + TyKind::AnonStruct(node_id, fields) | TyKind::AnonUnion(node_id, fields) => { + // Here its `def_id` is created in `build_reduced_graph`. + let def_id = self.local_def_id(*node_id); debug!(?def_id); let owner_id = hir::OwnerId { def_id }; - self.with_hir_id_owner(*def_node_id, |this| { + self.with_hir_id_owner(*node_id, |this| { let fields = this.arena.alloc_from_iter( fields.iter().enumerate().map(|f| this.lower_field_def(f)), ); let span = t.span; - let variant_data = hir::VariantData::Struct(fields, false); + let variant_data = hir::VariantData::Struct { fields, recovered: false }; // FIXME: capture the generics from the outer adt. let generics = hir::Generics::empty(); + let kind = match t.kind { + TyKind::AnonStruct(..) => hir::ItemKind::Struct(variant_data, generics), + TyKind::AnonUnion(..) => hir::ItemKind::Union(variant_data, generics), + _ => unreachable!(), + }; hir::OwnerNode::Item(this.arena.alloc(hir::Item { ident: Ident::new(kw::Empty, span), owner_id, - kind: item_kind(variant_data, generics), + kind, span: this.lower_span(span), vis_span: this.lower_span(span.shrink_to_lo()), })) diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 12e7b5dbfce..15ddbd84b2c 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -31,6 +31,7 @@ use rustc_middle::ty::util::{Discr, IntTypeExt}; use rustc_middle::ty::{self, AdtKind, Const, IsSuggestable, ToPredicate, Ty, TyCtxt}; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::Span; +use rustc_target::abi::FieldIdx; use rustc_target::spec::abi; use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::traits::error_reporting::suggestions::NextTypeParamName; @@ -84,6 +85,7 @@ pub fn provide(providers: &mut Providers) { coroutine_for_closure, collect_mod_item_types, is_type_alias_impl_trait, + find_field, ..*providers }; } @@ -875,8 +877,8 @@ fn check_field_uniqueness( // Abort due to errors (there must be an error if an unnamed field // has any type kind other than an anonymous adt or a named adt) _ => { - debug_assert!(tcx.sess.has_errors().is_some()); - tcx.sess.abort_if_errors() + debug_assert!(tcx.dcx().has_errors().is_some()); + tcx.dcx().abort_if_errors() } } return; @@ -884,6 +886,18 @@ fn check_field_uniqueness( check(field.ident, field.span.into()); } +fn find_field(tcx: TyCtxt<'_>, (def_id, ident): (DefId, Ident)) -> Option { + tcx.adt_def(def_id).non_enum_variant().fields.iter_enumerated().find_map(|(idx, field)| { + if field.is_unnamed() { + let field_ty = tcx.type_of(field.did).instantiate_identity(); + let adt_def = field_ty.ty_adt_def().expect("expect Adt for unnamed field"); + tcx.find_field((adt_def.did(), ident)).map(|_| idx) + } else { + (field.ident(tcx).normalize_to_macros_2_0() == ident).then_some(idx) + } + }) +} + fn convert_variant( tcx: TyCtxt<'_>, variant_did: Option, @@ -908,14 +922,14 @@ fn convert_variant( let ident = ident.normalize_to_macros_2_0(); match (field_decl, seen_fields.get(&ident).copied()) { (NotNested(span), Some(NotNested(prev_span))) => { - tcx.sess.emit_err(errors::FieldAlreadyDeclared::NotNested { + tcx.dcx().emit_err(errors::FieldAlreadyDeclared::NotNested { field_name, span, prev_span, }); } (NotNested(span), Some(Nested(prev))) => { - tcx.sess.emit_err(errors::FieldAlreadyDeclared::PreviousNested { + tcx.dcx().emit_err(errors::FieldAlreadyDeclared::PreviousNested { field_name, span, prev_span: prev.span, @@ -926,7 +940,7 @@ fn convert_variant( Nested(NestedSpan { span, nested_field_span }), Some(NotNested(prev_span)), ) => { - tcx.sess.emit_err(errors::FieldAlreadyDeclared::CurrentNested { + tcx.dcx().emit_err(errors::FieldAlreadyDeclared::CurrentNested { field_name, span, nested_field_span, @@ -934,7 +948,7 @@ fn convert_variant( }); } (Nested(NestedSpan { span, nested_field_span }), Some(Nested(prev))) => { - tcx.sess.emit_err(errors::FieldAlreadyDeclared::BothNested { + tcx.dcx().emit_err(errors::FieldAlreadyDeclared::BothNested { field_name, span, nested_field_span, diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 31c97aab7fb..8e8dcdaa105 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -1721,7 +1721,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let ident = tcx.adjust_ident(field.ident, variant.def_id); let field_type = if let Some((i, v_field)) = remaining_fields.remove(&ident) { seen_fields.insert(ident, field.span); - self.write_field_index(field.hir_id, i); + // FIXME: handle nested fields + self.write_field_index(field.hir_id, i, Vec::new()); // We don't look at stability attributes on // struct-like enums (yet...), but it's definitely not @@ -2367,24 +2368,39 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let body_hir_id = self.tcx.local_def_id_to_hir_id(self.body_id); let (ident, def_scope) = self.tcx.adjust_ident_and_get_scope(field, base_def.did(), body_hir_id); - let fields = &base_def.non_enum_variant().fields; - if let Some((index, field)) = fields - .iter_enumerated() - .find(|(_, f)| f.ident(self.tcx).normalize_to_macros_2_0() == ident) - { + let mut adt_def = *base_def; + let mut last_ty = None; + let mut nested_fields = Vec::new(); + let mut index = None; + while let Some(idx) = self.tcx.find_field((adt_def.did(), ident)) { + let &mut first_idx = index.get_or_insert(idx); + let field = &adt_def.non_enum_variant().fields[idx]; let field_ty = self.field_ty(expr.span, field, args); - // Save the index of all fields regardless of their visibility in case - // of error recovery. - self.write_field_index(expr.hir_id, index); - let adjustments = self.adjust_steps(&autoderef); - if field.vis.is_accessible_from(def_scope, self.tcx) { - self.apply_adjustments(base, adjustments); - self.register_predicates(autoderef.into_obligations()); - - self.tcx.check_stability(field.did, Some(expr.hir_id), expr.span, None); - return field_ty; + if let Some(ty) = last_ty { + nested_fields.push((ty, idx)); } - private_candidate = Some((adjustments, base_def.did())); + if field.ident(self.tcx).normalize_to_macros_2_0() == ident { + // Save the index of all fields regardless of their visibility in case + // of error recovery. + self.write_field_index(expr.hir_id, first_idx, nested_fields); + let adjustments = self.adjust_steps(&autoderef); + if field.vis.is_accessible_from(def_scope, self.tcx) { + self.apply_adjustments(base, adjustments); + self.register_predicates(autoderef.into_obligations()); + + self.tcx.check_stability( + field.did, + Some(expr.hir_id), + expr.span, + None, + ); + return field_ty; + } + private_candidate = Some((adjustments, base_def.did())); + break; + } + last_ty = Some(field_ty); + adt_def = field_ty.ty_adt_def().expect("expect Adt for unnamed field"); } } ty::Tuple(tys) => { @@ -2395,7 +2411,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.apply_adjustments(base, adjustments); self.register_predicates(autoderef.into_obligations()); - self.write_field_index(expr.hir_id, FieldIdx::from_usize(index)); + self.write_field_index( + expr.hir_id, + FieldIdx::from_usize(index), + Vec::new(), + ); return field_ty; } } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index 7eb421ca8f5..165937de247 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -145,8 +145,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - pub fn write_field_index(&self, hir_id: hir::HirId, index: FieldIdx) { + pub fn write_field_index( + &self, + hir_id: hir::HirId, + index: FieldIdx, + nested_fields: Vec<(Ty<'tcx>, FieldIdx)>, + ) { self.typeck_results.borrow_mut().field_indices_mut().insert(hir_id, index); + if !nested_fields.is_empty() { + self.typeck_results.borrow_mut().nested_fields_mut().insert(hir_id, nested_fields); + } } #[instrument(level = "debug", skip(self))] diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index 67aa9218585..5026fbe4b80 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -1389,7 +1389,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { field_map .get(&ident) .map(|(i, f)| { - self.write_field_index(field.hir_id, *i); + // FIXME: handle nested fields + self.write_field_index(field.hir_id, *i, Vec::new()); self.tcx.check_stability(f.did, Some(pat.hir_id), span, None); self.field_ty(span, f, args) }) diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs index 94f6c06157e..e48939d8f8b 100644 --- a/compiler/rustc_hir_typeck/src/writeback.rs +++ b/compiler/rustc_hir_typeck/src/writeback.rs @@ -596,6 +596,11 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { { self.typeck_results.field_indices_mut().insert(hir_id, index); } + if let Some(nested_fields) = + self.fcx.typeck_results.borrow_mut().nested_fields_mut().remove(hir_id) + { + self.typeck_results.nested_fields_mut().insert(hir_id, nested_fields); + } } #[instrument(skip(self, span), level = "debug")] diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs index a272a51f327..7039749b1b7 100644 --- a/compiler/rustc_middle/src/query/erase.rs +++ b/compiler/rustc_middle/src/query/erase.rs @@ -238,6 +238,7 @@ trivial! { Option, Option, Option, + Option, Option, Option, Result<(), rustc_errors::ErrorGuaranteed>, diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 938fba0ed09..e9f61a54270 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -2217,6 +2217,10 @@ rustc_queries! { desc { "whether the item should be made inlinable across crates" } separate_provide_extern } + + query find_field((def_id, ident): (DefId, rustc_span::symbol::Ident)) -> Option { + desc { |tcx| "find the index of maybe nested field `{ident}` in `{}`", tcx.def_path_str(def_id) } + } } rustc_query_append! { define_callbacks! } diff --git a/compiler/rustc_middle/src/ty/typeck_results.rs b/compiler/rustc_middle/src/ty/typeck_results.rs index ad41a674dd8..be91474b988 100644 --- a/compiler/rustc_middle/src/ty/typeck_results.rs +++ b/compiler/rustc_middle/src/ty/typeck_results.rs @@ -44,6 +44,12 @@ pub struct TypeckResults<'tcx> { /// belongs, but it may not exist if it's a tuple field (`tuple.0`). field_indices: ItemLocalMap, + /// Resolved types and indices for the nested fields' accesses of `obj.field` (expanded + /// to `obj._(1)._(2).field` in THIR). This map only stores the intermediate type + /// of `obj._(1)` and index of `_(1)._(2)`, and the type of `_(1)._(2)`, and the index of + /// `_(2).field`. + nested_fields: ItemLocalMap, FieldIdx)>>, + /// Stores the types for various nodes in the AST. Note that this table /// is not guaranteed to be populated outside inference. See /// typeck::check::fn_ctxt for details. @@ -214,6 +220,7 @@ impl<'tcx> TypeckResults<'tcx> { hir_owner, type_dependent_defs: Default::default(), field_indices: Default::default(), + nested_fields: Default::default(), user_provided_types: Default::default(), user_provided_sigs: Default::default(), node_types: Default::default(), @@ -285,6 +292,18 @@ impl<'tcx> TypeckResults<'tcx> { self.field_indices().get(id).cloned() } + pub fn nested_fields(&self) -> LocalTableInContext<'_, Vec<(Ty<'tcx>, FieldIdx)>> { + LocalTableInContext { hir_owner: self.hir_owner, data: &self.nested_fields } + } + + pub fn nested_fields_mut(&mut self) -> LocalTableInContextMut<'_, Vec<(Ty<'tcx>, FieldIdx)>> { + LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.nested_fields } + } + + pub fn nested_field_tys_and_indices(&self, id: hir::HirId) -> &[(Ty<'tcx>, FieldIdx)] { + self.nested_fields().get(id).map_or(&[], Vec::as_slice) + } + pub fn user_provided_types(&self) -> LocalTableInContext<'_, CanonicalUserType<'tcx>> { LocalTableInContext { hir_owner: self.hir_owner, data: &self.user_provided_types } } diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index 35adcc33480..79719f6f4cc 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -734,11 +734,21 @@ impl<'tcx> Cx<'tcx> { }); ExprKind::Loop { body } } - hir::ExprKind::Field(source, ..) => ExprKind::Field { - lhs: self.mirror_expr(source), - variant_index: FIRST_VARIANT, - name: self.typeck_results.field_index(expr.hir_id), - }, + hir::ExprKind::Field(source, ..) => { + let mut kind = ExprKind::Field { + lhs: self.mirror_expr(source), + variant_index: FIRST_VARIANT, + name: self.typeck_results.field_index(expr.hir_id), + }; + let nested_field_tys_and_indices = + self.typeck_results.nested_field_tys_and_indices(expr.hir_id); + for &(ty, idx) in nested_field_tys_and_indices { + let expr = Expr { temp_lifetime, ty, span: source.span, kind }; + let lhs = self.thir.exprs.push(expr); + kind = ExprKind::Field { lhs, variant_index: FIRST_VARIANT, name: idx }; + } + kind + } hir::ExprKind::Cast(source, cast_ty) => { // Check for a user-given type annotation on this `cast` let user_provided_types = self.typeck_results.user_provided_types(); diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 7eb7c8c2bca..6bb9c22b04d 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -313,18 +313,17 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { } } - fn insert_field_def_ids(&mut self, def_id: LocalDefId, vdata: &ast::VariantData) { - if vdata.fields().iter().any(|field| field.is_placeholder) { + fn insert_field_def_ids(&mut self, def_id: LocalDefId, fields: &[ast::FieldDef]) { + if fields.iter().any(|field| field.is_placeholder) { // The fields are not expanded yet. return; } - let def_ids = vdata.fields().iter().map(|field| self.r.local_def_id(field.id).to_def_id()); + let def_ids = fields.iter().map(|field| self.r.local_def_id(field.id).to_def_id()); self.r.field_def_ids.insert(def_id, self.r.tcx.arena.alloc_from_iter(def_ids)); } - fn insert_field_visibilities_local(&mut self, def_id: DefId, vdata: &ast::VariantData) { - let field_vis = vdata - .fields() + fn insert_field_visibilities_local(&mut self, def_id: DefId, fields: &[ast::FieldDef]) { + let field_vis = fields .iter() .map(|field| field.vis.span.until(field.ident.map_or(field.ty.span, |i| i.span))) .collect(); @@ -629,6 +628,50 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { } } + fn build_reduced_graph_for_fields( + &mut self, + fields: &[ast::FieldDef], + ident: Ident, + def_id: LocalDefId, + adt_res: Res, + adt_vis: ty::Visibility, + adt_span: Span, + ) { + let parent_scope = &self.parent_scope; + let parent = parent_scope.module; + let expansion = parent_scope.expansion; + + // Define a name in the type namespace if it is not anonymous. + self.r.define(parent, ident, TypeNS, (adt_res, adt_vis, adt_span, expansion)); + self.r.feed_visibility(def_id, adt_vis); + + // Record field names for error reporting. + self.insert_field_def_ids(def_id, fields); + self.insert_field_visibilities_local(def_id.to_def_id(), fields); + + for field in fields { + match &field.ty.kind { + ast::TyKind::AnonStruct(id, nested_fields) + | ast::TyKind::AnonUnion(id, nested_fields) => { + let local_def_id = self.r.local_def_id(*id); + let def_id = local_def_id.to_def_id(); + let def_kind = self.r.tcx.def_kind(local_def_id); + let res = Res::Def(def_kind, def_id); + self.build_reduced_graph_for_fields( + &nested_fields, + Ident::empty(), + local_def_id, + res, + // Anonymous adts inherit visibility from their parent adts. + adt_vis, + field.span, + ); + } + _ => {} + } + } + } + /// Constructs the reduced graph for one item. fn build_reduced_graph_for_item(&mut self, item: &'b Item) { let parent_scope = &self.parent_scope; @@ -716,12 +759,14 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { // These items live in both the type and value namespaces. ItemKind::Struct(ref vdata, _) => { - // Define a name in the type namespace. - self.r.define(parent, ident, TypeNS, (res, vis, sp, expansion)); - - // Record field names for error reporting. - self.insert_field_def_ids(local_def_id, vdata); - self.insert_field_visibilities_local(def_id, vdata); + self.build_reduced_graph_for_fields( + vdata.fields(), + ident, + local_def_id, + res, + vis, + sp, + ); // If this is a tuple or unit struct, define a name // in the value namespace as well. @@ -755,7 +800,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { self.r.define(parent, ident, ValueNS, (ctor_res, ctor_vis, sp, expansion)); self.r.feed_visibility(ctor_def_id, ctor_vis); // We need the field visibility spans also for the constructor for E0603. - self.insert_field_visibilities_local(ctor_def_id.to_def_id(), vdata); + self.insert_field_visibilities_local(ctor_def_id.to_def_id(), vdata.fields()); self.r .struct_constructors @@ -764,11 +809,14 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { } ItemKind::Union(ref vdata, _) => { - self.r.define(parent, ident, TypeNS, (res, vis, sp, expansion)); - - // Record field names for error reporting. - self.insert_field_def_ids(local_def_id, vdata); - self.insert_field_visibilities_local(def_id, vdata); + self.build_reduced_graph_for_fields( + vdata.fields(), + ident, + local_def_id, + res, + vis, + sp, + ); } // These items do not add names to modules. @@ -1461,8 +1509,8 @@ impl<'a, 'b, 'tcx> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b, 'tcx> { } // Record field names for error reporting. - self.insert_field_def_ids(def_id, &variant.data); - self.insert_field_visibilities_local(def_id.to_def_id(), &variant.data); + self.insert_field_def_ids(def_id, variant.data.fields()); + self.insert_field_visibilities_local(def_id.to_def_id(), variant.data.fields()); visit::walk_variant(self, variant); } diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index 42ace9bb22f..08b1c88873e 100644 --- a/compiler/rustc_resolve/src/def_collector.rs +++ b/compiler/rustc_resolve/src/def_collector.rs @@ -324,8 +324,21 @@ impl<'a, 'b, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'b, 'tcx> { } fn visit_ty(&mut self, ty: &'a Ty) { - match ty.kind { + match &ty.kind { TyKind::MacCall(..) => self.visit_macro_invoc(ty.id), + TyKind::AnonStruct(node_id, fields) | TyKind::AnonUnion(node_id, fields) => { + let def_kind = match &ty.kind { + TyKind::AnonStruct(..) => DefKind::Struct, + TyKind::AnonUnion(..) => DefKind::Union, + _ => unreachable!(), + }; + let def_id = self.create_def(*node_id, kw::Empty, def_kind, ty.span); + self.with_parent(def_id, |this| { + for f in fields { + this.visit_field_def(f); + } + }); + } _ => visit::walk_ty(self, ty), } } diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 6c0f2b89347..6b07bfdec67 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -1016,6 +1016,8 @@ pub struct Resolver<'a, 'tcx> { binding_parent_modules: FxHashMap, Module<'a>>, underscore_disambiguator: u32, + /// Disambiguator for anonymous adts. + empty_disambiguator: u32, /// Maps glob imports to the names of items actually imported. glob_map: FxHashMap>, @@ -1367,6 +1369,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { module_children: Default::default(), trait_map: NodeMap::default(), underscore_disambiguator: 0, + empty_disambiguator: 0, empty_module, module_map, block_map: Default::default(), @@ -1734,6 +1737,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { let disambiguator = if ident.name == kw::Underscore { self.underscore_disambiguator += 1; self.underscore_disambiguator + } else if ident.name == kw::Empty { + self.empty_disambiguator += 1; + self.empty_disambiguator } else { 0 }; diff --git a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs index b320ded40a7..e2d5eaded3f 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs @@ -183,7 +183,7 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_copy_clone_trait<'tcx>( // Check for anonymous adts. ty::Adt(adt, generics) if adt.is_anonymous() => { - Ok(adt.all_fields().map(|f| f.ty(ecx.tcx(), generics)).collect()) + Ok(adt.non_enum_variant().fields.iter().map(|f| f.ty(ecx.tcx(), generics)).collect()) } ty::Dynamic(..) diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index c2f7d5160f6..43ab476056a 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -2212,14 +2212,14 @@ impl<'tcx> SelectionContext<'_, 'tcx> { // FIXME(async_closures): These are never clone, for now. ty::CoroutineClosure(_, _) => None, - // `Copy` and `Clone` are automatically impelemented for an anonymous adt + // `Copy` and `Clone` are automatically implemented for an anonymous adt // if all of its fields are `Copy` and `Clone` ty::Adt(adt, args) if adt.is_anonymous() => { // (*) binder moved here Where( obligation .predicate - .rebind(adt.all_fields().map(|f| f.ty(self.tcx(), args)).collect()), + .rebind(adt.non_enum_variant().fields.iter().map(|f| f.ty(self.tcx(), args)).collect()), ) } diff --git a/tests/mir-opt/unnamed-fields/field_access.bar.SimplifyCfg-initial.after.mir b/tests/mir-opt/unnamed-fields/field_access.bar.SimplifyCfg-initial.after.mir new file mode 100644 index 00000000000..2a57b272f9b --- /dev/null +++ b/tests/mir-opt/unnamed-fields/field_access.bar.SimplifyCfg-initial.after.mir @@ -0,0 +1,61 @@ +// MIR for `bar` after SimplifyCfg-initial + +fn bar(_1: Bar) -> () { + debug bar => _1; + let mut _0: (); + let _2: (); + let mut _3: u8; + let _4: (); + let mut _5: i8; + let _6: (); + let mut _7: bool; + let _8: (); + let mut _9: [u8; 1]; + scope 1 { + } + + bb0: { + StorageLive(_2); + StorageLive(_3); + _3 = (_1.0: u8); + _2 = access::(move _3) -> [return: bb1, unwind: bb5]; + } + + bb1: { + StorageDead(_3); + StorageDead(_2); + StorageLive(_4); + StorageLive(_5); + _5 = ((_1.1: Bar::_::{anon_adt#0}).0: i8); + _4 = access::(move _5) -> [return: bb2, unwind: bb5]; + } + + bb2: { + StorageDead(_5); + StorageDead(_4); + StorageLive(_6); + StorageLive(_7); + _7 = ((_1.1: Bar::_::{anon_adt#0}).1: bool); + _6 = access::(move _7) -> [return: bb3, unwind: bb5]; + } + + bb3: { + StorageDead(_7); + StorageDead(_6); + StorageLive(_8); + StorageLive(_9); + _9 = (((_1.2: Bar::_::{anon_adt#0}).0: Bar::_::{anon_adt#0}::_::{anon_adt#0}).0: [u8; 1]); + _8 = access::<[u8; 1]>(move _9) -> [return: bb4, unwind: bb5]; + } + + bb4: { + StorageDead(_9); + StorageDead(_8); + _0 = const (); + return; + } + + bb5 (cleanup): { + resume; + } +} diff --git a/tests/mir-opt/unnamed-fields/field_access.foo.SimplifyCfg-initial.after.mir b/tests/mir-opt/unnamed-fields/field_access.foo.SimplifyCfg-initial.after.mir new file mode 100644 index 00000000000..8b10a6f13ce --- /dev/null +++ b/tests/mir-opt/unnamed-fields/field_access.foo.SimplifyCfg-initial.after.mir @@ -0,0 +1,59 @@ +// MIR for `foo` after SimplifyCfg-initial + +fn foo(_1: Foo) -> () { + debug foo => _1; + let mut _0: (); + let _2: (); + let mut _3: u8; + let _4: (); + let mut _5: i8; + let _6: (); + let mut _7: bool; + let _8: (); + let mut _9: [u8; 1]; + + bb0: { + StorageLive(_2); + StorageLive(_3); + _3 = (_1.0: u8); + _2 = access::(move _3) -> [return: bb1, unwind: bb5]; + } + + bb1: { + StorageDead(_3); + StorageDead(_2); + StorageLive(_4); + StorageLive(_5); + _5 = ((_1.1: Foo::_::{anon_adt#0}).0: i8); + _4 = access::(move _5) -> [return: bb2, unwind: bb5]; + } + + bb2: { + StorageDead(_5); + StorageDead(_4); + StorageLive(_6); + StorageLive(_7); + _7 = ((_1.1: Foo::_::{anon_adt#0}).1: bool); + _6 = access::(move _7) -> [return: bb3, unwind: bb5]; + } + + bb3: { + StorageDead(_7); + StorageDead(_6); + StorageLive(_8); + StorageLive(_9); + _9 = (((_1.2: Foo::_::{anon_adt#0}).0: Foo::_::{anon_adt#0}::_::{anon_adt#0}).0: [u8; 1]); + _8 = access::<[u8; 1]>(move _9) -> [return: bb4, unwind: bb5]; + } + + bb4: { + StorageDead(_9); + StorageDead(_8); + _0 = const (); + return; + } + + bb5 (cleanup): { + resume; + } +} diff --git a/tests/mir-opt/unnamed-fields/field_access.rs b/tests/mir-opt/unnamed-fields/field_access.rs new file mode 100644 index 00000000000..3d33ca26875 --- /dev/null +++ b/tests/mir-opt/unnamed-fields/field_access.rs @@ -0,0 +1,56 @@ +// skip-filecheck +// EMIT_MIR field_access.foo.SimplifyCfg-initial.after.mir +// EMIT_MIR field_access.bar.SimplifyCfg-initial.after.mir + +#![allow(incomplete_features)] +#![feature(unnamed_fields)] + +#[repr(C)] +struct Foo { + a: u8, + _: struct { + b: i8, + c: bool, + }, + _: struct { + _: struct { + d: [u8; 1], + } + } +} + +#[repr(C)] +union Bar { + a: u8, + _: union { + b: i8, + c: bool, + }, + _: union { + _: union { + d: [u8; 1], + } + } +} + + +fn access(_: T) {} + +fn foo(foo: Foo) { + access(foo.a); + access(foo.b); + access(foo.c); + access(foo.d); +} + +fn bar(bar: Bar) { + unsafe { + access(bar.a); + access(bar.b); + access(bar.c); + access(bar.d); + } +} + + +fn main() {} From 7d012e8f19591f224b25cabf64d9da2bb2e08166 Mon Sep 17 00:00:00 2001 From: Frank King Date: Sat, 6 Jan 2024 15:52:22 +0800 Subject: [PATCH 27/56] Add rustfmt test from #117942 --- src/tools/rustfmt/tests/target/anonymous-types.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/tools/rustfmt/tests/target/anonymous-types.rs b/src/tools/rustfmt/tests/target/anonymous-types.rs index 8e08c314ed1..e8c2d83878c 100644 --- a/src/tools/rustfmt/tests/target/anonymous-types.rs +++ b/src/tools/rustfmt/tests/target/anonymous-types.rs @@ -16,4 +16,16 @@ struct Foo { e: f32, } +// Test for https://github.com/rust-lang/rust/issues/117942 +struct Foo { + _: union { + #[rustfmt::skip] + f: String, + }, + #[rustfmt::skip] + _: struct { + g: i32, + }, +} + fn main() {} From 7660d6bf2c4e02b4f809b99f35c0f290e6171d45 Mon Sep 17 00:00:00 2001 From: Frank King Date: Sat, 6 Jan 2024 18:22:37 +0800 Subject: [PATCH 28/56] Check representation of unnamed fields --- compiler/rustc_hir_analysis/messages.ftl | 11 ++ .../rustc_hir_analysis/src/check/check.rs | 49 ++++++++ compiler/rustc_hir_analysis/src/collect.rs | 6 +- compiler/rustc_hir_analysis/src/errors.rs | 30 +++++ compiler/rustc_resolve/src/def_collector.rs | 31 ++--- .../src/traits/select/mod.rs | 8 +- ...d_access.bar.SimplifyCfg-initial.after.mir | 6 +- ...d_access.foo.SimplifyCfg-initial.after.mir | 6 +- .../feature-gate-unnamed_fields.rs | 5 + .../feature-gate-unnamed_fields.stderr | 10 +- tests/ui/union/unnamed-fields/repr_check.rs | 69 +++++++++++ .../ui/union/unnamed-fields/repr_check.stderr | 108 ++++++++++++++++++ 12 files changed, 309 insertions(+), 30 deletions(-) create mode 100644 tests/ui/union/unnamed-fields/repr_check.rs create mode 100644 tests/ui/union/unnamed-fields/repr_check.stderr diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl index 662d859e993..cf1a42c9285 100644 --- a/compiler/rustc_hir_analysis/messages.ftl +++ b/compiler/rustc_hir_analysis/messages.ftl @@ -439,6 +439,17 @@ hir_analysis_typeof_reserved_keyword_used = hir_analysis_unconstrained_opaque_type = unconstrained opaque type .note = `{$name}` must be used in combination with a concrete type within the same {$what} +hir_analysis_unnamed_fields_repr_field_defined = unnamed field defined here + +hir_analysis_unnamed_fields_repr_field_missing_repr_c = + named type of unnamed field must have `#[repr(C)]` representation + .label = unnamed field defined here + .field_ty_label = `{$field_ty}` defined here + +hir_analysis_unnamed_fields_repr_missing_repr_c = + {$adt_kind} with unnamed fields must have `#[repr(C)]` representation + .label = {$adt_kind} `{$adt_name}` defined here + hir_analysis_unrecognized_atomic_operation = unrecognized atomic operation function: `{$op}` .label = unrecognized atomic operation diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 7250dc81faf..3cbd67a482c 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -80,6 +80,7 @@ fn check_struct(tcx: TyCtxt<'_>, def_id: LocalDefId) { check_transparent(tcx, def); check_packed(tcx, span, def); + check_unnamed_fields(tcx, def); } fn check_union(tcx: TyCtxt<'_>, def_id: LocalDefId) { @@ -89,6 +90,54 @@ fn check_union(tcx: TyCtxt<'_>, def_id: LocalDefId) { check_transparent(tcx, def); check_union_fields(tcx, span, def_id); check_packed(tcx, span, def); + check_unnamed_fields(tcx, def); +} + +/// Check the representation of adts with unnamed fields. +fn check_unnamed_fields(tcx: TyCtxt<'_>, def: ty::AdtDef<'_>) { + if def.is_enum() { + return; + } + let variant = def.non_enum_variant(); + if !variant.has_unnamed_fields() { + return; + } + if !def.is_anonymous() { + let adt_kind = def.descr(); + let span = tcx.def_span(def.did()); + let unnamed_fields = variant + .fields + .iter() + .filter(|f| f.is_unnamed()) + .map(|f| { + let span = tcx.def_span(f.did); + errors::UnnamedFieldsReprFieldDefined { span } + }) + .collect::>(); + debug_assert_ne!(unnamed_fields.len(), 0, "expect unnamed fields in this adt"); + let adt_name = tcx.item_name(def.did()); + if !def.repr().c() { + tcx.dcx().emit_err(errors::UnnamedFieldsRepr::MissingReprC { + span, + adt_kind, + adt_name, + unnamed_fields, + }); + } + } + for field in variant.fields.iter().filter(|f| f.is_unnamed()) { + let field_ty = tcx.type_of(field.did).instantiate_identity(); + if let Some(adt) = field_ty.ty_adt_def() + && !adt.is_anonymous() + && !adt.repr().c() + { + tcx.dcx().emit_err(errors::UnnamedFieldsRepr::FieldMissingReprC { + span: tcx.def_span(field.did), + field_ty_span: tcx.def_span(adt.did()), + field_ty, + }); + } + } } /// Check that the fields of the `union` do not need dropping. diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 15ddbd84b2c..45938eacd65 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -997,7 +997,11 @@ fn adt_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::AdtDef<'_> { }; let is_anonymous = item.ident.name == kw::Empty; - let repr = tcx.repr_options_of_def(def_id.to_def_id()); + let repr = if is_anonymous { + tcx.adt_def(tcx.local_parent(def_id)).repr() + } else { + tcx.repr_options_of_def(def_id.to_def_id()) + }; let (kind, variants) = match &item.kind { ItemKind::Enum(def, _) => { let mut distance_from_explicit = 0; diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index 1e172f1d9f0..f7fa3263eaa 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -1571,3 +1571,33 @@ pub(crate) enum UnusedGenericParameterHelp { #[help(hir_analysis_unused_generic_parameter_ty_alias_help)] TyAlias { param_name: Ident }, } + +#[derive(Diagnostic)] +pub enum UnnamedFieldsRepr<'a> { + #[diag(hir_analysis_unnamed_fields_repr_missing_repr_c)] + MissingReprC { + #[primary_span] + #[label] + span: Span, + adt_kind: &'static str, + adt_name: Symbol, + #[subdiagnostic] + unnamed_fields: Vec, + }, + #[diag(hir_analysis_unnamed_fields_repr_field_missing_repr_c)] + FieldMissingReprC { + #[primary_span] + #[label] + span: Span, + #[label(hir_analysis_field_ty_label)] + field_ty_span: Span, + field_ty: Ty<'a>, + }, +} + +#[derive(Subdiagnostic)] +#[note(hir_analysis_unnamed_fields_repr_field_defined)] +pub struct UnnamedFieldsReprFieldDefined { + #[primary_span] + pub span: Span, +} diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index 08b1c88873e..45aea585f97 100644 --- a/compiler/rustc_resolve/src/def_collector.rs +++ b/compiler/rustc_resolve/src/def_collector.rs @@ -80,6 +80,22 @@ impl<'a, 'b, 'tcx> DefCollector<'a, 'b, 'tcx> { let name = field.ident.map_or_else(|| sym::integer(index(self)), |ident| ident.name); let def = self.create_def(field.id, name, DefKind::Field, field.span); self.with_parent(def, |this| visit::walk_field_def(this, field)); + self.visit_anon_adt(&field.ty); + } + } + + fn visit_anon_adt(&mut self, ty: &'a Ty) { + let def_kind = match &ty.kind { + TyKind::AnonStruct(..) => DefKind::Struct, + TyKind::AnonUnion(..) => DefKind::Union, + _ => return, + }; + match &ty.kind { + TyKind::AnonStruct(node_id, _) | TyKind::AnonUnion(node_id, _) => { + let def_id = self.create_def(*node_id, kw::Empty, def_kind, ty.span); + self.with_parent(def_id, |this| visit::walk_ty(this, ty)); + } + _ => {} } } @@ -326,19 +342,8 @@ impl<'a, 'b, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'b, 'tcx> { fn visit_ty(&mut self, ty: &'a Ty) { match &ty.kind { TyKind::MacCall(..) => self.visit_macro_invoc(ty.id), - TyKind::AnonStruct(node_id, fields) | TyKind::AnonUnion(node_id, fields) => { - let def_kind = match &ty.kind { - TyKind::AnonStruct(..) => DefKind::Struct, - TyKind::AnonUnion(..) => DefKind::Union, - _ => unreachable!(), - }; - let def_id = self.create_def(*node_id, kw::Empty, def_kind, ty.span); - self.with_parent(def_id, |this| { - for f in fields { - this.visit_field_def(f); - } - }); - } + // Anonymous structs or unions are visited later after defined. + TyKind::AnonStruct(..) | TyKind::AnonUnion(..) => {} _ => visit::walk_ty(self, ty), } } diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 43ab476056a..60453f5ab9c 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -2216,11 +2216,9 @@ impl<'tcx> SelectionContext<'_, 'tcx> { // if all of its fields are `Copy` and `Clone` ty::Adt(adt, args) if adt.is_anonymous() => { // (*) binder moved here - Where( - obligation - .predicate - .rebind(adt.non_enum_variant().fields.iter().map(|f| f.ty(self.tcx(), args)).collect()), - ) + Where(obligation.predicate.rebind( + adt.non_enum_variant().fields.iter().map(|f| f.ty(self.tcx(), args)).collect(), + )) } ty::Adt(..) | ty::Alias(..) | ty::Param(..) | ty::Placeholder(..) => { diff --git a/tests/mir-opt/unnamed-fields/field_access.bar.SimplifyCfg-initial.after.mir b/tests/mir-opt/unnamed-fields/field_access.bar.SimplifyCfg-initial.after.mir index 2a57b272f9b..8edc7b5df88 100644 --- a/tests/mir-opt/unnamed-fields/field_access.bar.SimplifyCfg-initial.after.mir +++ b/tests/mir-opt/unnamed-fields/field_access.bar.SimplifyCfg-initial.after.mir @@ -26,7 +26,7 @@ fn bar(_1: Bar) -> () { StorageDead(_2); StorageLive(_4); StorageLive(_5); - _5 = ((_1.1: Bar::_::{anon_adt#0}).0: i8); + _5 = ((_1.1: Bar::{anon_adt#0}).0: i8); _4 = access::(move _5) -> [return: bb2, unwind: bb5]; } @@ -35,7 +35,7 @@ fn bar(_1: Bar) -> () { StorageDead(_4); StorageLive(_6); StorageLive(_7); - _7 = ((_1.1: Bar::_::{anon_adt#0}).1: bool); + _7 = ((_1.1: Bar::{anon_adt#0}).1: bool); _6 = access::(move _7) -> [return: bb3, unwind: bb5]; } @@ -44,7 +44,7 @@ fn bar(_1: Bar) -> () { StorageDead(_6); StorageLive(_8); StorageLive(_9); - _9 = (((_1.2: Bar::_::{anon_adt#0}).0: Bar::_::{anon_adt#0}::_::{anon_adt#0}).0: [u8; 1]); + _9 = (((_1.2: Bar::{anon_adt#1}).0: Bar::{anon_adt#1}::{anon_adt#0}).0: [u8; 1]); _8 = access::<[u8; 1]>(move _9) -> [return: bb4, unwind: bb5]; } diff --git a/tests/mir-opt/unnamed-fields/field_access.foo.SimplifyCfg-initial.after.mir b/tests/mir-opt/unnamed-fields/field_access.foo.SimplifyCfg-initial.after.mir index 8b10a6f13ce..d48a969f06e 100644 --- a/tests/mir-opt/unnamed-fields/field_access.foo.SimplifyCfg-initial.after.mir +++ b/tests/mir-opt/unnamed-fields/field_access.foo.SimplifyCfg-initial.after.mir @@ -24,7 +24,7 @@ fn foo(_1: Foo) -> () { StorageDead(_2); StorageLive(_4); StorageLive(_5); - _5 = ((_1.1: Foo::_::{anon_adt#0}).0: i8); + _5 = ((_1.1: Foo::{anon_adt#0}).0: i8); _4 = access::(move _5) -> [return: bb2, unwind: bb5]; } @@ -33,7 +33,7 @@ fn foo(_1: Foo) -> () { StorageDead(_4); StorageLive(_6); StorageLive(_7); - _7 = ((_1.1: Foo::_::{anon_adt#0}).1: bool); + _7 = ((_1.1: Foo::{anon_adt#0}).1: bool); _6 = access::(move _7) -> [return: bb3, unwind: bb5]; } @@ -42,7 +42,7 @@ fn foo(_1: Foo) -> () { StorageDead(_6); StorageLive(_8); StorageLive(_9); - _9 = (((_1.2: Foo::_::{anon_adt#0}).0: Foo::_::{anon_adt#0}::_::{anon_adt#0}).0: [u8; 1]); + _9 = (((_1.2: Foo::{anon_adt#1}).0: Foo::{anon_adt#1}::{anon_adt#0}).0: [u8; 1]); _8 = access::<[u8; 1]>(move _9) -> [return: bb4, unwind: bb5]; } diff --git a/tests/ui/feature-gates/feature-gate-unnamed_fields.rs b/tests/ui/feature-gates/feature-gate-unnamed_fields.rs index 6ee8de89564..302a9bbeb45 100644 --- a/tests/ui/feature-gates/feature-gate-unnamed_fields.rs +++ b/tests/ui/feature-gates/feature-gate-unnamed_fields.rs @@ -1,3 +1,4 @@ +#[repr(C)] struct Foo { foo: u8, _: union { //~ ERROR unnamed fields are not yet fully implemented [E0658] @@ -7,6 +8,7 @@ struct Foo { } } +#[repr(C)] union Bar { foobar: u8, _: struct { //~ ERROR unnamed fields are not yet fully implemented [E0658] @@ -16,7 +18,10 @@ union Bar { } } +#[repr(C)] struct S; + +#[repr(C)] struct Baz { _: S //~ ERROR unnamed fields are not yet fully implemented [E0658] } diff --git a/tests/ui/feature-gates/feature-gate-unnamed_fields.stderr b/tests/ui/feature-gates/feature-gate-unnamed_fields.stderr index 8fa342c08ae..bc9e95bab98 100644 --- a/tests/ui/feature-gates/feature-gate-unnamed_fields.stderr +++ b/tests/ui/feature-gates/feature-gate-unnamed_fields.stderr @@ -1,5 +1,5 @@ error[E0658]: unnamed fields are not yet fully implemented - --> $DIR/feature-gate-unnamed_fields.rs:3:5 + --> $DIR/feature-gate-unnamed_fields.rs:4:5 | LL | _: union { | ^ @@ -9,7 +9,7 @@ LL | _: union { = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: unnamed fields are not yet fully implemented - --> $DIR/feature-gate-unnamed_fields.rs:3:8 + --> $DIR/feature-gate-unnamed_fields.rs:4:8 | LL | _: union { | ________^ @@ -24,7 +24,7 @@ LL | | } = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: unnamed fields are not yet fully implemented - --> $DIR/feature-gate-unnamed_fields.rs:12:5 + --> $DIR/feature-gate-unnamed_fields.rs:14:5 | LL | _: struct { | ^ @@ -34,7 +34,7 @@ LL | _: struct { = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: unnamed fields are not yet fully implemented - --> $DIR/feature-gate-unnamed_fields.rs:12:8 + --> $DIR/feature-gate-unnamed_fields.rs:14:8 | LL | _: struct { | ________^ @@ -49,7 +49,7 @@ LL | | } = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: unnamed fields are not yet fully implemented - --> $DIR/feature-gate-unnamed_fields.rs:21:5 + --> $DIR/feature-gate-unnamed_fields.rs:26:5 | LL | _: S | ^ diff --git a/tests/ui/union/unnamed-fields/repr_check.rs b/tests/ui/union/unnamed-fields/repr_check.rs new file mode 100644 index 00000000000..b50b54b20af --- /dev/null +++ b/tests/ui/union/unnamed-fields/repr_check.rs @@ -0,0 +1,69 @@ +#![allow(incomplete_features)] +#![feature(unnamed_fields)] + +struct A { //~ ERROR struct with unnamed fields must have `#[repr(C)]` representation + //~^ NOTE struct `A` defined here + _: struct { //~ NOTE unnamed field defined here + a: i32, + }, + _: struct { //~ NOTE unnamed field defined here + _: struct { + b: i32, + }, + }, +} + +union B { //~ ERROR union with unnamed fields must have `#[repr(C)]` representation + //~^ NOTE union `B` defined here + _: union { //~ NOTE unnamed field defined here + a: i32, + }, + _: union { //~ NOTE unnamed field defined here + _: union { + b: i32, + }, + }, +} + +#[derive(Clone, Copy)] +#[repr(C)] +struct Foo {} + +#[derive(Clone, Copy)] +struct Bar {} +//~^ `Bar` defined here +//~| `Bar` defined here +//~| `Bar` defined here +//~| `Bar` defined here + +struct C { //~ ERROR struct with unnamed fields must have `#[repr(C)]` representation + //~^ NOTE struct `C` defined here + _: Foo, //~ NOTE unnamed field defined here +} + +union D { //~ ERROR union with unnamed fields must have `#[repr(C)]` representation + //~^ NOTE union `D` defined here + _: Foo, //~ NOTE unnamed field defined here +} + +#[repr(C)] +struct E { + _: Bar, //~ ERROR named type of unnamed field must have `#[repr(C)]` representation + //~^ NOTE unnamed field defined here + _: struct { + _: Bar, //~ ERROR named type of unnamed field must have `#[repr(C)]` representation + //~^ NOTE unnamed field defined here + }, +} + +#[repr(C)] +union F { + _: Bar, //~ ERROR named type of unnamed field must have `#[repr(C)]` representation + //~^ NOTE unnamed field defined here + _: union { + _: Bar, //~ ERROR named type of unnamed field must have `#[repr(C)]` representation + //~^ NOTE unnamed field defined here + }, +} + +fn main() {} diff --git a/tests/ui/union/unnamed-fields/repr_check.stderr b/tests/ui/union/unnamed-fields/repr_check.stderr new file mode 100644 index 00000000000..ca6a1f3a780 --- /dev/null +++ b/tests/ui/union/unnamed-fields/repr_check.stderr @@ -0,0 +1,108 @@ +error: struct with unnamed fields must have `#[repr(C)]` representation + --> $DIR/repr_check.rs:4:1 + | +LL | struct A { + | ^^^^^^^^ struct `A` defined here + | +note: unnamed field defined here + --> $DIR/repr_check.rs:6:5 + | +LL | / _: struct { +LL | | a: i32, +LL | | }, + | |_____^ +note: unnamed field defined here + --> $DIR/repr_check.rs:9:5 + | +LL | / _: struct { +LL | | _: struct { +LL | | b: i32, +LL | | }, +LL | | }, + | |_____^ + +error: union with unnamed fields must have `#[repr(C)]` representation + --> $DIR/repr_check.rs:16:1 + | +LL | union B { + | ^^^^^^^ union `B` defined here + | +note: unnamed field defined here + --> $DIR/repr_check.rs:18:5 + | +LL | / _: union { +LL | | a: i32, +LL | | }, + | |_____^ +note: unnamed field defined here + --> $DIR/repr_check.rs:21:5 + | +LL | / _: union { +LL | | _: union { +LL | | b: i32, +LL | | }, +LL | | }, + | |_____^ + +error: struct with unnamed fields must have `#[repr(C)]` representation + --> $DIR/repr_check.rs:39:1 + | +LL | struct C { + | ^^^^^^^^ struct `C` defined here + | +note: unnamed field defined here + --> $DIR/repr_check.rs:41:5 + | +LL | _: Foo, + | ^^^^^^ + +error: union with unnamed fields must have `#[repr(C)]` representation + --> $DIR/repr_check.rs:44:1 + | +LL | union D { + | ^^^^^^^ union `D` defined here + | +note: unnamed field defined here + --> $DIR/repr_check.rs:46:5 + | +LL | _: Foo, + | ^^^^^^ + +error: named type of unnamed field must have `#[repr(C)]` representation + --> $DIR/repr_check.rs:51:5 + | +LL | struct Bar {} + | ---------- `Bar` defined here +... +LL | _: Bar, + | ^^^^^^ unnamed field defined here + +error: named type of unnamed field must have `#[repr(C)]` representation + --> $DIR/repr_check.rs:54:9 + | +LL | struct Bar {} + | ---------- `Bar` defined here +... +LL | _: Bar, + | ^^^^^^ unnamed field defined here + +error: named type of unnamed field must have `#[repr(C)]` representation + --> $DIR/repr_check.rs:61:5 + | +LL | struct Bar {} + | ---------- `Bar` defined here +... +LL | _: Bar, + | ^^^^^^ unnamed field defined here + +error: named type of unnamed field must have `#[repr(C)]` representation + --> $DIR/repr_check.rs:64:9 + | +LL | struct Bar {} + | ---------- `Bar` defined here +... +LL | _: Bar, + | ^^^^^^ unnamed field defined here + +error: aborting due to 8 previous errors + From 822d6dc5fd01356a8d07cfeb06b2a0a244bfe2da Mon Sep 17 00:00:00 2001 From: Frank King Date: Thu, 18 Jan 2024 14:35:14 +0800 Subject: [PATCH 29/56] Fix compile error in rustdoc. --- src/librustdoc/clean/mod.rs | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index b697f945f20..0b705df2a60 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1892,15 +1892,8 @@ pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> T TyKind::BareFn(barefn) => BareFunction(Box::new(clean_bare_fn_ty(barefn, cx))), // Rustdoc handles `TyKind::Err`s by turning them into `Type::Infer`s. TyKind::Infer | TyKind::Err(_) | TyKind::Typeof(..) | TyKind::InferDelegation(..) => Infer, - TyKind::AnonAdt(item_id) => { - let path = external_path( - cx, - item_id.owner_id.def_id.to_def_id(), - false, - ThinVec::new(), - ty::Binder::dummy(ty::GenericArgs::empty()), - ); - Type::Path { path } + TyKind::AnonAdt(..) => { + unimplemented!("Anonymous structs or unions are not supported yet") } } } From 2b04ca94bb06c6913b8b14ba267b3d64b23e3c4d Mon Sep 17 00:00:00 2001 From: Frank King Date: Sat, 20 Jan 2024 12:55:21 +0800 Subject: [PATCH 30/56] Add `#[derive(Clone, Copy)]` to anonymous adts Fix the `AssertBoundIsClone` error for anonymous adts. --- compiler/rustc_ast/src/ast.rs | 4 + .../src/deriving/clone.rs | 4 +- .../rustc_builtin_macros/src/deriving/mod.rs | 2 + .../unnamed-fields/field_uniqueness_check.rs | 9 + .../field_uniqueness_check.stderr | 350 +++++++++--------- 5 files changed, 193 insertions(+), 176 deletions(-) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index e41228bd501..098e2606a3b 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -2161,6 +2161,10 @@ impl TyKind { None } } + + pub fn is_anon_adt(&self) -> bool { + matches!(self, TyKind::AnonStruct(..) | TyKind::AnonUnion(..)) + } } /// Syntax used to declare a trait object. diff --git a/compiler/rustc_builtin_macros/src/deriving/clone.rs b/compiler/rustc_builtin_macros/src/deriving/clone.rs index 7bf19f61166..267405ac32e 100644 --- a/compiler/rustc_builtin_macros/src/deriving/clone.rs +++ b/compiler/rustc_builtin_macros/src/deriving/clone.rs @@ -110,7 +110,9 @@ fn cs_clone_simple( && !seen_type_names.insert(name) { // Already produced an assertion for this type. - } else { + // Anonymous structs or unions must be eliminated as they cannot be + // type parameters. + } else if !field.ty.kind.is_anon_adt() { // let _: AssertParamIsClone; super::assert_ty_bounds( cx, diff --git a/compiler/rustc_builtin_macros/src/deriving/mod.rs b/compiler/rustc_builtin_macros/src/deriving/mod.rs index a6f3252e7be..8a3375cba9d 100644 --- a/compiler/rustc_builtin_macros/src/deriving/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/mod.rs @@ -123,6 +123,8 @@ fn assert_ty_bounds( span: Span, assert_path: &[Symbol], ) { + // Deny anonymous structs or unions to avoid wierd errors. + assert!(!ty.kind.is_anon_adt(), "Anonymous structs or unions cannot be type parameters"); // Generate statement `let _: assert_path;`. let span = cx.with_def_site_ctxt(span); let assert_path = cx.path_all(span, true, cx.std_path(assert_path), vec![GenericArg::Type(ty)]); diff --git a/tests/ui/union/unnamed-fields/field_uniqueness_check.rs b/tests/ui/union/unnamed-fields/field_uniqueness_check.rs index 3cc36211875..ddb951aa06c 100644 --- a/tests/ui/union/unnamed-fields/field_uniqueness_check.rs +++ b/tests/ui/union/unnamed-fields/field_uniqueness_check.rs @@ -1,11 +1,13 @@ #![allow(incomplete_features)] #![feature(unnamed_fields)] +#[derive(Clone, Copy)] #[repr(C)] struct Foo { a: u8, } +#[derive(Clone, Copy)] #[repr(C)] struct Bar { _: union { @@ -15,6 +17,7 @@ struct Bar { // duplicated with a normal field +#[derive(Clone, Copy)] #[repr(C)] union A { // referent field @@ -44,6 +47,7 @@ union A { } // duplicated with a nested field +#[derive(Clone, Copy)] #[repr(C)] struct B { _: union { @@ -95,6 +99,7 @@ struct B { } // duplicated with a more nested field +#[derive(Clone, Copy)] #[repr(C)] union C { _: struct { @@ -168,6 +173,7 @@ union C { } // duplicated with a nested field in a named adt +#[derive(Clone, Copy)] #[repr(C)] struct D { // referent field `a` @@ -196,6 +202,7 @@ struct D { } // duplicated with a nested field in a nested field of a named adt +#[derive(Clone, Copy)] #[repr(C)] union D2 { // referent field `a` @@ -224,6 +231,7 @@ union D2 { } // duplicated with a nested field in a named adt in an anonymous adt +#[derive(Clone, Copy)] #[repr(C)] struct E { _: struct { @@ -276,6 +284,7 @@ struct E { // duplicated with a nested field in a named adt in an anonymous adt #[repr(C)] +#[derive(Clone, Copy)] union E2 { _: struct { // referent field `a` diff --git a/tests/ui/union/unnamed-fields/field_uniqueness_check.stderr b/tests/ui/union/unnamed-fields/field_uniqueness_check.stderr index 4dea0aa4233..5773d3bb039 100644 --- a/tests/ui/union/unnamed-fields/field_uniqueness_check.stderr +++ b/tests/ui/union/unnamed-fields/field_uniqueness_check.stderr @@ -1,5 +1,5 @@ error[E0124]: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:24:5 + --> $DIR/field_uniqueness_check.rs:27:5 | LL | a: u8, | ----- `a` first declared here @@ -8,7 +8,7 @@ LL | a: u8, | ^^^^^ field already declared error[E0124]: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:27:9 + --> $DIR/field_uniqueness_check.rs:30:9 | LL | a: u8, | ----- `a` first declared here @@ -17,7 +17,7 @@ LL | a: u8, | ^^^^^ field already declared error[E0124]: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:28:9 + --> $DIR/field_uniqueness_check.rs:31:9 | LL | a: u8, | ----- `a` first declared here @@ -26,7 +26,7 @@ LL | a: u8, | ^^^^^ field already declared error[E0124]: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:33:13 + --> $DIR/field_uniqueness_check.rs:36:13 | LL | a: u8, | ----- `a` first declared here @@ -35,7 +35,7 @@ LL | a: u8, | ^^^^^ field already declared error: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:37:5 + --> $DIR/field_uniqueness_check.rs:40:5 | LL | a: u8, | ----- `a` first declared here @@ -44,13 +44,13 @@ LL | _: Foo, | ^^^^^^ field `a` declared in this unnamed field | note: field `a` declared here - --> $DIR/field_uniqueness_check.rs:6:5 + --> $DIR/field_uniqueness_check.rs:7:5 | LL | a: u8, | ^^^^^ error: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:38:5 + --> $DIR/field_uniqueness_check.rs:41:5 | LL | a: u8, | ----- `a` first declared here @@ -59,13 +59,13 @@ LL | _: Bar, | ^^^^^^ field `a` declared in this unnamed field | note: field `a` declared here - --> $DIR/field_uniqueness_check.rs:12:9 + --> $DIR/field_uniqueness_check.rs:14:9 | LL | a: u8, | ^^^^^ error: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:41:9 + --> $DIR/field_uniqueness_check.rs:44:9 | LL | a: u8, | ----- `a` first declared here @@ -74,13 +74,13 @@ LL | _: Foo, | ^^^^^^ field `a` declared in this unnamed field | note: field `a` declared here - --> $DIR/field_uniqueness_check.rs:6:5 + --> $DIR/field_uniqueness_check.rs:7:5 | LL | a: u8, | ^^^^^ error: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:42:9 + --> $DIR/field_uniqueness_check.rs:45:9 | LL | a: u8, | ----- `a` first declared here @@ -89,13 +89,13 @@ LL | _: Bar, | ^^^^^^ field `a` declared in this unnamed field | note: field `a` declared here - --> $DIR/field_uniqueness_check.rs:12:9 + --> $DIR/field_uniqueness_check.rs:14:9 | LL | a: u8, | ^^^^^ error[E0124]: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:54:9 + --> $DIR/field_uniqueness_check.rs:58:9 | LL | a: u8, | ----- `a` first declared here @@ -104,7 +104,7 @@ LL | a: u8, | ^^^^^ field already declared error[E0124]: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:57:13 + --> $DIR/field_uniqueness_check.rs:61:13 | LL | a: u8, | ----- `a` first declared here @@ -113,7 +113,7 @@ LL | a: u8, | ^^^^^ field already declared error[E0124]: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:62:17 + --> $DIR/field_uniqueness_check.rs:66:17 | LL | a: u8, | ----- `a` first declared here @@ -122,7 +122,7 @@ LL | a: u8, | ^^^^^ field already declared error: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:66:9 + --> $DIR/field_uniqueness_check.rs:70:9 | LL | a: u8, | ----- `a` first declared here @@ -131,13 +131,13 @@ LL | _: Foo, | ^^^^^^ field `a` declared in this unnamed field | note: field `a` declared here - --> $DIR/field_uniqueness_check.rs:6:5 + --> $DIR/field_uniqueness_check.rs:7:5 | LL | a: u8, | ^^^^^ error: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:67:9 + --> $DIR/field_uniqueness_check.rs:71:9 | LL | a: u8, | ----- `a` first declared here @@ -146,13 +146,13 @@ LL | _: Bar, | ^^^^^^ field `a` declared in this unnamed field | note: field `a` declared here - --> $DIR/field_uniqueness_check.rs:12:9 + --> $DIR/field_uniqueness_check.rs:14:9 | LL | a: u8, | ^^^^^ error: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:70:13 + --> $DIR/field_uniqueness_check.rs:74:13 | LL | a: u8, | ----- `a` first declared here @@ -161,13 +161,13 @@ LL | _: Foo, | ^^^^^^ field `a` declared in this unnamed field | note: field `a` declared here - --> $DIR/field_uniqueness_check.rs:6:5 + --> $DIR/field_uniqueness_check.rs:7:5 | LL | a: u8, | ^^^^^ error: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:71:13 + --> $DIR/field_uniqueness_check.rs:75:13 | LL | a: u8, | ----- `a` first declared here @@ -176,13 +176,13 @@ LL | _: Bar, | ^^^^^^ field `a` declared in this unnamed field | note: field `a` declared here - --> $DIR/field_uniqueness_check.rs:12:9 + --> $DIR/field_uniqueness_check.rs:14:9 | LL | a: u8, | ^^^^^ error[E0124]: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:76:5 + --> $DIR/field_uniqueness_check.rs:80:5 | LL | a: u8, | ----- `a` first declared here @@ -191,7 +191,7 @@ LL | a: u8, | ^^^^^ field already declared error[E0124]: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:79:9 + --> $DIR/field_uniqueness_check.rs:83:9 | LL | a: u8, | ----- `a` first declared here @@ -200,7 +200,7 @@ LL | a: u8, | ^^^^^ field already declared error[E0124]: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:84:13 + --> $DIR/field_uniqueness_check.rs:88:13 | LL | a: u8, | ----- `a` first declared here @@ -209,7 +209,7 @@ LL | a: u8, | ^^^^^ field already declared error: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:88:5 + --> $DIR/field_uniqueness_check.rs:92:5 | LL | a: u8, | ----- `a` first declared here @@ -218,13 +218,13 @@ LL | _: Foo, | ^^^^^^ field `a` declared in this unnamed field | note: field `a` declared here - --> $DIR/field_uniqueness_check.rs:6:5 + --> $DIR/field_uniqueness_check.rs:7:5 | LL | a: u8, | ^^^^^ error: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:89:5 + --> $DIR/field_uniqueness_check.rs:93:5 | LL | a: u8, | ----- `a` first declared here @@ -233,13 +233,13 @@ LL | _: Bar, | ^^^^^^ field `a` declared in this unnamed field | note: field `a` declared here - --> $DIR/field_uniqueness_check.rs:12:9 + --> $DIR/field_uniqueness_check.rs:14:9 | LL | a: u8, | ^^^^^ error: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:92:9 + --> $DIR/field_uniqueness_check.rs:96:9 | LL | a: u8, | ----- `a` first declared here @@ -248,13 +248,13 @@ LL | _: Foo, | ^^^^^^ field `a` declared in this unnamed field | note: field `a` declared here - --> $DIR/field_uniqueness_check.rs:6:5 + --> $DIR/field_uniqueness_check.rs:7:5 | LL | a: u8, | ^^^^^ error: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:93:9 + --> $DIR/field_uniqueness_check.rs:97:9 | LL | a: u8, | ----- `a` first declared here @@ -263,13 +263,13 @@ LL | _: Bar, | ^^^^^^ field `a` declared in this unnamed field | note: field `a` declared here - --> $DIR/field_uniqueness_check.rs:12:9 + --> $DIR/field_uniqueness_check.rs:14:9 | LL | a: u8, | ^^^^^ error[E0124]: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:106:13 + --> $DIR/field_uniqueness_check.rs:111:13 | LL | a: u8, | ----- `a` first declared here @@ -278,7 +278,7 @@ LL | a: u8, | ^^^^^ field already declared error[E0124]: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:109:17 + --> $DIR/field_uniqueness_check.rs:114:17 | LL | a: u8, | ----- `a` first declared here @@ -287,7 +287,7 @@ LL | a: u8, | ^^^^^ field already declared error[E0124]: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:114:21 + --> $DIR/field_uniqueness_check.rs:119:21 | LL | a: u8, | ----- `a` first declared here @@ -296,7 +296,7 @@ LL | a: u8, | ^^^^^ field already declared error: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:118:13 + --> $DIR/field_uniqueness_check.rs:123:13 | LL | a: u8, | ----- `a` first declared here @@ -305,13 +305,13 @@ LL | _: Foo, | ^^^^^^ field `a` declared in this unnamed field | note: field `a` declared here - --> $DIR/field_uniqueness_check.rs:6:5 + --> $DIR/field_uniqueness_check.rs:7:5 | LL | a: u8, | ^^^^^ error: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:119:13 + --> $DIR/field_uniqueness_check.rs:124:13 | LL | a: u8, | ----- `a` first declared here @@ -320,13 +320,13 @@ LL | _: Bar, | ^^^^^^ field `a` declared in this unnamed field | note: field `a` declared here - --> $DIR/field_uniqueness_check.rs:12:9 + --> $DIR/field_uniqueness_check.rs:14:9 | LL | a: u8, | ^^^^^ error: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:122:17 + --> $DIR/field_uniqueness_check.rs:127:17 | LL | a: u8, | ----- `a` first declared here @@ -335,13 +335,13 @@ LL | _: Foo, | ^^^^^^ field `a` declared in this unnamed field | note: field `a` declared here - --> $DIR/field_uniqueness_check.rs:6:5 + --> $DIR/field_uniqueness_check.rs:7:5 | LL | a: u8, | ^^^^^ error: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:123:17 + --> $DIR/field_uniqueness_check.rs:128:17 | LL | a: u8, | ----- `a` first declared here @@ -350,13 +350,13 @@ LL | _: Bar, | ^^^^^^ field `a` declared in this unnamed field | note: field `a` declared here - --> $DIR/field_uniqueness_check.rs:12:9 + --> $DIR/field_uniqueness_check.rs:14:9 | LL | a: u8, | ^^^^^ error[E0124]: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:128:9 + --> $DIR/field_uniqueness_check.rs:133:9 | LL | a: u8, | ----- `a` first declared here @@ -365,7 +365,7 @@ LL | a: u8, | ^^^^^ field already declared error[E0124]: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:131:13 + --> $DIR/field_uniqueness_check.rs:136:13 | LL | a: u8, | ----- `a` first declared here @@ -374,7 +374,7 @@ LL | a: u8, | ^^^^^ field already declared error[E0124]: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:136:17 + --> $DIR/field_uniqueness_check.rs:141:17 | LL | a: u8, | ----- `a` first declared here @@ -383,7 +383,7 @@ LL | a: u8, | ^^^^^ field already declared error: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:140:9 + --> $DIR/field_uniqueness_check.rs:145:9 | LL | a: u8, | ----- `a` first declared here @@ -392,13 +392,13 @@ LL | _: Foo, | ^^^^^^ field `a` declared in this unnamed field | note: field `a` declared here - --> $DIR/field_uniqueness_check.rs:6:5 + --> $DIR/field_uniqueness_check.rs:7:5 | LL | a: u8, | ^^^^^ error: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:141:9 + --> $DIR/field_uniqueness_check.rs:146:9 | LL | a: u8, | ----- `a` first declared here @@ -407,13 +407,13 @@ LL | _: Bar, | ^^^^^^ field `a` declared in this unnamed field | note: field `a` declared here - --> $DIR/field_uniqueness_check.rs:12:9 + --> $DIR/field_uniqueness_check.rs:14:9 | LL | a: u8, | ^^^^^ error: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:144:13 + --> $DIR/field_uniqueness_check.rs:149:13 | LL | a: u8, | ----- `a` first declared here @@ -422,13 +422,13 @@ LL | _: Foo, | ^^^^^^ field `a` declared in this unnamed field | note: field `a` declared here - --> $DIR/field_uniqueness_check.rs:6:5 + --> $DIR/field_uniqueness_check.rs:7:5 | LL | a: u8, | ^^^^^ error: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:145:13 + --> $DIR/field_uniqueness_check.rs:150:13 | LL | a: u8, | ----- `a` first declared here @@ -437,13 +437,13 @@ LL | _: Bar, | ^^^^^^ field `a` declared in this unnamed field | note: field `a` declared here - --> $DIR/field_uniqueness_check.rs:12:9 + --> $DIR/field_uniqueness_check.rs:14:9 | LL | a: u8, | ^^^^^ error[E0124]: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:149:5 + --> $DIR/field_uniqueness_check.rs:154:5 | LL | a: u8, | ----- `a` first declared here @@ -452,7 +452,7 @@ LL | a: u8, | ^^^^^ field already declared error[E0124]: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:152:9 + --> $DIR/field_uniqueness_check.rs:157:9 | LL | a: u8, | ----- `a` first declared here @@ -461,7 +461,7 @@ LL | a: u8, | ^^^^^ field already declared error[E0124]: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:157:13 + --> $DIR/field_uniqueness_check.rs:162:13 | LL | a: u8, | ----- `a` first declared here @@ -470,7 +470,7 @@ LL | a: u8, | ^^^^^ field already declared error: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:161:5 + --> $DIR/field_uniqueness_check.rs:166:5 | LL | a: u8, | ----- `a` first declared here @@ -479,13 +479,13 @@ LL | _: Foo, | ^^^^^^ field `a` declared in this unnamed field | note: field `a` declared here - --> $DIR/field_uniqueness_check.rs:6:5 + --> $DIR/field_uniqueness_check.rs:7:5 | LL | a: u8, | ^^^^^ error: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:162:5 + --> $DIR/field_uniqueness_check.rs:167:5 | LL | a: u8, | ----- `a` first declared here @@ -494,13 +494,13 @@ LL | _: Bar, | ^^^^^^ field `a` declared in this unnamed field | note: field `a` declared here - --> $DIR/field_uniqueness_check.rs:12:9 + --> $DIR/field_uniqueness_check.rs:14:9 | LL | a: u8, | ^^^^^ error: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:165:9 + --> $DIR/field_uniqueness_check.rs:170:9 | LL | a: u8, | ----- `a` first declared here @@ -509,13 +509,13 @@ LL | _: Foo, | ^^^^^^ field `a` declared in this unnamed field | note: field `a` declared here - --> $DIR/field_uniqueness_check.rs:6:5 + --> $DIR/field_uniqueness_check.rs:7:5 | LL | a: u8, | ^^^^^ error: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:166:9 + --> $DIR/field_uniqueness_check.rs:171:9 | LL | a: u8, | ----- `a` first declared here @@ -524,13 +524,13 @@ LL | _: Bar, | ^^^^^^ field `a` declared in this unnamed field | note: field `a` declared here - --> $DIR/field_uniqueness_check.rs:12:9 + --> $DIR/field_uniqueness_check.rs:14:9 | LL | a: u8, | ^^^^^ error: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:177:5 + --> $DIR/field_uniqueness_check.rs:183:5 | LL | _: Foo, | ------ `a` first declared here in this unnamed field @@ -539,13 +539,13 @@ LL | a: u8, | ^^^^^ field already declared | note: field `a` first declared here - --> $DIR/field_uniqueness_check.rs:6:5 + --> $DIR/field_uniqueness_check.rs:7:5 | LL | a: u8, | ^^^^^ error: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:180:9 + --> $DIR/field_uniqueness_check.rs:186:9 | LL | _: Foo, | ------ `a` first declared here in this unnamed field @@ -554,13 +554,13 @@ LL | a: u8, | ^^^^^ field already declared | note: field `a` first declared here - --> $DIR/field_uniqueness_check.rs:6:5 + --> $DIR/field_uniqueness_check.rs:7:5 | LL | a: u8, | ^^^^^ error: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:185:13 + --> $DIR/field_uniqueness_check.rs:191:13 | LL | _: Foo, | ------ `a` first declared here in this unnamed field @@ -569,13 +569,13 @@ LL | a: u8, | ^^^^^ field already declared | note: field `a` first declared here - --> $DIR/field_uniqueness_check.rs:6:5 + --> $DIR/field_uniqueness_check.rs:7:5 | LL | a: u8, | ^^^^^ error: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:189:5 + --> $DIR/field_uniqueness_check.rs:195:5 | LL | _: Foo, | ------ `a` first declared here in this unnamed field @@ -584,18 +584,18 @@ LL | _: Foo, | ^^^^^^ field `a` declared in this unnamed field | note: field `a` declared here - --> $DIR/field_uniqueness_check.rs:6:5 + --> $DIR/field_uniqueness_check.rs:7:5 | LL | a: u8, | ^^^^^ note: field `a` first declared here - --> $DIR/field_uniqueness_check.rs:6:5 + --> $DIR/field_uniqueness_check.rs:7:5 | LL | a: u8, | ^^^^^ error: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:190:5 + --> $DIR/field_uniqueness_check.rs:196:5 | LL | _: Foo, | ------ `a` first declared here in this unnamed field @@ -604,18 +604,18 @@ LL | _: Bar, | ^^^^^^ field `a` declared in this unnamed field | note: field `a` declared here - --> $DIR/field_uniqueness_check.rs:12:9 + --> $DIR/field_uniqueness_check.rs:14:9 | LL | a: u8, | ^^^^^ note: field `a` first declared here - --> $DIR/field_uniqueness_check.rs:6:5 + --> $DIR/field_uniqueness_check.rs:7:5 | LL | a: u8, | ^^^^^ error: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:193:9 + --> $DIR/field_uniqueness_check.rs:199:9 | LL | _: Foo, | ------ `a` first declared here in this unnamed field @@ -624,18 +624,18 @@ LL | _: Foo, | ^^^^^^ field `a` declared in this unnamed field | note: field `a` declared here - --> $DIR/field_uniqueness_check.rs:6:5 + --> $DIR/field_uniqueness_check.rs:7:5 | LL | a: u8, | ^^^^^ note: field `a` first declared here - --> $DIR/field_uniqueness_check.rs:6:5 + --> $DIR/field_uniqueness_check.rs:7:5 | LL | a: u8, | ^^^^^ error: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:194:9 + --> $DIR/field_uniqueness_check.rs:200:9 | LL | _: Foo, | ------ `a` first declared here in this unnamed field @@ -644,18 +644,18 @@ LL | _: Bar, | ^^^^^^ field `a` declared in this unnamed field | note: field `a` declared here - --> $DIR/field_uniqueness_check.rs:12:9 + --> $DIR/field_uniqueness_check.rs:14:9 | LL | a: u8, | ^^^^^ note: field `a` first declared here - --> $DIR/field_uniqueness_check.rs:6:5 + --> $DIR/field_uniqueness_check.rs:7:5 | LL | a: u8, | ^^^^^ error: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:205:5 + --> $DIR/field_uniqueness_check.rs:212:5 | LL | _: Bar, | ------ `a` first declared here in this unnamed field @@ -664,13 +664,13 @@ LL | a: u8, | ^^^^^ field already declared | note: field `a` first declared here - --> $DIR/field_uniqueness_check.rs:12:9 + --> $DIR/field_uniqueness_check.rs:14:9 | LL | a: u8, | ^^^^^ error: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:208:9 + --> $DIR/field_uniqueness_check.rs:215:9 | LL | _: Bar, | ------ `a` first declared here in this unnamed field @@ -679,13 +679,13 @@ LL | a: u8, | ^^^^^ field already declared | note: field `a` first declared here - --> $DIR/field_uniqueness_check.rs:12:9 + --> $DIR/field_uniqueness_check.rs:14:9 | LL | a: u8, | ^^^^^ error: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:213:13 + --> $DIR/field_uniqueness_check.rs:220:13 | LL | _: Bar, | ------ `a` first declared here in this unnamed field @@ -694,13 +694,13 @@ LL | a: u8, | ^^^^^ field already declared | note: field `a` first declared here - --> $DIR/field_uniqueness_check.rs:12:9 + --> $DIR/field_uniqueness_check.rs:14:9 | LL | a: u8, | ^^^^^ error: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:217:5 + --> $DIR/field_uniqueness_check.rs:224:5 | LL | _: Bar, | ------ `a` first declared here in this unnamed field @@ -709,18 +709,18 @@ LL | _: Foo, | ^^^^^^ field `a` declared in this unnamed field | note: field `a` declared here - --> $DIR/field_uniqueness_check.rs:6:5 + --> $DIR/field_uniqueness_check.rs:7:5 | LL | a: u8, | ^^^^^ note: field `a` first declared here - --> $DIR/field_uniqueness_check.rs:12:9 + --> $DIR/field_uniqueness_check.rs:14:9 | LL | a: u8, | ^^^^^ error: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:218:5 + --> $DIR/field_uniqueness_check.rs:225:5 | LL | _: Bar, | ------ `a` first declared here in this unnamed field @@ -729,18 +729,18 @@ LL | _: Bar, | ^^^^^^ field `a` declared in this unnamed field | note: field `a` declared here - --> $DIR/field_uniqueness_check.rs:12:9 + --> $DIR/field_uniqueness_check.rs:14:9 | LL | a: u8, | ^^^^^ note: field `a` first declared here - --> $DIR/field_uniqueness_check.rs:12:9 + --> $DIR/field_uniqueness_check.rs:14:9 | LL | a: u8, | ^^^^^ error: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:221:9 + --> $DIR/field_uniqueness_check.rs:228:9 | LL | _: Bar, | ------ `a` first declared here in this unnamed field @@ -749,18 +749,18 @@ LL | _: Foo, | ^^^^^^ field `a` declared in this unnamed field | note: field `a` declared here - --> $DIR/field_uniqueness_check.rs:6:5 + --> $DIR/field_uniqueness_check.rs:7:5 | LL | a: u8, | ^^^^^ note: field `a` first declared here - --> $DIR/field_uniqueness_check.rs:12:9 + --> $DIR/field_uniqueness_check.rs:14:9 | LL | a: u8, | ^^^^^ error: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:222:9 + --> $DIR/field_uniqueness_check.rs:229:9 | LL | _: Bar, | ------ `a` first declared here in this unnamed field @@ -769,18 +769,18 @@ LL | _: Bar, | ^^^^^^ field `a` declared in this unnamed field | note: field `a` declared here - --> $DIR/field_uniqueness_check.rs:12:9 + --> $DIR/field_uniqueness_check.rs:14:9 | LL | a: u8, | ^^^^^ note: field `a` first declared here - --> $DIR/field_uniqueness_check.rs:12:9 + --> $DIR/field_uniqueness_check.rs:14:9 | LL | a: u8, | ^^^^^ error: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:234:9 + --> $DIR/field_uniqueness_check.rs:242:9 | LL | _: Foo, | ------ `a` first declared here in this unnamed field @@ -789,13 +789,13 @@ LL | a: u8, | ^^^^^ field already declared | note: field `a` first declared here - --> $DIR/field_uniqueness_check.rs:6:5 + --> $DIR/field_uniqueness_check.rs:7:5 | LL | a: u8, | ^^^^^ error: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:237:13 + --> $DIR/field_uniqueness_check.rs:245:13 | LL | _: Foo, | ------ `a` first declared here in this unnamed field @@ -804,13 +804,13 @@ LL | a: u8, | ^^^^^ field already declared | note: field `a` first declared here - --> $DIR/field_uniqueness_check.rs:6:5 + --> $DIR/field_uniqueness_check.rs:7:5 | LL | a: u8, | ^^^^^ error: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:242:17 + --> $DIR/field_uniqueness_check.rs:250:17 | LL | _: Foo, | ------ `a` first declared here in this unnamed field @@ -819,13 +819,13 @@ LL | a: u8, | ^^^^^ field already declared | note: field `a` first declared here - --> $DIR/field_uniqueness_check.rs:6:5 + --> $DIR/field_uniqueness_check.rs:7:5 | LL | a: u8, | ^^^^^ error: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:246:9 + --> $DIR/field_uniqueness_check.rs:254:9 | LL | _: Foo, | ------ `a` first declared here in this unnamed field @@ -834,18 +834,18 @@ LL | _: Foo, | ^^^^^^ field `a` declared in this unnamed field | note: field `a` declared here - --> $DIR/field_uniqueness_check.rs:6:5 + --> $DIR/field_uniqueness_check.rs:7:5 | LL | a: u8, | ^^^^^ note: field `a` first declared here - --> $DIR/field_uniqueness_check.rs:6:5 + --> $DIR/field_uniqueness_check.rs:7:5 | LL | a: u8, | ^^^^^ error: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:247:9 + --> $DIR/field_uniqueness_check.rs:255:9 | LL | _: Foo, | ------ `a` first declared here in this unnamed field @@ -854,18 +854,18 @@ LL | _: Bar, | ^^^^^^ field `a` declared in this unnamed field | note: field `a` declared here - --> $DIR/field_uniqueness_check.rs:12:9 + --> $DIR/field_uniqueness_check.rs:14:9 | LL | a: u8, | ^^^^^ note: field `a` first declared here - --> $DIR/field_uniqueness_check.rs:6:5 + --> $DIR/field_uniqueness_check.rs:7:5 | LL | a: u8, | ^^^^^ error: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:250:13 + --> $DIR/field_uniqueness_check.rs:258:13 | LL | _: Foo, | ------ `a` first declared here in this unnamed field @@ -874,18 +874,18 @@ LL | _: Foo, | ^^^^^^ field `a` declared in this unnamed field | note: field `a` declared here - --> $DIR/field_uniqueness_check.rs:6:5 + --> $DIR/field_uniqueness_check.rs:7:5 | LL | a: u8, | ^^^^^ note: field `a` first declared here - --> $DIR/field_uniqueness_check.rs:6:5 + --> $DIR/field_uniqueness_check.rs:7:5 | LL | a: u8, | ^^^^^ error: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:251:13 + --> $DIR/field_uniqueness_check.rs:259:13 | LL | _: Foo, | ------ `a` first declared here in this unnamed field @@ -894,18 +894,18 @@ LL | _: Bar, | ^^^^^^ field `a` declared in this unnamed field | note: field `a` declared here - --> $DIR/field_uniqueness_check.rs:12:9 + --> $DIR/field_uniqueness_check.rs:14:9 | LL | a: u8, | ^^^^^ note: field `a` first declared here - --> $DIR/field_uniqueness_check.rs:6:5 + --> $DIR/field_uniqueness_check.rs:7:5 | LL | a: u8, | ^^^^^ error: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:256:5 + --> $DIR/field_uniqueness_check.rs:264:5 | LL | _: Foo, | ------ `a` first declared here in this unnamed field @@ -914,13 +914,13 @@ LL | a: u8, | ^^^^^ field already declared | note: field `a` first declared here - --> $DIR/field_uniqueness_check.rs:6:5 + --> $DIR/field_uniqueness_check.rs:7:5 | LL | a: u8, | ^^^^^ error: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:259:9 + --> $DIR/field_uniqueness_check.rs:267:9 | LL | _: Foo, | ------ `a` first declared here in this unnamed field @@ -929,13 +929,13 @@ LL | a: u8, | ^^^^^ field already declared | note: field `a` first declared here - --> $DIR/field_uniqueness_check.rs:6:5 + --> $DIR/field_uniqueness_check.rs:7:5 | LL | a: u8, | ^^^^^ error: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:264:13 + --> $DIR/field_uniqueness_check.rs:272:13 | LL | _: Foo, | ------ `a` first declared here in this unnamed field @@ -944,13 +944,13 @@ LL | a: u8, | ^^^^^ field already declared | note: field `a` first declared here - --> $DIR/field_uniqueness_check.rs:6:5 + --> $DIR/field_uniqueness_check.rs:7:5 | LL | a: u8, | ^^^^^ error: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:268:5 + --> $DIR/field_uniqueness_check.rs:276:5 | LL | _: Foo, | ------ `a` first declared here in this unnamed field @@ -959,18 +959,18 @@ LL | _: Foo, | ^^^^^^ field `a` declared in this unnamed field | note: field `a` declared here - --> $DIR/field_uniqueness_check.rs:6:5 + --> $DIR/field_uniqueness_check.rs:7:5 | LL | a: u8, | ^^^^^ note: field `a` first declared here - --> $DIR/field_uniqueness_check.rs:6:5 + --> $DIR/field_uniqueness_check.rs:7:5 | LL | a: u8, | ^^^^^ error: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:269:5 + --> $DIR/field_uniqueness_check.rs:277:5 | LL | _: Foo, | ------ `a` first declared here in this unnamed field @@ -979,18 +979,18 @@ LL | _: Bar, | ^^^^^^ field `a` declared in this unnamed field | note: field `a` declared here - --> $DIR/field_uniqueness_check.rs:12:9 + --> $DIR/field_uniqueness_check.rs:14:9 | LL | a: u8, | ^^^^^ note: field `a` first declared here - --> $DIR/field_uniqueness_check.rs:6:5 + --> $DIR/field_uniqueness_check.rs:7:5 | LL | a: u8, | ^^^^^ error: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:272:9 + --> $DIR/field_uniqueness_check.rs:280:9 | LL | _: Foo, | ------ `a` first declared here in this unnamed field @@ -999,18 +999,18 @@ LL | _: Foo, | ^^^^^^ field `a` declared in this unnamed field | note: field `a` declared here - --> $DIR/field_uniqueness_check.rs:6:5 + --> $DIR/field_uniqueness_check.rs:7:5 | LL | a: u8, | ^^^^^ note: field `a` first declared here - --> $DIR/field_uniqueness_check.rs:6:5 + --> $DIR/field_uniqueness_check.rs:7:5 | LL | a: u8, | ^^^^^ error: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:273:9 + --> $DIR/field_uniqueness_check.rs:281:9 | LL | _: Foo, | ------ `a` first declared here in this unnamed field @@ -1019,18 +1019,18 @@ LL | _: Bar, | ^^^^^^ field `a` declared in this unnamed field | note: field `a` declared here - --> $DIR/field_uniqueness_check.rs:12:9 + --> $DIR/field_uniqueness_check.rs:14:9 | LL | a: u8, | ^^^^^ note: field `a` first declared here - --> $DIR/field_uniqueness_check.rs:6:5 + --> $DIR/field_uniqueness_check.rs:7:5 | LL | a: u8, | ^^^^^ error: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:285:9 + --> $DIR/field_uniqueness_check.rs:294:9 | LL | _: Bar, | ------ `a` first declared here in this unnamed field @@ -1039,13 +1039,13 @@ LL | a: u8, | ^^^^^ field already declared | note: field `a` first declared here - --> $DIR/field_uniqueness_check.rs:12:9 + --> $DIR/field_uniqueness_check.rs:14:9 | LL | a: u8, | ^^^^^ error: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:288:13 + --> $DIR/field_uniqueness_check.rs:297:13 | LL | _: Bar, | ------ `a` first declared here in this unnamed field @@ -1054,13 +1054,13 @@ LL | a: u8, | ^^^^^ field already declared | note: field `a` first declared here - --> $DIR/field_uniqueness_check.rs:12:9 + --> $DIR/field_uniqueness_check.rs:14:9 | LL | a: u8, | ^^^^^ error: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:293:17 + --> $DIR/field_uniqueness_check.rs:302:17 | LL | _: Bar, | ------ `a` first declared here in this unnamed field @@ -1069,13 +1069,13 @@ LL | a: u8, | ^^^^^ field already declared | note: field `a` first declared here - --> $DIR/field_uniqueness_check.rs:12:9 + --> $DIR/field_uniqueness_check.rs:14:9 | LL | a: u8, | ^^^^^ error: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:297:9 + --> $DIR/field_uniqueness_check.rs:306:9 | LL | _: Bar, | ------ `a` first declared here in this unnamed field @@ -1084,18 +1084,18 @@ LL | _: Foo, | ^^^^^^ field `a` declared in this unnamed field | note: field `a` declared here - --> $DIR/field_uniqueness_check.rs:6:5 + --> $DIR/field_uniqueness_check.rs:7:5 | LL | a: u8, | ^^^^^ note: field `a` first declared here - --> $DIR/field_uniqueness_check.rs:12:9 + --> $DIR/field_uniqueness_check.rs:14:9 | LL | a: u8, | ^^^^^ error: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:298:9 + --> $DIR/field_uniqueness_check.rs:307:9 | LL | _: Bar, | ------ `a` first declared here in this unnamed field @@ -1104,18 +1104,18 @@ LL | _: Bar, | ^^^^^^ field `a` declared in this unnamed field | note: field `a` declared here - --> $DIR/field_uniqueness_check.rs:12:9 + --> $DIR/field_uniqueness_check.rs:14:9 | LL | a: u8, | ^^^^^ note: field `a` first declared here - --> $DIR/field_uniqueness_check.rs:12:9 + --> $DIR/field_uniqueness_check.rs:14:9 | LL | a: u8, | ^^^^^ error: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:301:13 + --> $DIR/field_uniqueness_check.rs:310:13 | LL | _: Bar, | ------ `a` first declared here in this unnamed field @@ -1124,18 +1124,18 @@ LL | _: Foo, | ^^^^^^ field `a` declared in this unnamed field | note: field `a` declared here - --> $DIR/field_uniqueness_check.rs:6:5 + --> $DIR/field_uniqueness_check.rs:7:5 | LL | a: u8, | ^^^^^ note: field `a` first declared here - --> $DIR/field_uniqueness_check.rs:12:9 + --> $DIR/field_uniqueness_check.rs:14:9 | LL | a: u8, | ^^^^^ error: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:302:13 + --> $DIR/field_uniqueness_check.rs:311:13 | LL | _: Bar, | ------ `a` first declared here in this unnamed field @@ -1144,18 +1144,18 @@ LL | _: Bar, | ^^^^^^ field `a` declared in this unnamed field | note: field `a` declared here - --> $DIR/field_uniqueness_check.rs:12:9 + --> $DIR/field_uniqueness_check.rs:14:9 | LL | a: u8, | ^^^^^ note: field `a` first declared here - --> $DIR/field_uniqueness_check.rs:12:9 + --> $DIR/field_uniqueness_check.rs:14:9 | LL | a: u8, | ^^^^^ error: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:307:5 + --> $DIR/field_uniqueness_check.rs:316:5 | LL | _: Bar, | ------ `a` first declared here in this unnamed field @@ -1164,13 +1164,13 @@ LL | a: u8, | ^^^^^ field already declared | note: field `a` first declared here - --> $DIR/field_uniqueness_check.rs:12:9 + --> $DIR/field_uniqueness_check.rs:14:9 | LL | a: u8, | ^^^^^ error: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:310:9 + --> $DIR/field_uniqueness_check.rs:319:9 | LL | _: Bar, | ------ `a` first declared here in this unnamed field @@ -1179,13 +1179,13 @@ LL | a: u8, | ^^^^^ field already declared | note: field `a` first declared here - --> $DIR/field_uniqueness_check.rs:12:9 + --> $DIR/field_uniqueness_check.rs:14:9 | LL | a: u8, | ^^^^^ error: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:315:13 + --> $DIR/field_uniqueness_check.rs:324:13 | LL | _: Bar, | ------ `a` first declared here in this unnamed field @@ -1194,13 +1194,13 @@ LL | a: u8, | ^^^^^ field already declared | note: field `a` first declared here - --> $DIR/field_uniqueness_check.rs:12:9 + --> $DIR/field_uniqueness_check.rs:14:9 | LL | a: u8, | ^^^^^ error: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:319:5 + --> $DIR/field_uniqueness_check.rs:328:5 | LL | _: Bar, | ------ `a` first declared here in this unnamed field @@ -1209,18 +1209,18 @@ LL | _: Foo, | ^^^^^^ field `a` declared in this unnamed field | note: field `a` declared here - --> $DIR/field_uniqueness_check.rs:6:5 + --> $DIR/field_uniqueness_check.rs:7:5 | LL | a: u8, | ^^^^^ note: field `a` first declared here - --> $DIR/field_uniqueness_check.rs:12:9 + --> $DIR/field_uniqueness_check.rs:14:9 | LL | a: u8, | ^^^^^ error: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:320:5 + --> $DIR/field_uniqueness_check.rs:329:5 | LL | _: Bar, | ------ `a` first declared here in this unnamed field @@ -1229,18 +1229,18 @@ LL | _: Bar, | ^^^^^^ field `a` declared in this unnamed field | note: field `a` declared here - --> $DIR/field_uniqueness_check.rs:12:9 + --> $DIR/field_uniqueness_check.rs:14:9 | LL | a: u8, | ^^^^^ note: field `a` first declared here - --> $DIR/field_uniqueness_check.rs:12:9 + --> $DIR/field_uniqueness_check.rs:14:9 | LL | a: u8, | ^^^^^ error: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:323:9 + --> $DIR/field_uniqueness_check.rs:332:9 | LL | _: Bar, | ------ `a` first declared here in this unnamed field @@ -1249,18 +1249,18 @@ LL | _: Foo, | ^^^^^^ field `a` declared in this unnamed field | note: field `a` declared here - --> $DIR/field_uniqueness_check.rs:6:5 + --> $DIR/field_uniqueness_check.rs:7:5 | LL | a: u8, | ^^^^^ note: field `a` first declared here - --> $DIR/field_uniqueness_check.rs:12:9 + --> $DIR/field_uniqueness_check.rs:14:9 | LL | a: u8, | ^^^^^ error: field `a` is already declared - --> $DIR/field_uniqueness_check.rs:324:9 + --> $DIR/field_uniqueness_check.rs:333:9 | LL | _: Bar, | ------ `a` first declared here in this unnamed field @@ -1269,12 +1269,12 @@ LL | _: Bar, | ^^^^^^ field `a` declared in this unnamed field | note: field `a` declared here - --> $DIR/field_uniqueness_check.rs:12:9 + --> $DIR/field_uniqueness_check.rs:14:9 | LL | a: u8, | ^^^^^ note: field `a` first declared here - --> $DIR/field_uniqueness_check.rs:12:9 + --> $DIR/field_uniqueness_check.rs:14:9 | LL | a: u8, | ^^^^^ From 0dbd6e9572c7c2bac7922116d6cd9357177ccbc9 Mon Sep 17 00:00:00 2001 From: Frank King Date: Mon, 29 Jan 2024 15:08:11 +0800 Subject: [PATCH 31/56] Improve some codes according to the reviews - improve diagnostics of field uniqueness check and representation check - simplify the implementation of field uniqueness check - remove some useless codes and improvement neatness --- compiler/rustc_hir_analysis/messages.ftl | 5 + .../rustc_hir_analysis/src/check/check.rs | 6 +- compiler/rustc_hir_analysis/src/collect.rs | 238 ++++----- compiler/rustc_hir_analysis/src/errors.rs | 20 + .../rustc_resolve/src/build_reduced_graph.rs | 10 +- .../src/solve/assembly/structural_traits.rs | 5 - src/librustdoc/clean/types.rs | 4 - .../field_uniqueness_check.stderr | 450 ++++++++++++++++++ .../ui/union/unnamed-fields/repr_check.stderr | 44 ++ 9 files changed, 658 insertions(+), 124 deletions(-) diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl index cf1a42c9285..537b7d9470d 100644 --- a/compiler/rustc_hir_analysis/messages.ftl +++ b/compiler/rustc_hir_analysis/messages.ftl @@ -136,6 +136,9 @@ hir_analysis_field_already_declared_current_nested = .nested_field_decl_note = field `{$field_name}` declared here .previous_decl_label = `{$field_name}` first declared here +hir_analysis_field_already_declared_nested_help = + fields from the type of this unnamed field are considered fields of the outer type + hir_analysis_field_already_declared_previous_nested = field `{$field_name}` is already declared .label = field already declared @@ -445,10 +448,12 @@ hir_analysis_unnamed_fields_repr_field_missing_repr_c = named type of unnamed field must have `#[repr(C)]` representation .label = unnamed field defined here .field_ty_label = `{$field_ty}` defined here + .suggestion = add `#[repr(C)]` to this {$field_adt_kind} hir_analysis_unnamed_fields_repr_missing_repr_c = {$adt_kind} with unnamed fields must have `#[repr(C)]` representation .label = {$adt_kind} `{$adt_name}` defined here + .suggestion = add `#[repr(C)]` to this {$adt_kind} hir_analysis_unrecognized_atomic_operation = unrecognized atomic operation function: `{$op}` diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 3cbd67a482c..f55cba2707c 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -122,6 +122,7 @@ fn check_unnamed_fields(tcx: TyCtxt<'_>, def: ty::AdtDef<'_>) { adt_kind, adt_name, unnamed_fields, + sugg_span: span.shrink_to_lo(), }); } } @@ -131,10 +132,13 @@ fn check_unnamed_fields(tcx: TyCtxt<'_>, def: ty::AdtDef<'_>) { && !adt.is_anonymous() && !adt.repr().c() { + let field_ty_span = tcx.def_span(adt.did()); tcx.dcx().emit_err(errors::UnnamedFieldsRepr::FieldMissingReprC { span: tcx.def_span(field.did), - field_ty_span: tcx.def_span(adt.did()), + field_ty_span, field_ty, + field_adt_kind: adt.descr(), + sugg_span: field_ty_span.shrink_to_lo(), }); } } diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 45938eacd65..d92e1a14151 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -791,12 +791,30 @@ fn convert_enum_variant_types(tcx: TyCtxt<'_>, def_id: DefId) { } } +fn find_field(tcx: TyCtxt<'_>, (def_id, ident): (DefId, Ident)) -> Option { + tcx.adt_def(def_id).non_enum_variant().fields.iter_enumerated().find_map(|(idx, field)| { + if field.is_unnamed() { + let field_ty = tcx.type_of(field.did).instantiate_identity(); + let adt_def = field_ty.ty_adt_def().expect("expect Adt for unnamed field"); + tcx.find_field((adt_def.did(), ident)).map(|_| idx) + } else { + (field.ident(tcx).normalize_to_macros_2_0() == ident).then_some(idx) + } + }) +} + #[derive(Clone, Copy)] struct NestedSpan { span: Span, nested_field_span: Span, } +impl NestedSpan { + fn to_field_already_declared_nested_help(&self) -> errors::FieldAlreadyDeclaredNestedHelp { + errors::FieldAlreadyDeclaredNestedHelp { span: self.span } + } +} + #[derive(Clone, Copy)] enum FieldDeclSpan { NotNested(Span), @@ -815,87 +833,131 @@ impl From for FieldDeclSpan { } } -/// Check the uniqueness of fields across adt where there are -/// nested fields imported from an unnamed field. -fn check_field_uniqueness_in_nested_adt( - tcx: TyCtxt<'_>, - adt_def: ty::AdtDef<'_>, - check: &mut impl FnMut(Ident, /* nested_field_span */ Span), -) { - for field in adt_def.all_fields() { - if field.is_unnamed() { - // Here we don't care about the generic parameters, so `instantiate_identity` is enough. - match tcx.type_of(field.did).instantiate_identity().kind() { - ty::Adt(adt_def, _) => { - check_field_uniqueness_in_nested_adt(tcx, *adt_def, &mut *check); - } - ty_kind => bug!( - "Unexpected ty kind in check_field_uniqueness_in_nested_adt(): {ty_kind:?}" - ), - } - } else { - check(field.ident(tcx), tcx.def_span(field.did)); - } - } +struct FieldUniquenessCheckContext<'tcx> { + tcx: TyCtxt<'tcx>, + seen_fields: FxHashMap, } -/// Check the uniqueness of fields in a struct variant, and recursively -/// check the nested fields if it is an unnamed field with type of an -/// annoymous adt. -fn check_field_uniqueness( - tcx: TyCtxt<'_>, - field: &hir::FieldDef<'_>, - check: &mut impl FnMut(Ident, FieldDeclSpan), -) { - if field.ident.name == kw::Underscore { - let ty_span = field.ty.span; +impl<'tcx> FieldUniquenessCheckContext<'tcx> { + fn new(tcx: TyCtxt<'tcx>) -> Self { + Self { tcx, seen_fields: FxHashMap::default() } + } + + /// Check if a given field `ident` declared at `field_decl` has been declared elsewhere before. + fn check_field_decl(&mut self, ident: Ident, field_decl: FieldDeclSpan) { + use FieldDeclSpan::*; + let field_name = ident.name; + let ident = ident.normalize_to_macros_2_0(); + match (field_decl, self.seen_fields.get(&ident).copied()) { + (NotNested(span), Some(NotNested(prev_span))) => { + self.tcx.dcx().emit_err(errors::FieldAlreadyDeclared::NotNested { + field_name, + span, + prev_span, + }); + } + (NotNested(span), Some(Nested(prev))) => { + self.tcx.dcx().emit_err(errors::FieldAlreadyDeclared::PreviousNested { + field_name, + span, + prev_span: prev.span, + prev_nested_field_span: prev.nested_field_span, + prev_help: prev.to_field_already_declared_nested_help(), + }); + } + ( + Nested(current @ NestedSpan { span, nested_field_span, .. }), + Some(NotNested(prev_span)), + ) => { + self.tcx.dcx().emit_err(errors::FieldAlreadyDeclared::CurrentNested { + field_name, + span, + nested_field_span, + help: current.to_field_already_declared_nested_help(), + prev_span, + }); + } + (Nested(current @ NestedSpan { span, nested_field_span }), Some(Nested(prev))) => { + self.tcx.dcx().emit_err(errors::FieldAlreadyDeclared::BothNested { + field_name, + span, + nested_field_span, + help: current.to_field_already_declared_nested_help(), + prev_span: prev.span, + prev_nested_field_span: prev.nested_field_span, + prev_help: prev.to_field_already_declared_nested_help(), + }); + } + (field_decl, None) => { + self.seen_fields.insert(ident, field_decl); + } + } + } + + /// Check the uniqueness of fields across adt where there are + /// nested fields imported from an unnamed field. + fn check_field_in_nested_adt(&mut self, adt_def: ty::AdtDef<'_>, unnamed_field_span: Span) { + for field in adt_def.all_fields() { + if field.is_unnamed() { + // Here we don't care about the generic parameters, so `instantiate_identity` is enough. + match self.tcx.type_of(field.did).instantiate_identity().kind() { + ty::Adt(adt_def, _) => { + self.check_field_in_nested_adt(*adt_def, unnamed_field_span); + } + ty_kind => span_bug!( + self.tcx.def_span(field.did), + "Unexpected TyKind in FieldUniquenessCheckContext::check_field_in_nested_adt(): {ty_kind:?}" + ), + } + } else { + self.check_field_decl( + field.ident(self.tcx), + NestedSpan { + span: unnamed_field_span, + nested_field_span: self.tcx.def_span(field.did), + } + .into(), + ); + } + } + } + + /// Check the uniqueness of fields in a struct variant, and recursively + /// check the nested fields if it is an unnamed field with type of an + /// annoymous adt. + fn check_field(&mut self, field: &hir::FieldDef<'_>) { + if field.ident.name != kw::Underscore { + self.check_field_decl(field.ident, field.span.into()); + return; + } match &field.ty.kind { hir::TyKind::AnonAdt(item_id) => { - match &tcx.hir_node(item_id.hir_id()).expect_item().kind { + match &self.tcx.hir_node(item_id.hir_id()).expect_item().kind { hir::ItemKind::Struct(variant_data, ..) | hir::ItemKind::Union(variant_data, ..) => { - variant_data - .fields() - .iter() - .for_each(|f| check_field_uniqueness(tcx, f, &mut *check)); + variant_data.fields().iter().for_each(|f| self.check_field(f)); } item_kind => span_bug!( - ty_span, - "Unexpected item kind in check_field_uniqueness(): {item_kind:?}" + field.ty.span, + "Unexpected ItemKind in FieldUniquenessCheckContext::check_field(): {item_kind:?}" ), } } hir::TyKind::Path(hir::QPath::Resolved(_, hir::Path { res, .. })) => { - check_field_uniqueness_in_nested_adt( - tcx, - tcx.adt_def(res.def_id()), - &mut |ident, nested_field_span| { - check(ident, NestedSpan { span: field.span, nested_field_span }.into()) - }, - ); + self.check_field_in_nested_adt(self.tcx.adt_def(res.def_id()), field.span); } // Abort due to errors (there must be an error if an unnamed field // has any type kind other than an anonymous adt or a named adt) - _ => { - debug_assert!(tcx.dcx().has_errors().is_some()); - tcx.dcx().abort_if_errors() + ty_kind => { + self.tcx.dcx().span_delayed_bug( + field.ty.span, + format!("Unexpected TyKind in FieldUniquenessCheckContext::check_field(): {ty_kind:?}"), + ); + // FIXME: errors during AST validation should abort the compilation before reaching here. + self.tcx.dcx().abort_if_errors(); } } - return; } - check(field.ident, field.span.into()); -} - -fn find_field(tcx: TyCtxt<'_>, (def_id, ident): (DefId, Ident)) -> Option { - tcx.adt_def(def_id).non_enum_variant().fields.iter_enumerated().find_map(|(idx, field)| { - if field.is_unnamed() { - let field_ty = tcx.type_of(field.did).instantiate_identity(); - let adt_def = field_ty.ty_adt_def().expect("expect Adt for unnamed field"); - tcx.find_field((adt_def.did(), ident)).map(|_| idx) - } else { - (field.ident(tcx).normalize_to_macros_2_0() == ident).then_some(idx) - } - }) } fn convert_variant( @@ -909,58 +971,16 @@ fn convert_variant( is_anonymous: bool, ) -> ty::VariantDef { let mut has_unnamed_fields = false; - let mut seen_fields: FxHashMap = Default::default(); + let mut field_uniqueness_check_ctx = FieldUniquenessCheckContext::new(tcx); let fields = def .fields() .iter() .inspect(|f| { has_unnamed_fields |= f.ident.name == kw::Underscore; + // We only check named ADT here because anonymous ADTs are checked inside + // the nammed ADT in which they are defined. if !is_anonymous { - check_field_uniqueness(tcx, f, &mut |ident, field_decl| { - use FieldDeclSpan::*; - let field_name = ident.name; - let ident = ident.normalize_to_macros_2_0(); - match (field_decl, seen_fields.get(&ident).copied()) { - (NotNested(span), Some(NotNested(prev_span))) => { - tcx.dcx().emit_err(errors::FieldAlreadyDeclared::NotNested { - field_name, - span, - prev_span, - }); - } - (NotNested(span), Some(Nested(prev))) => { - tcx.dcx().emit_err(errors::FieldAlreadyDeclared::PreviousNested { - field_name, - span, - prev_span: prev.span, - prev_nested_field_span: prev.nested_field_span, - }); - } - ( - Nested(NestedSpan { span, nested_field_span }), - Some(NotNested(prev_span)), - ) => { - tcx.dcx().emit_err(errors::FieldAlreadyDeclared::CurrentNested { - field_name, - span, - nested_field_span, - prev_span, - }); - } - (Nested(NestedSpan { span, nested_field_span }), Some(Nested(prev))) => { - tcx.dcx().emit_err(errors::FieldAlreadyDeclared::BothNested { - field_name, - span, - nested_field_span, - prev_span: prev.span, - prev_nested_field_span: prev.nested_field_span, - }); - } - (field_decl, None) => { - seen_fields.insert(ident, field_decl); - } - } - }); + field_uniqueness_check_ctx.check_field(f); } }) .map(|f| ty::FieldDef { diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index f7fa3263eaa..6e163cff7ed 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -193,6 +193,8 @@ pub enum FieldAlreadyDeclared { span: Span, #[note(hir_analysis_nested_field_decl_note)] nested_field_span: Span, + #[subdiagnostic] + help: FieldAlreadyDeclaredNestedHelp, #[label(hir_analysis_previous_decl_label)] prev_span: Span, }, @@ -206,6 +208,8 @@ pub enum FieldAlreadyDeclared { prev_span: Span, #[note(hir_analysis_previous_nested_field_decl_note)] prev_nested_field_span: Span, + #[subdiagnostic] + prev_help: FieldAlreadyDeclaredNestedHelp, }, #[diag(hir_analysis_field_already_declared_both_nested)] BothNested { @@ -215,13 +219,24 @@ pub enum FieldAlreadyDeclared { span: Span, #[note(hir_analysis_nested_field_decl_note)] nested_field_span: Span, + #[subdiagnostic] + help: FieldAlreadyDeclaredNestedHelp, #[label(hir_analysis_previous_decl_label)] prev_span: Span, #[note(hir_analysis_previous_nested_field_decl_note)] prev_nested_field_span: Span, + #[subdiagnostic] + prev_help: FieldAlreadyDeclaredNestedHelp, }, } +#[derive(Subdiagnostic)] +#[help(hir_analysis_field_already_declared_nested_help)] +pub struct FieldAlreadyDeclaredNestedHelp { + #[primary_span] + pub span: Span, +} + #[derive(Diagnostic)] #[diag(hir_analysis_copy_impl_on_type_with_dtor, code = E0184)] pub struct CopyImplOnTypeWithDtor { @@ -1583,6 +1598,8 @@ pub enum UnnamedFieldsRepr<'a> { adt_name: Symbol, #[subdiagnostic] unnamed_fields: Vec, + #[suggestion(code = "#[repr(C)]\n")] + sugg_span: Span, }, #[diag(hir_analysis_unnamed_fields_repr_field_missing_repr_c)] FieldMissingReprC { @@ -1592,6 +1609,9 @@ pub enum UnnamedFieldsRepr<'a> { #[label(hir_analysis_field_ty_label)] field_ty_span: Span, field_ty: Ty<'a>, + field_adt_kind: &'static str, + #[suggestion(code = "#[repr(C)]\n")] + sugg_span: Span, }, } diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 6bb9c22b04d..469d15e4214 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -628,7 +628,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { } } - fn build_reduced_graph_for_fields( + fn build_reduced_graph_for_struct_variant( &mut self, fields: &[ast::FieldDef], ident: Ident, @@ -657,14 +657,14 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { let def_id = local_def_id.to_def_id(); let def_kind = self.r.tcx.def_kind(local_def_id); let res = Res::Def(def_kind, def_id); - self.build_reduced_graph_for_fields( + self.build_reduced_graph_for_struct_variant( &nested_fields, Ident::empty(), local_def_id, res, // Anonymous adts inherit visibility from their parent adts. adt_vis, - field.span, + field.ty.span, ); } _ => {} @@ -759,7 +759,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { // These items live in both the type and value namespaces. ItemKind::Struct(ref vdata, _) => { - self.build_reduced_graph_for_fields( + self.build_reduced_graph_for_struct_variant( vdata.fields(), ident, local_def_id, @@ -809,7 +809,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { } ItemKind::Union(ref vdata, _) => { - self.build_reduced_graph_for_fields( + self.build_reduced_graph_for_struct_variant( vdata.fields(), ident, local_def_id, diff --git a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs index e2d5eaded3f..819b070cf8b 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs @@ -181,11 +181,6 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_copy_clone_trait<'tcx>( | ty::Ref(_, _, Mutability::Not) | ty::Array(..) => Err(NoSolution), - // Check for anonymous adts. - ty::Adt(adt, generics) if adt.is_anonymous() => { - Ok(adt.non_enum_variant().fields.iter().map(|f| f.ty(ecx.tcx(), generics)).collect()) - } - ty::Dynamic(..) | ty::Str | ty::Slice(_) diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 324ce03dcfd..6710193f961 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -1511,10 +1511,6 @@ pub(crate) enum Type { /// An `impl Trait`: `impl TraitA + TraitB + ...` ImplTrait(Vec), - // /// An anonymous struct type i.e. `struct { foo: Type }` - // AnonStruct(VariantStruct), - // /// An anonymous union type i.e. `union { bar: Type }` - // AnonUnion(VariantStruct), } impl Type { diff --git a/tests/ui/union/unnamed-fields/field_uniqueness_check.stderr b/tests/ui/union/unnamed-fields/field_uniqueness_check.stderr index 5773d3bb039..11978386843 100644 --- a/tests/ui/union/unnamed-fields/field_uniqueness_check.stderr +++ b/tests/ui/union/unnamed-fields/field_uniqueness_check.stderr @@ -48,6 +48,11 @@ note: field `a` declared here | LL | a: u8, | ^^^^^ +help: fields from the type of this unnamed field are considered fields of the outer type + --> $DIR/field_uniqueness_check.rs:40:5 + | +LL | _: Foo, + | ^^^^^^ error: field `a` is already declared --> $DIR/field_uniqueness_check.rs:41:5 @@ -63,6 +68,11 @@ note: field `a` declared here | LL | a: u8, | ^^^^^ +help: fields from the type of this unnamed field are considered fields of the outer type + --> $DIR/field_uniqueness_check.rs:41:5 + | +LL | _: Bar, + | ^^^^^^ error: field `a` is already declared --> $DIR/field_uniqueness_check.rs:44:9 @@ -78,6 +88,11 @@ note: field `a` declared here | LL | a: u8, | ^^^^^ +help: fields from the type of this unnamed field are considered fields of the outer type + --> $DIR/field_uniqueness_check.rs:44:9 + | +LL | _: Foo, + | ^^^^^^ error: field `a` is already declared --> $DIR/field_uniqueness_check.rs:45:9 @@ -93,6 +108,11 @@ note: field `a` declared here | LL | a: u8, | ^^^^^ +help: fields from the type of this unnamed field are considered fields of the outer type + --> $DIR/field_uniqueness_check.rs:45:9 + | +LL | _: Bar, + | ^^^^^^ error[E0124]: field `a` is already declared --> $DIR/field_uniqueness_check.rs:58:9 @@ -135,6 +155,11 @@ note: field `a` declared here | LL | a: u8, | ^^^^^ +help: fields from the type of this unnamed field are considered fields of the outer type + --> $DIR/field_uniqueness_check.rs:70:9 + | +LL | _: Foo, + | ^^^^^^ error: field `a` is already declared --> $DIR/field_uniqueness_check.rs:71:9 @@ -150,6 +175,11 @@ note: field `a` declared here | LL | a: u8, | ^^^^^ +help: fields from the type of this unnamed field are considered fields of the outer type + --> $DIR/field_uniqueness_check.rs:71:9 + | +LL | _: Bar, + | ^^^^^^ error: field `a` is already declared --> $DIR/field_uniqueness_check.rs:74:13 @@ -165,6 +195,11 @@ note: field `a` declared here | LL | a: u8, | ^^^^^ +help: fields from the type of this unnamed field are considered fields of the outer type + --> $DIR/field_uniqueness_check.rs:74:13 + | +LL | _: Foo, + | ^^^^^^ error: field `a` is already declared --> $DIR/field_uniqueness_check.rs:75:13 @@ -180,6 +215,11 @@ note: field `a` declared here | LL | a: u8, | ^^^^^ +help: fields from the type of this unnamed field are considered fields of the outer type + --> $DIR/field_uniqueness_check.rs:75:13 + | +LL | _: Bar, + | ^^^^^^ error[E0124]: field `a` is already declared --> $DIR/field_uniqueness_check.rs:80:5 @@ -222,6 +262,11 @@ note: field `a` declared here | LL | a: u8, | ^^^^^ +help: fields from the type of this unnamed field are considered fields of the outer type + --> $DIR/field_uniqueness_check.rs:92:5 + | +LL | _: Foo, + | ^^^^^^ error: field `a` is already declared --> $DIR/field_uniqueness_check.rs:93:5 @@ -237,6 +282,11 @@ note: field `a` declared here | LL | a: u8, | ^^^^^ +help: fields from the type of this unnamed field are considered fields of the outer type + --> $DIR/field_uniqueness_check.rs:93:5 + | +LL | _: Bar, + | ^^^^^^ error: field `a` is already declared --> $DIR/field_uniqueness_check.rs:96:9 @@ -252,6 +302,11 @@ note: field `a` declared here | LL | a: u8, | ^^^^^ +help: fields from the type of this unnamed field are considered fields of the outer type + --> $DIR/field_uniqueness_check.rs:96:9 + | +LL | _: Foo, + | ^^^^^^ error: field `a` is already declared --> $DIR/field_uniqueness_check.rs:97:9 @@ -267,6 +322,11 @@ note: field `a` declared here | LL | a: u8, | ^^^^^ +help: fields from the type of this unnamed field are considered fields of the outer type + --> $DIR/field_uniqueness_check.rs:97:9 + | +LL | _: Bar, + | ^^^^^^ error[E0124]: field `a` is already declared --> $DIR/field_uniqueness_check.rs:111:13 @@ -309,6 +369,11 @@ note: field `a` declared here | LL | a: u8, | ^^^^^ +help: fields from the type of this unnamed field are considered fields of the outer type + --> $DIR/field_uniqueness_check.rs:123:13 + | +LL | _: Foo, + | ^^^^^^ error: field `a` is already declared --> $DIR/field_uniqueness_check.rs:124:13 @@ -324,6 +389,11 @@ note: field `a` declared here | LL | a: u8, | ^^^^^ +help: fields from the type of this unnamed field are considered fields of the outer type + --> $DIR/field_uniqueness_check.rs:124:13 + | +LL | _: Bar, + | ^^^^^^ error: field `a` is already declared --> $DIR/field_uniqueness_check.rs:127:17 @@ -339,6 +409,11 @@ note: field `a` declared here | LL | a: u8, | ^^^^^ +help: fields from the type of this unnamed field are considered fields of the outer type + --> $DIR/field_uniqueness_check.rs:127:17 + | +LL | _: Foo, + | ^^^^^^ error: field `a` is already declared --> $DIR/field_uniqueness_check.rs:128:17 @@ -354,6 +429,11 @@ note: field `a` declared here | LL | a: u8, | ^^^^^ +help: fields from the type of this unnamed field are considered fields of the outer type + --> $DIR/field_uniqueness_check.rs:128:17 + | +LL | _: Bar, + | ^^^^^^ error[E0124]: field `a` is already declared --> $DIR/field_uniqueness_check.rs:133:9 @@ -396,6 +476,11 @@ note: field `a` declared here | LL | a: u8, | ^^^^^ +help: fields from the type of this unnamed field are considered fields of the outer type + --> $DIR/field_uniqueness_check.rs:145:9 + | +LL | _: Foo, + | ^^^^^^ error: field `a` is already declared --> $DIR/field_uniqueness_check.rs:146:9 @@ -411,6 +496,11 @@ note: field `a` declared here | LL | a: u8, | ^^^^^ +help: fields from the type of this unnamed field are considered fields of the outer type + --> $DIR/field_uniqueness_check.rs:146:9 + | +LL | _: Bar, + | ^^^^^^ error: field `a` is already declared --> $DIR/field_uniqueness_check.rs:149:13 @@ -426,6 +516,11 @@ note: field `a` declared here | LL | a: u8, | ^^^^^ +help: fields from the type of this unnamed field are considered fields of the outer type + --> $DIR/field_uniqueness_check.rs:149:13 + | +LL | _: Foo, + | ^^^^^^ error: field `a` is already declared --> $DIR/field_uniqueness_check.rs:150:13 @@ -441,6 +536,11 @@ note: field `a` declared here | LL | a: u8, | ^^^^^ +help: fields from the type of this unnamed field are considered fields of the outer type + --> $DIR/field_uniqueness_check.rs:150:13 + | +LL | _: Bar, + | ^^^^^^ error[E0124]: field `a` is already declared --> $DIR/field_uniqueness_check.rs:154:5 @@ -483,6 +583,11 @@ note: field `a` declared here | LL | a: u8, | ^^^^^ +help: fields from the type of this unnamed field are considered fields of the outer type + --> $DIR/field_uniqueness_check.rs:166:5 + | +LL | _: Foo, + | ^^^^^^ error: field `a` is already declared --> $DIR/field_uniqueness_check.rs:167:5 @@ -498,6 +603,11 @@ note: field `a` declared here | LL | a: u8, | ^^^^^ +help: fields from the type of this unnamed field are considered fields of the outer type + --> $DIR/field_uniqueness_check.rs:167:5 + | +LL | _: Bar, + | ^^^^^^ error: field `a` is already declared --> $DIR/field_uniqueness_check.rs:170:9 @@ -513,6 +623,11 @@ note: field `a` declared here | LL | a: u8, | ^^^^^ +help: fields from the type of this unnamed field are considered fields of the outer type + --> $DIR/field_uniqueness_check.rs:170:9 + | +LL | _: Foo, + | ^^^^^^ error: field `a` is already declared --> $DIR/field_uniqueness_check.rs:171:9 @@ -528,6 +643,11 @@ note: field `a` declared here | LL | a: u8, | ^^^^^ +help: fields from the type of this unnamed field are considered fields of the outer type + --> $DIR/field_uniqueness_check.rs:171:9 + | +LL | _: Bar, + | ^^^^^^ error: field `a` is already declared --> $DIR/field_uniqueness_check.rs:183:5 @@ -543,6 +663,11 @@ note: field `a` first declared here | LL | a: u8, | ^^^^^ +help: fields from the type of this unnamed field are considered fields of the outer type + --> $DIR/field_uniqueness_check.rs:180:5 + | +LL | _: Foo, + | ^^^^^^ error: field `a` is already declared --> $DIR/field_uniqueness_check.rs:186:9 @@ -558,6 +683,11 @@ note: field `a` first declared here | LL | a: u8, | ^^^^^ +help: fields from the type of this unnamed field are considered fields of the outer type + --> $DIR/field_uniqueness_check.rs:180:5 + | +LL | _: Foo, + | ^^^^^^ error: field `a` is already declared --> $DIR/field_uniqueness_check.rs:191:13 @@ -573,6 +703,11 @@ note: field `a` first declared here | LL | a: u8, | ^^^^^ +help: fields from the type of this unnamed field are considered fields of the outer type + --> $DIR/field_uniqueness_check.rs:180:5 + | +LL | _: Foo, + | ^^^^^^ error: field `a` is already declared --> $DIR/field_uniqueness_check.rs:195:5 @@ -588,11 +723,21 @@ note: field `a` declared here | LL | a: u8, | ^^^^^ +help: fields from the type of this unnamed field are considered fields of the outer type + --> $DIR/field_uniqueness_check.rs:195:5 + | +LL | _: Foo, + | ^^^^^^ note: field `a` first declared here --> $DIR/field_uniqueness_check.rs:7:5 | LL | a: u8, | ^^^^^ +help: fields from the type of this unnamed field are considered fields of the outer type + --> $DIR/field_uniqueness_check.rs:180:5 + | +LL | _: Foo, + | ^^^^^^ error: field `a` is already declared --> $DIR/field_uniqueness_check.rs:196:5 @@ -608,11 +753,21 @@ note: field `a` declared here | LL | a: u8, | ^^^^^ +help: fields from the type of this unnamed field are considered fields of the outer type + --> $DIR/field_uniqueness_check.rs:196:5 + | +LL | _: Bar, + | ^^^^^^ note: field `a` first declared here --> $DIR/field_uniqueness_check.rs:7:5 | LL | a: u8, | ^^^^^ +help: fields from the type of this unnamed field are considered fields of the outer type + --> $DIR/field_uniqueness_check.rs:180:5 + | +LL | _: Foo, + | ^^^^^^ error: field `a` is already declared --> $DIR/field_uniqueness_check.rs:199:9 @@ -628,11 +783,21 @@ note: field `a` declared here | LL | a: u8, | ^^^^^ +help: fields from the type of this unnamed field are considered fields of the outer type + --> $DIR/field_uniqueness_check.rs:199:9 + | +LL | _: Foo, + | ^^^^^^ note: field `a` first declared here --> $DIR/field_uniqueness_check.rs:7:5 | LL | a: u8, | ^^^^^ +help: fields from the type of this unnamed field are considered fields of the outer type + --> $DIR/field_uniqueness_check.rs:180:5 + | +LL | _: Foo, + | ^^^^^^ error: field `a` is already declared --> $DIR/field_uniqueness_check.rs:200:9 @@ -648,11 +813,21 @@ note: field `a` declared here | LL | a: u8, | ^^^^^ +help: fields from the type of this unnamed field are considered fields of the outer type + --> $DIR/field_uniqueness_check.rs:200:9 + | +LL | _: Bar, + | ^^^^^^ note: field `a` first declared here --> $DIR/field_uniqueness_check.rs:7:5 | LL | a: u8, | ^^^^^ +help: fields from the type of this unnamed field are considered fields of the outer type + --> $DIR/field_uniqueness_check.rs:180:5 + | +LL | _: Foo, + | ^^^^^^ error: field `a` is already declared --> $DIR/field_uniqueness_check.rs:212:5 @@ -668,6 +843,11 @@ note: field `a` first declared here | LL | a: u8, | ^^^^^ +help: fields from the type of this unnamed field are considered fields of the outer type + --> $DIR/field_uniqueness_check.rs:209:5 + | +LL | _: Bar, + | ^^^^^^ error: field `a` is already declared --> $DIR/field_uniqueness_check.rs:215:9 @@ -683,6 +863,11 @@ note: field `a` first declared here | LL | a: u8, | ^^^^^ +help: fields from the type of this unnamed field are considered fields of the outer type + --> $DIR/field_uniqueness_check.rs:209:5 + | +LL | _: Bar, + | ^^^^^^ error: field `a` is already declared --> $DIR/field_uniqueness_check.rs:220:13 @@ -698,6 +883,11 @@ note: field `a` first declared here | LL | a: u8, | ^^^^^ +help: fields from the type of this unnamed field are considered fields of the outer type + --> $DIR/field_uniqueness_check.rs:209:5 + | +LL | _: Bar, + | ^^^^^^ error: field `a` is already declared --> $DIR/field_uniqueness_check.rs:224:5 @@ -713,11 +903,21 @@ note: field `a` declared here | LL | a: u8, | ^^^^^ +help: fields from the type of this unnamed field are considered fields of the outer type + --> $DIR/field_uniqueness_check.rs:224:5 + | +LL | _: Foo, + | ^^^^^^ note: field `a` first declared here --> $DIR/field_uniqueness_check.rs:14:9 | LL | a: u8, | ^^^^^ +help: fields from the type of this unnamed field are considered fields of the outer type + --> $DIR/field_uniqueness_check.rs:209:5 + | +LL | _: Bar, + | ^^^^^^ error: field `a` is already declared --> $DIR/field_uniqueness_check.rs:225:5 @@ -733,11 +933,21 @@ note: field `a` declared here | LL | a: u8, | ^^^^^ +help: fields from the type of this unnamed field are considered fields of the outer type + --> $DIR/field_uniqueness_check.rs:225:5 + | +LL | _: Bar, + | ^^^^^^ note: field `a` first declared here --> $DIR/field_uniqueness_check.rs:14:9 | LL | a: u8, | ^^^^^ +help: fields from the type of this unnamed field are considered fields of the outer type + --> $DIR/field_uniqueness_check.rs:209:5 + | +LL | _: Bar, + | ^^^^^^ error: field `a` is already declared --> $DIR/field_uniqueness_check.rs:228:9 @@ -753,11 +963,21 @@ note: field `a` declared here | LL | a: u8, | ^^^^^ +help: fields from the type of this unnamed field are considered fields of the outer type + --> $DIR/field_uniqueness_check.rs:228:9 + | +LL | _: Foo, + | ^^^^^^ note: field `a` first declared here --> $DIR/field_uniqueness_check.rs:14:9 | LL | a: u8, | ^^^^^ +help: fields from the type of this unnamed field are considered fields of the outer type + --> $DIR/field_uniqueness_check.rs:209:5 + | +LL | _: Bar, + | ^^^^^^ error: field `a` is already declared --> $DIR/field_uniqueness_check.rs:229:9 @@ -773,11 +993,21 @@ note: field `a` declared here | LL | a: u8, | ^^^^^ +help: fields from the type of this unnamed field are considered fields of the outer type + --> $DIR/field_uniqueness_check.rs:229:9 + | +LL | _: Bar, + | ^^^^^^ note: field `a` first declared here --> $DIR/field_uniqueness_check.rs:14:9 | LL | a: u8, | ^^^^^ +help: fields from the type of this unnamed field are considered fields of the outer type + --> $DIR/field_uniqueness_check.rs:209:5 + | +LL | _: Bar, + | ^^^^^^ error: field `a` is already declared --> $DIR/field_uniqueness_check.rs:242:9 @@ -793,6 +1023,11 @@ note: field `a` first declared here | LL | a: u8, | ^^^^^ +help: fields from the type of this unnamed field are considered fields of the outer type + --> $DIR/field_uniqueness_check.rs:239:9 + | +LL | _: Foo, + | ^^^^^^ error: field `a` is already declared --> $DIR/field_uniqueness_check.rs:245:13 @@ -808,6 +1043,11 @@ note: field `a` first declared here | LL | a: u8, | ^^^^^ +help: fields from the type of this unnamed field are considered fields of the outer type + --> $DIR/field_uniqueness_check.rs:239:9 + | +LL | _: Foo, + | ^^^^^^ error: field `a` is already declared --> $DIR/field_uniqueness_check.rs:250:17 @@ -823,6 +1063,11 @@ note: field `a` first declared here | LL | a: u8, | ^^^^^ +help: fields from the type of this unnamed field are considered fields of the outer type + --> $DIR/field_uniqueness_check.rs:239:9 + | +LL | _: Foo, + | ^^^^^^ error: field `a` is already declared --> $DIR/field_uniqueness_check.rs:254:9 @@ -838,11 +1083,21 @@ note: field `a` declared here | LL | a: u8, | ^^^^^ +help: fields from the type of this unnamed field are considered fields of the outer type + --> $DIR/field_uniqueness_check.rs:254:9 + | +LL | _: Foo, + | ^^^^^^ note: field `a` first declared here --> $DIR/field_uniqueness_check.rs:7:5 | LL | a: u8, | ^^^^^ +help: fields from the type of this unnamed field are considered fields of the outer type + --> $DIR/field_uniqueness_check.rs:239:9 + | +LL | _: Foo, + | ^^^^^^ error: field `a` is already declared --> $DIR/field_uniqueness_check.rs:255:9 @@ -858,11 +1113,21 @@ note: field `a` declared here | LL | a: u8, | ^^^^^ +help: fields from the type of this unnamed field are considered fields of the outer type + --> $DIR/field_uniqueness_check.rs:255:9 + | +LL | _: Bar, + | ^^^^^^ note: field `a` first declared here --> $DIR/field_uniqueness_check.rs:7:5 | LL | a: u8, | ^^^^^ +help: fields from the type of this unnamed field are considered fields of the outer type + --> $DIR/field_uniqueness_check.rs:239:9 + | +LL | _: Foo, + | ^^^^^^ error: field `a` is already declared --> $DIR/field_uniqueness_check.rs:258:13 @@ -878,11 +1143,21 @@ note: field `a` declared here | LL | a: u8, | ^^^^^ +help: fields from the type of this unnamed field are considered fields of the outer type + --> $DIR/field_uniqueness_check.rs:258:13 + | +LL | _: Foo, + | ^^^^^^ note: field `a` first declared here --> $DIR/field_uniqueness_check.rs:7:5 | LL | a: u8, | ^^^^^ +help: fields from the type of this unnamed field are considered fields of the outer type + --> $DIR/field_uniqueness_check.rs:239:9 + | +LL | _: Foo, + | ^^^^^^ error: field `a` is already declared --> $DIR/field_uniqueness_check.rs:259:13 @@ -898,11 +1173,21 @@ note: field `a` declared here | LL | a: u8, | ^^^^^ +help: fields from the type of this unnamed field are considered fields of the outer type + --> $DIR/field_uniqueness_check.rs:259:13 + | +LL | _: Bar, + | ^^^^^^ note: field `a` first declared here --> $DIR/field_uniqueness_check.rs:7:5 | LL | a: u8, | ^^^^^ +help: fields from the type of this unnamed field are considered fields of the outer type + --> $DIR/field_uniqueness_check.rs:239:9 + | +LL | _: Foo, + | ^^^^^^ error: field `a` is already declared --> $DIR/field_uniqueness_check.rs:264:5 @@ -918,6 +1203,11 @@ note: field `a` first declared here | LL | a: u8, | ^^^^^ +help: fields from the type of this unnamed field are considered fields of the outer type + --> $DIR/field_uniqueness_check.rs:239:9 + | +LL | _: Foo, + | ^^^^^^ error: field `a` is already declared --> $DIR/field_uniqueness_check.rs:267:9 @@ -933,6 +1223,11 @@ note: field `a` first declared here | LL | a: u8, | ^^^^^ +help: fields from the type of this unnamed field are considered fields of the outer type + --> $DIR/field_uniqueness_check.rs:239:9 + | +LL | _: Foo, + | ^^^^^^ error: field `a` is already declared --> $DIR/field_uniqueness_check.rs:272:13 @@ -948,6 +1243,11 @@ note: field `a` first declared here | LL | a: u8, | ^^^^^ +help: fields from the type of this unnamed field are considered fields of the outer type + --> $DIR/field_uniqueness_check.rs:239:9 + | +LL | _: Foo, + | ^^^^^^ error: field `a` is already declared --> $DIR/field_uniqueness_check.rs:276:5 @@ -963,11 +1263,21 @@ note: field `a` declared here | LL | a: u8, | ^^^^^ +help: fields from the type of this unnamed field are considered fields of the outer type + --> $DIR/field_uniqueness_check.rs:276:5 + | +LL | _: Foo, + | ^^^^^^ note: field `a` first declared here --> $DIR/field_uniqueness_check.rs:7:5 | LL | a: u8, | ^^^^^ +help: fields from the type of this unnamed field are considered fields of the outer type + --> $DIR/field_uniqueness_check.rs:239:9 + | +LL | _: Foo, + | ^^^^^^ error: field `a` is already declared --> $DIR/field_uniqueness_check.rs:277:5 @@ -983,11 +1293,21 @@ note: field `a` declared here | LL | a: u8, | ^^^^^ +help: fields from the type of this unnamed field are considered fields of the outer type + --> $DIR/field_uniqueness_check.rs:277:5 + | +LL | _: Bar, + | ^^^^^^ note: field `a` first declared here --> $DIR/field_uniqueness_check.rs:7:5 | LL | a: u8, | ^^^^^ +help: fields from the type of this unnamed field are considered fields of the outer type + --> $DIR/field_uniqueness_check.rs:239:9 + | +LL | _: Foo, + | ^^^^^^ error: field `a` is already declared --> $DIR/field_uniqueness_check.rs:280:9 @@ -1003,11 +1323,21 @@ note: field `a` declared here | LL | a: u8, | ^^^^^ +help: fields from the type of this unnamed field are considered fields of the outer type + --> $DIR/field_uniqueness_check.rs:280:9 + | +LL | _: Foo, + | ^^^^^^ note: field `a` first declared here --> $DIR/field_uniqueness_check.rs:7:5 | LL | a: u8, | ^^^^^ +help: fields from the type of this unnamed field are considered fields of the outer type + --> $DIR/field_uniqueness_check.rs:239:9 + | +LL | _: Foo, + | ^^^^^^ error: field `a` is already declared --> $DIR/field_uniqueness_check.rs:281:9 @@ -1023,11 +1353,21 @@ note: field `a` declared here | LL | a: u8, | ^^^^^ +help: fields from the type of this unnamed field are considered fields of the outer type + --> $DIR/field_uniqueness_check.rs:281:9 + | +LL | _: Bar, + | ^^^^^^ note: field `a` first declared here --> $DIR/field_uniqueness_check.rs:7:5 | LL | a: u8, | ^^^^^ +help: fields from the type of this unnamed field are considered fields of the outer type + --> $DIR/field_uniqueness_check.rs:239:9 + | +LL | _: Foo, + | ^^^^^^ error: field `a` is already declared --> $DIR/field_uniqueness_check.rs:294:9 @@ -1043,6 +1383,11 @@ note: field `a` first declared here | LL | a: u8, | ^^^^^ +help: fields from the type of this unnamed field are considered fields of the outer type + --> $DIR/field_uniqueness_check.rs:291:9 + | +LL | _: Bar, + | ^^^^^^ error: field `a` is already declared --> $DIR/field_uniqueness_check.rs:297:13 @@ -1058,6 +1403,11 @@ note: field `a` first declared here | LL | a: u8, | ^^^^^ +help: fields from the type of this unnamed field are considered fields of the outer type + --> $DIR/field_uniqueness_check.rs:291:9 + | +LL | _: Bar, + | ^^^^^^ error: field `a` is already declared --> $DIR/field_uniqueness_check.rs:302:17 @@ -1073,6 +1423,11 @@ note: field `a` first declared here | LL | a: u8, | ^^^^^ +help: fields from the type of this unnamed field are considered fields of the outer type + --> $DIR/field_uniqueness_check.rs:291:9 + | +LL | _: Bar, + | ^^^^^^ error: field `a` is already declared --> $DIR/field_uniqueness_check.rs:306:9 @@ -1088,11 +1443,21 @@ note: field `a` declared here | LL | a: u8, | ^^^^^ +help: fields from the type of this unnamed field are considered fields of the outer type + --> $DIR/field_uniqueness_check.rs:306:9 + | +LL | _: Foo, + | ^^^^^^ note: field `a` first declared here --> $DIR/field_uniqueness_check.rs:14:9 | LL | a: u8, | ^^^^^ +help: fields from the type of this unnamed field are considered fields of the outer type + --> $DIR/field_uniqueness_check.rs:291:9 + | +LL | _: Bar, + | ^^^^^^ error: field `a` is already declared --> $DIR/field_uniqueness_check.rs:307:9 @@ -1108,11 +1473,21 @@ note: field `a` declared here | LL | a: u8, | ^^^^^ +help: fields from the type of this unnamed field are considered fields of the outer type + --> $DIR/field_uniqueness_check.rs:307:9 + | +LL | _: Bar, + | ^^^^^^ note: field `a` first declared here --> $DIR/field_uniqueness_check.rs:14:9 | LL | a: u8, | ^^^^^ +help: fields from the type of this unnamed field are considered fields of the outer type + --> $DIR/field_uniqueness_check.rs:291:9 + | +LL | _: Bar, + | ^^^^^^ error: field `a` is already declared --> $DIR/field_uniqueness_check.rs:310:13 @@ -1128,11 +1503,21 @@ note: field `a` declared here | LL | a: u8, | ^^^^^ +help: fields from the type of this unnamed field are considered fields of the outer type + --> $DIR/field_uniqueness_check.rs:310:13 + | +LL | _: Foo, + | ^^^^^^ note: field `a` first declared here --> $DIR/field_uniqueness_check.rs:14:9 | LL | a: u8, | ^^^^^ +help: fields from the type of this unnamed field are considered fields of the outer type + --> $DIR/field_uniqueness_check.rs:291:9 + | +LL | _: Bar, + | ^^^^^^ error: field `a` is already declared --> $DIR/field_uniqueness_check.rs:311:13 @@ -1148,11 +1533,21 @@ note: field `a` declared here | LL | a: u8, | ^^^^^ +help: fields from the type of this unnamed field are considered fields of the outer type + --> $DIR/field_uniqueness_check.rs:311:13 + | +LL | _: Bar, + | ^^^^^^ note: field `a` first declared here --> $DIR/field_uniqueness_check.rs:14:9 | LL | a: u8, | ^^^^^ +help: fields from the type of this unnamed field are considered fields of the outer type + --> $DIR/field_uniqueness_check.rs:291:9 + | +LL | _: Bar, + | ^^^^^^ error: field `a` is already declared --> $DIR/field_uniqueness_check.rs:316:5 @@ -1168,6 +1563,11 @@ note: field `a` first declared here | LL | a: u8, | ^^^^^ +help: fields from the type of this unnamed field are considered fields of the outer type + --> $DIR/field_uniqueness_check.rs:291:9 + | +LL | _: Bar, + | ^^^^^^ error: field `a` is already declared --> $DIR/field_uniqueness_check.rs:319:9 @@ -1183,6 +1583,11 @@ note: field `a` first declared here | LL | a: u8, | ^^^^^ +help: fields from the type of this unnamed field are considered fields of the outer type + --> $DIR/field_uniqueness_check.rs:291:9 + | +LL | _: Bar, + | ^^^^^^ error: field `a` is already declared --> $DIR/field_uniqueness_check.rs:324:13 @@ -1198,6 +1603,11 @@ note: field `a` first declared here | LL | a: u8, | ^^^^^ +help: fields from the type of this unnamed field are considered fields of the outer type + --> $DIR/field_uniqueness_check.rs:291:9 + | +LL | _: Bar, + | ^^^^^^ error: field `a` is already declared --> $DIR/field_uniqueness_check.rs:328:5 @@ -1213,11 +1623,21 @@ note: field `a` declared here | LL | a: u8, | ^^^^^ +help: fields from the type of this unnamed field are considered fields of the outer type + --> $DIR/field_uniqueness_check.rs:328:5 + | +LL | _: Foo, + | ^^^^^^ note: field `a` first declared here --> $DIR/field_uniqueness_check.rs:14:9 | LL | a: u8, | ^^^^^ +help: fields from the type of this unnamed field are considered fields of the outer type + --> $DIR/field_uniqueness_check.rs:291:9 + | +LL | _: Bar, + | ^^^^^^ error: field `a` is already declared --> $DIR/field_uniqueness_check.rs:329:5 @@ -1233,11 +1653,21 @@ note: field `a` declared here | LL | a: u8, | ^^^^^ +help: fields from the type of this unnamed field are considered fields of the outer type + --> $DIR/field_uniqueness_check.rs:329:5 + | +LL | _: Bar, + | ^^^^^^ note: field `a` first declared here --> $DIR/field_uniqueness_check.rs:14:9 | LL | a: u8, | ^^^^^ +help: fields from the type of this unnamed field are considered fields of the outer type + --> $DIR/field_uniqueness_check.rs:291:9 + | +LL | _: Bar, + | ^^^^^^ error: field `a` is already declared --> $DIR/field_uniqueness_check.rs:332:9 @@ -1253,11 +1683,21 @@ note: field `a` declared here | LL | a: u8, | ^^^^^ +help: fields from the type of this unnamed field are considered fields of the outer type + --> $DIR/field_uniqueness_check.rs:332:9 + | +LL | _: Foo, + | ^^^^^^ note: field `a` first declared here --> $DIR/field_uniqueness_check.rs:14:9 | LL | a: u8, | ^^^^^ +help: fields from the type of this unnamed field are considered fields of the outer type + --> $DIR/field_uniqueness_check.rs:291:9 + | +LL | _: Bar, + | ^^^^^^ error: field `a` is already declared --> $DIR/field_uniqueness_check.rs:333:9 @@ -1273,11 +1713,21 @@ note: field `a` declared here | LL | a: u8, | ^^^^^ +help: fields from the type of this unnamed field are considered fields of the outer type + --> $DIR/field_uniqueness_check.rs:333:9 + | +LL | _: Bar, + | ^^^^^^ note: field `a` first declared here --> $DIR/field_uniqueness_check.rs:14:9 | LL | a: u8, | ^^^^^ +help: fields from the type of this unnamed field are considered fields of the outer type + --> $DIR/field_uniqueness_check.rs:291:9 + | +LL | _: Bar, + | ^^^^^^ error: aborting due to 85 previous errors diff --git a/tests/ui/union/unnamed-fields/repr_check.stderr b/tests/ui/union/unnamed-fields/repr_check.stderr index ca6a1f3a780..324968b1264 100644 --- a/tests/ui/union/unnamed-fields/repr_check.stderr +++ b/tests/ui/union/unnamed-fields/repr_check.stderr @@ -20,6 +20,11 @@ LL | | b: i32, LL | | }, LL | | }, | |_____^ +help: add `#[repr(C)]` to this struct + | +LL + #[repr(C)] +LL | struct A { + | error: union with unnamed fields must have `#[repr(C)]` representation --> $DIR/repr_check.rs:16:1 @@ -43,6 +48,11 @@ LL | | b: i32, LL | | }, LL | | }, | |_____^ +help: add `#[repr(C)]` to this union + | +LL + #[repr(C)] +LL | union B { + | error: struct with unnamed fields must have `#[repr(C)]` representation --> $DIR/repr_check.rs:39:1 @@ -55,6 +65,11 @@ note: unnamed field defined here | LL | _: Foo, | ^^^^^^ +help: add `#[repr(C)]` to this struct + | +LL + #[repr(C)] +LL | struct C { + | error: union with unnamed fields must have `#[repr(C)]` representation --> $DIR/repr_check.rs:44:1 @@ -67,6 +82,11 @@ note: unnamed field defined here | LL | _: Foo, | ^^^^^^ +help: add `#[repr(C)]` to this union + | +LL + #[repr(C)] +LL | union D { + | error: named type of unnamed field must have `#[repr(C)]` representation --> $DIR/repr_check.rs:51:5 @@ -76,6 +96,12 @@ LL | struct Bar {} ... LL | _: Bar, | ^^^^^^ unnamed field defined here + | +help: add `#[repr(C)]` to this struct + | +LL + #[repr(C)] +LL | struct Bar {} + | error: named type of unnamed field must have `#[repr(C)]` representation --> $DIR/repr_check.rs:54:9 @@ -85,6 +111,12 @@ LL | struct Bar {} ... LL | _: Bar, | ^^^^^^ unnamed field defined here + | +help: add `#[repr(C)]` to this struct + | +LL + #[repr(C)] +LL | struct Bar {} + | error: named type of unnamed field must have `#[repr(C)]` representation --> $DIR/repr_check.rs:61:5 @@ -94,6 +126,12 @@ LL | struct Bar {} ... LL | _: Bar, | ^^^^^^ unnamed field defined here + | +help: add `#[repr(C)]` to this struct + | +LL + #[repr(C)] +LL | struct Bar {} + | error: named type of unnamed field must have `#[repr(C)]` representation --> $DIR/repr_check.rs:64:9 @@ -103,6 +141,12 @@ LL | struct Bar {} ... LL | _: Bar, | ^^^^^^ unnamed field defined here + | +help: add `#[repr(C)]` to this struct + | +LL + #[repr(C)] +LL | struct Bar {} + | error: aborting due to 8 previous errors From fc7693d63b2f3736b7d847c8c3d9c7219c4bea4a Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 12 Feb 2024 04:51:21 +0000 Subject: [PATCH 32/56] Clean inlined type alias with correct param-env --- src/librustdoc/clean/mod.rs | 4 +++- .../rustdoc-ui/normalize-in-inlined-type-alias.rs | 14 ++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) create mode 100644 tests/rustdoc-ui/normalize-in-inlined-type-alias.rs diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 89977934cde..abd0b3562d2 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1840,7 +1840,9 @@ fn maybe_expand_private_type_alias<'tcx>( } } - Some(cx.enter_alias(args, def_id.to_def_id(), |cx| clean_ty(&ty, cx))) + Some(cx.enter_alias(args, def_id.to_def_id(), |cx| { + cx.with_param_env(def_id.to_def_id(), |cx| clean_ty(&ty, cx)) + })) } pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> Type { diff --git a/tests/rustdoc-ui/normalize-in-inlined-type-alias.rs b/tests/rustdoc-ui/normalize-in-inlined-type-alias.rs new file mode 100644 index 00000000000..45e04a70c09 --- /dev/null +++ b/tests/rustdoc-ui/normalize-in-inlined-type-alias.rs @@ -0,0 +1,14 @@ +// check-pass +// compile-flags: -Znormalize-docs + +trait Woo { + type Assoc; +} + +impl Woo for () { + type Assoc = (); +} + +type Alias

= <() as Woo

>::Assoc; + +pub fn hello() -> Alias {} From 3856df059ed90b8fd19a82efbfb9da36f68e6bb9 Mon Sep 17 00:00:00 2001 From: Shoyu Vanilla Date: Mon, 12 Feb 2024 15:39:32 +0900 Subject: [PATCH 33/56] Dejargnonize subst --- .../src/diagnostics/conflict_errors.rs | 2 +- .../src/region_infer/opaque_types.rs | 24 ++--- .../src/interpret/eval_context.rs | 15 +-- .../rustc_const_eval/src/interpret/operand.rs | 12 ++- .../rustc_const_eval/src/interpret/place.rs | 7 +- .../rustc_const_eval/src/interpret/step.rs | 4 +- .../src/interpret/terminator.rs | 6 +- .../rustc_const_eval/src/interpret/util.rs | 14 +-- .../src/error_codes/E0139.md | 8 +- .../src/error_codes/E0230.md | 6 +- .../src/error_codes/E0231.md | 6 +- .../src/error_codes/E0393.md | 4 +- .../src/error_codes/E0794.md | 4 +- compiler/rustc_hir/src/hir.rs | 2 +- compiler/rustc_hir_analysis/messages.ftl | 4 +- .../rustc_hir_analysis/src/astconv/bounds.rs | 13 +-- .../src/astconv/generics.rs | 8 +- .../rustc_hir_analysis/src/astconv/mod.rs | 18 ++-- .../src/astconv/object_safety.rs | 2 +- .../rustc_hir_analysis/src/check/check.rs | 6 +- .../src/check/compare_impl_item.rs | 18 ++-- .../rustc_hir_analysis/src/check/dropck.rs | 4 +- compiler/rustc_hir_analysis/src/check/mod.rs | 2 +- .../rustc_hir_analysis/src/check/wfcheck.rs | 42 +++++---- .../src/coherence/builtin.rs | 2 +- .../src/collect/generics_of.rs | 2 +- .../src/collect/resolve_bound_vars.rs | 3 +- .../src/constrained_generic_params.rs | 2 +- compiler/rustc_hir_analysis/src/errors.rs | 4 +- .../src/impl_wf_check/min_specialization.rs | 14 +-- .../src/outlives/implicit_infer.rs | 6 +- .../rustc_hir_analysis/src/variance/mod.rs | 8 +- compiler/rustc_hir_typeck/src/check.rs | 2 +- compiler/rustc_hir_typeck/src/coercion.rs | 2 +- compiler/rustc_hir_typeck/src/expr.rs | 2 +- .../rustc_hir_typeck/src/fn_ctxt/_impl.rs | 30 +++--- .../src/fn_ctxt/adjust_fulfillment_errors.rs | 8 +- .../src/fn_ctxt/suggestions.rs | 14 +-- .../rustc_hir_typeck/src/method/confirm.rs | 32 ++++--- compiler/rustc_hir_typeck/src/method/mod.rs | 4 +- compiler/rustc_hir_typeck/src/method/probe.rs | 12 +-- compiler/rustc_hir_typeck/src/place_op.rs | 2 +- compiler/rustc_hir_typeck/src/writeback.rs | 4 +- .../{substitute.rs => instantiate.rs} | 22 ++--- .../rustc_infer/src/infer/canonical/mod.rs | 14 +-- .../src/infer/canonical/query_response.rs | 91 ++++++++++--------- compiler/rustc_infer/src/infer/mod.rs | 24 ++--- .../rustc_infer/src/infer/opaque_types.rs | 2 +- .../src/infer/outlives/test_type_match.rs | 4 +- .../rustc_infer/src/infer/outlives/verify.rs | 2 +- .../src/infer/relate/generalize.rs | 10 +- .../rustc_infer/src/infer/type_variable.rs | 2 +- compiler/rustc_infer/src/traits/util.rs | 3 +- compiler/rustc_middle/src/infer/canonical.rs | 2 +- .../rustc_middle/src/mir/interpret/queries.rs | 18 ++-- compiler/rustc_middle/src/mir/mono.rs | 2 +- compiler/rustc_middle/src/query/mod.rs | 4 +- compiler/rustc_middle/src/traits/mod.rs | 2 +- compiler/rustc_middle/src/traits/select.rs | 3 +- compiler/rustc_middle/src/traits/util.rs | 2 +- compiler/rustc_middle/src/ty/_match.rs | 2 +- compiler/rustc_middle/src/ty/consts.rs | 2 +- compiler/rustc_middle/src/ty/fold.rs | 4 +- compiler/rustc_middle/src/ty/generic_args.rs | 26 +++--- compiler/rustc_middle/src/ty/generics.rs | 4 +- compiler/rustc_middle/src/ty/instance.rs | 16 ++-- compiler/rustc_middle/src/ty/mod.rs | 4 +- .../src/ty/normalize_erasing_regions.rs | 12 +-- compiler/rustc_middle/src/ty/opaque_types.rs | 8 +- compiler/rustc_middle/src/ty/predicate.rs | 30 +++--- compiler/rustc_middle/src/ty/sty.rs | 30 +++--- .../rustc_middle/src/ty/typeck_results.rs | 22 ++--- compiler/rustc_mir_build/src/thir/cx/expr.rs | 4 +- compiler/rustc_mir_build/src/thir/util.rs | 2 +- compiler/rustc_mir_transform/src/add_retag.rs | 4 +- .../src/deduce_param_attrs.rs | 4 +- .../src/function_item_references.rs | 8 +- compiler/rustc_mir_transform/src/gvn.rs | 16 ++-- .../rustc_mir_transform/src/inline/cycle.rs | 4 +- .../rustc_mir_transform/src/instsimplify.rs | 2 +- compiler/rustc_mir_transform/src/lib.rs | 8 +- compiler/rustc_mir_transform/src/ref_prop.rs | 8 +- compiler/rustc_mir_transform/src/shim.rs | 6 +- compiler/rustc_mir_transform/src/ssa.rs | 2 +- compiler/rustc_monomorphize/src/collector.rs | 8 +- .../rustc_monomorphize/src/polymorphize.rs | 2 +- compiler/rustc_passes/src/dead.rs | 4 +- compiler/rustc_pattern_analysis/src/rustc.rs | 2 +- compiler/rustc_privacy/src/lib.rs | 6 +- compiler/rustc_smir/src/rustc_smir/context.rs | 2 +- compiler/rustc_symbol_mangling/src/legacy.rs | 2 +- compiler/rustc_symbol_mangling/src/v0.rs | 4 +- .../src/solve/assembly/structural_traits.rs | 2 +- .../src/solve/eval_ctxt/canonical.rs | 19 ++-- .../src/solve/eval_ctxt/select.rs | 6 +- .../src/solve/normalizes_to/inherent.rs | 12 +-- .../src/solve/trait_goals.rs | 6 +- .../src/traits/coherence.rs | 18 ++-- .../traits/error_reporting/infer_ctxt_ext.rs | 2 +- .../error_reporting/on_unimplemented.rs | 2 +- .../src/traits/error_reporting/suggestions.rs | 4 +- .../error_reporting/type_err_ctxt_ext.rs | 30 +++--- .../rustc_trait_selection/src/traits/mod.rs | 8 +- .../src/traits/object_safety.rs | 6 +- .../src/traits/project.rs | 6 +- .../traits/query/type_op/ascribe_user_type.rs | 2 +- .../query/type_op/implied_outlives_bounds.rs | 2 +- .../src/traits/select/candidate_assembly.rs | 2 +- .../src/traits/select/confirmation.rs | 6 +- .../src/traits/select/mod.rs | 6 +- .../src/traits/specialize/mod.rs | 24 ++--- .../rustc_trait_selection/src/traits/util.rs | 2 +- .../src/traits/vtable.rs | 2 +- .../rustc_trait_selection/src/traits/wf.rs | 2 +- .../src/normalize_projection_ty.rs | 2 +- compiler/rustc_ty_utils/src/abi.rs | 4 +- compiler/rustc_ty_utils/src/layout.rs | 6 +- compiler/rustc_ty_utils/src/needs_drop.rs | 11 ++- compiler/rustc_ty_utils/src/opaque_types.rs | 14 +-- .../rustc_ty_utils/src/representability.rs | 8 +- compiler/rustc_type_ir/src/flags.rs | 2 +- compiler/rustc_type_ir/src/region_kind.rs | 10 +- compiler/rustc_type_ir/src/ty_kind.rs | 6 +- compiler/stable_mir/src/compiler_interface.rs | 2 +- compiler/stable_mir/src/mir/mono.rs | 2 +- src/librustdoc/clean/mod.rs | 14 ++- src/librustdoc/clean/types.rs | 6 +- src/librustdoc/core.rs | 10 +- 128 files changed, 574 insertions(+), 541 deletions(-) rename compiler/rustc_infer/src/infer/canonical/{substitute.rs => instantiate.rs} (80%) diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 44e4dea3481..8b9b4e926ef 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -691,7 +691,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { // If the type is opaque/param/closure, and it is Fn or FnMut, let's suggest (mutably) // borrowing the type, since `&mut F: FnMut` iff `F: FnMut` and similarly for `Fn`. - // These types seem reasonably opaque enough that they could be substituted with their + // These types seem reasonably opaque enough that they could be instantiated with their // borrowed variants in a function body when we see a move error. let borrow_level = match *ty.kind() { ty::Param(_) => tcx diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs index 636c174e002..cd2fe56ca49 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs @@ -45,7 +45,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// be allowed: /// `fn f<'a: 'b, 'b: 'a>(x: *mut &'b i32) -> impl Sized + 'a { x }` /// - /// Then we map the regions in both the type and the subst to their + /// Then we map the regions in both the type and the generic parameters to their /// `external_name` giving `concrete_type = &'a i32`, /// `args = ['static, 'a]`. This will then allow /// `infer_opaque_definition_from_instantiation` to determine that @@ -77,9 +77,9 @@ impl<'tcx> RegionInferenceContext<'tcx> { let args = opaque_type_key.args; debug!(?concrete_type, ?args); - let mut subst_regions = vec![self.universal_regions.fr_static]; + let mut arg_regions = vec![self.universal_regions.fr_static]; - let to_universal_region = |vid, subst_regions: &mut Vec<_>| { + let to_universal_region = |vid, arg_regions: &mut Vec<_>| { trace!(?vid); let scc = self.constraint_sccs.scc(vid); trace!(?scc); @@ -88,11 +88,11 @@ impl<'tcx> RegionInferenceContext<'tcx> { }) { Some(region) => { let vid = self.universal_regions.to_region_vid(region); - subst_regions.push(vid); + arg_regions.push(vid); region } None => { - subst_regions.push(vid); + arg_regions.push(vid); ty::Region::new_error_with_message( infcx.tcx, concrete_type.span, @@ -106,10 +106,10 @@ impl<'tcx> RegionInferenceContext<'tcx> { // This will ensure they get precedence when folding the regions in the concrete type. if let Some(&ci) = member_constraints.get(&opaque_type_key) { for &vid in self.member_constraints.choice_regions(ci) { - to_universal_region(vid, &mut subst_regions); + to_universal_region(vid, &mut arg_regions); } } - debug!(?subst_regions); + debug!(?arg_regions); // Next, insert universal regions from args, so we can translate regions that appear // in them but are not subject to member constraints, for instance closure args. @@ -119,18 +119,18 @@ impl<'tcx> RegionInferenceContext<'tcx> { return region; } let vid = self.to_region_vid(region); - to_universal_region(vid, &mut subst_regions) + to_universal_region(vid, &mut arg_regions) }); debug!(?universal_args); - debug!(?subst_regions); + debug!(?arg_regions); // Deduplicate the set of regions while keeping the chosen order. - let subst_regions = subst_regions.into_iter().collect::>(); - debug!(?subst_regions); + let arg_regions = arg_regions.into_iter().collect::>(); + debug!(?arg_regions); let universal_concrete_type = infcx.tcx.fold_regions(concrete_type, |region, _| match *region { - ty::ReVar(vid) => subst_regions + ty::ReVar(vid) => arg_regions .iter() .find(|ur_vid| self.eval_equal(vid, **ur_vid)) .and_then(|ur_vid| self.definitions[*ur_vid].external_name) diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs index dd9dfe3fe79..ffab8f5e555 100644 --- a/compiler/rustc_const_eval/src/interpret/eval_context.rs +++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs @@ -554,18 +554,20 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { /// Call this on things you got out of the MIR (so it is as generic as the current /// stack frame), to bring it into the proper environment for this interpreter. - pub(super) fn subst_from_current_frame_and_normalize_erasing_regions< + pub(super) fn instantiate_from_current_frame_and_normalize_erasing_regions< T: TypeFoldable>, >( &self, value: T, ) -> Result { - self.subst_from_frame_and_normalize_erasing_regions(self.frame(), value) + self.instantiate_from_frame_and_normalize_erasing_regions(self.frame(), value) } /// Call this on things you got out of the MIR (so it is as generic as the provided /// stack frame), to bring it into the proper environment for this interpreter. - pub(super) fn subst_from_frame_and_normalize_erasing_regions>>( + pub(super) fn instantiate_from_frame_and_normalize_erasing_regions< + T: TypeFoldable>, + >( &self, frame: &Frame<'mir, 'tcx, M::Provenance, M::FrameExtra>, value: T, @@ -656,7 +658,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let layout = from_known_layout(self.tcx, self.param_env, layout, || { let local_ty = frame.body.local_decls[local].ty; - let local_ty = self.subst_from_frame_and_normalize_erasing_regions(frame, local_ty)?; + let local_ty = + self.instantiate_from_frame_and_normalize_erasing_regions(frame, local_ty)?; self.layout_of(local_ty) })?; @@ -791,8 +794,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // Make sure all the constants required by this frame evaluate successfully (post-monomorphization check). if M::POST_MONO_CHECKS { for &const_ in &body.required_consts { - let c = - self.subst_from_current_frame_and_normalize_erasing_regions(const_.const_)?; + let c = self + .instantiate_from_current_frame_and_normalize_erasing_regions(const_.const_)?; c.eval(*self.tcx, self.param_env, Some(const_.span)).map_err(|err| { err.emit_note(*self.tcx); err diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs index 4653c9016c6..317e5673b51 100644 --- a/compiler/rustc_const_eval/src/interpret/operand.rs +++ b/compiler/rustc_const_eval/src/interpret/operand.rs @@ -696,9 +696,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { trace!("eval_place_to_op: got {:?}", op); // Sanity-check the type we ended up with. if cfg!(debug_assertions) { - let normalized_place_ty = self.subst_from_current_frame_and_normalize_erasing_regions( - mir_place.ty(&self.frame().body.local_decls, *self.tcx).ty, - )?; + let normalized_place_ty = self + .instantiate_from_current_frame_and_normalize_erasing_regions( + mir_place.ty(&self.frame().body.local_decls, *self.tcx).ty, + )?; if !mir_assign_valid_types( *self.tcx, self.param_env, @@ -731,8 +732,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { &Copy(place) | &Move(place) => self.eval_place_to_op(place, layout)?, Constant(constant) => { - let c = - self.subst_from_current_frame_and_normalize_erasing_regions(constant.const_)?; + let c = self.instantiate_from_current_frame_and_normalize_erasing_regions( + constant.const_, + )?; // This can still fail: // * During ConstProp, with `TooGeneric` or since the `required_consts` were not all diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs index 772445f4f62..03d1dc9fd3d 100644 --- a/compiler/rustc_const_eval/src/interpret/place.rs +++ b/compiler/rustc_const_eval/src/interpret/place.rs @@ -542,9 +542,10 @@ where trace!("{:?}", self.dump_place(&place)); // Sanity-check the type we ended up with. if cfg!(debug_assertions) { - let normalized_place_ty = self.subst_from_current_frame_and_normalize_erasing_regions( - mir_place.ty(&self.frame().body.local_decls, *self.tcx).ty, - )?; + let normalized_place_ty = self + .instantiate_from_current_frame_and_normalize_erasing_regions( + mir_place.ty(&self.frame().body.local_decls, *self.tcx).ty, + )?; if !mir_assign_valid_types( *self.tcx, self.param_env, diff --git a/compiler/rustc_const_eval/src/interpret/step.rs b/compiler/rustc_const_eval/src/interpret/step.rs index f0f1008aba8..23f3d7eb67d 100644 --- a/compiler/rustc_const_eval/src/interpret/step.rs +++ b/compiler/rustc_const_eval/src/interpret/step.rs @@ -235,7 +235,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } NullaryOp(ref null_op, ty) => { - let ty = self.subst_from_current_frame_and_normalize_erasing_regions(ty)?; + let ty = self.instantiate_from_current_frame_and_normalize_erasing_regions(ty)?; let layout = self.layout_of(ty)?; if let mir::NullOp::SizeOf | mir::NullOp::AlignOf = null_op && layout.is_unsized() @@ -276,7 +276,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Cast(cast_kind, ref operand, cast_ty) => { let src = self.eval_operand(operand, None)?; let cast_ty = - self.subst_from_current_frame_and_normalize_erasing_regions(cast_ty)?; + self.instantiate_from_current_frame_and_normalize_erasing_regions(cast_ty)?; self.cast(&src, cast_kind, cast_ty, &dest)?; } diff --git a/compiler/rustc_const_eval/src/interpret/terminator.rs b/compiler/rustc_const_eval/src/interpret/terminator.rs index ff20fc5092c..4037220e5ed 100644 --- a/compiler/rustc_const_eval/src/interpret/terminator.rs +++ b/compiler/rustc_const_eval/src/interpret/terminator.rs @@ -173,7 +173,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Drop { place, target, unwind, replace: _ } => { let frame = self.frame(); let ty = place.ty(&frame.body.local_decls, *self.tcx).ty; - let ty = self.subst_from_frame_and_normalize_erasing_regions(frame, ty)?; + let ty = self.instantiate_from_frame_and_normalize_erasing_regions(frame, ty)?; let instance = Instance::resolve_drop_in_place(*self.tcx, ty); if let ty::InstanceDef::DropGlue(_, None) = instance.def { // This is the branch we enter if and only if the dropped type has no drop glue @@ -672,8 +672,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // Construct the destination place for this argument. At this point all // locals are still dead, so we cannot construct a `PlaceTy`. let dest = mir::Place::from(local); - // `layout_of_local` does more than just the substitution we need to get the - // type, but the result gets cached so this avoids calling the substitution + // `layout_of_local` does more than just the instantiation we need to get the + // type, but the result gets cached so this avoids calling the instantiation // query *again* the next time this local is accessed. let ty = self.layout_of_local(self.frame(), local, None)?.ty; if Some(local) == body.spread_arg { diff --git a/compiler/rustc_const_eval/src/interpret/util.rs b/compiler/rustc_const_eval/src/interpret/util.rs index 416443f5f4d..d15dd1bee19 100644 --- a/compiler/rustc_const_eval/src/interpret/util.rs +++ b/compiler/rustc_const_eval/src/interpret/util.rs @@ -19,11 +19,11 @@ where } struct FoundParam; - struct UsedParamsNeedSubstVisitor<'tcx> { + struct UsedParamsNeedInstantiationVisitor<'tcx> { tcx: TyCtxt<'tcx>, } - impl<'tcx> TypeVisitor> for UsedParamsNeedSubstVisitor<'tcx> { + impl<'tcx> TypeVisitor> for UsedParamsNeedInstantiationVisitor<'tcx> { type BreakTy = FoundParam; fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow { @@ -38,17 +38,17 @@ where | ty::FnDef(def_id, args) => { let instance = ty::InstanceDef::Item(def_id); let unused_params = self.tcx.unused_generic_params(instance); - for (index, subst) in args.into_iter().enumerate() { + for (index, arg) in args.into_iter().enumerate() { let index = index .try_into() .expect("more generic parameters than can fit into a `u32`"); // Only recurse when generic parameters in fns, closures and coroutines // are used and have to be instantiated. // - // Just in case there are closures or coroutines within this subst, + // Just in case there are closures or coroutines within this arg, // recurse. - if unused_params.is_used(index) && subst.has_param() { - return subst.visit_with(self); + if unused_params.is_used(index) && arg.has_param() { + return arg.visit_with(self); } } ControlFlow::Continue(()) @@ -65,7 +65,7 @@ where } } - let mut vis = UsedParamsNeedSubstVisitor { tcx }; + let mut vis = UsedParamsNeedInstantiationVisitor { tcx }; if matches!(ty.visit_with(&mut vis), ControlFlow::Break(FoundParam)) { throw_inval!(TooGeneric); } else { diff --git a/compiler/rustc_error_codes/src/error_codes/E0139.md b/compiler/rustc_error_codes/src/error_codes/E0139.md index a116cf29395..4f7f65689c6 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0139.md +++ b/compiler/rustc_error_codes/src/error_codes/E0139.md @@ -22,9 +22,9 @@ fn foo(x: Vec) { In this specific case there's a good chance that the transmute is harmless (but this is not guaranteed by Rust). However, when alignment and enum optimizations come into the picture, it's quite likely that the sizes may or may not match -with different type parameter substitutions. It's not possible to check this for -_all_ possible types, so `transmute()` simply only accepts types without any -unsubstituted type parameters. +with different type parameter instantiations. It's not possible to check this +for _all_ possible types, so `transmute()` simply only accepts types without any +uninstantiated type parameters. If you need this, there's a good chance you're doing something wrong. Keep in mind that Rust doesn't guarantee much about the layout of different structs @@ -32,7 +32,7 @@ mind that Rust doesn't guarantee much about the layout of different structs there is a solution that avoids the transmute entirely, try it instead. If it's possible, hand-monomorphize the code by writing the function for each -possible type substitution. It's possible to use traits to do this cleanly, +possible type instantiation. It's possible to use traits to do this cleanly, for example: ``` diff --git a/compiler/rustc_error_codes/src/error_codes/E0230.md b/compiler/rustc_error_codes/src/error_codes/E0230.md index 87ea90e73c9..c30a7e38e9c 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0230.md +++ b/compiler/rustc_error_codes/src/error_codes/E0230.md @@ -15,9 +15,9 @@ There will be an error about `bool` not implementing `Index`, followed by a note saying "the type `bool` cannot be indexed by `u8`". As you can see, you can specify type parameters in curly braces for -substitution with the actual types (using the regular format string syntax) in -a given situation. Furthermore, `{Self}` will substitute to the type (in this -case, `bool`) that we tried to use. +instantiation with the actual types (using the regular format string syntax) in +a given situation. Furthermore, `{Self}` will be instantiated to the type (in +this case, `bool`) that we tried to use. This error appears when the curly braces contain an identifier which doesn't match with any of the type parameters or the string `Self`. This might happen diff --git a/compiler/rustc_error_codes/src/error_codes/E0231.md b/compiler/rustc_error_codes/src/error_codes/E0231.md index a1aaf90df49..b22e3c7082a 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0231.md +++ b/compiler/rustc_error_codes/src/error_codes/E0231.md @@ -15,9 +15,9 @@ there will be an error about `bool` not implementing `Index`, followed by a note saying "the type `bool` cannot be indexed by `u8`". As you can see, you can specify type parameters in curly braces for -substitution with the actual types (using the regular format string syntax) in -a given situation. Furthermore, `{Self}` will substitute to the type (in this -case, `bool`) that we tried to use. +instantiation with the actual types (using the regular format string syntax) in +a given situation. Furthermore, `{Self}` will be instantiated to the type (in +this case, `bool`) that we tried to use. This error appears when the curly braces do not contain an identifier. Please add one of the same name as a type parameter. If you intended to use literal diff --git a/compiler/rustc_error_codes/src/error_codes/E0393.md b/compiler/rustc_error_codes/src/error_codes/E0393.md index 3e853cf1b8a..50225b25163 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0393.md +++ b/compiler/rustc_error_codes/src/error_codes/E0393.md @@ -12,12 +12,12 @@ fn together_we_will_rule_the_galaxy(son: &A) {} ``` A trait object is defined over a single, fully-defined trait. With a regular -default parameter, this parameter can just be substituted in. However, if the +default parameter, this parameter can just be instantiated in. However, if the default parameter is `Self`, the trait changes for each concrete type; i.e. `i32` will be expected to implement `A`, `bool` will be expected to implement `A`, etc... These types will not share an implementation of a fully-defined trait; instead they share implementations of a trait with -different parameters substituted in for each implementation. This is +different parameters instantiated in for each implementation. This is irreconcilable with what we need to make a trait object work, and is thus disallowed. Making the trait concrete by explicitly specifying the value of the defaulted parameter will fix this issue. Fixed example: diff --git a/compiler/rustc_error_codes/src/error_codes/E0794.md b/compiler/rustc_error_codes/src/error_codes/E0794.md index c8f73de95a2..dcbe2b97c85 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0794.md +++ b/compiler/rustc_error_codes/src/error_codes/E0794.md @@ -14,7 +14,7 @@ let _ = foo::<'static>; The type of a concrete instance of a generic function is universally quantified over late-bound lifetime parameters. This is because we want the function to -work for any lifetime substituted for the late-bound lifetime parameter, no +work for any lifetime instantiated for the late-bound lifetime parameter, no matter where the function is called. Consequently, it doesn't make sense to specify arguments for late-bound lifetime parameters, since they are not resolved until the function's call site(s). @@ -56,7 +56,7 @@ let bar_fn3 = bar::; // OK In the definition of `bar`, the lifetime parameter `'a` is late-bound, while `'b` is early-bound. This is reflected in the type annotation for `bar_fn`, -where `'a` is universally quantified and `'b` is substituted by a specific +where `'a` is universally quantified and `'b` is instantiated with a specific lifetime. It is not allowed to explicitly specify early-bound lifetime arguments when late-bound lifetime parameters are present (as for `bar_fn2`, see [issue #42868](https://github.com/rust-lang/rust/issues/42868)), although diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index a7a1c69b9be..85d30112514 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -2536,7 +2536,7 @@ pub struct OpaqueTy<'hir> { /// lifetimes that are captured from the function signature they originate from. /// /// This is done by generating a new early-bound lifetime parameter local to the - /// opaque which is substituted in the function signature with the late-bound + /// opaque which is instantiated in the function signature with the late-bound /// lifetime. /// /// This mapping associated a captured lifetime (first parameter) with the new diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl index d6f604c180b..4e96393bb9b 100644 --- a/compiler/rustc_hir_analysis/messages.ftl +++ b/compiler/rustc_hir_analysis/messages.ftl @@ -131,6 +131,8 @@ hir_analysis_function_not_have_default_implementation = function doesn't have a hir_analysis_functions_names_duplicated = functions names are duplicated .note = all `#[rustc_must_implement_one_of]` arguments must be unique +hir_analysis_generic_args_on_overridden_impl = could not resolve generic parameters on overridden impl + hir_analysis_impl_not_marked_default = `{$ident}` specializes an item from a parent `impl`, but that item is not marked `default` .label = cannot specialize default item `{$ident}` .ok_label = parent `impl` is here @@ -365,8 +367,6 @@ hir_analysis_static_mut_ref_lint = {$shared}reference of mutable static is disco hir_analysis_static_specialize = cannot specialize on `'static` lifetime -hir_analysis_substs_on_overridden_impl = could not resolve substs on overridden impl - hir_analysis_tait_forward_compat = item constrains opaque type that is not in its signature .note = this item must mention the opaque type in its signature in order to be able to register hidden types diff --git a/compiler/rustc_hir_analysis/src/astconv/bounds.rs b/compiler/rustc_hir_analysis/src/astconv/bounds.rs index 1ae267d1a40..7157382c883 100644 --- a/compiler/rustc_hir_analysis/src/astconv/bounds.rs +++ b/compiler/rustc_hir_analysis/src/astconv/bounds.rs @@ -336,12 +336,12 @@ impl<'tcx> dyn AstConv<'tcx> + '_ { let projection_ty = if let ty::AssocKind::Fn = assoc_kind { let mut emitted_bad_param_err = None; - // If we have an method return type bound, then we need to substitute + // If we have an method return type bound, then we need to instantiate // the method's early bound params with suitable late-bound params. let mut num_bound_vars = candidate.bound_vars().len(); let args = candidate.skip_binder().args.extend_to(tcx, assoc_item.def_id, |param, _| { - let subst = match param.kind { + let arg = match param.kind { ty::GenericParamDefKind::Lifetime => ty::Region::new_bound( tcx, ty::INNERMOST, @@ -379,7 +379,7 @@ impl<'tcx> dyn AstConv<'tcx> + '_ { } }; num_bound_vars += 1; - subst + arg }); // Next, we need to check that the return-type notation is being used on @@ -402,12 +402,13 @@ impl<'tcx> dyn AstConv<'tcx> + '_ { // Finally, move the fn return type's bound vars over to account for the early bound // params (and trait ref's late bound params). This logic is very similar to - // `Predicate::subst_supertrait`, and it's no coincidence why. + // `rustc_middle::ty::predicate::Clause::instantiate_supertrait` + // and it's no coincidence why. let shifted_output = tcx.shift_bound_var_indices(num_bound_vars, output); - let subst_output = ty::EarlyBinder::bind(shifted_output).instantiate(tcx, args); + let instantiation_output = ty::EarlyBinder::bind(shifted_output).instantiate(tcx, args); let bound_vars = tcx.late_bound_vars(binding.hir_id); - ty::Binder::bind_with_vars(subst_output, bound_vars) + ty::Binder::bind_with_vars(instantiation_output, bound_vars) } else { // Append the generic arguments of the associated type to the `trait_ref`. candidate.map_bound(|trait_ref| { diff --git a/compiler/rustc_hir_analysis/src/astconv/generics.rs b/compiler/rustc_hir_analysis/src/astconv/generics.rs index aa826c1f268..614e5f9d32b 100644 --- a/compiler/rustc_hir_analysis/src/astconv/generics.rs +++ b/compiler/rustc_hir_analysis/src/astconv/generics.rs @@ -1,6 +1,6 @@ use super::IsMethodCall; use crate::astconv::{ - errors::prohibit_assoc_ty_binding, CreateSubstsForGenericArgsCtxt, ExplicitLateBound, + errors::prohibit_assoc_ty_binding, CreateInstantiationsForGenericArgsCtxt, ExplicitLateBound, GenericArgCountMismatch, GenericArgCountResult, GenericArgPosition, }; use crate::structured_errors::{GenericArgsInfo, StructuredDiagnostic, WrongNumberOfGenericArgs}; @@ -177,9 +177,9 @@ pub fn create_args_for_parent_generic_args<'tcx: 'a, 'a>( has_self: bool, self_ty: Option>, arg_count: &GenericArgCountResult, - ctx: &mut impl CreateSubstsForGenericArgsCtxt<'a, 'tcx>, + ctx: &mut impl CreateInstantiationsForGenericArgsCtxt<'a, 'tcx>, ) -> GenericArgsRef<'tcx> { - // Collect the segments of the path; we need to substitute arguments + // Collect the segments of the path; we need to instantiate arguments // for parameters throughout the entire path (wherever there are // generic parameters). let mut parent_defs = tcx.generics_of(def_id); @@ -191,7 +191,7 @@ pub fn create_args_for_parent_generic_args<'tcx: 'a, 'a>( } // We manually build up the generic arguments, rather than using convenience - // methods in `subst.rs`, so that we can iterate over the arguments and + // methods in `rustc_middle/src/ty/generic_args.rs`, so that we can iterate over the arguments and // parameters in lock-step linearly, instead of trying to match each pair. let mut args: SmallVec<[ty::GenericArg<'tcx>; 8]> = SmallVec::with_capacity(count); // Iterate over each segment of the path. diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs index 1ae3ebaebbb..6b6be2b3d53 100644 --- a/compiler/rustc_hir_analysis/src/astconv/mod.rs +++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs @@ -214,7 +214,7 @@ pub struct GenericArgCountResult { pub correct: Result<(), GenericArgCountMismatch>, } -pub trait CreateSubstsForGenericArgsCtxt<'a, 'tcx> { +pub trait CreateInstantiationsForGenericArgsCtxt<'a, 'tcx> { fn args_for_def_id(&mut self, def_id: DefId) -> (Option<&'a GenericArgs<'tcx>>, bool); fn provided_kind( @@ -366,8 +366,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { if generics.has_self { if generics.parent.is_some() { - // The parent is a trait so it should have at least one subst - // for the `Self` type. + // The parent is a trait so it should have at least one + // generic parameter for the `Self` type. assert!(!parent_args.is_empty()) } else { // This item (presumably a trait) needs a self-type. @@ -402,7 +402,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { return (tcx.mk_args(parent_args), arg_count); } - struct SubstsForAstPathCtxt<'a, 'tcx> { + struct InstantiationsForAstPathCtxt<'a, 'tcx> { astconv: &'a (dyn AstConv<'tcx> + 'a), def_id: DefId, generic_args: &'a GenericArgs<'tcx>, @@ -411,7 +411,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { infer_args: bool, } - impl<'a, 'tcx> CreateSubstsForGenericArgsCtxt<'a, 'tcx> for SubstsForAstPathCtxt<'a, 'tcx> { + impl<'a, 'tcx> CreateInstantiationsForGenericArgsCtxt<'a, 'tcx> + for InstantiationsForAstPathCtxt<'a, 'tcx> + { fn args_for_def_id(&mut self, did: DefId) -> (Option<&'a GenericArgs<'tcx>>, bool) { if did == self.def_id { (Some(self.generic_args), self.infer_args) @@ -556,7 +558,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { } } - let mut args_ctx = SubstsForAstPathCtxt { + let mut args_ctx = InstantiationsForAstPathCtxt { astconv: self, def_id, span, @@ -2412,8 +2414,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let self_ty = self.tcx().type_of(parent).instantiate_identity(); let generic_self_ty = ty::GenericArg::from(self_ty); - let substs = self.tcx().mk_args_from_iter(std::iter::once(generic_self_ty)); - sig.instantiate(self.tcx(), substs) + let args = self.tcx().mk_args_from_iter(std::iter::once(generic_self_ty)); + sig.instantiate(self.tcx(), args) } else { sig.instantiate_identity() }; diff --git a/compiler/rustc_hir_analysis/src/astconv/object_safety.rs b/compiler/rustc_hir_analysis/src/astconv/object_safety.rs index 2d85ad5789e..cbbf560076e 100644 --- a/compiler/rustc_hir_analysis/src/astconv/object_safety.rs +++ b/compiler/rustc_hir_analysis/src/astconv/object_safety.rs @@ -175,7 +175,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { } ty::PredicateKind::Clause(ty::ClauseKind::Projection(pred)) => { let pred = bound_predicate.rebind(pred); - // A `Self` within the original bound will be substituted with a + // A `Self` within the original bound will be instantiated with a // `trait_object_dummy_self`, so check for that. let references_self = match pred.skip_binder().term.unpack() { ty::TermKind::Ty(ty) => ty.walk().any(|arg| arg == dummy_self.into()), diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 7250dc81faf..ae0f27a6f55 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -1030,7 +1030,7 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>) match t.kind() { ty::Tuple(list) => list.iter().try_for_each(|t| check_non_exhaustive(tcx, t)), ty::Array(ty, _) => check_non_exhaustive(tcx, *ty), - ty::Adt(def, subst) => { + ty::Adt(def, args) => { if !def.did().is_local() { let non_exhaustive = def.is_variant_list_non_exhaustive() || def @@ -1042,13 +1042,13 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>) return ControlFlow::Break(( def.descr(), def.did(), - subst, + args, non_exhaustive, )); } } def.all_fields() - .map(|field| field.ty(tcx, subst)) + .map(|field| field.ty(tcx, args)) .try_for_each(|t| check_non_exhaustive(tcx, t)) } _ => ControlFlow::Continue(()), diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index 6edd68f1bae..69a02b73a79 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -125,9 +125,9 @@ fn check_method_is_structurally_compatible<'tcx>( /// <'b> fn(t: &'i0 U0, m: &'b N0) -> Foo /// ``` /// -/// We now want to extract and substitute the type of the *trait* +/// We now want to extract and instantiate the type of the *trait* /// method and compare it. To do so, we must create a compound -/// substitution by combining `trait_to_impl_args` and +/// instantiation by combining `trait_to_impl_args` and /// `impl_to_placeholder_args`, and also adding a mapping for the method /// type parameters. We extend the mapping to also include /// the method parameters. @@ -146,11 +146,11 @@ fn check_method_is_structurally_compatible<'tcx>( /// vs `'b`). However, the normal subtyping rules on fn types handle /// this kind of equivalency just fine. /// -/// We now use these substitutions to ensure that all declared bounds are -/// satisfied by the implementation's method. +/// We now use these generic parameters to ensure that all declared bounds +/// are satisfied by the implementation's method. /// /// We do this by creating a parameter environment which contains a -/// substitution corresponding to `impl_to_placeholder_args`. We then build +/// generic parameter corresponding to `impl_to_placeholder_args`. We then build /// `trait_to_placeholder_args` and use it to convert the predicates contained /// in the `trait_m` generics to the placeholder form. /// @@ -454,7 +454,7 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>( let impl_trait_ref = tcx.impl_trait_ref(impl_m.impl_container(tcx).unwrap()).unwrap().instantiate_identity(); // First, check a few of the same things as `compare_impl_method`, - // just so we don't ICE during substitution later. + // just so we don't ICE during instantiation later. check_method_is_structurally_compatible(tcx, impl_m, trait_m, impl_trait_ref, true)?; let trait_to_impl_args = impl_trait_ref.args; @@ -543,7 +543,7 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>( // } // ``` // .. to compile. However, since we use both the normalized and unnormalized - // inputs and outputs from the substituted trait signature, we will end up + // inputs and outputs from the instantiated trait signature, we will end up // seeing the hidden type of an RPIT in the signature itself. Naively, this // means that we will use the hidden type to imply the hidden type's own // well-formedness. @@ -699,7 +699,7 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>( // NOTE(compiler-errors): RPITITs, like all other RPITs, have early-bound // region args that are synthesized during AST lowering. These are args // that are appended to the parent args (trait and trait method). However, - // we're trying to infer the unsubstituted type value of the RPITIT inside + // we're trying to infer the uninstantiated type value of the RPITIT inside // the *impl*, so we can later use the impl's method args to normalize // an RPITIT to a concrete type (`confirm_impl_trait_in_trait_candidate`). // @@ -711,7 +711,7 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>( // guarantee that the indices from the trait args and impl args line up. // So to fix this, we subtract the number of trait args and add the number of // impl args to *renumber* these early-bound regions to their corresponding - // indices in the impl's substitutions list. + // indices in the impl's generic parameters list. // // Also, we only need to account for a difference in trait and impl args, // since we previously enforce that the trait method and impl method have the diff --git a/compiler/rustc_hir_analysis/src/check/dropck.rs b/compiler/rustc_hir_analysis/src/check/dropck.rs index 7b60457affa..82a6b6b6f2c 100644 --- a/compiler/rustc_hir_analysis/src/check/dropck.rs +++ b/compiler/rustc_hir_analysis/src/check/dropck.rs @@ -124,14 +124,14 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>( let infcx = tcx.infer_ctxt().build(); let ocx = ObligationCtxt::new(&infcx); - // Take the param-env of the adt and substitute the args that show up in + // Take the param-env of the adt and instantiate the args that show up in // the implementation's self type. This gives us the assumptions that the // self ty of the implementation is allowed to know just from it being a // well-formed adt, since that's all we're allowed to assume while proving // the Drop implementation is not specialized. // // We don't need to normalize this param-env or anything, since we're only - // substituting it with free params, so no additional param-env normalization + // instantiating it with free params, so no additional param-env normalization // can occur on top of what has been done in the param_env query itself. let param_env = ty::EarlyBinder::bind(tcx.param_env(adt_def_id)).instantiate(tcx, adt_to_impl_args); diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs index b7443198311..2f8e065df33 100644 --- a/compiler/rustc_hir_analysis/src/check/mod.rs +++ b/compiler/rustc_hir_analysis/src/check/mod.rs @@ -56,7 +56,7 @@ type variable is an instance of a type parameter. That is, given a generic function `fn foo(t: T)`, while checking the function `foo`, the type `ty_param(0)` refers to the type `T`, which is treated in abstract. However, when `foo()` is called, `T` will be -substituted for a fresh type variable `N`. This variable will +instantiated with a fresh type variable `N`. This variable will eventually be resolved to some concrete type (which might itself be a type parameter). diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 646a84b043c..44a3d2d9374 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -618,7 +618,7 @@ fn gather_gat_bounds<'tcx, T: TypeFoldable>>( // The bounds we that we would require from `to_check` let mut bounds = FxHashSet::default(); - let (regions, types) = GATSubstCollector::visit(gat_def_id.to_def_id(), to_check); + let (regions, types) = GATArgsCollector::visit(gat_def_id.to_def_id(), to_check); // If both regions and types are empty, then this GAT isn't in the // set of types we are checking, and we shouldn't try to do clause analysis @@ -787,34 +787,34 @@ fn test_region_obligations<'tcx>( /// `>::GAT` and adds the arguments `P0..Pm` into /// the two vectors, `regions` and `types` (depending on their kind). For each /// parameter `Pi` also track the index `i`. -struct GATSubstCollector<'tcx> { +struct GATArgsCollector<'tcx> { gat: DefId, - // Which region appears and which parameter index its substituted for + // Which region appears and which parameter index its instantiated with regions: FxHashSet<(ty::Region<'tcx>, usize)>, - // Which params appears and which parameter index its substituted for + // Which params appears and which parameter index its instantiated with types: FxHashSet<(Ty<'tcx>, usize)>, } -impl<'tcx> GATSubstCollector<'tcx> { +impl<'tcx> GATArgsCollector<'tcx> { fn visit>>( gat: DefId, t: T, ) -> (FxHashSet<(ty::Region<'tcx>, usize)>, FxHashSet<(Ty<'tcx>, usize)>) { let mut visitor = - GATSubstCollector { gat, regions: FxHashSet::default(), types: FxHashSet::default() }; + GATArgsCollector { gat, regions: FxHashSet::default(), types: FxHashSet::default() }; t.visit_with(&mut visitor); (visitor.regions, visitor.types) } } -impl<'tcx> TypeVisitor> for GATSubstCollector<'tcx> { +impl<'tcx> TypeVisitor> for GATArgsCollector<'tcx> { type BreakTy = !; fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { match t.kind() { ty::Alias(ty::Projection, p) if p.def_id == self.gat => { - for (idx, subst) in p.args.iter().enumerate() { - match subst.unpack() { + for (idx, arg) in p.args.iter().enumerate() { + match arg.unpack() { GenericArgKind::Lifetime(lt) if !lt.is_bound() => { self.regions.insert((lt, idx)); } @@ -1407,14 +1407,14 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id } } - // Check that trait predicates are WF when params are substituted by their defaults. + // Check that trait predicates are WF when params are instantiated with their defaults. // We don't want to overly constrain the predicates that may be written but we want to // catch cases where a default my never be applied such as `struct Foo`. // Therefore we check if a predicate which contains a single type param - // with a concrete default is WF with that default substituted. + // with a concrete default is WF with that default instantiated. // For more examples see tests `defaults-well-formedness.rs` and `type-check-defaults.rs`. // - // First we build the defaulted substitution. + // First we build the defaulted generic parameters. let args = GenericArgs::for_item(tcx, def_id.to_def_id(), |param, _| { match param.kind { GenericParamDefKind::Lifetime => { @@ -1428,7 +1428,7 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id let default_ty = tcx.type_of(param.def_id).instantiate_identity(); // ... and it's not a dependent default, ... if !default_ty.has_param() { - // ... then substitute it with the default. + // ... then instantiate it with the default. return default_ty.into(); } } @@ -1441,7 +1441,7 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id let default_ct = tcx.const_param_default(param.def_id).instantiate_identity(); // ... and it's not a dependent default, ... if !default_ct.has_param() { - // ... then substitute it with the default. + // ... then instantiate it with the default. return default_ct.into(); } } @@ -1451,7 +1451,7 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id } }); - // Now we build the substituted predicates. + // Now we build the instantiated predicates. let default_obligations = predicates .predicates .iter() @@ -1483,23 +1483,25 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id } let mut param_count = CountParams::default(); let has_region = pred.visit_with(&mut param_count).is_break(); - let substituted_pred = ty::EarlyBinder::bind(pred).instantiate(tcx, args); + let instantiated_pred = ty::EarlyBinder::bind(pred).instantiate(tcx, args); // Don't check non-defaulted params, dependent defaults (including lifetimes) // or preds with multiple params. - if substituted_pred.has_non_region_param() || param_count.params.len() > 1 || has_region + if instantiated_pred.has_non_region_param() + || param_count.params.len() > 1 + || has_region { None - } else if predicates.predicates.iter().any(|&(p, _)| p == substituted_pred) { + } else if predicates.predicates.iter().any(|&(p, _)| p == instantiated_pred) { // Avoid duplication of predicates that contain no parameters, for example. None } else { - Some((substituted_pred, sp)) + Some((instantiated_pred, sp)) } }) .map(|(pred, sp)| { // Convert each of those into an obligation. So if you have // something like `struct Foo`, we would - // take that predicate `T: Copy`, substitute to `String: Copy` + // take that predicate `T: Copy`, instantiated with `String: Copy` // (actually that happens in the previous `flat_map` call), // and then try to prove it (in this case, we'll fail). // diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs index 5a387844593..7d551fbf035 100644 --- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs +++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs @@ -396,7 +396,7 @@ pub fn coerce_unsized_info<'tcx>( // // To check if this impl is legal, we would walk down // the fields of `Foo` and consider their types with - // both substitutes. We are looking to find that + // both generic parameters. We are looking to find that // exactly one (non-phantom) field has changed its // type, which we will expect to be the pointer that // is becoming fat (we could probably generalize this diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs index e5e731bbe8c..9cc6c16c126 100644 --- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs @@ -71,7 +71,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { // end up with that const looking like: `ty::ConstKind::Unevaluated(def_id, args: [N#0])`. // // This causes ICEs (#86580) when building the args for Foo in `fn foo() -> Foo { .. }` as - // we substitute the defaults with the partially built args when we build the args. Subst'ing + // we instantiate the defaults with the partially built args when we build the args. Instantiating // the `N#0` on the unevaluated const indexes into the empty args we're in the process of building. // // We fix this by having this function return the parent's generics ourselves and truncating the diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs index 1aa9c6929f8..c9cf43ddfc8 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -1786,7 +1786,8 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { let bound_predicate = pred.kind(); match bound_predicate.skip_binder() { ty::ClauseKind::Trait(data) => { - // The order here needs to match what we would get from `subst_supertrait` + // The order here needs to match what we would get from + // `rustc_middle::ty::predicate::Clause::instantiate_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()); diff --git a/compiler/rustc_hir_analysis/src/constrained_generic_params.rs b/compiler/rustc_hir_analysis/src/constrained_generic_params.rs index 65d1ffa40e2..05efad3ccb3 100644 --- a/compiler/rustc_hir_analysis/src/constrained_generic_params.rs +++ b/compiler/rustc_hir_analysis/src/constrained_generic_params.rs @@ -119,7 +119,7 @@ pub fn identify_constrained_generic_params<'tcx>( /// * `::Item = T` -- a desugared ProjectionPredicate /// /// When we, for example, try to go over the trait-reference -/// `IntoIter as Trait`, we substitute the impl parameters with fresh +/// `IntoIter as Trait`, we instantiate the impl parameters with fresh /// variables and match them with the impl trait-ref, so we know that /// `$U = IntoIter`. /// diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index bec53693d6c..cc4336f74d5 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -372,8 +372,8 @@ pub struct ManualImplementation { } #[derive(Diagnostic)] -#[diag(hir_analysis_substs_on_overridden_impl)] -pub struct SubstsOnOverriddenImpl { +#[diag(hir_analysis_generic_args_on_overridden_impl)] +pub struct GenericArgsOnOverriddenImpl { #[primary_span] pub span: Span, } diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs index 1b6a39d8162..beab8997160 100644 --- a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs +++ b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs @@ -34,8 +34,8 @@ //! impl> SpecExtend for I { /* default impl */ } //! ``` //! -//! We get that the subst for `impl2` are `[T, std::vec::IntoIter]`. `T` is -//! constrained to be `::Item`, so we check only +//! We get that the generic pamameters for `impl2` are `[T, std::vec::IntoIter]`. +//! `T` is constrained to be `::Item`, so we check only //! `std::vec::IntoIter` for repeated parameters, which it doesn't have. The //! predicates of `impl1` are only `T: Sized`, which is also a predicate of //! `impl2`. So this specialization is sound. @@ -65,7 +65,7 @@ //! cause use after frees with purely safe code in the same way as specializing //! on traits with methods can. -use crate::errors::SubstsOnOverriddenImpl; +use crate::errors::GenericArgsOnOverriddenImpl; use crate::{constrained_generic_params as cgp, errors}; use rustc_data_structures::fx::FxHashSet; @@ -179,8 +179,8 @@ fn check_constness( } /// Given a specializing impl `impl1`, and the base impl `impl2`, returns two -/// substitutions `(S1, S2)` that equate their trait references. The returned -/// types are expressed in terms of the generics of `impl1`. +/// generic parameters `(S1, S2)` that equate their trait references. +/// The returned types are expressed in terms of the generics of `impl1`. /// /// Example /// @@ -228,13 +228,13 @@ fn get_impl_args( let _ = ocx.resolve_regions_and_report_errors(impl1_def_id, &outlives_env); let Ok(impl2_args) = infcx.fully_resolve(impl2_args) else { let span = tcx.def_span(impl1_def_id); - let guar = tcx.dcx().emit_err(SubstsOnOverriddenImpl { span }); + let guar = tcx.dcx().emit_err(GenericArgsOnOverriddenImpl { span }); return Err(guar); }; Ok((impl1_args, impl2_args)) } -/// Returns a list of all of the unconstrained subst of the given impl. +/// Returns a list of all of the unconstrained generic parameters of the given impl. /// /// For example given the impl: /// diff --git a/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs b/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs index 0cb38094cec..0c0dbbe7ad9 100644 --- a/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs +++ b/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs @@ -229,7 +229,7 @@ fn insert_required_predicates_to_be_wf<'tcx>( /// Here, we should fetch the explicit predicates, which /// will give us `U: 'static` and `U: Outer`. The latter we /// can ignore, but we will want to process `U: 'static`, -/// applying the substitution as above. +/// applying the instantiation as above. fn check_explicit_predicates<'tcx>( tcx: TyCtxt<'tcx>, def_id: DefId, @@ -316,7 +316,7 @@ fn check_explicit_predicates<'tcx>( /// Here, when processing the type of field `outer`, we would request the /// set of implicit predicates computed for `Inner` thus far. This will /// initially come back empty, but in next round we will get `U: 'b`. -/// We then apply the substitution `['b => 'a, U => T]` and thus get the +/// We then apply the instantiation `['b => 'a, U => T]` and thus get the /// requirement that `T: 'a` holds for `Outer`. fn check_inferred_predicates<'tcx>( tcx: TyCtxt<'tcx>, @@ -334,7 +334,7 @@ fn check_inferred_predicates<'tcx>( for (&predicate, &span) in predicates.as_ref().skip_binder() { // `predicate` is `U: 'b` in the example above. - // So apply the substitution to get `T: 'a`. + // So apply the instantiation to get `T: 'a`. let ty::OutlivesPredicate(arg, region) = predicates.rebind(predicate).instantiate(tcx, args); insert_outlives_predicate(tcx, arg, region, span, required_predicates); diff --git a/compiler/rustc_hir_analysis/src/variance/mod.rs b/compiler/rustc_hir_analysis/src/variance/mod.rs index 7d145ea1f23..4d5dcbadc4a 100644 --- a/compiler/rustc_hir_analysis/src/variance/mod.rs +++ b/compiler/rustc_hir_analysis/src/variance/mod.rs @@ -172,16 +172,16 @@ fn variance_of_opaque(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[ty::Varianc trait_ref: ty::TraitRef { def_id: _, args, .. }, polarity: _, }) => { - for subst in &args[1..] { - subst.visit_with(&mut collector); + for arg in &args[1..] { + arg.visit_with(&mut collector); } } ty::ClauseKind::Projection(ty::ProjectionPredicate { projection_ty: ty::AliasTy { args, .. }, term, }) => { - for subst in &args[1..] { - subst.visit_with(&mut collector); + for arg in &args[1..] { + arg.visit_with(&mut collector); } term.visit_with(&mut collector); } diff --git a/compiler/rustc_hir_typeck/src/check.rs b/compiler/rustc_hir_typeck/src/check.rs index aab78465f8c..9380f9943f3 100644 --- a/compiler/rustc_hir_typeck/src/check.rs +++ b/compiler/rustc_hir_typeck/src/check.rs @@ -123,7 +123,7 @@ pub(super) fn check_fn<'a, 'tcx>( if let ty::Dynamic(..) = declared_ret_ty.kind() { // We have special-cased the case where the function is declared // `-> dyn Foo` and we don't actually relate it to the - // `fcx.ret_coercion`, so just substitute a type variable. + // `fcx.ret_coercion`, so just instantiate a type variable. actual_return_ty = fcx.next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::DynReturnFn, span }); debug!("actual_return_ty replaced with {:?}", actual_return_ty); diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index 549ad44d7e3..e98ace948f9 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -752,7 +752,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { let mut obligations: Vec<_> = predicates .iter() .map(|predicate| { - // For each existential predicate (e.g., `?Self: Clone`) substitute + // For each existential predicate (e.g., `?Self: Clone`) instantiate // the type of the expression (e.g., `usize` in our example above) // and then require that the resulting predicate (e.g., `usize: Clone`) // holds (it does). diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 31c97aab7fb..31295a106ae 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -1801,7 +1801,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // consistency. But they should be merged as much as possible. let fru_tys = if self.tcx.features().type_changing_struct_update { if adt.is_struct() { - // Make some fresh substitutions for our ADT type. + // Make some fresh generic parameters for our ADT type. let fresh_args = self.fresh_args_for_item(base_expr.span, adt.did()); // We do subtyping on the FRU fields first, so we can // learn exactly what types we expect the base expr diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index 7eb421ca8f5..1d2c8841539 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -15,7 +15,7 @@ use rustc_hir_analysis::astconv::generics::{ check_generic_arg_count_for_call, create_args_for_parent_generic_args, }; use rustc_hir_analysis::astconv::{ - AstConv, CreateSubstsForGenericArgsCtxt, ExplicitLateBound, GenericArgCountMismatch, + AstConv, CreateInstantiationsForGenericArgsCtxt, ExplicitLateBound, GenericArgCountMismatch, GenericArgCountResult, IsMethodCall, PathSeg, }; use rustc_infer::infer::canonical::{Canonical, OriginalQueryValues, QueryResponse}; @@ -179,8 +179,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } /// Given the args that we just converted from the HIR, try to - /// canonicalize them and store them as user-given substitutions - /// (i.e., substitutions that must be respected by the NLL check). + /// canonicalize them and store them as user-given parameters + /// (i.e., parameters that must be respected by the NLL check). /// /// This should be invoked **before any unifications have /// occurred**, so that annotations like `Vec<_>` are preserved @@ -733,7 +733,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return Err(TypeError::Mismatch); } - // Record all the argument types, with the substitutions + // Record all the argument types, with the args // produced from the above subtyping unification. Ok(Some(formal_args.iter().map(|&ty| self.resolve_vars_if_possible(ty)).collect())) }) @@ -1163,7 +1163,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Now we have to compare the types that the user *actually* // provided against the types that were *expected*. If the user - // did not provide any types, then we want to substitute inference + // did not provide any types, then we want to instantiate inference // variables. If the user provided some types, we may still need // to add defaults. If the user provided *too many* types, that's // a problem. @@ -1253,14 +1253,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }, }; - struct CreateCtorSubstsContext<'a, 'tcx> { + struct CreateCtorInstantiationsContext<'a, 'tcx> { fcx: &'a FnCtxt<'a, 'tcx>, span: Span, path_segs: &'a [PathSeg], infer_args_for_err: &'a FxHashSet, segments: &'tcx [hir::PathSegment<'tcx>], } - impl<'tcx, 'a> CreateSubstsForGenericArgsCtxt<'a, 'tcx> for CreateCtorSubstsContext<'a, 'tcx> { + impl<'tcx, 'a> CreateInstantiationsForGenericArgsCtxt<'a, 'tcx> + for CreateCtorInstantiationsContext<'a, 'tcx> + { fn args_for_def_id( &mut self, def_id: DefId, @@ -1384,7 +1386,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { has_self, self_ty.map(|s| s.raw), &arg_count, - &mut CreateCtorSubstsContext { + &mut CreateCtorInstantiationsContext { fcx: self, span, path_segs: &path_segs, @@ -1402,18 +1404,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.add_required_obligations_for_hir(span, def_id, args, hir_id); - // Substitute the values for the type parameters into the type of + // Instantiate the values for the type parameters into the type of // the referenced item. let ty = tcx.type_of(def_id); assert!(!args.has_escaping_bound_vars()); assert!(!ty.skip_binder().has_escaping_bound_vars()); - let ty_substituted = self.normalize(span, ty.instantiate(tcx, args)); + let ty_instantiated = self.normalize(span, ty.instantiate(tcx, args)); if let Some(UserSelfTy { impl_def_id, self_ty }) = user_self_ty { // In the case of `Foo::method` and `>::method`, if `method` // is inherent, there is no `Self` parameter; instead, the impl needs // type parameters, which we can infer by unifying the provided `Self` - // with the substituted impl type. + // with the instantiated impl type. // This also occurs for an enum variant on a type alias. let impl_ty = self.normalize(span, tcx.type_of(impl_def_id).instantiate(tcx, args)); let self_ty = self.normalize(span, self_ty); @@ -1434,13 +1436,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - debug!("instantiate_value_path: type of {:?} is {:?}", hir_id, ty_substituted); + debug!("instantiate_value_path: type of {:?} is {:?}", hir_id, ty_instantiated); self.write_args(hir_id, args); - (ty_substituted, res) + (ty_instantiated, res) } - /// Add all the obligations that are required, substituting and normalized appropriately. + /// Add all the obligations that are required, instantiated and normalized appropriately. pub(crate) fn add_required_obligations_for_hir( &self, span: Span, diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs index 6aa986b0df4..f0631dd4b5f 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs @@ -21,7 +21,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return false; }; - let Some(unsubstituted_pred) = self + let Some(uninstantiated_pred) = self .tcx .predicates_of(def_id) .instantiate_identity(self.tcx) @@ -34,7 +34,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let generics = self.tcx.generics_of(def_id); let (predicate_args, predicate_self_type_to_point_at) = - match unsubstituted_pred.kind().skip_binder() { + match uninstantiated_pred.kind().skip_binder() { ty::ClauseKind::Trait(pred) => { (pred.trait_ref.args.to_vec(), Some(pred.self_ty().into())) } @@ -343,10 +343,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { && let TypeVariableOriginKind::TypeParameterDefinition(_, def_id) = origin.kind && let generics = self.0.tcx.generics_of(self.1) && let Some(index) = generics.param_def_id_to_index(self.0.tcx, def_id) - && let Some(subst) = + && let Some(arg) = ty::GenericArgs::identity_for_item(self.0.tcx, self.1).get(index as usize) { - ControlFlow::Break(*subst) + ControlFlow::Break(*arg) } else { ty.super_visit_with(self) } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index 193c9a4b908..d68e20541ef 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -2133,17 +2133,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expr_ty: Ty<'tcx>, ) -> bool { let tcx = self.tcx; - let (adt, substs, unwrap) = match expected.kind() { + let (adt, args, unwrap) = match expected.kind() { // In case Option is wanted, but * is provided, suggest calling new - ty::Adt(adt, substs) if tcx.is_diagnostic_item(sym::Option, adt.did()) => { - let nonzero_type = substs.type_at(0); // Unwrap option type. - let ty::Adt(adt, substs) = nonzero_type.kind() else { + ty::Adt(adt, args) if tcx.is_diagnostic_item(sym::Option, adt.did()) => { + let nonzero_type = args.type_at(0); // Unwrap option type. + let ty::Adt(adt, args) = nonzero_type.kind() else { return false; }; - (adt, substs, "") + (adt, args, "") } // In case `NonZero<*>` is wanted but `*` is provided, also add `.unwrap()` to satisfy types. - ty::Adt(adt, substs) => (adt, substs, ".unwrap()"), + ty::Adt(adt, args) => (adt, args, ".unwrap()"), _ => return false, }; @@ -2165,7 +2165,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ("NonZeroI128", tcx.types.i128), ]; - let int_type = substs.type_at(0); + let int_type = args.type_at(0); let Some(nonzero_alias) = coercable_types.iter().find_map(|(nonzero_alias, t)| { if *t == int_type && self.can_coerce(expr_ty, *t) { Some(nonzero_alias) } else { None } diff --git a/compiler/rustc_hir_typeck/src/method/confirm.rs b/compiler/rustc_hir_typeck/src/method/confirm.rs index 3a44c6c2410..4e9cb92919a 100644 --- a/compiler/rustc_hir_typeck/src/method/confirm.rs +++ b/compiler/rustc_hir_typeck/src/method/confirm.rs @@ -7,7 +7,7 @@ use rustc_hir::GenericArg; use rustc_hir_analysis::astconv::generics::{ check_generic_arg_count_for_call, create_args_for_parent_generic_args, }; -use rustc_hir_analysis::astconv::{AstConv, CreateSubstsForGenericArgsCtxt, IsMethodCall}; +use rustc_hir_analysis::astconv::{AstConv, CreateInstantiationsForGenericArgsCtxt, IsMethodCall}; use rustc_infer::infer::{self, DefineOpaqueTypes, InferOk}; use rustc_middle::traits::{ObligationCauseCode, UnifyReceiverContext}; use rustc_middle::ty::adjustment::{Adjust, Adjustment, PointerCoercion}; @@ -95,7 +95,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { // Adjust the self expression the user provided and obtain the adjusted type. let self_ty = self.adjust_self_ty(unadjusted_self_ty, pick); - // Create substitutions for the method's type parameters. + // Create generic args for the method's type parameters. let rcvr_args = self.fresh_receiver_args(self_ty, pick); let all_args = self.instantiate_method_args(pick, segment, rcvr_args); @@ -246,11 +246,11 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { target } - /// Returns a set of substitutions for the method *receiver* where all type and region - /// parameters are instantiated with fresh variables. This substitution does not include any + /// Returns a set of generic parameters for the method *receiver* where all type and region + /// parameters are instantiated with fresh variables. This generic paramters does not include any /// parameters declared on the method itself. /// - /// Note that this substitution may include late-bound regions from the impl level. If so, + /// Note that this generic parameters may include late-bound regions from the impl level. If so, /// these are instantiated later in the `instantiate_method_sig` routine. fn fresh_receiver_args( &mut self, @@ -272,8 +272,8 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { self.extract_existential_trait_ref(self_ty, |this, object_ty, principal| { // The object data has no entry for the Self // Type. For the purposes of this method call, we - // substitute the object type itself. This - // wouldn't be a sound substitution in all cases, + // instantiate the object type itself. This + // wouldn't be a sound instantiation in all cases, // since each instance of the object type is a // different existential and hence could match // distinct types (e.g., if `Self` appeared as an @@ -362,16 +362,18 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { IsMethodCall::Yes, ); - // Create subst for early-bound lifetime parameters, combining - // parameters from the type and those from the method. + // Create generic paramters for early-bound lifetime parameters, + // combining parameters from the type and those from the method. assert_eq!(generics.parent_count, parent_args.len()); - struct MethodSubstsCtxt<'a, 'tcx> { + struct MethodInstantiationsCtxt<'a, 'tcx> { cfcx: &'a ConfirmContext<'a, 'tcx>, pick: &'a probe::Pick<'tcx>, seg: &'a hir::PathSegment<'tcx>, } - impl<'a, 'tcx> CreateSubstsForGenericArgsCtxt<'a, 'tcx> for MethodSubstsCtxt<'a, 'tcx> { + impl<'a, 'tcx> CreateInstantiationsForGenericArgsCtxt<'a, 'tcx> + for MethodInstantiationsCtxt<'a, 'tcx> + { fn args_for_def_id( &mut self, def_id: DefId, @@ -437,7 +439,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { false, None, &arg_count_correct, - &mut MethodSubstsCtxt { cfcx: self, pick, seg }, + &mut MethodInstantiationsCtxt { cfcx: self, pick, seg }, ); // When the method is confirmed, the `args` includes @@ -538,15 +540,15 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { debug!("instantiate_method_sig(pick={:?}, all_args={:?})", pick, all_args); // Instantiate the bounds on the method with the - // type/early-bound-regions substitutions performed. There can + // type/early-bound-regions instatiations performed. There can // be no late-bound regions appearing here. let def_id = pick.item.def_id; let method_predicates = self.tcx.predicates_of(def_id).instantiate(self.tcx, all_args); - debug!("method_predicates after subst = {:?}", method_predicates); + debug!("method_predicates after instantitation = {:?}", method_predicates); let sig = self.tcx.fn_sig(def_id).instantiate(self.tcx, all_args); - debug!("type scheme substituted, sig={:?}", sig); + debug!("type scheme instantiated, sig={:?}", sig); let sig = self.instantiate_binder_with_fresh_vars(sig); debug!("late-bound lifetimes from method instantiated, sig={:?}", sig); diff --git a/compiler/rustc_hir_typeck/src/method/mod.rs b/compiler/rustc_hir_typeck/src/method/mod.rs index 804d6ff2cb5..fb969c82d8a 100644 --- a/compiler/rustc_hir_typeck/src/method/mod.rs +++ b/compiler/rustc_hir_typeck/src/method/mod.rs @@ -38,7 +38,7 @@ pub struct MethodCallee<'tcx> { pub args: GenericArgsRef<'tcx>, /// Instantiated method signature, i.e., it has been - /// substituted, normalized, and has had late-bound + /// instantiated, normalized, and has had late-bound /// lifetimes replaced with inference variables. pub sig: ty::FnSig<'tcx>, } @@ -395,7 +395,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { debug!("lookup_in_trait_adjusted: method_item={:?}", method_item); let mut obligations = vec![]; - // Instantiate late-bound regions and substitute the trait + // Instantiate late-bound regions and instantiate the trait // parameters into the method type to get the actual method type. // // N.B., instantiate late-bound regions before normalizing the diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index a446c7aa42b..d7edc70bce8 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -111,7 +111,7 @@ pub(crate) struct Candidate<'tcx> { // The way this is handled is through `xform_self_ty`. It contains // the receiver type of this candidate, but `xform_self_ty`, // `xform_ret_ty` and `kind` (which contains the predicates) have the - // generic parameters of this candidate substituted with the *same set* + // generic parameters of this candidate instantiated with the *same set* // of inference variables, which acts as some weird sort of "query". // // When we check out a candidate, we require `xform_self_ty` to be @@ -799,7 +799,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { // the `Self` type. An [`ObjectSafetyViolation::SupertraitSelf`] error // will be reported by `object_safety.rs` if the method refers to the // `Self` type anywhere other than the receiver. Here, we use a - // substitution that replaces `Self` with the object type itself. Hence, + // instantiation that replaces `Self` with the object type itself. Hence, // a `&self` method will wind up with an argument type like `&dyn Trait`. let trait_ref = principal.with_self_ty(self.tcx, self_ty); self.elaborate_bounds(iter::once(trait_ref), |this, new_trait_ref, item| { @@ -1857,8 +1857,8 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { assert!(!args.has_escaping_bound_vars()); // It is possible for type parameters or early-bound lifetimes - // to appear in the signature of `self`. The substitutions we - // are given do not include type/lifetime parameters for the + // to appear in the signature of `self`. The generic parameters + // we are given do not include type/lifetime parameters for the // method yet. So create fresh variables here for those too, // if there are any. let generics = self.tcx.generics_of(method); @@ -1889,7 +1889,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { self.instantiate_bound_regions_with_erased(xform_fn_sig) } - /// Gets the type of an impl and generate substitutions with inference vars. + /// Gets the type of an impl and generate generic parameters with inference vars. fn impl_ty_and_args( &self, impl_def_id: DefId, @@ -1913,7 +1913,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { /// late-bound regions with 'static. Otherwise, if we were going to replace late-bound /// regions with actual region variables as is proper, we'd have to ensure that the same /// region got replaced with the same variable, which requires a bit more coordination - /// and/or tracking the substitution and + /// and/or tracking the instantiations and /// so forth. fn instantiate_bound_regions_with_erased(&self, value: ty::Binder<'tcx, T>) -> T where diff --git a/compiler/rustc_hir_typeck/src/place_op.rs b/compiler/rustc_hir_typeck/src/place_op.rs index 1eaaf30043b..6c5715b323c 100644 --- a/compiler/rustc_hir_typeck/src/place_op.rs +++ b/compiler/rustc_hir_typeck/src/place_op.rs @@ -357,7 +357,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { PlaceOp::Deref => None, PlaceOp::Index => { // We would need to recover the `T` used when we resolve `<_ as Index>::index` - // in try_index_step. This is the subst at index 1. + // in try_index_step. This is the arg at index 1. // // Note: we should *not* use `expr_ty` of index_expr here because autoderef // during coercions can cause type of index_expr to differ from `T` (#72002). diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs index 94f6c06157e..c95e7dfbc3d 100644 --- a/compiler/rustc_hir_typeck/src/writeback.rs +++ b/compiler/rustc_hir_typeck/src/writeback.rs @@ -1,6 +1,6 @@ // Type resolution: the phase that finds all the types in the AST with // unresolved type variables and replaces "ty_var" types with their -// substitutions. +// generic parameters. use crate::FnCtxt; use rustc_data_structures::unord::ExtendUnord; @@ -616,7 +616,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { self.write_ty_to_typeck_results(hir_id, n_ty); debug!(?n_ty); - // Resolve any substitutions + // Resolve any generic parameters if let Some(args) = self.fcx.typeck_results.borrow().node_args_opt(hir_id) { let args = self.resolve(args, &span); debug!("write_args_to_tcx({:?}, {:?})", hir_id, args); diff --git a/compiler/rustc_infer/src/infer/canonical/substitute.rs b/compiler/rustc_infer/src/infer/canonical/instantiate.rs similarity index 80% rename from compiler/rustc_infer/src/infer/canonical/substitute.rs rename to compiler/rustc_infer/src/infer/canonical/instantiate.rs index e0b97bb160c..f6b583151fd 100644 --- a/compiler/rustc_infer/src/infer/canonical/substitute.rs +++ b/compiler/rustc_infer/src/infer/canonical/instantiate.rs @@ -1,4 +1,4 @@ -//! This module contains code to substitute new values into a +//! This module contains code to instantiate new values into a //! `Canonical<'tcx, T>`. //! //! For an overview of what canonicalization is and how it fits into @@ -16,17 +16,17 @@ use rustc_middle::ty::{self, TyCtxt}; pub trait CanonicalExt<'tcx, V> { /// Instantiate the wrapped value, replacing each canonical value /// with the value given in `var_values`. - fn substitute(&self, tcx: TyCtxt<'tcx>, var_values: &CanonicalVarValues<'tcx>) -> V + fn instantiate(&self, tcx: TyCtxt<'tcx>, var_values: &CanonicalVarValues<'tcx>) -> V where V: TypeFoldable>; - /// Allows one to apply a substitute to some subset of + /// Allows one to apply a instantiation to some subset of /// `self.value`. Invoke `projection_fn` with `self.value` to get /// a value V that is expressed in terms of the same canonical /// variables bound in `self` (usually this extracts from subset - /// of `self`). Apply the substitution `var_values` to this value + /// of `self`). Apply the instantiation `var_values` to this value /// V, replacing each of the canonical variables. - fn substitute_projected( + fn instantiate_projected( &self, tcx: TyCtxt<'tcx>, var_values: &CanonicalVarValues<'tcx>, @@ -37,14 +37,14 @@ pub trait CanonicalExt<'tcx, V> { } impl<'tcx, V> CanonicalExt<'tcx, V> for Canonical<'tcx, V> { - fn substitute(&self, tcx: TyCtxt<'tcx>, var_values: &CanonicalVarValues<'tcx>) -> V + fn instantiate(&self, tcx: TyCtxt<'tcx>, var_values: &CanonicalVarValues<'tcx>) -> V where V: TypeFoldable>, { - self.substitute_projected(tcx, var_values, |value| value.clone()) + self.instantiate_projected(tcx, var_values, |value| value.clone()) } - fn substitute_projected( + fn instantiate_projected( &self, tcx: TyCtxt<'tcx>, var_values: &CanonicalVarValues<'tcx>, @@ -55,14 +55,14 @@ impl<'tcx, V> CanonicalExt<'tcx, V> for Canonical<'tcx, V> { { assert_eq!(self.variables.len(), var_values.len()); let value = projection_fn(&self.value); - substitute_value(tcx, var_values, value) + instantiate_value(tcx, var_values, value) } } -/// Substitute the values from `var_values` into `value`. `var_values` +/// Instantiate the values from `var_values` into `value`. `var_values` /// must be values for the set of canonical variables that appear in /// `value`. -pub(super) fn substitute_value<'tcx, T>( +pub(super) fn instantiate_value<'tcx, T>( tcx: TyCtxt<'tcx>, var_values: &CanonicalVarValues<'tcx>, value: T, diff --git a/compiler/rustc_infer/src/infer/canonical/mod.rs b/compiler/rustc_infer/src/infer/canonical/mod.rs index 1f68a5a9c61..1d203a29b14 100644 --- a/compiler/rustc_infer/src/infer/canonical/mod.rs +++ b/compiler/rustc_infer/src/infer/canonical/mod.rs @@ -30,24 +30,24 @@ use rustc_middle::ty::GenericArg; use rustc_middle::ty::{self, List, Ty, TyCtxt}; use rustc_span::Span; +pub use instantiate::CanonicalExt; pub use rustc_middle::infer::canonical::*; -pub use substitute::CanonicalExt; mod canonicalizer; +mod instantiate; pub mod query_response; -mod substitute; impl<'tcx> InferCtxt<'tcx> { - /// Creates a substitution S for the canonical value with fresh + /// Creates an instantiation S for the canonical value with fresh /// inference variables and applies it to the canonical value. - /// Returns both the instantiated result *and* the substitution S. + /// Returns both the instantiated result *and* the instantiation S. /// /// This can be invoked as part of constructing an /// inference context at the start of a query (see /// `InferCtxtBuilder::build_with_canonical`). It basically /// brings the canonical value "into scope" within your new infcx. /// - /// At the end of processing, the substitution S (once + /// At the end of processing, the instantiation S (once /// canonicalized) then represents the values that you computed /// for each of the canonical inputs to your query. pub fn instantiate_canonical_with_fresh_inference_vars( @@ -73,14 +73,14 @@ impl<'tcx> InferCtxt<'tcx> { let canonical_inference_vars = self.instantiate_canonical_vars(span, canonical.variables, |ui| universes[ui]); - let result = canonical.substitute(self.tcx, &canonical_inference_vars); + let result = canonical.instantiate(self.tcx, &canonical_inference_vars); (result, canonical_inference_vars) } /// Given the "infos" about the canonical variables from some /// canonical, creates fresh variables with the same /// characteristics (see `instantiate_canonical_var` for - /// details). You can then use `substitute` to instantiate the + /// details). You can then use `instantiate` to instantiate the /// canonical variable with these inference variables. fn instantiate_canonical_vars( &self, diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs index 1f071a9ff0b..216b2e70abf 100644 --- a/compiler/rustc_infer/src/infer/canonical/query_response.rs +++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs @@ -7,7 +7,7 @@ //! //! [c]: https://rust-lang.github.io/chalk/book/canonical_queries/canonicalization.html -use crate::infer::canonical::substitute::{substitute_value, CanonicalExt}; +use crate::infer::canonical::instantiate::{instantiate_value, CanonicalExt}; use crate::infer::canonical::{ Canonical, CanonicalQueryResponse, CanonicalVarValues, Certainty, OriginalQueryValues, QueryOutlivesConstraint, QueryRegionConstraints, QueryResponse, @@ -189,18 +189,18 @@ impl<'tcx> InferCtxt<'tcx> { where R: Debug + TypeFoldable>, { - let InferOk { value: result_subst, mut obligations } = - self.query_response_substitution(cause, param_env, original_values, query_response)?; + let InferOk { value: result_args, mut obligations } = + self.query_response_instantiation(cause, param_env, original_values, query_response)?; obligations.extend(self.query_outlives_constraints_into_obligations( cause, param_env, &query_response.value.region_constraints.outlives, - &result_subst, + &result_args, )); let user_result: R = - query_response.substitute_projected(self.tcx, &result_subst, |q_r| q_r.value.clone()); + query_response.instantiate_projected(self.tcx, &result_args, |q_r| q_r.value.clone()); Ok(InferOk { value: user_result, obligations }) } @@ -225,11 +225,11 @@ impl<'tcx> InferCtxt<'tcx> { /// basic operations as `instantiate_query_response_and_region_obligations` but /// it returns its result differently: /// - /// - It creates a substitution `S` that maps from the original + /// - It creates an instantiation `S` that maps from the original /// query variables to the values computed in the query /// result. If any errors arise, they are propagated back as an /// `Err` result. - /// - In the case of a successful substitution, we will append + /// - In the case of a successful instantiation, we will append /// `QueryOutlivesConstraint` values onto the /// `output_query_region_constraints` vector for the solver to /// use (if an error arises, some values may also be pushed, but @@ -239,7 +239,7 @@ impl<'tcx> InferCtxt<'tcx> { /// that must be processed. In this case, those subobligations /// are propagated back in the return value. /// - Finally, the query result (of type `R`) is propagated back, - /// after applying the substitution `S`. + /// after applying the instantiation `S`. pub fn instantiate_nll_query_response_and_region_obligations( &self, cause: &ObligationCause<'tcx>, @@ -251,8 +251,13 @@ impl<'tcx> InferCtxt<'tcx> { where R: Debug + TypeFoldable>, { - let InferOk { value: result_subst, mut obligations } = self - .query_response_substitution_guess(cause, param_env, original_values, query_response)?; + let InferOk { value: result_args, mut obligations } = self + .query_response_instantiation_guess( + cause, + param_env, + original_values, + query_response, + )?; // Compute `QueryOutlivesConstraint` values that unify each of // the original values `v_o` that was canonicalized into a @@ -262,7 +267,7 @@ impl<'tcx> InferCtxt<'tcx> { for (index, original_value) in original_values.var_values.iter().enumerate() { // ...with the value `v_r` of that variable from the query. - let result_value = query_response.substitute_projected(self.tcx, &result_subst, |v| { + let result_value = query_response.instantiate_projected(self.tcx, &result_args, |v| { v.var_values[BoundVar::new(index)] }); match (original_value.unpack(), result_value.unpack()) { @@ -321,7 +326,7 @@ impl<'tcx> InferCtxt<'tcx> { // ...also include the other query region constraints from the query. output_query_region_constraints.outlives.extend( query_response.value.region_constraints.outlives.iter().filter_map(|&r_c| { - let r_c = substitute_value(self.tcx, &result_subst, r_c); + let r_c = instantiate_value(self.tcx, &result_args, r_c); // Screen out `'a: 'a` cases. let ty::OutlivesPredicate(k1, r2) = r_c.0; @@ -336,26 +341,26 @@ impl<'tcx> InferCtxt<'tcx> { .region_constraints .member_constraints .iter() - .map(|p_c| substitute_value(self.tcx, &result_subst, p_c.clone())), + .map(|p_c| instantiate_value(self.tcx, &result_args, p_c.clone())), ); let user_result: R = - query_response.substitute_projected(self.tcx, &result_subst, |q_r| q_r.value.clone()); + query_response.instantiate_projected(self.tcx, &result_args, |q_r| q_r.value.clone()); Ok(InferOk { value: user_result, obligations }) } /// Given the original values and the (canonicalized) result from - /// computing a query, returns a substitution that can be applied + /// computing a query, returns an instantiation that can be applied /// to the query result to convert the result back into the /// original namespace. /// - /// The substitution also comes accompanied with subobligations + /// The instantiation also comes accompanied with subobligations /// that arose from unification; these might occur if (for /// example) we are doing lazy normalization and the value /// assigned to a type variable is unified with an unnormalized /// projection. - fn query_response_substitution( + fn query_response_instantiation( &self, cause: &ObligationCause<'tcx>, param_env: ty::ParamEnv<'tcx>, @@ -366,11 +371,11 @@ impl<'tcx> InferCtxt<'tcx> { R: Debug + TypeFoldable>, { debug!( - "query_response_substitution(original_values={:#?}, query_response={:#?})", + "query_response_instantiation(original_values={:#?}, query_response={:#?})", original_values, query_response, ); - let mut value = self.query_response_substitution_guess( + let mut value = self.query_response_instantiation_guess( cause, param_env, original_values, @@ -378,7 +383,7 @@ impl<'tcx> InferCtxt<'tcx> { )?; value.obligations.extend( - self.unify_query_response_substitution_guess( + self.unify_query_response_instantiation_guess( cause, param_env, original_values, @@ -392,7 +397,7 @@ impl<'tcx> InferCtxt<'tcx> { } /// Given the original values and the (canonicalized) result from - /// computing a query, returns a **guess** at a substitution that + /// computing a query, returns a **guess** at an instantiation that /// can be applied to the query result to convert the result back /// into the original namespace. This is called a **guess** /// because it uses a quick heuristic to find the values for each @@ -401,7 +406,7 @@ impl<'tcx> InferCtxt<'tcx> { /// variable instead. Therefore, the result of this method must be /// properly unified #[instrument(level = "debug", skip(self, cause, param_env))] - fn query_response_substitution_guess( + fn query_response_instantiation_guess( &self, cause: &ObligationCause<'tcx>, param_env: ty::ParamEnv<'tcx>, @@ -450,7 +455,7 @@ impl<'tcx> InferCtxt<'tcx> { if let ty::Bound(debruijn, b) = *result_value.kind() { // ...in which case we would set `canonical_vars[0]` to `Some(?U)`. - // We only allow a `ty::INNERMOST` index in substitutions. + // We only allow a `ty::INNERMOST` index in generic parameters. assert_eq!(debruijn, ty::INNERMOST); opt_values[b.var] = Some(*original_value); } @@ -460,7 +465,7 @@ impl<'tcx> InferCtxt<'tcx> { if let ty::ReBound(debruijn, br) = *result_value { // ... in which case we would set `canonical_vars[0]` to `Some('static)`. - // We only allow a `ty::INNERMOST` index in substitutions. + // We only allow a `ty::INNERMOST` index in generic parameters. assert_eq!(debruijn, ty::INNERMOST); opt_values[br.var] = Some(*original_value); } @@ -469,7 +474,7 @@ impl<'tcx> InferCtxt<'tcx> { if let ty::ConstKind::Bound(debruijn, b) = result_value.kind() { // ...in which case we would set `canonical_vars[0]` to `Some(const X)`. - // We only allow a `ty::INNERMOST` index in substitutions. + // We only allow a `ty::INNERMOST` index in generic parameters. assert_eq!(debruijn, ty::INNERMOST); opt_values[b] = Some(*original_value); } @@ -477,10 +482,10 @@ impl<'tcx> InferCtxt<'tcx> { } } - // Create a result substitution: if we found a value for a + // Create result arguments: if we found a value for a // given variable in the loop above, use that. Otherwise, use // a fresh inference variable. - let result_subst = CanonicalVarValues { + let result_args = CanonicalVarValues { var_values: self.tcx.mk_args_from_iter( query_response.variables.iter().enumerate().map(|(index, info)| { if info.universe() != ty::UniverseIndex::ROOT { @@ -511,8 +516,8 @@ impl<'tcx> InferCtxt<'tcx> { // Carry all newly resolved opaque types to the caller's scope for &(a, b) in &query_response.value.opaque_types { - let a = substitute_value(self.tcx, &result_subst, a); - let b = substitute_value(self.tcx, &result_subst, b); + let a = instantiate_value(self.tcx, &result_args, a); + let b = instantiate_value(self.tcx, &result_args, b); debug!(?a, ?b, "constrain opaque type"); // We use equate here instead of, for example, just registering the // opaque type's hidden value directly, because we may be instantiating @@ -532,7 +537,7 @@ impl<'tcx> InferCtxt<'tcx> { ); } - Ok(InferOk { value: result_subst, obligations }) + Ok(InferOk { value: result_args, obligations }) } /// Given a "guess" at the values for the canonical variables in @@ -540,13 +545,13 @@ impl<'tcx> InferCtxt<'tcx> { /// query result. Often, but not always, this is a no-op, because /// we already found the mapping in the "guessing" step. /// - /// See also: `query_response_substitution_guess` - fn unify_query_response_substitution_guess( + /// See also: [`Self::query_response_instantiation_guess`] + fn unify_query_response_instantiation_guess( &self, cause: &ObligationCause<'tcx>, param_env: ty::ParamEnv<'tcx>, original_values: &OriginalQueryValues<'tcx>, - result_subst: &CanonicalVarValues<'tcx>, + result_args: &CanonicalVarValues<'tcx>, query_response: &Canonical<'tcx, QueryResponse<'tcx, R>>, ) -> InferResult<'tcx, ()> where @@ -554,15 +559,15 @@ impl<'tcx> InferCtxt<'tcx> { { // A closure that yields the result value for the given // canonical variable; this is taken from - // `query_response.var_values` after applying the substitution - // `result_subst`. - let substituted_query_response = |index: BoundVar| -> GenericArg<'tcx> { - query_response.substitute_projected(self.tcx, result_subst, |v| v.var_values[index]) + // `query_response.var_values` after applying the instantiation + // by `result_args`. + let instantiated_query_response = |index: BoundVar| -> GenericArg<'tcx> { + query_response.instantiate_projected(self.tcx, result_args, |v| v.var_values[index]) }; // Unify the original value for each variable with the value - // taken from `query_response` (after applying `result_subst`). - self.unify_canonical_vars(cause, param_env, original_values, substituted_query_response) + // taken from `query_response` (after applying `result_args`). + self.unify_canonical_vars(cause, param_env, original_values, instantiated_query_response) } /// Converts the region constraints resulting from a query into an @@ -571,11 +576,11 @@ impl<'tcx> InferCtxt<'tcx> { &'a self, cause: &'a ObligationCause<'tcx>, param_env: ty::ParamEnv<'tcx>, - unsubstituted_region_constraints: &'a [QueryOutlivesConstraint<'tcx>], - result_subst: &'a CanonicalVarValues<'tcx>, + uninstantiated_region_constraints: &'a [QueryOutlivesConstraint<'tcx>], + result_args: &'a CanonicalVarValues<'tcx>, ) -> impl Iterator> + 'a + Captures<'tcx> { - unsubstituted_region_constraints.iter().map(move |&constraint| { - let predicate = substitute_value(self.tcx, result_subst, constraint); + uninstantiated_region_constraints.iter().map(move |&constraint| { + let predicate = instantiate_value(self.tcx, result_args, constraint); self.query_outlives_constraint_to_obligation(predicate, cause.clone(), param_env) }) } diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 78ef70398e5..0bf4598608f 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -679,7 +679,7 @@ impl<'tcx> InferCtxtBuilder<'tcx> { /// inference context that contains each of the bound values /// within instantiated as a fresh variable. The `f` closure is /// invoked with the new infcx, along with the instantiated value - /// `V` and a substitution `S`. This substitution `S` maps from + /// `V` and a instantiation `S`. This instantiation `S` maps from /// the bound values in `C` to their instantiated values in `V` /// (in other words, `S(C) = V`). pub fn build_with_canonical( @@ -691,8 +691,8 @@ impl<'tcx> InferCtxtBuilder<'tcx> { T: TypeFoldable>, { let infcx = self.build(); - let (value, subst) = infcx.instantiate_canonical_with_fresh_inference_vars(span, canonical); - (infcx, value, subst) + let (value, args) = infcx.instantiate_canonical_with_fresh_inference_vars(span, canonical); + (infcx, value, args) } pub fn build(&mut self) -> InferCtxt<'tcx> { @@ -1194,13 +1194,13 @@ impl<'tcx> InferCtxt<'tcx> { } GenericParamDefKind::Type { .. } => { // Create a type inference variable for the given - // type parameter definition. The substitutions are + // type parameter definition. The generic parameters are // for actual parameters that may be referred to by // the default of this type parameter, if it exists. // e.g., `struct Foo(...);` when // used in a path such as `Foo::::new()` will // use an inference variable for `C` with `[T, U]` - // as the substitutions for the default, `(T, U)`. + // as the generic parameters for the default, `(T, U)`. let ty_var_id = self.inner.borrow_mut().type_variables().new_var( self.universe(), TypeVariableOrigin { @@ -1256,7 +1256,7 @@ impl<'tcx> InferCtxt<'tcx> { ty::Const::new_infer(self.tcx, ty::InferConst::EffectVar(effect_vid), ty).into() } - /// Given a set of generics defined on a type or impl, returns a substitution mapping each + /// Given a set of generics defined on a type or impl, returns the generic parameters mapping each /// type/region parameter to a fresh inference variable. pub fn fresh_args_for_item(&self, span: Span, def_id: DefId) -> GenericArgsRef<'tcx> { GenericArgs::for_item(self.tcx, def_id, |param, _| self.var_for_def(span, param)) @@ -1411,7 +1411,7 @@ impl<'tcx> InferCtxt<'tcx> { T: TypeFoldable>, { if !value.has_infer() { - return value; // Avoid duplicated subst-folding. + return value; // Avoid duplicated type-folding. } let mut r = InferenceLiteralEraser { tcx: self.tcx }; value.fold_with(&mut r) @@ -1458,7 +1458,7 @@ impl<'tcx> InferCtxt<'tcx> { // Instantiates the bound variables in a given binder with fresh inference // variables in the current universe. // - // Use this method if you'd like to find some substitution of the binder's + // Use this method if you'd like to find some generic parameters of the binder's // variables (e.g. during a method call). If there isn't a [`BoundRegionConversionTime`] // that corresponds to your use case, consider whether or not you should // use [`InferCtxt::enter_forall`] instead. @@ -1603,10 +1603,10 @@ impl<'tcx> InferCtxt<'tcx> { /// Resolves and evaluates a constant. /// /// The constant can be located on a trait like `::C`, in which case the given - /// substitutions and environment are used to resolve the constant. Alternatively if the - /// constant has generic parameters in scope the substitutions are used to evaluate the value of + /// generic parameters and environment are used to resolve the constant. Alternatively if the + /// constant has generic parameters in scope the instantiations are used to evaluate the value of /// the constant. For example in `fn foo() { let _ = [0; bar::()]; }` the repeat count - /// constant `bar::()` requires a substitution for `T`, if the substitution for `T` is still + /// constant `bar::()` requires a instantiation for `T`, if the instantiation for `T` is still /// too generic for the constant to be evaluated then `Err(ErrorHandled::TooGeneric)` is /// returned. /// @@ -1652,7 +1652,7 @@ impl<'tcx> InferCtxt<'tcx> { let unevaluated = ty::UnevaluatedConst { def: unevaluated.def, args: args_erased }; // The return value is the evaluated value which doesn't contain any reference to inference - // variables, thus we don't need to substitute back the original values. + // variables, thus we don't need to instantiate back the original values. tcx.const_eval_resolve_for_typeck(param_env_erased, unevaluated, span) } diff --git a/compiler/rustc_infer/src/infer/opaque_types.rs b/compiler/rustc_infer/src/infer/opaque_types.rs index 46c4f80cb0c..ec674407e52 100644 --- a/compiler/rustc_infer/src/infer/opaque_types.rs +++ b/compiler/rustc_infer/src/infer/opaque_types.rs @@ -219,7 +219,7 @@ impl<'tcx> InferCtxt<'tcx> { /// ``` /// /// As indicating in the comments above, each of those references - /// is (in the compiler) basically a substitution (`args`) + /// is (in the compiler) basically generic paramters (`args`) /// applied to the type of a suitable `def_id` (which identifies /// `Foo1` or `Foo2`). /// diff --git a/compiler/rustc_infer/src/infer/outlives/test_type_match.rs b/compiler/rustc_infer/src/infer/outlives/test_type_match.rs index 236dc4ec384..d547f51f381 100644 --- a/compiler/rustc_infer/src/infer/outlives/test_type_match.rs +++ b/compiler/rustc_infer/src/infer/outlives/test_type_match.rs @@ -25,7 +25,7 @@ use crate::infer::region_constraints::VerifyIfEq; /// * `None` if `some_type` cannot be made equal to `test_ty`, /// no matter the values of the variables in `exists`. /// * `Some(r)` with a suitable bound (typically the value of `bound_region`, modulo -/// any bound existential variables, which will be substituted) for the +/// any bound existential variables, which will be instantiated) for the /// type under test. /// /// NB: This function uses a simplistic, syntactic version of type equality. @@ -59,7 +59,7 @@ pub fn extract_verify_if_eq<'tcx>( } } else { // The region does not contain any bound variables, so we don't need - // to do any substitution. + // to do any instantiation. // // Example: // diff --git a/compiler/rustc_infer/src/infer/outlives/verify.rs b/compiler/rustc_infer/src/infer/outlives/verify.rs index 5d2f51c689b..24b351988bf 100644 --- a/compiler/rustc_infer/src/infer/outlives/verify.rs +++ b/compiler/rustc_infer/src/infer/outlives/verify.rs @@ -277,7 +277,7 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { /// ``` /// /// If we were given the `DefId` of `Foo::Bar`, we would return - /// `'a`. You could then apply the substitutions from the + /// `'a`. You could then apply the instantiations from the /// projection to convert this into your namespace. This also /// works if the user writes `where >::Bar: 'a` on /// the trait. In fact, it works by searching for just such a diff --git a/compiler/rustc_infer/src/infer/relate/generalize.rs b/compiler/rustc_infer/src/infer/relate/generalize.rs index 417c8695e24..bc16d613ccb 100644 --- a/compiler/rustc_infer/src/infer/relate/generalize.rs +++ b/compiler/rustc_infer/src/infer/relate/generalize.rs @@ -183,14 +183,14 @@ where fn relate_item_args( &mut self, item_def_id: DefId, - a_subst: ty::GenericArgsRef<'tcx>, - b_subst: ty::GenericArgsRef<'tcx>, + a_arg: ty::GenericArgsRef<'tcx>, + b_arg: ty::GenericArgsRef<'tcx>, ) -> RelateResult<'tcx, ty::GenericArgsRef<'tcx>> { if self.ambient_variance == ty::Variance::Invariant { // Avoid fetching the variance if we are in an invariant // context; no need, and it can induce dependency cycles // (e.g., #41849). - relate::relate_args_invariantly(self, a_subst, b_subst) + relate::relate_args_invariantly(self, a_arg, b_arg) } else { let tcx = self.tcx(); let opt_variances = tcx.variances_of(item_def_id); @@ -198,8 +198,8 @@ where self, item_def_id, opt_variances, - a_subst, - b_subst, + a_arg, + b_arg, false, ) } diff --git a/compiler/rustc_infer/src/infer/type_variable.rs b/compiler/rustc_infer/src/infer/type_variable.rs index 58b8110157b..8b81eac8739 100644 --- a/compiler/rustc_infer/src/infer/type_variable.rs +++ b/compiler/rustc_infer/src/infer/type_variable.rs @@ -118,7 +118,7 @@ pub enum TypeVariableOriginKind { AdjustmentType, /// In type check, when we are type checking a function that - /// returns `-> dyn Foo`, we substitute a type variable for the + /// returns `-> dyn Foo`, we instantiate a type variable with the /// return type for diagnostic purposes. DynReturnFn, LatticeVariable, diff --git a/compiler/rustc_infer/src/traits/util.rs b/compiler/rustc_infer/src/traits/util.rs index 50190058a76..e9df0505cbb 100644 --- a/compiler/rustc_infer/src/traits/util.rs +++ b/compiler/rustc_infer/src/traits/util.rs @@ -285,7 +285,8 @@ impl<'tcx, O: Elaboratable<'tcx>> Elaborator<'tcx, O> { let obligations = predicates.predicates.iter().enumerate().map(|(index, &(clause, span))| { elaboratable.child_with_derived_cause( - clause.subst_supertrait(tcx, &bound_clause.rebind(data.trait_ref)), + clause + .instantiate_supertrait(tcx, &bound_clause.rebind(data.trait_ref)), span, bound_clause.rebind(data), index, diff --git a/compiler/rustc_middle/src/infer/canonical.rs b/compiler/rustc_middle/src/infer/canonical.rs index e544c2a26e8..7b65c11bc3c 100644 --- a/compiler/rustc_middle/src/infer/canonical.rs +++ b/compiler/rustc_middle/src/infer/canonical.rs @@ -53,7 +53,7 @@ impl<'tcx> ty::TypeFoldable> for CanonicalVarInfos<'tcx> { /// A set of values corresponding to the canonical variables from some /// `Canonical`. You can give these values to -/// `canonical_value.substitute` to substitute them into the canonical +/// `canonical_value.instantiate` to instantiate them into the canonical /// value at the right places. /// /// When you canonicalize a value `V`, you get back one of these diff --git a/compiler/rustc_middle/src/mir/interpret/queries.rs b/compiler/rustc_middle/src/mir/interpret/queries.rs index 5f9e7f6e368..e8aca5f2e7d 100644 --- a/compiler/rustc_middle/src/mir/interpret/queries.rs +++ b/compiler/rustc_middle/src/mir/interpret/queries.rs @@ -11,13 +11,13 @@ use rustc_session::lint; use rustc_span::{Span, DUMMY_SP}; impl<'tcx> TyCtxt<'tcx> { - /// Evaluates a constant without providing any substitutions. This is useful to evaluate consts + /// Evaluates a constant without providing any generic parameters. This is useful to evaluate consts /// that can't take any generic arguments like statics, const items or enum discriminants. If a /// generic parameter is used within the constant `ErrorHandled::ToGeneric` will be returned. #[instrument(skip(self), level = "debug")] pub fn const_eval_poly(self, def_id: DefId) -> EvalToConstValueResult<'tcx> { - // In some situations def_id will have substitutions within scope, but they aren't allowed - // to be used. So we can't use `Instance::mono`, instead we feed unresolved substitutions + // In some situations def_id will have generic parameters within scope, but they aren't allowed + // to be used. So we can't use `Instance::mono`, instead we feed unresolved generic parameters // into `const_eval` which will return `ErrorHandled::ToGeneric` if any of them are // encountered. let args = GenericArgs::identity_for_item(self, def_id); @@ -29,10 +29,10 @@ impl<'tcx> TyCtxt<'tcx> { /// Resolves and evaluates a constant. /// /// The constant can be located on a trait like `::C`, in which case the given - /// substitutions and environment are used to resolve the constant. Alternatively if the - /// constant has generic parameters in scope the substitutions are used to evaluate the value of + /// generic parameters and environment are used to resolve the constant. Alternatively if the + /// constant has generic parameters in scope the generic parameters are used to evaluate the value of /// the constant. For example in `fn foo() { let _ = [0; bar::()]; }` the repeat count - /// constant `bar::()` requires a substitution for `T`, if the substitution for `T` is still + /// constant `bar::()` requires a instantiation for `T`, if the instantiation for `T` is still /// too generic for the constant to be evaluated then `Err(ErrorHandled::TooGeneric)` is /// returned. #[instrument(level = "debug", skip(self))] @@ -214,13 +214,13 @@ impl<'tcx> TyCtxtAt<'tcx> { } impl<'tcx> TyCtxtEnsure<'tcx> { - /// Evaluates a constant without providing any substitutions. This is useful to evaluate consts + /// Evaluates a constant without providing any generic parameters. This is useful to evaluate consts /// that can't take any generic arguments like statics, const items or enum discriminants. If a /// generic parameter is used within the constant `ErrorHandled::ToGeneric` will be returned. #[instrument(skip(self), level = "debug")] pub fn const_eval_poly(self, def_id: DefId) { - // In some situations def_id will have substitutions within scope, but they aren't allowed - // to be used. So we can't use `Instance::mono`, instead we feed unresolved substitutions + // In some situations def_id will have generic parameters within scope, but they aren't allowed + // to be used. So we can't use `Instance::mono`, instead we feed unresolved generic parameters // into `const_eval` which will return `ErrorHandled::ToGeneric` if any of them are // encountered. let args = GenericArgs::identity_for_item(self.tcx, def_id); diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs index 6937df7bb18..3cd251caf5e 100644 --- a/compiler/rustc_middle/src/mir/mono.rs +++ b/compiler/rustc_middle/src/mir/mono.rs @@ -186,7 +186,7 @@ impl<'tcx> MonoItem<'tcx> { MonoItem::GlobalAsm(..) => return true, }; - !tcx.subst_and_check_impossible_predicates((def_id, &args)) + !tcx.instantiate_and_check_impossible_predicates((def_id, &args)) } pub fn local_span(&self, tcx: TyCtxt<'tcx>) -> Option { diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 938fba0ed09..50c0f53ae3a 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -2078,9 +2078,9 @@ rustc_queries! { desc { "normalizing `{:?}`", goal.value.value.value } } - query subst_and_check_impossible_predicates(key: (DefId, GenericArgsRef<'tcx>)) -> bool { + query instantiate_and_check_impossible_predicates(key: (DefId, GenericArgsRef<'tcx>)) -> bool { desc { |tcx| - "checking impossible substituted predicates: `{}`", + "checking impossible instantiated predicates: `{}`", tcx.def_path_str(key.0) } } diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index 894acf3c2aa..8e5f026b4c2 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -721,7 +721,7 @@ impl<'tcx, N> ImplSource<'tcx, N> { } /// Identifies a particular impl in the source, along with a set of -/// substitutions from the impl's type/lifetime parameters. The +/// generic parameters from the impl's type/lifetime parameters. The /// `nested` vector corresponds to the nested obligations attached to /// the impl's type parameters. /// diff --git a/compiler/rustc_middle/src/traits/select.rs b/compiler/rustc_middle/src/traits/select.rs index 28eba133c76..e3050007c7b 100644 --- a/compiler/rustc_middle/src/traits/select.rs +++ b/compiler/rustc_middle/src/traits/select.rs @@ -49,7 +49,8 @@ pub type EvaluationCache<'tcx> = Cache< /// parameters don't unify with regular types, but they *can* unify /// with variables from blanket impls, and (unless we know its bounds /// will always be satisfied) picking the blanket impl will be wrong -/// for at least *some* substitutions. To make this concrete, if we have +/// for at least *some* generic parameters. To make this concrete, if +/// we have /// /// ```rust, ignore /// trait AsDebug { type Out: fmt::Debug; fn debug(self) -> Self::Out; } diff --git a/compiler/rustc_middle/src/traits/util.rs b/compiler/rustc_middle/src/traits/util.rs index fd5302dc75b..3419827a742 100644 --- a/compiler/rustc_middle/src/traits/util.rs +++ b/compiler/rustc_middle/src/traits/util.rs @@ -37,7 +37,7 @@ impl<'tcx> Elaborator<'tcx> { let super_predicates = self.tcx.super_predicates_of(trait_ref.def_id()).predicates.iter().filter_map( |&(pred, _)| { - let clause = pred.subst_supertrait(self.tcx, &trait_ref); + let clause = pred.instantiate_supertrait(self.tcx, &trait_ref); self.visited.insert(clause).then_some(clause) }, ); diff --git a/compiler/rustc_middle/src/ty/_match.rs b/compiler/rustc_middle/src/ty/_match.rs index 417f1932c6f..425a2dbd890 100644 --- a/compiler/rustc_middle/src/ty/_match.rs +++ b/compiler/rustc_middle/src/ty/_match.rs @@ -3,7 +3,7 @@ use crate::ty::relate::{self, Relate, RelateResult, TypeRelation}; use crate::ty::{self, InferConst, Ty, TyCtxt}; /// A type "A" *matches* "B" if the fresh types in B could be -/// substituted with values so as to make it equal to A. Matching is +/// instantiated with values so as to make it equal to A. Matching is /// intended to be used only on freshened types, and it basically /// indicates if the non-freshened versions of A and B could have been /// unified. diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs index a930c7e8ebf..23771073745 100644 --- a/compiler/rustc_middle/src/ty/consts.rs +++ b/compiler/rustc_middle/src/ty/consts.rs @@ -235,7 +235,7 @@ impl<'tcx> Const<'tcx> { // FIXME(const_generics): We currently have to special case parameters because `min_const_generics` // does not provide the parents generics to anonymous constants. We still allow generic const // parameters by themselves however, e.g. `N`. These constants would cause an ICE if we were to - // ever try to substitute the generic parameters in their bodies. + // ever try to instantiate the generic parameters in their bodies. match expr.kind { hir::ExprKind::Path(hir::QPath::Resolved( _, diff --git a/compiler/rustc_middle/src/ty/fold.rs b/compiler/rustc_middle/src/ty/fold.rs index 3e64f9a2a90..b57d4f372a7 100644 --- a/compiler/rustc_middle/src/ty/fold.rs +++ b/compiler/rustc_middle/src/ty/fold.rs @@ -418,10 +418,10 @@ impl<'tcx> TyCtxt<'tcx> { // Shifter // // Shifts the De Bruijn indices on all escaping bound vars by a -// fixed amount. Useful in substitution or when otherwise introducing +// fixed amount. Useful in instantiation or when otherwise introducing // a binding level that is not intended to capture the existing bound // vars. See comment on `shift_vars_through_binders` method in -// `subst.rs` for more details. +// `rustc_middle/src/ty/generic_args.rs` for more details. struct Shifter<'tcx> { tcx: TyCtxt<'tcx>, diff --git a/compiler/rustc_middle/src/ty/generic_args.rs b/compiler/rustc_middle/src/ty/generic_args.rs index b9fff660a03..84de12b23a0 100644 --- a/compiler/rustc_middle/src/ty/generic_args.rs +++ b/compiler/rustc_middle/src/ty/generic_args.rs @@ -803,13 +803,13 @@ impl<'tcx, T: TypeFoldable>> ty::EarlyBinder { } /////////////////////////////////////////////////////////////////////////// -// The actual substitution engine itself is a type folder. +// The actual instantiation engine itself is a type folder. struct ArgFolder<'a, 'tcx> { tcx: TyCtxt<'tcx>, args: &'a [GenericArg<'tcx>], - /// Number of region binders we have passed through while doing the substitution + /// Number of region binders we have passed through while doing the instantiation binders_passed: u32, } @@ -834,7 +834,7 @@ impl<'a, 'tcx> TypeFolder> for ArgFolder<'a, 'tcx> { #[inline(never)] fn region_param_out_of_range(data: ty::EarlyParamRegion, args: &[GenericArg<'_>]) -> ! { bug!( - "Region parameter out of range when substituting in region {} (index={}, args = {:?})", + "Region parameter out of range when instantiating in region {} (index={}, args = {:?})", data.name, data.index, args, @@ -845,7 +845,7 @@ impl<'a, 'tcx> TypeFolder> for ArgFolder<'a, 'tcx> { #[inline(never)] fn region_param_invalid(data: ty::EarlyParamRegion, other: GenericArgKind<'_>) -> ! { bug!( - "Unexpected parameter {:?} when substituting in region {} (index={})", + "Unexpected parameter {:?} when instantiating in region {} (index={})", other, data.name, data.index @@ -854,7 +854,7 @@ impl<'a, 'tcx> TypeFolder> for ArgFolder<'a, 'tcx> { // Note: This routine only handles regions that are bound on // type declarations and other outer declarations, not those - // bound in *fn types*. Region substitution of the bound + // bound in *fn types*. Region instantiation of the bound // regions that appear in a function signature is done using // the specialized routine `ty::replace_late_regions()`. match *r { @@ -913,7 +913,7 @@ impl<'a, 'tcx> ArgFolder<'a, 'tcx> { #[inline(never)] fn type_param_expected(&self, p: ty::ParamTy, ty: Ty<'tcx>, kind: GenericArgKind<'tcx>) -> ! { bug!( - "expected type for `{:?}` ({:?}/{}) but found {:?} when substituting, args={:?}", + "expected type for `{:?}` ({:?}/{}) but found {:?} when instantiating, args={:?}", p, ty, p.index, @@ -926,7 +926,7 @@ impl<'a, 'tcx> ArgFolder<'a, 'tcx> { #[inline(never)] fn type_param_out_of_range(&self, p: ty::ParamTy, ty: Ty<'tcx>) -> ! { bug!( - "type parameter `{:?}` ({:?}/{}) out of range when substituting, args={:?}", + "type parameter `{:?}` ({:?}/{}) out of range when instantiating, args={:?}", p, ty, p.index, @@ -955,7 +955,7 @@ impl<'a, 'tcx> ArgFolder<'a, 'tcx> { kind: GenericArgKind<'tcx>, ) -> ! { bug!( - "expected const for `{:?}` ({:?}/{}) but found {:?} when substituting args={:?}", + "expected const for `{:?}` ({:?}/{}) but found {:?} when instantiating args={:?}", p, ct, p.index, @@ -968,7 +968,7 @@ impl<'a, 'tcx> ArgFolder<'a, 'tcx> { #[inline(never)] fn const_param_out_of_range(&self, p: ty::ParamConst, ct: ty::Const<'tcx>) -> ! { bug!( - "const parameter `{:?}` ({:?}/{}) out of range when substituting args={:?}", + "const parameter `{:?}` ({:?}/{}) out of range when instantiating args={:?}", p, ct, p.index, @@ -976,8 +976,8 @@ impl<'a, 'tcx> ArgFolder<'a, 'tcx> { ) } - /// It is sometimes necessary to adjust the De Bruijn indices during substitution. This occurs - /// when we are substituting a type with escaping bound vars into a context where we have + /// It is sometimes necessary to adjust the De Bruijn indices during instantiation. This occurs + /// when we are instantating a type with escaping bound vars into a context where we have /// passed through binders. That's quite a mouthful. Let's see an example: /// /// ``` @@ -997,7 +997,7 @@ impl<'a, 'tcx> ArgFolder<'a, 'tcx> { /// inner one. Therefore, that appearance will have a DebruijnIndex of 2, because we must skip /// over the inner binder (remember that we count De Bruijn indices from 1). However, in the /// definition of `MetaFunc`, the binder is not visible, so the type `&'a i32` will have a - /// De Bruijn index of 1. It's only during the substitution that we can see we must increase the + /// De Bruijn index of 1. It's only during the instantiation that we can see we must increase the /// depth by 1 to account for the binder that we passed through. /// /// As a second example, consider this twist: @@ -1015,7 +1015,7 @@ impl<'a, 'tcx> ArgFolder<'a, 'tcx> { /// // DebruijnIndex of 1 | /// // DebruijnIndex of 2 /// ``` - /// As indicated in the diagram, here the same type `&'a i32` is substituted once, but in the + /// As indicated in the diagram, here the same type `&'a i32` is instantiated once, but in the /// first case we do not increase the De Bruijn index and in the second case we do. The reason /// is that only in the second case have we passed through a fn binder. fn shift_vars_through_binders>>(&self, val: T) -> T { diff --git a/compiler/rustc_middle/src/ty/generics.rs b/compiler/rustc_middle/src/ty/generics.rs index 4821ae3f087..c81d9dfbc7d 100644 --- a/compiler/rustc_middle/src/ty/generics.rs +++ b/compiler/rustc_middle/src/ty/generics.rs @@ -125,7 +125,7 @@ pub struct GenericParamCount { /// Information about the formal type/lifetime parameters associated /// with an item or method. Analogous to `hir::Generics`. /// -/// The ordering of parameters is the same as in `Subst` (excluding child generics): +/// The ordering of parameters is the same as in [`ty::GenericArg`] (excluding child generics): /// `Self` (optionally), `Lifetime` params..., `Type` params... #[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable)] pub struct Generics { @@ -140,7 +140,7 @@ pub struct Generics { pub has_self: bool, pub has_late_bound_regions: Option, - // The index of the host effect when substituted. (i.e. might be index to parent args) + // The index of the host effect when instantiated. (i.e. might be index to parent args) pub host_effect_index: Option, } diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index 8848d216f5b..b49cc51e982 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -19,7 +19,7 @@ use std::fmt; /// /// Monomorphization happens on-the-fly and no monomorphized MIR is ever created. Instead, this type /// simply couples a potentially generic `InstanceDef` with some args, and codegen and const eval -/// will do all required substitution as they run. +/// will do all required instantiations as they run. /// /// Note: the `Lift` impl is currently not used by rustc, but is used by /// rustc_codegen_cranelift when the `jit` feature is enabled. @@ -138,7 +138,7 @@ pub enum InstanceDef<'tcx> { } impl<'tcx> Instance<'tcx> { - /// Returns the `Ty` corresponding to this `Instance`, with generic substitutions applied and + /// Returns the `Ty` corresponding to this `Instance`, with generic instantiations applied and /// lifetimes erased, allowing a `ParamEnv` to be specified for use during normalization. pub fn ty(&self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Ty<'tcx> { let ty = tcx.type_of(self.def.def_id()); @@ -298,11 +298,11 @@ impl<'tcx> InstanceDef<'tcx> { } /// Returns `true` when the MIR body associated with this instance should be monomorphized - /// by its users (e.g. codegen or miri) by substituting the `args` from `Instance` (see + /// by its users (e.g. codegen or miri) by instantiating the `args` from `Instance` (see /// `Instance::args_for_mir_body`). /// /// Otherwise, returns `false` only for some kinds of shims where the construction of the MIR - /// body should perform necessary substitutions. + /// body should perform necessary instantiations. pub fn has_polymorphic_mir_body(&self) -> bool { match *self { InstanceDef::CloneShim(..) @@ -672,13 +672,13 @@ impl<'tcx> Instance<'tcx> { /// Depending on the kind of `InstanceDef`, the MIR body associated with an /// instance is expressed in terms of the generic parameters of `self.def_id()`, and in other - /// cases the MIR body is expressed in terms of the types found in the substitution array. - /// In the former case, we want to substitute those generic types and replace them with the + /// cases the MIR body is expressed in terms of the types found in the generic parameter array. + /// In the former case, we want to instantiate those generic types and replace them with the /// values from the args when monomorphizing the function body. But in the latter case, we - /// don't want to do that substitution, since it has already been done effectively. + /// don't want to do that instantiation, since it has already been done effectively. /// /// This function returns `Some(args)` in the former case and `None` otherwise -- i.e., if - /// this function returns `None`, then the MIR body does not require substitution during + /// this function returns `None`, then the MIR body does not require instantiation during /// codegen. fn args_for_mir_body(&self) -> Option> { self.def.has_polymorphic_mir_body().then_some(self.args) diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index c9137f374a2..6370c8bd5bb 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -728,7 +728,7 @@ impl From for TermVid { /// the `GenericPredicates` are expressed in terms of the bound type /// parameters of the impl/trait/whatever, an `InstantiatedPredicates` instance /// represented a set of bounds for some particular instantiation, -/// meaning that the generic parameters have been substituted with +/// meaning that the generic parameters have been instantiated with /// their values. /// /// Example: @@ -1654,7 +1654,7 @@ impl<'tcx> TyCtxt<'tcx> { } } - /// Returns the possibly-auto-generated MIR of a `(DefId, Subst)` pair. + /// Returns the possibly-auto-generated MIR of a [`ty::InstanceDef`]. #[instrument(skip(self), level = "debug")] pub fn instance_mir(self, instance: ty::InstanceDef<'tcx>) -> &'tcx Body<'tcx> { match instance { diff --git a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs index 27c436c82f5..d4c8f5900f9 100644 --- a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs +++ b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs @@ -135,7 +135,7 @@ impl<'tcx> TyCtxt<'tcx> { } /// Monomorphizes a type from the AST by first applying the - /// in-scope substitutions and then normalizing any associated + /// in-scope instantiations and then normalizing any associated /// types. /// Panics if normalization fails. In case normalization might fail /// use `try_instantiate_and_normalize_erasing_regions` instead. @@ -149,12 +149,12 @@ impl<'tcx> TyCtxt<'tcx> { where T: TypeFoldable>, { - let substituted = value.instantiate(self, param_args); - self.normalize_erasing_regions(param_env, substituted) + let instantiated = value.instantiate(self, param_args); + self.normalize_erasing_regions(param_env, instantiated) } /// Monomorphizes a type from the AST by first applying the - /// in-scope substitutions and then trying to normalize any associated + /// in-scope instantiations and then trying to normalize any associated /// types. Contrary to `instantiate_and_normalize_erasing_regions` this does /// not assume that normalization succeeds. #[instrument(level = "debug", skip(self))] @@ -167,8 +167,8 @@ impl<'tcx> TyCtxt<'tcx> { where T: TypeFoldable>, { - let substituted = value.instantiate(self, param_args); - self.try_normalize_erasing_regions(param_env, substituted) + let instantiated = value.instantiate(self, param_args); + self.try_normalize_erasing_regions(param_env, instantiated) } } diff --git a/compiler/rustc_middle/src/ty/opaque_types.rs b/compiler/rustc_middle/src/ty/opaque_types.rs index 5ca88ec3102..fa5265c58e4 100644 --- a/compiler/rustc_middle/src/ty/opaque_types.rs +++ b/compiler/rustc_middle/src/ty/opaque_types.rs @@ -164,9 +164,9 @@ impl<'tcx> TypeFolder> for ReverseMapper<'tcx> { } ty::Param(param) => { - // Look it up in the substitution list. + // Look it up in the generic parameters list. match self.map.get(&ty.into()).map(|k| k.unpack()) { - // Found it in the substitution list; replace with the parameter from the + // Found it in the generic parameters list; replace with the parameter from the // opaque type. Some(GenericArgKind::Type(t1)) => t1, Some(u) => panic!("type mapped to unexpected kind: {u:?}"), @@ -199,9 +199,9 @@ impl<'tcx> TypeFolder> for ReverseMapper<'tcx> { // Find a const parameter match ct.kind() { ty::ConstKind::Param(..) => { - // Look it up in the substitution list. + // Look it up in the generic parameters list. match self.map.get(&ct.into()).map(|k| k.unpack()) { - // Found it in the substitution list, replace with the parameter from the + // Found it in the generic parameters list, replace with the parameter from the // opaque type. Some(GenericArgKind::Const(c1)) => c1, Some(u) => panic!("const mapped to unexpected kind: {u:?}"), diff --git a/compiler/rustc_middle/src/ty/predicate.rs b/compiler/rustc_middle/src/ty/predicate.rs index 7c5b49512ae..200811940ed 100644 --- a/compiler/rustc_middle/src/ty/predicate.rs +++ b/compiler/rustc_middle/src/ty/predicate.rs @@ -323,7 +323,7 @@ impl<'tcx> ty::List> { /// and `U` as parameter 1. /// /// Trait references also appear in object types like `Foo`, but in -/// that case the `Self` parameter is absent from the substitutions. +/// that case the `Self` parameter is absent from the generic parameters. #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, TyEncodable, TyDecodable)] #[derive(HashStable, TypeFoldable, TypeVisitable, Lift)] pub struct TraitRef<'tcx> { @@ -406,7 +406,7 @@ impl<'tcx> IntoDiagnosticArg for TraitRef<'tcx> { /// ```ignore (illustrative) /// exists T. T: Trait<'a, 'b, X, Y> /// ``` -/// The substitutions don't include the erased `Self`, only trait +/// The generic parameters don't include the erased `Self`, only trait /// type and lifetime parameters (`[X, Y]` and `['a, 'b]` above). #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, TyEncodable, TyDecodable)] #[derive(HashStable, TypeFoldable, TypeVisitable, Lift)] @@ -481,8 +481,8 @@ impl<'tcx> ExistentialProjection<'tcx> { /// reference. pub fn trait_ref(&self, tcx: TyCtxt<'tcx>) -> ty::ExistentialTraitRef<'tcx> { let def_id = tcx.parent(self.def_id); - let subst_count = tcx.generics_of(def_id).count() - 1; - let args = tcx.mk_args(&self.args[..subst_count]); + let args_count = tcx.generics_of(def_id).count() - 1; + let args = tcx.mk_args(&self.args[..args_count]); ty::ExistentialTraitRef { def_id, args } } @@ -534,12 +534,12 @@ impl<'tcx> PolyExistentialProjection<'tcx> { } impl<'tcx> Clause<'tcx> { - /// Performs a substitution suitable for going from a + /// Performs a instantiation suitable for going from a /// poly-trait-ref to supertraits that must hold if that /// poly-trait-ref holds. This is slightly different from a normal - /// substitution in terms of what happens with bound regions. See + /// instantiation in terms of what happens with bound regions. See /// lengthy comment below for details. - pub fn subst_supertrait( + pub fn instantiate_supertrait( self, tcx: TyCtxt<'tcx>, trait_ref: &ty::PolyTraitRef<'tcx>, @@ -556,7 +556,7 @@ impl<'tcx> Clause<'tcx> { // we can deduce that `for<'x> T: Bar<'x,'x>`. Basically, if we // knew that `Foo<'x>` (for any 'x) then we also know that // `Bar<'x,'x>` (for any 'x). This more-or-less falls out from - // normal substitution. + // normal instantiation. // // In terms of why this is sound, the idea is that whenever there // is an impl of `T:Foo<'a>`, it must show that `T:Bar<'a,'a>` @@ -582,7 +582,7 @@ impl<'tcx> Clause<'tcx> { // - We start out with `for<'x> T: Foo1<'x>`. In this case, `'x` // has a De Bruijn index of 1. We want to produce `for<'x,'b> T: Bar1<'x,'b>`, // where both `'x` and `'b` would have a DB index of 1. - // The substitution from the input trait-ref is therefore going to be + // The instantiation from the input trait-ref is therefore going to be // `'a => 'x` (where `'x` has a DB index of 1). // - The supertrait-ref is `for<'b> Bar1<'a,'b>`, where `'a` is an // early-bound parameter and `'b` is a late-bound parameter with a @@ -591,17 +591,17 @@ impl<'tcx> Clause<'tcx> { // a DB index of 1, and thus we'll have `for<'x,'b> Bar1<'x,'b>` // just as we wanted. // - // There is only one catch. If we just apply the substitution `'a - // => 'x` to `for<'b> Bar1<'a,'b>`, the substitution code will - // adjust the DB index because we substituting into a binder (it + // There is only one catch. If we just apply the instantiation `'a + // => 'x` to `for<'b> Bar1<'a,'b>`, the instantiation code will + // adjust the DB index because we instantiating into a binder (it // tries to be so smart...) resulting in `for<'x> for<'b> // Bar1<'x,'b>` (we have no syntax for this, so use your // imagination). Basically the 'x will have DB index of 2 and 'b // will have DB index of 1. Not quite what we want. So we apply - // the substitution to the *contents* of the trait reference, + // the instantiation to the *contents* of the trait reference, // rather than the trait reference itself (put another way, the - // substitution code expects equal binding levels in the values - // from the substitution and the value being substituted into, and + // instantiation code expects equal binding levels in the values + // from the instantiation and the value being instantiated into, and // this trick achieves that). // Working through the second example: diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index f592acd4b6f..a3d5f1f1955 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -208,7 +208,7 @@ impl<'tcx> ClosureArgs<'tcx> { } } - /// Returns the substitutions of the closure's parent. + /// Returns the generic parameters of the closure's parent. pub fn parent_args(self) -> &'tcx [GenericArg<'tcx>] { self.split().parent_args } @@ -615,7 +615,7 @@ impl<'tcx> CoroutineArgs<'tcx> { } } - /// Returns the substitutions of the coroutine's parent. + /// Returns the generic parameters of the coroutine's parent. pub fn parent_args(self) -> &'tcx [GenericArg<'tcx>] { self.split().parent_args } @@ -819,7 +819,7 @@ impl<'tcx> UpvarArgs<'tcx> { /// inherited from the item that defined the inline const, /// - R represents the type of the constant. /// -/// When the inline const is instantiated, `R` is substituted as the actual inferred +/// When the inline const is instantiated, `R` is instantiated as the actual inferred /// type of the constant. The reason that `R` is represented as an extra type parameter /// is the same reason that [`ClosureArgs`] have `CS` and `U` as type parameters: /// inline const can reference lifetimes that are internal to the creating function. @@ -858,7 +858,7 @@ impl<'tcx> InlineConstArgs<'tcx> { } } - /// Returns the substitutions of the inline const's parent. + /// Returns the generic parameters of the inline const's parent. pub fn parent_args(self) -> &'tcx [GenericArg<'tcx>] { self.split().parent_args } @@ -1105,13 +1105,13 @@ where pub struct AliasTy<'tcx> { /// The parameters of the associated or opaque item. /// - /// For a projection, these are the substitutions for the trait and the - /// GAT substitutions, if there are any. + /// For a projection, these are the generic parameters for the trait and the + /// GAT parameters, if there are any. /// - /// For an inherent projection, they consist of the self type and the GAT substitutions, + /// For an inherent projection, they consist of the self type and the GAT parameters, /// if there are any. /// - /// For RPIT the substitutions are for the generics of the function, + /// For RPIT the generic parameters are for the generics of the function, /// while for TAIT it is used for the generic parameters of the alias. pub args: GenericArgsRef<'tcx>, @@ -1235,15 +1235,15 @@ impl<'tcx> AliasTy<'tcx> { /// The following methods work only with inherent associated type projections. impl<'tcx> AliasTy<'tcx> { - /// Transform the substitutions to have the given `impl` args as the base and the GAT args on top of that. + /// Transform the generic parameters to have the given `impl` args as the base and the GAT args on top of that. /// /// Does the following transformation: /// /// ```text /// [Self, P_0...P_m] -> [I_0...I_n, P_0...P_m] /// - /// I_i impl subst - /// P_j GAT subst + /// I_i impl args + /// P_j GAT args /// ``` pub fn rebase_inherent_args_onto_impl( self, @@ -1690,7 +1690,7 @@ impl<'tcx> Ty<'tcx> { debug_assert_eq!( closure_args.len(), tcx.generics_of(tcx.typeck_root_def_id(def_id)).count() + 3, - "closure constructed with incorrect substitutions" + "closure constructed with incorrect generic parameters" ); Ty::new(tcx, Closure(def_id, closure_args)) } @@ -1704,7 +1704,7 @@ impl<'tcx> Ty<'tcx> { debug_assert_eq!( closure_args.len(), tcx.generics_of(tcx.typeck_root_def_id(def_id)).count() + 5, - "closure constructed with incorrect substitutions" + "closure constructed with incorrect generic parameters" ); Ty::new(tcx, CoroutineClosure(def_id, closure_args)) } @@ -1718,7 +1718,7 @@ impl<'tcx> Ty<'tcx> { debug_assert_eq!( coroutine_args.len(), tcx.generics_of(tcx.typeck_root_def_id(def_id)).count() + 6, - "coroutine constructed with incorrect number of substitutions" + "coroutine constructed with incorrect number of generic parameters" ); Ty::new(tcx, Coroutine(def_id, coroutine_args)) } @@ -2530,7 +2530,7 @@ impl<'tcx> Ty<'tcx> { } /// Returns `true` when the outermost type cannot be further normalized, - /// resolved, or substituted. This includes all primitive types, but also + /// resolved, or instantiated. This includes all primitive types, but also /// things like ADTs and trait objects, sice even if their arguments or /// nested types may be further simplified, the outermost [`TyKind`] or /// type constructor remains the same. diff --git a/compiler/rustc_middle/src/ty/typeck_results.rs b/compiler/rustc_middle/src/ty/typeck_results.rs index ad41a674dd8..0fae0c55dcf 100644 --- a/compiler/rustc_middle/src/ty/typeck_results.rs +++ b/compiler/rustc_middle/src/ty/typeck_results.rs @@ -49,19 +49,19 @@ pub struct TypeckResults<'tcx> { /// typeck::check::fn_ctxt for details. node_types: ItemLocalMap>, - /// Stores the type parameters which were substituted to obtain the type + /// Stores the type parameters which were instantiated to obtain the type /// of this node. This only applies to nodes that refer to entities /// parameterized by type parameters, such as generic fns, types, or /// other items. node_args: ItemLocalMap>, /// This will either store the canonicalized types provided by the user - /// or the substitutions that the user explicitly gave (if any) attached + /// or the generic parameters that the user explicitly gave (if any) attached /// to `id`. These will not include any inferred values. The canonical form /// is used to capture things like `_` or other unspecified values. /// /// For example, if the user wrote `foo.collect::>()`, then the - /// canonical substitutions would include only `for { Vec }`. + /// canonical generic parameters would include only `for { Vec }`. /// /// See also `AscribeUserType` statement in MIR. user_provided_types: ItemLocalMap>, @@ -329,7 +329,7 @@ impl<'tcx> TypeckResults<'tcx> { } /// Returns the type of a pattern as a monotype. Like [`expr_ty`], this function - /// doesn't provide type parameter substitutions. + /// doesn't provide type parameter args. /// /// [`expr_ty`]: TypeckResults::expr_ty pub fn pat_ty(&self, pat: &hir::Pat<'_>) -> Ty<'tcx> { @@ -341,9 +341,9 @@ impl<'tcx> TypeckResults<'tcx> { /// NB (1): This is the PRE-ADJUSTMENT TYPE for the expression. That is, in /// some cases, we insert `Adjustment` annotations such as auto-deref or /// auto-ref. The type returned by this function does not consider such - /// adjustments. See `expr_ty_adjusted()` instead. + /// adjustments. See [`Self::expr_ty_adjusted`] instead. /// - /// NB (2): This type doesn't provide type parameter substitutions; e.g., if you + /// NB (2): This type doesn't provide type parameter args; e.g., if you /// ask for the type of `id` in `id(3)`, it will return `fn(&isize) -> isize` /// instead of `fn(ty) -> T with T = isize`. pub fn expr_ty(&self, expr: &hir::Expr<'_>) -> Ty<'tcx> { @@ -608,7 +608,7 @@ pub enum UserType<'tcx> { Ty(Ty<'tcx>), /// The canonical type is the result of `type_of(def_id)` with the - /// given substitutions applied. + /// given generic parameters applied. TypeOf(DefId, UserArgs<'tcx>), } @@ -617,7 +617,7 @@ pub trait IsIdentity { } impl<'tcx> IsIdentity for CanonicalUserType<'tcx> { - /// Returns `true` if this represents a substitution of the form `[?0, ?1, ?2]`, + /// Returns `true` if this represents the generic parameters of the form `[?0, ?1, ?2]`, /// i.e., each thing is mapped to a canonical variable with the same index. fn is_identity(&self) -> bool { match self.value { @@ -631,7 +631,7 @@ impl<'tcx> IsIdentity for CanonicalUserType<'tcx> { match kind.unpack() { GenericArgKind::Type(ty) => match ty.kind() { ty::Bound(debruijn, b) => { - // We only allow a `ty::INNERMOST` index in substitutions. + // We only allow a `ty::INNERMOST` index in generic parameters. assert_eq!(*debruijn, ty::INNERMOST); cvar == b.var } @@ -640,7 +640,7 @@ impl<'tcx> IsIdentity for CanonicalUserType<'tcx> { GenericArgKind::Lifetime(r) => match *r { ty::ReBound(debruijn, br) => { - // We only allow a `ty::INNERMOST` index in substitutions. + // We only allow a `ty::INNERMOST` index in generic parameters. assert_eq!(debruijn, ty::INNERMOST); cvar == br.var } @@ -649,7 +649,7 @@ impl<'tcx> IsIdentity for CanonicalUserType<'tcx> { GenericArgKind::Const(ct) => match ct.kind() { ty::ConstKind::Bound(debruijn, b) => { - // We only allow a `ty::INNERMOST` index in substitutions. + // We only allow a `ty::INNERMOST` index in generic parameters. assert_eq!(debruijn, ty::INNERMOST); cvar == b } diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index 35adcc33480..61b2977a45f 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -801,7 +801,7 @@ impl<'tcx> Cx<'tcx> { let user_provided_type = match res { // A reference to something callable -- e.g., a fn, method, or // a tuple-struct or tuple-variant. This has the type of a - // `Fn` but with the user-given substitutions. + // `Fn` but with the user-given generic parameters. Res::Def(DefKind::Fn, _) | Res::Def(DefKind::AssocFn, _) | Res::Def(DefKind::Ctor(_, CtorKind::Fn), _) @@ -812,7 +812,7 @@ impl<'tcx> Cx<'tcx> { // A unit struct/variant which is used as a value (e.g., // `None`). This has the type of the enum/struct that defines - // this variant -- but with the substitutions given by the + // this variant -- but with the generic parameters given by the // user. Res::Def(DefKind::Ctor(_, CtorKind::Const), _) => { self.user_args_applied_to_ty_of_hir_id(hir_id).map(Box::new) diff --git a/compiler/rustc_mir_build/src/thir/util.rs b/compiler/rustc_mir_build/src/thir/util.rs index 9106b4d33fc..52c9cf14ac8 100644 --- a/compiler/rustc_mir_build/src/thir/util.rs +++ b/compiler/rustc_mir_build/src/thir/util.rs @@ -7,7 +7,7 @@ pub(crate) trait UserAnnotatedTyHelpers<'tcx> { fn typeck_results(&self) -> &ty::TypeckResults<'tcx>; /// Looks up the type associated with this hir-id and applies the - /// user-given substitutions; the hir-id must map to a suitable + /// user-given generic parameters; the hir-id must map to a suitable /// type. fn user_args_applied_to_ty_of_hir_id( &self, diff --git a/compiler/rustc_mir_transform/src/add_retag.rs b/compiler/rustc_mir_transform/src/add_retag.rs index 94077c63057..430d9572e75 100644 --- a/compiler/rustc_mir_transform/src/add_retag.rs +++ b/compiler/rustc_mir_transform/src/add_retag.rs @@ -36,10 +36,10 @@ fn may_contain_reference<'tcx>(ty: Ty<'tcx>, depth: u32, tcx: TyCtxt<'tcx>) -> b ty::Tuple(tys) => { depth == 0 || tys.iter().any(|ty| may_contain_reference(ty, depth - 1, tcx)) } - ty::Adt(adt, subst) => { + ty::Adt(adt, args) => { depth == 0 || adt.variants().iter().any(|v| { - v.fields.iter().any(|f| may_contain_reference(f.ty(tcx, subst), depth - 1, tcx)) + v.fields.iter().any(|f| may_contain_reference(f.ty(tcx, args), depth - 1, tcx)) }) } // Conservative fallback diff --git a/compiler/rustc_mir_transform/src/deduce_param_attrs.rs b/compiler/rustc_mir_transform/src/deduce_param_attrs.rs index a6750911394..ca63f5550ae 100644 --- a/compiler/rustc_mir_transform/src/deduce_param_attrs.rs +++ b/compiler/rustc_mir_transform/src/deduce_param_attrs.rs @@ -205,8 +205,8 @@ pub fn deduced_param_attrs<'tcx>( |(arg_index, local_decl)| DeducedParamAttrs { read_only: !deduce_read_only.mutable_args.contains(arg_index) // We must normalize here to reveal opaques and normalize - // their substs, otherwise we'll see exponential blow-up in - // compile times: #113372 + // their generic parameters, otherwise we'll see exponential + // blow-up in compile times: #113372 && tcx .normalize_erasing_regions(param_env, local_decl.ty) .is_freeze(tcx, param_env), diff --git a/compiler/rustc_mir_transform/src/function_item_references.rs b/compiler/rustc_mir_transform/src/function_item_references.rs index f413bd9b311..e935dc7f5eb 100644 --- a/compiler/rustc_mir_transform/src/function_item_references.rs +++ b/compiler/rustc_mir_transform/src/function_item_references.rs @@ -63,7 +63,7 @@ impl<'tcx> Visitor<'tcx> for FunctionItemRefChecker<'_, 'tcx> { impl<'tcx> FunctionItemRefChecker<'_, 'tcx> { /// Emits a lint for function reference arguments bound by `fmt::Pointer` in calls to the - /// function defined by `def_id` with the substitutions `args_ref`. + /// function defined by `def_id` with the generic parameters `args_ref`. fn check_bound_args( &self, def_id: DefId, @@ -83,11 +83,11 @@ impl<'tcx> FunctionItemRefChecker<'_, 'tcx> { for inner_ty in arg_def.walk().filter_map(|arg| arg.as_type()) { // If the inner type matches the type bound by `Pointer` if inner_ty == bound_ty { - // Do a substitution using the parameters from the callsite - let subst_ty = + // Do an instantiation using the parameters from the callsite + let instantiated_ty = EarlyBinder::bind(inner_ty).instantiate(self.tcx, args_ref); if let Some((fn_id, fn_args)) = - FunctionItemRefChecker::is_fn_ref(subst_ty) + FunctionItemRefChecker::is_fn_ref(instantiated_ty) { let mut span = self.nth_arg_span(args, arg_num); if span.from_expansion() { diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index 2c7ae53055f..8d4afd5b5dc 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -853,10 +853,10 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { fn simplify_discriminant(&mut self, place: VnIndex) -> Option { if let Value::Aggregate(enum_ty, variant, _) = *self.get(place) - && let AggregateTy::Def(enum_did, enum_substs) = enum_ty + && let AggregateTy::Def(enum_did, enum_args) = enum_ty && let DefKind::Enum = self.tcx.def_kind(enum_did) { - let enum_ty = self.tcx.type_of(enum_did).instantiate(self.tcx, enum_substs); + let enum_ty = self.tcx.type_of(enum_did).instantiate(self.tcx, enum_args); let discr = self.ecx.discriminant_for_variant(enum_ty, variant).ok()?; return Some(self.insert_scalar(discr.to_scalar(), discr.layout.ty)); } @@ -899,13 +899,11 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { assert!(!fields.is_empty()); (AggregateTy::Tuple, FIRST_VARIANT) } - AggregateKind::Closure(did, substs) - | AggregateKind::CoroutineClosure(did, substs) - | AggregateKind::Coroutine(did, substs) => { - (AggregateTy::Def(did, substs), FIRST_VARIANT) - } - AggregateKind::Adt(did, variant_index, substs, _, None) => { - (AggregateTy::Def(did, substs), variant_index) + AggregateKind::Closure(did, args) + | AggregateKind::CoroutineClosure(did, args) + | AggregateKind::Coroutine(did, args) => (AggregateTy::Def(did, args), FIRST_VARIANT), + AggregateKind::Adt(did, variant_index, args, _, None) => { + (AggregateTy::Def(did, args), variant_index) } // Do not track unions. AggregateKind::Adt(_, _, _, _, Some(_)) => return None, diff --git a/compiler/rustc_mir_transform/src/inline/cycle.rs b/compiler/rustc_mir_transform/src/inline/cycle.rs index 5b03bc361dd..f2b6dcac586 100644 --- a/compiler/rustc_mir_transform/src/inline/cycle.rs +++ b/compiler/rustc_mir_transform/src/inline/cycle.rs @@ -80,7 +80,7 @@ pub(crate) fn mir_callgraph_reachable<'tcx>( } // These have no own callable MIR. InstanceDef::Intrinsic(_) | InstanceDef::Virtual(..) => continue, - // These have MIR and if that MIR is inlined, substituted and then inlining is run + // These have MIR and if that MIR is inlined, instantiated and then inlining is run // again, a function item can end up getting inlined. Thus we'll be able to cause // a cycle that way InstanceDef::VTableShim(_) @@ -95,7 +95,7 @@ pub(crate) fn mir_callgraph_reachable<'tcx>( // This shim does not call any other functions, thus there can be no recursion. InstanceDef::FnPtrAddrShim(..) => continue, InstanceDef::DropGlue(..) => { - // FIXME: A not fully substituted drop shim can cause ICEs if one attempts to + // FIXME: A not fully instantiated drop shim can cause ICEs if one attempts to // have its MIR built. Likely oli-obk just screwed up the `ParamEnv`s, so this // needs some more analysis. if callee.has_param() { diff --git a/compiler/rustc_mir_transform/src/instsimplify.rs b/compiler/rustc_mir_transform/src/instsimplify.rs index f65eb5cbea9..75073537f5f 100644 --- a/compiler/rustc_mir_transform/src/instsimplify.rs +++ b/compiler/rustc_mir_transform/src/instsimplify.rs @@ -211,7 +211,7 @@ impl<'tcx> InstSimplifyContext<'tcx, '_> { // Only bother looking more if it's easy to know what we're calling let Some((fn_def_id, fn_args)) = func.const_fn_def() else { return }; - // Clone needs one subst, so we can cheaply rule out other stuff + // Clone needs one arg, so we can cheaply rule out other stuff if fn_args.len() != 1 { return; } diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index 72d9ffe8ca5..9f30f2836f1 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -436,7 +436,7 @@ fn mir_drops_elaborated_and_const_checked(tcx: TyCtxt<'_>, def: LocalDefId) -> & // // We manually filter the predicates, skipping anything that's not // "global". We are in a potentially generic context - // (e.g. we are evaluating a function without substituting generic + // (e.g. we are evaluating a function without instantiating generic // parameters, so this filtering serves two purposes: // // 1. We skip evaluating any predicates that we would @@ -576,10 +576,10 @@ fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { &inline::Inline, // Code from other crates may have storage markers, so this needs to happen after inlining. &remove_storage_markers::RemoveStorageMarkers, - // Inlining and substitution may introduce ZST and useless drops. + // Inlining and instantiation may introduce ZST and useless drops. &remove_zsts::RemoveZsts, &remove_unneeded_drops::RemoveUnneededDrops, - // Type substitution may create uninhabited enums. + // Type instantiation may create uninhabited enums. &uninhabited_enum_branching::UninhabitedEnumBranching, &unreachable_prop::UnreachablePropagation, &o1(simplify::SimplifyCfg::AfterUninhabitedEnumBranching), @@ -673,7 +673,7 @@ fn inner_optimized_mir(tcx: TyCtxt<'_>, did: LocalDefId) -> Body<'_> { } /// Fetch all the promoteds of an item and prepare their MIR bodies to be ready for -/// constant evaluation once all substitutions become known. +/// constant evaluation once all generic parameters become known. fn promoted_mir(tcx: TyCtxt<'_>, def: LocalDefId) -> &IndexVec> { if tcx.is_constructor(def.to_def_id()) { return tcx.arena.alloc(IndexVec::new()); diff --git a/compiler/rustc_mir_transform/src/ref_prop.rs b/compiler/rustc_mir_transform/src/ref_prop.rs index 05a3ac3cc75..d5642be5513 100644 --- a/compiler/rustc_mir_transform/src/ref_prop.rs +++ b/compiler/rustc_mir_transform/src/ref_prop.rs @@ -44,7 +44,7 @@ use crate::ssa::{SsaLocals, StorageLiveLocals}; /// /// # Liveness /// -/// When performing a substitution, we must take care not to introduce uses of dangling locals. +/// When performing an instantiation, we must take care not to introduce uses of dangling locals. /// To ensure this, we walk the body with the `MaybeStorageDead` dataflow analysis: /// - if we want to replace `*x` by reborrow `*y` and `y` may be dead, we allow replacement and /// mark storage statements on `y` for removal; @@ -55,7 +55,7 @@ use crate::ssa::{SsaLocals, StorageLiveLocals}; /// /// For `&mut` borrows, we also need to preserve the uniqueness property: /// we must avoid creating a state where we interleave uses of `*_1` and `_2`. -/// To do it, we only perform full substitution of mutable borrows: +/// To do it, we only perform full instantiation of mutable borrows: /// we replace either all or none of the occurrences of `*_1`. /// /// Some care has to be taken when `_1` is copied in other locals. @@ -63,10 +63,10 @@ use crate::ssa::{SsaLocals, StorageLiveLocals}; /// _3 = *_1; /// _4 = _1 /// _5 = *_4 -/// In such cases, fully substituting `_1` means fully substituting all of the copies. +/// In such cases, fully instantiating `_1` means fully instantiating all of the copies. /// /// For immutable borrows, we do not need to preserve such uniqueness property, -/// so we perform all the possible substitutions without removing the `_1 = &_2` statement. +/// so we perform all the possible instantiations without removing the `_1 = &_2` statement. pub struct ReferencePropagation; impl<'tcx> MirPass<'tcx> for ReferencePropagation { diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs index 860d280be29..75613a2c555 100644 --- a/compiler/rustc_mir_transform/src/shim.rs +++ b/compiler/rustc_mir_transform/src/shim.rs @@ -477,7 +477,7 @@ struct CloneShimBuilder<'tcx> { impl<'tcx> CloneShimBuilder<'tcx> { fn new(tcx: TyCtxt<'tcx>, def_id: DefId, self_ty: Ty<'tcx>) -> Self { - // we must subst the self_ty because it's + // we must instantiate the self_ty because it's // otherwise going to be TySelf and we can't index // or access fields of a Place of type TySelf. let sig = tcx.fn_sig(def_id).instantiate(tcx, &[self_ty.into()]); @@ -716,8 +716,8 @@ fn build_call_shim<'tcx>( call_kind: CallKind<'tcx>, ) -> Body<'tcx> { // `FnPtrShim` contains the fn pointer type that a call shim is being built for - this is used - // to substitute into the signature of the shim. It is not necessary for users of this - // MIR body to perform further substitutions (see `InstanceDef::has_polymorphic_mir_body`). + // to instantiate into the signature of the shim. It is not necessary for users of this + // MIR body to perform further instantiations (see `InstanceDef::has_polymorphic_mir_body`). let (sig_args, untuple_args) = if let ty::InstanceDef::FnPtrShim(_, ty) = instance { let sig = tcx.instantiate_bound_regions_with_erased(ty.fn_sig(tcx)); diff --git a/compiler/rustc_mir_transform/src/ssa.rs b/compiler/rustc_mir_transform/src/ssa.rs index 1ed3b14e755..e4fdbd6ae69 100644 --- a/compiler/rustc_mir_transform/src/ssa.rs +++ b/compiler/rustc_mir_transform/src/ssa.rs @@ -170,7 +170,7 @@ impl SsaLocals { /// _c => _a /// _d => _a // transitively through _c /// - /// Exception: we do not see through the return place, as it cannot be substituted. + /// Exception: we do not see through the return place, as it cannot be instantiated. pub fn copy_classes(&self) -> &IndexSlice { &self.copy_classes } diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 149e4c2cb08..6dde7872f56 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -62,7 +62,7 @@ //! syntactic items in the source code. We find them by walking the HIR of the //! crate, and whenever we hit upon a public function, method, or static item, //! we create a mono item consisting of the items DefId and, since we only -//! consider non-generic items, an empty type-substitution set. (In eager +//! consider non-generic items, an empty type-parameters set. (In eager //! collection mode, during incremental compilation, all non-generic functions //! are considered as roots, as well as when the `-Clink-dead-code` option is //! specified. Functions marked `#[no_mangle]` and functions called by inlinable @@ -1383,11 +1383,11 @@ fn create_mono_items_for_default_impls<'tcx>( // items, we never actually check that the predicates of this impl are satisfied // in a empty reveal-all param env (i.e. with no assumptions). // - // Even though this impl has no type or const substitutions, because we don't + // Even though this impl has no type or const generic parameters, because we don't // consider higher-ranked predicates such as `for<'a> &'a mut [u8]: Copy` to // be trivially false. We must now check that the impl has no impossible-to-satisfy // predicates. - if tcx.subst_and_check_impossible_predicates((item.owner_id.to_def_id(), impl_args)) { + if tcx.instantiate_and_check_impossible_predicates((item.owner_id.to_def_id(), impl_args)) { return; } @@ -1404,7 +1404,7 @@ fn create_mono_items_for_default_impls<'tcx>( } // As mentioned above, the method is legal to eagerly instantiate if it - // only has lifetime substitutions. This is validated by + // only has lifetime generic parameters. This is validated by let args = trait_ref.args.extend_to(tcx, method.def_id, only_region_params); let instance = ty::Instance::expect_resolve(tcx, param_env, method.def_id, args); diff --git a/compiler/rustc_monomorphize/src/polymorphize.rs b/compiler/rustc_monomorphize/src/polymorphize.rs index 009bd0b97b6..fb42532e247 100644 --- a/compiler/rustc_monomorphize/src/polymorphize.rs +++ b/compiler/rustc_monomorphize/src/polymorphize.rs @@ -90,7 +90,7 @@ fn should_polymorphize<'tcx>( def_id: DefId, instance: ty::InstanceDef<'tcx>, ) -> bool { - // If an instance's MIR body is not polymorphic then the modified substitutions that are + // If an instance's MIR body is not polymorphic then the modified generic parameters that are // derived from polymorphization's result won't make any difference. if !instance.has_polymorphic_mir_body() { return false; diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index e11102c459e..486396b0677 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -263,11 +263,11 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { for &(variant, field) in indices { match current_ty.kind() { - ty::Adt(def, subst) => { + ty::Adt(def, args) => { let field = &def.variant(variant).fields[field]; self.insert_def_id(field.did); - let field_ty = field.ty(self.tcx, subst); + let field_ty = field.ty(self.tcx, args); current_ty = self.tcx.normalize_erasing_regions(param_env, field_ty); } diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs index a8fe0cb6a1d..5b62731e202 100644 --- a/compiler/rustc_pattern_analysis/src/rustc.rs +++ b/compiler/rustc_pattern_analysis/src/rustc.rs @@ -173,7 +173,7 @@ impl<'p, 'tcx: 'p> RustcMatchCheckCtxt<'p, 'tcx> { variant.fields.iter().enumerate().filter_map(move |(i, field)| { let ty = field.ty(cx.tcx, args); - // `field.ty()` doesn't normalize after substituting. + // `field.ty()` doesn't normalize after instantiating. let ty = cx.tcx.normalize_erasing_regions(cx.param_env, ty); let is_visible = adt.is_enum() || field.vis.is_accessible_from(cx.module, cx.tcx); let is_uninhabited = (cx.tcx.features().exhaustive_patterns diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 6d8e7ba937e..9d8a9f5fce3 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -133,7 +133,7 @@ where if V::SHALLOW { ControlFlow::Continue(()) } else { - assoc_args.iter().try_for_each(|subst| subst.visit_with(self)) + assoc_args.iter().try_for_each(|arg| arg.visit_with(self)) } } @@ -209,7 +209,7 @@ where // Visitors searching for minimal visibility/reachability want to // conservatively approximate associated types like `Type::Alias` // as visible/reachable even if `Type` is private. - // Ideally, associated types should be substituted in the same way as + // Ideally, associated types should be instantiated in the same way as // free type aliases, but this isn't done yet. return ControlFlow::Continue(()); } @@ -230,7 +230,7 @@ where } else if kind == ty::Projection { self.visit_projection_ty(data) } else { - data.args.iter().try_for_each(|subst| subst.visit_with(self)) + data.args.iter().try_for_each(|arg| arg.visit_with(self)) }; } ty::Dynamic(predicates, ..) => { diff --git a/compiler/rustc_smir/src/rustc_smir/context.rs b/compiler/rustc_smir/src/rustc_smir/context.rs index 94a1fb33f99..70d7200bf60 100644 --- a/compiler/rustc_smir/src/rustc_smir/context.rs +++ b/compiler/rustc_smir/src/rustc_smir/context.rs @@ -369,7 +369,7 @@ impl<'tcx> Context for TablesWrapper<'tcx> { fn instance_ty(&self, def: InstanceDef) -> stable_mir::ty::Ty { let mut tables = self.0.borrow_mut(); let instance = tables.instances[def]; - assert!(!instance.has_non_region_param(), "{instance:?} needs further substitution"); + assert!(!instance.has_non_region_param(), "{instance:?} needs further instantiation"); instance.ty(tables.tcx, ParamEnv::reveal_all()).stable(&mut *tables) } diff --git a/compiler/rustc_symbol_mangling/src/legacy.rs b/compiler/rustc_symbol_mangling/src/legacy.rs index 646649293fc..83e920e2f8e 100644 --- a/compiler/rustc_symbol_mangling/src/legacy.rs +++ b/compiler/rustc_symbol_mangling/src/legacy.rs @@ -99,7 +99,7 @@ fn get_symbol_hash<'tcx>( instance: Instance<'tcx>, // type of the item, without any generic - // parameters substituted; this is + // parameters instantiated; this is // included in the hash as a kind of // safeguard. item_type: Ty<'tcx>, diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index 530221555c5..72c8181152d 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -251,8 +251,8 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> { None => "M", }); - // Encode impl generic params if the substitutions contain parameters (implying - // polymorphization is enabled) and this isn't an inherent impl. + // Encode impl generic params if the generic parameters contain non-region parameters + // (implying polymorphization is enabled) and this isn't an inherent impl. if impl_trait_ref.is_some() && args.iter().any(|a| a.has_non_region_param()) { self.path_generic_args( |this| { diff --git a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs index 819b070cf8b..3b902dd80f5 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs @@ -576,7 +576,7 @@ pub(in crate::solve) fn predicates_for_object_candidate<'tcx>( assert_eq!( old_ty, None, - "{} has two substitutions: {} and {}", + "{} has two generic parameters: {} and {}", proj.projection_ty, proj.term, old_ty.unwrap() diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs index ecdae2521b9..1a6aa3f144c 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs @@ -192,11 +192,14 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { original_values: Vec>, response: CanonicalResponse<'tcx>, ) -> Result<(Certainty, Vec>>), NoSolution> { - let substitution = - Self::compute_query_response_substitution(self.infcx, &original_values, &response); + let instantiation = Self::compute_query_response_instantiation_values( + self.infcx, + &original_values, + &response, + ); let Response { var_values, external_constraints, certainty } = - response.substitute(self.tcx(), &substitution); + response.instantiate(self.tcx(), &instantiation); let nested_goals = Self::unify_query_var_values(self.infcx, param_env, &original_values, var_values)?; @@ -209,10 +212,10 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { Ok((certainty, nested_goals)) } - /// This returns the substitutions to instantiate the bound variables of + /// This returns the canoncial variable values to instantiate the bound variables of /// the canonical response. This depends on the `original_values` for the /// bound variables. - fn compute_query_response_substitution>( + fn compute_query_response_instantiation_values>( infcx: &InferCtxt<'tcx>, original_values: &[ty::GenericArg<'tcx>], response: &Canonical<'tcx, T>, @@ -369,10 +372,10 @@ impl<'tcx> inspect::ProofTreeBuilder<'tcx> { original_values: &[ty::GenericArg<'tcx>], state: inspect::CanonicalState<'tcx, T>, ) -> Result<(Vec>>, T), NoSolution> { - let substitution = - EvalCtxt::compute_query_response_substitution(infcx, original_values, &state); + let instantiation = + EvalCtxt::compute_query_response_instantiation_values(infcx, original_values, &state); - let inspect::State { var_values, data } = state.substitute(infcx.tcx, &substitution); + let inspect::State { var_values, data } = state.instantiate(infcx.tcx, &instantiation); let nested_goals = EvalCtxt::unify_query_var_values(infcx, param_env, original_values, var_values)?; diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs index 69b69930432..eab59624436 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs @@ -312,8 +312,8 @@ fn rematch_unsize<'tcx>( let a_tail_ty = tail_field_ty.instantiate(tcx, a_args); let b_tail_ty = tail_field_ty.instantiate(tcx, b_args); - // Substitute just the unsizing params from B into A. The type after - // this substitution must be equal to B. This is so we don't unsize + // Instantiate just the unsizing params from B into A. The type after + // this instantiation must be equal to B. This is so we don't unsize // unrelated type parameters. let new_a_args = tcx.mk_args_from_iter( a_args @@ -349,7 +349,7 @@ fn rematch_unsize<'tcx>( let (a_last_ty, a_rest_tys) = a_tys.split_last().unwrap(); let b_last_ty = b_tys.last().unwrap(); - // Substitute just the tail field of B., and require that they're equal. + // Instantiate just the tail field of B., and require that they're equal. let unsized_a_ty = Ty::new_tup_from_iter(tcx, a_rest_tys.iter().chain([b_last_ty]).copied()); nested.extend( diff --git a/compiler/rustc_trait_selection/src/solve/normalizes_to/inherent.rs b/compiler/rustc_trait_selection/src/solve/normalizes_to/inherent.rs index b2dff9b48ff..52d2fe1e3ec 100644 --- a/compiler/rustc_trait_selection/src/solve/normalizes_to/inherent.rs +++ b/compiler/rustc_trait_selection/src/solve/normalizes_to/inherent.rs @@ -1,7 +1,7 @@ //! Computes a normalizes-to (projection) goal for inherent associated types, //! `#![feature(inherent_associated_type)]`. Since astconv already determines //! which impl the IAT is being projected from, we just: -//! 1. instantiate substs, +//! 1. instantiate generic parameters, //! 2. equate the self type, and //! 3. instantiate and register where clauses. use rustc_middle::traits::solve::{Certainty, Goal, GoalSource, QueryResult}; @@ -19,21 +19,21 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { let expected = goal.predicate.term.ty().expect("inherent consts are treated separately"); let impl_def_id = tcx.parent(inherent.def_id); - let impl_substs = self.fresh_args_for_item(impl_def_id); + let impl_args = self.fresh_args_for_item(impl_def_id); // Equate impl header and add impl where clauses self.eq( goal.param_env, inherent.self_ty(), - tcx.type_of(impl_def_id).instantiate(tcx, impl_substs), + tcx.type_of(impl_def_id).instantiate(tcx, impl_args), )?; // Equate IAT with the RHS of the project goal - let inherent_substs = inherent.rebase_inherent_args_onto_impl(impl_substs, tcx); + let inherent_args = inherent.rebase_inherent_args_onto_impl(impl_args, tcx); self.eq( goal.param_env, expected, - tcx.type_of(inherent.def_id).instantiate(tcx, inherent_substs), + tcx.type_of(inherent.def_id).instantiate(tcx, inherent_args), ) .expect("expected goal term to be fully unconstrained"); @@ -46,7 +46,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { self.add_goals( GoalSource::Misc, tcx.predicates_of(inherent.def_id) - .instantiate(tcx, inherent_substs) + .instantiate(tcx, inherent_args) .into_iter() .map(|(pred, _)| goal.with(tcx, pred)), ); diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs index 044832224e5..32b46c7ac44 100644 --- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs @@ -877,8 +877,8 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { let a_tail_ty = tail_field_ty.instantiate(tcx, a_args); let b_tail_ty = tail_field_ty.instantiate(tcx, b_args); - // Substitute just the unsizing params from B into A. The type after - // this substitution must be equal to B. This is so we don't unsize + // Instantiate just the unsizing params from B into A. The type after + // this instantiation must be equal to B. This is so we don't unsize // unrelated type parameters. let new_a_args = tcx.mk_args_from_iter( a_args @@ -927,7 +927,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { let (&a_last_ty, a_rest_tys) = a_tys.split_last().unwrap(); let &b_last_ty = b_tys.last().unwrap(); - // Substitute just the tail field of B., and require that they're equal. + // Instantiate just the tail field of B., and require that they're equal. let unsized_a_ty = Ty::new_tup_from_iter(tcx, a_rest_tys.iter().copied().chain([b_last_ty])); self.eq(goal.param_env, unsized_a_ty, b_ty)?; diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index cbe9a238b1c..e48bd437f59 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -84,7 +84,7 @@ impl TrackAmbiguityCauses { /// If there are types that satisfy both impls, returns `Some` /// with a suitably-freshened `ImplHeader` with those types -/// substituted. Otherwise, returns `None`. +/// instantiated. Otherwise, returns `None`. #[instrument(skip(tcx, skip_leak_check), level = "debug")] pub fn overlapping_impls( tcx: TyCtxt<'_>, @@ -561,21 +561,21 @@ pub fn trait_ref_is_knowable<'tcx, E: Debug>( ) -> Result, E> { if orphan_check_trait_ref(trait_ref, InCrate::Remote, &mut lazily_normalize_ty)?.is_ok() { // A downstream or cousin crate is allowed to implement some - // substitution of this trait-ref. + // generic parameters of this trait-ref. return Ok(Err(Conflict::Downstream)); } if trait_ref_is_local_or_fundamental(tcx, trait_ref) { // This is a local or fundamental trait, so future-compatibility // is no concern. We know that downstream/cousin crates are not - // allowed to implement a substitution of this trait ref, which - // means impls could only come from dependencies of this crate, - // which we already know about. + // allowed to implement a generic parameter of this trait ref, + // which means impls could only come from dependencies of this + // crate, which we already know about. return Ok(Ok(())); } // This is a remote non-fundamental trait, so if another crate - // can be the "final owner" of a substitution of this trait-ref, + // can be the "final owner" of the generic parameters of this trait-ref, // they are allowed to implement it future-compatibly. // // However, if we are a final owner, then nobody else can be, @@ -628,8 +628,8 @@ pub fn orphan_check(tcx: TyCtxt<'_>, impl_def_id: DefId) -> Result<(), OrphanChe /// /// The current rule is that a trait-ref orphan checks in a crate C: /// -/// 1. Order the parameters in the trait-ref in subst order - Self first, -/// others linearly (e.g., `>` is U < V < W). +/// 1. Order the parameters in the trait-ref in generic parameters order +/// - Self first, others linearly (e.g., `>` is U < V < W). /// 2. Of these type parameters, there is at least one type parameter /// in which, walking the type as a tree, you can reach a type local /// to C where all types in-between are fundamental types. Call the @@ -696,7 +696,7 @@ pub fn orphan_check(tcx: TyCtxt<'_>, impl_def_id: DefId) -> Result<(), OrphanChe /// /// Because we never perform negative reasoning generically (coherence does /// not involve type parameters), this can be interpreted as doing the full -/// orphan check (using InCrate::Local mode), substituting non-local known +/// orphan check (using InCrate::Local mode), instantiating non-local known /// types for all inference variables. /// /// This allows for crates to future-compatibly add impls as long as they diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/infer_ctxt_ext.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/infer_ctxt_ext.rs index ca43436848b..15d064d4036 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/infer_ctxt_ext.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/infer_ctxt_ext.rs @@ -242,7 +242,7 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { self.tcx.lang_items().fn_once_trait(), ] { let Some(trait_def_id) = trait_def_id else { continue }; - // Make a fresh inference variable so we can determine what the substitutions + // Make a fresh inference variable so we can determine what the generic parameters // of the trait are. let var = self.next_ty_var(TypeVariableOrigin { span: DUMMY_SP, 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 ceff7187646..f0773fd1671 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 @@ -814,7 +814,7 @@ impl<'tcx> OnUnimplementedFormatString { tcx.dcx(), self.span, E0231, - "only named substitution parameters are allowed" + "only named generic parameters are allowed" ) .emit(); result = Err(reported); 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 eb75b04ed1c..c7b56aac7e5 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -635,7 +635,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { | hir::Node::ImplItem(hir::ImplItem { generics, .. }) if param_ty => { - // We skip the 0'th subst (self) because we do not want + // We skip the 0'th arg (self) because we do not want // to consider the predicate as not suggestible if the // self type is an arg position `impl Trait` -- instead, // we handle that by adding ` + Bound` below. @@ -2343,7 +2343,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { err: &mut DiagnosticBuilder<'tcx>, ) { // First, look for an `ExprBindingObligation`, which means we can get - // the unsubstituted predicate list of the called function. And check + // the uninstantiated predicate list of the called function. And check // that the predicate that we failed to satisfy is a `Fn`-like trait. if let ObligationCauseCode::ExprBindingObligation(def_id, _, _, idx) = cause && let predicates = self.tcx.predicates_of(def_id).instantiate_identity(self.tcx) diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs index 7d14395850b..e192c8a04fd 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs @@ -2426,16 +2426,16 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { // known, since we don't dispatch based on region // relationships. - // Pick the first substitution that still contains inference variables as the one + // Pick the first generic parameter that still contains inference variables as the one // we're going to emit an error for. If there are none (see above), fall back to // a more general error. - let subst = data.trait_ref.args.iter().find(|s| s.has_non_region_infer()); + let arg = data.trait_ref.args.iter().find(|s| s.has_non_region_infer()); - let mut err = if let Some(subst) = subst { + let mut err = if let Some(arg) = arg { self.emit_inference_failure_err( obligation.cause.body_id, span, - subst, + arg, ErrorCode::E0283, true, ) @@ -2473,9 +2473,9 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } if ambiguities.len() > 1 && ambiguities.len() < 10 && has_non_region_infer { if let Some(e) = self.tainted_by_errors() - && subst.is_none() + && arg.is_none() { - // If `subst.is_none()`, then this is probably two param-env + // If `arg.is_none()`, then this is probably two param-env // candidates or impl candidates that are equal modulo lifetimes. // Therefore, if we've already emitted an error, just skip this // one, since it's not particularly actionable. @@ -2509,7 +2509,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { self.suggest_fully_qualified_path(&mut err, def_id, span, trait_ref.def_id()); } - if let Some(ty::GenericArgKind::Type(_)) = subst.map(|subst| subst.unpack()) + if let Some(ty::GenericArgKind::Type(_)) = arg.map(|arg| arg.unpack()) && let Some(body_id) = self.tcx.hir().maybe_body_owned_by(obligation.cause.body_id) { @@ -2687,23 +2687,23 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { // other `Foo` impls are incoherent. return guar; } - let subst = data + let arg = data .projection_ty .args .iter() .chain(Some(data.term.into_arg())) .find(|g| g.has_non_region_infer()); - if let Some(subst) = subst { + if let Some(arg) = arg { self.emit_inference_failure_err( obligation.cause.body_id, span, - subst, + arg, ErrorCode::E0284, true, ) .with_note(format!("cannot satisfy `{predicate}`")) } else { - // If we can't find a substitution, just print a generic error + // If we can't find a generic parameter, just print a generic error struct_span_code_err!( self.dcx(), span, @@ -2722,18 +2722,18 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { if let Some(e) = self.tainted_by_errors() { return e; } - let subst = data.walk().find(|g| g.is_non_region_infer()); - if let Some(subst) = subst { + let arg = data.walk().find(|g| g.is_non_region_infer()); + if let Some(arg) = arg { let err = self.emit_inference_failure_err( obligation.cause.body_id, span, - subst, + arg, ErrorCode::E0284, true, ); err } else { - // If we can't find a substitution, just print a generic error + // If we can't find a generic parameter, just print a generic error struct_span_code_err!( self.dcx(), span, diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index a7f6021d57a..7caaccab63b 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -443,11 +443,11 @@ pub fn impossible_predicates<'tcx>(tcx: TyCtxt<'tcx>, predicates: Vec( +fn instantiate_and_check_impossible_predicates<'tcx>( tcx: TyCtxt<'tcx>, key: (DefId, GenericArgsRef<'tcx>), ) -> bool { - debug!("subst_and_check_impossible_predicates(key={:?})", key); + debug!("instantiate_and_check_impossible_predicates(key={:?})", key); let mut predicates = tcx.predicates_of(key.0).instantiate(tcx, key.1).predicates; @@ -461,7 +461,7 @@ fn subst_and_check_impossible_predicates<'tcx>( predicates.retain(|predicate| !predicate.has_param()); let result = impossible_predicates(tcx, predicates); - debug!("subst_and_check_impossible_predicates(key={:?}) = {:?}", key, result); + debug!("instantiate_and_check_impossible_predicates(key={:?}) = {:?}", key, result); result } @@ -548,7 +548,7 @@ pub fn provide(providers: &mut Providers) { *providers = Providers { specialization_graph_of: specialize::specialization_graph_provider, specializes: specialize::specializes, - subst_and_check_impossible_predicates, + instantiate_and_check_impossible_predicates, check_tys_might_be_eq: misc::check_tys_might_be_eq, is_impossible_associated_item, ..*providers diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs index 3289dfe343e..29a4a078fe0 100644 --- a/compiler/rustc_trait_selection/src/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -263,7 +263,7 @@ fn predicates_reference_self( predicates .predicates .iter() - .map(|&(predicate, sp)| (predicate.subst_supertrait(tcx, &trait_ref), sp)) + .map(|&(predicate, sp)| (predicate.instantiate_supertrait(tcx, &trait_ref), sp)) .filter_map(|predicate| predicate_references_self(tcx, predicate)) .collect() } @@ -607,7 +607,7 @@ fn virtual_call_violations_for_method<'tcx>( errors } -/// Performs a type substitution to produce the version of `receiver_ty` when `Self = self_ty`. +/// Performs a type instantiation to produce the version of `receiver_ty` when `Self = self_ty`. /// For example, for `receiver_ty = Rc` and `self_ty = Foo`, returns `Rc`. fn receiver_for_self_ty<'tcx>( tcx: TyCtxt<'tcx>, @@ -682,7 +682,7 @@ fn object_ty_for_trait<'tcx>( /// ``` /// /// where `Foo[X => Y]` means "the same type as `Foo`, but with `X` replaced with `Y`" -/// (substitution notation). +/// (instantiation notation). /// /// Some examples of receiver types and their required obligation: /// - `&'a mut self` requires `&'a mut Self: DispatchFromDyn<&'a mut dyn Trait>`, diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 054402acb5c..049877bc5fe 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -266,7 +266,7 @@ pub(super) fn poly_project_and_unify_type<'cx, 'tcx>( // universe just created. Otherwise, we can end up with something like `for<'a> I: 'a`, // which isn't quite what we want. Ideally, we want either an implied // `for<'a where I: 'a> I: 'a` or we want to "lazily" check these hold when we - // substitute concrete regions. There is design work to be done here; until then, + // instantiate concrete regions. There is design work to be done here; until then, // however, this allows experimenting potential GAT features without running into // well-formedness issues. let new_obligations = obligations @@ -1115,7 +1115,7 @@ impl<'tcx> TypeFolder> for PlaceholderReplacer<'_, 'tcx> { /// as Trait>::Item`. The result is always a type (and possibly /// additional obligations). If ambiguity arises, which implies that /// there are unresolved type variables in the projection, we will -/// substitute a fresh type variable `$X` and generate a new +/// instantiate it with a fresh type variable `$X` and generate a new /// obligation `::Item == $X` for later. pub fn normalize_projection_type<'a, 'b, 'tcx>( selcx: &'a mut SelectionContext<'b, 'tcx>, @@ -1400,7 +1400,7 @@ pub fn normalize_inherent_projection<'a, 'b, 'tcx>( cause.span, cause.body_id, // FIXME(inherent_associated_types): Since we can't pass along the self type to the - // cause code, inherent projections will be printed with identity substitutions in + // cause code, inherent projections will be printed with identity instantiation in // diagnostics which is not ideal. // Consider creating separate cause codes for this specific situation. if span.is_dummy() { diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/ascribe_user_type.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/ascribe_user_type.rs index 0aaeacb6a23..aca16950223 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/ascribe_user_type.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/ascribe_user_type.rs @@ -116,7 +116,7 @@ fn relate_mir_and_user_args<'tcx>( ocx.register_obligation(Obligation::new(tcx, cause, param_env, instantiated_predicate)); } - // Now prove the well-formedness of `def_id` with `substs`. + // Now prove the well-formedness of `def_id` with `args`. // Note for some items, proving the WF of `ty` is not sufficient because the // well-formedness of an item may depend on the WF of gneneric args not present in the // item's type. Currently this is true for associated consts, e.g.: 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 83d23597c0c..423ed0f7105 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 @@ -170,7 +170,7 @@ pub fn compute_implied_outlives_bounds_compat_inner<'tcx>( } // Compute the obligations for `arg` to be well-formed. If `arg` is - // an unresolved inference variable, just substituted an empty set + // an unresolved inference variable, just instantiated an empty set // -- because the return type here is going to be things we *add* // to the environment, it's always ok for this set to be smaller // than the ultimate set. (Note: normally there won't be diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index f9a292c2bd7..bafb8c10bf1 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -557,7 +557,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation.predicate.def_id(), obligation.predicate.skip_binder().trait_ref.self_ty(), |impl_def_id| { - // Before we create the substitutions and everything, first + // Before we create the generic parameters and everything, first // consider a "quick reject". This avoids creating more types // and so forth that we need to. let impl_trait_ref = self.tcx().impl_trait_ref(impl_def_id).unwrap(); diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 6ca24933979..2ce33a4d122 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -444,7 +444,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ) -> ImplSourceUserDefinedData<'tcx, PredicateObligation<'tcx>> { debug!(?obligation, ?impl_def_id, "confirm_impl_candidate"); - // First, create the substitutions by matching the impl again, + // First, create the generic parameters by matching the impl again, // this time not in a probe. let args = self.rematch_impl(impl_def_id, obligation); debug!(?args, "impl args"); @@ -585,7 +585,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // higher-ranked things. // Prevent, e.g., `dyn Iterator`. for bound in self.tcx().item_bounds(assoc_type).transpose_iter() { - let subst_bound = if defs.count() == 0 { + let arg_bound = if defs.count() == 0 { bound.instantiate(tcx, trait_predicate.trait_ref.args) } else { let mut args = smallvec::SmallVec::with_capacity(defs.count()); @@ -649,7 +649,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation.param_env, obligation.cause.clone(), obligation.recursion_depth + 1, - subst_bound, + arg_bound, &mut nested, ); nested.push(obligation.with(tcx, normalized_bound)); diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index ac6cfcdeb59..368427dfb27 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -1684,7 +1684,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { /// Return `Yes` if the obligation's predicate type applies to the env_predicate, and /// `No` if it does not. Return `Ambiguous` in the case that the projection type is a GAT, - /// and applying this env_predicate constrains any of the obligation's GAT substitutions. + /// and applying this env_predicate constrains any of the obligation's GAT parameters. /// /// This behavior is a somewhat of a hack to prevent over-constraining inference variables /// in cases like #91762. @@ -2673,7 +2673,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> { } /// Returns the obligations that are implied by instantiating an - /// impl or trait. The obligations are substituted and fully + /// impl or trait. The obligations are instantiated and fully /// normalized. This is used when confirming an impl or default /// impl. #[instrument(level = "debug", skip(self, cause, param_env))] @@ -2698,7 +2698,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> { // U: Iterator, U: Sized, // V: Iterator, V: Sized, // ::Item: Copy - // When we substitute, say, `V => IntoIter, U => $0`, the last + // When we instantiate, say, `V => IntoIter, U => $0`, the last // obligation will normalize to `<$0 as Iterator>::Item = $1` and // `$1: Copy`, so we must ensure the obligations are emitted in // that order. diff --git a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs index 8e0fa79c977..be066e45d0a 100644 --- a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs @@ -41,17 +41,17 @@ pub struct OverlapError<'tcx> { pub involves_placeholder: bool, } -/// Given a subst for the requested impl, translate it to a subst +/// Given the generic parameters for the requested impl, translate it to the generic parameters /// appropriate for the actual item definition (whether it be in that impl, /// a parent impl, or the trait). /// /// When we have selected one impl, but are actually using item definitions from /// a parent impl providing a default, we need a way to translate between the /// type parameters of the two impls. Here the `source_impl` is the one we've -/// selected, and `source_args` is a substitution of its generics. +/// selected, and `source_args` is its generic parameters. /// And `target_node` is the impl/trait we're actually going to get the -/// definition from. The resulting substitution will map from `target_node`'s -/// generics to `source_impl`'s generics as instantiated by `source_subst`. +/// definition from. The resulting instantiation will map from `target_node`'s +/// generics to `source_impl`'s generics as instantiated by `source_args`. /// /// For example, consider the following scenario: /// @@ -62,7 +62,7 @@ pub struct OverlapError<'tcx> { /// ``` /// /// Suppose we have selected "source impl" with `V` instantiated with `u32`. -/// This function will produce a substitution with `T` and `U` both mapping to `u32`. +/// This function will produce an instantiation with `T` and `U` both mapping to `u32`. /// /// where-clauses add some trickiness here, because they can be used to "define" /// an argument indirectly: @@ -72,7 +72,7 @@ pub struct OverlapError<'tcx> { /// where I: Iterator, T: Clone /// ``` /// -/// In a case like this, the substitution for `T` is determined indirectly, +/// In a case like this, the instantiation for `T` is determined indirectly, /// through associated type projection. We deal with such cases by using /// *fulfillment* to relate the two impls, requiring that all projections are /// resolved. @@ -109,7 +109,7 @@ pub fn translate_args_with_cause<'tcx>( let source_trait_ref = infcx.tcx.impl_trait_ref(source_impl).unwrap().instantiate(infcx.tcx, source_args); - // translate the Self and Param parts of the substitution, since those + // translate the Self and Param parts of the generic parameters, since those // vary across impls let target_args = match target_node { specialization_graph::Node::Impl(target_impl) => { @@ -121,8 +121,8 @@ pub fn translate_args_with_cause<'tcx>( fulfill_implication(infcx, param_env, source_trait_ref, source_impl, target_impl, cause) .unwrap_or_else(|()| { bug!( - "When translating substitutions from {source_impl:?} to {target_impl:?}, \ - the expected specialization failed to hold" + "When translating generic parameters from {source_impl:?} to \ + {target_impl:?}, the expected specialization failed to hold" ) }) } @@ -200,7 +200,7 @@ pub(super) fn specializes(tcx: TyCtxt<'_>, (impl1_def_id, impl2_def_id): (DefId, } /// Attempt to fulfill all obligations of `target_impl` after unification with -/// `source_trait_ref`. If successful, returns a substitution for *all* the +/// `source_trait_ref`. If successful, returns the generic parameters for *all* the /// generics of `target_impl`, including both those needed to unify with /// `source_trait_ref` and those whose identity is determined via a where /// clause in the impl. @@ -247,7 +247,7 @@ fn fulfill_implication<'tcx>( }; // Needs to be `in_snapshot` because this function is used to rebase - // substitutions, which may happen inside of a select within a probe. + // generic parameters, which may happen inside of a select within a probe. let ocx = ObligationCtxt::new(infcx); // attempt to prove all of the predicates for impl2 given those for impl1 // (which are packed up in penv) @@ -269,7 +269,7 @@ fn fulfill_implication<'tcx>( debug!("fulfill_implication: an impl for {:?} specializes {:?}", source_trait, target_trait); - // Now resolve the *substitution* we built for the target earlier, replacing + // Now resolve the *generic parameters* we built for the target earlier, replacing // the inference variables inside with whatever we got from fulfillment. Ok(infcx.resolve_vars_if_possible(target_args)) } diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs index c40ed10e52f..af172eb0713 100644 --- a/compiler/rustc_trait_selection/src/traits/util.rs +++ b/compiler/rustc_trait_selection/src/traits/util.rs @@ -128,7 +128,7 @@ impl<'tcx> TraitAliasExpander<'tcx> { debug!(?predicates); let items = predicates.predicates.iter().rev().filter_map(|(pred, span)| { - pred.subst_supertrait(tcx, &trait_ref) + pred.instantiate_supertrait(tcx, &trait_ref) .as_trait_clause() .map(|trait_ref| item.clone_and_push(trait_ref.map_bound(|t| t.trait_ref), *span)) }); diff --git a/compiler/rustc_trait_selection/src/traits/vtable.rs b/compiler/rustc_trait_selection/src/traits/vtable.rs index d39583b5c7d..3c0316fce17 100644 --- a/compiler/rustc_trait_selection/src/traits/vtable.rs +++ b/compiler/rustc_trait_selection/src/traits/vtable.rs @@ -124,7 +124,7 @@ fn prepare_vtable_segments_inner<'tcx, T>( .predicates .into_iter() .filter_map(move |(pred, _)| { - pred.subst_supertrait(tcx, &inner_most_trait_ref).as_trait_clause() + pred.instantiate_supertrait(tcx, &inner_most_trait_ref).as_trait_clause() }); // Find an unvisited supertrait diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index b4f13ee95a6..c727ef53d55 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -380,7 +380,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { .filter(|(_, arg)| !arg.has_escaping_bound_vars()) .map(|(i, arg)| { let mut cause = traits::ObligationCause::misc(self.span, self.body_id); - // The first subst is the self ty - use the correct span for it. + // The first arg is the self ty - use the correct span for it. if i == 0 { if let Some(hir::ItemKind::Impl(hir::Impl { self_ty, .. })) = item.map(|i| &i.kind) diff --git a/compiler/rustc_traits/src/normalize_projection_ty.rs b/compiler/rustc_traits/src/normalize_projection_ty.rs index 21a016e29d6..07089d5f19e 100644 --- a/compiler/rustc_traits/src/normalize_projection_ty.rs +++ b/compiler/rustc_traits/src/normalize_projection_ty.rs @@ -42,7 +42,7 @@ fn normalize_projection_ty<'tcx>( ); ocx.register_obligations(obligations); // #112047: With projections and opaques, we are able to create opaques that - // are recursive (given some substitution of the opaque's type variables). + // are recursive (given some generic parameters of the opaque's type variables). // In that case, we may only realize a cycle error when calling // `normalize_erasing_regions` in mono. if !ocx.infcx.next_trait_solver() { diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs index 0542ef4ecf9..638c9a53d22 100644 --- a/compiler/rustc_ty_utils/src/abi.rs +++ b/compiler/rustc_ty_utils/src/abi.rs @@ -50,7 +50,7 @@ fn fn_sig_for_fn_abi<'tcx>( // `tests/ui/polymorphization/normalized_sig_types.rs`), and codegen not keeping // track of a polymorphization `ParamEnv` to allow normalizing later. // - // We normalize the `fn_sig` again after substituting at a later point. + // We normalize the `fn_sig` again after instantiating at a later point. let mut sig = match *ty.kind() { ty::FnDef(def_id, args) => tcx .fn_sig(def_id) @@ -163,7 +163,7 @@ fn fn_sig_for_fn_abi<'tcx>( // a separate def-id for these bodies. if let InstanceDef::CoroutineKindShim { target_kind, .. } = instance.def { // Grab the parent coroutine-closure. It has the same args for the purposes - // of substitution, so this will be okay to do. + // of instantiation, so this will be okay to do. let ty::CoroutineClosure(_, coroutine_closure_args) = *tcx .instantiate_and_normalize_erasing_regions( args, diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs index f20ded355b1..96f8148bf72 100644 --- a/compiler/rustc_ty_utils/src/layout.rs +++ b/compiler/rustc_ty_utils/src/layout.rs @@ -741,7 +741,7 @@ fn coroutine_layout<'tcx>( ) -> Result, &'tcx LayoutError<'tcx>> { use SavedLocalEligibility::*; let tcx = cx.tcx; - let subst_field = |ty: Ty<'tcx>| EarlyBinder::bind(ty).instantiate(tcx, args); + let instantiate_field = |ty: Ty<'tcx>| EarlyBinder::bind(ty).instantiate(tcx, args); let Some(info) = tcx.coroutine_layout(def_id) else { return Err(error(cx, LayoutError::Unknown(ty))); @@ -763,7 +763,7 @@ fn coroutine_layout<'tcx>( let tag_layout = cx.tcx.mk_layout(LayoutS::scalar(cx, tag)); let promoted_layouts = ineligible_locals.iter().map(|local| { - let field_ty = subst_field(info.field_tys[local].ty); + let field_ty = instantiate_field(info.field_tys[local].ty); let uninit_ty = Ty::new_maybe_uninit(tcx, field_ty); Ok(cx.spanned_layout_of(uninit_ty, info.field_tys[local].source_info.span)?.layout) }); @@ -838,7 +838,7 @@ fn coroutine_layout<'tcx>( Ineligible(_) => false, }) .map(|local| { - let field_ty = subst_field(info.field_tys[*local].ty); + let field_ty = instantiate_field(info.field_tys[*local].ty); Ty::new_maybe_uninit(tcx, field_ty) }); diff --git a/compiler/rustc_ty_utils/src/needs_drop.rs b/compiler/rustc_ty_utils/src/needs_drop.rs index 7b3d2ab22cf..48339e6120a 100644 --- a/compiler/rustc_ty_utils/src/needs_drop.rs +++ b/compiler/rustc_ty_utils/src/needs_drop.rs @@ -264,9 +264,9 @@ fn drop_tys_helper<'tcx>( ) -> NeedsDropResult>> { iter.into_iter().try_fold(Vec::new(), |mut vec, subty| { match subty.kind() { - ty::Adt(adt_id, subst) => { + ty::Adt(adt_id, args) => { for subty in tcx.adt_drop_tys(adt_id.did())? { - vec.push(EarlyBinder::bind(subty).instantiate(tcx, subst)); + vec.push(EarlyBinder::bind(subty).instantiate(tcx, args)); } } _ => vec.push(subty), @@ -300,7 +300,10 @@ fn drop_tys_helper<'tcx>( } else { let field_tys = adt_def.all_fields().map(|field| { let r = tcx.type_of(field.did).instantiate(tcx, args); - debug!("drop_tys_helper: Subst into {:?} with {:?} getting {:?}", field, args, r); + debug!( + "drop_tys_helper: Instantiate into {:?} with {:?} getting {:?}", + field, args, r + ); r }); if only_significant { @@ -363,7 +366,7 @@ fn adt_drop_tys<'tcx>( .map(|components| tcx.mk_type_list(&components)) } // If `def_id` refers to a generic ADT, the queries above and below act as if they had been handed -// a `tcx.make_ty(def, identity_args)` and as such it is legal to substitute the generic parameters +// a `tcx.make_ty(def, identity_args)` and as such it is legal to instantiate the generic parameters // of the ADT into the outputted `ty`s. fn adt_significant_drop_tys( tcx: TyCtxt<'_>, diff --git a/compiler/rustc_ty_utils/src/opaque_types.rs b/compiler/rustc_ty_utils/src/opaque_types.rs index ef67317a601..329cf32cad5 100644 --- a/compiler/rustc_ty_utils/src/opaque_types.rs +++ b/compiler/rustc_ty_utils/src/opaque_types.rs @@ -155,7 +155,7 @@ impl<'tcx> OpaqueTypeCollector<'tcx> { // Collect opaque types nested within the associated type bounds of this opaque type. // We use identity args here, because we already know that the opaque type uses - // only generic parameters, and thus substituting would not give us more information. + // only generic parameters, and thus instantiating would not give us more information. for (pred, span) in self .tcx .explicit_item_bounds(alias_ty.def_id) @@ -211,7 +211,7 @@ impl<'tcx> TypeVisitor> for OpaqueTypeCollector<'tcx> { // in the same impl block. if let Some(parent_trait_ref) = self.parent_trait_ref() { // If the trait ref of the associated item and the impl differs, - // then we can't use the impl's identity substitutions below, so + // then we can't use the impl's identity args below, so // just skip. if alias_ty.trait_ref(self.tcx) == parent_trait_ref { let parent = self.parent().expect("we should have a parent here"); @@ -258,11 +258,11 @@ impl<'tcx> TypeVisitor> for OpaqueTypeCollector<'tcx> { for field in variant.fields.iter() { // Don't use the `ty::Adt` args, we either // * found the opaque in the args - // * will find the opaque in the unsubstituted fields - // The only other situation that can occur is that after substituting, + // * will find the opaque in the uninstantiated fields + // The only other situation that can occur is that after instantiating, // some projection resolves to an opaque that we would have otherwise - // not found. While we could substitute and walk those, that would mean we - // would have to walk all substitutions of an Adt, which can quickly + // not found. While we could instantiate and walk those, that would mean we + // would have to walk all generic parameters of an Adt, which can quickly // degenerate into looking at an exponential number of types. let ty = self.tcx.type_of(field.did).instantiate_identity(); self.visit_spanned(self.tcx.def_span(field.did), ty); @@ -306,7 +306,7 @@ impl<'tcx> TypeVisitor> for ImplTraitInAssocTypeCollector<'tcx> { .parent_trait_ref() .expect("impl trait in assoc type collector used on non-assoc item"); // If the trait ref of the associated item and the impl differs, - // then we can't use the impl's identity substitutions below, so + // then we can't use the impl's identity args below, so // just skip. if alias_ty.trait_ref(self.0.tcx) == parent_trait_ref { let parent = self.0.parent().expect("we should have a parent here"); diff --git a/compiler/rustc_ty_utils/src/representability.rs b/compiler/rustc_ty_utils/src/representability.rs index 70f1f099688..3ca2aba7c04 100644 --- a/compiler/rustc_ty_utils/src/representability.rs +++ b/compiler/rustc_ty_utils/src/representability.rs @@ -73,8 +73,8 @@ fn representability_adt_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Representab // At this point, we know that the item of the ADT type is representable; // but the type parameters may cause a cycle with an upstream type let params_in_repr = tcx.params_in_repr(adt.did()); - for (i, subst) in args.iter().enumerate() { - if let ty::GenericArgKind::Type(ty) = subst.unpack() { + for (i, arg) in args.iter().enumerate() { + if let ty::GenericArgKind::Type(ty) = arg.unpack() { if params_in_repr.contains(i as u32) { rtry!(representability_ty(tcx, ty)); } @@ -103,8 +103,8 @@ fn params_in_repr_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, params_in_repr: &mut match *ty.kind() { ty::Adt(adt, args) => { let inner_params_in_repr = tcx.params_in_repr(adt.did()); - for (i, subst) in args.iter().enumerate() { - if let ty::GenericArgKind::Type(ty) = subst.unpack() { + for (i, arg) in args.iter().enumerate() { + if let ty::GenericArgKind::Type(ty) = arg.unpack() { if inner_params_in_repr.contains(i as u32) { params_in_repr_ty(tcx, ty, params_in_repr); } diff --git a/compiler/rustc_type_ir/src/flags.rs b/compiler/rustc_type_ir/src/flags.rs index bc57d6daf47..1da26cfc242 100644 --- a/compiler/rustc_type_ir/src/flags.rs +++ b/compiler/rustc_type_ir/src/flags.rs @@ -5,7 +5,7 @@ bitflags! { /// over the type itself. #[derive(Debug, PartialEq, Eq, Clone, Copy)] pub struct TypeFlags: u32 { - // Does this have parameters? Used to determine whether substitution is + // Does this have parameters? Used to determine whether instantiation is // required. /// Does this have `Param`? const HAS_TY_PARAM = 1 << 0; diff --git a/compiler/rustc_type_ir/src/region_kind.rs b/compiler/rustc_type_ir/src/region_kind.rs index 777c649fabd..cf13f066cbf 100644 --- a/compiler/rustc_type_ir/src/region_kind.rs +++ b/compiler/rustc_type_ir/src/region_kind.rs @@ -64,17 +64,17 @@ use self::RegionKind::*; /// /// ## Bound Regions /// -/// These are regions that are stored behind a binder and must be substituted +/// These are regions that are stored behind a binder and must be instantiated /// with some concrete region before being used. There are two kind of /// bound regions: early-bound, which are bound in an item's `Generics`, -/// and are substituted by an `GenericArgs`, and late-bound, which are part of -/// higher-ranked types (e.g., `for<'a> fn(&'a ())`), and are substituted by +/// and are instantiated by an `GenericArgs`, and late-bound, which are part of +/// higher-ranked types (e.g., `for<'a> fn(&'a ())`), and are instantiated by /// the likes of `liberate_late_bound_regions`. The distinction exists /// because higher-ranked lifetimes aren't supported in all places. See [1][2]. /// /// Unlike `Param`s, bound regions are not supposed to exist "in the wild" /// outside their binder, e.g., in types passed to type inference, and -/// should first be substituted (by placeholder regions, free regions, +/// should first be instantiated (by placeholder regions, free regions, /// or region variables). /// /// ## Placeholder and Free Regions @@ -101,7 +101,7 @@ use self::RegionKind::*; /// `RePlaceholder` is designed for this purpose. In these contexts, /// there's also the risk that some inference variable laying around will /// get unified with your placeholder region: if you want to check whether -/// `for<'a> Foo<'_>: 'a`, and you substitute your bound region `'a` +/// `for<'a> Foo<'_>: 'a`, and you instantiate your bound region `'a` /// with a placeholder region `'%a`, the variable `'_` would just be /// instantiated to the placeholder region `'%a`, which is wrong because /// the inference variable is supposed to satisfy the relation diff --git a/compiler/rustc_type_ir/src/ty_kind.rs b/compiler/rustc_type_ir/src/ty_kind.rs index a4fe572067b..d389933fd2d 100644 --- a/compiler/rustc_type_ir/src/ty_kind.rs +++ b/compiler/rustc_type_ir/src/ty_kind.rs @@ -143,7 +143,7 @@ pub enum TyKind { /// For example, the type `List` would be represented using the `AdtDef` /// for `struct List` and the args `[i32]`. /// - /// Note that generic parameters in fields only get lazily substituted + /// Note that generic parameters in fields only get lazily instantiated /// by using something like `adt_def.all_fields().map(|field| field.ty(tcx, args))`. Adt(I::AdtDef, I::GenericArgs), @@ -197,14 +197,14 @@ pub enum TyKind { /// The anonymous type of a closure. Used to represent the type of `|a| a`. /// - /// Closure args contain both the - potentially substituted - generic parameters + /// Closure args contain both the - potentially instantiated - generic parameters /// of its parent and some synthetic parameters. See the documentation for /// `ClosureArgs` for more details. Closure(I::DefId, I::GenericArgs), /// The anonymous type of a closure. Used to represent the type of `async |a| a`. /// - /// Coroutine-closure args contain both the - potentially substituted - generic + /// Coroutine-closure args contain both the - potentially instantiated - generic /// parameters of its parent and some synthetic parameters. See the documentation /// for `CoroutineClosureArgs` for more details. CoroutineClosure(I::DefId, I::GenericArgs), diff --git a/compiler/stable_mir/src/compiler_interface.rs b/compiler/stable_mir/src/compiler_interface.rs index fb83dae5714..de045f6b56c 100644 --- a/compiler/stable_mir/src/compiler_interface.rs +++ b/compiler/stable_mir/src/compiler_interface.rs @@ -124,7 +124,7 @@ pub trait Context { /// Get the body of an Instance which is already monomorphized. fn instance_body(&self, instance: InstanceDef) -> Option; - /// Get the instance type with generic substitutions applied and lifetimes erased. + /// Get the instance type with generic instantiations applied and lifetimes erased. fn instance_ty(&self, instance: InstanceDef) -> Ty; /// Get the instantiation types. diff --git a/compiler/stable_mir/src/mir/mono.rs b/compiler/stable_mir/src/mir/mono.rs index 6c791ae8552..97f57d2c7b3 100644 --- a/compiler/stable_mir/src/mir/mono.rs +++ b/compiler/stable_mir/src/mir/mono.rs @@ -57,7 +57,7 @@ impl Instance { with(|cx| cx.is_foreign_item(self.def.def_id())) } - /// Get the instance type with generic substitutions applied and lifetimes erased. + /// Get the instance type with generic instantiations applied and lifetimes erased. pub fn ty(&self) -> Ty { with(|context| context.instance_ty(self.def)) } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 89977934cde..efe2816fbe6 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1796,7 +1796,7 @@ fn maybe_expand_private_type_alias<'tcx>( } else { Lifetime::elided() }; - args.insert(param.def_id.to_def_id(), SubstParam::Lifetime(cleaned)); + args.insert(param.def_id.to_def_id(), InstantiationParam::Lifetime(cleaned)); } indices.lifetimes += 1; } @@ -1813,9 +1813,15 @@ fn maybe_expand_private_type_alias<'tcx>( _ => None, }); if let Some(ty) = type_ { - args.insert(param.def_id.to_def_id(), SubstParam::Type(clean_ty(ty, cx))); + args.insert( + param.def_id.to_def_id(), + InstantiationParam::Type(clean_ty(ty, cx)), + ); } else if let Some(default) = *default { - args.insert(param.def_id.to_def_id(), SubstParam::Type(clean_ty(default, cx))); + args.insert( + param.def_id.to_def_id(), + InstantiationParam::Type(clean_ty(default, cx)), + ); } indices.types += 1; } @@ -1832,7 +1838,7 @@ fn maybe_expand_private_type_alias<'tcx>( _ => None, }); if let Some(_) = const_ { - args.insert(param.def_id.to_def_id(), SubstParam::Constant); + args.insert(param.def_id.to_def_id(), InstantiationParam::Constant); } // FIXME(const_generics_defaults) indices.consts += 1; diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 6710193f961..96b4d1a45f6 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -2542,14 +2542,14 @@ pub(crate) enum TypeBindingKind { /// ``` /// /// `public_fn`'s docs will show it as returning `Vec`, since `PrivAlias` is private. -/// [`SubstParam`] is used to record that `T` should be mapped to `i32`. -pub(crate) enum SubstParam { +/// [`InstantiationParam`] is used to record that `T` should be mapped to `i32`. +pub(crate) enum InstantiationParam { Type(Type), Lifetime(Lifetime), Constant, } -impl SubstParam { +impl InstantiationParam { pub(crate) fn as_ty(&self) -> Option<&Type> { if let Self::Type(ty) = self { Some(ty) } else { None } } diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 9eb62c25892..28ccda39e4d 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -44,10 +44,10 @@ pub(crate) struct DocContext<'tcx> { /// Used while populating `external_traits` to ensure we don't process the same trait twice at /// the same time. pub(crate) active_extern_traits: DefIdSet, - // The current set of parameter substitutions, + // The current set of parameter instantiations, // for expanding type aliases at the HIR level: - /// Table `DefId` of type, lifetime, or const parameter -> substituted type, lifetime, or const - pub(crate) args: DefIdMap, + /// Table `DefId` of type, lifetime, or const parameter -> instantiated type, lifetime, or const + pub(crate) args: DefIdMap, pub(crate) current_type_aliases: DefIdMap, /// Table synthetic type parameter for `impl Trait` in argument position -> bounds pub(crate) impl_trait_bounds: FxHashMap>, @@ -84,10 +84,10 @@ impl<'tcx> DocContext<'tcx> { } /// Call the closure with the given parameters set as - /// the substitutions for a type alias' RHS. + /// the generic parameters for a type alias' RHS. pub(crate) fn enter_alias( &mut self, - args: DefIdMap, + args: DefIdMap, def_id: DefId, f: F, ) -> R From db8cb766e23e5438007c8dd12f3392b7f41be56e Mon Sep 17 00:00:00 2001 From: Shoyu Vanilla Date: Mon, 12 Feb 2024 16:24:41 +0900 Subject: [PATCH 34/56] Fix failing test --- tests/ui/on-unimplemented/bad-annotation.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/ui/on-unimplemented/bad-annotation.rs b/tests/ui/on-unimplemented/bad-annotation.rs index f05436b8c04..4c6610f8864 100644 --- a/tests/ui/on-unimplemented/bad-annotation.rs +++ b/tests/ui/on-unimplemented/bad-annotation.rs @@ -25,7 +25,7 @@ trait BadAnnotation2 {} #[rustc_on_unimplemented = "Unimplemented trait error on `{Self}` with params `<{A},{B},{}>`"] -//~^ only named substitution parameters are allowed +//~^ only named generic parameters are allowed trait BadAnnotation3 {} From 30774b00610bb3ab3339931f5eba21574d35a39a Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 9 Feb 2024 16:12:18 +1100 Subject: [PATCH 35/56] Remove final unwanted `unchecked_error_guaranteed` calls. Now that error counts can't go up and down due to stashing/stealing, we have a nice property: (err_count > 0) iff (an ErrorGuaranteed has been produced) So we can now record `ErrorGuaranteed`s within `DiagCtxt` and use that in methods like `has_error`, instead of checking that the count is greater than 0 and calling `unchecked_error_guaranteed` to create the `ErrorGuaranteed`. In fact, we can record a `Vec` and use its length to count the number, instead of maintaining a separate count. --- compiler/rustc_errors/src/lib.rs | 118 +++++++++++++++++-------------- 1 file changed, 65 insertions(+), 53 deletions(-) diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index ab3ad0e9d68..fc5a8ef13f0 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -428,10 +428,14 @@ pub struct DiagCtxt { struct DiagCtxtInner { flags: DiagCtxtFlags, - /// The number of lint errors that have been emitted, including duplicates. - lint_err_count: usize, - /// The number of non-lint errors that have been emitted, including duplicates. - err_count: usize, + /// The error guarantees from all emitted errors. The length gives the error count. + err_guars: Vec, + /// The error guarantee from all emitted lint errors. The length gives the + /// lint error count. + lint_err_guars: Vec, + /// The delayed bugs and their error guarantees. + delayed_bugs: Vec<(DelayedDiagnostic, ErrorGuaranteed)>, + good_path_delayed_bugs: Vec, /// The number of stashed errors. Unlike the other counts, this can go up /// and down, so it doesn't guarantee anything. @@ -447,8 +451,6 @@ struct DiagCtxtInner { has_printed: bool, emitter: Box, - delayed_bugs: Vec, - good_path_delayed_bugs: Vec, /// This flag indicates that an expected diagnostic was emitted and suppressed. /// This is used for the `good_path_delayed_bugs` check. suppressed_expected_diag: bool, @@ -560,7 +562,7 @@ impl Drop for DiagCtxtInner { fn drop(&mut self) { self.emit_stashed_diagnostics(); - if !self.has_errors() { + if self.err_guars.is_empty() { self.flush_delayed(DelayedBugKind::Normal) } @@ -604,15 +606,15 @@ impl DiagCtxt { Self { inner: Lock::new(DiagCtxtInner { flags: DiagCtxtFlags { can_emit_warnings: true, ..Default::default() }, - lint_err_count: 0, - err_count: 0, + err_guars: Vec::new(), + lint_err_guars: Vec::new(), + delayed_bugs: Vec::new(), + good_path_delayed_bugs: Vec::new(), stashed_err_count: 0, deduplicated_err_count: 0, deduplicated_warn_count: 0, has_printed: false, emitter, - delayed_bugs: Vec::new(), - good_path_delayed_bugs: Vec::new(), suppressed_expected_diag: false, taught_diagnostics: Default::default(), emitted_diagnostic_codes: Default::default(), @@ -661,14 +663,14 @@ impl DiagCtxt { /// the overall count of emitted error diagnostics. pub fn reset_err_count(&self) { let mut inner = self.inner.borrow_mut(); - inner.lint_err_count = 0; - inner.err_count = 0; inner.stashed_err_count = 0; inner.deduplicated_err_count = 0; inner.deduplicated_warn_count = 0; inner.has_printed = false; // actually free the underlying memory (which `clear` would not do) + inner.err_guars = Default::default(); + inner.lint_err_guars = Default::default(); inner.delayed_bugs = Default::default(); inner.good_path_delayed_bugs = Default::default(); inner.taught_diagnostics = Default::default(); @@ -932,7 +934,7 @@ impl DiagCtxt { /// This excludes lint errors, delayed bugs, and stashed errors. #[inline] pub fn err_count(&self) -> usize { - self.inner.borrow().err_count + self.inner.borrow().err_guars.len() } /// This excludes normal errors, lint errors and delayed bugs. Unless @@ -946,36 +948,19 @@ impl DiagCtxt { /// This excludes lint errors, delayed bugs, and stashed errors. pub fn has_errors(&self) -> Option { - self.inner.borrow().has_errors().then(|| { - // FIXME(nnethercote) find a way to store an `ErrorGuaranteed`. - #[allow(deprecated)] - ErrorGuaranteed::unchecked_error_guaranteed() - }) + self.inner.borrow().has_errors() } /// This excludes delayed bugs and stashed errors. Unless absolutely /// necessary, prefer `has_errors` to this method. pub fn has_errors_or_lint_errors(&self) -> Option { - let inner = self.inner.borrow(); - let result = inner.has_errors() || inner.lint_err_count > 0; - result.then(|| { - // FIXME(nnethercote) find a way to store an `ErrorGuaranteed`. - #[allow(deprecated)] - ErrorGuaranteed::unchecked_error_guaranteed() - }) + self.inner.borrow().has_errors_or_lint_errors() } /// This excludes stashed errors. Unless absolutely necessary, prefer /// `has_errors` or `has_errors_or_lint_errors` to this method. pub fn has_errors_or_lint_errors_or_delayed_bugs(&self) -> Option { - let inner = self.inner.borrow(); - let result = - inner.has_errors() || inner.lint_err_count > 0 || !inner.delayed_bugs.is_empty(); - result.then(|| { - // FIXME(nnethercote) find a way to store an `ErrorGuaranteed`. - #[allow(deprecated)] - ErrorGuaranteed::unchecked_error_guaranteed() - }) + self.inner.borrow().has_errors_or_lint_errors_or_delayed_bugs() } pub fn print_error_count(&self, registry: &Registry) { @@ -1055,7 +1040,7 @@ impl DiagCtxt { pub fn abort_if_errors(&self) { let mut inner = self.inner.borrow_mut(); inner.emit_stashed_diagnostics(); - if inner.has_errors() { + if !inner.err_guars.is_empty() { FatalError.raise(); } } @@ -1175,8 +1160,21 @@ impl DiagCtxt { ) { let mut inner = self.inner.borrow_mut(); + // This "error" is an odd duck. + // - It's only produce with JSON output. + // - It's not emitted the usual way, via `emit_diagnostic`. + // - The `$message_type` field is "unused_externs" rather than the usual + // "diagnosic". + // + // We count it as a lint error because it has a lint level. The value + // of `loud` (which comes from "unused-externs" or + // "unused-externs-silent"), also affects whether it's treated like a + // hard error or not. if loud && lint_level.is_error() { - inner.lint_err_count += 1; + // This `unchecked_error_guaranteed` is valid. It is where the + // `ErrorGuaranteed` for unused_extern errors originates. + #[allow(deprecated)] + inner.lint_err_guars.push(ErrorGuaranteed::unchecked_error_guaranteed()); inner.panic_if_treat_err_as_bug(); } @@ -1236,7 +1234,7 @@ impl DiagCtxt { impl DiagCtxtInner { /// Emit all stashed diagnostics. fn emit_stashed_diagnostics(&mut self) { - let has_errors = self.has_errors(); + let has_errors = !self.err_guars.is_empty(); for (_, diag) in std::mem::take(&mut self.stashed_diagnostics).into_iter() { // Decrement the count tracking the stash; emitting will increment it. if diag.is_error() { @@ -1298,9 +1296,13 @@ impl DiagCtxtInner { // when an error is first emitted, also), but maybe there's a case // in which that's not sound? otherwise this is really inefficient. let backtrace = std::backtrace::Backtrace::capture(); - self.delayed_bugs.push(DelayedDiagnostic::with_backtrace(diagnostic, backtrace)); + // This `unchecked_error_guaranteed` is valid. It is where the + // `ErrorGuaranteed` for delayed bugs originates. #[allow(deprecated)] - return Some(ErrorGuaranteed::unchecked_error_guaranteed()); + let guar = ErrorGuaranteed::unchecked_error_guaranteed(); + self.delayed_bugs + .push((DelayedDiagnostic::with_backtrace(diagnostic, backtrace), guar)); + return Some(guar); } GoodPathDelayedBug => { let backtrace = std::backtrace::Backtrace::capture(); @@ -1334,7 +1336,6 @@ impl DiagCtxtInner { !self.emitted_diagnostics.insert(diagnostic_hash) }; - let level = diagnostic.level; let is_error = diagnostic.is_error(); let is_lint = diagnostic.is_lint.is_some(); @@ -1373,36 +1374,47 @@ impl DiagCtxtInner { } if is_error { + // This `unchecked_error_guaranteed` is valid. It is where the + // `ErrorGuaranteed` for errors and lint errors originates. + #[allow(deprecated)] + let guar = ErrorGuaranteed::unchecked_error_guaranteed(); + guaranteed = Some(guar); if is_lint { - self.lint_err_count += 1; + self.lint_err_guars.push(guar); } else { - self.err_count += 1; + self.err_guars.push(guar); } self.panic_if_treat_err_as_bug(); } - - #[allow(deprecated)] - if level == Level::Error { - guaranteed = Some(ErrorGuaranteed::unchecked_error_guaranteed()); - } }); guaranteed } fn treat_err_as_bug(&self) -> bool { - self.flags.treat_err_as_bug.is_some_and(|c| self.err_count + self.lint_err_count >= c.get()) + self.flags + .treat_err_as_bug + .is_some_and(|c| self.err_guars.len() + self.lint_err_guars.len() >= c.get()) } // Use this one before incrementing `err_count`. fn treat_next_err_as_bug(&self) -> bool { self.flags .treat_err_as_bug - .is_some_and(|c| self.err_count + self.lint_err_count + 1 >= c.get()) + .is_some_and(|c| self.err_guars.len() + self.lint_err_guars.len() + 1 >= c.get()) } - fn has_errors(&self) -> bool { - self.err_count > 0 + fn has_errors(&self) -> Option { + self.err_guars.get(0).copied() + } + + fn has_errors_or_lint_errors(&self) -> Option { + self.has_errors().or_else(|| self.lint_err_guars.get(0).copied()) + } + + fn has_errors_or_lint_errors_or_delayed_bugs(&self) -> Option { + self.has_errors_or_lint_errors() + .or_else(|| self.delayed_bugs.get(0).map(|(_, guar)| guar).copied()) } fn failure_note(&mut self, msg: impl Into) { @@ -1412,7 +1424,7 @@ impl DiagCtxtInner { fn flush_delayed(&mut self, kind: DelayedBugKind) { let (bugs, note1) = match kind { DelayedBugKind::Normal => ( - std::mem::take(&mut self.delayed_bugs), + std::mem::take(&mut self.delayed_bugs).into_iter().map(|(b, _)| b).collect(), "no errors encountered even though delayed bugs were created", ), DelayedBugKind::GoodPath => ( @@ -1477,7 +1489,7 @@ impl DiagCtxtInner { fn panic_if_treat_err_as_bug(&self) { if self.treat_err_as_bug() { let n = self.flags.treat_err_as_bug.map(|c| c.get()).unwrap(); - assert_eq!(n, self.err_count + self.lint_err_count); + assert_eq!(n, self.err_guars.len() + self.lint_err_guars.len()); if n == 1 { panic!("aborting due to `-Z treat-err-as-bug=1`"); } else { From e0a0cc29710828066da211abf605e6c75c7410fc Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 12 Feb 2024 15:18:18 +1100 Subject: [PATCH 36/56] Remove `dcx` arg from `ReportErrorExt::add_args`. Because it also has a `DiagnosticBuilder` arg, which contains a `dcx` reference. Also rename some `builder` variables as `diag`, because that's the usual name. --- .../rustc_const_eval/src/const_eval/error.rs | 2 +- compiler/rustc_const_eval/src/errors.rs | 134 ++++++++---------- .../src/interpret/eval_context.rs | 2 +- 3 files changed, 62 insertions(+), 76 deletions(-) diff --git a/compiler/rustc_const_eval/src/const_eval/error.rs b/compiler/rustc_const_eval/src/const_eval/error.rs index 71085c2b2a5..80d02589900 100644 --- a/compiler/rustc_const_eval/src/const_eval/error.rs +++ b/compiler/rustc_const_eval/src/const_eval/error.rs @@ -151,7 +151,7 @@ where let mut err = tcx.dcx().create_err(err); let msg = error.diagnostic_message(); - error.add_args(tcx.dcx(), &mut err); + error.add_args(&mut err); // Use *our* span to label the interp error err.span_label(our_span, msg); diff --git a/compiler/rustc_const_eval/src/errors.rs b/compiler/rustc_const_eval/src/errors.rs index a649526c196..11679ab77e3 100644 --- a/compiler/rustc_const_eval/src/errors.rs +++ b/compiler/rustc_const_eval/src/errors.rs @@ -426,7 +426,7 @@ pub struct UndefinedBehavior { pub trait ReportErrorExt { /// Returns the diagnostic message for this error. fn diagnostic_message(&self) -> DiagnosticMessage; - fn add_args(self, dcx: &DiagCtxt, builder: &mut DiagnosticBuilder<'_, G>); + fn add_args(self, diag: &mut DiagnosticBuilder<'_, G>); fn debug(self) -> String where @@ -434,11 +434,11 @@ pub trait ReportErrorExt { { ty::tls::with(move |tcx| { let dcx = tcx.dcx(); - let mut builder = dcx.struct_allow(DiagnosticMessage::Str(String::new().into())); + let mut diag = dcx.struct_allow(DiagnosticMessage::Str(String::new().into())); let message = self.diagnostic_message(); - self.add_args(dcx, &mut builder); - let s = dcx.eagerly_translate_to_string(message, builder.args()); - builder.cancel(); + self.add_args(&mut diag); + let s = dcx.eagerly_translate_to_string(message, diag.args()); + diag.cancel(); s }) } @@ -505,20 +505,17 @@ impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> { } } - fn add_args( - self, - dcx: &DiagCtxt, - builder: &mut DiagnosticBuilder<'_, G>, - ) { + fn add_args(self, diag: &mut DiagnosticBuilder<'_, G>) { use UndefinedBehaviorInfo::*; + let dcx = diag.dcx; match self { Ub(_) => {} Custom(custom) => { (custom.add_args)(&mut |name, value| { - builder.arg(name, value); + diag.arg(name, value); }); } - ValidationError(e) => e.add_args(dcx, builder), + ValidationError(e) => e.add_args(diag), Unreachable | DivisionByZero @@ -533,20 +530,18 @@ impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> { | UninhabitedEnumVariantWritten(_) | UninhabitedEnumVariantRead(_) => {} BoundsCheckFailed { len, index } => { - builder.arg("len", len); - builder.arg("index", index); + diag.arg("len", len); + diag.arg("index", index); } UnterminatedCString(ptr) | InvalidFunctionPointer(ptr) | InvalidVTablePointer(ptr) => { - builder.arg("pointer", ptr); + diag.arg("pointer", ptr); } PointerUseAfterFree(alloc_id, msg) => { - builder - .arg("alloc_id", alloc_id) + diag.arg("alloc_id", alloc_id) .arg("bad_pointer_message", bad_pointer_message(msg, dcx)); } PointerOutOfBounds { alloc_id, alloc_size, ptr_offset, ptr_size, msg } => { - builder - .arg("alloc_id", alloc_id) + diag.arg("alloc_id", alloc_id) .arg("alloc_size", alloc_size.bytes()) .arg("ptr_offset", ptr_offset) .arg("ptr_size", ptr_size.bytes()) @@ -554,47 +549,47 @@ impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> { } DanglingIntPointer(ptr, msg) => { if ptr != 0 { - builder.arg("pointer", format!("{ptr:#x}[noalloc]")); + diag.arg("pointer", format!("{ptr:#x}[noalloc]")); } - builder.arg("bad_pointer_message", bad_pointer_message(msg, dcx)); + diag.arg("bad_pointer_message", bad_pointer_message(msg, dcx)); } AlignmentCheckFailed(Misalignment { required, has }, msg) => { - builder.arg("required", required.bytes()); - builder.arg("has", has.bytes()); - builder.arg("msg", format!("{msg:?}")); + diag.arg("required", required.bytes()); + diag.arg("has", has.bytes()); + diag.arg("msg", format!("{msg:?}")); } WriteToReadOnly(alloc) | DerefFunctionPointer(alloc) | DerefVTablePointer(alloc) => { - builder.arg("allocation", alloc); + diag.arg("allocation", alloc); } InvalidBool(b) => { - builder.arg("value", format!("{b:02x}")); + diag.arg("value", format!("{b:02x}")); } InvalidChar(c) => { - builder.arg("value", format!("{c:08x}")); + diag.arg("value", format!("{c:08x}")); } InvalidTag(tag) => { - builder.arg("tag", format!("{tag:x}")); + diag.arg("tag", format!("{tag:x}")); } InvalidStr(err) => { - builder.arg("err", format!("{err}")); + diag.arg("err", format!("{err}")); } InvalidUninitBytes(Some((alloc, info))) => { - builder.arg("alloc", alloc); - builder.arg("access", info.access); - builder.arg("uninit", info.bad); + diag.arg("alloc", alloc); + diag.arg("access", info.access); + diag.arg("uninit", info.bad); } ScalarSizeMismatch(info) => { - builder.arg("target_size", info.target_size); - builder.arg("data_size", info.data_size); + diag.arg("target_size", info.target_size); + diag.arg("data_size", info.data_size); } InvalidNichedEnumVariantWritten { enum_ty } => { - builder.arg("ty", enum_ty.to_string()); + diag.arg("ty", enum_ty.to_string()); } AbiMismatchArgument { caller_ty, callee_ty } | AbiMismatchReturn { caller_ty, callee_ty } => { - builder.arg("caller_ty", caller_ty.to_string()); - builder.arg("callee_ty", callee_ty.to_string()); + diag.arg("caller_ty", caller_ty.to_string()); + diag.arg("callee_ty", callee_ty.to_string()); } } } @@ -674,7 +669,7 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> { } } - fn add_args(self, dcx: &DiagCtxt, err: &mut DiagnosticBuilder<'_, G>) { + fn add_args(self, err: &mut DiagnosticBuilder<'_, G>) { use crate::fluent_generated as fluent; use rustc_middle::mir::interpret::ValidationErrorKind::*; @@ -684,12 +679,12 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> { } let message = if let Some(path) = self.path { - dcx.eagerly_translate_to_string( + err.dcx.eagerly_translate_to_string( fluent::const_eval_validation_front_matter_invalid_value_with_path, [("path".into(), DiagnosticArgValue::Str(path.into()))].iter().map(|(a, b)| (a, b)), ) } else { - dcx.eagerly_translate_to_string( + err.dcx.eagerly_translate_to_string( fluent::const_eval_validation_front_matter_invalid_value, [].into_iter(), ) @@ -700,7 +695,6 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> { fn add_range_arg( r: WrappingRange, max_hi: u128, - dcx: &DiagCtxt, err: &mut DiagnosticBuilder<'_, G>, ) { let WrappingRange { start: lo, end: hi } = r; @@ -724,7 +718,7 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> { ("hi".into(), DiagnosticArgValue::Str(hi.to_string().into())), ]; let args = args.iter().map(|(a, b)| (a, b)); - let message = dcx.eagerly_translate_to_string(msg, args); + let message = err.dcx.eagerly_translate_to_string(msg, args); err.arg("in_range", message); } @@ -746,7 +740,7 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> { ExpectedKind::EnumTag => fluent::const_eval_validation_expected_enum_tag, ExpectedKind::Str => fluent::const_eval_validation_expected_str, }; - let msg = dcx.eagerly_translate_to_string(msg, [].into_iter()); + let msg = err.dcx.eagerly_translate_to_string(msg, [].into_iter()); err.arg("expected", msg); } InvalidEnumTag { value } @@ -757,11 +751,11 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> { err.arg("value", value); } NullablePtrOutOfRange { range, max_value } | PtrOutOfRange { range, max_value } => { - add_range_arg(range, max_value, dcx, err) + add_range_arg(range, max_value, err) } OutOfRange { range, max_value, value } => { err.arg("value", value); - add_range_arg(range, max_value, dcx, err); + add_range_arg(range, max_value, err); } UnalignedPtr { required_bytes, found_bytes, .. } => { err.arg("required_bytes", required_bytes); @@ -802,13 +796,13 @@ impl ReportErrorExt for UnsupportedOpInfo { UnsupportedOpInfo::ExternStatic(_) => const_eval_extern_static, } } - fn add_args(self, _: &DiagCtxt, builder: &mut DiagnosticBuilder<'_, G>) { + fn add_args(self, diag: &mut DiagnosticBuilder<'_, G>) { use crate::fluent_generated::*; use UnsupportedOpInfo::*; if let ReadPointerAsInt(_) | OverwritePartialPointer(_) | ReadPartialPointer(_) = self { - builder.help(const_eval_ptr_as_bytes_1); - builder.help(const_eval_ptr_as_bytes_2); + diag.help(const_eval_ptr_as_bytes_1); + diag.help(const_eval_ptr_as_bytes_2); } match self { // `ReadPointerAsInt(Some(info))` is never printed anyway, it only serves as an error to @@ -816,10 +810,10 @@ impl ReportErrorExt for UnsupportedOpInfo { // print. So it's not worth the effort of having diagnostics that can print the `info`. UnsizedLocal | Unsupported(_) | ReadPointerAsInt(_) => {} OverwritePartialPointer(ptr) | ReadPartialPointer(ptr) => { - builder.arg("ptr", ptr); + diag.arg("ptr", ptr); } ThreadLocalStatic(did) | ExternStatic(did) => { - builder.arg("did", format!("{did:?}")); + diag.arg("did", format!("{did:?}")); } } } @@ -835,18 +829,14 @@ impl<'tcx> ReportErrorExt for InterpError<'tcx> { InterpError::MachineStop(e) => e.diagnostic_message(), } } - fn add_args( - self, - dcx: &DiagCtxt, - builder: &mut DiagnosticBuilder<'_, G>, - ) { + fn add_args(self, diag: &mut DiagnosticBuilder<'_, G>) { match self { - InterpError::UndefinedBehavior(ub) => ub.add_args(dcx, builder), - InterpError::Unsupported(e) => e.add_args(dcx, builder), - InterpError::InvalidProgram(e) => e.add_args(dcx, builder), - InterpError::ResourceExhaustion(e) => e.add_args(dcx, builder), + InterpError::UndefinedBehavior(ub) => ub.add_args(diag), + InterpError::Unsupported(e) => e.add_args(diag), + InterpError::InvalidProgram(e) => e.add_args(diag), + InterpError::ResourceExhaustion(e) => e.add_args(diag), InterpError::MachineStop(e) => e.add_args(&mut |name, value| { - builder.arg(name, value); + diag.arg(name, value); }), } } @@ -864,28 +854,24 @@ impl<'tcx> ReportErrorExt for InvalidProgramInfo<'tcx> { } } } - fn add_args( - self, - dcx: &DiagCtxt, - builder: &mut DiagnosticBuilder<'_, G>, - ) { + fn add_args(self, diag: &mut DiagnosticBuilder<'_, G>) { match self { InvalidProgramInfo::TooGeneric | InvalidProgramInfo::AlreadyReported(_) => {} InvalidProgramInfo::Layout(e) => { - // The level doesn't matter, `diag` is consumed without it being used. + // The level doesn't matter, `dummy_diag` is consumed without it being used. let dummy_level = Level::Bug; - let diag: DiagnosticBuilder<'_, ()> = - e.into_diagnostic().into_diagnostic(dcx, dummy_level); - for (name, val) in diag.args() { - builder.arg(name.clone(), val.clone()); + let dummy_diag: DiagnosticBuilder<'_, ()> = + e.into_diagnostic().into_diagnostic(diag.dcx, dummy_level); + for (name, val) in dummy_diag.args() { + diag.arg(name.clone(), val.clone()); } - diag.cancel(); + dummy_diag.cancel(); } InvalidProgramInfo::FnAbiAdjustForForeignAbi( AdjustForForeignAbiError::Unsupported { arch, abi }, ) => { - builder.arg("arch", arch); - builder.arg("abi", abi.name()); + diag.arg("arch", arch); + diag.arg("abi", abi.name()); } } } @@ -900,7 +886,7 @@ impl ReportErrorExt for ResourceExhaustionInfo { ResourceExhaustionInfo::AddressSpaceFull => const_eval_address_space_full, } } - fn add_args(self, _: &DiagCtxt, _: &mut DiagnosticBuilder<'_, G>) {} + fn add_args(self, _: &mut DiagnosticBuilder<'_, G>) {} } impl rustc_errors::IntoDiagnosticArg for InternKind { diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs index dd9dfe3fe79..ff90059203a 100644 --- a/compiler/rustc_const_eval/src/interpret/eval_context.rs +++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs @@ -445,7 +445,7 @@ pub fn format_interp_error<'tcx>(dcx: &DiagCtxt, e: InterpErrorInfo<'tcx>) -> St #[allow(rustc::untranslatable_diagnostic)] let mut diag = dcx.struct_allow(""); let msg = e.diagnostic_message(); - e.add_args(dcx, &mut diag); + e.add_args(&mut diag); let s = dcx.eagerly_translate_to_string(msg, diag.args()); diag.cancel(); s From d4b77f64e4085f06caf5bd4ef8ae3c64d681eeff Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 12 Feb 2024 15:26:59 +1100 Subject: [PATCH 37/56] Tweak delayed bug mentions. Now that we have both `delayed_bug` and `span_delayed_bug`, it makes sense to use the generic term "delayed bug" more. --- compiler/rustc_errors/src/lib.rs | 6 +++--- compiler/rustc_feature/src/builtin_attrs.rs | 2 +- compiler/rustc_hir_analysis/src/check/wfcheck.rs | 6 +++--- .../rustc_infer/src/infer/canonical/canonicalizer.rs | 2 +- compiler/rustc_interface/src/queries.rs | 6 +++--- compiler/rustc_middle/src/query/mod.rs | 6 +++--- compiler/rustc_middle/src/ty/region.rs | 8 ++++---- compiler/rustc_middle/src/ty/visit.rs | 2 +- compiler/rustc_middle/src/util/bug.rs | 12 ++++++------ compiler/rustc_span/src/symbol.rs | 2 +- src/tools/clippy/tests/integration.rs | 2 +- .../rust-analyzer/crates/hir-def/src/attr/builtin.rs | 2 +- tests/incremental/delayed_span_bug.rs | 4 ++-- tests/ui/treat-err-as-bug/span_delayed_bug.rs | 4 ++-- tests/ui/treat-err-as-bug/span_delayed_bug.stderr | 4 ++-- 15 files changed, 34 insertions(+), 34 deletions(-) diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index fc5a8ef13f0..2a68443ee38 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -411,8 +411,8 @@ impl CodeSuggestion { /// or `.span_bug` rather than a failed assertion, etc. pub struct ExplicitBug; -/// Signifies that the compiler died with an explicit call to `.delay_*_bug` -/// rather than a failed assertion, etc. +/// Signifies that the compiler died due to a delayed bug rather than a failed +/// assertion, etc. pub struct DelayedBugPanic; /// A `DiagCtxt` deals with errors and other compiler output. @@ -1446,7 +1446,7 @@ impl DiagCtxtInner { { let _ = write!( &mut out, - "delayed span bug: {}\n{}\n", + "delayed bug: {}\n{}\n", bug.inner .messages .iter() diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 019cc1c847e..6aedd2a5e33 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -806,7 +806,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ rustc_attr!(TEST, rustc_regions, Normal, template!(Word), WarnFollowing), rustc_attr!( TEST, rustc_error, Normal, - template!(Word, List: "span_delayed_bug_from_inside_query"), WarnFollowingWordOnly + template!(Word, List: "delayed_bug_from_inside_query"), WarnFollowingWordOnly ), rustc_attr!(TEST, rustc_dump_user_args, Normal, template!(Word), WarnFollowing), rustc_attr!(TEST, rustc_evaluate_where_clauses, Normal, template!(Word), WarnFollowing), diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 646a84b043c..1bdfa452360 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -118,9 +118,9 @@ where return Err(err); } else { // HACK(oli-obk): tests/ui/specialization/min_specialization/specialize_on_type_error.rs - // causes an error (span_delayed_bug) during normalization, without reporting an error, - // so we need to act as if no error happened, in order to let our callers continue and - // report an error later in check_impl_items_against_trait. + // causes an delayed bug during normalization, without reporting an error, so we need + // to act as if no error happened, in order to let our callers continue and report an + // error later in check_impl_items_against_trait. return Ok(()); } } diff --git a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs index 156a4f71017..99882a42abc 100644 --- a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs +++ b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs @@ -191,7 +191,7 @@ impl CanonicalizeMode for CanonicalizeQueryResponse { // // rust-lang/rust#57464: `impl Trait` can leak local // scopes (in manner violating typeck). Therefore, use - // `span_delayed_bug` to allow type error over an ICE. + // `delayed_bug` to allow type error over an ICE. canonicalizer .tcx .dcx() diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs index e66ea6f2ca9..2a4eefb7f77 100644 --- a/compiler/rustc_interface/src/queries.rs +++ b/compiler/rustc_interface/src/queries.rs @@ -194,16 +194,16 @@ impl<'tcx> Queries<'tcx> { let Some((def_id, _)) = tcx.entry_fn(()) else { return }; for attr in tcx.get_attrs(def_id, sym::rustc_error) { match attr.meta_item_list() { - // Check if there is a `#[rustc_error(span_delayed_bug_from_inside_query)]`. + // Check if there is a `#[rustc_error(delayed_bug_from_inside_query)]`. Some(list) if list.iter().any(|list_item| { matches!( list_item.ident().map(|i| i.name), - Some(sym::span_delayed_bug_from_inside_query) + Some(sym::delayed_bug_from_inside_query) ) }) => { - tcx.ensure().trigger_span_delayed_bug(def_id); + tcx.ensure().trigger_delayed_bug(def_id); } // Bare `#[rustc_error]`. diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 938fba0ed09..5fe736c9047 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -108,9 +108,9 @@ pub use plumbing::{IntoQueryParam, TyCtxtAt, TyCtxtEnsure, TyCtxtEnsureWithValue // Queries marked with `fatal_cycle` do not need the latter implementation, // as they will raise an fatal error on query cycles instead. rustc_queries! { - /// This exists purely for testing the interactions between span_delayed_bug and incremental. - query trigger_span_delayed_bug(key: DefId) { - desc { "triggering a span delayed bug for testing incremental" } + /// This exists purely for testing the interactions between delayed bugs and incremental. + query trigger_delayed_bug(key: DefId) { + desc { "triggering a delayed bug for testing incremental" } } /// Collects the list of all tools registered using `#![register_tool]`. diff --git a/compiler/rustc_middle/src/ty/region.rs b/compiler/rustc_middle/src/ty/region.rs index 75be380704e..1191d7fca32 100644 --- a/compiler/rustc_middle/src/ty/region.rs +++ b/compiler/rustc_middle/src/ty/region.rs @@ -82,8 +82,8 @@ impl<'tcx> Region<'tcx> { tcx.intern_region(ty::ReError(reported)) } - /// Constructs a `RegionKind::ReError` region and registers a `span_delayed_bug` to ensure it - /// gets used. + /// Constructs a `RegionKind::ReError` region and registers a delayed bug to ensure it gets + /// used. #[track_caller] pub fn new_error_misc(tcx: TyCtxt<'tcx>) -> Region<'tcx> { Region::new_error_with_message( @@ -93,8 +93,8 @@ impl<'tcx> Region<'tcx> { ) } - /// Constructs a `RegionKind::ReError` region and registers a `span_delayed_bug` with the given - /// `msg` to ensure it gets used. + /// Constructs a `RegionKind::ReError` region and registers a delayed bug with the given `msg` + /// to ensure it gets used. #[track_caller] pub fn new_error_with_message>( tcx: TyCtxt<'tcx>, diff --git a/compiler/rustc_middle/src/ty/visit.rs b/compiler/rustc_middle/src/ty/visit.rs index a750a86d257..7acdb931f1a 100644 --- a/compiler/rustc_middle/src/ty/visit.rs +++ b/compiler/rustc_middle/src/ty/visit.rs @@ -55,7 +55,7 @@ pub trait TypeVisitableExt<'tcx>: TypeVisitable> { } fn error_reported(&self) -> Result<(), ErrorGuaranteed> { if self.references_error() { - // We must include lint errors and span delayed bugs here. + // We must include lint errors and delayed bugs here. if let Some(reported) = ty::tls::with(|tcx| tcx.dcx().has_errors_or_lint_errors_or_delayed_bugs()) { diff --git a/compiler/rustc_middle/src/util/bug.rs b/compiler/rustc_middle/src/util/bug.rs index d1a3dbbf5d3..a67ec991582 100644 --- a/compiler/rustc_middle/src/util/bug.rs +++ b/compiler/rustc_middle/src/util/bug.rs @@ -38,16 +38,16 @@ fn opt_span_bug_fmt>( }) } -/// A query to trigger a `span_delayed_bug`. Clearly, if one has a `tcx` one can already trigger a -/// `span_delayed_bug`, so what is the point of this? It exists to help us test `span_delayed_bug`'s -/// interactions with the query system and incremental. -pub fn trigger_span_delayed_bug(tcx: TyCtxt<'_>, key: rustc_hir::def_id::DefId) { +/// A query to trigger a delayed bug. Clearly, if one has a `tcx` one can already trigger a +/// delayed bug, so what is the point of this? It exists to help us test the interaction of delayed +/// bugs with the query system and incremental. +pub fn trigger_delayed_bug(tcx: TyCtxt<'_>, key: rustc_hir::def_id::DefId) { tcx.dcx().span_delayed_bug( tcx.def_span(key), - "delayed span bug triggered by #[rustc_error(span_delayed_bug_from_inside_query)]", + "delayed bug triggered by #[rustc_error(delayed_bug_from_inside_query)]", ); } pub fn provide(providers: &mut crate::query::Providers) { - *providers = crate::query::Providers { trigger_span_delayed_bug, ..*providers }; + *providers = crate::query::Providers { trigger_delayed_bug, ..*providers }; } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index aa912c93c08..83eca6c032b 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -655,6 +655,7 @@ symbols! { default_method_body_is_const, default_type_parameter_fallback, default_type_params, + delayed_bug_from_inside_query, deny, deprecated, deprecated_safe, @@ -1579,7 +1580,6 @@ symbols! { slice_patterns, slicing_syntax, soft, - span_delayed_bug_from_inside_query, specialization, speed, spotlight, diff --git a/src/tools/clippy/tests/integration.rs b/src/tools/clippy/tests/integration.rs index 267f095f9c2..7f4500826ff 100644 --- a/src/tools/clippy/tests/integration.rs +++ b/src/tools/clippy/tests/integration.rs @@ -77,7 +77,7 @@ fn integration_test() { // the repo basically just contains a span_delayed_bug that forces rustc/clippy to panic: /* #![feature(rustc_attrs)] - #[rustc_error(span_delayed_bug_from_inside_query)] + #[rustc_error(delayed_bug_from_inside_query)] fn main() {} */ diff --git a/src/tools/rust-analyzer/crates/hir-def/src/attr/builtin.rs b/src/tools/rust-analyzer/crates/hir-def/src/attr/builtin.rs index b20ee9e5bf6..55b9a1dfdcb 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/attr/builtin.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/attr/builtin.rs @@ -650,7 +650,7 @@ pub const INERT_ATTRIBUTES: &[BuiltinAttribute] = &[ rustc_attr!(TEST, rustc_regions, Normal, template!(Word), WarnFollowing), rustc_attr!( TEST, rustc_error, Normal, - template!(Word, List: "span_delayed_bug_from_inside_query"), WarnFollowingWordOnly + template!(Word, List: "delayed_bug_from_inside_query"), WarnFollowingWordOnly ), rustc_attr!(TEST, rustc_dump_user_args, Normal, template!(Word), WarnFollowing), rustc_attr!(TEST, rustc_evaluate_where_clauses, Normal, template!(Word), WarnFollowing), diff --git a/tests/incremental/delayed_span_bug.rs b/tests/incremental/delayed_span_bug.rs index cc9831fff96..5c9d3c2c1d5 100644 --- a/tests/incremental/delayed_span_bug.rs +++ b/tests/incremental/delayed_span_bug.rs @@ -1,8 +1,8 @@ // revisions: cfail1 cfail2 // should-ice -// error-pattern: delayed span bug triggered by #[rustc_error(span_delayed_bug_from_inside_query)] +// error-pattern: delayed bug triggered by #[rustc_error(delayed_bug_from_inside_query)] #![feature(rustc_attrs)] -#[rustc_error(span_delayed_bug_from_inside_query)] +#[rustc_error(delayed_bug_from_inside_query)] fn main() {} diff --git a/tests/ui/treat-err-as-bug/span_delayed_bug.rs b/tests/ui/treat-err-as-bug/span_delayed_bug.rs index 8b9526bf3f9..1ea14aee6c4 100644 --- a/tests/ui/treat-err-as-bug/span_delayed_bug.rs +++ b/tests/ui/treat-err-as-bug/span_delayed_bug.rs @@ -1,12 +1,12 @@ // compile-flags: -Ztreat-err-as-bug -Zeagerly-emit-delayed-bugs // failure-status: 101 // error-pattern: aborting due to `-Z treat-err-as-bug=1` -// error-pattern: [trigger_span_delayed_bug] triggering a span delayed bug for testing incremental +// error-pattern: [trigger_delayed_bug] triggering a delayed bug for testing incremental // normalize-stderr-test "note: .*\n\n" -> "" // normalize-stderr-test "thread 'rustc' panicked.*:\n.*\n" -> "" // rustc-env:RUST_BACKTRACE=0 #![feature(rustc_attrs)] -#[rustc_error(span_delayed_bug_from_inside_query)] +#[rustc_error(delayed_bug_from_inside_query)] fn main() {} diff --git a/tests/ui/treat-err-as-bug/span_delayed_bug.stderr b/tests/ui/treat-err-as-bug/span_delayed_bug.stderr index a61ffaea8c2..f0e8cd0ddb9 100644 --- a/tests/ui/treat-err-as-bug/span_delayed_bug.stderr +++ b/tests/ui/treat-err-as-bug/span_delayed_bug.stderr @@ -1,4 +1,4 @@ -error: internal compiler error: delayed span bug triggered by #[rustc_error(span_delayed_bug_from_inside_query)] +error: internal compiler error: delayed bug triggered by #[rustc_error(delayed_bug_from_inside_query)] --> $DIR/span_delayed_bug.rs:12:1 | LL | fn main() {} @@ -7,5 +7,5 @@ LL | fn main() {} error: the compiler unexpectedly panicked. this is a bug. query stack during panic: -#0 [trigger_span_delayed_bug] triggering a span delayed bug for testing incremental +#0 [trigger_delayed_bug] triggering a delayed bug for testing incremental end of query stack From 1f39c8b08f2a9d30916a77beaf518f8d58d13a62 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 12 Feb 2024 16:34:39 +1100 Subject: [PATCH 38/56] Change level used in `print_error_count`. From `Fatal` to `Error`. It has no functional effect, but `Error` makes more sense and lines up better with the `Warning` level used just above. --- compiler/rustc_errors/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 2a68443ee38..16077b3d98f 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -993,10 +993,10 @@ impl DiagCtxt { .emit_diagnostic(Diagnostic::new(Warning, DiagnosticMessage::Str(warnings))); } (_, 0) => { - inner.emit_diagnostic(Diagnostic::new(Fatal, errors)); + inner.emit_diagnostic(Diagnostic::new(Error, errors)); } (_, _) => { - inner.emit_diagnostic(Diagnostic::new(Fatal, format!("{errors}; {warnings}"))); + inner.emit_diagnostic(Diagnostic::new(Error, format!("{errors}; {warnings}"))); } } From 5fa69deb006aaec28e5e9aba6ca1faf66e36ae1f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 12 Feb 2024 08:51:41 +0100 Subject: [PATCH 39/56] fix cycle error when a static and a promoted are mutually recursive This also now allows promoteds everywhere to point to 'extern static', because why not? We still check that constants cannot transitively reach 'extern static' through references. (We allow it through raw pointers.) --- .../src/const_eval/eval_queries.rs | 13 ++------- .../src/interpret/validity.rs | 28 ++++++++++--------- tests/ui/consts/cycle-static-promoted.rs | 12 ++++++++ 3 files changed, 29 insertions(+), 24 deletions(-) create mode 100644 tests/ui/consts/cycle-static-promoted.rs diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs index 0844cdbe99b..c55d899e4d5 100644 --- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs @@ -356,22 +356,13 @@ pub fn const_validate_mplace<'mir, 'tcx>( let mut inner = false; while let Some((mplace, path)) = ref_tracking.todo.pop() { let mode = match ecx.tcx.static_mutability(cid.instance.def_id()) { - Some(_) if cid.promoted.is_some() => { - // Promoteds in statics are consts that re allowed to point to statics. - CtfeValidationMode::Const { - allow_immutable_unsafe_cell: false, - allow_extern_static_ptrs: true, - } - } + _ if cid.promoted.is_some() => CtfeValidationMode::Promoted, Some(mutbl) => CtfeValidationMode::Static { mutbl }, // a `static` None => { // In normal `const` (not promoted), the outermost allocation is always only copied, // so having `UnsafeCell` in there is okay despite them being in immutable memory. let allow_immutable_unsafe_cell = cid.promoted.is_none() && !inner; - CtfeValidationMode::Const { - allow_immutable_unsafe_cell, - allow_extern_static_ptrs: false, - } + CtfeValidationMode::Const { allow_immutable_unsafe_cell } } }; ecx.const_validate_operand(&mplace.into(), path, &mut ref_tracking, mode)?; diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs index 38aeace02ba..05e28db652f 100644 --- a/compiler/rustc_const_eval/src/interpret/validity.rs +++ b/compiler/rustc_const_eval/src/interpret/validity.rs @@ -129,17 +129,20 @@ pub enum PathElem { pub enum CtfeValidationMode { /// Validation of a `static` Static { mutbl: Mutability }, - /// Validation of a `const` (including promoteds). + /// Validation of a promoted. + Promoted, + /// Validation of a `const`. /// `allow_immutable_unsafe_cell` says whether we allow `UnsafeCell` in immutable memory (which is the /// case for the top-level allocation of a `const`, where this is fine because the allocation will be /// copied at each use site). - Const { allow_immutable_unsafe_cell: bool, allow_extern_static_ptrs: bool }, + Const { allow_immutable_unsafe_cell: bool }, } impl CtfeValidationMode { fn allow_immutable_unsafe_cell(self) -> bool { match self { CtfeValidationMode::Static { .. } => false, + CtfeValidationMode::Promoted { .. } => false, CtfeValidationMode::Const { allow_immutable_unsafe_cell, .. } => { allow_immutable_unsafe_cell } @@ -149,6 +152,7 @@ impl CtfeValidationMode { fn may_contain_mutable_ref(self) -> bool { match self { CtfeValidationMode::Static { mutbl } => mutbl == Mutability::Mut, + CtfeValidationMode::Promoted { .. } => false, CtfeValidationMode::Const { .. } => false, } } @@ -476,34 +480,32 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' throw_validation_failure!(self.path, MutableRefToImmutable); } } + // Mode-specific checks match self.ctfe_mode { - Some(CtfeValidationMode::Static { .. }) => { + Some( + CtfeValidationMode::Static { .. } + | CtfeValidationMode::Promoted { .. }, + ) => { // We skip recursively checking other statics. These statics must be sound by // themselves, and the only way to get broken statics here is by using // unsafe code. // The reasons we don't check other statics is twofold. For one, in all // sound cases, the static was already validated on its own, and second, we // trigger cycle errors if we try to compute the value of the other static - // and that static refers back to us. + // and that static refers back to us (potentially through a promoted). // This could miss some UB, but that's fine. return Ok(()); } - Some(CtfeValidationMode::Const { - allow_extern_static_ptrs, .. - }) => { + Some(CtfeValidationMode::Const { .. }) => { // For consts on the other hand we have to recursively check; // pattern matching assumes a valid value. However we better make // sure this is not mutable. if is_mut { throw_validation_failure!(self.path, ConstRefToMutable); } + // We can't recursively validate `extern static`, so we better reject them. if self.ecx.tcx.is_foreign_item(did) { - if !allow_extern_static_ptrs { - throw_validation_failure!(self.path, ConstRefToExtern); - } else { - // We can't validate this... - return Ok(()); - } + throw_validation_failure!(self.path, ConstRefToExtern); } } None => {} diff --git a/tests/ui/consts/cycle-static-promoted.rs b/tests/ui/consts/cycle-static-promoted.rs new file mode 100644 index 00000000000..5838dc58a3a --- /dev/null +++ b/tests/ui/consts/cycle-static-promoted.rs @@ -0,0 +1,12 @@ +// check-pass + +struct Value { + values: &'static [&'static Value], +} + +// This `static` recursively points to itself through a promoted (the slice). +static VALUE: Value = Value { + values: &[&VALUE], +}; + +fn main() {} From 8959434c70c2d3de86f5a1539792fa06de3c5715 Mon Sep 17 00:00:00 2001 From: Shoyu Vanilla Date: Mon, 12 Feb 2024 18:09:39 +0900 Subject: [PATCH 40/56] Fix failing test --- tests/ui/on-unimplemented/bad-annotation.stderr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/ui/on-unimplemented/bad-annotation.stderr b/tests/ui/on-unimplemented/bad-annotation.stderr index a8d3c8680fa..9bb9423788c 100644 --- a/tests/ui/on-unimplemented/bad-annotation.stderr +++ b/tests/ui/on-unimplemented/bad-annotation.stderr @@ -17,7 +17,7 @@ error[E0230]: there is no parameter `C` on trait `BadAnnotation2` LL | #[rustc_on_unimplemented = "Unimplemented trait error on `{Self}` with params `<{A},{B},{C}>`"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0231]: only named substitution parameters are allowed +error[E0231]: only named generic parameters are allowed --> $DIR/bad-annotation.rs:27:1 | LL | #[rustc_on_unimplemented = "Unimplemented trait error on `{Self}` with params `<{A},{B},{}>`"] From 916951efcc51bb7c225a0dba676c34adef620f1d Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Sat, 10 Feb 2024 21:26:48 +0000 Subject: [PATCH 41/56] Make impl_trait_ref into a query also returning more information about the impl --- compiler/rustc_hir_analysis/src/collect.rs | 51 +++++++++---------- .../src/persist/dirty_clean.rs | 2 +- .../src/rmeta/decoder/cstore_impl.rs | 2 +- compiler/rustc_metadata/src/rmeta/encoder.rs | 5 +- compiler/rustc_metadata/src/rmeta/mod.rs | 2 +- compiler/rustc_middle/src/query/erase.rs | 5 +- compiler/rustc_middle/src/query/mod.rs | 4 +- compiler/rustc_middle/src/ty/context.rs | 9 ++++ tests/incremental/hashes/trait_impls.rs | 8 +-- 9 files changed, 48 insertions(+), 40 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index f458ff01c10..0f0facdca65 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -78,7 +78,7 @@ pub fn provide(providers: &mut Providers) { trait_def, adt_def, fn_sig, - impl_trait_ref, + impl_trait_header, impl_polarity, coroutine_kind, coroutine_for_closure, @@ -598,7 +598,7 @@ fn convert_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) { hir::ItemKind::Impl { .. } => { tcx.ensure().generics_of(def_id); tcx.ensure().type_of(def_id); - tcx.ensure().impl_trait_ref(def_id); + tcx.ensure().impl_trait_header(def_id); tcx.ensure().predicates_of(def_id); } hir::ItemKind::Trait(..) => { @@ -1323,19 +1323,20 @@ fn suggest_impl_trait<'tcx>( None } -fn impl_trait_ref( +fn impl_trait_header( tcx: TyCtxt<'_>, def_id: LocalDefId, -) -> Option>> { +) -> Option<(ty::EarlyBinder>, ty::ImplPolarity)> { let icx = ItemCtxt::new(tcx, def_id); - let impl_ = tcx.hir().expect_item(def_id).expect_impl(); + let item = tcx.hir().expect_item(def_id); + let impl_ = item.expect_impl(); impl_ .of_trait .as_ref() .map(|ast_trait_ref| { let selfty = tcx.type_of(def_id).instantiate_identity(); - if let Some(ErrorGuaranteed { .. }) = check_impl_constness( + let impl_trait_ref = if let Some(ErrorGuaranteed { .. }) = check_impl_constness( tcx, tcx.is_const_trait_impl_raw(def_id.to_def_id()), ast_trait_ref, @@ -1360,9 +1361,9 @@ fn impl_trait_ref( icx.astconv().instantiate_mono_trait_ref(trait_ref, selfty) } else { icx.astconv().instantiate_mono_trait_ref(ast_trait_ref, selfty) - } + }; + (ty::EarlyBinder::bind(impl_trait_ref), polarity_of_impl(tcx, def_id, impl_, item.span)) }) - .map(ty::EarlyBinder::bind) } fn check_impl_constness( @@ -1391,42 +1392,38 @@ fn check_impl_constness( } fn impl_polarity(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::ImplPolarity { - let is_rustc_reservation = tcx.has_attr(def_id, sym::rustc_reservation_impl); let item = tcx.hir().expect_item(def_id); - match &item.kind { - hir::ItemKind::Impl(hir::Impl { - polarity: hir::ImplPolarity::Negative(span), - of_trait, - .. - }) => { + polarity_of_impl(tcx, def_id, item.expect_impl(), item.span) +} + +fn polarity_of_impl( + tcx: TyCtxt<'_>, + def_id: LocalDefId, + impl_: &hir::Impl<'_>, + span: Span, +) -> ty::ImplPolarity { + let is_rustc_reservation = tcx.has_attr(def_id, sym::rustc_reservation_impl); + match &impl_ { + hir::Impl { polarity: hir::ImplPolarity::Negative(span), of_trait, .. } => { if is_rustc_reservation { let span = span.to(of_trait.as_ref().map_or(*span, |t| t.path.span)); tcx.dcx().span_err(span, "reservation impls can't be negative"); } ty::ImplPolarity::Negative } - hir::ItemKind::Impl(hir::Impl { - polarity: hir::ImplPolarity::Positive, - of_trait: None, - .. - }) => { + hir::Impl { polarity: hir::ImplPolarity::Positive, of_trait: None, .. } => { if is_rustc_reservation { - tcx.dcx().span_err(item.span, "reservation impls can't be inherent"); + tcx.dcx().span_err(span, "reservation impls can't be inherent"); } ty::ImplPolarity::Positive } - hir::ItemKind::Impl(hir::Impl { - polarity: hir::ImplPolarity::Positive, - of_trait: Some(_), - .. - }) => { + hir::Impl { polarity: hir::ImplPolarity::Positive, of_trait: Some(_), .. } => { if is_rustc_reservation { ty::ImplPolarity::Reservation } else { ty::ImplPolarity::Positive } } - item => bug!("impl_polarity: {:?} not an impl", item), } } diff --git a/compiler/rustc_incremental/src/persist/dirty_clean.rs b/compiler/rustc_incremental/src/persist/dirty_clean.rs index 14cc8c260e2..8311a735133 100644 --- a/compiler/rustc_incremental/src/persist/dirty_clean.rs +++ b/compiler/rustc_incremental/src/persist/dirty_clean.rs @@ -63,7 +63,7 @@ const BASE_HIR: &[&str] = &[ /// `impl` implementation of struct/trait const BASE_IMPL: &[&str] = - &[label_strs::associated_item_def_ids, label_strs::generics_of, label_strs::impl_trait_ref]; + &[label_strs::associated_item_def_ids, label_strs::generics_of, label_strs::impl_trait_header]; /// DepNodes for mir_built/Optimized, which is relevant in "executable" /// code, i.e., functions+methods diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index 988388edfd5..058f28a3ee9 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -215,7 +215,7 @@ provide! { tcx, def_id, other, cdata, variances_of => { table } fn_sig => { table } codegen_fn_attrs => { table } - impl_trait_ref => { table } + impl_trait_header => { table } const_param_default => { table } object_lifetime_default => { table } thir_abstract_const => { table } diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 6ca1973396f..361c0a3f87e 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1971,8 +1971,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { self.tables.defaultness.set_some(def_id.index, tcx.defaultness(def_id)); self.tables.impl_polarity.set_some(def_id.index, tcx.impl_polarity(def_id)); - if of_trait && let Some(trait_ref) = tcx.impl_trait_ref(def_id) { - record!(self.tables.impl_trait_ref[def_id] <- trait_ref); + if of_trait && let Some(header) = tcx.impl_trait_header(def_id) { + record!(self.tables.impl_trait_header[def_id] <- header); + let (trait_ref, _polarity) = header; let trait_ref = trait_ref.instantiate_identity(); let simplified_self_ty = fast_reject::simplify_type( diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index 8205e995c19..f2d4ae11105 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -423,7 +423,7 @@ define_tables! { variances_of: Table>, fn_sig: Table>>>, codegen_fn_attrs: Table>, - impl_trait_ref: Table>>>, + impl_trait_header: Table>, ty::ImplPolarity)>>, const_param_default: Table>>>, object_lifetime_default: Table>, optimized_mir: Table>>, diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs index a272a51f327..e15a051b33f 100644 --- a/compiler/rustc_middle/src/query/erase.rs +++ b/compiler/rustc_middle/src/query/erase.rs @@ -177,8 +177,9 @@ impl EraseType for Option> { type Result = [u8; size_of::>>()]; } -impl EraseType for Option>> { - type Result = [u8; size_of::>>>()]; +impl EraseType for Option<(ty::EarlyBinder>, ty::ImplPolarity)> { + type Result = + [u8; size_of::>, ty::ImplPolarity)>>()]; } impl EraseType for Option>> { diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 938fba0ed09..59fb198a3da 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -846,9 +846,9 @@ rustc_queries! { cache_on_disk_if { true } } - /// Given an `impl_id`, return the trait it implements. + /// Given an `impl_id`, return the trait it implements along with some header information. /// Return `None` if this is an inherent impl. - query impl_trait_ref(impl_id: DefId) -> Option>> { + query impl_trait_header(impl_id: DefId) -> Option<(ty::EarlyBinder>, ty::ImplPolarity)> { desc { |tcx| "computing trait implemented by `{}`", tcx.def_path_str(impl_id) } cache_on_disk_if { impl_id.is_local() } separate_provide_extern diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index b747f0a4fb6..c3b69cee9ed 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -2308,6 +2308,15 @@ impl<'tcx> TyCtxt<'tcx> { pub fn module_children_local(self, def_id: LocalDefId) -> &'tcx [ModChild] { self.resolutions(()).module_children.get(&def_id).map_or(&[], |v| &v[..]) } + + /// Given an `impl_id`, return the trait it implements. + /// Return `None` if this is an inherent impl. + pub fn impl_trait_ref( + self, + def_id: impl IntoQueryParam, + ) -> Option>> { + Some(self.impl_trait_header(def_id)?.0) + } } /// Parameter attributes that can only be determined by examining the body of a function instead diff --git a/tests/incremental/hashes/trait_impls.rs b/tests/incremental/hashes/trait_impls.rs index 2e97a35d36b..e103be0a085 100644 --- a/tests/incremental/hashes/trait_impls.rs +++ b/tests/incremental/hashes/trait_impls.rs @@ -462,9 +462,9 @@ impl AddTypeParameterToImpl for Bar { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="opt_hir_owner_nodes,generics_of,impl_trait_ref", cfg="cfail2")] +#[rustc_clean(except="opt_hir_owner_nodes,generics_of,impl_trait_header", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="opt_hir_owner_nodes,generics_of,impl_trait_ref", cfg="cfail5")] +#[rustc_clean(except="opt_hir_owner_nodes,generics_of,impl_trait_header", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] impl AddTypeParameterToImpl for Bar { #[rustc_clean( @@ -493,9 +493,9 @@ impl ChangeSelfTypeOfImpl for u32 { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(except="opt_hir_owner_nodes,impl_trait_ref", cfg="cfail2")] +#[rustc_clean(except="opt_hir_owner_nodes,impl_trait_header", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(except="opt_hir_owner_nodes,impl_trait_ref", cfg="cfail5")] +#[rustc_clean(except="opt_hir_owner_nodes,impl_trait_header", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] impl ChangeSelfTypeOfImpl for u64 { #[rustc_clean(except="fn_sig,typeck,optimized_mir", cfg="cfail2")] From 90a43f14063c601fa6a3791aac092bfc2e094911 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Sat, 10 Feb 2024 21:46:44 +0000 Subject: [PATCH 42/56] Use a struct instead of a tuple --- compiler/rustc_hir_analysis/src/collect.rs | 9 ++++++--- compiler/rustc_metadata/src/rmeta/encoder.rs | 2 +- compiler/rustc_metadata/src/rmeta/mod.rs | 2 +- compiler/rustc_middle/src/query/erase.rs | 5 ++--- compiler/rustc_middle/src/query/mod.rs | 2 +- compiler/rustc_middle/src/ty/context.rs | 2 +- compiler/rustc_middle/src/ty/mod.rs | 6 ++++++ compiler/rustc_middle/src/ty/parameterized.rs | 1 + 8 files changed, 19 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 0f0facdca65..67d5064ff02 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -1326,7 +1326,7 @@ fn suggest_impl_trait<'tcx>( fn impl_trait_header( tcx: TyCtxt<'_>, def_id: LocalDefId, -) -> Option<(ty::EarlyBinder>, ty::ImplPolarity)> { +) -> Option>> { let icx = ItemCtxt::new(tcx, def_id); let item = tcx.hir().expect_item(def_id); let impl_ = item.expect_impl(); @@ -1336,7 +1336,7 @@ fn impl_trait_header( .map(|ast_trait_ref| { let selfty = tcx.type_of(def_id).instantiate_identity(); - let impl_trait_ref = if let Some(ErrorGuaranteed { .. }) = check_impl_constness( + let trait_ref = if let Some(ErrorGuaranteed { .. }) = check_impl_constness( tcx, tcx.is_const_trait_impl_raw(def_id.to_def_id()), ast_trait_ref, @@ -1362,7 +1362,10 @@ fn impl_trait_header( } else { icx.astconv().instantiate_mono_trait_ref(ast_trait_ref, selfty) }; - (ty::EarlyBinder::bind(impl_trait_ref), polarity_of_impl(tcx, def_id, impl_, item.span)) + ty::EarlyBinder::bind(ty::ImplTraitHeader { + trait_ref, + polarity: polarity_of_impl(tcx, def_id, impl_, item.span) + }) }) } diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 361c0a3f87e..5630566676b 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1973,7 +1973,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { if of_trait && let Some(header) = tcx.impl_trait_header(def_id) { record!(self.tables.impl_trait_header[def_id] <- header); - let (trait_ref, _polarity) = header; + let trait_ref = header.map_bound(|h| h.trait_ref); let trait_ref = trait_ref.instantiate_identity(); let simplified_self_ty = fast_reject::simplify_type( diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index f2d4ae11105..88a749da156 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -423,7 +423,7 @@ define_tables! { variances_of: Table>, fn_sig: Table>>>, codegen_fn_attrs: Table>, - impl_trait_header: Table>, ty::ImplPolarity)>>, + impl_trait_header: Table>>>, const_param_default: Table>>>, object_lifetime_default: Table>, optimized_mir: Table>>, diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs index e15a051b33f..6bd73e9b203 100644 --- a/compiler/rustc_middle/src/query/erase.rs +++ b/compiler/rustc_middle/src/query/erase.rs @@ -177,9 +177,8 @@ impl EraseType for Option> { type Result = [u8; size_of::>>()]; } -impl EraseType for Option<(ty::EarlyBinder>, ty::ImplPolarity)> { - type Result = - [u8; size_of::>, ty::ImplPolarity)>>()]; +impl EraseType for Option>> { + type Result = [u8; size_of::>>>()]; } impl EraseType for Option>> { diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 59fb198a3da..2f947f96c26 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -848,7 +848,7 @@ rustc_queries! { /// Given an `impl_id`, return the trait it implements along with some header information. /// Return `None` if this is an inherent impl. - query impl_trait_header(impl_id: DefId) -> Option<(ty::EarlyBinder>, ty::ImplPolarity)> { + query impl_trait_header(impl_id: DefId) -> Option>> { desc { |tcx| "computing trait implemented by `{}`", tcx.def_path_str(impl_id) } cache_on_disk_if { impl_id.is_local() } separate_provide_extern diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index c3b69cee9ed..7c91da292cb 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -2315,7 +2315,7 @@ impl<'tcx> TyCtxt<'tcx> { self, def_id: impl IntoQueryParam, ) -> Option>> { - Some(self.impl_trait_header(def_id)?.0) + Some(self.impl_trait_header(def_id)?.map_bound(|h| h.trait_ref)) } } diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index c9137f374a2..e41368957c7 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -248,6 +248,12 @@ pub struct ImplHeader<'tcx> { pub predicates: Vec>, } +#[derive(Copy, Clone, Debug, TypeFoldable, TypeVisitable, TyEncodable, TyDecodable, HashStable)] +pub struct ImplTraitHeader<'tcx> { + pub trait_ref: ty::TraitRef<'tcx>, + pub polarity: ImplPolarity, +} + #[derive(Copy, Clone, PartialEq, Eq, Debug, TypeFoldable, TypeVisitable)] pub enum ImplSubject<'tcx> { Trait(TraitRef<'tcx>), diff --git a/compiler/rustc_middle/src/ty/parameterized.rs b/compiler/rustc_middle/src/ty/parameterized.rs index 47f9d9e61ad..045856dd9cd 100644 --- a/compiler/rustc_middle/src/ty/parameterized.rs +++ b/compiler/rustc_middle/src/ty/parameterized.rs @@ -134,4 +134,5 @@ parameterized_over_tcx! { ty::Predicate, ty::Clause, ty::ClauseKind, + ty::ImplTraitHeader } From a9e0e968be44160eae362ff5272ebf91eba7b214 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Sat, 10 Feb 2024 22:04:46 +0000 Subject: [PATCH 43/56] Unwrap an Option that can only be Some, as inherent impls can't overlap --- compiler/rustc_middle/src/ty/mod.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index e41368957c7..574ca0ee7eb 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -1590,12 +1590,12 @@ impl<'tcx> TyCtxt<'tcx> { def_id1: DefId, def_id2: DefId, ) -> Option { - let impl_trait_ref1 = self.impl_trait_ref(def_id1); - let impl_trait_ref2 = self.impl_trait_ref(def_id2); + let impl_trait_ref1 = self.impl_trait_ref(def_id1).unwrap(); + let impl_trait_ref2 = self.impl_trait_ref(def_id2).unwrap(); // If either trait impl references an error, they're allowed to overlap, // as one of them essentially doesn't exist. - if impl_trait_ref1.is_some_and(|tr| tr.instantiate_identity().references_error()) - || impl_trait_ref2.is_some_and(|tr| tr.instantiate_identity().references_error()) + if impl_trait_ref1.instantiate_identity().references_error() + || impl_trait_ref2.instantiate_identity().references_error() { return Some(ImplOverlapKind::Permitted { marker: false }); } @@ -1615,8 +1615,8 @@ impl<'tcx> TyCtxt<'tcx> { }; let is_marker_overlap = { - let is_marker_impl = |trait_ref: Option>>| -> bool { - trait_ref.is_some_and(|tr| self.trait_def(tr.skip_binder().def_id).is_marker) + let is_marker_impl = |trait_ref: EarlyBinder>| -> bool { + self.trait_def(trait_ref.skip_binder().def_id).is_marker }; is_marker_impl(impl_trait_ref1) && is_marker_impl(impl_trait_ref2) }; From ab0e8b314507cdda07a54f8b8de6a7a6a68e6ce4 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Sat, 10 Feb 2024 22:06:58 +0000 Subject: [PATCH 44/56] Eagerly dismiss binder --- compiler/rustc_middle/src/ty/mod.rs | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 574ca0ee7eb..a45cd9aa396 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -1590,13 +1590,11 @@ impl<'tcx> TyCtxt<'tcx> { def_id1: DefId, def_id2: DefId, ) -> Option { - let impl_trait_ref1 = self.impl_trait_ref(def_id1).unwrap(); - let impl_trait_ref2 = self.impl_trait_ref(def_id2).unwrap(); + let impl_trait_ref1 = self.impl_trait_ref(def_id1).unwrap().instantiate_identity(); + let impl_trait_ref2 = self.impl_trait_ref(def_id2).unwrap().instantiate_identity(); // If either trait impl references an error, they're allowed to overlap, // as one of them essentially doesn't exist. - if impl_trait_ref1.instantiate_identity().references_error() - || impl_trait_ref2.instantiate_identity().references_error() - { + if impl_trait_ref1.references_error() || impl_trait_ref2.references_error() { return Some(ImplOverlapKind::Permitted { marker: false }); } @@ -1615,9 +1613,8 @@ impl<'tcx> TyCtxt<'tcx> { }; let is_marker_overlap = { - let is_marker_impl = |trait_ref: EarlyBinder>| -> bool { - self.trait_def(trait_ref.skip_binder().def_id).is_marker - }; + let is_marker_impl = + |trait_ref: TraitRef<'_>| -> bool { self.trait_def(trait_ref.def_id).is_marker }; is_marker_impl(impl_trait_ref1) && is_marker_impl(impl_trait_ref2) }; From b43fbe63e7675a3c8d762127f450a62def4f653e Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Sat, 10 Feb 2024 22:27:03 +0000 Subject: [PATCH 45/56] Stop calling `impl_polarity` when `impl_trait_ref` was also called --- .../rustc_hir_analysis/src/astconv/mod.rs | 19 +++++++-------- .../rustc_hir_analysis/src/check/check.rs | 24 +++++++++++-------- .../rustc_hir_analysis/src/check/wfcheck.rs | 15 ++++++------ .../rustc_hir_typeck/src/method/suggest.rs | 14 +++++++---- compiler/rustc_middle/src/ty/mod.rs | 11 +++++---- compiler/rustc_monomorphize/src/collector.rs | 13 +++++----- .../src/solve/trait_goals.rs | 11 +++++---- .../error_reporting/type_err_ctxt_ext.rs | 15 ++++++------ .../src/traits/select/candidate_assembly.rs | 10 ++++---- .../src/traits/select/mod.rs | 18 +++++++------- .../src/traits/specialize/mod.rs | 16 +++++++++---- compiler/rustc_ty_utils/src/ty.rs | 7 +++--- 12 files changed, 96 insertions(+), 77 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs index 1ae3ebaebbb..657de8ae9ad 100644 --- a/compiler/rustc_hir_analysis/src/astconv/mod.rs +++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs @@ -1671,9 +1671,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { .is_accessible_from(self.item_def_id(), tcx) && tcx.all_impls(*trait_def_id) .any(|impl_def_id| { - let trait_ref = tcx.impl_trait_ref(impl_def_id); - trait_ref.is_some_and(|trait_ref| { - let impl_ = trait_ref.instantiate( + let impl_header = tcx.impl_trait_header(impl_def_id); + impl_header.is_some_and(|header| { + let header = header.instantiate( tcx, infcx.fresh_args_for_item(DUMMY_SP, impl_def_id), ); @@ -1685,11 +1685,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { infcx .can_eq( ty::ParamEnv::empty(), - impl_.self_ty(), + header.trait_ref.self_ty(), value, - ) + ) && header.polarity != ty::ImplPolarity::Negative }) - && tcx.impl_polarity(impl_def_id) != ty::ImplPolarity::Negative }) }) .map(|trait_def_id| tcx.def_path_str(trait_def_id)) @@ -1735,13 +1734,13 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { } else { // Find all the types that have an `impl` for the trait. tcx.all_impls(trait_def_id) - .filter(|impl_def_id| { + .filter_map(|impl_def_id| tcx.impl_trait_header(impl_def_id)) + .filter(|header| { // Consider only accessible traits tcx.visibility(trait_def_id).is_accessible_from(self.item_def_id(), tcx) - && tcx.impl_polarity(impl_def_id) != ty::ImplPolarity::Negative + && header.skip_binder().polarity != ty::ImplPolarity::Negative }) - .filter_map(|impl_def_id| tcx.impl_trait_ref(impl_def_id)) - .map(|impl_| impl_.instantiate_identity().self_ty()) + .map(|header| header.instantiate_identity().trait_ref.self_ty()) // We don't care about blanket impls. .filter(|self_ty| !self_ty.has_non_region_param()) .map(|self_ty| tcx.erase_regions(self_ty).to_string()) diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 7250dc81faf..2bdf8f9326d 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -474,8 +474,12 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) { } DefKind::Fn => {} // entirely within check_item_body DefKind::Impl { of_trait } => { - if of_trait && let Some(impl_trait_ref) = tcx.impl_trait_ref(def_id) { - check_impl_items_against_trait(tcx, def_id, impl_trait_ref.instantiate_identity()); + if of_trait && let Some(impl_trait_header) = tcx.impl_trait_header(def_id) { + check_impl_items_against_trait( + tcx, + def_id, + impl_trait_header.instantiate_identity(), + ); check_on_unimplemented(tcx, def_id); } } @@ -666,19 +670,19 @@ pub(super) fn check_specialization_validity<'tcx>( fn check_impl_items_against_trait<'tcx>( tcx: TyCtxt<'tcx>, impl_id: LocalDefId, - impl_trait_ref: ty::TraitRef<'tcx>, + impl_trait_header: ty::ImplTraitHeader<'tcx>, ) { // If the trait reference itself is erroneous (so the compilation is going // to fail), skip checking the items here -- the `impl_item` table in `tcx` // isn't populated for such impls. - if impl_trait_ref.references_error() { + if impl_trait_header.references_error() { return; } let impl_item_refs = tcx.associated_item_def_ids(impl_id); // Negative impls are not expected to have any items - match tcx.impl_polarity(impl_id) { + match impl_trait_header.polarity { ty::ImplPolarity::Reservation | ty::ImplPolarity::Positive => {} ty::ImplPolarity::Negative => { if let [first_item_ref, ..] = impl_item_refs { @@ -695,7 +699,7 @@ fn check_impl_items_against_trait<'tcx>( } } - let trait_def = tcx.trait_def(impl_trait_ref.def_id); + let trait_def = tcx.trait_def(impl_trait_header.trait_ref.def_id); for &impl_item in impl_item_refs { let ty_impl_item = tcx.associated_item(impl_item); @@ -714,10 +718,10 @@ fn check_impl_items_against_trait<'tcx>( )); } ty::AssocKind::Fn => { - compare_impl_method(tcx, ty_impl_item, ty_trait_item, impl_trait_ref); + compare_impl_method(tcx, ty_impl_item, ty_trait_item, impl_trait_header.trait_ref); } ty::AssocKind::Type => { - compare_impl_ty(tcx, ty_impl_item, ty_trait_item, impl_trait_ref); + compare_impl_ty(tcx, ty_impl_item, ty_trait_item, impl_trait_header.trait_ref); } } @@ -737,7 +741,7 @@ fn check_impl_items_against_trait<'tcx>( let mut must_implement_one_of: Option<&[Ident]> = trait_def.must_implement_one_of.as_deref(); - for &trait_item_id in tcx.associated_item_def_ids(impl_trait_ref.def_id) { + for &trait_item_id in tcx.associated_item_def_ids(impl_trait_header.trait_ref.def_id) { let leaf_def = ancestors.leaf_def(tcx, trait_item_id); let is_implemented = leaf_def @@ -815,7 +819,7 @@ fn check_impl_items_against_trait<'tcx>( if let Some(missing_items) = must_implement_one_of { let attr_span = tcx - .get_attr(impl_trait_ref.def_id, sym::rustc_must_implement_one_of) + .get_attr(impl_trait_header.trait_ref.def_id, sym::rustc_must_implement_one_of) .map(|attr| attr.span); missing_items_must_implement_one_of_err( diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 646a84b043c..6eba853af30 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -245,9 +245,9 @@ fn check_item<'tcx>(tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>) -> Result<() // won't be allowed unless there's an *explicit* implementation of `Send` // for `T` hir::ItemKind::Impl(impl_) => { - let is_auto = tcx - .impl_trait_ref(def_id) - .is_some_and(|trait_ref| tcx.trait_is_auto(trait_ref.skip_binder().def_id)); + let header = tcx.impl_trait_header(def_id); + let is_auto = header + .is_some_and(|header| tcx.trait_is_auto(header.skip_binder().trait_ref.def_id)); let mut res = Ok(()); if let (hir::Defaultness::Default { .. }, true) = (impl_.defaultness, is_auto) { let sp = impl_.of_trait.as_ref().map_or(item.span, |t| t.path.span); @@ -259,11 +259,12 @@ fn check_item<'tcx>(tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>) -> Result<() .emit()); } // We match on both `ty::ImplPolarity` and `ast::ImplPolarity` just to get the `!` span. - match tcx.impl_polarity(def_id) { - ty::ImplPolarity::Positive => { + match header.map(|h| h.skip_binder().polarity) { + // `None` means this is an inherent impl + Some(ty::ImplPolarity::Positive) | None => { res = res.and(check_impl(tcx, item, impl_.self_ty, &impl_.of_trait)); } - ty::ImplPolarity::Negative => { + Some(ty::ImplPolarity::Negative) => { let ast::ImplPolarity::Negative(span) = impl_.polarity else { bug!("impl_polarity query disagrees with impl's polarity in AST"); }; @@ -280,7 +281,7 @@ fn check_item<'tcx>(tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>) -> Result<() .emit()); } } - ty::ImplPolarity::Reservation => { + Some(ty::ImplPolarity::Reservation) => { // FIXME: what amount of WF checking do we need for reservation impls? } } diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 7fc51e36a2b..ab5c0f32705 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -3134,12 +3134,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if self .tcx .all_impls(candidate.def_id) - .filter(|imp_did| { - self.tcx.impl_polarity(*imp_did) == ty::ImplPolarity::Negative + .map(|imp_did| { + self.tcx.impl_trait_header(imp_did).expect( + "inherent impls can't be candidates, only trait impls can be", + ) }) - .any(|imp_did| { - let imp = - self.tcx.impl_trait_ref(imp_did).unwrap().instantiate_identity(); + .filter(|header| { + header.skip_binder().polarity == ty::ImplPolarity::Negative + }) + .any(|header| { + let imp = header.instantiate_identity().trait_ref; let imp_simp = simplify_type(self.tcx, imp.self_ty(), TreatParams::ForLookup); imp_simp.is_some_and(|s| s == simp_rcvr_ty) diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index a45cd9aa396..e64ebae255f 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -1590,15 +1590,16 @@ impl<'tcx> TyCtxt<'tcx> { def_id1: DefId, def_id2: DefId, ) -> Option { - let impl_trait_ref1 = self.impl_trait_ref(def_id1).unwrap().instantiate_identity(); - let impl_trait_ref2 = self.impl_trait_ref(def_id2).unwrap().instantiate_identity(); + let impl1 = self.impl_trait_header(def_id1).unwrap().instantiate_identity(); + let impl2 = self.impl_trait_header(def_id2).unwrap().instantiate_identity(); + // If either trait impl references an error, they're allowed to overlap, // as one of them essentially doesn't exist. - if impl_trait_ref1.references_error() || impl_trait_ref2.references_error() { + if impl1.references_error() || impl2.references_error() { return Some(ImplOverlapKind::Permitted { marker: false }); } - match (self.impl_polarity(def_id1), self.impl_polarity(def_id2)) { + match (impl1.polarity, impl2.polarity) { (ImplPolarity::Reservation, _) | (_, ImplPolarity::Reservation) => { // `#[rustc_reservation_impl]` impls don't overlap with anything return Some(ImplOverlapKind::Permitted { marker: false }); @@ -1615,7 +1616,7 @@ impl<'tcx> TyCtxt<'tcx> { let is_marker_overlap = { let is_marker_impl = |trait_ref: TraitRef<'_>| -> bool { self.trait_def(trait_ref.def_id).is_marker }; - is_marker_impl(impl_trait_ref1) && is_marker_impl(impl_trait_ref2) + is_marker_impl(impl1.trait_ref) && is_marker_impl(impl2.trait_ref) }; if is_marker_overlap { diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 149e4c2cb08..e34194f0bb0 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -1347,8 +1347,11 @@ fn create_mono_items_for_default_impls<'tcx>( item: hir::ItemId, output: &mut MonoItems<'tcx>, ) { - let polarity = tcx.impl_polarity(item.owner_id); - if matches!(polarity, ty::ImplPolarity::Negative) { + let Some(impl_) = tcx.impl_trait_header(item.owner_id) else { + return; + }; + + if matches!(impl_.skip_binder().polarity, ty::ImplPolarity::Negative) { return; } @@ -1356,10 +1359,6 @@ fn create_mono_items_for_default_impls<'tcx>( return; } - let Some(trait_ref) = tcx.impl_trait_ref(item.owner_id) else { - return; - }; - // Lifetimes never affect trait selection, so we are allowed to eagerly // instantiate an instance of an impl method if the impl (and method, // which we check below) is only parameterized over lifetime. In that case, @@ -1376,7 +1375,7 @@ fn create_mono_items_for_default_impls<'tcx>( } }; let impl_args = GenericArgs::for_item(tcx, item.owner_id.to_def_id(), only_region_params); - let trait_ref = trait_ref.instantiate(tcx, impl_args); + let trait_ref = impl_.instantiate(tcx, impl_args).trait_ref; // Unlike 'lazy' monomorphization that begins by collecting items transitively // called by `main` or other global items, when eagerly monomorphizing impl diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs index 044832224e5..42ae82a907f 100644 --- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs @@ -39,15 +39,18 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { ) -> Result, NoSolution> { let tcx = ecx.tcx(); - let impl_trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap(); + let impl_trait_header = tcx.impl_trait_header(impl_def_id).unwrap(); let drcx = DeepRejectCtxt { treat_obligation_params: TreatParams::ForLookup }; - if !drcx.args_may_unify(goal.predicate.trait_ref.args, impl_trait_ref.skip_binder().args) { + if !drcx.args_may_unify( + goal.predicate.trait_ref.args, + impl_trait_header.skip_binder().trait_ref.args, + ) { return Err(NoSolution); } - let impl_polarity = tcx.impl_polarity(impl_def_id); // An upper bound of the certainty of this goal, used to lower the certainty // of reservation impl to ambiguous during coherence. + let impl_polarity = impl_trait_header.skip_binder().polarity; let maximal_certainty = match impl_polarity { ty::ImplPolarity::Positive | ty::ImplPolarity::Negative => { match impl_polarity == goal.predicate.polarity { @@ -63,7 +66,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { ecx.probe_trait_candidate(CandidateSource::Impl(impl_def_id)).enter(|ecx| { let impl_args = ecx.fresh_args_for_item(impl_def_id); - let impl_trait_ref = impl_trait_ref.instantiate(tcx, impl_args); + let impl_trait_ref = impl_trait_header.instantiate(tcx, impl_args).trait_ref; ecx.eq(goal.param_env, goal.predicate.trait_ref, impl_trait_ref)?; let where_clause_bounds = tcx diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs index 7d14395850b..8fa5cd5c522 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs @@ -1980,13 +1980,13 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { .tcx .all_impls(trait_pred.def_id()) .filter_map(|def_id| { - if self.tcx.impl_polarity(def_id) == ty::ImplPolarity::Negative + let imp = self.tcx.impl_trait_header(def_id).unwrap().skip_binder(); + if imp.polarity == ty::ImplPolarity::Negative || !self.tcx.is_user_visible_dep(def_id.krate) { return None; } - - let imp = self.tcx.impl_trait_ref(def_id).unwrap().skip_binder(); + let imp = imp.trait_ref; self.fuzzy_match_tys(trait_pred.skip_binder().self_ty(), imp.self_ty(), false).map( |similarity| ImplCandidate { trait_ref: imp, similarity, impl_def_id: def_id }, @@ -2165,12 +2165,13 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { .tcx .all_impls(def_id) // Ignore automatically derived impls and `!Trait` impls. - .filter(|&def_id| { - self.tcx.impl_polarity(def_id) != ty::ImplPolarity::Negative + .filter_map(|def_id| self.tcx.impl_trait_header(def_id)) + .map(ty::EarlyBinder::instantiate_identity) + .filter(|header| { + header.polarity != ty::ImplPolarity::Negative || self.tcx.is_automatically_derived(def_id) }) - .filter_map(|def_id| self.tcx.impl_trait_ref(def_id)) - .map(ty::EarlyBinder::instantiate_identity) + .map(|header| header.trait_ref) .filter(|trait_ref| { let self_ty = trait_ref.self_ty(); // Avoid mentioning type parameters. diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index f9a292c2bd7..b6f672bfabe 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -560,20 +560,22 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // Before we create the substitutions and everything, first // consider a "quick reject". This avoids creating more types // and so forth that we need to. - let impl_trait_ref = self.tcx().impl_trait_ref(impl_def_id).unwrap(); - if !drcx.args_may_unify(obligation_args, impl_trait_ref.skip_binder().args) { + let impl_trait_header = self.tcx().impl_trait_header(impl_def_id).unwrap(); + if !drcx + .args_may_unify(obligation_args, impl_trait_header.skip_binder().trait_ref.args) + { return; } if self.reject_fn_ptr_impls( impl_def_id, obligation, - impl_trait_ref.skip_binder().self_ty(), + impl_trait_header.skip_binder().trait_ref.self_ty(), ) { return; } self.infcx.probe(|_| { - if let Ok(_args) = self.match_impl(impl_def_id, impl_trait_ref, obligation) { + if let Ok(_args) = self.match_impl(impl_def_id, impl_trait_header, obligation) { candidates.vec.push(ImplCandidate(impl_def_id)); } }); diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index ac6cfcdeb59..5f11bb600e3 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -2404,8 +2404,8 @@ impl<'tcx> SelectionContext<'_, 'tcx> { impl_def_id: DefId, obligation: &PolyTraitObligation<'tcx>, ) -> Normalized<'tcx, GenericArgsRef<'tcx>> { - let impl_trait_ref = self.tcx().impl_trait_ref(impl_def_id).unwrap(); - match self.match_impl(impl_def_id, impl_trait_ref, obligation) { + let impl_trait_header = self.tcx().impl_trait_header(impl_def_id).unwrap(); + match self.match_impl(impl_def_id, impl_trait_header, obligation) { Ok(args) => args, Err(()) => { // FIXME: A rematch may fail when a candidate cache hit occurs @@ -2438,7 +2438,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> { fn match_impl( &mut self, impl_def_id: DefId, - impl_trait_ref: EarlyBinder>, + impl_trait_header: EarlyBinder>, obligation: &PolyTraitObligation<'tcx>, ) -> Result>, ()> { let placeholder_obligation = @@ -2447,12 +2447,12 @@ impl<'tcx> SelectionContext<'_, 'tcx> { let impl_args = self.infcx.fresh_args_for_item(obligation.cause.span, impl_def_id); - let impl_trait_ref = impl_trait_ref.instantiate(self.tcx(), impl_args); - if impl_trait_ref.references_error() { + let impl_trait_header = impl_trait_header.instantiate(self.tcx(), impl_args); + if impl_trait_header.references_error() { return Err(()); } - debug!(?impl_trait_ref); + debug!(?impl_trait_header); let Normalized { value: impl_trait_ref, obligations: mut nested_obligations } = ensure_sufficient_stack(|| { @@ -2461,7 +2461,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> { obligation.param_env, obligation.cause.clone(), obligation.recursion_depth + 1, - impl_trait_ref, + impl_trait_header.trait_ref, ) }); @@ -2482,9 +2482,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> { })?; nested_obligations.extend(obligations); - if !self.is_intercrate() - && self.tcx().impl_polarity(impl_def_id) == ty::ImplPolarity::Reservation - { + if !self.is_intercrate() && impl_trait_header.polarity == ty::ImplPolarity::Reservation { debug!("reservation impls only apply in intercrate mode"); return Err(()); } diff --git a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs index 8e0fa79c977..6de839f5d98 100644 --- a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs @@ -168,6 +168,8 @@ pub(super) fn specializes(tcx: TyCtxt<'_>, (impl1_def_id, impl2_def_id): (DefId, } } + let impl1_trait_header = tcx.impl_trait_header(impl1_def_id).unwrap().instantiate_identity(); + // We determine whether there's a subset relationship by: // // - replacing bound vars with placeholders in impl1, @@ -181,21 +183,25 @@ pub(super) fn specializes(tcx: TyCtxt<'_>, (impl1_def_id, impl2_def_id): (DefId, // See RFC 1210 for more details and justification. // Currently we do not allow e.g., a negative impl to specialize a positive one - if tcx.impl_polarity(impl1_def_id) != tcx.impl_polarity(impl2_def_id) { + if impl1_trait_header.polarity != tcx.impl_polarity(impl2_def_id) { return false; } // create a parameter environment corresponding to a (placeholder) instantiation of impl1 let penv = tcx.param_env(impl1_def_id); - let impl1_trait_ref = tcx.impl_trait_ref(impl1_def_id).unwrap().instantiate_identity(); // Create an infcx, taking the predicates of impl1 as assumptions: let infcx = tcx.infer_ctxt().build(); // Attempt to prove that impl2 applies, given all of the above. - fulfill_implication(&infcx, penv, impl1_trait_ref, impl1_def_id, impl2_def_id, |_, _| { - ObligationCause::dummy() - }) + fulfill_implication( + &infcx, + penv, + impl1_trait_header.trait_ref, + impl1_def_id, + impl2_def_id, + |_, _| ObligationCause::dummy(), + ) .is_ok() } diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs index 60b1bbe8c2a..b725eda33ce 100644 --- a/compiler/rustc_ty_utils/src/ty.rs +++ b/compiler/rustc_ty_utils/src/ty.rs @@ -257,14 +257,15 @@ fn param_env_reveal_all_normalized(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamE fn issue33140_self_ty(tcx: TyCtxt<'_>, def_id: DefId) -> Option>> { debug!("issue33140_self_ty({:?})", def_id); - let trait_ref = tcx - .impl_trait_ref(def_id) + let impl_ = tcx + .impl_trait_header(def_id) .unwrap_or_else(|| bug!("issue33140_self_ty called on inherent impl {:?}", def_id)) .skip_binder(); + let trait_ref = impl_.trait_ref; debug!("issue33140_self_ty({:?}), trait-ref={:?}", def_id, trait_ref); - let is_marker_like = tcx.impl_polarity(def_id) == ty::ImplPolarity::Positive + let is_marker_like = impl_.polarity == ty::ImplPolarity::Positive && tcx.associated_item_def_ids(trait_ref.def_id).is_empty(); // Check whether these impls would be ok for a marker trait. From 74c9dffac3d7a4e87bd87815f8a28f1f71e52d08 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Sun, 11 Feb 2024 07:11:48 +0000 Subject: [PATCH 46/56] Remove impl_polarity query --- compiler/rustc_hir_analysis/src/collect.rs | 6 ------ compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs | 1 - compiler/rustc_metadata/src/rmeta/encoder.rs | 1 - compiler/rustc_metadata/src/rmeta/mod.rs | 1 - compiler/rustc_middle/src/query/mod.rs | 4 ---- compiler/rustc_middle/src/ty/context.rs | 5 +++++ 6 files changed, 5 insertions(+), 13 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 67d5064ff02..58fc4ceaa4a 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -79,7 +79,6 @@ pub fn provide(providers: &mut Providers) { adt_def, fn_sig, impl_trait_header, - impl_polarity, coroutine_kind, coroutine_for_closure, collect_mod_item_types, @@ -1394,11 +1393,6 @@ fn check_impl_constness( })) } -fn impl_polarity(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::ImplPolarity { - let item = tcx.hir().expect_item(def_id); - polarity_of_impl(tcx, def_id, item.expect_impl(), item.span) -} - fn polarity_of_impl( tcx: TyCtxt<'_>, def_id: LocalDefId, diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index 058f28a3ee9..d79d4b226a5 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -234,7 +234,6 @@ provide! { tcx, def_id, other, cdata, unused_generic_params => { cdata.root.tables.unused_generic_params.get(cdata, def_id.index) } def_kind => { cdata.def_kind(def_id.index) } impl_parent => { table } - impl_polarity => { table_direct } defaultness => { table_direct } constness => { table_direct } coerce_unsized_info => { diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 5630566676b..4a24c038f7a 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1969,7 +1969,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let def_id = id.owner_id.to_def_id(); self.tables.defaultness.set_some(def_id.index, tcx.defaultness(def_id)); - self.tables.impl_polarity.set_some(def_id.index, tcx.impl_polarity(def_id)); if of_trait && let Some(header) = tcx.impl_trait_header(def_id) { record!(self.tables.impl_trait_header[def_id] <- header); diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index 88a749da156..4d0a6cb60ee 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -433,7 +433,6 @@ define_tables! { promoted_mir: Table>>>, thir_abstract_const: Table>>>, impl_parent: Table, - impl_polarity: Table, constness: Table, defaultness: Table, // FIXME(eddyb) perhaps compute this on the fly if cheap enough? diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 2f947f96c26..63db3250c94 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -853,10 +853,6 @@ rustc_queries! { cache_on_disk_if { impl_id.is_local() } separate_provide_extern } - query impl_polarity(impl_id: DefId) -> ty::ImplPolarity { - desc { |tcx| "computing implementation polarity of `{}`", tcx.def_path_str(impl_id) } - separate_provide_extern - } query issue33140_self_ty(key: DefId) -> Option>> { desc { |tcx| "computing Self type wrt issue #33140 `{}`", tcx.def_path_str(key) } diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 7c91da292cb..52db913f36e 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -2317,6 +2317,11 @@ impl<'tcx> TyCtxt<'tcx> { ) -> Option>> { Some(self.impl_trait_header(def_id)?.map_bound(|h| h.trait_ref)) } + + pub fn impl_polarity(self, def_id: impl IntoQueryParam) -> ty::ImplPolarity { + self.impl_trait_header(def_id) + .map_or(ty::ImplPolarity::Positive, |h| h.skip_binder().polarity) + } } /// Parameter attributes that can only be determined by examining the body of a function instead From 83a850f2a1259eb05ef444c81bcb5869d6dbf336 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Mon, 12 Feb 2024 09:06:45 -0300 Subject: [PATCH 47/56] Add lahfsahf and prfchw target feature --- compiler/rustc_codegen_llvm/src/llvm_util.rs | 1 + compiler/rustc_codegen_ssa/src/target_features.rs | 2 ++ compiler/rustc_feature/src/unstable.rs | 2 ++ compiler/rustc_span/src/symbol.rs | 2 ++ compiler/rustc_target/src/target_features.rs | 2 ++ tests/ui/check-cfg/well-known-values.stderr | 2 +- tests/ui/target-feature/gate.rs | 2 ++ tests/ui/target-feature/gate.stderr | 2 +- 8 files changed, 13 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index 4bb400b1879..e48479c8da2 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -213,6 +213,7 @@ pub fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> LLVMFeature<'a> { ("x86", "rdrand") => LLVMFeature::new("rdrnd"), ("x86", "bmi1") => LLVMFeature::new("bmi"), ("x86", "cmpxchg16b") => LLVMFeature::new("cx16"), + ("x86", "lahfsahf") => LLVMFeature::new("sahf"), ("aarch64", "rcpc2") => LLVMFeature::new("rcpc-immo"), ("aarch64", "dpb") => LLVMFeature::new("ccpp"), ("aarch64", "dpb2") => LLVMFeature::new("ccdp"), diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs index 3694e41a0e0..ee1d548b231 100644 --- a/compiler/rustc_codegen_ssa/src/target_features.rs +++ b/compiler/rustc_codegen_ssa/src/target_features.rs @@ -77,6 +77,8 @@ pub fn from_target_feature( Some(sym::aarch64_ver_target_feature) => rust_features.aarch64_ver_target_feature, Some(sym::csky_target_feature) => rust_features.csky_target_feature, Some(sym::loongarch_target_feature) => rust_features.loongarch_target_feature, + Some(sym::lahfsahf_target_feature) => rust_features.lahfsahf_target_feature, + Some(sym::prfchw_target_feature) => rust_features.prfchw_target_feature, Some(name) => bug!("unknown target feature gate {}", name), None => true, }; diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index efb0b1fbabb..9012b731a13 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -301,9 +301,11 @@ declare_features! ( (unstable, csky_target_feature, "1.73.0", Some(44839)), (unstable, ermsb_target_feature, "1.49.0", Some(44839)), (unstable, hexagon_target_feature, "1.27.0", Some(44839)), + (unstable, lahfsahf_target_feature, "CURRENT_RUSTC_VERSION", Some(44839)), (unstable, loongarch_target_feature, "1.73.0", Some(44839)), (unstable, mips_target_feature, "1.27.0", Some(44839)), (unstable, powerpc_target_feature, "1.27.0", Some(44839)), + (unstable, prfchw_target_feature, "CURRENT_RUSTC_VERSION", Some(44839)), (unstable, riscv_target_feature, "1.45.0", Some(44839)), (unstable, rtm_target_feature, "1.35.0", Some(44839)), (unstable, sse4a_target_feature, "1.27.0", Some(44839)), diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index aa912c93c08..9cc4613bfb4 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -932,6 +932,7 @@ symbols! { kreg0, label, label_break_value, + lahfsahf_target_feature, lang, lang_items, large_assignments, @@ -1240,6 +1241,7 @@ symbols! { prelude, prelude_import, preserves_flags, + prfchw_target_feature, print_macro, println_macro, proc_dash_macro: "proc-macro", diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs index c350a37975d..04943fa3879 100644 --- a/compiler/rustc_target/src/target_features.rs +++ b/compiler/rustc_target/src/target_features.rs @@ -218,10 +218,12 @@ const X86_ALLOWED_FEATURES: &[(&str, Stability)] = &[ ("fma", Stable), ("fxsr", Stable), ("gfni", Unstable(sym::avx512_target_feature)), + ("lahfsahf", Unstable(sym::lahfsahf_target_feature)), ("lzcnt", Stable), ("movbe", Stable), ("pclmulqdq", Stable), ("popcnt", Stable), + ("prfchw", Unstable(sym::prfchw_target_feature)), ("rdrand", Stable), ("rdseed", Stable), ("rtm", Unstable(sym::rtm_target_feature)), diff --git a/tests/ui/check-cfg/well-known-values.stderr b/tests/ui/check-cfg/well-known-values.stderr index 652e573d6ef..7eeaa31cbb6 100644 --- a/tests/ui/check-cfg/well-known-values.stderr +++ b/tests/ui/check-cfg/well-known-values.stderr @@ -143,7 +143,7 @@ warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` LL | target_feature = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: expected values for `target_feature` are: `10e60`, `2e3`, `3e3r1`, `3e3r2`, `3e3r3`, `3e7`, `7e10`, `a`, `aclass`, `adx`, `aes`, `altivec`, `alu32`, `atomics`, `avx`, `avx2`, `avx512bf16`, `avx512bitalg`, `avx512bw`, `avx512cd`, `avx512dq`, `avx512er`, `avx512f`, `avx512fp16`, `avx512ifma`, `avx512pf`, `avx512vbmi`, `avx512vbmi2`, `avx512vl`, `avx512vnni`, `avx512vp2intersect`, `avx512vpopcntdq`, `bf16`, `bmi1`, `bmi2`, `bti`, `bulk-memory`, `c`, `cache`, `cmpxchg16b`, `crc`, `crt-static`, `d`, `d32`, `dit`, `doloop`, `dotprod`, `dpb`, `dpb2`, `dsp`, `dsp1e2`, `dspe60`, `e`, `e1`, `e2`, `edsp`, `elrw`, `ermsb`, `exception-handling`, `f`, `f16c`, `f32mm`, `f64mm`, `fast-unaligned-access`, `fcma`, `fdivdu`, `fhm`, `flagm`, `float1e2`, `float1e3`, `float3e4`, `float7e60`, `floate1`, `fma`, `fp-armv8`, `fp16`, `fp64`, `fpuv2_df`, `fpuv2_sf`, `fpuv3_df`, `fpuv3_hf`, `fpuv3_hi`, `fpuv3_sf`, `frintts`, `fxsr`, `gfni`, `hard-float`, `hard-float-abi`, `hard-tp`, `high-registers`, `hvx`, `hvx-length128b`, `hwdiv`, `i8mm`, `jsconv`, `lasx`, `lbt`, `lor`, `lse`, `lsx`, `lvz`, `lzcnt`, `m`, `mclass`, `movbe`, `mp`, `mp1e2`, `msa`, `mte`, `multivalue`, `mutable-globals`, `neon`, `nontrapping-fptoint`, `nvic`, `paca`, `pacg`, `pan`, `pclmulqdq`, `pmuv3`, `popcnt`, `power10-vector`, `power8-altivec`, `power8-vector`, `power9-altivec`, `power9-vector`, `rand`, `ras`, `rclass`, `rcpc`, `rcpc2`, `rdm`, `rdrand`, `rdseed`, `reference-types`, `relax`, `relaxed-simd`, `rtm`, `sb`, `sha`, `sha2`, `sha3`, `sign-ext`, `simd128`, `sm4`, `spe`, `ssbs`, `sse`, `sse2`, `sse3`, `sse4.1`, `sse4.2`, `sse4a`, `ssse3`, `sve`, `sve2`, `sve2-aes`, `sve2-bitperm`, `sve2-sha3`, `sve2-sm4`, `tbm`, `thumb-mode`, `thumb2`, `tme`, `trust`, `trustzone`, `ual`, `v`, `v5te`, `v6`, `v6k`, `v6t2`, `v7`, `v8`, `v8.1a`, `v8.2a`, `v8.3a`, `v8.4a`, `v8.5a`, `v8.6a`, `v8.7a`, `vaes`, `vdsp2e60f`, `vdspv1`, `vdspv2`, `vfp2`, `vfp3`, `vfp4`, `vh`, `virt`, `virtualization`, `vpclmulqdq`, `vsx`, `xsave`, `xsavec`, `xsaveopt`, `xsaves`, `zba`, `zbb`, `zbc`, `zbkb`, `zbkc`, `zbkx`, `zbs`, `zdinx`, `zfh`, `zfhmin`, `zfinx`, `zhinx`, `zhinxmin`, `zk`, `zkn`, `zknd`, `zkne`, `zknh`, `zkr`, `zks`, `zksed`, `zksh`, `zkt` + = note: expected values for `target_feature` are: `10e60`, `2e3`, `3e3r1`, `3e3r2`, `3e3r3`, `3e7`, `7e10`, `a`, `aclass`, `adx`, `aes`, `altivec`, `alu32`, `atomics`, `avx`, `avx2`, `avx512bf16`, `avx512bitalg`, `avx512bw`, `avx512cd`, `avx512dq`, `avx512er`, `avx512f`, `avx512fp16`, `avx512ifma`, `avx512pf`, `avx512vbmi`, `avx512vbmi2`, `avx512vl`, `avx512vnni`, `avx512vp2intersect`, `avx512vpopcntdq`, `bf16`, `bmi1`, `bmi2`, `bti`, `bulk-memory`, `c`, `cache`, `cmpxchg16b`, `crc`, `crt-static`, `d`, `d32`, `dit`, `doloop`, `dotprod`, `dpb`, `dpb2`, `dsp`, `dsp1e2`, `dspe60`, `e`, `e1`, `e2`, `edsp`, `elrw`, `ermsb`, `exception-handling`, `f`, `f16c`, `f32mm`, `f64mm`, `fast-unaligned-access`, `fcma`, `fdivdu`, `fhm`, `flagm`, `float1e2`, `float1e3`, `float3e4`, `float7e60`, `floate1`, `fma`, `fp-armv8`, `fp16`, `fp64`, `fpuv2_df`, `fpuv2_sf`, `fpuv3_df`, `fpuv3_hf`, `fpuv3_hi`, `fpuv3_sf`, `frintts`, `fxsr`, `gfni`, `hard-float`, `hard-float-abi`, `hard-tp`, `high-registers`, `hvx`, `hvx-length128b`, `hwdiv`, `i8mm`, `jsconv`, `lahfsahf`, `lasx`, `lbt`, `lor`, `lse`, `lsx`, `lvz`, `lzcnt`, `m`, `mclass`, `movbe`, `mp`, `mp1e2`, `msa`, `mte`, `multivalue`, `mutable-globals`, `neon`, `nontrapping-fptoint`, `nvic`, `paca`, `pacg`, `pan`, `pclmulqdq`, `pmuv3`, `popcnt`, `power10-vector`, `power8-altivec`, `power8-vector`, `power9-altivec`, `power9-vector`, `prfchw`, `rand`, `ras`, `rclass`, `rcpc`, `rcpc2`, `rdm`, `rdrand`, `rdseed`, `reference-types`, `relax`, `relaxed-simd`, `rtm`, `sb`, `sha`, `sha2`, `sha3`, `sign-ext`, `simd128`, `sm4`, `spe`, `ssbs`, `sse`, `sse2`, `sse3`, `sse4.1`, `sse4.2`, `sse4a`, `ssse3`, `sve`, `sve2`, `sve2-aes`, `sve2-bitperm`, `sve2-sha3`, `sve2-sm4`, `tbm`, `thumb-mode`, `thumb2`, `tme`, `trust`, `trustzone`, `ual`, `v`, `v5te`, `v6`, `v6k`, `v6t2`, `v7`, `v8`, `v8.1a`, `v8.2a`, `v8.3a`, `v8.4a`, `v8.5a`, `v8.6a`, `v8.7a`, `vaes`, `vdsp2e60f`, `vdspv1`, `vdspv2`, `vfp2`, `vfp3`, `vfp4`, `vh`, `virt`, `virtualization`, `vpclmulqdq`, `vsx`, `xsave`, `xsavec`, `xsaveopt`, `xsaves`, `zba`, `zbb`, `zbc`, `zbkb`, `zbkc`, `zbkx`, `zbs`, `zdinx`, `zfh`, `zfhmin`, `zfinx`, `zhinx`, `zhinxmin`, `zk`, `zkn`, `zknd`, `zkne`, `zknh`, `zkr`, `zks`, `zksed`, `zksh`, `zkt` = note: see for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` diff --git a/tests/ui/target-feature/gate.rs b/tests/ui/target-feature/gate.rs index 971a4654b4c..d6a191d7850 100644 --- a/tests/ui/target-feature/gate.rs +++ b/tests/ui/target-feature/gate.rs @@ -19,6 +19,8 @@ // gate-test-aarch64_ver_target_feature // gate-test-csky_target_feature // gate-test-loongarch_target_feature +// gate-test-lahfsahf_target_feature +// gate-test-prfchw_target_feature #[target_feature(enable = "avx512bw")] //~^ ERROR: currently unstable diff --git a/tests/ui/target-feature/gate.stderr b/tests/ui/target-feature/gate.stderr index d281f0a6ab9..31198f73c20 100644 --- a/tests/ui/target-feature/gate.stderr +++ b/tests/ui/target-feature/gate.stderr @@ -1,5 +1,5 @@ error[E0658]: the target feature `avx512bw` is currently unstable - --> $DIR/gate.rs:23:18 + --> $DIR/gate.rs:25:18 | LL | #[target_feature(enable = "avx512bw")] | ^^^^^^^^^^^^^^^^^^^ From 95c5b060004928984b6b76a9ef67a3ca7147568c Mon Sep 17 00:00:00 2001 From: Lukas Markeffsky <@> Date: Sun, 11 Feb 2024 23:26:06 +0100 Subject: [PATCH 48/56] fix ICE for deref coercions with type errors --- compiler/rustc_hir_analysis/src/autoderef.rs | 8 ++++---- .../rustc_hir_analysis/src/check/wfcheck.rs | 10 +++++++--- tests/ui/coercion/type-errors.rs | 19 +++++++++++++++---- tests/ui/coercion/type-errors.stderr | 14 +++++++++++++- 4 files changed, 39 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/autoderef.rs b/compiler/rustc_hir_analysis/src/autoderef.rs index 5bc904e5930..f2ceb470264 100644 --- a/compiler/rustc_hir_analysis/src/autoderef.rs +++ b/compiler/rustc_hir_analysis/src/autoderef.rs @@ -91,10 +91,6 @@ impl<'a, 'tcx> Iterator for Autoderef<'a, 'tcx> { return None; }; - if new_ty.references_error() { - return None; - } - self.state.steps.push((self.state.cur_ty, kind)); debug!( "autoderef stage #{:?} is {:?} from {:?}", @@ -137,6 +133,10 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> { debug!("overloaded_deref_ty({:?})", ty); let tcx = self.infcx.tcx; + if ty.references_error() { + return None; + } + // let trait_ref = ty::TraitRef::new(tcx, tcx.lang_items().deref_trait()?, [ty]); let cause = traits::ObligationCause::misc(self.span, self.body_id); diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 646a84b043c..bf22c70ebfd 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -1635,6 +1635,12 @@ fn check_method_receiver<'tcx>( let receiver_ty = sig.inputs()[0]; let receiver_ty = wfcx.normalize(span, None, receiver_ty); + // If the receiver already has errors reported, consider it valid to avoid + // unnecessary errors (#58712). + if receiver_ty.references_error() { + return Ok(()); + } + if tcx.features().arbitrary_self_types { if !receiver_is_valid(wfcx, span, receiver_ty, self_ty, true) { // Report error; `arbitrary_self_types` was enabled. @@ -1749,9 +1755,7 @@ fn receiver_is_valid<'tcx>( } } else { debug!("receiver_is_valid: type `{:?}` does not deref to `{:?}`", receiver_ty, self_ty); - // If the receiver already has errors reported due to it, consider it valid to avoid - // unnecessary errors (#58712). - return receiver_ty.references_error(); + return false; } } diff --git a/tests/ui/coercion/type-errors.rs b/tests/ui/coercion/type-errors.rs index a2f0e55f1b9..a86789907a0 100644 --- a/tests/ui/coercion/type-errors.rs +++ b/tests/ui/coercion/type-errors.rs @@ -1,15 +1,26 @@ -// Regression test for an ICE: https://github.com/rust-lang/rust/issues/120884 +// Test that we don't ICE for coercions with type errors. // We still need to properly go through coercions between types with errors instead of // shortcutting and returning success, because we need the adjustments for building the MIR. pub fn has_error() -> TypeError {} //~^ ERROR cannot find type `TypeError` in this scope +// https://github.com/rust-lang/rust/issues/120884 +// Casting a function item to a data pointer in valid in HIR, but invalid in MIR. +// We need an adjustment (ReifyFnPointer) to insert a cast from the function item +// to a function pointer as a separate MIR statement. pub fn cast() -> *const u8 { - // Casting a function item to a data pointer in valid in HIR, but invalid in MIR. - // We need an adjustment (ReifyFnPointer) to insert a cast from the function item - // to a function pointer as a separate MIR statement. has_error as *const u8 } +// https://github.com/rust-lang/rust/issues/120945 +// This one ICEd, because we skipped the builtin deref from `&TypeError` to `TypeError`. +pub fn autoderef_source(e: &TypeError) { + //~^ ERROR cannot find type `TypeError` in this scope + autoderef_target(e) +} + +pub fn autoderef_target(_: &TypeError) {} +//~^ ERROR cannot find type `TypeError` in this scope + fn main() {} diff --git a/tests/ui/coercion/type-errors.stderr b/tests/ui/coercion/type-errors.stderr index 489cd9ddf13..14deb785f75 100644 --- a/tests/ui/coercion/type-errors.stderr +++ b/tests/ui/coercion/type-errors.stderr @@ -4,6 +4,18 @@ error[E0412]: cannot find type `TypeError` in this scope LL | pub fn has_error() -> TypeError {} | ^^^^^^^^^ not found in this scope -error: aborting due to 1 previous error +error[E0412]: cannot find type `TypeError` in this scope + --> $DIR/type-errors.rs:18:29 + | +LL | pub fn autoderef_source(e: &TypeError) { + | ^^^^^^^^^ not found in this scope + +error[E0412]: cannot find type `TypeError` in this scope + --> $DIR/type-errors.rs:23:29 + | +LL | pub fn autoderef_target(_: &TypeError) {} + | ^^^^^^^^^ not found in this scope + +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0412`. From a313ffb8844d51f6048be35b1b0ea39e7dfc48c7 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 12 Feb 2024 14:52:20 +0100 Subject: [PATCH 49/56] add another test for promoteds-in-static --- .../static-promoted-to-mutable-static.rs | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 tests/ui/consts/static-promoted-to-mutable-static.rs diff --git a/tests/ui/consts/static-promoted-to-mutable-static.rs b/tests/ui/consts/static-promoted-to-mutable-static.rs new file mode 100644 index 00000000000..d49ba478dbc --- /dev/null +++ b/tests/ui/consts/static-promoted-to-mutable-static.rs @@ -0,0 +1,33 @@ +// check-pass +#![allow(non_camel_case_types, non_upper_case_globals, static_mut_ref)] + +pub struct wl_interface { + pub version: i32 +} + +pub struct Interface { + pub other_interfaces: &'static [&'static Interface], + pub c_ptr: Option<&'static wl_interface>, +} + +pub static mut wl_callback_interface: wl_interface = wl_interface { + version: 0, +}; + +pub static WL_CALLBACK_INTERFACE: Interface = Interface { + other_interfaces: &[], + c_ptr: Some(unsafe { &wl_callback_interface }), +}; + +// This static contains a promoted that points to a static that points to a mutable static. +pub static WL_SURFACE_INTERFACE: Interface = Interface { + other_interfaces: &[&WL_CALLBACK_INTERFACE], + c_ptr: None, +}; + +// And another variant of the same thing, this time with interior mutability. +use std::sync::OnceLock; +static LAZY_INIT: OnceLock = OnceLock::new(); +static LAZY_INIT_REF: &[&OnceLock] = &[&LAZY_INIT]; + +fn main() {} From cdea33aa2e40b6b40dfd8c13ad3954900f41d310 Mon Sep 17 00:00:00 2001 From: rustbot <47979223+rustbot@users.noreply.github.com> Date: Mon, 12 Feb 2024 12:00:33 -0500 Subject: [PATCH 50/56] Update books --- src/doc/edition-guide | 2 +- src/doc/reference | 2 +- src/doc/rust-by-example | 2 +- src/doc/rustc-dev-guide | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/doc/edition-guide b/src/doc/edition-guide index baafacc6d87..76bd48a273a 160000 --- a/src/doc/edition-guide +++ b/src/doc/edition-guide @@ -1 +1 @@ -Subproject commit baafacc6d8701269dab1e1e333f3547fb54b5a59 +Subproject commit 76bd48a273a0e0413a3bf22c699112d41497b99e diff --git a/src/doc/reference b/src/doc/reference index a0b119535e7..8227666de13 160000 --- a/src/doc/reference +++ b/src/doc/reference @@ -1 +1 @@ -Subproject commit a0b119535e7740f68494c4f0582f7ad008b00ccd +Subproject commit 8227666de13f6e7bb32dea9dc42e841adb5ce4b7 diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example index 179256a445d..e188d5d466f 160000 --- a/src/doc/rust-by-example +++ b/src/doc/rust-by-example @@ -1 +1 @@ -Subproject commit 179256a445d6144f5f371fdefb993f48f33978b0 +Subproject commit e188d5d466f7f3ff9f1d518393235f4fe951be46 diff --git a/src/doc/rustc-dev-guide b/src/doc/rustc-dev-guide index ec287e33277..1f30cc7cca9 160000 --- a/src/doc/rustc-dev-guide +++ b/src/doc/rustc-dev-guide @@ -1 +1 @@ -Subproject commit ec287e332777627185be4798ad22599ffe7b84aa +Subproject commit 1f30cc7cca9a3433bc1872abdc98960b36c21ca0 From 915200fbe077786370bf40aac30aae36dd0ff71b Mon Sep 17 00:00:00 2001 From: Urgau Date: Wed, 13 Dec 2023 14:40:19 +0100 Subject: [PATCH 51/56] Lint on reference casting to bigger underlying allocation --- compiler/rustc_lint/messages.ftl | 5 + compiler/rustc_lint/src/lints.rs | 14 +- compiler/rustc_lint/src/reference_casting.rs | 73 +++++++- tests/ui/cast/cast-rfc0401.rs | 12 +- tests/ui/lint/reference_casting.rs | 105 +++++++++++- tests/ui/lint/reference_casting.stderr | 165 ++++++++++++++++++- 6 files changed, 356 insertions(+), 18 deletions(-) diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index 5652a34103b..785895e0ab8 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -319,6 +319,11 @@ lint_invalid_nan_comparisons_lt_le_gt_ge = incorrect NaN comparison, NaN is not lint_invalid_reference_casting_assign_to_ref = assigning to `&T` is undefined behavior, consider using an `UnsafeCell` .label = casting happend here +lint_invalid_reference_casting_bigger_layout = casting references to a bigger memory layout than the backing allocation is undefined behavior, even if the reference is unused + .label = casting happend here + .alloc = backing allocation comes from here + .layout = casting from `{$from_ty}` ({$from_size} bytes) to `{$to_ty}` ({$to_size} bytes) + lint_invalid_reference_casting_borrow_as_mut = casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell` .label = casting happend here diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 42d9760f8aa..7445e2e80b4 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -716,7 +716,7 @@ pub enum InvalidFromUtf8Diag { // reference_casting.rs #[derive(LintDiagnostic)] -pub enum InvalidReferenceCastingDiag { +pub enum InvalidReferenceCastingDiag<'tcx> { #[diag(lint_invalid_reference_casting_borrow_as_mut)] #[note(lint_invalid_reference_casting_note_book)] BorrowAsMut { @@ -733,6 +733,18 @@ pub enum InvalidReferenceCastingDiag { #[note(lint_invalid_reference_casting_note_ty_has_interior_mutability)] ty_has_interior_mutability: Option<()>, }, + #[diag(lint_invalid_reference_casting_bigger_layout)] + #[note(lint_layout)] + BiggerLayout { + #[label] + orig_cast: Option, + #[label(lint_alloc)] + alloc: Span, + from_ty: Ty<'tcx>, + from_size: u64, + to_ty: Ty<'tcx>, + to_size: u64, + }, } // hidden_unicode_codepoints.rs diff --git a/compiler/rustc_lint/src/reference_casting.rs b/compiler/rustc_lint/src/reference_casting.rs index 9e6cca85317..9d67fd4b892 100644 --- a/compiler/rustc_lint/src/reference_casting.rs +++ b/compiler/rustc_lint/src/reference_casting.rs @@ -1,6 +1,7 @@ use rustc_ast::Mutability; use rustc_hir::{Expr, ExprKind, UnOp}; -use rustc_middle::ty::{self, TypeAndMut}; +use rustc_middle::ty::layout::LayoutOf as _; +use rustc_middle::ty::{self, layout::TyAndLayout, TypeAndMut}; use rustc_span::sym; use crate::{lints::InvalidReferenceCastingDiag, LateContext, LateLintPass, LintContext}; @@ -38,13 +39,12 @@ declare_lint_pass!(InvalidReferenceCasting => [INVALID_REFERENCE_CASTING]); impl<'tcx> LateLintPass<'tcx> for InvalidReferenceCasting { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { if let Some((e, pat)) = borrow_or_assign(cx, expr) { - if matches!(pat, PatternKind::Borrow { mutbl: Mutability::Mut } | PatternKind::Assign) { - let init = cx.expr_or_init(e); + let init = cx.expr_or_init(e); + let orig_cast = if init.span != e.span { Some(init.span) } else { None }; - let Some(ty_has_interior_mutability) = is_cast_from_ref_to_mut_ptr(cx, init) else { - return; - }; - let orig_cast = if init.span != e.span { Some(init.span) } else { None }; + if matches!(pat, PatternKind::Borrow { mutbl: Mutability::Mut } | PatternKind::Assign) + && let Some(ty_has_interior_mutability) = is_cast_from_ref_to_mut_ptr(cx, init) + { let ty_has_interior_mutability = ty_has_interior_mutability.then_some(()); cx.emit_span_lint( @@ -63,6 +63,23 @@ impl<'tcx> LateLintPass<'tcx> for InvalidReferenceCasting { }, ); } + + if let Some((from_ty_layout, to_ty_layout, e_alloc)) = + is_cast_to_bigger_memory_layout(cx, init) + { + cx.emit_span_lint( + INVALID_REFERENCE_CASTING, + expr.span, + InvalidReferenceCastingDiag::BiggerLayout { + orig_cast, + alloc: e_alloc.span, + from_ty: from_ty_layout.ty, + from_size: from_ty_layout.layout.size().bytes(), + to_ty: to_ty_layout.ty, + to_size: to_ty_layout.layout.size().bytes(), + }, + ); + } } } } @@ -151,6 +168,48 @@ fn is_cast_from_ref_to_mut_ptr<'tcx>( } } +fn is_cast_to_bigger_memory_layout<'tcx>( + cx: &LateContext<'tcx>, + orig_expr: &'tcx Expr<'tcx>, +) -> Option<(TyAndLayout<'tcx>, TyAndLayout<'tcx>, Expr<'tcx>)> { + let end_ty = cx.typeck_results().node_type(orig_expr.hir_id); + + let ty::RawPtr(TypeAndMut { ty: inner_end_ty, mutbl: _ }) = end_ty.kind() else { + return None; + }; + + let (e, _) = peel_casts(cx, orig_expr); + let start_ty = cx.typeck_results().node_type(e.hir_id); + + let ty::Ref(_, inner_start_ty, _) = start_ty.kind() else { + return None; + }; + + // try to find the underlying allocation + let e_alloc = cx.expr_or_init(e); + let e_alloc = + if let ExprKind::AddrOf(_, _, inner_expr) = e_alloc.kind { inner_expr } else { e_alloc }; + let alloc_ty = cx.typeck_results().node_type(e_alloc.hir_id); + + // if we do not find it we bail out, as this may not be UB + // see https://github.com/rust-lang/unsafe-code-guidelines/issues/256 + if alloc_ty.is_any_ptr() { + return None; + } + + let from_layout = cx.layout_of(*inner_start_ty).ok()?; + let alloc_layout = cx.layout_of(alloc_ty).ok()?; + let to_layout = cx.layout_of(*inner_end_ty).ok()?; + + if to_layout.layout.size() > from_layout.layout.size() + && to_layout.layout.size() > alloc_layout.layout.size() + { + Some((from_layout, to_layout, *e_alloc)) + } else { + None + } +} + fn peel_casts<'tcx>(cx: &LateContext<'tcx>, mut e: &'tcx Expr<'tcx>) -> (&'tcx Expr<'tcx>, bool) { let mut gone_trough_unsafe_cell_raw_get = false; diff --git a/tests/ui/cast/cast-rfc0401.rs b/tests/ui/cast/cast-rfc0401.rs index 9a987541615..424feeba0c4 100644 --- a/tests/ui/cast/cast-rfc0401.rs +++ b/tests/ui/cast/cast-rfc0401.rs @@ -81,14 +81,14 @@ fn main() assert_eq!(u as *const u16, p as *const u16); // ptr-ptr-cast (Length vtables) - let mut l : [u8; 2] = [0,1]; - let w: *mut [u16; 2] = &mut l as *mut [u8; 2] as *mut _; - let w: *mut [u16] = unsafe {&mut *w}; - let w_u8 : *const [u8] = w as *const [u8]; - assert_eq!(unsafe{&*w_u8}, &l); + let mut l : [u16; 2] = [0,1]; + let w: *mut [u8; 2] = &mut l as *mut [u16; 2] as *mut _; + let w: *mut [u8] = unsafe {&mut *w}; + let w_u16 : *const [u16] = w as *const [u16]; + assert_eq!(unsafe{&*w_u16}, &l); let s: *mut str = w as *mut str; - let l_via_str = unsafe{&*(s as *const [u8])}; + let l_via_str = unsafe{&*(s as *const [u16])}; assert_eq!(&l, l_via_str); // ptr-ptr-cast (Length vtables, check length is preserved) diff --git a/tests/ui/lint/reference_casting.rs b/tests/ui/lint/reference_casting.rs index 84267c0af03..63541943d65 100644 --- a/tests/ui/lint/reference_casting.rs +++ b/tests/ui/lint/reference_casting.rs @@ -30,7 +30,7 @@ unsafe fn ref_to_mut() { //~^ ERROR casting `&T` to `&mut T` is undefined behavior let _num = &mut *(num as *const i32).cast::().cast_mut().cast_const().cast_mut(); //~^ ERROR casting `&T` to `&mut T` is undefined behavior - let _num = &mut *(std::ptr::from_ref(static_u8()) as *mut i32); + let _num = &mut *(std::ptr::from_ref(static_u8()) as *mut i8); //~^ ERROR casting `&T` to `&mut T` is undefined behavior let _num = &mut *std::mem::transmute::<_, *mut i32>(num); //~^ ERROR casting `&T` to `&mut T` is undefined behavior @@ -141,6 +141,109 @@ unsafe fn assign_to_ref() { } } +#[repr(align(16))] +struct I64(i64); + +#[repr(C)] +struct Mat3 { + a: Vec3, + b: Vec3, + c: Vec3, +} + +#[repr(C)] +struct Vec3(T, T, T); + +unsafe fn bigger_layout() { + { + let num = &mut 3i32; + + let _num = &*(num as *const i32 as *const i64); + //~^ ERROR casting references to a bigger memory layout + let _num = &mut *(num as *mut i32 as *mut i64); + //~^ ERROR casting references to a bigger memory layout + let _num = &mut *(num as *mut i32 as *mut I64); + //~^ ERROR casting references to a bigger memory layout + std::ptr::write(num as *mut i32 as *mut i64, 2); + //~^ ERROR casting references to a bigger memory layout + + let _num = &mut *(num as *mut i32); + } + + { + let num = &mut [0i32; 3]; + + let _num = &mut *(num as *mut _ as *mut [i64; 2]); + //~^ ERROR casting references to a bigger memory layout + std::ptr::write_unaligned(num as *mut _ as *mut [i32; 4], [0, 0, 1, 1]); + //~^ ERROR casting references to a bigger memory layout + + let _num = &mut *(num as *mut _ as *mut [u32; 3]); + let _num = &mut *(num as *mut _ as *mut [u32; 2]); + } + + { + let num = &mut [0i32; 3] as &mut [i32]; + + let _num = &mut *(num as *mut _ as *mut i128); + //~^ ERROR casting references to a bigger memory layout + let _num = &mut *(num as *mut _ as *mut [i64; 4]); + //~^ ERROR casting references to a bigger memory layout + + let _num = &mut *(num as *mut _ as *mut [u32]); + let _num = &mut *(num as *mut _ as *mut [i16]); + } + + { + let mat3 = Mat3 { a: Vec3(0i32, 0, 0), b: Vec3(0, 0, 0), c: Vec3(0, 0, 0) }; + + let _num = &mut *(&mat3 as *const _ as *mut [[i64; 3]; 3]); + //~^ ERROR casting `&T` to `&mut T` + //~^^ ERROR casting references to a bigger memory layout + let _num = &*(&mat3 as *const _ as *mut [[i64; 3]; 3]); + //~^ ERROR casting references to a bigger memory layout + + let _num = &*(&mat3 as *const _ as *mut [[i32; 3]; 3]); + } + + { + let mut l: [u8; 2] = [0,1]; + let w: *mut [u16; 2] = &mut l as *mut [u8; 2] as *mut _; + let w: *mut [u16] = unsafe {&mut *w}; + //~^ ERROR casting references to a bigger memory layout + } + + { + fn foo() -> [i32; 1] { todo!() } + + let num = foo(); + let _num = &*(&num as *const i32 as *const i64); + //~^ ERROR casting references to a bigger memory layout + let _num = &*(&foo() as *const i32 as *const i64); + //~^ ERROR casting references to a bigger memory layout + } + + { + fn bar(_a: &[i32; 2]) -> &[i32; 1] { todo!() } + + let num = bar(&[0, 0]); + let _num = &*(num as *const i32 as *const i64); + let _num = &*(bar(&[0, 0]) as *const i32 as *const i64); + } + + { + fn foi() -> T { todo!() } + + let num = foi::(); + let _num = &*(&num as *const i32 as *const i64); + //~^ ERROR casting references to a bigger memory layout + } + + unsafe fn from_ref(this: &i32) -> &i64 { + &*(this as *const i32 as *const i64) + } +} + const RAW_PTR: *mut u8 = 1 as *mut u8; unsafe fn no_warn() { let num = &3i32; diff --git a/tests/ui/lint/reference_casting.stderr b/tests/ui/lint/reference_casting.stderr index 374a58d7b7b..26af60b6bc5 100644 --- a/tests/ui/lint/reference_casting.stderr +++ b/tests/ui/lint/reference_casting.stderr @@ -66,8 +66,8 @@ LL | let _num = &mut *(num as *const i32).cast::().cast_mut().cast_cons error: casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell` --> $DIR/reference_casting.rs:33:16 | -LL | let _num = &mut *(std::ptr::from_ref(static_u8()) as *mut i32); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | let _num = &mut *(std::ptr::from_ref(static_u8()) as *mut i8); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: for more information, visit @@ -373,5 +373,164 @@ LL | *(this as *const _ as *mut _) = a; | = note: for more information, visit -error: aborting due to 42 previous errors +error: casting references to a bigger memory layout than the backing allocation is undefined behavior, even if the reference is unused + --> $DIR/reference_casting.rs:161:20 + | +LL | let num = &mut 3i32; + | ---- backing allocation comes from here +LL | +LL | let _num = &*(num as *const i32 as *const i64); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: casting from `i32` (4 bytes) to `i64` (8 bytes) + +error: casting references to a bigger memory layout than the backing allocation is undefined behavior, even if the reference is unused + --> $DIR/reference_casting.rs:163:20 + | +LL | let num = &mut 3i32; + | ---- backing allocation comes from here +... +LL | let _num = &mut *(num as *mut i32 as *mut i64); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: casting from `i32` (4 bytes) to `i64` (8 bytes) + +error: casting references to a bigger memory layout than the backing allocation is undefined behavior, even if the reference is unused + --> $DIR/reference_casting.rs:165:20 + | +LL | let num = &mut 3i32; + | ---- backing allocation comes from here +... +LL | let _num = &mut *(num as *mut i32 as *mut I64); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: casting from `i32` (4 bytes) to `I64` (16 bytes) + +error: casting references to a bigger memory layout than the backing allocation is undefined behavior, even if the reference is unused + --> $DIR/reference_casting.rs:167:9 + | +LL | let num = &mut 3i32; + | ---- backing allocation comes from here +... +LL | std::ptr::write(num as *mut i32 as *mut i64, 2); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: casting from `i32` (4 bytes) to `i64` (8 bytes) + +error: casting references to a bigger memory layout than the backing allocation is undefined behavior, even if the reference is unused + --> $DIR/reference_casting.rs:176:20 + | +LL | let num = &mut [0i32; 3]; + | --------- backing allocation comes from here +LL | +LL | let _num = &mut *(num as *mut _ as *mut [i64; 2]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: casting from `[i32; 3]` (12 bytes) to `[i64; 2]` (16 bytes) + +error: casting references to a bigger memory layout than the backing allocation is undefined behavior, even if the reference is unused + --> $DIR/reference_casting.rs:178:9 + | +LL | let num = &mut [0i32; 3]; + | --------- backing allocation comes from here +... +LL | std::ptr::write_unaligned(num as *mut _ as *mut [i32; 4], [0, 0, 1, 1]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: casting from `[i32; 3]` (12 bytes) to `[i32; 4]` (16 bytes) + +error: casting references to a bigger memory layout than the backing allocation is undefined behavior, even if the reference is unused + --> $DIR/reference_casting.rs:188:20 + | +LL | let num = &mut [0i32; 3] as &mut [i32]; + | --------- backing allocation comes from here +LL | +LL | let _num = &mut *(num as *mut _ as *mut i128); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: casting from `[i32; 3]` (12 bytes) to `i128` (16 bytes) + +error: casting references to a bigger memory layout than the backing allocation is undefined behavior, even if the reference is unused + --> $DIR/reference_casting.rs:190:20 + | +LL | let num = &mut [0i32; 3] as &mut [i32]; + | --------- backing allocation comes from here +... +LL | let _num = &mut *(num as *mut _ as *mut [i64; 4]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: casting from `[i32; 3]` (12 bytes) to `[i64; 4]` (32 bytes) + +error: casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell` + --> $DIR/reference_casting.rs:200:20 + | +LL | let _num = &mut *(&mat3 as *const _ as *mut [[i64; 3]; 3]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: for more information, visit + +error: casting references to a bigger memory layout than the backing allocation is undefined behavior, even if the reference is unused + --> $DIR/reference_casting.rs:200:20 + | +LL | let _num = &mut *(&mat3 as *const _ as *mut [[i64; 3]; 3]); + | ^^^^^^^^----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | backing allocation comes from here + | + = note: casting from `Mat3` (36 bytes) to `[[i64; 3]; 3]` (72 bytes) + +error: casting references to a bigger memory layout than the backing allocation is undefined behavior, even if the reference is unused + --> $DIR/reference_casting.rs:203:20 + | +LL | let _num = &*(&mat3 as *const _ as *mut [[i64; 3]; 3]); + | ^^^^----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | backing allocation comes from here + | + = note: casting from `Mat3` (36 bytes) to `[[i64; 3]; 3]` (72 bytes) + +error: casting references to a bigger memory layout than the backing allocation is undefined behavior, even if the reference is unused + --> $DIR/reference_casting.rs:212:37 + | +LL | let w: *mut [u16; 2] = &mut l as *mut [u8; 2] as *mut _; + | -------------------------------- + | | | + | | backing allocation comes from here + | casting happend here +LL | let w: *mut [u16] = unsafe {&mut *w}; + | ^^^^^^^ + | + = note: casting from `[u8; 2]` (2 bytes) to `[u16; 2]` (4 bytes) + +error: casting references to a bigger memory layout than the backing allocation is undefined behavior, even if the reference is unused + --> $DIR/reference_casting.rs:220:20 + | +LL | let _num = &*(&num as *const i32 as *const i64); + | ^^^^---^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | backing allocation comes from here + | + = note: casting from `[i32; 1]` (4 bytes) to `i64` (8 bytes) + +error: casting references to a bigger memory layout than the backing allocation is undefined behavior, even if the reference is unused + --> $DIR/reference_casting.rs:222:20 + | +LL | let _num = &*(&foo() as *const i32 as *const i64); + | ^^^^-----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | backing allocation comes from here + | + = note: casting from `[i32; 1]` (4 bytes) to `i64` (8 bytes) + +error: casting references to a bigger memory layout than the backing allocation is undefined behavior, even if the reference is unused + --> $DIR/reference_casting.rs:238:20 + | +LL | let _num = &*(&num as *const i32 as *const i64); + | ^^^^---^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | backing allocation comes from here + | + = note: casting from `i32` (4 bytes) to `i64` (8 bytes) + +error: aborting due to 57 previous errors From 6a8f50e907a64117cc6dfaee7a98f28c5195e6cc Mon Sep 17 00:00:00 2001 From: Urgau Date: Fri, 15 Dec 2023 11:30:16 +0100 Subject: [PATCH 52/56] Introduce small cache to avoid recomputing the same value twice --- compiler/rustc_lint/src/reference_casting.rs | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_lint/src/reference_casting.rs b/compiler/rustc_lint/src/reference_casting.rs index 9d67fd4b892..519ab8bd50f 100644 --- a/compiler/rustc_lint/src/reference_casting.rs +++ b/compiler/rustc_lint/src/reference_casting.rs @@ -42,8 +42,15 @@ impl<'tcx> LateLintPass<'tcx> for InvalidReferenceCasting { let init = cx.expr_or_init(e); let orig_cast = if init.span != e.span { Some(init.span) } else { None }; + // small cache to avoid recomputing needlesly computing peel_casts of init + let mut peel_casts = { + let mut peel_casts_cache = None; + move || *peel_casts_cache.get_or_insert_with(|| peel_casts(cx, init)) + }; + if matches!(pat, PatternKind::Borrow { mutbl: Mutability::Mut } | PatternKind::Assign) - && let Some(ty_has_interior_mutability) = is_cast_from_ref_to_mut_ptr(cx, init) + && let Some(ty_has_interior_mutability) = + is_cast_from_ref_to_mut_ptr(cx, init, &mut peel_casts) { let ty_has_interior_mutability = ty_has_interior_mutability.then_some(()); @@ -65,7 +72,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidReferenceCasting { } if let Some((from_ty_layout, to_ty_layout, e_alloc)) = - is_cast_to_bigger_memory_layout(cx, init) + is_cast_to_bigger_memory_layout(cx, init, &mut peel_casts) { cx.emit_span_lint( INVALID_REFERENCE_CASTING, @@ -141,6 +148,7 @@ fn borrow_or_assign<'tcx>( fn is_cast_from_ref_to_mut_ptr<'tcx>( cx: &LateContext<'tcx>, orig_expr: &'tcx Expr<'tcx>, + mut peel_casts: impl FnMut() -> (&'tcx Expr<'tcx>, bool), ) -> Option { let end_ty = cx.typeck_results().node_type(orig_expr.hir_id); @@ -149,7 +157,7 @@ fn is_cast_from_ref_to_mut_ptr<'tcx>( return None; } - let (e, need_check_freeze) = peel_casts(cx, orig_expr); + let (e, need_check_freeze) = peel_casts(); let start_ty = cx.typeck_results().node_type(e.hir_id); if let ty::Ref(_, inner_ty, Mutability::Not) = start_ty.kind() { @@ -171,6 +179,7 @@ fn is_cast_from_ref_to_mut_ptr<'tcx>( fn is_cast_to_bigger_memory_layout<'tcx>( cx: &LateContext<'tcx>, orig_expr: &'tcx Expr<'tcx>, + mut peel_casts: impl FnMut() -> (&'tcx Expr<'tcx>, bool), ) -> Option<(TyAndLayout<'tcx>, TyAndLayout<'tcx>, Expr<'tcx>)> { let end_ty = cx.typeck_results().node_type(orig_expr.hir_id); @@ -178,7 +187,7 @@ fn is_cast_to_bigger_memory_layout<'tcx>( return None; }; - let (e, _) = peel_casts(cx, orig_expr); + let (e, _) = peel_casts(); let start_ty = cx.typeck_results().node_type(e.hir_id); let ty::Ref(_, inner_start_ty, _) = start_ty.kind() else { From 746bb7e13610df9a9f88222a74302b93456c1675 Mon Sep 17 00:00:00 2001 From: Urgau Date: Sun, 17 Dec 2023 17:28:24 +0100 Subject: [PATCH 53/56] Avoid UB in clippy transmute_ptr_to_ptr UI test --- src/tools/clippy/tests/ui/transmute_ptr_to_ptr.fixed | 6 +++--- src/tools/clippy/tests/ui/transmute_ptr_to_ptr.rs | 6 +++--- src/tools/clippy/tests/ui/transmute_ptr_to_ptr.stderr | 10 +++++----- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/tools/clippy/tests/ui/transmute_ptr_to_ptr.fixed b/src/tools/clippy/tests/ui/transmute_ptr_to_ptr.fixed index 4e145693c55..696def08f14 100644 --- a/src/tools/clippy/tests/ui/transmute_ptr_to_ptr.fixed +++ b/src/tools/clippy/tests/ui/transmute_ptr_to_ptr.fixed @@ -35,7 +35,7 @@ fn transmute_ptr_to_ptr() { // ref-ref transmutes; bad let _: &f32 = &*(&1u32 as *const u32 as *const f32); //~^ ERROR: transmute from a reference to a reference - let _: &f64 = &*(&1f32 as *const f32 as *const f64); + let _: &f32 = &*(&1f64 as *const f64 as *const f32); //~^ ERROR: transmute from a reference to a reference //:^ this test is here because both f32 and f64 are the same TypeVariant, but they are not // the same type @@ -43,8 +43,8 @@ fn transmute_ptr_to_ptr() { //~^ ERROR: transmute from a reference to a reference let _: &GenericParam = &*(&GenericParam { t: 1u32 } as *const GenericParam as *const GenericParam); //~^ ERROR: transmute from a reference to a reference - let u8_ref: &u8 = &0u8; - let u64_ref: &u64 = unsafe { &*(u8_ref as *const u8 as *const u64) }; + let u64_ref: &u64 = &0u64; + let u8_ref: &u8 = unsafe { &*(u64_ref as *const u64 as *const u8) }; //~^ ERROR: transmute from a reference to a reference } diff --git a/src/tools/clippy/tests/ui/transmute_ptr_to_ptr.rs b/src/tools/clippy/tests/ui/transmute_ptr_to_ptr.rs index 086aadc3647..0700d8c1957 100644 --- a/src/tools/clippy/tests/ui/transmute_ptr_to_ptr.rs +++ b/src/tools/clippy/tests/ui/transmute_ptr_to_ptr.rs @@ -35,7 +35,7 @@ fn transmute_ptr_to_ptr() { // ref-ref transmutes; bad let _: &f32 = std::mem::transmute(&1u32); //~^ ERROR: transmute from a reference to a reference - let _: &f64 = std::mem::transmute(&1f32); + let _: &f32 = std::mem::transmute(&1f64); //~^ ERROR: transmute from a reference to a reference //:^ this test is here because both f32 and f64 are the same TypeVariant, but they are not // the same type @@ -43,8 +43,8 @@ fn transmute_ptr_to_ptr() { //~^ ERROR: transmute from a reference to a reference let _: &GenericParam = std::mem::transmute(&GenericParam { t: 1u32 }); //~^ ERROR: transmute from a reference to a reference - let u8_ref: &u8 = &0u8; - let u64_ref: &u64 = unsafe { std::mem::transmute(u8_ref) }; + let u64_ref: &u64 = &0u64; + let u8_ref: &u8 = unsafe { std::mem::transmute(u64_ref) }; //~^ ERROR: transmute from a reference to a reference } diff --git a/src/tools/clippy/tests/ui/transmute_ptr_to_ptr.stderr b/src/tools/clippy/tests/ui/transmute_ptr_to_ptr.stderr index 9f8599921ec..6e3af1f7337 100644 --- a/src/tools/clippy/tests/ui/transmute_ptr_to_ptr.stderr +++ b/src/tools/clippy/tests/ui/transmute_ptr_to_ptr.stderr @@ -22,8 +22,8 @@ LL | let _: &f32 = std::mem::transmute(&1u32); error: transmute from a reference to a reference --> $DIR/transmute_ptr_to_ptr.rs:38:23 | -LL | let _: &f64 = std::mem::transmute(&1f32); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(&1f32 as *const f32 as *const f64)` +LL | let _: &f32 = std::mem::transmute(&1f64); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(&1f64 as *const f64 as *const f32)` error: transmute from a reference to a reference --> $DIR/transmute_ptr_to_ptr.rs:42:27 @@ -38,10 +38,10 @@ LL | let _: &GenericParam = std::mem::transmute(&GenericParam { t: | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(&GenericParam { t: 1u32 } as *const GenericParam as *const GenericParam)` error: transmute from a reference to a reference - --> $DIR/transmute_ptr_to_ptr.rs:47:38 + --> $DIR/transmute_ptr_to_ptr.rs:47:36 | -LL | let u64_ref: &u64 = unsafe { std::mem::transmute(u8_ref) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(u8_ref as *const u8 as *const u64)` +LL | let u8_ref: &u8 = unsafe { std::mem::transmute(u64_ref) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(u64_ref as *const u64 as *const u8)` error: aborting due to 7 previous errors From e08c9d1f812b02e397c6ef618472a2e5586879b6 Mon Sep 17 00:00:00 2001 From: Urgau Date: Sun, 17 Dec 2023 18:40:49 +0100 Subject: [PATCH 54/56] Allow invalid ref casting in Miri unaligned_ref_addr_of test --- .../miri/tests/fail/unaligned_pointers/unaligned_ref_addr_of.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ref_addr_of.rs b/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ref_addr_of.rs index 470420acd50..225feef7281 100644 --- a/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ref_addr_of.rs +++ b/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ref_addr_of.rs @@ -1,6 +1,8 @@ // This should fail even without Stacked Borrows. //@compile-flags: -Zmiri-disable-stacked-borrows -Cdebug-assertions=no +#![allow(invalid_reference_casting)] // for u16 -> u32 + fn main() { // Try many times as this might work by chance. for _ in 0..20 { From 760e8d284241f95fd74e96f065055293e9698d79 Mon Sep 17 00:00:00 2001 From: The Miri Conjob Bot Date: Tue, 13 Feb 2024 05:14:22 +0000 Subject: [PATCH 55/56] Preparing for merge from rustc --- src/tools/miri/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index 2c98082bc1e..eca1a2335c8 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -b17491c8f6d555386104dfd82004c01bfef09c95 +d26b41711282042c4ea0c5733e7332b07cfa4933 From 43e9411db839747f650e1125ed06266566c20b65 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 13 Feb 2024 08:31:45 +0000 Subject: [PATCH 56/56] Prevent rustfmt from messing up experimental syntax --- src/tools/miri/tests/pass/async-closure.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/tools/miri/tests/pass/async-closure.rs b/src/tools/miri/tests/pass/async-closure.rs index 9b2fc2948bf..e04acfc39cf 100644 --- a/src/tools/miri/tests/pass/async-closure.rs +++ b/src/tools/miri/tests/pass/async-closure.rs @@ -16,6 +16,7 @@ pub fn block_on(fut: impl Future) -> T { } } +#[rustfmt::skip] async fn call_once(f: impl async FnOnce(DropMe)) { f(DropMe("world")).await; }