diff options
Diffstat (limited to 'compiler')
200 files changed, 3746 insertions, 2309 deletions
diff --git a/compiler/rustc/src/main.rs b/compiler/rustc/src/main.rs index c80fab99496..4edd095af10 100644 --- a/compiler/rustc/src/main.rs +++ b/compiler/rustc/src/main.rs @@ -1,25 +1,32 @@ -// Configure jemalloc as the `global_allocator` when configured. This is -// so that we use the sized deallocation apis jemalloc provides -// (namely `sdallocx`). +// A note about jemalloc: rustc uses jemalloc when built for CI and +// distribution. The obvious way to do this is with the `#[global_allocator]` +// mechanism. However, for complicated reasons (see +// https://github.com/rust-lang/rust/pull/81782#issuecomment-784438001 for some +// details) that mechanism doesn't work here. Also, we must use a consistent +// allocator across the rustc <-> llvm boundary, and `#[global_allocator]` +// wouldn't provide that. // -// The symbol overrides documented below are also performed so that we can -// ensure that we use a consistent allocator across the rustc <-> llvm boundary -#[cfg(feature = "jemalloc")] -#[global_allocator] -static ALLOC: tikv_jemallocator::Jemalloc = tikv_jemallocator::Jemalloc; - +// Instead, we use a lower-level mechanism. rustc is linked with jemalloc in a +// way such that jemalloc's implementation of `malloc`, `free`, etc., override +// the libc allocator's implementation. This means that Rust's `System` +// allocator, which calls `libc::malloc()` et al., is actually calling into +// jemalloc. +// +// A consequence of not using `GlobalAlloc` (and the `tikv-jemallocator` crate +// provides an impl of that trait, which is called `Jemalloc`) is that we +// cannot use the sized deallocation APIs (`sdallocx`) that jemalloc provides. +// It's unclear how much performance is lost because of this. +// +// As for the symbol overrides in `main` below: we're pulling in a static copy +// of jemalloc. We need to actually reference its symbols for it to get linked. +// The two crates we link to here, `std` and `rustc_driver`, are both dynamic +// libraries. So we must reference jemalloc symbols one way or another, because +// this file is the only object code in the rustc executable. #[cfg(feature = "tikv-jemalloc-sys")] use tikv_jemalloc_sys as jemalloc_sys; fn main() { - // Pull in jemalloc when enabled. - // - // Note that we're pulling in a static copy of jemalloc which means that to - // pull it in we need to actually reference its symbols for it to get - // linked. The two crates we link to here, std and rustc_driver, are both - // dynamic libraries. That means to pull in jemalloc we actually need to - // reference allocation symbols one way or another (as this file is the only - // object code in the rustc executable). + // See the comment at the top of this file for an explanation of this. #[cfg(feature = "tikv-jemalloc-sys")] { use std::os::raw::{c_int, c_void}; 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_lowering/src/path.rs b/compiler/rustc_ast_lowering/src/path.rs index 78afc339748..46928a18465 100644 --- a/compiler/rustc_ast_lowering/src/path.rs +++ b/compiler/rustc_ast_lowering/src/path.rs @@ -277,7 +277,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // See rustc_resolve::late::lifetimes::LifetimeContext::add_missing_lifetime_specifiers_label let elided_lifetime_span = if generic_args.span.is_empty() { // If there are no brackets, use the identifier span. - path_span + // HACK: we use find_ancestor_inside to properly suggest elided spans in paths + // originating from macros, since the segment's span might be from a macro arg. + segment.ident.span.find_ancestor_inside(path_span).unwrap_or(path_span) } else if generic_args.is_empty() { // If there are brackets, but not generic arguments, then use the opening bracket generic_args.span.with_hi(generic_args.span.lo() + BytePos(1)) 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/mod.rs b/compiler/rustc_ast_pretty/src/pprust/mod.rs index 4b5703a429e..ac9e7d06c4e 100644 --- a/compiler/rustc_ast_pretty/src/pprust/mod.rs +++ b/compiler/rustc_ast_pretty/src/pprust/mod.rs @@ -73,11 +73,11 @@ pub fn attribute_to_string(attr: &ast::Attribute) -> String { } pub fn to_string(f: impl FnOnce(&mut State<'_>)) -> String { - State::new().to_string(f) + State::to_string(f) } pub fn crate_to_string_for_macros(krate: &ast::Crate) -> String { - State::new().to_string(|s| { + State::to_string(|s| { s.print_inner_attributes(&krate.attrs); for item in &krate.items { s.print_item(item); diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index 6c5b38bc4bb..fa9a20f2e03 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -211,7 +211,7 @@ pub fn literal_to_string(lit: token::Lit) -> String { } fn visibility_qualified(vis: &ast::Visibility, s: &str) -> String { - format!("{}{}", State::new().to_string(|s| s.print_visibility(vis)), s) + format!("{}{}", State::to_string(|s| s.print_visibility(vis)), s) } impl std::ops::Deref for State<'_> { @@ -387,23 +387,23 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere self.print_string(sym.as_str(), style); } - fn print_inner_attributes(&mut self, attrs: &[ast::Attribute]) { + fn print_inner_attributes(&mut self, attrs: &[ast::Attribute]) -> bool { self.print_either_attributes(attrs, ast::AttrStyle::Inner, false, true) } - fn print_inner_attributes_no_trailing_hardbreak(&mut self, attrs: &[ast::Attribute]) { + fn print_inner_attributes_no_trailing_hardbreak(&mut self, attrs: &[ast::Attribute]) -> bool { self.print_either_attributes(attrs, ast::AttrStyle::Inner, false, false) } - fn print_outer_attributes(&mut self, attrs: &[ast::Attribute]) { + fn print_outer_attributes(&mut self, attrs: &[ast::Attribute]) -> bool { self.print_either_attributes(attrs, ast::AttrStyle::Outer, false, true) } - fn print_inner_attributes_inline(&mut self, attrs: &[ast::Attribute]) { + fn print_inner_attributes_inline(&mut self, attrs: &[ast::Attribute]) -> bool { self.print_either_attributes(attrs, ast::AttrStyle::Inner, true, true) } - fn print_outer_attributes_inline(&mut self, attrs: &[ast::Attribute]) { + fn print_outer_attributes_inline(&mut self, attrs: &[ast::Attribute]) -> bool { self.print_either_attributes(attrs, ast::AttrStyle::Outer, true, true) } @@ -413,20 +413,21 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere kind: ast::AttrStyle, is_inline: bool, trailing_hardbreak: bool, - ) { - let mut count = 0; + ) -> bool { + let mut printed = false; for attr in attrs { if attr.style == kind { self.print_attribute_inline(attr, is_inline); if is_inline { self.nbsp(); } - count += 1; + printed = true; } } - if count > 0 && trailing_hardbreak && !is_inline { + if printed && trailing_hardbreak && !is_inline { self.hardbreak_if_not_bol(); } + printed } fn print_attribute(&mut self, attr: &ast::Attribute) { @@ -792,55 +793,55 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere } fn ty_to_string(&self, ty: &ast::Ty) -> String { - self.to_string(|s| s.print_type(ty)) + Self::to_string(|s| s.print_type(ty)) } fn bounds_to_string(&self, bounds: &[ast::GenericBound]) -> String { - self.to_string(|s| s.print_type_bounds("", bounds)) + Self::to_string(|s| s.print_type_bounds("", bounds)) } fn pat_to_string(&self, pat: &ast::Pat) -> String { - self.to_string(|s| s.print_pat(pat)) + Self::to_string(|s| s.print_pat(pat)) } fn expr_to_string(&self, e: &ast::Expr) -> String { - self.to_string(|s| s.print_expr(e)) + Self::to_string(|s| s.print_expr(e)) } fn tt_to_string(&self, tt: &TokenTree) -> String { - self.to_string(|s| s.print_tt(tt, false)) + Self::to_string(|s| s.print_tt(tt, false)) } fn tts_to_string(&self, tokens: &TokenStream) -> String { - self.to_string(|s| s.print_tts(tokens, false)) + Self::to_string(|s| s.print_tts(tokens, false)) } fn stmt_to_string(&self, stmt: &ast::Stmt) -> String { - self.to_string(|s| s.print_stmt(stmt)) + Self::to_string(|s| s.print_stmt(stmt)) } fn item_to_string(&self, i: &ast::Item) -> String { - self.to_string(|s| s.print_item(i)) + Self::to_string(|s| s.print_item(i)) } fn generic_params_to_string(&self, generic_params: &[ast::GenericParam]) -> String { - self.to_string(|s| s.print_generic_params(generic_params)) + Self::to_string(|s| s.print_generic_params(generic_params)) } fn path_to_string(&self, p: &ast::Path) -> String { - self.to_string(|s| s.print_path(p, false, 0)) + Self::to_string(|s| s.print_path(p, false, 0)) } fn path_segment_to_string(&self, p: &ast::PathSegment) -> String { - self.to_string(|s| s.print_path_segment(p, false)) + Self::to_string(|s| s.print_path_segment(p, false)) } fn vis_to_string(&self, v: &ast::Visibility) -> String { - self.to_string(|s| s.print_visibility(v)) + Self::to_string(|s| s.print_visibility(v)) } fn block_to_string(&self, blk: &ast::Block) -> String { - self.to_string(|s| { + Self::to_string(|s| { // Containing cbox, will be closed by `print_block` at `}`. s.cbox(INDENT_UNIT); // Head-ibox, will be closed by `print_block` after `{`. @@ -850,22 +851,22 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere } fn meta_list_item_to_string(&self, li: &ast::NestedMetaItem) -> String { - self.to_string(|s| s.print_meta_list_item(li)) + Self::to_string(|s| s.print_meta_list_item(li)) } fn attr_item_to_string(&self, ai: &ast::AttrItem) -> String { - self.to_string(|s| s.print_attr_item(ai, ai.path.span)) + Self::to_string(|s| s.print_attr_item(ai, ai.path.span)) } fn attribute_to_string(&self, attr: &ast::Attribute) -> String { - self.to_string(|s| s.print_attribute(attr)) + Self::to_string(|s| s.print_attribute(attr)) } fn param_to_string(&self, arg: &ast::Param) -> String { - self.to_string(|s| s.print_param(arg, false)) + Self::to_string(|s| s.print_param(arg, false)) } - fn to_string(&self, f: impl FnOnce(&mut State<'_>)) -> String { + fn to_string(f: impl FnOnce(&mut State<'_>)) -> String { let mut printer = State::new(); f(&mut printer); printer.s.eof() @@ -1115,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("="); @@ -1199,7 +1202,7 @@ impl<'a> State<'a> { ); } ast::ItemKind::Mod(unsafety, ref mod_kind) => { - self.head(self.to_string(|s| { + self.head(Self::to_string(|s| { s.print_visibility(&item.vis); s.print_unsafety(unsafety); s.word("mod"); @@ -1225,7 +1228,7 @@ impl<'a> State<'a> { } } ast::ItemKind::ForeignMod(ref nmod) => { - self.head(self.to_string(|s| { + self.head(Self::to_string(|s| { s.print_unsafety(nmod.unsafety); s.word("extern"); })); @@ -1284,14 +1287,17 @@ impl<'a> State<'a> { self.print_visibility(&item.vis); self.print_defaultness(defaultness); self.print_unsafety(unsafety); - self.word_nbsp("impl"); - self.print_constness(constness); + self.word("impl"); - if !generics.params.is_empty() { + if generics.params.is_empty() { + self.nbsp(); + } else { self.print_generic_params(&generics.params); self.space(); } + self.print_constness(constness); + if let ast::ImplPolarity::Negative(_) = polarity { self.word("!"); } @@ -1444,7 +1450,7 @@ impl<'a> State<'a> { ast::CrateSugar::JustCrate => self.word_nbsp("crate"), }, ast::VisibilityKind::Restricted { ref path, .. } => { - let path = self.to_string(|s| s.print_path(path, false, 0)); + let path = Self::to_string(|s| s.print_path(path, false, 0)); if path == "self" || path == "super" { self.word_nbsp(format!("pub({})", path)) } else { @@ -1646,7 +1652,7 @@ impl<'a> State<'a> { self.ann.pre(self, AnnNode::Block(blk)); self.bopen(); - self.print_inner_attributes(attrs); + let has_attrs = self.print_inner_attributes(attrs); for (i, st) in blk.stmts.iter().enumerate() { match st.kind { @@ -1660,7 +1666,7 @@ impl<'a> State<'a> { } } - let empty = attrs.is_empty() && blk.stmts.is_empty(); + let empty = !has_attrs && blk.stmts.is_empty(); self.bclose_maybe_open(blk.span, empty, close_box); self.ann.post(self, AnnNode::Block(blk)) } @@ -2238,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 => { @@ -2459,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, @@ -2480,7 +2489,9 @@ impl<'a> State<'a> { } self.word(".."); } - self.space(); + if !empty { + self.space(); + } self.word("}"); } PatKind::Tuple(ref elts) => { @@ -2514,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("..."), @@ -2780,34 +2790,34 @@ impl<'a> State<'a> { self.word_space(","); } - match *predicate { - ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate { - ref bound_generic_params, - ref bounded_ty, - ref bounds, - .. - }) => { - self.print_formal_generic_params(bound_generic_params); - self.print_type(bounded_ty); - self.print_type_bounds(":", bounds); - } - ast::WherePredicate::RegionPredicate(ast::WhereRegionPredicate { - ref lifetime, - ref bounds, - .. - }) => { - self.print_lifetime_bounds(*lifetime, bounds); - } - ast::WherePredicate::EqPredicate(ast::WhereEqPredicate { - ref lhs_ty, - ref rhs_ty, - .. - }) => { - self.print_type(lhs_ty); - self.space(); - self.word_space("="); - self.print_type(rhs_ty); - } + self.print_where_predicate(predicate); + } + } + + pub fn print_where_predicate(&mut self, predicate: &ast::WherePredicate) { + match predicate { + ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate { + bound_generic_params, + bounded_ty, + bounds, + .. + }) => { + self.print_formal_generic_params(bound_generic_params); + self.print_type(bounded_ty); + self.print_type_bounds(":", bounds); + } + ast::WherePredicate::RegionPredicate(ast::WhereRegionPredicate { + lifetime, + bounds, + .. + }) => { + self.print_lifetime_bounds(*lifetime, bounds); + } + ast::WherePredicate::EqPredicate(ast::WhereEqPredicate { lhs_ty, rhs_ty, .. }) => { + self.print_type(lhs_ty); + self.space(); + self.word_space("="); + self.print_type(rhs_ty); } } } @@ -2908,10 +2918,7 @@ impl<'a> State<'a> { generic_params: &[ast::GenericParam], ) { self.ibox(INDENT_UNIT); - if !generic_params.is_empty() { - self.word("for"); - self.print_generic_params(generic_params); - } + self.print_formal_generic_params(generic_params); let generics = ast::Generics { params: Vec::new(), where_clause: ast::WhereClause { 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_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 872a4321447..1f745f977d4 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -1916,7 +1916,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { let tcx = self.tcx(); match *ak { - AggregateKind::Adt(def, variant_index, substs, _, active_field_index) => { + AggregateKind::Adt(adt_did, variant_index, substs, _, active_field_index) => { + let def = tcx.adt_def(adt_did); let variant = &def.variants[variant_index]; let adj_field_index = active_field_index.unwrap_or(field_index); if let Some(field) = variant.fields.get(adj_field_index) { @@ -2621,8 +2622,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { ); let (def_id, instantiated_predicates) = match aggregate_kind { - AggregateKind::Adt(def, _, substs, _, _) => { - (def.did, tcx.predicates_of(def.did).instantiate(tcx, substs)) + AggregateKind::Adt(adt_did, _, substs, _, _) => { + (*adt_did, tcx.predicates_of(*adt_did).instantiate(tcx, substs)) } // For closures, we have some **extra requirements** we diff --git a/compiler/rustc_builtin_macros/src/asm.rs b/compiler/rustc_builtin_macros/src/asm.rs index 41856761916..1a93b9be99e 100644 --- a/compiler/rustc_builtin_macros/src/asm.rs +++ b/compiler/rustc_builtin_macros/src/asm.rs @@ -809,7 +809,7 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option<ast::Inl }) } -pub fn expand_asm<'cx>( +pub(super) fn expand_asm<'cx>( ecx: &'cx mut ExtCtxt<'_>, sp: Span, tts: TokenStream, @@ -836,7 +836,7 @@ pub fn expand_asm<'cx>( } } -pub fn expand_global_asm<'cx>( +pub(super) fn expand_global_asm<'cx>( ecx: &'cx mut ExtCtxt<'_>, sp: Span, tts: TokenStream, 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_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs index 3e8b43fea8a..8c3ef2864f4 100644 --- a/compiler/rustc_builtin_macros/src/lib.rs +++ b/compiler/rustc_builtin_macros/src/lib.rs @@ -19,7 +19,6 @@ use rustc_expand::base::{MacroExpanderFn, ResolverExpand, SyntaxExtensionKind}; use rustc_expand::proc_macro::BangProcMacro; use rustc_span::symbol::sym; -mod asm; mod assert; mod cfg; mod cfg_accessible; @@ -42,6 +41,7 @@ mod test; mod trace_macros; mod util; +pub mod asm; pub mod cmdline_attrs; pub mod proc_macro_harness; pub mod standard_library_imports; 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..60ff18af0a9 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -18,6 +18,7 @@ use crate::llvm::debuginfo::{ use crate::value::Value; use cstr::cstr; +use rustc_codegen_ssa::debuginfo::type_names::cpp_like_debuginfo; use rustc_codegen_ssa::traits::*; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::FxHashMap; @@ -933,16 +934,16 @@ fn basic_type_metadata<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>) -> &'l // When targeting MSVC, emit MSVC style type names for compatibility with // .natvis visualizers (and perhaps other existing native debuggers?) - let msvc_like_names = cx.tcx.sess.target.is_like_msvc; + let cpp_like_debuginfo = cpp_like_debuginfo(cx.tcx); let (name, encoding) = match t.kind() { ty::Never => ("!", DW_ATE_unsigned), ty::Tuple(elements) if elements.is_empty() => ("()", DW_ATE_unsigned), ty::Bool => ("bool", DW_ATE_boolean), ty::Char => ("char", DW_ATE_unsigned_char), - ty::Int(int_ty) if msvc_like_names => (int_ty.msvc_basic_name(), DW_ATE_signed), - ty::Uint(uint_ty) if msvc_like_names => (uint_ty.msvc_basic_name(), DW_ATE_unsigned), - ty::Float(float_ty) if msvc_like_names => (float_ty.msvc_basic_name(), DW_ATE_float), + ty::Int(int_ty) if cpp_like_debuginfo => (int_ty.msvc_basic_name(), DW_ATE_signed), + ty::Uint(uint_ty) if cpp_like_debuginfo => (uint_ty.msvc_basic_name(), DW_ATE_unsigned), + ty::Float(float_ty) if cpp_like_debuginfo => (float_ty.msvc_basic_name(), DW_ATE_float), ty::Int(int_ty) => (int_ty.name_str(), DW_ATE_signed), ty::Uint(uint_ty) => (uint_ty.name_str(), DW_ATE_unsigned), ty::Float(float_ty) => (float_ty.name_str(), DW_ATE_float), @@ -959,7 +960,7 @@ fn basic_type_metadata<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>) -> &'l ) }; - if !msvc_like_names { + if !cpp_like_debuginfo { return ty_metadata; } @@ -1072,7 +1073,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 { @@ -1521,13 +1526,6 @@ fn prepare_union_metadata<'ll, 'tcx>( // Enums //=----------------------------------------------------------------------------- -/// DWARF variant support is only available starting in LLVM 8, but -/// on MSVC we have to use the fallback mode, because LLVM doesn't -/// lower variant parts to PDB. -fn use_enum_fallback(cx: &CodegenCx<'_, '_>) -> bool { - cx.sess().target.is_like_msvc -} - // FIXME(eddyb) maybe precompute this? Right now it's computed once // per generator monomorphization, but it doesn't depend on substs. fn generator_layout_and_saved_local_names<'tcx>( @@ -1602,7 +1600,10 @@ impl<'ll, 'tcx> EnumMemberDescriptionFactory<'ll, 'tcx> { _ => bug!(), }; - let fallback = use_enum_fallback(cx); + // While LLVM supports generating debuginfo for variant types (enums), it doesn't support + // lowering that debuginfo to CodeView records for msvc targets. So if we are targeting + // msvc, then we need to use a different, fallback encoding of the debuginfo. + let fallback = cpp_like_debuginfo(cx.tcx); // This will always find the metadata in the type map. let self_metadata = type_metadata(cx, self.enum_type, self.span); @@ -2155,7 +2156,10 @@ fn prepare_enum_metadata<'ll, 'tcx>( return FinalMetadata(discriminant_type_metadata(tag.value)); } - if use_enum_fallback(cx) { + // While LLVM supports generating debuginfo for variant types (enums), it doesn't support + // lowering that debuginfo to CodeView records for msvc targets. So if we are targeting + // msvc, then we need to use a different encoding of the debuginfo. + if cpp_like_debuginfo(tcx) { let discriminant_type_metadata = match layout.variants { Variants::Single { .. } => None, Variants::Multiple { tag_encoding: TagEncoding::Niche { .. }, tag, .. } 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/debuginfo/type_names.rs b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs index 00e76800d47..93bb1aee25f 100644 --- a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs +++ b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs @@ -53,14 +53,14 @@ fn push_debuginfo_type_name<'tcx>( ) { // When targeting MSVC, emit C++ style type names for compatibility with // .natvis visualizers (and perhaps other existing native debuggers?) - let cpp_like_names = cpp_like_names(tcx); + let cpp_like_debuginfo = cpp_like_debuginfo(tcx); match *t.kind() { ty::Bool => output.push_str("bool"), ty::Char => output.push_str("char"), ty::Str => output.push_str("str"), ty::Never => { - if cpp_like_names { + if cpp_like_debuginfo { output.push_str("never$"); } else { output.push('!'); @@ -71,7 +71,7 @@ fn push_debuginfo_type_name<'tcx>( ty::Float(float_ty) => output.push_str(float_ty.name_str()), ty::Foreign(def_id) => push_item_name(tcx, def_id, qualified, output), ty::Adt(def, substs) => { - if def.is_enum() && cpp_like_names { + if def.is_enum() && cpp_like_debuginfo { msvc_enum_fallback(tcx, t, def, substs, output, visited); } else { push_item_name(tcx, def.did, qualified, output); @@ -79,7 +79,7 @@ fn push_debuginfo_type_name<'tcx>( } } ty::Tuple(component_types) => { - if cpp_like_names { + if cpp_like_debuginfo { output.push_str("tuple$<"); } else { output.push('('); @@ -87,20 +87,20 @@ fn push_debuginfo_type_name<'tcx>( for component_type in component_types { push_debuginfo_type_name(tcx, component_type.expect_ty(), true, output, visited); - push_arg_separator(cpp_like_names, output); + push_arg_separator(cpp_like_debuginfo, output); } if !component_types.is_empty() { pop_arg_separator(output); } - if cpp_like_names { - push_close_angle_bracket(cpp_like_names, output); + if cpp_like_debuginfo { + push_close_angle_bracket(cpp_like_debuginfo, output); } else { output.push(')'); } } ty::RawPtr(ty::TypeAndMut { ty: inner_type, mutbl }) => { - if cpp_like_names { + if cpp_like_debuginfo { match mutbl { hir::Mutability::Not => output.push_str("ptr_const$<"), hir::Mutability::Mut => output.push_str("ptr_mut$<"), @@ -115,8 +115,8 @@ fn push_debuginfo_type_name<'tcx>( push_debuginfo_type_name(tcx, inner_type, qualified, output, visited); - if cpp_like_names { - push_close_angle_bracket(cpp_like_names, output); + if cpp_like_debuginfo { + push_close_angle_bracket(cpp_like_debuginfo, output); } } ty::Ref(_, inner_type, mutbl) => { @@ -126,7 +126,7 @@ fn push_debuginfo_type_name<'tcx>( // types out to aid debugging in MSVC. let is_slice_or_str = matches!(*inner_type.kind(), ty::Slice(_) | ty::Str); - if !cpp_like_names { + if !cpp_like_debuginfo { output.push('&'); output.push_str(mutbl.prefix_str()); } else if !is_slice_or_str { @@ -138,12 +138,12 @@ fn push_debuginfo_type_name<'tcx>( push_debuginfo_type_name(tcx, inner_type, qualified, output, visited); - if cpp_like_names && !is_slice_or_str { - push_close_angle_bracket(cpp_like_names, output); + if cpp_like_debuginfo && !is_slice_or_str { + push_close_angle_bracket(cpp_like_debuginfo, output); } } ty::Array(inner_type, len) => { - if cpp_like_names { + if cpp_like_debuginfo { output.push_str("array$<"); push_debuginfo_type_name(tcx, inner_type, true, output, visited); match len.val { @@ -162,7 +162,7 @@ fn push_debuginfo_type_name<'tcx>( } } ty::Slice(inner_type) => { - if cpp_like_names { + if cpp_like_debuginfo { output.push_str("slice$<"); } else { output.push('['); @@ -170,8 +170,8 @@ fn push_debuginfo_type_name<'tcx>( push_debuginfo_type_name(tcx, inner_type, true, output, visited); - if cpp_like_names { - push_close_angle_bracket(cpp_like_names, output); + if cpp_like_debuginfo { + push_close_angle_bracket(cpp_like_debuginfo, output); } else { output.push(']'); } @@ -179,7 +179,7 @@ fn push_debuginfo_type_name<'tcx>( ty::Dynamic(ref trait_data, ..) => { let auto_traits: SmallVec<[DefId; 4]> = trait_data.auto_traits().collect(); - let has_enclosing_parens = if cpp_like_names { + let has_enclosing_parens = if cpp_like_debuginfo { output.push_str("dyn$<"); false } else { @@ -216,14 +216,14 @@ fn push_debuginfo_type_name<'tcx>( } for (item_def_id, ty) in projection_bounds { - push_arg_separator(cpp_like_names, output); + push_arg_separator(cpp_like_debuginfo, output); - if cpp_like_names { + if cpp_like_debuginfo { output.push_str("assoc$<"); push_item_name(tcx, item_def_id, false, output); - push_arg_separator(cpp_like_names, output); + push_arg_separator(cpp_like_debuginfo, output); push_debuginfo_type_name(tcx, ty, true, output, visited); - push_close_angle_bracket(cpp_like_names, output); + push_close_angle_bracket(cpp_like_debuginfo, output); } else { push_item_name(tcx, item_def_id, false, output); output.push('='); @@ -231,11 +231,11 @@ fn push_debuginfo_type_name<'tcx>( } } - push_close_angle_bracket(cpp_like_names, output); + push_close_angle_bracket(cpp_like_debuginfo, output); } if auto_traits.len() != 0 { - push_auto_trait_separator(cpp_like_names, output); + push_auto_trait_separator(cpp_like_debuginfo, output); } } @@ -252,14 +252,14 @@ fn push_debuginfo_type_name<'tcx>( for auto_trait in auto_traits { output.push_str(&auto_trait); - push_auto_trait_separator(cpp_like_names, output); + push_auto_trait_separator(cpp_like_debuginfo, output); } pop_auto_trait_separator(output); } - if cpp_like_names { - push_close_angle_bracket(cpp_like_names, output); + if cpp_like_debuginfo { + push_close_angle_bracket(cpp_like_debuginfo, output); } else if has_enclosing_parens { output.push(')'); } @@ -279,7 +279,7 @@ fn push_debuginfo_type_name<'tcx>( // use a dummy string that should make it clear // that something unusual is going on if !visited.insert(t) { - output.push_str(if cpp_like_names { + output.push_str(if cpp_like_debuginfo { "recursive_type$" } else { "<recursive_type>" @@ -290,7 +290,7 @@ fn push_debuginfo_type_name<'tcx>( let sig = tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), t.fn_sig(tcx)); - if cpp_like_names { + if cpp_like_debuginfo { // Format as a C++ function pointer: return_type (*)(params...) if sig.output().is_unit() { output.push_str("void"); @@ -313,7 +313,7 @@ fn push_debuginfo_type_name<'tcx>( if !sig.inputs().is_empty() { for ¶meter_type in sig.inputs() { push_debuginfo_type_name(tcx, parameter_type, true, output, visited); - push_arg_separator(cpp_like_names, output); + push_arg_separator(cpp_like_debuginfo, output); } pop_arg_separator(output); } @@ -328,7 +328,7 @@ fn push_debuginfo_type_name<'tcx>( output.push(')'); - if !cpp_like_names && !sig.output().is_unit() { + if !cpp_like_debuginfo && !sig.output().is_unit() { output.push_str(" -> "); push_debuginfo_type_name(tcx, sig.output(), true, output, visited); } @@ -426,9 +426,9 @@ fn push_debuginfo_type_name<'tcx>( const NON_CPP_AUTO_TRAIT_SEPARATOR: &str = " + "; - fn push_auto_trait_separator(cpp_like_names: bool, output: &mut String) { - if cpp_like_names { - push_arg_separator(cpp_like_names, output); + fn push_auto_trait_separator(cpp_like_debuginfo: bool, output: &mut String) { + if cpp_like_debuginfo { + push_arg_separator(cpp_like_debuginfo, output); } else { output.push_str(NON_CPP_AUTO_TRAIT_SEPARATOR); } @@ -457,11 +457,11 @@ pub fn compute_debuginfo_vtable_name<'tcx>( t: Ty<'tcx>, trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>, ) -> String { - let cpp_like_names = cpp_like_names(tcx); + let cpp_like_debuginfo = cpp_like_debuginfo(tcx); let mut vtable_name = String::with_capacity(64); - if cpp_like_names { + if cpp_like_debuginfo { vtable_name.push_str("impl$<"); } else { vtable_name.push('<'); @@ -470,7 +470,7 @@ pub fn compute_debuginfo_vtable_name<'tcx>( let mut visited = FxHashSet::default(); push_debuginfo_type_name(tcx, t, true, &mut vtable_name, &mut visited); - if cpp_like_names { + if cpp_like_debuginfo { vtable_name.push_str(", "); } else { vtable_name.push_str(" as "); @@ -486,9 +486,9 @@ pub fn compute_debuginfo_vtable_name<'tcx>( vtable_name.push_str("_"); } - push_close_angle_bracket(cpp_like_names, &mut vtable_name); + push_close_angle_bracket(cpp_like_debuginfo, &mut vtable_name); - let suffix = if cpp_like_names { "::vtable$" } else { "::{vtable}" }; + let suffix = if cpp_like_debuginfo { "::vtable$" } else { "::{vtable}" }; vtable_name.reserve_exact(suffix.len()); vtable_name.push_str(suffix); @@ -521,7 +521,7 @@ fn push_unqualified_item_name( DefPathData::ClosureExpr if tcx.generator_kind(def_id).is_some() => { // Generators look like closures, but we want to treat them differently // in the debug info. - if cpp_like_names(tcx) { + if cpp_like_debuginfo(tcx) { write!(output, "generator${}", disambiguated_data.disambiguator).unwrap(); } else { write!(output, "{{generator#{}}}", disambiguated_data.disambiguator).unwrap(); @@ -532,7 +532,7 @@ fn push_unqualified_item_name( output.push_str(name.as_str()); } DefPathDataName::Anon { namespace } => { - if cpp_like_names(tcx) { + if cpp_like_debuginfo(tcx) { write!(output, "{}${}", namespace, disambiguated_data.disambiguator).unwrap(); } else { write!(output, "{{{}#{}}}", namespace, disambiguated_data.disambiguator) @@ -560,7 +560,7 @@ fn push_generic_params_internal<'tcx>( debug_assert_eq!(substs, tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), substs)); - let cpp_like_names = cpp_like_names(tcx); + let cpp_like_debuginfo = cpp_like_debuginfo(tcx); output.push('<'); @@ -575,10 +575,10 @@ fn push_generic_params_internal<'tcx>( other => bug!("Unexpected non-erasable generic: {:?}", other), } - push_arg_separator(cpp_like_names, output); + push_arg_separator(cpp_like_debuginfo, output); } pop_arg_separator(output); - push_close_angle_bracket(cpp_like_names, output); + push_close_angle_bracket(cpp_like_debuginfo, output); true } @@ -617,7 +617,7 @@ fn push_const_param<'tcx>(tcx: TyCtxt<'tcx>, ct: &'tcx ty::Const<'tcx>, output: // avoiding collisions and will make the emitted type names shorter. let hash: u64 = hasher.finish(); - if cpp_like_names(tcx) { + if cpp_like_debuginfo(tcx) { write!(output, "CONST${:x}", hash) } else { write!(output, "{{CONST#{:x}}}", hash) @@ -634,10 +634,10 @@ pub fn push_generic_params<'tcx>(tcx: TyCtxt<'tcx>, substs: SubstsRef<'tcx>, out push_generic_params_internal(tcx, substs, output, &mut visited); } -fn push_close_angle_bracket(cpp_like_names: bool, output: &mut String) { +fn push_close_angle_bracket(cpp_like_debuginfo: bool, output: &mut String) { // MSVC debugger always treats `>>` as a shift, even when parsing templates, // so add a space to avoid confusion. - if cpp_like_names && output.ends_with('>') { + if cpp_like_debuginfo && output.ends_with('>') { output.push(' ') }; @@ -652,11 +652,11 @@ fn pop_close_angle_bracket(output: &mut String) { } } -fn push_arg_separator(cpp_like_names: bool, output: &mut String) { +fn push_arg_separator(cpp_like_debuginfo: bool, output: &mut String) { // Natvis does not always like having spaces between parts of the type name // and this causes issues when we need to write a typename in natvis, for example // as part of a cast like the `HashMap` visualizer does. - if cpp_like_names { + if cpp_like_debuginfo { output.push(','); } else { output.push_str(", "); @@ -673,6 +673,7 @@ fn pop_arg_separator(output: &mut String) { output.pop(); } -fn cpp_like_names(tcx: TyCtxt<'_>) -> bool { +/// Check if we should generate C++ like names and debug information. +pub fn cpp_like_debuginfo(tcx: TyCtxt<'_>) -> bool { tcx.sess.target.is_like_msvc } 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 f087b9f7815..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}; @@ -112,9 +111,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { mir::Rvalue::Aggregate(ref kind, ref operands) => { let (dest, active_field_index) = match **kind { - mir::AggregateKind::Adt(adt_def, variant_index, _, _, active_field_index) => { + mir::AggregateKind::Adt(adt_did, variant_index, _, _, active_field_index) => { dest.codegen_set_discr(&mut bx, variant_index); - if adt_def.is_enum() { + if bx.tcx().adt_def(adt_did).is_enum() { (dest.project_downcast(&mut bx, variant_index), active_field_index) } else { (dest, active_field_index) @@ -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 550715abc10..30e9cbe4403 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -260,7 +260,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, args: &[OpTy<'tcx>], _ret: Option<(&PlaceTy<'tcx>, mir::BasicBlock)>, _unwind: StackPopUnwind, // unwinding is not supported in consts - ) -> InterpResult<'tcx, Option<&'mir mir::Body<'tcx>>> { + ) -> InterpResult<'tcx, Option<(&'mir mir::Body<'tcx>, ty::Instance<'tcx>)>> { debug!("find_mir_or_eval_fn: {:?}", instance); // Only check non-glue functions @@ -279,11 +279,21 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, if let Some(new_instance) = ecx.hook_special_const_fn(instance, args)? { // We call another const fn instead. - return Self::find_mir_or_eval_fn(ecx, new_instance, _abi, args, _ret, _unwind); + // However, we return the *original* instance to make backtraces work out + // (and we hope this does not confuse the FnAbi checks too much). + return Ok(Self::find_mir_or_eval_fn( + ecx, + new_instance, + _abi, + args, + _ret, + _unwind, + )? + .map(|(body, _instance)| (body, instance))); } } // This is a const fn. Call it. - Ok(Some(ecx.load_mir(instance.def, None)?)) + Ok(Some((ecx.load_mir(instance.def, None)?, instance))) } fn call_intrinsic( @@ -388,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 d9faa6777ea..0a8112da2ab 100644 --- a/compiler/rustc_const_eval/src/interpret/eval_context.rs +++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs @@ -8,7 +8,10 @@ use rustc_index::vec::IndexVec; use rustc_macros::HashStable; use rustc_middle::mir; use rustc_middle::mir::interpret::{InterpError, InvalidProgramInfo}; -use rustc_middle::ty::layout::{self, LayoutError, LayoutOf, LayoutOfHelpers, TyAndLayout}; +use rustc_middle::ty::layout::{ + self, FnAbiError, FnAbiOfHelpers, FnAbiRequest, LayoutError, LayoutOf, LayoutOfHelpers, + TyAndLayout, +}; use rustc_middle::ty::{ self, query::TyCtxtAt, subst::SubstsRef, ParamEnv, Ty, TyCtxt, TypeFoldable, }; @@ -16,7 +19,7 @@ use rustc_mir_dataflow::storage::AlwaysLiveLocals; use rustc_query_system::ich::StableHashingContext; use rustc_session::Limit; use rustc_span::{Pos, Span}; -use rustc_target::abi::{Align, HasDataLayout, Size, TargetDataLayout}; +use rustc_target::abi::{call::FnAbi, Align, HasDataLayout, Size, TargetDataLayout}; use super::{ AllocId, GlobalId, Immediate, InterpErrorInfo, InterpResult, MPlaceTy, Machine, MemPlace, @@ -153,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 @@ -333,6 +336,24 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> LayoutOfHelpers<'tcx> for InterpC } } +impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> FnAbiOfHelpers<'tcx> for InterpCx<'mir, 'tcx, M> { + type FnAbiOfResult = InterpResult<'tcx, &'tcx FnAbi<'tcx, Ty<'tcx>>>; + + fn handle_fn_abi_err( + &self, + err: FnAbiError<'tcx>, + _span: Span, + _fn_abi_request: FnAbiRequest<'tcx>, + ) -> InterpErrorInfo<'tcx> { + match err { + FnAbiError::Layout(err) => err_inval!(Layout(err)).into(), + FnAbiError::AdjustForForeignAbi(err) => { + err_inval!(FnAbiAdjustForForeignAbi(err)).into() + } + } + } +} + /// Test if it is valid for a MIR assignment to assign `src`-typed place to `dest`-typed value. /// This test should be symmetric, as it is primarily about layout compatibility. pub(super) fn mir_assign_valid_types<'tcx>( @@ -828,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 { @@ -853,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) @@ -862,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 727099848a4..23ec3875cbc 100644 --- a/compiler/rustc_const_eval/src/interpret/machine.rs +++ b/compiler/rustc_const_eval/src/interpret/machine.rs @@ -167,7 +167,7 @@ pub trait Machine<'mir, 'tcx>: Sized { args: &[OpTy<'tcx, Self::PointerTag>], ret: Option<(&PlaceTy<'tcx, Self::PointerTag>, mir::BasicBlock)>, unwind: StackPopUnwind, - ) -> InterpResult<'tcx, Option<&'mir mir::Body<'tcx>>>; + ) -> InterpResult<'tcx, Option<(&'mir mir::Body<'tcx>, ty::Instance<'tcx>)>>; /// Execute `fn_val`. It is the hook's responsibility to advance the instruction /// pointer as appropriate. @@ -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 992cef1cb6a..3daa1d3c2b3 100644 --- a/compiler/rustc_const_eval/src/interpret/step.rs +++ b/compiler/rustc_const_eval/src/interpret/step.rs @@ -199,9 +199,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Aggregate(ref kind, ref operands) => { // active_field_index is for union initialization. let (dest, active_field_index) = match **kind { - mir::AggregateKind::Adt(adt_def, variant_index, _, _, active_field_index) => { + mir::AggregateKind::Adt(adt_did, variant_index, _, _, active_field_index) => { self.write_discriminant(variant_index, &dest)?; - if adt_def.is_enum() { + if self.tcx.adt_def(adt_did).is_enum() { assert!(active_field_index.is_none()); (self.place_downcast(&dest, variant_index)?, None) } else { @@ -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/terminator.rs b/compiler/rustc_const_eval/src/interpret/terminator.rs index df177fd9679..f3910c9765d 100644 --- a/compiler/rustc_const_eval/src/interpret/terminator.rs +++ b/compiler/rustc_const_eval/src/interpret/terminator.rs @@ -1,14 +1,14 @@ use std::borrow::Cow; use std::convert::TryFrom; -use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; -use rustc_middle::ty::layout::{self, LayoutOf as _, TyAndLayout}; +use rustc_middle::ty::layout::{FnAbiOf, LayoutOf}; use rustc_middle::ty::Instance; use rustc_middle::{ mir, ty::{self, Ty}, }; use rustc_target::abi; +use rustc_target::abi::call::{ArgAbi, ArgAttribute, ArgAttributes, FnAbi, PassMode}; use rustc_target::spec::abi::Abi; use super::{ @@ -17,10 +17,6 @@ use super::{ }; impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { - fn fn_can_unwind(&self, attrs: CodegenFnAttrFlags, abi: Abi) -> bool { - layout::fn_can_unwind(*self.tcx, attrs, abi) - } - pub(super) fn eval_terminator( &mut self, terminator: &mir::Terminator<'tcx>, @@ -64,25 +60,27 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let old_stack = self.frame_idx(); let old_loc = self.frame().loc; let func = self.eval_operand(func, None)?; - let (fn_val, abi, caller_can_unwind) = match *func.layout.ty.kind() { - ty::FnPtr(sig) => { - let caller_abi = sig.abi(); + let args = self.eval_operands(args)?; + + let fn_sig_binder = func.layout.ty.fn_sig(*self.tcx); + let fn_sig = + self.tcx.normalize_erasing_late_bound_regions(self.param_env, fn_sig_binder); + let extra_args = &args[fn_sig.inputs().len()..]; + let extra_args = self.tcx.mk_type_list(extra_args.iter().map(|arg| arg.layout.ty)); + + let (fn_val, fn_abi, with_caller_location) = match *func.layout.ty.kind() { + ty::FnPtr(_sig) => { let fn_ptr = self.read_pointer(&func)?; let fn_val = self.memory.get_fn(fn_ptr)?; - ( - fn_val, - caller_abi, - self.fn_can_unwind(CodegenFnAttrFlags::empty(), caller_abi), - ) + (fn_val, self.fn_abi_of_fn_ptr(fn_sig_binder, extra_args)?, false) } ty::FnDef(def_id, substs) => { - let sig = func.layout.ty.fn_sig(*self.tcx); + let instance = + self.resolve(ty::WithOptConstParam::unknown(def_id), substs)?; ( - FnVal::Instance( - self.resolve(ty::WithOptConstParam::unknown(def_id), substs)?, - ), - sig.abi(), - self.fn_can_unwind(self.tcx.codegen_fn_attrs(def_id).flags, sig.abi()), + FnVal::Instance(instance), + self.fn_abi_of_instance(instance, extra_args)?, + instance.def.requires_caller_location(*self.tcx), ) } _ => span_bug!( @@ -91,7 +89,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { func.layout.ty ), }; - let args = self.eval_operands(args)?; + let dest_place; let ret = match destination { Some((dest, ret)) => { @@ -102,10 +100,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { }; self.eval_fn_call( fn_val, - abi, + (fn_sig.abi, fn_abi), &args, + with_caller_location, ret, - match (cleanup, caller_can_unwind) { + match (cleanup, fn_abi.can_unwind) { (Some(cleanup), true) => StackPopUnwind::Cleanup(*cleanup), (None, true) => StackPopUnwind::Skip, (_, false) => StackPopUnwind::NotAllowed, @@ -174,68 +173,128 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } fn check_argument_compat( - rust_abi: bool, - caller: TyAndLayout<'tcx>, - callee: TyAndLayout<'tcx>, + caller_abi: &ArgAbi<'tcx, Ty<'tcx>>, + callee_abi: &ArgAbi<'tcx, Ty<'tcx>>, ) -> bool { - if caller.ty == callee.ty { - // No question + // Heuristic for type comparison. + let layout_compat = || { + if caller_abi.layout.ty == callee_abi.layout.ty { + // No question + return true; + } + // Compare layout + match (caller_abi.layout.abi, callee_abi.layout.abi) { + // Different valid ranges are okay (once we enforce validity, + // that will take care to make it UB to leave the range, just + // like for transmute). + (abi::Abi::Scalar(caller), abi::Abi::Scalar(callee)) => { + caller.value == callee.value + } + ( + abi::Abi::ScalarPair(caller1, caller2), + abi::Abi::ScalarPair(callee1, callee2), + ) => caller1.value == callee1.value && caller2.value == callee2.value, + // Be conservative + _ => false, + } + }; + // Padding must be fully equal. + let pad_compat = || caller_abi.pad == callee_abi.pad; + // When comparing the PassMode, we have to be smart about comparing the attributes. + let arg_attr_compat = |a1: ArgAttributes, a2: ArgAttributes| { + // There's only one regular attribute that matters for the call ABI: InReg. + // Everything else is things like noalias, dereferencable, nonnull, ... + // (This also applies to pointee_size, pointee_align.) + if a1.regular.contains(ArgAttribute::InReg) != a2.regular.contains(ArgAttribute::InReg) + { + return false; + } + // We also compare the sign extension mode -- this could let the callee make assumptions + // about bits that conceptually were not even passed. + if a1.arg_ext != a2.arg_ext { + return false; + } return true; - } - if !rust_abi { - // Don't risk anything - return false; - } - // Compare layout - match (caller.abi, callee.abi) { - // Different valid ranges are okay (once we enforce validity, - // that will take care to make it UB to leave the range, just - // like for transmute). - (abi::Abi::Scalar(caller), abi::Abi::Scalar(callee)) => caller.value == callee.value, - (abi::Abi::ScalarPair(caller1, caller2), abi::Abi::ScalarPair(callee1, callee2)) => { - caller1.value == callee1.value && caller2.value == callee2.value + }; + let mode_compat = || match (caller_abi.mode, callee_abi.mode) { + (PassMode::Ignore, PassMode::Ignore) => true, + (PassMode::Direct(a1), PassMode::Direct(a2)) => arg_attr_compat(a1, a2), + (PassMode::Pair(a1, b1), PassMode::Pair(a2, b2)) => { + arg_attr_compat(a1, a2) && arg_attr_compat(b1, b2) } - // Be conservative + (PassMode::Cast(c1), PassMode::Cast(c2)) => c1 == c2, + ( + PassMode::Indirect { attrs: a1, extra_attrs: None, on_stack: s1 }, + PassMode::Indirect { attrs: a2, extra_attrs: None, on_stack: s2 }, + ) => arg_attr_compat(a1, a2) && s1 == s2, + ( + PassMode::Indirect { attrs: a1, extra_attrs: Some(e1), on_stack: s1 }, + PassMode::Indirect { attrs: a2, extra_attrs: Some(e2), on_stack: s2 }, + ) => arg_attr_compat(a1, a2) && arg_attr_compat(e1, e2) && s1 == s2, _ => false, + }; + + if layout_compat() && pad_compat() && mode_compat() { + return true; } + trace!( + "check_argument_compat: incompatible ABIs:\ncaller: {:?}\ncallee: {:?}", + caller_abi, + callee_abi + ); + return false; } - /// Pass a single argument, checking the types for compatibility. - fn pass_argument( + /// Initialize a single callee argument, checking the types for compatibility. + fn pass_argument<'x, 'y>( &mut self, - rust_abi: bool, - caller_arg: &mut impl Iterator<Item = OpTy<'tcx, M::PointerTag>>, + caller_args: &mut impl Iterator< + Item = (&'x OpTy<'tcx, M::PointerTag>, &'y ArgAbi<'tcx, Ty<'tcx>>), + >, + callee_abi: &ArgAbi<'tcx, Ty<'tcx>>, callee_arg: &PlaceTy<'tcx, M::PointerTag>, - ) -> InterpResult<'tcx> { - if rust_abi && callee_arg.layout.is_zst() { - // Nothing to do. - trace!("Skipping callee ZST"); + ) -> InterpResult<'tcx> + where + 'tcx: 'x, + 'tcx: 'y, + { + if matches!(callee_abi.mode, PassMode::Ignore) { + // This one is skipped. return Ok(()); } - let caller_arg = caller_arg.next().ok_or_else(|| { + // Find next caller arg. + let (caller_arg, caller_abi) = caller_args.next().ok_or_else(|| { err_ub_format!("calling a function with fewer arguments than it requires") })?; - if rust_abi { - assert!(!caller_arg.layout.is_zst(), "ZSTs must have been already filtered out"); - } // Now, check - if !Self::check_argument_compat(rust_abi, caller_arg.layout, callee_arg.layout) { + if !Self::check_argument_compat(caller_abi, callee_abi) { throw_ub_format!( "calling a function with argument of type {:?} passing data of type {:?}", callee_arg.layout.ty, caller_arg.layout.ty ) } - // We allow some transmutes here + // We allow some transmutes here. + // FIXME: Depending on the PassMode, this should reset some padding to uninitialized. (This + // is true for all `copy_op`, but there are a lot of special cases for argument passing + // specifically.) self.copy_op_transmute(&caller_arg, callee_arg) } /// Call this function -- pushing the stack frame and initializing the arguments. + /// + /// `caller_fn_abi` is used to determine if all the arguments are passed the proper way. + /// However, we also need `caller_abi` to determine if we need to do untupling of arguments. + /// + /// `with_caller_location` indicates whether the caller passed a caller location. Miri + /// implements caller locations without argument passing, but to match `FnAbi` we need to know + /// when those arguments are present. pub(crate) fn eval_fn_call( &mut self, fn_val: FnVal<'tcx, M::ExtraFnVal>, - caller_abi: Abi, + (caller_abi, caller_fn_abi): (Abi, &FnAbi<'tcx, Ty<'tcx>>), args: &[OpTy<'tcx, M::PointerTag>], + with_caller_location: bool, ret: Option<(&PlaceTy<'tcx, M::PointerTag>, mir::BasicBlock)>, mut unwind: StackPopUnwind, ) -> InterpResult<'tcx> { @@ -248,39 +307,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } }; - let get_abi = |this: &Self, instance_ty: Ty<'tcx>| match instance_ty.kind() { - ty::FnDef(..) => instance_ty.fn_sig(*this.tcx).abi(), - ty::Closure(..) => Abi::RustCall, - ty::Generator(..) => Abi::Rust, - _ => span_bug!(this.cur_span(), "unexpected callee ty: {:?}", instance_ty), - }; - - // ABI check - let check_abi = |callee_abi: Abi| -> InterpResult<'tcx> { - let normalize_abi = |abi| match abi { - Abi::Rust | Abi::RustCall | Abi::RustIntrinsic | Abi::PlatformIntrinsic => - // These are all the same ABI, really. - { - Abi::Rust - } - abi => abi, - }; - if normalize_abi(caller_abi) != normalize_abi(callee_abi) { - throw_ub_format!( - "calling a function with ABI {} using caller ABI {}", - callee_abi.name(), - caller_abi.name() - ) - } - Ok(()) - }; - match instance.def { ty::InstanceDef::Intrinsic(..) => { - if M::enforce_abi(self) { - check_abi(get_abi(self, instance.ty(*self.tcx, self.param_env)))?; - } assert!(caller_abi == Abi::RustIntrinsic || caller_abi == Abi::PlatformIntrinsic); + // caller_fn_abi is not relevant here, we interpret the arguments directly for each intrinsic. M::call_intrinsic(self, instance, args, ret, unwind) } ty::InstanceDef::VtableShim(..) @@ -291,26 +321,37 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { | ty::InstanceDef::CloneShim(..) | ty::InstanceDef::Item(_) => { // We need MIR for this fn - let body = + let (body, instance) = match M::find_mir_or_eval_fn(self, instance, caller_abi, args, ret, unwind)? { Some(body) => body, None => return Ok(()), }; - // Check against the ABI of the MIR body we are calling (not the ABI of `instance`; - // these can differ when `find_mir_or_eval_fn` does something clever like resolve - // exported symbol names). - let callee_def_id = body.source.def_id(); - let callee_abi = get_abi(self, self.tcx.type_of(callee_def_id)); + // Compute callee information using the `instance` returned by + // `find_mir_or_eval_fn`. + // FIXME: for variadic support, do we have to somehow determine calle's extra_args? + let callee_fn_abi = self.fn_abi_of_instance(instance, ty::List::empty())?; + + if callee_fn_abi.c_variadic != caller_fn_abi.c_variadic { + throw_ub_format!( + "calling a c-variadic function via a non-variadic call site, or vice versa" + ); + } + if callee_fn_abi.c_variadic { + throw_unsup_format!("calling a c-variadic function is not supported"); + } if M::enforce_abi(self) { - check_abi(callee_abi)?; + if caller_fn_abi.conv != callee_fn_abi.conv { + throw_ub_format!( + "calling a function with calling convention {:?} using calling convention {:?}", + callee_fn_abi.conv, + caller_fn_abi.conv + ) + } } - if !matches!(unwind, StackPopUnwind::NotAllowed) - && !self - .fn_can_unwind(self.tcx.codegen_fn_attrs(callee_def_id).flags, callee_abi) - { + if !matches!(unwind, StackPopUnwind::NotAllowed) && !callee_fn_abi.can_unwind { // The callee cannot unwind. unwind = StackPopUnwind::NotAllowed; } @@ -343,12 +384,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { .collect::<Vec<_>>() ); - // Figure out how to pass which arguments. - // The Rust ABI is special: ZST get skipped. - let rust_abi = matches!(caller_abi, Abi::Rust | Abi::RustCall); - - // We have two iterators: Where the arguments come from, - // and where they go to. + // In principle, we have two iterators: Where the arguments come from, and where + // they go to. // For where they come from: If the ABI is RustCall, we untuple the // last incoming argument. These two iterators do not have the same type, @@ -373,53 +410,59 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // Plain arg passing Cow::from(args) }; - // Skip ZSTs - let mut caller_iter = - caller_args.iter().filter(|op| !rust_abi || !op.layout.is_zst()).copied(); + // If `with_caller_location` is set we pretend there is an extra argument (that + // we will not pass). + assert_eq!( + caller_args.len() + if with_caller_location { 1 } else { 0 }, + caller_fn_abi.args.len(), + "mismatch between caller ABI and caller arguments", + ); + let mut caller_args = caller_args + .iter() + .zip(caller_fn_abi.args.iter()) + .filter(|arg_and_abi| !matches!(arg_and_abi.1.mode, PassMode::Ignore)); // Now we have to spread them out across the callee's locals, // taking into account the `spread_arg`. If we could write // this is a single iterator (that handles `spread_arg`), then // `pass_argument` would be the loop body. It takes care to // not advance `caller_iter` for ZSTs. + let mut callee_args_abis = callee_fn_abi.args.iter(); for local in body.args_iter() { let dest = self.eval_place(mir::Place::from(local))?; if Some(local) == body.spread_arg { // Must be a tuple for i in 0..dest.layout.fields.count() { let dest = self.place_field(&dest, i)?; - self.pass_argument(rust_abi, &mut caller_iter, &dest)?; + let callee_abi = callee_args_abis.next().unwrap(); + self.pass_argument(&mut caller_args, callee_abi, &dest)?; } } else { // Normal argument - self.pass_argument(rust_abi, &mut caller_iter, &dest)?; + let callee_abi = callee_args_abis.next().unwrap(); + self.pass_argument(&mut caller_args, callee_abi, &dest)?; } } - // Now we should have no more caller args - if caller_iter.next().is_some() { + // If the callee needs a caller location, pretend we consume one more argument from the ABI. + if instance.def.requires_caller_location(*self.tcx) { + callee_args_abis.next().unwrap(); + } + // Now we should have no more caller args or callee arg ABIs + assert!( + callee_args_abis.next().is_none(), + "mismatch between callee ABI and callee body arguments" + ); + if caller_args.next().is_some() { throw_ub_format!("calling a function with more arguments than it expected") } // Don't forget to check the return type! - if let Some((caller_ret, _)) = ret { - let callee_ret = self.eval_place(mir::Place::return_place())?; - if !Self::check_argument_compat( - rust_abi, - caller_ret.layout, - callee_ret.layout, - ) { - throw_ub_format!( - "calling a function with return type {:?} passing \ - return place of type {:?}", - callee_ret.layout.ty, - caller_ret.layout.ty - ) - } - } else { - let local = mir::RETURN_PLACE; - let callee_layout = self.layout_of_local(self.frame(), local, None)?; - if !callee_layout.abi.is_uninhabited() { - throw_ub_format!("calling a returning function without a return place") - } + if !Self::check_argument_compat(&caller_fn_abi.ret, &callee_fn_abi.ret) { + throw_ub_format!( + "calling a function with return type {:?} passing \ + return place of type {:?}", + callee_fn_abi.ret.layout.ty, + caller_fn_abi.ret.layout.ty, + ) } }; match res { @@ -464,7 +507,14 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { )); trace!("Patched self operand to {:#?}", args[0]); // recurse with concrete function - self.eval_fn_call(fn_val, caller_abi, &args, ret, unwind) + self.eval_fn_call( + fn_val, + (caller_abi, caller_fn_abi), + &args, + with_caller_location, + ret, + unwind, + ) } } } @@ -489,6 +539,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } _ => (instance, place), }; + let fn_abi = self.fn_abi_of_instance(instance, ty::List::empty())?; let arg = ImmTy::from_immediate( place.to_ref(self), @@ -500,8 +551,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { self.eval_fn_call( FnVal::Instance(instance), - Abi::Rust, + (Abi::Rust, fn_abi), &[arg.into()], + false, Some((&dest.into(), target)), match unwind { Some(cleanup) => StackPopUnwind::Cleanup(cleanup), 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/check_consts/qualifs.rs b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs index a8077b258bb..27f2da34262 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs @@ -270,7 +270,8 @@ where Rvalue::Aggregate(kind, operands) => { // Return early if we know that the struct or enum being constructed is always // qualified. - if let AggregateKind::Adt(def, _, substs, ..) = **kind { + if let AggregateKind::Adt(adt_did, _, substs, ..) = **kind { + let def = cx.tcx.adt_def(adt_did); if Q::in_adt_inherently(cx, def, substs) { return true; } 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_const_eval/src/util/aggregate.rs b/compiler/rustc_const_eval/src/util/aggregate.rs index 4bc0357cab8..e5f5e7072d5 100644 --- a/compiler/rustc_const_eval/src/util/aggregate.rs +++ b/compiler/rustc_const_eval/src/util/aggregate.rs @@ -22,7 +22,8 @@ pub fn expand_aggregate<'tcx>( ) -> impl Iterator<Item = Statement<'tcx>> + TrustedLen { let mut set_discriminant = None; let active_field_index = match kind { - AggregateKind::Adt(adt_def, variant_index, _, _, active_field_index) => { + AggregateKind::Adt(adt_did, variant_index, _, _, active_field_index) => { + let adt_def = tcx.adt_def(adt_did); if adt_def.is_enum() { set_discriminant = Some(Statement { kind: StatementKind::SetDiscriminant { place: Box::new(lhs), variant_index }, 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/stable_hasher.rs b/compiler/rustc_data_structures/src/stable_hasher.rs index d87aa5ed0d5..3da35178957 100644 --- a/compiler/rustc_data_structures/src/stable_hasher.rs +++ b/compiler/rustc_data_structures/src/stable_hasher.rs @@ -379,9 +379,8 @@ impl<T: ?Sized + HashStable<CTX>, CTX> HashStable<CTX> for ::std::sync::Arc<T> { impl<CTX> HashStable<CTX> for str { #[inline] - fn hash_stable(&self, _: &mut CTX, hasher: &mut StableHasher) { - self.len().hash(hasher); - self.as_bytes().hash(hasher); + fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { + self.as_bytes().hash_stable(ctx, hasher); } } 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..694c679c158 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') { @@ -1047,7 +1040,7 @@ pub fn handle_options(args: &[String]) -> Option<getopts::Matches> { let wall = matches.opt_strs("W"); if wall.iter().any(|x| *x == "all") { print_wall_help(); - return None; + rustc_errors::FatalError.raise(); } // Don't handle -W help here, because we might first load plugins. @@ -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_error_codes/src/error_codes.rs b/compiler/rustc_error_codes/src/error_codes.rs index ce26ff62235..79d9c55b547 100644 --- a/compiler/rustc_error_codes/src/error_codes.rs +++ b/compiler/rustc_error_codes/src/error_codes.rs @@ -120,6 +120,7 @@ E0223: include_str!("./error_codes/E0223.md"), E0224: include_str!("./error_codes/E0224.md"), E0225: include_str!("./error_codes/E0225.md"), E0226: include_str!("./error_codes/E0226.md"), +E0227: include_str!("./error_codes/E0227.md"), E0228: include_str!("./error_codes/E0228.md"), E0229: include_str!("./error_codes/E0229.md"), E0230: include_str!("./error_codes/E0230.md"), @@ -530,7 +531,6 @@ E0786: include_str!("./error_codes/E0786.md"), // E0217, // ambiguous associated type, defined in multiple supertraits // E0218, // no associated type defined // E0219, // associated type defined in higher-ranked supertrait - E0227, // ambiguous lifetime bound, explicit lifetime bound required // E0233, // E0234, // E0235, // structure constructor specifies a structure of type but diff --git a/compiler/rustc_error_codes/src/error_codes/E0227.md b/compiler/rustc_error_codes/src/error_codes/E0227.md new file mode 100644 index 00000000000..f68614723d4 --- /dev/null +++ b/compiler/rustc_error_codes/src/error_codes/E0227.md @@ -0,0 +1,33 @@ +This error indicates that the compiler is unable to determine whether there is +exactly one unique region in the set of derived region bounds. + +Example of erroneous code: + +```compile_fail,E0227 +trait Foo<'foo>: 'foo {} +trait Bar<'bar>: 'bar {} + +trait FooBar<'foo, 'bar>: Foo<'foo> + Bar<'bar> {} + +struct Baz<'foo, 'bar> { + baz: dyn FooBar<'foo, 'bar>, +} +``` + +Here, `baz` can have either `'foo` or `'bar` lifetimes. + +To resolve this error, provide an explicit lifetime: + +```rust +trait Foo<'foo>: 'foo {} +trait Bar<'bar>: 'bar {} + +trait FooBar<'foo, 'bar>: Foo<'foo> + Bar<'bar> {} + +struct Baz<'foo, 'bar, 'baz> +where + 'baz: 'foo + 'bar, +{ + obj: dyn FooBar<'foo, 'bar> + 'baz, +} +``` 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 2f5f158856f..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("..."), @@ -2327,10 +2339,7 @@ impl<'a> State<'a> { arg_names: &[Ident], ) { self.ibox(INDENT_UNIT); - if !generic_params.is_empty() { - self.word("for"); - self.print_generic_params(generic_params); - } + self.print_formal_generic_params(generic_params); let generics = hir::Generics { params: &[], where_clause: hir::WhereClause { predicates: &[], span: rustc_span::DUMMY_SP }, 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..c21e4acbefe 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -341,14 +341,12 @@ extern "C" void LLVMRustRemoveFunctionAttributes(LLVMValueRef Fn, unsigned Index, LLVMRustAttribute RustAttr) { Function *F = unwrap<Function>(Fn); - Attribute Attr = Attribute::get(F->getContext(), fromRust(RustAttr)); - AttrBuilder B(Attr); - auto PAL = F->getAttributes(); + AttributeList PAL = F->getAttributes(); AttributeList PALNew; #if LLVM_VERSION_LT(14, 0) - PALNew = PAL.removeAttributes(F->getContext(), Index, B); + PALNew = PAL.removeAttribute(F->getContext(), Index, fromRust(RustAttr)); #else - PALNew = PAL.removeAttributesAtIndex(F->getContext(), Index, B); + PALNew = PAL.removeAttributeAtIndex(F->getContext(), Index, fromRust(RustAttr)); #endif F->setAttributes(PALNew); } @@ -716,6 +714,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 +977,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 +1055,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/creader.rs b/compiler/rustc_metadata/src/creader.rs index c0da386edfd..36a1798cd6a 100644 --- a/compiler/rustc_metadata/src/creader.rs +++ b/compiler/rustc_metadata/src/creader.rs @@ -102,30 +102,23 @@ struct CrateDump<'a>(&'a CStore); impl<'a> std::fmt::Debug for CrateDump<'a> { fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { writeln!(fmt, "resolved crates:")?; - // `iter_crate_data` does not allow returning values. Thus we use a mutable variable here - // that aggregates the value (and any errors that could happen). - let mut res = Ok(()); - self.0.iter_crate_data(|cnum, data| { - res = res.and( - try { - writeln!(fmt, " name: {}", data.name())?; - writeln!(fmt, " cnum: {}", cnum)?; - writeln!(fmt, " hash: {}", data.hash())?; - writeln!(fmt, " reqd: {:?}", data.dep_kind())?; - let CrateSource { dylib, rlib, rmeta } = data.source(); - if let Some(dylib) = dylib { - writeln!(fmt, " dylib: {}", dylib.0.display())?; - } - if let Some(rlib) = rlib { - writeln!(fmt, " rlib: {}", rlib.0.display())?; - } - if let Some(rmeta) = rmeta { - writeln!(fmt, " rmeta: {}", rmeta.0.display())?; - } - }, - ); - }); - res + for (cnum, data) in self.0.iter_crate_data() { + writeln!(fmt, " name: {}", data.name())?; + writeln!(fmt, " cnum: {}", cnum)?; + writeln!(fmt, " hash: {}", data.hash())?; + writeln!(fmt, " reqd: {:?}", data.dep_kind())?; + let CrateSource { dylib, rlib, rmeta } = data.source(); + if let Some(dylib) = dylib { + writeln!(fmt, " dylib: {}", dylib.0.display())?; + } + if let Some(rlib) = rlib { + writeln!(fmt, " rlib: {}", rlib.0.display())?; + } + if let Some(rmeta) = rmeta { + writeln!(fmt, " rmeta: {}", rmeta.0.display())?; + } + } + Ok(()) } } @@ -154,12 +147,10 @@ impl CStore { self.metas[cnum] = Some(Lrc::new(data)); } - crate fn iter_crate_data(&self, mut f: impl FnMut(CrateNum, &CrateMetadata)) { - for (cnum, data) in self.metas.iter_enumerated() { - if let Some(data) = data { - f(cnum, data); - } - } + crate fn iter_crate_data(&self) -> impl Iterator<Item = (CrateNum, &CrateMetadata)> { + self.metas + .iter_enumerated() + .filter_map(|(cnum, data)| data.as_ref().map(|data| (cnum, &**data))) } fn push_dependencies_in_postorder(&self, deps: &mut Vec<CrateNum>, cnum: CrateNum) { @@ -178,7 +169,9 @@ impl CStore { crate fn crate_dependencies_in_postorder(&self, cnum: CrateNum) -> Vec<CrateNum> { let mut deps = Vec::new(); if cnum == LOCAL_CRATE { - self.iter_crate_data(|cnum, _| self.push_dependencies_in_postorder(&mut deps, cnum)); + for (cnum, _) in self.iter_crate_data() { + self.push_dependencies_in_postorder(&mut deps, cnum); + } } else { self.push_dependencies_in_postorder(&mut deps, cnum); } @@ -263,21 +256,17 @@ impl<'a> CrateLoader<'a> { } fn existing_match(&self, name: Symbol, hash: Option<Svh>, kind: PathKind) -> Option<CrateNum> { - let mut ret = None; - self.cstore.iter_crate_data(|cnum, data| { + for (cnum, data) in self.cstore.iter_crate_data() { if data.name() != name { tracing::trace!("{} did not match {}", data.name(), name); - return; + continue; } match hash { - Some(hash) if hash == data.hash() => { - ret = Some(cnum); - return; - } + Some(hash) if hash == data.hash() => return Some(cnum), Some(hash) => { debug!("actual hash {} did not match expected {}", hash, data.hash()); - return; + continue; } None => {} } @@ -301,10 +290,10 @@ impl<'a> CrateLoader<'a> { || source.rlib.as_ref().map(|(p, _)| p) == Some(l) || source.rmeta.as_ref().map(|(p, _)| p) == Some(l) }) { - ret = Some(cnum); + return Some(cnum); } } - return; + continue; } // Alright, so we've gotten this far which means that `data` has the @@ -321,15 +310,16 @@ impl<'a> CrateLoader<'a> { .expect("No sources for crate") .1; if kind.matches(prev_kind) { - ret = Some(cnum); + return Some(cnum); } else { debug!( "failed to load existing crate {}; kind {:?} did not match prev_kind {:?}", name, kind, prev_kind ); } - }); - ret + } + + None } fn verify_no_symbol_conflicts(&self, root: &CrateRoot<'_>) -> Result<(), CrateError> { @@ -339,17 +329,14 @@ impl<'a> CrateLoader<'a> { } // Check for conflicts with any crate loaded so far - let mut res = Ok(()); - self.cstore.iter_crate_data(|_, other| { - if other.stable_crate_id() == root.stable_crate_id() && // same stable crate id - other.hash() != root.hash() - { - // but different SVH - res = Err(CrateError::SymbolConflictsOthers(root.name())); + for (_, other) in self.cstore.iter_crate_data() { + // Same stable crate id but different SVH + if other.stable_crate_id() == root.stable_crate_id() && other.hash() != root.hash() { + return Err(CrateError::SymbolConflictsOthers(root.name())); } - }); + } - res + Ok(()) } fn verify_no_stable_crate_id_hash_conflicts( @@ -607,13 +594,14 @@ impl<'a> CrateLoader<'a> { locator.triple == self.sess.opts.target_triple || locator.is_proc_macro; Ok(Some(if can_reuse_cratenum { let mut result = LoadResult::Loaded(library); - self.cstore.iter_crate_data(|cnum, data| { + for (cnum, data) in self.cstore.iter_crate_data() { if data.name() == root.name() && root.hash() == data.hash() { assert!(locator.hash.is_none()); info!("load success, going to previous cnum: {}", cnum); result = LoadResult::Previous(cnum); + break; } - }); + } result } else { LoadResult::Loaded(library) @@ -711,7 +699,7 @@ impl<'a> CrateLoader<'a> { let mut needs_panic_runtime = self.sess.contains_name(&krate.attrs, sym::needs_panic_runtime); - self.cstore.iter_crate_data(|cnum, data| { + for (cnum, data) in self.cstore.iter_crate_data() { needs_panic_runtime = needs_panic_runtime || data.needs_panic_runtime(); if data.is_panic_runtime() { // Inject a dependency from all #![needs_panic_runtime] to this @@ -721,7 +709,7 @@ impl<'a> CrateLoader<'a> { }); runtime_found = runtime_found || data.dep_kind() == CrateDepKind::Explicit; } - }); + } // If an explicitly linked and matching panic runtime was found, or if // we just don't need one at all, then we're done here and there's @@ -813,11 +801,9 @@ impl<'a> CrateLoader<'a> { // Check to see if we actually need an allocator. This desire comes // about through the `#![needs_allocator]` attribute and is typically // written down in liballoc. - let mut needs_allocator = self.sess.contains_name(&krate.attrs, sym::needs_allocator); - self.cstore.iter_crate_data(|_, data| { - needs_allocator = needs_allocator || data.needs_allocator(); - }); - if !needs_allocator { + if !self.sess.contains_name(&krate.attrs, sym::needs_allocator) + && !self.cstore.iter_crate_data().any(|(_, data)| data.needs_allocator()) + { return; } @@ -838,23 +824,19 @@ impl<'a> CrateLoader<'a> { // global allocator. let mut global_allocator = self.cstore.has_global_allocator.then(|| Symbol::intern("this crate")); - self.cstore.iter_crate_data(|_, data| { - if !data.has_global_allocator() { - return; - } - match global_allocator { - Some(other_crate) => { - self.sess.err(&format!( - "the `#[global_allocator]` in {} \ - conflicts with global \ - allocator in: {}", + for (_, data) in self.cstore.iter_crate_data() { + if data.has_global_allocator() { + match global_allocator { + Some(other_crate) => self.sess.err(&format!( + "the `#[global_allocator]` in {} conflicts with global allocator in: {}", other_crate, data.name() - )); + )), + None => global_allocator = Some(data.name()), } - None => global_allocator = Some(data.name()), } - }); + } + if global_allocator.is_some() { self.cstore.allocator_kind = Some(AllocatorKind::Global); return; @@ -864,19 +846,12 @@ impl<'a> CrateLoader<'a> { // allocator. At this point our allocator request is typically fulfilled // by the standard library, denoted by the `#![default_lib_allocator]` // attribute. - let mut has_default = self.sess.contains_name(&krate.attrs, sym::default_lib_allocator); - self.cstore.iter_crate_data(|_, data| { - if data.has_default_lib_allocator() { - has_default = true; - } - }); - - if !has_default { + if !self.sess.contains_name(&krate.attrs, sym::default_lib_allocator) + && !self.cstore.iter_crate_data().any(|(_, data)| data.has_default_lib_allocator()) + { self.sess.err( - "no global memory allocator found but one is \ - required; link to std or \ - add `#[global_allocator]` to a static item \ - that implements the GlobalAlloc trait", + "no global memory allocator found but one is required; link to std or add \ + `#[global_allocator]` to a static item that implements the GlobalAlloc trait", ); } self.cstore.allocator_kind = Some(AllocatorKind::Default); @@ -916,14 +891,12 @@ impl<'a> CrateLoader<'a> { // crate provided for this compile, but in order for this compilation to // be successfully linked we need to inject a dependency (to order the // crates on the command line correctly). - self.cstore.iter_crate_data(|cnum, data| { - if !needs_dep(data) { - return; + for (cnum, data) in self.cstore.iter_crate_data() { + if needs_dep(data) { + info!("injecting a dep from {} to {}", cnum, krate); + data.add_dependency(krate); } - - info!("injecting a dep from {} to {}", cnum, krate); - data.add_dependency(krate); - }); + } } fn report_unused_deps(&mut self, krate: &ast::Crate) { diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index 09c6cb010b0..5c275279579 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -27,6 +27,7 @@ use rustc_middle::mir::interpret::{AllocDecodingSession, AllocDecodingState}; use rustc_middle::mir::{self, Body, Promoted}; use rustc_middle::thir; use rustc_middle::ty::codec::TyDecoder; +use rustc_middle::ty::fast_reject::SimplifiedType; use rustc_middle::ty::{self, Ty, TyCtxt, Visibility}; use rustc_serialize::{opaque, Decodable, Decoder}; use rustc_session::cstore::{ @@ -45,7 +46,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; @@ -91,8 +93,7 @@ crate struct CrateMetadata { /// Trait impl data. /// FIXME: Used only from queries and can use query cache, /// so pre-decoding can probably be avoided. - trait_impls: - FxHashMap<(u32, DefIndex), Lazy<[(DefIndex, Option<ty::fast_reject::SimplifiedType>)]>>, + trait_impls: FxHashMap<(u32, DefIndex), Lazy<[(DefIndex, Option<SimplifiedType>)]>>, /// Proc macro descriptions for this crate, if it's a proc macro crate. raw_proc_macros: Option<&'static [ProcMacro]>, /// Source maps for code from the crate. @@ -721,25 +722,24 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { &self.raw_proc_macros.unwrap()[pos] } - fn try_item_ident(&self, item_index: DefIndex, sess: &Session) -> Result<Ident, String> { - let name = self - .def_key(item_index) - .disambiguated_data - .data - .get_opt_name() - .ok_or_else(|| format!("Missing opt name for {:?}", item_index))?; - let span = self - .root - .tables - .ident_span - .get(self, item_index) - .ok_or_else(|| format!("Missing ident span for {:?} ({:?})", name, item_index))? - .decode((self, sess)); - Ok(Ident::new(name, span)) + fn opt_item_ident(&self, item_index: DefIndex, sess: &Session) -> Option<Ident> { + let name = self.def_key(item_index).disambiguated_data.data.get_opt_name()?; + let span = match self.root.tables.ident_span.get(self, item_index) { + Some(lazy_span) => lazy_span.decode((self, sess)), + None => { + // FIXME: this weird case of a name with no span is specific to `extern crate` + // items, which are supposed to be treated like `use` items and only be encoded + // to metadata as `Export`s, return `None` because that's what all the callers + // expect in this case. + assert_eq!(self.def_kind(item_index), DefKind::ExternCrate); + return None; + } + }; + Some(Ident::new(name, span)) } fn item_ident(&self, item_index: DefIndex, sess: &Session) -> Ident { - self.try_item_ident(item_index, sess).unwrap() + self.opt_item_ident(item_index, sess).expect("no encoded ident for item") } fn maybe_kind(&self, item_id: DefIndex) -> Option<EntryKind> { @@ -1008,6 +1008,10 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { self.get_impl_data(id).constness } + fn get_trait_item_def_id(&self, id: DefIndex) -> Option<DefId> { + self.root.tables.trait_item_def_id.get(self, id).map(|d| d.decode(self)) + } + fn get_coerce_unsized_info(&self, id: DefIndex) -> Option<ty::adjustment::CoerceUnsizedInfo> { self.get_impl_data(id).coerce_unsized_info } @@ -1099,70 +1103,29 @@ 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)) { - // Get the item. - let child_kind = match self.maybe_kind(child_index) { - Some(child_kind) => child_kind, - None => continue, - }; - - // Hand off the item to the callback. - match child_kind { - // FIXME(eddyb) Don't encode these in children. - EntryKind::ForeignMod => { - let child_children = self - .root - .tables - .children - .get(self, child_index) - .unwrap_or_else(Lazy::empty); - for child_index in child_children.decode((self, sess)) { - let kind = self.def_kind(child_index); - callback(Export { - res: Res::Def(kind, self.local_def_id(child_index)), - ident: self.item_ident(child_index, sess), - vis: self.get_visibility(child_index), - span: self - .root - .tables - .span - .get(self, child_index) - .unwrap() - .decode((self, sess)), - }); - } + if let Some(ident) = self.opt_item_ident(child_index, sess) { + let kind = self.def_kind(child_index); + if matches!(kind, DefKind::Macro(..)) { + // FIXME: Macros are currently encoded twice, once as items and once as + // reexports. We ignore the items here and only use the reexports. continue; } - EntryKind::Impl(_) => continue, - - _ => {} - } - - let def_key = self.def_key(child_index); - if def_key.disambiguated_data.data.get_opt_name().is_some() { - let span = self.get_span(child_index, sess); - let kind = self.def_kind(child_index); - let ident = self.item_ident(child_index, sess); - let vis = self.get_visibility(child_index); let def_id = self.local_def_id(child_index); let res = Res::Def(kind, def_id); + let vis = self.get_visibility(child_index); + let span = self.get_span(child_index, sess); - // FIXME: Macros are currently encoded twice, once as items and once as - // reexports. We ignore the items here and only use the reexports. - if !matches!(kind, DefKind::Macro(..)) { - callback(Export { res, ident, vis, span }); - } + callback(Export { ident, res, vis, span }); // For non-re-export structs and variants add their constructors to children. // Re-export lists automatically contain constructors when necessary. match kind { DefKind::Struct => { - if let Some(ctor_def_id) = self.get_ctor_def_id(child_index) { - let ctor_kind = self.get_ctor_kind(child_index); + if let Some((ctor_def_id, ctor_kind)) = + self.get_ctor_def_id_and_kind(child_index) + { let ctor_res = Res::Def(DefKind::Ctor(CtorOf::Struct, ctor_kind), ctor_def_id); let vis = self.get_visibility(ctor_def_id.index); @@ -1174,8 +1137,9 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { // value namespace, they are reserved for possible future use. // It's ok to use the variant's id as a ctor id since an // error will be reported on any use of such resolution anyway. - let ctor_def_id = self.get_ctor_def_id(child_index).unwrap_or(def_id); - let ctor_kind = self.get_ctor_kind(child_index); + let (ctor_def_id, ctor_kind) = self + .get_ctor_def_id_and_kind(child_index) + .unwrap_or((def_id, CtorKind::Fictive)); let ctor_res = Res::Def(DefKind::Ctor(CtorOf::Variant, ctor_kind), ctor_def_id); let mut vis = self.get_visibility(ctor_def_id.index); @@ -1200,11 +1164,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); } } @@ -1296,6 +1255,23 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { } } + fn get_fn_has_self_parameter(&self, id: DefIndex) -> bool { + match self.kind(id) { + EntryKind::AssocFn(data) => data.decode(self).has_self, + _ => false, + } + } + + fn get_associated_item_def_ids(&self, tcx: TyCtxt<'tcx>, id: DefIndex) -> &'tcx [DefId] { + if let Some(children) = self.root.tables.children.get(self, id) { + tcx.arena.alloc_from_iter( + children.decode((self, tcx.sess)).map(|child_index| self.local_def_id(child_index)), + ) + } else { + &[] + } + } + fn get_associated_item(&self, id: DefIndex, sess: &Session) -> ty::AssocItem { let def_key = self.def_key(id); let parent = self.local_def_id(def_key.parent.unwrap()); @@ -1317,6 +1293,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { vis: self.get_visibility(id), defaultness: container.defaultness(), def_id: self.local_def_id(id), + trait_item_def_id: self.get_trait_item_def_id(id), container: container.with_def_id(parent), fn_has_self_parameter: has_self, } @@ -1326,22 +1303,11 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { self.root.tables.variances.get(self, id).unwrap_or_else(Lazy::empty).decode(self) } - fn get_ctor_kind(&self, node_id: DefIndex) -> CtorKind { + fn get_ctor_def_id_and_kind(&self, node_id: DefIndex) -> Option<(DefId, CtorKind)> { match self.kind(node_id) { - EntryKind::Struct(data, _) | EntryKind::Union(data, _) | EntryKind::Variant(data) => { - data.decode(self).ctor_kind - } - _ => CtorKind::Fictive, - } - } - - fn get_ctor_def_id(&self, node_id: DefIndex) -> Option<DefId> { - match self.kind(node_id) { - EntryKind::Struct(data, _) => { - data.decode(self).ctor.map(|index| self.local_def_id(index)) - } - EntryKind::Variant(data) => { - data.decode(self).ctor.map(|index| self.local_def_id(index)) + EntryKind::Struct(data, _) | EntryKind::Variant(data) => { + let vdata = data.decode(self); + vdata.ctor.map(|index| (self.local_def_id(index), vdata.ctor_kind)) } _ => None, } @@ -1349,24 +1315,26 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { fn get_item_attrs( &'a self, - node_id: DefIndex, + id: DefIndex, sess: &'a Session, ) -> impl Iterator<Item = ast::Attribute> + 'a { - // The attributes for a tuple struct/variant are attached to the definition, not the ctor; - // we assume that someone passing in a tuple struct ctor is actually wanting to - // look at the definition - let def_key = self.def_key(node_id); - let item_id = if def_key.disambiguated_data.data == DefPathData::Ctor { - def_key.parent.unwrap() - } else { - node_id - }; - self.root .tables .attributes - .get(self, item_id) - .unwrap_or_else(Lazy::empty) + .get(self, id) + .unwrap_or_else(|| { + // Structure and variant constructors don't have any attributes encoded for them, + // but we assume that someone passing a constructor ID actually wants to look at + // the attributes on the corresponding struct or variant. + let def_key = self.def_key(id); + assert_eq!(def_key.disambiguated_data.data, DefPathData::Ctor); + let parent_id = def_key.parent.expect("no parent for a constructor"); + self.root + .tables + .attributes + .get(self, parent_id) + .expect("no encoded attributes for a structure or variant") + }) .decode((self, sess)) } @@ -1408,39 +1376,43 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { ) } - fn get_implementations_for_trait( + fn get_traits(&'a self) -> impl Iterator<Item = DefId> + 'a { + self.root.traits.decode(self).map(|index| self.local_def_id(index)) + } + + fn get_trait_impls(&'a self) -> impl Iterator<Item = (DefId, Option<SimplifiedType>)> + 'a { + self.trait_impls.values().flat_map(move |impls| { + impls + .decode(self) + .map(|(idx, simplified_self_ty)| (self.local_def_id(idx), simplified_self_ty)) + }) + } + + fn get_implementations_of_trait( &self, tcx: TyCtxt<'tcx>, - filter: Option<DefId>, - ) -> &'tcx [(DefId, Option<ty::fast_reject::SimplifiedType>)] { + trait_def_id: DefId, + ) -> &'tcx [(DefId, Option<SimplifiedType>)] { if self.root.is_proc_macro_crate() { // proc-macro crates export no trait impls. return &[]; } - if let Some(def_id) = filter { - // Do a reverse lookup beforehand to avoid touching the crate_num - // hash map in the loop below. - let filter = match self.reverse_translate_def_id(def_id) { - Some(def_id) => (def_id.krate.as_u32(), def_id.index), - None => return &[], - }; + // Do a reverse lookup beforehand to avoid touching the crate_num + // hash map in the loop below. + let key = match self.reverse_translate_def_id(trait_def_id) { + Some(def_id) => (def_id.krate.as_u32(), def_id.index), + None => return &[], + }; - if let Some(impls) = self.trait_impls.get(&filter) { - tcx.arena.alloc_from_iter( - impls.decode(self).map(|(idx, simplified_self_ty)| { - (self.local_def_id(idx), simplified_self_ty) - }), - ) - } else { - &[] - } - } else { - tcx.arena.alloc_from_iter(self.trait_impls.values().flat_map(|impls| { + if let Some(impls) = self.trait_impls.get(&key) { + tcx.arena.alloc_from_iter( impls .decode(self) - .map(|(idx, simplified_self_ty)| (self.local_def_id(idx), simplified_self_ty)) - })) + .map(|(idx, simplified_self_ty)| (self.local_def_id(idx), simplified_self_ty)), + ) + } else { + &[] } } diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index 4e5d21049a0..804f277e26e 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -103,12 +103,7 @@ provide! { <'tcx> tcx, def_id, other, cdata, tcx.calculate_dtor(def_id, |_,_| Ok(())) } variances_of => { tcx.arena.alloc_from_iter(cdata.get_item_variances(def_id.index)) } - associated_item_def_ids => { - let mut result = SmallVec::<[_; 8]>::new(); - cdata.each_child_of_item(def_id.index, - |child| result.push(child.res.def_id()), tcx.sess); - tcx.arena.alloc_slice(&result) - } + associated_item_def_ids => { cdata.get_associated_item_def_ids(tcx, def_id.index) } associated_item => { cdata.get_associated_item(def_id.index, tcx.sess) } impl_trait_ref => { cdata.get_impl_trait(def_id.index, tcx) } impl_polarity => { cdata.get_impl_polarity(def_id.index) } @@ -133,9 +128,7 @@ provide! { <'tcx> tcx, def_id, other, cdata, generator_kind => { cdata.generator_kind(def_id.index) } opt_def_kind => { Some(cdata.def_kind(def_id.index)) } def_span => { cdata.get_span(def_id.index, &tcx.sess) } - def_ident_span => { - cdata.try_item_ident(def_id.index, &tcx.sess).ok().map(|ident| ident.span) - } + def_ident_span => { cdata.opt_item_ident(def_id.index, &tcx.sess).map(|ident| ident.span) } lookup_stability => { cdata.get_stability(def_id.index).map(|s| tcx.intern_stability(s)) } @@ -145,9 +138,7 @@ provide! { <'tcx> tcx, def_id, other, cdata, lookup_deprecation_entry => { cdata.get_deprecation(def_id.index).map(DeprecationEntry::external) } - item_attrs => { tcx.arena.alloc_from_iter( - cdata.get_item_attrs(def_id.index, tcx.sess) - ) } + item_attrs => { tcx.arena.alloc_from_iter(cdata.get_item_attrs(def_id.index, tcx.sess)) } fn_arg_names => { cdata.get_fn_param_names(tcx, def_id.index) } rendered_const => { cdata.get_rendered_const(def_id.index) } impl_parent => { cdata.get_parent_impl(def_id.index) } @@ -195,13 +186,10 @@ provide! { <'tcx> tcx, def_id, other, cdata, extra_filename => { cdata.root.extra_filename.clone() } - implementations_of_trait => { - cdata.get_implementations_for_trait(tcx, Some(other)) - } + traits_in_crate => { tcx.arena.alloc_from_iter(cdata.get_traits()) } + all_trait_implementations => { tcx.arena.alloc_from_iter(cdata.get_trait_impls()) } - all_trait_implementations => { - cdata.get_implementations_for_trait(tcx, None) - } + implementations_of_trait => { cdata.get_implementations_of_trait(tcx, other) } visibility => { cdata.get_visibility(def_id.index) } dep_kind => { @@ -239,7 +227,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 @@ -372,7 +360,7 @@ pub fn provide(providers: &mut Providers) { tcx.arena .alloc_slice(&CStore::from_tcx(tcx).crate_dependencies_in_postorder(LOCAL_CRATE)) }, - crates: |tcx, ()| tcx.arena.alloc_slice(&CStore::from_tcx(tcx).crates_untracked()), + crates: |tcx, ()| tcx.arena.alloc_from_iter(CStore::from_tcx(tcx).crates_untracked()), ..*providers }; @@ -388,9 +376,7 @@ impl CStore { } pub fn ctor_def_id_and_kind_untracked(&self, def: DefId) -> Option<(DefId, CtorKind)> { - self.get_crate_data(def.krate).get_ctor_def_id(def.index).map(|ctor_def_id| { - (ctor_def_id, self.get_crate_data(def.krate).get_ctor_kind(def.index)) - }) + self.get_crate_data(def.krate).get_ctor_def_id_and_kind(def.index) } pub fn visibility_untracked(&self, def: DefId) -> Visibility { @@ -417,16 +403,12 @@ impl CStore { let span = data.get_span(id.index, sess); - let attrs = data.get_item_attrs(id.index, sess).collect(); - - let ident = data.item_ident(id.index, sess); - LoadedMacro::MacroDef( ast::Item { - ident, + ident: data.item_ident(id.index, sess), id: ast::DUMMY_NODE_ID, span, - attrs, + attrs: data.get_item_attrs(id.index, sess).collect(), kind: ast::ItemKind::MacroDef(data.get_macro(id.index, sess)), vis: ast::Visibility { span: span.shrink_to_lo(), @@ -439,8 +421,8 @@ impl CStore { ) } - pub fn associated_item_cloned_untracked(&self, def: DefId, sess: &Session) -> ty::AssocItem { - self.get_crate_data(def.krate).get_associated_item(def.index, sess) + pub fn fn_has_self_parameter_untracked(&self, def: DefId) -> bool { + self.get_crate_data(def.krate).get_fn_has_self_parameter(def.index) } pub fn crate_source_untracked(&self, cnum: CrateNum) -> CrateSource { @@ -455,10 +437,8 @@ impl CStore { self.get_crate_data(def.krate).def_kind(def.index) } - pub fn crates_untracked(&self) -> Vec<CrateNum> { - let mut result = vec![]; - self.iter_crate_data(|cnum, _| result.push(cnum)); - result + pub fn crates_untracked(&self) -> impl Iterator<Item = CrateNum> + '_ { + self.iter_crate_data().map(|(cnum, _)| cnum) } pub fn item_generics_num_lifetimes(&self, def_id: DefId, sess: &Session) -> usize { @@ -476,7 +456,7 @@ impl CStore { self.get_crate_data(cnum).num_def_ids() } - pub fn item_attrs(&self, def_id: DefId, sess: &Session) -> Vec<ast::Attribute> { + pub fn item_attrs_untracked(&self, def_id: DefId, sess: &Session) -> Vec<ast::Attribute> { self.get_crate_data(def_id.krate).get_item_attrs(def_id.index, sess).collect() } @@ -536,4 +516,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 eeb907d0114..11a986f0a7c 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -26,7 +26,8 @@ use rustc_middle::mir::interpret; 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::fast_reject::{self, SimplifiedType, 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); @@ -1100,9 +1108,21 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { // Encode this here because we don't do it in encode_def_ids. record!(self.tables.expn_that_defined[def_id] <- tcx.expn_that_defined(local_def_id)); } else { - record!(self.tables.children[def_id] <- md.item_ids.iter().map(|item_id| { - item_id.def_id.local_def_index - })); + let direct_children = md.item_ids.iter().map(|item_id| item_id.def_id.local_def_index); + // Foreign items are planted into their parent modules from name resolution point of view. + let tcx = self.tcx; + let foreign_item_children = md + .item_ids + .iter() + .filter_map(|item_id| match tcx.hir().item(*item_id).kind { + hir::ItemKind::ForeignMod { items, .. } => { + Some(items.iter().map(|fi_ref| fi_ref.id.def_id.local_def_index)) + } + _ => None, + }) + .flatten(); + + record!(self.tables.children[def_id] <- direct_children.chain(foreign_item_children)); } } @@ -1274,6 +1294,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } self.encode_ident_span(def_id, impl_item.ident); self.encode_item_type(def_id); + if let Some(trait_item_def_id) = impl_item.trait_item_def_id { + record!(self.tables.trait_item_def_id[def_id] <- trait_item_def_id); + } if impl_item.kind == ty::AssocKind::Fn { record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(def_id)); } @@ -1503,11 +1526,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { record!(self.tables.kind[def_id] <- entry_kind); // FIXME(eddyb) there should be a nicer way to do this. match item.kind { - hir::ItemKind::ForeignMod { items, .. } => record!(self.tables.children[def_id] <- - items - .iter() - .map(|foreign_item| foreign_item.id.def_id.local_def_index) - ), hir::ItemKind::Enum(..) => record!(self.tables.children[def_id] <- self.tcx.adt_def(def_id).variants.iter().map(|v| { assert!(v.def_id.is_local()); @@ -1783,12 +1801,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(); @@ -2033,27 +2056,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>)>>, + impls: FxHashMap<DefId, Vec<(DefIndex, Option<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)); + } } + _ => {} } } @@ -2202,3 +2228,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..fa44cbc2d55 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -16,6 +16,8 @@ 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::fast_reject::SimplifiedType; +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 +31,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 +224,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>, @@ -259,7 +262,7 @@ crate struct CrateDep { #[derive(MetadataEncodable, MetadataDecodable)] crate struct TraitImpls { trait_id: (u32, DefIndex), - impls: Lazy<[(DefIndex, Option<ty::fast_reject::SimplifiedType>)]>, + impls: Lazy<[(DefIndex, Option<SimplifiedType>)]>, } /// Define `LazyTables` and `TableBuilders` at the same time. @@ -299,6 +302,7 @@ define_tables! { ty: Table<DefIndex, Lazy!(Ty<'tcx>)>, fn_sig: Table<DefIndex, Lazy!(ty::PolyFnSig<'tcx>)>, impl_trait_ref: Table<DefIndex, Lazy!(ty::TraitRef<'tcx>)>, + trait_item_def_id: Table<DefIndex, Lazy<DefId>>, inherent_impls: Table<DefIndex, Lazy<[DefIndex]>>, variances: Table<DefIndex, Lazy<[ty::Variance]>>, generics: Table<DefIndex, Lazy<ty::Generics>>, @@ -453,3 +457,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/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs index 37ec2006172..e9a857d0912 100644 --- a/compiler/rustc_middle/src/mir/interpret/error.rs +++ b/compiler/rustc_middle/src/mir/interpret/error.rs @@ -8,7 +8,7 @@ use rustc_errors::{pluralize, struct_span_err, DiagnosticBuilder, ErrorReported} use rustc_macros::HashStable; use rustc_session::CtfeBacktrace; use rustc_span::def_id::DefId; -use rustc_target::abi::{Align, Size}; +use rustc_target::abi::{call, Align, Size}; use std::{any::Any, backtrace::Backtrace, fmt}; #[derive(Debug, Copy, Clone, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)] @@ -141,6 +141,10 @@ pub enum InvalidProgramInfo<'tcx> { AlreadyReported(ErrorReported), /// An error occurred during layout computation. Layout(layout::LayoutError<'tcx>), + /// An error occurred during FnAbi computation: the passed --target lacks FFI support + /// (which unfortunately typeck does not reject). + /// Not using `FnAbiError` as that contains a nested `LayoutError`. + FnAbiAdjustForForeignAbi(call::AdjustForForeignAbiError), /// An invalid transmute happened. TransmuteSizeDiff(Ty<'tcx>, Ty<'tcx>), /// SizeOf of unsized type was requested. @@ -157,6 +161,7 @@ impl fmt::Display for InvalidProgramInfo<'_> { write!(f, "encountered constants with type errors, stopping evaluation") } Layout(ref err) => write!(f, "{}", err), + FnAbiAdjustForForeignAbi(ref err) => write!(f, "{}", err), TransmuteSizeDiff(from_ty, to_ty) => write!( f, "transmuting `{}` to `{}` is not possible, because these types do not have the same size", diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index d2dd15aad12..52ef380001c 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -2268,7 +2268,7 @@ pub enum AggregateKind<'tcx> { /// active field number and is present only for union expressions /// -- e.g., for a union expression `SomeUnion { c: .. }`, the /// active field index would identity the field `c` - Adt(&'tcx AdtDef, VariantIdx, SubstsRef<'tcx>, Option<UserTypeAnnotationIndex>, Option<usize>), + Adt(DefId, VariantIdx, SubstsRef<'tcx>, Option<UserTypeAnnotationIndex>, Option<usize>), Closure(DefId, SubstsRef<'tcx>), Generator(DefId, SubstsRef<'tcx>, hir::Movability), @@ -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)] @@ -2427,28 +2425,26 @@ impl<'tcx> Debug for Rvalue<'tcx> { } } - AggregateKind::Adt(adt_def, variant, substs, _user_ty, _) => { - let variant_def = &adt_def.variants[variant]; - - let name = ty::tls::with(|tcx| { + AggregateKind::Adt(adt_did, variant, substs, _user_ty, _) => { + ty::tls::with(|tcx| { let mut name = String::new(); + let variant_def = &tcx.adt_def(adt_did).variants[variant]; let substs = tcx.lift(substs).expect("could not lift for printing"); FmtPrinter::new(tcx, &mut name, Namespace::ValueNS) .print_def_path(variant_def.def_id, substs)?; - Ok(name) - })?; - - match variant_def.ctor_kind { - CtorKind::Const => fmt.write_str(&name), - CtorKind::Fn => fmt_tuple(fmt, &name), - CtorKind::Fictive => { - let mut struct_fmt = fmt.debug_struct(&name); - for (field, place) in iter::zip(&variant_def.fields, places) { - struct_fmt.field(field.ident.as_str(), place); + + match variant_def.ctor_kind { + CtorKind::Const => fmt.write_str(&name), + CtorKind::Fn => fmt_tuple(fmt, &name), + CtorKind::Fictive => { + let mut struct_fmt = fmt.debug_struct(&name); + for (field, place) in iter::zip(&variant_def.fields, places) { + struct_fmt.field(field.ident.as_str(), place); + } + struct_fmt.finish() } - struct_fmt.finish() } - } + }) } AggregateKind::Closure(def_id, substs) => ty::tls::with(|tcx| { diff --git a/compiler/rustc_middle/src/mir/tcx.rs b/compiler/rustc_middle/src/mir/tcx.rs index c3c5ebe705e..dc53dc8de9d 100644 --- a/compiler/rustc_middle/src/mir/tcx.rs +++ b/compiler/rustc_middle/src/mir/tcx.rs @@ -195,12 +195,11 @@ 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), AggregateKind::Tuple => tcx.mk_tup(ops.iter().map(|op| op.ty(local_decls, tcx))), - AggregateKind::Adt(def, _, substs, _, _) => tcx.type_of(def.did).subst(tcx, substs), + AggregateKind::Adt(did, _, substs, _, _) => tcx.type_of(did).subst(tcx, substs), AggregateKind::Closure(did, substs) => tcx.mk_closure(did, substs), AggregateKind::Generator(did, substs, movability) => { tcx.mk_generator(did, substs, movability) @@ -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..f1c2be660bc 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -630,6 +630,32 @@ rustc_queries! { desc { |tcx| "collecting associated items of {}", tcx.def_path_str(key) } } + /// Maps from associated items on a trait to the corresponding associated + /// item on the impl specified by `impl_id`. + /// + /// For example, with the following code + /// + /// ``` + /// struct Type {} + /// // DefId + /// trait Trait { // trait_id + /// fn f(); // trait_f + /// fn g() {} // trait_g + /// } + /// + /// impl Trait for Type { // impl_id + /// fn f() {} // impl_f + /// fn g() {} // impl_g + /// } + /// ``` + /// + /// The map returned for `tcx.impl_item_implementor_ids(impl_id)` would be + ///`{ trait_f: impl_f, trait_g: impl_g }` + query impl_item_implementor_ids(impl_id: DefId) -> FxHashMap<DefId, DefId> { + desc { |tcx| "comparing impl items against trait for {}", tcx.def_path_str(impl_id) } + storage(ArenaCacheSelector<'tcx>) + } + /// Given an `impl_id`, return the trait it implements. /// Return `None` if this is an inherent impl. query impl_trait_ref(impl_id: DefId) -> Option<ty::TraitRef<'tcx>> { @@ -1411,16 +1437,14 @@ rustc_queries! { /// Given a crate and a trait, look up all impls of that trait in the crate. /// Return `(impl_id, self_ty)`. - query implementations_of_trait(_: (CrateNum, DefId)) - -> &'tcx [(DefId, Option<ty::fast_reject::SimplifiedType>)] { + query implementations_of_trait(_: (CrateNum, DefId)) -> &'tcx [(DefId, Option<SimplifiedType>)] { desc { "looking up implementations of a trait in a crate" } separate_provide_extern } /// Given a crate, look up all trait impls in that crate. /// Return `(impl_id, self_ty)`. - query all_trait_implementations(_: CrateNum) - -> &'tcx [(DefId, Option<ty::fast_reject::SimplifiedType>)] { + query all_trait_implementations(_: CrateNum) -> &'tcx [(DefId, Option<SimplifiedType>)] { desc { "looking up all (?) trait implementations" } separate_provide_extern } @@ -1609,11 +1633,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/traits/specialization_graph.rs b/compiler/rustc_middle/src/traits/specialization_graph.rs index 3e9cd6b46b2..087be313b26 100644 --- a/compiler/rustc_middle/src/traits/specialization_graph.rs +++ b/compiler/rustc_middle/src/traits/specialization_graph.rs @@ -4,7 +4,6 @@ use crate::ty::{self, TyCtxt}; use rustc_data_structures::fx::FxIndexMap; use rustc_errors::ErrorReported; use rustc_hir::def_id::{DefId, DefIdMap}; -use rustc_span::symbol::Ident; /// A per-trait graph of impls in specialization order. At the moment, this /// graph forms a tree rooted with the trait itself, with all other nodes @@ -75,34 +74,28 @@ pub enum Node { Trait(DefId), } -impl<'tcx> Node { +impl Node { pub fn is_from_trait(&self) -> bool { matches!(self, Node::Trait(..)) } - /// Iterate over the items defined directly by the given (impl or trait) node. - pub fn items(&self, tcx: TyCtxt<'tcx>) -> impl 'tcx + Iterator<Item = &'tcx ty::AssocItem> { - tcx.associated_items(self.def_id()).in_definition_order() - } - - /// Finds an associated item defined in this node. + /// Trys to find the associated item that implements `trait_item_def_id` + /// defined in this node. /// /// If this returns `None`, the item can potentially still be found in /// parents of this node. - pub fn item( + pub fn item<'tcx>( &self, tcx: TyCtxt<'tcx>, - trait_item_name: Ident, - trait_item_kind: ty::AssocKind, - trait_def_id: DefId, - ) -> Option<ty::AssocItem> { - tcx.associated_items(self.def_id()) - .filter_by_name_unhygienic(trait_item_name.name) - .find(move |impl_item| { - trait_item_kind == impl_item.kind - && tcx.hygienic_eq(impl_item.ident, trait_item_name, trait_def_id) - }) - .copied() + trait_item_def_id: DefId, + ) -> Option<&'tcx ty::AssocItem> { + match *self { + Node::Trait(_) => Some(tcx.associated_item(trait_item_def_id)), + Node::Impl(impl_def_id) => { + let id = tcx.impl_item_implementor_ids(impl_def_id).get(&trait_item_def_id)?; + Some(tcx.associated_item(*id)) + } + } } pub fn def_id(&self) -> DefId { @@ -181,17 +174,11 @@ impl LeafDef { impl<'tcx> Ancestors<'tcx> { /// Finds the bottom-most (ie. most specialized) definition of an associated /// item. - pub fn leaf_def( - mut self, - tcx: TyCtxt<'tcx>, - trait_item_name: Ident, - trait_item_kind: ty::AssocKind, - ) -> Option<LeafDef> { - let trait_def_id = self.trait_def_id; + pub fn leaf_def(mut self, tcx: TyCtxt<'tcx>, trait_item_def_id: DefId) -> Option<LeafDef> { let mut finalizing_node = None; self.find_map(|node| { - if let Some(item) = node.item(tcx, trait_item_name, trait_item_kind, trait_def_id) { + if let Some(item) = node.item(tcx, trait_item_def_id) { if finalizing_node.is_none() { let is_specializable = item.defaultness.is_default() || tcx.impl_defaultness(node.def_id()).is_default(); @@ -201,7 +188,7 @@ impl<'tcx> Ancestors<'tcx> { } } - Some(LeafDef { item, defining_node: node, finalizing_node }) + Some(LeafDef { item: *item, defining_node: node, finalizing_node }) } else { // Item not mentioned. This "finalizes" any defaulted item provided by an ancestor. finalizing_node = Some(node); diff --git a/compiler/rustc_middle/src/ty/assoc.rs b/compiler/rustc_middle/src/ty/assoc.rs index bf5a3e68250..5af4eef40d4 100644 --- a/compiler/rustc_middle/src/ty/assoc.rs +++ b/compiler/rustc_middle/src/ty/assoc.rs @@ -40,6 +40,7 @@ impl AssocItemContainer { } } +/// Information about an associated item #[derive(Copy, Clone, Debug, PartialEq, HashStable, Eq, Hash)] pub struct AssocItem { pub def_id: DefId, @@ -50,6 +51,10 @@ pub struct AssocItem { pub defaultness: hir::Defaultness, pub container: AssocItemContainer, + /// If this is an item in an impl of a trait then this is the `DefId` of + /// the associated item on the trait that this implements. + pub trait_item_def_id: Option<DefId>, + /// Whether this is a method with an explicit self /// as its first parameter, allowing method calls. pub fn_has_self_parameter: bool, 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/fast_reject.rs b/compiler/rustc_middle/src/ty/fast_reject.rs index 04011552e31..daf9156a15f 100644 --- a/compiler/rustc_middle/src/ty/fast_reject.rs +++ b/compiler/rustc_middle/src/ty/fast_reject.rs @@ -143,6 +143,18 @@ pub fn simplify_type( } impl<D: Copy + Debug + Ord + Eq> SimplifiedTypeGen<D> { + pub fn def(self) -> Option<D> { + match self { + AdtSimplifiedType(d) + | ForeignSimplifiedType(d) + | TraitSimplifiedType(d) + | ClosureSimplifiedType(d) + | GeneratorSimplifiedType(d) + | OpaqueSimplifiedType(d) => Some(d), + _ => None, + } + } + pub fn map_def<U, F>(self, map: F) -> SimplifiedTypeGen<U> where F: Fn(D) -> U, diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index 7ec6d3f3b2b..196fe7ce1b6 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -2581,9 +2581,12 @@ impl<'tcx> ty::Instance<'tcx> { // for `Instance` (e.g. typeck would use `Ty::fn_sig` instead), // or should go through `FnAbi` instead, to avoid losing any // adjustments `fn_abi_of_instance` might be performing. - fn fn_sig_for_fn_abi(&self, tcx: TyCtxt<'tcx>) -> ty::PolyFnSig<'tcx> { - // FIXME(davidtwco,eddyb): A `ParamEnv` should be passed through to this function. - let ty = self.ty(tcx, ty::ParamEnv::reveal_all()); + fn fn_sig_for_fn_abi( + &self, + tcx: TyCtxt<'tcx>, + param_env: ty::ParamEnv<'tcx>, + ) -> ty::PolyFnSig<'tcx> { + let ty = self.ty(tcx, param_env); match *ty.kind() { ty::FnDef(..) => { // HACK(davidtwco,eddyb): This is a workaround for polymorphization considering @@ -2965,7 +2968,7 @@ fn fn_abi_of_instance<'tcx>( ) -> Result<&'tcx FnAbi<'tcx, Ty<'tcx>>, FnAbiError<'tcx>> { let (param_env, (instance, extra_args)) = query.into_parts(); - let sig = instance.fn_sig_for_fn_abi(tcx); + let sig = instance.fn_sig_for_fn_abi(tcx, param_env); let caller_location = if instance.def.requires_caller_location(tcx) { Some(tcx.caller_location_ty()) 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/query.rs b/compiler/rustc_middle/src/ty/query.rs index 2f91503afdf..3af1b3a0440 100644 --- a/compiler/rustc_middle/src/ty/query.rs +++ b/compiler/rustc_middle/src/ty/query.rs @@ -28,6 +28,7 @@ use crate::traits::query::{ }; use crate::traits::specialization_graph; use crate::traits::{self, ImplSource}; +use crate::ty::fast_reject::SimplifiedType; use crate::ty::subst::{GenericArg, SubstsRef}; use crate::ty::util::AlwaysRequiresDrop; use crate::ty::{self, AdtSizedConstraint, CrateInherentImpls, ParamEnvAnd, Ty, TyCtxt}; 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_middle/src/ty/trait_def.rs b/compiler/rustc_middle/src/ty/trait_def.rs index cbb88def7e2..34d059f4ec8 100644 --- a/compiler/rustc_middle/src/ty/trait_def.rs +++ b/compiler/rustc_middle/src/ty/trait_def.rs @@ -1,5 +1,5 @@ use crate::traits::specialization_graph; -use crate::ty::fast_reject::{self, SimplifyParams, StripReferences}; +use crate::ty::fast_reject::{self, SimplifiedType, SimplifyParams, StripReferences}; use crate::ty::fold::TypeFoldable; use crate::ty::{Ty, TyCtxt}; use rustc_hir as hir; @@ -68,7 +68,7 @@ pub enum TraitSpecializationKind { pub struct TraitImpls { blanket_impls: Vec<DefId>, /// Impls indexed by their simplified self type, for fast lookup. - non_blanket_impls: FxIndexMap<fast_reject::SimplifiedType, Vec<DefId>>, + non_blanket_impls: FxIndexMap<SimplifiedType, Vec<DefId>>, } impl TraitImpls { diff --git a/compiler/rustc_mir_build/src/build/expr/into.rs b/compiler/rustc_mir_build/src/build/expr/into.rs index abec67af08b..d9896ff5ac9 100644 --- a/compiler/rustc_mir_build/src/build/expr/into.rs +++ b/compiler/rustc_mir_build/src/build/expr/into.rs @@ -377,7 +377,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { }) }); let adt = Box::new(AggregateKind::Adt( - adt_def, + adt_def.did, variant_index, substs, user_ty, 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/check_unsafety.rs b/compiler/rustc_mir_transform/src/check_unsafety.rs index 2dda19badd7..a40c4d1c366 100644 --- a/compiler/rustc_mir_transform/src/check_unsafety.rs +++ b/compiler/rustc_mir_transform/src/check_unsafety.rs @@ -117,8 +117,8 @@ impl<'tcx> Visitor<'tcx> for UnsafetyChecker<'_, 'tcx> { match rvalue { Rvalue::Aggregate(box ref aggregate, _) => match aggregate { &AggregateKind::Array(..) | &AggregateKind::Tuple => {} - &AggregateKind::Adt(ref def, ..) => { - match self.tcx.layout_scalar_valid_range(def.did) { + &AggregateKind::Adt(adt_did, ..) => { + match self.tcx.layout_scalar_valid_range(adt_did) { (Bound::Unbounded, Bound::Unbounded) => {} _ => self.require_unsafe( UnsafetyViolationKind::General, diff --git a/compiler/rustc_mir_transform/src/const_prop.rs b/compiler/rustc_mir_transform/src/const_prop.rs index 84bdb8eece6..e3ff6ad4549 100644 --- a/compiler/rustc_mir_transform/src/const_prop.rs +++ b/compiler/rustc_mir_transform/src/const_prop.rs @@ -207,7 +207,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx> _args: &[OpTy<'tcx>], _ret: Option<(&PlaceTy<'tcx>, BasicBlock)>, _unwind: StackPopUnwind, - ) -> InterpResult<'tcx, Option<&'mir Body<'tcx>>> { + ) -> InterpResult<'tcx, Option<(&'mir Body<'tcx>, ty::Instance<'tcx>)>> { Ok(None) } @@ -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_mir_transform/src/generator.rs b/compiler/rustc_mir_transform/src/generator.rs index 6220cee8d21..bc9a104e849 100644 --- a/compiler/rustc_mir_transform/src/generator.rs +++ b/compiler/rustc_mir_transform/src/generator.rs @@ -243,7 +243,7 @@ impl<'tcx> TransformVisitor<'tcx> { val: Operand<'tcx>, source_info: SourceInfo, ) -> impl Iterator<Item = Statement<'tcx>> { - let kind = AggregateKind::Adt(self.state_adt_ref, idx, self.state_substs, None, None); + let kind = AggregateKind::Adt(self.state_adt_ref.did, idx, self.state_substs, None, None); assert_eq!(self.state_adt_ref.variants[idx].fields.len(), 1); let ty = self .tcx diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs index d0039380361..58996dcd673 100644 --- a/compiler/rustc_mir_transform/src/shim.rs +++ b/compiler/rustc_mir_transform/src/shim.rs @@ -777,7 +777,7 @@ pub fn build_adt_ctor(tcx: TyCtxt<'_>, ctor_id: DefId) -> Body<'_> { adt_def.variants[variant_index].fields.iter().enumerate().map(|(idx, field_def)| { (Operand::Move(Place::from(Local::new(idx + 1))), field_def.ty(tcx, substs)) }), - AggregateKind::Adt(adt_def, variant_index, substs, None, None), + AggregateKind::Adt(adt_def.did, variant_index, substs, None, None), source_info, tcx, ) diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index b1fa9041342..3e06e7f36d4 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); @@ -1319,10 +1310,9 @@ fn create_mono_items_for_default_impls<'tcx>( if let Some(trait_ref) = tcx.impl_trait_ref(item.def_id) { let param_env = ty::ParamEnv::reveal_all(); let trait_ref = tcx.normalize_erasing_regions(param_env, trait_ref); - let overridden_methods: FxHashSet<_> = - impl_.items.iter().map(|iiref| iiref.ident.normalize_to_macros_2_0()).collect(); + let overridden_methods = tcx.impl_item_implementor_ids(item.def_id); for method in tcx.provided_trait_methods(trait_ref.def_id) { - if overridden_methods.contains(&method.ident.normalize_to_macros_2_0()) { + if overridden_methods.contains_key(&method.def_id) { continue; } diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 618aa3fd002..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. @@ -794,6 +794,44 @@ impl<'a> Parser<'a> { )) } + /// Emits an error that the where clause at the end of a type alias is not + /// allowed and suggests moving it. + fn error_ty_alias_where( + &self, + before_where_clause_present: bool, + before_where_clause_span: Span, + after_predicates: &[WherePredicate], + after_where_clause_span: Span, + ) { + let mut err = + self.struct_span_err(after_where_clause_span, "where clause not allowed here"); + if !after_predicates.is_empty() { + let mut state = crate::pprust::State::new(); + if !before_where_clause_present { + state.space(); + state.word_space("where"); + } else { + state.word_space(","); + } + let mut first = true; + for p in after_predicates.iter() { + if !first { + state.word_space(","); + } + first = false; + state.print_where_predicate(p); + } + let suggestion = state.s.eof(); + err.span_suggestion( + before_where_clause_span.shrink_to_hi(), + "move it here", + suggestion, + Applicability::MachineApplicable, + ); + } + err.emit() + } + /// Parses a `type` alias with the following grammar: /// ``` /// TypeAlias = "type" Ident Generics {":" GenericBounds}? {"=" Ty}? ";" ; @@ -806,9 +844,24 @@ impl<'a> Parser<'a> { // Parse optional colon and param bounds. let bounds = if self.eat(&token::Colon) { self.parse_generic_bounds(None)? } else { Vec::new() }; + generics.where_clause = self.parse_where_clause()?; let ty = if self.eat(&token::Eq) { Some(self.parse_ty()?) } else { None }; + + if self.token.is_keyword(kw::Where) { + let after_where_clause = self.parse_where_clause()?; + + self.error_ty_alias_where( + generics.where_clause.has_where_token, + generics.where_clause.span, + &after_where_clause.predicates, + after_where_clause.span, + ); + + generics.where_clause.predicates.extend(after_where_clause.predicates.into_iter()); + } + self.expect_semi()?; Ok((ident, ItemKind::TyAlias(Box::new(TyAlias { defaultness, generics, bounds, ty })))) diff --git a/compiler/rustc_passes/src/check_const.rs b/compiler/rustc_passes/src/check_const.rs index a5a65740707..b755f686f6a 100644 --- a/compiler/rustc_passes/src/check_const.rs +++ b/compiler/rustc_passes/src/check_const.rs @@ -93,26 +93,29 @@ impl<'tcx> hir::itemlikevisit::ItemLikeVisitor<'tcx> for CheckConstTraitVisitor< for trait_item in self.tcx.associated_items(trait_def_id).in_definition_order() { if let ty::AssocItem { - kind: ty::AssocKind::Fn, ident, defaultness, .. - } = trait_item + kind: ty::AssocKind::Fn, + defaultness, + def_id: trait_item_id, + .. + } = *trait_item { // we can ignore functions that do not have default bodies: // if those are unimplemented it will be catched by typeck. if !defaultness.has_value() || self .tcx - .has_attr(trait_item.def_id, sym::default_method_body_is_const) + .has_attr(trait_item_id, sym::default_method_body_is_const) { continue; } let is_implemented = ancestors - .leaf_def(self.tcx, trait_item.ident, trait_item.kind) + .leaf_def(self.tcx, trait_item_id) .map(|node_item| !node_item.defining_node.is_from_trait()) .unwrap_or(false); if !is_implemented { - to_implement.push(ident.to_string()); + to_implement.push(self.tcx.item_name(trait_item_id).to_string()); } } } 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_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index 5f19991f9c7..c136411df27 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -794,19 +794,12 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> { } } - if let Res::Def(DefKind::Trait, trait_did) = t.path.res { - for impl_item_ref in items { - let impl_item = self.tcx.hir().impl_item(impl_item_ref.id); - let trait_item_def_id = self - .tcx - .associated_items(trait_did) - .filter_by_name_unhygienic(impl_item.ident.name) - .next() - .map(|item| item.def_id); - if let Some(def_id) = trait_item_def_id { - // Pass `None` to skip deprecation warnings. - self.tcx.check_stability(def_id, None, impl_item.span, None); - } + for impl_item_ref in items { + let impl_item = self.tcx.associated_item(impl_item_ref.id.def_id); + + if let Some(def_id) = impl_item.trait_item_def_id { + // Pass `None` to skip deprecation warnings. + self.tcx.check_stability(def_id, None, impl_item_ref.span, None); } } } diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 10f6f6b1a9f..183a5a205ec 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -2064,7 +2064,11 @@ impl<'tcx> Visitor<'tcx> for PrivateItemsInPublicInterfacesVisitor<'tcx> { // Subitems of trait impls have inherited publicity. hir::ItemKind::Impl(ref impl_) => { let impl_vis = ty::Visibility::of_impl(item.def_id, tcx, &Default::default()); - self.check(item.def_id, impl_vis).generics().predicates(); + // check that private components do not appear in the generics or predicates of inherent impls + // this check is intentionally NOT performed for impls of traits, per #90586 + if impl_.of_trait.is_none() { + self.check(item.def_id, impl_vis).generics().predicates(); + } for impl_item_ref in impl_.items { let impl_item_vis = if impl_.of_trait.is_none() { min(tcx.visibility(impl_item_ref.id.def_id), impl_vis, tcx) 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 19788a979ad..7c96f68ffb3 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)), } @@ -500,6 +506,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 192da6735fc..da1f3617647 100644 --- a/compiler/rustc_query_system/src/query/plumbing.rs +++ b/compiler/rustc_query_system/src/query/plumbing.rs @@ -524,6 +524,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 74edc3a2d5e..39074f811a5 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -1016,10 +1016,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { self.insert_field_names(def_id, field_names); } Res::Def(DefKind::AssocFn, def_id) => { - if cstore - .associated_item_cloned_untracked(def_id, self.r.session) - .fn_has_self_parameter - { + if cstore.fn_has_self_parameter_untracked(def_id) { self.r.has_self.insert(def_id); } } @@ -1515,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/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index babfa8015af..4feeae5cab1 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -895,8 +895,11 @@ impl<'a> Resolver<'a> { // a note about editions let note = if let Some(did) = did { let requires_note = !did.is_local() - && this.cstore().item_attrs(did, this.session).iter().any( - |attr| { + && this + .cstore() + .item_attrs_untracked(did, this.session) + .iter() + .any(|attr| { if attr.has_name(sym::rustc_diagnostic_item) { [sym::TryInto, sym::TryFrom, sym::FromIterator] .map(|x| Some(x)) @@ -904,8 +907,7 @@ impl<'a> Resolver<'a> { } else { false } - }, - ); + }); requires_note.then(|| { format!( diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 12123c946cc..57305023138 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -1603,10 +1603,13 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { pat_src: PatternSource, bindings: &mut SmallVec<[(PatBoundCtx, FxHashSet<Ident>); 1]>, ) { + // We walk the pattern before declaring the pattern's inner bindings, + // so that we avoid resolving a literal expression to a binding defined + // by the pattern. + visit::walk_pat(self, pat); self.resolve_pattern_inner(pat, pat_src, bindings); // This has to happen *after* we determine which pat_idents are variants: self.check_consistent_bindings_top(pat); - visit::walk_pat(self, pat); } /// Resolve bindings in a pattern. This is a helper to `resolve_pattern`. @@ -2376,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/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index e74a7a95650..4cd1b34bedc 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -2115,10 +2115,13 @@ impl<'tcx> LifetimeContext<'_, 'tcx> { let spans_suggs: Vec<_> = formatters .into_iter() .zip(spans_with_counts.iter()) - .filter_map(|(fmt, (span, _))| { - if let Some(formatter) = fmt { Some((formatter, span)) } else { None } + .filter_map(|(formatter, (span, _))| { + if let Some(formatter) = formatter { + Some((*span, formatter(name))) + } else { + None + } }) - .map(|(formatter, span)| (*span, formatter(name))) .collect(); if spans_suggs.is_empty() { // If all the spans come from macros, we cannot extract snippets and then diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 84ce492ba72..b46a93c0673 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 { @@ -3419,27 +3418,21 @@ impl<'a> Resolver<'a> { return v.clone(); } - let parse_attrs = || { - let attrs = self.cstore().item_attrs(def_id, self.session); - let attr = - attrs.iter().find(|a| a.has_name(sym::rustc_legacy_const_generics))?; - let mut ret = vec![]; - for meta in attr.meta_item_list()? { - match meta.literal()?.kind { - LitKind::Int(a, _) => { - ret.push(a as usize); - } - _ => panic!("invalid arg index"), - } + let attr = self + .cstore() + .item_attrs_untracked(def_id, self.session) + .into_iter() + .find(|a| a.has_name(sym::rustc_legacy_const_generics))?; + let mut ret = Vec::new(); + for meta in attr.meta_item_list()? { + match meta.literal()?.kind { + LitKind::Int(a, _) => ret.push(a as usize), + _ => panic!("invalid arg index"), } - Some(ret) - }; - - // Cache the lookup to avoid parsing attributes for an iterm - // multiple times. - let ret = parse_attrs(); - self.legacy_const_generic_args.insert(def_id, ret.clone()); - return ret; + } + // Cache the lookup to avoid parsing attributes for an iterm multiple times. + self.legacy_const_generic_args.insert(def_id, Some(ret.clone())); + return Some(ret); } } None 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/lib.rs b/compiler/rustc_save_analysis/src/lib.rs index 7ec619e07ff..a83f0230814 100644 --- a/compiler/rustc_save_analysis/src/lib.rs +++ b/compiler/rustc_save_analysis/src/lib.rs @@ -710,13 +710,11 @@ impl<'tcx> SaveContext<'tcx> { } Res::Def(HirDefKind::AssocFn, decl_id) => { let def_id = if decl_id.is_local() { - let ti = self.tcx.associated_item(decl_id); - - self.tcx - .associated_items(ti.container.id()) - .filter_by_name_unhygienic(ti.ident.name) - .find(|item| item.defaultness.has_value()) - .map(|item| item.def_id) + if self.tcx.associated_item(decl_id).defaultness.has_value() { + Some(decl_id) + } else { + None + } } else { None }; 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..24d2a8ac073 100644 --- a/compiler/rustc_span/src/def_id.rs +++ b/compiler/rustc_span/src/def_id.rs @@ -136,8 +136,8 @@ impl Borrow<Fingerprint> for DefPathHash { /// collisions when loading crates and abort compilation in order to avoid /// further trouble. /// -/// See the discussion in [`DefId`] for more information -/// on the possibility of hash collisions in rustc, +/// For more information on the possibility of hash collisions in rustc, +/// see the discussion in [`DefId`]. #[derive(Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord, Debug)] #[derive(HashStable_Generic, Encodable, Decodable)] pub struct StableCrateId(pub(crate) u64); @@ -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/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs index 53ff911ea0c..05d2a373dc6 100644 --- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs +++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs @@ -839,7 +839,17 @@ impl<'tcx> AutoTraitFinder<'tcx> { _ => return false, } } - _ => panic!("Unexpected predicate {:?} {:?}", ty, predicate), + // There's not really much we can do with these predicates - + // we start out with a `ParamEnv` with no inference variables, + // and these don't correspond to adding any new bounds to + // the `ParamEnv`. + ty::PredicateKind::WellFormed(..) + | ty::PredicateKind::ObjectSafe(..) + | ty::PredicateKind::ClosureKind(..) + | ty::PredicateKind::Subtype(..) + | ty::PredicateKind::ConstEvaluatable(..) + | ty::PredicateKind::Coerce(..) + | ty::PredicateKind::TypeWellFormedFromEnv(..) => {} }; } true 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_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 23f615a9618..51bd505366c 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -1883,7 +1883,6 @@ fn assoc_ty_def( assoc_ty_def_id: DefId, ) -> Result<specialization_graph::LeafDef, ErrorReported> { let tcx = selcx.tcx(); - let assoc_ty_name = tcx.associated_item(assoc_ty_def_id).ident; let trait_def_id = tcx.impl_trait_ref(impl_def_id).unwrap().def_id; let trait_def = tcx.trait_def(trait_def_id); @@ -1893,21 +1892,18 @@ fn assoc_ty_def( // for the associated item at the given impl. // If there is no such item in that impl, this function will fail with a // cycle error if the specialization graph is currently being built. - let impl_node = specialization_graph::Node::Impl(impl_def_id); - for item in impl_node.items(tcx) { - if matches!(item.kind, ty::AssocKind::Type) - && tcx.hygienic_eq(item.ident, assoc_ty_name, trait_def_id) - { - return Ok(specialization_graph::LeafDef { - item: *item, - defining_node: impl_node, - finalizing_node: if item.defaultness.is_default() { None } else { Some(impl_node) }, - }); - } + if let Some(&impl_item_id) = tcx.impl_item_implementor_ids(impl_def_id).get(&assoc_ty_def_id) { + let item = tcx.associated_item(impl_item_id); + let impl_node = specialization_graph::Node::Impl(impl_def_id); + return Ok(specialization_graph::LeafDef { + item: *item, + defining_node: impl_node, + finalizing_node: if item.defaultness.is_default() { None } else { Some(impl_node) }, + }); } let ancestors = trait_def.ancestors(tcx, impl_def_id)?; - if let Some(assoc_item) = ancestors.leaf_def(tcx, assoc_ty_name, ty::AssocKind::Type) { + if let Some(assoc_item) = ancestors.leaf_def(tcx, assoc_ty_def_id) { Ok(assoc_item) } else { // This is saying that neither the trait nor @@ -1916,7 +1912,11 @@ fn assoc_ty_def( // could only arise through a compiler bug -- // if the user wrote a bad item name, it // should have failed in astconv. - bug!("No associated type `{}` for {}", assoc_ty_name, tcx.def_path_str(impl_def_id)) + bug!( + "No associated type `{}` for {}", + tcx.item_name(assoc_ty_def_id), + tcx.def_path_str(impl_def_id) + ) } } diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index e9b368f683e..b7fc578ea3b 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -8,6 +8,7 @@ //! https://rustc-dev-guide.rust-lang.org/traits/resolution.html#confirmation use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_hir::lang_items::LangItem; +use rustc_hir::Constness; use rustc_index::bit_set::GrowableBitSet; use rustc_infer::infer::InferOk; use rustc_infer::infer::LateBoundRegionConversionTime::HigherRankedType; @@ -51,6 +52,38 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation: &TraitObligation<'tcx>, candidate: SelectionCandidate<'tcx>, ) -> Result<Selection<'tcx>, SelectionError<'tcx>> { + let mut obligation = obligation; + let new_obligation; + + // HACK(const_trait_impl): the surrounding environment is remapped to a non-const context + // because nested obligations might be actually `~const` then (incorrectly) requiring + // const impls. for example: + // ``` + // pub trait Super {} + // pub trait Sub: Super {} + // + // impl<A> const Super for &A where A: ~const Super {} + // impl<A> const Sub for &A where A: ~const Sub {} + // ``` + // + // The procedure to check the code above without the remapping code is as follows: + // ``` + // CheckWf(impl const Sub for &A where A: ~const Sub) // <- const env + // CheckPredicate(&A: Super) + // CheckPredicate(A: ~const Super) // <- still const env, failure + // ``` + if obligation.param_env.constness() == Constness::Const + && obligation.predicate.skip_binder().constness == ty::BoundConstness::NotConst + { + new_obligation = TraitObligation { + cause: obligation.cause.clone(), + param_env: obligation.param_env.without_const(), + ..*obligation + }; + + obligation = &new_obligation; + } + match candidate { BuiltinCandidate { has_nested } => { let data = self.confirm_builtin_candidate(obligation, has_nested); diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index 4bd73ef68aa..72ffe9085cb 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -197,14 +197,13 @@ fn extend_cause_with_original_assoc_item_obligation<'tcx>( item: Option<&hir::Item<'tcx>>, cause: &mut traits::ObligationCause<'tcx>, pred: &ty::Predicate<'tcx>, - mut trait_assoc_items: impl Iterator<Item = &'tcx ty::AssocItem>, ) { debug!( "extended_cause_with_original_assoc_item_obligation {:?} {:?} {:?} {:?}", trait_ref, item, cause, pred ); - let items = match item { - Some(hir::Item { kind: hir::ItemKind::Impl(impl_), .. }) => impl_.items, + let (items, impl_def_id) = match item { + Some(hir::Item { kind: hir::ItemKind::Impl(impl_), def_id, .. }) => (impl_.items, *def_id), _ => return, }; let fix_span = @@ -222,11 +221,16 @@ fn extend_cause_with_original_assoc_item_obligation<'tcx>( // `src/test/ui/associated-types/point-at-type-on-obligation-failure.rs` and // `traits-assoc-type-in-supertrait-bad.rs`. if let ty::Projection(projection_ty) = proj.ty.kind() { - let trait_assoc_item = tcx.associated_item(projection_ty.item_def_id); - if let Some(impl_item_span) = - items.iter().find(|item| item.ident == trait_assoc_item.ident).map(fix_span) + if let Some(&impl_item_id) = + tcx.impl_item_implementor_ids(impl_def_id).get(&projection_ty.item_def_id) { - cause.span = impl_item_span; + if let Some(impl_item_span) = items + .iter() + .find(|item| item.id.def_id.to_def_id() == impl_item_id) + .map(fix_span) + { + cause.span = impl_item_span; + } } } } @@ -235,13 +239,16 @@ fn extend_cause_with_original_assoc_item_obligation<'tcx>( // can be seen in `ui/associated-types/point-at-type-on-obligation-failure-2.rs`. debug!("extended_cause_with_original_assoc_item_obligation trait proj {:?}", pred); if let ty::Projection(ty::ProjectionTy { item_def_id, .. }) = *pred.self_ty().kind() { - if let Some(impl_item_span) = trait_assoc_items - .find(|i| i.def_id == item_def_id) - .and_then(|trait_assoc_item| { - items.iter().find(|i| i.ident == trait_assoc_item.ident).map(fix_span) - }) + if let Some(&impl_item_id) = + tcx.impl_item_implementor_ids(impl_def_id).get(&item_def_id) { - cause.span = impl_item_span; + if let Some(impl_item_span) = items + .iter() + .find(|item| item.id.def_id.to_def_id() == impl_item_id) + .map(fix_span) + { + cause.span = impl_item_span; + } } } } @@ -312,7 +319,6 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { item, &mut cause, &obligation.predicate, - tcx.associated_items(trait_ref.def_id).in_definition_order(), ); traits::Obligation::with_depth(cause, depth, param_env, obligation.predicate) }; diff --git a/compiler/rustc_traits/src/chalk/db.rs b/compiler/rustc_traits/src/chalk/db.rs index 1b79e537634..3f51442277f 100644 --- a/compiler/rustc_traits/src/chalk/db.rs +++ b/compiler/rustc_traits/src/chalk/db.rs @@ -436,23 +436,13 @@ impl<'tcx> chalk_solve::RustIrDatabase<RustInterner<'tcx>> for RustIrDatabase<'t ) -> Arc<chalk_solve::rust_ir::AssociatedTyValue<RustInterner<'tcx>>> { let def_id = associated_ty_id.0; let assoc_item = self.interner.tcx.associated_item(def_id); - let (impl_id, trait_id) = match assoc_item.container { - AssocItemContainer::TraitContainer(def_id) => (def_id, def_id), - AssocItemContainer::ImplContainer(def_id) => { - (def_id, self.interner.tcx.impl_trait_ref(def_id).unwrap().def_id) - } - }; + let impl_id = assoc_item.container.id(); match assoc_item.kind { AssocKind::Type => {} _ => unimplemented!("Not possible??"), } - let trait_item = self - .interner - .tcx - .associated_items(trait_id) - .find_by_name_and_kind(self.interner.tcx, assoc_item.ident, assoc_item.kind, trait_id) - .unwrap(); + let trait_item_id = assoc_item.trait_item_def_id.expect("assoc_ty with no trait version"); let bound_vars = bound_vars_for_item(self.interner.tcx, def_id); let binders = binders_for(self.interner, bound_vars); let ty = self @@ -464,7 +454,7 @@ impl<'tcx> chalk_solve::RustIrDatabase<RustInterner<'tcx>> for RustIrDatabase<'t Arc::new(chalk_solve::rust_ir::AssociatedTyValue { impl_id: chalk_ir::ImplId(impl_id), - associated_ty_id: chalk_ir::AssocTypeId(trait_item.def_id), + associated_ty_id: chalk_ir::AssocTypeId(trait_item_id), value: chalk_ir::Binders::new( binders, chalk_solve::rust_ir::AssociatedTyValueBound { ty }, @@ -724,7 +714,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_ty_utils/src/assoc.rs b/compiler/rustc_ty_utils/src/assoc.rs new file mode 100644 index 00000000000..b1d47f6c29a --- /dev/null +++ b/compiler/rustc_ty_utils/src/assoc.rs @@ -0,0 +1,239 @@ +use rustc_data_structures::fx::FxHashMap; +use rustc_errors::struct_span_err; +use rustc_hir as hir; +use rustc_hir::def_id::{DefId, LocalDefId}; +use rustc_middle::ty::{self, TyCtxt, TypeFoldable}; + +pub fn provide(providers: &mut ty::query::Providers) { + *providers = ty::query::Providers { + associated_item, + associated_item_def_ids, + associated_items, + impl_item_implementor_ids, + trait_of_item, + ..*providers + }; +} + +fn associated_item_def_ids(tcx: TyCtxt<'_>, def_id: DefId) -> &[DefId] { + let item = tcx.hir().expect_item(def_id.expect_local()); + match item.kind { + hir::ItemKind::Trait(.., ref trait_item_refs) => tcx.arena.alloc_from_iter( + trait_item_refs.iter().map(|trait_item_ref| trait_item_ref.id.def_id.to_def_id()), + ), + hir::ItemKind::Impl(ref impl_) => tcx.arena.alloc_from_iter( + impl_.items.iter().map(|impl_item_ref| impl_item_ref.id.def_id.to_def_id()), + ), + hir::ItemKind::TraitAlias(..) => &[], + _ => span_bug!(item.span, "associated_item_def_ids: not impl or trait"), + } +} + +fn associated_items(tcx: TyCtxt<'_>, def_id: DefId) -> ty::AssocItems<'_> { + let items = tcx.associated_item_def_ids(def_id).iter().map(|did| tcx.associated_item(*did)); + ty::AssocItems::new(items) +} + +fn impl_item_implementor_ids(tcx: TyCtxt<'_>, impl_id: DefId) -> FxHashMap<DefId, DefId> { + tcx.associated_items(impl_id) + .in_definition_order() + .filter_map(|item| item.trait_item_def_id.map(|trait_item| (trait_item, item.def_id))) + .collect() +} + +/// If the given `DefId` describes an item belonging to a trait, +/// returns the `DefId` of the trait that the trait item belongs to; +/// otherwise, returns `None`. +fn trait_of_item(tcx: TyCtxt<'_>, def_id: DefId) -> Option<DefId> { + tcx.opt_associated_item(def_id).and_then(|associated_item| match associated_item.container { + ty::TraitContainer(def_id) => Some(def_id), + ty::ImplContainer(_) => None, + }) +} + +fn associated_item(tcx: TyCtxt<'_>, def_id: DefId) -> ty::AssocItem { + let id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local()); + let parent_id = tcx.hir().get_parent_item(id); + let parent_def_id = tcx.hir().local_def_id(parent_id); + let parent_item = tcx.hir().expect_item(parent_def_id); + match parent_item.kind { + hir::ItemKind::Impl(ref impl_) => { + if let Some(impl_item_ref) = + impl_.items.iter().find(|i| i.id.def_id.to_def_id() == def_id) + { + let assoc_item = + associated_item_from_impl_item_ref(tcx, parent_def_id, impl_item_ref); + debug_assert_eq!(assoc_item.def_id, def_id); + return assoc_item; + } + } + + hir::ItemKind::Trait(.., ref trait_item_refs) => { + if let Some(trait_item_ref) = + trait_item_refs.iter().find(|i| i.id.def_id.to_def_id() == def_id) + { + let assoc_item = + associated_item_from_trait_item_ref(tcx, parent_def_id, trait_item_ref); + debug_assert_eq!(assoc_item.def_id, def_id); + return assoc_item; + } + } + + _ => {} + } + + span_bug!( + parent_item.span, + "unexpected parent of trait or impl item or item not found: {:?}", + parent_item.kind + ) +} + +fn associated_item_from_trait_item_ref( + tcx: TyCtxt<'_>, + parent_def_id: LocalDefId, + trait_item_ref: &hir::TraitItemRef, +) -> ty::AssocItem { + let def_id = trait_item_ref.id.def_id; + let (kind, has_self) = match trait_item_ref.kind { + hir::AssocItemKind::Const => (ty::AssocKind::Const, false), + hir::AssocItemKind::Fn { has_self } => (ty::AssocKind::Fn, has_self), + hir::AssocItemKind::Type => (ty::AssocKind::Type, false), + }; + + ty::AssocItem { + ident: trait_item_ref.ident, + kind, + vis: tcx.visibility(def_id), + defaultness: trait_item_ref.defaultness, + def_id: def_id.to_def_id(), + trait_item_def_id: Some(def_id.to_def_id()), + container: ty::TraitContainer(parent_def_id.to_def_id()), + fn_has_self_parameter: has_self, + } +} + +fn associated_item_from_impl_item_ref( + tcx: TyCtxt<'_>, + parent_def_id: LocalDefId, + impl_item_ref: &hir::ImplItemRef, +) -> ty::AssocItem { + let def_id = impl_item_ref.id.def_id; + let (kind, has_self) = match impl_item_ref.kind { + hir::AssocItemKind::Const => (ty::AssocKind::Const, false), + hir::AssocItemKind::Fn { has_self } => (ty::AssocKind::Fn, has_self), + hir::AssocItemKind::Type => (ty::AssocKind::Type, false), + }; + + let trait_item_def_id = impl_item_base_id(tcx, parent_def_id, impl_item_ref); + + ty::AssocItem { + ident: impl_item_ref.ident, + kind, + vis: tcx.visibility(def_id), + defaultness: impl_item_ref.defaultness, + def_id: def_id.to_def_id(), + trait_item_def_id, + container: ty::ImplContainer(parent_def_id.to_def_id()), + fn_has_self_parameter: has_self, + } +} + +fn impl_item_base_id<'tcx>( + tcx: TyCtxt<'tcx>, + parent_def_id: LocalDefId, + impl_item: &hir::ImplItemRef, +) -> Option<DefId> { + let impl_trait_ref = tcx.impl_trait_ref(parent_def_id)?; + + // If the trait reference itself is erroneous (so the compilation is going + // to fail), skip checking the items here -- the `impl_item` table in `tcx` + // isn't populated for such impls. + if impl_trait_ref.references_error() { + return None; + } + + // Locate trait items + let associated_items = tcx.associated_items(impl_trait_ref.def_id); + + // Match item against trait + let mut items = associated_items.filter_by_name(tcx, impl_item.ident, impl_trait_ref.def_id); + + let mut trait_item = items.next()?; + + let is_compatible = |ty: &&ty::AssocItem| match (ty.kind, &impl_item.kind) { + (ty::AssocKind::Const, hir::AssocItemKind::Const) => true, + (ty::AssocKind::Fn, hir::AssocItemKind::Fn { .. }) => true, + (ty::AssocKind::Type, hir::AssocItemKind::Type) => true, + _ => false, + }; + + // If we don't have a compatible item, we'll use the first one whose name matches + // to report an error. + let mut compatible_kind = is_compatible(&trait_item); + + if !compatible_kind { + if let Some(ty_trait_item) = items.find(is_compatible) { + compatible_kind = true; + trait_item = ty_trait_item; + } + } + + if compatible_kind { + Some(trait_item.def_id) + } else { + report_mismatch_error(tcx, trait_item.def_id, impl_trait_ref, impl_item); + None + } +} + +#[inline(never)] +#[cold] +fn report_mismatch_error<'tcx>( + tcx: TyCtxt<'tcx>, + trait_item_def_id: DefId, + impl_trait_ref: ty::TraitRef<'tcx>, + impl_item: &hir::ImplItemRef, +) { + let mut err = match impl_item.kind { + hir::AssocItemKind::Const => { + // Find associated const definition. + struct_span_err!( + tcx.sess, + impl_item.span, + E0323, + "item `{}` is an associated const, which doesn't match its trait `{}`", + impl_item.ident, + impl_trait_ref.print_only_trait_path() + ) + } + + hir::AssocItemKind::Fn { .. } => { + struct_span_err!( + tcx.sess, + impl_item.span, + E0324, + "item `{}` is an associated method, which doesn't match its trait `{}`", + impl_item.ident, + impl_trait_ref.print_only_trait_path() + ) + } + + hir::AssocItemKind::Type => { + struct_span_err!( + tcx.sess, + impl_item.span, + E0325, + "item `{}` is an associated type, which doesn't match its trait `{}`", + impl_item.ident, + impl_trait_ref.print_only_trait_path() + ) + } + }; + + err.span_label(impl_item.span, "does not match trait"); + if let Some(trait_span) = tcx.hir().span_if_local(trait_item_def_id) { + err.span_label(trait_span, "item in trait"); + } + err.emit(); +} diff --git a/compiler/rustc_ty_utils/src/instance.rs b/compiler/rustc_ty_utils/src/instance.rs index 13ffb2a5adc..e0aea786b83 100644 --- a/compiler/rustc_ty_utils/src/instance.rs +++ b/compiler/rustc_ty_utils/src/instance.rs @@ -152,8 +152,7 @@ fn inner_resolve_instance<'tcx>( let result = if let Some(trait_def_id) = tcx.trait_of_item(def.did) { debug!(" => associated item, attempting to find impl in param_env {:#?}", param_env); - let item = tcx.associated_item(def.did); - resolve_associated_item(tcx, &item, param_env, trait_def_id, substs) + resolve_associated_item(tcx, def.did, param_env, trait_def_id, substs) } else { let ty = tcx.type_of(def.def_id_for_type_of()); let item_type = tcx.subst_and_normalize_erasing_regions(substs, param_env, ty); @@ -204,19 +203,12 @@ fn inner_resolve_instance<'tcx>( fn resolve_associated_item<'tcx>( tcx: TyCtxt<'tcx>, - trait_item: &ty::AssocItem, + trait_item_id: DefId, param_env: ty::ParamEnv<'tcx>, trait_id: DefId, rcvr_substs: SubstsRef<'tcx>, ) -> Result<Option<Instance<'tcx>>, ErrorReported> { - let def_id = trait_item.def_id; - debug!( - "resolve_associated_item(trait_item={:?}, \ - param_env={:?}, \ - trait_id={:?}, \ - rcvr_substs={:?})", - def_id, param_env, trait_id, rcvr_substs - ); + debug!(?trait_item_id, ?param_env, ?trait_id, ?rcvr_substs, "resolve_associated_item"); let trait_ref = ty::TraitRef::from_method(tcx, trait_id, rcvr_substs); @@ -232,7 +224,7 @@ fn resolve_associated_item<'tcx>( traits::ImplSource::UserDefined(impl_data) => { debug!( "resolving ImplSource::UserDefined: {:?}, {:?}, {:?}, {:?}", - param_env, trait_item, rcvr_substs, impl_data + param_env, trait_item_id, rcvr_substs, impl_data ); assert!(!rcvr_substs.needs_infer()); assert!(!trait_ref.needs_infer()); @@ -241,9 +233,9 @@ fn resolve_associated_item<'tcx>( let trait_def = tcx.trait_def(trait_def_id); let leaf_def = trait_def .ancestors(tcx, impl_data.impl_def_id)? - .leaf_def(tcx, trait_item.ident, trait_item.kind) + .leaf_def(tcx, trait_item_id) .unwrap_or_else(|| { - bug!("{:?} not found in {:?}", trait_item, impl_data.impl_def_id); + bug!("{:?} not found in {:?}", trait_item_id, impl_data.impl_def_id); }); let substs = tcx.infer_ctxt().enter(|infcx| { @@ -297,22 +289,22 @@ fn resolve_associated_item<'tcx>( // performs (i.e. that the definition's type in the `impl` matches // the declaration in the `trait`), so that we can cheaply check // here if it failed, instead of approximating it. - if trait_item.kind == ty::AssocKind::Const - && trait_item.def_id != leaf_def.item.def_id + if leaf_def.item.kind == ty::AssocKind::Const + && trait_item_id != leaf_def.item.def_id && leaf_def.item.def_id.is_local() { let normalized_type_of = |def_id, substs| { tcx.subst_and_normalize_erasing_regions(substs, param_env, tcx.type_of(def_id)) }; - let original_ty = normalized_type_of(trait_item.def_id, rcvr_substs); + let original_ty = normalized_type_of(trait_item_id, rcvr_substs); let resolved_ty = normalized_type_of(leaf_def.item.def_id, substs); if original_ty != resolved_ty { let msg = format!( "Instance::resolve: inconsistent associated `const` type: \ was `{}: {}` but resolved to `{}: {}`", - tcx.def_path_str_with_substs(trait_item.def_id, rcvr_substs), + tcx.def_path_str_with_substs(trait_item_id, rcvr_substs), original_ty, tcx.def_path_str_with_substs(leaf_def.item.def_id, substs), resolved_ty, @@ -343,19 +335,22 @@ fn resolve_associated_item<'tcx>( } traits::ImplSource::FnPointer(ref data) => match data.fn_ty.kind() { ty::FnDef(..) | ty::FnPtr(..) => Some(Instance { - def: ty::InstanceDef::FnPtrShim(trait_item.def_id, data.fn_ty), + def: ty::InstanceDef::FnPtrShim(trait_item_id, data.fn_ty), substs: rcvr_substs, }), _ => None, }, traits::ImplSource::Object(ref data) => { - let index = traits::get_vtable_index_of_object_method(tcx, data, def_id); - Some(Instance { def: ty::InstanceDef::Virtual(def_id, index), substs: rcvr_substs }) + let index = traits::get_vtable_index_of_object_method(tcx, data, trait_item_id); + Some(Instance { + def: ty::InstanceDef::Virtual(trait_item_id, index), + substs: rcvr_substs, + }) } traits::ImplSource::Builtin(..) => { if Some(trait_ref.def_id) == tcx.lang_items().clone_trait() { // FIXME(eddyb) use lang items for methods instead of names. - let name = tcx.item_name(def_id); + let name = tcx.item_name(trait_item_id); if name == sym::clone { let self_ty = trait_ref.self_ty(); @@ -367,7 +362,7 @@ fn resolve_associated_item<'tcx>( }; Some(Instance { - def: ty::InstanceDef::CloneShim(def_id, self_ty), + def: ty::InstanceDef::CloneShim(trait_item_id, self_ty), substs: rcvr_substs, }) } else { @@ -375,7 +370,7 @@ fn resolve_associated_item<'tcx>( // Use the default `fn clone_from` from `trait Clone`. let substs = tcx.erase_regions(rcvr_substs); - Some(ty::Instance::new(def_id, substs)) + Some(ty::Instance::new(trait_item_id, substs)) } } else { None diff --git a/compiler/rustc_ty_utils/src/lib.rs b/compiler/rustc_ty_utils/src/lib.rs index 60f8e196bcb..55e19990761 100644 --- a/compiler/rustc_ty_utils/src/lib.rs +++ b/compiler/rustc_ty_utils/src/lib.rs @@ -16,6 +16,7 @@ extern crate tracing; use rustc_middle::ty::query::Providers; +mod assoc; mod common_traits; pub mod instance; mod needs_drop; @@ -23,6 +24,7 @@ pub mod representability; mod ty; pub fn provide(providers: &mut Providers) { + assoc::provide(providers); common_traits::provide(providers); needs_drop::provide(providers); ty::provide(providers); diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs index 6c2657bd64b..8f50e3e0fe1 100644 --- a/compiler/rustc_ty_utils/src/ty.rs +++ b/compiler/rustc_ty_utils/src/ty.rs @@ -1,6 +1,6 @@ use rustc_data_structures::fx::FxIndexSet; use rustc_hir as hir; -use rustc_hir::def_id::{DefId, LocalDefId}; +use rustc_hir::def_id::DefId; use rustc_middle::ty::subst::Subst; use rustc_middle::ty::{self, Binder, Predicate, PredicateKind, ToPredicate, Ty, TyCtxt}; use rustc_span::{sym, Span}; @@ -71,90 +71,6 @@ fn sized_constraint_for_ty<'tcx>( result } -fn associated_item_from_trait_item_ref( - tcx: TyCtxt<'_>, - parent_def_id: LocalDefId, - trait_item_ref: &hir::TraitItemRef, -) -> ty::AssocItem { - let def_id = trait_item_ref.id.def_id; - let (kind, has_self) = match trait_item_ref.kind { - hir::AssocItemKind::Const => (ty::AssocKind::Const, false), - hir::AssocItemKind::Fn { has_self } => (ty::AssocKind::Fn, has_self), - hir::AssocItemKind::Type => (ty::AssocKind::Type, false), - }; - - ty::AssocItem { - ident: trait_item_ref.ident, - kind, - vis: tcx.visibility(def_id), - defaultness: trait_item_ref.defaultness, - def_id: def_id.to_def_id(), - container: ty::TraitContainer(parent_def_id.to_def_id()), - fn_has_self_parameter: has_self, - } -} - -fn associated_item_from_impl_item_ref( - tcx: TyCtxt<'_>, - parent_def_id: LocalDefId, - impl_item_ref: &hir::ImplItemRef, -) -> ty::AssocItem { - let def_id = impl_item_ref.id.def_id; - let (kind, has_self) = match impl_item_ref.kind { - hir::AssocItemKind::Const => (ty::AssocKind::Const, false), - hir::AssocItemKind::Fn { has_self } => (ty::AssocKind::Fn, has_self), - hir::AssocItemKind::Type => (ty::AssocKind::Type, false), - }; - - ty::AssocItem { - ident: impl_item_ref.ident, - kind, - vis: tcx.visibility(def_id), - defaultness: impl_item_ref.defaultness, - def_id: def_id.to_def_id(), - container: ty::ImplContainer(parent_def_id.to_def_id()), - fn_has_self_parameter: has_self, - } -} - -fn associated_item(tcx: TyCtxt<'_>, def_id: DefId) -> ty::AssocItem { - let id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local()); - let parent_id = tcx.hir().get_parent_item(id); - let parent_def_id = tcx.hir().local_def_id(parent_id); - let parent_item = tcx.hir().expect_item(parent_def_id); - match parent_item.kind { - hir::ItemKind::Impl(ref impl_) => { - if let Some(impl_item_ref) = - impl_.items.iter().find(|i| i.id.def_id.to_def_id() == def_id) - { - let assoc_item = - associated_item_from_impl_item_ref(tcx, parent_def_id, impl_item_ref); - debug_assert_eq!(assoc_item.def_id, def_id); - return assoc_item; - } - } - - hir::ItemKind::Trait(.., ref trait_item_refs) => { - if let Some(trait_item_ref) = - trait_item_refs.iter().find(|i| i.id.def_id.to_def_id() == def_id) - { - let assoc_item = - associated_item_from_trait_item_ref(tcx, parent_def_id, trait_item_ref); - debug_assert_eq!(assoc_item.def_id, def_id); - return assoc_item; - } - } - - _ => {} - } - - span_bug!( - parent_item.span, - "unexpected parent of trait or impl item or item not found: {:?}", - parent_item.kind - ) -} - fn impl_defaultness(tcx: TyCtxt<'_>, def_id: DefId) -> hir::Defaultness { let item = tcx.hir().expect_item(def_id.expect_local()); if let hir::ItemKind::Impl(impl_) = &item.kind { @@ -197,25 +113,6 @@ fn adt_sized_constraint(tcx: TyCtxt<'_>, def_id: DefId) -> ty::AdtSizedConstrain ty::AdtSizedConstraint(result) } -fn associated_item_def_ids(tcx: TyCtxt<'_>, def_id: DefId) -> &[DefId] { - let item = tcx.hir().expect_item(def_id.expect_local()); - match item.kind { - hir::ItemKind::Trait(.., ref trait_item_refs) => tcx.arena.alloc_from_iter( - trait_item_refs.iter().map(|trait_item_ref| trait_item_ref.id.def_id.to_def_id()), - ), - hir::ItemKind::Impl(ref impl_) => tcx.arena.alloc_from_iter( - impl_.items.iter().map(|impl_item_ref| impl_item_ref.id.def_id.to_def_id()), - ), - hir::ItemKind::TraitAlias(..) => &[], - _ => span_bug!(item.span, "associated_item_def_ids: not impl or trait"), - } -} - -fn associated_items(tcx: TyCtxt<'_>, def_id: DefId) -> ty::AssocItems<'_> { - let items = tcx.associated_item_def_ids(def_id).iter().map(|did| tcx.associated_item(*did)); - ty::AssocItems::new(items) -} - fn def_ident_span(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Span> { tcx.hir() .get_if_local(def_id) @@ -231,16 +128,6 @@ fn def_ident_span(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Span> { .map(|ident| ident.span) } -/// If the given `DefId` describes an item belonging to a trait, -/// returns the `DefId` of the trait that the trait item belongs to; -/// otherwise, returns `None`. -fn trait_of_item(tcx: TyCtxt<'_>, def_id: DefId) -> Option<DefId> { - tcx.opt_associated_item(def_id).and_then(|associated_item| match associated_item.container { - ty::TraitContainer(def_id) => Some(def_id), - ty::ImplContainer(_) => None, - }) -} - /// See `ParamEnv` struct definition for details. #[instrument(level = "debug", skip(tcx))] fn param_env(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamEnv<'_> { @@ -620,14 +507,10 @@ pub fn conservative_is_privately_uninhabited_raw<'tcx>( pub fn provide(providers: &mut ty::query::Providers) { *providers = ty::query::Providers { asyncness, - associated_item, - associated_item_def_ids, - associated_items, adt_sized_constraint, def_ident_span, param_env, param_env_reveal_all_normalized, - trait_of_item, instance_def_size_estimate, issue33140_self_ty, impl_defaultness, 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/check.rs b/compiler/rustc_typeck/src/check/check.rs index fd7b3a55dfb..dcf42e1aefe 100644 --- a/compiler/rustc_typeck/src/check/check.rs +++ b/compiler/rustc_typeck/src/check/check.rs @@ -841,14 +841,8 @@ pub(super) fn check_specialization_validity<'tcx>( trait_def: &ty::TraitDef, trait_item: &ty::AssocItem, impl_id: DefId, - impl_item: &hir::ImplItem<'_>, + impl_item: &hir::ImplItemRef, ) { - let kind = match impl_item.kind { - hir::ImplItemKind::Const(..) => ty::AssocKind::Const, - hir::ImplItemKind::Fn(..) => ty::AssocKind::Fn, - hir::ImplItemKind::TyAlias(_) => ty::AssocKind::Type, - }; - let ancestors = match trait_def.ancestors(tcx, impl_id) { Ok(ancestors) => ancestors, Err(_) => return, @@ -857,7 +851,7 @@ pub(super) fn check_specialization_validity<'tcx>( if parent.is_from_trait() { None } else { - Some((parent, parent.item(tcx, trait_item.ident, kind, trait_def.def_id))) + Some((parent, parent.item(tcx, trait_item.def_id))) } }); @@ -894,7 +888,7 @@ pub(super) fn check_specialization_validity<'tcx>( } } -pub(super) fn check_impl_items_against_trait<'tcx>( +fn check_impl_items_against_trait<'tcx>( tcx: TyCtxt<'tcx>, full_impl_span: Span, impl_id: LocalDefId, @@ -926,174 +920,82 @@ pub(super) fn check_impl_items_against_trait<'tcx>( } } - // Locate trait definition and items let trait_def = tcx.trait_def(impl_trait_ref.def_id); - let impl_items = impl_item_refs.iter().map(|iiref| tcx.hir().impl_item(iiref.id)); - let associated_items = tcx.associated_items(impl_trait_ref.def_id); - - // Check existing impl methods to see if they are both present in trait - // and compatible with trait signature - for impl_item in impl_items { - let ty_impl_item = tcx.associated_item(impl_item.def_id); - - let mut items = - associated_items.filter_by_name(tcx, ty_impl_item.ident, impl_trait_ref.def_id); - - let (compatible_kind, ty_trait_item) = if let Some(ty_trait_item) = items.next() { - let is_compatible = |ty: &&ty::AssocItem| match (ty.kind, &impl_item.kind) { - (ty::AssocKind::Const, hir::ImplItemKind::Const(..)) => true, - (ty::AssocKind::Fn, hir::ImplItemKind::Fn(..)) => true, - (ty::AssocKind::Type, hir::ImplItemKind::TyAlias(..)) => true, - _ => false, - }; - - // If we don't have a compatible item, we'll use the first one whose name matches - // to report an error. - let mut compatible_kind = is_compatible(&ty_trait_item); - let mut trait_item = ty_trait_item; - - if !compatible_kind { - if let Some(ty_trait_item) = items.find(is_compatible) { - compatible_kind = true; - trait_item = ty_trait_item; - } - } - (compatible_kind, trait_item) + for impl_item in impl_item_refs { + let ty_impl_item = tcx.associated_item(impl_item.id.def_id); + let ty_trait_item = if let Some(trait_item_id) = ty_impl_item.trait_item_def_id { + tcx.associated_item(trait_item_id) } else { + // Checked in `associated_item`. + tcx.sess.delay_span_bug(impl_item.span, "missing associated item in trait"); continue; }; - - if compatible_kind { - match impl_item.kind { - hir::ImplItemKind::Const(..) => { - // Find associated const definition. - compare_const_impl( - tcx, - &ty_impl_item, - impl_item.span, - &ty_trait_item, - impl_trait_ref, - ); - } - hir::ImplItemKind::Fn(..) => { - let opt_trait_span = tcx.hir().span_if_local(ty_trait_item.def_id); - compare_impl_method( - tcx, - &ty_impl_item, - impl_item.span, - &ty_trait_item, - impl_trait_ref, - opt_trait_span, - ); - } - hir::ImplItemKind::TyAlias(impl_ty) => { - let opt_trait_span = tcx.hir().span_if_local(ty_trait_item.def_id); - compare_ty_impl( - tcx, - &ty_impl_item, - impl_ty.span, - &ty_trait_item, - impl_trait_ref, - opt_trait_span, - ); - } + let impl_item_full = tcx.hir().impl_item(impl_item.id); + match impl_item_full.kind { + hir::ImplItemKind::Const(..) => { + // Find associated const definition. + compare_const_impl( + tcx, + &ty_impl_item, + impl_item.span, + &ty_trait_item, + impl_trait_ref, + ); + } + hir::ImplItemKind::Fn(..) => { + let opt_trait_span = tcx.hir().span_if_local(ty_trait_item.def_id); + compare_impl_method( + tcx, + &ty_impl_item, + impl_item.span, + &ty_trait_item, + impl_trait_ref, + opt_trait_span, + ); + } + hir::ImplItemKind::TyAlias(impl_ty) => { + let opt_trait_span = tcx.hir().span_if_local(ty_trait_item.def_id); + compare_ty_impl( + tcx, + &ty_impl_item, + impl_ty.span, + &ty_trait_item, + impl_trait_ref, + opt_trait_span, + ); } - - check_specialization_validity( - tcx, - trait_def, - &ty_trait_item, - impl_id.to_def_id(), - impl_item, - ); - } else { - report_mismatch_error( - tcx, - ty_trait_item.def_id, - impl_trait_ref, - impl_item, - &ty_impl_item, - ); } + + check_specialization_validity( + tcx, + trait_def, + &ty_trait_item, + impl_id.to_def_id(), + impl_item, + ); } if let Ok(ancestors) = trait_def.ancestors(tcx, impl_id.to_def_id()) { - let impl_span = tcx.sess.source_map().guess_head_span(full_impl_span); - // Check for missing items from trait let mut missing_items = Vec::new(); - for trait_item in tcx.associated_items(impl_trait_ref.def_id).in_definition_order() { + for &trait_item_id in tcx.associated_item_def_ids(impl_trait_ref.def_id) { let is_implemented = ancestors - .leaf_def(tcx, trait_item.ident, trait_item.kind) - .map(|node_item| !node_item.defining_node.is_from_trait()) - .unwrap_or(false); + .leaf_def(tcx, trait_item_id) + .map_or(false, |node_item| node_item.item.defaultness.has_value()); if !is_implemented && tcx.impl_defaultness(impl_id).is_final() { - if !trait_item.defaultness.has_value() { - missing_items.push(*trait_item); - } + missing_items.push(tcx.associated_item(trait_item_id)); } } if !missing_items.is_empty() { + let impl_span = tcx.sess.source_map().guess_head_span(full_impl_span); missing_items_err(tcx, impl_span, &missing_items, full_impl_span); } } } -#[inline(never)] -#[cold] -fn report_mismatch_error<'tcx>( - tcx: TyCtxt<'tcx>, - trait_item_def_id: DefId, - impl_trait_ref: ty::TraitRef<'tcx>, - impl_item: &hir::ImplItem<'_>, - ty_impl_item: &ty::AssocItem, -) { - let mut err = match impl_item.kind { - hir::ImplItemKind::Const(..) => { - // Find associated const definition. - struct_span_err!( - tcx.sess, - impl_item.span, - E0323, - "item `{}` is an associated const, which doesn't match its trait `{}`", - ty_impl_item.ident, - impl_trait_ref.print_only_trait_path() - ) - } - - hir::ImplItemKind::Fn(..) => { - struct_span_err!( - tcx.sess, - impl_item.span, - E0324, - "item `{}` is an associated method, which doesn't match its trait `{}`", - ty_impl_item.ident, - impl_trait_ref.print_only_trait_path() - ) - } - - hir::ImplItemKind::TyAlias(_) => { - struct_span_err!( - tcx.sess, - impl_item.span, - E0325, - "item `{}` is an associated type, which doesn't match its trait `{}`", - ty_impl_item.ident, - impl_trait_ref.print_only_trait_path() - ) - } - }; - - err.span_label(impl_item.span, "does not match trait"); - if let Some(trait_span) = tcx.hir().span_if_local(trait_item_def_id) { - err.span_label(trait_span, "item in trait"); - } - err.emit(); -} - /// Checks whether a type can be represented in memory. In particular, it /// identifies types that contain themselves without indirection through a /// pointer, which would mean their size is unbounded. diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs index 096c4fcf472..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() { @@ -1508,7 +1508,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } else { self.check_expr_has_type_or_error(base_expr, adt_ty, |_| { - let base_ty = self.check_expr(base_expr); + let base_ty = self.typeck_results.borrow().node_type(base_expr.hir_id); let same_adt = match (adt_ty.kind(), base_ty.kind()) { (ty::Adt(adt, _), ty::Adt(base_adt, _)) if adt == base_adt => true, _ => false, 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/check/mod.rs b/compiler/rustc_typeck/src/check/mod.rs index a9e6b1caff0..d576154ff90 100644 --- a/compiler/rustc_typeck/src/check/mod.rs +++ b/compiler/rustc_typeck/src/check/mod.rs @@ -566,7 +566,7 @@ fn maybe_check_static_with_link_section(tcx: TyCtxt<'_>, id: LocalDefId, span: S fn report_forbidden_specialization( tcx: TyCtxt<'_>, - impl_item: &hir::ImplItem<'_>, + impl_item: &hir::ImplItemRef, parent_impl: DefId, ) { let mut err = struct_span_err!( @@ -598,7 +598,7 @@ fn report_forbidden_specialization( fn missing_items_err( tcx: TyCtxt<'_>, impl_span: Span, - missing_items: &[ty::AssocItem], + missing_items: &[&ty::AssocItem], full_impl_span: Span, ) { let missing_items_msg = missing_items diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index e7b728d491b..d4d4baa3f71 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 @@ -3142,21 +3150,12 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs { /// applied to the method prototype. fn should_inherit_track_caller(tcx: TyCtxt<'_>, def_id: DefId) -> bool { if let Some(impl_item) = tcx.opt_associated_item(def_id) { - if let ty::AssocItemContainer::ImplContainer(impl_def_id) = impl_item.container { - if let Some(trait_def_id) = tcx.trait_id_of_impl(impl_def_id) { - if let Some(trait_item) = tcx - .associated_items(trait_def_id) - .filter_by_name_unhygienic(impl_item.ident.name) - .find(move |trait_item| { - trait_item.kind == ty::AssocKind::Fn - && tcx.hygienic_eq(impl_item.ident, trait_item.ident, trait_def_id) - }) - { - return tcx - .codegen_fn_attrs(trait_item.def_id) - .flags - .intersects(CodegenFnAttrFlags::TRACK_CALLER); - } + if let ty::AssocItemContainer::ImplContainer(_) = impl_item.container { + if let Some(trait_item) = impl_item.trait_item_def_id { + return tcx + .codegen_fn_attrs(trait_item) + .flags + .intersects(CodegenFnAttrFlags::TRACK_CALLER); } } } 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. |
