diff options
Diffstat (limited to 'compiler')
161 files changed, 2492 insertions, 1252 deletions
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 4f55f37e2e9..a2d32cdc00f 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -510,8 +510,10 @@ pub struct Crate { pub attrs: Vec<Attribute>, pub items: Vec<P<Item>>, pub span: Span, - // Placeholder ID if the crate node is a macro placeholder. - pub is_placeholder: Option<NodeId>, + /// Must be equal to `CRATE_NODE_ID` after the crate root is expanded, but may hold + /// expansion placeholders or an unassigned value (`DUMMY_NODE_ID`) before that. + pub id: NodeId, + pub is_placeholder: bool, } /// Possible values inside of compile-time attribute lists. diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs index 927d7c6aaf6..d66774040f7 100644 --- a/compiler/rustc_ast/src/attr/mod.rs +++ b/compiler/rustc_ast/src/attr/mod.rs @@ -136,15 +136,15 @@ impl Attribute { pub fn value_str(&self) -> Option<Symbol> { match self.kind { - AttrKind::Normal(ref item, _) => item.meta(self.span).and_then(|meta| meta.value_str()), + AttrKind::Normal(ref item, _) => item.meta_kind().and_then(|kind| kind.value_str()), AttrKind::DocComment(..) => None, } } pub fn meta_item_list(&self) -> Option<Vec<NestedMetaItem>> { match self.kind { - AttrKind::Normal(ref item, _) => match item.meta(self.span) { - Some(MetaItem { kind: MetaItemKind::List(list), .. }) => Some(list), + AttrKind::Normal(ref item, _) => match item.meta_kind() { + Some(MetaItemKind::List(list)) => Some(list), _ => None, }, AttrKind::DocComment(..) => None, @@ -228,6 +228,10 @@ impl AttrItem { span, }) } + + pub fn meta_kind(&self) -> Option<MetaItemKind> { + Some(MetaItemKind::from_mac_args(&self.args)?) + } } impl Attribute { @@ -242,7 +246,7 @@ impl Attribute { match self.kind { AttrKind::DocComment(.., data) => Some(data), AttrKind::Normal(ref item, _) if item.path == sym::doc => { - item.meta(self.span).and_then(|meta| meta.value_str()) + item.meta_kind().and_then(|kind| kind.value_str()) } _ => None, } @@ -270,6 +274,13 @@ impl Attribute { } } + pub fn meta_kind(&self) -> Option<MetaItemKind> { + match self.kind { + AttrKind::Normal(ref item, _) => item.meta_kind(), + AttrKind::DocComment(..) => None, + } + } + pub fn tokens(&self) -> AttrAnnotatedTokenStream { match self.kind { AttrKind::Normal(_, ref tokens) => tokens @@ -436,6 +447,16 @@ impl MetaItem { } impl MetaItemKind { + pub fn value_str(&self) -> Option<Symbol> { + match self { + MetaItemKind::NameValue(ref v) => match v.kind { + LitKind::Str(ref s, _) => Some(*s), + _ => None, + }, + _ => None, + } + } + pub fn mac_args(&self, span: Span) -> MacArgs { match self { MetaItemKind::Word => MacArgs::Empty, diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index 6bf23af81bf..9ef78aaf667 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -14,13 +14,14 @@ use crate::tokenstream::*; use rustc_data_structures::map_in_place::MapInPlace; use rustc_data_structures::sync::Lrc; +use rustc_data_structures::thin_vec::ThinVec; use rustc_span::source_map::Spanned; use rustc_span::symbol::Ident; use rustc_span::Span; use smallvec::{smallvec, Array, SmallVec}; use std::ops::DerefMut; -use std::{panic, process, ptr}; +use std::{panic, ptr}; pub trait ExpectOne<A: Array> { fn expect_one(self, err: &'static str) -> A::Item; @@ -283,23 +284,21 @@ pub trait MutVisitor: Sized { /// Use a map-style function (`FnOnce(T) -> T`) to overwrite a `&mut T`. Useful /// when using a `flat_map_*` or `filter_map_*` method within a `visit_` -/// method. Abort the program if the closure panics. -/// -/// FIXME: Abort on panic means that any fatal error inside `visit_clobber` will abort the compiler. -/// Instead of aborting on catching a panic we need to reset the visited node to some valid but -/// possibly meaningless value and rethrow the panic. +/// method. // // No `noop_` prefix because there isn't a corresponding method in `MutVisitor`. -pub fn visit_clobber<T, F>(t: &mut T, f: F) -where - F: FnOnce(T) -> T, -{ +pub fn visit_clobber<T: DummyAstNode>(t: &mut T, f: impl FnOnce(T) -> T) { unsafe { // Safe because `t` is used in a read-only fashion by `read()` before // being overwritten by `write()`. let old_t = ptr::read(t); - let new_t = panic::catch_unwind(panic::AssertUnwindSafe(|| f(old_t))) - .unwrap_or_else(|_| process::abort()); + let new_t = + panic::catch_unwind(panic::AssertUnwindSafe(|| f(old_t))).unwrap_or_else(|err| { + // Set `t` to some valid but possible meaningless value, + // and pass the fatal error further. + ptr::write(t, T::dummy()); + panic::resume_unwind(err); + }); ptr::write(t, new_t); } } @@ -1110,7 +1109,8 @@ pub fn noop_visit_fn_header<T: MutVisitor>(header: &mut FnHeader, vis: &mut T) { } pub fn noop_visit_crate<T: MutVisitor>(krate: &mut Crate, vis: &mut T) { - let Crate { attrs, items, span, is_placeholder: _ } = krate; + let Crate { attrs, items, span, id, is_placeholder: _ } = krate; + vis.visit_id(id); visit_attrs(attrs, vis); items.flat_map_in_place(|item| vis.flat_map_item(item)); vis.visit_span(span); @@ -1454,3 +1454,109 @@ pub fn noop_visit_vis<T: MutVisitor>(visibility: &mut Visibility, vis: &mut T) { } vis.visit_span(&mut visibility.span); } + +/// Some value for the AST node that is valid but possibly meaningless. +pub trait DummyAstNode { + fn dummy() -> Self; +} + +impl<T> DummyAstNode for Option<T> { + fn dummy() -> Self { + Default::default() + } +} + +impl<T: DummyAstNode + 'static> DummyAstNode for P<T> { + fn dummy() -> Self { + P(DummyAstNode::dummy()) + } +} + +impl<T> DummyAstNode for ThinVec<T> { + fn dummy() -> Self { + Default::default() + } +} + +impl DummyAstNode for Item { + fn dummy() -> Self { + Item { + attrs: Default::default(), + id: DUMMY_NODE_ID, + span: Default::default(), + vis: Visibility { + kind: VisibilityKind::Public, + span: Default::default(), + tokens: Default::default(), + }, + ident: Ident::empty(), + kind: ItemKind::ExternCrate(None), + tokens: Default::default(), + } + } +} + +impl DummyAstNode for Expr { + fn dummy() -> Self { + Expr { + id: DUMMY_NODE_ID, + kind: ExprKind::Err, + span: Default::default(), + attrs: Default::default(), + tokens: Default::default(), + } + } +} + +impl DummyAstNode for Ty { + fn dummy() -> Self { + Ty { + id: DUMMY_NODE_ID, + kind: TyKind::Err, + span: Default::default(), + tokens: Default::default(), + } + } +} + +impl DummyAstNode for Pat { + fn dummy() -> Self { + Pat { + id: DUMMY_NODE_ID, + kind: PatKind::Wild, + span: Default::default(), + tokens: Default::default(), + } + } +} + +impl DummyAstNode for Stmt { + fn dummy() -> Self { + Stmt { id: DUMMY_NODE_ID, kind: StmtKind::Empty, span: Default::default() } + } +} + +impl DummyAstNode for Block { + fn dummy() -> Self { + Block { + stmts: Default::default(), + id: DUMMY_NODE_ID, + rules: BlockCheckMode::Default, + span: Default::default(), + tokens: Default::default(), + could_be_bare_literal: Default::default(), + } + } +} + +impl DummyAstNode for Crate { + fn dummy() -> Self { + Crate { + attrs: Default::default(), + items: Default::default(), + span: Default::default(), + id: DUMMY_NODE_ID, + is_placeholder: Default::default(), + } + } +} diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 6ee1dbe4ae3..75f384405bb 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -34,7 +34,7 @@ impl<'hir> LoweringContext<'_, 'hir> { } ExprKind::Repeat(ref expr, ref count) => { let expr = self.lower_expr(expr); - let count = self.lower_anon_const(count); + let count = self.lower_array_length(count); hir::ExprKind::Repeat(expr, count) } ExprKind::Tup(ref elts) => hir::ExprKind::Tup(self.lower_exprs(elts)), diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 77738b2c5cc..35eb716949a 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -56,6 +56,7 @@ use rustc_hir::{ConstArg, GenericArg, ParamName}; use rustc_index::vec::{Idx, IndexVec}; use rustc_query_system::ich::StableHashingContext; use rustc_session::lint::LintBuffer; +use rustc_session::parse::feature_err; use rustc_session::utils::{FlattenNonterminals, NtToTokenstream}; use rustc_session::Session; use rustc_span::hygiene::ExpnId; @@ -1248,7 +1249,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { )) } TyKind::Array(ref ty, ref length) => { - hir::TyKind::Array(self.lower_ty(ty, itctx), self.lower_anon_const(length)) + hir::TyKind::Array(self.lower_ty(ty, itctx), self.lower_array_length(length)) } TyKind::Typeof(ref expr) => hir::TyKind::Typeof(self.lower_anon_const(expr)), TyKind::TraitObject(ref bounds, kind) => { @@ -2039,6 +2040,26 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { self.expr_block(block, AttrVec::new()) } + fn lower_array_length(&mut self, c: &AnonConst) -> hir::ArrayLen { + match c.value.kind { + ExprKind::Underscore => { + if self.sess.features_untracked().generic_arg_infer { + hir::ArrayLen::Infer(self.lower_node_id(c.id), c.value.span) + } else { + feature_err( + &self.sess.parse_sess, + sym::generic_arg_infer, + c.value.span, + "using `_` for array lengths is unstable", + ) + .emit(); + hir::ArrayLen::Body(self.lower_anon_const(c)) + } + } + _ => hir::ArrayLen::Body(self.lower_anon_const(c)), + } + } + fn lower_anon_const(&mut self, c: &AnonConst) -> hir::AnonConst { self.with_new_scopes(|this| hir::AnonConst { hir_id: this.lower_node_id(c.id), diff --git a/compiler/rustc_ast_lowering/src/pat.rs b/compiler/rustc_ast_lowering/src/pat.rs index 0a9b264aa42..ebae7798433 100644 --- a/compiler/rustc_ast_lowering/src/pat.rs +++ b/compiler/rustc_ast_lowering/src/pat.rs @@ -24,7 +24,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let lower_sub = |this: &mut Self| sub.as_ref().map(|s| this.lower_pat(&*s)); break self.lower_pat_ident(pattern, binding_mode, ident, lower_sub); } - PatKind::Lit(ref e) => break hir::PatKind::Lit(self.lower_expr(e)), + PatKind::Lit(ref e) => { + break hir::PatKind::Lit(self.lower_expr_within_pat(e, false)); + } PatKind::TupleStruct(ref qself, ref path, ref pats) => { let qpath = self.lower_qpath( pattern.id, @@ -81,8 +83,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } PatKind::Range(ref e1, ref e2, Spanned { node: ref end, .. }) => { break hir::PatKind::Range( - e1.as_deref().map(|e| self.lower_expr(e)), - e2.as_deref().map(|e| self.lower_expr(e)), + e1.as_deref().map(|e| self.lower_expr_within_pat(e, true)), + e2.as_deref().map(|e| self.lower_expr_within_pat(e, true)), self.lower_range_end(end, e2.is_some()), ); } @@ -314,4 +316,33 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { RangeEnd::Excluded | RangeEnd::Included(_) => hir::RangeEnd::Included, } } + + /// Matches `'-' lit | lit (cf. parser::Parser::parse_literal_maybe_minus)`, + /// or paths for ranges. + // + // FIXME: do we want to allow `expr -> pattern` conversion to create path expressions? + // That means making this work: + // + // ```rust,ignore (FIXME) + // struct S; + // macro_rules! m { + // ($a:expr) => { + // let $a = S; + // } + // } + // m!(S); + // ``` + fn lower_expr_within_pat(&mut self, expr: &Expr, allow_paths: bool) -> &'hir hir::Expr<'hir> { + match expr.kind { + ExprKind::Lit(..) | ExprKind::ConstBlock(..) | ExprKind::Err => {} + ExprKind::Path(..) if allow_paths => {} + ExprKind::Unary(UnOp::Neg, ref inner) if matches!(inner.kind, ExprKind::Lit(_)) => {} + _ => { + self.diagnostic() + .span_err(expr.span, "arbitrary expressions aren't allowed in patterns"); + return self.arena.alloc(self.expr_err(expr.span)); + } + } + self.lower_expr(expr) + } } diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 3c3ea2bfd35..6237a01f694 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -302,34 +302,6 @@ impl<'a> AstValidator<'a> { } } - /// Matches `'-' lit | lit (cf. parser::Parser::parse_literal_maybe_minus)`, - /// or paths for ranges. - // - // FIXME: do we want to allow `expr -> pattern` conversion to create path expressions? - // That means making this work: - // - // ```rust,ignore (FIXME) - // struct S; - // macro_rules! m { - // ($a:expr) => { - // let $a = S; - // } - // } - // m!(S); - // ``` - fn check_expr_within_pat(&self, expr: &Expr, allow_paths: bool) { - match expr.kind { - ExprKind::Lit(..) | ExprKind::ConstBlock(..) | ExprKind::Err => {} - ExprKind::Path(..) if allow_paths => {} - ExprKind::Unary(UnOp::Neg, ref inner) if matches!(inner.kind, ExprKind::Lit(_)) => {} - _ => self.err_handler().span_err( - expr.span, - "arbitrary expressions aren't allowed \ - in patterns", - ), - } - } - fn check_late_bound_lifetime_defs(&self, params: &[GenericParam]) { // Check only lifetime parameters are present and that the lifetime // parameters that are present have no bounds. @@ -1426,25 +1398,6 @@ impl<'a> Visitor<'a> for AstValidator<'a> { visit::walk_param_bound(self, bound) } - fn visit_pat(&mut self, pat: &'a Pat) { - match &pat.kind { - PatKind::Lit(expr) => { - self.check_expr_within_pat(expr, false); - } - PatKind::Range(start, end, _) => { - if let Some(expr) = start { - self.check_expr_within_pat(expr, true); - } - if let Some(expr) = end { - self.check_expr_within_pat(expr, true); - } - } - _ => {} - } - - visit::walk_pat(self, pat) - } - fn visit_poly_trait_ref(&mut self, t: &'a PolyTraitRef, m: &'a TraitBoundModifier) { self.check_late_bound_lifetime_defs(&t.bound_generic_params); visit::walk_poly_trait_ref(self, t, m); diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index c2253e63356..3267945f427 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -1116,7 +1116,9 @@ impl<'a> State<'a> { self.print_ident(ident); self.word_space(":"); self.print_type(ty); - self.space(); + if body.is_some() { + self.space(); + } self.end(); // end the head-ibox if let Some(body) = body { self.word_space("="); @@ -2242,7 +2244,6 @@ impl<'a> State<'a> { } ast::ExprKind::TryBlock(ref blk) => { self.head("try"); - self.space(); self.print_block_with_attrs(blk, attrs) } ast::ExprKind::Err => { @@ -2463,7 +2464,11 @@ impl<'a> State<'a> { self.print_path(path, true, 0); } self.nbsp(); - self.word_space("{"); + self.word("{"); + let empty = fields.is_empty() && !etc; + if !empty { + self.space(); + } self.commasep_cmnt( Consistent, &fields, @@ -2484,7 +2489,9 @@ impl<'a> State<'a> { } self.word(".."); } - self.space(); + if !empty { + self.space(); + } self.word("}"); } PatKind::Tuple(ref elts) => { @@ -2518,7 +2525,6 @@ impl<'a> State<'a> { PatKind::Range(ref begin, ref end, Spanned { node: ref end_kind, .. }) => { if let Some(e) = begin { self.print_expr(e); - self.space(); } match *end_kind { RangeEnd::Included(RangeSyntax::DotDotDot) => self.word("..."), diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs index 11cdbe84acc..df23eaf24bc 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs @@ -6,7 +6,7 @@ use rustc_infer::infer::{ error_reporting::unexpected_hidden_region_diagnostic, NllRegionVariableOrigin, }; use rustc_middle::mir::{ConstraintCategory, ReturnConstraint}; -use rustc_middle::ty::subst::Subst; +use rustc_middle::ty::subst::{InternalSubsts, Subst}; use rustc_middle::ty::{self, RegionVid, Ty}; use rustc_span::symbol::{kw, sym}; use rustc_span::{BytePos, Span}; @@ -334,13 +334,43 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { match variance_info { ty::VarianceDiagInfo::None => {} - ty::VarianceDiagInfo::Mut { kind, ty } => { - let kind_name = match kind { - ty::VarianceDiagMutKind::Ref => "reference", - ty::VarianceDiagMutKind::RawPtr => "pointer", + ty::VarianceDiagInfo::Invariant { ty, param_index } => { + let (desc, note) = match ty.kind() { + ty::RawPtr(ty_mut) => { + assert_eq!(ty_mut.mutbl, rustc_hir::Mutability::Mut); + ( + format!("a mutable pointer to {}", ty_mut.ty), + "mutable pointers are invariant over their type parameter".to_string(), + ) + } + ty::Ref(_, inner_ty, mutbl) => { + assert_eq!(*mutbl, rustc_hir::Mutability::Mut); + ( + format!("a mutable reference to {}", inner_ty), + "mutable references are invariant over their type parameter" + .to_string(), + ) + } + ty::Adt(adt, substs) => { + let generic_arg = substs[param_index as usize]; + let identity_substs = + InternalSubsts::identity_for_item(self.infcx.tcx, adt.did); + let base_ty = self.infcx.tcx.mk_adt(adt, identity_substs); + let base_generic_arg = identity_substs[param_index as usize]; + let adt_desc = adt.descr(); + + let desc = format!( + "the type {ty}, which makes the generic argument {generic_arg} invariant" + ); + let note = format!( + "the {adt_desc} {base_ty} is invariant over the parameter {base_generic_arg}" + ); + (desc, note) + } + _ => panic!("Unexpected type {:?}", ty), }; - diag.note(&format!("requirement occurs because of a mutable {kind_name} to {ty}",)); - diag.note(&format!("mutable {kind_name}s are invariant over their type parameter")); + diag.note(&format!("requirement occurs because of {desc}",)); + diag.note(¬e); diag.help("see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance"); } } diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 63ffcb3ec45..fe34d6e7ca9 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -1394,10 +1394,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { Rvalue::NullaryOp(_op, _ty) => { // nullary ops take no dynamic input; no borrowck effect. - // - // FIXME: is above actually true? Do we want to track - // the fact that uninitialized data can be created via - // `NullOp::Box`? } Rvalue::Aggregate(ref aggregate_kind, ref operands) => { diff --git a/compiler/rustc_borrowck/src/region_infer/values.rs b/compiler/rustc_borrowck/src/region_infer/values.rs index 100ac578f92..4a70535c63b 100644 --- a/compiler/rustc_borrowck/src/region_infer/values.rs +++ b/compiler/rustc_borrowck/src/region_infer/values.rs @@ -1,5 +1,7 @@ use rustc_data_structures::fx::FxIndexSet; -use rustc_index::bit_set::{HybridBitSet, SparseBitMatrix}; +use rustc_index::bit_set::SparseBitMatrix; +use rustc_index::interval::IntervalSet; +use rustc_index::interval::SparseIntervalMatrix; use rustc_index::vec::Idx; use rustc_index::vec::IndexVec; use rustc_middle::mir::{BasicBlock, Body, Location}; @@ -110,11 +112,11 @@ crate enum RegionElement { PlaceholderRegion(ty::PlaceholderRegion), } -/// When we initially compute liveness, we use a bit matrix storing -/// points for each region-vid. +/// When we initially compute liveness, we use an interval matrix storing +/// liveness ranges for each region-vid. crate struct LivenessValues<N: Idx> { elements: Rc<RegionValueElements>, - points: SparseBitMatrix<N, PointIndex>, + points: SparseIntervalMatrix<N, PointIndex>, } impl<N: Idx> LivenessValues<N> { @@ -122,7 +124,7 @@ impl<N: Idx> LivenessValues<N> { /// Each of the regions in num_region_variables will be initialized with an /// empty set of points and no causal information. crate fn new(elements: Rc<RegionValueElements>) -> Self { - Self { points: SparseBitMatrix::new(elements.num_points), elements } + Self { points: SparseIntervalMatrix::new(elements.num_points), elements } } /// Iterate through each region that has a value in this set. @@ -140,7 +142,7 @@ impl<N: Idx> LivenessValues<N> { /// Adds all the elements in the given bit array into the given /// region. Returns whether any of them are newly added. - crate fn add_elements(&mut self, row: N, locations: &HybridBitSet<PointIndex>) -> bool { + crate fn add_elements(&mut self, row: N, locations: &IntervalSet<PointIndex>) -> bool { debug!("LivenessValues::add_elements(row={:?}, locations={:?})", row, locations); self.points.union_row(row, locations) } @@ -153,7 +155,7 @@ impl<N: Idx> LivenessValues<N> { /// Returns `true` if the region `r` contains the given element. crate fn contains(&self, row: N, location: Location) -> bool { let index = self.elements.point_from_location(location); - self.points.contains(row, index) + self.points.row(row).map_or(false, |r| r.contains(index)) } /// Returns an iterator of all the elements contained by the region `r` @@ -221,7 +223,7 @@ impl PlaceholderIndices { crate struct RegionValues<N: Idx> { elements: Rc<RegionValueElements>, placeholder_indices: Rc<PlaceholderIndices>, - points: SparseBitMatrix<N, PointIndex>, + points: SparseIntervalMatrix<N, PointIndex>, free_regions: SparseBitMatrix<N, RegionVid>, /// Placeholders represent bound regions -- so something like `'a` @@ -241,7 +243,7 @@ impl<N: Idx> RegionValues<N> { let num_placeholders = placeholder_indices.len(); Self { elements: elements.clone(), - points: SparseBitMatrix::new(elements.num_points), + points: SparseIntervalMatrix::new(elements.num_points), placeholder_indices: placeholder_indices.clone(), free_regions: SparseBitMatrix::new(num_universal_regions), placeholders: SparseBitMatrix::new(num_placeholders), diff --git a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs index 0969b9a508f..094af20f52e 100644 --- a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs +++ b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs @@ -1,5 +1,6 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_index::bit_set::HybridBitSet; +use rustc_index::interval::IntervalSet; use rustc_infer::infer::canonical::QueryRegionConstraints; use rustc_middle::mir::{BasicBlock, Body, ConstraintCategory, Local, Location}; use rustc_middle::ty::{Ty, TypeFoldable}; @@ -105,12 +106,12 @@ struct LivenessResults<'me, 'typeck, 'flow, 'tcx> { /// Points where the current variable is "use live" -- meaning /// that there is a future "full use" that may use its value. - use_live_at: HybridBitSet<PointIndex>, + use_live_at: IntervalSet<PointIndex>, /// Points where the current variable is "drop live" -- meaning /// that there is no future "full use" that may use its value, but /// there is a future drop. - drop_live_at: HybridBitSet<PointIndex>, + drop_live_at: IntervalSet<PointIndex>, /// Locations where drops may occur. drop_locations: Vec<Location>, @@ -125,8 +126,8 @@ impl<'me, 'typeck, 'flow, 'tcx> LivenessResults<'me, 'typeck, 'flow, 'tcx> { LivenessResults { cx, defs: HybridBitSet::new_empty(num_points), - use_live_at: HybridBitSet::new_empty(num_points), - drop_live_at: HybridBitSet::new_empty(num_points), + use_live_at: IntervalSet::new(num_points), + drop_live_at: IntervalSet::new(num_points), drop_locations: vec![], stack: vec![], } @@ -165,7 +166,7 @@ impl<'me, 'typeck, 'flow, 'tcx> LivenessResults<'me, 'typeck, 'flow, 'tcx> { drop_used: Vec<(Local, Location)>, live_locals: FxHashSet<Local>, ) { - let locations = HybridBitSet::new_empty(self.cx.elements.num_points()); + let locations = IntervalSet::new(self.cx.elements.num_points()); for (local, location) in drop_used { if !live_locals.contains(&local) { @@ -456,7 +457,7 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> { fn add_use_live_facts_for( &mut self, value: impl TypeFoldable<'tcx>, - live_at: &HybridBitSet<PointIndex>, + live_at: &IntervalSet<PointIndex>, ) { debug!("add_use_live_facts_for(value={:?})", value); @@ -473,7 +474,7 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> { dropped_local: Local, dropped_ty: Ty<'tcx>, drop_locations: &[Location], - live_at: &HybridBitSet<PointIndex>, + live_at: &IntervalSet<PointIndex>, ) { debug!( "add_drop_live_constraint(\ @@ -521,7 +522,7 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> { elements: &RegionValueElements, typeck: &mut TypeChecker<'_, 'tcx>, value: impl TypeFoldable<'tcx>, - live_at: &HybridBitSet<PointIndex>, + live_at: &IntervalSet<PointIndex>, ) { debug!("make_all_regions_live(value={:?})", value); debug!( diff --git a/compiler/rustc_builtin_macros/src/concat_bytes.rs b/compiler/rustc_builtin_macros/src/concat_bytes.rs index a107f5993b5..eb08170959b 100644 --- a/compiler/rustc_builtin_macros/src/concat_bytes.rs +++ b/compiler/rustc_builtin_macros/src/concat_bytes.rs @@ -72,6 +72,52 @@ fn invalid_type_err(cx: &mut base::ExtCtxt<'_>, expr: &P<rustc_ast::Expr>, is_ne } } +fn handle_array_element( + cx: &mut base::ExtCtxt<'_>, + has_errors: &mut bool, + missing_literals: &mut Vec<rustc_span::Span>, + expr: &P<rustc_ast::Expr>, +) -> Option<u8> { + match expr.kind { + ast::ExprKind::Array(_) | ast::ExprKind::Repeat(_, _) => { + if !*has_errors { + cx.span_err(expr.span, "cannot concatenate doubly nested array"); + } + *has_errors = true; + None + } + ast::ExprKind::Lit(ref lit) => match lit.kind { + ast::LitKind::Int( + val, + ast::LitIntType::Unsuffixed | ast::LitIntType::Unsigned(ast::UintTy::U8), + ) if val <= u8::MAX.into() => Some(val as u8), + + ast::LitKind::Byte(val) => Some(val), + ast::LitKind::ByteStr(_) => { + if !*has_errors { + cx.struct_span_err(expr.span, "cannot concatenate doubly nested array") + .note("byte strings are treated as arrays of bytes") + .help("try flattening the array") + .emit(); + } + *has_errors = true; + None + } + _ => { + if !*has_errors { + invalid_type_err(cx, expr, true); + } + *has_errors = true; + None + } + }, + _ => { + missing_literals.push(expr.span); + None + } + } +} + pub fn expand_concat_bytes( cx: &mut base::ExtCtxt<'_>, sp: rustc_span::Span, @@ -88,48 +134,27 @@ pub fn expand_concat_bytes( match e.kind { ast::ExprKind::Array(ref exprs) => { for expr in exprs { - match expr.kind { - ast::ExprKind::Array(_) => { - if !has_errors { - cx.span_err(expr.span, "cannot concatenate doubly nested array"); - } - has_errors = true; - } - ast::ExprKind::Lit(ref lit) => match lit.kind { - ast::LitKind::Int( - val, - ast::LitIntType::Unsuffixed - | ast::LitIntType::Unsigned(ast::UintTy::U8), - ) if val <= u8::MAX.into() => { - accumulator.push(val as u8); - } - - ast::LitKind::Byte(val) => { - accumulator.push(val); - } - ast::LitKind::ByteStr(_) => { - if !has_errors { - cx.struct_span_err( - expr.span, - "cannot concatenate doubly nested array", - ) - .note("byte strings are treated as arrays of bytes") - .help("try flattening the array") - .emit(); - } - has_errors = true; - } - _ => { - if !has_errors { - invalid_type_err(cx, expr, true); - } - has_errors = true; - } - }, - _ => { - missing_literals.push(expr.span); + if let Some(elem) = + handle_array_element(cx, &mut has_errors, &mut missing_literals, expr) + { + accumulator.push(elem); + } + } + } + ast::ExprKind::Repeat(ref expr, ref count) => { + if let ast::ExprKind::Lit(ast::Lit { + kind: ast::LitKind::Int(count_val, _), .. + }) = count.value.kind + { + if let Some(elem) = + handle_array_element(cx, &mut has_errors, &mut missing_literals, expr) + { + for _ in 0..count_val { + accumulator.push(elem); } } + } else { + cx.span_err(count.value.span, "repeat count is not a positive number"); } } ast::ExprKind::Lit(ref lit) => match lit.kind { diff --git a/compiler/rustc_builtin_macros/src/format_foreign.rs b/compiler/rustc_builtin_macros/src/format_foreign.rs index bfddd7073ff..ecd16736e7c 100644 --- a/compiler/rustc_builtin_macros/src/format_foreign.rs +++ b/compiler/rustc_builtin_macros/src/format_foreign.rs @@ -7,28 +7,29 @@ pub(crate) mod printf { pub enum Substitution<'a> { /// A formatted output substitution with its internal byte offset. Format(Format<'a>), - /// A literal `%%` escape. - Escape, + /// A literal `%%` escape, with its start and end indices. + Escape((usize, usize)), } impl<'a> Substitution<'a> { pub fn as_str(&self) -> &str { match *self { Substitution::Format(ref fmt) => fmt.span, - Substitution::Escape => "%%", + Substitution::Escape(_) => "%%", } } pub fn position(&self) -> Option<InnerSpan> { match *self { Substitution::Format(ref fmt) => Some(fmt.position), - _ => None, + Substitution::Escape((start, end)) => Some(InnerSpan::new(start, end)), } } pub fn set_position(&mut self, start: usize, end: usize) { - if let Substitution::Format(ref mut fmt) = self { - fmt.position = InnerSpan::new(start, end); + match self { + Substitution::Format(ref mut fmt) => fmt.position = InnerSpan::new(start, end), + Substitution::Escape(ref mut pos) => *pos = (start, end), } } @@ -39,7 +40,7 @@ pub(crate) mod printf { pub fn translate(&self) -> Result<String, Option<String>> { match *self { Substitution::Format(ref fmt) => fmt.translate(), - Substitution::Escape => Err(None), + Substitution::Escape(_) => Err(None), } } } @@ -304,14 +305,9 @@ pub(crate) mod printf { fn next(&mut self) -> Option<Self::Item> { let (mut sub, tail) = parse_next_substitution(self.s)?; self.s = tail; - match sub { - Substitution::Format(_) => { - if let Some(inner_span) = sub.position() { - sub.set_position(inner_span.start + self.pos, inner_span.end + self.pos); - self.pos += inner_span.end; - } - } - Substitution::Escape => self.pos += 2, + if let Some(InnerSpan { start, end }) = sub.position() { + sub.set_position(start + self.pos, end + self.pos); + self.pos += end; } Some(sub) } @@ -340,7 +336,7 @@ pub(crate) mod printf { let at = { let start = s.find('%')?; if let '%' = s[start + 1..].chars().next()? { - return Some((Substitution::Escape, &s[start + 2..])); + return Some((Substitution::Escape((start, start + 2)), &s[start + 2..])); } Cur::new_at(s, start) diff --git a/compiler/rustc_builtin_macros/src/format_foreign/printf/tests.rs b/compiler/rustc_builtin_macros/src/format_foreign/printf/tests.rs index 1336aab7316..fc7442470ac 100644 --- a/compiler/rustc_builtin_macros/src/format_foreign/printf/tests.rs +++ b/compiler/rustc_builtin_macros/src/format_foreign/printf/tests.rs @@ -13,9 +13,9 @@ macro_rules! assert_eq_pnsat { fn test_escape() { assert_eq!(pns("has no escapes"), None); assert_eq!(pns("has no escapes, either %"), None); - assert_eq!(pns("*so* has a %% escape"), Some((S::Escape, " escape"))); - assert_eq!(pns("%% leading escape"), Some((S::Escape, " leading escape"))); - assert_eq!(pns("trailing escape %%"), Some((S::Escape, ""))); + assert_eq!(pns("*so* has a %% escape"), Some((S::Escape((11, 13)), " escape"))); + assert_eq!(pns("%% leading escape"), Some((S::Escape((0, 2)), " leading escape"))); + assert_eq!(pns("trailing escape %%"), Some((S::Escape((16, 18)), ""))); } #[test] diff --git a/compiler/rustc_codegen_cranelift/.github/workflows/main.yml b/compiler/rustc_codegen_cranelift/.github/workflows/main.yml index 7b73d3c00e6..3aba528abfd 100644 --- a/compiler/rustc_codegen_cranelift/.github/workflows/main.yml +++ b/compiler/rustc_codegen_cranelift/.github/workflows/main.yml @@ -5,6 +5,21 @@ on: - pull_request jobs: + rustfmt: + runs-on: ubuntu-latest + timeout-minutes: 10 + + steps: + - uses: actions/checkout@v2 + + - name: Install rustfmt + run: | + rustup component add rustfmt + + - name: Rustfmt + run: | + cargo fmt --check + build: runs-on: ${{ matrix.os }} timeout-minutes: 60 diff --git a/compiler/rustc_codegen_cranelift/.github/workflows/nightly-cranelift.yml b/compiler/rustc_codegen_cranelift/.github/workflows/nightly-cranelift.yml index c5b96a47828..a019793edd8 100644 --- a/compiler/rustc_codegen_cranelift/.github/workflows/nightly-cranelift.yml +++ b/compiler/rustc_codegen_cranelift/.github/workflows/nightly-cranelift.yml @@ -3,7 +3,7 @@ name: Test nightly Cranelift on: push: schedule: - - cron: '1 17 * * *' # At 01:17 UTC every day. + - cron: '17 1 * * *' # At 01:17 UTC every day. jobs: build: diff --git a/compiler/rustc_codegen_cranelift/.gitignore b/compiler/rustc_codegen_cranelift/.gitignore index b6567aca786..5aeaf3a1788 100644 --- a/compiler/rustc_codegen_cranelift/.gitignore +++ b/compiler/rustc_codegen_cranelift/.gitignore @@ -7,6 +7,7 @@ perf.data.old *.events *.string* /y.bin +/y.bin.dSYM /build /build_sysroot/sysroot_src /build_sysroot/compiler-builtins diff --git a/compiler/rustc_codegen_cranelift/Cargo.toml b/compiler/rustc_codegen_cranelift/Cargo.toml index 900411286b5..3be4250296e 100644 --- a/compiler/rustc_codegen_cranelift/Cargo.toml +++ b/compiler/rustc_codegen_cranelift/Cargo.toml @@ -40,31 +40,12 @@ unstable-features = ["jit", "inline_asm"] jit = ["cranelift-jit", "libloading"] inline_asm = [] -[profile.dev] -# By compiling dependencies with optimizations, performing tests gets much faster. -opt-level = 3 - -[profile.dev.package.rustc_codegen_cranelift] -# Disabling optimizations for cg_clif itself makes compilation after a change faster. -opt-level = 0 - -[profile.release.package.rustc_codegen_cranelift] -incremental = true - # Disable optimizations and debuginfo of build scripts and some of the heavy build deps, as the # execution time of build scripts is so fast that optimizing them slows down the total build time. -[profile.dev.build-override] -opt-level = 0 -debug = false - [profile.release.build-override] opt-level = 0 debug = false -[profile.dev.package.cranelift-codegen-meta] -opt-level = 0 -debug = false - [profile.release.package.cranelift-codegen-meta] opt-level = 0 debug = false diff --git a/compiler/rustc_codegen_cranelift/Readme.md b/compiler/rustc_codegen_cranelift/Readme.md index dad8ed90b53..8a2db5a43ec 100644 --- a/compiler/rustc_codegen_cranelift/Readme.md +++ b/compiler/rustc_codegen_cranelift/Readme.md @@ -37,7 +37,7 @@ Assuming `$cg_clif_dir` is the directory you cloned this repo into and you follo In the directory with your project (where you can do the usual `cargo build`), run: ```bash -$ $cg_clif_dir/build/cargo build +$ $cg_clif_dir/build/cargo-clif build ``` This will build your project with rustc_codegen_cranelift instead of the usual LLVM backend. diff --git a/compiler/rustc_codegen_cranelift/build_system/build_backend.rs b/compiler/rustc_codegen_cranelift/build_system/build_backend.rs index ccc50ee4a59..1382c7e5379 100644 --- a/compiler/rustc_codegen_cranelift/build_system/build_backend.rs +++ b/compiler/rustc_codegen_cranelift/build_system/build_backend.rs @@ -10,6 +10,18 @@ pub(crate) fn build_backend( let mut cmd = Command::new("cargo"); cmd.arg("build").arg("--target").arg(host_triple); + cmd.env("CARGO_BUILD_INCREMENTAL", "true"); // Force incr comp even in release mode + + let mut rustflags = env::var("RUSTFLAGS").unwrap_or_default(); + + if env::var("CI").as_ref().map(|val| &**val) == Ok("true") { + // Deny warnings on CI + rustflags += " -Dwarnings"; + + // Disabling incr comp reduces cache size and incr comp doesn't save as much on CI anyway + cmd.env("CARGO_BUILD_INCREMENTAL", "false"); + } + if use_unstable_features { cmd.arg("--features").arg("unstable-features"); } @@ -22,25 +34,20 @@ pub(crate) fn build_backend( _ => unreachable!(), } + // Set the rpath to make the cg_clif executable find librustc_codegen_cranelift without changing + // LD_LIBRARY_PATH if cfg!(unix) { if cfg!(target_os = "macos") { - cmd.env( - "RUSTFLAGS", - "-Csplit-debuginfo=unpacked \ + rustflags += " -Csplit-debuginfo=unpacked \ -Clink-arg=-Wl,-rpath,@loader_path/../lib \ - -Zosx-rpath-install-name" - .to_string() - + env::var("RUSTFLAGS").as_deref().unwrap_or(""), - ); + -Zosx-rpath-install-name"; } else { - cmd.env( - "RUSTFLAGS", - "-Clink-arg=-Wl,-rpath=$ORIGIN/../lib ".to_string() - + env::var("RUSTFLAGS").as_deref().unwrap_or(""), - ); + rustflags += " -Clink-arg=-Wl,-rpath=$ORIGIN/../lib "; } } + cmd.env("RUSTFLAGS", rustflags); + eprintln!("[BUILD] rustc_codegen_cranelift"); crate::utils::spawn_and_wait(cmd); diff --git a/compiler/rustc_codegen_cranelift/build_system/build_sysroot.rs b/compiler/rustc_codegen_cranelift/build_system/build_sysroot.rs index 1c78e7b5171..2956fb698e1 100644 --- a/compiler/rustc_codegen_cranelift/build_system/build_sysroot.rs +++ b/compiler/rustc_codegen_cranelift/build_system/build_sysroot.rs @@ -46,9 +46,9 @@ pub(crate) fn build_sysroot( // Build and copy cargo wrapper let mut build_cargo_wrapper_cmd = Command::new("rustc"); build_cargo_wrapper_cmd - .arg("scripts/cargo.rs") + .arg("scripts/cargo-clif.rs") .arg("-o") - .arg(target_dir.join("cargo")) + .arg(target_dir.join("cargo-clif")) .arg("-g"); spawn_and_wait(build_cargo_wrapper_cmd); diff --git a/compiler/rustc_codegen_cranelift/docs/usage.md b/compiler/rustc_codegen_cranelift/docs/usage.md index bcc5745d9d1..785c7383783 100644 --- a/compiler/rustc_codegen_cranelift/docs/usage.md +++ b/compiler/rustc_codegen_cranelift/docs/usage.md @@ -9,7 +9,7 @@ Assuming `$cg_clif_dir` is the directory you cloned this repo into and you follo In the directory with your project (where you can do the usual `cargo build`), run: ```bash -$ $cg_clif_dir/build/cargo build +$ $cg_clif_dir/build/cargo-clif build ``` This will build your project with rustc_codegen_cranelift instead of the usual LLVM backend. @@ -32,7 +32,7 @@ In jit mode cg_clif will immediately execute your code without creating an execu > The jit mode will probably need cargo integration to make this possible. ```bash -$ $cg_clif_dir/build/cargo jit +$ $cg_clif_dir/build/cargo-clif jit ``` or @@ -45,7 +45,7 @@ There is also an experimental lazy jit mode. In this mode functions are only com first called. ```bash -$ $cg_clif_dir/build/cargo lazy-jit +$ $cg_clif_dir/build/cargo-clif lazy-jit ``` ## Shell diff --git a/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs b/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs index cbfdb3c44f3..ef3b575d393 100644 --- a/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs +++ b/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs @@ -129,6 +129,7 @@ fn call_return_u128_pair() { return_u128_pair(); } +#[allow(unreachable_code)] // FIXME false positive fn main() { take_unique(Unique { pointer: 0 as *const (), diff --git a/compiler/rustc_codegen_cranelift/rust-toolchain b/compiler/rustc_codegen_cranelift/rust-toolchain index 7b5db307a2d..cab94c0b8cf 100644 --- a/compiler/rustc_codegen_cranelift/rust-toolchain +++ b/compiler/rustc_codegen_cranelift/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2021-12-20" +channel = "nightly-2021-12-30" components = ["rust-src", "rustc-dev", "llvm-tools-preview"] diff --git a/compiler/rustc_codegen_cranelift/scripts/cargo.rs b/compiler/rustc_codegen_cranelift/scripts/cargo-clif.rs index 41d82b581cd..41d82b581cd 100644 --- a/compiler/rustc_codegen_cranelift/scripts/cargo.rs +++ b/compiler/rustc_codegen_cranelift/scripts/cargo-clif.rs diff --git a/compiler/rustc_codegen_cranelift/scripts/setup_rust_fork.sh b/compiler/rustc_codegen_cranelift/scripts/setup_rust_fork.sh index 46c3b5b7f11..73600faa1e9 100644 --- a/compiler/rustc_codegen_cranelift/scripts/setup_rust_fork.sh +++ b/compiler/rustc_codegen_cranelift/scripts/setup_rust_fork.sh @@ -1,7 +1,7 @@ #!/bin/bash set -e -./y.rs build +./y.rs build --no-unstable-features source scripts/config.sh echo "[SETUP] Rust fork" diff --git a/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh b/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh index 99fddf5361e..6bcc3049ecc 100755 --- a/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh +++ b/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh @@ -47,6 +47,8 @@ rm src/test/ui/codegen/init-large-type.rs # same rm src/test/ui/sse2.rs # cpuid not supported, so sse2 not detected rm src/test/ui/issues/issue-33992.rs # unsupported linkages rm src/test/ui/issues/issue-51947.rs # same +rm src/test/incremental/hashes/function_interfaces.rs # same +rm src/test/incremental/hashes/statics.rs # same rm src/test/ui/numbers-arithmetic/saturating-float-casts.rs # intrinsic gives different but valid result rm src/test/ui/mir/mir_misc_casts.rs # depends on deduplication of constants rm src/test/ui/mir/mir_raw_fat_ptr.rs # same @@ -60,18 +62,14 @@ rm src/test/ui/intrinsics/intrinsic-nearby.rs # unimplemented nearbyintf32 and n rm src/test/incremental/hashes/inline_asm.rs # inline asm rm src/test/incremental/issue-72386.rs # same -rm src/test/incremental/issue-49482.rs # same -rm src/test/incremental/issue-54059.rs # same rm src/test/incremental/lto.rs # requires lto +rm src/test/incremental/dirty_clean.rs # TODO rm -r src/test/run-make/emit-shared-files # requires the rustdoc executable in build/bin/ rm -r src/test/run-make/unstable-flag-required # same rm -r src/test/run-make/rustdoc-* # same rm -r src/test/run-make/emit-named-files # requires full --emit support -rm src/test/pretty/asm.rs # inline asm -rm src/test/pretty/raw-str-nonexpr.rs # same - rm -r src/test/run-pass-valgrind/unsized-locals rm src/test/ui/json-bom-plus-crlf-multifile.rs # differing warning @@ -97,6 +95,12 @@ rm src/test/ui/command/command-current-dir.rs # can't find libstd.so rm src/test/ui/abi/stack-protector.rs # requires stack protector support +rm src/test/incremental/issue-80691-bad-eval-cache.rs # wrong exit code +rm src/test/incremental/spike-neg1.rs # errors out for some reason +rm src/test/incremental/spike-neg2.rs # same + +rm src/test/incremental/thinlto/cgu_invalidated_when_import_{added,removed}.rs # requires LLVM + echo "[TEST] rustc test suite" -RUST_TEST_NOCAPTURE=1 COMPILETEST_FORCE_STAGE0=1 ./x.py test --stage 0 src/test/{codegen-units,run-make,run-pass-valgrind,ui} +RUST_TEST_NOCAPTURE=1 COMPILETEST_FORCE_STAGE0=1 ./x.py test --stage 0 src/test/{codegen-units,run-make,run-pass-valgrind,ui,incremental} popd diff --git a/compiler/rustc_codegen_cranelift/scripts/tests.sh b/compiler/rustc_codegen_cranelift/scripts/tests.sh index fd2b3761ff0..bdb3de0936d 100755 --- a/compiler/rustc_codegen_cranelift/scripts/tests.sh +++ b/compiler/rustc_codegen_cranelift/scripts/tests.sh @@ -80,73 +80,73 @@ function base_sysroot_tests() { function extended_sysroot_tests() { pushd rand - ../build/cargo clean + ../build/cargo-clif clean if [[ "$HOST_TRIPLE" = "$TARGET_TRIPLE" ]]; then echo "[TEST] rust-random/rand" - ../build/cargo test --workspace + ../build/cargo-clif test --workspace else echo "[AOT] rust-random/rand" - ../build/cargo build --workspace --target $TARGET_TRIPLE --tests + ../build/cargo-clif build --workspace --target $TARGET_TRIPLE --tests fi popd pushd simple-raytracer if [[ "$HOST_TRIPLE" = "$TARGET_TRIPLE" ]]; then echo "[BENCH COMPILE] ebobby/simple-raytracer" - hyperfine --runs "${RUN_RUNS:-10}" --warmup 1 --prepare "../build/cargo clean" \ + hyperfine --runs "${RUN_RUNS:-10}" --warmup 1 --prepare "../build/cargo-clif clean" \ "RUSTC=rustc RUSTFLAGS='' cargo build" \ - "../build/cargo build" + "../build/cargo-clif build" echo "[BENCH RUN] ebobby/simple-raytracer" cp ./target/debug/main ./raytracer_cg_clif hyperfine --runs "${RUN_RUNS:-10}" ./raytracer_cg_llvm ./raytracer_cg_clif else - ../build/cargo clean + ../build/cargo-clif clean echo "[BENCH COMPILE] ebobby/simple-raytracer (skipped)" echo "[COMPILE] ebobby/simple-raytracer" - ../build/cargo build --target $TARGET_TRIPLE + ../build/cargo-clif build --target $TARGET_TRIPLE echo "[BENCH RUN] ebobby/simple-raytracer (skipped)" fi popd pushd build_sysroot/sysroot_src/library/core/tests echo "[TEST] libcore" - ../../../../../build/cargo clean + ../../../../../build/cargo-clif clean if [[ "$HOST_TRIPLE" = "$TARGET_TRIPLE" ]]; then - ../../../../../build/cargo test + ../../../../../build/cargo-clif test else - ../../../../../build/cargo build --target $TARGET_TRIPLE --tests + ../../../../../build/cargo-clif build --target $TARGET_TRIPLE --tests fi popd pushd regex echo "[TEST] rust-lang/regex example shootout-regex-dna" - ../build/cargo clean + ../build/cargo-clif clean export RUSTFLAGS="$RUSTFLAGS --cap-lints warn" # newer aho_corasick versions throw a deprecation warning # Make sure `[codegen mono items] start` doesn't poison the diff - ../build/cargo build --example shootout-regex-dna --target $TARGET_TRIPLE + ../build/cargo-clif build --example shootout-regex-dna --target $TARGET_TRIPLE if [[ "$HOST_TRIPLE" = "$TARGET_TRIPLE" ]]; then cat examples/regexdna-input.txt \ - | ../build/cargo run --example shootout-regex-dna --target $TARGET_TRIPLE \ + | ../build/cargo-clif run --example shootout-regex-dna --target $TARGET_TRIPLE \ | grep -v "Spawned thread" > res.txt diff -u res.txt examples/regexdna-output.txt fi if [[ "$HOST_TRIPLE" = "$TARGET_TRIPLE" ]]; then echo "[TEST] rust-lang/regex tests" - ../build/cargo test --tests -- --exclude-should-panic --test-threads 1 -Zunstable-options -q + ../build/cargo-clif test --tests -- --exclude-should-panic --test-threads 1 -Zunstable-options -q else echo "[AOT] rust-lang/regex tests" - ../build/cargo build --tests --target $TARGET_TRIPLE + ../build/cargo-clif build --tests --target $TARGET_TRIPLE fi popd pushd portable-simd echo "[TEST] rust-lang/portable-simd" - ../build/cargo clean - ../build/cargo build --all-targets --target $TARGET_TRIPLE + ../build/cargo-clif clean + ../build/cargo-clif build --all-targets --target $TARGET_TRIPLE if [[ "$HOST_TRIPLE" = "$TARGET_TRIPLE" ]]; then - ../build/cargo test -q + ../build/cargo-clif test -q fi popd } diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs index fc2f04f146e..b16f5af66f2 100644 --- a/compiler/rustc_codegen_cranelift/src/base.rs +++ b/compiler/rustc_codegen_cranelift/src/base.rs @@ -715,30 +715,6 @@ fn codegen_stmt<'tcx>( let operand = operand.load_scalar(fx); lval.write_cvalue(fx, CValue::by_val(operand, box_layout)); } - Rvalue::NullaryOp(NullOp::Box, content_ty) => { - let usize_type = fx.clif_type(fx.tcx.types.usize).unwrap(); - let content_ty = fx.monomorphize(content_ty); - let layout = fx.layout_of(content_ty); - let llsize = fx.bcx.ins().iconst(usize_type, layout.size.bytes() as i64); - let llalign = fx.bcx.ins().iconst(usize_type, layout.align.abi.bytes() as i64); - let box_layout = fx.layout_of(fx.tcx.mk_box(content_ty)); - - // Allocate space: - let def_id = - match fx.tcx.lang_items().require(rustc_hir::LangItem::ExchangeMalloc) { - Ok(id) => id, - Err(s) => { - fx.tcx - .sess - .fatal(&format!("allocation of `{}` {}", box_layout.ty, s)); - } - }; - let instance = ty::Instance::mono(fx.tcx, def_id).polymorphize(fx.tcx); - let func_ref = fx.get_function_ref(instance); - let call = fx.bcx.ins().call(func_ref, &[llsize, llalign]); - let ptr = fx.bcx.inst_results(call)[0]; - lval.write_cvalue(fx, CValue::by_val(ptr, box_layout)); - } Rvalue::NullaryOp(null_op, ty) => { assert!( lval.layout() @@ -749,7 +725,6 @@ fn codegen_stmt<'tcx>( let val = match null_op { NullOp::SizeOf => layout.size.bytes(), NullOp::AlignOf => layout.align.abi.bytes(), - NullOp::Box => unreachable!(), }; let val = CValue::const_val(fx, fx.layout_of(fx.tcx.types.usize), val.into()); lval.write_cvalue(fx, val); diff --git a/compiler/rustc_codegen_cranelift/src/common.rs b/compiler/rustc_codegen_cranelift/src/common.rs index 644204d10b8..3b6025c73d1 100644 --- a/compiler/rustc_codegen_cranelift/src/common.rs +++ b/compiler/rustc_codegen_cranelift/src/common.rs @@ -237,7 +237,7 @@ pub(crate) struct FunctionCx<'m, 'clif, 'tcx: 'm> { pub(crate) module: &'m mut dyn Module, pub(crate) tcx: TyCtxt<'tcx>, pub(crate) target_config: TargetFrontendConfig, // Cached from module - pub(crate) pointer_type: Type, // Cached from module + pub(crate) pointer_type: Type, // Cached from module pub(crate) constants_cx: ConstantCx, pub(crate) instance: Instance<'tcx>, diff --git a/compiler/rustc_codegen_cranelift/src/debuginfo/emit.rs b/compiler/rustc_codegen_cranelift/src/debuginfo/emit.rs index 4120ba6e533..589910ede96 100644 --- a/compiler/rustc_codegen_cranelift/src/debuginfo/emit.rs +++ b/compiler/rustc_codegen_cranelift/src/debuginfo/emit.rs @@ -67,7 +67,7 @@ impl WriterRelocate { } /// Perform the collected relocations to be usable for JIT usage. - #[cfg(feature = "jit")] + #[cfg(all(feature = "jit", not(windows)))] pub(super) fn relocate_for_jit(mut self, jit_module: &cranelift_jit::JITModule) -> Vec<u8> { for reloc in self.relocs.drain(..) { match reloc.name { diff --git a/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs b/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs index dd19dd5d2b9..638b025be22 100644 --- a/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs @@ -10,7 +10,7 @@ use crate::prelude::*; use rustc_index::vec::IndexVec; use cranelift_codegen::entity::EntityRef; -use cranelift_codegen::ir::{LabelValueLoc, ValueLabel}; +use cranelift_codegen::ir::{Endianness, LabelValueLoc, ValueLabel}; use cranelift_codegen::isa::TargetIsa; use cranelift_codegen::ValueLocRange; @@ -23,15 +23,6 @@ use gimli::{Encoding, Format, LineEncoding, RunTimeEndian, X86_64}; pub(crate) use emit::{DebugReloc, DebugRelocName}; pub(crate) use unwind::UnwindContext; -fn target_endian(tcx: TyCtxt<'_>) -> RunTimeEndian { - use rustc_target::abi::Endian; - - match tcx.data_layout.endian { - Endian::Big => RunTimeEndian::Big, - Endian::Little => RunTimeEndian::Little, - } -} - pub(crate) struct DebugContext<'tcx> { tcx: TyCtxt<'tcx>, @@ -60,6 +51,11 @@ impl<'tcx> DebugContext<'tcx> { address_size: isa.frontend_config().pointer_bytes(), }; + let endian = match isa.endianness() { + Endianness::Little => RunTimeEndian::Little, + Endianness::Big => RunTimeEndian::Big, + }; + let mut dwarf = DwarfUnit::new(encoding); let producer = format!( @@ -108,7 +104,7 @@ impl<'tcx> DebugContext<'tcx> { DebugContext { tcx, - endian: target_endian(tcx), + endian, dwarf, unit_range_list: RangeList(Vec::new()), diff --git a/compiler/rustc_codegen_cranelift/src/debuginfo/unwind.rs b/compiler/rustc_codegen_cranelift/src/debuginfo/unwind.rs index f0896ea0e16..e4f28338096 100644 --- a/compiler/rustc_codegen_cranelift/src/debuginfo/unwind.rs +++ b/compiler/rustc_codegen_cranelift/src/debuginfo/unwind.rs @@ -2,6 +2,7 @@ use crate::prelude::*; +use cranelift_codegen::ir::Endianness; use cranelift_codegen::isa::{unwind::UnwindInfo, TargetIsa}; use cranelift_object::ObjectProduct; @@ -17,8 +18,11 @@ pub(crate) struct UnwindContext { } impl UnwindContext { - pub(crate) fn new(tcx: TyCtxt<'_>, isa: &dyn TargetIsa, pic_eh_frame: bool) -> Self { - let endian = super::target_endian(tcx); + pub(crate) fn new(isa: &dyn TargetIsa, pic_eh_frame: bool) -> Self { + let endian = match isa.endianness() { + Endianness::Little => RunTimeEndian::Little, + Endianness::Big => RunTimeEndian::Big, + }; let mut frame_table = FrameTable::default(); let cie_id = if let Some(mut cie) = isa.create_systemv_cie() { diff --git a/compiler/rustc_codegen_cranelift/src/driver/aot.rs b/compiler/rustc_codegen_cranelift/src/driver/aot.rs index 7f888c80464..046e4393a68 100644 --- a/compiler/rustc_codegen_cranelift/src/driver/aot.rs +++ b/compiler/rustc_codegen_cranelift/src/driver/aot.rs @@ -243,7 +243,7 @@ pub(crate) fn run_aot( let isa = crate::build_isa(tcx.sess, &backend_config); let mut allocator_module = make_module(tcx.sess, isa, "allocator_shim".to_string()); assert_eq!(pointer_ty(tcx), allocator_module.target_config().pointer_type()); - let mut allocator_unwind_context = UnwindContext::new(tcx, allocator_module.isa(), true); + let mut allocator_unwind_context = UnwindContext::new(allocator_module.isa(), true); let created_alloc_shim = crate::allocator::codegen(tcx, &mut allocator_module, &mut allocator_unwind_context); diff --git a/compiler/rustc_codegen_cranelift/src/lib.rs b/compiler/rustc_codegen_cranelift/src/lib.rs index 3f288474827..cb18f42f741 100644 --- a/compiler/rustc_codegen_cranelift/src/lib.rs +++ b/compiler/rustc_codegen_cranelift/src/lib.rs @@ -141,7 +141,7 @@ impl<'tcx> CodegenCx<'tcx> { assert_eq!(pointer_ty(tcx), isa.pointer_type()); let unwind_context = - UnwindContext::new(tcx, isa, matches!(backend_config.codegen_mode, CodegenMode::Aot)); + UnwindContext::new(isa, matches!(backend_config.codegen_mode, CodegenMode::Aot)); let debug_context = if debug_info { Some(DebugContext::new(tcx, isa)) } else { None }; CodegenCx { tcx, diff --git a/compiler/rustc_codegen_gcc/Cargo.lock b/compiler/rustc_codegen_gcc/Cargo.lock index 60a2101c689..47925f72c2c 100644 --- a/compiler/rustc_codegen_gcc/Cargo.lock +++ b/compiler/rustc_codegen_gcc/Cargo.lock @@ -18,12 +18,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "450575f58f7bee32816abbff470cbc47797397c2a81e0eaced4b98436daf52e1" [[package]] -name = "autocfg" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" - -[[package]] name = "bitflags" version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -36,15 +30,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] -name = "crc32fast" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81156fece84ab6a9f2afdb109ce3ae577e42b1228441eded99bd77f627953b1a" -dependencies = [ - "cfg-if", -] - -[[package]] name = "fm" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -56,7 +41,7 @@ dependencies = [ [[package]] name = "gccjit" version = "1.0.0" -source = "git+https://github.com/antoyo/gccjit.rs#2d4fea7319f80531b2e5d264fca9f1c498a3a62e" +source = "git+https://github.com/antoyo/gccjit.rs#0672b78d162d65b6f36ea4062947253affe9fdef" dependencies = [ "gccjit_sys", ] @@ -64,7 +49,7 @@ dependencies = [ [[package]] name = "gccjit_sys" version = "0.0.1" -source = "git+https://github.com/antoyo/gccjit.rs#2d4fea7319f80531b2e5d264fca9f1c498a3a62e" +source = "git+https://github.com/antoyo/gccjit.rs#0672b78d162d65b6f36ea4062947253affe9fdef" dependencies = [ "libc 0.1.12", ] @@ -85,33 +70,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753" dependencies = [ "cfg-if", - "libc 0.2.102", + "libc 0.2.112", "wasi", ] [[package]] -name = "hashbrown" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" - -[[package]] name = "hermit-abi" version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" dependencies = [ - "libc 0.2.102", -] - -[[package]] -name = "indexmap" -version = "1.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc633605454125dec4b66843673f01c7df2b89479b32e0ed634e43a91cff62a5" -dependencies = [ - "autocfg", - "hashbrown", + "libc 0.2.112", ] [[package]] @@ -122,7 +91,7 @@ checksum = "96bd995a092cac79868250589869b5a5d656b02a02bd74c8ebdc566dc7203090" dependencies = [ "fm", "getopts", - "libc 0.2.102", + "libc 0.2.112", "num_cpus", "termcolor", "threadpool", @@ -138,9 +107,9 @@ checksum = "e32a70cf75e5846d53a673923498228bbec6a8624708a9ea5645f075d6276122" [[package]] name = "libc" -version = "0.2.102" +version = "0.2.112" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2a5ac8f984bfcf3a823267e5fde638acc3325f6496633a5da6bb6eb2171e103" +checksum = "1b03d17f364a3a042d5e5d46b053bbbf82c92c9430c592dd4c064dc6ee997125" [[package]] name = "memchr" @@ -155,25 +124,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" dependencies = [ "hermit-abi", - "libc 0.2.102", -] - -[[package]] -name = "object" -version = "0.25.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a38f2be3697a57b4060074ff41b44c16870d916ad7877c17696e063257482bc7" -dependencies = [ - "crc32fast", - "indexmap", - "memchr", + "libc 0.2.112", ] [[package]] name = "ppv-lite86" -version = "0.2.10" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857" +checksum = "ed0cfbc8191465bed66e1718596ee0b0b35d5ee1f41c5df2189d0fe8bde535ba" [[package]] name = "rand" @@ -181,7 +139,7 @@ version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2e7573632e6454cf6b99d7aac4ccca54be06da05aca2ef7423d22d27d4d4bcd8" dependencies = [ - "libc 0.2.102", + "libc 0.2.112", "rand_chacha", "rand_core", "rand_hc", @@ -257,7 +215,6 @@ dependencies = [ "ar", "gccjit", "lang_tester", - "object", "target-lexicon", "tempfile", ] @@ -284,7 +241,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22" dependencies = [ "cfg-if", - "libc 0.2.102", + "libc 0.2.112", "rand", "redox_syscall", "remove_dir_all", @@ -321,7 +278,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6" dependencies = [ - "libc 0.2.102", + "libc 0.2.112", ] [[package]] diff --git a/compiler/rustc_codegen_gcc/Cargo.toml b/compiler/rustc_codegen_gcc/Cargo.toml index 9e8c195c15f..21f0bfbf69d 100644 --- a/compiler/rustc_codegen_gcc/Cargo.toml +++ b/compiler/rustc_codegen_gcc/Cargo.toml @@ -23,11 +23,6 @@ target-lexicon = "0.10.0" ar = "0.8.0" -[dependencies.object] -version = "0.25.0" -default-features = false -features = ["read", "std", "write"] # We don't need WASM support. - [dev-dependencies] lang_tester = "0.3.9" tempfile = "3.1.0" diff --git a/compiler/rustc_codegen_gcc/Readme.md b/compiler/rustc_codegen_gcc/Readme.md index 709d93c6edb..1fcfb5f6e20 100644 --- a/compiler/rustc_codegen_gcc/Readme.md +++ b/compiler/rustc_codegen_gcc/Readme.md @@ -111,6 +111,8 @@ Or add a breakpoint to `add_error` in gdb and print the line number using: p loc->m_line ``` +To get the `rustc` command to run in `gdb`, add the `--verbose` flag to `cargo build`. + ### How to use a custom-build rustc * Build the stage2 compiler (`rustup toolchain link debug-current build/x86_64-unknown-linux-gnu/stage2`). diff --git a/compiler/rustc_codegen_gcc/config.sh b/compiler/rustc_codegen_gcc/config.sh index 87df2f2102b..a932c1c8372 100644 --- a/compiler/rustc_codegen_gcc/config.sh +++ b/compiler/rustc_codegen_gcc/config.sh @@ -38,7 +38,7 @@ if [[ "$HOST_TRIPLE" != "$TARGET_TRIPLE" ]]; then fi fi -export RUSTFLAGS="$linker -Cpanic=abort -Zsymbol-mangling-version=v0 -Cdebuginfo=2 -Clto=off -Zpanic-abort-tests -Zcodegen-backend=$(pwd)/target/${CHANNEL:-debug}/librustc_codegen_gcc.$dylib_ext --sysroot $(pwd)/build_sysroot/sysroot" +export RUSTFLAGS="$linker -Cpanic=abort -Csymbol-mangling-version=v0 -Cdebuginfo=2 -Clto=off -Zpanic-abort-tests -Zcodegen-backend=$(pwd)/target/${CHANNEL:-debug}/librustc_codegen_gcc.$dylib_ext --sysroot $(pwd)/build_sysroot/sysroot" # FIXME(antoyo): remove once the atomic shim is gone if [[ `uname` == 'Darwin' ]]; then diff --git a/compiler/rustc_codegen_gcc/patches/0023-core-Ignore-failing-tests.patch b/compiler/rustc_codegen_gcc/patches/0023-core-Ignore-failing-tests.patch index ee5ba449fb8..73e9c858caf 100644 --- a/compiler/rustc_codegen_gcc/patches/0023-core-Ignore-failing-tests.patch +++ b/compiler/rustc_codegen_gcc/patches/0023-core-Ignore-failing-tests.patch @@ -46,4 +46,24 @@ index 4bc44e9..8e3c7a4 100644 #[test] fn cell_allows_array_cycle() { +diff --git a/library/core/tests/slice.rs b/library/core/tests/slice.rs +index 3e00e0a..8e5663b 100644 +--- a/library/core/tests/slice.rs ++++ b/library/core/tests/slice.rs +@@ -2108,6 +2108,7 @@ fn test_copy_within_panics_src_out_of_bounds() { + bytes.copy_within(usize::MAX..=usize::MAX, 0); + } + ++/* + #[test] + fn test_is_sorted() { + let empty: [i32; 0] = []; +@@ -2122,6 +2123,7 @@ fn test_is_sorted() { + assert!(!["c", "bb", "aaa"].is_sorted()); + assert!(["c", "bb", "aaa"].is_sorted_by_key(|s| s.len())); + } ++*/ + + #[test] + fn test_slice_run_destructors() { -- 2.21.0 (Apple Git-122) diff --git a/compiler/rustc_codegen_gcc/patches/0024-core-Disable-portable-simd-test.patch b/compiler/rustc_codegen_gcc/patches/0024-core-Disable-portable-simd-test.patch new file mode 100644 index 00000000000..8954f91021f --- /dev/null +++ b/compiler/rustc_codegen_gcc/patches/0024-core-Disable-portable-simd-test.patch @@ -0,0 +1,24 @@ +From b1ae000f6da1abd3b8e9b80c40bc11c89b8ae93c Mon Sep 17 00:00:00 2001 +From: bjorn3 <bjorn3@users.noreply.github.com> +Date: Thu, 30 Dec 2021 16:54:40 +0100 +Subject: [PATCH] [core] Disable portable-simd test + +--- + library/core/tests/lib.rs | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs +index ec70034..7cd9e21 100644 +--- a/library/core/tests/lib.rs ++++ b/library/core/tests/lib.rs +@@ -121,7 +121,6 @@ mod pattern; + mod pin; + mod ptr; + mod result; +-mod simd; + mod slice; + mod str; + mod str_lossy; +-- +2.26.2.7.g19db9cfb68 + diff --git a/compiler/rustc_codegen_gcc/patches/0028-core-Disable-long-running-tests.patch b/compiler/rustc_codegen_gcc/patches/0028-core-Disable-long-running-tests.patch new file mode 100644 index 00000000000..bf74a74c7c4 --- /dev/null +++ b/compiler/rustc_codegen_gcc/patches/0028-core-Disable-long-running-tests.patch @@ -0,0 +1,30 @@ +From 0ffdd8eda8df364391c8ac6e1ce92c73ba9254d4 Mon Sep 17 00:00:00 2001 +From: bjorn3 <bjorn3@users.noreply.github.com> +Date: Fri, 3 Dec 2021 12:16:30 +0100 +Subject: [PATCH] Disable long running tests + +--- + library/core/tests/slice.rs | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/library/core/tests/slice.rs b/library/core/tests/slice.rs +index 2c8f00a..44847ee 100644 +--- a/library/core/tests/slice.rs ++++ b/library/core/tests/slice.rs +@@ -2332,7 +2332,8 @@ macro_rules! empty_max_mut { + }; + } + ++/* + #[cfg(not(miri))] // Comparing usize::MAX many elements takes forever in Miri (and in rustc without optimizations) + take_tests! { + slice: &[(); usize::MAX], method: take, + (take_in_bounds_max_range_to, (..usize::MAX), Some(EMPTY_MAX), &[(); 0]), +@@ -2345,3 +2347,4 @@ take_tests! { + (take_mut_oob_max_range_to_inclusive, (..=usize::MAX), None, empty_max_mut!()), + (take_mut_in_bounds_max_range_from, (usize::MAX..), Some(&mut [] as _), empty_max_mut!()), + } ++*/ +-- +2.26.2.7.g19db9cfb68 + diff --git a/compiler/rustc_codegen_gcc/rust-toolchain b/compiler/rustc_codegen_gcc/rust-toolchain index d311a33f807..ee0822f6c31 100644 --- a/compiler/rustc_codegen_gcc/rust-toolchain +++ b/compiler/rustc_codegen_gcc/rust-toolchain @@ -1 +1 @@ -nightly-2021-09-28 +nightly-2021-12-30 diff --git a/compiler/rustc_codegen_gcc/src/asm.rs b/compiler/rustc_codegen_gcc/src/asm.rs index 10edcf36955..453bcd601d3 100644 --- a/compiler/rustc_codegen_gcc/src/asm.rs +++ b/compiler/rustc_codegen_gcc/src/asm.rs @@ -18,30 +18,30 @@ use crate::type_of::LayoutGccExt; // Rust asm! and GCC Extended Asm semantics differ substantially. // -// 1. Rust asm operands go along as one list of operands. Operands themselves indicate -// if they're "in" or "out". "In" and "out" operands can interleave. One operand can be +// 1. Rust asm operands go along as one list of operands. Operands themselves indicate +// if they're "in" or "out". "In" and "out" operands can interleave. One operand can be // both "in" and "out" (`inout(reg)`). // -// GCC asm has two different lists for "in" and "out" operands. In terms of gccjit, -// this means that all "out" operands must go before "in" operands. "In" and "out" operands +// GCC asm has two different lists for "in" and "out" operands. In terms of gccjit, +// this means that all "out" operands must go before "in" operands. "In" and "out" operands // cannot interleave. // -// 2. Operand lists in both Rust and GCC are indexed. Index starts from 0. Indexes are important +// 2. Operand lists in both Rust and GCC are indexed. Index starts from 0. Indexes are important // because the asm template refers to operands by index. // // Mapping from Rust to GCC index would be 1-1 if it wasn't for... // -// 3. Clobbers. GCC has a separate list of clobbers, and clobbers don't have indexes. -// Contrary, Rust expresses clobbers through "out" operands that aren't tied to +// 3. Clobbers. GCC has a separate list of clobbers, and clobbers don't have indexes. +// Contrary, Rust expresses clobbers through "out" operands that aren't tied to // a variable (`_`), and such "clobbers" do have index. // -// 4. Furthermore, GCC Extended Asm does not support explicit register constraints -// (like `out("eax")`) directly, offering so-called "local register variables" -// as a workaround. These variables need to be declared and initialized *before* -// the Extended Asm block but *after* normal local variables +// 4. Furthermore, GCC Extended Asm does not support explicit register constraints +// (like `out("eax")`) directly, offering so-called "local register variables" +// as a workaround. These variables need to be declared and initialized *before* +// the Extended Asm block but *after* normal local variables // (see comment in `codegen_inline_asm` for explanation). // -// With that in mind, let's see how we translate Rust syntax to GCC +// With that in mind, let's see how we translate Rust syntax to GCC // (from now on, `CC` stands for "constraint code"): // // * `out(reg_class) var` -> translated to output operand: `"=CC"(var)` @@ -52,18 +52,17 @@ use crate::type_of::LayoutGccExt; // // * `out("explicit register") _` -> not translated to any operands, register is simply added to clobbers list // -// * `inout(reg_class) in_var => out_var` -> translated to two operands: +// * `inout(reg_class) in_var => out_var` -> translated to two operands: // output: `"=CC"(in_var)` -// input: `"num"(out_var)` where num is the GCC index +// input: `"num"(out_var)` where num is the GCC index // of the corresponding output operand // -// * `inout(reg_class) in_var => _` -> same as `inout(reg_class) in_var => tmp`, +// * `inout(reg_class) in_var => _` -> same as `inout(reg_class) in_var => tmp`, // where "tmp" is a temporary unused variable // -// * `out/in/inout("explicit register") var` -> translated to one or two operands as described above -// with `"r"(var)` constraint, +// * `out/in/inout("explicit register") var` -> translated to one or two operands as described above +// with `"r"(var)` constraint, // and one register variable assigned to the desired register. -// const ATT_SYNTAX_INS: &str = ".att_syntax noprefix\n\t"; const INTEL_SYNTAX_INS: &str = "\n\t.intel_syntax noprefix"; @@ -131,7 +130,7 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { let att_dialect = is_x86 && options.contains(InlineAsmOptions::ATT_SYNTAX); let intel_dialect = is_x86 && !options.contains(InlineAsmOptions::ATT_SYNTAX); - // GCC index of an output operand equals its position in the array + // GCC index of an output operand equals its position in the array let mut outputs = vec![]; // GCC index of an input operand equals its position in the array @@ -145,9 +144,9 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { let mut constants_len = 0; // There are rules we must adhere to if we want GCC to do the right thing: - // + // // * Every local variable that the asm block uses as an output must be declared *before* - // the asm block. + // the asm block. // * There must be no instructions whatsoever between the register variables and the asm. // // Therefore, the backend must generate the instructions strictly in this order: @@ -159,7 +158,7 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { // We also must make sure that no input operands are emitted before output operands. // // This is why we work in passes, first emitting local vars, then local register vars. - // Also, we don't emit any asm operands immediately; we save them to + // Also, we don't emit any asm operands immediately; we save them to // the one of the buffers to be emitted later. // 1. Normal variables (and saving operands to buffers). @@ -172,7 +171,7 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { (Constraint(constraint), Some(place)) => (constraint, place.layout.gcc_type(self.cx, false)), // When `reg` is a class and not an explicit register but the out place is not specified, // we need to create an unused output variable to assign the output to. This var - // needs to be of a type that's "compatible" with the register class, but specific type + // needs to be of a type that's "compatible" with the register class, but specific type // doesn't matter. (Constraint(constraint), None) => (constraint, dummy_output_type(self.cx, reg.reg_class())), (Register(_), Some(_)) => { @@ -200,7 +199,7 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { let tmp_var = self.current_func().new_local(None, ty, "output_register"); outputs.push(AsmOutOperand { - constraint, + constraint, rust_idx, late, readwrite: false, @@ -211,12 +210,12 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { InlineAsmOperandRef::In { reg, value } => { if let ConstraintOrRegister::Constraint(constraint) = reg_to_gcc(reg) { - inputs.push(AsmInOperand { - constraint: Cow::Borrowed(constraint), - rust_idx, + inputs.push(AsmInOperand { + constraint: Cow::Borrowed(constraint), + rust_idx, val: value.immediate() }); - } + } else { // left for the next pass continue @@ -226,7 +225,7 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { InlineAsmOperandRef::InOut { reg, late, in_value, out_place } => { let constraint = if let ConstraintOrRegister::Constraint(constraint) = reg_to_gcc(reg) { constraint - } + } else { // left for the next pass continue @@ -235,22 +234,22 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { // Rustc frontend guarantees that input and output types are "compatible", // so we can just use input var's type for the output variable. // - // This decision is also backed by the fact that LLVM needs in and out - // values to be of *exactly the same type*, not just "compatible". + // This decision is also backed by the fact that LLVM needs in and out + // values to be of *exactly the same type*, not just "compatible". // I'm not sure if GCC is so picky too, but better safe than sorry. let ty = in_value.layout.gcc_type(self.cx, false); let tmp_var = self.current_func().new_local(None, ty, "output_register"); // If the out_place is None (i.e `inout(reg) _` syntax was used), we translate - // it to one "readwrite (+) output variable", otherwise we translate it to two + // it to one "readwrite (+) output variable", otherwise we translate it to two // "out and tied in" vars as described above. let readwrite = out_place.is_none(); outputs.push(AsmOutOperand { - constraint, + constraint, rust_idx, late, readwrite, - tmp_var, + tmp_var, out_place, }); @@ -259,8 +258,8 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { let constraint = Cow::Owned(out_gcc_idx.to_string()); inputs.push(AsmInOperand { - constraint, - rust_idx, + constraint, + rust_idx, val: in_value.immediate() }); } @@ -287,7 +286,7 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { if let ConstraintOrRegister::Register(reg_name) = reg_to_gcc(reg) { let out_place = if let Some(place) = place { place - } + } else { // processed in the previous pass continue @@ -298,7 +297,7 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { tmp_var.set_register_name(reg_name); outputs.push(AsmOutOperand { - constraint: "r".into(), + constraint: "r".into(), rust_idx, late, readwrite: false, @@ -318,9 +317,9 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { reg_var.set_register_name(reg_name); self.llbb().add_assignment(None, reg_var, value.immediate()); - inputs.push(AsmInOperand { - constraint: "r".into(), - rust_idx, + inputs.push(AsmInOperand { + constraint: "r".into(), + rust_idx, val: reg_var.to_rvalue() }); } @@ -331,31 +330,23 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { // `inout("explicit register") in_var => out_var` InlineAsmOperandRef::InOut { reg, late, in_value, out_place } => { if let ConstraintOrRegister::Register(reg_name) = reg_to_gcc(reg) { - let out_place = if let Some(place) = out_place { - place - } - else { - // processed in the previous pass - continue - }; - // See explanation in the first pass. let ty = in_value.layout.gcc_type(self.cx, false); let tmp_var = self.current_func().new_local(None, ty, "output_register"); tmp_var.set_register_name(reg_name); outputs.push(AsmOutOperand { - constraint: "r".into(), + constraint: "r".into(), rust_idx, late, readwrite: false, tmp_var, - out_place: Some(out_place) + out_place, }); let constraint = Cow::Owned((outputs.len() - 1).to_string()); - inputs.push(AsmInOperand { - constraint, + inputs.push(AsmInOperand { + constraint, rust_idx, val: in_value.immediate() }); @@ -364,8 +355,8 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { // processed in the previous pass } - InlineAsmOperandRef::Const { .. } - | InlineAsmOperandRef::SymFn { .. } + InlineAsmOperandRef::Const { .. } + | InlineAsmOperandRef::SymFn { .. } | InlineAsmOperandRef::SymStatic { .. } => { // processed in the previous pass } @@ -460,7 +451,7 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { if !intel_dialect { template_str.push_str(INTEL_SYNTAX_INS); } - + // 4. Generate Extended Asm block let block = self.llbb(); @@ -479,7 +470,7 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { } if !options.contains(InlineAsmOptions::PRESERVES_FLAGS) { - // TODO(@Commeownist): I'm not 100% sure this one clobber is sufficient + // TODO(@Commeownist): I'm not 100% sure this one clobber is sufficient // on all architectures. For instance, what about FP stack? extended_asm.add_clobber("cc"); } @@ -498,10 +489,10 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { self.call(self.type_void(), builtin_unreachable, &[], None); } - // Write results to outputs. + // Write results to outputs. // // We need to do this because: - // 1. Turning `PlaceRef` into `RValue` is error-prone and has nasty edge cases + // 1. Turning `PlaceRef` into `RValue` is error-prone and has nasty edge cases // (especially with current `rustc_backend_ssa` API). // 2. Not every output operand has an `out_place`, and it's required by `add_output_operand`. // @@ -509,7 +500,7 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { // generates `out_place = tmp_var;` assignments if out_place exists. for op in &outputs { if let Some(place) = op.out_place { - OperandValue::Immediate(op.tmp_var.to_rvalue()).store(self, place); + OperandValue::Immediate(op.tmp_var.to_rvalue()).store(self, place); } } diff --git a/compiler/rustc_codegen_gcc/src/back/write.rs b/compiler/rustc_codegen_gcc/src/back/write.rs index 4962d016152..334ef32f1d1 100644 --- a/compiler/rustc_codegen_gcc/src/back/write.rs +++ b/compiler/rustc_codegen_gcc/src/back/write.rs @@ -1,4 +1,4 @@ -use std::fs; +use std::{env, fs}; use gccjit::OutputKind; use rustc_codegen_ssa::{CompiledModule, ModuleCodegen}; @@ -42,17 +42,17 @@ pub(crate) unsafe fn codegen(cgcx: &CodegenContext<GccCodegenBackend>, _diag_han let _timer = cgcx .prof .generic_activity_with_arg("LLVM_module_codegen_emit_obj", &*module.name); - match &*module.name { - "std_example.7rcbfp3g-cgu.15" => { - println!("Dumping reproducer {}", module.name); - let _ = fs::create_dir("/tmp/reproducers"); - // FIXME(antoyo): segfault in dump_reproducer_to_file() might be caused by - // transmuting an rvalue to an lvalue. - // Segfault is actually in gcc::jit::reproducer::get_identifier_as_lvalue - context.dump_reproducer_to_file(&format!("/tmp/reproducers/{}.c", module.name)); - println!("Dumped reproducer {}", module.name); - }, - _ => (), + if env::var("CG_GCCJIT_DUMP_MODULE_NAMES").as_deref() == Ok("1") { + println!("Module {}", module.name); + } + if env::var("CG_GCCJIT_DUMP_MODULE").as_deref() == Ok(&module.name) { + println!("Dumping reproducer {}", module.name); + let _ = fs::create_dir("/tmp/reproducers"); + // FIXME(antoyo): segfault in dump_reproducer_to_file() might be caused by + // transmuting an rvalue to an lvalue. + // Segfault is actually in gcc::jit::reproducer::get_identifier_as_lvalue + context.dump_reproducer_to_file(&format!("/tmp/reproducers/{}.c", module.name)); + println!("Dumped reproducer {}", module.name); } context.compile_to_file(OutputKind::ObjectFile, obj_out.to_str().expect("path to str")); } diff --git a/compiler/rustc_codegen_gcc/src/base.rs b/compiler/rustc_codegen_gcc/src/base.rs index dee70bf7536..8b23e96066e 100644 --- a/compiler/rustc_codegen_gcc/src/base.rs +++ b/compiler/rustc_codegen_gcc/src/base.rs @@ -81,7 +81,10 @@ pub fn compile_codegen_unit<'tcx>(tcx: TyCtxt<'tcx>, cgu_name: Symbol) -> (Modul for arg in &tcx.sess.opts.cg.llvm_args { context.add_command_line_option(arg); } + // NOTE: an optimization (https://github.com/rust-lang/rustc_codegen_gcc/issues/53). context.add_command_line_option("-fno-semantic-interposition"); + // NOTE: Rust relies on LLVM not doing TBAA (https://github.com/rust-lang/unsafe-code-guidelines/issues/292). + context.add_command_line_option("-fno-strict-aliasing"); if env::var("CG_GCCJIT_DUMP_CODE").as_deref() == Ok("1") { context.set_dump_code_on_compile(true); } diff --git a/compiler/rustc_codegen_gcc/src/builder.rs b/compiler/rustc_codegen_gcc/src/builder.rs index fff2aa6df7c..379c88bbd40 100644 --- a/compiler/rustc_codegen_gcc/src/builder.rs +++ b/compiler/rustc_codegen_gcc/src/builder.rs @@ -200,7 +200,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { fn check_ptr_call<'b>(&mut self, _typ: &str, func_ptr: RValue<'gcc>, args: &'b [RValue<'gcc>]) -> Cow<'b, [RValue<'gcc>]> { let mut all_args_match = true; let mut param_types = vec![]; - let gcc_func = func_ptr.get_type().is_function_ptr_type().expect("function ptr"); + let gcc_func = func_ptr.get_type().dyncast_function_ptr_type().expect("function ptr"); for (index, arg) in args.iter().enumerate().take(gcc_func.get_param_count()) { let param = gcc_func.get_param_type(index); if param != arg.get_type() { @@ -277,7 +277,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { // gccjit requires to use the result of functions, even when it's not used. // That's why we assign the result to a local or call add_eval(). - let gcc_func = func_ptr.get_type().is_function_ptr_type().expect("function ptr"); + let gcc_func = func_ptr.get_type().dyncast_function_ptr_type().expect("function ptr"); let mut return_type = gcc_func.get_return_type(); let current_block = self.current_block.borrow().expect("block"); let void_type = self.context.new_type::<()>(); @@ -605,22 +605,17 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { } fn and(&mut self, a: RValue<'gcc>, mut b: RValue<'gcc>) -> RValue<'gcc> { - // FIXME(antoyo): hack by putting the result in a variable to workaround this bug: - // https://gcc.gnu.org/bugzilla//show_bug.cgi?id=95498 if a.get_type() != b.get_type() { b = self.context.new_cast(None, b, a.get_type()); } - let res = self.current_func().new_local(None, b.get_type(), "andResult"); - self.llbb().add_assignment(None, res, a & b); - res.to_rvalue() + a & b } - fn or(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { - // FIXME(antoyo): hack by putting the result in a variable to workaround this bug: - // https://gcc.gnu.org/bugzilla//show_bug.cgi?id=95498 - let res = self.current_func().new_local(None, b.get_type(), "orResult"); - self.llbb().add_assignment(None, res, a | b); - res.to_rvalue() + fn or(&mut self, a: RValue<'gcc>, mut b: RValue<'gcc>) -> RValue<'gcc> { + if a.get_type() != b.get_type() { + b = self.context.new_cast(None, b, a.get_type()); + } + a | b } fn xor(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { @@ -628,8 +623,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { } fn neg(&mut self, a: RValue<'gcc>) -> RValue<'gcc> { - // TODO(antoyo): use new_unary_op()? - self.cx.context.new_rvalue_from_long(a.get_type(), 0) - a + self.cx.context.new_unary_op(None, UnaryOp::Minus, a.get_type(), a) } fn fneg(&mut self, a: RValue<'gcc>) -> RValue<'gcc> { @@ -816,7 +810,10 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { let atomic_load = self.context.get_builtin_function(&format!("__atomic_load_{}", size.bytes())); let ordering = self.context.new_rvalue_from_int(self.i32_type, order.to_gcc()); - let volatile_const_void_ptr_type = self.context.new_type::<*mut ()>().make_const().make_volatile(); + let volatile_const_void_ptr_type = self.context.new_type::<()>() + .make_const() + .make_volatile() + .make_pointer(); let ptr = self.context.new_cast(None, ptr, volatile_const_void_ptr_type); self.context.new_call(None, atomic_load, &[ptr, ordering]) } @@ -941,7 +938,9 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { // TODO(antoyo): handle alignment. let atomic_store = self.context.get_builtin_function(&format!("__atomic_store_{}", size.bytes())); let ordering = self.context.new_rvalue_from_int(self.i32_type, order.to_gcc()); - let volatile_const_void_ptr_type = self.context.new_type::<*mut ()>().make_const().make_volatile(); + let volatile_const_void_ptr_type = self.context.new_type::<()>() + .make_volatile() + .make_pointer(); let ptr = self.context.new_cast(None, ptr, volatile_const_void_ptr_type); // FIXME(antoyo): fix libgccjit to allow comparing an integer type with an aligned integer type because @@ -981,12 +980,12 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { assert_eq!(idx as usize as u64, idx); let value = ptr.dereference(None).to_rvalue(); - if value_type.is_array().is_some() { + if value_type.dyncast_array().is_some() { let index = self.context.new_rvalue_from_long(self.u64_type, i64::try_from(idx).expect("i64::try_from")); let element = self.context.new_array_access(None, value, index); element.get_address(None) } - else if let Some(vector_type) = value_type.is_vector() { + else if let Some(vector_type) = value_type.dyncast_vector() { let array_type = vector_type.get_element_type().make_pointer(); let array = self.bitcast(ptr, array_type); let index = self.context.new_rvalue_from_long(self.u64_type, i64::try_from(idx).expect("i64::try_from")); @@ -1009,7 +1008,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { fn sext(&mut self, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> { // TODO(antoyo): check that it indeed sign extend the value. - if dest_ty.is_vector().is_some() { + if dest_ty.dyncast_vector().is_some() { // TODO(antoyo): nothing to do as it is only for LLVM? return value; } @@ -1081,7 +1080,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { let right_type = rhs.get_type(); if left_type != right_type { // NOTE: because libgccjit cannot compare function pointers. - if left_type.is_function_ptr_type().is_some() && right_type.is_function_ptr_type().is_some() { + if left_type.dyncast_function_ptr_type().is_some() && right_type.dyncast_function_ptr_type().is_some() { lhs = self.context.new_cast(None, lhs, self.usize_type.make_pointer()); rhs = self.context.new_cast(None, rhs, self.usize_type.make_pointer()); } @@ -1189,12 +1188,12 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { assert_eq!(idx as usize as u64, idx); let value_type = aggregate_value.get_type(); - if value_type.is_array().is_some() { + if value_type.dyncast_array().is_some() { let index = self.context.new_rvalue_from_long(self.u64_type, i64::try_from(idx).expect("i64::try_from")); let element = self.context.new_array_access(None, aggregate_value, index); element.get_address(None) } - else if value_type.is_vector().is_some() { + else if value_type.dyncast_vector().is_some() { panic!(); } else if let Some(pointer_type) = value_type.get_pointee() { @@ -1221,11 +1220,11 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { let value_type = aggregate_value.get_type(); let lvalue = - if value_type.is_array().is_some() { + if value_type.dyncast_array().is_some() { let index = self.context.new_rvalue_from_long(self.u64_type, i64::try_from(idx).expect("i64::try_from")); self.context.new_array_access(None, aggregate_value, index) } - else if value_type.is_vector().is_some() { + else if value_type.dyncast_vector().is_some() { panic!(); } else if let Some(pointer_type) = value_type.get_pointee() { @@ -1404,7 +1403,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { self.cx } - fn do_not_inline(&mut self, _llret: RValue<'gcc>) { + fn apply_attrs_to_cleanup_callsite(&mut self, _llret: RValue<'gcc>) { unimplemented!(); } diff --git a/compiler/rustc_codegen_gcc/src/common.rs b/compiler/rustc_codegen_gcc/src/common.rs index ec542e55681..5851826147d 100644 --- a/compiler/rustc_codegen_gcc/src/common.rs +++ b/compiler/rustc_codegen_gcc/src/common.rs @@ -1,5 +1,4 @@ use std::convert::TryFrom; -use std::convert::TryInto; use gccjit::LValue; use gccjit::{Block, CType, RValue, Type, ToRValue}; @@ -44,7 +43,7 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { let string = self.context.new_string_literal(&*string); let sym = self.generate_local_symbol_name("str"); let global = self.declare_private_global(&sym, self.val_ty(string)); - global.global_set_initializer_value(string); + global.global_set_initializer_rvalue(string); global // TODO(antoyo): set linkage. } @@ -79,7 +78,7 @@ pub fn bytes_in_context<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, bytes: &[u8]) -> bytes.iter() .map(|&byte| context.new_rvalue_from_int(byte_type, byte as i32)) .collect(); - context.new_rvalue_from_array(None, typ, &elements) + context.new_array_constructor(None, typ, &elements) } pub fn type_is_pointer<'gcc>(typ: Type<'gcc>) -> bool { @@ -120,13 +119,6 @@ impl<'gcc, 'tcx> ConstMethods<'tcx> for CodegenCx<'gcc, 'tcx> { } fn const_uint_big(&self, typ: Type<'gcc>, num: u128) -> RValue<'gcc> { - let num64: Result<i64, _> = num.try_into(); - if let Ok(num) = num64 { - // FIXME(antoyo): workaround for a bug where libgccjit is expecting a constant. - // The operations >> 64 and | low are making the normal case a non-constant. - return self.context.new_rvalue_from_long(typ, num as i64); - } - if num >> 64 != 0 { // FIXME(antoyo): use a new function new_rvalue_from_unsigned_long()? let low = self.context.new_rvalue_from_long(self.u64_type, num as u64 as i64); @@ -193,7 +185,7 @@ impl<'gcc, 'tcx> ConstMethods<'tcx> for CodegenCx<'gcc, 'tcx> { // TODO(antoyo): cache the type? It's anonymous, so probably not. let typ = self.type_struct(&fields, packed); let struct_type = typ.is_struct().expect("struct type"); - self.context.new_rvalue_from_struct(None, struct_type, values) + self.context.new_struct_constructor(None, struct_type.as_type(), None, values) } fn const_to_opt_uint(&self, _v: RValue<'gcc>) -> Option<u64> { diff --git a/compiler/rustc_codegen_gcc/src/consts.rs b/compiler/rustc_codegen_gcc/src/consts.rs index 205498acc31..ba4589bd810 100644 --- a/compiler/rustc_codegen_gcc/src/consts.rs +++ b/compiler/rustc_codegen_gcc/src/consts.rs @@ -20,7 +20,7 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { pub fn const_bitcast(&self, value: RValue<'gcc>, typ: Type<'gcc>) -> RValue<'gcc> { if value.get_type() == self.bool_type.make_pointer() { if let Some(pointee) = typ.get_pointee() { - if pointee.is_vector().is_some() { + if pointee.dyncast_vector().is_some() { panic!() } } @@ -31,9 +31,13 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { impl<'gcc, 'tcx> StaticMethods for CodegenCx<'gcc, 'tcx> { fn static_addr_of(&self, cv: RValue<'gcc>, align: Align, kind: Option<&str>) -> RValue<'gcc> { - if let Some(global_value) = self.const_globals.borrow().get(&cv) { - // TODO(antoyo): upgrade alignment. - return *global_value; + // TODO(antoyo): implement a proper rvalue comparison in libgccjit instead of doing the + // following: + for (value, variable) in &*self.const_globals.borrow() { + if format!("{:?}", value) == format!("{:?}", cv) { + // TODO(antoyo): upgrade alignment. + return *variable; + } } let global_value = self.static_addr_of_mut(cv, align, kind); // TODO(antoyo): set global constant. @@ -77,7 +81,7 @@ impl<'gcc, 'tcx> StaticMethods for CodegenCx<'gcc, 'tcx> { else { value }; - global.global_set_initializer_value(value); + global.global_set_initializer_rvalue(value); // As an optimization, all shared statics which do not have interior // mutability are placed into read-only memory. @@ -176,7 +180,7 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { }; // FIXME(antoyo): I think the name coming from generate_local_symbol_name() above cannot be used // globally. - global.global_set_initializer_value(cv); + global.global_set_initializer_rvalue(cv); // TODO(antoyo): set unnamed address. global.get_address(None) } @@ -371,7 +375,7 @@ fn check_and_apply_linkage<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, attrs: &Codeg real_name.push_str(&sym); let global2 = cx.define_global(&real_name, llty, is_tls, attrs.link_section); // TODO(antoyo): set linkage. - global2.global_set_initializer_value(global1.get_address(None)); + global2.global_set_initializer_rvalue(global1.get_address(None)); // TODO(antoyo): use global_set_initializer() when it will work. global2 } diff --git a/compiler/rustc_codegen_gcc/src/context.rs b/compiler/rustc_codegen_gcc/src/context.rs index 7677ade7314..dfcd1b62312 100644 --- a/compiler/rustc_codegen_gcc/src/context.rs +++ b/compiler/rustc_codegen_gcc/src/context.rs @@ -1,16 +1,6 @@ use std::cell::{Cell, RefCell}; -use gccjit::{ - Block, - Context, - CType, - Function, - FunctionType, - LValue, - RValue, - Struct, - Type, -}; +use gccjit::{Block, CType, Context, Function, FunctionType, LValue, RValue, Struct, Type}; use rustc_codegen_ssa::base::wants_msvc_seh; use rustc_codegen_ssa::traits::{ BackendTypes, diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs index 0782adeb6a1..572ac559d09 100644 --- a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs +++ b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs @@ -526,7 +526,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { let value = if result_type.is_signed(self.cx) { - self.context.new_bitcast(None, value, typ) + self.context.new_cast(None, value, typ) } else { value @@ -690,7 +690,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { }, }; - self.context.new_bitcast(None, result, result_type) + self.context.new_cast(None, result, result_type) } fn count_leading_zeroes(&self, width: u64, arg: RValue<'gcc>) -> RValue<'gcc> { @@ -741,6 +741,11 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { let not_low = self.context.new_unary_op(None, UnaryOp::LogicalNegate, self.u64_type, low); let not_low_and_not_high = not_low & not_high; let index = not_high + not_low_and_not_high; + // NOTE: the following cast is necessary to avoid a GIMPLE verification failure in + // gcc. + // TODO(antoyo): do the correct verification in libgccjit to avoid an error at the + // compilation stage. + let index = self.context.new_cast(None, index, self.i32_type); let res = self.context.new_array_access(None, result, index); @@ -764,7 +769,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { let arg = if result_type.is_signed(self.cx) { let new_type = result_type.to_unsigned(self.cx); - self.context.new_bitcast(None, arg, new_type) + self.context.new_cast(None, arg, new_type) } else { arg @@ -816,10 +821,15 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { let not_high = self.context.new_unary_op(None, UnaryOp::LogicalNegate, self.u64_type, high); let not_low_and_not_high = not_low & not_high; let index = not_low + not_low_and_not_high; + // NOTE: the following cast is necessary to avoid a GIMPLE verification failure in + // gcc. + // TODO(antoyo): do the correct verification in libgccjit to avoid an error at the + // compilation stage. + let index = self.context.new_cast(None, index, self.i32_type); let res = self.context.new_array_access(None, result, index); - return self.context.new_bitcast(None, res, result_type); + return self.context.new_cast(None, res, result_type); } else { unimplemented!("count_trailing_zeroes for {:?}", arg_type); @@ -833,7 +843,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { arg }; let res = self.context.new_call(None, count_trailing_zeroes, &[arg]); - self.context.new_bitcast(None, res, result_type) + self.context.new_cast(None, res, result_type) } fn int_width(&self, typ: Type<'gcc>) -> i64 { @@ -847,7 +857,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { let value = if result_type.is_signed(self.cx) { - self.context.new_bitcast(None, value, value_type) + self.context.new_cast(None, value, value_type) } else { value @@ -863,7 +873,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { let low = self.context.new_cast(None, value, self.cx.ulonglong_type); let low = self.context.new_call(None, popcount, &[low]); let res = high + low; - return self.context.new_bitcast(None, res, result_type); + return self.context.new_cast(None, res, result_type); } // First step. @@ -888,7 +898,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { let value = left + right; if value_type.is_u8(&self.cx) { - return self.context.new_bitcast(None, value, result_type); + return self.context.new_cast(None, value, result_type); } // Fourth step. @@ -899,7 +909,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { let value = left + right; if value_type.is_u16(&self.cx) { - return self.context.new_bitcast(None, value, result_type); + return self.context.new_cast(None, value, result_type); } // Fifth step. @@ -910,7 +920,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { let value = left + right; if value_type.is_u32(&self.cx) { - return self.context.new_bitcast(None, value, result_type); + return self.context.new_cast(None, value, result_type); } // Sixth step. @@ -920,7 +930,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { let right = shifted & mask; let value = left + right; - self.context.new_bitcast(None, value, result_type) + self.context.new_cast(None, value, result_type) } // Algorithm from: https://blog.regehr.org/archives/1063 diff --git a/compiler/rustc_codegen_gcc/src/lib.rs b/compiler/rustc_codegen_gcc/src/lib.rs index 30a33b99e50..20347f18786 100644 --- a/compiler/rustc_codegen_gcc/src/lib.rs +++ b/compiler/rustc_codegen_gcc/src/lib.rs @@ -20,7 +20,6 @@ extern crate rustc_metadata; extern crate rustc_middle; extern crate rustc_session; extern crate rustc_span; -extern crate rustc_symbol_mangling; extern crate rustc_target; // This prevents duplicating functions and statics that are already part of the host rustc process. @@ -91,8 +90,6 @@ impl CodegenBackend for GccCodegenBackend { let target_cpu = target_cpu(tcx.sess); let res = codegen_crate(self.clone(), tcx, target_cpu.to_string(), metadata, need_metadata_module); - rustc_symbol_mangling::test::report_symbol_names(tcx); - Box::new(res) } diff --git a/compiler/rustc_codegen_gcc/src/type_.rs b/compiler/rustc_codegen_gcc/src/type_.rs index 3545e1b6281..28e2adc492b 100644 --- a/compiler/rustc_codegen_gcc/src/type_.rs +++ b/compiler/rustc_codegen_gcc/src/type_.rs @@ -122,7 +122,7 @@ impl<'gcc, 'tcx> BaseTypeMethods<'tcx> for CodegenCx<'gcc, 'tcx> { if typ.is_integral() { TypeKind::Integer } - else if typ.is_vector().is_some() { + else if typ.dyncast_vector().is_some() { TypeKind::Vector } else { @@ -141,10 +141,10 @@ impl<'gcc, 'tcx> BaseTypeMethods<'tcx> for CodegenCx<'gcc, 'tcx> { } fn element_type(&self, ty: Type<'gcc>) -> Type<'gcc> { - if let Some(typ) = ty.is_array() { + if let Some(typ) = ty.dyncast_array() { typ } - else if let Some(vector_type) = ty.is_vector() { + else if let Some(vector_type) = ty.dyncast_vector() { vector_type.get_element_type() } else if let Some(typ) = ty.get_pointee() { diff --git a/compiler/rustc_codegen_gcc/test.sh b/compiler/rustc_codegen_gcc/test.sh index 944d0ce516e..b9aeee79550 100755 --- a/compiler/rustc_codegen_gcc/test.sh +++ b/compiler/rustc_codegen_gcc/test.sh @@ -183,7 +183,7 @@ EOF git checkout src/test/ui/type-alias-impl-trait/auxiliary/cross_crate_ice2.rs rm src/test/ui/llvm-asm/llvm-asm-in-out-operand.rs || true # TODO(antoyo): Enable back this test if I ever implement the llvm_asm! macro. - RUSTC_ARGS="-Zpanic-abort-tests -Zsymbol-mangling-version=v0 -Zcodegen-backend="$(pwd)"/../target/"$CHANNEL"/librustc_codegen_gcc."$dylib_ext" --sysroot "$(pwd)"/../build_sysroot/sysroot -Cpanic=abort" + RUSTC_ARGS="-Zpanic-abort-tests -Csymbol-mangling-version=v0 -Zcodegen-backend="$(pwd)"/../target/"$CHANNEL"/librustc_codegen_gcc."$dylib_ext" --sysroot "$(pwd)"/../build_sysroot/sysroot -Cpanic=abort" echo "[TEST] rustc test suite" COMPILETEST_FORCE_STAGE0=1 ./x.py test --run always --stage 0 src/test/ui/ --rustc-args "$RUSTC_ARGS" diff --git a/compiler/rustc_codegen_gcc/tests/run/asm.rs b/compiler/rustc_codegen_gcc/tests/run/asm.rs index 48c0203d594..46abbb553bf 100644 --- a/compiler/rustc_codegen_gcc/tests/run/asm.rs +++ b/compiler/rustc_codegen_gcc/tests/run/asm.rs @@ -3,6 +3,10 @@ // Run-time: // status: 0 +#![feature(asm_const, asm_sym)] + +use std::arch::{asm, global_asm}; + global_asm!(" .global add_asm add_asm: @@ -15,6 +19,16 @@ extern "C" { fn add_asm(a: i64, b: i64) -> i64; } +pub unsafe fn mem_cpy(dst: *mut u8, src: *const u8, len: usize) { + asm!( + "rep movsb", + inout("rdi") dst => _, + inout("rsi") src => _, + inout("rcx") len => _, + options(preserves_flags, nostack) + ); +} + fn main() { unsafe { asm!("nop"); @@ -60,11 +74,11 @@ fn main() { } assert_eq!(x, 43); - // check inout(reg_class) x + // check inout(reg_class) x let mut x: u64 = 42; unsafe { asm!("add {0}, {0}", - inout(reg) x + inout(reg) x ); } assert_eq!(x, 84); @@ -73,7 +87,7 @@ fn main() { let mut x: u64 = 42; unsafe { asm!("add r11, r11", - inout("r11") x + inout("r11") x ); } assert_eq!(x, 84); @@ -96,12 +110,12 @@ fn main() { assert_eq!(res, 7); assert_eq!(rem, 2); - // check const + // check const let mut x: u64 = 42; unsafe { asm!("add {}, {}", inout(reg) x, - const 1 + const 1 ); } assert_eq!(x, 43); @@ -148,4 +162,11 @@ fn main() { assert_eq!(x, 42); assert_eq!(unsafe { add_asm(40, 2) }, 42); + + let array1 = [1u8, 2, 3]; + let mut array2 = [0u8, 0, 0]; + unsafe { + mem_cpy(array2.as_mut_ptr(), array1.as_ptr(), 3); + } + assert_eq!(array1, array2); } diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs index 4bb1fed2d51..ddba43cd1f1 100644 --- a/compiler/rustc_codegen_llvm/src/back/lto.rs +++ b/compiler/rustc_codegen_llvm/src/back/lto.rs @@ -3,7 +3,7 @@ use crate::back::write::{ }; use crate::llvm::archive_ro::ArchiveRO; use crate::llvm::{self, build_string, False, True}; -use crate::{LlvmCodegenBackend, ModuleLlvm}; +use crate::{llvm_util, LlvmCodegenBackend, ModuleLlvm}; use rustc_codegen_ssa::back::lto::{LtoModuleCodegen, SerializedModule, ThinModule, ThinShared}; use rustc_codegen_ssa::back::symbol_export; use rustc_codegen_ssa::back::write::{ @@ -596,7 +596,10 @@ pub(crate) fn run_pass_manager( // tools/lto/LTOCodeGenerator.cpp debug!("running the pass manager"); unsafe { - if write::should_use_new_llvm_pass_manager(cgcx, config) { + if llvm_util::should_use_new_llvm_pass_manager( + &config.new_llvm_pass_manager, + &cgcx.target_arch, + ) { let opt_stage = if thin { llvm::OptStage::ThinLTO } else { llvm::OptStage::FatLTO }; let opt_level = config.opt_level.unwrap_or(config::OptLevel::No); write::optimize_with_new_llvm_pass_manager( diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index fb194a98a0d..384596dfff5 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -23,7 +23,7 @@ use rustc_errors::{FatalError, Handler, Level}; use rustc_fs_util::{link_or_copy, path_to_c_string}; use rustc_middle::bug; use rustc_middle::ty::TyCtxt; -use rustc_session::config::{self, Lto, OutputType, Passes, SwitchWithOptPath}; +use rustc_session::config::{self, Lto, OutputType, Passes, SplitDwarfKind, SwitchWithOptPath}; use rustc_session::Session; use rustc_span::symbol::sym; use rustc_span::InnerSpan; @@ -106,7 +106,11 @@ pub fn create_informational_target_machine(sess: &Session) -> &'static mut llvm: pub fn create_target_machine(tcx: TyCtxt<'_>, mod_name: &str) -> &'static mut llvm::TargetMachine { let split_dwarf_file = if tcx.sess.target_can_use_split_dwarf() { - tcx.output_filenames(()).split_dwarf_path(tcx.sess.split_debuginfo(), Some(mod_name)) + tcx.output_filenames(()).split_dwarf_path( + tcx.sess.split_debuginfo(), + tcx.sess.opts.debugging_opts.split_dwarf_kind, + Some(mod_name), + ) } else { None }; @@ -416,21 +420,6 @@ fn get_pgo_sample_use_path(config: &ModuleConfig) -> Option<CString> { .map(|path_buf| CString::new(path_buf.to_string_lossy().as_bytes()).unwrap()) } -pub(crate) fn should_use_new_llvm_pass_manager( - cgcx: &CodegenContext<LlvmCodegenBackend>, - config: &ModuleConfig, -) -> bool { - // The new pass manager is enabled by default for LLVM >= 13. - // This matches Clang, which also enables it since Clang 13. - - // FIXME: There are some perf issues with the new pass manager - // when targeting s390x, so it is temporarily disabled for that - // arch, see https://github.com/rust-lang/rust/issues/89609 - config - .new_llvm_pass_manager - .unwrap_or_else(|| cgcx.target_arch != "s390x" && llvm_util::get_version() >= (13, 0, 0)) -} - pub(crate) unsafe fn optimize_with_new_llvm_pass_manager( cgcx: &CodegenContext<LlvmCodegenBackend>, diag_handler: &Handler, @@ -473,6 +462,8 @@ pub(crate) unsafe fn optimize_with_new_llvm_pass_manager( let extra_passes = config.passes.join(","); + let llvm_plugins = config.llvm_plugins.join(","); + // FIXME: NewPM doesn't provide a facility to pass custom InlineParams. // We would have to add upstream support for this first, before we can support // config.inline_threshold and our more aggressive default thresholds. @@ -502,6 +493,8 @@ pub(crate) unsafe fn optimize_with_new_llvm_pass_manager( selfprofile_after_pass_callback, extra_passes.as_ptr().cast(), extra_passes.len(), + llvm_plugins.as_ptr().cast(), + llvm_plugins.len(), ); result.into_result().map_err(|()| llvm_err(diag_handler, "failed to run LLVM passes")) } @@ -530,7 +523,10 @@ pub(crate) unsafe fn optimize( } if let Some(opt_level) = config.opt_level { - if should_use_new_llvm_pass_manager(cgcx, config) { + if llvm_util::should_use_new_llvm_pass_manager( + &config.new_llvm_pass_manager, + &cgcx.target_arch, + ) { let opt_stage = match cgcx.lto { Lto::Fat => llvm::OptStage::PreLinkFatLTO, Lto::Thin | Lto::ThinLocal => llvm::OptStage::PreLinkThinLTO, @@ -900,17 +896,18 @@ pub(crate) unsafe fn codegen( .generic_activity_with_arg("LLVM_module_codegen_emit_obj", &*module.name); let dwo_out = cgcx.output_filenames.temp_path_dwo(module_name); - let dwo_out = match cgcx.split_debuginfo { - // Don't change how DWARF is emitted in single mode (or when disabled). - SplitDebuginfo::Off | SplitDebuginfo::Packed => None, - // Emit (a subset of the) DWARF into a separate file in split mode. - SplitDebuginfo::Unpacked => { - if cgcx.target_can_use_split_dwarf { - Some(dwo_out.as_path()) - } else { - None - } - } + let dwo_out = match (cgcx.split_debuginfo, cgcx.split_dwarf_kind) { + // Don't change how DWARF is emitted when disabled. + (SplitDebuginfo::Off, _) => None, + // Don't provide a DWARF object path if split debuginfo is enabled but this is + // a platform that doesn't support Split DWARF. + _ if !cgcx.target_can_use_split_dwarf => None, + // Don't provide a DWARF object path in single mode, sections will be written + // into the object as normal but ignored by linker. + (_, SplitDwarfKind::Single) => None, + // Emit (a subset of the) DWARF into a separate dwarf object file in split + // mode. + (_, SplitDwarfKind::Split) => Some(dwo_out.as_path()), }; with_codegen(tm, llmod, config.no_builtins, |cpm| { @@ -947,7 +944,9 @@ pub(crate) unsafe fn codegen( Ok(module.into_compiled_module( config.emit_obj != EmitObj::None, - cgcx.target_can_use_split_dwarf && cgcx.split_debuginfo == SplitDebuginfo::Unpacked, + cgcx.target_can_use_split_dwarf + && cgcx.split_debuginfo != SplitDebuginfo::Off + && cgcx.split_dwarf_kind == SplitDwarfKind::Split, config.emit_bc, &cgcx.output_filenames, )) diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index 8c3054b23ff..5217fa2758f 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -1201,8 +1201,15 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { unsafe { llvm::LLVMBuildZExt(self.llbuilder, val, dest_ty, UNNAMED) } } - fn do_not_inline(&mut self, llret: &'ll Value) { - llvm::Attribute::NoInline.apply_callsite(llvm::AttributePlace::Function, llret); + fn apply_attrs_to_cleanup_callsite(&mut self, llret: &'ll Value) { + // Cleanup is always the cold path. + llvm::Attribute::Cold.apply_callsite(llvm::AttributePlace::Function, llret); + + // In LLVM versions with deferred inlining (currently, system LLVM < 14), + // inlining drop glue can lead to exponential size blowup, see #41696 and #92110. + if !llvm_util::is_rust_llvm() && llvm_util::get_version() < (14, 0, 0) { + llvm::Attribute::NoInline.apply_callsite(llvm::AttributePlace::Function, llret); + } } } diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index 9f24a95482c..bb16bc5dccd 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -21,7 +21,7 @@ use rustc_middle::ty::layout::{ }; use rustc_middle::ty::{self, Instance, Ty, TyCtxt}; use rustc_middle::{bug, span_bug}; -use rustc_session::config::{CFGuard, CrateType, DebugInfo}; +use rustc_session::config::{BranchProtection, CFGuard, CrateType, DebugInfo, PAuthKey, PacRet}; use rustc_session::Session; use rustc_span::source_map::Span; use rustc_span::symbol::Symbol; @@ -242,6 +242,34 @@ pub unsafe fn create_module<'ll>( } } + if sess.target.arch == "aarch64" { + let BranchProtection { bti, pac_ret: pac } = sess.opts.debugging_opts.branch_protection; + + llvm::LLVMRustAddModuleFlag( + llmod, + "branch-target-enforcement\0".as_ptr().cast(), + bti.into(), + ); + + llvm::LLVMRustAddModuleFlag( + llmod, + "sign-return-address\0".as_ptr().cast(), + pac.is_some().into(), + ); + let pac_opts = pac.unwrap_or(PacRet { leaf: false, key: PAuthKey::A }); + llvm::LLVMRustAddModuleFlag( + llmod, + "sign-return-address-all\0".as_ptr().cast(), + pac_opts.leaf.into(), + ); + let is_bkey = if pac_opts.key == PAuthKey::A { false } else { true }; + llvm::LLVMRustAddModuleFlag( + llmod, + "sign-return-address-with-bkey\0".as_ptr().cast(), + is_bkey.into(), + ); + } + llmod } diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index 5f9c4189168..e8d35cf5697 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -1072,7 +1072,11 @@ pub fn compile_unit_metadata<'ll, 'tcx>( let output_filenames = tcx.output_filenames(()); let split_name = if tcx.sess.target_can_use_split_dwarf() { output_filenames - .split_dwarf_path(tcx.sess.split_debuginfo(), Some(codegen_unit_name)) + .split_dwarf_path( + tcx.sess.split_debuginfo(), + tcx.sess.opts.debugging_opts.split_dwarf_kind, + Some(codegen_unit_name), + ) // We get a path relative to the working directory from split_dwarf_path .map(|f| tcx.sess.source_map().path_mapping().map_prefix(f).0) } else { diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs index 3e7371179cc..01f7868df34 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs @@ -160,17 +160,17 @@ impl<'ll> DebugInfoBuilderMethods for Builder<'_, 'll, '_> { // the values should match the ones in the DWARF standard anyway. let op_deref = || unsafe { llvm::LLVMRustDIBuilderCreateOpDeref() }; let op_plus_uconst = || unsafe { llvm::LLVMRustDIBuilderCreateOpPlusUconst() }; - let mut addr_ops = SmallVec::<[_; 8]>::new(); + let mut addr_ops = SmallVec::<[u64; 8]>::new(); if direct_offset.bytes() > 0 { addr_ops.push(op_plus_uconst()); - addr_ops.push(direct_offset.bytes() as i64); + addr_ops.push(direct_offset.bytes() as u64); } for &offset in indirect_offsets { addr_ops.push(op_deref()); if offset.bytes() > 0 { addr_ops.push(op_plus_uconst()); - addr_ops.push(offset.bytes() as i64); + addr_ops.push(offset.bytes() as u64); } } diff --git a/compiler/rustc_codegen_llvm/src/declare.rs b/compiler/rustc_codegen_llvm/src/declare.rs index 90d0d5caba1..a6e06ffa819 100644 --- a/compiler/rustc_codegen_llvm/src/declare.rs +++ b/compiler/rustc_codegen_llvm/src/declare.rs @@ -47,6 +47,7 @@ fn declare_raw_fn<'ll>( attributes::default_optimisation_attrs(cx.tcx.sess, llfn); attributes::non_lazy_bind(cx.sess(), llfn); + llfn } diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 6c911938ccc..f2782f84f55 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -1902,6 +1902,8 @@ extern "C" { pub fn LLVMRustVersionMinor() -> u32; pub fn LLVMRustVersionPatch() -> u32; + pub fn LLVMRustIsRustLLVM() -> bool; + pub fn LLVMRustAddModuleFlag(M: &Module, name: *const c_char, value: u32); pub fn LLVMRustMetadataAsValue<'a>(C: &'a Context, MD: &'a Metadata) -> &'a Value; @@ -2106,7 +2108,7 @@ extern "C" { Builder: &DIBuilder<'a>, Val: &'a Value, VarInfo: &'a DIVariable, - AddrOps: *const i64, + AddrOps: *const u64, AddrOpsCount: c_uint, DL: &'a DILocation, InsertAtEnd: &'a BasicBlock, @@ -2197,8 +2199,8 @@ extern "C" { Scope: &'a DIScope, InlinedAt: Option<&'a DILocation>, ) -> &'a DILocation; - pub fn LLVMRustDIBuilderCreateOpDeref() -> i64; - pub fn LLVMRustDIBuilderCreateOpPlusUconst() -> i64; + pub fn LLVMRustDIBuilderCreateOpDeref() -> u64; + pub fn LLVMRustDIBuilderCreateOpPlusUconst() -> u64; #[allow(improper_ctypes)] pub fn LLVMRustWriteTypeToString(Type: &Type, s: &RustString); @@ -2313,6 +2315,8 @@ extern "C" { end_callback: SelfProfileAfterPassCallback, ExtraPasses: *const c_char, ExtraPassesLen: size_t, + LLVMPlugins: *const c_char, + LLVMPluginsLen: size_t, ) -> LLVMRustResult; pub fn LLVMRustPrintModule( M: &Module, diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index e4935ac431c..d49df29f453 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -121,14 +121,20 @@ unsafe fn configure_llvm(sess: &Session) { llvm::LLVMInitializePasses(); - // Register LLVM plugins by loading them into the compiler process. - for plugin in &sess.opts.debugging_opts.llvm_plugins { - let lib = Library::new(plugin).unwrap_or_else(|e| bug!("couldn't load plugin: {}", e)); - debug!("LLVM plugin loaded successfully {:?} ({})", lib, plugin); - - // Intentionally leak the dynamic library. We can't ever unload it - // since the library can make things that will live arbitrarily long. - mem::forget(lib); + // Use the legacy plugin registration if we don't use the new pass manager + if !should_use_new_llvm_pass_manager( + &sess.opts.debugging_opts.new_llvm_pass_manager, + &sess.target.arch, + ) { + // Register LLVM plugins by loading them into the compiler process. + for plugin in &sess.opts.debugging_opts.llvm_plugins { + let lib = Library::new(plugin).unwrap_or_else(|e| bug!("couldn't load plugin: {}", e)); + debug!("LLVM plugin loaded successfully {:?} ({})", lib, plugin); + + // Intentionally leak the dynamic library. We can't ever unload it + // since the library can make things that will live arbitrarily long. + mem::forget(lib); + } } rustc_llvm::initialize_available_targets(); @@ -217,6 +223,12 @@ pub fn get_version() -> (u32, u32, u32) { } } +/// Returns `true` if this LLVM is Rust's bundled LLVM (and not system LLVM). +pub fn is_rust_llvm() -> bool { + // Can be called without initializing LLVM + unsafe { llvm::LLVMRustIsRustLLVM() } +} + pub fn print_passes() { // Can be called without initializing LLVM unsafe { @@ -411,3 +423,13 @@ pub fn tune_cpu(sess: &Session) -> Option<&str> { let name = sess.opts.debugging_opts.tune_cpu.as_ref()?; Some(handle_native(name)) } + +pub(crate) fn should_use_new_llvm_pass_manager(user_opt: &Option<bool>, target_arch: &str) -> bool { + // The new pass manager is enabled by default for LLVM >= 13. + // This matches Clang, which also enables it since Clang 13. + + // FIXME: There are some perf issues with the new pass manager + // when targeting s390x, so it is temporarily disabled for that + // arch, see https://github.com/rust-lang/rust/issues/89609 + user_opt.unwrap_or_else(|| target_arch != "s390x" && llvm_util::get_version() >= (13, 0, 0)) +} diff --git a/compiler/rustc_codegen_ssa/Cargo.toml b/compiler/rustc_codegen_ssa/Cargo.toml index 18dbcd8e52d..5c13dfdc1b5 100644 --- a/compiler/rustc_codegen_ssa/Cargo.toml +++ b/compiler/rustc_codegen_ssa/Cargo.toml @@ -14,12 +14,14 @@ tracing = "0.1" libc = "0.2.50" jobserver = "0.1.22" tempfile = "3.2" +thorin-dwp = "0.1.1" pathdiff = "0.2.0" snap = "1" smallvec = { version = "1.6.1", features = ["union", "may_dangle"] } regex = "1.4" rustc_serialize = { path = "../rustc_serialize" } +rustc_arena = { path = "../rustc_arena" } rustc_ast = { path = "../rustc_ast" } rustc_span = { path = "../rustc_span" } rustc_middle = { path = "../rustc_middle" } diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 42a28f94298..f7fe194d207 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -1,11 +1,13 @@ +use rustc_arena::TypedArena; use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; +use rustc_data_structures::memmap::Mmap; use rustc_data_structures::temp_dir::MaybeTempDir; use rustc_errors::{ErrorReported, Handler}; use rustc_fs_util::fix_windows_verbatim_for_gcc; use rustc_hir::def_id::CrateNum; use rustc_middle::middle::dependency_format::Linkage; use rustc_session::config::{self, CFGuard, CrateType, DebugInfo, LdImpl, Strip}; -use rustc_session::config::{OutputFilenames, OutputType, PrintRequest}; +use rustc_session::config::{OutputFilenames, OutputType, PrintRequest, SplitDwarfKind}; use rustc_session::cstore::DllImport; use rustc_session::output::{check_file_is_writeable, invalid_output_for_target, out_filename}; use rustc_session::search_paths::PathKind; @@ -32,7 +34,10 @@ use cc::windows_registry; use regex::Regex; use tempfile::Builder as TempFileBuilder; -use std::ffi::{OsStr, OsString}; +use std::borrow::Borrow; +use std::ffi::OsString; +use std::fs::{File, OpenOptions}; +use std::io::{BufWriter, Write}; use std::lazy::OnceCell; use std::path::{Path, PathBuf}; use std::process::{ExitStatus, Output, Stdio}; @@ -134,31 +139,47 @@ pub fn link_binary<'a, B: ArchiveBuilder<'a>>( } } - // Remove the temporary object file and metadata if we aren't saving temps + // Remove the temporary object file and metadata if we aren't saving temps. sess.time("link_binary_remove_temps", || { - if !sess.opts.cg.save_temps { - let remove_temps_from_module = |module: &CompiledModule| { - if let Some(ref obj) = module.object { - ensure_removed(sess.diagnostic(), obj); - } - - if let Some(ref obj) = module.dwarf_object { - ensure_removed(sess.diagnostic(), obj); - } - }; + // If the user requests that temporaries are saved, don't delete any. + if sess.opts.cg.save_temps { + return; + } - if sess.opts.output_types.should_link() && !preserve_objects_for_their_debuginfo(sess) { - for module in &codegen_results.modules { - remove_temps_from_module(module); - } + let remove_temps_from_module = |module: &CompiledModule| { + if let Some(ref obj) = module.object { + ensure_removed(sess.diagnostic(), obj); } + }; + + // Otherwise, always remove the metadata and allocator module temporaries. + if let Some(ref metadata_module) = codegen_results.metadata_module { + remove_temps_from_module(metadata_module); + } + + if let Some(ref allocator_module) = codegen_results.allocator_module { + remove_temps_from_module(allocator_module); + } - if let Some(ref metadata_module) = codegen_results.metadata_module { - remove_temps_from_module(metadata_module); + // If no requested outputs require linking, then the object temporaries should + // be kept. + if !sess.opts.output_types.should_link() { + return; + } + + // Potentially keep objects for their debuginfo. + let (preserve_objects, preserve_dwarf_objects) = preserve_objects_for_their_debuginfo(sess); + debug!(?preserve_objects, ?preserve_dwarf_objects); + + for module in &codegen_results.modules { + if !preserve_objects { + remove_temps_from_module(module); } - if let Some(ref allocator_module) = codegen_results.allocator_module { - remove_temps_from_module(allocator_module); + if !preserve_dwarf_objects { + if let Some(ref obj) = module.dwarf_object { + ensure_removed(sess.diagnostic(), obj); + } } } }); @@ -245,8 +266,14 @@ fn link_rlib<'a, B: ArchiveBuilder<'a>>( let mut ab = <B as ArchiveBuilder>::new(sess, out_filename, None); - for obj in codegen_results.modules.iter().filter_map(|m| m.object.as_ref()) { - ab.add_file(obj); + for m in &codegen_results.modules { + if let Some(obj) = m.object.as_ref() { + ab.add_file(obj); + } + + if let Some(dwarf_obj) = m.dwarf_object.as_ref() { + ab.add_file(dwarf_obj); + } } // Note that in this loop we are ignoring the value of `lib.cfg`. That is, @@ -502,59 +529,108 @@ fn escape_stdout_stderr_string(s: &[u8]) -> String { }) } -const LLVM_DWP_EXECUTABLE: &'static str = "rust-llvm-dwp"; - -/// Invoke `llvm-dwp` (shipped alongside rustc) to link debuginfo in object files into a `dwp` -/// file. -fn link_dwarf_object<'a, I>(sess: &'a Session, executable_out_filename: &Path, object_files: I) -where - I: IntoIterator<Item: AsRef<OsStr>>, -{ - info!("preparing dwp to {}.dwp", executable_out_filename.to_str().unwrap()); - +/// Use `thorin` (rust implementation of a dwarf packaging utility) to link DWARF objects into a +/// DWARF package. +fn link_dwarf_object<'a>( + sess: &'a Session, + cg_results: &CodegenResults, + executable_out_filename: &Path, +) { let dwp_out_filename = executable_out_filename.with_extension("dwp"); - let mut cmd = Command::new(LLVM_DWP_EXECUTABLE); - cmd.arg("-o"); - cmd.arg(&dwp_out_filename); - cmd.args(object_files); + debug!(?dwp_out_filename, ?executable_out_filename); - let mut new_path = sess.get_tools_search_paths(false); - if let Some(path) = env::var_os("PATH") { - new_path.extend(env::split_paths(&path)); + #[derive(Default)] + struct ThorinSession<Relocations> { + arena_data: TypedArena<Vec<u8>>, + arena_mmap: TypedArena<Mmap>, + arena_relocations: TypedArena<Relocations>, } - let new_path = env::join_paths(new_path).unwrap(); - cmd.env("PATH", new_path); - info!("{:?}", &cmd); - match sess.time("run_dwp", || cmd.output()) { - Ok(prog) if !prog.status.success() => { - sess.struct_err(&format!( - "linking dwarf objects with `{}` failed: {}", - LLVM_DWP_EXECUTABLE, prog.status - )) - .note(&format!("{:?}", &cmd)) - .note(&escape_stdout_stderr_string(&prog.stdout)) - .note(&escape_stdout_stderr_string(&prog.stderr)) - .emit(); - info!("linker stderr:\n{}", escape_stdout_stderr_string(&prog.stderr)); - info!("linker stdout:\n{}", escape_stdout_stderr_string(&prog.stdout)); + impl<Relocations> ThorinSession<Relocations> { + fn alloc_mmap<'arena>(&'arena self, data: Mmap) -> &'arena Mmap { + (*self.arena_mmap.alloc(data)).borrow() } - Ok(_) => {} - Err(e) => { - let dwp_not_found = e.kind() == io::ErrorKind::NotFound; - let mut err = if dwp_not_found { - sess.struct_err(&format!("linker `{}` not found", LLVM_DWP_EXECUTABLE)) - } else { - sess.struct_err(&format!("could not exec the linker `{}`", LLVM_DWP_EXECUTABLE)) - }; + } - err.note(&e.to_string()); + impl<Relocations> thorin::Session<Relocations> for ThorinSession<Relocations> { + fn alloc_data<'arena>(&'arena self, data: Vec<u8>) -> &'arena [u8] { + (*self.arena_data.alloc(data)).borrow() + } - if !dwp_not_found { - err.note(&format!("{:?}", &cmd)); + fn alloc_relocation<'arena>(&'arena self, data: Relocations) -> &'arena Relocations { + (*self.arena_relocations.alloc(data)).borrow() + } + + fn read_input<'arena>(&'arena self, path: &Path) -> std::io::Result<&'arena [u8]> { + let file = File::open(&path)?; + let mmap = (unsafe { Mmap::map(file) })?; + Ok(self.alloc_mmap(mmap)) + } + } + + match sess.time("run_thorin", || -> Result<(), thorin::Error> { + let thorin_sess = ThorinSession::default(); + let mut package = thorin::DwarfPackage::new(&thorin_sess); + + // Input objs contain .o/.dwo files from the current crate. + match sess.opts.debugging_opts.split_dwarf_kind { + SplitDwarfKind::Single => { + for input_obj in cg_results.modules.iter().filter_map(|m| m.object.as_ref()) { + package.add_input_object(input_obj)?; + } } + SplitDwarfKind::Split => { + for input_obj in cg_results.modules.iter().filter_map(|m| m.dwarf_object.as_ref()) { + package.add_input_object(input_obj)?; + } + } + } - err.emit(); + // Input rlibs contain .o/.dwo files from dependencies. + let input_rlibs = cg_results + .crate_info + .used_crate_source + .values() + .filter_map(|csource| csource.rlib.as_ref()) + .map(|(path, _)| path); + for input_rlib in input_rlibs { + debug!(?input_rlib); + package.add_input_object(input_rlib)?; + } + + // Failing to read the referenced objects is expected for dependencies where the path in the + // executable will have been cleaned by Cargo, but the referenced objects will be contained + // within rlibs provided as inputs. + // + // If paths have been remapped, then .o/.dwo files from the current crate also won't be + // found, but are provided explicitly above. + // + // Adding an executable is primarily done to make `thorin` check that all the referenced + // dwarf objects are found in the end. + package.add_executable( + &executable_out_filename, + thorin::MissingReferencedObjectBehaviour::Skip, + )?; + + let output = package.finish()?.write()?; + let mut output_stream = BufWriter::new( + OpenOptions::new() + .read(true) + .write(true) + .create(true) + .truncate(true) + .open(dwp_out_filename)?, + ); + output_stream.write_all(&output)?; + output_stream.flush()?; + + Ok(()) + }) { + Ok(()) => {} + Err(e) => { + sess.struct_err("linking dwarf objects with thorin failed") + .note(&format!("{:?}", e)) + .emit(); } } } @@ -900,14 +976,11 @@ fn link_natively<'a, B: ArchiveBuilder<'a>>( SplitDebuginfo::Packed if sess.target.is_like_msvc => {} // ... and otherwise we're processing a `*.dwp` packed dwarf file. + // // We cannot rely on the .o paths in the exectuable because they may have been - // remapped by --remap-path-prefix and therefore invalid. So we need to provide - // the .o paths explicitly - SplitDebuginfo::Packed => link_dwarf_object( - sess, - &out_filename, - codegen_results.modules.iter().filter_map(|m| m.object.as_ref()), - ), + // remapped by --remap-path-prefix and therefore invalid, so we need to provide + // the .o/.dwo paths explicitly. + SplitDebuginfo::Packed => link_dwarf_object(sess, codegen_results, out_filename), } let strip = strip_value(sess); @@ -1138,26 +1211,36 @@ pub fn linker_and_flavor(sess: &Session) -> (PathBuf, LinkerFlavor) { bug!("Not enough information provided to determine how to invoke the linker"); } -/// Returns a boolean indicating whether we should preserve the object files on -/// the filesystem for their debug information. This is often useful with -/// split-dwarf like schemes. -fn preserve_objects_for_their_debuginfo(sess: &Session) -> bool { +/// Returns a pair of boolean indicating whether we should preserve the object and +/// dwarf object files on the filesystem for their debug information. This is often +/// useful with split-dwarf like schemes. +fn preserve_objects_for_their_debuginfo(sess: &Session) -> (bool, bool) { // If the objects don't have debuginfo there's nothing to preserve. if sess.opts.debuginfo == config::DebugInfo::None { - return false; + return (false, false); } // If we're only producing artifacts that are archives, no need to preserve // the objects as they're losslessly contained inside the archives. - let output_linked = - sess.crate_types().iter().any(|&x| x != CrateType::Rlib && x != CrateType::Staticlib); - if !output_linked { - return false; + if sess.crate_types().iter().all(|&x| x.is_archive()) { + return (false, false); + } + + match (sess.split_debuginfo(), sess.opts.debugging_opts.split_dwarf_kind) { + // If there is no split debuginfo then do not preserve objects. + (SplitDebuginfo::Off, _) => (false, false), + // If there is packed split debuginfo, then the debuginfo in the objects + // has been packaged and the objects can be deleted. + (SplitDebuginfo::Packed, _) => (false, false), + // If there is unpacked split debuginfo and the current target can not use + // split dwarf, then keep objects. + (SplitDebuginfo::Unpacked, _) if !sess.target_can_use_split_dwarf() => (true, false), + // If there is unpacked split debuginfo and the target can use split dwarf, then + // keep the object containing that debuginfo (whether that is an object file or + // dwarf object file depends on the split dwarf kind). + (SplitDebuginfo::Unpacked, SplitDwarfKind::Single) => (true, false), + (SplitDebuginfo::Unpacked, SplitDwarfKind::Split) => (false, true), } - - // "unpacked" split debuginfo means that we leave object files as the - // debuginfo is found in the original object files themselves - sess.split_debuginfo() == SplitDebuginfo::Unpacked } fn archive_search_paths(sess: &Session) -> Vec<PathBuf> { diff --git a/compiler/rustc_codegen_ssa/src/back/metadata.rs b/compiler/rustc_codegen_ssa/src/back/metadata.rs index 7c97143e807..79c24f0f172 100644 --- a/compiler/rustc_codegen_ssa/src/back/metadata.rs +++ b/compiler/rustc_codegen_ssa/src/back/metadata.rs @@ -6,8 +6,8 @@ use std::path::Path; use object::write::{self, StandardSegment, Symbol, SymbolSection}; use object::{ - elf, Architecture, BinaryFormat, Endianness, FileFlags, Object, ObjectSection, SectionFlags, - SectionKind, SymbolFlags, SymbolKind, SymbolScope, + elf, pe, Architecture, BinaryFormat, Endianness, FileFlags, Object, ObjectSection, + SectionFlags, SectionKind, SymbolFlags, SymbolKind, SymbolScope, }; use snap::write::FrameEncoder; @@ -216,13 +216,12 @@ pub fn create_rmeta_file(sess: &Session, metadata: &[u8]) -> Vec<u8> { ); match file.format() { BinaryFormat::Coff => { - const IMAGE_SCN_LNK_REMOVE: u32 = 0; file.section_mut(section).flags = - SectionFlags::Coff { characteristics: IMAGE_SCN_LNK_REMOVE }; + SectionFlags::Coff { characteristics: pe::IMAGE_SCN_LNK_REMOVE }; } BinaryFormat::Elf => { - const SHF_EXCLUDE: u64 = 0x80000000; - file.section_mut(section).flags = SectionFlags::Elf { sh_flags: SHF_EXCLUDE }; + file.section_mut(section).flags = + SectionFlags::Elf { sh_flags: elf::SHF_EXCLUDE as u64 }; } _ => {} }; diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index d6af6104155..bea454458c4 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -113,6 +113,7 @@ pub struct ModuleConfig { pub inline_threshold: Option<u32>, pub new_llvm_pass_manager: Option<bool>, pub emit_lifetime_markers: bool, + pub llvm_plugins: Vec<String>, } impl ModuleConfig { @@ -260,6 +261,7 @@ impl ModuleConfig { inline_threshold: sess.opts.cg.inline_threshold, new_llvm_pass_manager: sess.opts.debugging_opts.new_llvm_pass_manager, emit_lifetime_markers: sess.emit_lifetime_markers(), + llvm_plugins: if_regular!(sess.opts.debugging_opts.llvm_plugins.clone(), vec![]), } } @@ -284,7 +286,11 @@ impl TargetMachineFactoryConfig { module_name: &str, ) -> TargetMachineFactoryConfig { let split_dwarf_file = if cgcx.target_can_use_split_dwarf { - cgcx.output_filenames.split_dwarf_path(cgcx.split_debuginfo, Some(module_name)) + cgcx.output_filenames.split_dwarf_path( + cgcx.split_debuginfo, + cgcx.split_dwarf_kind, + Some(module_name), + ) } else { None }; @@ -327,6 +333,7 @@ pub struct CodegenContext<B: WriteBackendMethods> { pub target_arch: String, pub debuginfo: config::DebugInfo, pub split_debuginfo: rustc_target::spec::SplitDebuginfo, + pub split_dwarf_kind: rustc_session::config::SplitDwarfKind, // Number of cgus excluding the allocator/metadata modules pub total_cgus: usize, @@ -1058,6 +1065,7 @@ fn start_executing_work<B: ExtraBackendMethods>( target_arch: tcx.sess.target.arch.clone(), debuginfo: tcx.sess.opts.debuginfo, split_debuginfo: tcx.sess.split_debuginfo(), + split_dwarf_kind: tcx.sess.opts.debugging_opts.split_dwarf_kind, }; // This is the "main loop" of parallel work happening for parallel codegen. diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index e914e493269..dcfe5fcc2ca 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -160,11 +160,7 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> { let llret = bx.call(fn_ty, fn_ptr, &llargs, self.funclet(fx)); bx.apply_attrs_callsite(&fn_abi, llret); if fx.mir[self.bb].is_cleanup { - // Cleanup is always the cold path. Don't inline - // drop glue. Also, when there is a deeply-nested - // struct, there are "symmetry" issues that cause - // exponential inlining - see issue #41696. - bx.do_not_inline(llret); + bx.apply_attrs_to_cleanup_callsite(llret); } if let Some((ret_dest, target)) = destination { diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index 6f960ca44cd..679c4576701 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -8,7 +8,6 @@ use crate::traits::*; use crate::MemFlags; use rustc_apfloat::{ieee, Float, Round, Status}; -use rustc_hir::lang_items::LangItem; use rustc_middle::mir; use rustc_middle::ty::cast::{CastTy, IntTy}; use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf}; @@ -486,31 +485,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { ) } - mir::Rvalue::NullaryOp(mir::NullOp::Box, content_ty) => { - let content_ty = self.monomorphize(content_ty); - let content_layout = bx.cx().layout_of(content_ty); - let llsize = bx.cx().const_usize(content_layout.size.bytes()); - let llalign = bx.cx().const_usize(content_layout.align.abi.bytes()); - let box_layout = bx.cx().layout_of(bx.tcx().mk_box(content_ty)); - let llty_ptr = bx.cx().backend_type(box_layout); - - // Allocate space: - let def_id = match bx.tcx().lang_items().require(LangItem::ExchangeMalloc) { - Ok(id) => id, - Err(s) => { - bx.cx().sess().fatal(&format!("allocation of `{}` {}", box_layout.ty, s)); - } - }; - let instance = ty::Instance::mono(bx.tcx(), def_id); - let r = bx.cx().get_fn_addr(instance); - let ty = bx.type_func(&[bx.type_isize(), bx.type_isize()], bx.type_i8p()); - let call = bx.call(ty, r, &[llsize, llalign], None); - let val = bx.pointercast(call, llty_ptr); - - let operand = OperandRef { val: OperandValue::Immediate(val), layout: box_layout }; - (bx, operand) - } - mir::Rvalue::NullaryOp(null_op, ty) => { let ty = self.monomorphize(ty); assert!(bx.cx().type_is_sized(ty)); @@ -518,7 +492,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let val = match null_op { mir::NullOp::SizeOf => layout.size.bytes(), mir::NullOp::AlignOf => layout.align.abi.bytes(), - mir::NullOp::Box => unreachable!(), }; let val = bx.cx().const_usize(val); let tcx = self.cx.tcx(); diff --git a/compiler/rustc_codegen_ssa/src/traits/builder.rs b/compiler/rustc_codegen_ssa/src/traits/builder.rs index 158e658301e..48d88095855 100644 --- a/compiler/rustc_codegen_ssa/src/traits/builder.rs +++ b/compiler/rustc_codegen_ssa/src/traits/builder.rs @@ -311,5 +311,5 @@ pub trait BuilderMethods<'a, 'tcx>: ) -> Self::Value; fn zext(&mut self, val: Self::Value, dest_ty: Self::Type) -> Self::Value; - fn do_not_inline(&mut self, llret: Self::Value); + fn apply_attrs_to_cleanup_callsite(&mut self, llret: Self::Value); } diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs index c5412affafe..3ec9f3ca3b8 100644 --- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs @@ -63,7 +63,7 @@ fn eval_body_using_ecx<'mir, 'tcx>( cid.instance, body, Some(&ret.into()), - StackPopCleanup::None { cleanup: false }, + StackPopCleanup::Root { cleanup: false }, )?; // The main interpreter loop. diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index fef0e00e507..30e9cbe4403 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -398,13 +398,6 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, Err(ConstEvalErrKind::NeedsRfc("pointer arithmetic or comparison".to_string()).into()) } - fn box_alloc( - _ecx: &mut InterpCx<'mir, 'tcx, Self>, - _dest: &PlaceTy<'tcx>, - ) -> InterpResult<'tcx> { - Err(ConstEvalErrKind::NeedsRfc("heap allocations via `box` keyword".to_string()).into()) - } - fn before_terminator(ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx> { // The step limit has already been hit in a previous call to `before_terminator`. if ecx.machine.steps_remaining == 0 { diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs index 246807a112a..0a8112da2ab 100644 --- a/compiler/rustc_const_eval/src/interpret/eval_context.rs +++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs @@ -156,11 +156,11 @@ pub enum StackPopCleanup { /// `ret` stores the block we jump to on a normal return, while `unwind` /// stores the block used for cleanup during unwinding. Goto { ret: Option<mir::BasicBlock>, unwind: StackPopUnwind }, - /// Just do nothing: Used by Main and for the `box_alloc` hook in miri. + /// The root frame of the stack: nowhere else to jump to. /// `cleanup` says whether locals are deallocated. Static computation /// wants them leaked to intern what they need (and just throw away /// the entire `ecx` when it is done). - None { cleanup: bool }, + Root { cleanup: bool }, } /// State of a local variable including a memoized layout @@ -849,7 +849,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // because this is CTFE and the final value will be thoroughly validated anyway. let cleanup = match return_to_block { StackPopCleanup::Goto { .. } => true, - StackPopCleanup::None { cleanup, .. } => cleanup, + StackPopCleanup::Root { cleanup, .. } => cleanup, }; if !cleanup { @@ -874,8 +874,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // Follow the unwind edge. let unwind = match return_to_block { StackPopCleanup::Goto { unwind, .. } => unwind, - StackPopCleanup::None { .. } => { - panic!("Encountered StackPopCleanup::None when unwinding!") + StackPopCleanup::Root { .. } => { + panic!("encountered StackPopCleanup::Root when unwinding!") } }; self.unwind_to_block(unwind) @@ -883,7 +883,13 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // Follow the normal return edge. match return_to_block { StackPopCleanup::Goto { ret, .. } => self.return_to_block(ret), - StackPopCleanup::None { .. } => Ok(()), + StackPopCleanup::Root { .. } => { + assert!( + self.stack().is_empty(), + "only the topmost frame can have StackPopCleanup::Root" + ); + Ok(()) + } } } } diff --git a/compiler/rustc_const_eval/src/interpret/machine.rs b/compiler/rustc_const_eval/src/interpret/machine.rs index 6a03b699d47..23ec3875cbc 100644 --- a/compiler/rustc_const_eval/src/interpret/machine.rs +++ b/compiler/rustc_const_eval/src/interpret/machine.rs @@ -212,12 +212,6 @@ pub trait Machine<'mir, 'tcx>: Sized { right: &ImmTy<'tcx, Self::PointerTag>, ) -> InterpResult<'tcx, (Scalar<Self::PointerTag>, bool, Ty<'tcx>)>; - /// Heap allocations via the `box` keyword. - fn box_alloc( - ecx: &mut InterpCx<'mir, 'tcx, Self>, - dest: &PlaceTy<'tcx, Self::PointerTag>, - ) -> InterpResult<'tcx>; - /// Called to read the specified `local` from the `frame`. /// Since reading a ZST is not actually accessing memory or locals, this is never invoked /// for ZST reads. diff --git a/compiler/rustc_const_eval/src/interpret/step.rs b/compiler/rustc_const_eval/src/interpret/step.rs index 6e37aae0f5e..3daa1d3c2b3 100644 --- a/compiler/rustc_const_eval/src/interpret/step.rs +++ b/compiler/rustc_const_eval/src/interpret/step.rs @@ -271,10 +271,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { self.write_immediate(place.to_ref(self), &dest)?; } - NullaryOp(mir::NullOp::Box, _) => { - M::box_alloc(self, &dest)?; - } - NullaryOp(null_op, ty) => { let ty = self.subst_from_current_frame_and_normalize_erasing_regions(ty)?; let layout = self.layout_of(ty)?; @@ -289,7 +285,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let val = match null_op { mir::NullOp::SizeOf => layout.size.bytes(), mir::NullOp::AlignOf => layout.align.abi.bytes(), - mir::NullOp::Box => unreachable!(), }; self.write_scalar(Scalar::from_machine_usize(val, self), &dest)?; } diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs index 6be3e19a833..5a398c2f45a 100644 --- a/compiler/rustc_const_eval/src/interpret/validity.rs +++ b/compiler/rustc_const_eval/src/interpret/validity.rs @@ -14,6 +14,7 @@ use rustc_middle::mir::interpret::InterpError; use rustc_middle::ty; use rustc_middle::ty::layout::{LayoutOf, TyAndLayout}; use rustc_span::symbol::{sym, Symbol}; +use rustc_span::DUMMY_SP; use rustc_target::abi::{Abi, Scalar as ScalarAbi, Size, VariantIdx, Variants, WrappingRange}; use std::hash::Hash; @@ -736,9 +737,15 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> #[inline(always)] fn visit_union( &mut self, - _op: &OpTy<'tcx, M::PointerTag>, + op: &OpTy<'tcx, M::PointerTag>, _fields: NonZeroUsize, ) -> InterpResult<'tcx> { + // Special check preventing `UnsafeCell` inside unions in the inner part of constants. + if matches!(self.ctfe_mode, Some(CtfeValidationMode::Const { inner: true, .. })) { + if !op.layout.ty.is_freeze(self.ecx.tcx.at(DUMMY_SP), self.ecx.param_env) { + throw_validation_failure!(self.path, { "`UnsafeCell` in a `const`" }); + } + } Ok(()) } diff --git a/compiler/rustc_const_eval/src/transform/check_consts/check.rs b/compiler/rustc_const_eval/src/transform/check_consts/check.rs index 1d5f4630152..dd749c03934 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs @@ -632,7 +632,6 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { } Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf, _) => {} - Rvalue::NullaryOp(NullOp::Box, _) => self.check_op(ops::HeapAllocation), Rvalue::ShallowInitBox(_, _) => {} Rvalue::UnaryOp(_, ref operand) => { diff --git a/compiler/rustc_const_eval/src/transform/promote_consts.rs b/compiler/rustc_const_eval/src/transform/promote_consts.rs index 1537de993d1..55fba5d7ddf 100644 --- a/compiler/rustc_const_eval/src/transform/promote_consts.rs +++ b/compiler/rustc_const_eval/src/transform/promote_consts.rs @@ -508,7 +508,6 @@ impl<'tcx> Validator<'_, 'tcx> { } Rvalue::NullaryOp(op, _) => match op { - NullOp::Box => return Err(Unpromotable), NullOp::SizeOf => {} NullOp::AlignOf => {} }, diff --git a/compiler/rustc_data_structures/src/sip128.rs b/compiler/rustc_data_structures/src/sip128.rs index 53062b9c20d..872b0eb7854 100644 --- a/compiler/rustc_data_structures/src/sip128.rs +++ b/compiler/rustc_data_structures/src/sip128.rs @@ -409,6 +409,20 @@ impl SipHasher128 { } } +macro_rules! dispatch_value { + ($target: expr, $value:expr) => { + let value = $value; + #[allow(unreachable_patterns)] + #[allow(overflowing_literals)] + match value { + 0..=0xFF => $target.short_write(value as u8), + 0x100..=0xFFFF => $target.short_write(value as u16), + 0x10000..=0xFFFFFFFF => $target.short_write(value as u32), + _ => $target.short_write(value as u64), + } + }; +} + impl Hasher for SipHasher128 { #[inline] fn write_u8(&mut self, i: u8) { @@ -422,7 +436,7 @@ impl Hasher for SipHasher128 { #[inline] fn write_u32(&mut self, i: u32) { - self.short_write(i); + dispatch_value!(self, i); } #[inline] @@ -452,7 +466,7 @@ impl Hasher for SipHasher128 { #[inline] fn write_i64(&mut self, i: i64) { - self.short_write(i as u64); + dispatch_value!(self, i as u64); } #[inline] diff --git a/compiler/rustc_data_structures/src/thin_vec.rs b/compiler/rustc_data_structures/src/thin_vec.rs index b5d2d24736c..716259142d1 100644 --- a/compiler/rustc_data_structures/src/thin_vec.rs +++ b/compiler/rustc_data_structures/src/thin_vec.rs @@ -5,7 +5,7 @@ use std::iter::FromIterator; /// A vector type optimized for cases where this size is usually 0 (cf. `SmallVec`). /// The `Option<Box<..>>` wrapping allows us to represent a zero sized vector with `None`, /// which uses only a single (null) pointer. -#[derive(Clone, Encodable, Decodable, Debug)] +#[derive(Clone, Encodable, Decodable, Debug, Hash, Eq, PartialEq)] pub struct ThinVec<T>(Option<Box<Vec<T>>>); impl<T> ThinVec<T> { @@ -20,6 +20,13 @@ impl<T> ThinVec<T> { pub fn iter_mut(&mut self) -> std::slice::IterMut<'_, T> { self.into_iter() } + + pub fn push(&mut self, item: T) { + match *self { + ThinVec(Some(ref mut vec)) => vec.push(item), + ThinVec(None) => *self = vec![item].into(), + } + } } impl<T> From<Vec<T>> for ThinVec<T> { @@ -101,10 +108,7 @@ impl<T> Extend<T> for ThinVec<T> { } fn extend_one(&mut self, item: T) { - match *self { - ThinVec(Some(ref mut vec)) => vec.push(item), - ThinVec(None) => *self = vec![item].into(), - } + self.push(item) } fn extend_reserve(&mut self, additional: usize) { diff --git a/compiler/rustc_driver/Cargo.toml b/compiler/rustc_driver/Cargo.toml index 2383a000687..872f946bf7d 100644 --- a/compiler/rustc_driver/Cargo.toml +++ b/compiler/rustc_driver/Cargo.toml @@ -8,10 +8,8 @@ crate-type = ["dylib"] [dependencies] libc = "0.2" -atty = "0.2" tracing = { version = "0.1.28" } -tracing-subscriber = { version = "0.3.3", default-features = false, features = ["fmt", "env-filter", "smallvec", "parking_lot", "ansi"] } -tracing-tree = "0.2.0" +rustc_log = { path = "../rustc_log" } rustc_middle = { path = "../rustc_middle" } rustc_ast_pretty = { path = "../rustc_ast_pretty" } rustc_target = { path = "../rustc_target" } @@ -40,4 +38,4 @@ winapi = { version = "0.3", features = ["consoleapi", "debugapi", "processenv"] [features] llvm = ['rustc_interface/llvm'] -max_level_info = ['tracing/max_level_info'] +max_level_info = ['rustc_log/max_level_info'] diff --git a/compiler/rustc_driver/src/lib.rs b/compiler/rustc_driver/src/lib.rs index 12e0b7a4977..3d58b27f839 100644 --- a/compiler/rustc_driver/src/lib.rs +++ b/compiler/rustc_driver/src/lib.rs @@ -24,6 +24,7 @@ use rustc_feature::find_gated_cfg; use rustc_interface::util::{self, collect_crate_types, get_codegen_backend}; use rustc_interface::{interface, Queries}; use rustc_lint::LintStore; +use rustc_log::stdout_isatty; use rustc_metadata::locator; use rustc_save_analysis as save; use rustc_save_analysis::DumpHandler; @@ -514,14 +515,6 @@ impl Compilation { #[derive(Copy, Clone)] pub struct RustcDefaultCalls; -fn stdout_isatty() -> bool { - atty::is(atty::Stream::Stdout) -} - -fn stderr_isatty() -> bool { - atty::is(atty::Stream::Stderr) -} - fn handle_explain(registry: Registry, code: &str, output: ErrorOutputType) { let upper_cased_code = code.to_ascii_uppercase(); let normalised = if upper_cased_code.starts_with('E') { @@ -1254,54 +1247,18 @@ pub fn install_ice_hook() { /// This allows tools to enable rust logging without having to magically match rustc's /// tracing crate version. pub fn init_rustc_env_logger() { - init_env_logger("RUSTC_LOG") + if let Err(error) = rustc_log::init_rustc_env_logger() { + early_error(ErrorOutputType::default(), &error.to_string()); + } } /// This allows tools to enable rust logging without having to magically match rustc's /// tracing crate version. In contrast to `init_rustc_env_logger` it allows you to choose an env var /// other than `RUSTC_LOG`. pub fn init_env_logger(env: &str) { - use tracing_subscriber::{ - filter::{self, EnvFilter, LevelFilter}, - layer::SubscriberExt, - }; - - let filter = match std::env::var(env) { - Ok(env) => EnvFilter::new(env), - _ => EnvFilter::default().add_directive(filter::Directive::from(LevelFilter::WARN)), - }; - - let color_logs = match std::env::var(String::from(env) + "_COLOR") { - Ok(value) => match value.as_ref() { - "always" => true, - "never" => false, - "auto" => stderr_isatty(), - _ => early_error( - ErrorOutputType::default(), - &format!( - "invalid log color value '{}': expected one of always, never, or auto", - value - ), - ), - }, - Err(std::env::VarError::NotPresent) => stderr_isatty(), - Err(std::env::VarError::NotUnicode(_value)) => early_error( - ErrorOutputType::default(), - "non-Unicode log color value: expected one of always, never, or auto", - ), - }; - - let layer = tracing_tree::HierarchicalLayer::default() - .with_writer(io::stderr) - .with_indent_lines(true) - .with_ansi(color_logs) - .with_targets(true) - .with_indent_amount(2); - #[cfg(parallel_compiler)] - let layer = layer.with_thread_ids(true).with_thread_names(true); - - let subscriber = tracing_subscriber::Registry::default().with(filter).with(layer); - tracing::subscriber::set_global_default(subscriber).unwrap(); + if let Err(error) = rustc_log::init_env_logger(env) { + early_error(ErrorOutputType::default(), &error.to_string()); + } } #[cfg(all(unix, any(target_env = "gnu", target_os = "macos")))] diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index ba675daac41..7f49f80a843 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -377,6 +377,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { dir_path, }); let krate = self.fully_expand_fragment(AstFragment::Crate(krate)).make_crate(); + assert_eq!(krate.id, ast::CRATE_NODE_ID); self.cx.trace_macros_diag(); krate } @@ -1160,13 +1161,19 @@ macro_rules! assign_id { impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { fn visit_crate(&mut self, krate: &mut ast::Crate) { - let span = krate.span; - let empty_crate = - || ast::Crate { attrs: Vec::new(), items: Vec::new(), span, is_placeholder: None }; - let mut fold_crate = |krate: ast::Crate| { + visit_clobber(krate, |krate| { + let span = krate.span; let mut krate = match self.configure(krate) { Some(krate) => krate, - None => return empty_crate(), + None => { + return ast::Crate { + attrs: Vec::new(), + items: Vec::new(), + span, + id: self.cx.resolver.next_node_id(), + is_placeholder: false, + }; + } }; if let Some(attr) = self.take_first_attr(&mut krate) { @@ -1175,12 +1182,9 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { .make_crate(); } - noop_visit_crate(&mut krate, self); + assign_id!(self, &mut krate.id, || noop_visit_crate(&mut krate, self)); krate - }; - - // Cannot use `visit_clobber` here, see the FIXME on it. - *krate = fold_crate(mem::replace(krate, empty_crate())); + }) } fn visit_expr(&mut self, expr: &mut P<ast::Expr>) { diff --git a/compiler/rustc_expand/src/placeholders.rs b/compiler/rustc_expand/src/placeholders.rs index 25b3a5820e6..825af9a7b2b 100644 --- a/compiler/rustc_expand/src/placeholders.rs +++ b/compiler/rustc_expand/src/placeholders.rs @@ -50,7 +50,8 @@ pub fn placeholder( attrs: Default::default(), items: Default::default(), span, - is_placeholder: Some(id), + id, + is_placeholder: true, }), AstFragmentKind::Expr => AstFragment::Expr(expr_placeholder()), AstFragmentKind::OptExpr => AstFragment::OptExpr(Some(expr_placeholder())), @@ -362,8 +363,8 @@ impl MutVisitor for PlaceholderExpander { } fn visit_crate(&mut self, krate: &mut ast::Crate) { - if let Some(id) = krate.is_placeholder { - *krate = self.remove(id).make_crate(); + if krate.is_placeholder { + *krate = self.remove(krate.id).make_crate(); } else { noop_visit_crate(krate, self) } diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 69572807e7c..d59756239d9 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1407,6 +1407,20 @@ impl fmt::Display for ConstContext { /// A literal. pub type Lit = Spanned<LitKind>; +#[derive(Copy, Clone, PartialEq, Eq, Encodable, Debug, HashStable_Generic)] +pub enum ArrayLen { + Infer(HirId, Span), + Body(AnonConst), +} + +impl ArrayLen { + pub fn hir_id(&self) -> HirId { + match self { + &ArrayLen::Infer(hir_id, _) | &ArrayLen::Body(AnonConst { hir_id, body: _ }) => hir_id, + } + } +} + /// A constant (expression) that's not an item or associated item, /// but needs its own `DefId` for type-checking, const-eval, etc. /// These are usually found nested inside types (e.g., array lengths) @@ -1756,7 +1770,7 @@ pub enum ExprKind<'hir> { /// /// E.g., `[1; 5]`. The first expression is the element /// to be repeated; the second is the number of times to repeat it. - Repeat(&'hir Expr<'hir>, AnonConst), + Repeat(&'hir Expr<'hir>, ArrayLen), /// A suspension point for generators (i.e., `yield <expr>`). Yield(&'hir Expr<'hir>, YieldSource), @@ -2266,7 +2280,7 @@ pub enum TyKind<'hir> { /// A variable length slice (i.e., `[T]`). Slice(&'hir Ty<'hir>), /// A fixed length array (i.e., `[T; n]`). - Array(&'hir Ty<'hir>, AnonConst), + Array(&'hir Ty<'hir>, ArrayLen), /// A raw pointer (i.e., `*const T` or `*mut T`). Ptr(MutTy<'hir>), /// A reference (i.e., `&'a T` or `&'a mut T`). @@ -2484,7 +2498,7 @@ impl FnRetTy<'_> { } } -#[derive(Encodable, Debug)] +#[derive(Encodable, Debug, HashStable_Generic)] pub struct Mod<'hir> { /// A span from the first token past `{` to the last token until `}`. /// For `mod foo;`, the inner span ranges from the first token diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 0fab7cbfeea..d0eee422202 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -383,6 +383,9 @@ pub trait Visitor<'v>: Sized { fn visit_pat(&mut self, p: &'v Pat<'v>) { walk_pat(self, p) } + fn visit_array_length(&mut self, len: &'v ArrayLen) { + walk_array_len(self, len) + } fn visit_anon_const(&mut self, c: &'v AnonConst) { walk_anon_const(self, c) } @@ -753,7 +756,7 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty<'v>) { } TyKind::Array(ref ty, ref length) => { visitor.visit_ty(ty); - visitor.visit_anon_const(length) + visitor.visit_array_length(length) } TyKind::TraitObject(bounds, ref lifetime, _syntax) => { for bound in bounds { @@ -1124,6 +1127,13 @@ pub fn walk_stmt<'v, V: Visitor<'v>>(visitor: &mut V, statement: &'v Stmt<'v>) { } } +pub fn walk_array_len<'v, V: Visitor<'v>>(visitor: &mut V, len: &'v ArrayLen) { + match len { + &ArrayLen::Infer(hir_id, _span) => visitor.visit_id(hir_id), + ArrayLen::Body(c) => visitor.visit_anon_const(c), + } +} + pub fn walk_anon_const<'v, V: Visitor<'v>>(visitor: &mut V, constant: &'v AnonConst) { visitor.visit_id(constant.hir_id); visitor.visit_nested_body(constant.body); @@ -1147,7 +1157,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>) ExprKind::ConstBlock(ref anon_const) => visitor.visit_anon_const(anon_const), ExprKind::Repeat(ref element, ref count) => { visitor.visit_expr(element); - visitor.visit_anon_const(count) + visitor.visit_array_length(count) } ExprKind::Struct(ref qpath, fields, ref optional_base) => { visitor.visit_qpath(qpath, expression.hir_id, expression.span); diff --git a/compiler/rustc_hir/src/stable_hash_impls.rs b/compiler/rustc_hir/src/stable_hash_impls.rs index c8d729a999e..a43c1f9d9ae 100644 --- a/compiler/rustc_hir/src/stable_hash_impls.rs +++ b/compiler/rustc_hir/src/stable_hash_impls.rs @@ -2,7 +2,7 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHas use crate::hir::{ AttributeMap, BodyId, Crate, Expr, ForeignItem, ForeignItemId, ImplItem, ImplItemId, Item, - ItemId, Mod, OwnerNodes, TraitCandidate, TraitItem, TraitItemId, Ty, VisibilityKind, + ItemId, OwnerNodes, TraitCandidate, TraitItem, TraitItemId, Ty, VisibilityKind, }; use crate::hir_id::{HirId, ItemLocalId}; use rustc_span::def_id::DefPathHash; @@ -16,7 +16,6 @@ pub trait HashStableContext: fn hash_hir_id(&mut self, _: HirId, hasher: &mut StableHasher); fn hash_body_id(&mut self, _: BodyId, hasher: &mut StableHasher); fn hash_reference_to_item(&mut self, _: HirId, hasher: &mut StableHasher); - fn hash_hir_mod(&mut self, _: &Mod<'_>, hasher: &mut StableHasher); fn hash_hir_expr(&mut self, _: &Expr<'_>, hasher: &mut StableHasher); fn hash_hir_ty(&mut self, _: &Ty<'_>, hasher: &mut StableHasher); fn hash_hir_visibility_kind(&mut self, _: &VisibilityKind<'_>, hasher: &mut StableHasher); @@ -132,12 +131,6 @@ impl<HirCtx: crate::HashStableContext> HashStable<HirCtx> for TraitItemId { } } -impl<HirCtx: crate::HashStableContext> HashStable<HirCtx> for Mod<'_> { - fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) { - hcx.hash_hir_mod(self, hasher) - } -} - impl<HirCtx: crate::HashStableContext> HashStable<HirCtx> for Expr<'_> { fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) { hcx.hash_hir_expr(self, hasher) diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 334fa6f4e5c..4c9e2d7fe42 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -358,7 +358,7 @@ impl<'a> State<'a> { self.word("["); self.print_type(&ty); self.word("; "); - self.print_anon_const(length); + self.print_array_length(length); self.word("]"); } hir::TyKind::Typeof(ref e) => { @@ -1065,6 +1065,13 @@ impl<'a> State<'a> { self.print_else(elseopt) } + pub fn print_array_length(&mut self, len: &hir::ArrayLen) { + match len { + hir::ArrayLen::Infer(_, _) => self.word("_"), + hir::ArrayLen::Body(ct) => self.print_anon_const(ct), + } + } + pub fn print_anon_const(&mut self, constant: &hir::AnonConst) { self.ann.nested(self, Nested::Body(constant.body)) } @@ -1140,12 +1147,12 @@ impl<'a> State<'a> { self.end() } - fn print_expr_repeat(&mut self, element: &hir::Expr<'_>, count: &hir::AnonConst) { + fn print_expr_repeat(&mut self, element: &hir::Expr<'_>, count: &hir::ArrayLen) { self.ibox(INDENT_UNIT); self.word("["); self.print_expr(element); self.word_space(";"); - self.print_anon_const(count); + self.print_array_length(count); self.word("]"); self.end() } @@ -1874,7 +1881,11 @@ impl<'a> State<'a> { PatKind::Struct(ref qpath, ref fields, etc) => { self.print_qpath(qpath, true); self.nbsp(); - self.word_space("{"); + self.word("{"); + let empty = fields.is_empty() && !etc; + if !empty { + self.space(); + } self.commasep_cmnt( Consistent, &fields, @@ -1895,7 +1906,9 @@ impl<'a> State<'a> { } self.word(".."); } - self.space(); + if !empty { + self.space(); + } self.word("}"); } PatKind::Or(ref pats) => { @@ -1948,7 +1961,6 @@ impl<'a> State<'a> { PatKind::Range(ref begin, ref end, ref end_kind) => { if let Some(expr) = begin { self.print_expr(expr); - self.space(); } match *end_kind { RangeEnd::Included => self.word("..."), diff --git a/compiler/rustc_incremental/src/persist/dirty_clean.rs b/compiler/rustc_incremental/src/persist/dirty_clean.rs index 7ac00b4609a..88795679943 100644 --- a/compiler/rustc_incremental/src/persist/dirty_clean.rs +++ b/compiler/rustc_incremental/src/persist/dirty_clean.rs @@ -9,6 +9,13 @@ //! - `#[rustc_clean(cfg="rev2")]` same as above, except that the //! fingerprints must be the SAME (along with all other fingerprints). //! +//! - `#[rustc_clean(cfg="rev2", loaded_from_disk='typeck")]` asserts that +//! the query result for `DepNode::typeck(X)` was actually +//! loaded from disk (not just marked green). This can be useful +//! to ensure that a test is actually exercising the deserialization +//! logic for a particular query result. This can be combined with +//! `except` +//! //! Errors are reported if we are in the suitable configuration but //! the required condition is not met. @@ -28,6 +35,7 @@ use rustc_span::Span; use std::iter::FromIterator; use std::vec::Vec; +const LOADED_FROM_DISK: Symbol = sym::loaded_from_disk; const EXCEPT: Symbol = sym::except; const CFG: Symbol = sym::cfg; @@ -124,6 +132,7 @@ type Labels = FxHashSet<String>; struct Assertion { clean: Labels, dirty: Labels, + loaded_from_disk: Labels, } pub fn check_dirty_clean_annotations(tcx: TyCtxt<'_>) { @@ -174,6 +183,7 @@ impl<'tcx> DirtyCleanVisitor<'tcx> { fn assertion_auto(&mut self, item_id: LocalDefId, attr: &Attribute) -> Assertion { let (name, mut auto) = self.auto_labels(item_id, attr); let except = self.except(attr); + let loaded_from_disk = self.loaded_from_disk(attr); for e in except.iter() { if !auto.remove(e) { let msg = format!( @@ -183,7 +193,19 @@ impl<'tcx> DirtyCleanVisitor<'tcx> { self.tcx.sess.span_fatal(attr.span, &msg); } } - Assertion { clean: auto, dirty: except } + Assertion { clean: auto, dirty: except, loaded_from_disk } + } + + /// `loaded_from_disk=` attribute value + fn loaded_from_disk(&self, attr: &Attribute) -> Labels { + for item in attr.meta_item_list().unwrap_or_else(Vec::new) { + if item.has_name(LOADED_FROM_DISK) { + let value = expect_associated_value(self.tcx, &item); + return self.resolve_labels(&item, value); + } + } + // If `loaded_from_disk=` is not specified, don't assert anything + Labels::default() } /// `except=` attribute value @@ -332,6 +354,18 @@ impl<'tcx> DirtyCleanVisitor<'tcx> { } } + fn assert_loaded_from_disk(&self, item_span: Span, dep_node: DepNode) { + debug!("assert_loaded_from_disk({:?})", dep_node); + + if !self.tcx.dep_graph.debug_was_loaded_from_disk(dep_node) { + let dep_node_str = self.dep_node_str(&dep_node); + self.tcx.sess.span_err( + item_span, + &format!("`{}` should have been loaded from disk but it was not", dep_node_str), + ); + } + } + fn check_item(&mut self, item_id: LocalDefId, item_span: Span) { let def_path_hash = self.tcx.def_path_hash(item_id.to_def_id()); for attr in self.tcx.get_attrs(item_id.to_def_id()).iter() { @@ -348,6 +382,10 @@ impl<'tcx> DirtyCleanVisitor<'tcx> { let dep_node = DepNode::from_label_string(self.tcx, &label, def_path_hash).unwrap(); self.assert_dirty(item_span, dep_node); } + for label in assertion.loaded_from_disk { + let dep_node = DepNode::from_label_string(self.tcx, &label, def_path_hash).unwrap(); + self.assert_loaded_from_disk(item_span, dep_node); + } } } } @@ -382,7 +420,7 @@ fn check_config(tcx: TyCtxt<'_>, attr: &Attribute) -> bool { let value = expect_associated_value(tcx, &item); debug!("check_config: searching for cfg {:?}", value); cfg = Some(config.contains(&(value, None))); - } else if !item.has_name(EXCEPT) { + } else if !(item.has_name(EXCEPT) || item.has_name(LOADED_FROM_DISK)) { tcx.sess.span_err(attr.span, &format!("unknown item `{}`", item.name_or_empty())); } } diff --git a/compiler/rustc_index/Cargo.toml b/compiler/rustc_index/Cargo.toml index b984a1321e0..89419bfce6f 100644 --- a/compiler/rustc_index/Cargo.toml +++ b/compiler/rustc_index/Cargo.toml @@ -10,3 +10,4 @@ doctest = false arrayvec = { version = "0.7", default-features = false } rustc_serialize = { path = "../rustc_serialize" } rustc_macros = { path = "../rustc_macros" } +smallvec = "1" diff --git a/compiler/rustc_index/src/interval.rs b/compiler/rustc_index/src/interval.rs new file mode 100644 index 00000000000..6da95053b11 --- /dev/null +++ b/compiler/rustc_index/src/interval.rs @@ -0,0 +1,269 @@ +use std::iter::Step; +use std::marker::PhantomData; +use std::ops::Bound; +use std::ops::RangeBounds; + +use crate::vec::Idx; +use crate::vec::IndexVec; +use smallvec::SmallVec; + +#[cfg(test)] +mod tests; + +/// Stores a set of intervals on the indices. +#[derive(Debug, Clone)] +pub struct IntervalSet<I> { + // Start, end + map: SmallVec<[(u32, u32); 4]>, + domain: usize, + _data: PhantomData<I>, +} + +#[inline] +fn inclusive_start<T: Idx>(range: impl RangeBounds<T>) -> u32 { + match range.start_bound() { + Bound::Included(start) => start.index() as u32, + Bound::Excluded(start) => start.index() as u32 + 1, + Bound::Unbounded => 0, + } +} + +#[inline] +fn inclusive_end<T: Idx>(domain: usize, range: impl RangeBounds<T>) -> Option<u32> { + let end = match range.end_bound() { + Bound::Included(end) => end.index() as u32, + Bound::Excluded(end) => end.index().checked_sub(1)? as u32, + Bound::Unbounded => domain.checked_sub(1)? as u32, + }; + Some(end) +} + +impl<I: Idx> IntervalSet<I> { + pub fn new(domain: usize) -> IntervalSet<I> { + IntervalSet { map: SmallVec::new(), domain, _data: PhantomData } + } + + pub fn clear(&mut self) { + self.map.clear(); + } + + pub fn iter(&self) -> impl Iterator<Item = I> + '_ + where + I: Step, + { + self.iter_intervals().flatten() + } + + /// Iterates through intervals stored in the set, in order. + pub fn iter_intervals(&self) -> impl Iterator<Item = std::ops::Range<I>> + '_ + where + I: Step, + { + self.map.iter().map(|&(start, end)| I::new(start as usize)..I::new(end as usize + 1)) + } + + /// Returns true if we increased the number of elements present. + pub fn insert(&mut self, point: I) -> bool { + self.insert_range(point..=point) + } + + /// Returns true if we increased the number of elements present. + pub fn insert_range(&mut self, range: impl RangeBounds<I> + Clone) -> bool { + let start = inclusive_start(range.clone()); + let Some(mut end) = inclusive_end(self.domain, range) else { + // empty range + return false; + }; + if start > end { + return false; + } + + loop { + // This condition looks a bit weird, but actually makes sense. + // + // if r.0 == end + 1, then we're actually adjacent, so we want to + // continue to the next range. We're looking here for the first + // range which starts *non-adjacently* to our end. + let next = self.map.partition_point(|r| r.0 <= end + 1); + if let Some(last) = next.checked_sub(1) { + let (prev_start, prev_end) = &mut self.map[last]; + if *prev_end + 1 >= start { + // If the start for the inserted range is adjacent to the + // end of the previous, we can extend the previous range. + if start < *prev_start { + // Our range starts before the one we found. We'll need + // to *remove* it, and then try again. + // + // FIXME: This is not so efficient; we may need to + // recurse a bunch of times here. Instead, it's probably + // better to do something like drain_filter(...) on the + // map to be able to delete or modify all the ranges in + // start..=end and then potentially re-insert a new + // range. + end = std::cmp::max(end, *prev_end); + self.map.remove(last); + } else { + // We overlap with the previous range, increase it to + // include us. + // + // Make sure we're actually going to *increase* it though -- + // it may be that end is just inside the previously existing + // set. + return if end > *prev_end { + *prev_end = end; + true + } else { + false + }; + } + } else { + // Otherwise, we don't overlap, so just insert + self.map.insert(last + 1, (start, end)); + return true; + } + } else { + if self.map.is_empty() { + // Quite common in practice, and expensive to call memcpy + // with length zero. + self.map.push((start, end)); + } else { + self.map.insert(next, (start, end)); + } + return true; + } + } + } + + pub fn contains(&self, needle: I) -> bool { + let needle = needle.index() as u32; + let last = match self.map.partition_point(|r| r.0 <= needle).checked_sub(1) { + Some(idx) => idx, + None => { + // All ranges in the map start after the new range's end + return false; + } + }; + let (_, prev_end) = &self.map[last]; + needle <= *prev_end + } + + pub fn superset(&self, other: &IntervalSet<I>) -> bool + where + I: Step, + { + // FIXME: Performance here is probably not great. We will be doing a lot + // of pointless tree traversals. + other.iter().all(|elem| self.contains(elem)) + } + + pub fn is_empty(&self) -> bool { + self.map.is_empty() + } + + /// Returns the maximum (last) element present in the set from `range`. + pub fn last_set_in(&self, range: impl RangeBounds<I> + Clone) -> Option<I> { + let start = inclusive_start(range.clone()); + let Some(end) = inclusive_end(self.domain, range) else { + // empty range + return None; + }; + if start > end { + return None; + } + let last = match self.map.partition_point(|r| r.0 <= end).checked_sub(1) { + Some(idx) => idx, + None => { + // All ranges in the map start after the new range's end + return None; + } + }; + let (_, prev_end) = &self.map[last]; + if start <= *prev_end { Some(I::new(std::cmp::min(*prev_end, end) as usize)) } else { None } + } + + pub fn insert_all(&mut self) { + self.clear(); + self.map.push((0, self.domain.try_into().unwrap())); + } + + pub fn union(&mut self, other: &IntervalSet<I>) -> bool + where + I: Step, + { + assert_eq!(self.domain, other.domain); + let mut did_insert = false; + for range in other.iter_intervals() { + did_insert |= self.insert_range(range); + } + did_insert + } +} + +/// This data structure optimizes for cases where the stored bits in each row +/// are expected to be highly contiguous (long ranges of 1s or 0s), in contrast +/// to BitMatrix and SparseBitMatrix which are optimized for +/// "random"/non-contiguous bits and cheap(er) point queries at the expense of +/// memory usage. +#[derive(Clone)] +pub struct SparseIntervalMatrix<R, C> +where + R: Idx, + C: Idx, +{ + rows: IndexVec<R, IntervalSet<C>>, + column_size: usize, +} + +impl<R: Idx, C: Step + Idx> SparseIntervalMatrix<R, C> { + pub fn new(column_size: usize) -> SparseIntervalMatrix<R, C> { + SparseIntervalMatrix { rows: IndexVec::new(), column_size } + } + + pub fn rows(&self) -> impl Iterator<Item = R> { + self.rows.indices() + } + + pub fn row(&self, row: R) -> Option<&IntervalSet<C>> { + self.rows.get(row) + } + + fn ensure_row(&mut self, row: R) -> &mut IntervalSet<C> { + self.rows.ensure_contains_elem(row, || IntervalSet::new(self.column_size)); + &mut self.rows[row] + } + + pub fn union_row(&mut self, row: R, from: &IntervalSet<C>) -> bool + where + C: Step, + { + self.ensure_row(row).union(from) + } + + pub fn union_rows(&mut self, read: R, write: R) -> bool + where + C: Step, + { + if read == write || self.rows.get(read).is_none() { + return false; + } + self.ensure_row(write); + let (read_row, write_row) = self.rows.pick2_mut(read, write); + write_row.union(read_row) + } + + pub fn insert_all_into_row(&mut self, row: R) { + self.ensure_row(row).insert_all(); + } + + pub fn insert_range(&mut self, row: R, range: impl RangeBounds<C> + Clone) { + self.ensure_row(row).insert_range(range); + } + + pub fn insert(&mut self, row: R, point: C) -> bool { + self.ensure_row(row).insert(point) + } + + pub fn contains(&self, row: R, point: C) -> bool { + self.row(row).map_or(false, |r| r.contains(point)) + } +} diff --git a/compiler/rustc_index/src/interval/tests.rs b/compiler/rustc_index/src/interval/tests.rs new file mode 100644 index 00000000000..d90b449f326 --- /dev/null +++ b/compiler/rustc_index/src/interval/tests.rs @@ -0,0 +1,199 @@ +use super::*; + +#[test] +fn insert_collapses() { + let mut set = IntervalSet::<u32>::new(3000); + set.insert_range(9831..=9837); + set.insert_range(43..=9830); + assert_eq!(set.iter_intervals().collect::<Vec<_>>(), [43..9838]); +} + +#[test] +fn contains() { + let mut set = IntervalSet::new(300); + set.insert(0u32); + assert!(set.contains(0)); + set.insert_range(0..10); + assert!(set.contains(9)); + assert!(!set.contains(10)); + set.insert_range(10..11); + assert!(set.contains(10)); +} + +#[test] +fn insert() { + for i in 0..30usize { + let mut set = IntervalSet::new(300); + for j in i..30usize { + set.insert(j); + for k in i..j { + assert!(set.contains(k)); + } + } + } + + let mut set = IntervalSet::new(300); + set.insert_range(0..1u32); + assert!(set.contains(0), "{:?}", set.map); + assert!(!set.contains(1)); + set.insert_range(1..1); + assert!(set.contains(0)); + assert!(!set.contains(1)); + + let mut set = IntervalSet::new(300); + set.insert_range(4..5u32); + set.insert_range(5..10); + assert_eq!(set.iter().collect::<Vec<_>>(), [4, 5, 6, 7, 8, 9]); + set.insert_range(3..7); + assert_eq!(set.iter().collect::<Vec<_>>(), [3, 4, 5, 6, 7, 8, 9]); + + let mut set = IntervalSet::new(300); + set.insert_range(0..10u32); + set.insert_range(3..5); + assert_eq!(set.iter().collect::<Vec<_>>(), [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]); + + let mut set = IntervalSet::new(300); + set.insert_range(0..10u32); + set.insert_range(0..3); + assert_eq!(set.iter().collect::<Vec<_>>(), [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]); + + let mut set = IntervalSet::new(300); + set.insert_range(0..10u32); + set.insert_range(0..10); + assert_eq!(set.iter().collect::<Vec<_>>(), [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]); + + let mut set = IntervalSet::new(300); + set.insert_range(0..10u32); + set.insert_range(5..10); + assert_eq!(set.iter().collect::<Vec<_>>(), [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]); + + let mut set = IntervalSet::new(300); + set.insert_range(0..10u32); + set.insert_range(5..13); + assert_eq!(set.iter().collect::<Vec<_>>(), [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]); +} + +#[test] +fn insert_range() { + #[track_caller] + fn check<R>(range: R) + where + R: RangeBounds<usize> + Clone + IntoIterator<Item = usize> + std::fmt::Debug, + { + let mut set = IntervalSet::new(300); + set.insert_range(range.clone()); + for i in set.iter() { + assert!(range.contains(&i)); + } + for i in range.clone() { + assert!(set.contains(i), "A: {} in {:?}, inserted {:?}", i, set, range); + } + set.insert_range(range.clone()); + for i in set.iter() { + assert!(range.contains(&i), "{} in {:?}", i, set); + } + for i in range.clone() { + assert!(set.contains(i), "B: {} in {:?}, inserted {:?}", i, set, range); + } + } + check(10..10); + check(10..100); + check(10..30); + check(0..5); + check(0..250); + check(200..250); + + check(10..=10); + check(10..=100); + check(10..=30); + check(0..=5); + check(0..=250); + check(200..=250); + + for i in 0..30 { + for j in i..30 { + check(i..j); + check(i..=j); + } + } +} + +#[test] +fn insert_range_dual() { + let mut set = IntervalSet::<u32>::new(300); + set.insert_range(0..3); + assert_eq!(set.iter().collect::<Vec<_>>(), [0, 1, 2]); + set.insert_range(5..7); + assert_eq!(set.iter().collect::<Vec<_>>(), [0, 1, 2, 5, 6]); + set.insert_range(3..4); + assert_eq!(set.iter().collect::<Vec<_>>(), [0, 1, 2, 3, 5, 6]); + set.insert_range(3..5); + assert_eq!(set.iter().collect::<Vec<_>>(), [0, 1, 2, 3, 4, 5, 6]); +} + +#[test] +fn last_set_before_adjacent() { + let mut set = IntervalSet::<u32>::new(300); + set.insert_range(0..3); + set.insert_range(3..5); + assert_eq!(set.last_set_in(0..3), Some(2)); + assert_eq!(set.last_set_in(0..5), Some(4)); + assert_eq!(set.last_set_in(3..5), Some(4)); + set.insert_range(2..5); + assert_eq!(set.last_set_in(0..3), Some(2)); + assert_eq!(set.last_set_in(0..5), Some(4)); + assert_eq!(set.last_set_in(3..5), Some(4)); +} + +#[test] +fn last_set_in() { + fn easy(set: &IntervalSet<usize>, needle: impl RangeBounds<usize>) -> Option<usize> { + let mut last_leq = None; + for e in set.iter() { + if needle.contains(&e) { + last_leq = Some(e); + } + } + last_leq + } + + #[track_caller] + fn cmp(set: &IntervalSet<usize>, needle: impl RangeBounds<usize> + Clone + std::fmt::Debug) { + assert_eq!( + set.last_set_in(needle.clone()), + easy(set, needle.clone()), + "{:?} in {:?}", + needle, + set + ); + } + let mut set = IntervalSet::new(300); + cmp(&set, 50..=50); + set.insert(64); + cmp(&set, 64..=64); + set.insert(64 - 1); + cmp(&set, 0..=64 - 1); + cmp(&set, 0..=5); + cmp(&set, 10..100); + set.insert(100); + cmp(&set, 100..110); + cmp(&set, 99..100); + cmp(&set, 99..=100); + + for i in 0..=30 { + for j in i..=30 { + for k in 0..30 { + let mut set = IntervalSet::new(100); + cmp(&set, ..j); + cmp(&set, i..); + cmp(&set, i..j); + cmp(&set, i..=j); + set.insert(k); + cmp(&set, ..j); + cmp(&set, i..); + cmp(&set, i..j); + cmp(&set, i..=j); + } + } + } +} diff --git a/compiler/rustc_index/src/lib.rs b/compiler/rustc_index/src/lib.rs index a9efd6bb8bc..359b1859c68 100644 --- a/compiler/rustc_index/src/lib.rs +++ b/compiler/rustc_index/src/lib.rs @@ -7,6 +7,7 @@ #![feature(let_else)] pub mod bit_set; +pub mod interval; pub mod vec; // FIXME(#56935): Work around ICEs during cross-compilation. diff --git a/compiler/rustc_infer/src/infer/combine.rs b/compiler/rustc_infer/src/infer/combine.rs index 5e48fbf253d..da71edbd2d9 100644 --- a/compiler/rustc_infer/src/infer/combine.rs +++ b/compiler/rustc_infer/src/infer/combine.rs @@ -572,8 +572,9 @@ impl<'tcx> TypeRelation<'tcx> for Generalizer<'_, 'tcx> { // (e.g., #41849). relate::relate_substs(self, None, a_subst, b_subst) } else { - let opt_variances = self.tcx().variances_of(item_def_id); - relate::relate_substs(self, Some(&opt_variances), a_subst, b_subst) + let tcx = self.tcx(); + let opt_variances = tcx.variances_of(item_def_id); + relate::relate_substs(self, Some((item_def_id, &opt_variances)), a_subst, b_subst) } } diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 9a76c05e4f6..f0c73d0c2f3 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -2041,11 +2041,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { if let ValuePairs::Types(ty::error::ExpectedFound { expected, found }) = trace.values { - // If a tuple of length one was expected and the found expression has - // parentheses around it, perhaps the user meant to write `(expr,)` to - // build a tuple (issue #86100) match (expected.kind(), found.kind()) { (ty::Tuple(_), ty::Tuple(_)) => {} + // If a tuple of length one was expected and the found expression has + // parentheses around it, perhaps the user meant to write `(expr,)` to + // build a tuple (issue #86100) (ty::Tuple(_), _) if expected.tuple_fields().count() == 1 => { if let Ok(code) = self.tcx.sess().source_map().span_to_snippet(span) { if let Some(code) = @@ -2060,6 +2060,41 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } } } + // If a character was expected and the found expression is a string literal + // containing a single character, perhaps the user meant to write `'c'` to + // specify a character literal (issue #92479) + (ty::Char, ty::Ref(_, r, _)) if r.is_str() => { + if let Ok(code) = self.tcx.sess().source_map().span_to_snippet(span) { + if let Some(code) = + code.strip_prefix('"').and_then(|s| s.strip_suffix('"')) + { + if code.chars().nth(1).is_none() { + err.span_suggestion( + span, + "if you meant to write a `char` literal, use single quotes", + format!("'{}'", code), + Applicability::MachineApplicable, + ); + } + } + } + } + // If a string was expected and the found expression is a character literal, + // perhaps the user meant to write `"s"` to specify a string literal. + (ty::Ref(_, r, _), ty::Char) if r.is_str() => { + if let Ok(code) = self.tcx.sess().source_map().span_to_snippet(span) { + if let Some(code) = + code.strip_prefix('\'').and_then(|s| s.strip_suffix('\'')) + { + err.span_suggestion( + span, + "if you meant to write a `str` literal, use double quotes", + format!("\"{}\"", code), + Applicability::MachineApplicable, + ); + } + } + } _ => {} } } diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs index 2904b3f5b70..3804e100307 100644 --- a/compiler/rustc_interface/src/interface.rs +++ b/compiler/rustc_interface/src/interface.rs @@ -11,7 +11,7 @@ use rustc_errors::registry::Registry; use rustc_errors::{ErrorReported, Handler}; use rustc_lint::LintStore; use rustc_middle::ty; -use rustc_parse::new_parser_from_source_str; +use rustc_parse::maybe_new_parser_from_source_str; use rustc_query_impl::QueryCtxt; use rustc_session::config::{self, ErrorOutputType, Input, OutputFilenames}; use rustc_session::early_error; @@ -91,7 +91,6 @@ pub fn parse_cfgspecs(cfgspecs: Vec<String>) -> FxHashSet<(String, Option<String s ))); let filename = FileName::cfg_spec_source_code(&s); - let mut parser = new_parser_from_source_str(&sess, filename, s.to_string()); macro_rules! error { ($reason: expr) => { @@ -102,26 +101,27 @@ pub fn parse_cfgspecs(cfgspecs: Vec<String>) -> FxHashSet<(String, Option<String }; } - match &mut parser.parse_meta_item() { - Ok(meta_item) if parser.token == token::Eof => { - if meta_item.path.segments.len() != 1 { - error!("argument key must be an identifier"); - } - match &meta_item.kind { - MetaItemKind::List(..) => { - error!(r#"expected `key` or `key="value"`"#); - } - MetaItemKind::NameValue(lit) if !lit.kind.is_str() => { - error!("argument value must be a string"); + match maybe_new_parser_from_source_str(&sess, filename, s.to_string()) { + Ok(mut parser) => match &mut parser.parse_meta_item() { + Ok(meta_item) if parser.token == token::Eof => { + if meta_item.path.segments.len() != 1 { + error!("argument key must be an identifier"); } - MetaItemKind::NameValue(..) | MetaItemKind::Word => { - let ident = meta_item.ident().expect("multi-segment cfg key"); - return (ident.name, meta_item.value_str()); + match &meta_item.kind { + MetaItemKind::List(..) => {} + MetaItemKind::NameValue(lit) if !lit.kind.is_str() => { + error!("argument value must be a string"); + } + MetaItemKind::NameValue(..) | MetaItemKind::Word => { + let ident = meta_item.ident().expect("multi-segment cfg key"); + return (ident.name, meta_item.value_str()); + } } } - } - Ok(..) => {} - Err(err) => err.cancel(), + Ok(..) => {} + Err(err) => err.cancel(), + }, + Err(errs) => errs.into_iter().for_each(|mut err| err.cancel()), } error!(r#"expected `key` or `key="value"`"#); diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index d11cc52b508..33bf670f570 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -3,7 +3,7 @@ use crate::proc_macro_decls; use crate::util; use rustc_ast::mut_visit::MutVisitor; -use rustc_ast::{self as ast, visit}; +use rustc_ast::{self as ast, visit, DUMMY_NODE_ID}; use rustc_borrowck as mir_borrowck; use rustc_codegen_ssa::back::link::emit_metadata; use rustc_codegen_ssa::traits::CodegenBackend; @@ -323,7 +323,7 @@ pub fn configure_and_expand( let crate_attrs = krate.attrs.clone(); let extern_mod_loaded = |ident: Ident, attrs, items, span| { - let krate = ast::Crate { attrs, items, span, is_placeholder: None }; + let krate = ast::Crate { attrs, items, span, id: DUMMY_NODE_ID, is_placeholder: false }; pre_expansion_lint(sess, lint_store, &krate, &crate_attrs, ident.name.as_str()); (krate.attrs, krate.items) }; diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index c651feaaa66..816e770f012 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -8,10 +8,11 @@ use rustc_session::config::{build_configuration, build_session_options, to_crate use rustc_session::config::{ rustc_optgroups, ErrorOutputType, ExternLocation, LocationDetail, Options, Passes, }; -use rustc_session::config::{CFGuard, ExternEntry, LinkerPluginLto, LtoCli, SwitchWithOptPath}; use rustc_session::config::{ - Externs, OutputType, OutputTypes, SymbolManglingVersion, WasiExecModel, + BranchProtection, Externs, OutputType, OutputTypes, PAuthKey, PacRet, SymbolManglingVersion, + WasiExecModel, }; +use rustc_session::config::{CFGuard, ExternEntry, LinkerPluginLto, LtoCli, SwitchWithOptPath}; use rustc_session::lint::Level; use rustc_session::search_paths::SearchPath; use rustc_session::utils::{CanonicalizedPath, NativeLib, NativeLibKind}; @@ -593,6 +594,7 @@ fn test_codegen_options_tracking_hash() { tracked!(relocation_model, Some(RelocModel::Pic)); tracked!(soft_float, true); tracked!(split_debuginfo, Some(SplitDebuginfo::Packed)); + tracked!(symbol_mangling_version, Some(SymbolManglingVersion::V0)); tracked!(target_cpu, Some(String::from("abc"))); tracked!(target_feature, String::from("all the features, all of them")); } @@ -717,6 +719,10 @@ fn test_debugging_options_tracking_hash() { tracked!(asm_comments, true); tracked!(assume_incomplete_release, true); tracked!(binary_dep_depinfo, true); + tracked!( + branch_protection, + BranchProtection { bti: true, pac_ret: Some(PacRet { leaf: true, key: PAuthKey::B }) } + ); tracked!(chalk, true); tracked!(codegen_backend, Some("abc".to_string())); tracked!(crate_attr, vec!["abc".to_string()]); diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs index b04f91634cc..cb51555f5ca 100644 --- a/compiler/rustc_interface/src/util.rs +++ b/compiler/rustc_interface/src/util.rs @@ -484,7 +484,7 @@ pub(crate) fn check_attr_crate_type( return; } - if let ast::MetaItemKind::NameValue(spanned) = a.meta().unwrap().kind { + if let ast::MetaItemKind::NameValue(spanned) = a.meta_kind().unwrap() { let span = spanned.span; let lev_candidate = find_best_match_for_name( &CRATE_TYPES.iter().map(|(k, _)| *k).collect::<Vec<_>>(), diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp index 4f77db8a24d..f06fc3edf58 100644 --- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp @@ -17,6 +17,7 @@ #include "llvm/Object/ObjectFile.h" #include "llvm/Object/IRObjectFile.h" #include "llvm/Passes/PassBuilder.h" +#include "llvm/Passes/PassPlugin.h" #include "llvm/Passes/StandardInstrumentations.h" #include "llvm/Support/CBindingWrapping.h" #include "llvm/Support/FileSystem.h" @@ -753,7 +754,8 @@ LLVMRustOptimizeWithNewPassManager( void* LlvmSelfProfiler, LLVMRustSelfProfileBeforePassCallback BeforePassCallback, LLVMRustSelfProfileAfterPassCallback AfterPassCallback, - const char *ExtraPasses, size_t ExtraPassesLen) { + const char *ExtraPasses, size_t ExtraPassesLen, + const char *LLVMPlugins, size_t LLVMPluginsLen) { Module *TheModule = unwrap(ModuleRef); TargetMachine *TM = unwrap(TMRef); OptimizationLevel OptLevel = fromRust(OptLevelRust); @@ -924,6 +926,20 @@ LLVMRustOptimizeWithNewPassManager( } } + if (LLVMPluginsLen) { + auto PluginsStr = StringRef(LLVMPlugins, LLVMPluginsLen); + SmallVector<StringRef> Plugins; + PluginsStr.split(Plugins, ',', -1, false); + for (auto PluginPath: Plugins) { + auto Plugin = PassPlugin::Load(PluginPath.str()); + if (!Plugin) { + LLVMRustSetLastError(("Failed to load pass plugin" + PluginPath.str()).c_str()); + continue; + } + Plugin->registerPassBuilderCallbacks(PB); + } + } + #if LLVM_VERSION_GE(13, 0) ModulePassManager MPM; #else diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index 3fbf020c552..2a0f4fdc774 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -716,6 +716,14 @@ extern "C" uint32_t LLVMRustVersionMinor() { return LLVM_VERSION_MINOR; } extern "C" uint32_t LLVMRustVersionMajor() { return LLVM_VERSION_MAJOR; } +extern "C" bool LLVMRustIsRustLLVM() { +#ifdef LLVM_RUSTLLVM + return true; +#else + return false; +#endif +} + extern "C" void LLVMRustAddModuleFlag(LLVMModuleRef M, const char *Name, uint32_t Value) { unwrap(M)->addModuleFlag(Module::Warning, Name, Value); @@ -971,11 +979,11 @@ LLVMRustDIBuilderGetOrCreateArray(LLVMRustDIBuilderRef Builder, extern "C" LLVMValueRef LLVMRustDIBuilderInsertDeclareAtEnd( LLVMRustDIBuilderRef Builder, LLVMValueRef V, LLVMMetadataRef VarInfo, - int64_t *AddrOps, unsigned AddrOpsCount, LLVMMetadataRef DL, + uint64_t *AddrOps, unsigned AddrOpsCount, LLVMMetadataRef DL, LLVMBasicBlockRef InsertAtEnd) { return wrap(Builder->insertDeclare( unwrap(V), unwrap<DILocalVariable>(VarInfo), - Builder->createExpression(llvm::ArrayRef<int64_t>(AddrOps, AddrOpsCount)), + Builder->createExpression(llvm::ArrayRef<uint64_t>(AddrOps, AddrOpsCount)), DebugLoc(cast<MDNode>(unwrap(DL))), unwrap(InsertAtEnd))); } @@ -1049,11 +1057,11 @@ LLVMRustDIBuilderCreateDebugLocation(unsigned Line, unsigned Column, return wrap(Loc); } -extern "C" int64_t LLVMRustDIBuilderCreateOpDeref() { +extern "C" uint64_t LLVMRustDIBuilderCreateOpDeref() { return dwarf::DW_OP_deref; } -extern "C" int64_t LLVMRustDIBuilderCreateOpPlusUconst() { +extern "C" uint64_t LLVMRustDIBuilderCreateOpPlusUconst() { return dwarf::DW_OP_plus_uconst; } diff --git a/compiler/rustc_log/Cargo.toml b/compiler/rustc_log/Cargo.toml new file mode 100644 index 00000000000..1b2cde60555 --- /dev/null +++ b/compiler/rustc_log/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "rustc_log" +version = "0.0.0" +edition = "2021" + +[dependencies] +atty = "0.2" +tracing = "0.1.28" +tracing-subscriber = { version = "0.3.3", default-features = false, features = ["fmt", "env-filter", "smallvec", "parking_lot", "ansi"] } +tracing-tree = "0.2.0" + +[dev-dependencies] +rustc_span = { path = "../rustc_span" } + +[features] +max_level_info = ['tracing/max_level_info'] diff --git a/compiler/rustc_log/src/lib.rs b/compiler/rustc_log/src/lib.rs new file mode 100644 index 00000000000..f5e7435d36e --- /dev/null +++ b/compiler/rustc_log/src/lib.rs @@ -0,0 +1,115 @@ +//! This crate allows tools to enable rust logging without having to magically +//! match rustc's tracing crate version. +//! +//! For example if someone is working on rustc_ast and wants to write some +//! minimal code against it to run in a debugger, with access to the `debug!` +//! logs emitted by rustc_ast, that can be done by writing: +//! +//! ```toml +//! [dependencies] +//! rustc_ast = { path = "../rust/compiler/rustc_ast" } +//! rustc_log = { path = "../rust/compiler/rustc_log" } +//! rustc_span = { path = "../rust/compiler/rustc_span" } +//! ``` +//! +//! ``` +//! fn main() { +//! rustc_log::init_rustc_env_logger().unwrap(); +//! +//! let edition = rustc_span::edition::Edition::Edition2021; +//! rustc_span::create_session_globals_then(edition, || { +//! /* ... */ +//! }); +//! } +//! ``` +//! +//! Now `RUSTC_LOG=debug cargo run` will run your minimal main.rs and show +//! rustc's debug logging. In a workflow like this, one might also add +//! `std::env::set_var("RUSTC_LOG", "debug")` to the top of main so that `cargo +//! run` by itself is sufficient to get logs. +//! +//! The reason rustc_log is a tiny separate crate, as opposed to exposing the +//! same things in rustc_driver only, is to enable the above workflow. If you +//! had to depend on rustc_driver in order to turn on rustc's debug logs, that's +//! an enormously bigger dependency tree; every change you make to rustc_ast (or +//! whichever piece of the compiler you are interested in) would involve +//! rebuilding all the rest of rustc up to rustc_driver in order to run your +//! main.rs. Whereas by depending only on rustc_log and the few crates you are +//! debugging, you can make changes inside those crates and quickly run main.rs +//! to read the debug logs. + +use std::env::{self, VarError}; +use std::fmt::{self, Display}; +use std::io; +use tracing_subscriber::filter::{Directive, EnvFilter, LevelFilter}; +use tracing_subscriber::layer::SubscriberExt; + +pub fn init_rustc_env_logger() -> Result<(), Error> { + init_env_logger("RUSTC_LOG") +} + +/// In contrast to `init_rustc_env_logger` this allows you to choose an env var +/// other than `RUSTC_LOG`. +pub fn init_env_logger(env: &str) -> Result<(), Error> { + let filter = match env::var(env) { + Ok(env) => EnvFilter::new(env), + _ => EnvFilter::default().add_directive(Directive::from(LevelFilter::WARN)), + }; + + let color_logs = match env::var(String::from(env) + "_COLOR") { + Ok(value) => match value.as_ref() { + "always" => true, + "never" => false, + "auto" => stderr_isatty(), + _ => return Err(Error::InvalidColorValue(value)), + }, + Err(VarError::NotPresent) => stderr_isatty(), + Err(VarError::NotUnicode(_value)) => return Err(Error::NonUnicodeColorValue), + }; + + let layer = tracing_tree::HierarchicalLayer::default() + .with_writer(io::stderr) + .with_indent_lines(true) + .with_ansi(color_logs) + .with_targets(true) + .with_indent_amount(2); + #[cfg(parallel_compiler)] + let layer = layer.with_thread_ids(true).with_thread_names(true); + + let subscriber = tracing_subscriber::Registry::default().with(filter).with(layer); + tracing::subscriber::set_global_default(subscriber).unwrap(); + + Ok(()) +} + +pub fn stdout_isatty() -> bool { + atty::is(atty::Stream::Stdout) +} + +pub fn stderr_isatty() -> bool { + atty::is(atty::Stream::Stderr) +} + +#[derive(Debug)] +pub enum Error { + InvalidColorValue(String), + NonUnicodeColorValue, +} + +impl std::error::Error for Error {} + +impl Display for Error { + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Error::InvalidColorValue(value) => write!( + formatter, + "invalid log color value '{}': expected one of always, never, or auto", + value, + ), + Error::NonUnicodeColorValue => write!( + formatter, + "non-Unicode log color value: expected one of always, never, or auto", + ), + } + } +} diff --git a/compiler/rustc_macros/src/serialize.rs b/compiler/rustc_macros/src/serialize.rs index 66e6b571beb..3351564299c 100644 --- a/compiler/rustc_macros/src/serialize.rs +++ b/compiler/rustc_macros/src/serialize.rs @@ -1,6 +1,7 @@ use proc_macro2::TokenStream; -use quote::quote; +use quote::{quote, quote_spanned}; use syn::parse_quote; +use syn::spanned::Spanned; pub fn type_decodable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream { let decoder_ty = quote! { __D }; @@ -104,6 +105,8 @@ fn decodable_body( } fn decode_field(field: &syn::Field, index: usize, is_struct: bool) -> proc_macro2::TokenStream { + let field_span = field.ident.as_ref().map_or(field.ty.span(), |ident| ident.span()); + let decode_inner_method = if let syn::Type::Reference(_) = field.ty { quote! { ::rustc_middle::ty::codec::RefDecodable::decode } } else { @@ -111,20 +114,21 @@ fn decode_field(field: &syn::Field, index: usize, is_struct: bool) -> proc_macro }; let (decode_method, opt_field_name) = if is_struct { let field_name = field.ident.as_ref().map_or_else(|| index.to_string(), |i| i.to_string()); - ( - proc_macro2::Ident::new("read_struct_field", proc_macro2::Span::call_site()), - quote! { #field_name, }, - ) + (proc_macro2::Ident::new("read_struct_field", field_span), quote! { #field_name, }) } else { - ( - proc_macro2::Ident::new("read_enum_variant_arg", proc_macro2::Span::call_site()), - quote! {}, - ) + (proc_macro2::Ident::new("read_enum_variant_arg", field_span), quote! {}) + }; + + let __decoder = quote! { __decoder }; + // Use the span of the field for the method call, so + // that backtraces will point to the field. + let decode_call = quote_spanned! {field_span=> + ::rustc_serialize::Decoder::#decode_method( + #__decoder, #opt_field_name #decode_inner_method) }; quote! { - match ::rustc_serialize::Decoder::#decode_method( - __decoder, #opt_field_name #decode_inner_method) { + match #decode_call { ::std::result::Result::Ok(__res) => __res, ::std::result::Result::Err(__err) => return ::std::result::Result::Err(__err), } diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index caf29df2276..8ff3b1e72d8 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -45,7 +45,8 @@ use std::num::NonZeroUsize; use std::path::Path; use tracing::debug; -pub use cstore_impl::{provide, provide_extern}; +pub(super) use cstore_impl::provide; +pub use cstore_impl::provide_extern; use rustc_span::hygiene::HygieneDecodeContext; mod cstore_impl; @@ -1099,10 +1100,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { }; // Iterate over all children. - let macros_only = self.dep_kind.lock().macros_only(); - if !macros_only { - let children = self.root.tables.children.get(self, id).unwrap_or_else(Lazy::empty); - + if let Some(children) = self.root.tables.children.get(self, id) { for child_index in children.decode((self, sess)) { // FIXME: Merge with the logic below. if let None | Some(EntryKind::ForeignMod | EntryKind::Impl(_)) = @@ -1171,11 +1169,6 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { if let EntryKind::Mod(exports) = kind { for exp in exports.decode((self, sess)) { - match exp.res { - Res::Def(DefKind::Macro(..), _) => {} - _ if macros_only => continue, - _ => {} - } callback(exp); } } @@ -1375,6 +1368,10 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { ) } + fn get_traits(&'a self) -> impl Iterator<Item = DefId> + 'a { + self.root.traits.decode(self).map(|index| self.local_def_id(index)) + } + fn get_implementations_for_trait( &self, tcx: TyCtxt<'tcx>, diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index 06b72d537c2..7ffc586fda3 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -195,6 +195,8 @@ provide! { <'tcx> tcx, def_id, other, cdata, extra_filename => { cdata.root.extra_filename.clone() } + traits_in_crate => { tcx.arena.alloc_from_iter(cdata.get_traits()) } + implementations_of_trait => { cdata.get_implementations_for_trait(tcx, Some(other)) } @@ -239,7 +241,7 @@ provide! { <'tcx> tcx, def_id, other, cdata, expn_that_defined => { cdata.get_expn_that_defined(def_id.index, tcx.sess) } } -pub fn provide(providers: &mut Providers) { +pub(in crate::rmeta) fn provide(providers: &mut Providers) { // FIXME(#44234) - almost all of these queries have no sub-queries and // therefore no actual inputs, they're just reading tables calculated in // resolve! Does this work? Unsure! That's what the issue is about @@ -528,4 +530,8 @@ impl CrateStore for CStore { ) -> ExpnId { self.get_crate_data(cnum).expn_hash_to_expn_id(sess, index_guess, hash) } + + fn import_source_files(&self, sess: &Session, cnum: CrateNum) { + self.get_crate_data(cnum).imported_source_files(sess); + } } diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 531ed4c3d6d..3942846e79d 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -27,6 +27,7 @@ use rustc_middle::thir; use rustc_middle::traits::specialization_graph; use rustc_middle::ty::codec::TyEncoder; use rustc_middle::ty::fast_reject::{self, SimplifyParams, StripReferences}; +use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, SymbolName, Ty, TyCtxt}; use rustc_serialize::{opaque, Encodable, Encoder}; use rustc_session::config::CrateType; @@ -612,10 +613,15 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { self.encode_def_path_table(); let def_path_table_bytes = self.position() - i; + // Encode the def IDs of traits, for rustdoc and diagnostics. + i = self.position(); + let traits = self.encode_traits(); + let traits_bytes = self.position() - i; + // Encode the def IDs of impls, for coherence checking. i = self.position(); let impls = self.encode_impls(); - let impl_bytes = self.position() - i; + let impls_bytes = self.position() - i; let tcx = self.tcx; @@ -715,7 +721,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { no_builtins: tcx.sess.contains_name(&attrs, sym::no_builtins), panic_runtime: tcx.sess.contains_name(&attrs, sym::panic_runtime), profiler_runtime: tcx.sess.contains_name(&attrs, sym::profiler_runtime), - symbol_mangling_version: tcx.sess.opts.debugging_opts.get_symbol_mangling_version(), + symbol_mangling_version: tcx.sess.opts.get_symbol_mangling_version(), crate_deps, dylib_dependency_formats, @@ -726,6 +732,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { native_libraries, foreign_modules, source_map, + traits, impls, exported_symbols, interpret_alloc_index, @@ -753,7 +760,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { eprintln!(" diagnostic item bytes: {}", diagnostic_item_bytes); eprintln!(" native bytes: {}", native_lib_bytes); eprintln!(" source_map bytes: {}", source_map_bytes); - eprintln!(" impl bytes: {}", impl_bytes); + eprintln!(" traits bytes: {}", traits_bytes); + eprintln!(" impls bytes: {}", impls_bytes); eprintln!(" exp. symbols bytes: {}", exported_symbols_bytes); eprintln!(" def-path table bytes: {}", def_path_table_bytes); eprintln!(" def-path hashes bytes: {}", def_path_hash_map_bytes); @@ -1790,12 +1798,17 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { self.lazy(&tcx.lang_items().missing) } + fn encode_traits(&mut self) -> Lazy<[DefIndex]> { + empty_proc_macro!(self); + self.lazy(self.tcx.traits_in_crate(LOCAL_CRATE).iter().map(|def_id| def_id.index)) + } + /// Encodes an index, mapping each trait to its (local) implementations. fn encode_impls(&mut self) -> Lazy<[TraitImpls]> { + debug!("EncodeContext::encode_traits_and_impls()"); empty_proc_macro!(self); - debug!("EncodeContext::encode_impls()"); let tcx = self.tcx; - let mut visitor = ImplVisitor { tcx, impls: FxHashMap::default() }; + let mut visitor = ImplsVisitor { tcx, impls: FxHashMap::default() }; tcx.hir().visit_all_item_likes(&mut visitor); let mut all_impls: Vec<_> = visitor.impls.into_iter().collect(); @@ -2040,27 +2053,30 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } } -struct ImplVisitor<'tcx> { +struct ImplsVisitor<'tcx> { tcx: TyCtxt<'tcx>, impls: FxHashMap<DefId, Vec<(DefIndex, Option<fast_reject::SimplifiedType>)>>, } -impl<'tcx, 'v> ItemLikeVisitor<'v> for ImplVisitor<'tcx> { +impl<'tcx, 'v> ItemLikeVisitor<'v> for ImplsVisitor<'tcx> { fn visit_item(&mut self, item: &hir::Item<'_>) { - if let hir::ItemKind::Impl { .. } = item.kind { - if let Some(trait_ref) = self.tcx.impl_trait_ref(item.def_id.to_def_id()) { - let simplified_self_ty = fast_reject::simplify_type( - self.tcx, - trait_ref.self_ty(), - SimplifyParams::No, - StripReferences::No, - ); + match item.kind { + hir::ItemKind::Impl(..) => { + if let Some(trait_ref) = self.tcx.impl_trait_ref(item.def_id.to_def_id()) { + let simplified_self_ty = fast_reject::simplify_type( + self.tcx, + trait_ref.self_ty(), + SimplifyParams::No, + StripReferences::No, + ); - self.impls - .entry(trait_ref.def_id) - .or_default() - .push((item.def_id.local_def_index, simplified_self_ty)); + self.impls + .entry(trait_ref.def_id) + .or_default() + .push((item.def_id.local_def_index, simplified_self_ty)); + } } + _ => {} } } @@ -2209,3 +2225,34 @@ fn encode_metadata_impl(tcx: TyCtxt<'_>) -> EncodedMetadata { EncodedMetadata { raw_data: result } } + +pub fn provide(providers: &mut Providers) { + *providers = Providers { + traits_in_crate: |tcx, cnum| { + assert_eq!(cnum, LOCAL_CRATE); + + #[derive(Default)] + struct TraitsVisitor { + traits: Vec<DefId>, + } + impl ItemLikeVisitor<'_> for TraitsVisitor { + fn visit_item(&mut self, item: &hir::Item<'_>) { + if let hir::ItemKind::Trait(..) | hir::ItemKind::TraitAlias(..) = item.kind { + self.traits.push(item.def_id.to_def_id()); + } + } + fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem<'_>) {} + fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem<'_>) {} + fn visit_foreign_item(&mut self, _foreign_item: &hir::ForeignItem<'_>) {} + } + + let mut visitor = TraitsVisitor::default(); + tcx.hir().visit_all_item_likes(&mut visitor); + // Bring everything into deterministic order. + visitor.traits.sort_by_cached_key(|&def_id| tcx.def_path_hash(def_id)); + tcx.arena.alloc_slice(&visitor.traits) + }, + + ..*providers + }; +} diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index 5ce239ac704..35016453369 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -16,6 +16,7 @@ use rustc_middle::hir::exports::Export; use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportLevel}; use rustc_middle::mir; use rustc_middle::thir; +use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, ReprOptions, Ty}; use rustc_serialize::opaque::Encoder; use rustc_session::config::SymbolManglingVersion; @@ -29,8 +30,8 @@ use rustc_target::spec::{PanicStrategy, TargetTriple}; use std::marker::PhantomData; use std::num::NonZeroUsize; +pub use decoder::provide_extern; use decoder::DecodeContext; -pub use decoder::{provide, provide_extern}; crate use decoder::{CrateMetadata, CrateNumMap, MetadataBlob}; use encoder::EncodeContext; pub use encoder::{encode_metadata, EncodedMetadata}; @@ -222,6 +223,7 @@ crate struct CrateRoot<'tcx> { diagnostic_items: Lazy<[(Symbol, DefIndex)]>, native_libraries: Lazy<[NativeLib]>, foreign_modules: Lazy<[ForeignModule]>, + traits: Lazy<[DefIndex]>, impls: Lazy<[TraitImpls]>, interpret_alloc_index: Lazy<[u32]>, proc_macro_data: Option<ProcMacroData>, @@ -453,3 +455,8 @@ struct GeneratorData<'tcx> { const TAG_VALID_SPAN_LOCAL: u8 = 0; const TAG_VALID_SPAN_FOREIGN: u8 = 1; const TAG_PARTIAL_SPAN: u8 = 2; + +pub fn provide(providers: &mut Providers) { + encoder::provide(providers); + decoder::provide(providers); +} diff --git a/compiler/rustc_middle/Cargo.toml b/compiler/rustc_middle/Cargo.toml index f8d3fb6c48d..a9db8469384 100644 --- a/compiler/rustc_middle/Cargo.toml +++ b/compiler/rustc_middle/Cargo.toml @@ -10,7 +10,7 @@ doctest = false rustc_arena = { path = "../rustc_arena" } bitflags = "1.2.1" either = "1.5.0" -gsgdt = "0.1.3" +gsgdt = "0.1.2" tracing = "0.1" rustc-rayon = "0.3.1" rustc-rayon-core = "0.3.1" diff --git a/compiler/rustc_middle/src/mir/generic_graph.rs b/compiler/rustc_middle/src/mir/generic_graph.rs index 44d0ce935df..770b52a4d4b 100644 --- a/compiler/rustc_middle/src/mir/generic_graph.rs +++ b/compiler/rustc_middle/src/mir/generic_graph.rs @@ -55,7 +55,7 @@ fn bb_to_graph_node(block: BasicBlock, body: &Body<'_>, dark_mode: bool) -> Node data.terminator().kind.fmt_head(&mut terminator_head).unwrap(); stmts.push(terminator_head); - Node::from_list(stmts, label, title, style) + Node::new(stmts, label, title, style) } // Must match `[0-9A-Za-z_]*`. This does not appear in the rendered graph, so diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index c7c306e7d06..52ef380001c 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -2336,8 +2336,6 @@ pub enum NullOp { SizeOf, /// Returns the minimum alignment of a type AlignOf, - /// Creates a new uninitialized box for a value of that type - Box, } #[derive(Copy, Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)] diff --git a/compiler/rustc_middle/src/mir/tcx.rs b/compiler/rustc_middle/src/mir/tcx.rs index e577df48205..dc53dc8de9d 100644 --- a/compiler/rustc_middle/src/mir/tcx.rs +++ b/compiler/rustc_middle/src/mir/tcx.rs @@ -195,7 +195,6 @@ impl<'tcx> Rvalue<'tcx> { } Rvalue::UnaryOp(UnOp::Not | UnOp::Neg, ref operand) => operand.ty(local_decls, tcx), Rvalue::Discriminant(ref place) => place.ty(local_decls, tcx).ty.discriminant_ty(tcx), - Rvalue::NullaryOp(NullOp::Box, t) => tcx.mk_box(t), Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf, _) => tcx.types.usize, Rvalue::Aggregate(ref ak, ref ops) => match **ak { AggregateKind::Array(ty) => tcx.mk_array(ty, ops.len() as u64), @@ -215,9 +214,7 @@ impl<'tcx> Rvalue<'tcx> { /// whether its only shallowly initialized (`Rvalue::Box`). pub fn initialization_state(&self) -> RvalueInitializationState { match *self { - Rvalue::NullaryOp(NullOp::Box, _) | Rvalue::ShallowInitBox(_, _) => { - RvalueInitializationState::Shallow - } + Rvalue::ShallowInitBox(_, _) => RvalueInitializationState::Shallow, _ => RvalueInitializationState::Deep, } } diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index ad3f61d0784..027c0c64924 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1609,11 +1609,11 @@ rustc_queries! { desc { "fetching all foreign CrateNum instances" } } - /// A vector of every trait accessible in the whole crate - /// (i.e., including those from subcrates). This is used only for - /// error reporting. - query all_traits(_: ()) -> &'tcx [DefId] { - desc { "fetching all foreign and local traits" } + /// A list of all traits in a crate, used by rustdoc and error reporting. + /// NOTE: Not named just `traits` due to a naming conflict. + query traits_in_crate(_: CrateNum) -> &'tcx [DefId] { + desc { "fetching all traits in a crate" } + separate_provide_extern } /// The list of symbols exported from the given crate. diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index caa7008f108..dd571e29bf6 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -1577,6 +1577,12 @@ impl<'tcx> TyCtxt<'tcx> { pub fn const_eval_limit(self) -> Limit { self.limits(()).const_eval_limit } + + pub fn all_traits(self) -> impl Iterator<Item = DefId> + 'tcx { + iter::once(LOCAL_CRATE) + .chain(self.crates(()).iter().copied()) + .flat_map(move |cnum| self.traits_in_crate(cnum).iter().copied()) + } } /// A trait implemented for all `X<'a>` types that can be safely and diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 37d99766da9..78ccfbd5e8c 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -77,7 +77,7 @@ pub use self::sty::{ GeneratorSubsts, GeneratorSubstsParts, InlineConstSubsts, InlineConstSubstsParts, ParamConst, ParamTy, PolyExistentialProjection, PolyExistentialTraitRef, PolyFnSig, PolyGenSig, PolyTraitRef, ProjectionTy, Region, RegionKind, RegionVid, TraitRef, TyKind, TypeAndMut, - UpvarSubsts, VarianceDiagInfo, VarianceDiagMutKind, + UpvarSubsts, VarianceDiagInfo, }; pub use self::trait_def::TraitDef; diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs index 905a5c47d2b..63ed318cadb 100644 --- a/compiler/rustc_middle/src/ty/relate.rs +++ b/compiler/rustc_middle/src/ty/relate.rs @@ -6,7 +6,7 @@ use crate::mir::interpret::{get_slice_bytes, ConstValue, GlobalAlloc, Scalar}; use crate::ty::error::{ExpectedFound, TypeError}; -use crate::ty::subst::{GenericArg, GenericArgKind, SubstsRef}; +use crate::ty::subst::{GenericArg, GenericArgKind, Subst, SubstsRef}; use crate::ty::{self, Ty, TyCtxt, TypeFoldable}; use rustc_hir as ast; use rustc_hir::def_id::DefId; @@ -59,8 +59,9 @@ pub trait TypeRelation<'tcx>: Sized { item_def_id, a_subst, b_subst ); - let opt_variances = self.tcx().variances_of(item_def_id); - relate_substs(self, Some(opt_variances), a_subst, b_subst) + let tcx = self.tcx(); + let opt_variances = tcx.variances_of(item_def_id); + relate_substs(self, Some((item_def_id, opt_variances)), a_subst, b_subst) } /// Switch variance for the purpose of relating `a` and `b`. @@ -116,7 +117,7 @@ pub fn relate_type_and_mut<'tcx, R: TypeRelation<'tcx>>( relation: &mut R, a: ty::TypeAndMut<'tcx>, b: ty::TypeAndMut<'tcx>, - kind: ty::VarianceDiagMutKind, + base_ty: Ty<'tcx>, ) -> RelateResult<'tcx, ty::TypeAndMut<'tcx>> { debug!("{}.mts({:?}, {:?})", relation.tag(), a, b); if a.mutbl != b.mutbl { @@ -125,7 +126,9 @@ pub fn relate_type_and_mut<'tcx, R: TypeRelation<'tcx>>( let mutbl = a.mutbl; let (variance, info) = match mutbl { ast::Mutability::Not => (ty::Covariant, ty::VarianceDiagInfo::None), - ast::Mutability::Mut => (ty::Invariant, ty::VarianceDiagInfo::Mut { kind, ty: a.ty }), + ast::Mutability::Mut => { + (ty::Invariant, ty::VarianceDiagInfo::Invariant { ty: base_ty, param_index: 0 }) + } }; let ty = relation.relate_with_variance(variance, info, a.ty, b.ty)?; Ok(ty::TypeAndMut { ty, mutbl }) @@ -134,15 +137,29 @@ pub fn relate_type_and_mut<'tcx, R: TypeRelation<'tcx>>( pub fn relate_substs<'tcx, R: TypeRelation<'tcx>>( relation: &mut R, - variances: Option<&[ty::Variance]>, + variances: Option<(DefId, &[ty::Variance])>, a_subst: SubstsRef<'tcx>, b_subst: SubstsRef<'tcx>, ) -> RelateResult<'tcx, SubstsRef<'tcx>> { let tcx = relation.tcx(); + let mut cached_ty = None; let params = iter::zip(a_subst, b_subst).enumerate().map(|(i, (a, b))| { - let variance = variances.map_or(ty::Invariant, |v| v[i]); - relation.relate_with_variance(variance, ty::VarianceDiagInfo::default(), a, b) + let (variance, variance_info) = match variances { + Some((ty_def_id, variances)) => { + let variance = variances[i]; + let variance_info = if variance == ty::Invariant { + let ty = + cached_ty.get_or_insert_with(|| tcx.type_of(ty_def_id).subst(tcx, a_subst)); + ty::VarianceDiagInfo::Invariant { ty, param_index: i.try_into().unwrap() } + } else { + ty::VarianceDiagInfo::default() + }; + (variance, variance_info) + } + None => (ty::Invariant, ty::VarianceDiagInfo::default()), + }; + relation.relate_with_variance(variance, variance_info, a, b) }); tcx.mk_substs(params) @@ -436,7 +453,7 @@ pub fn super_relate_tys<'tcx, R: TypeRelation<'tcx>>( } (&ty::RawPtr(a_mt), &ty::RawPtr(b_mt)) => { - let mt = relate_type_and_mut(relation, a_mt, b_mt, ty::VarianceDiagMutKind::RawPtr)?; + let mt = relate_type_and_mut(relation, a_mt, b_mt, a)?; Ok(tcx.mk_ptr(mt)) } @@ -449,7 +466,7 @@ pub fn super_relate_tys<'tcx, R: TypeRelation<'tcx>>( )?; let a_mt = ty::TypeAndMut { ty: a_ty, mutbl: a_mutbl }; let b_mt = ty::TypeAndMut { ty: b_ty, mutbl: b_mutbl }; - let mt = relate_type_and_mut(relation, a_mt, b_mt, ty::VarianceDiagMutKind::Ref)?; + let mt = relate_type_and_mut(relation, a_mt, b_mt, a)?; Ok(tcx.mk_ref(r, mt)) } diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 8706661b250..c24a1d8eb52 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -2282,36 +2282,26 @@ pub enum VarianceDiagInfo<'tcx> { /// We will not add any additional information to error messages. #[default] None, - /// We switched our variance because a type occurs inside - /// the generic argument of a mutable reference or pointer - /// (`*mut T` or `&mut T`). In either case, our variance - /// will always be `Invariant`. - Mut { - /// Tracks whether we had a mutable pointer or reference, - /// for better error messages - kind: VarianceDiagMutKind, - /// The type parameter of the mutable pointer/reference - /// (the `T` in `&mut T` or `*mut T`). + /// We switched our variance because a generic argument occurs inside + /// the invariant generic argument of another type. + Invariant { + /// The generic type containing the generic parameter + /// that changes the variance (e.g. `*mut T`, `MyStruct<T>`) ty: Ty<'tcx>, + /// The index of the generic parameter being used + /// (e.g. `0` for `*mut T`, `1` for `MyStruct<'CovariantParam, 'InvariantParam>`) + param_index: u32, }, } -#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] -pub enum VarianceDiagMutKind { - /// A mutable raw pointer (`*mut T`) - RawPtr, - /// A mutable reference (`&mut T`) - Ref, -} - impl<'tcx> VarianceDiagInfo<'tcx> { /// Mirrors `Variance::xform` - used to 'combine' the existing /// and new `VarianceDiagInfo`s when our variance changes. pub fn xform(self, other: VarianceDiagInfo<'tcx>) -> VarianceDiagInfo<'tcx> { - // For now, just use the first `VarianceDiagInfo::Mut` that we see + // For now, just use the first `VarianceDiagInfo::Invariant` that we see match self { VarianceDiagInfo::None => other, - VarianceDiagInfo::Mut { .. } => self, + VarianceDiagInfo::Invariant { .. } => self, } } } diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index 092fe131174..bdde6b4a356 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -583,9 +583,12 @@ impl<'tcx> Cx<'tcx> { ExprKind::ConstBlock { value } } // Now comes the rote stuff: - hir::ExprKind::Repeat(ref v, ref count) => { - let count_def_id = self.tcx.hir().local_def_id(count.hir_id); - let count = ty::Const::from_anon_const(self.tcx, count_def_id); + hir::ExprKind::Repeat(ref v, _) => { + let ty = self.typeck_results().expr_ty(expr); + let count = match ty.kind() { + ty::Array(_, ct) => ct, + _ => span_bug!(expr.span, "unexpected repeat expr ty: {:?}", ty), + }; ExprKind::Repeat { value: self.mirror_expr(v), count } } diff --git a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs index feb85d4ffdf..2e00b4f9a5e 100644 --- a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs +++ b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs @@ -343,19 +343,7 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> { | Rvalue::AddressOf(..) | Rvalue::Discriminant(..) | Rvalue::Len(..) - | Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf, _) - | Rvalue::NullaryOp(NullOp::Box, _) => { - // This returns an rvalue with uninitialized contents. We can't - // move out of it here because it is an rvalue - assignments always - // completely initialize their place. - // - // However, this does not matter - MIR building is careful to - // only emit a shallow free for the partially-initialized - // temporary. - // - // In any case, if we want to fix this, we have to register a - // special move and change the `statement_effect` functions. - } + | Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf, _) => {} } } diff --git a/compiler/rustc_mir_transform/src/const_prop.rs b/compiler/rustc_mir_transform/src/const_prop.rs index 7e56e062fc9..e3ff6ad4549 100644 --- a/compiler/rustc_mir_transform/src/const_prop.rs +++ b/compiler/rustc_mir_transform/src/const_prop.rs @@ -239,13 +239,6 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx> throw_machine_stop_str!("pointer arithmetic or comparisons aren't supported in ConstProp") } - fn box_alloc( - _ecx: &mut InterpCx<'mir, 'tcx, Self>, - _dest: &PlaceTy<'tcx>, - ) -> InterpResult<'tcx> { - throw_machine_stop_str!("can't const prop heap allocations") - } - fn access_local( _ecx: &InterpCx<'mir, 'tcx, Self>, frame: &Frame<'mir, 'tcx, Self::PointerTag, Self::FrameExtra>, @@ -413,7 +406,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { Instance::new(def_id, substs), dummy_body, ret.as_ref(), - StackPopCleanup::None { cleanup: false }, + StackPopCleanup::Root { cleanup: false }, ) .expect("failed to push initial stack frame"); diff --git a/compiler/rustc_mir_transform/src/elaborate_drops.rs b/compiler/rustc_mir_transform/src/elaborate_drops.rs index d346dfb1772..7320b2738a7 100644 --- a/compiler/rustc_mir_transform/src/elaborate_drops.rs +++ b/compiler/rustc_mir_transform/src/elaborate_drops.rs @@ -316,12 +316,12 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { LookupResult::Parent(Some(parent)) => { let (_maybe_live, maybe_dead) = self.init_data.maybe_live_dead(parent); if maybe_dead { - span_bug!( + self.tcx.sess.delay_span_bug( terminator.source_info.span, - "drop of untracked, uninitialized value {:?}, place {:?} ({:?})", - bb, - place, - path + &format!( + "drop of untracked, uninitialized value {:?}, place {:?} ({:?})", + bb, place, path, + ), ); } continue; @@ -368,10 +368,9 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { bb, ), LookupResult::Parent(..) => { - span_bug!( + self.tcx.sess.delay_span_bug( terminator.source_info.span, - "drop of untracked value {:?}", - bb + &format!("drop of untracked value {:?}", bb), ); } } diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index b1fa9041342..b70c24b76d5 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -688,15 +688,6 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { _ => bug!(), } } - mir::Rvalue::NullaryOp(mir::NullOp::Box, _) => { - let tcx = self.tcx; - let exchange_malloc_fn_def_id = - tcx.require_lang_item(LangItem::ExchangeMalloc, None); - let instance = Instance::mono(tcx, exchange_malloc_fn_def_id); - if should_codegen_locally(tcx, &instance) { - self.output.push(create_fn_mono_item(self.tcx, instance, span)); - } - } mir::Rvalue::ThreadLocalRef(def_id) => { assert!(self.tcx.is_thread_local_static(def_id)); let instance = Instance::mono(self.tcx, def_id); diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index d335ef8788b..ade441b0e7d 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -27,7 +27,7 @@ impl<'a> Parser<'a> { /// Parses a source module as a crate. This is the main entry point for the parser. pub fn parse_crate_mod(&mut self) -> PResult<'a, ast::Crate> { let (attrs, items, span) = self.parse_mod(&token::Eof)?; - Ok(ast::Crate { attrs, items, span, is_placeholder: None }) + Ok(ast::Crate { attrs, items, span, id: DUMMY_NODE_ID, is_placeholder: false }) } /// Parses a `mod <foo> { ... }` or `mod <foo>;` item. diff --git a/compiler/rustc_passes/src/lib_features.rs b/compiler/rustc_passes/src/lib_features.rs index 55ae808dc30..40d12c4a22d 100644 --- a/compiler/rustc_passes/src/lib_features.rs +++ b/compiler/rustc_passes/src/lib_features.rs @@ -4,7 +4,7 @@ // and `#[unstable (..)]`), but are not declared in one single location // (unlike lang features), which means we need to collect them instead. -use rustc_ast::{Attribute, MetaItem, MetaItemKind}; +use rustc_ast::{Attribute, MetaItemKind}; use rustc_errors::struct_span_err; use rustc_hir::intravisit::{NestedVisitorMap, Visitor}; use rustc_middle::hir::map::Map; @@ -34,8 +34,8 @@ impl<'tcx> LibFeatureCollector<'tcx> { // Find a stability attribute (i.e., `#[stable (..)]`, `#[unstable (..)]`, // `#[rustc_const_unstable (..)]`). if let Some(stab_attr) = stab_attrs.iter().find(|stab_attr| attr.has_name(**stab_attr)) { - let meta_item = attr.meta(); - if let Some(MetaItem { kind: MetaItemKind::List(ref metas), .. }) = meta_item { + let meta_kind = attr.meta_kind(); + if let Some(MetaItemKind::List(ref metas)) = meta_kind { let mut feature = None; let mut since = None; for meta in metas { diff --git a/compiler/rustc_query_impl/src/on_disk_cache.rs b/compiler/rustc_query_impl/src/on_disk_cache.rs index 11f54ea66fa..6a88e123537 100644 --- a/compiler/rustc_query_impl/src/on_disk_cache.rs +++ b/compiler/rustc_query_impl/src/on_disk_cache.rs @@ -495,6 +495,20 @@ impl<'a, 'tcx> CacheDecoder<'a, 'tcx> { .entry(index) .or_insert_with(|| { let stable_id = file_index_to_stable_id[&index].translate(tcx); + + // If this `SourceFile` is from a foreign crate, then make sure + // that we've imported all of the source files from that crate. + // This has usually already been done during macro invocation. + // However, when encoding query results like `TypeckResults`, + // we might encode an `AdtDef` for a foreign type (because it + // was referenced in the body of the function). There is no guarantee + // that we will load the source files from that crate during macro + // expansion, so we use `import_source_files` to ensure that the foreign + // source files are actually imported before we call `source_file_by_stable_id`. + if stable_id.cnum != LOCAL_CRATE { + self.tcx.cstore_untracked().import_source_files(self.tcx.sess, stable_id.cnum); + } + source_map .source_file_by_stable_id(stable_id) .expect("failed to lookup `SourceFile` in new context") diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs index a8be1ca34c0..7bc3fd718e0 100644 --- a/compiler/rustc_query_system/src/dep_graph/graph.rs +++ b/compiler/rustc_query_system/src/dep_graph/graph.rs @@ -88,6 +88,11 @@ struct DepGraphData<K: DepKind> { previous_work_products: FxHashMap<WorkProductId, WorkProduct>, dep_node_debug: Lock<FxHashMap<DepNode<K>, String>>, + + /// Used by incremental compilation tests to assert that + /// a particular query result was decoded from disk + /// (not just marked green) + debug_loaded_from_disk: Lock<FxHashSet<DepNode<K>>>, } pub fn hash_result<R>(hcx: &mut StableHashingContext<'_>, result: &R) -> Fingerprint @@ -135,6 +140,7 @@ impl<K: DepKind> DepGraph<K> { processed_side_effects: Default::default(), previous: prev_graph, colors: DepNodeColorMap::new(prev_graph_node_count), + debug_loaded_from_disk: Default::default(), })), virtual_dep_node_index: Lrc::new(AtomicU32::new(0)), } @@ -438,6 +444,14 @@ impl<K: DepKind> DepGraph<K> { &self.data.as_ref().unwrap().previous_work_products } + pub fn mark_debug_loaded_from_disk(&self, dep_node: DepNode<K>) { + self.data.as_ref().unwrap().debug_loaded_from_disk.lock().insert(dep_node); + } + + pub fn debug_was_loaded_from_disk(&self, dep_node: DepNode<K>) -> bool { + self.data.as_ref().unwrap().debug_loaded_from_disk.lock().contains(&dep_node) + } + #[inline(always)] pub fn register_dep_node_debug_str<F>(&self, dep_node: DepNode<K>, debug_str_gen: F) where diff --git a/compiler/rustc_query_system/src/ich/impls_hir.rs b/compiler/rustc_query_system/src/ich/impls_hir.rs index 3a0aab81fdb..3117140a5b6 100644 --- a/compiler/rustc_query_system/src/ich/impls_hir.rs +++ b/compiler/rustc_query_system/src/ich/impls_hir.rs @@ -3,8 +3,7 @@ use crate::ich::hcx::BodyResolver; use crate::ich::{NodeIdHashingMode, StableHashingContext}; -use rustc_data_structures::fingerprint::Fingerprint; -use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey}; +use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_hir as hir; use std::mem; @@ -47,28 +46,6 @@ impl<'ctx> rustc_hir::HashStableContext for StableHashingContext<'ctx> { }) } - #[inline] - fn hash_hir_mod(&mut self, module: &hir::Mod<'_>, hasher: &mut StableHasher) { - let hcx = self; - let hir::Mod { inner: ref inner_span, ref item_ids } = *module; - - inner_span.hash_stable(hcx, hasher); - - // Combining the `DefPathHash`s directly is faster than feeding them - // into the hasher. Because we use a commutative combine, we also don't - // have to sort the array. - let item_ids_hash = item_ids - .iter() - .map(|id| { - let def_path_hash = id.to_stable_hash_key(hcx); - def_path_hash.0 - }) - .fold(Fingerprint::ZERO, |a, b| a.combine_commutative(b)); - - item_ids.len().hash_stable(hcx, hasher); - item_ids_hash.hash_stable(hcx, hasher); - } - fn hash_hir_expr(&mut self, expr: &hir::Expr<'_>, hasher: &mut StableHasher) { self.while_hashing_hir_bodies(true, |hcx| { let hir::Expr { hir_id: _, ref span, ref kind } = *expr; diff --git a/compiler/rustc_query_system/src/query/plumbing.rs b/compiler/rustc_query_system/src/query/plumbing.rs index b08db39e245..33732f9df73 100644 --- a/compiler/rustc_query_system/src/query/plumbing.rs +++ b/compiler/rustc_query_system/src/query/plumbing.rs @@ -519,6 +519,10 @@ where prof_timer.finish_with_query_invocation_id(dep_node_index.into()); if let Some(result) = result { + if unlikely!(tcx.dep_context().sess().opts.debugging_opts.query_dep_graph) { + dep_graph.mark_debug_loaded_from_disk(*dep_node) + } + let prev_fingerprint = tcx .dep_context() .dep_graph() diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index d57591186d8..39074f811a5 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -1512,8 +1512,8 @@ impl<'a, 'b> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b> { } fn visit_crate(&mut self, krate: &'b ast::Crate) { - if let Some(id) = krate.is_placeholder { - self.visit_invoc_in_module(id); + if krate.is_placeholder { + self.visit_invoc_in_module(krate.id); } else { visit::walk_crate(self, krate); self.contains_macro_use(&krate.attrs); diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index 688b7b1a8c6..8ea5dca6f10 100644 --- a/compiler/rustc_resolve/src/def_collector.rs +++ b/compiler/rustc_resolve/src/def_collector.rs @@ -344,8 +344,8 @@ impl<'a, 'b> visit::Visitor<'a> for DefCollector<'a, 'b> { } fn visit_crate(&mut self, krate: &'a Crate) { - if let Some(id) = krate.is_placeholder { - self.visit_macro_invoc(id) + if krate.is_placeholder { + self.visit_macro_invoc(krate.id) } else { visit::walk_crate(self, krate) } diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 5098cef11e8..57305023138 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -2379,7 +2379,9 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { ExprKind::While(ref cond, ref block, label) => { self.with_resolved_label(label, expr.id, |this| { this.with_rib(ValueNS, NormalRibKind, |this| { + let old = this.diagnostic_metadata.in_if_condition.replace(cond); this.visit_expr(cond); + this.diagnostic_metadata.in_if_condition = old; this.visit_block(block); }) }); diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 26344080381..2008570d6f0 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -68,7 +68,7 @@ use smallvec::{smallvec, SmallVec}; use std::cell::{Cell, RefCell}; use std::collections::{BTreeMap, BTreeSet}; use std::ops::ControlFlow; -use std::{cmp, fmt, iter, ptr}; +use std::{cmp, fmt, iter, mem, ptr}; use tracing::debug; use diagnostics::{extend_span_to_previous_binding, find_span_of_binding_until_next_binding}; @@ -1394,7 +1394,7 @@ impl<'a> Resolver<'a> { .chain(features.declared_lang_features.iter().map(|(feat, ..)| *feat)) .collect(), lint_buffer: LintBuffer::default(), - next_node_id: NodeId::from_u32(1), + next_node_id: CRATE_NODE_ID, node_id_to_def_id, def_id_to_node_id, placeholder_field_indices: Default::default(), @@ -1430,8 +1430,7 @@ impl<'a> Resolver<'a> { pub fn next_node_id(&mut self) -> NodeId { let next = self.next_node_id.as_u32().checked_add(1).expect("input too large; ran out of NodeIds"); - self.next_node_id = ast::NodeId::from_u32(next); - self.next_node_id + mem::replace(&mut self.next_node_id, ast::NodeId::from_u32(next)) } pub fn lint_buffer(&mut self) -> &mut LintBuffer { diff --git a/compiler/rustc_save_analysis/src/dump_visitor.rs b/compiler/rustc_save_analysis/src/dump_visitor.rs index f1a5282b088..23f5b17fa78 100644 --- a/compiler/rustc_save_analysis/src/dump_visitor.rs +++ b/compiler/rustc_save_analysis/src/dump_visitor.rs @@ -1326,12 +1326,18 @@ impl<'tcx> Visitor<'tcx> for DumpVisitor<'tcx> { } intravisit::walk_qpath(self, path, t.hir_id, t.span); } - hir::TyKind::Array(ref ty, ref anon_const) => { + hir::TyKind::Array(ref ty, ref length) => { self.visit_ty(ty); let map = self.tcx.hir(); - self.nest_typeck_results(self.tcx.hir().local_def_id(anon_const.hir_id), |v| { - v.visit_expr(&map.body(anon_const.body).value) - }); + match length { + // FIXME(generic_arg_infer): We probably want to + // output the inferred type here? :shrug: + hir::ArrayLen::Infer(..) => {} + hir::ArrayLen::Body(anon_const) => self + .nest_typeck_results(self.tcx.hir().local_def_id(anon_const.hir_id), |v| { + v.visit_expr(&map.body(anon_const.body).value) + }), + } } hir::TyKind::OpaqueDef(item_id, _) => { let item = self.tcx.hir().item(item_id); @@ -1390,12 +1396,18 @@ impl<'tcx> Visitor<'tcx> for DumpVisitor<'tcx> { v.visit_expr(&body.value) }); } - hir::ExprKind::Repeat(ref expr, ref anon_const) => { + hir::ExprKind::Repeat(ref expr, ref length) => { self.visit_expr(expr); let map = self.tcx.hir(); - self.nest_typeck_results(self.tcx.hir().local_def_id(anon_const.hir_id), |v| { - v.visit_expr(&map.body(anon_const.body).value) - }); + match length { + // FIXME(generic_arg_infer): We probably want to + // output the inferred type here? :shrug: + hir::ArrayLen::Infer(..) => {} + hir::ArrayLen::Body(anon_const) => self + .nest_typeck_results(self.tcx.hir().local_def_id(anon_const.hir_id), |v| { + v.visit_expr(&map.body(anon_const.body).value) + }), + } } // In particular, we take this branch for call and path expressions, // where we'll index the idents involved just by continuing to walk. diff --git a/compiler/rustc_save_analysis/src/sig.rs b/compiler/rustc_save_analysis/src/sig.rs index e43344ad6d9..4971bb6d1aa 100644 --- a/compiler/rustc_save_analysis/src/sig.rs +++ b/compiler/rustc_save_analysis/src/sig.rs @@ -310,9 +310,9 @@ impl<'hir> Sig for hir::Ty<'hir> { let nested = bounds_to_string(&bounds); Ok(text_sig(nested)) } - hir::TyKind::Array(ref ty, ref anon_const) => { + hir::TyKind::Array(ref ty, ref length) => { let nested_ty = ty.make(offset + 1, id, scx)?; - let expr = id_to_string(&scx.tcx.hir(), anon_const.body.hir_id).replace('\n', " "); + let expr = id_to_string(&scx.tcx.hir(), length.hir_id()).replace('\n', " "); let text = format!("[{}; {}]", nested_ty.text, expr); Ok(replace_text(nested_ty, text)) } diff --git a/compiler/rustc_serialize/src/opaque.rs b/compiler/rustc_serialize/src/opaque.rs index cc1216418ae..f2ef1481681 100644 --- a/compiler/rustc_serialize/src/opaque.rs +++ b/compiler/rustc_serialize/src/opaque.rs @@ -92,7 +92,8 @@ impl serialize::Encoder for Encoder { #[inline] fn emit_u16(&mut self, v: u16) -> EncodeResult { - write_leb128!(self, v, u16, write_u16_leb128) + self.data.extend_from_slice(&v.to_le_bytes()); + Ok(()) } #[inline] @@ -123,7 +124,8 @@ impl serialize::Encoder for Encoder { #[inline] fn emit_i16(&mut self, v: i16) -> EncodeResult { - write_leb128!(self, v, i16, write_i16_leb128) + self.data.extend_from_slice(&v.to_le_bytes()); + Ok(()) } #[inline] @@ -446,7 +448,7 @@ impl serialize::Encoder for FileEncoder { #[inline] fn emit_u16(&mut self, v: u16) -> FileEncodeResult { - file_encoder_write_leb128!(self, v, u16, write_u16_leb128) + self.write_all(&v.to_le_bytes()) } #[inline] @@ -476,13 +478,12 @@ impl serialize::Encoder for FileEncoder { #[inline] fn emit_i16(&mut self, v: i16) -> FileEncodeResult { - file_encoder_write_leb128!(self, v, i16, write_i16_leb128) + self.write_all(&v.to_le_bytes()) } #[inline] fn emit_i8(&mut self, v: i8) -> FileEncodeResult { - let as_u8: u8 = unsafe { std::mem::transmute(v) }; - self.emit_u8(as_u8) + self.emit_u8(v as u8) } #[inline] @@ -591,7 +592,10 @@ impl<'a> serialize::Decoder for Decoder<'a> { #[inline] fn read_u16(&mut self) -> Result<u16, Self::Error> { - read_leb128!(self, read_u16_leb128) + let bytes = [self.data[self.position], self.data[self.position + 1]]; + let value = u16::from_le_bytes(bytes); + self.position += 2; + Ok(value) } #[inline] @@ -623,7 +627,10 @@ impl<'a> serialize::Decoder for Decoder<'a> { #[inline] fn read_i16(&mut self) -> Result<i16, Self::Error> { - read_leb128!(self, read_i16_leb128) + let bytes = [self.data[self.position], self.data[self.position + 1]]; + let value = i16::from_le_bytes(bytes); + self.position += 2; + Ok(value) } #[inline] diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index de5ff231d61..62b351f5e02 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -231,6 +231,37 @@ pub enum DebugInfo { Full, } +/// Split debug-information is enabled by `-C split-debuginfo`, this enum is only used if split +/// debug-information is enabled (in either `Packed` or `Unpacked` modes), and the platform +/// uses DWARF for debug-information. +/// +/// Some debug-information requires link-time relocation and some does not. LLVM can partition +/// the debuginfo into sections depending on whether or not it requires link-time relocation. Split +/// DWARF provides a mechanism which allows the linker to skip the sections which don't require +/// link-time relocation - either by putting those sections in DWARF object files, or by keeping +/// them in the object file in such a way that the linker will skip them. +#[derive(Clone, Copy, Debug, PartialEq, Hash)] +pub enum SplitDwarfKind { + /// Sections which do not require relocation are written into object file but ignored by the + /// linker. + Single, + /// Sections which do not require relocation are written into a DWARF object (`.dwo`) file + /// which is ignored by the linker. + Split, +} + +impl FromStr for SplitDwarfKind { + type Err = (); + + fn from_str(s: &str) -> Result<Self, ()> { + Ok(match s { + "single" => SplitDwarfKind::Single, + "split" => SplitDwarfKind::Split, + _ => return Err(()), + }) + } +} + #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, PartialOrd, Ord)] #[derive(Encodable, Decodable)] pub enum OutputType { @@ -378,7 +409,7 @@ impl OutputTypes { self.0.len() } - // Returns `true` if any of the output types require codegen or linking. + /// Returns `true` if any of the output types require codegen or linking. pub fn should_codegen(&self) -> bool { self.0.keys().any(|k| match *k { OutputType::Bitcode @@ -391,7 +422,7 @@ impl OutputTypes { }) } - // Returns `true` if any of the output types require linking. + /// Returns `true` if any of the output types require linking. pub fn should_link(&self) -> bool { self.0.keys().any(|k| match *k { OutputType::Bitcode @@ -681,18 +712,23 @@ impl OutputFilenames { pub fn split_dwarf_path( &self, split_debuginfo_kind: SplitDebuginfo, + split_dwarf_kind: SplitDwarfKind, cgu_name: Option<&str>, ) -> Option<PathBuf> { let obj_out = self.temp_path(OutputType::Object, cgu_name); let dwo_out = self.temp_path_dwo(cgu_name); - match split_debuginfo_kind { - SplitDebuginfo::Off => None, + match (split_debuginfo_kind, split_dwarf_kind) { + (SplitDebuginfo::Off, SplitDwarfKind::Single | SplitDwarfKind::Split) => None, // Single mode doesn't change how DWARF is emitted, but does add Split DWARF attributes // (pointing at the path which is being determined here). Use the path to the current // object file. - SplitDebuginfo::Packed => Some(obj_out), + (SplitDebuginfo::Packed | SplitDebuginfo::Unpacked, SplitDwarfKind::Single) => { + Some(obj_out) + } // Split mode emits the DWARF into a different file, use that path. - SplitDebuginfo::Unpacked => Some(dwo_out), + (SplitDebuginfo::Packed | SplitDebuginfo::Unpacked, SplitDwarfKind::Split) => { + Some(dwo_out) + } } } } @@ -781,6 +817,10 @@ impl Options { }, } } + + pub fn get_symbol_mangling_version(&self) -> SymbolManglingVersion { + self.cg.symbol_mangling_version.unwrap_or(SymbolManglingVersion::Legacy) + } } impl DebuggingOptions { @@ -794,10 +834,6 @@ impl DebuggingOptions { deduplicate_diagnostics: self.deduplicate_diagnostics, } } - - pub fn get_symbol_mangling_version(&self) -> SymbolManglingVersion { - self.symbol_mangling_version.unwrap_or(SymbolManglingVersion::Legacy) - } } // The type of entry function, so users can have their own entry functions @@ -821,6 +857,18 @@ pub enum CrateType { impl_stable_hash_via_hash!(CrateType); +impl CrateType { + /// When generated, is this crate type an archive? + pub fn is_archive(&self) -> bool { + match *self { + CrateType::Rlib | CrateType::Staticlib => true, + CrateType::Executable | CrateType::Dylib | CrateType::Cdylib | CrateType::ProcMacro => { + false + } + } + } +} + #[derive(Clone, Hash, Debug, PartialEq, Eq)] pub enum Passes { Some(Vec<String>), @@ -843,6 +891,30 @@ impl Passes { } } +#[derive(Clone, Copy, Hash, Debug, PartialEq)] +pub enum PAuthKey { + A, + B, +} + +#[derive(Clone, Copy, Hash, Debug, PartialEq)] +pub struct PacRet { + pub leaf: bool, + pub key: PAuthKey, +} + +#[derive(Clone, Copy, Hash, Debug, PartialEq)] +pub struct BranchProtection { + pub bti: bool, + pub pac_ret: Option<PacRet>, +} + +impl Default for BranchProtection { + fn default() -> Self { + BranchProtection { bti: false, pac_ret: None } + } +} + pub const fn default_lib_output() -> CrateType { CrateType::Rlib } @@ -2092,6 +2164,34 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { ); } + // Handle both `-Z symbol-mangling-version` and `-C symbol-mangling-version`; the latter takes + // precedence. + match (cg.symbol_mangling_version, debugging_opts.symbol_mangling_version) { + (Some(smv_c), Some(smv_z)) if smv_c != smv_z => { + early_error( + error_format, + "incompatible values passed for `-C symbol-mangling-version` \ + and `-Z symbol-mangling-version`", + ); + } + (Some(SymbolManglingVersion::V0), _) => {} + (Some(_), _) if !debugging_opts.unstable_options => { + early_error( + error_format, + "`-C symbol-mangling-version=legacy` requires `-Z unstable-options`", + ); + } + (None, None) => {} + (None, smv) => { + early_warn( + error_format, + "`-Z symbol-mangling-version` is deprecated; use `-C symbol-mangling-version`", + ); + cg.symbol_mangling_version = smv; + } + _ => {} + } + if debugging_opts.instrument_coverage.is_some() && debugging_opts.instrument_coverage != Some(InstrumentCoverage::Off) { @@ -2103,19 +2203,17 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { ); } - // `-Z instrument-coverage` implies `-Z symbol-mangling-version=v0` - to ensure consistent + // `-Z instrument-coverage` implies `-C symbol-mangling-version=v0` - to ensure consistent // and reversible name mangling. Note, LLVM coverage tools can analyze coverage over // multiple runs, including some changes to source code; so mangled names must be consistent // across compilations. - match debugging_opts.symbol_mangling_version { - None => { - debugging_opts.symbol_mangling_version = Some(SymbolManglingVersion::V0); - } + match cg.symbol_mangling_version { + None => cg.symbol_mangling_version = Some(SymbolManglingVersion::V0), Some(SymbolManglingVersion::Legacy) => { early_warn( error_format, "-Z instrument-coverage requires symbol mangling version `v0`, \ - but `-Z symbol-mangling-version=legacy` was specified", + but `-C symbol-mangling-version=legacy` was specified", ); } Some(SymbolManglingVersion::V0) => {} @@ -2497,9 +2595,9 @@ impl PpMode { crate mod dep_tracking { use super::LdImpl; use super::{ - CFGuard, CrateType, DebugInfo, ErrorOutputType, InstrumentCoverage, LinkerPluginLto, - LocationDetail, LtoCli, OptLevel, OutputType, OutputTypes, Passes, SourceFileHashAlgorithm, - SwitchWithOptPath, SymbolManglingVersion, TrimmedDefPaths, + BranchProtection, CFGuard, CrateType, DebugInfo, ErrorOutputType, InstrumentCoverage, + LinkerPluginLto, LocationDetail, LtoCli, OptLevel, OutputType, OutputTypes, Passes, + SourceFileHashAlgorithm, SwitchWithOptPath, SymbolManglingVersion, TrimmedDefPaths, }; use crate::lint; use crate::options::WasiExecModel; @@ -2593,6 +2691,7 @@ crate mod dep_tracking { OutputType, RealFileName, LocationDetail, + BranchProtection, ); impl<T1, T2> DepTrackingHash for (T1, T2) diff --git a/compiler/rustc_session/src/cstore.rs b/compiler/rustc_session/src/cstore.rs index 59e7abc2ea3..281fc887633 100644 --- a/compiler/rustc_session/src/cstore.rs +++ b/compiler/rustc_session/src/cstore.rs @@ -201,6 +201,12 @@ pub trait CrateStore: std::fmt::Debug { index_guess: u32, hash: ExpnHash, ) -> ExpnId; + + /// Imports all `SourceFile`s from the given crate into the current session. + /// This normally happens automatically when we decode a `Span` from + /// that crate's metadata - however, the incr comp cache needs + /// to trigger this manually when decoding a foreign `Span` + fn import_source_files(&self, sess: &Session, cnum: CrateNum); } pub type CrateStoreDyn = dyn CrateStore + sync::Sync; diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 9090524c933..0b9623d1c7d 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -412,9 +412,13 @@ mod desc { pub const parse_wasi_exec_model: &str = "either `command` or `reactor`"; pub const parse_split_debuginfo: &str = "one of supported split-debuginfo modes (`off`, `packed`, or `unpacked`)"; + pub const parse_split_dwarf_kind: &str = + "one of supported split dwarf modes (`split` or `single`)"; pub const parse_gcc_ld: &str = "one of: no value, `lld`"; pub const parse_stack_protector: &str = "one of (`none` (default), `basic`, `strong`, or `all`)"; + pub const parse_branch_protection: &str = + "a `,` separated combination of `bti`, `b-key`, `pac-ret`, or `leaf`"; } mod parse { @@ -939,6 +943,14 @@ mod parse { true } + crate fn parse_split_dwarf_kind(slot: &mut SplitDwarfKind, v: Option<&str>) -> bool { + match v.and_then(|s| SplitDwarfKind::from_str(s).ok()) { + Some(e) => *slot = e, + _ => return false, + } + true + } + crate fn parse_gcc_ld(slot: &mut Option<LdImpl>, v: Option<&str>) -> bool { match v { None => *slot = None, @@ -955,6 +967,32 @@ mod parse { } true } + + crate fn parse_branch_protection(slot: &mut BranchProtection, v: Option<&str>) -> bool { + match v { + Some(s) => { + for opt in s.split(',') { + match opt { + "bti" => slot.bti = true, + "pac-ret" if slot.pac_ret.is_none() => { + slot.pac_ret = Some(PacRet { leaf: false, key: PAuthKey::A }) + } + "leaf" => match slot.pac_ret.as_mut() { + Some(pac) => pac.leaf = true, + _ => return false, + }, + "b-key" => match slot.pac_ret.as_mut() { + Some(pac) => pac.key = PAuthKey::B, + _ => return false, + }, + _ => return false, + }; + } + } + _ => return false, + } + true + } } options! { @@ -1055,6 +1093,9 @@ options! { "how to handle split-debuginfo, a platform-specific option"), strip: Strip = (Strip::None, parse_strip, [UNTRACKED], "tell the linker which information to strip (`none` (default), `debuginfo` or `symbols`)"), + symbol_mangling_version: Option<SymbolManglingVersion> = (None, + parse_symbol_mangling_version, [TRACKED], + "which mangling version to use for symbol names ('legacy' (default) or 'v0')"), target_cpu: Option<String> = (None, parse_opt_string, [TRACKED], "select target processor (`rustc --print target-cpus` for details)"), target_feature: String = (String::new(), parse_target_feature, [TRACKED], @@ -1096,6 +1137,8 @@ options! { (default: no)"), borrowck: String = ("migrate".to_string(), parse_string, [UNTRACKED], "select which borrowck is used (`mir` or `migrate`) (default: `migrate`)"), + branch_protection: BranchProtection = (BranchProtection::default(), parse_branch_protection, [TRACKED], + "set options for branch target identification and pointer authentication on AArch64"), cgu_partitioning_strategy: Option<String> = (None, parse_opt_string, [TRACKED], "the codegen unit partitioning strategy to use"), chalk: bool = (false, parse_bool, [TRACKED], @@ -1197,7 +1240,7 @@ options! { instrument_coverage: Option<InstrumentCoverage> = (None, parse_instrument_coverage, [TRACKED], "instrument the generated code to support LLVM source-based code coverage \ reports (note, the compiler build config must include `profiler = true`); \ - implies `-Z symbol-mangling-version=v0`. Optional values are: + implies `-C symbol-mangling-version=v0`. Optional values are: `=all` (implicit value) `=except-unused-generics` `=except-unused-functions` @@ -1370,6 +1413,14 @@ options! { "control stack smash protection strategy (`rustc --print stack-protector-strategies` for details)"), strip: Strip = (Strip::None, parse_strip, [UNTRACKED], "tell the linker which information to strip (`none` (default), `debuginfo` or `symbols`)"), + split_dwarf_kind: SplitDwarfKind = (SplitDwarfKind::Split, parse_split_dwarf_kind, [UNTRACKED], + "split dwarf variant (only if -Csplit-debuginfo is enabled and on relevant platform) + (default: `split`) + + `split`: sections which do not require relocation are written into a DWARF object (`.dwo`) + file which is ignored by the linker + `single`: sections which do not require relocation are written into object file but ignored + by the linker"), split_dwarf_inlining: bool = (true, parse_bool, [UNTRACKED], "provide minimal debug info in the object/executable to facilitate online \ symbolication/stack traces in the absence of .dwo/.dwp files when using Split DWARF"), diff --git a/compiler/rustc_span/src/def_id.rs b/compiler/rustc_span/src/def_id.rs index d15befbf287..f6b0785a07c 100644 --- a/compiler/rustc_span/src/def_id.rs +++ b/compiler/rustc_span/src/def_id.rs @@ -316,17 +316,23 @@ impl fmt::Debug for DefId { rustc_data_structures::define_id_collections!(DefIdMap, DefIdSet, DefId); -/// A LocalDefId is equivalent to a DefId with `krate == LOCAL_CRATE`. Since +/// A `LocalDefId` is equivalent to a `DefId` with `krate == LOCAL_CRATE`. Since /// we encode this information in the type, we can ensure at compile time that -/// no DefIds from upstream crates get thrown into the mix. There are quite a -/// few cases where we know that only DefIds from the local crate are expected -/// and a DefId from a different crate would signify a bug somewhere. This -/// is when LocalDefId comes in handy. +/// no `DefId`s from upstream crates get thrown into the mix. There are quite a +/// few cases where we know that only `DefId`s from the local crate are expected; +/// a `DefId` from a different crate would signify a bug somewhere. This +/// is when `LocalDefId` comes in handy. #[derive(Clone, Copy, PartialEq, Eq, Hash)] pub struct LocalDefId { pub local_def_index: DefIndex, } +// To ensure correctness of incremental compilation, +// `LocalDefId` must not implement `Ord` or `PartialOrd`. +// See https://github.com/rust-lang/rust/issues/90317. +impl !Ord for LocalDefId {} +impl !PartialOrd for LocalDefId {} + pub const CRATE_DEF_ID: LocalDefId = LocalDefId { local_def_index: CRATE_DEF_INDEX }; impl Idx for LocalDefId { diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 51a7a2644f6..84cf8878af8 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -788,6 +788,7 @@ symbols! { literal, llvm_asm, load, + loaded_from_disk, local, local_inner_macros, log10f32, diff --git a/compiler/rustc_symbol_mangling/src/lib.rs b/compiler/rustc_symbol_mangling/src/lib.rs index 65b5852bc39..1f38240ee41 100644 --- a/compiler/rustc_symbol_mangling/src/lib.rs +++ b/compiler/rustc_symbol_mangling/src/lib.rs @@ -237,7 +237,7 @@ fn compute_symbol_name<'tcx>( // Pick the crate responsible for the symbol mangling version, which has to: // 1. be stable for each instance, whether it's being defined or imported - // 2. obey each crate's own `-Z symbol-mangling-version`, as much as possible + // 2. obey each crate's own `-C symbol-mangling-version`, as much as possible // We solve these as follows: // 1. because symbol names depend on both `def_id` and `instantiating_crate`, // both their `CrateNum`s are stable for any given instance, so we can pick @@ -245,7 +245,7 @@ fn compute_symbol_name<'tcx>( // 2. we favor `instantiating_crate` where possible (i.e. when `Some`) let mangling_version_crate = instantiating_crate.unwrap_or(def_id.krate); let mangling_version = if mangling_version_crate == LOCAL_CRATE { - tcx.sess.opts.debugging_opts.get_symbol_mangling_version() + tcx.sess.opts.get_symbol_mangling_version() } else { tcx.symbol_mangling_version(mangling_version_crate) }; diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 43913183694..ca1949b9f75 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -479,7 +479,7 @@ pub enum SplitDebuginfo { /// /// * Windows - not supported /// * macOS - supported, scattered object files - /// * ELF - supported, scattered `*.dwo` files + /// * ELF - supported, scattered `*.dwo` or `*.o` files (see `SplitDwarfKind`) Unpacked, } diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index b5c5724f56e..a9ae0ec53c7 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -1567,14 +1567,14 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> { self.tcx.find_map_relevant_impl(trait_def_id, trait_ref.skip_binder().self_ty(), Some) }; let required_trait_path = self.tcx.def_path_str(trait_ref.def_id()); - let all_traits = self.tcx.all_traits(()); - let traits_with_same_path: std::collections::BTreeSet<_> = all_traits - .iter() - .filter(|trait_def_id| **trait_def_id != trait_ref.def_id()) - .filter(|trait_def_id| self.tcx.def_path_str(**trait_def_id) == required_trait_path) + let traits_with_same_path: std::collections::BTreeSet<_> = self + .tcx + .all_traits() + .filter(|trait_def_id| *trait_def_id != trait_ref.def_id()) + .filter(|trait_def_id| self.tcx.def_path_str(*trait_def_id) == required_trait_path) .collect(); for trait_with_same_path in traits_with_same_path { - if let Some(impl_def_id) = get_trait_impl(*trait_with_same_path) { + if let Some(impl_def_id) = get_trait_impl(trait_with_same_path) { let impl_span = self.tcx.def_span(impl_def_id); err.span_help(impl_span, "trait impl with same name found"); let trait_crate = self.tcx.crate_name(trait_with_same_path.krate); diff --git a/compiler/rustc_traits/src/chalk/db.rs b/compiler/rustc_traits/src/chalk/db.rs index 1b79e537634..c38680651af 100644 --- a/compiler/rustc_traits/src/chalk/db.rs +++ b/compiler/rustc_traits/src/chalk/db.rs @@ -724,7 +724,7 @@ impl<'tcx> chalk_ir::UnificationDatabase<RustInterner<'tcx>> for RustIrDatabase< /// var bound at index `0`. For types, we use a `BoundVar` index equal to /// the type parameter index. For regions, we use the `BoundRegionKind::BrNamed` /// variant (which has a `DefId`). -fn bound_vars_for_item(tcx: TyCtxt<'tcx>, def_id: DefId) -> SubstsRef<'tcx> { +fn bound_vars_for_item<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> SubstsRef<'tcx> { InternalSubsts::for_item(tcx, def_id, |param, substs| match param.kind { ty::GenericParamDefKind::Type { .. } => tcx .mk_ty(ty::Bound( diff --git a/compiler/rustc_traits/src/implied_outlives_bounds.rs b/compiler/rustc_traits/src/implied_outlives_bounds.rs index 92f2760e62c..90c698db8fb 100644 --- a/compiler/rustc_traits/src/implied_outlives_bounds.rs +++ b/compiler/rustc_traits/src/implied_outlives_bounds.rs @@ -138,7 +138,7 @@ fn compute_implied_outlives_bounds<'tcx>( /// this down to determine what relationships would have to hold for /// `T: 'a` to hold. We get to assume that the caller has validated /// those relationships. -fn implied_bounds_from_components( +fn implied_bounds_from_components<'tcx>( sub_region: ty::Region<'tcx>, sup_components: SmallVec<[Component<'tcx>; 4]>, ) -> Vec<OutlivesBound<'tcx>> { diff --git a/compiler/rustc_traits/src/lib.rs b/compiler/rustc_traits/src/lib.rs index 8612499623b..b814b984dae 100644 --- a/compiler/rustc_traits/src/lib.rs +++ b/compiler/rustc_traits/src/lib.rs @@ -2,7 +2,6 @@ //! the guts are broken up into modules; see the comments in those modules. #![feature(crate_visibility_modifier)] -#![feature(in_band_lifetimes)] #![feature(nll)] #![recursion_limit = "256"] diff --git a/compiler/rustc_traits/src/normalize_erasing_regions.rs b/compiler/rustc_traits/src/normalize_erasing_regions.rs index 87530cf9961..46c2f7e4cf2 100644 --- a/compiler/rustc_traits/src/normalize_erasing_regions.rs +++ b/compiler/rustc_traits/src/normalize_erasing_regions.rs @@ -57,7 +57,7 @@ fn try_normalize_after_erasing_regions<'tcx, T: TypeFoldable<'tcx> + PartialEq + }) } -fn not_outlives_predicate(p: &ty::Predicate<'tcx>) -> bool { +fn not_outlives_predicate<'tcx>(p: &ty::Predicate<'tcx>) -> bool { match p.kind().skip_binder() { ty::PredicateKind::RegionOutlives(..) | ty::PredicateKind::TypeOutlives(..) => false, ty::PredicateKind::Trait(..) diff --git a/compiler/rustc_traits/src/type_op.rs b/compiler/rustc_traits/src/type_op.rs index cc0b7d5817b..6fcac9fcdc6 100644 --- a/compiler/rustc_traits/src/type_op.rs +++ b/compiler/rustc_traits/src/type_op.rs @@ -70,7 +70,7 @@ struct AscribeUserTypeCx<'me, 'tcx> { fulfill_cx: &'me mut dyn TraitEngine<'tcx>, } -impl AscribeUserTypeCx<'me, 'tcx> { +impl<'me, 'tcx> AscribeUserTypeCx<'me, 'tcx> { fn normalize<T>(&mut self, value: T) -> T where T: TypeFoldable<'tcx>, @@ -195,7 +195,7 @@ fn type_op_eq<'tcx>( }) } -fn type_op_normalize<T>( +fn type_op_normalize<'tcx, T>( infcx: &InferCtxt<'_, 'tcx>, fulfill_cx: &mut dyn TraitEngine<'tcx>, key: ParamEnvAnd<'tcx, Normalize<T>>, @@ -210,28 +210,28 @@ where Ok(value) } -fn type_op_normalize_ty( +fn type_op_normalize_ty<'tcx>( tcx: TyCtxt<'tcx>, canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Normalize<Ty<'tcx>>>>, ) -> Result<&'tcx Canonical<'tcx, QueryResponse<'tcx, Ty<'tcx>>>, NoSolution> { tcx.infer_ctxt().enter_canonical_trait_query(&canonicalized, type_op_normalize) } -fn type_op_normalize_predicate( +fn type_op_normalize_predicate<'tcx>( tcx: TyCtxt<'tcx>, canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Normalize<Predicate<'tcx>>>>, ) -> Result<&'tcx Canonical<'tcx, QueryResponse<'tcx, Predicate<'tcx>>>, NoSolution> { tcx.infer_ctxt().enter_canonical_trait_query(&canonicalized, type_op_normalize) } -fn type_op_normalize_fn_sig( +fn type_op_normalize_fn_sig<'tcx>( tcx: TyCtxt<'tcx>, canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Normalize<FnSig<'tcx>>>>, ) -> Result<&'tcx Canonical<'tcx, QueryResponse<'tcx, FnSig<'tcx>>>, NoSolution> { tcx.infer_ctxt().enter_canonical_trait_query(&canonicalized, type_op_normalize) } -fn type_op_normalize_poly_fn_sig( +fn type_op_normalize_poly_fn_sig<'tcx>( tcx: TyCtxt<'tcx>, canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Normalize<PolyFnSig<'tcx>>>>, ) -> Result<&'tcx Canonical<'tcx, QueryResponse<'tcx, PolyFnSig<'tcx>>>, NoSolution> { diff --git a/compiler/rustc_typeck/src/astconv/generics.rs b/compiler/rustc_typeck/src/astconv/generics.rs index caa5c71e21c..956696546da 100644 --- a/compiler/rustc_typeck/src/astconv/generics.rs +++ b/compiler/rustc_typeck/src/astconv/generics.rs @@ -104,7 +104,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { GenericArg::Type(hir::Ty { kind: hir::TyKind::Array(_, len), .. }), GenericParamDefKind::Const { .. }, ) if tcx.type_of(param.def_id) == tcx.types.usize => { - let snippet = sess.source_map().span_to_snippet(tcx.hir().span(len.hir_id)); + let snippet = sess.source_map().span_to_snippet(tcx.hir().span(len.hir_id())); if let Ok(snippet) = snippet { err.span_suggestion( arg.span(), diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs index 8db706c3709..8226ffbccc4 100644 --- a/compiler/rustc_typeck/src/astconv/mod.rs +++ b/compiler/rustc_typeck/src/astconv/mod.rs @@ -2363,8 +2363,14 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { self.normalize_ty(span, tcx.at(span).type_of(def_id).subst(tcx, substs)) } hir::TyKind::Array(ref ty, ref length) => { - let length_def_id = tcx.hir().local_def_id(length.hir_id); - let length = ty::Const::from_anon_const(tcx, length_def_id); + let length = match length { + &hir::ArrayLen::Infer(_, span) => self.ct_infer(tcx.types.usize, None, span), + hir::ArrayLen::Body(constant) => { + let length_def_id = tcx.hir().local_def_id(constant.hir_id); + ty::Const::from_anon_const(tcx, length_def_id) + } + }; + let array_ty = tcx.mk_ty(ty::Array(self.ast_ty_to_ty(ty), length)); self.normalize_ty(ast_ty.span, array_ty) } diff --git a/compiler/rustc_typeck/src/check/callee.rs b/compiler/rustc_typeck/src/check/callee.rs index e67ee1cab3d..eea8f40635d 100644 --- a/compiler/rustc_typeck/src/check/callee.rs +++ b/compiler/rustc_typeck/src/check/callee.rs @@ -496,7 +496,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { call_expr.span, call_expr, fn_sig.inputs(), - &expected_arg_tys, + expected_arg_tys, arg_exprs, fn_sig.c_variadic, TupleArgumentsFlag::DontTupleArguments, @@ -529,7 +529,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { call_expr.span, call_expr, fn_sig.inputs(), - &expected_arg_tys, + expected_arg_tys, arg_exprs, fn_sig.c_variadic, TupleArgumentsFlag::TupleArguments, diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs index 8d370e440ea..621938c9b78 100644 --- a/compiler/rustc_typeck/src/check/expr.rs +++ b/compiler/rustc_typeck/src/check/expr.rs @@ -1238,12 +1238,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn check_expr_repeat( &self, element: &'tcx hir::Expr<'tcx>, - count: &'tcx hir::AnonConst, + count: &'tcx hir::ArrayLen, expected: Expectation<'tcx>, _expr: &'tcx hir::Expr<'tcx>, ) -> Ty<'tcx> { let tcx = self.tcx; - let count = self.to_const(count); + let count = self.array_length_to_const(count); let uty = match expected { ExpectHasType(uty) => match *uty.kind() { diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs index 67630fd4e58..1aca2911533 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs @@ -498,6 +498,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty } + pub fn array_length_to_const(&self, length: &hir::ArrayLen) -> &'tcx ty::Const<'tcx> { + match length { + &hir::ArrayLen::Infer(_, span) => self.ct_infer(self.tcx.types.usize, None, span), + hir::ArrayLen::Body(anon_const) => self.to_const(anon_const), + } + } + pub fn to_const(&self, ast_c: &hir::AnonConst) -> &'tcx ty::Const<'tcx> { let const_def_id = self.tcx.hir().local_def_id(ast_c.hir_id); let c = ty::Const::from_anon_const(self.tcx, const_def_id); diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs index 11b63a99043..e796fe58170 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs @@ -62,7 +62,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { sp, expr, &err_inputs, - &[], + vec![], args_no_rcvr, false, tuple_arguments, @@ -73,7 +73,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let method = method.unwrap(); // HACK(eddyb) ignore self in the definition (see above). - let expected_arg_tys = self.expected_inputs_for_expected_output( + let expected_input_tys = self.expected_inputs_for_expected_output( sp, expected, method.sig.output(), @@ -83,7 +83,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { sp, expr, &method.sig.inputs()[1..], - &expected_arg_tys[..], + expected_input_tys, args_no_rcvr, method.sig.c_variadic, tuple_arguments, @@ -96,34 +96,43 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// method calls and overloaded operators. pub(in super::super) fn check_argument_types( &self, - sp: Span, - expr: &'tcx hir::Expr<'tcx>, - fn_inputs: &[Ty<'tcx>], - expected_arg_tys: &[Ty<'tcx>], - args: &'tcx [hir::Expr<'tcx>], + // Span enclosing the call site + call_span: Span, + // Expression of the call site + call_expr: &'tcx hir::Expr<'tcx>, + // Types (as defined in the *signature* of the target function) + formal_input_tys: &[Ty<'tcx>], + // More specific expected types, after unifying with caller output types + expected_input_tys: Vec<Ty<'tcx>>, + // The expressions for each provided argument + provided_args: &'tcx [hir::Expr<'tcx>], + // Whether the function is variadic, for example when imported from C c_variadic: bool, + // Whether the arguments have been bundled in a tuple (ex: closures) tuple_arguments: TupleArgumentsFlag, - def_id: Option<DefId>, + // The DefId for the function being called, for better error messages + fn_def_id: Option<DefId>, ) { let tcx = self.tcx; // Grab the argument types, supplying fresh type variables // if the wrong number of arguments were supplied - let supplied_arg_count = if tuple_arguments == DontTupleArguments { args.len() } else { 1 }; + let supplied_arg_count = + if tuple_arguments == DontTupleArguments { provided_args.len() } else { 1 }; // All the input types from the fn signature must outlive the call // so as to validate implied bounds. - for (&fn_input_ty, arg_expr) in iter::zip(fn_inputs, args) { + for (&fn_input_ty, arg_expr) in iter::zip(formal_input_tys, provided_args) { self.register_wf_obligation(fn_input_ty.into(), arg_expr.span, traits::MiscObligation); } - let expected_arg_count = fn_inputs.len(); + let expected_arg_count = formal_input_tys.len(); let param_count_error = |expected_count: usize, arg_count: usize, error_code: &str, c_variadic: bool, sugg_unit: bool| { - let (span, start_span, args, ctor_of) = match &expr.kind { + let (span, start_span, args, ctor_of) = match &call_expr.kind { hir::ExprKind::Call( hir::Expr { span, @@ -156,14 +165,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &args[1..], // Skip the receiver. None, // methods are never ctors ), - k => span_bug!(sp, "checking argument types on a non-call: `{:?}`", k), + k => span_bug!(call_span, "checking argument types on a non-call: `{:?}`", k), }; - let arg_spans = if args.is_empty() { + let arg_spans = if provided_args.is_empty() { // foo() // ^^^-- supplied 0 arguments // | // expected 2 arguments - vec![tcx.sess.source_map().next_point(start_span).with_hi(sp.hi())] + vec![tcx.sess.source_map().next_point(start_span).with_hi(call_span.hi())] } else { // foo(1, 2, 3) // ^^^ - - - supplied 3 arguments @@ -196,7 +205,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); } - if let Some(def_id) = def_id { + if let Some(def_id) = fn_def_id { if let Some(def_span) = tcx.def_ident_span(def_id) { let mut spans: MultiSpan = def_span.into(); @@ -218,7 +227,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } if sugg_unit { - let sugg_span = tcx.sess.source_map().end_point(expr.span); + let sugg_span = tcx.sess.source_map().end_point(call_expr.span); // remove closing `)` from the span let sugg_span = sugg_span.shrink_to_lo(); err.span_suggestion( @@ -240,110 +249,148 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { err.emit(); }; - let mut expected_arg_tys = expected_arg_tys.to_vec(); - - let formal_tys = if tuple_arguments == TupleArguments { - let tuple_type = self.structurally_resolved_type(sp, fn_inputs[0]); + let (formal_input_tys, expected_input_tys) = if tuple_arguments == TupleArguments { + let tuple_type = self.structurally_resolved_type(call_span, formal_input_tys[0]); match tuple_type.kind() { - ty::Tuple(arg_types) if arg_types.len() != args.len() => { - param_count_error(arg_types.len(), args.len(), "E0057", false, false); - expected_arg_tys = vec![]; - self.err_args(args.len()) + ty::Tuple(arg_types) if arg_types.len() != provided_args.len() => { + param_count_error(arg_types.len(), provided_args.len(), "E0057", false, false); + (self.err_args(provided_args.len()), vec![]) } ty::Tuple(arg_types) => { - expected_arg_tys = match expected_arg_tys.get(0) { + let expected_input_tys = match expected_input_tys.get(0) { Some(&ty) => match ty.kind() { ty::Tuple(ref tys) => tys.iter().map(|k| k.expect_ty()).collect(), _ => vec![], }, None => vec![], }; - arg_types.iter().map(|k| k.expect_ty()).collect() + (arg_types.iter().map(|k| k.expect_ty()).collect(), expected_input_tys) } _ => { struct_span_err!( tcx.sess, - sp, + call_span, E0059, "cannot use call notation; the first type parameter \ for the function trait is neither a tuple nor unit" ) .emit(); - expected_arg_tys = vec![]; - self.err_args(args.len()) + (self.err_args(provided_args.len()), vec![]) } } } else if expected_arg_count == supplied_arg_count { - fn_inputs.to_vec() + (formal_input_tys.to_vec(), expected_input_tys) } else if c_variadic { if supplied_arg_count >= expected_arg_count { - fn_inputs.to_vec() + (formal_input_tys.to_vec(), expected_input_tys) } else { param_count_error(expected_arg_count, supplied_arg_count, "E0060", true, false); - expected_arg_tys = vec![]; - self.err_args(supplied_arg_count) + (self.err_args(supplied_arg_count), vec![]) } } else { // is the missing argument of type `()`? - let sugg_unit = if expected_arg_tys.len() == 1 && supplied_arg_count == 0 { - self.resolve_vars_if_possible(expected_arg_tys[0]).is_unit() - } else if fn_inputs.len() == 1 && supplied_arg_count == 0 { - self.resolve_vars_if_possible(fn_inputs[0]).is_unit() + let sugg_unit = if expected_input_tys.len() == 1 && supplied_arg_count == 0 { + self.resolve_vars_if_possible(expected_input_tys[0]).is_unit() + } else if formal_input_tys.len() == 1 && supplied_arg_count == 0 { + self.resolve_vars_if_possible(formal_input_tys[0]).is_unit() } else { false }; param_count_error(expected_arg_count, supplied_arg_count, "E0061", false, sugg_unit); - expected_arg_tys = vec![]; - self.err_args(supplied_arg_count) + (self.err_args(supplied_arg_count), vec![]) }; debug!( - "check_argument_types: formal_tys={:?}", - formal_tys.iter().map(|t| self.ty_to_string(*t)).collect::<Vec<String>>() + "check_argument_types: formal_input_tys={:?}", + formal_input_tys.iter().map(|t| self.ty_to_string(*t)).collect::<Vec<String>>() ); - // If there is no expectation, expect formal_tys. - let expected_arg_tys = - if !expected_arg_tys.is_empty() { expected_arg_tys } else { formal_tys.clone() }; + // If there is no expectation, expect formal_input_tys. + let expected_input_tys = if !expected_input_tys.is_empty() { + expected_input_tys + } else { + formal_input_tys.clone() + }; + + assert_eq!(expected_input_tys.len(), formal_input_tys.len()); + // Keep track of the fully coerced argument types let mut final_arg_types: Vec<(usize, Ty<'_>, Ty<'_>)> = vec![]; + // We introduce a helper function to demand that a given argument satisfy a given input + // This is more complicated than just checking type equality, as arguments could be coerced + // This version writes those types back so further type checking uses the narrowed types + let demand_compatible = |idx, final_arg_types: &mut Vec<(usize, Ty<'tcx>, Ty<'tcx>)>| { + let formal_input_ty: Ty<'tcx> = formal_input_tys[idx]; + let expected_input_ty: Ty<'tcx> = expected_input_tys[idx]; + let provided_arg = &provided_args[idx]; + + debug!("checking argument {}: {:?} = {:?}", idx, provided_arg, formal_input_ty); + + // The special-cased logic below has three functions: + // 1. Provide as good of an expected type as possible. + let expectation = Expectation::rvalue_hint(self, expected_input_ty); + + let checked_ty = self.check_expr_with_expectation(provided_arg, expectation); + + // 2. Coerce to the most detailed type that could be coerced + // to, which is `expected_ty` if `rvalue_hint` returns an + // `ExpectHasType(expected_ty)`, or the `formal_ty` otherwise. + let coerced_ty = expectation.only_has_type(self).unwrap_or(formal_input_ty); + + // Keep track of these for below + final_arg_types.push((idx, checked_ty, coerced_ty)); + + // Cause selection errors caused by resolving a single argument to point at the + // argument and not the call. This is otherwise redundant with the `demand_coerce` + // call immediately after, but it lets us customize the span pointed to in the + // fulfillment error to be more accurate. + let _ = + self.resolve_vars_with_obligations_and_mutate_fulfillment(coerced_ty, |errors| { + self.point_at_type_arg_instead_of_call_if_possible(errors, call_expr); + self.point_at_arg_instead_of_call_if_possible( + errors, + &final_arg_types, + call_expr, + call_span, + provided_args, + ); + }); + + // We're processing function arguments so we definitely want to use + // two-phase borrows. + self.demand_coerce(&provided_arg, checked_ty, coerced_ty, None, AllowTwoPhase::Yes); + + // 3. Relate the expected type and the formal one, + // if the expected type was used for the coercion. + self.demand_suptype(provided_arg.span, formal_input_ty, coerced_ty); + }; + // Check the arguments. // We do this in a pretty awful way: first we type-check any arguments // that are not closures, then we type-check the closures. This is so // that we have more information about the types of arguments when we // type-check the functions. This isn't really the right way to do this. for check_closures in [false, true] { - debug!("check_closures={}", check_closures); - // More awful hacks: before we check argument types, try to do // an "opportunistic" trait resolution of any trait bounds on // the call. This helps coercions. if check_closures { self.select_obligations_where_possible(false, |errors| { - self.point_at_type_arg_instead_of_call_if_possible(errors, expr); + self.point_at_type_arg_instead_of_call_if_possible(errors, call_expr); self.point_at_arg_instead_of_call_if_possible( errors, &final_arg_types, - expr, - sp, - &args, + call_expr, + call_span, + &provided_args, ); }) } - // For C-variadic functions, we don't have a declared type for all of - // the arguments hence we only do our usual type checking with - // the arguments who's types we do know. - let t = if c_variadic { - expected_arg_count - } else if tuple_arguments == TupleArguments { - args.len() - } else { - supplied_arg_count - }; - for (i, arg) in args.iter().take(t).enumerate() { + let minimum_input_count = formal_input_tys.len(); + for (idx, arg) in provided_args.iter().enumerate() { // Warn only for the first loop (the "no closures" one). // Closure arguments themselves can't be diverging, but // a previous argument can, e.g., `foo(panic!(), || {})`. @@ -351,53 +398,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.warn_if_unreachable(arg.hir_id, arg.span, "expression"); } - let is_closure = matches!(arg.kind, ExprKind::Closure(..)); + // For C-variadic functions, we don't have a declared type for all of + // the arguments hence we only do our usual type checking with + // the arguments who's types we do know. However, we *can* check + // for unreachable expressions (see above). + // FIXME: unreachable warning current isn't emitted + if idx >= minimum_input_count { + continue; + } + let is_closure = matches!(arg.kind, ExprKind::Closure(..)); if is_closure != check_closures { continue; } - let formal_ty = formal_tys[i]; - debug!("checking argument {}: {:?} = {:?}", i, arg, formal_ty); - - // The special-cased logic below has three functions: - // 1. Provide as good of an expected type as possible. - let expected = Expectation::rvalue_hint(self, expected_arg_tys[i]); - - let checked_ty = self.check_expr_with_expectation(&arg, expected); - - // 2. Coerce to the most detailed type that could be coerced - // to, which is `expected_ty` if `rvalue_hint` returns an - // `ExpectHasType(expected_ty)`, or the `formal_ty` otherwise. - let coerce_ty = expected.only_has_type(self).unwrap_or(formal_ty); - - final_arg_types.push((i, checked_ty, coerce_ty)); - - // Cause selection errors caused by resolving a single argument to point at the - // argument and not the call. This is otherwise redundant with the `demand_coerce` - // call immediately after, but it lets us customize the span pointed to in the - // fulfillment error to be more accurate. - let _ = self.resolve_vars_with_obligations_and_mutate_fulfillment( - coerce_ty, - |errors| { - self.point_at_type_arg_instead_of_call_if_possible(errors, expr); - self.point_at_arg_instead_of_call_if_possible( - errors, - &final_arg_types, - expr, - sp, - args, - ); - }, - ); - - // We're processing function arguments so we definitely want to use - // two-phase borrows. - self.demand_coerce(&arg, checked_ty, coerce_ty, None, AllowTwoPhase::Yes); - - // 3. Relate the expected type and the formal one, - // if the expected type was used for the coercion. - self.demand_suptype(arg.span, formal_ty, coerce_ty); + demand_compatible(idx, &mut final_arg_types); } } @@ -410,7 +425,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { MissingCastForVariadicArg { sess, span, ty, cast_ty }.diagnostic().emit() } - for arg in args.iter().skip(expected_arg_count) { + for arg in provided_args.iter().skip(expected_arg_count) { let arg_ty = self.check_expr(&arg); // There are a few types which get autopromoted when passed via varargs diff --git a/compiler/rustc_typeck/src/check/method/mod.rs b/compiler/rustc_typeck/src/check/method/mod.rs index 03518dc8d12..f7f4c52c2a1 100644 --- a/compiler/rustc_typeck/src/check/method/mod.rs +++ b/compiler/rustc_typeck/src/check/method/mod.rs @@ -7,7 +7,7 @@ mod prelude2021; pub mod probe; mod suggest; -pub use self::suggest::{SelfSource, TraitInfo}; +pub use self::suggest::SelfSource; pub use self::CandidateSource::*; pub use self::MethodError::*; @@ -31,7 +31,6 @@ use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; use self::probe::{IsSuggestion, ProbeScope}; pub fn provide(providers: &mut ty::query::Providers) { - suggest::provide(providers); probe::provide(providers); } diff --git a/compiler/rustc_typeck/src/check/method/suggest.rs b/compiler/rustc_typeck/src/check/method/suggest.rs index f3a5fbbb444..7f9c75c7fee 100644 --- a/compiler/rustc_typeck/src/check/method/suggest.rs +++ b/compiler/rustc_typeck/src/check/method/suggest.rs @@ -5,8 +5,8 @@ use crate::check::FnCtxt; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder}; use rustc_hir as hir; -use rustc_hir::def::{DefKind, Namespace, Res}; -use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_INDEX}; +use rustc_hir::def::Namespace; +use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::lang_items::LangItem; use rustc_hir::{ExprKind, Node, QPath}; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; @@ -1922,76 +1922,10 @@ impl Ord for TraitInfo { } } -/// Retrieves all traits in this crate and any dependent crates. +/// Retrieves all traits in this crate and any dependent crates, +/// and wraps them into `TraitInfo` for custom sorting. pub fn all_traits(tcx: TyCtxt<'_>) -> Vec<TraitInfo> { - tcx.all_traits(()).iter().map(|&def_id| TraitInfo { def_id }).collect() -} - -/// Computes all traits in this crate and any dependent crates. -fn compute_all_traits(tcx: TyCtxt<'_>, (): ()) -> &[DefId] { - use hir::itemlikevisit; - - let mut traits = vec![]; - - // Crate-local: - - struct Visitor<'a> { - traits: &'a mut Vec<DefId>, - } - - impl<'v, 'a> itemlikevisit::ItemLikeVisitor<'v> for Visitor<'a> { - fn visit_item(&mut self, i: &'v hir::Item<'v>) { - match i.kind { - hir::ItemKind::Trait(..) | hir::ItemKind::TraitAlias(..) => { - self.traits.push(i.def_id.to_def_id()); - } - _ => (), - } - } - - fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem<'_>) {} - - fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem<'_>) {} - - fn visit_foreign_item(&mut self, _foreign_item: &hir::ForeignItem<'_>) {} - } - - tcx.hir().visit_all_item_likes(&mut Visitor { traits: &mut traits }); - - // Cross-crate: - - let mut external_mods = FxHashSet::default(); - fn handle_external_res( - tcx: TyCtxt<'_>, - traits: &mut Vec<DefId>, - external_mods: &mut FxHashSet<DefId>, - res: Res<!>, - ) { - match res { - Res::Def(DefKind::Trait | DefKind::TraitAlias, def_id) => { - traits.push(def_id); - } - Res::Def(DefKind::Mod, def_id) => { - if !external_mods.insert(def_id) { - return; - } - for child in tcx.item_children(def_id).iter() { - handle_external_res(tcx, traits, external_mods, child.res) - } - } - _ => {} - } - } - for &cnum in tcx.crates(()).iter() { - let def_id = DefId { krate: cnum, index: CRATE_DEF_INDEX }; - handle_external_res(tcx, &mut traits, &mut external_mods, Res::Def(DefKind::Mod, def_id)); - } - - tcx.arena.alloc_from_iter(traits) -} - -pub fn provide(providers: &mut ty::query::Providers) { - providers.all_traits = compute_all_traits; + tcx.all_traits().map(|def_id| TraitInfo { def_id }).collect() } fn find_use_placement<'tcx>(tcx: TyCtxt<'tcx>, target_module: LocalDefId) -> (Option<Span>, bool) { diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index e7b728d491b..41c8a37a71a 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -182,7 +182,7 @@ crate fn placeholder_type_error<'tcx>( sugg.push((span, format!(", {}", type_name))); } - let mut err = bad_placeholder_type(tcx, placeholder_types, kind); + let mut err = bad_placeholder(tcx, "type", placeholder_types, kind); // Suggest, but only if it is not a function in const or static if suggest { @@ -295,7 +295,9 @@ impl<'tcx> Visitor<'tcx> for CollectItemTypesVisitor<'tcx> { if let hir::ExprKind::Closure(..) = expr.kind { let def_id = self.tcx.hir().local_def_id(expr.hir_id); self.tcx.ensure().generics_of(def_id); - self.tcx.ensure().type_of(def_id); + // We do not call `type_of` for closures here as that + // depends on typecheck and would therefore hide + // any further errors in case one typeck fails. } intravisit::walk_expr(self, expr); } @@ -314,8 +316,9 @@ impl<'tcx> Visitor<'tcx> for CollectItemTypesVisitor<'tcx> { /////////////////////////////////////////////////////////////////////////// // Utility types and common code for the above passes. -fn bad_placeholder_type<'tcx>( +fn bad_placeholder<'tcx>( tcx: TyCtxt<'tcx>, + placeholder_kind: &'static str, mut spans: Vec<Span>, kind: &'static str, ) -> rustc_errors::DiagnosticBuilder<'tcx> { @@ -326,7 +329,8 @@ fn bad_placeholder_type<'tcx>( tcx.sess, spans.clone(), E0121, - "the type placeholder `_` is not allowed within types on item signatures for {}", + "the {} placeholder `_` is not allowed within types on item signatures for {}", + placeholder_kind, kind ); for span in spans { @@ -393,7 +397,7 @@ impl<'tcx> AstConv<'tcx> for ItemCtxt<'tcx> { _: Option<&ty::GenericParamDef>, span: Span, ) -> &'tcx Const<'tcx> { - bad_placeholder_type(self.tcx(), vec![span], "generic").emit(); + bad_placeholder(self.tcx(), "const", vec![span], "generic").emit(); // Typeck doesn't expect erased regions to be returned from `type_of`. let ty = self.tcx.fold_regions(ty, &mut false, |r, _| match r { ty::ReErased => self.tcx.lifetimes.re_static, @@ -1482,7 +1486,11 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics { // `enum` discriminants (i.e. `D` in `enum Foo { Bar = D }`), // as they shouldn't be able to cause query cycle errors. Node::Expr(&Expr { kind: ExprKind::Repeat(_, ref constant), .. }) - | Node::Variant(Variant { disr_expr: Some(ref constant), .. }) + if constant.hir_id() == hir_id => + { + Some(parent_def_id.to_def_id()) + } + Node::Variant(Variant { disr_expr: Some(ref constant), .. }) if constant.hir_id == hir_id => { Some(parent_def_id.to_def_id()) @@ -1788,7 +1796,7 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: DefId) -> ty::PolyFnSig<'_> { let mut visitor = PlaceholderHirTyCollector::default(); visitor.visit_ty(ty); - let mut diag = bad_placeholder_type(tcx, visitor.0, "return type"); + let mut diag = bad_placeholder(tcx, "type", visitor.0, "return type"); let ret_ty = fn_sig.skip_binder().output(); if !ret_ty.references_error() { if !ret_ty.is_closure() { @@ -2894,7 +2902,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs { } } } else if attr.has_name(sym::instruction_set) { - codegen_fn_attrs.instruction_set = match attr.meta().map(|i| i.kind) { + codegen_fn_attrs.instruction_set = match attr.meta_kind() { Some(MetaItemKind::List(ref items)) => match items.as_slice() { [NestedMetaItem::MetaItem(set)] => { let segments = @@ -2999,7 +3007,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs { if !attr.has_name(sym::inline) { return ia; } - match attr.meta().map(|i| i.kind) { + match attr.meta_kind() { Some(MetaItemKind::Word) => InlineAttr::Hint, Some(MetaItemKind::List(ref items)) => { inline_span = Some(attr.span); @@ -3038,7 +3046,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs { return ia; } let err = |sp, s| struct_span_err!(tcx.sess.diagnostic(), sp, E0722, "{}", s).emit(); - match attr.meta().map(|i| i.kind) { + match attr.meta_kind() { Some(MetaItemKind::Word) => { err(attr.span, "expected one argument"); ia diff --git a/compiler/rustc_typeck/src/collect/type_of.rs b/compiler/rustc_typeck/src/collect/type_of.rs index 99fddcb00ce..ae8d262fcf1 100644 --- a/compiler/rustc_typeck/src/collect/type_of.rs +++ b/compiler/rustc_typeck/src/collect/type_of.rs @@ -13,7 +13,7 @@ use rustc_span::symbol::Ident; use rustc_span::{Span, DUMMY_SP}; use super::ItemCtxt; -use super::{bad_placeholder_type, is_suggestable_infer_ty}; +use super::{bad_placeholder, is_suggestable_infer_ty}; /// Computes the relevant generic parameter for a potential generic const argument. /// @@ -470,14 +470,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> { Node::Field(field) => icx.to_ty(field.ty), - Node::Expr(&Expr { kind: ExprKind::Closure(.., gen), .. }) => { - let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id()); - if let Some(movability) = gen { - tcx.mk_generator(def_id.to_def_id(), substs, movability) - } else { - tcx.mk_closure(def_id.to_def_id(), substs) - } - } + Node::Expr(&Expr { kind: ExprKind::Closure(..), .. }) => tcx.typeck(def_id).node_type(hir_id), Node::AnonConst(_) if let Some(param) = tcx.opt_const_param_of(def_id) => { // We defer to `type_of` of the corresponding parameter @@ -490,7 +483,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> { match parent_node { Node::Ty(&Ty { kind: TyKind::Array(_, ref constant), .. }) | Node::Expr(&Expr { kind: ExprKind::Repeat(_, ref constant), .. }) - if constant.hir_id == hir_id => + if constant.hir_id() == hir_id => { tcx.types.usize } @@ -788,7 +781,7 @@ fn infer_placeholder_type<'a>( err.emit(); } None => { - let mut diag = bad_placeholder_type(tcx, vec![span], kind); + let mut diag = bad_placeholder(tcx, "type", vec![span], kind); if !ty.references_error() { let mut mk_nameable = MakeNameable::new(tcx); diff --git a/compiler/rustc_typeck/src/expr_use_visitor.rs b/compiler/rustc_typeck/src/expr_use_visitor.rs index 32b4018f626..1ae0ff30364 100644 --- a/compiler/rustc_typeck/src/expr_use_visitor.rs +++ b/compiler/rustc_typeck/src/expr_use_visitor.rs @@ -715,13 +715,14 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { debug!("walk_captures({:?})", closure_expr); - let closure_def_id = self.tcx().hir().local_def_id(closure_expr.hir_id).to_def_id(); - let upvars = self.tcx().upvars_mentioned(self.body_owner); + let tcx = self.tcx(); + let closure_def_id = tcx.hir().local_def_id(closure_expr.hir_id).to_def_id(); + let upvars = tcx.upvars_mentioned(self.body_owner); // For purposes of this function, generator and closures are equivalent. let body_owner_is_closure = matches!( - self.tcx().type_of(self.body_owner.to_def_id()).kind(), - ty::Closure(..) | ty::Generator(..) + tcx.hir().body_owner_kind(tcx.hir().local_def_id_to_hir_id(self.body_owner)), + hir::BodyOwnerKind::Closure, ); // If we have a nested closure, we want to include the fake reads present in the nested closure. |
