diff options
| author | The Miri Cronjob Bot <miri@cron.bot> | 2025-06-07 05:01:19 +0000 |
|---|---|---|
| committer | The Miri Cronjob Bot <miri@cron.bot> | 2025-06-07 05:01:19 +0000 |
| commit | 4c4904b54a2d9db26e8a164b8388c586c3c5fd16 (patch) | |
| tree | 432eb7bbe6cc257bcfdc879c7ab5dd0ed4603782 | |
| parent | cf5aea57cc741ad10a80841a3ec2fde52a939279 (diff) | |
| parent | 775e0c8aeb8f63192854b27156f8b05a06b51814 (diff) | |
| download | rust-4c4904b54a2d9db26e8a164b8388c586c3c5fd16.tar.gz rust-4c4904b54a2d9db26e8a164b8388c586c3c5fd16.zip | |
Merge from rustc
198 files changed, 3562 insertions, 3660 deletions
diff --git a/compiler/rustc_abi/src/canon_abi.rs b/compiler/rustc_abi/src/canon_abi.rs index 2cf7648a859..03eeb645489 100644 --- a/compiler/rustc_abi/src/canon_abi.rs +++ b/compiler/rustc_abi/src/canon_abi.rs @@ -50,18 +50,10 @@ pub enum CanonAbi { impl fmt::Display for CanonAbi { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.to_erased_extern_abi().as_str().fmt(f) - } -} - -impl CanonAbi { - /// convert to the ExternAbi that *shares a string* with this CanonAbi - /// - /// A target-insensitive mapping of CanonAbi to ExternAbi, convenient for "forwarding" impls. - /// Importantly, the set of CanonAbi values is a logical *subset* of ExternAbi values, - /// so this is injective: if you take an ExternAbi to a CanonAbi and back, you have lost data. - const fn to_erased_extern_abi(self) -> ExternAbi { - match self { + // convert to the ExternAbi that *shares a string* with this CanonAbi. + // FIXME: ideally we'd avoid printing `CanonAbi`, and preserve `ExternAbi` everywhere + // that we need to generate error messages. + let erased_abi = match self { CanonAbi::C => ExternAbi::C { unwind: false }, CanonAbi::Rust => ExternAbi::Rust, CanonAbi::RustCold => ExternAbi::RustCold, @@ -87,7 +79,8 @@ impl CanonAbi { X86Call::Vectorcall => ExternAbi::Vectorcall { unwind: false }, X86Call::Win64 => ExternAbi::Win64 { unwind: false }, }, - } + }; + erased_abi.as_str().fmt(f) } } diff --git a/compiler/rustc_abi/src/layout/ty.rs b/compiler/rustc_abi/src/layout/ty.rs index 4f43c0e6f8e..b5f93351d68 100644 --- a/compiler/rustc_abi/src/layout/ty.rs +++ b/compiler/rustc_abi/src/layout/ty.rs @@ -39,6 +39,13 @@ rustc_index::newtype_index! { pub struct FieldIdx {} } +impl FieldIdx { + /// The second field, at index 1. + /// + /// For use alongside [`FieldIdx::ZERO`], particularly with scalar pairs. + pub const ONE: FieldIdx = FieldIdx::from_u32(1); +} + rustc_index::newtype_index! { /// The *source-order* index of a variant in a type. /// @@ -274,7 +281,7 @@ impl<'a, Ty> TyAndLayout<'a, Ty> { /// Finds the one field that is not a 1-ZST. /// Returns `None` if there are multiple non-1-ZST fields or only 1-ZST-fields. - pub fn non_1zst_field<C>(&self, cx: &C) -> Option<(usize, Self)> + pub fn non_1zst_field<C>(&self, cx: &C) -> Option<(FieldIdx, Self)> where Ty: TyAbiInterface<'a, C> + Copy, { @@ -288,7 +295,7 @@ impl<'a, Ty> TyAndLayout<'a, Ty> { // More than one non-1-ZST field. return None; } - found = Some((field_idx, field)); + found = Some((FieldIdx::from_usize(field_idx), field)); } found } diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index c9a8adec31a..cf40c3f7f6f 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -1119,10 +1119,9 @@ impl Stmt { pub fn add_trailing_semicolon(mut self) -> Self { self.kind = match self.kind { StmtKind::Expr(expr) => StmtKind::Semi(expr), - StmtKind::MacCall(mac) => { - StmtKind::MacCall(mac.map(|MacCallStmt { mac, style: _, attrs, tokens }| { - MacCallStmt { mac, style: MacStmtStyle::Semicolon, attrs, tokens } - })) + StmtKind::MacCall(mut mac) => { + mac.style = MacStmtStyle::Semicolon; + StmtKind::MacCall(mac) } kind => kind, }; @@ -1724,7 +1723,7 @@ pub enum ExprKind { /// /// Usually not written directly in user code but /// indirectly via the macro `core::mem::offset_of!(...)`. - OffsetOf(P<Ty>, P<[Ident]>), + OffsetOf(P<Ty>, Vec<Ident>), /// A macro invocation; pre-expansion. MacCall(P<MacCall>), diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs index f165c4ddcdd..621e3042b62 100644 --- a/compiler/rustc_ast/src/attr/mod.rs +++ b/compiler/rustc_ast/src/attr/mod.rs @@ -63,7 +63,7 @@ impl Attribute { pub fn unwrap_normal_item(self) -> AttrItem { match self.kind { - AttrKind::Normal(normal) => normal.into_inner().item, + AttrKind::Normal(normal) => normal.item, AttrKind::DocComment(..) => panic!("unexpected doc comment"), } } diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index 08726ee6b41..77cbdde61a4 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -208,11 +208,7 @@ pub trait MutVisitor: Sized { } fn visit_ident(&mut self, i: &mut Ident) { - walk_ident(self, i); - } - - fn visit_modifiers(&mut self, m: &mut TraitBoundModifiers) { - walk_modifiers(self, m); + self.visit_span(&mut i.span); } fn visit_path(&mut self, p: &mut Path) { @@ -367,6 +363,33 @@ pub trait MutVisitor: Sized { super::common_visitor_and_walkers!((mut) MutVisitor); +macro_rules! generate_flat_map_visitor_fns { + ($($name:ident, $Ty:ty, $flat_map_fn:ident$(, $param:ident: $ParamTy:ty)*;)+) => { + $( + fn $name<V: MutVisitor>( + vis: &mut V, + values: &mut ThinVec<$Ty>, + $( + $param: $ParamTy, + )* + ) { + values.flat_map_in_place(|value| vis.$flat_map_fn(value$(,$param)*)); + } + )+ + } +} + +generate_flat_map_visitor_fns! { + visit_items, P<Item>, flat_map_item; + visit_foreign_items, P<ForeignItem>, flat_map_foreign_item; + visit_generic_params, GenericParam, flat_map_generic_param; + visit_stmts, Stmt, flat_map_stmt; + visit_exprs, P<Expr>, filter_map_expr; + visit_pat_fields, PatField, flat_map_pat_field; + visit_variants, Variant, flat_map_variant; + visit_assoc_items, P<AssocItem>, flat_map_assoc_item, ctxt: AssocCtxt; +} + #[inline] fn visit_vec<T, F>(elems: &mut Vec<T>, mut visit_elem: F) where @@ -403,15 +426,6 @@ fn visit_attrs<T: MutVisitor>(vis: &mut T, attrs: &mut AttrVec) { } } -#[allow(unused)] -fn visit_exprs<T: MutVisitor>(vis: &mut T, exprs: &mut Vec<P<Expr>>) { - exprs.flat_map_in_place(|expr| vis.filter_map_expr(expr)) -} - -fn visit_thin_exprs<T: MutVisitor>(vis: &mut T, exprs: &mut ThinVec<P<Expr>>) { - exprs.flat_map_in_place(|expr| vis.filter_map_expr(expr)) -} - fn visit_attr_args<T: MutVisitor>(vis: &mut T, args: &mut AttrArgs) { match args { AttrArgs::Empty => {} @@ -430,15 +444,6 @@ fn visit_delim_args<T: MutVisitor>(vis: &mut T, args: &mut DelimArgs) { vis.visit_span(close); } -pub fn walk_pat_field<T: MutVisitor>(vis: &mut T, fp: &mut PatField) { - let PatField { attrs, id, ident, is_placeholder: _, is_shorthand: _, pat, span } = fp; - vis.visit_id(id); - visit_attrs(vis, attrs); - vis.visit_ident(ident); - vis.visit_pat(pat); - vis.visit_span(span); -} - pub fn walk_flat_map_pat_field<T: MutVisitor>( vis: &mut T, mut fp: PatField, @@ -447,21 +452,13 @@ pub fn walk_flat_map_pat_field<T: MutVisitor>( smallvec![fp] } -fn walk_use_tree<T: MutVisitor>(vis: &mut T, use_tree: &mut UseTree) { - let UseTree { prefix, kind, span } = use_tree; - vis.visit_path(prefix); - match kind { - UseTreeKind::Simple(rename) => visit_opt(rename, |rename| vis.visit_ident(rename)), - UseTreeKind::Nested { items, span } => { - for (tree, id) in items { - vis.visit_id(id); - vis.visit_use_tree(tree); - } - vis.visit_span(span); - } - UseTreeKind::Glob => {} - } - vis.visit_span(span); +fn visit_nested_use_tree<V: MutVisitor>( + vis: &mut V, + nested_tree: &mut UseTree, + nested_id: &mut NodeId, +) { + vis.visit_id(nested_id); + vis.visit_use_tree(nested_tree); } pub fn walk_arm<T: MutVisitor>(vis: &mut T, arm: &mut Arm) { @@ -498,31 +495,6 @@ fn walk_assoc_item_constraint<T: MutVisitor>( vis.visit_span(span); } -pub fn walk_ty_pat<T: MutVisitor>(vis: &mut T, ty: &mut TyPat) { - let TyPat { id, kind, span, tokens: _ } = ty; - vis.visit_id(id); - match kind { - TyPatKind::Range(start, end, _include_end) => { - visit_opt(start, |c| vis.visit_anon_const(c)); - visit_opt(end, |c| vis.visit_anon_const(c)); - } - TyPatKind::Or(variants) => visit_thin_vec(variants, |p| vis.visit_ty_pat(p)), - TyPatKind::Err(_) => {} - } - vis.visit_span(span); -} - -pub fn walk_variant<T: MutVisitor>(visitor: &mut T, variant: &mut Variant) { - let Variant { ident, vis, attrs, id, data, disr_expr, span, is_placeholder: _ } = variant; - visitor.visit_id(id); - visit_attrs(visitor, attrs); - visitor.visit_vis(vis); - visitor.visit_ident(ident); - visitor.visit_variant_data(data); - visit_opt(disr_expr, |disr_expr| visitor.visit_anon_const(disr_expr)); - visitor.visit_span(span); -} - pub fn walk_flat_map_variant<T: MutVisitor>( vis: &mut T, mut variant: Variant, @@ -531,25 +503,6 @@ pub fn walk_flat_map_variant<T: MutVisitor>( smallvec![variant] } -fn walk_ident<T: MutVisitor>(vis: &mut T, Ident { name: _, span }: &mut Ident) { - vis.visit_span(span); -} - -fn walk_path<T: MutVisitor>(vis: &mut T, Path { segments, span, tokens: _ }: &mut Path) { - for segment in segments { - vis.visit_path_segment(segment); - } - vis.visit_span(span); -} - -fn walk_qself<T: MutVisitor>(vis: &mut T, qself: &mut Option<P<QSelf>>) { - visit_opt(qself, |qself| { - let QSelf { ty, path_span, position: _ } = &mut **qself; - vis.visit_ty(ty); - vis.visit_span(path_span); - }) -} - fn walk_generic_args<T: MutVisitor>(vis: &mut T, generic_args: &mut GenericArgs) { match generic_args { GenericArgs::AngleBracketed(data) => vis.visit_angle_bracketed_parameter_data(data), @@ -583,27 +536,6 @@ fn walk_parenthesized_parameter_data<T: MutVisitor>(vis: &mut T, args: &mut Pare vis.visit_span(inputs_span); } -fn walk_local<T: MutVisitor>(vis: &mut T, local: &mut Local) { - let Local { id, super_, pat, ty, kind, span, colon_sp, attrs, tokens: _ } = local; - visit_opt(super_, |sp| vis.visit_span(sp)); - vis.visit_id(id); - visit_attrs(vis, attrs); - vis.visit_pat(pat); - visit_opt(ty, |ty| vis.visit_ty(ty)); - match kind { - LocalKind::Decl => {} - LocalKind::Init(init) => { - vis.visit_expr(init); - } - LocalKind::InitElse(init, els) => { - vis.visit_expr(init); - vis.visit_block(els); - } - } - visit_opt(colon_sp, |sp| vis.visit_span(sp)); - vis.visit_span(span); -} - fn walk_attribute<T: MutVisitor>(vis: &mut T, attr: &mut Attribute) { let Attribute { kind, id: _, style: _, span } = attr; match kind { @@ -853,35 +785,6 @@ fn walk_variant_data<T: MutVisitor>(vis: &mut T, vdata: &mut VariantData) { } } -fn walk_trait_ref<T: MutVisitor>(vis: &mut T, TraitRef { path, ref_id }: &mut TraitRef) { - vis.visit_id(ref_id); - vis.visit_path(path); -} - -fn walk_poly_trait_ref<T: MutVisitor>(vis: &mut T, p: &mut PolyTraitRef) { - let PolyTraitRef { bound_generic_params, modifiers, trait_ref, span } = p; - vis.visit_modifiers(modifiers); - bound_generic_params.flat_map_in_place(|param| vis.flat_map_generic_param(param)); - vis.visit_trait_ref(trait_ref); - vis.visit_span(span); -} - -fn walk_modifiers<V: MutVisitor>(vis: &mut V, m: &mut TraitBoundModifiers) { - let TraitBoundModifiers { constness, asyncness, polarity } = m; - match constness { - BoundConstness::Never => {} - BoundConstness::Always(span) | BoundConstness::Maybe(span) => vis.visit_span(span), - } - match asyncness { - BoundAsyncness::Normal => {} - BoundAsyncness::Async(span) => vis.visit_span(span), - } - match polarity { - BoundPolarity::Positive => {} - BoundPolarity::Negative(span) | BoundPolarity::Maybe(span) => vis.visit_span(span), - } -} - pub fn walk_field_def<T: MutVisitor>(visitor: &mut T, fd: &mut FieldDef) { let FieldDef { span, ident, vis, id, ty, attrs, is_placeholder: _, safety, default } = fd; visitor.visit_id(id); @@ -902,15 +805,6 @@ pub fn walk_flat_map_field_def<T: MutVisitor>( smallvec![fd] } -pub fn walk_expr_field<T: MutVisitor>(vis: &mut T, f: &mut ExprField) { - let ExprField { ident, expr, span, is_shorthand: _, attrs, id, is_placeholder: _ } = f; - vis.visit_id(id); - visit_attrs(vis, attrs); - vis.visit_ident(ident); - vis.visit_expr(expr); - vis.visit_span(span); -} - pub fn walk_flat_map_expr_field<T: MutVisitor>( vis: &mut T, mut f: ExprField, @@ -930,16 +824,6 @@ pub fn walk_item_kind<K: WalkItemKind>( kind.walk(span, id, visibility, ctxt, vis) } -pub fn walk_crate<T: MutVisitor>(vis: &mut T, krate: &mut Crate) { - let Crate { attrs, items, spans, id, is_placeholder: _ } = krate; - vis.visit_id(id); - visit_attrs(vis, attrs); - items.flat_map_in_place(|item| vis.flat_map_item(item)); - let ModSpans { inner_span, inject_use_span } = spans; - vis.visit_span(inner_span); - vis.visit_span(inject_use_span); -} - pub fn walk_flat_map_item(vis: &mut impl MutVisitor, mut item: P<Item>) -> SmallVec<[P<Item>; 1]> { vis.visit_item(&mut item); smallvec![item] @@ -1021,7 +905,7 @@ pub fn walk_expr<T: MutVisitor>(vis: &mut T, Expr { kind, id, span, attrs, token vis.visit_id(id); visit_attrs(vis, attrs); match kind { - ExprKind::Array(exprs) => visit_thin_exprs(vis, exprs), + ExprKind::Array(exprs) => visit_exprs(vis, exprs), ExprKind::ConstBlock(anon_const) => { vis.visit_anon_const(anon_const); } @@ -1029,10 +913,10 @@ pub fn walk_expr<T: MutVisitor>(vis: &mut T, Expr { kind, id, span, attrs, token vis.visit_expr(expr); vis.visit_anon_const(count); } - ExprKind::Tup(exprs) => visit_thin_exprs(vis, exprs), + ExprKind::Tup(exprs) => visit_exprs(vis, exprs), ExprKind::Call(f, args) => { vis.visit_expr(f); - visit_thin_exprs(vis, args); + visit_exprs(vis, args); } ExprKind::MethodCall(box MethodCall { seg: PathSegment { ident, id, args: seg_args }, @@ -1044,7 +928,7 @@ pub fn walk_expr<T: MutVisitor>(vis: &mut T, Expr { kind, id, span, attrs, token vis.visit_id(id); vis.visit_ident(ident); visit_opt(seg_args, |args| vis.visit_generic_args(args)); - visit_thin_exprs(vis, call_args); + visit_exprs(vis, call_args); vis.visit_span(span); } ExprKind::Binary(binop, lhs, rhs) => { diff --git a/compiler/rustc_ast/src/ptr.rs b/compiler/rustc_ast/src/ptr.rs index dd923305cdf..fffeab8bbca 100644 --- a/compiler/rustc_ast/src/ptr.rs +++ b/compiler/rustc_ast/src/ptr.rs @@ -1,209 +1,11 @@ -//! The AST pointer. -//! -//! Provides [`P<T>`][struct@P], an owned smart pointer. -//! -//! # Motivations and benefits -//! -//! * **Identity**: sharing AST nodes is problematic for the various analysis -//! passes (e.g., one may be able to bypass the borrow checker with a shared -//! `ExprKind::AddrOf` node taking a mutable borrow). -//! -//! * **Efficiency**: folding can reuse allocation space for `P<T>` and `Vec<T>`, -//! the latter even when the input and output types differ (as it would be the -//! case with arenas or a GADT AST using type parameters to toggle features). -//! -//! * **Maintainability**: `P<T>` provides an interface, which can remain fully -//! functional even if the implementation changes (using a special thread-local -//! heap, for example). Moreover, a switch to, e.g., `P<'a, T>` would be easy -//! and mostly automated. - -use std::fmt::{self, Debug, Display}; -use std::ops::{Deref, DerefMut}; -use std::{slice, vec}; - -use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; -use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; -/// An owned smart pointer. +/// A pointer type that uniquely owns a heap allocation of type T. /// -/// See the [module level documentation][crate::ptr] for details. -pub struct P<T: ?Sized> { - ptr: Box<T>, -} +/// This used to be its own type, but now it's just a typedef for `Box` and we are planning to +/// remove it soon. +pub type P<T> = Box<T>; /// Construct a `P<T>` from a `T` value. #[allow(non_snake_case)] -pub fn P<T: 'static>(value: T) -> P<T> { - P { ptr: Box::new(value) } -} - -impl<T: 'static> P<T> { - /// Move out of the pointer. - /// Intended for chaining transformations not covered by `map`. - pub fn and_then<U, F>(self, f: F) -> U - where - F: FnOnce(T) -> U, - { - f(*self.ptr) - } - - /// Equivalent to `and_then(|x| x)`. - pub fn into_inner(self) -> T { - *self.ptr - } - - /// Produce a new `P<T>` from `self` without reallocating. - pub fn map<F>(mut self, f: F) -> P<T> - where - F: FnOnce(T) -> T, - { - let x = f(*self.ptr); - *self.ptr = x; - - self - } - - /// Optionally produce a new `P<T>` from `self` without reallocating. - pub fn filter_map<F>(mut self, f: F) -> Option<P<T>> - where - F: FnOnce(T) -> Option<T>, - { - *self.ptr = f(*self.ptr)?; - Some(self) - } -} - -impl<T: ?Sized> Deref for P<T> { - type Target = T; - - fn deref(&self) -> &T { - &self.ptr - } -} - -impl<T: ?Sized> DerefMut for P<T> { - fn deref_mut(&mut self) -> &mut T { - &mut self.ptr - } -} - -impl<T: 'static + Clone> Clone for P<T> { - fn clone(&self) -> P<T> { - P((**self).clone()) - } -} - -impl<T: ?Sized + Debug> Debug for P<T> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - Debug::fmt(&self.ptr, f) - } -} - -impl<T: Display> Display for P<T> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - Display::fmt(&**self, f) - } -} - -impl<T> fmt::Pointer for P<T> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Pointer::fmt(&self.ptr, f) - } -} - -impl<D: Decoder, T: 'static + Decodable<D>> Decodable<D> for P<T> { - fn decode(d: &mut D) -> P<T> { - P(Decodable::decode(d)) - } -} - -impl<S: Encoder, T: Encodable<S>> Encodable<S> for P<T> { - fn encode(&self, s: &mut S) { - (**self).encode(s); - } -} - -impl<T> P<[T]> { - // FIXME(const-hack) make this const again - pub fn new() -> P<[T]> { - P { ptr: Box::default() } - } - - #[inline(never)] - pub fn from_vec(v: Vec<T>) -> P<[T]> { - P { ptr: v.into_boxed_slice() } - } - - #[inline(never)] - pub fn into_vec(self) -> Vec<T> { - self.ptr.into_vec() - } -} - -impl<T> Default for P<[T]> { - /// Creates an empty `P<[T]>`. - fn default() -> P<[T]> { - P::new() - } -} - -impl<T: Clone> Clone for P<[T]> { - fn clone(&self) -> P<[T]> { - P::from_vec(self.to_vec()) - } -} - -impl<T> From<Vec<T>> for P<[T]> { - fn from(v: Vec<T>) -> Self { - P::from_vec(v) - } -} - -impl<T> From<P<[T]>> for Vec<T> { - fn from(val: P<[T]>) -> Self { - val.into_vec() - } -} - -impl<T> FromIterator<T> for P<[T]> { - fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> P<[T]> { - P::from_vec(iter.into_iter().collect()) - } -} - -impl<T> IntoIterator for P<[T]> { - type Item = T; - type IntoIter = vec::IntoIter<T>; - - fn into_iter(self) -> Self::IntoIter { - self.into_vec().into_iter() - } -} - -impl<'a, T> IntoIterator for &'a P<[T]> { - type Item = &'a T; - type IntoIter = slice::Iter<'a, T>; - fn into_iter(self) -> Self::IntoIter { - self.ptr.iter() - } -} - -impl<S: Encoder, T: Encodable<S>> Encodable<S> for P<[T]> { - fn encode(&self, s: &mut S) { - Encodable::encode(&**self, s); - } -} - -impl<D: Decoder, T: Decodable<D>> Decodable<D> for P<[T]> { - fn decode(d: &mut D) -> P<[T]> { - P::from_vec(Decodable::decode(d)) - } -} - -impl<CTX, T> HashStable<CTX> for P<T> -where - T: ?Sized + HashStable<CTX>, -{ - fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) { - (**self).hash_stable(hcx, hasher); - } +pub fn P<T>(value: T) -> P<T> { + Box::new(value) } diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index 1f7c97380dc..d2f22b04a67 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -219,9 +219,6 @@ pub trait Visitor<'ast>: Sized { fn visit_field_def(&mut self, s: &'ast FieldDef) -> Self::Result { walk_field_def(self, s) } - fn visit_enum_def(&mut self, enum_definition: &'ast EnumDef) -> Self::Result { - walk_enum_def(self, enum_definition) - } fn visit_variant(&mut self, v: &'ast Variant) -> Self::Result { walk_variant(self, v) } @@ -246,13 +243,12 @@ pub trait Visitor<'ast>: Sized { fn visit_path(&mut self, path: &'ast Path) -> Self::Result { walk_path(self, path) } - fn visit_use_tree( - &mut self, - use_tree: &'ast UseTree, - id: NodeId, - _nested: bool, - ) -> Self::Result { - walk_use_tree(self, use_tree, id) + fn visit_use_tree(&mut self, use_tree: &'ast UseTree) -> Self::Result { + walk_use_tree(self, use_tree) + } + fn visit_nested_use_tree(&mut self, use_tree: &'ast UseTree, id: NodeId) -> Self::Result { + try_visit!(self.visit_id(id)); + self.visit_use_tree(use_tree) } fn visit_path_segment(&mut self, path_segment: &'ast PathSegment) -> Self::Result { walk_path_segment(self, path_segment) @@ -378,13 +374,39 @@ macro_rules! common_visitor_and_walkers { } } - fn visit_polarity<$($lt,)? V: $Visitor$(<$lt>)?>(vis: &mut V, polarity: &$($lt)? $($mut)? ImplPolarity) $(-> <V as Visitor<$lt>>::Result)? { + fn visit_polarity<$($lt,)? V: $Visitor$(<$lt>)?>( + vis: &mut V, + polarity: &$($lt)? $($mut)? ImplPolarity, + ) $(-> <V as Visitor<$lt>>::Result)? { match polarity { ImplPolarity::Positive => { $(<V as Visitor<$lt>>::Result::output())? } ImplPolarity::Negative(span) => visit_span(vis, span), } } + $(${ignore($lt)} + #[inline] + )? + fn visit_modifiers<$($lt,)? V: $Visitor$(<$lt>)?>( + vis: &mut V, + m: &$($lt)? $($mut)? TraitBoundModifiers + ) $(-> <V as Visitor<$lt>>::Result)? { + let TraitBoundModifiers { constness, asyncness, polarity } = m; + match constness { + BoundConstness::Never => {} + BoundConstness::Always(span) | BoundConstness::Maybe(span) => try_visit!(visit_span(vis, span)), + } + match asyncness { + BoundAsyncness::Normal => {} + BoundAsyncness::Async(span) => try_visit!(visit_span(vis, span)), + } + match polarity { + BoundPolarity::Positive => {} + BoundPolarity::Negative(span) | BoundPolarity::Maybe(span) => try_visit!(visit_span(vis, span)), + } + $(<V as Visitor<$lt>>::Result::output())? + } + fn visit_bounds<$($lt,)? V: $Visitor$(<$lt>)?>(visitor: &mut V, bounds: &$($lt)? $($mut)? GenericBounds, ctxt: BoundKind) $(-> <V as Visitor<$lt>>::Result)? { walk_list!(visitor, visit_param_bound, bounds, ctxt); $(<V as Visitor<$lt>>::Result::output())? @@ -446,8 +468,7 @@ macro_rules! common_visitor_and_walkers { ) $(-> <V as Visitor<$lt>>::Result)? { match self { ItemKind::ExternCrate(_orig_name, ident) => vis.visit_ident(ident), - // FIXME(fee1-dead): look into this weird assymetry - ItemKind::Use(use_tree) => vis.visit_use_tree(use_tree$(${ignore($lt)}, id, false)?), + ItemKind::Use(use_tree) => vis.visit_use_tree(use_tree), ItemKind::Static(box StaticItem { ident, ty, @@ -478,12 +499,7 @@ macro_rules! common_visitor_and_walkers { ModSpans { inner_span, inject_use_span }, _, ) => { - $(${ignore($mut)} - items.flat_map_in_place(|item| vis.flat_map_item(item)); - )? - $(${ignore($lt)} - walk_list!(vis, visit_item, items); - )? + try_visit!(visit_items(vis, items)); try_visit!(visit_span(vis, inner_span)); try_visit!(visit_span(vis, inject_use_span)); } @@ -515,10 +531,7 @@ macro_rules! common_visitor_and_walkers { ItemKind::Enum(ident, generics, enum_definition) => { try_visit!(vis.visit_ident(ident)); try_visit!(vis.visit_generics(generics)); - $(${ignore($mut)} - enum_definition.variants.flat_map_in_place(|variant| vis.flat_map_variant(variant)); - )? - $(${ignore($lt)}vis.visit_enum_def(enum_definition))? + visit_variants(vis, &$($mut)? enum_definition.variants) } ItemKind::Struct(ident, generics, variant_data) | ItemKind::Union(ident, generics, variant_data) => { @@ -543,35 +556,14 @@ macro_rules! common_visitor_and_walkers { try_visit!(visit_polarity(vis, polarity)); visit_opt!(vis, visit_trait_ref, of_trait); try_visit!(vis.visit_ty(self_ty)); - $(${ignore($mut)} - items.flat_map_in_place(|item| { - vis.flat_map_assoc_item(item, AssocCtxt::Impl { of_trait: of_trait.is_some() }) - }); - )? - $(${ignore($lt)} - walk_list!( - vis, - visit_assoc_item, - items, - AssocCtxt::Impl { of_trait: of_trait.is_some() } - ); - <V as Visitor<$lt>>::Result::output() - )? + visit_assoc_items(vis, items, AssocCtxt::Impl { of_trait: of_trait.is_some() }) } ItemKind::Trait(box Trait { safety, is_auto: _, ident, generics, bounds, items }) => { try_visit!(visit_safety(vis, safety)); try_visit!(vis.visit_ident(ident)); try_visit!(vis.visit_generics(generics)); try_visit!(visit_bounds(vis, bounds, BoundKind::Bound)); - $(${ignore($mut)} - items.flat_map_in_place(|item| { - vis.flat_map_assoc_item(item, AssocCtxt::Trait) - }); - )? - $(${ignore($lt)} - walk_list!(vis, visit_assoc_item, items, AssocCtxt::Trait); - <V as Visitor<$lt>>::Result::output() - )? + visit_assoc_items(vis, items, AssocCtxt::Trait) } ItemKind::TraitAlias(ident, generics, bounds) => { try_visit!(vis.visit_ident(ident)); @@ -616,7 +608,10 @@ macro_rules! common_visitor_and_walkers { } } - fn walk_const_item<$($lt,)? V: $Visitor$(<$lt>)?>(vis: &mut V, item: &$($lt)? $($mut)? ConstItem) $(-> <V as Visitor<$lt>>::Result)? { + fn walk_const_item<$($lt,)? V: $Visitor$(<$lt>)?>( + vis: &mut V, + item: &$($lt)? $($mut)? ConstItem, + ) $(-> <V as Visitor<$lt>>::Result)? { let ConstItem { defaultness, ident, generics, ty, expr, define_opaque } = item; try_visit!(visit_defaultness(vis, defaultness)); try_visit!(vis.visit_ident(ident)); @@ -629,13 +624,7 @@ macro_rules! common_visitor_and_walkers { fn walk_foreign_mod<$($lt,)? V: $Visitor$(<$lt>)?>(vis: &mut V, foreign_mod: &$($lt)? $($mut)? ForeignMod) $(-> <V as Visitor<$lt>>::Result)? { let ForeignMod { extern_span: _, safety, abi: _, items } = foreign_mod; try_visit!(visit_safety(vis, safety)); - $(${ignore($mut)} - items.flat_map_in_place(|item| vis.flat_map_foreign_item(item)); - )? - $( - walk_list!(vis, visit_foreign_item, items); - <V as Visitor<$lt>>::Result::output() - )? + visit_foreign_items(vis, items) } fn walk_define_opaques<$($lt,)? V: $Visitor$(<$lt>)?>( @@ -780,15 +769,13 @@ macro_rules! common_visitor_and_walkers { vis: &mut V, coroutine_kind: &$($lt)? $($mut)? CoroutineKind, ) $(-> <V as Visitor<$lt>>::Result)? { - match coroutine_kind { - CoroutineKind::Async { span, closure_id, return_impl_trait_id } + let (CoroutineKind::Async { span, closure_id, return_impl_trait_id } | CoroutineKind::Gen { span, closure_id, return_impl_trait_id } - | CoroutineKind::AsyncGen { span, closure_id, return_impl_trait_id } => { - try_visit!(visit_id(vis, closure_id)); - try_visit!(visit_id(vis, return_impl_trait_id)); - visit_span(vis, span) - } - } + | CoroutineKind::AsyncGen { span, closure_id, return_impl_trait_id }) + = coroutine_kind; + try_visit!(visit_id(vis, closure_id)); + try_visit!(visit_id(vis, return_impl_trait_id)); + visit_span(vis, span) } pub fn walk_pat<$($lt,)? V: $Visitor$(<$lt>)?>( @@ -817,15 +804,7 @@ macro_rules! common_visitor_and_walkers { PatKind::Struct(opt_qself, path, fields, _rest) => { try_visit!(vis.visit_qself(opt_qself)); try_visit!(vis.visit_path(path)); - - $( - ${ignore($lt)} - walk_list!(vis, visit_pat_field, fields); - )? - $( - ${ignore($mut)} - fields.flat_map_in_place(|field| vis.flat_map_pat_field(field)); - )? + try_visit!(visit_pat_fields(vis, fields)); } PatKind::Box(subpattern) | PatKind::Deref(subpattern) | PatKind::Paren(subpattern) => { try_visit!(vis.visit_pat(subpattern)); @@ -876,14 +855,7 @@ macro_rules! common_visitor_and_walkers { ) $(-> <V as Visitor<$lt>>::Result)? { let Block { stmts, id, rules: _, span, tokens: _ } = block; try_visit!(visit_id(vis, id)); - $( - ${ignore($lt)} - walk_list!(vis, visit_stmt, stmts); - )? - $( - ${ignore($mut)} - stmts.flat_map_in_place(|stmt| vis.flat_map_stmt(stmt)); - )? + try_visit!(visit_stmts(vis, stmts)); visit_span(vis, span) } @@ -911,28 +883,13 @@ macro_rules! common_visitor_and_walkers { let BareFnTy { safety, ext: _, generic_params, decl, decl_span } = &$($mut)? **function_declaration; visit_safety(vis, safety); - $( - ${ignore($lt)} - walk_list!(vis, visit_generic_param, generic_params); - )? - $( - ${ignore($mut)} - generic_params.flat_map_in_place(|param| vis.flat_map_generic_param(param)); - )? - + try_visit!(visit_generic_params(vis, generic_params)); try_visit!(vis.visit_fn_decl(decl)); try_visit!(visit_span(vis, decl_span)); } TyKind::UnsafeBinder(binder) => { - $( - ${ignore($lt)} - walk_list!(vis, visit_generic_param, &binder.generic_params); - )? - $( - ${ignore($mut)} - binder.generic_params.flat_map_in_place(|param| vis.flat_map_generic_param(param)); - )? - try_visit!(vis.visit_ty(&$($mut)?binder.inner_ty)); + try_visit!(visit_generic_params(vis, &$($mut)? binder.generic_params)); + try_visit!(vis.visit_ty(&$($mut)? binder.inner_ty)); } TyKind::Path(maybe_qself, path) => { try_visit!(vis.visit_qself(maybe_qself)); @@ -959,130 +916,204 @@ macro_rules! common_visitor_and_walkers { } visit_span(vis, span) } - }; -} -common_visitor_and_walkers!(Visitor<'a>); + pub fn walk_crate<$($lt,)? V: $Visitor$(<$lt>)?>( + vis: &mut V, + krate: &$($lt)? $($mut)? Crate, + ) $(-> <V as Visitor<$lt>>::Result)? { + let Crate { attrs, items, spans, id, is_placeholder: _ } = krate; + try_visit!(visit_id(vis, id)); + walk_list!(vis, visit_attribute, attrs); + try_visit!(visit_items(vis, items)); + let ModSpans { inner_span, inject_use_span } = spans; + try_visit!(visit_span(vis, inner_span)); + visit_span(vis, inject_use_span) + } -pub fn walk_crate<'a, V: Visitor<'a>>(visitor: &mut V, krate: &'a Crate) -> V::Result { - let Crate { attrs, items, spans: _, id: _, is_placeholder: _ } = krate; - walk_list!(visitor, visit_attribute, attrs); - walk_list!(visitor, visit_item, items); - V::Result::output() -} + pub fn walk_local<$($lt,)? V: $Visitor$(<$lt>)?>( + vis: &mut V, + local: &$($lt)? $($mut)? Local, + ) $(-> <V as Visitor<$lt>>::Result)? { + let Local { id, super_, pat, ty, kind, span, colon_sp, attrs, tokens: _ } = local; + if let Some(sp) = super_ { + try_visit!(visit_span(vis, sp)); + } + try_visit!(visit_id(vis, id)); + walk_list!(vis, visit_attribute, attrs); + try_visit!(vis.visit_pat(pat)); + visit_opt!(vis, visit_ty, ty); + match kind { + LocalKind::Decl => {} + LocalKind::Init(init) => { + try_visit!(vis.visit_expr(init)) + } + LocalKind::InitElse(init, els) => { + try_visit!(vis.visit_expr(init)); + try_visit!(vis.visit_block(els)); + } + } + if let Some(sp) = colon_sp { + try_visit!(visit_span(vis, sp)); + } + visit_span(vis, span) + } -pub fn walk_local<'a, V: Visitor<'a>>(visitor: &mut V, local: &'a Local) -> V::Result { - let Local { id: _, super_: _, pat, ty, kind, span: _, colon_sp: _, attrs, tokens: _ } = local; - walk_list!(visitor, visit_attribute, attrs); - try_visit!(visitor.visit_pat(pat)); - visit_opt!(visitor, visit_ty, ty); - if let Some((init, els)) = kind.init_else_opt() { - try_visit!(visitor.visit_expr(init)); - visit_opt!(visitor, visit_block, els); - } - V::Result::output() -} + pub fn walk_poly_trait_ref<$($lt,)? V: $Visitor$(<$lt>)?>( + vis: &mut V, + p: &$($lt)? $($mut)? PolyTraitRef, + ) $(-> <V as Visitor<$lt>>::Result)? { + let PolyTraitRef { bound_generic_params, modifiers, trait_ref, span } = p; + try_visit!(visit_modifiers(vis, modifiers)); + try_visit!(visit_generic_params(vis, bound_generic_params)); + try_visit!(vis.visit_trait_ref(trait_ref)); + visit_span(vis, span) + } -pub fn walk_poly_trait_ref<'a, V>(visitor: &mut V, trait_ref: &'a PolyTraitRef) -> V::Result -where - V: Visitor<'a>, -{ - let PolyTraitRef { bound_generic_params, modifiers: _, trait_ref, span: _ } = trait_ref; - walk_list!(visitor, visit_generic_param, bound_generic_params); - visitor.visit_trait_ref(trait_ref) -} + pub fn walk_trait_ref<$($lt,)? V: $Visitor$(<$lt>)?>( + vis: &mut V, + TraitRef { path, ref_id }: &$($lt)? $($mut)? TraitRef, + ) $(-> <V as Visitor<$lt>>::Result)? { + try_visit!(vis.visit_path(path)); + visit_id(vis, ref_id) + } -pub fn walk_trait_ref<'a, V: Visitor<'a>>(visitor: &mut V, trait_ref: &'a TraitRef) -> V::Result { - let TraitRef { path, ref_id } = trait_ref; - try_visit!(visitor.visit_path(path)); - visitor.visit_id(*ref_id) -} + pub fn walk_variant<$($lt,)? V: $Visitor$(<$lt>)?>( + vis: &mut V, + variant: &$($lt)? $($mut)? Variant, + ) $(-> <V as Visitor<$lt>>::Result)? { + let Variant { attrs, id, span, vis: visibility, ident, data, disr_expr, is_placeholder: _ } = variant; + try_visit!(visit_id(vis, id)); + walk_list!(vis, visit_attribute, attrs); + try_visit!(vis.visit_vis(visibility)); + try_visit!(vis.visit_ident(ident)); + try_visit!(vis.visit_variant_data(data)); + $(${ignore($lt)} visit_opt!(vis, visit_variant_discr, disr_expr); )? + $(${ignore($mut)} visit_opt!(vis, visit_anon_const, disr_expr); )? + visit_span(vis, span) + } -pub fn walk_enum_def<'a, V: Visitor<'a>>( - visitor: &mut V, - EnumDef { variants }: &'a EnumDef, -) -> V::Result { - walk_list!(visitor, visit_variant, variants); - V::Result::output() -} + pub fn walk_expr_field<$($lt,)? V: $Visitor$(<$lt>)?>( + vis: &mut V, + f: &$($lt)? $($mut)? ExprField, + ) $(-> <V as Visitor<$lt>>::Result)? { + let ExprField { attrs, id, span, ident, expr, is_shorthand: _, is_placeholder: _ } = f; + try_visit!(visit_id(vis, id)); + walk_list!(vis, visit_attribute, attrs); + try_visit!(vis.visit_ident(ident)); + try_visit!(vis.visit_expr(expr)); + visit_span(vis, span) + } -pub fn walk_variant<'a, V: Visitor<'a>>(visitor: &mut V, variant: &'a Variant) -> V::Result -where - V: Visitor<'a>, -{ - let Variant { attrs, id: _, span: _, vis, ident, data, disr_expr, is_placeholder: _ } = variant; - walk_list!(visitor, visit_attribute, attrs); - try_visit!(visitor.visit_vis(vis)); - try_visit!(visitor.visit_ident(ident)); - try_visit!(visitor.visit_variant_data(data)); - visit_opt!(visitor, visit_variant_discr, disr_expr); - V::Result::output() -} + pub fn walk_pat_field<$($lt,)? V: $Visitor$(<$lt>)?>( + vis: &mut V, + fp: &$($lt)? $($mut)? PatField, + ) $(-> <V as Visitor<$lt>>::Result)? { + let PatField { ident, pat, is_shorthand: _, attrs, id, span, is_placeholder: _ } = fp; + try_visit!(visit_id(vis, id)); + walk_list!(vis, visit_attribute, attrs); + try_visit!(vis.visit_ident(ident)); + try_visit!(vis.visit_pat(pat)); + visit_span(vis, span) + } -pub fn walk_expr_field<'a, V: Visitor<'a>>(visitor: &mut V, f: &'a ExprField) -> V::Result { - let ExprField { attrs, id: _, span: _, ident, expr, is_shorthand: _, is_placeholder: _ } = f; - walk_list!(visitor, visit_attribute, attrs); - try_visit!(visitor.visit_ident(ident)); - try_visit!(visitor.visit_expr(expr)); - V::Result::output() -} + pub fn walk_ty_pat<$($lt,)? V: $Visitor$(<$lt>)?>( + vis: &mut V, + tp: &$($lt)? $($mut)? TyPat, + ) $(-> <V as Visitor<$lt>>::Result)? { + let TyPat { id, kind, span, tokens: _ } = tp; + try_visit!(visit_id(vis, id)); + match kind { + TyPatKind::Range(start, end, _include_end) => { + visit_opt!(vis, visit_anon_const, start); + visit_opt!(vis, visit_anon_const, end); + } + TyPatKind::Or(variants) => walk_list!(vis, visit_ty_pat, variants), + TyPatKind::Err(_) => {} + } + visit_span(vis, span) + } -pub fn walk_pat_field<'a, V: Visitor<'a>>(visitor: &mut V, fp: &'a PatField) -> V::Result { - let PatField { ident, pat, is_shorthand: _, attrs, id: _, span: _, is_placeholder: _ } = fp; - walk_list!(visitor, visit_attribute, attrs); - try_visit!(visitor.visit_ident(ident)); - try_visit!(visitor.visit_pat(pat)); - V::Result::output() -} + fn walk_qself<$($lt,)? V: $Visitor$(<$lt>)?>( + vis: &mut V, + qself: &$($lt)? $($mut)? Option<P<QSelf>>, + ) $(-> <V as Visitor<$lt>>::Result)? { + if let Some(qself) = qself { + let QSelf { ty, path_span, position: _ } = &$($mut)? **qself; + try_visit!(vis.visit_ty(ty)); + try_visit!(visit_span(vis, path_span)); + } + $(<V as Visitor<$lt>>::Result::output())? + } -pub fn walk_ty_pat<'a, V: Visitor<'a>>(visitor: &mut V, tp: &'a TyPat) -> V::Result { - let TyPat { id: _, kind, span: _, tokens: _ } = tp; - match kind { - TyPatKind::Range(start, end, _include_end) => { - visit_opt!(visitor, visit_anon_const, start); - visit_opt!(visitor, visit_anon_const, end); + pub fn walk_path<$($lt,)? V: $Visitor$(<$lt>)?>( + vis: &mut V, + path: &$($lt)? $($mut)? Path, + ) $(-> <V as Visitor<$lt>>::Result)? { + let Path { span, segments, tokens: _ } = path; + walk_list!(vis, visit_path_segment, segments); + visit_span(vis, span) } - TyPatKind::Or(variants) => walk_list!(visitor, visit_ty_pat, variants), - TyPatKind::Err(_) => {} - } - V::Result::output() + + pub fn walk_use_tree<$($lt,)? V: $Visitor$(<$lt>)?>( + vis: &mut V, + use_tree: &$($lt)? $($mut)? UseTree, + ) $(-> <V as Visitor<$lt>>::Result)? { + let UseTree { prefix, kind, span } = use_tree; + try_visit!(vis.visit_path(prefix)); + match kind { + UseTreeKind::Simple(rename) => { + // The extra IDs are handled during AST lowering. + visit_opt!(vis, visit_ident, rename); + } + UseTreeKind::Glob => {} + UseTreeKind::Nested { items, span } => { + for (nested_tree, nested_id) in items { + try_visit!(visit_nested_use_tree(vis, nested_tree, nested_id)); + } + try_visit!(visit_span(vis, span)); + } + } + visit_span(vis, span) + } + }; } -fn walk_qself<'a, V: Visitor<'a>>(visitor: &mut V, qself: &'a Option<P<QSelf>>) -> V::Result { - if let Some(qself) = qself { - let QSelf { ty, path_span: _, position: _ } = &**qself; - try_visit!(visitor.visit_ty(ty)); +common_visitor_and_walkers!(Visitor<'a>); + +macro_rules! generate_list_visit_fns { + ($($name:ident, $Ty:ty, $visit_fn:ident$(, $param:ident: $ParamTy:ty)*;)+) => { + $( + fn $name<'a, V: Visitor<'a>>( + vis: &mut V, + values: &'a ThinVec<$Ty>, + $( + $param: $ParamTy, + )* + ) -> V::Result { + walk_list!(vis, $visit_fn, values$(,$param)*); + V::Result::output() + } + )+ } - V::Result::output() } -pub fn walk_path<'a, V: Visitor<'a>>(visitor: &mut V, path: &'a Path) -> V::Result { - let Path { span: _, segments, tokens: _ } = path; - walk_list!(visitor, visit_path_segment, segments); - V::Result::output() +generate_list_visit_fns! { + visit_items, P<Item>, visit_item; + visit_foreign_items, P<ForeignItem>, visit_foreign_item; + visit_generic_params, GenericParam, visit_generic_param; + visit_stmts, Stmt, visit_stmt; + visit_pat_fields, PatField, visit_pat_field; + visit_variants, Variant, visit_variant; + visit_assoc_items, P<AssocItem>, visit_assoc_item, ctxt: AssocCtxt; } -pub fn walk_use_tree<'a, V: Visitor<'a>>( - visitor: &mut V, - use_tree: &'a UseTree, - id: NodeId, +#[expect(rustc::pass_by_value)] // needed for symmetry with mut_visit +fn visit_nested_use_tree<'a, V: Visitor<'a>>( + vis: &mut V, + nested_tree: &'a UseTree, + &nested_id: &NodeId, ) -> V::Result { - let UseTree { prefix, kind, span: _ } = use_tree; - try_visit!(visitor.visit_id(id)); - try_visit!(visitor.visit_path(prefix)); - match kind { - UseTreeKind::Simple(rename) => { - // The extra IDs are handled during AST lowering. - visit_opt!(visitor, visit_ident, rename); - } - UseTreeKind::Glob => {} - UseTreeKind::Nested { items, span: _ } => { - for &(ref nested_tree, nested_id) in items { - try_visit!(visitor.visit_use_tree(nested_tree, nested_id, true)); - } - } - } - V::Result::output() + vis.visit_nested_use_tree(nested_tree, nested_id) } pub fn walk_generic_args<'a, V>(visitor: &mut V, generic_args: &'a GenericArgs) -> V::Result diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 64d4a00ea4d..3004be40334 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -732,7 +732,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { span: Span, args: Option<&'hir hir::GenericArgs<'hir>>, ) -> &'hir hir::Path<'hir> { - let def_id = self.tcx.require_lang_item(lang_item, Some(span)); + let def_id = self.tcx.require_lang_item(lang_item, span); let def_kind = self.tcx.def_kind(def_id); let res = Res::Def(def_kind, def_id); self.arena.alloc(hir::Path { diff --git a/compiler/rustc_attr_parsing/src/attributes/mod.rs b/compiler/rustc_attr_parsing/src/attributes/mod.rs index f45cf984f71..bf18e10e19f 100644 --- a/compiler/rustc_attr_parsing/src/attributes/mod.rs +++ b/compiler/rustc_attr_parsing/src/attributes/mod.rs @@ -74,7 +74,7 @@ pub(crate) trait AttributeParser: Default + 'static { pub(crate) trait SingleAttributeParser: 'static { const PATH: &'static [Symbol]; - /// Caled when a duplicate attribute is found. + /// Called when a duplicate attribute is found. /// /// `first_span` is the span of the first occurrence of this attribute. // FIXME(jdonszelmann): default error diff --git a/compiler/rustc_attr_parsing/src/lib.rs b/compiler/rustc_attr_parsing/src/lib.rs index 63bccf52018..15037e802ff 100644 --- a/compiler/rustc_attr_parsing/src/lib.rs +++ b/compiler/rustc_attr_parsing/src/lib.rs @@ -1,31 +1,38 @@ //! Centralized logic for parsing and attributes. //! -//! Part of a series of crates: -//! - rustc_attr_data_structures: contains types that the parsers parse into -//! - rustc_attr_parsing: this crate -//! - (in the future): rustc_attr_validation +//! ## Architecture +//! This crate is part of a series of crates that handle attribute processing. +//! - [rustc_attr_data_structures](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_attr_data_structures/index.html): Defines the data structures that store parsed attributes +//! - [rustc_attr_parsing](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_attr_parsing/index.html): This crate, handles the parsing of attributes +//! - (planned) rustc_attr_validation: Will handle attribute validation //! -//! History: Check out [#131229](https://github.com/rust-lang/rust/issues/131229). -//! There used to be only one definition of attributes in the compiler: `ast::Attribute`. -//! These were then parsed or validated or both in places distributed all over the compiler. -//! This was a mess... +//! The separation between data structures and parsing follows the principle of separation of concerns. +//! Data structures (`rustc_attr_data_structures`) define what attributes look like after parsing. +//! This crate (`rustc_attr_parsing`) handles how to convert raw tokens into those structures. +//! This split allows other parts of the compiler to use the data structures without needing +//! the parsing logic, making the codebase more modular and maintainable. //! -//! Attributes are markers on items. -//! Many of them are actually attribute-like proc-macros, and are expanded to some other rust syntax. -//! This could either be a user provided proc macro, or something compiler provided. -//! `derive` is an example of one that the compiler provides. -//! These are built-in, but they have a valid expansion to Rust tokens and are thus called "active". -//! I personally like calling these *active* compiler-provided attributes, built-in *macros*, -//! because they still expand, and this helps to differentiate them from built-in *attributes*. -//! However, I'll be the first to admit that the naming here can be confusing. +//! ## Background +//! Previously, the compiler had a single attribute definition (`ast::Attribute`) with parsing and +//! validation scattered throughout the codebase. This was reorganized for better maintainability +//! (see [#131229](https://github.com/rust-lang/rust/issues/131229)). //! -//! The alternative to active attributes, are inert attributes. -//! These can occur in user code (proc-macro helper attributes). -//! But what's important is, many built-in attributes are inert like this. -//! There is nothing they expand to during the macro expansion process, -//! sometimes because they literally cannot expand to something that is valid Rust. -//! They are really just markers to guide the compilation process. -//! An example is `#[inline(...)]` which changes how code for functions is generated. +//! ## Types of Attributes +//! In Rust, attributes are markers that can be attached to items. They come in two main categories. +//! +//! ### 1. Active Attributes +//! These are attribute-like proc-macros that expand into other Rust code. +//! They can be either user-defined or compiler-provided. Examples of compiler-provided active attributes: +//! - `#[derive(...)]`: Expands into trait implementations +//! - `#[cfg()]`: Expands based on configuration +//! - `#[cfg_attr()]`: Conditional attribute application +//! +//! ### 2. Inert Attributes +//! These are pure markers that don't expand into other code. They guide the compilation process. +//! They can be user-defined (in proc-macro helpers) or built-in. Examples of built-in inert attributes: +//! - `#[stable()]`: Marks stable API items +//! - `#[inline()]`: Suggests function inlining +//! - `#[repr()]`: Controls type representation //! //! ```text //! Active Inert @@ -33,27 +40,21 @@ //! │ (mostly in) │ these are parsed │ //! │ rustc_builtin_macros │ here! │ //! │ │ │ -//! │ │ │ //! │ #[derive(...)] │ #[stable()] │ //! Built-in │ #[cfg()] │ #[inline()] │ //! │ #[cfg_attr()] │ #[repr()] │ //! │ │ │ -//! │ │ │ -//! │ │ │ //! ├──────────────────────┼──────────────────────┤ //! │ │ │ -//! │ │ │ //! │ │ `b` in │ //! │ │ #[proc_macro_derive( │ //! User created │ #[proc_macro_attr()] │ a, │ //! │ │ attributes(b) │ //! │ │ ] │ -//! │ │ │ -//! │ │ │ -//! │ │ │ //! └──────────────────────┴──────────────────────┘ //! ``` //! +//! ## How This Crate Works //! In this crate, syntactical attributes (sequences of tokens that look like //! `#[something(something else)]`) are parsed into more semantic attributes, markers on items. //! Multiple syntactic attributes might influence a single semantic attribute. For example, @@ -63,18 +64,17 @@ //! and `#[unstable()]` syntactic attributes, and at the end produce a single //! [`AttributeKind::Stability`](rustc_attr_data_structures::AttributeKind::Stability). //! -//! As a rule of thumb, when a syntactical attribute can be applied more than once, they should be -//! combined into a single semantic attribute. For example: +//! When multiple instances of the same attribute are allowed, they're combined into a single +//! semantic attribute. For example: //! -//! ``` +//! ```rust //! #[repr(C)] //! #[repr(packed)] //! struct Meow {} //! ``` //! -//! should result in a single `AttributeKind::Repr` containing a list of repr annotations, in this -//! case `C` and `packed`. This is equivalent to writing `#[repr(C, packed)]` in a single -//! syntactical annotation. +//! This is equivalent to `#[repr(C, packed)]` and results in a single `AttributeKind::Repr` +//! containing both `C` and `packed` annotations. // tidy-alphabetical-start #![allow(internal_features)] diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index b7b6a2da549..1b4bb11d87b 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -263,7 +263,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { // something that already has `Fn`-like bounds (or is a closure), so we can't // restrict anyways. } else { - let copy_did = self.infcx.tcx.require_lang_item(LangItem::Copy, Some(span)); + let copy_did = self.infcx.tcx.require_lang_item(LangItem::Copy, span); self.suggest_adding_bounds(&mut err, ty, copy_did, span); } @@ -1915,7 +1915,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { let local_ty = self.body.local_decls[place.local].ty; let typeck_results = tcx.typeck(self.mir_def_id()); - let clone = tcx.require_lang_item(LangItem::Clone, Some(body.span)); + let clone = tcx.require_lang_item(LangItem::Clone, body.span); for expr in expr_finder.clones { if let hir::ExprKind::MethodCall(_, rcvr, _, span) = expr.kind && let Some(rcvr_ty) = typeck_results.node_type_opt(rcvr.hir_id) diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 4f5baeff7c3..4f75dd7e992 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -688,7 +688,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { if !self.unsized_feature_enabled() { let trait_ref = ty::TraitRef::new( tcx, - tcx.require_lang_item(LangItem::Sized, Some(self.last_span)), + tcx.require_lang_item(LangItem::Sized, self.last_span), [place_ty], ); self.prove_trait_ref( @@ -1010,7 +1010,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { let ty = place.ty(self.body, tcx).ty; let trait_ref = ty::TraitRef::new( tcx, - tcx.require_lang_item(LangItem::Copy, Some(span)), + tcx.require_lang_item(LangItem::Copy, span), [ty], ); @@ -1025,11 +1025,8 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { } &Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf, ty) => { - let trait_ref = ty::TraitRef::new( - tcx, - tcx.require_lang_item(LangItem::Sized, Some(span)), - [ty], - ); + let trait_ref = + ty::TraitRef::new(tcx, tcx.require_lang_item(LangItem::Sized, span), [ty]); self.prove_trait_ref( trait_ref, @@ -1041,11 +1038,8 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { &Rvalue::NullaryOp(NullOp::UbChecks, _) => {} Rvalue::ShallowInitBox(_operand, ty) => { - let trait_ref = ty::TraitRef::new( - tcx, - tcx.require_lang_item(LangItem::Sized, Some(span)), - [*ty], - ); + let trait_ref = + ty::TraitRef::new(tcx, tcx.require_lang_item(LangItem::Sized, span), [*ty]); self.prove_trait_ref( trait_ref, @@ -1222,7 +1216,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { let &ty = ty; let trait_ref = ty::TraitRef::new( tcx, - tcx.require_lang_item(LangItem::CoerceUnsized, Some(span)), + tcx.require_lang_item(LangItem::CoerceUnsized, span), [op.ty(self.body, tcx), ty], ); @@ -1811,7 +1805,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { if let PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy) = context { let trait_ref = ty::TraitRef::new( tcx, - tcx.require_lang_item(LangItem::Copy, Some(self.last_span)), + tcx.require_lang_item(LangItem::Copy, self.last_span), [place_ty.ty], ); diff --git a/compiler/rustc_borrowck/src/universal_regions.rs b/compiler/rustc_borrowck/src/universal_regions.rs index c11e14d214c..846299711be 100644 --- a/compiler/rustc_borrowck/src/universal_regions.rs +++ b/compiler/rustc_borrowck/src/universal_regions.rs @@ -544,10 +544,10 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { // (as it's created inside the body itself, not passed in from outside). if let DefiningTy::FnDef(def_id, _) = defining_ty { if self.infcx.tcx.fn_sig(def_id).skip_binder().c_variadic() { - let va_list_did = self.infcx.tcx.require_lang_item( - LangItem::VaList, - Some(self.infcx.tcx.def_span(self.mir_def)), - ); + let va_list_did = self + .infcx + .tcx + .require_lang_item(LangItem::VaList, self.infcx.tcx.def_span(self.mir_def)); let reg_vid = self .infcx diff --git a/compiler/rustc_builtin_macros/src/deriving/mod.rs b/compiler/rustc_builtin_macros/src/deriving/mod.rs index 50e7b989ed8..e45d09b5796 100644 --- a/compiler/rustc_builtin_macros/src/deriving/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/mod.rs @@ -57,7 +57,7 @@ impl MultiItemModifier for BuiltinDerive { let mut items = Vec::new(); match item { Annotatable::Stmt(stmt) => { - if let ast::StmtKind::Item(item) = stmt.into_inner().kind { + if let ast::StmtKind::Item(item) = stmt.kind { (self.0)( ecx, span, diff --git a/compiler/rustc_builtin_macros/src/pattern_type.rs b/compiler/rustc_builtin_macros/src/pattern_type.rs index 3529e5525fc..b61af0b0aaa 100644 --- a/compiler/rustc_builtin_macros/src/pattern_type.rs +++ b/compiler/rustc_builtin_macros/src/pattern_type.rs @@ -30,14 +30,12 @@ fn parse_pat_ty<'a>(cx: &mut ExtCtxt<'a>, stream: TokenStream) -> PResult<'a, (P let pat = pat_to_ty_pat( cx, - parser - .parse_pat_no_top_guard( - None, - RecoverComma::No, - RecoverColon::No, - CommaRecoveryMode::EitherTupleOrPipe, - )? - .into_inner(), + *parser.parse_pat_no_top_guard( + None, + RecoverComma::No, + RecoverColon::No, + CommaRecoveryMode::EitherTupleOrPipe, + )?, ); if parser.token != token::Eof { @@ -58,9 +56,9 @@ fn pat_to_ty_pat(cx: &mut ExtCtxt<'_>, pat: ast::Pat) -> P<TyPat> { end.map(|value| P(AnonConst { id: DUMMY_NODE_ID, value })), include_end, ), - ast::PatKind::Or(variants) => TyPatKind::Or( - variants.into_iter().map(|pat| pat_to_ty_pat(cx, pat.into_inner())).collect(), - ), + ast::PatKind::Or(variants) => { + TyPatKind::Or(variants.into_iter().map(|pat| pat_to_ty_pat(cx, *pat)).collect()) + } ast::PatKind::Err(guar) => TyPatKind::Err(guar), _ => TyPatKind::Err(cx.dcx().span_err(pat.span, "pattern not supported in pattern types")), }; diff --git a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs index a91f2d38a93..daf480a9ce4 100644 --- a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs +++ b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs @@ -354,30 +354,28 @@ fn mk_decls(cx: &mut ExtCtxt<'_>, macros: &[ProcMacro]) -> P<ast::Item> { }) .collect(); - let decls_static = cx - .item_static( + let mut decls_static = cx.item_static( + span, + Ident::new(sym::_DECLS, span), + cx.ty_ref( span, - Ident::new(sym::_DECLS, span), - cx.ty_ref( + cx.ty( span, - cx.ty( - span, - ast::TyKind::Slice( - cx.ty_path(cx.path(span, vec![proc_macro, bridge, client, proc_macro_ty])), - ), + ast::TyKind::Slice( + cx.ty_path(cx.path(span, vec![proc_macro, bridge, client, proc_macro_ty])), ), - None, - ast::Mutability::Not, ), + None, ast::Mutability::Not, - cx.expr_array_ref(span, decls), - ) - .map(|mut i| { - i.attrs.push(cx.attr_word(sym::rustc_proc_macro_decls, span)); - i.attrs.push(cx.attr_word(sym::used, span)); - i.attrs.push(cx.attr_nested_word(sym::allow, sym::deprecated, span)); - i - }); + ), + ast::Mutability::Not, + cx.expr_array_ref(span, decls), + ); + decls_static.attrs.extend([ + cx.attr_word(sym::rustc_proc_macro_decls, span), + cx.attr_word(sym::used, span), + cx.attr_nested_word(sym::allow, sym::deprecated, span), + ]); let block = cx.expr_block( cx.block(span, thin_vec![cx.stmt_item(span, krate), cx.stmt_item(span, decls_static)]), diff --git a/compiler/rustc_builtin_macros/src/test.rs b/compiler/rustc_builtin_macros/src/test.rs index 1cef4f9514c..b439fa34f5b 100644 --- a/compiler/rustc_builtin_macros/src/test.rs +++ b/compiler/rustc_builtin_macros/src/test.rs @@ -40,7 +40,7 @@ pub(crate) fn expand_test_case( let (mut item, is_stmt) = match anno_item { Annotatable::Item(item) => (item, false), Annotatable::Stmt(stmt) if let ast::StmtKind::Item(_) = stmt.kind => { - if let ast::StmtKind::Item(i) = stmt.into_inner().kind { + if let ast::StmtKind::Item(i) = stmt.kind { (i, true) } else { unreachable!() @@ -120,11 +120,7 @@ pub(crate) fn expand_test_or_bench( Annotatable::Item(i) => (i, false), Annotatable::Stmt(stmt) if matches!(stmt.kind, ast::StmtKind::Item(_)) => { // FIXME: Use an 'if let' guard once they are implemented - if let ast::StmtKind::Item(i) = stmt.into_inner().kind { - (i, true) - } else { - unreachable!() - } + if let ast::StmtKind::Item(i) = stmt.kind { (i, true) } else { unreachable!() } } other => { not_testable_error(cx, attr_sp, None); @@ -381,10 +377,7 @@ pub(crate) fn expand_test_or_bench( .into(), ), ); - test_const = test_const.map(|mut tc| { - tc.vis.kind = ast::VisibilityKind::Public; - tc - }); + test_const.vis.kind = ast::VisibilityKind::Public; // extern crate test let test_extern = diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs index 4617304105a..0b641ba64b7 100644 --- a/compiler/rustc_codegen_cranelift/src/base.rs +++ b/compiler/rustc_codegen_cranelift/src/base.rs @@ -380,7 +380,7 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) { rustc_hir::LangItem::PanicBoundsCheck, &[index, len, location], *unwind, - Some(source_info.span), + source_info.span, ); } AssertKind::MisalignedPointerDereference { ref required, ref found } => { @@ -393,7 +393,7 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) { rustc_hir::LangItem::PanicMisalignedPointerDereference, &[required, found, location], *unwind, - Some(source_info.span), + source_info.span, ); } AssertKind::NullPointerDereference => { @@ -404,7 +404,7 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) { rustc_hir::LangItem::PanicNullPointerDereference, &[location], *unwind, - Some(source_info.span), + source_info.span, ) } _ => { @@ -415,7 +415,7 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) { msg.panic_function(), &[location], *unwind, - Some(source_info.span), + source_info.span, ); } } @@ -531,7 +531,7 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) { ); } TerminatorKind::UnwindTerminate(reason) => { - codegen_unwind_terminate(fx, Some(source_info.span), *reason); + codegen_unwind_terminate(fx, source_info.span, *reason); } TerminatorKind::UnwindResume => { // FIXME implement unwinding @@ -1074,7 +1074,7 @@ pub(crate) fn codegen_operand<'tcx>( pub(crate) fn codegen_panic_nounwind<'tcx>( fx: &mut FunctionCx<'_, '_, 'tcx>, msg_str: &str, - span: Option<Span>, + span: Span, ) { let msg_ptr = fx.anonymous_str(msg_str); let msg_len = fx.bcx.ins().iconst(fx.pointer_type, i64::try_from(msg_str.len()).unwrap()); @@ -1091,7 +1091,7 @@ pub(crate) fn codegen_panic_nounwind<'tcx>( pub(crate) fn codegen_unwind_terminate<'tcx>( fx: &mut FunctionCx<'_, '_, 'tcx>, - span: Option<Span>, + span: Span, reason: UnwindTerminateReason, ) { codegen_panic_inner(fx, reason.lang_item(), &[], UnwindAction::Unreachable, span); @@ -1102,7 +1102,7 @@ fn codegen_panic_inner<'tcx>( lang_item: rustc_hir::LangItem, args: &[Value], _unwind: UnwindAction, - span: Option<Span>, + span: Span, ) { fx.bcx.set_cold_block(fx.bcx.current_block().unwrap()); diff --git a/compiler/rustc_codegen_cranelift/src/inline_asm.rs b/compiler/rustc_codegen_cranelift/src/inline_asm.rs index afee5095549..120d6ff9e38 100644 --- a/compiler/rustc_codegen_cranelift/src/inline_asm.rs +++ b/compiler/rustc_codegen_cranelift/src/inline_asm.rs @@ -850,7 +850,7 @@ fn asm_clif_type<'tcx>(fx: &FunctionCx<'_, '_, 'tcx>, ty: Ty<'tcx>) -> Option<ty // Adapted from https://github.com/rust-lang/rust/blob/f3c66088610c1b80110297c2d9a8b5f9265b013f/compiler/rustc_hir_analysis/src/check/intrinsicck.rs#L136-L151 ty::Adt(adt, args) if fx.tcx.is_lang_item(adt.did(), LangItem::MaybeUninit) => { let fields = &adt.non_enum_variant().fields; - let ty = fields[FieldIdx::from_u32(1)].ty(fx.tcx, args); + let ty = fields[FieldIdx::ONE].ty(fx.tcx, args); let ty::Adt(ty, args) = ty.kind() else { unreachable!("expected first field of `MaybeUninit` to be an ADT") }; diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm.rs index 2e02e85a997..99a5518d0b6 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm.rs @@ -71,7 +71,7 @@ pub(crate) fn codegen_llvm_intrinsic_call<'tcx>( See https://github.com/rust-lang/rustc_codegen_cranelift/issues/171\n\ Please open an issue at https://github.com/rust-lang/rustc_codegen_cranelift/issues" ); - crate::base::codegen_panic_nounwind(fx, &msg, None); + crate::base::codegen_panic_nounwind(fx, &msg, span); return; } } diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_aarch64.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_aarch64.rs index d22483cf177..c22f2a7b873 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_aarch64.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_aarch64.rs @@ -512,7 +512,7 @@ pub(super) fn codegen_aarch64_llvm_intrinsic_call<'tcx>( See https://github.com/rust-lang/rustc_codegen_cranelift/issues/171\n\ Please open an issue at https://github.com/rust-lang/rustc_codegen_cranelift/issues" ); - crate::base::codegen_panic_nounwind(fx, &msg, None); + crate::base::codegen_panic_nounwind(fx, &msg, fx.mir.span); return; } } diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs index 3d67913a8ff..615f6c47d90 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs @@ -1321,7 +1321,7 @@ pub(super) fn codegen_x86_llvm_intrinsic_call<'tcx>( See https://github.com/rust-lang/rustc_codegen_cranelift/issues/171\n\ Please open an issue at https://github.com/rust-lang/rustc_codegen_cranelift/issues" ); - crate::base::codegen_panic_nounwind(fx, &msg, None); + crate::base::codegen_panic_nounwind(fx, &msg, span); return; } } diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs index 0de23e55e81..27a5df8b152 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs @@ -785,7 +785,7 @@ fn codegen_regular_intrinsic_call<'tcx>( } }) }); - crate::base::codegen_panic_nounwind(fx, &msg_str, Some(source_info.span)); + crate::base::codegen_panic_nounwind(fx, &msg_str, source_info.span); return Ok(()); } } @@ -884,7 +884,7 @@ fn codegen_regular_intrinsic_call<'tcx>( crate::base::codegen_panic_nounwind( fx, "128bit atomics not yet supported", - None, + source_info.span, ); return Ok(()); } else { @@ -919,7 +919,7 @@ fn codegen_regular_intrinsic_call<'tcx>( crate::base::codegen_panic_nounwind( fx, "128bit atomics not yet supported", - None, + source_info.span, ); return Ok(()); } else { diff --git a/compiler/rustc_codegen_cranelift/src/main_shim.rs b/compiler/rustc_codegen_cranelift/src/main_shim.rs index 6eef97c14dd..bf756860b64 100644 --- a/compiler/rustc_codegen_cranelift/src/main_shim.rs +++ b/compiler/rustc_codegen_cranelift/src/main_shim.rs @@ -101,7 +101,7 @@ pub(crate) fn maybe_create_entry_wrapper( let call_inst = bcx.ins().call(main_func_ref, &[]); let call_results = bcx.func.dfg.inst_results(call_inst).to_owned(); - let termination_trait = tcx.require_lang_item(LangItem::Termination, None); + let termination_trait = tcx.require_lang_item(LangItem::Termination, DUMMY_SP); let report = tcx .associated_items(termination_trait) .find_by_ident_and_kind( @@ -136,7 +136,7 @@ pub(crate) fn maybe_create_entry_wrapper( } } else { // Regular main fn invoked via start lang item. - let start_def_id = tcx.require_lang_item(LangItem::Start, None); + let start_def_id = tcx.require_lang_item(LangItem::Start, DUMMY_SP); let start_instance = Instance::expect_resolve( tcx, ty::TypingEnv::fully_monomorphized(), diff --git a/compiler/rustc_codegen_cranelift/src/num.rs b/compiler/rustc_codegen_cranelift/src/num.rs index f53045df6e7..95d44dfb6d9 100644 --- a/compiler/rustc_codegen_cranelift/src/num.rs +++ b/compiler/rustc_codegen_cranelift/src/num.rs @@ -54,7 +54,7 @@ fn codegen_three_way_compare<'tcx>( let gt = fx.bcx.ins().icmp(gt_cc, lhs, rhs); let lt = fx.bcx.ins().icmp(lt_cc, lhs, rhs); let val = fx.bcx.ins().isub(gt, lt); - CValue::by_val(val, fx.layout_of(fx.tcx.ty_ordering_enum(Some(fx.mir.span)))) + CValue::by_val(val, fx.layout_of(fx.tcx.ty_ordering_enum(fx.mir.span))) } fn codegen_compare_bin_op<'tcx>( diff --git a/compiler/rustc_codegen_cranelift/src/unsize.rs b/compiler/rustc_codegen_cranelift/src/unsize.rs index f8bbb214920..662546e4999 100644 --- a/compiler/rustc_codegen_cranelift/src/unsize.rs +++ b/compiler/rustc_codegen_cranelift/src/unsize.rs @@ -240,7 +240,7 @@ pub(crate) fn size_and_align_of<'tcx>( }) }); - codegen_panic_nounwind(fx, &msg_str, None); + codegen_panic_nounwind(fx, &msg_str, fx.mir.span); fx.bcx.switch_to_block(next_block); diff --git a/compiler/rustc_codegen_cranelift/src/vtable.rs b/compiler/rustc_codegen_cranelift/src/vtable.rs index 9d9e0462a9b..05a8e3c3342 100644 --- a/compiler/rustc_codegen_cranelift/src/vtable.rs +++ b/compiler/rustc_codegen_cranelift/src/vtable.rs @@ -53,7 +53,7 @@ pub(crate) fn get_ptr_and_method_ref<'tcx>( .layout() .non_1zst_field(fx) .expect("not exactly one non-1-ZST field in a `DispatchFromDyn` type"); - arg = arg.value_field(fx, FieldIdx::new(idx)); + arg = arg.value_field(fx, idx); } } @@ -62,8 +62,7 @@ pub(crate) fn get_ptr_and_method_ref<'tcx>( let inner_layout = fx.layout_of(arg.layout().ty.builtin_deref(true).unwrap()); let dyn_star = CPlace::for_ptr(Pointer::new(arg.load_scalar(fx)), inner_layout); let ptr = dyn_star.place_field(fx, FieldIdx::ZERO).to_ptr(); - let vtable = - dyn_star.place_field(fx, FieldIdx::new(1)).to_cvalue(fx).load_scalar(fx); + let vtable = dyn_star.place_field(fx, FieldIdx::ONE).to_cvalue(fx).load_scalar(fx); break 'block (ptr, vtable); } } diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index f7863fe4ae2..c2d6a26de0f 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -561,7 +561,7 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( let EntryFnType::Main { sigpipe } = entry_type; let (start_fn, start_ty, args, instance) = { - let start_def_id = cx.tcx().require_lang_item(LangItem::Start, None); + let start_def_id = cx.tcx().require_lang_item(LangItem::Start, DUMMY_SP); let start_instance = ty::Instance::expect_resolve( cx.tcx(), cx.typing_env(), diff --git a/compiler/rustc_codegen_ssa/src/common.rs b/compiler/rustc_codegen_ssa/src/common.rs index ef0d565333e..48565e0b4de 100644 --- a/compiler/rustc_codegen_ssa/src/common.rs +++ b/compiler/rustc_codegen_ssa/src/common.rs @@ -110,7 +110,7 @@ mod temp_stable_hash_impls { pub(crate) fn build_langcall<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( bx: &Bx, - span: Option<Span>, + span: Span, li: LangItem, ) -> (Bx::FnAbiOfResult, Bx::Value, Instance<'tcx>) { let tcx = bx.tcx(); diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index 1baab62ae43..43b87171d51 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -783,7 +783,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } }; - let (fn_abi, llfn, instance) = common::build_langcall(bx, Some(span), lang_item); + let (fn_abi, llfn, instance) = common::build_langcall(bx, span, lang_item); // Codegen the actual panic invoke/call. let merging_succ = @@ -803,7 +803,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { self.set_debug_loc(bx, terminator.source_info); // Obtain the panic entry point. - let (fn_abi, llfn, instance) = common::build_langcall(bx, Some(span), reason.lang_item()); + let (fn_abi, llfn, instance) = common::build_langcall(bx, span, reason.lang_item()); // Codegen the actual panic invoke/call. let merging_succ = helper.do_call( @@ -871,7 +871,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // Obtain the panic entry point. let (fn_abi, llfn, instance) = - common::build_langcall(bx, Some(source_info.span), LangItem::PanicNounwind); + common::build_langcall(bx, source_info.span, LangItem::PanicNounwind); // Codegen the actual panic invoke/call. Some(helper.do_call( @@ -1077,7 +1077,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let (idx, _) = op.layout.non_1zst_field(bx).expect( "not exactly one non-1-ZST field in a `DispatchFromDyn` type", ); - op = op.extract_field(self, bx, idx); + op = op.extract_field(self, bx, idx.as_usize()); } // Now that we have `*dyn Trait` or `&dyn Trait`, split it up into its @@ -1109,7 +1109,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let (idx, _) = op.layout.non_1zst_field(bx).expect( "not exactly one non-1-ZST field in a `DispatchFromDyn` type", ); - op = op.extract_field(self, bx, idx); + op = op.extract_field(self, bx, idx.as_usize()); } // Make sure that we've actually unwrapped the rcvr down @@ -1830,7 +1830,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { self.set_debug_loc(&mut bx, mir::SourceInfo::outermost(self.mir.span)); - let (fn_abi, fn_ptr, instance) = common::build_langcall(&bx, None, reason.lang_item()); + let (fn_abi, fn_ptr, instance) = + common::build_langcall(&bx, self.mir.span, reason.lang_item()); if is_call_from_compiler_builtins_to_upstream_monomorphization(bx.tcx(), instance) { bx.abort(); } else { diff --git a/compiler/rustc_codegen_ssa/src/mir/operand.rs b/compiler/rustc_codegen_ssa/src/mir/operand.rs index b7f2277bfda..e9389ddf93b 100644 --- a/compiler/rustc_codegen_ssa/src/mir/operand.rs +++ b/compiler/rustc_codegen_ssa/src/mir/operand.rs @@ -45,9 +45,15 @@ pub enum OperandValue<V> { Immediate(V), /// A pair of immediate LLVM values. Used by wide pointers too. /// - /// An `OperandValue` *must* be this variant for any type for which + /// # Invariants + /// - For `Pair(a, b)`, `a` is always at offset 0, but may have `FieldIdx(1..)` + /// - `b` is not at offset 0, because `V` is not a 1ZST type. + /// - `a` and `b` will have a different FieldIdx, but otherwise `b`'s may be lower + /// or they may not be adjacent, due to arbitrary numbers of 1ZST fields that + /// will not affect the shape of the data which determines if `Pair` will be used. + /// - An `OperandValue` *must* be this variant for any type for which /// [`LayoutTypeCodegenMethods::is_backend_scalar_pair`] returns `true`. - /// The backend values in this variant must be the *immediate* backend types, + /// - The backend values in this variant must be the *immediate* backend types, /// as returned by [`LayoutTypeCodegenMethods::scalar_pair_element_backend_type`] /// with `immediate: true`. Pair(V, V), diff --git a/compiler/rustc_codegen_ssa/src/size_of_val.rs b/compiler/rustc_codegen_ssa/src/size_of_val.rs index ac2366340fb..577012151e4 100644 --- a/compiler/rustc_codegen_ssa/src/size_of_val.rs +++ b/compiler/rustc_codegen_ssa/src/size_of_val.rs @@ -5,6 +5,7 @@ use rustc_hir::LangItem; use rustc_middle::bug; use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths}; use rustc_middle::ty::{self, Ty}; +use rustc_span::DUMMY_SP; use tracing::{debug, trace}; use crate::common::IntPredicate; @@ -62,7 +63,7 @@ pub fn size_and_align_of_dst<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( // Obtain the panic entry point. let (fn_abi, llfn, _instance) = - common::build_langcall(bx, None, LangItem::PanicNounwind); + common::build_langcall(bx, DUMMY_SP, LangItem::PanicNounwind); // Generate the call. Cannot use `do_call` since we don't have a MIR terminator so we // can't create a `TerminationCodegenHelper`. (But we are in good company, this code is diff --git a/compiler/rustc_const_eval/src/check_consts/ops.rs b/compiler/rustc_const_eval/src/check_consts/ops.rs index d701646719a..9c30dbff99e 100644 --- a/compiler/rustc_const_eval/src/check_consts/ops.rs +++ b/compiler/rustc_const_eval/src/check_consts/ops.rs @@ -345,11 +345,7 @@ fn build_error_for_const_call<'tcx>( non_or_conditionally, }); - note_trait_if_possible( - &mut err, - self_ty, - tcx.require_lang_item(LangItem::Deref, Some(span)), - ); + note_trait_if_possible(&mut err, self_ty, tcx.require_lang_item(LangItem::Deref, span)); err } _ if tcx.opt_parent(callee) == tcx.get_diagnostic_item(sym::FmtArgumentsNew) => { diff --git a/compiler/rustc_const_eval/src/check_consts/qualifs.rs b/compiler/rustc_const_eval/src/check_consts/qualifs.rs index dfcd1969a73..c1a37ab6a83 100644 --- a/compiler/rustc_const_eval/src/check_consts/qualifs.rs +++ b/compiler/rustc_const_eval/src/check_consts/qualifs.rs @@ -99,7 +99,7 @@ impl Qualif for HasMutInterior { // requires borrowck, which in turn will invoke mir_const_qualifs again, causing a cycle error. // Instead we invoke an obligation context manually, and provide the opaque type inference settings // that allow the trait solver to just error out instead of cycling. - let freeze_def_id = cx.tcx.require_lang_item(LangItem::Freeze, Some(cx.body.span)); + let freeze_def_id = cx.tcx.require_lang_item(LangItem::Freeze, cx.body.span); // FIXME(#132279): Once we've got a typing mode which reveals opaque types using the HIR // typeck results without causing query cycles, we should use this here instead of defining // opaque types. @@ -180,7 +180,7 @@ impl Qualif for NeedsNonConstDrop { // that the components of this type are also `~const Destruct`. This // amounts to verifying that there are no values in this ADT that may have // a non-const drop. - let destruct_def_id = cx.tcx.require_lang_item(LangItem::Destruct, Some(cx.body.span)); + let destruct_def_id = cx.tcx.require_lang_item(LangItem::Destruct, cx.body.span); let (infcx, param_env) = cx.tcx.infer_ctxt().build_with_typing_env(cx.typing_env); let ocx = ObligationCtxt::new(&infcx); ocx.register_obligation(Obligation::new( diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index 3922b33ea84..a68dcf29988 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -249,7 +249,7 @@ impl<'tcx> CompileTimeInterpCx<'tcx> { return Err(ConstEvalErrKind::Panic { msg, file, line, col }).into(); } else if self.tcx.is_lang_item(def_id, LangItem::PanicFmt) { // For panic_fmt, call const_panic_fmt instead. - let const_def_id = self.tcx.require_lang_item(LangItem::ConstPanicFmt, None); + let const_def_id = self.tcx.require_lang_item(LangItem::ConstPanicFmt, self.tcx.span); let new_instance = ty::Instance::expect_resolve( *self.tcx, self.typing_env(), diff --git a/compiler/rustc_const_eval/src/const_eval/mod.rs b/compiler/rustc_const_eval/src/const_eval/mod.rs index c0438fb3ff8..6fd0b9d26e3 100644 --- a/compiler/rustc_const_eval/src/const_eval/mod.rs +++ b/compiler/rustc_const_eval/src/const_eval/mod.rs @@ -1,6 +1,6 @@ // Not in interpret to make sure we do not use private implementation details -use rustc_abi::VariantIdx; +use rustc_abi::{FieldIdx, VariantIdx}; use rustc_middle::query::Key; use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::{self, Ty, TyCtxt}; @@ -60,7 +60,7 @@ pub(crate) fn try_destructure_mir_constant_for_user_output<'tcx>( let fields_iter = (0..field_count) .map(|i| { - let field_op = ecx.project_field(&down, i).discard_err()?; + let field_op = ecx.project_field(&down, FieldIdx::from_usize(i)).discard_err()?; let val = op_to_const(&ecx, &field_op, /* for diagnostics */ true); Some((val, field_op.layout.ty)) }) diff --git a/compiler/rustc_const_eval/src/const_eval/valtrees.rs b/compiler/rustc_const_eval/src/const_eval/valtrees.rs index 34239ae1d15..58d230af683 100644 --- a/compiler/rustc_const_eval/src/const_eval/valtrees.rs +++ b/compiler/rustc_const_eval/src/const_eval/valtrees.rs @@ -1,4 +1,4 @@ -use rustc_abi::{BackendRepr, VariantIdx}; +use rustc_abi::{BackendRepr, FieldIdx, VariantIdx}; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_middle::mir::interpret::{EvalToValTreeResult, GlobalId, ReportedErrorInfo}; use rustc_middle::ty::layout::{LayoutCx, LayoutOf, TyAndLayout}; @@ -40,7 +40,7 @@ fn branches<'tcx>( } for i in 0..field_count { - let field = ecx.project_field(&place, i).unwrap(); + let field = ecx.project_field(&place, FieldIdx::from_usize(i)).unwrap(); let valtree = const_to_valtree_inner(ecx, &field, num_nodes)?; branches.push(valtree); } @@ -437,7 +437,7 @@ fn valtree_into_mplace<'tcx>( ty::Str | ty::Slice(_) | ty::Array(..) => { ecx.project_index(place, i as u64).unwrap() } - _ => ecx.project_field(&place_adjusted, i).unwrap(), + _ => ecx.project_field(&place_adjusted, FieldIdx::from_usize(i)).unwrap(), }; debug!(?place_inner); diff --git a/compiler/rustc_const_eval/src/interpret/call.rs b/compiler/rustc_const_eval/src/interpret/call.rs index 789baea0734..37677f9e048 100644 --- a/compiler/rustc_const_eval/src/interpret/call.rs +++ b/compiler/rustc_const_eval/src/interpret/call.rs @@ -62,7 +62,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { pub(super) fn fn_arg_field( &self, arg: &FnArg<'tcx, M::Provenance>, - field: usize, + field: FieldIdx, ) -> InterpResult<'tcx, FnArg<'tcx, M::Provenance>> { interp_ok(match arg { FnArg::Copy(op) => FnArg::Copy(self.project_field(op, field)?), @@ -600,10 +600,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { Cow::from( args.iter() .map(|a| interp_ok(a.clone())) - .chain( - (0..untuple_arg.layout().fields.count()) - .map(|i| self.fn_arg_field(untuple_arg, i)), - ) + .chain((0..untuple_arg.layout().fields.count()).map(|i| { + self.fn_arg_field(untuple_arg, FieldIdx::from_usize(i)) + })) .collect::<InterpResult<'_, Vec<_>>>()?, ) } else { diff --git a/compiler/rustc_const_eval/src/interpret/cast.rs b/compiler/rustc_const_eval/src/interpret/cast.rs index 643a5805019..9e15f4572d7 100644 --- a/compiler/rustc_const_eval/src/interpret/cast.rs +++ b/compiler/rustc_const_eval/src/interpret/cast.rs @@ -1,6 +1,6 @@ use std::assert_matches::assert_matches; -use rustc_abi::Integer; +use rustc_abi::{FieldIdx, Integer}; use rustc_apfloat::ieee::{Double, Half, Quad, Single}; use rustc_apfloat::{Float, FloatConvert}; use rustc_middle::mir::CastKind; @@ -484,6 +484,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { let mut found_cast_field = false; for i in 0..src.layout.fields.count() { let cast_ty_field = cast_ty.field(self, i); + let i = FieldIdx::from_usize(i); let src_field = self.project_field(src, i)?; let dst_field = self.project_field(dest, i)?; if src_field.layout.is_1zst() && cast_ty_field.is_1zst() { diff --git a/compiler/rustc_const_eval/src/interpret/discriminant.rs b/compiler/rustc_const_eval/src/interpret/discriminant.rs index 020cd65d75d..6c4b000e16b 100644 --- a/compiler/rustc_const_eval/src/interpret/discriminant.rs +++ b/compiler/rustc_const_eval/src/interpret/discriminant.rs @@ -26,7 +26,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // No need to validate that the discriminant here because the // `TyAndLayout::for_variant()` call earlier already checks the // variant is valid. - let tag_dest = self.project_field(dest, tag_field.as_usize())?; + let tag_dest = self.project_field(dest, tag_field)?; self.write_scalar(tag, &tag_dest) } None => { @@ -96,7 +96,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { let tag_layout = self.layout_of(tag_scalar_layout.primitive().to_int_ty(*self.tcx))?; // Read tag and sanity-check `tag_layout`. - let tag_val = self.read_immediate(&self.project_field(op, tag_field.as_usize())?)?; + let tag_val = self.read_immediate(&self.project_field(op, tag_field)?)?; assert_eq!(tag_layout.size, tag_val.layout.size); assert_eq!(tag_layout.backend_repr.is_signed(), tag_val.layout.backend_repr.is_signed()); trace!("tag value: {}", tag_val); diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs index 39755169e6c..77667ba823a 100644 --- a/compiler/rustc_const_eval/src/interpret/operand.rs +++ b/compiler/rustc_const_eval/src/interpret/operand.rs @@ -12,6 +12,7 @@ use rustc_middle::ty::layout::{HasTyCtxt, HasTypingEnv, LayoutOf, TyAndLayout}; use rustc_middle::ty::print::{FmtPrinter, PrettyPrinter}; use rustc_middle::ty::{ConstInt, ScalarInt, Ty, TyCtxt}; use rustc_middle::{bug, mir, span_bug, ty}; +use rustc_span::DUMMY_SP; use tracing::trace; use super::{ @@ -307,7 +308,7 @@ impl<'tcx, Prov: Provenance> ImmTy<'tcx, Prov> { #[inline] pub fn from_ordering(c: std::cmp::Ordering, tcx: TyCtxt<'tcx>) -> Self { // Can use any typing env, since `Ordering` is always monomorphic. - let ty = tcx.ty_ordering_enum(None); + let ty = tcx.ty_ordering_enum(DUMMY_SP); let layout = tcx.layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(ty)).unwrap(); Self::from_scalar(Scalar::Int(c.into()), layout) diff --git a/compiler/rustc_const_eval/src/interpret/projection.rs b/compiler/rustc_const_eval/src/interpret/projection.rs index 8ecb3e13d5c..ad47a19a14d 100644 --- a/compiler/rustc_const_eval/src/interpret/projection.rs +++ b/compiler/rustc_const_eval/src/interpret/projection.rs @@ -10,7 +10,7 @@ use std::marker::PhantomData; use std::ops::Range; -use rustc_abi::{self as abi, Size, VariantIdx}; +use rustc_abi::{self as abi, FieldIdx, Size, VariantIdx}; use rustc_middle::ty::Ty; use rustc_middle::ty::layout::{LayoutOf, TyAndLayout}; use rustc_middle::{bug, mir, span_bug, ty}; @@ -144,22 +144,22 @@ where /// always possible without allocating, so it can take `&self`. Also return the field's layout. /// This supports both struct and array fields, but not slices! /// - /// This also works for arrays, but then the `usize` index type is restricting. - /// For indexing into arrays, use `mplace_index`. + /// This also works for arrays, but then the `FieldIdx` index type is restricting. + /// For indexing into arrays, use [`Self::project_index`]. pub fn project_field<P: Projectable<'tcx, M::Provenance>>( &self, base: &P, - field: usize, + field: FieldIdx, ) -> InterpResult<'tcx, P> { // Slices nominally have length 0, so they will panic somewhere in `fields.offset`. debug_assert!( !matches!(base.layout().ty.kind(), ty::Slice(..)), "`field` projection called on a slice -- call `index` projection instead" ); - let offset = base.layout().fields.offset(field); + let offset = base.layout().fields.offset(field.as_usize()); // Computing the layout does normalization, so we get a normalized type out of this // even if the field type is non-normalized (possible e.g. via associated types). - let field_layout = base.layout().field(self, field); + let field_layout = base.layout().field(self, field.as_usize()); // Offset may need adjustment for unsized fields. let (meta, offset) = if field_layout.is_unsized() { @@ -244,7 +244,7 @@ where } _ => span_bug!( self.cur_span(), - "`mplace_index` called on non-array type {:?}", + "`project_index` called on non-array type {:?}", base.layout().ty ), }; @@ -260,7 +260,7 @@ where ) -> InterpResult<'tcx, (P, u64)> { assert!(base.layout().ty.ty_adt_def().unwrap().repr().simd()); // SIMD types must be newtypes around arrays, so all we have to do is project to their only field. - let array = self.project_field(base, 0)?; + let array = self.project_field(base, FieldIdx::ZERO)?; let len = array.len(self)?; interp_ok((array, len)) } @@ -384,7 +384,7 @@ where UnwrapUnsafeBinder(target) => base.transmute(self.layout_of(target)?, self)?, // We don't want anything happening here, this is here as a dummy. Subtype(_) => base.transmute(base.layout(), self)?, - Field(field, _) => self.project_field(base, field.index())?, + Field(field, _) => self.project_field(base, field)?, Downcast(_, variant) => self.project_downcast(base, variant)?, Deref => self.deref_pointer(&base.to_op(self)?)?.into(), Index(local) => { diff --git a/compiler/rustc_const_eval/src/interpret/step.rs b/compiler/rustc_const_eval/src/interpret/step.rs index 975325b0c1e..833fcc38817 100644 --- a/compiler/rustc_const_eval/src/interpret/step.rs +++ b/compiler/rustc_const_eval/src/interpret/step.rs @@ -333,7 +333,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { } for (field_index, operand) in operands.iter_enumerated() { let field_index = active_field_index.unwrap_or(field_index); - let field_dest = self.project_field(&variant_dest, field_index.as_usize())?; + let field_dest = self.project_field(&variant_dest, field_index)?; let op = self.eval_operand(operand, Some(field_dest.layout))?; self.copy_op(&op, &field_dest)?; } diff --git a/compiler/rustc_const_eval/src/interpret/traits.rs b/compiler/rustc_const_eval/src/interpret/traits.rs index a5029eea5a7..7249ef23bf6 100644 --- a/compiler/rustc_const_eval/src/interpret/traits.rs +++ b/compiler/rustc_const_eval/src/interpret/traits.rs @@ -1,4 +1,4 @@ -use rustc_abi::{Align, Size}; +use rustc_abi::{Align, FieldIdx, Size}; use rustc_middle::mir::interpret::{InterpResult, Pointer}; use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::{self, ExistentialPredicateStableCmpExt, Ty, TyCtxt, VtblEntry}; @@ -137,8 +137,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { matches!(val.layout().ty.kind(), ty::Dynamic(_, _, ty::DynStar)), "`unpack_dyn_star` only makes sense on `dyn*` types" ); - let data = self.project_field(val, 0)?; - let vtable = self.project_field(val, 1)?; + let data = self.project_field(val, FieldIdx::ZERO)?; + let vtable = self.project_field(val, FieldIdx::ONE)?; let vtable = self.read_pointer(&vtable.to_op(self)?)?; let ty = self.get_ptr_vtable_ty(vtable, Some(expected_trait))?; // `data` is already the right thing but has the wrong type. So we transmute it. diff --git a/compiler/rustc_const_eval/src/interpret/visitor.rs b/compiler/rustc_const_eval/src/interpret/visitor.rs index 3647c109a6e..5aea91233bd 100644 --- a/compiler/rustc_const_eval/src/interpret/visitor.rs +++ b/compiler/rustc_const_eval/src/interpret/visitor.rs @@ -112,8 +112,10 @@ pub trait ValueVisitor<'tcx, M: Machine<'tcx>>: Sized { // So we transmute it to a raw pointer. let raw_ptr_ty = Ty::new_mut_ptr(*self.ecx().tcx, self.ecx().tcx.types.unit); let raw_ptr_ty = self.ecx().layout_of(raw_ptr_ty)?; - let vtable_field = - self.ecx().project_field(v, 1)?.transmute(raw_ptr_ty, self.ecx())?; + let vtable_field = self + .ecx() + .project_field(v, FieldIdx::ONE)? + .transmute(raw_ptr_ty, self.ecx())?; self.visit_field(v, 1, &vtable_field)?; // Then unpack the first field, and continue. @@ -140,14 +142,16 @@ pub trait ValueVisitor<'tcx, M: Machine<'tcx>>: Sized { // `Box` has two fields: the pointer we care about, and the allocator. assert_eq!(v.layout().fields.count(), 2, "`Box` must have exactly 2 fields"); - let (unique_ptr, alloc) = - (self.ecx().project_field(v, 0)?, self.ecx().project_field(v, 1)?); + let (unique_ptr, alloc) = ( + self.ecx().project_field(v, FieldIdx::ZERO)?, + self.ecx().project_field(v, FieldIdx::ONE)?, + ); // Unfortunately there is some type junk in the way here: `unique_ptr` is a `Unique`... // (which means another 2 fields, the second of which is a `PhantomData`) assert_eq!(unique_ptr.layout().fields.count(), 2); let (nonnull_ptr, phantom) = ( - self.ecx().project_field(&unique_ptr, 0)?, - self.ecx().project_field(&unique_ptr, 1)?, + self.ecx().project_field(&unique_ptr, FieldIdx::ZERO)?, + self.ecx().project_field(&unique_ptr, FieldIdx::ONE)?, ); assert!( phantom.layout().ty.ty_adt_def().is_some_and(|adt| adt.is_phantom_data()), @@ -156,7 +160,7 @@ pub trait ValueVisitor<'tcx, M: Machine<'tcx>>: Sized { ); // ... that contains a `NonNull`... (gladly, only a single field here) assert_eq!(nonnull_ptr.layout().fields.count(), 1); - let raw_ptr = self.ecx().project_field(&nonnull_ptr, 0)?; // the actual raw ptr + let raw_ptr = self.ecx().project_field(&nonnull_ptr, FieldIdx::ZERO)?; // the actual raw ptr // ... whose only field finally is a raw ptr we can dereference. self.visit_box(ty, &raw_ptr)?; @@ -188,9 +192,8 @@ pub trait ValueVisitor<'tcx, M: Machine<'tcx>>: Sized { } FieldsShape::Arbitrary { memory_index, .. } => { for idx in Self::aggregate_field_iter(memory_index) { - let idx = idx.as_usize(); let field = self.ecx().project_field(v, idx)?; - self.visit_field(v, idx, &field)?; + self.visit_field(v, idx.as_usize(), &field)?; } } FieldsShape::Array { .. } => { diff --git a/compiler/rustc_const_eval/src/util/caller_location.rs b/compiler/rustc_const_eval/src/util/caller_location.rs index 9c867cc615e..671214002a0 100644 --- a/compiler/rustc_const_eval/src/util/caller_location.rs +++ b/compiler/rustc_const_eval/src/util/caller_location.rs @@ -1,3 +1,4 @@ +use rustc_abi::FieldIdx; use rustc_hir::LangItem; use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::{self, TyCtxt}; @@ -35,17 +36,20 @@ fn alloc_caller_location<'tcx>( // Allocate memory for `CallerLocation` struct. let loc_ty = ecx .tcx - .type_of(ecx.tcx.require_lang_item(LangItem::PanicLocation, None)) + .type_of(ecx.tcx.require_lang_item(LangItem::PanicLocation, ecx.tcx.span)) .instantiate(*ecx.tcx, ecx.tcx.mk_args(&[ecx.tcx.lifetimes.re_erased.into()])); let loc_layout = ecx.layout_of(loc_ty).unwrap(); let location = ecx.allocate(loc_layout, MemoryKind::CallerLocation).unwrap(); // Initialize fields. - ecx.write_immediate(file_wide_ptr, &ecx.project_field(&location, 0).unwrap()) + ecx.write_immediate( + file_wide_ptr, + &ecx.project_field(&location, FieldIdx::from_u32(0)).unwrap(), + ) + .expect("writing to memory we just allocated cannot fail"); + ecx.write_scalar(line, &ecx.project_field(&location, FieldIdx::from_u32(1)).unwrap()) .expect("writing to memory we just allocated cannot fail"); - ecx.write_scalar(line, &ecx.project_field(&location, 1).unwrap()) - .expect("writing to memory we just allocated cannot fail"); - ecx.write_scalar(col, &ecx.project_field(&location, 2).unwrap()) + ecx.write_scalar(col, &ecx.project_field(&location, FieldIdx::from_u32(2)).unwrap()) .expect("writing to memory we just allocated cannot fail"); location diff --git a/compiler/rustc_error_codes/src/error_codes/E0783.md b/compiler/rustc_error_codes/src/error_codes/E0783.md index 73981e59e0d..ac8641cfc5a 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0783.md +++ b/compiler/rustc_error_codes/src/error_codes/E0783.md @@ -9,7 +9,7 @@ match 2u8 { } ``` -Older Rust code using previous editions allowed `...` to stand for exclusive +Older Rust code using previous editions allowed `...` to stand for inclusive ranges which are now signified using `..=`. To make this code compile replace the `...` with `..=`. diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index 2accfba383e..c7b975d8f3e 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -167,7 +167,7 @@ impl Annotatable { pub fn expect_stmt(self) -> ast::Stmt { match self { - Annotatable::Stmt(stmt) => stmt.into_inner(), + Annotatable::Stmt(stmt) => *stmt, _ => panic!("expected statement"), } } diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 82a2719ca96..569165a64e5 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -1183,9 +1183,8 @@ impl InvocationCollectorNode for P<ast::Item> { matches!(self.kind, ItemKind::MacCall(..)) } fn take_mac_call(self) -> (P<ast::MacCall>, ast::AttrVec, AddSemicolon) { - let node = self.into_inner(); - match node.kind { - ItemKind::MacCall(mac) => (mac, node.attrs, AddSemicolon::No), + match self.kind { + ItemKind::MacCall(mac) => (mac, self.attrs, AddSemicolon::No), _ => unreachable!(), } } @@ -1339,7 +1338,7 @@ impl InvocationCollectorNode for AstNodeWrapper<P<ast::AssocItem>, TraitItemTag> matches!(self.wrapped.kind, AssocItemKind::MacCall(..)) } fn take_mac_call(self) -> (P<ast::MacCall>, ast::AttrVec, AddSemicolon) { - let item = self.wrapped.into_inner(); + let item = self.wrapped; match item.kind { AssocItemKind::MacCall(mac) => (mac, item.attrs, AddSemicolon::No), _ => unreachable!(), @@ -1380,7 +1379,7 @@ impl InvocationCollectorNode for AstNodeWrapper<P<ast::AssocItem>, ImplItemTag> matches!(self.wrapped.kind, AssocItemKind::MacCall(..)) } fn take_mac_call(self) -> (P<ast::MacCall>, ast::AttrVec, AddSemicolon) { - let item = self.wrapped.into_inner(); + let item = self.wrapped; match item.kind { AssocItemKind::MacCall(mac) => (mac, item.attrs, AddSemicolon::No), _ => unreachable!(), @@ -1421,7 +1420,7 @@ impl InvocationCollectorNode for AstNodeWrapper<P<ast::AssocItem>, TraitImplItem matches!(self.wrapped.kind, AssocItemKind::MacCall(..)) } fn take_mac_call(self) -> (P<ast::MacCall>, ast::AttrVec, AddSemicolon) { - let item = self.wrapped.into_inner(); + let item = self.wrapped; match item.kind { AssocItemKind::MacCall(mac) => (mac, item.attrs, AddSemicolon::No), _ => unreachable!(), @@ -1459,9 +1458,8 @@ impl InvocationCollectorNode for P<ast::ForeignItem> { matches!(self.kind, ForeignItemKind::MacCall(..)) } fn take_mac_call(self) -> (P<ast::MacCall>, ast::AttrVec, AddSemicolon) { - let node = self.into_inner(); - match node.kind { - ForeignItemKind::MacCall(mac) => (mac, node.attrs, AddSemicolon::No), + match self.kind { + ForeignItemKind::MacCall(mac) => (mac, self.attrs, AddSemicolon::No), _ => unreachable!(), } } @@ -1596,16 +1594,16 @@ impl InvocationCollectorNode for ast::Stmt { // `StmtKind`s and treat them as statement macro invocations, not as items or expressions. let (add_semicolon, mac, attrs) = match self.kind { StmtKind::MacCall(mac) => { - let ast::MacCallStmt { mac, style, attrs, .. } = mac.into_inner(); + let ast::MacCallStmt { mac, style, attrs, .. } = *mac; (style == MacStmtStyle::Semicolon, mac, attrs) } - StmtKind::Item(item) => match item.into_inner() { + StmtKind::Item(item) => match *item { ast::Item { kind: ItemKind::MacCall(mac), attrs, .. } => { (mac.args.need_semicolon(), mac, attrs) } _ => unreachable!(), }, - StmtKind::Semi(expr) => match expr.into_inner() { + StmtKind::Semi(expr) => match *expr { ast::Expr { kind: ExprKind::MacCall(mac), attrs, .. } => { (mac.args.need_semicolon(), mac, attrs) } @@ -1686,8 +1684,7 @@ impl InvocationCollectorNode for P<ast::Ty> { matches!(self.kind, ast::TyKind::MacCall(..)) } fn take_mac_call(self) -> (P<ast::MacCall>, ast::AttrVec, AddSemicolon) { - let node = self.into_inner(); - match node.kind { + match self.kind { TyKind::MacCall(mac) => (mac, AttrVec::new(), AddSemicolon::No), _ => unreachable!(), } @@ -1710,8 +1707,7 @@ impl InvocationCollectorNode for P<ast::Pat> { matches!(self.kind, PatKind::MacCall(..)) } fn take_mac_call(self) -> (P<ast::MacCall>, ast::AttrVec, AddSemicolon) { - let node = self.into_inner(); - match node.kind { + match self.kind { PatKind::MacCall(mac) => (mac, AttrVec::new(), AddSemicolon::No), _ => unreachable!(), } @@ -1737,9 +1733,8 @@ impl InvocationCollectorNode for P<ast::Expr> { matches!(self.kind, ExprKind::MacCall(..)) } fn take_mac_call(self) -> (P<ast::MacCall>, ast::AttrVec, AddSemicolon) { - let node = self.into_inner(); - match node.kind { - ExprKind::MacCall(mac) => (mac, node.attrs, AddSemicolon::No), + match self.kind { + ExprKind::MacCall(mac) => (mac, self.attrs, AddSemicolon::No), _ => unreachable!(), } } @@ -1763,7 +1758,7 @@ impl InvocationCollectorNode for AstNodeWrapper<P<ast::Expr>, OptExprTag> { matches!(self.wrapped.kind, ast::ExprKind::MacCall(..)) } fn take_mac_call(self) -> (P<ast::MacCall>, ast::AttrVec, AddSemicolon) { - let node = self.wrapped.into_inner(); + let node = self.wrapped; match node.kind { ExprKind::MacCall(mac) => (mac, node.attrs, AddSemicolon::No), _ => unreachable!(), @@ -1797,7 +1792,7 @@ impl InvocationCollectorNode for AstNodeWrapper<P<ast::Expr>, MethodReceiverTag> matches!(self.wrapped.kind, ast::ExprKind::MacCall(..)) } fn take_mac_call(self) -> (P<ast::MacCall>, ast::AttrVec, AddSemicolon) { - let node = self.wrapped.into_inner(); + let node = self.wrapped; match node.kind { ExprKind::MacCall(mac) => (mac, node.attrs, AddSemicolon::No), _ => unreachable!(), diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index bcf0353498e..8c52f5dbbbe 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -97,7 +97,7 @@ fn allowed_union_or_unsafe_field<'tcx>( let def_id = tcx .lang_items() .get(LangItem::BikeshedGuaranteedNoDrop) - .unwrap_or_else(|| tcx.require_lang_item(LangItem::Copy, Some(span))); + .unwrap_or_else(|| tcx.require_lang_item(LangItem::Copy, span)); let Ok(ty) = tcx.try_normalize_erasing_regions(typing_env, ty) else { tcx.dcx().span_delayed_bug(span, "could not normalize field type"); return true; @@ -1142,7 +1142,7 @@ fn check_simd(tcx: TyCtxt<'_>, sp: Span, def_id: LocalDefId) { return; }; - if let Some(second_field) = fields.get(FieldIdx::from_u32(1)) { + if let Some(second_field) = fields.get(FieldIdx::ONE) { struct_span_code_err!(tcx.dcx(), sp, E0075, "SIMD vector cannot have multiple fields") .with_span_label(tcx.def_span(second_field.did), "excess field") .emit(); diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index 09610a2f3ec..234520c1583 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -180,7 +180,7 @@ pub(crate) fn check_intrinsic_type( ty::BoundVariableKind::Region(ty::BoundRegionKind::ClosureEnv), ]); let mk_va_list_ty = |mutbl| { - let did = tcx.require_lang_item(LangItem::VaList, Some(span)); + let did = tcx.require_lang_item(LangItem::VaList, span); let region = ty::Region::new_bound( tcx, ty::INNERMOST, @@ -442,9 +442,7 @@ pub(crate) fn check_intrinsic_type( sym::bswap | sym::bitreverse => (1, 0, vec![param(0)], param(0)), - sym::three_way_compare => { - (1, 0, vec![param(0), param(0)], tcx.ty_ordering_enum(Some(span))) - } + sym::three_way_compare => (1, 0, vec![param(0), param(0)], tcx.ty_ordering_enum(span)), sym::add_with_overflow | sym::sub_with_overflow | sym::mul_with_overflow => { (1, 0, vec![param(0), param(0)], Ty::new_tup(tcx, &[param(0), tcx.types.bool])) @@ -520,7 +518,7 @@ pub(crate) fn check_intrinsic_type( sym::discriminant_value => { let assoc_items = tcx.associated_item_def_ids( - tcx.require_lang_item(hir::LangItem::DiscriminantKind, None), + tcx.require_lang_item(hir::LangItem::DiscriminantKind, span), ); let discriminant_def_id = assoc_items[0]; diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 00316682df8..b8dc01cbc03 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -969,7 +969,7 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) -> Result<(), ), wfcx.param_env, ty, - tcx.require_lang_item(LangItem::UnsizedConstParamTy, Some(hir_ty.span)), + tcx.require_lang_item(LangItem::UnsizedConstParamTy, hir_ty.span), ); Ok(()) }) @@ -983,7 +983,7 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) -> Result<(), ), wfcx.param_env, ty, - tcx.require_lang_item(LangItem::ConstParamTy, Some(hir_ty.span)), + tcx.require_lang_item(LangItem::ConstParamTy, hir_ty.span), ); Ok(()) }) @@ -1232,7 +1232,7 @@ fn check_type_defn<'tcx>( ), wfcx.param_env, ty, - tcx.require_lang_item(LangItem::Sized, Some(hir_ty.span)), + tcx.require_lang_item(LangItem::Sized, hir_ty.span), ); } @@ -1356,7 +1356,7 @@ fn check_static_item( ), wfcx.param_env, item_ty, - tcx.require_lang_item(LangItem::Sized, Some(ty_span)), + tcx.require_lang_item(LangItem::Sized, ty_span), ); } @@ -1375,7 +1375,7 @@ fn check_static_item( ), wfcx.param_env, item_ty, - tcx.require_lang_item(LangItem::Sync, Some(ty_span)), + tcx.require_lang_item(LangItem::Sync, ty_span), ); } Ok(()) @@ -1401,7 +1401,7 @@ fn check_const_item( ), wfcx.param_env, ty, - tcx.require_lang_item(LangItem::Sized, None), + tcx.require_lang_item(LangItem::Sized, ty_span), ); check_where_clauses(wfcx, item_span, def_id); @@ -1725,13 +1725,13 @@ fn check_fn_or_method<'tcx>( ObligationCause::new(span, wfcx.body_def_id, ObligationCauseCode::RustCall), wfcx.param_env, *ty, - tcx.require_lang_item(hir::LangItem::Tuple, Some(span)), + tcx.require_lang_item(hir::LangItem::Tuple, span), ); wfcx.register_bound( ObligationCause::new(span, wfcx.body_def_id, ObligationCauseCode::RustCall), wfcx.param_env, *ty, - tcx.require_lang_item(hir::LangItem::Sized, Some(span)), + tcx.require_lang_item(hir::LangItem::Sized, span), ); } else { tcx.dcx().span_err( @@ -1776,7 +1776,7 @@ fn check_sized_if_body<'tcx>( ObligationCause::new(span, def_id, code), wfcx.param_env, ty, - tcx.require_lang_item(LangItem::Sized, Some(span)), + tcx.require_lang_item(LangItem::Sized, span), ); } } @@ -2013,7 +2013,7 @@ fn receiver_is_valid<'tcx>( // deref chain implement `LegacyReceiver`. if arbitrary_self_types_enabled.is_none() { let legacy_receiver_trait_def_id = - tcx.require_lang_item(LangItem::LegacyReceiver, Some(span)); + tcx.require_lang_item(LangItem::LegacyReceiver, span); if !legacy_receiver_is_implemented( wfcx, legacy_receiver_trait_def_id, diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs index b92d1d7104f..4779f4fb702 100644 --- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs +++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs @@ -225,7 +225,7 @@ fn visit_implementation_of_dispatch_from_dyn(checker: &Checker<'_>) -> Result<() // redundant errors for `DispatchFromDyn`. This is best effort, though. let mut res = Ok(()); tcx.for_each_relevant_impl( - tcx.require_lang_item(LangItem::CoerceUnsized, Some(span)), + tcx.require_lang_item(LangItem::CoerceUnsized, span), source, |impl_def_id| { res = res.and(tcx.ensure_ok().coerce_unsized_info(impl_def_id)); @@ -379,8 +379,8 @@ pub(crate) fn coerce_unsized_info<'tcx>( let span = tcx.def_span(impl_did); let trait_name = "CoerceUnsized"; - let coerce_unsized_trait = tcx.require_lang_item(LangItem::CoerceUnsized, Some(span)); - let unsize_trait = tcx.require_lang_item(LangItem::Unsize, Some(span)); + let coerce_unsized_trait = tcx.require_lang_item(LangItem::CoerceUnsized, span); + let unsize_trait = tcx.require_lang_item(LangItem::Unsize, span); let source = tcx.type_of(impl_did).instantiate_identity(); let trait_ref = tcx.impl_trait_ref(impl_did).unwrap().instantiate_identity(); @@ -591,7 +591,7 @@ fn infringing_fields_error<'tcx>( impl_did: LocalDefId, impl_span: Span, ) -> ErrorGuaranteed { - let trait_did = tcx.require_lang_item(lang_item, Some(impl_span)); + let trait_did = tcx.require_lang_item(lang_item, impl_span); let trait_name = tcx.def_path_str(trait_did); @@ -748,7 +748,7 @@ fn visit_implementation_of_pointer_like(checker: &Checker<'_>) -> Result<(), Err ObligationCause::misc(impl_span, checker.impl_def_id), param_env, nontrivial_field_ty, - tcx.require_lang_item(LangItem::PointerLike, Some(impl_span)), + tcx.require_lang_item(LangItem::PointerLike, impl_span), ); // FIXME(dyn-star): We should regionck this implementation. if ocx.select_all_or_error().is_empty() { diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs index 21f0f9648ea..3a26b8331f8 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs @@ -73,7 +73,7 @@ fn generic_arg_mismatch_err( let param_name = tcx.hir_ty_param_name(param_local_id); let param_type = tcx.type_of(param.def_id).instantiate_identity(); if param_type.is_suggestable(tcx, false) { - err.span_suggestion( + err.span_suggestion_verbose( tcx.def_span(src_def_id), "consider changing this type parameter to a const parameter", format!("const {param_name}: {param_type}"), 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 2a37a8bdbd4..4c65d0d0510 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -2590,7 +2590,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { .unwrap_or_else(|guar| Ty::new_error(tcx, guar)) } &hir::TyKind::Path(hir::QPath::LangItem(lang_item, span)) => { - let def_id = tcx.require_lang_item(lang_item, Some(span)); + let def_id = tcx.require_lang_item(lang_item, span); let (args, _) = self.lower_generic_args_of_path( span, def_id, diff --git a/compiler/rustc_hir_typeck/messages.ftl b/compiler/rustc_hir_typeck/messages.ftl index 5e79d10612d..6c33dfb4ec0 100644 --- a/compiler/rustc_hir_typeck/messages.ftl +++ b/compiler/rustc_hir_typeck/messages.ftl @@ -137,6 +137,18 @@ hir_typeck_lossy_provenance_ptr2int = hir_typeck_missing_parentheses_in_range = can't call method `{$method_name}` on type `{$ty_str}` +hir_typeck_naked_asm_outside_naked_fn = + the `naked_asm!` macro can only be used in functions marked with `#[unsafe(naked)]` + +hir_typeck_naked_functions_asm_block = + naked functions must contain a single `naked_asm!` invocation + .label_multiple_asm = multiple `naked_asm!` invocations are not allowed in naked functions + .label_non_asm = not allowed in naked functions + +hir_typeck_naked_functions_must_naked_asm = + the `asm!` macro is not allowed in naked functions + .label = consider using the `naked_asm!` macro instead + hir_typeck_never_type_fallback_flowing_into_unsafe_call = never type fallback affects this call to an `unsafe` function .help = specify the type explicitly hir_typeck_never_type_fallback_flowing_into_unsafe_deref = never type fallback affects this raw pointer dereference @@ -159,6 +171,9 @@ hir_typeck_no_field_on_variant = no field named `{$field}` on enum variant `{$co hir_typeck_no_field_on_variant_enum = this enum variant... hir_typeck_no_field_on_variant_field = ...does not have this field +hir_typeck_no_patterns = + patterns not allowed in naked function parameters + hir_typeck_note_caller_chooses_ty_for_ty_param = the caller chooses a type for `{$ty_param_name}` which can be different from `{$found_ty}` hir_typeck_note_edition_guide = for more on editions, read https://doc.rust-lang.org/edition-guide @@ -167,6 +182,10 @@ hir_typeck_option_result_asref = use `{$def_path}::as_ref` to convert `{$expecte hir_typeck_option_result_cloned = use `{$def_path}::cloned` to clone the value inside the `{$def_path}` hir_typeck_option_result_copied = use `{$def_path}::copied` to copy the value inside the `{$def_path}` +hir_typeck_params_not_allowed = + referencing function parameters is not allowed in naked functions + .help = follow the calling convention in asm block to use parameters + hir_typeck_pass_to_variadic_function = can't pass `{$ty}` to variadic function .suggestion = cast the value to `{$cast_ty}` .teach_help = certain types, like `{$ty}`, must be cast before passing them to a variadic function to match the implicit cast that a C compiler would perform as part of C's numeric promotion rules diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs index f555d116c52..d173fe7c2c2 100644 --- a/compiler/rustc_hir_typeck/src/callee.rs +++ b/compiler/rustc_hir_typeck/src/callee.rs @@ -508,7 +508,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if let Some(ty) = fn_sig.inputs().last().copied() { self.register_bound( ty, - self.tcx.require_lang_item(hir::LangItem::Tuple, Some(sp)), + self.tcx.require_lang_item(hir::LangItem::Tuple, sp), self.cause(sp, ObligationCauseCode::RustCall), ); self.require_type_is_sized(ty, sp, ObligationCauseCode::RustCall); diff --git a/compiler/rustc_hir_typeck/src/check.rs b/compiler/rustc_hir_typeck/src/check.rs index 99103f14d68..ac42eebf08c 100644 --- a/compiler/rustc_hir_typeck/src/check.rs +++ b/compiler/rustc_hir_typeck/src/check.rs @@ -57,7 +57,7 @@ pub(super) fn check_fn<'a, 'tcx>( // (as it's created inside the body itself, not passed in from outside). let maybe_va_list = fn_sig.c_variadic.then(|| { let span = body.params.last().unwrap().span; - let va_list_did = tcx.require_lang_item(LangItem::VaList, Some(span)); + let va_list_did = tcx.require_lang_item(LangItem::VaList, span); let region = fcx.next_region_var(RegionVariableOrigin::MiscVariable(span)); tcx.type_of(va_list_did).instantiate(tcx, &[region.into()]) @@ -178,7 +178,7 @@ fn check_panic_info_fn(tcx: TyCtxt<'_>, fn_id: LocalDefId, fn_sig: ty::FnSig<'_> tcx.dcx().span_err(span, "should have no const parameters"); } - let panic_info_did = tcx.require_lang_item(hir::LangItem::PanicInfo, Some(span)); + let panic_info_did = tcx.require_lang_item(hir::LangItem::PanicInfo, span); // build type `for<'a, 'b> fn(&'a PanicInfo<'b>) -> !` let panic_info_ty = tcx.type_of(panic_info_did).instantiate( diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs index cd3746be1d1..459c0498d50 100644 --- a/compiler/rustc_hir_typeck/src/closure.rs +++ b/compiler/rustc_hir_typeck/src/closure.rs @@ -142,13 +142,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Ty::new_adt( tcx, - tcx.adt_def( - tcx.require_lang_item(hir::LangItem::Poll, Some(expr_span)), - ), + tcx.adt_def(tcx.require_lang_item(hir::LangItem::Poll, expr_span)), tcx.mk_args(&[Ty::new_adt( tcx, tcx.adt_def( - tcx.require_lang_item(hir::LangItem::Option, Some(expr_span)), + tcx.require_lang_item(hir::LangItem::Option, expr_span), ), tcx.mk_args(&[yield_ty.into()]), ) diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index ddc80fab2ce..d9fa56fefeb 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -760,8 +760,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { self.param_env, ty::TraitRef::new( self.tcx, - self.tcx - .require_lang_item(hir::LangItem::PointerLike, Some(self.cause.span)), + self.tcx.require_lang_item(hir::LangItem::PointerLike, self.cause.span), [a], ), ), @@ -1969,7 +1968,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { fcx.param_env, ty::TraitRef::new( fcx.tcx, - fcx.tcx.require_lang_item(hir::LangItem::Sized, None), + fcx.tcx.require_lang_item(hir::LangItem::Sized, DUMMY_SP), [sig.output()], ), )) diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs index 06103fe1c91..97a90548fc5 100644 --- a/compiler/rustc_hir_typeck/src/errors.rs +++ b/compiler/rustc_hir_typeck/src/errors.rs @@ -4,8 +4,8 @@ use std::borrow::Cow; use rustc_errors::codes::*; use rustc_errors::{ - Applicability, Diag, DiagArgValue, DiagSymbolList, EmissionGuarantee, IntoDiagArg, MultiSpan, - Subdiagnostic, + Applicability, Diag, DiagArgValue, DiagCtxtHandle, DiagSymbolList, Diagnostic, + EmissionGuarantee, IntoDiagArg, Level, MultiSpan, Subdiagnostic, }; use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; use rustc_middle::ty::{self, Ty}; @@ -983,3 +983,55 @@ pub(crate) struct RegisterTypeUnstable<'a> { pub span: Span, pub ty: Ty<'a>, } + +#[derive(Diagnostic)] +#[diag(hir_typeck_naked_asm_outside_naked_fn)] +pub(crate) struct NakedAsmOutsideNakedFn { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(hir_typeck_no_patterns)] +pub(crate) struct NoPatterns { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(hir_typeck_params_not_allowed)] +#[help] +pub(crate) struct ParamsNotAllowed { + #[primary_span] + pub span: Span, +} + +pub(crate) struct NakedFunctionsAsmBlock { + pub span: Span, + pub multiple_asms: Vec<Span>, + pub non_asms: Vec<Span>, +} + +impl<G: EmissionGuarantee> Diagnostic<'_, G> for NakedFunctionsAsmBlock { + #[track_caller] + fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> { + let mut diag = Diag::new(dcx, level, fluent::hir_typeck_naked_functions_asm_block); + diag.span(self.span); + diag.code(E0787); + for span in self.multiple_asms.iter() { + diag.span_label(*span, fluent::hir_typeck_label_multiple_asm); + } + for span in self.non_asms.iter() { + diag.span_label(*span, fluent::hir_typeck_label_non_asm); + } + diag + } +} + +#[derive(Diagnostic)] +#[diag(hir_typeck_naked_functions_must_naked_asm, code = E0787)] +pub(crate) struct NakedFunctionsMustNakedAsm { + #[primary_span] + #[label] + pub span: Span, +} diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 082ddac7e5a..dfc7935d02b 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -44,9 +44,9 @@ use crate::errors::{ AddressOfTemporaryTaken, BaseExpressionDoubleDot, BaseExpressionDoubleDotAddExpr, BaseExpressionDoubleDotEnableDefaultFieldValues, BaseExpressionDoubleDotRemove, CantDereference, FieldMultiplySpecifiedInInitializer, FunctionalRecordUpdateOnNonStruct, - HelpUseLatestEdition, NoFieldOnType, NoFieldOnVariant, ReturnLikeStatementKind, - ReturnStmtOutsideOfFnBody, StructExprNonExhaustive, TypeMismatchFruTypo, - YieldExprOutsideOfCoroutine, + HelpUseLatestEdition, NakedAsmOutsideNakedFn, NoFieldOnType, NoFieldOnVariant, + ReturnLikeStatementKind, ReturnStmtOutsideOfFnBody, StructExprNonExhaustive, + TypeMismatchFruTypo, YieldExprOutsideOfCoroutine, }; use crate::{ BreakableCtxt, CoroutineTypes, Diverges, FnCtxt, GatherLocalsVisitor, Needs, @@ -524,7 +524,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ExprKind::InlineAsm(asm) => { // We defer some asm checks as we may not have resolved the input and output types yet (they may still be infer vars). self.deferred_asm_checks.borrow_mut().push((asm, expr.hir_id)); - self.check_expr_asm(asm) + self.check_expr_asm(asm, expr.span) } ExprKind::OffsetOf(container, fields) => { self.check_expr_offset_of(container, fields, expr) @@ -1407,7 +1407,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let lhs_deref_ty_is_sized = self .infcx .type_implements_trait( - self.tcx.require_lang_item(LangItem::Sized, None), + self.tcx.require_lang_item(LangItem::Sized, span), [lhs_deref_ty], self.param_env, ) @@ -3761,7 +3761,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - fn check_expr_asm(&self, asm: &'tcx hir::InlineAsm<'tcx>) -> Ty<'tcx> { + fn check_expr_asm(&self, asm: &'tcx hir::InlineAsm<'tcx>, span: Span) -> Ty<'tcx> { + if let rustc_ast::AsmMacro::NakedAsm = asm.asm_macro { + if !self.tcx.has_attr(self.body_id, sym::naked) { + self.tcx.dcx().emit_err(NakedAsmOutsideNakedFn { span }); + } + } + let mut diverge = asm.asm_macro.diverges(asm.options); for (op, _op_sp) in asm.operands { diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index 362c7d8efac..8a90e768d70 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -409,7 +409,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { code: traits::ObligationCauseCode<'tcx>, ) { if !ty.references_error() { - let lang_item = self.tcx.require_lang_item(LangItem::Sized, None); + let lang_item = self.tcx.require_lang_item(LangItem::Sized, span); self.require_type_meets(ty, span, code, lang_item); } } @@ -443,7 +443,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Nothing else is required here. } else { // We can't be sure, let's required full `Sized`. - let lang_item = self.tcx.require_lang_item(LangItem::Sized, None); + let lang_item = self.tcx.require_lang_item(LangItem::Sized, span); self.require_type_meets(ty, span, ObligationCauseCode::Misc, lang_item); } } @@ -732,7 +732,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { span: Span, hir_id: HirId, ) -> (Res, Ty<'tcx>) { - let def_id = self.tcx.require_lang_item(lang_item, Some(span)); + let def_id = self.tcx.require_lang_item(lang_item, span); let def_kind = self.tcx.def_kind(def_id); let item_ty = if let DefKind::Variant = def_kind { diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 59aba6fae5e..95c7f251c88 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -165,7 +165,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { _ => traits::IsConstable::No, }; - let lang_item = self.tcx.require_lang_item(LangItem::Copy, None); + let lang_item = self.tcx.require_lang_item(LangItem::Copy, element.span); let code = traits::ObligationCauseCode::RepeatElementCopy { is_constable, elt_span: element.span, @@ -1680,8 +1680,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ast::LitKind::CStr(_, _) => Ty::new_imm_ref( tcx, tcx.lifetimes.re_static, - tcx.type_of(tcx.require_lang_item(hir::LangItem::CStr, Some(lit.span))) - .skip_binder(), + tcx.type_of(tcx.require_lang_item(hir::LangItem::CStr, lit.span)).skip_binder(), ), ast::LitKind::Err(guar) => Ty::new_error(tcx, guar), } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index 1c3bc338d85..66af085cfd4 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -2679,7 +2679,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut sugg_sp = sp; if let hir::ExprKind::MethodCall(segment, receiver, args, _) = expr.kind { let clone_trait = - self.tcx.require_lang_item(LangItem::Clone, Some(segment.ident.span)); + self.tcx.require_lang_item(LangItem::Clone, segment.ident.span); if args.is_empty() && self .typeck_results diff --git a/compiler/rustc_hir_typeck/src/inline_asm.rs b/compiler/rustc_hir_typeck/src/inline_asm.rs index 6399f0a78ae..b59c1752c25 100644 --- a/compiler/rustc_hir_typeck/src/inline_asm.rs +++ b/compiler/rustc_hir_typeck/src/inline_asm.rs @@ -171,7 +171,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { _ if ty.references_error() => return None, ty::Adt(adt, args) if self.tcx().is_lang_item(adt.did(), LangItem::MaybeUninit) => { let fields = &adt.non_enum_variant().fields; - let ty = fields[FieldIdx::from_u32(1)].ty(self.tcx(), args); + let ty = fields[FieldIdx::ONE].ty(self.tcx(), args); // FIXME: Are we just trying to map to the `T` in `MaybeUninit<T>`? // If so, just get it from the args. let ty::Adt(ty, args) = ty.kind() else { diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs index 5a814822163..b0346f8d32e 100644 --- a/compiler/rustc_hir_typeck/src/lib.rs +++ b/compiler/rustc_hir_typeck/src/lib.rs @@ -31,6 +31,7 @@ mod fn_ctxt; mod gather_locals; mod intrinsicck; mod method; +mod naked_functions; mod op; mod opaque_types; mod pat; @@ -55,8 +56,8 @@ use rustc_middle::query::Providers; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::{bug, span_bug}; use rustc_session::config; -use rustc_span::Span; use rustc_span::def_id::LocalDefId; +use rustc_span::{Span, sym}; use tracing::{debug, instrument}; use typeck_root_ctxt::TypeckRootCtxt; @@ -170,6 +171,10 @@ fn typeck_with_inspect<'tcx>( .map(|(idx, ty)| fcx.normalize(arg_span(idx), ty)), ); + if tcx.has_attr(def_id, sym::naked) { + naked_functions::typeck_naked_fn(tcx, def_id, body); + } + check_fn(&mut fcx, fn_sig, None, decl, def_id, body, tcx.features().unsized_fn_params()); } else { let expected_type = if let Some(infer_ty) = infer_type_if_missing(&fcx, node) { diff --git a/compiler/rustc_passes/src/naked_functions.rs b/compiler/rustc_hir_typeck/src/naked_functions.rs index 3c9f8b72c36..2518d6478e6 100644 --- a/compiler/rustc_passes/src/naked_functions.rs +++ b/compiler/rustc_hir_typeck/src/naked_functions.rs @@ -1,56 +1,29 @@ //! Checks validity of naked functions. use rustc_hir as hir; -use rustc_hir::def::DefKind; -use rustc_hir::def_id::{LocalDefId, LocalModDefId}; +use rustc_hir::def_id::LocalDefId; use rustc_hir::intravisit::Visitor; use rustc_hir::{ExprKind, HirIdSet, StmtKind}; -use rustc_middle::hir::nested_filter::OnlyBodies; -use rustc_middle::query::Providers; use rustc_middle::span_bug; use rustc_middle::ty::TyCtxt; use rustc_span::{Span, sym}; use crate::errors::{ - NakedAsmOutsideNakedFn, NakedFunctionsAsmBlock, NakedFunctionsMustNakedAsm, NoPatterns, - ParamsNotAllowed, + NakedFunctionsAsmBlock, NakedFunctionsMustNakedAsm, NoPatterns, ParamsNotAllowed, }; -pub(crate) fn provide(providers: &mut Providers) { - *providers = Providers { check_mod_naked_functions, ..*providers }; -} - -fn check_mod_naked_functions(tcx: TyCtxt<'_>, module_def_id: LocalModDefId) { - let items = tcx.hir_module_items(module_def_id); - for def_id in items.definitions() { - if !matches!(tcx.def_kind(def_id), DefKind::Fn | DefKind::AssocFn) { - continue; - } - - let body = match tcx.hir_node_by_def_id(def_id) { - hir::Node::Item(hir::Item { - kind: hir::ItemKind::Fn { body: body_id, .. }, .. - }) - | hir::Node::TraitItem(hir::TraitItem { - kind: hir::TraitItemKind::Fn(_, hir::TraitFn::Provided(body_id)), - .. - }) - | hir::Node::ImplItem(hir::ImplItem { - kind: hir::ImplItemKind::Fn(_, body_id), .. - }) => tcx.hir_body(*body_id), - _ => continue, - }; - - if tcx.has_attr(def_id, sym::naked) { - check_no_patterns(tcx, body.params); - check_no_parameters_use(tcx, body); - check_asm(tcx, def_id, body); - } else { - // `naked_asm!` is not allowed outside of functions marked as `#[naked]` - let mut visitor = CheckNakedAsmInNakedFn { tcx }; - visitor.visit_body(body); - } - } +/// Naked fns can only have trivial binding patterns in arguments, +/// may not actually use those arguments, and the body must consist of just +/// a single asm statement. +pub(crate) fn typeck_naked_fn<'tcx>( + tcx: TyCtxt<'tcx>, + def_id: LocalDefId, + body: &'tcx hir::Body<'tcx>, +) { + debug_assert!(tcx.has_attr(def_id, sym::naked)); + check_no_patterns(tcx, body.params); + check_no_parameters_use(tcx, body); + check_asm(tcx, def_id, body); } /// Checks that parameters don't use patterns. Mirrors the checks for function declarations. @@ -231,25 +204,3 @@ impl<'tcx> Visitor<'tcx> for CheckInlineAssembly { self.check_expr(expr, expr.span); } } - -struct CheckNakedAsmInNakedFn<'tcx> { - tcx: TyCtxt<'tcx>, -} - -impl<'tcx> Visitor<'tcx> for CheckNakedAsmInNakedFn<'tcx> { - type NestedFilter = OnlyBodies; - - fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt { - self.tcx - } - - fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) { - if let ExprKind::InlineAsm(inline_asm) = expr.kind { - if let rustc_ast::AsmMacro::NakedAsm = inline_asm.asm_macro { - self.tcx.dcx().emit_err(NakedAsmOutsideNakedFn { span: expr.span }); - } - } - - hir::intravisit::walk_expr(self, expr); - } -} diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index 17d48184dd9..432eeae8016 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -796,7 +796,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if *negated { self.register_bound( ty, - self.tcx.require_lang_item(LangItem::Neg, Some(lt.span)), + self.tcx.require_lang_item(LangItem::Neg, lt.span), ObligationCause::dummy_with_span(lt.span), ); } @@ -2553,13 +2553,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let tcx = self.tcx; self.register_bound( source_ty, - tcx.require_lang_item(hir::LangItem::DerefPure, Some(span)), + tcx.require_lang_item(hir::LangItem::DerefPure, span), self.misc(span), ); // The expected type for the deref pat's inner pattern is `<expected as Deref>::Target`. let target_ty = Ty::new_projection( tcx, - tcx.require_lang_item(hir::LangItem::DerefTarget, Some(span)), + tcx.require_lang_item(hir::LangItem::DerefTarget, span), [source_ty], ); let target_ty = self.normalize(span, target_ty); @@ -2580,7 +2580,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { for mutably_derefed_ty in derefed_tys { self.register_bound( mutably_derefed_ty, - self.tcx.require_lang_item(hir::LangItem::DerefMut, Some(span)), + self.tcx.require_lang_item(hir::LangItem::DerefMut, span), self.misc(span), ); } diff --git a/compiler/rustc_hir_typeck/src/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs index 4b2e87f5674..5b5253c7e7e 100644 --- a/compiler/rustc_hir_typeck/src/upvar.rs +++ b/compiler/rustc_hir_typeck/src/upvar.rs @@ -1560,7 +1560,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; let is_drop_defined_for_ty = |ty: Ty<'tcx>| { - let drop_trait = self.tcx.require_lang_item(hir::LangItem::Drop, Some(closure_span)); + let drop_trait = self.tcx.require_lang_item(hir::LangItem::Drop, closure_span); self.infcx .type_implements_trait(drop_trait, [ty], self.tcx.param_env(closure_def_id)) .must_apply_modulo_regions() diff --git a/compiler/rustc_infer/src/infer/opaque_types/table.rs b/compiler/rustc_infer/src/infer/opaque_types/table.rs index ab65da3913d..df5a66243fc 100644 --- a/compiler/rustc_infer/src/infer/opaque_types/table.rs +++ b/compiler/rustc_infer/src/infer/opaque_types/table.rs @@ -53,7 +53,7 @@ impl<'tcx> OpaqueTypeStorage<'tcx> { assert!(entry.is_some()); } - pub(crate) fn is_empty(&self) -> bool { + pub fn is_empty(&self) -> bool { let OpaqueTypeStorage { opaque_types, duplicate_entries } = self; opaque_types.is_empty() && duplicate_entries.is_empty() } diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index f4045eeea4d..ee41df6b1f6 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -956,7 +956,6 @@ fn run_required_analyses(tcx: TyCtxt<'_>) { tcx.par_hir_for_each_module(|module| { tcx.ensure_ok().check_mod_loops(module); tcx.ensure_ok().check_mod_attrs(module); - tcx.ensure_ok().check_mod_naked_functions(module); tcx.ensure_ok().check_mod_unstable_api_usage(module); }); }, diff --git a/compiler/rustc_lexer/src/cursor.rs b/compiler/rustc_lexer/src/cursor.rs index 526693d3de1..165262b82c7 100644 --- a/compiler/rustc_lexer/src/cursor.rs +++ b/compiler/rustc_lexer/src/cursor.rs @@ -68,7 +68,7 @@ impl<'a> Cursor<'a> { /// Peeks the third symbol from the input stream without consuming it. pub fn third(&self) -> char { - // `.next()` optimizes better than `.nth(1)` + // `.next()` optimizes better than `.nth(2)` let mut iter = self.chars.clone(); iter.next(); iter.next(); diff --git a/compiler/rustc_lexer/src/lib.rs b/compiler/rustc_lexer/src/lib.rs index ece3f9107b0..b2bd5e188ef 100644 --- a/compiler/rustc_lexer/src/lib.rs +++ b/compiler/rustc_lexer/src/lib.rs @@ -30,14 +30,13 @@ mod cursor; #[cfg(test)] mod tests; +use LiteralKind::*; +use TokenKind::*; +use cursor::EOF_CHAR; +pub use cursor::{Cursor, FrontmatterAllowed}; use unicode_properties::UnicodeEmoji; pub use unicode_xid::UNICODE_VERSION as UNICODE_XID_VERSION; -use self::LiteralKind::*; -use self::TokenKind::*; -use crate::cursor::EOF_CHAR; -pub use crate::cursor::{Cursor, FrontmatterAllowed}; - /// Parsed token. /// It doesn't contain information about data that has been parsed, /// only the type of the token and its size. @@ -372,9 +371,8 @@ pub fn is_ident(string: &str) -> bool { impl Cursor<'_> { /// Parses a token from the input string. pub fn advance_token(&mut self) -> Token { - let first_char = match self.bump() { - Some(c) => c, - None => return Token::new(TokenKind::Eof, 0), + let Some(first_char) = self.bump() else { + return Token::new(TokenKind::Eof, 0); }; let token_kind = match first_char { @@ -788,7 +786,7 @@ impl Cursor<'_> { } else { // No base prefix, parse number in the usual way. self.eat_decimal_digits(); - }; + } match self.first() { // Don't be greedy if this is actually an diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 47b80135bae..69e9f8e1b2c 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -39,7 +39,7 @@ pub use rustc_session::lint::builtin::*; use rustc_session::{declare_lint, declare_lint_pass, impl_lint_pass}; use rustc_span::edition::Edition; use rustc_span::source_map::Spanned; -use rustc_span::{BytePos, Ident, InnerSpan, Span, Symbol, kw, sym}; +use rustc_span::{BytePos, DUMMY_SP, Ident, InnerSpan, Span, Symbol, kw, sym}; use rustc_target::asm::InlineAsmArch; use rustc_trait_selection::infer::{InferCtxtExt, TyCtxtInferExt}; use rustc_trait_selection::traits::misc::type_allowed_to_implement_copy; @@ -635,7 +635,8 @@ fn type_implements_negative_copy_modulo_regions<'tcx>( typing_env: ty::TypingEnv<'tcx>, ) -> bool { let (infcx, param_env) = tcx.infer_ctxt().build_with_typing_env(typing_env); - let trait_ref = ty::TraitRef::new(tcx, tcx.require_lang_item(hir::LangItem::Copy, None), [ty]); + let trait_ref = + ty::TraitRef::new(tcx, tcx.require_lang_item(hir::LangItem::Copy, DUMMY_SP), [ty]); let pred = ty::TraitPredicate { trait_ref, polarity: ty::PredicatePolarity::Negative }; let obligation = traits::Obligation { cause: traits::ObligationCause::dummy(), diff --git a/compiler/rustc_middle/src/error.rs b/compiler/rustc_middle/src/error.rs index bd315577efb..6c6b12fed67 100644 --- a/compiler/rustc_middle/src/error.rs +++ b/compiler/rustc_middle/src/error.rs @@ -95,7 +95,7 @@ pub(crate) struct StrictCoherenceNeedsNegativeCoherence { #[diag(middle_requires_lang_item)] pub(crate) struct RequiresLangItem { #[primary_span] - pub span: Option<Span>, + pub span: Span, pub name: Symbol, } diff --git a/compiler/rustc_middle/src/middle/lang_items.rs b/compiler/rustc_middle/src/middle/lang_items.rs index 0f92c1910f1..93264f02cc2 100644 --- a/compiler/rustc_middle/src/middle/lang_items.rs +++ b/compiler/rustc_middle/src/middle/lang_items.rs @@ -17,7 +17,7 @@ use crate::ty::{self, TyCtxt}; impl<'tcx> TyCtxt<'tcx> { /// Returns the `DefId` for a given `LangItem`. /// If not found, fatally aborts compilation. - pub fn require_lang_item(self, lang_item: LangItem, span: Option<Span>) -> DefId { + pub fn require_lang_item(self, lang_item: LangItem, span: Span) -> DefId { self.lang_items().get(lang_item).unwrap_or_else(|| { self.dcx().emit_fatal(crate::error::RequiresLangItem { span, name: lang_item.name() }); }) diff --git a/compiler/rustc_middle/src/mir/statement.rs b/compiler/rustc_middle/src/mir/statement.rs index 06e41e64fdc..d98b40f0fcf 100644 --- a/compiler/rustc_middle/src/mir/statement.rs +++ b/compiler/rustc_middle/src/mir/statement.rs @@ -835,7 +835,7 @@ impl<'tcx> BinOp { &BinOp::Cmp => { // these should be integer-like types of the same size. assert_eq!(lhs_ty, rhs_ty); - tcx.ty_ordering_enum(None) + tcx.ty_ordering_enum(DUMMY_SP) } } } diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index d900e16b005..d03f01bf863 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1120,10 +1120,6 @@ rustc_queries! { desc { |tcx| "checking loops in {}", describe_as_module(key, tcx) } } - query check_mod_naked_functions(key: LocalModDefId) { - desc { |tcx| "checking naked functions in {}", describe_as_module(key, tcx) } - } - query check_mod_privacy(key: LocalModDefId) { desc { |tcx| "checking privacy in {}", describe_as_module(key.to_local_def_id(), tcx) } } diff --git a/compiler/rustc_middle/src/ty/adjustment.rs b/compiler/rustc_middle/src/ty/adjustment.rs index a61a6c571a2..3bacdfe5ac8 100644 --- a/compiler/rustc_middle/src/ty/adjustment.rs +++ b/compiler/rustc_middle/src/ty/adjustment.rs @@ -128,8 +128,8 @@ impl OverloadedDeref { /// for this overloaded deref's mutability. pub fn method_call<'tcx>(&self, tcx: TyCtxt<'tcx>) -> DefId { let trait_def_id = match self.mutbl { - hir::Mutability::Not => tcx.require_lang_item(LangItem::Deref, None), - hir::Mutability::Mut => tcx.require_lang_item(LangItem::DerefMut, None), + hir::Mutability::Not => tcx.require_lang_item(LangItem::Deref, self.span), + hir::Mutability::Mut => tcx.require_lang_item(LangItem::DerefMut, self.span), }; tcx.associated_items(trait_def_id) .in_definition_order() diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 57b20a1bba6..0b1e9852d2a 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -458,7 +458,7 @@ impl<'tcx> Interner for TyCtxt<'tcx> { } fn require_lang_item(self, lang_item: TraitSolverLangItem) -> DefId { - self.require_lang_item(trait_lang_item_to_lang_item(lang_item), None) + self.require_lang_item(trait_lang_item_to_lang_item(lang_item), DUMMY_SP) } fn is_lang_item(self, def_id: DefId, lang_item: TraitSolverLangItem) -> bool { @@ -1710,7 +1710,7 @@ impl<'tcx> TyCtxt<'tcx> { /// Gets a `Ty` representing the [`LangItem::OrderingEnum`] #[track_caller] - pub fn ty_ordering_enum(self, span: Option<Span>) -> Ty<'tcx> { + pub fn ty_ordering_enum(self, span: Span) -> Ty<'tcx> { let ordering_enum = self.require_lang_item(hir::LangItem::OrderingEnum, span); self.type_of(ordering_enum).no_bound_vars().unwrap() } @@ -2253,7 +2253,7 @@ impl<'tcx> TyCtxt<'tcx> { Ty::new_imm_ref( self, self.lifetimes.re_static, - self.type_of(self.require_lang_item(LangItem::PanicLocation, None)) + self.type_of(self.require_lang_item(LangItem::PanicLocation, DUMMY_SP)) .instantiate(self, self.mk_args(&[self.lifetimes.re_static.into()])), ) } @@ -2712,7 +2712,7 @@ impl<'tcx> TyCtxt<'tcx> { /// Given a `ty`, return whether it's an `impl Future<...>`. pub fn ty_is_opaque_future(self, ty: Ty<'_>) -> bool { let ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) = ty.kind() else { return false }; - let future_trait = self.require_lang_item(LangItem::Future, None); + let future_trait = self.require_lang_item(LangItem::Future, DUMMY_SP); self.explicit_item_self_bounds(def_id).skip_binder().iter().any(|&(predicate, _)| { let ty::ClauseKind::Trait(trait_predicate) = predicate.kind().skip_binder() else { diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index 0d99a1b5149..5ba4e5446e9 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -786,7 +786,7 @@ impl<'tcx> Instance<'tcx> { } pub fn resolve_drop_in_place(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> ty::Instance<'tcx> { - let def_id = tcx.require_lang_item(LangItem::DropInPlace, None); + let def_id = tcx.require_lang_item(LangItem::DropInPlace, DUMMY_SP); let args = tcx.mk_args(&[ty.into()]); Instance::expect_resolve( tcx, @@ -798,7 +798,7 @@ impl<'tcx> Instance<'tcx> { } pub fn resolve_async_drop_in_place(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> ty::Instance<'tcx> { - let def_id = tcx.require_lang_item(LangItem::AsyncDropInPlace, None); + let def_id = tcx.require_lang_item(LangItem::AsyncDropInPlace, DUMMY_SP); let args = tcx.mk_args(&[ty.into()]); Instance::expect_resolve( tcx, @@ -824,7 +824,7 @@ impl<'tcx> Instance<'tcx> { closure_did: DefId, args: ty::GenericArgsRef<'tcx>, ) -> Instance<'tcx> { - let fn_once = tcx.require_lang_item(LangItem::FnOnce, None); + let fn_once = tcx.require_lang_item(LangItem::FnOnce, DUMMY_SP); let call_once = tcx .associated_items(fn_once) .in_definition_order() diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 404674c359e..cbf545c01c5 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -593,7 +593,7 @@ impl<'tcx> Ty<'tcx> { ty: Ty<'tcx>, mutbl: ty::Mutability, ) -> Ty<'tcx> { - let pin = tcx.adt_def(tcx.require_lang_item(LangItem::Pin, None)); + let pin = tcx.adt_def(tcx.require_lang_item(LangItem::Pin, DUMMY_SP)); Ty::new_adt(tcx, pin, tcx.mk_args(&[Ty::new_ref(tcx, r, ty, mutbl).into()])) } @@ -857,19 +857,19 @@ impl<'tcx> Ty<'tcx> { #[inline] pub fn new_box(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> { - let def_id = tcx.require_lang_item(LangItem::OwnedBox, None); + let def_id = tcx.require_lang_item(LangItem::OwnedBox, DUMMY_SP); Ty::new_generic_adt(tcx, def_id, ty) } #[inline] pub fn new_maybe_uninit(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> { - let def_id = tcx.require_lang_item(LangItem::MaybeUninit, None); + let def_id = tcx.require_lang_item(LangItem::MaybeUninit, DUMMY_SP); Ty::new_generic_adt(tcx, def_id, ty) } /// Creates a `&mut Context<'_>` [`Ty`] with erased lifetimes. pub fn new_task_context(tcx: TyCtxt<'tcx>) -> Ty<'tcx> { - let context_did = tcx.require_lang_item(LangItem::Context, None); + let context_did = tcx.require_lang_item(LangItem::Context, DUMMY_SP); let context_adt_ref = tcx.adt_def(context_did); let context_args = tcx.mk_args(&[tcx.lifetimes.re_erased.into()]); let context_ty = Ty::new_adt(tcx, context_adt_ref, context_args); @@ -1549,7 +1549,7 @@ impl<'tcx> Ty<'tcx> { ty::Param(_) | ty::Alias(..) | ty::Infer(ty::TyVar(_)) => { let assoc_items = tcx.associated_item_def_ids( - tcx.require_lang_item(hir::LangItem::DiscriminantKind, None), + tcx.require_lang_item(hir::LangItem::DiscriminantKind, DUMMY_SP), ); Ty::new_projection_from_args(tcx, assoc_items[0], tcx.mk_args(&[self.into()])) } @@ -1629,7 +1629,7 @@ impl<'tcx> Ty<'tcx> { ty::Str | ty::Slice(_) => Ok(tcx.types.usize), ty::Dynamic(_, _, ty::Dyn) => { - let dyn_metadata = tcx.require_lang_item(LangItem::DynMetadata, None); + let dyn_metadata = tcx.require_lang_item(LangItem::DynMetadata, DUMMY_SP); Ok(tcx.type_of(dyn_metadata).instantiate(tcx, &[tail.into()])) } @@ -1683,7 +1683,7 @@ impl<'tcx> Ty<'tcx> { match pointee_ty.ptr_metadata_ty_or_tail(tcx, |x| x) { Ok(metadata_ty) => metadata_ty, Err(tail_ty) => { - let metadata_def_id = tcx.require_lang_item(LangItem::Metadata, None); + let metadata_def_id = tcx.require_lang_item(LangItem::Metadata, DUMMY_SP); Ty::new_projection(tcx, metadata_def_id, [tail_ty]) } } diff --git a/compiler/rustc_middle/src/ty/typeck_results.rs b/compiler/rustc_middle/src/ty/typeck_results.rs index cc3887079d8..88583407d25 100644 --- a/compiler/rustc_middle/src/ty/typeck_results.rs +++ b/compiler/rustc_middle/src/ty/typeck_results.rs @@ -199,7 +199,7 @@ pub struct TypeckResults<'tcx> { /// Tracks the rvalue scoping rules which defines finer scoping for rvalue expressions /// by applying extended parameter rules. - /// Details may be find in `rustc_hir_analysis::check::rvalue_scopes`. + /// Details may be found in `rustc_hir_analysis::check::rvalue_scopes`. pub rvalue_scopes: RvalueScopes, /// Stores the predicates that apply on coroutine witness types. diff --git a/compiler/rustc_mir_build/src/builder/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/builder/expr/as_rvalue.rs index 5a97b08db28..b23bc089cd4 100644 --- a/compiler/rustc_mir_build/src/builder/expr/as_rvalue.rs +++ b/compiler/rustc_mir_build/src/builder/expr/as_rvalue.rs @@ -145,7 +145,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // malloc some memory of suitable size and align: let exchange_malloc = Operand::function_handle( tcx, - tcx.require_lang_item(LangItem::ExchangeMalloc, Some(expr_span)), + tcx.require_lang_item(LangItem::ExchangeMalloc, expr_span), [], expr_span, ); diff --git a/compiler/rustc_mir_build/src/builder/expr/into.rs b/compiler/rustc_mir_build/src/builder/expr/into.rs index a9a07997410..2074fbce0ae 100644 --- a/compiler/rustc_mir_build/src/builder/expr/into.rs +++ b/compiler/rustc_mir_build/src/builder/expr/into.rs @@ -307,7 +307,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } else if this.infcx.type_is_use_cloned_modulo_regions(this.param_env, ty) { // Convert `expr.use` to a call like `Clone::clone(&expr)` let success = this.cfg.start_new_block(); - let clone_trait = this.tcx.require_lang_item(LangItem::Clone, None); + let clone_trait = this.tcx.require_lang_item(LangItem::Clone, span); let clone_fn = this.tcx.associated_item_def_ids(clone_trait)[0]; let func = Operand::function_handle(this.tcx, clone_fn, [ty.into()], expr_span); let ref_ty = Ty::new_imm_ref(this.tcx, this.tcx.lifetimes.re_erased, ty); diff --git a/compiler/rustc_mir_build/src/builder/matches/test.rs b/compiler/rustc_mir_build/src/builder/matches/test.rs index 210b9cce581..a4609a6053e 100644 --- a/compiler/rustc_mir_build/src/builder/matches/test.rs +++ b/compiler/rustc_mir_build/src/builder/matches/test.rs @@ -364,7 +364,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let borrow_kind = super::util::ref_pat_borrow_kind(mutability); let source_info = self.source_info(span); let re_erased = self.tcx.lifetimes.re_erased; - let trait_item = self.tcx.require_lang_item(trait_item, None); + let trait_item = self.tcx.require_lang_item(trait_item, span); let method = trait_method(self.tcx, trait_item, method, [ty]); let ref_src = self.temp(Ty::new_ref(self.tcx, re_erased, ty, mutability), span); // `let ref_src = &src_place;` @@ -437,7 +437,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { val: Operand<'tcx>, ) { let str_ty = self.tcx.types.str_; - let eq_def_id = self.tcx.require_lang_item(LangItem::PartialEq, Some(source_info.span)); + let eq_def_id = self.tcx.require_lang_item(LangItem::PartialEq, source_info.span); let method = trait_method(self.tcx, eq_def_id, sym::eq, [str_ty, str_ty]); let bool_ty = self.tcx.types.bool; diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index 226dc920a49..3baeccf6409 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -38,7 +38,10 @@ impl<'tcx> ThirBuildCx<'tcx> { } pub(crate) fn mirror_exprs(&mut self, exprs: &'tcx [hir::Expr<'tcx>]) -> Box<[ExprId]> { - exprs.iter().map(|expr| self.mirror_expr_inner(expr)).collect() + // `mirror_exprs` may also recurse deeply, so it needs protection from stack overflow. + // Note that we *could* forward to `mirror_expr` for that, but we can consolidate the + // overhead of stack growth by doing it outside the iteration. + ensure_sufficient_stack(|| exprs.iter().map(|expr| self.mirror_expr_inner(expr)).collect()) } #[instrument(level = "trace", skip(self, hir_expr))] @@ -220,7 +223,7 @@ impl<'tcx> ThirBuildCx<'tcx> { }); // kind = Pin { __pointer: pointer } - let pin_did = self.tcx.require_lang_item(rustc_hir::LangItem::Pin, Some(span)); + let pin_did = self.tcx.require_lang_item(rustc_hir::LangItem::Pin, span); let args = self.tcx.mk_args(&[new_pin_target.into()]); let kind = ExprKind::Adt(Box::new(AdtExpr { adt_def: self.tcx.adt_def(pin_did), diff --git a/compiler/rustc_mir_build/src/thir/cx/mod.rs b/compiler/rustc_mir_build/src/thir/cx/mod.rs index 8c817605847..24d4136c642 100644 --- a/compiler/rustc_mir_build/src/thir/cx/mod.rs +++ b/compiler/rustc_mir_build/src/thir/cx/mod.rs @@ -189,7 +189,7 @@ impl<'tcx> ThirBuildCx<'tcx> { // C-variadic fns also have a `VaList` input that's not listed in `fn_sig` // (as it's created inside the body itself, not passed in from outside). let ty = if fn_decl.c_variadic && index == fn_decl.inputs.len() { - let va_list_did = self.tcx.require_lang_item(LangItem::VaList, Some(param.span)); + let va_list_did = self.tcx.require_lang_item(LangItem::VaList, param.span); self.tcx .type_of(va_list_did) diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs index 84a0190a7fa..003ad170861 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs @@ -15,7 +15,7 @@ use rustc_middle::ty::{ }; use rustc_middle::{mir, span_bug}; use rustc_span::def_id::DefId; -use rustc_span::{Span, sym}; +use rustc_span::{DUMMY_SP, Span, sym}; use rustc_trait_selection::traits::ObligationCause; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; use tracing::{debug, instrument, trace}; @@ -480,8 +480,9 @@ fn type_has_partial_eq_impl<'tcx>( // (If there isn't, then we can safely issue a hard // error, because that's never worked, due to compiler // using `PartialEq::eq` in this scenario in the past.) - let partial_eq_trait_id = tcx.require_lang_item(hir::LangItem::PartialEq, None); - let structural_partial_eq_trait_id = tcx.require_lang_item(hir::LangItem::StructuralPeq, None); + let partial_eq_trait_id = tcx.require_lang_item(hir::LangItem::PartialEq, DUMMY_SP); + let structural_partial_eq_trait_id = + tcx.require_lang_item(hir::LangItem::StructuralPeq, DUMMY_SP); let partial_eq_obligation = Obligation::new( tcx, diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs index cddb2f84778..d5d0d56f528 100644 --- a/compiler/rustc_mir_transform/src/coroutine.rs +++ b/compiler/rustc_mir_transform/src/coroutine.rs @@ -225,7 +225,7 @@ impl<'tcx> TransformVisitor<'tcx> { CoroutineKind::Coroutine(_) => span_bug!(body.span, "`Coroutine`s cannot be fused"), // `gen` continues return `None` CoroutineKind::Desugared(CoroutineDesugaring::Gen, _) => { - let option_def_id = self.tcx.require_lang_item(LangItem::Option, None); + let option_def_id = self.tcx.require_lang_item(LangItem::Option, body.span); make_aggregate_adt( option_def_id, VariantIdx::ZERO, @@ -242,7 +242,7 @@ impl<'tcx> TransformVisitor<'tcx> { span: source_info.span, const_: Const::Unevaluated( UnevaluatedConst::new( - self.tcx.require_lang_item(LangItem::AsyncGenFinished, None), + self.tcx.require_lang_item(LangItem::AsyncGenFinished, body.span), self.tcx.mk_args(&[yield_ty.into()]), ), self.old_yield_ty, @@ -282,7 +282,7 @@ impl<'tcx> TransformVisitor<'tcx> { const ONE: VariantIdx = VariantIdx::from_usize(1); let rvalue = match self.coroutine_kind { CoroutineKind::Desugared(CoroutineDesugaring::Async, _) => { - let poll_def_id = self.tcx.require_lang_item(LangItem::Poll, None); + let poll_def_id = self.tcx.require_lang_item(LangItem::Poll, source_info.span); let args = self.tcx.mk_args(&[self.old_ret_ty.into()]); let (variant_idx, operands) = if is_return { (ZERO, IndexVec::from_raw(vec![val])) // Poll::Ready(val) @@ -292,7 +292,7 @@ impl<'tcx> TransformVisitor<'tcx> { make_aggregate_adt(poll_def_id, variant_idx, args, operands) } CoroutineKind::Desugared(CoroutineDesugaring::Gen, _) => { - let option_def_id = self.tcx.require_lang_item(LangItem::Option, None); + let option_def_id = self.tcx.require_lang_item(LangItem::Option, source_info.span); let args = self.tcx.mk_args(&[self.old_yield_ty.into()]); let (variant_idx, operands) = if is_return { (ZERO, IndexVec::new()) // None @@ -310,7 +310,10 @@ impl<'tcx> TransformVisitor<'tcx> { span: source_info.span, const_: Const::Unevaluated( UnevaluatedConst::new( - self.tcx.require_lang_item(LangItem::AsyncGenFinished, None), + self.tcx.require_lang_item( + LangItem::AsyncGenFinished, + source_info.span, + ), self.tcx.mk_args(&[yield_ty.into()]), ), self.old_yield_ty, @@ -323,7 +326,7 @@ impl<'tcx> TransformVisitor<'tcx> { } CoroutineKind::Coroutine(_) => { let coroutine_state_def_id = - self.tcx.require_lang_item(LangItem::CoroutineState, None); + self.tcx.require_lang_item(LangItem::CoroutineState, source_info.span); let args = self.tcx.mk_args(&[self.old_yield_ty.into(), self.old_ret_ty.into()]); let variant_idx = if is_return { ONE // CoroutineState::Complete(val) @@ -496,7 +499,7 @@ fn make_coroutine_state_argument_indirect<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Bo fn make_coroutine_state_argument_pinned<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { let ref_coroutine_ty = body.local_decls.raw[1].ty; - let pin_did = tcx.require_lang_item(LangItem::Pin, Some(body.span)); + let pin_did = tcx.require_lang_item(LangItem::Pin, body.span); let pin_adt_ref = tcx.adt_def(pin_did); let args = tcx.mk_args(&[ref_coroutine_ty.into()]); let pin_ref_coroutine_ty = Ty::new_adt(tcx, pin_adt_ref, args); @@ -557,7 +560,7 @@ fn transform_async_context<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) -> Ty // replace the type of the `resume` argument replace_resume_ty_local(tcx, body, CTX_ARG, context_mut_ref); - let get_context_def_id = tcx.require_lang_item(LangItem::GetContext, None); + let get_context_def_id = tcx.require_lang_item(LangItem::GetContext, body.span); for bb in body.basic_blocks.indices() { let bb_data = &body[bb]; @@ -618,7 +621,7 @@ fn replace_resume_ty_local<'tcx>( #[cfg(debug_assertions)] { if let ty::Adt(resume_ty_adt, _) = local_ty.kind() { - let expected_adt = tcx.adt_def(tcx.require_lang_item(LangItem::ResumeTy, None)); + let expected_adt = tcx.adt_def(tcx.require_lang_item(LangItem::ResumeTy, body.span)); assert_eq!(*resume_ty_adt, expected_adt); } else { panic!("expected `ResumeTy`, found `{:?}`", local_ty); @@ -1095,7 +1098,7 @@ fn insert_term_block<'tcx>(body: &mut Body<'tcx>, kind: TerminatorKind<'tcx>) -> fn return_poll_ready_assign<'tcx>(tcx: TyCtxt<'tcx>, source_info: SourceInfo) -> Statement<'tcx> { // Poll::Ready(()) - let poll_def_id = tcx.require_lang_item(LangItem::Poll, None); + let poll_def_id = tcx.require_lang_item(LangItem::Poll, source_info.span); let args = tcx.mk_args(&[tcx.types.unit.into()]); let val = Operand::Constant(Box::new(ConstOperand { span: source_info.span, @@ -1437,7 +1440,7 @@ fn check_field_tys_sized<'tcx>( ), param_env, field_ty.ty, - tcx.require_lang_item(hir::LangItem::Sized, Some(field_ty.source_info.span)), + tcx.require_lang_item(hir::LangItem::Sized, field_ty.source_info.span), ); } @@ -1473,14 +1476,14 @@ impl<'tcx> crate::MirPass<'tcx> for StateTransform { let new_ret_ty = match coroutine_kind { CoroutineKind::Desugared(CoroutineDesugaring::Async, _) => { // Compute Poll<return_ty> - let poll_did = tcx.require_lang_item(LangItem::Poll, None); + let poll_did = tcx.require_lang_item(LangItem::Poll, body.span); let poll_adt_ref = tcx.adt_def(poll_did); let poll_args = tcx.mk_args(&[old_ret_ty.into()]); Ty::new_adt(tcx, poll_adt_ref, poll_args) } CoroutineKind::Desugared(CoroutineDesugaring::Gen, _) => { // Compute Option<yield_ty> - let option_did = tcx.require_lang_item(LangItem::Option, None); + let option_did = tcx.require_lang_item(LangItem::Option, body.span); let option_adt_ref = tcx.adt_def(option_did); let option_args = tcx.mk_args(&[old_yield_ty.into()]); Ty::new_adt(tcx, option_adt_ref, option_args) @@ -1491,7 +1494,7 @@ impl<'tcx> crate::MirPass<'tcx> for StateTransform { } CoroutineKind::Coroutine(_) => { // Compute CoroutineState<yield_ty, return_ty> - let state_did = tcx.require_lang_item(LangItem::CoroutineState, None); + let state_did = tcx.require_lang_item(LangItem::CoroutineState, body.span); let state_adt_ref = tcx.adt_def(state_did); let state_args = tcx.mk_args(&[old_yield_ty.into(), old_ret_ty.into()]); Ty::new_adt(tcx, state_adt_ref, state_args) diff --git a/compiler/rustc_mir_transform/src/coroutine/drop.rs b/compiler/rustc_mir_transform/src/coroutine/drop.rs index 625e53f9959..6021e795d21 100644 --- a/compiler/rustc_mir_transform/src/coroutine/drop.rs +++ b/compiler/rustc_mir_transform/src/coroutine/drop.rs @@ -42,7 +42,7 @@ fn build_poll_call<'tcx>( context_ref_place: &Place<'tcx>, unwind: UnwindAction, ) -> BasicBlock { - let poll_fn = tcx.require_lang_item(LangItem::FuturePoll, None); + let poll_fn = tcx.require_lang_item(LangItem::FuturePoll, DUMMY_SP); let poll_fn = Ty::new_fn_def(tcx, poll_fn, [fut_ty]); let poll_fn = Operand::Constant(Box::new(ConstOperand { span: DUMMY_SP, @@ -77,11 +77,8 @@ fn build_pin_fut<'tcx>( let fut_ty = fut_place.ty(&body.local_decls, tcx).ty; let fut_ref_ty = Ty::new_mut_ref(tcx, tcx.lifetimes.re_erased, fut_ty); let fut_ref_place = Place::from(body.local_decls.push(LocalDecl::new(fut_ref_ty, span))); - let pin_fut_new_unchecked_fn = Ty::new_fn_def( - tcx, - tcx.require_lang_item(LangItem::PinNewUnchecked, Some(span)), - [fut_ref_ty], - ); + let pin_fut_new_unchecked_fn = + Ty::new_fn_def(tcx, tcx.require_lang_item(LangItem::PinNewUnchecked, span), [fut_ref_ty]); let fut_pin_ty = pin_fut_new_unchecked_fn.fn_sig(tcx).output().skip_binder(); let fut_pin_place = Place::from(body.local_decls.push(LocalDecl::new(fut_pin_ty, span))); let pin_fut_new_unchecked_fn = Operand::Constant(Box::new(ConstOperand { @@ -143,13 +140,15 @@ fn build_poll_switch<'tcx>( let Discr { val: poll_ready_discr, ty: poll_discr_ty } = poll_enum .discriminant_for_variant( tcx, - poll_enum_adt.variant_index_with_id(tcx.require_lang_item(LangItem::PollReady, None)), + poll_enum_adt + .variant_index_with_id(tcx.require_lang_item(LangItem::PollReady, DUMMY_SP)), ) .unwrap(); let poll_pending_discr = poll_enum .discriminant_for_variant( tcx, - poll_enum_adt.variant_index_with_id(tcx.require_lang_item(LangItem::PollPending, None)), + poll_enum_adt + .variant_index_with_id(tcx.require_lang_item(LangItem::PollPending, DUMMY_SP)), ) .unwrap() .val; @@ -316,16 +315,17 @@ pub(super) fn expand_async_drops<'tcx>( // pending => return rv (yield) // ready => *continue_bb|drop_bb* + let source_info = body[bb].terminator.as_ref().unwrap().source_info; + // Compute Poll<> (aka Poll with void return) - let poll_adt_ref = tcx.adt_def(tcx.require_lang_item(LangItem::Poll, None)); + let poll_adt_ref = tcx.adt_def(tcx.require_lang_item(LangItem::Poll, source_info.span)); let poll_enum = Ty::new_adt(tcx, poll_adt_ref, tcx.mk_args(&[tcx.types.unit.into()])); - let poll_decl = LocalDecl::new(poll_enum, body.span); + let poll_decl = LocalDecl::new(poll_enum, source_info.span); let poll_unit_place = Place::from(body.local_decls.push(poll_decl)); // First state-loop yield for mainline let context_ref_place = - Place::from(body.local_decls.push(LocalDecl::new(context_mut_ref, body.span))); - let source_info = body[bb].terminator.as_ref().unwrap().source_info; + Place::from(body.local_decls.push(LocalDecl::new(context_mut_ref, source_info.span))); let arg = Rvalue::Use(Operand::Move(Place::from(CTX_ARG))); body[bb].statements.push(Statement { source_info, @@ -353,8 +353,9 @@ pub(super) fn expand_async_drops<'tcx>( let mut dropline_context_ref: Option<Place<'_>> = None; let mut dropline_call_bb: Option<BasicBlock> = None; if !is_dropline_bb { - let context_ref_place2: Place<'_> = - Place::from(body.local_decls.push(LocalDecl::new(context_mut_ref, body.span))); + let context_ref_place2: Place<'_> = Place::from( + body.local_decls.push(LocalDecl::new(context_mut_ref, source_info.span)), + ); let drop_yield_block = insert_term_block(body, TerminatorKind::Unreachable); // `kind` replaced later to yield let drop_switch_block = build_poll_switch( tcx, @@ -394,7 +395,7 @@ pub(super) fn expand_async_drops<'tcx>( span: source_info.span, const_: Const::Unevaluated( UnevaluatedConst::new( - tcx.require_lang_item(LangItem::AsyncGenPending, None), + tcx.require_lang_item(LangItem::AsyncGenPending, source_info.span), tcx.mk_args(&[yield_ty.into()]), ), full_yield_ty, @@ -404,7 +405,7 @@ pub(super) fn expand_async_drops<'tcx>( } else { // value needed only for return-yields or gen-coroutines, so just const here Operand::Constant(Box::new(ConstOperand { - span: body.span, + span: source_info.span, user_ty: None, const_: Const::from_bool(tcx, false), })) @@ -595,7 +596,7 @@ pub(super) fn create_coroutine_drop_shim<'tcx>( // Update the body's def to become the drop glue. let coroutine_instance = body.source.instance; - let drop_in_place = tcx.require_lang_item(LangItem::DropInPlace, None); + let drop_in_place = tcx.require_lang_item(LangItem::DropInPlace, body.span); let drop_instance = InstanceKind::DropGlue(drop_in_place, Some(coroutine_ty)); // Temporary change MirSource to coroutine's instance so that dump_mir produces more sensible @@ -666,7 +667,7 @@ pub(super) fn create_coroutine_drop_shim_async<'tcx>( } // Replace the return variable: Poll<RetT> to Poll<()> - let poll_adt_ref = tcx.adt_def(tcx.require_lang_item(LangItem::Poll, None)); + let poll_adt_ref = tcx.adt_def(tcx.require_lang_item(LangItem::Poll, body.span)); let poll_enum = Ty::new_adt(tcx, poll_adt_ref, tcx.mk_args(&[tcx.types.unit.into()])); body.local_decls[RETURN_PLACE] = LocalDecl::with_source_info(poll_enum, source_info); @@ -717,7 +718,7 @@ pub(super) fn create_coroutine_drop_shim_proxy_async<'tcx>( let source_info = SourceInfo::outermost(body.span); // Replace the return variable: Poll<RetT> to Poll<()> - let poll_adt_ref = tcx.adt_def(tcx.require_lang_item(LangItem::Poll, None)); + let poll_adt_ref = tcx.adt_def(tcx.require_lang_item(LangItem::Poll, body.span)); let poll_enum = Ty::new_adt(tcx, poll_adt_ref, tcx.mk_args(&[tcx.types.unit.into()])); body.local_decls[RETURN_PLACE] = LocalDecl::with_source_info(poll_enum, source_info); diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs index 99b95e7312b..0cf8142a560 100644 --- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs +++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs @@ -616,7 +616,7 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> { place, operand, &mut |elem, op| match elem { - TrackElem::Field(idx) => self.ecx.project_field(op, idx.as_usize()).discard_err(), + TrackElem::Field(idx) => self.ecx.project_field(op, idx).discard_err(), TrackElem::Variant(idx) => self.ecx.project_downcast(op, idx).discard_err(), TrackElem::Discriminant => { let variant = self.ecx.read_discriminant(op).discard_err()?; @@ -890,7 +890,8 @@ fn try_write_constant<'tcx>( ty::Tuple(elem_tys) => { for (i, elem) in elem_tys.iter().enumerate() { - let Some(field) = map.apply(place, TrackElem::Field(FieldIdx::from_usize(i))) else { + let i = FieldIdx::from_usize(i); + let Some(field) = map.apply(place, TrackElem::Field(i)) else { throw_machine_stop_str!("missing field in tuple") }; let field_dest = ecx.project_field(dest, i)?; @@ -928,7 +929,7 @@ fn try_write_constant<'tcx>( let Some(field) = map.apply(variant_place, TrackElem::Field(i)) else { throw_machine_stop_str!("missing field in ADT") }; - let field_dest = ecx.project_field(&variant_dest, i.as_usize())?; + let field_dest = ecx.project_field(&variant_dest, i)?; try_write_constant(ecx, &field_dest, field, ty, state, map)?; } ecx.write_discriminant(variant_idx, dest)?; diff --git a/compiler/rustc_mir_transform/src/elaborate_drop.rs b/compiler/rustc_mir_transform/src/elaborate_drop.rs index c15d7d6f732..3a5e2620b14 100644 --- a/compiler/rustc_mir_transform/src/elaborate_drop.rs +++ b/compiler/rustc_mir_transform/src/elaborate_drop.rs @@ -235,11 +235,8 @@ where let (fut_ty, drop_fn_def_id, trait_args) = if call_destructor_only { // Resolving obj.<AsyncDrop::drop>() - let trait_ref = ty::TraitRef::new( - tcx, - tcx.require_lang_item(LangItem::AsyncDrop, Some(span)), - [drop_ty], - ); + let trait_ref = + ty::TraitRef::new(tcx, tcx.require_lang_item(LangItem::AsyncDrop, span), [drop_ty]); let (drop_trait, trait_args) = match tcx.codegen_select_candidate( ty::TypingEnv::fully_monomorphized().as_query_input(trait_ref), ) { @@ -292,7 +289,7 @@ where (sig.output(), drop_fn_def_id, trait_args) } else { // Resolving async_drop_in_place<T> function for drop_ty - let drop_fn_def_id = tcx.require_lang_item(LangItem::AsyncDropInPlace, Some(span)); + let drop_fn_def_id = tcx.require_lang_item(LangItem::AsyncDropInPlace, span); let trait_args = tcx.mk_args(&[drop_ty.into()]); let sig = tcx.fn_sig(drop_fn_def_id).instantiate(tcx, trait_args); let sig = tcx.instantiate_bound_regions_with_erased(sig); @@ -319,7 +316,7 @@ where // pin_obj_place preparation let pin_obj_new_unchecked_fn = Ty::new_fn_def( tcx, - tcx.require_lang_item(LangItem::PinNewUnchecked, Some(span)), + tcx.require_lang_item(LangItem::PinNewUnchecked, span), [GenericArg::from(obj_ref_ty)], ); let pin_obj_ty = pin_obj_new_unchecked_fn.fn_sig(tcx).output().no_bound_vars().unwrap(); @@ -937,7 +934,7 @@ where fn destructor_call_block_sync(&mut self, (succ, unwind): (BasicBlock, Unwind)) -> BasicBlock { debug!("destructor_call_block_sync({:?}, {:?})", self, succ); let tcx = self.tcx(); - let drop_trait = tcx.require_lang_item(LangItem::Drop, None); + let drop_trait = tcx.require_lang_item(LangItem::Drop, DUMMY_SP); let drop_fn = tcx.associated_item_def_ids(drop_trait)[0]; let ty = self.place_ty(self.place); diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index a91d46ec406..92c30d239b5 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -438,8 +438,10 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { dest.clone() }; for (field_index, op) in fields.into_iter().enumerate() { - let field_dest = - self.ecx.project_field(&variant_dest, field_index).discard_err()?; + let field_dest = self + .ecx + .project_field(&variant_dest, FieldIdx::from_usize(field_index)) + .discard_err()?; self.ecx.copy_op(op, &field_dest).discard_err()?; } self.ecx @@ -1583,7 +1585,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { // We needed to check the variant to avoid trying to read the tag // field from an enum where no fields have variants, since that tag // field isn't in the `Aggregate` from which we're getting values. - Some((FieldIdx::from_usize(field_idx), field_layout.ty)) + Some((field_idx, field_layout.ty)) } else if let ty::Adt(adt, args) = ty.kind() && adt.is_struct() && adt.repr().transparent() diff --git a/compiler/rustc_mir_transform/src/jump_threading.rs b/compiler/rustc_mir_transform/src/jump_threading.rs index 31b361ec1a9..48db536c122 100644 --- a/compiler/rustc_mir_transform/src/jump_threading.rs +++ b/compiler/rustc_mir_transform/src/jump_threading.rs @@ -388,7 +388,7 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> { lhs, constant, &mut |elem, op| match elem { - TrackElem::Field(idx) => self.ecx.project_field(op, idx.as_usize()).discard_err(), + TrackElem::Field(idx) => self.ecx.project_field(op, idx).discard_err(), TrackElem::Variant(idx) => self.ecx.project_downcast(op, idx).discard_err(), TrackElem::Discriminant => { let variant = self.ecx.read_discriminant(op).discard_err()?; diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs index 9688ac8ed2e..6d45bbc6e16 100644 --- a/compiler/rustc_mir_transform/src/shim.rs +++ b/compiler/rustc_mir_transform/src/shim.rs @@ -98,7 +98,7 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceKind<'tcx>) -> Body< build_call_shim(tcx, instance, None, CallKind::Direct(def_id)) } ty::InstanceKind::ClosureOnceShim { call_once: _, track_caller: _ } => { - let fn_mut = tcx.require_lang_item(LangItem::FnMut, None); + let fn_mut = tcx.require_lang_item(LangItem::FnMut, DUMMY_SP); let call_mut = tcx .associated_items(fn_mut) .in_definition_order() diff --git a/compiler/rustc_mir_transform/src/shim/async_destructor_ctor.rs b/compiler/rustc_mir_transform/src/shim/async_destructor_ctor.rs index fbc8ee9b06c..fd7b7362cd9 100644 --- a/compiler/rustc_mir_transform/src/shim/async_destructor_ctor.rs +++ b/compiler/rustc_mir_transform/src/shim/async_destructor_ctor.rs @@ -64,7 +64,7 @@ pub(super) fn build_async_drop_shim<'tcx>( let needs_async_drop = drop_ty.needs_async_drop(tcx, typing_env); let needs_sync_drop = !needs_async_drop && drop_ty.needs_drop(tcx, typing_env); - let resume_adt = tcx.adt_def(tcx.require_lang_item(LangItem::ResumeTy, None)); + let resume_adt = tcx.adt_def(tcx.require_lang_item(LangItem::ResumeTy, DUMMY_SP)); let resume_ty = Ty::new_adt(tcx, resume_adt, ty::List::empty()); let fn_sig = ty::Binder::dummy(tcx.mk_fn_sig( @@ -220,7 +220,7 @@ fn build_adrop_for_coroutine_shim<'tcx>( body.source.instance = instance; body.phase = MirPhase::Runtime(RuntimePhase::Initial); body.var_debug_info.clear(); - let pin_adt_ref = tcx.adt_def(tcx.require_lang_item(LangItem::Pin, Some(span))); + let pin_adt_ref = tcx.adt_def(tcx.require_lang_item(LangItem::Pin, span)); let args = tcx.mk_args(&[proxy_ref.into()]); let pin_proxy_ref = Ty::new_adt(tcx, pin_adt_ref, args); @@ -308,10 +308,10 @@ fn build_adrop_for_adrop_shim<'tcx>( let cor_ref = Ty::new_mut_ref(tcx, tcx.lifetimes.re_erased, impl_ty); // ret_ty = `Poll<()>` - let poll_adt_ref = tcx.adt_def(tcx.require_lang_item(LangItem::Poll, None)); + let poll_adt_ref = tcx.adt_def(tcx.require_lang_item(LangItem::Poll, span)); let ret_ty = Ty::new_adt(tcx, poll_adt_ref, tcx.mk_args(&[tcx.types.unit.into()])); // env_ty = `Pin<&mut proxy_ty>` - let pin_adt_ref = tcx.adt_def(tcx.require_lang_item(LangItem::Pin, None)); + let pin_adt_ref = tcx.adt_def(tcx.require_lang_item(LangItem::Pin, span)); let env_ty = Ty::new_adt(tcx, pin_adt_ref, tcx.mk_args(&[proxy_ref.into()])); // sig = `fn (Pin<&mut proxy_ty>, &mut Context) -> Poll<()>` let sig = tcx.mk_fn_sig( @@ -376,7 +376,7 @@ fn build_adrop_for_adrop_shim<'tcx>( let cor_pin_ty = Ty::new_adt(tcx, pin_adt_ref, tcx.mk_args(&[cor_ref.into()])); let cor_pin_place = Place::from(locals.push(LocalDecl::new(cor_pin_ty, span))); - let pin_fn = tcx.require_lang_item(LangItem::PinNewUnchecked, Some(span)); + let pin_fn = tcx.require_lang_item(LangItem::PinNewUnchecked, span); // call Pin<FutTy>::new_unchecked(&mut impl_cor) blocks.push(BasicBlockData { statements, @@ -396,7 +396,7 @@ fn build_adrop_for_adrop_shim<'tcx>( }); // When dropping async drop coroutine, we continue its execution: // we call impl::poll (impl_layout, ctx) - let poll_fn = tcx.require_lang_item(LangItem::FuturePoll, None); + let poll_fn = tcx.require_lang_item(LangItem::FuturePoll, span); let resume_ctx = Place::from(Local::new(2)); blocks.push(BasicBlockData { statements: vec![], diff --git a/compiler/rustc_mir_transform/src/validate.rs b/compiler/rustc_mir_transform/src/validate.rs index c8aa7588d03..fd91508cc11 100644 --- a/compiler/rustc_mir_transform/src/validate.rs +++ b/compiler/rustc_mir_transform/src/validate.rs @@ -1253,7 +1253,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { self.tcx, self.tcx.require_lang_item( LangItem::CoerceUnsized, - Some(self.body.source_info(location).span), + self.body.source_info(location).span, ), [op_ty, *target_type], )) { diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 1ee977a5457..173030e0326 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -781,7 +781,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> { let tcx = self.tcx; let push_mono_lang_item = |this: &mut Self, lang_item: LangItem| { - let instance = Instance::mono(tcx, tcx.require_lang_item(lang_item, Some(source))); + let instance = Instance::mono(tcx, tcx.require_lang_item(lang_item, source)); if tcx.should_codegen_locally(instance) { this.used_items.push(create_fn_mono_item(tcx, instance, source)); } @@ -921,7 +921,7 @@ fn visit_instance_use<'tcx>( // be lowered in codegen to nothing or a call to panic_nounwind. So if we encounter any // of those intrinsics, we need to include a mono item for panic_nounwind, else we may try to // codegen a call to that function without generating code for the function itself. - let def_id = tcx.require_lang_item(LangItem::PanicNounwind, None); + let def_id = tcx.require_lang_item(LangItem::PanicNounwind, source); let panic_instance = Instance::mono(tcx, def_id); if tcx.should_codegen_locally(panic_instance) { output.push(create_fn_mono_item(tcx, panic_instance, source)); diff --git a/compiler/rustc_monomorphize/src/lib.rs b/compiler/rustc_monomorphize/src/lib.rs index 5c66017bc61..05683940cba 100644 --- a/compiler/rustc_monomorphize/src/lib.rs +++ b/compiler/rustc_monomorphize/src/lib.rs @@ -29,7 +29,7 @@ fn custom_coerce_unsize_info<'tcx>( ) -> Result<CustomCoerceUnsized, ErrorGuaranteed> { let trait_ref = ty::TraitRef::new( tcx.tcx, - tcx.require_lang_item(LangItem::CoerceUnsized, Some(tcx.span)), + tcx.require_lang_item(LangItem::CoerceUnsized, tcx.span), [source_ty, target_ty], ); diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index 6277dde7c97..b49a13ce584 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -2273,9 +2273,9 @@ impl<'a> Parser<'a> { ), // Also catches `fn foo(&a)`. PatKind::Ref(ref inner_pat, mutab) - if matches!(inner_pat.clone().into_inner().kind, PatKind::Ident(..)) => + if matches!(inner_pat.clone().kind, PatKind::Ident(..)) => { - match inner_pat.clone().into_inner().kind { + match inner_pat.clone().kind { PatKind::Ident(_, ident, _) => { let mutab = mutab.prefix_str(); ( diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index adfea3641e6..a298c4d4dec 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -1119,7 +1119,7 @@ impl<'a> Parser<'a> { /// Parse the field access used in offset_of, matched by `$(e:expr)+`. /// Currently returns a list of idents. However, it should be possible in /// future to also do array indices, which might be arbitrary expressions. - fn parse_floating_field_access(&mut self) -> PResult<'a, P<[Ident]>> { + fn parse_floating_field_access(&mut self) -> PResult<'a, Vec<Ident>> { let mut fields = Vec::new(); let mut trailing_dot = None; @@ -3468,10 +3468,8 @@ impl<'a> Parser<'a> { // Detect and recover from `($pat if $cond) => $arm`. // FIXME(guard_patterns): convert this to a normal guard instead let span = pat.span; - let ast::PatKind::Paren(subpat) = pat.into_inner().kind else { unreachable!() }; - let ast::PatKind::Guard(_, mut cond) = subpat.into_inner().kind else { - unreachable!() - }; + let ast::PatKind::Paren(subpat) = pat.kind else { unreachable!() }; + let ast::PatKind::Guard(_, mut cond) = subpat.kind else { unreachable!() }; self.psess.gated_spans.ungate_last(sym::guard_patterns, cond.span); CondChecker::new(self, LetChainsPolicy::AlwaysAllowed).visit_expr(&mut cond); let right = self.prev_token.span; diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index c7b0eb11e5a..a325c2a57ab 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -145,7 +145,7 @@ impl<'a> Parser<'a> { { let mut item = item.expect("an actual item"); attrs.prepend_to_nt_inner(&mut item.attrs); - return Ok(Some(item.into_inner())); + return Ok(Some(*item)); } self.collect_tokens(None, attrs, force_collect, |this, mut attrs| { @@ -637,7 +637,7 @@ impl<'a> Parser<'a> { self.dcx().emit_err(errors::MissingForInTraitImpl { span: missing_for_span }); } - let ty_first = ty_first.into_inner(); + let ty_first = *ty_first; let path = match ty_first.kind { // This notably includes paths passed through `ty` macro fragments (#46438). TyKind::Path(None, path) => path, diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index d6ff80b2eb4..7a226136e23 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -1086,7 +1086,7 @@ impl<'a> Parser<'a> { if matches!(pat.kind, PatKind::Ident(BindingMode(ByRef::Yes(_), Mutability::Mut), ..)) { self.psess.gated_spans.gate(sym::mut_ref, pat.span); } - Ok(pat.into_inner().kind) + Ok(pat.kind) } /// Turn all by-value immutable bindings in a pattern into mutable bindings. diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index 17481731b11..9ddfc179e9b 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -7,6 +7,7 @@ use rustc_ast::{ Pinnedness, PolyTraitRef, PreciseCapturingArg, TraitBoundModifiers, TraitObjectSyntax, Ty, TyKind, UnsafeBinderTy, }; +use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_errors::{Applicability, Diag, PResult}; use rustc_span::{ErrorGuaranteed, Ident, Span, kw, sym}; use thin_vec::{ThinVec, thin_vec}; @@ -104,14 +105,17 @@ fn can_begin_dyn_bound_in_edition_2015(t: &Token) -> bool { impl<'a> Parser<'a> { /// Parses a type. pub fn parse_ty(&mut self) -> PResult<'a, P<Ty>> { - self.parse_ty_common( - AllowPlus::Yes, - AllowCVariadic::No, - RecoverQPath::Yes, - RecoverReturnSign::Yes, - None, - RecoverQuestionMark::Yes, - ) + // Make sure deeply nested types don't overflow the stack. + ensure_sufficient_stack(|| { + self.parse_ty_common( + AllowPlus::Yes, + AllowCVariadic::No, + RecoverQPath::Yes, + RecoverReturnSign::Yes, + None, + RecoverQuestionMark::Yes, + ) + }) } pub(super) fn parse_ty_with_generics_recovery( @@ -404,7 +408,7 @@ impl<'a> Parser<'a> { })?; if ts.len() == 1 && matches!(trailing, Trailing::No) { - let ty = ts.into_iter().next().unwrap().into_inner(); + let ty = ts.into_iter().next().unwrap(); let maybe_bounds = allow_plus == AllowPlus::Yes && self.token.is_like_plus(); match ty.kind { // `(TY_BOUND_NOPAREN) + BOUND + ...`. @@ -420,7 +424,7 @@ impl<'a> Parser<'a> { self.parse_remaining_bounds(bounds, true) } // `(TYPE)` - _ => Ok(TyKind::Paren(P(ty))), + _ => Ok(TyKind::Paren(ty)), } } else { Ok(TyKind::Tup(ts)) @@ -1295,7 +1299,7 @@ impl<'a> Parser<'a> { ) -> PResult<'a, ()> { let fn_path_segment = fn_path.segments.last_mut().unwrap(); let generic_args = if let Some(p_args) = &fn_path_segment.args { - p_args.clone().into_inner() + *p_args.clone() } else { // Normally it wouldn't come here because the upstream should have parsed // generic parameters (otherwise it's impossible to call this function). diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index 6d815e510ea..983e562cdf3 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -509,23 +509,11 @@ passes_must_not_suspend = passes_must_use_no_effect = `#[must_use]` has no effect when applied to {$article} {$target} -passes_naked_asm_outside_naked_fn = - the `naked_asm!` macro can only be used in functions marked with `#[unsafe(naked)]` - -passes_naked_functions_asm_block = - naked functions must contain a single `naked_asm!` invocation - .label_multiple_asm = multiple `naked_asm!` invocations are not allowed in naked functions - .label_non_asm = not allowed in naked functions - passes_naked_functions_incompatible_attribute = attribute incompatible with `#[unsafe(naked)]` .label = the `{$attr}` attribute is incompatible with `#[unsafe(naked)]` .naked_attribute = function marked with `#[unsafe(naked)]` here -passes_naked_functions_must_naked_asm = - the `asm!` macro is not allowed in naked functions - .label = consider using the `naked_asm!` macro instead - passes_no_link = attribute should be applied to an `extern crate` item .label = not an `extern crate` item @@ -556,9 +544,6 @@ passes_no_mangle_foreign = .note = symbol names in extern blocks are not mangled .suggestion = remove this attribute -passes_no_patterns = - patterns not allowed in naked function parameters - passes_no_sanitize = `#[no_sanitize({$attr_str})]` should be applied to {$accepted_kind} .label = not {$accepted_kind} @@ -606,10 +591,6 @@ passes_panic_unwind_without_std = .note = since the core library is usually precompiled with panic="unwind", rebuilding your crate with panic="abort" may not be enough to fix the problem .help = using nightly cargo, use -Zbuild-std with panic="abort" to avoid unwinding -passes_params_not_allowed = - referencing function parameters is not allowed in naked functions - .help = follow the calling convention in asm block to use parameters - passes_parent_info = {$num -> [one] {$descr} diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index 00682a9c7a7..b995781719b 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -1197,51 +1197,6 @@ pub(crate) struct UnlabeledCfInWhileCondition<'a> { } #[derive(Diagnostic)] -#[diag(passes_no_patterns)] -pub(crate) struct NoPatterns { - #[primary_span] - pub span: Span, -} - -#[derive(Diagnostic)] -#[diag(passes_params_not_allowed)] -#[help] -pub(crate) struct ParamsNotAllowed { - #[primary_span] - pub span: Span, -} - -pub(crate) struct NakedFunctionsAsmBlock { - pub span: Span, - pub multiple_asms: Vec<Span>, - pub non_asms: Vec<Span>, -} - -impl<G: EmissionGuarantee> Diagnostic<'_, G> for NakedFunctionsAsmBlock { - #[track_caller] - fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> { - let mut diag = Diag::new(dcx, level, fluent::passes_naked_functions_asm_block); - diag.span(self.span); - diag.code(E0787); - for span in self.multiple_asms.iter() { - diag.span_label(*span, fluent::passes_label_multiple_asm); - } - for span in self.non_asms.iter() { - diag.span_label(*span, fluent::passes_label_non_asm); - } - diag - } -} - -#[derive(Diagnostic)] -#[diag(passes_naked_functions_must_naked_asm, code = E0787)] -pub(crate) struct NakedFunctionsMustNakedAsm { - #[primary_span] - #[label] - pub span: Span, -} - -#[derive(Diagnostic)] #[diag(passes_naked_functions_incompatible_attribute, code = E0736)] pub(crate) struct NakedFunctionIncompatibleAttribute { #[primary_span] @@ -1253,13 +1208,6 @@ pub(crate) struct NakedFunctionIncompatibleAttribute { } #[derive(Diagnostic)] -#[diag(passes_naked_asm_outside_naked_fn)] -pub(crate) struct NakedAsmOutsideNakedFn { - #[primary_span] - pub span: Span, -} - -#[derive(Diagnostic)] #[diag(passes_attr_only_in_functions)] pub(crate) struct AttrOnlyInFunctions { #[primary_span] diff --git a/compiler/rustc_passes/src/lang_items.rs b/compiler/rustc_passes/src/lang_items.rs index 275714c2d0e..3afed9784de 100644 --- a/compiler/rustc_passes/src/lang_items.rs +++ b/compiler/rustc_passes/src/lang_items.rs @@ -307,18 +307,14 @@ impl<'ast, 'tcx> visit::Visitor<'ast> for LanguageItemCollector<'ast, 'tcx> { self.parent_item = parent_item; } - fn visit_enum_def(&mut self, enum_definition: &'ast ast::EnumDef) { - for variant in &enum_definition.variants { - self.check_for_lang( - Target::Variant, - self.resolver.node_id_to_def_id[&variant.id], - &variant.attrs, - variant.span, - None, - ); - } - - visit::walk_enum_def(self, enum_definition); + fn visit_variant(&mut self, variant: &'ast ast::Variant) { + self.check_for_lang( + Target::Variant, + self.resolver.node_id_to_def_id[&variant.id], + &variant.attrs, + variant.span, + None, + ); } fn visit_assoc_item(&mut self, i: &'ast ast::AssocItem, ctxt: visit::AssocCtxt) { diff --git a/compiler/rustc_passes/src/lib.rs b/compiler/rustc_passes/src/lib.rs index f9445485f60..639ca683cf6 100644 --- a/compiler/rustc_passes/src/lib.rs +++ b/compiler/rustc_passes/src/lib.rs @@ -14,7 +14,7 @@ #![feature(try_blocks)] // tidy-alphabetical-end -use rustc_middle::query::Providers; +use rustc_middle::util::Providers; pub mod abi_test; mod check_attr; @@ -32,7 +32,6 @@ pub mod layout_test; mod lib_features; mod liveness; pub mod loops; -mod naked_functions; mod reachable; pub mod stability; mod upvars; @@ -49,7 +48,6 @@ pub fn provide(providers: &mut Providers) { lang_items::provide(providers); lib_features::provide(providers); loops::provide(providers); - naked_functions::provide(providers); liveness::provide(providers); reachable::provide(providers); stability::provide(providers); diff --git a/compiler/rustc_resolve/src/check_unused.rs b/compiler/rustc_resolve/src/check_unused.rs index 9b824572b66..2e870c47f8e 100644 --- a/compiler/rustc_resolve/src/check_unused.rs +++ b/compiler/rustc_resolve/src/check_unused.rs @@ -100,6 +100,21 @@ impl<'a, 'ra, 'tcx> UnusedImportCheckVisitor<'a, 'ra, 'tcx> { } } + fn check_use_tree(&mut self, use_tree: &'a ast::UseTree, id: ast::NodeId) { + if self.r.effective_visibilities.is_exported(self.r.local_def_id(id)) { + self.check_import_as_underscore(use_tree, id); + return; + } + + if let ast::UseTreeKind::Nested { ref items, .. } = use_tree.kind { + if items.is_empty() { + self.unused_import(self.base_id).add(id); + } + } else { + self.check_import(id); + } + } + fn unused_import(&mut self, id: ast::NodeId) -> &mut UnusedImport { let use_tree_id = self.base_id; let use_tree = self.base_use_tree.unwrap().clone(); @@ -225,13 +240,21 @@ impl<'a, 'ra, 'tcx> UnusedImportCheckVisitor<'a, 'ra, 'tcx> { impl<'a, 'ra, 'tcx> Visitor<'a> for UnusedImportCheckVisitor<'a, 'ra, 'tcx> { fn visit_item(&mut self, item: &'a ast::Item) { - match item.kind { + self.item_span = item.span_with_attributes(); + match &item.kind { // Ignore is_public import statements because there's no way to be sure // whether they're used or not. Also ignore imports with a dummy span // because this means that they were generated in some fashion by the // compiler and we don't need to consider them. ast::ItemKind::Use(..) if item.span.is_dummy() => return, - ast::ItemKind::ExternCrate(orig_name, ident) => { + // Use the base UseTree's NodeId as the item id + // This allows the grouping of all the lints in the same item + ast::ItemKind::Use(use_tree) => { + self.base_id = item.id; + self.base_use_tree = Some(use_tree); + self.check_use_tree(use_tree, item.id); + } + &ast::ItemKind::ExternCrate(orig_name, ident) => { self.extern_crate_items.push(ExternCrateToLint { id: item.id, span: item.span, @@ -245,32 +268,12 @@ impl<'a, 'ra, 'tcx> Visitor<'a> for UnusedImportCheckVisitor<'a, 'ra, 'tcx> { _ => {} } - self.item_span = item.span_with_attributes(); visit::walk_item(self, item); } - fn visit_use_tree(&mut self, use_tree: &'a ast::UseTree, id: ast::NodeId, nested: bool) { - // Use the base UseTree's NodeId as the item id - // This allows the grouping of all the lints in the same item - if !nested { - self.base_id = id; - self.base_use_tree = Some(use_tree); - } - - if self.r.effective_visibilities.is_exported(self.r.local_def_id(id)) { - self.check_import_as_underscore(use_tree, id); - return; - } - - if let ast::UseTreeKind::Nested { ref items, .. } = use_tree.kind { - if items.is_empty() { - self.unused_import(self.base_id).add(id); - } - } else { - self.check_import(id); - } - - visit::walk_use_tree(self, use_tree, id); + fn visit_nested_use_tree(&mut self, use_tree: &'a ast::UseTree, id: ast::NodeId) { + self.check_use_tree(use_tree, id); + visit::walk_use_tree(self, use_tree); } } diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index 25485be5622..dc16fe212b1 100644 --- a/compiler/rustc_resolve/src/def_collector.rs +++ b/compiler/rustc_resolve/src/def_collector.rs @@ -147,7 +147,10 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { DefKind::Macro(macro_kind) } ItemKind::GlobalAsm(..) => DefKind::GlobalAsm, - ItemKind::Use(..) => return visit::walk_item(self, i), + ItemKind::Use(use_tree) => { + self.create_def(i.id, None, DefKind::Use, use_tree.span); + return visit::walk_item(self, i); + } ItemKind::MacCall(..) | ItemKind::DelegationMac(..) => { return self.visit_macro_invoc(i.id); } @@ -232,9 +235,9 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { } } - fn visit_use_tree(&mut self, use_tree: &'a UseTree, id: NodeId, _nested: bool) { + fn visit_nested_use_tree(&mut self, use_tree: &'a UseTree, id: NodeId) { self.create_def(id, None, DefKind::Use, use_tree.span); - visit::walk_use_tree(self, use_tree, id); + visit::walk_use_tree(self, use_tree); } fn visit_foreign_item(&mut self, fi: &'a ForeignItem) { diff --git a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs index d2917478e4e..c69991f3fb2 100644 --- a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs +++ b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs @@ -14,7 +14,7 @@ use rustc_middle::ty::{ TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt, UintTy, }; use rustc_span::def_id::DefId; -use rustc_span::sym; +use rustc_span::{DUMMY_SP, sym}; use rustc_trait_selection::traits; use tracing::{debug, instrument}; @@ -414,7 +414,7 @@ pub(crate) fn transform_instance<'tcx>( } ty::Coroutine(..) => match tcx.coroutine_kind(instance.def_id()).unwrap() { hir::CoroutineKind::Coroutine(..) => ( - tcx.require_lang_item(LangItem::Coroutine, None), + tcx.require_lang_item(LangItem::Coroutine, DUMMY_SP), Some(instance.args.as_coroutine().resume_ty()), ), hir::CoroutineKind::Desugared(desugaring, _) => { @@ -423,11 +423,11 @@ pub(crate) fn transform_instance<'tcx>( hir::CoroutineDesugaring::AsyncGen => LangItem::AsyncIterator, hir::CoroutineDesugaring::Gen => LangItem::Iterator, }; - (tcx.require_lang_item(lang_item, None), None) + (tcx.require_lang_item(lang_item, DUMMY_SP), None) } }, ty::CoroutineClosure(..) => ( - tcx.require_lang_item(LangItem::FnOnce, None), + tcx.require_lang_item(LangItem::FnOnce, DUMMY_SP), Some( tcx.instantiate_bound_regions_with_erased( instance.args.as_coroutine_closure().coroutine_closure_sig(), diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs index 8e2137da655..2c16672d786 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs @@ -73,7 +73,7 @@ use rustc_middle::ty::{ TypeVisitableExt, }; use rustc_span::def_id::LOCAL_CRATE; -use rustc_span::{BytePos, DesugaringKind, Pos, Span, sym}; +use rustc_span::{BytePos, DUMMY_SP, DesugaringKind, Pos, Span, sym}; use tracing::{debug, instrument}; use crate::error_reporting::TypeErrCtxt; @@ -194,7 +194,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { _ => return None, }; - let future_trait = self.tcx.require_lang_item(LangItem::Future, None); + let future_trait = self.tcx.require_lang_item(LangItem::Future, DUMMY_SP); let item_def_id = self.tcx.associated_item_def_ids(future_trait)[0]; self.tcx diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/call_kind.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/call_kind.rs index d8b405e904c..8a67e4ccd45 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/call_kind.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/call_kind.rs @@ -6,7 +6,7 @@ use rustc_hir::def::DefKind; use rustc_hir::def_id::DefId; use rustc_hir::{LangItem, lang_items}; use rustc_middle::ty::{AssocItemContainer, GenericArgsRef, Instance, Ty, TyCtxt, TypingEnv}; -use rustc_span::{DesugaringKind, Ident, Span, sym}; +use rustc_span::{DUMMY_SP, DesugaringKind, Ident, Span, sym}; use tracing::debug; use crate::traits::specialization_graph; @@ -31,9 +31,9 @@ impl CallDesugaringKind { pub fn trait_def_id(self, tcx: TyCtxt<'_>) -> DefId { match self { Self::ForLoopIntoIter => tcx.get_diagnostic_item(sym::IntoIterator).unwrap(), - Self::ForLoopNext => tcx.require_lang_item(LangItem::Iterator, None), + Self::ForLoopNext => tcx.require_lang_item(LangItem::Iterator, DUMMY_SP), Self::QuestionBranch | Self::TryBlockFromOutput => { - tcx.require_lang_item(LangItem::Try, None) + tcx.require_lang_item(LangItem::Try, DUMMY_SP) } Self::QuestionFromResidual => tcx.get_diagnostic_item(sym::FromResidual).unwrap(), Self::Await => tcx.get_diagnostic_item(sym::IntoFuture).unwrap(), diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs index 9c301373cf9..3b7fd8b7a20 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -955,7 +955,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { return false; }; - let clone_trait = self.tcx.require_lang_item(LangItem::Clone, None); + let clone_trait = self.tcx.require_lang_item(LangItem::Clone, obligation.cause.span); let has_clone = |ty| { self.type_implements_trait(clone_trait, [ty], obligation.param_env) .must_apply_modulo_regions() @@ -3625,7 +3625,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { trait_pred: ty::PolyTraitPredicate<'tcx>, span: Span, ) { - let future_trait = self.tcx.require_lang_item(LangItem::Future, None); + let future_trait = self.tcx.require_lang_item(LangItem::Future, span); let self_ty = self.resolve_vars_if_possible(trait_pred.self_ty()); let impls_future = self.type_implements_trait( @@ -4141,7 +4141,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { let pred = ty::Binder::dummy(ty::TraitPredicate { trait_ref: ty::TraitRef::new( tcx, - tcx.require_lang_item(LangItem::Clone, Some(span)), + tcx.require_lang_item(LangItem::Clone, span), [*ty], ), polarity: ty::PredicatePolarity::Positive, diff --git a/compiler/rustc_trait_selection/src/infer.rs b/compiler/rustc_trait_selection/src/infer.rs index 0dab3adadb0..0118321befb 100644 --- a/compiler/rustc_trait_selection/src/infer.rs +++ b/compiler/rustc_trait_selection/src/infer.rs @@ -38,7 +38,7 @@ impl<'tcx> InferCtxt<'tcx> { return self.tcx.type_is_copy_modulo_regions(self.typing_env(param_env), ty); } - let copy_def_id = self.tcx.require_lang_item(LangItem::Copy, None); + let copy_def_id = self.tcx.require_lang_item(LangItem::Copy, DUMMY_SP); // This can get called from typeck (by euv), and `moves_by_default` // rightly refuses to work with inference variables, but @@ -49,7 +49,7 @@ impl<'tcx> InferCtxt<'tcx> { fn type_is_clone_modulo_regions(&self, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> bool { let ty = self.resolve_vars_if_possible(ty); - let clone_def_id = self.tcx.require_lang_item(LangItem::Clone, None); + let clone_def_id = self.tcx.require_lang_item(LangItem::Clone, DUMMY_SP); traits::type_known_to_meet_bound_modulo_regions(self, param_env, ty, clone_def_id) } @@ -59,12 +59,12 @@ impl<'tcx> InferCtxt<'tcx> { ty: Ty<'tcx>, ) -> bool { let ty = self.resolve_vars_if_possible(ty); - let use_cloned_def_id = self.tcx.require_lang_item(LangItem::UseCloned, None); + let use_cloned_def_id = self.tcx.require_lang_item(LangItem::UseCloned, DUMMY_SP); traits::type_known_to_meet_bound_modulo_regions(self, param_env, ty, use_cloned_def_id) } fn type_is_sized_modulo_regions(&self, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> bool { - let lang_item = self.tcx.require_lang_item(LangItem::Sized, None); + let lang_item = self.tcx.require_lang_item(LangItem::Sized, DUMMY_SP); traits::type_known_to_meet_bound_modulo_regions(self, param_env, ty, lang_item) } diff --git a/compiler/rustc_trait_selection/src/solve/delegate.rs b/compiler/rustc_trait_selection/src/solve/delegate.rs index e92e37b8738..69a0c0809b5 100644 --- a/compiler/rustc_trait_selection/src/solve/delegate.rs +++ b/compiler/rustc_trait_selection/src/solve/delegate.rs @@ -64,6 +64,16 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate< span: Span, ) -> Option<Certainty> { if let Some(trait_pred) = goal.predicate.as_trait_clause() { + if self.shallow_resolve(trait_pred.self_ty().skip_binder()).is_ty_var() + // We don't do this fast path when opaques are defined since we may + // eventually use opaques to incompletely guide inference via ty var + // self types. + // FIXME: Properly consider opaques here. + && self.inner.borrow_mut().opaque_types().is_empty() + { + return Some(Certainty::AMBIGUOUS); + } + if trait_pred.polarity() == ty::PredicatePolarity::Positive { match self.0.tcx.as_lang_item(trait_pred.def_id()) { Some(LangItem::Sized) @@ -115,6 +125,17 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate< Some(Certainty::Yes) } + ty::PredicateKind::Subtype(ty::SubtypePredicate { a, b, .. }) + | ty::PredicateKind::Coerce(ty::CoercePredicate { a, b }) => { + if self.shallow_resolve(a).is_ty_var() && self.shallow_resolve(b).is_ty_var() { + // FIXME: We also need to register a subtype relation between these vars + // when those are added, and if they aren't in the same sub root then + // we should mark this goal as `has_changed`. + Some(Certainty::AMBIGUOUS) + } else { + None + } + } _ => None, } } diff --git a/compiler/rustc_trait_selection/src/traits/effects.rs b/compiler/rustc_trait_selection/src/traits/effects.rs index cc5861b5a1f..e77d9e32cb9 100644 --- a/compiler/rustc_trait_selection/src/traits/effects.rs +++ b/compiler/rustc_trait_selection/src/traits/effects.rs @@ -248,7 +248,7 @@ fn evaluate_host_effect_for_destruct_goal<'tcx>( obligation: &HostEffectObligation<'tcx>, ) -> Result<ThinVec<PredicateObligation<'tcx>>, EvaluationFailure> { let tcx = selcx.tcx(); - let destruct_def_id = tcx.require_lang_item(LangItem::Destruct, None); + let destruct_def_id = tcx.require_lang_item(LangItem::Destruct, obligation.cause.span); let self_ty = obligation.predicate.self_ty(); let const_conditions = match *self_ty.kind() { @@ -267,7 +267,7 @@ fn evaluate_host_effect_for_destruct_goal<'tcx>( Some(hir::Constness::NotConst) => return Err(EvaluationFailure::NoSolution), // `Drop` impl exists, and it's const. Require `Ty: ~const Drop` to hold. Some(hir::Constness::Const) => { - let drop_def_id = tcx.require_lang_item(LangItem::Drop, None); + let drop_def_id = tcx.require_lang_item(LangItem::Drop, obligation.cause.span); let drop_trait_ref = ty::TraitRef::new(tcx, drop_def_id, [self_ty]); const_conditions.push(drop_trait_ref); } diff --git a/compiler/rustc_trait_selection/src/traits/misc.rs b/compiler/rustc_trait_selection/src/traits/misc.rs index a4b6f330b9d..393f458bea2 100644 --- a/compiler/rustc_trait_selection/src/traits/misc.rs +++ b/compiler/rustc_trait_selection/src/traits/misc.rs @@ -157,7 +157,7 @@ pub fn type_allowed_to_implement_const_param_ty<'tcx>( parent_cause.clone(), param_env, inner_ty, - tcx.require_lang_item(lang_item, Some(parent_cause.span)), + tcx.require_lang_item(lang_item, parent_cause.span), ); let errors = ocx.select_all_or_error(); @@ -193,7 +193,7 @@ pub fn all_fields_implement_trait<'tcx>( parent_cause: ObligationCause<'tcx>, lang_item: LangItem, ) -> Result<(), Vec<(&'tcx ty::FieldDef, Ty<'tcx>, InfringingFieldsReason<'tcx>)>> { - let trait_def_id = tcx.require_lang_item(lang_item, Some(parent_cause.span)); + let trait_def_id = tcx.require_lang_item(lang_item, parent_cause.span); let mut infringing = Vec::new(); for variant in adt.variants() { diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index ed0f34b5aa9..6dd80551980 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -1117,7 +1117,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( selcx.tcx(), selcx.tcx().require_lang_item( LangItem::Sized, - Some(obligation.cause.span), + obligation.cause.span, ), [self_ty], ), @@ -1317,7 +1317,7 @@ fn confirm_coroutine_candidate<'cx, 'tcx>( let tcx = selcx.tcx(); - let coroutine_def_id = tcx.require_lang_item(LangItem::Coroutine, None); + let coroutine_def_id = tcx.require_lang_item(LangItem::Coroutine, obligation.cause.span); let (trait_ref, yield_ty, return_ty) = super::util::coroutine_trait_ref_and_outputs( tcx, @@ -1375,7 +1375,7 @@ fn confirm_future_candidate<'cx, 'tcx>( debug!(?obligation, ?coroutine_sig, ?obligations, "confirm_future_candidate"); let tcx = selcx.tcx(); - let fut_def_id = tcx.require_lang_item(LangItem::Future, None); + let fut_def_id = tcx.require_lang_item(LangItem::Future, obligation.cause.span); let (trait_ref, return_ty) = super::util::future_trait_ref_and_outputs( tcx, @@ -1421,7 +1421,7 @@ fn confirm_iterator_candidate<'cx, 'tcx>( debug!(?obligation, ?gen_sig, ?obligations, "confirm_iterator_candidate"); let tcx = selcx.tcx(); - let iter_def_id = tcx.require_lang_item(LangItem::Iterator, None); + let iter_def_id = tcx.require_lang_item(LangItem::Iterator, obligation.cause.span); let (trait_ref, yield_ty) = super::util::iterator_trait_ref_and_outputs( tcx, @@ -1467,7 +1467,7 @@ fn confirm_async_iterator_candidate<'cx, 'tcx>( debug!(?obligation, ?gen_sig, ?obligations, "confirm_async_iterator_candidate"); let tcx = selcx.tcx(); - let iter_def_id = tcx.require_lang_item(LangItem::AsyncIterator, None); + let iter_def_id = tcx.require_lang_item(LangItem::AsyncIterator, obligation.cause.span); let (trait_ref, yield_ty) = super::util::async_iterator_trait_ref_and_outputs( tcx, @@ -1511,12 +1511,13 @@ fn confirm_builtin_candidate<'cx, 'tcx>( let trait_def_id = tcx.trait_of_item(item_def_id).unwrap(); let args = tcx.mk_args(&[self_ty.into()]); let (term, obligations) = if tcx.is_lang_item(trait_def_id, LangItem::DiscriminantKind) { - let discriminant_def_id = tcx.require_lang_item(LangItem::Discriminant, None); + let discriminant_def_id = + tcx.require_lang_item(LangItem::Discriminant, obligation.cause.span); assert_eq!(discriminant_def_id, item_def_id); (self_ty.discriminant_ty(tcx).into(), PredicateObligations::new()) } else if tcx.is_lang_item(trait_def_id, LangItem::PointeeTrait) { - let metadata_def_id = tcx.require_lang_item(LangItem::Metadata, None); + let metadata_def_id = tcx.require_lang_item(LangItem::Metadata, obligation.cause.span); assert_eq!(metadata_def_id, item_def_id); let mut obligations = PredicateObligations::new(); @@ -1538,7 +1539,7 @@ fn confirm_builtin_candidate<'cx, 'tcx>( // exist. Instead, `Pointee<Metadata = ()>` should be a supertrait of `Sized`. let sized_predicate = ty::TraitRef::new( tcx, - tcx.require_lang_item(LangItem::Sized, Some(obligation.cause.span)), + tcx.require_lang_item(LangItem::Sized, obligation.cause.span), [self_ty], ); obligations.push(obligation.with(tcx, sized_predicate)); @@ -1620,7 +1621,7 @@ fn confirm_closure_candidate<'cx, 'tcx>( ) } else { let upvars_projection_def_id = - tcx.require_lang_item(LangItem::AsyncFnKindUpvars, None); + tcx.require_lang_item(LangItem::AsyncFnKindUpvars, obligation.cause.span); let tupled_upvars_ty = Ty::new_projection( tcx, upvars_projection_def_id, @@ -1681,8 +1682,9 @@ fn confirm_callable_candidate<'cx, 'tcx>( debug!(?obligation, ?fn_sig, "confirm_callable_candidate"); - let fn_once_def_id = tcx.require_lang_item(LangItem::FnOnce, None); - let fn_once_output_def_id = tcx.require_lang_item(LangItem::FnOnceOutput, None); + let fn_once_def_id = tcx.require_lang_item(LangItem::FnOnce, obligation.cause.span); + let fn_once_output_def_id = + tcx.require_lang_item(LangItem::FnOnceOutput, obligation.cause.span); let predicate = super::util::closure_trait_ref_and_return_type( tcx, @@ -1740,8 +1742,8 @@ fn confirm_async_closure_candidate<'cx, 'tcx>( args.coroutine_captures_by_ref_ty(), ) } else { - let upvars_projection_def_id = - tcx.require_lang_item(LangItem::AsyncFnKindUpvars, None); + let upvars_projection_def_id = tcx + .require_lang_item(LangItem::AsyncFnKindUpvars, obligation.cause.span); // When we don't know the closure kind (and therefore also the closure's upvars, // which are computed at the same time), we must delay the computation of the // generator's upvars. We do this using the `AsyncFnKindHelper`, which as a trait @@ -1798,7 +1800,8 @@ fn confirm_async_closure_candidate<'cx, 'tcx>( let term = match item_name { sym::CallOnceFuture | sym::CallRefFuture => sig.output(), sym::Output => { - let future_output_def_id = tcx.require_lang_item(LangItem::FutureOutput, None); + let future_output_def_id = + tcx.require_lang_item(LangItem::FutureOutput, obligation.cause.span); Ty::new_projection(tcx, future_output_def_id, [sig.output()]) } name => bug!("no such associated type: {name}"), @@ -1831,7 +1834,8 @@ fn confirm_async_closure_candidate<'cx, 'tcx>( let term = match item_name { sym::CallOnceFuture | sym::CallRefFuture => sig.output(), sym::Output => { - let future_output_def_id = tcx.require_lang_item(LangItem::FutureOutput, None); + let future_output_def_id = + tcx.require_lang_item(LangItem::FutureOutput, obligation.cause.span); Ty::new_projection(tcx, future_output_def_id, [sig.output()]) } name => bug!("no such associated type: {name}"), diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index c9169127e0b..7acf0f990d1 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -318,7 +318,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let make_freeze_obl = |ty| { let trait_ref = ty::TraitRef::new( tcx, - tcx.require_lang_item(LangItem::Freeze, None), + tcx.require_lang_item(LangItem::Freeze, obligation.cause.span), [ty::GenericArg::from(ty)], ); Obligation::with_depth( @@ -657,7 +657,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ); let tr = ty::TraitRef::new( self.tcx(), - self.tcx().require_lang_item(LangItem::Sized, Some(cause.span)), + self.tcx().require_lang_item(LangItem::Sized, cause.span), [output_ty], ); nested.push(Obligation::new(self.infcx.tcx, cause, obligation.param_env, tr)); @@ -877,14 +877,16 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { }); // We must additionally check that the return type impls `Future + Sized`. - let future_trait_def_id = tcx.require_lang_item(LangItem::Future, None); + let future_trait_def_id = + tcx.require_lang_item(LangItem::Future, obligation.cause.span); nested.push(obligation.with( tcx, sig.output().map_bound(|output_ty| { ty::TraitRef::new(tcx, future_trait_def_id, [output_ty]) }), )); - let sized_trait_def_id = tcx.require_lang_item(LangItem::Sized, None); + let sized_trait_def_id = + tcx.require_lang_item(LangItem::Sized, obligation.cause.span); nested.push(obligation.with( tcx, sig.output().map_bound(|output_ty| { @@ -906,13 +908,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { }); // We must additionally check that the return type impls `Future + Sized`. - let future_trait_def_id = tcx.require_lang_item(LangItem::Future, None); + let future_trait_def_id = + tcx.require_lang_item(LangItem::Future, obligation.cause.span); let placeholder_output_ty = self.infcx.enter_forall_and_leak_universe(sig.output()); nested.push(obligation.with( tcx, ty::TraitRef::new(tcx, future_trait_def_id, [placeholder_output_ty]), )); - let sized_trait_def_id = tcx.require_lang_item(LangItem::Sized, None); + let sized_trait_def_id = + tcx.require_lang_item(LangItem::Sized, obligation.cause.span); nested.push(obligation.with( tcx, sig.output().map_bound(|output_ty| { @@ -946,10 +950,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation.param_env, ty::TraitRef::new( self.tcx(), - self.tcx().require_lang_item( - LangItem::AsyncFnKindHelper, - Some(obligation.cause.span), - ), + self.tcx() + .require_lang_item(LangItem::AsyncFnKindHelper, obligation.cause.span), [kind_ty, Ty::from_closure_kind(self.tcx(), goal_kind)], ), )); @@ -1165,7 +1167,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // We can only make objects from sized types. let tr = ty::TraitRef::new( tcx, - tcx.require_lang_item(LangItem::Sized, Some(obligation.cause.span)), + tcx.require_lang_item(LangItem::Sized, obligation.cause.span), [source], ); nested.push(predicate_to_obligation(tr.upcast(tcx))); @@ -1359,7 +1361,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { self_ty.map_bound(|ty| { ty::TraitRef::new( tcx, - tcx.require_lang_item(LangItem::Copy, Some(obligation.cause.span)), + tcx.require_lang_item(LangItem::Copy, obligation.cause.span), [ty], ) }), @@ -1411,7 +1413,7 @@ fn pointer_like_goal_for_rpitit<'tcx>( ty::Binder::bind_with_vars( ty::TraitRef::new( tcx, - tcx.require_lang_item(LangItem::PointerLike, Some(cause.span)), + tcx.require_lang_item(LangItem::PointerLike, cause.span), [Ty::new_projection_from_args(tcx, rpitit_item, args)], ), tcx.mk_bound_variable_kinds(&bound_vars), diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index 3018dad8e09..416865e861e 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -541,7 +541,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { let cause = self.cause(cause); let trait_ref = ty::TraitRef::new( self.tcx(), - self.tcx().require_lang_item(LangItem::Sized, Some(cause.span)), + self.tcx().require_lang_item(LangItem::Sized, cause.span), [subty], ); self.out.push(traits::Obligation::with_depth( @@ -895,7 +895,7 @@ impl<'a, 'tcx> TypeVisitor<TyCtxt<'tcx>> for WfPredicates<'a, 'tcx> { self.tcx(), self.tcx().require_lang_item( LangItem::BikeshedGuaranteedNoDrop, - Some(self.span), + self.span, ), [ty], ) diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs index 83d7416b03e..bb5187e4f5c 100644 --- a/compiler/rustc_ty_utils/src/abi.rs +++ b/compiler/rustc_ty_utils/src/abi.rs @@ -11,6 +11,7 @@ use rustc_middle::ty::layout::{ }; use rustc_middle::ty::{self, InstanceKind, Ty, TyCtxt}; use rustc_session::config::OptLevel; +use rustc_span::DUMMY_SP; use rustc_span::def_id::DefId; use rustc_target::callconv::{ AbiMap, ArgAbi, ArgAttribute, ArgAttributes, ArgExtension, FnAbi, PassMode, @@ -124,7 +125,7 @@ fn fn_sig_for_fn_abi<'tcx>( let env_ty = Ty::new_mut_ref(tcx, tcx.lifetimes.re_erased, ty); - let pin_did = tcx.require_lang_item(LangItem::Pin, None); + let pin_did = tcx.require_lang_item(LangItem::Pin, DUMMY_SP); let pin_adt_ref = tcx.adt_def(pin_did); let pin_args = tcx.mk_args(&[env_ty.into()]); let env_ty = match coroutine_kind { @@ -149,7 +150,7 @@ fn fn_sig_for_fn_abi<'tcx>( // The signature should be `Future::poll(_, &mut Context<'_>) -> Poll<Output>` assert_eq!(sig.yield_ty, tcx.types.unit); - let poll_did = tcx.require_lang_item(LangItem::Poll, None); + let poll_did = tcx.require_lang_item(LangItem::Poll, DUMMY_SP); let poll_adt_ref = tcx.adt_def(poll_did); let poll_args = tcx.mk_args(&[sig.return_ty.into()]); let ret_ty = Ty::new_adt(tcx, poll_adt_ref, poll_args); @@ -160,7 +161,7 @@ fn fn_sig_for_fn_abi<'tcx>( { if let ty::Adt(resume_ty_adt, _) = sig.resume_ty.kind() { let expected_adt = - tcx.adt_def(tcx.require_lang_item(LangItem::ResumeTy, None)); + tcx.adt_def(tcx.require_lang_item(LangItem::ResumeTy, DUMMY_SP)); assert_eq!(*resume_ty_adt, expected_adt); } else { panic!("expected `ResumeTy`, found `{:?}`", sig.resume_ty); @@ -172,7 +173,7 @@ fn fn_sig_for_fn_abi<'tcx>( } hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Gen, _) => { // The signature should be `Iterator::next(_) -> Option<Yield>` - let option_did = tcx.require_lang_item(LangItem::Option, None); + let option_did = tcx.require_lang_item(LangItem::Option, DUMMY_SP); let option_adt_ref = tcx.adt_def(option_did); let option_args = tcx.mk_args(&[sig.yield_ty.into()]); let ret_ty = Ty::new_adt(tcx, option_adt_ref, option_args); @@ -196,7 +197,7 @@ fn fn_sig_for_fn_abi<'tcx>( { if let ty::Adt(resume_ty_adt, _) = sig.resume_ty.kind() { let expected_adt = - tcx.adt_def(tcx.require_lang_item(LangItem::ResumeTy, None)); + tcx.adt_def(tcx.require_lang_item(LangItem::ResumeTy, DUMMY_SP)); assert_eq!(*resume_ty_adt, expected_adt); } else { panic!("expected `ResumeTy`, found `{:?}`", sig.resume_ty); @@ -208,7 +209,7 @@ fn fn_sig_for_fn_abi<'tcx>( } hir::CoroutineKind::Coroutine(_) => { // The signature should be `Coroutine::resume(_, Resume) -> CoroutineState<Yield, Return>` - let state_did = tcx.require_lang_item(LangItem::CoroutineState, None); + let state_did = tcx.require_lang_item(LangItem::CoroutineState, DUMMY_SP); let state_adt_ref = tcx.adt_def(state_did); let state_args = tcx.mk_args(&[sig.yield_ty.into(), sig.return_ty.into()]); let ret_ty = Ty::new_adt(tcx, state_adt_ref, state_args); diff --git a/compiler/rustc_ty_utils/src/common_traits.rs b/compiler/rustc_ty_utils/src/common_traits.rs index bb2c4172b08..7219f40710e 100644 --- a/compiler/rustc_ty_utils/src/common_traits.rs +++ b/compiler/rustc_ty_utils/src/common_traits.rs @@ -4,6 +4,7 @@ use rustc_hir::lang_items::LangItem; use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::query::Providers; use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_span::DUMMY_SP; use rustc_trait_selection::traits; fn is_copy_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::PseudoCanonicalInput<'tcx, Ty<'tcx>>) -> bool { @@ -42,7 +43,7 @@ fn is_item_raw<'tcx>( item: LangItem, ) -> bool { let (infcx, param_env) = tcx.infer_ctxt().build_with_typing_env(query.typing_env); - let trait_def_id = tcx.require_lang_item(item, None); + let trait_def_id = tcx.require_lang_item(item, DUMMY_SP); traits::type_known_to_meet_bound_modulo_regions(&infcx, param_env, query.value, trait_def_id) } diff --git a/compiler/rustc_ty_utils/src/structural_match.rs b/compiler/rustc_ty_utils/src/structural_match.rs index 0b4efab1d9c..e900264a76c 100644 --- a/compiler/rustc_ty_utils/src/structural_match.rs +++ b/compiler/rustc_ty_utils/src/structural_match.rs @@ -16,8 +16,7 @@ fn has_structural_eq_impl<'tcx>(tcx: TyCtxt<'tcx>, adt_ty: Ty<'tcx>) -> bool { let ocx = ObligationCtxt::new(infcx); // require `#[derive(PartialEq)]` - let structural_peq_def_id = - infcx.tcx.require_lang_item(LangItem::StructuralPeq, Some(cause.span)); + let structural_peq_def_id = infcx.tcx.require_lang_item(LangItem::StructuralPeq, cause.span); ocx.register_bound(cause.clone(), ty::ParamEnv::empty(), adt_ty, structural_peq_def_id); // We deliberately skip *reporting* fulfillment errors (via diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs index 330aaa25d13..e39fd6b947b 100644 --- a/compiler/rustc_ty_utils/src/ty.rs +++ b/compiler/rustc_ty_utils/src/ty.rs @@ -104,7 +104,7 @@ fn adt_sized_constraint<'tcx>( // perf hack: if there is a `constraint_ty: Sized` bound, then we know // that the type is sized and do not need to check it on the impl. - let sized_trait_def_id = tcx.require_lang_item(LangItem::Sized, None); + let sized_trait_def_id = tcx.require_lang_item(LangItem::Sized, DUMMY_SP); let predicates = tcx.predicates_of(def.did()).predicates; if predicates.iter().any(|(p, _)| { p.as_trait_clause().is_some_and(|trait_pred| { diff --git a/library/alloc/src/slice.rs b/library/alloc/src/slice.rs index b49b3f41a76..b4da56578c8 100644 --- a/library/alloc/src/slice.rs +++ b/library/alloc/src/slice.rs @@ -493,8 +493,6 @@ impl<T> [T] { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// assert_eq!([1, 2].repeat(3), vec![1, 2, 1, 2, 1, 2]); /// ``` diff --git a/library/alloc/src/str.rs b/library/alloc/src/str.rs index f1b1734b8b2..22cdd8ecde0 100644 --- a/library/alloc/src/str.rs +++ b/library/alloc/src/str.rs @@ -246,8 +246,6 @@ impl str { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// let s = "this is old"; /// @@ -303,8 +301,6 @@ impl str { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// let s = "foo foo 123 foo"; /// assert_eq!("new new 123 foo", s.replacen("foo", "new", 2)); diff --git a/library/core/src/fmt/num.rs b/library/core/src/fmt/num.rs index ba30518d70b..dd9c379b666 100644 --- a/library/core/src/fmt/num.rs +++ b/library/core/src/fmt/num.rs @@ -678,8 +678,8 @@ impl fmt::Display for i128 { /// It also has to handle 1 last item, as 10^40 > 2^128 > 10^39, whereas /// 10^20 > 2^64 > 10^19. fn fmt_u128(n: u128, is_nonnegative: bool, f: &mut fmt::Formatter<'_>) -> fmt::Result { - // 2^128 is about 3*10^38, so 39 gives an extra byte of space - let mut buf = [MaybeUninit::<u8>::uninit(); 39]; + const MAX_DEC_N: usize = u128::MAX.ilog(10) as usize + 1; + let mut buf = [MaybeUninit::<u8>::uninit(); MAX_DEC_N]; let mut curr = buf.len(); let (n, rem) = udiv_1e19(n); diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs index a279f002772..511807b409f 100644 --- a/library/core/src/num/nonzero.rs +++ b/library/core/src/num/nonzero.rs @@ -551,8 +551,6 @@ macro_rules! nonzero_integer { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// # use std::num::NonZero; /// # @@ -583,8 +581,6 @@ macro_rules! nonzero_integer { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// # use std::num::NonZero; /// # @@ -612,8 +608,6 @@ macro_rules! nonzero_integer { /// /// # Example /// - /// Basic usage: - /// /// ``` /// #![feature(isolate_most_least_significant_one)] /// @@ -644,8 +638,6 @@ macro_rules! nonzero_integer { /// /// # Example /// - /// Basic usage: - /// /// ``` /// #![feature(isolate_most_least_significant_one)] /// @@ -676,8 +668,6 @@ macro_rules! nonzero_integer { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// # use std::num::NonZero; /// # @@ -713,8 +703,6 @@ macro_rules! nonzero_integer { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// #![feature(nonzero_bitwise)] /// # use std::num::NonZero; @@ -746,8 +734,6 @@ macro_rules! nonzero_integer { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// #![feature(nonzero_bitwise)] /// # use std::num::NonZero; @@ -775,8 +761,6 @@ macro_rules! nonzero_integer { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// #![feature(nonzero_bitwise)] /// # use std::num::NonZero; @@ -805,8 +789,6 @@ macro_rules! nonzero_integer { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// #![feature(nonzero_bitwise)] /// # use std::num::NonZero; @@ -837,8 +819,6 @@ macro_rules! nonzero_integer { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// #![feature(nonzero_bitwise)] /// # use std::num::NonZero; @@ -872,8 +852,6 @@ macro_rules! nonzero_integer { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// #![feature(nonzero_bitwise)] /// # use std::num::NonZero; @@ -907,8 +885,6 @@ macro_rules! nonzero_integer { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// #![feature(nonzero_bitwise)] /// # use std::num::NonZero; @@ -942,8 +918,6 @@ macro_rules! nonzero_integer { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// #![feature(nonzero_bitwise)] /// # use std::num::NonZero; @@ -1635,8 +1609,6 @@ macro_rules! nonzero_integer_signedness_dependent_methods { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// # use std::num::NonZero; /// # @@ -1666,7 +1638,6 @@ macro_rules! nonzero_integer_signedness_dependent_methods { /// /// # Examples /// - /// Basic usage: /// ``` /// # use std::num::NonZero; /// # @@ -1699,8 +1670,6 @@ macro_rules! nonzero_integer_signedness_dependent_methods { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// # use std::num::NonZero; /// @@ -2138,8 +2107,6 @@ macro_rules! nonzero_integer_signedness_dependent_methods { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// # use std::num::NonZero; /// diff --git a/library/std/src/ffi/mod.rs b/library/std/src/ffi/mod.rs index 024cb71b915..f44e12d48ad 100644 --- a/library/std/src/ffi/mod.rs +++ b/library/std/src/ffi/mod.rs @@ -178,6 +178,8 @@ pub use core::ffi::{ c_char, c_double, c_float, c_int, c_long, c_longlong, c_schar, c_short, c_uchar, c_uint, c_ulong, c_ulonglong, c_ushort, }; +#[unstable(feature = "c_size_t", issue = "88345")] +pub use core::ffi::{c_ptrdiff_t, c_size_t, c_ssize_t}; #[doc(inline)] #[stable(feature = "cstr_from_bytes_until_nul", since = "1.69.0")] diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs index 711efc7d011..6cbf8301e01 100644 --- a/library/std/src/fs.rs +++ b/library/std/src/fs.rs @@ -1311,9 +1311,39 @@ impl Write for &File { } #[stable(feature = "rust1", since = "1.0.0")] impl Seek for &File { + /// Seek to an offset, in bytes in a file. + /// + /// See [`Seek::seek`] docs for more info. + /// + /// # Platform-specific behavior + /// + /// This function currently corresponds to the `lseek64` function on Unix + /// and the `SetFilePointerEx` function on Windows. Note that this [may + /// change in the future][changes]. + /// + /// [changes]: io#platform-specific-behavior fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> { self.inner.seek(pos) } + + /// Returns the length of this file (in bytes). + /// + /// See [`Seek::stream_len`] docs for more info. + /// + /// # Platform-specific behavior + /// + /// This function currently corresponds to the `statx` function on Linux + /// (with fallbacks) and the `GetFileSizeEx` function on Windows. Note that + /// this [may change in the future][changes]. + /// + /// [changes]: io#platform-specific-behavior + fn stream_len(&mut self) -> io::Result<u64> { + if let Some(result) = self.inner.size() { + return result; + } + io::stream_len_default(self) + } + fn stream_position(&mut self) -> io::Result<u64> { self.inner.tell() } @@ -1363,6 +1393,9 @@ impl Seek for File { fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> { (&*self).seek(pos) } + fn stream_len(&mut self) -> io::Result<u64> { + (&*self).stream_len() + } fn stream_position(&mut self) -> io::Result<u64> { (&*self).stream_position() } @@ -1412,6 +1445,9 @@ impl Seek for Arc<File> { fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> { (&**self).seek(pos) } + fn stream_len(&mut self) -> io::Result<u64> { + (&**self).stream_len() + } fn stream_position(&mut self) -> io::Result<u64> { (&**self).stream_position() } diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index 03f5f838311..20c82b64bcc 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -2028,7 +2028,7 @@ pub trait Seek { /// Returns the length of this stream (in bytes). /// - /// This method is implemented using up to three seek operations. If this + /// The default implementation uses up to three seek operations. If this /// method returns successfully, the seek position is unchanged (i.e. the /// position before calling this method is the same as afterwards). /// However, if this method returns an error, the seek position is @@ -2062,16 +2062,7 @@ pub trait Seek { /// ``` #[unstable(feature = "seek_stream_len", issue = "59359")] fn stream_len(&mut self) -> Result<u64> { - let old_pos = self.stream_position()?; - let len = self.seek(SeekFrom::End(0))?; - - // Avoid seeking a third time when we were already at the end of the - // stream. The branch is usually way cheaper than a seek operation. - if old_pos != len { - self.seek(SeekFrom::Start(old_pos))?; - } - - Ok(len) + stream_len_default(self) } /// Returns the current seek position from the start of the stream. @@ -2132,6 +2123,19 @@ pub trait Seek { } } +pub(crate) fn stream_len_default<T: Seek + ?Sized>(self_: &mut T) -> Result<u64> { + let old_pos = self_.stream_position()?; + let len = self_.seek(SeekFrom::End(0))?; + + // Avoid seeking a third time when we were already at the end of the + // stream. The branch is usually way cheaper than a seek operation. + if old_pos != len { + self_.seek(SeekFrom::Start(old_pos))?; + } + + Ok(len) +} + /// Enumeration of possible methods to seek within an I/O object. /// /// It is used by the [`Seek`] trait. diff --git a/library/std/src/keyword_docs.rs b/library/std/src/keyword_docs.rs index 79b25040ef6..1c55824ab90 100644 --- a/library/std/src/keyword_docs.rs +++ b/library/std/src/keyword_docs.rs @@ -1916,10 +1916,6 @@ mod type_keyword {} /// - and to declare that a programmer has checked that these contracts have been upheld (`unsafe /// {}` and `unsafe impl`, but also `unsafe fn` -- see below). /// -/// They are not mutually exclusive, as can be seen in `unsafe fn`: the body of an `unsafe fn` is, -/// by default, treated like an unsafe block. The `unsafe_op_in_unsafe_fn` lint can be enabled to -/// change that. -/// /// # Unsafe abilities /// /// **No matter what, Safe Rust can't cause Undefined Behavior**. This is @@ -1961,13 +1957,6 @@ mod type_keyword {} /// - `unsafe impl`: the contract necessary to implement the trait has been /// checked by the programmer and is guaranteed to be respected. /// -/// By default, `unsafe fn` also acts like an `unsafe {}` block -/// around the code inside the function. This means it is not just a signal to -/// the caller, but also promises that the preconditions for the operations -/// inside the function are upheld. Mixing these two meanings can be confusing, so the -/// `unsafe_op_in_unsafe_fn` lint can be enabled to warn against that and require explicit unsafe -/// blocks even inside `unsafe fn`. -/// /// See the [Rustonomicon] and the [Reference] for more information. /// /// # Examples @@ -2109,6 +2098,7 @@ mod type_keyword {} /// impl Indexable for i32 { /// const LEN: usize = 1; /// +/// /// See `Indexable` for the safety contract. /// unsafe fn idx_unchecked(&self, idx: usize) -> i32 { /// debug_assert_eq!(idx, 0); /// *self @@ -2120,6 +2110,7 @@ mod type_keyword {} /// impl Indexable for [i32; 42] { /// const LEN: usize = 42; /// +/// /// See `Indexable` for the safety contract. /// unsafe fn idx_unchecked(&self, idx: usize) -> i32 { /// // SAFETY: As per this trait's documentation, the caller ensures /// // that `idx < 42`. @@ -2132,6 +2123,7 @@ mod type_keyword {} /// impl Indexable for ! { /// const LEN: usize = 0; /// +/// /// See `Indexable` for the safety contract. /// unsafe fn idx_unchecked(&self, idx: usize) -> i32 { /// // SAFETY: As per this trait's documentation, the caller ensures /// // that `idx < 0`, which is impossible, so this is dead code. @@ -2153,11 +2145,14 @@ mod type_keyword {} /// contract of `idx_unchecked`. Implementing `Indexable` is safe because when writing /// `idx_unchecked`, we don't have to worry: our *callers* need to discharge a proof obligation /// (like `use_indexable` does), but the *implementation* of `get_unchecked` has no proof obligation -/// to contend with. Of course, the implementation of `Indexable` may choose to call other unsafe -/// operations, and then it needs an `unsafe` *block* to indicate it discharged the proof -/// obligations of its callees. (We enabled `unsafe_op_in_unsafe_fn`, so the body of `idx_unchecked` -/// is not implicitly an unsafe block.) For that purpose it can make use of the contract that all -/// its callers must uphold -- the fact that `idx < LEN`. +/// to contend with. Of course, the implementation may choose to call other unsafe operations, and +/// then it needs an `unsafe` *block* to indicate it discharged the proof obligations of its +/// callees. For that purpose it can make use of the contract that all its callers must uphold -- +/// the fact that `idx < LEN`. +/// +/// Note that unlike normal `unsafe fn`, an `unsafe fn` in a trait implementation does not get to +/// just pick an arbitrary safety contract! It *has* to use the safety contract defined by the trait +/// (or one with weaker preconditions). /// /// Formally speaking, an `unsafe fn` in a trait is a function with *preconditions* that go beyond /// those encoded by the argument types (such as `idx < LEN`), whereas an `unsafe trait` can declare diff --git a/library/std/src/sys/fs/hermit.rs b/library/std/src/sys/fs/hermit.rs index a9774bef9e3..175d919c289 100644 --- a/library/std/src/sys/fs/hermit.rs +++ b/library/std/src/sys/fs/hermit.rs @@ -422,6 +422,10 @@ impl File { self.0.seek(pos) } + pub fn size(&self) -> Option<io::Result<u64>> { + None + } + pub fn tell(&self) -> io::Result<u64> { self.0.tell() } diff --git a/library/std/src/sys/fs/solid.rs b/library/std/src/sys/fs/solid.rs index 3bfb39bac95..808a9582911 100644 --- a/library/std/src/sys/fs/solid.rs +++ b/library/std/src/sys/fs/solid.rs @@ -459,6 +459,10 @@ impl File { self.tell() } + pub fn size(&self) -> Option<io::Result<u64>> { + None + } + pub fn tell(&self) -> io::Result<u64> { unsafe { let mut out_offset = MaybeUninit::uninit(); diff --git a/library/std/src/sys/fs/uefi.rs b/library/std/src/sys/fs/uefi.rs index 416c90b98b6..5763d7862f5 100644 --- a/library/std/src/sys/fs/uefi.rs +++ b/library/std/src/sys/fs/uefi.rs @@ -280,6 +280,10 @@ impl File { self.0 } + pub fn size(&self) -> Option<io::Result<u64>> { + self.0 + } + pub fn tell(&self) -> io::Result<u64> { self.0 } diff --git a/library/std/src/sys/fs/unix.rs b/library/std/src/sys/fs/unix.rs index a3e520fdeef..dc278274f00 100644 --- a/library/std/src/sys/fs/unix.rs +++ b/library/std/src/sys/fs/unix.rs @@ -1464,6 +1464,15 @@ impl File { Ok(n as u64) } + pub fn size(&self) -> Option<io::Result<u64>> { + match self.file_attr().map(|attr| attr.size()) { + // Fall back to default implementation if the returned size is 0, + // we might be in a proc mount. + Ok(0) => None, + result => Some(result), + } + } + pub fn tell(&self) -> io::Result<u64> { self.seek(SeekFrom::Current(0)) } diff --git a/library/std/src/sys/fs/unsupported.rs b/library/std/src/sys/fs/unsupported.rs index 0ff9533c047..efaddb51b37 100644 --- a/library/std/src/sys/fs/unsupported.rs +++ b/library/std/src/sys/fs/unsupported.rs @@ -259,6 +259,10 @@ impl File { self.0 } + pub fn size(&self) -> Option<io::Result<u64>> { + self.0 + } + pub fn tell(&self) -> io::Result<u64> { self.0 } diff --git a/library/std/src/sys/fs/wasi.rs b/library/std/src/sys/fs/wasi.rs index ebfc7377a2e..b65d86de12a 100644 --- a/library/std/src/sys/fs/wasi.rs +++ b/library/std/src/sys/fs/wasi.rs @@ -516,6 +516,10 @@ impl File { self.fd.seek(pos) } + pub fn size(&self) -> Option<io::Result<u64>> { + None + } + pub fn tell(&self) -> io::Result<u64> { self.fd.tell() } diff --git a/library/std/src/sys/fs/windows.rs b/library/std/src/sys/fs/windows.rs index d01a572ac73..a95709b4891 100644 --- a/library/std/src/sys/fs/windows.rs +++ b/library/std/src/sys/fs/windows.rs @@ -616,6 +616,14 @@ impl File { Ok(newpos as u64) } + pub fn size(&self) -> Option<io::Result<u64>> { + let mut result = 0; + Some( + cvt(unsafe { c::GetFileSizeEx(self.handle.as_raw_handle(), &mut result) }) + .map(|_| result as u64), + ) + } + pub fn tell(&self) -> io::Result<u64> { self.seek(SeekFrom::Current(0)) } diff --git a/library/std/src/sys/pal/unix/os.rs b/library/std/src/sys/pal/unix/os.rs index 48609030aed..850bdfdf5b5 100644 --- a/library/std/src/sys/pal/unix/os.rs +++ b/library/std/src/sys/pal/unix/os.rs @@ -282,7 +282,7 @@ pub fn current_exe() -> io::Result<PathBuf> { return getcwd().map(|cwd| cwd.join(path))?.canonicalize(); } // Search PATH to infer current_exe. - if let Some(p) = getenv(OsStr::from_bytes("PATH".as_bytes())) { + if let Some(p) = env::var_os(OsStr::from_bytes("PATH".as_bytes())) { for search_path in split_paths(&p) { let pb = search_path.join(&path); if pb.is_file() diff --git a/library/std/src/sys/pal/windows/c/bindings.txt b/library/std/src/sys/pal/windows/c/bindings.txt index d5fbb453c6f..a99c474c763 100644 --- a/library/std/src/sys/pal/windows/c/bindings.txt +++ b/library/std/src/sys/pal/windows/c/bindings.txt @@ -2156,6 +2156,7 @@ GetExitCodeProcess GetFileAttributesW GetFileInformationByHandle GetFileInformationByHandleEx +GetFileSizeEx GetFileType GETFINALPATHNAMEBYHANDLE_FLAGS GetFinalPathNameByHandleW diff --git a/library/std/src/sys/pal/windows/c/windows_sys.rs b/library/std/src/sys/pal/windows/c/windows_sys.rs index eb2914b8644..95bf8040229 100644 --- a/library/std/src/sys/pal/windows/c/windows_sys.rs +++ b/library/std/src/sys/pal/windows/c/windows_sys.rs @@ -44,6 +44,7 @@ windows_targets::link!("kernel32.dll" "system" fn GetExitCodeProcess(hprocess : windows_targets::link!("kernel32.dll" "system" fn GetFileAttributesW(lpfilename : PCWSTR) -> u32); windows_targets::link!("kernel32.dll" "system" fn GetFileInformationByHandle(hfile : HANDLE, lpfileinformation : *mut BY_HANDLE_FILE_INFORMATION) -> BOOL); windows_targets::link!("kernel32.dll" "system" fn GetFileInformationByHandleEx(hfile : HANDLE, fileinformationclass : FILE_INFO_BY_HANDLE_CLASS, lpfileinformation : *mut core::ffi::c_void, dwbuffersize : u32) -> BOOL); +windows_targets::link!("kernel32.dll" "system" fn GetFileSizeEx(hfile : HANDLE, lpfilesize : *mut i64) -> BOOL); windows_targets::link!("kernel32.dll" "system" fn GetFileType(hfile : HANDLE) -> FILE_TYPE); windows_targets::link!("kernel32.dll" "system" fn GetFinalPathNameByHandleW(hfile : HANDLE, lpszfilepath : PWSTR, cchfilepath : u32, dwflags : GETFINALPATHNAMEBYHANDLE_FLAGS) -> u32); windows_targets::link!("kernel32.dll" "system" fn GetFullPathNameW(lpfilename : PCWSTR, nbufferlength : u32, lpbuffer : PWSTR, lpfilepart : *mut PWSTR) -> u32); diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index d52b9dd1f3a..5ecce31fe15 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -668,7 +668,8 @@ pub fn std_cargo(builder: &Builder<'_>, target: TargetSelection, stage: u32, car // Enable frame pointers by default for the library. Note that they are still controlled by a // separate setting for the compiler. - cargo.rustflag("-Cforce-frame-pointers=yes"); + cargo.rustflag("-Zunstable-options"); + cargo.rustflag("-Cforce-frame-pointers=non-leaf"); let html_root = format!("-Zcrate-attr=doc(html_root_url=\"{}/\")", builder.doc_rust_lang_org_channel(),); diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index 00e46875908..491f55ccaf3 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -1,36 +1,56 @@ -//! Serialized configuration of a build. +//! This module defines the central `Config` struct, which aggregates all components +//! of the bootstrap configuration into a single unit. //! -//! This module implements parsing `bootstrap.toml` configuration files to tweak -//! how the build runs. +//! It serves as the primary public interface for accessing the bootstrap configuration. +//! The module coordinates the overall configuration parsing process using logic from `parsing.rs` +//! and provides top-level methods such as `Config::parse()` for initialization, as well as +//! utility methods for querying and manipulating the complete configuration state. +//! +//! Additionally, this module contains the core logic for parsing, validating, and inferring +//! the final `Config` from various raw inputs. +//! +//! It manages the process of reading command-line arguments, environment variables, +//! and the `bootstrap.toml` file—merging them, applying defaults, and performing +//! cross-component validation. The main `parse_inner` function and its supporting +//! helpers reside here, transforming raw `Toml` data into the structured `Config` type. use std::cell::Cell; use std::collections::{BTreeSet, HashMap, HashSet}; -use std::fmt::{self, Display}; -use std::hash::Hash; use std::io::IsTerminal; use std::path::{Path, PathBuf, absolute}; -use std::process::Command; use std::str::FromStr; -use std::sync::{Arc, Mutex, OnceLock}; +use std::sync::{Arc, Mutex}; use std::{cmp, env, fs}; use build_helper::ci::CiEnv; use build_helper::exit; use build_helper::git::{GitConfig, PathFreshness, check_path_modifications, output_result}; -use serde::{Deserialize, Deserializer}; -use serde_derive::Deserialize; +use serde::Deserialize; +#[cfg(feature = "tracing")] +use tracing::{instrument, span}; #[cfg(feature = "tracing")] use tracing::{instrument, span}; -use crate::core::build_steps::compile::CODEGEN_BACKEND_PREFIX; use crate::core::build_steps::llvm; use crate::core::build_steps::llvm::LLVM_INVALIDATION_PATHS; pub use crate::core::config::flags::Subcommand; -use crate::core::config::flags::{Color, Flags, Warnings}; +use crate::core::config::flags::{Color, Flags}; +use crate::core::config::target_selection::TargetSelectionList; +use crate::core::config::toml::TomlConfig; +use crate::core::config::toml::build::Build; +use crate::core::config::toml::change_id::ChangeId; +use crate::core::config::toml::rust::{ + LldMode, RustOptimize, check_incompatible_options_for_ci_rustc, +}; +use crate::core::config::toml::target::Target; +use crate::core::config::{ + DebuginfoLevel, DryRun, GccCiMode, LlvmLibunwind, Merge, ReplaceOpt, RustcLto, SplitDebuginfo, + StringOrBool, set, threads_from_config, +}; use crate::core::download::is_download_ci_available; -use crate::utils::cache::{INTERNER, Interned}; -use crate::utils::channel::{self, GitInfo}; -use crate::utils::helpers::{self, exe, output, t}; +use crate::utils::channel; +use crate::utils::helpers::exe; +use crate::{Command, GitInfo, OnceLock, TargetSelection, check_ci_llvm, helpers, output, t}; /// Each path in this list is considered "allowed" in the `download-rustc="if-unchanged"` logic. /// This means they can be modified and changes to these paths should never trigger a compiler build @@ -44,7 +64,7 @@ use crate::utils::helpers::{self, exe, output, t}; /// For example, "src/bootstrap" should never be included in this list as it plays a crucial role in the /// final output/compiler, which can be significantly affected by changes made to the bootstrap sources. #[rustfmt::skip] // We don't want rustfmt to oneline this list -pub(crate) const RUSTC_IF_UNCHANGED_ALLOWED_PATHS: &[&str] = &[ +pub const RUSTC_IF_UNCHANGED_ALLOWED_PATHS: &[&str] = &[ ":!library", ":!src/tools", ":!src/librustdoc", @@ -53,138 +73,6 @@ pub(crate) const RUSTC_IF_UNCHANGED_ALLOWED_PATHS: &[&str] = &[ ":!triagebot.toml", ]; -macro_rules! check_ci_llvm { - ($name:expr) => { - assert!( - $name.is_none(), - "setting {} is incompatible with download-ci-llvm.", - stringify!($name).replace("_", "-") - ); - }; -} - -/// This file is embedded in the overlay directory of the tarball sources. It is -/// useful in scenarios where developers want to see how the tarball sources were -/// generated. -/// -/// We also use this file to compare the host's bootstrap.toml against the CI rustc builder -/// configuration to detect any incompatible options. -pub(crate) const BUILDER_CONFIG_FILENAME: &str = "builder-config"; - -#[derive(Clone, Default)] -pub enum DryRun { - /// This isn't a dry run. - #[default] - Disabled, - /// This is a dry run enabled by bootstrap itself, so it can verify that no work is done. - SelfCheck, - /// This is a dry run enabled by the `--dry-run` flag. - UserSelected, -} - -#[derive(Copy, Clone, Default, Debug, Eq, PartialEq)] -pub enum DebuginfoLevel { - #[default] - None, - LineDirectivesOnly, - LineTablesOnly, - Limited, - Full, -} - -// NOTE: can't derive(Deserialize) because the intermediate trip through toml::Value only -// deserializes i64, and derive() only generates visit_u64 -impl<'de> Deserialize<'de> for DebuginfoLevel { - fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> - where - D: Deserializer<'de>, - { - use serde::de::Error; - - Ok(match Deserialize::deserialize(deserializer)? { - StringOrInt::String(s) if s == "none" => DebuginfoLevel::None, - StringOrInt::Int(0) => DebuginfoLevel::None, - StringOrInt::String(s) if s == "line-directives-only" => { - DebuginfoLevel::LineDirectivesOnly - } - StringOrInt::String(s) if s == "line-tables-only" => DebuginfoLevel::LineTablesOnly, - StringOrInt::String(s) if s == "limited" => DebuginfoLevel::Limited, - StringOrInt::Int(1) => DebuginfoLevel::Limited, - StringOrInt::String(s) if s == "full" => DebuginfoLevel::Full, - StringOrInt::Int(2) => DebuginfoLevel::Full, - StringOrInt::Int(n) => { - let other = serde::de::Unexpected::Signed(n); - return Err(D::Error::invalid_value(other, &"expected 0, 1, or 2")); - } - StringOrInt::String(s) => { - let other = serde::de::Unexpected::Str(&s); - return Err(D::Error::invalid_value( - other, - &"expected none, line-tables-only, limited, or full", - )); - } - }) - } -} - -/// Suitable for passing to `-C debuginfo` -impl Display for DebuginfoLevel { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - use DebuginfoLevel::*; - f.write_str(match self { - None => "0", - LineDirectivesOnly => "line-directives-only", - LineTablesOnly => "line-tables-only", - Limited => "1", - Full => "2", - }) - } -} - -/// LLD in bootstrap works like this: -/// - Self-contained lld: use `rust-lld` from the compiler's sysroot -/// - External: use an external `lld` binary -/// -/// It is configured depending on the target: -/// 1) Everything except MSVC -/// - Self-contained: `-Clinker-flavor=gnu-lld-cc -Clink-self-contained=+linker` -/// - External: `-Clinker-flavor=gnu-lld-cc` -/// 2) MSVC -/// - Self-contained: `-Clinker=<path to rust-lld>` -/// - External: `-Clinker=lld` -#[derive(Copy, Clone, Default, Debug, PartialEq)] -pub enum LldMode { - /// Do not use LLD - #[default] - Unused, - /// Use `rust-lld` from the compiler's sysroot - SelfContained, - /// Use an externally provided `lld` binary. - /// Note that the linker name cannot be overridden, the binary has to be named `lld` and it has - /// to be in $PATH. - External, -} - -impl LldMode { - pub fn is_used(&self) -> bool { - match self { - LldMode::SelfContained | LldMode::External => true, - LldMode::Unused => false, - } - } -} - -/// Determines how will GCC be provided. -#[derive(Default, Clone)] -pub enum GccCiMode { - /// Build GCC from the local `src/gcc` submodule. - #[default] - BuildLocally, - /// Try to download GCC from CI. - /// If it is not available on CI, it will be built locally instead. - DownloadFromCi, -} - /// Global configuration for the entire build and/or bootstrap. /// /// This structure is parsed from `bootstrap.toml`, and some of the fields are inferred from `git` or build-time parameters. @@ -250,9 +138,6 @@ pub struct Config { pub free_args: Vec<String>, /// `None` if we shouldn't download CI compiler artifacts, or the commit to download if we should. - #[cfg(not(test))] - download_rustc_commit: Option<String>, - #[cfg(test)] pub download_rustc_commit: Option<String>, pub deny_warnings: bool, @@ -269,10 +154,6 @@ pub struct Config { pub llvm_release_debuginfo: bool, pub llvm_static_stdcpp: bool, pub llvm_libzstd: bool, - /// `None` if `llvm_from_ci` is true and we haven't yet downloaded llvm. - #[cfg(not(test))] - llvm_link_shared: Cell<Option<bool>>, - #[cfg(test)] pub llvm_link_shared: Cell<Option<bool>>, pub llvm_clang_cl: Option<String>, pub llvm_targets: Option<String>, @@ -345,9 +226,6 @@ pub struct Config { pub hosts: Vec<TargetSelection>, pub targets: Vec<TargetSelection>, pub local_rebuild: bool, - #[cfg(not(test))] - jemalloc: bool, - #[cfg(test)] pub jemalloc: bool, pub control_flow_guard: bool, pub ehcont_guard: bool, @@ -430,932 +308,6 @@ pub struct Config { pub skip_std_check_if_no_download_rustc: bool, } -#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)] -pub enum LlvmLibunwind { - #[default] - No, - InTree, - System, -} - -impl FromStr for LlvmLibunwind { - type Err = String; - - fn from_str(value: &str) -> Result<Self, Self::Err> { - match value { - "no" => Ok(Self::No), - "in-tree" => Ok(Self::InTree), - "system" => Ok(Self::System), - invalid => Err(format!("Invalid value '{invalid}' for rust.llvm-libunwind config.")), - } - } -} - -#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub enum SplitDebuginfo { - Packed, - Unpacked, - #[default] - Off, -} - -impl std::str::FromStr for SplitDebuginfo { - type Err = (); - - fn from_str(s: &str) -> Result<Self, Self::Err> { - match s { - "packed" => Ok(SplitDebuginfo::Packed), - "unpacked" => Ok(SplitDebuginfo::Unpacked), - "off" => Ok(SplitDebuginfo::Off), - _ => Err(()), - } - } -} - -impl SplitDebuginfo { - /// Returns the default `-Csplit-debuginfo` value for the current target. See the comment for - /// `rust.split-debuginfo` in `bootstrap.example.toml`. - fn default_for_platform(target: TargetSelection) -> Self { - if target.contains("apple") { - SplitDebuginfo::Unpacked - } else if target.is_windows() { - SplitDebuginfo::Packed - } else { - SplitDebuginfo::Off - } - } -} - -/// LTO mode used for compiling rustc itself. -#[derive(Default, Clone, PartialEq, Debug)] -pub enum RustcLto { - Off, - #[default] - ThinLocal, - Thin, - Fat, -} - -impl std::str::FromStr for RustcLto { - type Err = String; - - fn from_str(s: &str) -> Result<Self, Self::Err> { - match s { - "thin-local" => Ok(RustcLto::ThinLocal), - "thin" => Ok(RustcLto::Thin), - "fat" => Ok(RustcLto::Fat), - "off" => Ok(RustcLto::Off), - _ => Err(format!("Invalid value for rustc LTO: {s}")), - } - } -} - -#[derive(Copy, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] -// N.B.: This type is used everywhere, and the entire codebase relies on it being Copy. -// Making !Copy is highly nontrivial! -pub struct TargetSelection { - pub triple: Interned<String>, - file: Option<Interned<String>>, - synthetic: bool, -} - -/// Newtype over `Vec<TargetSelection>` so we can implement custom parsing logic -#[derive(Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] -pub struct TargetSelectionList(Vec<TargetSelection>); - -pub fn target_selection_list(s: &str) -> Result<TargetSelectionList, String> { - Ok(TargetSelectionList( - s.split(',').filter(|s| !s.is_empty()).map(TargetSelection::from_user).collect(), - )) -} - -impl TargetSelection { - pub fn from_user(selection: &str) -> Self { - let path = Path::new(selection); - - let (triple, file) = if path.exists() { - let triple = path - .file_stem() - .expect("Target specification file has no file stem") - .to_str() - .expect("Target specification file stem is not UTF-8"); - - (triple, Some(selection)) - } else { - (selection, None) - }; - - let triple = INTERNER.intern_str(triple); - let file = file.map(|f| INTERNER.intern_str(f)); - - Self { triple, file, synthetic: false } - } - - pub fn create_synthetic(triple: &str, file: &str) -> Self { - Self { - triple: INTERNER.intern_str(triple), - file: Some(INTERNER.intern_str(file)), - synthetic: true, - } - } - - pub fn rustc_target_arg(&self) -> &str { - self.file.as_ref().unwrap_or(&self.triple) - } - - pub fn contains(&self, needle: &str) -> bool { - self.triple.contains(needle) - } - - pub fn starts_with(&self, needle: &str) -> bool { - self.triple.starts_with(needle) - } - - pub fn ends_with(&self, needle: &str) -> bool { - self.triple.ends_with(needle) - } - - // See src/bootstrap/synthetic_targets.rs - pub fn is_synthetic(&self) -> bool { - self.synthetic - } - - pub fn is_msvc(&self) -> bool { - self.contains("msvc") - } - - pub fn is_windows(&self) -> bool { - self.contains("windows") - } - - pub fn is_windows_gnu(&self) -> bool { - self.ends_with("windows-gnu") - } - - pub fn is_cygwin(&self) -> bool { - self.is_windows() && - // ref. https://cygwin.com/pipermail/cygwin/2022-February/250802.html - env::var("OSTYPE").is_ok_and(|v| v.to_lowercase().contains("cygwin")) - } - - pub fn needs_crt_begin_end(&self) -> bool { - self.contains("musl") && !self.contains("unikraft") - } - - /// Path to the file defining the custom target, if any. - pub fn filepath(&self) -> Option<&Path> { - self.file.as_ref().map(Path::new) - } -} - -impl fmt::Display for TargetSelection { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}", self.triple)?; - if let Some(file) = self.file { - write!(f, "({file})")?; - } - Ok(()) - } -} - -impl fmt::Debug for TargetSelection { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{self}") - } -} - -impl PartialEq<&str> for TargetSelection { - fn eq(&self, other: &&str) -> bool { - self.triple == *other - } -} - -// Targets are often used as directory names throughout bootstrap. -// This impl makes it more ergonomics to use them as such. -impl AsRef<Path> for TargetSelection { - fn as_ref(&self) -> &Path { - self.triple.as_ref() - } -} - -/// Per-target configuration stored in the global configuration structure. -#[derive(Debug, Default, Clone, PartialEq, Eq)] -pub struct Target { - /// Some(path to llvm-config) if using an external LLVM. - pub llvm_config: Option<PathBuf>, - pub llvm_has_rust_patches: Option<bool>, - /// Some(path to FileCheck) if one was specified. - pub llvm_filecheck: Option<PathBuf>, - pub llvm_libunwind: Option<LlvmLibunwind>, - pub cc: Option<PathBuf>, - pub cxx: Option<PathBuf>, - pub ar: Option<PathBuf>, - pub ranlib: Option<PathBuf>, - pub default_linker: Option<PathBuf>, - pub linker: Option<PathBuf>, - pub split_debuginfo: Option<SplitDebuginfo>, - pub sanitizers: Option<bool>, - pub profiler: Option<StringOrBool>, - pub rpath: Option<bool>, - pub crt_static: Option<bool>, - pub musl_root: Option<PathBuf>, - pub musl_libdir: Option<PathBuf>, - pub wasi_root: Option<PathBuf>, - pub qemu_rootfs: Option<PathBuf>, - pub runner: Option<String>, - pub no_std: bool, - pub codegen_backends: Option<Vec<String>>, - pub optimized_compiler_builtins: Option<bool>, - pub jemalloc: Option<bool>, -} - -impl Target { - pub fn from_triple(triple: &str) -> Self { - let mut target: Self = Default::default(); - if triple.contains("-none") || triple.contains("nvptx") || triple.contains("switch") { - target.no_std = true; - } - if triple.contains("emscripten") { - target.runner = Some("node".into()); - } - target - } -} -/// Structure of the `bootstrap.toml` file that configuration is read from. -/// -/// This structure uses `Decodable` to automatically decode a TOML configuration -/// file into this format, and then this is traversed and written into the above -/// `Config` structure. -#[derive(Deserialize, Default)] -#[serde(deny_unknown_fields, rename_all = "kebab-case")] -pub(crate) struct TomlConfig { - #[serde(flatten)] - change_id: ChangeIdWrapper, - build: Option<Build>, - install: Option<Install>, - llvm: Option<Llvm>, - gcc: Option<Gcc>, - rust: Option<Rust>, - target: Option<HashMap<String, TomlTarget>>, - dist: Option<Dist>, - profile: Option<String>, - include: Option<Vec<PathBuf>>, -} - -/// This enum is used for deserializing change IDs from TOML, allowing both numeric values and the string `"ignore"`. -#[derive(Clone, Debug, PartialEq)] -pub enum ChangeId { - Ignore, - Id(usize), -} - -/// Since we use `#[serde(deny_unknown_fields)]` on `TomlConfig`, we need a wrapper type -/// for the "change-id" field to parse it even if other fields are invalid. This ensures -/// that if deserialization fails due to other fields, we can still provide the changelogs -/// to allow developers to potentially find the reason for the failure in the logs.. -#[derive(Deserialize, Default)] -pub(crate) struct ChangeIdWrapper { - #[serde(alias = "change-id", default, deserialize_with = "deserialize_change_id")] - pub(crate) inner: Option<ChangeId>, -} - -fn deserialize_change_id<'de, D: Deserializer<'de>>( - deserializer: D, -) -> Result<Option<ChangeId>, D::Error> { - let value = toml::Value::deserialize(deserializer)?; - Ok(match value { - toml::Value::String(s) if s == "ignore" => Some(ChangeId::Ignore), - toml::Value::Integer(i) => Some(ChangeId::Id(i as usize)), - _ => { - return Err(serde::de::Error::custom( - "expected \"ignore\" or an integer for change-id", - )); - } - }) -} - -/// Describes how to handle conflicts in merging two [`TomlConfig`] -#[derive(Copy, Clone, Debug)] -enum ReplaceOpt { - /// Silently ignore a duplicated value - IgnoreDuplicate, - /// Override the current value, even if it's `Some` - Override, - /// Exit with an error on duplicate values - ErrorOnDuplicate, -} - -trait Merge { - fn merge( - &mut self, - parent_config_path: Option<PathBuf>, - included_extensions: &mut HashSet<PathBuf>, - other: Self, - replace: ReplaceOpt, - ); -} - -impl Merge for TomlConfig { - fn merge( - &mut self, - parent_config_path: Option<PathBuf>, - included_extensions: &mut HashSet<PathBuf>, - TomlConfig { build, install, llvm, gcc, rust, dist, target, profile, change_id, include }: Self, - replace: ReplaceOpt, - ) { - fn do_merge<T: Merge>(x: &mut Option<T>, y: Option<T>, replace: ReplaceOpt) { - if let Some(new) = y { - if let Some(original) = x { - original.merge(None, &mut Default::default(), new, replace); - } else { - *x = Some(new); - } - } - } - - self.change_id.inner.merge(None, &mut Default::default(), change_id.inner, replace); - self.profile.merge(None, &mut Default::default(), profile, replace); - - do_merge(&mut self.build, build, replace); - do_merge(&mut self.install, install, replace); - do_merge(&mut self.llvm, llvm, replace); - do_merge(&mut self.gcc, gcc, replace); - do_merge(&mut self.rust, rust, replace); - do_merge(&mut self.dist, dist, replace); - - match (self.target.as_mut(), target) { - (_, None) => {} - (None, Some(target)) => self.target = Some(target), - (Some(original_target), Some(new_target)) => { - for (triple, new) in new_target { - if let Some(original) = original_target.get_mut(&triple) { - original.merge(None, &mut Default::default(), new, replace); - } else { - original_target.insert(triple, new); - } - } - } - } - - let parent_dir = parent_config_path - .as_ref() - .and_then(|p| p.parent().map(ToOwned::to_owned)) - .unwrap_or_default(); - - // `include` handled later since we ignore duplicates using `ReplaceOpt::IgnoreDuplicate` to - // keep the upper-level configuration to take precedence. - for include_path in include.clone().unwrap_or_default().iter().rev() { - let include_path = parent_dir.join(include_path); - let include_path = include_path.canonicalize().unwrap_or_else(|e| { - eprintln!("ERROR: Failed to canonicalize '{}' path: {e}", include_path.display()); - exit!(2); - }); - - let included_toml = Config::get_toml_inner(&include_path).unwrap_or_else(|e| { - eprintln!("ERROR: Failed to parse '{}': {e}", include_path.display()); - exit!(2); - }); - - assert!( - included_extensions.insert(include_path.clone()), - "Cyclic inclusion detected: '{}' is being included again before its previous inclusion was fully processed.", - include_path.display() - ); - - self.merge( - Some(include_path.clone()), - included_extensions, - included_toml, - // Ensures that parent configuration always takes precedence - // over child configurations. - ReplaceOpt::IgnoreDuplicate, - ); - - included_extensions.remove(&include_path); - } - } -} - -// We are using a decl macro instead of a derive proc macro here to reduce the compile time of bootstrap. -macro_rules! define_config { - ($(#[$attr:meta])* struct $name:ident { - $($field:ident: Option<$field_ty:ty> = $field_key:literal,)* - }) => { - $(#[$attr])* - struct $name { - $($field: Option<$field_ty>,)* - } - - impl Merge for $name { - fn merge( - &mut self, - _parent_config_path: Option<PathBuf>, - _included_extensions: &mut HashSet<PathBuf>, - other: Self, - replace: ReplaceOpt - ) { - $( - match replace { - ReplaceOpt::IgnoreDuplicate => { - if self.$field.is_none() { - self.$field = other.$field; - } - }, - ReplaceOpt::Override => { - if other.$field.is_some() { - self.$field = other.$field; - } - } - ReplaceOpt::ErrorOnDuplicate => { - if other.$field.is_some() { - if self.$field.is_some() { - if cfg!(test) { - panic!("overriding existing option") - } else { - eprintln!("overriding existing option: `{}`", stringify!($field)); - exit!(2); - } - } else { - self.$field = other.$field; - } - } - } - } - )* - } - } - - // The following is a trimmed version of what serde_derive generates. All parts not relevant - // for toml deserialization have been removed. This reduces the binary size and improves - // compile time of bootstrap. - impl<'de> Deserialize<'de> for $name { - fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> - where - D: Deserializer<'de>, - { - struct Field; - impl<'de> serde::de::Visitor<'de> for Field { - type Value = $name; - fn expecting(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.write_str(concat!("struct ", stringify!($name))) - } - - #[inline] - fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error> - where - A: serde::de::MapAccess<'de>, - { - $(let mut $field: Option<$field_ty> = None;)* - while let Some(key) = - match serde::de::MapAccess::next_key::<String>(&mut map) { - Ok(val) => val, - Err(err) => { - return Err(err); - } - } - { - match &*key { - $($field_key => { - if $field.is_some() { - return Err(<A::Error as serde::de::Error>::duplicate_field( - $field_key, - )); - } - $field = match serde::de::MapAccess::next_value::<$field_ty>( - &mut map, - ) { - Ok(val) => Some(val), - Err(err) => { - return Err(err); - } - }; - })* - key => { - return Err(serde::de::Error::unknown_field(key, FIELDS)); - } - } - } - Ok($name { $($field),* }) - } - } - const FIELDS: &'static [&'static str] = &[ - $($field_key,)* - ]; - Deserializer::deserialize_struct( - deserializer, - stringify!($name), - FIELDS, - Field, - ) - } - } - } -} - -impl<T> Merge for Option<T> { - fn merge( - &mut self, - _parent_config_path: Option<PathBuf>, - _included_extensions: &mut HashSet<PathBuf>, - other: Self, - replace: ReplaceOpt, - ) { - match replace { - ReplaceOpt::IgnoreDuplicate => { - if self.is_none() { - *self = other; - } - } - ReplaceOpt::Override => { - if other.is_some() { - *self = other; - } - } - ReplaceOpt::ErrorOnDuplicate => { - if other.is_some() { - if self.is_some() { - if cfg!(test) { - panic!("overriding existing option") - } else { - eprintln!("overriding existing option"); - exit!(2); - } - } else { - *self = other; - } - } - } - } - } -} - -define_config! { - /// TOML representation of various global build decisions. - #[derive(Default)] - struct Build { - build: Option<String> = "build", - description: Option<String> = "description", - host: Option<Vec<String>> = "host", - target: Option<Vec<String>> = "target", - build_dir: Option<String> = "build-dir", - cargo: Option<PathBuf> = "cargo", - rustc: Option<PathBuf> = "rustc", - rustfmt: Option<PathBuf> = "rustfmt", - cargo_clippy: Option<PathBuf> = "cargo-clippy", - docs: Option<bool> = "docs", - compiler_docs: Option<bool> = "compiler-docs", - library_docs_private_items: Option<bool> = "library-docs-private-items", - docs_minification: Option<bool> = "docs-minification", - submodules: Option<bool> = "submodules", - gdb: Option<String> = "gdb", - lldb: Option<String> = "lldb", - nodejs: Option<String> = "nodejs", - npm: Option<String> = "npm", - python: Option<String> = "python", - reuse: Option<String> = "reuse", - locked_deps: Option<bool> = "locked-deps", - vendor: Option<bool> = "vendor", - full_bootstrap: Option<bool> = "full-bootstrap", - bootstrap_cache_path: Option<PathBuf> = "bootstrap-cache-path", - extended: Option<bool> = "extended", - tools: Option<HashSet<String>> = "tools", - verbose: Option<usize> = "verbose", - sanitizers: Option<bool> = "sanitizers", - profiler: Option<bool> = "profiler", - cargo_native_static: Option<bool> = "cargo-native-static", - low_priority: Option<bool> = "low-priority", - configure_args: Option<Vec<String>> = "configure-args", - local_rebuild: Option<bool> = "local-rebuild", - print_step_timings: Option<bool> = "print-step-timings", - print_step_rusage: Option<bool> = "print-step-rusage", - check_stage: Option<u32> = "check-stage", - doc_stage: Option<u32> = "doc-stage", - build_stage: Option<u32> = "build-stage", - test_stage: Option<u32> = "test-stage", - install_stage: Option<u32> = "install-stage", - dist_stage: Option<u32> = "dist-stage", - bench_stage: Option<u32> = "bench-stage", - patch_binaries_for_nix: Option<bool> = "patch-binaries-for-nix", - // NOTE: only parsed by bootstrap.py, `--feature build-metrics` enables metrics unconditionally - metrics: Option<bool> = "metrics", - android_ndk: Option<PathBuf> = "android-ndk", - optimized_compiler_builtins: Option<bool> = "optimized-compiler-builtins", - jobs: Option<u32> = "jobs", - compiletest_diff_tool: Option<String> = "compiletest-diff-tool", - compiletest_use_stage0_libtest: Option<bool> = "compiletest-use-stage0-libtest", - ccache: Option<StringOrBool> = "ccache", - exclude: Option<Vec<PathBuf>> = "exclude", - } -} - -define_config! { - /// TOML representation of various global install decisions. - struct Install { - prefix: Option<String> = "prefix", - sysconfdir: Option<String> = "sysconfdir", - docdir: Option<String> = "docdir", - bindir: Option<String> = "bindir", - libdir: Option<String> = "libdir", - mandir: Option<String> = "mandir", - datadir: Option<String> = "datadir", - } -} - -define_config! { - /// TOML representation of how the LLVM build is configured. - struct Llvm { - optimize: Option<bool> = "optimize", - thin_lto: Option<bool> = "thin-lto", - release_debuginfo: Option<bool> = "release-debuginfo", - assertions: Option<bool> = "assertions", - tests: Option<bool> = "tests", - enzyme: Option<bool> = "enzyme", - plugins: Option<bool> = "plugins", - // FIXME: Remove this field at Q2 2025, it has been replaced by build.ccache - ccache: Option<StringOrBool> = "ccache", - static_libstdcpp: Option<bool> = "static-libstdcpp", - libzstd: Option<bool> = "libzstd", - ninja: Option<bool> = "ninja", - targets: Option<String> = "targets", - experimental_targets: Option<String> = "experimental-targets", - link_jobs: Option<u32> = "link-jobs", - link_shared: Option<bool> = "link-shared", - version_suffix: Option<String> = "version-suffix", - clang_cl: Option<String> = "clang-cl", - cflags: Option<String> = "cflags", - cxxflags: Option<String> = "cxxflags", - ldflags: Option<String> = "ldflags", - use_libcxx: Option<bool> = "use-libcxx", - use_linker: Option<String> = "use-linker", - allow_old_toolchain: Option<bool> = "allow-old-toolchain", - offload: Option<bool> = "offload", - polly: Option<bool> = "polly", - clang: Option<bool> = "clang", - enable_warnings: Option<bool> = "enable-warnings", - download_ci_llvm: Option<StringOrBool> = "download-ci-llvm", - build_config: Option<HashMap<String, String>> = "build-config", - } -} - -define_config! { - /// TOML representation of how the GCC build is configured. - struct Gcc { - download_ci_gcc: Option<bool> = "download-ci-gcc", - } -} - -define_config! { - struct Dist { - sign_folder: Option<String> = "sign-folder", - upload_addr: Option<String> = "upload-addr", - src_tarball: Option<bool> = "src-tarball", - compression_formats: Option<Vec<String>> = "compression-formats", - compression_profile: Option<String> = "compression-profile", - include_mingw_linker: Option<bool> = "include-mingw-linker", - vendor: Option<bool> = "vendor", - } -} - -#[derive(Clone, Debug, Deserialize, PartialEq, Eq)] -#[serde(untagged)] -pub enum StringOrBool { - String(String), - Bool(bool), -} - -impl Default for StringOrBool { - fn default() -> StringOrBool { - StringOrBool::Bool(false) - } -} - -impl StringOrBool { - fn is_string_or_true(&self) -> bool { - matches!(self, Self::String(_) | Self::Bool(true)) - } -} - -#[derive(Clone, Debug, PartialEq, Eq)] -pub enum RustOptimize { - String(String), - Int(u8), - Bool(bool), -} - -impl Default for RustOptimize { - fn default() -> RustOptimize { - RustOptimize::Bool(false) - } -} - -impl<'de> Deserialize<'de> for RustOptimize { - fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> - where - D: Deserializer<'de>, - { - deserializer.deserialize_any(OptimizeVisitor) - } -} - -struct OptimizeVisitor; - -impl serde::de::Visitor<'_> for OptimizeVisitor { - type Value = RustOptimize; - - fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - formatter.write_str(r#"one of: 0, 1, 2, 3, "s", "z", true, false"#) - } - - fn visit_str<E>(self, value: &str) -> Result<Self::Value, E> - where - E: serde::de::Error, - { - if matches!(value, "s" | "z") { - Ok(RustOptimize::String(value.to_string())) - } else { - Err(serde::de::Error::custom(format_optimize_error_msg(value))) - } - } - - fn visit_i64<E>(self, value: i64) -> Result<Self::Value, E> - where - E: serde::de::Error, - { - if matches!(value, 0..=3) { - Ok(RustOptimize::Int(value as u8)) - } else { - Err(serde::de::Error::custom(format_optimize_error_msg(value))) - } - } - - fn visit_bool<E>(self, value: bool) -> Result<Self::Value, E> - where - E: serde::de::Error, - { - Ok(RustOptimize::Bool(value)) - } -} - -fn format_optimize_error_msg(v: impl std::fmt::Display) -> String { - format!( - r#"unrecognized option for rust optimize: "{v}", expected one of 0, 1, 2, 3, "s", "z", true, false"# - ) -} - -impl RustOptimize { - pub(crate) fn is_release(&self) -> bool { - match &self { - RustOptimize::Bool(true) | RustOptimize::String(_) => true, - RustOptimize::Int(i) => *i > 0, - RustOptimize::Bool(false) => false, - } - } - - pub(crate) fn get_opt_level(&self) -> Option<String> { - match &self { - RustOptimize::String(s) => Some(s.clone()), - RustOptimize::Int(i) => Some(i.to_string()), - RustOptimize::Bool(_) => None, - } - } -} - -#[derive(Deserialize)] -#[serde(untagged)] -enum StringOrInt { - String(String), - Int(i64), -} - -impl<'de> Deserialize<'de> for LldMode { - fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> - where - D: Deserializer<'de>, - { - struct LldModeVisitor; - - impl serde::de::Visitor<'_> for LldModeVisitor { - type Value = LldMode; - - fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { - formatter.write_str("one of true, 'self-contained' or 'external'") - } - - fn visit_bool<E>(self, v: bool) -> Result<Self::Value, E> - where - E: serde::de::Error, - { - Ok(if v { LldMode::External } else { LldMode::Unused }) - } - - fn visit_str<E>(self, v: &str) -> Result<Self::Value, E> - where - E: serde::de::Error, - { - match v { - "external" => Ok(LldMode::External), - "self-contained" => Ok(LldMode::SelfContained), - _ => Err(E::custom(format!("unknown mode {v}"))), - } - } - } - - deserializer.deserialize_any(LldModeVisitor) - } -} - -define_config! { - /// TOML representation of how the Rust build is configured. - struct Rust { - optimize: Option<RustOptimize> = "optimize", - debug: Option<bool> = "debug", - codegen_units: Option<u32> = "codegen-units", - codegen_units_std: Option<u32> = "codegen-units-std", - rustc_debug_assertions: Option<bool> = "debug-assertions", - randomize_layout: Option<bool> = "randomize-layout", - std_debug_assertions: Option<bool> = "debug-assertions-std", - tools_debug_assertions: Option<bool> = "debug-assertions-tools", - overflow_checks: Option<bool> = "overflow-checks", - overflow_checks_std: Option<bool> = "overflow-checks-std", - debug_logging: Option<bool> = "debug-logging", - debuginfo_level: Option<DebuginfoLevel> = "debuginfo-level", - debuginfo_level_rustc: Option<DebuginfoLevel> = "debuginfo-level-rustc", - debuginfo_level_std: Option<DebuginfoLevel> = "debuginfo-level-std", - debuginfo_level_tools: Option<DebuginfoLevel> = "debuginfo-level-tools", - debuginfo_level_tests: Option<DebuginfoLevel> = "debuginfo-level-tests", - backtrace: Option<bool> = "backtrace", - incremental: Option<bool> = "incremental", - default_linker: Option<String> = "default-linker", - channel: Option<String> = "channel", - // FIXME: Remove this field at Q2 2025, it has been replaced by build.description - description: Option<String> = "description", - musl_root: Option<String> = "musl-root", - rpath: Option<bool> = "rpath", - strip: Option<bool> = "strip", - frame_pointers: Option<bool> = "frame-pointers", - stack_protector: Option<String> = "stack-protector", - verbose_tests: Option<bool> = "verbose-tests", - optimize_tests: Option<bool> = "optimize-tests", - codegen_tests: Option<bool> = "codegen-tests", - omit_git_hash: Option<bool> = "omit-git-hash", - dist_src: Option<bool> = "dist-src", - save_toolstates: Option<String> = "save-toolstates", - codegen_backends: Option<Vec<String>> = "codegen-backends", - llvm_bitcode_linker: Option<bool> = "llvm-bitcode-linker", - lld: Option<bool> = "lld", - lld_mode: Option<LldMode> = "use-lld", - llvm_tools: Option<bool> = "llvm-tools", - deny_warnings: Option<bool> = "deny-warnings", - backtrace_on_ice: Option<bool> = "backtrace-on-ice", - verify_llvm_ir: Option<bool> = "verify-llvm-ir", - thin_lto_import_instr_limit: Option<u32> = "thin-lto-import-instr-limit", - remap_debuginfo: Option<bool> = "remap-debuginfo", - jemalloc: Option<bool> = "jemalloc", - test_compare_mode: Option<bool> = "test-compare-mode", - llvm_libunwind: Option<String> = "llvm-libunwind", - control_flow_guard: Option<bool> = "control-flow-guard", - ehcont_guard: Option<bool> = "ehcont-guard", - new_symbol_mangling: Option<bool> = "new-symbol-mangling", - profile_generate: Option<String> = "profile-generate", - profile_use: Option<String> = "profile-use", - // ignored; this is set from an env var set by bootstrap.py - download_rustc: Option<StringOrBool> = "download-rustc", - lto: Option<String> = "lto", - validate_mir_opts: Option<u32> = "validate-mir-opts", - std_features: Option<BTreeSet<String>> = "std-features", - } -} - -define_config! { - /// TOML representation of how each build target is configured. - struct TomlTarget { - cc: Option<String> = "cc", - cxx: Option<String> = "cxx", - ar: Option<String> = "ar", - ranlib: Option<String> = "ranlib", - default_linker: Option<PathBuf> = "default-linker", - linker: Option<String> = "linker", - split_debuginfo: Option<String> = "split-debuginfo", - llvm_config: Option<String> = "llvm-config", - llvm_has_rust_patches: Option<bool> = "llvm-has-rust-patches", - llvm_filecheck: Option<String> = "llvm-filecheck", - llvm_libunwind: Option<String> = "llvm-libunwind", - sanitizers: Option<bool> = "sanitizers", - profiler: Option<StringOrBool> = "profiler", - rpath: Option<bool> = "rpath", - crt_static: Option<bool> = "crt-static", - musl_root: Option<String> = "musl-root", - musl_libdir: Option<String> = "musl-libdir", - wasi_root: Option<String> = "wasi-root", - qemu_rootfs: Option<String> = "qemu-rootfs", - no_std: Option<bool> = "no-std", - codegen_backends: Option<Vec<String>> = "codegen-backends", - runner: Option<String> = "runner", - optimized_compiler_builtins: Option<bool> = "optimized-compiler-builtins", - jemalloc: Option<bool> = "jemalloc", - } -} - impl Config { #[cfg_attr( feature = "tracing", @@ -1410,47 +362,6 @@ impl Config { } } - pub(crate) fn get_builder_toml(&self, build_name: &str) -> Result<TomlConfig, toml::de::Error> { - if self.dry_run() { - return Ok(TomlConfig::default()); - } - - let builder_config_path = - self.out.join(self.build.triple).join(build_name).join(BUILDER_CONFIG_FILENAME); - Self::get_toml(&builder_config_path) - } - - pub(crate) fn get_toml(file: &Path) -> Result<TomlConfig, toml::de::Error> { - #[cfg(test)] - return Ok(TomlConfig::default()); - - #[cfg(not(test))] - Self::get_toml_inner(file) - } - - fn get_toml_inner(file: &Path) -> Result<TomlConfig, toml::de::Error> { - let contents = - t!(fs::read_to_string(file), format!("config file {} not found", file.display())); - // Deserialize to Value and then TomlConfig to prevent the Deserialize impl of - // TomlConfig and sub types to be monomorphized 5x by toml. - toml::from_str(&contents) - .and_then(|table: toml::Value| TomlConfig::deserialize(table)) - .inspect_err(|_| { - if let Ok(ChangeIdWrapper { inner: Some(ChangeId::Id(id)) }) = - toml::from_str::<toml::Value>(&contents) - .and_then(|table: toml::Value| ChangeIdWrapper::deserialize(table)) - { - let changes = crate::find_recent_config_change_ids(id); - if !changes.is_empty() { - println!( - "WARNING: There have been changes to x.py since you last updated:\n{}", - crate::human_readable_changes(changes) - ); - } - } - }) - } - #[cfg_attr( feature = "tracing", instrument(target = "CONFIG_HANDLING", level = "trace", name = "Config::parse", skip_all) @@ -1912,42 +823,11 @@ impl Config { // Verbose flag is a good default for `rust.verbose-tests`. config.verbose_tests = config.is_verbose(); - if let Some(install) = toml.install { - let Install { prefix, sysconfdir, docdir, bindir, libdir, mandir, datadir } = install; - config.prefix = prefix.map(PathBuf::from); - config.sysconfdir = sysconfdir.map(PathBuf::from); - config.datadir = datadir.map(PathBuf::from); - config.docdir = docdir.map(PathBuf::from); - set(&mut config.bindir, bindir.map(PathBuf::from)); - config.libdir = libdir.map(PathBuf::from); - config.mandir = mandir.map(PathBuf::from); - } + config.apply_install_config(toml.install); config.llvm_assertions = toml.llvm.as_ref().is_some_and(|llvm| llvm.assertions.unwrap_or(false)); - // Store off these values as options because if they're not provided - // we'll infer default values for them later - let mut llvm_tests = None; - let mut llvm_enzyme = None; - let mut llvm_offload = None; - let mut llvm_plugins = None; - let mut debug = None; - let mut rustc_debug_assertions = None; - let mut std_debug_assertions = None; - let mut tools_debug_assertions = None; - let mut overflow_checks = None; - let mut overflow_checks_std = None; - let mut debug_logging = None; - let mut debuginfo_level = None; - let mut debuginfo_level_rustc = None; - let mut debuginfo_level_std = None; - let mut debuginfo_level_tools = None; - let mut debuginfo_level_tests = None; - let mut optimize = None; - let mut lld_enabled = None; - let mut std_features = None; - let file_content = t!(fs::read_to_string(config.src.join("src/ci/channel"))); let ci_channel = file_content.trim_end(); @@ -1991,190 +871,10 @@ impl Config { config.channel = ci_channel.into(); } - if let Some(rust) = toml.rust { - let Rust { - optimize: optimize_toml, - debug: debug_toml, - codegen_units, - codegen_units_std, - rustc_debug_assertions: rustc_debug_assertions_toml, - std_debug_assertions: std_debug_assertions_toml, - tools_debug_assertions: tools_debug_assertions_toml, - overflow_checks: overflow_checks_toml, - overflow_checks_std: overflow_checks_std_toml, - debug_logging: debug_logging_toml, - debuginfo_level: debuginfo_level_toml, - debuginfo_level_rustc: debuginfo_level_rustc_toml, - debuginfo_level_std: debuginfo_level_std_toml, - debuginfo_level_tools: debuginfo_level_tools_toml, - debuginfo_level_tests: debuginfo_level_tests_toml, - backtrace, - incremental, - randomize_layout, - default_linker, - channel: _, // already handled above - description: rust_description, - musl_root, - rpath, - verbose_tests, - optimize_tests, - codegen_tests, - omit_git_hash: _, // already handled above - dist_src, - save_toolstates, - codegen_backends, - lld: lld_enabled_toml, - llvm_tools, - llvm_bitcode_linker, - deny_warnings, - backtrace_on_ice, - verify_llvm_ir, - thin_lto_import_instr_limit, - remap_debuginfo, - jemalloc, - test_compare_mode, - llvm_libunwind, - control_flow_guard, - ehcont_guard, - new_symbol_mangling, - profile_generate, - profile_use, - download_rustc, - lto, - validate_mir_opts, - frame_pointers, - stack_protector, - strip, - lld_mode, - std_features: std_features_toml, - } = rust; - - // FIXME(#133381): alt rustc builds currently do *not* have rustc debug assertions - // enabled. We should not download a CI alt rustc if we need rustc to have debug - // assertions (e.g. for crashes test suite). This can be changed once something like - // [Enable debug assertions on alt - // builds](https://github.com/rust-lang/rust/pull/131077) lands. - // - // Note that `rust.debug = true` currently implies `rust.debug-assertions = true`! - // - // This relies also on the fact that the global default for `download-rustc` will be - // `false` if it's not explicitly set. - let debug_assertions_requested = matches!(rustc_debug_assertions_toml, Some(true)) - || (matches!(debug_toml, Some(true)) - && !matches!(rustc_debug_assertions_toml, Some(false))); - - if debug_assertions_requested - && let Some(ref opt) = download_rustc - && opt.is_string_or_true() - { - eprintln!( - "WARN: currently no CI rustc builds have rustc debug assertions \ - enabled. Please either set `rust.debug-assertions` to `false` if you \ - want to use download CI rustc or set `rust.download-rustc` to `false`." - ); - } + config.rust_profile_use = flags.rust_profile_use; + config.rust_profile_generate = flags.rust_profile_generate; - config.download_rustc_commit = config.download_ci_rustc_commit( - download_rustc, - debug_assertions_requested, - config.llvm_assertions, - ); - - debug = debug_toml; - rustc_debug_assertions = rustc_debug_assertions_toml; - std_debug_assertions = std_debug_assertions_toml; - tools_debug_assertions = tools_debug_assertions_toml; - overflow_checks = overflow_checks_toml; - overflow_checks_std = overflow_checks_std_toml; - debug_logging = debug_logging_toml; - debuginfo_level = debuginfo_level_toml; - debuginfo_level_rustc = debuginfo_level_rustc_toml; - debuginfo_level_std = debuginfo_level_std_toml; - debuginfo_level_tools = debuginfo_level_tools_toml; - debuginfo_level_tests = debuginfo_level_tests_toml; - lld_enabled = lld_enabled_toml; - std_features = std_features_toml; - - optimize = optimize_toml; - config.rust_new_symbol_mangling = new_symbol_mangling; - set(&mut config.rust_optimize_tests, optimize_tests); - set(&mut config.codegen_tests, codegen_tests); - set(&mut config.rust_rpath, rpath); - set(&mut config.rust_strip, strip); - set(&mut config.rust_frame_pointers, frame_pointers); - config.rust_stack_protector = stack_protector; - set(&mut config.jemalloc, jemalloc); - set(&mut config.test_compare_mode, test_compare_mode); - set(&mut config.backtrace, backtrace); - if rust_description.is_some() { - eprintln!( - "Warning: rust.description is deprecated. Use build.description instead." - ); - } - description = description.or(rust_description); - set(&mut config.rust_dist_src, dist_src); - set(&mut config.verbose_tests, verbose_tests); - // in the case "false" is set explicitly, do not overwrite the command line args - if let Some(true) = incremental { - config.incremental = true; - } - set(&mut config.lld_mode, lld_mode); - set(&mut config.llvm_bitcode_linker_enabled, llvm_bitcode_linker); - - config.rust_randomize_layout = randomize_layout.unwrap_or_default(); - config.llvm_tools_enabled = llvm_tools.unwrap_or(true); - - config.llvm_enzyme = - llvm_enzyme.unwrap_or(config.channel == "dev" || config.channel == "nightly"); - config.rustc_default_linker = default_linker; - config.musl_root = musl_root.map(PathBuf::from); - config.save_toolstates = save_toolstates.map(PathBuf::from); - set( - &mut config.deny_warnings, - match flags.warnings { - Warnings::Deny => Some(true), - Warnings::Warn => Some(false), - Warnings::Default => deny_warnings, - }, - ); - set(&mut config.backtrace_on_ice, backtrace_on_ice); - set(&mut config.rust_verify_llvm_ir, verify_llvm_ir); - config.rust_thin_lto_import_instr_limit = thin_lto_import_instr_limit; - set(&mut config.rust_remap_debuginfo, remap_debuginfo); - set(&mut config.control_flow_guard, control_flow_guard); - set(&mut config.ehcont_guard, ehcont_guard); - config.llvm_libunwind_default = - llvm_libunwind.map(|v| v.parse().expect("failed to parse rust.llvm-libunwind")); - - if let Some(ref backends) = codegen_backends { - let available_backends = ["llvm", "cranelift", "gcc"]; - - config.rust_codegen_backends = backends.iter().map(|s| { - if let Some(backend) = s.strip_prefix(CODEGEN_BACKEND_PREFIX) { - if available_backends.contains(&backend) { - panic!("Invalid value '{s}' for 'rust.codegen-backends'. Instead, please use '{backend}'."); - } else { - println!("HELP: '{s}' for 'rust.codegen-backends' might fail. \ - Codegen backends are mostly defined without the '{CODEGEN_BACKEND_PREFIX}' prefix. \ - In this case, it would be referred to as '{backend}'."); - } - } - - s.clone() - }).collect(); - } - - config.rust_codegen_units = codegen_units.map(threads_from_config); - config.rust_codegen_units_std = codegen_units_std.map(threads_from_config); - config.rust_profile_use = flags.rust_profile_use.or(profile_use); - config.rust_profile_generate = flags.rust_profile_generate.or(profile_generate); - config.rust_lto = - lto.as_deref().map(|value| RustcLto::from_str(value).unwrap()).unwrap_or_default(); - config.rust_validate_mir_opts = validate_mir_opts; - } else { - config.rust_profile_use = flags.rust_profile_use; - config.rust_profile_generate = flags.rust_profile_generate; - } + config.apply_rust_config(toml.rust, flags.warnings, &mut description); config.reproducible_artifacts = flags.reproducible_artifact; config.description = description; @@ -2195,206 +895,11 @@ impl Config { config.channel = channel; } - if let Some(llvm) = toml.llvm { - let Llvm { - optimize: optimize_toml, - thin_lto, - release_debuginfo, - assertions: _, - tests, - enzyme, - plugins, - ccache: llvm_ccache, - static_libstdcpp, - libzstd, - ninja, - targets, - experimental_targets, - link_jobs, - link_shared, - version_suffix, - clang_cl, - cflags, - cxxflags, - ldflags, - use_libcxx, - use_linker, - allow_old_toolchain, - offload, - polly, - clang, - enable_warnings, - download_ci_llvm, - build_config, - } = llvm; - if llvm_ccache.is_some() { - eprintln!("Warning: llvm.ccache is deprecated. Use build.ccache instead."); - } - - ccache = ccache.or(llvm_ccache); - set(&mut config.ninja_in_file, ninja); - llvm_tests = tests; - llvm_enzyme = enzyme; - llvm_offload = offload; - llvm_plugins = plugins; - set(&mut config.llvm_optimize, optimize_toml); - set(&mut config.llvm_thin_lto, thin_lto); - set(&mut config.llvm_release_debuginfo, release_debuginfo); - set(&mut config.llvm_static_stdcpp, static_libstdcpp); - set(&mut config.llvm_libzstd, libzstd); - if let Some(v) = link_shared { - config.llvm_link_shared.set(Some(v)); - } - config.llvm_targets.clone_from(&targets); - config.llvm_experimental_targets.clone_from(&experimental_targets); - config.llvm_link_jobs = link_jobs; - config.llvm_version_suffix.clone_from(&version_suffix); - config.llvm_clang_cl.clone_from(&clang_cl); - - config.llvm_cflags.clone_from(&cflags); - config.llvm_cxxflags.clone_from(&cxxflags); - config.llvm_ldflags.clone_from(&ldflags); - set(&mut config.llvm_use_libcxx, use_libcxx); - config.llvm_use_linker.clone_from(&use_linker); - config.llvm_allow_old_toolchain = allow_old_toolchain.unwrap_or(false); - config.llvm_offload = offload.unwrap_or(false); - config.llvm_polly = polly.unwrap_or(false); - config.llvm_clang = clang.unwrap_or(false); - config.llvm_enable_warnings = enable_warnings.unwrap_or(false); - config.llvm_build_config = build_config.clone().unwrap_or(Default::default()); - - config.llvm_from_ci = - config.parse_download_ci_llvm(download_ci_llvm, config.llvm_assertions); - - if config.llvm_from_ci { - let warn = |option: &str| { - println!( - "WARNING: `{option}` will only be used on `compiler/rustc_llvm` build, not for the LLVM build." - ); - println!( - "HELP: To use `{option}` for LLVM builds, set `download-ci-llvm` option to false." - ); - }; - - if static_libstdcpp.is_some() { - warn("static-libstdcpp"); - } - - if link_shared.is_some() { - warn("link-shared"); - } - - // FIXME(#129153): instead of all the ad-hoc `download-ci-llvm` checks that follow, - // use the `builder-config` present in tarballs since #128822 to compare the local - // config to the ones used to build the LLVM artifacts on CI, and only notify users - // if they've chosen a different value. - - if libzstd.is_some() { - println!( - "WARNING: when using `download-ci-llvm`, the local `llvm.libzstd` option, \ - like almost all `llvm.*` options, will be ignored and set by the LLVM CI \ - artifacts builder config." - ); - println!( - "HELP: To use `llvm.libzstd` for LLVM/LLD builds, set `download-ci-llvm` option to false." - ); - } - } - - if !config.llvm_from_ci && config.llvm_thin_lto && link_shared.is_none() { - // If we're building with ThinLTO on, by default we want to link - // to LLVM shared, to avoid re-doing ThinLTO (which happens in - // the link step) with each stage. - config.llvm_link_shared.set(Some(true)); - } - } else { - config.llvm_from_ci = config.parse_download_ci_llvm(None, false); - } - - if let Some(gcc) = toml.gcc { - config.gcc_ci_mode = match gcc.download_ci_gcc { - Some(value) => match value { - true => GccCiMode::DownloadFromCi, - false => GccCiMode::BuildLocally, - }, - None => GccCiMode::default(), - }; - } + config.apply_llvm_config(toml.llvm, &mut ccache); - if let Some(t) = toml.target { - for (triple, cfg) in t { - let mut target = Target::from_triple(&triple); + config.apply_gcc_config(toml.gcc); - if let Some(ref s) = cfg.llvm_config { - if config.download_rustc_commit.is_some() && triple == *config.build.triple { - panic!( - "setting llvm_config for the host is incompatible with download-rustc" - ); - } - target.llvm_config = Some(config.src.join(s)); - } - if let Some(patches) = cfg.llvm_has_rust_patches { - assert!( - config.submodules == Some(false) || cfg.llvm_config.is_some(), - "use of `llvm-has-rust-patches` is restricted to cases where either submodules are disabled or llvm-config been provided" - ); - target.llvm_has_rust_patches = Some(patches); - } - if let Some(ref s) = cfg.llvm_filecheck { - target.llvm_filecheck = Some(config.src.join(s)); - } - target.llvm_libunwind = cfg.llvm_libunwind.as_ref().map(|v| { - v.parse().unwrap_or_else(|_| { - panic!("failed to parse target.{triple}.llvm-libunwind") - }) - }); - if let Some(s) = cfg.no_std { - target.no_std = s; - } - target.cc = cfg.cc.map(PathBuf::from); - target.cxx = cfg.cxx.map(PathBuf::from); - target.ar = cfg.ar.map(PathBuf::from); - target.ranlib = cfg.ranlib.map(PathBuf::from); - target.linker = cfg.linker.map(PathBuf::from); - target.crt_static = cfg.crt_static; - target.musl_root = cfg.musl_root.map(PathBuf::from); - target.musl_libdir = cfg.musl_libdir.map(PathBuf::from); - target.wasi_root = cfg.wasi_root.map(PathBuf::from); - target.qemu_rootfs = cfg.qemu_rootfs.map(PathBuf::from); - target.runner = cfg.runner; - target.sanitizers = cfg.sanitizers; - target.profiler = cfg.profiler; - target.rpath = cfg.rpath; - target.optimized_compiler_builtins = cfg.optimized_compiler_builtins; - target.jemalloc = cfg.jemalloc; - - if let Some(ref backends) = cfg.codegen_backends { - let available_backends = ["llvm", "cranelift", "gcc"]; - - target.codegen_backends = Some(backends.iter().map(|s| { - if let Some(backend) = s.strip_prefix(CODEGEN_BACKEND_PREFIX) { - if available_backends.contains(&backend) { - panic!("Invalid value '{s}' for 'target.{triple}.codegen-backends'. Instead, please use '{backend}'."); - } else { - println!("HELP: '{s}' for 'target.{triple}.codegen-backends' might fail. \ - Codegen backends are mostly defined without the '{CODEGEN_BACKEND_PREFIX}' prefix. \ - In this case, it would be referred to as '{backend}'."); - } - } - - s.clone() - }).collect()); - } - - target.split_debuginfo = cfg.split_debuginfo.as_ref().map(|v| { - v.parse().unwrap_or_else(|_| { - panic!("invalid value for target.{triple}.split-debuginfo") - }) - }); - - config.target_config.insert(TargetSelection::from_user(&triple), target); - } - } + config.apply_target_config(toml.target); match ccache { Some(StringOrBool::String(ref s)) => config.ccache = Some(s.to_string()), @@ -2418,69 +923,11 @@ impl Config { build_target.llvm_filecheck = Some(ci_llvm_bin.join(exe("FileCheck", config.build))); } - if let Some(dist) = toml.dist { - let Dist { - sign_folder, - upload_addr, - src_tarball, - compression_formats, - compression_profile, - include_mingw_linker, - vendor, - } = dist; - config.dist_sign_folder = sign_folder.map(PathBuf::from); - config.dist_upload_addr = upload_addr; - config.dist_compression_formats = compression_formats; - set(&mut config.dist_compression_profile, compression_profile); - set(&mut config.rust_dist_src, src_tarball); - set(&mut config.dist_include_mingw_linker, include_mingw_linker); - config.dist_vendor = vendor.unwrap_or_else(|| { - // If we're building from git or tarball sources, enable it by default. - config.rust_info.is_managed_git_subrepository() - || config.rust_info.is_from_tarball() - }); - } + config.apply_dist_config(toml.dist); config.initial_rustfmt = if let Some(r) = rustfmt { Some(r) } else { config.maybe_download_rustfmt() }; - // Now that we've reached the end of our configuration, infer the - // default values for all options that we haven't otherwise stored yet. - - config.llvm_tests = llvm_tests.unwrap_or(false); - config.llvm_enzyme = llvm_enzyme.unwrap_or(false); - config.llvm_offload = llvm_offload.unwrap_or(false); - config.llvm_plugins = llvm_plugins.unwrap_or(false); - config.rust_optimize = optimize.unwrap_or(RustOptimize::Bool(true)); - - // We make `x86_64-unknown-linux-gnu` use the self-contained linker by default, so we will - // build our internal lld and use it as the default linker, by setting the `rust.lld` config - // to true by default: - // - on the `x86_64-unknown-linux-gnu` target - // - on the `dev` and `nightly` channels - // - when building our in-tree llvm (i.e. the target has not set an `llvm-config`), so that - // we're also able to build the corresponding lld - // - or when using an external llvm that's downloaded from CI, which also contains our prebuilt - // lld - // - otherwise, we'd be using an external llvm, and lld would not necessarily available and - // thus, disabled - // - similarly, lld will not be built nor used by default when explicitly asked not to, e.g. - // when the config sets `rust.lld = false` - if config.build.triple == "x86_64-unknown-linux-gnu" - && config.hosts == [config.build] - && (config.channel == "dev" || config.channel == "nightly") - { - let no_llvm_config = config - .target_config - .get(&config.build) - .is_some_and(|target_config| target_config.llvm_config.is_none()); - let enable_lld = config.llvm_from_ci || no_llvm_config; - // Prefer the config setting in case an explicit opt-out is needed. - config.lld_enabled = lld_enabled.unwrap_or(enable_lld); - } else { - set(&mut config.lld_enabled, lld_enabled); - } - if matches!(config.lld_mode, LldMode::SelfContained) && !config.lld_enabled && flags.stage.unwrap_or(0) > 0 @@ -2496,31 +943,6 @@ impl Config { ); } - let default_std_features = BTreeSet::from([String::from("panic-unwind")]); - config.rust_std_features = std_features.unwrap_or(default_std_features); - - let default = debug == Some(true); - config.rustc_debug_assertions = rustc_debug_assertions.unwrap_or(default); - config.std_debug_assertions = std_debug_assertions.unwrap_or(config.rustc_debug_assertions); - config.tools_debug_assertions = - tools_debug_assertions.unwrap_or(config.rustc_debug_assertions); - config.rust_overflow_checks = overflow_checks.unwrap_or(default); - config.rust_overflow_checks_std = - overflow_checks_std.unwrap_or(config.rust_overflow_checks); - - config.rust_debug_logging = debug_logging.unwrap_or(config.rustc_debug_assertions); - - let with_defaults = |debuginfo_level_specific: Option<_>| { - debuginfo_level_specific.or(debuginfo_level).unwrap_or(if debug == Some(true) { - DebuginfoLevel::Limited - } else { - DebuginfoLevel::None - }) - }; - config.rust_debuginfo_level_rustc = with_defaults(debuginfo_level_rustc); - config.rust_debuginfo_level_std = with_defaults(debuginfo_level_std); - config.rust_debuginfo_level_tools = with_defaults(debuginfo_level_tools); - config.rust_debuginfo_level_tests = debuginfo_level_tests.unwrap_or(DebuginfoLevel::None); config.optimized_compiler_builtins = optimized_compiler_builtins.unwrap_or(config.channel != "dev"); config.compiletest_diff_tool = compiletest_diff_tool; @@ -2845,75 +1267,17 @@ impl Config { } } - pub fn sanitizers_enabled(&self, target: TargetSelection) -> bool { - self.target_config.get(&target).and_then(|t| t.sanitizers).unwrap_or(self.sanitizers) - } - - pub fn needs_sanitizer_runtime_built(&self, target: TargetSelection) -> bool { - // MSVC uses the Microsoft-provided sanitizer runtime, but all other runtimes we build. - !target.is_msvc() && self.sanitizers_enabled(target) - } - pub fn any_sanitizers_to_build(&self) -> bool { self.target_config .iter() .any(|(ts, t)| !ts.is_msvc() && t.sanitizers.unwrap_or(self.sanitizers)) } - pub fn profiler_path(&self, target: TargetSelection) -> Option<&str> { - match self.target_config.get(&target)?.profiler.as_ref()? { - StringOrBool::String(s) => Some(s), - StringOrBool::Bool(_) => None, - } - } - - pub fn profiler_enabled(&self, target: TargetSelection) -> bool { - self.target_config - .get(&target) - .and_then(|t| t.profiler.as_ref()) - .map(StringOrBool::is_string_or_true) - .unwrap_or(self.profiler) - } - pub fn any_profiler_enabled(&self) -> bool { self.target_config.values().any(|t| matches!(&t.profiler, Some(p) if p.is_string_or_true())) || self.profiler } - pub fn rpath_enabled(&self, target: TargetSelection) -> bool { - self.target_config.get(&target).and_then(|t| t.rpath).unwrap_or(self.rust_rpath) - } - - pub fn optimized_compiler_builtins(&self, target: TargetSelection) -> bool { - self.target_config - .get(&target) - .and_then(|t| t.optimized_compiler_builtins) - .unwrap_or(self.optimized_compiler_builtins) - } - - pub fn llvm_enabled(&self, target: TargetSelection) -> bool { - self.codegen_backends(target).contains(&"llvm".to_owned()) - } - - pub fn llvm_libunwind(&self, target: TargetSelection) -> LlvmLibunwind { - self.target_config - .get(&target) - .and_then(|t| t.llvm_libunwind) - .or(self.llvm_libunwind_default) - .unwrap_or(if target.contains("fuchsia") { - LlvmLibunwind::InTree - } else { - LlvmLibunwind::No - }) - } - - pub fn split_debuginfo(&self, target: TargetSelection) -> SplitDebuginfo { - self.target_config - .get(&target) - .and_then(|t| t.split_debuginfo) - .unwrap_or_else(|| SplitDebuginfo::default_for_platform(target)) - } - /// Returns whether or not submodules should be managed by bootstrap. pub fn submodules(&self) -> bool { // If not specified in config, the default is to only manage @@ -2921,21 +1285,6 @@ impl Config { self.submodules.unwrap_or(self.rust_info.is_managed_git_subrepository()) } - pub fn codegen_backends(&self, target: TargetSelection) -> &[String] { - self.target_config - .get(&target) - .and_then(|cfg| cfg.codegen_backends.as_deref()) - .unwrap_or(&self.rust_codegen_backends) - } - - pub fn jemalloc(&self, target: TargetSelection) -> bool { - self.target_config.get(&target).and_then(|cfg| cfg.jemalloc).unwrap_or(self.jemalloc) - } - - pub fn default_codegen_backend(&self, target: TargetSelection) -> Option<String> { - self.codegen_backends(target).first().cloned() - } - pub fn git_config(&self) -> GitConfig<'_> { GitConfig { nightly_branch: &self.stage0_metadata.config.nightly_branch, @@ -3119,7 +1468,7 @@ impl Config { } /// Returns the commit to download, or `None` if we shouldn't download CI artifacts. - fn download_ci_rustc_commit( + pub fn download_ci_rustc_commit( &self, download_rustc: Option<StringOrBool>, debug_assertions_requested: bool, @@ -3199,7 +1548,7 @@ impl Config { Some(commit) } - fn parse_download_ci_llvm( + pub fn parse_download_ci_llvm( &self, download_ci_llvm: Option<StringOrBool>, asserts: bool, @@ -3282,6 +1631,83 @@ impl Config { .clone() } + pub fn ci_env(&self) -> CiEnv { + if self.is_running_on_ci { CiEnv::GitHubActions } else { CiEnv::None } + } + + pub fn sanitizers_enabled(&self, target: TargetSelection) -> bool { + self.target_config.get(&target).and_then(|t| t.sanitizers).unwrap_or(self.sanitizers) + } + + pub fn needs_sanitizer_runtime_built(&self, target: TargetSelection) -> bool { + // MSVC uses the Microsoft-provided sanitizer runtime, but all other runtimes we build. + !target.is_msvc() && self.sanitizers_enabled(target) + } + + pub fn profiler_path(&self, target: TargetSelection) -> Option<&str> { + match self.target_config.get(&target)?.profiler.as_ref()? { + StringOrBool::String(s) => Some(s), + StringOrBool::Bool(_) => None, + } + } + + pub fn profiler_enabled(&self, target: TargetSelection) -> bool { + self.target_config + .get(&target) + .and_then(|t| t.profiler.as_ref()) + .map(StringOrBool::is_string_or_true) + .unwrap_or(self.profiler) + } + + pub fn codegen_backends(&self, target: TargetSelection) -> &[String] { + self.target_config + .get(&target) + .and_then(|cfg| cfg.codegen_backends.as_deref()) + .unwrap_or(&self.rust_codegen_backends) + } + + pub fn jemalloc(&self, target: TargetSelection) -> bool { + self.target_config.get(&target).and_then(|cfg| cfg.jemalloc).unwrap_or(self.jemalloc) + } + + pub fn default_codegen_backend(&self, target: TargetSelection) -> Option<String> { + self.codegen_backends(target).first().cloned() + } + + pub fn rpath_enabled(&self, target: TargetSelection) -> bool { + self.target_config.get(&target).and_then(|t| t.rpath).unwrap_or(self.rust_rpath) + } + + pub fn optimized_compiler_builtins(&self, target: TargetSelection) -> bool { + self.target_config + .get(&target) + .and_then(|t| t.optimized_compiler_builtins) + .unwrap_or(self.optimized_compiler_builtins) + } + + pub fn llvm_enabled(&self, target: TargetSelection) -> bool { + self.codegen_backends(target).contains(&"llvm".to_owned()) + } + + pub fn llvm_libunwind(&self, target: TargetSelection) -> LlvmLibunwind { + self.target_config + .get(&target) + .and_then(|t| t.llvm_libunwind) + .or(self.llvm_libunwind_default) + .unwrap_or(if target.contains("fuchsia") { + LlvmLibunwind::InTree + } else { + LlvmLibunwind::No + }) + } + + pub fn split_debuginfo(&self, target: TargetSelection) -> SplitDebuginfo { + self.target_config + .get(&target) + .and_then(|t| t.split_debuginfo) + .unwrap_or_else(|| SplitDebuginfo::default_for_platform(target)) + } + /// Checks if the given target is the same as the host target. pub fn is_host_target(&self, target: TargetSelection) -> bool { self.build == target @@ -3317,290 +1743,4 @@ impl Config { _ => !self.is_system_llvm(target), } } - - pub fn ci_env(&self) -> CiEnv { - if self.is_running_on_ci { CiEnv::GitHubActions } else { CiEnv::None } - } -} - -/// Compares the current `Llvm` options against those in the CI LLVM builder and detects any incompatible options. -/// It does this by destructuring the `Llvm` instance to make sure every `Llvm` field is covered and not missing. -#[cfg(not(test))] -pub(crate) fn check_incompatible_options_for_ci_llvm( - current_config_toml: TomlConfig, - ci_config_toml: TomlConfig, -) -> Result<(), String> { - macro_rules! err { - ($current:expr, $expected:expr) => { - if let Some(current) = &$current { - if Some(current) != $expected.as_ref() { - return Err(format!( - "ERROR: Setting `llvm.{}` is incompatible with `llvm.download-ci-llvm`. \ - Current value: {:?}, Expected value(s): {}{:?}", - stringify!($expected).replace("_", "-"), - $current, - if $expected.is_some() { "None/" } else { "" }, - $expected, - )); - }; - }; - }; - } - - macro_rules! warn { - ($current:expr, $expected:expr) => { - if let Some(current) = &$current { - if Some(current) != $expected.as_ref() { - println!( - "WARNING: `llvm.{}` has no effect with `llvm.download-ci-llvm`. \ - Current value: {:?}, Expected value(s): {}{:?}", - stringify!($expected).replace("_", "-"), - $current, - if $expected.is_some() { "None/" } else { "" }, - $expected, - ); - }; - }; - }; - } - - let (Some(current_llvm_config), Some(ci_llvm_config)) = - (current_config_toml.llvm, ci_config_toml.llvm) - else { - return Ok(()); - }; - - let Llvm { - optimize, - thin_lto, - release_debuginfo, - assertions: _, - tests: _, - plugins, - ccache: _, - static_libstdcpp: _, - libzstd, - ninja: _, - targets, - experimental_targets, - link_jobs: _, - link_shared: _, - version_suffix, - clang_cl, - cflags, - cxxflags, - ldflags, - use_libcxx, - use_linker, - allow_old_toolchain, - offload, - polly, - clang, - enable_warnings, - download_ci_llvm: _, - build_config, - enzyme, - } = ci_llvm_config; - - err!(current_llvm_config.optimize, optimize); - err!(current_llvm_config.thin_lto, thin_lto); - err!(current_llvm_config.release_debuginfo, release_debuginfo); - err!(current_llvm_config.libzstd, libzstd); - err!(current_llvm_config.targets, targets); - err!(current_llvm_config.experimental_targets, experimental_targets); - err!(current_llvm_config.clang_cl, clang_cl); - err!(current_llvm_config.version_suffix, version_suffix); - err!(current_llvm_config.cflags, cflags); - err!(current_llvm_config.cxxflags, cxxflags); - err!(current_llvm_config.ldflags, ldflags); - err!(current_llvm_config.use_libcxx, use_libcxx); - err!(current_llvm_config.use_linker, use_linker); - err!(current_llvm_config.allow_old_toolchain, allow_old_toolchain); - err!(current_llvm_config.offload, offload); - err!(current_llvm_config.polly, polly); - err!(current_llvm_config.clang, clang); - err!(current_llvm_config.build_config, build_config); - err!(current_llvm_config.plugins, plugins); - err!(current_llvm_config.enzyme, enzyme); - - warn!(current_llvm_config.enable_warnings, enable_warnings); - - Ok(()) -} - -/// Compares the current Rust options against those in the CI rustc builder and detects any incompatible options. -/// It does this by destructuring the `Rust` instance to make sure every `Rust` field is covered and not missing. -fn check_incompatible_options_for_ci_rustc( - host: TargetSelection, - current_config_toml: TomlConfig, - ci_config_toml: TomlConfig, -) -> Result<(), String> { - macro_rules! err { - ($current:expr, $expected:expr, $config_section:expr) => { - if let Some(current) = &$current { - if Some(current) != $expected.as_ref() { - return Err(format!( - "ERROR: Setting `{}` is incompatible with `rust.download-rustc`. \ - Current value: {:?}, Expected value(s): {}{:?}", - format!("{}.{}", $config_section, stringify!($expected).replace("_", "-")), - $current, - if $expected.is_some() { "None/" } else { "" }, - $expected, - )); - }; - }; - }; - } - - macro_rules! warn { - ($current:expr, $expected:expr, $config_section:expr) => { - if let Some(current) = &$current { - if Some(current) != $expected.as_ref() { - println!( - "WARNING: `{}` has no effect with `rust.download-rustc`. \ - Current value: {:?}, Expected value(s): {}{:?}", - format!("{}.{}", $config_section, stringify!($expected).replace("_", "-")), - $current, - if $expected.is_some() { "None/" } else { "" }, - $expected, - ); - }; - }; - }; - } - - let current_profiler = current_config_toml.build.as_ref().and_then(|b| b.profiler); - let profiler = ci_config_toml.build.as_ref().and_then(|b| b.profiler); - err!(current_profiler, profiler, "build"); - - let current_optimized_compiler_builtins = - current_config_toml.build.as_ref().and_then(|b| b.optimized_compiler_builtins); - let optimized_compiler_builtins = - ci_config_toml.build.as_ref().and_then(|b| b.optimized_compiler_builtins); - err!(current_optimized_compiler_builtins, optimized_compiler_builtins, "build"); - - // We always build the in-tree compiler on cross targets, so we only care - // about the host target here. - let host_str = host.to_string(); - if let Some(current_cfg) = current_config_toml.target.as_ref().and_then(|c| c.get(&host_str)) - && current_cfg.profiler.is_some() - { - let ci_target_toml = ci_config_toml.target.as_ref().and_then(|c| c.get(&host_str)); - let ci_cfg = ci_target_toml.ok_or(format!( - "Target specific config for '{host_str}' is not present for CI-rustc" - ))?; - - let profiler = &ci_cfg.profiler; - err!(current_cfg.profiler, profiler, "build"); - - let optimized_compiler_builtins = &ci_cfg.optimized_compiler_builtins; - err!(current_cfg.optimized_compiler_builtins, optimized_compiler_builtins, "build"); - } - - let (Some(current_rust_config), Some(ci_rust_config)) = - (current_config_toml.rust, ci_config_toml.rust) - else { - return Ok(()); - }; - - let Rust { - // Following options are the CI rustc incompatible ones. - optimize, - randomize_layout, - debug_logging, - debuginfo_level_rustc, - llvm_tools, - llvm_bitcode_linker, - lto, - stack_protector, - strip, - lld_mode, - jemalloc, - rpath, - channel, - description, - incremental, - default_linker, - std_features, - - // Rest of the options can simply be ignored. - debug: _, - codegen_units: _, - codegen_units_std: _, - rustc_debug_assertions: _, - std_debug_assertions: _, - tools_debug_assertions: _, - overflow_checks: _, - overflow_checks_std: _, - debuginfo_level: _, - debuginfo_level_std: _, - debuginfo_level_tools: _, - debuginfo_level_tests: _, - backtrace: _, - musl_root: _, - verbose_tests: _, - optimize_tests: _, - codegen_tests: _, - omit_git_hash: _, - dist_src: _, - save_toolstates: _, - codegen_backends: _, - lld: _, - deny_warnings: _, - backtrace_on_ice: _, - verify_llvm_ir: _, - thin_lto_import_instr_limit: _, - remap_debuginfo: _, - test_compare_mode: _, - llvm_libunwind: _, - control_flow_guard: _, - ehcont_guard: _, - new_symbol_mangling: _, - profile_generate: _, - profile_use: _, - download_rustc: _, - validate_mir_opts: _, - frame_pointers: _, - } = ci_rust_config; - - // There are two kinds of checks for CI rustc incompatible options: - // 1. Checking an option that may change the compiler behaviour/output. - // 2. Checking an option that have no effect on the compiler behaviour/output. - // - // If the option belongs to the first category, we call `err` macro for a hard error; - // otherwise, we just print a warning with `warn` macro. - - err!(current_rust_config.optimize, optimize, "rust"); - err!(current_rust_config.randomize_layout, randomize_layout, "rust"); - err!(current_rust_config.debug_logging, debug_logging, "rust"); - err!(current_rust_config.debuginfo_level_rustc, debuginfo_level_rustc, "rust"); - err!(current_rust_config.rpath, rpath, "rust"); - err!(current_rust_config.strip, strip, "rust"); - err!(current_rust_config.lld_mode, lld_mode, "rust"); - err!(current_rust_config.llvm_tools, llvm_tools, "rust"); - err!(current_rust_config.llvm_bitcode_linker, llvm_bitcode_linker, "rust"); - err!(current_rust_config.jemalloc, jemalloc, "rust"); - err!(current_rust_config.default_linker, default_linker, "rust"); - err!(current_rust_config.stack_protector, stack_protector, "rust"); - err!(current_rust_config.lto, lto, "rust"); - err!(current_rust_config.std_features, std_features, "rust"); - - warn!(current_rust_config.channel, channel, "rust"); - warn!(current_rust_config.description, description, "rust"); - warn!(current_rust_config.incremental, incremental, "rust"); - - Ok(()) -} - -fn set<T>(field: &mut T, val: Option<T>) { - if let Some(v) = val { - *field = v; - } -} - -fn threads_from_config(v: u32) -> u32 { - match v { - 0 => std::thread::available_parallelism().map_or(1, std::num::NonZeroUsize::get) as u32, - n => n, - } } diff --git a/src/bootstrap/src/core/config/flags.rs b/src/bootstrap/src/core/config/flags.rs index 45a0836ee67..30617f58d43 100644 --- a/src/bootstrap/src/core/config/flags.rs +++ b/src/bootstrap/src/core/config/flags.rs @@ -12,7 +12,8 @@ use tracing::instrument; use crate::core::build_steps::perf::PerfArgs; use crate::core::build_steps::setup::Profile; use crate::core::builder::{Builder, Kind}; -use crate::core::config::{Config, TargetSelectionList, target_selection_list}; +use crate::core::config::Config; +use crate::core::config::target_selection::{TargetSelectionList, target_selection_list}; use crate::{Build, DocTests}; #[derive(Copy, Clone, Default, Debug, ValueEnum)] diff --git a/src/bootstrap/src/core/config/mod.rs b/src/bootstrap/src/core/config/mod.rs index 179e15e778b..f39e7b02ccc 100644 --- a/src/bootstrap/src/core/config/mod.rs +++ b/src/bootstrap/src/core/config/mod.rs @@ -1,7 +1,418 @@ +//! Entry point for the `config` module. +//! +//! This module defines two macros: +//! +//! - `define_config!`: A declarative macro used instead of `#[derive(Deserialize)]` to reduce +//! compile time and binary size, especially for the bootstrap binary. +//! +//! - `check_ci_llvm!`: A compile-time assertion macro that ensures certain settings are +//! not enabled when `download-ci-llvm` is active. +//! +//! A declarative macro is used here in place of a procedural derive macro to minimize +//! the compile time of the bootstrap process. +//! +//! Additionally, this module defines common types, enums, and helper functions used across +//! various TOML configuration sections in `bootstrap.toml`. +//! +//! It provides shared definitions for: +//! - Data types deserialized from TOML. +//! - Utility enums for specific configuration options. +//! - Helper functions for managing configuration values. + #[expect(clippy::module_inception)] mod config; pub mod flags; +pub mod target_selection; #[cfg(test)] mod tests; +pub mod toml; + +use std::collections::HashSet; +use std::path::PathBuf; +use build_helper::exit; pub use config::*; +use serde::{Deserialize, Deserializer}; +use serde_derive::Deserialize; +pub use target_selection::TargetSelection; +pub use toml::BUILDER_CONFIG_FILENAME; +pub use toml::change_id::ChangeId; +pub use toml::rust::LldMode; +pub use toml::target::Target; +#[cfg(feature = "tracing")] +use tracing::{instrument, span}; + +use crate::Display; +use crate::str::FromStr; + +// We are using a decl macro instead of a derive proc macro here to reduce the compile time of bootstrap. +#[macro_export] +macro_rules! define_config { + ($(#[$attr:meta])* struct $name:ident { + $($field:ident: Option<$field_ty:ty> = $field_key:literal,)* + }) => { + $(#[$attr])* + pub struct $name { + $(pub $field: Option<$field_ty>,)* + } + + impl Merge for $name { + fn merge( + &mut self, + _parent_config_path: Option<PathBuf>, + _included_extensions: &mut HashSet<PathBuf>, + other: Self, + replace: ReplaceOpt + ) { + $( + match replace { + ReplaceOpt::IgnoreDuplicate => { + if self.$field.is_none() { + self.$field = other.$field; + } + }, + ReplaceOpt::Override => { + if other.$field.is_some() { + self.$field = other.$field; + } + } + ReplaceOpt::ErrorOnDuplicate => { + if other.$field.is_some() { + if self.$field.is_some() { + if cfg!(test) { + panic!("overriding existing option") + } else { + eprintln!("overriding existing option: `{}`", stringify!($field)); + exit!(2); + } + } else { + self.$field = other.$field; + } + } + } + } + )* + } + } + + // The following is a trimmed version of what serde_derive generates. All parts not relevant + // for toml deserialization have been removed. This reduces the binary size and improves + // compile time of bootstrap. + impl<'de> Deserialize<'de> for $name { + fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> + where + D: Deserializer<'de>, + { + struct Field; + impl<'de> serde::de::Visitor<'de> for Field { + type Value = $name; + fn expecting(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.write_str(concat!("struct ", stringify!($name))) + } + + #[inline] + fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error> + where + A: serde::de::MapAccess<'de>, + { + $(let mut $field: Option<$field_ty> = None;)* + while let Some(key) = + match serde::de::MapAccess::next_key::<String>(&mut map) { + Ok(val) => val, + Err(err) => { + return Err(err); + } + } + { + match &*key { + $($field_key => { + if $field.is_some() { + return Err(<A::Error as serde::de::Error>::duplicate_field( + $field_key, + )); + } + $field = match serde::de::MapAccess::next_value::<$field_ty>( + &mut map, + ) { + Ok(val) => Some(val), + Err(err) => { + return Err(err); + } + }; + })* + key => { + return Err(serde::de::Error::unknown_field(key, FIELDS)); + } + } + } + Ok($name { $($field),* }) + } + } + const FIELDS: &'static [&'static str] = &[ + $($field_key,)* + ]; + Deserializer::deserialize_struct( + deserializer, + stringify!($name), + FIELDS, + Field, + ) + } + } + } +} + +#[macro_export] +macro_rules! check_ci_llvm { + ($name:expr) => { + assert!( + $name.is_none(), + "setting {} is incompatible with download-ci-llvm.", + stringify!($name).replace("_", "-") + ); + }; +} + +pub(crate) trait Merge { + fn merge( + &mut self, + parent_config_path: Option<PathBuf>, + included_extensions: &mut HashSet<PathBuf>, + other: Self, + replace: ReplaceOpt, + ); +} + +impl<T> Merge for Option<T> { + fn merge( + &mut self, + _parent_config_path: Option<PathBuf>, + _included_extensions: &mut HashSet<PathBuf>, + other: Self, + replace: ReplaceOpt, + ) { + match replace { + ReplaceOpt::IgnoreDuplicate => { + if self.is_none() { + *self = other; + } + } + ReplaceOpt::Override => { + if other.is_some() { + *self = other; + } + } + ReplaceOpt::ErrorOnDuplicate => { + if other.is_some() { + if self.is_some() { + if cfg!(test) { + panic!("overriding existing option") + } else { + eprintln!("overriding existing option"); + exit!(2); + } + } else { + *self = other; + } + } + } + } + } +} + +#[derive(Copy, Clone, Default, Debug, Eq, PartialEq)] +pub enum DebuginfoLevel { + #[default] + None, + LineDirectivesOnly, + LineTablesOnly, + Limited, + Full, +} + +// NOTE: can't derive(Deserialize) because the intermediate trip through toml::Value only +// deserializes i64, and derive() only generates visit_u64 +impl<'de> Deserialize<'de> for DebuginfoLevel { + fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> + where + D: Deserializer<'de>, + { + use serde::de::Error; + + Ok(match Deserialize::deserialize(deserializer)? { + StringOrInt::String(s) if s == "none" => DebuginfoLevel::None, + StringOrInt::Int(0) => DebuginfoLevel::None, + StringOrInt::String(s) if s == "line-directives-only" => { + DebuginfoLevel::LineDirectivesOnly + } + StringOrInt::String(s) if s == "line-tables-only" => DebuginfoLevel::LineTablesOnly, + StringOrInt::String(s) if s == "limited" => DebuginfoLevel::Limited, + StringOrInt::Int(1) => DebuginfoLevel::Limited, + StringOrInt::String(s) if s == "full" => DebuginfoLevel::Full, + StringOrInt::Int(2) => DebuginfoLevel::Full, + StringOrInt::Int(n) => { + let other = serde::de::Unexpected::Signed(n); + return Err(D::Error::invalid_value(other, &"expected 0, 1, or 2")); + } + StringOrInt::String(s) => { + let other = serde::de::Unexpected::Str(&s); + return Err(D::Error::invalid_value( + other, + &"expected none, line-tables-only, limited, or full", + )); + } + }) + } +} + +/// Suitable for passing to `-C debuginfo` +impl Display for DebuginfoLevel { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + use DebuginfoLevel::*; + f.write_str(match self { + None => "0", + LineDirectivesOnly => "line-directives-only", + LineTablesOnly => "line-tables-only", + Limited => "1", + Full => "2", + }) + } +} + +#[derive(Clone, Debug, Deserialize, PartialEq, Eq)] +#[serde(untagged)] +pub enum StringOrBool { + String(String), + Bool(bool), +} + +impl Default for StringOrBool { + fn default() -> StringOrBool { + StringOrBool::Bool(false) + } +} + +impl StringOrBool { + pub fn is_string_or_true(&self) -> bool { + matches!(self, Self::String(_) | Self::Bool(true)) + } +} + +#[derive(Deserialize)] +#[serde(untagged)] +pub enum StringOrInt { + String(String), + Int(i64), +} + +#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)] +pub enum LlvmLibunwind { + #[default] + No, + InTree, + System, +} + +impl FromStr for LlvmLibunwind { + type Err = String; + + fn from_str(value: &str) -> Result<Self, Self::Err> { + match value { + "no" => Ok(Self::No), + "in-tree" => Ok(Self::InTree), + "system" => Ok(Self::System), + invalid => Err(format!("Invalid value '{invalid}' for rust.llvm-libunwind config.")), + } + } +} + +#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub enum SplitDebuginfo { + Packed, + Unpacked, + #[default] + Off, +} + +impl std::str::FromStr for SplitDebuginfo { + type Err = (); + + fn from_str(s: &str) -> Result<Self, Self::Err> { + match s { + "packed" => Ok(SplitDebuginfo::Packed), + "unpacked" => Ok(SplitDebuginfo::Unpacked), + "off" => Ok(SplitDebuginfo::Off), + _ => Err(()), + } + } +} + +/// Describes how to handle conflicts in merging two `TomlConfig` +#[derive(Copy, Clone, Debug)] +pub enum ReplaceOpt { + /// Silently ignore a duplicated value + IgnoreDuplicate, + /// Override the current value, even if it's `Some` + Override, + /// Exit with an error on duplicate values + ErrorOnDuplicate, +} + +#[derive(Clone, Default)] +pub enum DryRun { + /// This isn't a dry run. + #[default] + Disabled, + /// This is a dry run enabled by bootstrap itself, so it can verify that no work is done. + SelfCheck, + /// This is a dry run enabled by the `--dry-run` flag. + UserSelected, +} + +/// LTO mode used for compiling rustc itself. +#[derive(Default, Clone, PartialEq, Debug)] +pub enum RustcLto { + Off, + #[default] + ThinLocal, + Thin, + Fat, +} + +impl std::str::FromStr for RustcLto { + type Err = String; + + fn from_str(s: &str) -> Result<Self, Self::Err> { + match s { + "thin-local" => Ok(RustcLto::ThinLocal), + "thin" => Ok(RustcLto::Thin), + "fat" => Ok(RustcLto::Fat), + "off" => Ok(RustcLto::Off), + _ => Err(format!("Invalid value for rustc LTO: {s}")), + } + } +} + +/// Determines how will GCC be provided. +#[derive(Default, Clone)] +pub enum GccCiMode { + /// Build GCC from the local `src/gcc` submodule. + #[default] + BuildLocally, + /// Try to download GCC from CI. + /// If it is not available on CI, it will be built locally instead. + DownloadFromCi, +} + +pub fn set<T>(field: &mut T, val: Option<T>) { + if let Some(v) = val { + *field = v; + } +} + +pub fn threads_from_config(v: u32) -> u32 { + match v { + 0 => std::thread::available_parallelism().map_or(1, std::num::NonZeroUsize::get) as u32, + n => n, + } +} diff --git a/src/bootstrap/src/core/config/target_selection.rs b/src/bootstrap/src/core/config/target_selection.rs new file mode 100644 index 00000000000..ebd3fe7a8c6 --- /dev/null +++ b/src/bootstrap/src/core/config/target_selection.rs @@ -0,0 +1,147 @@ +use std::fmt; + +use crate::core::config::SplitDebuginfo; +use crate::utils::cache::{INTERNER, Interned}; +use crate::{Path, env}; + +#[derive(Copy, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] +// N.B.: This type is used everywhere, and the entire codebase relies on it being Copy. +// Making !Copy is highly nontrivial! +pub struct TargetSelection { + pub triple: Interned<String>, + pub file: Option<Interned<String>>, + pub synthetic: bool, +} + +/// Newtype over `Vec<TargetSelection>` so we can implement custom parsing logic +#[derive(Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] +pub struct TargetSelectionList(pub Vec<TargetSelection>); + +pub fn target_selection_list(s: &str) -> Result<TargetSelectionList, String> { + Ok(TargetSelectionList( + s.split(',').filter(|s| !s.is_empty()).map(TargetSelection::from_user).collect(), + )) +} + +impl TargetSelection { + pub fn from_user(selection: &str) -> Self { + let path = Path::new(selection); + + let (triple, file) = if path.exists() { + let triple = path + .file_stem() + .expect("Target specification file has no file stem") + .to_str() + .expect("Target specification file stem is not UTF-8"); + + (triple, Some(selection)) + } else { + (selection, None) + }; + + let triple = INTERNER.intern_str(triple); + let file = file.map(|f| INTERNER.intern_str(f)); + + Self { triple, file, synthetic: false } + } + + pub fn create_synthetic(triple: &str, file: &str) -> Self { + Self { + triple: INTERNER.intern_str(triple), + file: Some(INTERNER.intern_str(file)), + synthetic: true, + } + } + + pub fn rustc_target_arg(&self) -> &str { + self.file.as_ref().unwrap_or(&self.triple) + } + + pub fn contains(&self, needle: &str) -> bool { + self.triple.contains(needle) + } + + pub fn starts_with(&self, needle: &str) -> bool { + self.triple.starts_with(needle) + } + + pub fn ends_with(&self, needle: &str) -> bool { + self.triple.ends_with(needle) + } + + // See src/bootstrap/synthetic_targets.rs + pub fn is_synthetic(&self) -> bool { + self.synthetic + } + + pub fn is_msvc(&self) -> bool { + self.contains("msvc") + } + + pub fn is_windows(&self) -> bool { + self.contains("windows") + } + + pub fn is_windows_gnu(&self) -> bool { + self.ends_with("windows-gnu") + } + + pub fn is_cygwin(&self) -> bool { + self.is_windows() && + // ref. https://cygwin.com/pipermail/cygwin/2022-February/250802.html + env::var("OSTYPE").is_ok_and(|v| v.to_lowercase().contains("cygwin")) + } + + pub fn needs_crt_begin_end(&self) -> bool { + self.contains("musl") && !self.contains("unikraft") + } + + /// Path to the file defining the custom target, if any. + pub fn filepath(&self) -> Option<&Path> { + self.file.as_ref().map(Path::new) + } +} + +impl fmt::Display for TargetSelection { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.triple)?; + if let Some(file) = self.file { + write!(f, "({file})")?; + } + Ok(()) + } +} + +impl fmt::Debug for TargetSelection { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{self}") + } +} + +impl PartialEq<&str> for TargetSelection { + fn eq(&self, other: &&str) -> bool { + self.triple == *other + } +} + +// Targets are often used as directory names throughout bootstrap. +// This impl makes it more ergonomics to use them as such. +impl AsRef<Path> for TargetSelection { + fn as_ref(&self) -> &Path { + self.triple.as_ref() + } +} + +impl SplitDebuginfo { + /// Returns the default `-Csplit-debuginfo` value for the current target. See the comment for + /// `rust.split-debuginfo` in `bootstrap.example.toml`. + pub fn default_for_platform(target: TargetSelection) -> Self { + if target.contains("apple") { + SplitDebuginfo::Unpacked + } else if target.is_windows() { + SplitDebuginfo::Packed + } else { + SplitDebuginfo::Off + } + } +} diff --git a/src/bootstrap/src/core/config/tests.rs b/src/bootstrap/src/core/config/tests.rs index 96ac8a6d52f..50eba12aba7 100644 --- a/src/bootstrap/src/core/config/tests.rs +++ b/src/bootstrap/src/core/config/tests.rs @@ -10,12 +10,14 @@ use clap::CommandFactory; use serde::Deserialize; use super::flags::Flags; -use super::{ChangeIdWrapper, Config, RUSTC_IF_UNCHANGED_ALLOWED_PATHS}; +use super::toml::change_id::ChangeIdWrapper; +use super::{Config, RUSTC_IF_UNCHANGED_ALLOWED_PATHS}; use crate::ChangeId; use crate::core::build_steps::clippy::{LintConfig, get_clippy_rules_in_order}; use crate::core::build_steps::llvm; use crate::core::build_steps::llvm::LLVM_INVALIDATION_PATHS; -use crate::core::config::{LldMode, Target, TargetSelection, TomlConfig}; +use crate::core::config::toml::TomlConfig; +use crate::core::config::{LldMode, Target, TargetSelection}; use crate::utils::tests::git::git_test; pub(crate) fn parse(config: &str) -> Config { diff --git a/src/bootstrap/src/core/config/toml/build.rs b/src/bootstrap/src/core/config/toml/build.rs new file mode 100644 index 00000000000..85ded3c87d9 --- /dev/null +++ b/src/bootstrap/src/core/config/toml/build.rs @@ -0,0 +1,72 @@ +//! This module defines the `Build` struct, which represents the `[build]` table +//! in the `bootstrap.toml` configuration file. +//! +//! The `[build]` table contains global options that influence the overall build process, +//! such as default host and target triples, paths to tools, build directories, and +//! various feature flags. These options apply across different stages and components +//! unless specifically overridden by other configuration sections or command-line flags. + +use serde::{Deserialize, Deserializer}; + +use crate::core::config::toml::ReplaceOpt; +use crate::core::config::{Merge, StringOrBool}; +use crate::{HashSet, PathBuf, define_config, exit}; + +define_config! { + /// TOML representation of various global build decisions. + #[derive(Default)] + struct Build { + build: Option<String> = "build", + description: Option<String> = "description", + host: Option<Vec<String>> = "host", + target: Option<Vec<String>> = "target", + build_dir: Option<String> = "build-dir", + cargo: Option<PathBuf> = "cargo", + rustc: Option<PathBuf> = "rustc", + rustfmt: Option<PathBuf> = "rustfmt", + cargo_clippy: Option<PathBuf> = "cargo-clippy", + docs: Option<bool> = "docs", + compiler_docs: Option<bool> = "compiler-docs", + library_docs_private_items: Option<bool> = "library-docs-private-items", + docs_minification: Option<bool> = "docs-minification", + submodules: Option<bool> = "submodules", + gdb: Option<String> = "gdb", + lldb: Option<String> = "lldb", + nodejs: Option<String> = "nodejs", + npm: Option<String> = "npm", + python: Option<String> = "python", + reuse: Option<String> = "reuse", + locked_deps: Option<bool> = "locked-deps", + vendor: Option<bool> = "vendor", + full_bootstrap: Option<bool> = "full-bootstrap", + bootstrap_cache_path: Option<PathBuf> = "bootstrap-cache-path", + extended: Option<bool> = "extended", + tools: Option<HashSet<String>> = "tools", + verbose: Option<usize> = "verbose", + sanitizers: Option<bool> = "sanitizers", + profiler: Option<bool> = "profiler", + cargo_native_static: Option<bool> = "cargo-native-static", + low_priority: Option<bool> = "low-priority", + configure_args: Option<Vec<String>> = "configure-args", + local_rebuild: Option<bool> = "local-rebuild", + print_step_timings: Option<bool> = "print-step-timings", + print_step_rusage: Option<bool> = "print-step-rusage", + check_stage: Option<u32> = "check-stage", + doc_stage: Option<u32> = "doc-stage", + build_stage: Option<u32> = "build-stage", + test_stage: Option<u32> = "test-stage", + install_stage: Option<u32> = "install-stage", + dist_stage: Option<u32> = "dist-stage", + bench_stage: Option<u32> = "bench-stage", + patch_binaries_for_nix: Option<bool> = "patch-binaries-for-nix", + // NOTE: only parsed by bootstrap.py, `--feature build-metrics` enables metrics unconditionally + metrics: Option<bool> = "metrics", + android_ndk: Option<PathBuf> = "android-ndk", + optimized_compiler_builtins: Option<bool> = "optimized-compiler-builtins", + jobs: Option<u32> = "jobs", + compiletest_diff_tool: Option<String> = "compiletest-diff-tool", + compiletest_use_stage0_libtest: Option<bool> = "compiletest-use-stage0-libtest", + ccache: Option<StringOrBool> = "ccache", + exclude: Option<Vec<PathBuf>> = "exclude", + } +} diff --git a/src/bootstrap/src/core/config/toml/change_id.rs b/src/bootstrap/src/core/config/toml/change_id.rs new file mode 100644 index 00000000000..41dd2531d43 --- /dev/null +++ b/src/bootstrap/src/core/config/toml/change_id.rs @@ -0,0 +1,34 @@ +use serde::{Deserialize, Deserializer}; +use serde_derive::Deserialize; + +/// This enum is used for deserializing change IDs from TOML, allowing both numeric values and the string `"ignore"`. +#[derive(Clone, Debug, PartialEq)] +pub enum ChangeId { + Ignore, + Id(usize), +} + +/// Since we use `#[serde(deny_unknown_fields)]` on `TomlConfig`, we need a wrapper type +/// for the "change-id" field to parse it even if other fields are invalid. This ensures +/// that if deserialization fails due to other fields, we can still provide the changelogs +/// to allow developers to potentially find the reason for the failure in the logs.. +#[derive(Deserialize, Default)] +pub(crate) struct ChangeIdWrapper { + #[serde(alias = "change-id", default, deserialize_with = "deserialize_change_id")] + pub(crate) inner: Option<ChangeId>, +} + +fn deserialize_change_id<'de, D: Deserializer<'de>>( + deserializer: D, +) -> Result<Option<ChangeId>, D::Error> { + let value = toml::Value::deserialize(deserializer)?; + Ok(match value { + toml::Value::String(s) if s == "ignore" => Some(ChangeId::Ignore), + toml::Value::Integer(i) => Some(ChangeId::Id(i as usize)), + _ => { + return Err(serde::de::Error::custom( + "expected \"ignore\" or an integer for change-id", + )); + } + }) +} diff --git a/src/bootstrap/src/core/config/toml/dist.rs b/src/bootstrap/src/core/config/toml/dist.rs new file mode 100644 index 00000000000..b1429ef1861 --- /dev/null +++ b/src/bootstrap/src/core/config/toml/dist.rs @@ -0,0 +1,52 @@ +//! This module defines the `Dist` struct, which represents the `[dist]` table +//! in the `bootstrap.toml` configuration file. +//! +//! The `[dist]` table contains options related to the distribution process, +//! including signing, uploading artifacts, source tarballs, compression settings, +//! and inclusion of specific tools. + +use serde::{Deserialize, Deserializer}; + +use crate::core::config::toml::ReplaceOpt; +use crate::core::config::{Merge, set}; +use crate::{Config, HashSet, PathBuf, define_config, exit}; + +define_config! { + struct Dist { + sign_folder: Option<String> = "sign-folder", + upload_addr: Option<String> = "upload-addr", + src_tarball: Option<bool> = "src-tarball", + compression_formats: Option<Vec<String>> = "compression-formats", + compression_profile: Option<String> = "compression-profile", + include_mingw_linker: Option<bool> = "include-mingw-linker", + vendor: Option<bool> = "vendor", + } +} + +impl Config { + /// Applies distribution-related configuration from the `Dist` struct + /// to the global `Config` structure. + pub fn apply_dist_config(&mut self, toml_dist: Option<Dist>) { + if let Some(dist) = toml_dist { + let Dist { + sign_folder, + upload_addr, + src_tarball, + compression_formats, + compression_profile, + include_mingw_linker, + vendor, + } = dist; + self.dist_sign_folder = sign_folder.map(PathBuf::from); + self.dist_upload_addr = upload_addr; + self.dist_compression_formats = compression_formats; + set(&mut self.dist_compression_profile, compression_profile); + set(&mut self.rust_dist_src, src_tarball); + set(&mut self.dist_include_mingw_linker, include_mingw_linker); + self.dist_vendor = vendor.unwrap_or_else(|| { + // If we're building from git or tarball sources, enable it by default. + self.rust_info.is_managed_git_subrepository() || self.rust_info.is_from_tarball() + }); + } + } +} diff --git a/src/bootstrap/src/core/config/toml/gcc.rs b/src/bootstrap/src/core/config/toml/gcc.rs new file mode 100644 index 00000000000..bb817c2aaef --- /dev/null +++ b/src/bootstrap/src/core/config/toml/gcc.rs @@ -0,0 +1,34 @@ +//! This module defines the `Gcc` struct, which represents the `[gcc]` table +//! in the `bootstrap.toml` configuration file. +//! +//! The `[gcc]` table contains options specifically related to building or +//! acquiring the GCC compiler for use within the Rust build process. + +use serde::{Deserialize, Deserializer}; + +use crate::core::config::toml::ReplaceOpt; +use crate::core::config::{GccCiMode, Merge}; +use crate::{Config, HashSet, PathBuf, define_config, exit}; + +define_config! { + /// TOML representation of how the GCC build is configured. + struct Gcc { + download_ci_gcc: Option<bool> = "download-ci-gcc", + } +} + +impl Config { + /// Applies GCC-related configuration from the `TomlGcc` struct to the + /// global `Config` structure. + pub fn apply_gcc_config(&mut self, toml_gcc: Option<Gcc>) { + if let Some(gcc) = toml_gcc { + self.gcc_ci_mode = match gcc.download_ci_gcc { + Some(value) => match value { + true => GccCiMode::DownloadFromCi, + false => GccCiMode::BuildLocally, + }, + None => GccCiMode::default(), + }; + } + } +} diff --git a/src/bootstrap/src/core/config/toml/install.rs b/src/bootstrap/src/core/config/toml/install.rs new file mode 100644 index 00000000000..6b9ab87a0b6 --- /dev/null +++ b/src/bootstrap/src/core/config/toml/install.rs @@ -0,0 +1,43 @@ +//! This module defines the `Install` struct, which represents the `[install]` table +//! in the `bootstrap.toml` configuration file. +//! +//! The `[install]` table contains options that specify the installation paths +//! for various components of the Rust toolchain. These paths determine where +//! executables, libraries, documentation, and other files will be placed +//! during the `install` stage of the build. + +use serde::{Deserialize, Deserializer}; + +use crate::core::config::toml::ReplaceOpt; +use crate::core::config::{Merge, set}; +use crate::{Config, HashSet, PathBuf, define_config, exit}; + +define_config! { + /// TOML representation of various global install decisions. + struct Install { + prefix: Option<String> = "prefix", + sysconfdir: Option<String> = "sysconfdir", + docdir: Option<String> = "docdir", + bindir: Option<String> = "bindir", + libdir: Option<String> = "libdir", + mandir: Option<String> = "mandir", + datadir: Option<String> = "datadir", + } +} + +impl Config { + /// Applies installation-related configuration from the `Install` struct + /// to the global `Config` structure. + pub fn apply_install_config(&mut self, toml_install: Option<Install>) { + if let Some(install) = toml_install { + let Install { prefix, sysconfdir, docdir, bindir, libdir, mandir, datadir } = install; + self.prefix = prefix.map(PathBuf::from); + self.sysconfdir = sysconfdir.map(PathBuf::from); + self.datadir = datadir.map(PathBuf::from); + self.docdir = docdir.map(PathBuf::from); + set(&mut self.bindir, bindir.map(PathBuf::from)); + self.libdir = libdir.map(PathBuf::from); + self.mandir = mandir.map(PathBuf::from); + } + } +} diff --git a/src/bootstrap/src/core/config/toml/llvm.rs b/src/bootstrap/src/core/config/toml/llvm.rs new file mode 100644 index 00000000000..4774e202bd8 --- /dev/null +++ b/src/bootstrap/src/core/config/toml/llvm.rs @@ -0,0 +1,284 @@ +//! This module defines the `Llvm` struct, which represents the `[llvm]` table +//! in the `bootstrap.toml` configuration file. + +use serde::{Deserialize, Deserializer}; + +use crate::core::config::toml::{Merge, ReplaceOpt, TomlConfig}; +use crate::core::config::{StringOrBool, set}; +use crate::{Config, HashMap, HashSet, PathBuf, define_config, exit}; + +define_config! { + /// TOML representation of how the LLVM build is configured. + struct Llvm { + optimize: Option<bool> = "optimize", + thin_lto: Option<bool> = "thin-lto", + release_debuginfo: Option<bool> = "release-debuginfo", + assertions: Option<bool> = "assertions", + tests: Option<bool> = "tests", + enzyme: Option<bool> = "enzyme", + plugins: Option<bool> = "plugins", + // FIXME: Remove this field at Q2 2025, it has been replaced by build.ccache + ccache: Option<StringOrBool> = "ccache", + static_libstdcpp: Option<bool> = "static-libstdcpp", + libzstd: Option<bool> = "libzstd", + ninja: Option<bool> = "ninja", + targets: Option<String> = "targets", + experimental_targets: Option<String> = "experimental-targets", + link_jobs: Option<u32> = "link-jobs", + link_shared: Option<bool> = "link-shared", + version_suffix: Option<String> = "version-suffix", + clang_cl: Option<String> = "clang-cl", + cflags: Option<String> = "cflags", + cxxflags: Option<String> = "cxxflags", + ldflags: Option<String> = "ldflags", + use_libcxx: Option<bool> = "use-libcxx", + use_linker: Option<String> = "use-linker", + allow_old_toolchain: Option<bool> = "allow-old-toolchain", + offload: Option<bool> = "offload", + polly: Option<bool> = "polly", + clang: Option<bool> = "clang", + enable_warnings: Option<bool> = "enable-warnings", + download_ci_llvm: Option<StringOrBool> = "download-ci-llvm", + build_config: Option<HashMap<String, String>> = "build-config", + } +} + +/// Compares the current `Llvm` options against those in the CI LLVM builder and detects any incompatible options. +/// It does this by destructuring the `Llvm` instance to make sure every `Llvm` field is covered and not missing. +#[cfg(not(test))] +pub fn check_incompatible_options_for_ci_llvm( + current_config_toml: TomlConfig, + ci_config_toml: TomlConfig, +) -> Result<(), String> { + macro_rules! err { + ($current:expr, $expected:expr) => { + if let Some(current) = &$current { + if Some(current) != $expected.as_ref() { + return Err(format!( + "ERROR: Setting `llvm.{}` is incompatible with `llvm.download-ci-llvm`. \ + Current value: {:?}, Expected value(s): {}{:?}", + stringify!($expected).replace("_", "-"), + $current, + if $expected.is_some() { "None/" } else { "" }, + $expected, + )); + }; + }; + }; + } + + macro_rules! warn { + ($current:expr, $expected:expr) => { + if let Some(current) = &$current { + if Some(current) != $expected.as_ref() { + println!( + "WARNING: `llvm.{}` has no effect with `llvm.download-ci-llvm`. \ + Current value: {:?}, Expected value(s): {}{:?}", + stringify!($expected).replace("_", "-"), + $current, + if $expected.is_some() { "None/" } else { "" }, + $expected, + ); + }; + }; + }; + } + + let (Some(current_llvm_config), Some(ci_llvm_config)) = + (current_config_toml.llvm, ci_config_toml.llvm) + else { + return Ok(()); + }; + + let Llvm { + optimize, + thin_lto, + release_debuginfo, + assertions: _, + tests: _, + plugins, + ccache: _, + static_libstdcpp: _, + libzstd, + ninja: _, + targets, + experimental_targets, + link_jobs: _, + link_shared: _, + version_suffix, + clang_cl, + cflags, + cxxflags, + ldflags, + use_libcxx, + use_linker, + allow_old_toolchain, + offload, + polly, + clang, + enable_warnings, + download_ci_llvm: _, + build_config, + enzyme, + } = ci_llvm_config; + + err!(current_llvm_config.optimize, optimize); + err!(current_llvm_config.thin_lto, thin_lto); + err!(current_llvm_config.release_debuginfo, release_debuginfo); + err!(current_llvm_config.libzstd, libzstd); + err!(current_llvm_config.targets, targets); + err!(current_llvm_config.experimental_targets, experimental_targets); + err!(current_llvm_config.clang_cl, clang_cl); + err!(current_llvm_config.version_suffix, version_suffix); + err!(current_llvm_config.cflags, cflags); + err!(current_llvm_config.cxxflags, cxxflags); + err!(current_llvm_config.ldflags, ldflags); + err!(current_llvm_config.use_libcxx, use_libcxx); + err!(current_llvm_config.use_linker, use_linker); + err!(current_llvm_config.allow_old_toolchain, allow_old_toolchain); + err!(current_llvm_config.offload, offload); + err!(current_llvm_config.polly, polly); + err!(current_llvm_config.clang, clang); + err!(current_llvm_config.build_config, build_config); + err!(current_llvm_config.plugins, plugins); + err!(current_llvm_config.enzyme, enzyme); + + warn!(current_llvm_config.enable_warnings, enable_warnings); + + Ok(()) +} + +impl Config { + pub fn apply_llvm_config( + &mut self, + toml_llvm: Option<Llvm>, + ccache: &mut Option<StringOrBool>, + ) { + let mut llvm_tests = None; + let mut llvm_enzyme = None; + let mut llvm_offload = None; + let mut llvm_plugins = None; + + if let Some(llvm) = toml_llvm { + let Llvm { + optimize: optimize_toml, + thin_lto, + release_debuginfo, + assertions: _, + tests, + enzyme, + plugins, + ccache: llvm_ccache, + static_libstdcpp, + libzstd, + ninja, + targets, + experimental_targets, + link_jobs, + link_shared, + version_suffix, + clang_cl, + cflags, + cxxflags, + ldflags, + use_libcxx, + use_linker, + allow_old_toolchain, + offload, + polly, + clang, + enable_warnings, + download_ci_llvm, + build_config, + } = llvm; + if llvm_ccache.is_some() { + eprintln!("Warning: llvm.ccache is deprecated. Use build.ccache instead."); + } + + if ccache.is_none() { + *ccache = llvm_ccache; + } + set(&mut self.ninja_in_file, ninja); + llvm_tests = tests; + llvm_enzyme = enzyme; + llvm_offload = offload; + llvm_plugins = plugins; + set(&mut self.llvm_optimize, optimize_toml); + set(&mut self.llvm_thin_lto, thin_lto); + set(&mut self.llvm_release_debuginfo, release_debuginfo); + set(&mut self.llvm_static_stdcpp, static_libstdcpp); + set(&mut self.llvm_libzstd, libzstd); + if let Some(v) = link_shared { + self.llvm_link_shared.set(Some(v)); + } + self.llvm_targets.clone_from(&targets); + self.llvm_experimental_targets.clone_from(&experimental_targets); + self.llvm_link_jobs = link_jobs; + self.llvm_version_suffix.clone_from(&version_suffix); + self.llvm_clang_cl.clone_from(&clang_cl); + + self.llvm_cflags.clone_from(&cflags); + self.llvm_cxxflags.clone_from(&cxxflags); + self.llvm_ldflags.clone_from(&ldflags); + set(&mut self.llvm_use_libcxx, use_libcxx); + self.llvm_use_linker.clone_from(&use_linker); + self.llvm_allow_old_toolchain = allow_old_toolchain.unwrap_or(false); + self.llvm_offload = offload.unwrap_or(false); + self.llvm_polly = polly.unwrap_or(false); + self.llvm_clang = clang.unwrap_or(false); + self.llvm_enable_warnings = enable_warnings.unwrap_or(false); + self.llvm_build_config = build_config.clone().unwrap_or(Default::default()); + + self.llvm_from_ci = self.parse_download_ci_llvm(download_ci_llvm, self.llvm_assertions); + + if self.llvm_from_ci { + let warn = |option: &str| { + println!( + "WARNING: `{option}` will only be used on `compiler/rustc_llvm` build, not for the LLVM build." + ); + println!( + "HELP: To use `{option}` for LLVM builds, set `download-ci-llvm` option to false." + ); + }; + + if static_libstdcpp.is_some() { + warn("static-libstdcpp"); + } + + if link_shared.is_some() { + warn("link-shared"); + } + + // FIXME(#129153): instead of all the ad-hoc `download-ci-llvm` checks that follow, + // use the `builder-config` present in tarballs since #128822 to compare the local + // config to the ones used to build the LLVM artifacts on CI, and only notify users + // if they've chosen a different value. + + if libzstd.is_some() { + println!( + "WARNING: when using `download-ci-llvm`, the local `llvm.libzstd` option, \ + like almost all `llvm.*` options, will be ignored and set by the LLVM CI \ + artifacts builder config." + ); + println!( + "HELP: To use `llvm.libzstd` for LLVM/LLD builds, set `download-ci-llvm` option to false." + ); + } + } + + if !self.llvm_from_ci && self.llvm_thin_lto && link_shared.is_none() { + // If we're building with ThinLTO on, by default we want to link + // to LLVM shared, to avoid re-doing ThinLTO (which happens in + // the link step) with each stage. + self.llvm_link_shared.set(Some(true)); + } + } else { + self.llvm_from_ci = self.parse_download_ci_llvm(None, false); + } + + self.llvm_tests = llvm_tests.unwrap_or(false); + self.llvm_enzyme = llvm_enzyme.unwrap_or(false); + self.llvm_offload = llvm_offload.unwrap_or(false); + self.llvm_plugins = llvm_plugins.unwrap_or(false); + } +} diff --git a/src/bootstrap/src/core/config/toml/mod.rs b/src/bootstrap/src/core/config/toml/mod.rs new file mode 100644 index 00000000000..ac4e249e580 --- /dev/null +++ b/src/bootstrap/src/core/config/toml/mod.rs @@ -0,0 +1,184 @@ +//! This module defines the structures that directly mirror the `bootstrap.toml` +//! file's format. These types are used for `serde` deserialization. +//! +//! Crucially, this module also houses the core logic for loading, parsing, and merging +//! these raw TOML configurations from various sources (the main `bootstrap.toml`, +//! included files, profile defaults, and command-line overrides). This processed +//! TOML data then serves as an intermediate representation, which is further +//! transformed and applied to the final [`Config`] struct. + +use serde::Deserialize; +use serde_derive::Deserialize; +pub mod build; +pub mod change_id; +pub mod dist; +pub mod gcc; +pub mod install; +pub mod llvm; +pub mod rust; +pub mod target; + +use build::Build; +use change_id::{ChangeId, ChangeIdWrapper}; +use dist::Dist; +use gcc::Gcc; +use install::Install; +use llvm::Llvm; +use rust::Rust; +use target::TomlTarget; + +use crate::core::config::{Merge, ReplaceOpt}; +use crate::{Config, HashMap, HashSet, Path, PathBuf, exit, fs, t}; + +/// Structure of the `bootstrap.toml` file that configuration is read from. +/// +/// This structure uses `Decodable` to automatically decode a TOML configuration +/// file into this format, and then this is traversed and written into the above +/// `Config` structure. +#[derive(Deserialize, Default)] +#[serde(deny_unknown_fields, rename_all = "kebab-case")] +pub(crate) struct TomlConfig { + #[serde(flatten)] + pub(crate) change_id: ChangeIdWrapper, + pub(super) build: Option<Build>, + pub(super) install: Option<Install>, + pub(super) llvm: Option<Llvm>, + pub(super) gcc: Option<Gcc>, + pub(super) rust: Option<Rust>, + pub(super) target: Option<HashMap<String, TomlTarget>>, + pub(super) dist: Option<Dist>, + pub(super) profile: Option<String>, + pub(super) include: Option<Vec<PathBuf>>, +} + +impl Merge for TomlConfig { + fn merge( + &mut self, + parent_config_path: Option<PathBuf>, + included_extensions: &mut HashSet<PathBuf>, + TomlConfig { build, install, llvm, gcc, rust, dist, target, profile, change_id, include }: Self, + replace: ReplaceOpt, + ) { + fn do_merge<T: Merge>(x: &mut Option<T>, y: Option<T>, replace: ReplaceOpt) { + if let Some(new) = y { + if let Some(original) = x { + original.merge(None, &mut Default::default(), new, replace); + } else { + *x = Some(new); + } + } + } + + self.change_id.inner.merge(None, &mut Default::default(), change_id.inner, replace); + self.profile.merge(None, &mut Default::default(), profile, replace); + + do_merge(&mut self.build, build, replace); + do_merge(&mut self.install, install, replace); + do_merge(&mut self.llvm, llvm, replace); + do_merge(&mut self.gcc, gcc, replace); + do_merge(&mut self.rust, rust, replace); + do_merge(&mut self.dist, dist, replace); + + match (self.target.as_mut(), target) { + (_, None) => {} + (None, Some(target)) => self.target = Some(target), + (Some(original_target), Some(new_target)) => { + for (triple, new) in new_target { + if let Some(original) = original_target.get_mut(&triple) { + original.merge(None, &mut Default::default(), new, replace); + } else { + original_target.insert(triple, new); + } + } + } + } + + let parent_dir = parent_config_path + .as_ref() + .and_then(|p| p.parent().map(ToOwned::to_owned)) + .unwrap_or_default(); + + // `include` handled later since we ignore duplicates using `ReplaceOpt::IgnoreDuplicate` to + // keep the upper-level configuration to take precedence. + for include_path in include.clone().unwrap_or_default().iter().rev() { + let include_path = parent_dir.join(include_path); + let include_path = include_path.canonicalize().unwrap_or_else(|e| { + eprintln!("ERROR: Failed to canonicalize '{}' path: {e}", include_path.display()); + exit!(2); + }); + + let included_toml = Config::get_toml_inner(&include_path).unwrap_or_else(|e| { + eprintln!("ERROR: Failed to parse '{}': {e}", include_path.display()); + exit!(2); + }); + + assert!( + included_extensions.insert(include_path.clone()), + "Cyclic inclusion detected: '{}' is being included again before its previous inclusion was fully processed.", + include_path.display() + ); + + self.merge( + Some(include_path.clone()), + included_extensions, + included_toml, + // Ensures that parent configuration always takes precedence + // over child configurations. + ReplaceOpt::IgnoreDuplicate, + ); + + included_extensions.remove(&include_path); + } + } +} + +/// This file is embedded in the overlay directory of the tarball sources. It is +/// useful in scenarios where developers want to see how the tarball sources were +/// generated. +/// +/// We also use this file to compare the host's bootstrap.toml against the CI rustc builder +/// configuration to detect any incompatible options. +pub const BUILDER_CONFIG_FILENAME: &str = "builder-config"; + +impl Config { + pub(crate) fn get_builder_toml(&self, build_name: &str) -> Result<TomlConfig, toml::de::Error> { + if self.dry_run() { + return Ok(TomlConfig::default()); + } + + let builder_config_path = + self.out.join(self.build.triple).join(build_name).join(BUILDER_CONFIG_FILENAME); + Self::get_toml(&builder_config_path) + } + + pub(crate) fn get_toml(file: &Path) -> Result<TomlConfig, toml::de::Error> { + #[cfg(test)] + return Ok(TomlConfig::default()); + + #[cfg(not(test))] + Self::get_toml_inner(file) + } + + pub(crate) fn get_toml_inner(file: &Path) -> Result<TomlConfig, toml::de::Error> { + let contents = + t!(fs::read_to_string(file), format!("config file {} not found", file.display())); + // Deserialize to Value and then TomlConfig to prevent the Deserialize impl of + // TomlConfig and sub types to be monomorphized 5x by toml. + toml::from_str(&contents) + .and_then(|table: toml::Value| TomlConfig::deserialize(table)) + .inspect_err(|_| { + if let Ok(ChangeIdWrapper { inner: Some(ChangeId::Id(id)) }) = + toml::from_str::<toml::Value>(&contents) + .and_then(|table: toml::Value| ChangeIdWrapper::deserialize(table)) + { + let changes = crate::find_recent_config_change_ids(id); + if !changes.is_empty() { + println!( + "WARNING: There have been changes to x.py since you last updated:\n{}", + crate::human_readable_changes(changes) + ); + } + } + }) + } +} diff --git a/src/bootstrap/src/core/config/toml/rust.rs b/src/bootstrap/src/core/config/toml/rust.rs new file mode 100644 index 00000000000..81f95f356a5 --- /dev/null +++ b/src/bootstrap/src/core/config/toml/rust.rs @@ -0,0 +1,664 @@ +//! This module defines the `Rust` struct, which represents the `[rust]` table +//! in the `bootstrap.toml` configuration file. + +use std::str::FromStr; + +use serde::{Deserialize, Deserializer}; + +use crate::core::build_steps::compile::CODEGEN_BACKEND_PREFIX; +use crate::core::config::toml::TomlConfig; +use crate::core::config::{ + DebuginfoLevel, Merge, ReplaceOpt, RustcLto, StringOrBool, set, threads_from_config, +}; +use crate::flags::Warnings; +use crate::{BTreeSet, Config, HashSet, PathBuf, TargetSelection, define_config, exit}; + +define_config! { + /// TOML representation of how the Rust build is configured. + struct Rust { + optimize: Option<RustOptimize> = "optimize", + debug: Option<bool> = "debug", + codegen_units: Option<u32> = "codegen-units", + codegen_units_std: Option<u32> = "codegen-units-std", + rustc_debug_assertions: Option<bool> = "debug-assertions", + randomize_layout: Option<bool> = "randomize-layout", + std_debug_assertions: Option<bool> = "debug-assertions-std", + tools_debug_assertions: Option<bool> = "debug-assertions-tools", + overflow_checks: Option<bool> = "overflow-checks", + overflow_checks_std: Option<bool> = "overflow-checks-std", + debug_logging: Option<bool> = "debug-logging", + debuginfo_level: Option<DebuginfoLevel> = "debuginfo-level", + debuginfo_level_rustc: Option<DebuginfoLevel> = "debuginfo-level-rustc", + debuginfo_level_std: Option<DebuginfoLevel> = "debuginfo-level-std", + debuginfo_level_tools: Option<DebuginfoLevel> = "debuginfo-level-tools", + debuginfo_level_tests: Option<DebuginfoLevel> = "debuginfo-level-tests", + backtrace: Option<bool> = "backtrace", + incremental: Option<bool> = "incremental", + default_linker: Option<String> = "default-linker", + channel: Option<String> = "channel", + // FIXME: Remove this field at Q2 2025, it has been replaced by build.description + description: Option<String> = "description", + musl_root: Option<String> = "musl-root", + rpath: Option<bool> = "rpath", + strip: Option<bool> = "strip", + frame_pointers: Option<bool> = "frame-pointers", + stack_protector: Option<String> = "stack-protector", + verbose_tests: Option<bool> = "verbose-tests", + optimize_tests: Option<bool> = "optimize-tests", + codegen_tests: Option<bool> = "codegen-tests", + omit_git_hash: Option<bool> = "omit-git-hash", + dist_src: Option<bool> = "dist-src", + save_toolstates: Option<String> = "save-toolstates", + codegen_backends: Option<Vec<String>> = "codegen-backends", + llvm_bitcode_linker: Option<bool> = "llvm-bitcode-linker", + lld: Option<bool> = "lld", + lld_mode: Option<LldMode> = "use-lld", + llvm_tools: Option<bool> = "llvm-tools", + deny_warnings: Option<bool> = "deny-warnings", + backtrace_on_ice: Option<bool> = "backtrace-on-ice", + verify_llvm_ir: Option<bool> = "verify-llvm-ir", + thin_lto_import_instr_limit: Option<u32> = "thin-lto-import-instr-limit", + remap_debuginfo: Option<bool> = "remap-debuginfo", + jemalloc: Option<bool> = "jemalloc", + test_compare_mode: Option<bool> = "test-compare-mode", + llvm_libunwind: Option<String> = "llvm-libunwind", + control_flow_guard: Option<bool> = "control-flow-guard", + ehcont_guard: Option<bool> = "ehcont-guard", + new_symbol_mangling: Option<bool> = "new-symbol-mangling", + profile_generate: Option<String> = "profile-generate", + profile_use: Option<String> = "profile-use", + // ignored; this is set from an env var set by bootstrap.py + download_rustc: Option<StringOrBool> = "download-rustc", + lto: Option<String> = "lto", + validate_mir_opts: Option<u32> = "validate-mir-opts", + std_features: Option<BTreeSet<String>> = "std-features", + } +} + +/// LLD in bootstrap works like this: +/// - Self-contained lld: use `rust-lld` from the compiler's sysroot +/// - External: use an external `lld` binary +/// +/// It is configured depending on the target: +/// 1) Everything except MSVC +/// - Self-contained: `-Clinker-flavor=gnu-lld-cc -Clink-self-contained=+linker` +/// - External: `-Clinker-flavor=gnu-lld-cc` +/// 2) MSVC +/// - Self-contained: `-Clinker=<path to rust-lld>` +/// - External: `-Clinker=lld` +#[derive(Copy, Clone, Default, Debug, PartialEq)] +pub enum LldMode { + /// Do not use LLD + #[default] + Unused, + /// Use `rust-lld` from the compiler's sysroot + SelfContained, + /// Use an externally provided `lld` binary. + /// Note that the linker name cannot be overridden, the binary has to be named `lld` and it has + /// to be in $PATH. + External, +} + +impl LldMode { + pub fn is_used(&self) -> bool { + match self { + LldMode::SelfContained | LldMode::External => true, + LldMode::Unused => false, + } + } +} + +impl<'de> Deserialize<'de> for LldMode { + fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> + where + D: Deserializer<'de>, + { + struct LldModeVisitor; + + impl serde::de::Visitor<'_> for LldModeVisitor { + type Value = LldMode; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("one of true, 'self-contained' or 'external'") + } + + fn visit_bool<E>(self, v: bool) -> Result<Self::Value, E> + where + E: serde::de::Error, + { + Ok(if v { LldMode::External } else { LldMode::Unused }) + } + + fn visit_str<E>(self, v: &str) -> Result<Self::Value, E> + where + E: serde::de::Error, + { + match v { + "external" => Ok(LldMode::External), + "self-contained" => Ok(LldMode::SelfContained), + _ => Err(E::custom(format!("unknown mode {v}"))), + } + } + } + + deserializer.deserialize_any(LldModeVisitor) + } +} + +#[derive(Clone, Debug, PartialEq, Eq)] +pub enum RustOptimize { + String(String), + Int(u8), + Bool(bool), +} + +impl Default for RustOptimize { + fn default() -> RustOptimize { + RustOptimize::Bool(false) + } +} + +impl<'de> Deserialize<'de> for RustOptimize { + fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> + where + D: Deserializer<'de>, + { + deserializer.deserialize_any(OptimizeVisitor) + } +} + +struct OptimizeVisitor; + +impl serde::de::Visitor<'_> for OptimizeVisitor { + type Value = RustOptimize; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str(r#"one of: 0, 1, 2, 3, "s", "z", true, false"#) + } + + fn visit_str<E>(self, value: &str) -> Result<Self::Value, E> + where + E: serde::de::Error, + { + if matches!(value, "s" | "z") { + Ok(RustOptimize::String(value.to_string())) + } else { + Err(serde::de::Error::custom(format_optimize_error_msg(value))) + } + } + + fn visit_i64<E>(self, value: i64) -> Result<Self::Value, E> + where + E: serde::de::Error, + { + if matches!(value, 0..=3) { + Ok(RustOptimize::Int(value as u8)) + } else { + Err(serde::de::Error::custom(format_optimize_error_msg(value))) + } + } + + fn visit_bool<E>(self, value: bool) -> Result<Self::Value, E> + where + E: serde::de::Error, + { + Ok(RustOptimize::Bool(value)) + } +} + +fn format_optimize_error_msg(v: impl std::fmt::Display) -> String { + format!( + r#"unrecognized option for rust optimize: "{v}", expected one of 0, 1, 2, 3, "s", "z", true, false"# + ) +} + +impl RustOptimize { + pub(crate) fn is_release(&self) -> bool { + match &self { + RustOptimize::Bool(true) | RustOptimize::String(_) => true, + RustOptimize::Int(i) => *i > 0, + RustOptimize::Bool(false) => false, + } + } + + pub(crate) fn get_opt_level(&self) -> Option<String> { + match &self { + RustOptimize::String(s) => Some(s.clone()), + RustOptimize::Int(i) => Some(i.to_string()), + RustOptimize::Bool(_) => None, + } + } +} + +/// Compares the current Rust options against those in the CI rustc builder and detects any incompatible options. +/// It does this by destructuring the `Rust` instance to make sure every `Rust` field is covered and not missing. +pub fn check_incompatible_options_for_ci_rustc( + host: TargetSelection, + current_config_toml: TomlConfig, + ci_config_toml: TomlConfig, +) -> Result<(), String> { + macro_rules! err { + ($current:expr, $expected:expr, $config_section:expr) => { + if let Some(current) = &$current { + if Some(current) != $expected.as_ref() { + return Err(format!( + "ERROR: Setting `{}` is incompatible with `rust.download-rustc`. \ + Current value: {:?}, Expected value(s): {}{:?}", + format!("{}.{}", $config_section, stringify!($expected).replace("_", "-")), + $current, + if $expected.is_some() { "None/" } else { "" }, + $expected, + )); + }; + }; + }; + } + + macro_rules! warn { + ($current:expr, $expected:expr, $config_section:expr) => { + if let Some(current) = &$current { + if Some(current) != $expected.as_ref() { + println!( + "WARNING: `{}` has no effect with `rust.download-rustc`. \ + Current value: {:?}, Expected value(s): {}{:?}", + format!("{}.{}", $config_section, stringify!($expected).replace("_", "-")), + $current, + if $expected.is_some() { "None/" } else { "" }, + $expected, + ); + }; + }; + }; + } + + let current_profiler = current_config_toml.build.as_ref().and_then(|b| b.profiler); + let profiler = ci_config_toml.build.as_ref().and_then(|b| b.profiler); + err!(current_profiler, profiler, "build"); + + let current_optimized_compiler_builtins = + current_config_toml.build.as_ref().and_then(|b| b.optimized_compiler_builtins); + let optimized_compiler_builtins = + ci_config_toml.build.as_ref().and_then(|b| b.optimized_compiler_builtins); + err!(current_optimized_compiler_builtins, optimized_compiler_builtins, "build"); + + // We always build the in-tree compiler on cross targets, so we only care + // about the host target here. + let host_str = host.to_string(); + if let Some(current_cfg) = current_config_toml.target.as_ref().and_then(|c| c.get(&host_str)) + && current_cfg.profiler.is_some() + { + let ci_target_toml = ci_config_toml.target.as_ref().and_then(|c| c.get(&host_str)); + let ci_cfg = ci_target_toml.ok_or(format!( + "Target specific config for '{host_str}' is not present for CI-rustc" + ))?; + + let profiler = &ci_cfg.profiler; + err!(current_cfg.profiler, profiler, "build"); + + let optimized_compiler_builtins = &ci_cfg.optimized_compiler_builtins; + err!(current_cfg.optimized_compiler_builtins, optimized_compiler_builtins, "build"); + } + + let (Some(current_rust_config), Some(ci_rust_config)) = + (current_config_toml.rust, ci_config_toml.rust) + else { + return Ok(()); + }; + + let Rust { + // Following options are the CI rustc incompatible ones. + optimize, + randomize_layout, + debug_logging, + debuginfo_level_rustc, + llvm_tools, + llvm_bitcode_linker, + lto, + stack_protector, + strip, + lld_mode, + jemalloc, + rpath, + channel, + description, + incremental, + default_linker, + std_features, + + // Rest of the options can simply be ignored. + debug: _, + codegen_units: _, + codegen_units_std: _, + rustc_debug_assertions: _, + std_debug_assertions: _, + tools_debug_assertions: _, + overflow_checks: _, + overflow_checks_std: _, + debuginfo_level: _, + debuginfo_level_std: _, + debuginfo_level_tools: _, + debuginfo_level_tests: _, + backtrace: _, + musl_root: _, + verbose_tests: _, + optimize_tests: _, + codegen_tests: _, + omit_git_hash: _, + dist_src: _, + save_toolstates: _, + codegen_backends: _, + lld: _, + deny_warnings: _, + backtrace_on_ice: _, + verify_llvm_ir: _, + thin_lto_import_instr_limit: _, + remap_debuginfo: _, + test_compare_mode: _, + llvm_libunwind: _, + control_flow_guard: _, + ehcont_guard: _, + new_symbol_mangling: _, + profile_generate: _, + profile_use: _, + download_rustc: _, + validate_mir_opts: _, + frame_pointers: _, + } = ci_rust_config; + + // There are two kinds of checks for CI rustc incompatible options: + // 1. Checking an option that may change the compiler behaviour/output. + // 2. Checking an option that have no effect on the compiler behaviour/output. + // + // If the option belongs to the first category, we call `err` macro for a hard error; + // otherwise, we just print a warning with `warn` macro. + + err!(current_rust_config.optimize, optimize, "rust"); + err!(current_rust_config.randomize_layout, randomize_layout, "rust"); + err!(current_rust_config.debug_logging, debug_logging, "rust"); + err!(current_rust_config.debuginfo_level_rustc, debuginfo_level_rustc, "rust"); + err!(current_rust_config.rpath, rpath, "rust"); + err!(current_rust_config.strip, strip, "rust"); + err!(current_rust_config.lld_mode, lld_mode, "rust"); + err!(current_rust_config.llvm_tools, llvm_tools, "rust"); + err!(current_rust_config.llvm_bitcode_linker, llvm_bitcode_linker, "rust"); + err!(current_rust_config.jemalloc, jemalloc, "rust"); + err!(current_rust_config.default_linker, default_linker, "rust"); + err!(current_rust_config.stack_protector, stack_protector, "rust"); + err!(current_rust_config.lto, lto, "rust"); + err!(current_rust_config.std_features, std_features, "rust"); + + warn!(current_rust_config.channel, channel, "rust"); + warn!(current_rust_config.description, description, "rust"); + warn!(current_rust_config.incremental, incremental, "rust"); + + Ok(()) +} + +impl Config { + pub fn apply_rust_config( + &mut self, + toml_rust: Option<Rust>, + warnings: Warnings, + description: &mut Option<String>, + ) { + let mut debug = None; + let mut rustc_debug_assertions = None; + let mut std_debug_assertions = None; + let mut tools_debug_assertions = None; + let mut overflow_checks = None; + let mut overflow_checks_std = None; + let mut debug_logging = None; + let mut debuginfo_level = None; + let mut debuginfo_level_rustc = None; + let mut debuginfo_level_std = None; + let mut debuginfo_level_tools = None; + let mut debuginfo_level_tests = None; + let mut optimize = None; + let mut lld_enabled = None; + let mut std_features = None; + + if let Some(rust) = toml_rust { + let Rust { + optimize: optimize_toml, + debug: debug_toml, + codegen_units, + codegen_units_std, + rustc_debug_assertions: rustc_debug_assertions_toml, + std_debug_assertions: std_debug_assertions_toml, + tools_debug_assertions: tools_debug_assertions_toml, + overflow_checks: overflow_checks_toml, + overflow_checks_std: overflow_checks_std_toml, + debug_logging: debug_logging_toml, + debuginfo_level: debuginfo_level_toml, + debuginfo_level_rustc: debuginfo_level_rustc_toml, + debuginfo_level_std: debuginfo_level_std_toml, + debuginfo_level_tools: debuginfo_level_tools_toml, + debuginfo_level_tests: debuginfo_level_tests_toml, + backtrace, + incremental, + randomize_layout, + default_linker, + channel: _, // already handled above + description: rust_description, + musl_root, + rpath, + verbose_tests, + optimize_tests, + codegen_tests, + omit_git_hash: _, // already handled above + dist_src, + save_toolstates, + codegen_backends, + lld: lld_enabled_toml, + llvm_tools, + llvm_bitcode_linker, + deny_warnings, + backtrace_on_ice, + verify_llvm_ir, + thin_lto_import_instr_limit, + remap_debuginfo, + jemalloc, + test_compare_mode, + llvm_libunwind, + control_flow_guard, + ehcont_guard, + new_symbol_mangling, + profile_generate, + profile_use, + download_rustc, + lto, + validate_mir_opts, + frame_pointers, + stack_protector, + strip, + lld_mode, + std_features: std_features_toml, + } = rust; + + // FIXME(#133381): alt rustc builds currently do *not* have rustc debug assertions + // enabled. We should not download a CI alt rustc if we need rustc to have debug + // assertions (e.g. for crashes test suite). This can be changed once something like + // [Enable debug assertions on alt + // builds](https://github.com/rust-lang/rust/pull/131077) lands. + // + // Note that `rust.debug = true` currently implies `rust.debug-assertions = true`! + // + // This relies also on the fact that the global default for `download-rustc` will be + // `false` if it's not explicitly set. + let debug_assertions_requested = matches!(rustc_debug_assertions_toml, Some(true)) + || (matches!(debug_toml, Some(true)) + && !matches!(rustc_debug_assertions_toml, Some(false))); + + if debug_assertions_requested + && let Some(ref opt) = download_rustc + && opt.is_string_or_true() + { + eprintln!( + "WARN: currently no CI rustc builds have rustc debug assertions \ + enabled. Please either set `rust.debug-assertions` to `false` if you \ + want to use download CI rustc or set `rust.download-rustc` to `false`." + ); + } + + self.download_rustc_commit = self.download_ci_rustc_commit( + download_rustc, + debug_assertions_requested, + self.llvm_assertions, + ); + + debug = debug_toml; + rustc_debug_assertions = rustc_debug_assertions_toml; + std_debug_assertions = std_debug_assertions_toml; + tools_debug_assertions = tools_debug_assertions_toml; + overflow_checks = overflow_checks_toml; + overflow_checks_std = overflow_checks_std_toml; + debug_logging = debug_logging_toml; + debuginfo_level = debuginfo_level_toml; + debuginfo_level_rustc = debuginfo_level_rustc_toml; + debuginfo_level_std = debuginfo_level_std_toml; + debuginfo_level_tools = debuginfo_level_tools_toml; + debuginfo_level_tests = debuginfo_level_tests_toml; + lld_enabled = lld_enabled_toml; + std_features = std_features_toml; + + optimize = optimize_toml; + self.rust_new_symbol_mangling = new_symbol_mangling; + set(&mut self.rust_optimize_tests, optimize_tests); + set(&mut self.codegen_tests, codegen_tests); + set(&mut self.rust_rpath, rpath); + set(&mut self.rust_strip, strip); + set(&mut self.rust_frame_pointers, frame_pointers); + self.rust_stack_protector = stack_protector; + set(&mut self.jemalloc, jemalloc); + set(&mut self.test_compare_mode, test_compare_mode); + set(&mut self.backtrace, backtrace); + if rust_description.is_some() { + eprintln!( + "Warning: rust.description is deprecated. Use build.description instead." + ); + } + if description.is_none() { + *description = rust_description; + } + set(&mut self.rust_dist_src, dist_src); + set(&mut self.verbose_tests, verbose_tests); + // in the case "false" is set explicitly, do not overwrite the command line args + if let Some(true) = incremental { + self.incremental = true; + } + set(&mut self.lld_mode, lld_mode); + set(&mut self.llvm_bitcode_linker_enabled, llvm_bitcode_linker); + + self.rust_randomize_layout = randomize_layout.unwrap_or_default(); + self.llvm_tools_enabled = llvm_tools.unwrap_or(true); + + self.llvm_enzyme = self.channel == "dev" || self.channel == "nightly"; + self.rustc_default_linker = default_linker; + self.musl_root = musl_root.map(PathBuf::from); + self.save_toolstates = save_toolstates.map(PathBuf::from); + set( + &mut self.deny_warnings, + match warnings { + Warnings::Deny => Some(true), + Warnings::Warn => Some(false), + Warnings::Default => deny_warnings, + }, + ); + set(&mut self.backtrace_on_ice, backtrace_on_ice); + set(&mut self.rust_verify_llvm_ir, verify_llvm_ir); + self.rust_thin_lto_import_instr_limit = thin_lto_import_instr_limit; + set(&mut self.rust_remap_debuginfo, remap_debuginfo); + set(&mut self.control_flow_guard, control_flow_guard); + set(&mut self.ehcont_guard, ehcont_guard); + self.llvm_libunwind_default = + llvm_libunwind.map(|v| v.parse().expect("failed to parse rust.llvm-libunwind")); + + if let Some(ref backends) = codegen_backends { + let available_backends = ["llvm", "cranelift", "gcc"]; + + self.rust_codegen_backends = backends.iter().map(|s| { + if let Some(backend) = s.strip_prefix(CODEGEN_BACKEND_PREFIX) { + if available_backends.contains(&backend) { + panic!("Invalid value '{s}' for 'rust.codegen-backends'. Instead, please use '{backend}'."); + } else { + println!("HELP: '{s}' for 'rust.codegen-backends' might fail. \ + Codegen backends are mostly defined without the '{CODEGEN_BACKEND_PREFIX}' prefix. \ + In this case, it would be referred to as '{backend}'."); + } + } + + s.clone() + }).collect(); + } + + self.rust_codegen_units = codegen_units.map(threads_from_config); + self.rust_codegen_units_std = codegen_units_std.map(threads_from_config); + + if self.rust_profile_use.is_none() { + self.rust_profile_use = profile_use; + } + + if self.rust_profile_generate.is_none() { + self.rust_profile_generate = profile_generate; + } + + self.rust_lto = + lto.as_deref().map(|value| RustcLto::from_str(value).unwrap()).unwrap_or_default(); + self.rust_validate_mir_opts = validate_mir_opts; + } + + self.rust_optimize = optimize.unwrap_or(RustOptimize::Bool(true)); + + // We make `x86_64-unknown-linux-gnu` use the self-contained linker by default, so we will + // build our internal lld and use it as the default linker, by setting the `rust.lld` config + // to true by default: + // - on the `x86_64-unknown-linux-gnu` target + // - on the `dev` and `nightly` channels + // - when building our in-tree llvm (i.e. the target has not set an `llvm-config`), so that + // we're also able to build the corresponding lld + // - or when using an external llvm that's downloaded from CI, which also contains our prebuilt + // lld + // - otherwise, we'd be using an external llvm, and lld would not necessarily available and + // thus, disabled + // - similarly, lld will not be built nor used by default when explicitly asked not to, e.g. + // when the config sets `rust.lld = false` + if self.build.triple == "x86_64-unknown-linux-gnu" + && self.hosts == [self.build] + && (self.channel == "dev" || self.channel == "nightly") + { + let no_llvm_config = self + .target_config + .get(&self.build) + .is_some_and(|target_config| target_config.llvm_config.is_none()); + let enable_lld = self.llvm_from_ci || no_llvm_config; + // Prefer the config setting in case an explicit opt-out is needed. + self.lld_enabled = lld_enabled.unwrap_or(enable_lld); + } else { + set(&mut self.lld_enabled, lld_enabled); + } + + let default_std_features = BTreeSet::from([String::from("panic-unwind")]); + self.rust_std_features = std_features.unwrap_or(default_std_features); + + let default = debug == Some(true); + self.rustc_debug_assertions = rustc_debug_assertions.unwrap_or(default); + self.std_debug_assertions = std_debug_assertions.unwrap_or(self.rustc_debug_assertions); + self.tools_debug_assertions = tools_debug_assertions.unwrap_or(self.rustc_debug_assertions); + self.rust_overflow_checks = overflow_checks.unwrap_or(default); + self.rust_overflow_checks_std = overflow_checks_std.unwrap_or(self.rust_overflow_checks); + + self.rust_debug_logging = debug_logging.unwrap_or(self.rustc_debug_assertions); + + let with_defaults = |debuginfo_level_specific: Option<_>| { + debuginfo_level_specific.or(debuginfo_level).unwrap_or(if debug == Some(true) { + DebuginfoLevel::Limited + } else { + DebuginfoLevel::None + }) + }; + self.rust_debuginfo_level_rustc = with_defaults(debuginfo_level_rustc); + self.rust_debuginfo_level_std = with_defaults(debuginfo_level_std); + self.rust_debuginfo_level_tools = with_defaults(debuginfo_level_tools); + self.rust_debuginfo_level_tests = debuginfo_level_tests.unwrap_or(DebuginfoLevel::None); + } +} diff --git a/src/bootstrap/src/core/config/toml/target.rs b/src/bootstrap/src/core/config/toml/target.rs new file mode 100644 index 00000000000..7f074d1b25e --- /dev/null +++ b/src/bootstrap/src/core/config/toml/target.rs @@ -0,0 +1,174 @@ +//! This module defines the structures and logic for handling target-specific configuration +//! within the `bootstrap.toml` file. This allows you to customize build settings, tools, +//! and flags for individual compilation targets. +//! +//! It includes: +//! +//! * [`TomlTarget`]: This struct directly mirrors the `[target.<triple>]` sections in your +//! `bootstrap.toml`. It's used for deserializing raw TOML data for a specific target. +//! * [`Target`]: This struct represents the processed and validated configuration for a +//! build target, which is is stored in the main [`Config`] structure. +//! * [`Config::apply_target_config`]: This method processes the `TomlTarget` data and +//! applies it to the global [`Config`], ensuring proper path resolution, validation, +//! and integration with other build settings. + +use std::collections::HashMap; + +use serde::{Deserialize, Deserializer}; + +use crate::core::build_steps::compile::CODEGEN_BACKEND_PREFIX; +use crate::core::config::{LlvmLibunwind, Merge, ReplaceOpt, SplitDebuginfo, StringOrBool}; +use crate::{Config, HashSet, PathBuf, TargetSelection, define_config, exit}; + +define_config! { + /// TOML representation of how each build target is configured. + struct TomlTarget { + cc: Option<String> = "cc", + cxx: Option<String> = "cxx", + ar: Option<String> = "ar", + ranlib: Option<String> = "ranlib", + default_linker: Option<PathBuf> = "default-linker", + linker: Option<String> = "linker", + split_debuginfo: Option<String> = "split-debuginfo", + llvm_config: Option<String> = "llvm-config", + llvm_has_rust_patches: Option<bool> = "llvm-has-rust-patches", + llvm_filecheck: Option<String> = "llvm-filecheck", + llvm_libunwind: Option<String> = "llvm-libunwind", + sanitizers: Option<bool> = "sanitizers", + profiler: Option<StringOrBool> = "profiler", + rpath: Option<bool> = "rpath", + crt_static: Option<bool> = "crt-static", + musl_root: Option<String> = "musl-root", + musl_libdir: Option<String> = "musl-libdir", + wasi_root: Option<String> = "wasi-root", + qemu_rootfs: Option<String> = "qemu-rootfs", + no_std: Option<bool> = "no-std", + codegen_backends: Option<Vec<String>> = "codegen-backends", + runner: Option<String> = "runner", + optimized_compiler_builtins: Option<bool> = "optimized-compiler-builtins", + jemalloc: Option<bool> = "jemalloc", + } +} + +/// Per-target configuration stored in the global configuration structure. +#[derive(Debug, Default, Clone, PartialEq, Eq)] +pub struct Target { + /// Some(path to llvm-config) if using an external LLVM. + pub llvm_config: Option<PathBuf>, + pub llvm_has_rust_patches: Option<bool>, + /// Some(path to FileCheck) if one was specified. + pub llvm_filecheck: Option<PathBuf>, + pub llvm_libunwind: Option<LlvmLibunwind>, + pub cc: Option<PathBuf>, + pub cxx: Option<PathBuf>, + pub ar: Option<PathBuf>, + pub ranlib: Option<PathBuf>, + pub default_linker: Option<PathBuf>, + pub linker: Option<PathBuf>, + pub split_debuginfo: Option<SplitDebuginfo>, + pub sanitizers: Option<bool>, + pub profiler: Option<StringOrBool>, + pub rpath: Option<bool>, + pub crt_static: Option<bool>, + pub musl_root: Option<PathBuf>, + pub musl_libdir: Option<PathBuf>, + pub wasi_root: Option<PathBuf>, + pub qemu_rootfs: Option<PathBuf>, + pub runner: Option<String>, + pub no_std: bool, + pub codegen_backends: Option<Vec<String>>, + pub optimized_compiler_builtins: Option<bool>, + pub jemalloc: Option<bool>, +} + +impl Target { + pub fn from_triple(triple: &str) -> Self { + let mut target: Self = Default::default(); + if triple.contains("-none") || triple.contains("nvptx") || triple.contains("switch") { + target.no_std = true; + } + if triple.contains("emscripten") { + target.runner = Some("node".into()); + } + target + } +} + +impl Config { + pub fn apply_target_config(&mut self, toml_target: Option<HashMap<String, TomlTarget>>) { + if let Some(t) = toml_target { + for (triple, cfg) in t { + let mut target = Target::from_triple(&triple); + + if let Some(ref s) = cfg.llvm_config { + if self.download_rustc_commit.is_some() && triple == *self.build.triple { + panic!( + "setting llvm_config for the host is incompatible with download-rustc" + ); + } + target.llvm_config = Some(self.src.join(s)); + } + if let Some(patches) = cfg.llvm_has_rust_patches { + assert!( + self.submodules == Some(false) || cfg.llvm_config.is_some(), + "use of `llvm-has-rust-patches` is restricted to cases where either submodules are disabled or llvm-config been provided" + ); + target.llvm_has_rust_patches = Some(patches); + } + if let Some(ref s) = cfg.llvm_filecheck { + target.llvm_filecheck = Some(self.src.join(s)); + } + target.llvm_libunwind = cfg.llvm_libunwind.as_ref().map(|v| { + v.parse().unwrap_or_else(|_| { + panic!("failed to parse target.{triple}.llvm-libunwind") + }) + }); + if let Some(s) = cfg.no_std { + target.no_std = s; + } + target.cc = cfg.cc.map(PathBuf::from); + target.cxx = cfg.cxx.map(PathBuf::from); + target.ar = cfg.ar.map(PathBuf::from); + target.ranlib = cfg.ranlib.map(PathBuf::from); + target.linker = cfg.linker.map(PathBuf::from); + target.crt_static = cfg.crt_static; + target.musl_root = cfg.musl_root.map(PathBuf::from); + target.musl_libdir = cfg.musl_libdir.map(PathBuf::from); + target.wasi_root = cfg.wasi_root.map(PathBuf::from); + target.qemu_rootfs = cfg.qemu_rootfs.map(PathBuf::from); + target.runner = cfg.runner; + target.sanitizers = cfg.sanitizers; + target.profiler = cfg.profiler; + target.rpath = cfg.rpath; + target.optimized_compiler_builtins = cfg.optimized_compiler_builtins; + target.jemalloc = cfg.jemalloc; + + if let Some(ref backends) = cfg.codegen_backends { + let available_backends = ["llvm", "cranelift", "gcc"]; + + target.codegen_backends = Some(backends.iter().map(|s| { + if let Some(backend) = s.strip_prefix(CODEGEN_BACKEND_PREFIX) { + if available_backends.contains(&backend) { + panic!("Invalid value '{s}' for 'target.{triple}.codegen-backends'. Instead, please use '{backend}'."); + } else { + println!("HELP: '{s}' for 'target.{triple}.codegen-backends' might fail. \ + Codegen backends are mostly defined without the '{CODEGEN_BACKEND_PREFIX}' prefix. \ + In this case, it would be referred to as '{backend}'."); + } + } + + s.clone() + }).collect()); + } + + target.split_debuginfo = cfg.split_debuginfo.as_ref().map(|v| { + v.parse().unwrap_or_else(|_| { + panic!("invalid value for target.{triple}.split-debuginfo") + }) + }); + + self.target_config.insert(TargetSelection::from_user(&triple), target); + } + } + } +} diff --git a/src/bootstrap/src/core/download.rs b/src/bootstrap/src/core/download.rs index d942334d1c3..ba00b405c61 100644 --- a/src/bootstrap/src/core/download.rs +++ b/src/bootstrap/src/core/download.rs @@ -727,7 +727,7 @@ download-rustc = false use build_helper::git::PathFreshness; use crate::core::build_steps::llvm::detect_llvm_freshness; - use crate::core::config::check_incompatible_options_for_ci_llvm; + use crate::core::config::toml::llvm::check_incompatible_options_for_ci_llvm; if !self.llvm_from_ci { return; diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index e8cf25b1906..7658e7ad35f 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -371,10 +371,9 @@ fn clean_where_predicate<'tcx>( bounds: wrp.bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect(), }, - hir::WherePredicateKind::EqPredicate(wrp) => WherePredicate::EqPredicate { - lhs: clean_ty(wrp.lhs_ty, cx), - rhs: clean_ty(wrp.rhs_ty, cx).into(), - }, + // We should never actually reach this case because these predicates should've already been + // rejected in an earlier compiler pass. This feature isn't fully implemented (#20041). + hir::WherePredicateKind::EqPredicate(_) => bug!("EqPredicate"), }) } @@ -470,49 +469,37 @@ fn clean_projection_predicate<'tcx>( cx: &mut DocContext<'tcx>, ) -> WherePredicate { WherePredicate::EqPredicate { - lhs: clean_projection( - pred.map_bound(|p| { - // FIXME: This needs to be made resilient for `AliasTerm`s that - // are associated consts. - p.projection_term.expect_ty(cx.tcx) - }), - cx, - None, - ), + lhs: clean_projection(pred.map_bound(|p| p.projection_term), cx, None), rhs: clean_middle_term(pred.map_bound(|p| p.term), cx), } } fn clean_projection<'tcx>( - ty: ty::Binder<'tcx, ty::AliasTy<'tcx>>, + proj: ty::Binder<'tcx, ty::AliasTerm<'tcx>>, cx: &mut DocContext<'tcx>, - def_id: Option<DefId>, -) -> Type { - if cx.tcx.is_impl_trait_in_trait(ty.skip_binder().def_id) { - return clean_middle_opaque_bounds(cx, ty.skip_binder().def_id, ty.skip_binder().args); - } - + parent_def_id: Option<DefId>, +) -> QPathData { let trait_ = clean_trait_ref_with_constraints( cx, - ty.map_bound(|ty| ty.trait_ref(cx.tcx)), + proj.map_bound(|proj| proj.trait_ref(cx.tcx)), ThinVec::new(), ); - let self_type = clean_middle_ty(ty.map_bound(|ty| ty.self_ty()), cx, None, None); - let self_def_id = if let Some(def_id) = def_id { - cx.tcx.opt_parent(def_id).or(Some(def_id)) - } else { - self_type.def_id(&cx.cache) + let self_type = clean_middle_ty(proj.map_bound(|proj| proj.self_ty()), cx, None, None); + let self_def_id = match parent_def_id { + Some(parent_def_id) => cx.tcx.opt_parent(parent_def_id).or(Some(parent_def_id)), + None => self_type.def_id(&cx.cache), }; - let should_show_cast = compute_should_show_cast(self_def_id, &trait_, &self_type); - Type::QPath(Box::new(QPathData { - assoc: projection_to_path_segment(ty, cx), - should_show_cast, + let should_fully_qualify = should_fully_qualify_path(self_def_id, &trait_, &self_type); + + QPathData { + assoc: projection_to_path_segment(proj, cx), self_type, + should_fully_qualify, trait_: Some(trait_), - })) + } } -fn compute_should_show_cast(self_def_id: Option<DefId>, trait_: &Path, self_type: &Type) -> bool { +fn should_fully_qualify_path(self_def_id: Option<DefId>, trait_: &Path, self_type: &Type) -> bool { !trait_.segments.is_empty() && self_def_id .zip(Some(trait_.def_id())) @@ -520,18 +507,17 @@ fn compute_should_show_cast(self_def_id: Option<DefId>, trait_: &Path, self_type } fn projection_to_path_segment<'tcx>( - ty: ty::Binder<'tcx, ty::AliasTy<'tcx>>, + proj: ty::Binder<'tcx, ty::AliasTerm<'tcx>>, cx: &mut DocContext<'tcx>, ) -> PathSegment { - let def_id = ty.skip_binder().def_id; - let item = cx.tcx.associated_item(def_id); + let def_id = proj.skip_binder().def_id; let generics = cx.tcx.generics_of(def_id); PathSegment { - name: item.name(), + name: cx.tcx.item_name(def_id), args: GenericArgs::AngleBracketed { args: clean_middle_generic_args( cx, - ty.map_bound(|ty| &ty.args[generics.parent_count..]), + proj.map_bound(|ty| &ty.args[generics.parent_count..]), false, def_id, ), @@ -845,7 +831,7 @@ fn clean_ty_generics<'tcx>( .predicates .iter() .flat_map(|(pred, _)| { - let mut projection = None; + let mut proj_pred = None; let param_idx = { let bound_p = pred.kind(); match bound_p.skip_binder() { @@ -860,7 +846,7 @@ fn clean_ty_generics<'tcx>( ty::ClauseKind::Projection(p) if let ty::Param(param) = p.projection_term.self_ty().kind() => { - projection = Some(bound_p.rebind(p)); + proj_pred = Some(bound_p.rebind(p)); Some(param.index) } _ => None, @@ -874,22 +860,12 @@ fn clean_ty_generics<'tcx>( bounds.extend(pred.get_bounds().into_iter().flatten().cloned()); - if let Some(proj) = projection - && let lhs = clean_projection( - proj.map_bound(|p| { - // FIXME: This needs to be made resilient for `AliasTerm`s that - // are associated consts. - p.projection_term.expect_ty(cx.tcx) - }), - cx, - None, - ) - && let Some((_, trait_did, name)) = lhs.projection() - { + if let Some(pred) = proj_pred { + let lhs = clean_projection(pred.map_bound(|p| p.projection_term), cx, None); impl_trait_proj.entry(param_idx).or_default().push(( - trait_did, - name, - proj.map_bound(|p| p.term), + lhs.trait_.unwrap().def_id(), + lhs.assoc, + pred.map_bound(|p| p.term), )); } @@ -1695,10 +1671,11 @@ fn clean_qpath<'tcx>(hir_ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> Type register_res(cx, trait_.res); let self_def_id = DefId::local(qself.hir_id.owner.def_id.local_def_index); let self_type = clean_ty(qself, cx); - let should_show_cast = compute_should_show_cast(Some(self_def_id), &trait_, &self_type); + let should_fully_qualify = + should_fully_qualify_path(Some(self_def_id), &trait_, &self_type); Type::QPath(Box::new(QPathData { assoc: clean_path_segment(p.segments.last().expect("segments were empty"), cx), - should_show_cast, + should_fully_qualify, self_type, trait_: Some(trait_), })) @@ -1707,16 +1684,16 @@ fn clean_qpath<'tcx>(hir_ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> Type let ty = lower_ty(cx.tcx, hir_ty); let self_type = clean_ty(qself, cx); - let (trait_, should_show_cast) = match ty.kind() { + let (trait_, should_fully_qualify) = match ty.kind() { ty::Alias(ty::Projection, proj) => { let res = Res::Def(DefKind::Trait, proj.trait_ref(cx.tcx).def_id); let trait_ = clean_path(&hir::Path { span, res, segments: &[] }, cx); register_res(cx, trait_.res); let self_def_id = res.opt_def_id(); - let should_show_cast = - compute_should_show_cast(self_def_id, &trait_, &self_type); + let should_fully_qualify = + should_fully_qualify_path(self_def_id, &trait_, &self_type); - (Some(trait_), should_show_cast) + (Some(trait_), should_fully_qualify) } ty::Alias(ty::Inherent, _) => (None, false), // Rustdoc handles `ty::Error`s by turning them into `Type::Infer`s. @@ -1726,7 +1703,7 @@ fn clean_qpath<'tcx>(hir_ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> Type Type::QPath(Box::new(QPathData { assoc: clean_path_segment(segment, cx), - should_show_cast, + should_fully_qualify, self_type, trait_, })) @@ -2145,14 +2122,8 @@ pub(crate) fn clean_middle_ty<'tcx>( .map(|pb| AssocItemConstraint { assoc: projection_to_path_segment( pb.map_bound(|pb| { - pb - // HACK(compiler-errors): Doesn't actually matter what self - // type we put here, because we're only using the GAT's args. - .with_self_ty(cx.tcx, cx.tcx.types.self_param) + pb.with_self_ty(cx.tcx, cx.tcx.types.trait_object_dummy_self) .projection_term - // FIXME: This needs to be made resilient for `AliasTerm`s - // that are associated consts. - .expect_ty(cx.tcx) }), cx, ), @@ -2185,18 +2156,25 @@ pub(crate) fn clean_middle_ty<'tcx>( Tuple(t.iter().map(|t| clean_middle_ty(bound_ty.rebind(t), cx, None, None)).collect()) } - ty::Alias(ty::Projection, data) => { - clean_projection(bound_ty.rebind(data), cx, parent_def_id) + ty::Alias(ty::Projection, alias_ty @ ty::AliasTy { def_id, args, .. }) => { + if cx.tcx.is_impl_trait_in_trait(def_id) { + clean_middle_opaque_bounds(cx, def_id, args) + } else { + Type::QPath(Box::new(clean_projection( + bound_ty.rebind(alias_ty.into()), + cx, + parent_def_id, + ))) + } } - ty::Alias(ty::Inherent, alias_ty) => { - let def_id = alias_ty.def_id; + ty::Alias(ty::Inherent, alias_ty @ ty::AliasTy { def_id, .. }) => { let alias_ty = bound_ty.rebind(alias_ty); let self_type = clean_middle_ty(alias_ty.map_bound(|ty| ty.self_ty()), cx, None, None); Type::QPath(Box::new(QPathData { assoc: PathSegment { - name: cx.tcx.associated_item(def_id).name(), + name: cx.tcx.item_name(def_id), args: GenericArgs::AngleBracketed { args: clean_middle_generic_args( cx, @@ -2207,26 +2185,21 @@ pub(crate) fn clean_middle_ty<'tcx>( constraints: Default::default(), }, }, - should_show_cast: false, + should_fully_qualify: false, self_type, trait_: None, })) } - ty::Alias(ty::Free, data) => { + ty::Alias(ty::Free, ty::AliasTy { def_id, args, .. }) => { if cx.tcx.features().lazy_type_alias() { // Free type alias `data` represents the `type X` in `type X = Y`. If we need `Y`, // we need to use `type_of`. - let path = clean_middle_path( - cx, - data.def_id, - false, - ThinVec::new(), - bound_ty.rebind(data.args), - ); + let path = + clean_middle_path(cx, def_id, false, ThinVec::new(), bound_ty.rebind(args)); Type::Path { path } } else { - let ty = cx.tcx.type_of(data.def_id).instantiate(cx.tcx, data.args); + let ty = cx.tcx.type_of(def_id).instantiate(cx.tcx, args); clean_middle_ty(bound_ty.rebind(ty), cx, None, None) } } @@ -2313,18 +2286,17 @@ fn clean_middle_opaque_bounds<'tcx>( let bindings: ThinVec<_> = bounds .iter() .filter_map(|(bound, _)| { - if let ty::ClauseKind::Projection(proj) = bound.kind().skip_binder() - && proj.projection_term.trait_ref(cx.tcx) == trait_ref.skip_binder() + let bound = bound.kind(); + if let ty::ClauseKind::Projection(proj_pred) = bound.skip_binder() + && proj_pred.projection_term.trait_ref(cx.tcx) == trait_ref.skip_binder() { return Some(AssocItemConstraint { assoc: projection_to_path_segment( - // FIXME: This needs to be made resilient for `AliasTerm`s that - // are associated consts. - bound.kind().rebind(proj.projection_term.expect_ty(cx.tcx)), + bound.rebind(proj_pred.projection_term), cx, ), kind: AssocItemConstraintKind::Equality { - term: clean_middle_term(bound.kind().rebind(proj.term), cx), + term: clean_middle_term(bound.rebind(proj_pred.term), cx), }, }); } diff --git a/src/librustdoc/clean/simplify.rs b/src/librustdoc/clean/simplify.rs index 41943b94d1e..40efa997868 100644 --- a/src/librustdoc/clean/simplify.rs +++ b/src/librustdoc/clean/simplify.rs @@ -46,11 +46,8 @@ pub(crate) fn where_clauses(cx: &DocContext<'_>, clauses: ThinVec<WP>) -> ThinVe // Look for equality predicates on associated types that can be merged into // general bound predicates. equalities.retain(|(lhs, rhs)| { - let Some((ty, trait_did, name)) = lhs.projection() else { - return true; - }; - let Some((bounds, _)) = tybounds.get_mut(ty) else { return true }; - merge_bounds(cx, bounds, trait_did, name, rhs) + let Some((bounds, _)) = tybounds.get_mut(&lhs.self_type) else { return true }; + merge_bounds(cx, bounds, lhs.trait_.as_ref().unwrap().def_id(), lhs.assoc.clone(), rhs) }); // And finally, let's reassemble everything diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 9e46d0b47e9..bde1a2e5e66 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -1277,7 +1277,7 @@ impl GenericBound { } fn sized_with(cx: &mut DocContext<'_>, modifiers: hir::TraitBoundModifiers) -> GenericBound { - let did = cx.tcx.require_lang_item(LangItem::Sized, None); + let did = cx.tcx.require_lang_item(LangItem::Sized, DUMMY_SP); let empty = ty::Binder::dummy(ty::GenericArgs::empty()); let path = clean_middle_path(cx, did, false, ThinVec::new(), empty); inline::record_extern_fqn(cx, did, ItemType::Trait); @@ -1341,7 +1341,7 @@ impl PreciseCapturingArg { pub(crate) enum WherePredicate { BoundPredicate { ty: Type, bounds: Vec<GenericBound>, bound_params: Vec<GenericParamDef> }, RegionPredicate { lifetime: Lifetime, bounds: Vec<GenericBound> }, - EqPredicate { lhs: Type, rhs: Term }, + EqPredicate { lhs: QPathData, rhs: Term }, } impl WherePredicate { @@ -1704,14 +1704,6 @@ impl Type { matches!(self, Type::Tuple(v) if v.is_empty()) } - pub(crate) fn projection(&self) -> Option<(&Type, DefId, PathSegment)> { - if let QPath(box QPathData { self_type, trait_, assoc, .. }) = self { - Some((self_type, trait_.as_ref()?.def_id(), assoc.clone())) - } else { - None - } - } - /// Use this method to get the [DefId] of a [clean] AST node, including [PrimitiveType]s. /// /// [clean]: crate::clean @@ -1746,7 +1738,7 @@ pub(crate) struct QPathData { pub assoc: PathSegment, pub self_type: Type, /// FIXME: compute this field on demand. - pub should_show_cast: bool, + pub should_fully_qualify: bool, pub trait_: Option<Path>, } diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index e9a7f4367a3..6ab1520386d 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -1019,18 +1019,33 @@ fn fmt_type( f.write_str("impl ")?; print_generic_bounds(bounds, cx).fmt(f) } - &clean::QPath(box clean::QPathData { - ref assoc, - ref self_type, - ref trait_, - should_show_cast, - }) => { + clean::QPath(qpath) => qpath.print(cx).fmt(f), + } +} + +impl clean::Type { + pub(crate) fn print(&self, cx: &Context<'_>) -> impl Display { + fmt::from_fn(move |f| fmt_type(self, f, false, cx)) + } +} + +impl clean::Path { + pub(crate) fn print(&self, cx: &Context<'_>) -> impl Display { + fmt::from_fn(move |f| resolved_path(f, self.def_id(), self, false, false, cx)) + } +} + +impl clean::QPathData { + fn print(&self, cx: &Context<'_>) -> impl Display { + let Self { ref assoc, ref self_type, should_fully_qualify, ref trait_ } = *self; + + fmt::from_fn(move |f| { // FIXME(inherent_associated_types): Once we support non-ADT self-types (#106719), // we need to surround them with angle brackets in some cases (e.g. `<dyn …>::P`). if f.alternate() { if let Some(trait_) = trait_ - && should_show_cast + && should_fully_qualify { write!(f, "<{:#} as {:#}>::", self_type.print(cx), trait_.print(cx))? } else { @@ -1038,7 +1053,7 @@ fn fmt_type( } } else { if let Some(trait_) = trait_ - && should_show_cast + && should_fully_qualify { write!(f, "<{} as {}>::", self_type.print(cx), trait_.print(cx))? } else { @@ -1090,19 +1105,7 @@ fn fmt_type( }?; assoc.args.print(cx).fmt(f) - } - } -} - -impl clean::Type { - pub(crate) fn print(&self, cx: &Context<'_>) -> impl Display { - fmt::from_fn(move |f| fmt_type(self, f, false, cx)) - } -} - -impl clean::Path { - pub(crate) fn print(&self, cx: &Context<'_>) -> impl Display { - fmt::from_fn(move |f| resolved_path(f, self.def_id(), self, false, false, cx)) + }) } } diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index bfcb794b89a..3ade40940bc 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -468,6 +468,9 @@ impl FromClean<clean::WherePredicate> for WherePredicate { .collect(), }, EqPredicate { lhs, rhs } => WherePredicate::EqPredicate { + // The LHS currently has type `Type` but it should be a `QualifiedPath` since it may + // refer to an associated const. However, `EqPredicate` shouldn't exist in the first + // place: <https://github.com/rust-lang/rust/141368>. lhs: lhs.into_json(renderer), rhs: rhs.into_json(renderer), }, @@ -557,12 +560,7 @@ impl FromClean<clean::Type> for Type { is_mutable: mutability == ast::Mutability::Mut, type_: Box::new((*type_).into_json(renderer)), }, - QPath(box clean::QPathData { assoc, self_type, trait_, .. }) => Type::QualifiedPath { - name: assoc.name.to_string(), - args: Box::new(assoc.args.into_json(renderer)), - self_type: Box::new(self_type.into_json(renderer)), - trait_: trait_.map(|trait_| trait_.into_json(renderer)), - }, + QPath(qpath) => (*qpath).into_json(renderer), // FIXME(unsafe_binder): Implement rustdoc-json. UnsafeBinder(_) => todo!(), } @@ -579,6 +577,19 @@ impl FromClean<clean::Path> for Path { } } +impl FromClean<clean::QPathData> for Type { + fn from_clean(qpath: clean::QPathData, renderer: &JsonRenderer<'_>) -> Self { + let clean::QPathData { assoc, self_type, should_fully_qualify: _, trait_ } = qpath; + + Self::QualifiedPath { + name: assoc.name.to_string(), + args: Box::new(assoc.args.into_json(renderer)), + self_type: Box::new(self_type.into_json(renderer)), + trait_: trait_.map(|trait_| trait_.into_json(renderer)), + } + } +} + impl FromClean<clean::Term> for Term { fn from_clean(term: clean::Term, renderer: &JsonRenderer<'_>) -> Term { match term { diff --git a/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs b/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs index 9ad184450de..b839b6f5672 100644 --- a/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs +++ b/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs @@ -426,7 +426,7 @@ fn drain_matching( // Check if we should extract, but only if `idx >= start`. if idx > start && predicate(&alternatives[i].kind) { let pat = alternatives.remove(i); - tail_or.push(extract(pat.into_inner().kind)); + tail_or.push(extract(pat.kind)); } else { i += 1; } diff --git a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs index 5b4ec12cbec..8e16f943e9f 100644 --- a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs +++ b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs @@ -439,7 +439,7 @@ fn is_ty_const_destruct<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, body: &Body<'tcx> tcx, ObligationCause::dummy_with_span(body.span), param_env, - TraitRef::new(tcx, tcx.require_lang_item(LangItem::Destruct, Some(body.span)), [ty]), + TraitRef::new(tcx, tcx.require_lang_item(LangItem::Destruct, body.span), [ty]), ); let mut selcx = SelectionContext::new(&infcx); diff --git a/src/tools/miri/src/eval.rs b/src/tools/miri/src/eval.rs index 1477f103ca5..6f5f756e144 100644 --- a/src/tools/miri/src/eval.rs +++ b/src/tools/miri/src/eval.rs @@ -358,8 +358,8 @@ pub fn create_ecx<'tcx>( let argvs_layout = ecx.layout_of(Ty::new_array(tcx, u8_ptr_type, u64::try_from(argvs.len()).unwrap()))?; let argvs_place = ecx.allocate(argvs_layout, MiriMemoryKind::Machine.into())?; - for (idx, arg) in argvs.into_iter().enumerate() { - let place = ecx.project_field(&argvs_place, idx)?; + for (arg, idx) in argvs.into_iter().zip(0..) { + let place = ecx.project_index(&argvs_place, idx)?; ecx.write_immediate(arg, &place)?; } ecx.mark_immutable(&argvs_place); @@ -388,8 +388,8 @@ pub fn create_ecx<'tcx>( ecx.allocate(ecx.layout_of(cmd_type)?, MiriMemoryKind::Machine.into())?; ecx.machine.cmd_line = Some(cmd_place.ptr()); // Store the UTF-16 string. We just allocated so we know the bounds are fine. - for (idx, &c) in cmd_utf16.iter().enumerate() { - let place = ecx.project_field(&cmd_place, idx)?; + for (&c, idx) in cmd_utf16.iter().zip(0..) { + let place = ecx.project_index(&cmd_place, idx)?; ecx.write_scalar(Scalar::from_u16(c), &place)?; } ecx.mark_immutable(&cmd_place); diff --git a/src/tools/miri/src/helpers.rs b/src/tools/miri/src/helpers.rs index 20ea239b7e5..4edecc864dd 100644 --- a/src/tools/miri/src/helpers.rs +++ b/src/tools/miri/src/helpers.rs @@ -326,7 +326,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { ) -> InterpResult<'tcx, Option<P>> { let this = self.eval_context_ref(); let adt = base.layout().ty.ty_adt_def().unwrap(); - for (idx, field) in adt.non_enum_variant().fields.iter().enumerate() { + for (idx, field) in adt.non_enum_variant().fields.iter_enumerated() { if field.name.as_str() == name { return interp_ok(Some(this.project_field(base, idx)?)); } @@ -376,6 +376,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); for (idx, &val) in values.iter().enumerate() { + let idx = FieldIdx::from_usize(idx); let field = this.project_field(dest, idx)?; this.write_int(val, &field)?; } @@ -763,10 +764,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { /// `EINVAL` in this case. fn read_timespec(&mut self, tp: &MPlaceTy<'tcx>) -> InterpResult<'tcx, Option<Duration>> { let this = self.eval_context_mut(); - let seconds_place = this.project_field(tp, 0)?; + let seconds_place = this.project_field(tp, FieldIdx::ZERO)?; let seconds_scalar = this.read_scalar(&seconds_place)?; let seconds = seconds_scalar.to_target_isize(this)?; - let nanoseconds_place = this.project_field(tp, 1)?; + let nanoseconds_place = this.project_field(tp, FieldIdx::ONE)?; let nanoseconds_scalar = this.read_scalar(&nanoseconds_place)?; let nanoseconds = nanoseconds_scalar.to_target_isize(this)?; diff --git a/src/tools/miri/src/shims/backtrace.rs b/src/tools/miri/src/shims/backtrace.rs index ab11553df63..8606735c913 100644 --- a/src/tools/miri/src/shims/backtrace.rs +++ b/src/tools/miri/src/shims/backtrace.rs @@ -1,4 +1,4 @@ -use rustc_abi::{CanonAbi, Size}; +use rustc_abi::{CanonAbi, FieldIdx, Size}; use rustc_middle::ty::layout::LayoutOf as _; use rustc_middle::ty::{self, Instance, Ty}; use rustc_span::{BytePos, Loc, Symbol, hygiene}; @@ -159,23 +159,23 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { 1 => { this.write_scalar( Scalar::from_target_usize(name.len().to_u64(), this), - &this.project_field(dest, 0)?, + &this.project_field(dest, FieldIdx::from_u32(0))?, )?; this.write_scalar( Scalar::from_target_usize(filename.len().to_u64(), this), - &this.project_field(dest, 1)?, + &this.project_field(dest, FieldIdx::from_u32(1))?, )?; } _ => throw_unsup_format!("unknown `miri_resolve_frame` flags {}", flags), } - this.write_scalar(Scalar::from_u32(lineno), &this.project_field(dest, 2)?)?; - this.write_scalar(Scalar::from_u32(colno), &this.project_field(dest, 3)?)?; + this.write_scalar(Scalar::from_u32(lineno), &this.project_field(dest, FieldIdx::from_u32(2))?)?; + this.write_scalar(Scalar::from_u32(colno), &this.project_field(dest, FieldIdx::from_u32(3))?)?; // Support a 4-field struct for now - this is deprecated // and slated for removal. if num_fields == 5 { - this.write_pointer(fn_ptr, &this.project_field(dest, 4)?)?; + this.write_pointer(fn_ptr, &this.project_field(dest, FieldIdx::from_u32(4))?)?; } interp_ok(()) diff --git a/src/tools/miri/src/shims/panic.rs b/src/tools/miri/src/shims/panic.rs index 549d859a6e1..a6bce830149 100644 --- a/src/tools/miri/src/shims/panic.rs +++ b/src/tools/miri/src/shims/panic.rs @@ -247,7 +247,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { _ => { // Call the lang item associated with this message. - let fn_item = this.tcx.require_lang_item(msg.panic_function(), None); + let fn_item = this.tcx.require_lang_item(msg.panic_function(), this.tcx.span); let instance = ty::Instance::mono(this.tcx.tcx, fn_item); this.call_function( instance, diff --git a/src/tools/miri/src/shims/unix/env.rs b/src/tools/miri/src/shims/unix/env.rs index aebb5757aec..62ac7ee3806 100644 --- a/src/tools/miri/src/shims/unix/env.rs +++ b/src/tools/miri/src/shims/unix/env.rs @@ -2,8 +2,9 @@ use std::ffi::{OsStr, OsString}; use std::io::ErrorKind; use std::{env, mem}; -use rustc_abi::Size; +use rustc_abi::{FieldIdx, Size}; use rustc_data_structures::fx::FxHashMap; +use rustc_index::IndexVec; use rustc_middle::ty::Ty; use rustc_middle::ty::layout::LayoutOf; @@ -118,7 +119,7 @@ fn alloc_env_var<'tcx>( /// Allocates an `environ` block with the given list of pointers. fn alloc_environ_block<'tcx>( ecx: &mut InterpCx<'tcx, MiriMachine<'tcx>>, - mut vars: Vec<Pointer>, + mut vars: IndexVec<FieldIdx, Pointer>, ) -> InterpResult<'tcx, Pointer> { // Add trailing null. vars.push(Pointer::null()); @@ -129,7 +130,7 @@ fn alloc_environ_block<'tcx>( u64::try_from(vars.len()).unwrap(), ))?; let vars_place = ecx.allocate(vars_layout, MiriMemoryKind::Runtime.into())?; - for (idx, var) in vars.into_iter().enumerate() { + for (idx, var) in vars.into_iter_enumerated() { let place = ecx.project_field(&vars_place, idx)?; ecx.write_pointer(var, &place)?; } diff --git a/src/tools/miri/src/shims/unix/freebsd/sync.rs b/src/tools/miri/src/shims/unix/freebsd/sync.rs index 54650f35b2c..f4e7d9e58f9 100644 --- a/src/tools/miri/src/shims/unix/freebsd/sync.rs +++ b/src/tools/miri/src/shims/unix/freebsd/sync.rs @@ -2,6 +2,8 @@ use core::time::Duration; +use rustc_abi::FieldIdx; + use crate::concurrency::sync::FutexRef; use crate::*; @@ -214,18 +216,18 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Only flag allowed is UMTX_ABSTIME. let abs_time = this.eval_libc_u32("UMTX_ABSTIME"); - let timespec_place = this.project_field(ut, 0)?; + let timespec_place = this.project_field(ut, FieldIdx::from_u32(0))?; // Inner `timespec` must still be valid. let duration = match this.read_timespec(×pec_place)? { Some(dur) => dur, None => return interp_ok(None), }; - let flags_place = this.project_field(ut, 1)?; + let flags_place = this.project_field(ut, FieldIdx::from_u32(1))?; let flags = this.read_scalar(&flags_place)?.to_u32()?; let abs_time_flag = flags == abs_time; - let clock_id_place = this.project_field(ut, 2)?; + let clock_id_place = this.project_field(ut, FieldIdx::from_u32(2))?; let clock_id = this.read_scalar(&clock_id_place)?.to_i32()?; let timeout_clock = this.translate_umtx_time_clock_id(clock_id)?; diff --git a/src/tools/miri/src/shims/unix/linux_like/epoll.rs b/src/tools/miri/src/shims/unix/linux_like/epoll.rs index b489595b4cd..f971fb10b19 100644 --- a/src/tools/miri/src/shims/unix/linux_like/epoll.rs +++ b/src/tools/miri/src/shims/unix/linux_like/epoll.rs @@ -4,6 +4,8 @@ use std::io; use std::rc::{Rc, Weak}; use std::time::Duration; +use rustc_abi::FieldIdx; + use crate::concurrency::VClock; use crate::shims::files::{ DynFileDescriptionRef, FdId, FileDescription, FileDescriptionRef, WeakFileDescriptionRef, @@ -284,8 +286,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { if op == epoll_ctl_add || op == epoll_ctl_mod { // Read event bitmask and data from epoll_event passed by caller. - let mut events = this.read_scalar(&this.project_field(&event, 0)?)?.to_u32()?; - let data = this.read_scalar(&this.project_field(&event, 1)?)?.to_u64()?; + let mut events = this.read_scalar(&this.project_field(&event, FieldIdx::ZERO)?)?.to_u32()?; + let data = this.read_scalar(&this.project_field(&event, FieldIdx::ONE)?)?.to_u64()?; // Unset the flag we support to discover if any unsupported flags are used. let mut flags = events; diff --git a/src/tools/miri/src/shims/x86/mod.rs b/src/tools/miri/src/shims/x86/mod.rs index 7dee8ddd23c..1e82f521249 100644 --- a/src/tools/miri/src/shims/x86/mod.rs +++ b/src/tools/miri/src/shims/x86/mod.rs @@ -1,4 +1,4 @@ -use rustc_abi::{CanonAbi, Size}; +use rustc_abi::{CanonAbi, FieldIdx, Size}; use rustc_apfloat::Float; use rustc_apfloat::ieee::Single; use rustc_middle::ty::Ty; @@ -54,8 +54,8 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { }; let (sum, cb_out) = carrying_add(this, cb_in, a, b, op)?; - this.write_scalar(cb_out, &this.project_field(dest, 0)?)?; - this.write_immediate(*sum, &this.project_field(dest, 1)?)?; + this.write_scalar(cb_out, &this.project_field(dest, FieldIdx::ZERO)?)?; + this.write_immediate(*sum, &this.project_field(dest, FieldIdx::ONE)?)?; } // Used to implement the `_addcarryx_u{32, 64}` functions. They are semantically identical with the `_addcarry_u{32, 64}` functions, diff --git a/src/tools/rustfmt/src/modules.rs b/src/tools/rustfmt/src/modules.rs index bc5a6d3e704..44c8123517c 100644 --- a/src/tools/rustfmt/src/modules.rs +++ b/src/tools/rustfmt/src/modules.rs @@ -174,7 +174,7 @@ impl<'ast, 'psess, 'c> ModResolver<'ast, 'psess> { ) -> Result<(), ModuleResolutionError> { for item in items { if is_cfg_if(&item) { - self.visit_cfg_if(Cow::Owned(item.into_inner()))?; + self.visit_cfg_if(Cow::Owned(*item))?; continue; } diff --git a/src/tools/rustfmt/src/parse/macros/cfg_if.rs b/src/tools/rustfmt/src/parse/macros/cfg_if.rs index 30b83373c17..26bf6c5326f 100644 --- a/src/tools/rustfmt/src/parse/macros/cfg_if.rs +++ b/src/tools/rustfmt/src/parse/macros/cfg_if.rs @@ -62,7 +62,7 @@ fn parse_cfg_if_inner<'a>( while parser.token != TokenKind::CloseBrace && parser.token.kind != TokenKind::Eof { let item = match parser.parse_item(ForceCollect::No) { - Ok(Some(item_ptr)) => item_ptr.into_inner(), + Ok(Some(item_ptr)) => *item_ptr, Ok(None) => continue, Err(err) => { err.cancel(); diff --git a/tests/rustdoc/inline_cross/assoc-const-equality.rs b/tests/rustdoc/inline_cross/assoc-const-equality.rs index ec5c2f748ef..36ab027ef71 100644 --- a/tests/rustdoc/inline_cross/assoc-const-equality.rs +++ b/tests/rustdoc/inline_cross/assoc-const-equality.rs @@ -1,6 +1,5 @@ //@ aux-crate:assoc_const_equality=assoc-const-equality.rs //@ edition:2021 -//@ ignore-test (FIXME: #125092) #![crate_name = "user"] diff --git a/tests/ui/cleanup-rvalue-scopes-cf.rs b/tests/ui/borrowck/rvalue-borrow-scope-error.rs index e3cecb1bffe..5bf96e800d3 100644 --- a/tests/ui/cleanup-rvalue-scopes-cf.rs +++ b/tests/ui/borrowck/rvalue-borrow-scope-error.rs @@ -1,15 +1,19 @@ -// Test that the borrow checker prevents pointers to temporaries -// with statement lifetimes from escaping. +//! Test that the borrow checker prevents pointers to temporaries +//! with statement lifetimes from escaping. use std::ops::Drop; static mut FLAGS: u64 = 0; -struct StackBox<T> { f: T } -struct AddFlags { bits: u64 } +struct StackBox<T> { + f: T, +} +struct AddFlags { + bits: u64, +} fn AddFlags(bits: u64) -> AddFlags { - AddFlags { bits: bits } + AddFlags { bits } } fn arg(x: &AddFlags) -> &AddFlags { diff --git a/tests/ui/cleanup-rvalue-scopes-cf.stderr b/tests/ui/borrowck/rvalue-borrow-scope-error.stderr index 425cd75141c..bedcfce4541 100644 --- a/tests/ui/cleanup-rvalue-scopes-cf.stderr +++ b/tests/ui/borrowck/rvalue-borrow-scope-error.stderr @@ -1,5 +1,5 @@ error[E0716]: temporary value dropped while borrowed - --> $DIR/cleanup-rvalue-scopes-cf.rs:26:19 + --> $DIR/rvalue-borrow-scope-error.rs:30:19 | LL | let x1 = arg(&AddFlags(1)); | ^^^^^^^^^^^ - temporary value is freed at the end of this statement @@ -16,7 +16,7 @@ LL ~ let x1 = arg(&binding); | error[E0716]: temporary value dropped while borrowed - --> $DIR/cleanup-rvalue-scopes-cf.rs:27:14 + --> $DIR/rvalue-borrow-scope-error.rs:31:14 | LL | let x2 = AddFlags(1).get(); | ^^^^^^^^^^^ - temporary value is freed at the end of this statement @@ -33,7 +33,7 @@ LL ~ let x2 = binding.get(); | error[E0716]: temporary value dropped while borrowed - --> $DIR/cleanup-rvalue-scopes-cf.rs:28:21 + --> $DIR/rvalue-borrow-scope-error.rs:32:21 | LL | let x3 = &*arg(&AddFlags(1)); | ^^^^^^^^^^^ - temporary value is freed at the end of this statement @@ -50,7 +50,7 @@ LL ~ let x3 = &*arg(&binding); | error[E0716]: temporary value dropped while borrowed - --> $DIR/cleanup-rvalue-scopes-cf.rs:29:24 + --> $DIR/rvalue-borrow-scope-error.rs:33:24 | LL | let ref x4 = *arg(&AddFlags(1)); | ^^^^^^^^^^^ - temporary value is freed at the end of this statement @@ -67,7 +67,7 @@ LL ~ let ref x4 = *arg(&binding); | error[E0716]: temporary value dropped while borrowed - --> $DIR/cleanup-rvalue-scopes-cf.rs:30:24 + --> $DIR/rvalue-borrow-scope-error.rs:34:24 | LL | let &ref x5 = arg(&AddFlags(1)); | ^^^^^^^^^^^ - temporary value is freed at the end of this statement @@ -84,7 +84,7 @@ LL ~ let &ref x5 = arg(&binding); | error[E0716]: temporary value dropped while borrowed - --> $DIR/cleanup-rvalue-scopes-cf.rs:31:14 + --> $DIR/rvalue-borrow-scope-error.rs:35:14 | LL | let x6 = AddFlags(1).get(); | ^^^^^^^^^^^ - temporary value is freed at the end of this statement @@ -101,7 +101,7 @@ LL ~ let x6 = binding.get(); | error[E0716]: temporary value dropped while borrowed - --> $DIR/cleanup-rvalue-scopes-cf.rs:32:44 + --> $DIR/rvalue-borrow-scope-error.rs:36:44 | LL | let StackBox { f: x7 } = StackBox { f: AddFlags(1).get() }; | ^^^^^^^^^^^ - temporary value is freed at the end of this statement diff --git a/tests/ui/cleanup-rvalue-scopes.rs b/tests/ui/cleanup-rvalue-scopes.rs deleted file mode 100644 index 09ceda065b9..00000000000 --- a/tests/ui/cleanup-rvalue-scopes.rs +++ /dev/null @@ -1,128 +0,0 @@ -//@ run-pass -#![allow(unused_braces)] -#![allow(non_snake_case)] -#![allow(unused_variables)] -// Test that destructors for rvalue temporaries run either at end of -// statement or end of block, as appropriate given the temporary -// lifetime rules. - -#![feature(box_patterns)] - -static mut FLAGS: u64 = 0; - -struct Box<T> { f: T } -struct AddFlags { bits: u64 } - -fn AddFlags(bits: u64) -> AddFlags { - AddFlags { bits: bits } -} - -fn arg(exp: u64, _x: &AddFlags) { - check_flags(exp); -} - -fn pass<T>(v: T) -> T { - v -} - -fn check_flags(exp: u64) { - unsafe { - let x = FLAGS; - FLAGS = 0; - println!("flags {}, expected {}", x, exp); - assert_eq!(x, exp); - } -} - -impl AddFlags { - fn check_flags<'a>(&'a self, exp: u64) -> &'a AddFlags { - check_flags(exp); - self - } - - fn bits(&self) -> u64 { - self.bits - } -} - -impl Drop for AddFlags { - fn drop(&mut self) { - unsafe { - FLAGS = FLAGS + self.bits; - } - } -} - -macro_rules! end_of_block { - ($pat:pat, $expr:expr) => ( - { - println!("end_of_block({})", stringify!({let $pat = $expr;})); - - { - // Destructor here does not run until exit from the block. - let $pat = $expr; - check_flags(0); - } - check_flags(1); - } - ) -} - -macro_rules! end_of_stmt { - ($pat:pat, $expr:expr) => ( - { - println!("end_of_stmt({})", stringify!($expr)); - - { - // Destructor here run after `let` statement - // terminates. - let $pat = $expr; - check_flags(1); - } - - check_flags(0); - } - ) -} - -pub fn main() { - - // In all these cases, we trip over the rules designed to cover - // the case where we are taking addr of rvalue and storing that - // addr into a stack slot, either via `let ref` or via a `&` in - // the initializer. - - end_of_block!(_x, AddFlags(1)); - end_of_block!(_x, &AddFlags(1)); - end_of_block!(_x, & &AddFlags(1)); - end_of_block!(_x, Box { f: AddFlags(1) }); - end_of_block!(_x, Box { f: &AddFlags(1) }); - end_of_block!(_x, Box { f: &AddFlags(1) }); - end_of_block!(_x, pass(AddFlags(1))); - end_of_block!(ref _x, AddFlags(1)); - end_of_block!(AddFlags { bits: ref _x }, AddFlags(1)); - end_of_block!(&AddFlags { bits }, &AddFlags(1)); - end_of_block!((_, ref _y), (AddFlags(1), 22)); - end_of_block!(box ref _x, std::boxed::Box::new(AddFlags(1))); - end_of_block!(box _x, std::boxed::Box::new(AddFlags(1))); - end_of_block!(_, { { check_flags(0); &AddFlags(1) } }); - end_of_block!(_, &((Box { f: AddFlags(1) }).f)); - end_of_block!(_, &(([AddFlags(1)])[0])); - - // LHS does not create a ref binding, so temporary lives as long - // as statement, and we do not move the AddFlags out: - end_of_stmt!(_, AddFlags(1)); - end_of_stmt!((_, _), (AddFlags(1), 22)); - - // `&` operator appears inside an arg to a function, - // so it is not prolonged: - end_of_stmt!(ref _x, arg(0, &AddFlags(1))); - - // autoref occurs inside receiver, so temp lifetime is not - // prolonged: - end_of_stmt!(ref _x, AddFlags(1).check_flags(0).bits()); - - // No reference is created on LHS, thus RHS is moved into - // a temporary that lives just as long as the statement. - end_of_stmt!(AddFlags { bits }, AddFlags(1)); -} diff --git a/tests/ui/close-over-big-then-small-data.rs b/tests/ui/close-over-big-then-small-data.rs deleted file mode 100644 index d3cb1db8886..00000000000 --- a/tests/ui/close-over-big-then-small-data.rs +++ /dev/null @@ -1,39 +0,0 @@ -//@ run-pass - -#![allow(dead_code)] -// If we use GEPi rather than GEP_tup_like when -// storing closure data (as we used to do), the u64 would -// overwrite the u16. - -struct Pair<A,B> { - a: A, b: B -} - -struct Invoker<A> { - a: A, - b: u16, -} - -trait Invokable<A> { - fn f(&self) -> (A, u16); -} - -impl<A:Clone> Invokable<A> for Invoker<A> { - fn f(&self) -> (A, u16) { - (self.a.clone(), self.b) - } -} - -fn f<A:Clone + 'static>(a: A, b: u16) -> Box<dyn Invokable<A>+'static> { - Box::new(Invoker { - a: a, - b: b, - }) as Box<dyn Invokable<A>+'static> -} - -pub fn main() { - let (a, b) = f(22_u64, 44u16).f(); - println!("a={} b={}", a, b); - assert_eq!(a, 22u64); - assert_eq!(b, 44u16); -} diff --git a/tests/ui/const-generics/early/invalid-const-arguments.stderr b/tests/ui/const-generics/early/invalid-const-arguments.stderr index 86b4d006454..3a9868836ec 100644 --- a/tests/ui/const-generics/early/invalid-const-arguments.stderr +++ b/tests/ui/const-generics/early/invalid-const-arguments.stderr @@ -51,9 +51,13 @@ error[E0747]: type provided when a constant was expected --> $DIR/invalid-const-arguments.rs:10:19 | LL | impl<N> Foo for B<N> {} - | - ^ - | | - | help: consider changing this type parameter to a const parameter: `const N: u8` + | ^ + | +help: consider changing this type parameter to a const parameter + | +LL - impl<N> Foo for B<N> {} +LL + impl<const N: u8> Foo for B<N> {} + | error[E0747]: unresolved item provided when a constant was expected --> $DIR/invalid-const-arguments.rs:14:32 diff --git a/tests/ui/const-generics/kind_mismatch.stderr b/tests/ui/const-generics/kind_mismatch.stderr index 1487b189619..12a2ab141a6 100644 --- a/tests/ui/const-generics/kind_mismatch.stderr +++ b/tests/ui/const-generics/kind_mismatch.stderr @@ -2,17 +2,25 @@ error[E0747]: type provided when a constant was expected --> $DIR/kind_mismatch.rs:11:38 | LL | impl<K> ContainsKey<K> for KeyHolder<K> {} - | - ^ - | | - | help: consider changing this type parameter to a const parameter: `const K: u8` + | ^ + | +help: consider changing this type parameter to a const parameter + | +LL - impl<K> ContainsKey<K> for KeyHolder<K> {} +LL + impl<const K: u8> ContainsKey<K> for KeyHolder<K> {} + | error[E0747]: type provided when a constant was expected --> $DIR/kind_mismatch.rs:11:21 | LL | impl<K> ContainsKey<K> for KeyHolder<K> {} - | - ^ - | | - | help: consider changing this type parameter to a const parameter: `const K: u8` + | ^ + | +help: consider changing this type parameter to a const parameter + | +LL - impl<K> ContainsKey<K> for KeyHolder<K> {} +LL + impl<const K: u8> ContainsKey<K> for KeyHolder<K> {} + | error: aborting due to 2 previous errors diff --git a/tests/ui/command-line-diagnostics.rs b/tests/ui/diagnostic-width/command-line-error-format-human.rs index 8a6cf5b8e32..a2cfbbcbeb1 100644 --- a/tests/ui/command-line-diagnostics.rs +++ b/tests/ui/diagnostic-width/command-line-error-format-human.rs @@ -1,4 +1,5 @@ -// This test checks the output format without the intermediate json representation +//! This test checks the output format without the intermediate json representation + //@ compile-flags: --error-format=human pub fn main() { diff --git a/tests/ui/command-line-diagnostics.stderr b/tests/ui/diagnostic-width/command-line-error-format-human.stderr index 6d33fb4172f..b4b78239f88 100644 --- a/tests/ui/command-line-diagnostics.stderr +++ b/tests/ui/diagnostic-width/command-line-error-format-human.stderr @@ -1,5 +1,5 @@ error[E0384]: cannot assign twice to immutable variable `x` - --> $DIR/command-line-diagnostics.rs:6:5 + --> $DIR/command-line-error-format-human.rs:7:5 | LL | let x = 42; | - first assignment to `x` diff --git a/tests/ui/drop/issue-2735-2.rs b/tests/ui/drop/issue-2735-2.rs index 66025956e08..43fbafe7a0e 100644 --- a/tests/ui/drop/issue-2735-2.rs +++ b/tests/ui/drop/issue-2735-2.rs @@ -1,27 +1,24 @@ //@ run-pass -#![allow(non_camel_case_types)] use std::cell::Cell; // This test should behave exactly like issue-2735-3 -struct defer<'a> { +struct Defer<'a> { b: &'a Cell<bool>, } -impl<'a> Drop for defer<'a> { +impl<'a> Drop for Defer<'a> { fn drop(&mut self) { self.b.set(true); } } -fn defer(b: &Cell<bool>) -> defer<'_> { - defer { - b: b - } +fn defer(b: &Cell<bool>) -> Defer<'_> { + Defer { b } } pub fn main() { let dtor_ran = &Cell::new(false); - let _ = defer(dtor_ran); + let _ = defer(dtor_ran); assert!(dtor_ran.get()); } diff --git a/tests/ui/drop/issue-2735-3.rs b/tests/ui/drop/issue-2735-3.rs index c9535168653..cc28f96d2b0 100644 --- a/tests/ui/drop/issue-2735-3.rs +++ b/tests/ui/drop/issue-2735-3.rs @@ -1,23 +1,20 @@ //@ run-pass -#![allow(non_camel_case_types)] use std::cell::Cell; // This test should behave exactly like issue-2735-2 -struct defer<'a> { +struct Defer<'a> { b: &'a Cell<bool>, } -impl<'a> Drop for defer<'a> { +impl<'a> Drop for Defer<'a> { fn drop(&mut self) { self.b.set(true); } } -fn defer(b: &Cell<bool>) -> defer<'_> { - defer { - b: b - } +fn defer(b: &Cell<bool>) -> Defer<'_> { + Defer { b } } pub fn main() { diff --git a/tests/ui/drop/issue-2735.rs b/tests/ui/drop/issue-2735.rs index cd7e0b8f461..838b9da109b 100644 --- a/tests/ui/drop/issue-2735.rs +++ b/tests/ui/drop/issue-2735.rs @@ -1,15 +1,13 @@ //@ run-pass #![allow(dead_code)] -#![allow(non_camel_case_types)] - -trait hax { - fn dummy(&self) { } +trait Hax { + fn dummy(&self) {} } -impl<A> hax for A { } +impl<A> Hax for A {} -fn perform_hax<T: 'static>(x: Box<T>) -> Box<dyn hax+'static> { - Box::new(x) as Box<dyn hax+'static> +fn perform_hax<T: 'static>(x: Box<T>) -> Box<dyn Hax + 'static> { + Box::new(x) as Box<dyn Hax + 'static> } fn deadcode() { diff --git a/tests/ui/drop/issue-979.rs b/tests/ui/drop/issue-979.rs index 70052708be6..abbcc71de18 100644 --- a/tests/ui/drop/issue-979.rs +++ b/tests/ui/drop/issue-979.rs @@ -1,22 +1,19 @@ //@ run-pass -#![allow(non_camel_case_types)] use std::cell::Cell; -struct r<'a> { +struct R<'a> { b: &'a Cell<isize>, } -impl<'a> Drop for r<'a> { +impl<'a> Drop for R<'a> { fn drop(&mut self) { self.b.set(self.b.get() + 1); } } -fn r(b: &Cell<isize>) -> r<'_> { - r { - b: b - } +fn r(b: &Cell<isize>) -> R<'_> { + R { b } } pub fn main() { diff --git a/tests/ui/lang-items/lang-item-generic-requirements.rs b/tests/ui/lang-items/lang-item-generic-requirements.rs index 7676b5557d2..25a4ff283ba 100644 --- a/tests/ui/lang-items/lang-item-generic-requirements.rs +++ b/tests/ui/lang-items/lang-item-generic-requirements.rs @@ -48,6 +48,7 @@ fn ice() { // Use index let arr = [0; 5]; + //~^ ERROR requires `copy` lang_item let _ = arr[2]; //~^ ERROR cannot index into a value of type `[{integer}; 5]` @@ -61,5 +62,3 @@ fn ice() { // use `start` fn main() {} - -//~? ERROR requires `copy` lang_item diff --git a/tests/ui/lang-items/lang-item-generic-requirements.stderr b/tests/ui/lang-items/lang-item-generic-requirements.stderr index 409fa05d637..c82bdb00fd1 100644 --- a/tests/ui/lang-items/lang-item-generic-requirements.stderr +++ b/tests/ui/lang-items/lang-item-generic-requirements.stderr @@ -77,13 +77,13 @@ LL | r + a; | {integer} error[E0608]: cannot index into a value of type `[{integer}; 5]` - --> $DIR/lang-item-generic-requirements.rs:51:16 + --> $DIR/lang-item-generic-requirements.rs:52:16 | LL | let _ = arr[2]; | ^^^ error[E0308]: mismatched types - --> $DIR/lang-item-generic-requirements.rs:58:17 + --> $DIR/lang-item-generic-requirements.rs:59:17 | LL | let _: () = Foo; | -- ^^^ expected `()`, found `Foo` @@ -91,6 +91,10 @@ LL | let _: () = Foo; | expected due to this error: requires `copy` lang_item + --> $DIR/lang-item-generic-requirements.rs:50:16 + | +LL | let arr = [0; 5]; + | ^ error: aborting due to 12 previous errors diff --git a/tests/ui/cleanup-shortcircuit.rs b/tests/ui/lifetimes/rvalue-cleanup-shortcircuit.rs index 40a5dfa94e3..dba899585c4 100644 --- a/tests/ui/cleanup-shortcircuit.rs +++ b/tests/ui/lifetimes/rvalue-cleanup-shortcircuit.rs @@ -1,10 +1,9 @@ -//@ run-pass -// Test that cleanups for the RHS of shortcircuiting operators work. +//! Test that cleanups for the RHS of shortcircuiting operators work. +//@ run-pass #![allow(deref_nullptr)] - use std::env; pub fn main() { @@ -18,6 +17,8 @@ pub fn main() { if args.len() >= 2 && args[1] == "signal" { // Raise a segfault. - unsafe { *std::ptr::null_mut::<isize>() = 0; } + unsafe { + *std::ptr::null_mut::<isize>() = 0; + } } } diff --git a/tests/ui/lifetimes/rvalue-lifetime-drop-timing.rs b/tests/ui/lifetimes/rvalue-lifetime-drop-timing.rs new file mode 100644 index 00000000000..9e7b84bfccf --- /dev/null +++ b/tests/ui/lifetimes/rvalue-lifetime-drop-timing.rs @@ -0,0 +1,104 @@ +//! Test that destructors for temporaries run either at end of +//! statement or end of block as appropriate. + +//@ run-pass + +#![feature(box_patterns)] + +static mut FLAGS: u64 = 0; + +struct Box<T> { + f: T, +} + +struct AddFlags { + bits: u64, +} + +fn add_flags(bits: u64) -> AddFlags { + AddFlags { bits } +} + +fn arg(expected: u64, _x: &AddFlags) { + check_flags(expected); +} + +fn pass<T>(v: T) -> T { + v +} + +fn check_flags(expected: u64) { + unsafe { + let actual = FLAGS; + FLAGS = 0; + assert_eq!(actual, expected, "flags {}, expected {}", actual, expected); + } +} + +impl AddFlags { + fn check_flags(&self, expected: u64) -> &AddFlags { + check_flags(expected); + self + } + + fn bits(&self) -> u64 { + self.bits + } +} + +impl Drop for AddFlags { + fn drop(&mut self) { + unsafe { + FLAGS += self.bits; + } + } +} + +macro_rules! end_of_block { + ($pat:pat, $expr:expr) => {{ + { + let $pat = $expr; + check_flags(0); + } + check_flags(1); + }}; +} + +macro_rules! end_of_stmt { + ($pat:pat, $expr:expr) => {{ + { + let $pat = $expr; + check_flags(1); + } + check_flags(0); + }}; +} + +fn main() { + end_of_block!(_x, add_flags(1)); + end_of_block!(_x, &add_flags(1)); + end_of_block!(_x, &&add_flags(1)); + end_of_block!(_x, Box { f: add_flags(1) }); + end_of_block!(_x, Box { f: &add_flags(1) }); + end_of_block!(_x, pass(add_flags(1))); + end_of_block!(ref _x, add_flags(1)); + end_of_block!(AddFlags { bits: ref _x }, add_flags(1)); + end_of_block!(&AddFlags { bits: _ }, &add_flags(1)); + end_of_block!((_, ref _y), (add_flags(1), 22)); + end_of_block!(box ref _x, std::boxed::Box::new(add_flags(1))); + end_of_block!(box _x, std::boxed::Box::new(add_flags(1))); + end_of_block!(_, { + { + check_flags(0); + &add_flags(1) + } + }); + end_of_block!(_, &((Box { f: add_flags(1) }).f)); + end_of_block!(_, &(([add_flags(1)])[0])); + + end_of_stmt!(_, add_flags(1)); + end_of_stmt!((_, _), (add_flags(1), 22)); + end_of_stmt!(ref _x, arg(0, &add_flags(1))); + end_of_stmt!(ref _x, add_flags(1).check_flags(0).bits()); + end_of_stmt!(AddFlags { bits: _ }, add_flags(1)); +} diff --git a/tests/ui/cleanup-rvalue-temp-during-incomplete-alloc.rs b/tests/ui/panics/rvalue-cleanup-during-box-panic.rs index 4c59df24e4b..84c5d85d7e0 100644 --- a/tests/ui/cleanup-rvalue-temp-during-incomplete-alloc.rs +++ b/tests/ui/panics/rvalue-cleanup-during-box-panic.rs @@ -25,16 +25,20 @@ use std::thread; enum Conzabble { - Bickwick(Foo) + Bickwick(Foo), } -struct Foo { field: Box<usize> } +struct Foo { + field: Box<usize>, +} fn do_it(x: &[usize]) -> Foo { panic!() } -fn get_bar(x: usize) -> Vec<usize> { vec![x * 2] } +fn get_bar(x: usize) -> Vec<usize> { + vec![x * 2] +} pub fn fails() { let x = 2; diff --git a/tests/ui/traits/next-solver/coherence/coherence-fulfill-overflow.stderr b/tests/ui/traits/next-solver/coherence/coherence-fulfill-overflow.stderr index 57cba790b55..7d39c82d22f 100644 --- a/tests/ui/traits/next-solver/coherence/coherence-fulfill-overflow.stderr +++ b/tests/ui/traits/next-solver/coherence/coherence-fulfill-overflow.stderr @@ -1,13 +1,10 @@ -error[E0119]: conflicting implementations of trait `Trait` for type `W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<_>>>>>>>>>>>>>>>>>>>>>` +error[E0119]: conflicting implementations of trait `Trait` for type `W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<_>>>>>>>>>>>>>>>>>>>>>>>` --> $DIR/coherence-fulfill-overflow.rs:12:1 | LL | impl<T: ?Sized + TwoW> Trait for W<T> {} | ------------------------------------- first implementation here LL | impl<T: ?Sized + TwoW> Trait for T {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<_>>>>>>>>>>>>>>>>>>>>>` - | - = note: overflow evaluating the requirement `W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<_>>>>>>>>>>>>>>>>>>>>>: TwoW` - = help: consider increasing the recursion limit by adding a `#![recursion_limit = "20"]` attribute to your crate (`coherence_fulfill_overflow`) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<_>>>>>>>>>>>>>>>>>>>>>>>` error: aborting due to 1 previous error diff --git a/triagebot.toml b/triagebot.toml index db263a3768f..15c56f8861f 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -1210,6 +1210,7 @@ compiler = [ "@fee1-dead", "@fmease", "@jieyouxu", + "@jdonszelmann", "@lcnr", "@Nadrieril", "@nnethercote", |
