diff options
Diffstat (limited to 'compiler')
130 files changed, 1635 insertions, 1384 deletions
diff --git a/compiler/rustc_abi/src/layout.rs b/compiler/rustc_abi/src/layout.rs index 9165b4f2df3..197dd7f9c9e 100644 --- a/compiler/rustc_abi/src/layout.rs +++ b/compiler/rustc_abi/src/layout.rs @@ -186,7 +186,7 @@ pub trait LayoutCalculator { let (present_first, present_second) = { let mut present_variants = variants .iter_enumerated() - .filter_map(|(i, v)| if absent(v) { None } else { Some(i) }); + .filter_map(|(i, v)| if !repr.c() && absent(v) { None } else { Some(i) }); (present_variants.next(), present_variants.next()) }; let present_first = match present_first { @@ -621,7 +621,7 @@ where let discr_type = repr.discr_type(); let bits = Integer::from_attr(dl, discr_type).size().bits(); for (i, mut val) in discriminants { - if variants[i].iter().any(|f| f.abi.is_uninhabited()) { + if !repr.c() && variants[i].iter().any(|f| f.abi.is_uninhabited()) { continue; } if discr_type.is_signed() { diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs index 31c66a56bea..78332d66f03 100644 --- a/compiler/rustc_abi/src/lib.rs +++ b/compiler/rustc_abi/src/lib.rs @@ -1429,7 +1429,7 @@ pub enum Variants<FieldIdx: Idx, VariantIdx: Idx> { /// Single enum variants, structs/tuples, unions, and all non-ADTs. Single { index: VariantIdx }, - /// Enum-likes with more than one inhabited variant: each variant comes with + /// Enum-likes with more than one variant: each variant comes with /// a *discriminant* (usually the same as the variant index but the user can /// assign explicit discriminant values). That discriminant is encoded /// as a *tag* on the machine. The layout of each variant is diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index dbbc4980050..75c656973f9 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -176,7 +176,7 @@ pub enum GenericArgs { AngleBracketed(AngleBracketedArgs), /// The `(A, B)` and `C` in `Foo(A, B) -> C`. Parenthesized(ParenthesizedArgs), - /// `(..)` in return type notation + /// `(..)` in return type notation. ParenthesizedElided(Span), } @@ -197,11 +197,11 @@ impl GenericArgs { /// Concrete argument in the sequence of generic args. #[derive(Clone, Encodable, Decodable, Debug)] pub enum GenericArg { - /// `'a` in `Foo<'a>` + /// `'a` in `Foo<'a>`. Lifetime(Lifetime), - /// `Bar` in `Foo<Bar>` + /// `Bar` in `Foo<Bar>`. Type(P<Ty>), - /// `1` in `Foo<1>` + /// `1` in `Foo<1>`. Const(AnonConst), } @@ -355,7 +355,7 @@ pub enum GenericParamKind { ty: P<Ty>, /// Span of the `const` keyword. kw_span: Span, - /// Optional default value for the const generic param + /// Optional default value for the const generic param. default: Option<AnonConst>, }, } @@ -714,6 +714,7 @@ pub enum ByRef { } impl ByRef { + #[must_use] pub fn cap_ref_mutability(mut self, mutbl: Mutability) -> Self { if let ByRef::Yes(old_mutbl) = &mut self { *old_mutbl = cmp::min(*old_mutbl, mutbl); @@ -832,7 +833,7 @@ pub enum PatKind { /// only one rest pattern may occur in the pattern sequences. Rest, - // A never pattern `!` + // A never pattern `!`. Never, /// Parentheses in patterns used for grouping (i.e., `(PAT)`). @@ -1121,9 +1122,9 @@ impl LocalKind { #[derive(Clone, Encodable, Decodable, Debug)] pub struct Arm { pub attrs: AttrVec, - /// Match arm pattern, e.g. `10` in `match foo { 10 => {}, _ => {} }` + /// Match arm pattern, e.g. `10` in `match foo { 10 => {}, _ => {} }`. pub pat: P<Pat>, - /// Match arm guard, e.g. `n > 10` in `match foo { n if n > 10 => {}, _ => {} }` + /// Match arm guard, e.g. `n > 10` in `match foo { n if n > 10 => {}, _ => {} }`. pub guard: Option<P<Expr>>, /// Match arm body. Omitted if the pattern is a never pattern. pub body: Option<P<Expr>>, @@ -1354,12 +1355,12 @@ pub struct Closure { pub fn_arg_span: Span, } -/// Limit types of a range (inclusive or exclusive) +/// Limit types of a range (inclusive or exclusive). #[derive(Copy, Clone, PartialEq, Encodable, Decodable, Debug)] pub enum RangeLimits { - /// Inclusive at the beginning, exclusive at the end + /// Inclusive at the beginning, exclusive at the end. HalfOpen, - /// Inclusive at the beginning and end + /// Inclusive at the beginning and end. Closed, } @@ -1400,9 +1401,9 @@ pub struct StructExpr { pub enum ExprKind { /// An array (e.g, `[a, b, c, d]`). Array(ThinVec<P<Expr>>), - /// Allow anonymous constants from an inline `const` block + /// Allow anonymous constants from an inline `const` block. ConstBlock(AnonConst), - /// A function call + /// A function call. /// /// The first field resolves to the function itself, /// and the second field is the list of arguments. @@ -1456,7 +1457,7 @@ pub enum ExprKind { /// A block (`'label: { ... }`). Block(P<Block>, Option<Label>), /// An `async` block (`async move { ... }`), - /// or a `gen` block (`gen move { ... }`) + /// or a `gen` block (`gen move { ... }`). /// /// The span is the "decl", which is the header before the body `{ }` /// including the `asyng`/`gen` keywords and possibly `move`. @@ -2156,9 +2157,9 @@ pub enum TyKind { Never, /// A tuple (`(A, B, C, D,...)`). Tup(ThinVec<P<Ty>>), - /// An anonymous struct type i.e. `struct { foo: Type }` + /// An anonymous struct type i.e. `struct { foo: Type }`. AnonStruct(NodeId, ThinVec<FieldDef>), - /// An anonymous union type i.e. `union { bar: Type }` + /// An anonymous union type i.e. `union { bar: Type }`. AnonUnion(NodeId, ThinVec<FieldDef>), /// A path (`module::module::...::Type`), optionally /// "qualified", e.g., `<Vec<T> as SomeTrait>::SomeType`. @@ -2232,9 +2233,9 @@ pub enum TraitObjectSyntax { #[derive(Clone, Encodable, Decodable, Debug)] pub enum PreciseCapturingArg { - /// Lifetime parameter + /// Lifetime parameter. Lifetime(Lifetime), - /// Type or const parameter + /// Type or const parameter. Arg(Path, NodeId), } @@ -2528,11 +2529,11 @@ pub enum Safety { /// Iterator`. #[derive(Copy, Clone, Encodable, Decodable, Debug)] pub enum CoroutineKind { - /// `async`, which returns an `impl Future` + /// `async`, which returns an `impl Future`. Async { span: Span, closure_id: NodeId, return_impl_trait_id: NodeId }, - /// `gen`, which returns an `impl Iterator` + /// `gen`, which returns an `impl Iterator`. Gen { span: Span, closure_id: NodeId, return_impl_trait_id: NodeId }, - /// `async gen`, which returns an `impl AsyncIterator` + /// `async gen`, which returns an `impl AsyncIterator`. AsyncGen { span: Span, closure_id: NodeId, return_impl_trait_id: NodeId }, } @@ -2749,7 +2750,7 @@ pub struct Variant { pub data: VariantData, /// Explicit discriminant, e.g., `Foo = 1`. pub disr_expr: Option<AnonConst>, - /// Is a macro placeholder + /// Is a macro placeholder. pub is_placeholder: bool, } @@ -3023,19 +3024,19 @@ impl Item { /// `extern` qualifier on a function item or function type. #[derive(Clone, Copy, Encodable, Decodable, Debug)] pub enum Extern { - /// No explicit extern keyword was used + /// No explicit extern keyword was used. /// - /// E.g. `fn foo() {}` + /// E.g. `fn foo() {}`. None, - /// An explicit extern keyword was used, but with implicit ABI + /// An explicit extern keyword was used, but with implicit ABI. /// - /// E.g. `extern fn foo() {}` + /// E.g. `extern fn foo() {}`. /// - /// This is just `extern "C"` (see `rustc_target::spec::abi::Abi::FALLBACK`) + /// This is just `extern "C"` (see `rustc_target::spec::abi::Abi::FALLBACK`). Implicit(Span), - /// An explicit extern keyword was used with an explicit ABI + /// An explicit extern keyword was used with an explicit ABI. /// - /// E.g. `extern "C" fn foo() {}` + /// E.g. `extern "C" fn foo() {}`. Explicit(StrLit, Span), } @@ -3054,13 +3055,13 @@ impl Extern { /// included in this struct (e.g., `async unsafe fn` or `const extern "C" fn`). #[derive(Clone, Copy, Encodable, Decodable, Debug)] pub struct FnHeader { - /// Whether this is `unsafe`, or has a default safety + /// Whether this is `unsafe`, or has a default safety. pub safety: Safety, /// Whether this is `async`, `gen`, or nothing. pub coroutine_kind: Option<CoroutineKind>, /// The `const` keyword, if any pub constness: Const, - /// The `extern` keyword and corresponding ABI string, if any + /// The `extern` keyword and corresponding ABI string, if any. pub ext: Extern, } @@ -3254,7 +3255,7 @@ pub enum ItemKind { /// /// E.g., `trait Foo { .. }`, `trait Foo<T> { .. }` or `auto trait Foo {}`. Trait(Box<Trait>), - /// Trait alias + /// Trait alias. /// /// E.g., `trait Foo = Bar + Quux;`. TraitAlias(Generics, GenericBounds), diff --git a/compiler/rustc_ast/src/ast_traits.rs b/compiler/rustc_ast/src/ast_traits.rs index 2cf811e9122..7754ca0a0f5 100644 --- a/compiler/rustc_ast/src/ast_traits.rs +++ b/compiler/rustc_ast/src/ast_traits.rs @@ -10,8 +10,6 @@ use crate::{AssocItem, Expr, ForeignItem, Item, NodeId}; use crate::{AttrItem, AttrKind, Block, Pat, Path, Ty, Visibility}; use crate::{AttrVec, Attribute, Stmt, StmtKind}; -use rustc_span::Span; - use std::fmt; use std::marker::PhantomData; @@ -91,37 +89,6 @@ impl<T: AstDeref<Target: HasNodeId>> HasNodeId for T { } } -/// A trait for AST nodes having a span. -pub trait HasSpan { - fn span(&self) -> Span; -} - -macro_rules! impl_has_span { - ($($T:ty),+ $(,)?) => { - $( - impl HasSpan for $T { - fn span(&self) -> Span { - self.span - } - } - )+ - }; -} - -impl_has_span!(AssocItem, Block, Expr, ForeignItem, Item, Pat, Path, Stmt, Ty, Visibility); - -impl<T: AstDeref<Target: HasSpan>> HasSpan for T { - fn span(&self) -> Span { - self.ast_deref().span() - } -} - -impl HasSpan for AttrItem { - fn span(&self) -> Span { - self.span() - } -} - /// A trait for AST nodes having (or not having) collected tokens. pub trait HasTokens { fn tokens(&self) -> Option<&LazyAttrTokenStream>; diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs index 65f1b5dbaf5..088ae9ba441 100644 --- a/compiler/rustc_ast/src/attr/mod.rs +++ b/compiler/rustc_ast/src/attr/mod.rs @@ -202,7 +202,8 @@ impl Attribute { } } - pub fn tokens(&self) -> TokenStream { + // Named `get_tokens` to distinguish it from the `<Attribute as HasTokens>::tokens` method. + pub fn get_tokens(&self) -> TokenStream { match &self.kind { AttrKind::Normal(normal) => TokenStream::new( normal diff --git a/compiler/rustc_ast/src/lib.rs b/compiler/rustc_ast/src/lib.rs index 7ca950e50e6..846a108091f 100644 --- a/compiler/rustc_ast/src/lib.rs +++ b/compiler/rustc_ast/src/lib.rs @@ -44,7 +44,7 @@ pub mod tokenstream; pub mod visit; pub use self::ast::*; -pub use self::ast_traits::{AstDeref, AstNodeWrapper, HasAttrs, HasNodeId, HasSpan, HasTokens}; +pub use self::ast_traits::{AstDeref, AstNodeWrapper, HasAttrs, HasNodeId, HasTokens}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index f816375b912..cbf21317f1a 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -704,7 +704,7 @@ fn visit_attr_tt<T: MutVisitor>(tt: &mut AttrTokenTree, vis: &mut T) { visit_attr_tts(tts, vis); visit_delim_span(dspan, vis); } - AttrTokenTree::Attributes(AttributesData { attrs, tokens }) => { + AttrTokenTree::AttrsTarget(AttrsTarget { attrs, tokens }) => { visit_attrs(attrs, vis); visit_lazy_tts_opt_mut(Some(tokens), vis); } diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs index 655c18e4559..ee068f19332 100644 --- a/compiler/rustc_ast/src/tokenstream.rs +++ b/compiler/rustc_ast/src/tokenstream.rs @@ -14,7 +14,7 @@ //! ownership of the original. use crate::ast::{AttrStyle, StmtKind}; -use crate::ast_traits::{HasAttrs, HasSpan, HasTokens}; +use crate::ast_traits::{HasAttrs, HasTokens}; use crate::token::{self, Delimiter, Nonterminal, Token, TokenKind}; use crate::AttrVec; @@ -170,8 +170,8 @@ pub enum AttrTokenTree { Delimited(DelimSpan, DelimSpacing, Delimiter, AttrTokenStream), /// Stores the attributes for an attribute target, /// along with the tokens for that attribute target. - /// See `AttributesData` for more information - Attributes(AttributesData), + /// See `AttrsTarget` for more information + AttrsTarget(AttrsTarget), } impl AttrTokenStream { @@ -180,7 +180,7 @@ impl AttrTokenStream { } /// Converts this `AttrTokenStream` to a plain `Vec<TokenTree>`. - /// During conversion, `AttrTokenTree::Attributes` get 'flattened' + /// During conversion, `AttrTokenTree::AttrsTarget` get 'flattened' /// back to a `TokenStream` of the form `outer_attr attr_target`. /// If there are inner attributes, they are inserted into the proper /// place in the attribute target tokens. @@ -199,13 +199,13 @@ impl AttrTokenStream { TokenStream::new(stream.to_token_trees()), )) } - AttrTokenTree::Attributes(data) => { - let idx = data + AttrTokenTree::AttrsTarget(target) => { + let idx = target .attrs .partition_point(|attr| matches!(attr.style, crate::AttrStyle::Outer)); - let (outer_attrs, inner_attrs) = data.attrs.split_at(idx); + let (outer_attrs, inner_attrs) = target.attrs.split_at(idx); - let mut target_tokens = data.tokens.to_attr_token_stream().to_token_trees(); + let mut target_tokens = target.tokens.to_attr_token_stream().to_token_trees(); if !inner_attrs.is_empty() { let mut found = false; // Check the last two trees (to account for a trailing semi) @@ -227,7 +227,7 @@ impl AttrTokenStream { let mut stream = TokenStream::default(); for inner_attr in inner_attrs { - stream.push_stream(inner_attr.tokens()); + stream.push_stream(inner_attr.get_tokens()); } stream.push_stream(delim_tokens.clone()); *tree = TokenTree::Delimited(*span, *spacing, *delim, stream); @@ -242,7 +242,7 @@ impl AttrTokenStream { ); } for attr in outer_attrs { - res.extend(attr.tokens().0.iter().cloned()); + res.extend(attr.get_tokens().0.iter().cloned()); } res.extend(target_tokens); } @@ -262,7 +262,7 @@ impl AttrTokenStream { /// have an `attrs` field containing the `#[cfg(FALSE)]` attr, /// and a `tokens` field storing the (unparsed) tokens `struct Foo {}` #[derive(Clone, Debug, Encodable, Decodable)] -pub struct AttributesData { +pub struct AttrsTarget { /// Attributes, both outer and inner. /// These are stored in the original order that they were parsed in. pub attrs: AttrVec, @@ -436,17 +436,17 @@ impl TokenStream { TokenStream::new(vec![TokenTree::token_alone(kind, span)]) } - pub fn from_ast(node: &(impl HasAttrs + HasSpan + HasTokens + fmt::Debug)) -> TokenStream { + pub fn from_ast(node: &(impl HasAttrs + HasTokens + fmt::Debug)) -> TokenStream { let Some(tokens) = node.tokens() else { - panic!("missing tokens for node at {:?}: {:?}", node.span(), node); + panic!("missing tokens for node: {:?}", node); }; let attrs = node.attrs(); let attr_stream = if attrs.is_empty() { tokens.to_attr_token_stream() } else { - let attr_data = - AttributesData { attrs: attrs.iter().cloned().collect(), tokens: tokens.clone() }; - AttrTokenStream::new(vec![AttrTokenTree::Attributes(attr_data)]) + let target = + AttrsTarget { attrs: attrs.iter().cloned().collect(), tokens: tokens.clone() }; + AttrTokenStream::new(vec![AttrTokenTree::AttrsTarget(target)]) }; TokenStream::new(attr_stream.to_token_trees()) } @@ -765,6 +765,7 @@ mod size_asserts { static_assert_size!(AttrTokenStream, 8); static_assert_size!(AttrTokenTree, 32); static_assert_size!(LazyAttrTokenStream, 8); + static_assert_size!(Option<LazyAttrTokenStream>, 8); // must be small, used in many AST nodes static_assert_size!(TokenStream, 8); static_assert_size!(TokenTree, 32); // tidy-alphabetical-end diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 7ef53fa2078..c2c3f5bc79e 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -39,6 +39,7 @@ use rustc_trait_selection::traits::error_reporting::suggestions::TypeErrCtxtExt; use rustc_trait_selection::traits::error_reporting::FindExprBySpan; use rustc_trait_selection::traits::{Obligation, ObligationCause, ObligationCtxt}; use std::iter; +use std::ops::ControlFlow; use crate::borrow_set::TwoPhaseActivation; use crate::borrowck_errors; @@ -784,20 +785,20 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> { /// binding declaration within every scope we inspect. struct Finder { hir_id: hir::HirId, - found: bool, } impl<'hir> Visitor<'hir> for Finder { - fn visit_pat(&mut self, pat: &'hir hir::Pat<'hir>) { + type Result = ControlFlow<()>; + fn visit_pat(&mut self, pat: &'hir hir::Pat<'hir>) -> Self::Result { if pat.hir_id == self.hir_id { - self.found = true; + return ControlFlow::Break(()); } - hir::intravisit::walk_pat(self, pat); + hir::intravisit::walk_pat(self, pat) } - fn visit_expr(&mut self, ex: &'hir hir::Expr<'hir>) { + fn visit_expr(&mut self, ex: &'hir hir::Expr<'hir>) -> Self::Result { if ex.hir_id == self.hir_id { - self.found = true; + return ControlFlow::Break(()); } - hir::intravisit::walk_expr(self, ex); + hir::intravisit::walk_expr(self, ex) } } // The immediate HIR parent of the moved expression. We'll look for it to be a call. @@ -822,9 +823,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> { _ => continue, }; if let Some(&hir_id) = local_hir_id { - let mut finder = Finder { hir_id, found: false }; - finder.visit_expr(e); - if finder.found { + if (Finder { hir_id }).visit_expr(e).is_break() { // The current scope includes the declaration of the binding we're accessing, we // can't look up any further for loops. break; @@ -839,9 +838,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> { hir::Node::Expr(hir::Expr { kind: hir::ExprKind::If(cond, ..), .. }) => { - let mut finder = Finder { hir_id: expr.hir_id, found: false }; - finder.visit_expr(cond); - if finder.found { + if (Finder { hir_id: expr.hir_id }).visit_expr(cond).is_break() { // The expression where the move error happened is in a `while let` // condition Don't suggest clone as it will likely end in an // infinite loop. @@ -1837,7 +1834,6 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> { pub struct Holds<'tcx> { ty: Ty<'tcx>, - holds: bool, } impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for Holds<'tcx> { @@ -1845,7 +1841,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> { fn visit_ty(&mut self, t: Ty<'tcx>) -> Self::Result { if t == self.ty { - self.holds = true; + return ControlFlow::Break(()); } t.super_visit_with(self) } @@ -1863,9 +1859,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> { && rcvr_ty == ty && let ty::Ref(_, inner, _) = rcvr_ty.kind() && let inner = inner.peel_refs() - && let mut v = (Holds { ty: inner, holds: false }) - && let _ = v.visit_ty(local_ty) - && v.holds + && (Holds { ty: inner }).visit_ty(local_ty).is_break() && let None = self.infcx.type_implements_trait_shallow(clone, inner, self.param_env) { err.span_label( @@ -3757,13 +3751,11 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> { assigned_span: Span, err_place: Place<'tcx>, ) { - let (from_arg, local_decl, local_name) = match err_place.as_local() { - Some(local) => ( - self.body.local_kind(local) == LocalKind::Arg, - Some(&self.body.local_decls[local]), - self.local_names[local], - ), - None => (false, None, None), + let (from_arg, local_decl) = match err_place.as_local() { + Some(local) => { + (self.body.local_kind(local) == LocalKind::Arg, Some(&self.body.local_decls[local])) + } + None => (false, None), }; // If root local is initialized immediately (everything apart from let @@ -3795,13 +3787,12 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> { err.span_label(assigned_span, format!("first assignment to {place_description}")); } if let Some(decl) = local_decl - && let Some(name) = local_name && decl.can_be_made_mutable() { - err.span_suggestion( - decl.source_info.span, + err.span_suggestion_verbose( + decl.source_info.span.shrink_to_lo(), "consider making this binding mutable", - format!("mut {name}"), + "mut ".to_string(), Applicability::MachineApplicable, ); if !from_arg @@ -3813,10 +3804,10 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> { })) ) { - err.span_suggestion( - decl.source_info.span, + err.span_suggestion_verbose( + decl.source_info.span.shrink_to_lo(), "to modify the original value, take a borrow instead", - format!("ref mut {name}"), + "ref mut ".to_string(), Applicability::MaybeIncorrect, ); } @@ -4328,15 +4319,14 @@ impl<'tcx> AnnotatedBorrowFnSignature<'tcx> { } /// Detect whether one of the provided spans is a statement nested within the top-most visited expr -struct ReferencedStatementsVisitor<'a>(&'a [Span], bool); +struct ReferencedStatementsVisitor<'a>(&'a [Span]); -impl<'a, 'v> Visitor<'v> for ReferencedStatementsVisitor<'a> { - fn visit_stmt(&mut self, s: &'v hir::Stmt<'v>) { +impl<'v> Visitor<'v> for ReferencedStatementsVisitor<'_> { + type Result = ControlFlow<()>; + fn visit_stmt(&mut self, s: &'v hir::Stmt<'v>) -> Self::Result { match s.kind { - hir::StmtKind::Semi(expr) if self.0.contains(&expr.span) => { - self.1 = true; - } - _ => {} + hir::StmtKind::Semi(expr) if self.0.contains(&expr.span) => ControlFlow::Break(()), + _ => ControlFlow::Continue(()), } } } @@ -4378,9 +4368,7 @@ impl<'b, 'v, 'tcx> Visitor<'v> for ConditionVisitor<'b, 'tcx> { hir::ExprKind::If(cond, body, None) => { // `if` expressions with no `else` that initialize the binding might be missing an // `else` arm. - let mut v = ReferencedStatementsVisitor(self.spans, false); - v.visit_expr(body); - if v.1 { + if ReferencedStatementsVisitor(self.spans).visit_expr(body).is_break() { self.errors.push(( cond.span, format!( @@ -4397,11 +4385,9 @@ impl<'b, 'v, 'tcx> Visitor<'v> for ConditionVisitor<'b, 'tcx> { hir::ExprKind::If(cond, body, Some(other)) => { // `if` expressions where the binding is only initialized in one of the two arms // might be missing a binding initialization. - let mut a = ReferencedStatementsVisitor(self.spans, false); - a.visit_expr(body); - let mut b = ReferencedStatementsVisitor(self.spans, false); - b.visit_expr(other); - match (a.1, b.1) { + let a = ReferencedStatementsVisitor(self.spans).visit_expr(body).is_break(); + let b = ReferencedStatementsVisitor(self.spans).visit_expr(other).is_break(); + match (a, b) { (true, true) | (false, false) => {} (true, false) => { if other.span.is_desugaring(DesugaringKind::WhileLoop) { @@ -4440,11 +4426,7 @@ impl<'b, 'v, 'tcx> Visitor<'v> for ConditionVisitor<'b, 'tcx> { // arms might be missing an initialization. let results: Vec<bool> = arms .iter() - .map(|arm| { - let mut v = ReferencedStatementsVisitor(self.spans, false); - v.visit_arm(arm); - v.1 - }) + .map(|arm| ReferencedStatementsVisitor(self.spans).visit_arm(arm).is_break()) .collect(); if results.iter().any(|x| *x) && !results.iter().all(|x| *x) { for (arm, seen) in arms.iter().zip(results) { diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index 19a4df0cd7b..677029f9d3f 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -408,10 +408,10 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> { fn_decl.implicit_self, hir::ImplicitSelfKind::RefImm | hir::ImplicitSelfKind::RefMut ) { - err.span_suggestion( - upvar_ident.span, + err.span_suggestion_verbose( + upvar_ident.span.shrink_to_lo(), "consider changing this to be mutable", - format!("mut {}", upvar_ident.name), + "mut ", Applicability::MachineApplicable, ); break; @@ -419,10 +419,10 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> { } } } else { - err.span_suggestion( - upvar_ident.span, + err.span_suggestion_verbose( + upvar_ident.span.shrink_to_lo(), "consider changing this to be mutable", - format!("mut {}", upvar_ident.name), + "mut ", Applicability::MachineApplicable, ); } @@ -449,8 +449,8 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> { .is_ok_and(|snippet| snippet.starts_with("&mut ")) => { err.span_label(span, format!("cannot {act}")); - err.span_suggestion( - span, + err.span_suggestion_verbose( + span.with_hi(span.lo() + BytePos(5)), "try removing `&mut` here", "", Applicability::MaybeIncorrect, @@ -755,13 +755,16 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> { pat: hir::Pat { kind: hir::PatKind::Ref(_, _), .. }, .. }) = node - && let Ok(name) = - self.infcx.tcx.sess.source_map().span_to_snippet(local_decl.source_info.span) { - err.span_suggestion( - pat_span, + err.multipart_suggestion( "consider changing this to be mutable", - format!("&(mut {name})"), + vec![ + (pat_span.until(local_decl.source_info.span), "&(mut ".to_string()), + ( + local_decl.source_info.span.shrink_to_hi().with_hi(pat_span.hi()), + ")".to_string(), + ), + ], Applicability::MachineApplicable, ); return; diff --git a/compiler/rustc_borrowck/src/facts.rs b/compiler/rustc_borrowck/src/facts.rs index 51ea59e2092..af96f115385 100644 --- a/compiler/rustc_borrowck/src/facts.rs +++ b/compiler/rustc_borrowck/src/facts.rs @@ -213,8 +213,32 @@ trait FactCell { fn to_string(&self, location_table: &LocationTable) -> String; } -impl<A: Debug> FactCell for A { - default fn to_string(&self, _location_table: &LocationTable) -> String { +impl FactCell for BorrowIndex { + fn to_string(&self, _location_table: &LocationTable) -> String { + format!("{self:?}") + } +} + +impl FactCell for Local { + fn to_string(&self, _location_table: &LocationTable) -> String { + format!("{self:?}") + } +} + +impl FactCell for MovePathIndex { + fn to_string(&self, _location_table: &LocationTable) -> String { + format!("{self:?}") + } +} + +impl FactCell for PoloniusRegionVid { + fn to_string(&self, _location_table: &LocationTable) -> String { + format!("{self:?}") + } +} + +impl FactCell for RegionVid { + fn to_string(&self, _location_table: &LocationTable) -> String { format!("{self:?}") } } diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index e6f8ffd428d..36ba1d81be6 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -7,7 +7,6 @@ #![feature(box_patterns)] #![feature(control_flow_enum)] #![feature(let_chains)] -#![feature(min_specialization)] #![feature(never_type)] #![feature(rustc_attrs)] #![feature(rustdoc_internals)] diff --git a/compiler/rustc_borrowck/src/type_check/relate_tys.rs b/compiler/rustc_borrowck/src/type_check/relate_tys.rs index b9a82046e59..02b9c2d48b1 100644 --- a/compiler/rustc_borrowck/src/type_check/relate_tys.rs +++ b/compiler/rustc_borrowck/src/type_check/relate_tys.rs @@ -1,8 +1,9 @@ use rustc_data_structures::fx::FxHashMap; use rustc_errors::ErrorGuaranteed; -use rustc_infer::infer::relate::{PredicateEmittingRelation, StructurallyRelateAliases}; -use rustc_infer::infer::relate::{Relate, RelateResult, TypeRelation}; -use rustc_infer::infer::NllRegionVariableOrigin; +use rustc_infer::infer::relate::{ + PredicateEmittingRelation, Relate, RelateResult, StructurallyRelateAliases, TypeRelation, +}; +use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin}; use rustc_infer::traits::solve::Goal; use rustc_infer::traits::Obligation; use rustc_middle::mir::ConstraintCategory; @@ -522,7 +523,7 @@ impl<'bccx, 'tcx> TypeRelation<TyCtxt<'tcx>> for NllTypeRelating<'_, 'bccx, 'tcx } } -impl<'bccx, 'tcx> PredicateEmittingRelation<'tcx> for NllTypeRelating<'_, 'bccx, 'tcx> { +impl<'bccx, 'tcx> PredicateEmittingRelation<InferCtxt<'tcx>> for NllTypeRelating<'_, 'bccx, 'tcx> { fn span(&self) -> Span { self.locations.span(self.type_checker.body) } diff --git a/compiler/rustc_builtin_macros/messages.ftl b/compiler/rustc_builtin_macros/messages.ftl index 2d1269e1b6a..b56bfa98357 100644 --- a/compiler/rustc_builtin_macros/messages.ftl +++ b/compiler/rustc_builtin_macros/messages.ftl @@ -17,6 +17,9 @@ builtin_macros_asm_expected_other = expected operand, {$is_global_asm -> *[false] clobber_abi, options }, or additional template string +builtin_macros_asm_expected_string_literal = expected string literal + .label = not a string literal + builtin_macros_asm_explicit_register_name = explicit register arguments cannot have names builtin_macros_asm_mayunwind = asm labels are not allowed with the `may_unwind` option @@ -25,6 +28,8 @@ builtin_macros_asm_modifier_invalid = asm template modifier must be a single cha builtin_macros_asm_mutually_exclusive = the `{$opt1}` and `{$opt2}` options are mutually exclusive +builtin_macros_asm_no_matched_argument_name = there is no argument named `{$name}` + builtin_macros_asm_noreturn = asm outputs are not allowed with the `noreturn` option builtin_macros_asm_opt_already_provided = the `{$symbol}` option was already provided @@ -228,10 +233,16 @@ builtin_macros_only_one_argument = {$name} takes 1 argument builtin_macros_proc_macro = `proc-macro` crate types currently cannot export any items other than functions tagged with `#[proc_macro]`, `#[proc_macro_derive]`, or `#[proc_macro_attribute]` +builtin_macros_proc_macro_attribute_only_be_used_on_bare_functions = the `#[{$path}]` attribute may only be used on bare functions + +builtin_macros_proc_macro_attribute_only_usable_with_crate_type = the `#[{$path}]` attribute is only usable with crates of the `proc-macro` crate type + builtin_macros_requires_cfg_pattern = macro requires a cfg-pattern as an argument .label = cfg-pattern required +builtin_macros_source_uitls_expected_item = expected item, found `{$token}` + builtin_macros_takes_no_arguments = {$name} takes no arguments builtin_macros_test_bad_fn = {$kind} functions cannot be used for tests diff --git a/compiler/rustc_builtin_macros/src/asm.rs b/compiler/rustc_builtin_macros/src/asm.rs index 64238e81b26..dd0f9aaf221 100644 --- a/compiler/rustc_builtin_macros/src/asm.rs +++ b/compiler/rustc_builtin_macros/src/asm.rs @@ -390,9 +390,7 @@ fn parse_clobber_abi<'a>(p: &mut Parser<'a>, args: &mut AsmArgs) -> PResult<'a, } Err(opt_lit) => { let span = opt_lit.map_or(p.token.span, |lit| lit.span); - let mut err = p.dcx().struct_span_err(span, "expected string literal"); - err.span_label(span, "not a string literal"); - return Err(err); + return Err(p.dcx().create_err(errors::AsmExpectedStringLiteral { span })); } }; @@ -639,14 +637,13 @@ fn expand_preparsed_asm( match args.named_args.get(&Symbol::intern(name)) { Some(&idx) => Some(idx), None => { - let msg = format!("there is no argument named `{name}`"); let span = arg.position_span; ecx.dcx() - .struct_span_err( - template_span + .create_err(errors::AsmNoMatchedArgumentName { + name: name.to_owned(), + span: template_span .from_inner(InnerSpan::new(span.start, span.end)), - msg, - ) + }) .emit(); None } diff --git a/compiler/rustc_builtin_macros/src/cfg_eval.rs b/compiler/rustc_builtin_macros/src/cfg_eval.rs index 884cebf1939..b09975c0ba7 100644 --- a/compiler/rustc_builtin_macros/src/cfg_eval.rs +++ b/compiler/rustc_builtin_macros/src/cfg_eval.rs @@ -193,7 +193,7 @@ impl CfgEval<'_> { // Re-parse the tokens, setting the `capture_cfg` flag to save extra information // to the captured `AttrTokenStream` (specifically, we capture - // `AttrTokenTree::AttributesData` for all occurrences of `#[cfg]` and `#[cfg_attr]`) + // `AttrTokenTree::AttrsTarget` for all occurrences of `#[cfg]` and `#[cfg_attr]`) let mut parser = Parser::new(&self.0.sess.psess, orig_tokens, None); parser.capture_cfg = true; match parse_annotatable_with(&mut parser) { diff --git a/compiler/rustc_builtin_macros/src/deriving/default.rs b/compiler/rustc_builtin_macros/src/deriving/default.rs index 577523a1d5a..7a65ed97f00 100644 --- a/compiler/rustc_builtin_macros/src/deriving/default.rs +++ b/compiler/rustc_builtin_macros/src/deriving/default.rs @@ -240,7 +240,7 @@ fn has_a_default_variant(item: &Annotatable) -> bool { if v.attrs.iter().any(|attr| attr.has_name(kw::Default)) { ControlFlow::Break(()) } else { - // no need to subrecurse. + // no need to walk the variant, we are only looking for top level variants ControlFlow::Continue(()) } } diff --git a/compiler/rustc_builtin_macros/src/deriving/smart_ptr.rs b/compiler/rustc_builtin_macros/src/deriving/smart_ptr.rs index ea054a7e355..bbc7cd39627 100644 --- a/compiler/rustc_builtin_macros/src/deriving/smart_ptr.rs +++ b/compiler/rustc_builtin_macros/src/deriving/smart_ptr.rs @@ -3,8 +3,9 @@ use std::mem::swap; use ast::HasAttrs; use rustc_ast::{ self as ast, GenericArg, GenericBound, GenericParamKind, ItemKind, MetaItem, - TraitBoundModifiers, + TraitBoundModifiers, VariantData, }; +use rustc_attr as attr; use rustc_expand::base::{Annotatable, ExtCtxt}; use rustc_span::symbol::{sym, Ident}; use rustc_span::Span; @@ -24,11 +25,43 @@ pub fn expand_deriving_smart_ptr( _is_const: bool, ) { let (name_ident, generics) = if let Annotatable::Item(aitem) = item - && let ItemKind::Struct(_, g) = &aitem.kind + && let ItemKind::Struct(struct_data, g) = &aitem.kind { + let is_transparent = aitem.attrs.iter().any(|attr| { + attr::find_repr_attrs(cx.sess, attr) + .into_iter() + .any(|r| matches!(r, attr::ReprTransparent)) + }); + if !is_transparent { + cx.dcx() + .struct_span_err( + span, + "`SmartPointer` can only be derived on `struct`s with `#[repr(transparent)]`", + ) + .emit(); + return; + } + if !matches!( + struct_data, + VariantData::Struct { fields, recovered: _ } | VariantData::Tuple(fields, _) + if !fields.is_empty()) + { + cx.dcx() + .struct_span_err( + span, + "`SmartPointer` can only be derived on `struct`s with at least one field", + ) + .emit(); + return; + } (aitem.ident, g) } else { - cx.dcx().struct_span_err(span, "`SmartPointer` can only be derived on `struct`s").emit(); + cx.dcx() + .struct_span_err( + span, + "`SmartPointer` can only be derived on `struct`s with `#[repr(transparent)]`", + ) + .emit(); return; }; diff --git a/compiler/rustc_builtin_macros/src/errors.rs b/compiler/rustc_builtin_macros/src/errors.rs index ed2f98f2a39..49d640436c2 100644 --- a/compiler/rustc_builtin_macros/src/errors.rs +++ b/compiler/rustc_builtin_macros/src/errors.rs @@ -729,6 +729,14 @@ pub(crate) struct AsmExpectedComma { } #[derive(Diagnostic)] +#[diag(builtin_macros_asm_expected_string_literal)] +pub(crate) struct AsmExpectedStringLiteral { + #[primary_span] + #[label] + pub(crate) span: Span, +} + +#[derive(Diagnostic)] #[diag(builtin_macros_asm_underscore_input)] pub(crate) struct AsmUnderscoreInput { #[primary_span] @@ -782,6 +790,14 @@ pub(crate) struct AsmNoReturn { } #[derive(Diagnostic)] +#[diag(builtin_macros_asm_no_matched_argument_name)] +pub(crate) struct AsmNoMatchedArgumentName { + pub(crate) name: String, + #[primary_span] + pub(crate) span: Span, +} + +#[derive(Diagnostic)] #[diag(builtin_macros_asm_mayunwind)] pub(crate) struct AsmMayUnwind { #[primary_span] @@ -872,3 +888,27 @@ pub(crate) struct TakesNoArguments<'a> { pub span: Span, pub name: &'a str, } + +#[derive(Diagnostic)] +#[diag(builtin_macros_proc_macro_attribute_only_be_used_on_bare_functions)] +pub(crate) struct AttributeOnlyBeUsedOnBareFunctions<'a> { + #[primary_span] + pub span: Span, + pub path: &'a str, +} + +#[derive(Diagnostic)] +#[diag(builtin_macros_proc_macro_attribute_only_usable_with_crate_type)] +pub(crate) struct AttributeOnlyUsableWithCrateType<'a> { + #[primary_span] + pub span: Span, + pub path: &'a str, +} + +#[derive(Diagnostic)] +#[diag(builtin_macros_source_uitls_expected_item)] +pub(crate) struct ExpectedItem<'a> { + #[primary_span] + pub span: Span, + pub token: &'a str, +} diff --git a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs index 99d0191958d..a8a595ea579 100644 --- a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs +++ b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs @@ -214,12 +214,12 @@ impl<'a> Visitor<'a> for CollectProcMacros<'a> { }; if !is_fn { - let msg = format!( - "the `#[{}]` attribute may only be used on bare functions", - pprust::path_to_string(&attr.get_normal_item().path), - ); - - self.dcx.span_err(attr.span, msg); + self.dcx + .create_err(errors::AttributeOnlyBeUsedOnBareFunctions { + span: attr.span, + path: &pprust::path_to_string(&attr.get_normal_item().path), + }) + .emit(); return; } @@ -228,12 +228,12 @@ impl<'a> Visitor<'a> for CollectProcMacros<'a> { } if !self.is_proc_macro_crate { - let msg = format!( - "the `#[{}]` attribute is only usable with crates of the `proc-macro` crate type", - pprust::path_to_string(&attr.get_normal_item().path), - ); - - self.dcx.span_err(attr.span, msg); + self.dcx + .create_err(errors::AttributeOnlyUsableWithCrateType { + span: attr.span, + path: &pprust::path_to_string(&attr.get_normal_item().path), + }) + .emit(); return; } diff --git a/compiler/rustc_builtin_macros/src/source_util.rs b/compiler/rustc_builtin_macros/src/source_util.rs index dc1d82df0c3..44db12cf695 100644 --- a/compiler/rustc_builtin_macros/src/source_util.rs +++ b/compiler/rustc_builtin_macros/src/source_util.rs @@ -1,3 +1,4 @@ +use crate::errors; use crate::util::{ check_zero_tts, get_single_str_from_tts, get_single_str_spanned_from_tts, parse_expr, }; @@ -165,9 +166,13 @@ pub(crate) fn expand_include<'cx>( Ok(Some(item)) => ret.push(item), Ok(None) => { if self.p.token != token::Eof { - let token = pprust::token_to_string(&self.p.token); - let msg = format!("expected item, found `{token}`"); - self.p.dcx().span_err(self.p.token.span, msg); + self.p + .dcx() + .create_err(errors::ExpectedItem { + span: self.p.token.span, + token: &pprust::token_to_string(&self.p.token), + }) + .emit(); } break; diff --git a/compiler/rustc_codegen_cranelift/src/constant.rs b/compiler/rustc_codegen_cranelift/src/constant.rs index 87c5da3b7c3..9f7b95261d5 100644 --- a/compiler/rustc_codegen_cranelift/src/constant.rs +++ b/compiler/rustc_codegen_cranelift/src/constant.rs @@ -155,7 +155,7 @@ pub(crate) fn codegen_const_value<'tcx>( fx.bcx.ins().global_value(fx.pointer_type, local_data_id) } } - GlobalAlloc::Function(instance) => { + GlobalAlloc::Function { instance, .. } => { let func_id = crate::abi::import_function(fx.tcx, fx.module, instance); let local_func_id = fx.module.declare_func_in_func(func_id, &mut fx.bcx.func); @@ -351,7 +351,9 @@ fn define_all_allocs(tcx: TyCtxt<'_>, module: &mut dyn Module, cx: &mut Constant TodoItem::Alloc(alloc_id) => { let alloc = match tcx.global_alloc(alloc_id) { GlobalAlloc::Memory(alloc) => alloc, - GlobalAlloc::Function(_) | GlobalAlloc::Static(_) | GlobalAlloc::VTable(..) => { + GlobalAlloc::Function { .. } + | GlobalAlloc::Static(_) + | GlobalAlloc::VTable(..) => { unreachable!() } }; @@ -415,7 +417,7 @@ fn define_all_allocs(tcx: TyCtxt<'_>, module: &mut dyn Module, cx: &mut Constant let reloc_target_alloc = tcx.global_alloc(alloc_id); let data_id = match reloc_target_alloc { - GlobalAlloc::Function(instance) => { + GlobalAlloc::Function { instance, .. } => { assert_eq!(addend, 0); let func_id = crate::abi::import_function(tcx, module, instance.polymorphize(tcx)); diff --git a/compiler/rustc_codegen_gcc/src/common.rs b/compiler/rustc_codegen_gcc/src/common.rs index 230fe4f5871..fa8a1ec037c 100644 --- a/compiler/rustc_codegen_gcc/src/common.rs +++ b/compiler/rustc_codegen_gcc/src/common.rs @@ -220,7 +220,7 @@ impl<'gcc, 'tcx> ConstMethods<'tcx> for CodegenCx<'gcc, 'tcx> { } value } - GlobalAlloc::Function(fn_instance) => self.get_fn_addr(fn_instance), + GlobalAlloc::Function { instance, .. } => self.get_fn_addr(instance), GlobalAlloc::VTable(ty, trait_ref) => { let alloc = self .tcx diff --git a/compiler/rustc_codegen_llvm/src/common.rs b/compiler/rustc_codegen_llvm/src/common.rs index d42c6ed827a..fe64649cf70 100644 --- a/compiler/rustc_codegen_llvm/src/common.rs +++ b/compiler/rustc_codegen_llvm/src/common.rs @@ -289,8 +289,8 @@ impl<'ll, 'tcx> ConstMethods<'tcx> for CodegenCx<'ll, 'tcx> { (value, AddressSpace::DATA) } } - GlobalAlloc::Function(fn_instance) => ( - self.get_fn_addr(fn_instance.polymorphize(self.tcx)), + GlobalAlloc::Function { instance, .. } => ( + self.get_fn_addr(instance.polymorphize(self.tcx)), self.data_layout().instruction_address_space, ), GlobalAlloc::VTable(ty, trait_ref) => { diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index b5b0086f740..e02c61cd296 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -1121,8 +1121,8 @@ fn generic_simd_intrinsic<'ll, 'tcx>( if name == sym::simd_select_bitmask { let (len, _) = require_simd!(arg_tys[1], SimdArgument); - let expected_int_bits = (len.max(8) - 1).next_power_of_two(); - let expected_bytes = len / 8 + ((len % 8 > 0) as u64); + let expected_int_bits = len.max(8).next_power_of_two(); + let expected_bytes = len.div_ceil(8); let mask_ty = arg_tys[0]; let mask = match mask_ty.kind() { @@ -1379,17 +1379,16 @@ fn generic_simd_intrinsic<'ll, 'tcx>( } if name == sym::simd_bitmask { - // The `fn simd_bitmask(vector) -> unsigned integer` intrinsic takes a - // vector mask and returns the most significant bit (MSB) of each lane in the form - // of either: + // The `fn simd_bitmask(vector) -> unsigned integer` intrinsic takes a vector mask and + // returns one bit for each lane (which must all be `0` or `!0`) in the form of either: // * an unsigned integer // * an array of `u8` // If the vector has less than 8 lanes, a u8 is returned with zeroed trailing bits. // // The bit order of the result depends on the byte endianness, LSB-first for little // endian and MSB-first for big endian. - let expected_int_bits = in_len.max(8); - let expected_bytes = expected_int_bits / 8 + ((expected_int_bits % 8 > 0) as u64); + let expected_int_bits = in_len.max(8).next_power_of_two(); + let expected_bytes = in_len.div_ceil(8); // Integer vector <i{in_bitwidth} x in_len>: let (i_xn, in_elem_bitwidth) = match in_elem.kind() { @@ -1409,7 +1408,8 @@ fn generic_simd_intrinsic<'ll, 'tcx>( }), }; - // Shift the MSB to the right by "in_elem_bitwidth - 1" into the first bit position. + // LLVM doesn't always know the inputs are `0` or `!0`, so we shift here so it optimizes to + // `pmovmskb` and similar on x86. let shift_indices = vec![ bx.cx.const_int(bx.type_ix(in_elem_bitwidth), (in_elem_bitwidth - 1) as _); diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index 1d54da267ee..d86f1a7a34f 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -301,9 +301,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { } // The signed form of the intrinsic allows this. If we interpret the // difference as isize, we'll get the proper signed difference. If that - // seems *positive*, they were more than isize::MAX apart. + // seems *positive* or equal to isize::MIN, they were more than isize::MAX apart. let dist = val.to_target_isize(self)?; - if dist >= 0 { + if dist >= 0 || i128::from(dist) == self.pointer_size().signed_int_min() { throw_ub_custom!( fluent::const_eval_offset_from_underflow, name = intrinsic_name, diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs index 9d0c4908225..36fe8dfdd29 100644 --- a/compiler/rustc_const_eval/src/interpret/memory.rs +++ b/compiler/rustc_const_eval/src/interpret/memory.rs @@ -308,7 +308,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { let Some((alloc_kind, mut alloc)) = self.memory.alloc_map.remove(&alloc_id) else { // Deallocating global memory -- always an error return Err(match self.tcx.try_get_global_alloc(alloc_id) { - Some(GlobalAlloc::Function(..)) => { + Some(GlobalAlloc::Function { .. }) => { err_ub_custom!( fluent::const_eval_invalid_dealloc, alloc_id = alloc_id, @@ -555,7 +555,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // Memory of a constant or promoted or anonymous memory referenced by a static. (mem, None) } - Some(GlobalAlloc::Function(..)) => throw_ub!(DerefFunctionPointer(id)), + Some(GlobalAlloc::Function { .. }) => throw_ub!(DerefFunctionPointer(id)), Some(GlobalAlloc::VTable(..)) => throw_ub!(DerefVTablePointer(id)), None => throw_ub!(PointerUseAfterFree(id, CheckInAllocMsg::MemoryAccessTest)), Some(GlobalAlloc::Static(def_id)) => { @@ -828,7 +828,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { let alloc = alloc.inner(); (alloc.size(), alloc.align, AllocKind::LiveData) } - Some(GlobalAlloc::Function(_)) => bug!("We already checked function pointers above"), + Some(GlobalAlloc::Function { .. }) => { + bug!("We already checked function pointers above") + } Some(GlobalAlloc::VTable(..)) => { // No data to be accessed here. But vtables are pointer-aligned. return (Size::ZERO, self.tcx.data_layout.pointer_align.abi, AllocKind::VTable); @@ -865,7 +867,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { Some(FnVal::Other(*extra)) } else { match self.tcx.try_get_global_alloc(id) { - Some(GlobalAlloc::Function(instance)) => Some(FnVal::Instance(instance)), + Some(GlobalAlloc::Function { instance, .. }) => Some(FnVal::Instance(instance)), _ => None, } } @@ -1056,8 +1058,8 @@ impl<'a, 'tcx, M: Machine<'tcx>> std::fmt::Debug for DumpAllocs<'a, 'tcx, M> { alloc.inner(), )?; } - Some(GlobalAlloc::Function(func)) => { - write!(fmt, " (fn: {func})")?; + Some(GlobalAlloc::Function { instance, .. }) => { + write!(fmt, " (fn: {instance})")?; } Some(GlobalAlloc::VTable(ty, Some(trait_ref))) => { write!(fmt, " (vtable: impl {trait_ref} for {ty})")?; diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs index add48e1b186..7fea0617666 100644 --- a/compiler/rustc_const_eval/src/interpret/validity.rs +++ b/compiler/rustc_const_eval/src/interpret/validity.rs @@ -745,7 +745,7 @@ fn mutability<'tcx>(ecx: &InterpCx<'tcx, impl Machine<'tcx>>, alloc_id: AllocId) } } GlobalAlloc::Memory(alloc) => alloc.inner().mutability, - GlobalAlloc::Function(..) | GlobalAlloc::VTable(..) => { + GlobalAlloc::Function { .. } | GlobalAlloc::VTable(..) => { // These are immutable, we better don't allow mutable pointers here. Mutability::Not } diff --git a/compiler/rustc_error_codes/src/error_codes/E0502.md b/compiler/rustc_error_codes/src/error_codes/E0502.md index dc3ffdfddd9..85f38b9286f 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0502.md +++ b/compiler/rustc_error_codes/src/error_codes/E0502.md @@ -1,4 +1,5 @@ -A variable already borrowed as immutable was borrowed as mutable. +A variable already borrowed with a certain mutability (either mutable or +immutable) was borrowed again with a different mutability. Erroneous code example: @@ -13,7 +14,7 @@ fn foo(a: &mut i32) { ``` To fix this error, ensure that you don't have any other references to the -variable before trying to access it mutably: +variable before trying to access it with a different mutability: ``` fn bar(x: &mut i32) {} diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index 45118bcc58a..aa47ca16676 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -2273,9 +2273,26 @@ impl HumanEmitter { &normalize_whitespace(last_line), Style::NoStyle, ); - buffer.puts(*row_num, 0, &self.maybe_anonymized(line_num), Style::LineNumber); - buffer.puts(*row_num, max_line_num_len + 1, "+ ", Style::Addition); - buffer.append(*row_num, &normalize_whitespace(line_to_add), Style::NoStyle); + if !line_to_add.trim().is_empty() { + // Check if after the removal, the line is left with only whitespace. If so, we + // will not show an "addition" line, as removing the whole line is what the user + // would really want. + // For example, for the following: + // | + // 2 - .await + // 2 + (note the left over whitepsace) + // | + // We really want + // | + // 2 - .await + // | + // *row_num -= 1; + buffer.puts(*row_num, 0, &self.maybe_anonymized(line_num), Style::LineNumber); + buffer.puts(*row_num, max_line_num_len + 1, "+ ", Style::Addition); + buffer.append(*row_num, &normalize_whitespace(line_to_add), Style::NoStyle); + } else { + *row_num -= 1; + } } else { *row_num -= 2; } diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs index 56cbb54fcec..40e16b45115 100644 --- a/compiler/rustc_expand/src/config.rs +++ b/compiler/rustc_expand/src/config.rs @@ -172,7 +172,7 @@ impl<'a> StripUnconfigured<'a> { fn configure_tokens(&self, stream: &AttrTokenStream) -> AttrTokenStream { fn can_skip(stream: &AttrTokenStream) -> bool { stream.0.iter().all(|tree| match tree { - AttrTokenTree::Attributes(_) => false, + AttrTokenTree::AttrsTarget(_) => false, AttrTokenTree::Token(..) => true, AttrTokenTree::Delimited(.., inner) => can_skip(inner), }) @@ -185,22 +185,22 @@ impl<'a> StripUnconfigured<'a> { let trees: Vec<_> = stream .0 .iter() - .flat_map(|tree| match tree.clone() { - AttrTokenTree::Attributes(mut data) => { - data.attrs.flat_map_in_place(|attr| self.process_cfg_attr(&attr)); + .filter_map(|tree| match tree.clone() { + AttrTokenTree::AttrsTarget(mut target) => { + target.attrs.flat_map_in_place(|attr| self.process_cfg_attr(&attr)); - if self.in_cfg(&data.attrs) { - data.tokens = LazyAttrTokenStream::new( - self.configure_tokens(&data.tokens.to_attr_token_stream()), + if self.in_cfg(&target.attrs) { + target.tokens = LazyAttrTokenStream::new( + self.configure_tokens(&target.tokens.to_attr_token_stream()), ); - Some(AttrTokenTree::Attributes(data)).into_iter() + Some(AttrTokenTree::AttrsTarget(target)) } else { - None.into_iter() + None } } AttrTokenTree::Delimited(sp, spacing, delim, mut inner) => { inner = self.configure_tokens(&inner); - Some(AttrTokenTree::Delimited(sp, spacing, delim, inner)).into_iter() + Some(AttrTokenTree::Delimited(sp, spacing, delim, inner)) } AttrTokenTree::Token( Token { @@ -220,9 +220,7 @@ impl<'a> StripUnconfigured<'a> { ) => { panic!("Should be `AttrTokenTree::Delimited`, not delim tokens: {:?}", tree); } - AttrTokenTree::Token(token, spacing) => { - Some(AttrTokenTree::Token(token, spacing)).into_iter() - } + AttrTokenTree::Token(token, spacing) => Some(AttrTokenTree::Token(token, spacing)), }) .collect(); AttrTokenStream::new(trees) @@ -294,7 +292,7 @@ impl<'a> StripUnconfigured<'a> { attr: &Attribute, (item, item_span): (ast::AttrItem, Span), ) -> Attribute { - let orig_tokens = attr.tokens(); + let orig_tokens = attr.get_tokens(); // We are taking an attribute of the form `#[cfg_attr(pred, attr)]` // and producing an attribute of the form `#[attr]`. We @@ -310,12 +308,11 @@ impl<'a> StripUnconfigured<'a> { else { panic!("Bad tokens for attribute {attr:?}"); }; - let pound_span = pound_token.span; // We don't really have a good span to use for the synthesized `[]` // in `#[attr]`, so just use the span of the `#` token. let bracket_group = AttrTokenTree::Delimited( - DelimSpan::from_single(pound_span), + DelimSpan::from_single(pound_token.span), DelimSpacing::new(Spacing::JointHidden, Spacing::Alone), Delimiter::Bracket, item.tokens diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index ad6f7da8937..c05cac155b7 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -575,6 +575,8 @@ declare_features! ( (unstable, raw_ref_op, "1.41.0", Some(64490)), /// Makes `&` and `&mut` patterns eat only one layer of references in Rust 2024. (incomplete, ref_pat_eat_one_layer_2024, "1.79.0", Some(123076)), + /// Makes `&` and `&mut` patterns eat only one layer of references in Rust 2024—structural variant + (incomplete, ref_pat_eat_one_layer_2024_structural, "CURRENT_RUSTC_VERSION", Some(123076)), /// Allows using the `#[register_tool]` attribute. (unstable, register_tool, "1.41.0", Some(66079)), /// Allows the `#[repr(i128)]` attribute for enums. diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl index 064d9c077b0..91b1506d1e4 100644 --- a/compiler/rustc_hir_analysis/messages.ftl +++ b/compiler/rustc_hir_analysis/messages.ftl @@ -55,8 +55,6 @@ hir_analysis_cannot_capture_late_bound_ty = cannot capture late-bound type parameter in {$what} .label = parameter defined here -hir_analysis_cast_thin_pointer_to_fat_pointer = cannot cast thin pointer `{$expr_ty}` to fat pointer `{$cast_ty}` - hir_analysis_closure_implicit_hrtb = implicit types in closure signatures are forbidden when `for<...>` is present .label = `for<...>` is here 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 b5b68471b9d..8a1ee9374c3 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -21,6 +21,7 @@ use rustc_middle::ty::{ use rustc_middle::ty::{GenericParamDefKind, TyCtxt}; use rustc_middle::{bug, span_bug}; use rustc_span::Span; +use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::regions::InferCtxtRegionExt; use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt; use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _; @@ -981,7 +982,7 @@ fn report_trait_method_mismatch<'tcx>( .next() .unwrap_or(impl_err_span); - diag.span_suggestion( + diag.span_suggestion_verbose( span, "change the self-receiver type to match the trait", sugg, @@ -1005,12 +1006,12 @@ fn report_trait_method_mismatch<'tcx>( } hir::FnRetTy::Return(hir_ty) => { let sugg = trait_sig.output(); - diag.span_suggestion(hir_ty.span, msg, sugg, ap); + diag.span_suggestion_verbose(hir_ty.span, msg, sugg, ap); } }; }; } else if let Some(trait_ty) = trait_sig.inputs().get(*i) { - diag.span_suggestion( + diag.span_suggestion_verbose( impl_err_span, "change the parameter type to match the trait", trait_ty, diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 2230528a5ae..30ff272ce12 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -39,6 +39,7 @@ use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _ use rustc_trait_selection::traits::{ self, FulfillmentError, ObligationCause, ObligationCauseCode, ObligationCtxt, WellFormedLoc, }; +use rustc_type_ir::solve::NoSolution; use rustc_type_ir::TypeFlags; use std::cell::LazyCell; @@ -1712,13 +1713,12 @@ fn receiver_is_valid<'tcx>( let cause = ObligationCause::new(span, wfcx.body_def_id, traits::ObligationCauseCode::MethodReceiver); - let can_eq_self = |ty| infcx.can_eq(wfcx.param_env, self_ty, ty); - - // `self: Self` is always valid. - if can_eq_self(receiver_ty) { - if let Err(err) = wfcx.eq(&cause, wfcx.param_env, self_ty, receiver_ty) { - infcx.err_ctxt().report_mismatched_types(&cause, self_ty, receiver_ty, err).emit(); - } + // Special case `receiver == self_ty`, which doesn't necessarily require the `Receiver` lang item. + if let Ok(()) = wfcx.infcx.commit_if_ok(|_| { + let ocx = ObligationCtxt::new(wfcx.infcx); + ocx.eq(&cause, wfcx.param_env, self_ty, receiver_ty)?; + if ocx.select_all_or_error().is_empty() { Ok(()) } else { Err(NoSolution) } + }) { return true; } @@ -1729,58 +1729,51 @@ fn receiver_is_valid<'tcx>( autoderef = autoderef.include_raw_pointers(); } - // The first type is `receiver_ty`, which we know its not equal to `self_ty`; skip it. - autoderef.next(); - let receiver_trait_def_id = tcx.require_lang_item(LangItem::Receiver, Some(span)); // Keep dereferencing `receiver_ty` until we get to `self_ty`. - loop { - if let Some((potential_self_ty, _)) = autoderef.next() { - debug!( - "receiver_is_valid: potential self type `{:?}` to match `{:?}`", - potential_self_ty, self_ty - ); - - if can_eq_self(potential_self_ty) { - wfcx.register_obligations(autoderef.into_obligations()); + while let Some((potential_self_ty, _)) = autoderef.next() { + debug!( + "receiver_is_valid: potential self type `{:?}` to match `{:?}`", + potential_self_ty, self_ty + ); - if let Err(err) = wfcx.eq(&cause, wfcx.param_env, self_ty, potential_self_ty) { - infcx - .err_ctxt() - .report_mismatched_types(&cause, self_ty, potential_self_ty, err) - .emit(); - } + // Check if the self type unifies. If it does, then commit the result + // since it may have region side-effects. + if let Ok(()) = wfcx.infcx.commit_if_ok(|_| { + let ocx = ObligationCtxt::new(wfcx.infcx); + ocx.eq(&cause, wfcx.param_env, self_ty, potential_self_ty)?; + if ocx.select_all_or_error().is_empty() { Ok(()) } else { Err(NoSolution) } + }) { + wfcx.register_obligations(autoderef.into_obligations()); + return true; + } + // Without `feature(arbitrary_self_types)`, we require that each step in the + // deref chain implement `receiver`. + if !arbitrary_self_types_enabled { + if !receiver_is_implemented( + wfcx, + receiver_trait_def_id, + cause.clone(), + potential_self_ty, + ) { + // We cannot proceed. break; - } else { - // Without `feature(arbitrary_self_types)`, we require that each step in the - // deref chain implement `receiver` - if !arbitrary_self_types_enabled - && !receiver_is_implemented( - wfcx, - receiver_trait_def_id, - cause.clone(), - potential_self_ty, - ) - { - return false; - } } - } else { - debug!("receiver_is_valid: type `{:?}` does not deref to `{:?}`", receiver_ty, self_ty); - return false; - } - } - // Without `feature(arbitrary_self_types)`, we require that `receiver_ty` implements `Receiver`. - if !arbitrary_self_types_enabled - && !receiver_is_implemented(wfcx, receiver_trait_def_id, cause.clone(), receiver_ty) - { - return false; + // Register the bound, in case it has any region side-effects. + wfcx.register_bound( + cause.clone(), + wfcx.param_env, + potential_self_ty, + receiver_trait_def_id, + ); + } } - true + debug!("receiver_is_valid: type `{:?}` does not deref to `{:?}`", receiver_ty, self_ty); + false } fn receiver_is_implemented<'tcx>( diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs index 9b02c1a61fa..22d465c8e62 100644 --- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs @@ -1,3 +1,5 @@ +use std::ops::ControlFlow; + use crate::middle::resolve_bound_vars as rbv; use hir::{ intravisit::{self, Visitor}, @@ -87,14 +89,9 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { let mut in_param_ty = false; for (_parent, node) in tcx.hir().parent_iter(hir_id) { if let Some(generics) = node.generics() { - let mut visitor = AnonConstInParamTyDetector { - in_param_ty: false, - found_anon_const_in_param_ty: false, - ct: hir_id, - }; + let mut visitor = AnonConstInParamTyDetector { in_param_ty: false, ct: hir_id }; - visitor.visit_generics(generics); - in_param_ty = visitor.found_anon_const_in_param_ty; + in_param_ty = visitor.visit_generics(generics).is_break(); break; } } @@ -460,50 +457,45 @@ fn has_late_bound_regions<'tcx>(tcx: TyCtxt<'tcx>, node: Node<'tcx>) -> Option<S struct LateBoundRegionsDetector<'tcx> { tcx: TyCtxt<'tcx>, outer_index: ty::DebruijnIndex, - has_late_bound_regions: Option<Span>, } impl<'tcx> Visitor<'tcx> for LateBoundRegionsDetector<'tcx> { - fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) { - if self.has_late_bound_regions.is_some() { - return; - } + type Result = ControlFlow<Span>; + fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) -> ControlFlow<Span> { match ty.kind { hir::TyKind::BareFn(..) => { self.outer_index.shift_in(1); - intravisit::walk_ty(self, ty); + let res = intravisit::walk_ty(self, ty); self.outer_index.shift_out(1); + res } _ => intravisit::walk_ty(self, ty), } } - fn visit_poly_trait_ref(&mut self, tr: &'tcx hir::PolyTraitRef<'tcx>) { - if self.has_late_bound_regions.is_some() { - return; - } + fn visit_poly_trait_ref(&mut self, tr: &'tcx hir::PolyTraitRef<'tcx>) -> ControlFlow<Span> { self.outer_index.shift_in(1); - intravisit::walk_poly_trait_ref(self, tr); + let res = intravisit::walk_poly_trait_ref(self, tr); self.outer_index.shift_out(1); + res } - fn visit_lifetime(&mut self, lt: &'tcx hir::Lifetime) { - if self.has_late_bound_regions.is_some() { - return; - } - + fn visit_lifetime(&mut self, lt: &'tcx hir::Lifetime) -> ControlFlow<Span> { match self.tcx.named_bound_var(lt.hir_id) { - Some(rbv::ResolvedArg::StaticLifetime | rbv::ResolvedArg::EarlyBound(..)) => {} + Some(rbv::ResolvedArg::StaticLifetime | rbv::ResolvedArg::EarlyBound(..)) => { + ControlFlow::Continue(()) + } Some(rbv::ResolvedArg::LateBound(debruijn, _, _)) - if debruijn < self.outer_index => {} + if debruijn < self.outer_index => + { + ControlFlow::Continue(()) + } Some( rbv::ResolvedArg::LateBound(..) | rbv::ResolvedArg::Free(..) | rbv::ResolvedArg::Error(_), ) - | None => { - self.has_late_bound_regions = Some(lt.ident.span); - } + | None => ControlFlow::Break(lt.ident.span), } } } @@ -513,11 +505,7 @@ fn has_late_bound_regions<'tcx>(tcx: TyCtxt<'tcx>, node: Node<'tcx>) -> Option<S generics: &'tcx hir::Generics<'tcx>, decl: &'tcx hir::FnDecl<'tcx>, ) -> Option<Span> { - let mut visitor = LateBoundRegionsDetector { - tcx, - outer_index: ty::INNERMOST, - has_late_bound_regions: None, - }; + let mut visitor = LateBoundRegionsDetector { tcx, outer_index: ty::INNERMOST }; for param in generics.params { if let GenericParamKind::Lifetime { .. } = param.kind { if tcx.is_late_bound(param.hir_id) { @@ -525,8 +513,7 @@ fn has_late_bound_regions<'tcx>(tcx: TyCtxt<'tcx>, node: Node<'tcx>) -> Option<S } } } - visitor.visit_fn_decl(decl); - visitor.has_late_bound_regions + visitor.visit_fn_decl(decl).break_value() } let decl = node.fn_decl()?; @@ -536,26 +523,29 @@ fn has_late_bound_regions<'tcx>(tcx: TyCtxt<'tcx>, node: Node<'tcx>) -> Option<S struct AnonConstInParamTyDetector { in_param_ty: bool, - found_anon_const_in_param_ty: bool, ct: HirId, } impl<'v> Visitor<'v> for AnonConstInParamTyDetector { - fn visit_generic_param(&mut self, p: &'v hir::GenericParam<'v>) { + type Result = ControlFlow<()>; + + fn visit_generic_param(&mut self, p: &'v hir::GenericParam<'v>) -> Self::Result { if let GenericParamKind::Const { ty, default: _, is_host_effect: _, synthetic: _ } = p.kind { let prev = self.in_param_ty; self.in_param_ty = true; - self.visit_ty(ty); + let res = self.visit_ty(ty); self.in_param_ty = prev; + res + } else { + ControlFlow::Continue(()) } } - fn visit_anon_const(&mut self, c: &'v hir::AnonConst) { + fn visit_anon_const(&mut self, c: &'v hir::AnonConst) -> Self::Result { if self.in_param_ty && self.ct == c.hir_id { - self.found_anon_const_in_param_ty = true; - } else { - intravisit::walk_anon_const(self, c) + return ControlFlow::Break(()); } + intravisit::walk_anon_const(self, c) } } diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index 3ffb51fa992..7d44ac458de 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -453,12 +453,11 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for MissingTypeParams { } else { // The user wrote `Iterator`, so we don't have a type we can suggest, but at // least we can clue them to the correct syntax `Iterator<Type>`. - err.span_suggestion( - self.span, + err.span_suggestion_verbose( + self.span.shrink_to_hi(), fluent::hir_analysis_suggestion, format!( - "{}<{}>", - snippet, + "<{}>", self.missing_type_params .iter() .map(|n| n.to_string()) @@ -708,15 +707,6 @@ pub(crate) struct PassToVariadicFunction<'tcx, 'a> { } #[derive(Diagnostic)] -#[diag(hir_analysis_cast_thin_pointer_to_fat_pointer, code = E0607)] -pub(crate) struct CastThinPointerToFatPointer<'tcx> { - #[primary_span] - pub span: Span, - pub expr_ty: Ty<'tcx>, - pub cast_ty: String, -} - -#[derive(Diagnostic)] #[diag(hir_analysis_invalid_union_field, code = E0740)] pub(crate) struct InvalidUnionField { #[primary_span] diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index 2a68d3915bb..02db0352daa 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -49,6 +49,7 @@ use rustc_span::edit_distance::find_best_match_for_name; use rustc_span::symbol::{kw, Ident, Symbol}; use rustc_span::{sym, Span, DUMMY_SP}; use rustc_target::spec::abi; +use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::traits::wf::object_region_bounds; use rustc_trait_selection::traits::{self, ObligationCtxt}; diff --git a/compiler/rustc_hir_analysis/src/outlives/utils.rs b/compiler/rustc_hir_analysis/src/outlives/utils.rs index 5086c2af3f6..08015c28a26 100644 --- a/compiler/rustc_hir_analysis/src/outlives/utils.rs +++ b/compiler/rustc_hir_analysis/src/outlives/utils.rs @@ -1,9 +1,9 @@ use rustc_data_structures::fx::FxIndexMap; -use rustc_infer::infer::outlives::components::{push_outlives_components, Component}; use rustc_middle::ty::{self, Region, Ty, TyCtxt}; use rustc_middle::ty::{GenericArg, GenericArgKind}; use rustc_middle::{bug, span_bug}; use rustc_span::Span; +use rustc_type_ir::outlives::{push_outlives_components, Component}; use smallvec::smallvec; /// Tracks the `T: 'a` or `'a: 'a` predicates that we have inferred diff --git a/compiler/rustc_hir_analysis/src/structured_errors.rs b/compiler/rustc_hir_analysis/src/structured_errors.rs index 5abfd25dd95..61a2400f9e4 100644 --- a/compiler/rustc_hir_analysis/src/structured_errors.rs +++ b/compiler/rustc_hir_analysis/src/structured_errors.rs @@ -1,10 +1,7 @@ mod missing_cast_for_variadic_arg; -mod sized_unsized_cast; mod wrong_number_of_generic_args; -pub use self::{ - missing_cast_for_variadic_arg::*, sized_unsized_cast::*, wrong_number_of_generic_args::*, -}; +pub use self::{missing_cast_for_variadic_arg::*, wrong_number_of_generic_args::*}; use rustc_errors::{Diag, ErrCode}; use rustc_session::Session; diff --git a/compiler/rustc_hir_analysis/src/structured_errors/sized_unsized_cast.rs b/compiler/rustc_hir_analysis/src/structured_errors/sized_unsized_cast.rs deleted file mode 100644 index 9e871ff9af0..00000000000 --- a/compiler/rustc_hir_analysis/src/structured_errors/sized_unsized_cast.rs +++ /dev/null @@ -1,56 +0,0 @@ -use crate::{errors, structured_errors::StructuredDiag}; -use rustc_errors::{codes::*, Diag}; -use rustc_middle::ty::{Ty, TypeVisitableExt}; -use rustc_session::Session; -use rustc_span::Span; - -pub struct SizedUnsizedCast<'tcx> { - pub sess: &'tcx Session, - pub span: Span, - pub expr_ty: Ty<'tcx>, - pub cast_ty: String, -} - -impl<'tcx> StructuredDiag<'tcx> for SizedUnsizedCast<'tcx> { - fn session(&self) -> &Session { - self.sess - } - - fn code(&self) -> ErrCode { - E0607 - } - - fn diagnostic_common(&self) -> Diag<'tcx> { - let mut err = self.sess.dcx().create_err(errors::CastThinPointerToFatPointer { - span: self.span, - expr_ty: self.expr_ty, - cast_ty: self.cast_ty.to_owned(), - }); - - if self.expr_ty.references_error() { - err.downgrade_to_delayed_bug(); - } - - err - } - - fn diagnostic_extended(&self, mut err: Diag<'tcx>) -> Diag<'tcx> { - err.help( - "Thin pointers are \"simple\" pointers: they are purely a reference to a -memory address. - -Fat pointers are pointers referencing \"Dynamically Sized Types\" (also -called DST). DST don't have a statically known size, therefore they can -only exist behind some kind of pointers that contain additional -information. Slices and trait objects are DSTs. In the case of slices, -the additional information the fat pointer holds is their size. - -To fix this error, don't try to cast directly between thin and fat -pointers. - -For more information about casts, take a look at The Book: -https://doc.rust-lang.org/reference/expressions/operator-expr.html#type-cast-expressions", - ); - err - } -} diff --git a/compiler/rustc_hir_typeck/messages.ftl b/compiler/rustc_hir_typeck/messages.ftl index d6f3f4d640b..3c5070bd006 100644 --- a/compiler/rustc_hir_typeck/messages.ftl +++ b/compiler/rustc_hir_typeck/messages.ftl @@ -23,6 +23,21 @@ hir_typeck_cannot_cast_to_bool = cannot cast `{$expr_ty}` as `bool` hir_typeck_cast_enum_drop = cannot cast enum `{$expr_ty}` into integer `{$cast_ty}` because it implements `Drop` +hir_typeck_cast_thin_pointer_to_fat_pointer = cannot cast thin pointer `{$expr_ty}` to fat pointer `{$cast_ty}` + .teach_help = Thin pointers are "simple" pointers: they are purely a reference to a + memory address. + + Fat pointers are pointers referencing "Dynamically Sized Types" (also + called DST). DST don't have a statically known size, therefore they can + only exist behind some kind of pointers that contain additional + information. Slices and trait objects are DSTs. In the case of slices, + the additional information the fat pointer holds is their size. + + To fix this error, don't try to cast directly between thin and fat + pointers. + + For more information about casts, take a look at The Book: + https://doc.rust-lang.org/reference/expressions/operator-expr.html#type-cast-expressions", hir_typeck_cast_unknown_pointer = cannot cast {$to -> [true] to *[false] from diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs index cb1a412d17e..53e44d6bcae 100644 --- a/compiler/rustc_hir_typeck/src/cast.rs +++ b/compiler/rustc_hir_typeck/src/cast.rs @@ -500,16 +500,12 @@ impl<'a, 'tcx> CastCheck<'tcx> { err.emit(); } CastError::SizedUnsizedCast => { - use rustc_hir_analysis::structured_errors::{SizedUnsizedCast, StructuredDiag}; - - SizedUnsizedCast { - sess: fcx.tcx.sess, + fcx.dcx().emit_err(errors::CastThinPointerToFatPointer { span: self.span, expr_ty: self.expr_ty, cast_ty: fcx.ty_to_string(self.cast_ty), - } - .diagnostic() - .emit(); + teach: fcx.tcx.sess.teach(E0607).then_some(()), + }); } CastError::IntToFatCast(known_metadata) => { let expr_if_nightly = fcx.tcx.sess.is_nightly_build().then_some(self.expr_span); diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs index ad9c1e28211..4f1c2fdd922 100644 --- a/compiler/rustc_hir_typeck/src/demand.rs +++ b/compiler/rustc_hir_typeck/src/demand.rs @@ -13,6 +13,7 @@ use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{self, AssocItem, Ty, TypeFoldable, TypeVisitableExt}; use rustc_span::symbol::sym; use rustc_span::{Span, DUMMY_SP}; +use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::traits::ObligationCause; use super::method::probe; diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs index 98add86252c..f1ed2ade3d4 100644 --- a/compiler/rustc_hir_typeck/src/errors.rs +++ b/compiler/rustc_hir_typeck/src/errors.rs @@ -501,6 +501,7 @@ pub enum SuggestBoxing { #[suggestion( hir_typeck_suggest_ptr_null_mut, applicability = "maybe-incorrect", + style = "verbose", code = "core::ptr::null_mut()" )] pub struct SuggestPtrNullMut { @@ -689,3 +690,14 @@ pub struct ReplaceWithName { pub span: Span, pub name: String, } + +#[derive(Diagnostic)] +#[diag(hir_typeck_cast_thin_pointer_to_fat_pointer, code = E0607)] +pub(crate) struct CastThinPointerToFatPointer<'tcx> { + #[primary_span] + pub span: Span, + pub expr_ty: Ty<'tcx>, + pub cast_ty: String, + #[note(hir_typeck_teach_help)] + pub(crate) teach: Option<()>, +} diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index f3aece4e1d8..bd5e5294983 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -2551,10 +2551,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { match *base_ty.peel_refs().kind() { ty::Array(_, len) => { - self.maybe_suggest_array_indexing(&mut err, expr, base, ident, len); + self.maybe_suggest_array_indexing(&mut err, base, ident, len); } ty::RawPtr(..) => { - self.suggest_first_deref_field(&mut err, expr, base, ident); + self.suggest_first_deref_field(&mut err, base, ident); } ty::Param(param_ty) => { err.span_label(ident.span, "unknown field"); @@ -2721,7 +2721,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn maybe_suggest_array_indexing( &self, err: &mut Diag<'_>, - expr: &hir::Expr<'_>, base: &hir::Expr<'_>, field: Ident, len: ty::Const<'tcx>, @@ -2729,32 +2728,41 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { err.span_label(field.span, "unknown field"); if let (Some(len), Ok(user_index)) = (len.try_eval_target_usize(self.tcx, self.param_env), field.as_str().parse::<u64>()) - && let Ok(base) = self.tcx.sess.source_map().span_to_snippet(base.span) { let help = "instead of using tuple indexing, use array indexing"; - let suggestion = format!("{base}[{field}]"); let applicability = if len < user_index { Applicability::MachineApplicable } else { Applicability::MaybeIncorrect }; - err.span_suggestion(expr.span, help, suggestion, applicability); + err.multipart_suggestion( + help, + vec![ + (base.span.between(field.span), "[".to_string()), + (field.span.shrink_to_hi(), "]".to_string()), + ], + applicability, + ); } } - fn suggest_first_deref_field( - &self, - err: &mut Diag<'_>, - expr: &hir::Expr<'_>, - base: &hir::Expr<'_>, - field: Ident, - ) { + fn suggest_first_deref_field(&self, err: &mut Diag<'_>, base: &hir::Expr<'_>, field: Ident) { err.span_label(field.span, "unknown field"); - if let Ok(base) = self.tcx.sess.source_map().span_to_snippet(base.span) { - let msg = format!("`{base}` is a raw pointer; try dereferencing it"); - let suggestion = format!("(*{base}).{field}"); - err.span_suggestion(expr.span, msg, suggestion, Applicability::MaybeIncorrect); - } + let val = if let Ok(base) = self.tcx.sess.source_map().span_to_snippet(base.span) + && base.len() < 20 + { + format!("`{base}`") + } else { + "the value".to_string() + }; + err.multipart_suggestion( + format!("{val} is a raw pointer; try dereferencing it"), + vec![ + (base.span.shrink_to_lo(), "(*".to_string()), + (base.span.shrink_to_hi(), ")".to_string()), + ], + Applicability::MaybeIncorrect, + ); } fn no_such_field_err(&self, field: Ident, expr_t: Ty<'tcx>, id: HirId) -> Diag<'_> { diff --git a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs index c8ab0429ffc..193dbbbcdf4 100644 --- a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs +++ b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs @@ -734,7 +734,9 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx // struct; however, when EUV is run during typeck, it // may not. This will generate an error earlier in typeck, // so we can just ignore it. - span_bug!(with_expr.span, "with expression doesn't evaluate to a struct"); + if self.cx.tainted_by_errors().is_ok() { + span_bug!(with_expr.span, "with expression doesn't evaluate to a struct"); + } } } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 56dff080867..10092dce587 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -40,6 +40,7 @@ use rustc_middle::{bug, span_bug}; use rustc_session::Session; use rustc_span::symbol::{kw, Ident}; use rustc_span::{sym, BytePos, Span, DUMMY_SP}; +use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::traits::{self, ObligationCauseCode, SelectionContext}; use std::iter; @@ -1384,7 +1385,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Some(format!("provide the argument{}", if plural { "s" } else { "" })) } SuggestionText::Remove(plural) => { - err.multipart_suggestion( + err.multipart_suggestion_verbose( format!("remove the extra argument{}", if plural { "s" } else { "" }), suggestions, Applicability::HasPlaceholders, diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs index fab7eb7495c..90dd5f73586 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs @@ -104,8 +104,6 @@ struct NestedObligationsForSelfTy<'a, 'tcx> { } impl<'a, 'tcx> ProofTreeVisitor<'tcx> for NestedObligationsForSelfTy<'a, 'tcx> { - type Result = (); - fn span(&self) -> Span { self.root_cause.span } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index 8d380caf916..fca0a3e195d 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -2582,7 +2582,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } (hir::ExprKind::AddrOf(hir::BorrowKind::Ref, _, expr), _, &ty::Ref(_, checked, _)) - if self.can_sub(self.param_env, checked, expected) => + if self.can_eq(self.param_env, checked, expected) => { let make_sugg = |start: Span, end: BytePos| { // skip `(` for tuples such as `(c) = (&123)`. diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index 63b30d79aba..6a7af5510e0 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -33,6 +33,7 @@ use rustc_span::edit_distance::{ }; use rustc_span::symbol::sym; use rustc_span::{symbol::Ident, Span, Symbol, DUMMY_SP}; +use rustc_trait_selection::infer::InferCtxtExt as _; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; use rustc_trait_selection::traits::query::method_autoderef::MethodAutoderefBadTy; use rustc_trait_selection::traits::query::method_autoderef::{ @@ -857,7 +858,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { let args = self.fresh_args_for_item(self.span, method.def_id); let fty = self.tcx.fn_sig(method.def_id).instantiate(self.tcx, args); let fty = self.instantiate_binder_with_fresh_vars(self.span, infer::FnCall, fty); - self.can_sub(self.param_env, fty.output(), expected) + self.can_eq(self.param_env, fty.output(), expected) }), _ => false, } diff --git a/compiler/rustc_hir_typeck/src/op.rs b/compiler/rustc_hir_typeck/src/op.rs index 5a11cb7096f..7264bc5a78d 100644 --- a/compiler/rustc_hir_typeck/src/op.rs +++ b/compiler/rustc_hir_typeck/src/op.rs @@ -838,8 +838,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }, ) = ex.kind { - err.span_suggestion( - ex.span, + let span = if let hir::Node::Expr(parent) = + self.tcx.parent_hir_node(ex.hir_id) + && let hir::ExprKind::Cast(..) = parent.kind + { + // `-1 as usize` -> `usize::MAX` + parent.span + } else { + ex.span + }; + err.span_suggestion_verbose( + span, format!( "you may have meant the maximum value of `{actual}`", ), diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index f932a27e9a2..be526e1c26c 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -19,6 +19,7 @@ use rustc_span::source_map::Spanned; use rustc_span::symbol::{kw, sym, Ident}; use rustc_span::{BytePos, Span, DUMMY_SP}; use rustc_target::abi::FieldIdx; +use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::traits::{ObligationCause, ObligationCauseCode}; use ty::VariantDef; @@ -328,8 +329,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { adjust_mode: AdjustMode, max_ref_mutbl: MutblCap, ) -> (Ty<'tcx>, ByRef, MutblCap) { - if let ByRef::Yes(Mutability::Mut) = def_br { - debug_assert!(max_ref_mutbl == MutblCap::Mut); + #[cfg(debug_assertions)] + if def_br == ByRef::Yes(Mutability::Mut) && max_ref_mutbl != MutblCap::Mut { + span_bug!(pat.span, "Pattern mutability cap violated!"); } match adjust_mode { AdjustMode::Pass => (expected, def_br, max_ref_mutbl), @@ -437,7 +439,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }); } - if self.tcx.features().ref_pat_eat_one_layer_2024 { + let features = self.tcx.features(); + if features.ref_pat_eat_one_layer_2024 || features.ref_pat_eat_one_layer_2024_structural { def_br = def_br.cap_ref_mutability(max_ref_mutbl.as_mutbl()); if def_br == ByRef::Yes(Mutability::Not) { max_ref_mutbl = MutblCap::Not; @@ -669,7 +672,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Determine the binding mode... let bm = match user_bind_annot { BindingMode(ByRef::No, Mutability::Mut) if matches!(def_br, ByRef::Yes(_)) => { - if pat.span.at_least_rust_2024() && self.tcx.features().ref_pat_eat_one_layer_2024 { + if pat.span.at_least_rust_2024() + && (self.tcx.features().ref_pat_eat_one_layer_2024 + || self.tcx.features().ref_pat_eat_one_layer_2024_structural) + { if !self.tcx.features().mut_ref { feature_err( &self.tcx.sess, @@ -2123,7 +2129,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { mut expected: Ty<'tcx>, mut pat_info: PatInfo<'tcx, '_>, ) -> Ty<'tcx> { - let no_ref_mut_behind_and = self.tcx.features().ref_pat_eat_one_layer_2024; + let tcx = self.tcx; + let features = tcx.features(); + let ref_pat_eat_one_layer_2024 = features.ref_pat_eat_one_layer_2024; + let ref_pat_eat_one_layer_2024_structural = features.ref_pat_eat_one_layer_2024_structural; + + let no_ref_mut_behind_and = + ref_pat_eat_one_layer_2024 || ref_pat_eat_one_layer_2024_structural; let new_match_ergonomics = pat.span.at_least_rust_2024() && no_ref_mut_behind_and; let pat_prefix_span = @@ -2138,32 +2150,49 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pat_info.max_ref_mutbl = MutblCap::Mut; } + expected = self.try_structurally_resolve_type(pat.span, expected); if new_match_ergonomics { if let ByRef::Yes(inh_mut) = pat_info.binding_mode { - // ref pattern consumes inherited reference - - if pat_mutbl > inh_mut { - // Tried to match inherited `ref` with `&mut`, which is an error - let err_msg = "cannot match inherited `&` with `&mut` pattern"; - let err = if let Some(span) = pat_prefix_span { - let mut err = self.dcx().struct_span_err(span, err_msg); - err.span_suggestion_verbose( - span, - "replace this `&mut` pattern with `&`", - "&", - Applicability::MachineApplicable, - ); - err + if !ref_pat_eat_one_layer_2024 && let ty::Ref(_, _, r_mutbl) = *expected.kind() { + // Don't attempt to consume inherited reference + pat_info.binding_mode = pat_info.binding_mode.cap_ref_mutability(r_mutbl); + } else { + // ref pattern attempts to consume inherited reference + if pat_mutbl > inh_mut { + // Tried to match inherited `ref` with `&mut` + if !ref_pat_eat_one_layer_2024_structural { + let err_msg = "mismatched types"; + let err = if let Some(span) = pat_prefix_span { + let mut err = self.dcx().struct_span_err(span, err_msg); + err.code(E0308); + err.note("cannot match inherited `&` with `&mut` pattern"); + err.span_suggestion_verbose( + span, + "replace this `&mut` pattern with `&`", + "&", + Applicability::MachineApplicable, + ); + err + } else { + self.dcx().struct_span_err(pat.span, err_msg) + }; + err.emit(); + + pat_info.binding_mode = ByRef::No; + self.typeck_results + .borrow_mut() + .skipped_ref_pats_mut() + .insert(pat.hir_id); + self.check_pat(inner, expected, pat_info); + return expected; + } } else { - self.dcx().struct_span_err(pat.span, err_msg) - }; - err.emit(); + pat_info.binding_mode = ByRef::No; + self.typeck_results.borrow_mut().skipped_ref_pats_mut().insert(pat.hir_id); + self.check_pat(inner, expected, pat_info); + return expected; + } } - - pat_info.binding_mode = ByRef::No; - self.typeck_results.borrow_mut().skipped_ref_pats_mut().insert(pat.hir_id); - self.check_pat(inner, expected, pat_info); - return expected; } } else { // Reset binding mode on old editions @@ -2178,8 +2207,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - let tcx = self.tcx; - expected = self.try_structurally_resolve_type(pat.span, expected); let (ref_ty, inner_ty) = match self.check_dereferenceable(pat.span, expected, inner) { Ok(()) => { // `demand::subtype` would be good enough, but using `eqtype` turns @@ -2191,7 +2218,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { debug!("check_pat_ref: expected={:?}", expected); match *expected.kind() { ty::Ref(_, r_ty, r_mutbl) - if (new_match_ergonomics && r_mutbl >= pat_mutbl) + if (no_ref_mut_behind_and && r_mutbl >= pat_mutbl) || r_mutbl == pat_mutbl => { if no_ref_mut_behind_and && r_mutbl == Mutability::Not { @@ -2499,7 +2526,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .any(|(ty, _)| matches!(ty.kind(), ty::Slice(..) | ty::Array(..))) && let Some(span) = ti.span && let Some(_) = ti.origin_expr - && let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) { let resolved_ty = self.resolve_vars_if_possible(ti.expected); let (is_slice_or_array_or_vector, resolved_ty) = @@ -2510,10 +2536,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { || self.tcx.is_diagnostic_item(sym::Result, adt_def.did()) => { // Slicing won't work here, but `.as_deref()` might (issue #91328). - err.span_suggestion( - span, + err.span_suggestion_verbose( + span.shrink_to_hi(), "consider using `as_deref` here", - format!("{snippet}.as_deref()"), + ".as_deref()", Applicability::MaybeIncorrect, ); } @@ -2522,10 +2548,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let is_top_level = current_depth <= 1; if is_slice_or_array_or_vector && is_top_level { - err.span_suggestion( - span, + err.span_suggestion_verbose( + span.shrink_to_hi(), "consider slicing here", - format!("{snippet}[..]"), + "[..]", Applicability::MachineApplicable, ); } diff --git a/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs b/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs index b6e9000ef95..c99e8a7fe8e 100644 --- a/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs +++ b/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs @@ -18,7 +18,7 @@ use rustc_trait_selection::traits::{ use std::cell::RefCell; use std::ops::Deref; -// Data shared between a "typeck root" and its nested bodies, +/// Data shared between a "typeck root" and its nested bodies, /// e.g. closures defined within the function. For example: /// ```ignore (illustrative) /// fn foo() { diff --git a/compiler/rustc_index/src/lib.rs b/compiler/rustc_index/src/lib.rs index db6b250467e..b775ae1f5e9 100644 --- a/compiler/rustc_index/src/lib.rs +++ b/compiler/rustc_index/src/lib.rs @@ -1,10 +1,7 @@ // tidy-alphabetical-start #![cfg_attr(all(feature = "nightly", test), feature(stmt_expr_attributes))] -#![cfg_attr( - feature = "nightly", - feature(extend_one, min_specialization, new_uninit, step_trait, test) -)] #![cfg_attr(feature = "nightly", allow(internal_features))] +#![cfg_attr(feature = "nightly", feature(extend_one, new_uninit, step_trait, test))] // tidy-alphabetical-end pub mod bit_set; diff --git a/compiler/rustc_index/src/vec.rs b/compiler/rustc_index/src/vec.rs index 88298150a79..b866c8b8433 100644 --- a/compiler/rustc_index/src/vec.rs +++ b/compiler/rustc_index/src/vec.rs @@ -208,6 +208,11 @@ impl<I: Idx, T> IndexVec<I, Option<T>> { pub fn remove(&mut self, index: I) -> Option<T> { self.get_mut(index)?.take() } + + #[inline] + pub fn contains(&self, index: I) -> bool { + self.get(index).and_then(Option::as_ref).is_some() + } } impl<I: Idx, T: fmt::Debug> fmt::Debug for IndexVec<I, T> { diff --git a/compiler/rustc_index_macros/src/lib.rs b/compiler/rustc_index_macros/src/lib.rs index 3e55dd82a6e..2b444932f85 100644 --- a/compiler/rustc_index_macros/src/lib.rs +++ b/compiler/rustc_index_macros/src/lib.rs @@ -34,10 +34,7 @@ mod newtype; /// optimizations. The default max value is 0xFFFF_FF00. /// - `#[gate_rustc_only]`: makes parts of the generated code nightly-only. #[proc_macro] -#[cfg_attr( - feature = "nightly", - allow_internal_unstable(step_trait, rustc_attrs, trusted_step, min_specialization) -)] +#[cfg_attr(feature = "nightly", allow_internal_unstable(step_trait, rustc_attrs, trusted_step))] pub fn newtype_index(input: TokenStream) -> TokenStream { newtype::newtype(input) } diff --git a/compiler/rustc_index_macros/src/newtype.rs b/compiler/rustc_index_macros/src/newtype.rs index 41863f7b15f..1ac2c44e9dc 100644 --- a/compiler/rustc_index_macros/src/newtype.rs +++ b/compiler/rustc_index_macros/src/newtype.rs @@ -139,10 +139,6 @@ impl Parse for Newtype { Self::index(start).checked_sub(u).map(Self::from_usize) } } - - // Safety: The implementation of `Step` upholds all invariants. - #gate_rustc_only - unsafe impl ::std::iter::TrustedStep for #name {} } } else { quote! {} diff --git a/compiler/rustc_infer/Cargo.toml b/compiler/rustc_infer/Cargo.toml index c1565a7d40f..1f616710200 100644 --- a/compiler/rustc_infer/Cargo.toml +++ b/compiler/rustc_infer/Cargo.toml @@ -16,8 +16,10 @@ rustc_hir = { path = "../rustc_hir" } rustc_index = { path = "../rustc_index" } rustc_macros = { path = "../rustc_macros" } rustc_middle = { path = "../rustc_middle" } +rustc_next_trait_solver = { path = "../rustc_next_trait_solver" } rustc_span = { path = "../rustc_span" } rustc_target = { path = "../rustc_target" } +rustc_type_ir = { path = "../rustc_type_ir" } smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } tracing = "0.1" # tidy-alphabetical-end diff --git a/compiler/rustc_infer/src/infer/context.rs b/compiler/rustc_infer/src/infer/context.rs new file mode 100644 index 00000000000..209996b12e2 --- /dev/null +++ b/compiler/rustc_infer/src/infer/context.rs @@ -0,0 +1,172 @@ +///! Definition of `InferCtxtLike` from the librarified type layer. +use rustc_hir::def_id::{DefId, LocalDefId}; +use rustc_middle::traits::solve::{Goal, NoSolution, SolverMode}; +use rustc_middle::traits::ObligationCause; +use rustc_middle::ty::fold::TypeFoldable; +use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_span::DUMMY_SP; +use rustc_type_ir::relate::Relate; +use rustc_type_ir::InferCtxtLike; + +use super::{BoundRegionConversionTime, InferCtxt, SubregionOrigin}; + +impl<'tcx> InferCtxtLike for InferCtxt<'tcx> { + type Interner = TyCtxt<'tcx>; + + fn cx(&self) -> TyCtxt<'tcx> { + self.tcx + } + + fn solver_mode(&self) -> ty::solve::SolverMode { + match self.intercrate { + true => SolverMode::Coherence, + false => SolverMode::Normal, + } + } + + fn universe(&self) -> ty::UniverseIndex { + self.universe() + } + + fn create_next_universe(&self) -> ty::UniverseIndex { + self.create_next_universe() + } + + fn universe_of_ty(&self, vid: ty::TyVid) -> Option<ty::UniverseIndex> { + match self.probe_ty_var(vid) { + Err(universe) => Some(universe), + Ok(_) => None, + } + } + + fn universe_of_lt(&self, lt: ty::RegionVid) -> Option<ty::UniverseIndex> { + match self.inner.borrow_mut().unwrap_region_constraints().probe_value(lt) { + Err(universe) => Some(universe), + Ok(_) => None, + } + } + + fn universe_of_ct(&self, ct: ty::ConstVid) -> Option<ty::UniverseIndex> { + match self.probe_const_var(ct) { + Err(universe) => Some(universe), + Ok(_) => None, + } + } + + fn root_ty_var(&self, var: ty::TyVid) -> ty::TyVid { + self.root_var(var) + } + + fn root_const_var(&self, var: ty::ConstVid) -> ty::ConstVid { + self.root_const_var(var) + } + + fn opportunistic_resolve_ty_var(&self, vid: ty::TyVid) -> Ty<'tcx> { + match self.probe_ty_var(vid) { + Ok(ty) => ty, + Err(_) => Ty::new_var(self.tcx, self.root_var(vid)), + } + } + + fn opportunistic_resolve_int_var(&self, vid: ty::IntVid) -> Ty<'tcx> { + self.opportunistic_resolve_int_var(vid) + } + + fn opportunistic_resolve_float_var(&self, vid: ty::FloatVid) -> Ty<'tcx> { + self.opportunistic_resolve_float_var(vid) + } + + fn opportunistic_resolve_ct_var(&self, vid: ty::ConstVid) -> ty::Const<'tcx> { + match self.probe_const_var(vid) { + Ok(ct) => ct, + Err(_) => ty::Const::new_var(self.tcx, self.root_const_var(vid)), + } + } + + fn opportunistic_resolve_effect_var(&self, vid: ty::EffectVid) -> ty::Const<'tcx> { + match self.probe_effect_var(vid) { + Some(ct) => ct, + None => { + ty::Const::new_infer(self.tcx, ty::InferConst::EffectVar(self.root_effect_var(vid))) + } + } + } + + fn opportunistic_resolve_lt_var(&self, vid: ty::RegionVid) -> ty::Region<'tcx> { + self.inner.borrow_mut().unwrap_region_constraints().opportunistic_resolve_var(self.tcx, vid) + } + + fn defining_opaque_types(&self) -> &'tcx ty::List<LocalDefId> { + self.defining_opaque_types() + } + + fn next_ty_infer(&self) -> Ty<'tcx> { + self.next_ty_var(DUMMY_SP) + } + + fn next_const_infer(&self) -> ty::Const<'tcx> { + self.next_const_var(DUMMY_SP) + } + + fn fresh_args_for_item(&self, def_id: DefId) -> ty::GenericArgsRef<'tcx> { + self.fresh_args_for_item(DUMMY_SP, def_id) + } + + fn instantiate_binder_with_infer<T: TypeFoldable<TyCtxt<'tcx>> + Copy>( + &self, + value: ty::Binder<'tcx, T>, + ) -> T { + self.instantiate_binder_with_fresh_vars( + DUMMY_SP, + BoundRegionConversionTime::HigherRankedType, + value, + ) + } + + fn enter_forall<T: TypeFoldable<TyCtxt<'tcx>> + Copy, U>( + &self, + value: ty::Binder<'tcx, T>, + f: impl FnOnce(T) -> U, + ) -> U { + self.enter_forall(value, f) + } + + fn relate<T: Relate<TyCtxt<'tcx>>>( + &self, + param_env: ty::ParamEnv<'tcx>, + lhs: T, + variance: ty::Variance, + rhs: T, + ) -> Result<Vec<Goal<'tcx, ty::Predicate<'tcx>>>, NoSolution> { + self.at(&ObligationCause::dummy(), param_env).relate_no_trace(lhs, variance, rhs) + } + + fn eq_structurally_relating_aliases<T: Relate<TyCtxt<'tcx>>>( + &self, + param_env: ty::ParamEnv<'tcx>, + lhs: T, + rhs: T, + ) -> Result<Vec<Goal<'tcx, ty::Predicate<'tcx>>>, NoSolution> { + self.at(&ObligationCause::dummy(), param_env) + .eq_structurally_relating_aliases_no_trace(lhs, rhs) + } + + fn resolve_vars_if_possible<T>(&self, value: T) -> T + where + T: TypeFoldable<TyCtxt<'tcx>>, + { + self.resolve_vars_if_possible(value) + } + + fn probe<T>(&self, probe: impl FnOnce() -> T) -> T { + self.probe(|_| probe()) + } + + fn sub_regions(&self, sub: ty::Region<'tcx>, sup: ty::Region<'tcx>) { + self.sub_regions(SubregionOrigin::RelateRegionParamBound(DUMMY_SP), sub, sup) + } + + fn register_ty_outlives(&self, ty: Ty<'tcx>, r: ty::Region<'tcx>) { + self.register_region_obligation_with_cause(ty, r, &ObligationCause::dummy()); + } +} diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index a8fd3ca8c59..cebb9d09a47 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -1168,14 +1168,16 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { let output1 = sig1.output(); let output2 = sig2.output(); let (x1, x2) = self.cmp(output1, output2); - if !output1.is_unit() { + let output_diff = x1 != x2; + if !output1.is_unit() || output_diff { values.0.push_normal(" -> "); (values.0).0.extend(x1.0); } - if !output2.is_unit() { + if !output2.is_unit() || output_diff { values.1.push_normal(" -> "); (values.1).0.extend(x2.0); } + values } diff --git a/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs b/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs index bc59b5e033b..d5e7de897d0 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs @@ -52,10 +52,10 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { ) = tcx.sess.source_map().span_to_snippet(sp) => { if snippet.chars().all(|c| c.is_digit(10) || c == '-' || c == '_') { - diag.span_suggestion( - sp, + diag.span_suggestion_verbose( + sp.shrink_to_hi(), "use a float literal", - format!("{snippet}.0"), + ".0", MachineApplicable, ); } @@ -820,7 +820,7 @@ fn foo(&self) -> Self::T { String::new() } tcx.defaultness(item.id.owner_id) { let assoc_ty = tcx.type_of(item.id.owner_id).instantiate_identity(); - if self.infcx.can_eq(param_env, assoc_ty, found) { + if self.infcx.can_eq_shallow(param_env, assoc_ty, found) { diag.span_label( item.span, "associated type defaults can't be assumed inside the \ @@ -843,7 +843,7 @@ fn foo(&self) -> Self::T { String::new() } let assoc_ty = tcx.type_of(item.id.owner_id).instantiate_identity(); if let hir::Defaultness::Default { has_value: true } = tcx.defaultness(item.id.owner_id) - && self.infcx.can_eq(param_env, assoc_ty, found) + && self.infcx.can_eq_shallow(param_env, assoc_ty, found) { diag.span_label( item.span, diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index ff593d7ffb7..9f55939c165 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -53,6 +53,7 @@ use type_variable::TypeVariableOrigin; pub mod at; pub mod canonical; +mod context; pub mod error_reporting; pub mod free_regions; mod freshen; @@ -767,19 +768,9 @@ impl<'tcx> InferCtxt<'tcx> { .collect() } - pub fn can_sub<T>(&self, param_env: ty::ParamEnv<'tcx>, expected: T, actual: T) -> bool - where - T: at::ToTrace<'tcx>, - { - let origin = &ObligationCause::dummy(); - self.probe(|_| { - // We're only answering whether there could be a subtyping relation, and with - // opaque types, "there could be one", via registering a hidden type. - self.at(origin, param_env).sub(DefineOpaqueTypes::Yes, expected, actual).is_ok() - }) - } - - pub fn can_eq<T>(&self, param_env: ty::ParamEnv<'tcx>, a: T, b: T) -> bool + // FIXME(-Znext-solver): Get rid of this method, it's never correct. Either that, + // or we need to process the obligations. + pub fn can_eq_shallow<T>(&self, param_env: ty::ParamEnv<'tcx>, a: T, b: T) -> bool where T: at::ToTrace<'tcx>, { diff --git a/compiler/rustc_infer/src/infer/outlives/components.rs b/compiler/rustc_infer/src/infer/outlives/components.rs deleted file mode 100644 index 6bab3ad6ba3..00000000000 --- a/compiler/rustc_infer/src/infer/outlives/components.rs +++ /dev/null @@ -1,266 +0,0 @@ -// The outlines relation `T: 'a` or `'a: 'b`. This code frequently -// refers to rules defined in RFC 1214 (`OutlivesFooBar`), so see that -// RFC for reference. - -use rustc_data_structures::sso::SsoHashSet; -use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt}; -use rustc_middle::ty::{GenericArg, GenericArgKind}; -use smallvec::{smallvec, SmallVec}; - -#[derive(Debug)] -pub enum Component<'tcx> { - Region(ty::Region<'tcx>), - Param(ty::ParamTy), - Placeholder(ty::PlaceholderType), - UnresolvedInferenceVariable(ty::InferTy), - - // Projections like `T::Foo` are tricky because a constraint like - // `T::Foo: 'a` can be satisfied in so many ways. There may be a - // where-clause that says `T::Foo: 'a`, or the defining trait may - // include a bound like `type Foo: 'static`, or -- in the most - // conservative way -- we can prove that `T: 'a` (more generally, - // that all components in the projection outlive `'a`). This code - // is not in a position to judge which is the best technique, so - // we just product the projection as a component and leave it to - // the consumer to decide (but see `EscapingProjection` below). - Alias(ty::AliasTy<'tcx>), - - // In the case where a projection has escaping regions -- meaning - // regions bound within the type itself -- we always use - // the most conservative rule, which requires that all components - // outlive the bound. So for example if we had a type like this: - // - // for<'a> Trait1< <T as Trait2<'a,'b>>::Foo > - // ~~~~~~~~~~~~~~~~~~~~~~~~~ - // - // then the inner projection (underlined) has an escaping region - // `'a`. We consider that outer trait `'c` to meet a bound if `'b` - // outlives `'b: 'c`, and we don't consider whether the trait - // declares that `Foo: 'static` etc. Therefore, we just return the - // free components of such a projection (in this case, `'b`). - // - // However, in the future, we may want to get smarter, and - // actually return a "higher-ranked projection" here. Therefore, - // we mark that these components are part of an escaping - // projection, so that implied bounds code can avoid relying on - // them. This gives us room to improve the regionck reasoning in - // the future without breaking backwards compat. - EscapingAlias(Vec<Component<'tcx>>), -} - -/// Push onto `out` all the things that must outlive `'a` for the condition -/// `ty0: 'a` to hold. Note that `ty0` must be a **fully resolved type**. -pub fn push_outlives_components<'tcx>( - tcx: TyCtxt<'tcx>, - ty0: Ty<'tcx>, - out: &mut SmallVec<[Component<'tcx>; 4]>, -) { - let mut visited = SsoHashSet::new(); - compute_components(tcx, ty0, out, &mut visited); - debug!("components({:?}) = {:?}", ty0, out); -} - -fn compute_components<'tcx>( - tcx: TyCtxt<'tcx>, - ty: Ty<'tcx>, - out: &mut SmallVec<[Component<'tcx>; 4]>, - visited: &mut SsoHashSet<GenericArg<'tcx>>, -) { - // Descend through the types, looking for the various "base" - // components and collecting them into `out`. This is not written - // with `collect()` because of the need to sometimes skip subtrees - // in the `subtys` iterator (e.g., when encountering a - // projection). - match *ty.kind() { - ty::FnDef(_, args) => { - // HACK(eddyb) ignore lifetimes found shallowly in `args`. - // This is inconsistent with `ty::Adt` (including all args) - // and with `ty::Closure` (ignoring all args other than - // upvars, of which a `ty::FnDef` doesn't have any), but - // consistent with previous (accidental) behavior. - // See https://github.com/rust-lang/rust/issues/70917 - // for further background and discussion. - for child in args { - match child.unpack() { - GenericArgKind::Type(ty) => { - compute_components(tcx, ty, out, visited); - } - GenericArgKind::Lifetime(_) => {} - GenericArgKind::Const(_) => { - compute_components_recursive(tcx, child, out, visited); - } - } - } - } - - ty::Pat(element, _) | - ty::Array(element, _) => { - // Don't look into the len const as it doesn't affect regions - compute_components(tcx, element, out, visited); - } - - ty::Closure(_, args) => { - let tupled_ty = args.as_closure().tupled_upvars_ty(); - compute_components(tcx, tupled_ty, out, visited); - } - - ty::CoroutineClosure(_, args) => { - let tupled_ty = args.as_coroutine_closure().tupled_upvars_ty(); - compute_components(tcx, tupled_ty, out, visited); - } - - ty::Coroutine(_, args) => { - // Same as the closure case - let tupled_ty = args.as_coroutine().tupled_upvars_ty(); - compute_components(tcx, tupled_ty, out, visited); - - // We ignore regions in the coroutine interior as we don't - // want these to affect region inference - } - - // All regions are bound inside a witness - ty::CoroutineWitness(..) => (), - - // OutlivesTypeParameterEnv -- the actual checking that `X:'a` - // is implied by the environment is done in regionck. - ty::Param(p) => { - out.push(Component::Param(p)); - } - - ty::Placeholder(p) => { - out.push(Component::Placeholder(p)); - } - - // For projections, we prefer to generate an obligation like - // `<P0 as Trait<P1...Pn>>::Foo: 'a`, because this gives the - // regionck more ways to prove that it holds. However, - // regionck is not (at least currently) prepared to deal with - // higher-ranked regions that may appear in the - // trait-ref. Therefore, if we see any higher-ranked regions, - // we simply fallback to the most restrictive rule, which - // requires that `Pi: 'a` for all `i`. - ty::Alias(_, alias_ty) => { - if !alias_ty.has_escaping_bound_vars() { - // best case: no escaping regions, so push the - // projection and skip the subtree (thus generating no - // constraints for Pi). This defers the choice between - // the rules OutlivesProjectionEnv, - // OutlivesProjectionTraitDef, and - // OutlivesProjectionComponents to regionck. - out.push(Component::Alias(alias_ty)); - } else { - // fallback case: hard code - // OutlivesProjectionComponents. Continue walking - // through and constrain Pi. - let mut subcomponents = smallvec![]; - let mut subvisited = SsoHashSet::new(); - compute_alias_components_recursive(tcx, ty, &mut subcomponents, &mut subvisited); - out.push(Component::EscapingAlias(subcomponents.into_iter().collect())); - } - } - - // We assume that inference variables are fully resolved. - // So, if we encounter an inference variable, just record - // the unresolved variable as a component. - ty::Infer(infer_ty) => { - out.push(Component::UnresolvedInferenceVariable(infer_ty)); - } - - // Most types do not introduce any region binders, nor - // involve any other subtle cases, and so the WF relation - // simply constraints any regions referenced directly by - // the type and then visits the types that are lexically - // contained within. (The comments refer to relevant rules - // from RFC1214.) - ty::Bool | // OutlivesScalar - ty::Char | // OutlivesScalar - ty::Int(..) | // OutlivesScalar - ty::Uint(..) | // OutlivesScalar - ty::Float(..) | // OutlivesScalar - ty::Never | // ... - ty::Adt(..) | // OutlivesNominalType - ty::Foreign(..) | // OutlivesNominalType - ty::Str | // OutlivesScalar (ish) - ty::Slice(..) | // ... - ty::RawPtr(..) | // ... - ty::Ref(..) | // OutlivesReference - ty::Tuple(..) | // ... - ty::FnPtr(_) | // OutlivesFunction (*) - ty::Dynamic(..) | // OutlivesObject, OutlivesFragment (*) - ty::Bound(..) | - ty::Error(_) => { - // (*) Function pointers and trait objects are both binders. - // In the RFC, this means we would add the bound regions to - // the "bound regions list". In our representation, no such - // list is maintained explicitly, because bound regions - // themselves can be readily identified. - compute_components_recursive(tcx, ty.into(), out, visited); - } - } -} - -/// Collect [Component]s for *all* the args of `parent`. -/// -/// This should not be used to get the components of `parent` itself. -/// Use [push_outlives_components] instead. -pub(super) fn compute_alias_components_recursive<'tcx>( - tcx: TyCtxt<'tcx>, - alias_ty: Ty<'tcx>, - out: &mut SmallVec<[Component<'tcx>; 4]>, - visited: &mut SsoHashSet<GenericArg<'tcx>>, -) { - let ty::Alias(kind, alias_ty) = alias_ty.kind() else { - unreachable!("can only call `compute_alias_components_recursive` on an alias type") - }; - let opt_variances = if *kind == ty::Opaque { tcx.variances_of(alias_ty.def_id) } else { &[] }; - for (index, child) in alias_ty.args.iter().enumerate() { - if opt_variances.get(index) == Some(&ty::Bivariant) { - continue; - } - if !visited.insert(child) { - continue; - } - match child.unpack() { - GenericArgKind::Type(ty) => { - compute_components(tcx, ty, out, visited); - } - GenericArgKind::Lifetime(lt) => { - // Ignore higher ranked regions. - if !lt.is_bound() { - out.push(Component::Region(lt)); - } - } - GenericArgKind::Const(_) => { - compute_components_recursive(tcx, child, out, visited); - } - } - } -} - -/// Collect [Component]s for *all* the args of `parent`. -/// -/// This should not be used to get the components of `parent` itself. -/// Use [push_outlives_components] instead. -fn compute_components_recursive<'tcx>( - tcx: TyCtxt<'tcx>, - parent: GenericArg<'tcx>, - out: &mut SmallVec<[Component<'tcx>; 4]>, - visited: &mut SsoHashSet<GenericArg<'tcx>>, -) { - for child in parent.walk_shallow(visited) { - match child.unpack() { - GenericArgKind::Type(ty) => { - compute_components(tcx, ty, out, visited); - } - GenericArgKind::Lifetime(lt) => { - // Ignore higher ranked regions. - if !lt.is_bound() { - out.push(Component::Region(lt)); - } - } - GenericArgKind::Const(_) => { - compute_components_recursive(tcx, child, out, visited); - } - } - } -} diff --git a/compiler/rustc_infer/src/infer/outlives/mod.rs b/compiler/rustc_infer/src/infer/outlives/mod.rs index 48d006e7fbc..89ff4604560 100644 --- a/compiler/rustc_infer/src/infer/outlives/mod.rs +++ b/compiler/rustc_infer/src/infer/outlives/mod.rs @@ -8,7 +8,6 @@ use crate::infer::lexical_region_resolve; use rustc_middle::traits::query::{NoSolution, OutlivesBound}; use rustc_middle::ty; -pub mod components; pub mod env; pub mod for_liveness; pub mod obligations; diff --git a/compiler/rustc_infer/src/infer/outlives/obligations.rs b/compiler/rustc_infer/src/infer/outlives/obligations.rs index 32c790523b6..9bb5f775e4a 100644 --- a/compiler/rustc_infer/src/infer/outlives/obligations.rs +++ b/compiler/rustc_infer/src/infer/outlives/obligations.rs @@ -59,7 +59,6 @@ //! might later infer `?U` to something like `&'b u32`, which would //! imply that `'b: 'a`. -use crate::infer::outlives::components::{push_outlives_components, Component}; use crate::infer::outlives::env::RegionBoundPairs; use crate::infer::outlives::verify::VerifyBoundCx; use crate::infer::resolve::OpportunisticRegionResolver; @@ -75,6 +74,7 @@ use rustc_middle::ty::{ }; use rustc_middle::ty::{GenericArgKind, PolyTypeOutlivesPredicate}; use rustc_span::DUMMY_SP; +use rustc_type_ir::outlives::{push_outlives_components, Component}; use smallvec::smallvec; use super::env::OutlivesEnvironment; @@ -291,7 +291,7 @@ where fn components_must_outlive( &mut self, origin: infer::SubregionOrigin<'tcx>, - components: &[Component<'tcx>], + components: &[Component<TyCtxt<'tcx>>], region: ty::Region<'tcx>, category: ConstraintCategory<'tcx>, ) { diff --git a/compiler/rustc_infer/src/infer/outlives/verify.rs b/compiler/rustc_infer/src/infer/outlives/verify.rs index 7e977b9b954..ad102dfcc1f 100644 --- a/compiler/rustc_infer/src/infer/outlives/verify.rs +++ b/compiler/rustc_infer/src/infer/outlives/verify.rs @@ -1,10 +1,10 @@ -use crate::infer::outlives::components::{compute_alias_components_recursive, Component}; use crate::infer::outlives::env::RegionBoundPairs; use crate::infer::region_constraints::VerifyIfEq; use crate::infer::{GenericKind, VerifyBound}; use rustc_data_structures::sso::SsoHashSet; use rustc_middle::ty::GenericArg; use rustc_middle::ty::{self, OutlivesPredicate, Ty, TyCtxt}; +use rustc_type_ir::outlives::{compute_alias_components_recursive, Component}; use smallvec::smallvec; @@ -139,7 +139,7 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { fn bound_from_components( &self, - components: &[Component<'tcx>], + components: &[Component<TyCtxt<'tcx>>], visited: &mut SsoHashSet<GenericArg<'tcx>>, ) -> VerifyBound<'tcx> { let mut bounds = components @@ -158,7 +158,7 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { fn bound_from_single_component( &self, - component: &Component<'tcx>, + component: &Component<TyCtxt<'tcx>>, visited: &mut SsoHashSet<GenericArg<'tcx>>, ) -> VerifyBound<'tcx> { match *component { diff --git a/compiler/rustc_infer/src/infer/relate/combine.rs b/compiler/rustc_infer/src/infer/relate/combine.rs index 0a2e85cc891..c93b89756f9 100644 --- a/compiler/rustc_infer/src/infer/relate/combine.rs +++ b/compiler/rustc_infer/src/infer/relate/combine.rs @@ -18,11 +18,13 @@ //! On success, the LUB/GLB operations return the appropriate bound. The //! return value of `Equate` or `Sub` shouldn't really be used. +pub use rustc_next_trait_solver::relate::combine::*; + use super::glb::Glb; use super::lub::Lub; use super::type_relating::TypeRelating; +use super::RelateResult; use super::StructurallyRelateAliases; -use super::{RelateResult, TypeRelation}; use crate::infer::relate; use crate::infer::{DefineOpaqueTypes, InferCtxt, TypeTrace}; use crate::traits::{Obligation, PredicateObligation}; @@ -32,7 +34,6 @@ use rustc_middle::traits::solve::Goal; use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::{self, InferConst, Ty, TyCtxt, TypeVisitableExt, Upcast}; use rustc_middle::ty::{IntType, UintType}; -use rustc_span::Span; #[derive(Clone)] pub struct CombineFields<'infcx, 'tcx> { @@ -76,7 +77,7 @@ impl<'tcx> InferCtxt<'tcx> { b: Ty<'tcx>, ) -> RelateResult<'tcx, Ty<'tcx>> where - R: PredicateEmittingRelation<'tcx>, + R: PredicateEmittingRelation<InferCtxt<'tcx>>, { debug_assert!(!a.has_escaping_bound_vars()); debug_assert!(!b.has_escaping_bound_vars()); @@ -171,7 +172,7 @@ impl<'tcx> InferCtxt<'tcx> { b: ty::Const<'tcx>, ) -> RelateResult<'tcx, ty::Const<'tcx>> where - R: PredicateEmittingRelation<'tcx>, + R: PredicateEmittingRelation<InferCtxt<'tcx>>, { debug!("{}.consts({:?}, {:?})", relation.tag(), a, b); debug_assert!(!a.has_escaping_bound_vars()); @@ -323,30 +324,3 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> { ) } } - -pub trait PredicateEmittingRelation<'tcx>: TypeRelation<TyCtxt<'tcx>> { - fn span(&self) -> Span; - - fn param_env(&self) -> ty::ParamEnv<'tcx>; - - /// Whether aliases should be related structurally. This is pretty much - /// always `No` unless you're equating in some specific locations of the - /// new solver. See the comments in these use-cases for more details. - fn structurally_relate_aliases(&self) -> StructurallyRelateAliases; - - /// Register obligations that must hold in order for this relation to hold - fn register_goals( - &mut self, - obligations: impl IntoIterator<Item = Goal<'tcx, ty::Predicate<'tcx>>>, - ); - - /// Register predicates that must hold in order for this relation to hold. - /// This uses the default `param_env` of the obligation. - fn register_predicates( - &mut self, - obligations: impl IntoIterator<Item: Upcast<TyCtxt<'tcx>, ty::Predicate<'tcx>>>, - ); - - /// Register `AliasRelate` obligation(s) that both types must be related to each other. - fn register_alias_relate_predicate(&mut self, a: Ty<'tcx>, b: Ty<'tcx>); -} diff --git a/compiler/rustc_infer/src/infer/relate/generalize.rs b/compiler/rustc_infer/src/infer/relate/generalize.rs index d6e57d85387..fe3b8d60fb9 100644 --- a/compiler/rustc_infer/src/infer/relate/generalize.rs +++ b/compiler/rustc_infer/src/infer/relate/generalize.rs @@ -30,7 +30,7 @@ impl<'tcx> InferCtxt<'tcx> { /// `TypeRelation`. Do not use this, and instead please use `At::eq`, for all /// other usecases (i.e. setting the value of a type var). #[instrument(level = "debug", skip(self, relation))] - pub fn instantiate_ty_var<R: PredicateEmittingRelation<'tcx>>( + pub fn instantiate_ty_var<R: PredicateEmittingRelation<InferCtxt<'tcx>>>( &self, relation: &mut R, target_is_expected: bool, @@ -178,7 +178,7 @@ impl<'tcx> InferCtxt<'tcx> { /// /// See `tests/ui/const-generics/occurs-check/` for more examples where this is relevant. #[instrument(level = "debug", skip(self, relation))] - pub(super) fn instantiate_const_var<R: PredicateEmittingRelation<'tcx>>( + pub(super) fn instantiate_const_var<R: PredicateEmittingRelation<InferCtxt<'tcx>>>( &self, relation: &mut R, target_is_expected: bool, diff --git a/compiler/rustc_infer/src/infer/relate/glb.rs b/compiler/rustc_infer/src/infer/relate/glb.rs index 067004ecaeb..5bb8a113e17 100644 --- a/compiler/rustc_infer/src/infer/relate/glb.rs +++ b/compiler/rustc_infer/src/infer/relate/glb.rs @@ -123,7 +123,7 @@ impl<'combine, 'infcx, 'tcx> LatticeDir<'infcx, 'tcx> for Glb<'combine, 'infcx, } } -impl<'tcx> PredicateEmittingRelation<'tcx> for Glb<'_, '_, 'tcx> { +impl<'tcx> PredicateEmittingRelation<InferCtxt<'tcx>> for Glb<'_, '_, 'tcx> { fn span(&self) -> Span { self.fields.trace.span() } diff --git a/compiler/rustc_infer/src/infer/relate/lattice.rs b/compiler/rustc_infer/src/infer/relate/lattice.rs index 6cc8d6d910a..46e7466141a 100644 --- a/compiler/rustc_infer/src/infer/relate/lattice.rs +++ b/compiler/rustc_infer/src/infer/relate/lattice.rs @@ -30,7 +30,7 @@ use rustc_middle::ty::{self, Ty}; /// /// GLB moves "down" the lattice (to smaller values); LUB moves /// "up" the lattice (to bigger values). -pub trait LatticeDir<'f, 'tcx>: PredicateEmittingRelation<'tcx> { +pub trait LatticeDir<'f, 'tcx>: PredicateEmittingRelation<InferCtxt<'tcx>> { fn infcx(&self) -> &'f InferCtxt<'tcx>; fn cause(&self) -> &ObligationCause<'tcx>; diff --git a/compiler/rustc_infer/src/infer/relate/lub.rs b/compiler/rustc_infer/src/infer/relate/lub.rs index 2184416b4cc..94c1464817f 100644 --- a/compiler/rustc_infer/src/infer/relate/lub.rs +++ b/compiler/rustc_infer/src/infer/relate/lub.rs @@ -123,7 +123,7 @@ impl<'combine, 'infcx, 'tcx> LatticeDir<'infcx, 'tcx> for Lub<'combine, 'infcx, } } -impl<'tcx> PredicateEmittingRelation<'tcx> for Lub<'_, '_, 'tcx> { +impl<'tcx> PredicateEmittingRelation<InferCtxt<'tcx>> for Lub<'_, '_, 'tcx> { fn span(&self) -> Span { self.fields.trace.span() } diff --git a/compiler/rustc_infer/src/infer/relate/mod.rs b/compiler/rustc_infer/src/infer/relate/mod.rs index 41cc945492d..dd97dc061fe 100644 --- a/compiler/rustc_infer/src/infer/relate/mod.rs +++ b/compiler/rustc_infer/src/infer/relate/mod.rs @@ -2,11 +2,13 @@ //! (except for some relations used for diagnostics and heuristics in the compiler). //! As well as the implementation of `Relate` for interned things (`Ty`/`Const`/etc). -pub use rustc_middle::ty::relate::*; +pub use rustc_middle::ty::relate::RelateResult; +pub use rustc_next_trait_solver::relate::*; pub use self::combine::CombineFields; pub use self::combine::PredicateEmittingRelation; +#[allow(hidden_glob_reexports)] pub(super) mod combine; mod generalize; mod glb; diff --git a/compiler/rustc_infer/src/infer/relate/type_relating.rs b/compiler/rustc_infer/src/infer/relate/type_relating.rs index f2bec9392d5..e206f530519 100644 --- a/compiler/rustc_infer/src/infer/relate/type_relating.rs +++ b/compiler/rustc_infer/src/infer/relate/type_relating.rs @@ -1,7 +1,7 @@ use super::combine::CombineFields; use crate::infer::relate::{PredicateEmittingRelation, StructurallyRelateAliases}; use crate::infer::BoundRegionConversionTime::HigherRankedType; -use crate::infer::{DefineOpaqueTypes, SubregionOrigin}; +use crate::infer::{DefineOpaqueTypes, InferCtxt, SubregionOrigin}; use rustc_middle::traits::solve::Goal; use rustc_middle::ty::relate::{ relate_args_invariantly, relate_args_with_variances, Relate, RelateResult, TypeRelation, @@ -296,7 +296,7 @@ impl<'tcx> TypeRelation<TyCtxt<'tcx>> for TypeRelating<'_, '_, 'tcx> { } } -impl<'tcx> PredicateEmittingRelation<'tcx> for TypeRelating<'_, '_, 'tcx> { +impl<'tcx> PredicateEmittingRelation<InferCtxt<'tcx>> for TypeRelating<'_, '_, 'tcx> { fn span(&self) -> Span { self.fields.trace.span() } diff --git a/compiler/rustc_infer/src/traits/util.rs b/compiler/rustc_infer/src/traits/util.rs index 24cf9f03fcd..b269bfcbfeb 100644 --- a/compiler/rustc_infer/src/traits/util.rs +++ b/compiler/rustc_infer/src/traits/util.rs @@ -1,11 +1,12 @@ use smallvec::smallvec; -use crate::infer::outlives::components::{push_outlives_components, Component}; use crate::traits::{self, Obligation, ObligationCauseCode, PredicateObligation}; use rustc_data_structures::fx::FxHashSet; +use rustc_middle::ty::ToPolyTraitRef; use rustc_middle::ty::{self, Ty, TyCtxt, Upcast}; use rustc_span::symbol::Ident; use rustc_span::Span; +use rustc_type_ir::outlives::{push_outlives_components, Component}; pub fn anonymize_predicate<'tcx>( tcx: TyCtxt<'tcx>, @@ -82,7 +83,6 @@ pub struct Elaborator<'tcx, O> { enum Filter { All, OnlySelf, - OnlySelfThatDefines(Ident), } /// Describes how to elaborate an obligation into a sub-obligation. @@ -252,12 +252,6 @@ impl<'tcx, O: Elaboratable<'tcx>> Elaborator<'tcx, O> { self } - /// Filter to only the supertraits of trait predicates that define the assoc_ty. - pub fn filter_only_self_that_defines(mut self, assoc_ty: Ident) -> Self { - self.mode = Filter::OnlySelfThatDefines(assoc_ty); - self - } - fn elaborate(&mut self, elaboratable: &O) { let tcx = self.visited.tcx; @@ -277,9 +271,6 @@ impl<'tcx, O: Elaboratable<'tcx>> Elaborator<'tcx, O> { let predicates = match self.mode { Filter::All => tcx.explicit_implied_predicates_of(data.def_id()), Filter::OnlySelf => tcx.explicit_super_predicates_of(data.def_id()), - Filter::OnlySelfThatDefines(ident) => { - tcx.explicit_supertraits_containing_assoc_item((data.def_id(), ident)) - } }; let obligations = @@ -405,14 +396,14 @@ impl<'tcx, O: Elaboratable<'tcx>> Iterator for Elaborator<'tcx, O> { pub fn supertraits<'tcx>( tcx: TyCtxt<'tcx>, trait_ref: ty::PolyTraitRef<'tcx>, -) -> FilterToTraits<Elaborator<'tcx, ty::Predicate<'tcx>>> { +) -> FilterToTraits<Elaborator<'tcx, ty::Clause<'tcx>>> { elaborate(tcx, [trait_ref.upcast(tcx)]).filter_only_self().filter_to_traits() } pub fn transitive_bounds<'tcx>( tcx: TyCtxt<'tcx>, trait_refs: impl Iterator<Item = ty::PolyTraitRef<'tcx>>, -) -> FilterToTraits<Elaborator<'tcx, ty::Predicate<'tcx>>> { +) -> FilterToTraits<Elaborator<'tcx, ty::Clause<'tcx>>> { elaborate(tcx, trait_refs.map(|trait_ref| trait_ref.upcast(tcx))) .filter_only_self() .filter_to_traits() @@ -427,17 +418,37 @@ pub fn transitive_bounds_that_define_assoc_item<'tcx>( tcx: TyCtxt<'tcx>, trait_refs: impl Iterator<Item = ty::PolyTraitRef<'tcx>>, assoc_name: Ident, -) -> FilterToTraits<Elaborator<'tcx, ty::Predicate<'tcx>>> { - elaborate(tcx, trait_refs.map(|trait_ref| trait_ref.upcast(tcx))) - .filter_only_self_that_defines(assoc_name) - .filter_to_traits() +) -> impl Iterator<Item = ty::PolyTraitRef<'tcx>> { + let mut seen = FxHashSet::default(); + let mut stack: Vec<_> = trait_refs.collect(); + + std::iter::from_fn(move || { + while let Some(trait_ref) = stack.pop() { + if !seen.insert(tcx.anonymize_bound_vars(trait_ref)) { + continue; + } + + stack.extend( + tcx.explicit_supertraits_containing_assoc_item((trait_ref.def_id(), assoc_name)) + .instantiate_own_identity() + .map(|(clause, _)| clause.instantiate_supertrait(tcx, trait_ref)) + .filter_map(|clause| clause.as_trait_clause()) + // FIXME: Negative supertraits are elaborated here lol + .map(|trait_pred| trait_pred.to_poly_trait_ref()), + ); + + return Some(trait_ref); + } + + None + }) } /////////////////////////////////////////////////////////////////////////// // Other /////////////////////////////////////////////////////////////////////////// -impl<'tcx> Elaborator<'tcx, ty::Predicate<'tcx>> { +impl<'tcx> Elaborator<'tcx, ty::Clause<'tcx>> { fn filter_to_traits(self) -> FilterToTraits<Self> { FilterToTraits { base_iterator: self } } @@ -449,7 +460,7 @@ pub struct FilterToTraits<I> { base_iterator: I, } -impl<'tcx, I: Iterator<Item = ty::Predicate<'tcx>>> Iterator for FilterToTraits<I> { +impl<'tcx, I: Iterator<Item = ty::Clause<'tcx>>> Iterator for FilterToTraits<I> { type Item = ty::PolyTraitRef<'tcx>; fn next(&mut self) -> Option<ty::PolyTraitRef<'tcx>> { diff --git a/compiler/rustc_lint/src/context/diagnostics/check_cfg.rs b/compiler/rustc_lint/src/context/diagnostics/check_cfg.rs index c69e680cb64..da36f68fca9 100644 --- a/compiler/rustc_lint/src/context/diagnostics/check_cfg.rs +++ b/compiler/rustc_lint/src/context/diagnostics/check_cfg.rs @@ -261,10 +261,16 @@ pub(super) fn unexpected_cfg_value( lints::unexpected_cfg_value::CodeSuggestion::RemoveCondition { suggestion, name } }; - // We don't want to suggest adding values to well known names - // since those are defined by rustc it-self. Users can still - // do it if they want, but should not encourage them. - let is_cfg_a_well_know_name = sess.psess.check_config.well_known_names.contains(&name); + // We don't want to encourage people to add values to a well-known names, as these are + // defined by rustc/Rust itself. Users can still do this if they wish, but should not be + // encouraged to do so. + let can_suggest_adding_value = !sess.psess.check_config.well_known_names.contains(&name) + // Except when working on rustc or the standard library itself, in which case we want to + // suggest adding these cfgs to the "normal" place because of bootstraping reasons. As a + // basic heuristic, we use the "cheat" unstable feature enable method and the + // non-ui-testing enabled option. + || (matches!(sess.psess.unstable_features, rustc_feature::UnstableFeatures::Cheat) + && !sess.opts.unstable_opts.ui_testing); let inst = |escape_quotes| to_check_cfg_arg(name, value.map(|(v, _s)| v), escape_quotes); @@ -275,14 +281,14 @@ pub(super) fn unexpected_cfg_value( } else { Some(lints::unexpected_cfg_value::CargoHelp::DefineFeatures) } - } else if !is_cfg_a_well_know_name { + } else if can_suggest_adding_value { Some(lints::unexpected_cfg_value::CargoHelp::Other(cargo_help_sub(sess, &inst))) } else { None }; lints::unexpected_cfg_value::InvocationHelp::Cargo(help) } else { - let help = if !is_cfg_a_well_know_name { + let help = if can_suggest_adding_value { Some(lints::UnexpectedCfgRustcHelp::new(&inst(EscapeQuotes::No))) } else { None diff --git a/compiler/rustc_middle/src/middle/dependency_format.rs b/compiler/rustc_middle/src/middle/dependency_format.rs index e7d0cffc85c..a3aff9a1101 100644 --- a/compiler/rustc_middle/src/middle/dependency_format.rs +++ b/compiler/rustc_middle/src/middle/dependency_format.rs @@ -4,15 +4,15 @@ //! For all the gory details, see the provider of the `dependency_formats` //! query. +// FIXME: move this file to rustc_metadata::dependency_format, but +// this will introduce circular dependency between rustc_metadata and rustc_middle + use rustc_macros::{Decodable, Encodable, HashStable}; use rustc_session::config::CrateType; /// A list of dependencies for a certain crate type. /// /// The length of this vector is the same as the number of external crates used. -/// The value is None if the crate does not need to be linked (it was found -/// statically in another dylib), or Some(kind) if it needs to be linked as -/// `kind` (either static or dynamic). pub type DependencyList = Vec<Linkage>; /// A mapping of all required dependencies for a particular flavor of output. diff --git a/compiler/rustc_middle/src/mir/coverage.rs b/compiler/rustc_middle/src/mir/coverage.rs index da25fbb0a82..beaaadd497d 100644 --- a/compiler/rustc_middle/src/mir/coverage.rs +++ b/compiler/rustc_middle/src/mir/coverage.rs @@ -103,7 +103,7 @@ pub enum CoverageKind { SpanMarker, /// Marks its enclosing basic block with an ID that can be referred to by - /// side data in [`BranchInfo`]. + /// side data in [`CoverageInfoHi`]. /// /// Should be erased before codegen (at some point after `InstrumentCoverage`). BlockMarker { id: BlockMarkerId }, @@ -274,10 +274,15 @@ pub struct FunctionCoverageInfo { pub mcdc_num_condition_bitmaps: usize, } -/// Branch information recorded during THIR-to-MIR lowering, and stored in MIR. +/// Coverage information for a function, recorded during MIR building and +/// attached to the corresponding `mir::Body`. Used by the `InstrumentCoverage` +/// MIR pass. +/// +/// ("Hi" indicates that this is "high-level" information collected at the +/// THIR/MIR boundary, before the MIR-based coverage instrumentation pass.) #[derive(Clone, Debug)] #[derive(TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable, TypeVisitable)] -pub struct BranchInfo { +pub struct CoverageInfoHi { /// 1 more than the highest-numbered [`CoverageKind::BlockMarker`] that was /// injected into the MIR body. This makes it possible to allocate per-ID /// data structures without having to scan the entire body first. diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs index 16093cfca6a..4e95e600b5a 100644 --- a/compiler/rustc_middle/src/mir/interpret/mod.rs +++ b/compiler/rustc_middle/src/mir/interpret/mod.rs @@ -18,6 +18,7 @@ use smallvec::{smallvec, SmallVec}; use tracing::{debug, trace}; use rustc_ast::LitKind; +use rustc_attr::InlineAttr; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sync::{HashMapExt, Lock}; use rustc_errors::ErrorGuaranteed; @@ -134,10 +135,11 @@ pub fn specialized_encode_alloc_id<'tcx, E: TyEncoder<I = TyCtxt<'tcx>>>( AllocDiscriminant::Alloc.encode(encoder); alloc.encode(encoder); } - GlobalAlloc::Function(fn_instance) => { - trace!("encoding {:?} with {:#?}", alloc_id, fn_instance); + GlobalAlloc::Function { instance, unique } => { + trace!("encoding {:?} with {:#?}", alloc_id, instance); AllocDiscriminant::Fn.encode(encoder); - fn_instance.encode(encoder); + instance.encode(encoder); + unique.encode(encoder); } GlobalAlloc::VTable(ty, poly_trait_ref) => { trace!("encoding {:?} with {ty:#?}, {poly_trait_ref:#?}", alloc_id); @@ -285,7 +287,12 @@ impl<'s> AllocDecodingSession<'s> { trace!("creating fn alloc ID"); let instance = ty::Instance::decode(decoder); trace!("decoded fn alloc instance: {:?}", instance); - let alloc_id = decoder.interner().reserve_and_set_fn_alloc(instance); + let unique = bool::decode(decoder); + // Here we cannot call `reserve_and_set_fn_alloc` as that would use a query, which + // is not possible in this context. That's why the allocation stores + // whether it is unique or not. + let alloc_id = + decoder.interner().reserve_and_set_fn_alloc_internal(instance, unique); alloc_id } AllocDiscriminant::VTable => { @@ -323,7 +330,12 @@ impl<'s> AllocDecodingSession<'s> { #[derive(Debug, Clone, Eq, PartialEq, Hash, TyDecodable, TyEncodable, HashStable)] pub enum GlobalAlloc<'tcx> { /// The alloc ID is used as a function pointer. - Function(Instance<'tcx>), + Function { + instance: Instance<'tcx>, + /// Stores whether this instance is unique, i.e. all pointers to this function use the same + /// alloc ID. + unique: bool, + }, /// This alloc ID points to a symbolic (not-reified) vtable. VTable(Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>), /// The alloc ID points to a "lazy" static variable that did not get computed (yet). @@ -349,7 +361,7 @@ impl<'tcx> GlobalAlloc<'tcx> { #[inline] pub fn unwrap_fn(&self) -> Instance<'tcx> { match *self { - GlobalAlloc::Function(instance) => instance, + GlobalAlloc::Function { instance, .. } => instance, _ => bug!("expected function, got {:?}", self), } } @@ -368,7 +380,7 @@ impl<'tcx> GlobalAlloc<'tcx> { #[inline] pub fn address_space(&self, cx: &impl HasDataLayout) -> AddressSpace { match self { - GlobalAlloc::Function(..) => cx.data_layout().instruction_address_space, + GlobalAlloc::Function { .. } => cx.data_layout().instruction_address_space, GlobalAlloc::Static(..) | GlobalAlloc::Memory(..) | GlobalAlloc::VTable(..) => { AddressSpace::DATA } @@ -426,7 +438,7 @@ impl<'tcx> TyCtxt<'tcx> { fn reserve_and_set_dedup(self, alloc: GlobalAlloc<'tcx>) -> AllocId { let mut alloc_map = self.alloc_map.lock(); match alloc { - GlobalAlloc::Function(..) | GlobalAlloc::Static(..) | GlobalAlloc::VTable(..) => {} + GlobalAlloc::Function { .. } | GlobalAlloc::Static(..) | GlobalAlloc::VTable(..) => {} GlobalAlloc::Memory(..) => bug!("Trying to dedup-reserve memory with real data!"), } if let Some(&alloc_id) = alloc_map.dedup.get(&alloc) { @@ -445,30 +457,45 @@ impl<'tcx> TyCtxt<'tcx> { self.reserve_and_set_dedup(GlobalAlloc::Static(static_id)) } + /// Generates an `AllocId` for a function. The caller must already have decided whether this + /// function obtains a unique AllocId or gets de-duplicated via the cache. + fn reserve_and_set_fn_alloc_internal(self, instance: Instance<'tcx>, unique: bool) -> AllocId { + let alloc = GlobalAlloc::Function { instance, unique }; + if unique { + // Deduplicate. + self.reserve_and_set_dedup(alloc) + } else { + // Get a fresh ID. + let mut alloc_map = self.alloc_map.lock(); + let id = alloc_map.reserve(); + alloc_map.alloc_map.insert(id, alloc); + id + } + } + /// Generates an `AllocId` for a function. Depending on the function type, /// this might get deduplicated or assigned a new ID each time. pub fn reserve_and_set_fn_alloc(self, instance: Instance<'tcx>) -> AllocId { // Functions cannot be identified by pointers, as asm-equal functions can get deduplicated // by the linker (we set the "unnamed_addr" attribute for LLVM) and functions can be - // duplicated across crates. - // We thus generate a new `AllocId` for every mention of a function. This means that - // `main as fn() == main as fn()` is false, while `let x = main as fn(); x == x` is true. - // However, formatting code relies on function identity (see #58320), so we only do - // this for generic functions. Lifetime parameters are ignored. + // duplicated across crates. We thus generate a new `AllocId` for every mention of a + // function. This means that `main as fn() == main as fn()` is false, while `let x = main as + // fn(); x == x` is true. However, as a quality-of-life feature it can be useful to identify + // certain functions uniquely, e.g. for backtraces. So we identify whether codegen will + // actually emit duplicate functions. It does that when they have non-lifetime generics, or + // when they can be inlined. All other functions are given a unique address. + // This is not a stable guarantee! The `inline` attribute is a hint and cannot be relied + // upon for anything. But if we don't do this, backtraces look terrible. let is_generic = instance .args .into_iter() .any(|kind| !matches!(kind.unpack(), GenericArgKind::Lifetime(_))); - if is_generic { - // Get a fresh ID. - let mut alloc_map = self.alloc_map.lock(); - let id = alloc_map.reserve(); - alloc_map.alloc_map.insert(id, GlobalAlloc::Function(instance)); - id - } else { - // Deduplicate. - self.reserve_and_set_dedup(GlobalAlloc::Function(instance)) - } + let can_be_inlined = match self.codegen_fn_attrs(instance.def_id()).inline { + InlineAttr::Never => false, + _ => true, + }; + let unique = !is_generic && !can_be_inlined; + self.reserve_and_set_fn_alloc_internal(instance, unique) } /// Generates an `AllocId` for a (symbolic, not-reified) vtable. Will get deduplicated. diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index ef88b253864..83e3898cebf 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -430,11 +430,12 @@ pub struct Body<'tcx> { pub tainted_by_errors: Option<ErrorGuaranteed>, - /// Branch coverage information collected during MIR building, to be used by - /// the `InstrumentCoverage` pass. + /// Coverage information collected from THIR/MIR during MIR building, + /// to be used by the `InstrumentCoverage` pass. /// - /// Only present if branch coverage is enabled and this function is eligible. - pub coverage_branch_info: Option<Box<coverage::BranchInfo>>, + /// Only present if coverage is enabled and this function is eligible. + /// Boxed to limit space overhead in non-coverage builds. + pub coverage_info_hi: Option<Box<coverage::CoverageInfoHi>>, /// Per-function coverage information added by the `InstrumentCoverage` /// pass, to be used in conjunction with the coverage statements injected @@ -484,7 +485,7 @@ impl<'tcx> Body<'tcx> { is_polymorphic: false, injection_phase: None, tainted_by_errors, - coverage_branch_info: None, + coverage_info_hi: None, function_coverage_info: None, }; body.is_polymorphic = body.has_non_region_param(); @@ -515,7 +516,7 @@ impl<'tcx> Body<'tcx> { is_polymorphic: false, injection_phase: None, tainted_by_errors: None, - coverage_branch_info: None, + coverage_info_hi: None, function_coverage_info: None, }; body.is_polymorphic = body.has_non_region_param(); diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index 4657f4dcf81..af19ed95193 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -473,8 +473,8 @@ pub fn write_mir_intro<'tcx>( // Add an empty line before the first block is printed. writeln!(w)?; - if let Some(branch_info) = &body.coverage_branch_info { - write_coverage_branch_info(branch_info, w)?; + if let Some(coverage_info_hi) = &body.coverage_info_hi { + write_coverage_info_hi(coverage_info_hi, w)?; } if let Some(function_coverage_info) = &body.function_coverage_info { write_function_coverage_info(function_coverage_info, w)?; @@ -483,18 +483,26 @@ pub fn write_mir_intro<'tcx>( Ok(()) } -fn write_coverage_branch_info( - branch_info: &coverage::BranchInfo, +fn write_coverage_info_hi( + coverage_info_hi: &coverage::CoverageInfoHi, w: &mut dyn io::Write, ) -> io::Result<()> { - let coverage::BranchInfo { branch_spans, mcdc_branch_spans, mcdc_decision_spans, .. } = - branch_info; + let coverage::CoverageInfoHi { + num_block_markers: _, + branch_spans, + mcdc_branch_spans, + mcdc_decision_spans, + } = coverage_info_hi; + + // Only add an extra trailing newline if we printed at least one thing. + let mut did_print = false; for coverage::BranchSpan { span, true_marker, false_marker } in branch_spans { writeln!( w, "{INDENT}coverage branch {{ true: {true_marker:?}, false: {false_marker:?} }} => {span:?}", )?; + did_print = true; } for coverage::MCDCBranchSpan { @@ -510,6 +518,7 @@ fn write_coverage_branch_info( "{INDENT}coverage mcdc branch {{ condition_id: {:?}, true: {true_marker:?}, false: {false_marker:?}, depth: {decision_depth:?} }} => {span:?}", condition_info.map(|info| info.condition_id) )?; + did_print = true; } for coverage::MCDCDecisionSpan { span, num_conditions, end_markers, decision_depth } in @@ -519,10 +528,10 @@ fn write_coverage_branch_info( w, "{INDENT}coverage mcdc decision {{ num_conditions: {num_conditions:?}, end: {end_markers:?}, depth: {decision_depth:?} }} => {span:?}" )?; + did_print = true; } - if !branch_spans.is_empty() || !mcdc_branch_spans.is_empty() || !mcdc_decision_spans.is_empty() - { + if did_print { writeln!(w)?; } @@ -1449,7 +1458,7 @@ pub fn write_allocations<'tcx>( // This can't really happen unless there are bugs, but it doesn't cost us anything to // gracefully handle it and allow buggy rustc to be debugged via allocation printing. None => write!(w, " (deallocated)")?, - Some(GlobalAlloc::Function(inst)) => write!(w, " (fn: {inst})")?, + Some(GlobalAlloc::Function { instance, .. }) => write!(w, " (fn: {instance})")?, Some(GlobalAlloc::VTable(ty, Some(trait_ref))) => { write!(w, " (vtable: impl {trait_ref} for {ty})")? } diff --git a/compiler/rustc_middle/src/ty/consts/kind.rs b/compiler/rustc_middle/src/ty/consts/kind.rs index bf834ef7607..98f35b6b8ab 100644 --- a/compiler/rustc_middle/src/ty/consts/kind.rs +++ b/compiler/rustc_middle/src/ty/consts/kind.rs @@ -54,6 +54,13 @@ pub struct Expr<'tcx> { pub kind: ExprKind, args: ty::GenericArgsRef<'tcx>, } + +impl<'tcx> rustc_type_ir::inherent::ExprConst<TyCtxt<'tcx>> for Expr<'tcx> { + fn args(self) -> ty::GenericArgsRef<'tcx> { + self.args + } +} + impl<'tcx> Expr<'tcx> { pub fn new_binop( tcx: TyCtxt<'tcx>, diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 055749ba3a3..dca48069974 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -92,6 +92,8 @@ use std::ops::{Bound, Deref}; impl<'tcx> Interner for TyCtxt<'tcx> { type DefId = DefId; type LocalDefId = LocalDefId; + type Span = Span; + type GenericArgs = ty::GenericArgsRef<'tcx>; type GenericArgsSlice = &'tcx [ty::GenericArg<'tcx>]; diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index ae54411d788..c50a98e88fd 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -5,6 +5,7 @@ use crate::ty::{ self, EarlyBinder, GenericArgs, GenericArgsRef, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, }; +use rustc_data_structures::fx::FxHashMap; use rustc_errors::ErrorGuaranteed; use rustc_hir as hir; use rustc_hir::def::Namespace; @@ -388,13 +389,25 @@ impl<'tcx> InstanceKind<'tcx> { } fn type_length<'tcx>(item: impl TypeVisitable<TyCtxt<'tcx>>) -> usize { - struct Visitor { + struct Visitor<'tcx> { type_length: usize, + cache: FxHashMap<Ty<'tcx>, usize>, } - impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for Visitor { + impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for Visitor<'tcx> { fn visit_ty(&mut self, t: Ty<'tcx>) { + if let Some(&value) = self.cache.get(&t) { + self.type_length += value; + return; + } + + let prev = self.type_length; self.type_length += 1; t.super_visit_with(self); + + // We don't try to use the cache if the type is fairly small. + if self.type_length > 16 { + self.cache.insert(t, self.type_length - prev); + } } fn visit_const(&mut self, ct: ty::Const<'tcx>) { @@ -402,7 +415,7 @@ fn type_length<'tcx>(item: impl TypeVisitable<TyCtxt<'tcx>>) -> usize { ct.super_visit_with(self); } } - let mut visitor = Visitor { type_length: 0 }; + let mut visitor = Visitor { type_length: 0, cache: Default::default() }; item.visit_with(&mut visitor); visitor.type_length diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index d2f32cafb9d..7e64c507406 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -1667,7 +1667,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { Some(GlobalAlloc::Static(def_id)) => { p!(write("<static({:?})>", def_id)) } - Some(GlobalAlloc::Function(_)) => p!("<function>"), + Some(GlobalAlloc::Function { .. }) => p!("<function>"), Some(GlobalAlloc::VTable(..)) => p!("<vtable>"), None => p!("<dangling pointer>"), } @@ -1679,7 +1679,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { ty::FnPtr(_) => { // FIXME: We should probably have a helper method to share code with the "Byte strings" // printing above (which also has to handle pointers to all sorts of things). - if let Some(GlobalAlloc::Function(instance)) = + if let Some(GlobalAlloc::Function { instance, .. }) = self.tcx().try_get_global_alloc(prov.alloc_id()) { self.typed_value( diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs index b169d672a84..ebf0d7ed737 100644 --- a/compiler/rustc_middle/src/ty/relate.rs +++ b/compiler/rustc_middle/src/ty/relate.rs @@ -10,18 +10,6 @@ use crate::ty::{self as ty, Ty, TyCtxt}; pub type RelateResult<'tcx, T> = rustc_type_ir::relate::RelateResult<TyCtxt<'tcx>, T>; -/// Whether aliases should be related structurally or not. Used -/// to adjust the behavior of generalization and combine. -/// -/// This should always be `No` unless in a few special-cases when -/// instantiating canonical responses and in the new solver. Each -/// such case should have a comment explaining why it is used. -#[derive(Debug, Copy, Clone)] -pub enum StructurallyRelateAliases { - Yes, - No, -} - impl<'tcx> Relate<TyCtxt<'tcx>> for ty::ImplSubject<'tcx> { #[inline] fn relate<R: TypeRelation<TyCtxt<'tcx>>>( diff --git a/compiler/rustc_middle/src/ty/walk.rs b/compiler/rustc_middle/src/ty/walk.rs index e0f204a687f..efcaf89081f 100644 --- a/compiler/rustc_middle/src/ty/walk.rs +++ b/compiler/rustc_middle/src/ty/walk.rs @@ -78,23 +78,6 @@ impl<'tcx> GenericArg<'tcx> { pub fn walk(self) -> TypeWalker<'tcx> { TypeWalker::new(self) } - - /// Iterator that walks the immediate children of `self`. Hence - /// `Foo<Bar<i32>, u32>` yields the sequence `[Bar<i32>, u32]` - /// (but not `i32`, like `walk`). - /// - /// Iterator only walks items once. - /// It accepts visited set, updates it with all visited types - /// and skips any types that are already there. - pub fn walk_shallow( - self, - visited: &mut SsoHashSet<GenericArg<'tcx>>, - ) -> impl Iterator<Item = GenericArg<'tcx>> { - let mut stack = SmallVec::new(); - push_inner(&mut stack, self); - stack.retain(|a| visited.insert(*a)); - stack.into_iter() - } } impl<'tcx> Ty<'tcx> { diff --git a/compiler/rustc_mir_build/src/build/coverageinfo.rs b/compiler/rustc_mir_build/src/build/coverageinfo.rs index 876faca5172..204ee45bfa2 100644 --- a/compiler/rustc_mir_build/src/build/coverageinfo.rs +++ b/compiler/rustc_mir_build/src/build/coverageinfo.rs @@ -2,7 +2,7 @@ use std::assert_matches::assert_matches; use std::collections::hash_map::Entry; use rustc_data_structures::fx::FxHashMap; -use rustc_middle::mir::coverage::{BlockMarkerId, BranchSpan, CoverageKind}; +use rustc_middle::mir::coverage::{BlockMarkerId, BranchSpan, CoverageInfoHi, CoverageKind}; use rustc_middle::mir::{self, BasicBlock, SourceInfo, UnOp}; use rustc_middle::thir::{ExprId, ExprKind, Pat, Thir}; use rustc_middle::ty::TyCtxt; @@ -13,16 +13,25 @@ use crate::build::{Builder, CFG}; mod mcdc; -pub(crate) struct BranchInfoBuilder { +/// Collects coverage-related information during MIR building, to eventually be +/// turned into a function's [`CoverageInfoHi`] when MIR building is complete. +pub(crate) struct CoverageInfoBuilder { /// Maps condition expressions to their enclosing `!`, for better instrumentation. nots: FxHashMap<ExprId, NotInfo>, markers: BlockMarkerGen, - branch_spans: Vec<BranchSpan>, + /// Present if branch coverage is enabled. + branch_info: Option<BranchInfo>, + /// Present if MC/DC coverage is enabled. mcdc_info: Option<MCDCInfoBuilder>, } +#[derive(Default)] +struct BranchInfo { + branch_spans: Vec<BranchSpan>, +} + #[derive(Clone, Copy)] struct NotInfo { /// When visiting the associated expression as a branch condition, treat this @@ -62,20 +71,20 @@ impl BlockMarkerGen { } } -impl BranchInfoBuilder { - /// Creates a new branch info builder, but only if branch coverage instrumentation +impl CoverageInfoBuilder { + /// Creates a new coverage info builder, but only if coverage instrumentation /// is enabled and `def_id` represents a function that is eligible for coverage. pub(crate) fn new_if_enabled(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<Self> { - if tcx.sess.instrument_coverage_branch() && tcx.is_eligible_for_coverage(def_id) { - Some(Self { - nots: FxHashMap::default(), - markers: BlockMarkerGen::default(), - branch_spans: vec![], - mcdc_info: tcx.sess.instrument_coverage_mcdc().then(MCDCInfoBuilder::new), - }) - } else { - None + if !tcx.sess.instrument_coverage() || !tcx.is_eligible_for_coverage(def_id) { + return None; } + + Some(Self { + nots: FxHashMap::default(), + markers: BlockMarkerGen::default(), + branch_info: tcx.sess.instrument_coverage_branch().then(BranchInfo::default), + mcdc_info: tcx.sess.instrument_coverage_mcdc().then(MCDCInfoBuilder::new), + }) } /// Unary `!` expressions inside an `if` condition are lowered by lowering @@ -88,6 +97,12 @@ impl BranchInfoBuilder { pub(crate) fn visit_unary_not(&mut self, thir: &Thir<'_>, unary_not: ExprId) { assert_matches!(thir[unary_not].kind, ExprKind::Unary { op: UnOp::Not, .. }); + // The information collected by this visitor is only needed when branch + // coverage or higher is enabled. + if self.branch_info.is_none() { + return; + } + self.visit_with_not_info( thir, unary_not, @@ -137,40 +152,40 @@ impl BranchInfoBuilder { false_block, inject_block_marker, ); - } else { - let true_marker = self.markers.inject_block_marker(cfg, source_info, true_block); - let false_marker = self.markers.inject_block_marker(cfg, source_info, false_block); - - self.branch_spans.push(BranchSpan { - span: source_info.span, - true_marker, - false_marker, - }); + return; } + + // Bail out if branch coverage is not enabled. + let Some(branch_info) = self.branch_info.as_mut() else { return }; + + let true_marker = self.markers.inject_block_marker(cfg, source_info, true_block); + let false_marker = self.markers.inject_block_marker(cfg, source_info, false_block); + + branch_info.branch_spans.push(BranchSpan { + span: source_info.span, + true_marker, + false_marker, + }); } - pub(crate) fn into_done(self) -> Option<Box<mir::coverage::BranchInfo>> { - let Self { - nots: _, - markers: BlockMarkerGen { num_block_markers }, - branch_spans, - mcdc_info, - } = self; + pub(crate) fn into_done(self) -> Box<CoverageInfoHi> { + let Self { nots: _, markers: BlockMarkerGen { num_block_markers }, branch_info, mcdc_info } = + self; - if num_block_markers == 0 { - assert!(branch_spans.is_empty()); - return None; - } + let branch_spans = + branch_info.map(|branch_info| branch_info.branch_spans).unwrap_or_default(); let (mcdc_decision_spans, mcdc_branch_spans) = mcdc_info.map(MCDCInfoBuilder::into_done).unwrap_or_default(); - Some(Box::new(mir::coverage::BranchInfo { + // For simplicity, always return an info struct (without Option), even + // if there's nothing interesting in it. + Box::new(CoverageInfoHi { num_block_markers, branch_spans, mcdc_branch_spans, mcdc_decision_spans, - })) + }) } } @@ -184,7 +199,7 @@ impl<'tcx> Builder<'_, 'tcx> { block: &mut BasicBlock, ) { // Bail out if condition coverage is not enabled for this function. - let Some(branch_info) = self.coverage_branch_info.as_mut() else { return }; + let Some(coverage_info) = self.coverage_info.as_mut() else { return }; if !self.tcx.sess.instrument_coverage_condition() { return; }; @@ -224,7 +239,7 @@ impl<'tcx> Builder<'_, 'tcx> { ); // Separate path for handling branches when MC/DC is enabled. - branch_info.register_two_way_branch( + coverage_info.register_two_way_branch( self.tcx, &mut self.cfg, source_info, @@ -247,12 +262,12 @@ impl<'tcx> Builder<'_, 'tcx> { mut then_block: BasicBlock, mut else_block: BasicBlock, ) { - // Bail out if branch coverage is not enabled for this function. - let Some(branch_info) = self.coverage_branch_info.as_mut() else { return }; + // Bail out if coverage is not enabled for this function. + let Some(coverage_info) = self.coverage_info.as_mut() else { return }; // If this condition expression is nested within one or more `!` expressions, // replace it with the enclosing `!` collected by `visit_unary_not`. - if let Some(&NotInfo { enclosing_not, is_flipped }) = branch_info.nots.get(&expr_id) { + if let Some(&NotInfo { enclosing_not, is_flipped }) = coverage_info.nots.get(&expr_id) { expr_id = enclosing_not; if is_flipped { std::mem::swap(&mut then_block, &mut else_block); @@ -261,7 +276,7 @@ impl<'tcx> Builder<'_, 'tcx> { let source_info = SourceInfo { span: self.thir[expr_id].span, scope: self.source_scope }; - branch_info.register_two_way_branch( + coverage_info.register_two_way_branch( self.tcx, &mut self.cfg, source_info, @@ -280,13 +295,11 @@ impl<'tcx> Builder<'_, 'tcx> { true_block: BasicBlock, false_block: BasicBlock, ) { - // Bail out if branch coverage is not enabled for this function. - let Some(branch_info) = self.coverage_branch_info.as_mut() else { return }; - - // FIXME(#124144) This may need special handling when MC/DC is enabled. + // Bail out if coverage is not enabled for this function. + let Some(coverage_info) = self.coverage_info.as_mut() else { return }; let source_info = SourceInfo { span: pattern.span, scope: self.source_scope }; - branch_info.register_two_way_branch( + coverage_info.register_two_way_branch( self.tcx, &mut self.cfg, source_info, diff --git a/compiler/rustc_mir_build/src/build/coverageinfo/mcdc.rs b/compiler/rustc_mir_build/src/build/coverageinfo/mcdc.rs index f97e9ef60a2..3aa6e708476 100644 --- a/compiler/rustc_mir_build/src/build/coverageinfo/mcdc.rs +++ b/compiler/rustc_mir_build/src/build/coverageinfo/mcdc.rs @@ -250,24 +250,24 @@ impl MCDCInfoBuilder { impl Builder<'_, '_> { pub(crate) fn visit_coverage_branch_operation(&mut self, logical_op: LogicalOp, span: Span) { - if let Some(branch_info) = self.coverage_branch_info.as_mut() - && let Some(mcdc_info) = branch_info.mcdc_info.as_mut() + if let Some(coverage_info) = self.coverage_info.as_mut() + && let Some(mcdc_info) = coverage_info.mcdc_info.as_mut() { mcdc_info.state.record_conditions(logical_op, span); } } pub(crate) fn mcdc_increment_depth_if_enabled(&mut self) { - if let Some(branch_info) = self.coverage_branch_info.as_mut() - && let Some(mcdc_info) = branch_info.mcdc_info.as_mut() + if let Some(coverage_info) = self.coverage_info.as_mut() + && let Some(mcdc_info) = coverage_info.mcdc_info.as_mut() { mcdc_info.state.decision_ctx_stack.push(MCDCDecisionCtx::default()); }; } pub(crate) fn mcdc_decrement_depth_if_enabled(&mut self) { - if let Some(branch_info) = self.coverage_branch_info.as_mut() - && let Some(mcdc_info) = branch_info.mcdc_info.as_mut() + if let Some(coverage_info) = self.coverage_info.as_mut() + && let Some(mcdc_info) = coverage_info.mcdc_info.as_mut() { if mcdc_info.state.decision_ctx_stack.pop().is_none() { bug!("Unexpected empty decision stack"); diff --git a/compiler/rustc_mir_build/src/build/custom/mod.rs b/compiler/rustc_mir_build/src/build/custom/mod.rs index a0a512a2eff..f6ebcbcbdc9 100644 --- a/compiler/rustc_mir_build/src/build/custom/mod.rs +++ b/compiler/rustc_mir_build/src/build/custom/mod.rs @@ -62,7 +62,7 @@ pub(super) fn build_custom_mir<'tcx>( tainted_by_errors: None, injection_phase: None, pass_count: 0, - coverage_branch_info: None, + coverage_info_hi: None, function_coverage_info: None, }; diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index efed52231e3..e435e2f9288 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -160,8 +160,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // Improve branch coverage instrumentation by noting conditions // nested within one or more `!` expressions. // (Skipped if branch coverage is not enabled.) - if let Some(branch_info) = this.coverage_branch_info.as_mut() { - branch_info.visit_unary_not(this.thir, expr_id); + if let Some(coverage_info) = this.coverage_info.as_mut() { + coverage_info.visit_unary_not(this.thir, expr_id); } let local_scope = this.local_scope(); diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs index 601e5d4d3dc..0f9746cb719 100644 --- a/compiler/rustc_mir_build/src/build/mod.rs +++ b/compiler/rustc_mir_build/src/build/mod.rs @@ -218,8 +218,8 @@ struct Builder<'a, 'tcx> { lint_level_roots_cache: GrowableBitSet<hir::ItemLocalId>, /// Collects additional coverage information during MIR building. - /// Only present if branch coverage is enabled and this function is eligible. - coverage_branch_info: Option<coverageinfo::BranchInfoBuilder>, + /// Only present if coverage is enabled and this function is eligible. + coverage_info: Option<coverageinfo::CoverageInfoBuilder>, } type CaptureMap<'tcx> = SortedIndexMultiMap<usize, HirId, Capture<'tcx>>; @@ -773,7 +773,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { unit_temp: None, var_debug_info: vec![], lint_level_roots_cache: GrowableBitSet::new_empty(), - coverage_branch_info: coverageinfo::BranchInfoBuilder::new_if_enabled(tcx, def), + coverage_info: coverageinfo::CoverageInfoBuilder::new_if_enabled(tcx, def), }; assert_eq!(builder.cfg.start_new_block(), START_BLOCK); @@ -802,7 +802,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { self.coroutine, None, ); - body.coverage_branch_info = self.coverage_branch_info.and_then(|b| b.into_done()); + body.coverage_info_hi = self.coverage_info.map(|b| b.into_done()); body } diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs index 4c00038365b..9d44001f915 100644 --- a/compiler/rustc_mir_transform/src/coroutine.rs +++ b/compiler/rustc_mir_transform/src/coroutine.rs @@ -58,7 +58,7 @@ use crate::deref_separator::deref_finder; use crate::errors; use crate::pass_manager as pm; use crate::simplify; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::fx::FxHashSet; use rustc_errors::pluralize; use rustc_hir as hir; use rustc_hir::lang_items::LangItem; @@ -233,8 +233,7 @@ struct TransformVisitor<'tcx> { discr_ty: Ty<'tcx>, // Mapping from Local to (type of local, coroutine struct index) - // FIXME(eddyb) This should use `IndexVec<Local, Option<_>>`. - remap: FxHashMap<Local, (Ty<'tcx>, VariantIdx, FieldIdx)>, + remap: IndexVec<Local, Option<(Ty<'tcx>, VariantIdx, FieldIdx)>>, // A map from a suspension point in a block to the locals which have live storage at that point storage_liveness: IndexVec<BasicBlock, Option<BitSet<Local>>>, @@ -482,7 +481,7 @@ impl<'tcx> MutVisitor<'tcx> for TransformVisitor<'tcx> { } fn visit_local(&mut self, local: &mut Local, _: PlaceContext, _: Location) { - assert_eq!(self.remap.get(local), None); + assert!(!self.remap.contains(*local)); } fn visit_place( @@ -492,7 +491,7 @@ impl<'tcx> MutVisitor<'tcx> for TransformVisitor<'tcx> { _location: Location, ) { // Replace an Local in the remap with a coroutine struct access - if let Some(&(ty, variant_index, idx)) = self.remap.get(&place.local) { + if let Some(&Some((ty, variant_index, idx))) = self.remap.get(place.local) { replace_base(place, self.make_field(variant_index, idx, ty), self.tcx); } } @@ -501,7 +500,7 @@ impl<'tcx> MutVisitor<'tcx> for TransformVisitor<'tcx> { // Remove StorageLive and StorageDead statements for remapped locals data.retain_statements(|s| match s.kind { StatementKind::StorageLive(l) | StatementKind::StorageDead(l) => { - !self.remap.contains_key(&l) + !self.remap.contains(l) } _ => true, }); @@ -526,13 +525,9 @@ impl<'tcx> MutVisitor<'tcx> for TransformVisitor<'tcx> { // The resume arg target location might itself be remapped if its base local is // live across a yield. - let resume_arg = - if let Some(&(ty, variant, idx)) = self.remap.get(&resume_arg.local) { - replace_base(&mut resume_arg, self.make_field(variant, idx, ty), self.tcx); - resume_arg - } else { - resume_arg - }; + if let Some(&Some((ty, variant, idx))) = self.remap.get(resume_arg.local) { + replace_base(&mut resume_arg, self.make_field(variant, idx, ty), self.tcx); + } let storage_liveness: GrowableBitSet<Local> = self.storage_liveness[block].clone().unwrap().into(); @@ -540,7 +535,7 @@ impl<'tcx> MutVisitor<'tcx> for TransformVisitor<'tcx> { for i in 0..self.always_live_locals.domain_size() { let l = Local::new(i); let needs_storage_dead = storage_liveness.contains(l) - && !self.remap.contains_key(&l) + && !self.remap.contains(l) && !self.always_live_locals.contains(l); if needs_storage_dead { data.statements @@ -1034,7 +1029,7 @@ fn compute_layout<'tcx>( liveness: LivenessInfo, body: &Body<'tcx>, ) -> ( - FxHashMap<Local, (Ty<'tcx>, VariantIdx, FieldIdx)>, + IndexVec<Local, Option<(Ty<'tcx>, VariantIdx, FieldIdx)>>, CoroutineLayout<'tcx>, IndexVec<BasicBlock, Option<BitSet<Local>>>, ) { @@ -1095,7 +1090,7 @@ fn compute_layout<'tcx>( // Create a map from local indices to coroutine struct indices. let mut variant_fields: IndexVec<VariantIdx, IndexVec<FieldIdx, CoroutineSavedLocal>> = iter::repeat(IndexVec::new()).take(RESERVED_VARIANTS).collect(); - let mut remap = FxHashMap::default(); + let mut remap = IndexVec::from_elem_n(None, saved_locals.domain_size()); for (suspension_point_idx, live_locals) in live_locals_at_suspension_points.iter().enumerate() { let variant_index = VariantIdx::from(RESERVED_VARIANTS + suspension_point_idx); let mut fields = IndexVec::new(); @@ -1106,7 +1101,7 @@ fn compute_layout<'tcx>( // around inside coroutines, so it doesn't matter which variant // index we access them by. let idx = FieldIdx::from_usize(idx); - remap.entry(locals[saved_local]).or_insert((tys[saved_local].ty, variant_index, idx)); + remap[locals[saved_local]] = Some((tys[saved_local].ty, variant_index, idx)); } variant_fields.push(fields); variant_source_info.push(source_info_at_suspension_points[suspension_point_idx]); @@ -1118,7 +1113,9 @@ fn compute_layout<'tcx>( for var in &body.var_debug_info { let VarDebugInfoContents::Place(place) = &var.value else { continue }; let Some(local) = place.as_local() else { continue }; - let Some(&(_, variant, field)) = remap.get(&local) else { continue }; + let Some(&Some((_, variant, field))) = remap.get(local) else { + continue; + }; let saved_local = variant_fields[variant][field]; field_names.get_or_insert_with(saved_local, || var.name); @@ -1521,7 +1518,7 @@ fn create_cases<'tcx>( for i in 0..(body.local_decls.len()) { let l = Local::new(i); let needs_storage_live = point.storage_liveness.contains(l) - && !transform.remap.contains_key(&l) + && !transform.remap.contains(l) && !transform.always_live_locals.contains(l); if needs_storage_live { statements diff --git a/compiler/rustc_mir_transform/src/coverage/mappings.rs b/compiler/rustc_mir_transform/src/coverage/mappings.rs index 235992ac547..25297245172 100644 --- a/compiler/rustc_mir_transform/src/coverage/mappings.rs +++ b/compiler/rustc_mir_transform/src/coverage/mappings.rs @@ -3,7 +3,9 @@ use std::collections::BTreeSet; use rustc_data_structures::graph::DirectedGraph; use rustc_index::bit_set::BitSet; use rustc_index::IndexVec; -use rustc_middle::mir::coverage::{BlockMarkerId, BranchSpan, ConditionInfo, CoverageKind}; +use rustc_middle::mir::coverage::{ + BlockMarkerId, BranchSpan, ConditionInfo, CoverageInfoHi, CoverageKind, +}; use rustc_middle::mir::{self, BasicBlock, StatementKind}; use rustc_middle::ty::TyCtxt; use rustc_span::Span; @@ -157,12 +159,12 @@ impl ExtractedMappings { } fn resolve_block_markers( - branch_info: &mir::coverage::BranchInfo, + coverage_info_hi: &CoverageInfoHi, mir_body: &mir::Body<'_>, ) -> IndexVec<BlockMarkerId, Option<BasicBlock>> { let mut block_markers = IndexVec::<BlockMarkerId, Option<BasicBlock>>::from_elem_n( None, - branch_info.num_block_markers, + coverage_info_hi.num_block_markers, ); // Fill out the mapping from block marker IDs to their enclosing blocks. @@ -188,11 +190,11 @@ pub(super) fn extract_branch_pairs( hir_info: &ExtractedHirInfo, basic_coverage_blocks: &CoverageGraph, ) -> Vec<BranchPair> { - let Some(branch_info) = mir_body.coverage_branch_info.as_deref() else { return vec![] }; + let Some(coverage_info_hi) = mir_body.coverage_info_hi.as_deref() else { return vec![] }; - let block_markers = resolve_block_markers(branch_info, mir_body); + let block_markers = resolve_block_markers(coverage_info_hi, mir_body); - branch_info + coverage_info_hi .branch_spans .iter() .filter_map(|&BranchSpan { span: raw_span, true_marker, false_marker }| { @@ -222,9 +224,9 @@ pub(super) fn extract_mcdc_mappings( mcdc_branches: &mut impl Extend<MCDCBranch>, mcdc_decisions: &mut impl Extend<MCDCDecision>, ) { - let Some(branch_info) = mir_body.coverage_branch_info.as_deref() else { return }; + let Some(coverage_info_hi) = mir_body.coverage_info_hi.as_deref() else { return }; - let block_markers = resolve_block_markers(branch_info, mir_body); + let block_markers = resolve_block_markers(coverage_info_hi, mir_body); let bcb_from_marker = |marker: BlockMarkerId| basic_coverage_blocks.bcb_from_bb(block_markers[marker]?); @@ -243,7 +245,7 @@ pub(super) fn extract_mcdc_mappings( Some((span, true_bcb, false_bcb)) }; - mcdc_branches.extend(branch_info.mcdc_branch_spans.iter().filter_map( + mcdc_branches.extend(coverage_info_hi.mcdc_branch_spans.iter().filter_map( |&mir::coverage::MCDCBranchSpan { span: raw_span, condition_info, @@ -257,7 +259,7 @@ pub(super) fn extract_mcdc_mappings( }, )); - mcdc_decisions.extend(branch_info.mcdc_decision_spans.iter().filter_map( + mcdc_decisions.extend(coverage_info_hi.mcdc_decision_spans.iter().filter_map( |decision: &mir::coverage::MCDCDecisionSpan| { let span = unexpand_into_body_span(decision.span, body_span)?; diff --git a/compiler/rustc_mir_transform/src/elaborate_drops.rs b/compiler/rustc_mir_transform/src/elaborate_drops.rs index fbbb8c5e472..25bebb0539a 100644 --- a/compiler/rustc_mir_transform/src/elaborate_drops.rs +++ b/compiler/rustc_mir_transform/src/elaborate_drops.rs @@ -33,16 +33,16 @@ use std::fmt; /// as it would allow running a destructor on a place behind a reference: /// /// ```text -// fn drop_term<T>(t: &mut T) { -// mir! { -// { -// Drop(*t, exit) -// } -// exit = { -// Return() -// } -// } -// } +/// fn drop_term<T>(t: &mut T) { +/// mir! { +/// { +/// Drop(*t, exit) +/// } +/// exit = { +/// Return() +/// } +/// } +/// } /// ``` pub struct ElaborateDrops; diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 342c01ff697..005a22f642f 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -1160,10 +1160,10 @@ fn collect_alloc<'tcx>(tcx: TyCtxt<'tcx>, alloc_id: AllocId, output: &mut MonoIt }); } } - GlobalAlloc::Function(fn_instance) => { - if should_codegen_locally(tcx, fn_instance) { - trace!("collecting {:?} with {:#?}", alloc_id, fn_instance); - output.push(create_fn_mono_item(tcx, fn_instance, DUMMY_SP)); + GlobalAlloc::Function { instance, .. } => { + if should_codegen_locally(tcx, instance) { + trace!("collecting {:?} with {:#?}", alloc_id, instance); + output.push(create_fn_mono_item(tcx, instance, DUMMY_SP)); } } GlobalAlloc::VTable(ty, trait_ref) => { diff --git a/compiler/rustc_next_trait_solver/src/canonicalizer.rs b/compiler/rustc_next_trait_solver/src/canonicalizer.rs index 695d02705ab..82488088e30 100644 --- a/compiler/rustc_next_trait_solver/src/canonicalizer.rs +++ b/compiler/rustc_next_trait_solver/src/canonicalizer.rs @@ -4,7 +4,8 @@ use rustc_type_ir::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable}; use rustc_type_ir::inherent::*; use rustc_type_ir::visit::TypeVisitableExt; use rustc_type_ir::{ - self as ty, Canonical, CanonicalTyVarKind, CanonicalVarInfo, CanonicalVarKind, Interner, + self as ty, Canonical, CanonicalTyVarKind, CanonicalVarInfo, CanonicalVarKind, InferCtxtLike, + Interner, }; use crate::delegate::SolverDelegate; diff --git a/compiler/rustc_next_trait_solver/src/delegate.rs b/compiler/rustc_next_trait_solver/src/delegate.rs index 6626acfe963..31032dc679a 100644 --- a/compiler/rustc_next_trait_solver/src/delegate.rs +++ b/compiler/rustc_next_trait_solver/src/delegate.rs @@ -1,18 +1,20 @@ use std::fmt::Debug; +use std::ops::Deref; use rustc_type_ir::fold::TypeFoldable; -use rustc_type_ir::relate::Relate; use rustc_type_ir::solve::{Certainty, Goal, NoSolution, SolverMode}; -use rustc_type_ir::{self as ty, Interner}; +use rustc_type_ir::{self as ty, InferCtxtLike, Interner}; -pub trait SolverDelegate: Sized { +pub trait SolverDelegate: + Deref<Target: InferCtxtLike<Interner = <Self as SolverDelegate>::Interner>> + Sized +{ type Interner: Interner; - fn cx(&self) -> Self::Interner; + fn cx(&self) -> Self::Interner { + (**self).cx() + } type Span: Copy; - fn solver_mode(&self) -> SolverMode; - fn build_with_canonical<V>( cx: Self::Interner, solver_mode: SolverMode, @@ -21,82 +23,12 @@ pub trait SolverDelegate: Sized { where V: TypeFoldable<Self::Interner>; - fn universe(&self) -> ty::UniverseIndex; - fn create_next_universe(&self) -> ty::UniverseIndex; - - fn universe_of_ty(&self, ty: ty::TyVid) -> Option<ty::UniverseIndex>; - fn universe_of_lt(&self, lt: ty::RegionVid) -> Option<ty::UniverseIndex>; - fn universe_of_ct(&self, ct: ty::ConstVid) -> Option<ty::UniverseIndex>; - - fn root_ty_var(&self, var: ty::TyVid) -> ty::TyVid; - fn root_const_var(&self, var: ty::ConstVid) -> ty::ConstVid; - - fn opportunistic_resolve_ty_var(&self, vid: ty::TyVid) -> <Self::Interner as Interner>::Ty; - fn opportunistic_resolve_int_var(&self, vid: ty::IntVid) -> <Self::Interner as Interner>::Ty; - fn opportunistic_resolve_float_var( - &self, - vid: ty::FloatVid, - ) -> <Self::Interner as Interner>::Ty; - fn opportunistic_resolve_ct_var( - &self, - vid: ty::ConstVid, - ) -> <Self::Interner as Interner>::Const; - fn opportunistic_resolve_effect_var( - &self, - vid: ty::EffectVid, - ) -> <Self::Interner as Interner>::Const; - fn opportunistic_resolve_lt_var( - &self, - vid: ty::RegionVid, - ) -> <Self::Interner as Interner>::Region; - - fn defining_opaque_types(&self) -> <Self::Interner as Interner>::DefiningOpaqueTypes; - - fn next_ty_infer(&self) -> <Self::Interner as Interner>::Ty; - fn next_const_infer(&self) -> <Self::Interner as Interner>::Const; - fn fresh_args_for_item( - &self, - def_id: <Self::Interner as Interner>::DefId, - ) -> <Self::Interner as Interner>::GenericArgs; - fn fresh_var_for_kind_with_span( &self, arg: <Self::Interner as Interner>::GenericArg, span: Self::Span, ) -> <Self::Interner as Interner>::GenericArg; - fn instantiate_binder_with_infer<T: TypeFoldable<Self::Interner> + Copy>( - &self, - value: ty::Binder<Self::Interner, T>, - ) -> T; - - fn enter_forall<T: TypeFoldable<Self::Interner> + Copy, U>( - &self, - value: ty::Binder<Self::Interner, T>, - f: impl FnOnce(T) -> U, - ) -> U; - - fn relate<T: Relate<Self::Interner>>( - &self, - param_env: <Self::Interner as Interner>::ParamEnv, - lhs: T, - variance: ty::Variance, - rhs: T, - ) -> Result<Vec<Goal<Self::Interner, <Self::Interner as Interner>::Predicate>>, NoSolution>; - - fn eq_structurally_relating_aliases<T: Relate<Self::Interner>>( - &self, - param_env: <Self::Interner as Interner>::ParamEnv, - lhs: T, - rhs: T, - ) -> Result<Vec<Goal<Self::Interner, <Self::Interner as Interner>::Predicate>>, NoSolution>; - - fn resolve_vars_if_possible<T>(&self, value: T) -> T - where - T: TypeFoldable<Self::Interner>; - - fn probe<T>(&self, probe: impl FnOnce() -> T) -> T; - // FIXME: Uplift the leak check into this crate. fn leak_check(&self, max_input_universe: ty::UniverseIndex) -> Result<(), NoSolution>; @@ -112,18 +44,6 @@ pub trait SolverDelegate: Sized { unevaluated: ty::UnevaluatedConst<Self::Interner>, ) -> Option<<Self::Interner as Interner>::Const>; - fn sub_regions( - &self, - sub: <Self::Interner as Interner>::Region, - sup: <Self::Interner as Interner>::Region, - ); - - fn register_ty_outlives( - &self, - ty: <Self::Interner as Interner>::Ty, - r: <Self::Interner as Interner>::Region, - ); - // FIXME: This only is here because `wf::obligations` is in `rustc_trait_selection`! fn well_formed_goals( &self, diff --git a/compiler/rustc_next_trait_solver/src/lib.rs b/compiler/rustc_next_trait_solver/src/lib.rs index a6a9c01faaa..761475d3d6b 100644 --- a/compiler/rustc_next_trait_solver/src/lib.rs +++ b/compiler/rustc_next_trait_solver/src/lib.rs @@ -6,5 +6,6 @@ pub mod canonicalizer; pub mod delegate; +pub mod relate; pub mod resolve; pub mod solve; diff --git a/compiler/rustc_next_trait_solver/src/relate.rs b/compiler/rustc_next_trait_solver/src/relate.rs new file mode 100644 index 00000000000..db819961bbd --- /dev/null +++ b/compiler/rustc_next_trait_solver/src/relate.rs @@ -0,0 +1,15 @@ +pub use rustc_type_ir::relate::*; + +pub mod combine; + +/// Whether aliases should be related structurally or not. Used +/// to adjust the behavior of generalization and combine. +/// +/// This should always be `No` unless in a few special-cases when +/// instantiating canonical responses and in the new solver. Each +/// such case should have a comment explaining why it is used. +#[derive(Debug, Copy, Clone)] +pub enum StructurallyRelateAliases { + Yes, + No, +} diff --git a/compiler/rustc_next_trait_solver/src/relate/combine.rs b/compiler/rustc_next_trait_solver/src/relate/combine.rs new file mode 100644 index 00000000000..96968327d8e --- /dev/null +++ b/compiler/rustc_next_trait_solver/src/relate/combine.rs @@ -0,0 +1,34 @@ +pub use rustc_type_ir::relate::*; +use rustc_type_ir::solve::Goal; +use rustc_type_ir::{InferCtxtLike, Interner, Upcast}; + +use super::StructurallyRelateAliases; + +pub trait PredicateEmittingRelation<Infcx, I = <Infcx as InferCtxtLike>::Interner>: + TypeRelation<I> +where + Infcx: InferCtxtLike<Interner = I>, + I: Interner, +{ + fn span(&self) -> I::Span; + + fn param_env(&self) -> I::ParamEnv; + + /// Whether aliases should be related structurally. This is pretty much + /// always `No` unless you're equating in some specific locations of the + /// new solver. See the comments in these use-cases for more details. + fn structurally_relate_aliases(&self) -> StructurallyRelateAliases; + + /// Register obligations that must hold in order for this relation to hold + fn register_goals(&mut self, obligations: impl IntoIterator<Item = Goal<I, I::Predicate>>); + + /// Register predicates that must hold in order for this relation to hold. + /// This uses the default `param_env` of the obligation. + fn register_predicates( + &mut self, + obligations: impl IntoIterator<Item: Upcast<I, I::Predicate>>, + ); + + /// Register `AliasRelate` obligation(s) that both types must be related to each other. + fn register_alias_relate_predicate(&mut self, a: I::Ty, b: I::Ty); +} diff --git a/compiler/rustc_next_trait_solver/src/resolve.rs b/compiler/rustc_next_trait_solver/src/resolve.rs index 6ed58d0e4fb..254ee514f8b 100644 --- a/compiler/rustc_next_trait_solver/src/resolve.rs +++ b/compiler/rustc_next_trait_solver/src/resolve.rs @@ -2,7 +2,7 @@ use crate::delegate::SolverDelegate; use rustc_type_ir::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable}; use rustc_type_ir::inherent::*; use rustc_type_ir::visit::TypeVisitableExt; -use rustc_type_ir::{self as ty, Interner}; +use rustc_type_ir::{self as ty, InferCtxtLike, Interner}; /////////////////////////////////////////////////////////////////////////// // EAGER RESOLUTION diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs index 0a313c6a951..9474d501d6f 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs @@ -14,7 +14,7 @@ use std::iter; use rustc_index::IndexVec; use rustc_type_ir::fold::TypeFoldable; use rustc_type_ir::inherent::*; -use rustc_type_ir::{self as ty, Canonical, CanonicalVarValues, Interner}; +use rustc_type_ir::{self as ty, Canonical, CanonicalVarValues, InferCtxtLike, Interner}; use tracing::{instrument, trace}; use crate::canonicalizer::{CanonicalizeMode, Canonicalizer}; diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs index 87342eefb33..d8a3acc655a 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs @@ -7,7 +7,7 @@ use rustc_type_ir::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable}; use rustc_type_ir::inherent::*; use rustc_type_ir::relate::Relate; use rustc_type_ir::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor}; -use rustc_type_ir::{self as ty, CanonicalVarValues, Interner}; +use rustc_type_ir::{self as ty, CanonicalVarValues, InferCtxtLike, Interner}; use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic}; use tracing::{instrument, trace}; diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/probe.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/probe.rs index e9516c60c70..4258dd9263a 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/probe.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/probe.rs @@ -1,6 +1,6 @@ use std::marker::PhantomData; -use rustc_type_ir::Interner; +use rustc_type_ir::{InferCtxtLike, Interner}; use tracing::instrument; use crate::delegate::SolverDelegate; diff --git a/compiler/rustc_parse/src/parser/attr.rs b/compiler/rustc_parse/src/parser/attr.rs index 58fef9b6c45..a8fe35f45b3 100644 --- a/compiler/rustc_parse/src/parser/attr.rs +++ b/compiler/rustc_parse/src/parser/attr.rs @@ -282,7 +282,7 @@ impl<'a> Parser<'a> { pub fn parse_inner_attributes(&mut self) -> PResult<'a, ast::AttrVec> { let mut attrs = ast::AttrVec::new(); loop { - let start_pos: u32 = self.num_bump_calls.try_into().unwrap(); + let start_pos = self.num_bump_calls; // Only try to parse if it is an inner attribute (has `!`). let attr = if self.check(&token::Pound) && self.look_ahead(1, |t| t == &token::Not) { Some(self.parse_attribute(InnerAttrPolicy::Permitted)?) @@ -303,7 +303,7 @@ impl<'a> Parser<'a> { None }; if let Some(attr) = attr { - let end_pos: u32 = self.num_bump_calls.try_into().unwrap(); + let end_pos = self.num_bump_calls; // If we are currently capturing tokens, mark the location of this inner attribute. // If capturing ends up creating a `LazyAttrTokenStream`, we will include // this replace range with it, removing the inner attribute from the final @@ -313,7 +313,7 @@ impl<'a> Parser<'a> { // corresponding macro). let range = start_pos..end_pos; if let Capturing::Yes = self.capture_state.capturing { - self.capture_state.inner_attr_ranges.insert(attr.id, (range, vec![])); + self.capture_state.inner_attr_ranges.insert(attr.id, (range, None)); } attrs.push(attr); } else { diff --git a/compiler/rustc_parse/src/parser/attr_wrapper.rs b/compiler/rustc_parse/src/parser/attr_wrapper.rs index 13a647adfe3..38f18022e3c 100644 --- a/compiler/rustc_parse/src/parser/attr_wrapper.rs +++ b/compiler/rustc_parse/src/parser/attr_wrapper.rs @@ -1,6 +1,6 @@ use super::{Capturing, FlatToken, ForceCollect, Parser, ReplaceRange, TokenCursor, TrailingToken}; use rustc_ast::token::{self, Delimiter, Token, TokenKind}; -use rustc_ast::tokenstream::{AttrTokenStream, AttrTokenTree, AttributesData, DelimSpacing}; +use rustc_ast::tokenstream::{AttrTokenStream, AttrTokenTree, AttrsTarget, DelimSpacing}; use rustc_ast::tokenstream::{DelimSpan, LazyAttrTokenStream, Spacing, ToAttrTokenStream}; use rustc_ast::{self as ast}; use rustc_ast::{AttrVec, Attribute, HasAttrs, HasTokens}; @@ -8,7 +8,6 @@ use rustc_errors::PResult; use rustc_session::parse::ParseSess; use rustc_span::{sym, Span, DUMMY_SP}; -use std::ops::Range; use std::{iter, mem}; /// A wrapper type to ensure that the parser handles outer attributes correctly. @@ -88,7 +87,6 @@ fn has_cfg_or_cfg_attr(attrs: &[Attribute]) -> bool { // // This also makes `Parser` very cheap to clone, since // there is no intermediate collection buffer to clone. -#[derive(Clone)] struct LazyAttrTokenStreamImpl { start_token: (Token, Spacing), cursor_snapshot: TokenCursor, @@ -146,24 +144,23 @@ impl ToAttrTokenStream for LazyAttrTokenStreamImpl { // start position, we ensure that any replace range which encloses // another replace range will capture the *replaced* tokens for the inner // range, not the original tokens. - for (range, new_tokens) in replace_ranges.into_iter().rev() { + for (range, target) in replace_ranges.into_iter().rev() { assert!(!range.is_empty(), "Cannot replace an empty range: {range:?}"); - // Replace ranges are only allowed to decrease the number of tokens. - assert!( - range.len() >= new_tokens.len(), - "Range {range:?} has greater len than {new_tokens:?}" - ); - - // Replace any removed tokens with `FlatToken::Empty`. - // This keeps the total length of `tokens` constant throughout the - // replacement process, allowing us to use all of the `ReplaceRanges` entries - // without adjusting indices. - let filler = iter::repeat((FlatToken::Empty, Spacing::Alone)) - .take(range.len() - new_tokens.len()); + // Replace the tokens in range with zero or one `FlatToken::AttrsTarget`s, plus + // enough `FlatToken::Empty`s to fill up the rest of the range. This keeps the + // total length of `tokens` constant throughout the replacement process, allowing + // us to use all of the `ReplaceRanges` entries without adjusting indices. + let target_len = target.is_some() as usize; tokens.splice( (range.start as usize)..(range.end as usize), - new_tokens.into_iter().chain(filler), + target + .into_iter() + .map(|target| (FlatToken::AttrsTarget(target), Spacing::Alone)) + .chain( + iter::repeat((FlatToken::Empty, Spacing::Alone)) + .take(range.len() - target_len), + ), ); } make_attr_token_stream(tokens.into_iter(), self.break_last_token) @@ -316,7 +313,7 @@ impl<'a> Parser<'a> { .iter() .cloned() .chain(inner_attr_replace_ranges.iter().cloned()) - .map(|(range, tokens)| ((range.start - start_pos)..(range.end - start_pos), tokens)) + .map(|(range, data)| ((range.start - start_pos)..(range.end - start_pos), data)) .collect() }; @@ -346,18 +343,14 @@ impl<'a> Parser<'a> { && matches!(self.capture_state.capturing, Capturing::Yes) && has_cfg_or_cfg_attr(final_attrs) { - let attr_data = AttributesData { attrs: final_attrs.iter().cloned().collect(), tokens }; + assert!(!self.break_last_token, "Should not have unglued last token with cfg attr"); - // Replace the entire AST node that we just parsed, including attributes, - // with a `FlatToken::AttrTarget`. If this AST node is inside an item - // that has `#[derive]`, then this will allow us to cfg-expand this - // AST node. + // Replace the entire AST node that we just parsed, including attributes, with + // `target`. If this AST node is inside an item that has `#[derive]`, then this will + // allow us to cfg-expand this AST node. let start_pos = if has_outer_attrs { attrs.start_pos } else { start_pos }; - let new_tokens = vec![(FlatToken::AttrTarget(attr_data), Spacing::Alone)]; - - assert!(!self.break_last_token, "Should not have unglued last token with cfg attr"); - let range: Range<u32> = (start_pos.try_into().unwrap())..(end_pos.try_into().unwrap()); - self.capture_state.replace_ranges.push((range, new_tokens)); + let target = AttrsTarget { attrs: final_attrs.iter().cloned().collect(), tokens }; + self.capture_state.replace_ranges.push((start_pos..end_pos, Some(target))); self.capture_state.replace_ranges.extend(inner_attr_replace_ranges); } @@ -419,11 +412,11 @@ fn make_attr_token_stream( .expect("Bottom token frame is missing!") .inner .push(AttrTokenTree::Token(token, spacing)), - FlatToken::AttrTarget(data) => stack + FlatToken::AttrsTarget(target) => stack .last_mut() .expect("Bottom token frame is missing!") .inner - .push(AttrTokenTree::Attributes(data)), + .push(AttrTokenTree::AttrsTarget(target)), FlatToken::Empty => {} } token_and_spacing = iter.next(); diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 5f16a3e1f37..45ca267fe5d 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -20,7 +20,7 @@ use path::PathStyle; use rustc_ast::ptr::P; use rustc_ast::token::{self, Delimiter, IdentIsRaw, Nonterminal, Token, TokenKind}; -use rustc_ast::tokenstream::{AttributesData, DelimSpacing, DelimSpan, Spacing}; +use rustc_ast::tokenstream::{AttrsTarget, DelimSpacing, DelimSpan, Spacing}; use rustc_ast::tokenstream::{TokenStream, TokenTree, TokenTreeCursor}; use rustc_ast::util::case::Case; use rustc_ast::{ @@ -203,13 +203,13 @@ struct ClosureSpans { } /// Indicates a range of tokens that should be replaced by -/// the tokens in the provided vector. This is used in two +/// the tokens in the provided `AttrsTarget`. This is used in two /// places during token collection: /// /// 1. During the parsing of an AST node that may have a `#[derive]` /// attribute, we parse a nested AST node that has `#[cfg]` or `#[cfg_attr]` /// In this case, we use a `ReplaceRange` to replace the entire inner AST node -/// with `FlatToken::AttrTarget`, allowing us to perform eager cfg-expansion +/// with `FlatToken::AttrsTarget`, allowing us to perform eager cfg-expansion /// on an `AttrTokenStream`. /// /// 2. When we parse an inner attribute while collecting tokens. We @@ -219,7 +219,7 @@ struct ClosureSpans { /// the first macro inner attribute to invoke a proc-macro). /// When create a `TokenStream`, the inner attributes get inserted /// into the proper place in the token stream. -type ReplaceRange = (Range<u32>, Vec<(FlatToken, Spacing)>); +type ReplaceRange = (Range<u32>, Option<AttrsTarget>); /// Controls how we capture tokens. Capturing can be expensive, /// so we try to avoid performing capturing in cases where @@ -1608,11 +1608,10 @@ enum FlatToken { /// A token - this holds both delimiter (e.g. '{' and '}') /// and non-delimiter tokens Token(Token), - /// Holds the `AttributesData` for an AST node. The - /// `AttributesData` is inserted directly into the - /// constructed `AttrTokenStream` as - /// an `AttrTokenTree::Attributes`. - AttrTarget(AttributesData), + /// Holds the `AttrsTarget` for an AST node. The `AttrsTarget` is inserted + /// directly into the constructed `AttrTokenStream` as an + /// `AttrTokenTree::AttrsTarget`. + AttrsTarget(AttrsTarget), /// A special 'empty' token that is ignored during the conversion /// to an `AttrTokenStream`. This is used to simplify the /// handling of replace ranges. diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index 6ea0ed339a6..55514883cb1 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -277,7 +277,10 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { pats: &[hir::PatField<'_>], ) { let variant = match self.typeck_results().node_type(lhs.hir_id).kind() { - ty::Adt(adt, _) => adt.variant_of_res(res), + ty::Adt(adt, _) => { + self.check_def_id(adt.did()); + adt.variant_of_res(res) + } _ => span_bug!(lhs.span, "non-ADT in struct pattern"), }; for pat in pats { @@ -297,7 +300,10 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { dotdot: hir::DotDotPos, ) { let variant = match self.typeck_results().node_type(lhs.hir_id).kind() { - ty::Adt(adt, _) => adt.variant_of_res(res), + ty::Adt(adt, _) => { + self.check_def_id(adt.did()); + adt.variant_of_res(res) + } _ => { self.tcx.dcx().span_delayed_bug(lhs.span, "non-ADT in tuple struct pattern"); return; @@ -402,31 +408,6 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { return false; } - // don't ignore impls for Enums and pub Structs whose methods don't have self receiver, - // cause external crate may call such methods to construct values of these types - if let Some(local_impl_of) = impl_of.as_local() - && let Some(local_def_id) = def_id.as_local() - && let Some(fn_sig) = - self.tcx.hir().fn_sig_by_hir_id(self.tcx.local_def_id_to_hir_id(local_def_id)) - && matches!(fn_sig.decl.implicit_self, hir::ImplicitSelfKind::None) - && let TyKind::Path(hir::QPath::Resolved(_, path)) = - self.tcx.hir().expect_item(local_impl_of).expect_impl().self_ty.kind - && let Res::Def(def_kind, did) = path.res - { - match def_kind { - // for example, #[derive(Default)] pub struct T(i32); - // external crate can call T::default() to construct T, - // so that don't ignore impl Default for pub Enum and Structs - DefKind::Struct | DefKind::Union if self.tcx.visibility(did).is_public() => { - return false; - } - // don't ignore impl Default for Enums, - // cause we don't know which variant is constructed - DefKind::Enum => return false, - _ => (), - }; - } - if let Some(trait_of) = self.tcx.trait_id_of_impl(impl_of) && self.tcx.has_attr(trait_of, sym::rustc_trivial_field_reads) { @@ -690,6 +671,9 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> { self.handle_field_pattern_match(pat, res, fields); } PatKind::Path(ref qpath) => { + if let ty::Adt(adt, _) = self.typeck_results().node_type(pat.hir_id).kind() { + self.check_def_id(adt.did()); + } let res = self.typeck_results().qpath_res(qpath, pat.hir_id); self.handle_res(res); } @@ -845,7 +829,7 @@ fn check_item<'tcx>( // mark the method live if the self_ty is public, // or the method is public and may construct self if tcx.visibility(local_def_id).is_public() - && (ty_and_all_fields_are_public || may_construct_self) + && (ty_and_all_fields_are_public || (ty_is_public && may_construct_self)) { // if the impl item is public, // and the ty may be constructed or can be constructed in foreign crates, diff --git a/compiler/rustc_passes/src/reachable.rs b/compiler/rustc_passes/src/reachable.rs index 6dd8eaf7e67..dee8ba7e87d 100644 --- a/compiler/rustc_passes/src/reachable.rs +++ b/compiler/rustc_passes/src/reachable.rs @@ -310,7 +310,7 @@ impl<'tcx> ReachableContext<'tcx> { GlobalAlloc::Static(def_id) => { self.propagate_item(Res::Def(self.tcx.def_kind(def_id), def_id)) } - GlobalAlloc::Function(instance) => { + GlobalAlloc::Function { instance, .. } => { // Manually visit to actually see the instance's `DefId`. Type visitors won't see it self.propagate_item(Res::Def( self.tcx.def_kind(instance.def_id()), diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index 80619c59cc3..a4fdb4a0baf 100644 --- a/compiler/rustc_resolve/src/def_collector.rs +++ b/compiler/rustc_resolve/src/def_collector.rs @@ -8,6 +8,7 @@ use rustc_hir::def_id::LocalDefId; use rustc_span::hygiene::LocalExpnId; use rustc_span::symbol::{kw, sym, Symbol}; use rustc_span::Span; +use std::mem; use tracing::debug; pub(crate) fn collect_definitions( @@ -15,8 +16,9 @@ pub(crate) fn collect_definitions( fragment: &AstFragment, expansion: LocalExpnId, ) { - let (parent_def, impl_trait_context) = resolver.invocation_parents[&expansion]; - fragment.visit_with(&mut DefCollector { resolver, parent_def, expansion, impl_trait_context }); + let (parent_def, impl_trait_context, in_attr) = resolver.invocation_parents[&expansion]; + let mut visitor = DefCollector { resolver, parent_def, expansion, impl_trait_context, in_attr }; + fragment.visit_with(&mut visitor); } /// Creates `DefId`s for nodes in the AST. @@ -24,6 +26,7 @@ struct DefCollector<'a, 'b, 'tcx> { resolver: &'a mut Resolver<'b, 'tcx>, parent_def: LocalDefId, impl_trait_context: ImplTraitContext, + in_attr: bool, expansion: LocalExpnId, } @@ -53,7 +56,7 @@ impl<'a, 'b, 'tcx> DefCollector<'a, 'b, 'tcx> { } fn with_parent<F: FnOnce(&mut Self)>(&mut self, parent_def: LocalDefId, f: F) { - let orig_parent_def = std::mem::replace(&mut self.parent_def, parent_def); + let orig_parent_def = mem::replace(&mut self.parent_def, parent_def); f(self); self.parent_def = orig_parent_def; } @@ -63,7 +66,7 @@ impl<'a, 'b, 'tcx> DefCollector<'a, 'b, 'tcx> { impl_trait_context: ImplTraitContext, f: F, ) { - let orig_itc = std::mem::replace(&mut self.impl_trait_context, impl_trait_context); + let orig_itc = mem::replace(&mut self.impl_trait_context, impl_trait_context); f(self); self.impl_trait_context = orig_itc; } @@ -105,8 +108,10 @@ impl<'a, 'b, 'tcx> DefCollector<'a, 'b, 'tcx> { fn visit_macro_invoc(&mut self, id: NodeId) { let id = id.placeholder_to_expn_id(); - let old_parent = - self.resolver.invocation_parents.insert(id, (self.parent_def, self.impl_trait_context)); + let old_parent = self + .resolver + .invocation_parents + .insert(id, (self.parent_def, self.impl_trait_context, self.in_attr)); assert!(old_parent.is_none(), "parent `LocalDefId` is reset for an invocation"); } } @@ -413,4 +418,10 @@ impl<'a, 'b, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'b, 'tcx> { visit::walk_crate(self, krate) } } + + fn visit_attribute(&mut self, attr: &'a Attribute) -> Self::Result { + let orig_in_attr = mem::replace(&mut self.in_attr, true); + visit::walk_attribute(self, attr); + self.in_attr = orig_in_attr; + } } diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index ad4e222f4de..1d37264f96a 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -1744,7 +1744,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { ) { self.r.dcx().emit_err(errors::LendingIteratorReportError { lifetime: lifetime.ident.span, - ty: ty.span(), + ty: ty.span, }); } else { self.r.dcx().emit_err(errors::AnonymousLivetimeNonGatReportError { diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 38963ef4ef0..610cb1d2aad 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -1139,7 +1139,7 @@ pub struct Resolver<'a, 'tcx> { /// When collecting definitions from an AST fragment produced by a macro invocation `ExpnId` /// we know what parent node that fragment should be attached to thanks to this table, /// and how the `impl Trait` fragments were introduced. - invocation_parents: FxHashMap<LocalExpnId, (LocalDefId, ImplTraitContext)>, + invocation_parents: FxHashMap<LocalExpnId, (LocalDefId, ImplTraitContext, bool /*in_attr*/)>, /// Some way to know that we are in a *trait* impl in `visit_assoc_item`. /// FIXME: Replace with a more general AST map (together with some other fields). @@ -1371,7 +1371,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { node_id_to_def_id.insert(CRATE_NODE_ID, crate_feed); let mut invocation_parents = FxHashMap::default(); - invocation_parents.insert(LocalExpnId::ROOT, (CRATE_DEF_ID, ImplTraitContext::Existential)); + invocation_parents + .insert(LocalExpnId::ROOT, (CRATE_DEF_ID, ImplTraitContext::Existential, false)); let mut extern_prelude: FxHashMap<Ident, ExternPreludeEntry<'_>> = tcx .sess diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index 026a2ca1412..cb9bebd33d3 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -297,11 +297,12 @@ impl<'a, 'tcx> ResolverExpand for Resolver<'a, 'tcx> { .invocation_parents .get(&invoc_id) .or_else(|| self.invocation_parents.get(&eager_expansion_root)) - .map(|&(mod_def_id, _)| mod_def_id) - .filter(|&mod_def_id| { - invoc.fragment_kind == AstFragmentKind::Expr + .filter(|&&(mod_def_id, _, in_attr)| { + in_attr + && invoc.fragment_kind == AstFragmentKind::Expr && self.tcx.def_kind(mod_def_id) == DefKind::Mod - }); + }) + .map(|&(mod_def_id, ..)| mod_def_id); let (ext, res) = self.smart_resolve_macro_path( path, kind, diff --git a/compiler/rustc_smir/src/rustc_smir/convert/mir.rs b/compiler/rustc_smir/src/rustc_smir/convert/mir.rs index f15b82d0c03..9d5a14b5145 100644 --- a/compiler/rustc_smir/src/rustc_smir/convert/mir.rs +++ b/compiler/rustc_smir/src/rustc_smir/convert/mir.rs @@ -709,7 +709,7 @@ impl<'tcx> Stable<'tcx> for mir::interpret::GlobalAlloc<'tcx> { fn stable(&self, tables: &mut Tables<'_>) -> Self::T { match self { - mir::interpret::GlobalAlloc::Function(instance) => { + mir::interpret::GlobalAlloc::Function { instance, .. } => { GlobalAlloc::Function(instance.stable(tables)) } mir::interpret::GlobalAlloc::VTable(ty, trait_ref) => { diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 7da9211bcbf..af56f4e5141 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1513,6 +1513,7 @@ symbols! { recursion_limit, reexport_test_harness_main, ref_pat_eat_one_layer_2024, + ref_pat_eat_one_layer_2024_structural, ref_pat_everywhere, ref_unwind_safe_trait, reference, diff --git a/compiler/rustc_trait_selection/src/infer.rs b/compiler/rustc_trait_selection/src/infer.rs index c95649e2ffb..ad087620ae0 100644 --- a/compiler/rustc_trait_selection/src/infer.rs +++ b/compiler/rustc_trait_selection/src/infer.rs @@ -1,3 +1,4 @@ +use crate::infer::at::ToTrace; use crate::traits::query::evaluate_obligation::InferCtxtExt as _; use crate::traits::{self, Obligation, ObligationCause, ObligationCtxt, SelectionContext}; @@ -17,6 +18,16 @@ pub use rustc_infer::infer::*; #[extension(pub trait InferCtxtExt<'tcx>)] impl<'tcx> InferCtxt<'tcx> { + fn can_eq<T: ToTrace<'tcx>>(&self, param_env: ty::ParamEnv<'tcx>, a: T, b: T) -> bool { + self.probe(|_| { + let ocx = ObligationCtxt::new(self); + let Ok(()) = ocx.eq(&ObligationCause::dummy(), param_env, a, b) else { + return false; + }; + ocx.select_where_possible().is_empty() + }) + } + fn type_is_copy_modulo_regions(&self, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> bool { let ty = self.resolve_vars_if_possible(ty); diff --git a/compiler/rustc_trait_selection/src/solve/delegate.rs b/compiler/rustc_trait_selection/src/solve/delegate.rs index 643d5f80480..f98744e906f 100644 --- a/compiler/rustc_trait_selection/src/solve/delegate.rs +++ b/compiler/rustc_trait_selection/src/solve/delegate.rs @@ -1,21 +1,18 @@ use std::ops::Deref; use rustc_data_structures::fx::FxHashSet; -use rustc_hir::def_id::{DefId, LocalDefId}; +use rustc_hir::def_id::DefId; use rustc_infer::infer::canonical::query_response::make_query_region_constraints; use rustc_infer::infer::canonical::{ Canonical, CanonicalExt as _, CanonicalVarInfo, CanonicalVarValues, }; -use rustc_infer::infer::{ - BoundRegionConversionTime, InferCtxt, RegionVariableOrigin, SubregionOrigin, TyCtxtInferExt, -}; +use rustc_infer::infer::{InferCtxt, RegionVariableOrigin, TyCtxtInferExt}; use rustc_infer::traits::solve::Goal; use rustc_infer::traits::util::supertraits; use rustc_infer::traits::{ObligationCause, Reveal}; use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt as _}; use rustc_span::{ErrorGuaranteed, Span, DUMMY_SP}; -use rustc_type_ir::relate::Relate; use rustc_type_ir::solve::{Certainty, NoSolution, SolverMode}; use crate::traits::coherence::trait_ref_is_knowable; @@ -48,13 +45,6 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate< type Span = Span; - fn solver_mode(&self) -> ty::solve::SolverMode { - match self.intercrate { - true => SolverMode::Coherence, - false => SolverMode::Normal, - } - } - fn build_with_canonical<V>( interner: TyCtxt<'tcx>, solver_mode: SolverMode, @@ -74,104 +64,6 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate< (SolverDelegate(infcx), value, vars) } - fn universe(&self) -> ty::UniverseIndex { - self.0.universe() - } - - fn create_next_universe(&self) -> ty::UniverseIndex { - self.0.create_next_universe() - } - - fn universe_of_ty(&self, vid: ty::TyVid) -> Option<ty::UniverseIndex> { - // FIXME(BoxyUwU): this is kind of jank and means that printing unresolved - // ty infers will give you the universe of the var it resolved to not the universe - // it actually had. It also means that if you have a `?0.1` and infer it to `u8` then - // try to print out `?0.1` it will just print `?0`. - match self.0.probe_ty_var(vid) { - Err(universe) => Some(universe), - Ok(_) => None, - } - } - - fn universe_of_lt(&self, lt: ty::RegionVid) -> Option<ty::UniverseIndex> { - match self.0.inner.borrow_mut().unwrap_region_constraints().probe_value(lt) { - Err(universe) => Some(universe), - Ok(_) => None, - } - } - - fn universe_of_ct(&self, ct: ty::ConstVid) -> Option<ty::UniverseIndex> { - // Same issue as with `universe_of_ty` - match self.0.probe_const_var(ct) { - Err(universe) => Some(universe), - Ok(_) => None, - } - } - - fn root_ty_var(&self, var: ty::TyVid) -> ty::TyVid { - self.0.root_var(var) - } - - fn root_const_var(&self, var: ty::ConstVid) -> ty::ConstVid { - self.0.root_const_var(var) - } - - fn opportunistic_resolve_ty_var(&self, vid: ty::TyVid) -> Ty<'tcx> { - match self.0.probe_ty_var(vid) { - Ok(ty) => ty, - Err(_) => Ty::new_var(self.0.tcx, self.0.root_var(vid)), - } - } - - fn opportunistic_resolve_int_var(&self, vid: ty::IntVid) -> Ty<'tcx> { - self.0.opportunistic_resolve_int_var(vid) - } - - fn opportunistic_resolve_float_var(&self, vid: ty::FloatVid) -> Ty<'tcx> { - self.0.opportunistic_resolve_float_var(vid) - } - - fn opportunistic_resolve_ct_var(&self, vid: ty::ConstVid) -> ty::Const<'tcx> { - match self.0.probe_const_var(vid) { - Ok(ct) => ct, - Err(_) => ty::Const::new_var(self.0.tcx, self.0.root_const_var(vid)), - } - } - - fn opportunistic_resolve_effect_var(&self, vid: ty::EffectVid) -> ty::Const<'tcx> { - match self.0.probe_effect_var(vid) { - Some(ct) => ct, - None => ty::Const::new_infer( - self.0.tcx, - ty::InferConst::EffectVar(self.0.root_effect_var(vid)), - ), - } - } - - fn opportunistic_resolve_lt_var(&self, vid: ty::RegionVid) -> ty::Region<'tcx> { - self.0 - .inner - .borrow_mut() - .unwrap_region_constraints() - .opportunistic_resolve_var(self.0.tcx, vid) - } - - fn defining_opaque_types(&self) -> &'tcx ty::List<LocalDefId> { - self.0.defining_opaque_types() - } - - fn next_ty_infer(&self) -> Ty<'tcx> { - self.0.next_ty_var(DUMMY_SP) - } - - fn next_const_infer(&self) -> ty::Const<'tcx> { - self.0.next_const_var(DUMMY_SP) - } - - fn fresh_args_for_item(&self, def_id: DefId) -> ty::GenericArgsRef<'tcx> { - self.0.fresh_args_for_item(DUMMY_SP, def_id) - } - fn fresh_var_for_kind_with_span( &self, arg: ty::GenericArg<'tcx>, @@ -186,57 +78,6 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate< } } - fn instantiate_binder_with_infer<T: TypeFoldable<TyCtxt<'tcx>> + Copy>( - &self, - value: ty::Binder<'tcx, T>, - ) -> T { - self.0.instantiate_binder_with_fresh_vars( - DUMMY_SP, - BoundRegionConversionTime::HigherRankedType, - value, - ) - } - - fn enter_forall<T: TypeFoldable<TyCtxt<'tcx>> + Copy, U>( - &self, - value: ty::Binder<'tcx, T>, - f: impl FnOnce(T) -> U, - ) -> U { - self.0.enter_forall(value, f) - } - - fn relate<T: Relate<TyCtxt<'tcx>>>( - &self, - param_env: ty::ParamEnv<'tcx>, - lhs: T, - variance: ty::Variance, - rhs: T, - ) -> Result<Vec<Goal<'tcx, ty::Predicate<'tcx>>>, NoSolution> { - self.0.at(&ObligationCause::dummy(), param_env).relate_no_trace(lhs, variance, rhs) - } - - fn eq_structurally_relating_aliases<T: Relate<TyCtxt<'tcx>>>( - &self, - param_env: ty::ParamEnv<'tcx>, - lhs: T, - rhs: T, - ) -> Result<Vec<Goal<'tcx, ty::Predicate<'tcx>>>, NoSolution> { - self.0 - .at(&ObligationCause::dummy(), param_env) - .eq_structurally_relating_aliases_no_trace(lhs, rhs) - } - - fn resolve_vars_if_possible<T>(&self, value: T) -> T - where - T: TypeFoldable<TyCtxt<'tcx>>, - { - self.0.resolve_vars_if_possible(value) - } - - fn probe<T>(&self, probe: impl FnOnce() -> T) -> T { - self.0.probe(|_| probe()) - } - fn leak_check(&self, max_input_universe: ty::UniverseIndex) -> Result<(), NoSolution> { self.0.leak_check(max_input_universe, None).map_err(|_| NoSolution) } @@ -265,14 +106,6 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate< } } - fn sub_regions(&self, sub: ty::Region<'tcx>, sup: ty::Region<'tcx>) { - self.0.sub_regions(SubregionOrigin::RelateRegionParamBound(DUMMY_SP), sub, sup) - } - - fn register_ty_outlives(&self, ty: Ty<'tcx>, r: ty::Region<'tcx>) { - self.0.register_region_obligation_with_cause(ty, r, &ObligationCause::dummy()); - } - fn well_formed_goals( &self, param_env: ty::ParamEnv<'tcx>, 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 32c8a454b40..94b28426f43 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 @@ -1,5 +1,10 @@ use super::{ObligationCauseCode, PredicateObligation}; +use crate::errors::{ + EmptyOnClauseInOnUnimplemented, InvalidOnClauseInOnUnimplemented, NoValueInOnUnimplemented, +}; use crate::infer::error_reporting::TypeErrCtxt; +use crate::infer::InferCtxtExt; +use crate::traits::error_reporting::type_err_ctxt_ext::InferCtxtPrivExt; use rustc_ast::AttrArgs; use rustc_ast::AttrArgsEq; use rustc_ast::AttrKind; @@ -21,12 +26,6 @@ use rustc_span::Span; use std::iter; use std::path::PathBuf; -use crate::errors::{ - EmptyOnClauseInOnUnimplemented, InvalidOnClauseInOnUnimplemented, NoValueInOnUnimplemented, -}; - -use crate::traits::error_reporting::type_err_ctxt_ext::InferCtxtPrivExt; - /// The symbols which are always allowed in a format string static ALLOWED_FORMAT_SYMBOLS: &[Symbol] = &[ kw::SelfUpper, 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 a0a8e5963f1..52edffce614 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -3472,6 +3472,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ) }); } + // Suppress `compare_type_predicate_entailment` errors for RPITITs, since they + // should be implied by the parent method. + ObligationCauseCode::CompareImplItem { trait_item_def_id, .. } + if tcx.is_impl_trait_in_trait(trait_item_def_id) => {} ObligationCauseCode::CompareImplItem { trait_item_def_id, kind, .. } => { let item_name = tcx.item_name(trait_item_def_id); let msg = format!( 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 17b6dd2bc58..5461f9e65af 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 @@ -1073,7 +1073,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { // mismatched, then we have a totally different error to report. if self.enter_forall(found_args, |found_args| { self.enter_forall(expected_args, |expected_args| { - !self.can_sub(obligation.param_env, expected_args, found_args) + !self.can_eq(obligation.param_env, expected_args, found_args) }) }) { return None; diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs index f1611bd049d..5b2c8fb1950 100644 --- a/compiler/rustc_trait_selection/src/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -805,10 +805,11 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeVisitable<TyCtxt<'tcx>>>( .unwrap() .contains(&data.trait_ref(self.tcx).def_id); + // only walk contained types if it's not a super trait if is_supertrait_of_current_trait { - ControlFlow::Continue(()) // do not walk contained types, do not report error, do collect $200 + ControlFlow::Continue(()) } else { - t.super_visit_with(self) // DO walk contained types, POSSIBLY reporting an error + t.super_visit_with(self) // POSSIBLY reporting an error } } _ => t.super_visit_with(self), // walk contained types, if any 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 b38841db923..8525215a3bc 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 @@ -3,7 +3,6 @@ use crate::traits::wf; use crate::traits::ObligationCtxt; use rustc_infer::infer::canonical::Canonical; -use rustc_infer::infer::outlives::components::{push_outlives_components, Component}; use rustc_infer::infer::resolve::OpportunisticRegionResolver; use rustc_infer::traits::query::OutlivesBound; use rustc_macros::{HashStable, TypeFoldable, TypeVisitable}; @@ -12,6 +11,7 @@ use rustc_middle::traits::ObligationCause; use rustc_middle::ty::{self, ParamEnvAnd, Ty, TyCtxt, TypeFolder, TypeVisitableExt}; use rustc_span::def_id::CRATE_DEF_ID; use rustc_span::DUMMY_SP; +use rustc_type_ir::outlives::{push_outlives_components, Component}; use smallvec::{smallvec, SmallVec}; #[derive(Copy, Clone, Debug, HashStable, TypeFoldable, TypeVisitable)] @@ -284,7 +284,7 @@ pub fn compute_implied_outlives_bounds_compat_inner<'tcx>( /// those relationships. fn implied_bounds_from_components<'tcx>( sub_region: ty::Region<'tcx>, - sup_components: SmallVec<[Component<'tcx>; 4]>, + sup_components: SmallVec<[Component<TyCtxt<'tcx>>; 4]>, ) -> Vec<OutlivesBound<'tcx>> { sup_components .into_iter() diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 68cc04bc8e6..fa130420174 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -18,7 +18,7 @@ use super::{ TraitQueryMode, }; -use crate::infer::{InferCtxt, InferOk, TypeFreshener}; +use crate::infer::{InferCtxt, InferCtxtExt, InferOk, TypeFreshener}; use crate::solve::InferCtxtSelectExt as _; use crate::traits::error_reporting::TypeErrCtxtExt; use crate::traits::normalize::normalize_with_depth; diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index e3952679f96..f071dc6c784 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -640,8 +640,6 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { } impl<'a, 'tcx> TypeVisitor<TyCtxt<'tcx>> for WfPredicates<'a, 'tcx> { - type Result = (); - fn visit_ty(&mut self, t: Ty<'tcx>) -> Self::Result { debug!("wf bounds for t={:?} t.kind={:#?}", t, t.kind()); diff --git a/compiler/rustc_type_ir/src/infer_ctxt.rs b/compiler/rustc_type_ir/src/infer_ctxt.rs new file mode 100644 index 00000000000..2c80ee0a73d --- /dev/null +++ b/compiler/rustc_type_ir/src/infer_ctxt.rs @@ -0,0 +1,93 @@ +use crate::fold::TypeFoldable; +use crate::relate::Relate; +use crate::solve::{Goal, NoSolution, SolverMode}; +use crate::{self as ty, Interner}; + +pub trait InferCtxtLike { + type Interner: Interner; + fn cx(&self) -> Self::Interner; + + fn solver_mode(&self) -> SolverMode; + + fn universe(&self) -> ty::UniverseIndex; + fn create_next_universe(&self) -> ty::UniverseIndex; + + fn universe_of_ty(&self, ty: ty::TyVid) -> Option<ty::UniverseIndex>; + fn universe_of_lt(&self, lt: ty::RegionVid) -> Option<ty::UniverseIndex>; + fn universe_of_ct(&self, ct: ty::ConstVid) -> Option<ty::UniverseIndex>; + + fn root_ty_var(&self, var: ty::TyVid) -> ty::TyVid; + fn root_const_var(&self, var: ty::ConstVid) -> ty::ConstVid; + + fn opportunistic_resolve_ty_var(&self, vid: ty::TyVid) -> <Self::Interner as Interner>::Ty; + fn opportunistic_resolve_int_var(&self, vid: ty::IntVid) -> <Self::Interner as Interner>::Ty; + fn opportunistic_resolve_float_var( + &self, + vid: ty::FloatVid, + ) -> <Self::Interner as Interner>::Ty; + fn opportunistic_resolve_ct_var( + &self, + vid: ty::ConstVid, + ) -> <Self::Interner as Interner>::Const; + fn opportunistic_resolve_effect_var( + &self, + vid: ty::EffectVid, + ) -> <Self::Interner as Interner>::Const; + fn opportunistic_resolve_lt_var( + &self, + vid: ty::RegionVid, + ) -> <Self::Interner as Interner>::Region; + + fn defining_opaque_types(&self) -> <Self::Interner as Interner>::DefiningOpaqueTypes; + + fn next_ty_infer(&self) -> <Self::Interner as Interner>::Ty; + fn next_const_infer(&self) -> <Self::Interner as Interner>::Const; + fn fresh_args_for_item( + &self, + def_id: <Self::Interner as Interner>::DefId, + ) -> <Self::Interner as Interner>::GenericArgs; + + fn instantiate_binder_with_infer<T: TypeFoldable<Self::Interner> + Copy>( + &self, + value: ty::Binder<Self::Interner, T>, + ) -> T; + + fn enter_forall<T: TypeFoldable<Self::Interner> + Copy, U>( + &self, + value: ty::Binder<Self::Interner, T>, + f: impl FnOnce(T) -> U, + ) -> U; + + fn relate<T: Relate<Self::Interner>>( + &self, + param_env: <Self::Interner as Interner>::ParamEnv, + lhs: T, + variance: ty::Variance, + rhs: T, + ) -> Result<Vec<Goal<Self::Interner, <Self::Interner as Interner>::Predicate>>, NoSolution>; + + fn eq_structurally_relating_aliases<T: Relate<Self::Interner>>( + &self, + param_env: <Self::Interner as Interner>::ParamEnv, + lhs: T, + rhs: T, + ) -> Result<Vec<Goal<Self::Interner, <Self::Interner as Interner>::Predicate>>, NoSolution>; + + fn resolve_vars_if_possible<T>(&self, value: T) -> T + where + T: TypeFoldable<Self::Interner>; + + fn probe<T>(&self, probe: impl FnOnce() -> T) -> T; + + fn sub_regions( + &self, + sub: <Self::Interner as Interner>::Region, + sup: <Self::Interner as Interner>::Region, + ); + + fn register_ty_outlives( + &self, + ty: <Self::Interner as Interner>::Ty, + r: <Self::Interner as Interner>::Region, + ); +} diff --git a/compiler/rustc_type_ir/src/inherent.rs b/compiler/rustc_type_ir/src/inherent.rs index ffe16964ae5..68c2575258d 100644 --- a/compiler/rustc_type_ir/src/inherent.rs +++ b/compiler/rustc_type_ir/src/inherent.rs @@ -232,6 +232,10 @@ pub trait Region<I: Interner<Region = Self>>: fn new_anon_bound(interner: I, debruijn: ty::DebruijnIndex, var: ty::BoundVar) -> Self; fn new_static(interner: I) -> Self; + + fn is_bound(self) -> bool { + matches!(self.kind(), ty::ReBound(..)) + } } pub trait Const<I: Interner<Const = Self>>: @@ -272,6 +276,10 @@ pub trait Const<I: Interner<Const = Self>>: } } +pub trait ExprConst<I: Interner<ExprConst = Self>>: Copy + Debug + Hash + Eq + Relate<I> { + fn args(self) -> I::GenericArgs; +} + pub trait GenericsOf<I: Interner<GenericsOf = Self>> { fn count(&self) -> usize; } diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index db97bdca382..6e013768c3e 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -32,6 +32,7 @@ pub trait Interner: { type DefId: DefId<Self>; type LocalDefId: Copy + Debug + Hash + Eq + Into<Self::DefId> + TypeFoldable<Self>; + type Span: Copy + Debug + Hash + Eq; type GenericArgs: GenericArgs<Self>; type GenericArgsSlice: Copy + Debug + Hash + Eq + SliceLike<Item = Self::GenericArg>; @@ -109,7 +110,7 @@ pub trait Interner: type ParamConst: Copy + Debug + Hash + Eq + ParamLike; type BoundConst: Copy + Debug + Hash + Eq + BoundVarLike<Self>; type ValueConst: Copy + Debug + Hash + Eq; - type ExprConst: Copy + Debug + Hash + Eq + Relate<Self>; + type ExprConst: ExprConst<Self>; // Kinds of regions type Region: Region<Self>; diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs index 1b5529cd8db..2a909b06baf 100644 --- a/compiler/rustc_type_ir/src/lib.rs +++ b/compiler/rustc_type_ir/src/lib.rs @@ -2,7 +2,7 @@ #![allow(rustc::usage_of_ty_tykind)] #![cfg_attr( feature = "nightly", - feature(associated_type_defaults, min_specialization, never_type, rustc_attrs, negative_impls) + feature(associated_type_defaults, never_type, rustc_attrs, negative_impls) )] #![cfg_attr(feature = "nightly", allow(internal_features))] // tidy-alphabetical-end @@ -27,6 +27,7 @@ pub mod inherent; pub mod ir_print; pub mod lang_items; pub mod lift; +pub mod outlives; pub mod relate; pub mod solve; @@ -39,6 +40,7 @@ mod const_kind; mod effects; mod flags; mod generic_arg; +mod infer_ctxt; mod interner; mod opaque_ty; mod predicate; @@ -56,6 +58,7 @@ pub use const_kind::*; pub use effects::*; pub use flags::*; pub use generic_arg::*; +pub use infer_ctxt::*; pub use interner::*; pub use opaque_ty::*; pub use predicate::*; diff --git a/compiler/rustc_type_ir/src/outlives.rs b/compiler/rustc_type_ir/src/outlives.rs new file mode 100644 index 00000000000..61dfa2643d8 --- /dev/null +++ b/compiler/rustc_type_ir/src/outlives.rs @@ -0,0 +1,335 @@ +//! The outlives relation `T: 'a` or `'a: 'b`. This code frequently +//! refers to rules defined in RFC 1214 (`OutlivesFooBar`), so see that +//! RFC for reference. + +use smallvec::{smallvec, SmallVec}; +use tracing::debug; + +use crate::data_structures::SsoHashSet; +use crate::inherent::*; +use crate::visit::TypeVisitableExt as _; +use crate::{self as ty, Interner}; + +#[derive(derivative::Derivative)] +#[derivative(Debug(bound = ""))] +pub enum Component<I: Interner> { + Region(I::Region), + Param(I::ParamTy), + Placeholder(I::PlaceholderTy), + UnresolvedInferenceVariable(ty::InferTy), + + // Projections like `T::Foo` are tricky because a constraint like + // `T::Foo: 'a` can be satisfied in so many ways. There may be a + // where-clause that says `T::Foo: 'a`, or the defining trait may + // include a bound like `type Foo: 'static`, or -- in the most + // conservative way -- we can prove that `T: 'a` (more generally, + // that all components in the projection outlive `'a`). This code + // is not in a position to judge which is the best technique, so + // we just product the projection as a component and leave it to + // the consumer to decide (but see `EscapingProjection` below). + Alias(ty::AliasTy<I>), + + // In the case where a projection has escaping regions -- meaning + // regions bound within the type itself -- we always use + // the most conservative rule, which requires that all components + // outlive the bound. So for example if we had a type like this: + // + // for<'a> Trait1< <T as Trait2<'a,'b>>::Foo > + // ~~~~~~~~~~~~~~~~~~~~~~~~~ + // + // then the inner projection (underlined) has an escaping region + // `'a`. We consider that outer trait `'c` to meet a bound if `'b` + // outlives `'b: 'c`, and we don't consider whether the trait + // declares that `Foo: 'static` etc. Therefore, we just return the + // free components of such a projection (in this case, `'b`). + // + // However, in the future, we may want to get smarter, and + // actually return a "higher-ranked projection" here. Therefore, + // we mark that these components are part of an escaping + // projection, so that implied bounds code can avoid relying on + // them. This gives us room to improve the regionck reasoning in + // the future without breaking backwards compat. + EscapingAlias(Vec<Component<I>>), +} + +/// Push onto `out` all the things that must outlive `'a` for the condition +/// `ty0: 'a` to hold. Note that `ty0` must be a **fully resolved type**. +pub fn push_outlives_components<I: Interner>( + tcx: I, + ty0: I::Ty, + out: &mut SmallVec<[Component<I>; 4]>, +) { + let mut visited = SsoHashSet::new(); + compute_components_for_ty(tcx, ty0, out, &mut visited); + debug!("components({:?}) = {:?}", ty0, out); +} + +fn compute_components_for_arg<I: Interner>( + tcx: I, + arg: I::GenericArg, + out: &mut SmallVec<[Component<I>; 4]>, + visited: &mut SsoHashSet<I::GenericArg>, +) { + match arg.kind() { + ty::GenericArgKind::Type(ty) => { + compute_components_for_ty(tcx, ty, out, visited); + } + ty::GenericArgKind::Lifetime(lt) => { + compute_components_for_lt(lt, out); + } + ty::GenericArgKind::Const(ct) => { + compute_components_for_const(tcx, ct, out, visited); + } + } +} + +fn compute_components_for_ty<I: Interner>( + tcx: I, + ty: I::Ty, + out: &mut SmallVec<[Component<I>; 4]>, + visited: &mut SsoHashSet<I::GenericArg>, +) { + if !visited.insert(ty.into()) { + return; + } + // Descend through the types, looking for the various "base" + // components and collecting them into `out`. This is not written + // with `collect()` because of the need to sometimes skip subtrees + // in the `subtys` iterator (e.g., when encountering a + // projection). + match ty.kind() { + ty::FnDef(_, args) => { + // HACK(eddyb) ignore lifetimes found shallowly in `args`. + // This is inconsistent with `ty::Adt` (including all args) + // and with `ty::Closure` (ignoring all args other than + // upvars, of which a `ty::FnDef` doesn't have any), but + // consistent with previous (accidental) behavior. + // See https://github.com/rust-lang/rust/issues/70917 + // for further background and discussion. + for child in args.iter() { + match child.kind() { + ty::GenericArgKind::Type(ty) => { + compute_components_for_ty(tcx, ty, out, visited); + } + ty::GenericArgKind::Lifetime(_) => {} + ty::GenericArgKind::Const(ct) => { + compute_components_for_const(tcx, ct, out, visited); + } + } + } + } + + ty::Pat(element, _) | ty::Array(element, _) => { + compute_components_for_ty(tcx, element, out, visited); + } + + ty::Closure(_, args) => { + let tupled_ty = args.as_closure().tupled_upvars_ty(); + compute_components_for_ty(tcx, tupled_ty, out, visited); + } + + ty::CoroutineClosure(_, args) => { + let tupled_ty = args.as_coroutine_closure().tupled_upvars_ty(); + compute_components_for_ty(tcx, tupled_ty, out, visited); + } + + ty::Coroutine(_, args) => { + // Same as the closure case + let tupled_ty = args.as_coroutine().tupled_upvars_ty(); + compute_components_for_ty(tcx, tupled_ty, out, visited); + + // We ignore regions in the coroutine interior as we don't + // want these to affect region inference + } + + // All regions are bound inside a witness, and we don't emit + // higher-ranked outlives components currently. + ty::CoroutineWitness(..) => {}, + + // OutlivesTypeParameterEnv -- the actual checking that `X:'a` + // is implied by the environment is done in regionck. + ty::Param(p) => { + out.push(Component::Param(p)); + } + + ty::Placeholder(p) => { + out.push(Component::Placeholder(p)); + } + + // For projections, we prefer to generate an obligation like + // `<P0 as Trait<P1...Pn>>::Foo: 'a`, because this gives the + // regionck more ways to prove that it holds. However, + // regionck is not (at least currently) prepared to deal with + // higher-ranked regions that may appear in the + // trait-ref. Therefore, if we see any higher-ranked regions, + // we simply fallback to the most restrictive rule, which + // requires that `Pi: 'a` for all `i`. + ty::Alias(_, alias_ty) => { + if !alias_ty.has_escaping_bound_vars() { + // best case: no escaping regions, so push the + // projection and skip the subtree (thus generating no + // constraints for Pi). This defers the choice between + // the rules OutlivesProjectionEnv, + // OutlivesProjectionTraitDef, and + // OutlivesProjectionComponents to regionck. + out.push(Component::Alias(alias_ty)); + } else { + // fallback case: hard code + // OutlivesProjectionComponents. Continue walking + // through and constrain Pi. + let mut subcomponents = smallvec![]; + let mut subvisited = SsoHashSet::new(); + compute_alias_components_recursive(tcx, ty, &mut subcomponents, &mut subvisited); + out.push(Component::EscapingAlias(subcomponents.into_iter().collect())); + } + } + + // We assume that inference variables are fully resolved. + // So, if we encounter an inference variable, just record + // the unresolved variable as a component. + ty::Infer(infer_ty) => { + out.push(Component::UnresolvedInferenceVariable(infer_ty)); + } + + // Most types do not introduce any region binders, nor + // involve any other subtle cases, and so the WF relation + // simply constraints any regions referenced directly by + // the type and then visits the types that are lexically + // contained within. (The comments refer to relevant rules + // from RFC1214.) + + ty::Bool | // OutlivesScalar + ty::Char | // OutlivesScalar + ty::Int(..) | // OutlivesScalar + ty::Uint(..) | // OutlivesScalar + ty::Float(..) | // OutlivesScalar + ty::Never | // OutlivesScalar + ty::Foreign(..) | // OutlivesNominalType + ty::Str | // OutlivesScalar (ish) + ty::Bound(..) | + ty::Error(_) => { + // Trivial. + } + + // OutlivesNominalType + ty::Adt(_, args) => { + for arg in args.iter() { + compute_components_for_arg(tcx, arg, out, visited); + } + } + + // OutlivesNominalType + ty::Slice(ty) | + ty::RawPtr(ty, _) => { + compute_components_for_ty(tcx, ty, out, visited); + } + ty::Tuple(tys) => { + for ty in tys.iter() { + compute_components_for_ty(tcx, ty, out, visited); + } + } + + // OutlivesReference + ty::Ref(lt, ty, _) => { + compute_components_for_lt(lt, out); + compute_components_for_ty(tcx, ty, out, visited); + } + + ty::Dynamic(preds, lt, _) => { + compute_components_for_lt(lt, out); + for pred in preds.iter() { + match pred.skip_binder() { + ty::ExistentialPredicate::Trait(tr) => { + for arg in tr.args.iter() { + compute_components_for_arg(tcx, arg, out, visited); + } + } + ty::ExistentialPredicate::Projection(proj) => { + for arg in proj.args.iter() { + compute_components_for_arg(tcx, arg, out, visited); + } + match proj.term.kind() { + ty::TermKind::Ty(ty) => { + compute_components_for_ty(tcx, ty, out, visited) + } + ty::TermKind::Const(ct) => { + compute_components_for_const(tcx, ct, out, visited) + } + } + } + ty::ExistentialPredicate::AutoTrait(..) => {} + } + } + } + + ty::FnPtr(sig) => { + for ty in sig.skip_binder().inputs_and_output.iter() { + compute_components_for_ty(tcx, ty, out, visited); + } + } + } +} + +/// Collect [Component]s for *all* the args of `parent`. +/// +/// This should not be used to get the components of `parent` itself. +/// Use [push_outlives_components] instead. +pub fn compute_alias_components_recursive<I: Interner>( + tcx: I, + alias_ty: I::Ty, + out: &mut SmallVec<[Component<I>; 4]>, + visited: &mut SsoHashSet<I::GenericArg>, +) { + let ty::Alias(kind, alias_ty) = alias_ty.kind() else { + unreachable!("can only call `compute_alias_components_recursive` on an alias type") + }; + + let opt_variances = + if kind == ty::Opaque { Some(tcx.variances_of(alias_ty.def_id)) } else { None }; + + for (index, child) in alias_ty.args.iter().enumerate() { + if opt_variances.and_then(|variances| variances.get(index)) == Some(ty::Bivariant) { + continue; + } + compute_components_for_arg(tcx, child, out, visited); + } +} + +fn compute_components_for_lt<I: Interner>(lt: I::Region, out: &mut SmallVec<[Component<I>; 4]>) { + if !lt.is_bound() { + out.push(Component::Region(lt)); + } +} + +fn compute_components_for_const<I: Interner>( + tcx: I, + ct: I::Const, + out: &mut SmallVec<[Component<I>; 4]>, + visited: &mut SsoHashSet<I::GenericArg>, +) { + if !visited.insert(ct.into()) { + return; + } + match ct.kind() { + ty::ConstKind::Param(_) + | ty::ConstKind::Bound(_, _) + | ty::ConstKind::Infer(_) + | ty::ConstKind::Placeholder(_) + | ty::ConstKind::Error(_) => { + // Trivial + } + ty::ConstKind::Expr(e) => { + for arg in e.args().iter() { + compute_components_for_arg(tcx, arg, out, visited); + } + } + ty::ConstKind::Value(ty, _) => { + compute_components_for_ty(tcx, ty, out, visited); + } + ty::ConstKind::Unevaluated(uv) => { + for arg in uv.args.iter() { + compute_components_for_arg(tcx, arg, out, visited); + } + } + } +} |
