Importing rustc-1.51.0
Change-Id: Ie4f520eabee71971211e4637a45cbc9bf4a91e95
diff --git a/compiler/rustc_arena/src/lib.rs b/compiler/rustc_arena/src/lib.rs
index f468bad..651f4c6 100644
--- a/compiler/rustc_arena/src/lib.rs
+++ b/compiler/rustc_arena/src/lib.rs
@@ -11,12 +11,10 @@
html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/",
test(no_crate_inject, attr(deny(warnings)))
)]
-#![feature(array_value_iter_slice)]
#![feature(dropck_eyepatch)]
#![feature(new_uninit)]
#![feature(maybe_uninit_slice)]
-#![feature(array_value_iter)]
-#![feature(min_const_generics)]
+#![cfg_attr(bootstrap, feature(min_const_generics))]
#![feature(min_specialization)]
#![cfg_attr(test, feature(test))]
@@ -32,7 +30,7 @@
#[inline(never)]
#[cold]
-pub fn cold_path<F: FnOnce() -> R, R>(f: F) -> R {
+fn cold_path<F: FnOnce() -> R, R>(f: F) -> R {
f()
}
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index 220bbed..2ddcb9e 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -23,8 +23,8 @@
pub use UnsafeSource::*;
use crate::ptr::P;
-use crate::token::{self, CommentKind, DelimToken};
-use crate::tokenstream::{DelimSpan, LazyTokenStream, TokenStream};
+use crate::token::{self, CommentKind, DelimToken, Token};
+use crate::tokenstream::{DelimSpan, LazyTokenStream, TokenStream, TokenTree};
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_data_structures::stack::ensure_sufficient_stack;
@@ -167,10 +167,7 @@
impl GenericArgs {
pub fn is_angle_bracketed(&self) -> bool {
- match *self {
- AngleBracketed(..) => true,
- _ => false,
- }
+ matches!(self, AngleBracketed(..))
}
pub fn span(&self) -> Span {
@@ -245,12 +242,21 @@
/// A path like `Foo(A, B) -> C`.
#[derive(Clone, Encodable, Decodable, Debug)]
pub struct ParenthesizedArgs {
- /// Overall span
+ /// ```text
+ /// Foo(A, B) -> C
+ /// ^^^^^^^^^^^^^^
+ /// ```
pub span: Span,
/// `(A, B)`
pub inputs: Vec<P<Ty>>,
+ /// ```text
+ /// Foo(A, B) -> C
+ /// ^^^^^^
+ /// ```
+ pub inputs_span: Span,
+
/// `C`
pub output: FnRetTy,
}
@@ -371,6 +377,8 @@
ty: P<Ty>,
/// Span of the `const` keyword.
kw_span: Span,
+ /// Optional default value for the const generic param
+ default: Option<AnonConst>,
},
}
@@ -434,9 +442,9 @@
impl WherePredicate {
pub fn span(&self) -> Span {
match self {
- &WherePredicate::BoundPredicate(ref p) => p.span,
- &WherePredicate::RegionPredicate(ref p) => p.span,
- &WherePredicate::EqPredicate(ref p) => p.span,
+ WherePredicate::BoundPredicate(p) => p.span,
+ WherePredicate::RegionPredicate(p) => p.span,
+ WherePredicate::EqPredicate(p) => p.span,
}
}
}
@@ -629,23 +637,20 @@
/// Is this a `..` pattern?
pub fn is_rest(&self) -> bool {
- match self.kind {
- PatKind::Rest => true,
- _ => false,
- }
+ matches!(self.kind, PatKind::Rest)
}
}
-/// A single field in a struct pattern
+/// A single field in a struct pattern.
///
-/// Patterns like the fields of Foo `{ x, ref y, ref mut z }`
-/// are treated the same as` x: x, y: ref y, z: ref mut z`,
-/// except is_shorthand is true
+/// Patterns like the fields of `Foo { x, ref y, ref mut z }`
+/// are treated the same as `x: x, y: ref y, z: ref mut z`,
+/// except when `is_shorthand` is true.
#[derive(Clone, Encodable, Decodable, Debug)]
pub struct FieldPat {
- /// The identifier for the field
+ /// The identifier for the field.
pub ident: Ident,
- /// The pattern the field is destructured to
+ /// The pattern the field is destructured to.
pub pat: P<Pat>,
pub is_shorthand: bool,
pub attrs: AttrVec,
@@ -852,10 +857,7 @@
}
}
pub fn lazy(&self) -> bool {
- match *self {
- BinOpKind::And | BinOpKind::Or => true,
- _ => false,
- }
+ matches!(self, BinOpKind::And | BinOpKind::Or)
}
pub fn is_comparison(&self) -> bool {
@@ -923,16 +925,6 @@
}
}
- pub fn set_tokens(&mut self, tokens: Option<LazyTokenStream>) {
- match self.kind {
- StmtKind::Local(ref mut local) => local.tokens = tokens,
- StmtKind::Item(ref mut item) => item.tokens = tokens,
- StmtKind::Expr(ref mut expr) | StmtKind::Semi(ref mut expr) => expr.tokens = tokens,
- StmtKind::Empty => {}
- StmtKind::MacCall(ref mut mac) => mac.tokens = tokens,
- }
- }
-
pub fn has_trailing_semicolon(&self) -> bool {
match &self.kind {
StmtKind::Semi(_) => true,
@@ -963,17 +955,11 @@
}
pub fn is_item(&self) -> bool {
- match self.kind {
- StmtKind::Item(_) => true,
- _ => false,
- }
+ matches!(self.kind, StmtKind::Item(_))
}
pub fn is_expr(&self) -> bool {
- match self.kind {
- StmtKind::Expr(_) => true,
- _ => false,
- }
+ matches!(self.kind, StmtKind::Expr(_))
}
}
@@ -1107,15 +1093,9 @@
if let ExprKind::Block(ref block, _) = self.kind {
match block.stmts.last().map(|last_stmt| &last_stmt.kind) {
// Implicit return
- Some(&StmtKind::Expr(_)) => true,
- Some(&StmtKind::Semi(ref expr)) => {
- if let ExprKind::Ret(_) = expr.kind {
- // Last statement is explicit return.
- true
- } else {
- false
- }
- }
+ Some(StmtKind::Expr(_)) => true,
+ // Last statement is an explicit return?
+ Some(StmtKind::Semi(expr)) => matches!(expr.kind, ExprKind::Ret(_)),
// This is a block that doesn't end in either an implicit or explicit return.
_ => false,
}
@@ -1128,7 +1108,7 @@
/// Is this expr either `N`, or `{ N }`.
///
/// If this is not the case, name resolution does not resolve `N` when using
- /// `feature(min_const_generics)` as more complex expressions are not supported.
+ /// `min_const_generics` as more complex expressions are not supported.
pub fn is_potential_trivial_const_param(&self) -> bool {
let this = if let ExprKind::Block(ref block, None) = self.kind {
if block.stmts.len() == 1 {
@@ -1483,8 +1463,8 @@
Eq(
/// Span of the `=` token.
Span,
- /// Token stream of the "value".
- TokenStream,
+ /// "value" as a nonterminal token.
+ Token,
),
}
@@ -1497,10 +1477,10 @@
}
pub fn span(&self) -> Option<Span> {
- match *self {
+ match self {
MacArgs::Empty => None,
MacArgs::Delimited(dspan, ..) => Some(dspan.entire()),
- MacArgs::Eq(eq_span, ref tokens) => Some(eq_span.to(tokens.span().unwrap_or(eq_span))),
+ MacArgs::Eq(eq_span, token) => Some(eq_span.to(token.span)),
}
}
@@ -1509,7 +1489,8 @@
pub fn inner_tokens(&self) -> TokenStream {
match self {
MacArgs::Empty => TokenStream::default(),
- MacArgs::Delimited(.., tokens) | MacArgs::Eq(.., tokens) => tokens.clone(),
+ MacArgs::Delimited(.., tokens) => tokens.clone(),
+ MacArgs::Eq(.., token) => TokenTree::Token(token.clone()).into(),
}
}
@@ -1652,26 +1633,17 @@
impl LitKind {
/// Returns `true` if this literal is a string.
pub fn is_str(&self) -> bool {
- match *self {
- LitKind::Str(..) => true,
- _ => false,
- }
+ matches!(self, LitKind::Str(..))
}
/// Returns `true` if this literal is byte literal string.
pub fn is_bytestr(&self) -> bool {
- match self {
- LitKind::ByteStr(_) => true,
- _ => false,
- }
+ matches!(self, LitKind::ByteStr(_))
}
/// Returns `true` if this is a numeric literal.
pub fn is_numeric(&self) -> bool {
- match *self {
- LitKind::Int(..) | LitKind::Float(..) => true,
- _ => false,
- }
+ matches!(self, LitKind::Int(..) | LitKind::Float(..))
}
/// Returns `true` if this literal has no suffix.
@@ -1974,7 +1946,7 @@
}
pub fn is_unit(&self) -> bool {
- if let TyKind::Tup(ref tys) = *self { tys.is_empty() } else { false }
+ matches!(self, TyKind::Tup(tys) if tys.is_empty())
}
}
@@ -2237,10 +2209,7 @@
self.inputs.get(0).map_or(false, Param::is_self)
}
pub fn c_variadic(&self) -> bool {
- self.inputs.last().map_or(false, |arg| match arg.ty.kind {
- TyKind::CVarArgs => true,
- _ => false,
- })
+ self.inputs.last().map_or(false, |arg| matches!(arg.ty.kind, TyKind::CVarArgs))
}
}
@@ -2687,6 +2656,36 @@
}
#[derive(Clone, Encodable, Decodable, Debug)]
+pub struct TraitKind(
+ pub IsAuto,
+ pub Unsafe,
+ pub Generics,
+ pub GenericBounds,
+ pub Vec<P<AssocItem>>,
+);
+
+#[derive(Clone, Encodable, Decodable, Debug)]
+pub struct TyAliasKind(pub Defaultness, pub Generics, pub GenericBounds, pub Option<P<Ty>>);
+
+#[derive(Clone, Encodable, Decodable, Debug)]
+pub struct ImplKind {
+ pub unsafety: Unsafe,
+ pub polarity: ImplPolarity,
+ pub defaultness: Defaultness,
+ pub constness: Const,
+ pub generics: Generics,
+
+ /// The trait being implemented, if any.
+ pub of_trait: Option<TraitRef>,
+
+ pub self_ty: P<Ty>,
+ pub items: Vec<P<AssocItem>>,
+}
+
+#[derive(Clone, Encodable, Decodable, Debug)]
+pub struct FnKind(pub Defaultness, pub FnSig, pub Generics, pub Option<P<Block>>);
+
+#[derive(Clone, Encodable, Decodable, Debug)]
pub enum ItemKind {
/// An `extern crate` item, with the optional *original* crate name if the crate was renamed.
///
@@ -2707,7 +2706,7 @@
/// A function declaration (`fn`).
///
/// E.g., `fn foo(bar: usize) -> usize { .. }`.
- Fn(Defaultness, FnSig, Generics, Option<P<Block>>),
+ Fn(Box<FnKind>),
/// A module declaration (`mod`).
///
/// E.g., `mod foo;` or `mod foo { .. }`.
@@ -2721,7 +2720,7 @@
/// A type alias (`type`).
///
/// E.g., `type Foo = Bar<u8>;`.
- TyAlias(Defaultness, Generics, GenericBounds, Option<P<Ty>>),
+ TyAlias(Box<TyAliasKind>),
/// An enum definition (`enum`).
///
/// E.g., `enum Foo<A, B> { C<A>, D<B> }`.
@@ -2737,7 +2736,7 @@
/// A trait declaration (`trait`).
///
/// E.g., `trait Foo { .. }`, `trait Foo<T> { .. }` or `auto trait Foo {}`.
- Trait(IsAuto, Unsafe, Generics, GenericBounds, Vec<P<AssocItem>>),
+ Trait(Box<TraitKind>),
/// Trait alias
///
/// E.g., `trait Foo = Bar + Quux;`.
@@ -2745,19 +2744,7 @@
/// An implementation.
///
/// E.g., `impl<A> Foo<A> { .. }` or `impl<A> Trait for Foo<A> { .. }`.
- Impl {
- unsafety: Unsafe,
- polarity: ImplPolarity,
- defaultness: Defaultness,
- constness: Const,
- generics: Generics,
-
- /// The trait being implemented, if any.
- of_trait: Option<TraitRef>,
-
- self_ty: P<Ty>,
- items: Vec<P<AssocItem>>,
- },
+ Impl(Box<ImplKind>),
/// A macro invocation.
///
/// E.g., `foo!(..)`.
@@ -2767,6 +2754,9 @@
MacroDef(MacroDef),
}
+#[cfg(target_arch = "x86_64")]
+rustc_data_structures::static_assert_size!(ItemKind, 112);
+
impl ItemKind {
pub fn article(&self) -> &str {
use ItemKind::*;
@@ -2801,14 +2791,14 @@
pub fn generics(&self) -> Option<&Generics> {
match self {
- Self::Fn(_, _, generics, _)
- | Self::TyAlias(_, generics, ..)
+ Self::Fn(box FnKind(_, _, generics, _))
+ | Self::TyAlias(box TyAliasKind(_, generics, ..))
| Self::Enum(_, generics)
| Self::Struct(_, generics)
| Self::Union(_, generics)
- | Self::Trait(_, _, generics, ..)
+ | Self::Trait(box TraitKind(_, _, generics, ..))
| Self::TraitAlias(generics, _)
- | Self::Impl { generics, .. } => Some(generics),
+ | Self::Impl(box ImplKind { generics, .. }) => Some(generics),
_ => None,
}
}
@@ -2831,17 +2821,22 @@
/// If `def` is parsed, then the constant is provided, and otherwise required.
Const(Defaultness, P<Ty>, Option<P<Expr>>),
/// An associated function.
- Fn(Defaultness, FnSig, Generics, Option<P<Block>>),
+ Fn(Box<FnKind>),
/// An associated type.
- TyAlias(Defaultness, Generics, GenericBounds, Option<P<Ty>>),
+ TyAlias(Box<TyAliasKind>),
/// A macro expanding to associated items.
MacCall(MacCall),
}
+#[cfg(target_arch = "x86_64")]
+rustc_data_structures::static_assert_size!(AssocItemKind, 72);
+
impl AssocItemKind {
pub fn defaultness(&self) -> Defaultness {
match *self {
- Self::Const(def, ..) | Self::Fn(def, ..) | Self::TyAlias(def, ..) => def,
+ Self::Const(def, ..)
+ | Self::Fn(box FnKind(def, ..))
+ | Self::TyAlias(box TyAliasKind(def, ..)) => def,
Self::MacCall(..) => Defaultness::Final,
}
}
@@ -2851,8 +2846,8 @@
fn from(assoc_item_kind: AssocItemKind) -> ItemKind {
match assoc_item_kind {
AssocItemKind::Const(a, b, c) => ItemKind::Const(a, b, c),
- AssocItemKind::Fn(a, b, c, d) => ItemKind::Fn(a, b, c, d),
- AssocItemKind::TyAlias(a, b, c, d) => ItemKind::TyAlias(a, b, c, d),
+ AssocItemKind::Fn(fn_kind) => ItemKind::Fn(fn_kind),
+ AssocItemKind::TyAlias(ty_alias_kind) => ItemKind::TyAlias(ty_alias_kind),
AssocItemKind::MacCall(a) => ItemKind::MacCall(a),
}
}
@@ -2864,8 +2859,8 @@
fn try_from(item_kind: ItemKind) -> Result<AssocItemKind, ItemKind> {
Ok(match item_kind {
ItemKind::Const(a, b, c) => AssocItemKind::Const(a, b, c),
- ItemKind::Fn(a, b, c, d) => AssocItemKind::Fn(a, b, c, d),
- ItemKind::TyAlias(a, b, c, d) => AssocItemKind::TyAlias(a, b, c, d),
+ ItemKind::Fn(fn_kind) => AssocItemKind::Fn(fn_kind),
+ ItemKind::TyAlias(ty_alias_kind) => AssocItemKind::TyAlias(ty_alias_kind),
ItemKind::MacCall(a) => AssocItemKind::MacCall(a),
_ => return Err(item_kind),
})
@@ -2877,20 +2872,23 @@
pub enum ForeignItemKind {
/// A foreign static item (`static FOO: u8`).
Static(P<Ty>, Mutability, Option<P<Expr>>),
- /// A foreign function.
- Fn(Defaultness, FnSig, Generics, Option<P<Block>>),
- /// A foreign type.
- TyAlias(Defaultness, Generics, GenericBounds, Option<P<Ty>>),
+ /// An foreign function.
+ Fn(Box<FnKind>),
+ /// An foreign type.
+ TyAlias(Box<TyAliasKind>),
/// A macro expanding to foreign items.
MacCall(MacCall),
}
+#[cfg(target_arch = "x86_64")]
+rustc_data_structures::static_assert_size!(ForeignItemKind, 72);
+
impl From<ForeignItemKind> for ItemKind {
fn from(foreign_item_kind: ForeignItemKind) -> ItemKind {
match foreign_item_kind {
ForeignItemKind::Static(a, b, c) => ItemKind::Static(a, b, c),
- ForeignItemKind::Fn(a, b, c, d) => ItemKind::Fn(a, b, c, d),
- ForeignItemKind::TyAlias(a, b, c, d) => ItemKind::TyAlias(a, b, c, d),
+ ForeignItemKind::Fn(fn_kind) => ItemKind::Fn(fn_kind),
+ ForeignItemKind::TyAlias(ty_alias_kind) => ItemKind::TyAlias(ty_alias_kind),
ForeignItemKind::MacCall(a) => ItemKind::MacCall(a),
}
}
@@ -2902,8 +2900,8 @@
fn try_from(item_kind: ItemKind) -> Result<ForeignItemKind, ItemKind> {
Ok(match item_kind {
ItemKind::Static(a, b, c) => ForeignItemKind::Static(a, b, c),
- ItemKind::Fn(a, b, c, d) => ForeignItemKind::Fn(a, b, c, d),
- ItemKind::TyAlias(a, b, c, d) => ForeignItemKind::TyAlias(a, b, c, d),
+ ItemKind::Fn(fn_kind) => ForeignItemKind::Fn(fn_kind),
+ ItemKind::TyAlias(ty_alias_kind) => ForeignItemKind::TyAlias(ty_alias_kind),
ItemKind::MacCall(a) => ForeignItemKind::MacCall(a),
_ => return Err(item_kind),
})
@@ -2911,3 +2909,69 @@
}
pub type ForeignItem = Item<ForeignItemKind>;
+
+pub trait HasTokens {
+ /// Called by `Parser::collect_tokens` to store the collected
+ /// tokens inside an AST node
+ fn finalize_tokens(&mut self, tokens: LazyTokenStream);
+}
+
+impl<T: HasTokens + 'static> HasTokens for P<T> {
+ fn finalize_tokens(&mut self, tokens: LazyTokenStream) {
+ (**self).finalize_tokens(tokens);
+ }
+}
+
+impl<T: HasTokens> HasTokens for Option<T> {
+ fn finalize_tokens(&mut self, tokens: LazyTokenStream) {
+ if let Some(inner) = self {
+ inner.finalize_tokens(tokens);
+ }
+ }
+}
+
+impl HasTokens for Attribute {
+ fn finalize_tokens(&mut self, tokens: LazyTokenStream) {
+ match &mut self.kind {
+ AttrKind::Normal(_, attr_tokens) => {
+ if attr_tokens.is_none() {
+ *attr_tokens = Some(tokens);
+ }
+ }
+ AttrKind::DocComment(..) => {
+ panic!("Called finalize_tokens on doc comment attr {:?}", self)
+ }
+ }
+ }
+}
+
+impl HasTokens for Stmt {
+ fn finalize_tokens(&mut self, tokens: LazyTokenStream) {
+ let stmt_tokens = match self.kind {
+ StmtKind::Local(ref mut local) => &mut local.tokens,
+ StmtKind::Item(ref mut item) => &mut item.tokens,
+ StmtKind::Expr(ref mut expr) | StmtKind::Semi(ref mut expr) => &mut expr.tokens,
+ StmtKind::Empty => return,
+ StmtKind::MacCall(ref mut mac) => &mut mac.tokens,
+ };
+ if stmt_tokens.is_none() {
+ *stmt_tokens = Some(tokens);
+ }
+ }
+}
+
+macro_rules! derive_has_tokens {
+ ($($ty:path),*) => { $(
+ impl HasTokens for $ty {
+ fn finalize_tokens(&mut self, tokens: LazyTokenStream) {
+ if self.tokens.is_none() {
+ self.tokens = Some(tokens);
+ }
+ }
+ }
+ )* }
+}
+
+derive_has_tokens! {
+ Item, Expr, Ty, AttrItem, Visibility, Path, Block, Pat
+}
diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs
index 19c7c47..4dcbe48 100644
--- a/compiler/rustc_ast/src/attr/mod.rs
+++ b/compiler/rustc_ast/src/attr/mod.rs
@@ -234,10 +234,7 @@
}
pub fn is_word(&self) -> bool {
- match self.kind {
- MetaItemKind::Word => true,
- _ => false,
- }
+ matches!(self.kind, MetaItemKind::Word)
}
pub fn has_name(&self, name: Symbol) -> bool {
@@ -479,7 +476,7 @@
pub fn mac_args(&self, span: Span) -> MacArgs {
match self {
MetaItemKind::Word => MacArgs::Empty,
- MetaItemKind::NameValue(lit) => MacArgs::Eq(span, lit.token_tree().into()),
+ MetaItemKind::NameValue(lit) => MacArgs::Eq(span, lit.to_token()),
MetaItemKind::List(list) => {
let mut tts = Vec::new();
for (i, item) in list.iter().enumerate() {
@@ -501,7 +498,10 @@
match *self {
MetaItemKind::Word => vec![],
MetaItemKind::NameValue(ref lit) => {
- vec![TokenTree::token(token::Eq, span).into(), lit.token_tree().into()]
+ vec![
+ TokenTree::token(token::Eq, span).into(),
+ TokenTree::Token(lit.to_token()).into(),
+ ]
}
MetaItemKind::List(ref list) => {
let mut tokens = Vec::new();
@@ -526,7 +526,7 @@
fn list_from_tokens(tokens: TokenStream) -> Option<MetaItemKind> {
let mut tokens = tokens.into_trees().peekable();
let mut result = Vec::new();
- while let Some(..) = tokens.peek() {
+ while tokens.peek().is_some() {
let item = NestedMetaItem::from_tokens(&mut tokens)?;
result.push(item);
match tokens.next() {
@@ -557,10 +557,7 @@
MetaItemKind::list_from_tokens(tokens.clone())
}
MacArgs::Delimited(..) => None,
- MacArgs::Eq(_, tokens) => {
- assert!(tokens.len() == 1);
- MetaItemKind::name_value_from_tokens(&mut tokens.trees())
- }
+ MacArgs::Eq(_, token) => Lit::from_token(token).ok().map(MetaItemKind::NameValue),
MacArgs::Empty => Some(MetaItemKind::Word),
}
}
@@ -595,7 +592,7 @@
fn token_trees_and_spacings(&self) -> Vec<TreeAndSpacing> {
match *self {
NestedMetaItem::MetaItem(ref item) => item.token_trees_and_spacings(),
- NestedMetaItem::Literal(ref lit) => vec![lit.token_tree().into()],
+ NestedMetaItem::Literal(ref lit) => vec![TokenTree::Token(lit.to_token()).into()],
}
}
diff --git a/compiler/rustc_ast/src/lib.rs b/compiler/rustc_ast/src/lib.rs
index 8a20dd7..ddf52ca 100644
--- a/compiler/rustc_ast/src/lib.rs
+++ b/compiler/rustc_ast/src/lib.rs
@@ -9,6 +9,7 @@
test(attr(deny(warnings)))
)]
#![feature(box_syntax)]
+#![feature(box_patterns)]
#![feature(const_fn)] // For the `transmute` in `P::new`
#![feature(const_fn_transmute)]
#![feature(const_panic)]
diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs
index 3889ede..024d968 100644
--- a/compiler/rustc_ast/src/mut_visit.rs
+++ b/compiler/rustc_ast/src/mut_visit.rs
@@ -28,7 +28,7 @@
impl<A: Array> ExpectOne<A> for SmallVec<A> {
fn expect_one(self, err: &'static str) -> A::Item {
- assert!(self.len() == 1, err);
+ assert!(self.len() == 1, "{}", err);
self.into_iter().next().unwrap()
}
}
@@ -365,18 +365,16 @@
visit_delim_span(dspan, vis);
visit_tts(tokens, vis);
}
- MacArgs::Eq(eq_span, tokens) => {
+ MacArgs::Eq(eq_span, token) => {
vis.visit_span(eq_span);
- visit_tts(tokens, vis);
- // The value in `#[key = VALUE]` must be visited as an expression for backward
- // compatibility, so that macros can be expanded in that position.
- if !vis.token_visiting_enabled() {
- match Lrc::make_mut(&mut tokens.0).get_mut(0) {
- Some((TokenTree::Token(token), _spacing)) => match &mut token.kind {
- token::Interpolated(nt) => match Lrc::make_mut(nt) {
- token::NtExpr(expr) => vis.visit_expr(expr),
- t => panic!("unexpected token in key-value attribute: {:?}", t),
- },
+ if vis.token_visiting_enabled() {
+ visit_token(token, vis);
+ } else {
+ // The value in `#[key = VALUE]` must be visited as an expression for backward
+ // compatibility, so that macros can be expanded in that position.
+ match &mut token.kind {
+ token::Interpolated(nt) => match Lrc::make_mut(nt) {
+ token::NtExpr(expr) => vis.visit_expr(expr),
t => panic!("unexpected token in key-value attribute: {:?}", t),
},
t => panic!("unexpected token in key-value attribute: {:?}", t),
@@ -567,7 +565,7 @@
args: &mut ParenthesizedArgs,
vis: &mut T,
) {
- let ParenthesizedArgs { inputs, output, span } = args;
+ let ParenthesizedArgs { inputs, output, span, .. } = args;
visit_vec(inputs, |input| vis.visit_ty(input));
noop_visit_fn_ret_ty(output, vis);
vis.visit_span(span);
@@ -790,8 +788,9 @@
GenericParamKind::Type { default } => {
visit_opt(default, |default| vis.visit_ty(default));
}
- GenericParamKind::Const { ty, kw_span: _ } => {
+ GenericParamKind::Const { ty, kw_span: _, default } => {
vis.visit_ty(ty);
+ visit_opt(default, |default| vis.visit_anon_const(default));
}
}
smallvec![param]
@@ -913,7 +912,7 @@
vis.visit_ty(ty);
visit_opt(expr, |expr| vis.visit_expr(expr));
}
- ItemKind::Fn(_, sig, generics, body) => {
+ ItemKind::Fn(box FnKind(_, sig, generics, body)) => {
visit_fn_sig(sig, vis);
vis.visit_generics(generics);
visit_opt(body, |body| vis.visit_block(body));
@@ -921,7 +920,7 @@
ItemKind::Mod(m) => vis.visit_mod(m),
ItemKind::ForeignMod(nm) => vis.visit_foreign_mod(nm),
ItemKind::GlobalAsm(_ga) => {}
- ItemKind::TyAlias(_, generics, bounds, ty) => {
+ ItemKind::TyAlias(box TyAliasKind(_, generics, bounds, ty)) => {
vis.visit_generics(generics);
visit_bounds(bounds, vis);
visit_opt(ty, |ty| vis.visit_ty(ty));
@@ -934,7 +933,7 @@
vis.visit_variant_data(variant_data);
vis.visit_generics(generics);
}
- ItemKind::Impl {
+ ItemKind::Impl(box ImplKind {
unsafety: _,
polarity: _,
defaultness: _,
@@ -943,13 +942,13 @@
of_trait,
self_ty,
items,
- } => {
+ }) => {
vis.visit_generics(generics);
visit_opt(of_trait, |trait_ref| vis.visit_trait_ref(trait_ref));
vis.visit_ty(self_ty);
items.flat_map_in_place(|item| vis.flat_map_impl_item(item));
}
- ItemKind::Trait(_is_auto, _unsafety, generics, bounds, items) => {
+ ItemKind::Trait(box TraitKind(.., generics, bounds, items)) => {
vis.visit_generics(generics);
visit_bounds(bounds, vis);
items.flat_map_in_place(|item| vis.flat_map_trait_item(item));
@@ -977,12 +976,12 @@
visitor.visit_ty(ty);
visit_opt(expr, |expr| visitor.visit_expr(expr));
}
- AssocItemKind::Fn(_, sig, generics, body) => {
+ AssocItemKind::Fn(box FnKind(_, sig, generics, body)) => {
visitor.visit_generics(generics);
visit_fn_sig(sig, visitor);
visit_opt(body, |body| visitor.visit_block(body));
}
- AssocItemKind::TyAlias(_, generics, bounds, ty) => {
+ AssocItemKind::TyAlias(box TyAliasKind(_, generics, bounds, ty)) => {
visitor.visit_generics(generics);
visit_bounds(bounds, visitor);
visit_opt(ty, |ty| visitor.visit_ty(ty));
@@ -1067,12 +1066,12 @@
visitor.visit_ty(ty);
visit_opt(expr, |expr| visitor.visit_expr(expr));
}
- ForeignItemKind::Fn(_, sig, generics, body) => {
+ ForeignItemKind::Fn(box FnKind(_, sig, generics, body)) => {
visitor.visit_generics(generics);
visit_fn_sig(sig, visitor);
visit_opt(body, |body| visitor.visit_block(body));
}
- ForeignItemKind::TyAlias(_, generics, bounds, ty) => {
+ ForeignItemKind::TyAlias(box TyAliasKind(_, generics, bounds, ty)) => {
visitor.visit_generics(generics);
visit_bounds(bounds, visitor);
visit_opt(ty, |ty| visitor.visit_ty(ty));
diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs
index a744649..90bfb01 100644
--- a/compiler/rustc_ast/src/token.rs
+++ b/compiler/rustc_ast/src/token.rs
@@ -15,7 +15,7 @@
use rustc_span::source_map::SourceMap;
use rustc_span::symbol::{kw, sym};
use rustc_span::symbol::{Ident, Symbol};
-use rustc_span::{self, FileName, RealFileName, Span, DUMMY_SP};
+use rustc_span::{self, edition::Edition, FileName, RealFileName, Span, DUMMY_SP};
use std::borrow::Cow;
use std::{fmt, mem};
@@ -130,10 +130,7 @@
}
crate fn may_have_suffix(self) -> bool {
- match self {
- Integer | Float | Err => true,
- _ => false,
- }
+ matches!(self, Integer | Float | Err)
}
}
@@ -305,10 +302,7 @@
}
pub fn should_end_const_arg(&self) -> bool {
- match self {
- Gt | Ge | BinOp(Shr) | BinOpEq(Shr) => true,
- _ => false,
- }
+ matches!(self, Gt | Ge | BinOp(Shr) | BinOpEq(Shr))
}
}
@@ -346,18 +340,21 @@
}
pub fn is_op(&self) -> bool {
- match self.kind {
- OpenDelim(..) | CloseDelim(..) | Literal(..) | DocComment(..) | Ident(..)
- | Lifetime(..) | Interpolated(..) | Eof => false,
- _ => true,
- }
+ !matches!(
+ self.kind,
+ OpenDelim(..)
+ | CloseDelim(..)
+ | Literal(..)
+ | DocComment(..)
+ | Ident(..)
+ | Lifetime(..)
+ | Interpolated(..)
+ | Eof
+ )
}
pub fn is_like_plus(&self) -> bool {
- match self.kind {
- BinOp(Plus) | BinOpEq(Plus) => true,
- _ => false,
- }
+ matches!(self.kind, BinOp(Plus) | BinOpEq(Plus))
}
/// Returns `true` if the token can appear at the start of an expression.
@@ -379,13 +376,10 @@
ModSep | // global path
Lifetime(..) | // labeled loop
Pound => true, // expression attributes
- Interpolated(ref nt) => match **nt {
- NtLiteral(..) |
+ Interpolated(ref nt) => matches!(**nt, NtLiteral(..) |
NtExpr(..) |
NtBlock(..) |
- NtPath(..) => true,
- _ => false,
- },
+ NtPath(..)),
_ => false,
}
}
@@ -405,10 +399,7 @@
Lifetime(..) | // lifetime bound in trait object
Lt | BinOp(Shl) | // associated path
ModSep => true, // global path
- Interpolated(ref nt) => match **nt {
- NtTy(..) | NtPath(..) => true,
- _ => false,
- },
+ Interpolated(ref nt) => matches!(**nt, NtTy(..) | NtPath(..)),
_ => false,
}
}
@@ -417,10 +408,7 @@
pub fn can_begin_const_arg(&self) -> bool {
match self.kind {
OpenDelim(Brace) => true,
- Interpolated(ref nt) => match **nt {
- NtExpr(..) | NtBlock(..) | NtLiteral(..) => true,
- _ => false,
- },
+ Interpolated(ref nt) => matches!(**nt, NtExpr(..) | NtBlock(..) | NtLiteral(..)),
_ => self.can_begin_literal_maybe_minus(),
}
}
@@ -436,10 +424,7 @@
/// Returns `true` if the token is any literal.
pub fn is_lit(&self) -> bool {
- match self.kind {
- Literal(..) => true,
- _ => false,
- }
+ matches!(self.kind, Literal(..))
}
/// Returns `true` if the token is any literal, a minus (which can prefix a literal,
@@ -705,7 +690,16 @@
Item,
Block,
Stmt,
- Pat,
+ Pat2018 {
+ /// Keep track of whether the user used `:pat2018` or `:pat` and we inferred it from the
+ /// edition of the span. This is used for diagnostics.
+ inferred: bool,
+ },
+ Pat2021 {
+ /// Keep track of whether the user used `:pat2018` or `:pat` and we inferred it from the
+ /// edition of the span. This is used for diagnostics.
+ inferred: bool,
+ },
Expr,
Ty,
Ident,
@@ -718,12 +712,24 @@
}
impl NonterminalKind {
- pub fn from_symbol(symbol: Symbol) -> Option<NonterminalKind> {
+ /// The `edition` closure is used to get the edition for the given symbol. Doing
+ /// `span.edition()` is expensive, so we do it lazily.
+ pub fn from_symbol(
+ symbol: Symbol,
+ edition: impl FnOnce() -> Edition,
+ ) -> Option<NonterminalKind> {
Some(match symbol {
sym::item => NonterminalKind::Item,
sym::block => NonterminalKind::Block,
sym::stmt => NonterminalKind::Stmt,
- sym::pat => NonterminalKind::Pat,
+ sym::pat => match edition() {
+ Edition::Edition2015 | Edition::Edition2018 => {
+ NonterminalKind::Pat2018 { inferred: true }
+ }
+ Edition::Edition2021 => NonterminalKind::Pat2021 { inferred: true },
+ },
+ sym::pat2018 => NonterminalKind::Pat2018 { inferred: false },
+ sym::pat2021 => NonterminalKind::Pat2021 { inferred: false },
sym::expr => NonterminalKind::Expr,
sym::ty => NonterminalKind::Ty,
sym::ident => NonterminalKind::Ident,
@@ -741,7 +747,10 @@
NonterminalKind::Item => sym::item,
NonterminalKind::Block => sym::block,
NonterminalKind::Stmt => sym::stmt,
- NonterminalKind::Pat => sym::pat,
+ NonterminalKind::Pat2018 { inferred: false } => sym::pat2018,
+ NonterminalKind::Pat2021 { inferred: false } => sym::pat2021,
+ NonterminalKind::Pat2018 { inferred: true }
+ | NonterminalKind::Pat2021 { inferred: true } => sym::pat,
NonterminalKind::Expr => sym::expr,
NonterminalKind::Ty => sym::ty,
NonterminalKind::Ident => sym::ident,
@@ -762,7 +771,7 @@
}
impl Nonterminal {
- fn span(&self) -> Span {
+ pub fn span(&self) -> Span {
match self {
NtItem(item) => item.span,
NtBlock(block) => block.span,
diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs
index b2207f2..9ac05f3 100644
--- a/compiler/rustc_ast/src/tokenstream.rs
+++ b/compiler/rustc_ast/src/tokenstream.rs
@@ -1,15 +1,15 @@
//! # Token Streams
//!
//! `TokenStream`s represent syntactic objects before they are converted into ASTs.
-//! A `TokenStream` is, roughly speaking, a sequence (eg stream) of `TokenTree`s,
-//! which are themselves a single `Token` or a `Delimited` subsequence of tokens.
+//! A `TokenStream` is, roughly speaking, a sequence of [`TokenTree`]s,
+//! which are themselves a single [`Token`] or a `Delimited` subsequence of tokens.
//!
//! ## Ownership
//!
//! `TokenStream`s are persistent data structures constructed as ropes with reference
//! counted-children. In general, this means that calling an operation on a `TokenStream`
//! (such as `slice`) produces an entirely new `TokenStream` from the borrowed reference to
-//! the original. This essentially coerces `TokenStream`s into 'views' of their subparts,
+//! the original. This essentially coerces `TokenStream`s into "views" of their subparts,
//! and a borrowed `TokenStream` is sufficient to build an owned `TokenStream` without taking
//! ownership of the original.
@@ -24,9 +24,9 @@
use std::{fmt, iter, mem};
-/// When the main rust parser encounters a syntax-extension invocation, it
-/// parses the arguments to the invocation as a token-tree. This is a very
-/// loose structure, such that all sorts of different AST-fragments can
+/// When the main Rust parser encounters a syntax-extension invocation, it
+/// parses the arguments to the invocation as a token tree. This is a very
+/// loose structure, such that all sorts of different AST fragments can
/// be passed to syntax extensions using a uniform type.
///
/// If the syntax extension is an MBE macro, it will attempt to match its
@@ -38,12 +38,18 @@
/// Nothing special happens to misnamed or misplaced `SubstNt`s.
#[derive(Debug, Clone, PartialEq, Encodable, Decodable, HashStable_Generic)]
pub enum TokenTree {
- /// A single token
+ /// A single token.
Token(Token),
- /// A delimited sequence of token trees
+ /// A delimited sequence of token trees.
Delimited(DelimSpan, DelimToken, TokenStream),
}
+#[derive(Copy, Clone)]
+pub enum CanSynthesizeMissingTokens {
+ Yes,
+ No,
+}
+
// Ensure all fields of `TokenTree` is `Send` and `Sync`.
#[cfg(parallel_compiler)]
fn _dummy()
@@ -56,7 +62,7 @@
}
impl TokenTree {
- /// Checks if this TokenTree is equal to the other, regardless of span information.
+ /// Checks if this `TokenTree` is equal to the other, regardless of span information.
pub fn eq_unspanned(&self, other: &TokenTree) -> bool {
match (self, other) {
(TokenTree::Token(token), TokenTree::Token(token2)) => token.kind == token2.kind,
@@ -67,7 +73,7 @@
}
}
- /// Retrieves the TokenTree's span.
+ /// Retrieves the `TokenTree`'s span.
pub fn span(&self) -> Span {
match self {
TokenTree::Token(token) => token.span,
@@ -121,20 +127,16 @@
}
pub trait CreateTokenStream: sync::Send + sync::Sync {
- fn add_trailing_semi(&self) -> Box<dyn CreateTokenStream>;
fn create_token_stream(&self) -> TokenStream;
}
impl CreateTokenStream for TokenStream {
- fn add_trailing_semi(&self) -> Box<dyn CreateTokenStream> {
- panic!("Cannot call `add_trailing_semi` on a `TokenStream`!");
- }
fn create_token_stream(&self) -> TokenStream {
self.clone()
}
}
-/// A lazy version of `TokenStream`, which defers creation
+/// A lazy version of [`TokenStream`], which defers creation
/// of an actual `TokenStream` until it is needed.
/// `Box` is here only to reduce the structure size.
#[derive(Clone)]
@@ -145,13 +147,6 @@
LazyTokenStream(Lrc::new(Box::new(inner)))
}
- /// Extends the captured stream by one token,
- /// which must be a trailing semicolon. This
- /// affects the `TokenStream` created by `make_tokenstream`.
- pub fn add_trailing_semi(&self) -> LazyTokenStream {
- LazyTokenStream(Lrc::new(self.0.add_trailing_semi()))
- }
-
pub fn create_token_stream(&self) -> TokenStream {
self.0.create_token_stream()
}
@@ -182,11 +177,12 @@
}
}
-/// A `TokenStream` is an abstract sequence of tokens, organized into `TokenTree`s.
+/// A `TokenStream` is an abstract sequence of tokens, organized into [`TokenTree`]s.
///
/// The goal is for procedural macros to work with `TokenStream`s and `TokenTree`s
/// instead of a representation of the abstract syntax tree.
-/// Today's `TokenTree`s can still contain AST via `token::Interpolated` for back-compat.
+/// Today's `TokenTree`s can still contain AST via `token::Interpolated` for
+/// backwards compatability.
#[derive(Clone, Debug, Default, Encodable, Decodable)]
pub struct TokenStream(pub(crate) Lrc<Vec<TreeAndSpacing>>);
@@ -423,7 +419,7 @@
}
}
-/// By-reference iterator over a `TokenStream`.
+/// By-reference iterator over a [`TokenStream`].
#[derive(Clone)]
pub struct CursorRef<'t> {
stream: &'t TokenStream,
@@ -451,8 +447,8 @@
}
}
-/// Owning by-value iterator over a `TokenStream`.
-/// FIXME: Many uses of this can be replaced with by-reference iterator to avoid clones.
+/// Owning by-value iterator over a [`TokenStream`].
+// FIXME: Many uses of this can be replaced with by-reference iterator to avoid clones.
#[derive(Clone)]
pub struct Cursor {
pub stream: TokenStream,
diff --git a/compiler/rustc_ast/src/util/classify.rs b/compiler/rustc_ast/src/util/classify.rs
index 60422a2..9078652 100644
--- a/compiler/rustc_ast/src/util/classify.rs
+++ b/compiler/rustc_ast/src/util/classify.rs
@@ -12,14 +12,14 @@
/// |x| 5
/// isn't parsed as (if true {...} else {...} | x) | 5
pub fn expr_requires_semi_to_be_stmt(e: &ast::Expr) -> bool {
- match e.kind {
+ !matches!(
+ e.kind,
ast::ExprKind::If(..)
- | ast::ExprKind::Match(..)
- | ast::ExprKind::Block(..)
- | ast::ExprKind::While(..)
- | ast::ExprKind::Loop(..)
- | ast::ExprKind::ForLoop(..)
- | ast::ExprKind::TryBlock(..) => false,
- _ => true,
- }
+ | ast::ExprKind::Match(..)
+ | ast::ExprKind::Block(..)
+ | ast::ExprKind::While(..)
+ | ast::ExprKind::Loop(..)
+ | ast::ExprKind::ForLoop(..)
+ | ast::ExprKind::TryBlock(..)
+ )
}
diff --git a/compiler/rustc_ast/src/util/comments.rs b/compiler/rustc_ast/src/util/comments.rs
index 5d994c9..542a330 100644
--- a/compiler/rustc_ast/src/util/comments.rs
+++ b/compiler/rustc_ast/src/util/comments.rs
@@ -180,10 +180,8 @@
}
rustc_lexer::TokenKind::BlockComment { doc_style, .. } => {
if doc_style.is_none() {
- let code_to_the_right = match text[pos + token.len..].chars().next() {
- Some('\r' | '\n') => false,
- _ => true,
- };
+ let code_to_the_right =
+ !matches!(text[pos + token.len..].chars().next(), Some('\r' | '\n'));
let style = match (code_to_the_left, code_to_the_right) {
(_, true) => CommentStyle::Mixed,
(false, false) => CommentStyle::Isolated,
diff --git a/compiler/rustc_ast/src/util/literal.rs b/compiler/rustc_ast/src/util/literal.rs
index f6f1ad0..2124f1e 100644
--- a/compiler/rustc_ast/src/util/literal.rs
+++ b/compiler/rustc_ast/src/util/literal.rs
@@ -2,7 +2,6 @@
use crate::ast::{self, Lit, LitKind};
use crate::token::{self, Token};
-use crate::tokenstream::TokenTree;
use rustc_lexer::unescape::{unescape_byte, unescape_char};
use rustc_lexer::unescape::{unescape_byte_literal, unescape_literal, Mode};
@@ -88,7 +87,6 @@
}
});
error?;
- buf.shrink_to_fit();
Symbol::intern(&buf)
} else {
symbol
@@ -106,7 +104,6 @@
}
});
error?;
- buf.shrink_to_fit();
LitKind::ByteStr(buf.into())
}
token::ByteStrRaw(_) => {
@@ -121,7 +118,6 @@
}
});
error?;
- buf.shrink_to_fit();
buf
} else {
symbol.to_string().into_bytes()
@@ -225,13 +221,13 @@
Lit { token: kind.to_lit_token(), kind, span }
}
- /// Losslessly convert an AST literal into a token stream.
- pub fn token_tree(&self) -> TokenTree {
- let token = match self.token.kind {
+ /// Losslessly convert an AST literal into a token.
+ pub fn to_token(&self) -> Token {
+ let kind = match self.token.kind {
token::Bool => token::Ident(self.token.symbol, false),
_ => token::Literal(self.token),
};
- TokenTree::token(token, self.span)
+ Token::new(kind, self.span)
}
}
diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs
index a420bb5..c37d4cd 100644
--- a/compiler/rustc_ast/src/visit.rs
+++ b/compiler/rustc_ast/src/visit.rs
@@ -15,7 +15,6 @@
use crate::ast::*;
use crate::token;
-use crate::tokenstream::TokenTree;
use rustc_span::symbol::{Ident, Symbol};
use rustc_span::Span;
@@ -293,7 +292,7 @@
visitor.visit_ty(typ);
walk_list!(visitor, visit_expr, expr);
}
- ItemKind::Fn(_, ref sig, ref generics, ref body) => {
+ ItemKind::Fn(box FnKind(_, ref sig, ref generics, ref body)) => {
visitor.visit_generics(generics);
let kind = FnKind::Fn(FnCtxt::Free, item.ident, sig, &item.vis, body.as_deref());
visitor.visit_fn(kind, item.span, item.id)
@@ -303,7 +302,7 @@
walk_list!(visitor, visit_foreign_item, &foreign_module.items);
}
ItemKind::GlobalAsm(ref ga) => visitor.visit_global_asm(ga),
- ItemKind::TyAlias(_, ref generics, ref bounds, ref ty) => {
+ ItemKind::TyAlias(box TyAliasKind(_, ref generics, ref bounds, ref ty)) => {
visitor.visit_generics(generics);
walk_list!(visitor, visit_param_bound, bounds);
walk_list!(visitor, visit_ty, ty);
@@ -312,7 +311,7 @@
visitor.visit_generics(generics);
visitor.visit_enum_def(enum_definition, generics, item.id, item.span)
}
- ItemKind::Impl {
+ ItemKind::Impl(box ImplKind {
unsafety: _,
polarity: _,
defaultness: _,
@@ -321,7 +320,7 @@
ref of_trait,
ref self_ty,
ref items,
- } => {
+ }) => {
visitor.visit_generics(generics);
walk_list!(visitor, visit_trait_ref, of_trait);
visitor.visit_ty(self_ty);
@@ -332,7 +331,7 @@
visitor.visit_generics(generics);
visitor.visit_variant_data(struct_definition);
}
- ItemKind::Trait(.., ref generics, ref bounds, ref items) => {
+ ItemKind::Trait(box TraitKind(.., ref generics, ref bounds, ref items)) => {
visitor.visit_generics(generics);
walk_list!(visitor, visit_param_bound, bounds);
walk_list!(visitor, visit_assoc_item, items, AssocCtxt::Trait);
@@ -544,12 +543,12 @@
visitor.visit_ty(ty);
walk_list!(visitor, visit_expr, expr);
}
- ForeignItemKind::Fn(_, sig, generics, body) => {
+ ForeignItemKind::Fn(box FnKind(_, sig, generics, body)) => {
visitor.visit_generics(generics);
let kind = FnKind::Fn(FnCtxt::Foreign, ident, sig, vis, body.as_deref());
visitor.visit_fn(kind, span, id);
}
- ForeignItemKind::TyAlias(_, generics, bounds, ty) => {
+ ForeignItemKind::TyAlias(box TyAliasKind(_, generics, bounds, ty)) => {
visitor.visit_generics(generics);
walk_list!(visitor, visit_param_bound, bounds);
walk_list!(visitor, visit_ty, ty);
@@ -578,7 +577,12 @@
match param.kind {
GenericParamKind::Lifetime => (),
GenericParamKind::Type { ref default } => walk_list!(visitor, visit_ty, default),
- GenericParamKind::Const { ref ty, .. } => visitor.visit_ty(ty),
+ GenericParamKind::Const { ref ty, ref default, .. } => {
+ visitor.visit_ty(ty);
+ if let Some(default) = default {
+ visitor.visit_anon_const(default);
+ }
+ }
}
}
@@ -649,12 +653,12 @@
visitor.visit_ty(ty);
walk_list!(visitor, visit_expr, expr);
}
- AssocItemKind::Fn(_, sig, generics, body) => {
+ AssocItemKind::Fn(box FnKind(_, sig, generics, body)) => {
visitor.visit_generics(generics);
let kind = FnKind::Fn(FnCtxt::Assoc(ctxt), ident, sig, vis, body.as_deref());
visitor.visit_fn(kind, span, id);
}
- AssocItemKind::TyAlias(_, generics, bounds, ty) => {
+ AssocItemKind::TyAlias(box TyAliasKind(_, generics, bounds, ty)) => {
visitor.visit_generics(generics);
walk_list!(visitor, visit_param_bound, bounds);
walk_list!(visitor, visit_ty, ty);
@@ -900,12 +904,9 @@
MacArgs::Delimited(_dspan, _delim, _tokens) => {}
// The value in `#[key = VALUE]` must be visited as an expression for backward
// compatibility, so that macros can be expanded in that position.
- MacArgs::Eq(_eq_span, tokens) => match tokens.trees_ref().next() {
- Some(TokenTree::Token(token)) => match &token.kind {
- token::Interpolated(nt) => match &**nt {
- token::NtExpr(expr) => visitor.visit_expr(expr),
- t => panic!("unexpected token in key-value attribute: {:?}", t),
- },
+ MacArgs::Eq(_eq_span, token) => match &token.kind {
+ token::Interpolated(nt) => match &**nt {
+ token::NtExpr(expr) => visitor.visit_expr(expr),
t => panic!("unexpected token in key-value attribute: {:?}", t),
},
t => panic!("unexpected token in key-value attribute: {:?}", t),
diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs
index 9b1642d..4d6afd2 100644
--- a/compiler/rustc_ast_lowering/src/expr.rs
+++ b/compiler/rustc_ast_lowering/src/expr.rs
@@ -10,9 +10,9 @@
use rustc_hir as hir;
use rustc_hir::def::Res;
use rustc_session::parse::feature_err;
-use rustc_span::hygiene::ForLoopLoc;
use rustc_span::source_map::{respan, DesugaringKind, Span, Spanned};
use rustc_span::symbol::{sym, Ident, Symbol};
+use rustc_span::{hygiene::ForLoopLoc, DUMMY_SP};
use rustc_target::asm;
use std::collections::hash_map::Entry;
use std::fmt::Write;
@@ -87,9 +87,12 @@
ExprKind::Let(ref pat, ref scrutinee) => {
self.lower_expr_let(e.span, pat, scrutinee)
}
- ExprKind::If(ref cond, ref then, ref else_opt) => {
- self.lower_expr_if(e.span, cond, then, else_opt.as_deref())
- }
+ ExprKind::If(ref cond, ref then, ref else_opt) => match cond.kind {
+ ExprKind::Let(ref pat, ref scrutinee) => {
+ self.lower_expr_if_let(e.span, pat, scrutinee, then, else_opt.as_deref())
+ }
+ _ => self.lower_expr_if(cond, then, else_opt.as_deref()),
+ },
ExprKind::While(ref cond, ref body, opt_label) => self
.with_loop_scope(e.id, |this| {
this.lower_expr_while_in_loop_scope(e.span, cond, body, opt_label)
@@ -99,6 +102,7 @@
this.lower_block(body, false),
opt_label,
hir::LoopSource::Loop,
+ DUMMY_SP,
)
}),
ExprKind::TryBlock(ref body) => self.lower_expr_try_block(body),
@@ -337,11 +341,31 @@
fn lower_expr_if(
&mut self,
- span: Span,
cond: &Expr,
then: &Block,
else_opt: Option<&Expr>,
) -> hir::ExprKind<'hir> {
+ macro_rules! make_if {
+ ($opt:expr) => {{
+ let then_expr = self.lower_block_expr(then);
+ hir::ExprKind::If(self.lower_expr(cond), self.arena.alloc(then_expr), $opt)
+ }};
+ }
+ if let Some(rslt) = else_opt {
+ make_if!(Some(self.lower_expr(rslt)))
+ } else {
+ make_if!(None)
+ }
+ }
+
+ fn lower_expr_if_let(
+ &mut self,
+ span: Span,
+ pat: &Pat,
+ scrutinee: &Expr,
+ then: &Block,
+ else_opt: Option<&Expr>,
+ ) -> hir::ExprKind<'hir> {
// FIXME(#53667): handle lowering of && and parens.
// `_ => else_block` where `else_block` is `{}` if there's `None`:
@@ -353,30 +377,13 @@
let else_arm = self.arm(else_pat, else_expr);
// Handle then + scrutinee:
- let (then_pat, scrutinee, desugar) = match cond.kind {
- // `<pat> => <then>`:
- ExprKind::Let(ref pat, ref scrutinee) => {
- let scrutinee = self.lower_expr(scrutinee);
- let pat = self.lower_pat(pat);
- (pat, scrutinee, hir::MatchSource::IfLetDesugar { contains_else_clause })
- }
- // `true => <then>`:
- _ => {
- // Lower condition:
- let cond = self.lower_expr(cond);
- let span_block =
- self.mark_span_with_reason(DesugaringKind::CondTemporary, cond.span, None);
- // Wrap in a construct equivalent to `{ let _t = $cond; _t }`
- // to preserve drop semantics since `if cond { ... }` does not
- // let temporaries live outside of `cond`.
- let cond = self.expr_drop_temps(span_block, cond, ThinVec::new());
- let pat = self.pat_bool(span, true);
- (pat, cond, hir::MatchSource::IfDesugar { contains_else_clause })
- }
- };
+ let scrutinee = self.lower_expr(scrutinee);
+ let then_pat = self.lower_pat(pat);
+
let then_expr = self.lower_block_expr(then);
let then_arm = self.arm(then_pat, self.arena.alloc(then_expr));
+ let desugar = hir::MatchSource::IfLetDesugar { contains_else_clause };
hir::ExprKind::Match(scrutinee, arena_vec![self; then_arm, else_arm], desugar)
}
@@ -447,7 +454,12 @@
self.expr_match(span, scrutinee, arena_vec![self; then_arm, else_arm], desugar);
// `[opt_ident]: loop { ... }`
- hir::ExprKind::Loop(self.block_expr(self.arena.alloc(match_expr)), opt_label, source)
+ hir::ExprKind::Loop(
+ self.block_expr(self.arena.alloc(match_expr)),
+ opt_label,
+ source,
+ span.with_hi(cond.span.hi()),
+ )
}
/// Desugar `try { <stmts>; <expr> }` into `{ <stmts>; ::std::ops::Try::from_ok(<expr>) }`,
@@ -742,7 +754,7 @@
// loop { .. }
let loop_expr = self.arena.alloc(hir::Expr {
hir_id: loop_hir_id,
- kind: hir::ExprKind::Loop(loop_block, None, hir::LoopSource::Loop),
+ kind: hir::ExprKind::Loop(loop_block, None, hir::LoopSource::Loop, span),
span,
attrs: ThinVec::new(),
});
@@ -764,10 +776,7 @@
body: &Expr,
fn_decl_span: Span,
) -> hir::ExprKind<'hir> {
- // Lower outside new scope to preserve `is_in_loop_condition`.
- let fn_decl = self.lower_fn_decl(decl, None, false, None);
-
- self.with_new_scopes(move |this| {
+ let (body_id, generator_option) = self.with_new_scopes(move |this| {
let prev = this.current_item;
this.current_item = Some(fn_decl_span);
let mut generator_kind = None;
@@ -779,8 +788,13 @@
let generator_option =
this.generator_movability_for_fn(&decl, fn_decl_span, generator_kind, movability);
this.current_item = prev;
- hir::ExprKind::Closure(capture_clause, fn_decl, body_id, fn_decl_span, generator_option)
- })
+ (body_id, generator_option)
+ });
+
+ // Lower outside new scope to preserve `is_in_loop_condition`.
+ let fn_decl = self.lower_fn_decl(decl, None, false, None);
+
+ hir::ExprKind::Closure(capture_clause, fn_decl, body_id, fn_decl_span, generator_option)
}
fn generator_movability_for_fn(
@@ -826,12 +840,8 @@
) -> hir::ExprKind<'hir> {
let outer_decl =
FnDecl { inputs: decl.inputs.clone(), output: FnRetTy::Default(fn_decl_span) };
- // We need to lower the declaration outside the new scope, because we
- // have to conserve the state of being inside a loop condition for the
- // closure argument types.
- let fn_decl = self.lower_fn_decl(&outer_decl, None, false, None);
- self.with_new_scopes(move |this| {
+ let body_id = self.with_new_scopes(|this| {
// FIXME(cramertj): allow `async` non-`move` closures with arguments.
if capture_clause == CaptureBy::Ref && !decl.inputs.is_empty() {
struct_span_err!(
@@ -862,8 +872,15 @@
);
this.expr(fn_decl_span, async_body, ThinVec::new())
});
- hir::ExprKind::Closure(capture_clause, fn_decl, body_id, fn_decl_span, None)
- })
+ body_id
+ });
+
+ // We need to lower the declaration outside the new scope, because we
+ // have to conserve the state of being inside a loop condition for the
+ // closure argument types.
+ let fn_decl = self.lower_fn_decl(&outer_decl, None, false, None);
+
+ hir::ExprKind::Closure(capture_clause, fn_decl, body_id, fn_decl_span, None)
}
/// Destructure the LHS of complex assignments.
@@ -1703,7 +1720,12 @@
);
// `[opt_ident]: loop { ... }`
- let kind = hir::ExprKind::Loop(loop_block, opt_label, hir::LoopSource::ForLoop);
+ let kind = hir::ExprKind::Loop(
+ loop_block,
+ opt_label,
+ hir::LoopSource::ForLoop,
+ e.span.with_hi(orig_head_span.hi()),
+ );
let loop_expr = self.arena.alloc(hir::Expr {
hir_id: self.lower_node_id(e.id),
kind,
diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs
index eef6d38..1efe83c 100644
--- a/compiler/rustc_ast_lowering/src/item.rs
+++ b/compiler/rustc_ast_lowering/src/item.rs
@@ -67,7 +67,7 @@
if let Some(hir_id) = item_hir_id {
self.lctx.with_parent_item_lifetime_defs(hir_id, |this| {
let this = &mut ItemLowerer { lctx: this };
- if let ItemKind::Impl { ref of_trait, .. } = item.kind {
+ if let ItemKind::Impl(box ImplKind { ref of_trait, .. }) = item.kind {
this.with_trait_impl_ref(of_trait, |this| visit::walk_item(this, item));
} else {
visit::walk_item(this, item);
@@ -134,7 +134,7 @@
let old_len = self.in_scope_lifetimes.len();
let parent_generics = match self.items.get(&parent_hir_id).unwrap().kind {
- hir::ItemKind::Impl { ref generics, .. }
+ hir::ItemKind::Impl(hir::Impl { ref generics, .. })
| hir::ItemKind::Trait(_, _, ref generics, ..) => &generics.params[..],
_ => &[],
};
@@ -189,7 +189,9 @@
vec
}
ItemKind::MacroDef(..) => SmallVec::new(),
- ItemKind::Fn(..) | ItemKind::Impl { of_trait: None, .. } => smallvec![i.id],
+ ItemKind::Fn(..) | ItemKind::Impl(box ImplKind { of_trait: None, .. }) => {
+ smallvec![i.id]
+ }
_ => smallvec![i.id],
};
@@ -276,12 +278,12 @@
let (ty, body_id) = self.lower_const_item(t, span, e.as_deref());
hir::ItemKind::Const(ty, body_id)
}
- ItemKind::Fn(
+ ItemKind::Fn(box FnKind(
_,
FnSig { ref decl, header, span: fn_sig_span },
ref generics,
ref body,
- ) => {
+ )) => {
let fn_def_id = self.resolver.local_def_id(id);
self.with_new_scopes(|this| {
this.current_item = Some(ident.span);
@@ -310,21 +312,26 @@
);
let sig = hir::FnSig {
decl,
- header: this.lower_fn_header(header),
+ header: this.lower_fn_header(header, fn_sig_span, id),
span: fn_sig_span,
};
hir::ItemKind::Fn(sig, generics, body_id)
})
}
ItemKind::Mod(ref m) => hir::ItemKind::Mod(self.lower_mod(m)),
- ItemKind::ForeignMod(ref fm) => hir::ItemKind::ForeignMod {
- abi: fm.abi.map_or(abi::Abi::C, |abi| self.lower_abi(abi)),
- items: self
- .arena
- .alloc_from_iter(fm.items.iter().map(|x| self.lower_foreign_item_ref(x))),
- },
+ ItemKind::ForeignMod(ref fm) => {
+ if fm.abi.is_none() {
+ self.maybe_lint_missing_abi(span, id, abi::Abi::C);
+ }
+ hir::ItemKind::ForeignMod {
+ abi: fm.abi.map_or(abi::Abi::C, |abi| self.lower_abi(abi)),
+ items: self
+ .arena
+ .alloc_from_iter(fm.items.iter().map(|x| self.lower_foreign_item_ref(x))),
+ }
+ }
ItemKind::GlobalAsm(ref ga) => hir::ItemKind::GlobalAsm(self.lower_global_asm(ga)),
- ItemKind::TyAlias(_, ref gen, _, Some(ref ty)) => {
+ ItemKind::TyAlias(box TyAliasKind(_, ref gen, _, Some(ref ty))) => {
// We lower
//
// type Foo = impl Trait
@@ -343,7 +350,7 @@
let generics = self.lower_generics(gen, ImplTraitContext::disallowed());
hir::ItemKind::TyAlias(ty, generics)
}
- ItemKind::TyAlias(_, ref generics, _, None) => {
+ ItemKind::TyAlias(box TyAliasKind(_, ref generics, _, None)) => {
let ty = self.arena.alloc(self.ty(span, hir::TyKind::Err));
let generics = self.lower_generics(generics, ImplTraitContext::disallowed());
hir::ItemKind::TyAlias(ty, generics)
@@ -370,7 +377,7 @@
self.lower_generics(generics, ImplTraitContext::disallowed()),
)
}
- ItemKind::Impl {
+ ItemKind::Impl(box ImplKind {
unsafety,
polarity,
defaultness,
@@ -379,7 +386,7 @@
of_trait: ref trait_ref,
self_ty: ref ty,
items: ref impl_items,
- } => {
+ }) => {
let def_id = self.resolver.local_def_id(id);
// Lower the "impl header" first. This ordering is important
@@ -431,7 +438,7 @@
// to not cause an assertion failure inside the `lower_defaultness` function.
let has_val = true;
let (defaultness, defaultness_span) = self.lower_defaultness(defaultness, has_val);
- hir::ItemKind::Impl {
+ hir::ItemKind::Impl(hir::Impl {
unsafety: self.lower_unsafety(unsafety),
polarity,
defaultness,
@@ -441,9 +448,15 @@
of_trait: trait_ref,
self_ty: lowered_ty,
items: new_impl_items,
- }
+ })
}
- ItemKind::Trait(is_auto, unsafety, ref generics, ref bounds, ref items) => {
+ ItemKind::Trait(box TraitKind(
+ is_auto,
+ unsafety,
+ ref generics,
+ ref bounds,
+ ref items,
+ )) => {
let bounds = self.lower_param_bounds(bounds, ImplTraitContext::disallowed());
let items = self
.arena
@@ -693,7 +706,7 @@
ident: i.ident,
attrs: self.lower_attrs(&i.attrs),
kind: match i.kind {
- ForeignItemKind::Fn(_, ref sig, ref generics, _) => {
+ ForeignItemKind::Fn(box FnKind(_, ref sig, ref generics, _)) => {
let fdec = &sig.decl;
let (generics, (fn_dec, fn_args)) = self.add_in_band_defs(
generics,
@@ -798,19 +811,19 @@
let body = default.as_ref().map(|x| self.lower_const_body(i.span, Some(x)));
(hir::Generics::empty(), hir::TraitItemKind::Const(ty, body))
}
- AssocItemKind::Fn(_, ref sig, ref generics, None) => {
+ AssocItemKind::Fn(box FnKind(_, ref sig, ref generics, None)) => {
let names = self.lower_fn_params_to_names(&sig.decl);
let (generics, sig) =
- self.lower_method_sig(generics, sig, trait_item_def_id, false, None);
+ self.lower_method_sig(generics, sig, trait_item_def_id, false, None, i.id);
(generics, hir::TraitItemKind::Fn(sig, hir::TraitFn::Required(names)))
}
- AssocItemKind::Fn(_, ref sig, ref generics, Some(ref body)) => {
+ AssocItemKind::Fn(box FnKind(_, ref sig, ref generics, Some(ref body))) => {
let body_id = self.lower_fn_body_block(i.span, &sig.decl, Some(body));
let (generics, sig) =
- self.lower_method_sig(generics, sig, trait_item_def_id, false, None);
+ self.lower_method_sig(generics, sig, trait_item_def_id, false, None, i.id);
(generics, hir::TraitItemKind::Fn(sig, hir::TraitFn::Provided(body_id)))
}
- AssocItemKind::TyAlias(_, ref generics, ref bounds, ref default) => {
+ AssocItemKind::TyAlias(box TyAliasKind(_, ref generics, ref bounds, ref default)) => {
let ty = default.as_ref().map(|x| self.lower_ty(x, ImplTraitContext::disallowed()));
let generics = self.lower_generics(generics, ImplTraitContext::disallowed());
let kind = hir::TraitItemKind::Type(
@@ -836,10 +849,10 @@
fn lower_trait_item_ref(&mut self, i: &AssocItem) -> hir::TraitItemRef {
let (kind, has_default) = match &i.kind {
AssocItemKind::Const(_, _, default) => (hir::AssocItemKind::Const, default.is_some()),
- AssocItemKind::TyAlias(_, _, _, default) => {
+ AssocItemKind::TyAlias(box TyAliasKind(_, _, _, default)) => {
(hir::AssocItemKind::Type, default.is_some())
}
- AssocItemKind::Fn(_, sig, _, default) => {
+ AssocItemKind::Fn(box FnKind(_, sig, _, default)) => {
(hir::AssocItemKind::Fn { has_self: sig.decl.has_self() }, default.is_some())
}
AssocItemKind::MacCall(..) => unimplemented!(),
@@ -865,7 +878,7 @@
hir::ImplItemKind::Const(ty, self.lower_const_body(i.span, expr.as_deref())),
)
}
- AssocItemKind::Fn(_, sig, generics, body) => {
+ AssocItemKind::Fn(box FnKind(_, sig, generics, body)) => {
self.current_item = Some(i.span);
let asyncness = sig.header.asyncness;
let body_id =
@@ -877,11 +890,12 @@
impl_item_def_id,
impl_trait_return_allow,
asyncness.opt_return_id(),
+ i.id,
);
(generics, hir::ImplItemKind::Fn(sig, body_id))
}
- AssocItemKind::TyAlias(_, generics, _, ty) => {
+ AssocItemKind::TyAlias(box TyAliasKind(_, generics, _, ty)) => {
let generics = self.lower_generics(generics, ImplTraitContext::disallowed());
let kind = match ty {
None => {
@@ -932,7 +946,7 @@
kind: match &i.kind {
AssocItemKind::Const(..) => hir::AssocItemKind::Const,
AssocItemKind::TyAlias(..) => hir::AssocItemKind::Type,
- AssocItemKind::Fn(_, sig, ..) => {
+ AssocItemKind::Fn(box FnKind(_, sig, ..)) => {
hir::AssocItemKind::Fn { has_self: sig.decl.has_self() }
}
AssocItemKind::MacCall(..) => unimplemented!(),
@@ -1270,8 +1284,9 @@
fn_def_id: LocalDefId,
impl_trait_return_allow: bool,
is_async: Option<NodeId>,
+ id: NodeId,
) -> (hir::Generics<'hir>, hir::FnSig<'hir>) {
- let header = self.lower_fn_header(sig.header);
+ let header = self.lower_fn_header(sig.header, sig.span, id);
let (generics, decl) = self.add_in_band_defs(
generics,
fn_def_id,
@@ -1288,12 +1303,12 @@
(generics, hir::FnSig { header, decl, span: sig.span })
}
- fn lower_fn_header(&mut self, h: FnHeader) -> hir::FnHeader {
+ fn lower_fn_header(&mut self, h: FnHeader, span: Span, id: NodeId) -> hir::FnHeader {
hir::FnHeader {
unsafety: self.lower_unsafety(h.unsafety),
asyncness: self.lower_asyncness(h.asyncness),
constness: self.lower_constness(h.constness),
- abi: self.lower_extern(h.ext),
+ abi: self.lower_extern(h.ext, span, id),
}
}
@@ -1304,10 +1319,13 @@
})
}
- pub(super) fn lower_extern(&mut self, ext: Extern) -> abi::Abi {
+ pub(super) fn lower_extern(&mut self, ext: Extern, span: Span, id: NodeId) -> abi::Abi {
match ext {
Extern::None => abi::Abi::Rust,
- Extern::Implicit => abi::Abi::C,
+ Extern::Implicit => {
+ self.maybe_lint_missing_abi(span, id, abi::Abi::C);
+ abi::Abi::C
+ }
Extern::Explicit(abi) => self.lower_abi(abi),
}
}
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index 2e1b5a7..f076dca 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -30,14 +30,14 @@
//! get confused if the spans from leaf AST nodes occur in multiple places
//! in the HIR, especially for multiple identifiers.
-#![feature(array_value_iter)]
#![feature(crate_visibility_modifier)]
#![feature(or_patterns)]
+#![feature(box_patterns)]
#![recursion_limit = "256"]
use rustc_ast::node_id::NodeMap;
use rustc_ast::token::{self, DelimToken, Nonterminal, Token};
-use rustc_ast::tokenstream::{DelimSpan, TokenStream, TokenTree};
+use rustc_ast::tokenstream::{CanSynthesizeMissingTokens, DelimSpan, TokenStream, TokenTree};
use rustc_ast::visit::{self, AssocCtxt, Visitor};
use rustc_ast::walk_list;
use rustc_ast::{self as ast, *};
@@ -53,13 +53,15 @@
use rustc_hir::intravisit;
use rustc_hir::{ConstArg, GenericArg, ParamName};
use rustc_index::vec::{Idx, IndexVec};
-use rustc_session::lint::{builtin::BARE_TRAIT_OBJECTS, BuiltinLintDiagnostics, LintBuffer};
+use rustc_session::lint::builtin::{BARE_TRAIT_OBJECTS, MISSING_ABI};
+use rustc_session::lint::{BuiltinLintDiagnostics, LintBuffer};
use rustc_session::parse::ParseSess;
use rustc_session::Session;
use rustc_span::hygiene::ExpnId;
-use rustc_span::source_map::{respan, DesugaringKind, ExpnData, ExpnKind};
+use rustc_span::source_map::{respan, DesugaringKind};
use rustc_span::symbol::{kw, sym, Ident, Symbol};
use rustc_span::Span;
+use rustc_target::spec::abi::Abi;
use smallvec::{smallvec, SmallVec};
use std::collections::BTreeMap;
@@ -206,7 +208,7 @@
) -> LocalDefId;
}
-type NtToTokenstream = fn(&Nonterminal, &ParseSess, Span) -> TokenStream;
+type NtToTokenstream = fn(&Nonterminal, &ParseSess, CanSynthesizeMissingTokens) -> TokenStream;
/// Context of `impl Trait` in code, which determines whether it is allowed in an HIR subtree,
/// and if so, what meaning it has.
@@ -393,6 +395,42 @@
PassThrough,
}
+struct TokenStreamLowering<'a> {
+ parse_sess: &'a ParseSess,
+ synthesize_tokens: CanSynthesizeMissingTokens,
+ nt_to_tokenstream: NtToTokenstream,
+}
+
+impl<'a> TokenStreamLowering<'a> {
+ fn lower_token_stream(&mut self, tokens: TokenStream) -> TokenStream {
+ tokens.into_trees().flat_map(|tree| self.lower_token_tree(tree).into_trees()).collect()
+ }
+
+ fn lower_token_tree(&mut self, tree: TokenTree) -> TokenStream {
+ match tree {
+ TokenTree::Token(token) => self.lower_token(token),
+ TokenTree::Delimited(span, delim, tts) => {
+ TokenTree::Delimited(span, delim, self.lower_token_stream(tts)).into()
+ }
+ }
+ }
+
+ fn lower_token(&mut self, token: Token) -> TokenStream {
+ match token.kind {
+ token::Interpolated(nt) => {
+ let tts = (self.nt_to_tokenstream)(&nt, self.parse_sess, self.synthesize_tokens);
+ TokenTree::Delimited(
+ DelimSpan::from_single(token.span),
+ DelimToken::NoDelim,
+ self.lower_token_stream(tts),
+ )
+ .into()
+ }
+ _ => TokenTree::Token(token).into(),
+ }
+ }
+}
+
struct ImplTraitTypeIdVisitor<'a> {
ids: &'a mut SmallVec<[NodeId; 1]>,
}
@@ -463,13 +501,15 @@
ItemKind::Struct(_, ref generics)
| ItemKind::Union(_, ref generics)
| ItemKind::Enum(_, ref generics)
- | ItemKind::TyAlias(_, ref generics, ..)
- | ItemKind::Trait(_, _, ref generics, ..) => {
+ | ItemKind::TyAlias(box TyAliasKind(_, ref generics, ..))
+ | ItemKind::Trait(box TraitKind(_, _, ref generics, ..)) => {
let def_id = self.lctx.resolver.local_def_id(item.id);
let count = generics
.params
.iter()
- .filter(|param| matches!(param.kind, ast::GenericParamKind::Lifetime { .. }))
+ .filter(|param| {
+ matches!(param.kind, ast::GenericParamKind::Lifetime { .. })
+ })
.count();
self.lctx.type_def_lifetime_params.insert(def_id.to_def_id(), count);
}
@@ -701,10 +741,7 @@
span: Span,
allow_internal_unstable: Option<Lrc<[Symbol]>>,
) -> Span {
- span.fresh_expansion(ExpnData {
- allow_internal_unstable,
- ..ExpnData::default(ExpnKind::Desugaring(reason), span, self.sess.edition(), None)
- })
+ span.mark_with_reason(allow_internal_unstable, reason, self.sess.edition())
}
fn with_anonymous_lifetime_mode<R>(
@@ -955,42 +992,77 @@
match *args {
MacArgs::Empty => MacArgs::Empty,
MacArgs::Delimited(dspan, delim, ref tokens) => {
- MacArgs::Delimited(dspan, delim, self.lower_token_stream(tokens.clone()))
- }
- MacArgs::Eq(eq_span, ref tokens) => {
- MacArgs::Eq(eq_span, self.lower_token_stream(tokens.clone()))
- }
- }
- }
-
- fn lower_token_stream(&mut self, tokens: TokenStream) -> TokenStream {
- tokens.into_trees().flat_map(|tree| self.lower_token_tree(tree).into_trees()).collect()
- }
-
- fn lower_token_tree(&mut self, tree: TokenTree) -> TokenStream {
- match tree {
- TokenTree::Token(token) => self.lower_token(token),
- TokenTree::Delimited(span, delim, tts) => {
- TokenTree::Delimited(span, delim, self.lower_token_stream(tts)).into()
- }
- }
- }
-
- fn lower_token(&mut self, token: Token) -> TokenStream {
- match token.kind {
- token::Interpolated(nt) => {
- let tts = (self.nt_to_tokenstream)(&nt, &self.sess.parse_sess, token.span);
- TokenTree::Delimited(
- DelimSpan::from_single(token.span),
- DelimToken::NoDelim,
- self.lower_token_stream(tts),
+ // This is either a non-key-value attribute, or a `macro_rules!` body.
+ // We either not have any nonterminals present (in the case of an attribute),
+ // or have tokens available for all nonterminals in the case of a nested
+ // `macro_rules`: e.g:
+ //
+ // ```rust
+ // macro_rules! outer {
+ // ($e:expr) => {
+ // macro_rules! inner {
+ // () => { $e }
+ // }
+ // }
+ // }
+ // ```
+ //
+ // In both cases, we don't want to synthesize any tokens
+ MacArgs::Delimited(
+ dspan,
+ delim,
+ self.lower_token_stream(tokens.clone(), CanSynthesizeMissingTokens::No),
)
- .into()
}
- _ => TokenTree::Token(token).into(),
+ // This is an inert key-value attribute - it will never be visible to macros
+ // after it gets lowered to HIR. Therefore, we can synthesize tokens with fake
+ // spans to handle nonterminals in `#[doc]` (e.g. `#[doc = $e]`).
+ MacArgs::Eq(eq_span, ref token) => {
+ // In valid code the value is always representable as a single literal token.
+ fn unwrap_single_token(sess: &Session, tokens: TokenStream, span: Span) -> Token {
+ if tokens.len() != 1 {
+ sess.diagnostic()
+ .delay_span_bug(span, "multiple tokens in key-value attribute's value");
+ }
+ match tokens.into_trees().next() {
+ Some(TokenTree::Token(token)) => token,
+ Some(TokenTree::Delimited(_, delim, tokens)) => {
+ if delim != token::NoDelim {
+ sess.diagnostic().delay_span_bug(
+ span,
+ "unexpected delimiter in key-value attribute's value",
+ )
+ }
+ unwrap_single_token(sess, tokens, span)
+ }
+ None => Token::dummy(),
+ }
+ }
+
+ let tokens = TokenStreamLowering {
+ parse_sess: &self.sess.parse_sess,
+ synthesize_tokens: CanSynthesizeMissingTokens::Yes,
+ nt_to_tokenstream: self.nt_to_tokenstream,
+ }
+ .lower_token(token.clone());
+ MacArgs::Eq(eq_span, unwrap_single_token(self.sess, tokens, token.span))
+ }
}
}
+ fn lower_token_stream(
+ &self,
+ tokens: TokenStream,
+ synthesize_tokens: CanSynthesizeMissingTokens,
+ ) -> TokenStream {
+ TokenStreamLowering {
+ parse_sess: &self.sess.parse_sess,
+ synthesize_tokens,
+ nt_to_tokenstream: self.nt_to_tokenstream,
+ }
+ .lower_token_stream(tokens)
+ }
+
/// Given an associated type constraint like one of these:
///
/// ```
@@ -1004,16 +1076,40 @@
fn lower_assoc_ty_constraint(
&mut self,
constraint: &AssocTyConstraint,
- itctx: ImplTraitContext<'_, 'hir>,
+ mut itctx: ImplTraitContext<'_, 'hir>,
) -> hir::TypeBinding<'hir> {
debug!("lower_assoc_ty_constraint(constraint={:?}, itctx={:?})", constraint, itctx);
- if let Some(ref gen_args) = constraint.gen_args {
- self.sess.span_fatal(
- gen_args.span(),
- "generic associated types in trait paths are currently not implemented",
- );
- }
+ // lower generic arguments of identifier in constraint
+ let gen_args = if let Some(ref gen_args) = constraint.gen_args {
+ let gen_args_ctor = match gen_args {
+ GenericArgs::AngleBracketed(ref data) => {
+ self.lower_angle_bracketed_parameter_data(
+ data,
+ ParamMode::Explicit,
+ itctx.reborrow(),
+ )
+ .0
+ }
+ GenericArgs::Parenthesized(ref data) => {
+ let mut err = self.sess.struct_span_err(
+ gen_args.span(),
+ "parenthesized generic arguments cannot be used in associated type constraints"
+ );
+ // FIXME: try to write a suggestion here
+ err.emit();
+ self.lower_angle_bracketed_parameter_data(
+ &data.as_angle_bracketed_args(),
+ ParamMode::Explicit,
+ itctx.reborrow(),
+ )
+ .0
+ }
+ };
+ self.arena.alloc(gen_args_ctor.into_generic_args(&self.arena))
+ } else {
+ self.arena.alloc(hir::GenericArgs::none())
+ };
let kind = match constraint.kind {
AssocTyConstraintKind::Equality { ref ty } => {
@@ -1110,6 +1206,7 @@
hir::TypeBinding {
hir_id: self.lower_node_id(constraint.id),
ident: constraint.ident,
+ gen_args,
kind,
span: constraint.span,
}
@@ -1220,6 +1317,7 @@
}
TyKind::BareFn(ref f) => self.with_in_scope_lifetime_defs(&f.generic_params, |this| {
this.with_anonymous_lifetime_mode(AnonymousLifetimeMode::PassThrough, |this| {
+ let span = this.sess.source_map().next_point(t.span.shrink_to_lo());
hir::TyKind::BareFn(this.arena.alloc(hir::BareFnTy {
generic_params: this.lower_generic_params(
&f.generic_params,
@@ -1227,7 +1325,7 @@
ImplTraitContext::disallowed(),
),
unsafety: this.lower_unsafety(f.unsafety),
- abi: this.lower_extern(f.ext),
+ abi: this.lower_extern(f.ext, span, t.id),
decl: this.lower_fn_decl(&f.decl, None, false, None),
param_names: this.lower_fn_params_to_names(&f.decl),
}))
@@ -1716,7 +1814,7 @@
}
self.arena.alloc_from_iter(inputs.iter().map(|param| match param.pat.kind {
PatKind::Ident(_, ident, _) => ident,
- _ => Ident::new(kw::Invalid, param.pat.span),
+ _ => Ident::new(kw::Empty, param.pat.span),
}))
}
@@ -1806,12 +1904,11 @@
output,
c_variadic,
implicit_self: decl.inputs.get(0).map_or(hir::ImplicitSelfKind::None, |arg| {
- let is_mutable_pat = match arg.pat.kind {
- PatKind::Ident(BindingMode::ByValue(mt) | BindingMode::ByRef(mt), _, _) => {
- mt == Mutability::Mut
- }
- _ => false,
- };
+ use BindingMode::{ByRef, ByValue};
+ let is_mutable_pat = matches!(
+ arg.pat.kind,
+ PatKind::Ident(ByValue(Mutability::Mut) | ByRef(Mutability::Mut), ..)
+ );
match arg.ty.kind {
TyKind::ImplicitSelf if is_mutable_pat => hir::ImplicitSelfKind::Mut,
@@ -2192,13 +2289,14 @@
(hir::ParamName::Plain(param.ident), kind)
}
- GenericParamKind::Const { ref ty, kw_span: _ } => {
+ GenericParamKind::Const { ref ty, kw_span: _, ref default } => {
let ty = self
.with_anonymous_lifetime_mode(AnonymousLifetimeMode::ReportError, |this| {
this.lower_ty(&ty, ImplTraitContext::disallowed())
});
+ let default = default.as_ref().map(|def| self.lower_anon_const(def));
- (hir::ParamName::Plain(param.ident), hir::GenericParamKind::Const { ty })
+ (hir::ParamName::Plain(param.ident), hir::GenericParamKind::Const { ty, default })
}
};
@@ -2709,6 +2807,26 @@
)
}
}
+
+ fn maybe_lint_missing_abi(&mut self, span: Span, id: NodeId, default: Abi) {
+ // FIXME(davidtwco): This is a hack to detect macros which produce spans of the
+ // call site which do not have a macro backtrace. See #61963.
+ let is_macro_callsite = self
+ .sess
+ .source_map()
+ .span_to_snippet(span)
+ .map(|snippet| snippet.starts_with("#["))
+ .unwrap_or(true);
+ if !is_macro_callsite {
+ self.resolver.lint_buffer().buffer_lint_with_diagnostic(
+ MISSING_ABI,
+ id,
+ span,
+ "extern declarations without an explicit ABI are deprecated",
+ BuiltinLintDiagnostics::MissingAbi(span, default),
+ )
+ }
+ }
}
fn body_ids(bodies: &BTreeMap<hir::BodyId, hir::Body<'_>>) -> Vec<hir::BodyId> {
diff --git a/compiler/rustc_ast_lowering/src/path.rs b/compiler/rustc_ast_lowering/src/path.rs
index 6afed35..cb4d5ea 100644
--- a/compiler/rustc_ast_lowering/src/path.rs
+++ b/compiler/rustc_ast_lowering/src/path.rs
@@ -273,7 +273,7 @@
if !generic_args.parenthesized && !has_lifetimes {
generic_args.args = self
.elided_path_lifetimes(
- first_generic_span.map(|s| s.shrink_to_lo()).unwrap_or(segment.ident.span),
+ first_generic_span.map_or(segment.ident.span, |s| s.shrink_to_lo()),
expected_lifetimes,
)
.map(GenericArg::Lifetime)
@@ -362,7 +362,7 @@
}
}
- fn lower_angle_bracketed_parameter_data(
+ pub(crate) fn lower_angle_bracketed_parameter_data(
&mut self,
data: &AngleBracketedArgs,
param_mode: ParamMode,
@@ -401,15 +401,15 @@
// compatibility, even in contexts like an impl header where
// we generally don't permit such things (see #51008).
self.with_anonymous_lifetime_mode(AnonymousLifetimeMode::PassThrough, |this| {
- let &ParenthesizedArgs { ref inputs, ref output, span } = data;
+ let ParenthesizedArgs { span, inputs, inputs_span, output } = data;
let inputs = this.arena.alloc_from_iter(
inputs.iter().map(|ty| this.lower_ty_direct(ty, ImplTraitContext::disallowed())),
);
let output_ty = match output {
FnRetTy::Ty(ty) => this.lower_ty(&ty, ImplTraitContext::disallowed()),
- FnRetTy::Default(_) => this.arena.alloc(this.ty_tup(span, &[])),
+ FnRetTy::Default(_) => this.arena.alloc(this.ty_tup(*span, &[])),
};
- let args = smallvec![GenericArg::Type(this.ty_tup(span, inputs))];
+ let args = smallvec![GenericArg::Type(this.ty_tup(*inputs_span, inputs))];
let binding = this.output_ty_binding(output_ty.span, output_ty);
(
GenericArgsCtor { args, bindings: arena_vec![this; binding], parenthesized: true },
@@ -426,6 +426,9 @@
) -> hir::TypeBinding<'hir> {
let ident = Ident::with_dummy_span(hir::FN_OUTPUT_NAME);
let kind = hir::TypeBindingKind::Equality { ty };
- hir::TypeBinding { hir_id: self.next_id(), span, ident, kind }
+ let args = arena_vec![self;];
+ let bindings = arena_vec![self;];
+ let gen_args = self.arena.alloc(hir::GenericArgs { args, bindings, parenthesized: false });
+ hir::TypeBinding { hir_id: self.next_id(), gen_args, span, ident, kind }
}
}
diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs
index bf6d332..8defd91 100644
--- a/compiler/rustc_ast_passes/src/ast_validation.rs
+++ b/compiler/rustc_ast_passes/src/ast_validation.rs
@@ -16,7 +16,7 @@
use rustc_errors::{error_code, pluralize, struct_span_err, Applicability};
use rustc_parse::validate_attr;
use rustc_session::lint::builtin::PATTERNS_IN_FNS_WITHOUT_BODY;
-use rustc_session::lint::LintBuffer;
+use rustc_session::lint::{BuiltinLintDiagnostics, LintBuffer};
use rustc_session::Session;
use rustc_span::symbol::{kw, sym, Ident};
use rustc_span::Span;
@@ -184,7 +184,7 @@
}
fn check_lifetime(&self, ident: Ident) {
- let valid_names = [kw::UnderscoreLifetime, kw::StaticLifetime, kw::Invalid];
+ let valid_names = [kw::UnderscoreLifetime, kw::StaticLifetime, kw::Empty];
if !valid_names.contains(&ident.name) && ident.without_first_quote().is_reserved() {
self.err_handler().span_err(ident.span, "lifetimes cannot use keyword names");
}
@@ -213,14 +213,14 @@
err.emit();
}
- fn check_decl_no_pat(decl: &FnDecl, mut report_err: impl FnMut(Span, bool)) {
+ fn check_decl_no_pat(decl: &FnDecl, mut report_err: impl FnMut(Span, Option<Ident>, bool)) {
for Param { pat, .. } in &decl.inputs {
match pat.kind {
PatKind::Ident(BindingMode::ByValue(Mutability::Not), _, None) | PatKind::Wild => {}
- PatKind::Ident(BindingMode::ByValue(Mutability::Mut), _, None) => {
- report_err(pat.span, true)
+ PatKind::Ident(BindingMode::ByValue(Mutability::Mut), ident, None) => {
+ report_err(pat.span, Some(ident), true)
}
- _ => report_err(pat.span, false),
+ _ => report_err(pat.span, None, false),
}
}
}
@@ -717,35 +717,46 @@
/// Checks that generic parameters are in the correct order,
/// which is lifetimes, then types and then consts. (`<'a, T, const N: usize>`)
-fn validate_generic_param_order<'a>(
+fn validate_generic_param_order(
sess: &Session,
handler: &rustc_errors::Handler,
- generics: impl Iterator<Item = (ParamKindOrd, Option<&'a [GenericBound]>, Span, Option<String>)>,
+ generics: &[GenericParam],
span: Span,
) {
let mut max_param: Option<ParamKindOrd> = None;
let mut out_of_order = FxHashMap::default();
let mut param_idents = vec![];
- for (kind, bounds, span, ident) in generics {
+ for param in generics {
+ let ident = Some(param.ident.to_string());
+ let (kind, bounds, span) = (¶m.kind, Some(&*param.bounds), param.ident.span);
+ let (ord_kind, ident) = match ¶m.kind {
+ GenericParamKind::Lifetime => (ParamKindOrd::Lifetime, ident),
+ GenericParamKind::Type { default: _ } => (ParamKindOrd::Type, ident),
+ GenericParamKind::Const { ref ty, kw_span: _, default: _ } => {
+ let ty = pprust::ty_to_string(ty);
+ let unordered = sess.features_untracked().const_generics;
+ (ParamKindOrd::Const { unordered }, Some(format!("const {}: {}", param.ident, ty)))
+ }
+ };
if let Some(ident) = ident {
- param_idents.push((kind, bounds, param_idents.len(), ident));
+ param_idents.push((kind, ord_kind, bounds, param_idents.len(), ident));
}
let max_param = &mut max_param;
match max_param {
- Some(max_param) if *max_param > kind => {
- let entry = out_of_order.entry(kind).or_insert((*max_param, vec![]));
+ Some(max_param) if *max_param > ord_kind => {
+ let entry = out_of_order.entry(ord_kind).or_insert((*max_param, vec![]));
entry.1.push(span);
}
- Some(_) | None => *max_param = Some(kind),
+ Some(_) | None => *max_param = Some(ord_kind),
};
}
let mut ordered_params = "<".to_string();
if !out_of_order.is_empty() {
- param_idents.sort_by_key(|&(po, _, i, _)| (po, i));
+ param_idents.sort_by_key(|&(_, po, _, i, _)| (po, i));
let mut first = true;
- for (_, bounds, _, ident) in param_idents {
+ for (kind, _, bounds, _, ident) in param_idents {
if !first {
ordered_params += ", ";
}
@@ -756,6 +767,16 @@
ordered_params += &pprust::bounds_to_string(&bounds);
}
}
+ match kind {
+ GenericParamKind::Type { default: Some(default) } => {
+ ordered_params += " = ";
+ ordered_params += &pprust::ty_to_string(default);
+ }
+ GenericParamKind::Type { default: None } => (),
+ GenericParamKind::Lifetime => (),
+ // FIXME(const_generics_defaults)
+ GenericParamKind::Const { ty: _, kw_span: _, default: _ } => (),
+ }
first = false;
}
}
@@ -773,14 +794,12 @@
err.span_suggestion(
span,
&format!(
- "reorder the parameters: lifetimes{}",
+ "reorder the parameters: lifetimes, {}",
if sess.features_untracked().const_generics {
- ", then consts and types"
- } else if sess.features_untracked().min_const_generics {
- ", then types, then consts"
+ "then consts and types"
} else {
- ", then types"
- },
+ "then types, then consts"
+ }
),
ordered_params.clone(),
Applicability::MachineApplicable,
@@ -815,7 +834,7 @@
match ty.kind {
TyKind::BareFn(ref bfty) => {
self.check_fn_decl(&bfty.decl, SelfSemantic::No);
- Self::check_decl_no_pat(&bfty.decl, |span, _| {
+ Self::check_decl_no_pat(&bfty.decl, |span, _, _| {
struct_span_err!(
self.session,
span,
@@ -901,7 +920,7 @@
}
match item.kind {
- ItemKind::Impl {
+ ItemKind::Impl(box ImplKind {
unsafety,
polarity,
defaultness: _,
@@ -910,7 +929,7 @@
of_trait: Some(ref t),
ref self_ty,
items: _,
- } => {
+ }) => {
self.with_in_trait_impl(true, |this| {
this.invalid_visibility(&item.vis, None);
if let TyKind::Err = self_ty.kind {
@@ -938,7 +957,7 @@
});
return; // Avoid visiting again.
}
- ItemKind::Impl {
+ ItemKind::Impl(box ImplKind {
unsafety,
polarity,
defaultness,
@@ -947,7 +966,7 @@
of_trait: None,
ref self_ty,
items: _,
- } => {
+ }) => {
let error = |annotation_span, annotation| {
let mut err = self.err_handler().struct_span_err(
self_ty.span,
@@ -979,7 +998,7 @@
.emit();
}
}
- ItemKind::Fn(def, _, _, ref body) => {
+ ItemKind::Fn(box FnKind(def, _, _, ref body)) => {
self.check_defaultness(item.span, def);
if body.is_none() {
@@ -1008,7 +1027,13 @@
}
}
}
- ItemKind::Trait(is_auto, _, ref generics, ref bounds, ref trait_items) => {
+ ItemKind::Trait(box TraitKind(
+ is_auto,
+ _,
+ ref generics,
+ ref bounds,
+ ref trait_items,
+ )) => {
if is_auto == IsAuto::Yes {
// Auto traits cannot have generics, super traits nor contain items.
self.deny_generic_params(generics, item.ident.span);
@@ -1056,7 +1081,7 @@
let msg = "free static item without body";
self.error_item_without_body(item.span, "static", msg, " = <expr>;");
}
- ItemKind::TyAlias(def, _, ref bounds, ref body) => {
+ ItemKind::TyAlias(box TyAliasKind(def, _, ref bounds, ref body)) => {
self.check_defaultness(item.span, def);
if body.is_none() {
let msg = "free type alias without body";
@@ -1072,12 +1097,12 @@
fn visit_foreign_item(&mut self, fi: &'a ForeignItem) {
match &fi.kind {
- ForeignItemKind::Fn(def, sig, _, body) => {
+ ForeignItemKind::Fn(box FnKind(def, sig, _, body)) => {
self.check_defaultness(fi.span, *def);
self.check_foreign_fn_bodyless(fi.ident, body.as_deref());
self.check_foreign_fn_headerless(fi.ident, fi.span, sig.header);
}
- ForeignItemKind::TyAlias(def, generics, bounds, body) => {
+ ForeignItemKind::TyAlias(box TyAliasKind(def, generics, bounds, body)) => {
self.check_defaultness(fi.span, *def);
self.check_foreign_kind_bodyless(fi.ident, "type", body.as_ref().map(|b| b.span));
self.check_type_no_bounds(bounds, "`extern` blocks");
@@ -1152,22 +1177,7 @@
validate_generic_param_order(
self.session,
self.err_handler(),
- generics.params.iter().map(|param| {
- let ident = Some(param.ident.to_string());
- let (kind, ident) = match ¶m.kind {
- GenericParamKind::Lifetime => (ParamKindOrd::Lifetime, ident),
- GenericParamKind::Type { default: _ } => (ParamKindOrd::Type, ident),
- GenericParamKind::Const { ref ty, kw_span: _ } => {
- let ty = pprust::ty_to_string(ty);
- let unordered = self.session.features_untracked().const_generics;
- (
- ParamKindOrd::Const { unordered },
- Some(format!("const {}: {}", param.ident, ty)),
- )
- }
- };
- (kind, Some(&*param.bounds), param.ident.span, ident)
- }),
+ &generics.params,
generics.span,
);
@@ -1208,11 +1218,11 @@
}
fn visit_pat(&mut self, pat: &'a Pat) {
- match pat.kind {
- PatKind::Lit(ref expr) => {
+ match &pat.kind {
+ PatKind::Lit(expr) => {
self.check_expr_within_pat(expr, false);
}
- PatKind::Range(ref start, ref end, _) => {
+ PatKind::Range(start, end, _) => {
if let Some(expr) = start {
self.check_expr_within_pat(expr, true);
}
@@ -1285,7 +1295,7 @@
// Functions without bodies cannot have patterns.
if let FnKind::Fn(ctxt, _, sig, _, None) = fk {
- Self::check_decl_no_pat(&sig.decl, |span, mut_ident| {
+ Self::check_decl_no_pat(&sig.decl, |span, ident, mut_ident| {
let (code, msg, label) = match ctxt {
FnCtxt::Foreign => (
error_code!(E0130),
@@ -1299,7 +1309,16 @@
),
};
if mut_ident && matches!(ctxt, FnCtxt::Assoc(_)) {
- self.lint_buffer.buffer_lint(PATTERNS_IN_FNS_WITHOUT_BODY, id, span, msg);
+ if let Some(ident) = ident {
+ let diag = BuiltinLintDiagnostics::PatternsInFnsWithoutBody(span, ident);
+ self.lint_buffer.buffer_lint_with_diagnostic(
+ PATTERNS_IN_FNS_WITHOUT_BODY,
+ id,
+ span,
+ msg,
+ diag,
+ )
+ }
} else {
self.err_handler()
.struct_span_err(span, msg)
@@ -1323,10 +1342,10 @@
AssocItemKind::Const(_, _, body) => {
self.check_impl_item_provided(item.span, body, "constant", " = <expr>;");
}
- AssocItemKind::Fn(_, _, _, body) => {
+ AssocItemKind::Fn(box FnKind(_, _, _, body)) => {
self.check_impl_item_provided(item.span, body, "function", " { <body> }");
}
- AssocItemKind::TyAlias(_, _, bounds, body) => {
+ AssocItemKind::TyAlias(box TyAliasKind(_, _, bounds, body)) => {
self.check_impl_item_provided(item.span, body, "type", " = <type>;");
self.check_type_no_bounds(bounds, "`impl`s");
}
@@ -1336,7 +1355,7 @@
if ctxt == AssocCtxt::Trait || self.in_trait_impl {
self.invalid_visibility(&item.vis, None);
- if let AssocItemKind::Fn(_, sig, _, _) = &item.kind {
+ if let AssocItemKind::Fn(box FnKind(_, sig, _, _)) = &item.kind {
self.check_trait_fn_not_const(sig.header.constness);
self.check_trait_fn_not_async(item.span, sig.header.asyncness);
}
diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs
index bb22267..6514de2 100644
--- a/compiler/rustc_ast_passes/src/feature_gate.rs
+++ b/compiler/rustc_ast_passes/src/feature_gate.rs
@@ -1,7 +1,7 @@
use rustc_ast as ast;
use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor};
use rustc_ast::{AssocTyConstraint, AssocTyConstraintKind, NodeId};
-use rustc_ast::{GenericParam, GenericParamKind, PatKind, RangeEnd, VariantData};
+use rustc_ast::{PatKind, RangeEnd, VariantData};
use rustc_errors::struct_span_err;
use rustc_feature::{AttributeGate, BUILTIN_ATTRIBUTE_MAP};
use rustc_feature::{Features, GateIssue};
@@ -14,6 +14,17 @@
use tracing::debug;
macro_rules! gate_feature_fn {
+ ($visitor: expr, $has_feature: expr, $span: expr, $name: expr, $explain: expr, $help: expr) => {{
+ let (visitor, has_feature, span, name, explain, help) =
+ (&*$visitor, $has_feature, $span, $name, $explain, $help);
+ let has_feature: bool = has_feature(visitor.features);
+ debug!("gate_feature(feature = {:?}, span = {:?}); has? {}", name, span, has_feature);
+ if !has_feature && !span.allows_unstable($name) {
+ feature_err_issue(&visitor.sess.parse_sess, name, span, GateIssue::Language, explain)
+ .help(help)
+ .emit();
+ }
+ }};
($visitor: expr, $has_feature: expr, $span: expr, $name: expr, $explain: expr) => {{
let (visitor, has_feature, span, name, explain) =
(&*$visitor, $has_feature, $span, $name, $explain);
@@ -27,6 +38,9 @@
}
macro_rules! gate_feature_post {
+ ($visitor: expr, $feature: ident, $span: expr, $explain: expr, $help: expr) => {
+ gate_feature_fn!($visitor, |x: &Features| x.$feature, $span, sym::$feature, $explain, $help)
+ };
($visitor: expr, $feature: ident, $span: expr, $explain: expr) => {
gate_feature_fn!($visitor, |x: &Features| x.$feature, $span, sym::$feature, $explain)
};
@@ -142,6 +156,14 @@
"efiapi ABI is experimental and subject to change"
);
}
+ "C-cmse-nonsecure-call" => {
+ gate_feature_post!(
+ &self,
+ abi_c_cmse_nonsecure_call,
+ span,
+ "C-cmse-nonsecure-call ABI is experimental and subject to change"
+ );
+ }
abi => self
.sess
.parse_sess
@@ -351,12 +373,14 @@
}
}
- ast::ItemKind::Impl { polarity, defaultness, ref of_trait, .. } => {
+ ast::ItemKind::Impl(box ast::ImplKind {
+ polarity, defaultness, ref of_trait, ..
+ }) => {
if let ast::ImplPolarity::Negative(span) = polarity {
gate_feature_post!(
&self,
negative_impls,
- span.to(of_trait.as_ref().map(|t| t.path.span).unwrap_or(span)),
+ span.to(of_trait.as_ref().map_or(span, |t| t.path.span)),
"negative trait bounds are not yet fully implemented; \
use marker types for now"
);
@@ -367,7 +391,7 @@
}
}
- ast::ItemKind::Trait(ast::IsAuto::Yes, ..) => {
+ ast::ItemKind::Trait(box ast::TraitKind(ast::IsAuto::Yes, ..)) => {
gate_feature_post!(
&self,
auto_traits,
@@ -385,7 +409,9 @@
gate_feature_post!(&self, decl_macro, i.span, msg);
}
- ast::ItemKind::TyAlias(_, _, _, Some(ref ty)) => self.check_impl_trait(&ty),
+ ast::ItemKind::TyAlias(box ast::TyAliasKind(_, _, _, Some(ref ty))) => {
+ self.check_impl_trait(&ty)
+ }
_ => {}
}
@@ -397,10 +423,8 @@
match i.kind {
ast::ForeignItemKind::Fn(..) | ast::ForeignItemKind::Static(..) => {
let link_name = self.sess.first_attr_value_str_by_name(&i.attrs, sym::link_name);
- let links_to_llvm = match link_name {
- Some(val) => val.as_str().starts_with("llvm."),
- _ => false,
- };
+ let links_to_llvm =
+ link_name.map_or(false, |val| val.as_str().starts_with("llvm."));
if links_to_llvm {
gate_feature_post!(
&self,
@@ -529,19 +553,6 @@
visit::walk_fn(self, fn_kind, span)
}
- fn visit_generic_param(&mut self, param: &'a GenericParam) {
- if let GenericParamKind::Const { .. } = param.kind {
- gate_feature_fn!(
- &self,
- |x: &Features| x.const_generics || x.min_const_generics,
- param.ident.span,
- sym::min_const_generics,
- "const generics are unstable"
- );
- }
- visit::walk_generic_param(self, param)
- }
-
fn visit_assoc_ty_constraint(&mut self, constraint: &'a AssocTyConstraint) {
if let AssocTyConstraintKind::Bound { .. } = constraint.kind {
gate_feature_post!(
@@ -556,13 +567,13 @@
fn visit_assoc_item(&mut self, i: &'a ast::AssocItem, ctxt: AssocCtxt) {
let is_fn = match i.kind {
- ast::AssocItemKind::Fn(_, ref sig, _, _) => {
+ ast::AssocItemKind::Fn(box ast::FnKind(_, ref sig, _, _)) => {
if let (ast::Const::Yes(_), AssocCtxt::Trait) = (sig.header.constness, ctxt) {
gate_feature_post!(&self, const_fn, i.span, "const fn is unstable");
}
true
}
- ast::AssocItemKind::TyAlias(_, ref generics, _, ref ty) => {
+ ast::AssocItemKind::TyAlias(box ast::TyAliasKind(_, ref generics, _, ref ty)) => {
if let (Some(_), AssocCtxt::Trait) = (ty, ctxt) {
gate_feature_post!(
&self,
@@ -612,6 +623,13 @@
let spans = sess.parse_sess.gated_spans.spans.borrow();
macro_rules! gate_all {
+ ($gate:ident, $msg:literal, $help:literal) => {
+ if let Some(spans) = spans.get(&sym::$gate) {
+ for span in spans {
+ gate_feature_post!(&visitor, $gate, *span, $msg, $help);
+ }
+ }
+ };
($gate:ident, $msg:literal) => {
if let Some(spans) = spans.get(&sym::$gate) {
for span in spans {
@@ -622,7 +640,11 @@
}
gate_all!(if_let_guard, "`if let` guards are experimental");
gate_all!(let_chains, "`let` expressions in this position are experimental");
- gate_all!(async_closure, "async closures are unstable");
+ gate_all!(
+ async_closure,
+ "async closures are unstable",
+ "to use an async block, remove the `||`: `async {`"
+ );
gate_all!(generators, "yield syntax is experimental");
gate_all!(or_patterns, "or-patterns syntax is experimental");
gate_all!(raw_ref_op, "raw address of syntax is experimental");
@@ -634,6 +656,10 @@
extended_key_value_attributes,
"arbitrary expressions in key-value attributes are unstable"
);
+ gate_all!(
+ const_generics_defaults,
+ "default values for const generic parameters are experimental"
+ );
if sess.parse_sess.span_diagnostic.err_count() == 0 {
// Errors for `destructuring_assignment` can get quite noisy, especially where `_` is
// involved, so we only emit errors where there are no other parsing errors.
diff --git a/compiler/rustc_ast_passes/src/lib.rs b/compiler/rustc_ast_passes/src/lib.rs
index 7487421..c9e2d20 100644
--- a/compiler/rustc_ast_passes/src/lib.rs
+++ b/compiler/rustc_ast_passes/src/lib.rs
@@ -6,6 +6,8 @@
#![feature(bindings_after_at)]
#![feature(iter_is_partitioned)]
+#![feature(box_syntax)]
+#![feature(box_patterns)]
#![recursion_limit = "256"]
pub mod ast_validation;
diff --git a/compiler/rustc_ast_passes/src/node_count.rs b/compiler/rustc_ast_passes/src/node_count.rs
index 6efc78c..2971fa4 100644
--- a/compiler/rustc_ast_passes/src/node_count.rs
+++ b/compiler/rustc_ast_passes/src/node_count.rs
@@ -68,7 +68,7 @@
self.count += 1;
walk_generics(self, g)
}
- fn visit_fn(&mut self, fk: FnKind<'_>, s: Span, _: NodeId) {
+ fn visit_fn(&mut self, fk: visit::FnKind<'_>, s: Span, _: NodeId) {
self.count += 1;
walk_fn(self, fk, s)
}
diff --git a/compiler/rustc_ast_pretty/Cargo.toml b/compiler/rustc_ast_pretty/Cargo.toml
index f447bc7..6ea942a 100644
--- a/compiler/rustc_ast_pretty/Cargo.toml
+++ b/compiler/rustc_ast_pretty/Cargo.toml
@@ -11,4 +11,3 @@
tracing = "0.1"
rustc_span = { path = "../rustc_span" }
rustc_ast = { path = "../rustc_ast" }
-rustc_target = { path = "../rustc_target" }
diff --git a/compiler/rustc_ast_pretty/src/lib.rs b/compiler/rustc_ast_pretty/src/lib.rs
index 9adc6c6..d869baa 100644
--- a/compiler/rustc_ast_pretty/src/lib.rs
+++ b/compiler/rustc_ast_pretty/src/lib.rs
@@ -1,6 +1,7 @@
#![feature(bool_to_option)]
#![feature(crate_visibility_modifier)]
#![feature(or_patterns)]
+#![feature(box_patterns)]
#![recursion_limit = "256"]
mod helpers;
diff --git a/compiler/rustc_ast_pretty/src/pp.rs b/compiler/rustc_ast_pretty/src/pp.rs
index 56e769b..ea298d2 100644
--- a/compiler/rustc_ast_pretty/src/pp.rs
+++ b/compiler/rustc_ast_pretty/src/pp.rs
@@ -75,7 +75,7 @@
//! breaking inconsistently to become
//!
//! ```
-//! foo(hello, there
+//! foo(hello, there,
//! good, friends);
//! ```
//!
@@ -83,7 +83,7 @@
//!
//! ```
//! foo(hello,
-//! there
+//! there,
//! good,
//! friends);
//! ```
diff --git a/compiler/rustc_ast_pretty/src/pprust/mod.rs b/compiler/rustc_ast_pretty/src/pprust/mod.rs
index b34ea41..b88699f 100644
--- a/compiler/rustc_ast_pretty/src/pprust/mod.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/mod.rs
@@ -8,11 +8,6 @@
use rustc_ast::token::{Nonterminal, Token, TokenKind};
use rustc_ast::tokenstream::{TokenStream, TokenTree};
-pub fn nonterminal_to_string_no_extra_parens(nt: &Nonterminal) -> String {
- let state = State::without_insert_extra_parens();
- state.nonterminal_to_string(nt)
-}
-
pub fn nonterminal_to_string(nt: &Nonterminal) -> String {
State::new().nonterminal_to_string(nt)
}
diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs
index dcb6e11..7f4775b 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state.rs
@@ -88,13 +88,6 @@
comments: Option<Comments<'a>>,
ann: &'a (dyn PpAnn + 'a),
is_expanded: bool,
- // If `true`, additional parenthesis (separate from `ExprKind::Paren`)
- // are inserted to ensure that proper precedence is preserved
- // in the pretty-printed output.
- //
- // This is usually `true`, except when performing the pretty-print/reparse
- // check in `nt_to_tokenstream`
- insert_extra_parens: bool,
}
crate const INDENT_UNIT: usize = 4;
@@ -115,7 +108,6 @@
comments: Some(Comments::new(sm, filename, input)),
ann,
is_expanded,
- insert_extra_parens: true,
};
if is_expanded && !krate.attrs.iter().any(|attr| attr.has_name(sym::no_core)) {
@@ -235,7 +227,6 @@
}
pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::DerefMut {
- fn insert_extra_parens(&self) -> bool;
fn comments(&mut self) -> &mut Option<Comments<'a>>;
fn print_ident(&mut self, ident: Ident);
fn print_generic_args(&mut self, args: &ast::GenericArgs, colons_before_params: bool);
@@ -454,10 +445,11 @@
),
MacArgs::Empty | MacArgs::Eq(..) => {
self.print_path(&item.path, false, 0);
- if let MacArgs::Eq(_, tokens) = &item.args {
+ if let MacArgs::Eq(_, token) = &item.args {
self.space();
self.word_space("=");
- self.print_tts(tokens, true);
+ let token_str = self.token_to_string_ext(token, true);
+ self.word(token_str);
}
}
}
@@ -819,16 +811,12 @@
fn to_string(&self, f: impl FnOnce(&mut State<'_>)) -> String {
let mut printer = State::new();
- printer.insert_extra_parens = self.insert_extra_parens();
f(&mut printer);
printer.s.eof()
}
}
impl<'a> PrintState<'a> for State<'a> {
- fn insert_extra_parens(&self) -> bool {
- self.insert_extra_parens
- }
fn comments(&mut self) -> &mut Option<Comments<'a>> {
&mut self.comments
}
@@ -865,17 +853,7 @@
impl<'a> State<'a> {
pub fn new() -> State<'a> {
- State {
- s: pp::mk_printer(),
- comments: None,
- ann: &NoAnn,
- is_expanded: false,
- insert_extra_parens: true,
- }
- }
-
- pub(super) fn without_insert_extra_parens() -> State<'a> {
- State { insert_extra_parens: false, ..State::new() }
+ State { s: pp::mk_printer(), comments: None, ann: &NoAnn, is_expanded: false }
}
// Synthesizes a comment that was not textually present in the original source
@@ -1044,14 +1022,14 @@
self.maybe_print_comment(span.lo());
self.print_outer_attributes(attrs);
match kind {
- ast::ForeignItemKind::Fn(def, sig, gen, body) => {
+ ast::ForeignItemKind::Fn(box ast::FnKind(def, sig, gen, body)) => {
self.print_fn_full(sig, ident, gen, vis, *def, body.as_deref(), attrs);
}
ast::ForeignItemKind::Static(ty, mutbl, body) => {
let def = ast::Defaultness::Final;
self.print_item_const(ident, Some(*mutbl), ty, body.as_deref(), vis, def);
}
- ast::ForeignItemKind::TyAlias(def, generics, bounds, ty) => {
+ ast::ForeignItemKind::TyAlias(box ast::TyAliasKind(def, generics, bounds, ty)) => {
self.print_associated_type(ident, generics, bounds, ty.as_deref(), vis, *def);
}
ast::ForeignItemKind::MacCall(m) => {
@@ -1156,7 +1134,7 @@
ast::ItemKind::Const(def, ref ty, ref body) => {
self.print_item_const(item.ident, None, ty, body.as_deref(), &item.vis, def);
}
- ast::ItemKind::Fn(def, ref sig, ref gen, ref body) => {
+ ast::ItemKind::Fn(box ast::FnKind(def, ref sig, ref gen, ref body)) => {
let body = body.as_deref();
self.print_fn_full(sig, item.ident, gen, &item.vis, def, body, &item.attrs);
}
@@ -1197,7 +1175,7 @@
self.s.word(ga.asm.to_string());
self.end();
}
- ast::ItemKind::TyAlias(def, ref generics, ref bounds, ref ty) => {
+ ast::ItemKind::TyAlias(box ast::TyAliasKind(def, ref generics, ref bounds, ref ty)) => {
let ty = ty.as_deref();
self.print_associated_type(item.ident, generics, bounds, ty, &item.vis, def);
}
@@ -1212,7 +1190,7 @@
self.head(visibility_qualified(&item.vis, "union"));
self.print_struct(struct_def, generics, item.ident, item.span, true);
}
- ast::ItemKind::Impl {
+ ast::ItemKind::Impl(box ast::ImplKind {
unsafety,
polarity,
defaultness,
@@ -1221,7 +1199,7 @@
ref of_trait,
ref self_ty,
ref items,
- } => {
+ }) => {
self.head("");
self.print_visibility(&item.vis);
self.print_defaultness(defaultness);
@@ -1255,7 +1233,13 @@
}
self.bclose(item.span);
}
- ast::ItemKind::Trait(is_auto, unsafety, ref generics, ref bounds, ref trait_items) => {
+ ast::ItemKind::Trait(box ast::TraitKind(
+ is_auto,
+ unsafety,
+ ref generics,
+ ref bounds,
+ ref trait_items,
+ )) => {
self.head("");
self.print_visibility(&item.vis);
self.print_unsafety(unsafety);
@@ -1475,13 +1459,13 @@
self.maybe_print_comment(span.lo());
self.print_outer_attributes(attrs);
match kind {
- ast::AssocItemKind::Fn(def, sig, gen, body) => {
+ ast::AssocItemKind::Fn(box ast::FnKind(def, sig, gen, body)) => {
self.print_fn_full(sig, ident, gen, vis, *def, body.as_deref(), attrs);
}
ast::AssocItemKind::Const(def, ty, body) => {
self.print_item_const(ident, None, ty, body.as_deref(), vis, *def);
}
- ast::AssocItemKind::TyAlias(def, generics, bounds, ty) => {
+ ast::AssocItemKind::TyAlias(box ast::TyAliasKind(def, generics, bounds, ty)) => {
self.print_associated_type(ident, generics, bounds, ty.as_deref(), vis, *def);
}
ast::AssocItemKind::MacCall(m) => {
@@ -1680,8 +1664,7 @@
}
/// Prints `expr` or `(expr)` when `needs_par` holds.
- fn print_expr_cond_paren(&mut self, expr: &ast::Expr, mut needs_par: bool) {
- needs_par &= self.insert_extra_parens;
+ fn print_expr_cond_paren(&mut self, expr: &ast::Expr, needs_par: bool) {
if needs_par {
self.popen();
}
@@ -2668,13 +2651,16 @@
s.print_type(default)
}
}
- ast::GenericParamKind::Const { ref ty, kw_span: _ } => {
+ ast::GenericParamKind::Const { ref ty, kw_span: _, ref default } => {
s.word_space("const");
s.print_ident(param.ident);
s.s.space();
s.word_space(":");
s.print_type(ty);
- s.print_type_bounds(":", ¶m.bounds)
+ s.print_type_bounds(":", ¶m.bounds);
+ if let Some(ref _default) = default {
+ // FIXME(const_generics_defaults): print the `default` value here
+ }
}
}
});
@@ -2787,7 +2773,7 @@
self.print_explicit_self(&eself);
} else {
let invalid = if let PatKind::Ident(_, ident, _) = input.pat.kind {
- ident.name == kw::Invalid
+ ident.name == kw::Empty
} else {
false
};
diff --git a/compiler/rustc_attr/Cargo.toml b/compiler/rustc_attr/Cargo.toml
index 5f941a0a..dc0711a 100644
--- a/compiler/rustc_attr/Cargo.toml
+++ b/compiler/rustc_attr/Cargo.toml
@@ -18,4 +18,3 @@
rustc_macros = { path = "../rustc_macros" }
rustc_session = { path = "../rustc_session" }
rustc_ast = { path = "../rustc_ast" }
-version_check = "0.9"
diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs
index ead90f2..aca3fbb 100644
--- a/compiler/rustc_attr/src/builtin.rs
+++ b/compiler/rustc_attr/src/builtin.rs
@@ -10,7 +10,6 @@
use rustc_span::hygiene::Transparency;
use rustc_span::{symbol::sym, symbol::Symbol, Span};
use std::num::NonZeroU32;
-use version_check::Version;
pub fn is_builtin_attr(attr: &Attribute) -> bool {
attr.is_doc_comment() || attr.ident().filter(|ident| is_builtin_attr_name(ident.name)).is_some()
@@ -67,7 +66,7 @@
}
}
-#[derive(Copy, Clone, PartialEq, Encodable, Decodable)]
+#[derive(Copy, Clone, PartialEq, Encodable, Decodable, Debug)]
pub enum InlineAttr {
None,
Hint,
@@ -75,13 +74,13 @@
Never,
}
-#[derive(Clone, Encodable, Decodable)]
+#[derive(Clone, Encodable, Decodable, Debug, PartialEq, Eq)]
pub enum InstructionSetAttr {
ArmA32,
ArmT32,
}
-#[derive(Clone, Encodable, Decodable)]
+#[derive(Clone, Encodable, Decodable, Debug)]
pub enum OptimizeAttr {
None,
Speed,
@@ -526,6 +525,26 @@
}
}
+#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
+struct Version {
+ major: u16,
+ minor: u16,
+ patch: u16,
+}
+
+fn parse_version(s: &str, allow_appendix: bool) -> Option<Version> {
+ let mut components = s.split('-');
+ let d = components.next()?;
+ if !allow_appendix && components.next().is_some() {
+ return None;
+ }
+ let mut digits = d.splitn(3, '.');
+ let major = digits.next()?.parse().ok()?;
+ let minor = digits.next()?.parse().ok()?;
+ let patch = digits.next().unwrap_or("0").parse().ok()?;
+ Some(Version { major, minor, patch })
+}
+
/// Evaluate a cfg-like condition (with `any` and `all`), using `eval` to
/// evaluate individual items.
pub fn eval_condition(
@@ -555,19 +574,26 @@
return false;
}
};
- let min_version = match Version::parse(&min_version.as_str()) {
+ let min_version = match parse_version(&min_version.as_str(), false) {
Some(ver) => ver,
None => {
- sess.span_diagnostic.struct_span_err(*span, "invalid version literal").emit();
+ sess.span_diagnostic
+ .struct_span_warn(
+ *span,
+ "unknown version literal format, assuming it refers to a future version",
+ )
+ .emit();
return false;
}
};
- let channel = env!("CFG_RELEASE_CHANNEL");
- let nightly = channel == "nightly" || channel == "dev";
- let rustc_version = Version::parse(env!("CFG_RELEASE")).unwrap();
+ let rustc_version = parse_version(env!("CFG_RELEASE"), true).unwrap();
- // See https://github.com/rust-lang/rust/issues/64796#issuecomment-625474439 for details
- if nightly { rustc_version > min_version } else { rustc_version >= min_version }
+ // See https://github.com/rust-lang/rust/issues/64796#issuecomment-640851454 for details
+ if sess.assume_incomplete_release {
+ rustc_version > min_version
+ } else {
+ rustc_version >= min_version
+ }
}
ast::MetaItemKind::List(ref mis) => {
for mi in mis.iter() {
diff --git a/compiler/rustc_builtin_macros/src/assert.rs b/compiler/rustc_builtin_macros/src/assert.rs
index bb6d3f6..93ba54d 100644
--- a/compiler/rustc_builtin_macros/src/assert.rs
+++ b/compiler/rustc_builtin_macros/src/assert.rs
@@ -12,27 +12,43 @@
pub fn expand_assert<'cx>(
cx: &'cx mut ExtCtxt<'_>,
- sp: Span,
+ span: Span,
tts: TokenStream,
) -> Box<dyn MacResult + 'cx> {
- let Assert { cond_expr, custom_message } = match parse_assert(cx, sp, tts) {
+ let Assert { cond_expr, custom_message } = match parse_assert(cx, span, tts) {
Ok(assert) => assert,
Err(mut err) => {
err.emit();
- return DummyResult::any(sp);
+ return DummyResult::any(span);
}
};
// `core::panic` and `std::panic` are different macros, so we use call-site
// context to pick up whichever is currently in scope.
- let sp = cx.with_call_site_ctxt(sp);
+ let sp = cx.with_call_site_ctxt(span);
let panic_call = if let Some(tokens) = custom_message {
+ let path = if span.rust_2021() {
+ // On edition 2021, we always call `$crate::panic::panic_2021!()`.
+ Path {
+ span: sp,
+ segments: cx
+ .std_path(&[sym::panic, sym::panic_2021])
+ .into_iter()
+ .map(|ident| PathSegment::from_ident(ident))
+ .collect(),
+ tokens: None,
+ }
+ } else {
+ // Before edition 2021, we call `panic!()` unqualified,
+ // such that it calls either `std::panic!()` or `core::panic!()`.
+ Path::from_ident(Ident::new(sym::panic, sp))
+ };
// Pass the custom message to panic!().
cx.expr(
sp,
ExprKind::MacCall(MacCall {
- path: Path::from_ident(Ident::new(sym::panic, sp)),
+ path,
args: P(MacArgs::Delimited(
DelimSpan::from_single(sp),
MacDelimiter::Parenthesis,
diff --git a/compiler/rustc_builtin_macros/src/deriving/clone.rs b/compiler/rustc_builtin_macros/src/deriving/clone.rs
index 957c803..ca1226b 100644
--- a/compiler/rustc_builtin_macros/src/deriving/clone.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/clone.rs
@@ -38,10 +38,9 @@
| ItemKind::Enum(_, Generics { ref params, .. }) => {
let container_id = cx.current_expansion.id.expn_data().parent;
if cx.resolver.has_derive_copy(container_id)
- && !params.iter().any(|param| match param.kind {
- ast::GenericParamKind::Type { .. } => true,
- _ => false,
- })
+ && !params
+ .iter()
+ .any(|param| matches!(param.kind, ast::GenericParamKind::Type { .. }))
{
bounds = vec![];
is_shallow = true;
diff --git a/compiler/rustc_builtin_macros/src/deriving/debug.rs b/compiler/rustc_builtin_macros/src/deriving/debug.rs
index 5c21329..ba43be6 100644
--- a/compiler/rustc_builtin_macros/src/deriving/debug.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/debug.rs
@@ -8,6 +8,10 @@
use rustc_span::symbol::{sym, Ident};
use rustc_span::{Span, DUMMY_SP};
+fn make_mut_borrow(cx: &mut ExtCtxt<'_>, sp: Span, expr: P<Expr>) -> P<Expr> {
+ cx.expr(sp, ast::ExprKind::AddrOf(ast::BorrowKind::Ref, ast::Mutability::Mut, expr))
+}
+
pub fn expand_deriving_debug(
cx: &mut ExtCtxt<'_>,
span: Span,
@@ -67,11 +71,12 @@
let fmt = substr.nonself_args[0].clone();
let mut stmts = Vec::with_capacity(fields.len() + 2);
+ let fn_path_finish;
match vdata {
ast::VariantData::Tuple(..) | ast::VariantData::Unit(..) => {
// tuple struct/"normal" variant
- let expr =
- cx.expr_method_call(span, fmt, Ident::new(sym::debug_tuple, span), vec![name]);
+ let fn_path_debug_tuple = cx.std_path(&[sym::fmt, sym::Formatter, sym::debug_tuple]);
+ let expr = cx.expr_call_global(span, fn_path_debug_tuple, vec![fmt, name]);
stmts.push(cx.stmt_let(span, true, builder, expr));
for field in fields {
@@ -79,22 +84,21 @@
let field = cx.expr_addr_of(field.span, field.self_.clone());
let field = cx.expr_addr_of(field.span, field);
- let expr = cx.expr_method_call(
- span,
- builder_expr.clone(),
- Ident::new(sym::field, span),
- vec![field],
- );
+ let fn_path_field = cx.std_path(&[sym::fmt, sym::DebugTuple, sym::field]);
+ let builder_recv = make_mut_borrow(cx, span, builder_expr.clone());
+ let expr = cx.expr_call_global(span, fn_path_field, vec![builder_recv, field]);
// Use `let _ = expr;` to avoid triggering the
// unused_results lint.
stmts.push(stmt_let_underscore(cx, span, expr));
}
+
+ fn_path_finish = cx.std_path(&[sym::fmt, sym::DebugTuple, sym::finish]);
}
ast::VariantData::Struct(..) => {
// normal struct/struct variant
- let expr =
- cx.expr_method_call(span, fmt, Ident::new(sym::debug_struct, span), vec![name]);
+ let fn_path_debug_struct = cx.std_path(&[sym::fmt, sym::Formatter, sym::debug_struct]);
+ let expr = cx.expr_call_global(span, fn_path_debug_struct, vec![fmt, name]);
stmts.push(cx.stmt_let(DUMMY_SP, true, builder, expr));
for field in fields {
@@ -104,20 +108,20 @@
);
// Use double indirection to make sure this works for unsized types
+ let fn_path_field = cx.std_path(&[sym::fmt, sym::DebugStruct, sym::field]);
let field = cx.expr_addr_of(field.span, field.self_.clone());
let field = cx.expr_addr_of(field.span, field);
- let expr = cx.expr_method_call(
- span,
- builder_expr.clone(),
- Ident::new(sym::field, span),
- vec![name, field],
- );
+ let builder_recv = make_mut_borrow(cx, span, builder_expr.clone());
+ let expr =
+ cx.expr_call_global(span, fn_path_field, vec![builder_recv, name, field]);
stmts.push(stmt_let_underscore(cx, span, expr));
}
+ fn_path_finish = cx.std_path(&[sym::fmt, sym::DebugStruct, sym::finish]);
}
}
- let expr = cx.expr_method_call(span, builder_expr, Ident::new(sym::finish, span), vec![]);
+ let builder_recv = make_mut_borrow(cx, span, builder_expr);
+ let expr = cx.expr_call_global(span, fn_path_finish, vec![builder_recv]);
stmts.push(cx.stmt_expr(expr));
let block = cx.block(span, stmts);
diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
index 6531e68..d498c8e 100644
--- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
@@ -404,12 +404,10 @@
let has_no_type_params = match item.kind {
ast::ItemKind::Struct(_, ref generics)
| ast::ItemKind::Enum(_, ref generics)
- | ast::ItemKind::Union(_, ref generics) => {
- !generics.params.iter().any(|param| match param.kind {
- ast::GenericParamKind::Type { .. } => true,
- _ => false,
- })
- }
+ | ast::ItemKind::Union(_, ref generics) => !generics
+ .params
+ .iter()
+ .any(|param| matches!(param.kind, ast::GenericParamKind::Type { .. })),
_ => unreachable!(),
};
let container_id = cx.current_expansion.id.expn_data().parent;
@@ -529,12 +527,12 @@
tokens: None,
},
attrs: Vec::new(),
- kind: ast::AssocItemKind::TyAlias(
+ kind: ast::AssocItemKind::TyAlias(box ast::TyAliasKind(
ast::Defaultness::Final,
Generics::default(),
Vec::new(),
Some(type_def.to_ty(cx, self.span, type_ident, generics)),
- ),
+ )),
tokens: None,
})
});
@@ -600,7 +598,7 @@
let mut ty_params = params
.iter()
- .filter(|param| matches!(param.kind, ast::GenericParamKind::Type{..}))
+ .filter(|param| matches!(param.kind, ast::GenericParamKind::Type { .. }))
.peekable();
if ty_params.peek().is_some() {
@@ -689,7 +687,7 @@
self.span,
Ident::invalid(),
a,
- ast::ItemKind::Impl {
+ ast::ItemKind::Impl(box ast::ImplKind {
unsafety,
polarity: ast::ImplPolarity::Positive,
defaultness: ast::Defaultness::Final,
@@ -698,7 +696,7 @@
of_trait: opt_trait_ref,
self_ty: self_type,
items: methods.into_iter().chain(associated_types).collect(),
- },
+ }),
)
}
@@ -868,7 +866,7 @@
Self_ if nonstatic => {
self_args.push(arg_expr);
}
- Ptr(ref ty, _) if (if let Self_ = **ty { true } else { false }) && nonstatic => {
+ Ptr(ref ty, _) if matches!(**ty, Self_) && nonstatic => {
self_args.push(cx.expr_deref(trait_.span, arg_expr))
}
_ => {
@@ -931,7 +929,7 @@
tokens: None,
},
ident: method_ident,
- kind: ast::AssocItemKind::Fn(def, sig, fn_generics, Some(body_block)),
+ kind: ast::AssocItemKind::Fn(box ast::FnKind(def, sig, fn_generics, Some(body_block))),
tokens: None,
})
}
diff --git a/compiler/rustc_builtin_macros/src/deriving/hash.rs b/compiler/rustc_builtin_macros/src/deriving/hash.rs
index 868f863..7114b98 100644
--- a/compiler/rustc_builtin_macros/src/deriving/hash.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/hash.rs
@@ -48,8 +48,8 @@
}
fn hash_substructure(cx: &mut ExtCtxt<'_>, trait_span: Span, substr: &Substructure<'_>) -> P<Expr> {
- let state_expr = match &substr.nonself_args {
- &[o_f] => o_f,
+ let state_expr = match substr.nonself_args {
+ [o_f] => o_f,
_ => cx.span_bug(trait_span, "incorrect number of arguments in `derive(Hash)`"),
};
let call_hash = |span, thing_expr| {
@@ -64,9 +64,9 @@
};
let mut stmts = Vec::new();
- let fields = match *substr.fields {
- Struct(_, ref fs) | EnumMatching(_, 1, .., ref fs) => fs,
- EnumMatching(.., ref fs) => {
+ let fields = match substr.fields {
+ Struct(_, fs) | EnumMatching(_, 1, .., fs) => fs,
+ EnumMatching(.., fs) => {
let variant_value = deriving::call_intrinsic(
cx,
trait_span,
diff --git a/compiler/rustc_builtin_macros/src/deriving/mod.rs b/compiler/rustc_builtin_macros/src/deriving/mod.rs
index 1651180..7dea609 100644
--- a/compiler/rustc_builtin_macros/src/deriving/mod.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/mod.rs
@@ -2,7 +2,7 @@
use rustc_ast as ast;
use rustc_ast::ptr::P;
-use rustc_ast::{ItemKind, MetaItem};
+use rustc_ast::{ImplKind, ItemKind, MetaItem};
use rustc_expand::base::{Annotatable, ExpandResult, ExtCtxt, MultiItemModifier};
use rustc_span::symbol::{sym, Ident, Symbol};
use rustc_span::Span;
@@ -145,7 +145,8 @@
*default = None;
ast::GenericArg::Type(cx.ty_ident(span, param.ident))
}
- ast::GenericParamKind::Const { ty: _, kw_span: _ } => {
+ ast::GenericParamKind::Const { ty: _, kw_span: _, default } => {
+ *default = None;
ast::GenericArg::Const(cx.const_ident(span, param.ident))
}
})
@@ -178,7 +179,7 @@
span,
Ident::invalid(),
attrs,
- ItemKind::Impl {
+ ItemKind::Impl(box ImplKind {
unsafety: ast::Unsafe::No,
polarity: ast::ImplPolarity::Positive,
defaultness: ast::Defaultness::Final,
@@ -187,7 +188,7 @@
of_trait: Some(trait_ref),
self_ty: self_type,
items: Vec::new(),
- },
+ }),
);
push(Annotatable::Item(newitem));
diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs
index 550524e..85ca1da 100644
--- a/compiler/rustc_builtin_macros/src/format.rs
+++ b/compiler/rustc_builtin_macros/src/format.rs
@@ -1044,10 +1044,7 @@
let numbered_position_args = pieces.iter().any(|arg: &parse::Piece<'_>| match *arg {
parse::String(_) => false,
- parse::NextArgument(arg) => match arg.position {
- parse::Position::ArgumentIs(_) => true,
- _ => false,
- },
+ parse::NextArgument(arg) => matches!(arg.position, parse::Position::ArgumentIs(_)),
});
cx.build_index_map();
diff --git a/compiler/rustc_builtin_macros/src/format_foreign.rs b/compiler/rustc_builtin_macros/src/format_foreign.rs
index f00dfd1..0496c72 100644
--- a/compiler/rustc_builtin_macros/src/format_foreign.rs
+++ b/compiler/rustc_builtin_macros/src/format_foreign.rs
@@ -580,10 +580,7 @@
}
fn is_flag(c: &char) -> bool {
- match c {
- '0' | '-' | '+' | ' ' | '#' | '\'' => true,
- _ => false,
- }
+ matches!(c, '0' | '-' | '+' | ' ' | '#' | '\'')
}
#[cfg(test)]
diff --git a/compiler/rustc_builtin_macros/src/global_allocator.rs b/compiler/rustc_builtin_macros/src/global_allocator.rs
index e976805..9b43c11 100644
--- a/compiler/rustc_builtin_macros/src/global_allocator.rs
+++ b/compiler/rustc_builtin_macros/src/global_allocator.rs
@@ -5,7 +5,7 @@
};
use rustc_ast::ptr::P;
use rustc_ast::{self as ast, Attribute, Expr, FnHeader, FnSig, Generics, Param, StmtKind};
-use rustc_ast::{ItemKind, Mutability, Stmt, Ty, TyKind, Unsafe};
+use rustc_ast::{FnKind, ItemKind, Mutability, Stmt, Ty, TyKind, Unsafe};
use rustc_expand::base::{Annotatable, ExtCtxt};
use rustc_span::symbol::{kw, sym, Ident, Symbol};
use rustc_span::Span;
@@ -85,7 +85,8 @@
let header = FnHeader { unsafety: Unsafe::Yes(self.span), ..FnHeader::default() };
let sig = FnSig { decl, header, span: self.span };
let block = Some(self.cx.block_expr(output_expr));
- let kind = ItemKind::Fn(ast::Defaultness::Final, sig, Generics::default(), block);
+ let kind =
+ ItemKind::Fn(box FnKind(ast::Defaultness::Final, sig, Generics::default(), block));
let item = self.cx.item(
self.span,
Ident::from_str_and_span(&self.kind.fn_name(method.name), self.span),
diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs
index 97cadb9..59844b6 100644
--- a/compiler/rustc_builtin_macros/src/lib.rs
+++ b/compiler/rustc_builtin_macros/src/lib.rs
@@ -2,6 +2,8 @@
//! injecting code into the crate before it is lowered to HIR.
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
+#![feature(box_patterns)]
+#![feature(box_syntax)]
#![feature(bool_to_option)]
#![feature(crate_visibility_modifier)]
#![feature(decl_macro)]
@@ -14,10 +16,9 @@
use crate::deriving::*;
-use rustc_expand::base::{MacroExpanderFn, ResolverExpand, SyntaxExtension, SyntaxExtensionKind};
+use rustc_expand::base::{MacroExpanderFn, ResolverExpand, SyntaxExtensionKind};
use rustc_expand::proc_macro::BangProcMacro;
-use rustc_span::edition::Edition;
-use rustc_span::symbol::{sym, Ident};
+use rustc_span::symbol::sym;
mod asm;
mod assert;
@@ -34,6 +35,7 @@
mod global_asm;
mod llvm_asm;
mod log_syntax;
+mod panic;
mod source_util;
mod test;
mod trace_macros;
@@ -44,13 +46,8 @@
pub mod standard_library_imports;
pub mod test_harness;
-pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand, edition: Edition) {
- let mut register = |name, kind| {
- resolver.register_builtin_macro(
- Ident::with_dummy_span(name),
- SyntaxExtension { is_builtin: true, ..SyntaxExtension::default(kind, edition) },
- )
- };
+pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) {
+ let mut register = |name, kind| resolver.register_builtin_macro(name, kind);
macro register_bang($($name:ident: $f:expr,)*) {
$(register(sym::$name, SyntaxExtensionKind::LegacyBang(Box::new($f as MacroExpanderFn)));)*
}
@@ -82,6 +79,8 @@
log_syntax: log_syntax::expand_log_syntax,
module_path: source_util::expand_mod,
option_env: env::expand_option_env,
+ core_panic: panic::expand_panic,
+ std_panic: panic::expand_panic,
stringify: source_util::expand_stringify,
trace_macros: trace_macros::expand_trace_macros,
}
diff --git a/compiler/rustc_builtin_macros/src/llvm_asm.rs b/compiler/rustc_builtin_macros/src/llvm_asm.rs
index db73fdb..d72bfa6 100644
--- a/compiler/rustc_builtin_macros/src/llvm_asm.rs
+++ b/compiler/rustc_builtin_macros/src/llvm_asm.rs
@@ -87,13 +87,15 @@
// parsed as `llvm_asm!(z)` with `z = "x": y` which is type ascription.
let first_colon = tts
.trees()
- .position(|tt| match tt {
- tokenstream::TokenTree::Token(Token { kind: token::Colon | token::ModSep, .. }) => true,
- _ => false,
+ .position(|tt| {
+ matches!(
+ tt,
+ tokenstream::TokenTree::Token(Token { kind: token::Colon | token::ModSep, .. })
+ )
})
.unwrap_or(tts.len());
let mut p = cx.new_parser_from_tts(tts.trees().skip(first_colon).collect());
- let mut asm = kw::Invalid;
+ let mut asm = kw::Empty;
let mut asm_str_style = None;
let mut outputs = Vec::new();
let mut inputs = Vec::new();
diff --git a/compiler/rustc_builtin_macros/src/panic.rs b/compiler/rustc_builtin_macros/src/panic.rs
new file mode 100644
index 0000000..6f5962d
--- /dev/null
+++ b/compiler/rustc_builtin_macros/src/panic.rs
@@ -0,0 +1,48 @@
+use rustc_ast::ptr::P;
+use rustc_ast::tokenstream::{DelimSpan, TokenStream};
+use rustc_ast::*;
+use rustc_expand::base::*;
+use rustc_span::symbol::sym;
+use rustc_span::Span;
+
+// This expands to either
+// - `$crate::panic::panic_2015!(...)` or
+// - `$crate::panic::panic_2021!(...)`
+// depending on the edition.
+//
+// This is used for both std::panic!() and core::panic!().
+//
+// `$crate` will refer to either the `std` or `core` crate depending on which
+// one we're expanding from.
+pub fn expand_panic<'cx>(
+ cx: &'cx mut ExtCtxt<'_>,
+ sp: Span,
+ tts: TokenStream,
+) -> Box<dyn MacResult + 'cx> {
+ let panic = if sp.rust_2021() { sym::panic_2021 } else { sym::panic_2015 };
+
+ let sp = cx.with_call_site_ctxt(sp);
+
+ MacEager::expr(
+ cx.expr(
+ sp,
+ ExprKind::MacCall(MacCall {
+ path: Path {
+ span: sp,
+ segments: cx
+ .std_path(&[sym::panic, panic])
+ .into_iter()
+ .map(|ident| PathSegment::from_ident(ident))
+ .collect(),
+ tokens: None,
+ },
+ args: P(MacArgs::Delimited(
+ DelimSpan::from_single(sp),
+ MacDelimiter::Parenthesis,
+ tts,
+ )),
+ prior_type_ascription: None,
+ }),
+ ),
+ )
+}
diff --git a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs
index 4e91436..7582d98 100644
--- a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs
+++ b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs
@@ -256,10 +256,7 @@
// we're just not interested in this item.
//
// If we find one, try to locate a `#[proc_macro_derive]` attribute on it.
- let is_fn = match item.kind {
- ast::ItemKind::Fn(..) => true,
- _ => false,
- };
+ let is_fn = matches!(item.kind, ast::ItemKind::Fn(..));
let mut found_attr: Option<&'a ast::Attribute> = None;
diff --git a/compiler/rustc_builtin_macros/src/source_util.rs b/compiler/rustc_builtin_macros/src/source_util.rs
index f76bbd8..28efd48 100644
--- a/compiler/rustc_builtin_macros/src/source_util.rs
+++ b/compiler/rustc_builtin_macros/src/source_util.rs
@@ -5,7 +5,8 @@
use rustc_ast_pretty::pprust;
use rustc_expand::base::{self, *};
use rustc_expand::module::DirectoryOwnership;
-use rustc_parse::{self, new_parser_from_file, parser::Parser};
+use rustc_parse::parser::{ForceCollect, Parser};
+use rustc_parse::{self, new_parser_from_file};
use rustc_session::lint::builtin::INCOMPLETE_INCLUDE;
use rustc_span::symbol::Symbol;
use rustc_span::{self, Pos, Span};
@@ -139,7 +140,7 @@
fn make_items(mut self: Box<ExpandResult<'a>>) -> Option<SmallVec<[P<ast::Item>; 1]>> {
let mut ret = SmallVec::new();
while self.p.token != token::Eof {
- match self.p.parse_item() {
+ match self.p.parse_item(ForceCollect::No) {
Err(mut err) => {
err.emit();
break;
diff --git a/compiler/rustc_builtin_macros/src/test.rs b/compiler/rustc_builtin_macros/src/test.rs
index 25d3f46d..e845f9e 100644
--- a/compiler/rustc_builtin_macros/src/test.rs
+++ b/compiler/rustc_builtin_macros/src/test.rs
@@ -425,7 +425,7 @@
fn has_test_signature(cx: &ExtCtxt<'_>, i: &ast::Item) -> bool {
let has_should_panic_attr = cx.sess.contains_name(&i.attrs, sym::should_panic);
let sd = &cx.sess.parse_sess.span_diagnostic;
- if let ast::ItemKind::Fn(_, ref sig, ref generics, _) = i.kind {
+ if let ast::ItemKind::Fn(box ast::FnKind(_, ref sig, ref generics, _)) = i.kind {
if let ast::Unsafe::Yes(span) = sig.header.unsafety {
sd.struct_span_err(i.span, "unsafe functions cannot be used for tests")
.span_label(span, "`unsafe` because of this")
@@ -474,7 +474,7 @@
}
fn has_bench_signature(cx: &ExtCtxt<'_>, i: &ast::Item) -> bool {
- let has_sig = if let ast::ItemKind::Fn(_, ref sig, _, _) = i.kind {
+ let has_sig = if let ast::ItemKind::Fn(box ast::FnKind(_, ref sig, _, _)) = i.kind {
// N.B., inadequate check, but we're running
// well before resolve, can't get too deep.
sig.decl.inputs.len() == 1
diff --git a/compiler/rustc_builtin_macros/src/test_harness.rs b/compiler/rustc_builtin_macros/src/test_harness.rs
index 9976140..4ac22be 100644
--- a/compiler/rustc_builtin_macros/src/test_harness.rs
+++ b/compiler/rustc_builtin_macros/src/test_harness.rs
@@ -311,7 +311,8 @@
let decl = ecx.fn_decl(vec![], ast::FnRetTy::Ty(main_ret_ty));
let sig = ast::FnSig { decl, header: ast::FnHeader::default(), span: sp };
let def = ast::Defaultness::Final;
- let main = ast::ItemKind::Fn(def, sig, ast::Generics::default(), Some(main_body));
+ let main =
+ ast::ItemKind::Fn(box ast::FnKind(def, sig, ast::Generics::default(), Some(main_body)));
// Honor the reexport_test_harness_main attribute
let main_id = match cx.reexport_test_harness_main {
diff --git a/compiler/rustc_codegen_cranelift/.github/workflows/main.yml b/compiler/rustc_codegen_cranelift/.github/workflows/main.yml
index e6d3375..20c5842 100644
--- a/compiler/rustc_codegen_cranelift/.github/workflows/main.yml
+++ b/compiler/rustc_codegen_cranelift/.github/workflows/main.yml
@@ -12,6 +12,9 @@
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest]
+ env:
+ - BACKEND: ""
+ - BACKEND: --oldbe
steps:
- uses: actions/checkout@v2
@@ -51,7 +54,7 @@
export COMPILE_RUNS=2
export RUN_RUNS=2
- ./test.sh
+ ./test.sh $BACKEND
- name: Package prebuilt cg_clif
run: tar cvfJ cg_clif.tar.xz build
diff --git a/compiler/rustc_codegen_cranelift/.vscode/settings.json b/compiler/rustc_codegen_cranelift/.vscode/settings.json
index 04ab508..19ea415 100644
--- a/compiler/rustc_codegen_cranelift/.vscode/settings.json
+++ b/compiler/rustc_codegen_cranelift/.vscode/settings.json
@@ -1,6 +1,7 @@
{
// source for rustc_* is not included in the rust-src component; disable the errors about this
"rust-analyzer.diagnostics.disabled": ["unresolved-extern-crate"],
+ "rust-analyzer.assist.importMergeBehavior": "last",
"rust-analyzer.cargo.loadOutDirsFromCheck": true,
"rust-analyzer.linkedProjects": [
"./Cargo.toml",
diff --git a/compiler/rustc_codegen_cranelift/Cargo.lock b/compiler/rustc_codegen_cranelift/Cargo.lock
index 67ed41e..5495cfa 100644
--- a/compiler/rustc_codegen_cranelift/Cargo.lock
+++ b/compiler/rustc_codegen_cranelift/Cargo.lock
@@ -2,9 +2,9 @@
# It is not intended for manual editing.
[[package]]
name = "anyhow"
-version = "1.0.34"
+version = "1.0.38"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bf8dcb5b4bbaa28653b647d8c77bd4ed40183b48882e130c1f1ffb73de069fd7"
+checksum = "afddf7f520a80dbf76e6f50a35bca42a2331ef227a28b3b6dc5c2e2338d114b1"
[[package]]
name = "ar"
@@ -25,15 +25,15 @@
[[package]]
name = "byteorder"
-version = "1.3.4"
+version = "1.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de"
+checksum = "ae44d1a3d5a19df61dd0c8beb138458ac2a53a7ac09eba97d55592540004306b"
[[package]]
name = "cc"
-version = "1.0.62"
+version = "1.0.66"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f1770ced377336a88a67c473594ccc14eca6f4559217c34f64aac8f83d641b40"
+checksum = "4c0496836a84f8d0495758516b8621a622beb77c0fed418570e50764093ced48"
[[package]]
name = "cfg-if"
@@ -49,16 +49,16 @@
[[package]]
name = "cranelift-bforest"
-version = "0.68.0"
-source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#19640367dbf0da7093e61add3306c8d092644fb3"
+version = "0.69.0"
+source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#986b5768f9e68f1564b43f32b8a4080a6582c8ca"
dependencies = [
"cranelift-entity",
]
[[package]]
name = "cranelift-codegen"
-version = "0.68.0"
-source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#19640367dbf0da7093e61add3306c8d092644fb3"
+version = "0.69.0"
+source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#986b5768f9e68f1564b43f32b8a4080a6582c8ca"
dependencies = [
"byteorder",
"cranelift-bforest",
@@ -75,8 +75,8 @@
[[package]]
name = "cranelift-codegen-meta"
-version = "0.68.0"
-source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#19640367dbf0da7093e61add3306c8d092644fb3"
+version = "0.69.0"
+source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#986b5768f9e68f1564b43f32b8a4080a6582c8ca"
dependencies = [
"cranelift-codegen-shared",
"cranelift-entity",
@@ -84,18 +84,18 @@
[[package]]
name = "cranelift-codegen-shared"
-version = "0.68.0"
-source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#19640367dbf0da7093e61add3306c8d092644fb3"
+version = "0.69.0"
+source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#986b5768f9e68f1564b43f32b8a4080a6582c8ca"
[[package]]
name = "cranelift-entity"
-version = "0.68.0"
-source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#19640367dbf0da7093e61add3306c8d092644fb3"
+version = "0.69.0"
+source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#986b5768f9e68f1564b43f32b8a4080a6582c8ca"
[[package]]
name = "cranelift-frontend"
-version = "0.68.0"
-source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#19640367dbf0da7093e61add3306c8d092644fb3"
+version = "0.69.0"
+source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#986b5768f9e68f1564b43f32b8a4080a6582c8ca"
dependencies = [
"cranelift-codegen",
"log",
@@ -104,47 +104,13 @@
]
[[package]]
-name = "cranelift-module"
-version = "0.68.0"
-source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#19640367dbf0da7093e61add3306c8d092644fb3"
+name = "cranelift-jit"
+version = "0.69.0"
+source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#986b5768f9e68f1564b43f32b8a4080a6582c8ca"
dependencies = [
"anyhow",
"cranelift-codegen",
"cranelift-entity",
- "log",
- "thiserror",
-]
-
-[[package]]
-name = "cranelift-native"
-version = "0.68.0"
-source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#19640367dbf0da7093e61add3306c8d092644fb3"
-dependencies = [
- "cranelift-codegen",
- "raw-cpuid",
- "target-lexicon",
-]
-
-[[package]]
-name = "cranelift-object"
-version = "0.68.0"
-source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#19640367dbf0da7093e61add3306c8d092644fb3"
-dependencies = [
- "anyhow",
- "cranelift-codegen",
- "cranelift-module",
- "log",
- "object",
- "target-lexicon",
-]
-
-[[package]]
-name = "cranelift-simplejit"
-version = "0.68.0"
-source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#19640367dbf0da7093e61add3306c8d092644fb3"
-dependencies = [
- "cranelift-codegen",
- "cranelift-entity",
"cranelift-module",
"cranelift-native",
"errno",
@@ -156,6 +122,41 @@
]
[[package]]
+name = "cranelift-module"
+version = "0.69.0"
+source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#986b5768f9e68f1564b43f32b8a4080a6582c8ca"
+dependencies = [
+ "anyhow",
+ "cranelift-codegen",
+ "cranelift-entity",
+ "log",
+ "thiserror",
+]
+
+[[package]]
+name = "cranelift-native"
+version = "0.69.0"
+source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#986b5768f9e68f1564b43f32b8a4080a6582c8ca"
+dependencies = [
+ "cranelift-codegen",
+ "raw-cpuid",
+ "target-lexicon",
+]
+
+[[package]]
+name = "cranelift-object"
+version = "0.69.0"
+source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#986b5768f9e68f1564b43f32b8a4080a6582c8ca"
+dependencies = [
+ "anyhow",
+ "cranelift-codegen",
+ "cranelift-module",
+ "log",
+ "object",
+ "target-lexicon",
+]
+
+[[package]]
name = "crc32fast"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -208,9 +209,9 @@
[[package]]
name = "indexmap"
-version = "1.6.0"
+version = "1.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "55e2e4c765aa53a0424761bf9f41aa7a6ac1efa87238f59560640e27fca028f2"
+checksum = "4fb1fa934250de4de8aef298d81c729a7d33d8c239daa3a7575e6b92bfc7313b"
dependencies = [
"autocfg",
"hashbrown",
@@ -218,15 +219,15 @@
[[package]]
name = "libc"
-version = "0.2.80"
+version = "0.2.82"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4d58d1b70b004888f764dfbf6a26a3b0342a1632d33968e4a179d8011c760614"
+checksum = "89203f3fba0a3795506acaad8ebce3c80c0af93f994d5a1d7a0b1eeb23271929"
[[package]]
name = "libloading"
-version = "0.6.5"
+version = "0.6.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1090080fe06ec2648d0da3881d9453d97e71a45f00eb179af7fdd7e3f686fdb0"
+checksum = "351a32417a12d5f7e82c368a66781e307834dae04c6ce0cd4456d52989229883"
dependencies = [
"cfg-if 1.0.0",
"winapi",
@@ -234,9 +235,9 @@
[[package]]
name = "log"
-version = "0.4.11"
+version = "0.4.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4fabed175da42fed1fa0746b0ea71f412aa9d35e76e95e59b192c64b9dc2bf8b"
+checksum = "fcf3805d4480bb5b86070dcfeb9e2cb2ebc148adb753c5cca5f884d1d65a42b2"
dependencies = [
"cfg-if 0.1.10",
]
@@ -271,9 +272,9 @@
[[package]]
name = "quote"
-version = "1.0.7"
+version = "1.0.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37"
+checksum = "991431c3519a3f36861882da93630ce66b52918dcf1b8e2fd66b397fc96f28df"
dependencies = [
"proc-macro2",
]
@@ -325,13 +326,14 @@
"ar",
"cranelift-codegen",
"cranelift-frontend",
+ "cranelift-jit",
"cranelift-module",
"cranelift-object",
- "cranelift-simplejit",
"gimli",
"indexmap",
"libloading",
"object",
+ "smallvec",
"target-lexicon",
]
@@ -361,15 +363,15 @@
[[package]]
name = "smallvec"
-version = "1.4.2"
+version = "1.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fbee7696b84bbf3d89a1c2eccff0850e3047ed46bfcd2e92c29a2d074d57e252"
+checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e"
[[package]]
name = "syn"
-version = "1.0.48"
+version = "1.0.58"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cc371affeffc477f42a221a1e4297aedcea33d47d19b61455588bd9d8f6b19ac"
+checksum = "cc60a3d73ea6594cd712d830cc1f0390fd71542d8c8cd24e70cc54cdfd5e05d5"
dependencies = [
"proc-macro2",
"quote",
@@ -384,18 +386,18 @@
[[package]]
name = "thiserror"
-version = "1.0.22"
+version = "1.0.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0e9ae34b84616eedaaf1e9dd6026dbe00dcafa92aa0c8077cb69df1fcfe5e53e"
+checksum = "76cc616c6abf8c8928e2fdcc0dbfab37175edd8fb49a4641066ad1364fdab146"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
-version = "1.0.22"
+version = "1.0.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9ba20f23e85b10754cd195504aebf6a27e2e6cbe28c17778a0c930724628dd56"
+checksum = "9be73a2caec27583d0046ef3796c3794f868a5bc813db689eed00c7631275cd1"
dependencies = [
"proc-macro2",
"quote",
diff --git a/compiler/rustc_codegen_cranelift/Cargo.toml b/compiler/rustc_codegen_cranelift/Cargo.toml
index cbff067..3820fce 100644
--- a/compiler/rustc_codegen_cranelift/Cargo.toml
+++ b/compiler/rustc_codegen_cranelift/Cargo.toml
@@ -9,10 +9,10 @@
[dependencies]
# These have to be in sync with each other
-cranelift-codegen = { git = "https://github.com/bytecodealliance/wasmtime/", branch = "main", features = ["unwind"] }
+cranelift-codegen = { git = "https://github.com/bytecodealliance/wasmtime/", branch = "main", features = ["unwind", "x86", "x64"] }
cranelift-frontend = { git = "https://github.com/bytecodealliance/wasmtime/", branch = "main" }
cranelift-module = { git = "https://github.com/bytecodealliance/wasmtime/", branch = "main" }
-cranelift-simplejit = { git = "https://github.com/bytecodealliance/wasmtime/", branch = "main", optional = true }
+cranelift-jit = { git = "https://github.com/bytecodealliance/wasmtime/", branch = "main", optional = true }
cranelift-object = { git = "https://github.com/bytecodealliance/wasmtime/", branch = "main" }
target-lexicon = "0.11.0"
gimli = { version = "0.23.0", default-features = false, features = ["write"]}
@@ -21,13 +21,14 @@
ar = { git = "https://github.com/bjorn3/rust-ar.git", branch = "do_not_remove_cg_clif_ranlib" }
indexmap = "1.0.2"
libloading = { version = "0.6.0", optional = true }
+smallvec = "1.6.1"
# Uncomment to use local checkout of cranelift
#[patch."https://github.com/bytecodealliance/wasmtime/"]
#cranelift-codegen = { path = "../wasmtime/cranelift/codegen" }
#cranelift-frontend = { path = "../wasmtime/cranelift/frontend" }
#cranelift-module = { path = "../wasmtime/cranelift/module" }
-#cranelift-simplejit = { path = "../wasmtime/cranelift/simplejit" }
+#cranelift-jit = { path = "../wasmtime/cranelift/jit" }
#cranelift-object = { path = "../wasmtime/cranelift/object" }
#[patch.crates-io]
@@ -35,8 +36,9 @@
[features]
default = ["jit", "inline_asm"]
-jit = ["cranelift-simplejit", "libloading"]
+jit = ["cranelift-jit", "libloading"]
inline_asm = []
+oldbe = []
[profile.dev]
# By compiling dependencies with optimizations, performing tests gets much faster.
diff --git a/compiler/rustc_codegen_cranelift/Readme.md b/compiler/rustc_codegen_cranelift/Readme.md
index de54bf6..6fa5eeb 100644
--- a/compiler/rustc_codegen_cranelift/Readme.md
+++ b/compiler/rustc_codegen_cranelift/Readme.md
@@ -1,8 +1,6 @@
-# WIP Cranelift codegen backend for rust
+# Cranelift codegen backend for rust
-> âš âš âš Certain kinds of FFI don't work yet. âš âš âš
-
-The goal of this project is to create an alternative codegen backend for the rust compiler based on [Cranelift](https://github.com/bytecodealliance/wasmtime/blob/master/cranelift).
+The goal of this project is to create an alternative codegen backend for the rust compiler based on [Cranelift](https://github.com/bytecodealliance/wasmtime/blob/main/cranelift).
This has the potential to improve compilation times in debug mode.
If your project doesn't use any of the things listed under "Not yet supported", it should work fine.
If not please open an issue.
@@ -68,7 +66,15 @@
or
```bash
-$ $cg_clif_dir/build/bin/cg_clif --jit my_crate.rs
+$ $cg_clif_dir/build/bin/cg_clif -Cllvm-args=mode=jit -Cprefer-dynamic my_crate.rs
+```
+
+There is also an experimental lazy jit mode. In this mode functions are only compiled once they are
+first called. It currently does not work with multi-threaded programs. When a not yet compiled
+function is called from another thread than the main thread, you will get an ICE.
+
+```bash
+$ $cg_clif_dir/build/cargo.sh lazy-jit
```
### Shell
@@ -77,7 +83,7 @@
```bash
function jit_naked() {
- echo "$@" | $cg_clif_dir/build/bin/cg_clif - --jit
+ echo "$@" | $cg_clif_dir/build/bin/cg_clif - -Cllvm-args=mode=jit -Cprefer-dynamic
}
function jit() {
@@ -95,8 +101,7 @@
## Not yet supported
-* Good non-rust abi support ([several problems](https://github.com/bjorn3/rustc_codegen_cranelift/issues/10))
-* Inline assembly ([no cranelift support](https://github.com/bytecodealliance/wasmtime/issues/1041)
+* Inline assembly ([no cranelift support](https://github.com/bytecodealliance/wasmtime/issues/1041))
* On Linux there is support for invoking an external assembler for `global_asm!` and `asm!`.
`llvm_asm!` will remain unimplemented forever. `asm!` doesn't yet support reg classes. You
have to specify specific registers instead.
diff --git a/compiler/rustc_codegen_cranelift/build.sh b/compiler/rustc_codegen_cranelift/build.sh
index 26041b5..598ce35 100755
--- a/compiler/rustc_codegen_cranelift/build.sh
+++ b/compiler/rustc_codegen_cranelift/build.sh
@@ -3,23 +3,29 @@
# Settings
export CHANNEL="release"
-build_sysroot=1
+build_sysroot="clif"
target_dir='build'
+oldbe=''
while [[ $# != 0 ]]; do
case $1 in
"--debug")
export CHANNEL="debug"
;;
- "--without-sysroot")
- build_sysroot=0
+ "--sysroot")
+ build_sysroot=$2
+ shift
;;
"--target-dir")
target_dir=$2
shift
;;
+ "--oldbe")
+ oldbe='--features oldbe'
+ ;;
*)
echo "Unknown flag '$1'"
- echo "Usage: ./build.sh [--debug] [--without-sysroot] [--target-dir DIR]"
+ echo "Usage: ./build.sh [--debug] [--sysroot none|clif|llvm] [--target-dir DIR] [--oldbe]"
+ exit 1
;;
esac
shift
@@ -27,23 +33,24 @@
# Build cg_clif
unset CARGO_TARGET_DIR
-export RUSTFLAGS="-Zrun_dsymutil=no"
unamestr=$(uname)
if [[ "$unamestr" == 'Linux' ]]; then
export RUSTFLAGS='-Clink-arg=-Wl,-rpath=$ORIGIN/../lib '$RUSTFLAGS
elif [[ "$unamestr" == 'Darwin' ]]; then
- export RUSTFLAGS='-Clink-arg=-Wl,-rpath,@loader_path/../lib -Zosx-rpath-install-name '$RUSTFLAGS
+ export RUSTFLAGS='-Csplit-debuginfo=unpacked -Clink-arg=-Wl,-rpath,@loader_path/../lib -Zosx-rpath-install-name '$RUSTFLAGS
dylib_ext='dylib'
else
echo "Unsupported os"
exit 1
fi
if [[ "$CHANNEL" == "release" ]]; then
- cargo build --release
+ cargo build $oldbe --release
else
- cargo build
+ cargo build $oldbe
fi
+source scripts/ext_config.sh
+
rm -rf "$target_dir"
mkdir "$target_dir"
mkdir "$target_dir"/bin "$target_dir"/lib
@@ -51,10 +58,29 @@
ln target/$CHANNEL/*rustc_codegen_cranelift* "$target_dir"/lib
ln rust-toolchain scripts/config.sh scripts/cargo.sh "$target_dir"
-if [[ "$build_sysroot" == "1" ]]; then
- echo "[BUILD] sysroot"
- export CG_CLIF_INCR_CACHE_DISABLED=1
- dir=$(pwd)
- cd "$target_dir"
- time "$dir/build_sysroot/build_sysroot.sh"
+mkdir -p "$target_dir/lib/rustlib/$TARGET_TRIPLE/lib/"
+if [[ "$TARGET_TRIPLE" == "x86_64-pc-windows-gnu" ]]; then
+ cp $(rustc --print sysroot)/lib/rustlib/$TARGET_TRIPLE/lib/*.o "$target_dir/lib/rustlib/$TARGET_TRIPLE/lib/"
fi
+
+case "$build_sysroot" in
+ "none")
+ ;;
+ "llvm")
+ cp -r $(rustc --print sysroot)/lib/rustlib/$TARGET_TRIPLE/lib "$target_dir/lib/rustlib/$TARGET_TRIPLE/"
+ ;;
+ "clif")
+ echo "[BUILD] sysroot"
+ dir=$(pwd)
+ cd "$target_dir"
+ time "$dir/build_sysroot/build_sysroot.sh"
+ cp lib/rustlib/*/lib/libstd-* lib/
+ ;;
+ *)
+ echo "Unknown sysroot kind \`$build_sysroot\`."
+ echo "The allowed values are:"
+ echo " none A sysroot that doesn't contain the standard library"
+ echo " llvm Copy the sysroot from rustc compiled by cg_llvm"
+ echo " clif Build a new sysroot using cg_clif"
+ exit 1
+esac
diff --git a/compiler/rustc_codegen_cranelift/build_sysroot/Cargo.lock b/compiler/rustc_codegen_cranelift/build_sysroot/Cargo.lock
index a2b8f44..0da9999 100644
--- a/compiler/rustc_codegen_cranelift/build_sysroot/Cargo.lock
+++ b/compiler/rustc_codegen_cranelift/build_sysroot/Cargo.lock
@@ -2,9 +2,9 @@
# It is not intended for manual editing.
[[package]]
name = "addr2line"
-version = "0.14.0"
+version = "0.14.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7c0929d69e78dd9bf5408269919fcbcaeb2e35e5d43e5815517cdc6a8e11a423"
+checksum = "a55f82cfe485775d02112886f4169bde0c5894d75e79ead7eafe7e40a25e45f7"
dependencies = [
"compiler_builtins",
"gimli",
@@ -47,9 +47,9 @@
[[package]]
name = "cc"
-version = "1.0.65"
+version = "1.0.66"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "95752358c8f7552394baf48cd82695b345628ad3f170d607de3ca03b8dacca15"
+checksum = "4c0496836a84f8d0495758516b8621a622beb77c0fed418570e50764093ced48"
[[package]]
name = "cfg-if"
@@ -63,9 +63,7 @@
[[package]]
name = "compiler_builtins"
-version = "0.1.36"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7cd0782e0a7da7598164153173e5a5d4d9b1da094473c98dce0ff91406112369"
+version = "0.1.39"
dependencies = [
"rustc-std-workspace-core",
]
@@ -130,9 +128,9 @@
[[package]]
name = "hermit-abi"
-version = "0.1.17"
+version = "0.1.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5aca5565f760fb5b220e499d72710ed156fdb74e631659e99377d9ebfbd13ae8"
+checksum = "322f4de77956e22ed0e5032c359a0f1273f1f7f0d79bfa3b8ffbc730d7fbcc5c"
dependencies = [
"compiler_builtins",
"libc",
@@ -141,9 +139,9 @@
[[package]]
name = "libc"
-version = "0.2.80"
+version = "0.2.84"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4d58d1b70b004888f764dfbf6a26a3b0342a1632d33968e4a179d8011c760614"
+checksum = "1cca32fa0182e8c0989459524dc356b8f2b5c10f1b9eb521b7d182c03cf8c5ff"
dependencies = [
"rustc-std-workspace-core",
]
diff --git a/compiler/rustc_codegen_cranelift/build_sysroot/Cargo.toml b/compiler/rustc_codegen_cranelift/build_sysroot/Cargo.toml
index e562ded..82516c9 100644
--- a/compiler/rustc_codegen_cranelift/build_sysroot/Cargo.toml
+++ b/compiler/rustc_codegen_cranelift/build_sysroot/Cargo.toml
@@ -5,17 +5,19 @@
[dependencies]
core = { path = "./sysroot_src/library/core" }
-compiler_builtins = "0.1"
alloc = { path = "./sysroot_src/library/alloc" }
std = { path = "./sysroot_src/library/std", features = ["panic_unwind", "backtrace"] }
test = { path = "./sysroot_src/library/test" }
alloc_system = { path = "./alloc_system" }
+compiler_builtins = { version = "0.1.39", default-features = false, features = ["no-asm"] }
+
[patch.crates-io]
rustc-std-workspace-core = { path = "./sysroot_src/library/rustc-std-workspace-core" }
rustc-std-workspace-alloc = { path = "./sysroot_src/library/rustc-std-workspace-alloc" }
rustc-std-workspace-std = { path = "./sysroot_src/library/rustc-std-workspace-std" }
+compiler_builtins = { path = "./compiler-builtins" }
[profile.dev]
lto = "off"
diff --git a/compiler/rustc_codegen_cranelift/build_sysroot/build_sysroot.sh b/compiler/rustc_codegen_cranelift/build_sysroot/build_sysroot.sh
index d7a72df..282ce4a 100755
--- a/compiler/rustc_codegen_cranelift/build_sysroot/build_sysroot.sh
+++ b/compiler/rustc_codegen_cranelift/build_sysroot/build_sysroot.sh
@@ -24,17 +24,16 @@
# Build libs
export RUSTFLAGS="$RUSTFLAGS -Zforce-unstable-if-unmarked -Cpanic=abort"
+export __CARGO_DEFAULT_LIB_METADATA="cg_clif"
if [[ "$1" != "--debug" ]]; then
sysroot_channel='release'
# FIXME Enable incremental again once rust-lang/rust#74946 is fixed
- # FIXME Enable -Zmir-opt-level=2 again once it doesn't ice anymore
- CARGO_INCREMENTAL=0 RUSTFLAGS="$RUSTFLAGS" cargo build --target "$TARGET_TRIPLE" --release
+ CARGO_INCREMENTAL=0 RUSTFLAGS="$RUSTFLAGS -Zmir-opt-level=2" cargo build --target "$TARGET_TRIPLE" --release
else
sysroot_channel='debug'
cargo build --target "$TARGET_TRIPLE"
fi
# Copy files to sysroot
-mkdir -p "$dir/lib/rustlib/$TARGET_TRIPLE/lib/"
ln "target/$TARGET_TRIPLE/$sysroot_channel/deps/"* "$dir/lib/rustlib/$TARGET_TRIPLE/lib/"
rm "$dir/lib/rustlib/$TARGET_TRIPLE/lib/"*.{rmeta,d}
diff --git a/compiler/rustc_codegen_cranelift/build_sysroot/prepare_sysroot_src.sh b/compiler/rustc_codegen_cranelift/build_sysroot/prepare_sysroot_src.sh
index 40fbaf6..d3b87e0 100755
--- a/compiler/rustc_codegen_cranelift/build_sysroot/prepare_sysroot_src.sh
+++ b/compiler/rustc_codegen_cranelift/build_sysroot/prepare_sysroot_src.sh
@@ -29,4 +29,11 @@
done
popd
-echo "Successfully prepared libcore for building"
+git clone https://github.com/rust-lang/compiler-builtins.git || echo "rust-lang/compiler-builtins has already been cloned"
+pushd compiler-builtins
+git checkout -- .
+git checkout 0.1.39
+git apply ../../crate_patches/0001-compiler-builtins-Remove-rotate_left-from-Int.patch
+popd
+
+echo "Successfully prepared sysroot source for building"
diff --git a/compiler/rustc_codegen_cranelift/clean_all.sh b/compiler/rustc_codegen_cranelift/clean_all.sh
index 5a69c86..b47efe7 100755
--- a/compiler/rustc_codegen_cranelift/clean_all.sh
+++ b/compiler/rustc_codegen_cranelift/clean_all.sh
@@ -1,5 +1,5 @@
#!/bin/bash --verbose
set -e
-rm -rf target/ build/ build_sysroot/{sysroot_src/,target/} perf.data{,.old}
+rm -rf target/ build/ build_sysroot/{sysroot_src/,target/,compiler-builtins/} perf.data{,.old}
rm -rf rand/ regex/ simple-raytracer/
diff --git a/compiler/rustc_codegen_cranelift/crate_patches/0001-compiler-builtins-Remove-rotate_left-from-Int.patch b/compiler/rustc_codegen_cranelift/crate_patches/0001-compiler-builtins-Remove-rotate_left-from-Int.patch
new file mode 100644
index 0000000..e147689
--- /dev/null
+++ b/compiler/rustc_codegen_cranelift/crate_patches/0001-compiler-builtins-Remove-rotate_left-from-Int.patch
@@ -0,0 +1,35 @@
+From 7078cca3cb614e1e82da428380b4e16fc3afef46 Mon Sep 17 00:00:00 2001
+From: bjorn3 <[email protected]>
+Date: Thu, 21 Jan 2021 14:46:36 +0100
+Subject: [PATCH] Remove rotate_left from Int
+
+---
+ src/int/mod.rs | 5 -----
+ 1 file changed, 5 deletions(-)
+
+diff --git a/src/int/mod.rs b/src/int/mod.rs
+index 06054c8..3bea17b 100644
+--- a/src/int/mod.rs
++++ b/src/int/mod.rs
+@@ -85,7 +85,6 @@ pub trait Int:
+ fn wrapping_sub(self, other: Self) -> Self;
+ fn wrapping_shl(self, other: u32) -> Self;
+ fn wrapping_shr(self, other: u32) -> Self;
+- fn rotate_left(self, other: u32) -> Self;
+ fn overflowing_add(self, other: Self) -> (Self, bool);
+ fn aborting_div(self, other: Self) -> Self;
+ fn aborting_rem(self, other: Self) -> Self;
+@@ -209,10 +208,6 @@ macro_rules! int_impl_common {
+ <Self>::wrapping_shr(self, other)
+ }
+
+- fn rotate_left(self, other: u32) -> Self {
+- <Self>::rotate_left(self, other)
+- }
+-
+ fn overflowing_add(self, other: Self) -> (Self, bool) {
+ <Self>::overflowing_add(self, other)
+ }
+--
+2.26.2.7.g19db9cfb68
+
diff --git a/compiler/rustc_codegen_cranelift/example/alloc_example.rs b/compiler/rustc_codegen_cranelift/example/alloc_example.rs
index dc2ad4c..f59600e 100644
--- a/compiler/rustc_codegen_cranelift/example/alloc_example.rs
+++ b/compiler/rustc_codegen_cranelift/example/alloc_example.rs
@@ -11,7 +11,8 @@
#[global_allocator]
static ALLOC: System = System;
-#[link(name = "c")]
+#[cfg_attr(unix, link(name = "c"))]
+#[cfg_attr(target_env = "msvc", link(name = "msvcrt"))]
extern "C" {
fn puts(s: *const u8) -> i32;
}
diff --git a/compiler/rustc_codegen_cranelift/example/mini_core.rs b/compiler/rustc_codegen_cranelift/example/mini_core.rs
index 10cba992..002ec7e 100644
--- a/compiler/rustc_codegen_cranelift/example/mini_core.rs
+++ b/compiler/rustc_codegen_cranelift/example/mini_core.rs
@@ -532,8 +532,8 @@
}
pub mod libc {
- #[cfg_attr(not(windows), link(name = "c"))]
- #[cfg_attr(windows, link(name = "msvcrt"))]
+ #[cfg_attr(unix, link(name = "c"))]
+ #[cfg_attr(target_env = "msvc", link(name = "msvcrt"))]
extern "C" {
pub fn puts(s: *const i8) -> i32;
pub fn printf(format: *const i8, ...) -> i32;
diff --git a/compiler/rustc_codegen_cranelift/example/mod_bench.rs b/compiler/rustc_codegen_cranelift/example/mod_bench.rs
index bc65221..152041a 100644
--- a/compiler/rustc_codegen_cranelift/example/mod_bench.rs
+++ b/compiler/rustc_codegen_cranelift/example/mod_bench.rs
@@ -1,7 +1,8 @@
#![feature(start, box_syntax, core_intrinsics, lang_items)]
#![no_std]
-#[link(name = "c")]
+#[cfg_attr(unix, link(name = "c"))]
+#[cfg_attr(target_env = "msvc", link(name = "msvcrt"))]
extern {}
#[panic_handler]
diff --git a/compiler/rustc_codegen_cranelift/example/std_example.rs b/compiler/rustc_codegen_cranelift/example/std_example.rs
index b38e253..015bbdf 100644
--- a/compiler/rustc_codegen_cranelift/example/std_example.rs
+++ b/compiler/rustc_codegen_cranelift/example/std_example.rs
@@ -15,6 +15,8 @@
let stderr = ::std::io::stderr();
let mut stderr = stderr.lock();
+ // FIXME support lazy jit when multi threading
+ #[cfg(not(lazy_jit))]
std::thread::spawn(move || {
println!("Hello from another thread!");
});
diff --git a/compiler/rustc_codegen_cranelift/patches/0022-core-Disable-not-compiling-tests.patch b/compiler/rustc_codegen_cranelift/patches/0022-core-Disable-not-compiling-tests.patch
index 8cfffe5..3eb1006 100644
--- a/compiler/rustc_codegen_cranelift/patches/0022-core-Disable-not-compiling-tests.patch
+++ b/compiler/rustc_codegen_cranelift/patches/0022-core-Disable-not-compiling-tests.patch
@@ -119,5 +119,21 @@
#[test]
#[should_panic(expected = "index 0 greater than length of slice")]
+diff --git a/library/core/tests/num/ops.rs b/library/core/tests/num/ops.rs
+index 9979cc8..d5d1d83 100644
+--- a/library/core/tests/num/ops.rs
++++ b/library/core/tests/num/ops.rs
+@@ -238,7 +238,7 @@ macro_rules! test_shift_assign {
+ }
+ };
+ }
+-test_shift!(test_shl_defined, Shl::shl);
+-test_shift_assign!(test_shl_assign_defined, ShlAssign::shl_assign);
+-test_shift!(test_shr_defined, Shr::shr);
+-test_shift_assign!(test_shr_assign_defined, ShrAssign::shr_assign);
++//test_shift!(test_shl_defined, Shl::shl);
++//test_shift_assign!(test_shl_assign_defined, ShlAssign::shl_assign);
++//test_shift!(test_shr_defined, Shr::shr);
++//test_shift_assign!(test_shr_assign_defined, ShrAssign::shr_assign);
--
2.21.0 (Apple Git-122)
diff --git a/compiler/rustc_codegen_cranelift/rust-toolchain b/compiler/rustc_codegen_cranelift/rust-toolchain
index ed1e64f..a08f00d 100644
--- a/compiler/rustc_codegen_cranelift/rust-toolchain
+++ b/compiler/rustc_codegen_cranelift/rust-toolchain
@@ -1 +1 @@
-nightly-2020-11-27
+nightly-2021-01-30
diff --git a/compiler/rustc_codegen_cranelift/scripts/cargo.sh b/compiler/rustc_codegen_cranelift/scripts/cargo.sh
index dcd40ac..a3d6d30 100755
--- a/compiler/rustc_codegen_cranelift/scripts/cargo.sh
+++ b/compiler/rustc_codegen_cranelift/scripts/cargo.sh
@@ -10,7 +10,9 @@
shift || true
if [[ "$cmd" = "jit" ]]; then
-cargo "+${TOOLCHAIN}" rustc "$@" -- --jit
+cargo "+${TOOLCHAIN}" rustc "$@" -- -Cllvm-args=mode=jit -Cprefer-dynamic
+elif [[ "$cmd" = "lazy-jit" ]]; then
+cargo "+${TOOLCHAIN}" rustc "$@" -- -Cllvm-args=mode=jit-lazy -Cprefer-dynamic
else
cargo "+${TOOLCHAIN}" "$cmd" "$@"
fi
diff --git a/compiler/rustc_codegen_cranelift/scripts/config.sh b/compiler/rustc_codegen_cranelift/scripts/config.sh
index dea037e..834708a 100644
--- a/compiler/rustc_codegen_cranelift/scripts/config.sh
+++ b/compiler/rustc_codegen_cranelift/scripts/config.sh
@@ -12,28 +12,6 @@
exit 1
fi
-HOST_TRIPLE=$(rustc -vV | grep host | cut -d: -f2 | tr -d " ")
-TARGET_TRIPLE=$HOST_TRIPLE
-#TARGET_TRIPLE="x86_64-pc-windows-gnu"
-#TARGET_TRIPLE="aarch64-unknown-linux-gnu"
-
-linker=''
-RUN_WRAPPER=''
-export JIT_SUPPORTED=1
-if [[ "$HOST_TRIPLE" != "$TARGET_TRIPLE" ]]; then
- export JIT_SUPPORTED=0
- if [[ "$TARGET_TRIPLE" == "aarch64-unknown-linux-gnu" ]]; then
- # We are cross-compiling for aarch64. Use the correct linker and run tests in qemu.
- linker='-Clinker=aarch64-linux-gnu-gcc'
- RUN_WRAPPER='qemu-aarch64 -L /usr/aarch64-linux-gnu'
- elif [[ "$TARGET_TRIPLE" == "x86_64-pc-windows-gnu" ]]; then
- # We are cross-compiling for Windows. Run tests in wine.
- RUN_WRAPPER='wine'
- else
- echo "Unknown non-native platform"
- fi
-fi
-
if echo "$RUSTC_WRAPPER" | grep sccache; then
echo
echo -e "\x1b[1;93m=== Warning: Unset RUSTC_WRAPPER to prevent interference with sccache ===\x1b[0m"
@@ -44,16 +22,14 @@
dir=$(cd "$(dirname "${BASH_SOURCE[0]}")"; pwd)
export RUSTC=$dir"/bin/cg_clif"
-export RUSTFLAGS=$linker" "$RUSTFLAGS
+
export RUSTDOCFLAGS=$linker' -Cpanic=abort -Zpanic-abort-tests '\
'-Zcodegen-backend='$dir'/lib/librustc_codegen_cranelift.'$dylib_ext' --sysroot '$dir
# FIXME remove once the atomic shim is gone
-if [[ $(uname) == 'Darwin' ]]; then
+if [[ "$unamestr" == 'Darwin' ]]; then
export RUSTFLAGS="$RUSTFLAGS -Clink-arg=-undefined -Clink-arg=dynamic_lookup"
fi
-export LD_LIBRARY_PATH="$(rustc --print sysroot)/lib"
+export LD_LIBRARY_PATH="$(rustc --print sysroot)/lib:"$dir"/lib"
export DYLD_LIBRARY_PATH=$LD_LIBRARY_PATH
-
-export CG_CLIF_DISPLAY_CG_TIME=1
diff --git a/compiler/rustc_codegen_cranelift/scripts/ext_config.sh b/compiler/rustc_codegen_cranelift/scripts/ext_config.sh
new file mode 100644
index 0000000..7971f62
--- /dev/null
+++ b/compiler/rustc_codegen_cranelift/scripts/ext_config.sh
@@ -0,0 +1,27 @@
+# Note to people running shellcheck: this file should only be sourced, not executed directly.
+
+# Various env vars that should only be set for the build system but not for cargo.sh
+
+set -e
+
+export CG_CLIF_DISPLAY_CG_TIME=1
+export CG_CLIF_INCR_CACHE_DISABLED=1
+
+export HOST_TRIPLE=$(rustc -vV | grep host | cut -d: -f2 | tr -d " ")
+export TARGET_TRIPLE=${TARGET_TRIPLE:-$HOST_TRIPLE}
+
+export RUN_WRAPPER=''
+export JIT_SUPPORTED=1
+if [[ "$HOST_TRIPLE" != "$TARGET_TRIPLE" ]]; then
+ export JIT_SUPPORTED=0
+ if [[ "$TARGET_TRIPLE" == "aarch64-unknown-linux-gnu" ]]; then
+ # We are cross-compiling for aarch64. Use the correct linker and run tests in qemu.
+ export RUSTFLAGS='-Clinker=aarch64-linux-gnu-gcc '$RUSTFLAGS
+ export RUN_WRAPPER='qemu-aarch64 -L /usr/aarch64-linux-gnu'
+ elif [[ "$TARGET_TRIPLE" == "x86_64-pc-windows-gnu" ]]; then
+ # We are cross-compiling for Windows. Run tests in wine.
+ export RUN_WRAPPER='wine'
+ else
+ echo "Unknown non-native platform"
+ fi
+fi
diff --git a/compiler/rustc_codegen_cranelift/scripts/filter_profile.rs b/compiler/rustc_codegen_cranelift/scripts/filter_profile.rs
index 3327c10..1538892 100755
--- a/compiler/rustc_codegen_cranelift/scripts/filter_profile.rs
+++ b/compiler/rustc_codegen_cranelift/scripts/filter_profile.rs
@@ -4,7 +4,7 @@
pushd $(dirname "$0")/../
source build/config.sh
popd
-PROFILE=$1 OUTPUT=$2 exec $RUSTC $RUSTFLAGS --jit $0
+PROFILE=$1 OUTPUT=$2 exec $RUSTC $RUSTFLAGS -Cllvm-args=mode=jit -Cprefer-dynamic $0
#*/
//! This program filters away uninteresting samples and trims uninteresting frames for stackcollapse
diff --git a/compiler/rustc_codegen_cranelift/scripts/tests.sh b/compiler/rustc_codegen_cranelift/scripts/tests.sh
index 114b6f3..d37b57b 100755
--- a/compiler/rustc_codegen_cranelift/scripts/tests.sh
+++ b/compiler/rustc_codegen_cranelift/scripts/tests.sh
@@ -3,7 +3,7 @@
set -e
source build/config.sh
-export CG_CLIF_INCR_CACHE_DISABLED=1
+source scripts/ext_config.sh
MY_RUSTC="$RUSTC $RUSTFLAGS -L crate=target/out --out-dir target/out -Cdebuginfo=2"
function no_sysroot_tests() {
@@ -15,7 +15,10 @@
if [[ "$JIT_SUPPORTED" = "1" ]]; then
echo "[JIT] mini_core_hello_world"
- CG_CLIF_JIT_ARGS="abc bcd" $MY_RUSTC --jit example/mini_core_hello_world.rs --cfg jit --target "$HOST_TRIPLE"
+ CG_CLIF_JIT_ARGS="abc bcd" $MY_RUSTC -Cllvm-args=mode=jit -Cprefer-dynamic example/mini_core_hello_world.rs --cfg jit --target "$HOST_TRIPLE"
+
+ echo "[JIT-lazy] mini_core_hello_world"
+ CG_CLIF_JIT_ARGS="abc bcd" $MY_RUSTC -Cllvm-args=mode=jit-lazy -Cprefer-dynamic example/mini_core_hello_world.rs --cfg jit --target "$HOST_TRIPLE"
else
echo "[JIT] mini_core_hello_world (skipped)"
fi
@@ -37,7 +40,10 @@
if [[ "$JIT_SUPPORTED" = "1" ]]; then
echo "[JIT] std_example"
- $MY_RUSTC --jit example/std_example.rs --target "$HOST_TRIPLE"
+ $MY_RUSTC -Cllvm-args=mode=jit -Cprefer-dynamic example/std_example.rs --target "$HOST_TRIPLE"
+
+ echo "[JIT-lazy] std_example"
+ $MY_RUSTC -Cllvm-args=mode=jit-lazy -Cprefer-dynamic example/std_example.rs --cfg lazy_jit --target "$HOST_TRIPLE"
else
echo "[JIT] std_example (skipped)"
fi
diff --git a/compiler/rustc_codegen_cranelift/src/abi/comments.rs b/compiler/rustc_codegen_cranelift/src/abi/comments.rs
index 01073d2..9aab45b 100644
--- a/compiler/rustc_codegen_cranelift/src/abi/comments.rs
+++ b/compiler/rustc_codegen_cranelift/src/abi/comments.rs
@@ -4,10 +4,10 @@
use std::borrow::Cow;
use rustc_middle::mir;
+use rustc_target::abi::call::PassMode;
use cranelift_codegen::entity::EntityRef;
-use crate::abi::pass_mode::*;
use crate::prelude::*;
pub(super) fn add_args_header_comment(fx: &mut FunctionCx<'_, '_, impl Module>) {
@@ -21,9 +21,9 @@
kind: &str,
local: Option<mir::Local>,
local_field: Option<usize>,
- params: EmptySinglePair<Value>,
- pass_mode: PassMode,
- ty: Ty<'tcx>,
+ params: &[Value],
+ arg_abi_mode: PassMode,
+ arg_layout: TyAndLayout<'tcx>,
) {
let local = if let Some(local) = local {
Cow::Owned(format!("{:?}", local))
@@ -37,12 +37,20 @@
};
let params = match params {
- Empty => Cow::Borrowed("-"),
- Single(param) => Cow::Owned(format!("= {:?}", param)),
- Pair(param_a, param_b) => Cow::Owned(format!("= {:?}, {:?}", param_a, param_b)),
+ [] => Cow::Borrowed("-"),
+ [param] => Cow::Owned(format!("= {:?}", param)),
+ [param_a, param_b] => Cow::Owned(format!("= {:?},{:?}", param_a, param_b)),
+ params => Cow::Owned(format!(
+ "= {}",
+ params
+ .iter()
+ .map(ToString::to_string)
+ .collect::<Vec<_>>()
+ .join(",")
+ )),
};
- let pass_mode = format!("{:?}", pass_mode);
+ let pass_mode = format!("{:?}", arg_abi_mode);
fx.add_global_comment(format!(
"{kind:5}{local:>3}{local_field:<5} {params:10} {pass_mode:36} {ty:?}",
kind = kind,
@@ -50,7 +58,7 @@
local_field = local_field,
params = params,
pass_mode = pass_mode,
- ty = ty,
+ ty = arg_layout.ty,
));
}
diff --git a/compiler/rustc_codegen_cranelift/src/abi/mod.rs b/compiler/rustc_codegen_cranelift/src/abi/mod.rs
index 76e1987..b2647e6 100644
--- a/compiler/rustc_codegen_cranelift/src/abi/mod.rs
+++ b/compiler/rustc_codegen_cranelift/src/abi/mod.rs
@@ -6,199 +6,51 @@
mod returning;
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
+use rustc_middle::ty::layout::FnAbiExt;
+use rustc_target::abi::call::{Conv, FnAbi};
use rustc_target::spec::abi::Abi;
-use cranelift_codegen::ir::{AbiParam, ArgumentPurpose};
+use cranelift_codegen::ir::AbiParam;
+use smallvec::smallvec;
use self::pass_mode::*;
use crate::prelude::*;
pub(crate) use self::returning::{can_return_to_ssa_var, codegen_return};
-// Copied from https://github.com/rust-lang/rust/blob/f52c72948aa1dd718cc1f168d21c91c584c0a662/src/librustc_middle/ty/layout.rs#L2301
-#[rustfmt::skip]
-pub(crate) fn fn_sig_for_fn_abi<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) -> ty::PolyFnSig<'tcx> {
- use rustc_middle::ty::subst::Subst;
-
- // FIXME(davidtwco,eddyb): A `ParamEnv` should be passed through to this function.
- let ty = instance.ty(tcx, ty::ParamEnv::reveal_all());
- match *ty.kind() {
- ty::FnDef(..) => {
- // HACK(davidtwco,eddyb): This is a workaround for polymorphization considering
- // parameters unused if they show up in the signature, but not in the `mir::Body`
- // (i.e. due to being inside a projection that got normalized, see
- // `src/test/ui/polymorphization/normalized_sig_types.rs`), and codegen not keeping
- // track of a polymorphization `ParamEnv` to allow normalizing later.
- let mut sig = match *ty.kind() {
- ty::FnDef(def_id, substs) => tcx
- .normalize_erasing_regions(tcx.param_env(def_id), tcx.fn_sig(def_id))
- .subst(tcx, substs),
- _ => unreachable!(),
- };
-
- if let ty::InstanceDef::VtableShim(..) = instance.def {
- // Modify `fn(self, ...)` to `fn(self: *mut Self, ...)`.
- sig = sig.map_bound(|mut sig| {
- let mut inputs_and_output = sig.inputs_and_output.to_vec();
- inputs_and_output[0] = tcx.mk_mut_ptr(inputs_and_output[0]);
- sig.inputs_and_output = tcx.intern_type_list(&inputs_and_output);
- sig
- });
- }
- sig
- }
- ty::Closure(def_id, substs) => {
- let sig = substs.as_closure().sig();
-
- let env_ty = tcx.closure_env_ty(def_id, substs).unwrap();
- sig.map_bound(|sig| {
- tcx.mk_fn_sig(
- std::iter::once(env_ty.skip_binder()).chain(sig.inputs().iter().cloned()),
- sig.output(),
- sig.c_variadic,
- sig.unsafety,
- sig.abi,
- )
- })
- }
- ty::Generator(_, substs, _) => {
- let sig = substs.as_generator().poly_sig();
-
- let env_region = ty::ReLateBound(ty::INNERMOST, ty::BoundRegion { kind: ty::BrEnv });
- let env_ty = tcx.mk_mut_ref(tcx.mk_region(env_region), ty);
-
- let pin_did = tcx.require_lang_item(rustc_hir::LangItem::Pin, None);
- let pin_adt_ref = tcx.adt_def(pin_did);
- let pin_substs = tcx.intern_substs(&[env_ty.into()]);
- let env_ty = tcx.mk_adt(pin_adt_ref, pin_substs);
-
- sig.map_bound(|sig| {
- let state_did = tcx.require_lang_item(rustc_hir::LangItem::GeneratorState, None);
- let state_adt_ref = tcx.adt_def(state_did);
- let state_substs =
- tcx.intern_substs(&[sig.yield_ty.into(), sig.return_ty.into()]);
- let ret_ty = tcx.mk_adt(state_adt_ref, state_substs);
-
- tcx.mk_fn_sig(
- [env_ty, sig.resume_ty].iter(),
- &ret_ty,
- false,
- rustc_hir::Unsafety::Normal,
- rustc_target::spec::abi::Abi::Rust,
- )
- })
- }
- _ => bug!("unexpected type {:?} in Instance::fn_sig", ty),
- }
-}
-
-fn clif_sig_from_fn_sig<'tcx>(
+fn clif_sig_from_fn_abi<'tcx>(
tcx: TyCtxt<'tcx>,
triple: &target_lexicon::Triple,
- sig: FnSig<'tcx>,
- span: Span,
- is_vtable_fn: bool,
- requires_caller_location: bool,
+ fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
) -> Signature {
- let abi = match sig.abi {
- Abi::System => Abi::C,
- abi => abi,
- };
- let (call_conv, inputs, output): (CallConv, Vec<Ty<'tcx>>, Ty<'tcx>) = match abi {
- Abi::Rust => (
- CallConv::triple_default(triple),
- sig.inputs().to_vec(),
- sig.output(),
- ),
- Abi::C | Abi::Unadjusted => (
- CallConv::triple_default(triple),
- sig.inputs().to_vec(),
- sig.output(),
- ),
- Abi::SysV64 => (CallConv::SystemV, sig.inputs().to_vec(), sig.output()),
- Abi::RustCall => {
- assert_eq!(sig.inputs().len(), 2);
- let extra_args = match sig.inputs().last().unwrap().kind() {
- ty::Tuple(ref tupled_arguments) => tupled_arguments,
- _ => bug!("argument to function with \"rust-call\" ABI is not a tuple"),
- };
- let mut inputs: Vec<Ty<'tcx>> = vec![sig.inputs()[0]];
- inputs.extend(extra_args.types());
- (CallConv::triple_default(triple), inputs, sig.output())
+ let call_conv = match fn_abi.conv {
+ Conv::Rust | Conv::C => CallConv::triple_default(triple),
+ Conv::X86_64SysV => CallConv::SystemV,
+ Conv::X86_64Win64 => CallConv::WindowsFastcall,
+ Conv::ArmAapcs
+ | Conv::CCmseNonSecureCall
+ | Conv::Msp430Intr
+ | Conv::PtxKernel
+ | Conv::X86Fastcall
+ | Conv::X86Intr
+ | Conv::X86Stdcall
+ | Conv::X86ThisCall
+ | Conv::X86VectorCall
+ | Conv::AmdGpuKernel
+ | Conv::AvrInterrupt
+ | Conv::AvrNonBlockingInterrupt => {
+ todo!("{:?}", fn_abi.conv)
}
- Abi::System => unreachable!(),
- Abi::RustIntrinsic => (
- CallConv::triple_default(triple),
- sig.inputs().to_vec(),
- sig.output(),
- ),
- _ => unimplemented!("unsupported abi {:?}", sig.abi),
};
-
- let inputs = inputs
- .into_iter()
- .enumerate()
- .map(|(i, ty)| {
- let mut layout = tcx.layout_of(ParamEnv::reveal_all().and(ty)).unwrap();
- if i == 0 && is_vtable_fn {
- // Virtual calls turn their self param into a thin pointer.
- // See https://github.com/rust-lang/rust/blob/37b6a5e5e82497caf5353d9d856e4eb5d14cbe06/src/librustc/ty/layout.rs#L2519-L2572 for more info
- layout = tcx
- .layout_of(ParamEnv::reveal_all().and(tcx.mk_mut_ptr(tcx.mk_unit())))
- .unwrap();
- }
- let pass_mode = get_pass_mode(tcx, layout);
- if abi != Abi::Rust && abi != Abi::RustCall && abi != Abi::RustIntrinsic {
- match pass_mode {
- PassMode::NoPass | PassMode::ByVal(_) => {}
- PassMode::ByRef { size: Some(size) } => {
- let purpose = ArgumentPurpose::StructArgument(u32::try_from(size.bytes()).expect("struct too big to pass on stack"));
- return EmptySinglePair::Single(AbiParam::special(pointer_ty(tcx), purpose)).into_iter();
- }
- PassMode::ByValPair(_, _) | PassMode::ByRef { size: None } => {
- tcx.sess.span_warn(
- span,
- &format!(
- "Argument of type `{:?}` with pass mode `{:?}` is not yet supported \
- for non-rust abi `{}`. Calling this function may result in a crash.",
- layout.ty,
- pass_mode,
- abi,
- ),
- );
- }
- }
- }
- pass_mode.get_param_ty(tcx).map(AbiParam::new).into_iter()
- })
+ let inputs = fn_abi
+ .args
+ .iter()
+ .map(|arg_abi| arg_abi.get_abi_param(tcx).into_iter())
.flatten();
- let (mut params, returns): (Vec<_>, Vec<_>) = match get_pass_mode(
- tcx,
- tcx.layout_of(ParamEnv::reveal_all().and(output)).unwrap(),
- ) {
- PassMode::NoPass => (inputs.collect(), vec![]),
- PassMode::ByVal(ret_ty) => (inputs.collect(), vec![AbiParam::new(ret_ty)]),
- PassMode::ByValPair(ret_ty_a, ret_ty_b) => (
- inputs.collect(),
- vec![AbiParam::new(ret_ty_a), AbiParam::new(ret_ty_b)],
- ),
- PassMode::ByRef { size: Some(_) } => {
- (
- Some(pointer_ty(tcx)) // First param is place to put return val
- .into_iter()
- .map(|ty| AbiParam::special(ty, ArgumentPurpose::StructReturn))
- .chain(inputs)
- .collect(),
- vec![],
- )
- }
- PassMode::ByRef { size: None } => todo!(),
- };
-
- if requires_caller_location {
- params.push(AbiParam::new(pointer_ty(tcx)));
- }
+ let (return_ptr, returns) = fn_abi.ret.get_abi_return(tcx);
+ // Sometimes the first param is an pointer to the place where the return value needs to be stored.
+ let params: Vec<_> = return_ptr.into_iter().chain(inputs).collect();
Signature {
params,
@@ -207,30 +59,17 @@
}
}
-pub(crate) fn get_function_name_and_sig<'tcx>(
+pub(crate) fn get_function_sig<'tcx>(
tcx: TyCtxt<'tcx>,
triple: &target_lexicon::Triple,
inst: Instance<'tcx>,
- support_vararg: bool,
-) -> (String, Signature) {
+) -> Signature {
assert!(!inst.substs.needs_infer());
- let fn_sig = tcx
- .normalize_erasing_late_bound_regions(ParamEnv::reveal_all(), fn_sig_for_fn_abi(tcx, inst));
- if fn_sig.c_variadic && !support_vararg {
- tcx.sess.span_fatal(
- tcx.def_span(inst.def_id()),
- "Variadic function definitions are not yet supported",
- );
- }
- let sig = clif_sig_from_fn_sig(
+ clif_sig_from_fn_abi(
tcx,
triple,
- fn_sig,
- tcx.def_span(inst.def_id()),
- false,
- inst.def.requires_caller_location(tcx),
- );
- (tcx.symbol_name(inst).name.to_string(), sig)
+ &FnAbi::of_instance(&RevealAllLayoutCx(tcx), inst, &[]),
+ )
}
/// Instance must be monomorphized
@@ -239,7 +78,8 @@
module: &mut impl Module,
inst: Instance<'tcx>,
) -> FuncId {
- let (name, sig) = get_function_name_and_sig(tcx, module.isa().triple(), inst, true);
+ let name = tcx.symbol_name(inst).name.to_string();
+ let sig = get_function_sig(tcx, module.isa().triple(), inst);
module
.declare_function(&name, Linkage::Import, &sig)
.unwrap()
@@ -263,13 +103,13 @@
pub(crate) fn lib_call(
&mut self,
name: &str,
- input_tys: Vec<types::Type>,
- output_tys: Vec<types::Type>,
+ params: Vec<AbiParam>,
+ returns: Vec<AbiParam>,
args: &[Value],
) -> &[Value] {
let sig = Signature {
- params: input_tys.iter().cloned().map(AbiParam::new).collect(),
- returns: output_tys.iter().cloned().map(AbiParam::new).collect(),
+ params,
+ returns,
call_conv: CallConv::triple_default(self.triple()),
};
let func_id = self
@@ -301,16 +141,18 @@
.iter()
.map(|arg| {
(
- self.clif_type(arg.layout().ty).unwrap(),
+ AbiParam::new(self.clif_type(arg.layout().ty).unwrap()),
arg.load_scalar(self),
)
})
.unzip();
let return_layout = self.layout_of(return_ty);
let return_tys = if let ty::Tuple(tup) = return_ty.kind() {
- tup.types().map(|ty| self.clif_type(ty).unwrap()).collect()
+ tup.types()
+ .map(|ty| AbiParam::new(self.clif_type(ty).unwrap()))
+ .collect()
} else {
- vec![self.clif_type(return_ty).unwrap()]
+ vec![AbiParam::new(self.clif_type(return_ty).unwrap())]
};
let ret_vals = self.lib_call(name, input_tys, return_tys, &args);
match *ret_vals {
@@ -352,12 +194,25 @@
fx: &mut FunctionCx<'_, 'tcx, impl Module>,
start_block: Block,
) {
+ fx.bcx.append_block_params_for_function_params(start_block);
+
+ fx.bcx.switch_to_block(start_block);
+ fx.bcx.ins().nop();
+
let ssa_analyzed = crate::analyze::analyze(fx);
#[cfg(debug_assertions)]
self::comments::add_args_header_comment(fx);
- let ret_place = self::returning::codegen_return_param(fx, &ssa_analyzed, start_block);
+ let mut block_params_iter = fx
+ .bcx
+ .func
+ .dfg
+ .block_params(start_block)
+ .to_vec()
+ .into_iter();
+ let ret_place =
+ self::returning::codegen_return_param(fx, &ssa_analyzed, &mut block_params_iter);
assert_eq!(fx.local_map.push(ret_place), RETURN_PLACE);
// None means pass_mode == NoPass
@@ -366,6 +221,9 @@
Spread(Vec<Option<CValue<'tcx>>>),
}
+ let fn_abi = fx.fn_abi.take().unwrap();
+ let mut arg_abis_iter = fn_abi.args.iter();
+
let func_params = fx
.mir
.args_iter()
@@ -385,14 +243,18 @@
};
let mut params = Vec::new();
- for (i, arg_ty) in tupled_arg_tys.types().enumerate() {
- let param = cvalue_for_param(fx, start_block, Some(local), Some(i), arg_ty);
+ for (i, _arg_ty) in tupled_arg_tys.types().enumerate() {
+ let arg_abi = arg_abis_iter.next().unwrap();
+ let param =
+ cvalue_for_param(fx, Some(local), Some(i), arg_abi, &mut block_params_iter);
params.push(param);
}
(local, ArgKind::Spread(params), arg_ty)
} else {
- let param = cvalue_for_param(fx, start_block, Some(local), None, arg_ty);
+ let arg_abi = arg_abis_iter.next().unwrap();
+ let param =
+ cvalue_for_param(fx, Some(local), None, arg_abi, &mut block_params_iter);
(local, ArgKind::Normal(param), arg_ty)
}
})
@@ -401,13 +263,14 @@
assert!(fx.caller_location.is_none());
if fx.instance.def.requires_caller_location(fx.tcx) {
// Store caller location for `#[track_caller]`.
- fx.caller_location = Some(
- cvalue_for_param(fx, start_block, None, None, fx.tcx.caller_location_ty()).unwrap(),
- );
+ let arg_abi = arg_abis_iter.next().unwrap();
+ fx.caller_location =
+ Some(cvalue_for_param(fx, None, None, arg_abi, &mut block_params_iter).unwrap());
}
- fx.bcx.switch_to_block(start_block);
- fx.bcx.ins().nop();
+ assert!(arg_abis_iter.next().is_none(), "ArgAbi left behind");
+ fx.fn_abi = Some(fn_abi);
+ assert!(block_params_iter.next().is_none(), "arg_value left behind");
#[cfg(debug_assertions)]
self::comments::add_locals_header_comment(fx);
@@ -533,6 +396,21 @@
None
};
+ let extra_args = &args[fn_sig.inputs().len()..];
+ let extra_args = extra_args
+ .iter()
+ .map(|op_arg| fx.monomorphize(op_arg.ty(fx.mir, fx.tcx)))
+ .collect::<Vec<_>>();
+ let fn_abi = if let Some(instance) = instance {
+ FnAbi::of_instance(&RevealAllLayoutCx(fx.tcx), instance, &extra_args)
+ } else {
+ FnAbi::of_fn_ptr(
+ &RevealAllLayoutCx(fx.tcx),
+ fn_ty.fn_sig(fx.tcx),
+ &extra_args,
+ )
+ };
+
let is_cold = instance
.map(|inst| {
fx.tcx
@@ -570,8 +448,8 @@
// | indirect call target
// | | the first argument to be passed
- // v v v virtual calls are special cased below
- let (func_ref, first_arg, is_virtual_call) = match instance {
+ // v v
+ let (func_ref, first_arg) = match instance {
// Trait object call
Some(Instance {
def: InstanceDef::Virtual(_, idx),
@@ -582,23 +460,19 @@
let nop_inst = fx.bcx.ins().nop();
fx.add_comment(
nop_inst,
- format!(
- "virtual call; self arg pass mode: {:?}",
- get_pass_mode(fx.tcx, args[0].layout())
- ),
+ format!("virtual call; self arg pass mode: {:?}", &fn_abi.args[0],),
);
}
let (ptr, method) = crate::vtable::get_ptr_and_method_ref(fx, args[0], idx);
- (Some(method), Single(ptr), true)
+ (Some(method), smallvec![ptr])
}
// Normal call
Some(_) => (
None,
args.get(0)
- .map(|arg| adjust_arg_for_abi(fx, *arg))
- .unwrap_or(Empty),
- false,
+ .map(|arg| adjust_arg_for_abi(fx, *arg, &fn_abi.args[0]))
+ .unwrap_or(smallvec![]),
),
// Indirect call
@@ -612,23 +486,27 @@
(
Some(func),
args.get(0)
- .map(|arg| adjust_arg_for_abi(fx, *arg))
- .unwrap_or(Empty),
- false,
+ .map(|arg| adjust_arg_for_abi(fx, *arg, &fn_abi.args[0]))
+ .unwrap_or(smallvec![]),
)
}
};
let ret_place = destination.map(|(place, _)| place);
- let (call_inst, call_args) =
- self::returning::codegen_with_call_return_arg(fx, fn_sig, ret_place, |fx, return_ptr| {
+ let (call_inst, call_args) = self::returning::codegen_with_call_return_arg(
+ fx,
+ &fn_abi.ret,
+ ret_place,
+ |fx, return_ptr| {
+ let regular_args_count = args.len();
let mut call_args: Vec<Value> = return_ptr
.into_iter()
.chain(first_arg.into_iter())
.chain(
args.into_iter()
+ .enumerate()
.skip(1)
- .map(|arg| adjust_arg_for_abi(fx, arg).into_iter())
+ .map(|(i, arg)| adjust_arg_for_abi(fx, arg, &fn_abi.args[i]).into_iter())
.flatten(),
)
.collect::<Vec<_>>();
@@ -639,18 +517,17 @@
{
// Pass the caller location for `#[track_caller]`.
let caller_location = fx.get_caller_location(span);
- call_args.extend(adjust_arg_for_abi(fx, caller_location).into_iter());
+ call_args.extend(
+ adjust_arg_for_abi(fx, caller_location, &fn_abi.args[regular_args_count])
+ .into_iter(),
+ );
+ assert_eq!(fn_abi.args.len(), regular_args_count + 1);
+ } else {
+ assert_eq!(fn_abi.args.len(), regular_args_count);
}
let call_inst = if let Some(func_ref) = func_ref {
- let sig = clif_sig_from_fn_sig(
- fx.tcx,
- fx.triple(),
- fn_sig,
- span,
- is_virtual_call,
- false, // calls through function pointers never pass the caller location
- );
+ let sig = clif_sig_from_fn_abi(fx.tcx, fx.triple(), &fn_abi);
let sig = fx.bcx.import_signature(sig);
fx.bcx.ins().call_indirect(sig, func_ref, &call_args)
} else {
@@ -660,7 +537,8 @@
};
(call_inst, call_args)
- });
+ },
+ );
// FIXME find a cleaner way to support varargs
if fn_sig.c_variadic {
@@ -701,37 +579,33 @@
drop_place: CPlace<'tcx>,
) {
let ty = drop_place.layout().ty;
- let drop_fn = Instance::resolve_drop_in_place(fx.tcx, ty).polymorphize(fx.tcx);
+ let drop_instance = Instance::resolve_drop_in_place(fx.tcx, ty).polymorphize(fx.tcx);
- if let ty::InstanceDef::DropGlue(_, None) = drop_fn.def {
+ if let ty::InstanceDef::DropGlue(_, None) = drop_instance.def {
// we don't actually need to drop anything
} else {
- let drop_fn_ty = drop_fn.ty(fx.tcx, ParamEnv::reveal_all());
- let fn_sig = fx.tcx.normalize_erasing_late_bound_regions(
- ParamEnv::reveal_all(),
- drop_fn_ty.fn_sig(fx.tcx),
- );
- assert_eq!(fn_sig.output(), fx.tcx.mk_unit());
-
match ty.kind() {
ty::Dynamic(..) => {
let (ptr, vtable) = drop_place.to_ptr_maybe_unsized();
let ptr = ptr.get_addr(fx);
let drop_fn = crate::vtable::drop_fn_of_obj(fx, vtable.unwrap());
- let sig = clif_sig_from_fn_sig(
- fx.tcx,
- fx.triple(),
- fn_sig,
- span,
- true,
- false, // `drop_in_place` is never `#[track_caller]`
- );
+ // FIXME(eddyb) perhaps move some of this logic into
+ // `Instance::resolve_drop_in_place`?
+ let virtual_drop = Instance {
+ def: ty::InstanceDef::Virtual(drop_instance.def_id(), 0),
+ substs: drop_instance.substs,
+ };
+ let fn_abi = FnAbi::of_instance(&RevealAllLayoutCx(fx.tcx), virtual_drop, &[]);
+
+ let sig = clif_sig_from_fn_abi(fx.tcx, fx.triple(), &fn_abi);
let sig = fx.bcx.import_signature(sig);
fx.bcx.ins().call_indirect(sig, drop_fn, &[ptr]);
}
_ => {
- assert!(!matches!(drop_fn.def, InstanceDef::Virtual(_, _)));
+ assert!(!matches!(drop_instance.def, InstanceDef::Virtual(_, _)));
+
+ let fn_abi = FnAbi::of_instance(&RevealAllLayoutCx(fx.tcx), drop_instance, &[]);
let arg_value = drop_place.place_ref(
fx,
@@ -743,17 +617,19 @@
},
)),
);
- let arg_value = adjust_arg_for_abi(fx, arg_value);
+ let arg_value = adjust_arg_for_abi(fx, arg_value, &fn_abi.args[0]);
let mut call_args: Vec<Value> = arg_value.into_iter().collect::<Vec<_>>();
- if drop_fn.def.requires_caller_location(fx.tcx) {
+ if drop_instance.def.requires_caller_location(fx.tcx) {
// Pass the caller location for `#[track_caller]`.
let caller_location = fx.get_caller_location(span);
- call_args.extend(adjust_arg_for_abi(fx, caller_location).into_iter());
+ call_args.extend(
+ adjust_arg_for_abi(fx, caller_location, &fn_abi.args[1]).into_iter(),
+ );
}
- let func_ref = fx.get_function_ref(drop_fn);
+ let func_ref = fx.get_function_ref(drop_instance);
fx.bcx.ins().call(func_ref, &call_args);
}
}
diff --git a/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs b/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs
index 8e3682c..1202c23 100644
--- a/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs
+++ b/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs
@@ -1,140 +1,281 @@
//! Argument passing
use crate::prelude::*;
+use crate::value_and_place::assert_assignable;
-pub(super) use EmptySinglePair::*;
+use cranelift_codegen::ir::{ArgumentExtension, ArgumentPurpose};
+use rustc_target::abi::call::{
+ ArgAbi, ArgAttributes, ArgExtension as RustcArgExtension, CastTarget, PassMode, Reg, RegKind,
+};
+use smallvec::{smallvec, SmallVec};
-#[derive(Copy, Clone, Debug)]
-pub(super) enum PassMode {
- NoPass,
- ByVal(Type),
- ByValPair(Type, Type),
- ByRef { size: Option<Size> },
+pub(super) trait ArgAbiExt<'tcx> {
+ fn get_abi_param(&self, tcx: TyCtxt<'tcx>) -> SmallVec<[AbiParam; 2]>;
+ fn get_abi_return(&self, tcx: TyCtxt<'tcx>) -> (Option<AbiParam>, Vec<AbiParam>);
}
-#[derive(Copy, Clone, Debug)]
-pub(super) enum EmptySinglePair<T> {
- Empty,
- Single(T),
- Pair(T, T),
+fn reg_to_abi_param(reg: Reg) -> AbiParam {
+ let clif_ty = match (reg.kind, reg.size.bytes()) {
+ (RegKind::Integer, 1) => types::I8,
+ (RegKind::Integer, 2) => types::I16,
+ (RegKind::Integer, 4) => types::I32,
+ (RegKind::Integer, 8) => types::I64,
+ (RegKind::Integer, 16) => types::I128,
+ (RegKind::Float, 4) => types::F32,
+ (RegKind::Float, 8) => types::F64,
+ (RegKind::Vector, size) => types::I8.by(u16::try_from(size).unwrap()).unwrap(),
+ _ => unreachable!("{:?}", reg),
+ };
+ AbiParam::new(clif_ty)
}
-impl<T> EmptySinglePair<T> {
- pub(super) fn into_iter(self) -> EmptySinglePairIter<T> {
- EmptySinglePairIter(self)
+fn apply_arg_attrs_to_abi_param(mut param: AbiParam, arg_attrs: ArgAttributes) -> AbiParam {
+ match arg_attrs.arg_ext {
+ RustcArgExtension::None => {}
+ RustcArgExtension::Zext => param.extension = ArgumentExtension::Uext,
+ RustcArgExtension::Sext => param.extension = ArgumentExtension::Sext,
}
-
- pub(super) fn map<U>(self, mut f: impl FnMut(T) -> U) -> EmptySinglePair<U> {
- match self {
- Empty => Empty,
- Single(v) => Single(f(v)),
- Pair(a, b) => Pair(f(a), f(b)),
- }
- }
+ param
}
-pub(super) struct EmptySinglePairIter<T>(EmptySinglePair<T>);
-
-impl<T> Iterator for EmptySinglePairIter<T> {
- type Item = T;
-
- fn next(&mut self) -> Option<T> {
- match std::mem::replace(&mut self.0, Empty) {
- Empty => None,
- Single(v) => Some(v),
- Pair(a, b) => {
- self.0 = Single(b);
- Some(a)
- }
- }
- }
-}
-
-impl<T: std::fmt::Debug> EmptySinglePair<T> {
- pub(super) fn assert_single(self) -> T {
- match self {
- Single(v) => v,
- _ => panic!("Called assert_single on {:?}", self),
- }
- }
-
- pub(super) fn assert_pair(self) -> (T, T) {
- match self {
- Pair(a, b) => (a, b),
- _ => panic!("Called assert_pair on {:?}", self),
- }
- }
-}
-
-impl PassMode {
- pub(super) fn get_param_ty(self, tcx: TyCtxt<'_>) -> EmptySinglePair<Type> {
- match self {
- PassMode::NoPass => Empty,
- PassMode::ByVal(clif_type) => Single(clif_type),
- PassMode::ByValPair(a, b) => Pair(a, b),
- PassMode::ByRef { size: Some(_) } => Single(pointer_ty(tcx)),
- PassMode::ByRef { size: None } => Pair(pointer_ty(tcx), pointer_ty(tcx)),
- }
- }
-}
-
-pub(super) fn get_pass_mode<'tcx>(tcx: TyCtxt<'tcx>, layout: TyAndLayout<'tcx>) -> PassMode {
- if layout.is_zst() {
- // WARNING zst arguments must never be passed, as that will break CastKind::ClosureFnPointer
- PassMode::NoPass
+fn cast_target_to_abi_params(cast: CastTarget) -> SmallVec<[AbiParam; 2]> {
+ let (rest_count, rem_bytes) = if cast.rest.unit.size.bytes() == 0 {
+ (0, 0)
} else {
- match &layout.abi {
- Abi::Uninhabited => PassMode::NoPass,
- Abi::Scalar(scalar) => PassMode::ByVal(scalar_to_clif_type(tcx, scalar.clone())),
- Abi::ScalarPair(a, b) => {
- let a = scalar_to_clif_type(tcx, a.clone());
- let b = scalar_to_clif_type(tcx, b.clone());
- if a == types::I128 && b == types::I128 {
- // Returning (i128, i128) by-val-pair would take 4 regs, while only 3 are
- // available on x86_64. Cranelift gets confused when too many return params
- // are used.
- PassMode::ByRef {
- size: Some(layout.size),
- }
- } else {
- PassMode::ByValPair(a, b)
- }
- }
+ (
+ cast.rest.total.bytes() / cast.rest.unit.size.bytes(),
+ cast.rest.total.bytes() % cast.rest.unit.size.bytes(),
+ )
+ };
- // FIXME implement Vector Abi in a cg_llvm compatible way
- Abi::Vector { .. } => {
- if let Some(vector_ty) = crate::intrinsics::clif_vector_type(tcx, layout) {
- PassMode::ByVal(vector_ty)
- } else {
- PassMode::ByRef {
- size: Some(layout.size),
- }
- }
- }
-
- Abi::Aggregate { sized: true } => PassMode::ByRef {
- size: Some(layout.size),
- },
- Abi::Aggregate { sized: false } => PassMode::ByRef { size: None },
+ if cast.prefix.iter().all(|x| x.is_none()) {
+ // Simplify to a single unit when there is no prefix and size <= unit size
+ if cast.rest.total <= cast.rest.unit.size {
+ let clif_ty = match (cast.rest.unit.kind, cast.rest.unit.size.bytes()) {
+ (RegKind::Integer, 1) => types::I8,
+ (RegKind::Integer, 2) => types::I16,
+ (RegKind::Integer, 3..=4) => types::I32,
+ (RegKind::Integer, 5..=8) => types::I64,
+ (RegKind::Integer, 9..=16) => types::I128,
+ (RegKind::Float, 4) => types::F32,
+ (RegKind::Float, 8) => types::F64,
+ (RegKind::Vector, size) => types::I8.by(u16::try_from(size).unwrap()).unwrap(),
+ _ => unreachable!("{:?}", cast.rest.unit),
+ };
+ return smallvec![AbiParam::new(clif_ty)];
}
}
+
+ // Create list of fields in the main structure
+ let mut args = cast
+ .prefix
+ .iter()
+ .flatten()
+ .map(|&kind| {
+ reg_to_abi_param(Reg {
+ kind,
+ size: cast.prefix_chunk_size,
+ })
+ })
+ .chain((0..rest_count).map(|_| reg_to_abi_param(cast.rest.unit)))
+ .collect::<SmallVec<_>>();
+
+ // Append final integer
+ if rem_bytes != 0 {
+ // Only integers can be really split further.
+ assert_eq!(cast.rest.unit.kind, RegKind::Integer);
+ args.push(reg_to_abi_param(Reg {
+ kind: RegKind::Integer,
+ size: Size::from_bytes(rem_bytes),
+ }));
+ }
+
+ args
+}
+
+impl<'tcx> ArgAbiExt<'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
+ fn get_abi_param(&self, tcx: TyCtxt<'tcx>) -> SmallVec<[AbiParam; 2]> {
+ match self.mode {
+ PassMode::Ignore => smallvec![],
+ PassMode::Direct(attrs) => match &self.layout.abi {
+ Abi::Scalar(scalar) => {
+ smallvec![apply_arg_attrs_to_abi_param(
+ AbiParam::new(scalar_to_clif_type(tcx, scalar.clone())),
+ attrs
+ )]
+ }
+ Abi::Vector { .. } => {
+ let vector_ty = crate::intrinsics::clif_vector_type(tcx, self.layout).unwrap();
+ smallvec![AbiParam::new(vector_ty)]
+ }
+ _ => unreachable!("{:?}", self.layout.abi),
+ },
+ PassMode::Pair(attrs_a, attrs_b) => match &self.layout.abi {
+ Abi::ScalarPair(a, b) => {
+ let a = scalar_to_clif_type(tcx, a.clone());
+ let b = scalar_to_clif_type(tcx, b.clone());
+ smallvec![
+ apply_arg_attrs_to_abi_param(AbiParam::new(a), attrs_a),
+ apply_arg_attrs_to_abi_param(AbiParam::new(b), attrs_b),
+ ]
+ }
+ _ => unreachable!("{:?}", self.layout.abi),
+ },
+ PassMode::Cast(cast) => cast_target_to_abi_params(cast),
+ PassMode::Indirect {
+ attrs,
+ extra_attrs: None,
+ on_stack,
+ } => {
+ if on_stack {
+ let size = u32::try_from(self.layout.size.bytes()).unwrap();
+ smallvec![apply_arg_attrs_to_abi_param(
+ AbiParam::special(pointer_ty(tcx), ArgumentPurpose::StructArgument(size),),
+ attrs
+ )]
+ } else {
+ smallvec![apply_arg_attrs_to_abi_param(
+ AbiParam::new(pointer_ty(tcx)),
+ attrs
+ )]
+ }
+ }
+ PassMode::Indirect {
+ attrs,
+ extra_attrs: Some(extra_attrs),
+ on_stack,
+ } => {
+ assert!(!on_stack);
+ smallvec![
+ apply_arg_attrs_to_abi_param(AbiParam::new(pointer_ty(tcx)), attrs),
+ apply_arg_attrs_to_abi_param(AbiParam::new(pointer_ty(tcx)), extra_attrs),
+ ]
+ }
+ }
+ }
+
+ fn get_abi_return(&self, tcx: TyCtxt<'tcx>) -> (Option<AbiParam>, Vec<AbiParam>) {
+ match self.mode {
+ PassMode::Ignore => (None, vec![]),
+ PassMode::Direct(_) => match &self.layout.abi {
+ Abi::Scalar(scalar) => (
+ None,
+ vec![AbiParam::new(scalar_to_clif_type(tcx, scalar.clone()))],
+ ),
+ Abi::Vector { .. } => {
+ let vector_ty = crate::intrinsics::clif_vector_type(tcx, self.layout).unwrap();
+ (None, vec![AbiParam::new(vector_ty)])
+ }
+ _ => unreachable!("{:?}", self.layout.abi),
+ },
+ PassMode::Pair(_, _) => match &self.layout.abi {
+ Abi::ScalarPair(a, b) => {
+ let a = scalar_to_clif_type(tcx, a.clone());
+ let b = scalar_to_clif_type(tcx, b.clone());
+ (None, vec![AbiParam::new(a), AbiParam::new(b)])
+ }
+ _ => unreachable!("{:?}", self.layout.abi),
+ },
+ PassMode::Cast(cast) => (None, cast_target_to_abi_params(cast).into_iter().collect()),
+ PassMode::Indirect {
+ attrs: _,
+ extra_attrs: None,
+ on_stack,
+ } => {
+ assert!(!on_stack);
+ (
+ Some(AbiParam::special(
+ pointer_ty(tcx),
+ ArgumentPurpose::StructReturn,
+ )),
+ vec![],
+ )
+ }
+ PassMode::Indirect {
+ attrs: _,
+ extra_attrs: Some(_),
+ on_stack: _,
+ } => unreachable!("unsized return value"),
+ }
+ }
+}
+
+pub(super) fn to_casted_value<'tcx>(
+ fx: &mut FunctionCx<'_, 'tcx, impl Module>,
+ arg: CValue<'tcx>,
+ cast: CastTarget,
+) -> SmallVec<[Value; 2]> {
+ let (ptr, meta) = arg.force_stack(fx);
+ assert!(meta.is_none());
+ let mut offset = 0;
+ cast_target_to_abi_params(cast)
+ .into_iter()
+ .map(|param| {
+ let val = ptr
+ .offset_i64(fx, offset)
+ .load(fx, param.value_type, MemFlags::new());
+ offset += i64::from(param.value_type.bytes());
+ val
+ })
+ .collect()
+}
+
+pub(super) fn from_casted_value<'tcx>(
+ fx: &mut FunctionCx<'_, 'tcx, impl Module>,
+ block_params: &[Value],
+ layout: TyAndLayout<'tcx>,
+ cast: CastTarget,
+) -> CValue<'tcx> {
+ let abi_params = cast_target_to_abi_params(cast);
+ let abi_param_size: u32 = abi_params
+ .iter()
+ .map(|param| param.value_type.bytes())
+ .sum();
+ let layout_size = u32::try_from(layout.size.bytes()).unwrap();
+ let stack_slot = fx.bcx.create_stack_slot(StackSlotData {
+ kind: StackSlotKind::ExplicitSlot,
+ // FIXME Don't force the size to a multiple of 16 bytes once Cranelift gets a way to
+ // specify stack slot alignment.
+ // Stack slot size may be bigger for for example `[u8; 3]` which is packed into an `i32`.
+ // It may also be smaller for example when the type is a wrapper around an integer with a
+ // larger alignment than the integer.
+ size: (std::cmp::max(abi_param_size, layout_size) + 15) / 16 * 16,
+ offset: None,
+ });
+ let ptr = Pointer::new(fx.bcx.ins().stack_addr(pointer_ty(fx.tcx), stack_slot, 0));
+ let mut offset = 0;
+ let mut block_params_iter = block_params.into_iter().copied();
+ for param in abi_params {
+ let val = ptr.offset_i64(fx, offset).store(
+ fx,
+ block_params_iter.next().unwrap(),
+ MemFlags::new(),
+ );
+ offset += i64::from(param.value_type.bytes());
+ val
+ }
+ assert_eq!(block_params_iter.next(), None, "Leftover block param");
+ CValue::by_ref(ptr, layout)
}
/// Get a set of values to be passed as function arguments.
pub(super) fn adjust_arg_for_abi<'tcx>(
fx: &mut FunctionCx<'_, 'tcx, impl Module>,
arg: CValue<'tcx>,
-) -> EmptySinglePair<Value> {
- match get_pass_mode(fx.tcx, arg.layout()) {
- PassMode::NoPass => Empty,
- PassMode::ByVal(_) => Single(arg.load_scalar(fx)),
- PassMode::ByValPair(_, _) => {
+ arg_abi: &ArgAbi<'tcx, Ty<'tcx>>,
+) -> SmallVec<[Value; 2]> {
+ assert_assignable(fx, arg.layout().ty, arg_abi.layout.ty);
+ match arg_abi.mode {
+ PassMode::Ignore => smallvec![],
+ PassMode::Direct(_) => smallvec![arg.load_scalar(fx)],
+ PassMode::Pair(_, _) => {
let (a, b) = arg.load_scalar_pair(fx);
- Pair(a, b)
+ smallvec![a, b]
}
- PassMode::ByRef { size: _ } => match arg.force_stack(fx) {
- (ptr, None) => Single(ptr.get_addr(fx)),
- (ptr, Some(meta)) => Pair(ptr.get_addr(fx), meta),
+ PassMode::Cast(cast) => to_casted_value(fx, arg, cast),
+ PassMode::Indirect { .. } => match arg.force_stack(fx) {
+ (ptr, None) => smallvec![ptr.get_addr(fx)],
+ (ptr, Some(meta)) => smallvec![ptr.get_addr(fx), meta],
},
}
}
@@ -143,20 +284,23 @@
/// as necessary.
pub(super) fn cvalue_for_param<'tcx>(
fx: &mut FunctionCx<'_, 'tcx, impl Module>,
- start_block: Block,
#[cfg_attr(not(debug_assertions), allow(unused_variables))] local: Option<mir::Local>,
#[cfg_attr(not(debug_assertions), allow(unused_variables))] local_field: Option<usize>,
- arg_ty: Ty<'tcx>,
+ arg_abi: &ArgAbi<'tcx, Ty<'tcx>>,
+ block_params_iter: &mut impl Iterator<Item = Value>,
) -> Option<CValue<'tcx>> {
- let layout = fx.layout_of(arg_ty);
- let pass_mode = get_pass_mode(fx.tcx, layout);
-
- if let PassMode::NoPass = pass_mode {
- return None;
- }
-
- let clif_types = pass_mode.get_param_ty(fx.tcx);
- let block_params = clif_types.map(|t| fx.bcx.append_block_param(start_block, t));
+ let block_params = arg_abi
+ .get_abi_param(fx.tcx)
+ .into_iter()
+ .map(|abi_param| {
+ let block_param = block_params_iter.next().unwrap();
+ assert_eq!(
+ fx.bcx.func.dfg.value_type(block_param),
+ abi_param.value_type
+ );
+ block_param
+ })
+ .collect::<SmallVec<[_; 2]>>();
#[cfg(debug_assertions)]
crate::abi::comments::add_arg_comment(
@@ -164,25 +308,48 @@
"arg",
local,
local_field,
- block_params,
- pass_mode,
- arg_ty,
+ &block_params,
+ arg_abi.mode,
+ arg_abi.layout,
);
- match pass_mode {
- PassMode::NoPass => unreachable!(),
- PassMode::ByVal(_) => Some(CValue::by_val(block_params.assert_single(), layout)),
- PassMode::ByValPair(_, _) => {
- let (a, b) = block_params.assert_pair();
- Some(CValue::by_val_pair(a, b, layout))
+ match arg_abi.mode {
+ PassMode::Ignore => None,
+ PassMode::Direct(_) => {
+ assert_eq!(block_params.len(), 1, "{:?}", block_params);
+ Some(CValue::by_val(block_params[0], arg_abi.layout))
}
- PassMode::ByRef { size: Some(_) } => Some(CValue::by_ref(
- Pointer::new(block_params.assert_single()),
- layout,
- )),
- PassMode::ByRef { size: None } => {
- let (ptr, meta) = block_params.assert_pair();
- Some(CValue::by_ref_unsized(Pointer::new(ptr), meta, layout))
+ PassMode::Pair(_, _) => {
+ assert_eq!(block_params.len(), 2, "{:?}", block_params);
+ Some(CValue::by_val_pair(
+ block_params[0],
+ block_params[1],
+ arg_abi.layout,
+ ))
+ }
+ PassMode::Cast(cast) => Some(from_casted_value(fx, &block_params, arg_abi.layout, cast)),
+ PassMode::Indirect {
+ attrs: _,
+ extra_attrs: None,
+ on_stack: _,
+ } => {
+ assert_eq!(block_params.len(), 1, "{:?}", block_params);
+ Some(CValue::by_ref(
+ Pointer::new(block_params[0]),
+ arg_abi.layout,
+ ))
+ }
+ PassMode::Indirect {
+ attrs: _,
+ extra_attrs: Some(_),
+ on_stack: _,
+ } => {
+ assert_eq!(block_params.len(), 2, "{:?}", block_params);
+ Some(CValue::by_ref_unsized(
+ Pointer::new(block_params[0]),
+ block_params[1],
+ arg_abi.layout,
+ ))
}
}
}
diff --git a/compiler/rustc_codegen_cranelift/src/abi/returning.rs b/compiler/rustc_codegen_cranelift/src/abi/returning.rs
index f6d40c8..a382963 100644
--- a/compiler/rustc_codegen_cranelift/src/abi/returning.rs
+++ b/compiler/rustc_codegen_cranelift/src/abi/returning.rs
@@ -1,21 +1,57 @@
//! Return value handling
-use crate::abi::pass_mode::*;
use crate::prelude::*;
-fn return_layout<'a, 'tcx>(fx: &mut FunctionCx<'a, 'tcx, impl Module>) -> TyAndLayout<'tcx> {
- fx.layout_of(fx.monomorphize(&fx.mir.local_decls[RETURN_PLACE].ty))
-}
+use rustc_middle::ty::layout::FnAbiExt;
+use rustc_target::abi::call::{ArgAbi, FnAbi, PassMode};
+use smallvec::{smallvec, SmallVec};
/// Can the given type be returned into an ssa var or does it need to be returned on the stack.
pub(crate) fn can_return_to_ssa_var<'tcx>(
- tcx: TyCtxt<'tcx>,
- dest_layout: TyAndLayout<'tcx>,
+ fx: &FunctionCx<'_, 'tcx, impl Module>,
+ func: &mir::Operand<'tcx>,
+ args: &[mir::Operand<'tcx>],
) -> bool {
- match get_pass_mode(tcx, dest_layout) {
- PassMode::NoPass | PassMode::ByVal(_) | PassMode::ByValPair(_, _) => true,
- // FIXME Make it possible to return ByRef to an ssa var.
- PassMode::ByRef { size: _ } => false,
+ let fn_ty = fx.monomorphize(func.ty(fx.mir, fx.tcx));
+ let fn_sig = fx
+ .tcx
+ .normalize_erasing_late_bound_regions(ParamEnv::reveal_all(), fn_ty.fn_sig(fx.tcx));
+
+ // Handle special calls like instrinsics and empty drop glue.
+ let instance = if let ty::FnDef(def_id, substs) = *fn_ty.kind() {
+ let instance = ty::Instance::resolve(fx.tcx, ty::ParamEnv::reveal_all(), def_id, substs)
+ .unwrap()
+ .unwrap()
+ .polymorphize(fx.tcx);
+
+ match instance.def {
+ InstanceDef::Intrinsic(_) | InstanceDef::DropGlue(_, _) => {
+ return true;
+ }
+ _ => Some(instance),
+ }
+ } else {
+ None
+ };
+
+ let extra_args = &args[fn_sig.inputs().len()..];
+ let extra_args = extra_args
+ .iter()
+ .map(|op_arg| fx.monomorphize(op_arg.ty(fx.mir, fx.tcx)))
+ .collect::<Vec<_>>();
+ let fn_abi = if let Some(instance) = instance {
+ FnAbi::of_instance(&RevealAllLayoutCx(fx.tcx), instance, &extra_args)
+ } else {
+ FnAbi::of_fn_ptr(
+ &RevealAllLayoutCx(fx.tcx),
+ fn_ty.fn_sig(fx.tcx),
+ &extra_args,
+ )
+ };
+ match fn_abi.ret.mode {
+ PassMode::Ignore | PassMode::Direct(_) | PassMode::Pair(_, _) => true,
+ // FIXME Make it possible to return Cast and Indirect to an ssa var.
+ PassMode::Cast(_) | PassMode::Indirect { .. } => false,
}
}
@@ -24,27 +60,45 @@
pub(super) fn codegen_return_param<'tcx>(
fx: &mut FunctionCx<'_, 'tcx, impl Module>,
ssa_analyzed: &rustc_index::vec::IndexVec<Local, crate::analyze::SsaKind>,
- start_block: Block,
+ block_params_iter: &mut impl Iterator<Item = Value>,
) -> CPlace<'tcx> {
- let ret_layout = return_layout(fx);
- let ret_pass_mode = get_pass_mode(fx.tcx, ret_layout);
- let (ret_place, ret_param) = match ret_pass_mode {
- PassMode::NoPass => (CPlace::no_place(ret_layout), Empty),
- PassMode::ByVal(_) | PassMode::ByValPair(_, _) => {
+ let (ret_place, ret_param): (_, SmallVec<[_; 2]>) = match fx.fn_abi.as_ref().unwrap().ret.mode {
+ PassMode::Ignore => (
+ CPlace::no_place(fx.fn_abi.as_ref().unwrap().ret.layout),
+ smallvec![],
+ ),
+ PassMode::Direct(_) | PassMode::Pair(_, _) | PassMode::Cast(_) => {
let is_ssa = ssa_analyzed[RETURN_PLACE] == crate::analyze::SsaKind::Ssa;
(
- super::make_local_place(fx, RETURN_PLACE, ret_layout, is_ssa),
- Empty,
+ super::make_local_place(
+ fx,
+ RETURN_PLACE,
+ fx.fn_abi.as_ref().unwrap().ret.layout,
+ is_ssa,
+ ),
+ smallvec![],
)
}
- PassMode::ByRef { size: Some(_) } => {
- let ret_param = fx.bcx.append_block_param(start_block, fx.pointer_type);
+ PassMode::Indirect {
+ attrs: _,
+ extra_attrs: None,
+ on_stack: _,
+ } => {
+ let ret_param = block_params_iter.next().unwrap();
+ assert_eq!(fx.bcx.func.dfg.value_type(ret_param), pointer_ty(fx.tcx));
(
- CPlace::for_ptr(Pointer::new(ret_param), ret_layout),
- Single(ret_param),
+ CPlace::for_ptr(
+ Pointer::new(ret_param),
+ fx.fn_abi.as_ref().unwrap().ret.layout,
+ ),
+ smallvec![ret_param],
)
}
- PassMode::ByRef { size: None } => todo!(),
+ PassMode::Indirect {
+ attrs: _,
+ extra_attrs: Some(_),
+ on_stack: _,
+ } => unreachable!("unsized return value"),
};
#[cfg(not(debug_assertions))]
@@ -56,9 +110,9 @@
"ret",
Some(RETURN_PLACE),
None,
- ret_param,
- ret_pass_mode,
- ret_layout.ty,
+ &ret_param,
+ fx.fn_abi.as_ref().unwrap().ret.mode,
+ fx.fn_abi.as_ref().unwrap().ret.layout,
);
ret_place
@@ -68,42 +122,71 @@
/// returns the call return value(s) if any are written to the correct place.
pub(super) fn codegen_with_call_return_arg<'tcx, M: Module, T>(
fx: &mut FunctionCx<'_, 'tcx, M>,
- fn_sig: FnSig<'tcx>,
+ ret_arg_abi: &ArgAbi<'tcx, Ty<'tcx>>,
ret_place: Option<CPlace<'tcx>>,
f: impl FnOnce(&mut FunctionCx<'_, 'tcx, M>, Option<Value>) -> (Inst, T),
) -> (Inst, T) {
- let ret_layout = fx.layout_of(fn_sig.output());
-
- let output_pass_mode = get_pass_mode(fx.tcx, ret_layout);
- let return_ptr = match output_pass_mode {
- PassMode::NoPass => None,
- PassMode::ByRef { size: Some(_) } => match ret_place {
+ let return_ptr = match ret_arg_abi.mode {
+ PassMode::Ignore => None,
+ PassMode::Indirect {
+ attrs: _,
+ extra_attrs: None,
+ on_stack: _,
+ } => match ret_place {
Some(ret_place) => Some(ret_place.to_ptr().get_addr(fx)),
None => Some(fx.bcx.ins().iconst(fx.pointer_type, 43)), // FIXME allocate temp stack slot
},
- PassMode::ByRef { size: None } => todo!(),
- PassMode::ByVal(_) | PassMode::ByValPair(_, _) => None,
+ PassMode::Indirect {
+ attrs: _,
+ extra_attrs: Some(_),
+ on_stack: _,
+ } => unreachable!("unsized return value"),
+ PassMode::Direct(_) | PassMode::Pair(_, _) | PassMode::Cast(_) => None,
};
let (call_inst, meta) = f(fx, return_ptr);
- match output_pass_mode {
- PassMode::NoPass => {}
- PassMode::ByVal(_) => {
+ match ret_arg_abi.mode {
+ PassMode::Ignore => {}
+ PassMode::Direct(_) => {
if let Some(ret_place) = ret_place {
let ret_val = fx.bcx.inst_results(call_inst)[0];
- ret_place.write_cvalue(fx, CValue::by_val(ret_val, ret_layout));
+ ret_place.write_cvalue(fx, CValue::by_val(ret_val, ret_arg_abi.layout));
}
}
- PassMode::ByValPair(_, _) => {
+ PassMode::Pair(_, _) => {
if let Some(ret_place) = ret_place {
let ret_val_a = fx.bcx.inst_results(call_inst)[0];
let ret_val_b = fx.bcx.inst_results(call_inst)[1];
- ret_place.write_cvalue(fx, CValue::by_val_pair(ret_val_a, ret_val_b, ret_layout));
+ ret_place.write_cvalue(
+ fx,
+ CValue::by_val_pair(ret_val_a, ret_val_b, ret_arg_abi.layout),
+ );
}
}
- PassMode::ByRef { size: Some(_) } => {}
- PassMode::ByRef { size: None } => todo!(),
+ PassMode::Cast(cast) => {
+ if let Some(ret_place) = ret_place {
+ let results = fx
+ .bcx
+ .inst_results(call_inst)
+ .into_iter()
+ .copied()
+ .collect::<SmallVec<[Value; 2]>>();
+ let result =
+ super::pass_mode::from_casted_value(fx, &results, ret_place.layout(), cast);
+ ret_place.write_cvalue(fx, result);
+ }
+ }
+ PassMode::Indirect {
+ attrs: _,
+ extra_attrs: None,
+ on_stack: _,
+ } => {}
+ PassMode::Indirect {
+ attrs: _,
+ extra_attrs: Some(_),
+ on_stack: _,
+ } => unreachable!("unsized return value"),
}
(call_inst, meta)
@@ -111,20 +194,35 @@
/// Codegen a return instruction with the right return value(s) if any.
pub(crate) fn codegen_return(fx: &mut FunctionCx<'_, '_, impl Module>) {
- match get_pass_mode(fx.tcx, return_layout(fx)) {
- PassMode::NoPass | PassMode::ByRef { size: Some(_) } => {
+ match fx.fn_abi.as_ref().unwrap().ret.mode {
+ PassMode::Ignore
+ | PassMode::Indirect {
+ attrs: _,
+ extra_attrs: None,
+ on_stack: _,
+ } => {
fx.bcx.ins().return_(&[]);
}
- PassMode::ByRef { size: None } => todo!(),
- PassMode::ByVal(_) => {
+ PassMode::Indirect {
+ attrs: _,
+ extra_attrs: Some(_),
+ on_stack: _,
+ } => unreachable!("unsized return value"),
+ PassMode::Direct(_) => {
let place = fx.get_local_place(RETURN_PLACE);
let ret_val = place.to_cvalue(fx).load_scalar(fx);
fx.bcx.ins().return_(&[ret_val]);
}
- PassMode::ByValPair(_, _) => {
+ PassMode::Pair(_, _) => {
let place = fx.get_local_place(RETURN_PLACE);
let (ret_val_a, ret_val_b) = place.to_cvalue(fx).load_scalar_pair(fx);
fx.bcx.ins().return_(&[ret_val_a, ret_val_b]);
}
+ PassMode::Cast(cast) => {
+ let place = fx.get_local_place(RETURN_PLACE);
+ let ret_val = place.to_cvalue(fx);
+ let ret_vals = super::pass_mode::to_casted_value(fx, ret_val, cast);
+ fx.bcx.ins().return_(&ret_vals);
+ }
}
}
diff --git a/compiler/rustc_codegen_cranelift/src/analyze.rs b/compiler/rustc_codegen_cranelift/src/analyze.rs
index adf5c7a..62fbcfe 100644
--- a/compiler/rustc_codegen_cranelift/src/analyze.rs
+++ b/compiler/rustc_codegen_cranelift/src/analyze.rs
@@ -40,11 +40,14 @@
}
match &bb.terminator().kind {
- TerminatorKind::Call { destination, .. } => {
+ TerminatorKind::Call {
+ destination,
+ func,
+ args,
+ ..
+ } => {
if let Some((dest_place, _dest_bb)) = destination {
- let dest_layout = fx
- .layout_of(fx.monomorphize(&dest_place.ty(&fx.mir.local_decls, fx.tcx).ty));
- if !crate::abi::can_return_to_ssa_var(fx.tcx, dest_layout) {
+ if !crate::abi::can_return_to_ssa_var(fx, func, args) {
not_ssa(&mut flag_map, dest_place.local)
}
}
diff --git a/compiler/rustc_codegen_cranelift/src/backend.rs b/compiler/rustc_codegen_cranelift/src/backend.rs
index 9e32259..0ce34c9 100644
--- a/compiler/rustc_codegen_cranelift/src/backend.rs
+++ b/compiler/rustc_codegen_cranelift/src/backend.rs
@@ -162,7 +162,7 @@
}
pub(crate) fn with_object(sess: &Session, name: &str, f: impl FnOnce(&mut Object)) -> Vec<u8> {
- let triple = crate::build_isa(sess, true).triple().clone();
+ let triple = crate::build_isa(sess).triple().clone();
let binary_format = match triple.binary_format {
target_lexicon::BinaryFormat::Elf => object::BinaryFormat::Elf,
@@ -193,7 +193,7 @@
pub(crate) fn make_module(sess: &Session, name: String) -> ObjectModule {
let mut builder = ObjectBuilder::new(
- crate::build_isa(sess, true),
+ crate::build_isa(sess),
name + ".o",
cranelift_module::default_libcall_names(),
)
diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs
index 7207389..4842628 100644
--- a/compiler/rustc_codegen_cranelift/src/base.rs
+++ b/compiler/rustc_codegen_cranelift/src/base.rs
@@ -2,6 +2,8 @@
use rustc_index::vec::IndexVec;
use rustc_middle::ty::adjustment::PointerCast;
+use rustc_middle::ty::layout::FnAbiExt;
+use rustc_target::abi::call::FnAbi;
use crate::prelude::*;
@@ -19,7 +21,8 @@
let mir = tcx.instance_mir(instance.def);
// Declare function
- let (name, sig) = get_function_name_and_sig(tcx, cx.module.isa().triple(), instance, false);
+ let name = tcx.symbol_name(instance).name.to_string();
+ let sig = get_function_sig(tcx, cx.module.isa().triple(), instance);
let func_id = cx.module.declare_function(&name, linkage, &sig).unwrap();
cx.cached_context.clear();
@@ -50,6 +53,7 @@
instance,
mir,
+ fn_abi: Some(FnAbi::of_instance(&RevealAllLayoutCx(tcx), instance, &[])),
bcx,
block_map,
@@ -117,6 +121,11 @@
context.compute_domtree();
context.eliminate_unreachable_code(cx.module.isa()).unwrap();
context.dce(cx.module.isa()).unwrap();
+ // Some Cranelift optimizations expect the domtree to not yet be computed and as such don't
+ // invalidate it when it would change.
+ context.domtree.clear();
+
+ context.want_disasm = crate::pretty_clif::should_write_ir(tcx);
// Define function
let module = &mut cx.module;
@@ -140,6 +149,16 @@
&clif_comments,
);
+ if let Some(mach_compile_result) = &context.mach_compile_result {
+ if let Some(disasm) = &mach_compile_result.disasm {
+ crate::pretty_clif::write_ir_file(
+ tcx,
+ &format!("{}.vcode", tcx.symbol_name(instance).name),
+ |file| file.write_all(disasm.as_bytes()),
+ )
+ }
+ }
+
// Define debuginfo for function
let isa = cx.module.isa();
let debug_context = &mut cx.debug_context;
@@ -307,7 +326,9 @@
} => {
let discr = codegen_operand(fx, discr).load_scalar(fx);
- if switch_ty.kind() == fx.tcx.types.bool.kind() {
+ let use_bool_opt = switch_ty.kind() == fx.tcx.types.bool.kind()
+ || (targets.iter().count() == 1 && targets.iter().next().unwrap().0 == 0);
+ if use_bool_opt {
assert_eq!(targets.iter().count(), 1);
let (then_value, then_block) = targets.iter().next().unwrap();
let then_block = fx.get_block(then_block);
@@ -325,12 +346,22 @@
let discr = crate::optimize::peephole::maybe_unwrap_bint(&mut fx.bcx, discr);
let discr =
crate::optimize::peephole::make_branchable_value(&mut fx.bcx, discr);
- if test_zero {
- fx.bcx.ins().brz(discr, then_block, &[]);
- fx.bcx.ins().jump(else_block, &[]);
+ if let Some(taken) = crate::optimize::peephole::maybe_known_branch_taken(
+ &fx.bcx, discr, test_zero,
+ ) {
+ if taken {
+ fx.bcx.ins().jump(then_block, &[]);
+ } else {
+ fx.bcx.ins().jump(else_block, &[]);
+ }
} else {
- fx.bcx.ins().brnz(discr, then_block, &[]);
- fx.bcx.ins().jump(else_block, &[]);
+ if test_zero {
+ fx.bcx.ins().brz(discr, then_block, &[]);
+ fx.bcx.ins().jump(else_block, &[]);
+ } else {
+ fx.bcx.ins().brnz(discr, then_block, &[]);
+ fx.bcx.ins().jump(else_block, &[]);
+ }
}
} else {
let mut switch = ::cranelift_frontend::Switch::new();
@@ -1029,7 +1060,11 @@
fx.lib_call(
&*symbol_name,
- vec![fx.pointer_type, fx.pointer_type, fx.pointer_type],
+ vec![
+ AbiParam::new(fx.pointer_type),
+ AbiParam::new(fx.pointer_type),
+ AbiParam::new(fx.pointer_type),
+ ],
vec![],
args,
);
diff --git a/compiler/rustc_codegen_cranelift/src/bin/cg_clif.rs b/compiler/rustc_codegen_cranelift/src/bin/cg_clif.rs
index f4d23eb..be369b0 100644
--- a/compiler/rustc_codegen_cranelift/src/bin/cg_clif.rs
+++ b/compiler/rustc_codegen_cranelift/src/bin/cg_clif.rs
@@ -6,7 +6,7 @@
extern crate rustc_session;
extern crate rustc_target;
-use rustc_data_structures::profiling::print_time_passes_entry;
+use rustc_data_structures::profiling::{get_resident_set_size, print_time_passes_entry};
use rustc_interface::interface;
use rustc_session::config::ErrorOutputType;
use rustc_session::early_error;
@@ -39,14 +39,13 @@
}
fn main() {
- let start = std::time::Instant::now();
+ let start_time = std::time::Instant::now();
+ let start_rss = get_resident_set_size();
rustc_driver::init_rustc_env_logger();
let mut callbacks = CraneliftPassesCallbacks::default();
rustc_driver::install_ice_hook();
let exit_code = rustc_driver::catch_with_exit_code(|| {
- let mut use_jit = false;
-
- let mut args = std::env::args_os()
+ let args = std::env::args_os()
.enumerate()
.map(|(i, arg)| {
arg.into_string().unwrap_or_else(|arg| {
@@ -56,27 +55,18 @@
)
})
})
- .filter(|arg| {
- if arg == "--jit" {
- use_jit = true;
- false
- } else {
- true
- }
- })
.collect::<Vec<_>>();
- if use_jit {
- args.push("-Cprefer-dynamic".to_string());
- }
let mut run_compiler = rustc_driver::RunCompiler::new(&args, &mut callbacks);
run_compiler.set_make_codegen_backend(Some(Box::new(move |_| {
- Box::new(rustc_codegen_cranelift::CraneliftCodegenBackend {
- config: rustc_codegen_cranelift::BackendConfig { use_jit },
- })
+ Box::new(rustc_codegen_cranelift::CraneliftCodegenBackend { config: None })
})));
run_compiler.run()
});
- // The extra `\t` is necessary to align this label with the others.
- print_time_passes_entry(callbacks.time_passes, "\ttotal", start.elapsed());
+
+ if callbacks.time_passes {
+ let end_rss = get_resident_set_size();
+ print_time_passes_entry("total", start_time.elapsed(), start_rss, end_rss);
+ }
+
std::process::exit(exit_code)
}
diff --git a/compiler/rustc_codegen_cranelift/src/bin/cg_clif_build_sysroot.rs b/compiler/rustc_codegen_cranelift/src/bin/cg_clif_build_sysroot.rs
index 165d33d..83e5dc6 100644
--- a/compiler/rustc_codegen_cranelift/src/bin/cg_clif_build_sysroot.rs
+++ b/compiler/rustc_codegen_cranelift/src/bin/cg_clif_build_sysroot.rs
@@ -53,10 +53,7 @@
.unwrap()
.parent()
.unwrap()
- .parent()
- .unwrap()
- .join("build_sysroot")
- .join("sysroot"),
+ .to_owned(),
);
}
}
@@ -92,9 +89,7 @@
let mut run_compiler = rustc_driver::RunCompiler::new(&args, &mut callbacks);
if use_clif {
run_compiler.set_make_codegen_backend(Some(Box::new(move |_| {
- Box::new(rustc_codegen_cranelift::CraneliftCodegenBackend {
- config: rustc_codegen_cranelift::BackendConfig { use_jit: false },
- })
+ Box::new(rustc_codegen_cranelift::CraneliftCodegenBackend { config: None })
})));
}
run_compiler.run()
diff --git a/compiler/rustc_codegen_cranelift/src/codegen_i128.rs b/compiler/rustc_codegen_cranelift/src/codegen_i128.rs
index d6a38bd..866ba90 100644
--- a/compiler/rustc_codegen_cranelift/src/codegen_i128.rs
+++ b/compiler/rustc_codegen_cranelift/src/codegen_i128.rs
@@ -1,5 +1,7 @@
//! Replaces 128-bit operators with lang item calls where necessary
+use cranelift_codegen::ir::ArgumentPurpose;
+
use crate::prelude::*;
pub(crate) fn maybe_codegen<'tcx>(
@@ -24,41 +26,41 @@
None
}
BinOp::Add | BinOp::Sub if !checked => None,
- BinOp::Add => {
- let out_ty = fx.tcx.mk_tup([lhs.layout().ty, fx.tcx.types.bool].iter());
- return Some(if is_signed {
- fx.easy_call("__rust_i128_addo", &[lhs, rhs], out_ty)
+ BinOp::Mul if !checked => {
+ let val_ty = if is_signed {
+ fx.tcx.types.i128
} else {
- fx.easy_call("__rust_u128_addo", &[lhs, rhs], out_ty)
- });
+ fx.tcx.types.u128
+ };
+ Some(fx.easy_call("__multi3", &[lhs, rhs], val_ty))
}
- BinOp::Sub => {
+ BinOp::Add | BinOp::Sub | BinOp::Mul => {
+ assert!(checked);
let out_ty = fx.tcx.mk_tup([lhs.layout().ty, fx.tcx.types.bool].iter());
- return Some(if is_signed {
- fx.easy_call("__rust_i128_subo", &[lhs, rhs], out_ty)
- } else {
- fx.easy_call("__rust_u128_subo", &[lhs, rhs], out_ty)
- });
+ let out_place = CPlace::new_stack_slot(fx, fx.layout_of(out_ty));
+ let param_types = vec![
+ AbiParam::special(pointer_ty(fx.tcx), ArgumentPurpose::StructReturn),
+ AbiParam::new(types::I128),
+ AbiParam::new(types::I128),
+ ];
+ let args = [
+ out_place.to_ptr().get_addr(fx),
+ lhs.load_scalar(fx),
+ rhs.load_scalar(fx),
+ ];
+ let name = match (bin_op, is_signed) {
+ (BinOp::Add, false) => "__rust_u128_addo",
+ (BinOp::Add, true) => "__rust_i128_addo",
+ (BinOp::Sub, false) => "__rust_u128_subo",
+ (BinOp::Sub, true) => "__rust_i128_subo",
+ (BinOp::Mul, false) => "__rust_u128_mulo",
+ (BinOp::Mul, true) => "__rust_i128_mulo",
+ _ => unreachable!(),
+ };
+ fx.lib_call(name, param_types, vec![], &args);
+ Some(out_place.to_cvalue(fx))
}
BinOp::Offset => unreachable!("offset should only be used on pointers, not 128bit ints"),
- BinOp::Mul => {
- let res = if checked {
- let out_ty = fx.tcx.mk_tup([lhs.layout().ty, fx.tcx.types.bool].iter());
- if is_signed {
- fx.easy_call("__rust_i128_mulo", &[lhs, rhs], out_ty)
- } else {
- fx.easy_call("__rust_u128_mulo", &[lhs, rhs], out_ty)
- }
- } else {
- let val_ty = if is_signed {
- fx.tcx.types.i128
- } else {
- fx.tcx.types.u128
- };
- fx.easy_call("__multi3", &[lhs, rhs], val_ty)
- };
- Some(res)
- }
BinOp::Div => {
assert!(!checked);
if is_signed {
diff --git a/compiler/rustc_codegen_cranelift/src/common.rs b/compiler/rustc_codegen_cranelift/src/common.rs
index 1485d44..fbee84e 100644
--- a/compiler/rustc_codegen_cranelift/src/common.rs
+++ b/compiler/rustc_codegen_cranelift/src/common.rs
@@ -1,4 +1,5 @@
use rustc_index::vec::IndexVec;
+use rustc_target::abi::call::FnAbi;
use rustc_target::abi::{Integer, Primitive};
use rustc_target::spec::{HasTargetSpec, Target};
@@ -294,6 +295,7 @@
pub(crate) instance: Instance<'tcx>,
pub(crate) mir: &'tcx Body<'tcx>,
+ pub(crate) fn_abi: Option<FnAbi<'tcx, Ty<'tcx>>>,
pub(crate) bcx: FunctionBuilder<'clif>,
pub(crate) block_map: IndexVec<BasicBlock, Block>,
@@ -319,16 +321,7 @@
type TyAndLayout = TyAndLayout<'tcx>;
fn layout_of(&self, ty: Ty<'tcx>) -> TyAndLayout<'tcx> {
- assert!(!ty.still_further_specializable());
- self.tcx
- .layout_of(ParamEnv::reveal_all().and(&ty))
- .unwrap_or_else(|e| {
- if let layout::LayoutError::SizeOverflow(_) = e {
- self.tcx.sess.fatal(&e.to_string())
- } else {
- bug!("failed to get layout for `{}`: {}", ty, e)
- }
- })
+ RevealAllLayoutCx(self.tcx).layout_of(ty)
}
}
@@ -442,3 +435,47 @@
self.bcx.ins().global_value(self.pointer_type, local_msg_id)
}
}
+
+pub(crate) struct RevealAllLayoutCx<'tcx>(pub(crate) TyCtxt<'tcx>);
+
+impl<'tcx> LayoutOf for RevealAllLayoutCx<'tcx> {
+ type Ty = Ty<'tcx>;
+ type TyAndLayout = TyAndLayout<'tcx>;
+
+ fn layout_of(&self, ty: Ty<'tcx>) -> TyAndLayout<'tcx> {
+ assert!(!ty.still_further_specializable());
+ self.0
+ .layout_of(ParamEnv::reveal_all().and(&ty))
+ .unwrap_or_else(|e| {
+ if let layout::LayoutError::SizeOverflow(_) = e {
+ self.0.sess.fatal(&e.to_string())
+ } else {
+ bug!("failed to get layout for `{}`: {}", ty, e)
+ }
+ })
+ }
+}
+
+impl<'tcx> layout::HasTyCtxt<'tcx> for RevealAllLayoutCx<'tcx> {
+ fn tcx<'b>(&'b self) -> TyCtxt<'tcx> {
+ self.0
+ }
+}
+
+impl<'tcx> rustc_target::abi::HasDataLayout for RevealAllLayoutCx<'tcx> {
+ fn data_layout(&self) -> &rustc_target::abi::TargetDataLayout {
+ &self.0.data_layout
+ }
+}
+
+impl<'tcx> layout::HasParamEnv<'tcx> for RevealAllLayoutCx<'tcx> {
+ fn param_env(&self) -> ParamEnv<'tcx> {
+ ParamEnv::reveal_all()
+ }
+}
+
+impl<'tcx> HasTargetSpec for RevealAllLayoutCx<'tcx> {
+ fn target_spec(&self) -> &Target {
+ &self.0.sess.target
+ }
+}
diff --git a/compiler/rustc_codegen_cranelift/src/constant.rs b/compiler/rustc_codegen_cranelift/src/constant.rs
index 544b020..5702832 100644
--- a/compiler/rustc_codegen_cranelift/src/constant.rs
+++ b/compiler/rustc_codegen_cranelift/src/constant.rs
@@ -100,7 +100,10 @@
let global_ptr = fx.bcx.ins().global_value(fx.pointer_type, local_data_id);
assert!(!layout.is_unsized(), "unsized statics aren't supported");
assert!(
- matches!(fx.bcx.func.global_values[local_data_id], GlobalValueData::Symbol { tls: false, ..}),
+ matches!(
+ fx.bcx.func.global_values[local_data_id],
+ GlobalValueData::Symbol { tls: false, .. }
+ ),
"tls static referenced without Rvalue::ThreadLocalRef"
);
CPlace::for_ptr(crate::pointer::Pointer::new(global_ptr), layout)
@@ -131,11 +134,9 @@
{
Ok(const_val) => const_val,
Err(_) => {
- if promoted.is_none() {
- fx.tcx
- .sess
- .span_err(constant.span, "erroneous constant encountered");
- }
+ fx.tcx
+ .sess
+ .span_err(constant.span, "erroneous constant encountered");
return crate::trap::trap_unreachable_ret_value(
fx,
fx.layout_of(const_.ty),
@@ -447,7 +448,8 @@
data_ctx.write_data_addr(offset.bytes() as u32, global_value, addend as i64);
}
- module.define_data(data_id, &data_ctx).unwrap();
+ // FIXME don't duplicate definitions in lazy jit mode
+ let _ = module.define_data(data_id, &data_ctx);
cx.done.insert(data_id);
}
diff --git a/compiler/rustc_codegen_cranelift/src/debuginfo/emit.rs b/compiler/rustc_codegen_cranelift/src/debuginfo/emit.rs
index c21835b..6160f9b 100644
--- a/compiler/rustc_codegen_cranelift/src/debuginfo/emit.rs
+++ b/compiler/rustc_codegen_cranelift/src/debuginfo/emit.rs
@@ -74,10 +74,7 @@
/// Perform the collected relocations to be usable for JIT usage.
#[cfg(feature = "jit")]
- pub(super) fn relocate_for_jit(
- mut self,
- jit_module: &cranelift_simplejit::SimpleJITModule,
- ) -> Vec<u8> {
+ pub(super) fn relocate_for_jit(mut self, jit_module: &cranelift_jit::JITModule) -> Vec<u8> {
use std::convert::TryInto;
for reloc in self.relocs.drain(..) {
diff --git a/compiler/rustc_codegen_cranelift/src/debuginfo/unwind.rs b/compiler/rustc_codegen_cranelift/src/debuginfo/unwind.rs
index e0f62b6..49de927 100644
--- a/compiler/rustc_codegen_cranelift/src/debuginfo/unwind.rs
+++ b/compiler/rustc_codegen_cranelift/src/debuginfo/unwind.rs
@@ -15,11 +15,11 @@
}
impl<'tcx> UnwindContext<'tcx> {
- pub(crate) fn new(tcx: TyCtxt<'tcx>, isa: &dyn TargetIsa) -> Self {
+ pub(crate) fn new(tcx: TyCtxt<'tcx>, isa: &dyn TargetIsa, pic_eh_frame: bool) -> Self {
let mut frame_table = FrameTable::default();
let cie_id = if let Some(mut cie) = isa.create_systemv_cie() {
- if isa.flags().is_pic() {
+ if pic_eh_frame {
cie.fde_address_encoding =
gimli::DwEhPe(gimli::DW_EH_PE_pcrel.0 | gimli::DW_EH_PE_sdata4.0);
}
@@ -80,7 +80,7 @@
#[cfg(feature = "jit")]
pub(crate) unsafe fn register_jit(
self,
- jit_module: &cranelift_simplejit::SimpleJITModule,
+ jit_module: &cranelift_jit::JITModule,
) -> Option<UnwindRegistry> {
let mut eh_frame = EhFrame::from(super::emit::WriterRelocate::new(super::target_endian(
self.tcx,
diff --git a/compiler/rustc_codegen_cranelift/src/driver/aot.rs b/compiler/rustc_codegen_cranelift/src/driver/aot.rs
index 78d6ff0..df89883 100644
--- a/compiler/rustc_codegen_cranelift/src/driver/aot.rs
+++ b/compiler/rustc_codegen_cranelift/src/driver/aot.rs
@@ -8,7 +8,7 @@
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
use rustc_middle::middle::cstore::EncodedMetadata;
-use rustc_middle::mir::mono::CodegenUnit;
+use rustc_middle::mir::mono::{CodegenUnit, MonoItem};
use rustc_session::cgu_reuse_tracker::CguReuse;
use rustc_session::config::{DebugInfo, OutputType};
@@ -146,11 +146,34 @@
}
}
- let mut cx = crate::CodegenCx::new(tcx, module, tcx.sess.opts.debuginfo != DebugInfo::None);
+ let mut cx = crate::CodegenCx::new(
+ tcx,
+ module,
+ tcx.sess.opts.debuginfo != DebugInfo::None,
+ true,
+ );
super::predefine_mono_items(&mut cx, &mono_items);
for (mono_item, (linkage, visibility)) in mono_items {
let linkage = crate::linkage::get_clif_linkage(mono_item, linkage, visibility);
- super::codegen_mono_item(&mut cx, mono_item, linkage);
+ match mono_item {
+ MonoItem::Fn(inst) => {
+ cx.tcx.sess.time("codegen fn", || {
+ crate::base::codegen_fn(&mut cx, inst, linkage)
+ });
+ }
+ MonoItem::Static(def_id) => {
+ crate::constant::codegen_static(&mut cx.constants_cx, def_id)
+ }
+ MonoItem::GlobalAsm(hir_id) => {
+ let item = cx.tcx.hir().expect_item(hir_id);
+ if let rustc_hir::ItemKind::GlobalAsm(rustc_hir::GlobalAsm { asm }) = item.kind {
+ cx.global_asm.push_str(&*asm.as_str());
+ cx.global_asm.push_str("\n\n");
+ } else {
+ bug!("Expected GlobalAsm found {:?}", item);
+ }
+ }
+ }
}
let (mut module, global_asm, debug, mut unwind_context) =
tcx.sess.time("finalize CodegenCx", || cx.finalize());
@@ -236,7 +259,7 @@
tcx.sess.abort_if_errors();
let mut allocator_module = new_module(tcx, "allocator_shim".to_string());
- let mut allocator_unwind_context = UnwindContext::new(tcx, allocator_module.isa());
+ let mut allocator_unwind_context = UnwindContext::new(tcx, allocator_module.isa(), true);
let created_alloc_shim =
crate::allocator::codegen(tcx, &mut allocator_module, &mut allocator_unwind_context);
@@ -258,9 +281,6 @@
None
};
- rustc_incremental::assert_dep_graph(tcx);
- rustc_incremental::save_dep_graph(tcx);
-
let metadata_module = if need_metadata_module {
let _timer = tcx.prof.generic_activity("codegen crate metadata");
let (metadata_cgu_name, tmp_file) = tcx.sess.time("write compressed metadata", || {
@@ -299,10 +319,6 @@
None
};
- if tcx.sess.opts.output_types.should_codegen() {
- rustc_incremental::assert_module_sources::assert_module_sources(tcx);
- }
-
Box::new((
CodegenResults {
crate_name: tcx.crate_name(LOCAL_CRATE),
diff --git a/compiler/rustc_codegen_cranelift/src/driver/jit.rs b/compiler/rustc_codegen_cranelift/src/driver/jit.rs
index 5a84484..2d14ff2 100644
--- a/compiler/rustc_codegen_cranelift/src/driver/jit.rs
+++ b/compiler/rustc_codegen_cranelift/src/driver/jit.rs
@@ -1,16 +1,23 @@
//! The JIT driver uses [`cranelift_simplejit`] to JIT execute programs without writing any object
//! files.
+use std::cell::RefCell;
use std::ffi::CString;
use std::os::raw::{c_char, c_int};
use rustc_codegen_ssa::CrateInfo;
+use rustc_middle::mir::mono::MonoItem;
-use cranelift_simplejit::{SimpleJITBuilder, SimpleJITModule};
+use cranelift_jit::{JITBuilder, JITModule};
use crate::prelude::*;
+use crate::{CodegenCx, CodegenMode};
-pub(super) fn run_jit(tcx: TyCtxt<'_>) -> ! {
+thread_local! {
+ pub static CURRENT_MODULE: RefCell<Option<JITModule>> = RefCell::new(None);
+}
+
+pub(super) fn run_jit(tcx: TyCtxt<'_>, codegen_mode: CodegenMode) -> ! {
if !tcx.sess.opts.output_types.should_codegen() {
tcx.sess.fatal("JIT mode doesn't work with `cargo check`.");
}
@@ -35,12 +42,13 @@
let imported_symbols = load_imported_symbols_for_jit(tcx);
- let mut jit_builder = SimpleJITBuilder::with_isa(
- crate::build_isa(tcx.sess, false),
+ let mut jit_builder = JITBuilder::with_isa(
+ crate::build_isa(tcx.sess),
cranelift_module::default_libcall_names(),
);
+ jit_builder.hotswap(matches!(codegen_mode, CodegenMode::JitLazy));
jit_builder.symbols(imported_symbols);
- let mut jit_module = SimpleJITModule::new(jit_builder);
+ let mut jit_module = JITModule::new(jit_builder);
assert_eq!(pointer_ty(tcx), jit_module.target_config().pointer_type());
let sig = Signature {
@@ -66,20 +74,42 @@
.into_iter()
.collect::<Vec<(_, (_, _))>>();
- let mut cx = crate::CodegenCx::new(tcx, jit_module, false);
+ let mut cx = crate::CodegenCx::new(tcx, jit_module, false, false);
+
+ super::time(tcx, "codegen mono items", || {
+ super::predefine_mono_items(&mut cx, &mono_items);
+ for (mono_item, (linkage, visibility)) in mono_items {
+ let linkage = crate::linkage::get_clif_linkage(mono_item, linkage, visibility);
+ match mono_item {
+ MonoItem::Fn(inst) => match codegen_mode {
+ CodegenMode::Aot => unreachable!(),
+ CodegenMode::Jit => {
+ cx.tcx.sess.time("codegen fn", || {
+ crate::base::codegen_fn(&mut cx, inst, linkage)
+ });
+ }
+ CodegenMode::JitLazy => codegen_shim(&mut cx, inst),
+ },
+ MonoItem::Static(def_id) => {
+ crate::constant::codegen_static(&mut cx.constants_cx, def_id);
+ }
+ MonoItem::GlobalAsm(hir_id) => {
+ let item = cx.tcx.hir().expect_item(hir_id);
+ tcx.sess
+ .span_fatal(item.span, "Global asm is not supported in JIT mode");
+ }
+ }
+ }
+ });
let (mut jit_module, global_asm, _debug, mut unwind_context) =
- super::time(tcx, "codegen mono items", || {
- super::predefine_mono_items(&mut cx, &mono_items);
- for (mono_item, (linkage, visibility)) in mono_items {
- let linkage = crate::linkage::get_clif_linkage(mono_item, linkage, visibility);
- super::codegen_mono_item(&mut cx, mono_item, linkage);
- }
- tcx.sess.time("finalize CodegenCx", || cx.finalize())
- });
+ tcx.sess.time("finalize CodegenCx", || cx.finalize());
+ jit_module.finalize_definitions();
+
if !global_asm.is_empty() {
- tcx.sess.fatal("Global asm is not supported in JIT mode");
+ tcx.sess.fatal("Inline asm is not supported in JIT mode");
}
+
crate::main_shim::maybe_create_entry_wrapper(tcx, &mut jit_module, &mut unwind_context, true);
crate::allocator::codegen(tcx, &mut jit_module, &mut unwind_context);
@@ -91,7 +121,7 @@
let finalized_main: *const u8 = jit_module.get_finalized_function(main_func_id);
- println!("Rustc codegen cranelift will JIT run the executable, because --jit was passed");
+ println!("Rustc codegen cranelift will JIT run the executable, because -Cllvm-args=mode=jit was passed");
let f: extern "C" fn(c_int, *const *const c_char) -> c_int =
unsafe { ::std::mem::transmute(finalized_main) };
@@ -107,11 +137,46 @@
// useful as some dynamic linkers use it as a marker to jump over.
argv.push(std::ptr::null());
+ CURRENT_MODULE
+ .with(|current_module| assert!(current_module.borrow_mut().replace(jit_module).is_none()));
+
let ret = f(args.len() as c_int, argv.as_ptr());
std::process::exit(ret);
}
+#[no_mangle]
+extern "C" fn __clif_jit_fn(instance_ptr: *const Instance<'static>) -> *const u8 {
+ rustc_middle::ty::tls::with(|tcx| {
+ // lift is used to ensure the correct lifetime for instance.
+ let instance = tcx.lift(unsafe { *instance_ptr }).unwrap();
+
+ CURRENT_MODULE.with(|jit_module| {
+ let mut jit_module = jit_module.borrow_mut();
+ let jit_module = jit_module.as_mut().unwrap();
+ let mut cx = crate::CodegenCx::new(tcx, jit_module, false, false);
+
+ let name = tcx.symbol_name(instance).name.to_string();
+ let sig = crate::abi::get_function_sig(tcx, cx.module.isa().triple(), instance);
+ let func_id = cx
+ .module
+ .declare_function(&name, Linkage::Export, &sig)
+ .unwrap();
+ cx.module.prepare_for_function_redefine(func_id).unwrap();
+
+ tcx.sess.time("codegen fn", || {
+ crate::base::codegen_fn(&mut cx, instance, Linkage::Export)
+ });
+
+ let (jit_module, global_asm, _debug_context, unwind_context) = cx.finalize();
+ assert!(global_asm.is_empty());
+ jit_module.finalize_definitions();
+ std::mem::forget(unsafe { unwind_context.register_jit(&jit_module) });
+ jit_module.get_finalized_function(func_id)
+ })
+ })
+}
+
fn load_imported_symbols_for_jit(tcx: TyCtxt<'_>) -> Vec<(String, *const u8)> {
use rustc_middle::middle::dependency_format::Linkage;
@@ -171,3 +236,68 @@
imported_symbols
}
+
+pub(super) fn codegen_shim<'tcx>(cx: &mut CodegenCx<'tcx, impl Module>, inst: Instance<'tcx>) {
+ let tcx = cx.tcx;
+
+ let pointer_type = cx.module.target_config().pointer_type();
+
+ let name = tcx.symbol_name(inst).name.to_string();
+ let sig = crate::abi::get_function_sig(tcx, cx.module.isa().triple(), inst);
+ let func_id = cx
+ .module
+ .declare_function(&name, Linkage::Export, &sig)
+ .unwrap();
+
+ let instance_ptr = Box::into_raw(Box::new(inst));
+
+ let jit_fn = cx
+ .module
+ .declare_function(
+ "__clif_jit_fn",
+ Linkage::Import,
+ &Signature {
+ call_conv: cx.module.target_config().default_call_conv,
+ params: vec![AbiParam::new(pointer_type)],
+ returns: vec![AbiParam::new(pointer_type)],
+ },
+ )
+ .unwrap();
+
+ let mut trampoline = Function::with_name_signature(ExternalName::default(), sig.clone());
+ let mut builder_ctx = FunctionBuilderContext::new();
+ let mut trampoline_builder = FunctionBuilder::new(&mut trampoline, &mut builder_ctx);
+
+ let jit_fn = cx
+ .module
+ .declare_func_in_func(jit_fn, trampoline_builder.func);
+ let sig_ref = trampoline_builder.func.import_signature(sig);
+
+ let entry_block = trampoline_builder.create_block();
+ trampoline_builder.append_block_params_for_function_params(entry_block);
+ let fn_args = trampoline_builder
+ .func
+ .dfg
+ .block_params(entry_block)
+ .to_vec();
+
+ trampoline_builder.switch_to_block(entry_block);
+ let instance_ptr = trampoline_builder
+ .ins()
+ .iconst(pointer_type, instance_ptr as u64 as i64);
+ let jitted_fn = trampoline_builder.ins().call(jit_fn, &[instance_ptr]);
+ let jitted_fn = trampoline_builder.func.dfg.inst_results(jitted_fn)[0];
+ let call_inst = trampoline_builder
+ .ins()
+ .call_indirect(sig_ref, jitted_fn, &fn_args);
+ let ret_vals = trampoline_builder.func.dfg.inst_results(call_inst).to_vec();
+ trampoline_builder.ins().return_(&ret_vals);
+
+ cx.module
+ .define_function(
+ func_id,
+ &mut Context::for_function(trampoline),
+ &mut cranelift_codegen::binemit::NullTrapSink {},
+ )
+ .unwrap();
+}
diff --git a/compiler/rustc_codegen_cranelift/src/driver/mod.rs b/compiler/rustc_codegen_cranelift/src/driver/mod.rs
index 7b8cc2d..2497f9d 100644
--- a/compiler/rustc_codegen_cranelift/src/driver/mod.rs
+++ b/compiler/rustc_codegen_cranelift/src/driver/mod.rs
@@ -7,6 +7,7 @@
use rustc_middle::mir::mono::{Linkage as RLinkage, MonoItem, Visibility};
use crate::prelude::*;
+use crate::CodegenMode;
mod aot;
#[cfg(feature = "jit")]
@@ -20,24 +21,25 @@
) -> Box<dyn Any> {
tcx.sess.abort_if_errors();
- if config.use_jit {
- let is_executable = tcx
- .sess
- .crate_types()
- .contains(&rustc_session::config::CrateType::Executable);
- if !is_executable {
- tcx.sess.fatal("can't jit non-executable crate");
+ match config.codegen_mode {
+ CodegenMode::Aot => aot::run_aot(tcx, metadata, need_metadata_module),
+ CodegenMode::Jit | CodegenMode::JitLazy => {
+ let is_executable = tcx
+ .sess
+ .crate_types()
+ .contains(&rustc_session::config::CrateType::Executable);
+ if !is_executable {
+ tcx.sess.fatal("can't jit non-executable crate");
+ }
+
+ #[cfg(feature = "jit")]
+ let _: ! = jit::run_jit(tcx, config.codegen_mode);
+
+ #[cfg(not(feature = "jit"))]
+ tcx.sess
+ .fatal("jit support was disabled when compiling rustc_codegen_cranelift");
}
-
- #[cfg(feature = "jit")]
- let _: ! = jit::run_jit(tcx);
-
- #[cfg(not(feature = "jit"))]
- tcx.sess
- .fatal("jit support was disabled when compiling rustc_codegen_cranelift");
}
-
- aot::run_aot(tcx, metadata, need_metadata_module)
}
fn predefine_mono_items<'tcx>(
@@ -48,12 +50,9 @@
for &(mono_item, (linkage, visibility)) in mono_items {
match mono_item {
MonoItem::Fn(instance) => {
- let (name, sig) = get_function_name_and_sig(
- cx.tcx,
- cx.module.isa().triple(),
- instance,
- false,
- );
+ let name = cx.tcx.symbol_name(instance).name.to_string();
+ let _inst_guard = crate::PrintOnPanic(|| format!("{:?} {}", instance, name));
+ let sig = get_function_sig(cx.tcx, cx.module.isa().triple(), instance);
let linkage = crate::linkage::get_clif_linkage(mono_item, linkage, visibility);
cx.module.declare_function(&name, linkage, &sig).unwrap();
}
@@ -63,30 +62,6 @@
});
}
-fn codegen_mono_item<'tcx, M: Module>(
- cx: &mut crate::CodegenCx<'tcx, M>,
- mono_item: MonoItem<'tcx>,
- linkage: Linkage,
-) {
- match mono_item {
- MonoItem::Fn(inst) => {
- cx.tcx
- .sess
- .time("codegen fn", || crate::base::codegen_fn(cx, inst, linkage));
- }
- MonoItem::Static(def_id) => crate::constant::codegen_static(&mut cx.constants_cx, def_id),
- MonoItem::GlobalAsm(hir_id) => {
- let item = cx.tcx.hir().expect_item(hir_id);
- if let rustc_hir::ItemKind::GlobalAsm(rustc_hir::GlobalAsm { asm }) = item.kind {
- cx.global_asm.push_str(&*asm.as_str());
- cx.global_asm.push_str("\n\n");
- } else {
- bug!("Expected GlobalAsm found {:?}", item);
- }
- }
- }
-}
-
fn time<R>(tcx: TyCtxt<'_>, name: &'static str, f: impl FnOnce() -> R) -> R {
if std::env::var("CG_CLIF_DISPLAY_CG_TIME")
.as_ref()
diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm.rs
index 171445f..d58e4d4 100644
--- a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm.rs
+++ b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm.rs
@@ -23,8 +23,8 @@
// Used by `_mm_movemask_epi8` and `_mm256_movemask_epi8`
llvm.x86.sse2.pmovmskb.128 | llvm.x86.avx2.pmovmskb | llvm.x86.sse2.movmsk.pd, (c a) {
- let (lane_layout, lane_count) = lane_type_and_count(fx.tcx, a.layout());
- let lane_ty = fx.clif_type(lane_layout.ty).unwrap();
+ let (lane_count, lane_ty) = a.layout().ty.simd_size_and_type(fx.tcx);
+ let lane_ty = fx.clif_type(lane_ty).unwrap();
assert!(lane_count <= 32);
let mut res = fx.bcx.ins().iconst(types::I32, 0);
diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
index df8aa1b..8946ac4 100644
--- a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
+++ b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
@@ -171,27 +171,6 @@
}
}
-fn lane_type_and_count<'tcx>(
- tcx: TyCtxt<'tcx>,
- layout: TyAndLayout<'tcx>,
-) -> (TyAndLayout<'tcx>, u16) {
- assert!(layout.ty.is_simd());
- let lane_count = match layout.fields {
- rustc_target::abi::FieldsShape::Array { stride: _, count } => u16::try_from(count).unwrap(),
- _ => unreachable!("lane_type_and_count({:?})", layout),
- };
- let lane_layout = layout
- .field(
- &ty::layout::LayoutCx {
- tcx,
- param_env: ParamEnv::reveal_all(),
- },
- 0,
- )
- .unwrap();
- (lane_layout, lane_count)
-}
-
pub(crate) fn clif_vector_type<'tcx>(tcx: TyCtxt<'tcx>, layout: TyAndLayout<'tcx>) -> Option<Type> {
let (element, count) = match &layout.abi {
Abi::Vector { element, count } => (element.clone(), *count),
@@ -218,8 +197,10 @@
) {
let layout = val.layout();
- let (lane_layout, lane_count) = lane_type_and_count(fx.tcx, layout);
- let (ret_lane_layout, ret_lane_count) = lane_type_and_count(fx.tcx, ret.layout());
+ let (lane_count, lane_ty) = layout.ty.simd_size_and_type(fx.tcx);
+ let lane_layout = fx.layout_of(lane_ty);
+ let (ret_lane_count, ret_lane_ty) = ret.layout().ty.simd_size_and_type(fx.tcx);
+ let ret_lane_layout = fx.layout_of(ret_lane_ty);
assert_eq!(lane_count, ret_lane_count);
for lane_idx in 0..lane_count {
@@ -248,8 +229,10 @@
assert_eq!(x.layout(), y.layout());
let layout = x.layout();
- let (lane_layout, lane_count) = lane_type_and_count(fx.tcx, layout);
- let (ret_lane_layout, ret_lane_count) = lane_type_and_count(fx.tcx, ret.layout());
+ let (lane_count, lane_ty) = layout.ty.simd_size_and_type(fx.tcx);
+ let lane_layout = fx.layout_of(lane_ty);
+ let (ret_lane_count, ret_lane_ty) = ret.layout().ty.simd_size_and_type(fx.tcx);
+ let ret_lane_layout = fx.layout_of(ret_lane_ty);
assert_eq!(lane_count, ret_lane_count);
for lane in 0..lane_count {
@@ -269,13 +252,14 @@
ret: CPlace<'tcx>,
f: impl Fn(&mut FunctionCx<'_, 'tcx, M>, TyAndLayout<'tcx>, Value, Value) -> Value,
) {
- let (lane_layout, lane_count) = lane_type_and_count(fx.tcx, val.layout());
+ let (lane_count, lane_ty) = val.layout().ty.simd_size_and_type(fx.tcx);
+ let lane_layout = fx.layout_of(lane_ty);
assert_eq!(lane_layout, ret.layout());
let mut res_val = val.value_field(fx, mir::Field::new(0)).load_scalar(fx);
for lane_idx in 1..lane_count {
let lane = val
- .value_field(fx, mir::Field::new(lane_idx.into()))
+ .value_field(fx, mir::Field::new(lane_idx.try_into().unwrap()))
.load_scalar(fx);
res_val = f(fx, lane_layout, res_val, lane);
}
@@ -289,14 +273,14 @@
ret: CPlace<'tcx>,
f: impl Fn(&mut FunctionCx<'_, 'tcx, M>, Value, Value) -> Value,
) {
- let (_lane_layout, lane_count) = lane_type_and_count(fx.tcx, val.layout());
+ let (lane_count, _lane_ty) = val.layout().ty.simd_size_and_type(fx.tcx);
assert!(ret.layout().ty.is_bool());
let res_val = val.value_field(fx, mir::Field::new(0)).load_scalar(fx);
let mut res_val = fx.bcx.ins().band_imm(res_val, 1); // mask to boolean
for lane_idx in 1..lane_count {
let lane = val
- .value_field(fx, mir::Field::new(lane_idx.into()))
+ .value_field(fx, mir::Field::new(lane_idx.try_into().unwrap()))
.load_scalar(fx);
let lane = fx.bcx.ins().band_imm(lane, 1); // mask to boolean
res_val = f(fx, res_val, lane);
@@ -460,9 +444,6 @@
"abort" => {
trap_abort(fx, "Called intrinsic::abort.");
}
- "unreachable" => {
- trap_unreachable(fx, "[corruption] Called intrinsic::unreachable.");
- }
"transmute" => {
crate::base::codegen_panic(fx, "Transmuting to uninhabited type.", span);
}
@@ -575,12 +556,6 @@
fx.bcx.call_memmove(fx.cx.module.target_config(), dst, src, byte_amount);
}
};
- discriminant_value, (c ptr) {
- let pointee_layout = fx.layout_of(ptr.layout().ty.builtin_deref(true).unwrap().ty);
- let val = CValue::by_ref(Pointer::new(ptr.load_scalar(fx)), pointee_layout);
- let discr = crate::discriminant::codegen_get_discriminant(fx, val, ret.layout());
- ret.write_cvalue(fx, discr);
- };
size_of_val, <T> (c ptr) {
let layout = fx.layout_of(T);
let size = if layout.is_unsized() {
@@ -641,22 +616,6 @@
);
ret.write_cvalue(fx, res);
};
- _ if intrinsic.starts_with("wrapping_"), (c x, c y) {
- assert_eq!(x.layout().ty, y.layout().ty);
- let bin_op = match intrinsic {
- "wrapping_add" => BinOp::Add,
- "wrapping_sub" => BinOp::Sub,
- "wrapping_mul" => BinOp::Mul,
- _ => unreachable!("intrinsic {}", intrinsic),
- };
- let res = crate::num::codegen_int_binop(
- fx,
- bin_op,
- x,
- y,
- );
- ret.write_cvalue(fx, res);
- };
_ if intrinsic.starts_with("saturating_"), <T> (c lhs, c rhs) {
assert_eq!(lhs.layout().ty, rhs.layout().ty);
let bin_op = match intrinsic {
@@ -865,7 +824,7 @@
}
ty => unreachable!("bswap {}", ty),
}
- };
+ }
let res = CValue::by_val(swap(&mut fx.bcx, arg), fx.layout_of(T));
ret.write_cvalue(fx, res);
};
@@ -916,7 +875,7 @@
dest.write_cvalue(fx, val);
};
- size_of | pref_align_of | min_align_of | needs_drop | type_id | type_name | variant_count, () {
+ pref_align_of | min_align_of | needs_drop | type_id | type_name | variant_count, () {
let const_val =
fx.tcx.const_eval_instance(ParamEnv::reveal_all(), instance, None).unwrap();
let val = crate::constant::codegen_const_value(
diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs
index 2b32e86..e0eb5c5 100644
--- a/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs
+++ b/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs
@@ -73,11 +73,11 @@
assert_eq!(x.layout(), y.layout());
let layout = x.layout();
- let (lane_type, lane_count) = lane_type_and_count(fx.tcx, layout);
- let (ret_lane_type, ret_lane_count) = lane_type_and_count(fx.tcx, ret.layout());
+ let (lane_count, lane_ty) = layout.ty.simd_size_and_type(fx.tcx);
+ let (ret_lane_count, ret_lane_ty) = ret.layout().ty.simd_size_and_type(fx.tcx);
- assert_eq!(lane_type, ret_lane_type);
- assert_eq!(n, ret_lane_count);
+ assert_eq!(lane_ty, ret_lane_ty);
+ assert_eq!(u64::from(n), ret_lane_count);
let total_len = lane_count * 2;
@@ -105,14 +105,14 @@
};
for &idx in &indexes {
- assert!(idx < total_len, "idx {} out of range 0..{}", idx, total_len);
+ assert!(u64::from(idx) < total_len, "idx {} out of range 0..{}", idx, total_len);
}
for (out_idx, in_idx) in indexes.into_iter().enumerate() {
- let in_lane = if in_idx < lane_count {
+ let in_lane = if u64::from(in_idx) < lane_count {
x.value_field(fx, mir::Field::new(in_idx.into()))
} else {
- y.value_field(fx, mir::Field::new((in_idx - lane_count).into()))
+ y.value_field(fx, mir::Field::new(usize::from(in_idx) - usize::try_from(lane_count).unwrap()))
};
let out_lane = ret.place_field(fx, mir::Field::new(out_idx));
out_lane.write_cvalue(fx, in_lane);
@@ -131,7 +131,7 @@
};
let idx = idx_const.val.try_to_bits(Size::from_bytes(4 /* u32*/)).unwrap_or_else(|| panic!("kind not scalar: {:?}", idx_const));
- let (_lane_type, lane_count) = lane_type_and_count(fx.tcx, base.layout());
+ let (lane_count, _lane_ty) = base.layout().ty.simd_size_and_type(fx.tcx);
if idx >= lane_count.into() {
fx.tcx.sess.span_fatal(fx.mir.span, &format!("[simd_insert] idx {} >= lane_count {}", idx, lane_count));
}
@@ -160,7 +160,7 @@
};
let idx = idx_const.val.try_to_bits(Size::from_bytes(4 /* u32*/)).unwrap_or_else(|| panic!("kind not scalar: {:?}", idx_const));
- let (_lane_type, lane_count) = lane_type_and_count(fx.tcx, v.layout());
+ let (lane_count, _lane_ty) = v.layout().ty.simd_size_and_type(fx.tcx);
if idx >= lane_count.into() {
fx.tcx.sess.span_fatal(fx.mir.span, &format!("[simd_extract] idx {} >= lane_count {}", idx, lane_count));
}
@@ -212,12 +212,13 @@
assert_eq!(a.layout(), c.layout());
let layout = a.layout();
- let (_lane_layout, lane_count) = lane_type_and_count(fx.tcx, layout);
- let (ret_lane_layout, ret_lane_count) = lane_type_and_count(fx.tcx, ret.layout());
+ let (lane_count, _lane_ty) = layout.ty.simd_size_and_type(fx.tcx);
+ let (ret_lane_count, ret_lane_ty) = ret.layout().ty.simd_size_and_type(fx.tcx);
assert_eq!(lane_count, ret_lane_count);
+ let ret_lane_layout = fx.layout_of(ret_lane_ty);
for lane in 0..lane_count {
- let lane = mir::Field::new(lane.into());
+ let lane = mir::Field::new(lane.try_into().unwrap());
let a_lane = a.value_field(fx, lane).load_scalar(fx);
let b_lane = b.value_field(fx, lane).load_scalar(fx);
let c_lane = c.value_field(fx, lane).load_scalar(fx);
diff --git a/compiler/rustc_codegen_cranelift/src/lib.rs b/compiler/rustc_codegen_cranelift/src/lib.rs
index ba9ee0d..1707504 100644
--- a/compiler/rustc_codegen_cranelift/src/lib.rs
+++ b/compiler/rustc_codegen_cranelift/src/lib.rs
@@ -5,7 +5,8 @@
associated_type_bounds,
never_type,
try_blocks,
- hash_drain_filter
+ hash_drain_filter,
+ str_split_once
)]
#![warn(rust_2018_idioms)]
#![warn(unused_lifetimes)]
@@ -26,7 +27,6 @@
extern crate rustc_index;
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.
@@ -34,6 +34,7 @@
extern crate rustc_driver;
use std::any::Any;
+use std::str::FromStr;
use rustc_codegen_ssa::traits::CodegenBackend;
use rustc_codegen_ssa::CodegenResults;
@@ -81,7 +82,6 @@
mod prelude {
pub(crate) use std::convert::{TryFrom, TryInto};
- pub(crate) use rustc_ast::ast::{FloatTy, IntTy, UintTy};
pub(crate) use rustc_span::Span;
pub(crate) use rustc_hir::def_id::{DefId, LOCAL_CRATE};
@@ -89,7 +89,8 @@
pub(crate) use rustc_middle::mir::{self, *};
pub(crate) use rustc_middle::ty::layout::{self, TyAndLayout};
pub(crate) use rustc_middle::ty::{
- self, FnSig, Instance, InstanceDef, ParamEnv, Ty, TyCtxt, TypeAndMut, TypeFoldable,
+ self, FloatTy, Instance, InstanceDef, IntTy, ParamEnv, Ty, TyCtxt, TypeAndMut,
+ TypeFoldable, UintTy,
};
pub(crate) use rustc_target::abi::{Abi, LayoutOf, Scalar, Size, VariantIdx};
@@ -141,8 +142,8 @@
}
impl<'tcx, M: Module> CodegenCx<'tcx, M> {
- fn new(tcx: TyCtxt<'tcx>, module: M, debug_info: bool) -> Self {
- let unwind_context = UnwindContext::new(tcx, module.isa());
+ fn new(tcx: TyCtxt<'tcx>, module: M, debug_info: bool, pic_eh_frame: bool) -> Self {
+ let unwind_context = UnwindContext::new(tcx, module.isa(), pic_eh_frame);
let debug_context = if debug_info {
Some(DebugContext::new(tcx, module.isa()))
} else {
@@ -172,12 +173,55 @@
}
#[derive(Copy, Clone, Debug)]
+pub enum CodegenMode {
+ Aot,
+ Jit,
+ JitLazy,
+}
+
+impl Default for CodegenMode {
+ fn default() -> Self {
+ CodegenMode::Aot
+ }
+}
+
+impl FromStr for CodegenMode {
+ type Err = String;
+
+ fn from_str(s: &str) -> Result<Self, Self::Err> {
+ match s {
+ "aot" => Ok(CodegenMode::Aot),
+ "jit" => Ok(CodegenMode::Jit),
+ "jit-lazy" => Ok(CodegenMode::JitLazy),
+ _ => Err(format!("Unknown codegen mode `{}`", s)),
+ }
+ }
+}
+
+#[derive(Copy, Clone, Debug, Default)]
pub struct BackendConfig {
- pub use_jit: bool,
+ pub codegen_mode: CodegenMode,
+}
+
+impl BackendConfig {
+ fn from_opts(opts: &[String]) -> Result<Self, String> {
+ let mut config = BackendConfig::default();
+ for opt in opts {
+ if let Some((name, value)) = opt.split_once('=') {
+ match name {
+ "mode" => config.codegen_mode = value.parse()?,
+ _ => return Err(format!("Unknown option `{}`", name)),
+ }
+ } else {
+ return Err(format!("Invalid option `{}`", opt));
+ }
+ }
+ Ok(config)
+ }
}
pub struct CraneliftCodegenBackend {
- pub config: BackendConfig,
+ pub config: Option<BackendConfig>,
}
impl CodegenBackend for CraneliftCodegenBackend {
@@ -204,9 +248,13 @@
metadata: EncodedMetadata,
need_metadata_module: bool,
) -> Box<dyn Any> {
- let res = driver::codegen_crate(tcx, metadata, need_metadata_module, self.config);
-
- rustc_symbol_mangling::test::report_symbol_names(tcx);
+ let config = if let Some(config) = self.config {
+ config
+ } else {
+ BackendConfig::from_opts(&tcx.sess.opts.cg.llvm_args)
+ .unwrap_or_else(|err| tcx.sess.fatal(&err))
+ };
+ let res = driver::codegen_crate(tcx, metadata, need_metadata_module, config);
res
}
@@ -229,18 +277,14 @@
) -> Result<(), ErrorReported> {
use rustc_codegen_ssa::back::link::link_binary;
- let _timer = sess.prof.generic_activity("link_crate");
-
- sess.time("linking", || {
- let target_cpu = crate::target_triple(sess).to_string();
- link_binary::<crate::archive::ArArchiveBuilder<'_>>(
- sess,
- &codegen_results,
- outputs,
- &codegen_results.crate_name.as_str(),
- &target_cpu,
- );
- });
+ let target_cpu = crate::target_triple(sess).to_string();
+ link_binary::<crate::archive::ArArchiveBuilder<'_>>(
+ sess,
+ &codegen_results,
+ outputs,
+ &codegen_results.crate_name.as_str(),
+ &target_cpu,
+ );
Ok(())
}
@@ -250,17 +294,13 @@
sess.target.llvm_target.parse().unwrap()
}
-fn build_isa(sess: &Session, enable_pic: bool) -> Box<dyn isa::TargetIsa + 'static> {
+fn build_isa(sess: &Session) -> Box<dyn isa::TargetIsa + 'static> {
use target_lexicon::BinaryFormat;
let target_triple = crate::target_triple(sess);
let mut flags_builder = settings::builder();
- if enable_pic {
- flags_builder.enable("is_pic").unwrap();
- } else {
- flags_builder.set("is_pic", "false").unwrap();
- }
+ flags_builder.enable("is_pic").unwrap();
flags_builder.set("enable_probestack", "false").unwrap(); // __cranelift_probestack is not provided
flags_builder
.set(
@@ -283,8 +323,6 @@
flags_builder.set("enable_simd", "true").unwrap();
- // FIXME(CraneStation/cranelift#732) fix LICM in presence of jump tables
- /*
use rustc_session::config::OptLevel;
match sess.opts.optimize {
OptLevel::No => {
@@ -297,11 +335,16 @@
OptLevel::Size | OptLevel::SizeMin => {
sess.warn("Optimizing for size is not supported. Just ignoring the request");
}
- }*/
+ }
let flags = settings::Flags::new(flags_builder);
- let mut isa_builder = cranelift_codegen::isa::lookup(target_triple).unwrap();
+ let variant = if cfg!(feature = "oldbe") {
+ cranelift_codegen::isa::BackendVariant::Legacy
+ } else {
+ cranelift_codegen::isa::BackendVariant::MachInst
+ };
+ let mut isa_builder = cranelift_codegen::isa::lookup_variant(target_triple, variant).unwrap();
// Don't use "haswell", as it implies `has_lzcnt`.macOS CI is still at Ivy Bridge EP, so `lzcnt`
// is interpreted as `bsr`.
isa_builder.enable("nehalem").unwrap();
@@ -311,7 +354,5 @@
/// This is the entrypoint for a hot plugged rustc_codegen_cranelift
#[no_mangle]
pub fn __rustc_codegen_backend() -> Box<dyn CodegenBackend> {
- Box::new(CraneliftCodegenBackend {
- config: BackendConfig { use_jit: false },
- })
+ Box::new(CraneliftCodegenBackend { config: None })
}
diff --git a/compiler/rustc_codegen_cranelift/src/main_shim.rs b/compiler/rustc_codegen_cranelift/src/main_shim.rs
index 6c472e6..b193cea 100644
--- a/compiler/rustc_codegen_cranelift/src/main_shim.rs
+++ b/compiler/rustc_codegen_cranelift/src/main_shim.rs
@@ -69,8 +69,8 @@
let instance = Instance::mono(tcx, rust_main_def_id).polymorphize(tcx);
- let (main_name, main_sig) =
- get_function_name_and_sig(tcx, m.isa().triple(), instance, false);
+ let main_name = tcx.symbol_name(instance).name.to_string();
+ let main_sig = get_function_sig(tcx, m.isa().triple(), instance);
let main_func_id = m
.declare_function(&main_name, Linkage::Import, &main_sig)
.unwrap();
diff --git a/compiler/rustc_codegen_cranelift/src/num.rs b/compiler/rustc_codegen_cranelift/src/num.rs
index 41f4a9b..d1d2b3b 100644
--- a/compiler/rustc_codegen_cranelift/src/num.rs
+++ b/compiler/rustc_codegen_cranelift/src/num.rs
@@ -280,7 +280,6 @@
(val, fx.bcx.ins().bor(has_underflow, has_overflow))
}
types::I64 => {
- //let val = fx.easy_call("__mulodi4", &[lhs, rhs, overflow_ptr], types::I64);
let val = fx.bcx.ins().imul(lhs, rhs);
let has_overflow = if !signed {
let val_hi = fx.bcx.ins().umulhi(lhs, rhs);
diff --git a/compiler/rustc_codegen_cranelift/src/optimize/peephole.rs b/compiler/rustc_codegen_cranelift/src/optimize/peephole.rs
index f8e0f3a..a575ed8 100644
--- a/compiler/rustc_codegen_cranelift/src/optimize/peephole.rs
+++ b/compiler/rustc_codegen_cranelift/src/optimize/peephole.rs
@@ -73,7 +73,7 @@
})()
.unwrap_or_else(|| {
match bcx.func.dfg.value_type(arg) {
- types::I8 | types::I32 => {
+ types::I8 | types::I16 => {
// WORKAROUND for brz.i8 and brnz.i8 not yet being implemented
bcx.ins().uextend(types::I32, arg)
}
@@ -81,3 +81,40 @@
}
})
}
+
+/// Returns whether the branch is statically known to be taken or `None` if it isn't statically known.
+pub(crate) fn maybe_known_branch_taken(
+ bcx: &FunctionBuilder<'_>,
+ arg: Value,
+ test_zero: bool,
+) -> Option<bool> {
+ let arg_inst = if let ValueDef::Result(arg_inst, 0) = bcx.func.dfg.value_def(arg) {
+ arg_inst
+ } else {
+ return None;
+ };
+
+ match bcx.func.dfg[arg_inst] {
+ InstructionData::UnaryBool {
+ opcode: Opcode::Bconst,
+ imm,
+ } => {
+ if test_zero {
+ Some(!imm)
+ } else {
+ Some(imm)
+ }
+ }
+ InstructionData::UnaryImm {
+ opcode: Opcode::Iconst,
+ imm,
+ } => {
+ if test_zero {
+ Some(imm.bits() == 0)
+ } else {
+ Some(imm.bits() != 0)
+ }
+ }
+ _ => None,
+ }
+}
diff --git a/compiler/rustc_codegen_cranelift/src/pretty_clif.rs b/compiler/rustc_codegen_cranelift/src/pretty_clif.rs
index a9f060e..f4a15ab 100644
--- a/compiler/rustc_codegen_cranelift/src/pretty_clif.rs
+++ b/compiler/rustc_codegen_cranelift/src/pretty_clif.rs
@@ -53,6 +53,7 @@
//! ```
use std::fmt;
+use std::io::Write;
use cranelift_codegen::{
entity::SecondaryMap,
@@ -60,7 +61,9 @@
write::{FuncWriter, PlainWriter},
};
+use rustc_middle::ty::layout::FnAbiExt;
use rustc_session::config::OutputType;
+use rustc_target::abi::call::FnAbi;
use crate::prelude::*;
@@ -77,11 +80,8 @@
format!("symbol {}", tcx.symbol_name(instance).name),
format!("instance {:?}", instance),
format!(
- "sig {:?}",
- tcx.normalize_erasing_late_bound_regions(
- ParamEnv::reveal_all(),
- crate::abi::fn_sig_for_fn_abi(tcx, instance)
- )
+ "abi {:?}",
+ FnAbi::of_instance(&RevealAllLayoutCx(tcx), instance, &[])
),
String::new(),
]
@@ -200,32 +200,24 @@
}
}
-pub(crate) fn write_clif_file<'tcx>(
- tcx: TyCtxt<'tcx>,
- postfix: &str,
- isa: Option<&dyn cranelift_codegen::isa::TargetIsa>,
- instance: Instance<'tcx>,
- context: &cranelift_codegen::Context,
- mut clif_comments: &CommentWriter,
-) {
- use std::io::Write;
-
- if !cfg!(debug_assertions)
- && !tcx
+pub(crate) fn should_write_ir(tcx: TyCtxt<'_>) -> bool {
+ cfg!(debug_assertions)
+ || tcx
.sess
.opts
.output_types
.contains_key(&OutputType::LlvmAssembly)
- {
+}
+
+pub(crate) fn write_ir_file<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ name: &str,
+ write: impl FnOnce(&mut dyn Write) -> std::io::Result<()>,
+) {
+ if !should_write_ir(tcx) {
return;
}
- let value_ranges = isa.map(|isa| {
- context
- .build_value_labels_ranges(isa)
- .expect("value location ranges")
- });
-
let clif_output_dir = tcx.output_filenames(LOCAL_CRATE).with_extension("clif");
match std::fs::create_dir(&clif_output_dir) {
@@ -234,41 +226,58 @@
res @ Err(_) => res.unwrap(),
}
- let clif_file_name = clif_output_dir.join(format!(
- "{}.{}.clif",
- tcx.symbol_name(instance).name,
- postfix
- ));
-
- let mut clif = String::new();
- cranelift_codegen::write::decorate_function(
- &mut clif_comments,
- &mut clif,
- &context.func,
- &DisplayFunctionAnnotations {
- isa: Some(&*crate::build_isa(
- tcx.sess, true, /* PIC doesn't matter here */
- )),
- value_ranges: value_ranges.as_ref(),
- },
- )
- .unwrap();
+ let clif_file_name = clif_output_dir.join(name);
let res: std::io::Result<()> = try {
let mut file = std::fs::File::create(clif_file_name)?;
- let target_triple = crate::target_triple(tcx.sess);
- writeln!(file, "test compile")?;
- writeln!(file, "set is_pic")?;
- writeln!(file, "set enable_simd")?;
- writeln!(file, "target {} haswell", target_triple)?;
- writeln!(file)?;
- file.write_all(clif.as_bytes())?;
+ write(&mut file)?;
};
if let Err(err) = res {
- tcx.sess.warn(&format!("err writing clif file: {}", err));
+ tcx.sess.warn(&format!("error writing ir file: {}", err));
}
}
+pub(crate) fn write_clif_file<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ postfix: &str,
+ isa: Option<&dyn cranelift_codegen::isa::TargetIsa>,
+ instance: Instance<'tcx>,
+ context: &cranelift_codegen::Context,
+ mut clif_comments: &CommentWriter,
+) {
+ write_ir_file(
+ tcx,
+ &format!("{}.{}.clif", tcx.symbol_name(instance).name, postfix),
+ |file| {
+ let value_ranges = isa.map(|isa| {
+ context
+ .build_value_labels_ranges(isa)
+ .expect("value location ranges")
+ });
+
+ let mut clif = String::new();
+ cranelift_codegen::write::decorate_function(
+ &mut clif_comments,
+ &mut clif,
+ &context.func,
+ &DisplayFunctionAnnotations {
+ isa: Some(&*crate::build_isa(tcx.sess)),
+ value_ranges: value_ranges.as_ref(),
+ },
+ )
+ .unwrap();
+
+ writeln!(file, "test compile")?;
+ writeln!(file, "set is_pic")?;
+ writeln!(file, "set enable_simd")?;
+ writeln!(file, "target {} haswell", crate::target_triple(tcx.sess))?;
+ writeln!(file)?;
+ file.write_all(clif.as_bytes())?;
+ Ok(())
+ },
+ );
+}
+
impl<M: Module> fmt::Debug for FunctionCx<'_, '_, M> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
writeln!(f, "{:?}", self.instance.substs)?;
diff --git a/compiler/rustc_codegen_cranelift/src/value_and_place.rs b/compiler/rustc_codegen_cranelift/src/value_and_place.rs
index 5bcb11f..765604e 100644
--- a/compiler/rustc_codegen_cranelift/src/value_and_place.rs
+++ b/compiler/rustc_codegen_cranelift/src/value_and_place.rs
@@ -334,7 +334,9 @@
let stack_slot = fx.bcx.create_stack_slot(StackSlotData {
kind: StackSlotKind::ExplicitSlot,
- size: u32::try_from(layout.size.bytes()).unwrap(),
+ // FIXME Don't force the size to a multiple of 16 bytes once Cranelift gets a way to
+ // specify stack slot alignment.
+ size: (u32::try_from(layout.size.bytes()).unwrap() + 15) / 16 * 16,
offset: None,
});
CPlace {
@@ -450,64 +452,6 @@
fx: &mut FunctionCx<'_, 'tcx, impl Module>,
from: CValue<'tcx>,
) {
- fn assert_assignable<'tcx>(
- fx: &FunctionCx<'_, 'tcx, impl Module>,
- from_ty: Ty<'tcx>,
- to_ty: Ty<'tcx>,
- ) {
- match (from_ty.kind(), to_ty.kind()) {
- (ty::Ref(_, a, _), ty::Ref(_, b, _))
- | (
- ty::RawPtr(TypeAndMut { ty: a, mutbl: _ }),
- ty::RawPtr(TypeAndMut { ty: b, mutbl: _ }),
- ) => {
- assert_assignable(fx, a, b);
- }
- (ty::FnPtr(_), ty::FnPtr(_)) => {
- let from_sig = fx.tcx.normalize_erasing_late_bound_regions(
- ParamEnv::reveal_all(),
- from_ty.fn_sig(fx.tcx),
- );
- let to_sig = fx.tcx.normalize_erasing_late_bound_regions(
- ParamEnv::reveal_all(),
- to_ty.fn_sig(fx.tcx),
- );
- assert_eq!(
- from_sig, to_sig,
- "Can't write fn ptr with incompatible sig {:?} to place with sig {:?}\n\n{:#?}",
- from_sig, to_sig, fx,
- );
- // fn(&T) -> for<'l> fn(&'l T) is allowed
- }
- (&ty::Dynamic(from_traits, _), &ty::Dynamic(to_traits, _)) => {
- for (from, to) in from_traits.iter().zip(to_traits) {
- let from = fx
- .tcx
- .normalize_erasing_late_bound_regions(ParamEnv::reveal_all(), from);
- let to = fx
- .tcx
- .normalize_erasing_late_bound_regions(ParamEnv::reveal_all(), to);
- assert_eq!(
- from, to,
- "Can't write trait object of incompatible traits {:?} to place with traits {:?}\n\n{:#?}",
- from_traits, to_traits, fx,
- );
- }
- // dyn for<'r> Trait<'r> -> dyn Trait<'_> is allowed
- }
- _ => {
- assert_eq!(
- from_ty,
- to_ty,
- "Can't write value with incompatible type {:?} to place with type {:?}\n\n{:#?}",
- from_ty,
- to_ty,
- fx,
- );
- }
- }
- }
-
assert_assignable(fx, from.layout().ty, self.layout().ty);
self.write_cvalue_maybe_transmute(fx, from, "write_cvalue");
@@ -556,7 +500,9 @@
// FIXME do something more efficient for transmutes between vectors and integers.
let stack_slot = fx.bcx.create_stack_slot(StackSlotData {
kind: StackSlotKind::ExplicitSlot,
- size: src_ty.bytes(),
+ // FIXME Don't force the size to a multiple of 16 bytes once Cranelift gets a way to
+ // specify stack slot alignment.
+ size: (src_ty.bytes() + 15) / 16 * 16,
offset: None,
});
let ptr = Pointer::stack_slot(stack_slot);
@@ -794,3 +740,62 @@
}
}
}
+
+#[track_caller]
+pub(crate) fn assert_assignable<'tcx>(
+ fx: &FunctionCx<'_, 'tcx, impl Module>,
+ from_ty: Ty<'tcx>,
+ to_ty: Ty<'tcx>,
+) {
+ match (from_ty.kind(), to_ty.kind()) {
+ (ty::Ref(_, a, _), ty::Ref(_, b, _))
+ | (
+ ty::RawPtr(TypeAndMut { ty: a, mutbl: _ }),
+ ty::RawPtr(TypeAndMut { ty: b, mutbl: _ }),
+ ) => {
+ assert_assignable(fx, a, b);
+ }
+ (ty::Ref(_, a, _), ty::RawPtr(TypeAndMut { ty: b, mutbl: _ }))
+ | (ty::RawPtr(TypeAndMut { ty: a, mutbl: _ }), ty::Ref(_, b, _)) => {
+ assert_assignable(fx, a, b);
+ }
+ (ty::FnPtr(_), ty::FnPtr(_)) => {
+ let from_sig = fx.tcx.normalize_erasing_late_bound_regions(
+ ParamEnv::reveal_all(),
+ from_ty.fn_sig(fx.tcx),
+ );
+ let to_sig = fx
+ .tcx
+ .normalize_erasing_late_bound_regions(ParamEnv::reveal_all(), to_ty.fn_sig(fx.tcx));
+ assert_eq!(
+ from_sig, to_sig,
+ "Can't write fn ptr with incompatible sig {:?} to place with sig {:?}\n\n{:#?}",
+ from_sig, to_sig, fx,
+ );
+ // fn(&T) -> for<'l> fn(&'l T) is allowed
+ }
+ (&ty::Dynamic(from_traits, _), &ty::Dynamic(to_traits, _)) => {
+ for (from, to) in from_traits.iter().zip(to_traits) {
+ let from = fx
+ .tcx
+ .normalize_erasing_late_bound_regions(ParamEnv::reveal_all(), from);
+ let to = fx
+ .tcx
+ .normalize_erasing_late_bound_regions(ParamEnv::reveal_all(), to);
+ assert_eq!(
+ from, to,
+ "Can't write trait object of incompatible traits {:?} to place with traits {:?}\n\n{:#?}",
+ from_traits, to_traits, fx,
+ );
+ }
+ // dyn for<'r> Trait<'r> -> dyn Trait<'_> is allowed
+ }
+ _ => {
+ assert_eq!(
+ from_ty, to_ty,
+ "Can't write value with incompatible type {:?} to place with type {:?}\n\n{:#?}",
+ from_ty, to_ty, fx,
+ );
+ }
+ }
+}
diff --git a/compiler/rustc_codegen_cranelift/src/vtable.rs b/compiler/rustc_codegen_cranelift/src/vtable.rs
index 238abc0..8f15586 100644
--- a/compiler/rustc_codegen_cranelift/src/vtable.rs
+++ b/compiler/rustc_codegen_cranelift/src/vtable.rs
@@ -158,7 +158,8 @@
)
.unwrap();
- fx.cx.module.define_data(data_id, &data_ctx).unwrap();
+ // FIXME don't duplicate definitions in lazy jit mode
+ let _ = fx.cx.module.define_data(data_id, &data_ctx);
data_id
}
diff --git a/compiler/rustc_codegen_cranelift/test.sh b/compiler/rustc_codegen_cranelift/test.sh
index c6c4956..5ab10e0 100755
--- a/compiler/rustc_codegen_cranelift/test.sh
+++ b/compiler/rustc_codegen_cranelift/test.sh
@@ -1,9 +1,7 @@
#!/bin/bash
set -e
-export RUSTFLAGS="-Zrun_dsymutil=no"
-
-./build.sh --without-sysroot "$@"
+./build.sh --sysroot none "$@"
rm -r target/out || true
diff --git a/compiler/rustc_codegen_llvm/src/abi.rs b/compiler/rustc_codegen_llvm/src/abi.rs
index 915dd3d..a69241e 100644
--- a/compiler/rustc_codegen_llvm/src/abi.rs
+++ b/compiler/rustc_codegen_llvm/src/abi.rs
@@ -389,7 +389,7 @@
fn llvm_cconv(&self) -> llvm::CallConv {
match self.conv {
- Conv::C | Conv::Rust => llvm::CCallConv,
+ Conv::C | Conv::Rust | Conv::CCmseNonSecureCall => llvm::CCallConv,
Conv::AmdGpuKernel => llvm::AmdGpuKernel,
Conv::AvrInterrupt => llvm::AvrInterrupt,
Conv::AvrNonBlockingInterrupt => llvm::AvrNonBlockingInterrupt,
@@ -546,6 +546,18 @@
if cconv != llvm::CCallConv {
llvm::SetInstructionCallConv(callsite, cconv);
}
+
+ if self.conv == Conv::CCmseNonSecureCall {
+ // This will probably get ignored on all targets but those supporting the TrustZone-M
+ // extension (thumbv8m targets).
+ unsafe {
+ llvm::AddCallSiteAttrString(
+ callsite,
+ llvm::AttributePlace::Function,
+ rustc_data_structures::const_cstr!("cmse_nonsecure_call"),
+ );
+ }
+ }
}
}
diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs
index 97c38e0..a78d692 100644
--- a/compiler/rustc_codegen_llvm/src/attributes.rs
+++ b/compiler/rustc_codegen_llvm/src/attributes.rs
@@ -13,6 +13,7 @@
use rustc_middle::ty::{self, TyCtxt};
use rustc_session::config::{OptLevel, SanitizerSet};
use rustc_session::Session;
+use rustc_target::spec::StackProbeType;
use crate::attributes;
use crate::llvm::AttributePlace::Function;
@@ -98,12 +99,6 @@
}
fn set_probestack(cx: &CodegenCx<'ll, '_>, llfn: &'ll Value) {
- // Only use stack probes if the target specification indicates that we
- // should be using stack probes
- if !cx.sess().target.stack_probes {
- return;
- }
-
// Currently stack probes seem somewhat incompatible with the address
// sanitizer and thread sanitizer. With asan we're already protected from
// stack overflow anyway so we don't really need stack probes regardless.
@@ -127,14 +122,31 @@
return;
}
- // Flag our internal `__rust_probestack` function as the stack probe symbol.
- // This is defined in the `compiler-builtins` crate for each architecture.
- llvm::AddFunctionAttrStringValue(
- llfn,
- llvm::AttributePlace::Function,
- const_cstr!("probe-stack"),
- const_cstr!("__rust_probestack"),
- );
+ let attr_value = match cx.sess().target.stack_probes {
+ StackProbeType::None => None,
+ // Request LLVM to generate the probes inline. If the given LLVM version does not support
+ // this, no probe is generated at all (even if the attribute is specified).
+ StackProbeType::Inline => Some(const_cstr!("inline-asm")),
+ // Flag our internal `__rust_probestack` function as the stack probe symbol.
+ // This is defined in the `compiler-builtins` crate for each architecture.
+ StackProbeType::Call => Some(const_cstr!("__rust_probestack")),
+ // Pick from the two above based on the LLVM version.
+ StackProbeType::InlineOrCall { min_llvm_version_for_inline } => {
+ if llvm_util::get_version() < min_llvm_version_for_inline {
+ Some(const_cstr!("__rust_probestack"))
+ } else {
+ Some(const_cstr!("inline-asm"))
+ }
+ }
+ };
+ if let Some(attr_value) = attr_value {
+ llvm::AddFunctionAttrStringValue(
+ llfn,
+ llvm::AttributePlace::Function,
+ const_cstr!("probe-stack"),
+ attr_value,
+ );
+ }
}
pub fn llvm_target_features(sess: &Session) -> impl Iterator<Item = &str> {
diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs
index 2941597..5effe68 100644
--- a/compiler/rustc_codegen_llvm/src/back/lto.rs
+++ b/compiler/rustc_codegen_llvm/src/back/lto.rs
@@ -732,10 +732,7 @@
let diag_handler = cgcx.create_diag_handler();
let module_name = &thin_module.shared.module_names[thin_module.idx];
- let split_dwarf_file = cgcx
- .output_filenames
- .split_dwarf_filename(cgcx.split_dwarf_kind, Some(module_name.to_str().unwrap()));
- let tm_factory_config = TargetMachineFactoryConfig { split_dwarf_file };
+ let tm_factory_config = TargetMachineFactoryConfig::new(cgcx, module_name.to_str().unwrap());
let tm =
(cgcx.tm_factory)(tm_factory_config).map_err(|e| write::llvm_err(&diag_handler, &e))?;
diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs
index 3fda1e2..326ae35 100644
--- a/compiler/rustc_codegen_llvm/src/back/write.rs
+++ b/compiler/rustc_codegen_llvm/src/back/write.rs
@@ -23,13 +23,11 @@
use rustc_hir::def_id::LOCAL_CRATE;
use rustc_middle::bug;
use rustc_middle::ty::TyCtxt;
-use rustc_session::config::{
- self, Lto, OutputType, Passes, SanitizerSet, SplitDwarfKind, SwitchWithOptPath,
-};
+use rustc_session::config::{self, Lto, OutputType, Passes, SanitizerSet, SwitchWithOptPath};
use rustc_session::Session;
use rustc_span::symbol::sym;
use rustc_span::InnerSpan;
-use rustc_target::spec::{CodeModel, RelocModel};
+use rustc_target::spec::{CodeModel, RelocModel, SplitDebuginfo};
use tracing::debug;
use libc::{c_char, c_int, c_uint, c_void, size_t};
@@ -93,9 +91,12 @@
}
pub fn create_target_machine(tcx: TyCtxt<'_>, mod_name: &str) -> &'static mut llvm::TargetMachine {
- let split_dwarf_file = tcx
- .output_filenames(LOCAL_CRATE)
- .split_dwarf_filename(tcx.sess.opts.debugging_opts.split_dwarf, Some(mod_name));
+ let split_dwarf_file = if tcx.sess.target_can_use_split_dwarf() {
+ tcx.output_filenames(LOCAL_CRATE)
+ .split_dwarf_filename(tcx.sess.split_debuginfo(), Some(mod_name))
+ } else {
+ None
+ };
let config = TargetMachineFactoryConfig { split_dwarf_file };
target_machine_factory(&tcx.sess, tcx.backend_optimization_level(LOCAL_CRATE))(config)
.unwrap_or_else(|err| llvm_err(tcx.sess.diagnostic(), &err).raise())
@@ -164,7 +165,8 @@
let code_model = to_llvm_code_model(sess.code_model());
- let features = attributes::llvm_target_features(sess).collect::<Vec<_>>();
+ let mut features = llvm_util::handle_native_features(sess);
+ features.extend(attributes::llvm_target_features(sess).map(|s| s.to_owned()));
let mut singlethread = sess.target.singlethread;
// On the wasm target once the `atomics` feature is enabled that means that
@@ -485,7 +487,7 @@
diag_handler: &Handler,
module: &ModuleCodegen<ModuleLlvm>,
config: &ModuleConfig,
-) -> Result<(), FatalError> {
+) {
let _timer = cgcx.prof.generic_activity_with_arg("LLVM_module_optimize", &module.name[..]);
let llmod = module.module_llvm.llmod();
@@ -511,7 +513,7 @@
_ => llvm::OptStage::PreLinkNoLTO,
};
optimize_with_new_llvm_pass_manager(cgcx, module, config, opt_level, opt_stage);
- return Ok(());
+ return;
}
if cgcx.prof.llvm_recording_enabled() {
@@ -634,7 +636,6 @@
llvm::LLVMDisposePassManager(fpm);
llvm::LLVMDisposePassManager(mpm);
}
- Ok(())
}
unsafe fn add_sanitizer_passes(config: &ModuleConfig, passes: &mut Vec<&'static mut llvm::Pass>) {
@@ -838,11 +839,17 @@
.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_dwarf_kind {
+ let dwo_out = match cgcx.split_debuginfo {
// Don't change how DWARF is emitted in single mode (or when disabled).
- SplitDwarfKind::None | SplitDwarfKind::Single => None,
+ SplitDebuginfo::Off | SplitDebuginfo::Packed => None,
// Emit (a subset of the) DWARF into a separate file in split mode.
- SplitDwarfKind::Split => Some(dwo_out.as_path()),
+ SplitDebuginfo::Unpacked => {
+ if cgcx.target_can_use_split_dwarf {
+ Some(dwo_out.as_path())
+ } else {
+ None
+ }
+ }
};
with_codegen(tm, llmod, config.no_builtins, |cpm| {
@@ -880,7 +887,7 @@
Ok(module.into_compiled_module(
config.emit_obj != EmitObj::None,
- cgcx.split_dwarf_kind == SplitDwarfKind::Split,
+ cgcx.target_can_use_split_dwarf && cgcx.split_debuginfo == SplitDebuginfo::Unpacked,
config.emit_bc,
&cgcx.output_filenames,
))
@@ -1002,8 +1009,7 @@
// reasonable defaults and prepare it to actually populate the pass
// manager.
let builder = llvm::LLVMPassManagerBuilderCreate();
- let opt_size =
- config.opt_size.map(|x| to_llvm_opt_settings(x).1).unwrap_or(llvm::CodeGenOptSizeNone);
+ let opt_size = config.opt_size.map_or(llvm::CodeGenOptSizeNone, |x| to_llvm_opt_settings(x).1);
let inline_threshold = config.inline_threshold;
let pgo_gen_path = get_pgo_gen_path(config);
let pgo_use_path = get_pgo_use_path(config);
diff --git a/compiler/rustc_codegen_llvm/src/base.rs b/compiler/rustc_codegen_llvm/src/base.rs
index 7d01f6a..d5be313 100644
--- a/compiler/rustc_codegen_llvm/src/base.rs
+++ b/compiler/rustc_codegen_llvm/src/base.rs
@@ -1,17 +1,15 @@
-//! Codegen the completed AST to the LLVM IR.
-//!
-//! Some functions here, such as codegen_block and codegen_expr, return a value --
-//! the result of the codegen to LLVM -- while others, such as codegen_fn
-//! and mono_item, are called only for the side effect of adding a
-//! particular definition to the LLVM IR output we're producing.
+//! Codegen the MIR to the LLVM IR.
//!
//! Hopefully useful general knowledge about codegen:
//!
-//! * There's no way to find out the `Ty` type of a Value. Doing so
+//! * There's no way to find out the [`Ty`] type of a [`Value`]. Doing so
//! would be "trying to get the eggs out of an omelette" (credit:
-//! pcwalton). You can, instead, find out its `llvm::Type` by calling `val_ty`,
-//! but one `llvm::Type` corresponds to many `Ty`s; for instance, `tup(int, int,
-//! int)` and `rec(x=int, y=int, z=int)` will have the same `llvm::Type`.
+//! pcwalton). You can, instead, find out its [`llvm::Type`] by calling [`val_ty`],
+//! but one [`llvm::Type`] corresponds to many [`Ty`]s; for instance, `tup(int, int,
+//! int)` and `rec(x=int, y=int, z=int)` will have the same [`llvm::Type`].
+//!
+//! [`Ty`]: rustc_middle::ty::Ty
+//! [`val_ty`]: common::val_ty
use super::ModuleLlvm;
diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs
index f122fa1..d2f4d3e 100644
--- a/compiler/rustc_codegen_llvm/src/builder.rs
+++ b/compiler/rustc_codegen_llvm/src/builder.rs
@@ -304,9 +304,8 @@
lhs: Self::Value,
rhs: Self::Value,
) -> (Self::Value, Self::Value) {
- use rustc_ast::IntTy::*;
- use rustc_ast::UintTy::*;
use rustc_middle::ty::{Int, Uint};
+ use rustc_middle::ty::{IntTy::*, UintTy::*};
let new_kind = match ty.kind() {
Int(t @ Isize) => Int(t.normalize(self.tcx.sess.target.pointer_width)),
diff --git a/compiler/rustc_codegen_llvm/src/common.rs b/compiler/rustc_codegen_llvm/src/common.rs
index 34e1b7a..58af9d4 100644
--- a/compiler/rustc_codegen_llvm/src/common.rs
+++ b/compiler/rustc_codegen_llvm/src/common.rs
@@ -314,6 +314,7 @@
}
}
+/// Get the [LLVM type][Type] of a [`Value`].
pub fn val_ty(v: &Value) -> &Type {
unsafe { llvm::LLVMTypeOf(v) }
}
diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs
index 14dd245..16e1a8a 100644
--- a/compiler/rustc_codegen_llvm/src/consts.rs
+++ b/compiler/rustc_codegen_llvm/src/consts.rs
@@ -8,9 +8,7 @@
use libc::c_uint;
use rustc_codegen_ssa::traits::*;
use rustc_data_structures::const_cstr;
-use rustc_hir as hir;
use rustc_hir::def_id::DefId;
-use rustc_hir::Node;
use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs};
use rustc_middle::mir::interpret::{
read_target_uint, Allocation, ErrorHandled, GlobalAlloc, Pointer,
@@ -18,7 +16,6 @@
use rustc_middle::mir::mono::MonoItem;
use rustc_middle::ty::{self, Instance, Ty};
use rustc_middle::{bug, span_bug};
-use rustc_span::symbol::sym;
use rustc_target::abi::{AddressSpace, Align, HasDataLayout, LayoutOf, Primitive, Scalar, Size};
use tracing::debug;
@@ -209,70 +206,42 @@
let ty = instance.ty(self.tcx, ty::ParamEnv::reveal_all());
let sym = self.tcx.symbol_name(instance).name;
+ let fn_attrs = self.tcx.codegen_fn_attrs(def_id);
- debug!("get_static: sym={} instance={:?}", sym, instance);
+ debug!("get_static: sym={} instance={:?} fn_attrs={:?}", sym, instance, fn_attrs);
- let g = if let Some(local_def_id) = def_id.as_local() {
- let id = self.tcx.hir().local_def_id_to_hir_id(local_def_id);
+ let g = if def_id.is_local() && !self.tcx.is_foreign_item(def_id) {
let llty = self.layout_of(ty).llvm_type(self);
- // FIXME: refactor this to work without accessing the HIR
- let (g, attrs) = match self.tcx.hir().get(id) {
- Node::Item(&hir::Item { attrs, kind: hir::ItemKind::Static(..), .. }) => {
- if let Some(g) = self.get_declared_value(sym) {
- if self.val_ty(g) != self.type_ptr_to(llty) {
- span_bug!(self.tcx.def_span(def_id), "Conflicting types for static");
- }
- }
-
- let g = self.declare_global(sym, llty);
-
- if !self.tcx.is_reachable_non_generic(local_def_id) {
- unsafe {
- llvm::LLVMRustSetVisibility(g, llvm::Visibility::Hidden);
- }
- }
-
- (g, attrs)
+ if let Some(g) = self.get_declared_value(sym) {
+ if self.val_ty(g) != self.type_ptr_to(llty) {
+ span_bug!(self.tcx.def_span(def_id), "Conflicting types for static");
}
+ }
- Node::ForeignItem(&hir::ForeignItem {
- ref attrs,
- kind: hir::ForeignItemKind::Static(..),
- ..
- }) => {
- let fn_attrs = self.tcx.codegen_fn_attrs(local_def_id);
- (check_and_apply_linkage(&self, &fn_attrs, ty, sym, def_id), &**attrs)
- }
+ let g = self.declare_global(sym, llty);
- item => bug!("get_static: expected static, found {:?}", item),
- };
-
- debug!("get_static: sym={} attrs={:?}", sym, attrs);
-
- for attr in attrs {
- if self.tcx.sess.check_name(attr, sym::thread_local) {
- llvm::set_thread_local_mode(g, self.tls_model);
+ if !self.tcx.is_reachable_non_generic(def_id) {
+ unsafe {
+ llvm::LLVMRustSetVisibility(g, llvm::Visibility::Hidden);
}
}
g
} else {
- // FIXME(nagisa): perhaps the map of externs could be offloaded to llvm somehow?
- debug!("get_static: sym={} item_attr={:?}", sym, self.tcx.item_attrs(def_id));
+ check_and_apply_linkage(&self, &fn_attrs, ty, sym, def_id)
+ };
- let attrs = self.tcx.codegen_fn_attrs(def_id);
- let g = check_and_apply_linkage(&self, &attrs, ty, sym, def_id);
+ // Thread-local statics in some other crate need to *always* be linked
+ // against in a thread-local fashion, so we need to be sure to apply the
+ // thread-local attribute locally if it was present remotely. If we
+ // don't do this then linker errors can be generated where the linker
+ // complains that one object files has a thread local version of the
+ // symbol and another one doesn't.
+ if fn_attrs.flags.contains(CodegenFnAttrFlags::THREAD_LOCAL) {
+ llvm::set_thread_local_mode(g, self.tls_model);
+ }
- // Thread-local statics in some other crate need to *always* be linked
- // against in a thread-local fashion, so we need to be sure to apply the
- // thread-local attribute locally if it was present remotely. If we
- // don't do this then linker errors can be generated where the linker
- // complains that one object files has a thread local version of the
- // symbol and another one doesn't.
- if attrs.flags.contains(CodegenFnAttrFlags::THREAD_LOCAL) {
- llvm::set_thread_local_mode(g, self.tls_model);
- }
-
+ if !def_id.is_local() {
let needs_dll_storage_attr = self.use_dll_storage_attrs && !self.tcx.is_foreign_item(def_id) &&
// ThinLTO can't handle this workaround in all cases, so we don't
// emit the attrs. Instead we make them unnecessary by disallowing
@@ -304,8 +273,7 @@
}
}
}
- g
- };
+ }
if self.use_dll_storage_attrs && self.tcx.is_dllimport_foreign_item(def_id) {
// For foreign (native) libs we know the exact storage type to use.
diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs
index 8dd4030..6acd26b 100644
--- a/compiler/rustc_codegen_llvm/src/context.rs
+++ b/compiler/rustc_codegen_llvm/src/context.rs
@@ -114,7 +114,7 @@
let llmod = llvm::LLVMModuleCreateWithNameInContext(mod_name.as_ptr(), llcx);
let mut target_data_layout = sess.target.data_layout.clone();
- if llvm_util::get_major_version() < 10
+ if llvm_util::get_version() < (10, 0, 0)
&& (sess.target.arch == "x86" || sess.target.arch == "x86_64")
{
target_data_layout = strip_x86_address_spaces(target_data_layout);
diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
index 72ba5bb..444a9d4 100644
--- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
+++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
@@ -292,7 +292,7 @@
if let Some(non_codegenned_file_name) = tcx.covered_file_name(non_codegenned_def_id) {
let def_ids = unreachable_def_ids_by_file
.entry(*non_codegenned_file_name)
- .or_insert_with(|| Vec::new());
+ .or_insert_with(Vec::new);
def_ids.push(non_codegenned_def_id);
}
}
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
index fa285f3..6e7c0b3 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
@@ -18,7 +18,6 @@
};
use crate::value::Value;
-use rustc_ast as ast;
use rustc_codegen_ssa::traits::*;
use rustc_data_structures::const_cstr;
use rustc_data_structures::fingerprint::Fingerprint;
@@ -830,37 +829,37 @@
fn msvc_basic_name(self) -> &'static str;
}
-impl MsvcBasicName for ast::IntTy {
+impl MsvcBasicName for ty::IntTy {
fn msvc_basic_name(self) -> &'static str {
match self {
- ast::IntTy::Isize => "ptrdiff_t",
- ast::IntTy::I8 => "__int8",
- ast::IntTy::I16 => "__int16",
- ast::IntTy::I32 => "__int32",
- ast::IntTy::I64 => "__int64",
- ast::IntTy::I128 => "__int128",
+ ty::IntTy::Isize => "ptrdiff_t",
+ ty::IntTy::I8 => "__int8",
+ ty::IntTy::I16 => "__int16",
+ ty::IntTy::I32 => "__int32",
+ ty::IntTy::I64 => "__int64",
+ ty::IntTy::I128 => "__int128",
}
}
}
-impl MsvcBasicName for ast::UintTy {
+impl MsvcBasicName for ty::UintTy {
fn msvc_basic_name(self) -> &'static str {
match self {
- ast::UintTy::Usize => "size_t",
- ast::UintTy::U8 => "unsigned __int8",
- ast::UintTy::U16 => "unsigned __int16",
- ast::UintTy::U32 => "unsigned __int32",
- ast::UintTy::U64 => "unsigned __int64",
- ast::UintTy::U128 => "unsigned __int128",
+ ty::UintTy::Usize => "size_t",
+ ty::UintTy::U8 => "unsigned __int8",
+ ty::UintTy::U16 => "unsigned __int16",
+ ty::UintTy::U32 => "unsigned __int32",
+ ty::UintTy::U64 => "unsigned __int64",
+ ty::UintTy::U128 => "unsigned __int128",
}
}
}
-impl MsvcBasicName for ast::FloatTy {
+impl MsvcBasicName for ty::FloatTy {
fn msvc_basic_name(self) -> &'static str {
match self {
- ast::FloatTy::F32 => "float",
- ast::FloatTy::F64 => "double",
+ ty::FloatTy::F32 => "float",
+ ty::FloatTy::F64 => "double",
}
}
}
@@ -996,10 +995,13 @@
let flags = "\0";
let out_dir = &tcx.output_filenames(LOCAL_CRATE).out_directory;
- let split_name = tcx
- .output_filenames(LOCAL_CRATE)
- .split_dwarf_filename(tcx.sess.opts.debugging_opts.split_dwarf, Some(codegen_unit_name))
- .unwrap_or_default();
+ let split_name = if tcx.sess.target_can_use_split_dwarf() {
+ tcx.output_filenames(LOCAL_CRATE)
+ .split_dwarf_filename(tcx.sess.split_debuginfo(), Some(codegen_unit_name))
+ } else {
+ None
+ }
+ .unwrap_or_default();
let out_dir = out_dir.to_str().unwrap();
let split_name = split_name.to_str().unwrap();
@@ -1832,8 +1834,9 @@
fn source_info(&self, cx: &CodegenCx<'ll, 'tcx>) -> Option<SourceInfo<'ll>> {
match self {
VariantInfo::Generator { def_id, variant_index, .. } => {
- let span =
- cx.tcx.generator_layout(*def_id).variant_source_info[*variant_index].span;
+ let span = cx.tcx.generator_layout(*def_id).unwrap().variant_source_info
+ [*variant_index]
+ .span;
if !span.is_dummy() {
let loc = cx.lookup_debug_loc(span.lo());
return Some(SourceInfo {
@@ -2322,13 +2325,13 @@
DIB(cx),
composite_type_metadata,
Some(type_array),
- type_params,
+ Some(type_params),
);
}
}
/// Computes the type parameters for a type, if any, for the given metadata.
-fn compute_type_parameters(cx: &CodegenCx<'ll, 'tcx>, ty: Ty<'tcx>) -> Option<&'ll DIArray> {
+fn compute_type_parameters(cx: &CodegenCx<'ll, 'tcx>, ty: Ty<'tcx>) -> &'ll DIArray {
if let ty::Adt(def, substs) = *ty.kind() {
if substs.types().next().is_some() {
let generics = cx.tcx.generics_of(def.did);
@@ -2358,10 +2361,10 @@
})
.collect();
- return Some(create_DIArray(DIB(cx), &template_params[..]));
+ return create_DIArray(DIB(cx), &template_params[..]);
}
}
- return Some(create_DIArray(DIB(cx), &[]));
+ return create_DIArray(DIB(cx), &[]);
fn get_parameter_names(cx: &CodegenCx<'_, '_>, generics: &ty::Generics) -> Vec<Symbol> {
let mut names = generics
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
index ccbe732..955e739 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
@@ -552,7 +552,6 @@
unsafe {
llvm::LLVMRustDIBuilderCreateDebugLocation(
- utils::debug_context(self).llcontext,
line.unwrap_or(UNKNOWN_LINE_NUMBER),
col.unwrap_or(UNKNOWN_COLUMN_NUMBER),
scope,
diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs
index a58c2fb..d11c159 100644
--- a/compiler/rustc_codegen_llvm/src/lib.rs
+++ b/compiler/rustc_codegen_llvm/src/lib.rs
@@ -160,7 +160,7 @@
module: &ModuleCodegen<Self::Module>,
config: &ModuleConfig,
) -> Result<(), FatalError> {
- back::write::optimize(cgcx, diag_handler, module, config)
+ Ok(back::write::optimize(cgcx, diag_handler, module, config))
}
unsafe fn optimize_thin(
cgcx: &CodegenContext<Self>,
@@ -298,21 +298,19 @@
codegen_results: CodegenResults,
outputs: &OutputFilenames,
) -> Result<(), ErrorReported> {
+ use crate::back::archive::LlvmArchiveBuilder;
+ use rustc_codegen_ssa::back::link::link_binary;
+
// Run the linker on any artifacts that resulted from the LLVM run.
// This should produce either a finished executable or library.
- sess.time("link_crate", || {
- use crate::back::archive::LlvmArchiveBuilder;
- use rustc_codegen_ssa::back::link::link_binary;
-
- let target_cpu = crate::llvm_util::target_cpu(sess);
- link_binary::<LlvmArchiveBuilder<'_>>(
- sess,
- &codegen_results,
- outputs,
- &codegen_results.crate_name.as_str(),
- target_cpu,
- );
- });
+ let target_cpu = crate::llvm_util::target_cpu(sess);
+ link_binary::<LlvmArchiveBuilder<'_>>(
+ sess,
+ &codegen_results,
+ outputs,
+ &codegen_results.crate_name.as_str(),
+ target_cpu,
+ );
Ok(())
}
@@ -353,12 +351,7 @@
unsafe {
let llcx = llvm::LLVMRustContextCreate(cgcx.fewer_names);
let llmod_raw = back::lto::parse_module(llcx, name, buffer, handler)?;
-
- let split_dwarf_file = cgcx
- .output_filenames
- .split_dwarf_filename(cgcx.split_dwarf_kind, Some(name.to_str().unwrap()));
- let tm_factory_config = TargetMachineFactoryConfig { split_dwarf_file };
-
+ let tm_factory_config = TargetMachineFactoryConfig::new(&cgcx, name.to_str().unwrap());
let tm = match (cgcx.tm_factory)(tm_factory_config) {
Ok(m) => m,
Err(e) => {
diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
index 707aaa2..e82198f 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
@@ -1100,6 +1100,7 @@
// Operations on call sites
pub fn LLVMSetInstructionCallConv(Instr: &Value, CC: c_uint);
pub fn LLVMRustAddCallSiteAttribute(Instr: &Value, index: c_uint, attr: Attribute);
+ pub fn LLVMRustAddCallSiteAttrString(Instr: &Value, index: c_uint, Name: *const c_char);
pub fn LLVMRustAddAlignmentCallSiteAttr(Instr: &Value, index: c_uint, bytes: u32);
pub fn LLVMRustAddDereferenceableCallSiteAttr(Instr: &Value, index: c_uint, bytes: u64);
pub fn LLVMRustAddDereferenceableOrNullCallSiteAttr(Instr: &Value, index: c_uint, bytes: u64);
@@ -1708,6 +1709,10 @@
PM: &PassManager<'_>,
);
+ pub fn LLVMGetHostCPUFeatures() -> *mut c_char;
+
+ pub fn LLVMDisposeMessage(message: *mut c_char);
+
// Stuff that's in llvm-wrapper/ because it's not upstream yet.
/// Opens an object file.
@@ -1807,6 +1812,7 @@
pub fn LLVMRustDebugMetadataVersion() -> u32;
pub fn LLVMRustVersionMajor() -> u32;
pub fn LLVMRustVersionMinor() -> u32;
+ pub fn LLVMRustVersionPatch() -> u32;
pub fn LLVMRustAddModuleFlag(M: &Module, name: *const c_char, value: u32);
@@ -2098,7 +2104,6 @@
);
pub fn LLVMRustDIBuilderCreateDebugLocation(
- Context: &'a Context,
Line: c_uint,
Column: c_uint,
Scope: &'a DIScope,
diff --git a/compiler/rustc_codegen_llvm/src/llvm/mod.rs b/compiler/rustc_codegen_llvm/src/llvm/mod.rs
index fc40065..bb9c6d4 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/mod.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/mod.rs
@@ -43,6 +43,10 @@
}
}
+pub fn AddCallSiteAttrString(callsite: &Value, idx: AttributePlace, attr: &CStr) {
+ unsafe { LLVMRustAddCallSiteAttrString(callsite, idx.as_uint(), attr.as_ptr()) }
+}
+
#[derive(Copy, Clone)]
pub enum AttributePlace {
ReturnValue,
diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs
index a3139ce..544ef38 100644
--- a/compiler/rustc_codegen_llvm/src/llvm_util.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs
@@ -8,7 +8,7 @@
use rustc_session::Session;
use rustc_span::symbol::Symbol;
use rustc_target::spec::{MergeFunctions, PanicStrategy};
-use std::ffi::CString;
+use std::ffi::{CStr, CString};
use std::slice;
use std::str;
@@ -171,14 +171,15 @@
}
pub fn print_version() {
- // Can be called without initializing LLVM
- unsafe {
- println!("LLVM version: {}.{}", llvm::LLVMRustVersionMajor(), llvm::LLVMRustVersionMinor());
- }
+ let (major, minor, patch) = get_version();
+ println!("LLVM version: {}.{}.{}", major, minor, patch);
}
-pub fn get_major_version() -> u32 {
- unsafe { llvm::LLVMRustVersionMajor() }
+pub fn get_version() -> (u32, u32, u32) {
+ // Can be called without initializing LLVM
+ unsafe {
+ (llvm::LLVMRustVersionMajor(), llvm::LLVMRustVersionMinor(), llvm::LLVMRustVersionPatch())
+ }
}
pub fn print_passes() {
@@ -213,17 +214,42 @@
}
pub fn target_cpu(sess: &Session) -> &str {
- let name = match sess.opts.cg.target_cpu {
- Some(ref s) => &**s,
- None => &*sess.target.cpu,
- };
-
+ let name = sess.opts.cg.target_cpu.as_ref().unwrap_or(&sess.target.cpu);
handle_native(name)
}
-pub fn tune_cpu(sess: &Session) -> Option<&str> {
- match sess.opts.debugging_opts.tune_cpu {
- Some(ref s) => Some(handle_native(&**s)),
- None => None,
+pub fn handle_native_features(sess: &Session) -> Vec<String> {
+ match sess.opts.cg.target_cpu {
+ Some(ref s) => {
+ if s != "native" {
+ return vec![];
+ }
+
+ let features_string = unsafe {
+ let ptr = llvm::LLVMGetHostCPUFeatures();
+ let features_string = if !ptr.is_null() {
+ CStr::from_ptr(ptr)
+ .to_str()
+ .unwrap_or_else(|e| {
+ bug!("LLVM returned a non-utf8 features string: {}", e);
+ })
+ .to_owned()
+ } else {
+ bug!("could not allocate host CPU features, LLVM returned a `null` string");
+ };
+
+ llvm::LLVMDisposeMessage(ptr);
+
+ features_string
+ };
+
+ features_string.split(",").map(|s| s.to_owned()).collect()
+ }
+ None => vec![],
}
}
+
+pub fn tune_cpu(sess: &Session) -> Option<&str> {
+ let name = sess.opts.debugging_opts.tune_cpu.as_ref()?;
+ Some(handle_native(name))
+}
diff --git a/compiler/rustc_codegen_llvm/src/type_.rs b/compiler/rustc_codegen_llvm/src/type_.rs
index a43724f..8fd0caae 100644
--- a/compiler/rustc_codegen_llvm/src/type_.rs
+++ b/compiler/rustc_codegen_llvm/src/type_.rs
@@ -7,13 +7,12 @@
use crate::llvm::{Bool, False, True};
use crate::type_of::LayoutLlvmExt;
use crate::value::Value;
-use rustc_ast as ast;
use rustc_codegen_ssa::common::TypeKind;
use rustc_codegen_ssa::traits::*;
use rustc_data_structures::small_c_str::SmallCStr;
use rustc_middle::bug;
use rustc_middle::ty::layout::TyAndLayout;
-use rustc_middle::ty::Ty;
+use rustc_middle::ty::{self, Ty};
use rustc_target::abi::call::{CastTarget, FnAbi, Reg};
use rustc_target::abi::{AddressSpace, Align, Integer, Size};
@@ -80,32 +79,32 @@
self.type_i8()
}
- crate fn type_int_from_ty(&self, t: ast::IntTy) -> &'ll Type {
+ crate fn type_int_from_ty(&self, t: ty::IntTy) -> &'ll Type {
match t {
- ast::IntTy::Isize => self.type_isize(),
- ast::IntTy::I8 => self.type_i8(),
- ast::IntTy::I16 => self.type_i16(),
- ast::IntTy::I32 => self.type_i32(),
- ast::IntTy::I64 => self.type_i64(),
- ast::IntTy::I128 => self.type_i128(),
+ ty::IntTy::Isize => self.type_isize(),
+ ty::IntTy::I8 => self.type_i8(),
+ ty::IntTy::I16 => self.type_i16(),
+ ty::IntTy::I32 => self.type_i32(),
+ ty::IntTy::I64 => self.type_i64(),
+ ty::IntTy::I128 => self.type_i128(),
}
}
- crate fn type_uint_from_ty(&self, t: ast::UintTy) -> &'ll Type {
+ crate fn type_uint_from_ty(&self, t: ty::UintTy) -> &'ll Type {
match t {
- ast::UintTy::Usize => self.type_isize(),
- ast::UintTy::U8 => self.type_i8(),
- ast::UintTy::U16 => self.type_i16(),
- ast::UintTy::U32 => self.type_i32(),
- ast::UintTy::U64 => self.type_i64(),
- ast::UintTy::U128 => self.type_i128(),
+ ty::UintTy::Usize => self.type_isize(),
+ ty::UintTy::U8 => self.type_i8(),
+ ty::UintTy::U16 => self.type_i16(),
+ ty::UintTy::U32 => self.type_i32(),
+ ty::UintTy::U64 => self.type_i64(),
+ ty::UintTy::U128 => self.type_i128(),
}
}
- crate fn type_float_from_ty(&self, t: ast::FloatTy) -> &'ll Type {
+ crate fn type_float_from_ty(&self, t: ty::FloatTy) -> &'ll Type {
match t {
- ast::FloatTy::F32 => self.type_f32(),
- ast::FloatTy::F64 => self.type_f64(),
+ ty::FloatTy::F32 => self.type_f32(),
+ ty::FloatTy::F64 => self.type_f64(),
}
}
diff --git a/compiler/rustc_codegen_llvm/src/va_arg.rs b/compiler/rustc_codegen_llvm/src/va_arg.rs
index 3fc56ee..39d08fb 100644
--- a/compiler/rustc_codegen_llvm/src/va_arg.rs
+++ b/compiler/rustc_codegen_llvm/src/va_arg.rs
@@ -9,7 +9,7 @@
};
use rustc_middle::ty::layout::HasTyCtxt;
use rustc_middle::ty::Ty;
-use rustc_target::abi::{Align, HasDataLayout, LayoutOf, Size};
+use rustc_target::abi::{Align, Endian, HasDataLayout, LayoutOf, Size};
fn round_pointer_up_to_alignment(
bx: &mut Builder<'a, 'll, 'tcx>,
@@ -52,7 +52,7 @@
let next = bx.inbounds_gep(addr, &[full_direct_size]);
bx.store(next, va_list_addr, bx.tcx().data_layout.pointer_align.abi);
- if size.bytes() < slot_size.bytes() && &*bx.tcx().sess.target.endian == "big" {
+ if size.bytes() < slot_size.bytes() && bx.tcx().sess.target.endian == Endian::Big {
let adjusted_size = bx.cx().const_i32((slot_size.bytes() - size.bytes()) as i32);
let adjusted = bx.inbounds_gep(addr, &[adjusted_size]);
(bx.bitcast(adjusted, bx.cx().type_ptr_to(llty)), addr_align)
@@ -105,7 +105,6 @@
let mut end = bx.build_sibling_block("va_arg.end");
let zero = bx.const_i32(0);
let offset_align = Align::from_bytes(4).unwrap();
- assert!(&*bx.tcx().sess.target.endian == "little");
let gr_type = target_ty.is_any_ptr() || target_ty.is_integral();
let (reg_off, reg_top_index, slot_size) = if gr_type {
@@ -144,9 +143,14 @@
let top = in_reg.load(top, bx.tcx().data_layout.pointer_align.abi);
// reg_value = *(@top + reg_off_v);
- let top = in_reg.gep(top, &[reg_off_v]);
- let top = in_reg.bitcast(top, bx.cx.type_ptr_to(layout.llvm_type(bx)));
- let reg_value = in_reg.load(top, layout.align.abi);
+ let mut reg_addr = in_reg.gep(top, &[reg_off_v]);
+ if bx.tcx().sess.target.endian == Endian::Big && layout.size.bytes() != slot_size {
+ // On big-endian systems the value is right-aligned in its slot.
+ let offset = bx.const_i32((slot_size - layout.size.bytes()) as i32);
+ reg_addr = in_reg.gep(reg_addr, &[offset]);
+ }
+ let reg_addr = in_reg.bitcast(reg_addr, bx.cx.type_ptr_to(layout.llvm_type(bx)));
+ let reg_value = in_reg.load(reg_addr, layout.align.abi);
in_reg.br(&end.llbb());
// On Stack block
diff --git a/compiler/rustc_codegen_ssa/Cargo.toml b/compiler/rustc_codegen_ssa/Cargo.toml
index e5df0f6..835f906 100644
--- a/compiler/rustc_codegen_ssa/Cargo.toml
+++ b/compiler/rustc_codegen_ssa/Cargo.toml
@@ -10,6 +10,7 @@
[dependencies]
bitflags = "1.2.1"
cc = "1.0.1"
+itertools = "0.9"
num_cpus = "1.0"
memmap = "0.7"
tracing = "0.1"
diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs
index a3a2ef0..8bc4e64 100644
--- a/compiler/rustc_codegen_ssa/src/back/link.rs
+++ b/compiler/rustc_codegen_ssa/src/back/link.rs
@@ -14,7 +14,7 @@
use rustc_session::{filesearch, Session};
use rustc_span::symbol::Symbol;
use rustc_target::spec::crt_objects::{CrtObjects, CrtObjectsFallback};
-use rustc_target::spec::{LinkOutputKind, LinkerFlavor, LldFlavor};
+use rustc_target::spec::{LinkOutputKind, LinkerFlavor, LldFlavor, SplitDebuginfo};
use rustc_target::spec::{PanicStrategy, RelocModel, RelroLevel, Target};
use super::archive::ArchiveBuilder;
@@ -74,7 +74,7 @@
}
});
- if outputs.outputs.should_codegen() {
+ if outputs.outputs.should_link() {
let tmpdir = TempFileBuilder::new()
.prefix("rustc")
.tempdir()
@@ -99,9 +99,6 @@
path.as_ref(),
target_cpu,
);
- if sess.opts.debugging_opts.split_dwarf == config::SplitDwarfKind::Split {
- link_dwarf_object(sess, &out_filename);
- }
}
}
if sess.opts.json_artifact_notifications {
@@ -123,9 +120,7 @@
}
};
- if sess.opts.output_types.should_codegen()
- && !preserve_objects_for_their_debuginfo(sess)
- {
+ if sess.opts.output_types.should_link() && !preserve_objects_for_their_debuginfo(sess) {
for module in &codegen_results.modules {
remove_temps_from_module(module);
}
@@ -166,7 +161,7 @@
_ => match flavor {
LinkerFlavor::Lld(f) => Command::lld(linker, f),
LinkerFlavor::Msvc if sess.opts.cg.linker.is_none() && sess.target.linker.is_none() => {
- Command::new(msvc_tool.as_ref().map(|t| t.path()).unwrap_or(linker))
+ Command::new(msvc_tool.as_ref().map_or(linker, |t| t.path()))
}
_ => Command::new(linker),
},
@@ -830,29 +825,43 @@
}
}
- // On macOS, debuggers need this utility to get run to do some munging of
- // the symbols. Note, though, that if the object files are being preserved
- // for their debug information there's no need for us to run dsymutil.
- if sess.target.is_like_osx
- && sess.opts.debuginfo != DebugInfo::None
- && !preserve_objects_for_their_debuginfo(sess)
- {
- let prog = Command::new("dsymutil").arg(out_filename).output();
- match prog {
- Ok(prog) => {
- if !prog.status.success() {
- let mut output = prog.stderr.clone();
- output.extend_from_slice(&prog.stdout);
- sess.struct_warn(&format!(
- "processing debug info with `dsymutil` failed: {}",
- prog.status
- ))
- .note(&escape_string(&output))
- .emit();
+ match sess.split_debuginfo() {
+ // If split debug information is disabled or located in individual files
+ // there's nothing to do here.
+ SplitDebuginfo::Off | SplitDebuginfo::Unpacked => {}
+
+ // If packed split-debuginfo is requested, but the final compilation
+ // doesn't actually have any debug information, then we skip this step.
+ SplitDebuginfo::Packed if sess.opts.debuginfo == DebugInfo::None => {}
+
+ // On macOS the external `dsymutil` tool is used to create the packed
+ // debug information. Note that this will read debug information from
+ // the objects on the filesystem which we'll clean up later.
+ SplitDebuginfo::Packed if sess.target.is_like_osx => {
+ let prog = Command::new("dsymutil").arg(out_filename).output();
+ match prog {
+ Ok(prog) => {
+ if !prog.status.success() {
+ let mut output = prog.stderr.clone();
+ output.extend_from_slice(&prog.stdout);
+ sess.struct_warn(&format!(
+ "processing debug info with `dsymutil` failed: {}",
+ prog.status
+ ))
+ .note(&escape_string(&output))
+ .emit();
+ }
}
+ Err(e) => sess.fatal(&format!("unable to run `dsymutil`: {}", e)),
}
- Err(e) => sess.fatal(&format!("unable to run `dsymutil`: {}", e)),
}
+
+ // On MSVC packed debug information is produced by the linker itself so
+ // there's no need to do anything else here.
+ SplitDebuginfo::Packed if sess.target.is_like_msvc => {}
+
+ // ... and otherwise we're processing a `*.dwp` packed dwarf file.
+ SplitDebuginfo::Packed => link_dwarf_object(sess, &out_filename),
}
}
@@ -887,23 +896,37 @@
}
fn link_sanitizer_runtime(sess: &Session, linker: &mut dyn Linker, name: &str) {
- let default_sysroot = filesearch::get_or_default_sysroot();
- let default_tlib =
- filesearch::make_target_lib_path(&default_sysroot, sess.opts.target_triple.triple());
+ fn find_sanitizer_runtime(sess: &Session, filename: &String) -> PathBuf {
+ let session_tlib =
+ filesearch::make_target_lib_path(&sess.sysroot, sess.opts.target_triple.triple());
+ let path = session_tlib.join(&filename);
+ if path.exists() {
+ return session_tlib;
+ } else {
+ let default_sysroot = filesearch::get_or_default_sysroot();
+ let default_tlib = filesearch::make_target_lib_path(
+ &default_sysroot,
+ sess.opts.target_triple.triple(),
+ );
+ return default_tlib;
+ }
+ }
+
let channel = option_env!("CFG_RELEASE_CHANNEL")
.map(|channel| format!("-{}", channel))
.unwrap_or_default();
match sess.opts.target_triple.triple() {
- "x86_64-apple-darwin" => {
+ "aarch64-apple-darwin" | "x86_64-apple-darwin" => {
// On Apple platforms, the sanitizer is always built as a dylib, and
// LLVM will link to `@rpath/*.dylib`, so we need to specify an
// rpath to the library as well (the rpath should be absolute, see
// PR #41352 for details).
- let libname = format!("rustc{}_rt.{}", channel, name);
- let rpath = default_tlib.to_str().expect("non-utf8 component in path");
+ let filename = format!("rustc{}_rt.{}", channel, name);
+ let path = find_sanitizer_runtime(&sess, &filename);
+ let rpath = path.to_str().expect("non-utf8 component in path");
linker.args(&["-Wl,-rpath", "-Xlinker", rpath]);
- linker.link_dylib(Symbol::intern(&libname));
+ linker.link_dylib(Symbol::intern(&filename));
}
"aarch64-fuchsia"
| "aarch64-unknown-linux-gnu"
@@ -911,7 +934,7 @@
| "x86_64-unknown-freebsd"
| "x86_64-unknown-linux-gnu" => {
let filename = format!("librustc{}_rt.{}.a", channel, name);
- let path = default_tlib.join(&filename);
+ let path = find_sanitizer_runtime(&sess, &filename).join(&filename);
linker.link_whole_rlib(&path);
}
_ => {}
@@ -1038,28 +1061,9 @@
return false;
}
- // Single mode keeps debuginfo in the same object file, but in such a way that it it skipped
- // by the linker - so it's expected that when codegen units are linked together that this
- // debuginfo would be lost without keeping around the temps.
- if sess.opts.debugging_opts.split_dwarf == config::SplitDwarfKind::Single {
- return true;
- }
-
- // If we're on OSX then the equivalent of split dwarf is turned on by
- // default. The final executable won't actually have any debug information
- // except it'll have pointers to elsewhere. Historically we've always run
- // `dsymutil` to "link all the dwarf together" but this is actually sort of
- // a bummer for incremental compilation! (the whole point of split dwarf is
- // that you don't do this sort of dwarf link).
- //
- // Basically as a result this just means that if we're on OSX and we're
- // *not* running dsymutil then the object files are the only source of truth
- // for debug information, so we must preserve them.
- if sess.target.is_like_osx {
- return !sess.opts.debugging_opts.run_dsymutil;
- }
-
- false
+ // "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
}
pub fn archive_search_paths(sess: &Session) -> Vec<PathBuf> {
@@ -1276,6 +1280,7 @@
fn link_output_kind(sess: &Session, crate_type: CrateType) -> LinkOutputKind {
let kind = match (crate_type, sess.crt_static(Some(crate_type)), sess.relocation_model()) {
+ (CrateType::Executable, _, _) if sess.is_wasi_reactor() => LinkOutputKind::WasiReactorExe,
(CrateType::Executable, false, RelocModel::Pic) => LinkOutputKind::DynamicPicExe,
(CrateType::Executable, false, _) => LinkOutputKind::DynamicNoPicExe,
(CrateType::Executable, true, RelocModel::Pic) => LinkOutputKind::StaticPicExe,
@@ -2198,8 +2203,13 @@
return;
}
};
- let arch_name = llvm_target.split('-').next().expect("LLVM target must have a hyphen");
- cmd.args(&["-arch", arch_name, "-isysroot", &sdk_root, "-Wl,-syslibroot", &sdk_root]);
+ if llvm_target.contains("macabi") {
+ cmd.args(&["-target", llvm_target])
+ } else {
+ let arch_name = llvm_target.split('-').next().expect("LLVM target must have a hyphen");
+ cmd.args(&["-arch", arch_name])
+ }
+ cmd.args(&["-isysroot", &sdk_root, "-Wl,-syslibroot", &sdk_root]);
}
fn get_apple_sdk_root(sdk_name: &str) -> Result<String, String> {
diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs
index 3df956c..bb35e7e 100644
--- a/compiler/rustc_codegen_ssa/src/back/linker.rs
+++ b/compiler/rustc_codegen_ssa/src/back/linker.rs
@@ -314,6 +314,10 @@
self.cmd.arg("-static");
self.build_dylib(out_filename);
}
+ LinkOutputKind::WasiReactorExe => {
+ self.linker_arg("--entry");
+ self.linker_arg("_initialize");
+ }
}
// VxWorks compiler driver introduced `--static-crt` flag specifically for rustc,
// it switches linking for libc and similar system libraries to static without using
@@ -662,6 +666,9 @@
arg.push(out_filename.with_extension("dll.lib"));
self.cmd.arg(arg);
}
+ LinkOutputKind::WasiReactorExe => {
+ panic!("can't link as reactor on non-wasi target");
+ }
}
}
@@ -1085,6 +1092,10 @@
LinkOutputKind::DynamicDylib | LinkOutputKind::StaticDylib => {
self.cmd.arg("--no-entry");
}
+ LinkOutputKind::WasiReactorExe => {
+ self.cmd.arg("--entry");
+ self.cmd.arg("_initialize");
+ }
}
}
diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs
index c84b879..6aef5cb 100644
--- a/compiler/rustc_codegen_ssa/src/back/write.rs
+++ b/compiler/rustc_codegen_ssa/src/back/write.rs
@@ -282,6 +282,20 @@
pub split_dwarf_file: Option<PathBuf>,
}
+impl TargetMachineFactoryConfig {
+ pub fn new(
+ cgcx: &CodegenContext<impl WriteBackendMethods>,
+ module_name: &str,
+ ) -> TargetMachineFactoryConfig {
+ let split_dwarf_file = if cgcx.target_can_use_split_dwarf {
+ cgcx.output_filenames.split_dwarf_filename(cgcx.split_debuginfo, Some(module_name))
+ } else {
+ None
+ };
+ TargetMachineFactoryConfig { split_dwarf_file }
+ }
+}
+
pub type TargetMachineFactoryFn<B> = Arc<
dyn Fn(TargetMachineFactoryConfig) -> Result<<B as WriteBackendMethods>::TargetMachine, String>
+ Send
@@ -311,10 +325,11 @@
pub tm_factory: TargetMachineFactoryFn<B>,
pub msvc_imps_needed: bool,
pub is_pe_coff: bool,
+ pub target_can_use_split_dwarf: bool,
pub target_pointer_width: u32,
pub target_arch: String,
pub debuginfo: config::DebugInfo,
- pub split_dwarf_kind: config::SplitDwarfKind,
+ pub split_debuginfo: rustc_target::spec::SplitDebuginfo,
// Number of cgus excluding the allocator/metadata modules
pub total_cgus: usize,
@@ -1035,10 +1050,11 @@
total_cgus,
msvc_imps_needed: msvc_imps_needed(tcx),
is_pe_coff: tcx.sess.target.is_like_windows,
+ target_can_use_split_dwarf: tcx.sess.target_can_use_split_dwarf(),
target_pointer_width: tcx.sess.target.pointer_width,
target_arch: tcx.sess.target.arch.clone(),
debuginfo: tcx.sess.opts.debuginfo,
- split_dwarf_kind: tcx.sess.opts.debugging_opts.split_dwarf,
+ split_debuginfo: tcx.sess.split_debuginfo(),
};
// This is the "main loop" of parallel work happening for parallel codegen.
diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs
index 18132a2..658ad3c 100644
--- a/compiler/rustc_codegen_ssa/src/base.rs
+++ b/compiler/rustc_codegen_ssa/src/base.rs
@@ -1,18 +1,3 @@
-//! Codegen the completed AST to the LLVM IR.
-//!
-//! Some functions here, such as `codegen_block` and `codegen_expr`, return a value --
-//! the result of the codegen to LLVM -- while others, such as `codegen_fn`
-//! and `mono_item`, are called only for the side effect of adding a
-//! particular definition to the LLVM IR output we're producing.
-//!
-//! Hopefully useful general knowledge about codegen:
-//!
-//! * There's no way to find out the `Ty` type of a `Value`. Doing so
-//! would be "trying to get the eggs out of an omelette" (credit:
-//! pcwalton). You can, instead, find out its `llvm::Type` by calling `val_ty`,
-//! but one `llvm::Type` corresponds to many `Ty`s; for instance, `tup(int, int,
-//! int)` and `rec(x=int, y=int, z=int)` will have the same `llvm::Type`.
-
use crate::back::write::{
compute_per_cgu_lto_type, start_async_codegen, submit_codegened_module_to_llvm,
submit_post_lto_module_to_llvm, submit_pre_lto_module_to_llvm, ComputedLtoType, OngoingCodegen,
@@ -27,8 +12,8 @@
use rustc_attr as attr;
use rustc_data_structures::fx::FxHashMap;
-use rustc_data_structures::profiling::print_time_passes_entry;
-use rustc_data_structures::sync::{par_iter, Lock, ParallelIterator};
+use rustc_data_structures::profiling::{get_resident_set_size, print_time_passes_entry};
+use rustc_data_structures::sync::{par_iter, ParallelIterator};
use rustc_hir as hir;
use rustc_hir::def_id::{LocalDefId, LOCAL_CRATE};
use rustc_hir::lang_items::LangItem;
@@ -44,15 +29,14 @@
use rustc_middle::ty::{self, Instance, Ty, TyCtxt};
use rustc_session::cgu_reuse_tracker::CguReuse;
use rustc_session::config::{self, EntryFnType};
-use rustc_session::utils::NativeLibKind;
use rustc_session::Session;
-use rustc_symbol_mangling::test as symbol_names_test;
use rustc_target::abi::{Align, LayoutOf, VariantIdx};
-use std::cmp;
use std::ops::{Deref, DerefMut};
use std::time::{Duration, Instant};
+use itertools::Itertools;
+
pub fn bin_op_to_icmp_predicate(op: hir::BinOpKind, signed: bool) -> IntPredicate {
match op {
hir::BinOpKind::Eq => IntPredicate::IntEQ,
@@ -486,8 +470,6 @@
ongoing_codegen.codegen_finished(tcx);
- finalize_tcx(tcx);
-
ongoing_codegen.check_for_errors(tcx.sess);
return ongoing_codegen;
@@ -565,15 +547,24 @@
ongoing_codegen.submit_pre_codegened_module_to_llvm(tcx, metadata_module);
}
- // We sort the codegen units by size. This way we can schedule work for LLVM
- // a bit more efficiently.
- let codegen_units = {
- let mut codegen_units = codegen_units.iter().collect::<Vec<_>>();
- codegen_units.sort_by_cached_key(|cgu| cmp::Reverse(cgu.size_estimate()));
- codegen_units
- };
+ // For better throughput during parallel processing by LLVM, we used to sort
+ // CGUs largest to smallest. This would lead to better thread utilization
+ // by, for example, preventing a large CGU from being processed last and
+ // having only one LLVM thread working while the rest remained idle.
+ //
+ // However, this strategy would lead to high memory usage, as it meant the
+ // LLVM-IR for all of the largest CGUs would be resident in memory at once.
+ //
+ // Instead, we can compromise by ordering CGUs such that the largest and
+ // smallest are first, second largest and smallest are next, etc. If there
+ // are large size variations, this can reduce memory usage significantly.
+ let codegen_units: Vec<_> = {
+ let mut sorted_cgus = codegen_units.iter().collect::<Vec<_>>();
+ sorted_cgus.sort_by_cached_key(|cgu| cgu.size_estimate());
- let total_codegen_time = Lock::new(Duration::new(0, 0));
+ let (first_half, second_half) = sorted_cgus.split_at(sorted_cgus.len() / 2);
+ second_half.iter().rev().interleave(first_half).copied().collect()
+ };
// The non-parallel compiler can only translate codegen units to LLVM IR
// on a single thread, leading to a staircase effect where the N LLVM
@@ -597,23 +588,26 @@
.collect();
// Compile the found CGUs in parallel.
- par_iter(cgus)
+ let start_time = Instant::now();
+
+ let pre_compiled_cgus = par_iter(cgus)
.map(|(i, _)| {
- let start_time = Instant::now();
let module = backend.compile_codegen_unit(tcx, codegen_units[i].name());
- let mut time = total_codegen_time.lock();
- *time += start_time.elapsed();
(i, module)
})
- .collect()
+ .collect();
+
+ (pre_compiled_cgus, start_time.elapsed())
})
} else {
- FxHashMap::default()
+ (FxHashMap::default(), Duration::new(0, 0))
}
};
let mut cgu_reuse = Vec::new();
let mut pre_compiled_cgus: Option<FxHashMap<usize, _>> = None;
+ let mut total_codegen_time = Duration::new(0, 0);
+ let start_rss = tcx.sess.time_passes().then(|| get_resident_set_size());
for (i, cgu) in codegen_units.iter().enumerate() {
ongoing_codegen.wait_for_signal_to_codegen_item();
@@ -626,7 +620,9 @@
codegen_units.iter().map(|cgu| determine_cgu_reuse(tcx, &cgu)).collect()
});
// Pre compile some CGUs
- pre_compiled_cgus = Some(pre_compile_cgus(&cgu_reuse));
+ let (compiled_cgus, codegen_time) = pre_compile_cgus(&cgu_reuse);
+ pre_compiled_cgus = Some(compiled_cgus);
+ total_codegen_time += codegen_time;
}
let cgu_reuse = cgu_reuse[i];
@@ -640,10 +636,14 @@
} else {
let start_time = Instant::now();
let module = backend.compile_codegen_unit(tcx, cgu.name());
- let mut time = total_codegen_time.lock();
- *time += start_time.elapsed();
+ total_codegen_time += start_time.elapsed();
module
};
+ // This will unwind if there are errors, which triggers our `AbortCodegenOnDrop`
+ // guard. Unfortunately, just skipping the `submit_codegened_module_to_llvm` makes
+ // compilation hang on post-monomorphization errors.
+ tcx.sess.abort_if_errors();
+
submit_codegened_module_to_llvm(
&backend,
&ongoing_codegen.coordinator_send,
@@ -682,20 +682,19 @@
// Since the main thread is sometimes blocked during codegen, we keep track
// -Ztime-passes output manually.
- print_time_passes_entry(
- tcx.sess.time_passes(),
- "codegen_to_LLVM_IR",
- total_codegen_time.into_inner(),
- );
+ if tcx.sess.time_passes() {
+ let end_rss = get_resident_set_size();
- rustc_incremental::assert_module_sources::assert_module_sources(tcx);
-
- symbol_names_test::report_symbol_names(tcx);
+ print_time_passes_entry(
+ "codegen_to_LLVM_IR",
+ total_codegen_time,
+ start_rss.unwrap(),
+ end_rss,
+ );
+ }
ongoing_codegen.check_for_errors(tcx.sess);
- finalize_tcx(tcx);
-
ongoing_codegen.into_inner()
}
@@ -746,18 +745,6 @@
}
}
-fn finalize_tcx(tcx: TyCtxt<'_>) {
- tcx.sess.time("assert_dep_graph", || rustc_incremental::assert_dep_graph(tcx));
- tcx.sess.time("serialize_dep_graph", || rustc_incremental::save_dep_graph(tcx));
-
- // We assume that no queries are run past here. If there are new queries
- // after this point, they'll show up as "<unknown>" in self-profiling data.
- {
- let _prof_timer = tcx.prof.generic_activity("self_profile_alloc_query_strings");
- tcx.alloc_self_profile_query_strings();
- }
-}
-
impl CrateInfo {
pub fn new(tcx: TyCtxt<'_>) -> CrateInfo {
let mut info = CrateInfo {
@@ -820,7 +807,7 @@
}
}
-pub fn provide_both(providers: &mut Providers) {
+pub fn provide(providers: &mut Providers) {
providers.backend_optimization_level = |tcx, cratenum| {
let for_speed = match tcx.sess.opts.optimize {
// If globally no optimisation is done, #[optimize] has no effect.
@@ -853,32 +840,6 @@
}
tcx.sess.opts.optimize
};
-
- providers.dllimport_foreign_items = |tcx, krate| {
- let module_map = tcx.foreign_modules(krate);
-
- let dllimports = tcx
- .native_libraries(krate)
- .iter()
- .filter(|lib| {
- if !matches!(lib.kind, NativeLibKind::Dylib | NativeLibKind::Unspecified) {
- return false;
- }
- let cfg = match lib.cfg {
- Some(ref cfg) => cfg,
- None => return true,
- };
- attr::cfg_matches(cfg, &tcx.sess.parse_sess, None)
- })
- .filter_map(|lib| lib.foreign_module)
- .map(|id| &module_map[&id])
- .flat_map(|module| module.foreign_items.iter().cloned())
- .collect();
- dllimports
- };
-
- providers.is_dllimport_foreign_item =
- |tcx, def_id| tcx.dllimport_foreign_items(def_id.krate).contains(&def_id);
}
fn determine_cgu_reuse<'tcx>(tcx: TyCtxt<'tcx>, cgu: &CodegenUnit<'tcx>) -> CguReuse {
diff --git a/compiler/rustc_codegen_ssa/src/coverageinfo/map.rs b/compiler/rustc_codegen_ssa/src/coverageinfo/map.rs
index b0d7953..549b8d4 100644
--- a/compiler/rustc_codegen_ssa/src/coverageinfo/map.rs
+++ b/compiler/rustc_codegen_ssa/src/coverageinfo/map.rs
@@ -170,30 +170,30 @@
// `expression_index`s lower than the referencing `Expression`. Therefore, it is
// reasonable to look up the new index of an expression operand while the `new_indexes`
// vector is only complete up to the current `ExpressionIndex`.
- let id_to_counter =
- |new_indexes: &IndexVec<InjectedExpressionIndex, Option<MappedExpressionIndex>>,
- id: ExpressionOperandId| {
- if id == ExpressionOperandId::ZERO {
- Some(Counter::zero())
- } else if id.index() < self.counters.len() {
- // Note: Some codegen-injected Counters may be only referenced by `Expression`s,
- // and may not have their own `CodeRegion`s,
- let index = CounterValueReference::from(id.index());
- Some(Counter::counter_value_reference(index))
- } else {
- let index = self.expression_index(u32::from(id));
- self.expressions
- .get(index)
- .expect("expression id is out of range")
- .as_ref()
- // If an expression was optimized out, assume it would have produced a count
- // of zero. This ensures that expressions dependent on optimized-out
- // expressions are still valid.
- .map_or(Some(Counter::zero()), |_| {
- new_indexes[index].map(|new_index| Counter::expression(new_index))
- })
- }
- };
+ let id_to_counter = |new_indexes: &IndexVec<
+ InjectedExpressionIndex,
+ Option<MappedExpressionIndex>,
+ >,
+ id: ExpressionOperandId| {
+ if id == ExpressionOperandId::ZERO {
+ Some(Counter::zero())
+ } else if id.index() < self.counters.len() {
+ // Note: Some codegen-injected Counters may be only referenced by `Expression`s,
+ // and may not have their own `CodeRegion`s,
+ let index = CounterValueReference::from(id.index());
+ Some(Counter::counter_value_reference(index))
+ } else {
+ let index = self.expression_index(u32::from(id));
+ self.expressions
+ .get(index)
+ .expect("expression id is out of range")
+ .as_ref()
+ // If an expression was optimized out, assume it would have produced a count
+ // of zero. This ensures that expressions dependent on optimized-out
+ // expressions are still valid.
+ .map_or(Some(Counter::zero()), |_| new_indexes[index].map(Counter::expression))
+ }
+ };
for (original_index, expression) in
self.expressions.iter_enumerated().filter_map(|(original_index, entry)| {
diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs
index bc93bd8..0307117 100644
--- a/compiler/rustc_codegen_ssa/src/lib.rs
+++ b/compiler/rustc_codegen_ssa/src/lib.rs
@@ -116,7 +116,7 @@
impl From<&cstore::NativeLib> for NativeLib {
fn from(lib: &cstore::NativeLib) -> Self {
- NativeLib { kind: lib.kind.clone(), name: lib.name.clone(), cfg: lib.cfg.clone() }
+ NativeLib { kind: lib.kind, name: lib.name, cfg: lib.cfg.clone() }
}
}
@@ -160,13 +160,12 @@
pub fn provide(providers: &mut Providers) {
crate::back::symbol_export::provide(providers);
- crate::base::provide_both(providers);
+ crate::base::provide(providers);
crate::target_features::provide(providers);
}
pub fn provide_extern(providers: &mut Providers) {
crate::back::symbol_export::provide_extern(providers);
- crate::base::provide_both(providers);
}
/// Checks if the given filename ends with the `.rcgu.o` extension that `rustc`
diff --git a/compiler/rustc_codegen_ssa/src/mir/analyze.rs b/compiler/rustc_codegen_ssa/src/mir/analyze.rs
index 44bb0de..fd0ff5b 100644
--- a/compiler/rustc_codegen_ssa/src/mir/analyze.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/analyze.rs
@@ -104,7 +104,7 @@
) {
let cx = self.fx.cx;
- if let &[ref proj_base @ .., elem] = place_ref.projection {
+ if let Some((place_base, elem)) = place_ref.last_projection() {
let mut base_context = if context.is_mutating_use() {
PlaceContext::MutatingUse(MutatingUseContext::Projection)
} else {
@@ -112,15 +112,14 @@
};
// Allow uses of projections that are ZSTs or from scalar fields.
- let is_consume = match context {
+ let is_consume = matches!(
+ context,
PlaceContext::NonMutatingUse(
NonMutatingUseContext::Copy | NonMutatingUseContext::Move,
- ) => true,
- _ => false,
- };
+ )
+ );
if is_consume {
- let base_ty =
- mir::Place::ty_from(place_ref.local, proj_base, self.fx.mir, cx.tcx());
+ let base_ty = place_base.ty(self.fx.mir, cx.tcx());
let base_ty = self.fx.monomorphize(base_ty);
// ZSTs don't require any actual memory access.
@@ -175,11 +174,7 @@
base_context = context;
}
- self.process_place(
- &mir::PlaceRef { local: place_ref.local, projection: proj_base },
- base_context,
- location,
- );
+ self.process_place(&place_base, base_context, location);
// HACK(eddyb) this emulates the old `visit_projection_elem`, this
// entire `visit_place`-like `process_place` method should be rewritten,
// now that we have moved to the "slice of projections" representation.
diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs
index ce56f16..c821908 100644
--- a/compiler/rustc_codegen_ssa/src/mir/block.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/block.rs
@@ -522,7 +522,7 @@
mut bx: Bx,
terminator: &mir::Terminator<'tcx>,
func: &mir::Operand<'tcx>,
- args: &Vec<mir::Operand<'tcx>>,
+ args: &[mir::Operand<'tcx>],
destination: &Option<(mir::Place<'tcx>, mir::BasicBlock)>,
cleanup: Option<mir::BasicBlock>,
fn_span: Span,
@@ -875,20 +875,16 @@
ty::Uint(_) => value.to_string(),
ty::Int(int_ty) => {
match int_ty.normalize(bx.tcx().sess.target.pointer_width) {
- ast::IntTy::I8 => (value as i8).to_string(),
- ast::IntTy::I16 => (value as i16).to_string(),
- ast::IntTy::I32 => (value as i32).to_string(),
- ast::IntTy::I64 => (value as i64).to_string(),
- ast::IntTy::I128 => (value as i128).to_string(),
- ast::IntTy::Isize => unreachable!(),
+ ty::IntTy::I8 => (value as i8).to_string(),
+ ty::IntTy::I16 => (value as i16).to_string(),
+ ty::IntTy::I32 => (value as i32).to_string(),
+ ty::IntTy::I64 => (value as i64).to_string(),
+ ty::IntTy::I128 => (value as i128).to_string(),
+ ty::IntTy::Isize => unreachable!(),
}
}
- ty::Float(ast::FloatTy::F32) => {
- f32::from_bits(value as u32).to_string()
- }
- ty::Float(ast::FloatTy::F64) => {
- f64::from_bits(value as u64).to_string()
- }
+ ty::Float(ty::FloatTy::F32) => f32::from_bits(value as u32).to_string(),
+ ty::Float(ty::FloatTy::F64) => f64::from_bits(value as u64).to_string(),
_ => span_bug!(span, "asm const has bad type {}", ty),
};
InlineAsmOperandRef::Const { string }
diff --git a/compiler/rustc_codegen_ssa/src/mir/constant.rs b/compiler/rustc_codegen_ssa/src/mir/constant.rs
index 3a85c26..b79a221 100644
--- a/compiler/rustc_codegen_ssa/src/mir/constant.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/constant.rs
@@ -30,12 +30,7 @@
.tcx()
.const_eval_resolve(ty::ParamEnv::reveal_all(), def, substs, promoted, None)
.map_err(|err| {
- if promoted.is_none() {
- self.cx
- .tcx()
- .sess
- .span_err(constant.span, "erroneous constant encountered");
- }
+ self.cx.tcx().sess.span_err(constant.span, "erroneous constant encountered");
err
}),
ty::ConstKind::Value(value) => Ok(value),
diff --git a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs
index d5b2cba..f1eae60 100644
--- a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs
@@ -170,7 +170,7 @@
// (after #67586 gets fixed).
None
} else {
- let name = kw::Invalid;
+ let name = kw::Empty;
let decl = &self.mir.local_decls[local];
let dbg_var = if full_debug_info {
self.adjusted_span_and_dbg_scope(decl.source_info).map(
@@ -204,7 +204,7 @@
None
} else {
Some(match whole_local_var.or(fallback_var) {
- Some(var) if var.name != kw::Invalid => var.name.to_string(),
+ Some(var) if var.name != kw::Empty => var.name.to_string(),
_ => format!("{:?}", local),
})
};
diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs
index 2851400..d31ecec 100644
--- a/compiler/rustc_codegen_ssa/src/mir/mod.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs
@@ -188,8 +188,11 @@
fx.per_local_var_debug_info = fx.compute_per_local_var_debug_info(&mut bx);
+ // Evaluate all required consts; codegen later assumes that CTFE will never fail.
+ let mut all_consts_ok = true;
for const_ in &mir.required_consts {
if let Err(err) = fx.eval_mir_constant(const_) {
+ all_consts_ok = false;
match err {
// errored or at least linted
ErrorHandled::Reported(ErrorReported) | ErrorHandled::Linted => {}
@@ -199,6 +202,11 @@
}
}
}
+ if !all_consts_ok {
+ // We leave the IR in some half-built state here, and rely on this code not even being
+ // submitted to LLVM once an error was raised.
+ return;
+ }
let memory_locals = analyze::non_ssa_locals(&fx);
diff --git a/compiler/rustc_codegen_ssa/src/mir/operand.rs b/compiler/rustc_codegen_ssa/src/mir/operand.rs
index 08a4ae3..25e84c3 100644
--- a/compiler/rustc_codegen_ssa/src/mir/operand.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/operand.rs
@@ -6,9 +6,8 @@
use crate::traits::*;
use crate::MemFlags;
-use rustc_errors::ErrorReported;
use rustc_middle::mir;
-use rustc_middle::mir::interpret::{ConstValue, ErrorHandled, Pointer, Scalar};
+use rustc_middle::mir::interpret::{ConstValue, Pointer, Scalar};
use rustc_middle::ty::layout::TyAndLayout;
use rustc_middle::ty::Ty;
use rustc_target::abi::{Abi, Align, LayoutOf, Size};
@@ -439,25 +438,9 @@
}
mir::Operand::Constant(ref constant) => {
- self.eval_mir_constant_to_operand(bx, constant).unwrap_or_else(|err| {
- match err {
- // errored or at least linted
- ErrorHandled::Reported(ErrorReported) | ErrorHandled::Linted => {}
- ErrorHandled::TooGeneric => {
- bug!("codegen encountered polymorphic constant")
- }
- }
- // Allow RalfJ to sleep soundly knowing that even refactorings that remove
- // the above error (or silence it under some conditions) will not cause UB.
- bx.abort();
- // We still have to return an operand but it doesn't matter,
- // this code is unreachable.
- let ty = self.monomorphize(constant.literal.ty);
- let layout = bx.cx().layout_of(ty);
- bx.load_operand(PlaceRef::new_sized(
- bx.cx().const_undef(bx.cx().type_ptr_to(bx.cx().backend_type(layout))),
- layout,
- ))
+ // This cannot fail because we checked all required_consts in advance.
+ self.eval_mir_constant_to_operand(bx, constant).unwrap_or_else(|_err| {
+ span_bug!(constant.span, "erroneous constant not captured by required_consts")
})
}
}
diff --git a/compiler/rustc_codegen_ssa/src/mir/place.rs b/compiler/rustc_codegen_ssa/src/mir/place.rs
index e4f4c88..66d9d1a 100644
--- a/compiler/rustc_codegen_ssa/src/mir/place.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/place.rs
@@ -178,16 +178,8 @@
// Get the alignment of the field
let (_, unsized_align) = glue::size_and_align_of_dst(bx, field.ty, meta);
- // Bump the unaligned offset up to the appropriate alignment using the
- // following expression:
- //
- // (unaligned offset + (align - 1)) & -align
-
- // Calculate offset.
- let align_sub_1 = bx.sub(unsized_align, bx.cx().const_usize(1u64));
- let and_lhs = bx.add(unaligned_offset, align_sub_1);
- let and_rhs = bx.neg(unsized_align);
- let offset = bx.and(and_lhs, and_rhs);
+ // Bump the unaligned offset up to the appropriate alignment
+ let offset = round_up_const_value_to_alignment(bx, unaligned_offset, unsized_align);
debug!("struct_field_ptr: DST field offset: {:?}", offset);
@@ -514,7 +506,49 @@
pub fn monomorphized_place_ty(&self, place_ref: mir::PlaceRef<'tcx>) -> Ty<'tcx> {
let tcx = self.cx.tcx();
- let place_ty = mir::Place::ty_from(place_ref.local, place_ref.projection, self.mir, tcx);
+ let place_ty = place_ref.ty(self.mir, tcx);
self.monomorphize(place_ty.ty)
}
}
+
+fn round_up_const_value_to_alignment<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
+ bx: &mut Bx,
+ value: Bx::Value,
+ align: Bx::Value,
+) -> Bx::Value {
+ // In pseudo code:
+ //
+ // if value & (align - 1) == 0 {
+ // value
+ // } else {
+ // (value & !(align - 1)) + align
+ // }
+ //
+ // Usually this is written without branches as
+ //
+ // (value + align - 1) & !(align - 1)
+ //
+ // But this formula cannot take advantage of constant `value`. E.g. if `value` is known
+ // at compile time to be `1`, this expression should be optimized to `align`. However,
+ // optimization only holds if `align` is a power of two. Since the optimizer doesn't know
+ // that `align` is a power of two, it cannot perform this optimization.
+ //
+ // Instead we use
+ //
+ // value + (-value & (align - 1))
+ //
+ // Since `align` is used only once, the expression can be optimized. For `value = 0`
+ // its optimized to `0` even in debug mode.
+ //
+ // NB: The previous version of this code used
+ //
+ // (value + align - 1) & -align
+ //
+ // Even though `-align == !(align - 1)`, LLVM failed to optimize this even for
+ // `value = 0`. Bug report: https://bugs.llvm.org/show_bug.cgi?id=48559
+ let one = bx.const_usize(1);
+ let align_minus_1 = bx.sub(align, one);
+ let neg_value = bx.neg(value);
+ let offset = bx.and(neg_value, align_minus_1);
+ bx.add(value, offset)
+}
diff --git a/compiler/rustc_data_structures/src/fingerprint.rs b/compiler/rustc_data_structures/src/fingerprint.rs
index 01efcaf..08c3419 100644
--- a/compiler/rustc_data_structures/src/fingerprint.rs
+++ b/compiler/rustc_data_structures/src/fingerprint.rs
@@ -1,10 +1,10 @@
use crate::stable_hasher;
use rustc_serialize::{
- opaque::{self, EncodeResult},
+ opaque::{self, EncodeResult, FileEncodeResult},
Decodable, Encodable,
};
use std::hash::{Hash, Hasher};
-use std::mem;
+use std::mem::{self, MaybeUninit};
#[derive(Eq, PartialEq, Ord, PartialOrd, Debug, Clone, Copy)]
pub struct Fingerprint(u64, u64);
@@ -53,15 +53,8 @@
format!("{:x}{:x}", self.0, self.1)
}
- pub fn encode_opaque(&self, encoder: &mut opaque::Encoder) -> EncodeResult {
- let bytes: [u8; 16] = unsafe { mem::transmute([self.0.to_le(), self.1.to_le()]) };
-
- encoder.emit_raw_bytes(&bytes);
- Ok(())
- }
-
pub fn decode_opaque(decoder: &mut opaque::Decoder<'_>) -> Result<Fingerprint, String> {
- let mut bytes = [0; 16];
+ let mut bytes: [MaybeUninit<u8>; 16] = MaybeUninit::uninit_array();
decoder.read_raw_bytes(&mut bytes)?;
@@ -142,7 +135,16 @@
impl FingerprintEncoder for opaque::Encoder {
fn encode_fingerprint(&mut self, f: &Fingerprint) -> EncodeResult {
- f.encode_opaque(self)
+ let bytes: [u8; 16] = unsafe { mem::transmute([f.0.to_le(), f.1.to_le()]) };
+ self.emit_raw_bytes(&bytes);
+ Ok(())
+ }
+}
+
+impl FingerprintEncoder for opaque::FileEncoder {
+ fn encode_fingerprint(&mut self, f: &Fingerprint) -> FileEncodeResult {
+ let bytes: [u8; 16] = unsafe { mem::transmute([f.0.to_le(), f.1.to_le()]) };
+ self.emit_raw_bytes(&bytes)
}
}
@@ -198,7 +200,7 @@
impl<D: rustc_serialize::Decoder> Decodable<D> for PackedFingerprint {
#[inline]
fn decode(d: &mut D) -> Result<Self, D::Error> {
- Fingerprint::decode(d).map(|f| PackedFingerprint(f))
+ Fingerprint::decode(d).map(PackedFingerprint)
}
}
diff --git a/compiler/rustc_data_structures/src/graph/dominators/mod.rs b/compiler/rustc_data_structures/src/graph/dominators/mod.rs
index 1cfbce2..ad62e3c 100644
--- a/compiler/rustc_data_structures/src/graph/dominators/mod.rs
+++ b/compiler/rustc_data_structures/src/graph/dominators/mod.rs
@@ -8,7 +8,6 @@
use super::iterate::reverse_post_order;
use super::ControlFlowGraph;
use rustc_index::vec::{Idx, IndexVec};
-use std::borrow::BorrowMut;
use std::cmp::Ordering;
#[cfg(test)]
@@ -20,22 +19,17 @@
dominators_given_rpo(graph, &rpo)
}
-fn dominators_given_rpo<G: ControlFlowGraph + BorrowMut<G>>(
- mut graph: G,
- rpo: &[G::Node],
-) -> Dominators<G::Node> {
- let start_node = graph.borrow().start_node();
+fn dominators_given_rpo<G: ControlFlowGraph>(graph: G, rpo: &[G::Node]) -> Dominators<G::Node> {
+ let start_node = graph.start_node();
assert_eq!(rpo[0], start_node);
// compute the post order index (rank) for each node
- let mut post_order_rank: IndexVec<G::Node, usize> =
- (0..graph.borrow().num_nodes()).map(|_| 0).collect();
+ let mut post_order_rank = IndexVec::from_elem_n(0, graph.num_nodes());
for (index, node) in rpo.iter().rev().cloned().enumerate() {
post_order_rank[node] = index;
}
- let mut immediate_dominators: IndexVec<G::Node, Option<G::Node>> =
- (0..graph.borrow().num_nodes()).map(|_| None).collect();
+ let mut immediate_dominators = IndexVec::from_elem_n(None, graph.num_nodes());
immediate_dominators[start_node] = Some(start_node);
let mut changed = true;
@@ -44,7 +38,7 @@
for &node in &rpo[1..] {
let mut new_idom = None;
- for pred in graph.borrow_mut().predecessors(node) {
+ for pred in graph.predecessors(node) {
if immediate_dominators[pred].is_some() {
// (*) dominators for `pred` have been calculated
new_idom = Some(if let Some(new_idom) = new_idom {
diff --git a/compiler/rustc_data_structures/src/graph/scc/mod.rs b/compiler/rustc_data_structures/src/graph/scc/mod.rs
index 5b3d823..e2cbb09 100644
--- a/compiler/rustc_data_structures/src/graph/scc/mod.rs
+++ b/compiler/rustc_data_structures/src/graph/scc/mod.rs
@@ -523,7 +523,7 @@
successors_len: 0,
min_depth: depth,
min_cycle_root: successor_node,
- successor_node: successor_node,
+ successor_node,
});
continue 'recurse;
}
diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs
index d903a55..5880bbd 100644
--- a/compiler/rustc_data_structures/src/lib.rs
+++ b/compiler/rustc_data_structures/src/lib.rs
@@ -15,8 +15,7 @@
#![feature(fn_traits)]
#![feature(int_bits_const)]
#![feature(min_specialization)]
-#![cfg_attr(bootstrap, feature(optin_builtin_traits))]
-#![cfg_attr(not(bootstrap), feature(auto_traits))]
+#![feature(auto_traits)]
#![feature(nll)]
#![feature(allow_internal_unstable)]
#![feature(hash_raw_entry)]
@@ -27,7 +26,7 @@
#![feature(thread_id_value)]
#![feature(extend_one)]
#![feature(const_panic)]
-#![feature(min_const_generics)]
+#![cfg_attr(bootstrap, feature(min_const_generics))]
#![feature(new_uninit)]
#![feature(once_cell)]
#![feature(maybe_uninit_uninit_array)]
diff --git a/compiler/rustc_data_structures/src/profiling.rs b/compiler/rustc_data_structures/src/profiling.rs
index 5d13b7f..f0b413c 100644
--- a/compiler/rustc_data_structures/src/profiling.rs
+++ b/compiler/rustc_data_structures/src/profiling.rs
@@ -166,7 +166,7 @@
// If there is no SelfProfiler then the filter mask is set to NONE,
// ensuring that nothing ever tries to actually access it.
let event_filter_mask =
- profiler.as_ref().map(|p| p.event_filter_mask).unwrap_or(EventFilter::empty());
+ profiler.as_ref().map_or(EventFilter::empty(), |p| p.event_filter_mask);
SelfProfilerRef {
profiler,
@@ -555,13 +555,16 @@
#[must_use]
pub struct VerboseTimingGuard<'a> {
- start_and_message: Option<(Instant, String)>,
+ start_and_message: Option<(Instant, Option<usize>, String)>,
_guard: TimingGuard<'a>,
}
impl<'a> VerboseTimingGuard<'a> {
pub fn start(message: Option<String>, _guard: TimingGuard<'a>) -> Self {
- VerboseTimingGuard { _guard, start_and_message: message.map(|msg| (Instant::now(), msg)) }
+ VerboseTimingGuard {
+ _guard,
+ start_and_message: message.map(|msg| (Instant::now(), get_resident_set_size(), msg)),
+ }
}
#[inline(always)]
@@ -573,25 +576,39 @@
impl Drop for VerboseTimingGuard<'_> {
fn drop(&mut self) {
- if let Some((start, ref message)) = self.start_and_message {
- print_time_passes_entry(true, &message[..], start.elapsed());
+ if let Some((start_time, start_rss, ref message)) = self.start_and_message {
+ let end_rss = get_resident_set_size();
+ print_time_passes_entry(&message[..], start_time.elapsed(), start_rss, end_rss);
}
}
}
-pub fn print_time_passes_entry(do_it: bool, what: &str, dur: Duration) {
- if !do_it {
- return;
- }
+pub fn print_time_passes_entry(
+ what: &str,
+ dur: Duration,
+ start_rss: Option<usize>,
+ end_rss: Option<usize>,
+) {
+ let rss_to_mb = |rss| (rss as f64 / 1_000_000.0).round() as usize;
+ let rss_change_to_mb = |rss| (rss as f64 / 1_000_000.0).round() as i128;
- let mem_string = match get_resident() {
- Some(n) => {
- let mb = n as f64 / 1_000_000.0;
- format!("; rss: {}MB", mb.round() as usize)
+ let mem_string = match (start_rss, end_rss) {
+ (Some(start_rss), Some(end_rss)) => {
+ let change_rss = end_rss as i128 - start_rss as i128;
+
+ format!(
+ "; rss: {:>4}MB -> {:>4}MB ({:>+5}MB)",
+ rss_to_mb(start_rss),
+ rss_to_mb(end_rss),
+ rss_change_to_mb(change_rss),
+ )
}
- None => String::new(),
+ (Some(start_rss), None) => format!("; rss start: {:>4}MB", rss_to_mb(start_rss)),
+ (None, Some(end_rss)) => format!("; rss end: {:>4}MB", rss_to_mb(end_rss)),
+ (None, None) => String::new(),
};
- println!("time: {}{}\t{}", duration_to_secs_str(dur), mem_string, what);
+
+ println!("time: {:>7}{}\t{}", duration_to_secs_str(dur), mem_string, what);
}
// Hack up our own formatting for the duration to make it easier for scripts
@@ -603,7 +620,7 @@
// Memory reporting
cfg_if! {
if #[cfg(windows)] {
- fn get_resident() -> Option<usize> {
+ pub fn get_resident_set_size() -> Option<usize> {
use std::mem::{self, MaybeUninit};
use winapi::shared::minwindef::DWORD;
use winapi::um::processthreadsapi::GetCurrentProcess;
@@ -621,7 +638,7 @@
}
}
} else if #[cfg(unix)] {
- fn get_resident() -> Option<usize> {
+ pub fn get_resident_set_size() -> Option<usize> {
let field = 1;
let contents = fs::read("/proc/self/statm").ok()?;
let contents = String::from_utf8(contents).ok()?;
@@ -630,7 +647,7 @@
Some(npages * 4096)
}
} else {
- fn get_resident() -> Option<usize> {
+ pub fn get_resident_set_size() -> Option<usize> {
None
}
}
diff --git a/compiler/rustc_data_structures/src/stable_hasher.rs b/compiler/rustc_data_structures/src/stable_hasher.rs
index 579eb1c..3850c9b 100644
--- a/compiler/rustc_data_structures/src/stable_hasher.rs
+++ b/compiler/rustc_data_structures/src/stable_hasher.rs
@@ -552,6 +552,7 @@
/// A vector container that makes sure that its items are hashed in a stable
/// order.
+#[derive(Debug)]
pub struct StableVec<T>(Vec<T>);
impl<T> StableVec<T> {
diff --git a/compiler/rustc_data_structures/src/steal.rs b/compiler/rustc_data_structures/src/steal.rs
index e532a84..30f659c 100644
--- a/compiler/rustc_data_structures/src/steal.rs
+++ b/compiler/rustc_data_structures/src/steal.rs
@@ -21,6 +21,7 @@
/// -- once the value is stolen -- it will never be read from again.
//
// FIXME(#41710): what is the best way to model linear queries?
+#[derive(Debug)]
pub struct Steal<T> {
value: RwLock<Option<T>>,
}
@@ -30,6 +31,7 @@
Steal { value: RwLock::new(Some(value)) }
}
+ #[track_caller]
pub fn borrow(&self) -> MappedReadGuard<'_, T> {
ReadGuard::map(self.value.borrow(), |opt| match *opt {
None => panic!("attempted to read from stolen value"),
@@ -37,10 +39,11 @@
})
}
+ #[track_caller]
pub fn steal(&self) -> T {
let value_ref = &mut *self.value.try_write().expect("stealing value which is locked");
let value = value_ref.take();
- value.expect("attempt to read from stolen value")
+ value.expect("attempt to steal from stolen value")
}
}
diff --git a/compiler/rustc_driver/Cargo.toml b/compiler/rustc_driver/Cargo.toml
index 0adc006..b88b556 100644
--- a/compiler/rustc_driver/Cargo.toml
+++ b/compiler/rustc_driver/Cargo.toml
@@ -9,6 +9,7 @@
[dependencies]
libc = "0.2"
+atty = "0.2"
tracing = { version = "0.1.18" }
tracing-subscriber = { version = "0.2.13", default-features = false, features = ["fmt", "env-filter", "smallvec", "parking_lot", "ansi"] }
tracing-tree = "0.1.6"
diff --git a/compiler/rustc_driver/src/lib.rs b/compiler/rustc_driver/src/lib.rs
index b3466f4..8295e88 100644
--- a/compiler/rustc_driver/src/lib.rs
+++ b/compiler/rustc_driver/src/lib.rs
@@ -16,7 +16,7 @@
use rustc_ast as ast;
use rustc_codegen_ssa::{traits::CodegenBackend, CodegenResults};
-use rustc_data_structures::profiling::print_time_passes_entry;
+use rustc_data_structures::profiling::{get_resident_set_size, print_time_passes_entry};
use rustc_data_structures::sync::SeqCst;
use rustc_errors::registry::{InvalidErrorCode, Registry};
use rustc_errors::{ErrorReported, PResult};
@@ -546,24 +546,12 @@
#[derive(Copy, Clone)]
pub struct RustcDefaultCalls;
-// FIXME remove these and use winapi 0.3 instead
-// Duplicates: bootstrap/compile.rs, librustc_errors/emitter.rs
-#[cfg(unix)]
fn stdout_isatty() -> bool {
- unsafe { libc::isatty(libc::STDOUT_FILENO) != 0 }
+ atty::is(atty::Stream::Stdout)
}
-#[cfg(windows)]
-fn stdout_isatty() -> bool {
- use winapi::um::consoleapi::GetConsoleMode;
- use winapi::um::processenv::GetStdHandle;
- use winapi::um::winbase::STD_OUTPUT_HANDLE;
-
- unsafe {
- let handle = GetStdHandle(STD_OUTPUT_HANDLE);
- let mut out = 0;
- GetConsoleMode(handle, &mut out) != 0
- }
+fn stderr_isatty() -> bool {
+ atty::is(atty::Stream::Stderr)
}
fn handle_explain(registry: Registry, code: &str, output: ErrorOutputType) {
@@ -603,7 +591,7 @@
}
}
-fn show_content_with_pager(content: &String) {
+fn show_content_with_pager(content: &str) {
let pager_name = env::var_os("PAGER").unwrap_or_else(|| {
if cfg!(windows) { OsString::from("more.com") } else { OsString::from("less") }
});
@@ -810,7 +798,7 @@
println!("commit-date: {}", unw(util::commit_date_str()));
println!("host: {}", config::host_triple());
println!("release: {}", unw(util::release_str()));
- if cfg!(llvm) {
+ if cfg!(feature = "llvm") {
get_builtin_codegen_backend("llvm")().print_version();
}
}
@@ -1099,7 +1087,7 @@
}
if cg_flags.iter().any(|x| *x == "passes=list") {
- if cfg!(llvm) {
+ if cfg!(feature = "llvm") {
get_builtin_codegen_backend("llvm")().print_passes();
}
return None;
@@ -1248,7 +1236,7 @@
}
// If backtraces are enabled, also print the query stack
- let backtrace = env::var_os("RUST_BACKTRACE").map(|x| &x != "0").unwrap_or(false);
+ let backtrace = env::var_os("RUST_BACKTRACE").map_or(false, |x| &x != "0");
let num_frames = if backtrace { None } else { Some(2) };
@@ -1290,7 +1278,7 @@
Ok(value) => match value.as_ref() {
"always" => true,
"never" => false,
- "auto" => stdout_isatty(),
+ "auto" => stderr_isatty(),
_ => early_error(
ErrorOutputType::default(),
&format!(
@@ -1299,7 +1287,7 @@
),
),
},
- Err(std::env::VarError::NotPresent) => stdout_isatty(),
+ 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",
@@ -1324,7 +1312,8 @@
}
pub fn main() -> ! {
- let start = Instant::now();
+ let start_time = Instant::now();
+ let start_rss = get_resident_set_size();
init_rustc_env_logger();
let mut callbacks = TimePassesCallbacks::default();
install_ice_hook();
@@ -1342,7 +1331,11 @@
.collect::<Vec<_>>();
RunCompiler::new(&args, &mut callbacks).run()
});
- // The extra `\t` is necessary to align this label with the others.
- print_time_passes_entry(callbacks.time_passes, "\ttotal", start.elapsed());
+
+ if callbacks.time_passes {
+ let end_rss = get_resident_set_size();
+ print_time_passes_entry("total", start_time.elapsed(), start_rss, end_rss);
+ }
+
process::exit(exit_code)
}
diff --git a/compiler/rustc_driver/src/pretty.rs b/compiler/rustc_driver/src/pretty.rs
index 305fa83..b7edc24 100644
--- a/compiler/rustc_driver/src/pretty.rs
+++ b/compiler/rustc_driver/src/pretty.rs
@@ -363,8 +363,15 @@
fn get_source(input: &Input, sess: &Session) -> (String, FileName) {
let src_name = input.source_name();
- let src =
- String::clone(&sess.source_map().get_source_file(&src_name).unwrap().src.as_ref().unwrap());
+ let src = String::clone(
+ &sess
+ .source_map()
+ .get_source_file(&src_name)
+ .expect("get_source_file")
+ .src
+ .as_ref()
+ .expect("src"),
+ );
(src, src_name)
}
diff --git a/compiler/rustc_error_codes/src/error_codes.rs b/compiler/rustc_error_codes/src/error_codes.rs
index fef6602..1ed43669 100644
--- a/compiler/rustc_error_codes/src/error_codes.rs
+++ b/compiler/rustc_error_codes/src/error_codes.rs
@@ -267,6 +267,7 @@
E0517: include_str!("./error_codes/E0517.md"),
E0518: include_str!("./error_codes/E0518.md"),
E0520: include_str!("./error_codes/E0520.md"),
+E0521: include_str!("./error_codes/E0521.md"),
E0522: include_str!("./error_codes/E0522.md"),
E0524: include_str!("./error_codes/E0524.md"),
E0525: include_str!("./error_codes/E0525.md"),
@@ -464,6 +465,8 @@
E0777: include_str!("./error_codes/E0777.md"),
E0778: include_str!("./error_codes/E0778.md"),
E0779: include_str!("./error_codes/E0779.md"),
+E0780: include_str!("./error_codes/E0780.md"),
+E0781: include_str!("./error_codes/E0781.md"),
;
// E0006, // merged with E0005
// E0008, // cannot bind by-move into a pattern guard
@@ -596,7 +599,6 @@
E0514, // metadata version mismatch
E0519, // local crate and dependency have same (crate-name, disambiguator)
// two dependencies have same (crate-name, disambiguator) but different SVH
- E0521, // borrowed data escapes outside of closure
E0523,
// E0526, // shuffle indices are not constant
// E0540, // multiple rustc_deprecated attributes
diff --git a/compiler/rustc_error_codes/src/error_codes/E0013.md b/compiler/rustc_error_codes/src/error_codes/E0013.md
index 8de1775..5605302 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0013.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0013.md
@@ -8,7 +8,7 @@
const Y: i32 = X;
```
-In this example, `Y` cannot refer to `X` here. To fix this, the value can be
+In this example, `Y` cannot refer to `X`. To fix this, the value can be
extracted as a const and then used:
```
diff --git a/compiler/rustc_error_codes/src/error_codes/E0038.md b/compiler/rustc_error_codes/src/error_codes/E0038.md
index b2cc2a2..019d54b 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0038.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0038.md
@@ -287,5 +287,5 @@
function. `Self` type parameters let us make object safe traits no longer safe,
so they are forbidden when specifying supertraits.
-There's no easy fix for this, generally code will need to be refactored so that
+There's no easy fix for this. Generally, code will need to be refactored so that
you no longer need to derive from `Super<Self>`.
diff --git a/compiler/rustc_error_codes/src/error_codes/E0044.md b/compiler/rustc_error_codes/src/error_codes/E0044.md
index 635ff95..ed7daf8 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0044.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0044.md
@@ -3,13 +3,13 @@
Example of erroneous code:
```compile_fail,E0044
-extern { fn some_func<T>(x: T); }
+extern "C" { fn some_func<T>(x: T); }
```
To fix this, replace the generic parameter with the specializations that you
need:
```
-extern { fn some_func_i32(x: i32); }
-extern { fn some_func_i64(x: i64); }
+extern "C" { fn some_func_i32(x: i32); }
+extern "C" { fn some_func_i64(x: i64); }
```
diff --git a/compiler/rustc_error_codes/src/error_codes/E0107.md b/compiler/rustc_error_codes/src/error_codes/E0107.md
index 4d22b17..4e37695 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0107.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0107.md
@@ -1,4 +1,4 @@
-An incorrect number of generic arguments were provided.
+An incorrect number of generic arguments was provided.
Erroneous code example:
diff --git a/compiler/rustc_error_codes/src/error_codes/E0116.md b/compiler/rustc_error_codes/src/error_codes/E0116.md
index ca849c2..653be60 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0116.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0116.md
@@ -10,7 +10,7 @@
where the type was defined. For example, an `impl` block as above is not allowed
since `Vec` is defined in the standard library.
-To fix this problem, you can do either of these things:
+To fix this problem, you can either:
- define a trait that has the desired associated functions/types/constants and
implement the trait for the type in question
diff --git a/compiler/rustc_error_codes/src/error_codes/E0130.md b/compiler/rustc_error_codes/src/error_codes/E0130.md
index a270fea..2cd27b5 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0130.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0130.md
@@ -3,7 +3,7 @@
Erroneous code example:
```compile_fail,E0130
-extern {
+extern "C" {
fn foo((a, b): (u32, u32)); // error: patterns aren't allowed in foreign
// function declarations
}
@@ -17,7 +17,7 @@
b: u32,
}
-extern {
+extern "C" {
fn foo(s: SomeStruct); // ok!
}
```
@@ -25,7 +25,7 @@
Or:
```
-extern {
+extern "C" {
fn foo(a: (u32, u32)); // ok!
}
```
diff --git a/compiler/rustc_error_codes/src/error_codes/E0207.md b/compiler/rustc_error_codes/src/error_codes/E0207.md
index cb4f5d5..8a7923a 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0207.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0207.md
@@ -14,7 +14,7 @@
}
```
-Any type parameter parameter of an `impl` must meet at least one of
+Any type parameter of an `impl` must meet at least one of
the following criteria:
- it appears in the _implementing type_ of the impl, e.g. `impl<T> Foo<T>`
diff --git a/compiler/rustc_error_codes/src/error_codes/E0277.md b/compiler/rustc_error_codes/src/error_codes/E0277.md
index 2e2cd5e..9f6db6e 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0277.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0277.md
@@ -59,9 +59,9 @@
}
```
-Note that the error here is in the definition of the generic function: Although
+Note that the error here is in the definition of the generic function. Although
we only call it with a parameter that does implement `Debug`, the compiler
-still rejects the function: It must work with all possible input types. In
+still rejects the function. It must work with all possible input types. In
order to make this example compile, we need to restrict the generic type we're
accepting:
diff --git a/compiler/rustc_error_codes/src/error_codes/E0309.md b/compiler/rustc_error_codes/src/error_codes/E0309.md
index e719ee5..c36a56b 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0309.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0309.md
@@ -25,7 +25,7 @@
The type definition contains some field whose type requires an outlives
annotation. Outlives annotations (e.g., `T: 'a`) are used to guarantee that all
-the data in T is valid for at least the lifetime `'a`. This scenario most
+the data in `T` is valid for at least the lifetime `'a`. This scenario most
commonly arises when the type contains an associated type reference like
`<T as SomeTrait<'a>>::Output`, as shown in the previous code.
diff --git a/compiler/rustc_error_codes/src/error_codes/E0373.md b/compiler/rustc_error_codes/src/error_codes/E0373.md
index fd96987..effa597 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0373.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0373.md
@@ -50,3 +50,24 @@
Now that the closure has its own copy of the data, there's no need to worry
about safety.
+
+This error may also be encountered while using `async` blocks:
+
+```compile_fail,E0373,edition2018
+use std::future::Future;
+
+async fn f() {
+ let v = vec![1, 2, 3i32];
+ spawn(async { //~ ERROR E0373
+ println!("{:?}", v)
+ });
+}
+
+fn spawn<F: Future + Send + 'static>(future: F) {
+ unimplemented!()
+}
+```
+
+Similarly to closures, `async` blocks are not executed immediately and may
+capture closed-over data by reference. For more information, see
+https://rust-lang.github.io/async-book/03_async_await/01_chapter.html.
diff --git a/compiler/rustc_error_codes/src/error_codes/E0435.md b/compiler/rustc_error_codes/src/error_codes/E0435.md
index 424e5ce..798a20d 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0435.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0435.md
@@ -7,6 +7,12 @@
let a: [u8; foo]; // error: attempt to use a non-constant value in a constant
```
+'constant' means 'a compile-time value'.
+
+More details can be found in the [Variables and Mutability] section of the book.
+
+[Variables and Mutability]: https://doc.rust-lang.org/book/ch03-01-variables-and-mutability.html#differences-between-variables-and-constants
+
To fix this error, please replace the value with a constant. Example:
```
diff --git a/compiler/rustc_error_codes/src/error_codes/E0454.md b/compiler/rustc_error_codes/src/error_codes/E0454.md
index 23ca6c7..95a22b9 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0454.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0454.md
@@ -3,7 +3,7 @@
Erroneous code example:
```compile_fail,E0454
-#[link(name = "")] extern {}
+#[link(name = "")] extern "C" {}
// error: `#[link(name = "")]` given with empty name
```
@@ -11,5 +11,5 @@
name. Example:
```no_run
-#[link(name = "some_lib")] extern {} // ok!
+#[link(name = "some_lib")] extern "C" {} // ok!
```
diff --git a/compiler/rustc_error_codes/src/error_codes/E0455.md b/compiler/rustc_error_codes/src/error_codes/E0455.md
index 2f80c34..84689b3 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0455.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0455.md
@@ -4,7 +4,7 @@
Erroneous code example:
```ignore (should-compile_fail-but-cannot-doctest-conditionally-without-macos)
-#[link(name = "FooCoreServices", kind = "framework")] extern {}
+#[link(name = "FooCoreServices", kind = "framework")] extern "C" {}
// OS used to compile is Linux for example
```
@@ -12,7 +12,7 @@
```
#[cfg_attr(target="macos", link(name = "FooCoreServices", kind = "framework"))]
-extern {}
+extern "C" {}
```
Learn more in the [Conditional Compilation][conditional-compilation] section
diff --git a/compiler/rustc_error_codes/src/error_codes/E0458.md b/compiler/rustc_error_codes/src/error_codes/E0458.md
index 075226a..359aeb6 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0458.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0458.md
@@ -3,7 +3,7 @@
Erroneous code example:
```compile_fail,E0458
-#[link(kind = "wonderful_unicorn")] extern {}
+#[link(kind = "wonderful_unicorn")] extern "C" {}
// error: unknown kind: `wonderful_unicorn`
```
diff --git a/compiler/rustc_error_codes/src/error_codes/E0459.md b/compiler/rustc_error_codes/src/error_codes/E0459.md
index 6f75f2a..4a49a76 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0459.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0459.md
@@ -3,7 +3,7 @@
Erroneous code example:
```compile_fail,E0459
-#[link(kind = "dylib")] extern {}
+#[link(kind = "dylib")] extern "C" {}
// error: `#[link(...)]` specified without `name = "foo"`
```
@@ -11,5 +11,5 @@
you want. Example:
```no_run
-#[link(kind = "dylib", name = "some_lib")] extern {} // ok!
+#[link(kind = "dylib", name = "some_lib")] extern "C" {} // ok!
```
diff --git a/compiler/rustc_error_codes/src/error_codes/E0463.md b/compiler/rustc_error_codes/src/error_codes/E0463.md
index e46938c..d0cd1b1 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0463.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0463.md
@@ -11,3 +11,24 @@
You need to link your code to the relevant crate in order to be able to use it
(through Cargo or the `-L` option of rustc example). Plugins are crates as
well, and you link to them the same way.
+
+## Common causes
+
+- The crate is not present at all. If using Cargo, add it to `[dependencies]`
+ in Cargo.toml.
+- The crate is present, but under a different name. If using Cargo, look for
+ `package = ` under `[dependencies]` in Cargo.toml.
+
+## Common causes for missing `std` or `core`
+
+- You are cross-compiling for a target which doesn't have `std` prepackaged.
+ Consider one of the following:
+ + Adding a pre-compiled version of std with `rustup target add`
+ + Building std from source with `cargo build -Z build-std`
+ + Using `#![no_std]` at the crate root, so you won't need `std` in the first
+ place.
+- You are developing the compiler itself and haven't built libstd from source.
+ You can usually build it with `x.py build library/std`. More information
+ about x.py is available in the [rustc-dev-guide].
+
+[rustc-dev-guide]: https://rustc-dev-guide.rust-lang.org/building/how-to-build-and-run.html#building-the-compiler
diff --git a/compiler/rustc_error_codes/src/error_codes/E0492.md b/compiler/rustc_error_codes/src/error_codes/E0492.md
index 1caa599..79e7c06 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0492.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0492.md
@@ -6,7 +6,7 @@
use std::sync::atomic::AtomicUsize;
const A: AtomicUsize = AtomicUsize::new(0);
-static B: &'static AtomicUsize = &A;
+const B: &'static AtomicUsize = &A;
// error: cannot borrow a constant which may contain interior mutability,
// create a static instead
```
@@ -18,7 +18,7 @@
it. That is, a constant value could be mutated. On the other hand, a `static` is
explicitly a single memory location, which can be mutated at will.
-So, in order to solve this error, either use statics which are `Sync`:
+So, in order to solve this error, use statics which are `Sync`:
```
use std::sync::atomic::AtomicUsize;
diff --git a/compiler/rustc_error_codes/src/error_codes/E0521.md b/compiler/rustc_error_codes/src/error_codes/E0521.md
new file mode 100644
index 0000000..65dcac9
--- /dev/null
+++ b/compiler/rustc_error_codes/src/error_codes/E0521.md
@@ -0,0 +1,28 @@
+Borrowed data escapes outside of closure.
+
+Erroneous code example:
+
+```compile_fail,E0521
+let mut list: Vec<&str> = Vec::new();
+
+let _add = |el: &str| {
+ list.push(el); // error: `el` escapes the closure body here
+};
+```
+
+A type anotation of a closure parameter implies a new lifetime declaration.
+Consider to drop it, the compiler is reliably able to infer them.
+
+```
+let mut list: Vec<&str> = Vec::new();
+
+let _add = |el| {
+ list.push(el);
+};
+```
+
+See the [Closure type inference and annotation][closure-infere-annotation] and
+[Lifetime elision][lifetime-elision] sections of the Book for more details.
+
+[closure-infere-annotation]: https://doc.rust-lang.org/book/ch13-01-closures.html#closure-type-inference-and-annotation
+[lifetime-elision]: https://doc.rust-lang.org/reference/lifetime-elision.html
diff --git a/compiler/rustc_error_codes/src/error_codes/E0597.md b/compiler/rustc_error_codes/src/error_codes/E0597.md
index 3340768..f6e0b62 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0597.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0597.md
@@ -1,4 +1,4 @@
-This error occurs because a value was dropped while it was still borrowed
+This error occurs because a value was dropped while it was still borrowed.
Erroneous code example:
@@ -15,7 +15,7 @@
println!("{:?}", x.x);
```
-In here, `y` is dropped at the end of the inner scope, but it is borrowed by
+Here, `y` is dropped at the end of the inner scope, but it is borrowed by
`x` until the `println`. To fix the previous example, just remove the scope
so that `y` isn't dropped until after the println
diff --git a/compiler/rustc_error_codes/src/error_codes/E0617.md b/compiler/rustc_error_codes/src/error_codes/E0617.md
index 61b5676..1c5d1f8 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0617.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0617.md
@@ -3,7 +3,7 @@
Erroneous code example:
```compile_fail,E0617
-extern {
+extern "C" {
fn printf(c: *const i8, ...);
}
@@ -21,7 +21,7 @@
In this case, `c_double` has the same size as `f64` so we can use it directly:
```no_run
-# extern {
+# extern "C" {
# fn printf(c: *const i8, ...);
# }
unsafe {
diff --git a/compiler/rustc_error_codes/src/error_codes/E0633.md b/compiler/rustc_error_codes/src/error_codes/E0633.md
index 7f488cd..4d1f0c4 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0633.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0633.md
@@ -6,7 +6,7 @@
#![feature(unwind_attributes)]
#[unwind()] // error: expected one argument
-pub extern fn something() {}
+pub extern "C" fn something() {}
fn main() {}
```
diff --git a/compiler/rustc_error_codes/src/error_codes/E0658.md b/compiler/rustc_error_codes/src/error_codes/E0658.md
index d821b902..24245a3 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0658.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0658.md
@@ -11,7 +11,7 @@
If you're using a stable or a beta version of rustc, you won't be able to use
any unstable features. In order to do so, please switch to a nightly version of
-rustc (by using rustup).
+rustc (by using [rustup]).
If you're using a nightly version of rustc, just add the corresponding feature
to be able to use it:
@@ -24,3 +24,5 @@
Bar(u64),
}
```
+
+[rustup]: https://rust-lang.github.io/rustup/concepts/channels.html
diff --git a/compiler/rustc_error_codes/src/error_codes/E0724.md b/compiler/rustc_error_codes/src/error_codes/E0724.md
index e8f84d0..70578ac 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0724.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0724.md
@@ -18,7 +18,7 @@
```
#![feature(ffi_returns_twice)]
-extern {
+extern "C" {
#[ffi_returns_twice] // ok!
pub fn foo();
}
diff --git a/compiler/rustc_error_codes/src/error_codes/E0730.md b/compiler/rustc_error_codes/src/error_codes/E0730.md
index 016b3f3..56d0e6a 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0730.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0730.md
@@ -3,8 +3,6 @@
Erroneous code example:
```compile_fail,E0730
-#![feature(const_generics)]
-
fn is_123<const N: usize>(x: [u32; N]) -> bool {
match x {
[1, 2, ..] => true, // error: cannot pattern-match on an
diff --git a/compiler/rustc_error_codes/src/error_codes/E0754.md b/compiler/rustc_error_codes/src/error_codes/E0754.md
index 57620bc..9f4b19c 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0754.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0754.md
@@ -1,4 +1,4 @@
-An non-ascii identifier was used in an invalid context.
+A non-ASCII identifier was used in an invalid context.
Erroneous code examples:
@@ -13,7 +13,7 @@
fn main() {}
```
-Non-ascii can be used as module names if it is inlined or if a `#[path]`
+Non-ASCII can be used as module names if it is inlined or if a `#[path]`
attribute is specified. For example:
```
diff --git a/compiler/rustc_error_codes/src/error_codes/E0759.md b/compiler/rustc_error_codes/src/error_codes/E0759.md
index 6d52531..2fe5ada 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0759.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0759.md
@@ -27,7 +27,7 @@
}
```
-Both [`dyn Trait`] and [`impl Trait`] in return types have a an implicit
+Both [`dyn Trait`] and [`impl Trait`] in return types have an implicit
`'static` requirement, meaning that the value implementing them that is being
returned has to be either a `'static` borrow or an owned value.
diff --git a/compiler/rustc_error_codes/src/error_codes/E0770.md b/compiler/rustc_error_codes/src/error_codes/E0770.md
index 278bf9b..b39163a 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0770.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0770.md
@@ -10,6 +10,5 @@
To fix this error, use a concrete type for the const parameter:
```
-#![feature(const_generics)]
fn foo<T, const N: usize>() {}
```
diff --git a/compiler/rustc_error_codes/src/error_codes/E0780.md b/compiler/rustc_error_codes/src/error_codes/E0780.md
new file mode 100644
index 0000000..704b4ae
--- /dev/null
+++ b/compiler/rustc_error_codes/src/error_codes/E0780.md
@@ -0,0 +1,19 @@
+Cannot use `doc(inline)` with anonymous imports
+
+Erroneous code example:
+
+```ignore (cannot-doctest-multicrate-project)
+
+#[doc(inline)] // error: invalid doc argument
+pub use foo::Foo as _;
+```
+
+Anonymous imports are always rendered with `#[doc(no_inline)]`. To fix this
+error, remove the `#[doc(inline)]` attribute.
+
+Example:
+
+```ignore (cannot-doctest-multicrate-project)
+
+pub use foo::Foo as _;
+```
diff --git a/compiler/rustc_error_codes/src/error_codes/E0781.md b/compiler/rustc_error_codes/src/error_codes/E0781.md
new file mode 100644
index 0000000..7641acf
--- /dev/null
+++ b/compiler/rustc_error_codes/src/error_codes/E0781.md
@@ -0,0 +1,12 @@
+The `C-cmse-nonsecure-call` ABI can only be used with function pointers.
+
+Erroneous code example:
+
+```compile_fail,E0781
+#![feature(abi_c_cmse_nonsecure_call)]
+
+pub extern "C-cmse-nonsecure-call" fn test() {}
+```
+
+The `C-cmse-nonsecure-call` ABI should be used by casting function pointers to
+specific addresses.
diff --git a/compiler/rustc_errors/src/diagnostic_builder.rs b/compiler/rustc_errors/src/diagnostic_builder.rs
index f165a60..c09cce2 100644
--- a/compiler/rustc_errors/src/diagnostic_builder.rs
+++ b/compiler/rustc_errors/src/diagnostic_builder.rs
@@ -36,7 +36,7 @@
($e:expr => $i:item) => {
#[doc = $e]
$i
- }
+ };
}
/// In general, the `DiagnosticBuilder` uses deref to allow access to
@@ -74,11 +74,10 @@
});
};
- // Forward pattern for &mut self -> &mut Self, with S: Into<MultiSpan>
- // type parameter. No obvious way to make this more generic.
+ // Forward pattern for &mut self -> &mut Self, with generic parameters.
(
$(#[$attrs:meta])*
- pub fn $n:ident<S: Into<MultiSpan>>(
+ pub fn $n:ident<$($generic:ident: $bound:path),*>(
&mut self,
$($name:ident: $ty:ty),*
$(,)?
@@ -86,7 +85,7 @@
) => {
$(#[$attrs])*
forward_inner_docs!(concat!("See [`Diagnostic::", stringify!($n), "()`].") =>
- pub fn $n<S: Into<MultiSpan>>(&mut self, $($name: $ty),*) -> &mut Self {
+ pub fn $n<$($generic: $bound),*>(&mut self, $($name: $ty),*) -> &mut Self {
self.0.diagnostic.$n($($name),*);
self
});
@@ -398,6 +397,7 @@
self
}
+ forward!(pub fn set_primary_message<M: Into<String>>(&mut self, msg: M) -> &mut Self);
forward!(pub fn set_span<S: Into<MultiSpan>>(&mut self, sp: S) -> &mut Self);
forward!(pub fn code(&mut self, s: DiagnosticId) -> &mut Self);
diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs
index 32104e6..ea62e21 100644
--- a/compiler/rustc_errors/src/emitter.rs
+++ b/compiler/rustc_errors/src/emitter.rs
@@ -644,6 +644,8 @@
code_offset: usize,
margin: Margin,
) {
+ // Tabs are assumed to have been replaced by spaces in calling code.
+ debug_assert!(!source_string.contains('\t'));
let line_len = source_string.len();
// Create the source line we will highlight.
let left = margin.left(line_len);
@@ -707,7 +709,7 @@
}
let source_string = match file.get_line(line.line_index - 1) {
- Some(s) => s,
+ Some(s) => replace_tabs(&*s),
None => return Vec::new(),
};
@@ -1376,8 +1378,17 @@
let file = annotated_file.file.clone();
let line = &annotated_file.lines[line_idx];
if let Some(source_string) = file.get_line(line.line_index - 1) {
- let leading_whitespace =
- source_string.chars().take_while(|c| c.is_whitespace()).count();
+ let leading_whitespace = source_string
+ .chars()
+ .take_while(|c| c.is_whitespace())
+ .map(|c| {
+ match c {
+ // Tabs are displayed as 4 spaces
+ '\t' => 4,
+ _ => 1,
+ }
+ })
+ .sum();
if source_string.chars().any(|c| !c.is_whitespace()) {
whitespace_margin = min(whitespace_margin, leading_whitespace);
}
@@ -1502,7 +1513,7 @@
self.draw_line(
&mut buffer,
- &unannotated_line,
+ &replace_tabs(&unannotated_line),
annotated_file.lines[line_idx + 1].line_index - 1,
last_buffer_line_num,
width_offset,
@@ -1598,7 +1609,7 @@
);
// print the suggestion
draw_col_separator(&mut buffer, row_num, max_line_num_len + 1);
- buffer.append(row_num, line, Style::NoStyle);
+ buffer.append(row_num, &replace_tabs(line), Style::NoStyle);
row_num += 1;
}
@@ -1930,6 +1941,10 @@
}
}
+fn replace_tabs(str: &str) -> String {
+ str.replace('\t', " ")
+}
+
fn draw_col_separator(buffer: &mut StyledBuffer, line: usize, col: usize) {
buffer.puts(line, col, "| ", Style::LineNumber);
}
diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs
index 593e0d9..aa88233 100644
--- a/compiler/rustc_errors/src/lib.rs
+++ b/compiler/rustc_errors/src/lib.rs
@@ -804,7 +804,7 @@
}
fn treat_err_as_bug(&self) -> bool {
- self.flags.treat_err_as_bug.map(|c| self.err_count() >= c).unwrap_or(false)
+ self.flags.treat_err_as_bug.map_or(false, |c| self.err_count() >= c)
}
fn print_error_count(&mut self, registry: &Registry) {
@@ -901,7 +901,7 @@
fn span_bug(&mut self, sp: impl Into<MultiSpan>, msg: &str) -> ! {
self.emit_diag_at_span(Diagnostic::new(Bug, msg), sp);
- panic!(ExplicitBug);
+ panic::panic_any(ExplicitBug);
}
fn emit_diag_at_span(&mut self, mut diag: Diagnostic, sp: impl Into<MultiSpan>) {
@@ -913,7 +913,7 @@
// This is technically `self.treat_err_as_bug()` but `delay_span_bug` is called before
// incrementing `err_count` by one, so we need to +1 the comparing.
// FIXME: Would be nice to increment err_count in a more coherent way.
- if self.flags.treat_err_as_bug.map(|c| self.err_count() + 1 >= c).unwrap_or(false) {
+ if self.flags.treat_err_as_bug.map_or(false, |c| self.err_count() + 1 >= c) {
// FIXME: don't abort here if report_delayed_bugs is off
self.span_bug(sp, msg);
}
@@ -955,7 +955,7 @@
fn bug(&mut self, msg: &str) -> ! {
self.emit_diagnostic(&Diagnostic::new(Bug, msg));
- panic!(ExplicitBug);
+ panic::panic_any(ExplicitBug);
}
fn delay_as_bug(&mut self, diagnostic: Diagnostic) {
diff --git a/compiler/rustc_errors/src/snippet.rs b/compiler/rustc_errors/src/snippet.rs
index dbb2523..acb88e5 100644
--- a/compiler/rustc_errors/src/snippet.rs
+++ b/compiler/rustc_errors/src/snippet.rs
@@ -122,11 +122,13 @@
}
pub fn is_multiline(&self) -> bool {
- matches!(self.annotation_type,
+ matches!(
+ self.annotation_type,
AnnotationType::Multiline(_)
- | AnnotationType::MultilineStart(_)
- | AnnotationType::MultilineLine(_)
- | AnnotationType::MultilineEnd(_))
+ | AnnotationType::MultilineStart(_)
+ | AnnotationType::MultilineLine(_)
+ | AnnotationType::MultilineEnd(_)
+ )
}
pub fn len(&self) -> usize {
@@ -158,7 +160,10 @@
pub fn takes_space(&self) -> bool {
// Multiline annotations always have to keep vertical space.
- matches!(self.annotation_type, AnnotationType::MultilineStart(_) | AnnotationType::MultilineEnd(_))
+ matches!(
+ self.annotation_type,
+ AnnotationType::MultilineStart(_) | AnnotationType::MultilineEnd(_)
+ )
}
}
diff --git a/compiler/rustc_errors/src/styled_buffer.rs b/compiler/rustc_errors/src/styled_buffer.rs
index f2d255d..ef71ee3 100644
--- a/compiler/rustc_errors/src/styled_buffer.rs
+++ b/compiler/rustc_errors/src/styled_buffer.rs
@@ -13,34 +13,13 @@
StyledBuffer { text: vec![], styles: vec![] }
}
- fn replace_tabs(&mut self) {
- for (line_pos, line) in self.text.iter_mut().enumerate() {
- let mut tab_pos = vec![];
- for (pos, c) in line.iter().enumerate() {
- if *c == '\t' {
- tab_pos.push(pos);
- }
- }
- // start with the tabs at the end of the line to replace them with 4 space chars
- for pos in tab_pos.iter().rev() {
- assert_eq!(line.remove(*pos), '\t');
- // fix the position of the style to match up after replacing the tabs
- let s = self.styles[line_pos].remove(*pos);
- for _ in 0..4 {
- line.insert(*pos, ' ');
- self.styles[line_pos].insert(*pos, s);
- }
- }
- }
- }
+ pub fn render(&self) -> Vec<Vec<StyledString>> {
+ // Tabs are assumed to have been replaced by spaces in calling code.
+ debug_assert!(self.text.iter().all(|r| !r.contains(&'\t')));
- pub fn render(&mut self) -> Vec<Vec<StyledString>> {
let mut output: Vec<Vec<StyledString>> = vec![];
let mut styled_vec: Vec<StyledString> = vec![];
- // before we render, replace tabs with spaces
- self.replace_tabs();
-
for (row, row_style) in self.text.iter().zip(&self.styles) {
let mut current_style = Style::NoStyle;
let mut current_text = String::new();
diff --git a/compiler/rustc_expand/Cargo.toml b/compiler/rustc_expand/Cargo.toml
index 25c2851..7413b0d 100644
--- a/compiler/rustc_expand/Cargo.toml
+++ b/compiler/rustc_expand/Cargo.toml
@@ -18,6 +18,7 @@
rustc_data_structures = { path = "../rustc_data_structures" }
rustc_errors = { path = "../rustc_errors" }
rustc_feature = { path = "../rustc_feature" }
+rustc_lint_defs = { path = "../rustc_lint_defs" }
rustc_macros = { path = "../rustc_macros" }
rustc_lexer = { path = "../rustc_lexer" }
rustc_parse = { path = "../rustc_parse" }
diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs
index 335f3b7..08543d1 100644
--- a/compiler/rustc_expand/src/base.rs
+++ b/compiler/rustc_expand/src/base.rs
@@ -2,8 +2,8 @@
use crate::module::DirectoryOwnership;
use rustc_ast::ptr::P;
-use rustc_ast::token;
-use rustc_ast::tokenstream::TokenStream;
+use rustc_ast::token::{self, Nonterminal};
+use rustc_ast::tokenstream::{CanSynthesizeMissingTokens, TokenStream};
use rustc_ast::visit::{AssocCtxt, Visitor};
use rustc_ast::{self as ast, Attribute, NodeId, PatKind};
use rustc_attr::{self as attr, Deprecation, HasAttrs, Stability};
@@ -12,7 +12,7 @@
use rustc_errors::{DiagnosticBuilder, ErrorReported};
use rustc_parse::{self, nt_to_tokenstream, parser, MACRO_ARGUMENTS};
use rustc_session::{parse::ParseSess, Limit, Session};
-use rustc_span::def_id::{DefId, LOCAL_CRATE};
+use rustc_span::def_id::DefId;
use rustc_span::edition::Edition;
use rustc_span::hygiene::{AstPass, ExpnData, ExpnId, ExpnKind};
use rustc_span::source_map::SourceMap;
@@ -119,8 +119,8 @@
}
}
- crate fn into_tokens(self, sess: &ParseSess) -> TokenStream {
- let nt = match self {
+ crate fn into_nonterminal(self) -> Nonterminal {
+ match self {
Annotatable::Item(item) => token::NtItem(item),
Annotatable::TraitItem(item) | Annotatable::ImplItem(item) => {
token::NtItem(P(item.and_then(ast::AssocItem::into_item)))
@@ -137,8 +137,11 @@
| Annotatable::Param(..)
| Annotatable::StructField(..)
| Annotatable::Variant(..) => panic!("unexpected annotatable"),
- };
- nt_to_tokenstream(&nt, sess, DUMMY_SP)
+ }
+ }
+
+ crate fn into_tokens(self, sess: &ParseSess) -> TokenStream {
+ nt_to_tokenstream(&self.into_nonterminal(), sess, CanSynthesizeMissingTokens::No)
}
pub fn expect_item(self) -> P<ast::Item> {
@@ -725,9 +728,7 @@
pub edition: Edition,
/// Built-in macros have a couple of special properties like availability
/// in `#[no_implicit_prelude]` modules, so we have to keep this flag.
- pub is_builtin: bool,
- /// We have to identify macros providing a `Copy` impl early for compatibility reasons.
- pub is_derive_copy: bool,
+ pub builtin_name: Option<Symbol>,
}
impl SyntaxExtension {
@@ -755,8 +756,7 @@
deprecation: None,
helper_attrs: Vec::new(),
edition,
- is_builtin: false,
- is_derive_copy: false,
+ builtin_name: None,
kind,
}
}
@@ -782,7 +782,9 @@
}
}
- let is_builtin = sess.contains_name(attrs, sym::rustc_builtin_macro);
+ let builtin_name = sess
+ .find_by_name(attrs, sym::rustc_builtin_macro)
+ .map(|a| a.value_str().unwrap_or(name));
let (stability, const_stability) = attr::find_stability(&sess, attrs, span);
if const_stability.is_some() {
sess.parse_sess
@@ -800,8 +802,7 @@
deprecation: attr::find_deprecation(&sess, attrs).map(|(d, _)| d),
helper_attrs,
edition,
- is_builtin,
- is_derive_copy: is_builtin && name == sym::Copy,
+ builtin_name,
}
}
@@ -839,19 +840,17 @@
descr: Symbol,
macro_def_id: Option<DefId>,
) -> ExpnData {
- ExpnData {
- kind: ExpnKind::Macro(self.macro_kind(), descr),
+ ExpnData::new(
+ ExpnKind::Macro(self.macro_kind(), descr),
parent,
call_site,
- def_site: self.span,
- allow_internal_unstable: self.allow_internal_unstable.clone(),
- allow_internal_unsafe: self.allow_internal_unsafe,
- local_inner_macros: self.local_inner_macros,
- edition: self.edition,
+ self.span,
+ self.allow_internal_unstable.clone(),
+ self.allow_internal_unsafe,
+ self.local_inner_macros,
+ self.edition,
macro_def_id,
- krate: LOCAL_CRATE,
- orig_id: None,
- }
+ )
}
}
@@ -869,7 +868,7 @@
fn resolve_dollar_crates(&mut self);
fn visit_ast_fragment_with_placeholders(&mut self, expn_id: ExpnId, fragment: &AstFragment);
- fn register_builtin_macro(&mut self, ident: Ident, ext: SyntaxExtension);
+ fn register_builtin_macro(&mut self, name: Symbol, ext: SyntaxExtensionKind);
fn expansion_for_ast_pass(
&mut self,
@@ -930,7 +929,9 @@
pub force_mode: bool,
pub expansions: FxHashMap<Span, Vec<String>>,
/// Called directly after having parsed an external `mod foo;` in expansion.
- pub(super) extern_mod_loaded: Option<&'a dyn Fn(&ast::Crate)>,
+ ///
+ /// `Ident` is the module name.
+ pub(super) extern_mod_loaded: Option<&'a dyn Fn(&ast::Crate, Ident)>,
}
impl<'a> ExtCtxt<'a> {
@@ -938,7 +939,7 @@
sess: &'a Session,
ecfg: expand::ExpansionConfig<'a>,
resolver: &'a mut dyn ResolverExpand,
- extern_mod_loaded: Option<&'a dyn Fn(&ast::Crate)>,
+ extern_mod_loaded: Option<&'a dyn Fn(&ast::Crate, Ident)>,
) -> ExtCtxt<'a> {
ExtCtxt {
sess,
diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs
index 563783c..b07bce94 100644
--- a/compiler/rustc_expand/src/config.rs
+++ b/compiler/rustc_expand/src/config.rs
@@ -29,6 +29,7 @@
pub struct StripUnconfigured<'a> {
pub sess: &'a Session,
pub features: Option<&'a Features>,
+ pub modified: bool,
}
fn get_features(
@@ -199,7 +200,7 @@
// `cfg_attr`-process the crate's attributes and compute the crate's features.
pub fn features(sess: &Session, mut krate: ast::Crate) -> (ast::Crate, Features) {
- let mut strip_unconfigured = StripUnconfigured { sess, features: None };
+ let mut strip_unconfigured = StripUnconfigured { sess, features: None, modified: false };
let unconfigured_attrs = krate.attrs.clone();
let diag = &sess.parse_sess.span_diagnostic;
@@ -243,7 +244,12 @@
impl<'a> StripUnconfigured<'a> {
pub fn configure<T: HasAttrs>(&mut self, mut node: T) -> Option<T> {
self.process_cfg_attrs(&mut node);
- self.in_cfg(node.attrs()).then_some(node)
+ if self.in_cfg(node.attrs()) {
+ Some(node)
+ } else {
+ self.modified = true;
+ None
+ }
}
/// Parse and expand all `cfg_attr` attributes into a list of attributes
@@ -270,6 +276,9 @@
return vec![attr];
}
+ // A `#[cfg_attr]` either gets removed, or replaced with a new attribute
+ self.modified = true;
+
let (cfg_predicate, expanded_attrs) = match self.parse_cfg_attr(&attr) {
None => return vec![],
Some(r) => r,
@@ -414,7 +423,7 @@
/// If attributes are not allowed on expressions, emit an error for `attr`
pub fn maybe_emit_expr_attr_err(&self, attr: &Attribute) {
- if !self.features.map(|features| features.stmt_expr_attributes).unwrap_or(true) {
+ if !self.features.map_or(true, |features| features.stmt_expr_attributes) {
let mut err = feature_err(
&self.sess.parse_sess,
sym::stmt_expr_attributes,
diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs
index 2da5bde..5fdb7fc 100644
--- a/compiler/rustc_expand/src/expand.rs
+++ b/compiler/rustc_expand/src/expand.rs
@@ -12,7 +12,7 @@
use rustc_ast::token;
use rustc_ast::tokenstream::TokenStream;
use rustc_ast::visit::{self, AssocCtxt, Visitor};
-use rustc_ast::{self as ast, AttrItem, Block, LitKind, NodeId, PatKind, Path};
+use rustc_ast::{self as ast, AttrItem, AttrStyle, Block, LitKind, NodeId, PatKind, Path};
use rustc_ast::{ItemKind, MacArgs, MacCallStmt, MacStmtStyle, StmtKind, Unsafe};
use rustc_ast_pretty::pprust;
use rustc_attr::{self as attr, is_builtin_attr, HasAttrs};
@@ -20,7 +20,7 @@
use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_errors::{struct_span_err, Applicability, PResult};
use rustc_feature::Features;
-use rustc_parse::parser::{AttemptLocalParseRecovery, Parser};
+use rustc_parse::parser::{AttemptLocalParseRecovery, ForceCollect, Parser};
use rustc_parse::validate_attr;
use rustc_session::lint::builtin::UNUSED_DOC_COMMENTS;
use rustc_session::lint::BuiltinLintDiagnostics;
@@ -522,12 +522,29 @@
item.visit_attrs(|attrs| attrs.retain(|a| !a.has_name(sym::derive)));
(item, Vec::new())
} else {
- let mut item = StripUnconfigured {
+ let mut visitor = StripUnconfigured {
sess: self.cx.sess,
features: self.cx.ecfg.features,
- }
- .fully_configure(item);
+ modified: false,
+ };
+ let mut item = visitor.fully_configure(item);
item.visit_attrs(|attrs| attrs.retain(|a| !a.has_name(sym::derive)));
+ if visitor.modified && !derives.is_empty() {
+ // Erase the tokens if cfg-stripping modified the item
+ // This will cause us to synthesize fake tokens
+ // when `nt_to_tokenstream` is called on this item.
+ match &mut item {
+ Annotatable::Item(item) => item.tokens = None,
+ Annotatable::Stmt(stmt) => {
+ if let StmtKind::Item(item) = &mut stmt.kind {
+ item.tokens = None
+ } else {
+ panic!("Unexpected stmt {:?}", stmt);
+ }
+ }
+ _ => panic!("Unexpected annotatable {:?}", item),
+ }
+ }
invocations.reserve(derives.len());
let derive_placeholders = derives
@@ -622,7 +639,11 @@
let invocations = {
let mut collector = InvocationCollector {
- cfg: StripUnconfigured { sess: &self.cx.sess, features: self.cx.ecfg.features },
+ cfg: StripUnconfigured {
+ sess: &self.cx.sess,
+ features: self.cx.ecfg.features,
+ modified: false,
+ },
cx: self.cx,
invocations: Vec::new(),
monotonic: self.monotonic,
@@ -716,7 +737,14 @@
SyntaxExtensionKind::Attr(expander) => {
self.gate_proc_macro_input(&item);
self.gate_proc_macro_attr_item(span, &item);
- let tokens = item.into_tokens(&self.cx.sess.parse_sess);
+ let tokens = match attr.style {
+ AttrStyle::Outer => item.into_tokens(&self.cx.sess.parse_sess),
+ // FIXME: Properly collect tokens for inner attributes
+ AttrStyle::Inner => rustc_parse::fake_token_stream(
+ &self.cx.sess.parse_sess,
+ &item.into_nonterminal(),
+ ),
+ };
let attr_item = attr.unwrap_normal_item();
if let MacArgs::Eq(..) = attr_item.args {
self.cx.span_err(span, "key-value macro attributes are not supported");
@@ -868,7 +896,9 @@
fragment
}
Err(mut err) => {
- err.set_span(span);
+ if err.span.is_dummy() {
+ err.set_span(span);
+ }
annotate_err_with_kind(&mut err, kind, span);
err.emit();
self.cx.trace_macros_diag();
@@ -885,7 +915,7 @@
Ok(match kind {
AstFragmentKind::Items => {
let mut items = SmallVec::new();
- while let Some(item) = this.parse_item()? {
+ while let Some(item) = this.parse_item(ForceCollect::No)? {
items.push(item);
}
AstFragment::Items(items)
@@ -991,15 +1021,16 @@
// with exception of the derive container case which is not resolved and can get
// its expansion data immediately.
let expn_data = match &kind {
- InvocationKind::DeriveContainer { item, .. } => Some(ExpnData {
- parent: self.cx.current_expansion.id,
- ..ExpnData::default(
+ InvocationKind::DeriveContainer { item, .. } => {
+ let mut expn_data = ExpnData::default(
ExpnKind::Macro(MacroKind::Attr, sym::derive),
item.span(),
self.cx.sess.parse_sess.edition,
None,
- )
- }),
+ );
+ expn_data.parent = self.cx.current_expansion.id;
+ Some(expn_data)
+ }
_ => None,
};
let expn_id = ExpnId::fresh(expn_data);
@@ -1378,7 +1409,7 @@
proc_macros: vec![],
};
if let Some(extern_mod_loaded) = self.cx.extern_mod_loaded {
- extern_mod_loaded(&krate);
+ extern_mod_loaded(&krate, ident);
}
*old_mod = krate.module;
@@ -1514,13 +1545,8 @@
}
fn visit_item_kind(&mut self, item: &mut ast::ItemKind) {
- match item {
- ast::ItemKind::MacroDef(..) => {}
- _ => {
- self.cfg.configure_item_kind(item);
- noop_visit_item_kind(item, self);
- }
- }
+ self.cfg.configure_item_kind(item);
+ noop_visit_item_kind(item, self);
}
fn flat_map_generic_param(
diff --git a/compiler/rustc_expand/src/mbe/macro_parser.rs b/compiler/rustc_expand/src/mbe/macro_parser.rs
index 0c44f5f..1aed42a 100644
--- a/compiler/rustc_expand/src/mbe/macro_parser.rs
+++ b/compiler/rustc_expand/src/mbe/macro_parser.rs
@@ -77,9 +77,9 @@
use crate::mbe::{self, TokenTree};
use rustc_ast::token::{self, DocComment, Nonterminal, Token};
-use rustc_parse::parser::{OrPatNonterminalMode, Parser};
+use rustc_parse::parser::Parser;
use rustc_session::parse::ParseSess;
-use rustc_span::{edition::Edition, symbol::MacroRulesNormalizedIdent};
+use rustc_span::symbol::MacroRulesNormalizedIdent;
use smallvec::{smallvec, SmallVec};
@@ -419,18 +419,6 @@
}
}
-/// In edition 2015/18, `:pat` can only match `pat<no_top_alt>` because otherwise, we have
-/// breakage. As of edition 2021, `:pat` matches `top_pat`.
-///
-/// See <https://github.com/rust-lang/rust/issues/54883> for more info.
-fn or_pat_mode(edition: Edition) -> OrPatNonterminalMode {
- match edition {
- Edition::Edition2015 | Edition::Edition2018 => OrPatNonterminalMode::NoTopAlt,
- // FIXME(mark-i-m): uncomment this when edition 2021 machinery is added.
- // Edition::Edition2021 => OrPatNonterminalMode::TopPat,
- }
-}
-
/// Process the matcher positions of `cur_items` until it is empty. In the process, this will
/// produce more items in `next_items`, `eof_items`, and `bb_items`.
///
@@ -512,7 +500,7 @@
if idx == len && item.sep.is_some() {
// We have a separator, and it is the current token. We can advance past the
// separator token.
- if item.sep.as_ref().map(|sep| token_name_eq(token, sep)).unwrap_or(false) {
+ if item.sep.as_ref().map_or(false, |sep| token_name_eq(token, sep)) {
item.idx += 1;
next_items.push(item);
}
@@ -578,14 +566,13 @@
// We need to match a metavar with a valid ident... call out to the black-box
// parser by adding an item to `bb_items`.
- TokenTree::MetaVarDecl(span, _, Some(kind)) => {
+ TokenTree::MetaVarDecl(_, _, Some(kind)) => {
// Built-in nonterminals never start with these tokens, so we can eliminate
// them from consideration.
//
// We use the span of the metavariable declaration to determine any
// edition-specific matching behavior for non-terminals.
- if Parser::nonterminal_may_begin_with(kind, token, or_pat_mode(span.edition()))
- {
+ if Parser::nonterminal_may_begin_with(kind, token) {
bb_items.push(item);
}
}
@@ -749,8 +736,7 @@
let match_cur = item.match_cur;
// We use the span of the metavariable declaration to determine any
// edition-specific matching behavior for non-terminals.
- let nt = match parser.to_mut().parse_nonterminal(kind, or_pat_mode(span.edition()))
- {
+ let nt = match parser.to_mut().parse_nonterminal(kind) {
Err(mut err) => {
err.span_label(
span,
diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs
index 89d375b..73fbde7 100644
--- a/compiler/rustc_expand/src/mbe/macro_rules.rs
+++ b/compiler/rustc_expand/src/mbe/macro_rules.rs
@@ -11,12 +11,14 @@
use rustc_ast as ast;
use rustc_ast::token::{self, NonterminalKind, NtTT, Token, TokenKind::*};
use rustc_ast::tokenstream::{DelimSpan, TokenStream};
+use rustc_ast::NodeId;
use rustc_ast_pretty::pprust;
use rustc_attr::{self as attr, TransparencyError};
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::sync::Lrc;
use rustc_errors::{Applicability, DiagnosticBuilder};
use rustc_feature::Features;
+use rustc_lint_defs::builtin::SEMICOLON_IN_EXPRESSIONS_FROM_MACROS;
use rustc_parse::parser::Parser;
use rustc_session::parse::ParseSess;
use rustc_session::Session;
@@ -37,6 +39,7 @@
site_span: Span,
/// The ident of the macro we're parsing
macro_ident: Ident,
+ lint_node_id: NodeId,
arm_span: Span,
}
@@ -56,36 +59,11 @@
};
}
-/// Instead of e.g. `vec![a, b, c]` in a pattern context, suggest `[a, b, c]`.
-fn suggest_slice_pat(e: &mut DiagnosticBuilder<'_>, site_span: Span, parser: &Parser<'_>) {
- let mut suggestion = None;
- if let Ok(code) = parser.sess.source_map().span_to_snippet(site_span) {
- if let Some(bang) = code.find('!') {
- suggestion = Some(code[bang + 1..].to_string());
- }
- }
- if let Some(suggestion) = suggestion {
- e.span_suggestion(
- site_span,
- "use a slice pattern here instead",
- suggestion,
- Applicability::MachineApplicable,
- );
- } else {
- e.span_label(site_span, "use a slice pattern here instead");
- }
- e.help(
- "for more information, see https://doc.rust-lang.org/edition-guide/\
- rust-2018/slice-patterns.html",
- );
-}
-
fn emit_frag_parse_err(
mut e: DiagnosticBuilder<'_>,
parser: &Parser<'_>,
orig_parser: &mut Parser<'_>,
site_span: Span,
- macro_ident: Ident,
arm_span: Span,
kind: AstFragmentKind,
) {
@@ -113,9 +91,6 @@
e.span_label(site_span, "in this macro invocation");
}
match kind {
- AstFragmentKind::Pat if macro_ident.name == sym::vec => {
- suggest_slice_pat(&mut e, site_span, parser);
- }
// Try a statement if an expression is wanted but failed and suggest adding `;` to call.
AstFragmentKind::Expr => match parse_ast_fragment(orig_parser, AstFragmentKind::Stmts) {
Err(mut err) => err.cancel(),
@@ -138,12 +113,13 @@
impl<'a> ParserAnyMacro<'a> {
crate fn make(mut self: Box<ParserAnyMacro<'a>>, kind: AstFragmentKind) -> AstFragment {
- let ParserAnyMacro { site_span, macro_ident, ref mut parser, arm_span } = *self;
+ let ParserAnyMacro { site_span, macro_ident, ref mut parser, lint_node_id, arm_span } =
+ *self;
let snapshot = &mut parser.clone();
let fragment = match parse_ast_fragment(parser, kind) {
Ok(f) => f,
Err(err) => {
- emit_frag_parse_err(err, parser, snapshot, site_span, macro_ident, arm_span, kind);
+ emit_frag_parse_err(err, parser, snapshot, site_span, arm_span, kind);
return kind.dummy(site_span);
}
};
@@ -152,6 +128,12 @@
// `macro_rules! m { () => { panic!(); } }` isn't parsed by `.parse_expr()`,
// but `m!()` is allowed in expression positions (cf. issue #34706).
if kind == AstFragmentKind::Expr && parser.token == token::Semi {
+ parser.sess.buffer_lint(
+ SEMICOLON_IN_EXPRESSIONS_FROM_MACROS,
+ parser.token.span,
+ lint_node_id,
+ "trailing semicolon in macro used in expression position",
+ );
parser.bump();
}
@@ -203,7 +185,7 @@
}
fn trace_macros_note(cx_expansions: &mut FxHashMap<Span, Vec<String>>, sp: Span, message: String) {
- let sp = sp.macro_backtrace().last().map(|trace| trace.call_site).unwrap_or(sp);
+ let sp = sp.macro_backtrace().last().map_or(sp, |trace| trace.call_site);
cx_expansions.entry(sp).or_default().push(message);
}
@@ -304,6 +286,7 @@
let mut p = Parser::new(sess, tts, false, None);
p.last_type_ascription = cx.current_expansion.prior_type_ascription;
+ let lint_node_id = cx.resolver.lint_node_id(cx.current_expansion.id);
// Let the context choose how to interpret the result.
// Weird, but useful for X-macros.
@@ -315,6 +298,7 @@
// macro leaves unparsed tokens.
site_span: sp,
macro_ident: name,
+ lint_node_id,
arm_span,
});
}
@@ -476,10 +460,15 @@
.map(|m| {
if let MatchedNonterminal(ref nt) = *m {
if let NtTT(ref tt) = **nt {
- let tt =
- mbe::quoted::parse(tt.clone().into(), true, &sess.parse_sess, def.id)
- .pop()
- .unwrap();
+ let tt = mbe::quoted::parse(
+ tt.clone().into(),
+ true,
+ &sess.parse_sess,
+ def.id,
+ features,
+ )
+ .pop()
+ .unwrap();
valid &= check_lhs_nt_follows(&sess.parse_sess, features, &def.attrs, &tt);
return tt;
}
@@ -501,6 +490,7 @@
false,
&sess.parse_sess,
def.id,
+ features,
)
.pop()
.unwrap();
@@ -1090,7 +1080,7 @@
_ => IsInFollow::No(TOKENS),
}
}
- NonterminalKind::Pat => {
+ NonterminalKind::Pat2018 { .. } | NonterminalKind::Pat2021 { .. } => {
const TOKENS: &[&str] = &["`=>`", "`,`", "`=`", "`|`", "`if`", "`in`"];
match tok {
TokenTree::Token(token) => match token.kind {
diff --git a/compiler/rustc_expand/src/mbe/quoted.rs b/compiler/rustc_expand/src/mbe/quoted.rs
index 01b11bb..c804949 100644
--- a/compiler/rustc_expand/src/mbe/quoted.rs
+++ b/compiler/rustc_expand/src/mbe/quoted.rs
@@ -5,8 +5,9 @@
use rustc_ast::tokenstream;
use rustc_ast::{NodeId, DUMMY_NODE_ID};
use rustc_ast_pretty::pprust;
-use rustc_session::parse::ParseSess;
-use rustc_span::symbol::{kw, Ident};
+use rustc_feature::Features;
+use rustc_session::parse::{feature_err, ParseSess};
+use rustc_span::symbol::{kw, sym, Ident};
use rustc_span::Span;
@@ -29,10 +30,8 @@
/// `ident` are "matchers". They are not present in the body of a macro rule -- just in the
/// pattern, so we pass a parameter to indicate whether to expect them or not.
/// - `sess`: the parsing session. Any errors will be emitted to this session.
-/// - `features`, `attrs`: language feature flags and attributes so that we know whether to use
-/// unstable features or not.
-/// - `edition`: which edition are we in.
-/// - `macro_node_id`: the NodeId of the macro we are parsing.
+/// - `node_id`: the NodeId of the macro we are parsing.
+/// - `features`: language features so we can do feature gating.
///
/// # Returns
///
@@ -42,6 +41,7 @@
expect_matchers: bool,
sess: &ParseSess,
node_id: NodeId,
+ features: &Features,
) -> Vec<TokenTree> {
// Will contain the final collection of `self::TokenTree`
let mut result = Vec::new();
@@ -52,7 +52,7 @@
while let Some(tree) = trees.next() {
// Given the parsed tree, if there is a metavar and we are expecting matchers, actually
// parse out the matcher (i.e., in `$id:ident` this would parse the `:` and `ident`).
- let tree = parse_tree(tree, &mut trees, expect_matchers, sess, node_id);
+ let tree = parse_tree(tree, &mut trees, expect_matchers, sess, node_id, features);
match tree {
TokenTree::MetaVar(start_sp, ident) if expect_matchers => {
let span = match trees.next() {
@@ -61,27 +61,48 @@
Some(tokenstream::TokenTree::Token(token)) => match token.ident() {
Some((frag, _)) => {
let span = token.span.with_lo(start_sp.lo());
- let kind = token::NonterminalKind::from_symbol(frag.name)
- .unwrap_or_else(|| {
- let msg = format!(
- "invalid fragment specifier `{}`",
- frag.name
- );
- sess.span_diagnostic
- .struct_span_err(span, &msg)
- .help(VALID_FRAGMENT_NAMES_MSG)
+
+ match frag.name {
+ sym::pat2018 | sym::pat2021 => {
+ if !features.edition_macro_pats {
+ feature_err(
+ sess,
+ sym::edition_macro_pats,
+ frag.span,
+ "`pat2018` and `pat2021` are unstable.",
+ )
.emit();
- token::NonterminalKind::Ident
- });
+ }
+ }
+ _ => {}
+ }
+
+ let kind =
+ token::NonterminalKind::from_symbol(frag.name, || {
+ span.edition()
+ })
+ .unwrap_or_else(
+ || {
+ let msg = format!(
+ "invalid fragment specifier `{}`",
+ frag.name
+ );
+ sess.span_diagnostic
+ .struct_span_err(span, &msg)
+ .help(VALID_FRAGMENT_NAMES_MSG)
+ .emit();
+ token::NonterminalKind::Ident
+ },
+ );
result.push(TokenTree::MetaVarDecl(span, ident, Some(kind)));
continue;
}
_ => token.span,
},
- tree => tree.as_ref().map(tokenstream::TokenTree::span).unwrap_or(span),
+ tree => tree.as_ref().map_or(span, tokenstream::TokenTree::span),
}
}
- tree => tree.as_ref().map(tokenstream::TokenTree::span).unwrap_or(start_sp),
+ tree => tree.as_ref().map_or(start_sp, tokenstream::TokenTree::span),
};
if node_id != DUMMY_NODE_ID {
// Macros loaded from other crates have dummy node ids.
@@ -110,14 +131,14 @@
/// converting `tree`
/// - `expect_matchers`: same as for `parse` (see above).
/// - `sess`: the parsing session. Any errors will be emitted to this session.
-/// - `features`, `attrs`: language feature flags and attributes so that we know whether to use
-/// unstable features or not.
+/// - `features`: language features so we can do feature gating.
fn parse_tree(
tree: tokenstream::TokenTree,
outer_trees: &mut impl Iterator<Item = tokenstream::TokenTree>,
expect_matchers: bool,
sess: &ParseSess,
node_id: NodeId,
+ features: &Features,
) -> TokenTree {
// Depending on what `tree` is, we could be parsing different parts of a macro
match tree {
@@ -145,7 +166,7 @@
sess.span_diagnostic.span_err(span.entire(), &msg);
}
// Parse the contents of the sequence itself
- let sequence = parse(tts, expect_matchers, sess, node_id);
+ let sequence = parse(tts, expect_matchers, sess, node_id, features);
// Get the Kleene operator and optional separator
let (separator, kleene) =
parse_sep_and_kleene_op(&mut trees, span.entire(), sess);
@@ -196,7 +217,10 @@
// descend into the delimited set and further parse it.
tokenstream::TokenTree::Delimited(span, delim, tts) => TokenTree::Delimited(
span,
- Lrc::new(Delimited { delim, tts: parse(tts, expect_matchers, sess, node_id) }),
+ Lrc::new(Delimited {
+ delim,
+ tts: parse(tts, expect_matchers, sess, node_id, features),
+ }),
),
}
}
@@ -226,7 +250,7 @@
Some(op) => Ok(Ok((op, token.span))),
None => Ok(Err(token)),
},
- tree => Err(tree.as_ref().map(tokenstream::TokenTree::span).unwrap_or(span)),
+ tree => Err(tree.as_ref().map_or(span, tokenstream::TokenTree::span)),
}
}
diff --git a/compiler/rustc_expand/src/parse/tests.rs b/compiler/rustc_expand/src/parse/tests.rs
index 643305f..f4fcaf5 100644
--- a/compiler/rustc_expand/src/parse/tests.rs
+++ b/compiler/rustc_expand/src/parse/tests.rs
@@ -8,6 +8,7 @@
use rustc_ast_pretty::pprust::item_to_string;
use rustc_errors::PResult;
use rustc_parse::new_parser_from_source_str;
+use rustc_parse::parser::ForceCollect;
use rustc_session::parse::ParseSess;
use rustc_span::source_map::FilePathMapping;
use rustc_span::symbol::{kw, sym, Symbol};
@@ -29,7 +30,7 @@
source: String,
sess: &ParseSess,
) -> PResult<'_, Option<P<ast::Item>>> {
- new_parser_from_source_str(sess, name, source).parse_item()
+ new_parser_from_source_str(sess, name, source).parse_item(ForceCollect::No)
}
// Produces a `rustc_span::span`.
@@ -44,7 +45,7 @@
/// Parses a string, returns an item.
fn string_to_item(source_str: String) -> Option<P<ast::Item>> {
- with_error_checking_parse(source_str, &sess(), |p| p.parse_item())
+ with_error_checking_parse(source_str, &sess(), |p| p.parse_item(ForceCollect::No))
}
#[should_panic]
diff --git a/compiler/rustc_expand/src/placeholders.rs b/compiler/rustc_expand/src/placeholders.rs
index ce19e81..d040539c 100644
--- a/compiler/rustc_expand/src/placeholders.rs
+++ b/compiler/rustc_expand/src/placeholders.rs
@@ -258,12 +258,9 @@
fn flat_map_item(&mut self, item: P<ast::Item>) -> SmallVec<[P<ast::Item>; 1]> {
match item.kind {
- ast::ItemKind::MacCall(_) => return self.remove(item.id).make_items(),
- ast::ItemKind::MacroDef(_) => return smallvec![item],
- _ => {}
+ ast::ItemKind::MacCall(_) => self.remove(item.id).make_items(),
+ _ => noop_flat_map_item(item, self),
}
-
- noop_flat_map_item(item, self)
}
fn flat_map_trait_item(&mut self, item: P<ast::AssocItem>) -> SmallVec<[P<ast::AssocItem>; 1]> {
diff --git a/compiler/rustc_expand/src/proc_macro.rs b/compiler/rustc_expand/src/proc_macro.rs
index 36707a1..6779734 100644
--- a/compiler/rustc_expand/src/proc_macro.rs
+++ b/compiler/rustc_expand/src/proc_macro.rs
@@ -3,12 +3,13 @@
use rustc_ast::ptr::P;
use rustc_ast::token;
-use rustc_ast::tokenstream::{TokenStream, TokenTree};
+use rustc_ast::tokenstream::{CanSynthesizeMissingTokens, TokenStream, TokenTree};
use rustc_ast::{self as ast, *};
use rustc_data_structures::sync::Lrc;
use rustc_errors::{struct_span_err, Applicability, ErrorReported};
use rustc_lexer::is_ident;
use rustc_parse::nt_to_tokenstream;
+use rustc_parse::parser::ForceCollect;
use rustc_span::symbol::sym;
use rustc_span::{Span, DUMMY_SP};
@@ -94,7 +95,7 @@
let input = if item.pretty_printing_compatibility_hack() {
TokenTree::token(token::Interpolated(Lrc::new(item)), DUMMY_SP).into()
} else {
- nt_to_tokenstream(&item, &ecx.sess.parse_sess, DUMMY_SP)
+ nt_to_tokenstream(&item, &ecx.sess.parse_sess, CanSynthesizeMissingTokens::Yes)
};
let server = proc_macro_server::Rustc::new(ecx);
@@ -117,7 +118,7 @@
let mut items = vec![];
loop {
- match parser.parse_item() {
+ match parser.parse_item(ForceCollect::No) {
Ok(None) => break,
Ok(Some(item)) => {
if is_stmt {
diff --git a/compiler/rustc_expand/src/proc_macro_server.rs b/compiler/rustc_expand/src/proc_macro_server.rs
index 4cfb188..b6195d3 100644
--- a/compiler/rustc_expand/src/proc_macro_server.rs
+++ b/compiler/rustc_expand/src/proc_macro_server.rs
@@ -2,7 +2,8 @@
use rustc_ast as ast;
use rustc_ast::token;
-use rustc_ast::tokenstream::{self, DelimSpan, Spacing::*, TokenStream, TreeAndSpacing};
+use rustc_ast::tokenstream::{self, CanSynthesizeMissingTokens};
+use rustc_ast::tokenstream::{DelimSpan, Spacing::*, TokenStream, TreeAndSpacing};
use rustc_ast_pretty::pprust;
use rustc_data_structures::sync::Lrc;
use rustc_errors::Diagnostic;
@@ -178,7 +179,7 @@
{
TokenTree::Ident(Ident::new(sess, name.name, is_raw, name.span))
} else {
- let stream = nt_to_tokenstream(&nt, sess, span);
+ let stream = nt_to_tokenstream(&nt, sess, CanSynthesizeMissingTokens::No);
TokenTree::Group(Group {
delimiter: Delimiter::None,
stream,
diff --git a/compiler/rustc_expand/src/tests.rs b/compiler/rustc_expand/src/tests.rs
index 6993ce5..f2345ff 100644
--- a/compiler/rustc_expand/src/tests.rs
+++ b/compiler/rustc_expand/src/tests.rs
@@ -92,7 +92,7 @@
/// Advances the given peekable `Iterator` until it reaches a non-whitespace character.
fn scan_for_non_ws_or_end<I: Iterator<Item = char>>(iter: &mut Peekable<I>) {
- while iter.peek().copied().map(|c| rustc_lexer::is_whitespace(c)) == Some(true) {
+ while iter.peek().copied().map(rustc_lexer::is_whitespace) == Some(true) {
iter.next();
}
}
diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs
index 4401ec0..aa54ffb 100644
--- a/compiler/rustc_feature/src/accepted.rs
+++ b/compiler/rustc_feature/src/accepted.rs
@@ -273,6 +273,8 @@
/// Allows patterns with concurrent by-move and by-ref bindings.
/// For example, you can write `Foo(a, ref b)` where `a` is by-move and `b` is by-ref.
(accepted, move_ref_pattern, "1.48.0", Some(68354), None),
+ /// The smallest useful subset of `const_generics`.
+ (accepted, min_const_generics, "1.51.0", Some(74878), None),
// -------------------------------------------------------------------------
// feature-group-end: accepted features
diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs
index 845e031..4f38e06 100644
--- a/compiler/rustc_feature/src/active.rs
+++ b/compiler/rustc_feature/src/active.rs
@@ -36,7 +36,7 @@
),+];
/// A set of features to be used by later passes.
- #[derive(Clone, Default)]
+ #[derive(Clone, Default, Debug)]
pub struct Features {
/// `#![feature]` attrs for language features, for error reporting.
pub declared_lang_features: Vec<(Symbol, Span, Option<Symbol>)>,
@@ -485,9 +485,6 @@
/// Allows `async || body` closures.
(active, async_closure, "1.37.0", Some(62290), None),
- /// Allows `[x; N]` where `x` is a constant (RFC 2203).
- (active, const_in_array_repeat_expressions, "1.37.0", Some(49147), None),
-
/// Allows `impl Trait` to be used inside type aliases (RFC 2515).
(active, type_alias_impl_trait, "1.38.0", Some(63063), None),
@@ -578,13 +575,10 @@
/// Allows calling `transmute` in const fn
(active, const_fn_transmute, "1.46.0", Some(53605), None),
- /// The smallest useful subset of `const_generics`.
- (active, min_const_generics, "1.47.0", Some(74878), None),
-
/// Allows `if let` guard in match arms.
(active, if_let_guard, "1.47.0", Some(51114), None),
- /// Allows non-trivial generic constants which have to be manually propageted upwards.
+ /// Allows non-trivial generic constants which have to be manually propagated upwards.
(active, const_evaluatable_checked, "1.48.0", Some(76560), None),
/// Allows basic arithmetic on floating point types in a `const fn`.
@@ -623,6 +617,23 @@
/// Allows arbitrary expressions in key-value attributes at parse time.
(active, extended_key_value_attributes, "1.50.0", Some(78835), None),
+ /// `:pat2018` and `:pat2021` macro matchers.
+ (active, edition_macro_pats, "1.51.0", Some(54883), None),
+
+ /// Allows const generics to have default values (e.g. `struct Foo<const N: usize = 3>(...);`).
+ (active, const_generics_defaults, "1.51.0", Some(44580), None),
+
+ /// Allows references to types with interior mutability within constants
+ (active, const_refs_to_cell, "1.51.0", Some(80384), None),
+
+ /// Allows using `pointer` and `reference` in intra-doc links
+ (active, intra_doc_pointers, "1.51.0", Some(80896), None),
+
+ /// Allows `extern "C-cmse-nonsecure-call" fn()`.
+ (active, abi_c_cmse_nonsecure_call, "1.51.0", Some(81391), None),
+
+ /// Lessens the requirements for structs to implement `Unsize`.
+ (active, relaxed_struct_unsize, "1.51.0", Some(1), None),
// -------------------------------------------------------------------------
// feature-group-end: actual feature gates
// -------------------------------------------------------------------------
@@ -647,9 +658,12 @@
sym::repr128,
sym::unsized_locals,
sym::capture_disjoint_fields,
+ sym::const_generics_defaults,
];
/// Some features are not allowed to be used together at the same time, if
/// the two are present, produce an error.
-pub const INCOMPATIBLE_FEATURES: &[(Symbol, Symbol)] =
- &[(sym::const_generics, sym::min_const_generics)];
+///
+/// Currently empty, but we will probably need this again in the future,
+/// so let's keep it in for now.
+pub const INCOMPATIBLE_FEATURES: &[(Symbol, Symbol)] = &[];
diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs
index fa8edba..3ed5320 100644
--- a/compiler/rustc_feature/src/builtin_attrs.rs
+++ b/compiler/rustc_feature/src/builtin_attrs.rs
@@ -442,7 +442,7 @@
// Internal attributes, Macro related:
// ==========================================================================
- rustc_attr!(rustc_builtin_macro, AssumedUsed, template!(Word), IMPL_DETAIL),
+ rustc_attr!(rustc_builtin_macro, AssumedUsed, template!(Word, NameValueStr: "name"), IMPL_DETAIL),
rustc_attr!(rustc_proc_macro_decls, Normal, template!(Word), INTERNAL_UNSTABLE),
rustc_attr!(
rustc_macro_transparency, AssumedUsed,
diff --git a/compiler/rustc_feature/src/removed.rs b/compiler/rustc_feature/src/removed.rs
index 07bd160..38a3a4e 100644
--- a/compiler/rustc_feature/src/removed.rs
+++ b/compiler/rustc_feature/src/removed.rs
@@ -97,6 +97,9 @@
(removed, extern_in_paths, "1.33.0", Some(55600), None,
Some("subsumed by `::foo::bar` paths")),
(removed, quote, "1.33.0", Some(29601), None, None),
+ /// Allows `[x; N]` where `x` is a constant (RFC 2203).
+ (removed, const_in_array_repeat_expressions, "1.37.0", Some(49147), None,
+ Some("removed due to causing promotable bugs")),
/// Allows using `#[unsafe_destructor_blind_to_params]` (RFC 1238).
(removed, dropck_parametricity, "1.38.0", Some(28498), None, None),
(removed, await_macro, "1.38.0", Some(50547), None,
diff --git a/compiler/rustc_fs_util/src/lib.rs b/compiler/rustc_fs_util/src/lib.rs
index 7742961..87e97c7 100644
--- a/compiler/rustc_fs_util/src/lib.rs
+++ b/compiler/rustc_fs_util/src/lib.rs
@@ -62,8 +62,10 @@
pub fn link_or_copy<P: AsRef<Path>, Q: AsRef<Path>>(p: P, q: Q) -> io::Result<LinkOrCopy> {
let p = p.as_ref();
let q = q.as_ref();
- if q.exists() {
- fs::remove_file(&q)?;
+ match fs::remove_file(&q) {
+ Ok(()) => (),
+ Err(err) if err.kind() == io::ErrorKind::NotFound => (),
+ Err(err) => return Err(err),
}
match fs::hard_link(p, q) {
diff --git a/compiler/rustc_graphviz/src/tests.rs b/compiler/rustc_graphviz/src/tests.rs
index 055e131..70b8197 100644
--- a/compiler/rustc_graphviz/src/tests.rs
+++ b/compiler/rustc_graphviz/src/tests.rs
@@ -55,7 +55,7 @@
fn to_opt_strs(self) -> Vec<Option<&'static str>> {
match self {
UnlabelledNodes(len) => vec![None; len],
- AllNodesLabelled(lbls) => lbls.into_iter().map(|l| Some(l)).collect(),
+ AllNodesLabelled(lbls) => lbls.into_iter().map(Some).collect(),
SomeNodesLabelled(lbls) => lbls.into_iter().collect(),
}
}
diff --git a/compiler/rustc_hir/Cargo.toml b/compiler/rustc_hir/Cargo.toml
index b24c208..c141654 100644
--- a/compiler/rustc_hir/Cargo.toml
+++ b/compiler/rustc_hir/Cargo.toml
@@ -9,6 +9,7 @@
[dependencies]
rustc_target = { path = "../rustc_target" }
+rustc_feature = { path = "../rustc_feature" }
rustc_macros = { path = "../rustc_macros" }
rustc_data_structures = { path = "../rustc_data_structures" }
rustc_index = { path = "../rustc_index" }
diff --git a/compiler/rustc_hir/src/def.rs b/compiler/rustc_hir/src/def.rs
index 4ede9d6..a81eb74 100644
--- a/compiler/rustc_hir/src/def.rs
+++ b/compiler/rustc_hir/src/def.rs
@@ -5,6 +5,7 @@
use rustc_ast::NodeId;
use rustc_macros::HashStable_Generic;
use rustc_span::hygiene::MacroKind;
+use rustc_span::Symbol;
use std::array::IntoIter;
use std::fmt::Debug;
@@ -34,7 +35,7 @@
#[derive(HashStable_Generic)]
pub enum NonMacroAttrKind {
/// Single-segment attribute defined by the language (`#[inline]`)
- Builtin,
+ Builtin(Symbol),
/// Multi-segment custom attribute living in a "tool module" (`#[rustfmt::skip]`).
Tool,
/// Single-segment custom attribute registered by a derive macro (`#[serde(default)]`).
@@ -371,7 +372,7 @@
impl NonMacroAttrKind {
pub fn descr(self) -> &'static str {
match self {
- NonMacroAttrKind::Builtin => "built-in attribute",
+ NonMacroAttrKind::Builtin(..) => "built-in attribute",
NonMacroAttrKind::Tool => "tool attribute",
NonMacroAttrKind::DeriveHelper | NonMacroAttrKind::DeriveHelperCompat => {
"derive helper attribute"
@@ -393,7 +394,7 @@
NonMacroAttrKind::Tool
| NonMacroAttrKind::DeriveHelper
| NonMacroAttrKind::DeriveHelperCompat => true,
- NonMacroAttrKind::Builtin | NonMacroAttrKind::Registered => false,
+ NonMacroAttrKind::Builtin(..) | NonMacroAttrKind::Registered => false,
}
}
}
diff --git a/compiler/rustc_hir/src/definitions.rs b/compiler/rustc_hir/src/definitions.rs
index d5ade86..6a1b9bd 100644
--- a/compiler/rustc_hir/src/definitions.rs
+++ b/compiler/rustc_hir/src/definitions.rs
@@ -419,6 +419,10 @@
pub fn add_parent_module_of_macro_def(&mut self, expn_id: ExpnId, module: DefId) {
self.parent_modules_of_macro_defs.insert(expn_id, module);
}
+
+ pub fn iter_local_def_id(&self) -> impl Iterator<Item = LocalDefId> + '_ {
+ self.def_id_to_hir_id.iter_enumerated().map(|(k, _)| k)
+ }
}
#[derive(Copy, Clone, PartialEq, Debug)]
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index 2abebbd..67a1541 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -11,9 +11,9 @@
use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
use rustc_data_structures::sync::{par_for_each_in, Send, Sync};
use rustc_macros::HashStable_Generic;
-use rustc_span::def_id::LocalDefId;
-use rustc_span::source_map::Spanned;
+use rustc_span::source_map::{SourceMap, Spanned};
use rustc_span::symbol::{kw, sym, Ident, Symbol};
+use rustc_span::{def_id::LocalDefId, BytePos};
use rustc_span::{MultiSpan, Span, DUMMY_SP};
use rustc_target::asm::InlineAsmRegOrRegClass;
use rustc_target::spec::abi::Abi;
@@ -28,7 +28,7 @@
pub span: Span,
/// Either "`'a`", referring to a named lifetime definition,
- /// or "``" (i.e., `kw::Invalid`), for elision placeholders.
+ /// or "``" (i.e., `kw::Empty`), for elision placeholders.
///
/// HIR lowering inserts these placeholders in type paths that
/// refer to type definitions needing lifetime parameters,
@@ -231,7 +231,11 @@
PathSegment { ident, hir_id: None, res: None, infer_args: true, args: None }
}
- pub fn generic_args(&self) -> &GenericArgs<'hir> {
+ pub fn invalid() -> Self {
+ Self::from_ident(Ident::invalid())
+ }
+
+ pub fn args(&self) -> &GenericArgs<'hir> {
if let Some(ref args) = self.args {
args
} else {
@@ -275,6 +279,10 @@
matches!(self, GenericArg::Const(_))
}
+ pub fn is_synthetic(&self) -> bool {
+ matches!(self, GenericArg::Lifetime(lifetime) if lifetime.name.ident() == Ident::invalid())
+ }
+
pub fn descr(&self) -> &'static str {
match self {
GenericArg::Lifetime(_) => "lifetime",
@@ -283,11 +291,11 @@
}
}
- pub fn short_descr(&self) -> &'static str {
+ pub fn to_ord(&self, feats: &rustc_feature::Features) -> ast::ParamKindOrd {
match self {
- GenericArg::Lifetime(_) => "lifetime",
- GenericArg::Type(_) => "type",
- GenericArg::Const(_) => "const",
+ GenericArg::Lifetime(_) => ast::ParamKindOrd::Lifetime,
+ GenericArg::Type(_) => ast::ParamKindOrd::Type,
+ GenericArg::Const(_) => ast::ParamKindOrd::Const { unordered: feats.const_generics },
}
}
}
@@ -344,6 +352,39 @@
own_counts
}
+
+ pub fn span(&self) -> Option<Span> {
+ self.args
+ .iter()
+ .filter(|arg| !arg.is_synthetic())
+ .map(|arg| arg.span())
+ .reduce(|span1, span2| span1.to(span2))
+ }
+
+ /// Returns span encompassing arguments and their surrounding `<>` or `()`
+ pub fn span_ext(&self, sm: &SourceMap) -> Option<Span> {
+ let mut span = self.span()?;
+
+ let (o, c) = if self.parenthesized { ('(', ')') } else { ('<', '>') };
+
+ if let Ok(snippet) = sm.span_to_snippet(span) {
+ let snippet = snippet.as_bytes();
+
+ if snippet[0] != (o as u8) || snippet[snippet.len() - 1] != (c as u8) {
+ span = sm.span_extend_to_prev_char(span, o, true);
+ span = span.with_lo(span.lo() - BytePos(1));
+
+ span = sm.span_extend_to_next_char(span, c, true);
+ span = span.with_hi(span.hi() + BytePos(1));
+ }
+ }
+
+ Some(span)
+ }
+
+ pub fn is_empty(&self) -> bool {
+ self.args.is_empty()
+ }
}
/// A modifier on a bound, currently this is only used for `?Sized`, where the
@@ -378,9 +419,9 @@
pub fn span(&self) -> Span {
match self {
- &GenericBound::Trait(ref t, ..) => t.span,
- &GenericBound::LangItemTrait(_, span, ..) => span,
- &GenericBound::Outlives(ref l) => l.span,
+ GenericBound::Trait(t, ..) => t.span,
+ GenericBound::LangItemTrait(_, span, ..) => *span,
+ GenericBound::Outlives(l) => l.span,
}
}
}
@@ -418,6 +459,8 @@
},
Const {
ty: &'hir Ty<'hir>,
+ /// Optional default value for the const generic param
+ default: Option<AnonConst>,
},
}
@@ -518,7 +561,7 @@
/// in `fn foo<T>(t: T) where T: Foo,` so we don't suggest two trailing commas.
pub fn tail_span_for_suggestion(&self) -> Span {
let end = self.span_for_predicates_or_empty_place().shrink_to_hi();
- self.predicates.last().map(|p| p.span()).unwrap_or(end).shrink_to_hi().to(end)
+ self.predicates.last().map_or(end, |p| p.span()).shrink_to_hi().to(end)
}
}
@@ -536,9 +579,9 @@
impl WherePredicate<'_> {
pub fn span(&self) -> Span {
match self {
- &WherePredicate::BoundPredicate(ref p) => p.span,
- &WherePredicate::RegionPredicate(ref p) => p.span,
- &WherePredicate::EqPredicate(ref p) => p.span,
+ WherePredicate::BoundPredicate(p) => p.span,
+ WherePredicate::RegionPredicate(p) => p.span,
+ WherePredicate::EqPredicate(p) => p.span,
}
}
}
@@ -607,7 +650,7 @@
// over the ids in increasing order. In principle it should not
// matter what order we visit things in, but in *practice* it
// does, because it can affect the order in which errors are
- // detected, which in turn can make compile-fail tests yield
+ // detected, which in turn can make UI tests yield
// slightly different results.
pub items: BTreeMap<HirId, Item<'hir>>,
@@ -760,9 +803,9 @@
pub default_binding_modes: bool,
}
-impl Pat<'_> {
+impl<'hir> Pat<'hir> {
// FIXME(#19596) this is a workaround, but there should be a better way
- fn walk_short_(&self, it: &mut impl FnMut(&Pat<'_>) -> bool) -> bool {
+ fn walk_short_(&self, it: &mut impl FnMut(&Pat<'hir>) -> bool) -> bool {
if !it(self) {
return false;
}
@@ -785,12 +828,12 @@
/// Note that when visiting e.g. `Tuple(ps)`,
/// if visiting `ps[0]` returns `false`,
/// then `ps[1]` will not be visited.
- pub fn walk_short(&self, mut it: impl FnMut(&Pat<'_>) -> bool) -> bool {
+ pub fn walk_short(&self, mut it: impl FnMut(&Pat<'hir>) -> bool) -> bool {
self.walk_short_(&mut it)
}
// FIXME(#19596) this is a workaround, but there should be a better way
- fn walk_(&self, it: &mut impl FnMut(&Pat<'_>) -> bool) {
+ fn walk_(&self, it: &mut impl FnMut(&Pat<'hir>) -> bool) {
if !it(self) {
return;
}
@@ -810,7 +853,7 @@
/// Walk the pattern in left-to-right order.
///
/// If `it(pat)` returns `false`, the children are not visited.
- pub fn walk(&self, mut it: impl FnMut(&Pat<'_>) -> bool) {
+ pub fn walk(&self, mut it: impl FnMut(&Pat<'hir>) -> bool) {
self.walk_(&mut it)
}
@@ -1388,6 +1431,7 @@
ExprKind::Lit(_) => ExprPrecedence::Lit,
ExprKind::Type(..) | ExprKind::Cast(..) => ExprPrecedence::Cast,
ExprKind::DropTemps(ref expr, ..) => expr.precedence(),
+ ExprKind::If(..) => ExprPrecedence::If,
ExprKind::Loop(..) => ExprPrecedence::Loop,
ExprKind::Match(..) => ExprPrecedence::Match,
ExprKind::Closure(..) => ExprPrecedence::Closure,
@@ -1449,6 +1493,7 @@
| ExprKind::MethodCall(..)
| ExprKind::Struct(..)
| ExprKind::Tup(..)
+ | ExprKind::If(..)
| ExprKind::Match(..)
| ExprKind::Closure(..)
| ExprKind::Block(..)
@@ -1498,10 +1543,10 @@
**qpath,
QPath::LangItem(
LangItem::Range
- | LangItem::RangeTo
- | LangItem::RangeFrom
- | LangItem::RangeFull
- | LangItem::RangeToInclusive,
+ | LangItem::RangeTo
+ | LangItem::RangeFrom
+ | LangItem::RangeFull
+ | LangItem::RangeToInclusive,
_,
)
),
@@ -1565,10 +1610,16 @@
/// This construct only exists to tweak the drop order in HIR lowering.
/// An example of that is the desugaring of `for` loops.
DropTemps(&'hir Expr<'hir>),
+ /// An `if` block, with an optional else block.
+ ///
+ /// I.e., `if <expr> { <expr> } else { <expr> }`.
+ If(&'hir Expr<'hir>, &'hir Expr<'hir>, Option<&'hir Expr<'hir>>),
/// A conditionless loop (can be exited with `break`, `continue`, or `return`).
///
/// I.e., `'label: loop { <block> }`.
- Loop(&'hir Block<'hir>, Option<Label>, LoopSource),
+ ///
+ /// The `Span` is the loop header (`for x in y`/`while let pat = expr`).
+ Loop(&'hir Block<'hir>, Option<Label>, LoopSource, Span),
/// A `match` block, with a source that indicates whether or not it is
/// the result of a desugaring, and if so, which kind.
Match(&'hir Expr<'hir>, &'hir [Arm<'hir>], MatchSource),
@@ -1718,8 +1769,6 @@
pub enum MatchSource {
/// A `match _ { .. }`.
Normal,
- /// An `if _ { .. }` (optionally with `else { .. }`).
- IfDesugar { contains_else_clause: bool },
/// An `if let _ = _ { .. }` (optionally with `else { .. }`).
IfLetDesugar { contains_else_clause: bool },
/// An `if let _ = _ => { .. }` match guard.
@@ -1742,7 +1791,7 @@
use MatchSource::*;
match self {
Normal => "match",
- IfDesugar { .. } | IfLetDesugar { .. } | IfLetGuardDesugar => "if",
+ IfLetDesugar { .. } | IfLetGuardDesugar => "if",
WhileDesugar | WhileLetDesugar => "while",
ForLoopDesugar => "for",
TryDesugar => "?",
@@ -1966,6 +2015,7 @@
pub hir_id: HirId,
#[stable_hasher(project(name))]
pub ident: Ident,
+ pub gen_args: &'hir GenericArgs<'hir>,
pub kind: TypeBindingKind<'hir>,
pub span: Span,
}
@@ -2552,22 +2602,25 @@
TraitAlias(Generics<'hir>, GenericBounds<'hir>),
/// An implementation, e.g., `impl<A> Trait for Foo { .. }`.
- Impl {
- unsafety: Unsafety,
- polarity: ImplPolarity,
- defaultness: Defaultness,
- // We do not put a `Span` in `Defaultness` because it breaks foreign crate metadata
- // decoding as `Span`s cannot be decoded when a `Session` is not available.
- defaultness_span: Option<Span>,
- constness: Constness,
- generics: Generics<'hir>,
+ Impl(Impl<'hir>),
+}
- /// The trait being implemented, if any.
- of_trait: Option<TraitRef<'hir>>,
+#[derive(Debug, HashStable_Generic)]
+pub struct Impl<'hir> {
+ pub unsafety: Unsafety,
+ pub polarity: ImplPolarity,
+ pub defaultness: Defaultness,
+ // We do not put a `Span` in `Defaultness` because it breaks foreign crate metadata
+ // decoding as `Span`s cannot be decoded when a `Session` is not available.
+ pub defaultness_span: Option<Span>,
+ pub constness: Constness,
+ pub generics: Generics<'hir>,
- self_ty: &'hir Ty<'hir>,
- items: &'hir [ImplItemRef<'hir>],
- },
+ /// The trait being implemented, if any.
+ pub of_trait: Option<TraitRef<'hir>>,
+
+ pub self_ty: &'hir Ty<'hir>,
+ pub items: &'hir [ImplItemRef<'hir>],
}
impl ItemKind<'_> {
@@ -2580,7 +2633,7 @@
| ItemKind::Struct(_, ref generics)
| ItemKind::Union(_, ref generics)
| ItemKind::Trait(_, _, ref generics, _, _)
- | ItemKind::Impl { ref generics, .. } => generics,
+ | ItemKind::Impl(Impl { ref generics, .. }) => generics,
_ => return None,
})
}
diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs
index 03c8b17..f8b3f0d 100644
--- a/compiler/rustc_hir/src/intravisit.rs
+++ b/compiler/rustc_hir/src/intravisit.rs
@@ -611,7 +611,7 @@
// `visit_enum_def()` takes care of visiting the `Item`'s `HirId`.
visitor.visit_enum_def(enum_definition, generics, item.hir_id, item.span)
}
- ItemKind::Impl {
+ ItemKind::Impl(Impl {
unsafety: _,
defaultness: _,
polarity: _,
@@ -621,7 +621,7 @@
ref of_trait,
ref self_ty,
items,
- } => {
+ }) => {
visitor.visit_id(item.hir_id);
visitor.visit_generics(generics);
walk_list!(visitor, visit_trait_ref, of_trait);
@@ -781,6 +781,7 @@
) {
visitor.visit_id(type_binding.hir_id);
visitor.visit_ident(type_binding.ident);
+ visitor.visit_generic_args(type_binding.span, type_binding.gen_args);
match type_binding.kind {
TypeBindingKind::Equality { ref ty } => {
visitor.visit_ty(ty);
@@ -877,7 +878,12 @@
match param.kind {
GenericParamKind::Lifetime { .. } => {}
GenericParamKind::Type { ref default, .. } => walk_list!(visitor, visit_ty, default),
- GenericParamKind::Const { ref ty } => visitor.visit_ty(ty),
+ GenericParamKind::Const { ref ty, ref default } => {
+ visitor.visit_ty(ty);
+ if let Some(ref default) = default {
+ visitor.visit_anon_const(default);
+ }
+ }
}
walk_list!(visitor, visit_param_bound, param.bounds);
}
@@ -891,8 +897,8 @@
visitor: &mut V,
predicate: &'v WherePredicate<'v>,
) {
- match predicate {
- &WherePredicate::BoundPredicate(WhereBoundPredicate {
+ match *predicate {
+ WherePredicate::BoundPredicate(WhereBoundPredicate {
ref bounded_ty,
bounds,
bound_generic_params,
@@ -902,11 +908,11 @@
walk_list!(visitor, visit_param_bound, bounds);
walk_list!(visitor, visit_generic_param, bound_generic_params);
}
- &WherePredicate::RegionPredicate(WhereRegionPredicate { ref lifetime, bounds, .. }) => {
+ WherePredicate::RegionPredicate(WhereRegionPredicate { ref lifetime, bounds, .. }) => {
visitor.visit_lifetime(lifetime);
walk_list!(visitor, visit_param_bound, bounds);
}
- &WherePredicate::EqPredicate(WhereEqPredicate {
+ WherePredicate::EqPredicate(WhereEqPredicate {
hir_id, ref lhs_ty, ref rhs_ty, ..
}) => {
visitor.visit_id(hir_id);
@@ -1141,7 +1147,12 @@
ExprKind::DropTemps(ref subexpression) => {
visitor.visit_expr(subexpression);
}
- ExprKind::Loop(ref block, ref opt_label, _) => {
+ ExprKind::If(ref cond, ref then, ref else_opt) => {
+ visitor.visit_expr(cond);
+ visitor.visit_expr(then);
+ walk_list!(visitor, visit_expr, else_opt);
+ }
+ ExprKind::Loop(ref block, ref opt_label, _, _) => {
walk_list!(visitor, visit_label, opt_label);
visitor.visit_block(block);
}
diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs
index 3e4eb9e..26ce30c 100644
--- a/compiler/rustc_hir/src/lang_items.rs
+++ b/compiler/rustc_hir/src/lang_items.rs
@@ -67,7 +67,7 @@
}
}
- #[derive(HashStable_Generic)]
+ #[derive(HashStable_Generic, Debug)]
pub struct LanguageItems {
/// Mappings from lang items to their possibly found `DefId`s.
/// The index corresponds to the order in `LangItem`.
@@ -157,7 +157,7 @@
}
language_item_table! {
-// Variant name, Name, Method name, Target;
+// Variant name, Name, Method name, Target;
Bool, sym::bool, bool_impl, Target::Impl;
Char, sym::char, char_impl, Target::Impl;
Str, sym::str, str_impl, Target::Impl;
diff --git a/compiler/rustc_hir/src/lib.rs b/compiler/rustc_hir/src/lib.rs
index 9d931b3..c69a9b0 100644
--- a/compiler/rustc_hir/src/lib.rs
+++ b/compiler/rustc_hir/src/lib.rs
@@ -2,7 +2,6 @@
//!
//! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/hir.html
-#![feature(array_value_iter)]
#![feature(crate_visibility_modifier)]
#![feature(const_fn)] // For the unsizing cast on `&[]`
#![feature(const_panic)]
diff --git a/compiler/rustc_hir/src/target.rs b/compiler/rustc_hir/src/target.rs
index 2774cc9..6dbcfb9 100644
--- a/compiler/rustc_hir/src/target.rs
+++ b/compiler/rustc_hir/src/target.rs
@@ -38,12 +38,14 @@
Enum,
Variant,
Struct,
+ Field,
Union,
Trait,
TraitAlias,
Impl,
Expression,
Statement,
+ Arm,
AssocConst,
Method(MethodKind),
AssocTy,
@@ -51,6 +53,7 @@
ForeignStatic,
ForeignTy,
GenericParam(GenericParamKind),
+ MacroDef,
}
impl Display for Target {
@@ -73,12 +76,14 @@
Target::Enum => "enum",
Target::Variant => "enum variant",
Target::Struct => "struct",
+ Target::Field => "struct field",
Target::Union => "union",
Target::Trait => "trait",
Target::TraitAlias => "trait alias",
Target::Impl => "item",
Target::Expression => "expression",
Target::Statement => "statement",
+ Target::Arm => "match arm",
Target::AssocConst => "associated const",
Target::Method(_) => "method",
Target::AssocTy => "associated type",
@@ -90,6 +95,7 @@
GenericParamKind::Lifetime => "lifetime parameter",
GenericParamKind::Const => "const parameter",
},
+ Target::MacroDef => "macro def",
}
)
}
diff --git a/compiler/rustc_hir/src/weak_lang_items.rs b/compiler/rustc_hir/src/weak_lang_items.rs
index 52f28bf..b8cd15e 100644
--- a/compiler/rustc_hir/src/weak_lang_items.rs
+++ b/compiler/rustc_hir/src/weak_lang_items.rs
@@ -4,7 +4,7 @@
use crate::{lang_items, LangItem, LanguageItems};
use rustc_ast as ast;
-use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::stable_map::StableMap;
use rustc_span::symbol::{sym, Symbol};
use std::lazy::SyncLazy;
@@ -12,8 +12,8 @@
macro_rules! weak_lang_items {
($($name:ident, $item:ident, $sym:ident;)*) => (
-pub static WEAK_ITEMS_REFS: SyncLazy<FxHashMap<Symbol, LangItem>> = SyncLazy::new(|| {
- let mut map = FxHashMap::default();
+pub static WEAK_ITEMS_REFS: SyncLazy<StableMap<Symbol, LangItem>> = SyncLazy::new(|| {
+ let mut map = StableMap::default();
$(map.insert(sym::$name, LangItem::$item);)*
map
});
diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs
index 0b5eb1d..4595855 100644
--- a/compiler/rustc_hir_pretty/src/lib.rs
+++ b/compiler/rustc_hir_pretty/src/lib.rs
@@ -138,9 +138,6 @@
}
impl<'a> PrintState<'a> for State<'a> {
- fn insert_extra_parens(&self) -> bool {
- true
- }
fn comments(&mut self) -> &mut Option<Comments<'a>> {
&mut self.comments
}
@@ -687,7 +684,7 @@
self.head(visibility_qualified(&item.vis, "union"));
self.print_struct(struct_def, generics, item.ident.name, item.span, true);
}
- hir::ItemKind::Impl {
+ hir::ItemKind::Impl(hir::Impl {
unsafety,
polarity,
defaultness,
@@ -697,7 +694,7 @@
ref of_trait,
ref self_ty,
items,
- } => {
+ }) => {
self.head("");
self.print_visibility(&item.vis);
self.print_defaultness(defaultness);
@@ -1083,6 +1080,50 @@
self.ann.post(self, AnnNode::Block(blk))
}
+ fn print_else(&mut self, els: Option<&hir::Expr<'_>>) {
+ match els {
+ Some(_else) => {
+ match _else.kind {
+ // "another else-if"
+ hir::ExprKind::If(ref i, ref then, ref e) => {
+ self.cbox(INDENT_UNIT - 1);
+ self.ibox(0);
+ self.s.word(" else if ");
+ self.print_expr_as_cond(&i);
+ self.s.space();
+ self.print_expr(&then);
+ self.print_else(e.as_ref().map(|e| &**e))
+ }
+ // "final else"
+ hir::ExprKind::Block(ref b, _) => {
+ self.cbox(INDENT_UNIT - 1);
+ self.ibox(0);
+ self.s.word(" else ");
+ self.print_block(&b)
+ }
+ // BLEAH, constraints would be great here
+ _ => {
+ panic!("print_if saw if with weird alternative");
+ }
+ }
+ }
+ _ => {}
+ }
+ }
+
+ pub fn print_if(
+ &mut self,
+ test: &hir::Expr<'_>,
+ blk: &hir::Expr<'_>,
+ elseopt: Option<&hir::Expr<'_>>,
+ ) {
+ self.head("if");
+ self.print_expr_as_cond(test);
+ self.s.space();
+ self.print_expr(blk);
+ self.print_else(elseopt)
+ }
+
pub fn print_anon_const(&mut self, constant: &hir::AnonConst) {
self.ann.nested(self, Nested::Body(constant.body))
}
@@ -1216,7 +1257,7 @@
self.s.word(".");
self.print_ident(segment.ident);
- let generic_args = segment.generic_args();
+ let generic_args = segment.args();
if !generic_args.args.is_empty() || !generic_args.bindings.is_empty() {
self.print_generic_args(generic_args, segment.infer_args, true);
}
@@ -1352,7 +1393,10 @@
// Print `}`:
self.bclose_maybe_open(expr.span, true);
}
- hir::ExprKind::Loop(ref blk, opt_label, _) => {
+ hir::ExprKind::If(ref test, ref blk, ref elseopt) => {
+ self.print_if(&test, &blk, elseopt.as_ref().map(|e| &**e));
+ }
+ hir::ExprKind::Loop(ref blk, opt_label, _, _) => {
if let Some(label) = opt_label {
self.print_ident(label.ident);
self.word_space(":");
@@ -1664,11 +1708,7 @@
}
if segment.ident.name != kw::PathRoot {
self.print_ident(segment.ident);
- self.print_generic_args(
- segment.generic_args(),
- segment.infer_args,
- colons_before_params,
- );
+ self.print_generic_args(segment.args(), segment.infer_args, colons_before_params);
}
}
}
@@ -1676,7 +1716,7 @@
pub fn print_path_segment(&mut self, segment: &hir::PathSegment<'_>) {
if segment.ident.name != kw::PathRoot {
self.print_ident(segment.ident);
- self.print_generic_args(segment.generic_args(), segment.infer_args, false);
+ self.print_generic_args(segment.args(), segment.infer_args, false);
}
}
@@ -1696,7 +1736,7 @@
if segment.ident.name != kw::PathRoot {
self.print_ident(segment.ident);
self.print_generic_args(
- segment.generic_args(),
+ segment.args(),
segment.infer_args,
colons_before_params,
);
@@ -1708,7 +1748,7 @@
let item_segment = path.segments.last().unwrap();
self.print_ident(item_segment.ident);
self.print_generic_args(
- item_segment.generic_args(),
+ item_segment.args(),
item_segment.infer_args,
colons_before_params,
)
@@ -1728,7 +1768,7 @@
self.s.word("::");
self.print_ident(item_segment.ident);
self.print_generic_args(
- item_segment.generic_args(),
+ item_segment.args(),
item_segment.infer_args,
colons_before_params,
)
@@ -1800,6 +1840,7 @@
for binding in generic_args.bindings.iter() {
start_or_comma(self);
self.print_ident(binding.ident);
+ self.print_generic_args(binding.gen_args, false, false);
self.s.space();
match generic_args.bindings[0].kind {
hir::TypeBindingKind::Equality { ref ty } => {
@@ -2205,9 +2246,12 @@
self.print_type(&default)
}
}
- GenericParamKind::Const { ref ty } => {
+ GenericParamKind::Const { ref ty, ref default } => {
self.word_space(":");
- self.print_type(ty)
+ self.print_type(ty);
+ if let Some(ref _default) = default {
+ // FIXME(const_generics_defaults): print the `default` value here
+ }
}
}
}
@@ -2230,19 +2274,19 @@
}
match predicate {
- &hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate {
- ref bound_generic_params,
- ref bounded_ty,
+ hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate {
+ bound_generic_params,
+ bounded_ty,
bounds,
..
}) => {
self.print_formal_generic_params(bound_generic_params);
self.print_type(&bounded_ty);
- self.print_bounds(":", bounds);
+ self.print_bounds(":", *bounds);
}
- &hir::WherePredicate::RegionPredicate(hir::WhereRegionPredicate {
- ref lifetime,
- ref bounds,
+ hir::WherePredicate::RegionPredicate(hir::WhereRegionPredicate {
+ lifetime,
+ bounds,
..
}) => {
self.print_lifetime(lifetime);
@@ -2261,10 +2305,8 @@
}
}
}
- &hir::WherePredicate::EqPredicate(hir::WhereEqPredicate {
- ref lhs_ty,
- ref rhs_ty,
- ..
+ hir::WherePredicate::EqPredicate(hir::WhereEqPredicate {
+ lhs_ty, rhs_ty, ..
}) => {
self.print_type(lhs_ty);
self.s.space();
@@ -2435,7 +2477,13 @@
//
// Duplicated from `parse::classify`, but adapted for the HIR.
fn expr_requires_semi_to_be_stmt(e: &hir::Expr<'_>) -> bool {
- !matches!(e.kind, hir::ExprKind::Match(..) | hir::ExprKind::Block(..) | hir::ExprKind::Loop(..))
+ !matches!(
+ e.kind,
+ hir::ExprKind::If(..)
+ | hir::ExprKind::Match(..)
+ | hir::ExprKind::Block(..)
+ | hir::ExprKind::Loop(..)
+ )
}
/// This statement requires a semicolon after it.
diff --git a/compiler/rustc_incremental/src/assert_dep_graph.rs b/compiler/rustc_incremental/src/assert_dep_graph.rs
index e173964..f39a92b 100644
--- a/compiler/rustc_incremental/src/assert_dep_graph.rs
+++ b/compiler/rustc_incremental/src/assert_dep_graph.rs
@@ -12,7 +12,7 @@
//! In this code, we report errors on each `rustc_if_this_changed`
//! annotation. If a path exists in all cases, then we would report
//! "all path(s) exist". Otherwise, we report: "no path to `foo`" for
-//! each case where no path exists. `compile-fail` tests can then be
+//! each case where no path exists. `ui` tests can then be
//! used to check when paths exist or do not.
//!
//! The full form of the `rustc_if_this_changed` annotation is
@@ -310,13 +310,13 @@
sources: &Option<FxHashSet<&'q DepNode>>,
targets: &Option<FxHashSet<&'q DepNode>>,
) -> FxHashSet<&'q DepNode> {
- if let &Some(ref sources) = sources {
- if let &Some(ref targets) = targets {
+ if let Some(sources) = sources {
+ if let Some(targets) = targets {
walk_between(query, sources, targets)
} else {
walk_nodes(query, sources, OUTGOING)
}
- } else if let &Some(ref targets) = targets {
+ } else if let Some(targets) = targets {
walk_nodes(query, targets, INCOMING)
} else {
query.nodes().into_iter().collect()
diff --git a/compiler/rustc_incremental/src/lib.rs b/compiler/rustc_incremental/src/lib.rs
index a80c4be..95456c0 100644
--- a/compiler/rustc_incremental/src/lib.rs
+++ b/compiler/rustc_incremental/src/lib.rs
@@ -17,7 +17,6 @@
pub use assert_dep_graph::assert_dep_graph;
pub use persist::copy_cgu_workproduct_to_incr_comp_cache_dir;
pub use persist::delete_workproduct_files;
-pub use persist::dep_graph_tcx_init;
pub use persist::finalize_session_directory;
pub use persist::garbage_collect_session_directories;
pub use persist::in_incr_comp_dir;
diff --git a/compiler/rustc_incremental/src/persist/file_format.rs b/compiler/rustc_incremental/src/persist/file_format.rs
index e185ee2..087f83c 100644
--- a/compiler/rustc_incremental/src/persist/file_format.rs
+++ b/compiler/rustc_incremental/src/persist/file_format.rs
@@ -14,7 +14,7 @@
use std::io::{self, Read};
use std::path::Path;
-use rustc_serialize::opaque::Encoder;
+use rustc_serialize::opaque::{FileEncodeResult, FileEncoder};
/// The first few bytes of files generated by incremental compilation.
const FILE_MAGIC: &[u8] = b"RSIC";
@@ -27,15 +27,17 @@
/// the Git commit hash.
const RUSTC_VERSION: Option<&str> = option_env!("CFG_VERSION");
-pub fn write_file_header(stream: &mut Encoder, nightly_build: bool) {
- stream.emit_raw_bytes(FILE_MAGIC);
- stream
- .emit_raw_bytes(&[(HEADER_FORMAT_VERSION >> 0) as u8, (HEADER_FORMAT_VERSION >> 8) as u8]);
+pub fn write_file_header(stream: &mut FileEncoder, nightly_build: bool) -> FileEncodeResult {
+ stream.emit_raw_bytes(FILE_MAGIC)?;
+ stream.emit_raw_bytes(&[
+ (HEADER_FORMAT_VERSION >> 0) as u8,
+ (HEADER_FORMAT_VERSION >> 8) as u8,
+ ])?;
let rustc_version = rustc_version(nightly_build);
assert_eq!(rustc_version.len(), (rustc_version.len() as u8) as usize);
- stream.emit_raw_bytes(&[rustc_version.len() as u8]);
- stream.emit_raw_bytes(rustc_version.as_bytes());
+ stream.emit_raw_bytes(&[rustc_version.len() as u8])?;
+ stream.emit_raw_bytes(rustc_version.as_bytes())
}
/// Reads the contents of a file with a file header as defined in this module.
@@ -52,11 +54,11 @@
path: &Path,
nightly_build: bool,
) -> io::Result<Option<(Vec<u8>, usize)>> {
- if !path.exists() {
- return Ok(None);
- }
-
- let data = fs::read(path)?;
+ let data = match fs::read(path) {
+ Ok(data) => data,
+ Err(err) if err.kind() == io::ErrorKind::NotFound => return Ok(None),
+ Err(err) => return Err(err),
+ };
let mut file = io::Cursor::new(data);
diff --git a/compiler/rustc_incremental/src/persist/fs.rs b/compiler/rustc_incremental/src/persist/fs.rs
index 9fdf0a5..7a1976b 100644
--- a/compiler/rustc_incremental/src/persist/fs.rs
+++ b/compiler/rustc_incremental/src/persist/fs.rs
@@ -922,22 +922,24 @@
/// before passing it to std::fs::remove_dir_all(). This will convert the path
/// into the '\\?\' format, which supports much longer paths.
fn safe_remove_dir_all(p: &Path) -> io::Result<()> {
- if p.exists() {
- let canonicalized = p.canonicalize()?;
- std_fs::remove_dir_all(canonicalized)
- } else {
- Ok(())
- }
+ let canonicalized = match std_fs::canonicalize(p) {
+ Ok(canonicalized) => canonicalized,
+ Err(err) if err.kind() == io::ErrorKind::NotFound => return Ok(()),
+ Err(err) => return Err(err),
+ };
+
+ std_fs::remove_dir_all(canonicalized)
}
fn safe_remove_file(p: &Path) -> io::Result<()> {
- if p.exists() {
- let canonicalized = p.canonicalize()?;
- match std_fs::remove_file(canonicalized) {
- Err(ref err) if err.kind() == io::ErrorKind::NotFound => Ok(()),
- result => result,
- }
- } else {
- Ok(())
+ let canonicalized = match std_fs::canonicalize(p) {
+ Ok(canonicalized) => canonicalized,
+ Err(err) if err.kind() == io::ErrorKind::NotFound => return Ok(()),
+ Err(err) => return Err(err),
+ };
+
+ match std_fs::remove_file(canonicalized) {
+ Err(err) if err.kind() == io::ErrorKind::NotFound => Ok(()),
+ result => result,
}
}
diff --git a/compiler/rustc_incremental/src/persist/load.rs b/compiler/rustc_incremental/src/persist/load.rs
index 35428dc..0add0c5 100644
--- a/compiler/rustc_incremental/src/persist/load.rs
+++ b/compiler/rustc_incremental/src/persist/load.rs
@@ -4,7 +4,6 @@
use rustc_hir::definitions::Definitions;
use rustc_middle::dep_graph::{PreviousDepGraph, SerializedDepGraph, WorkProduct, WorkProductId};
use rustc_middle::ty::query::OnDiskCache;
-use rustc_middle::ty::TyCtxt;
use rustc_serialize::opaque::Decoder;
use rustc_serialize::Decodable as RustcDecodable;
use rustc_session::Session;
@@ -15,14 +14,6 @@
use super::fs::*;
use super::work_product;
-pub fn dep_graph_tcx_init(tcx: TyCtxt<'_>) {
- if !tcx.dep_graph.is_fully_enabled() {
- return;
- }
-
- tcx.allocate_metadata_dep_nodes();
-}
-
type WorkProductMap = FxHashMap<WorkProductId, WorkProduct>;
pub enum LoadResult<T> {
diff --git a/compiler/rustc_incremental/src/persist/mod.rs b/compiler/rustc_incremental/src/persist/mod.rs
index 7bc3b47..8821b34 100644
--- a/compiler/rustc_incremental/src/persist/mod.rs
+++ b/compiler/rustc_incremental/src/persist/mod.rs
@@ -15,7 +15,6 @@
pub use fs::in_incr_comp_dir;
pub use fs::in_incr_comp_dir_sess;
pub use fs::prepare_session_directory;
-pub use load::dep_graph_tcx_init;
pub use load::load_query_result_cache;
pub use load::LoadResult;
pub use load::{load_dep_graph, DepGraphFuture};
diff --git a/compiler/rustc_incremental/src/persist/save.rs b/compiler/rustc_incremental/src/persist/save.rs
index 102a77e..45d474b 100644
--- a/compiler/rustc_incremental/src/persist/save.rs
+++ b/compiler/rustc_incremental/src/persist/save.rs
@@ -1,11 +1,12 @@
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::sync::join;
-use rustc_middle::dep_graph::{DepGraph, DepKind, WorkProduct, WorkProductId};
+use rustc_middle::dep_graph::{DepGraph, WorkProduct, WorkProductId};
use rustc_middle::ty::TyCtxt;
-use rustc_serialize::opaque::Encoder;
+use rustc_serialize::opaque::{FileEncodeResult, FileEncoder};
use rustc_serialize::Encodable as RustcEncodable;
use rustc_session::Session;
use std::fs;
+use std::io;
use std::path::PathBuf;
use super::data::*;
@@ -32,12 +33,12 @@
join(
move || {
sess.time("incr_comp_persist_result_cache", || {
- save_in(sess, query_cache_path, |e| encode_query_cache(tcx, e));
+ save_in(sess, query_cache_path, "query cache", |e| encode_query_cache(tcx, e));
});
},
|| {
sess.time("incr_comp_persist_dep_graph", || {
- save_in(sess, dep_graph_path, |e| {
+ save_in(sess, dep_graph_path, "dependency graph", |e| {
sess.time("incr_comp_encode_dep_graph", || encode_dep_graph(tcx, e))
});
});
@@ -64,7 +65,7 @@
debug!("save_work_product_index()");
dep_graph.assert_ignored();
let path = work_products_path(sess);
- save_in(sess, path, |e| encode_work_product_index(&new_work_products, e));
+ save_in(sess, path, "work product index", |e| encode_work_product_index(&new_work_products, e));
// We also need to clean out old work-products, as not all of them are
// deleted during invalidation. Some object files don't change their
@@ -91,138 +92,77 @@
});
}
-fn save_in<F>(sess: &Session, path_buf: PathBuf, encode: F)
+fn save_in<F>(sess: &Session, path_buf: PathBuf, name: &str, encode: F)
where
- F: FnOnce(&mut Encoder),
+ F: FnOnce(&mut FileEncoder) -> FileEncodeResult,
{
debug!("save: storing data in {}", path_buf.display());
- // delete the old dep-graph, if any
+ // Delete the old file, if any.
// Note: It's important that we actually delete the old file and not just
// truncate and overwrite it, since it might be a shared hard-link, the
// underlying data of which we don't want to modify
- if path_buf.exists() {
- match fs::remove_file(&path_buf) {
- Ok(()) => {
- debug!("save: remove old file");
- }
- Err(err) => {
- sess.err(&format!(
- "unable to delete old dep-graph at `{}`: {}",
- path_buf.display(),
- err
- ));
- return;
- }
+ match fs::remove_file(&path_buf) {
+ Ok(()) => {
+ debug!("save: remove old file");
}
- }
-
- // generate the data in a memory buffer
- let mut encoder = Encoder::new(Vec::new());
- file_format::write_file_header(&mut encoder, sess.is_nightly_build());
- encode(&mut encoder);
-
- // write the data out
- let data = encoder.into_inner();
- match fs::write(&path_buf, data) {
- Ok(_) => {
- debug!("save: data written to disk successfully");
- }
+ Err(err) if err.kind() == io::ErrorKind::NotFound => (),
Err(err) => {
- sess.err(&format!("failed to write dep-graph to `{}`: {}", path_buf.display(), err));
+ sess.err(&format!(
+ "unable to delete old {} at `{}`: {}",
+ name,
+ path_buf.display(),
+ err
+ ));
+ return;
}
}
+
+ let mut encoder = match FileEncoder::new(&path_buf) {
+ Ok(encoder) => encoder,
+ Err(err) => {
+ sess.err(&format!("failed to create {} at `{}`: {}", name, path_buf.display(), err));
+ return;
+ }
+ };
+
+ if let Err(err) = file_format::write_file_header(&mut encoder, sess.is_nightly_build()) {
+ sess.err(&format!("failed to write {} header to `{}`: {}", name, path_buf.display(), err));
+ return;
+ }
+
+ if let Err(err) = encode(&mut encoder) {
+ sess.err(&format!("failed to write {} to `{}`: {}", name, path_buf.display(), err));
+ return;
+ }
+
+ if let Err(err) = encoder.flush() {
+ sess.err(&format!("failed to flush {} to `{}`: {}", name, path_buf.display(), err));
+ return;
+ }
+
+ debug!("save: data written to disk successfully");
}
-fn encode_dep_graph(tcx: TyCtxt<'_>, encoder: &mut Encoder) {
+fn encode_dep_graph(tcx: TyCtxt<'_>, encoder: &mut FileEncoder) -> FileEncodeResult {
// First encode the commandline arguments hash
- tcx.sess.opts.dep_tracking_hash().encode(encoder).unwrap();
-
- // Encode the graph data.
- let serialized_graph =
- tcx.sess.time("incr_comp_serialize_dep_graph", || tcx.dep_graph.serialize());
+ tcx.sess.opts.dep_tracking_hash().encode(encoder)?;
if tcx.sess.opts.debugging_opts.incremental_info {
- #[derive(Clone)]
- struct Stat {
- kind: DepKind,
- node_counter: u64,
- edge_counter: u64,
- }
-
- let total_node_count = serialized_graph.nodes.len();
- let total_edge_count = serialized_graph.edge_list_data.len();
-
- let mut counts: FxHashMap<_, Stat> =
- FxHashMap::with_capacity_and_hasher(total_node_count, Default::default());
-
- for (i, &node) in serialized_graph.nodes.iter_enumerated() {
- let stat = counts.entry(node.kind).or_insert(Stat {
- kind: node.kind,
- node_counter: 0,
- edge_counter: 0,
- });
-
- stat.node_counter += 1;
- let (edge_start, edge_end) = serialized_graph.edge_list_indices[i];
- stat.edge_counter += (edge_end - edge_start) as u64;
- }
-
- let mut counts: Vec<_> = counts.values().cloned().collect();
- counts.sort_by_key(|s| -(s.node_counter as i64));
-
- println!("[incremental]");
- println!("[incremental] DepGraph Statistics");
-
- const SEPARATOR: &str = "[incremental] --------------------------------\
- ----------------------------------------------\
- ------------";
-
- println!("{}", SEPARATOR);
- println!("[incremental]");
- println!("[incremental] Total Node Count: {}", total_node_count);
- println!("[incremental] Total Edge Count: {}", total_edge_count);
- if let Some((total_edge_reads, total_duplicate_edge_reads)) =
- tcx.dep_graph.edge_deduplication_data()
- {
- println!("[incremental] Total Edge Reads: {}", total_edge_reads);
- println!("[incremental] Total Duplicate Edge Reads: {}", total_duplicate_edge_reads);
- }
- println!("[incremental]");
- println!(
- "[incremental] {:<36}| {:<17}| {:<12}| {:<17}|",
- "Node Kind", "Node Frequency", "Node Count", "Avg. Edge Count"
- );
- println!(
- "[incremental] -------------------------------------\
- |------------------\
- |-------------\
- |------------------|"
- );
-
- for stat in counts.iter() {
- println!(
- "[incremental] {:<36}|{:>16.1}% |{:>12} |{:>17.1} |",
- format!("{:?}", stat.kind),
- (100.0 * (stat.node_counter as f64)) / (total_node_count as f64), // percentage of all nodes
- stat.node_counter,
- (stat.edge_counter as f64) / (stat.node_counter as f64), // average edges per kind
- );
- }
-
- println!("{}", SEPARATOR);
- println!("[incremental]");
+ tcx.dep_graph.print_incremental_info();
}
- tcx.sess.time("incr_comp_encode_serialized_dep_graph", || {
- serialized_graph.encode(encoder).unwrap();
- });
+ // There is a tiny window between printing the incremental info above and encoding the dep
+ // graph below in which the dep graph could change, thus making the printed incremental info
+ // slightly out of date. If this matters to you, please feel free to submit a patch. :)
+
+ tcx.sess.time("incr_comp_encode_serialized_dep_graph", || tcx.dep_graph.encode(encoder))
}
fn encode_work_product_index(
work_products: &FxHashMap<WorkProductId, WorkProduct>,
- encoder: &mut Encoder,
-) {
+ encoder: &mut FileEncoder,
+) -> FileEncodeResult {
let serialized_products: Vec<_> = work_products
.iter()
.map(|(id, work_product)| SerializedWorkProduct {
@@ -231,11 +171,9 @@
})
.collect();
- serialized_products.encode(encoder).unwrap();
+ serialized_products.encode(encoder)
}
-fn encode_query_cache(tcx: TyCtxt<'_>, encoder: &mut Encoder) {
- tcx.sess.time("incr_comp_serialize_result_cache", || {
- tcx.serialize_query_result_cache(encoder).unwrap();
- })
+fn encode_query_cache(tcx: TyCtxt<'_>, encoder: &mut FileEncoder) -> FileEncodeResult {
+ tcx.sess.time("incr_comp_serialize_result_cache", || tcx.serialize_query_result_cache(encoder))
}
diff --git a/compiler/rustc_index/src/bit_set.rs b/compiler/rustc_index/src/bit_set.rs
index 0b501da..100824f 100644
--- a/compiler/rustc_index/src/bit_set.rs
+++ b/compiler/rustc_index/src/bit_set.rs
@@ -707,6 +707,18 @@
self.bit_set.insert(elem)
}
+ /// Returns `true` if the set has changed.
+ #[inline]
+ pub fn remove(&mut self, elem: T) -> bool {
+ self.ensure(elem.index() + 1);
+ self.bit_set.remove(elem)
+ }
+
+ #[inline]
+ pub fn is_empty(&self) -> bool {
+ self.bit_set.is_empty()
+ }
+
#[inline]
pub fn contains(&self, elem: T) -> bool {
let (word_index, mask) = word_index_and_mask(elem);
diff --git a/compiler/rustc_index/src/bit_set/tests.rs b/compiler/rustc_index/src/bit_set/tests.rs
index 6cc3e94..c11b98e 100644
--- a/compiler/rustc_index/src/bit_set/tests.rs
+++ b/compiler/rustc_index/src/bit_set/tests.rs
@@ -1,6 +1,7 @@
use super::*;
extern crate test;
+use std::hint::black_box;
use test::Bencher;
#[test]
@@ -364,3 +365,36 @@
sparse.union(&dense);
})
}
+
+#[bench]
+fn bench_insert(b: &mut Bencher) {
+ let mut bs = BitSet::new_filled(99999usize);
+ b.iter(|| {
+ black_box(bs.insert(black_box(100u32)));
+ });
+}
+
+#[bench]
+fn bench_remove(b: &mut Bencher) {
+ let mut bs = BitSet::new_filled(99999usize);
+ b.iter(|| {
+ black_box(bs.remove(black_box(100u32)));
+ });
+}
+
+#[bench]
+fn bench_iter(b: &mut Bencher) {
+ let bs = BitSet::new_filled(99999usize);
+ b.iter(|| {
+ bs.iter().map(|b: usize| black_box(b)).for_each(drop);
+ });
+}
+
+#[bench]
+fn bench_intersect(b: &mut Bencher) {
+ let mut ba: BitSet<u32> = BitSet::new_filled(99999usize);
+ let bb = BitSet::new_filled(99999usize);
+ b.iter(|| {
+ ba.intersect(black_box(&bb));
+ });
+}
diff --git a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
index 9002d25..aa4fd05 100644
--- a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
+++ b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
@@ -353,10 +353,8 @@
// `TyVar(vid)` is unresolved, track its universe index in the canonicalized
// result.
Err(mut ui) => {
- if !self.infcx.unwrap().tcx.sess.opts.debugging_opts.chalk {
- // FIXME: perf problem described in #55921.
- ui = ty::UniverseIndex::ROOT;
- }
+ // FIXME: perf problem described in #55921.
+ ui = ty::UniverseIndex::ROOT;
self.canonicalize_ty_var(
CanonicalVarInfo {
kind: CanonicalVarKind::Ty(CanonicalTyVarKind::General(ui)),
@@ -440,10 +438,8 @@
// `ConstVar(vid)` is unresolved, track its universe index in the
// canonicalized result
Err(mut ui) => {
- if !self.infcx.unwrap().tcx.sess.opts.debugging_opts.chalk {
- // FIXME: perf problem described in #55921.
- ui = ty::UniverseIndex::ROOT;
- }
+ // FIXME: perf problem described in #55921.
+ ui = ty::UniverseIndex::ROOT;
return self.canonicalize_const_var(
CanonicalVarInfo { kind: CanonicalVarKind::Const(ui) },
ct,
diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs
index 71ce50f..1546c1e 100644
--- a/compiler/rustc_infer/src/infer/canonical/query_response.rs
+++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs
@@ -14,7 +14,7 @@
};
use crate::infer::nll_relate::{NormalizationStrategy, TypeRelating, TypeRelatingDelegate};
use crate::infer::region_constraints::{Constraint, RegionConstraintData};
-use crate::infer::{InferCtxt, InferOk, InferResult, NLLRegionVariableOrigin};
+use crate::infer::{InferCtxt, InferOk, InferResult, NllRegionVariableOrigin};
use crate::traits::query::{Fallible, NoSolution};
use crate::traits::TraitEngine;
use crate::traits::{Obligation, ObligationCause, PredicateObligation};
@@ -530,10 +530,10 @@
let atom = match k1.unpack() {
GenericArgKind::Lifetime(r1) => {
- ty::PredicateAtom::RegionOutlives(ty::OutlivesPredicate(r1, r2))
+ ty::PredicateKind::RegionOutlives(ty::OutlivesPredicate(r1, r2))
}
GenericArgKind::Type(t1) => {
- ty::PredicateAtom::TypeOutlives(ty::OutlivesPredicate(t1, r2))
+ ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(t1, r2))
}
GenericArgKind::Const(..) => {
// Consts cannot outlive one another, so we don't expect to
@@ -541,8 +541,7 @@
span_bug!(cause.span, "unexpected const outlives {:?}", constraint);
}
};
- let predicate =
- predicate.rebind(atom).potentially_quantified(self.tcx, ty::PredicateKind::ForAll);
+ let predicate = predicate.rebind(atom).to_predicate(self.tcx);
Obligation::new(cause.clone(), param_env, predicate)
})
@@ -645,7 +644,7 @@
}
fn next_existential_region_var(&mut self, from_forall: bool) -> ty::Region<'tcx> {
- let origin = NLLRegionVariableOrigin::Existential { from_forall };
+ let origin = NllRegionVariableOrigin::Existential { from_forall };
self.infcx.next_nll_region_var(origin)
}
@@ -655,7 +654,7 @@
fn generalize_existential(&mut self, universe: ty::UniverseIndex) -> ty::Region<'tcx> {
self.infcx.next_nll_region_var_in_universe(
- NLLRegionVariableOrigin::Existential { from_forall: false },
+ NllRegionVariableOrigin::Existential { from_forall: false },
universe,
)
}
@@ -664,7 +663,7 @@
self.obligations.push(Obligation {
cause: self.cause.clone(),
param_env: self.param_env,
- predicate: ty::PredicateAtom::RegionOutlives(ty::OutlivesPredicate(sup, sub))
+ predicate: ty::PredicateKind::RegionOutlives(ty::OutlivesPredicate(sup, sub))
.to_predicate(self.infcx.tcx),
recursion_depth: 0,
});
diff --git a/compiler/rustc_infer/src/infer/combine.rs b/compiler/rustc_infer/src/infer/combine.rs
index e38eebe..e034ac5 100644
--- a/compiler/rustc_infer/src/infer/combine.rs
+++ b/compiler/rustc_infer/src/infer/combine.rs
@@ -34,7 +34,6 @@
use crate::traits::{Obligation, PredicateObligations};
-use rustc_ast as ast;
use rustc_data_structures::sso::SsoHashMap;
use rustc_hir::def_id::DefId;
use rustc_middle::traits::ObligationCause;
@@ -281,7 +280,7 @@
&self,
vid_is_expected: bool,
vid: ty::FloatVid,
- val: ast::FloatTy,
+ val: ty::FloatTy,
) -> RelateResult<'tcx, Ty<'tcx>> {
self.inner
.borrow_mut()
@@ -358,7 +357,7 @@
self.obligations.push(Obligation::new(
self.trace.cause.clone(),
self.param_env,
- ty::PredicateAtom::WellFormed(b_ty.into()).to_predicate(self.infcx.tcx),
+ ty::PredicateKind::WellFormed(b_ty.into()).to_predicate(self.infcx.tcx),
));
}
@@ -451,9 +450,9 @@
b: &'tcx ty::Const<'tcx>,
) {
let predicate = if a_is_expected {
- ty::PredicateAtom::ConstEquate(a, b)
+ ty::PredicateKind::ConstEquate(a, b)
} else {
- ty::PredicateAtom::ConstEquate(b, a)
+ ty::PredicateKind::ConstEquate(b, a)
};
self.obligations.push(Obligation::new(
self.trace.cause.clone(),
diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
index 6b7edde..84aa19a 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
@@ -69,7 +69,7 @@
subst::{Subst, SubstsRef},
Region, Ty, TyCtxt, TypeFoldable,
};
-use rustc_span::{BytePos, DesugaringKind, Pos, Span};
+use rustc_span::{sym, BytePos, DesugaringKind, Pos, Span};
use rustc_target::spec::abi;
use std::ops::ControlFlow;
use std::{cmp, fmt};
@@ -98,7 +98,7 @@
// uh oh, hope no user ever sees THIS
ty::ReEmpty(ui) => (format!("the empty lifetime in universe {:?}", ui), None),
- ty::RePlaceholder(_) => ("any other region".to_string(), None),
+ ty::RePlaceholder(_) => return,
// FIXME(#13998) RePlaceholder should probably print like
// ReFree rather than dumping Debug output on the user.
@@ -153,6 +153,7 @@
Some(Node::Item(it)) => item_scope_tag(&it),
Some(Node::TraitItem(it)) => trait_item_scope_tag(&it),
Some(Node::ImplItem(it)) => impl_item_scope_tag(&it),
+ Some(Node::ForeignItem(it)) => foreign_item_scope_tag(&it),
_ => unreachable!(),
};
let (prefix, span) = match *region {
@@ -233,6 +234,13 @@
}
}
+fn foreign_item_scope_tag(item: &hir::ForeignItem<'_>) -> &'static str {
+ match item.kind {
+ hir::ForeignItemKind::Fn(..) => "method body",
+ hir::ForeignItemKind::Static(..) | hir::ForeignItemKind::Type => "associated item",
+ }
+}
+
fn explain_span(tcx: TyCtxt<'tcx>, heading: &str, span: Span) -> (String, Option<Span>) {
let lo = tcx.sess.source_map().lookup_char_pos(span.lo());
(format!("the {} at {}:{}", heading, lo.line, lo.col.to_usize() + 1), Some(span))
@@ -417,7 +425,7 @@
// obviously it never weeds out ALL errors.
fn process_errors(
&self,
- errors: &Vec<RegionResolutionError<'tcx>>,
+ errors: &[RegionResolutionError<'tcx>],
) -> Vec<RegionResolutionError<'tcx>> {
debug!("process_errors()");
@@ -442,7 +450,7 @@
};
let mut errors = if errors.iter().all(|e| is_bound_failure(e)) {
- errors.clone()
+ errors.to_owned()
} else {
errors.iter().filter(|&e| !is_bound_failure(e)).cloned().collect()
};
@@ -907,7 +915,7 @@
self.highlight_outer(&mut t1_out, &mut t2_out, path, sub, i, &other_ty);
return Some(());
}
- if let &ty::Adt(def, _) = ta.kind() {
+ if let ty::Adt(def, _) = ta.kind() {
let path_ = self.tcx.def_path_str(def.did);
if path_ == other_path {
self.highlight_outer(&mut t1_out, &mut t2_out, path, sub, i, &other_ty);
@@ -950,7 +958,7 @@
ty::GenericParamDefKind::Type { has_default, .. } => {
Some((param.def_id, has_default))
}
- ty::GenericParamDefKind::Const => None, // FIXME(const_generics:defaults)
+ ty::GenericParamDefKind::Const => None, // FIXME(const_generics_defaults)
})
.peekable();
let has_default = {
@@ -1653,6 +1661,7 @@
debug!("exp_found {:?} terr {:?}", exp_found, terr);
if let Some(exp_found) = exp_found {
self.suggest_as_ref_where_appropriate(span, &exp_found, diag);
+ self.suggest_accessing_field_where_appropriate(cause, &exp_found, diag);
self.suggest_await_on_expect_found(cause, span, &exp_found, diag);
}
@@ -1667,6 +1676,16 @@
self.check_and_note_conflicting_crates(diag, terr);
self.tcx.note_and_explain_type_err(diag, terr, cause, span, body_owner_def_id.to_def_id());
+ if let Some(ValuePairs::PolyTraitRefs(exp_found)) = values {
+ if let ty::Closure(def_id, _) = exp_found.expected.skip_binder().self_ty().kind() {
+ if let Some(def_id) = def_id.as_local() {
+ let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id);
+ let span = self.tcx.hir().span(hir_id);
+ diag.span_note(span, "this closure does not fulfill the lifetime requirements");
+ }
+ }
+ }
+
// It reads better to have the error origin as the final
// thing.
self.note_error_origin(diag, cause, exp_found);
@@ -1688,8 +1707,8 @@
for (predicate, _) in bounds {
let predicate = predicate.subst(self.tcx, substs);
- if let ty::PredicateAtom::Projection(projection_predicate) =
- predicate.skip_binders()
+ if let ty::PredicateKind::Projection(projection_predicate) =
+ predicate.kind().skip_binder()
{
if projection_predicate.projection_ty.item_def_id == item_def_id {
// We don't account for multiple `Future::Output = Ty` contraints.
@@ -1801,6 +1820,53 @@
}
}
+ fn suggest_accessing_field_where_appropriate(
+ &self,
+ cause: &ObligationCause<'tcx>,
+ exp_found: &ty::error::ExpectedFound<Ty<'tcx>>,
+ diag: &mut DiagnosticBuilder<'tcx>,
+ ) {
+ debug!(
+ "suggest_accessing_field_where_appropriate(cause={:?}, exp_found={:?})",
+ cause, exp_found
+ );
+ if let ty::Adt(expected_def, expected_substs) = exp_found.expected.kind() {
+ if expected_def.is_enum() {
+ return;
+ }
+
+ if let Some((name, ty)) = expected_def
+ .non_enum_variant()
+ .fields
+ .iter()
+ .filter(|field| field.vis.is_accessible_from(field.did, self.tcx))
+ .map(|field| (field.ident.name, field.ty(self.tcx, expected_substs)))
+ .find(|(_, ty)| ty::TyS::same_type(ty, exp_found.found))
+ {
+ if let ObligationCauseCode::Pattern { span: Some(span), .. } = cause.code {
+ if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) {
+ let suggestion = if expected_def.is_struct() {
+ format!("{}.{}", snippet, name)
+ } else if expected_def.is_union() {
+ format!("unsafe {{ {}.{} }}", snippet, name)
+ } else {
+ return;
+ };
+ diag.span_suggestion(
+ span,
+ &format!(
+ "you might have meant to use field `{}` whose type is `{}`",
+ name, ty
+ ),
+ suggestion,
+ Applicability::MaybeIncorrect,
+ );
+ }
+ }
+ }
+ }
+ }
+
/// When encountering a case where `.as_ref()` on a `Result` or `Option` would be appropriate,
/// suggests it.
fn suggest_as_ref_where_appropriate(
@@ -2100,7 +2166,7 @@
let consider = format!(
"{} {}...",
msg,
- if type_param_span.map(|(_, _, is_impl_trait)| is_impl_trait).unwrap_or(false) {
+ if type_param_span.map_or(false, |(_, _, is_impl_trait)| is_impl_trait) {
format!(" `{}` to `{}`", sub, bound_kind)
} else {
format!("`{}: {}`", bound_kind, sub)
@@ -2274,6 +2340,14 @@
self.note_region_origin(&mut err, &sub_origin);
err.emit();
}
+
+ /// Determine whether an error associated with the given span and definition
+ /// should be treated as being caused by the implicit `From` conversion
+ /// within `?` desugaring.
+ pub fn is_try_conversion(&self, span: Span, trait_def_id: DefId) -> bool {
+ span.is_desugaring(DesugaringKind::QuestionMark)
+ && self.tcx.is_diagnostic_item(sym::from_trait, trait_def_id)
+ }
}
impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
@@ -2316,7 +2390,7 @@
let var_name = self.tcx.hir().name(upvar_id.var_path.hir_id);
format!(" for capture of `{}` by closure", var_name)
}
- infer::NLL(..) => bug!("NLL variable found in lexical phase"),
+ infer::Nll(..) => bug!("NLL variable found in lexical phase"),
};
struct_span_err!(
diff --git a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
index 373f0a6..bd43d3c 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
@@ -3,13 +3,14 @@
use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder};
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Namespace};
+use rustc_hir::def_id::DefId;
use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
use rustc_hir::{Body, Expr, ExprKind, FnRetTy, HirId, Local, Pat};
use rustc_middle::hir::map::Map;
use rustc_middle::infer::unify_key::ConstVariableOriginKind;
use rustc_middle::ty::print::Print;
use rustc_middle::ty::subst::{GenericArg, GenericArgKind};
-use rustc_middle::ty::{self, DefIdTree, InferConst, Ty};
+use rustc_middle::ty::{self, DefIdTree, InferConst, Ty, TyCtxt};
use rustc_span::source_map::DesugaringKind;
use rustc_span::symbol::kw;
use rustc_span::Span;
@@ -25,6 +26,7 @@
found_closure: Option<&'tcx Expr<'tcx>>,
found_method_call: Option<&'tcx Expr<'tcx>>,
found_exact_method_call: Option<&'tcx Expr<'tcx>>,
+ found_use_diagnostic: Option<UseDiagnostic<'tcx>>,
}
impl<'a, 'tcx> FindHirNodeVisitor<'a, 'tcx> {
@@ -39,44 +41,43 @@
found_closure: None,
found_method_call: None,
found_exact_method_call: None,
+ found_use_diagnostic: None,
}
}
- fn node_ty_contains_target(&mut self, hir_id: HirId) -> Option<Ty<'tcx>> {
- let ty_opt = self
- .infcx
- .in_progress_typeck_results
- .and_then(|typeck_results| typeck_results.borrow().node_type_opt(hir_id));
- match ty_opt {
- Some(ty) => {
- let ty = self.infcx.resolve_vars_if_possible(ty);
- if ty.walk().any(|inner| {
- inner == self.target
- || match (inner.unpack(), self.target.unpack()) {
- (GenericArgKind::Type(inner_ty), GenericArgKind::Type(target_ty)) => {
- match (inner_ty.kind(), target_ty.kind()) {
- (
- &ty::Infer(ty::TyVar(a_vid)),
- &ty::Infer(ty::TyVar(b_vid)),
- ) => self
- .infcx
- .inner
- .borrow_mut()
- .type_variables()
- .sub_unified(a_vid, b_vid),
- _ => false,
- }
+ fn node_type_opt(&self, hir_id: HirId) -> Option<Ty<'tcx>> {
+ self.infcx.in_progress_typeck_results?.borrow().node_type_opt(hir_id)
+ }
+
+ fn node_ty_contains_target(&self, hir_id: HirId) -> Option<Ty<'tcx>> {
+ self.node_type_opt(hir_id).map(|ty| self.infcx.resolve_vars_if_possible(ty)).filter(|ty| {
+ ty.walk().any(|inner| {
+ inner == self.target
+ || match (inner.unpack(), self.target.unpack()) {
+ (GenericArgKind::Type(inner_ty), GenericArgKind::Type(target_ty)) => {
+ use ty::{Infer, TyVar};
+ match (inner_ty.kind(), target_ty.kind()) {
+ (&Infer(TyVar(a_vid)), &Infer(TyVar(b_vid))) => self
+ .infcx
+ .inner
+ .borrow_mut()
+ .type_variables()
+ .sub_unified(a_vid, b_vid),
+ _ => false,
}
- _ => false,
}
- }) {
- Some(ty)
- } else {
- None
- }
- }
- None => None,
- }
+ _ => false,
+ }
+ })
+ })
+ }
+
+ /// Determine whether the expression, assumed to be the callee within a `Call`,
+ /// corresponds to the `From::from` emitted in desugaring of the `?` operator.
+ fn is_try_conversion(&self, callee: &Expr<'tcx>) -> bool {
+ self.infcx
+ .trait_def_from_hir_fn(callee.hir_id)
+ .map_or(false, |def_id| self.infcx.is_try_conversion(callee.span, def_id))
}
}
@@ -129,10 +130,23 @@
// are handled specially, but instead they should be handled in `annotate_method_call`,
// which currently doesn't work because this evaluates to `false` for const arguments.
// See https://github.com/rust-lang/rust/pull/77758 for more details.
- if self.node_ty_contains_target(expr.hir_id).is_some() {
+ if let Some(ty) = self.node_ty_contains_target(expr.hir_id) {
match expr.kind {
ExprKind::Closure(..) => self.found_closure = Some(&expr),
ExprKind::MethodCall(..) => self.found_method_call = Some(&expr),
+
+ // If the given expression falls within the target span and is a
+ // `From::from(e)` call emitted during desugaring of the `?` operator,
+ // extract the types inferred before and after the call
+ ExprKind::Call(callee, [arg])
+ if self.target_span.contains(expr.span)
+ && self.found_use_diagnostic.is_none()
+ && self.is_try_conversion(callee) =>
+ {
+ self.found_use_diagnostic = self.node_type_opt(arg.hir_id).map(|pre_ty| {
+ UseDiagnostic::TryConversion { pre_ty, post_ty: ty, span: callee.span }
+ });
+ }
_ => {}
}
}
@@ -140,17 +154,70 @@
}
}
+/// An observation about the use site of a type to be emitted as an additional
+/// note in an inference failure error.
+enum UseDiagnostic<'tcx> {
+ /// Records the types inferred before and after `From::from` is called on the
+ /// error value within the desugaring of the `?` operator.
+ TryConversion { pre_ty: Ty<'tcx>, post_ty: Ty<'tcx>, span: Span },
+}
+
+impl UseDiagnostic<'_> {
+ /// Return a descriptor of the value at the use site
+ fn descr(&self) -> &'static str {
+ match self {
+ Self::TryConversion { .. } => "error for `?` operator",
+ }
+ }
+
+ /// Return a descriptor of the type at the use site
+ fn type_descr(&self) -> &'static str {
+ match self {
+ Self::TryConversion { .. } => "error type for `?` operator",
+ }
+ }
+
+ fn applies_to(&self, span: Span) -> bool {
+ match *self {
+ // In some cases the span for an inference failure due to try
+ // conversion contains the antecedent expression as well as the `?`
+ Self::TryConversion { span: s, .. } => span.contains(s) && span.hi() == s.hi(),
+ }
+ }
+
+ fn attach_note(&self, err: &mut DiagnosticBuilder<'_>) {
+ match *self {
+ Self::TryConversion { pre_ty, post_ty, .. } => {
+ let intro = "`?` implicitly converts the error value";
+
+ let msg = match (pre_ty.is_ty_infer(), post_ty.is_ty_infer()) {
+ (true, true) => format!("{} using the `From` trait", intro),
+ (false, true) => {
+ format!("{} into a type implementing `From<{}>`", intro, pre_ty)
+ }
+ (true, false) => {
+ format!("{} into `{}` using the `From` trait", intro, post_ty)
+ }
+ (false, false) => {
+ format!(
+ "{} into `{}` using its implementation of `From<{}>`",
+ intro, post_ty, pre_ty
+ )
+ }
+ };
+
+ err.note(&msg);
+ }
+ }
+ }
+}
+
/// Suggest giving an appropriate return type to a closure expression.
fn closure_return_type_suggestion(
- span: Span,
err: &mut DiagnosticBuilder<'_>,
output: &FnRetTy<'_>,
body: &Body<'_>,
- descr: &str,
- name: &str,
ret: &str,
- parent_name: Option<String>,
- parent_descr: Option<&str>,
) {
let (arrow, post) = match output {
FnRetTy::DefaultReturn(_) => ("-> ", " "),
@@ -168,10 +235,6 @@
suggestion,
Applicability::HasPlaceholders,
);
- err.span_label(
- span,
- InferCtxt::cannot_infer_msg("type", &name, &descr, parent_name, parent_descr),
- );
}
/// Given a closure signature, return a `String` containing a list of all its argument types.
@@ -216,9 +279,67 @@
pub struct InferenceDiagnosticsData {
pub name: String,
pub span: Option<Span>,
- pub description: Cow<'static, str>,
- pub parent_name: Option<String>,
- pub parent_description: Option<&'static str>,
+ pub kind: UnderspecifiedArgKind,
+ pub parent: Option<InferenceDiagnosticsParentData>,
+}
+
+/// Data on the parent definition where a generic argument was declared.
+pub struct InferenceDiagnosticsParentData {
+ pub prefix: &'static str,
+ pub name: String,
+}
+
+pub enum UnderspecifiedArgKind {
+ Type { prefix: Cow<'static, str> },
+ Const { is_parameter: bool },
+}
+
+impl InferenceDiagnosticsData {
+ /// Generate a label for a generic argument which can't be inferred. When not
+ /// much is known about the argument, `use_diag` may be used to describe the
+ /// labeled value.
+ fn cannot_infer_msg(&self, use_diag: Option<&UseDiagnostic<'_>>) -> String {
+ if self.name == "_" && matches!(self.kind, UnderspecifiedArgKind::Type { .. }) {
+ if let Some(use_diag) = use_diag {
+ return format!("cannot infer type of {}", use_diag.descr());
+ }
+
+ return "cannot infer type".to_string();
+ }
+
+ let suffix = match (&self.parent, use_diag) {
+ (Some(parent), _) => format!(" declared on the {} `{}`", parent.prefix, parent.name),
+ (None, Some(use_diag)) => format!(" in {}", use_diag.type_descr()),
+ (None, None) => String::new(),
+ };
+
+ // For example: "cannot infer type for type parameter `T`"
+ format!("cannot infer {} `{}`{}", self.kind.prefix_string(), self.name, suffix)
+ }
+}
+
+impl InferenceDiagnosticsParentData {
+ fn for_def_id(tcx: TyCtxt<'_>, def_id: DefId) -> Option<InferenceDiagnosticsParentData> {
+ let parent_def_id = tcx.parent(def_id)?;
+
+ let parent_name =
+ tcx.def_key(parent_def_id).disambiguated_data.data.get_opt_name()?.to_string();
+
+ Some(InferenceDiagnosticsParentData {
+ prefix: tcx.def_kind(parent_def_id).descr(parent_def_id),
+ name: parent_name,
+ })
+ }
+}
+
+impl UnderspecifiedArgKind {
+ fn prefix_string(&self) -> Cow<'static, str> {
+ match self {
+ Self::Type { prefix } => format!("type for {}", prefix).into(),
+ Self::Const { is_parameter: true } => "the value of const parameter".into(),
+ Self::Const { is_parameter: false } => "the value of the constant".into(),
+ }
+ }
}
impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
@@ -238,32 +359,16 @@
if let TypeVariableOriginKind::TypeParameterDefinition(name, def_id) =
var_origin.kind
{
- let parent_def_id = def_id.and_then(|def_id| self.tcx.parent(def_id));
- let (parent_name, parent_description) =
- if let Some(parent_def_id) = parent_def_id {
- let parent_name = self
- .tcx
- .def_key(parent_def_id)
- .disambiguated_data
- .data
- .get_opt_name()
- .map(|parent_symbol| parent_symbol.to_string());
-
- (
- parent_name,
- Some(self.tcx.def_kind(parent_def_id).descr(parent_def_id)),
- )
- } else {
- (None, None)
- };
-
if name != kw::SelfUpper {
return InferenceDiagnosticsData {
name: name.to_string(),
span: Some(var_origin.span),
- description: "type parameter".into(),
- parent_name,
- parent_description,
+ kind: UnderspecifiedArgKind::Type {
+ prefix: "type parameter".into(),
+ },
+ parent: def_id.and_then(|def_id| {
+ InferenceDiagnosticsParentData::for_def_id(self.tcx, def_id)
+ }),
};
}
}
@@ -278,9 +383,8 @@
InferenceDiagnosticsData {
name: s,
span: None,
- description: ty.prefix_string(),
- parent_name: None,
- parent_description: None,
+ kind: UnderspecifiedArgKind::Type { prefix: ty.prefix_string() },
+ parent: None,
}
}
GenericArgKind::Const(ct) => {
@@ -290,31 +394,11 @@
if let ConstVariableOriginKind::ConstParameterDefinition(name, def_id) =
origin.kind
{
- let parent_def_id = self.tcx.parent(def_id);
- let (parent_name, parent_description) =
- if let Some(parent_def_id) = parent_def_id {
- let parent_name = self
- .tcx
- .def_key(parent_def_id)
- .disambiguated_data
- .data
- .get_opt_name()
- .map(|parent_symbol| parent_symbol.to_string());
-
- (
- parent_name,
- Some(self.tcx.def_kind(parent_def_id).descr(parent_def_id)),
- )
- } else {
- (None, None)
- };
-
return InferenceDiagnosticsData {
name: name.to_string(),
span: Some(origin.span),
- description: "const parameter".into(),
- parent_name,
- parent_description,
+ kind: UnderspecifiedArgKind::Const { is_parameter: true },
+ parent: InferenceDiagnosticsParentData::for_def_id(self.tcx, def_id),
};
}
@@ -329,9 +413,8 @@
InferenceDiagnosticsData {
name: s,
span: Some(origin.span),
- description: "the constant".into(),
- parent_name: None,
- parent_description: None,
+ kind: UnderspecifiedArgKind::Const { is_parameter: false },
+ parent: None,
}
} else {
bug!("unexpect const: {:?}", ct);
@@ -346,6 +429,7 @@
body_id: Option<hir::BodyId>,
span: Span,
arg: GenericArg<'tcx>,
+ impl_candidates: Vec<ty::TraitRef<'tcx>>,
error_code: TypeAnnotationNeeded,
) -> DiagnosticBuilder<'tcx> {
let arg = self.resolve_vars_if_possible(arg);
@@ -430,7 +514,7 @@
// When `arg_data.name` corresponds to a type argument, show the path of the full type we're
// trying to infer. In the following example, `ty_msg` contains
- // " in `std::result::Result<i32, E>`":
+ // " for `std::result::Result<i32, E>`":
// ```
// error[E0282]: type annotations needed for `std::result::Result<i32, E>`
// --> file.rs:L:CC
@@ -448,6 +532,13 @@
error_code,
);
+ let use_diag = local_visitor.found_use_diagnostic.as_ref();
+ if let Some(use_diag) = use_diag {
+ if use_diag.applies_to(err_span) {
+ use_diag.attach_note(&mut err);
+ }
+ }
+
let suffix = match local_visitor.found_node_ty {
Some(ty) if ty.is_closure() => {
let substs =
@@ -463,18 +554,17 @@
if let Some((decl, body_id)) = closure_decl_and_body_id {
closure_return_type_suggestion(
- span,
&mut err,
&decl.output,
self.tcx.hir().body(body_id),
- &arg_data.description,
- &arg_data.name,
&ret,
- arg_data.parent_name,
- arg_data.parent_description,
);
// We don't want to give the other suggestions when the problem is the
// closure return type.
+ err.span_label(
+ span,
+ arg_data.cannot_infer_msg(use_diag.filter(|d| d.applies_to(span))),
+ );
return err;
}
@@ -564,7 +654,44 @@
};
err.span_label(pattern.span, msg);
} else if let Some(e) = local_visitor.found_method_call {
- if let ExprKind::MethodCall(segment, ..) = &e.kind {
+ if let ExprKind::MethodCall(segment, _, exprs, _) = &e.kind {
+ // Suggest impl candidates:
+ //
+ // error[E0283]: type annotations needed
+ // --> $DIR/E0283.rs:35:24
+ // |
+ // LL | let bar = foo_impl.into() * 1u32;
+ // | ---------^^^^--
+ // | | |
+ // | | cannot infer type for type parameter `T` declared on the trait `Into`
+ // | this method call resolves to `T`
+ // | help: specify type like: `<Impl as Into<u32>>::into(foo_impl)`
+ // |
+ // = note: cannot satisfy `Impl: Into<_>`
+ if !impl_candidates.is_empty() && e.span.contains(span) {
+ if let Some(expr) = exprs.first() {
+ if let ExprKind::Path(hir::QPath::Resolved(_, path)) = expr.kind {
+ if let [path_segment] = &path.segments[..] {
+ let candidate_len = impl_candidates.len();
+ let suggestions = impl_candidates.iter().map(|candidate| {
+ format!(
+ "{}::{}({})",
+ candidate, segment.ident, path_segment.ident
+ )
+ });
+ err.span_suggestions(
+ e.span,
+ &format!(
+ "use the fully qualified path for the potential candidate{}",
+ pluralize!(candidate_len),
+ ),
+ suggestions,
+ Applicability::MaybeIncorrect,
+ );
+ }
+ }
+ };
+ }
// Suggest specifying type params or point out the return type of the call:
//
// error[E0282]: type annotations needed
@@ -611,6 +738,8 @@
// |
// = note: type must be known at this point
let span = arg_data.span.unwrap_or(err_span);
+
+ // Avoid multiple labels pointing at `span`.
if !err
.span
.span_labels()
@@ -618,44 +747,44 @@
.any(|span_label| span_label.label.is_some() && span_label.span == span)
&& local_visitor.found_arg_pattern.is_none()
{
- let (kind_str, const_value) = match arg.unpack() {
- GenericArgKind::Type(_) => ("type", None),
- GenericArgKind::Const(_) => ("the value", Some(())),
- GenericArgKind::Lifetime(_) => bug!("unexpected lifetime"),
- };
-
// FIXME(const_generics): we would like to handle const arguments
// as part of the normal diagnostics flow below, but there appear to
// be subtleties in doing so, so for now we special-case const args
// here.
- if let Some(suggestion) = const_value
- .and_then(|_| arg_data.parent_name.as_ref())
- .map(|parent| format!("{}::<{}>", parent, arg_data.name))
+ if let (UnderspecifiedArgKind::Const { .. }, Some(parent_data)) =
+ (&arg_data.kind, &arg_data.parent)
{
err.span_suggestion_verbose(
span,
"consider specifying the const argument",
- suggestion,
+ format!("{}::<{}>", parent_data.name, arg_data.name),
Applicability::MaybeIncorrect,
);
}
- // Avoid multiple labels pointing at `span`.
err.span_label(
span,
- InferCtxt::cannot_infer_msg(
- kind_str,
- &arg_data.name,
- &arg_data.description,
- arg_data.parent_name,
- arg_data.parent_description,
- ),
+ arg_data.cannot_infer_msg(use_diag.filter(|d| d.applies_to(span))),
);
}
err
}
+ fn trait_def_from_hir_fn(&self, hir_id: hir::HirId) -> Option<DefId> {
+ // The DefId will be the method's trait item ID unless this is an inherent impl
+ if let Some((DefKind::AssocFn, def_id)) =
+ self.in_progress_typeck_results?.borrow().type_dependent_def(hir_id)
+ {
+ return self
+ .tcx
+ .parent(def_id)
+ .filter(|&parent_def_id| self.tcx.is_trait(parent_def_id));
+ }
+
+ None
+ }
+
/// If the `FnSig` for the method call can be found and type arguments are identified as
/// needed, suggest annotating the call, otherwise point out the resulting type of the call.
fn annotate_method_call(
@@ -718,49 +847,7 @@
"type inside {} must be known in this context",
kind,
);
- err.span_label(
- span,
- InferCtxt::cannot_infer_msg(
- "type",
- &data.name,
- &data.description,
- data.parent_name,
- data.parent_description,
- ),
- );
+ err.span_label(span, data.cannot_infer_msg(None));
err
}
-
- fn cannot_infer_msg(
- kind_str: &str,
- type_name: &str,
- descr: &str,
- parent_name: Option<String>,
- parent_descr: Option<&str>,
- ) -> String {
- if type_name == "_" {
- format!("cannot infer {}", kind_str)
- } else {
- let parent_desc = if let Some(parent_name) = parent_name {
- let parent_type_descr = if let Some(parent_descr) = parent_descr {
- format!(" the {}", parent_descr)
- } else {
- "".into()
- };
-
- format!(" declared on{} `{}`", parent_type_descr, parent_name)
- } else {
- "".to_string()
- };
-
- // FIXME: We really shouldn't be dealing with strings here
- // but instead use a sensible enum for cases like this.
- let preposition = if "the value" == kind_str { "of" } else { "for" };
- // For example: "cannot infer type for type parameter `T`"
- format!(
- "cannot infer {} {} {} `{}`{}",
- kind_str, preposition, descr, type_name, parent_desc
- )
- }
- }
}
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs
index 5264854..c6ae71b 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs
@@ -345,9 +345,10 @@
match tcx.hir().get_if_local(def_id) {
Some(Node::ImplItem(ImplItem { ident, hir_id, .. })) => {
match tcx.hir().find(tcx.hir().get_parent_item(*hir_id)) {
- Some(Node::Item(Item { kind: ItemKind::Impl { self_ty, .. }, .. })) => {
- Some((*ident, self_ty))
- }
+ Some(Node::Item(Item {
+ kind: ItemKind::Impl(hir::Impl { self_ty, .. }),
+ ..
+ })) => Some((*ident, self_ty)),
_ => None,
}
}
@@ -367,7 +368,7 @@
let impl_did = tcx.hir().local_def_id(*impl_node);
match tcx.hir().get_if_local(impl_did.to_def_id()) {
Some(Node::Item(Item {
- kind: ItemKind::Impl { self_ty, .. },
+ kind: ItemKind::Impl(hir::Impl { self_ty, .. }),
..
})) if trait_objects.iter().all(|did| {
// FIXME: we should check `self_ty` against the receiver
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs
index 4d3217a..61c8113 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs
@@ -132,9 +132,11 @@
[segment]
if segment
.res
- .map(|res| match res {
- Res::SelfTy(_, _) | Res::Def(hir::def::DefKind::TyParam, _) => true,
- _ => false,
+ .map(|res| {
+ matches!(
+ res,
+ Res::SelfTy(_, _) | Res::Def(hir::def::DefKind::TyParam, _)
+ )
})
.unwrap_or(false) =>
{
diff --git a/compiler/rustc_infer/src/infer/error_reporting/note.rs b/compiler/rustc_infer/src/infer/error_reporting/note.rs
index 7fb9433..c88869a 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/note.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/note.rs
@@ -1,6 +1,7 @@
use crate::infer::error_reporting::{note_and_explain_region, ObligationCauseExt};
use crate::infer::{self, InferCtxt, SubregionOrigin};
use rustc_errors::{struct_span_err, DiagnosticBuilder};
+use rustc_middle::traits::ObligationCauseCode;
use rustc_middle::ty::error::TypeError;
use rustc_middle::ty::{self, Region};
@@ -107,14 +108,37 @@
infer::Subtype(box trace) => {
let terr = TypeError::RegionsDoesNotOutlive(sup, sub);
let mut err = self.report_and_explain_type_error(trace, &terr);
- note_and_explain_region(self.tcx, &mut err, "", sup, "...");
- note_and_explain_region(
- self.tcx,
- &mut err,
- "...does not necessarily outlive ",
- sub,
- "",
- );
+ match (sub, sup) {
+ (ty::RePlaceholder(_), ty::RePlaceholder(_)) => {}
+ (ty::RePlaceholder(_), _) => {
+ note_and_explain_region(
+ self.tcx,
+ &mut err,
+ "",
+ sup,
+ " doesn't meet the lifetime requirements",
+ );
+ }
+ (_, ty::RePlaceholder(_)) => {
+ note_and_explain_region(
+ self.tcx,
+ &mut err,
+ "the required lifetime does not necessarily outlive ",
+ sub,
+ "",
+ );
+ }
+ _ => {
+ note_and_explain_region(self.tcx, &mut err, "", sup, "...");
+ note_and_explain_region(
+ self.tcx,
+ &mut err,
+ "...does not necessarily outlive ",
+ sub,
+ "",
+ );
+ }
+ }
err
}
infer::Reborrow(span) => {
@@ -286,13 +310,31 @@
sup: Region<'tcx>,
) -> DiagnosticBuilder<'tcx> {
// I can't think how to do better than this right now. -nikomatsakis
+ debug!(?placeholder_origin, ?sub, ?sup, "report_placeholder_failure");
match placeholder_origin {
+ infer::Subtype(box ref trace)
+ if matches!(
+ &trace.cause.code.peel_derives(),
+ ObligationCauseCode::BindingObligation(..)
+ ) =>
+ {
+ // Hack to get around the borrow checker because trace.cause has an `Rc`.
+ if let ObligationCauseCode::BindingObligation(_, span) =
+ &trace.cause.code.peel_derives()
+ {
+ let span = *span;
+ let mut err = self.report_concrete_failure(placeholder_origin, sub, sup);
+ err.span_note(span, "the lifetime requirement is introduced here");
+ err
+ } else {
+ unreachable!()
+ }
+ }
infer::Subtype(box trace) => {
let terr = TypeError::RegionsPlaceholderMismatch;
- self.report_and_explain_type_error(trace, &terr)
+ return self.report_and_explain_type_error(trace, &terr);
}
-
- _ => self.report_concrete_failure(placeholder_origin, sub, sup),
+ _ => return self.report_concrete_failure(placeholder_origin, sub, sup),
}
}
}
diff --git a/compiler/rustc_infer/src/infer/free_regions.rs b/compiler/rustc_infer/src/infer/free_regions.rs
index 32f7323..728dc2d 100644
--- a/compiler/rustc_infer/src/infer/free_regions.rs
+++ b/compiler/rustc_infer/src/infer/free_regions.rs
@@ -93,10 +93,7 @@
/// True for free regions other than `'static`.
pub fn is_free(&self, r: Region<'_>) -> bool {
- match *r {
- ty::ReEarlyBound(_) | ty::ReFree(_) => true,
- _ => false,
- }
+ matches!(r, ty::ReEarlyBound(_) | ty::ReFree(_))
}
/// True if `r` is a free region or static of the sort that this
diff --git a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs
index d7b2ce7..ab34cda 100644
--- a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs
+++ b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs
@@ -393,10 +393,7 @@
if self.expand_node(a_region, b_vid, b_data) {
changes.push(b_vid);
}
- match *b_data {
- VarValue::Value(ReStatic) | VarValue::ErrorValue => false,
- _ => true,
- }
+ !matches!(b_data, VarValue::Value(ReStatic) | VarValue::ErrorValue)
});
}
}
@@ -972,11 +969,7 @@
}
VerifyBound::IsEmpty => {
- if let ty::ReEmpty(_) = min {
- true
- } else {
- false
- }
+ matches!(min, ty::ReEmpty(_))
}
VerifyBound::AnyBound(bs) => {
diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs
index 069f708..09eecd7 100644
--- a/compiler/rustc_infer/src/infer/mod.rs
+++ b/compiler/rustc_infer/src/infer/mod.rs
@@ -458,11 +458,11 @@
/// This origin is used for the inference variables that we create
/// during NLL region processing.
- NLL(NLLRegionVariableOrigin),
+ Nll(NllRegionVariableOrigin),
}
#[derive(Copy, Clone, Debug)]
-pub enum NLLRegionVariableOrigin {
+pub enum NllRegionVariableOrigin {
/// During NLL region processing, we create variables for free
/// regions that we encounter in the function signature and
/// elsewhere. This origin indices we've got one of those.
@@ -1078,17 +1078,17 @@
}
/// Just a convenient wrapper of `next_region_var` for using during NLL.
- pub fn next_nll_region_var(&self, origin: NLLRegionVariableOrigin) -> ty::Region<'tcx> {
- self.next_region_var(RegionVariableOrigin::NLL(origin))
+ pub fn next_nll_region_var(&self, origin: NllRegionVariableOrigin) -> ty::Region<'tcx> {
+ self.next_region_var(RegionVariableOrigin::Nll(origin))
}
/// Just a convenient wrapper of `next_region_var` for using during NLL.
pub fn next_nll_region_var_in_universe(
&self,
- origin: NLLRegionVariableOrigin,
+ origin: NllRegionVariableOrigin,
universe: ty::UniverseIndex,
) -> ty::Region<'tcx> {
- self.next_region_var_in_universe(RegionVariableOrigin::NLL(origin), universe)
+ self.next_region_var_in_universe(RegionVariableOrigin::Nll(origin), universe)
}
pub fn var_for_def(&self, span: Span, param: &ty::GenericParamDef) -> GenericArg<'tcx> {
@@ -1317,7 +1317,7 @@
T: TypeFoldable<'tcx>,
{
if !value.needs_infer() {
- return value.clone(); // Avoid duplicated subst-folding.
+ return value; // Avoid duplicated subst-folding.
}
let mut r = resolve::OpportunisticVarResolver::new(self);
value.fold_with(&mut r)
@@ -1533,7 +1533,7 @@
// Note: if these two lines are combined into one we get
// dynamic borrow errors on `self.inner`.
let known = self.inner.borrow_mut().type_variables().probe(v).known();
- known.map(|t| self.shallow_resolve_ty(t)).unwrap_or(typ)
+ known.map_or(typ, |t| self.shallow_resolve_ty(t))
}
ty::Infer(ty::IntVar(v)) => self
@@ -1770,7 +1770,7 @@
| LateBoundRegion(a, ..)
| UpvarRegion(_, a) => a,
BoundRegionInCoherence(_) => rustc_span::DUMMY_SP,
- NLL(..) => bug!("NLL variable used with `span`"),
+ Nll(..) => bug!("NLL variable used with `span`"),
}
}
}
diff --git a/compiler/rustc_infer/src/infer/outlives/mod.rs b/compiler/rustc_infer/src/infer/outlives/mod.rs
index de98ccc..07c75d5 100644
--- a/compiler/rustc_infer/src/infer/outlives/mod.rs
+++ b/compiler/rustc_infer/src/infer/outlives/mod.rs
@@ -6,7 +6,6 @@
use rustc_middle::traits::query::OutlivesBound;
use rustc_middle::ty;
-use rustc_middle::ty::fold::TypeFoldable;
pub fn explicit_outlives_bounds<'tcx>(
param_env: ty::ParamEnv<'tcx>,
@@ -15,20 +14,20 @@
param_env
.caller_bounds()
.into_iter()
- .map(ty::Predicate::skip_binders)
- .filter(|atom| !atom.has_escaping_bound_vars())
- .filter_map(move |atom| match atom {
- ty::PredicateAtom::Projection(..)
- | ty::PredicateAtom::Trait(..)
- | ty::PredicateAtom::Subtype(..)
- | ty::PredicateAtom::WellFormed(..)
- | ty::PredicateAtom::ObjectSafe(..)
- | ty::PredicateAtom::ClosureKind(..)
- | ty::PredicateAtom::TypeOutlives(..)
- | ty::PredicateAtom::ConstEvaluatable(..)
- | ty::PredicateAtom::ConstEquate(..)
- | ty::PredicateAtom::TypeWellFormedFromEnv(..) => None,
- ty::PredicateAtom::RegionOutlives(ty::OutlivesPredicate(r_a, r_b)) => {
+ .map(ty::Predicate::kind)
+ .filter_map(ty::Binder::no_bound_vars)
+ .filter_map(move |kind| match kind {
+ ty::PredicateKind::Projection(..)
+ | ty::PredicateKind::Trait(..)
+ | ty::PredicateKind::Subtype(..)
+ | ty::PredicateKind::WellFormed(..)
+ | ty::PredicateKind::ObjectSafe(..)
+ | ty::PredicateKind::ClosureKind(..)
+ | ty::PredicateKind::TypeOutlives(..)
+ | ty::PredicateKind::ConstEvaluatable(..)
+ | ty::PredicateKind::ConstEquate(..)
+ | ty::PredicateKind::TypeWellFormedFromEnv(..) => None,
+ ty::PredicateKind::RegionOutlives(ty::OutlivesPredicate(r_a, r_b)) => {
Some(OutlivesBound::RegionSubRegion(r_b, r_a))
}
})
diff --git a/compiler/rustc_infer/src/infer/sub.rs b/compiler/rustc_infer/src/infer/sub.rs
index a676c5e..6687198 100644
--- a/compiler/rustc_infer/src/infer/sub.rs
+++ b/compiler/rustc_infer/src/infer/sub.rs
@@ -100,7 +100,7 @@
self.fields.obligations.push(Obligation::new(
self.fields.trace.cause.clone(),
self.fields.param_env,
- ty::PredicateAtom::Subtype(ty::SubtypePredicate {
+ ty::PredicateKind::Subtype(ty::SubtypePredicate {
a_is_expected: self.a_is_expected,
a,
b,
diff --git a/compiler/rustc_infer/src/traits/util.rs b/compiler/rustc_infer/src/traits/util.rs
index 8273c2d..13cf1e10 100644
--- a/compiler/rustc_infer/src/traits/util.rs
+++ b/compiler/rustc_infer/src/traits/util.rs
@@ -9,13 +9,8 @@
tcx: TyCtxt<'tcx>,
pred: ty::Predicate<'tcx>,
) -> ty::Predicate<'tcx> {
- match *pred.kind() {
- ty::PredicateKind::ForAll(binder) => {
- let new = ty::PredicateKind::ForAll(tcx.anonymize_late_bound_regions(binder));
- tcx.reuse_or_mk_predicate(pred, new)
- }
- ty::PredicateKind::Atom(_) => pred,
- }
+ let new = tcx.anonymize_late_bound_regions(pred.kind());
+ tcx.reuse_or_mk_predicate(pred, new)
}
struct PredicateSet<'tcx> {
@@ -126,9 +121,9 @@
fn elaborate(&mut self, obligation: &PredicateObligation<'tcx>) {
let tcx = self.visited.tcx;
- let bound_predicate = obligation.predicate.bound_atom();
+ let bound_predicate = obligation.predicate.kind();
match bound_predicate.skip_binder() {
- ty::PredicateAtom::Trait(data, _) => {
+ ty::PredicateKind::Trait(data, _) => {
// Get predicates declared on the trait.
let predicates = tcx.super_predicates_of(data.def_id());
@@ -150,36 +145,36 @@
self.stack.extend(obligations);
}
- ty::PredicateAtom::WellFormed(..) => {
+ ty::PredicateKind::WellFormed(..) => {
// Currently, we do not elaborate WF predicates,
// although we easily could.
}
- ty::PredicateAtom::ObjectSafe(..) => {
+ ty::PredicateKind::ObjectSafe(..) => {
// Currently, we do not elaborate object-safe
// predicates.
}
- ty::PredicateAtom::Subtype(..) => {
+ ty::PredicateKind::Subtype(..) => {
// Currently, we do not "elaborate" predicates like `X <: Y`,
// though conceivably we might.
}
- ty::PredicateAtom::Projection(..) => {
+ ty::PredicateKind::Projection(..) => {
// Nothing to elaborate in a projection predicate.
}
- ty::PredicateAtom::ClosureKind(..) => {
+ ty::PredicateKind::ClosureKind(..) => {
// Nothing to elaborate when waiting for a closure's kind to be inferred.
}
- ty::PredicateAtom::ConstEvaluatable(..) => {
+ ty::PredicateKind::ConstEvaluatable(..) => {
// Currently, we do not elaborate const-evaluatable
// predicates.
}
- ty::PredicateAtom::ConstEquate(..) => {
+ ty::PredicateKind::ConstEquate(..) => {
// Currently, we do not elaborate const-equate
// predicates.
}
- ty::PredicateAtom::RegionOutlives(..) => {
+ ty::PredicateKind::RegionOutlives(..) => {
// Nothing to elaborate from `'a: 'b`.
}
- ty::PredicateAtom::TypeOutlives(ty::OutlivesPredicate(ty_max, r_min)) => {
+ ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(ty_max, r_min)) => {
// We know that `T: 'a` for some type `T`. We can
// often elaborate this. For example, if we know that
// `[U]: 'a`, that implies that `U: 'a`. Similarly, if
@@ -209,7 +204,7 @@
if r.is_late_bound() {
None
} else {
- Some(ty::PredicateAtom::RegionOutlives(ty::OutlivesPredicate(
+ Some(ty::PredicateKind::RegionOutlives(ty::OutlivesPredicate(
r, r_min,
)))
}
@@ -217,7 +212,7 @@
Component::Param(p) => {
let ty = tcx.mk_ty_param(p.index, p.name);
- Some(ty::PredicateAtom::TypeOutlives(ty::OutlivesPredicate(
+ Some(ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(
ty, r_min,
)))
}
@@ -242,7 +237,7 @@
}),
);
}
- ty::PredicateAtom::TypeWellFormedFromEnv(..) => {
+ ty::PredicateKind::TypeWellFormedFromEnv(..) => {
// Nothing to elaborate
}
}
diff --git a/compiler/rustc_interface/src/lib.rs b/compiler/rustc_interface/src/lib.rs
index 0935eb2..f2b69da 100644
--- a/compiler/rustc_interface/src/lib.rs
+++ b/compiler/rustc_interface/src/lib.rs
@@ -1,4 +1,5 @@
#![feature(bool_to_option)]
+#![feature(box_patterns)]
#![feature(box_syntax)]
#![feature(internal_output_capture)]
#![feature(nll)]
diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs
index 61ebd6d..56aa393 100644
--- a/compiler/rustc_interface/src/passes.rs
+++ b/compiler/rustc_interface/src/passes.rs
@@ -33,7 +33,7 @@
use rustc_session::output::{filename_for_input, filename_for_metadata};
use rustc_session::search_paths::PathKind;
use rustc_session::Session;
-use rustc_span::symbol::Symbol;
+use rustc_span::symbol::{Ident, Symbol};
use rustc_span::{FileName, RealFileName};
use rustc_trait_selection::traits;
use rustc_typeck as typeck;
@@ -211,8 +211,13 @@
Ok((krate, lint_store))
}
-fn pre_expansion_lint(sess: &Session, lint_store: &LintStore, krate: &ast::Crate) {
- sess.time("pre_AST_expansion_lint_checks", || {
+fn pre_expansion_lint(
+ sess: &Session,
+ lint_store: &LintStore,
+ krate: &ast::Crate,
+ crate_name: &str,
+) {
+ sess.prof.generic_activity_with_arg("pre_AST_expansion_lint_checks", crate_name).run(|| {
rustc_lint::check_ast_crate(
sess,
lint_store,
@@ -233,10 +238,10 @@
metadata_loader: &'a MetadataLoaderDyn,
) -> Result<(ast::Crate, Resolver<'a>)> {
tracing::trace!("configure_and_expand_inner");
- pre_expansion_lint(sess, lint_store, &krate);
+ pre_expansion_lint(sess, lint_store, &krate, crate_name);
let mut resolver = Resolver::new(sess, &krate, crate_name, metadata_loader, &resolver_arenas);
- rustc_builtin_macros::register_builtin_macros(&mut resolver, sess.edition());
+ rustc_builtin_macros::register_builtin_macros(&mut resolver);
krate = sess.time("crate_injection", || {
let alt_std_name = sess.opts.alt_std_name.as_ref().map(|s| Symbol::intern(s));
@@ -295,7 +300,9 @@
..rustc_expand::expand::ExpansionConfig::default(crate_name.to_string())
};
- let extern_mod_loaded = |k: &ast::Crate| pre_expansion_lint(sess, lint_store, k);
+ let extern_mod_loaded = |k: &ast::Crate, ident: Ident| {
+ pre_expansion_lint(sess, lint_store, k, &*ident.name.as_str())
+ };
let mut ecx = ExtCtxt::new(&sess, cfg, &mut resolver, Some(&extern_mod_loaded));
// Expand macros now!
@@ -797,12 +804,6 @@
})
});
- // Do some initialization of the DepGraph that can only be done with the tcx available.
- let icx = ty::tls::ImplicitCtxt::new(&gcx);
- ty::tls::enter_context(&icx, |_| {
- icx.tcx.sess.time("dep_graph_tcx_init", || rustc_incremental::dep_graph_tcx_init(icx.tcx));
- });
-
QueryContext(gcx)
}
@@ -889,7 +890,7 @@
// Avoid overwhelming user with errors if borrow checking failed.
// I'm not sure how helpful this is, to be honest, but it avoids a
- // lot of annoying errors in the compile-fail tests (basically,
+ // lot of annoying errors in the ui tests (basically,
// lint warnings and so on -- kindck used to do this abort, but
// kindck is gone now). -nmatsakis
if sess.has_errors() {
@@ -1013,6 +1014,16 @@
codegen_backend.codegen_crate(tcx, metadata, need_metadata_module)
});
+ // Don't run these test assertions when not doing codegen. Compiletest tries to build
+ // build-fail tests in check mode first and expects it to not give an error in that case.
+ if tcx.sess.opts.output_types.should_codegen() {
+ rustc_incremental::assert_module_sources::assert_module_sources(tcx);
+ rustc_symbol_mangling::test::report_symbol_names(tcx);
+ }
+
+ tcx.sess.time("assert_dep_graph", || rustc_incremental::assert_dep_graph(tcx));
+ tcx.sess.time("serialize_dep_graph", || rustc_incremental::save_dep_graph(tcx));
+
info!("Post-codegen\n{:?}", tcx.debug_stats());
if tcx.sess.opts.output_types.contains_key(&OutputType::Mir) {
diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs
index 6ea0828..ac6b6d0 100644
--- a/compiler/rustc_interface/src/queries.rs
+++ b/compiler/rustc_interface/src/queries.rs
@@ -280,7 +280,7 @@
// Don't do code generation if there were any errors
self.session().compile_status()?;
- // Hook for compile-fail tests.
+ // Hook for UI tests.
Self::check_for_rustc_errors_attr(tcx);
Ok(passes::start_codegen(&***self.codegen_backend(), tcx, &*outputs.peek()))
@@ -289,7 +289,7 @@
}
/// Check for the `#[rustc_error]` annotation, which forces an error in codegen. This is used
- /// to write compile-fail tests that actually test that compilation succeeds without reporting
+ /// to write UI tests that actually test that compilation succeeds without reporting
/// an error.
fn check_for_rustc_errors_attr(tcx: TyCtxt<'_>) {
let def_id = match tcx.entry_fn(LOCAL_CRATE) {
@@ -403,6 +403,7 @@
return Ok(());
}
+ let _timer = sess.prof.verbose_generic_activity("link_crate");
self.codegen_backend.link(&self.sess, codegen_results, &self.prepare_outputs)
}
}
@@ -416,9 +417,19 @@
let queries = Queries::new(&self);
let ret = f(&queries);
- if self.session().opts.debugging_opts.query_stats {
- if let Ok(gcx) = queries.global_ctxt() {
- gcx.peek_mut().print_stats();
+ // NOTE: intentionally does not compute the global context if it hasn't been built yet,
+ // since that likely means there was a parse error.
+ if let Some(Ok(gcx)) = &mut *queries.global_ctxt.result.borrow_mut() {
+ // We assume that no queries are run past here. If there are new queries
+ // after this point, they'll show up as "<unknown>" in self-profiling data.
+ {
+ let _prof_timer =
+ queries.session().prof.generic_activity("self_profile_alloc_query_strings");
+ gcx.enter(|tcx| tcx.alloc_self_profile_query_strings());
+ }
+
+ if self.session().opts.debugging_opts.query_stats {
+ gcx.print_stats();
}
}
diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs
index 3e94f16..f9c3406 100644
--- a/compiler/rustc_interface/src/tests.rs
+++ b/compiler/rustc_interface/src/tests.rs
@@ -7,20 +7,20 @@
use rustc_session::config::{rustc_optgroups, ErrorOutputType, ExternLocation, Options, Passes};
use rustc_session::config::{CFGuard, ExternEntry, LinkerPluginLto, LtoCli, SwitchWithOptPath};
use rustc_session::config::{
- Externs, OutputType, OutputTypes, SanitizerSet, SymbolManglingVersion,
+ Externs, OutputType, OutputTypes, SanitizerSet, SymbolManglingVersion, WasiExecModel,
};
use rustc_session::lint::Level;
use rustc_session::search_paths::SearchPath;
-use rustc_session::utils::NativeLibKind;
+use rustc_session::utils::{CanonicalizedPath, NativeLibKind};
use rustc_session::{build_session, getopts, DiagnosticOutput, Session};
use rustc_span::edition::{Edition, DEFAULT_EDITION};
use rustc_span::symbol::sym;
use rustc_span::SourceFileHashAlgorithm;
use rustc_target::spec::{CodeModel, LinkerFlavor, MergeFunctions, PanicStrategy};
-use rustc_target::spec::{RelocModel, RelroLevel, TlsModel};
+use rustc_target::spec::{RelocModel, RelroLevel, SplitDebuginfo, TlsModel};
use std::collections::{BTreeMap, BTreeSet};
use std::iter::FromIterator;
-use std::path::PathBuf;
+use std::path::{Path, PathBuf};
type CfgSpecs = FxHashSet<(String, Option<String>)>;
@@ -50,7 +50,8 @@
S: Into<String>,
I: IntoIterator<Item = S>,
{
- let locations: BTreeSet<_> = locations.into_iter().map(|s| s.into()).collect();
+ let locations: BTreeSet<CanonicalizedPath> =
+ locations.into_iter().map(|s| CanonicalizedPath::new(Path::new(&s.into()))).collect();
ExternEntry {
location: ExternLocation::ExactPaths(locations),
@@ -446,6 +447,7 @@
tracked!(profile_use, Some(PathBuf::from("abc")));
tracked!(relocation_model, Some(RelocModel::Pic));
tracked!(soft_float, true);
+ tracked!(split_debuginfo, Some(SplitDebuginfo::Packed));
tracked!(target_cpu, Some(String::from("abc")));
tracked!(target_feature, String::from("all the features, all of them"));
}
@@ -538,6 +540,7 @@
// This list is in alphabetical order.
tracked!(allow_features, Some(vec![String::from("lang_items")]));
tracked!(always_encode_mir, true);
+ tracked!(assume_incomplete_release, true);
tracked!(asm_comments, true);
tracked!(binary_dep_depinfo, true);
tracked!(chalk, true);
@@ -579,7 +582,6 @@
tracked!(relax_elf_relocations, Some(true));
tracked!(relro_level, Some(RelroLevel::Full));
tracked!(report_delayed_bugs, true);
- tracked!(run_dsymutil, false);
tracked!(sanitizer, SanitizerSet::ADDRESS);
tracked!(sanitizer_memory_track_origins, 2);
tracked!(sanitizer_recover, SanitizerSet::ADDRESS);
@@ -597,6 +599,7 @@
tracked!(unleash_the_miri_inside_of_you, true);
tracked!(use_ctors_section, Some(true));
tracked!(verify_llvm_ir, true);
+ tracked!(wasi_exec_model, Some(WasiExecModel::Reactor));
}
#[test]
diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs
index f34990a..b7dc539 100644
--- a/compiler/rustc_interface/src/util.rs
+++ b/compiler/rustc_interface/src/util.rs
@@ -759,7 +759,7 @@
fn visit_item_kind(&mut self, i: &mut ast::ItemKind) {
let is_const = match i {
ast::ItemKind::Static(..) | ast::ItemKind::Const(..) => true,
- ast::ItemKind::Fn(_, ref sig, _, _) => Self::is_sig_const(sig),
+ ast::ItemKind::Fn(box ast::FnKind(_, ref sig, _, _)) => Self::is_sig_const(sig),
_ => false,
};
self.run(is_const, |s| noop_visit_item_kind(i, s))
@@ -768,7 +768,7 @@
fn flat_map_trait_item(&mut self, i: P<ast::AssocItem>) -> SmallVec<[P<ast::AssocItem>; 1]> {
let is_const = match i.kind {
ast::AssocItemKind::Const(..) => true,
- ast::AssocItemKind::Fn(_, ref sig, _, _) => Self::is_sig_const(sig),
+ ast::AssocItemKind::Fn(box ast::FnKind(_, ref sig, _, _)) => Self::is_sig_const(sig),
_ => false,
};
self.run(is_const, |s| noop_flat_map_assoc_item(i, s))
diff --git a/compiler/rustc_lexer/src/cursor.rs b/compiler/rustc_lexer/src/cursor.rs
index c0045d3..297f3d1 100644
--- a/compiler/rustc_lexer/src/cursor.rs
+++ b/compiler/rustc_lexer/src/cursor.rs
@@ -33,7 +33,7 @@
#[cfg(not(debug_assertions))]
{
- '\0'
+ EOF_CHAR
}
}
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index 676c85e..2cedef6 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -43,6 +43,7 @@
use rustc_middle::lint::LintDiagnosticBuilder;
use rustc_middle::ty::print::with_no_trimmed_paths;
use rustc_middle::ty::subst::{GenericArgKind, Subst};
+use rustc_middle::ty::Instance;
use rustc_middle::ty::{self, layout::LayoutError, Ty, TyCtxt};
use rustc_session::Session;
use rustc_span::edition::Edition;
@@ -95,18 +96,24 @@
impl EarlyLintPass for WhileTrue {
fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) {
- if let ast::ExprKind::While(cond, ..) = &e.kind {
+ if let ast::ExprKind::While(cond, _, label) = &e.kind {
if let ast::ExprKind::Lit(ref lit) = pierce_parens(cond).kind {
if let ast::LitKind::Bool(true) = lit.kind {
if !lit.span.from_expansion() {
let msg = "denote infinite loops with `loop { ... }`";
- let condition_span = cx.sess.source_map().guess_head_span(e.span);
+ let condition_span = e.span.with_hi(cond.span.hi());
cx.struct_span_lint(WHILE_TRUE, condition_span, |lint| {
lint.build(msg)
.span_suggestion_short(
condition_span,
"use `loop`",
- "loop".to_owned(),
+ format!(
+ "{}loop",
+ label.map_or_else(String::new, |label| format!(
+ "{}: ",
+ label.ident,
+ ))
+ ),
Applicability::MachineApplicable,
)
.emit();
@@ -350,17 +357,15 @@
fn check_item(&mut self, cx: &EarlyContext<'_>, it: &ast::Item) {
match it.kind {
- ast::ItemKind::Trait(_, ast::Unsafe::Yes(_), ..) => {
- self.report_unsafe(cx, it.span, |lint| {
+ ast::ItemKind::Trait(box ast::TraitKind(_, ast::Unsafe::Yes(_), ..)) => self
+ .report_unsafe(cx, it.span, |lint| {
lint.build("declaration of an `unsafe` trait").emit()
- })
- }
+ }),
- ast::ItemKind::Impl { unsafety: ast::Unsafe::Yes(_), .. } => {
- self.report_unsafe(cx, it.span, |lint| {
+ ast::ItemKind::Impl(box ast::ImplKind { unsafety: ast::Unsafe::Yes(_), .. }) => self
+ .report_unsafe(cx, it.span, |lint| {
lint.build("implementation of an `unsafe` trait").emit()
- })
- }
+ }),
_ => {}
}
@@ -541,7 +546,7 @@
return;
}
}
- hir::ItemKind::Impl { of_trait: Some(ref trait_ref), items, .. } => {
+ hir::ItemKind::Impl(hir::Impl { of_trait: Some(ref trait_ref), items, .. }) => {
// If the trait is private, add the impl items to `private_traits` so they don't get
// reported for missing docs.
let real_trait = trait_ref.path.res.def_id();
@@ -865,10 +870,10 @@
impl EarlyLintPass for AnonymousParameters {
fn check_trait_item(&mut self, cx: &EarlyContext<'_>, it: &ast::AssocItem) {
- if let ast::AssocItemKind::Fn(_, ref sig, _, _) = it.kind {
+ if let ast::AssocItemKind::Fn(box FnKind(_, ref sig, _, _)) = it.kind {
for arg in sig.decl.inputs.iter() {
if let ast::PatKind::Ident(_, ident, None) = arg.pat.kind {
- if ident.name == kw::Invalid {
+ if ident.name == kw::Empty {
cx.struct_span_lint(ANONYMOUS_PARAMETERS, arg.pat.span, |lint| {
let ty_snip = cx.sess.source_map().span_to_snippet(arg.ty.span);
@@ -938,8 +943,8 @@
if attr.ident().map(|ident| ident.name) == Some(n) {
if let &AttributeGate::Gated(
Stability::Deprecated(link, suggestion),
- ref name,
- ref reason,
+ name,
+ reason,
_,
) = g
{
@@ -1549,13 +1554,13 @@
impl<'tcx> LateLintPass<'tcx> for TrivialConstraints {
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) {
use rustc_middle::ty::fold::TypeFoldable;
- use rustc_middle::ty::PredicateAtom::*;
+ use rustc_middle::ty::PredicateKind::*;
if cx.tcx.features().trivial_bounds {
let def_id = cx.tcx.hir().local_def_id(item.hir_id);
let predicates = cx.tcx.predicates_of(def_id);
for &(predicate, span) in predicates.predicates {
- let predicate_kind_name = match predicate.skip_binders() {
+ let predicate_kind_name = match predicate.kind().skip_binder() {
Trait(..) => "Trait",
TypeOutlives(..) |
RegionOutlives(..) => "Lifetime",
@@ -1935,8 +1940,8 @@
) -> Vec<ty::Region<'tcx>> {
inferred_outlives
.iter()
- .filter_map(|(pred, _)| match pred.skip_binders() {
- ty::PredicateAtom::RegionOutlives(ty::OutlivesPredicate(a, b)) => match a {
+ .filter_map(|(pred, _)| match pred.kind().skip_binder() {
+ ty::PredicateKind::RegionOutlives(ty::OutlivesPredicate(a, b)) => match a {
ty::ReEarlyBound(ebr) if ebr.index == index => Some(b),
_ => None,
},
@@ -1951,8 +1956,8 @@
) -> Vec<ty::Region<'tcx>> {
inferred_outlives
.iter()
- .filter_map(|(pred, _)| match pred.skip_binders() {
- ty::PredicateAtom::TypeOutlives(ty::OutlivesPredicate(a, b)) => {
+ .filter_map(|(pred, _)| match pred.kind().skip_binder() {
+ ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(a, b)) => {
a.is_param(index).then_some(b)
}
_ => None,
@@ -2299,7 +2304,7 @@
}
}
-const HAS_MIN_FEATURES: &[Symbol] = &[sym::const_generics, sym::specialization];
+const HAS_MIN_FEATURES: &[Symbol] = &[sym::specialization];
declare_lint! {
/// The `invalid_value` lint detects creating a value that is not valid,
@@ -2595,6 +2600,11 @@
}
pub struct ClashingExternDeclarations {
+ /// Map of function symbol name to the first-seen hir id for that symbol name.. If seen_decls
+ /// contains an entry for key K, it means a symbol with name K has been seen by this lint and
+ /// the symbol should be reported as a clashing declaration.
+ // FIXME: Technically, we could just store a &'tcx str here without issue; however, the
+ // `impl_lint_pass` macro doesn't currently support lints parametric over a lifetime.
seen_decls: FxHashMap<Symbol, HirId>,
}
@@ -2626,16 +2636,17 @@
fn insert(&mut self, tcx: TyCtxt<'_>, fi: &hir::ForeignItem<'_>) -> Option<HirId> {
let hid = fi.hir_id;
- let name =
- &tcx.codegen_fn_attrs(tcx.hir().local_def_id(hid)).link_name.unwrap_or(fi.ident.name);
-
- if self.seen_decls.contains_key(name) {
+ let local_did = tcx.hir().local_def_id(fi.hir_id);
+ let did = local_did.to_def_id();
+ let instance = Instance::new(did, ty::List::identity_for_item(tcx, did));
+ let name = Symbol::intern(tcx.symbol_name(instance).name);
+ if let Some(&hir_id) = self.seen_decls.get(&name) {
// Avoid updating the map with the new entry when we do find a collision. We want to
// make sure we're always pointing to the first definition as the previous declaration.
// This lets us avoid emitting "knock-on" diagnostics.
- Some(*self.seen_decls.get(name).unwrap())
+ Some(hir_id)
} else {
- self.seen_decls.insert(*name, hid)
+ self.seen_decls.insert(name, hid)
}
}
diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs
index 780bf5f..58a9064 100644
--- a/compiler/rustc_lint/src/context.rs
+++ b/compiler/rustc_lint/src/context.rs
@@ -262,6 +262,7 @@
}
}
+ #[track_caller]
pub fn register_renamed(&mut self, old_name: &str, new_name: &str) {
let target = match self.by_name.get(new_name) {
Some(&Id(lint_id)) => lint_id,
@@ -368,10 +369,23 @@
lint_name.to_string()
};
// If the lint was scoped with `tool::` check if the tool lint exists
- if tool_name.is_some() {
+ if let Some(tool_name) = tool_name {
match self.by_name.get(&complete_name) {
None => match self.lint_groups.get(&*complete_name) {
- None => return CheckLintNameResult::Tool(Err((None, String::new()))),
+ // If the lint isn't registered, there are two possibilities:
+ None => {
+ // 1. The tool is currently running, so this lint really doesn't exist.
+ // FIXME: should this handle tools that never register a lint, like rustfmt?
+ tracing::debug!("lints={:?}", self.by_name.keys().collect::<Vec<_>>());
+ let tool_prefix = format!("{}::", tool_name);
+ return if self.by_name.keys().any(|lint| lint.starts_with(&tool_prefix)) {
+ self.no_lint_suggestion(&complete_name)
+ } else {
+ // 2. The tool isn't currently running, so no lints will be registered.
+ // To avoid giving a false positive, ignore all unknown lints.
+ CheckLintNameResult::Tool(Err((None, String::new())))
+ };
+ }
Some(LintGroup { lint_ids, .. }) => {
return CheckLintNameResult::Tool(Ok(&lint_ids));
}
@@ -388,7 +402,7 @@
Some(new_name.to_owned()),
),
Some(&Removed(ref reason)) => CheckLintNameResult::Warning(
- format!("lint `{}` has been removed: `{}`", complete_name, reason),
+ format!("lint `{}` has been removed: {}", complete_name, reason),
None,
),
None => match self.lint_groups.get(&*complete_name) {
@@ -412,6 +426,21 @@
}
}
+ fn no_lint_suggestion(&self, lint_name: &str) -> CheckLintNameResult<'_> {
+ let name_lower = lint_name.to_lowercase();
+ let symbols =
+ self.get_lints().iter().map(|l| Symbol::intern(&l.name_lower())).collect::<Vec<_>>();
+
+ if lint_name.chars().any(char::is_uppercase) && self.find_lints(&name_lower).is_ok() {
+ // First check if the lint name is (partly) in upper case instead of lower case...
+ CheckLintNameResult::NoLint(Some(Symbol::intern(&name_lower)))
+ } else {
+ // ...if not, search for lints with a similar name
+ let suggestion = find_best_match_for_name(&symbols, Symbol::intern(&name_lower), None);
+ CheckLintNameResult::NoLint(suggestion)
+ }
+ }
+
fn check_tool_name_for_backwards_compat(
&self,
lint_name: &str,
@@ -421,18 +450,7 @@
match self.by_name.get(&complete_name) {
None => match self.lint_groups.get(&*complete_name) {
// Now we are sure, that this lint exists nowhere
- None => {
- let symbols =
- self.by_name.keys().map(|name| Symbol::intern(&name)).collect::<Vec<_>>();
-
- let suggestion = find_best_match_for_name(
- &symbols,
- Symbol::intern(&lint_name.to_lowercase()),
- None,
- );
-
- CheckLintNameResult::NoLint(suggestion)
- }
+ None => self.no_lint_suggestion(lint_name),
Some(LintGroup { lint_ids, depr, .. }) => {
// Reaching this would be weird, but let's cover this case anyway
if let Some(LintAlias { name, silent }) = depr {
@@ -611,6 +629,13 @@
db.help("to document an item produced by a macro, \
the macro must produce the documentation as part of its expansion");
}
+ BuiltinLintDiagnostics::PatternsInFnsWithoutBody(span, ident) => {
+ db.span_suggestion(span, "remove `mut` from the parameter", ident.to_string(), Applicability::MachineApplicable);
+ }
+ BuiltinLintDiagnostics::MissingAbi(span, default_abi) => {
+ db.span_label(span, "ABI should be specified here");
+ db.help(&format!("the default ABI is {}", default_abi.name()));
+ }
}
// Rewrap `db`, and pass control to the user.
decorate(LintDiagnosticBuilder::new(db));
@@ -736,6 +761,14 @@
hir::QPath::Resolved(_, ref path) => path.res,
hir::QPath::TypeRelative(..) | hir::QPath::LangItem(..) => self
.maybe_typeck_results()
+ .filter(|typeck_results| typeck_results.hir_owner == id.owner)
+ .or_else(|| {
+ if self.tcx.has_typeck_results(id.owner.to_def_id()) {
+ Some(self.tcx.typeck(id.owner))
+ } else {
+ None
+ }
+ })
.and_then(|typeck_results| typeck_results.type_dependent_def(id))
.map_or(Res::Err, |(kind, def_id)| Res::Def(kind, def_id)),
}
@@ -743,7 +776,7 @@
/// Check if a `DefId`'s path matches the given absolute type path usage.
///
- /// Anonymous scopes such as `extern` imports are matched with `kw::Invalid`;
+ /// Anonymous scopes such as `extern` imports are matched with `kw::Empty`;
/// inherent `impl` blocks are matched with the name of the type.
///
/// Instead of using this method, it is often preferable to instead use
diff --git a/compiler/rustc_lint/src/early.rs b/compiler/rustc_lint/src/early.rs
index 08c147e..231edf4 100644
--- a/compiler/rustc_lint/src/early.rs
+++ b/compiler/rustc_lint/src/early.rs
@@ -143,6 +143,14 @@
run_early_pass!(self, check_fn, fk, span, id);
self.check_id(id);
ast_visit::walk_fn(self, fk, span);
+
+ // Explicitly check for lints associated with 'closure_id', since
+ // it does not have a corresponding AST node
+ if let ast_visit::FnKind::Fn(_, _, sig, _, _) = fk {
+ if let ast::Async::Yes { closure_id, .. } = sig.header.asyncness {
+ self.check_id(closure_id);
+ }
+ }
run_early_pass!(self, check_fn_post, fk, span, id);
}
@@ -208,6 +216,14 @@
fn visit_expr_post(&mut self, e: &'a ast::Expr) {
run_early_pass!(self, check_expr_post, e);
+
+ // Explicitly check for lints associated with 'closure_id', since
+ // it does not have a corresponding AST node
+ match e.kind {
+ ast::ExprKind::Closure(_, ast::Async::Yes { closure_id, .. }, ..)
+ | ast::ExprKind::Async(_, closure_id, ..) => self.check_id(closure_id),
+ _ => {}
+ }
}
fn visit_generic_arg(&mut self, arg: &'a ast::GenericArg) {
@@ -379,17 +395,9 @@
// All of the buffered lints should have been emitted at this point.
// If not, that means that we somehow buffered a lint for a node id
// that was not lint-checked (perhaps it doesn't exist?). This is a bug.
- //
- // Rustdoc runs everybody-loops before the early lints and removes
- // function bodies, so it's totally possible for linted
- // node ids to not exist (e.g., macros defined within functions for the
- // unused_macro lint) anymore. So we only run this check
- // when we're not in rustdoc mode. (see issue #47639)
- if !sess.opts.actually_rustdoc {
- for (_id, lints) in buffered.map {
- for early_lint in lints {
- sess.delay_span_bug(early_lint.span, "failed to process buffered lint here");
- }
+ for (_id, lints) in buffered.map {
+ for early_lint in lints {
+ sess.delay_span_bug(early_lint.span, "failed to process buffered lint here");
}
}
}
diff --git a/compiler/rustc_lint/src/internal.rs b/compiler/rustc_lint/src/internal.rs
index af5972c..26e536e 100644
--- a/compiler/rustc_lint/src/internal.rs
+++ b/compiler/rustc_lint/src/internal.rs
@@ -2,7 +2,7 @@
//! Clippy.
use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext};
-use rustc_ast::{Item, ItemKind};
+use rustc_ast::{ImplKind, Item, ItemKind};
use rustc_data_structures::fx::FxHashMap;
use rustc_errors::Applicability;
use rustc_hir::def::Res;
@@ -243,7 +243,7 @@
impl EarlyLintPass for LintPassImpl {
fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) {
- if let ItemKind::Impl { of_trait: Some(lint_pass), .. } = &item.kind {
+ if let ItemKind::Impl(box ImplKind { of_trait: Some(lint_pass), .. }) = &item.kind {
if let Some(last) = lint_pass.path.segments.last() {
if last.ident.name == sym::LintPass {
let expn_data = lint_pass.path.span.ctxt().outer_expn_data();
diff --git a/compiler/rustc_lint/src/late.rs b/compiler/rustc_lint/src/late.rs
index 015e109..3821a39 100644
--- a/compiler/rustc_lint/src/late.rs
+++ b/compiler/rustc_lint/src/late.rs
@@ -140,6 +140,8 @@
fn visit_item(&mut self, it: &'tcx hir::Item<'tcx>) {
let generics = self.context.generics.take();
self.context.generics = it.kind.generics();
+ let old_cached_typeck_results = self.context.cached_typeck_results.take();
+ let old_enclosing_body = self.context.enclosing_body.take();
self.with_lint_attrs(it.hir_id, &it.attrs, |cx| {
cx.with_param_env(it.hir_id, |cx| {
lint_callback!(cx, check_item, it);
@@ -147,6 +149,8 @@
lint_callback!(cx, check_item_post, it);
});
});
+ self.context.enclosing_body = old_enclosing_body;
+ self.context.cached_typeck_results.set(old_cached_typeck_results);
self.context.generics = generics;
}
diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs
index 570578f..1fc2bd0 100644
--- a/compiler/rustc_lint/src/levels.rs
+++ b/compiler/rustc_lint/src/levels.rs
@@ -10,7 +10,7 @@
use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
use rustc_hir::{intravisit, HirId};
use rustc_middle::hir::map::Map;
-use rustc_middle::lint::LevelSource;
+use rustc_middle::lint::LevelAndSource;
use rustc_middle::lint::LintDiagnosticBuilder;
use rustc_middle::lint::{
struct_lint_level, LintLevelMap, LintLevelSets, LintLevelSource, LintSet,
@@ -112,9 +112,9 @@
/// diagnostic with no change to `specs`.
fn insert_spec(
&mut self,
- specs: &mut FxHashMap<LintId, LevelSource>,
+ specs: &mut FxHashMap<LintId, LevelAndSource>,
id: LintId,
- (level, src): LevelSource,
+ (level, src): LevelAndSource,
) {
// Setting to a non-forbid level is an error if the lint previously had
// a forbid level. Note that this is not necessarily true even with a
@@ -356,8 +356,7 @@
|lint| {
let msg = format!(
"lint name `{}` is deprecated \
- and may not have an effect in the future. \
- Also `cfg_attr(cargo-clippy)` won't be necessary anymore",
+ and may not have an effect in the future.",
name
);
lint.build(&msg)
@@ -426,6 +425,11 @@
src,
Some(li.span().into()),
|lint| {
+ let name = if let Some(tool_name) = tool_name {
+ format!("{}::{}", tool_name, name)
+ } else {
+ name.to_string()
+ };
let mut db = lint.build(&format!("unknown lint: `{}`", name));
if let Some(suggestion) = suggestion {
db.span_suggestion(
diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs
index 2336b52..638b73c 100644
--- a/compiler/rustc_lint/src/lib.rs
+++ b/compiler/rustc_lint/src/lib.rs
@@ -30,6 +30,7 @@
#![feature(array_windows)]
#![feature(bool_to_option)]
#![feature(box_syntax)]
+#![feature(box_patterns)]
#![feature(crate_visibility_modifier)]
#![feature(iter_order_by)]
#![feature(never_type)]
@@ -54,8 +55,8 @@
mod levels;
mod methods;
mod non_ascii_idents;
+mod non_fmt_panic;
mod nonstandard_style;
-mod panic_fmt;
mod passes;
mod redundant_semicolon;
mod traits;
@@ -80,8 +81,8 @@
use internal::*;
use methods::*;
use non_ascii_idents::*;
+use non_fmt_panic::NonPanicFmt;
use nonstandard_style::*;
-use panic_fmt::PanicFmt;
use redundant_semicolon::*;
use traits::*;
use types::*;
@@ -168,7 +169,7 @@
ClashingExternDeclarations: ClashingExternDeclarations::new(),
DropTraitConstraints: DropTraitConstraints,
TemporaryCStringAsPtr: TemporaryCStringAsPtr,
- PanicFmt: PanicFmt,
+ NonPanicFmt: NonPanicFmt,
]
);
};
diff --git a/compiler/rustc_lint/src/non_fmt_panic.rs b/compiler/rustc_lint/src/non_fmt_panic.rs
new file mode 100644
index 0000000..e98297b
--- /dev/null
+++ b/compiler/rustc_lint/src/non_fmt_panic.rs
@@ -0,0 +1,197 @@
+use crate::{LateContext, LateLintPass, LintContext};
+use rustc_ast as ast;
+use rustc_errors::{pluralize, Applicability};
+use rustc_hir as hir;
+use rustc_middle::ty;
+use rustc_parse_format::{ParseMode, Parser, Piece};
+use rustc_span::{sym, symbol::kw, InnerSpan, Span, Symbol};
+
+declare_lint! {
+ /// The `non_fmt_panic` lint detects `panic!(..)` invocations where the first
+ /// argument is not a formatting string.
+ ///
+ /// ### Example
+ ///
+ /// ```rust,no_run
+ /// panic!("{}");
+ /// panic!(123);
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// In Rust 2018 and earlier, `panic!(x)` directly uses `x` as the message.
+ /// That means that `panic!("{}")` panics with the message `"{}"` instead
+ /// of using it as a formatting string, and `panic!(123)` will panic with
+ /// an `i32` as message.
+ ///
+ /// Rust 2021 always interprets the first argument as format string.
+ NON_FMT_PANIC,
+ Warn,
+ "detect single-argument panic!() invocations in which the argument is not a format string",
+ report_in_external_macro
+}
+
+declare_lint_pass!(NonPanicFmt => [NON_FMT_PANIC]);
+
+impl<'tcx> LateLintPass<'tcx> for NonPanicFmt {
+ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) {
+ if let hir::ExprKind::Call(f, [arg]) = &expr.kind {
+ if let &ty::FnDef(def_id, _) = cx.typeck_results().expr_ty(f).kind() {
+ if Some(def_id) == cx.tcx.lang_items().begin_panic_fn()
+ || Some(def_id) == cx.tcx.lang_items().panic_fn()
+ || Some(def_id) == cx.tcx.lang_items().panic_str()
+ {
+ if let Some(id) = f.span.ctxt().outer_expn_data().macro_def_id {
+ if cx.tcx.is_diagnostic_item(sym::std_panic_2015_macro, id)
+ || cx.tcx.is_diagnostic_item(sym::core_panic_2015_macro, id)
+ {
+ check_panic(cx, f, arg);
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tcx hir::Expr<'tcx>) {
+ if let hir::ExprKind::Lit(lit) = &arg.kind {
+ if let ast::LitKind::Str(sym, _) = lit.node {
+ // The argument is a string literal.
+ check_panic_str(cx, f, arg, &sym.as_str());
+ return;
+ }
+ }
+
+ // The argument is *not* a string literal.
+
+ let (span, panic) = panic_call(cx, f);
+
+ cx.struct_span_lint(NON_FMT_PANIC, arg.span, |lint| {
+ let mut l = lint.build("panic message is not a string literal");
+ l.note("this is no longer accepted in Rust 2021");
+ if span.contains(arg.span) {
+ l.span_suggestion_verbose(
+ arg.span.shrink_to_lo(),
+ "add a \"{}\" format string to Display the message",
+ "\"{}\", ".into(),
+ Applicability::MaybeIncorrect,
+ );
+ if panic == sym::std_panic_macro {
+ l.span_suggestion_verbose(
+ span.until(arg.span),
+ "or use std::panic::panic_any instead",
+ "std::panic::panic_any(".into(),
+ Applicability::MachineApplicable,
+ );
+ }
+ }
+ l.emit();
+ });
+}
+
+fn check_panic_str<'tcx>(
+ cx: &LateContext<'tcx>,
+ f: &'tcx hir::Expr<'tcx>,
+ arg: &'tcx hir::Expr<'tcx>,
+ fmt: &str,
+) {
+ if !fmt.contains(&['{', '}'][..]) {
+ // No brace, no problem.
+ return;
+ }
+
+ let fmt_span = arg.span.source_callsite();
+
+ let (snippet, style) = match cx.sess().parse_sess.source_map().span_to_snippet(fmt_span) {
+ Ok(snippet) => {
+ // Count the number of `#`s between the `r` and `"`.
+ let style = snippet.strip_prefix('r').and_then(|s| s.find('"'));
+ (Some(snippet), style)
+ }
+ Err(_) => (None, None),
+ };
+
+ let mut fmt_parser =
+ Parser::new(fmt.as_ref(), style, snippet.clone(), false, ParseMode::Format);
+ let n_arguments = (&mut fmt_parser).filter(|a| matches!(a, Piece::NextArgument(_))).count();
+
+ let (span, _) = panic_call(cx, f);
+
+ if n_arguments > 0 && fmt_parser.errors.is_empty() {
+ let arg_spans: Vec<_> = match &fmt_parser.arg_places[..] {
+ [] => vec![fmt_span],
+ v => v.iter().map(|span| fmt_span.from_inner(*span)).collect(),
+ };
+ cx.struct_span_lint(NON_FMT_PANIC, arg_spans, |lint| {
+ let mut l = lint.build(match n_arguments {
+ 1 => "panic message contains an unused formatting placeholder",
+ _ => "panic message contains unused formatting placeholders",
+ });
+ l.note("this message is not used as a format string when given without arguments, but will be in Rust 2021");
+ if span.contains(arg.span) {
+ l.span_suggestion(
+ arg.span.shrink_to_hi(),
+ &format!("add the missing argument{}", pluralize!(n_arguments)),
+ ", ...".into(),
+ Applicability::HasPlaceholders,
+ );
+ l.span_suggestion(
+ arg.span.shrink_to_lo(),
+ "or add a \"{}\" format string to use the message literally",
+ "\"{}\", ".into(),
+ Applicability::MachineApplicable,
+ );
+ }
+ l.emit();
+ });
+ } else {
+ let brace_spans: Option<Vec<_>> =
+ snippet.filter(|s| s.starts_with('"') || s.starts_with("r#")).map(|s| {
+ s.char_indices()
+ .filter(|&(_, c)| c == '{' || c == '}')
+ .map(|(i, _)| fmt_span.from_inner(InnerSpan { start: i, end: i + 1 }))
+ .collect()
+ });
+ let msg = match &brace_spans {
+ Some(v) if v.len() == 1 => "panic message contains a brace",
+ _ => "panic message contains braces",
+ };
+ cx.struct_span_lint(NON_FMT_PANIC, brace_spans.unwrap_or(vec![span]), |lint| {
+ let mut l = lint.build(msg);
+ l.note("this message is not used as a format string, but will be in Rust 2021");
+ if span.contains(arg.span) {
+ l.span_suggestion(
+ arg.span.shrink_to_lo(),
+ "add a \"{}\" format string to use the message literally",
+ "\"{}\", ".into(),
+ Applicability::MachineApplicable,
+ );
+ }
+ l.emit();
+ });
+ }
+}
+
+fn panic_call<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>) -> (Span, Symbol) {
+ let mut expn = f.span.ctxt().outer_expn_data();
+
+ let mut panic_macro = kw::Empty;
+
+ // Unwrap more levels of macro expansion, as panic_2015!()
+ // was likely expanded from panic!() and possibly from
+ // [debug_]assert!().
+ for &i in
+ &[sym::std_panic_macro, sym::core_panic_macro, sym::assert_macro, sym::debug_assert_macro]
+ {
+ let parent = expn.call_site.ctxt().outer_expn_data();
+ if parent.macro_def_id.map_or(false, |id| cx.tcx.is_diagnostic_item(i, id)) {
+ expn = parent;
+ panic_macro = i;
+ }
+ }
+
+ (expn.call_site, panic_macro)
+}
diff --git a/compiler/rustc_lint/src/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs
index 6d61b86..121dde3 100644
--- a/compiler/rustc_lint/src/nonstandard_style.rs
+++ b/compiler/rustc_lint/src/nonstandard_style.rs
@@ -56,8 +56,19 @@
declare_lint_pass!(NonCamelCaseTypes => [NON_CAMEL_CASE_TYPES]);
+/// Some unicode characters *have* case, are considered upper case or lower case, but they *can't*
+/// be upper cased or lower cased. For the purposes of the lint suggestion, we care about being able
+/// to change the char's case.
fn char_has_case(c: char) -> bool {
- c.is_lowercase() || c.is_uppercase()
+ let mut l = c.to_lowercase();
+ let mut u = c.to_uppercase();
+ while let Some(l) = l.next() {
+ match u.next() {
+ Some(u) if l != u => return true,
+ _ => {}
+ }
+ }
+ u.next().is_some()
}
fn is_camel_case(name: &str) -> bool {
@@ -138,6 +149,8 @@
to_camel_case(name),
Applicability::MaybeIncorrect,
);
+ } else {
+ err.span_label(ident.span, "should have an UpperCamelCase name");
}
err.emit();
@@ -275,15 +288,32 @@
// We have a valid span in almost all cases, but we don't have one when linting a crate
// name provided via the command line.
if !ident.span.is_dummy() {
+ let sc_ident = Ident::from_str_and_span(&sc, ident.span);
+ let (message, suggestion) = if sc_ident.is_reserved() {
+ // We shouldn't suggest a reserved identifier to fix non-snake-case identifiers.
+ // Instead, recommend renaming the identifier entirely or, if permitted,
+ // escaping it to create a raw identifier.
+ if sc_ident.name.can_be_raw() {
+ ("rename the identifier or convert it to a snake case raw identifier", sc_ident.to_string())
+ } else {
+ err.note(&format!("`{}` cannot be used as a raw identifier", sc));
+ ("rename the identifier", String::new())
+ }
+ } else {
+ ("convert the identifier to snake case", sc)
+ };
+
err.span_suggestion(
ident.span,
- "convert the identifier to snake case",
- sc,
+ message,
+ suggestion,
Applicability::MaybeIncorrect,
);
} else {
err.help(&format!("convert the identifier to snake case: `{}`", sc));
}
+ } else {
+ err.span_label(ident.span, "should have a snake_case name");
}
err.emit();
@@ -397,7 +427,7 @@
}
fn check_pat(&mut self, cx: &LateContext<'_>, p: &hir::Pat<'_>) {
- if let &PatKind::Binding(_, hid, ident, _) = &p.kind {
+ if let PatKind::Binding(_, hid, ident, _) = p.kind {
if let hir::Node::Pat(parent_pat) = cx.tcx.hir().get(cx.tcx.hir().get_parent_node(hid))
{
if let PatKind::Struct(_, field_pats, _) = &parent_pat.kind {
@@ -462,6 +492,8 @@
uc,
Applicability::MaybeIncorrect,
);
+ } else {
+ err.span_label(ident.span, "should have an UPPER_CASE name");
}
err.emit();
diff --git a/compiler/rustc_lint/src/panic_fmt.rs b/compiler/rustc_lint/src/panic_fmt.rs
deleted file mode 100644
index e01ff16..0000000
--- a/compiler/rustc_lint/src/panic_fmt.rs
+++ /dev/null
@@ -1,151 +0,0 @@
-use crate::{LateContext, LateLintPass, LintContext};
-use rustc_ast as ast;
-use rustc_errors::{pluralize, Applicability};
-use rustc_hir as hir;
-use rustc_middle::ty;
-use rustc_parse_format::{ParseMode, Parser, Piece};
-use rustc_span::{sym, InnerSpan};
-
-declare_lint! {
- /// The `non_fmt_panic` lint detects `panic!("..")` with `{` or `}` in the string literal
- /// when it is not used as a format string.
- ///
- /// ### Example
- ///
- /// ```rust,no_run
- /// panic!("{}");
- /// ```
- ///
- /// {{produces}}
- ///
- /// ### Explanation
- ///
- /// `panic!("{}")` panics with the message `"{}"`, as a `panic!()` invocation
- /// with a single argument does not use `format_args!()`.
- /// A future edition of Rust will interpret this string as format string,
- /// which would break this.
- NON_FMT_PANIC,
- Warn,
- "detect braces in single-argument panic!() invocations",
- report_in_external_macro
-}
-
-declare_lint_pass!(PanicFmt => [NON_FMT_PANIC]);
-
-impl<'tcx> LateLintPass<'tcx> for PanicFmt {
- fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) {
- if let hir::ExprKind::Call(f, [arg]) = &expr.kind {
- if let &ty::FnDef(def_id, _) = cx.typeck_results().expr_ty(f).kind() {
- if Some(def_id) == cx.tcx.lang_items().begin_panic_fn()
- || Some(def_id) == cx.tcx.lang_items().panic_fn()
- {
- check_panic(cx, f, arg);
- }
- }
- }
- }
-}
-
-fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tcx hir::Expr<'tcx>) {
- if let hir::ExprKind::Lit(lit) = &arg.kind {
- if let ast::LitKind::Str(sym, _) = lit.node {
- let mut expn = f.span.ctxt().outer_expn_data();
- if let Some(id) = expn.macro_def_id {
- if cx.tcx.is_diagnostic_item(sym::std_panic_macro, id)
- || cx.tcx.is_diagnostic_item(sym::core_panic_macro, id)
- {
- let fmt = sym.as_str();
- if !fmt.contains(&['{', '}'][..]) {
- return;
- }
-
- let fmt_span = arg.span.source_callsite();
-
- let (snippet, style) =
- match cx.sess().parse_sess.source_map().span_to_snippet(fmt_span) {
- Ok(snippet) => {
- // Count the number of `#`s between the `r` and `"`.
- let style = snippet.strip_prefix('r').and_then(|s| s.find('"'));
- (Some(snippet), style)
- }
- Err(_) => (None, None),
- };
-
- let mut fmt_parser =
- Parser::new(fmt.as_ref(), style, snippet.clone(), false, ParseMode::Format);
- let n_arguments =
- (&mut fmt_parser).filter(|a| matches!(a, Piece::NextArgument(_))).count();
-
- // Unwrap another level of macro expansion if this panic!()
- // was expanded from assert!() or debug_assert!().
- for &assert in &[sym::assert_macro, sym::debug_assert_macro] {
- let parent = expn.call_site.ctxt().outer_expn_data();
- if parent
- .macro_def_id
- .map_or(false, |id| cx.tcx.is_diagnostic_item(assert, id))
- {
- expn = parent;
- }
- }
-
- if n_arguments > 0 && fmt_parser.errors.is_empty() {
- let arg_spans: Vec<_> = match &fmt_parser.arg_places[..] {
- [] => vec![fmt_span],
- v => v.iter().map(|span| fmt_span.from_inner(*span)).collect(),
- };
- cx.struct_span_lint(NON_FMT_PANIC, arg_spans, |lint| {
- let mut l = lint.build(match n_arguments {
- 1 => "panic message contains an unused formatting placeholder",
- _ => "panic message contains unused formatting placeholders",
- });
- l.note("this message is not used as a format string when given without arguments, but will be in a future Rust edition");
- if expn.call_site.contains(arg.span) {
- l.span_suggestion(
- arg.span.shrink_to_hi(),
- &format!("add the missing argument{}", pluralize!(n_arguments)),
- ", ...".into(),
- Applicability::HasPlaceholders,
- );
- l.span_suggestion(
- arg.span.shrink_to_lo(),
- "or add a \"{}\" format string to use the message literally",
- "\"{}\", ".into(),
- Applicability::MachineApplicable,
- );
- }
- l.emit();
- });
- } else {
- let brace_spans: Option<Vec<_>> = snippet
- .filter(|s| s.starts_with('"') || s.starts_with("r#"))
- .map(|s| {
- s.char_indices()
- .filter(|&(_, c)| c == '{' || c == '}')
- .map(|(i, _)| {
- fmt_span.from_inner(InnerSpan { start: i, end: i + 1 })
- })
- .collect()
- });
- let msg = match &brace_spans {
- Some(v) if v.len() == 1 => "panic message contains a brace",
- _ => "panic message contains braces",
- };
- cx.struct_span_lint(NON_FMT_PANIC, brace_spans.unwrap_or(vec![expn.call_site]), |lint| {
- let mut l = lint.build(msg);
- l.note("this message is not used as a format string, but will be in a future Rust edition");
- if expn.call_site.contains(arg.span) {
- l.span_suggestion(
- arg.span.shrink_to_lo(),
- "add a \"{}\" format string to use the message literally",
- "\"{}\", ".into(),
- Applicability::MachineApplicable,
- );
- }
- l.emit();
- });
- }
- }
- }
- }
- }
-}
diff --git a/compiler/rustc_lint/src/redundant_semicolon.rs b/compiler/rustc_lint/src/redundant_semicolon.rs
index 428198c..0fe6564 100644
--- a/compiler/rustc_lint/src/redundant_semicolon.rs
+++ b/compiler/rustc_lint/src/redundant_semicolon.rs
@@ -28,27 +28,19 @@
impl EarlyLintPass for RedundantSemicolons {
fn check_block(&mut self, cx: &EarlyContext<'_>, block: &Block) {
- let mut after_item_stmt = false;
let mut seq = None;
for stmt in block.stmts.iter() {
match (&stmt.kind, &mut seq) {
(StmtKind::Empty, None) => seq = Some((stmt.span, false)),
(StmtKind::Empty, Some(seq)) => *seq = (seq.0.to(stmt.span), true),
- (_, seq) => {
- maybe_lint_redundant_semis(cx, seq, after_item_stmt);
- after_item_stmt = matches!(stmt.kind, StmtKind::Item(_));
- }
+ (_, seq) => maybe_lint_redundant_semis(cx, seq),
}
}
- maybe_lint_redundant_semis(cx, &mut seq, after_item_stmt);
+ maybe_lint_redundant_semis(cx, &mut seq);
}
}
-fn maybe_lint_redundant_semis(
- cx: &EarlyContext<'_>,
- seq: &mut Option<(Span, bool)>,
- after_item_stmt: bool,
-) {
+fn maybe_lint_redundant_semis(cx: &EarlyContext<'_>, seq: &mut Option<(Span, bool)>) {
if let Some((span, multiple)) = seq.take() {
// FIXME: Find a better way of ignoring the trailing
// semicolon from macro expansion
@@ -56,12 +48,6 @@
return;
}
- // FIXME: Lint on semicolons after item statements
- // once doing so doesn't break bootstrapping
- if after_item_stmt {
- return;
- }
-
cx.struct_span_lint(REDUNDANT_SEMICOLONS, span, |lint| {
let (msg, rem) = if multiple {
("unnecessary trailing semicolons", "remove these semicolons")
diff --git a/compiler/rustc_lint/src/traits.rs b/compiler/rustc_lint/src/traits.rs
index d4f7903..b031c11 100644
--- a/compiler/rustc_lint/src/traits.rs
+++ b/compiler/rustc_lint/src/traits.rs
@@ -45,12 +45,12 @@
impl<'tcx> LateLintPass<'tcx> for DropTraitConstraints {
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) {
- use rustc_middle::ty::PredicateAtom::*;
+ use rustc_middle::ty::PredicateKind::*;
let def_id = cx.tcx.hir().local_def_id(item.hir_id);
let predicates = cx.tcx.explicit_predicates_of(def_id);
for &(predicate, span) in predicates.predicates {
- let trait_predicate = match predicate.skip_binders() {
+ let trait_predicate = match predicate.kind().skip_binder() {
Trait(trait_predicate, _constness) => trait_predicate,
_ => continue,
};
diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs
index 9ad9d53..1e879d2 100644
--- a/compiler/rustc_lint/src/types.rs
+++ b/compiler/rustc_lint/src/types.rs
@@ -168,25 +168,25 @@
// For `isize` & `usize`, be conservative with the warnings, so that the
// warnings are consistent between 32- and 64-bit platforms.
-fn int_ty_range(int_ty: ast::IntTy) -> (i128, i128) {
+fn int_ty_range(int_ty: ty::IntTy) -> (i128, i128) {
match int_ty {
- ast::IntTy::Isize => (i64::MIN.into(), i64::MAX.into()),
- ast::IntTy::I8 => (i8::MIN.into(), i8::MAX.into()),
- ast::IntTy::I16 => (i16::MIN.into(), i16::MAX.into()),
- ast::IntTy::I32 => (i32::MIN.into(), i32::MAX.into()),
- ast::IntTy::I64 => (i64::MIN.into(), i64::MAX.into()),
- ast::IntTy::I128 => (i128::MIN, i128::MAX),
+ ty::IntTy::Isize => (i64::MIN.into(), i64::MAX.into()),
+ ty::IntTy::I8 => (i8::MIN.into(), i8::MAX.into()),
+ ty::IntTy::I16 => (i16::MIN.into(), i16::MAX.into()),
+ ty::IntTy::I32 => (i32::MIN.into(), i32::MAX.into()),
+ ty::IntTy::I64 => (i64::MIN.into(), i64::MAX.into()),
+ ty::IntTy::I128 => (i128::MIN, i128::MAX),
}
}
-fn uint_ty_range(uint_ty: ast::UintTy) -> (u128, u128) {
+fn uint_ty_range(uint_ty: ty::UintTy) -> (u128, u128) {
let max = match uint_ty {
- ast::UintTy::Usize => u64::MAX.into(),
- ast::UintTy::U8 => u8::MAX.into(),
- ast::UintTy::U16 => u16::MAX.into(),
- ast::UintTy::U32 => u32::MAX.into(),
- ast::UintTy::U64 => u64::MAX.into(),
- ast::UintTy::U128 => u128::MAX,
+ ty::UintTy::Usize => u64::MAX.into(),
+ ty::UintTy::U8 => u8::MAX.into(),
+ ty::UintTy::U16 => u16::MAX.into(),
+ ty::UintTy::U32 => u32::MAX.into(),
+ ty::UintTy::U64 => u64::MAX.into(),
+ ty::UintTy::U128 => u128::MAX,
};
(0, max)
}
@@ -258,8 +258,8 @@
//
// No suggestion for: `isize`, `usize`.
fn get_type_suggestion(t: Ty<'_>, val: u128, negative: bool) -> Option<&'static str> {
- use rustc_ast::IntTy::*;
- use rustc_ast::UintTy::*;
+ use ty::IntTy::*;
+ use ty::UintTy::*;
macro_rules! find_fit {
($ty:expr, $val:expr, $negative:expr,
$($type:ident => [$($utypes:expr),*] => [$($itypes:expr),*]),+) => {
@@ -302,7 +302,7 @@
type_limits: &TypeLimits,
e: &'tcx hir::Expr<'tcx>,
lit: &hir::Lit,
- t: ast::IntTy,
+ t: ty::IntTy,
v: u128,
) {
let int_type = t.normalize(cx.sess().target.pointer_width);
@@ -314,7 +314,14 @@
// avoiding use of -min to prevent overflow/panic
if (negative && v > max + 1) || (!negative && v > max) {
if let Some(repr_str) = get_bin_hex_repr(cx, lit) {
- report_bin_hex_error(cx, e, attr::IntType::SignedInt(t), repr_str, v, negative);
+ report_bin_hex_error(
+ cx,
+ e,
+ attr::IntType::SignedInt(ty::ast_int_ty(t)),
+ repr_str,
+ v,
+ negative,
+ );
return;
}
@@ -351,7 +358,7 @@
cx: &LateContext<'tcx>,
e: &'tcx hir::Expr<'tcx>,
lit: &hir::Lit,
- t: ast::UintTy,
+ t: ty::UintTy,
) {
let uint_type = t.normalize(cx.sess().target.pointer_width);
let (min, max) = uint_ty_range(uint_type);
@@ -391,7 +398,14 @@
}
}
if let Some(repr_str) = get_bin_hex_repr(cx, lit) {
- report_bin_hex_error(cx, e, attr::IntType::UnsignedInt(t), repr_str, lit_val, false);
+ report_bin_hex_error(
+ cx,
+ e,
+ attr::IntType::UnsignedInt(ty::ast_uint_ty(t)),
+ repr_str,
+ lit_val,
+ false,
+ );
return;
}
cx.struct_span_lint(OVERFLOWING_LITERALS, e.span, |lint| {
@@ -430,8 +444,8 @@
ty::Float(t) => {
let is_infinite = match lit.node {
ast::LitKind::Float(v, _) => match t {
- ast::FloatTy::F32 => v.as_str().parse().map(f32::is_infinite),
- ast::FloatTy::F64 => v.as_str().parse().map(f64::is_infinite),
+ ty::FloatTy::F32 => v.as_str().parse().map(f32::is_infinite),
+ ty::FloatTy::F64 => v.as_str().parse().map(f64::is_infinite),
},
_ => bug!(),
};
@@ -647,8 +661,7 @@
let param_env = tcx.param_env(variant.def_id);
for field in &variant.fields {
let field_ty = tcx.type_of(field.did);
- let is_zst =
- tcx.layout_of(param_env.and(field_ty)).map(|layout| layout.is_zst()).unwrap_or(false);
+ let is_zst = tcx.layout_of(param_env.and(field_ty)).map_or(false, |layout| layout.is_zst());
if !is_zst {
return Some(field);
@@ -985,7 +998,7 @@
help: Some("consider using `u32` or `libc::wchar_t` instead".into()),
},
- ty::Int(ast::IntTy::I128) | ty::Uint(ast::UintTy::U128) => FfiUnsafe {
+ ty::Int(ty::IntTy::I128) | ty::Uint(ty::UintTy::U128) => FfiUnsafe {
ty,
reason: "128-bit integers don't currently have a known stable ABI".into(),
help: None,
diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs
index 5e1f94c..b611aeb 100644
--- a/compiler/rustc_lint/src/unused.rs
+++ b/compiler/rustc_lint/src/unused.rs
@@ -202,8 +202,8 @@
let mut has_emitted = false;
for &(predicate, _) in cx.tcx.explicit_item_bounds(def) {
// We only look at the `DefId`, so it is safe to skip the binder here.
- if let ty::PredicateAtom::Trait(ref poly_trait_predicate, _) =
- predicate.skip_binders()
+ if let ty::PredicateKind::Trait(ref poly_trait_predicate, _) =
+ predicate.kind().skip_binder()
{
let def_id = poly_trait_predicate.trait_ref.def_id;
let descr_pre =
@@ -529,8 +529,8 @@
pprust::expr_to_string(value)
};
let keep_space = (
- left_pos.map(|s| s >= value.span.lo()).unwrap_or(false),
- right_pos.map(|s| s <= value.span.hi()).unwrap_or(false),
+ left_pos.map_or(false, |s| s >= value.span.lo()),
+ right_pos.map_or(false, |s| s <= value.span.hi()),
);
self.emit_unused_delims(cx, value.span, &expr_text, ctx.into(), keep_space);
}
@@ -862,11 +862,11 @@
}
fn check_ty(&mut self, cx: &EarlyContext<'_>, ty: &ast::Ty) {
- if let &ast::TyKind::Paren(ref r) = &ty.kind {
+ if let ast::TyKind::Paren(r) = &ty.kind {
match &r.kind {
- &ast::TyKind::TraitObject(..) => {}
- &ast::TyKind::ImplTrait(_, ref bounds) if bounds.len() > 1 => {}
- &ast::TyKind::Array(_, ref len) => {
+ ast::TyKind::TraitObject(..) => {}
+ ast::TyKind::ImplTrait(_, bounds) if bounds.len() > 1 => {}
+ ast::TyKind::Array(_, len) => {
self.check_unused_delims_expr(
cx,
&len.value,
@@ -977,8 +977,6 @@
}
}
ast::ExprKind::Let(_, ref expr) => {
- // FIXME(#60336): Properly handle `let true = (false && true)`
- // actually needing the parenthesis.
self.check_unused_delims_expr(
cx,
expr,
diff --git a/compiler/rustc_lint_defs/Cargo.toml b/compiler/rustc_lint_defs/Cargo.toml
index 7f90808..f909f15 100644
--- a/compiler/rustc_lint_defs/Cargo.toml
+++ b/compiler/rustc_lint_defs/Cargo.toml
@@ -11,3 +11,4 @@
rustc_span = { path = "../rustc_span" }
rustc_serialize = { path = "../rustc_serialize" }
rustc_macros = { path = "../rustc_macros" }
+rustc_target = { path = "../rustc_target" }
diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs
index 655eb22..da62ad3 100644
--- a/compiler/rustc_lint_defs/src/builtin.rs
+++ b/compiler/rustc_lint_defs/src/builtin.rs
@@ -1,10 +1,13 @@
+// ignore-tidy-filelength
//! Some lints that are built in to the compiler.
//!
//! These are the built-in lints that are emitted direct in the main
//! compiler code, rather than using their own custom pass. Those
//! lints are all available in `rustc_lint::builtin`.
-use crate::{declare_lint, declare_lint_pass, declare_tool_lint};
+// ignore-tidy-filelength
+
+use crate::{declare_lint, declare_lint_pass};
use rustc_span::edition::Edition;
use rustc_span::symbol::sym;
@@ -257,14 +260,10 @@
///
/// ### Explanation
///
- /// This lint detects code that is very likely incorrect. When possible,
- /// the compiler will attempt to detect situations where code can be
- /// evaluated at compile-time to generate more efficient code. While
- /// evaluating such code, if it detects that the code will unconditionally
- /// panic, this usually indicates that it is doing something incorrectly.
- /// If this lint is allowed, then the code will not be evaluated at
- /// compile-time, and instead continue to generate code to evaluate at
- /// runtime, which may panic during runtime.
+ /// This lint detects code that is very likely incorrect because it will
+ /// always panic, such as division by zero and out-of-bounds array
+ /// accesses. Consider adjusting your code if this is a bug, or using the
+ /// `panic!` or `unreachable!` macro instead in case the panic is intended.
pub UNCONDITIONAL_PANIC,
Deny,
"operation will cause a panic at runtime"
@@ -278,41 +277,26 @@
///
/// ```rust,compile_fail
/// #![allow(unconditional_panic)]
- /// let x: &'static i32 = &(1 / 0);
+ /// const C: i32 = 1/0;
/// ```
///
/// {{produces}}
///
/// ### Explanation
///
- /// This lint detects code that is very likely incorrect. If this lint is
- /// allowed, then the code will not be evaluated at compile-time, and
- /// instead continue to generate code to evaluate at runtime, which may
- /// panic during runtime.
+ /// This lint detects constants that fail to evaluate. Allowing the lint will accept the
+ /// constant declaration, but any use of this constant will still lead to a hard error. This is
+ /// a future incompatibility lint; the plan is to eventually entirely forbid even declaring
+ /// constants that cannot be evaluated. See [issue #71800] for more details.
///
- /// Note that this lint may trigger in either inside or outside of a
- /// [const context]. Outside of a [const context], the compiler can
- /// sometimes evaluate an expression at compile-time in order to generate
- /// more efficient code. As the compiler becomes better at doing this, it
- /// needs to decide what to do when it encounters code that it knows for
- /// certain will panic or is otherwise incorrect. Making this a hard error
- /// would prevent existing code that exhibited this behavior from
- /// compiling, breaking backwards-compatibility. However, this is almost
- /// certainly incorrect code, so this is a deny-by-default lint. For more
- /// details, see [RFC 1229] and [issue #28238].
- ///
- /// Note that there are several other more specific lints associated with
- /// compile-time evaluation, such as [`arithmetic_overflow`],
- /// [`unconditional_panic`].
- ///
- /// [const context]: https://doc.rust-lang.org/reference/const_eval.html#const-context
- /// [RFC 1229]: https://github.com/rust-lang/rfcs/blob/master/text/1229-compile-time-asserts.md
- /// [issue #28238]: https://github.com/rust-lang/rust/issues/28238
- /// [`arithmetic_overflow`]: deny-by-default.html#arithmetic-overflow
- /// [`unconditional_panic`]: deny-by-default.html#unconditional-panic
+ /// [issue #71800]: https://github.com/rust-lang/rust/issues/71800
pub CONST_ERR,
Deny,
- "constant evaluation detected erroneous expression",
+ "constant evaluation encountered erroneous expression",
+ @future_incompatible = FutureIncompatibleInfo {
+ reference: "issue #71800 <https://github.com/rust-lang/rust/issues/71800>",
+ edition: None,
+ };
report_in_external_macro
}
@@ -2865,12 +2849,79 @@
};
}
-declare_tool_lint! {
- pub rustc::INEFFECTIVE_UNSTABLE_TRAIT_IMPL,
+declare_lint! {
+ /// The `ineffective_unstable_trait_impl` lint detects `#[unstable]` attributes which are not used.
+ ///
+ /// ### Example
+ ///
+ /// ```compile_fail
+ /// #![feature(staged_api)]
+ ///
+ /// #[derive(Clone)]
+ /// #[stable(feature = "x", since = "1")]
+ /// struct S {}
+ ///
+ /// #[unstable(feature = "y", issue = "none")]
+ /// impl Copy for S {}
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// `staged_api` does not currently support using a stability attribute on `impl` blocks.
+ /// `impl`s are always stable if both the type and trait are stable, and always unstable otherwise.
+ pub INEFFECTIVE_UNSTABLE_TRAIT_IMPL,
Deny,
"detects `#[unstable]` on stable trait implementations for stable types"
}
+declare_lint! {
+ /// The `semicolon_in_expressions_from_macros` lint detects trailing semicolons
+ /// in macro bodies when the macro is invoked in expression position.
+ /// This was previous accepted, but is being phased out.
+ ///
+ /// ### Example
+ ///
+ /// ```rust,compile_fail
+ /// #![deny(semicolon_in_expressions_from_macros)]
+ /// macro_rules! foo {
+ /// () => { true; }
+ /// }
+ ///
+ /// fn main() {
+ /// let val = match true {
+ /// true => false,
+ /// _ => foo!()
+ /// };
+ /// }
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// Previous, Rust ignored trailing semicolon in a macro
+ /// body when a macro was invoked in expression position.
+ /// However, this makes the treatment of semicolons in the language
+ /// inconsistent, and could lead to unexpected runtime behavior
+ /// in some circumstances (e.g. if the macro author expects
+ /// a value to be dropped).
+ ///
+ /// This is a [future-incompatible] lint to transition this
+ /// to a hard error in the future. See [issue #79813] for more details.
+ ///
+ /// [issue #79813]: https://github.com/rust-lang/rust/issues/79813
+ /// [future-incompatible]: ../index.md#future-incompatible-lints
+ pub SEMICOLON_IN_EXPRESSIONS_FROM_MACROS,
+ Allow,
+ "trailing semicolon in macro body used as expression",
+ @future_incompatible = FutureIncompatibleInfo {
+ reference: "issue #79813 <https://github.com/rust-lang/rust/issues/79813>",
+ edition: None,
+ };
+}
+
declare_lint_pass! {
/// Does nothing as a lint pass, but registers some `Lint`s
/// that are used by other parts of the compiler.
@@ -2958,6 +3009,9 @@
FUNCTION_ITEM_REFERENCES,
USELESS_DEPRECATED,
UNSUPPORTED_NAKED_FUNCTIONS,
+ MISSING_ABI,
+ SEMICOLON_IN_EXPRESSIONS_FROM_MACROS,
+ DISJOINT_CAPTURE_DROP_REORDER,
]
}
@@ -2984,4 +3038,74 @@
"detects doc comments that aren't used by rustdoc"
}
+declare_lint! {
+ /// The `disjoint_capture_drop_reorder` lint detects variables that aren't completely
+ /// captured when the feature `capture_disjoint_fields` is enabled and it affects the Drop
+ /// order of at least one path starting at this variable.
+ ///
+ /// ### Example
+ ///
+ /// ```rust,compile_fail
+ /// # #![deny(disjoint_capture_drop_reorder)]
+ /// # #![allow(unused)]
+ /// struct FancyInteger(i32);
+ ///
+ /// impl Drop for FancyInteger {
+ /// fn drop(&mut self) {
+ /// println!("Just dropped {}", self.0);
+ /// }
+ /// }
+ ///
+ /// struct Point { x: FancyInteger, y: FancyInteger }
+ ///
+ /// fn main() {
+ /// let p = Point { x: FancyInteger(10), y: FancyInteger(20) };
+ ///
+ /// let c = || {
+ /// let x = p.x;
+ /// };
+ ///
+ /// c();
+ ///
+ /// // ... More code ...
+ /// }
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// In the above example `p.y` will be dropped at the end of `f` instead of with `c` if
+ /// the feature `capture_disjoint_fields` is enabled.
+ pub DISJOINT_CAPTURE_DROP_REORDER,
+ Allow,
+ "Drop reorder because of `capture_disjoint_fields`"
+
+}
+
declare_lint_pass!(UnusedDocComment => [UNUSED_DOC_COMMENTS]);
+
+declare_lint! {
+ /// The `missing_abi` lint detects cases where the ABI is omitted from
+ /// extern declarations.
+ ///
+ /// ### Example
+ ///
+ /// ```rust,compile_fail
+ /// #![deny(missing_abi)]
+ ///
+ /// extern fn foo() {}
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// Historically, Rust implicitly selected C as the ABI for extern
+ /// declarations. We expect to add new ABIs, like `C-unwind`, in the future,
+ /// though this has not yet happened, and especially with their addition
+ /// seeing the ABI easily will make code review easier.
+ pub MISSING_ABI,
+ Allow,
+ "No declared ABI for extern declaration"
+}
diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs
index aec0fc2..9d60a51 100644
--- a/compiler/rustc_lint_defs/src/lib.rs
+++ b/compiler/rustc_lint_defs/src/lib.rs
@@ -6,6 +6,7 @@
use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey};
use rustc_span::edition::Edition;
use rustc_span::{sym, symbol::Ident, MultiSpan, Span, Symbol};
+use rustc_target::spec::abi::Abi;
pub mod builtin;
@@ -252,7 +253,9 @@
UnusedImports(String, Vec<(Span, String)>),
RedundantImport(Vec<(Span, bool)>, Ident),
DeprecatedMacro(Option<Symbol>, Span),
+ MissingAbi(Span, Abi),
UnusedDocComment(Span),
+ PatternsInFnsWithoutBody(Span, Ident),
}
/// Lints that are buffered up early on in the `Session` before the
diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
index c0ff62c..4118e93 100644
--- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
@@ -216,6 +216,14 @@
Call->addAttribute(Index, Attr);
}
+extern "C" void LLVMRustAddCallSiteAttrString(LLVMValueRef Instr, unsigned Index,
+ const char *Name) {
+ CallBase *Call = unwrap<CallBase>(Instr);
+ Attribute Attr = Attribute::get(Call->getContext(), Name);
+ Call->addAttribute(Index, Attr);
+}
+
+
extern "C" void LLVMRustAddAlignmentCallSiteAttr(LLVMValueRef Instr,
unsigned Index,
uint32_t Bytes) {
@@ -660,6 +668,8 @@
return DEBUG_METADATA_VERSION;
}
+extern "C" uint32_t LLVMRustVersionPatch() { return LLVM_VERSION_PATCH; }
+
extern "C" uint32_t LLVMRustVersionMinor() { return LLVM_VERSION_MINOR; }
extern "C" uint32_t LLVMRustVersionMajor() { return LLVM_VERSION_MAJOR; }
@@ -994,11 +1004,9 @@
}
extern "C" LLVMMetadataRef
-LLVMRustDIBuilderCreateDebugLocation(LLVMContextRef ContextRef, unsigned Line,
- unsigned Column, LLVMMetadataRef Scope,
+LLVMRustDIBuilderCreateDebugLocation(unsigned Line, unsigned Column,
+ LLVMMetadataRef Scope,
LLVMMetadataRef InlinedAt) {
- LLVMContext &Context = *unwrap(ContextRef);
-
DebugLoc debug_loc = DebugLoc::get(Line, Column, unwrapDIPtr<MDNode>(Scope),
unwrapDIPtr<MDNode>(InlinedAt));
diff --git a/compiler/rustc_llvm/src/lib.rs b/compiler/rustc_llvm/src/lib.rs
index b2ffa27..592010d 100644
--- a/compiler/rustc_llvm/src/lib.rs
+++ b/compiler/rustc_llvm/src/lib.rs
@@ -38,7 +38,7 @@
($cfg:meta, $($method:ident),*) => { {
#[cfg($cfg)]
fn init() {
- extern {
+ extern "C" {
$(fn $method();)*
}
unsafe {
diff --git a/compiler/rustc_macros/src/query.rs b/compiler/rustc_macros/src/query.rs
index 12990ae..cff8e98 100644
--- a/compiler/rustc_macros/src/query.rs
+++ b/compiler/rustc_macros/src/query.rs
@@ -5,8 +5,8 @@
use syn::punctuated::Punctuated;
use syn::spanned::Spanned;
use syn::{
- braced, parenthesized, parse_macro_input, AttrStyle, Attribute, Block, Error, Expr, Ident,
- ReturnType, Token, Type,
+ braced, parenthesized, parse_macro_input, parse_quote, AttrStyle, Attribute, Block, Error,
+ Expr, Ident, ReturnType, Token, Type,
};
mod kw {
@@ -189,25 +189,6 @@
}
}
-/// A named group containing queries.
-///
-/// For now, the name is not used any more, but the capability remains interesting for future
-/// developments of the query system.
-struct Group {
- #[allow(unused)]
- name: Ident,
- queries: List<Query>,
-}
-
-impl Parse for Group {
- fn parse(input: ParseStream<'_>) -> Result<Self> {
- let name: Ident = input.parse()?;
- let content;
- braced!(content in input);
- Ok(Group { name, queries: content.parse()? })
- }
-}
-
struct QueryModifiers {
/// The description of the query.
desc: (Option<Ident>, Punctuated<Expr, Token![,]>),
@@ -272,6 +253,40 @@
if desc.is_some() {
panic!("duplicate modifier `desc` for query `{}`", query.name);
}
+ // If there are no doc-comments, give at least some idea of what
+ // it does by showing the query description.
+ if query.doc_comments.is_empty() {
+ use ::syn::*;
+ let mut list = list.iter();
+ let format_str: String = match list.next() {
+ Some(&Expr::Lit(ExprLit { lit: Lit::Str(ref lit_str), .. })) => {
+ lit_str.value().replace("`{}`", "{}") // We add them later anyways for consistency
+ }
+ _ => panic!("Expected a string literal"),
+ };
+ let mut fmt_fragments = format_str.split("{}");
+ let mut doc_string = fmt_fragments.next().unwrap().to_string();
+ list.map(::quote::ToTokens::to_token_stream).zip(fmt_fragments).for_each(
+ |(tts, next_fmt_fragment)| {
+ use ::core::fmt::Write;
+ write!(
+ &mut doc_string,
+ " `{}` {}",
+ tts.to_string().replace(" . ", "."),
+ next_fmt_fragment,
+ )
+ .unwrap();
+ },
+ );
+ let doc_string = format!(
+ "[query description - consider adding a doc-comment!] {}",
+ doc_string
+ );
+ let comment = parse_quote! {
+ #[doc = #doc_string]
+ };
+ query.doc_comments.push(comment);
+ }
desc = Some((tcx, list));
}
QueryModifier::FatalCycle => {
@@ -395,7 +410,7 @@
};
let (tcx, desc) = modifiers.desc;
- let tcx = tcx.as_ref().map(|t| quote! { #t }).unwrap_or(quote! { _ });
+ let tcx = tcx.as_ref().map_or(quote! { _ }, |t| quote! { #t });
let desc = quote! {
#[allow(unused_variables)]
@@ -416,72 +431,70 @@
}
pub fn rustc_queries(input: TokenStream) -> TokenStream {
- let groups = parse_macro_input!(input as List<Group>);
+ let queries = parse_macro_input!(input as List<Query>);
let mut query_stream = quote! {};
let mut query_description_stream = quote! {};
let mut dep_node_def_stream = quote! {};
let mut cached_queries = quote! {};
- for group in groups.0 {
- for mut query in group.queries.0 {
- let modifiers = process_modifiers(&mut query);
- let name = &query.name;
- let arg = &query.arg;
- let result_full = &query.result;
- let result = match query.result {
- ReturnType::Default => quote! { -> () },
- _ => quote! { #result_full },
- };
+ for mut query in queries.0 {
+ let modifiers = process_modifiers(&mut query);
+ let name = &query.name;
+ let arg = &query.arg;
+ let result_full = &query.result;
+ let result = match query.result {
+ ReturnType::Default => quote! { -> () },
+ _ => quote! { #result_full },
+ };
- if modifiers.cache.is_some() {
- cached_queries.extend(quote! {
- #name,
- });
- }
-
- let mut attributes = Vec::new();
-
- // Pass on the fatal_cycle modifier
- if modifiers.fatal_cycle {
- attributes.push(quote! { fatal_cycle });
- };
- // Pass on the storage modifier
- if let Some(ref ty) = modifiers.storage {
- attributes.push(quote! { storage(#ty) });
- };
- // Pass on the cycle_delay_bug modifier
- if modifiers.cycle_delay_bug {
- attributes.push(quote! { cycle_delay_bug });
- };
- // Pass on the no_hash modifier
- if modifiers.no_hash {
- attributes.push(quote! { no_hash });
- };
- // Pass on the anon modifier
- if modifiers.anon {
- attributes.push(quote! { anon });
- };
- // Pass on the eval_always modifier
- if modifiers.eval_always {
- attributes.push(quote! { eval_always });
- };
-
- let attribute_stream = quote! {#(#attributes),*};
- let doc_comments = query.doc_comments.iter();
- // Add the query to the group
- query_stream.extend(quote! {
- #(#doc_comments)*
- [#attribute_stream] fn #name(#arg) #result,
+ if modifiers.cache.is_some() {
+ cached_queries.extend(quote! {
+ #name,
});
-
- // Create a dep node for the query
- dep_node_def_stream.extend(quote! {
- [#attribute_stream] #name(#arg),
- });
-
- add_query_description_impl(&query, modifiers, &mut query_description_stream);
}
+
+ let mut attributes = Vec::new();
+
+ // Pass on the fatal_cycle modifier
+ if modifiers.fatal_cycle {
+ attributes.push(quote! { fatal_cycle });
+ };
+ // Pass on the storage modifier
+ if let Some(ref ty) = modifiers.storage {
+ attributes.push(quote! { storage(#ty) });
+ };
+ // Pass on the cycle_delay_bug modifier
+ if modifiers.cycle_delay_bug {
+ attributes.push(quote! { cycle_delay_bug });
+ };
+ // Pass on the no_hash modifier
+ if modifiers.no_hash {
+ attributes.push(quote! { no_hash });
+ };
+ // Pass on the anon modifier
+ if modifiers.anon {
+ attributes.push(quote! { anon });
+ };
+ // Pass on the eval_always modifier
+ if modifiers.eval_always {
+ attributes.push(quote! { eval_always });
+ };
+
+ let attribute_stream = quote! {#(#attributes),*};
+ let doc_comments = query.doc_comments.iter();
+ // Add the query to the group
+ query_stream.extend(quote! {
+ #(#doc_comments)*
+ [#attribute_stream] fn #name(#arg) #result,
+ });
+
+ // Create a dep node for the query
+ dep_node_def_stream.extend(quote! {
+ [#attribute_stream] #name(#arg),
+ });
+
+ add_query_description_impl(&query, modifiers, &mut query_description_stream);
}
TokenStream::from(quote! {
diff --git a/compiler/rustc_macros/src/serialize.rs b/compiler/rustc_macros/src/serialize.rs
index dbeb3c7..72bd480 100644
--- a/compiler/rustc_macros/src/serialize.rs
+++ b/compiler/rustc_macros/src/serialize.rs
@@ -203,7 +203,7 @@
#field_name,
#field_idx,
|__encoder|
- ::rustc_serialize::Encodable::encode(#bind_ident, __encoder),
+ ::rustc_serialize::Encodable::<#encoder_ty>::encode(#bind_ident, __encoder),
) {
::std::result::Result::Ok(()) => (),
::std::result::Result::Err(__err)
@@ -237,7 +237,7 @@
__encoder,
#field_idx,
|__encoder|
- ::rustc_serialize::Encodable::encode(#bind_ident, __encoder),
+ ::rustc_serialize::Encodable::<#encoder_ty>::encode(#bind_ident, __encoder),
) {
::std::result::Result::Ok(()) => (),
::std::result::Result::Err(__err)
diff --git a/compiler/rustc_macros/src/session_diagnostic.rs b/compiler/rustc_macros/src/session_diagnostic.rs
index 610b915..5c061a9 100644
--- a/compiler/rustc_macros/src/session_diagnostic.rs
+++ b/compiler/rustc_macros/src/session_diagnostic.rs
@@ -574,7 +574,7 @@
/// format!("Expected a point greater than ({x}, {y})", x = self.x, y = self.y)
/// ```
/// This function builds the entire call to format!.
- fn build_format(&self, input: &String, span: proc_macro2::Span) -> proc_macro2::TokenStream {
+ fn build_format(&self, input: &str, span: proc_macro2::Span) -> proc_macro2::TokenStream {
// This set is used later to generate the final format string. To keep builds reproducible,
// the iteration order needs to be deterministic, hence why we use a BTreeSet here instead
// of a HashSet.
diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs
index 019ca51..e3fbd1a2 100644
--- a/compiler/rustc_metadata/src/creader.rs
+++ b/compiler/rustc_metadata/src/creader.rs
@@ -28,7 +28,7 @@
use proc_macro::bridge::client::ProcMacro;
use std::path::Path;
-use std::{cmp, env, fs};
+use std::{cmp, env};
use tracing::{debug, info};
#[derive(Clone)]
@@ -252,9 +252,10 @@
// Only use `--extern crate_name=path` here, not `--extern crate_name`.
if let Some(mut files) = entry.files() {
if files.any(|l| {
- let l = fs::canonicalize(l).unwrap_or(l.clone().into());
- source.dylib.as_ref().map(|p| &p.0) == Some(&l)
- || source.rlib.as_ref().map(|p| &p.0) == Some(&l)
+ let l = l.canonicalized();
+ source.dylib.as_ref().map(|(p, _)| p) == Some(l)
+ || source.rlib.as_ref().map(|(p, _)| p) == Some(l)
+ || source.rmeta.as_ref().map(|(p, _)| p) == Some(l)
}) {
ret = Some(cnum);
}
@@ -326,7 +327,7 @@
self.verify_no_symbol_conflicts(&crate_root)?;
let private_dep =
- self.sess.opts.externs.get(&name.as_str()).map(|e| e.is_private_dep).unwrap_or(false);
+ self.sess.opts.externs.get(&name.as_str()).map_or(false, |e| e.is_private_dep);
// Claim this crate number and cache it
let cnum = self.cstore.alloc_new_crate_num();
diff --git a/compiler/rustc_metadata/src/locator.rs b/compiler/rustc_metadata/src/locator.rs
index c4c025d..b66c6cf 100644
--- a/compiler/rustc_metadata/src/locator.rs
+++ b/compiler/rustc_metadata/src/locator.rs
@@ -224,6 +224,7 @@
use rustc_session::config::{self, CrateType};
use rustc_session::filesearch::{FileDoesntMatch, FileMatches, FileSearch};
use rustc_session::search_paths::PathKind;
+use rustc_session::utils::CanonicalizedPath;
use rustc_session::{CrateDisambiguator, Session};
use rustc_span::symbol::{sym, Symbol};
use rustc_span::Span;
@@ -244,7 +245,7 @@
// Immutable per-search configuration.
crate_name: Symbol,
- exact_paths: Vec<PathBuf>,
+ exact_paths: Vec<CanonicalizedPath>,
pub hash: Option<Svh>,
pub host_hash: Option<Svh>,
extra_filename: Option<&'a str>,
@@ -315,7 +316,7 @@
.into_iter()
.filter_map(|entry| entry.files())
.flatten()
- .map(PathBuf::from)
+ .cloned()
.collect()
} else {
// SVH being specified means this is a transitive dependency,
@@ -664,13 +665,19 @@
let mut rmetas = FxHashMap::default();
let mut dylibs = FxHashMap::default();
for loc in &self.exact_paths {
- if !loc.exists() {
- return Err(CrateError::ExternLocationNotExist(self.crate_name, loc.clone()));
+ if !loc.canonicalized().exists() {
+ return Err(CrateError::ExternLocationNotExist(
+ self.crate_name,
+ loc.original().clone(),
+ ));
}
- let file = match loc.file_name().and_then(|s| s.to_str()) {
+ let file = match loc.original().file_name().and_then(|s| s.to_str()) {
Some(file) => file,
None => {
- return Err(CrateError::ExternLocationNotFile(self.crate_name, loc.clone()));
+ return Err(CrateError::ExternLocationNotFile(
+ self.crate_name,
+ loc.original().clone(),
+ ));
}
};
@@ -685,7 +692,8 @@
// e.g. symbolic links. If we canonicalize too early, we resolve
// the symlink, the file type is lost and we might treat rlibs and
// rmetas as dylibs.
- let loc_canon = fs::canonicalize(&loc).unwrap_or_else(|_| loc.clone());
+ let loc_canon = loc.canonicalized().clone();
+ let loc = loc.original();
if loc.file_name().unwrap().to_str().unwrap().ends_with(".rlib") {
rlibs.insert(loc_canon, PathKind::ExternFlag);
} else if loc.file_name().unwrap().to_str().unwrap().ends_with(".rmeta") {
@@ -695,7 +703,7 @@
}
} else {
self.rejected_via_filename
- .push(CrateMismatch { path: loc.clone(), got: String::new() });
+ .push(CrateMismatch { path: loc.original().clone(), got: String::new() });
}
}
diff --git a/compiler/rustc_metadata/src/native_libs.rs b/compiler/rustc_metadata/src/native_libs.rs
index fe29f9d..8d09943 100644
--- a/compiler/rustc_metadata/src/native_libs.rs
+++ b/compiler/rustc_metadata/src/native_libs.rs
@@ -132,7 +132,7 @@
impl Collector<'tcx> {
fn register_native_lib(&mut self, span: Option<Span>, lib: NativeLib) {
- if lib.name.as_ref().map(|&s| s == kw::Invalid).unwrap_or(false) {
+ if lib.name.as_ref().map_or(false, |&s| s == kw::Empty) {
match span {
Some(span) => {
struct_span_err!(
@@ -192,13 +192,13 @@
fn process_command_line(&mut self) {
// First, check for errors
let mut renames = FxHashSet::default();
- for &(ref name, ref new_name, _) in &self.tcx.sess.opts.libs {
- if let &Some(ref new_name) = new_name {
+ for (name, new_name, _) in &self.tcx.sess.opts.libs {
+ if let Some(ref new_name) = new_name {
let any_duplicate = self
.libs
.iter()
.filter_map(|lib| lib.name.as_ref())
- .any(|n| n.as_str() == *name);
+ .any(|n| &n.as_str() == name);
if new_name.is_empty() {
self.tcx.sess.err(&format!(
"an empty renaming target was specified for library `{}`",
@@ -240,7 +240,7 @@
if kind != NativeLibKind::Unspecified {
lib.kind = kind;
}
- if let &Some(ref new_name) = new_name {
+ if let Some(new_name) = new_name {
lib.name = Some(Symbol::intern(new_name));
}
return true;
diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs
index 43f7b2a..e3c3539 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder.rs
@@ -10,7 +10,8 @@
use rustc_data_structures::fingerprint::{Fingerprint, FingerprintDecoder};
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::svh::Svh;
-use rustc_data_structures::sync::{AtomicCell, Lock, LockGuard, Lrc, OnceCell};
+use rustc_data_structures::sync::{Lock, LockGuard, Lrc, OnceCell};
+use rustc_data_structures::unhash::UnhashMap;
use rustc_errors::ErrorReported;
use rustc_expand::base::{SyntaxExtension, SyntaxExtensionKind};
use rustc_expand::proc_macro::{AttrProcMacro, BangProcMacro, ProcMacroDerive};
@@ -20,7 +21,6 @@
use rustc_hir::definitions::{DefKey, DefPath, DefPathData, DefPathHash};
use rustc_hir::lang_items;
use rustc_index::vec::{Idx, IndexVec};
-use rustc_middle::dep_graph::{self, DepNode, DepNodeExt, DepNodeIndex};
use rustc_middle::hir::exports::Export;
use rustc_middle::middle::cstore::{CrateSource, ExternCrate};
use rustc_middle::middle::cstore::{ForeignModule, LinkagePreference, NativeLib};
@@ -80,14 +80,9 @@
/// For every definition in this crate, maps its `DefPathHash` to its
/// `DefIndex`. See `raw_def_id_to_def_id` for more details about how
/// this is used.
- def_path_hash_map: OnceCell<FxHashMap<DefPathHash, DefIndex>>,
+ def_path_hash_map: OnceCell<UnhashMap<DefPathHash, DefIndex>>,
/// Used for decoding interpret::AllocIds in a cached & thread-safe manner.
alloc_decoding_state: AllocDecodingState,
- /// The `DepNodeIndex` of the `DepNode` representing this upstream crate.
- /// It is initialized on the first access in `get_crate_dep_node_index()`.
- /// Do not access the value directly, as it might not have been initialized yet.
- /// The field must always be initialized to `DepNodeIndex::INVALID`.
- dep_node_index: AtomicCell<DepNodeIndex>,
/// Caches decoded `DefKey`s.
def_key_cache: Lock<FxHashMap<DefIndex, DefKey>>,
/// Caches decoded `DefPathHash`es.
@@ -623,43 +618,6 @@
}
}
-impl EntryKind {
- fn def_kind(&self) -> DefKind {
- match *self {
- EntryKind::AnonConst(..) => DefKind::AnonConst,
- EntryKind::Const(..) => DefKind::Const,
- EntryKind::AssocConst(..) => DefKind::AssocConst,
- EntryKind::ImmStatic
- | EntryKind::MutStatic
- | EntryKind::ForeignImmStatic
- | EntryKind::ForeignMutStatic => DefKind::Static,
- EntryKind::Struct(_, _) => DefKind::Struct,
- EntryKind::Union(_, _) => DefKind::Union,
- EntryKind::Fn(_) | EntryKind::ForeignFn(_) => DefKind::Fn,
- EntryKind::AssocFn(_) => DefKind::AssocFn,
- EntryKind::Type => DefKind::TyAlias,
- EntryKind::TypeParam => DefKind::TyParam,
- EntryKind::ConstParam => DefKind::ConstParam,
- EntryKind::OpaqueTy => DefKind::OpaqueTy,
- EntryKind::AssocType(_) => DefKind::AssocTy,
- EntryKind::Mod(_) => DefKind::Mod,
- EntryKind::Variant(_) => DefKind::Variant,
- EntryKind::Trait(_) => DefKind::Trait,
- EntryKind::TraitAlias => DefKind::TraitAlias,
- EntryKind::Enum(..) => DefKind::Enum,
- EntryKind::MacroDef(_) => DefKind::Macro(MacroKind::Bang),
- EntryKind::ProcMacro(kind) => DefKind::Macro(kind),
- EntryKind::ForeignType => DefKind::ForeignTy,
- EntryKind::Impl(_) => DefKind::Impl,
- EntryKind::Closure => DefKind::Closure,
- EntryKind::ForeignMod => DefKind::ForeignMod,
- EntryKind::GlobalAsm => DefKind::GlobalAsm,
- EntryKind::Field => DefKind::Field,
- EntryKind::Generator(_) => DefKind::Generator,
- }
- }
-}
-
impl CrateRoot<'_> {
crate fn is_proc_macro_crate(&self) -> bool {
self.proc_macro_data.is_some()
@@ -690,21 +648,6 @@
}
impl<'a, 'tcx> CrateMetadataRef<'a> {
- fn maybe_kind(&self, item_id: DefIndex) -> Option<EntryKind> {
- self.root.tables.kind.get(self, item_id).map(|k| k.decode(self))
- }
-
- fn kind(&self, item_id: DefIndex) -> EntryKind {
- self.maybe_kind(item_id).unwrap_or_else(|| {
- bug!(
- "CrateMetadata::kind({:?}): id not found, in crate {:?} with number {}",
- item_id,
- self.root.name,
- self.cnum,
- )
- })
- }
-
fn raw_proc_macro(&self, id: DefIndex) -> &ProcMacro {
// DefIndex's in root.proc_macro_data have a one-to-one correspondence
// with items in 'raw_proc_macros'.
@@ -720,25 +663,51 @@
&self.raw_proc_macros.unwrap()[pos]
}
- fn item_ident(&self, item_index: DefIndex, sess: &Session) -> Ident {
+ 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()
- .expect("no name in item_ident");
+ .ok_or_else(|| format!("Missing opt name for {:?}", item_index))?;
let span = self
.root
.tables
.ident_span
.get(self, item_index)
- .map(|data| data.decode((self, sess)))
- .unwrap_or_else(|| panic!("Missing ident span for {:?} ({:?})", name, item_index));
- Ident::new(name, span)
+ .ok_or_else(|| format!("Missing ident span for {:?} ({:?})", name, item_index))?
+ .decode((self, sess));
+ Ok(Ident::new(name, span))
}
- fn def_kind(&self, index: DefIndex) -> DefKind {
- self.kind(index).def_kind()
+ fn item_ident(&self, item_index: DefIndex, sess: &Session) -> Ident {
+ self.try_item_ident(item_index, sess).unwrap()
+ }
+
+ fn maybe_kind(&self, item_id: DefIndex) -> Option<EntryKind> {
+ self.root.tables.kind.get(self, item_id).map(|k| k.decode(self))
+ }
+
+ fn kind(&self, item_id: DefIndex) -> EntryKind {
+ self.maybe_kind(item_id).unwrap_or_else(|| {
+ bug!(
+ "CrateMetadata::kind({:?}): id not found, in crate {:?} with number {}",
+ item_id,
+ self.root.name,
+ self.cnum,
+ )
+ })
+ }
+
+ fn def_kind(&self, item_id: DefIndex) -> DefKind {
+ self.root.tables.def_kind.get(self, item_id).map(|k| k.decode(self)).unwrap_or_else(|| {
+ bug!(
+ "CrateMetadata::def_kind({:?}): id not found, in crate {:?} with number {}",
+ item_id,
+ self.root.name,
+ self.cnum,
+ )
+ })
}
fn get_span(&self, index: DefIndex, sess: &Session) -> Span {
@@ -1055,19 +1024,15 @@
// Iterate over all children.
let macros_only = self.dep_kind.lock().macros_only();
- let children = self.root.tables.children.get(self, id).unwrap_or_else(Lazy::empty);
- for child_index in children.decode((self, sess)) {
- if macros_only {
- continue;
- }
+ if !macros_only {
+ let children = self.root.tables.children.get(self, id).unwrap_or_else(Lazy::empty);
- // Get the item.
- if let Some(child_kind) = self.maybe_kind(child_index) {
- match child_kind {
- EntryKind::MacroDef(..) => {}
- _ if macros_only => continue,
- _ => {}
- }
+ 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 {
@@ -1102,8 +1067,8 @@
}
let def_key = self.def_key(child_index);
- let span = self.get_span(child_index, sess);
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);
@@ -1137,9 +1102,8 @@
// within the crate. We only need this for fictive constructors,
// for other constructors correct visibilities
// were already encoded in metadata.
- let attrs: Vec<_> =
- self.get_item_attrs(def_id.index, sess).collect();
- if sess.contains_name(&attrs, sym::non_exhaustive) {
+ let mut attrs = self.get_item_attrs(def_id.index, sess);
+ if attrs.any(|item| item.has_name(sym::non_exhaustive)) {
let crate_def_id = self.local_def_id(CRATE_DEF_INDEX);
vis = ty::Visibility::Restricted(crate_def_id);
}
@@ -1164,6 +1128,10 @@
}
}
+ fn is_ctfe_mir_available(&self, id: DefIndex) -> bool {
+ self.root.tables.mir_for_ctfe.get(self, id).is_some()
+ }
+
fn is_item_mir_available(&self, id: DefIndex) -> bool {
self.root.tables.mir.get(self, id).is_some()
}
@@ -1187,6 +1155,17 @@
.decode((self, tcx))
}
+ fn get_mir_for_ctfe(&self, tcx: TyCtxt<'tcx>, id: DefIndex) -> Body<'tcx> {
+ self.root
+ .tables
+ .mir_for_ctfe
+ .get(self, id)
+ .unwrap_or_else(|| {
+ bug!("get_mir_for_ctfe: missing MIR for `{:?}`", self.local_def_id(id))
+ })
+ .decode((self, tcx))
+ }
+
fn get_mir_abstract_const(
&self,
tcx: TyCtxt<'tcx>,
@@ -1345,15 +1324,14 @@
return &[];
}
- // Do a reverse lookup beforehand to avoid touching the crate_num
- // hash map in the loop below.
- let filter = match filter.map(|def_id| self.reverse_translate_def_id(def_id)) {
- Some(Some(def_id)) => Some((def_id.krate.as_u32(), def_id.index)),
- Some(None) => return &[],
- None => None,
- };
+ 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 &[],
+ };
- if let Some(filter) = filter {
if let Some(impls) = self.trait_impls.get(&filter) {
tcx.arena.alloc_from_iter(
impls.decode(self).map(|(idx, simplified_self_ty)| {
@@ -1560,7 +1538,7 @@
// stored in this crate.
let map = self.cdata.def_path_hash_map.get_or_init(|| {
let end_id = self.root.tables.def_path_hashes.size() as u32;
- let mut map = FxHashMap::with_capacity_and_hasher(end_id as usize, Default::default());
+ let mut map = UnhashMap::with_capacity_and_hasher(end_id as usize, Default::default());
for i in 0..end_id {
let def_index = DefIndex::from_u32(i);
// There may be gaps in the encoded table if we're decoding a proc-macro crate
@@ -1597,31 +1575,6 @@
self.def_path_hash_unlocked(index, &mut def_path_hashes)
}
- /// Get the `DepNodeIndex` corresponding this crate. The result of this
- /// method is cached in the `dep_node_index` field.
- fn get_crate_dep_node_index(&self, tcx: TyCtxt<'tcx>) -> DepNodeIndex {
- let mut dep_node_index = self.dep_node_index.load();
-
- if unlikely!(dep_node_index == DepNodeIndex::INVALID) {
- // We have not cached the DepNodeIndex for this upstream crate yet,
- // so use the dep-graph to find it out and cache it.
- // Note that multiple threads can enter this block concurrently.
- // That is fine because the DepNodeIndex remains constant
- // throughout the whole compilation session, and multiple stores
- // would always write the same value.
-
- let def_path_hash = self.def_path_hash(CRATE_DEF_INDEX);
- let dep_node =
- DepNode::from_def_path_hash(def_path_hash, dep_graph::DepKind::CrateMetadata);
-
- dep_node_index = tcx.dep_graph.dep_node_index_of(&dep_node);
- assert!(dep_node_index != DepNodeIndex::INVALID);
- self.dep_node_index.store(dep_node_index);
- }
-
- dep_node_index
- }
-
/// Imports the source_map from an external crate into the source_map of the crate
/// currently being compiled (the "local crate").
///
@@ -1838,7 +1791,6 @@
source_map_import_info: OnceCell::new(),
def_path_hash_map: Default::default(),
alloc_decoding_state,
- dep_node_index: AtomicCell::new(DepNodeIndex::INVALID),
cnum,
cnum_map,
dependencies,
diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
index b7f2288..828c025 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
@@ -44,13 +44,16 @@
let ($def_id, $other) = def_id_arg.into_args();
assert!(!$def_id.is_local());
- let $cdata = CStore::from_tcx($tcx).get_crate_data($def_id.krate);
-
- if $tcx.dep_graph.is_fully_enabled() {
- let crate_dep_node_index = $cdata.get_crate_dep_node_index($tcx);
- $tcx.dep_graph.read_index(crate_dep_node_index);
+ // External query providers call `crate_hash` in order to register a dependency
+ // on the crate metadata. The exception is `crate_hash` itself, which obviously
+ // doesn't need to do this (and can't, as it would cause a query cycle).
+ use rustc_middle::dep_graph::DepKind;
+ if DepKind::$name != DepKind::crate_hash && $tcx.dep_graph.is_fully_enabled() {
+ $tcx.ensure().crate_hash($def_id.krate);
}
+ let $cdata = CStore::from_tcx($tcx).get_crate_data($def_id.krate);
+
$compute
})*
@@ -115,6 +118,7 @@
})
}
optimized_mir => { tcx.arena.alloc(cdata.get_optimized_mir(tcx, def_id.index)) }
+ mir_for_ctfe => { tcx.arena.alloc(cdata.get_mir_for_ctfe(tcx, def_id.index)) }
promoted_mir => { tcx.arena.alloc(cdata.get_promoted_mir(tcx, def_id.index)) }
mir_abstract_const => { cdata.get_mir_abstract_const(tcx, def_id.index) }
unused_generic_params => { cdata.get_unused_generic_params(def_id.index) }
@@ -126,8 +130,11 @@
is_foreign_item => { cdata.is_foreign_item(def_id.index) }
static_mutability => { cdata.static_mutability(def_id.index) }
generator_kind => { cdata.generator_kind(def_id.index) }
- def_kind => { cdata.def_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)
+ }
lookup_stability => {
cdata.get_stability(def_id.index).map(|s| tcx.intern_stability(s))
}
@@ -145,6 +152,7 @@
impl_parent => { cdata.get_parent_impl(def_id.index) }
trait_of_item => { cdata.get_trait_of_item(def_id.index) }
is_mir_available => { cdata.is_item_mir_available(def_id.index) }
+ is_ctfe_mir_available => { cdata.is_ctfe_mir_available(def_id.index) }
dylib_dependency_formats => { cdata.get_dylib_dependency_formats(tcx) }
is_panic_runtime => { cdata.root.panic_runtime }
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index 4dfe3e8..dd6a6fe 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -1,17 +1,16 @@
use crate::rmeta::table::{FixedSizeEncoding, TableBuilder};
use crate::rmeta::*;
-use rustc_ast as ast;
use rustc_data_structures::fingerprint::{Fingerprint, FingerprintEncoder};
-use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet};
+use rustc_data_structures::fx::{FxHashMap, FxIndexSet};
use rustc_data_structures::stable_hasher::StableHasher;
-use rustc_data_structures::sync::{join, Lrc};
+use rustc_data_structures::sync::{join, par_iter, Lrc, ParallelIterator};
use rustc_hir as hir;
-use rustc_hir::def::CtorKind;
+use rustc_hir::def::{CtorOf, DefKind};
use rustc_hir::def_id::{CrateNum, DefId, DefIndex, LocalDefId, CRATE_DEF_INDEX, LOCAL_CRATE};
use rustc_hir::definitions::DefPathData;
use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
-use rustc_hir::itemlikevisit::{ItemLikeVisitor, ParItemLikeVisitor};
+use rustc_hir::itemlikevisit::ItemLikeVisitor;
use rustc_hir::lang_items;
use rustc_hir::{AnonConst, GenericParamKind};
use rustc_index::bit_set::GrowableBitSet;
@@ -46,7 +45,7 @@
lazy_state: LazyState,
type_shorthands: FxHashMap<Ty<'tcx>, usize>,
- predicate_shorthands: FxHashMap<ty::Predicate<'tcx>, usize>,
+ predicate_shorthands: FxHashMap<ty::PredicateKind<'tcx>, usize>,
interpret_allocs: FxIndexSet<interpret::AllocId>,
@@ -308,7 +307,7 @@
impl<'a, 'tcx> FingerprintEncoder for EncodeContext<'a, 'tcx> {
fn encode_fingerprint(&mut self, f: &Fingerprint) -> Result<(), Self::Error> {
- f.encode_opaque(&mut self.opaque)
+ self.opaque.encode_fingerprint(f)
}
}
@@ -323,7 +322,7 @@
&mut self.type_shorthands
}
- fn predicate_shorthands(&mut self) -> &mut FxHashMap<rustc_middle::ty::Predicate<'tcx>, usize> {
+ fn predicate_shorthands(&mut self) -> &mut FxHashMap<ty::PredicateKind<'tcx>, usize> {
&mut self.predicate_shorthands
}
@@ -432,7 +431,7 @@
fn encode_info_for_items(&mut self) {
let krate = self.tcx.hir().krate();
- self.encode_info_for_mod(hir::CRATE_HIR_ID, &krate.item.module, &krate.item.attrs);
+ self.encode_info_for_mod(hir::CRATE_HIR_ID, &krate.item.module);
// Proc-macro crates only export proc-macro items, which are looked
// up using `proc_macro_data`
@@ -575,6 +574,8 @@
// Encode the items.
i = self.position();
+ self.encode_def_ids();
+ self.encode_mir();
self.encode_info_for_items();
let item_bytes = self.position() - i;
@@ -694,7 +695,7 @@
println!(" lang item bytes: {}", lang_item_bytes);
println!(" diagnostic item bytes: {}", diagnostic_item_bytes);
println!(" native bytes: {}", native_lib_bytes);
- println!(" source_map bytes: {}", source_map_bytes);
+ println!(" source_map bytes: {}", source_map_bytes);
println!(" impl bytes: {}", impl_bytes);
println!(" exp. symbols bytes: {}", exported_symbols_bytes);
println!(" def-path table bytes: {}", def_path_table_bytes);
@@ -710,7 +711,154 @@
}
}
+fn should_encode_visibility(def_kind: DefKind) -> bool {
+ match def_kind {
+ DefKind::Mod
+ | DefKind::Struct
+ | DefKind::Union
+ | DefKind::Enum
+ | DefKind::Variant
+ | DefKind::Trait
+ | DefKind::TyAlias
+ | DefKind::ForeignTy
+ | DefKind::TraitAlias
+ | DefKind::AssocTy
+ | DefKind::Fn
+ | DefKind::Const
+ | DefKind::Static
+ | DefKind::Ctor(..)
+ | DefKind::AssocFn
+ | DefKind::AssocConst
+ | DefKind::Macro(..)
+ | DefKind::Use
+ | DefKind::ForeignMod
+ | DefKind::OpaqueTy
+ | DefKind::Impl
+ | DefKind::Field => true,
+ DefKind::TyParam
+ | DefKind::ConstParam
+ | DefKind::LifetimeParam
+ | DefKind::AnonConst
+ | DefKind::GlobalAsm
+ | DefKind::Closure
+ | DefKind::Generator
+ | DefKind::ExternCrate => false,
+ }
+}
+
+fn should_encode_stability(def_kind: DefKind) -> bool {
+ match def_kind {
+ DefKind::Mod
+ | DefKind::Ctor(..)
+ | DefKind::Variant
+ | DefKind::Field
+ | DefKind::Struct
+ | DefKind::AssocTy
+ | DefKind::AssocFn
+ | DefKind::AssocConst
+ | DefKind::TyParam
+ | DefKind::ConstParam
+ | DefKind::Static
+ | DefKind::Const
+ | DefKind::Fn
+ | DefKind::ForeignMod
+ | DefKind::TyAlias
+ | DefKind::OpaqueTy
+ | DefKind::Enum
+ | DefKind::Union
+ | DefKind::Impl
+ | DefKind::Trait
+ | DefKind::TraitAlias
+ | DefKind::Macro(..)
+ | DefKind::ForeignTy => true,
+ DefKind::Use
+ | DefKind::LifetimeParam
+ | DefKind::AnonConst
+ | DefKind::GlobalAsm
+ | DefKind::Closure
+ | DefKind::Generator
+ | DefKind::ExternCrate => false,
+ }
+}
+
+/// Whether we should encode MIR.
+///
+/// Computing, optimizing and encoding the MIR is a relatively expensive operation.
+/// We want to avoid this work when not required. Therefore:
+/// - we only compute `mir_for_ctfe` on items with const-eval semantics;
+/// - we skip `optimized_mir` for check runs.
+///
+/// Return a pair, resp. for CTFE and for LLVM.
+fn should_encode_mir(tcx: TyCtxt<'_>, def_id: LocalDefId) -> (bool, bool) {
+ match tcx.def_kind(def_id) {
+ // Constructors
+ DefKind::Ctor(_, _) => {
+ let mir_opt_base = tcx.sess.opts.output_types.should_codegen()
+ || tcx.sess.opts.debugging_opts.always_encode_mir;
+ (true, mir_opt_base)
+ }
+ // Constants
+ DefKind::AnonConst | DefKind::AssocConst | DefKind::Static | DefKind::Const => {
+ (true, false)
+ }
+ // Full-fledged functions
+ DefKind::AssocFn | DefKind::Fn => {
+ let generics = tcx.generics_of(def_id);
+ let needs_inline = (generics.requires_monomorphization(tcx)
+ || tcx.codegen_fn_attrs(def_id).requests_inline())
+ && tcx.sess.opts.output_types.should_codegen();
+ // Only check the presence of the `const` modifier.
+ let is_const_fn = tcx.is_const_fn_raw(def_id.to_def_id());
+ let always_encode_mir = tcx.sess.opts.debugging_opts.always_encode_mir;
+ (is_const_fn, needs_inline || always_encode_mir)
+ }
+ // Closures can't be const fn.
+ DefKind::Closure => {
+ let generics = tcx.generics_of(def_id);
+ let needs_inline = (generics.requires_monomorphization(tcx)
+ || tcx.codegen_fn_attrs(def_id).requests_inline())
+ && tcx.sess.opts.output_types.should_codegen();
+ let always_encode_mir = tcx.sess.opts.debugging_opts.always_encode_mir;
+ (false, needs_inline || always_encode_mir)
+ }
+ // Generators require optimized MIR to compute layout.
+ DefKind::Generator => (false, true),
+ // The others don't have MIR.
+ _ => (false, false),
+ }
+}
+
impl EncodeContext<'a, 'tcx> {
+ fn encode_def_ids(&mut self) {
+ if self.is_proc_macro {
+ return;
+ }
+ let tcx = self.tcx;
+ let hir = tcx.hir();
+ for local_id in hir.iter_local_def_id() {
+ let def_id = local_id.to_def_id();
+ let def_kind = tcx.opt_def_kind(local_id);
+ let def_kind = if let Some(def_kind) = def_kind { def_kind } else { continue };
+ record!(self.tables.def_kind[def_id] <- match def_kind {
+ // Replace Ctor by the enclosing object to avoid leaking details in children crates.
+ DefKind::Ctor(CtorOf::Struct, _) => DefKind::Struct,
+ DefKind::Ctor(CtorOf::Variant, _) => DefKind::Variant,
+ def_kind => def_kind,
+ });
+ record!(self.tables.span[def_id] <- tcx.def_span(def_id));
+ record!(self.tables.attributes[def_id] <- tcx.get_attrs(def_id));
+ record!(self.tables.expn_that_defined[def_id] <- self.tcx.expansion_that_defined(def_id));
+ if should_encode_visibility(def_kind) {
+ record!(self.tables.visibility[def_id] <- self.tcx.visibility(def_id));
+ }
+ if should_encode_stability(def_kind) {
+ self.encode_stability(def_id);
+ self.encode_const_stability(def_id);
+ self.encode_deprecation(def_id);
+ }
+ }
+ }
+
fn encode_variances_of(&mut self, def_id: DefId) {
debug!("EncodeContext::encode_variances_of({:?})", def_id);
record!(self.tables.variances[def_id] <- &self.tcx.variances_of(def_id)[..]);
@@ -735,17 +883,11 @@
};
record!(self.tables.kind[def_id] <- EntryKind::Variant(self.lazy(data)));
- record!(self.tables.visibility[def_id] <- self.tcx.visibility(def_id));
- record!(self.tables.span[def_id] <- self.tcx.def_span(def_id));
- record!(self.tables.attributes[def_id] <- &self.tcx.get_attrs(def_id)[..]);
- record!(self.tables.expn_that_defined[def_id] <- self.tcx.expansion_that_defined(def_id));
record!(self.tables.children[def_id] <- variant.fields.iter().map(|f| {
assert!(f.did.is_local());
f.did.index
}));
self.encode_ident_span(def_id, variant.ident);
- self.encode_stability(def_id);
- self.encode_deprecation(def_id);
self.encode_item_type(def_id);
if variant.ctor_kind == CtorKind::Fn {
// FIXME(eddyb) encode signature only in `encode_enum_variant_ctor`.
@@ -758,8 +900,6 @@
self.encode_generics(def_id);
self.encode_explicit_predicates(def_id);
self.encode_inferred_outlives(def_id);
- self.encode_optimized_mir(def_id.expect_local());
- self.encode_promoted_mir(def_id.expect_local());
}
fn encode_enum_variant_ctor(&mut self, def: &ty::AdtDef, index: VariantIdx) {
@@ -777,10 +917,6 @@
};
record!(self.tables.kind[def_id] <- EntryKind::Variant(self.lazy(data)));
- record!(self.tables.visibility[def_id] <- self.tcx.visibility(def_id));
- record!(self.tables.span[def_id] <- self.tcx.def_span(def_id));
- self.encode_stability(def_id);
- self.encode_deprecation(def_id);
self.encode_item_type(def_id);
if variant.ctor_kind == CtorKind::Fn {
record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(def_id));
@@ -789,11 +925,9 @@
self.encode_generics(def_id);
self.encode_explicit_predicates(def_id);
self.encode_inferred_outlives(def_id);
- self.encode_optimized_mir(def_id.expect_local());
- self.encode_promoted_mir(def_id.expect_local());
}
- fn encode_info_for_mod(&mut self, id: hir::HirId, md: &hir::Mod<'_>, attrs: &[ast::Attribute]) {
+ fn encode_info_for_mod(&mut self, id: hir::HirId, md: &hir::Mod<'_>) {
let tcx = self.tcx;
let local_def_id = tcx.hir().local_def_id(id);
let def_id = local_def_id.to_def_id();
@@ -826,9 +960,6 @@
};
record!(self.tables.kind[def_id] <- EntryKind::Mod(self.lazy(data)));
- record!(self.tables.visibility[def_id] <- self.tcx.visibility(def_id));
- record!(self.tables.span[def_id] <- self.tcx.def_span(def_id));
- record!(self.tables.attributes[def_id] <- attrs);
if self.is_proc_macro {
record!(self.tables.children[def_id] <- &[]);
} else {
@@ -836,8 +967,6 @@
tcx.hir().local_def_id(item_id.id).local_def_index
}));
}
- self.encode_stability(def_id);
- self.encode_deprecation(def_id);
}
fn encode_field(
@@ -846,24 +975,14 @@
variant_index: VariantIdx,
field_index: usize,
) {
- let tcx = self.tcx;
let variant = &adt_def.variants[variant_index];
let field = &variant.fields[field_index];
let def_id = field.did;
debug!("EncodeContext::encode_field({:?})", def_id);
- let variant_id = tcx.hir().local_def_id_to_hir_id(variant.def_id.expect_local());
- let variant_data = tcx.hir().expect_variant_data(variant_id);
-
record!(self.tables.kind[def_id] <- EntryKind::Field);
- record!(self.tables.visibility[def_id] <- self.tcx.visibility(def_id));
- record!(self.tables.span[def_id] <- self.tcx.def_span(def_id));
- record!(self.tables.attributes[def_id] <- variant_data.fields()[field_index].attrs);
- record!(self.tables.expn_that_defined[def_id] <- self.tcx.expansion_that_defined(def_id));
self.encode_ident_span(def_id, field.ident);
- self.encode_stability(def_id);
- self.encode_deprecation(def_id);
self.encode_item_type(def_id);
self.encode_generics(def_id);
self.encode_explicit_predicates(def_id);
@@ -883,11 +1002,6 @@
};
record!(self.tables.kind[def_id] <- EntryKind::Struct(self.lazy(data), adt_def.repr));
- record!(self.tables.visibility[def_id] <- self.tcx.visibility(def_id));
- record!(self.tables.span[def_id] <- self.tcx.def_span(def_id));
- record!(self.tables.expn_that_defined[def_id] <- self.tcx.expansion_that_defined(def_id));
- self.encode_stability(def_id);
- self.encode_deprecation(def_id);
self.encode_item_type(def_id);
if variant.ctor_kind == CtorKind::Fn {
record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(def_id));
@@ -896,8 +1010,6 @@
self.encode_generics(def_id);
self.encode_explicit_predicates(def_id);
self.encode_inferred_outlives(def_id);
- self.encode_optimized_mir(def_id.expect_local());
- self.encode_promoted_mir(def_id.expect_local());
}
fn encode_generics(&mut self, def_id: DefId) {
@@ -946,29 +1058,25 @@
hir::Defaultness::Final => span_bug!(ast_item.span, "traits cannot have final items"),
};
- record!(self.tables.kind[def_id] <- match trait_item.kind {
+ match trait_item.kind {
ty::AssocKind::Const => {
let rendered = rustc_hir_pretty::to_string(
&(&self.tcx.hir() as &dyn intravisit::Map<'_>),
- |s| s.print_trait_item(ast_item)
+ |s| s.print_trait_item(ast_item),
);
let rendered_const = self.lazy(RenderedConst(rendered));
- EntryKind::AssocConst(
+ record!(self.tables.kind[def_id] <- EntryKind::AssocConst(
container,
Default::default(),
rendered_const,
- )
+ ));
}
ty::AssocKind::Fn => {
let fn_data = if let hir::TraitItemKind::Fn(m_sig, m) = &ast_item.kind {
let param_names = match *m {
- hir::TraitFn::Required(ref names) => {
- self.encode_fn_param_names(names)
- }
- hir::TraitFn::Provided(body) => {
- self.encode_fn_param_names_for_body(body)
- }
+ hir::TraitFn::Required(ref names) => self.encode_fn_param_names(names),
+ hir::TraitFn::Provided(body) => self.encode_fn_param_names_for_body(body),
};
FnData {
asyncness: m_sig.header.asyncness,
@@ -978,24 +1086,18 @@
} else {
bug!()
};
- EntryKind::AssocFn(self.lazy(AssocFnData {
+ record!(self.tables.kind[def_id] <- EntryKind::AssocFn(self.lazy(AssocFnData {
fn_data,
container,
has_self: trait_item.fn_has_self_parameter,
- }))
+ })));
}
ty::AssocKind::Type => {
self.encode_explicit_item_bounds(def_id);
- EntryKind::AssocType(container)
+ record!(self.tables.kind[def_id] <- EntryKind::AssocType(container));
}
- });
- record!(self.tables.visibility[def_id] <- self.tcx.visibility(def_id));
- record!(self.tables.span[def_id] <- ast_item.span);
- record!(self.tables.attributes[def_id] <- ast_item.attrs);
+ }
self.encode_ident_span(def_id, ast_item.ident);
- self.encode_stability(def_id);
- self.encode_const_stability(def_id);
- self.encode_deprecation(def_id);
match trait_item.kind {
ty::AssocKind::Const | ty::AssocKind::Fn => {
self.encode_item_type(def_id);
@@ -1013,15 +1115,6 @@
self.encode_generics(def_id);
self.encode_explicit_predicates(def_id);
self.encode_inferred_outlives(def_id);
-
- // This should be kept in sync with `PrefetchVisitor.visit_trait_item`.
- self.encode_optimized_mir(def_id.expect_local());
- self.encode_promoted_mir(def_id.expect_local());
- }
-
- fn metadata_output_only(&self) -> bool {
- // MIR optimisation can be skipped when we're just interested in the metadata.
- !self.tcx.sess.opts.output_types.should_codegen()
}
fn encode_info_for_impl_item(&mut self, def_id: DefId) {
@@ -1040,15 +1133,16 @@
}
};
- record!(self.tables.kind[def_id] <- match impl_item.kind {
+ match impl_item.kind {
ty::AssocKind::Const => {
if let hir::ImplItemKind::Const(_, body_id) = ast_item.kind {
let qualifs = self.tcx.at(ast_item.span).mir_const_qualif(def_id);
- EntryKind::AssocConst(
+ record!(self.tables.kind[def_id] <- EntryKind::AssocConst(
container,
qualifs,
self.encode_rendered_const_for_body(body_id))
+ );
} else {
bug!()
}
@@ -1063,21 +1157,17 @@
} else {
bug!()
};
- EntryKind::AssocFn(self.lazy(AssocFnData {
+ record!(self.tables.kind[def_id] <- EntryKind::AssocFn(self.lazy(AssocFnData {
fn_data,
container,
has_self: impl_item.fn_has_self_parameter,
- }))
+ })));
}
- ty::AssocKind::Type => EntryKind::AssocType(container)
- });
- record!(self.tables.visibility[def_id] <- self.tcx.visibility(def_id));
- record!(self.tables.span[def_id] <- ast_item.span);
- record!(self.tables.attributes[def_id] <- ast_item.attrs);
+ ty::AssocKind::Type => {
+ record!(self.tables.kind[def_id] <- EntryKind::AssocType(container));
+ }
+ }
self.encode_ident_span(def_id, impl_item.ident);
- self.encode_stability(def_id);
- self.encode_const_stability(def_id);
- self.encode_deprecation(def_id);
self.encode_item_type(def_id);
if impl_item.kind == ty::AssocKind::Fn {
record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(def_id));
@@ -1086,26 +1176,6 @@
self.encode_generics(def_id);
self.encode_explicit_predicates(def_id);
self.encode_inferred_outlives(def_id);
-
- // The following part should be kept in sync with `PrefetchVisitor.visit_impl_item`.
-
- let mir = match ast_item.kind {
- hir::ImplItemKind::Const(..) => true,
- hir::ImplItemKind::Fn(ref sig, _) => {
- let generics = self.tcx.generics_of(def_id);
- let needs_inline = (generics.requires_monomorphization(self.tcx)
- || tcx.codegen_fn_attrs(def_id).requests_inline())
- && !self.metadata_output_only();
- let is_const_fn = sig.header.constness == hir::Constness::Const;
- let always_encode_mir = self.tcx.sess.opts.debugging_opts.always_encode_mir;
- needs_inline || is_const_fn || always_encode_mir
- }
- hir::ImplItemKind::TyAlias(..) => false,
- };
- if mir {
- self.encode_optimized_mir(def_id.expect_local());
- self.encode_promoted_mir(def_id.expect_local());
- }
}
fn encode_fn_param_names_for_body(&mut self, body_id: hir::BodyId) -> Lazy<[Ident]> {
@@ -1116,27 +1186,47 @@
self.lazy(param_names.iter())
}
- fn encode_optimized_mir(&mut self, def_id: LocalDefId) {
- debug!("EntryBuilder::encode_mir({:?})", def_id);
- if self.tcx.mir_keys(LOCAL_CRATE).contains(&def_id) {
- record!(self.tables.mir[def_id.to_def_id()] <- self.tcx.optimized_mir(def_id));
+ fn encode_mir(&mut self) {
+ if self.is_proc_macro {
+ return;
+ }
+
+ let mut keys_and_jobs = self
+ .tcx
+ .mir_keys(LOCAL_CRATE)
+ .iter()
+ .filter_map(|&def_id| {
+ let (encode_const, encode_opt) = should_encode_mir(self.tcx, def_id);
+ if encode_const || encode_opt {
+ Some((def_id, encode_const, encode_opt))
+ } else {
+ None
+ }
+ })
+ .collect::<Vec<_>>();
+ // Sort everything to ensure a stable order for diagnotics.
+ keys_and_jobs.sort_by_key(|&(def_id, _, _)| def_id);
+ for (def_id, encode_const, encode_opt) in keys_and_jobs.into_iter() {
+ debug_assert!(encode_const || encode_opt);
+
+ debug!("EntryBuilder::encode_mir({:?})", def_id);
+ if encode_opt {
+ record!(self.tables.mir[def_id.to_def_id()] <- self.tcx.optimized_mir(def_id));
+ }
+ if encode_const {
+ record!(self.tables.mir_for_ctfe[def_id.to_def_id()] <- self.tcx.mir_for_ctfe(def_id));
+
+ let abstract_const = self.tcx.mir_abstract_const(def_id);
+ if let Ok(Some(abstract_const)) = abstract_const {
+ record!(self.tables.mir_abstract_consts[def_id.to_def_id()] <- abstract_const);
+ }
+ }
+ record!(self.tables.promoted_mir[def_id.to_def_id()] <- self.tcx.promoted_mir(def_id));
let unused = self.tcx.unused_generic_params(def_id);
if !unused.is_empty() {
record!(self.tables.unused_generic_params[def_id.to_def_id()] <- unused);
}
-
- let abstract_const = self.tcx.mir_abstract_const(def_id);
- if let Ok(Some(abstract_const)) = abstract_const {
- record!(self.tables.mir_abstract_consts[def_id.to_def_id()] <- abstract_const);
- }
- }
- }
-
- fn encode_promoted_mir(&mut self, def_id: LocalDefId) {
- debug!("EncodeContext::encode_promoted_mir({:?})", def_id);
- if self.tcx.mir_keys(LOCAL_CRATE).contains(&def_id) {
- record!(self.tables.promoted_mir[def_id.to_def_id()] <- self.tcx.promoted_mir(def_id));
}
}
@@ -1200,15 +1290,12 @@
self.encode_ident_span(def_id, item.ident);
- record!(self.tables.kind[def_id] <- match item.kind {
+ let entry_kind = match item.kind {
hir::ItemKind::Static(_, hir::Mutability::Mut, _) => EntryKind::MutStatic,
hir::ItemKind::Static(_, hir::Mutability::Not, _) => EntryKind::ImmStatic,
hir::ItemKind::Const(_, body_id) => {
let qualifs = self.tcx.at(item.span).mir_const_qualif(def_id);
- EntryKind::Const(
- qualifs,
- self.encode_rendered_const_for_body(body_id)
- )
+ EntryKind::Const(qualifs, self.encode_rendered_const_for_body(body_id))
}
hir::ItemKind::Fn(ref sig, .., body) => {
let data = FnData {
@@ -1220,7 +1307,7 @@
EntryKind::Fn(self.lazy(data))
}
hir::ItemKind::Mod(ref m) => {
- return self.encode_info_for_mod(item.hir_id, m, &item.attrs);
+ return self.encode_info_for_mod(item.hir_id, m);
}
hir::ItemKind::ForeignMod { .. } => EntryKind::ForeignMod,
hir::ItemKind::GlobalAsm(..) => EntryKind::GlobalAsm,
@@ -1237,61 +1324,61 @@
// Encode def_ids for each field and method
// for methods, write all the stuff get_trait_method
// needs to know
- let ctor = struct_def.ctor_hir_id().map(|ctor_hir_id| {
- self.tcx.hir().local_def_id(ctor_hir_id).local_def_index
- });
+ let ctor = struct_def
+ .ctor_hir_id()
+ .map(|ctor_hir_id| self.tcx.hir().local_def_id(ctor_hir_id).local_def_index);
- EntryKind::Struct(self.lazy(VariantData {
- ctor_kind: variant.ctor_kind,
- discr: variant.discr,
- ctor,
- is_non_exhaustive: variant.is_field_list_non_exhaustive(),
- }), adt_def.repr)
+ EntryKind::Struct(
+ self.lazy(VariantData {
+ ctor_kind: variant.ctor_kind,
+ discr: variant.discr,
+ ctor,
+ is_non_exhaustive: variant.is_field_list_non_exhaustive(),
+ }),
+ adt_def.repr,
+ )
}
hir::ItemKind::Union(..) => {
let adt_def = self.tcx.adt_def(def_id);
let variant = adt_def.non_enum_variant();
- EntryKind::Union(self.lazy(VariantData {
- ctor_kind: variant.ctor_kind,
- discr: variant.discr,
- ctor: None,
- is_non_exhaustive: variant.is_field_list_non_exhaustive(),
- }), adt_def.repr)
+ EntryKind::Union(
+ self.lazy(VariantData {
+ ctor_kind: variant.ctor_kind,
+ discr: variant.discr,
+ ctor: None,
+ is_non_exhaustive: variant.is_field_list_non_exhaustive(),
+ }),
+ adt_def.repr,
+ )
}
- hir::ItemKind::Impl { defaultness, .. } => {
+ hir::ItemKind::Impl(hir::Impl { defaultness, .. }) => {
let trait_ref = self.tcx.impl_trait_ref(def_id);
let polarity = self.tcx.impl_polarity(def_id);
let parent = if let Some(trait_ref) = trait_ref {
let trait_def = self.tcx.trait_def(trait_ref.def_id);
- trait_def.ancestors(self.tcx, def_id).ok()
- .and_then(|mut an| an.nth(1).and_then(|node| {
- match node {
- specialization_graph::Node::Impl(parent) => Some(parent),
- _ => None,
- }
- }))
+ trait_def.ancestors(self.tcx, def_id).ok().and_then(|mut an| {
+ an.nth(1).and_then(|node| match node {
+ specialization_graph::Node::Impl(parent) => Some(parent),
+ _ => None,
+ })
+ })
} else {
None
};
// if this is an impl of `CoerceUnsized`, create its
// "unsized info", else just store None
- let coerce_unsized_info =
- trait_ref.and_then(|t| {
- if Some(t.def_id) == self.tcx.lang_items().coerce_unsized_trait() {
- Some(self.tcx.at(item.span).coerce_unsized_info(def_id))
- } else {
- None
- }
- });
+ let coerce_unsized_info = trait_ref.and_then(|t| {
+ if Some(t.def_id) == self.tcx.lang_items().coerce_unsized_trait() {
+ Some(self.tcx.at(item.span).coerce_unsized_info(def_id))
+ } else {
+ None
+ }
+ });
- let data = ImplData {
- polarity,
- defaultness,
- parent_impl: parent,
- coerce_unsized_info,
- };
+ let data =
+ ImplData { polarity, defaultness, parent_impl: parent, coerce_unsized_info };
EntryKind::Impl(self.lazy(data))
}
@@ -1308,13 +1395,11 @@
EntryKind::Trait(self.lazy(data))
}
hir::ItemKind::TraitAlias(..) => EntryKind::TraitAlias,
- hir::ItemKind::ExternCrate(_) |
- hir::ItemKind::Use(..) => bug!("cannot encode info for item {:?}", item),
- });
- record!(self.tables.visibility[def_id] <- self.tcx.visibility(def_id));
- record!(self.tables.span[def_id] <- self.tcx.def_span(def_id));
- record!(self.tables.attributes[def_id] <- item.attrs);
- record!(self.tables.expn_that_defined[def_id] <- self.tcx.expansion_that_defined(def_id));
+ hir::ItemKind::ExternCrate(_) | hir::ItemKind::Use(..) => {
+ bug!("cannot encode info for item {:?}", item)
+ }
+ };
+ 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] <-
@@ -1348,9 +1433,6 @@
}
_ => {}
}
- self.encode_stability(def_id);
- self.encode_const_stability(def_id);
- self.encode_deprecation(def_id);
match item.kind {
hir::ItemKind::Static(..)
| hir::ItemKind::Const(..)
@@ -1403,42 +1485,17 @@
}
_ => {}
}
-
- // The following part should be kept in sync with `PrefetchVisitor.visit_item`.
-
- let mir = match item.kind {
- hir::ItemKind::Static(..) | hir::ItemKind::Const(..) => true,
- hir::ItemKind::Fn(ref sig, ..) => {
- let generics = tcx.generics_of(def_id);
- let needs_inline = (generics.requires_monomorphization(tcx)
- || tcx.codegen_fn_attrs(def_id).requests_inline())
- && !self.metadata_output_only();
- let always_encode_mir = self.tcx.sess.opts.debugging_opts.always_encode_mir;
- needs_inline || sig.header.constness == hir::Constness::Const || always_encode_mir
- }
- _ => false,
- };
- if mir {
- self.encode_optimized_mir(def_id.expect_local());
- self.encode_promoted_mir(def_id.expect_local());
- }
}
/// Serialize the text of exported macros
fn encode_info_for_macro_def(&mut self, macro_def: &hir::MacroDef<'_>) {
let def_id = self.tcx.hir().local_def_id(macro_def.hir_id).to_def_id();
record!(self.tables.kind[def_id] <- EntryKind::MacroDef(self.lazy(macro_def.ast.clone())));
- record!(self.tables.visibility[def_id] <- self.tcx.visibility(def_id));
- record!(self.tables.span[def_id] <- macro_def.span);
- record!(self.tables.attributes[def_id] <- macro_def.attrs);
self.encode_ident_span(def_id, macro_def.ident);
- self.encode_stability(def_id);
- self.encode_deprecation(def_id);
}
fn encode_info_for_generic_param(&mut self, def_id: DefId, kind: EntryKind, encode_type: bool) {
record!(self.tables.kind[def_id] <- kind);
- record!(self.tables.span[def_id] <- self.tcx.def_span(def_id));
if encode_type {
self.encode_item_type(def_id);
}
@@ -1452,25 +1509,23 @@
let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id);
let ty = self.tcx.typeck(def_id).node_type(hir_id);
- record!(self.tables.kind[def_id.to_def_id()] <- match ty.kind() {
+ match ty.kind() {
ty::Generator(..) => {
let data = self.tcx.generator_kind(def_id).unwrap();
- EntryKind::Generator(data)
+ record!(self.tables.kind[def_id.to_def_id()] <- EntryKind::Generator(data));
}
- ty::Closure(..) => EntryKind::Closure,
+ ty::Closure(..) => {
+ record!(self.tables.kind[def_id.to_def_id()] <- EntryKind::Closure);
+ }
_ => bug!("closure that is neither generator nor closure"),
- });
- record!(self.tables.span[def_id.to_def_id()] <- self.tcx.def_span(def_id));
- record!(self.tables.attributes[def_id.to_def_id()] <- &self.tcx.get_attrs(def_id.to_def_id())[..]);
+ }
self.encode_item_type(def_id.to_def_id());
if let ty::Closure(def_id, substs) = *ty.kind() {
record!(self.tables.fn_sig[def_id] <- substs.as_closure().sig());
}
self.encode_generics(def_id.to_def_id());
- self.encode_optimized_mir(def_id);
- self.encode_promoted_mir(def_id);
}
fn encode_info_for_anon_const(&mut self, def_id: LocalDefId) {
@@ -1481,13 +1536,10 @@
let qualifs = self.tcx.mir_const_qualif(def_id);
record!(self.tables.kind[def_id.to_def_id()] <- EntryKind::AnonConst(qualifs, const_data));
- record!(self.tables.span[def_id.to_def_id()] <- self.tcx.def_span(def_id));
self.encode_item_type(def_id.to_def_id());
self.encode_generics(def_id.to_def_id());
self.encode_explicit_predicates(def_id.to_def_id());
self.encode_inferred_outlives(def_id.to_def_id());
- self.encode_optimized_mir(def_id);
- self.encode_promoted_mir(def_id);
}
fn encode_native_libraries(&mut self) -> Lazy<[NativeLib]> {
@@ -1531,6 +1583,15 @@
let stability = tcx.lookup_stability(DefId::local(CRATE_DEF_INDEX)).copied();
let macros = self.lazy(hir.krate().proc_macros.iter().map(|p| p.owner.local_def_index));
+ record!(self.tables.def_kind[LOCAL_CRATE.as_def_id()] <- DefKind::Mod);
+ record!(self.tables.span[LOCAL_CRATE.as_def_id()] <- tcx.def_span(LOCAL_CRATE.as_def_id()));
+ record!(self.tables.attributes[LOCAL_CRATE.as_def_id()] <- tcx.get_attrs(LOCAL_CRATE.as_def_id()));
+ record!(self.tables.visibility[LOCAL_CRATE.as_def_id()] <- tcx.visibility(LOCAL_CRATE.as_def_id()));
+ if let Some(stability) = stability {
+ record!(self.tables.stability[LOCAL_CRATE.as_def_id()] <- stability);
+ }
+ self.encode_deprecation(LOCAL_CRATE.as_def_id());
+
// Normally, this information is encoded when we walk the items
// defined in this crate. However, we skip doing that for proc-macro crates,
// so we manually encode just the information that we need
@@ -1562,6 +1623,7 @@
def_key.disambiguated_data.data = DefPathData::MacroNs(name);
let def_id = DefId::local(id);
+ record!(self.tables.def_kind[def_id] <- DefKind::Macro(macro_kind));
record!(self.tables.kind[def_id] <- EntryKind::ProcMacro(macro_kind));
record!(self.tables.attributes[def_id] <- attrs);
record!(self.tables.def_keys[def_id] <- def_key);
@@ -1729,7 +1791,7 @@
debug!("EncodeContext::encode_info_for_foreign_item({:?})", def_id);
- record!(self.tables.kind[def_id] <- match nitem.kind {
+ match nitem.kind {
hir::ForeignItemKind::Fn(_, ref names, _) => {
let data = FnData {
asyncness: hir::IsAsync::NotAsync,
@@ -1740,19 +1802,19 @@
},
param_names: self.encode_fn_param_names(names),
};
- EntryKind::ForeignFn(self.lazy(data))
+ record!(self.tables.kind[def_id] <- EntryKind::ForeignFn(self.lazy(data)));
}
- hir::ForeignItemKind::Static(_, hir::Mutability::Mut) => EntryKind::ForeignMutStatic,
- hir::ForeignItemKind::Static(_, hir::Mutability::Not) => EntryKind::ForeignImmStatic,
- hir::ForeignItemKind::Type => EntryKind::ForeignType,
- });
- record!(self.tables.visibility[def_id] <- self.tcx.visibility(def_id));
- record!(self.tables.span[def_id] <- nitem.span);
- record!(self.tables.attributes[def_id] <- nitem.attrs);
+ hir::ForeignItemKind::Static(_, hir::Mutability::Mut) => {
+ record!(self.tables.kind[def_id] <- EntryKind::ForeignMutStatic);
+ }
+ hir::ForeignItemKind::Static(_, hir::Mutability::Not) => {
+ record!(self.tables.kind[def_id] <- EntryKind::ForeignImmStatic);
+ }
+ hir::ForeignItemKind::Type => {
+ record!(self.tables.kind[def_id] <- EntryKind::ForeignType);
+ }
+ }
self.encode_ident_span(def_id, nitem.ident);
- self.encode_stability(def_id);
- self.encode_const_stability(def_id);
- self.encode_deprecation(def_id);
self.encode_item_type(def_id);
self.encode_inherent_implementations(def_id);
if let hir::ForeignItemKind::Fn(..) = nitem.kind {
@@ -1818,15 +1880,12 @@
let def_id = self.tcx.hir().local_def_id(param.hir_id);
match param.kind {
GenericParamKind::Lifetime { .. } => continue,
- GenericParamKind::Type { ref default, .. } => {
+ GenericParamKind::Type { default, .. } => {
self.encode_info_for_generic_param(
def_id.to_def_id(),
EntryKind::TypeParam,
default.is_some(),
);
- if default.is_some() {
- self.encode_stability(def_id.to_def_id());
- }
}
GenericParamKind::Const { .. } => {
self.encode_info_for_generic_param(
@@ -1834,7 +1893,7 @@
EntryKind::ConstParam,
true,
);
- // FIXME(const_generics:defaults)
+ // FIXME(const_generics_defaults)
}
}
}
@@ -1945,71 +2004,25 @@
/// Used to prefetch queries which will be needed later by metadata encoding.
/// Only a subset of the queries are actually prefetched to keep this code smaller.
-struct PrefetchVisitor<'tcx> {
- tcx: TyCtxt<'tcx>,
- mir_keys: &'tcx FxHashSet<LocalDefId>,
-}
+fn prefetch_mir(tcx: TyCtxt<'_>) {
+ if !tcx.sess.opts.output_types.should_codegen() {
+ // We won't emit MIR, so don't prefetch it.
+ return;
+ }
-impl<'tcx> PrefetchVisitor<'tcx> {
- fn prefetch_mir(&self, def_id: LocalDefId) {
- if self.mir_keys.contains(&def_id) {
- self.tcx.ensure().optimized_mir(def_id);
- self.tcx.ensure().promoted_mir(def_id);
+ par_iter(tcx.mir_keys(LOCAL_CRATE)).for_each(|&def_id| {
+ let (encode_const, encode_opt) = should_encode_mir(tcx, def_id);
+
+ if encode_const {
+ tcx.ensure().mir_for_ctfe(def_id);
}
- }
-}
-
-impl<'tcx, 'v> ParItemLikeVisitor<'v> for PrefetchVisitor<'tcx> {
- fn visit_item(&self, item: &hir::Item<'_>) {
- // This should be kept in sync with `encode_info_for_item`.
- let tcx = self.tcx;
- match item.kind {
- hir::ItemKind::Static(..) | hir::ItemKind::Const(..) => {
- self.prefetch_mir(tcx.hir().local_def_id(item.hir_id))
- }
- hir::ItemKind::Fn(ref sig, ..) => {
- let def_id = tcx.hir().local_def_id(item.hir_id);
- let generics = tcx.generics_of(def_id.to_def_id());
- let needs_inline = generics.requires_monomorphization(tcx)
- || tcx.codegen_fn_attrs(def_id.to_def_id()).requests_inline();
- if needs_inline || sig.header.constness == hir::Constness::Const {
- self.prefetch_mir(def_id)
- }
- }
- _ => (),
+ if encode_opt {
+ tcx.ensure().optimized_mir(def_id);
}
- }
-
- fn visit_trait_item(&self, trait_item: &'v hir::TraitItem<'v>) {
- // This should be kept in sync with `encode_info_for_trait_item`.
- self.prefetch_mir(self.tcx.hir().local_def_id(trait_item.hir_id));
- }
-
- fn visit_impl_item(&self, impl_item: &'v hir::ImplItem<'v>) {
- // This should be kept in sync with `encode_info_for_impl_item`.
- let tcx = self.tcx;
- match impl_item.kind {
- hir::ImplItemKind::Const(..) => {
- self.prefetch_mir(tcx.hir().local_def_id(impl_item.hir_id))
- }
- hir::ImplItemKind::Fn(ref sig, _) => {
- let def_id = tcx.hir().local_def_id(impl_item.hir_id);
- let generics = tcx.generics_of(def_id.to_def_id());
- let needs_inline = generics.requires_monomorphization(tcx)
- || tcx.codegen_fn_attrs(def_id.to_def_id()).requests_inline();
- let is_const_fn = sig.header.constness == hir::Constness::Const;
- if needs_inline || is_const_fn {
- self.prefetch_mir(def_id)
- }
- }
- hir::ImplItemKind::TyAlias(..) => (),
+ if encode_opt || encode_const {
+ tcx.ensure().promoted_mir(def_id);
}
- }
-
- fn visit_foreign_item(&self, _foreign_item: &'v hir::ForeignItem<'v>) {
- // This should be kept in sync with `encode_info_for_foreign_item`.
- // Foreign items contain no MIR.
- }
+ })
}
// NOTE(eddyb) The following comment was preserved for posterity, even
@@ -2049,19 +2062,7 @@
// Prefetch some queries used by metadata encoding.
// This is not necessary for correctness, but is only done for performance reasons.
// It can be removed if it turns out to cause trouble or be detrimental to performance.
- join(
- || {
- if !tcx.sess.opts.output_types.should_codegen() {
- // We won't emit MIR, so don't prefetch it.
- return;
- }
- tcx.hir().krate().par_visit_all_item_likes(&PrefetchVisitor {
- tcx,
- mir_keys: tcx.mir_keys(LOCAL_CRATE),
- });
- },
- || tcx.exported_symbols(LOCAL_CRATE),
- );
+ join(|| prefetch_mir(tcx), || tcx.exported_symbols(LOCAL_CRATE));
},
)
.0
diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs
index 5360617..b44c3bf 100644
--- a/compiler/rustc_metadata/src/rmeta/mod.rs
+++ b/compiler/rustc_metadata/src/rmeta/mod.rs
@@ -6,7 +6,7 @@
use rustc_data_structures::svh::Svh;
use rustc_data_structures::sync::MetadataRef;
use rustc_hir as hir;
-use rustc_hir::def::CtorKind;
+use rustc_hir::def::{CtorKind, DefKind};
use rustc_hir::def_id::{DefId, DefIndex, DefPathHash};
use rustc_hir::definitions::DefKey;
use rustc_hir::lang_items;
@@ -279,6 +279,7 @@
}
define_tables! {
+ def_kind: Table<DefIndex, Lazy<DefKind>>,
kind: Table<DefIndex, Lazy<EntryKind>>,
visibility: Table<DefIndex, Lazy<ty::Visibility>>,
span: Table<DefIndex, Lazy<Span>>,
@@ -302,6 +303,7 @@
// As an optimization, a missing entry indicates an empty `&[]`.
explicit_item_bounds: Table<DefIndex, Lazy!([(ty::Predicate<'tcx>, Span)])>,
mir: Table<DefIndex, Lazy!(mir::Body<'tcx>)>,
+ mir_for_ctfe: Table<DefIndex, Lazy!(mir::Body<'tcx>)>,
promoted_mir: Table<DefIndex, Lazy!(IndexVec<mir::Promoted, mir::Body<'tcx>>)>,
mir_abstract_consts: Table<DefIndex, Lazy!(&'tcx [mir::abstract_const::Node<'tcx>])>,
unused_generic_params: Table<DefIndex, Lazy<FiniteBitSet<u32>>>,
diff --git a/compiler/rustc_middle/Cargo.toml b/compiler/rustc_middle/Cargo.toml
index 47b7768..d33aad3 100644
--- a/compiler/rustc_middle/Cargo.toml
+++ b/compiler/rustc_middle/Cargo.toml
@@ -26,7 +26,7 @@
rustc_serialize = { path = "../rustc_serialize" }
rustc_ast = { path = "../rustc_ast" }
rustc_span = { path = "../rustc_span" }
-chalk-ir = "0.36.0"
+chalk-ir = "0.55.0"
smallvec = { version = "1.0", features = ["union", "may_dangle"] }
measureme = "9.0.0"
rustc_session = { path = "../rustc_session" }
diff --git a/compiler/rustc_middle/src/dep_graph/dep_node.rs b/compiler/rustc_middle/src/dep_graph/dep_node.rs
index d954c8a..1cb7575 100644
--- a/compiler/rustc_middle/src/dep_graph/dep_node.rs
+++ b/compiler/rustc_middle/src/dep_graph/dep_node.rs
@@ -1,16 +1,17 @@
-//! This module defines the `DepNode` type which the compiler uses to represent
-//! nodes in the dependency graph.
+//! Nodes in the dependency graph.
//!
-//! A `DepNode` consists of a `DepKind` (which
-//! specifies the kind of thing it represents, like a piece of HIR, MIR, etc)
-//! and a `Fingerprint`, a 128-bit hash value the exact meaning of which
+//! A node in the [dependency graph] is represented by a [`DepNode`].
+//! A `DepNode` consists of a [`DepKind`] (which
+//! specifies the kind of thing it represents, like a piece of HIR, MIR, etc.)
+//! and a [`Fingerprint`], a 128-bit hash value, the exact meaning of which
//! depends on the node's `DepKind`. Together, the kind and the fingerprint
//! fully identify a dependency node, even across multiple compilation sessions.
//! In other words, the value of the fingerprint does not depend on anything
//! that is specific to a given compilation session, like an unpredictable
-//! interning key (e.g., NodeId, DefId, Symbol) or the numeric value of a
+//! interning key (e.g., `NodeId`, `DefId`, `Symbol`) or the numeric value of a
//! pointer. The concept behind this could be compared to how git commit hashes
-//! uniquely identify a given commit and has a few advantages:
+//! uniquely identify a given commit. The fingerprinting approach has
+//! a few advantages:
//!
//! * A `DepNode` can simply be serialized to disk and loaded in another session
//! without the need to do any "rebasing" (like we have to do for Spans and
@@ -29,9 +30,10 @@
//! contained no `DefId` for thing that had been removed.
//!
//! `DepNode` definition happens in the `define_dep_nodes!()` macro. This macro
-//! defines the `DepKind` enum and a corresponding `DepConstructor` enum. The
-//! `DepConstructor` enum links a `DepKind` to the parameters that are needed at
-//! runtime in order to construct a valid `DepNode` fingerprint.
+//! defines the `DepKind` enum. Each `DepKind` has its own parameters that are
+//! needed at runtime in order to construct a valid `DepNode` fingerprint.
+//! However, only `CompileCodegenUnit` is constructed explicitly (with
+//! `make_compile_codegen_unit`).
//!
//! Because the macro sees what parameters a given `DepKind` requires, it can
//! "infer" some properties for each kind of `DepNode`:
@@ -44,32 +46,120 @@
//! `DefId` it was computed from. In other cases, too much information gets
//! lost during fingerprint computation.
//!
-//! The `DepConstructor` enum, together with `DepNode::new()`, ensures that only
+//! `make_compile_codegen_unit`, together with `DepNode::new()`, ensures that only
//! valid `DepNode` instances can be constructed. For example, the API does not
//! allow for constructing parameterless `DepNode`s with anything other
//! than a zeroed out fingerprint. More generally speaking, it relieves the
//! user of the `DepNode` API of having to know how to compute the expected
//! fingerprint for a given set of node parameters.
+//!
+//! [dependency graph]: https://rustc-dev-guide.rust-lang.org/query.html
-use crate::mir::interpret::{GlobalId, LitToConstInput};
-use crate::traits;
-use crate::traits::query::{
- CanonicalPredicateGoal, CanonicalProjectionGoal, CanonicalTyGoal,
- CanonicalTypeOpAscribeUserTypeGoal, CanonicalTypeOpEqGoal, CanonicalTypeOpNormalizeGoal,
- CanonicalTypeOpProvePredicateGoal, CanonicalTypeOpSubtypeGoal,
-};
-use crate::ty::subst::{GenericArg, SubstsRef};
-use crate::ty::{self, ParamEnvAnd, Ty, TyCtxt};
+use crate::ty::TyCtxt;
use rustc_data_structures::fingerprint::Fingerprint;
use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, CRATE_DEF_INDEX};
use rustc_hir::definitions::DefPathHash;
use rustc_hir::HirId;
use rustc_span::symbol::Symbol;
+use rustc_span::DUMMY_SP;
use std::hash::Hash;
pub use rustc_query_system::dep_graph::{DepContext, DepNodeParams};
+/// This struct stores metadata about each DepKind.
+///
+/// Information is retrieved by indexing the `DEP_KINDS` array using the integer value
+/// of the `DepKind`. Overall, this allows to implement `DepContext` using this manual
+/// jump table instead of large matches.
+pub struct DepKindStruct {
+ /// Whether the DepNode has parameters (query keys).
+ pub(super) has_params: bool,
+
+ /// Anonymous queries cannot be replayed from one compiler invocation to the next.
+ /// When their result is needed, it is recomputed. They are useful for fine-grained
+ /// dependency tracking, and caching within one compiler invocation.
+ pub(super) is_anon: bool,
+
+ /// Eval-always queries do not track their dependencies, and are always recomputed, even if
+ /// their inputs have not changed since the last compiler invocation. The result is still
+ /// cached within one compiler invocation.
+ pub(super) is_eval_always: bool,
+
+ /// Whether the query key can be recovered from the hashed fingerprint.
+ /// See [DepNodeParams] trait for the behaviour of each key type.
+ // FIXME: Make this a simple boolean once DepNodeParams::can_reconstruct_query_key
+ // can be made a specialized associated const.
+ can_reconstruct_query_key: fn() -> bool,
+
+ /// The red/green evaluation system will try to mark a specific DepNode in the
+ /// dependency graph as green by recursively trying to mark the dependencies of
+ /// that `DepNode` as green. While doing so, it will sometimes encounter a `DepNode`
+ /// where we don't know if it is red or green and we therefore actually have
+ /// to recompute its value in order to find out. Since the only piece of
+ /// information that we have at that point is the `DepNode` we are trying to
+ /// re-evaluate, we need some way to re-run a query from just that. This is what
+ /// `force_from_dep_node()` implements.
+ ///
+ /// In the general case, a `DepNode` consists of a `DepKind` and an opaque
+ /// GUID/fingerprint that will uniquely identify the node. This GUID/fingerprint
+ /// is usually constructed by computing a stable hash of the query-key that the
+ /// `DepNode` corresponds to. Consequently, it is not in general possible to go
+ /// back from hash to query-key (since hash functions are not reversible). For
+ /// this reason `force_from_dep_node()` is expected to fail from time to time
+ /// because we just cannot find out, from the `DepNode` alone, what the
+ /// corresponding query-key is and therefore cannot re-run the query.
+ ///
+ /// The system deals with this case letting `try_mark_green` fail which forces
+ /// the root query to be re-evaluated.
+ ///
+ /// Now, if `force_from_dep_node()` would always fail, it would be pretty useless.
+ /// Fortunately, we can use some contextual information that will allow us to
+ /// reconstruct query-keys for certain kinds of `DepNode`s. In particular, we
+ /// enforce by construction that the GUID/fingerprint of certain `DepNode`s is a
+ /// valid `DefPathHash`. Since we also always build a huge table that maps every
+ /// `DefPathHash` in the current codebase to the corresponding `DefId`, we have
+ /// everything we need to re-run the query.
+ ///
+ /// Take the `mir_promoted` query as an example. Like many other queries, it
+ /// just has a single parameter: the `DefId` of the item it will compute the
+ /// validated MIR for. Now, when we call `force_from_dep_node()` on a `DepNode`
+ /// with kind `MirValidated`, we know that the GUID/fingerprint of the `DepNode`
+ /// is actually a `DefPathHash`, and can therefore just look up the corresponding
+ /// `DefId` in `tcx.def_path_hash_to_def_id`.
+ ///
+ /// When you implement a new query, it will likely have a corresponding new
+ /// `DepKind`, and you'll have to support it here in `force_from_dep_node()`. As
+ /// a rule of thumb, if your query takes a `DefId` or `LocalDefId` as sole parameter,
+ /// then `force_from_dep_node()` should not fail for it. Otherwise, you can just
+ /// add it to the "We don't have enough information to reconstruct..." group in
+ /// the match below.
+ pub(super) force_from_dep_node: fn(tcx: TyCtxt<'_>, dep_node: &DepNode) -> bool,
+
+ /// Invoke a query to put the on-disk cached value in memory.
+ pub(super) try_load_from_on_disk_cache: fn(TyCtxt<'_>, &DepNode),
+}
+
+impl std::ops::Deref for DepKind {
+ type Target = DepKindStruct;
+ fn deref(&self) -> &DepKindStruct {
+ &DEP_KINDS[*self as usize]
+ }
+}
+
+impl DepKind {
+ #[inline(always)]
+ pub fn can_reconstruct_query_key(&self) -> bool {
+ // Only fetch the DepKindStruct once.
+ let data: &DepKindStruct = &**self;
+ if data.is_anon {
+ return false;
+ }
+
+ (data.can_reconstruct_query_key)()
+ }
+}
+
// erase!() just makes tokens go away. It's used to specify which macro argument
// is repeated (i.e., which sub-expression of the macro we are in) but don't need
// to actually use any of the arguments.
@@ -103,6 +193,120 @@
($($attr:ident $(($($attr_args:tt)*))* ),*) => ({$(is_eval_always_attr!($attr) | )* false});
}
+#[allow(non_upper_case_globals)]
+pub mod dep_kind {
+ use super::*;
+ use crate::ty::query::{queries, query_keys};
+ use rustc_query_system::query::{force_query, QueryDescription};
+
+ // We use this for most things when incr. comp. is turned off.
+ pub const Null: DepKindStruct = DepKindStruct {
+ has_params: false,
+ is_anon: false,
+ is_eval_always: false,
+
+ can_reconstruct_query_key: || true,
+ force_from_dep_node: |_, dep_node| bug!("force_from_dep_node: encountered {:?}", dep_node),
+ try_load_from_on_disk_cache: |_, _| {},
+ };
+
+ pub const TraitSelect: DepKindStruct = DepKindStruct {
+ has_params: false,
+ is_anon: true,
+ is_eval_always: false,
+
+ can_reconstruct_query_key: || true,
+ force_from_dep_node: |_, _| false,
+ try_load_from_on_disk_cache: |_, _| {},
+ };
+
+ pub const CompileCodegenUnit: DepKindStruct = DepKindStruct {
+ has_params: true,
+ is_anon: false,
+ is_eval_always: false,
+
+ can_reconstruct_query_key: || false,
+ force_from_dep_node: |_, _| false,
+ try_load_from_on_disk_cache: |_, _| {},
+ };
+
+ macro_rules! define_query_dep_kinds {
+ ($(
+ [$($attrs:tt)*]
+ $variant:ident $(( $tuple_arg_ty:ty $(,)? ))*
+ ,)*) => (
+ $(pub const $variant: DepKindStruct = {
+ const has_params: bool = $({ erase!($tuple_arg_ty); true } |)* false;
+ const is_anon: bool = contains_anon_attr!($($attrs)*);
+ const is_eval_always: bool = contains_eval_always_attr!($($attrs)*);
+
+ #[inline(always)]
+ fn can_reconstruct_query_key() -> bool {
+ <query_keys::$variant<'_> as DepNodeParams<TyCtxt<'_>>>
+ ::can_reconstruct_query_key()
+ }
+
+ fn recover<'tcx>(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<query_keys::$variant<'tcx>> {
+ <query_keys::$variant<'_> as DepNodeParams<TyCtxt<'_>>>::recover(tcx, dep_node)
+ }
+
+ fn force_from_dep_node(tcx: TyCtxt<'_>, dep_node: &DepNode) -> bool {
+ if is_anon {
+ return false;
+ }
+
+ if !can_reconstruct_query_key() {
+ return false;
+ }
+
+ if let Some(key) = recover(tcx, dep_node) {
+ force_query::<queries::$variant<'_>, _>(
+ tcx,
+ key,
+ DUMMY_SP,
+ *dep_node
+ );
+ return true;
+ }
+
+ false
+ }
+
+ fn try_load_from_on_disk_cache(tcx: TyCtxt<'_>, dep_node: &DepNode) {
+ if is_anon {
+ return
+ }
+
+ if !can_reconstruct_query_key() {
+ return
+ }
+
+ debug_assert!(tcx.dep_graph
+ .node_color(dep_node)
+ .map(|c| c.is_green())
+ .unwrap_or(false));
+
+ let key = recover(tcx, dep_node).unwrap_or_else(|| panic!("Failed to recover key for {:?} with hash {}", dep_node, dep_node.hash));
+ if queries::$variant::cache_on_disk(tcx, &key, None) {
+ let _ = tcx.$variant(key);
+ }
+ }
+
+ DepKindStruct {
+ has_params,
+ is_anon,
+ is_eval_always,
+ can_reconstruct_query_key,
+ force_from_dep_node,
+ try_load_from_on_disk_cache,
+ }
+ };)*
+ );
+ }
+
+ rustc_dep_node_append!([define_query_dep_kinds!][]);
+}
+
macro_rules! define_dep_nodes {
(<$tcx:tt>
$(
@@ -110,182 +314,19 @@
$variant:ident $(( $tuple_arg_ty:ty $(,)? ))*
,)*
) => (
- #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Encodable, Decodable)]
+ static DEP_KINDS: &[DepKindStruct] = &[ $(dep_kind::$variant),* ];
+
+ /// This enum serves as an index into the `DEP_KINDS` array.
+ #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Encodable, Decodable)]
#[allow(non_camel_case_types)]
pub enum DepKind {
$($variant),*
}
- impl DepKind {
- #[allow(unreachable_code)]
- pub fn can_reconstruct_query_key<$tcx>(&self) -> bool {
- match *self {
- $(
- DepKind :: $variant => {
- if contains_anon_attr!($($attrs)*) {
- return false;
- }
-
- // tuple args
- $({
- return <$tuple_arg_ty as DepNodeParams<TyCtxt<'_>>>
- ::can_reconstruct_query_key();
- })*
-
- true
- }
- )*
- }
- }
-
- pub fn is_anon(&self) -> bool {
- match *self {
- $(
- DepKind :: $variant => { contains_anon_attr!($($attrs)*) }
- )*
- }
- }
-
- pub fn is_eval_always(&self) -> bool {
- match *self {
- $(
- DepKind :: $variant => { contains_eval_always_attr!($($attrs)*) }
- )*
- }
- }
-
- #[allow(unreachable_code)]
- pub fn has_params(&self) -> bool {
- match *self {
- $(
- DepKind :: $variant => {
- // tuple args
- $({
- erase!($tuple_arg_ty);
- return true;
- })*
-
- false
- }
- )*
- }
- }
- }
-
- pub struct DepConstructor;
-
- #[allow(non_camel_case_types)]
- impl DepConstructor {
- $(
- #[inline(always)]
- #[allow(unreachable_code, non_snake_case)]
- pub fn $variant(_tcx: TyCtxt<'_>, $(arg: $tuple_arg_ty)*) -> DepNode {
- // tuple args
- $({
- erase!($tuple_arg_ty);
- return DepNode::construct(_tcx, DepKind::$variant, &arg)
- })*
-
- return DepNode::construct(_tcx, DepKind::$variant, &())
- }
- )*
- }
-
- pub type DepNode = rustc_query_system::dep_graph::DepNode<DepKind>;
-
- // We keep a lot of `DepNode`s in memory during compilation. It's not
- // required that their size stay the same, but we don't want to change
- // it inadvertently. This assert just ensures we're aware of any change.
- #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
- static_assert_size!(DepNode, 17);
-
- #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
- static_assert_size!(DepNode, 24);
-
- pub trait DepNodeExt: Sized {
- /// Construct a DepNode from the given DepKind and DefPathHash. This
- /// method will assert that the given DepKind actually requires a
- /// single DefId/DefPathHash parameter.
- fn from_def_path_hash(def_path_hash: DefPathHash, kind: DepKind) -> Self;
-
- /// Extracts the DefId corresponding to this DepNode. This will work
- /// if two conditions are met:
- ///
- /// 1. The Fingerprint of the DepNode actually is a DefPathHash, and
- /// 2. the item that the DefPath refers to exists in the current tcx.
- ///
- /// Condition (1) is determined by the DepKind variant of the
- /// DepNode. Condition (2) might not be fulfilled if a DepNode
- /// refers to something from the previous compilation session that
- /// has been removed.
- fn extract_def_id(&self, tcx: TyCtxt<'_>) -> Option<DefId>;
-
- /// Used in testing
- fn from_label_string(label: &str, def_path_hash: DefPathHash)
- -> Result<Self, ()>;
-
- /// Used in testing
- fn has_label_string(label: &str) -> bool;
- }
-
- impl DepNodeExt for DepNode {
- /// Construct a DepNode from the given DepKind and DefPathHash. This
- /// method will assert that the given DepKind actually requires a
- /// single DefId/DefPathHash parameter.
- fn from_def_path_hash(def_path_hash: DefPathHash, kind: DepKind) -> DepNode {
- debug_assert!(kind.can_reconstruct_query_key() && kind.has_params());
- DepNode {
- kind,
- hash: def_path_hash.0.into(),
- }
- }
-
- /// Extracts the DefId corresponding to this DepNode. This will work
- /// if two conditions are met:
- ///
- /// 1. The Fingerprint of the DepNode actually is a DefPathHash, and
- /// 2. the item that the DefPath refers to exists in the current tcx.
- ///
- /// Condition (1) is determined by the DepKind variant of the
- /// DepNode. Condition (2) might not be fulfilled if a DepNode
- /// refers to something from the previous compilation session that
- /// has been removed.
- fn extract_def_id(&self, tcx: TyCtxt<'tcx>) -> Option<DefId> {
- if self.kind.can_reconstruct_query_key() {
- tcx.queries.on_disk_cache.as_ref()?.def_path_hash_to_def_id(tcx, DefPathHash(self.hash.into()))
- } else {
- None
- }
- }
-
- /// Used in testing
- fn from_label_string(label: &str, def_path_hash: DefPathHash) -> Result<DepNode, ()> {
- let kind = match label {
- $(
- stringify!($variant) => DepKind::$variant,
- )*
- _ => return Err(()),
- };
-
- if !kind.can_reconstruct_query_key() {
- return Err(());
- }
-
- if kind.has_params() {
- Ok(DepNode::from_def_path_hash(def_path_hash, kind))
- } else {
- Ok(DepNode::new_no_params(kind))
- }
- }
-
- /// Used in testing
- fn has_label_string(label: &str) -> bool {
- match label {
- $(
- stringify!($variant) => true,
- )*
- _ => false,
- }
+ fn dep_kind_from_label_string(label: &str) -> Result<DepKind, ()> {
+ match label {
+ $(stringify!($variant) => Ok(DepKind::$variant),)*
+ _ => Err(()),
}
}
@@ -304,16 +345,122 @@
// We use this for most things when incr. comp. is turned off.
[] Null,
- // Represents metadata from an extern crate.
- [eval_always] CrateMetadata(CrateNum),
-
[anon] TraitSelect,
+ // WARNING: if `Symbol` is changed, make sure you update `make_compile_codegen_unit` below.
[] CompileCodegenUnit(Symbol),
]);
+// WARNING: `construct` is generic and does not know that `CompileCodegenUnit` takes `Symbol`s as keys.
+// Be very careful changing this type signature!
+crate fn make_compile_codegen_unit(tcx: TyCtxt<'_>, name: Symbol) -> DepNode {
+ DepNode::construct(tcx, DepKind::CompileCodegenUnit, &name)
+}
+
+pub type DepNode = rustc_query_system::dep_graph::DepNode<DepKind>;
+
+// We keep a lot of `DepNode`s in memory during compilation. It's not
+// required that their size stay the same, but we don't want to change
+// it inadvertently. This assert just ensures we're aware of any change.
+#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+static_assert_size!(DepNode, 17);
+
+#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
+static_assert_size!(DepNode, 24);
+
+pub trait DepNodeExt: Sized {
+ /// Construct a DepNode from the given DepKind and DefPathHash. This
+ /// method will assert that the given DepKind actually requires a
+ /// single DefId/DefPathHash parameter.
+ fn from_def_path_hash(def_path_hash: DefPathHash, kind: DepKind) -> Self;
+
+ /// Extracts the DefId corresponding to this DepNode. This will work
+ /// if two conditions are met:
+ ///
+ /// 1. The Fingerprint of the DepNode actually is a DefPathHash, and
+ /// 2. the item that the DefPath refers to exists in the current tcx.
+ ///
+ /// Condition (1) is determined by the DepKind variant of the
+ /// DepNode. Condition (2) might not be fulfilled if a DepNode
+ /// refers to something from the previous compilation session that
+ /// has been removed.
+ fn extract_def_id(&self, tcx: TyCtxt<'_>) -> Option<DefId>;
+
+ /// Used in testing
+ fn from_label_string(label: &str, def_path_hash: DefPathHash) -> Result<Self, ()>;
+
+ /// Used in testing
+ fn has_label_string(label: &str) -> bool;
+}
+
+impl DepNodeExt for DepNode {
+ /// Construct a DepNode from the given DepKind and DefPathHash. This
+ /// method will assert that the given DepKind actually requires a
+ /// single DefId/DefPathHash parameter.
+ fn from_def_path_hash(def_path_hash: DefPathHash, kind: DepKind) -> DepNode {
+ debug_assert!(kind.can_reconstruct_query_key() && kind.has_params);
+ DepNode { kind, hash: def_path_hash.0.into() }
+ }
+
+ /// Extracts the DefId corresponding to this DepNode. This will work
+ /// if two conditions are met:
+ ///
+ /// 1. The Fingerprint of the DepNode actually is a DefPathHash, and
+ /// 2. the item that the DefPath refers to exists in the current tcx.
+ ///
+ /// Condition (1) is determined by the DepKind variant of the
+ /// DepNode. Condition (2) might not be fulfilled if a DepNode
+ /// refers to something from the previous compilation session that
+ /// has been removed.
+ fn extract_def_id(&self, tcx: TyCtxt<'tcx>) -> Option<DefId> {
+ if self.kind.can_reconstruct_query_key() {
+ tcx.queries
+ .on_disk_cache
+ .as_ref()?
+ .def_path_hash_to_def_id(tcx, DefPathHash(self.hash.into()))
+ } else {
+ None
+ }
+ }
+
+ /// Used in testing
+ fn from_label_string(label: &str, def_path_hash: DefPathHash) -> Result<DepNode, ()> {
+ let kind = dep_kind_from_label_string(label)?;
+
+ if !kind.can_reconstruct_query_key() {
+ return Err(());
+ }
+
+ if kind.has_params {
+ Ok(DepNode::from_def_path_hash(def_path_hash, kind))
+ } else {
+ Ok(DepNode::new_no_params(kind))
+ }
+ }
+
+ /// Used in testing
+ fn has_label_string(label: &str) -> bool {
+ dep_kind_from_label_string(label).is_ok()
+ }
+}
+
+impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for () {
+ #[inline(always)]
+ fn can_reconstruct_query_key() -> bool {
+ true
+ }
+
+ fn to_fingerprint(&self, _: TyCtxt<'tcx>) -> Fingerprint {
+ Fingerprint::ZERO
+ }
+
+ fn recover(_: TyCtxt<'tcx>, _: &DepNode) -> Option<Self> {
+ Some(())
+ }
+}
+
impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for DefId {
- #[inline]
+ #[inline(always)]
fn can_reconstruct_query_key() -> bool {
true
}
@@ -342,7 +489,7 @@
}
impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for LocalDefId {
- #[inline]
+ #[inline(always)]
fn can_reconstruct_query_key() -> bool {
true
}
@@ -361,7 +508,7 @@
}
impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for CrateNum {
- #[inline]
+ #[inline(always)]
fn can_reconstruct_query_key() -> bool {
true
}
@@ -381,7 +528,7 @@
}
impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for (DefId, DefId) {
- #[inline]
+ #[inline(always)]
fn can_reconstruct_query_key() -> bool {
false
}
@@ -406,7 +553,7 @@
}
impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for HirId {
- #[inline]
+ #[inline(always)]
fn can_reconstruct_query_key() -> bool {
false
}
diff --git a/compiler/rustc_middle/src/dep_graph/mod.rs b/compiler/rustc_middle/src/dep_graph/mod.rs
index 728bfef..b88ffa2 100644
--- a/compiler/rustc_middle/src/dep_graph/mod.rs
+++ b/compiler/rustc_middle/src/dep_graph/mod.rs
@@ -1,5 +1,4 @@
use crate::ich::StableHashingContext;
-use crate::ty::query::try_load_from_on_disk_cache;
use crate::ty::{self, TyCtxt};
use rustc_data_structures::profiling::SelfProfilerRef;
use rustc_data_structures::sync::Lock;
@@ -9,13 +8,13 @@
mod dep_node;
-pub(crate) use rustc_query_system::dep_graph::DepNodeParams;
pub use rustc_query_system::dep_graph::{
debug, hash_result, DepContext, DepNodeColor, DepNodeIndex, SerializedDepNodeIndex,
WorkProduct, WorkProductId,
};
-pub use dep_node::{label_strs, DepConstructor, DepKind, DepNode, DepNodeExt};
+crate use dep_node::make_compile_codegen_unit;
+pub use dep_node::{label_strs, DepKind, DepNode, DepNodeExt};
pub type DepGraph = rustc_query_system::dep_graph::DepGraph<DepKind>;
pub type TaskDeps = rustc_query_system::dep_graph::TaskDeps<DepKind>;
@@ -26,18 +25,25 @@
impl rustc_query_system::dep_graph::DepKind for DepKind {
const NULL: Self = DepKind::Null;
- fn is_eval_always(&self) -> bool {
- DepKind::is_eval_always(self)
+ #[inline(always)]
+ fn can_reconstruct_query_key(&self) -> bool {
+ DepKind::can_reconstruct_query_key(self)
}
+ #[inline(always)]
+ fn is_eval_always(&self) -> bool {
+ self.is_eval_always
+ }
+
+ #[inline(always)]
fn has_params(&self) -> bool {
- DepKind::has_params(self)
+ self.has_params
}
fn debug_node(node: &DepNode, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{:?}", node.kind)?;
- if !node.kind.has_params() && !node.kind.is_anon() {
+ if !node.kind.has_params && !node.kind.is_anon {
return Ok(());
}
@@ -81,10 +87,6 @@
op(icx.task_deps)
})
}
-
- fn can_reconstruct_query_key(&self) -> bool {
- DepKind::can_reconstruct_query_key(self)
- }
}
impl<'tcx> DepContext for TyCtxt<'tcx> {
@@ -114,20 +116,9 @@
// be removed. https://github.com/rust-lang/rust/issues/62649 is one such
// bug that must be fixed before removing this.
match dep_node.kind {
- DepKind::hir_owner | DepKind::hir_owner_nodes | DepKind::CrateMetadata => {
+ DepKind::hir_owner | DepKind::hir_owner_nodes => {
if let Some(def_id) = dep_node.extract_def_id(*self) {
- if def_id_corresponds_to_hir_dep_node(*self, def_id.expect_local()) {
- if dep_node.kind == DepKind::CrateMetadata {
- // The `DefPath` has corresponding node,
- // and that node should have been marked
- // either red or green in `data.colors`.
- bug!(
- "DepNode {:?} should have been \
- pre-marked as red or green but wasn't.",
- dep_node
- );
- }
- } else {
+ if !def_id_corresponds_to_hir_dep_node(*self, def_id.expect_local()) {
// This `DefPath` does not have a
// corresponding `DepNode` (e.g. a
// struct field), and the ` DefPath`
@@ -153,7 +144,26 @@
}
debug!("try_force_from_dep_node({:?}) --- trying to force", dep_node);
- ty::query::force_from_dep_node(*self, dep_node)
+
+ // We must avoid ever having to call `force_from_dep_node()` for a
+ // `DepNode::codegen_unit`:
+ // Since we cannot reconstruct the query key of a `DepNode::codegen_unit`, we
+ // would always end up having to evaluate the first caller of the
+ // `codegen_unit` query that *is* reconstructible. This might very well be
+ // the `compile_codegen_unit` query, thus re-codegenning the whole CGU just
+ // to re-trigger calling the `codegen_unit` query with the right key. At
+ // that point we would already have re-done all the work we are trying to
+ // avoid doing in the first place.
+ // The solution is simple: Just explicitly call the `codegen_unit` query for
+ // each CGU, right after partitioning. This way `try_mark_green` will always
+ // hit the cache instead of having to go through `force_from_dep_node`.
+ // This assertion makes sure, we actually keep applying the solution above.
+ debug_assert!(
+ dep_node.kind != DepKind::codegen_unit,
+ "calling force_from_dep_node() on DepKind::codegen_unit"
+ );
+
+ (dep_node.kind.force_from_dep_node)(*self, dep_node)
}
fn has_errors_or_delayed_span_bugs(&self) -> bool {
@@ -166,7 +176,7 @@
// Interactions with on_disk_cache
fn try_load_from_on_disk_cache(&self, dep_node: &DepNode) {
- try_load_from_on_disk_cache(*self, dep_node)
+ (dep_node.kind.try_load_from_on_disk_cache)(*self, dep_node)
}
fn load_diagnostics(&self, prev_dep_node_index: SerializedDepNodeIndex) -> Vec<Diagnostic> {
diff --git a/compiler/rustc_middle/src/hir/map/blocks.rs b/compiler/rustc_middle/src/hir/map/blocks.rs
index 6f572a4..9d392c7 100644
--- a/compiler/rustc_middle/src/hir/map/blocks.rs
+++ b/compiler/rustc_middle/src/hir/map/blocks.rs
@@ -42,37 +42,25 @@
impl MaybeFnLike for hir::Item<'_> {
fn is_fn_like(&self) -> bool {
- match self.kind {
- hir::ItemKind::Fn(..) => true,
- _ => false,
- }
+ matches!(self.kind, hir::ItemKind::Fn(..))
}
}
impl MaybeFnLike for hir::ImplItem<'_> {
fn is_fn_like(&self) -> bool {
- match self.kind {
- hir::ImplItemKind::Fn(..) => true,
- _ => false,
- }
+ matches!(self.kind, hir::ImplItemKind::Fn(..))
}
}
impl MaybeFnLike for hir::TraitItem<'_> {
fn is_fn_like(&self) -> bool {
- match self.kind {
- hir::TraitItemKind::Fn(_, hir::TraitFn::Provided(_)) => true,
- _ => false,
- }
+ matches!(self.kind, hir::TraitItemKind::Fn(_, hir::TraitFn::Provided(_)))
}
}
impl MaybeFnLike for hir::Expr<'_> {
fn is_fn_like(&self) -> bool {
- match self.kind {
- hir::ExprKind::Closure(..) => true,
- _ => false,
- }
+ matches!(self.kind, hir::ExprKind::Closure(..))
}
}
diff --git a/compiler/rustc_middle/src/hir/map/collector.rs b/compiler/rustc_middle/src/hir/map/collector.rs
index 82cfca4..872fcb0 100644
--- a/compiler/rustc_middle/src/hir/map/collector.rs
+++ b/compiler/rustc_middle/src/hir/map/collector.rs
@@ -529,13 +529,22 @@
}
fn visit_macro_def(&mut self, macro_def: &'hir MacroDef<'hir>) {
- self.with_dep_node_owner(macro_def.hir_id.owner, macro_def, |this, hash| {
- this.insert_with_hash(
- macro_def.span,
- macro_def.hir_id,
- Node::MacroDef(macro_def),
- hash,
- );
+ // Exported macros are visited directly from the crate root,
+ // so they do not have `parent_node` set.
+ // Find the correct enclosing module from their DefKey.
+ let def_key = self.definitions.def_key(macro_def.hir_id.owner);
+ let parent = def_key.parent.map_or(hir::CRATE_HIR_ID, |local_def_index| {
+ self.definitions.local_def_id_to_hir_id(LocalDefId { local_def_index })
+ });
+ self.with_parent(parent, |this| {
+ this.with_dep_node_owner(macro_def.hir_id.owner, macro_def, |this, hash| {
+ this.insert_with_hash(
+ macro_def.span,
+ macro_def.hir_id,
+ Node::MacroDef(macro_def),
+ hash,
+ );
+ })
});
}
diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs
index 598e28c..ee12c0e 100644
--- a/compiler/rustc_middle/src/hir/map/mod.rs
+++ b/compiler/rustc_middle/src/hir/map/mod.rs
@@ -1,7 +1,6 @@
use self::collector::NodeCollector;
use crate::hir::{Owner, OwnerNodes};
-use crate::ty::query::Providers;
use crate::ty::TyCtxt;
use rustc_ast as ast;
use rustc_data_structures::svh::Svh;
@@ -9,6 +8,7 @@
use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, CRATE_DEF_INDEX, LOCAL_CRATE};
use rustc_hir::definitions::{DefKey, DefPath, Definitions};
use rustc_hir::intravisit;
+use rustc_hir::intravisit::Visitor;
use rustc_hir::itemlikevisit::ItemLikeVisitor;
use rustc_hir::*;
use rustc_index::vec::IndexVec;
@@ -31,7 +31,7 @@
impl<'hir> Entry<'hir> {
fn parent_node(self) -> Option<HirId> {
match self.node {
- Node::Crate(_) | Node::MacroDef(_) => None,
+ Node::Crate(_) => None,
_ => Some(self.parent),
}
}
@@ -86,11 +86,13 @@
}
}
+#[derive(Debug)]
pub(super) struct HirOwnerData<'hir> {
pub(super) signature: Option<&'hir Owner<'hir>>,
pub(super) with_bodies: Option<&'hir mut OwnerNodes<'hir>>,
}
+#[derive(Debug)]
pub struct IndexedHir<'hir> {
/// The SVH of the local crate.
pub crate_hash: Svh,
@@ -183,14 +185,18 @@
self.tcx.definitions.opt_local_def_id_to_hir_id(def_id)
}
- pub fn def_kind(&self, local_def_id: LocalDefId) -> DefKind {
+ pub fn iter_local_def_id(&self) -> impl Iterator<Item = LocalDefId> + '_ {
+ self.tcx.definitions.iter_local_def_id()
+ }
+
+ pub fn opt_def_kind(&self, local_def_id: LocalDefId) -> Option<DefKind> {
// FIXME(eddyb) support `find` on the crate root.
if local_def_id.to_def_id().index == CRATE_DEF_INDEX {
- return DefKind::Mod;
+ return Some(DefKind::Mod);
}
let hir_id = self.local_def_id_to_hir_id(local_def_id);
- match self.get(hir_id) {
+ let def_kind = match self.find(hir_id)? {
Node::Item(item) => match item.kind {
ItemKind::Static(..) => DefKind::Static,
ItemKind::Const(..) => DefKind::Const,
@@ -249,6 +255,7 @@
GenericParamKind::Type { .. } => DefKind::TyParam,
GenericParamKind::Const { .. } => DefKind::ConstParam,
},
+ Node::Crate(_) => DefKind::Mod,
Node::Stmt(_)
| Node::PathSegment(_)
| Node::Ty(_)
@@ -260,9 +267,14 @@
| Node::Arm(_)
| Node::Lifetime(_)
| Node::Visibility(_)
- | Node::Block(_)
- | Node::Crate(_) => bug!("def_kind: unsupported node: {}", self.node_to_string(hir_id)),
- }
+ | Node::Block(_) => return None,
+ };
+ Some(def_kind)
+ }
+
+ pub fn def_kind(&self, local_def_id: LocalDefId) -> DefKind {
+ self.opt_def_kind(local_def_id)
+ .unwrap_or_else(|| bug!("def_kind: unsupported node: {:?}", local_def_id))
}
fn find_entry(&self, id: HirId) -> Option<Entry<'hir>> {
@@ -379,7 +391,7 @@
pub fn body_param_names(&self, id: BodyId) -> impl Iterator<Item = Ident> + 'hir {
self.body(id).params.iter().map(|arg| match arg.pat.kind {
PatKind::Binding(_, _, ident, _) => ident,
- _ => Ident::new(kw::Invalid, rustc_span::DUMMY_SP),
+ _ => Ident::new(kw::Empty, rustc_span::DUMMY_SP),
})
}
@@ -483,6 +495,15 @@
}
}
+ pub fn visit_exported_macros_in_krate<V>(&self, visitor: &mut V)
+ where
+ V: Visitor<'hir>,
+ {
+ for id in self.krate().exported_macros {
+ visitor.visit_macro_def(self.expect_macro_def(id.hir_id));
+ }
+ }
+
/// Retrieves the `Node` corresponding to `id`, panicking if it cannot be found.
pub fn get(&self, id: HirId) -> Node<'hir> {
self.find(id).unwrap_or_else(|| bug!("couldn't find hir id {} in the HIR map", id))
@@ -505,7 +526,7 @@
| ItemKind::Union(_, generics)
| ItemKind::Trait(_, _, generics, ..)
| ItemKind::TraitAlias(generics, _)
- | ItemKind::Impl { generics, .. },
+ | ItemKind::Impl(Impl { generics, .. }),
..
}) => Some(generics),
_ => None,
@@ -514,9 +535,7 @@
/// Retrieves the `Node` corresponding to `id`, returning `None` if cannot be found.
pub fn find(&self, hir_id: HirId) -> Option<Node<'hir>> {
- self.find_entry(hir_id).and_then(|entry| {
- if let Node::Crate(..) = entry.node { None } else { Some(entry.node) }
- })
+ self.find_entry(hir_id).map(|entry| entry.node)
}
/// Similar to `get_parent`; returns the parent HIR Id, or just `hir_id` if there
@@ -550,13 +569,24 @@
self.find(self.get_parent_node(id)),
Some(
Node::Item(_)
- | Node::TraitItem(_)
- | Node::ImplItem(_)
- | Node::Expr(Expr { kind: ExprKind::Closure(..), .. }),
+ | Node::TraitItem(_)
+ | Node::ImplItem(_)
+ | Node::Expr(Expr { kind: ExprKind::Closure(..), .. }),
)
)
}
+ /// Checks if the node is left-hand side of an assignment.
+ pub fn is_lhs(&self, id: HirId) -> bool {
+ match self.find(self.get_parent_node(id)) {
+ Some(Node::Expr(expr)) => match expr.kind {
+ ExprKind::Assign(lhs, _rhs, _span) => lhs.hir_id == id,
+ _ => false,
+ },
+ _ => false,
+ }
+ }
+
/// Whether the expression pointed at by `hir_id` belongs to a `const` evaluation context.
/// Used exclusively for diagnostics, to avoid suggestion function calls.
pub fn is_inside_const_context(&self, hir_id: HirId) -> bool {
@@ -658,12 +688,12 @@
CRATE_HIR_ID
}
- /// When on a match arm tail expression or on a match arm, give back the enclosing `match`
- /// expression.
+ /// When on an if expression, a match arm tail expression or a match arm, give back
+ /// the enclosing `if` or `match` expression.
///
- /// Used by error reporting when there's a type error in a match arm caused by the `match`
+ /// Used by error reporting when there's a type error in an if or match arm caused by the
/// expression needing to be unit.
- pub fn get_match_if_cause(&self, hir_id: HirId) -> Option<&'hir Expr<'hir>> {
+ pub fn get_if_cause(&self, hir_id: HirId) -> Option<&'hir Expr<'hir>> {
for (_, node) in self.parent_iter(hir_id) {
match node {
Node::Item(_)
@@ -671,7 +701,9 @@
| Node::TraitItem(_)
| Node::ImplItem(_)
| Node::Stmt(Stmt { kind: StmtKind::Local(_), .. }) => break,
- Node::Expr(expr @ Expr { kind: ExprKind::Match(..), .. }) => return Some(expr),
+ Node::Expr(expr @ Expr { kind: ExprKind::If(..) | ExprKind::Match(..), .. }) => {
+ return Some(expr);
+ }
_ => {}
}
}
@@ -710,15 +742,10 @@
let mut scope = id;
loop {
scope = self.get_enclosing_scope(scope).unwrap_or(CRATE_HIR_ID);
- if scope == CRATE_HIR_ID {
- return CRATE_HIR_ID;
- }
- match self.get(scope) {
- Node::Block(_) => {}
- _ => break,
+ if scope == CRATE_HIR_ID || !matches!(self.get(scope), Node::Block(_)) {
+ return scope;
}
}
- scope
}
pub fn get_parent_did(&self, id: HirId) -> LocalDefId {
@@ -785,6 +812,13 @@
}
}
+ pub fn expect_macro_def(&self, id: HirId) -> &'hir MacroDef<'hir> {
+ match self.find(id) {
+ Some(Node::MacroDef(macro_def)) => macro_def,
+ _ => bug!("expected macro def, found {}", self.node_to_string(id)),
+ }
+ }
+
pub fn expect_expr(&self, id: HirId) -> &'hir Expr<'hir> {
match self.find(id) {
Some(Node::Expr(expr)) => expr,
@@ -804,6 +838,7 @@
Node::GenericParam(param) => param.name.ident().name,
Node::Binding(&Pat { kind: PatKind::Binding(_, _, l, _), .. }) => l.name,
Node::Ctor(..) => self.name(self.get_parent_item(id)),
+ Node::MacroDef(md) => md.ident.name,
_ => return None,
})
}
@@ -818,7 +853,7 @@
/// Given a node ID, gets a list of attributes associated with the AST
/// corresponding to the node-ID.
pub fn attrs(&self, id: HirId) -> &'hir [ast::Attribute] {
- let attrs = self.find_entry(id).map(|entry| match entry.node {
+ self.find_entry(id).map_or(&[], |entry| match entry.node {
Node::Param(a) => &a.attrs[..],
Node::Local(l) => &l.attrs[..],
Node::Item(i) => &i.attrs[..],
@@ -845,57 +880,61 @@
| Node::Block(..)
| Node::Lifetime(..)
| Node::Visibility(..) => &[],
- });
- attrs.unwrap_or(&[])
+ })
}
/// Gets the span of the definition of the specified HIR node.
/// This is used by `tcx.get_span`
pub fn span(&self, hir_id: HirId) -> Span {
- match self.find_entry(hir_id).map(|entry| entry.node) {
- Some(Node::Param(param)) => param.span,
- Some(Node::Item(item)) => match &item.kind {
+ self.opt_span(hir_id)
+ .unwrap_or_else(|| bug!("hir::map::Map::span: id not in map: {:?}", hir_id))
+ }
+
+ pub fn opt_span(&self, hir_id: HirId) -> Option<Span> {
+ let span = match self.find_entry(hir_id)?.node {
+ Node::Param(param) => param.span,
+ Node::Item(item) => match &item.kind {
ItemKind::Fn(sig, _, _) => sig.span,
_ => item.span,
},
- Some(Node::ForeignItem(foreign_item)) => foreign_item.span,
- Some(Node::TraitItem(trait_item)) => match &trait_item.kind {
+ Node::ForeignItem(foreign_item) => foreign_item.span,
+ Node::TraitItem(trait_item) => match &trait_item.kind {
TraitItemKind::Fn(sig, _) => sig.span,
_ => trait_item.span,
},
- Some(Node::ImplItem(impl_item)) => match &impl_item.kind {
+ Node::ImplItem(impl_item) => match &impl_item.kind {
ImplItemKind::Fn(sig, _) => sig.span,
_ => impl_item.span,
},
- Some(Node::Variant(variant)) => variant.span,
- Some(Node::Field(field)) => field.span,
- Some(Node::AnonConst(constant)) => self.body(constant.body).value.span,
- Some(Node::Expr(expr)) => expr.span,
- Some(Node::Stmt(stmt)) => stmt.span,
- Some(Node::PathSegment(seg)) => seg.ident.span,
- Some(Node::Ty(ty)) => ty.span,
- Some(Node::TraitRef(tr)) => tr.path.span,
- Some(Node::Binding(pat)) => pat.span,
- Some(Node::Pat(pat)) => pat.span,
- Some(Node::Arm(arm)) => arm.span,
- Some(Node::Block(block)) => block.span,
- Some(Node::Ctor(..)) => match self.find(self.get_parent_node(hir_id)) {
- Some(Node::Item(item)) => item.span,
- Some(Node::Variant(variant)) => variant.span,
+ Node::Variant(variant) => variant.span,
+ Node::Field(field) => field.span,
+ Node::AnonConst(constant) => self.body(constant.body).value.span,
+ Node::Expr(expr) => expr.span,
+ Node::Stmt(stmt) => stmt.span,
+ Node::PathSegment(seg) => seg.ident.span,
+ Node::Ty(ty) => ty.span,
+ Node::TraitRef(tr) => tr.path.span,
+ Node::Binding(pat) => pat.span,
+ Node::Pat(pat) => pat.span,
+ Node::Arm(arm) => arm.span,
+ Node::Block(block) => block.span,
+ Node::Ctor(..) => match self.find(self.get_parent_node(hir_id))? {
+ Node::Item(item) => item.span,
+ Node::Variant(variant) => variant.span,
_ => unreachable!(),
},
- Some(Node::Lifetime(lifetime)) => lifetime.span,
- Some(Node::GenericParam(param)) => param.span,
- Some(Node::Visibility(&Spanned {
+ Node::Lifetime(lifetime) => lifetime.span,
+ Node::GenericParam(param) => param.span,
+ Node::Visibility(&Spanned {
node: VisibilityKind::Restricted { ref path, .. },
..
- })) => path.span,
- Some(Node::Visibility(v)) => bug!("unexpected Visibility {:?}", v),
- Some(Node::Local(local)) => local.span,
- Some(Node::MacroDef(macro_def)) => macro_def.span,
- Some(Node::Crate(item)) => item.span,
- None => bug!("hir::map::Map::span: id not in map: {:?}", hir_id),
- }
+ }) => path.span,
+ Node::Visibility(v) => bug!("unexpected Visibility {:?}", v),
+ Node::Local(local) => local.span,
+ Node::MacroDef(macro_def) => macro_def.span,
+ Node::Crate(item) => item.span,
+ };
+ Some(span)
}
/// Like `hir.span()`, but includes the body of function items
@@ -911,7 +950,7 @@
}
pub fn span_if_local(&self, id: DefId) -> Option<Span> {
- id.as_local().map(|id| self.span(self.local_def_id_to_hir_id(id)))
+ id.as_local().and_then(|id| self.opt_span(self.local_def_id_to_hir_id(id)))
}
pub fn res_span(&self, res: Res) -> Option<Span> {
@@ -1105,7 +1144,3 @@
None => format!("unknown node{}", id_str),
}
}
-
-pub fn provide(providers: &mut Providers) {
- providers.def_kind = |tcx, def_id| tcx.hir().def_kind(def_id.expect_local());
-}
diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs
index ae3b302..6934e06 100644
--- a/compiler/rustc_middle/src/hir/mod.rs
+++ b/compiler/rustc_middle/src/hir/mod.rs
@@ -15,7 +15,9 @@
use rustc_hir::def_id::{LocalDefId, LOCAL_CRATE};
use rustc_hir::*;
use rustc_index::vec::IndexVec;
+use rustc_span::DUMMY_SP;
+#[derive(Debug)]
pub struct Owner<'tcx> {
parent: HirId,
node: Node<'tcx>,
@@ -31,12 +33,13 @@
}
}
-#[derive(Clone)]
+#[derive(Clone, Debug)]
pub struct ParentedNode<'tcx> {
parent: ItemLocalId,
node: Node<'tcx>,
}
+#[derive(Debug)]
pub struct OwnerNodes<'tcx> {
hash: Fingerprint,
nodes: IndexVec<ItemLocalId, Option<ParentedNode<'tcx>>>,
@@ -77,6 +80,7 @@
};
providers.hir_owner = |tcx, id| tcx.index_hir(LOCAL_CRATE).map[id].signature;
providers.hir_owner_nodes = |tcx, id| tcx.index_hir(LOCAL_CRATE).map[id].with_bodies.as_deref();
+ providers.def_span = |tcx, def_id| tcx.hir().span_if_local(def_id).unwrap_or(DUMMY_SP);
providers.fn_arg_names = |tcx, id| {
let hir = tcx.hir();
let hir_id = hir.local_def_id_to_hir_id(id.expect_local());
@@ -92,5 +96,5 @@
span_bug!(hir.span(hir_id), "fn_arg_names: unexpected item {:?}", id);
}
};
- map::provide(providers);
+ providers.opt_def_kind = |tcx, def_id| tcx.hir().opt_def_kind(def_id.expect_local());
}
diff --git a/compiler/rustc_middle/src/hir/place.rs b/compiler/rustc_middle/src/hir/place.rs
index 1e2e9df..00db190 100644
--- a/compiler/rustc_middle/src/hir/place.rs
+++ b/compiler/rustc_middle/src/hir/place.rs
@@ -110,10 +110,7 @@
base: PlaceBase,
projections: Vec<Projection<'tcx>>,
) -> PlaceWithHirId<'tcx> {
- PlaceWithHirId {
- hir_id: hir_id,
- place: Place { base_ty: base_ty, base: base, projections: projections },
- }
+ PlaceWithHirId { hir_id, place: Place { base_ty, base, projections } }
}
}
diff --git a/compiler/rustc_middle/src/ich/hcx.rs b/compiler/rustc_middle/src/ich/hcx.rs
index 084fe4c..51b650e 100644
--- a/compiler/rustc_middle/src/ich/hcx.rs
+++ b/compiler/rustc_middle/src/ich/hcx.rs
@@ -12,11 +12,12 @@
use rustc_session::Session;
use rustc_span::source_map::SourceMap;
use rustc_span::symbol::Symbol;
-use rustc_span::{BytePos, CachingSourceMapView, SourceFile};
+use rustc_span::{BytePos, CachingSourceMapView, SourceFile, SpanData};
use rustc_span::def_id::{CrateNum, CRATE_DEF_INDEX};
use smallvec::SmallVec;
use std::cmp::Ord;
+use std::thread::LocalKey;
fn compute_ignored_attr_names() -> FxHashSet<Symbol> {
debug_assert!(!ich::IGNORED_ATTRIBUTES.is_empty());
@@ -242,12 +243,26 @@
hcx.def_path_hash(def_id).hash_stable(hcx, hasher);
}
+ fn expn_id_cache() -> &'static LocalKey<rustc_span::ExpnIdCache> {
+ thread_local! {
+ static CACHE: rustc_span::ExpnIdCache = Default::default();
+ }
+ &CACHE
+ }
+
fn byte_pos_to_line_and_col(
&mut self,
byte: BytePos,
) -> Option<(Lrc<SourceFile>, usize, BytePos)> {
self.source_map().byte_pos_to_line_and_col(byte)
}
+
+ fn span_data_to_lines_and_cols(
+ &mut self,
+ span: &SpanData,
+ ) -> Option<(Lrc<SourceFile>, usize, BytePos, usize, BytePos)> {
+ self.source_map().span_data_to_lines_and_cols(span)
+ }
}
pub fn hash_stable_trait_impls<'a>(
diff --git a/compiler/rustc_middle/src/infer/unify_key.rs b/compiler/rustc_middle/src/infer/unify_key.rs
index 16e9aaf..8318bde 100644
--- a/compiler/rustc_middle/src/infer/unify_key.rs
+++ b/compiler/rustc_middle/src/infer/unify_key.rs
@@ -1,4 +1,4 @@
-use crate::ty::{self, FloatVarValue, InferConst, IntVarValue, Ty, TyCtxt};
+use crate::ty::{self, InferConst, Ty, TyCtxt};
use rustc_data_structures::snapshot_vec;
use rustc_data_structures::undo_log::UndoLogs;
use rustc_data_structures::unify::{
@@ -15,36 +15,6 @@
fn to_type<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx>;
}
-/// Raw `TyVid` are used as the unification key for `sub_relations`;
-/// they carry no values.
-impl UnifyKey for ty::TyVid {
- type Value = ();
- fn index(&self) -> u32 {
- self.index
- }
- fn from_index(i: u32) -> ty::TyVid {
- ty::TyVid { index: i }
- }
- fn tag() -> &'static str {
- "TyVid"
- }
-}
-
-impl UnifyKey for ty::IntVid {
- type Value = Option<IntVarValue>;
- fn index(&self) -> u32 {
- self.index
- }
- fn from_index(i: u32) -> ty::IntVid {
- ty::IntVid { index: i }
- }
- fn tag() -> &'static str {
- "IntVid"
- }
-}
-
-impl EqUnifyValue for IntVarValue {}
-
#[derive(PartialEq, Copy, Clone, Debug)]
pub struct RegionVidKey {
/// The minimum region vid in the unification set. This is needed
@@ -80,7 +50,7 @@
}
}
-impl ToType for IntVarValue {
+impl ToType for ty::IntVarValue {
fn to_type<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
match *self {
ty::IntType(i) => tcx.mk_mach_int(i),
@@ -89,24 +59,7 @@
}
}
-// Floating point type keys
-
-impl UnifyKey for ty::FloatVid {
- type Value = Option<FloatVarValue>;
- fn index(&self) -> u32 {
- self.index
- }
- fn from_index(i: u32) -> ty::FloatVid {
- ty::FloatVid { index: i }
- }
- fn tag() -> &'static str {
- "FloatVid"
- }
-}
-
-impl EqUnifyValue for FloatVarValue {}
-
-impl ToType for FloatVarValue {
+impl ToType for ty::FloatVarValue {
fn to_type<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
tcx.mk_mach_float(self.0)
}
diff --git a/compiler/rustc_middle/src/lint.rs b/compiler/rustc_middle/src/lint.rs
index bd724a5..ca73481 100644
--- a/compiler/rustc_middle/src/lint.rs
+++ b/compiler/rustc_middle/src/lint.rs
@@ -49,22 +49,24 @@
}
/// A tuple of a lint level and its source.
-pub type LevelSource = (Level, LintLevelSource);
+pub type LevelAndSource = (Level, LintLevelSource);
+#[derive(Debug)]
pub struct LintLevelSets {
pub list: Vec<LintSet>,
pub lint_cap: Level,
}
+#[derive(Debug)]
pub enum LintSet {
CommandLine {
// -A,-W,-D flags, a `Symbol` for the flag itself and `Level` for which
// flag.
- specs: FxHashMap<LintId, LevelSource>,
+ specs: FxHashMap<LintId, LevelAndSource>,
},
Node {
- specs: FxHashMap<LintId, LevelSource>,
+ specs: FxHashMap<LintId, LevelAndSource>,
parent: u32,
},
}
@@ -78,9 +80,9 @@
&self,
lint: &'static Lint,
idx: u32,
- aux: Option<&FxHashMap<LintId, LevelSource>>,
+ aux: Option<&FxHashMap<LintId, LevelAndSource>>,
sess: &Session,
- ) -> LevelSource {
+ ) -> LevelAndSource {
let (level, mut src) = self.get_lint_id_level(LintId::of(lint), idx, aux);
// If `level` is none then we actually assume the default level for this
@@ -121,7 +123,7 @@
&self,
id: LintId,
mut idx: u32,
- aux: Option<&FxHashMap<LintId, LevelSource>>,
+ aux: Option<&FxHashMap<LintId, LevelAndSource>>,
) -> (Option<Level>, LintLevelSource) {
if let Some(specs) = aux {
if let Some(&(level, src)) = specs.get(&id) {
@@ -147,6 +149,7 @@
}
}
+#[derive(Debug)]
pub struct LintLevelMap {
pub sets: LintLevelSets,
pub id_to_set: FxHashMap<HirId, u32>,
@@ -165,7 +168,7 @@
lint: &'static Lint,
id: HirId,
session: &Session,
- ) -> Option<LevelSource> {
+ ) -> Option<LevelAndSource> {
self.id_to_set.get(&id).map(|idx| self.sets.get_lint_level(lint, *idx, None, session))
}
}
diff --git a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs
index a4363bb..5f2ffda 100644
--- a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs
+++ b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs
@@ -3,7 +3,7 @@
use rustc_session::config::SanitizerSet;
use rustc_span::symbol::Symbol;
-#[derive(Clone, TyEncodable, TyDecodable, HashStable)]
+#[derive(Clone, TyEncodable, TyDecodable, HashStable, Debug)]
pub struct CodegenFnAttrs {
pub flags: CodegenFnAttrFlags,
/// Parsed representation of the `#[inline]` attribute
diff --git a/compiler/rustc_middle/src/middle/cstore.rs b/compiler/rustc_middle/src/middle/cstore.rs
index 6d2c4387..4f1ca96 100644
--- a/compiler/rustc_middle/src/middle/cstore.rs
+++ b/compiler/rustc_middle/src/middle/cstore.rs
@@ -96,7 +96,7 @@
pub wasm_import_module: Option<Symbol>,
}
-#[derive(Clone, TyEncodable, TyDecodable, HashStable)]
+#[derive(Clone, TyEncodable, TyDecodable, HashStable, Debug)]
pub struct ForeignModule {
pub foreign_items: Vec<DefId>,
pub def_id: DefId,
diff --git a/compiler/rustc_middle/src/middle/mod.rs b/compiler/rustc_middle/src/middle/mod.rs
index 9bc9ca6..a369e85 100644
--- a/compiler/rustc_middle/src/middle/mod.rs
+++ b/compiler/rustc_middle/src/middle/mod.rs
@@ -7,7 +7,7 @@
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_span::symbol::Symbol;
- #[derive(HashStable)]
+ #[derive(HashStable, Debug)]
pub struct LibFeatures {
// A map from feature to stabilisation version.
pub stable: FxHashMap<Symbol, Symbol>,
diff --git a/compiler/rustc_middle/src/middle/resolve_lifetime.rs b/compiler/rustc_middle/src/middle/resolve_lifetime.rs
index 3d0144e..1b7d0e6 100644
--- a/compiler/rustc_middle/src/middle/resolve_lifetime.rs
+++ b/compiler/rustc_middle/src/middle/resolve_lifetime.rs
@@ -68,7 +68,7 @@
/// Maps the id of each lifetime reference to the lifetime decl
/// that it corresponds to.
-#[derive(Default, HashStable)]
+#[derive(Default, HashStable, Debug)]
pub struct ResolveLifetimes {
/// Maps from every use of a named (not anonymous) lifetime to a
/// `Region` describing how that region is bound
diff --git a/compiler/rustc_middle/src/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs
index 4f08057..89ca8ee 100644
--- a/compiler/rustc_middle/src/middle/stability.rs
+++ b/compiler/rustc_middle/src/middle/stability.rs
@@ -36,7 +36,7 @@
}
/// An entry in the `depr_map`.
-#[derive(Clone, HashStable)]
+#[derive(Clone, HashStable, Debug)]
pub struct DeprecationEntry {
/// The metadata of the attribute associated with this entry.
pub attr: Deprecation,
@@ -63,7 +63,7 @@
}
/// A stability index, giving the stability level for items and methods.
-#[derive(HashStable)]
+#[derive(HashStable, Debug)]
pub struct Index<'tcx> {
/// This is mostly a cache, except the stabilities of local items
/// are filled by the annotator.
diff --git a/compiler/rustc_middle/src/mir/coverage.rs b/compiler/rustc_middle/src/mir/coverage.rs
index 8a6bf9d..95096d0 100644
--- a/compiler/rustc_middle/src/mir/coverage.rs
+++ b/compiler/rustc_middle/src/mir/coverage.rs
@@ -118,17 +118,11 @@
}
pub fn is_counter(&self) -> bool {
- match self {
- Self::Counter { .. } => true,
- _ => false,
- }
+ matches!(self, Self::Counter { .. })
}
pub fn is_expression(&self) -> bool {
- match self {
- Self::Expression { .. } => true,
- _ => false,
- }
+ matches!(self, Self::Expression { .. })
}
pub fn is_unreachable(&self) -> bool {
diff --git a/compiler/rustc_middle/src/mir/graph_cyclic_cache.rs b/compiler/rustc_middle/src/mir/graph_cyclic_cache.rs
new file mode 100644
index 0000000..5f02897
--- /dev/null
+++ b/compiler/rustc_middle/src/mir/graph_cyclic_cache.rs
@@ -0,0 +1,62 @@
+use rustc_data_structures::graph::{
+ self, DirectedGraph, WithNumNodes, WithStartNode, WithSuccessors,
+};
+use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
+use rustc_data_structures::sync::OnceCell;
+use rustc_serialize as serialize;
+
+/// Helper type to cache the result of `graph::is_cyclic`.
+#[derive(Clone, Debug)]
+pub(super) struct GraphIsCyclicCache {
+ cache: OnceCell<bool>,
+}
+
+impl GraphIsCyclicCache {
+ #[inline]
+ pub(super) fn new() -> Self {
+ GraphIsCyclicCache { cache: OnceCell::new() }
+ }
+
+ pub(super) fn is_cyclic<G>(&self, graph: &G) -> bool
+ where
+ G: ?Sized + DirectedGraph + WithStartNode + WithSuccessors + WithNumNodes,
+ {
+ *self.cache.get_or_init(|| graph::is_cyclic(graph))
+ }
+
+ /// Invalidates the cache.
+ #[inline]
+ pub(super) fn invalidate(&mut self) {
+ // Invalidating the cache requires mutating the MIR, which in turn requires a unique
+ // reference (`&mut`) to the `mir::Body`. Because of this, we can assume that all
+ // callers of `invalidate` have a unique reference to the MIR and thus to the
+ // cache. This means we never need to do synchronization when `invalidate` is called,
+ // we can simply reinitialize the `OnceCell`.
+ self.cache = OnceCell::new();
+ }
+}
+
+impl<S: serialize::Encoder> serialize::Encodable<S> for GraphIsCyclicCache {
+ #[inline]
+ fn encode(&self, s: &mut S) -> Result<(), S::Error> {
+ serialize::Encodable::encode(&(), s)
+ }
+}
+
+impl<D: serialize::Decoder> serialize::Decodable<D> for GraphIsCyclicCache {
+ #[inline]
+ fn decode(d: &mut D) -> Result<Self, D::Error> {
+ serialize::Decodable::decode(d).map(|_v: ()| Self::new())
+ }
+}
+
+impl<CTX> HashStable<CTX> for GraphIsCyclicCache {
+ #[inline]
+ fn hash_stable(&self, _: &mut CTX, _: &mut StableHasher) {
+ // do nothing
+ }
+}
+
+TrivialTypeFoldableAndLiftImpls! {
+ GraphIsCyclicCache,
+}
diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs
index 397d2ff..cf931ec 100644
--- a/compiler/rustc_middle/src/mir/interpret/error.rs
+++ b/compiler/rustc_middle/src/mir/interpret/error.rs
@@ -127,6 +127,8 @@
Layout(layout::LayoutError<'tcx>),
/// An invalid transmute happened.
TransmuteSizeDiff(Ty<'tcx>, Ty<'tcx>),
+ /// SizeOf of unsized type was requested.
+ SizeOfUnsizedType(Ty<'tcx>),
}
impl fmt::Display for InvalidProgramInfo<'_> {
@@ -144,6 +146,7 @@
"transmuting `{}` to `{}` is not possible, because these types do not have the same size",
from_ty, to_ty
),
+ SizeOfUnsizedType(ty) => write!(f, "size_of called on unsized type `{}`", ty),
}
}
}
diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs
index 80b5864..55fe5f9 100644
--- a/compiler/rustc_middle/src/mir/interpret/mod.rs
+++ b/compiler/rustc_middle/src/mir/interpret/mod.rs
@@ -588,12 +588,3 @@
debug_assert!(source.len() == 0); // We should have consumed the source buffer.
uint
}
-
-/// Computes the unsigned absolute value without wrapping or panicking.
-#[inline]
-pub fn uabs(value: i64) -> u64 {
- // The only tricky part here is if value == i64::MIN. In that case,
- // wrapping_abs() returns i64::MIN == -2^63. Casting this value to a u64
- // gives 2^63, the correct value.
- value.wrapping_abs() as u64
-}
diff --git a/compiler/rustc_middle/src/mir/interpret/pointer.rs b/compiler/rustc_middle/src/mir/interpret/pointer.rs
index e3d5a08..8774b48 100644
--- a/compiler/rustc_middle/src/mir/interpret/pointer.rs
+++ b/compiler/rustc_middle/src/mir/interpret/pointer.rs
@@ -1,4 +1,4 @@
-use super::{uabs, AllocId, InterpResult};
+use super::{AllocId, InterpResult};
use rustc_macros::HashStable;
use rustc_target::abi::{HasDataLayout, Size};
@@ -57,7 +57,7 @@
#[inline]
fn overflowing_signed_offset(&self, val: u64, i: i64) -> (u64, bool) {
// We need to make sure that i fits in a machine isize.
- let n = uabs(i);
+ let n = i.unsigned_abs();
if i >= 0 {
let (val, over) = self.overflowing_offset(val, n);
(val, over || i > self.machine_isize_max())
diff --git a/compiler/rustc_middle/src/mir/interpret/value.rs b/compiler/rustc_middle/src/mir/interpret/value.rs
index 5e97862..4bb39fe 100644
--- a/compiler/rustc_middle/src/mir/interpret/value.rs
+++ b/compiler/rustc_middle/src/mir/interpret/value.rs
@@ -13,7 +13,7 @@
use super::{AllocId, Allocation, InterpResult, Pointer, PointerArithmetic};
/// Represents the result of const evaluation via the `eval_to_allocation` query.
-#[derive(Clone, HashStable, TyEncodable, TyDecodable)]
+#[derive(Clone, HashStable, TyEncodable, TyDecodable, Debug)]
pub struct ConstAlloc<'tcx> {
// the value lives here, at offset 0, and that allocation definitely is a `AllocKind::Memory`
// (so you can use `AllocMap::unwrap_memory`).
@@ -96,7 +96,7 @@
}
/// A `Scalar` represents an immediate, primitive value existing outside of a
-/// `memory::Allocation`. It is in many ways like a small chunk of a `Allocation`, up to 8 bytes in
+/// `memory::Allocation`. It is in many ways like a small chunk of a `Allocation`, up to 16 bytes in
/// size. Like a range of bytes in an `Allocation`, a `Scalar` can either represent the raw bytes
/// of a simple value or a pointer into another `Allocation`
#[derive(Clone, Copy, Eq, PartialEq, Ord, PartialOrd, TyEncodable, TyDecodable, Hash)]
diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs
index ad48c35..718e81c 100644
--- a/compiler/rustc_middle/src/mir/mod.rs
+++ b/compiler/rustc_middle/src/mir/mod.rs
@@ -35,11 +35,13 @@
use std::slice;
use std::{iter, mem, option};
+use self::graph_cyclic_cache::GraphIsCyclicCache;
use self::predecessors::{PredecessorCache, Predecessors};
pub use self::query::*;
pub mod abstract_const;
pub mod coverage;
+mod graph_cyclic_cache;
pub mod interpret;
pub mod mono;
mod predecessors;
@@ -52,7 +54,7 @@
pub mod visit;
/// Types for locals
-type LocalDecls<'tcx> = IndexVec<Local, LocalDecl<'tcx>>;
+pub type LocalDecls<'tcx> = IndexVec<Local, LocalDecl<'tcx>>;
pub trait HasLocalDecls<'tcx> {
fn local_decls(&self) -> &LocalDecls<'tcx>;
@@ -227,6 +229,7 @@
pub is_polymorphic: bool,
predecessor_cache: PredecessorCache,
+ is_cyclic: GraphIsCyclicCache,
}
impl<'tcx> Body<'tcx> {
@@ -267,6 +270,7 @@
required_consts: Vec::new(),
is_polymorphic: false,
predecessor_cache: PredecessorCache::new(),
+ is_cyclic: GraphIsCyclicCache::new(),
};
body.is_polymorphic = body.has_param_types_or_consts();
body
@@ -296,6 +300,7 @@
var_debug_info: Vec::new(),
is_polymorphic: false,
predecessor_cache: PredecessorCache::new(),
+ is_cyclic: GraphIsCyclicCache::new(),
};
body.is_polymorphic = body.has_param_types_or_consts();
body
@@ -309,11 +314,12 @@
#[inline]
pub fn basic_blocks_mut(&mut self) -> &mut IndexVec<BasicBlock, BasicBlockData<'tcx>> {
// Because the user could mutate basic block terminators via this reference, we need to
- // invalidate the predecessor cache.
+ // invalidate the caches.
//
// FIXME: Use a finer-grained API for this, so only transformations that alter terminators
- // invalidate the predecessor cache.
+ // invalidate the caches.
self.predecessor_cache.invalidate();
+ self.is_cyclic.invalidate();
&mut self.basic_blocks
}
@@ -322,6 +328,7 @@
&mut self,
) -> (&mut IndexVec<BasicBlock, BasicBlockData<'tcx>>, &mut LocalDecls<'tcx>) {
self.predecessor_cache.invalidate();
+ self.is_cyclic.invalidate();
(&mut self.basic_blocks, &mut self.local_decls)
}
@@ -334,13 +341,14 @@
&mut Vec<VarDebugInfo<'tcx>>,
) {
self.predecessor_cache.invalidate();
+ self.is_cyclic.invalidate();
(&mut self.basic_blocks, &mut self.local_decls, &mut self.var_debug_info)
}
/// Returns `true` if a cycle exists in the control-flow graph that is reachable from the
/// `START_BLOCK`.
pub fn is_cfg_cyclic(&self) -> bool {
- graph::is_cyclic(self)
+ self.is_cyclic.is_cyclic(self)
}
#[inline]
@@ -954,8 +962,7 @@
opt_ty_info: _,
opt_match_place: _,
pat_span: _,
- })
- | BindingForm::ImplicitSelf(ImplicitSelfKind::Imm),
+ }) | BindingForm::ImplicitSelf(ImplicitSelfKind::Imm),
)))
)
}
@@ -972,8 +979,7 @@
opt_ty_info: _,
opt_match_place: _,
pat_span: _,
- })
- | BindingForm::ImplicitSelf(_),
+ }) | BindingForm::ImplicitSelf(_),
)))
)
}
@@ -1737,18 +1743,14 @@
/// Finds the innermost `Local` from this `Place`, *if* it is either a local itself or
/// a single deref of a local.
- //
- // FIXME: can we safely swap the semantics of `fn base_local` below in here instead?
+ #[inline(always)]
pub fn local_or_deref_local(&self) -> Option<Local> {
- match self.as_ref() {
- PlaceRef { local, projection: [] }
- | PlaceRef { local, projection: [ProjectionElem::Deref] } => Some(local),
- _ => None,
- }
+ self.as_ref().local_or_deref_local()
}
/// If this place represents a local variable like `_X` with no
/// projections, return `Some(_X)`.
+ #[inline(always)]
pub fn as_local(&self) -> Option<Local> {
self.as_ref().as_local()
}
@@ -1762,6 +1764,7 @@
/// As a concrete example, given the place a.b.c, this would yield:
/// - (a, .b)
/// - (a.b, .c)
+ ///
/// Given a place without projections, the iterator is empty.
pub fn iter_projections(
self,
@@ -1782,8 +1785,6 @@
impl<'tcx> PlaceRef<'tcx> {
/// Finds the innermost `Local` from this `Place`, *if* it is either a local itself or
/// a single deref of a local.
- //
- // FIXME: can we safely swap the semantics of `fn base_local` below in here instead?
pub fn local_or_deref_local(&self) -> Option<Local> {
match *self {
PlaceRef { local, projection: [] }
@@ -1800,6 +1801,14 @@
_ => None,
}
}
+
+ pub fn last_projection(&self) -> Option<(PlaceRef<'tcx>, PlaceElem<'tcx>)> {
+ if let &[ref proj_base @ .., elem] = self.projection {
+ Some((PlaceRef { local: self.local, projection: proj_base }, elem))
+ } else {
+ None
+ }
+ }
}
impl Debug for Place<'_> {
diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs
index 1e70f76..eb13c89 100644
--- a/compiler/rustc_middle/src/mir/mono.rs
+++ b/compiler/rustc_middle/src/mir/mono.rs
@@ -1,4 +1,4 @@
-use crate::dep_graph::{DepConstructor, DepNode, WorkProduct, WorkProductId};
+use crate::dep_graph::{DepNode, WorkProduct, WorkProductId};
use crate::ich::{NodeIdHashingMode, StableHashingContext};
use crate::ty::{subst::InternalSubsts, Instance, InstanceDef, SymbolName, TyCtxt};
use rustc_attr::InlineAttr;
@@ -216,6 +216,7 @@
}
}
+#[derive(Debug)]
pub struct CodegenUnit<'tcx> {
/// A name for this CGU. Incremental compilation requires that
/// name be unique amongst **all** crates. Therefore, it should
@@ -362,7 +363,7 @@
}
pub fn codegen_dep_node(&self, tcx: TyCtxt<'tcx>) -> DepNode {
- DepConstructor::CompileCodegenUnit(tcx, self.name())
+ crate::dep_graph::make_compile_codegen_unit(tcx, self.name())
}
}
diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs
index 89a9309..c293fbe 100644
--- a/compiler/rustc_middle/src/mir/query.rs
+++ b/compiler/rustc_middle/src/mir/query.rs
@@ -17,7 +17,7 @@
use super::{Field, SourceInfo};
-#[derive(Copy, Clone, PartialEq, TyEncodable, TyDecodable, HashStable)]
+#[derive(Copy, Clone, PartialEq, TyEncodable, TyDecodable, HashStable, Debug)]
pub enum UnsafetyViolationKind {
/// Only permitted in regular `fn`s, prohibited in `const fn`s.
General,
@@ -36,7 +36,7 @@
UnsafeFnBorrowPacked,
}
-#[derive(Copy, Clone, PartialEq, TyEncodable, TyDecodable, HashStable)]
+#[derive(Copy, Clone, PartialEq, TyEncodable, TyDecodable, HashStable, Debug)]
pub enum UnsafetyViolationDetails {
CallToUnsafeFunction,
UseOfInlineAssembly,
@@ -121,7 +121,7 @@
}
}
-#[derive(Copy, Clone, PartialEq, TyEncodable, TyDecodable, HashStable)]
+#[derive(Copy, Clone, PartialEq, TyEncodable, TyDecodable, HashStable, Debug)]
pub struct UnsafetyViolation {
pub source_info: SourceInfo,
pub lint_root: hir::HirId,
@@ -129,7 +129,7 @@
pub details: UnsafetyViolationDetails,
}
-#[derive(Clone, TyEncodable, TyDecodable, HashStable)]
+#[derive(Clone, TyEncodable, TyDecodable, HashStable, Debug)]
pub struct UnsafetyCheckResult {
/// Violations that are propagated *upwards* from this function.
pub violations: Lrc<[UnsafetyViolation]>,
@@ -439,18 +439,27 @@
}
#[inline]
- pub fn optimized_mir_opt_const_arg(
+ pub fn optimized_mir_or_const_arg_mir(
self,
def: ty::WithOptConstParam<DefId>,
) -> &'tcx Body<'tcx> {
if let Some((did, param_did)) = def.as_const_arg() {
- self.optimized_mir_of_const_arg((did, param_did))
+ self.mir_for_ctfe_of_const_arg((did, param_did))
} else {
self.optimized_mir(def.did)
}
}
#[inline]
+ pub fn mir_for_ctfe_opt_const_arg(self, def: ty::WithOptConstParam<DefId>) -> &'tcx Body<'tcx> {
+ if let Some((did, param_did)) = def.as_const_arg() {
+ self.mir_for_ctfe_of_const_arg((did, param_did))
+ } else {
+ self.mir_for_ctfe(def.did)
+ }
+ }
+
+ #[inline]
pub fn mir_abstract_const_opt_const_arg(
self,
def: ty::WithOptConstParam<DefId>,
diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs
index e281010..023555d 100644
--- a/compiler/rustc_middle/src/mir/visit.rs
+++ b/compiler/rustc_middle/src/mir/visit.rs
@@ -306,13 +306,13 @@
let mut index = 0;
for statement in statements {
- let location = Location { block: block, statement_index: index };
+ let location = Location { block, statement_index: index };
self.visit_statement(statement, location);
index += 1;
}
if let Some(terminator) = terminator {
- let location = Location { block: block, statement_index: index };
+ let location = Location { block, statement_index: index };
self.visit_terminator(terminator, location);
}
}
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index 1b5f7a2..ca528b2 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -35,1618 +35,1591 @@
// Queries marked with `fatal_cycle` do not need the latter implementation,
// as they will raise an fatal error on query cycles instead.
rustc_queries! {
- Other {
- query trigger_delay_span_bug(key: DefId) -> () {
- desc { "trigger a delay span bug" }
+ query trigger_delay_span_bug(key: DefId) -> () {
+ desc { "trigger a delay span bug" }
+ }
+
+ /// Represents crate as a whole (as distinct from the top-level crate module).
+ /// If you call `hir_crate` (e.g., indirectly by calling `tcx.hir().krate()`),
+ /// we will have to assume that any change means that you need to be recompiled.
+ /// This is because the `hir_crate` query gives you access to all other items.
+ /// To avoid this fate, do not call `tcx.hir().krate()`; instead,
+ /// prefer wrappers like `tcx.visit_all_items_in_krate()`.
+ query hir_crate(key: CrateNum) -> &'tcx Crate<'tcx> {
+ eval_always
+ no_hash
+ desc { "get the crate HIR" }
+ }
+
+ /// The indexed HIR. This can be conveniently accessed by `tcx.hir()`.
+ /// Avoid calling this query directly.
+ query index_hir(_: CrateNum) -> &'tcx map::IndexedHir<'tcx> {
+ eval_always
+ no_hash
+ desc { "index HIR" }
+ }
+
+ /// The items in a module.
+ ///
+ /// This can be conveniently accessed by `tcx.hir().visit_item_likes_in_module`.
+ /// Avoid calling this query directly.
+ query hir_module_items(key: LocalDefId) -> &'tcx hir::ModuleItems {
+ eval_always
+ desc { |tcx| "HIR module items in `{}`", tcx.def_path_str(key.to_def_id()) }
+ }
+
+ /// Gives access to the HIR node for the HIR owner `key`.
+ ///
+ /// This can be conveniently accessed by methods on `tcx.hir()`.
+ /// Avoid calling this query directly.
+ query hir_owner(key: LocalDefId) -> Option<&'tcx crate::hir::Owner<'tcx>> {
+ eval_always
+ desc { |tcx| "HIR owner of `{}`", tcx.def_path_str(key.to_def_id()) }
+ }
+
+ /// Gives access to the HIR nodes and bodies inside the HIR owner `key`.
+ ///
+ /// This can be conveniently accessed by methods on `tcx.hir()`.
+ /// Avoid calling this query directly.
+ query hir_owner_nodes(key: LocalDefId) -> Option<&'tcx crate::hir::OwnerNodes<'tcx>> {
+ eval_always
+ desc { |tcx| "HIR owner items in `{}`", tcx.def_path_str(key.to_def_id()) }
+ }
+
+ /// Computes the `DefId` of the corresponding const parameter in case the `key` is a
+ /// const argument and returns `None` otherwise.
+ ///
+ /// ```ignore (incomplete)
+ /// let a = foo::<7>();
+ /// // ^ Calling `opt_const_param_of` for this argument,
+ ///
+ /// fn foo<const N: usize>()
+ /// // ^ returns this `DefId`.
+ ///
+ /// fn bar() {
+ /// // ^ While calling `opt_const_param_of` for other bodies returns `None`.
+ /// }
+ /// ```
+ // It looks like caching this query on disk actually slightly
+ // worsened performance in #74376.
+ //
+ // Once const generics are more prevalently used, we might want to
+ // consider only caching calls returning `Some`.
+ query opt_const_param_of(key: LocalDefId) -> Option<DefId> {
+ desc { |tcx| "computing the optional const parameter of `{}`", tcx.def_path_str(key.to_def_id()) }
+ }
+
+ /// Records the type of every item.
+ query type_of(key: DefId) -> Ty<'tcx> {
+ desc { |tcx| "computing type of `{}`", tcx.def_path_str(key) }
+ cache_on_disk_if { key.is_local() }
+ }
+
+ query analysis(key: CrateNum) -> Result<(), ErrorReported> {
+ eval_always
+ desc { "running analysis passes on this crate" }
+ }
+
+ /// Maps from the `DefId` of an item (trait/struct/enum/fn) to its
+ /// associated generics.
+ query generics_of(key: DefId) -> ty::Generics {
+ desc { |tcx| "computing generics of `{}`", tcx.def_path_str(key) }
+ storage(ArenaCacheSelector<'tcx>)
+ cache_on_disk_if { key.is_local() }
+ load_cached(tcx, id) {
+ let generics: Option<ty::Generics> = tcx.queries.on_disk_cache.as_ref()
+ .and_then(|c| c.try_load_query_result(tcx, id));
+ generics
}
}
- Other {
- /// Represents crate as a whole (as distinct from the top-level crate module).
- /// If you call `hir_crate` (e.g., indirectly by calling `tcx.hir().krate()`),
- /// we will have to assume that any change means that you need to be recompiled.
- /// This is because the `hir_crate` query gives you access to all other items.
- /// To avoid this fate, do not call `tcx.hir().krate()`; instead,
- /// prefer wrappers like `tcx.visit_all_items_in_krate()`.
- query hir_crate(key: CrateNum) -> &'tcx Crate<'tcx> {
- eval_always
- no_hash
- desc { "get the crate HIR" }
- }
+ /// Maps from the `DefId` of an item (trait/struct/enum/fn) to the
+ /// predicates (where-clauses) that must be proven true in order
+ /// to reference it. This is almost always the "predicates query"
+ /// that you want.
+ ///
+ /// `predicates_of` builds on `predicates_defined_on` -- in fact,
+ /// it is almost always the same as that query, except for the
+ /// case of traits. For traits, `predicates_of` contains
+ /// an additional `Self: Trait<...>` predicate that users don't
+ /// actually write. This reflects the fact that to invoke the
+ /// trait (e.g., via `Default::default`) you must supply types
+ /// that actually implement the trait. (However, this extra
+ /// predicate gets in the way of some checks, which are intended
+ /// to operate over only the actual where-clauses written by the
+ /// user.)
+ query predicates_of(key: DefId) -> ty::GenericPredicates<'tcx> {
+ desc { |tcx| "computing predicates of `{}`", tcx.def_path_str(key) }
+ cache_on_disk_if { key.is_local() }
+ }
- /// The indexed HIR. This can be conveniently accessed by `tcx.hir()`.
- /// Avoid calling this query directly.
- query index_hir(_: CrateNum) -> &'tcx map::IndexedHir<'tcx> {
- eval_always
- no_hash
- desc { "index HIR" }
- }
+ /// Returns the list of bounds that can be used for
+ /// `SelectionCandidate::ProjectionCandidate(_)` and
+ /// `ProjectionTyCandidate::TraitDef`.
+ /// Specifically this is the bounds written on the trait's type
+ /// definition, or those after the `impl` keyword
+ ///
+ /// ```ignore (incomplete)
+ /// type X: Bound + 'lt
+ /// // ^^^^^^^^^^^
+ /// impl Debug + Display
+ /// // ^^^^^^^^^^^^^^^
+ /// ```
+ ///
+ /// `key` is the `DefId` of the associated type or opaque type.
+ ///
+ /// Bounds from the parent (e.g. with nested impl trait) are not included.
+ query explicit_item_bounds(key: DefId) -> &'tcx [(ty::Predicate<'tcx>, Span)] {
+ desc { |tcx| "finding item bounds for `{}`", tcx.def_path_str(key) }
+ }
- /// The items in a module.
- ///
- /// This can be conveniently accessed by `tcx.hir().visit_item_likes_in_module`.
- /// Avoid calling this query directly.
- query hir_module_items(key: LocalDefId) -> &'tcx hir::ModuleItems {
- eval_always
- desc { |tcx| "HIR module items in `{}`", tcx.def_path_str(key.to_def_id()) }
- }
+ /// Elaborated version of the predicates from `explicit_item_bounds`.
+ ///
+ /// For example:
+ ///
+ /// ```
+ /// trait MyTrait {
+ /// type MyAType: Eq + ?Sized;
+ /// }
+ /// ```
+ ///
+ /// `explicit_item_bounds` returns `[<Self as MyTrait>::MyAType: Eq]`,
+ /// and `item_bounds` returns
+ /// ```text
+ /// [
+ /// <Self as Trait>::MyAType: Eq,
+ /// <Self as Trait>::MyAType: PartialEq<<Self as Trait>::MyAType>
+ /// ]
+ /// ```
+ ///
+ /// Bounds from the parent (e.g. with nested impl trait) are not included.
+ query item_bounds(key: DefId) -> &'tcx ty::List<ty::Predicate<'tcx>> {
+ desc { |tcx| "elaborating item bounds for `{}`", tcx.def_path_str(key) }
+ }
- /// Gives access to the HIR node for the HIR owner `key`.
- ///
- /// This can be conveniently accessed by methods on `tcx.hir()`.
- /// Avoid calling this query directly.
- query hir_owner(key: LocalDefId) -> Option<&'tcx crate::hir::Owner<'tcx>> {
- eval_always
- desc { |tcx| "HIR owner of `{}`", tcx.def_path_str(key.to_def_id()) }
- }
+ query projection_ty_from_predicates(key: (DefId, DefId)) -> Option<ty::ProjectionTy<'tcx>> {
+ desc { |tcx| "finding projection type inside predicates of `{}`", tcx.def_path_str(key.0) }
+ }
- /// Gives access to the HIR nodes and bodies inside the HIR owner `key`.
- ///
- /// This can be conveniently accessed by methods on `tcx.hir()`.
- /// Avoid calling this query directly.
- query hir_owner_nodes(key: LocalDefId) -> Option<&'tcx crate::hir::OwnerNodes<'tcx>> {
- eval_always
- desc { |tcx| "HIR owner items in `{}`", tcx.def_path_str(key.to_def_id()) }
- }
+ query native_libraries(_: CrateNum) -> Lrc<Vec<NativeLib>> {
+ desc { "looking up the native libraries of a linked crate" }
+ }
- /// Computes the `DefId` of the corresponding const parameter in case the `key` is a
- /// const argument and returns `None` otherwise.
- ///
- /// ```ignore (incomplete)
- /// let a = foo::<7>();
- /// // ^ Calling `opt_const_param_of` for this argument,
- ///
- /// fn foo<const N: usize>()
- /// // ^ returns this `DefId`.
- ///
- /// fn bar() {
- /// // ^ While calling `opt_const_param_of` for other bodies returns `None`.
- /// }
- /// ```
- // It looks like caching this query on disk actually slightly
- // worsened performance in #74376.
- //
- // Once const generics are more prevalently used, we might want to
- // consider only caching calls returning `Some`.
- query opt_const_param_of(key: LocalDefId) -> Option<DefId> {
- desc { |tcx| "computing the optional const parameter of `{}`", tcx.def_path_str(key.to_def_id()) }
- }
+ query lint_levels(_: CrateNum) -> LintLevelMap {
+ storage(ArenaCacheSelector<'tcx>)
+ eval_always
+ desc { "computing the lint levels for items in this crate" }
+ }
- /// Records the type of every item.
- query type_of(key: DefId) -> Ty<'tcx> {
- desc { |tcx| "computing type of `{}`", tcx.def_path_str(key) }
- cache_on_disk_if { key.is_local() }
- }
+ query parent_module_from_def_id(key: LocalDefId) -> LocalDefId {
+ eval_always
+ desc { |tcx| "parent module of `{}`", tcx.def_path_str(key.to_def_id()) }
+ }
- query analysis(key: CrateNum) -> Result<(), ErrorReported> {
- eval_always
- desc { "running analysis passes on this crate" }
- }
+ /// Internal helper query. Use `tcx.expansion_that_defined` instead
+ query expn_that_defined(key: DefId) -> rustc_span::ExpnId {
+ desc { |tcx| "expansion that defined `{}`", tcx.def_path_str(key) }
+ }
- /// Maps from the `DefId` of an item (trait/struct/enum/fn) to its
- /// associated generics.
- query generics_of(key: DefId) -> ty::Generics {
- desc { |tcx| "computing generics of `{}`", tcx.def_path_str(key) }
- storage(ArenaCacheSelector<'tcx>)
- cache_on_disk_if { key.is_local() }
- load_cached(tcx, id) {
- let generics: Option<ty::Generics> = tcx.queries.on_disk_cache.as_ref()
- .and_then(|c| c.try_load_query_result(tcx, id));
- generics
- }
- }
+ query is_panic_runtime(_: CrateNum) -> bool {
+ fatal_cycle
+ desc { "checking if the crate is_panic_runtime" }
+ }
- /// Maps from the `DefId` of an item (trait/struct/enum/fn) to the
- /// predicates (where-clauses) that must be proven true in order
- /// to reference it. This is almost always the "predicates query"
- /// that you want.
- ///
- /// `predicates_of` builds on `predicates_defined_on` -- in fact,
- /// it is almost always the same as that query, except for the
- /// case of traits. For traits, `predicates_of` contains
- /// an additional `Self: Trait<...>` predicate that users don't
- /// actually write. This reflects the fact that to invoke the
- /// trait (e.g., via `Default::default`) you must supply types
- /// that actually implement the trait. (However, this extra
- /// predicate gets in the way of some checks, which are intended
- /// to operate over only the actual where-clauses written by the
- /// user.)
- query predicates_of(key: DefId) -> ty::GenericPredicates<'tcx> {
- desc { |tcx| "computing predicates of `{}`", tcx.def_path_str(key) }
- cache_on_disk_if { key.is_local() }
- }
+ /// Set of all the `DefId`s in this crate that have MIR associated with
+ /// them. This includes all the body owners, but also things like struct
+ /// constructors.
+ query mir_keys(_: CrateNum) -> FxHashSet<LocalDefId> {
+ storage(ArenaCacheSelector<'tcx>)
+ desc { "getting a list of all mir_keys" }
+ }
- /// Returns the list of bounds that can be used for
- /// `SelectionCandidate::ProjectionCandidate(_)` and
- /// `ProjectionTyCandidate::TraitDef`.
- /// Specifically this is the bounds written on the trait's type
- /// definition, or those after the `impl` keyword
- ///
- /// ```ignore (incomplete)
- /// type X: Bound + 'lt
- /// // ^^^^^^^^^^^
- /// impl Debug + Display
- /// // ^^^^^^^^^^^^^^^
- /// ```
- ///
- /// `key` is the `DefId` of the associated type or opaque type.
- ///
- /// Bounds from the parent (e.g. with nested impl trait) are not included.
- query explicit_item_bounds(key: DefId) -> &'tcx [(ty::Predicate<'tcx>, Span)] {
- desc { |tcx| "finding item bounds for `{}`", tcx.def_path_str(key) }
- }
-
- /// Elaborated version of the predicates from `explicit_item_bounds`.
- ///
- /// For example:
- ///
- /// ```
- /// trait MyTrait {
- /// type MyAType: Eq + ?Sized;
- /// }
- /// ```
- ///
- /// `explicit_item_bounds` returns `[<Self as MyTrait>::MyAType: Eq]`,
- /// and `item_bounds` returns
- /// ```text
- /// [
- /// <Self as Trait>::MyAType: Eq,
- /// <Self as Trait>::MyAType: PartialEq<<Self as Trait>::MyAType>
- /// ]
- /// ```
- ///
- /// Bounds from the parent (e.g. with nested impl trait) are not included.
- query item_bounds(key: DefId) -> &'tcx ty::List<ty::Predicate<'tcx>> {
- desc { |tcx| "elaborating item bounds for `{}`", tcx.def_path_str(key) }
- }
-
- query projection_ty_from_predicates(key: (DefId, DefId)) -> Option<ty::ProjectionTy<'tcx>> {
- desc { |tcx| "finding projection type inside predicates of `{}`", tcx.def_path_str(key.0) }
- }
-
- query native_libraries(_: CrateNum) -> Lrc<Vec<NativeLib>> {
- desc { "looking up the native libraries of a linked crate" }
- }
-
- query lint_levels(_: CrateNum) -> LintLevelMap {
- storage(ArenaCacheSelector<'tcx>)
- eval_always
- desc { "computing the lint levels for items in this crate" }
- }
-
- query parent_module_from_def_id(key: LocalDefId) -> LocalDefId {
- eval_always
- desc { |tcx| "parent module of `{}`", tcx.def_path_str(key.to_def_id()) }
- }
-
- /// Internal helper query. Use `tcx.expansion_that_defined` instead
- query expn_that_defined(key: DefId) -> rustc_span::ExpnId {
- desc { |tcx| "expansion that defined `{}`", tcx.def_path_str(key) }
+ /// Maps DefId's that have an associated `mir::Body` to the result
+ /// of the MIR const-checking pass. This is the set of qualifs in
+ /// the final value of a `const`.
+ query mir_const_qualif(key: DefId) -> mir::ConstQualifs {
+ desc { |tcx| "const checking `{}`", tcx.def_path_str(key) }
+ cache_on_disk_if { key.is_local() }
+ }
+ query mir_const_qualif_const_arg(
+ key: (LocalDefId, DefId)
+ ) -> mir::ConstQualifs {
+ desc {
+ |tcx| "const checking the const argument `{}`",
+ tcx.def_path_str(key.0.to_def_id())
}
}
- Codegen {
- query is_panic_runtime(_: CrateNum) -> bool {
- fatal_cycle
- desc { "checking if the crate is_panic_runtime" }
+ /// Fetch the MIR for a given `DefId` right after it's built - this includes
+ /// unreachable code.
+ query mir_built(key: ty::WithOptConstParam<LocalDefId>) -> &'tcx Steal<mir::Body<'tcx>> {
+ desc { |tcx| "building MIR for `{}`", tcx.def_path_str(key.did.to_def_id()) }
+ }
+
+ /// Fetch the MIR for a given `DefId` up till the point where it is
+ /// ready for const qualification.
+ ///
+ /// See the README for the `mir` module for details.
+ query mir_const(key: ty::WithOptConstParam<LocalDefId>) -> &'tcx Steal<mir::Body<'tcx>> {
+ desc {
+ |tcx| "processing MIR for {}`{}`",
+ if key.const_param_did.is_some() { "the const argument " } else { "" },
+ tcx.def_path_str(key.did.to_def_id()),
+ }
+ no_hash
+ }
+
+ /// Try to build an abstract representation of the given constant.
+ query mir_abstract_const(
+ key: DefId
+ ) -> Result<Option<&'tcx [mir::abstract_const::Node<'tcx>]>, ErrorReported> {
+ desc {
+ |tcx| "building an abstract representation for {}", tcx.def_path_str(key),
+ }
+ }
+ /// Try to build an abstract representation of the given constant.
+ query mir_abstract_const_of_const_arg(
+ key: (LocalDefId, DefId)
+ ) -> Result<Option<&'tcx [mir::abstract_const::Node<'tcx>]>, ErrorReported> {
+ desc {
+ |tcx|
+ "building an abstract representation for the const argument {}",
+ tcx.def_path_str(key.0.to_def_id()),
}
}
- Codegen {
- /// Set of all the `DefId`s in this crate that have MIR associated with
- /// them. This includes all the body owners, but also things like struct
- /// constructors.
- query mir_keys(_: CrateNum) -> FxHashSet<LocalDefId> {
- storage(ArenaCacheSelector<'tcx>)
- desc { "getting a list of all mir_keys" }
- }
-
- /// Maps DefId's that have an associated `mir::Body` to the result
- /// of the MIR const-checking pass. This is the set of qualifs in
- /// the final value of a `const`.
- query mir_const_qualif(key: DefId) -> mir::ConstQualifs {
- desc { |tcx| "const checking `{}`", tcx.def_path_str(key) }
- cache_on_disk_if { key.is_local() }
- }
- query mir_const_qualif_const_arg(
- key: (LocalDefId, DefId)
- ) -> mir::ConstQualifs {
- desc {
- |tcx| "const checking the const argument `{}`",
- tcx.def_path_str(key.0.to_def_id())
- }
- }
-
- /// Fetch the MIR for a given `DefId` right after it's built - this includes
- /// unreachable code.
- query mir_built(key: ty::WithOptConstParam<LocalDefId>) -> &'tcx Steal<mir::Body<'tcx>> {
- desc { |tcx| "building MIR for `{}`", tcx.def_path_str(key.did.to_def_id()) }
- }
-
- /// Fetch the MIR for a given `DefId` up till the point where it is
- /// ready for const qualification.
- ///
- /// See the README for the `mir` module for details.
- query mir_const(key: ty::WithOptConstParam<LocalDefId>) -> &'tcx Steal<mir::Body<'tcx>> {
- desc {
- |tcx| "processing MIR for {}`{}`",
- if key.const_param_did.is_some() { "the const argument " } else { "" },
- tcx.def_path_str(key.did.to_def_id()),
- }
- no_hash
- }
-
- /// Try to build an abstract representation of the given constant.
- query mir_abstract_const(
- key: DefId
- ) -> Result<Option<&'tcx [mir::abstract_const::Node<'tcx>]>, ErrorReported> {
- desc {
- |tcx| "building an abstract representation for {}", tcx.def_path_str(key),
- }
- }
- /// Try to build an abstract representation of the given constant.
- query mir_abstract_const_of_const_arg(
- key: (LocalDefId, DefId)
- ) -> Result<Option<&'tcx [mir::abstract_const::Node<'tcx>]>, ErrorReported> {
- desc {
- |tcx|
- "building an abstract representation for the const argument {}",
- tcx.def_path_str(key.0.to_def_id()),
- }
- }
-
- query try_unify_abstract_consts(key: (
- (ty::WithOptConstParam<DefId>, SubstsRef<'tcx>),
- (ty::WithOptConstParam<DefId>, SubstsRef<'tcx>)
- )) -> bool {
- desc {
- |tcx| "trying to unify the generic constants {} and {}",
- tcx.def_path_str(key.0.0.did), tcx.def_path_str(key.1.0.did)
- }
- }
-
- query mir_drops_elaborated_and_const_checked(
- key: ty::WithOptConstParam<LocalDefId>
- ) -> &'tcx Steal<mir::Body<'tcx>> {
- no_hash
- desc { |tcx| "elaborating drops for `{}`", tcx.def_path_str(key.did.to_def_id()) }
- }
-
- query mir_promoted(key: ty::WithOptConstParam<LocalDefId>) ->
- (
- &'tcx Steal<mir::Body<'tcx>>,
- &'tcx Steal<IndexVec<mir::Promoted, mir::Body<'tcx>>>
- ) {
- no_hash
- desc {
- |tcx| "processing {}`{}`",
- if key.const_param_did.is_some() { "the const argument " } else { "" },
- tcx.def_path_str(key.did.to_def_id()),
- }
- }
-
- /// MIR after our optimization passes have run. This is MIR that is ready
- /// for codegen. This is also the only query that can fetch non-local MIR, at present.
- query optimized_mir(key: DefId) -> &'tcx mir::Body<'tcx> {
- desc { |tcx| "optimizing MIR for `{}`", tcx.def_path_str(key) }
- cache_on_disk_if { key.is_local() }
- }
- query optimized_mir_of_const_arg(key: (LocalDefId, DefId)) -> &'tcx mir::Body<'tcx> {
- desc {
- |tcx| "optimizing MIR for the const argument `{}`",
- tcx.def_path_str(key.0.to_def_id())
- }
- }
-
- /// Returns coverage summary info for a function, after executing the `InstrumentCoverage`
- /// MIR pass (assuming the -Zinstrument-coverage option is enabled).
- query coverageinfo(key: DefId) -> mir::CoverageInfo {
- desc { |tcx| "retrieving coverage info from MIR for `{}`", tcx.def_path_str(key) }
- storage(ArenaCacheSelector<'tcx>)
- cache_on_disk_if { key.is_local() }
- }
-
- /// Returns the name of the file that contains the function body, if instrumented for coverage.
- query covered_file_name(key: DefId) -> Option<Symbol> {
- desc { |tcx| "retrieving the covered file name, if instrumented, for `{}`", tcx.def_path_str(key) }
- storage(ArenaCacheSelector<'tcx>)
- cache_on_disk_if { key.is_local() }
- }
-
- /// Returns the `CodeRegions` for a function that has instrumented coverage, in case the
- /// function was optimized out before codegen, and before being added to the Coverage Map.
- query covered_code_regions(key: DefId) -> Vec<&'tcx mir::coverage::CodeRegion> {
- desc { |tcx| "retrieving the covered `CodeRegion`s, if instrumented, for `{}`", tcx.def_path_str(key) }
- storage(ArenaCacheSelector<'tcx>)
- cache_on_disk_if { key.is_local() }
- }
-
- /// The `DefId` is the `DefId` of the containing MIR body. Promoteds do not have their own
- /// `DefId`. This function returns all promoteds in the specified body. The body references
- /// promoteds by the `DefId` and the `mir::Promoted` index. This is necessary, because
- /// after inlining a body may refer to promoteds from other bodies. In that case you still
- /// need to use the `DefId` of the original body.
- query promoted_mir(key: DefId) -> &'tcx IndexVec<mir::Promoted, mir::Body<'tcx>> {
- desc { |tcx| "optimizing promoted MIR for `{}`", tcx.def_path_str(key) }
- cache_on_disk_if { key.is_local() }
- }
- query promoted_mir_of_const_arg(
- key: (LocalDefId, DefId)
- ) -> &'tcx IndexVec<mir::Promoted, mir::Body<'tcx>> {
- desc {
- |tcx| "optimizing promoted MIR for the const argument `{}`",
- tcx.def_path_str(key.0.to_def_id()),
- }
+ query try_unify_abstract_consts(key: (
+ (ty::WithOptConstParam<DefId>, SubstsRef<'tcx>),
+ (ty::WithOptConstParam<DefId>, SubstsRef<'tcx>)
+ )) -> bool {
+ desc {
+ |tcx| "trying to unify the generic constants {} and {}",
+ tcx.def_path_str(key.0.0.did), tcx.def_path_str(key.1.0.did)
}
}
- TypeChecking {
- /// Erases regions from `ty` to yield a new type.
- /// Normally you would just use `tcx.erase_regions(value)`,
- /// however, which uses this query as a kind of cache.
- query erase_regions_ty(ty: Ty<'tcx>) -> Ty<'tcx> {
- // This query is not expected to have input -- as a result, it
- // is not a good candidates for "replay" because it is essentially a
- // pure function of its input (and hence the expectation is that
- // no caller would be green **apart** from just these
- // queries). Making it anonymous avoids hashing the result, which
- // may save a bit of time.
- anon
- desc { "erasing regions from `{:?}`", ty }
+ query mir_drops_elaborated_and_const_checked(
+ key: ty::WithOptConstParam<LocalDefId>
+ ) -> &'tcx Steal<mir::Body<'tcx>> {
+ no_hash
+ desc { |tcx| "elaborating drops for `{}`", tcx.def_path_str(key.did.to_def_id()) }
+ }
+
+ query mir_for_ctfe(
+ key: DefId
+ ) -> &'tcx mir::Body<'tcx> {
+ desc { |tcx| "caching mir of `{}` for CTFE", tcx.def_path_str(key) }
+ cache_on_disk_if { key.is_local() }
+ }
+
+ query mir_for_ctfe_of_const_arg(key: (LocalDefId, DefId)) -> &'tcx mir::Body<'tcx> {
+ desc {
+ |tcx| "MIR for CTFE of the const argument `{}`",
+ tcx.def_path_str(key.0.to_def_id())
}
}
- Linking {
- query wasm_import_module_map(_: CrateNum) -> FxHashMap<DefId, String> {
- storage(ArenaCacheSelector<'tcx>)
- desc { "wasm import module map" }
+ query mir_promoted(key: ty::WithOptConstParam<LocalDefId>) ->
+ (
+ &'tcx Steal<mir::Body<'tcx>>,
+ &'tcx Steal<IndexVec<mir::Promoted, mir::Body<'tcx>>>
+ ) {
+ no_hash
+ desc {
+ |tcx| "processing {}`{}`",
+ if key.const_param_did.is_some() { "the const argument " } else { "" },
+ tcx.def_path_str(key.did.to_def_id()),
}
}
- Other {
- /// Maps from the `DefId` of an item (trait/struct/enum/fn) to the
- /// predicates (where-clauses) directly defined on it. This is
- /// equal to the `explicit_predicates_of` predicates plus the
- /// `inferred_outlives_of` predicates.
- query predicates_defined_on(key: DefId) -> ty::GenericPredicates<'tcx> {
- desc { |tcx| "computing predicates of `{}`", tcx.def_path_str(key) }
- }
+ /// MIR after our optimization passes have run. This is MIR that is ready
+ /// for codegen. This is also the only query that can fetch non-local MIR, at present.
+ query optimized_mir(key: DefId) -> &'tcx mir::Body<'tcx> {
+ desc { |tcx| "optimizing MIR for `{}`", tcx.def_path_str(key) }
+ cache_on_disk_if { key.is_local() }
+ }
- /// Returns everything that looks like a predicate written explicitly
- /// by the user on a trait item.
- ///
- /// Traits are unusual, because predicates on associated types are
- /// converted into bounds on that type for backwards compatibility:
- ///
- /// trait X where Self::U: Copy { type U; }
- ///
- /// becomes
- ///
- /// trait X { type U: Copy; }
- ///
- /// `explicit_predicates_of` and `explicit_item_bounds` will then take
- /// the appropriate subsets of the predicates here.
- query trait_explicit_predicates_and_bounds(key: LocalDefId) -> ty::GenericPredicates<'tcx> {
- desc { |tcx| "computing explicit predicates of trait `{}`", tcx.def_path_str(key.to_def_id()) }
- }
+ /// Returns coverage summary info for a function, after executing the `InstrumentCoverage`
+ /// MIR pass (assuming the -Zinstrument-coverage option is enabled).
+ query coverageinfo(key: DefId) -> mir::CoverageInfo {
+ desc { |tcx| "retrieving coverage info from MIR for `{}`", tcx.def_path_str(key) }
+ storage(ArenaCacheSelector<'tcx>)
+ cache_on_disk_if { key.is_local() }
+ }
- /// Returns the predicates written explicitly by the user.
- query explicit_predicates_of(key: DefId) -> ty::GenericPredicates<'tcx> {
- desc { |tcx| "computing explicit predicates of `{}`", tcx.def_path_str(key) }
- }
+ /// Returns the name of the file that contains the function body, if instrumented for coverage.
+ query covered_file_name(key: DefId) -> Option<Symbol> {
+ desc { |tcx| "retrieving the covered file name, if instrumented, for `{}`", tcx.def_path_str(key) }
+ storage(ArenaCacheSelector<'tcx>)
+ cache_on_disk_if { key.is_local() }
+ }
- /// Returns the inferred outlives predicates (e.g., for `struct
- /// Foo<'a, T> { x: &'a T }`, this would return `T: 'a`).
- query inferred_outlives_of(key: DefId) -> &'tcx [(ty::Predicate<'tcx>, Span)] {
- desc { |tcx| "computing inferred outlives predicates of `{}`", tcx.def_path_str(key) }
- }
+ /// Returns the `CodeRegions` for a function that has instrumented coverage, in case the
+ /// function was optimized out before codegen, and before being added to the Coverage Map.
+ query covered_code_regions(key: DefId) -> Vec<&'tcx mir::coverage::CodeRegion> {
+ desc { |tcx| "retrieving the covered `CodeRegion`s, if instrumented, for `{}`", tcx.def_path_str(key) }
+ storage(ArenaCacheSelector<'tcx>)
+ cache_on_disk_if { key.is_local() }
+ }
- /// Maps from the `DefId` of a trait to the list of
- /// super-predicates. This is a subset of the full list of
- /// predicates. We store these in a separate map because we must
- /// evaluate them even during type conversion, often before the
- /// full predicates are available (note that supertraits have
- /// additional acyclicity requirements).
- query super_predicates_of(key: DefId) -> ty::GenericPredicates<'tcx> {
- desc { |tcx| "computing the supertraits of `{}`", tcx.def_path_str(key) }
- }
-
- /// To avoid cycles within the predicates of a single item we compute
- /// per-type-parameter predicates for resolving `T::AssocTy`.
- query type_param_predicates(key: (DefId, LocalDefId)) -> ty::GenericPredicates<'tcx> {
- desc { |tcx| "computing the bounds for type parameter `{}`", {
- let id = tcx.hir().local_def_id_to_hir_id(key.1);
- tcx.hir().ty_param_name(id)
- }}
- }
-
- query trait_def(key: DefId) -> ty::TraitDef {
- desc { |tcx| "computing trait definition for `{}`", tcx.def_path_str(key) }
- storage(ArenaCacheSelector<'tcx>)
- }
- query adt_def(key: DefId) -> &'tcx ty::AdtDef {
- desc { |tcx| "computing ADT definition for `{}`", tcx.def_path_str(key) }
- }
- query adt_destructor(key: DefId) -> Option<ty::Destructor> {
- desc { |tcx| "computing `Drop` impl for `{}`", tcx.def_path_str(key) }
- }
-
- // The cycle error here should be reported as an error by `check_representable`.
- // We consider the type as Sized in the meanwhile to avoid
- // further errors (done in impl Value for AdtSizedConstraint).
- // Use `cycle_delay_bug` to delay the cycle error here to be emitted later
- // in case we accidentally otherwise don't emit an error.
- query adt_sized_constraint(
- key: DefId
- ) -> AdtSizedConstraint<'tcx> {
- desc { |tcx| "computing `Sized` constraints for `{}`", tcx.def_path_str(key) }
- cycle_delay_bug
- }
-
- query adt_dtorck_constraint(
- key: DefId
- ) -> Result<DtorckConstraint<'tcx>, NoSolution> {
- desc { |tcx| "computing drop-check constraints for `{}`", tcx.def_path_str(key) }
- }
-
- /// Returns `true` if this is a const fn, use the `is_const_fn` to know whether your crate
- /// actually sees it as const fn (e.g., the const-fn-ness might be unstable and you might
- /// not have the feature gate active).
- ///
- /// **Do not call this function manually.** It is only meant to cache the base data for the
- /// `is_const_fn` function.
- query is_const_fn_raw(key: DefId) -> bool {
- desc { |tcx| "checking if item is const fn: `{}`", tcx.def_path_str(key) }
- }
-
- /// Returns `true` if this is a const `impl`. **Do not call this function manually.**
- ///
- /// This query caches the base data for the `is_const_impl` helper function, which also
- /// takes into account stability attributes (e.g., `#[rustc_const_unstable]`).
- query is_const_impl_raw(key: DefId) -> bool {
- desc { |tcx| "checking if item is const impl: `{}`", tcx.def_path_str(key) }
- }
-
- query asyncness(key: DefId) -> hir::IsAsync {
- desc { |tcx| "checking if the function is async: `{}`", tcx.def_path_str(key) }
- }
-
- /// Returns `true` if calls to the function may be promoted.
- ///
- /// This is either because the function is e.g., a tuple-struct or tuple-variant
- /// constructor, or because it has the `#[rustc_promotable]` attribute. The attribute should
- /// be removed in the future in favour of some form of check which figures out whether the
- /// function does not inspect the bits of any of its arguments (so is essentially just a
- /// constructor function).
- query is_promotable_const_fn(key: DefId) -> bool {
- desc { |tcx| "checking if item is promotable: `{}`", tcx.def_path_str(key) }
- }
-
- /// Returns `true` if this is a foreign item (i.e., linked via `extern { ... }`).
- query is_foreign_item(key: DefId) -> bool {
- desc { |tcx| "checking if `{}` is a foreign item", tcx.def_path_str(key) }
- }
-
- /// Returns `Some(mutability)` if the node pointed to by `def_id` is a static item.
- query static_mutability(def_id: DefId) -> Option<hir::Mutability> {
- desc { |tcx| "looking up static mutability of `{}`", tcx.def_path_str(def_id) }
- }
-
- /// Returns `Some(generator_kind)` if the node pointed to by `def_id` is a generator.
- query generator_kind(def_id: DefId) -> Option<hir::GeneratorKind> {
- desc { |tcx| "looking up generator kind of `{}`", tcx.def_path_str(def_id) }
- }
-
- /// Gets a map with the variance of every item; use `item_variance` instead.
- query crate_variances(_: CrateNum) -> ty::CrateVariancesMap<'tcx> {
- storage(ArenaCacheSelector<'tcx>)
- desc { "computing the variances for items in this crate" }
- }
-
- /// Maps from the `DefId` of a type or region parameter to its (inferred) variance.
- query variances_of(def_id: DefId) -> &'tcx [ty::Variance] {
- desc { |tcx| "computing the variances of `{}`", tcx.def_path_str(def_id) }
+ /// The `DefId` is the `DefId` of the containing MIR body. Promoteds do not have their own
+ /// `DefId`. This function returns all promoteds in the specified body. The body references
+ /// promoteds by the `DefId` and the `mir::Promoted` index. This is necessary, because
+ /// after inlining a body may refer to promoteds from other bodies. In that case you still
+ /// need to use the `DefId` of the original body.
+ query promoted_mir(key: DefId) -> &'tcx IndexVec<mir::Promoted, mir::Body<'tcx>> {
+ desc { |tcx| "optimizing promoted MIR for `{}`", tcx.def_path_str(key) }
+ cache_on_disk_if { key.is_local() }
+ }
+ query promoted_mir_of_const_arg(
+ key: (LocalDefId, DefId)
+ ) -> &'tcx IndexVec<mir::Promoted, mir::Body<'tcx>> {
+ desc {
+ |tcx| "optimizing promoted MIR for the const argument `{}`",
+ tcx.def_path_str(key.0.to_def_id()),
}
}
- TypeChecking {
- /// Maps from thee `DefId` of a type to its (inferred) outlives.
- query inferred_outlives_crate(_: CrateNum)
- -> ty::CratePredicatesMap<'tcx> {
- storage(ArenaCacheSelector<'tcx>)
- desc { "computing the inferred outlives predicates for items in this crate" }
+ /// Erases regions from `ty` to yield a new type.
+ /// Normally you would just use `tcx.erase_regions(value)`,
+ /// however, which uses this query as a kind of cache.
+ query erase_regions_ty(ty: Ty<'tcx>) -> Ty<'tcx> {
+ // This query is not expected to have input -- as a result, it
+ // is not a good candidates for "replay" because it is essentially a
+ // pure function of its input (and hence the expectation is that
+ // no caller would be green **apart** from just these
+ // queries). Making it anonymous avoids hashing the result, which
+ // may save a bit of time.
+ anon
+ desc { "erasing regions from `{:?}`", ty }
+ }
+
+ query wasm_import_module_map(_: CrateNum) -> FxHashMap<DefId, String> {
+ storage(ArenaCacheSelector<'tcx>)
+ desc { "wasm import module map" }
+ }
+
+ /// Maps from the `DefId` of an item (trait/struct/enum/fn) to the
+ /// predicates (where-clauses) directly defined on it. This is
+ /// equal to the `explicit_predicates_of` predicates plus the
+ /// `inferred_outlives_of` predicates.
+ query predicates_defined_on(key: DefId) -> ty::GenericPredicates<'tcx> {
+ desc { |tcx| "computing predicates of `{}`", tcx.def_path_str(key) }
+ }
+
+ /// Returns everything that looks like a predicate written explicitly
+ /// by the user on a trait item.
+ ///
+ /// Traits are unusual, because predicates on associated types are
+ /// converted into bounds on that type for backwards compatibility:
+ ///
+ /// trait X where Self::U: Copy { type U; }
+ ///
+ /// becomes
+ ///
+ /// trait X { type U: Copy; }
+ ///
+ /// `explicit_predicates_of` and `explicit_item_bounds` will then take
+ /// the appropriate subsets of the predicates here.
+ query trait_explicit_predicates_and_bounds(key: LocalDefId) -> ty::GenericPredicates<'tcx> {
+ desc { |tcx| "computing explicit predicates of trait `{}`", tcx.def_path_str(key.to_def_id()) }
+ }
+
+ /// Returns the predicates written explicitly by the user.
+ query explicit_predicates_of(key: DefId) -> ty::GenericPredicates<'tcx> {
+ desc { |tcx| "computing explicit predicates of `{}`", tcx.def_path_str(key) }
+ }
+
+ /// Returns the inferred outlives predicates (e.g., for `struct
+ /// Foo<'a, T> { x: &'a T }`, this would return `T: 'a`).
+ query inferred_outlives_of(key: DefId) -> &'tcx [(ty::Predicate<'tcx>, Span)] {
+ desc { |tcx| "computing inferred outlives predicates of `{}`", tcx.def_path_str(key) }
+ }
+
+ /// Maps from the `DefId` of a trait to the list of
+ /// super-predicates. This is a subset of the full list of
+ /// predicates. We store these in a separate map because we must
+ /// evaluate them even during type conversion, often before the
+ /// full predicates are available (note that supertraits have
+ /// additional acyclicity requirements).
+ query super_predicates_of(key: DefId) -> ty::GenericPredicates<'tcx> {
+ desc { |tcx| "computing the supertraits of `{}`", tcx.def_path_str(key) }
+ }
+
+ /// To avoid cycles within the predicates of a single item we compute
+ /// per-type-parameter predicates for resolving `T::AssocTy`.
+ query type_param_predicates(key: (DefId, LocalDefId)) -> ty::GenericPredicates<'tcx> {
+ desc { |tcx| "computing the bounds for type parameter `{}`", {
+ let id = tcx.hir().local_def_id_to_hir_id(key.1);
+ tcx.hir().ty_param_name(id)
+ }}
+ }
+
+ query trait_def(key: DefId) -> ty::TraitDef {
+ desc { |tcx| "computing trait definition for `{}`", tcx.def_path_str(key) }
+ storage(ArenaCacheSelector<'tcx>)
+ }
+ query adt_def(key: DefId) -> &'tcx ty::AdtDef {
+ desc { |tcx| "computing ADT definition for `{}`", tcx.def_path_str(key) }
+ }
+ query adt_destructor(key: DefId) -> Option<ty::Destructor> {
+ desc { |tcx| "computing `Drop` impl for `{}`", tcx.def_path_str(key) }
+ }
+
+ // The cycle error here should be reported as an error by `check_representable`.
+ // We consider the type as Sized in the meanwhile to avoid
+ // further errors (done in impl Value for AdtSizedConstraint).
+ // Use `cycle_delay_bug` to delay the cycle error here to be emitted later
+ // in case we accidentally otherwise don't emit an error.
+ query adt_sized_constraint(
+ key: DefId
+ ) -> AdtSizedConstraint<'tcx> {
+ desc { |tcx| "computing `Sized` constraints for `{}`", tcx.def_path_str(key) }
+ cycle_delay_bug
+ }
+
+ query adt_dtorck_constraint(
+ key: DefId
+ ) -> Result<DtorckConstraint<'tcx>, NoSolution> {
+ desc { |tcx| "computing drop-check constraints for `{}`", tcx.def_path_str(key) }
+ }
+
+ /// Returns `true` if this is a const fn, use the `is_const_fn` to know whether your crate
+ /// actually sees it as const fn (e.g., the const-fn-ness might be unstable and you might
+ /// not have the feature gate active).
+ ///
+ /// **Do not call this function manually.** It is only meant to cache the base data for the
+ /// `is_const_fn` function.
+ query is_const_fn_raw(key: DefId) -> bool {
+ desc { |tcx| "checking if item is const fn: `{}`", tcx.def_path_str(key) }
+ }
+
+ /// Returns `true` if this is a const `impl`. **Do not call this function manually.**
+ ///
+ /// This query caches the base data for the `is_const_impl` helper function, which also
+ /// takes into account stability attributes (e.g., `#[rustc_const_unstable]`).
+ query is_const_impl_raw(key: DefId) -> bool {
+ desc { |tcx| "checking if item is const impl: `{}`", tcx.def_path_str(key) }
+ }
+
+ query asyncness(key: DefId) -> hir::IsAsync {
+ desc { |tcx| "checking if the function is async: `{}`", tcx.def_path_str(key) }
+ }
+
+ /// Returns `true` if calls to the function may be promoted.
+ ///
+ /// This is either because the function is e.g., a tuple-struct or tuple-variant
+ /// constructor, or because it has the `#[rustc_promotable]` attribute. The attribute should
+ /// be removed in the future in favour of some form of check which figures out whether the
+ /// function does not inspect the bits of any of its arguments (so is essentially just a
+ /// constructor function).
+ query is_promotable_const_fn(key: DefId) -> bool {
+ desc { |tcx| "checking if item is promotable: `{}`", tcx.def_path_str(key) }
+ }
+
+ /// Returns `true` if this is a foreign item (i.e., linked via `extern { ... }`).
+ query is_foreign_item(key: DefId) -> bool {
+ desc { |tcx| "checking if `{}` is a foreign item", tcx.def_path_str(key) }
+ }
+
+ /// Returns `Some(mutability)` if the node pointed to by `def_id` is a static item.
+ query static_mutability(def_id: DefId) -> Option<hir::Mutability> {
+ desc { |tcx| "looking up static mutability of `{}`", tcx.def_path_str(def_id) }
+ }
+
+ /// Returns `Some(generator_kind)` if the node pointed to by `def_id` is a generator.
+ query generator_kind(def_id: DefId) -> Option<hir::GeneratorKind> {
+ desc { |tcx| "looking up generator kind of `{}`", tcx.def_path_str(def_id) }
+ }
+
+ /// Gets a map with the variance of every item; use `item_variance` instead.
+ query crate_variances(_: CrateNum) -> ty::CrateVariancesMap<'tcx> {
+ storage(ArenaCacheSelector<'tcx>)
+ desc { "computing the variances for items in this crate" }
+ }
+
+ /// Maps from the `DefId` of a type or region parameter to its (inferred) variance.
+ query variances_of(def_id: DefId) -> &'tcx [ty::Variance] {
+ desc { |tcx| "computing the variances of `{}`", tcx.def_path_str(def_id) }
+ }
+
+ /// Maps from thee `DefId` of a type to its (inferred) outlives.
+ query inferred_outlives_crate(_: CrateNum)
+ -> ty::CratePredicatesMap<'tcx> {
+ storage(ArenaCacheSelector<'tcx>)
+ desc { "computing the inferred outlives predicates for items in this crate" }
+ }
+
+ /// Maps from an impl/trait `DefId to a list of the `DefId`s of its items.
+ query associated_item_def_ids(key: DefId) -> &'tcx [DefId] {
+ desc { |tcx| "collecting associated items of `{}`", tcx.def_path_str(key) }
+ }
+
+ /// Maps from a trait item to the trait item "descriptor".
+ query associated_item(key: DefId) -> ty::AssocItem {
+ desc { |tcx| "computing associated item data for `{}`", tcx.def_path_str(key) }
+ storage(ArenaCacheSelector<'tcx>)
+ }
+
+ /// Collects the associated items defined on a trait or impl.
+ query associated_items(key: DefId) -> ty::AssociatedItems<'tcx> {
+ storage(ArenaCacheSelector<'tcx>)
+ desc { |tcx| "collecting associated items of {}", tcx.def_path_str(key) }
+ }
+
+ /// 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>> {
+ desc { |tcx| "computing trait implemented by `{}`", tcx.def_path_str(impl_id) }
+ }
+ query impl_polarity(impl_id: DefId) -> ty::ImplPolarity {
+ desc { |tcx| "computing implementation polarity of `{}`", tcx.def_path_str(impl_id) }
+ }
+
+ query issue33140_self_ty(key: DefId) -> Option<ty::Ty<'tcx>> {
+ desc { |tcx| "computing Self type wrt issue #33140 `{}`", tcx.def_path_str(key) }
+ }
+
+ /// Maps a `DefId` of a type to a list of its inherent impls.
+ /// Contains implementations of methods that are inherent to a type.
+ /// Methods in these implementations don't need to be exported.
+ query inherent_impls(key: DefId) -> &'tcx [DefId] {
+ desc { |tcx| "collecting inherent impls for `{}`", tcx.def_path_str(key) }
+ eval_always
+ }
+
+ /// The result of unsafety-checking this `LocalDefId`.
+ query unsafety_check_result(key: LocalDefId) -> &'tcx mir::UnsafetyCheckResult {
+ desc { |tcx| "unsafety-checking `{}`", tcx.def_path_str(key.to_def_id()) }
+ cache_on_disk_if { true }
+ }
+ query unsafety_check_result_for_const_arg(key: (LocalDefId, DefId)) -> &'tcx mir::UnsafetyCheckResult {
+ desc {
+ |tcx| "unsafety-checking the const argument `{}`",
+ tcx.def_path_str(key.0.to_def_id())
}
}
- Other {
- /// Maps from an impl/trait `DefId to a list of the `DefId`s of its items.
- query associated_item_def_ids(key: DefId) -> &'tcx [DefId] {
- desc { |tcx| "collecting associated items of `{}`", tcx.def_path_str(key) }
+ /// HACK: when evaluated, this reports a "unsafe derive on repr(packed)" error.
+ ///
+ /// Unsafety checking is executed for each method separately, but we only want
+ /// to emit this error once per derive. As there are some impls with multiple
+ /// methods, we use a query for deduplication.
+ query unsafe_derive_on_repr_packed(key: LocalDefId) -> () {
+ desc { |tcx| "processing `{}`", tcx.def_path_str(key.to_def_id()) }
+ }
+
+ /// The signature of functions.
+ query fn_sig(key: DefId) -> ty::PolyFnSig<'tcx> {
+ desc { |tcx| "computing function signature of `{}`", tcx.def_path_str(key) }
+ }
+
+ query lint_mod(key: LocalDefId) -> () {
+ desc { |tcx| "linting {}", describe_as_module(key, tcx) }
+ }
+
+ /// Checks the attributes in the module.
+ query check_mod_attrs(key: LocalDefId) -> () {
+ desc { |tcx| "checking attributes in {}", describe_as_module(key, tcx) }
+ }
+
+ query check_mod_unstable_api_usage(key: LocalDefId) -> () {
+ desc { |tcx| "checking for unstable API usage in {}", describe_as_module(key, tcx) }
+ }
+
+ /// Checks the const bodies in the module for illegal operations (e.g. `if` or `loop`).
+ query check_mod_const_bodies(key: LocalDefId) -> () {
+ desc { |tcx| "checking consts in {}", describe_as_module(key, tcx) }
+ }
+
+ /// Checks the loops in the module.
+ query check_mod_loops(key: LocalDefId) -> () {
+ desc { |tcx| "checking loops in {}", describe_as_module(key, tcx) }
+ }
+
+ query check_mod_naked_functions(key: LocalDefId) -> () {
+ desc { |tcx| "checking naked functions in {}", describe_as_module(key, tcx) }
+ }
+
+ query check_mod_item_types(key: LocalDefId) -> () {
+ desc { |tcx| "checking item types in {}", describe_as_module(key, tcx) }
+ }
+
+ query check_mod_privacy(key: LocalDefId) -> () {
+ desc { |tcx| "checking privacy in {}", describe_as_module(key, tcx) }
+ }
+
+ query check_mod_intrinsics(key: LocalDefId) -> () {
+ desc { |tcx| "checking intrinsics in {}", describe_as_module(key, tcx) }
+ }
+
+ query check_mod_liveness(key: LocalDefId) -> () {
+ desc { |tcx| "checking liveness of variables in {}", describe_as_module(key, tcx) }
+ }
+
+ query check_mod_impl_wf(key: LocalDefId) -> () {
+ desc { |tcx| "checking that impls are well-formed in {}", describe_as_module(key, tcx) }
+ }
+
+ query collect_mod_item_types(key: LocalDefId) -> () {
+ desc { |tcx| "collecting item types in {}", describe_as_module(key, tcx) }
+ }
+
+ /// Caches `CoerceUnsized` kinds for impls on custom types.
+ query coerce_unsized_info(key: DefId)
+ -> ty::adjustment::CoerceUnsizedInfo {
+ desc { |tcx| "computing CoerceUnsized info for `{}`", tcx.def_path_str(key) }
}
- /// Maps from a trait item to the trait item "descriptor".
- query associated_item(key: DefId) -> ty::AssocItem {
- desc { |tcx| "computing associated item data for `{}`", tcx.def_path_str(key) }
- storage(ArenaCacheSelector<'tcx>)
- }
+ query typeck_item_bodies(_: CrateNum) -> () {
+ desc { "type-checking all item bodies" }
+ }
- /// Collects the associated items defined on a trait or impl.
- query associated_items(key: DefId) -> ty::AssociatedItems<'tcx> {
- storage(ArenaCacheSelector<'tcx>)
- desc { |tcx| "collecting associated items of {}", tcx.def_path_str(key) }
+ query typeck(key: LocalDefId) -> &'tcx ty::TypeckResults<'tcx> {
+ desc { |tcx| "type-checking `{}`", tcx.def_path_str(key.to_def_id()) }
+ cache_on_disk_if { true }
+ }
+ query typeck_const_arg(
+ key: (LocalDefId, DefId)
+ ) -> &'tcx ty::TypeckResults<'tcx> {
+ desc {
+ |tcx| "type-checking the const argument `{}`",
+ tcx.def_path_str(key.0.to_def_id()),
}
+ }
+ query diagnostic_only_typeck(key: LocalDefId) -> &'tcx ty::TypeckResults<'tcx> {
+ desc { |tcx| "type-checking `{}`", tcx.def_path_str(key.to_def_id()) }
+ cache_on_disk_if { true }
+ load_cached(tcx, id) {
+ let typeck_results: Option<ty::TypeckResults<'tcx>> = tcx
+ .queries.on_disk_cache.as_ref()
+ .and_then(|c| c.try_load_query_result(tcx, id));
- query impl_trait_ref(key: DefId) -> Option<ty::TraitRef<'tcx>> {
- desc { |tcx| "computing trait implemented by `{}`", tcx.def_path_str(key) }
- }
- query impl_polarity(key: DefId) -> ty::ImplPolarity {
- desc { |tcx| "computing implementation polarity of `{}`", tcx.def_path_str(key) }
- }
-
- query issue33140_self_ty(key: DefId) -> Option<ty::Ty<'tcx>> {
- desc { |tcx| "computing Self type wrt issue #33140 `{}`", tcx.def_path_str(key) }
+ typeck_results.map(|x| &*tcx.arena.alloc(x))
}
}
- TypeChecking {
- /// Maps a `DefId` of a type to a list of its inherent impls.
- /// Contains implementations of methods that are inherent to a type.
- /// Methods in these implementations don't need to be exported.
- query inherent_impls(key: DefId) -> &'tcx [DefId] {
- desc { |tcx| "collecting inherent impls for `{}`", tcx.def_path_str(key) }
- eval_always
+ query used_trait_imports(key: LocalDefId) -> &'tcx FxHashSet<LocalDefId> {
+ desc { |tcx| "used_trait_imports `{}`", tcx.def_path_str(key.to_def_id()) }
+ cache_on_disk_if { true }
+ }
+
+ query has_typeck_results(def_id: DefId) -> bool {
+ desc { |tcx| "checking whether `{}` has a body", tcx.def_path_str(def_id) }
+ }
+
+ query coherent_trait(def_id: DefId) -> () {
+ desc { |tcx| "coherence checking all impls of trait `{}`", tcx.def_path_str(def_id) }
+ }
+
+ /// Borrow-checks the function body. If this is a closure, returns
+ /// additional requirements that the closure's creator must verify.
+ query mir_borrowck(key: LocalDefId) -> &'tcx mir::BorrowCheckResult<'tcx> {
+ desc { |tcx| "borrow-checking `{}`", tcx.def_path_str(key.to_def_id()) }
+ cache_on_disk_if(tcx, opt_result) {
+ tcx.is_closure(key.to_def_id())
+ || opt_result.map_or(false, |r| !r.concrete_opaque_types.is_empty())
+ }
+ }
+ query mir_borrowck_const_arg(key: (LocalDefId, DefId)) -> &'tcx mir::BorrowCheckResult<'tcx> {
+ desc {
+ |tcx| "borrow-checking the const argument`{}`",
+ tcx.def_path_str(key.0.to_def_id())
}
}
- TypeChecking {
- /// The result of unsafety-checking this `LocalDefId`.
- query unsafety_check_result(key: LocalDefId) -> &'tcx mir::UnsafetyCheckResult {
- desc { |tcx| "unsafety-checking `{}`", tcx.def_path_str(key.to_def_id()) }
- cache_on_disk_if { true }
- }
- query unsafety_check_result_for_const_arg(key: (LocalDefId, DefId)) -> &'tcx mir::UnsafetyCheckResult {
- desc {
- |tcx| "unsafety-checking the const argument `{}`",
- tcx.def_path_str(key.0.to_def_id())
- }
- }
+ /// Gets a complete map from all types to their inherent impls.
+ /// Not meant to be used directly outside of coherence.
+ /// (Defined only for `LOCAL_CRATE`.)
+ query crate_inherent_impls(k: CrateNum)
+ -> CrateInherentImpls {
+ storage(ArenaCacheSelector<'tcx>)
+ eval_always
+ desc { "all inherent impls defined in crate `{:?}`", k }
+ }
- /// HACK: when evaluated, this reports a "unsafe derive on repr(packed)" error.
- ///
- /// Unsafety checking is executed for each method separately, but we only want
- /// to emit this error once per derive. As there are some impls with multiple
- /// methods, we use a query for deduplication.
- query unsafe_derive_on_repr_packed(key: LocalDefId) -> () {
- desc { |tcx| "processing `{}`", tcx.def_path_str(key.to_def_id()) }
- }
+ /// Checks all types in the crate for overlap in their inherent impls. Reports errors.
+ /// Not meant to be used directly outside of coherence.
+ /// (Defined only for `LOCAL_CRATE`.)
+ query crate_inherent_impls_overlap_check(_: CrateNum)
+ -> () {
+ eval_always
+ desc { "check for overlap between inherent impls defined in this crate" }
+ }
- /// The signature of functions.
- query fn_sig(key: DefId) -> ty::PolyFnSig<'tcx> {
- desc { |tcx| "computing function signature of `{}`", tcx.def_path_str(key) }
+ /// Check whether the function has any recursion that could cause the inliner to trigger
+ /// a cycle. Returns the call stack causing the cycle. The call stack does not contain the
+ /// current function, just all intermediate functions.
+ query mir_callgraph_reachable(key: (ty::Instance<'tcx>, LocalDefId)) -> bool {
+ fatal_cycle
+ desc { |tcx|
+ "computing if `{}` (transitively) calls `{}`",
+ key.0,
+ tcx.def_path_str(key.1.to_def_id()),
}
}
- Other {
- query lint_mod(key: LocalDefId) -> () {
- desc { |tcx| "linting {}", describe_as_module(key, tcx) }
- }
-
- /// Checks the attributes in the module.
- query check_mod_attrs(key: LocalDefId) -> () {
- desc { |tcx| "checking attributes in {}", describe_as_module(key, tcx) }
- }
-
- query check_mod_unstable_api_usage(key: LocalDefId) -> () {
- desc { |tcx| "checking for unstable API usage in {}", describe_as_module(key, tcx) }
- }
-
- /// Checks the const bodies in the module for illegal operations (e.g. `if` or `loop`).
- query check_mod_const_bodies(key: LocalDefId) -> () {
- desc { |tcx| "checking consts in {}", describe_as_module(key, tcx) }
- }
-
- /// Checks the loops in the module.
- query check_mod_loops(key: LocalDefId) -> () {
- desc { |tcx| "checking loops in {}", describe_as_module(key, tcx) }
- }
-
- query check_mod_naked_functions(key: LocalDefId) -> () {
- desc { |tcx| "checking naked functions in {}", describe_as_module(key, tcx) }
- }
-
- query check_mod_item_types(key: LocalDefId) -> () {
- desc { |tcx| "checking item types in {}", describe_as_module(key, tcx) }
- }
-
- query check_mod_privacy(key: LocalDefId) -> () {
- desc { |tcx| "checking privacy in {}", describe_as_module(key, tcx) }
- }
-
- query check_mod_intrinsics(key: LocalDefId) -> () {
- desc { |tcx| "checking intrinsics in {}", describe_as_module(key, tcx) }
- }
-
- query check_mod_liveness(key: LocalDefId) -> () {
- desc { |tcx| "checking liveness of variables in {}", describe_as_module(key, tcx) }
- }
-
- query check_mod_impl_wf(key: LocalDefId) -> () {
- desc { |tcx| "checking that impls are well-formed in {}", describe_as_module(key, tcx) }
- }
-
- query collect_mod_item_types(key: LocalDefId) -> () {
- desc { |tcx| "collecting item types in {}", describe_as_module(key, tcx) }
- }
-
- /// Caches `CoerceUnsized` kinds for impls on custom types.
- query coerce_unsized_info(key: DefId)
- -> ty::adjustment::CoerceUnsizedInfo {
- desc { |tcx| "computing CoerceUnsized info for `{}`", tcx.def_path_str(key) }
- }
- }
-
- TypeChecking {
- query typeck_item_bodies(_: CrateNum) -> () {
- desc { "type-checking all item bodies" }
- }
-
- query typeck(key: LocalDefId) -> &'tcx ty::TypeckResults<'tcx> {
- desc { |tcx| "type-checking `{}`", tcx.def_path_str(key.to_def_id()) }
- cache_on_disk_if { true }
- }
- query typeck_const_arg(
- key: (LocalDefId, DefId)
- ) -> &'tcx ty::TypeckResults<'tcx> {
- desc {
- |tcx| "type-checking the const argument `{}`",
- tcx.def_path_str(key.0.to_def_id()),
- }
- }
- query diagnostic_only_typeck(key: LocalDefId) -> &'tcx ty::TypeckResults<'tcx> {
- desc { |tcx| "type-checking `{}`", tcx.def_path_str(key.to_def_id()) }
- cache_on_disk_if { true }
- load_cached(tcx, id) {
- let typeck_results: Option<ty::TypeckResults<'tcx>> = tcx
- .queries.on_disk_cache.as_ref()
- .and_then(|c| c.try_load_query_result(tcx, id));
-
- typeck_results.map(|x| &*tcx.arena.alloc(x))
- }
+ /// Obtain all the calls into other local functions
+ query mir_inliner_callees(key: ty::InstanceDef<'tcx>) -> &'tcx [(DefId, SubstsRef<'tcx>)] {
+ fatal_cycle
+ desc { |tcx|
+ "computing all local function calls in `{}`",
+ tcx.def_path_str(key.def_id()),
}
}
- Other {
- query used_trait_imports(key: LocalDefId) -> &'tcx FxHashSet<LocalDefId> {
- desc { |tcx| "used_trait_imports `{}`", tcx.def_path_str(key.to_def_id()) }
- cache_on_disk_if { true }
+ /// Evaluates a constant and returns the computed allocation.
+ ///
+ /// **Do not use this** directly, use the `tcx.eval_static_initializer` wrapper.
+ query eval_to_allocation_raw(key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>)
+ -> EvalToAllocationRawResult<'tcx> {
+ desc { |tcx|
+ "const-evaluating + checking `{}`",
+ key.value.display(tcx)
+ }
+ cache_on_disk_if { true }
+ }
+
+ /// Evaluates const items or anonymous constants
+ /// (such as enum variant explicit discriminants or array lengths)
+ /// into a representation suitable for the type system and const generics.
+ ///
+ /// **Do not use this** directly, use one of the following wrappers: `tcx.const_eval_poly`,
+ /// `tcx.const_eval_resolve`, `tcx.const_eval_instance`, or `tcx.const_eval_global_id`.
+ query eval_to_const_value_raw(key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>)
+ -> EvalToConstValueResult<'tcx> {
+ desc { |tcx|
+ "simplifying constant for the type system `{}`",
+ key.value.display(tcx)
+ }
+ cache_on_disk_if { true }
+ }
+
+ /// Destructure a constant ADT or array into its variant index and its
+ /// field values.
+ query destructure_const(
+ key: ty::ParamEnvAnd<'tcx, &'tcx ty::Const<'tcx>>
+ ) -> mir::DestructuredConst<'tcx> {
+ desc { "destructure constant" }
+ }
+
+ /// Dereference a constant reference or raw pointer and turn the result into a constant
+ /// again.
+ query deref_const(
+ key: ty::ParamEnvAnd<'tcx, &'tcx ty::Const<'tcx>>
+ ) -> &'tcx ty::Const<'tcx> {
+ desc { "deref constant" }
+ }
+
+ query const_caller_location(key: (rustc_span::Symbol, u32, u32)) -> ConstValue<'tcx> {
+ desc { "get a &core::panic::Location referring to a span" }
+ }
+
+ query lit_to_const(
+ key: LitToConstInput<'tcx>
+ ) -> Result<&'tcx ty::Const<'tcx>, LitToConstError> {
+ desc { "converting literal to const" }
+ }
+
+ query check_match(key: DefId) {
+ desc { |tcx| "match-checking `{}`", tcx.def_path_str(key) }
+ cache_on_disk_if { key.is_local() }
+ }
+
+ /// Performs part of the privacy check and computes "access levels".
+ query privacy_access_levels(_: CrateNum) -> &'tcx AccessLevels {
+ eval_always
+ desc { "privacy access levels" }
+ }
+ query check_private_in_public(_: CrateNum) -> () {
+ eval_always
+ desc { "checking for private elements in public interfaces" }
+ }
+
+ query reachable_set(_: CrateNum) -> FxHashSet<LocalDefId> {
+ storage(ArenaCacheSelector<'tcx>)
+ desc { "reachability" }
+ }
+
+ /// Per-body `region::ScopeTree`. The `DefId` should be the owner `DefId` for the body;
+ /// in the case of closures, this will be redirected to the enclosing function.
+ query region_scope_tree(def_id: DefId) -> &'tcx region::ScopeTree {
+ desc { |tcx| "computing drop scopes for `{}`", tcx.def_path_str(def_id) }
+ }
+
+ query mir_shims(key: ty::InstanceDef<'tcx>) -> mir::Body<'tcx> {
+ storage(ArenaCacheSelector<'tcx>)
+ desc { |tcx| "generating MIR shim for `{}`", tcx.def_path_str(key.def_id()) }
+ }
+
+ /// The `symbol_name` query provides the symbol name for calling a
+ /// given instance from the local crate. In particular, it will also
+ /// look up the correct symbol name of instances from upstream crates.
+ query symbol_name(key: ty::Instance<'tcx>) -> ty::SymbolName<'tcx> {
+ desc { "computing the symbol for `{}`", key }
+ cache_on_disk_if { true }
+ }
+
+ query opt_def_kind(def_id: DefId) -> Option<DefKind> {
+ desc { |tcx| "looking up definition kind of `{}`", tcx.def_path_str(def_id) }
+ }
+
+ query def_span(def_id: DefId) -> Span {
+ desc { |tcx| "looking up span for `{}`", tcx.def_path_str(def_id) }
+ // FIXME(mw): DefSpans are not really inputs since they are derived from
+ // HIR. But at the moment HIR hashing still contains some hacks that allow
+ // to make type debuginfo to be source location independent. Declaring
+ // DefSpan an input makes sure that changes to these are always detected
+ // regardless of HIR hashing.
+ eval_always
+ }
+
+ query def_ident_span(def_id: DefId) -> Option<Span> {
+ desc { |tcx| "looking up span for `{}`'s identifier", tcx.def_path_str(def_id) }
+ }
+
+ query lookup_stability(def_id: DefId) -> Option<&'tcx attr::Stability> {
+ desc { |tcx| "looking up stability of `{}`", tcx.def_path_str(def_id) }
+ }
+
+ query lookup_const_stability(def_id: DefId) -> Option<&'tcx attr::ConstStability> {
+ desc { |tcx| "looking up const stability of `{}`", tcx.def_path_str(def_id) }
+ }
+
+ query lookup_deprecation_entry(def_id: DefId) -> Option<DeprecationEntry> {
+ desc { |tcx| "checking whether `{}` is deprecated", tcx.def_path_str(def_id) }
+ }
+
+ query item_attrs(def_id: DefId) -> &'tcx [ast::Attribute] {
+ desc { |tcx| "collecting attributes of `{}`", tcx.def_path_str(def_id) }
+ }
+
+ query codegen_fn_attrs(def_id: DefId) -> CodegenFnAttrs {
+ desc { |tcx| "computing codegen attributes of `{}`", tcx.def_path_str(def_id) }
+ storage(ArenaCacheSelector<'tcx>)
+ cache_on_disk_if { true }
+ }
+
+ query fn_arg_names(def_id: DefId) -> &'tcx [rustc_span::symbol::Ident] {
+ desc { |tcx| "looking up function parameter names for `{}`", tcx.def_path_str(def_id) }
+ }
+ /// Gets the rendered value of the specified constant or associated constant.
+ /// Used by rustdoc.
+ query rendered_const(def_id: DefId) -> String {
+ desc { |tcx| "rendering constant intializer of `{}`", tcx.def_path_str(def_id) }
+ }
+ query impl_parent(def_id: DefId) -> Option<DefId> {
+ desc { |tcx| "computing specialization parent impl of `{}`", tcx.def_path_str(def_id) }
+ }
+
+ /// Given an `associated_item`, find the trait it belongs to.
+ /// Return `None` if the `DefId` is not an associated item.
+ query trait_of_item(associated_item: DefId) -> Option<DefId> {
+ desc { |tcx| "finding trait defining `{}`", tcx.def_path_str(associated_item) }
+ }
+
+ query is_ctfe_mir_available(key: DefId) -> bool {
+ desc { |tcx| "checking if item has ctfe mir available: `{}`", tcx.def_path_str(key) }
+ }
+ query is_mir_available(key: DefId) -> bool {
+ desc { |tcx| "checking if item has mir available: `{}`", tcx.def_path_str(key) }
+ }
+
+ query vtable_methods(key: ty::PolyTraitRef<'tcx>)
+ -> &'tcx [Option<(DefId, SubstsRef<'tcx>)>] {
+ desc { |tcx| "finding all methods for trait {}", tcx.def_path_str(key.def_id()) }
+ }
+
+ query codegen_fulfill_obligation(
+ key: (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>)
+ ) -> Result<ImplSource<'tcx, ()>, ErrorReported> {
+ cache_on_disk_if { true }
+ desc { |tcx|
+ "checking if `{}` fulfills its obligations",
+ tcx.def_path_str(key.1.def_id())
}
}
- TypeChecking {
- query has_typeck_results(def_id: DefId) -> bool {
- desc { |tcx| "checking whether `{}` has a body", tcx.def_path_str(def_id) }
- }
+ /// Return all `impl` blocks in the current crate.
+ ///
+ /// To allow caching this between crates, you must pass in [`LOCAL_CRATE`] as the crate number.
+ /// Passing in any other crate will cause an ICE.
+ ///
+ /// [`LOCAL_CRATE`]: rustc_hir::def_id::LOCAL_CRATE
+ query all_local_trait_impls(local_crate: CrateNum) -> &'tcx BTreeMap<DefId, Vec<hir::HirId>> {
+ desc { "local trait impls" }
+ }
- query coherent_trait(def_id: DefId) -> () {
- desc { |tcx| "coherence checking all impls of trait `{}`", tcx.def_path_str(def_id) }
+ /// Given a trait `trait_id`, return all known `impl` blocks.
+ query trait_impls_of(trait_id: DefId) -> ty::trait_def::TraitImpls {
+ storage(ArenaCacheSelector<'tcx>)
+ desc { |tcx| "trait impls of `{}`", tcx.def_path_str(trait_id) }
+ }
+
+ query specialization_graph_of(trait_id: DefId) -> specialization_graph::Graph {
+ storage(ArenaCacheSelector<'tcx>)
+ desc { |tcx| "building specialization graph of trait `{}`", tcx.def_path_str(trait_id) }
+ cache_on_disk_if { true }
+ }
+ query object_safety_violations(trait_id: DefId) -> &'tcx [traits::ObjectSafetyViolation] {
+ desc { |tcx| "determine object safety of trait `{}`", tcx.def_path_str(trait_id) }
+ }
+
+ /// Gets the ParameterEnvironment for a given item; this environment
+ /// will be in "user-facing" mode, meaning that it is suitable for
+ /// type-checking etc, and it does not normalize specializable
+ /// associated types. This is almost always what you want,
+ /// unless you are doing MIR optimizations, in which case you
+ /// might want to use `reveal_all()` method to change modes.
+ query param_env(def_id: DefId) -> ty::ParamEnv<'tcx> {
+ desc { |tcx| "computing normalized predicates of `{}`", tcx.def_path_str(def_id) }
+ }
+
+ /// Like `param_env`, but returns the `ParamEnv in `Reveal::All` mode.
+ /// Prefer this over `tcx.param_env(def_id).with_reveal_all_normalized(tcx)`,
+ /// as this method is more efficient.
+ query param_env_reveal_all_normalized(def_id: DefId) -> ty::ParamEnv<'tcx> {
+ desc { |tcx| "computing revealed normalized predicates of `{}`", tcx.def_path_str(def_id) }
+ }
+
+ /// Trait selection queries. These are best used by invoking `ty.is_copy_modulo_regions()`,
+ /// `ty.is_copy()`, etc, since that will prune the environment where possible.
+ query is_copy_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
+ desc { "computing whether `{}` is `Copy`", env.value }
+ }
+ /// Query backing `TyS::is_sized`.
+ query is_sized_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
+ desc { "computing whether `{}` is `Sized`", env.value }
+ }
+ /// Query backing `TyS::is_freeze`.
+ query is_freeze_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
+ desc { "computing whether `{}` is freeze", env.value }
+ }
+ /// Query backing `TyS::needs_drop`.
+ query needs_drop_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
+ desc { "computing whether `{}` needs drop", env.value }
+ }
+
+ /// Query backing `TyS::is_structural_eq_shallow`.
+ ///
+ /// This is only correct for ADTs. Call `is_structural_eq_shallow` to handle all types
+ /// correctly.
+ query has_structural_eq_impls(ty: Ty<'tcx>) -> bool {
+ desc {
+ "computing whether `{:?}` implements `PartialStructuralEq` and `StructuralEq`",
+ ty
}
}
- BorrowChecking {
- /// Borrow-checks the function body. If this is a closure, returns
- /// additional requirements that the closure's creator must verify.
- query mir_borrowck(key: LocalDefId) -> &'tcx mir::BorrowCheckResult<'tcx> {
- desc { |tcx| "borrow-checking `{}`", tcx.def_path_str(key.to_def_id()) }
- cache_on_disk_if(tcx, opt_result) {
- tcx.is_closure(key.to_def_id())
- || opt_result.map_or(false, |r| !r.concrete_opaque_types.is_empty())
- }
- }
- query mir_borrowck_const_arg(key: (LocalDefId, DefId)) -> &'tcx mir::BorrowCheckResult<'tcx> {
- desc {
- |tcx| "borrow-checking the const argument`{}`",
- tcx.def_path_str(key.0.to_def_id())
- }
+ /// A list of types where the ADT requires drop if and only if any of
+ /// those types require drop. If the ADT is known to always need drop
+ /// then `Err(AlwaysRequiresDrop)` is returned.
+ query adt_drop_tys(def_id: DefId) -> Result<&'tcx ty::List<Ty<'tcx>>, AlwaysRequiresDrop> {
+ desc { |tcx| "computing when `{}` needs drop", tcx.def_path_str(def_id) }
+ cache_on_disk_if { true }
+ }
+
+ query layout_raw(
+ env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>
+ ) -> Result<&'tcx rustc_target::abi::Layout, ty::layout::LayoutError<'tcx>> {
+ desc { "computing layout of `{}`", env.value }
+ }
+
+ query dylib_dependency_formats(_: CrateNum)
+ -> &'tcx [(CrateNum, LinkagePreference)] {
+ desc { "dylib dependency formats of crate" }
+ }
+
+ query dependency_formats(_: CrateNum)
+ -> Lrc<crate::middle::dependency_format::Dependencies>
+ {
+ desc { "get the linkage format of all dependencies" }
+ }
+
+ query is_compiler_builtins(_: CrateNum) -> bool {
+ fatal_cycle
+ desc { "checking if the crate is_compiler_builtins" }
+ }
+ query has_global_allocator(_: CrateNum) -> bool {
+ fatal_cycle
+ desc { "checking if the crate has_global_allocator" }
+ }
+ query has_panic_handler(_: CrateNum) -> bool {
+ fatal_cycle
+ desc { "checking if the crate has_panic_handler" }
+ }
+ query is_profiler_runtime(_: CrateNum) -> bool {
+ fatal_cycle
+ desc { "query a crate is `#![profiler_runtime]`" }
+ }
+ query panic_strategy(_: CrateNum) -> PanicStrategy {
+ fatal_cycle
+ desc { "query a crate's configured panic strategy" }
+ }
+ query is_no_builtins(_: CrateNum) -> bool {
+ fatal_cycle
+ desc { "test whether a crate has `#![no_builtins]`" }
+ }
+ query symbol_mangling_version(_: CrateNum) -> SymbolManglingVersion {
+ fatal_cycle
+ desc { "query a crate's symbol mangling version" }
+ }
+
+ query extern_crate(def_id: DefId) -> Option<&'tcx ExternCrate> {
+ eval_always
+ desc { "getting crate's ExternCrateData" }
+ }
+
+ query specializes(_: (DefId, DefId)) -> bool {
+ desc { "computing whether impls specialize one another" }
+ }
+ query in_scope_traits_map(_: LocalDefId)
+ -> Option<&'tcx FxHashMap<ItemLocalId, StableVec<TraitCandidate>>> {
+ eval_always
+ desc { "traits in scope at a block" }
+ }
+
+ query module_exports(def_id: LocalDefId) -> Option<&'tcx [Export<LocalDefId>]> {
+ desc { |tcx| "looking up items exported by `{}`", tcx.def_path_str(def_id.to_def_id()) }
+ eval_always
+ }
+
+ query impl_defaultness(def_id: DefId) -> hir::Defaultness {
+ desc { |tcx| "looking up whether `{}` is a default impl", tcx.def_path_str(def_id) }
+ }
+
+ query check_item_well_formed(key: LocalDefId) -> () {
+ desc { |tcx| "checking that `{}` is well-formed", tcx.def_path_str(key.to_def_id()) }
+ }
+ query check_trait_item_well_formed(key: LocalDefId) -> () {
+ desc { |tcx| "checking that `{}` is well-formed", tcx.def_path_str(key.to_def_id()) }
+ }
+ query check_impl_item_well_formed(key: LocalDefId) -> () {
+ desc { |tcx| "checking that `{}` is well-formed", tcx.def_path_str(key.to_def_id()) }
+ }
+
+ // The `DefId`s of all non-generic functions and statics in the given crate
+ // that can be reached from outside the crate.
+ //
+ // We expect this items to be available for being linked to.
+ //
+ // This query can also be called for `LOCAL_CRATE`. In this case it will
+ // compute which items will be reachable to other crates, taking into account
+ // the kind of crate that is currently compiled. Crates with only a
+ // C interface have fewer reachable things.
+ //
+ // Does not include external symbols that don't have a corresponding DefId,
+ // like the compiler-generated `main` function and so on.
+ query reachable_non_generics(_: CrateNum)
+ -> DefIdMap<SymbolExportLevel> {
+ storage(ArenaCacheSelector<'tcx>)
+ desc { "looking up the exported symbols of a crate" }
+ }
+ query is_reachable_non_generic(def_id: DefId) -> bool {
+ desc { |tcx| "checking whether `{}` is an exported symbol", tcx.def_path_str(def_id) }
+ }
+ query is_unreachable_local_definition(def_id: DefId) -> bool {
+ desc { |tcx|
+ "checking whether `{}` is reachable from outside the crate",
+ tcx.def_path_str(def_id),
}
}
- TypeChecking {
- /// Gets a complete map from all types to their inherent impls.
- /// Not meant to be used directly outside of coherence.
- /// (Defined only for `LOCAL_CRATE`.)
- query crate_inherent_impls(k: CrateNum)
- -> CrateInherentImpls {
- storage(ArenaCacheSelector<'tcx>)
- eval_always
- desc { "all inherent impls defined in crate `{:?}`", k }
- }
-
- /// Checks all types in the crate for overlap in their inherent impls. Reports errors.
- /// Not meant to be used directly outside of coherence.
- /// (Defined only for `LOCAL_CRATE`.)
- query crate_inherent_impls_overlap_check(_: CrateNum)
- -> () {
- eval_always
- desc { "check for overlap between inherent impls defined in this crate" }
- }
+ /// The entire set of monomorphizations the local crate can safely link
+ /// to because they are exported from upstream crates. Do not depend on
+ /// this directly, as its value changes anytime a monomorphization gets
+ /// added or removed in any upstream crate. Instead use the narrower
+ /// `upstream_monomorphizations_for`, `upstream_drop_glue_for`, or, even
+ /// better, `Instance::upstream_monomorphization()`.
+ query upstream_monomorphizations(
+ k: CrateNum
+ ) -> DefIdMap<FxHashMap<SubstsRef<'tcx>, CrateNum>> {
+ storage(ArenaCacheSelector<'tcx>)
+ desc { "collecting available upstream monomorphizations `{:?}`", k }
}
- Other {
- /// Evaluates a constant and returns the computed allocation.
- ///
- /// **Do not use this** directly, use the `tcx.eval_static_initializer` wrapper.
- query eval_to_allocation_raw(key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>)
- -> EvalToAllocationRawResult<'tcx> {
+ /// Returns the set of upstream monomorphizations available for the
+ /// generic function identified by the given `def_id`. The query makes
+ /// sure to make a stable selection if the same monomorphization is
+ /// available in multiple upstream crates.
+ ///
+ /// You likely want to call `Instance::upstream_monomorphization()`
+ /// instead of invoking this query directly.
+ query upstream_monomorphizations_for(def_id: DefId)
+ -> Option<&'tcx FxHashMap<SubstsRef<'tcx>, CrateNum>> {
desc { |tcx|
- "const-evaluating + checking `{}`",
- key.value.display(tcx)
- }
- cache_on_disk_if { true }
- }
-
- /// Evaluates const items or anonymous constants
- /// (such as enum variant explicit discriminants or array lengths)
- /// into a representation suitable for the type system and const generics.
- ///
- /// **Do not use this** directly, use one of the following wrappers: `tcx.const_eval_poly`,
- /// `tcx.const_eval_resolve`, `tcx.const_eval_instance`, or `tcx.const_eval_global_id`.
- query eval_to_const_value_raw(key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>)
- -> EvalToConstValueResult<'tcx> {
- desc { |tcx|
- "simplifying constant for the type system `{}`",
- key.value.display(tcx)
- }
- cache_on_disk_if { true }
- }
-
- /// Destructure a constant ADT or array into its variant index and its
- /// field values.
- query destructure_const(
- key: ty::ParamEnvAnd<'tcx, &'tcx ty::Const<'tcx>>
- ) -> mir::DestructuredConst<'tcx> {
- desc { "destructure constant" }
- }
-
- /// Dereference a constant reference or raw pointer and turn the result into a constant
- /// again.
- query deref_const(
- key: ty::ParamEnvAnd<'tcx, &'tcx ty::Const<'tcx>>
- ) -> &'tcx ty::Const<'tcx> {
- desc { "deref constant" }
- }
-
- query const_caller_location(key: (rustc_span::Symbol, u32, u32)) -> ConstValue<'tcx> {
- desc { "get a &core::panic::Location referring to a span" }
- }
-
- query lit_to_const(
- key: LitToConstInput<'tcx>
- ) -> Result<&'tcx ty::Const<'tcx>, LitToConstError> {
- desc { "converting literal to const" }
- }
- }
-
- TypeChecking {
- query check_match(key: DefId) {
- desc { |tcx| "match-checking `{}`", tcx.def_path_str(key) }
- cache_on_disk_if { key.is_local() }
- }
-
- /// Performs part of the privacy check and computes "access levels".
- query privacy_access_levels(_: CrateNum) -> &'tcx AccessLevels {
- eval_always
- desc { "privacy access levels" }
- }
- query check_private_in_public(_: CrateNum) -> () {
- eval_always
- desc { "checking for private elements in public interfaces" }
- }
- }
-
- Other {
- query reachable_set(_: CrateNum) -> FxHashSet<LocalDefId> {
- storage(ArenaCacheSelector<'tcx>)
- desc { "reachability" }
- }
-
- /// Per-body `region::ScopeTree`. The `DefId` should be the owner `DefId` for the body;
- /// in the case of closures, this will be redirected to the enclosing function.
- query region_scope_tree(def_id: DefId) -> &'tcx region::ScopeTree {
- desc { |tcx| "computing drop scopes for `{}`", tcx.def_path_str(def_id) }
- }
-
- query mir_shims(key: ty::InstanceDef<'tcx>) -> mir::Body<'tcx> {
- storage(ArenaCacheSelector<'tcx>)
- desc { |tcx| "generating MIR shim for `{}`", tcx.def_path_str(key.def_id()) }
- }
-
- /// The `symbol_name` query provides the symbol name for calling a
- /// given instance from the local crate. In particular, it will also
- /// look up the correct symbol name of instances from upstream crates.
- query symbol_name(key: ty::Instance<'tcx>) -> ty::SymbolName<'tcx> {
- desc { "computing the symbol for `{}`", key }
- cache_on_disk_if { true }
- }
-
- query def_kind(def_id: DefId) -> DefKind {
- desc { |tcx| "looking up definition kind of `{}`", tcx.def_path_str(def_id) }
- }
- query def_span(def_id: DefId) -> Span {
- desc { |tcx| "looking up span for `{}`", tcx.def_path_str(def_id) }
- // FIXME(mw): DefSpans are not really inputs since they are derived from
- // HIR. But at the moment HIR hashing still contains some hacks that allow
- // to make type debuginfo to be source location independent. Declaring
- // DefSpan an input makes sure that changes to these are always detected
- // regardless of HIR hashing.
- eval_always
- }
- query lookup_stability(def_id: DefId) -> Option<&'tcx attr::Stability> {
- desc { |tcx| "looking up stability of `{}`", tcx.def_path_str(def_id) }
- }
- query lookup_const_stability(def_id: DefId) -> Option<&'tcx attr::ConstStability> {
- desc { |tcx| "looking up const stability of `{}`", tcx.def_path_str(def_id) }
- }
- query lookup_deprecation_entry(def_id: DefId) -> Option<DeprecationEntry> {
- desc { |tcx| "checking whether `{}` is deprecated", tcx.def_path_str(def_id) }
- }
- query item_attrs(def_id: DefId) -> &'tcx [ast::Attribute] {
- desc { |tcx| "collecting attributes of `{}`", tcx.def_path_str(def_id) }
- }
- }
-
- Codegen {
- query codegen_fn_attrs(def_id: DefId) -> CodegenFnAttrs {
- desc { |tcx| "computing codegen attributes of `{}`", tcx.def_path_str(def_id) }
- storage(ArenaCacheSelector<'tcx>)
- cache_on_disk_if { true }
- }
- }
-
- Other {
- query fn_arg_names(def_id: DefId) -> &'tcx [rustc_span::symbol::Ident] {
- desc { |tcx| "looking up function parameter names for `{}`", tcx.def_path_str(def_id) }
- }
- /// Gets the rendered value of the specified constant or associated constant.
- /// Used by rustdoc.
- query rendered_const(def_id: DefId) -> String {
- desc { |tcx| "rendering constant intializer of `{}`", tcx.def_path_str(def_id) }
- }
- query impl_parent(def_id: DefId) -> Option<DefId> {
- desc { |tcx| "computing specialization parent impl of `{}`", tcx.def_path_str(def_id) }
- }
- }
-
- TypeChecking {
- query trait_of_item(def_id: DefId) -> Option<DefId> {
- desc { |tcx| "finding trait defining `{}`", tcx.def_path_str(def_id) }
- }
- }
-
- Codegen {
- query is_mir_available(key: DefId) -> bool {
- desc { |tcx| "checking if item has mir available: `{}`", tcx.def_path_str(key) }
- }
- }
-
- Other {
- query vtable_methods(key: ty::PolyTraitRef<'tcx>)
- -> &'tcx [Option<(DefId, SubstsRef<'tcx>)>] {
- desc { |tcx| "finding all methods for trait {}", tcx.def_path_str(key.def_id()) }
- }
- }
-
- Codegen {
- query codegen_fulfill_obligation(
- key: (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>)
- ) -> Result<ImplSource<'tcx, ()>, ErrorReported> {
- cache_on_disk_if { true }
- desc { |tcx|
- "checking if `{}` fulfills its obligations",
- tcx.def_path_str(key.1.def_id())
- }
- }
- }
-
- TypeChecking {
- query all_local_trait_impls(key: CrateNum) -> &'tcx BTreeMap<DefId, Vec<hir::HirId>> {
- desc { "local trait impls" }
- }
- query trait_impls_of(key: DefId) -> ty::trait_def::TraitImpls {
- storage(ArenaCacheSelector<'tcx>)
- desc { |tcx| "trait impls of `{}`", tcx.def_path_str(key) }
- }
- query specialization_graph_of(key: DefId) -> specialization_graph::Graph {
- storage(ArenaCacheSelector<'tcx>)
- desc { |tcx| "building specialization graph of trait `{}`", tcx.def_path_str(key) }
- cache_on_disk_if { true }
- }
- query object_safety_violations(key: DefId) -> &'tcx [traits::ObjectSafetyViolation] {
- desc { |tcx| "determine object safety of trait `{}`", tcx.def_path_str(key) }
- }
-
- /// Gets the ParameterEnvironment for a given item; this environment
- /// will be in "user-facing" mode, meaning that it is suitable for
- /// type-checking etc, and it does not normalize specializable
- /// associated types. This is almost always what you want,
- /// unless you are doing MIR optimizations, in which case you
- query param_env(def_id: DefId) -> ty::ParamEnv<'tcx> {
- desc { |tcx| "computing normalized predicates of `{}`", tcx.def_path_str(def_id) }
- }
-
- /// Like `param_env`, but returns the `ParamEnv in `Reveal::All` mode.
- /// Prefer this over `tcx.param_env(def_id).with_reveal_all_normalized(tcx)`,
- /// as this method is more efficient.
- query param_env_reveal_all_normalized(def_id: DefId) -> ty::ParamEnv<'tcx> {
- desc { |tcx| "computing revealed normalized predicates of `{}`", tcx.def_path_str(def_id) }
- }
-
- /// Trait selection queries. These are best used by invoking `ty.is_copy_modulo_regions()`,
- /// `ty.is_copy()`, etc, since that will prune the environment where possible.
- query is_copy_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
- desc { "computing whether `{}` is `Copy`", env.value }
- }
- /// Query backing `TyS::is_sized`.
- query is_sized_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
- desc { "computing whether `{}` is `Sized`", env.value }
- }
- /// Query backing `TyS::is_freeze`.
- query is_freeze_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
- desc { "computing whether `{}` is freeze", env.value }
- }
- /// Query backing `TyS::needs_drop`.
- query needs_drop_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
- desc { "computing whether `{}` needs drop", env.value }
- }
-
- /// Query backing `TyS::is_structural_eq_shallow`.
- ///
- /// This is only correct for ADTs. Call `is_structural_eq_shallow` to handle all types
- /// correctly.
- query has_structural_eq_impls(ty: Ty<'tcx>) -> bool {
- desc {
- "computing whether `{:?}` implements `PartialStructuralEq` and `StructuralEq`",
- ty
- }
- }
-
- /// A list of types where the ADT requires drop if and only if any of
- /// those types require drop. If the ADT is known to always need drop
- /// then `Err(AlwaysRequiresDrop)` is returned.
- query adt_drop_tys(def_id: DefId) -> Result<&'tcx ty::List<Ty<'tcx>>, AlwaysRequiresDrop> {
- desc { |tcx| "computing when `{}` needs drop", tcx.def_path_str(def_id) }
- cache_on_disk_if { true }
- }
-
- query layout_raw(
- env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>
- ) -> Result<&'tcx rustc_target::abi::Layout, ty::layout::LayoutError<'tcx>> {
- desc { "computing layout of `{}`", env.value }
- }
- }
-
- Other {
- query dylib_dependency_formats(_: CrateNum)
- -> &'tcx [(CrateNum, LinkagePreference)] {
- desc { "dylib dependency formats of crate" }
- }
-
- query dependency_formats(_: CrateNum)
- -> Lrc<crate::middle::dependency_format::Dependencies>
- {
- desc { "get the linkage format of all dependencies" }
- }
- }
-
- Codegen {
- query is_compiler_builtins(_: CrateNum) -> bool {
- fatal_cycle
- desc { "checking if the crate is_compiler_builtins" }
- }
- query has_global_allocator(_: CrateNum) -> bool {
- fatal_cycle
- desc { "checking if the crate has_global_allocator" }
- }
- query has_panic_handler(_: CrateNum) -> bool {
- fatal_cycle
- desc { "checking if the crate has_panic_handler" }
- }
- query is_profiler_runtime(_: CrateNum) -> bool {
- fatal_cycle
- desc { "query a crate is `#![profiler_runtime]`" }
- }
- query panic_strategy(_: CrateNum) -> PanicStrategy {
- fatal_cycle
- desc { "query a crate's configured panic strategy" }
- }
- query is_no_builtins(_: CrateNum) -> bool {
- fatal_cycle
- desc { "test whether a crate has `#![no_builtins]`" }
- }
- query symbol_mangling_version(_: CrateNum) -> SymbolManglingVersion {
- fatal_cycle
- desc { "query a crate's symbol mangling version" }
- }
-
- query extern_crate(def_id: DefId) -> Option<&'tcx ExternCrate> {
- eval_always
- desc { "getting crate's ExternCrateData" }
- }
- }
-
- TypeChecking {
- query specializes(_: (DefId, DefId)) -> bool {
- desc { "computing whether impls specialize one another" }
- }
- query in_scope_traits_map(_: LocalDefId)
- -> Option<&'tcx FxHashMap<ItemLocalId, StableVec<TraitCandidate>>> {
- eval_always
- desc { "traits in scope at a block" }
- }
- }
-
- Other {
- query module_exports(def_id: LocalDefId) -> Option<&'tcx [Export<LocalDefId>]> {
- desc { |tcx| "looking up items exported by `{}`", tcx.def_path_str(def_id.to_def_id()) }
- eval_always
- }
- }
-
- TypeChecking {
- query impl_defaultness(def_id: DefId) -> hir::Defaultness {
- desc { |tcx| "looking up whether `{}` is a default impl", tcx.def_path_str(def_id) }
- }
-
- query check_item_well_formed(key: LocalDefId) -> () {
- desc { |tcx| "checking that `{}` is well-formed", tcx.def_path_str(key.to_def_id()) }
- }
- query check_trait_item_well_formed(key: LocalDefId) -> () {
- desc { |tcx| "checking that `{}` is well-formed", tcx.def_path_str(key.to_def_id()) }
- }
- query check_impl_item_well_formed(key: LocalDefId) -> () {
- desc { |tcx| "checking that `{}` is well-formed", tcx.def_path_str(key.to_def_id()) }
- }
- }
-
-
- Linking {
- // The `DefId`s of all non-generic functions and statics in the given crate
- // that can be reached from outside the crate.
- //
- // We expect this items to be available for being linked to.
- //
- // This query can also be called for `LOCAL_CRATE`. In this case it will
- // compute which items will be reachable to other crates, taking into account
- // the kind of crate that is currently compiled. Crates with only a
- // C interface have fewer reachable things.
- //
- // Does not include external symbols that don't have a corresponding DefId,
- // like the compiler-generated `main` function and so on.
- query reachable_non_generics(_: CrateNum)
- -> DefIdMap<SymbolExportLevel> {
- storage(ArenaCacheSelector<'tcx>)
- desc { "looking up the exported symbols of a crate" }
- }
- query is_reachable_non_generic(def_id: DefId) -> bool {
- desc { |tcx| "checking whether `{}` is an exported symbol", tcx.def_path_str(def_id) }
- }
- query is_unreachable_local_definition(def_id: DefId) -> bool {
- desc { |tcx|
- "checking whether `{}` is reachable from outside the crate",
+ "collecting available upstream monomorphizations for `{}`",
tcx.def_path_str(def_id),
}
}
+
+ /// Returns the upstream crate that exports drop-glue for the given
+ /// type (`substs` is expected to be a single-item list containing the
+ /// type one wants drop-glue for).
+ ///
+ /// This is a subset of `upstream_monomorphizations_for` in order to
+ /// increase dep-tracking granularity. Otherwise adding or removing any
+ /// type with drop-glue in any upstream crate would invalidate all
+ /// functions calling drop-glue of an upstream type.
+ ///
+ /// You likely want to call `Instance::upstream_monomorphization()`
+ /// instead of invoking this query directly.
+ ///
+ /// NOTE: This query could easily be extended to also support other
+ /// common functions that have are large set of monomorphizations
+ /// (like `Clone::clone` for example).
+ query upstream_drop_glue_for(substs: SubstsRef<'tcx>) -> Option<CrateNum> {
+ desc { "available upstream drop-glue for `{:?}`", substs }
}
- Codegen {
- /// The entire set of monomorphizations the local crate can safely link
- /// to because they are exported from upstream crates. Do not depend on
- /// this directly, as its value changes anytime a monomorphization gets
- /// added or removed in any upstream crate. Instead use the narrower
- /// `upstream_monomorphizations_for`, `upstream_drop_glue_for`, or, even
- /// better, `Instance::upstream_monomorphization()`.
- query upstream_monomorphizations(
- k: CrateNum
- ) -> DefIdMap<FxHashMap<SubstsRef<'tcx>, CrateNum>> {
- storage(ArenaCacheSelector<'tcx>)
- desc { "collecting available upstream monomorphizations `{:?}`", k }
+ query foreign_modules(_: CrateNum) -> Lrc<FxHashMap<DefId, ForeignModule>> {
+ desc { "looking up the foreign modules of a linked crate" }
+ }
+
+ /// Identifies the entry-point (e.g., the `main` function) for a given
+ /// crate, returning `None` if there is no entry point (such as for library crates).
+ query entry_fn(_: CrateNum) -> Option<(LocalDefId, EntryFnType)> {
+ desc { "looking up the entry function of a crate" }
+ }
+ query plugin_registrar_fn(_: CrateNum) -> Option<DefId> {
+ desc { "looking up the plugin registrar for a crate" }
+ }
+ query proc_macro_decls_static(_: CrateNum) -> Option<DefId> {
+ desc { "looking up the derive registrar for a crate" }
+ }
+ query crate_disambiguator(_: CrateNum) -> CrateDisambiguator {
+ eval_always
+ desc { "looking up the disambiguator a crate" }
+ }
+ // The macro which defines `rustc_metadata::provide_extern` depends on this query's name.
+ // Changing the name should cause a compiler error, but in case that changes, be aware.
+ query crate_hash(_: CrateNum) -> Svh {
+ eval_always
+ desc { "looking up the hash a crate" }
+ }
+ query crate_host_hash(_: CrateNum) -> Option<Svh> {
+ eval_always
+ desc { "looking up the hash of a host version of a crate" }
+ }
+ query original_crate_name(_: CrateNum) -> Symbol {
+ eval_always
+ desc { "looking up the original name a crate" }
+ }
+ query extra_filename(_: CrateNum) -> String {
+ eval_always
+ desc { "looking up the extra filename for a crate" }
+ }
+ query crate_extern_paths(_: CrateNum) -> Vec<PathBuf> {
+ eval_always
+ desc { "looking up the paths for extern crates" }
+ }
+
+ /// 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>)] {
+ desc { "looking up implementations of a trait in a crate" }
+ }
+
+ /// 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>)] {
+ desc { "looking up all (?) trait implementations" }
+ }
+
+ query is_dllimport_foreign_item(def_id: DefId) -> bool {
+ desc { |tcx| "is_dllimport_foreign_item({})", tcx.def_path_str(def_id) }
+ }
+ query is_statically_included_foreign_item(def_id: DefId) -> bool {
+ desc { |tcx| "is_statically_included_foreign_item({})", tcx.def_path_str(def_id) }
+ }
+ query native_library_kind(def_id: DefId)
+ -> Option<NativeLibKind> {
+ desc { |tcx| "native_library_kind({})", tcx.def_path_str(def_id) }
+ }
+
+ query link_args(_: CrateNum) -> Lrc<Vec<String>> {
+ eval_always
+ desc { "looking up link arguments for a crate" }
+ }
+
+ /// Lifetime resolution. See `middle::resolve_lifetimes`.
+ query resolve_lifetimes(_: CrateNum) -> ResolveLifetimes {
+ storage(ArenaCacheSelector<'tcx>)
+ desc { "resolving lifetimes" }
+ }
+ query named_region_map(_: LocalDefId) ->
+ Option<&'tcx FxHashMap<ItemLocalId, Region>> {
+ desc { "looking up a named region" }
+ }
+ query is_late_bound_map(_: LocalDefId) ->
+ Option<(LocalDefId, &'tcx FxHashSet<ItemLocalId>)> {
+ desc { "testing if a region is late bound" }
+ }
+ query object_lifetime_defaults_map(_: LocalDefId)
+ -> Option<&'tcx FxHashMap<ItemLocalId, Vec<ObjectLifetimeDefault>>> {
+ desc { "looking up lifetime defaults for a region" }
+ }
+
+ query visibility(def_id: DefId) -> ty::Visibility {
+ eval_always
+ desc { |tcx| "computing visibility of `{}`", tcx.def_path_str(def_id) }
+ }
+
+ /// Computes the set of modules from which this type is visibly uninhabited.
+ /// To check whether a type is uninhabited at all (not just from a given module), you could
+ /// check whether the forest is empty.
+ query type_uninhabited_from(
+ key: ty::ParamEnvAnd<'tcx, Ty<'tcx>>
+ ) -> ty::inhabitedness::DefIdForest {
+ desc { "computing the inhabitedness of `{:?}`", key }
+ }
+
+ query dep_kind(_: CrateNum) -> CrateDepKind {
+ eval_always
+ desc { "fetching what a dependency looks like" }
+ }
+ query crate_name(_: CrateNum) -> Symbol {
+ eval_always
+ desc { "fetching what a crate is named" }
+ }
+ query item_children(def_id: DefId) -> &'tcx [Export<hir::HirId>] {
+ desc { |tcx| "collecting child items of `{}`", tcx.def_path_str(def_id) }
+ }
+ query extern_mod_stmt_cnum(def_id: LocalDefId) -> Option<CrateNum> {
+ desc { |tcx| "computing crate imported by `{}`", tcx.def_path_str(def_id.to_def_id()) }
+ }
+
+ query get_lib_features(_: CrateNum) -> LibFeatures {
+ storage(ArenaCacheSelector<'tcx>)
+ eval_always
+ desc { "calculating the lib features map" }
+ }
+ query defined_lib_features(_: CrateNum)
+ -> &'tcx [(Symbol, Option<Symbol>)] {
+ desc { "calculating the lib features defined in a crate" }
+ }
+ /// Returns the lang items defined in another crate by loading it from metadata.
+ // FIXME: It is illegal to pass a `CrateNum` other than `LOCAL_CRATE` here, just get rid
+ // of that argument?
+ query get_lang_items(_: CrateNum) -> LanguageItems {
+ storage(ArenaCacheSelector<'tcx>)
+ eval_always
+ desc { "calculating the lang items map" }
+ }
+
+ /// Returns all diagnostic items defined in all crates.
+ query all_diagnostic_items(_: CrateNum) -> FxHashMap<Symbol, DefId> {
+ storage(ArenaCacheSelector<'tcx>)
+ eval_always
+ desc { "calculating the diagnostic items map" }
+ }
+
+ /// Returns the lang items defined in another crate by loading it from metadata.
+ query defined_lang_items(_: CrateNum) -> &'tcx [(DefId, usize)] {
+ desc { "calculating the lang items defined in a crate" }
+ }
+
+ /// Returns the diagnostic items defined in a crate.
+ query diagnostic_items(_: CrateNum) -> FxHashMap<Symbol, DefId> {
+ storage(ArenaCacheSelector<'tcx>)
+ desc { "calculating the diagnostic items map in a crate" }
+ }
+
+ query missing_lang_items(_: CrateNum) -> &'tcx [LangItem] {
+ desc { "calculating the missing lang items in a crate" }
+ }
+ query visible_parent_map(_: CrateNum)
+ -> DefIdMap<DefId> {
+ storage(ArenaCacheSelector<'tcx>)
+ desc { "calculating the visible parent map" }
+ }
+ query trimmed_def_paths(_: CrateNum)
+ -> FxHashMap<DefId, Symbol> {
+ storage(ArenaCacheSelector<'tcx>)
+ desc { "calculating trimmed def paths" }
+ }
+ query missing_extern_crate_item(_: CrateNum) -> bool {
+ eval_always
+ desc { "seeing if we're missing an `extern crate` item for this crate" }
+ }
+ query used_crate_source(_: CrateNum) -> Lrc<CrateSource> {
+ eval_always
+ desc { "looking at the source for a crate" }
+ }
+ query postorder_cnums(_: CrateNum) -> &'tcx [CrateNum] {
+ eval_always
+ desc { "generating a postorder list of CrateNums" }
+ }
+
+ query upvars_mentioned(def_id: DefId) -> Option<&'tcx FxIndexMap<hir::HirId, hir::Upvar>> {
+ desc { |tcx| "collecting upvars mentioned in `{}`", tcx.def_path_str(def_id) }
+ eval_always
+ }
+ query maybe_unused_trait_import(def_id: LocalDefId) -> bool {
+ eval_always
+ desc { |tcx| "maybe_unused_trait_import for `{}`", tcx.def_path_str(def_id.to_def_id()) }
+ }
+ query maybe_unused_extern_crates(_: CrateNum)
+ -> &'tcx [(LocalDefId, Span)] {
+ eval_always
+ desc { "looking up all possibly unused extern crates" }
+ }
+ query names_imported_by_glob_use(def_id: LocalDefId)
+ -> &'tcx FxHashSet<Symbol> {
+ eval_always
+ desc { |tcx| "names_imported_by_glob_use for `{}`", tcx.def_path_str(def_id.to_def_id()) }
+ }
+
+ query stability_index(_: CrateNum) -> stability::Index<'tcx> {
+ storage(ArenaCacheSelector<'tcx>)
+ eval_always
+ desc { "calculating the stability index for the local crate" }
+ }
+ query all_crate_nums(_: CrateNum) -> &'tcx [CrateNum] {
+ eval_always
+ 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(_: CrateNum) -> &'tcx [DefId] {
+ desc { "fetching all foreign and local traits" }
+ }
+
+ /// The list of symbols exported from the given crate.
+ ///
+ /// - All names contained in `exported_symbols(cnum)` are guaranteed to
+ /// correspond to a publicly visible symbol in `cnum` machine code.
+ /// - The `exported_symbols` sets of different crates do not intersect.
+ query exported_symbols(_: CrateNum)
+ -> &'tcx [(ExportedSymbol<'tcx>, SymbolExportLevel)] {
+ desc { "exported_symbols" }
+ }
+
+ query collect_and_partition_mono_items(_: CrateNum)
+ -> (&'tcx DefIdSet, &'tcx [CodegenUnit<'tcx>]) {
+ eval_always
+ desc { "collect_and_partition_mono_items" }
+ }
+ query is_codegened_item(def_id: DefId) -> bool {
+ desc { |tcx| "determining whether `{}` needs codegen", tcx.def_path_str(def_id) }
+ }
+ query codegen_unit(_: Symbol) -> &'tcx CodegenUnit<'tcx> {
+ desc { "codegen_unit" }
+ }
+ query unused_generic_params(key: DefId) -> FiniteBitSet<u32> {
+ cache_on_disk_if { key.is_local() }
+ desc {
+ |tcx| "determining which generic parameters are unused by `{}`",
+ tcx.def_path_str(key)
}
+ }
+ query backend_optimization_level(_: CrateNum) -> OptLevel {
+ desc { "optimization level used by backend" }
+ }
- /// Returns the set of upstream monomorphizations available for the
- /// generic function identified by the given `def_id`. The query makes
- /// sure to make a stable selection if the same monomorphization is
- /// available in multiple upstream crates.
- ///
- /// You likely want to call `Instance::upstream_monomorphization()`
- /// instead of invoking this query directly.
- query upstream_monomorphizations_for(def_id: DefId)
- -> Option<&'tcx FxHashMap<SubstsRef<'tcx>, CrateNum>> {
- desc { |tcx|
- "collecting available upstream monomorphizations for `{}`",
- tcx.def_path_str(def_id),
- }
- }
+ query output_filenames(_: CrateNum) -> Arc<OutputFilenames> {
+ eval_always
+ desc { "output_filenames" }
+ }
- /// Returns the upstream crate that exports drop-glue for the given
- /// type (`substs` is expected to be a single-item list containing the
- /// type one wants drop-glue for).
- ///
- /// This is a subset of `upstream_monomorphizations_for` in order to
- /// increase dep-tracking granularity. Otherwise adding or removing any
- /// type with drop-glue in any upstream crate would invalidate all
- /// functions calling drop-glue of an upstream type.
- ///
- /// You likely want to call `Instance::upstream_monomorphization()`
- /// instead of invoking this query directly.
- ///
- /// NOTE: This query could easily be extended to also support other
- /// common functions that have are large set of monomorphizations
- /// (like `Clone::clone` for example).
- query upstream_drop_glue_for(substs: SubstsRef<'tcx>) -> Option<CrateNum> {
- desc { "available upstream drop-glue for `{:?}`", substs }
+ /// Do not call this query directly: invoke `normalize` instead.
+ query normalize_projection_ty(
+ goal: CanonicalProjectionGoal<'tcx>
+ ) -> Result<
+ &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, NormalizationResult<'tcx>>>,
+ NoSolution,
+ > {
+ desc { "normalizing `{:?}`", goal }
+ }
+
+ /// Do not call this query directly: invoke `normalize_erasing_regions` instead.
+ query normalize_generic_arg_after_erasing_regions(
+ goal: ParamEnvAnd<'tcx, GenericArg<'tcx>>
+ ) -> GenericArg<'tcx> {
+ desc { "normalizing `{}`", goal.value }
+ }
+
+ query implied_outlives_bounds(
+ goal: CanonicalTyGoal<'tcx>
+ ) -> Result<
+ &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, Vec<OutlivesBound<'tcx>>>>,
+ NoSolution,
+ > {
+ desc { "computing implied outlives bounds for `{:?}`", goal }
+ }
+
+ /// Do not call this query directly: invoke `infcx.at().dropck_outlives()` instead.
+ query dropck_outlives(
+ goal: CanonicalTyGoal<'tcx>
+ ) -> Result<
+ &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, DropckOutlivesResult<'tcx>>>,
+ NoSolution,
+ > {
+ desc { "computing dropck types for `{:?}`", goal }
+ }
+
+ /// Do not call this query directly: invoke `infcx.predicate_may_hold()` or
+ /// `infcx.predicate_must_hold()` instead.
+ query evaluate_obligation(
+ goal: CanonicalPredicateGoal<'tcx>
+ ) -> Result<traits::EvaluationResult, traits::OverflowError> {
+ desc { "evaluating trait selection obligation `{}`", goal.value.value }
+ }
+
+ query evaluate_goal(
+ goal: traits::CanonicalChalkEnvironmentAndGoal<'tcx>
+ ) -> Result<
+ &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, ()>>,
+ NoSolution
+ > {
+ desc { "evaluating trait selection obligation `{}`", goal.value }
+ }
+
+ query type_implements_trait(
+ key: (DefId, Ty<'tcx>, SubstsRef<'tcx>, ty::ParamEnv<'tcx>, )
+ ) -> bool {
+ desc { "evaluating `type_implements_trait` `{:?}`", key }
+ }
+
+ /// Do not call this query directly: part of the `Eq` type-op
+ query type_op_ascribe_user_type(
+ goal: CanonicalTypeOpAscribeUserTypeGoal<'tcx>
+ ) -> Result<
+ &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, ()>>,
+ NoSolution,
+ > {
+ desc { "evaluating `type_op_ascribe_user_type` `{:?}`", goal }
+ }
+
+ /// Do not call this query directly: part of the `Eq` type-op
+ query type_op_eq(
+ goal: CanonicalTypeOpEqGoal<'tcx>
+ ) -> Result<
+ &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, ()>>,
+ NoSolution,
+ > {
+ desc { "evaluating `type_op_eq` `{:?}`", goal }
+ }
+
+ /// Do not call this query directly: part of the `Subtype` type-op
+ query type_op_subtype(
+ goal: CanonicalTypeOpSubtypeGoal<'tcx>
+ ) -> Result<
+ &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, ()>>,
+ NoSolution,
+ > {
+ desc { "evaluating `type_op_subtype` `{:?}`", goal }
+ }
+
+ /// Do not call this query directly: part of the `ProvePredicate` type-op
+ query type_op_prove_predicate(
+ goal: CanonicalTypeOpProvePredicateGoal<'tcx>
+ ) -> Result<
+ &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, ()>>,
+ NoSolution,
+ > {
+ desc { "evaluating `type_op_prove_predicate` `{:?}`", goal }
+ }
+
+ /// Do not call this query directly: part of the `Normalize` type-op
+ query type_op_normalize_ty(
+ goal: CanonicalTypeOpNormalizeGoal<'tcx, Ty<'tcx>>
+ ) -> Result<
+ &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, Ty<'tcx>>>,
+ NoSolution,
+ > {
+ desc { "normalizing `{:?}`", goal }
+ }
+
+ /// Do not call this query directly: part of the `Normalize` type-op
+ query type_op_normalize_predicate(
+ goal: CanonicalTypeOpNormalizeGoal<'tcx, ty::Predicate<'tcx>>
+ ) -> Result<
+ &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, ty::Predicate<'tcx>>>,
+ NoSolution,
+ > {
+ desc { "normalizing `{:?}`", goal }
+ }
+
+ /// Do not call this query directly: part of the `Normalize` type-op
+ query type_op_normalize_poly_fn_sig(
+ goal: CanonicalTypeOpNormalizeGoal<'tcx, ty::PolyFnSig<'tcx>>
+ ) -> Result<
+ &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, ty::PolyFnSig<'tcx>>>,
+ NoSolution,
+ > {
+ desc { "normalizing `{:?}`", goal }
+ }
+
+ /// Do not call this query directly: part of the `Normalize` type-op
+ query type_op_normalize_fn_sig(
+ goal: CanonicalTypeOpNormalizeGoal<'tcx, ty::FnSig<'tcx>>
+ ) -> Result<
+ &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, ty::FnSig<'tcx>>>,
+ NoSolution,
+ > {
+ desc { "normalizing `{:?}`", goal }
+ }
+
+ query subst_and_check_impossible_predicates(key: (DefId, SubstsRef<'tcx>)) -> bool {
+ desc { |tcx|
+ "impossible substituted predicates:`{}`",
+ tcx.def_path_str(key.0)
}
}
- Other {
- query foreign_modules(_: CrateNum) -> Lrc<FxHashMap<DefId, ForeignModule>> {
- desc { "looking up the foreign modules of a linked crate" }
- }
+ query method_autoderef_steps(
+ goal: CanonicalTyGoal<'tcx>
+ ) -> MethodAutoderefStepsResult<'tcx> {
+ desc { "computing autoderef types for `{:?}`", goal }
+ }
- /// Identifies the entry-point (e.g., the `main` function) for a given
- /// crate, returning `None` if there is no entry point (such as for library crates).
- query entry_fn(_: CrateNum) -> Option<(LocalDefId, EntryFnType)> {
- desc { "looking up the entry function of a crate" }
- }
- query plugin_registrar_fn(_: CrateNum) -> Option<DefId> {
- desc { "looking up the plugin registrar for a crate" }
- }
- query proc_macro_decls_static(_: CrateNum) -> Option<DefId> {
- desc { "looking up the derive registrar for a crate" }
- }
- query crate_disambiguator(_: CrateNum) -> CrateDisambiguator {
- eval_always
- desc { "looking up the disambiguator a crate" }
- }
- query crate_hash(_: CrateNum) -> Svh {
- eval_always
- desc { "looking up the hash a crate" }
- }
- query crate_host_hash(_: CrateNum) -> Option<Svh> {
- eval_always
- desc { "looking up the hash of a host version of a crate" }
- }
- query original_crate_name(_: CrateNum) -> Symbol {
- eval_always
- desc { "looking up the original name a crate" }
- }
- query extra_filename(_: CrateNum) -> String {
- eval_always
- desc { "looking up the extra filename for a crate" }
- }
- query crate_extern_paths(_: CrateNum) -> Vec<PathBuf> {
- eval_always
- desc { "looking up the paths for extern crates" }
+ query supported_target_features(_: CrateNum) -> FxHashMap<String, Option<Symbol>> {
+ storage(ArenaCacheSelector<'tcx>)
+ eval_always
+ desc { "looking up supported target features" }
+ }
+
+ /// Get an estimate of the size of an InstanceDef based on its MIR for CGU partitioning.
+ query instance_def_size_estimate(def: ty::InstanceDef<'tcx>)
+ -> usize {
+ desc { |tcx| "estimating size for `{}`", tcx.def_path_str(def.def_id()) }
+ }
+
+ query features_query(_: CrateNum) -> &'tcx rustc_feature::Features {
+ eval_always
+ desc { "looking up enabled feature gates" }
+ }
+
+ /// Attempt to resolve the given `DefId` to an `Instance`, for the
+ /// given generics args (`SubstsRef`), returning one of:
+ /// * `Ok(Some(instance))` on success
+ /// * `Ok(None)` when the `SubstsRef` are still too generic,
+ /// and therefore don't allow finding the final `Instance`
+ /// * `Err(ErrorReported)` when the `Instance` resolution process
+ /// couldn't complete due to errors elsewhere - this is distinct
+ /// from `Ok(None)` to avoid misleading diagnostics when an error
+ /// has already been/will be emitted, for the original cause
+ query resolve_instance(
+ key: ty::ParamEnvAnd<'tcx, (DefId, SubstsRef<'tcx>)>
+ ) -> Result<Option<ty::Instance<'tcx>>, ErrorReported> {
+ desc { "resolving instance `{}`", ty::Instance::new(key.value.0, key.value.1) }
+ }
+
+ query resolve_instance_of_const_arg(
+ key: ty::ParamEnvAnd<'tcx, (LocalDefId, DefId, SubstsRef<'tcx>)>
+ ) -> Result<Option<ty::Instance<'tcx>>, ErrorReported> {
+ desc {
+ "resolving instance of the const argument `{}`",
+ ty::Instance::new(key.value.0.to_def_id(), key.value.2),
}
}
- TypeChecking {
- query implementations_of_trait(_: (CrateNum, DefId))
- -> &'tcx [(DefId, Option<ty::fast_reject::SimplifiedType>)] {
- desc { "looking up implementations of a trait in a crate" }
- }
- query all_trait_implementations(_: CrateNum)
- -> &'tcx [(DefId, Option<ty::fast_reject::SimplifiedType>)] {
- desc { "looking up all (?) trait implementations" }
- }
- }
-
- Other {
- query dllimport_foreign_items(_: CrateNum)
- -> FxHashSet<DefId> {
- storage(ArenaCacheSelector<'tcx>)
- desc { "dllimport_foreign_items" }
- }
- query is_dllimport_foreign_item(def_id: DefId) -> bool {
- desc { |tcx| "is_dllimport_foreign_item({})", tcx.def_path_str(def_id) }
- }
- query is_statically_included_foreign_item(def_id: DefId) -> bool {
- desc { |tcx| "is_statically_included_foreign_item({})", tcx.def_path_str(def_id) }
- }
- query native_library_kind(def_id: DefId)
- -> Option<NativeLibKind> {
- desc { |tcx| "native_library_kind({})", tcx.def_path_str(def_id) }
- }
- }
-
- Linking {
- query link_args(_: CrateNum) -> Lrc<Vec<String>> {
- eval_always
- desc { "looking up link arguments for a crate" }
- }
- }
-
- BorrowChecking {
- /// Lifetime resolution. See `middle::resolve_lifetimes`.
- query resolve_lifetimes(_: CrateNum) -> ResolveLifetimes {
- storage(ArenaCacheSelector<'tcx>)
- desc { "resolving lifetimes" }
- }
- query named_region_map(_: LocalDefId) ->
- Option<&'tcx FxHashMap<ItemLocalId, Region>> {
- desc { "looking up a named region" }
- }
- query is_late_bound_map(_: LocalDefId) ->
- Option<&'tcx FxHashSet<ItemLocalId>> {
- desc { "testing if a region is late bound" }
- }
- query object_lifetime_defaults_map(_: LocalDefId)
- -> Option<&'tcx FxHashMap<ItemLocalId, Vec<ObjectLifetimeDefault>>> {
- desc { "looking up lifetime defaults for a region" }
- }
- }
-
- TypeChecking {
- query visibility(def_id: DefId) -> ty::Visibility {
- eval_always
- desc { |tcx| "computing visibility of `{}`", tcx.def_path_str(def_id) }
- }
- }
-
- Other {
- query dep_kind(_: CrateNum) -> CrateDepKind {
- eval_always
- desc { "fetching what a dependency looks like" }
- }
- query crate_name(_: CrateNum) -> Symbol {
- eval_always
- desc { "fetching what a crate is named" }
- }
- query item_children(def_id: DefId) -> &'tcx [Export<hir::HirId>] {
- desc { |tcx| "collecting child items of `{}`", tcx.def_path_str(def_id) }
- }
- query extern_mod_stmt_cnum(def_id: LocalDefId) -> Option<CrateNum> {
- desc { |tcx| "computing crate imported by `{}`", tcx.def_path_str(def_id.to_def_id()) }
- }
-
- query get_lib_features(_: CrateNum) -> LibFeatures {
- storage(ArenaCacheSelector<'tcx>)
- eval_always
- desc { "calculating the lib features map" }
- }
- query defined_lib_features(_: CrateNum)
- -> &'tcx [(Symbol, Option<Symbol>)] {
- desc { "calculating the lib features defined in a crate" }
- }
- /// Returns the lang items defined in another crate by loading it from metadata.
- // FIXME: It is illegal to pass a `CrateNum` other than `LOCAL_CRATE` here, just get rid
- // of that argument?
- query get_lang_items(_: CrateNum) -> LanguageItems {
- storage(ArenaCacheSelector<'tcx>)
- eval_always
- desc { "calculating the lang items map" }
- }
-
- /// Returns all diagnostic items defined in all crates.
- query all_diagnostic_items(_: CrateNum) -> FxHashMap<Symbol, DefId> {
- storage(ArenaCacheSelector<'tcx>)
- eval_always
- desc { "calculating the diagnostic items map" }
- }
-
- /// Returns the lang items defined in another crate by loading it from metadata.
- query defined_lang_items(_: CrateNum) -> &'tcx [(DefId, usize)] {
- desc { "calculating the lang items defined in a crate" }
- }
-
- /// Returns the diagnostic items defined in a crate.
- query diagnostic_items(_: CrateNum) -> FxHashMap<Symbol, DefId> {
- storage(ArenaCacheSelector<'tcx>)
- desc { "calculating the diagnostic items map in a crate" }
- }
-
- query missing_lang_items(_: CrateNum) -> &'tcx [LangItem] {
- desc { "calculating the missing lang items in a crate" }
- }
- query visible_parent_map(_: CrateNum)
- -> DefIdMap<DefId> {
- storage(ArenaCacheSelector<'tcx>)
- desc { "calculating the visible parent map" }
- }
- query trimmed_def_paths(_: CrateNum)
- -> FxHashMap<DefId, Symbol> {
- storage(ArenaCacheSelector<'tcx>)
- desc { "calculating trimmed def paths" }
- }
- query missing_extern_crate_item(_: CrateNum) -> bool {
- eval_always
- desc { "seeing if we're missing an `extern crate` item for this crate" }
- }
- query used_crate_source(_: CrateNum) -> Lrc<CrateSource> {
- eval_always
- desc { "looking at the source for a crate" }
- }
- query postorder_cnums(_: CrateNum) -> &'tcx [CrateNum] {
- eval_always
- desc { "generating a postorder list of CrateNums" }
- }
-
- query upvars_mentioned(def_id: DefId) -> Option<&'tcx FxIndexMap<hir::HirId, hir::Upvar>> {
- desc { |tcx| "collecting upvars mentioned in `{}`", tcx.def_path_str(def_id) }
- eval_always
- }
- query maybe_unused_trait_import(def_id: LocalDefId) -> bool {
- eval_always
- desc { |tcx| "maybe_unused_trait_import for `{}`", tcx.def_path_str(def_id.to_def_id()) }
- }
- query maybe_unused_extern_crates(_: CrateNum)
- -> &'tcx [(LocalDefId, Span)] {
- eval_always
- desc { "looking up all possibly unused extern crates" }
- }
- query names_imported_by_glob_use(def_id: LocalDefId)
- -> &'tcx FxHashSet<Symbol> {
- eval_always
- desc { |tcx| "names_imported_by_glob_use for `{}`", tcx.def_path_str(def_id.to_def_id()) }
- }
-
- query stability_index(_: CrateNum) -> stability::Index<'tcx> {
- storage(ArenaCacheSelector<'tcx>)
- eval_always
- desc { "calculating the stability index for the local crate" }
- }
- query all_crate_nums(_: CrateNum) -> &'tcx [CrateNum] {
- eval_always
- 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(_: CrateNum) -> &'tcx [DefId] {
- desc { "fetching all foreign and local traits" }
- }
- }
-
- Linking {
- /// The list of symbols exported from the given crate.
- ///
- /// - All names contained in `exported_symbols(cnum)` are guaranteed to
- /// correspond to a publicly visible symbol in `cnum` machine code.
- /// - The `exported_symbols` sets of different crates do not intersect.
- query exported_symbols(_: CrateNum)
- -> &'tcx [(ExportedSymbol<'tcx>, SymbolExportLevel)] {
- desc { "exported_symbols" }
- }
- }
-
- Codegen {
- query collect_and_partition_mono_items(_: CrateNum)
- -> (&'tcx DefIdSet, &'tcx [CodegenUnit<'tcx>]) {
- eval_always
- desc { "collect_and_partition_mono_items" }
- }
- query is_codegened_item(def_id: DefId) -> bool {
- desc { |tcx| "determining whether `{}` needs codegen", tcx.def_path_str(def_id) }
- }
- query codegen_unit(_: Symbol) -> &'tcx CodegenUnit<'tcx> {
- desc { "codegen_unit" }
- }
- query unused_generic_params(key: DefId) -> FiniteBitSet<u32> {
- cache_on_disk_if { key.is_local() }
- desc {
- |tcx| "determining which generic parameters are unused by `{}`",
- tcx.def_path_str(key)
- }
- }
- query backend_optimization_level(_: CrateNum) -> OptLevel {
- desc { "optimization level used by backend" }
- }
- }
-
- Other {
- query output_filenames(_: CrateNum) -> Arc<OutputFilenames> {
- eval_always
- desc { "output_filenames" }
- }
- }
-
- TypeChecking {
- /// Do not call this query directly: invoke `normalize` instead.
- query normalize_projection_ty(
- goal: CanonicalProjectionGoal<'tcx>
- ) -> Result<
- &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, NormalizationResult<'tcx>>>,
- NoSolution,
- > {
- desc { "normalizing `{:?}`", goal }
- }
-
- /// Do not call this query directly: invoke `normalize_erasing_regions` instead.
- query normalize_generic_arg_after_erasing_regions(
- goal: ParamEnvAnd<'tcx, GenericArg<'tcx>>
- ) -> GenericArg<'tcx> {
- desc { "normalizing `{}`", goal.value }
- }
-
- query implied_outlives_bounds(
- goal: CanonicalTyGoal<'tcx>
- ) -> Result<
- &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, Vec<OutlivesBound<'tcx>>>>,
- NoSolution,
- > {
- desc { "computing implied outlives bounds for `{:?}`", goal }
- }
-
- /// Do not call this query directly: invoke `infcx.at().dropck_outlives()` instead.
- query dropck_outlives(
- goal: CanonicalTyGoal<'tcx>
- ) -> Result<
- &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, DropckOutlivesResult<'tcx>>>,
- NoSolution,
- > {
- desc { "computing dropck types for `{:?}`", goal }
- }
-
- /// Do not call this query directly: invoke `infcx.predicate_may_hold()` or
- /// `infcx.predicate_must_hold()` instead.
- query evaluate_obligation(
- goal: CanonicalPredicateGoal<'tcx>
- ) -> Result<traits::EvaluationResult, traits::OverflowError> {
- desc { "evaluating trait selection obligation `{}`", goal.value.value }
- }
-
- query evaluate_goal(
- goal: traits::CanonicalChalkEnvironmentAndGoal<'tcx>
- ) -> Result<
- &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, ()>>,
- NoSolution
- > {
- desc { "evaluating trait selection obligation `{}`", goal.value }
- }
-
- query type_implements_trait(
- key: (DefId, Ty<'tcx>, SubstsRef<'tcx>, ty::ParamEnv<'tcx>, )
- ) -> bool {
- desc { "evaluating `type_implements_trait` `{:?}`", key }
- }
-
- /// Do not call this query directly: part of the `Eq` type-op
- query type_op_ascribe_user_type(
- goal: CanonicalTypeOpAscribeUserTypeGoal<'tcx>
- ) -> Result<
- &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, ()>>,
- NoSolution,
- > {
- desc { "evaluating `type_op_ascribe_user_type` `{:?}`", goal }
- }
-
- /// Do not call this query directly: part of the `Eq` type-op
- query type_op_eq(
- goal: CanonicalTypeOpEqGoal<'tcx>
- ) -> Result<
- &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, ()>>,
- NoSolution,
- > {
- desc { "evaluating `type_op_eq` `{:?}`", goal }
- }
-
- /// Do not call this query directly: part of the `Subtype` type-op
- query type_op_subtype(
- goal: CanonicalTypeOpSubtypeGoal<'tcx>
- ) -> Result<
- &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, ()>>,
- NoSolution,
- > {
- desc { "evaluating `type_op_subtype` `{:?}`", goal }
- }
-
- /// Do not call this query directly: part of the `ProvePredicate` type-op
- query type_op_prove_predicate(
- goal: CanonicalTypeOpProvePredicateGoal<'tcx>
- ) -> Result<
- &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, ()>>,
- NoSolution,
- > {
- desc { "evaluating `type_op_prove_predicate` `{:?}`", goal }
- }
-
- /// Do not call this query directly: part of the `Normalize` type-op
- query type_op_normalize_ty(
- goal: CanonicalTypeOpNormalizeGoal<'tcx, Ty<'tcx>>
- ) -> Result<
- &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, Ty<'tcx>>>,
- NoSolution,
- > {
- desc { "normalizing `{:?}`", goal }
- }
-
- /// Do not call this query directly: part of the `Normalize` type-op
- query type_op_normalize_predicate(
- goal: CanonicalTypeOpNormalizeGoal<'tcx, ty::Predicate<'tcx>>
- ) -> Result<
- &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, ty::Predicate<'tcx>>>,
- NoSolution,
- > {
- desc { "normalizing `{:?}`", goal }
- }
-
- /// Do not call this query directly: part of the `Normalize` type-op
- query type_op_normalize_poly_fn_sig(
- goal: CanonicalTypeOpNormalizeGoal<'tcx, ty::PolyFnSig<'tcx>>
- ) -> Result<
- &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, ty::PolyFnSig<'tcx>>>,
- NoSolution,
- > {
- desc { "normalizing `{:?}`", goal }
- }
-
- /// Do not call this query directly: part of the `Normalize` type-op
- query type_op_normalize_fn_sig(
- goal: CanonicalTypeOpNormalizeGoal<'tcx, ty::FnSig<'tcx>>
- ) -> Result<
- &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, ty::FnSig<'tcx>>>,
- NoSolution,
- > {
- desc { "normalizing `{:?}`", goal }
- }
-
- query subst_and_check_impossible_predicates(key: (DefId, SubstsRef<'tcx>)) -> bool {
- desc { |tcx|
- "impossible substituted predicates:`{}`",
- tcx.def_path_str(key.0)
- }
- }
-
- query method_autoderef_steps(
- goal: CanonicalTyGoal<'tcx>
- ) -> MethodAutoderefStepsResult<'tcx> {
- desc { "computing autoderef types for `{:?}`", goal }
- }
- }
-
- Other {
- query supported_target_features(_: CrateNum) -> FxHashMap<String, Option<Symbol>> {
- storage(ArenaCacheSelector<'tcx>)
- eval_always
- desc { "looking up supported target features" }
- }
-
- /// Get an estimate of the size of an InstanceDef based on its MIR for CGU partitioning.
- query instance_def_size_estimate(def: ty::InstanceDef<'tcx>)
- -> usize {
- desc { |tcx| "estimating size for `{}`", tcx.def_path_str(def.def_id()) }
- }
-
- query features_query(_: CrateNum) -> &'tcx rustc_feature::Features {
- eval_always
- desc { "looking up enabled feature gates" }
- }
-
- /// Attempt to resolve the given `DefId` to an `Instance`, for the
- /// given generics args (`SubstsRef`), returning one of:
- /// * `Ok(Some(instance))` on success
- /// * `Ok(None)` when the `SubstsRef` are still too generic,
- /// and therefore don't allow finding the final `Instance`
- /// * `Err(ErrorReported)` when the `Instance` resolution process
- /// couldn't complete due to errors elsewhere - this is distinct
- /// from `Ok(None)` to avoid misleading diagnostics when an error
- /// has already been/will be emitted, for the original cause
- query resolve_instance(
- key: ty::ParamEnvAnd<'tcx, (DefId, SubstsRef<'tcx>)>
- ) -> Result<Option<ty::Instance<'tcx>>, ErrorReported> {
- desc { "resolving instance `{}`", ty::Instance::new(key.value.0, key.value.1) }
- }
-
- query resolve_instance_of_const_arg(
- key: ty::ParamEnvAnd<'tcx, (LocalDefId, DefId, SubstsRef<'tcx>)>
- ) -> Result<Option<ty::Instance<'tcx>>, ErrorReported> {
- desc {
- "resolving instance of the const argument `{}`",
- ty::Instance::new(key.value.0.to_def_id(), key.value.2),
- }
- }
-
- query normalize_opaque_types(key: &'tcx ty::List<ty::Predicate<'tcx>>) -> &'tcx ty::List<ty::Predicate<'tcx>> {
- desc { "normalizing opaque types in {:?}", key }
- }
+ query normalize_opaque_types(key: &'tcx ty::List<ty::Predicate<'tcx>>) -> &'tcx ty::List<ty::Predicate<'tcx>> {
+ desc { "normalizing opaque types in {:?}", key }
}
}
diff --git a/compiler/rustc_middle/src/traits/chalk.rs b/compiler/rustc_middle/src/traits/chalk.rs
index f864ad8..7487377 100644
--- a/compiler/rustc_middle/src/traits/chalk.rs
+++ b/compiler/rustc_middle/src/traits/chalk.rs
@@ -72,6 +72,7 @@
type InternedQuantifiedWhereClauses = Vec<chalk_ir::QuantifiedWhereClause<Self>>;
type InternedVariableKinds = Vec<chalk_ir::VariableKind<Self>>;
type InternedCanonicalVarKinds = Vec<chalk_ir::CanonicalVarKind<Self>>;
+ type InternedVariances = Vec<chalk_ir::Variance>;
type InternedConstraints = Vec<chalk_ir::InEnvironment<chalk_ir::Constraint<Self>>>;
type DefId = DefId;
type InternedAdtId = &'tcx AdtDef;
@@ -86,17 +87,34 @@
write!(fmt, "{:?}", pci.consequence)?;
let conditions = pci.conditions.interned();
+ let constraints = pci.constraints.interned();
let conds = conditions.len();
- if conds == 0 {
+ let consts = constraints.len();
+ if conds == 0 && consts == 0 {
return Ok(());
}
write!(fmt, " :- ")?;
- for cond in &conditions[..conds - 1] {
- write!(fmt, "{:?}, ", cond)?;
+
+ if conds != 0 {
+ for cond in &conditions[..conds - 1] {
+ write!(fmt, "{:?}, ", cond)?;
+ }
+ write!(fmt, "{:?}", conditions[conds - 1])?;
}
- write!(fmt, "{:?}", conditions[conds - 1])?;
+
+ if conds != 0 && consts != 0 {
+ write!(fmt, " ; ")?;
+ }
+
+ if consts != 0 {
+ for constraint in &constraints[..consts - 1] {
+ write!(fmt, "{:?}, ", constraint)?;
+ }
+ write!(fmt, "{:?}", constraints[consts - 1])?;
+ }
+
Ok(())
};
Some(write())
@@ -351,6 +369,20 @@
) -> &'a [chalk_ir::InEnvironment<chalk_ir::Constraint<Self>>] {
constraints
}
+
+ fn intern_variances<E>(
+ &self,
+ data: impl IntoIterator<Item = Result<chalk_ir::Variance, E>>,
+ ) -> Result<Self::InternedVariances, E> {
+ data.into_iter().collect::<Result<Vec<_>, _>>()
+ }
+
+ fn variances_data<'a>(
+ &self,
+ variances: &'a Self::InternedVariances,
+ ) -> &'a [chalk_ir::Variance] {
+ variances
+ }
}
impl<'tcx> chalk_ir::interner::HasInterner for RustInterner<'tcx> {
diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs
index 0a663f7..163b400 100644
--- a/compiler/rustc_middle/src/traits/mod.rs
+++ b/compiler/rustc_middle/src/traits/mod.rs
@@ -228,8 +228,7 @@
/// Inline asm operand type must be `Sized`.
InlineAsmSized,
/// `[T, ..n]` implies that `T` must be `Copy`.
- /// If `true`, suggest `const_in_array_repeat_expressions` feature flag.
- RepeatVec(bool),
+ RepeatVec,
/// Types of fields (other than the last, except for packed structs) in a struct must be sized.
FieldSized {
diff --git a/compiler/rustc_middle/src/traits/specialization_graph.rs b/compiler/rustc_middle/src/traits/specialization_graph.rs
index ec6010e..cb60bfa 100644
--- a/compiler/rustc_middle/src/traits/specialization_graph.rs
+++ b/compiler/rustc_middle/src/traits/specialization_graph.rs
@@ -23,7 +23,7 @@
/// parents of a given specializing impl, which is needed for extracting
/// default items amongst other things. In the simple "chain" rule, every impl
/// has at most one parent.
-#[derive(TyEncodable, TyDecodable, HashStable)]
+#[derive(TyEncodable, TyDecodable, HashStable, Debug)]
pub struct Graph {
/// All impls have a parent; the "root" impls have as their parent the `def_id`
/// of the trait.
@@ -50,7 +50,7 @@
/// Children of a given impl, grouped into blanket/non-blanket varieties as is
/// done in `TraitDef`.
-#[derive(Default, TyEncodable, TyDecodable)]
+#[derive(Default, TyEncodable, TyDecodable, Debug)]
pub struct Children {
// Impls of a trait (or specializations of a given impl). To allow for
// quicker lookup, the impls are indexed by a simplified version of their
diff --git a/compiler/rustc_middle/src/ty/cast.rs b/compiler/rustc_middle/src/ty/cast.rs
index b47d9c5..20a6af5f 100644
--- a/compiler/rustc_middle/src/ty/cast.rs
+++ b/compiler/rustc_middle/src/ty/cast.rs
@@ -3,13 +3,12 @@
use crate::ty::{self, Ty};
-use rustc_ast as ast;
use rustc_macros::HashStable;
/// Types that are represented as ints.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum IntTy {
- U(ast::UintTy),
+ U(ty::UintTy),
I,
CEnum,
Bool,
@@ -22,15 +21,16 @@
/// Various types that are represented as ints and handled mostly
/// in the same way, merged for easier matching.
Int(IntTy),
- /// Floating-Point types
+ /// Floating-point types.
Float,
- /// Function Pointers
+ /// Function pointers.
FnPtr,
- /// Raw pointers
+ /// Raw pointers.
Ptr(ty::TypeAndMut<'tcx>),
}
-/// Cast Kind. See RFC 401 (or librustc_typeck/check/cast.rs)
+/// Cast Kind. See [RFC 401](https://rust-lang.github.io/rfcs/0401-coercions.html)
+/// (or librustc_typeck/check/cast.rs).
#[derive(Copy, Clone, Debug, TyEncodable, TyDecodable, HashStable)]
pub enum CastKind {
CoercionCast,
@@ -48,7 +48,7 @@
impl<'tcx> CastTy<'tcx> {
/// Returns `Some` for integral/pointer casts.
- /// casts like unsizing casts will return `None`
+ /// Casts like unsizing casts will return `None`.
pub fn from_ty(t: Ty<'tcx>) -> Option<CastTy<'tcx>> {
match *t.kind() {
ty::Bool => Some(CastTy::Int(IntTy::Bool)),
diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs
index df59469..0dad5df 100644
--- a/compiler/rustc_middle/src/ty/codec.rs
+++ b/compiler/rustc_middle/src/ty/codec.rs
@@ -18,7 +18,6 @@
use rustc_hir::def_id::{CrateNum, DefId};
use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
use rustc_span::Span;
-use std::convert::{TryFrom, TryInto};
use std::hash::Hash;
use std::intrinsics;
use std::marker::DiscriminantKind;
@@ -43,27 +42,13 @@
}
}
-impl<'tcx, E: TyEncoder<'tcx>> EncodableWithShorthand<'tcx, E> for ty::Predicate<'tcx> {
+impl<'tcx, E: TyEncoder<'tcx>> EncodableWithShorthand<'tcx, E> for ty::PredicateKind<'tcx> {
type Variant = ty::PredicateKind<'tcx>;
+
+ #[inline]
fn variant(&self) -> &Self::Variant {
- self.kind()
- }
-}
-
-pub trait OpaqueEncoder: Encoder {
- fn opaque(&mut self) -> &mut rustc_serialize::opaque::Encoder;
- fn encoder_position(&self) -> usize;
-}
-
-impl OpaqueEncoder for rustc_serialize::opaque::Encoder {
- #[inline]
- fn opaque(&mut self) -> &mut rustc_serialize::opaque::Encoder {
self
}
- #[inline]
- fn encoder_position(&self) -> usize {
- self.position()
- }
}
pub trait TyEncoder<'tcx>: Encoder {
@@ -71,7 +56,7 @@
fn position(&self) -> usize;
fn type_shorthands(&mut self) -> &mut FxHashMap<Ty<'tcx>, usize>;
- fn predicate_shorthands(&mut self) -> &mut FxHashMap<ty::Predicate<'tcx>, usize>;
+ fn predicate_shorthands(&mut self) -> &mut FxHashMap<ty::PredicateKind<'tcx>, usize>;
fn encode_alloc_id(&mut self, alloc_id: &AllocId) -> Result<(), Self::Error>;
}
@@ -95,7 +80,8 @@
E: TyEncoder<'tcx>,
M: for<'b> Fn(&'b mut E) -> &'b mut FxHashMap<T, usize>,
T: EncodableWithShorthand<'tcx, E>,
- <T::Variant as DiscriminantKind>::Discriminant: Ord + TryFrom<usize>,
+ // The discriminant and shorthand must have the same size.
+ T::Variant: DiscriminantKind<Discriminant = isize>,
{
let existing_shorthand = cache(encoder).get(value).copied();
if let Some(shorthand) = existing_shorthand {
@@ -111,7 +97,7 @@
// The shorthand encoding uses the same usize as the
// discriminant, with an offset so they can't conflict.
let discriminant = intrinsics::discriminant_value(variant);
- assert!(discriminant < SHORTHAND_OFFSET.try_into().ok().unwrap());
+ assert!(SHORTHAND_OFFSET > discriminant as usize);
let shorthand = start + SHORTHAND_OFFSET;
@@ -134,9 +120,15 @@
}
}
+impl<'tcx, E: TyEncoder<'tcx>> Encodable<E> for ty::Binder<ty::PredicateKind<'tcx>> {
+ fn encode(&self, e: &mut E) -> Result<(), E::Error> {
+ encode_with_shorthand(e, &self.skip_binder(), TyEncoder::predicate_shorthands)
+ }
+}
+
impl<'tcx, E: TyEncoder<'tcx>> Encodable<E> for ty::Predicate<'tcx> {
fn encode(&self, e: &mut E) -> Result<(), E::Error> {
- encode_with_shorthand(e, self, TyEncoder::predicate_shorthands)
+ self.kind().encode(e)
}
}
@@ -234,18 +226,24 @@
}
}
-impl<'tcx, D: TyDecoder<'tcx>> Decodable<D> for ty::Predicate<'tcx> {
- fn decode(decoder: &mut D) -> Result<ty::Predicate<'tcx>, D::Error> {
+impl<'tcx, D: TyDecoder<'tcx>> Decodable<D> for ty::Binder<ty::PredicateKind<'tcx>> {
+ fn decode(decoder: &mut D) -> Result<ty::Binder<ty::PredicateKind<'tcx>>, D::Error> {
// Handle shorthands first, if we have an usize > 0x80.
- let predicate_kind = if decoder.positioned_at_shorthand() {
+ Ok(ty::Binder::bind(if decoder.positioned_at_shorthand() {
let pos = decoder.read_usize()?;
assert!(pos >= SHORTHAND_OFFSET);
let shorthand = pos - SHORTHAND_OFFSET;
- decoder.with_position(shorthand, ty::PredicateKind::decode)
+ decoder.with_position(shorthand, ty::PredicateKind::decode)?
} else {
- ty::PredicateKind::decode(decoder)
- }?;
+ ty::PredicateKind::decode(decoder)?
+ }))
+ }
+}
+
+impl<'tcx, D: TyDecoder<'tcx>> Decodable<D> for ty::Predicate<'tcx> {
+ fn decode(decoder: &mut D) -> Result<ty::Predicate<'tcx>, D::Error> {
+ let predicate_kind = Decodable::decode(decoder)?;
let predicate = decoder.tcx().mk_predicate(predicate_kind);
Ok(predicate)
}
@@ -473,3 +471,28 @@
}
}
}
+
+macro_rules! impl_binder_encode_decode {
+ ($($t:ty),+ $(,)?) => {
+ $(
+ impl<'tcx, E: TyEncoder<'tcx>> Encodable<E> for ty::Binder<$t> {
+ fn encode(&self, e: &mut E) -> Result<(), E::Error> {
+ self.as_ref().skip_binder().encode(e)
+ }
+ }
+ impl<'tcx, D: TyDecoder<'tcx>> Decodable<D> for ty::Binder<$t> {
+ fn decode(decoder: &mut D) -> Result<Self, D::Error> {
+ Ok(ty::Binder::bind(Decodable::decode(decoder)?))
+ }
+ }
+ )*
+ }
+}
+
+impl_binder_encode_decode! {
+ &'tcx ty::List<Ty<'tcx>>,
+ ty::FnSig<'tcx>,
+ ty::ExistentialPredicate<'tcx>,
+ ty::TraitRef<'tcx>,
+ Vec<ty::GeneratorInteriorTypeCause<'tcx>>,
+}
diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs
index 0af884a..041c040 100644
--- a/compiler/rustc_middle/src/ty/consts.rs
+++ b/compiler/rustc_middle/src/ty/consts.rs
@@ -92,8 +92,7 @@
let item_id = tcx.hir().get_parent_node(hir_id);
let item_def_id = tcx.hir().local_def_id(item_id);
let generics = tcx.generics_of(item_def_id.to_def_id());
- let index =
- generics.param_def_id_to_index[&tcx.hir().local_def_id(hir_id).to_def_id()];
+ let index = generics.param_def_id_to_index[&def_id];
let name = tcx.hir().name(hir_id);
ty::ConstKind::Param(ty::ParamConst::new(index, name))
}
diff --git a/compiler/rustc_middle/src/ty/consts/kind.rs b/compiler/rustc_middle/src/ty/consts/kind.rs
index ecf2837..a2638d8 100644
--- a/compiler/rustc_middle/src/ty/consts/kind.rs
+++ b/compiler/rustc_middle/src/ty/consts/kind.rs
@@ -82,7 +82,7 @@
/// Tries to evaluate the constant if it is `Unevaluated`. If that doesn't succeed, return the
/// unevaluated constant.
pub fn eval(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Self {
- self.try_eval(tcx, param_env).and_then(Result::ok).map(ConstKind::Value).unwrap_or(self)
+ self.try_eval(tcx, param_env).and_then(Result::ok).map_or(self, ConstKind::Value)
}
#[inline]
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index 9b944f2..1255302 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -1,8 +1,9 @@
//! Type context book-keeping.
use crate::arena::Arena;
-use crate::dep_graph::{self, DepGraph, DepKind, DepNode, DepNodeExt};
+use crate::dep_graph::DepGraph;
use crate::hir::exports::ExportMap;
+use crate::hir::place::Place as HirPlace;
use crate::ich::{NodeIdHashingMode, StableHashingContext};
use crate::infer::canonical::{Canonical, CanonicalVarInfo, CanonicalVarInfos};
use crate::lint::{struct_lint_level, LintDiagnosticBuilder, LintLevelSource};
@@ -17,11 +18,11 @@
use crate::ty::subst::{GenericArg, GenericArgKind, InternalSubsts, Subst, SubstsRef, UserSubsts};
use crate::ty::TyKind::*;
use crate::ty::{
- self, AdtDef, AdtKind, BindingMode, BoundVar, CanonicalPolyFnSig, Const, ConstVid, DefIdTree,
- ExistentialPredicate, FloatVar, FloatVid, GenericParamDefKind, InferConst, InferTy, IntVar,
- IntVid, List, ParamConst, ParamTy, PolyFnSig, Predicate, PredicateInner, PredicateKind,
- ProjectionTy, Region, RegionKind, ReprOptions, TraitObjectVisitor, Ty, TyKind, TyS, TyVar,
- TyVid, TypeAndMut, Visibility,
+ self, AdtDef, AdtKind, Binder, BindingMode, BoundVar, CanonicalPolyFnSig, Const, ConstVid,
+ DefIdTree, ExistentialPredicate, FloatTy, FloatVar, FloatVid, GenericParamDefKind, InferConst,
+ InferTy, IntTy, IntVar, IntVid, List, ParamConst, ParamTy, PolyFnSig, Predicate,
+ PredicateInner, PredicateKind, ProjectionTy, Region, RegionKind, ReprOptions,
+ TraitObjectVisitor, Ty, TyKind, TyS, TyVar, TyVid, TypeAndMut, UintTy, Visibility,
};
use rustc_ast as ast;
use rustc_ast::expand::allocator::AllocatorKind;
@@ -37,8 +38,7 @@
use rustc_errors::ErrorReported;
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
-use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId};
-use rustc_hir::def_id::{CRATE_DEF_INDEX, LOCAL_CRATE};
+use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, LOCAL_CRATE};
use rustc_hir::definitions::Definitions;
use rustc_hir::intravisit::Visitor;
use rustc_hir::lang_items::LangItem;
@@ -47,6 +47,7 @@
};
use rustc_index::vec::{Idx, IndexVec};
use rustc_macros::HashStable;
+use rustc_serialize::opaque::{FileEncodeResult, FileEncoder};
use rustc_session::config::{BorrowckMode, CrateType, OutputFilenames};
use rustc_session::lint::{Level, Lint};
use rustc_session::Session;
@@ -133,7 +134,7 @@
}
#[inline(never)]
- fn intern_predicate(&self, kind: PredicateKind<'tcx>) -> &'tcx PredicateInner<'tcx> {
+ fn intern_predicate(&self, kind: Binder<PredicateKind<'tcx>>) -> &'tcx PredicateInner<'tcx> {
self.predicate
.intern(kind, |kind| {
let flags = super::flags::FlagComputation::for_predicate(kind);
@@ -379,7 +380,7 @@
/// Records the reasons that we picked the kind of each closure;
/// not all closures are present in the map.
- closure_kind_origins: ItemLocalMap<(Span, Symbol)>,
+ closure_kind_origins: ItemLocalMap<(Span, HirPlace<'tcx>)>,
/// For each fn, records the "liberated" types of its arguments
/// and return type. Liberated means that all bound regions
@@ -642,11 +643,13 @@
self.upvar_capture_map[&upvar_id]
}
- pub fn closure_kind_origins(&self) -> LocalTableInContext<'_, (Span, Symbol)> {
+ pub fn closure_kind_origins(&self) -> LocalTableInContext<'_, (Span, HirPlace<'tcx>)> {
LocalTableInContext { hir_owner: self.hir_owner, data: &self.closure_kind_origins }
}
- pub fn closure_kind_origins_mut(&mut self) -> LocalTableInContextMut<'_, (Span, Symbol)> {
+ pub fn closure_kind_origins_mut(
+ &mut self,
+ ) -> LocalTableInContextMut<'_, (Span, HirPlace<'tcx>)> {
LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.closure_kind_origins }
}
@@ -836,20 +839,20 @@
bool: mk(Bool),
char: mk(Char),
never: mk(Never),
- isize: mk(Int(ast::IntTy::Isize)),
- i8: mk(Int(ast::IntTy::I8)),
- i16: mk(Int(ast::IntTy::I16)),
- i32: mk(Int(ast::IntTy::I32)),
- i64: mk(Int(ast::IntTy::I64)),
- i128: mk(Int(ast::IntTy::I128)),
- usize: mk(Uint(ast::UintTy::Usize)),
- u8: mk(Uint(ast::UintTy::U8)),
- u16: mk(Uint(ast::UintTy::U16)),
- u32: mk(Uint(ast::UintTy::U32)),
- u64: mk(Uint(ast::UintTy::U64)),
- u128: mk(Uint(ast::UintTy::U128)),
- f32: mk(Float(ast::FloatTy::F32)),
- f64: mk(Float(ast::FloatTy::F64)),
+ isize: mk(Int(ty::IntTy::Isize)),
+ i8: mk(Int(ty::IntTy::I8)),
+ i16: mk(Int(ty::IntTy::I16)),
+ i32: mk(Int(ty::IntTy::I32)),
+ i64: mk(Int(ty::IntTy::I64)),
+ i128: mk(Int(ty::IntTy::I128)),
+ usize: mk(Uint(ty::UintTy::Usize)),
+ u8: mk(Uint(ty::UintTy::U8)),
+ u16: mk(Uint(ty::UintTy::U16)),
+ u32: mk(Uint(ty::UintTy::U32)),
+ u64: mk(Uint(ty::UintTy::U64)),
+ u128: mk(Uint(ty::UintTy::U128)),
+ f32: mk(Float(ty::FloatTy::F32)),
+ f64: mk(Float(ty::FloatTy::F64)),
str_: mk(Str),
self_param: mk(ty::Param(ty::ParamTy { index: 0, name: kw::SelfUpper })),
@@ -1314,33 +1317,8 @@
StableHashingContext::ignore_spans(self.sess, krate, self.definitions, &*self.cstore)
}
- // This method makes sure that we have a DepNode and a Fingerprint for
- // every upstream crate. It needs to be called once right after the tcx is
- // created.
- // With full-fledged red/green, the method will probably become unnecessary
- // as this will be done on-demand.
- pub fn allocate_metadata_dep_nodes(self) {
- // We cannot use the query versions of crates() and crate_hash(), since
- // those would need the DepNodes that we are allocating here.
- for cnum in self.cstore.crates_untracked() {
- let def_path_hash = self.def_path_hash(DefId { krate: cnum, index: CRATE_DEF_INDEX });
- let dep_node = DepNode::from_def_path_hash(def_path_hash, DepKind::CrateMetadata);
- let crate_hash = self.cstore.crate_hash_untracked(cnum);
- self.dep_graph.with_task(
- dep_node,
- self,
- crate_hash,
- |_, x| x, // No transformation needed
- dep_graph::hash_result,
- );
- }
- }
-
- pub fn serialize_query_result_cache<E>(self, encoder: &mut E) -> Result<(), E::Error>
- where
- E: ty::codec::OpaqueEncoder,
- {
- self.queries.on_disk_cache.as_ref().map(|c| c.serialize(self, encoder)).unwrap_or(Ok(()))
+ pub fn serialize_query_result_cache(self, encoder: &mut FileEncoder) -> FileEncodeResult {
+ self.queries.on_disk_cache.as_ref().map_or(Ok(()), |c| c.serialize(self, encoder))
}
/// If `true`, we should use the MIR-based borrowck, but also
@@ -1386,7 +1364,7 @@
#[inline]
pub fn lazy_normalization(self) -> bool {
let features = self.features();
- // Note: We do not enable lazy normalization for `features.min_const_generics`.
+ // Note: We do not enable lazy normalization for `min_const_generics`.
features.const_generics || features.lazy_normalization_consts
}
@@ -1973,8 +1951,8 @@
}
}
-impl<'tcx> Borrow<PredicateKind<'tcx>> for Interned<'tcx, PredicateInner<'tcx>> {
- fn borrow<'a>(&'a self) -> &'a PredicateKind<'tcx> {
+impl<'tcx> Borrow<Binder<PredicateKind<'tcx>>> for Interned<'tcx, PredicateInner<'tcx>> {
+ fn borrow<'a>(&'a self) -> &'a Binder<PredicateKind<'tcx>> {
&self.0.kind
}
}
@@ -2012,12 +1990,6 @@
}
}
-impl<'tcx> Borrow<PredicateKind<'tcx>> for Interned<'tcx, PredicateKind<'tcx>> {
- fn borrow<'a>(&'a self) -> &'a PredicateKind<'tcx> {
- &self.0
- }
-}
-
macro_rules! direct_interners {
($($name:ident: $method:ident($ty:ty),)+) => {
$(impl<'tcx> PartialEq for Interned<'tcx, $ty> {
@@ -2116,8 +2088,8 @@
}
#[inline]
- pub fn mk_predicate(self, kind: PredicateKind<'tcx>) -> Predicate<'tcx> {
- let inner = self.interners.intern_predicate(kind);
+ pub fn mk_predicate(self, binder: Binder<PredicateKind<'tcx>>) -> Predicate<'tcx> {
+ let inner = self.interners.intern_predicate(binder);
Predicate { inner }
}
@@ -2125,37 +2097,37 @@
pub fn reuse_or_mk_predicate(
self,
pred: Predicate<'tcx>,
- kind: PredicateKind<'tcx>,
+ binder: Binder<PredicateKind<'tcx>>,
) -> Predicate<'tcx> {
- if *pred.kind() != kind { self.mk_predicate(kind) } else { pred }
+ if pred.kind() != binder { self.mk_predicate(binder) } else { pred }
}
- pub fn mk_mach_int(self, tm: ast::IntTy) -> Ty<'tcx> {
+ pub fn mk_mach_int(self, tm: IntTy) -> Ty<'tcx> {
match tm {
- ast::IntTy::Isize => self.types.isize,
- ast::IntTy::I8 => self.types.i8,
- ast::IntTy::I16 => self.types.i16,
- ast::IntTy::I32 => self.types.i32,
- ast::IntTy::I64 => self.types.i64,
- ast::IntTy::I128 => self.types.i128,
+ IntTy::Isize => self.types.isize,
+ IntTy::I8 => self.types.i8,
+ IntTy::I16 => self.types.i16,
+ IntTy::I32 => self.types.i32,
+ IntTy::I64 => self.types.i64,
+ IntTy::I128 => self.types.i128,
}
}
- pub fn mk_mach_uint(self, tm: ast::UintTy) -> Ty<'tcx> {
+ pub fn mk_mach_uint(self, tm: UintTy) -> Ty<'tcx> {
match tm {
- ast::UintTy::Usize => self.types.usize,
- ast::UintTy::U8 => self.types.u8,
- ast::UintTy::U16 => self.types.u16,
- ast::UintTy::U32 => self.types.u32,
- ast::UintTy::U64 => self.types.u64,
- ast::UintTy::U128 => self.types.u128,
+ UintTy::Usize => self.types.usize,
+ UintTy::U8 => self.types.u8,
+ UintTy::U16 => self.types.u16,
+ UintTy::U32 => self.types.u32,
+ UintTy::U64 => self.types.u64,
+ UintTy::U128 => self.types.u128,
}
}
- pub fn mk_mach_float(self, tm: ast::FloatTy) -> Ty<'tcx> {
+ pub fn mk_mach_float(self, tm: FloatTy) -> Ty<'tcx> {
match tm {
- ast::FloatTy::F32 => self.types.f32,
- ast::FloatTy::F64 => self.types.f64,
+ FloatTy::F32 => self.types.f32,
+ FloatTy::F64 => self.types.f64,
}
}
@@ -2603,7 +2575,8 @@
}
pub fn is_late_bound(self, id: HirId) -> bool {
- self.is_late_bound_map(id.owner).map(|set| set.contains(&id.local_id)).unwrap_or(false)
+ self.is_late_bound_map(id.owner)
+ .map_or(false, |(owner, set)| owner == id.owner && set.contains(&id.local_id))
}
pub fn object_lifetime_defaults(self, id: HirId) -> Option<&'tcx [ObjectLifetimeDefault]> {
diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs
index 65703d0..4a131a4 100644
--- a/compiler/rustc_middle/src/ty/diagnostics.rs
+++ b/compiler/rustc_middle/src/ty/diagnostics.rs
@@ -1,8 +1,7 @@
//! Diagnostics related methods for `TyS`.
-use crate::ty::sty::InferTy;
use crate::ty::TyKind::*;
-use crate::ty::{TyCtxt, TyS};
+use crate::ty::{InferTy, TyCtxt, TyS};
use rustc_errors::{Applicability, DiagnosticBuilder};
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
@@ -13,13 +12,17 @@
pub fn is_primitive_ty(&self) -> bool {
matches!(
self.kind(),
- Bool | Char | Str | Int(_) | Uint(_) | Float(_)
- | Infer(
- InferTy::IntVar(_)
- | InferTy::FloatVar(_)
- | InferTy::FreshIntTy(_)
- | InferTy::FreshFloatTy(_)
- )
+ Bool | Char
+ | Str
+ | Int(_)
+ | Uint(_)
+ | Float(_)
+ | Infer(
+ InferTy::IntVar(_)
+ | InferTy::FloatVar(_)
+ | InferTy::FreshIntTy(_)
+ | InferTy::FreshFloatTy(_)
+ )
)
}
@@ -245,8 +248,8 @@
}
}
- match ¶m_spans[..] {
- &[¶m_span] => suggest_restrict(param_span.shrink_to_hi()),
+ match param_spans[..] {
+ [¶m_span] => suggest_restrict(param_span.shrink_to_hi()),
_ => {
err.span_suggestion_verbose(
generics.where_clause.tail_span_for_suggestion(),
diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs
index fc02e78..1669c59 100644
--- a/compiler/rustc_middle/src/ty/error.rs
+++ b/compiler/rustc_middle/src/ty/error.rs
@@ -1,7 +1,6 @@
use crate::traits::{ObligationCause, ObligationCauseCode};
use crate::ty::diagnostics::suggest_constraining_type_param;
use crate::ty::{self, BoundRegionKind, Region, Ty, TyCtxt};
-use rustc_ast as ast;
use rustc_errors::Applicability::{MachineApplicable, MaybeIncorrect};
use rustc_errors::{pluralize, DiagnosticBuilder};
use rustc_hir as hir;
@@ -48,7 +47,7 @@
Sorts(ExpectedFound<Ty<'tcx>>),
IntMismatch(ExpectedFound<ty::IntVarValue>),
- FloatMismatch(ExpectedFound<ast::FloatTy>),
+ FloatMismatch(ExpectedFound<ty::FloatTy>),
Traits(ExpectedFound<DefId>),
VariadicMismatch(ExpectedFound<bool>),
@@ -647,14 +646,14 @@
let current_method_ident = body_owner.and_then(|n| n.ident()).map(|i| i.name);
// We don't want to suggest calling an assoc fn in a scope where that isn't feasible.
- let callable_scope = match body_owner {
+ let callable_scope = matches!(
+ body_owner,
Some(
hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(..), .. })
- | hir::Node::TraitItem(hir::TraitItem { kind: hir::TraitItemKind::Fn(..), .. })
- | hir::Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Fn(..), .. }),
- ) => true,
- _ => false,
- };
+ | hir::Node::TraitItem(hir::TraitItem { kind: hir::TraitItemKind::Fn(..), .. })
+ | hir::Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Fn(..), .. }),
+ )
+ );
let impl_comparison = matches!(
cause_code,
ObligationCauseCode::CompareImplMethodObligation { .. }
@@ -832,7 +831,8 @@
}
}
Some(hir::Node::Item(hir::Item {
- kind: hir::ItemKind::Impl { items, .. }, ..
+ kind: hir::ItemKind::Impl(hir::Impl { items, .. }),
+ ..
})) => {
for item in &items[..] {
if let hir::AssocItemKind::Type = item.kind {
@@ -849,7 +849,7 @@
}
/// Given a slice of `hir::GenericBound`s, if any of them corresponds to the `trait_ref`
- /// requirement, provide a strucuted suggestion to constrain it to a given type `ty`.
+ /// requirement, provide a structured suggestion to constrain it to a given type `ty`.
fn constrain_generic_bound_associated_type_structured_suggestion(
self,
db: &mut DiagnosticBuilder<'_>,
diff --git a/compiler/rustc_middle/src/ty/fast_reject.rs b/compiler/rustc_middle/src/ty/fast_reject.rs
index 860f91d..94d75a4 100644
--- a/compiler/rustc_middle/src/ty/fast_reject.rs
+++ b/compiler/rustc_middle/src/ty/fast_reject.rs
@@ -1,6 +1,5 @@
use crate::ich::StableHashingContext;
use crate::ty::{self, Ty, TyCtxt};
-use rustc_ast as ast;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_hir::def_id::DefId;
use std::fmt::Debug;
@@ -24,9 +23,9 @@
{
BoolSimplifiedType,
CharSimplifiedType,
- IntSimplifiedType(ast::IntTy),
- UintSimplifiedType(ast::UintTy),
- FloatSimplifiedType(ast::FloatTy),
+ IntSimplifiedType(ty::IntTy),
+ UintSimplifiedType(ty::UintTy),
+ FloatSimplifiedType(ty::FloatTy),
AdtSimplifiedType(D),
StrSimplifiedType,
ArraySimplifiedType,
diff --git a/compiler/rustc_middle/src/ty/flags.rs b/compiler/rustc_middle/src/ty/flags.rs
index 4de3d15..6ecd1eb 100644
--- a/compiler/rustc_middle/src/ty/flags.rs
+++ b/compiler/rustc_middle/src/ty/flags.rs
@@ -22,9 +22,9 @@
result
}
- pub fn for_predicate(kind: ty::PredicateKind<'_>) -> FlagComputation {
+ pub fn for_predicate(binder: ty::Binder<ty::PredicateKind<'_>>) -> FlagComputation {
let mut result = FlagComputation::new();
- result.add_predicate_kind(kind);
+ result.add_predicate(binder);
result
}
@@ -204,53 +204,46 @@
}
}
- fn add_predicate_kind(&mut self, kind: ty::PredicateKind<'_>) {
- match kind {
- ty::PredicateKind::ForAll(binder) => {
- self.bound_computation(binder, |computation, atom| {
- computation.add_predicate_atom(atom)
- });
- }
- ty::PredicateKind::Atom(atom) => self.add_predicate_atom(atom),
- }
+ fn add_predicate(&mut self, binder: ty::Binder<ty::PredicateKind<'_>>) {
+ self.bound_computation(binder, |computation, atom| computation.add_predicate_atom(atom));
}
- fn add_predicate_atom(&mut self, atom: ty::PredicateAtom<'_>) {
+ fn add_predicate_atom(&mut self, atom: ty::PredicateKind<'_>) {
match atom {
- ty::PredicateAtom::Trait(trait_pred, _constness) => {
+ ty::PredicateKind::Trait(trait_pred, _constness) => {
self.add_substs(trait_pred.trait_ref.substs);
}
- ty::PredicateAtom::RegionOutlives(ty::OutlivesPredicate(a, b)) => {
+ ty::PredicateKind::RegionOutlives(ty::OutlivesPredicate(a, b)) => {
self.add_region(a);
self.add_region(b);
}
- ty::PredicateAtom::TypeOutlives(ty::OutlivesPredicate(ty, region)) => {
+ ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(ty, region)) => {
self.add_ty(ty);
self.add_region(region);
}
- ty::PredicateAtom::Subtype(ty::SubtypePredicate { a_is_expected: _, a, b }) => {
+ ty::PredicateKind::Subtype(ty::SubtypePredicate { a_is_expected: _, a, b }) => {
self.add_ty(a);
self.add_ty(b);
}
- ty::PredicateAtom::Projection(ty::ProjectionPredicate { projection_ty, ty }) => {
+ ty::PredicateKind::Projection(ty::ProjectionPredicate { projection_ty, ty }) => {
self.add_projection_ty(projection_ty);
self.add_ty(ty);
}
- ty::PredicateAtom::WellFormed(arg) => {
+ ty::PredicateKind::WellFormed(arg) => {
self.add_substs(slice::from_ref(&arg));
}
- ty::PredicateAtom::ObjectSafe(_def_id) => {}
- ty::PredicateAtom::ClosureKind(_def_id, substs, _kind) => {
+ ty::PredicateKind::ObjectSafe(_def_id) => {}
+ ty::PredicateKind::ClosureKind(_def_id, substs, _kind) => {
self.add_substs(substs);
}
- ty::PredicateAtom::ConstEvaluatable(_def_id, substs) => {
+ ty::PredicateKind::ConstEvaluatable(_def_id, substs) => {
self.add_substs(substs);
}
- ty::PredicateAtom::ConstEquate(expected, found) => {
+ ty::PredicateKind::ConstEquate(expected, found) => {
self.add_const(expected);
self.add_const(found);
}
- ty::PredicateAtom::TypeWellFormedFromEnv(ty) => {
+ ty::PredicateKind::TypeWellFormedFromEnv(ty) => {
self.add_ty(ty);
}
}
diff --git a/compiler/rustc_middle/src/ty/inhabitedness/def_id_forest.rs b/compiler/rustc_middle/src/ty/inhabitedness/def_id_forest.rs
index d9aebfc..275384e 100644
--- a/compiler/rustc_middle/src/ty/inhabitedness/def_id_forest.rs
+++ b/compiler/rustc_middle/src/ty/inhabitedness/def_id_forest.rs
@@ -3,6 +3,9 @@
use rustc_hir::CRATE_HIR_ID;
use smallvec::SmallVec;
use std::mem;
+use std::sync::Arc;
+
+use DefIdForest::*;
/// Represents a forest of `DefId`s closed under the ancestor relation. That is,
/// if a `DefId` representing a module is contained in the forest then all
@@ -11,45 +14,77 @@
///
/// This is used to represent a set of modules in which a type is visibly
/// uninhabited.
-#[derive(Clone)]
-pub struct DefIdForest {
- /// The minimal set of `DefId`s required to represent the whole set.
- /// If A and B are DefIds in the `DefIdForest`, and A is a descendant
- /// of B, then only B will be in `root_ids`.
- /// We use a `SmallVec` here because (for its use for caching inhabitedness)
- /// it's rare that this will contain even two IDs.
- root_ids: SmallVec<[DefId; 1]>,
+///
+/// We store the minimal set of `DefId`s required to represent the whole set. If A and B are
+/// `DefId`s in the `DefIdForest`, and A is a parent of B, then only A will be stored. When this is
+/// used with `type_uninhabited_from`, there will very rarely be more than one `DefId` stored.
+#[derive(Clone, HashStable, Debug)]
+pub enum DefIdForest {
+ Empty,
+ Single(DefId),
+ /// This variant is very rare.
+ /// Invariant: >1 elements
+ /// We use `Arc` because this is used in the output of a query.
+ Multiple(Arc<[DefId]>),
+}
+
+/// Tests whether a slice of roots contains a given DefId.
+#[inline]
+fn slice_contains(tcx: TyCtxt<'tcx>, slice: &[DefId], id: DefId) -> bool {
+ slice.iter().any(|root_id| tcx.is_descendant_of(id, *root_id))
}
impl<'tcx> DefIdForest {
/// Creates an empty forest.
pub fn empty() -> DefIdForest {
- DefIdForest { root_ids: SmallVec::new() }
+ DefIdForest::Empty
}
/// Creates a forest consisting of a single tree representing the entire
/// crate.
#[inline]
pub fn full(tcx: TyCtxt<'tcx>) -> DefIdForest {
- let crate_id = tcx.hir().local_def_id(CRATE_HIR_ID);
- DefIdForest::from_id(crate_id.to_def_id())
+ DefIdForest::from_id(tcx.hir().local_def_id(CRATE_HIR_ID).to_def_id())
}
/// Creates a forest containing a `DefId` and all its descendants.
pub fn from_id(id: DefId) -> DefIdForest {
- let mut root_ids = SmallVec::new();
- root_ids.push(id);
- DefIdForest { root_ids }
+ DefIdForest::Single(id)
+ }
+
+ fn as_slice(&self) -> &[DefId] {
+ match self {
+ Empty => &[],
+ Single(id) => std::slice::from_ref(id),
+ Multiple(root_ids) => root_ids,
+ }
+ }
+
+ // Only allocates in the rare `Multiple` case.
+ fn from_slice(root_ids: &[DefId]) -> DefIdForest {
+ match root_ids {
+ [] => Empty,
+ [id] => Single(*id),
+ _ => DefIdForest::Multiple(root_ids.into()),
+ }
}
/// Tests whether the forest is empty.
pub fn is_empty(&self) -> bool {
- self.root_ids.is_empty()
+ match self {
+ Empty => true,
+ Single(..) | Multiple(..) => false,
+ }
+ }
+
+ /// Iterate over the set of roots.
+ fn iter(&self) -> impl Iterator<Item = DefId> + '_ {
+ self.as_slice().iter().copied()
}
/// Tests whether the forest contains a given DefId.
pub fn contains(&self, tcx: TyCtxt<'tcx>, id: DefId) -> bool {
- self.root_ids.iter().any(|root_id| tcx.is_descendant_of(id, *root_id))
+ slice_contains(tcx, self.as_slice(), id)
}
/// Calculate the intersection of a collection of forests.
@@ -58,35 +93,28 @@
I: IntoIterator<Item = DefIdForest>,
{
let mut iter = iter.into_iter();
- let mut ret = if let Some(first) = iter.next() {
- first
+ let mut ret: SmallVec<[_; 1]> = if let Some(first) = iter.next() {
+ SmallVec::from_slice(first.as_slice())
} else {
return DefIdForest::full(tcx);
};
- let mut next_ret = SmallVec::new();
- let mut old_ret: SmallVec<[DefId; 1]> = SmallVec::new();
+ let mut next_ret: SmallVec<[_; 1]> = SmallVec::new();
for next_forest in iter {
// No need to continue if the intersection is already empty.
- if ret.is_empty() {
- break;
+ if ret.is_empty() || next_forest.is_empty() {
+ return DefIdForest::empty();
}
- for id in ret.root_ids.drain(..) {
- if next_forest.contains(tcx, id) {
- next_ret.push(id);
- } else {
- old_ret.push(id);
- }
- }
- ret.root_ids.extend(old_ret.drain(..));
+ // We keep the elements in `ret` that are also in `next_forest`.
+ next_ret.extend(ret.iter().copied().filter(|&id| next_forest.contains(tcx, id)));
+ // We keep the elements in `next_forest` that are also in `ret`.
+ next_ret.extend(next_forest.iter().filter(|&id| slice_contains(tcx, &ret, id)));
- next_ret.extend(next_forest.root_ids.into_iter().filter(|&id| ret.contains(tcx, id)));
-
- mem::swap(&mut next_ret, &mut ret.root_ids);
- next_ret.drain(..);
+ mem::swap(&mut next_ret, &mut ret);
+ next_ret.clear();
}
- ret
+ DefIdForest::from_slice(&ret)
}
/// Calculate the union of a collection of forests.
@@ -94,20 +122,26 @@
where
I: IntoIterator<Item = DefIdForest>,
{
- let mut ret = DefIdForest::empty();
- let mut next_ret = SmallVec::new();
+ let mut ret: SmallVec<[_; 1]> = SmallVec::new();
+ let mut next_ret: SmallVec<[_; 1]> = SmallVec::new();
for next_forest in iter {
- next_ret.extend(ret.root_ids.drain(..).filter(|&id| !next_forest.contains(tcx, id)));
+ // Union with the empty set is a no-op.
+ if next_forest.is_empty() {
+ continue;
+ }
- for id in next_forest.root_ids {
- if !next_ret.contains(&id) {
+ // We add everything in `ret` that is not in `next_forest`.
+ next_ret.extend(ret.iter().copied().filter(|&id| !next_forest.contains(tcx, id)));
+ // We add everything in `next_forest` that we haven't added yet.
+ for id in next_forest.iter() {
+ if !slice_contains(tcx, &next_ret, id) {
next_ret.push(id);
}
}
- mem::swap(&mut next_ret, &mut ret.root_ids);
- next_ret.drain(..);
+ mem::swap(&mut next_ret, &mut ret);
+ next_ret.clear();
}
- ret
+ DefIdForest::from_slice(&ret)
}
}
diff --git a/compiler/rustc_middle/src/ty/inhabitedness/mod.rs b/compiler/rustc_middle/src/ty/inhabitedness/mod.rs
index 2f7707b..119cb13 100644
--- a/compiler/rustc_middle/src/ty/inhabitedness/mod.rs
+++ b/compiler/rustc_middle/src/ty/inhabitedness/mod.rs
@@ -6,7 +6,6 @@
use crate::ty::{AdtDef, FieldDef, Ty, TyS, VariantDef};
use crate::ty::{AdtKind, Visibility};
use crate::ty::{DefId, SubstsRef};
-use rustc_data_structures::stack::ensure_sufficient_stack;
mod def_id_forest;
@@ -187,34 +186,46 @@
impl<'tcx> TyS<'tcx> {
/// Calculates the forest of `DefId`s from which this type is visibly uninhabited.
- fn uninhabited_from(&self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> DefIdForest {
- match *self.kind() {
- Adt(def, substs) => {
- ensure_sufficient_stack(|| def.uninhabited_from(tcx, substs, param_env))
- }
+ fn uninhabited_from(
+ &'tcx self,
+ tcx: TyCtxt<'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ ) -> DefIdForest {
+ tcx.type_uninhabited_from(param_env.and(self))
+ }
+}
- Never => DefIdForest::full(tcx),
+// Query provider for `type_uninhabited_from`.
+pub(crate) fn type_uninhabited_from<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ key: ty::ParamEnvAnd<'tcx, Ty<'tcx>>,
+) -> DefIdForest {
+ let ty = key.value;
+ let param_env = key.param_env;
+ match *ty.kind() {
+ Adt(def, substs) => def.uninhabited_from(tcx, substs, param_env),
- Tuple(ref tys) => DefIdForest::union(
- tcx,
- tys.iter().map(|ty| ty.expect_ty().uninhabited_from(tcx, param_env)),
- ),
+ Never => DefIdForest::full(tcx),
- Array(ty, len) => match len.try_eval_usize(tcx, param_env) {
- Some(0) | None => DefIdForest::empty(),
- // If the array is definitely non-empty, it's uninhabited if
- // the type of its elements is uninhabited.
- Some(1..) => ty.uninhabited_from(tcx, param_env),
- },
+ Tuple(ref tys) => DefIdForest::union(
+ tcx,
+ tys.iter().map(|ty| ty.expect_ty().uninhabited_from(tcx, param_env)),
+ ),
- // References to uninitialised memory are valid for any type, including
- // uninhabited types, in unsafe code, so we treat all references as
- // inhabited.
- // The precise semantics of inhabitedness with respect to references is currently
- // undecided.
- Ref(..) => DefIdForest::empty(),
+ Array(ty, len) => match len.try_eval_usize(tcx, param_env) {
+ Some(0) | None => DefIdForest::empty(),
+ // If the array is definitely non-empty, it's uninhabited if
+ // the type of its elements is uninhabited.
+ Some(1..) => ty.uninhabited_from(tcx, param_env),
+ },
- _ => DefIdForest::empty(),
- }
+ // References to uninitialised memory are valid for any type, including
+ // uninhabited types, in unsafe code, so we treat all references as
+ // inhabited.
+ // The precise semantics of inhabitedness with respect to references is currently
+ // undecided.
+ Ref(..) => DefIdForest::empty(),
+
+ _ => DefIdForest::empty(),
}
}
diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs
index 413c9cc..6ca5dcc 100644
--- a/compiler/rustc_middle/src/ty/instance.rs
+++ b/compiler/rustc_middle/src/ty/instance.rs
@@ -535,7 +535,7 @@
} else {
None
};
- let has_upvars = upvars_ty.map(|ty| ty.tuple_fields().count() > 0).unwrap_or(false);
+ let has_upvars = upvars_ty.map_or(false, |ty| ty.tuple_fields().count() > 0);
debug!("polymorphize: upvars_ty={:?} has_upvars={:?}", upvars_ty, has_upvars);
struct PolymorphizationFolder<'tcx> {
diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs
index b545b92..596e4f6 100644
--- a/compiler/rustc_middle/src/ty/layout.rs
+++ b/compiler/rustc_middle/src/ty/layout.rs
@@ -4,7 +4,7 @@
use crate::ty::subst::Subst;
use crate::ty::{self, subst::SubstsRef, ReprOptions, Ty, TyCtxt, TypeFoldable};
-use rustc_ast::{self as ast, IntTy, UintTy};
+use rustc_ast as ast;
use rustc_attr as attr;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_hir as hir;
@@ -30,6 +30,8 @@
pub trait IntegerExt {
fn to_ty<'tcx>(&self, tcx: TyCtxt<'tcx>, signed: bool) -> Ty<'tcx>;
fn from_attr<C: HasDataLayout>(cx: &C, ity: attr::IntType) -> Integer;
+ fn from_int_ty<C: HasDataLayout>(cx: &C, ity: ty::IntTy) -> Integer;
+ fn from_uint_ty<C: HasDataLayout>(cx: &C, uty: ty::UintTy) -> Integer;
fn repr_discr<'tcx>(
tcx: TyCtxt<'tcx>,
ty: Ty<'tcx>,
@@ -60,17 +62,38 @@
let dl = cx.data_layout();
match ity {
- attr::SignedInt(IntTy::I8) | attr::UnsignedInt(UintTy::U8) => I8,
- attr::SignedInt(IntTy::I16) | attr::UnsignedInt(UintTy::U16) => I16,
- attr::SignedInt(IntTy::I32) | attr::UnsignedInt(UintTy::U32) => I32,
- attr::SignedInt(IntTy::I64) | attr::UnsignedInt(UintTy::U64) => I64,
- attr::SignedInt(IntTy::I128) | attr::UnsignedInt(UintTy::U128) => I128,
- attr::SignedInt(IntTy::Isize) | attr::UnsignedInt(UintTy::Usize) => {
+ attr::SignedInt(ast::IntTy::I8) | attr::UnsignedInt(ast::UintTy::U8) => I8,
+ attr::SignedInt(ast::IntTy::I16) | attr::UnsignedInt(ast::UintTy::U16) => I16,
+ attr::SignedInt(ast::IntTy::I32) | attr::UnsignedInt(ast::UintTy::U32) => I32,
+ attr::SignedInt(ast::IntTy::I64) | attr::UnsignedInt(ast::UintTy::U64) => I64,
+ attr::SignedInt(ast::IntTy::I128) | attr::UnsignedInt(ast::UintTy::U128) => I128,
+ attr::SignedInt(ast::IntTy::Isize) | attr::UnsignedInt(ast::UintTy::Usize) => {
dl.ptr_sized_integer()
}
}
}
+ fn from_int_ty<C: HasDataLayout>(cx: &C, ity: ty::IntTy) -> Integer {
+ match ity {
+ ty::IntTy::I8 => I8,
+ ty::IntTy::I16 => I16,
+ ty::IntTy::I32 => I32,
+ ty::IntTy::I64 => I64,
+ ty::IntTy::I128 => I128,
+ ty::IntTy::Isize => cx.data_layout().ptr_sized_integer(),
+ }
+ }
+ fn from_uint_ty<C: HasDataLayout>(cx: &C, ity: ty::UintTy) -> Integer {
+ match ity {
+ ty::UintTy::U8 => I8,
+ ty::UintTy::U16 => I16,
+ ty::UintTy::U32 => I32,
+ ty::UintTy::U64 => I64,
+ ty::UintTy::U128 => I128,
+ ty::UintTy::Usize => cx.data_layout().ptr_sized_integer(),
+ }
+ }
+
/// Finds the appropriate Integer type and signedness for the given
/// signed discriminant range and `#[repr]` attribute.
/// N.B.: `u128` values above `i128::MAX` will be treated as signed, but
@@ -487,11 +510,11 @@
self,
Scalar { value: Int(I32, false), valid_range: 0..=0x10FFFF },
)),
- ty::Int(ity) => scalar(Int(Integer::from_attr(dl, attr::SignedInt(ity)), true)),
- ty::Uint(ity) => scalar(Int(Integer::from_attr(dl, attr::UnsignedInt(ity)), false)),
+ ty::Int(ity) => scalar(Int(Integer::from_int_ty(dl, ity), true)),
+ ty::Uint(ity) => scalar(Int(Integer::from_uint_ty(dl, ity), false)),
ty::Float(fty) => scalar(match fty {
- ast::FloatTy::F32 => F32,
- ast::FloatTy::F64 => F64,
+ ty::FloatTy::F32 => F32,
+ ty::FloatTy::F64 => F64,
}),
ty::FnPtr(_) => {
let mut ptr = scalar_unit(Pointer);
@@ -1466,10 +1489,12 @@
) -> Result<&'tcx Layout, LayoutError<'tcx>> {
use SavedLocalEligibility::*;
let tcx = self.tcx;
-
let subst_field = |ty: Ty<'tcx>| ty.subst(tcx, substs);
- let info = tcx.generator_layout(def_id);
+ let info = match tcx.generator_layout(def_id) {
+ None => return Err(LayoutError::Unknown(ty)),
+ Some(info) => info,
+ };
let (ineligible_locals, assignments) = self.generator_saved_local_eligibility(&info);
// Build a prefix layout, including "promoting" all ineligible
@@ -1634,7 +1659,7 @@
let layout = tcx.intern_layout(Layout {
variants: Variants::Multiple {
- tag: tag,
+ tag,
tag_encoding: TagEncoding::Direct,
tag_field: tag_index,
variants,
@@ -2512,7 +2537,7 @@
extra_args: &[Ty<'tcx>],
caller_location: Option<Ty<'tcx>>,
codegen_fn_attr_flags: CodegenFnAttrFlags,
- mk_arg_type: impl Fn(Ty<'tcx>, Option<usize>) -> ArgAbi<'tcx, Ty<'tcx>>,
+ make_self_ptr_thin: bool,
) -> Self;
fn adjust_for_abi(&mut self, cx: &C, abi: SpecAbi);
}
@@ -2572,9 +2597,7 @@
// Assume that fn pointers may always unwind
let codegen_fn_attr_flags = CodegenFnAttrFlags::UNWIND;
- call::FnAbi::new_internal(cx, sig, extra_args, None, codegen_fn_attr_flags, |ty, _| {
- ArgAbi::new(cx.layout_of(ty))
- })
+ call::FnAbi::new_internal(cx, sig, extra_args, None, codegen_fn_attr_flags, false)
}
fn of_instance(cx: &C, instance: ty::Instance<'tcx>, extra_args: &[Ty<'tcx>]) -> Self {
@@ -2588,55 +2611,14 @@
let attrs = cx.tcx().codegen_fn_attrs(instance.def_id()).flags;
- call::FnAbi::new_internal(cx, sig, extra_args, caller_location, attrs, |ty, arg_idx| {
- let mut layout = cx.layout_of(ty);
- // Don't pass the vtable, it's not an argument of the virtual fn.
- // Instead, pass just the data pointer, but give it the type `*const/mut dyn Trait`
- // or `&/&mut dyn Trait` because this is special-cased elsewhere in codegen
- if let (ty::InstanceDef::Virtual(..), Some(0)) = (&instance.def, arg_idx) {
- let fat_pointer_ty = if layout.is_unsized() {
- // unsized `self` is passed as a pointer to `self`
- // FIXME (mikeyhew) change this to use &own if it is ever added to the language
- cx.tcx().mk_mut_ptr(layout.ty)
- } else {
- match layout.abi {
- Abi::ScalarPair(..) => (),
- _ => bug!("receiver type has unsupported layout: {:?}", layout),
- }
-
- // In the case of Rc<Self>, we need to explicitly pass a *mut RcBox<Self>
- // with a Scalar (not ScalarPair) ABI. This is a hack that is understood
- // elsewhere in the compiler as a method on a `dyn Trait`.
- // To get the type `*mut RcBox<Self>`, we just keep unwrapping newtypes until we
- // get a built-in pointer type
- let mut fat_pointer_layout = layout;
- 'descend_newtypes: while !fat_pointer_layout.ty.is_unsafe_ptr()
- && !fat_pointer_layout.ty.is_region_ptr()
- {
- for i in 0..fat_pointer_layout.fields.count() {
- let field_layout = fat_pointer_layout.field(cx, i);
-
- if !field_layout.is_zst() {
- fat_pointer_layout = field_layout;
- continue 'descend_newtypes;
- }
- }
-
- bug!("receiver has no non-zero-sized fields {:?}", fat_pointer_layout);
- }
-
- fat_pointer_layout.ty
- };
-
- // we now have a type like `*mut RcBox<dyn Trait>`
- // change its layout to that of `*mut ()`, a thin pointer, but keep the same type
- // this is understood as a special case elsewhere in the compiler
- let unit_pointer_ty = cx.tcx().mk_mut_ptr(cx.tcx().mk_unit());
- layout = cx.layout_of(unit_pointer_ty);
- layout.ty = fat_pointer_ty;
- }
- ArgAbi::new(layout)
- })
+ call::FnAbi::new_internal(
+ cx,
+ sig,
+ extra_args,
+ caller_location,
+ attrs,
+ matches!(instance.def, ty::InstanceDef::Virtual(..)),
+ )
}
fn new_internal(
@@ -2645,7 +2627,7 @@
extra_args: &[Ty<'tcx>],
caller_location: Option<Ty<'tcx>>,
codegen_fn_attr_flags: CodegenFnAttrFlags,
- mk_arg_type: impl Fn(Ty<'tcx>, Option<usize>) -> ArgAbi<'tcx, Ty<'tcx>>,
+ force_thin_self_ptr: bool,
) -> Self {
debug!("FnAbi::new_internal({:?}, {:?})", sig, extra_args);
@@ -2668,6 +2650,7 @@
Win64 => Conv::X86_64Win64,
SysV64 => Conv::X86_64SysV,
Aapcs => Conv::ArmAapcs,
+ CCmseNonSecureCall => Conv::CCmseNonSecureCall,
PtxKernel => Conv::PtxKernel,
Msp430Interrupt => Conv::Msp430Intr,
X86Interrupt => Conv::X86Intr,
@@ -2776,7 +2759,23 @@
let arg_of = |ty: Ty<'tcx>, arg_idx: Option<usize>| {
let is_return = arg_idx.is_none();
- let mut arg = mk_arg_type(ty, arg_idx);
+
+ let layout = cx.layout_of(ty);
+ let layout = if force_thin_self_ptr && arg_idx == Some(0) {
+ // Don't pass the vtable, it's not an argument of the virtual fn.
+ // Instead, pass just the data pointer, but give it the type `*const/mut dyn Trait`
+ // or `&/&mut dyn Trait` because this is special-cased elsewhere in codegen
+ make_thin_self_ptr(cx, layout)
+ } else {
+ layout
+ };
+
+ let mut arg = ArgAbi::new(cx, layout, |layout, scalar, offset| {
+ let mut attrs = ArgAttributes::new();
+ adjust_for_rust_scalar(&mut attrs, scalar, *layout, offset, is_return);
+ attrs
+ });
+
if arg.layout.is_zst() {
// For some forsaken reason, x86_64-pc-windows-gnu
// doesn't ignore zero-sized struct arguments.
@@ -2792,30 +2791,6 @@
}
}
- // FIXME(eddyb) other ABIs don't have logic for scalar pairs.
- if !is_return && rust_abi {
- if let Abi::ScalarPair(ref a, ref b) = arg.layout.abi {
- let mut a_attrs = ArgAttributes::new();
- let mut b_attrs = ArgAttributes::new();
- adjust_for_rust_scalar(&mut a_attrs, a, arg.layout, Size::ZERO, false);
- adjust_for_rust_scalar(
- &mut b_attrs,
- b,
- arg.layout,
- a.value.size(cx).align_to(b.value.align(cx).abi),
- false,
- );
- arg.mode = PassMode::Pair(a_attrs, b_attrs);
- return arg;
- }
- }
-
- if let Abi::Scalar(ref scalar) = arg.layout.abi {
- if let PassMode::Direct(ref mut attrs) = arg.mode {
- adjust_for_rust_scalar(attrs, scalar, arg.layout, Size::ZERO, is_return);
- }
- }
-
arg
};
@@ -2913,3 +2888,52 @@
}
}
}
+
+fn make_thin_self_ptr<'tcx, C>(cx: &C, mut layout: TyAndLayout<'tcx>) -> TyAndLayout<'tcx>
+where
+ C: LayoutOf<Ty = Ty<'tcx>, TyAndLayout = TyAndLayout<'tcx>>
+ + HasTyCtxt<'tcx>
+ + HasParamEnv<'tcx>,
+{
+ let fat_pointer_ty = if layout.is_unsized() {
+ // unsized `self` is passed as a pointer to `self`
+ // FIXME (mikeyhew) change this to use &own if it is ever added to the language
+ cx.tcx().mk_mut_ptr(layout.ty)
+ } else {
+ match layout.abi {
+ Abi::ScalarPair(..) => (),
+ _ => bug!("receiver type has unsupported layout: {:?}", layout),
+ }
+
+ // In the case of Rc<Self>, we need to explicitly pass a *mut RcBox<Self>
+ // with a Scalar (not ScalarPair) ABI. This is a hack that is understood
+ // elsewhere in the compiler as a method on a `dyn Trait`.
+ // To get the type `*mut RcBox<Self>`, we just keep unwrapping newtypes until we
+ // get a built-in pointer type
+ let mut fat_pointer_layout = layout;
+ 'descend_newtypes: while !fat_pointer_layout.ty.is_unsafe_ptr()
+ && !fat_pointer_layout.ty.is_region_ptr()
+ {
+ for i in 0..fat_pointer_layout.fields.count() {
+ let field_layout = fat_pointer_layout.field(cx, i);
+
+ if !field_layout.is_zst() {
+ fat_pointer_layout = field_layout;
+ continue 'descend_newtypes;
+ }
+ }
+
+ bug!("receiver has no non-zero-sized fields {:?}", fat_pointer_layout);
+ }
+
+ fat_pointer_layout.ty
+ };
+
+ // we now have a type like `*mut RcBox<dyn Trait>`
+ // change its layout to that of `*mut ()`, a thin pointer, but keep the same type
+ // this is understood as a special case elsewhere in the compiler
+ let unit_pointer_ty = cx.tcx().mk_mut_ptr(cx.tcx().mk_unit());
+ layout = cx.layout_of(unit_pointer_ty);
+ layout.ty = fat_pointer_ty;
+ layout
+}
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index 8395692..babab00 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -17,7 +17,9 @@
pub use self::Variance::*;
use crate::hir::exports::ExportMap;
-use crate::hir::place::Place as HirPlace;
+use crate::hir::place::{
+ Place as HirPlace, PlaceBase as HirPlaceBase, ProjectionKind as HirProjectionKind,
+};
use crate::ich::StableHashingContext;
use crate::middle::cstore::CrateStoreDyn;
use crate::middle::resolve_lifetime::ObjectLifetimeDefault;
@@ -63,7 +65,6 @@
use std::str;
pub use self::sty::BoundRegionKind::*;
-pub use self::sty::InferTy::*;
pub use self::sty::RegionKind;
pub use self::sty::RegionKind::*;
pub use self::sty::TyKind::*;
@@ -72,13 +73,14 @@
pub use self::sty::{CanonicalPolyFnSig, FnSig, GenSig, PolyFnSig, PolyGenSig};
pub use self::sty::{ClosureSubsts, GeneratorSubsts, TypeAndMut, UpvarSubsts};
pub use self::sty::{ClosureSubstsParts, GeneratorSubstsParts};
-pub use self::sty::{ConstVid, FloatVid, IntVid, RegionVid, TyVid};
-pub use self::sty::{ExistentialPredicate, InferTy, ParamConst, ParamTy, ProjectionTy};
+pub use self::sty::{ConstVid, RegionVid};
+pub use self::sty::{ExistentialPredicate, ParamConst, ParamTy, ProjectionTy};
pub use self::sty::{ExistentialProjection, PolyExistentialProjection};
pub use self::sty::{ExistentialTraitRef, PolyExistentialTraitRef};
pub use self::sty::{PolyTraitRef, TraitRef, TyKind};
pub use crate::ty::diagnostics::*;
-pub use rustc_type_ir::{DebruijnIndex, TypeFlags, INNERMOST};
+pub use rustc_type_ir::InferTy::*;
+pub use rustc_type_ir::*;
pub use self::binding::BindingMode;
pub use self::binding::BindingMode::*;
@@ -183,7 +185,7 @@
pub predicates: Vec<Predicate<'tcx>>,
}
-#[derive(Copy, Clone, PartialEq, TyEncodable, TyDecodable, HashStable)]
+#[derive(Copy, Clone, PartialEq, TyEncodable, TyDecodable, HashStable, Debug)]
pub enum ImplPolarity {
/// `impl Trait for Type`
Positive,
@@ -419,21 +421,13 @@
}
}
-#[derive(Copy, Clone, PartialEq, TyDecodable, TyEncodable, HashStable)]
-pub enum Variance {
- Covariant, // T<A> <: T<B> iff A <: B -- e.g., function return type
- Invariant, // T<A> <: T<B> iff B == A -- e.g., type of mutable cell
- Contravariant, // T<A> <: T<B> iff B <: A -- e.g., function param type
- Bivariant, // T<A> <: T<B> -- e.g., unused type parameter
-}
-
/// The crate variances map is computed during typeck and contains the
/// variance of every item in the local crate. You should not use it
/// directly, because to do so will make your pass dependent on the
/// HIR of every item in the local crate. Instead, use
/// `tcx.variances_of()` to get the variance for a *particular*
/// item.
-#[derive(HashStable)]
+#[derive(HashStable, Debug)]
pub struct CrateVariancesMap<'tcx> {
/// For each item with generics, maps to a vector of the variance
/// of its generics. If an item has no generics, it will have no
@@ -441,66 +435,6 @@
pub variances: FxHashMap<DefId, &'tcx [ty::Variance]>,
}
-impl Variance {
- /// `a.xform(b)` combines the variance of a context with the
- /// variance of a type with the following meaning. If we are in a
- /// context with variance `a`, and we encounter a type argument in
- /// a position with variance `b`, then `a.xform(b)` is the new
- /// variance with which the argument appears.
- ///
- /// Example 1:
- ///
- /// *mut Vec<i32>
- ///
- /// Here, the "ambient" variance starts as covariant. `*mut T` is
- /// invariant with respect to `T`, so the variance in which the
- /// `Vec<i32>` appears is `Covariant.xform(Invariant)`, which
- /// yields `Invariant`. Now, the type `Vec<T>` is covariant with
- /// respect to its type argument `T`, and hence the variance of
- /// the `i32` here is `Invariant.xform(Covariant)`, which results
- /// (again) in `Invariant`.
- ///
- /// Example 2:
- ///
- /// fn(*const Vec<i32>, *mut Vec<i32)
- ///
- /// The ambient variance is covariant. A `fn` type is
- /// contravariant with respect to its parameters, so the variance
- /// within which both pointer types appear is
- /// `Covariant.xform(Contravariant)`, or `Contravariant`. `*const
- /// T` is covariant with respect to `T`, so the variance within
- /// which the first `Vec<i32>` appears is
- /// `Contravariant.xform(Covariant)` or `Contravariant`. The same
- /// is true for its `i32` argument. In the `*mut T` case, the
- /// variance of `Vec<i32>` is `Contravariant.xform(Invariant)`,
- /// and hence the outermost type is `Invariant` with respect to
- /// `Vec<i32>` (and its `i32` argument).
- ///
- /// Source: Figure 1 of "Taming the Wildcards:
- /// Combining Definition- and Use-Site Variance" published in PLDI'11.
- pub fn xform(self, v: ty::Variance) -> ty::Variance {
- match (self, v) {
- // Figure 1, column 1.
- (ty::Covariant, ty::Covariant) => ty::Covariant,
- (ty::Covariant, ty::Contravariant) => ty::Contravariant,
- (ty::Covariant, ty::Invariant) => ty::Invariant,
- (ty::Covariant, ty::Bivariant) => ty::Bivariant,
-
- // Figure 1, column 2.
- (ty::Contravariant, ty::Covariant) => ty::Contravariant,
- (ty::Contravariant, ty::Contravariant) => ty::Covariant,
- (ty::Contravariant, ty::Invariant) => ty::Invariant,
- (ty::Contravariant, ty::Bivariant) => ty::Bivariant,
-
- // Figure 1, column 3.
- (ty::Invariant, _) => ty::Invariant,
-
- // Figure 1, column 4.
- (ty::Bivariant, _) => ty::Bivariant,
- }
- }
-}
-
// Contains information needed to resolve types and (in the future) look up
// the types of AST nodes.
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
@@ -727,11 +661,65 @@
/// Part of `MinCaptureInformationMap`; List of `CapturePlace`s.
pub type MinCaptureList<'tcx> = Vec<CapturedPlace<'tcx>>;
-/// A `Place` and the corresponding `CaptureInfo`.
+/// A composite describing a `Place` that is captured by a closure.
#[derive(PartialEq, Clone, Debug, TyEncodable, TyDecodable, TypeFoldable, HashStable)]
pub struct CapturedPlace<'tcx> {
+ /// The `Place` that is captured.
pub place: HirPlace<'tcx>,
+
+ /// `CaptureKind` and expression(s) that resulted in such capture of `place`.
pub info: CaptureInfo<'tcx>,
+
+ /// Represents if `place` can be mutated or not.
+ pub mutability: hir::Mutability,
+}
+
+impl CapturedPlace<'tcx> {
+ /// Returns the hir-id of the root variable for the captured place.
+ /// e.g., if `a.b.c` was captured, would return the hir-id for `a`.
+ pub fn get_root_variable(&self) -> hir::HirId {
+ match self.place.base {
+ HirPlaceBase::Upvar(upvar_id) => upvar_id.var_path.hir_id,
+ base => bug!("Expected upvar, found={:?}", base),
+ }
+ }
+}
+
+pub fn place_to_string_for_capture(tcx: TyCtxt<'tcx>, place: &HirPlace<'tcx>) -> String {
+ let name = match place.base {
+ HirPlaceBase::Upvar(upvar_id) => tcx.hir().name(upvar_id.var_path.hir_id).to_string(),
+ _ => bug!("Capture_information should only contain upvars"),
+ };
+ let mut curr_string = name;
+
+ for (i, proj) in place.projections.iter().enumerate() {
+ match proj.kind {
+ HirProjectionKind::Deref => {
+ curr_string = format!("*{}", curr_string);
+ }
+ HirProjectionKind::Field(idx, variant) => match place.ty_before_projection(i).kind() {
+ ty::Adt(def, ..) => {
+ curr_string = format!(
+ "{}.{}",
+ curr_string,
+ def.variants[variant].fields[idx as usize].ident.name.as_str()
+ );
+ }
+ ty::Tuple(_) => {
+ curr_string = format!("{}.{}", curr_string, idx);
+ }
+ _ => {
+ bug!(
+ "Field projection applied to a type other than Adt or Tuple: {:?}.",
+ place.ty_before_projection(i).kind()
+ )
+ }
+ },
+ proj => bug!("{:?} unexpected because it isn't captured", proj),
+ }
+ }
+
+ curr_string.to_string()
}
/// Part of `MinCaptureInformationMap`; describes the capture kind (&, &mut, move)
@@ -741,8 +729,20 @@
pub struct CaptureInfo<'tcx> {
/// Expr Id pointing to use that resulted in selecting the current capture kind
///
+ /// Eg:
+ /// ```rust,no_run
+ /// let mut t = (0,1);
+ ///
+ /// let c = || {
+ /// println!("{}",t); // L1
+ /// t.1 = 4; // L2
+ /// };
+ /// ```
+ /// `capture_kind_expr_id` will point to the use on L2 and `path_expr_id` will point to the
+ /// use on L1.
+ ///
/// If the user doesn't enable feature `capture_disjoint_fields` (RFC 2229) then, it is
- /// possible that we don't see the use of a particular place resulting in expr_id being
+ /// possible that we don't see the use of a particular place resulting in capture_kind_expr_id being
/// None. In such case we fallback on uvpars_mentioned for span.
///
/// Eg:
@@ -756,7 +756,12 @@
///
/// In this example, if `capture_disjoint_fields` is **not** set, then x will be captured,
/// but we won't see it being used during capture analysis, since it's essentially a discard.
- pub expr_id: Option<hir::HirId>,
+ pub capture_kind_expr_id: Option<hir::HirId>,
+ /// Expr Id pointing to use that resulted the corresponding place being captured
+ ///
+ /// See `capture_kind_expr_id` for example.
+ ///
+ pub path_expr_id: Option<hir::HirId>,
/// Capture mode that was selected
pub capture_kind: UpvarCapture<'tcx>,
@@ -765,15 +770,6 @@
pub type UpvarListMap = FxHashMap<DefId, FxIndexMap<hir::HirId, UpvarId>>;
pub type UpvarCaptureMap<'tcx> = FxHashMap<UpvarId, UpvarCapture<'tcx>>;
-#[derive(Clone, Copy, PartialEq, Eq)]
-pub enum IntVarValue {
- IntType(ast::IntTy),
- UintType(ast::UintTy),
-}
-
-#[derive(Clone, Copy, PartialEq, Eq)]
-pub struct FloatVarValue(pub ast::FloatTy);
-
impl ty::EarlyBoundRegion {
/// Does this early bound region have a name? Early bound regions normally
/// always have names except when using anonymous lifetimes (`'_`).
@@ -801,6 +797,15 @@
GenericParamDefKind::Const => "constant",
}
}
+ pub fn to_ord(&self, tcx: TyCtxt<'_>) -> ast::ParamKindOrd {
+ match self {
+ GenericParamDefKind::Lifetime => ast::ParamKindOrd::Lifetime,
+ GenericParamDefKind::Type { .. } => ast::ParamKindOrd::Type,
+ GenericParamDefKind::Const => {
+ ast::ParamKindOrd::Const { unordered: tcx.features().const_generics }
+ }
+ }
+ }
}
#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable)]
@@ -862,19 +867,37 @@
// We could cache this as a property of `GenericParamCount`, but
// the aim is to refactor this away entirely eventually and the
// presence of this method will be a constant reminder.
- let mut own_counts: GenericParamCount = Default::default();
+ let mut own_counts = GenericParamCount::default();
for param in &self.params {
match param.kind {
GenericParamDefKind::Lifetime => own_counts.lifetimes += 1,
GenericParamDefKind::Type { .. } => own_counts.types += 1,
GenericParamDefKind::Const => own_counts.consts += 1,
- };
+ }
}
own_counts
}
+ pub fn own_defaults(&self) -> GenericParamCount {
+ let mut own_defaults = GenericParamCount::default();
+
+ for param in &self.params {
+ match param.kind {
+ GenericParamDefKind::Lifetime => (),
+ GenericParamDefKind::Type { has_default, .. } => {
+ own_defaults.types += has_default as usize;
+ }
+ GenericParamDefKind::Const => {
+ // FIXME(const_generics:defaults)
+ }
+ }
+ }
+
+ own_defaults
+ }
+
pub fn requires_monomorphization(&self, tcx: TyCtxt<'tcx>) -> bool {
if self.own_requires_monomorphization() {
return true;
@@ -1003,14 +1026,14 @@
#[derive(Debug)]
crate struct PredicateInner<'tcx> {
- kind: PredicateKind<'tcx>,
+ kind: Binder<PredicateKind<'tcx>>,
flags: TypeFlags,
/// See the comment for the corresponding field of [TyS].
outer_exclusive_binder: ty::DebruijnIndex,
}
#[cfg(target_arch = "x86_64")]
-static_assert_size!(PredicateInner<'_>, 48);
+static_assert_size!(PredicateInner<'_>, 40);
#[derive(Clone, Copy, Lift)]
pub struct Predicate<'tcx> {
@@ -1033,59 +1056,9 @@
impl<'tcx> Eq for Predicate<'tcx> {}
impl<'tcx> Predicate<'tcx> {
- #[inline(always)]
- pub fn kind(self) -> &'tcx PredicateKind<'tcx> {
- &self.inner.kind
- }
-
- /// Returns the inner `PredicateAtom`.
- ///
- /// The returned atom may contain unbound variables bound to binders skipped in this method.
- /// It is safe to reapply binders to the given atom.
- ///
- /// Note that this method panics in case this predicate has unbound variables.
- pub fn skip_binders(self) -> PredicateAtom<'tcx> {
- match self.kind() {
- &PredicateKind::ForAll(binder) => binder.skip_binder(),
- &PredicateKind::Atom(atom) => {
- debug_assert!(!atom.has_escaping_bound_vars());
- atom
- }
- }
- }
-
- /// Returns the inner `PredicateAtom`.
- ///
- /// Note that this method does not check if the predicate has unbound variables.
- ///
- /// Rebinding the returned atom can causes the previously bound variables
- /// to end up at the wrong binding level.
- pub fn skip_binders_unchecked(self) -> PredicateAtom<'tcx> {
- match self.kind() {
- &PredicateKind::ForAll(binder) => binder.skip_binder(),
- &PredicateKind::Atom(atom) => atom,
- }
- }
-
- /// Converts this to a `Binder<PredicateAtom<'tcx>>`. If the value was an
- /// `Atom`, then it is not allowed to contain escaping bound vars.
- pub fn bound_atom(self) -> Binder<PredicateAtom<'tcx>> {
- match self.kind() {
- &PredicateKind::ForAll(binder) => binder,
- &PredicateKind::Atom(atom) => {
- debug_assert!(!atom.has_escaping_bound_vars());
- Binder::dummy(atom)
- }
- }
- }
-
- /// Allows using a `Binder<PredicateAtom<'tcx>>` even if the given predicate previously
- /// contained unbound variables by shifting these variables outwards.
- pub fn bound_atom_with_opt_escaping(self, tcx: TyCtxt<'tcx>) -> Binder<PredicateAtom<'tcx>> {
- match self.kind() {
- &PredicateKind::ForAll(binder) => binder,
- &PredicateKind::Atom(atom) => Binder::wrap_nonbinding(tcx, atom),
- }
+ /// Gets the inner `Binder<PredicateKind<'tcx>>`.
+ pub fn kind(self) -> Binder<PredicateKind<'tcx>> {
+ self.inner.kind
}
}
@@ -1107,14 +1080,6 @@
#[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable)]
#[derive(HashStable, TypeFoldable)]
pub enum PredicateKind<'tcx> {
- /// `for<'a>: ...`
- ForAll(Binder<PredicateAtom<'tcx>>),
- Atom(PredicateAtom<'tcx>),
-}
-
-#[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable)]
-#[derive(HashStable, TypeFoldable)]
-pub enum PredicateAtom<'tcx> {
/// Corresponds to `where Foo: Bar<A, B, C>`. `Foo` here would be
/// the `Self` type of the trait reference and `A`, `B`, and `C`
/// would be the type parameters.
@@ -1160,28 +1125,13 @@
TypeWellFormedFromEnv(Ty<'tcx>),
}
-impl<'tcx> Binder<PredicateAtom<'tcx>> {
- /// Wraps `self` with the given qualifier if this predicate has any unbound variables.
- pub fn potentially_quantified(
- self,
- tcx: TyCtxt<'tcx>,
- qualifier: impl FnOnce(Binder<PredicateAtom<'tcx>>) -> PredicateKind<'tcx>,
- ) -> Predicate<'tcx> {
- match self.no_bound_vars() {
- Some(atom) => PredicateKind::Atom(atom),
- None => qualifier(self),
- }
- .to_predicate(tcx)
- }
-}
-
/// The crate outlives map is computed during typeck and contains the
/// outlives of every item in the local crate. You should not use it
/// directly, because to do so will make your pass dependent on the
/// HIR of every item in the local crate. Instead, use
/// `tcx.inferred_outlives_of()` to get the outlives for a *particular*
/// item.
-#[derive(HashStable)]
+#[derive(HashStable, Debug)]
pub struct CratePredicatesMap<'tcx> {
/// For each struct with outlive bounds, maps to a vector of the
/// predicate of its outlive bounds. If an item has no outlives
@@ -1260,13 +1210,9 @@
// from the substitution and the value being substituted into, and
// this trick achieves that).
let substs = trait_ref.skip_binder().substs;
- let pred = self.skip_binders();
+ let pred = self.kind().skip_binder();
let new = pred.subst(tcx, substs);
- if new != pred {
- ty::Binder::bind(new).potentially_quantified(tcx, PredicateKind::ForAll)
- } else {
- self
- }
+ tcx.reuse_or_mk_predicate(self, ty::Binder::bind(new))
}
}
@@ -1387,24 +1333,23 @@
fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx>;
}
-impl ToPredicate<'tcx> for PredicateKind<'tcx> {
+impl ToPredicate<'tcx> for Binder<PredicateKind<'tcx>> {
#[inline(always)]
fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
tcx.mk_predicate(self)
}
}
-impl ToPredicate<'tcx> for PredicateAtom<'tcx> {
+impl ToPredicate<'tcx> for PredicateKind<'tcx> {
#[inline(always)]
fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
- debug_assert!(!self.has_escaping_bound_vars(), "escaping bound vars for {:?}", self);
- tcx.mk_predicate(PredicateKind::Atom(self))
+ tcx.mk_predicate(Binder::dummy(self))
}
}
impl<'tcx> ToPredicate<'tcx> for ConstnessAnd<TraitRef<'tcx>> {
fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
- PredicateAtom::Trait(ty::TraitPredicate { trait_ref: self.value }, self.constness)
+ PredicateKind::Trait(ty::TraitPredicate { trait_ref: self.value }, self.constness)
.to_predicate(tcx)
}
}
@@ -1421,67 +1366,62 @@
impl<'tcx> ToPredicate<'tcx> for ConstnessAnd<PolyTraitPredicate<'tcx>> {
fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
- self.value
- .map_bound(|value| PredicateAtom::Trait(value, self.constness))
- .potentially_quantified(tcx, PredicateKind::ForAll)
+ self.value.map_bound(|value| PredicateKind::Trait(value, self.constness)).to_predicate(tcx)
}
}
impl<'tcx> ToPredicate<'tcx> for PolyRegionOutlivesPredicate<'tcx> {
fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
- self.map_bound(|value| PredicateAtom::RegionOutlives(value))
- .potentially_quantified(tcx, PredicateKind::ForAll)
+ self.map_bound(PredicateKind::RegionOutlives).to_predicate(tcx)
}
}
impl<'tcx> ToPredicate<'tcx> for PolyTypeOutlivesPredicate<'tcx> {
fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
- self.map_bound(|value| PredicateAtom::TypeOutlives(value))
- .potentially_quantified(tcx, PredicateKind::ForAll)
+ self.map_bound(PredicateKind::TypeOutlives).to_predicate(tcx)
}
}
impl<'tcx> ToPredicate<'tcx> for PolyProjectionPredicate<'tcx> {
fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
- self.map_bound(|value| PredicateAtom::Projection(value))
- .potentially_quantified(tcx, PredicateKind::ForAll)
+ self.map_bound(PredicateKind::Projection).to_predicate(tcx)
}
}
impl<'tcx> Predicate<'tcx> {
pub fn to_opt_poly_trait_ref(self) -> Option<ConstnessAnd<PolyTraitRef<'tcx>>> {
- let predicate = self.bound_atom();
+ let predicate = self.kind();
match predicate.skip_binder() {
- PredicateAtom::Trait(t, constness) => {
+ PredicateKind::Trait(t, constness) => {
Some(ConstnessAnd { constness, value: predicate.rebind(t.trait_ref) })
}
- PredicateAtom::Projection(..)
- | PredicateAtom::Subtype(..)
- | PredicateAtom::RegionOutlives(..)
- | PredicateAtom::WellFormed(..)
- | PredicateAtom::ObjectSafe(..)
- | PredicateAtom::ClosureKind(..)
- | PredicateAtom::TypeOutlives(..)
- | PredicateAtom::ConstEvaluatable(..)
- | PredicateAtom::ConstEquate(..)
- | PredicateAtom::TypeWellFormedFromEnv(..) => None,
+ PredicateKind::Projection(..)
+ | PredicateKind::Subtype(..)
+ | PredicateKind::RegionOutlives(..)
+ | PredicateKind::WellFormed(..)
+ | PredicateKind::ObjectSafe(..)
+ | PredicateKind::ClosureKind(..)
+ | PredicateKind::TypeOutlives(..)
+ | PredicateKind::ConstEvaluatable(..)
+ | PredicateKind::ConstEquate(..)
+ | PredicateKind::TypeWellFormedFromEnv(..) => None,
}
}
pub fn to_opt_type_outlives(self) -> Option<PolyTypeOutlivesPredicate<'tcx>> {
- let predicate = self.bound_atom();
+ let predicate = self.kind();
match predicate.skip_binder() {
- PredicateAtom::TypeOutlives(data) => Some(predicate.rebind(data)),
- PredicateAtom::Trait(..)
- | PredicateAtom::Projection(..)
- | PredicateAtom::Subtype(..)
- | PredicateAtom::RegionOutlives(..)
- | PredicateAtom::WellFormed(..)
- | PredicateAtom::ObjectSafe(..)
- | PredicateAtom::ClosureKind(..)
- | PredicateAtom::ConstEvaluatable(..)
- | PredicateAtom::ConstEquate(..)
- | PredicateAtom::TypeWellFormedFromEnv(..) => None,
+ PredicateKind::TypeOutlives(data) => Some(predicate.rebind(data)),
+ PredicateKind::Trait(..)
+ | PredicateKind::Projection(..)
+ | PredicateKind::Subtype(..)
+ | PredicateKind::RegionOutlives(..)
+ | PredicateKind::WellFormed(..)
+ | PredicateKind::ObjectSafe(..)
+ | PredicateKind::ClosureKind(..)
+ | PredicateKind::ConstEvaluatable(..)
+ | PredicateKind::ConstEquate(..)
+ | PredicateKind::TypeWellFormedFromEnv(..) => None,
}
}
}
@@ -1638,8 +1578,6 @@
/// which cause cycle errors.
///
/// ```rust
-/// #![feature(const_generics)]
-///
/// struct A;
/// impl A {
/// fn foo<const N: usize>(&self) -> [u8; N] { [0; N] }
@@ -2890,19 +2828,11 @@
}
pub fn opt_associated_item(self, def_id: DefId) -> Option<&'tcx AssocItem> {
- let is_associated_item = if let Some(def_id) = def_id.as_local() {
- matches!(
- self.hir().get(self.hir().local_def_id_to_hir_id(def_id)),
- Node::TraitItem(_) | Node::ImplItem(_)
- )
+ if let DefKind::AssocConst | DefKind::AssocFn | DefKind::AssocTy = self.def_kind(def_id) {
+ Some(self.associated_item(def_id))
} else {
- matches!(
- self.def_kind(def_id),
- DefKind::AssocConst | DefKind::AssocFn | DefKind::AssocTy
- )
- };
-
- is_associated_item.then(|| self.associated_item(def_id))
+ None
+ }
}
pub fn field_index(self, hir_id: hir::HirId, typeck_results: &TypeckResults<'_>) -> usize {
@@ -3012,7 +2942,16 @@
/// Returns the possibly-auto-generated MIR of a `(DefId, Subst)` pair.
pub fn instance_mir(self, instance: ty::InstanceDef<'tcx>) -> &'tcx Body<'tcx> {
match instance {
- ty::InstanceDef::Item(def) => self.optimized_mir_opt_const_arg(def),
+ ty::InstanceDef::Item(def) => match self.def_kind(def.did) {
+ DefKind::Const
+ | DefKind::Static
+ | DefKind::AssocConst
+ | DefKind::Ctor(..)
+ | DefKind::AnonConst => self.mir_for_ctfe_opt_const_arg(def),
+ // If the caller wants `mir_for_ctfe` of a function they should not be using
+ // `instance_mir`, so we'll assume const fn also wants the optimized version.
+ _ => self.optimized_mir_or_const_arg_mir(def),
+ },
ty::InstanceDef::VtableShim(..)
| ty::InstanceDef::ReifyShim(..)
| ty::InstanceDef::Intrinsic(..)
@@ -3043,8 +2982,10 @@
self.trait_def(trait_def_id).has_auto_impl
}
- pub fn generator_layout(self, def_id: DefId) -> &'tcx GeneratorLayout<'tcx> {
- self.optimized_mir(def_id).generator_layout.as_ref().unwrap()
+ /// Returns layout of a generator. Layout might be unavailable if the
+ /// generator is tainted by errors.
+ pub fn generator_layout(self, def_id: DefId) -> Option<&'tcx GeneratorLayout<'tcx>> {
+ self.optimized_mir(def_id).generator_layout.as_ref()
}
/// Given the `DefId` of an impl, returns the `DefId` of the trait it implements.
@@ -3123,7 +3064,7 @@
}
}
-#[derive(Clone, HashStable)]
+#[derive(Clone, HashStable, Debug)]
pub struct AdtSizedConstraint<'tcx>(pub &'tcx [Ty<'tcx>]);
/// Yields the parent function's `DefId` if `def_id` is an `impl Trait` definition.
@@ -3138,6 +3079,57 @@
None
}
+pub fn int_ty(ity: ast::IntTy) -> IntTy {
+ match ity {
+ ast::IntTy::Isize => IntTy::Isize,
+ ast::IntTy::I8 => IntTy::I8,
+ ast::IntTy::I16 => IntTy::I16,
+ ast::IntTy::I32 => IntTy::I32,
+ ast::IntTy::I64 => IntTy::I64,
+ ast::IntTy::I128 => IntTy::I128,
+ }
+}
+
+pub fn uint_ty(uty: ast::UintTy) -> UintTy {
+ match uty {
+ ast::UintTy::Usize => UintTy::Usize,
+ ast::UintTy::U8 => UintTy::U8,
+ ast::UintTy::U16 => UintTy::U16,
+ ast::UintTy::U32 => UintTy::U32,
+ ast::UintTy::U64 => UintTy::U64,
+ ast::UintTy::U128 => UintTy::U128,
+ }
+}
+
+pub fn float_ty(fty: ast::FloatTy) -> FloatTy {
+ match fty {
+ ast::FloatTy::F32 => FloatTy::F32,
+ ast::FloatTy::F64 => FloatTy::F64,
+ }
+}
+
+pub fn ast_int_ty(ity: IntTy) -> ast::IntTy {
+ match ity {
+ IntTy::Isize => ast::IntTy::Isize,
+ IntTy::I8 => ast::IntTy::I8,
+ IntTy::I16 => ast::IntTy::I16,
+ IntTy::I32 => ast::IntTy::I32,
+ IntTy::I64 => ast::IntTy::I64,
+ IntTy::I128 => ast::IntTy::I128,
+ }
+}
+
+pub fn ast_uint_ty(uty: UintTy) -> ast::UintTy {
+ match uty {
+ UintTy::Usize => ast::UintTy::Usize,
+ UintTy::U8 => ast::UintTy::U8,
+ UintTy::U16 => ast::UintTy::U16,
+ UintTy::U32 => ast::UintTy::U32,
+ UintTy::U64 => ast::UintTy::U64,
+ UintTy::U128 => ast::UintTy::U128,
+ }
+}
+
pub fn provide(providers: &mut ty::query::Providers) {
context::provide(providers);
erase_regions::provide(providers);
@@ -3148,6 +3140,7 @@
*providers = ty::query::Providers {
trait_impls_of: trait_def::trait_impls_of_provider,
all_local_trait_impls: trait_def::all_local_trait_impls,
+ type_uninhabited_from: inhabitedness::type_uninhabited_from,
..*providers
};
}
diff --git a/compiler/rustc_middle/src/ty/print/mod.rs b/compiler/rustc_middle/src/ty/print/mod.rs
index c79e06b..77f1668 100644
--- a/compiler/rustc_middle/src/ty/print/mod.rs
+++ b/compiler/rustc_middle/src/ty/print/mod.rs
@@ -203,7 +203,7 @@
self.tcx().type_of(param.def_id).subst(self.tcx(), substs),
)
}
- ty::GenericParamDefKind::Const => false, // FIXME(const_generics:defaults)
+ ty::GenericParamDefKind::Const => false, // FIXME(const_generics_defaults)
}
})
.count();
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index 9b178d9..4937fdd 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -3,7 +3,6 @@
use crate::ty::subst::{GenericArg, GenericArgKind, Subst};
use crate::ty::{self, ConstInt, DefIdTree, ParamConst, ScalarInt, Ty, TyCtxt, TypeFoldable};
use rustc_apfloat::ieee::{Double, Single};
-use rustc_ast as ast;
use rustc_data_structures::fx::FxHashMap;
use rustc_hir as hir;
use rustc_hir::def::{self, CtorKind, DefKind, Namespace};
@@ -557,14 +556,19 @@
}
ty::FnPtr(ref bare_fn) => p!(print(bare_fn)),
ty::Infer(infer_ty) => {
+ let verbose = self.tcx().sess.verbose();
if let ty::TyVar(ty_vid) = infer_ty {
if let Some(name) = self.infer_ty_name(ty_vid) {
p!(write("{}", name))
} else {
- p!(write("{}", infer_ty))
+ if verbose {
+ p!(write("{:?}", infer_ty))
+ } else {
+ p!(write("{}", infer_ty))
+ }
}
} else {
- p!(write("{}", infer_ty))
+ if verbose { p!(write("{:?}", infer_ty)) } else { p!(write("{}", infer_ty)) }
}
}
ty::Error(_) => p!("[type error]"),
@@ -623,12 +627,8 @@
p!("impl");
for (predicate, _) in bounds {
let predicate = predicate.subst(self.tcx(), substs);
- // Note: We can't use `to_opt_poly_trait_ref` here as `predicate`
- // may contain unbound variables. We therefore do this manually.
- //
- // FIXME(lcnr): Find out why exactly this is the case :)
- let bound_predicate = predicate.bound_atom_with_opt_escaping(self.tcx());
- if let ty::PredicateAtom::Trait(pred, _) = bound_predicate.skip_binder() {
+ let bound_predicate = predicate.kind();
+ if let ty::PredicateKind::Trait(pred, _) = bound_predicate.skip_binder() {
let trait_ref = bound_predicate.rebind(pred.trait_ref);
// Don't print +Sized, but rather +?Sized if absent.
if Some(trait_ref.def_id()) == self.tcx().lang_items().sized_trait() {
@@ -972,7 +972,7 @@
ty::TyS {
kind:
ty::Array(
- ty::TyS { kind: ty::Uint(ast::UintTy::U8), .. },
+ ty::TyS { kind: ty::Uint(ty::UintTy::U8), .. },
ty::Const {
val: ty::ConstKind::Value(ConstValue::Scalar(int)),
..
@@ -1001,10 +1001,10 @@
(Scalar::Int(int), ty::Bool) if int == ScalarInt::FALSE => p!("false"),
(Scalar::Int(int), ty::Bool) if int == ScalarInt::TRUE => p!("true"),
// Float
- (Scalar::Int(int), ty::Float(ast::FloatTy::F32)) => {
+ (Scalar::Int(int), ty::Float(ty::FloatTy::F32)) => {
p!(write("{}f32", Single::try_from(int).unwrap()))
}
- (Scalar::Int(int), ty::Float(ast::FloatTy::F64)) => {
+ (Scalar::Int(int), ty::Float(ty::FloatTy::F64)) => {
p!(write("{}f64", Double::try_from(int).unwrap()))
}
// Int
@@ -1250,7 +1250,7 @@
pub region_highlight_mode: RegionHighlightMode,
- pub name_resolver: Option<Box<&'a dyn Fn(ty::sty::TyVid) -> Option<String>>>,
+ pub name_resolver: Option<Box<&'a dyn Fn(ty::TyVid) -> Option<String>>>,
}
impl<F> Deref for FmtPrinter<'a, 'tcx, F> {
@@ -1481,7 +1481,7 @@
// FIXME(eddyb) `name` should never be empty, but it
// currently is for `extern { ... }` "foreign modules".
let name = disambiguated_data.data.name();
- if name != DefPathDataName::Named(kw::Invalid) {
+ if name != DefPathDataName::Named(kw::Empty) {
if !self.empty_path {
write!(self, "::")?;
}
@@ -1608,14 +1608,14 @@
match *region {
ty::ReEarlyBound(ref data) => {
- data.name != kw::Invalid && data.name != kw::UnderscoreLifetime
+ data.name != kw::Empty && data.name != kw::UnderscoreLifetime
}
ty::ReLateBound(_, ty::BoundRegion { kind: br })
| ty::ReFree(ty::FreeRegion { bound_region: br, .. })
| ty::RePlaceholder(ty::Placeholder { name: br, .. }) => {
if let ty::BrNamed(_, name) = br {
- if name != kw::Invalid && name != kw::UnderscoreLifetime {
+ if name != kw::Empty && name != kw::UnderscoreLifetime {
return true;
}
}
@@ -1685,7 +1685,7 @@
// `explain_region()` or `note_and_explain_region()`.
match *region {
ty::ReEarlyBound(ref data) => {
- if data.name != kw::Invalid {
+ if data.name != kw::Empty {
p!(write("{}", data.name));
return Ok(self);
}
@@ -1694,7 +1694,7 @@
| ty::ReFree(ty::FreeRegion { bound_region: br, .. })
| ty::RePlaceholder(ty::Placeholder { name: br, .. }) => {
if let ty::BrNamed(_, name) = br {
- if name != kw::Invalid && name != kw::UnderscoreLifetime {
+ if name != kw::Empty && name != kw::UnderscoreLifetime {
p!(write("{}", name));
return Ok(self);
}
@@ -2011,21 +2011,6 @@
p!("fn", pretty_fn_sig(self.inputs(), self.c_variadic, self.output()));
}
- ty::InferTy {
- if cx.tcx().sess.verbose() {
- p!(write("{:?}", self));
- return Ok(cx);
- }
- match *self {
- ty::TyVar(_) => p!("_"),
- ty::IntVar(_) => p!(write("{}", "{integer}")),
- ty::FloatVar(_) => p!(write("{}", "{float}")),
- ty::FreshTy(v) => p!(write("FreshTy({})", v)),
- ty::FreshIntTy(v) => p!(write("FreshIntTy({})", v)),
- ty::FreshFloatTy(v) => p!(write("FreshFloatTy({})", v))
- }
- }
-
ty::TraitRef<'tcx> {
p!(write("<{} as {}>", self.self_ty(), self.print_only_trait_path()))
}
@@ -2068,40 +2053,38 @@
}
ty::Predicate<'tcx> {
- match self.kind() {
- &ty::PredicateKind::Atom(atom) => p!(print(atom)),
- ty::PredicateKind::ForAll(binder) => p!(print(binder)),
- }
+ let binder = self.kind();
+ p!(print(binder))
}
- ty::PredicateAtom<'tcx> {
+ ty::PredicateKind<'tcx> {
match *self {
- ty::PredicateAtom::Trait(ref data, constness) => {
+ ty::PredicateKind::Trait(ref data, constness) => {
if let hir::Constness::Const = constness {
p!("const ");
}
p!(print(data))
}
- ty::PredicateAtom::Subtype(predicate) => p!(print(predicate)),
- ty::PredicateAtom::RegionOutlives(predicate) => p!(print(predicate)),
- ty::PredicateAtom::TypeOutlives(predicate) => p!(print(predicate)),
- ty::PredicateAtom::Projection(predicate) => p!(print(predicate)),
- ty::PredicateAtom::WellFormed(arg) => p!(print(arg), " well-formed"),
- ty::PredicateAtom::ObjectSafe(trait_def_id) => {
+ ty::PredicateKind::Subtype(predicate) => p!(print(predicate)),
+ ty::PredicateKind::RegionOutlives(predicate) => p!(print(predicate)),
+ ty::PredicateKind::TypeOutlives(predicate) => p!(print(predicate)),
+ ty::PredicateKind::Projection(predicate) => p!(print(predicate)),
+ ty::PredicateKind::WellFormed(arg) => p!(print(arg), " well-formed"),
+ ty::PredicateKind::ObjectSafe(trait_def_id) => {
p!("the trait `", print_def_path(trait_def_id, &[]), "` is object-safe")
}
- ty::PredicateAtom::ClosureKind(closure_def_id, _closure_substs, kind) => {
+ ty::PredicateKind::ClosureKind(closure_def_id, _closure_substs, kind) => {
p!("the closure `",
print_value_path(closure_def_id, &[]),
write("` implements the trait `{}`", kind))
}
- ty::PredicateAtom::ConstEvaluatable(def, substs) => {
+ ty::PredicateKind::ConstEvaluatable(def, substs) => {
p!("the constant `", print_value_path(def.did, substs), "` can be evaluated")
}
- ty::PredicateAtom::ConstEquate(c1, c2) => {
+ ty::PredicateKind::ConstEquate(c1, c2) => {
p!("the constant `", print(c1), "` equals `", print(c2), "`")
}
- ty::PredicateAtom::TypeWellFormedFromEnv(ty) => {
+ ty::PredicateKind::TypeWellFormedFromEnv(ty) => {
p!("the type `", print(ty), "` is found in the environment")
}
}
diff --git a/compiler/rustc_middle/src/ty/query/keys.rs b/compiler/rustc_middle/src/ty/query/keys.rs
index a005990..bfa1581 100644
--- a/compiler/rustc_middle/src/ty/query/keys.rs
+++ b/compiler/rustc_middle/src/ty/query/keys.rs
@@ -127,6 +127,17 @@
}
}
+impl Key for (ty::Instance<'tcx>, LocalDefId) {
+ type CacheSelector = DefaultCacheSelector;
+
+ fn query_crate(&self) -> CrateNum {
+ self.0.query_crate()
+ }
+ fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
+ self.0.default_span(tcx)
+ }
+}
+
impl Key for (DefId, LocalDefId) {
type CacheSelector = DefaultCacheSelector;
diff --git a/compiler/rustc_middle/src/ty/query/mod.rs b/compiler/rustc_middle/src/ty/query/mod.rs
index b269dd0..f580cb1 100644
--- a/compiler/rustc_middle/src/ty/query/mod.rs
+++ b/compiler/rustc_middle/src/ty/query/mod.rs
@@ -1,4 +1,4 @@
-use crate::dep_graph::{self, DepKind, DepNode, DepNodeParams};
+use crate::dep_graph;
use crate::hir::exports::Export;
use crate::hir::map;
use crate::infer::canonical::{self, Canonical};
@@ -103,138 +103,6 @@
rustc_query_append! { [define_queries!][<'tcx>] }
-/// The red/green evaluation system will try to mark a specific DepNode in the
-/// dependency graph as green by recursively trying to mark the dependencies of
-/// that `DepNode` as green. While doing so, it will sometimes encounter a `DepNode`
-/// where we don't know if it is red or green and we therefore actually have
-/// to recompute its value in order to find out. Since the only piece of
-/// information that we have at that point is the `DepNode` we are trying to
-/// re-evaluate, we need some way to re-run a query from just that. This is what
-/// `force_from_dep_node()` implements.
-///
-/// In the general case, a `DepNode` consists of a `DepKind` and an opaque
-/// GUID/fingerprint that will uniquely identify the node. This GUID/fingerprint
-/// is usually constructed by computing a stable hash of the query-key that the
-/// `DepNode` corresponds to. Consequently, it is not in general possible to go
-/// back from hash to query-key (since hash functions are not reversible). For
-/// this reason `force_from_dep_node()` is expected to fail from time to time
-/// because we just cannot find out, from the `DepNode` alone, what the
-/// corresponding query-key is and therefore cannot re-run the query.
-///
-/// The system deals with this case letting `try_mark_green` fail which forces
-/// the root query to be re-evaluated.
-///
-/// Now, if `force_from_dep_node()` would always fail, it would be pretty useless.
-/// Fortunately, we can use some contextual information that will allow us to
-/// reconstruct query-keys for certain kinds of `DepNode`s. In particular, we
-/// enforce by construction that the GUID/fingerprint of certain `DepNode`s is a
-/// valid `DefPathHash`. Since we also always build a huge table that maps every
-/// `DefPathHash` in the current codebase to the corresponding `DefId`, we have
-/// everything we need to re-run the query.
-///
-/// Take the `mir_promoted` query as an example. Like many other queries, it
-/// just has a single parameter: the `DefId` of the item it will compute the
-/// validated MIR for. Now, when we call `force_from_dep_node()` on a `DepNode`
-/// with kind `MirValidated`, we know that the GUID/fingerprint of the `DepNode`
-/// is actually a `DefPathHash`, and can therefore just look up the corresponding
-/// `DefId` in `tcx.def_path_hash_to_def_id`.
-///
-/// When you implement a new query, it will likely have a corresponding new
-/// `DepKind`, and you'll have to support it here in `force_from_dep_node()`. As
-/// a rule of thumb, if your query takes a `DefId` or `LocalDefId` as sole parameter,
-/// then `force_from_dep_node()` should not fail for it. Otherwise, you can just
-/// add it to the "We don't have enough information to reconstruct..." group in
-/// the match below.
-pub fn force_from_dep_node<'tcx>(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> bool {
- // We must avoid ever having to call `force_from_dep_node()` for a
- // `DepNode::codegen_unit`:
- // Since we cannot reconstruct the query key of a `DepNode::codegen_unit`, we
- // would always end up having to evaluate the first caller of the
- // `codegen_unit` query that *is* reconstructible. This might very well be
- // the `compile_codegen_unit` query, thus re-codegenning the whole CGU just
- // to re-trigger calling the `codegen_unit` query with the right key. At
- // that point we would already have re-done all the work we are trying to
- // avoid doing in the first place.
- // The solution is simple: Just explicitly call the `codegen_unit` query for
- // each CGU, right after partitioning. This way `try_mark_green` will always
- // hit the cache instead of having to go through `force_from_dep_node`.
- // This assertion makes sure, we actually keep applying the solution above.
- debug_assert!(
- dep_node.kind != DepKind::codegen_unit,
- "calling force_from_dep_node() on DepKind::codegen_unit"
- );
-
- if !dep_node.kind.can_reconstruct_query_key() {
- return false;
- }
-
- macro_rules! force_from_dep_node {
- ($($(#[$attr:meta])* [$($modifiers:tt)*] $name:ident($K:ty),)*) => {
- match dep_node.kind {
- // These are inputs that are expected to be pre-allocated and that
- // should therefore always be red or green already.
- DepKind::CrateMetadata |
-
- // These are anonymous nodes.
- DepKind::TraitSelect |
-
- // We don't have enough information to reconstruct the query key of
- // these.
- DepKind::CompileCodegenUnit |
-
- // Forcing this makes no sense.
- DepKind::Null => {
- bug!("force_from_dep_node: encountered {:?}", dep_node)
- }
-
- $(DepKind::$name => {
- debug_assert!(<$K as DepNodeParams<TyCtxt<'_>>>::can_reconstruct_query_key());
-
- if let Some(key) = <$K as DepNodeParams<TyCtxt<'_>>>::recover(tcx, dep_node) {
- force_query::<queries::$name<'_>, _>(
- tcx,
- key,
- DUMMY_SP,
- *dep_node
- );
- return true;
- }
- })*
- }
- }
- }
-
- rustc_dep_node_append! { [force_from_dep_node!][] }
-
- false
-}
-
-pub(crate) fn try_load_from_on_disk_cache<'tcx>(tcx: TyCtxt<'tcx>, dep_node: &DepNode) {
- macro_rules! try_load_from_on_disk_cache {
- ($($name:ident,)*) => {
- match dep_node.kind {
- $(DepKind::$name => {
- if <query_keys::$name<'tcx> as DepNodeParams<TyCtxt<'_>>>::can_reconstruct_query_key() {
- debug_assert!(tcx.dep_graph
- .node_color(dep_node)
- .map(|c| c.is_green())
- .unwrap_or(false));
-
- let key = <query_keys::$name<'tcx> as DepNodeParams<TyCtxt<'_>>>::recover(tcx, dep_node).unwrap_or_else(|| panic!("Failed to recover key for {:?} with hash {}", dep_node, dep_node.hash));
- if queries::$name::cache_on_disk(tcx, &key, None) {
- let _ = tcx.$name(key);
- }
- }
- })*
-
- _ => (),
- }
- }
- }
-
- rustc_cached_queries!(try_load_from_on_disk_cache!);
-}
-
mod sealed {
use super::{DefId, LocalDefId};
@@ -262,3 +130,19 @@
}
use sealed::IntoQueryParam;
+
+impl TyCtxt<'tcx> {
+ pub fn def_kind(self, def_id: impl IntoQueryParam<DefId>) -> DefKind {
+ let def_id = def_id.into_query_param();
+ self.opt_def_kind(def_id)
+ .unwrap_or_else(|| bug!("def_kind: unsupported node: {:?}", def_id))
+ }
+}
+
+impl TyCtxtAt<'tcx> {
+ pub fn def_kind(self, def_id: impl IntoQueryParam<DefId>) -> DefKind {
+ let def_id = def_id.into_query_param();
+ self.opt_def_kind(def_id)
+ .unwrap_or_else(|| bug!("def_kind: unsupported node: {:?}", def_id))
+ }
+}
diff --git a/compiler/rustc_middle/src/ty/query/on_disk_cache.rs b/compiler/rustc_middle/src/ty/query/on_disk_cache.rs
index 8a1165b..cfe4700 100644
--- a/compiler/rustc_middle/src/ty/query/on_disk_cache.rs
+++ b/compiler/rustc_middle/src/ty/query/on_disk_cache.rs
@@ -1,19 +1,23 @@
use crate::dep_graph::{DepNode, DepNodeIndex, SerializedDepNodeIndex};
use crate::mir::interpret::{AllocDecodingSession, AllocDecodingState};
use crate::mir::{self, interpret};
-use crate::ty::codec::{OpaqueEncoder, RefDecodable, TyDecoder, TyEncoder};
+use crate::ty::codec::{RefDecodable, TyDecoder, TyEncoder};
use crate::ty::context::TyCtxt;
use crate::ty::{self, Ty};
use rustc_data_structures::fingerprint::{Fingerprint, FingerprintDecoder, FingerprintEncoder};
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet};
use rustc_data_structures::sync::{HashMapExt, Lock, Lrc, OnceCell};
use rustc_data_structures::thin_vec::ThinVec;
+use rustc_data_structures::unhash::UnhashMap;
use rustc_errors::Diagnostic;
use rustc_hir::def_id::{CrateNum, DefId, DefIndex, LocalDefId, LOCAL_CRATE};
use rustc_hir::definitions::DefPathHash;
use rustc_hir::definitions::Definitions;
use rustc_index::vec::{Idx, IndexVec};
-use rustc_serialize::{opaque, Decodable, Decoder, Encodable, Encoder};
+use rustc_serialize::{
+ opaque::{self, FileEncodeResult, FileEncoder},
+ Decodable, Decoder, Encodable, Encoder,
+};
use rustc_session::{CrateDisambiguator, Session};
use rustc_span::hygiene::{
ExpnDataDecodeMode, ExpnDataEncodeMode, ExpnId, HygieneDecodeContext, HygieneEncodeContext,
@@ -28,8 +32,10 @@
const TAG_FILE_FOOTER: u128 = 0xC0FFEE_C0FFEE_C0FFEE_C0FFEE_C0FFEE;
-const TAG_VALID_SPAN: u8 = 0;
-const TAG_INVALID_SPAN: u8 = 1;
+// A normal span encoded with both location information and a `SyntaxContext`
+const TAG_FULL_SPAN: u8 = 0;
+// A partial span with no location information, encoded only with a `SyntaxContext`
+const TAG_PARTIAL_SPAN: u8 = 1;
const TAG_SYNTAX_CONTEXT: u8 = 0;
const TAG_EXPN_DATA: u8 = 1;
@@ -87,7 +93,7 @@
// compilation session. This is used as an initial 'guess' when
// we try to map a `DefPathHash` to its `DefId` in the current compilation
// session.
- foreign_def_path_hashes: FxHashMap<DefPathHash, RawDefId>,
+ foreign_def_path_hashes: UnhashMap<DefPathHash, RawDefId>,
// The *next* compilation sessison's `foreign_def_path_hashes` - at
// the end of our current compilation session, this will get written
@@ -95,19 +101,19 @@
// will become `foreign_def_path_hashes` of the next compilation session.
// This stores any `DefPathHash` that we may need to map to a `DefId`
// during the next compilation session.
- latest_foreign_def_path_hashes: Lock<FxHashMap<DefPathHash, RawDefId>>,
+ latest_foreign_def_path_hashes: Lock<UnhashMap<DefPathHash, RawDefId>>,
// Maps `DefPathHashes` to their corresponding `LocalDefId`s for all
// local items in the current compilation session. This is only populated
// when we are in incremental mode and have loaded a pre-existing cache
// from disk, since this map is only used when deserializing a `DefPathHash`
// from the incremental cache.
- local_def_path_hash_to_def_id: FxHashMap<DefPathHash, LocalDefId>,
+ local_def_path_hash_to_def_id: UnhashMap<DefPathHash, LocalDefId>,
// Caches all lookups of `DefPathHashes`, both for local and foreign
// definitions. A definition from the previous compilation session
// may no longer exist in the current compilation session, so
// we use `Option<DefId>` so that we can cache a lookup failure.
- def_path_hash_to_def_id_cache: Lock<FxHashMap<DefPathHash, Option<DefId>>>,
+ def_path_hash_to_def_id_cache: Lock<UnhashMap<DefPathHash, Option<DefId>>>,
}
// This type is used only for serialization and deserialization.
@@ -123,7 +129,7 @@
syntax_contexts: FxHashMap<u32, AbsoluteBytePos>,
// See `OnDiskCache.expn_data`
expn_data: FxHashMap<u32, AbsoluteBytePos>,
- foreign_def_path_hashes: FxHashMap<DefPathHash, RawDefId>,
+ foreign_def_path_hashes: UnhashMap<DefPathHash, RawDefId>,
}
type EncodedQueryResultIndex = Vec<(SerializedDepNodeIndex, AbsoluteBytePos)>;
@@ -160,8 +166,8 @@
pub index: u32,
}
-fn make_local_def_path_hash_map(definitions: &Definitions) -> FxHashMap<DefPathHash, LocalDefId> {
- FxHashMap::from_iter(
+fn make_local_def_path_hash_map(definitions: &Definitions) -> UnhashMap<DefPathHash, LocalDefId> {
+ UnhashMap::from_iter(
definitions
.def_path_table()
.all_def_path_hashes_and_def_ids(LOCAL_CRATE)
@@ -240,10 +246,11 @@
}
}
- pub fn serialize<'tcx, E>(&self, tcx: TyCtxt<'tcx>, encoder: &mut E) -> Result<(), E::Error>
- where
- E: OpaqueEncoder,
- {
+ pub fn serialize<'tcx>(
+ &self,
+ tcx: TyCtxt<'tcx>,
+ encoder: &mut FileEncoder,
+ ) -> FileEncodeResult {
// Serializing the `DepGraph` should not modify it.
tcx.dep_graph.with_ignore(|| {
// Allocate `SourceFileIndex`es.
@@ -297,14 +304,14 @@
// Encode query results.
let mut query_result_index = EncodedQueryResultIndex::new();
- tcx.sess.time("encode_query_results", || {
+ tcx.sess.time("encode_query_results", || -> FileEncodeResult {
let enc = &mut encoder;
let qri = &mut query_result_index;
macro_rules! encode_queries {
($($query:ident,)*) => {
$(
- encode_query_results::<ty::query::queries::$query<'_>, _>(
+ encode_query_results::<ty::query::queries::$query<'_>>(
tcx,
enc,
qri
@@ -323,15 +330,17 @@
.current_diagnostics
.borrow()
.iter()
- .map(|(dep_node_index, diagnostics)| {
- let pos = AbsoluteBytePos::new(encoder.position());
- // Let's make sure we get the expected type here.
- let diagnostics: &EncodedDiagnostics = diagnostics;
- let dep_node_index = SerializedDepNodeIndex::new(dep_node_index.index());
- encoder.encode_tagged(dep_node_index, diagnostics)?;
+ .map(
+ |(dep_node_index, diagnostics)| -> Result<_, <FileEncoder as Encoder>::Error> {
+ let pos = AbsoluteBytePos::new(encoder.position());
+ // Let's make sure we get the expected type here.
+ let diagnostics: &EncodedDiagnostics = diagnostics;
+ let dep_node_index = SerializedDepNodeIndex::new(dep_node_index.index());
+ encoder.encode_tagged(dep_node_index, diagnostics)?;
- Ok((dep_node_index, pos))
- })
+ Ok((dep_node_index, pos))
+ },
+ )
.collect::<Result<_, _>>()?;
let interpret_alloc_index = {
@@ -374,13 +383,13 @@
hygiene_encode_context.encode(
&mut encoder,
- |encoder, index, ctxt_data| {
+ |encoder, index, ctxt_data| -> FileEncodeResult {
let pos = AbsoluteBytePos::new(encoder.position());
encoder.encode_tagged(TAG_SYNTAX_CONTEXT, ctxt_data)?;
syntax_contexts.insert(index, pos);
Ok(())
},
- |encoder, index, expn_data| {
+ |encoder, index, expn_data| -> FileEncodeResult {
let pos = AbsoluteBytePos::new(encoder.position());
encoder.encode_tagged(TAG_EXPN_DATA, expn_data)?;
expn_ids.insert(index, pos);
@@ -409,7 +418,7 @@
// Encode the position of the footer as the last 8 bytes of the
// file so we know where to look for it.
- IntEncodedWithFixedSize(footer_pos).encode(encoder.encoder.opaque())?;
+ IntEncodedWithFixedSize(footer_pos).encode(encoder.encoder)?;
// DO NOT WRITE ANYTHING TO THE ENCODER AFTER THIS POINT! The address
// of the footer must be the last thing in the data stream.
@@ -807,6 +816,15 @@
crate::implement_ty_decoder!(CacheDecoder<'a, 'tcx>);
+// This ensures that the `Decodable<opaque::Decoder>::decode` specialization for `Vec<u8>` is used
+// when a `CacheDecoder` is passed to `Decodable::decode`. Unfortunately, we have to manually opt
+// into specializations this way, given how `CacheDecoder` and the decoding traits currently work.
+impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for Vec<u8> {
+ fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Result<Self, String> {
+ Decodable::decode(&mut d.opaque)
+ }
+}
+
impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for SyntaxContext {
fn decode(decoder: &mut CacheDecoder<'a, 'tcx>) -> Result<Self, String> {
let syntax_contexts = decoder.syntax_contexts;
@@ -848,10 +866,11 @@
fn decode(decoder: &mut CacheDecoder<'a, 'tcx>) -> Result<Self, String> {
let tag: u8 = Decodable::decode(decoder)?;
- if tag == TAG_INVALID_SPAN {
- return Ok(DUMMY_SP);
+ if tag == TAG_PARTIAL_SPAN {
+ let ctxt = SyntaxContext::decode(decoder)?;
+ return Ok(DUMMY_SP.with_ctxt(ctxt));
} else {
- debug_assert_eq!(tag, TAG_VALID_SPAN);
+ debug_assert_eq!(tag, TAG_FULL_SPAN);
}
let file_lo_index = SourceFileIndex::decode(decoder)?;
@@ -954,17 +973,28 @@
//- ENCODING -------------------------------------------------------------------
+trait OpaqueEncoder: Encoder {
+ fn position(&self) -> usize;
+}
+
+impl OpaqueEncoder for FileEncoder {
+ #[inline]
+ fn position(&self) -> usize {
+ FileEncoder::position(self)
+ }
+}
+
/// An encoder that can write to the incremental compilation cache.
struct CacheEncoder<'a, 'tcx, E: OpaqueEncoder> {
tcx: TyCtxt<'tcx>,
encoder: &'a mut E,
type_shorthands: FxHashMap<Ty<'tcx>, usize>,
- predicate_shorthands: FxHashMap<ty::Predicate<'tcx>, usize>,
+ predicate_shorthands: FxHashMap<ty::PredicateKind<'tcx>, usize>,
interpret_allocs: FxIndexSet<interpret::AllocId>,
source_map: CachingSourceMapView<'tcx>,
file_to_file_index: FxHashMap<*const SourceFile, SourceFileIndex>,
hygiene_context: &'a HygieneEncodeContext,
- latest_foreign_def_path_hashes: FxHashMap<DefPathHash, RawDefId>,
+ latest_foreign_def_path_hashes: UnhashMap<DefPathHash, RawDefId>,
}
impl<'a, 'tcx, E> CacheEncoder<'a, 'tcx, E>
@@ -995,9 +1025,9 @@
}
}
-impl<'a, 'tcx> FingerprintEncoder for CacheEncoder<'a, 'tcx, rustc_serialize::opaque::Encoder> {
- fn encode_fingerprint(&mut self, f: &Fingerprint) -> opaque::EncodeResult {
- f.encode_opaque(self.encoder)
+impl<'a, 'tcx, E: OpaqueEncoder> FingerprintEncoder for CacheEncoder<'a, 'tcx, E> {
+ fn encode_fingerprint(&mut self, f: &Fingerprint) -> Result<(), E::Error> {
+ self.encoder.encode_fingerprint(f)
}
}
@@ -1030,24 +1060,29 @@
{
fn encode(&self, s: &mut CacheEncoder<'a, 'tcx, E>) -> Result<(), E::Error> {
if *self == DUMMY_SP {
- return TAG_INVALID_SPAN.encode(s);
+ TAG_PARTIAL_SPAN.encode(s)?;
+ return SyntaxContext::root().encode(s);
}
let span_data = self.data();
- let (file_lo, line_lo, col_lo) = match s.source_map.byte_pos_to_line_and_col(span_data.lo) {
- Some(pos) => pos,
- None => return TAG_INVALID_SPAN.encode(s),
+ let pos = s.source_map.byte_pos_to_line_and_col(span_data.lo);
+ let partial_span = match &pos {
+ Some((file_lo, _, _)) => !file_lo.contains(span_data.hi),
+ None => true,
};
- if !file_lo.contains(span_data.hi) {
- return TAG_INVALID_SPAN.encode(s);
+ if partial_span {
+ TAG_PARTIAL_SPAN.encode(s)?;
+ return span_data.ctxt.encode(s);
}
+ let (file_lo, line_lo, col_lo) = pos.unwrap();
+
let len = span_data.hi - span_data.lo;
let source_file_index = s.source_file_index(file_lo);
- TAG_VALID_SPAN.encode(s)?;
+ TAG_FULL_SPAN.encode(s)?;
source_file_index.encode(s)?;
line_lo.encode(s)?;
col_lo.encode(s)?;
@@ -1063,12 +1098,12 @@
const CLEAR_CROSS_CRATE: bool = false;
fn position(&self) -> usize {
- self.encoder.encoder_position()
+ self.encoder.position()
}
fn type_shorthands(&mut self) -> &mut FxHashMap<Ty<'tcx>, usize> {
&mut self.type_shorthands
}
- fn predicate_shorthands(&mut self) -> &mut FxHashMap<ty::Predicate<'tcx>, usize> {
+ fn predicate_shorthands(&mut self) -> &mut FxHashMap<ty::PredicateKind<'tcx>, usize> {
&mut self.predicate_shorthands
}
fn encode_alloc_id(&mut self, alloc_id: &interpret::AllocId) -> Result<(), Self::Error> {
@@ -1149,6 +1184,16 @@
}
}
+// This ensures that the `Encodable<opaque::FileEncoder>::encode` specialization for byte slices
+// is used when a `CacheEncoder` having an `opaque::FileEncoder` is passed to `Encodable::encode`.
+// Unfortunately, we have to manually opt into specializations this way, given how `CacheEncoder`
+// and the encoding traits currently work.
+impl<'a, 'tcx> Encodable<CacheEncoder<'a, 'tcx, FileEncoder>> for [u8] {
+ fn encode(&self, e: &mut CacheEncoder<'a, 'tcx, FileEncoder>) -> FileEncodeResult {
+ self.encode(e.encoder)
+ }
+}
+
// An integer that will always encode to 8 bytes.
struct IntEncodedWithFixedSize(u64);
@@ -1156,8 +1201,8 @@
pub const ENCODED_SIZE: usize = 8;
}
-impl Encodable<opaque::Encoder> for IntEncodedWithFixedSize {
- fn encode(&self, e: &mut opaque::Encoder) -> Result<(), !> {
+impl<E: OpaqueEncoder> Encodable<E> for IntEncodedWithFixedSize {
+ fn encode(&self, e: &mut E) -> Result<(), E::Error> {
let start_pos = e.position();
for i in 0..IntEncodedWithFixedSize::ENCODED_SIZE {
((self.0 >> (i * 8)) as u8).encode(e)?;
@@ -1185,15 +1230,14 @@
}
}
-fn encode_query_results<'a, 'tcx, Q, E>(
+fn encode_query_results<'a, 'tcx, Q>(
tcx: TyCtxt<'tcx>,
- encoder: &mut CacheEncoder<'a, 'tcx, E>,
+ encoder: &mut CacheEncoder<'a, 'tcx, FileEncoder>,
query_result_index: &mut EncodedQueryResultIndex,
-) -> Result<(), E::Error>
+) -> FileEncodeResult
where
Q: super::QueryDescription<TyCtxt<'tcx>> + super::QueryAccessors<TyCtxt<'tcx>>,
- Q::Value: Encodable<CacheEncoder<'a, 'tcx, E>>,
- E: 'a + OpaqueEncoder,
+ Q::Value: Encodable<CacheEncoder<'a, 'tcx, FileEncoder>>,
{
let _timer = tcx
.sess
@@ -1210,7 +1254,7 @@
// Record position of the cache entry.
query_result_index
- .push((dep_node, AbsoluteBytePos::new(encoder.encoder.opaque().position())));
+ .push((dep_node, AbsoluteBytePos::new(encoder.encoder.position())));
// Encode the type check tables with the `SerializedDepNodeIndex`
// as tag.
diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs
index 7a1ca6a..0ca94a9 100644
--- a/compiler/rustc_middle/src/ty/structural_impls.rs
+++ b/compiler/rustc_middle/src/ty/structural_impls.rs
@@ -111,81 +111,24 @@
}
}
-impl fmt::Debug for ty::Variance {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.write_str(match *self {
- ty::Covariant => "+",
- ty::Contravariant => "-",
- ty::Invariant => "o",
- ty::Bivariant => "*",
- })
- }
-}
-
impl fmt::Debug for ty::FnSig<'tcx> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "({:?}; c_variadic: {})->{:?}", self.inputs(), self.c_variadic, self.output())
}
}
-impl fmt::Debug for ty::TyVid {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- write!(f, "_#{}t", self.index)
- }
-}
-
impl<'tcx> fmt::Debug for ty::ConstVid<'tcx> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "_#{}c", self.index)
}
}
-impl fmt::Debug for ty::IntVid {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- write!(f, "_#{}i", self.index)
- }
-}
-
-impl fmt::Debug for ty::FloatVid {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- write!(f, "_#{}f", self.index)
- }
-}
-
impl fmt::Debug for ty::RegionVid {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "'_#{}r", self.index())
}
}
-impl fmt::Debug for ty::InferTy {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- match *self {
- ty::TyVar(ref v) => v.fmt(f),
- ty::IntVar(ref v) => v.fmt(f),
- ty::FloatVar(ref v) => v.fmt(f),
- ty::FreshTy(v) => write!(f, "FreshTy({:?})", v),
- ty::FreshIntTy(v) => write!(f, "FreshIntTy({:?})", v),
- ty::FreshFloatTy(v) => write!(f, "FreshFloatTy({:?})", v),
- }
- }
-}
-
-impl fmt::Debug for ty::IntVarValue {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- match *self {
- ty::IntType(ref v) => v.fmt(f),
- ty::UintType(ref v) => v.fmt(f),
- }
- }
-}
-
-impl fmt::Debug for ty::FloatVarValue {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- self.0.fmt(f)
- }
-}
-
impl fmt::Debug for ty::TraitRef<'tcx> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
with_no_trimmed_paths(|| fmt::Display::fmt(self, f))
@@ -231,37 +174,28 @@
impl fmt::Debug for ty::PredicateKind<'tcx> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
- ty::PredicateKind::ForAll(binder) => write!(f, "ForAll({:?})", binder),
- ty::PredicateKind::Atom(atom) => write!(f, "{:?}", atom),
- }
- }
-}
-
-impl fmt::Debug for ty::PredicateAtom<'tcx> {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- match *self {
- ty::PredicateAtom::Trait(ref a, constness) => {
+ ty::PredicateKind::Trait(ref a, constness) => {
if let hir::Constness::Const = constness {
write!(f, "const ")?;
}
a.fmt(f)
}
- ty::PredicateAtom::Subtype(ref pair) => pair.fmt(f),
- ty::PredicateAtom::RegionOutlives(ref pair) => pair.fmt(f),
- ty::PredicateAtom::TypeOutlives(ref pair) => pair.fmt(f),
- ty::PredicateAtom::Projection(ref pair) => pair.fmt(f),
- ty::PredicateAtom::WellFormed(data) => write!(f, "WellFormed({:?})", data),
- ty::PredicateAtom::ObjectSafe(trait_def_id) => {
+ ty::PredicateKind::Subtype(ref pair) => pair.fmt(f),
+ ty::PredicateKind::RegionOutlives(ref pair) => pair.fmt(f),
+ ty::PredicateKind::TypeOutlives(ref pair) => pair.fmt(f),
+ ty::PredicateKind::Projection(ref pair) => pair.fmt(f),
+ ty::PredicateKind::WellFormed(data) => write!(f, "WellFormed({:?})", data),
+ ty::PredicateKind::ObjectSafe(trait_def_id) => {
write!(f, "ObjectSafe({:?})", trait_def_id)
}
- ty::PredicateAtom::ClosureKind(closure_def_id, closure_substs, kind) => {
+ ty::PredicateKind::ClosureKind(closure_def_id, closure_substs, kind) => {
write!(f, "ClosureKind({:?}, {:?}, {:?})", closure_def_id, closure_substs, kind)
}
- ty::PredicateAtom::ConstEvaluatable(def_id, substs) => {
+ ty::PredicateKind::ConstEvaluatable(def_id, substs) => {
write!(f, "ConstEvaluatable({:?}, {:?})", def_id, substs)
}
- ty::PredicateAtom::ConstEquate(c1, c2) => write!(f, "ConstEquate({:?}, {:?})", c1, c2),
- ty::PredicateAtom::TypeWellFormedFromEnv(ty) => {
+ ty::PredicateKind::ConstEquate(c1, c2) => write!(f, "ConstEquate({:?}, {:?})", c1, c2),
+ ty::PredicateKind::TypeWellFormedFromEnv(ty) => {
write!(f, "TypeWellFormedFromEnv({:?})", ty)
}
}
@@ -283,7 +217,7 @@
u64,
String,
crate::middle::region::Scope,
- ::rustc_ast::FloatTy,
+ crate::ty::FloatTy,
::rustc_ast::InlineAsmOptions,
::rustc_ast::InlineAsmTemplatePiece,
::rustc_ast::NodeId,
@@ -485,46 +419,36 @@
type Lifted = ty::PredicateKind<'tcx>;
fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
match self {
- ty::PredicateKind::ForAll(binder) => tcx.lift(binder).map(ty::PredicateKind::ForAll),
- ty::PredicateKind::Atom(atom) => tcx.lift(atom).map(ty::PredicateKind::Atom),
- }
- }
-}
-
-impl<'a, 'tcx> Lift<'tcx> for ty::PredicateAtom<'a> {
- type Lifted = ty::PredicateAtom<'tcx>;
- fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
- match self {
- ty::PredicateAtom::Trait(data, constness) => {
- tcx.lift(data).map(|data| ty::PredicateAtom::Trait(data, constness))
+ ty::PredicateKind::Trait(data, constness) => {
+ tcx.lift(data).map(|data| ty::PredicateKind::Trait(data, constness))
}
- ty::PredicateAtom::Subtype(data) => tcx.lift(data).map(ty::PredicateAtom::Subtype),
- ty::PredicateAtom::RegionOutlives(data) => {
- tcx.lift(data).map(ty::PredicateAtom::RegionOutlives)
+ ty::PredicateKind::Subtype(data) => tcx.lift(data).map(ty::PredicateKind::Subtype),
+ ty::PredicateKind::RegionOutlives(data) => {
+ tcx.lift(data).map(ty::PredicateKind::RegionOutlives)
}
- ty::PredicateAtom::TypeOutlives(data) => {
- tcx.lift(data).map(ty::PredicateAtom::TypeOutlives)
+ ty::PredicateKind::TypeOutlives(data) => {
+ tcx.lift(data).map(ty::PredicateKind::TypeOutlives)
}
- ty::PredicateAtom::Projection(data) => {
- tcx.lift(data).map(ty::PredicateAtom::Projection)
+ ty::PredicateKind::Projection(data) => {
+ tcx.lift(data).map(ty::PredicateKind::Projection)
}
- ty::PredicateAtom::WellFormed(ty) => tcx.lift(ty).map(ty::PredicateAtom::WellFormed),
- ty::PredicateAtom::ClosureKind(closure_def_id, closure_substs, kind) => {
+ ty::PredicateKind::WellFormed(ty) => tcx.lift(ty).map(ty::PredicateKind::WellFormed),
+ ty::PredicateKind::ClosureKind(closure_def_id, closure_substs, kind) => {
tcx.lift(closure_substs).map(|closure_substs| {
- ty::PredicateAtom::ClosureKind(closure_def_id, closure_substs, kind)
+ ty::PredicateKind::ClosureKind(closure_def_id, closure_substs, kind)
})
}
- ty::PredicateAtom::ObjectSafe(trait_def_id) => {
- Some(ty::PredicateAtom::ObjectSafe(trait_def_id))
+ ty::PredicateKind::ObjectSafe(trait_def_id) => {
+ Some(ty::PredicateKind::ObjectSafe(trait_def_id))
}
- ty::PredicateAtom::ConstEvaluatable(def_id, substs) => {
- tcx.lift(substs).map(|substs| ty::PredicateAtom::ConstEvaluatable(def_id, substs))
+ ty::PredicateKind::ConstEvaluatable(def_id, substs) => {
+ tcx.lift(substs).map(|substs| ty::PredicateKind::ConstEvaluatable(def_id, substs))
}
- ty::PredicateAtom::ConstEquate(c1, c2) => {
- tcx.lift((c1, c2)).map(|(c1, c2)| ty::PredicateAtom::ConstEquate(c1, c2))
+ ty::PredicateKind::ConstEquate(c1, c2) => {
+ tcx.lift((c1, c2)).map(|(c1, c2)| ty::PredicateKind::ConstEquate(c1, c2))
}
- ty::PredicateAtom::TypeWellFormedFromEnv(ty) => {
- tcx.lift(ty).map(ty::PredicateAtom::TypeWellFormedFromEnv)
+ ty::PredicateKind::TypeWellFormedFromEnv(ty) => {
+ tcx.lift(ty).map(ty::PredicateKind::TypeWellFormedFromEnv)
}
}
}
@@ -1036,12 +960,12 @@
impl<'tcx> TypeFoldable<'tcx> for ty::Predicate<'tcx> {
fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
- let new = ty::PredicateKind::super_fold_with(self.inner.kind, folder);
+ let new = self.inner.kind.fold_with(folder);
folder.tcx().reuse_or_mk_predicate(self, new)
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
- ty::PredicateKind::super_visit_with(&self.inner.kind, visitor)
+ self.inner.kind.visit_with(visitor)
}
fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index 4ce7640..c1fa84d 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -2,17 +2,16 @@
#![allow(rustc::usage_of_ty_tykind)]
-use self::InferTy::*;
use self::TyKind::*;
use crate::infer::canonical::Canonical;
use crate::ty::subst::{GenericArg, InternalSubsts, Subst, SubstsRef};
+use crate::ty::InferTy::{self, *};
use crate::ty::{
self, AdtDef, DefIdTree, Discr, Ty, TyCtxt, TypeFlags, TypeFoldable, WithConstness,
};
use crate::ty::{DelaySpanBugEmitted, List, ParamEnv, TyS};
use polonius_engine::Atom;
-use rustc_ast as ast;
use rustc_data_structures::captures::Captures;
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
@@ -104,13 +103,13 @@
Char,
/// A primitive signed integer type. For example, `i32`.
- Int(ast::IntTy),
+ Int(ty::IntTy),
/// A primitive unsigned integer type. For example, `u32`.
- Uint(ast::UintTy),
+ Uint(ty::UintTy),
/// A primitive floating-point type. For example, `f64`.
- Float(ast::FloatTy),
+ Float(ty::FloatTy),
/// Algebraic data types (ADT). For example: structures, enumerations and unions.
///
@@ -605,7 +604,7 @@
#[inline]
pub fn variant_range(&self, def_id: DefId, tcx: TyCtxt<'tcx>) -> Range<VariantIdx> {
// FIXME requires optimized MIR
- let num_variants = tcx.generator_layout(def_id).variant_fields.len();
+ let num_variants = tcx.generator_layout(def_id).unwrap().variant_fields.len();
VariantIdx::new(0)..VariantIdx::new(num_variants)
}
@@ -666,7 +665,7 @@
def_id: DefId,
tcx: TyCtxt<'tcx>,
) -> impl Iterator<Item = impl Iterator<Item = Ty<'tcx>> + Captures<'tcx>> {
- let layout = tcx.generator_layout(def_id);
+ let layout = tcx.generator_layout(def_id).unwrap();
layout.variant_fields.iter().map(move |variant| {
variant.iter().map(move |field| layout.field_tys[*field].subst(tcx, self.substs))
})
@@ -955,7 +954,9 @@
/// erase, or otherwise "discharge" these bound vars, we change the
/// type from `Binder<T>` to just `T` (see
/// e.g., `liberate_late_bound_regions`).
-#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, TyEncodable, TyDecodable)]
+///
+/// `Decodable` and `Encodable` are implemented for `Binder<T>` using the `impl_binder_encode_decode!` macro.
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
pub struct Binder<T>(T);
impl<T> Binder<T> {
@@ -1131,8 +1132,16 @@
/// For example, if this is a projection of `<T as Iterator>::Item`,
/// then this function would return a `T: Iterator` trait reference.
pub fn trait_ref(&self, tcx: TyCtxt<'tcx>) -> ty::TraitRef<'tcx> {
+ // FIXME: This method probably shouldn't exist at all, since it's not
+ // clear what this method really intends to do. Be careful when
+ // using this method since the resulting TraitRef additionally
+ // contains the substs for the assoc_item, which strictly speaking
+ // is not correct
let def_id = tcx.associated_item(self.item_def_id).container.id();
- ty::TraitRef { def_id, substs: self.substs.truncate_to(tcx, tcx.generics_of(def_id)) }
+ // Include substitutions for generic arguments of associated types
+ let assoc_item = tcx.associated_item(self.item_def_id);
+ let substs_assoc_item = self.substs.truncate_to(tcx, tcx.generics_of(assoc_item.def_id));
+ ty::TraitRef { def_id, substs: substs_assoc_item }
}
pub fn self_ty(&self) -> Ty<'tcx> {
@@ -1424,28 +1433,15 @@
pub name: Symbol,
}
-#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, TyEncodable, TyDecodable)]
-pub struct TyVid {
- pub index: u32,
-}
-
+/// A **`const`** **v**ariable **ID**.
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, TyEncodable, TyDecodable)]
pub struct ConstVid<'tcx> {
pub index: u32,
pub phantom: PhantomData<&'tcx ()>,
}
-#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, TyEncodable, TyDecodable)]
-pub struct IntVid {
- pub index: u32,
-}
-
-#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, TyEncodable, TyDecodable)]
-pub struct FloatVid {
- pub index: u32,
-}
-
rustc_index::newtype_index! {
+ /// A **region** (lifetime) **v**ariable **ID**.
pub struct RegionVid {
DEBUG_FORMAT = custom,
}
@@ -1457,21 +1453,6 @@
}
}
-#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, TyEncodable, TyDecodable)]
-#[derive(HashStable)]
-pub enum InferTy {
- TyVar(TyVid),
- IntVar(IntVid),
- FloatVar(FloatVid),
-
- /// A `FreshTy` is one that is generated as a replacement for an
- /// unbound type variable. This is convenient for caching etc. See
- /// `infer::freshen` for more details.
- FreshTy(u32),
- FreshIntTy(u32),
- FreshFloatTy(u32),
-}
-
rustc_index::newtype_index! {
pub struct BoundVar { .. }
}
@@ -1824,7 +1805,7 @@
pub fn sequence_element_type(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
match self.kind() {
Array(ty, _) | Slice(ty) => ty,
- Str => tcx.mk_mach_uint(ast::UintTy::U8),
+ Str => tcx.mk_mach_uint(ty::UintTy::U8),
_ => bug!("`sequence_element_type` called on non-sequence value: {}", self),
}
}
@@ -1898,8 +1879,14 @@
pub fn is_scalar(&self) -> bool {
matches!(
self.kind(),
- Bool | Char | Int(_) | Float(_) | Uint(_) | FnDef(..) | FnPtr(_) | RawPtr(_)
- | Infer(IntVar(_) | FloatVar(_))
+ Bool | Char
+ | Int(_)
+ | Float(_)
+ | Uint(_)
+ | FnDef(..)
+ | FnPtr(_)
+ | RawPtr(_)
+ | Infer(IntVar(_) | FloatVar(_))
)
}
@@ -1964,7 +1951,7 @@
#[inline]
pub fn is_ptr_sized_integral(&self) -> bool {
- matches!(self.kind(), Int(ast::IntTy::Isize) | Uint(ast::UintTy::Usize))
+ matches!(self.kind(), Int(ty::IntTy::Isize) | Uint(ty::UintTy::Usize))
}
#[inline]
@@ -2152,9 +2139,9 @@
pub fn to_opt_closure_kind(&self) -> Option<ty::ClosureKind> {
match self.kind() {
Int(int_ty) => match int_ty {
- ast::IntTy::I8 => Some(ty::ClosureKind::Fn),
- ast::IntTy::I16 => Some(ty::ClosureKind::FnMut),
- ast::IntTy::I32 => Some(ty::ClosureKind::FnOnce),
+ ty::IntTy::I8 => Some(ty::ClosureKind::Fn),
+ ty::IntTy::I16 => Some(ty::ClosureKind::FnMut),
+ ty::IntTy::I32 => Some(ty::ClosureKind::FnOnce),
_ => bug!("cannot convert type `{:?}` to a closure kind", self),
},
diff --git a/compiler/rustc_middle/src/ty/trait_def.rs b/compiler/rustc_middle/src/ty/trait_def.rs
index 86476df..f4d7eac 100644
--- a/compiler/rustc_middle/src/ty/trait_def.rs
+++ b/compiler/rustc_middle/src/ty/trait_def.rs
@@ -63,7 +63,7 @@
AlwaysApplicable,
}
-#[derive(Default)]
+#[derive(Default, Debug)]
pub struct TraitImpls {
blanket_impls: Vec<DefId>,
/// Impls indexed by their simplified self type, for fast lookup.
diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs
index a645803..8edde87 100644
--- a/compiler/rustc_middle/src/ty/util.rs
+++ b/compiler/rustc_middle/src/ty/util.rs
@@ -34,7 +34,7 @@
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self.ty.kind() {
ty::Int(ity) => {
- let size = ty::tls::with(|tcx| Integer::from_attr(&tcx, SignedInt(ity)).size());
+ let size = ty::tls::with(|tcx| Integer::from_int_ty(&tcx, ity).size());
let x = self.val;
// sign extend the raw representation to be an i128
let x = size.sign_extend(x) as i128;
@@ -59,8 +59,8 @@
fn int_size_and_signed<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> (Size, bool) {
let (int, signed) = match *ty.kind() {
- Int(ity) => (Integer::from_attr(&tcx, SignedInt(ity)), true),
- Uint(uty) => (Integer::from_attr(&tcx, UnsignedInt(uty)), false),
+ Int(ity) => (Integer::from_int_ty(&tcx, ity), true),
+ Uint(uty) => (Integer::from_uint_ty(&tcx, uty), false),
_ => bug!("non integer discriminant"),
};
(int.size(), signed)
@@ -642,8 +642,8 @@
}
ty::Char => Some(std::char::MAX as u128),
ty::Float(fty) => Some(match fty {
- ast::FloatTy::F32 => rustc_apfloat::ieee::Single::INFINITY.to_bits(),
- ast::FloatTy::F64 => rustc_apfloat::ieee::Double::INFINITY.to_bits(),
+ ty::FloatTy::F32 => rustc_apfloat::ieee::Single::INFINITY.to_bits(),
+ ty::FloatTy::F64 => rustc_apfloat::ieee::Double::INFINITY.to_bits(),
}),
_ => None,
};
@@ -661,8 +661,8 @@
}
ty::Char => Some(0),
ty::Float(fty) => Some(match fty {
- ast::FloatTy::F32 => (-::rustc_apfloat::ieee::Single::INFINITY).to_bits(),
- ast::FloatTy::F64 => (-::rustc_apfloat::ieee::Double::INFINITY).to_bits(),
+ ty::FloatTy::F32 => (-::rustc_apfloat::ieee::Single::INFINITY).to_bits(),
+ ty::FloatTy::F64 => (-::rustc_apfloat::ieee::Double::INFINITY).to_bits(),
}),
_ => None,
};
diff --git a/compiler/rustc_middle/src/util/bug.rs b/compiler/rustc_middle/src/util/bug.rs
index 0903ef5..791d506 100644
--- a/compiler/rustc_middle/src/util/bug.rs
+++ b/compiler/rustc_middle/src/util/bug.rs
@@ -3,7 +3,7 @@
use crate::ty::{tls, TyCtxt};
use rustc_span::{MultiSpan, Span};
use std::fmt;
-use std::panic::Location;
+use std::panic::{panic_any, Location};
#[cold]
#[inline(never)]
@@ -21,6 +21,7 @@
opt_span_bug_fmt(Some(span), args, Location::caller());
}
+#[track_caller]
fn opt_span_bug_fmt<S: Into<MultiSpan>>(
span: Option<S>,
args: fmt::Arguments<'_>,
@@ -31,7 +32,7 @@
match (tcx, span) {
(Some(tcx), Some(span)) => tcx.sess.diagnostic().span_bug(span, &msg),
(Some(tcx), None) => tcx.sess.diagnostic().bug(&msg),
- (None, _) => panic!(msg),
+ (None, _) => panic_any(msg),
}
});
unreachable!();
diff --git a/compiler/rustc_mir/src/borrow_check/borrow_set.rs b/compiler/rustc_mir/src/borrow_check/borrow_set.rs
index b4299fb..288eda3 100644
--- a/compiler/rustc_mir/src/borrow_check/borrow_set.rs
+++ b/compiler/rustc_mir/src/borrow_check/borrow_set.rs
@@ -149,7 +149,7 @@
}
crate fn activations_at_location(&self, location: Location) -> &[BorrowIndex] {
- self.activation_map.get(&location).map(|activations| &activations[..]).unwrap_or(&[])
+ self.activation_map.get(&location).map_or(&[], |activations| &activations[..])
}
crate fn len(&self) -> usize {
diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs
index 1474c7a..cd16a88 100644
--- a/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs
+++ b/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs
@@ -141,6 +141,7 @@
self.add_moved_or_invoked_closure_note(location, used_place, &mut err);
let mut is_loop_move = false;
+ let mut in_pattern = false;
for move_site in &move_site_vec {
let move_out = self.move_data.moves[(*move_site).moi];
@@ -151,95 +152,88 @@
let move_msg = if move_spans.for_closure() { " into closure" } else { "" };
+ let loop_message = if location == move_out.source || move_site.traversed_back_edge {
+ ", in previous iteration of loop"
+ } else {
+ ""
+ };
+
if location == move_out.source {
- err.span_label(
- span,
- format!(
- "value {}moved{} here, in previous iteration of loop",
- partially_str, move_msg
- ),
- );
is_loop_move = true;
- } else if move_site.traversed_back_edge {
+ }
+
+ if let UseSpans::FnSelfUse { var_span, fn_call_span, fn_span, kind } = move_spans {
+ let place_name = self
+ .describe_place(moved_place.as_ref())
+ .map(|n| format!("`{}`", n))
+ .unwrap_or_else(|| "value".to_owned());
+ match kind {
+ FnSelfUseKind::FnOnceCall => {
+ err.span_label(
+ fn_call_span,
+ &format!(
+ "{} {}moved due to this call{}",
+ place_name, partially_str, loop_message
+ ),
+ );
+ err.span_note(
+ var_span,
+ "this value implements `FnOnce`, which causes it to be moved when called",
+ );
+ }
+ FnSelfUseKind::Operator { self_arg } => {
+ err.span_label(
+ fn_call_span,
+ &format!(
+ "{} {}moved due to usage in operator{}",
+ place_name, partially_str, loop_message
+ ),
+ );
+ if self.fn_self_span_reported.insert(fn_span) {
+ err.span_note(
+ self_arg.span,
+ "calling this operator moves the left-hand side",
+ );
+ }
+ }
+ FnSelfUseKind::Normal { self_arg, implicit_into_iter } => {
+ if implicit_into_iter {
+ err.span_label(
+ fn_call_span,
+ &format!(
+ "{} {}moved due to this implicit call to `.into_iter()`{}",
+ place_name, partially_str, loop_message
+ ),
+ );
+ } else {
+ err.span_label(
+ fn_call_span,
+ &format!(
+ "{} {}moved due to this method call{}",
+ place_name, partially_str, loop_message
+ ),
+ );
+ }
+ // Avoid pointing to the same function in multiple different
+ // error messages
+ if self.fn_self_span_reported.insert(self_arg.span) {
+ err.span_note(
+ self_arg.span,
+ &format!("this function takes ownership of the receiver `self`, which moves {}", place_name)
+ );
+ }
+ }
+ // Deref::deref takes &self, which cannot cause a move
+ FnSelfUseKind::DerefCoercion { .. } => unreachable!(),
+ }
+ } else {
err.span_label(
move_span,
- format!(
- "value {}moved{} here, in previous iteration of loop",
- partially_str, move_msg
- ),
+ format!("value {}moved{} here{}", partially_str, move_msg, loop_message),
);
- } else {
- if let UseSpans::FnSelfUse { var_span, fn_call_span, fn_span, kind } =
- move_spans
- {
- let place_name = self
- .describe_place(moved_place.as_ref())
- .map(|n| format!("`{}`", n))
- .unwrap_or_else(|| "value".to_owned());
- match kind {
- FnSelfUseKind::FnOnceCall => {
- err.span_label(
- fn_call_span,
- &format!(
- "{} {}moved due to this call",
- place_name, partially_str
- ),
- );
- err.span_note(
- var_span,
- "this value implements `FnOnce`, which causes it to be moved when called",
- );
- }
- FnSelfUseKind::Operator { self_arg } => {
- err.span_label(
- fn_call_span,
- &format!(
- "{} {}moved due to usage in operator",
- place_name, partially_str
- ),
- );
- if self.fn_self_span_reported.insert(fn_span) {
- err.span_note(
- self_arg.span,
- "calling this operator moves the left-hand side",
- );
- }
- }
- FnSelfUseKind::Normal { self_arg, implicit_into_iter } => {
- if implicit_into_iter {
- err.span_label(
- fn_call_span,
- &format!(
- "{} {}moved due to this implicit call to `.into_iter()`",
- place_name, partially_str
- ),
- );
- } else {
- err.span_label(
- fn_call_span,
- &format!(
- "{} {}moved due to this method call",
- place_name, partially_str
- ),
- );
- }
- // Avoid pointing to the same function in multiple different
- // error messages
- if self.fn_self_span_reported.insert(self_arg.span) {
- err.span_note(
- self_arg.span,
- &format!("this function consumes the receiver `self` by taking ownership of it, which moves {}", place_name)
- );
- }
- }
- // Deref::deref takes &self, which cannot cause a move
- FnSelfUseKind::DerefCoercion { .. } => unreachable!(),
- }
- } else {
- err.span_label(
- move_span,
- format!("value {}moved{} here", partially_str, move_msg),
- );
+ // If the move error occurs due to a loop, don't show
+ // another message for the same span
+ if loop_message.is_empty() {
move_spans.var_span_label(
&mut err,
format!(
@@ -250,6 +244,7 @@
);
}
}
+
if let UseSpans::PatUse(span) = move_spans {
err.span_suggestion_verbose(
span.shrink_to_lo(),
@@ -262,6 +257,7 @@
"ref ".to_string(),
Applicability::MachineApplicable,
);
+ in_pattern = true;
}
if let Some(DesugaringKind::ForLoop(_)) = move_span.desugaring_kind() {
@@ -293,9 +289,7 @@
);
}
- let ty =
- Place::ty_from(used_place.local, used_place.projection, self.body, self.infcx.tcx)
- .ty;
+ let ty = used_place.ty(self.body, self.infcx.tcx).ty;
let needs_note = match ty.kind() {
ty::Closure(id, _) => {
let tables = self.infcx.tcx.typeck(id.expect_local());
@@ -310,7 +304,8 @@
let place = &self.move_data.move_paths[mpi].place;
let ty = place.ty(self.body, self.infcx.tcx).ty;
- if is_loop_move {
+ // If we're in pattern, we do nothing in favor of the previous suggestion (#80913).
+ if is_loop_move & !in_pattern {
if let ty::Ref(_, _, hir::Mutability::Mut) = ty.kind() {
// We have a `&mut` ref, we need to reborrow on each iteration (#62112).
err.span_suggestion_verbose(
@@ -732,8 +727,10 @@
) -> (String, String, String, String) {
// Define a small closure that we can use to check if the type of a place
// is a union.
- let union_ty = |place_base, place_projection| {
- let ty = Place::ty_from(place_base, place_projection, self.body, self.infcx.tcx).ty;
+ let union_ty = |place_base| {
+ // Need to use fn call syntax `PlaceRef::ty` to determine the type of `place_base`;
+ // using a type annotation in the closure argument instead leads to a lifetime error.
+ let ty = PlaceRef::ty(&place_base, self.body, self.infcx.tcx).ty;
ty.ty_adt_def().filter(|adt| adt.is_union()).map(|_| ty)
};
@@ -751,15 +748,10 @@
// field access to a union. If we find that, then we will keep the place of the
// union being accessed and the field that was being accessed so we can check the
// second borrowed place for the same union and a access to a different field.
- let Place { local, projection } = first_borrowed_place;
-
- let mut cursor = projection.as_ref();
- while let [proj_base @ .., elem] = cursor {
- cursor = proj_base;
-
+ for (place_base, elem) in first_borrowed_place.iter_projections().rev() {
match elem {
- ProjectionElem::Field(field, _) if union_ty(local, proj_base).is_some() => {
- return Some((PlaceRef { local, projection: proj_base }, field));
+ ProjectionElem::Field(field, _) if union_ty(place_base).is_some() => {
+ return Some((place_base, field));
}
_ => {}
}
@@ -769,23 +761,12 @@
.and_then(|(target_base, target_field)| {
// With the place of a union and a field access into it, we traverse the second
// borrowed place and look for a access to a different field of the same union.
- let Place { local, ref projection } = second_borrowed_place;
-
- let mut cursor = &projection[..];
- while let [proj_base @ .., elem] = cursor {
- cursor = proj_base;
-
+ for (place_base, elem) in second_borrowed_place.iter_projections().rev() {
if let ProjectionElem::Field(field, _) = elem {
- if let Some(union_ty) = union_ty(local, proj_base) {
- if field != target_field
- && local == target_base.local
- && proj_base == target_base.projection
- {
+ if let Some(union_ty) = union_ty(place_base) {
+ if field != target_field && place_base == target_base {
return Some((
- self.describe_any_place(PlaceRef {
- local,
- projection: proj_base,
- }),
+ self.describe_any_place(place_base),
self.describe_any_place(first_borrowed_place.as_ref()),
self.describe_any_place(second_borrowed_place.as_ref()),
union_ty.to_string(),
@@ -1342,21 +1323,30 @@
Applicability::MachineApplicable,
);
- let msg = match category {
+ match category {
ConstraintCategory::Return(_) | ConstraintCategory::OpaqueType => {
- format!("{} is returned here", kind)
+ let msg = format!("{} is returned here", kind);
+ err.span_note(constraint_span, &msg);
}
ConstraintCategory::CallArgument => {
fr_name.highlight_region_name(&mut err);
- format!("function requires argument type to outlive `{}`", fr_name)
+ if matches!(use_span.generator_kind(), Some(GeneratorKind::Async(_))) {
+ err.note(
+ "async blocks are not executed immediately and must either take a \
+ reference or ownership of outside variables they use",
+ );
+ } else {
+ let msg = format!("function requires argument type to outlive `{}`", fr_name);
+ err.span_note(constraint_span, &msg);
+ }
}
_ => bug!(
"report_escaping_closure_capture called with unexpected constraint \
category: `{:?}`",
category
),
- };
- err.span_note(constraint_span, &msg);
+ }
+
err
}
@@ -1628,20 +1618,17 @@
fn classify_drop_access_kind(&self, place: PlaceRef<'tcx>) -> StorageDeadOrDrop<'tcx> {
let tcx = self.infcx.tcx;
- match place.projection {
- [] => StorageDeadOrDrop::LocalStorageDead,
- [proj_base @ .., elem] => {
+ match place.last_projection() {
+ None => StorageDeadOrDrop::LocalStorageDead,
+ Some((place_base, elem)) => {
// FIXME(spastorino) make this iterate
- let base_access = self.classify_drop_access_kind(PlaceRef {
- local: place.local,
- projection: proj_base,
- });
+ let base_access = self.classify_drop_access_kind(place_base);
match elem {
ProjectionElem::Deref => match base_access {
StorageDeadOrDrop::LocalStorageDead
| StorageDeadOrDrop::BoxedStorageDead => {
assert!(
- Place::ty_from(place.local, proj_base, self.body, tcx).ty.is_box(),
+ place_base.ty(self.body, tcx).ty.is_box(),
"Drop of value behind a reference or raw pointer"
);
StorageDeadOrDrop::BoxedStorageDead
@@ -1649,7 +1636,7 @@
StorageDeadOrDrop::Destructor(_) => base_access,
},
ProjectionElem::Field(..) | ProjectionElem::Downcast(..) => {
- let base_ty = Place::ty_from(place.local, proj_base, self.body, tcx).ty;
+ let base_ty = place_base.ty(self.body, tcx).ty;
match base_ty.kind() {
ty::Adt(def, _) if def.has_dtor(tcx) => {
// Report the outermost adt with a destructor
@@ -1664,7 +1651,6 @@
_ => base_access,
}
}
-
ProjectionElem::ConstantIndex { .. }
| ProjectionElem::Subslice { .. }
| ProjectionElem::Index(_) => base_access,
diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/explain_borrow.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/explain_borrow.rs
index eccb616..06e3f4b 100644
--- a/compiler/rustc_mir/src/borrow_check/diagnostics/explain_borrow.rs
+++ b/compiler/rustc_mir/src/borrow_check/diagnostics/explain_borrow.rs
@@ -5,7 +5,7 @@
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::{Applicability, DiagnosticBuilder};
use rustc_index::vec::IndexVec;
-use rustc_infer::infer::NLLRegionVariableOrigin;
+use rustc_infer::infer::NllRegionVariableOrigin;
use rustc_middle::mir::{
Body, CastKind, ConstraintCategory, FakeReadCause, Local, Location, Operand, Place, Rvalue,
Statement, StatementKind, TerminatorKind,
@@ -75,7 +75,7 @@
LaterUseKind::FakeLetRead => "stored here",
LaterUseKind::Other => "used here",
};
- if !borrow_span.map(|sp| sp.overlaps(var_or_use_span)).unwrap_or(false) {
+ if !borrow_span.map_or(false, |sp| sp.overlaps(var_or_use_span)) {
err.span_label(
var_or_use_span,
format!("{}borrow later {}", borrow_desc, message),
@@ -258,7 +258,7 @@
let (category, from_closure, span) = self.regioncx.best_blame_constraint(
&self.body,
borrow_region,
- NLLRegionVariableOrigin::FreeRegion,
+ NllRegionVariableOrigin::FreeRegion,
|r| self.regioncx.provides_universal_region(r, borrow_region, outlived_region),
);
diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs
index 81571fd..04ea3cb 100644
--- a/compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs
+++ b/compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs
@@ -103,7 +103,7 @@
let did = did.expect_local();
let hir_id = self.infcx.tcx.hir().local_def_id_to_hir_id(did);
- if let Some((span, name)) =
+ if let Some((span, hir_place)) =
self.infcx.tcx.typeck(did).closure_kind_origins().get(hir_id)
{
diag.span_note(
@@ -111,7 +111,7 @@
&format!(
"closure cannot be invoked more than once because it moves the \
variable `{}` out of its environment",
- name,
+ ty::place_to_string_for_capture(self.infcx.tcx, hir_place)
),
);
return;
@@ -127,7 +127,7 @@
let did = did.expect_local();
let hir_id = self.infcx.tcx.hir().local_def_id_to_hir_id(did);
- if let Some((span, name)) =
+ if let Some((span, hir_place)) =
self.infcx.tcx.typeck(did).closure_kind_origins().get(hir_id)
{
diag.span_note(
@@ -135,7 +135,7 @@
&format!(
"closure cannot be moved more than once as it is not `Copy` due to \
moving the variable `{}` out of its environment",
- name
+ ty::place_to_string_for_capture(self.infcx.tcx, hir_place)
),
);
}
@@ -215,6 +215,7 @@
PlaceRef { local, projection: [proj_base @ .., elem] } => {
match elem {
ProjectionElem::Deref => {
+ // FIXME(project-rfc_2229#36): print capture precisely here.
let upvar_field_projection = self.is_upvar_field_projection(place);
if let Some(field) = upvar_field_projection {
let var_index = field.index();
@@ -259,6 +260,7 @@
ProjectionElem::Field(field, _ty) => {
autoderef = true;
+ // FIXME(project-rfc_2229#36): print capture precisely here.
let upvar_field_projection = self.is_upvar_field_projection(place);
if let Some(field) = upvar_field_projection {
let var_index = field.index();
@@ -338,8 +340,7 @@
self.describe_field(PlaceRef { local, projection: proj_base }, field)
}
ProjectionElem::Downcast(_, variant_index) => {
- let base_ty =
- Place::ty_from(place.local, place.projection, self.body, self.infcx.tcx).ty;
+ let base_ty = place.ty(self.body, self.infcx.tcx).ty;
self.describe_field_from_ty(&base_ty, field, Some(*variant_index))
}
ProjectionElem::Field(_, field_type) => {
@@ -473,7 +474,7 @@
// If we didn't find an overloaded deref or index, then assume it's a
// built in deref and check the type of the base.
- let base_ty = Place::ty_from(deref_base.local, deref_base.projection, self.body, tcx).ty;
+ let base_ty = deref_base.ty(self.body, tcx).ty;
if base_ty.is_unsafe_ptr() {
BorrowedContentSource::DerefRawPointer
} else if base_ty.is_mutable_ptr() {
@@ -954,7 +955,7 @@
&self,
def_id: DefId,
target_place: PlaceRef<'tcx>,
- places: &Vec<Operand<'tcx>>,
+ places: &[Operand<'tcx>],
) -> Option<(Span, Option<GeneratorKind>, Span)> {
debug!(
"closure_span: def_id={:?} target_place={:?} places={:?}",
diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/move_errors.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/move_errors.rs
index b1cebbd..fb7694b 100644
--- a/compiler/rustc_mir/src/borrow_check/diagnostics/move_errors.rs
+++ b/compiler/rustc_mir/src/borrow_check/diagnostics/move_errors.rs
@@ -302,7 +302,7 @@
.find_map(|p| self.is_upvar_field_projection(p));
let deref_base = match deref_target_place.projection.as_ref() {
- &[ref proj_base @ .., ProjectionElem::Deref] => {
+ [proj_base @ .., ProjectionElem::Deref] => {
PlaceRef { local: deref_target_place.local, projection: &proj_base }
}
_ => bug!("deref_target_place is not a deref projection"),
@@ -345,7 +345,9 @@
};
let upvar = &self.upvars[upvar_field.unwrap().index()];
- let upvar_hir_id = upvar.var_hir_id;
+ // FIXME(project-rfc-2229#8): Improve borrow-check diagnostics in case of precise
+ // capture.
+ let upvar_hir_id = upvar.place.get_root_variable();
let upvar_name = upvar.name;
let upvar_span = self.infcx.tcx.hir().span(upvar_hir_id);
diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/mutability_errors.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/mutability_errors.rs
index e1af6fc..333ac07 100644
--- a/compiler/rustc_mir/src/borrow_check/diagnostics/mutability_errors.rs
+++ b/compiler/rustc_mir/src/borrow_check/diagnostics/mutability_errors.rs
@@ -1,9 +1,12 @@
use rustc_hir as hir;
use rustc_hir::Node;
use rustc_index::vec::Idx;
-use rustc_middle::mir::{self, ClearCrossCrate, Local, LocalDecl, LocalInfo, Location};
use rustc_middle::mir::{Mutability, Place, PlaceRef, ProjectionElem};
use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_middle::{
+ hir::place::PlaceBase,
+ mir::{self, ClearCrossCrate, Local, LocalDecl, LocalInfo, Location},
+};
use rustc_span::source_map::DesugaringKind;
use rustc_span::symbol::{kw, Symbol};
use rustc_span::Span;
@@ -61,12 +64,29 @@
Place::ty_from(local, proj_base, self.body, self.infcx.tcx).ty
));
- item_msg = format!("`{}`", access_place_desc.unwrap());
- if self.is_upvar_field_projection(access_place.as_ref()).is_some() {
- reason = ", as it is not declared as mutable".to_string();
+ let imm_borrow_derefed = self.upvars[upvar_index.index()]
+ .place
+ .place
+ .deref_tys()
+ .any(|ty| matches!(ty.kind(), ty::Ref(.., hir::Mutability::Not)));
+
+ // If the place is immutable then:
+ //
+ // - Either we deref a immutable ref to get to our final place.
+ // - We don't capture derefs of raw ptrs
+ // - Or the final place is immut because the root variable of the capture
+ // isn't marked mut and we should suggest that to the user.
+ if imm_borrow_derefed {
+ // If we deref an immutable ref then the suggestion here doesn't help.
+ return;
} else {
- let name = self.upvars[upvar_index.index()].name;
- reason = format!(", as `{}` is not declared as mutable", name);
+ item_msg = format!("`{}`", access_place_desc.unwrap());
+ if self.is_upvar_field_projection(access_place.as_ref()).is_some() {
+ reason = ", as it is not declared as mutable".to_string();
+ } else {
+ let name = self.upvars[upvar_index.index()].name;
+ reason = format!(", as `{}` is not declared as mutable", name);
+ }
}
}
@@ -241,6 +261,10 @@
format!("mut {}", self.local_names[local].unwrap()),
Applicability::MachineApplicable,
);
+ let tcx = self.infcx.tcx;
+ if let ty::Closure(id, _) = the_place_err.ty(self.body, tcx).ty.kind() {
+ self.show_mutating_upvar(tcx, id, the_place_err, &mut err);
+ }
}
// Also suggest adding mut for upvars
@@ -252,9 +276,12 @@
Place::ty_from(local, proj_base, self.body, self.infcx.tcx).ty
));
+ let captured_place = &self.upvars[upvar_index.index()].place;
+
err.span_label(span, format!("cannot {ACT}", ACT = act));
- let upvar_hir_id = self.upvars[upvar_index.index()].var_hir_id;
+ let upvar_hir_id = captured_place.get_root_variable();
+
if let Some(Node::Binding(pat)) = self.infcx.tcx.hir().find(upvar_hir_id) {
if let hir::PatKind::Binding(
hir::BindingAnnotation::Unannotated,
@@ -271,6 +298,14 @@
);
}
}
+
+ let tcx = self.infcx.tcx;
+ if let ty::Ref(_, ty, Mutability::Mut) = the_place_err.ty(self.body, tcx).ty.kind()
+ {
+ if let ty::Closure(id, _) = ty.kind() {
+ self.show_mutating_upvar(tcx, id, the_place_err, &mut err);
+ }
+ }
}
// complete hack to approximate old AST-borrowck
@@ -463,6 +498,45 @@
err.buffer(&mut self.errors_buffer);
}
+ // point to span of upvar making closure call require mutable borrow
+ fn show_mutating_upvar(
+ &self,
+ tcx: TyCtxt<'_>,
+ id: &hir::def_id::DefId,
+ the_place_err: PlaceRef<'tcx>,
+ err: &mut DiagnosticBuilder<'_>,
+ ) {
+ let id = id.expect_local();
+ let tables = tcx.typeck(id);
+ let hir_id = tcx.hir().local_def_id_to_hir_id(id);
+ let (span, place) = &tables.closure_kind_origins()[hir_id];
+ let reason = if let PlaceBase::Upvar(upvar_id) = place.base {
+ let upvar = ty::place_to_string_for_capture(tcx, place);
+ match tables.upvar_capture(upvar_id) {
+ ty::UpvarCapture::ByRef(ty::UpvarBorrow {
+ kind: ty::BorrowKind::MutBorrow | ty::BorrowKind::UniqueImmBorrow,
+ ..
+ }) => {
+ format!("mutable borrow of `{}`", upvar)
+ }
+ ty::UpvarCapture::ByValue(_) => {
+ format!("possible mutation of `{}`", upvar)
+ }
+ val => bug!("upvar `{}` borrowed, but not mutably: {:?}", upvar, val),
+ }
+ } else {
+ bug!("not an upvar")
+ };
+ err.span_label(
+ *span,
+ format!(
+ "calling `{}` requires mutable binding due to {}",
+ self.describe_place(the_place_err).unwrap(),
+ reason
+ ),
+ );
+ }
+
/// Targeted error when encountering an `FnMut` closure where an `Fn` closure was expected.
fn expected_fn_found_fn_mut_call(&self, err: &mut DiagnosticBuilder<'_>, sp: Span, act: &str) {
err.span_label(sp, format!("cannot {}", act));
diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/region_errors.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/region_errors.rs
index 78da43c..0589865 100644
--- a/compiler/rustc_mir/src/borrow_check/diagnostics/region_errors.rs
+++ b/compiler/rustc_mir/src/borrow_check/diagnostics/region_errors.rs
@@ -3,7 +3,7 @@
use rustc_errors::{Applicability, DiagnosticBuilder};
use rustc_infer::infer::{
error_reporting::nice_region_error::NiceRegionError,
- error_reporting::unexpected_hidden_region_diagnostic, NLLRegionVariableOrigin,
+ error_reporting::unexpected_hidden_region_diagnostic, NllRegionVariableOrigin,
};
use rustc_middle::mir::{ConstraintCategory, ReturnConstraint};
use rustc_middle::ty::subst::Subst;
@@ -75,13 +75,13 @@
/// The region element that erroneously must be outlived by `longer_fr`.
error_element: RegionElement,
/// The origin of the placeholder region.
- fr_origin: NLLRegionVariableOrigin,
+ fr_origin: NllRegionVariableOrigin,
},
/// Any other lifetime error.
RegionError {
/// The origin of the region.
- fr_origin: NLLRegionVariableOrigin,
+ fr_origin: NllRegionVariableOrigin,
/// The region that should outlive `shorter_fr`.
longer_fr: RegionVid,
/// The region that should be shorter, but we can't prove it.
@@ -269,7 +269,7 @@
pub(in crate::borrow_check) fn report_region_error(
&mut self,
fr: RegionVid,
- fr_origin: NLLRegionVariableOrigin,
+ fr_origin: NllRegionVariableOrigin,
outlived_fr: RegionVid,
outlives_suggestion: &mut OutlivesSuggestionBuilder,
) {
@@ -590,8 +590,8 @@
let mut found = false;
for (bound, _) in bounds {
- if let ty::PredicateAtom::TypeOutlives(ty::OutlivesPredicate(_, r)) =
- bound.skip_binders()
+ if let ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(_, r)) =
+ bound.kind().skip_binder()
{
let r = r.subst(self.infcx.tcx, substs);
if let ty::RegionKind::ReStatic = r {
diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/var_name.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/var_name.rs
index a850b85..4abc623 100644
--- a/compiler/rustc_mir/src/borrow_check/diagnostics/var_name.rs
+++ b/compiler/rustc_mir/src/borrow_check/diagnostics/var_name.rs
@@ -12,7 +12,7 @@
tcx: TyCtxt<'tcx>,
body: &Body<'tcx>,
local_names: &IndexVec<Local, Option<Symbol>>,
- upvars: &[Upvar],
+ upvars: &[Upvar<'tcx>],
fr: RegionVid,
) -> Option<(Option<Symbol>, Span)> {
debug!("get_var_name_and_span_for_region(fr={:?})", fr);
@@ -21,6 +21,7 @@
debug!("get_var_name_and_span_for_region: attempting upvar");
self.get_upvar_index_for_region(tcx, fr)
.map(|index| {
+ // FIXME(project-rfc-2229#8): Use place span for diagnostics
let (name, span) = self.get_upvar_name_and_span_for_region(tcx, upvars, index);
(Some(name), span)
})
@@ -59,10 +60,10 @@
crate fn get_upvar_name_and_span_for_region(
&self,
tcx: TyCtxt<'tcx>,
- upvars: &[Upvar],
+ upvars: &[Upvar<'tcx>],
upvar_index: usize,
) -> (Symbol, Span) {
- let upvar_hir_id = upvars[upvar_index].var_hir_id;
+ let upvar_hir_id = upvars[upvar_index].place.get_root_variable();
debug!("get_upvar_name_and_span_for_region: upvar_hir_id={:?}", upvar_hir_id);
let upvar_name = tcx.hir().name(upvar_hir_id);
diff --git a/compiler/rustc_mir/src/borrow_check/mod.rs b/compiler/rustc_mir/src/borrow_check/mod.rs
index 44044d5..5db52db 100644
--- a/compiler/rustc_mir/src/borrow_check/mod.rs
+++ b/compiler/rustc_mir/src/borrow_check/mod.rs
@@ -5,11 +5,10 @@
use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorReported};
use rustc_hir as hir;
use rustc_hir::def_id::LocalDefId;
-use rustc_hir::{HirId, Node};
+use rustc_hir::Node;
use rustc_index::bit_set::BitSet;
use rustc_index::vec::IndexVec;
use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
-use rustc_middle::hir::place::PlaceBase as HirPlaceBase;
use rustc_middle::mir::{
traversal, Body, ClearCrossCrate, Local, Location, Mutability, Operand, Place, PlaceElem,
PlaceRef, VarDebugInfoContents,
@@ -18,7 +17,7 @@
use rustc_middle::mir::{Field, ProjectionElem, Promoted, Rvalue, Statement, StatementKind};
use rustc_middle::mir::{InlineAsmOperand, Terminator, TerminatorKind};
use rustc_middle::ty::query::Providers;
-use rustc_middle::ty::{self, ParamEnv, RegionVid, TyCtxt};
+use rustc_middle::ty::{self, CapturedPlace, ParamEnv, RegionVid, TyCtxt};
use rustc_session::lint::builtin::{MUTABLE_BORROW_RESERVATION_CONFLICT, UNUSED_MUT};
use rustc_span::{Span, Symbol, DUMMY_SP};
@@ -73,16 +72,14 @@
// FIXME(eddyb) perhaps move this somewhere more centrally.
#[derive(Debug)]
-crate struct Upvar {
+crate struct Upvar<'tcx> {
+ // FIXME(project-rfc_2229#36): print capture precisely here.
name: Symbol,
- // FIXME(project-rfc-2229#8): This should use Place or something similar
- var_hir_id: HirId,
+ place: CapturedPlace<'tcx>,
/// If true, the capture is behind a reference.
by_ref: bool,
-
- mutability: Mutability,
}
const DEREF_PROJECTION: &[PlaceElem<'_>; 1] = &[ProjectionElem::Deref];
@@ -161,26 +158,13 @@
let upvars: Vec<_> = tables
.closure_min_captures_flattened(def.did.to_def_id())
.map(|captured_place| {
- let var_hir_id = match captured_place.place.base {
- HirPlaceBase::Upvar(upvar_id) => upvar_id.var_path.hir_id,
- _ => bug!("Expected upvar"),
- };
+ let var_hir_id = captured_place.get_root_variable();
let capture = captured_place.info.capture_kind;
let by_ref = match capture {
ty::UpvarCapture::ByValue(_) => false,
ty::UpvarCapture::ByRef(..) => true,
};
- let mut upvar = Upvar {
- name: tcx.hir().name(var_hir_id),
- var_hir_id,
- by_ref,
- mutability: Mutability::Not,
- };
- let bm = *tables.pat_binding_modes().get(var_hir_id).expect("missing binding mode");
- if bm == ty::BindByValue(hir::Mutability::Mut) {
- upvar.mutability = Mutability::Mut;
- }
- upvar
+ Upvar { name: tcx.hir().name(var_hir_id), place: captured_place.clone(), by_ref }
})
.collect();
@@ -549,7 +533,7 @@
dominators: Dominators<BasicBlock>,
/// Information about upvars not necessarily preserved in types or MIR
- upvars: Vec<Upvar>,
+ upvars: Vec<Upvar<'tcx>>,
/// Names of local (user) variables (extracted from `var_debug_info`).
local_names: IndexVec<Local, Option<Symbol>>,
@@ -1374,13 +1358,38 @@
fn propagate_closure_used_mut_upvar(&mut self, operand: &Operand<'tcx>) {
let propagate_closure_used_mut_place = |this: &mut Self, place: Place<'tcx>| {
- if !place.projection.is_empty() {
- if let Some(field) = this.is_upvar_field_projection(place.as_ref()) {
- this.used_mut_upvars.push(field);
- }
- } else {
- this.used_mut.insert(place.local);
+ // We have three possibilities here:
+ // a. We are modifying something through a mut-ref
+ // b. We are modifying something that is local to our parent
+ // c. Current body is a nested closure, and we are modifying path starting from
+ // a Place captured by our parent closure.
+
+ // Handle (c), the path being modified is exactly the path captured by our parent
+ if let Some(field) = this.is_upvar_field_projection(place.as_ref()) {
+ this.used_mut_upvars.push(field);
+ return;
}
+
+ for (place_ref, proj) in place.iter_projections().rev() {
+ // Handle (a)
+ if proj == ProjectionElem::Deref {
+ match place_ref.ty(this.body(), this.infcx.tcx).ty.kind() {
+ // We aren't modifying a variable directly
+ ty::Ref(_, _, hir::Mutability::Mut) => return,
+
+ _ => {}
+ }
+ }
+
+ // Handle (c)
+ if let Some(field) = this.is_upvar_field_projection(place_ref) {
+ this.used_mut_upvars.push(field);
+ return;
+ }
+ }
+
+ // Handle(b)
+ this.used_mut.insert(place.local);
};
// This relies on the current way that by-value
@@ -1740,20 +1749,18 @@
self.check_if_full_path_is_moved(location, desired_action, place_span, flow_state);
- if let [base_proj @ .., ProjectionElem::Subslice { from, to, from_end: false }] =
- place_span.0.projection
+ if let Some((place_base, ProjectionElem::Subslice { from, to, from_end: false })) =
+ place_span.0.last_projection()
{
- let place_ty =
- Place::ty_from(place_span.0.local, base_proj, self.body(), self.infcx.tcx);
+ let place_ty = place_base.ty(self.body(), self.infcx.tcx);
if let ty::Array(..) = place_ty.ty.kind() {
- let array_place = PlaceRef { local: place_span.0.local, projection: base_proj };
self.check_if_subslice_element_is_moved(
location,
desired_action,
- (array_place, place_span.1),
+ (place_base, place_span.1),
maybe_uninits,
- *from,
- *to,
+ from,
+ to,
);
return;
}
@@ -1825,10 +1832,7 @@
debug!("check_if_assigned_path_is_moved place: {:?}", place);
// None case => assigning to `x` does not require `x` be initialized.
- let mut cursor = &*place.projection.as_ref();
- while let [proj_base @ .., elem] = cursor {
- cursor = proj_base;
-
+ for (place_base, elem) in place.iter_projections().rev() {
match elem {
ProjectionElem::Index(_/*operand*/) |
ProjectionElem::ConstantIndex { .. } |
@@ -1843,10 +1847,7 @@
ProjectionElem::Deref => {
self.check_if_full_path_is_moved(
location, InitializationRequiringAction::Use,
- (PlaceRef {
- local: place.local,
- projection: proj_base,
- }, span), flow_state);
+ (place_base, span), flow_state);
// (base initialized; no need to
// recur further)
break;
@@ -1862,15 +1863,12 @@
// assigning to `P.f` requires `P` itself
// be already initialized
let tcx = self.infcx.tcx;
- let base_ty = Place::ty_from(place.local, proj_base, self.body(), tcx).ty;
+ let base_ty = place_base.ty(self.body(), tcx).ty;
match base_ty.kind() {
ty::Adt(def, _) if def.has_dtor(tcx) => {
self.check_if_path_or_subpath_is_moved(
location, InitializationRequiringAction::Assignment,
- (PlaceRef {
- local: place.local,
- projection: proj_base,
- }, span), flow_state);
+ (place_base, span), flow_state);
// (base initialized; no need to
// recur further)
@@ -1880,10 +1878,7 @@
// Once `let s; s.x = V; read(s.x);`,
// is allowed, remove this match arm.
ty::Adt(..) | ty::Tuple(..) => {
- check_parent_of_field(self, location, PlaceRef {
- local: place.local,
- projection: proj_base,
- }, span, flow_state);
+ check_parent_of_field(self, location, place_base, span, flow_state);
// rust-lang/rust#21232, #54499, #54986: during period where we reject
// partial initialization, do not complain about unnecessary `mut` on
@@ -1965,9 +1960,7 @@
// no move out from an earlier location) then this is an attempt at initialization
// of the union - we should error in that case.
let tcx = this.infcx.tcx;
- if let ty::Adt(def, _) =
- Place::ty_from(base.local, base.projection, this.body(), tcx).ty.kind()
- {
+ if let ty::Adt(def, _) = base.ty(this.body(), tcx).ty.kind() {
if def.is_union() {
if this.move_data.path_map[mpi].iter().any(|moi| {
this.move_data.moves[*moi].source.is_predecessor_of(location, this.body)
@@ -2162,9 +2155,10 @@
place: PlaceRef<'tcx>,
is_local_mutation_allowed: LocalMutationIsAllowed,
) -> Result<RootPlace<'tcx>, PlaceRef<'tcx>> {
- match place {
- PlaceRef { local, projection: [] } => {
- let local = &self.body.local_decls[local];
+ debug!("is_mutable: place={:?}, is_local...={:?}", place, is_local_mutation_allowed);
+ match place.last_projection() {
+ None => {
+ let local = &self.body.local_decls[place.local];
match local.mutability {
Mutability::Not => match is_local_mutation_allowed {
LocalMutationIsAllowed::Yes => Ok(RootPlace {
@@ -2186,11 +2180,10 @@
}),
}
}
- PlaceRef { local: _, projection: [proj_base @ .., elem] } => {
+ Some((place_base, elem)) => {
match elem {
ProjectionElem::Deref => {
- let base_ty =
- Place::ty_from(place.local, proj_base, self.body(), self.infcx.tcx).ty;
+ let base_ty = place_base.ty(self.body(), self.infcx.tcx).ty;
// Check the kind of deref to decide
match base_ty.kind() {
@@ -2208,10 +2201,7 @@
_ => LocalMutationIsAllowed::Yes,
};
- self.is_mutable(
- PlaceRef { local: place.local, projection: proj_base },
- mode,
- )
+ self.is_mutable(place_base, mode)
}
}
}
@@ -2229,10 +2219,9 @@
}
}
// `Box<T>` owns its content, so mutable if its location is mutable
- _ if base_ty.is_box() => self.is_mutable(
- PlaceRef { local: place.local, projection: proj_base },
- is_local_mutation_allowed,
- ),
+ _ if base_ty.is_box() => {
+ self.is_mutable(place_base, is_local_mutation_allowed)
+ }
// Deref should only be for reference, pointers or boxes
_ => bug!("Deref of unexpected type: {:?}", base_ty),
}
@@ -2248,11 +2237,11 @@
if let Some(field) = upvar_field_projection {
let upvar = &self.upvars[field.index()];
debug!(
- "upvar.mutability={:?} local_mutation_is_allowed={:?} \
- place={:?}",
- upvar, is_local_mutation_allowed, place
+ "is_mutable: upvar.mutability={:?} local_mutation_is_allowed={:?} \
+ place={:?}, place_base={:?}",
+ upvar, is_local_mutation_allowed, place, place_base
);
- match (upvar.mutability, is_local_mutation_allowed) {
+ match (upvar.place.mutability, is_local_mutation_allowed) {
(
Mutability::Not,
LocalMutationIsAllowed::No
@@ -2286,10 +2275,8 @@
// });
// }
// ```
- let _ = self.is_mutable(
- PlaceRef { local: place.local, projection: proj_base },
- is_local_mutation_allowed,
- )?;
+ let _ =
+ self.is_mutable(place_base, is_local_mutation_allowed)?;
Ok(RootPlace {
place_local: place.local,
place_projection: place.projection,
@@ -2298,10 +2285,7 @@
}
}
} else {
- self.is_mutable(
- PlaceRef { local: place.local, projection: proj_base },
- is_local_mutation_allowed,
- )
+ self.is_mutable(place_base, is_local_mutation_allowed)
}
}
}
diff --git a/compiler/rustc_mir/src/borrow_check/nll.rs b/compiler/rustc_mir/src/borrow_check/nll.rs
index 359c5f2..a0265b2 100644
--- a/compiler/rustc_mir/src/borrow_check/nll.rs
+++ b/compiler/rustc_mir/src/borrow_check/nll.rs
@@ -165,7 +165,7 @@
flow_inits: &mut ResultsCursor<'cx, 'tcx, MaybeInitializedPlaces<'cx, 'tcx>>,
move_data: &MoveData<'tcx>,
borrow_set: &BorrowSet<'tcx>,
- upvars: &[Upvar],
+ upvars: &[Upvar<'tcx>],
) -> NllOutput<'tcx> {
let mut all_facts = AllFacts::enabled(infcx.tcx).then_some(AllFacts::default());
diff --git a/compiler/rustc_mir/src/borrow_check/path_utils.rs b/compiler/rustc_mir/src/borrow_check/path_utils.rs
index 9347295..80de3b4 100644
--- a/compiler/rustc_mir/src/borrow_check/path_utils.rs
+++ b/compiler/rustc_mir/src/borrow_check/path_utils.rs
@@ -143,31 +143,29 @@
/// of a closure type.
pub(crate) fn is_upvar_field_projection(
tcx: TyCtxt<'tcx>,
- upvars: &[Upvar],
+ upvars: &[Upvar<'tcx>],
place_ref: PlaceRef<'tcx>,
body: &Body<'tcx>,
) -> Option<Field> {
- let mut place_projection = place_ref.projection;
+ let mut place_ref = place_ref;
let mut by_ref = false;
- if let [proj_base @ .., ProjectionElem::Deref] = place_projection {
- place_projection = proj_base;
+ if let Some((place_base, ProjectionElem::Deref)) = place_ref.last_projection() {
+ place_ref = place_base;
by_ref = true;
}
- match place_projection {
- [base @ .., ProjectionElem::Field(field, _ty)] => {
- let base_ty = Place::ty_from(place_ref.local, base, body, tcx).ty;
-
+ match place_ref.last_projection() {
+ Some((place_base, ProjectionElem::Field(field, _ty))) => {
+ let base_ty = place_base.ty(body, tcx).ty;
if (base_ty.is_closure() || base_ty.is_generator())
&& (!by_ref || upvars[field.index()].by_ref)
{
- Some(*field)
+ Some(field)
} else {
None
}
}
-
_ => None,
}
}
diff --git a/compiler/rustc_mir/src/borrow_check/prefixes.rs b/compiler/rustc_mir/src/borrow_check/prefixes.rs
index 6c5d422..bdf2bec 100644
--- a/compiler/rustc_mir/src/borrow_check/prefixes.rs
+++ b/compiler/rustc_mir/src/borrow_check/prefixes.rs
@@ -10,7 +10,7 @@
use super::MirBorrowckCtxt;
use rustc_hir as hir;
-use rustc_middle::mir::{Body, Place, PlaceRef, ProjectionElem};
+use rustc_middle::mir::{Body, PlaceRef, ProjectionElem};
use rustc_middle::ty::{self, TyCtxt};
pub trait IsPrefixOf<'tcx> {
@@ -67,24 +67,23 @@
// downcasts here, but may return a base of a downcast).
'cursor: loop {
- match &cursor {
- PlaceRef { local: _, projection: [] } => {
+ match cursor.last_projection() {
+ None => {
self.next = None;
return Some(cursor);
}
- PlaceRef { local: _, projection: [proj_base @ .., elem] } => {
+ Some((cursor_base, elem)) => {
match elem {
ProjectionElem::Field(_ /*field*/, _ /*ty*/) => {
// FIXME: add union handling
- self.next =
- Some(PlaceRef { local: cursor.local, projection: proj_base });
+ self.next = Some(cursor_base);
return Some(cursor);
}
ProjectionElem::Downcast(..)
| ProjectionElem::Subslice { .. }
| ProjectionElem::ConstantIndex { .. }
| ProjectionElem::Index(_) => {
- cursor = PlaceRef { local: cursor.local, projection: proj_base };
+ cursor = cursor_base;
continue 'cursor;
}
ProjectionElem::Deref => {
@@ -92,7 +91,7 @@
}
}
- assert_eq!(*elem, ProjectionElem::Deref);
+ assert_eq!(elem, ProjectionElem::Deref);
match self.kind {
PrefixSet::Shallow => {
@@ -105,8 +104,7 @@
PrefixSet::All => {
// All prefixes: just blindly enqueue the base
// of the projection.
- self.next =
- Some(PlaceRef { local: cursor.local, projection: proj_base });
+ self.next = Some(cursor_base);
return Some(cursor);
}
PrefixSet::Supporting => {
@@ -119,7 +117,7 @@
// derefs, except we stop at the deref of a shared
// reference.
- let ty = Place::ty_from(cursor.local, proj_base, self.body, self.tcx).ty;
+ let ty = cursor_base.ty(self.body, self.tcx).ty;
match ty.kind() {
ty::RawPtr(_) | ty::Ref(_ /*rgn*/, _ /*ty*/, hir::Mutability::Not) => {
// don't continue traversing over derefs of raw pointers or shared
@@ -129,14 +127,12 @@
}
ty::Ref(_ /*rgn*/, _ /*ty*/, hir::Mutability::Mut) => {
- self.next =
- Some(PlaceRef { local: cursor.local, projection: proj_base });
+ self.next = Some(cursor_base);
return Some(cursor);
}
ty::Adt(..) if ty.is_box() => {
- self.next =
- Some(PlaceRef { local: cursor.local, projection: proj_base });
+ self.next = Some(cursor_base);
return Some(cursor);
}
diff --git a/compiler/rustc_mir/src/borrow_check/region_infer/dump_mir.rs b/compiler/rustc_mir/src/borrow_check/region_infer/dump_mir.rs
index d6e48de..86d9db2 100644
--- a/compiler/rustc_mir/src/borrow_check/region_infer/dump_mir.rs
+++ b/compiler/rustc_mir/src/borrow_check/region_infer/dump_mir.rs
@@ -5,7 +5,7 @@
use super::{OutlivesConstraint, RegionInferenceContext};
use crate::borrow_check::type_check::Locations;
-use rustc_infer::infer::NLLRegionVariableOrigin;
+use rustc_infer::infer::NllRegionVariableOrigin;
use rustc_middle::ty::TyCtxt;
use std::io::{self, Write};
@@ -20,7 +20,7 @@
writeln!(out, "| Free Region Mapping")?;
for region in self.regions() {
- if let NLLRegionVariableOrigin::FreeRegion = self.definitions[region].origin {
+ if let NllRegionVariableOrigin::FreeRegion = self.definitions[region].origin {
let classification = self.universal_regions.region_classification(region).unwrap();
let outlived_by = self.universal_region_relations.regions_outlived_by(region);
writeln!(
diff --git a/compiler/rustc_mir/src/borrow_check/region_infer/mod.rs b/compiler/rustc_mir/src/borrow_check/region_infer/mod.rs
index 9d45f6f..bbd512f 100644
--- a/compiler/rustc_mir/src/borrow_check/region_infer/mod.rs
+++ b/compiler/rustc_mir/src/borrow_check/region_infer/mod.rs
@@ -9,7 +9,7 @@
use rustc_index::vec::IndexVec;
use rustc_infer::infer::canonical::QueryOutlivesConstraint;
use rustc_infer::infer::region_constraints::{GenericKind, VarInfos, VerifyBound};
-use rustc_infer::infer::{InferCtxt, NLLRegionVariableOrigin, RegionVariableOrigin};
+use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin, RegionVariableOrigin};
use rustc_middle::mir::{
Body, ClosureOutlivesRequirement, ClosureOutlivesSubject, ClosureRegionRequirements,
ConstraintCategory, Local, Location, ReturnConstraint,
@@ -143,9 +143,9 @@
pub(crate) struct RegionDefinition<'tcx> {
/// What kind of variable is this -- a free region? existential
- /// variable? etc. (See the `NLLRegionVariableOrigin` for more
+ /// variable? etc. (See the `NllRegionVariableOrigin` for more
/// info.)
- pub(in crate::borrow_check) origin: NLLRegionVariableOrigin,
+ pub(in crate::borrow_check) origin: NllRegionVariableOrigin,
/// Which universe is this region variable defined in? This is
/// most often `ty::UniverseIndex::ROOT`, but when we encounter
@@ -451,7 +451,7 @@
let scc = self.constraint_sccs.scc(variable);
match self.definitions[variable].origin {
- NLLRegionVariableOrigin::FreeRegion => {
+ NllRegionVariableOrigin::FreeRegion => {
// For each free, universally quantified region X:
// Add all nodes in the CFG to liveness constraints
@@ -462,7 +462,7 @@
self.scc_values.add_element(scc, variable);
}
- NLLRegionVariableOrigin::Placeholder(placeholder) => {
+ NllRegionVariableOrigin::Placeholder(placeholder) => {
// Each placeholder region is only visible from
// its universe `ui` and its extensions. So we
// can't just add it into `scc` unless the
@@ -480,8 +480,8 @@
}
}
- NLLRegionVariableOrigin::RootEmptyRegion
- | NLLRegionVariableOrigin::Existential { .. } => {
+ NllRegionVariableOrigin::RootEmptyRegion
+ | NllRegionVariableOrigin::Existential { .. } => {
// For existential, regions, nothing to do.
}
}
@@ -1348,7 +1348,7 @@
) {
for (fr, fr_definition) in self.definitions.iter_enumerated() {
match fr_definition.origin {
- NLLRegionVariableOrigin::FreeRegion => {
+ NllRegionVariableOrigin::FreeRegion => {
// Go through each of the universal regions `fr` and check that
// they did not grow too large, accumulating any requirements
// for our caller into the `outlives_requirements` vector.
@@ -1360,12 +1360,12 @@
);
}
- NLLRegionVariableOrigin::Placeholder(placeholder) => {
+ NllRegionVariableOrigin::Placeholder(placeholder) => {
self.check_bound_universal_region(fr, placeholder, errors_buffer);
}
- NLLRegionVariableOrigin::RootEmptyRegion
- | NLLRegionVariableOrigin::Existential { .. } => {
+ NllRegionVariableOrigin::RootEmptyRegion
+ | NllRegionVariableOrigin::Existential { .. } => {
// nothing to check here
}
}
@@ -1449,7 +1449,7 @@
errors_buffer.push(RegionErrorKind::RegionError {
longer_fr: *longer_fr,
shorter_fr: *shorter_fr,
- fr_origin: NLLRegionVariableOrigin::FreeRegion,
+ fr_origin: NllRegionVariableOrigin::FreeRegion,
is_reported: true,
});
}
@@ -1459,16 +1459,16 @@
// a more complete picture on how to separate this responsibility.
for (fr, fr_definition) in self.definitions.iter_enumerated() {
match fr_definition.origin {
- NLLRegionVariableOrigin::FreeRegion => {
+ NllRegionVariableOrigin::FreeRegion => {
// handled by polonius above
}
- NLLRegionVariableOrigin::Placeholder(placeholder) => {
+ NllRegionVariableOrigin::Placeholder(placeholder) => {
self.check_bound_universal_region(fr, placeholder, errors_buffer);
}
- NLLRegionVariableOrigin::RootEmptyRegion
- | NLLRegionVariableOrigin::Existential { .. } => {
+ NllRegionVariableOrigin::RootEmptyRegion
+ | NllRegionVariableOrigin::Existential { .. } => {
// nothing to check here
}
}
@@ -1516,7 +1516,7 @@
errors_buffer.push(RegionErrorKind::RegionError {
longer_fr,
shorter_fr: representative,
- fr_origin: NLLRegionVariableOrigin::FreeRegion,
+ fr_origin: NllRegionVariableOrigin::FreeRegion,
is_reported: true,
});
}
@@ -1539,7 +1539,7 @@
errors_buffer.push(RegionErrorKind::RegionError {
longer_fr,
shorter_fr,
- fr_origin: NLLRegionVariableOrigin::FreeRegion,
+ fr_origin: NllRegionVariableOrigin::FreeRegion,
is_reported: !error_reported,
});
@@ -1597,7 +1597,7 @@
let blame_span_category = self.find_outlives_blame_span(
body,
longer_fr,
- NLLRegionVariableOrigin::FreeRegion,
+ NllRegionVariableOrigin::FreeRegion,
shorter_fr,
);
@@ -1656,7 +1656,7 @@
errors_buffer.push(RegionErrorKind::BoundUniversalRegionError {
longer_fr,
error_element,
- fr_origin: NLLRegionVariableOrigin::Placeholder(placeholder),
+ fr_origin: NllRegionVariableOrigin::Placeholder(placeholder),
});
}
@@ -1732,7 +1732,7 @@
debug!("cannot_name_value_of(r1={:?}, r2={:?})", r1, r2);
match self.definitions[r2].origin {
- NLLRegionVariableOrigin::Placeholder(placeholder) => {
+ NllRegionVariableOrigin::Placeholder(placeholder) => {
let universe1 = self.definitions[r1].universe;
debug!(
"cannot_name_value_of: universe1={:?} placeholder={:?}",
@@ -1741,9 +1741,9 @@
universe1.cannot_name(placeholder.universe)
}
- NLLRegionVariableOrigin::RootEmptyRegion
- | NLLRegionVariableOrigin::FreeRegion
- | NLLRegionVariableOrigin::Existential { .. } => false,
+ NllRegionVariableOrigin::RootEmptyRegion
+ | NllRegionVariableOrigin::FreeRegion
+ | NllRegionVariableOrigin::Existential { .. } => false,
}
}
@@ -1771,7 +1771,7 @@
&self,
body: &Body<'tcx>,
fr1: RegionVid,
- fr1_origin: NLLRegionVariableOrigin,
+ fr1_origin: NllRegionVariableOrigin,
fr2: RegionVid,
) -> (ConstraintCategory, Span) {
let (category, _, span) = self.best_blame_constraint(body, fr1, fr1_origin, |r| {
@@ -1933,7 +1933,7 @@
.definitions
.iter_enumerated()
.find_map(|(r, definition)| match definition.origin {
- NLLRegionVariableOrigin::Placeholder(p) if p == error_placeholder => Some(r),
+ NllRegionVariableOrigin::Placeholder(p) if p == error_placeholder => Some(r),
_ => None,
})
.unwrap(),
@@ -1965,7 +1965,7 @@
&self,
body: &Body<'tcx>,
from_region: RegionVid,
- from_region_origin: NLLRegionVariableOrigin,
+ from_region_origin: NllRegionVariableOrigin,
target_test: impl Fn(RegionVid) -> bool,
) -> (ConstraintCategory, bool, Span) {
debug!(
@@ -2059,11 +2059,11 @@
//
// and here we prefer to blame the source (the y = x statement).
let blame_source = match from_region_origin {
- NLLRegionVariableOrigin::FreeRegion
- | NLLRegionVariableOrigin::Existential { from_forall: false } => true,
- NLLRegionVariableOrigin::RootEmptyRegion
- | NLLRegionVariableOrigin::Placeholder(_)
- | NLLRegionVariableOrigin::Existential { from_forall: true } => false,
+ NllRegionVariableOrigin::FreeRegion
+ | NllRegionVariableOrigin::Existential { from_forall: false } => true,
+ NllRegionVariableOrigin::RootEmptyRegion
+ | NllRegionVariableOrigin::Placeholder(_)
+ | NllRegionVariableOrigin::Existential { from_forall: true } => false,
};
let find_region = |i: &usize| {
@@ -2144,8 +2144,8 @@
// `init_universal_regions`.
let origin = match rv_origin {
- RegionVariableOrigin::NLL(origin) => origin,
- _ => NLLRegionVariableOrigin::Existential { from_forall: false },
+ RegionVariableOrigin::Nll(origin) => origin,
+ _ => NllRegionVariableOrigin::Existential { from_forall: false },
};
Self { origin, universe, external_name: None }
diff --git a/compiler/rustc_mir/src/borrow_check/renumber.rs b/compiler/rustc_mir/src/borrow_check/renumber.rs
index e563e37..9377473 100644
--- a/compiler/rustc_mir/src/borrow_check/renumber.rs
+++ b/compiler/rustc_mir/src/borrow_check/renumber.rs
@@ -1,5 +1,5 @@
use rustc_index::vec::IndexVec;
-use rustc_infer::infer::{InferCtxt, NLLRegionVariableOrigin};
+use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin};
use rustc_middle::mir::visit::{MutVisitor, TyContext};
use rustc_middle::mir::{Body, Location, PlaceElem, Promoted};
use rustc_middle::ty::subst::SubstsRef;
@@ -15,7 +15,7 @@
debug!("renumber_mir()");
debug!("renumber_mir: body.arg_count={:?}", body.arg_count);
- let mut visitor = NLLVisitor { infcx };
+ let mut visitor = NllVisitor { infcx };
for body in promoted.iter_mut() {
visitor.visit_body(body);
@@ -33,16 +33,16 @@
debug!("renumber_regions(value={:?})", value);
infcx.tcx.fold_regions(value, &mut false, |_region, _depth| {
- let origin = NLLRegionVariableOrigin::Existential { from_forall: false };
+ let origin = NllRegionVariableOrigin::Existential { from_forall: false };
infcx.next_nll_region_var(origin)
})
}
-struct NLLVisitor<'a, 'tcx> {
+struct NllVisitor<'a, 'tcx> {
infcx: &'a InferCtxt<'a, 'tcx>,
}
-impl<'a, 'tcx> NLLVisitor<'a, 'tcx> {
+impl<'a, 'tcx> NllVisitor<'a, 'tcx> {
fn renumber_regions<T>(&mut self, value: T) -> T
where
T: TypeFoldable<'tcx>,
@@ -51,7 +51,7 @@
}
}
-impl<'a, 'tcx> MutVisitor<'tcx> for NLLVisitor<'a, 'tcx> {
+impl<'a, 'tcx> MutVisitor<'tcx> for NllVisitor<'a, 'tcx> {
fn tcx(&self) -> TyCtxt<'tcx> {
self.infcx.tcx
}
diff --git a/compiler/rustc_mir/src/borrow_check/type_check/input_output.rs b/compiler/rustc_mir/src/borrow_check/type_check/input_output.rs
index b7d22fa..157959b 100644
--- a/compiler/rustc_mir/src/borrow_check/type_check/input_output.rs
+++ b/compiler/rustc_mir/src/borrow_check/type_check/input_output.rs
@@ -39,10 +39,8 @@
user_provided_sig = None;
} else {
let typeck_results = self.tcx().typeck(mir_def_id);
- user_provided_sig = match typeck_results.user_provided_sigs.get(&mir_def_id.to_def_id())
- {
- None => None,
- Some(user_provided_poly_sig) => {
+ user_provided_sig = typeck_results.user_provided_sigs.get(&mir_def_id.to_def_id()).map(
+ |user_provided_poly_sig| {
// Instantiate the canonicalized variables from
// user-provided signature (e.g., the `_` in the code
// above) with fresh variables.
@@ -54,18 +52,16 @@
// Replace the bound items in the fn sig with fresh
// variables, so that they represent the view from
// "inside" the closure.
- Some(
- self.infcx
- .replace_bound_vars_with_fresh_vars(
- body.span,
- LateBoundRegionConversionTime::FnCall,
- poly_sig,
- )
- .0,
- )
- }
- }
- };
+ self.infcx
+ .replace_bound_vars_with_fresh_vars(
+ body.span,
+ LateBoundRegionConversionTime::FnCall,
+ poly_sig,
+ )
+ .0
+ },
+ );
+ }
debug!(
"equate_inputs_and_outputs: normalized_input_tys = {:?}, local_decls = {:?}",
diff --git a/compiler/rustc_mir/src/borrow_check/type_check/liveness/local_use_map.rs b/compiler/rustc_mir/src/borrow_check/type_check/liveness/local_use_map.rs
index 995e3a6..7e8a33e 100644
--- a/compiler/rustc_mir/src/borrow_check/type_check/liveness/local_use_map.rs
+++ b/compiler/rustc_mir/src/borrow_check/type_check/liveness/local_use_map.rs
@@ -58,11 +58,7 @@
}
impl LocalUseMap {
- crate fn build(
- live_locals: &Vec<Local>,
- elements: &RegionValueElements,
- body: &Body<'_>,
- ) -> Self {
+ crate fn build(live_locals: &[Local], elements: &RegionValueElements, body: &Body<'_>) -> Self {
let nones = IndexVec::from_elem_n(None, body.local_decls.len());
let mut local_use_map = LocalUseMap {
first_def_at: nones.clone(),
diff --git a/compiler/rustc_mir/src/borrow_check/type_check/mod.rs b/compiler/rustc_mir/src/borrow_check/type_check/mod.rs
index 42cd050..3ba06bd 100644
--- a/compiler/rustc_mir/src/borrow_check/type_check/mod.rs
+++ b/compiler/rustc_mir/src/borrow_check/type_check/mod.rs
@@ -16,7 +16,7 @@
use rustc_infer::infer::outlives::env::RegionBoundPairs;
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_infer::infer::{
- InferCtxt, InferOk, LateBoundRegionConversionTime, NLLRegionVariableOrigin,
+ InferCtxt, InferOk, LateBoundRegionConversionTime, NllRegionVariableOrigin,
};
use rustc_middle::mir::tcx::PlaceTy;
use rustc_middle::mir::visit::{NonMutatingUseContext, PlaceContext, Visitor};
@@ -43,10 +43,6 @@
use crate::dataflow::impls::MaybeInitializedPlaces;
use crate::dataflow::move_paths::MoveData;
use crate::dataflow::ResultsCursor;
-use crate::transform::{
- check_consts::ConstCx,
- promote_consts::should_suggest_const_in_array_repeat_expressions_attribute,
-};
use crate::borrow_check::{
borrow_set::BorrowSet,
@@ -132,7 +128,7 @@
flow_inits: &mut ResultsCursor<'mir, 'tcx, MaybeInitializedPlaces<'mir, 'tcx>>,
move_data: &MoveData<'tcx>,
elements: &Rc<RegionValueElements>,
- upvars: &[Upvar],
+ upvars: &[Upvar<'tcx>],
) -> MirTypeckResults<'tcx> {
let implicit_region_bound = infcx.tcx.mk_region(ty::ReVar(universal_regions.fr_fn_body));
let mut constraints = MirTypeckRegionConstraints {
@@ -821,7 +817,7 @@
all_facts: &'a mut Option<AllFacts>,
borrow_set: &'a BorrowSet<'tcx>,
constraints: &'a mut MirTypeckRegionConstraints<'tcx>,
- upvars: &'a [Upvar],
+ upvars: &'a [Upvar<'tcx>],
}
crate struct MirTypeckResults<'tcx> {
@@ -876,7 +872,7 @@
match self.placeholder_index_to_region.get(placeholder_index) {
Some(&v) => v,
None => {
- let origin = NLLRegionVariableOrigin::Placeholder(placeholder);
+ let origin = NllRegionVariableOrigin::Placeholder(placeholder);
let region = infcx.next_nll_region_var_in_universe(origin, placeholder.universe);
self.placeholder_index_to_region.push(region);
region
@@ -1014,7 +1010,7 @@
}
self.prove_predicate(
- ty::PredicateAtom::WellFormed(inferred_ty.into()).to_predicate(self.tcx()),
+ ty::PredicateKind::WellFormed(inferred_ty.into()).to_predicate(self.tcx()),
Locations::All(span),
ConstraintCategory::TypeAnnotation,
);
@@ -1266,7 +1262,7 @@
obligations.obligations.push(traits::Obligation::new(
ObligationCause::dummy(),
param_env,
- ty::PredicateAtom::WellFormed(revealed_ty.into()).to_predicate(infcx.tcx),
+ ty::PredicateKind::WellFormed(revealed_ty.into()).to_predicate(infcx.tcx),
));
obligations.add(
infcx
@@ -1611,7 +1607,7 @@
self.check_call_dest(body, term, &sig, destination, term_location);
self.prove_predicates(
- sig.inputs_and_output.iter().map(|ty| ty::PredicateAtom::WellFormed(ty.into())),
+ sig.inputs_and_output.iter().map(|ty| ty::PredicateKind::WellFormed(ty.into())),
term_location.to_locations(),
ConstraintCategory::Boring,
);
@@ -1855,8 +1851,8 @@
self.assert_iscleanup(body, block_data, unwind, true);
}
}
- TerminatorKind::InlineAsm { ref destination, .. } => {
- if let &Some(target) = destination {
+ TerminatorKind::InlineAsm { destination, .. } => {
+ if let Some(target) = destination {
self.assert_iscleanup(body, block_data, target, is_cleanup);
}
}
@@ -1997,22 +1993,13 @@
let span = body.source_info(location).span;
let ty = operand.ty(body, tcx);
if !self.infcx.type_is_copy_modulo_regions(self.param_env, ty, span) {
- let ccx = ConstCx::new_with_param_env(tcx, body, self.param_env);
- // To determine if `const_in_array_repeat_expressions` feature gate should
- // be mentioned, need to check if the rvalue is promotable.
- let should_suggest =
- should_suggest_const_in_array_repeat_expressions_attribute(
- &ccx, operand,
- );
- debug!("check_rvalue: should_suggest={:?}", should_suggest);
-
let def_id = body.source.def_id().expect_local();
self.infcx.report_selection_error(
&traits::Obligation::new(
ObligationCause::new(
span,
self.tcx().hir().local_def_id_to_hir_id(def_id),
- traits::ObligationCauseCode::RepeatVec(should_suggest),
+ traits::ObligationCauseCode::RepeatVec,
),
self.param_env,
ty::Binder::bind(ty::TraitRef::new(
@@ -2490,7 +2477,9 @@
body,
);
let category = if let Some(field) = field {
- ConstraintCategory::ClosureUpvar(self.borrowck_context.upvars[field.index()].var_hir_id)
+ let var_hir_id = self.borrowck_context.upvars[field.index()].place.get_root_variable();
+ // FIXME(project-rfc-2229#8): Use Place for better diagnostics
+ ConstraintCategory::ClosureUpvar(var_hir_id)
} else {
ConstraintCategory::Boring
};
@@ -2694,7 +2683,7 @@
category: ConstraintCategory,
) {
self.prove_predicates(
- Some(ty::PredicateAtom::Trait(
+ Some(ty::PredicateKind::Trait(
ty::TraitPredicate { trait_ref },
hir::Constness::NotConst,
)),
diff --git a/compiler/rustc_mir/src/borrow_check/type_check/relate_tys.rs b/compiler/rustc_mir/src/borrow_check/type_check/relate_tys.rs
index 91b1a1f..6665eb5 100644
--- a/compiler/rustc_mir/src/borrow_check/type_check/relate_tys.rs
+++ b/compiler/rustc_mir/src/borrow_check/type_check/relate_tys.rs
@@ -1,5 +1,5 @@
use rustc_infer::infer::nll_relate::{NormalizationStrategy, TypeRelating, TypeRelatingDelegate};
-use rustc_infer::infer::{InferCtxt, NLLRegionVariableOrigin};
+use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin};
use rustc_middle::mir::ConstraintCategory;
use rustc_middle::ty::relate::TypeRelation;
use rustc_middle::ty::{self, Const, Ty};
@@ -64,7 +64,7 @@
fn next_existential_region_var(&mut self, from_forall: bool) -> ty::Region<'tcx> {
if self.borrowck_context.is_some() {
- let origin = NLLRegionVariableOrigin::Existential { from_forall };
+ let origin = NllRegionVariableOrigin::Existential { from_forall };
self.infcx.next_nll_region_var(origin)
} else {
self.infcx.tcx.lifetimes.re_erased
@@ -81,7 +81,7 @@
fn generalize_existential(&mut self, universe: ty::UniverseIndex) -> ty::Region<'tcx> {
self.infcx.next_nll_region_var_in_universe(
- NLLRegionVariableOrigin::Existential { from_forall: false },
+ NllRegionVariableOrigin::Existential { from_forall: false },
universe,
)
}
diff --git a/compiler/rustc_mir/src/borrow_check/universal_regions.rs b/compiler/rustc_mir/src/borrow_check/universal_regions.rs
index c1a0d98..4b1acc1 100644
--- a/compiler/rustc_mir/src/borrow_check/universal_regions.rs
+++ b/compiler/rustc_mir/src/borrow_check/universal_regions.rs
@@ -20,7 +20,7 @@
use rustc_hir::lang_items::LangItem;
use rustc_hir::{BodyOwnerKind, HirId};
use rustc_index::vec::{Idx, IndexVec};
-use rustc_infer::infer::{InferCtxt, NLLRegionVariableOrigin};
+use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin};
use rustc_middle::ty::fold::TypeFoldable;
use rustc_middle::ty::subst::{InternalSubsts, Subst, SubstsRef};
use rustc_middle::ty::{self, RegionVid, Ty, TyCtxt};
@@ -393,7 +393,7 @@
param_env: ty::ParamEnv<'tcx>,
}
-const FR: NLLRegionVariableOrigin = NLLRegionVariableOrigin::FreeRegion;
+const FR: NllRegionVariableOrigin = NllRegionVariableOrigin::FreeRegion;
impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
fn build(self) -> UniversalRegions<'tcx> {
@@ -486,7 +486,7 @@
let root_empty = self
.infcx
- .next_nll_region_var(NLLRegionVariableOrigin::RootEmptyRegion)
+ .next_nll_region_var(NllRegionVariableOrigin::RootEmptyRegion)
.to_region_vid();
UniversalRegions {
@@ -647,7 +647,7 @@
trait InferCtxtExt<'tcx> {
fn replace_free_regions_with_nll_infer_vars<T>(
&self,
- origin: NLLRegionVariableOrigin,
+ origin: NllRegionVariableOrigin,
value: T,
) -> T
where
@@ -655,7 +655,7 @@
fn replace_bound_regions_with_nll_infer_vars<T>(
&self,
- origin: NLLRegionVariableOrigin,
+ origin: NllRegionVariableOrigin,
all_outlive_scope: LocalDefId,
value: ty::Binder<T>,
indices: &mut UniversalRegionIndices<'tcx>,
@@ -673,7 +673,7 @@
impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> {
fn replace_free_regions_with_nll_infer_vars<T>(
&self,
- origin: NLLRegionVariableOrigin,
+ origin: NllRegionVariableOrigin,
value: T,
) -> T
where
@@ -684,7 +684,7 @@
fn replace_bound_regions_with_nll_infer_vars<T>(
&self,
- origin: NLLRegionVariableOrigin,
+ origin: NllRegionVariableOrigin,
all_outlive_scope: LocalDefId,
value: ty::Binder<T>,
indices: &mut UniversalRegionIndices<'tcx>,
@@ -788,13 +788,13 @@
fn_def_id: DefId,
mut f: impl FnMut(ty::Region<'tcx>),
) {
- if let Some(late_bounds) = tcx.is_late_bound_map(fn_def_id.expect_local()) {
- for late_bound in late_bounds.iter() {
- let hir_id = HirId { owner: fn_def_id.expect_local(), local_id: *late_bound };
+ if let Some((owner, late_bounds)) = tcx.is_late_bound_map(fn_def_id.expect_local()) {
+ for &late_bound in late_bounds.iter() {
+ let hir_id = HirId { owner, local_id: late_bound };
let name = tcx.hir().name(hir_id);
let region_def_id = tcx.hir().local_def_id(hir_id);
let liberated_region = tcx.mk_region(ty::ReFree(ty::FreeRegion {
- scope: fn_def_id,
+ scope: owner.to_def_id(),
bound_region: ty::BoundRegionKind::BrNamed(region_def_id.to_def_id(), name),
}));
f(liberated_region);
diff --git a/compiler/rustc_mir/src/const_eval/eval_queries.rs b/compiler/rustc_mir/src/const_eval/eval_queries.rs
index df163f6..252f5e7 100644
--- a/compiler/rustc_mir/src/const_eval/eval_queries.rs
+++ b/compiler/rustc_mir/src/const_eval/eval_queries.rs
@@ -298,6 +298,8 @@
tcx.def_span(def.did),
key.param_env,
CompileTimeInterpreter::new(tcx.sess.const_eval_limit()),
+ // Statics (and promoteds inside statics) may access other statics, because unlike consts
+ // they do not have to behave "as if" they were evaluated at runtime.
MemoryExtra { can_access_statics: is_static },
);
@@ -305,83 +307,35 @@
match res.and_then(|body| eval_body_using_ecx(&mut ecx, cid, &body)) {
Err(error) => {
let err = ConstEvalErr::new(&ecx, error, None);
- // errors in statics are always emitted as fatal errors
- if is_static {
- // Ensure that if the above error was either `TooGeneric` or `Reported`
- // an error must be reported.
- let v = err.report_as_error(
- ecx.tcx.at(ecx.cur_span()),
- "could not evaluate static initializer",
- );
-
- // If this is `Reveal:All`, then we need to make sure an error is reported but if
- // this is `Reveal::UserFacing`, then it's expected that we could get a
- // `TooGeneric` error. When we fall back to `Reveal::All`, then it will either
- // succeed or we'll report this error then.
- if key.param_env.reveal() == Reveal::All {
- tcx.sess.delay_span_bug(
- err.span,
- &format!("static eval failure did not emit an error: {:#?}", v),
- );
- }
-
- Err(v)
- } else if let Some(def) = def.as_local() {
- // constant defined in this crate, we can figure out a lint level!
- match tcx.def_kind(def.did.to_def_id()) {
- // constants never produce a hard error at the definition site. Anything else is
- // a backwards compatibility hazard (and will break old versions of winapi for
- // sure)
- //
- // note that validation may still cause a hard error on this very same constant,
- // because any code that existed before validation could not have failed
- // validation thus preventing such a hard error from being a backwards
- // compatibility hazard
- DefKind::Const | DefKind::AssocConst => {
- let hir_id = tcx.hir().local_def_id_to_hir_id(def.did);
- Err(err.report_as_lint(
- tcx.at(tcx.def_span(def.did)),
- "any use of this value will cause an error",
- hir_id,
- Some(err.span),
- ))
- }
- // promoting runtime code is only allowed to error if it references broken
- // constants any other kind of error will be reported to the user as a
- // deny-by-default lint
- _ => {
- if let Some(p) = cid.promoted {
- let span = tcx.promoted_mir_opt_const_arg(def.to_global())[p].span;
- if let err_inval!(ReferencedConstant) = err.error {
- Err(err.report_as_error(
- tcx.at(span),
- "evaluation of constant expression failed",
- ))
- } else {
- Err(err.report_as_lint(
- tcx.at(span),
- "reaching this expression at runtime will panic or abort",
- tcx.hir().local_def_id_to_hir_id(def.did),
- Some(err.span),
- ))
- }
- // anything else (array lengths, enum initializers, constant patterns) are
- // reported as hard errors
- } else {
- Err(err.report_as_error(
- ecx.tcx.at(ecx.cur_span()),
- "evaluation of constant value failed",
- ))
- }
- }
- }
+ // Some CTFE errors raise just a lint, not a hard error; see
+ // <https://github.com/rust-lang/rust/issues/71800>.
+ let emit_as_lint = if let Some(def) = def.as_local() {
+ // (Associated) consts only emit a lint, since they might be unused.
+ matches!(tcx.def_kind(def.did.to_def_id()), DefKind::Const | DefKind::AssocConst)
} else {
- // use of broken constant from other crate
- Err(err.report_as_error(ecx.tcx.at(ecx.cur_span()), "could not evaluate constant"))
+ // use of broken constant from other crate: always an error
+ false
+ };
+ if emit_as_lint {
+ let hir_id = tcx.hir().local_def_id_to_hir_id(def.as_local().unwrap().did);
+ Err(err.report_as_lint(
+ tcx.at(tcx.def_span(def.did)),
+ "any use of this value will cause an error",
+ hir_id,
+ Some(err.span),
+ ))
+ } else {
+ let msg = if is_static {
+ "could not evaluate static initializer"
+ } else {
+ "evaluation of constant value failed"
+ };
+ Err(err.report_as_error(ecx.tcx.at(ecx.cur_span()), msg))
}
}
Ok(mplace) => {
- // Since evaluation had no errors, valiate the resulting constant:
+ // Since evaluation had no errors, validate the resulting constant.
+ // This is a separate `try` block to provide more targeted error reporting.
let validation = try {
let mut ref_tracking = RefTracking::new(mplace);
let mut inner = false;
@@ -399,7 +353,7 @@
}
};
if let Err(error) = validation {
- // Validation failed, report an error
+ // Validation failed, report an error. This is always a hard error.
let err = ConstEvalErr::new(&ecx, error, None);
Err(err.struct_error(
ecx.tcx,
diff --git a/compiler/rustc_mir/src/const_eval/fn_queries.rs b/compiler/rustc_mir/src/const_eval/fn_queries.rs
index aca822a..8c18dfc 100644
--- a/compiler/rustc_mir/src/const_eval/fn_queries.rs
+++ b/compiler/rustc_mir/src/const_eval/fn_queries.rs
@@ -126,7 +126,7 @@
matches!(
node,
hir::Node::Item(hir::Item {
- kind: hir::ItemKind::Impl { constness: hir::Constness::Const, .. },
+ kind: hir::ItemKind::Impl(hir::Impl { constness: hir::Constness::Const, .. }),
..
})
)
diff --git a/compiler/rustc_mir/src/const_eval/machine.rs b/compiler/rustc_mir/src/const_eval/machine.rs
index 72912dd..49126cf 100644
--- a/compiler/rustc_mir/src/const_eval/machine.rs
+++ b/compiler/rustc_mir/src/const_eval/machine.rs
@@ -13,6 +13,7 @@
use rustc_session::Limit;
use rustc_span::symbol::{sym, Symbol};
use rustc_target::abi::{Align, Size};
+use rustc_target::spec::abi::Abi;
use crate::interpret::{
self, compile_time_machine, AllocId, Allocation, Frame, ImmTy, InterpCx, InterpResult, Memory,
@@ -200,9 +201,26 @@
type MemoryExtra = MemoryExtra;
+ fn load_mir(
+ ecx: &InterpCx<'mir, 'tcx, Self>,
+ instance: ty::InstanceDef<'tcx>,
+ ) -> InterpResult<'tcx, &'tcx mir::Body<'tcx>> {
+ match instance {
+ ty::InstanceDef::Item(def) => {
+ if ecx.tcx.is_ctfe_mir_available(def.did) {
+ Ok(ecx.tcx.mir_for_ctfe_opt_const_arg(def))
+ } else {
+ throw_unsup!(NoMirFor(def.did))
+ }
+ }
+ _ => Ok(ecx.tcx.instance_mir(instance)),
+ }
+ }
+
fn find_mir_or_eval_fn(
ecx: &mut InterpCx<'mir, 'tcx, Self>,
instance: ty::Instance<'tcx>,
+ _abi: Abi,
args: &[OpTy<'tcx>],
_ret: Option<(PlaceTy<'tcx>, mir::BasicBlock)>,
_unwind: Option<mir::BasicBlock>, // unwinding is not supported in consts
diff --git a/compiler/rustc_mir/src/dataflow/move_paths/builder.rs b/compiler/rustc_mir/src/dataflow/move_paths/builder.rs
index ab7fada..ee78ff0 100644
--- a/compiler/rustc_mir/src/dataflow/move_paths/builder.rs
+++ b/compiler/rustc_mir/src/dataflow/move_paths/builder.rs
@@ -518,14 +518,10 @@
// Check if we are assigning into a field of a union, if so, lookup the place
// of the union so it is marked as initialized again.
- if let [proj_base @ .., ProjectionElem::Field(_, _)] = place.projection {
- if let ty::Adt(def, _) =
- Place::ty_from(place.local, proj_base, self.builder.body, self.builder.tcx)
- .ty
- .kind()
- {
+ if let Some((place_base, ProjectionElem::Field(_, _))) = place.last_projection() {
+ if let ty::Adt(def, _) = place_base.ty(self.builder.body, self.builder.tcx).ty.kind() {
if def.is_union() {
- place = PlaceRef { local: place.local, projection: proj_base }
+ place = place_base;
}
}
}
diff --git a/compiler/rustc_mir/src/interpret/cast.rs b/compiler/rustc_mir/src/interpret/cast.rs
index 6d224bc..128d8cf 100644
--- a/compiler/rustc_mir/src/interpret/cast.rs
+++ b/compiler/rustc_mir/src/interpret/cast.rs
@@ -2,13 +2,11 @@
use rustc_apfloat::ieee::{Double, Single};
use rustc_apfloat::{Float, FloatConvert};
-use rustc_ast::FloatTy;
-use rustc_attr as attr;
use rustc_middle::mir::interpret::{InterpResult, PointerArithmetic, Scalar};
use rustc_middle::mir::CastKind;
use rustc_middle::ty::adjustment::PointerCast;
use rustc_middle::ty::layout::{IntegerExt, TyAndLayout};
-use rustc_middle::ty::{self, Ty, TypeAndMut};
+use rustc_middle::ty::{self, FloatTy, Ty, TypeAndMut};
use rustc_span::symbol::sym;
use rustc_target::abi::{Integer, LayoutOf, Variants};
@@ -203,8 +201,8 @@
match *cast_ty.kind() {
Int(_) | Uint(_) | RawPtr(_) => {
let size = match *cast_ty.kind() {
- Int(t) => Integer::from_attr(self, attr::IntType::SignedInt(t)).size(),
- Uint(t) => Integer::from_attr(self, attr::IntType::UnsignedInt(t)).size(),
+ Int(t) => Integer::from_int_ty(self, t).size(),
+ Uint(t) => Integer::from_uint_ty(self, t).size(),
RawPtr(_) => self.pointer_size(),
_ => bug!(),
};
@@ -235,7 +233,7 @@
match *dest_ty.kind() {
// float -> uint
Uint(t) => {
- let size = Integer::from_attr(self, attr::IntType::UnsignedInt(t)).size();
+ let size = Integer::from_uint_ty(self, t).size();
// `to_u128` is a saturating cast, which is what we need
// (https://doc.rust-lang.org/nightly/nightly-rustc/rustc_apfloat/trait.Float.html#method.to_i128_r).
let v = f.to_u128(size.bits_usize()).value;
@@ -244,7 +242,7 @@
}
// float -> int
Int(t) => {
- let size = Integer::from_attr(self, attr::IntType::SignedInt(t)).size();
+ let size = Integer::from_int_ty(self, t).size();
// `to_i128` is a saturating cast, which is what we need
// (https://doc.rust-lang.org/nightly/nightly-rustc/rustc_apfloat/trait.Float.html#method.to_i128_r).
let v = f.to_i128(size.bits_usize()).value;
diff --git a/compiler/rustc_mir/src/interpret/eval_context.rs b/compiler/rustc_mir/src/interpret/eval_context.rs
index 3d95557..7e9594d 100644
--- a/compiler/rustc_mir/src/interpret/eval_context.rs
+++ b/compiler/rustc_mir/src/interpret/eval_context.rs
@@ -370,7 +370,7 @@
#[inline(always)]
pub fn cur_span(&self) -> Span {
- self.stack().last().map(|f| f.current_span()).unwrap_or(self.tcx.span)
+ self.stack().last().map_or(self.tcx.span, |f| f.current_span())
}
#[inline(always)]
@@ -477,16 +477,7 @@
if let Some(promoted) = promoted {
return Ok(&self.tcx.promoted_mir_opt_const_arg(def)[promoted]);
}
- match instance {
- ty::InstanceDef::Item(def) => {
- if self.tcx.is_mir_available(def.did) {
- Ok(self.tcx.optimized_mir_opt_const_arg(def))
- } else {
- throw_unsup!(NoMirFor(def.did))
- }
- }
- _ => Ok(self.tcx.instance_mir(instance)),
- }
+ M::load_mir(self, instance)
}
/// Call this on things you got out of the MIR (so it is as generic as the current
diff --git a/compiler/rustc_mir/src/interpret/intrinsics.rs b/compiler/rustc_mir/src/interpret/intrinsics.rs
index 474e1f8..f4309c9 100644
--- a/compiler/rustc_mir/src/interpret/intrinsics.rs
+++ b/compiler/rustc_mir/src/interpret/intrinsics.rs
@@ -7,7 +7,7 @@
use rustc_hir::def_id::DefId;
use rustc_middle::mir::{
self,
- interpret::{uabs, ConstValue, GlobalId, InterpResult, Scalar},
+ interpret::{ConstValue, GlobalId, InterpResult, Scalar},
BinOp,
};
use rustc_middle::ty;
@@ -141,9 +141,11 @@
}
sym::min_align_of_val | sym::size_of_val => {
- let place = self.deref_operand(args[0])?;
+ // Avoid `deref_operand` -- this is not a deref, the ptr does not have to be
+ // dereferencable!
+ let place = self.ref_to_mplace(self.read_immediate(args[0])?)?;
let (size, align) = self
- .size_and_align_of(place.meta, place.layout)?
+ .size_and_align_of_mplace(place)?
.ok_or_else(|| err_unsup_format!("`extern type` does not have known layout"))?;
let result = match intrinsic_name {
@@ -322,6 +324,29 @@
let result = Scalar::from_uint(truncated_bits, layout.size);
self.write_scalar(result, dest)?;
}
+ sym::copy | sym::copy_nonoverlapping => {
+ let elem_ty = instance.substs.type_at(0);
+ let elem_layout = self.layout_of(elem_ty)?;
+ let count = self.read_scalar(args[2])?.to_machine_usize(self)?;
+ let elem_align = elem_layout.align.abi;
+
+ let size = elem_layout.size.checked_mul(count, self).ok_or_else(|| {
+ err_ub_format!("overflow computing total size of `{}`", intrinsic_name)
+ })?;
+ let src = self.read_scalar(args[0])?.check_init()?;
+ let src = self.memory.check_ptr_access(src, size, elem_align)?;
+ let dest = self.read_scalar(args[1])?.check_init()?;
+ let dest = self.memory.check_ptr_access(dest, size, elem_align)?;
+
+ if let (Some(src), Some(dest)) = (src, dest) {
+ self.memory.copy(
+ src,
+ dest,
+ size,
+ intrinsic_name == sym::copy_nonoverlapping,
+ )?;
+ }
+ }
sym::offset => {
let ptr = self.read_scalar(args[0])?.check_init()?;
let offset_count = self.read_scalar(args[1])?.to_machine_isize(self)?;
@@ -517,7 +542,7 @@
// memory between these pointers must be accessible. Note that we do not require the
// pointers to be properly aligned (unlike a read/write operation).
let min_ptr = if offset_bytes >= 0 { ptr } else { offset_ptr };
- let size: u64 = uabs(offset_bytes);
+ let size = offset_bytes.unsigned_abs();
// This call handles checking for integer/NULL pointers.
self.memory.check_ptr_access_align(
min_ptr,
diff --git a/compiler/rustc_mir/src/interpret/machine.rs b/compiler/rustc_mir/src/interpret/machine.rs
index f50cc6c1..53ac62d 100644
--- a/compiler/rustc_mir/src/interpret/machine.rs
+++ b/compiler/rustc_mir/src/interpret/machine.rs
@@ -10,6 +10,7 @@
use rustc_middle::ty::{self, Ty};
use rustc_span::def_id::DefId;
use rustc_target::abi::Size;
+use rustc_target::spec::abi::Abi;
use super::{
AllocId, Allocation, AllocationExtra, CheckInAllocMsg, Frame, ImmTy, InterpCx, InterpResult,
@@ -131,6 +132,16 @@
/// Whether to enforce the validity invariant
fn enforce_validity(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool;
+ /// Entry point for obtaining the MIR of anything that should get evaluated.
+ /// So not just functions and shims, but also const/static initializers, anonymous
+ /// constants, ...
+ fn load_mir(
+ ecx: &InterpCx<'mir, 'tcx, Self>,
+ instance: ty::InstanceDef<'tcx>,
+ ) -> InterpResult<'tcx, &'tcx mir::Body<'tcx>> {
+ Ok(ecx.tcx.instance_mir(instance))
+ }
+
/// Entry point to all function calls.
///
/// Returns either the mir to use for the call, or `None` if execution should
@@ -144,6 +155,7 @@
fn find_mir_or_eval_fn(
ecx: &mut InterpCx<'mir, 'tcx, Self>,
instance: ty::Instance<'tcx>,
+ abi: Abi,
args: &[OpTy<'tcx, Self::PointerTag>],
ret: Option<(PlaceTy<'tcx, Self::PointerTag>, mir::BasicBlock)>,
unwind: Option<mir::BasicBlock>,
@@ -154,6 +166,7 @@
fn call_extra_fn(
ecx: &mut InterpCx<'mir, 'tcx, Self>,
fn_val: Self::ExtraFnVal,
+ abi: Abi,
args: &[OpTy<'tcx, Self::PointerTag>],
ret: Option<(PlaceTy<'tcx, Self::PointerTag>, mir::BasicBlock)>,
unwind: Option<mir::BasicBlock>,
@@ -405,6 +418,7 @@
fn call_extra_fn(
_ecx: &mut InterpCx<$mir, $tcx, Self>,
fn_val: !,
+ _abi: Abi,
_args: &[OpTy<$tcx>],
_ret: Option<(PlaceTy<$tcx>, mir::BasicBlock)>,
_unwind: Option<mir::BasicBlock>,
diff --git a/compiler/rustc_mir/src/interpret/operand.rs b/compiler/rustc_mir/src/interpret/operand.rs
index d9437a3..8823645 100644
--- a/compiler/rustc_mir/src/interpret/operand.rs
+++ b/compiler/rustc_mir/src/interpret/operand.rs
@@ -511,6 +511,10 @@
Constant(ref constant) => {
let val =
self.subst_from_current_frame_and_normalize_erasing_regions(constant.literal);
+ // This can still fail:
+ // * During ConstProp, with `TooGeneric` or since the `requried_consts` were not all
+ // checked yet.
+ // * During CTFE, since promoteds in `const`/`static` initializer bodies can fail.
self.const_to_op(val, layout)?
}
};
diff --git a/compiler/rustc_mir/src/interpret/operator.rs b/compiler/rustc_mir/src/interpret/operator.rs
index fc266fa..f508165 100644
--- a/compiler/rustc_mir/src/interpret/operator.rs
+++ b/compiler/rustc_mir/src/interpret/operator.rs
@@ -1,10 +1,9 @@
use std::convert::TryFrom;
use rustc_apfloat::Float;
-use rustc_ast::FloatTy;
use rustc_middle::mir;
use rustc_middle::mir::interpret::{InterpResult, Scalar};
-use rustc_middle::ty::{self, layout::TyAndLayout, Ty};
+use rustc_middle::ty::{self, layout::TyAndLayout, FloatTy, Ty};
use rustc_target::abi::LayoutOf;
use super::{ImmTy, Immediate, InterpCx, Machine, PlaceTy};
diff --git a/compiler/rustc_mir/src/interpret/place.rs b/compiler/rustc_mir/src/interpret/place.rs
index a003380..efde7fe 100644
--- a/compiler/rustc_mir/src/interpret/place.rs
+++ b/compiler/rustc_mir/src/interpret/place.rs
@@ -153,6 +153,7 @@
}
}
+ #[inline]
pub fn offset(
self,
offset: Size,
diff --git a/compiler/rustc_mir/src/interpret/step.rs b/compiler/rustc_mir/src/interpret/step.rs
index 95738db..fbc72ad 100644
--- a/compiler/rustc_mir/src/interpret/step.rs
+++ b/compiler/rustc_mir/src/interpret/step.rs
@@ -264,10 +264,14 @@
NullaryOp(mir::NullOp::SizeOf, ty) => {
let ty = self.subst_from_current_frame_and_normalize_erasing_regions(ty);
let layout = self.layout_of(ty)?;
- assert!(
- !layout.is_unsized(),
- "SizeOf nullary MIR operator called for unsized type"
- );
+ if layout.is_unsized() {
+ // FIXME: This should be a span_bug (#80742)
+ self.tcx.sess.delay_span_bug(
+ self.frame().current_span(),
+ &format!("SizeOf nullary MIR operator called for unsized type {}", ty),
+ );
+ throw_inval!(SizeOfUnsizedType(ty));
+ }
self.write_scalar(Scalar::from_machine_usize(layout.size.bytes(), self), dest)?;
}
diff --git a/compiler/rustc_mir/src/interpret/terminator.rs b/compiler/rustc_mir/src/interpret/terminator.rs
index a293132..575667f 100644
--- a/compiler/rustc_mir/src/interpret/terminator.rs
+++ b/compiler/rustc_mir/src/interpret/terminator.rs
@@ -219,7 +219,7 @@
let instance = match fn_val {
FnVal::Instance(instance) => instance,
FnVal::Other(extra) => {
- return M::call_extra_fn(self, extra, args, ret, unwind);
+ return M::call_extra_fn(self, extra, caller_abi, args, ret, unwind);
}
};
@@ -264,10 +264,11 @@
| ty::InstanceDef::CloneShim(..)
| ty::InstanceDef::Item(_) => {
// We need MIR for this fn
- let body = match M::find_mir_or_eval_fn(self, instance, args, ret, unwind)? {
- Some(body) => body,
- None => return Ok(()),
- };
+ let body =
+ match M::find_mir_or_eval_fn(self, instance, caller_abi, args, ret, unwind)? {
+ Some(body) => body,
+ None => return Ok(()),
+ };
self.push_stack_frame(
instance,
diff --git a/compiler/rustc_mir/src/interpret/util.rs b/compiler/rustc_mir/src/interpret/util.rs
index c2165db..89f34cd 100644
--- a/compiler/rustc_mir/src/interpret/util.rs
+++ b/compiler/rustc_mir/src/interpret/util.rs
@@ -47,8 +47,7 @@
let index = index
.try_into()
.expect("more generic parameters than can fit into a `u32`");
- let is_used =
- unused_params.contains(index).map(|unused| !unused).unwrap_or(true);
+ let is_used = unused_params.contains(index).map_or(true, |unused| !unused);
// Only recurse when generic parameters in fns, closures and generators
// are used and require substitution.
match (is_used, subst.needs_subst()) {
diff --git a/compiler/rustc_mir/src/interpret/validity.rs b/compiler/rustc_mir/src/interpret/validity.rs
index 57aec09..0b74926 100644
--- a/compiler/rustc_mir/src/interpret/validity.rs
+++ b/compiler/rustc_mir/src/interpret/validity.rs
@@ -153,7 +153,7 @@
}
/// Format a path
-fn write_path(out: &mut String, path: &Vec<PathElem>) {
+fn write_path(out: &mut String, path: &[PathElem]) {
use self::PathElem::*;
for elem in path.iter() {
@@ -391,7 +391,7 @@
}
// Make sure this is dereferenceable and all.
let size_and_align = try_validation!(
- self.ecx.size_and_align_of(place.meta, place.layout),
+ self.ecx.size_and_align_of_mplace(place),
self.path,
err_ub!(InvalidMeta(msg)) => { "invalid {} metadata: {}", kind, msg },
);
@@ -515,7 +515,11 @@
Ok(true)
}
ty::Float(_) | ty::Int(_) | ty::Uint(_) => {
- let value = self.ecx.read_scalar(value)?;
+ let value = try_validation!(
+ self.ecx.read_scalar(value),
+ self.path,
+ err_unsup!(ReadPointerAsBytes) => { "read of part of a pointer" },
+ );
// NOTE: Keep this in sync with the array optimization for int/float
// types below!
if self.ctfe_mode.is_some() {
diff --git a/compiler/rustc_mir/src/lib.rs b/compiler/rustc_mir/src/lib.rs
index e6d8220..8b3881e 100644
--- a/compiler/rustc_mir/src/lib.rs
+++ b/compiler/rustc_mir/src/lib.rs
@@ -57,6 +57,8 @@
providers.eval_to_const_value_raw = const_eval::eval_to_const_value_raw_provider;
providers.eval_to_allocation_raw = const_eval::eval_to_allocation_raw_provider;
providers.const_caller_location = const_eval::const_caller_location;
+ providers.mir_callgraph_reachable = transform::inline::cycle::mir_callgraph_reachable;
+ providers.mir_inliner_callees = transform::inline::cycle::mir_inliner_callees;
providers.destructure_const = |tcx, param_env_and_value| {
let (param_env, value) = param_env_and_value.into_parts();
const_eval::destructure_const(tcx, param_env, value)
diff --git a/compiler/rustc_mir/src/monomorphize/collector.rs b/compiler/rustc_mir/src/monomorphize/collector.rs
index 6370ead..75f80f6 100644
--- a/compiler/rustc_mir/src/monomorphize/collector.rs
+++ b/compiler/rustc_mir/src/monomorphize/collector.rs
@@ -823,7 +823,7 @@
}
if !tcx.is_mir_available(def_id) {
- bug!("cannot create local mono-item for {:?}", def_id)
+ bug!("no MIR available for {:?}", def_id);
}
true
@@ -1146,8 +1146,8 @@
output: &mut Vec<Spanned<MonoItem<'tcx>>>,
) {
match item.kind {
- hir::ItemKind::Impl { ref generics, ref items, .. } => {
- for param in generics.params {
+ hir::ItemKind::Impl(ref impl_) => {
+ for param in impl_.generics.params {
match param.kind {
hir::GenericParamKind::Lifetime { .. } => {}
hir::GenericParamKind::Type { .. } | hir::GenericParamKind::Const { .. } => {
@@ -1167,7 +1167,7 @@
let param_env = ty::ParamEnv::reveal_all();
let trait_ref = tcx.normalize_erasing_regions(param_env, trait_ref);
let overridden_methods: FxHashSet<_> =
- items.iter().map(|iiref| iiref.ident.normalize_to_macros_2_0()).collect();
+ impl_.items.iter().map(|iiref| iiref.ident.normalize_to_macros_2_0()).collect();
for method in tcx.provided_trait_methods(trait_ref.def_id) {
if overridden_methods.contains(&method.ident.normalize_to_macros_2_0()) {
continue;
diff --git a/compiler/rustc_mir/src/monomorphize/partitioning/mod.rs b/compiler/rustc_mir/src/monomorphize/partitioning/mod.rs
index db6d3b2..b9fcd32 100644
--- a/compiler/rustc_mir/src/monomorphize/partitioning/mod.rs
+++ b/compiler/rustc_mir/src/monomorphize/partitioning/mod.rs
@@ -247,8 +247,7 @@
for (mono_item, linkage) in cgu.items() {
let symbol_name = mono_item.symbol_name(tcx).name;
let symbol_hash_start = symbol_name.rfind('h');
- let symbol_hash =
- symbol_hash_start.map(|i| &symbol_name[i..]).unwrap_or("<no hash>");
+ let symbol_hash = symbol_hash_start.map_or("<no hash>", |i| &symbol_name[i..]);
debug!(
" - {} [{:?}] [{}] estimated size {}",
diff --git a/compiler/rustc_mir/src/monomorphize/polymorphize.rs b/compiler/rustc_mir/src/monomorphize/polymorphize.rs
index 0ce1c5a..4ad71ab 100644
--- a/compiler/rustc_mir/src/monomorphize/polymorphize.rs
+++ b/compiler/rustc_mir/src/monomorphize/polymorphize.rs
@@ -5,7 +5,7 @@
//! generic parameters are unused (and eventually, in what ways generic parameters are used - only
//! for their size, offset of a field, etc.).
-use rustc_hir::{def::DefKind, def_id::DefId};
+use rustc_hir::{def::DefKind, def_id::DefId, ConstContext};
use rustc_index::bit_set::FiniteBitSet;
use rustc_middle::mir::{
visit::{TyContext, Visitor},
@@ -54,9 +54,17 @@
}
// Exit early when there is no MIR available.
- if !tcx.is_mir_available(def_id) {
- debug!("unused_generic_params: (no mir available) def_id={:?}", def_id);
- return FiniteBitSet::new_empty();
+ let context = tcx.hir().body_const_context(def_id.expect_local());
+ match context {
+ Some(ConstContext::ConstFn) | None if !tcx.is_mir_available(def_id) => {
+ debug!("unused_generic_params: (no mir available) def_id={:?}", def_id);
+ return FiniteBitSet::new_empty();
+ }
+ Some(_) if !tcx.is_ctfe_mir_available(def_id) => {
+ debug!("unused_generic_params: (no ctfe mir available) def_id={:?}", def_id);
+ return FiniteBitSet::new_empty();
+ }
+ _ => {}
}
// Create a bitset with N rightmost ones for each parameter.
@@ -69,7 +77,12 @@
debug!("unused_generic_params: (after default) unused_parameters={:?}", unused_parameters);
// Visit MIR and accumululate used generic parameters.
- let body = tcx.optimized_mir(def_id);
+ let body = match context {
+ // Const functions are actually called and should thus be considered for polymorphization
+ // via their runtime MIR
+ Some(ConstContext::ConstFn) | None => tcx.optimized_mir(def_id),
+ Some(_) => tcx.mir_for_ctfe(def_id),
+ };
let mut vis = MarkUsedGenericParams { tcx, def_id, unused_parameters: &mut unused_parameters };
vis.visit_body(body);
debug!("unused_generic_params: (after visitor) unused_parameters={:?}", unused_parameters);
diff --git a/compiler/rustc_mir/src/shim.rs b/compiler/rustc_mir/src/shim.rs
index aa58356..6aaf27b 100644
--- a/compiler/rustc_mir/src/shim.rs
+++ b/compiler/rustc_mir/src/shim.rs
@@ -81,7 +81,7 @@
MirPhase::Const,
&[&[
&add_moves_for_packed_drops::AddMovesForPackedDrops,
- &no_landing_pads::NoLandingPads::new(tcx),
+ &no_landing_pads::NoLandingPads,
&remove_noop_landing_pads::RemoveNoopLandingPads,
&simplify::SimplifyCfg::new("make_shim"),
&add_call_guards::CriticalCallEdges,
@@ -165,7 +165,7 @@
let mut body =
new_body(source, blocks, local_decls_for_sig(&sig, span), sig.inputs().len(), span);
- if let Some(..) = ty {
+ if ty.is_some() {
// The first argument (index 0), but add 1 for the return value.
let dropee_ptr = Place::from(Local::new(1 + 0));
if tcx.sess.opts.debugging_opts.mir_emit_retag {
diff --git a/compiler/rustc_mir/src/transform/check_consts/ops.rs b/compiler/rustc_mir/src/transform/check_consts/ops.rs
index d2e65ab..6f98760 100644
--- a/compiler/rustc_mir/src/transform/check_consts/ops.rs
+++ b/compiler/rustc_mir/src/transform/check_consts/ops.rs
@@ -72,7 +72,7 @@
/// A function call where the callee is not marked as `const`.
#[derive(Debug)]
-pub struct FnCallNonConst(pub DefId);
+pub struct FnCallNonConst;
impl NonConstOp for FnCallNonConst {
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
struct_span_err!(
@@ -209,30 +209,79 @@
}
#[derive(Debug)]
-pub struct CellBorrow;
-impl NonConstOp for CellBorrow {
+/// A borrow of a type that contains an `UnsafeCell` somewhere. The borrow never escapes to
+/// the final value of the constant.
+pub struct TransientCellBorrow;
+impl NonConstOp for TransientCellBorrow {
+ fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status {
+ Status::Unstable(sym::const_refs_to_cell)
+ }
+ fn importance(&self) -> DiagnosticImportance {
+ // The cases that cannot possibly work will already emit a `CellBorrow`, so we should
+ // not additionally emit a feature gate error if activating the feature gate won't work.
+ DiagnosticImportance::Secondary
+ }
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
- struct_span_err!(
- ccx.tcx.sess,
+ feature_err(
+ &ccx.tcx.sess.parse_sess,
+ sym::const_refs_to_cell,
span,
- E0492,
- "cannot borrow a constant which may contain \
- interior mutability, create a static instead"
+ "cannot borrow here, since the borrowed element may contain interior mutability",
)
}
}
#[derive(Debug)]
+/// A borrow of a type that contains an `UnsafeCell` somewhere. The borrow might escape to
+/// the final value of the constant, and thus we cannot allow this (for now). We may allow
+/// it in the future for static items.
+pub struct CellBorrow;
+impl NonConstOp for CellBorrow {
+ fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
+ let mut err = struct_span_err!(
+ ccx.tcx.sess,
+ span,
+ E0492,
+ "{}s cannot refer to interior mutable data",
+ ccx.const_kind(),
+ );
+ err.span_label(
+ span,
+ format!("this borrow of an interior mutable value may end up in the final value"),
+ );
+ if let hir::ConstContext::Static(_) = ccx.const_kind() {
+ err.help(
+ "to fix this, the value can be extracted to a separate \
+ `static` item and then referenced",
+ );
+ }
+ if ccx.tcx.sess.teach(&err.get_code().unwrap()) {
+ err.note(
+ "A constant containing interior mutable data behind a reference can allow you
+ to modify that data. This would make multiple uses of a constant to be able to
+ see different values and allow circumventing the `Send` and `Sync` requirements
+ for shared mutable data, which is unsound.",
+ );
+ }
+ err
+ }
+}
+
+#[derive(Debug)]
+/// This op is for `&mut` borrows in the trailing expression of a constant
+/// which uses the "enclosing scopes rule" to leak its locals into anonymous
+/// static or const items.
pub struct MutBorrow(pub hir::BorrowKind);
impl NonConstOp for MutBorrow {
- fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status {
- // Forbid everywhere except in const fn with a feature gate
- if ccx.const_kind() == hir::ConstContext::ConstFn {
- Status::Unstable(sym::const_mut_refs)
- } else {
- Status::Forbidden
- }
+ fn status_in_item(&self, _ccx: &ConstCx<'_, '_>) -> Status {
+ Status::Forbidden
+ }
+
+ fn importance(&self) -> DiagnosticImportance {
+ // If there were primary errors (like non-const function calls), do not emit further
+ // errors about mutable references.
+ DiagnosticImportance::Secondary
}
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
@@ -241,25 +290,15 @@
hir::BorrowKind::Ref => "",
};
- let mut err = if ccx.const_kind() == hir::ConstContext::ConstFn {
- feature_err(
- &ccx.tcx.sess.parse_sess,
- sym::const_mut_refs,
- span,
- &format!("{}mutable references are not allowed in {}s", raw, ccx.const_kind()),
- )
- } else {
- let mut err = struct_span_err!(
- ccx.tcx.sess,
- span,
- E0764,
- "{}mutable references are not allowed in {}s",
- raw,
- ccx.const_kind(),
- );
- err.span_label(span, format!("`&{}mut` is only allowed in `const fn`", raw));
- err
- };
+ let mut err = struct_span_err!(
+ ccx.tcx.sess,
+ span,
+ E0764,
+ "{}mutable references are not allowed in the final value of {}s",
+ raw,
+ ccx.const_kind(),
+ );
+
if ccx.tcx.sess.teach(&err.get_code().unwrap()) {
err.note(
"References in statics and constants may only refer \
@@ -277,6 +316,29 @@
}
#[derive(Debug)]
+pub struct TransientMutBorrow(pub hir::BorrowKind);
+
+impl NonConstOp for TransientMutBorrow {
+ fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status {
+ Status::Unstable(sym::const_mut_refs)
+ }
+
+ fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
+ let raw = match self.0 {
+ hir::BorrowKind::Raw => "raw ",
+ hir::BorrowKind::Ref => "",
+ };
+
+ feature_err(
+ &ccx.tcx.sess.parse_sess,
+ sym::const_mut_refs,
+ span,
+ &format!("{}mutable references are not allowed in {}s", raw, ccx.const_kind()),
+ )
+ }
+}
+
+#[derive(Debug)]
pub struct MutDeref;
impl NonConstOp for MutDeref {
fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status {
@@ -284,7 +346,7 @@
}
fn importance(&self) -> DiagnosticImportance {
- // Usually a side-effect of a `MutBorrow` somewhere.
+ // Usually a side-effect of a `TransientMutBorrow` somewhere.
DiagnosticImportance::Secondary
}
diff --git a/compiler/rustc_mir/src/transform/check_consts/qualifs.rs b/compiler/rustc_mir/src/transform/check_consts/qualifs.rs
index c66d3ed..0ce1980 100644
--- a/compiler/rustc_mir/src/transform/check_consts/qualifs.rs
+++ b/compiler/rustc_mir/src/transform/check_consts/qualifs.rs
@@ -174,14 +174,10 @@
Rvalue::Ref(_, _, place) | Rvalue::AddressOf(_, place) => {
// Special-case reborrows to be more like a copy of the reference.
- if let &[ref proj_base @ .., ProjectionElem::Deref] = place.projection.as_ref() {
- let base_ty = Place::ty_from(place.local, proj_base, cx.body, cx.tcx).ty;
+ if let Some((place_base, ProjectionElem::Deref)) = place.as_ref().last_projection() {
+ let base_ty = place_base.ty(cx.body, cx.tcx).ty;
if let ty::Ref(..) = base_ty.kind() {
- return in_place::<Q, _>(
- cx,
- in_local,
- PlaceRef { local: place.local, projection: proj_base },
- );
+ return in_place::<Q, _>(cx, in_local, place_base);
}
}
@@ -209,9 +205,9 @@
Q: Qualif,
F: FnMut(Local) -> bool,
{
- let mut projection = place.projection;
- while let &[ref proj_base @ .., proj_elem] = projection {
- match proj_elem {
+ let mut place = place;
+ while let Some((place_base, elem)) = place.last_projection() {
+ match elem {
ProjectionElem::Index(index) if in_local(index) => return true,
ProjectionElem::Deref
@@ -222,16 +218,16 @@
| ProjectionElem::Index(_) => {}
}
- let base_ty = Place::ty_from(place.local, proj_base, cx.body, cx.tcx);
- let proj_ty = base_ty.projection_ty(cx.tcx, proj_elem).ty;
+ let base_ty = place_base.ty(cx.body, cx.tcx);
+ let proj_ty = base_ty.projection_ty(cx.tcx, elem).ty;
if !Q::in_any_value_of_ty(cx, proj_ty) {
return false;
}
- projection = proj_base;
+ place = place_base;
}
- assert!(projection.is_empty());
+ assert!(place.projection.is_empty());
in_local(place.local)
}
diff --git a/compiler/rustc_mir/src/transform/check_consts/validation.rs b/compiler/rustc_mir/src/transform/check_consts/validation.rs
index 90688eb..a92997d 100644
--- a/compiler/rustc_mir/src/transform/check_consts/validation.rs
+++ b/compiler/rustc_mir/src/transform/check_consts/validation.rs
@@ -3,6 +3,7 @@
use rustc_errors::{struct_span_err, Applicability, Diagnostic, ErrorReported};
use rustc_hir::def_id::DefId;
use rustc_hir::{self as hir, HirId, LangItem};
+use rustc_index::bit_set::BitSet;
use rustc_infer::infer::TyCtxtInferExt;
use rustc_infer::traits::{ImplSource, Obligation, ObligationCause};
use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor};
@@ -188,6 +189,9 @@
/// The span of the current statement.
span: Span,
+ /// A set that stores for each local whether it has a `StorageDead` for it somewhere.
+ local_has_storage_dead: Option<BitSet<Local>>,
+
error_emitted: Option<ErrorReported>,
secondary_errors: Vec<Diagnostic>,
}
@@ -206,6 +210,7 @@
span: ccx.body.span,
ccx,
qualifs: Default::default(),
+ local_has_storage_dead: None,
error_emitted: None,
secondary_errors: Vec::new(),
}
@@ -282,6 +287,27 @@
}
}
+ fn local_has_storage_dead(&mut self, local: Local) -> bool {
+ let ccx = self.ccx;
+ self.local_has_storage_dead
+ .get_or_insert_with(|| {
+ struct StorageDeads {
+ locals: BitSet<Local>,
+ }
+ impl Visitor<'tcx> for StorageDeads {
+ fn visit_statement(&mut self, stmt: &Statement<'tcx>, _: Location) {
+ if let StatementKind::StorageDead(l) = stmt.kind {
+ self.locals.insert(l);
+ }
+ }
+ }
+ let mut v = StorageDeads { locals: BitSet::new_empty(ccx.body.local_decls.len()) };
+ v.visit_body(ccx.body);
+ v.locals
+ })
+ .contains(local)
+ }
+
pub fn qualifs_in_return_place(&mut self) -> ConstQualifs {
self.qualifs.in_return_place(self.ccx, self.error_emitted)
}
@@ -385,24 +411,24 @@
loop {
let predicates = tcx.predicates_of(current);
for (predicate, _) in predicates.predicates {
- match predicate.skip_binders() {
- ty::PredicateAtom::RegionOutlives(_)
- | ty::PredicateAtom::TypeOutlives(_)
- | ty::PredicateAtom::WellFormed(_)
- | ty::PredicateAtom::Projection(_)
- | ty::PredicateAtom::ConstEvaluatable(..)
- | ty::PredicateAtom::ConstEquate(..)
- | ty::PredicateAtom::TypeWellFormedFromEnv(..) => continue,
- ty::PredicateAtom::ObjectSafe(_) => {
+ match predicate.kind().skip_binder() {
+ ty::PredicateKind::RegionOutlives(_)
+ | ty::PredicateKind::TypeOutlives(_)
+ | ty::PredicateKind::WellFormed(_)
+ | ty::PredicateKind::Projection(_)
+ | ty::PredicateKind::ConstEvaluatable(..)
+ | ty::PredicateKind::ConstEquate(..)
+ | ty::PredicateKind::TypeWellFormedFromEnv(..) => continue,
+ ty::PredicateKind::ObjectSafe(_) => {
bug!("object safe predicate on function: {:#?}", predicate)
}
- ty::PredicateAtom::ClosureKind(..) => {
+ ty::PredicateKind::ClosureKind(..) => {
bug!("closure kind predicate on function: {:#?}", predicate)
}
- ty::PredicateAtom::Subtype(_) => {
+ ty::PredicateKind::Subtype(_) => {
bug!("subtype predicate on function: {:#?}", predicate)
}
- ty::PredicateAtom::Trait(pred, constness) => {
+ ty::PredicateKind::Trait(pred, constness) => {
if Some(pred.def_id()) == tcx.lang_items().sized_trait() {
continue;
}
@@ -440,6 +466,29 @@
}
}
}
+
+ fn check_mut_borrow(&mut self, local: Local, kind: hir::BorrowKind) {
+ match self.const_kind() {
+ // In a const fn all borrows are transient or point to the places given via
+ // references in the arguments (so we already checked them with
+ // TransientMutBorrow/MutBorrow as appropriate).
+ // The borrow checker guarantees that no new non-transient borrows are created.
+ // NOTE: Once we have heap allocations during CTFE we need to figure out
+ // how to prevent `const fn` to create long-lived allocations that point
+ // to mutable memory.
+ hir::ConstContext::ConstFn => self.check_op(ops::TransientMutBorrow(kind)),
+ _ => {
+ // Locals with StorageDead do not live beyond the evaluation and can
+ // thus safely be borrowed without being able to be leaked to the final
+ // value of the constant.
+ if self.local_has_storage_dead(local) {
+ self.check_op(ops::TransientMutBorrow(kind));
+ } else {
+ self.check_op(ops::MutBorrow(kind));
+ }
+ }
+ }
+ }
}
impl Visitor<'tcx> for Validator<'mir, 'tcx> {
@@ -536,15 +585,15 @@
if !is_allowed {
if let BorrowKind::Mut { .. } = kind {
- self.check_op(ops::MutBorrow(hir::BorrowKind::Ref));
+ self.check_mut_borrow(place.local, hir::BorrowKind::Ref)
} else {
self.check_op(ops::CellBorrow);
}
}
}
- Rvalue::AddressOf(Mutability::Mut, _) => {
- self.check_op(ops::MutBorrow(hir::BorrowKind::Raw))
+ Rvalue::AddressOf(Mutability::Mut, ref place) => {
+ self.check_mut_borrow(place.local, hir::BorrowKind::Raw)
}
Rvalue::Ref(_, BorrowKind::Shared | BorrowKind::Shallow, ref place)
@@ -556,7 +605,29 @@
);
if borrowed_place_has_mut_interior {
- self.check_op(ops::CellBorrow);
+ match self.const_kind() {
+ // In a const fn all borrows are transient or point to the places given via
+ // references in the arguments (so we already checked them with
+ // TransientCellBorrow/CellBorrow as appropriate).
+ // The borrow checker guarantees that no new non-transient borrows are created.
+ // NOTE: Once we have heap allocations during CTFE we need to figure out
+ // how to prevent `const fn` to create long-lived allocations that point
+ // to (interior) mutable memory.
+ hir::ConstContext::ConstFn => self.check_op(ops::TransientCellBorrow),
+ _ => {
+ // Locals with StorageDead are definitely not part of the final constant value, and
+ // it is thus inherently safe to permit such locals to have their
+ // address taken as we can't end up with a reference to them in the
+ // final value.
+ // Note: This is only sound if every local that has a `StorageDead` has a
+ // `StorageDead` in every control flow path leading to a `return` terminator.
+ if self.local_has_storage_dead(place.local) {
+ self.check_op(ops::TransientCellBorrow);
+ } else {
+ self.check_op(ops::CellBorrow);
+ }
+ }
+ }
}
}
@@ -741,10 +812,10 @@
}
}
+ #[instrument(skip(self))]
fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) {
use rustc_target::spec::abi::Abi::RustIntrinsic;
- trace!("visit_terminator: terminator={:?} location={:?}", terminator, location);
self.super_terminator(terminator, location);
match &terminator.kind {
@@ -768,8 +839,9 @@
// Attempting to call a trait method?
if let Some(trait_id) = tcx.trait_of_item(callee) {
+ trace!("attempting to call a trait method");
if !self.tcx.features().const_trait_impl {
- self.check_op(ops::FnCallNonConst(callee));
+ self.check_op(ops::FnCallNonConst);
return;
}
@@ -823,25 +895,26 @@
return;
}
+ let is_intrinsic = tcx.fn_sig(callee).abi() == RustIntrinsic;
+
// HACK: This is to "unstabilize" the `transmute` intrinsic
// within const fns. `transmute` is allowed in all other const contexts.
// This won't really scale to more intrinsics or functions. Let's allow const
// transmutes in const fn before we add more hacks to this.
- if tcx.fn_sig(callee).abi() == RustIntrinsic
- && tcx.item_name(callee) == sym::transmute
- {
+ if is_intrinsic && tcx.item_name(callee) == sym::transmute {
self.check_op(ops::Transmute);
return;
}
if !tcx.is_const_fn_raw(callee) {
- self.check_op(ops::FnCallNonConst(callee));
+ self.check_op(ops::FnCallNonConst);
return;
}
// If the `const fn` we are trying to call is not const-stable, ensure that we have
// the proper feature gate enabled.
if let Some(gate) = is_unstable_const_fn(tcx, callee) {
+ trace!(?gate, "calling unstable const fn");
if self.span.allows_unstable(gate) {
return;
}
@@ -856,12 +929,14 @@
// If this crate is not using stability attributes, or the caller is not claiming to be a
// stable `const fn`, that is all that is required.
if !self.ccx.is_const_stable_const_fn() {
+ trace!("crate not using stability attributes or caller not stably const");
return;
}
// Otherwise, we are something const-stable calling a const-unstable fn.
if super::rustc_allow_const_fn_unstable(tcx, caller, gate) {
+ trace!("rustc_allow_const_fn_unstable gate active");
return;
}
@@ -875,10 +950,16 @@
let callee_is_unstable_unmarked = tcx.lookup_const_stability(callee).is_none()
&& tcx.lookup_stability(callee).map_or(false, |s| s.level.is_unstable());
if callee_is_unstable_unmarked {
- if self.ccx.is_const_stable_const_fn() {
+ trace!("callee_is_unstable_unmarked");
+ // We do not use `const` modifiers for intrinsic "functions", as intrinsics are
+ // `extern` funtions, and these have no way to get marked `const`. So instead we
+ // use `rustc_const_(un)stable` attributes to mean that the intrinsic is `const`
+ if self.ccx.is_const_stable_const_fn() || is_intrinsic {
self.check_op(ops::FnCallUnstable(callee, None));
+ return;
}
}
+ trace!("permitting call");
}
// Forbid all `Drop` terminators unless the place being dropped is a local with no
@@ -959,27 +1040,26 @@
body: &Body<'tcx>,
place: Place<'tcx>,
) -> Option<&'a [PlaceElem<'tcx>]> {
- place.projection.split_last().and_then(|(outermost, inner)| {
- if outermost != &ProjectionElem::Deref {
- return None;
+ match place.as_ref().last_projection() {
+ Some((place_base, ProjectionElem::Deref)) => {
+ // A borrow of a `static` also looks like `&(*_1)` in the MIR, but `_1` is a `const`
+ // that points to the allocation for the static. Don't treat these as reborrows.
+ if body.local_decls[place_base.local].is_ref_to_static() {
+ None
+ } else {
+ // Ensure the type being derefed is a reference and not a raw pointer.
+ //
+ // This is sufficient to prevent an access to a `static mut` from being marked as a
+ // reborrow, even if the check above were to disappear.
+ let inner_ty = place_base.ty(body, tcx).ty;
+ match inner_ty.kind() {
+ ty::Ref(..) => Some(place_base.projection),
+ _ => None,
+ }
+ }
}
-
- // A borrow of a `static` also looks like `&(*_1)` in the MIR, but `_1` is a `const`
- // that points to the allocation for the static. Don't treat these as reborrows.
- if body.local_decls[place.local].is_ref_to_static() {
- return None;
- }
-
- // Ensure the type being derefed is a reference and not a raw pointer.
- //
- // This is sufficient to prevent an access to a `static mut` from being marked as a
- // reborrow, even if the check above were to disappear.
- let inner_ty = Place::ty_from(place.local, inner, body, tcx).ty;
- match inner_ty.kind() {
- ty::Ref(..) => Some(inner),
- _ => None,
- }
- })
+ _ => None,
+ }
}
fn is_int_bool_or_char(ty: Ty<'_>) -> bool {
diff --git a/compiler/rustc_mir/src/transform/check_unsafety.rs b/compiler/rustc_mir/src/transform/check_unsafety.rs
index e64955c..f047275 100644
--- a/compiler/rustc_mir/src/transform/check_unsafety.rs
+++ b/compiler/rustc_mir/src/transform/check_unsafety.rs
@@ -223,13 +223,6 @@
// Check for raw pointer `Deref`.
for (base, proj) in place.iter_projections() {
if proj == ProjectionElem::Deref {
- let source_info = self.source_info; // Backup source_info so we can restore it later.
- if base.projection.is_empty() && decl.internal {
- // Internal locals are used in the `move_val_init` desugaring.
- // We want to check unsafety against the source info of the
- // desugaring, rather than the source info of the RHS.
- self.source_info = self.body.local_decls[place.local].source_info;
- }
let base_ty = base.ty(self.body, self.tcx).ty;
if base_ty.is_unsafe_ptr() {
self.require_unsafe(
@@ -237,7 +230,6 @@
UnsafetyViolationDetails::DerefOfRawPointer,
)
}
- self.source_info = source_info; // Restore backed-up source_info.
}
}
@@ -407,17 +399,13 @@
place: Place<'tcx>,
is_mut_use: bool,
) {
- let mut cursor = place.projection.as_ref();
- while let &[ref proj_base @ .., elem] = cursor {
- cursor = proj_base;
-
+ for (place_base, elem) in place.iter_projections().rev() {
match elem {
// Modifications behind a dereference don't affect the value of
// the pointer.
ProjectionElem::Deref => return,
ProjectionElem::Field(..) => {
- let ty =
- Place::ty_from(place.local, proj_base, &self.body.local_decls, self.tcx).ty;
+ let ty = place_base.ty(&self.body.local_decls, self.tcx).ty;
if let ty::Adt(def, _) = ty.kind() {
if self.tcx.layout_scalar_valid_range(def.did)
!= (Bound::Unbounded, Bound::Unbounded)
@@ -580,24 +568,23 @@
tcx: TyCtxt<'_>,
used_unsafe: &FxHashSet<hir::HirId>,
id: hir::HirId,
-) -> Option<(String, hir::HirId)> {
+ unsafe_op_in_unsafe_fn_allowed: bool,
+) -> Option<(&'static str, hir::HirId)> {
let parent_id = tcx.hir().get_parent_node(id);
if parent_id != id {
if used_unsafe.contains(&parent_id) {
- Some(("block".to_string(), parent_id))
+ Some(("block", parent_id))
} else if let Some(Node::Item(&hir::Item {
kind: hir::ItemKind::Fn(ref sig, _, _), ..
})) = tcx.hir().find(parent_id)
{
- if sig.header.unsafety == hir::Unsafety::Unsafe
- && !tcx.features().unsafe_block_in_unsafe_fn
- {
- Some(("fn".to_string(), parent_id))
+ if sig.header.unsafety == hir::Unsafety::Unsafe && unsafe_op_in_unsafe_fn_allowed {
+ Some(("fn", parent_id))
} else {
None
}
} else {
- is_enclosed(tcx, used_unsafe, parent_id)
+ is_enclosed(tcx, used_unsafe, parent_id, unsafe_op_in_unsafe_fn_allowed)
}
} else {
None
@@ -610,7 +597,9 @@
let msg = "unnecessary `unsafe` block";
let mut db = lint.build(msg);
db.span_label(span, msg);
- if let Some((kind, id)) = is_enclosed(tcx, used_unsafe, id) {
+ if let Some((kind, id)) =
+ is_enclosed(tcx, used_unsafe, id, unsafe_op_in_unsafe_fn_allowed(tcx, id))
+ {
db.span_label(
tcx.sess.source_map().guess_head_span(tcx.hir().span(id)),
format!("because it's nested under this `unsafe` {}", kind),
diff --git a/compiler/rustc_mir/src/transform/const_prop.rs b/compiler/rustc_mir/src/transform/const_prop.rs
index 1d949e0..fd5c223 100644
--- a/compiler/rustc_mir/src/transform/const_prop.rs
+++ b/compiler/rustc_mir/src/transform/const_prop.rs
@@ -25,6 +25,7 @@
use rustc_session::lint;
use rustc_span::{def_id::DefId, Span};
use rustc_target::abi::{HasDataLayout, LayoutOf, Size, TargetDataLayout};
+use rustc_target::spec::abi::Abi;
use rustc_trait_selection::traits;
use crate::const_eval::ConstEvalErr;
@@ -138,7 +139,7 @@
Default::default(),
body.arg_count,
Default::default(),
- tcx.def_span(def_id),
+ body.span,
body.generator_kind,
);
@@ -184,9 +185,17 @@
type MemoryExtra = ();
+ fn load_mir(
+ _ecx: &InterpCx<'mir, 'tcx, Self>,
+ _instance: ty::InstanceDef<'tcx>,
+ ) -> InterpResult<'tcx, &'tcx Body<'tcx>> {
+ throw_machine_stop_str!("calling functions isn't supported in ConstProp")
+ }
+
fn find_mir_or_eval_fn(
_ecx: &mut InterpCx<'mir, 'tcx, Self>,
_instance: ty::Instance<'tcx>,
+ _abi: Abi,
_args: &[OpTy<'tcx>],
_ret: Option<(PlaceTy<'tcx>, BasicBlock)>,
_unwind: Option<BasicBlock>,
@@ -431,7 +440,15 @@
}
fn lint_root(&self, source_info: SourceInfo) -> Option<HirId> {
- match &self.source_scopes[source_info.scope].local_data {
+ let mut data = &self.source_scopes[source_info.scope];
+ // FIXME(oli-obk): we should be able to just walk the `inlined_parent_scope`, but it
+ // does not work as I thought it would. Needs more investigation and documentation.
+ while data.inlined.is_some() {
+ trace!(?data);
+ data = &self.source_scopes[data.parent_scope.unwrap()];
+ }
+ trace!(?data);
+ match &data.local_data {
ClearCrossCrate::Set(data) => Some(data.lint_root),
ClearCrossCrate::Clear => None,
}
diff --git a/compiler/rustc_mir/src/transform/coverage/counters.rs b/compiler/rustc_mir/src/transform/coverage/counters.rs
index 20f6a16..272a7bf 100644
--- a/compiler/rustc_mir/src/transform/coverage/counters.rs
+++ b/compiler/rustc_mir/src/transform/coverage/counters.rs
@@ -32,7 +32,7 @@
}
/// Activate the `DebugCounters` data structures, to provide additional debug formatting
- /// features when formating `CoverageKind` (counter) values.
+ /// features when formatting `CoverageKind` (counter) values.
pub fn enable_debug(&mut self) {
self.debug_counters.enable();
}
@@ -140,7 +140,7 @@
/// message for subsequent debugging.
fn make_bcb_counters(
&mut self,
- coverage_spans: &Vec<CoverageSpan>,
+ coverage_spans: &[CoverageSpan],
) -> Result<Vec<CoverageKind>, Error> {
debug!("make_bcb_counters(): adding a counter or expression to each BasicCoverageBlock");
let num_bcbs = self.basic_coverage_blocks.num_nodes();
@@ -465,7 +465,7 @@
fn choose_preferred_expression_branch(
&self,
traversal: &TraverseCoverageGraphWithLoops,
- branches: &Vec<BcbBranch>,
+ branches: &[BcbBranch],
) -> BcbBranch {
let branch_needs_a_counter =
|branch: &BcbBranch| branch.counter(&self.basic_coverage_blocks).is_none();
@@ -509,7 +509,7 @@
fn find_some_reloop_branch(
&self,
traversal: &TraverseCoverageGraphWithLoops,
- branches: &Vec<BcbBranch>,
+ branches: &[BcbBranch],
) -> Option<BcbBranch> {
let branch_needs_a_counter =
|branch: &BcbBranch| branch.counter(&self.basic_coverage_blocks).is_none();
diff --git a/compiler/rustc_mir/src/transform/coverage/debug.rs b/compiler/rustc_mir/src/transform/coverage/debug.rs
index b66e374..2cd0dc6 100644
--- a/compiler/rustc_mir/src/transform/coverage/debug.rs
+++ b/compiler/rustc_mir/src/transform/coverage/debug.rs
@@ -130,7 +130,7 @@
pub(super) fn debug_options<'a>() -> &'a DebugOptions {
static DEBUG_OPTIONS: SyncOnceCell<DebugOptions> = SyncOnceCell::new();
- &DEBUG_OPTIONS.get_or_init(|| DebugOptions::from_env())
+ &DEBUG_OPTIONS.get_or_init(DebugOptions::from_env)
}
/// Parses and maintains coverage-specific debug options captured from the environment variable
@@ -430,7 +430,7 @@
{
bcb_to_coverage_spans_with_counters
.entry(bcb)
- .or_insert_with(|| Vec::new())
+ .or_insert_with(Vec::new)
.push((coverage_span.clone(), counter_kind.clone()));
}
}
@@ -456,7 +456,7 @@
if let Some(bcb_to_dependency_counters) = self.some_bcb_to_dependency_counters.as_mut() {
bcb_to_dependency_counters
.entry(bcb)
- .or_insert_with(|| Vec::new())
+ .or_insert_with(Vec::new)
.push(counter_kind.clone());
}
}
@@ -527,8 +527,8 @@
pub fn add_expression_operands(&mut self, expression: &CoverageKind) {
if let Some(used_expression_operands) = self.some_used_expression_operands.as_mut() {
if let CoverageKind::Expression { id, lhs, rhs, .. } = *expression {
- used_expression_operands.entry(lhs).or_insert_with(|| Vec::new()).push(id);
- used_expression_operands.entry(rhs).or_insert_with(|| Vec::new()).push(id);
+ used_expression_operands.entry(lhs).or_insert_with(Vec::new).push(id);
+ used_expression_operands.entry(rhs).or_insert_with(Vec::new).push(id);
}
}
}
diff --git a/compiler/rustc_mir/src/transform/coverage/graph.rs b/compiler/rustc_mir/src/transform/coverage/graph.rs
index b1a1bb9..e58b915 100644
--- a/compiler/rustc_mir/src/transform/coverage/graph.rs
+++ b/compiler/rustc_mir/src/transform/coverage/graph.rs
@@ -394,7 +394,7 @@
let operand = counter_kind.as_operand_id();
if let Some(replaced) = self
.edge_from_bcbs
- .get_or_insert_with(|| FxHashMap::default())
+ .get_or_insert_with(FxHashMap::default)
.insert(from_bcb, counter_kind)
{
Error::from_string(format!(
diff --git a/compiler/rustc_mir/src/transform/coverage/query.rs b/compiler/rustc_mir/src/transform/coverage/query.rs
index aa34ae7..4b455a6 100644
--- a/compiler/rustc_mir/src/transform/coverage/query.rs
+++ b/compiler/rustc_mir/src/transform/coverage/query.rs
@@ -4,7 +4,7 @@
use rustc_middle::mir::visit::Visitor;
use rustc_middle::mir::{self, Coverage, CoverageInfo, Location};
use rustc_middle::ty::query::Providers;
-use rustc_middle::ty::TyCtxt;
+use rustc_middle::ty::{self, TyCtxt};
use rustc_span::def_id::DefId;
/// The `query` provider for `CoverageInfo`, requested by `codegen_coverage()` (to inject each
@@ -112,7 +112,7 @@
}
fn coverageinfo_from_mir<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> CoverageInfo {
- let mir_body = tcx.optimized_mir(def_id);
+ let mir_body = mir_body(tcx, def_id);
let mut coverage_visitor = CoverageVisitor {
// num_counters always has at least the `ZERO` counter.
@@ -129,8 +129,7 @@
}
fn covered_file_name<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> Option<Symbol> {
- let mir_body = tcx.optimized_mir(def_id);
- for bb_data in mir_body.basic_blocks().iter() {
+ for bb_data in mir_body(tcx, def_id).basic_blocks().iter() {
for statement in bb_data.statements.iter() {
if let StatementKind::Coverage(box ref coverage) = statement.kind {
if let Some(code_region) = coverage.code_region.as_ref() {
@@ -142,9 +141,17 @@
None
}
+/// This function ensures we obtain the correct MIR for the given item irrespective of
+/// whether that means const mir or runtime mir. For `const fn` this opts for runtime
+/// mir.
+fn mir_body<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> &'tcx mir::Body<'tcx> {
+ let id = ty::WithOptConstParam::unknown(def_id);
+ let def = ty::InstanceDef::Item(id);
+ tcx.instance_mir(def)
+}
+
fn covered_code_regions<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> Vec<&'tcx CodeRegion> {
- let mir_body: &'tcx mir::Body<'tcx> = tcx.optimized_mir(def_id);
- mir_body
+ mir_body(tcx, def_id)
.basic_blocks()
.iter()
.map(|data| {
diff --git a/compiler/rustc_mir/src/transform/function_item_references.rs b/compiler/rustc_mir/src/transform/function_item_references.rs
index d592580..8d02ac6 100644
--- a/compiler/rustc_mir/src/transform/function_item_references.rs
+++ b/compiler/rustc_mir/src/transform/function_item_references.rs
@@ -5,7 +5,7 @@
use rustc_middle::ty::{
self,
subst::{GenericArgKind, Subst, SubstsRef},
- PredicateAtom, Ty, TyCtxt, TyS,
+ PredicateKind, Ty, TyCtxt, TyS,
};
use rustc_session::lint::builtin::FUNCTION_ITEM_REFERENCES;
use rustc_span::{symbol::sym, Span};
@@ -99,13 +99,13 @@
&self,
def_id: DefId,
substs_ref: SubstsRef<'tcx>,
- args: &Vec<Operand<'tcx>>,
+ args: &[Operand<'tcx>],
source_info: SourceInfo,
) {
let param_env = self.tcx.param_env(def_id);
let bounds = param_env.caller_bounds();
for bound in bounds {
- if let Some(bound_ty) = self.is_pointer_trait(&bound.skip_binders()) {
+ if let Some(bound_ty) = self.is_pointer_trait(&bound.kind().skip_binder()) {
// Get the argument types as they appear in the function signature.
let arg_defs = self.tcx.fn_sig(def_id).skip_binder().inputs();
for (arg_num, arg_def) in arg_defs.iter().enumerate() {
@@ -131,8 +131,8 @@
}
/// If the given predicate is the trait `fmt::Pointer`, returns the bound parameter type.
- fn is_pointer_trait(&self, bound: &PredicateAtom<'tcx>) -> Option<Ty<'tcx>> {
- if let ty::PredicateAtom::Trait(predicate, _) = bound {
+ fn is_pointer_trait(&self, bound: &PredicateKind<'tcx>) -> Option<Ty<'tcx>> {
+ if let ty::PredicateKind::Trait(predicate, _) = bound {
if self.tcx.is_diagnostic_item(sym::pointer_trait, predicate.def_id()) {
Some(predicate.trait_ref.self_ty())
} else {
@@ -162,7 +162,7 @@
.unwrap_or(None)
}
- fn nth_arg_span(&self, args: &Vec<Operand<'tcx>>, n: usize) -> Span {
+ fn nth_arg_span(&self, args: &[Operand<'tcx>], n: usize) -> Span {
match &args[n] {
Operand::Copy(place) | Operand::Move(place) => {
self.body.local_decls[place.local].source_info.span
diff --git a/compiler/rustc_mir/src/transform/inline.rs b/compiler/rustc_mir/src/transform/inline.rs
index 6e7575c..1635a95 100644
--- a/compiler/rustc_mir/src/transform/inline.rs
+++ b/compiler/rustc_mir/src/transform/inline.rs
@@ -17,6 +17,8 @@
use std::iter;
use std::ops::{Range, RangeFrom};
+crate mod cycle;
+
const INSTR_COST: usize = 5;
const CALL_PENALTY: usize = 25;
const LANDINGPAD_PENALTY: usize = 50;
@@ -37,10 +39,24 @@
impl<'tcx> MirPass<'tcx> for Inline {
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
+ // If you change this optimization level, also change the level in
+ // `mir_drops_elaborated_and_const_checked` for the call to `mir_inliner_callees`.
+ // Otherwise you will get an ICE about stolen MIR.
if tcx.sess.opts.debugging_opts.mir_opt_level < 2 {
return;
}
+ if tcx.sess.opts.debugging_opts.instrument_coverage {
+ // Since `Inline` happens after `InstrumentCoverage`, the function-specific coverage
+ // counters can be invalidated, such as by merging coverage counter statements from
+ // a pre-inlined function into a different function. This kind of change is invalid,
+ // so inlining must be skipped. Note: This check is performed here so inlining can
+ // be disabled without preventing other optimizations (regardless of `mir_opt_level`).
+ return;
+ }
+
+ let span = trace_span!("inline", body = %tcx.def_path_str(body.source.def_id()));
+ let _guard = span.enter();
if inline(tcx, body) {
debug!("running simplify cfg on {:?}", body.source);
CfgSimplifier::new(body).simplify();
@@ -81,8 +97,8 @@
codegen_fn_attrs: &'tcx CodegenFnAttrs,
/// Caller HirID.
hir_id: hir::HirId,
- /// Stack of inlined instances.
- history: Vec<Instance<'tcx>>,
+ /// Stack of inlined Instances.
+ history: Vec<ty::Instance<'tcx>>,
/// Indicates that the caller body has been modified.
changed: bool,
}
@@ -94,13 +110,28 @@
None => continue,
Some(it) => it,
};
+ let span = trace_span!("process_blocks", %callsite.callee, ?bb);
+ let _guard = span.enter();
- if !self.is_mir_available(&callsite.callee, caller_body) {
+ trace!(
+ "checking for self recursion ({:?} vs body_source: {:?})",
+ callsite.callee.def_id(),
+ caller_body.source.def_id()
+ );
+ if callsite.callee.def_id() == caller_body.source.def_id() {
+ debug!("Not inlining a function into itself");
+ continue;
+ }
+
+ if !self.is_mir_available(callsite.callee, caller_body) {
debug!("MIR unavailable {}", callsite.callee);
continue;
}
+ let span = trace_span!("instance_mir", %callsite.callee);
+ let instance_mir_guard = span.enter();
let callee_body = self.tcx.instance_mir(callsite.callee.def);
+ drop(instance_mir_guard);
if !self.should_inline(callsite, callee_body) {
continue;
}
@@ -128,28 +159,61 @@
}
}
- fn is_mir_available(&self, callee: &Instance<'tcx>, caller_body: &Body<'tcx>) -> bool {
- if let InstanceDef::Item(_) = callee.def {
- if !self.tcx.is_mir_available(callee.def_id()) {
- return false;
+ #[instrument(skip(self, caller_body))]
+ fn is_mir_available(&self, callee: Instance<'tcx>, caller_body: &Body<'tcx>) -> bool {
+ match callee.def {
+ InstanceDef::Item(_) => {
+ // If there is no MIR available (either because it was not in metadata or
+ // because it has no MIR because it's an extern function), then the inliner
+ // won't cause cycles on this.
+ if !self.tcx.is_mir_available(callee.def_id()) {
+ return false;
+ }
}
+ // These have no own callable MIR.
+ InstanceDef::Intrinsic(_) | InstanceDef::Virtual(..) => return false,
+ // This cannot result in an immediate cycle since the callee MIR is a shim, which does
+ // not get any optimizations run on it. Any subsequent inlining may cause cycles, but we
+ // do not need to catch this here, we can wait until the inliner decides to continue
+ // inlining a second time.
+ InstanceDef::VtableShim(_)
+ | InstanceDef::ReifyShim(_)
+ | InstanceDef::FnPtrShim(..)
+ | InstanceDef::ClosureOnceShim { .. }
+ | InstanceDef::DropGlue(..)
+ | InstanceDef::CloneShim(..) => return true,
+ }
+
+ if self.tcx.is_constructor(callee.def_id()) {
+ trace!("constructors always have MIR");
+ // Constructor functions cannot cause a query cycle.
+ return true;
}
if let Some(callee_def_id) = callee.def_id().as_local() {
let callee_hir_id = self.tcx.hir().local_def_id_to_hir_id(callee_def_id);
- // Avoid a cycle here by only using `instance_mir` only if we have
- // a lower `HirId` than the callee. This ensures that the callee will
- // not inline us. This trick only works without incremental compilation.
- // So don't do it if that is enabled. Also avoid inlining into generators,
+ // Avoid inlining into generators,
// since their `optimized_mir` is used for layout computation, which can
// create a cycle, even when no attempt is made to inline the function
// in the other direction.
- !self.tcx.dep_graph.is_fully_enabled()
+ caller_body.generator_kind.is_none()
+ && (
+ // Avoid a cycle here by only using `instance_mir` only if we have
+ // a lower `HirId` than the callee. This ensures that the callee will
+ // not inline us. This trick only works without incremental compilation.
+ // So don't do it if that is enabled.
+ !self.tcx.dep_graph.is_fully_enabled()
&& self.hir_id < callee_hir_id
- && caller_body.generator_kind.is_none()
+ // If we know for sure that the function we're calling will itself try to
+ // call us, then we avoid inlining that function.
+ || !self.tcx.mir_callgraph_reachable((callee, caller_body.source.def_id().expect_local()))
+ )
} else {
- // This cannot result in a cycle since the callee MIR is from another crate
- // and is already optimized.
+ // This cannot result in an immediate cycle since the callee MIR is from another crate
+ // and is already optimized. Any subsequent inlining may cause cycles, but we do
+ // not need to catch this here, we can wait until the inliner decides to continue
+ // inlining a second time.
+ trace!("functions from other crates always have MIR");
true
}
}
@@ -194,8 +258,8 @@
None
}
+ #[instrument(skip(self, callee_body))]
fn should_inline(&self, callsite: CallSite<'tcx>, callee_body: &Body<'tcx>) -> bool {
- debug!("should_inline({:?})", callsite);
let tcx = self.tcx;
if callsite.fn_sig.c_variadic() {
@@ -217,6 +281,11 @@
return false;
}
+ if self.codegen_fn_attrs.instruction_set != codegen_fn_attrs.instruction_set {
+ debug!("`callee has incompatible instruction set - not inlining");
+ return false;
+ }
+
let hinted = match codegen_fn_attrs.inline {
// Just treat inline(always) as a hint for now,
// there are cases that prevent inlining that we
@@ -324,7 +393,9 @@
if let Ok(Some(instance)) =
Instance::resolve(self.tcx, self.param_env, def_id, substs)
{
- if callsite.callee == instance || self.history.contains(&instance) {
+ if callsite.callee.def_id() == instance.def_id()
+ || self.history.contains(&instance)
+ {
debug!("`callee is recursive - not inlining");
return false;
}
@@ -373,7 +444,7 @@
// Cost of the var is the size in machine-words, if we know
// it.
if let Some(size) = type_size_of(tcx, self.param_env, ty) {
- cost += (size / ptr_size) as usize;
+ cost += ((size + ptr_size - 1) / ptr_size) as usize;
} else {
cost += UNKNOWN_SIZE_COST;
}
@@ -742,11 +813,11 @@
}
fn visit_span(&mut self, span: &mut Span) {
+ let mut expn_data =
+ ExpnData::default(ExpnKind::Inlined, *span, self.tcx.sess.edition(), None);
+ expn_data.def_site = self.body_span;
// Make sure that all spans track the fact that they were inlined.
- *span = self.callsite_span.fresh_expansion(ExpnData {
- def_site: self.body_span,
- ..ExpnData::default(ExpnKind::Inlined, *span, self.tcx.sess.edition(), None)
- });
+ *span = self.callsite_span.fresh_expansion(expn_data);
}
fn visit_place(&mut self, place: &mut Place<'tcx>, context: PlaceContext, location: Location) {
diff --git a/compiler/rustc_mir/src/transform/inline/cycle.rs b/compiler/rustc_mir/src/transform/inline/cycle.rs
new file mode 100644
index 0000000..e4d403f
--- /dev/null
+++ b/compiler/rustc_mir/src/transform/inline/cycle.rs
@@ -0,0 +1,157 @@
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::stack::ensure_sufficient_stack;
+use rustc_hir::def_id::{DefId, LocalDefId};
+use rustc_middle::mir::TerminatorKind;
+use rustc_middle::ty::TypeFoldable;
+use rustc_middle::ty::{self, subst::SubstsRef, InstanceDef, TyCtxt};
+
+// FIXME: check whether it is cheaper to precompute the entire call graph instead of invoking
+// this query riddiculously often.
+#[instrument(skip(tcx, root, target))]
+crate fn mir_callgraph_reachable(
+ tcx: TyCtxt<'tcx>,
+ (root, target): (ty::Instance<'tcx>, LocalDefId),
+) -> bool {
+ trace!(%root, target = %tcx.def_path_str(target.to_def_id()));
+ let param_env = tcx.param_env_reveal_all_normalized(target);
+ assert_ne!(
+ root.def_id().expect_local(),
+ target,
+ "you should not call `mir_callgraph_reachable` on immediate self recursion"
+ );
+ assert!(
+ matches!(root.def, InstanceDef::Item(_)),
+ "you should not call `mir_callgraph_reachable` on shims"
+ );
+ assert!(
+ !tcx.is_constructor(root.def_id()),
+ "you should not call `mir_callgraph_reachable` on enum/struct constructor functions"
+ );
+ #[instrument(skip(tcx, param_env, target, stack, seen, recursion_limiter, caller))]
+ fn process(
+ tcx: TyCtxt<'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ caller: ty::Instance<'tcx>,
+ target: LocalDefId,
+ stack: &mut Vec<ty::Instance<'tcx>>,
+ seen: &mut FxHashSet<ty::Instance<'tcx>>,
+ recursion_limiter: &mut FxHashMap<DefId, usize>,
+ ) -> bool {
+ trace!(%caller);
+ for &(callee, substs) in tcx.mir_inliner_callees(caller.def) {
+ let substs = caller.subst_mir_and_normalize_erasing_regions(tcx, param_env, substs);
+ let callee = match ty::Instance::resolve(tcx, param_env, callee, substs).unwrap() {
+ Some(callee) => callee,
+ None => {
+ trace!(?callee, "cannot resolve, skipping");
+ continue;
+ }
+ };
+
+ // Found a path.
+ if callee.def_id() == target.to_def_id() {
+ return true;
+ }
+
+ if tcx.is_constructor(callee.def_id()) {
+ trace!("constructors always have MIR");
+ // Constructor functions cannot cause a query cycle.
+ continue;
+ }
+
+ match callee.def {
+ InstanceDef::Item(_) => {
+ // If there is no MIR available (either because it was not in metadata or
+ // because it has no MIR because it's an extern function), then the inliner
+ // won't cause cycles on this.
+ if !tcx.is_mir_available(callee.def_id()) {
+ trace!(?callee, "no mir available, skipping");
+ continue;
+ }
+ }
+ // These have no own callable MIR.
+ InstanceDef::Intrinsic(_) | InstanceDef::Virtual(..) => continue,
+ // These have MIR and if that MIR is inlined, substituted and then inlining is run
+ // again, a function item can end up getting inlined. Thus we'll be able to cause
+ // a cycle that way
+ InstanceDef::VtableShim(_)
+ | InstanceDef::ReifyShim(_)
+ | InstanceDef::FnPtrShim(..)
+ | InstanceDef::ClosureOnceShim { .. }
+ | InstanceDef::CloneShim(..) => {}
+ InstanceDef::DropGlue(..) => {
+ // FIXME: A not fully substituted drop shim can cause ICEs if one attempts to
+ // have its MIR built. Likely oli-obk just screwed up the `ParamEnv`s, so this
+ // needs some more analysis.
+ if callee.needs_subst() {
+ continue;
+ }
+ }
+ }
+
+ if seen.insert(callee) {
+ let recursion = recursion_limiter.entry(callee.def_id()).or_default();
+ trace!(?callee, recursion = *recursion);
+ if tcx.sess.recursion_limit().value_within_limit(*recursion) {
+ *recursion += 1;
+ stack.push(callee);
+ let found_recursion = ensure_sufficient_stack(|| {
+ process(tcx, param_env, callee, target, stack, seen, recursion_limiter)
+ });
+ if found_recursion {
+ return true;
+ }
+ stack.pop();
+ } else {
+ // Pessimistically assume that there could be recursion.
+ return true;
+ }
+ }
+ }
+ false
+ }
+ process(
+ tcx,
+ param_env,
+ root,
+ target,
+ &mut Vec::new(),
+ &mut FxHashSet::default(),
+ &mut FxHashMap::default(),
+ )
+}
+
+crate fn mir_inliner_callees<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ instance: ty::InstanceDef<'tcx>,
+) -> &'tcx [(DefId, SubstsRef<'tcx>)] {
+ let steal;
+ let guard;
+ let body = match (instance, instance.def_id().as_local()) {
+ (InstanceDef::Item(_), Some(def_id)) => {
+ let def = ty::WithOptConstParam::unknown(def_id);
+ steal = tcx.mir_promoted(def).0;
+ guard = steal.borrow();
+ &*guard
+ }
+ // Functions from other crates and MIR shims
+ _ => tcx.instance_mir(instance),
+ };
+ let mut calls = Vec::new();
+ for bb_data in body.basic_blocks() {
+ let terminator = bb_data.terminator();
+ if let TerminatorKind::Call { func, .. } = &terminator.kind {
+ let ty = func.ty(&body.local_decls, tcx);
+ let call = match ty.kind() {
+ ty::FnDef(def_id, substs) => (*def_id, *substs),
+ _ => continue,
+ };
+ // We've seen this before
+ if calls.contains(&call) {
+ continue;
+ }
+ calls.push(call);
+ }
+ }
+ tcx.arena.alloc_slice(&calls)
+}
diff --git a/compiler/rustc_mir/src/transform/instcombine.rs b/compiler/rustc_mir/src/transform/instcombine.rs
index 3eb2b50..74dadb2 100644
--- a/compiler/rustc_mir/src/transform/instcombine.rs
+++ b/compiler/rustc_mir/src/transform/instcombine.rs
@@ -1,312 +1,123 @@
//! Performs various peephole optimizations.
use crate::transform::MirPass;
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_hir::Mutability;
-use rustc_index::vec::Idx;
use rustc_middle::mir::{
- visit::PlaceContext,
- visit::{MutVisitor, Visitor},
- Statement,
-};
-use rustc_middle::mir::{
- BinOp, Body, BorrowKind, Constant, Local, Location, Operand, Place, PlaceRef, ProjectionElem,
- Rvalue,
+ BinOp, Body, Constant, LocalDecls, Operand, Place, ProjectionElem, Rvalue, SourceInfo,
+ StatementKind,
};
use rustc_middle::ty::{self, TyCtxt};
-use std::mem;
pub struct InstCombine;
impl<'tcx> MirPass<'tcx> for InstCombine {
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
- // First, find optimization opportunities. This is done in a pre-pass to keep the MIR
- // read-only so that we can do global analyses on the MIR in the process (e.g.
- // `Place::ty()`).
- let optimizations = {
- let mut optimization_finder = OptimizationFinder::new(body, tcx);
- optimization_finder.visit_body(body);
- optimization_finder.optimizations
- };
-
- // Then carry out those optimizations.
- MutVisitor::visit_body(&mut InstCombineVisitor { optimizations, tcx }, body);
+ let (basic_blocks, local_decls) = body.basic_blocks_and_local_decls_mut();
+ let ctx = InstCombineContext { tcx, local_decls };
+ for block in basic_blocks.iter_mut() {
+ for statement in block.statements.iter_mut() {
+ match statement.kind {
+ StatementKind::Assign(box (_place, ref mut rvalue)) => {
+ ctx.combine_bool_cmp(&statement.source_info, rvalue);
+ ctx.combine_ref_deref(&statement.source_info, rvalue);
+ ctx.combine_len(&statement.source_info, rvalue);
+ }
+ _ => {}
+ }
+ }
+ }
}
}
-pub struct InstCombineVisitor<'tcx> {
- optimizations: OptimizationList<'tcx>,
+struct InstCombineContext<'tcx, 'a> {
tcx: TyCtxt<'tcx>,
+ local_decls: &'a LocalDecls<'tcx>,
}
-impl<'tcx> InstCombineVisitor<'tcx> {
- fn should_combine(&self, rvalue: &Rvalue<'tcx>, location: Location) -> bool {
+impl<'tcx, 'a> InstCombineContext<'tcx, 'a> {
+ fn should_combine(&self, source_info: &SourceInfo, rvalue: &Rvalue<'tcx>) -> bool {
self.tcx.consider_optimizing(|| {
- format!("InstCombine - Rvalue: {:?} Location: {:?}", rvalue, location)
+ format!("InstCombine - Rvalue: {:?} SourceInfo: {:?}", rvalue, source_info)
})
}
-}
-impl<'tcx> MutVisitor<'tcx> for InstCombineVisitor<'tcx> {
- fn tcx(&self) -> TyCtxt<'tcx> {
- self.tcx
- }
+ /// Transform boolean comparisons into logical operations.
+ fn combine_bool_cmp(&self, source_info: &SourceInfo, rvalue: &mut Rvalue<'tcx>) {
+ match rvalue {
+ Rvalue::BinaryOp(op @ (BinOp::Eq | BinOp::Ne), a, b) => {
+ let new = match (op, self.try_eval_bool(a), self.try_eval_bool(b)) {
+ // Transform "Eq(a, true)" ==> "a"
+ (BinOp::Eq, _, Some(true)) => Some(a.clone()),
- fn visit_rvalue(&mut self, rvalue: &mut Rvalue<'tcx>, location: Location) {
- if self.optimizations.and_stars.remove(&location) && self.should_combine(rvalue, location) {
- debug!("replacing `&*`: {:?}", rvalue);
- let new_place = match rvalue {
- Rvalue::Ref(_, _, place) => {
- if let &[ref proj_l @ .., proj_r] = place.projection.as_ref() {
- place.projection = self.tcx().intern_place_elems(&[proj_r]);
+ // Transform "Ne(a, false)" ==> "a"
+ (BinOp::Ne, _, Some(false)) => Some(a.clone()),
- Place {
- // Replace with dummy
- local: mem::replace(&mut place.local, Local::new(0)),
- projection: self.tcx().intern_place_elems(proj_l),
- }
- } else {
- unreachable!();
+ // Transform "Eq(true, b)" ==> "b"
+ (BinOp::Eq, Some(true), _) => Some(b.clone()),
+
+ // Transform "Ne(false, b)" ==> "b"
+ (BinOp::Ne, Some(false), _) => Some(b.clone()),
+
+ // FIXME: Consider combining remaining comparisons into logical operations:
+ // Transform "Eq(false, b)" ==> "Not(b)"
+ // Transform "Ne(true, b)" ==> "Not(b)"
+ // Transform "Eq(a, false)" ==> "Not(a)"
+ // Transform "Ne(a, true)" ==> "Not(a)"
+ _ => None,
+ };
+
+ if let Some(new) = new {
+ if self.should_combine(source_info, rvalue) {
+ *rvalue = Rvalue::Use(new);
}
}
- _ => bug!("Detected `&*` but didn't find `&*`!"),
- };
- *rvalue = Rvalue::Use(Operand::Copy(new_place))
- }
+ }
- if let Some(constant) = self.optimizations.arrays_lengths.remove(&location) {
- if self.should_combine(rvalue, location) {
- debug!("replacing `Len([_; N])`: {:?}", rvalue);
+ _ => {}
+ }
+ }
+
+ fn try_eval_bool(&self, a: &Operand<'_>) -> Option<bool> {
+ let a = a.constant()?;
+ if a.literal.ty.is_bool() { a.literal.val.try_to_bool() } else { None }
+ }
+
+ /// Transform "&(*a)" ==> "a".
+ fn combine_ref_deref(&self, source_info: &SourceInfo, rvalue: &mut Rvalue<'tcx>) {
+ if let Rvalue::Ref(_, _, place) = rvalue {
+ if let Some((base, ProjectionElem::Deref)) = place.as_ref().last_projection() {
+ if let ty::Ref(_, _, Mutability::Not) =
+ base.ty(self.local_decls, self.tcx).ty.kind()
+ {
+ // The dereferenced place must have type `&_`, so that we don't copy `&mut _`.
+ } else {
+ return;
+ }
+
+ if !self.should_combine(source_info, rvalue) {
+ return;
+ }
+
+ *rvalue = Rvalue::Use(Operand::Copy(Place {
+ local: base.local,
+ projection: self.tcx.intern_place_elems(base.projection),
+ }));
+ }
+ }
+ }
+
+ /// Transform "Len([_; N])" ==> "N".
+ fn combine_len(&self, source_info: &SourceInfo, rvalue: &mut Rvalue<'tcx>) {
+ if let Rvalue::Len(ref place) = *rvalue {
+ let place_ty = place.ty(self.local_decls, self.tcx).ty;
+ if let ty::Array(_, len) = place_ty.kind() {
+ if !self.should_combine(source_info, rvalue) {
+ return;
+ }
+
+ let constant = Constant { span: source_info.span, literal: len, user_ty: None };
*rvalue = Rvalue::Use(Operand::Constant(box constant));
}
}
-
- if let Some(operand) = self.optimizations.unneeded_equality_comparison.remove(&location) {
- if self.should_combine(rvalue, location) {
- debug!("replacing {:?} with {:?}", rvalue, operand);
- *rvalue = Rvalue::Use(operand);
- }
- }
-
- if let Some(place) = self.optimizations.unneeded_deref.remove(&location) {
- if self.should_combine(rvalue, location) {
- debug!("unneeded_deref: replacing {:?} with {:?}", rvalue, place);
- *rvalue = Rvalue::Use(Operand::Copy(place));
- }
- }
-
- self.super_rvalue(rvalue, location)
}
}
-
-struct MutatingUseVisitor {
- has_mutating_use: bool,
- local_to_look_for: Local,
-}
-
-impl MutatingUseVisitor {
- fn has_mutating_use_in_stmt(local: Local, stmt: &Statement<'tcx>, location: Location) -> bool {
- let mut _self = Self { has_mutating_use: false, local_to_look_for: local };
- _self.visit_statement(stmt, location);
- _self.has_mutating_use
- }
-}
-
-impl<'tcx> Visitor<'tcx> for MutatingUseVisitor {
- fn visit_local(&mut self, local: &Local, context: PlaceContext, _: Location) {
- if *local == self.local_to_look_for {
- self.has_mutating_use |= context.is_mutating_use();
- }
- }
-}
-
-/// Finds optimization opportunities on the MIR.
-struct OptimizationFinder<'b, 'tcx> {
- body: &'b Body<'tcx>,
- tcx: TyCtxt<'tcx>,
- optimizations: OptimizationList<'tcx>,
-}
-
-impl OptimizationFinder<'b, 'tcx> {
- fn new(body: &'b Body<'tcx>, tcx: TyCtxt<'tcx>) -> OptimizationFinder<'b, 'tcx> {
- OptimizationFinder { body, tcx, optimizations: OptimizationList::default() }
- }
-
- fn find_deref_of_address(&mut self, rvalue: &Rvalue<'tcx>, location: Location) -> Option<()> {
- // FIXME(#78192): This optimization can result in unsoundness.
- if !self.tcx.sess.opts.debugging_opts.unsound_mir_opts {
- return None;
- }
-
- // Look for the sequence
- //
- // _2 = &_1;
- // ...
- // _5 = (*_2);
- //
- // which we can replace the last statement with `_5 = _1;` to avoid the load of `_2`.
- if let Rvalue::Use(op) = rvalue {
- let local_being_derefed = match op.place()?.as_ref() {
- PlaceRef { local, projection: [ProjectionElem::Deref] } => Some(local),
- _ => None,
- }?;
-
- let mut dead_locals_seen = vec![];
-
- let stmt_index = location.statement_index;
- // Look behind for statement that assigns the local from a address of operator.
- // 6 is chosen as a heuristic determined by seeing the number of times
- // the optimization kicked in compiling rust std.
- let lower_index = stmt_index.saturating_sub(6);
- let statements_to_look_in = self.body.basic_blocks()[location.block].statements
- [lower_index..stmt_index]
- .iter()
- .rev();
- for stmt in statements_to_look_in {
- match &stmt.kind {
- // Exhaustive match on statements to detect conditions that warrant we bail out of the optimization.
- rustc_middle::mir::StatementKind::Assign(box (l, r))
- if l.local == local_being_derefed =>
- {
- match r {
- // Looking for immutable reference e.g _local_being_deref = &_1;
- Rvalue::Ref(
- _,
- // Only apply the optimization if it is an immutable borrow.
- BorrowKind::Shared,
- place_taken_address_of,
- ) => {
- // Make sure that the place has not been marked dead
- if dead_locals_seen.contains(&place_taken_address_of.local) {
- return None;
- }
-
- self.optimizations
- .unneeded_deref
- .insert(location, *place_taken_address_of);
- return Some(());
- }
-
- // We found an assignment of `local_being_deref` that is not an immutable ref, e.g the following sequence
- // _2 = &_1;
- // _3 = &5
- // _2 = _3; <-- this means it is no longer valid to replace the last statement with `_5 = _1;`
- // _5 = (*_2);
- _ => return None,
- }
- }
-
- // Inline asm can do anything, so bail out of the optimization.
- rustc_middle::mir::StatementKind::LlvmInlineAsm(_) => return None,
-
- // Remember `StorageDead`s, as the local being marked dead could be the
- // place RHS we are looking for, in which case we need to abort to avoid UB
- // using an uninitialized place
- rustc_middle::mir::StatementKind::StorageDead(dead) => {
- dead_locals_seen.push(*dead)
- }
-
- // Check that `local_being_deref` is not being used in a mutating way which can cause misoptimization.
- rustc_middle::mir::StatementKind::Assign(box (_, _))
- | rustc_middle::mir::StatementKind::Coverage(_)
- | rustc_middle::mir::StatementKind::Nop
- | rustc_middle::mir::StatementKind::FakeRead(_, _)
- | rustc_middle::mir::StatementKind::StorageLive(_)
- | rustc_middle::mir::StatementKind::Retag(_, _)
- | rustc_middle::mir::StatementKind::AscribeUserType(_, _)
- | rustc_middle::mir::StatementKind::SetDiscriminant { .. } => {
- if MutatingUseVisitor::has_mutating_use_in_stmt(
- local_being_derefed,
- stmt,
- location,
- ) {
- return None;
- }
- }
- }
- }
- }
- Some(())
- }
-
- fn find_unneeded_equality_comparison(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
- // find Ne(_place, false) or Ne(false, _place)
- // or Eq(_place, true) or Eq(true, _place)
- if let Rvalue::BinaryOp(op, l, r) = rvalue {
- let const_to_find = if *op == BinOp::Ne {
- false
- } else if *op == BinOp::Eq {
- true
- } else {
- return;
- };
- // (const, _place)
- if let Some(o) = self.find_operand_in_equality_comparison_pattern(l, r, const_to_find) {
- self.optimizations.unneeded_equality_comparison.insert(location, o.clone());
- }
- // (_place, const)
- else if let Some(o) =
- self.find_operand_in_equality_comparison_pattern(r, l, const_to_find)
- {
- self.optimizations.unneeded_equality_comparison.insert(location, o.clone());
- }
- }
- }
-
- fn find_operand_in_equality_comparison_pattern(
- &self,
- l: &Operand<'tcx>,
- r: &'a Operand<'tcx>,
- const_to_find: bool,
- ) -> Option<&'a Operand<'tcx>> {
- let const_ = l.constant()?;
- if const_.literal.ty == self.tcx.types.bool
- && const_.literal.val.try_to_bool() == Some(const_to_find)
- {
- if r.place().is_some() {
- return Some(r);
- }
- }
-
- None
- }
-}
-
-impl Visitor<'tcx> for OptimizationFinder<'b, 'tcx> {
- fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
- if let Rvalue::Ref(_, _, place) = rvalue {
- if let PlaceRef { local, projection: &[ref proj_base @ .., ProjectionElem::Deref] } =
- place.as_ref()
- {
- // The dereferenced place must have type `&_`.
- let ty = Place::ty_from(local, proj_base, self.body, self.tcx).ty;
- if let ty::Ref(_, _, Mutability::Not) = ty.kind() {
- self.optimizations.and_stars.insert(location);
- }
- }
- }
-
- if let Rvalue::Len(ref place) = *rvalue {
- let place_ty = place.ty(&self.body.local_decls, self.tcx).ty;
- if let ty::Array(_, len) = place_ty.kind() {
- let span = self.body.source_info(location).span;
- let constant = Constant { span, literal: len, user_ty: None };
- self.optimizations.arrays_lengths.insert(location, constant);
- }
- }
-
- let _ = self.find_deref_of_address(rvalue, location);
-
- self.find_unneeded_equality_comparison(rvalue, location);
-
- self.super_rvalue(rvalue, location)
- }
-}
-
-#[derive(Default)]
-struct OptimizationList<'tcx> {
- and_stars: FxHashSet<Location>,
- arrays_lengths: FxHashMap<Location, Constant<'tcx>>,
- unneeded_equality_comparison: FxHashMap<Location, Operand<'tcx>>,
- unneeded_deref: FxHashMap<Location, Place<'tcx>>,
-}
diff --git a/compiler/rustc_mir/src/transform/mod.rs b/compiler/rustc_mir/src/transform/mod.rs
index 7f3b421..2786127 100644
--- a/compiler/rustc_mir/src/transform/mod.rs
+++ b/compiler/rustc_mir/src/transform/mod.rs
@@ -71,9 +71,11 @@
},
mir_promoted,
mir_drops_elaborated_and_const_checked,
+ mir_for_ctfe,
+ mir_for_ctfe_of_const_arg,
optimized_mir,
- optimized_mir_of_const_arg,
is_mir_available,
+ is_ctfe_mir_available: |tcx, did| is_mir_available(tcx, did),
promoted_mir: |tcx, def_id| {
let def_id = def_id.expect_local();
if let Some(def) = ty::WithOptConstParam::try_lookup(def_id, tcx) {
@@ -278,6 +280,7 @@
tcx.alloc_steal_mir(body)
}
+/// Compute the main MIR body and the list of MIR bodies of the promoteds.
fn mir_promoted(
tcx: TyCtxt<'tcx>,
def: ty::WithOptConstParam<LocalDefId>,
@@ -319,6 +322,87 @@
(tcx.alloc_steal_mir(body), tcx.alloc_steal_promoted(promoted))
}
+/// Compute the MIR that is used during CTFE (and thus has no optimizations run on it)
+fn mir_for_ctfe<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> &'tcx Body<'tcx> {
+ let did = def_id.expect_local();
+ if let Some(def) = ty::WithOptConstParam::try_lookup(did, tcx) {
+ tcx.mir_for_ctfe_of_const_arg(def)
+ } else {
+ tcx.arena.alloc(inner_mir_for_ctfe(tcx, ty::WithOptConstParam::unknown(did)))
+ }
+}
+
+/// Same as `mir_for_ctfe`, but used to get the MIR of a const generic parameter.
+/// The docs on `WithOptConstParam` explain this a bit more, but the TLDR is that
+/// we'd get cycle errors with `mir_for_ctfe`, because typeck would need to typeck
+/// the const parameter while type checking the main body, which in turn would try
+/// to type check the main body again.
+fn mir_for_ctfe_of_const_arg<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ (did, param_did): (LocalDefId, DefId),
+) -> &'tcx Body<'tcx> {
+ tcx.arena.alloc(inner_mir_for_ctfe(
+ tcx,
+ ty::WithOptConstParam { did, const_param_did: Some(param_did) },
+ ))
+}
+
+fn inner_mir_for_ctfe(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -> Body<'_> {
+ // FIXME: don't duplicate this between the optimized_mir/mir_for_ctfe queries
+ if tcx.is_constructor(def.did.to_def_id()) {
+ // There's no reason to run all of the MIR passes on constructors when
+ // we can just output the MIR we want directly. This also saves const
+ // qualification and borrow checking the trouble of special casing
+ // constructors.
+ return shim::build_adt_ctor(tcx, def.did.to_def_id());
+ }
+
+ let context = tcx
+ .hir()
+ .body_const_context(def.did)
+ .expect("mir_for_ctfe should not be used for runtime functions");
+
+ let mut body = tcx.mir_drops_elaborated_and_const_checked(def).borrow().clone();
+
+ match context {
+ // Do not const prop functions, either they get executed at runtime or exported to metadata,
+ // so we run const prop on them, or they don't, in which case we const evaluate some control
+ // flow paths of the function and any errors in those paths will get emitted as const eval
+ // errors.
+ hir::ConstContext::ConstFn => {}
+ // Static items always get evaluated, so we can just let const eval see if any erroneous
+ // control flow paths get executed.
+ hir::ConstContext::Static(_) => {}
+ // Associated constants get const prop run so we detect common failure situations in the
+ // crate that defined the constant.
+ // Technically we want to not run on regular const items, but oli-obk doesn't know how to
+ // conveniently detect that at this point without looking at the HIR.
+ hir::ConstContext::Const => {
+ #[rustfmt::skip]
+ let optimizations: &[&dyn MirPass<'_>] = &[
+ &const_prop::ConstProp,
+ ];
+
+ #[rustfmt::skip]
+ run_passes(
+ tcx,
+ &mut body,
+ MirPhase::Optimization,
+ &[
+ optimizations,
+ ],
+ );
+ }
+ }
+
+ debug_assert!(!body.has_free_regions(), "Free regions in MIR for CTFE");
+
+ body
+}
+
+/// Obtain just the main MIR (no promoteds) and run some cleanups on it. This also runs
+/// mir borrowck *before* doing so in order to ensure that borrowck can be run and doesn't
+/// end up missing the source MIR due to stealing happening.
fn mir_drops_elaborated_and_const_checked<'tcx>(
tcx: TyCtxt<'tcx>,
def: ty::WithOptConstParam<LocalDefId>,
@@ -335,6 +419,20 @@
tcx.ensure().mir_borrowck(def.did);
}
+ let hir_id = tcx.hir().local_def_id_to_hir_id(def.did);
+ use rustc_middle::hir::map::blocks::FnLikeNode;
+ let is_fn_like = FnLikeNode::from_node(tcx.hir().get(hir_id)).is_some();
+ if is_fn_like {
+ let did = def.did.to_def_id();
+ let def = ty::WithOptConstParam::unknown(did);
+
+ // Do not compute the mir call graph without said call graph actually being used.
+ // Keep this in sync with the mir inliner's optimization level.
+ if tcx.sess.opts.debugging_opts.mir_opt_level >= 2 {
+ let _ = tcx.mir_inliner_callees(ty::InstanceDef::Item(def));
+ }
+ }
+
let (body, _) = tcx.mir_promoted(def);
let mut body = body.steal();
@@ -349,7 +447,7 @@
let post_borrowck_cleanup: &[&dyn MirPass<'tcx>] = &[
// Remove all things only needed by analysis
- &no_landing_pads::NoLandingPads::new(tcx),
+ &no_landing_pads::NoLandingPads,
&simplify_branches::SimplifyBranches::new("initial"),
&remove_noop_landing_pads::RemoveNoopLandingPads,
&cleanup_post_borrowck::CleanupNonCodegenStatements,
@@ -357,7 +455,7 @@
// These next passes must be executed together
&add_call_guards::CriticalCallEdges,
&elaborate_drops::ElaborateDrops,
- &no_landing_pads::NoLandingPads::new(tcx),
+ &no_landing_pads::NoLandingPads,
// AddMovesForPackedDrops needs to run after drop
// elaboration.
&add_moves_for_packed_drops::AddMovesForPackedDrops,
@@ -456,35 +554,32 @@
);
}
+/// Optimize the MIR and prepare it for codegen.
fn optimized_mir<'tcx>(tcx: TyCtxt<'tcx>, did: DefId) -> &'tcx Body<'tcx> {
let did = did.expect_local();
- if let Some(def) = ty::WithOptConstParam::try_lookup(did, tcx) {
- tcx.optimized_mir_of_const_arg(def)
- } else {
- tcx.arena.alloc(inner_optimized_mir(tcx, ty::WithOptConstParam::unknown(did)))
- }
+ assert_eq!(ty::WithOptConstParam::try_lookup(did, tcx), None);
+ tcx.arena.alloc(inner_optimized_mir(tcx, did))
}
-fn optimized_mir_of_const_arg<'tcx>(
- tcx: TyCtxt<'tcx>,
- (did, param_did): (LocalDefId, DefId),
-) -> &'tcx Body<'tcx> {
- tcx.arena.alloc(inner_optimized_mir(
- tcx,
- ty::WithOptConstParam { did, const_param_did: Some(param_did) },
- ))
-}
-
-fn inner_optimized_mir(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -> Body<'_> {
- if tcx.is_constructor(def.did.to_def_id()) {
+fn inner_optimized_mir(tcx: TyCtxt<'_>, did: LocalDefId) -> Body<'_> {
+ if tcx.is_constructor(did.to_def_id()) {
// There's no reason to run all of the MIR passes on constructors when
// we can just output the MIR we want directly. This also saves const
// qualification and borrow checking the trouble of special casing
// constructors.
- return shim::build_adt_ctor(tcx, def.did.to_def_id());
+ return shim::build_adt_ctor(tcx, did.to_def_id());
}
- let mut body = tcx.mir_drops_elaborated_and_const_checked(def).steal();
+ match tcx.hir().body_const_context(did) {
+ // Run the `mir_for_ctfe` query, which depends on `mir_drops_elaborated_and_const_checked`
+ // which we are going to steal below. Thus we need to run `mir_for_ctfe` first, so it
+ // computes and caches its result.
+ Some(hir::ConstContext::ConstFn) => tcx.ensure().mir_for_ctfe(did),
+ None => {}
+ Some(other) => panic!("do not use `optimized_mir` for constants: {:?}", other),
+ }
+ let mut body =
+ tcx.mir_drops_elaborated_and_const_checked(ty::WithOptConstParam::unknown(did)).steal();
run_optimization_passes(tcx, &mut body);
debug_assert!(!body.has_free_regions(), "Free regions in optimized MIR");
@@ -492,6 +587,8 @@
body
}
+/// Fetch all the promoteds of an item and prepare their MIR bodies to be ready for
+/// constant evaluation once all substitutions become known.
fn promoted_mir<'tcx>(
tcx: TyCtxt<'tcx>,
def: ty::WithOptConstParam<LocalDefId>,
@@ -510,7 +607,6 @@
for body in &mut promoted {
run_post_borrowck_cleanup_passes(tcx, body);
- run_optimization_passes(tcx, body);
}
debug_assert!(!promoted.has_free_regions(), "Free regions in promoted MIR");
diff --git a/compiler/rustc_mir/src/transform/no_landing_pads.rs b/compiler/rustc_mir/src/transform/no_landing_pads.rs
index 83954c9..5479f0c 100644
--- a/compiler/rustc_mir/src/transform/no_landing_pads.rs
+++ b/compiler/rustc_mir/src/transform/no_landing_pads.rs
@@ -2,42 +2,27 @@
//! specified.
use crate::transform::MirPass;
-use rustc_middle::mir::visit::MutVisitor;
use rustc_middle::mir::*;
use rustc_middle::ty::TyCtxt;
use rustc_target::spec::PanicStrategy;
-pub struct NoLandingPads<'tcx> {
- tcx: TyCtxt<'tcx>,
-}
+pub struct NoLandingPads;
-impl<'tcx> NoLandingPads<'tcx> {
- pub fn new(tcx: TyCtxt<'tcx>) -> Self {
- NoLandingPads { tcx }
- }
-}
-
-impl<'tcx> MirPass<'tcx> for NoLandingPads<'tcx> {
+impl<'tcx> MirPass<'tcx> for NoLandingPads {
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
no_landing_pads(tcx, body)
}
}
pub fn no_landing_pads<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
- if tcx.sess.panic_strategy() == PanicStrategy::Abort {
- NoLandingPads::new(tcx).visit_body(body);
- }
-}
-
-impl<'tcx> MutVisitor<'tcx> for NoLandingPads<'tcx> {
- fn tcx(&self) -> TyCtxt<'tcx> {
- self.tcx
+ if tcx.sess.panic_strategy() != PanicStrategy::Abort {
+ return;
}
- fn visit_terminator(&mut self, terminator: &mut Terminator<'tcx>, location: Location) {
+ for block in body.basic_blocks_mut() {
+ let terminator = block.terminator_mut();
if let Some(unwind) = terminator.kind.unwind_mut() {
unwind.take();
}
- self.super_terminator(terminator, location);
}
}
diff --git a/compiler/rustc_mir/src/transform/promote_consts.rs b/compiler/rustc_mir/src/transform/promote_consts.rs
index 8d5ed74..b4504a0 100644
--- a/compiler/rustc_mir/src/transform/promote_consts.rs
+++ b/compiler/rustc_mir/src/transform/promote_consts.rs
@@ -90,7 +90,7 @@
impl TempState {
pub fn is_promotable(&self) -> bool {
debug!("is_promotable: self={:?}", self);
- matches!(self, TempState::Defined { .. } )
+ matches!(self, TempState::Defined { .. })
}
}
@@ -102,9 +102,6 @@
/// Borrow of a constant temporary, candidate for lifetime extension.
Ref(Location),
- /// Promotion of the `x` in `[x; 32]`.
- Repeat(Location),
-
/// Currently applied to function calls where the callee has the unstable
/// `#[rustc_args_required_const]` attribute as well as the SIMD shuffle
/// intrinsic. The intrinsic requires the arguments are indeed constant and
@@ -120,14 +117,14 @@
/// Returns `true` if we should use the "explicit" rules for promotability for this `Candidate`.
fn forces_explicit_promotion(&self) -> bool {
match self {
- Candidate::Ref(_) | Candidate::Repeat(_) => false,
+ Candidate::Ref(_) => false,
Candidate::Argument { .. } | Candidate::InlineAsm { .. } => true,
}
}
fn source_info(&self, body: &Body<'_>) -> SourceInfo {
match self {
- Candidate::Ref(location) | Candidate::Repeat(location) => *body.source_info(*location),
+ Candidate::Ref(location) => *body.source_info(*location),
Candidate::Argument { bb, .. } | Candidate::InlineAsm { bb, .. } => {
*body.source_info(body.terminator_loc(*bb))
}
@@ -213,11 +210,6 @@
Rvalue::Ref(..) => {
self.candidates.push(Candidate::Ref(location));
}
- Rvalue::Repeat(..) if self.ccx.tcx.features().const_in_array_repeat_expressions => {
- // FIXME(#49147) only promote the element when it isn't `Copy`
- // (so that code that can copy it at runtime is unaffected).
- self.candidates.push(Candidate::Repeat(location));
- }
_ => {}
}
}
@@ -309,70 +301,31 @@
let statement = &self.body[loc.block].statements[loc.statement_index];
match &statement.kind {
StatementKind::Assign(box (_, Rvalue::Ref(_, kind, place))) => {
- match kind {
- BorrowKind::Shared | BorrowKind::Mut { .. } => {}
-
- // FIXME(eddyb) these aren't promoted here but *could*
- // be promoted as part of a larger value because
- // `validate_rvalue` doesn't check them, need to
- // figure out what is the intended behavior.
- BorrowKind::Shallow | BorrowKind::Unique => return Err(Unpromotable),
- }
-
// We can only promote interior borrows of promotable temps (non-temps
// don't get promoted anyway).
self.validate_local(place.local)?;
+ // The reference operation itself must be promotable.
+ // (Needs to come after `validate_local` to avoid ICEs.)
+ self.validate_ref(*kind, place)?;
+
+ // We do not check all the projections (they do not get promoted anyway),
+ // but we do stay away from promoting anything involving a dereference.
if place.projection.contains(&ProjectionElem::Deref) {
return Err(Unpromotable);
}
+
+ // We cannot promote things that need dropping, since the promoted value
+ // would not get dropped.
if self.qualif_local::<qualifs::NeedsDrop>(place.local) {
return Err(Unpromotable);
}
- // FIXME(eddyb) this duplicates part of `validate_rvalue`.
- let has_mut_interior =
- self.qualif_local::<qualifs::HasMutInterior>(place.local);
- if has_mut_interior {
- return Err(Unpromotable);
- }
-
- if let BorrowKind::Mut { .. } = kind {
- let ty = place.ty(self.body, self.tcx).ty;
-
- // In theory, any zero-sized value could be borrowed
- // mutably without consequences. However, only &mut []
- // is allowed right now.
- if let ty::Array(_, len) = ty.kind() {
- match len.try_eval_usize(self.tcx, self.param_env) {
- Some(0) => {}
- _ => return Err(Unpromotable),
- }
- } else {
- return Err(Unpromotable);
- }
- }
-
Ok(())
}
_ => bug!(),
}
}
- Candidate::Repeat(loc) => {
- assert!(!self.explicit);
-
- let statement = &self.body[loc.block].statements[loc.statement_index];
- match &statement.kind {
- StatementKind::Assign(box (_, Rvalue::Repeat(ref operand, _))) => {
- if !self.tcx.features().const_in_array_repeat_expressions {
- return Err(Unpromotable);
- }
-
- self.validate_operand(operand)
- }
- _ => bug!(),
- }
- }
Candidate::Argument { bb, index } => {
assert!(self.explicit);
@@ -439,10 +392,11 @@
// FIXME(eddyb) maybe cache this?
fn validate_local(&self, local: Local) -> Result<(), Unpromotable> {
if let TempState::Defined { location: loc, .. } = self.temps[local] {
- let num_stmts = self.body[loc.block].statements.len();
+ let block = &self.body[loc.block];
+ let num_stmts = block.statements.len();
if loc.statement_index < num_stmts {
- let statement = &self.body[loc.block].statements[loc.statement_index];
+ let statement = &block.statements[loc.statement_index];
match &statement.kind {
StatementKind::Assign(box (_, rhs)) => self.validate_rvalue(rhs),
_ => {
@@ -454,7 +408,7 @@
}
}
} else {
- let terminator = self.body[loc.block].terminator();
+ let terminator = block.terminator();
match &terminator.kind {
TerminatorKind::Call { func, args, .. } => self.validate_call(func, args),
TerminatorKind::Yield { .. } => Err(Unpromotable),
@@ -469,43 +423,43 @@
}
fn validate_place(&self, place: PlaceRef<'tcx>) -> Result<(), Unpromotable> {
- match place {
- PlaceRef { local, projection: [] } => self.validate_local(local),
- PlaceRef { local, projection: [proj_base @ .., elem] } => {
+ match place.last_projection() {
+ None => self.validate_local(place.local),
+ Some((place_base, elem)) => {
// Validate topmost projection, then recurse.
- match *elem {
+ match elem {
ProjectionElem::Deref => {
let mut promotable = false;
- // This is a special treatment for cases like *&STATIC where STATIC is a
- // global static variable.
- // This pattern is generated only when global static variables are directly
- // accessed and is qualified for promotion safely.
- if let TempState::Defined { location, .. } = self.temps[local] {
- let def_stmt =
- self.body[location.block].statements.get(location.statement_index);
- if let Some(Statement {
- kind:
- StatementKind::Assign(box (_, Rvalue::Use(Operand::Constant(c)))),
- ..
- }) = def_stmt
- {
- if let Some(did) = c.check_static_ptr(self.tcx) {
- // Evaluating a promoted may not read statics except if it got
- // promoted from a static (this is a CTFE check). So we
- // can only promote static accesses inside statics.
- if let Some(hir::ConstContext::Static(..)) = self.const_kind {
- // The `is_empty` predicate is introduced to exclude the case
- // where the projection operations are [ .field, * ].
- // The reason is because promotion will be illegal if field
- // accesses precede the dereferencing.
- // Discussion can be found at
- // https://github.com/rust-lang/rust/pull/74945#discussion_r463063247
- // There may be opportunity for generalization, but this needs to be
- // accounted for.
- if proj_base.is_empty()
- && !self.tcx.is_thread_local_static(did)
+ // We need to make sure this is a `Deref` of a local with no further projections.
+ // Discussion can be found at
+ // https://github.com/rust-lang/rust/pull/74945#discussion_r463063247
+ if let Some(local) = place_base.as_local() {
+ // This is a special treatment for cases like *&STATIC where STATIC is a
+ // global static variable.
+ // This pattern is generated only when global static variables are directly
+ // accessed and is qualified for promotion safely.
+ if let TempState::Defined { location, .. } = self.temps[local] {
+ let def_stmt = self.body[location.block]
+ .statements
+ .get(location.statement_index);
+ if let Some(Statement {
+ kind:
+ StatementKind::Assign(box (
+ _,
+ Rvalue::Use(Operand::Constant(c)),
+ )),
+ ..
+ }) = def_stmt
+ {
+ if let Some(did) = c.check_static_ptr(self.tcx) {
+ // Evaluating a promoted may not read statics except if it got
+ // promoted from a static (this is a CTFE check). So we
+ // can only promote static accesses inside statics.
+ if let Some(hir::ConstContext::Static(..)) = self.const_kind
{
- promotable = true;
+ if !self.tcx.is_thread_local_static(did) {
+ promotable = true;
+ }
}
}
}
@@ -522,12 +476,55 @@
ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } => {}
ProjectionElem::Index(local) => {
+ if !self.explicit {
+ let mut promotable = false;
+ // Only accept if we can predict the index and are indexing an array.
+ let val = if let TempState::Defined { location: loc, .. } =
+ self.temps[local]
+ {
+ let block = &self.body[loc.block];
+ if loc.statement_index < block.statements.len() {
+ let statement = &block.statements[loc.statement_index];
+ match &statement.kind {
+ StatementKind::Assign(box (
+ _,
+ Rvalue::Use(Operand::Constant(c)),
+ )) => c.literal.try_eval_usize(self.tcx, self.param_env),
+ _ => None,
+ }
+ } else {
+ None
+ }
+ } else {
+ None
+ };
+ if let Some(idx) = val {
+ // Determine the type of the thing we are indexing.
+ let ty = place_base.ty(self.body, self.tcx).ty;
+ match ty.kind() {
+ ty::Array(_, len) => {
+ // It's an array; determine its length.
+ if let Some(len) =
+ len.try_eval_usize(self.tcx, self.param_env)
+ {
+ // If the index is in-bounds, go ahead.
+ if idx < len {
+ promotable = true;
+ }
+ }
+ }
+ _ => {}
+ }
+ }
+ if !promotable {
+ return Err(Unpromotable);
+ }
+ }
self.validate_local(local)?;
}
ProjectionElem::Field(..) => {
- let base_ty =
- Place::ty_from(place.local, proj_base, self.body, self.tcx).ty;
+ let base_ty = place_base.ty(self.body, self.tcx).ty;
if let Some(def) = base_ty.ty_adt_def() {
// No promotion of union field accesses.
if def.is_union() {
@@ -537,7 +534,7 @@
}
}
- self.validate_place(PlaceRef { local: place.local, projection: proj_base })
+ self.validate_place(place_base)
}
}
}
@@ -572,117 +569,177 @@
}
}
- fn validate_rvalue(&self, rvalue: &Rvalue<'tcx>) -> Result<(), Unpromotable> {
- match *rvalue {
- Rvalue::Cast(CastKind::Misc, ref operand, cast_ty) => {
- let operand_ty = operand.ty(self.body, self.tcx);
- let cast_in = CastTy::from_ty(operand_ty).expect("bad input type for cast");
- let cast_out = CastTy::from_ty(cast_ty).expect("bad output type for cast");
- if let (CastTy::Ptr(_) | CastTy::FnPtr, CastTy::Int(_)) = (cast_in, cast_out) {
- // ptr-to-int casts are not possible in consts and thus not promotable
+ fn validate_ref(&self, kind: BorrowKind, place: &Place<'tcx>) -> Result<(), Unpromotable> {
+ match kind {
+ // Reject these borrow types just to be safe.
+ // FIXME(RalfJung): could we allow them? Should we? No point in it until we have a usecase.
+ BorrowKind::Shallow | BorrowKind::Unique => return Err(Unpromotable),
+
+ BorrowKind::Shared => {
+ let has_mut_interior = self.qualif_local::<qualifs::HasMutInterior>(place.local);
+ if has_mut_interior {
return Err(Unpromotable);
}
}
- Rvalue::BinaryOp(op, ref lhs, _) => {
- if let ty::RawPtr(_) | ty::FnPtr(..) = lhs.ty(self.body, self.tcx).kind() {
- assert!(
- op == BinOp::Eq
- || op == BinOp::Ne
- || op == BinOp::Le
- || op == BinOp::Lt
- || op == BinOp::Ge
- || op == BinOp::Gt
- || op == BinOp::Offset
- );
+ BorrowKind::Mut { .. } => {
+ let ty = place.ty(self.body, self.tcx).ty;
- // raw pointer operations are not allowed inside consts and thus not promotable
+ // In theory, any zero-sized value could be borrowed
+ // mutably without consequences. However, only &mut []
+ // is allowed right now.
+ if let ty::Array(_, len) = ty.kind() {
+ match len.try_eval_usize(self.tcx, self.param_env) {
+ Some(0) => {}
+ _ => return Err(Unpromotable),
+ }
+ } else {
return Err(Unpromotable);
}
}
-
- Rvalue::NullaryOp(NullOp::Box, _) => return Err(Unpromotable),
-
- // FIXME(RalfJung): the rest is *implicitly considered promotable*... that seems dangerous.
- _ => {}
}
+ Ok(())
+ }
+
+ fn validate_rvalue(&self, rvalue: &Rvalue<'tcx>) -> Result<(), Unpromotable> {
match rvalue {
- Rvalue::ThreadLocalRef(_) => Err(Unpromotable),
+ Rvalue::Use(operand) | Rvalue::Repeat(operand, _) => {
+ self.validate_operand(operand)?;
+ }
- Rvalue::NullaryOp(..) => Ok(()),
+ Rvalue::Discriminant(place) | Rvalue::Len(place) => {
+ self.validate_place(place.as_ref())?
+ }
- Rvalue::Discriminant(place) | Rvalue::Len(place) => self.validate_place(place.as_ref()),
+ Rvalue::ThreadLocalRef(_) => return Err(Unpromotable),
- Rvalue::Use(operand)
- | Rvalue::Repeat(operand, _)
- | Rvalue::UnaryOp(_, operand)
- | Rvalue::Cast(_, operand, _) => self.validate_operand(operand),
+ Rvalue::Cast(kind, operand, cast_ty) => {
+ if matches!(kind, CastKind::Misc) {
+ let operand_ty = operand.ty(self.body, self.tcx);
+ let cast_in = CastTy::from_ty(operand_ty).expect("bad input type for cast");
+ let cast_out = CastTy::from_ty(cast_ty).expect("bad output type for cast");
+ if let (CastTy::Ptr(_) | CastTy::FnPtr, CastTy::Int(_)) = (cast_in, cast_out) {
+ // ptr-to-int casts are not possible in consts and thus not promotable
+ return Err(Unpromotable);
+ }
+ // int-to-ptr casts are fine, they just use the integer value at pointer type.
+ }
- Rvalue::BinaryOp(_, lhs, rhs) | Rvalue::CheckedBinaryOp(_, lhs, rhs) => {
+ self.validate_operand(operand)?;
+ }
+
+ Rvalue::NullaryOp(op, _) => match op {
+ NullOp::Box => return Err(Unpromotable),
+ NullOp::SizeOf => {}
+ },
+
+ Rvalue::UnaryOp(op, operand) => {
+ match op {
+ // These operations can never fail.
+ UnOp::Neg | UnOp::Not => {}
+ }
+
+ self.validate_operand(operand)?;
+ }
+
+ Rvalue::BinaryOp(op, lhs, rhs) | Rvalue::CheckedBinaryOp(op, lhs, rhs) => {
+ let op = *op;
+ let lhs_ty = lhs.ty(self.body, self.tcx);
+
+ if let ty::RawPtr(_) | ty::FnPtr(..) = lhs_ty.kind() {
+ // Raw and fn pointer operations are not allowed inside consts and thus not promotable.
+ assert!(matches!(
+ op,
+ BinOp::Eq
+ | BinOp::Ne
+ | BinOp::Le
+ | BinOp::Lt
+ | BinOp::Ge
+ | BinOp::Gt
+ | BinOp::Offset
+ ));
+ return Err(Unpromotable);
+ }
+
+ match op {
+ BinOp::Div | BinOp::Rem => {
+ if !self.explicit && lhs_ty.is_integral() {
+ // Integer division: the RHS must be a non-zero const.
+ let const_val = match rhs {
+ Operand::Constant(c) => {
+ c.literal.try_eval_bits(self.tcx, self.param_env, lhs_ty)
+ }
+ _ => None,
+ };
+ match const_val {
+ Some(x) if x != 0 => {} // okay
+ _ => return Err(Unpromotable), // value not known or 0 -- not okay
+ }
+ }
+ }
+ // The remaining operations can never fail.
+ BinOp::Eq
+ | BinOp::Ne
+ | BinOp::Le
+ | BinOp::Lt
+ | BinOp::Ge
+ | BinOp::Gt
+ | BinOp::Offset
+ | BinOp::Add
+ | BinOp::Sub
+ | BinOp::Mul
+ | BinOp::BitXor
+ | BinOp::BitAnd
+ | BinOp::BitOr
+ | BinOp::Shl
+ | BinOp::Shr => {}
+ }
+
self.validate_operand(lhs)?;
- self.validate_operand(rhs)
+ self.validate_operand(rhs)?;
}
Rvalue::AddressOf(_, place) => {
// We accept `&raw *`, i.e., raw reborrows -- creating a raw pointer is
// no problem, only using it is.
- if let [proj_base @ .., ProjectionElem::Deref] = place.projection.as_ref() {
- let base_ty = Place::ty_from(place.local, proj_base, self.body, self.tcx).ty;
+ if let Some((place_base, ProjectionElem::Deref)) = place.as_ref().last_projection()
+ {
+ let base_ty = place_base.ty(self.body, self.tcx).ty;
if let ty::Ref(..) = base_ty.kind() {
- return self.validate_place(PlaceRef {
- local: place.local,
- projection: proj_base,
- });
+ return self.validate_place(place_base);
}
}
- Err(Unpromotable)
+ return Err(Unpromotable);
}
Rvalue::Ref(_, kind, place) => {
- if let BorrowKind::Mut { .. } = kind {
- let ty = place.ty(self.body, self.tcx).ty;
-
- // In theory, any zero-sized value could be borrowed
- // mutably without consequences. However, only &mut []
- // is allowed right now.
- if let ty::Array(_, len) = ty.kind() {
- match len.try_eval_usize(self.tcx, self.param_env) {
- Some(0) => {}
- _ => return Err(Unpromotable),
- }
- } else {
- return Err(Unpromotable);
- }
- }
-
// Special-case reborrows to be more like a copy of the reference.
- let mut place = place.as_ref();
- if let [proj_base @ .., ProjectionElem::Deref] = &place.projection {
- let base_ty = Place::ty_from(place.local, proj_base, self.body, self.tcx).ty;
+ let mut place_simplified = place.as_ref();
+ if let Some((place_base, ProjectionElem::Deref)) =
+ place_simplified.last_projection()
+ {
+ let base_ty = place_base.ty(self.body, self.tcx).ty;
if let ty::Ref(..) = base_ty.kind() {
- place = PlaceRef { local: place.local, projection: proj_base };
+ place_simplified = place_base;
}
}
- self.validate_place(place)?;
+ self.validate_place(place_simplified)?;
- let has_mut_interior = self.qualif_local::<qualifs::HasMutInterior>(place.local);
- if has_mut_interior {
- return Err(Unpromotable);
- }
-
- Ok(())
+ // Check that the reference is fine (using the original place!).
+ // (Needs to come after `validate_place` to avoid ICEs.)
+ self.validate_ref(*kind, place)?;
}
- Rvalue::Aggregate(_, ref operands) => {
+ Rvalue::Aggregate(_, operands) => {
for o in operands {
self.validate_operand(o)?;
}
-
- Ok(())
}
}
+
+ Ok(())
}
fn validate_call(
@@ -1010,18 +1067,6 @@
_ => bug!(),
}
}
- Candidate::Repeat(loc) => {
- let statement = &mut blocks[loc.block].statements[loc.statement_index];
- match statement.kind {
- StatementKind::Assign(box (_, Rvalue::Repeat(ref mut operand, _))) => {
- let ty = operand.ty(local_decls, self.tcx);
- let span = statement.source_info.span;
-
- Rvalue::Use(mem::replace(operand, promoted_operand(ty, span)))
- }
- _ => bug!(),
- }
- }
Candidate::Argument { bb, index } => {
let terminator = blocks[bb].terminator_mut();
match terminator.kind {
@@ -1102,8 +1147,7 @@
let mut extra_statements = vec![];
for candidate in candidates.into_iter().rev() {
match candidate {
- Candidate::Repeat(Location { block, statement_index })
- | Candidate::Ref(Location { block, statement_index }) => {
+ Candidate::Ref(Location { block, statement_index }) => {
if let StatementKind::Assign(box (place, _)) =
&body[block].statements[statement_index].kind
{
@@ -1187,27 +1231,3 @@
promotions
}
-
-/// This function returns `true` if the `const_in_array_repeat_expressions` feature attribute should
-/// be suggested. This function is probably quite expensive, it shouldn't be run in the happy path.
-/// Feature attribute should be suggested if `operand` can be promoted and the feature is not
-/// enabled.
-crate fn should_suggest_const_in_array_repeat_expressions_attribute<'tcx>(
- ccx: &ConstCx<'_, 'tcx>,
- operand: &Operand<'tcx>,
-) -> bool {
- let mut rpo = traversal::reverse_postorder(&ccx.body);
- let (temps, _) = collect_temps_and_candidates(&ccx, &mut rpo);
- let validator = Validator { ccx, temps: &temps, explicit: false };
-
- let should_promote = validator.validate_operand(operand).is_ok();
- let feature_flag = validator.ccx.tcx.features().const_in_array_repeat_expressions;
- debug!(
- "should_suggest_const_in_array_repeat_expressions_flag: def_id={:?} \
- should_promote={:?} feature_flag={:?}",
- validator.ccx.def_id(),
- should_promote,
- feature_flag
- );
- should_promote && !feature_flag
-}
diff --git a/compiler/rustc_mir/src/transform/remove_unneeded_drops.rs b/compiler/rustc_mir/src/transform/remove_unneeded_drops.rs
index 221114e..5144d48 100644
--- a/compiler/rustc_mir/src/transform/remove_unneeded_drops.rs
+++ b/compiler/rustc_mir/src/transform/remove_unneeded_drops.rs
@@ -1,9 +1,8 @@
//! This pass replaces a drop of a type that does not need dropping, with a goto
use crate::transform::MirPass;
-use rustc_middle::mir::visit::Visitor;
use rustc_middle::mir::*;
-use rustc_middle::ty::{ParamEnv, TyCtxt};
+use rustc_middle::ty::TyCtxt;
use super::simplify::simplify_cfg;
@@ -12,24 +11,26 @@
impl<'tcx> MirPass<'tcx> for RemoveUnneededDrops {
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
trace!("Running RemoveUnneededDrops on {:?}", body.source);
- let mut opt_finder = RemoveUnneededDropsOptimizationFinder {
- tcx,
- body,
- param_env: tcx.param_env(body.source.def_id()),
- optimizations: vec![],
- };
- opt_finder.visit_body(body);
- let should_simplify = !opt_finder.optimizations.is_empty();
- for (loc, target) in opt_finder.optimizations {
- if !tcx
- .consider_optimizing(|| format!("RemoveUnneededDrops {:?} ", body.source.def_id()))
- {
- break;
- }
- let terminator = body.basic_blocks_mut()[loc.block].terminator_mut();
- debug!("SUCCESS: replacing `drop` with goto({:?})", target);
- terminator.kind = TerminatorKind::Goto { target };
+ let did = body.source.def_id();
+ let param_env = tcx.param_env(did);
+ let mut should_simplify = false;
+
+ let (basic_blocks, local_decls) = body.basic_blocks_and_local_decls_mut();
+ for block in basic_blocks {
+ let terminator = block.terminator_mut();
+ if let TerminatorKind::Drop { place, target, .. } = terminator.kind {
+ let ty = place.ty(local_decls, tcx);
+ if ty.ty.needs_drop(tcx, param_env) {
+ continue;
+ }
+ if !tcx.consider_optimizing(|| format!("RemoveUnneededDrops {:?} ", did)) {
+ continue;
+ }
+ debug!("SUCCESS: replacing `drop` with goto({:?})", target);
+ terminator.kind = TerminatorKind::Goto { target };
+ should_simplify = true;
+ }
}
// if we applied optimizations, we potentially have some cfg to cleanup to
@@ -39,25 +40,3 @@
}
}
}
-
-impl<'a, 'tcx> Visitor<'tcx> for RemoveUnneededDropsOptimizationFinder<'a, 'tcx> {
- fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) {
- match terminator.kind {
- TerminatorKind::Drop { place, target, .. } => {
- let ty = place.ty(self.body, self.tcx);
- let needs_drop = ty.ty.needs_drop(self.tcx, self.param_env);
- if !needs_drop {
- self.optimizations.push((location, target));
- }
- }
- _ => {}
- }
- self.super_terminator(terminator, location);
- }
-}
-pub struct RemoveUnneededDropsOptimizationFinder<'a, 'tcx> {
- tcx: TyCtxt<'tcx>,
- body: &'a Body<'tcx>,
- optimizations: Vec<(Location, BasicBlock)>,
- param_env: ParamEnv<'tcx>,
-}
diff --git a/compiler/rustc_mir/src/transform/rustc_peek.rs b/compiler/rustc_mir/src/transform/rustc_peek.rs
index 205f718d..7598be4 100644
--- a/compiler/rustc_mir/src/transform/rustc_peek.rs
+++ b/compiler/rustc_mir/src/transform/rustc_peek.rs
@@ -92,7 +92,7 @@
/// "rustc_peek: bit not set".
///
/// The intention is that one can write unit tests for dataflow by
-/// putting code into a compile-fail test and using `rustc_peek` to
+/// putting code into an UI test and using `rustc_peek` to
/// make observations about the results of dataflow static analyses.
///
/// (If there are any calls to `rustc_peek` that do not match the
diff --git a/compiler/rustc_mir/src/transform/simplify.rs b/compiler/rustc_mir/src/transform/simplify.rs
index b7c9a3a..11539d3 100644
--- a/compiler/rustc_mir/src/transform/simplify.rs
+++ b/compiler/rustc_mir/src/transform/simplify.rs
@@ -28,7 +28,6 @@
//! return.
use crate::transform::MirPass;
-use rustc_index::bit_set::BitSet;
use rustc_index::vec::{Idx, IndexVec};
use rustc_middle::mir::visit::{MutVisitor, MutatingUseContext, PlaceContext, Visitor};
use rustc_middle::mir::*;
@@ -61,7 +60,7 @@
}
fn run_pass(&self, _tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
- debug!("SimplifyCfg({:?}) - simplifying {:?}", self.label, body);
+ debug!("SimplifyCfg({:?}) - simplifying {:?}", self.label, body.source);
simplify_cfg(body);
}
}
@@ -288,17 +287,17 @@
}
pub fn remove_dead_blocks(body: &mut Body<'_>) {
- let mut seen = BitSet::new_empty(body.basic_blocks().len());
- for (bb, _) in traversal::preorder(body) {
- seen.insert(bb.index());
+ let reachable = traversal::reachable_as_bitset(body);
+ let num_blocks = body.basic_blocks().len();
+ if num_blocks == reachable.count() {
+ return;
}
let basic_blocks = body.basic_blocks_mut();
-
- let num_blocks = basic_blocks.len();
let mut replacements: Vec<_> = (0..num_blocks).map(BasicBlock::new).collect();
let mut used_blocks = 0;
- for alive_index in seen.iter() {
+ for alive_index in reachable.iter() {
+ let alive_index = alive_index.index();
replacements[alive_index] = BasicBlock::new(used_blocks);
if alive_index != used_blocks {
// Swap the next alive block data with the current available slot. Since
diff --git a/compiler/rustc_mir/src/transform/simplify_try.rs b/compiler/rustc_mir/src/transform/simplify_try.rs
index a345988..05a8882 100644
--- a/compiler/rustc_mir/src/transform/simplify_try.rs
+++ b/compiler/rustc_mir/src/transform/simplify_try.rs
@@ -113,7 +113,7 @@
test: impl Fn(&'a Statement<'tcx>) -> bool,
mut action: impl FnMut(usize, &'a Statement<'tcx>),
) {
- while stmt_iter.peek().map(|(_, stmt)| test(stmt)).unwrap_or(false) {
+ while stmt_iter.peek().map_or(false, |(_, stmt)| test(stmt)) {
let (idx, stmt) = stmt_iter.next().unwrap();
action(idx, stmt);
@@ -635,7 +635,7 @@
})
.peekable();
- let bb_first = iter_bbs_reachable.peek().map(|(idx, _)| *idx).unwrap_or(&targets_and_values[0]);
+ let bb_first = iter_bbs_reachable.peek().map_or(&targets_and_values[0], |(idx, _)| *idx);
let mut all_successors_equivalent = StatementEquality::TrivialEqual;
// All successor basic blocks must be equal or contain statements that are pairwise considered equal.
diff --git a/compiler/rustc_mir/src/util/alignment.rs b/compiler/rustc_mir/src/util/alignment.rs
index a0728a6..f567c9c 100644
--- a/compiler/rustc_mir/src/util/alignment.rs
+++ b/compiler/rustc_mir/src/util/alignment.rs
@@ -38,15 +38,12 @@
where
L: HasLocalDecls<'tcx>,
{
- let mut cursor = place.projection.as_ref();
- while let &[ref proj_base @ .., elem] = cursor {
- cursor = proj_base;
-
+ for (place_base, elem) in place.iter_projections().rev() {
match elem {
// encountered a Deref, which is ABI-aligned
ProjectionElem::Deref => break,
ProjectionElem::Field(..) => {
- let ty = Place::ty_from(place.local, proj_base, local_decls, tcx).ty;
+ let ty = place_base.ty(local_decls, tcx).ty;
match ty.kind() {
ty::Adt(def, _) if def.repr.packed() => return true,
_ => {}
diff --git a/compiler/rustc_mir/src/util/pretty.rs b/compiler/rustc_mir/src/util/pretty.rs
index 89ce29b..7fc1c3a 100644
--- a/compiler/rustc_mir/src/util/pretty.rs
+++ b/compiler/rustc_mir/src/util/pretty.rs
@@ -273,8 +273,6 @@
let mut first = true;
for def_id in dump_mir_def_ids(tcx, single) {
- let body = &tcx.optimized_mir(def_id);
-
if first {
first = false;
} else {
@@ -282,11 +280,28 @@
writeln!(w)?;
}
- write_mir_fn(tcx, body, &mut |_, _| Ok(()), w)?;
-
- for body in tcx.promoted_mir(def_id) {
- writeln!(w)?;
+ let render_body = |w: &mut dyn Write, body| -> io::Result<()> {
write_mir_fn(tcx, body, &mut |_, _| Ok(()), w)?;
+
+ for body in tcx.promoted_mir(def_id) {
+ writeln!(w)?;
+ write_mir_fn(tcx, body, &mut |_, _| Ok(()), w)?;
+ }
+ Ok(())
+ };
+ match tcx.hir().body_const_context(def_id.expect_local()) {
+ None => render_body(w, tcx.optimized_mir(def_id))?,
+ // For `const fn` we want to render the optimized MIR. If you want the mir used in
+ // ctfe, you can dump the MIR after the `Deaggregator` optimization pass.
+ Some(rustc_hir::ConstContext::ConstFn) => {
+ render_body(w, tcx.optimized_mir(def_id))?;
+ writeln!(w)?;
+ writeln!(w, "// MIR FOR CTFE")?;
+ // Do not use `render_body`, as that would render the promoteds again, but these
+ // are shared between mir_for_ctfe and optimized_mir
+ write_mir_fn(tcx, tcx.mir_for_ctfe(def_id), &mut |_, _| Ok(()), w)?;
+ }
+ Some(_) => render_body(w, tcx.mir_for_ctfe(def_id))?,
}
}
Ok(())
diff --git a/compiler/rustc_mir/src/util/storage.rs b/compiler/rustc_mir/src/util/storage.rs
index 0b7b1c2..4e1696c 100644
--- a/compiler/rustc_mir/src/util/storage.rs
+++ b/compiler/rustc_mir/src/util/storage.rs
@@ -1,6 +1,5 @@
use rustc_index::bit_set::BitSet;
-use rustc_middle::mir::visit::Visitor;
-use rustc_middle::mir::{self, Local, Location};
+use rustc_middle::mir::{self, Local};
/// The set of locals in a MIR body that do not have `StorageLive`/`StorageDead` annotations.
///
@@ -13,12 +12,18 @@
impl AlwaysLiveLocals {
pub fn new(body: &mir::Body<'tcx>) -> Self {
- let mut ret = AlwaysLiveLocals(BitSet::new_filled(body.local_decls.len()));
+ let mut always_live_locals = AlwaysLiveLocals(BitSet::new_filled(body.local_decls.len()));
- let mut vis = StorageAnnotationVisitor(&mut ret);
- vis.visit_body(body);
+ for block in body.basic_blocks() {
+ for statement in &block.statements {
+ use mir::StatementKind::{StorageDead, StorageLive};
+ if let StorageLive(l) | StorageDead(l) = statement.kind {
+ always_live_locals.0.remove(l);
+ }
+ }
+ }
- ret
+ always_live_locals
}
pub fn into_inner(self) -> BitSet<Local> {
@@ -33,15 +38,3 @@
&self.0
}
}
-
-/// Removes locals that have `Storage*` annotations from `AlwaysLiveLocals`.
-struct StorageAnnotationVisitor<'a>(&'a mut AlwaysLiveLocals);
-
-impl Visitor<'tcx> for StorageAnnotationVisitor<'_> {
- fn visit_statement(&mut self, statement: &mir::Statement<'tcx>, _location: Location) {
- use mir::StatementKind::{StorageDead, StorageLive};
- if let StorageLive(l) | StorageDead(l) = statement.kind {
- (self.0).0.remove(l);
- }
- }
-}
diff --git a/compiler/rustc_mir_build/src/build/expr/as_place.rs b/compiler/rustc_mir_build/src/build/expr/as_place.rs
index e1a3dc8..3308a24 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_place.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_place.rs
@@ -6,8 +6,8 @@
use crate::thir::*;
use rustc_hir::def_id::DefId;
use rustc_hir::HirId;
-use rustc_middle::middle::region;
use rustc_middle::hir::place::ProjectionKind as HirProjectionKind;
+use rustc_middle::middle::region;
use rustc_middle::mir::AssertKind::BoundsCheck;
use rustc_middle::mir::*;
use rustc_middle::ty::{self, CanonicalUserTypeAnnotation, Ty, TyCtxt, Variance};
@@ -57,7 +57,8 @@
/// DefId of the closure
closure_def_id: DefId,
/// The trait closure implements, `Fn`, `FnMut`, `FnOnce`
- closure_kind: ty::ClosureKind },
+ closure_kind: ty::ClosureKind,
+ },
}
/// `PlaceBuilder` is used to create places during MIR construction. It allows you to "build up" a
@@ -79,10 +80,9 @@
/// part of a path that is captued by a closure. We stop applying projections once we see the first
/// projection that isn't captured by a closure.
fn convert_to_hir_projections_and_truncate_for_capture<'tcx>(
- mir_projections: &Vec<PlaceElem<'tcx>>,
+ mir_projections: &[PlaceElem<'tcx>],
) -> Vec<HirProjectionKind> {
-
- let mut hir_projections = Vec::new();
+ let mut hir_projections = Vec::new();
for mir_projection in mir_projections {
let hir_projection = match mir_projection {
@@ -91,20 +91,20 @@
// We will never encouter this for multivariant enums,
// read the comment for `Downcast`.
HirProjectionKind::Field(field.index() as u32, VariantIdx::new(0))
- },
+ }
ProjectionElem::Downcast(..) => {
// This projections exist only for enums that have
// multiple variants. Since such enums that are captured
// completely, we can stop here.
- break
- },
+ break;
+ }
ProjectionElem::Index(..)
| ProjectionElem::ConstantIndex { .. }
| ProjectionElem::Subslice { .. } => {
// We don't capture array-access projections.
// We can stop here as arrays are captured completely.
- break
- },
+ break;
+ }
};
hir_projections.push(hir_projection);
@@ -128,7 +128,7 @@
/// list are being applied to the same root variable.
fn is_ancestor_or_same_capture(
proj_possible_ancestor: &Vec<HirProjectionKind>,
- proj_capture: &Vec<HirProjectionKind>,
+ proj_capture: &[HirProjectionKind],
) -> bool {
// We want to make sure `is_ancestor_or_same_capture("x.0.0", "x.0")` to return false.
// Therefore we can't just check if all projections are same in the zipped iterator below.
@@ -171,7 +171,7 @@
typeck_results: &'a ty::TypeckResults<'tcx>,
var_hir_id: HirId,
closure_def_id: DefId,
- projections: &Vec<PlaceElem<'tcx>>,
+ projections: &[PlaceElem<'tcx>],
) -> Option<(usize, &'a ty::CapturedPlace<'tcx>)> {
let closure_min_captures = typeck_results.closure_min_captures.get(&closure_def_id)?;
let root_variable_min_captures = closure_min_captures.get(&var_hir_id)?;
@@ -181,9 +181,9 @@
// If an ancestor is found, `idx` is the index within the list of captured places
// for root variable `var_hir_id` and `capture` is the `ty::CapturedPlace` itself.
let (idx, capture) = root_variable_min_captures.iter().enumerate().find(|(_, capture)| {
- let possible_ancestor_proj_kinds =
- capture.place.projections.iter().map(|proj| proj.kind).collect();
- is_ancestor_or_same_capture(&possible_ancestor_proj_kinds, &hir_projections)
+ let possible_ancestor_proj_kinds =
+ capture.place.projections.iter().map(|proj| proj.kind).collect();
+ is_ancestor_or_same_capture(&possible_ancestor_proj_kinds, &hir_projections)
})?;
// Convert index to be from the presepective of the entire closure_min_captures map
@@ -213,35 +213,34 @@
ty::ClosureKind::FnOnce => {}
}
- let (capture_index, capture) =
- if let Some(capture_details) = find_capture_matching_projections(
+ let (capture_index, capture) = if let Some(capture_details) =
+ find_capture_matching_projections(
typeck_results,
var_hir_id,
closure_def_id,
&from_builder.projection,
) {
- capture_details
- } else {
- if !tcx.features().capture_disjoint_fields {
- bug!(
- "No associated capture found for {:?}[{:#?}] even though \
+ capture_details
+ } else {
+ if !tcx.features().capture_disjoint_fields {
+ bug!(
+ "No associated capture found for {:?}[{:#?}] even though \
capture_disjoint_fields isn't enabled",
- var_hir_id,
- from_builder.projection
- )
- } else {
- // FIXME(project-rfc-2229#24): Handle this case properly
- debug!(
- "No associated capture found for {:?}[{:#?}]",
- var_hir_id,
- from_builder.projection,
- );
- }
- return Err(var_hir_id);
- };
+ var_hir_id,
+ from_builder.projection
+ )
+ } else {
+ // FIXME(project-rfc-2229#24): Handle this case properly
+ debug!(
+ "No associated capture found for {:?}[{:#?}]",
+ var_hir_id, from_builder.projection,
+ );
+ }
+ return Err(var_hir_id);
+ };
- let closure_ty =
- typeck_results.node_type(tcx.hir().local_def_id_to_hir_id(closure_def_id.expect_local()));
+ let closure_ty = typeck_results
+ .node_type(tcx.hir().local_def_id_to_hir_id(closure_def_id.expect_local()));
let substs = match closure_ty.kind() {
ty::Closure(_, substs) => ty::UpvarSubsts::Closure(substs),
@@ -256,7 +255,8 @@
// we know that the capture exists and is the `capture_index`-th capture.
let var_ty = substs.tupled_upvars_ty().tuple_element_ty(capture_index).unwrap();
- upvar_resolved_place_builder = upvar_resolved_place_builder.field(Field::new(capture_index), var_ty);
+ upvar_resolved_place_builder =
+ upvar_resolved_place_builder.field(Field::new(capture_index), var_ty);
// If the variable is captured via ByRef(Immutable/Mutable) Borrow,
// we need to deref it
@@ -270,8 +270,9 @@
// We used some of the projections to build the capture itself,
// now we apply the remaining to the upvar resolved place.
- upvar_resolved_place_builder.projection.extend(
- curr_projections.drain(next_projection..));
+ upvar_resolved_place_builder
+ .projection
+ .extend(curr_projections.drain(next_projection..));
Ok(upvar_resolved_place_builder)
}
@@ -303,7 +304,7 @@
self.base
}
- fn field(self, f: Field, ty: Ty<'tcx>) -> Self {
+ crate fn field(self, f: Field, ty: Ty<'tcx>) -> Self {
self.project(PlaceElem::Field(f, ty))
}
@@ -356,7 +357,11 @@
/// This is used when constructing a compound `Place`, so that we can avoid creating
/// intermediate `Place` values until we know the full set of projections.
- crate fn as_place_builder<M>(&mut self, block: BasicBlock, expr: M) -> BlockAnd<PlaceBuilder<'tcx>>
+ crate fn as_place_builder<M>(
+ &mut self,
+ block: BasicBlock,
+ expr: M,
+ ) -> BlockAnd<PlaceBuilder<'tcx>>
where
M: Mirror<'tcx, Output = Expr<'tcx>>,
{
@@ -531,6 +536,7 @@
| ExprKind::Borrow { .. }
| ExprKind::AddressOf { .. }
| ExprKind::Match { .. }
+ | ExprKind::If { .. }
| ExprKind::Loop { .. }
| ExprKind::Block { .. }
| ExprKind::Assign { .. }
@@ -626,7 +632,8 @@
if is_outermost_index {
self.read_fake_borrows(block, fake_borrow_temps, source_info)
} else {
- base_place = base_place.expect_upvars_resolved(self.hir.tcx(), self.hir.typeck_results());
+ base_place =
+ base_place.expect_upvars_resolved(self.hir.tcx(), self.hir.typeck_results());
self.add_fake_borrows_of_base(
&base_place,
block,
@@ -678,7 +685,7 @@
let tcx = self.hir.tcx();
let local = match base_place.base {
PlaceBase::Local(local) => local,
- PlaceBase::Upvar { .. } => bug!("Expected PlacseBase::Local found Upvar")
+ PlaceBase::Upvar { .. } => bug!("Expected PlacseBase::Local found Upvar"),
};
let place_ty = Place::ty_from(local, &base_place.projection, &self.local_decls, tcx);
diff --git a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
index 581d842..e602f4d 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
@@ -2,9 +2,9 @@
use rustc_index::vec::Idx;
+use crate::build::expr::as_place::PlaceBase;
use crate::build::expr::category::{Category, RvalueFunc};
use crate::build::{BlockAnd, BlockAndExtension, Builder};
-use crate::build::expr::as_place::PlaceBase;
use crate::thir::*;
use rustc_middle::middle::region;
use rustc_middle::mir::AssertKind;
@@ -239,6 +239,7 @@
| ExprKind::StaticRef { .. }
| ExprKind::Block { .. }
| ExprKind::Match { .. }
+ | ExprKind::If { .. }
| ExprKind::NeverToAny { .. }
| ExprKind::Use { .. }
| ExprKind::Borrow { .. }
@@ -261,7 +262,10 @@
| ExprKind::ValueTypeAscription { .. } => {
// these do not have corresponding `Rvalue` variants,
// so make an operand and then return that
- debug_assert!(!matches!(Category::of(&expr.kind), Some(Category::Rvalue(RvalueFunc::AsRvalue))));
+ debug_assert!(!matches!(
+ Category::of(&expr.kind),
+ Some(Category::Rvalue(RvalueFunc::AsRvalue))
+ ));
let operand = unpack!(block = this.as_operand(block, scope, expr));
block.and(Rvalue::Use(operand))
}
@@ -388,34 +392,39 @@
// We are capturing a path that starts off a local variable in the parent.
// The mutability of the current capture is same as the mutability
// of the local declaration in the parent.
- PlaceBase::Local(local) => this.local_decls[local].mutability,
+ PlaceBase::Local(local) => this.local_decls[local].mutability,
// Parent is a closure and we are capturing a path that is captured
// by the parent itself. The mutability of the current capture
// is same as that of the capture in the parent closure.
PlaceBase::Upvar { .. } => {
- let enclosing_upvars_resolved = arg_place_builder.clone().into_place(
- this.hir.tcx(),
- this.hir.typeck_results());
+ let enclosing_upvars_resolved =
+ arg_place_builder.clone().into_place(this.hir.tcx(), this.hir.typeck_results());
match enclosing_upvars_resolved.as_ref() {
- PlaceRef { local, projection: &[ProjectionElem::Field(upvar_index, _), ..] }
+ PlaceRef {
+ local,
+ projection: &[ProjectionElem::Field(upvar_index, _), ..],
+ }
| PlaceRef {
local,
- projection: &[ProjectionElem::Deref, ProjectionElem::Field(upvar_index, _), ..] } => {
- // Not in a closure
- debug_assert!(
- local == Local::new(1),
- "Expected local to be Local(1), found {:?}",
- local
- );
- // Not in a closure
- debug_assert!(
- this.upvar_mutbls.len() > upvar_index.index(),
- "Unexpected capture place, upvar_mutbls={:#?}, upvar_index={:?}",
- this.upvar_mutbls, upvar_index
- );
- this.upvar_mutbls[upvar_index.index()]
- }
+ projection:
+ &[ProjectionElem::Deref, ProjectionElem::Field(upvar_index, _), ..],
+ } => {
+ // Not in a closure
+ debug_assert!(
+ local == Local::new(1),
+ "Expected local to be Local(1), found {:?}",
+ local
+ );
+ // Not in a closure
+ debug_assert!(
+ this.upvar_mutbls.len() > upvar_index.index(),
+ "Unexpected capture place, upvar_mutbls={:#?}, upvar_index={:?}",
+ this.upvar_mutbls,
+ upvar_index
+ );
+ this.upvar_mutbls[upvar_index.index()]
+ }
_ => bug!("Unexpected capture place"),
}
}
@@ -426,9 +435,7 @@
Mutability::Mut => BorrowKind::Mut { allow_two_phase_borrow: false },
};
- let arg_place = arg_place_builder.into_place(
- this.hir.tcx(),
- this.hir.typeck_results());
+ let arg_place = arg_place_builder.into_place(this.hir.tcx(), this.hir.typeck_results());
this.cfg.push_assign(
block,
diff --git a/compiler/rustc_mir_build/src/build/expr/category.rs b/compiler/rustc_mir_build/src/build/expr/category.rs
index 8561170..9320b58 100644
--- a/compiler/rustc_mir_build/src/build/expr/category.rs
+++ b/compiler/rustc_mir_build/src/build/expr/category.rs
@@ -45,6 +45,7 @@
ExprKind::LogicalOp { .. }
| ExprKind::Match { .. }
+ | ExprKind::If { .. }
| ExprKind::NeverToAny { .. }
| ExprKind::Use { .. }
| ExprKind::Adt { .. }
diff --git a/compiler/rustc_mir_build/src/build/expr/into.rs b/compiler/rustc_mir_build/src/build/expr/into.rs
index a86e4cb..235fe14 100644
--- a/compiler/rustc_mir_build/src/build/expr/into.rs
+++ b/compiler/rustc_mir_build/src/build/expr/into.rs
@@ -8,9 +8,7 @@
use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_hir as hir;
use rustc_middle::mir::*;
-use rustc_middle::ty::{self, CanonicalUserTypeAnnotation};
-use rustc_span::symbol::sym;
-use rustc_target::spec::abi::Abi;
+use rustc_middle::ty::CanonicalUserTypeAnnotation;
impl<'a, 'tcx> Builder<'a, 'tcx> {
/// Compile `expr`, storing the result into `destination`, which
@@ -30,11 +28,8 @@
let expr_span = expr.span;
let source_info = this.source_info(expr_span);
- let expr_is_block_or_scope = match expr.kind {
- ExprKind::Block { .. } => true,
- ExprKind::Scope { .. } => true,
- _ => false,
- };
+ let expr_is_block_or_scope =
+ matches!(expr.kind, ExprKind::Block { .. } | ExprKind::Scope { .. });
if !expr_is_block_or_scope {
this.block_context.push(BlockFrame::SubExpr);
@@ -55,13 +50,52 @@
ExprKind::Match { scrutinee, arms } => {
this.match_expr(destination, expr_span, block, scrutinee, arms)
}
+ ExprKind::If { cond, then, else_opt } => {
+ let place = unpack!(
+ block = this.as_temp(block, Some(this.local_scope()), cond, Mutability::Mut)
+ );
+ let operand = Operand::Move(Place::from(place));
+
+ let mut then_block = this.cfg.start_new_block();
+ let mut else_block = this.cfg.start_new_block();
+ let term = TerminatorKind::if_(this.hir.tcx(), operand, then_block, else_block);
+ this.cfg.terminate(block, source_info, term);
+
+ unpack!(then_block = this.into(destination, then_block, then));
+ else_block = if let Some(else_opt) = else_opt {
+ unpack!(this.into(destination, else_block, else_opt))
+ } else {
+ // Body of the `if` expression without an `else` clause must return `()`, thus
+ // we implicitly generate a `else {}` if it is not specified.
+ let correct_si = this.source_info(expr_span.shrink_to_hi());
+ this.cfg.push_assign_unit(else_block, correct_si, destination, this.hir.tcx());
+ else_block
+ };
+
+ let join_block = this.cfg.start_new_block();
+ this.cfg.terminate(
+ then_block,
+ source_info,
+ TerminatorKind::Goto { target: join_block },
+ );
+ this.cfg.terminate(
+ else_block,
+ source_info,
+ TerminatorKind::Goto { target: join_block },
+ );
+
+ join_block.unit()
+ }
ExprKind::NeverToAny { source } => {
let source = this.hir.mirror(source);
- let is_call = matches!(source.kind, ExprKind::Call { .. } | ExprKind::InlineAsm { .. });
+ let is_call =
+ matches!(source.kind, ExprKind::Call { .. } | ExprKind::InlineAsm { .. });
// (#66975) Source could be a const of type `!`, so has to
// exist in the generated MIR.
- unpack!(block = this.as_temp(block, Some(this.local_scope()), source, Mutability::Mut,));
+ unpack!(
+ block = this.as_temp(block, Some(this.local_scope()), source, Mutability::Mut,)
+ );
// This is an optimization. If the expression was a call then we already have an
// unreachable block. Don't bother to terminate it and create a new one.
@@ -161,78 +195,40 @@
None
})
}
- ExprKind::Call { ty, fun, args, from_hir_call, fn_span } => {
- let intrinsic = match *ty.kind() {
- ty::FnDef(def_id, _) => {
- let f = ty.fn_sig(this.hir.tcx());
- if f.abi() == Abi::RustIntrinsic || f.abi() == Abi::PlatformIntrinsic {
- Some(this.hir.tcx().item_name(def_id))
- } else {
- None
- }
- }
- _ => None,
- };
+ ExprKind::Call { ty: _, fun, args, from_hir_call, fn_span } => {
let fun = unpack!(block = this.as_local_operand(block, fun));
- if let Some(sym::move_val_init) = intrinsic {
- // `move_val_init` has "magic" semantics - the second argument is
- // always evaluated "directly" into the first one.
+ let args: Vec<_> = args
+ .into_iter()
+ .map(|arg| unpack!(block = this.as_local_call_operand(block, arg)))
+ .collect();
- let mut args = args.into_iter();
- let ptr = args.next().expect("0 arguments to `move_val_init`");
- let val = args.next().expect("1 argument to `move_val_init`");
- assert!(args.next().is_none(), ">2 arguments to `move_val_init`");
+ let success = this.cfg.start_new_block();
- let ptr = this.hir.mirror(ptr);
- let ptr_ty = ptr.ty;
- // Create an *internal* temp for the pointer, so that unsafety
- // checking won't complain about the raw pointer assignment.
- let ptr_temp = this
- .local_decls
- .push(LocalDecl::with_source_info(ptr_ty, source_info).internal());
- let ptr_temp = Place::from(ptr_temp);
- // No need for a scope, ptr_temp doesn't need drop
- let block = unpack!(this.into(ptr_temp, block, ptr));
- // Maybe we should provide a scope here so that
- // `move_val_init` wouldn't leak on panic even with an
- // arbitrary `val` expression, but `schedule_drop`,
- // borrowck and drop elaboration all prevent us from
- // dropping `ptr_temp.deref()`.
- this.into(this.hir.tcx().mk_place_deref(ptr_temp), block, val)
- } else {
- let args: Vec<_> = args
- .into_iter()
- .map(|arg| unpack!(block = this.as_local_call_operand(block, arg)))
- .collect();
+ this.record_operands_moved(&args);
- let success = this.cfg.start_new_block();
+ debug!("into_expr: fn_span={:?}", fn_span);
- this.record_operands_moved(&args);
-
- debug!("into_expr: fn_span={:?}", fn_span);
-
- this.cfg.terminate(
- block,
- source_info,
- TerminatorKind::Call {
- func: fun,
- args,
- cleanup: None,
- // FIXME(varkor): replace this with an uninhabitedness-based check.
- // This requires getting access to the current module to call
- // `tcx.is_ty_uninhabited_from`, which is currently tricky to do.
- destination: if expr.ty.is_never() {
- None
- } else {
- Some((destination, success))
- },
- from_hir_call,
- fn_span,
+ this.cfg.terminate(
+ block,
+ source_info,
+ TerminatorKind::Call {
+ func: fun,
+ args,
+ cleanup: None,
+ // FIXME(varkor): replace this with an uninhabitedness-based check.
+ // This requires getting access to the current module to call
+ // `tcx.is_ty_uninhabited_from`, which is currently tricky to do.
+ destination: if expr.ty.is_never() {
+ None
+ } else {
+ Some((destination, success))
},
- );
- this.diverge_from(block);
- success.unit()
- }
+ from_hir_call,
+ fn_span,
+ },
+ );
+ this.diverge_from(block);
+ success.unit()
}
ExprKind::Use { source } => this.into(destination, block, source),
ExprKind::Borrow { arg, borrow_kind } => {
@@ -277,7 +273,7 @@
let field_names = this.hir.all_fields(adt_def, variant_index);
let fields: Vec<_> = if let Some(FruInfo { base, field_types }) = base {
- let base = unpack!(block = this.as_place(block, base));
+ let place_builder = unpack!(block = this.as_place_builder(block, base));
// MIR does not natively support FRU, so for each
// base-supplied field, generate an operand that
@@ -287,9 +283,14 @@
.zip(field_types.into_iter())
.map(|(n, ty)| match fields_map.get(&n) {
Some(v) => v.clone(),
- None => this.consume_by_copy_or_move(
- this.hir.tcx().mk_place_field(base, n, ty),
- ),
+ None => {
+ let place_builder = place_builder.clone();
+ this.consume_by_copy_or_move(
+ place_builder
+ .field(n, ty)
+ .into_place(this.hir.tcx(), this.hir.typeck_results()),
+ )
+ }
})
.collect()
} else {
diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs
index c5f9412..fde007e 100644
--- a/compiler/rustc_mir_build/src/build/matches/mod.rs
+++ b/compiler/rustc_mir_build/src/build/matches/mod.rs
@@ -82,8 +82,8 @@
/// visible through borrow checking. False edges ensure that the CFG as
/// seen by borrow checking doesn't encode this. False edges are added:
///
- /// * From each prebinding block to the next prebinding block.
- /// * From each otherwise block to the next prebinding block.
+ /// * From each pre-binding block to the next pre-binding block.
+ /// * From each otherwise block to the next pre-binding block.
crate fn match_expr(
&mut self,
destination: Place<'tcx>,
@@ -690,10 +690,10 @@
#[derive(Debug)]
struct Candidate<'pat, 'tcx> {
- /// `Span` of the original pattern that gave rise to this candidate
+ /// [`Span`] of the original pattern that gave rise to this candidate.
span: Span,
- /// This `Candidate` has a guard.
+ /// Whether this `Candidate` has a guard.
has_guard: bool,
/// All of these must be satisfied...
@@ -705,14 +705,15 @@
/// ...and these types asserted...
ascriptions: Vec<Ascription<'tcx>>,
- /// ... and if this is non-empty, one of these subcandidates also has to match ...
+ /// ...and if this is non-empty, one of these subcandidates also has to match...
subcandidates: Vec<Candidate<'pat, 'tcx>>,
- /// ...and the guard must be evaluated, if false branch to Block...
+ /// ...and the guard must be evaluated; if it's `false` then branch to `otherwise_block`.
otherwise_block: Option<BasicBlock>,
- /// ...and the blocks for add false edges between candidates
+ /// The block before the `bindings` have been established.
pre_binding_block: Option<BasicBlock>,
+ /// The pre-binding block of the next candidate.
next_candidate_pre_binding_block: Option<BasicBlock>,
}
@@ -797,18 +798,19 @@
pattern: &'pat Pat<'tcx>,
}
+/// See [`Test`] for more.
#[derive(Clone, Debug, PartialEq)]
enum TestKind<'tcx> {
- /// Test the branches of enum.
+ /// Test what enum variant a value is.
Switch {
- /// The enum being tested
+ /// The enum type being tested.
adt_def: &'tcx ty::AdtDef,
/// The set of variants that we should create a branch for. We also
/// create an additional "otherwise" case.
variants: BitSet<VariantIdx>,
},
- /// Test what value an `integer`, `bool` or `char` has.
+ /// Test what value an integer, `bool`, or `char` has.
SwitchInt {
/// The type of the value that we're testing.
switch_ty: Ty<'tcx>,
@@ -816,7 +818,7 @@
///
/// For integers and `char`s we create a branch to each of the values in
/// `options`, as well as an "otherwise" branch for all other values, even
- /// in the (rare) case that options is exhaustive.
+ /// in the (rare) case that `options` is exhaustive.
///
/// For `bool` we always generate two edges, one for `true` and one for
/// `false`.
@@ -836,17 +838,21 @@
/// Test whether the value falls within an inclusive or exclusive range
Range(PatRange<'tcx>),
- /// Test length of the slice is equal to len
+ /// Test that the length of the slice is equal to `len`.
Len { len: u64, op: BinOp },
}
+/// A test to perform to determine which [`Candidate`] matches a value.
+///
+/// [`Test`] is just the test to perform; it does not include the value
+/// to be tested.
#[derive(Debug)]
crate struct Test<'tcx> {
span: Span,
kind: TestKind<'tcx>,
}
-/// ArmHasGuard is isomorphic to a boolean flag. It indicates whether
+/// `ArmHasGuard` is a wrapper around a boolean flag. It indicates whether
/// a match arm has a guard expression attached to it.
#[derive(Copy, Clone, Debug)]
crate struct ArmHasGuard(crate bool);
@@ -861,27 +867,27 @@
/// candidates are sorted such that the first item in the list
/// has the highest priority. When a candidate is found to match
/// the value, we will set and generate a branch to the appropriate
- /// prebinding block.
+ /// pre-binding block.
///
/// If we find that *NONE* of the candidates apply, we branch to the
/// `otherwise_block`, setting it to `Some` if required. In principle, this
/// means that the input list was not exhaustive, though at present we
/// sometimes are not smart enough to recognize all exhaustive inputs.
///
- /// It might be surprising that the input can be inexhaustive.
+ /// It might be surprising that the input can be non-exhaustive.
/// Indeed, initially, it is not, because all matches are
/// exhaustive in Rust. But during processing we sometimes divide
/// up the list of candidates and recurse with a non-exhaustive
/// list. This is important to keep the size of the generated code
- /// under control. See `test_candidates` for more details.
+ /// under control. See [`Builder::test_candidates`] for more details.
///
- /// If `fake_borrows` is Some, then places which need fake borrows
+ /// If `fake_borrows` is `Some`, then places which need fake borrows
/// will be added to it.
///
/// For an example of a case where we set `otherwise_block`, even for an
- /// exhaustive match consider:
+ /// exhaustive match, consider:
///
- /// ```rust
+ /// ```
/// match x {
/// (true, true) => (),
/// (_, false) => (),
@@ -890,8 +896,8 @@
/// ```
///
/// For this match, we check if `x.0` matches `true` (for the first
- /// arm). If that's false, we check `x.1`. If it's `true` we check if
- /// `x.0` matches `false` (for the third arm). In the (impossible at
+ /// arm). If it doesn't match, we check `x.1`. If `x.1` is `true` we check
+ /// if `x.0` matches `false` (for the third arm). In the (impossible at
/// runtime) case when `x.0` is now `true`, we branch to
/// `otherwise_block`.
fn match_candidates<'pat>(
@@ -998,26 +1004,31 @@
);
}
- /// Link up matched candidates. For example, if we have something like
- /// this:
+ /// Link up matched candidates.
+ ///
+ /// For example, if we have something like this:
///
/// ```rust
/// ...
- /// Some(x) if cond => ...
+ /// Some(x) if cond1 => ...
/// Some(x) => ...
- /// Some(x) if cond => ...
+ /// Some(x) if cond2 => ...
/// ...
/// ```
///
/// We generate real edges from:
- /// * `start_block` to the `prebinding_block` of the first pattern,
- /// * the otherwise block of the first pattern to the second pattern,
- /// * the otherwise block of the third pattern to the a block with an
- /// Unreachable terminator.
///
- /// As well as that we add fake edges from the otherwise blocks to the
- /// prebinding block of the next candidate in the original set of
+ /// * `start_block` to the [pre-binding block] of the first pattern,
+ /// * the [otherwise block] of the first pattern to the second pattern,
+ /// * the [otherwise block] of the third pattern to a block with an
+ /// [`Unreachable` terminator](TerminatorKind::Unreachable).
+ ///
+ /// In addition, we add fake edges from the otherwise blocks to the
+ /// pre-binding block of the next candidate in the original set of
/// candidates.
+ ///
+ /// [pre-binding block]: Candidate::pre_binding_block
+ /// [otherwise block]: Candidate::otherwise_block
fn select_matched_candidates(
&mut self,
matched_candidates: &mut [&mut Candidate<'_, 'tcx>],
@@ -1104,7 +1115,7 @@
/// forwards to [Builder::test_candidates].
///
/// Given a pattern `(P | Q, R | S)` we (in principle) generate a CFG like
- /// so
+ /// so:
///
/// ```text
/// [ start ]
@@ -1274,10 +1285,11 @@
/// This is the most subtle part of the matching algorithm. At
/// this point, the input candidates have been fully simplified,
/// and so we know that all remaining match-pairs require some
- /// sort of test. To decide what test to do, we take the highest
- /// priority candidate (last one in the list) and extract the
- /// first match-pair from the list. From this we decide what kind
- /// of test is needed using `test`, defined in the `test` module.
+ /// sort of test. To decide what test to perform, we take the highest
+ /// priority candidate (the first one in the list, as of January 2021)
+ /// and extract the first match-pair from the list. From this we decide
+ /// what kind of test is needed using [`Builder::test`], defined in the
+ /// [`test` module](mod@test).
///
/// *Note:* taking the first match pair is somewhat arbitrary, and
/// we might do better here by choosing more carefully what to
@@ -1285,20 +1297,23 @@
///
/// For example, consider the following possible match-pairs:
///
- /// 1. `x @ Some(P)` -- we will do a `Switch` to decide what variant `x` has
- /// 2. `x @ 22` -- we will do a `SwitchInt`
- /// 3. `x @ 3..5` -- we will do a range test
+ /// 1. `x @ Some(P)` -- we will do a [`Switch`] to decide what variant `x` has
+ /// 2. `x @ 22` -- we will do a [`SwitchInt`] to decide what value `x` has
+ /// 3. `x @ 3..5` -- we will do a [`Range`] test to decide what range `x` falls in
/// 4. etc.
///
+ /// [`Switch`]: TestKind::Switch
+ /// [`SwitchInt`]: TestKind::SwitchInt
+ /// [`Range`]: TestKind::Range
+ ///
/// Once we know what sort of test we are going to perform, this
- /// Tests may also help us with other candidates. So we walk over
+ /// test may also help us winnow down our candidates. So we walk over
/// the candidates (from high to low priority) and check. This
/// gives us, for each outcome of the test, a transformed list of
- /// candidates. For example, if we are testing the current
- /// variant of `x.0`, and we have a candidate `{x.0 @ Some(v), x.1
- /// @ 22}`, then we would have a resulting candidate of `{(x.0 as
- /// Some).0 @ v, x.1 @ 22}`. Note that the first match-pair is now
- /// simpler (and, in fact, irrefutable).
+ /// candidates. For example, if we are testing `x.0`'s variant,
+ /// and we have a candidate `(x.0 @ Some(v), x.1 @ 22)`,
+ /// then we would have a resulting candidate of `((x.0 as Some).0 @ v, x.1 @ 22)`.
+ /// Note that the first match-pair is now simpler (and, in fact, irrefutable).
///
/// But there may also be candidates that the test just doesn't
/// apply to. The classical example involves wildcards:
@@ -1328,7 +1343,7 @@
/// is trivially NP-complete:
///
/// ```rust
- /// match (var0, var1, var2, var3, ..) {
+ /// match (var0, var1, var2, var3, ...) {
/// (true, _, _, false, true, ...) => false,
/// (_, true, true, false, _, ...) => false,
/// (false, _, false, false, _, ...) => false,
@@ -1343,7 +1358,7 @@
///
/// That kind of exponential worst-case might not occur in practice, but
/// our simplistic treatment of constants and guards would make it occur
- /// in very common situations - for example #29740:
+ /// in very common situations - for example [#29740]:
///
/// ```rust
/// match x {
@@ -1354,13 +1369,17 @@
/// }
/// ```
///
- /// Here we first test the match-pair `x @ "foo"`, which is an `Eq` test.
+ /// [#29740]: https://github.com/rust-lang/rust/issues/29740
+ ///
+ /// Here we first test the match-pair `x @ "foo"`, which is an [`Eq` test].
+ ///
+ /// [`Eq` test]: TestKind::Eq
///
/// It might seem that we would end up with 2 disjoint candidate
- /// sets, consisting of the first candidate or the other 3, but our
- /// algorithm doesn't reason about "foo" being distinct from the other
+ /// sets, consisting of the first candidate or the other two, but our
+ /// algorithm doesn't reason about `"foo"` being distinct from the other
/// constants; it considers the latter arms to potentially match after
- /// both outcomes, which obviously leads to an exponential amount
+ /// both outcomes, which obviously leads to an exponential number
/// of tests.
///
/// To avoid these kinds of problems, our algorithm tries to ensure
@@ -1372,16 +1391,16 @@
///
/// After we perform our test, we branch into the appropriate candidate
/// set and recurse with `match_candidates`. These sub-matches are
- /// obviously inexhaustive - as we discarded our otherwise set - so
+ /// obviously non-exhaustive - as we discarded our otherwise set - so
/// we set their continuation to do `match_candidates` on the
- /// "unmatched" set (which is again inexhaustive).
+ /// "unmatched" set (which is again non-exhaustive).
///
/// If you apply this to the above test, you basically wind up
/// with an if-else-if chain, testing each candidate in turn,
/// which is precisely what we want.
///
/// In addition to avoiding exponential-time blowups, this algorithm
- /// also has nice property that each guard and arm is only generated
+ /// also has the nice property that each guard and arm is only generated
/// once.
fn test_candidates<'pat, 'b, 'c>(
&mut self,
@@ -1733,15 +1752,21 @@
let e = self.hir.mirror(e.clone());
let source_info = self.source_info(e.span);
(e.span, self.test_bool(block, e, source_info))
- },
+ }
Guard::IfLet(pat, scrutinee) => {
let scrutinee_span = scrutinee.span();
- let scrutinee_place = unpack!(block = self.lower_scrutinee(block, scrutinee.clone(), scrutinee_span));
+ let scrutinee_place = unpack!(
+ block = self.lower_scrutinee(block, scrutinee.clone(), scrutinee_span)
+ );
let mut guard_candidate = Candidate::new(scrutinee_place, &pat, false);
let wildcard = Pat::wildcard_from_ty(pat.ty);
let mut otherwise_candidate = Candidate::new(scrutinee_place, &wildcard, false);
- let fake_borrow_temps =
- self.lower_match_tree(block, pat.span, false, &mut [&mut guard_candidate, &mut otherwise_candidate]);
+ let fake_borrow_temps = self.lower_match_tree(
+ block,
+ pat.span,
+ false,
+ &mut [&mut guard_candidate, &mut otherwise_candidate],
+ );
self.declare_bindings(
None,
pat.span.to(arm_span.unwrap()),
diff --git a/compiler/rustc_mir_build/src/build/matches/simplify.rs b/compiler/rustc_mir_build/src/build/matches/simplify.rs
index 705266d..ddfaeaf 100644
--- a/compiler/rustc_mir_build/src/build/matches/simplify.rs
+++ b/compiler/rustc_mir_build/src/build/matches/simplify.rs
@@ -15,7 +15,6 @@
use crate::build::matches::{Ascription, Binding, Candidate, MatchPair};
use crate::build::Builder;
use crate::thir::{self, *};
-use rustc_attr::{SignedInt, UnsignedInt};
use rustc_hir::RangeEnd;
use rustc_middle::mir::Place;
use rustc_middle::ty;
@@ -55,7 +54,7 @@
// * the bindings from the previous iteration of the loop is prepended to the bindings from
// the current iteration (in the implementation this is done by mem::swap and extend)
// * after all iterations, these new bindings are then appended to the bindings that were
- // prexisting (i.e. `candidate.binding` when the function was called).
+ // preexisting (i.e. `candidate.binding` when the function was called).
//
// example:
// candidate.bindings = [1, 2, 3]
@@ -203,13 +202,13 @@
(Some(('\u{0000}' as u128, '\u{10FFFF}' as u128, Size::from_bits(32))), 0)
}
ty::Int(ity) => {
- let size = Integer::from_attr(&tcx, SignedInt(ity)).size();
+ let size = Integer::from_int_ty(&tcx, ity).size();
let max = size.truncate(u128::MAX);
let bias = 1u128 << (size.bits() - 1);
(Some((0, max, size)), bias)
}
ty::Uint(uty) => {
- let size = Integer::from_attr(&tcx, UnsignedInt(uty)).size();
+ let size = Integer::from_uint_ty(&tcx, uty).size();
let max = size.truncate(u128::MAX);
(Some((0, max, size)), 0)
}
diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs
index 07173f4..126fb95 100644
--- a/compiler/rustc_mir_build/src/build/matches/test.rs
+++ b/compiler/rustc_mir_build/src/build/matches/test.rs
@@ -23,7 +23,7 @@
impl<'a, 'tcx> Builder<'a, 'tcx> {
/// Identifies what test is needed to decide if `match_pair` is applicable.
///
- /// It is a bug to call this with a simplifiable pattern.
+ /// It is a bug to call this with a not-fully-simplified pattern.
pub(super) fn test<'pat>(&mut self, match_pair: &MatchPair<'pat, 'tcx>) -> Test<'tcx> {
match *match_pair.pattern.kind {
PatKind::Variant { ref adt_def, substs: _, variant_index: _, subpatterns: _ } => Test {
diff --git a/compiler/rustc_mir_build/src/build/matches/util.rs b/compiler/rustc_mir_build/src/build/matches/util.rs
index 4ef88c2..db1f678 100644
--- a/compiler/rustc_mir_build/src/build/matches/util.rs
+++ b/compiler/rustc_mir_build/src/build/matches/util.rs
@@ -32,9 +32,7 @@
) {
let tcx = self.hir.tcx();
let (min_length, exact_size) = match place.ty(&self.local_decls, tcx).ty.kind() {
- ty::Array(_, length) => {
- (length.eval_usize(tcx, self.hir.param_env), true)
- }
+ ty::Array(_, length) => (length.eval_usize(tcx, self.hir.param_env), true),
_ => ((prefix.len() + suffix.len()).try_into().unwrap(), false),
};
diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs
index a207997..5f6c8d2 100644
--- a/compiler/rustc_mir_build/src/build/mod.rs
+++ b/compiler/rustc_mir_build/src/build/mod.rs
@@ -830,9 +830,8 @@
_ => span_bug!(self.fn_span, "upvars with non-closure env ty {:?}", closure_ty),
};
let capture_tys = upvar_substs.upvar_tys();
- let captures_with_tys = hir_typeck_results
- .closure_min_captures_flattened(fn_def_id)
- .zip(capture_tys);
+ let captures_with_tys =
+ hir_typeck_results.closure_min_captures_flattened(fn_def_id).zip(capture_tys);
self.upvar_mutbls = captures_with_tys
.enumerate()
@@ -840,25 +839,16 @@
let capture = captured_place.info.capture_kind;
let var_id = match captured_place.place.base {
HirPlaceBase::Upvar(upvar_id) => upvar_id.var_path.hir_id,
- _ => bug!("Expected an upvar")
+ _ => bug!("Expected an upvar"),
};
- let mut mutability = Mutability::Not;
+ let mutability = captured_place.mutability;
// FIXME(project-rfc-2229#8): Store more precise information
- let mut name = kw::Invalid;
+ let mut name = kw::Empty;
if let Some(Node::Binding(pat)) = tcx_hir.find(var_id) {
if let hir::PatKind::Binding(_, _, ident, _) = pat.kind {
name = ident.name;
- match hir_typeck_results
- .extract_binding_mode(tcx.sess, pat.hir_id, pat.span)
- {
- Some(ty::BindByValue(hir::Mutability::Mut)) => {
- mutability = Mutability::Mut;
- }
- Some(_) => mutability = Mutability::Not,
- _ => {}
- }
}
}
diff --git a/compiler/rustc_mir_build/src/build/scope.rs b/compiler/rustc_mir_build/src/build/scope.rs
index e76175c..5e9d780 100644
--- a/compiler/rustc_mir_build/src/build/scope.rs
+++ b/compiler/rustc_mir_build/src/build/scope.rs
@@ -892,10 +892,7 @@
let local_scope = self.local_scope();
let scope = self.scopes.scopes.last_mut().unwrap();
- assert_eq!(
- scope.region_scope, local_scope,
- "local scope is not the topmost scope!",
- );
+ assert_eq!(scope.region_scope, local_scope, "local scope is not the topmost scope!",);
// look for moves of a local variable, like `MOVE(_X)`
let locals_moved = operands.iter().flat_map(|operand| match operand {
@@ -1008,9 +1005,9 @@
matches!(
self.cfg.block_data(start).terminator().kind,
TerminatorKind::Assert { .. }
- | TerminatorKind::Call {..}
- | TerminatorKind::DropAndReplace { .. }
- | TerminatorKind::FalseUnwind { .. }
+ | TerminatorKind::Call { .. }
+ | TerminatorKind::DropAndReplace { .. }
+ | TerminatorKind::FalseUnwind { .. }
),
"diverge_from called on block with terminator that cannot unwind."
);
diff --git a/compiler/rustc_mir_build/src/thir/constant.rs b/compiler/rustc_mir_build/src/thir/constant.rs
index dfe8231..969f7d1 100644
--- a/compiler/rustc_mir_build/src/thir/constant.rs
+++ b/compiler/rustc_mir_build/src/thir/constant.rs
@@ -39,7 +39,7 @@
let id = tcx.allocate_bytes(data);
ConstValue::Scalar(Scalar::Ptr(id.into()))
}
- (ast::LitKind::Byte(n), ty::Uint(ast::UintTy::U8)) => {
+ (ast::LitKind::Byte(n), ty::Uint(ty::UintTy::U8)) => {
ConstValue::Scalar(Scalar::from_uint(*n, Size::from_bytes(1)))
}
(ast::LitKind::Int(n, _), ty::Uint(_)) | (ast::LitKind::Int(n, _), ty::Int(_)) => {
@@ -56,11 +56,11 @@
Ok(ty::Const::from_value(tcx, lit, ty))
}
-fn parse_float<'tcx>(num: Symbol, fty: ast::FloatTy, neg: bool) -> Result<ConstValue<'tcx>, ()> {
+fn parse_float<'tcx>(num: Symbol, fty: ty::FloatTy, neg: bool) -> Result<ConstValue<'tcx>, ()> {
let num = num.as_str();
use rustc_apfloat::ieee::{Double, Single};
let scalar = match fty {
- ast::FloatTy::F32 => {
+ ty::FloatTy::F32 => {
num.parse::<f32>().map_err(|_| ())?;
let mut f = num.parse::<Single>().unwrap_or_else(|e| {
panic!("apfloat::ieee::Single failed to parse `{}`: {:?}", num, e)
@@ -70,7 +70,7 @@
}
Scalar::from_f32(f)
}
- ast::FloatTy::F64 => {
+ ty::FloatTy::F64 => {
num.parse::<f64>().map_err(|_| ())?;
let mut f = num.parse::<Double>().unwrap_or_else(|e| {
panic!("apfloat::ieee::Double failed to parse `{}`: {:?}", num, e)
diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs
index 417f9bd..2962cbe 100644
--- a/compiler/rustc_mir_build/src/thir/cx/expr.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs
@@ -537,13 +537,16 @@
},
Err(err) => bug!("invalid loop id for continue: {}", err),
},
+ hir::ExprKind::If(cond, then, else_opt) => ExprKind::If {
+ cond: cond.to_ref(),
+ then: then.to_ref(),
+ else_opt: else_opt.map(|el| el.to_ref()),
+ },
hir::ExprKind::Match(ref discr, ref arms, _) => ExprKind::Match {
scrutinee: discr.to_ref(),
arms: arms.iter().map(|a| convert_arm(cx, a)).collect(),
},
- hir::ExprKind::Loop(ref body, _, _) => {
- ExprKind::Loop { body: block::to_expr_ref(cx, body) }
- }
+ hir::ExprKind::Loop(ref body, ..) => ExprKind::Loop { body: block::to_expr_ref(cx, body) },
hir::ExprKind::Field(ref source, ..) => ExprKind::Field {
lhs: source.to_ref(),
name: Field::new(cx.tcx.field_index(expr.hir_id, cx.typeck_results)),
@@ -813,8 +816,7 @@
let item_id = cx.tcx.hir().get_parent_node(hir_id);
let item_def_id = cx.tcx.hir().local_def_id(item_id);
let generics = cx.tcx.generics_of(item_def_id);
- let local_def_id = cx.tcx.hir().local_def_id(hir_id);
- let index = generics.param_def_id_to_index[&local_def_id.to_def_id()];
+ let index = generics.param_def_id_to_index[&def_id];
let name = cx.tcx.hir().name(hir_id);
let val = ty::ConstKind::Param(ty::ParamConst::new(index, name));
ExprKind::Literal {
diff --git a/compiler/rustc_mir_build/src/thir/mod.rs b/compiler/rustc_mir_build/src/thir/mod.rs
index ace9cad..ed3d392 100644
--- a/compiler/rustc_mir_build/src/thir/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/mod.rs
@@ -139,6 +139,11 @@
Box {
value: ExprRef<'tcx>,
},
+ If {
+ cond: ExprRef<'tcx>,
+ then: ExprRef<'tcx>,
+ else_opt: Option<ExprRef<'tcx>>,
+ },
Call {
ty: Ty<'tcx>,
fun: ExprRef<'tcx>,
diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
index db817b3..3977068 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
@@ -403,7 +403,7 @@
match is_useful {
NotUseful => {
match source {
- hir::MatchSource::IfDesugar { .. } | hir::MatchSource::WhileDesugar => bug!(),
+ hir::MatchSource::WhileDesugar => bug!(),
hir::MatchSource::IfLetDesugar { .. } | hir::MatchSource::WhileLetDesugar => {
// Check which arm we're on.
@@ -503,6 +503,11 @@
));
}
}
+ if let ty::Ref(_, sub_ty, _) = scrut_ty.kind() {
+ if cx.tcx.is_ty_uninhabited_from(cx.module, sub_ty, cx.param_env) {
+ err.note("references are always considered inhabited");
+ }
+ }
err.emit();
}
diff --git a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs
index d79dd97..e67166c 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs
@@ -52,7 +52,6 @@
use rustc_data_structures::captures::Captures;
use rustc_index::vec::Idx;
-use rustc_attr::{SignedInt, UnsignedInt};
use rustc_hir::def_id::DefId;
use rustc_hir::{HirId, RangeEnd};
use rustc_middle::mir::interpret::ConstValue;
@@ -103,10 +102,10 @@
ty::Bool => Some((Size::from_bytes(1), 0)),
ty::Char => Some((Size::from_bytes(4), 0)),
ty::Int(ity) => {
- let size = Integer::from_attr(&tcx, SignedInt(ity)).size();
+ let size = Integer::from_int_ty(&tcx, ity).size();
Some((size, 1u128 << (size.bits() as u128 - 1)))
}
- ty::Uint(uty) => Some((Integer::from_attr(&tcx, UnsignedInt(uty)).size(), 0)),
+ ty::Uint(uty) => Some((Integer::from_uint_ty(&tcx, uty).size(), 0)),
_ => None,
}
}
@@ -167,7 +166,7 @@
fn signed_bias(tcx: TyCtxt<'_>, ty: Ty<'_>) -> u128 {
match *ty.kind() {
ty::Int(ity) => {
- let bits = Integer::from_attr(&tcx, SignedInt(ity)).size().bits() as u128;
+ let bits = Integer::from_int_ty(&tcx, ity).size().bits() as u128;
1u128 << (bits - 1)
}
_ => 0,
@@ -328,8 +327,8 @@
}
impl SplitIntRange {
- fn new(r: IntRange) -> Self {
- SplitIntRange { range: r.clone(), borders: Vec::new() }
+ fn new(range: IntRange) -> Self {
+ SplitIntRange { range, borders: Vec::new() }
}
/// Internal use
@@ -959,13 +958,13 @@
smallvec![NonExhaustive]
}
&ty::Int(ity) => {
- let bits = Integer::from_attr(&cx.tcx, SignedInt(ity)).size().bits() as u128;
+ let bits = Integer::from_int_ty(&cx.tcx, ity).size().bits() as u128;
let min = 1u128 << (bits - 1);
let max = min - 1;
smallvec![make_range(min, max)]
}
&ty::Uint(uty) => {
- let size = Integer::from_attr(&cx.tcx, UnsignedInt(uty)).size();
+ let size = Integer::from_uint_ty(&cx.tcx, uty).size();
let max = size.truncate(u128::MAX);
smallvec![make_range(0, max)]
}
diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
index 7e9a3a3..7186e26 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
@@ -9,7 +9,6 @@
use crate::thir::util::UserAnnotatedTyHelpers;
-use rustc_ast as ast;
use rustc_errors::struct_span_err;
use rustc_hir as hir;
use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
@@ -1069,20 +1068,19 @@
if let (Some(a), Some(b)) = (a_bits, b_bits) {
use rustc_apfloat::Float;
return match *ty.kind() {
- ty::Float(ast::FloatTy::F32) => {
+ ty::Float(ty::FloatTy::F32) => {
let l = rustc_apfloat::ieee::Single::from_bits(a);
let r = rustc_apfloat::ieee::Single::from_bits(b);
l.partial_cmp(&r)
}
- ty::Float(ast::FloatTy::F64) => {
+ ty::Float(ty::FloatTy::F64) => {
let l = rustc_apfloat::ieee::Double::from_bits(a);
let r = rustc_apfloat::ieee::Double::from_bits(b);
l.partial_cmp(&r)
}
ty::Int(ity) => {
- use rustc_attr::SignedInt;
use rustc_middle::ty::layout::IntegerExt;
- let size = rustc_target::abi::Integer::from_attr(&tcx, SignedInt(ity)).size();
+ let size = rustc_target::abi::Integer::from_int_ty(&tcx, ity).size();
let a = size.sign_extend(a);
let b = size.sign_extend(b);
Some((a as i128).cmp(&(b as i128)))
diff --git a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs
index 83fee38..d7c08a2 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs
@@ -952,7 +952,7 @@
assert!(rows.iter().all(|r| r.len() == v.len()));
// FIXME(Nadrieril): Hack to work around type normalization issues (see #72476).
- let ty = matrix.heads().next().map(|r| r.ty).unwrap_or(v.head().ty);
+ let ty = matrix.heads().next().map_or(v.head().ty, |r| r.ty);
let pcx = PatCtxt { cx, ty, span: v.head().span, is_top_level };
debug!("is_useful_expand_first_col: ty={:#?}, expanding {:#?}", pcx.ty, v.head());
diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs
index b2604ea..4a638ec 100644
--- a/compiler/rustc_parse/src/lexer/mod.rs
+++ b/compiler/rustc_parse/src/lexer/mod.rs
@@ -14,7 +14,7 @@
mod unescape_error_reporting;
mod unicode_chars;
-use unescape_error_reporting::{emit_unescape_error, push_escaped_char};
+use unescape_error_reporting::{emit_unescape_error, escaped_char};
#[derive(Clone, Debug)]
pub struct UnmatchedBrace {
@@ -122,11 +122,9 @@
m: &str,
c: char,
) -> DiagnosticBuilder<'a> {
- let mut m = m.to_string();
- m.push_str(": ");
- push_escaped_char(&mut m, c);
-
- self.sess.span_diagnostic.struct_span_fatal(self.mk_sp(from_pos, to_pos), &m[..])
+ self.sess
+ .span_diagnostic
+ .struct_span_fatal(self.mk_sp(from_pos, to_pos), &format!("{}: {}", m, escaped_char(c)))
}
/// Turns simple `rustc_lexer::TokenKind` enum into a rich
@@ -421,7 +419,7 @@
let content_start = start + BytePos(prefix_len);
let content_end = suffix_start - BytePos(postfix_len);
let id = self.symbol_from_to(content_start, content_end);
- self.validate_literal_escape(mode, content_start, content_end);
+ self.validate_literal_escape(mode, content_start, content_end, prefix_len, postfix_len);
(lit_kind, id)
}
@@ -525,13 +523,20 @@
.raise();
}
- fn validate_literal_escape(&self, mode: Mode, content_start: BytePos, content_end: BytePos) {
+ fn validate_literal_escape(
+ &self,
+ mode: Mode,
+ content_start: BytePos,
+ content_end: BytePos,
+ prefix_len: u32,
+ postfix_len: u32,
+ ) {
let lit_content = self.str_from_to(content_start, content_end);
unescape::unescape_literal(lit_content, mode, &mut |range, result| {
// Here we only check for errors. The actual unescaping is done later.
if let Err(err) = result {
- let span_with_quotes =
- self.mk_sp(content_start - BytePos(1), content_end + BytePos(1));
+ let span_with_quotes = self
+ .mk_sp(content_start - BytePos(prefix_len), content_end + BytePos(postfix_len));
let (start, end) = (range.start as u32, range.end as u32);
let lo = content_start + BytePos(start);
let hi = lo + BytePos(end - start);
diff --git a/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs b/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs
index 6a890be..a580f0c 100644
--- a/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs
+++ b/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs
@@ -37,20 +37,22 @@
EscapeError::LoneSurrogateUnicodeEscape => {
handler
.struct_span_err(span, "invalid unicode character escape")
+ .span_label(span, "invalid escape")
.help("unicode escape must not be a surrogate")
.emit();
}
EscapeError::OutOfRangeUnicodeEscape => {
handler
.struct_span_err(span, "invalid unicode character escape")
+ .span_label(span, "invalid escape")
.help("unicode escape must be at most 10FFFF")
.emit();
}
EscapeError::MoreThanOneChar => {
- let msg = if mode.is_bytes() {
- "if you meant to write a byte string literal, use double quotes"
+ let (prefix, msg) = if mode.is_bytes() {
+ ("b", "if you meant to write a byte string literal, use double quotes")
} else {
- "if you meant to write a `str` literal, use double quotes"
+ ("", "if you meant to write a `str` literal, use double quotes")
};
handler
@@ -61,31 +63,44 @@
.span_suggestion(
span_with_quotes,
msg,
- format!("\"{}\"", lit),
+ format!("{}\"{}\"", prefix, lit),
Applicability::MachineApplicable,
)
.emit();
}
EscapeError::EscapeOnlyChar => {
- let (c, _span) = last_char();
+ let (c, char_span) = last_char();
- let mut msg = if mode.is_bytes() {
- "byte constant must be escaped: "
+ let msg = if mode.is_bytes() {
+ "byte constant must be escaped"
} else {
- "character constant must be escaped: "
- }
- .to_string();
- push_escaped_char(&mut msg, c);
-
- handler.span_err(span, msg.as_str())
+ "character constant must be escaped"
+ };
+ handler
+ .struct_span_err(span, &format!("{}: `{}`", msg, escaped_char(c)))
+ .span_suggestion(
+ char_span,
+ "escape the character",
+ c.escape_default().to_string(),
+ Applicability::MachineApplicable,
+ )
+ .emit()
}
EscapeError::BareCarriageReturn => {
let msg = if mode.in_double_quotes() {
- "bare CR not allowed in string, use \\r instead"
+ "bare CR not allowed in string, use `\\r` instead"
} else {
- "character constant must be escaped: \\r"
+ "character constant must be escaped: `\\r`"
};
- handler.span_err(span, msg);
+ handler
+ .struct_span_err(span, msg)
+ .span_suggestion(
+ span,
+ "escape the character",
+ "\\r".to_string(),
+ Applicability::MachineApplicable,
+ )
+ .emit();
}
EscapeError::BareCarriageReturnInRawString => {
assert!(mode.in_double_quotes());
@@ -97,21 +112,22 @@
let label =
if mode.is_bytes() { "unknown byte escape" } else { "unknown character escape" };
- let mut msg = label.to_string();
- msg.push_str(": ");
- push_escaped_char(&mut msg, c);
-
- let mut diag = handler.struct_span_err(span, msg.as_str());
+ let ec = escaped_char(c);
+ let mut diag = handler.struct_span_err(span, &format!("{}: `{}`", label, ec));
diag.span_label(span, label);
if c == '{' || c == '}' && !mode.is_bytes() {
diag.help(
- "if used in a formatting string, \
- curly braces are escaped with `{{` and `}}`",
+ "if used in a formatting string, curly braces are escaped with `{{` and `}}`",
);
} else if c == '\r' {
diag.help(
- "this is an isolated carriage return; \
- consider checking your editor and version control settings",
+ "this is an isolated carriage return; consider checking your editor and \
+ version control settings",
+ );
+ } else {
+ diag.help(
+ "for more information, visit \
+ <https://static.rust-lang.org/doc/master/reference.html#literals>",
);
}
diag.emit();
@@ -122,45 +138,70 @@
EscapeError::InvalidCharInHexEscape | EscapeError::InvalidCharInUnicodeEscape => {
let (c, span) = last_char();
- let mut msg = if error == EscapeError::InvalidCharInHexEscape {
- "invalid character in numeric character escape: "
+ let msg = if error == EscapeError::InvalidCharInHexEscape {
+ "invalid character in numeric character escape"
} else {
- "invalid character in unicode escape: "
- }
- .to_string();
- push_escaped_char(&mut msg, c);
+ "invalid character in unicode escape"
+ };
+ let c = escaped_char(c);
- handler.span_err(span, msg.as_str())
+ handler
+ .struct_span_err(span, &format!("{}: `{}`", msg, c))
+ .span_label(span, msg)
+ .emit();
}
EscapeError::NonAsciiCharInByte => {
assert!(mode.is_bytes());
- let (_c, span) = last_char();
- handler.span_err(
- span,
- "byte constant must be ASCII. \
- Use a \\xHH escape for a non-ASCII byte",
- )
+ let (c, span) = last_char();
+ handler
+ .struct_span_err(span, "non-ASCII character in byte constant")
+ .span_label(span, "byte constant must be ASCII")
+ .span_suggestion(
+ span,
+ "use a \\xHH escape for a non-ASCII byte",
+ format!("\\x{:X}", c as u32),
+ Applicability::MachineApplicable,
+ )
+ .emit();
}
EscapeError::NonAsciiCharInByteString => {
assert!(mode.is_bytes());
let (_c, span) = last_char();
- handler.span_err(span, "raw byte string must be ASCII")
+ handler
+ .struct_span_err(span, "raw byte string must be ASCII")
+ .span_label(span, "must be ASCII")
+ .emit();
}
- EscapeError::OutOfRangeHexEscape => handler.span_err(
- span,
- "this form of character escape may only be used \
- with characters in the range [\\x00-\\x7f]",
- ),
+ EscapeError::OutOfRangeHexEscape => {
+ handler
+ .struct_span_err(span, "out of range hex escape")
+ .span_label(span, "must be a character in the range [\\x00-\\x7f]")
+ .emit();
+ }
EscapeError::LeadingUnderscoreUnicodeEscape => {
- let (_c, span) = last_char();
- handler.span_err(span, "invalid start of unicode escape")
+ let (c, span) = last_char();
+ let msg = "invalid start of unicode escape";
+ handler
+ .struct_span_err(span, &format!("{}: `{}`", msg, c))
+ .span_label(span, msg)
+ .emit();
}
EscapeError::OverlongUnicodeEscape => {
- handler.span_err(span, "overlong unicode escape (must have at most 6 hex digits)")
+ handler
+ .struct_span_err(span, "overlong unicode escape")
+ .span_label(span, "must have at most 6 hex digits")
+ .emit();
}
- EscapeError::UnclosedUnicodeEscape => {
- handler.span_err(span, "unterminated unicode escape (needed a `}`)")
- }
+ EscapeError::UnclosedUnicodeEscape => handler
+ .struct_span_err(span, "unterminated unicode escape")
+ .span_label(span, "missing a closing `}`")
+ .span_suggestion_verbose(
+ span.shrink_to_hi(),
+ "terminate the unicode escape",
+ "}".to_string(),
+ Applicability::MaybeIncorrect,
+ )
+ .emit(),
EscapeError::NoBraceInUnicodeEscape => {
let msg = "incorrect unicode escape sequence";
let mut diag = handler.struct_span_err(span, msg);
@@ -190,28 +231,38 @@
diag.emit();
}
- EscapeError::UnicodeEscapeInByte => handler.span_err(
- span,
- "unicode escape sequences cannot be used \
- as a byte or in a byte string",
- ),
- EscapeError::EmptyUnicodeEscape => {
- handler.span_err(span, "empty unicode escape (must have at least 1 hex digit)")
+ EscapeError::UnicodeEscapeInByte => {
+ let msg = "unicode escape in byte string";
+ handler
+ .struct_span_err(span, msg)
+ .span_label(span, msg)
+ .help("unicode escape sequences cannot be used as a byte or in a byte string")
+ .emit();
}
- EscapeError::ZeroChars => handler.span_err(span, "empty character literal"),
- EscapeError::LoneSlash => handler.span_err(span, "invalid trailing slash in literal"),
+ EscapeError::EmptyUnicodeEscape => {
+ handler
+ .struct_span_err(span, "empty unicode escape")
+ .span_label(span, "this escape must have at least 1 hex digit")
+ .emit();
+ }
+ EscapeError::ZeroChars => {
+ let msg = "empty character literal";
+ handler.struct_span_err(span, msg).span_label(span, msg).emit()
+ }
+ EscapeError::LoneSlash => {
+ let msg = "invalid trailing slash in literal";
+ handler.struct_span_err(span, msg).span_label(span, msg).emit();
+ }
}
}
/// Pushes a character to a message string for error reporting
-pub(crate) fn push_escaped_char(msg: &mut String, c: char) {
+pub(crate) fn escaped_char(c: char) -> String {
match c {
'\u{20}'..='\u{7e}' => {
// Don't escape \, ' or " for user-facing messages
- msg.push(c);
+ c.to_string()
}
- _ => {
- msg.extend(c.escape_default());
- }
+ _ => c.escape_default().to_string(),
}
}
diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs
index 44999c9..f155f3a 100644
--- a/compiler/rustc_parse/src/lib.rs
+++ b/compiler/rustc_parse/src/lib.rs
@@ -4,25 +4,23 @@
#![feature(bindings_after_at)]
#![feature(iter_order_by)]
#![feature(or_patterns)]
+#![feature(box_syntax)]
+#![feature(box_patterns)]
use rustc_ast as ast;
use rustc_ast::attr::HasAttrs;
-use rustc_ast::token::{self, DelimToken, Nonterminal, Token, TokenKind};
-use rustc_ast::tokenstream::{self, LazyTokenStream, TokenStream, TokenTree};
+use rustc_ast::token::{self, Nonterminal};
+use rustc_ast::tokenstream::{self, CanSynthesizeMissingTokens, LazyTokenStream, TokenStream};
use rustc_ast_pretty::pprust;
-use rustc_data_structures::fx::FxHashSet;
use rustc_data_structures::sync::Lrc;
use rustc_errors::{Diagnostic, FatalError, Level, PResult};
use rustc_session::parse::ParseSess;
-use rustc_span::{symbol::kw, FileName, SourceFile, Span, DUMMY_SP};
+use rustc_span::{FileName, SourceFile, Span};
-use smallvec::SmallVec;
-use std::cell::RefCell;
-use std::mem;
use std::path::Path;
use std::str;
-use tracing::{debug, info};
+use tracing::debug;
pub const MACRO_ARGUMENTS: Option<&str> = Some("macro arguments");
@@ -237,7 +235,11 @@
// NOTE(Centril): The following probably shouldn't be here but it acknowledges the
// fact that architecturally, we are using parsing (read on below to understand why).
-pub fn nt_to_tokenstream(nt: &Nonterminal, sess: &ParseSess, span: Span) -> TokenStream {
+pub fn nt_to_tokenstream(
+ nt: &Nonterminal,
+ sess: &ParseSess,
+ synthesize_tokens: CanSynthesizeMissingTokens,
+) -> TokenStream {
// A `Nonterminal` is often a parsed AST item. At this point we now
// need to convert the parsed AST to an actual token stream, e.g.
// un-parse it basically.
@@ -255,9 +257,18 @@
|tokens: Option<&LazyTokenStream>| tokens.as_ref().map(|t| t.create_token_stream());
let tokens = match *nt {
- Nonterminal::NtItem(ref item) => prepend_attrs(&item.attrs, item.tokens.as_ref()),
+ Nonterminal::NtItem(ref item) => prepend_attrs(sess, &item.attrs, nt, item.tokens.as_ref()),
Nonterminal::NtBlock(ref block) => convert_tokens(block.tokens.as_ref()),
- Nonterminal::NtStmt(ref stmt) => prepend_attrs(stmt.attrs(), stmt.tokens()),
+ Nonterminal::NtStmt(ref stmt) => {
+ let do_prepend = |tokens| prepend_attrs(sess, stmt.attrs(), nt, tokens);
+ if let ast::StmtKind::Empty = stmt.kind {
+ let tokens: TokenStream =
+ tokenstream::TokenTree::token(token::Semi, stmt.span).into();
+ do_prepend(Some(&LazyTokenStream::new(tokens)))
+ } else {
+ do_prepend(stmt.tokens())
+ }
+ }
Nonterminal::NtPat(ref pat) => convert_tokens(pat.tokens.as_ref()),
Nonterminal::NtTy(ref ty) => convert_tokens(ty.tokens.as_ref()),
Nonterminal::NtIdent(ident, is_raw) => {
@@ -274,376 +285,43 @@
if expr.tokens.is_none() {
debug!("missing tokens for expr {:?}", expr);
}
- prepend_attrs(&expr.attrs, expr.tokens.as_ref())
+ prepend_attrs(sess, &expr.attrs, nt, expr.tokens.as_ref())
}
};
- // Caches the stringification of 'good' `TokenStreams` which passed
- // `tokenstream_probably_equal_for_proc_macro`. This allows us to avoid
- // repeatedly stringifying and comparing the same `TokenStream` for deeply
- // nested nonterminals.
- //
- // We cache by the strinification instead of the `TokenStream` to avoid
- // needing to implement `Hash` for `TokenStream`. Note that it's possible to
- // have two distinct `TokenStream`s that stringify to the same result
- // (e.g. if they differ only in hygiene information). However, any
- // information lost during the stringification process is also intentionally
- // ignored by `tokenstream_probably_equal_for_proc_macro`, so it's fine
- // that a single cache entry may 'map' to multiple distinct `TokenStream`s.
- //
- // This is a temporary hack to prevent compilation blowup on certain inputs.
- // The entire pretty-print/retokenize process will be removed soon.
- thread_local! {
- static GOOD_TOKEN_CACHE: RefCell<FxHashSet<String>> = Default::default();
- }
-
- // FIXME(#43081): Avoid this pretty-print + reparse hack
- // Pretty-print the AST struct without inserting any parenthesis
- // beyond those explicitly written by the user (e.g. `ExpnKind::Paren`).
- // The resulting stream may have incorrect precedence, but it's only
- // ever used for a comparison against the capture tokenstream.
- let source = pprust::nonterminal_to_string_no_extra_parens(nt);
- let filename = FileName::macro_expansion_source_code(&source);
- let reparsed_tokens = parse_stream_from_source_str(filename, source.clone(), sess, Some(span));
-
- // During early phases of the compiler the AST could get modified
- // directly (e.g., attributes added or removed) and the internal cache
- // of tokens my not be invalidated or updated. Consequently if the
- // "lossless" token stream disagrees with our actual stringification
- // (which has historically been much more battle-tested) then we go
- // with the lossy stream anyway (losing span information).
- //
- // Note that the comparison isn't `==` here to avoid comparing spans,
- // but it *also* is a "probable" equality which is a pretty weird
- // definition. We mostly want to catch actual changes to the AST
- // like a `#[cfg]` being processed or some weird `macro_rules!`
- // expansion.
- //
- // What we *don't* want to catch is the fact that a user-defined
- // literal like `0xf` is stringified as `15`, causing the cached token
- // stream to not be literal `==` token-wise (ignoring spans) to the
- // token stream we got from stringification.
- //
- // Instead the "probably equal" check here is "does each token
- // recursively have the same discriminant?" We basically don't look at
- // the token values here and assume that such fine grained token stream
- // modifications, including adding/removing typically non-semantic
- // tokens such as extra braces and commas, don't happen.
if let Some(tokens) = tokens {
- if GOOD_TOKEN_CACHE.with(|cache| cache.borrow().contains(&source)) {
- return tokens;
- }
-
- // Compare with a non-relaxed delim match to start.
- if tokenstream_probably_equal_for_proc_macro(&tokens, &reparsed_tokens, sess, false) {
- GOOD_TOKEN_CACHE.with(|cache| cache.borrow_mut().insert(source.clone()));
- return tokens;
- }
-
- // The check failed. This time, we pretty-print the AST struct with parenthesis
- // inserted to preserve precedence. This may cause `None`-delimiters in the captured
- // token stream to match up with inserted parenthesis in the reparsed stream.
- let source_with_parens = pprust::nonterminal_to_string(nt);
- let filename_with_parens = FileName::macro_expansion_source_code(&source_with_parens);
-
- if GOOD_TOKEN_CACHE.with(|cache| cache.borrow().contains(&source_with_parens)) {
- return tokens;
- }
-
- let reparsed_tokens_with_parens = parse_stream_from_source_str(
- filename_with_parens,
- source_with_parens,
- sess,
- Some(span),
- );
-
- // Compare with a relaxed delim match - we want inserted parenthesis in the
- // reparsed stream to match `None`-delimiters in the original stream.
- if tokenstream_probably_equal_for_proc_macro(
- &tokens,
- &reparsed_tokens_with_parens,
- sess,
- true,
- ) {
- GOOD_TOKEN_CACHE.with(|cache| cache.borrow_mut().insert(source.clone()));
- return tokens;
- }
-
- info!(
- "cached tokens found, but they're not \"probably equal\", \
- going with stringified version"
- );
- info!("cached tokens: {}", pprust::tts_to_string(&tokens));
- info!("reparsed tokens: {}", pprust::tts_to_string(&reparsed_tokens_with_parens));
-
- info!("cached tokens debug: {:?}", tokens);
- info!("reparsed tokens debug: {:?}", reparsed_tokens_with_parens);
- }
- reparsed_tokens
-}
-
-// See comments in `Nonterminal::to_tokenstream` for why we care about
-// *probably* equal here rather than actual equality
-//
-// This is otherwise the same as `eq_unspanned`, only recursing with a
-// different method.
-pub fn tokenstream_probably_equal_for_proc_macro(
- tokens: &TokenStream,
- reparsed_tokens: &TokenStream,
- sess: &ParseSess,
- relaxed_delim_match: bool,
-) -> bool {
- // When checking for `probably_eq`, we ignore certain tokens that aren't
- // preserved in the AST. Because they are not preserved, the pretty
- // printer arbitrarily adds or removes them when printing as token
- // streams, making a comparison between a token stream generated from an
- // AST and a token stream which was parsed into an AST more reliable.
- fn semantic_tree(tree: &TokenTree) -> bool {
- if let TokenTree::Token(token) = tree {
- if let
- // The pretty printer tends to add trailing commas to
- // everything, and in particular, after struct fields.
- | token::Comma
- // The pretty printer collapses many semicolons into one.
- | token::Semi
- // We don't preserve leading `|` tokens in patterns, so
- // we ignore them entirely
- | token::BinOp(token::BinOpToken::Or)
- // We don't preserve trailing '+' tokens in trait bounds,
- // so we ignore them entirely
- | token::BinOp(token::BinOpToken::Plus)
- // The pretty printer can turn `$crate` into `::crate_name`
- | token::ModSep = token.kind {
- return false;
- }
- }
- true
- }
-
- // When comparing two `TokenStream`s, we ignore the `IsJoint` information.
- //
- // However, `rustc_parse::lexer::tokentrees::TokenStreamBuilder` will
- // use `Token.glue` on adjacent tokens with the proper `IsJoint`.
- // Since we are ignoreing `IsJoint`, a 'glued' token (e.g. `BinOp(Shr)`)
- // and its 'split'/'unglued' compoenents (e.g. `Gt, Gt`) are equivalent
- // when determining if two `TokenStream`s are 'probably equal'.
- //
- // Therefore, we use `break_two_token_op` to convert all tokens
- // to the 'unglued' form (if it exists). This ensures that two
- // `TokenStream`s which differ only in how their tokens are glued
- // will be considered 'probably equal', which allows us to keep spans.
- //
- // This is important when the original `TokenStream` contained
- // extra spaces (e.g. `f :: < Vec < _ > > ( ) ;'). These extra spaces
- // will be omitted when we pretty-print, which can cause the original
- // and reparsed `TokenStream`s to differ in the assignment of `IsJoint`,
- // leading to some tokens being 'glued' together in one stream but not
- // the other. See #68489 for more details.
- fn break_tokens(tree: TokenTree) -> impl Iterator<Item = TokenTree> {
- // In almost all cases, we should have either zero or one levels
- // of 'unglueing'. However, in some unusual cases, we may need
- // to iterate breaking tokens mutliple times. For example:
- // '[BinOpEq(Shr)] => [Gt, Ge] -> [Gt, Gt, Eq]'
- let mut token_trees: SmallVec<[_; 2]>;
- if let TokenTree::Token(token) = tree {
- let mut out = SmallVec::<[_; 2]>::new();
- out.push(token);
- // Iterate to fixpoint:
- // * We start off with 'out' containing our initial token, and `temp` empty
- // * If we are able to break any tokens in `out`, then `out` will have
- // at least one more element than 'temp', so we will try to break tokens
- // again.
- // * If we cannot break any tokens in 'out', we are done
- loop {
- let mut temp = SmallVec::<[_; 2]>::new();
- let mut changed = false;
-
- for token in out.into_iter() {
- if let Some((first, second)) = token.kind.break_two_token_op() {
- temp.push(Token::new(first, DUMMY_SP));
- temp.push(Token::new(second, DUMMY_SP));
- changed = true;
- } else {
- temp.push(token);
- }
- }
- out = temp;
- if !changed {
- break;
- }
- }
- token_trees = out.into_iter().map(TokenTree::Token).collect();
- } else {
- token_trees = SmallVec::new();
- token_trees.push(tree);
- }
- token_trees.into_iter()
- }
-
- fn expand_token(tree: TokenTree, sess: &ParseSess) -> impl Iterator<Item = TokenTree> {
- // When checking tokenstreams for 'probable equality', we are comparing
- // a captured (from parsing) `TokenStream` to a reparsed tokenstream.
- // The reparsed Tokenstream will never have `None`-delimited groups,
- // since they are only ever inserted as a result of macro expansion.
- // Therefore, inserting a `None`-delimtied group here (when we
- // convert a nested `Nonterminal` to a tokenstream) would cause
- // a mismatch with the reparsed tokenstream.
- //
- // Note that we currently do not handle the case where the
- // reparsed stream has a `Parenthesis`-delimited group
- // inserted. This will cause a spurious mismatch:
- // issue #75734 tracks resolving this.
-
- let expanded: SmallVec<[_; 1]> =
- if let TokenTree::Token(Token { kind: TokenKind::Interpolated(nt), span }) = &tree {
- nt_to_tokenstream(nt, sess, *span)
- .into_trees()
- .flat_map(|t| expand_token(t, sess))
- .collect()
- } else {
- // Filter before and after breaking tokens,
- // since we may want to ignore both glued and unglued tokens.
- std::iter::once(tree)
- .filter(semantic_tree)
- .flat_map(break_tokens)
- .filter(semantic_tree)
- .collect()
- };
- expanded.into_iter()
- }
-
- // Break tokens after we expand any nonterminals, so that we break tokens
- // that are produced as a result of nonterminal expansion.
- let tokens = tokens.trees().flat_map(|t| expand_token(t, sess));
- let reparsed_tokens = reparsed_tokens.trees().flat_map(|t| expand_token(t, sess));
-
- tokens.eq_by(reparsed_tokens, |t, rt| {
- tokentree_probably_equal_for_proc_macro(&t, &rt, sess, relaxed_delim_match)
- })
-}
-
-// See comments in `Nonterminal::to_tokenstream` for why we care about
-// *probably* equal here rather than actual equality
-//
-// This is otherwise the same as `eq_unspanned`, only recursing with a
-// different method.
-pub fn tokentree_probably_equal_for_proc_macro(
- token: &TokenTree,
- reparsed_token: &TokenTree,
- sess: &ParseSess,
- relaxed_delim_match: bool,
-) -> bool {
- match (token, reparsed_token) {
- (TokenTree::Token(token), TokenTree::Token(reparsed_token)) => {
- token_probably_equal_for_proc_macro(token, reparsed_token)
- }
- (
- TokenTree::Delimited(_, delim, tokens),
- TokenTree::Delimited(_, reparsed_delim, reparsed_tokens),
- ) if delim == reparsed_delim => tokenstream_probably_equal_for_proc_macro(
- tokens,
- reparsed_tokens,
- sess,
- relaxed_delim_match,
- ),
- (TokenTree::Delimited(_, DelimToken::NoDelim, tokens), reparsed_token) => {
- if relaxed_delim_match {
- if let TokenTree::Delimited(_, DelimToken::Paren, reparsed_tokens) = reparsed_token
- {
- if tokenstream_probably_equal_for_proc_macro(
- tokens,
- reparsed_tokens,
- sess,
- relaxed_delim_match,
- ) {
- return true;
- }
- }
- }
- tokens.len() == 1
- && tokentree_probably_equal_for_proc_macro(
- &tokens.trees().next().unwrap(),
- reparsed_token,
- sess,
- relaxed_delim_match,
- )
- }
- _ => false,
+ return tokens;
+ } else if matches!(synthesize_tokens, CanSynthesizeMissingTokens::Yes) {
+ return fake_token_stream(sess, nt);
+ } else {
+ panic!("Missing tokens for nt at {:?}: {:?}", nt.span(), pprust::nonterminal_to_string(nt));
}
}
-// See comments in `Nonterminal::to_tokenstream` for why we care about
-// *probably* equal here rather than actual equality
-fn token_probably_equal_for_proc_macro(first: &Token, other: &Token) -> bool {
- if mem::discriminant(&first.kind) != mem::discriminant(&other.kind) {
- return false;
- }
- use rustc_ast::token::TokenKind::*;
- match (&first.kind, &other.kind) {
- (&Eq, &Eq)
- | (&Lt, &Lt)
- | (&Le, &Le)
- | (&EqEq, &EqEq)
- | (&Ne, &Ne)
- | (&Ge, &Ge)
- | (&Gt, &Gt)
- | (&AndAnd, &AndAnd)
- | (&OrOr, &OrOr)
- | (&Not, &Not)
- | (&Tilde, &Tilde)
- | (&At, &At)
- | (&Dot, &Dot)
- | (&DotDot, &DotDot)
- | (&DotDotDot, &DotDotDot)
- | (&DotDotEq, &DotDotEq)
- | (&Comma, &Comma)
- | (&Semi, &Semi)
- | (&Colon, &Colon)
- | (&ModSep, &ModSep)
- | (&RArrow, &RArrow)
- | (&LArrow, &LArrow)
- | (&FatArrow, &FatArrow)
- | (&Pound, &Pound)
- | (&Dollar, &Dollar)
- | (&Question, &Question)
- | (&Eof, &Eof) => true,
-
- (&BinOp(a), &BinOp(b)) | (&BinOpEq(a), &BinOpEq(b)) => a == b,
-
- (&OpenDelim(a), &OpenDelim(b)) | (&CloseDelim(a), &CloseDelim(b)) => a == b,
-
- (&DocComment(a1, a2, a3), &DocComment(b1, b2, b3)) => a1 == b1 && a2 == b2 && a3 == b3,
-
- (&Literal(a), &Literal(b)) => a == b,
-
- (&Lifetime(a), &Lifetime(b)) => a == b,
- (&Ident(a, b), &Ident(c, d)) => {
- b == d && (a == c || a == kw::DollarCrate || c == kw::DollarCrate)
- }
-
- (&Interpolated(..), &Interpolated(..)) => panic!("Unexpanded Interpolated!"),
-
- _ => panic!("forgot to add a token?"),
- }
+pub fn fake_token_stream(sess: &ParseSess, nt: &Nonterminal) -> TokenStream {
+ let source = pprust::nonterminal_to_string(nt);
+ let filename = FileName::macro_expansion_source_code(&source);
+ parse_stream_from_source_str(filename, source, sess, Some(nt.span()))
}
fn prepend_attrs(
+ sess: &ParseSess,
attrs: &[ast::Attribute],
+ nt: &Nonterminal,
tokens: Option<&tokenstream::LazyTokenStream>,
) -> Option<tokenstream::TokenStream> {
- let tokens = tokens?.create_token_stream();
if attrs.is_empty() {
- return Some(tokens);
+ return Some(tokens?.create_token_stream());
}
let mut builder = tokenstream::TokenStreamBuilder::new();
for attr in attrs {
// FIXME: Correctly handle tokens for inner attributes.
// For now, we fall back to reparsing the original AST node
if attr.style == ast::AttrStyle::Inner {
- return None;
+ return Some(fake_token_stream(sess, nt));
}
builder.push(attr.tokens());
}
- builder.push(tokens);
+ builder.push(tokens?.create_token_stream());
Some(builder.build())
}
diff --git a/compiler/rustc_parse/src/parser/attr.rs b/compiler/rustc_parse/src/parser/attr.rs
index fae09fa..1b26fb3 100644
--- a/compiler/rustc_parse/src/parser/attr.rs
+++ b/compiler/rustc_parse/src/parser/attr.rs
@@ -89,7 +89,7 @@
inner_parse_policy, self.token
);
let lo = self.token.span;
- let ((item, style, span), tokens) = self.collect_tokens(|this| {
+ self.collect_tokens(|this| {
if this.eat(&token::Pound) {
let style = if this.eat(&token::Not) {
ast::AttrStyle::Inner
@@ -107,15 +107,13 @@
this.error_on_forbidden_inner_attr(attr_sp, inner_parse_policy);
}
- Ok((item, style, attr_sp))
+ Ok(attr::mk_attr_from_item(item, None, style, attr_sp))
} else {
let token_str = pprust::token_to_string(&this.token);
let msg = &format!("expected `#`, found `{}`", token_str);
Err(this.struct_span_err(this.token.span, msg))
}
- })?;
-
- Ok(attr::mk_attr_from_item(item, tokens, style, span))
+ })
}
pub(super) fn error_on_forbidden_inner_attr(&self, attr_sp: Span, policy: InnerAttrPolicy<'_>) {
@@ -165,13 +163,7 @@
let args = this.parse_attr_args()?;
Ok(ast::AttrItem { path, args, tokens: None })
};
- if capture_tokens {
- let (mut item, tokens) = self.collect_tokens(do_parse)?;
- item.tokens = tokens;
- item
- } else {
- do_parse(self)?
- }
+ if capture_tokens { self.collect_tokens(do_parse) } else { do_parse(self) }?
})
}
diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs
index 98c7b9a..5512e84 100644
--- a/compiler/rustc_parse/src/parser/diagnostics.rs
+++ b/compiler/rustc_parse/src/parser/diagnostics.rs
@@ -2,14 +2,13 @@
use super::TokenType;
use super::{BlockMode, Parser, PathStyle, Restrictions, SemiColonMode, SeqSep, TokenExpectType};
+use rustc_ast as ast;
use rustc_ast::ptr::P;
use rustc_ast::token::{self, Lit, LitKind, TokenKind};
use rustc_ast::util::parser::AssocOp;
-use rustc_ast::{
- self as ast, AngleBracketedArg, AngleBracketedArgs, AnonConst, AttrVec, BinOpKind, BindingMode,
- Block, BlockCheckMode, Expr, ExprKind, GenericArg, Item, ItemKind, Mutability, Param, Pat,
- PatKind, Path, PathSegment, QSelf, Ty, TyKind,
-};
+use rustc_ast::{AngleBracketedArg, AngleBracketedArgs, AnonConst, AttrVec};
+use rustc_ast::{BinOpKind, BindingMode, Block, BlockCheckMode, Expr, ExprKind, GenericArg, Item};
+use rustc_ast::{ItemKind, Mutability, Param, Pat, PatKind, Path, PathSegment, QSelf, Ty, TyKind};
use rustc_ast_pretty::pprust;
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::{pluralize, struct_span_err};
@@ -220,6 +219,7 @@
edible: &[TokenKind],
inedible: &[TokenKind],
) -> PResult<'a, bool /* recovered */> {
+ debug!("expected_one_of_not_found(edible: {:?}, inedible: {:?})", edible, inedible);
fn tokens_to_string(tokens: &[TokenType]) -> String {
let mut i = tokens.iter();
// This might be a sign we need a connect method on `Iterator`.
@@ -245,6 +245,7 @@
.collect::<Vec<_>>();
expected.sort_by_cached_key(|x| x.to_string());
expected.dedup();
+
let expect = tokens_to_string(&expected[..]);
let actual = super::token_descr(&self.token);
let (msg_exp, (label_sp, label_exp)) = if expected.len() > 1 {
@@ -270,6 +271,16 @@
};
self.last_unexpected_token_span = Some(self.token.span);
let mut err = self.struct_span_err(self.token.span, &msg_exp);
+
+ // Add suggestion for a missing closing angle bracket if '>' is included in expected_tokens
+ // there are unclosed angle brackets
+ if self.unmatched_angle_bracket_count > 0
+ && self.token.kind == TokenKind::Eq
+ && expected.iter().any(|tok| matches!(tok, TokenType::Token(TokenKind::Gt)))
+ {
+ err.span_label(self.prev_token.span, "maybe try to close unmatched angle bracket");
+ }
+
let sp = if self.token == token::Eof {
// This is EOF; don't want to point at the following char, but rather the last token.
self.prev_token.span
@@ -511,7 +522,7 @@
//
// `x.foo::<u32>>>(3)`
let parsed_angle_bracket_args =
- segment.args.as_ref().map(|args| args.is_angle_bracketed()).unwrap_or(false);
+ segment.args.as_ref().map_or(false, |args| args.is_angle_bracketed());
debug!(
"check_trailing_angle_brackets: parsed_angle_bracket_args={:?}",
@@ -1093,7 +1104,7 @@
let (prev_sp, sp) = match (&self.token.kind, self.subparser_name) {
// Point at the end of the macro call when reaching end of macro arguments.
(token::Eof, Some(_)) => {
- let sp = self.sess.source_map().next_point(self.token.span);
+ let sp = self.sess.source_map().next_point(self.prev_token.span);
(sp, sp)
}
// We don't want to point at the following span after DUMMY_SP.
@@ -1710,7 +1721,7 @@
pub(super) fn expected_expression_found(&self) -> DiagnosticBuilder<'a> {
let (span, msg) = match (&self.token.kind, self.subparser_name) {
(&token::Eof, Some(origin)) => {
- let sp = self.sess.source_map().next_point(self.token.span);
+ let sp = self.sess.source_map().next_point(self.prev_token.span);
(sp, format!("expected expression, found end of {}", origin))
}
_ => (
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index b147f42..cfd7ad4 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -15,6 +15,7 @@
use rustc_ast::{Arm, Async, BlockCheckMode, Expr, ExprKind, Label, Movability, RangeLimits};
use rustc_ast_pretty::pprust;
use rustc_errors::{Applicability, DiagnosticBuilder, PResult};
+use rustc_span::edition::LATEST_STABLE_EDITION;
use rustc_span::source_map::{self, Span, Spanned};
use rustc_span::symbol::{kw, sym, Ident, Symbol};
use rustc_span::{BytePos, Pos};
@@ -471,7 +472,12 @@
/// Parses a prefix-unary-operator expr.
fn parse_prefix_expr(&mut self, attrs: Option<AttrVec>) -> PResult<'a, P<Expr>> {
let attrs = self.parse_or_use_outer_attributes(attrs)?;
- self.maybe_collect_tokens(super::attr::maybe_needs_tokens(&attrs), |this| {
+ // FIXME: Use super::attr::maybe_needs_tokens(&attrs) once we come up
+ // with a good way of passing `force_tokens` through from `parse_nonterminal`.
+ // Checking !attrs.is_empty() is correct, but will cause us to unnecessarily
+ // capture tokens in some circumstances.
+ let needs_tokens = !attrs.is_empty();
+ let do_parse = |this: &mut Parser<'a>| {
let lo = this.token.span;
// Note: when adding new unary operators, don't forget to adjust TokenKind::can_begin_expr()
let (hi, ex) = match this.token.uninterpolate().kind {
@@ -487,7 +493,8 @@
_ => return this.parse_dot_or_call_expr(Some(attrs)),
}?;
Ok(this.mk_expr(lo.to(hi), ex, attrs))
- })
+ };
+ if needs_tokens { self.collect_tokens(do_parse) } else { do_parse(self) }
}
fn parse_prefix_expr_common(&mut self, lo: Span) -> PResult<'a, (Span, P<Expr>)> {
@@ -578,7 +585,7 @@
lhs_span: Span,
expr_kind: fn(P<Expr>, P<Ty>) -> ExprKind,
) -> PResult<'a, P<Expr>> {
- let mk_expr = |this: &mut Self, rhs: P<Ty>| {
+ let mk_expr = |this: &mut Self, lhs: P<Expr>, rhs: P<Ty>| {
this.mk_expr(
this.mk_expr_sp(&lhs, lhs_span, rhs.span),
expr_kind(lhs, rhs),
@@ -590,13 +597,49 @@
// LessThan comparison after this cast.
let parser_snapshot_before_type = self.clone();
let cast_expr = match self.parse_ty_no_plus() {
- Ok(rhs) => mk_expr(self, rhs),
+ Ok(rhs) => mk_expr(self, lhs, rhs),
Err(mut type_err) => {
// Rewind to before attempting to parse the type with generics, to recover
// from situations like `x as usize < y` in which we first tried to parse
// `usize < y` as a type with generic arguments.
let parser_snapshot_after_type = mem::replace(self, parser_snapshot_before_type);
+ // Check for typo of `'a: loop { break 'a }` with a missing `'`.
+ match (&lhs.kind, &self.token.kind) {
+ (
+ // `foo: `
+ ExprKind::Path(None, ast::Path { segments, .. }),
+ TokenKind::Ident(kw::For | kw::Loop | kw::While, false),
+ ) if segments.len() == 1 => {
+ let snapshot = self.clone();
+ let label = Label {
+ ident: Ident::from_str_and_span(
+ &format!("'{}", segments[0].ident),
+ segments[0].ident.span,
+ ),
+ };
+ match self.parse_labeled_expr(label, AttrVec::new(), false) {
+ Ok(expr) => {
+ type_err.cancel();
+ self.struct_span_err(label.ident.span, "malformed loop label")
+ .span_suggestion(
+ label.ident.span,
+ "use the correct loop label format",
+ label.ident.to_string(),
+ Applicability::MachineApplicable,
+ )
+ .emit();
+ return Ok(expr);
+ }
+ Err(mut err) => {
+ err.cancel();
+ *self = snapshot;
+ }
+ }
+ }
+ _ => {}
+ }
+
match self.parse_path(PathStyle::Expr) {
Ok(path) => {
let (op_noun, op_verb) = match self.token.kind {
@@ -623,7 +666,8 @@
op_noun,
);
let span_after_type = parser_snapshot_after_type.token.span;
- let expr = mk_expr(self, self.mk_ty(path.span, TyKind::Path(None, path)));
+ let expr =
+ mk_expr(self, lhs, self.mk_ty(path.span, TyKind::Path(None, path)));
let expr_str = self
.span_to_snippet(expr.span)
@@ -1060,7 +1104,7 @@
} else if self.eat_keyword(kw::While) {
self.parse_while_expr(None, self.prev_token.span, attrs)
} else if let Some(label) = self.eat_label() {
- self.parse_labeled_expr(label, attrs)
+ self.parse_labeled_expr(label, attrs, true)
} else if self.eat_keyword(kw::Loop) {
self.parse_loop_expr(None, self.prev_token.span, attrs)
} else if self.eat_keyword(kw::Continue) {
@@ -1124,20 +1168,6 @@
}
}
- fn maybe_collect_tokens(
- &mut self,
- needs_tokens: bool,
- f: impl FnOnce(&mut Self) -> PResult<'a, P<Expr>>,
- ) -> PResult<'a, P<Expr>> {
- if needs_tokens {
- let (mut expr, tokens) = self.collect_tokens(f)?;
- expr.tokens = tokens;
- Ok(expr)
- } else {
- f(self)
- }
- }
-
fn parse_lit_expr(&mut self, attrs: AttrVec) -> PResult<'a, P<Expr>> {
let lo = self.token.span;
match self.parse_opt_lit() {
@@ -1235,7 +1265,12 @@
}
/// Parse `'label: $expr`. The label is already parsed.
- fn parse_labeled_expr(&mut self, label: Label, attrs: AttrVec) -> PResult<'a, P<Expr>> {
+ fn parse_labeled_expr(
+ &mut self,
+ label: Label,
+ attrs: AttrVec,
+ consume_colon: bool,
+ ) -> PResult<'a, P<Expr>> {
let lo = label.ident.span;
let label = Some(label);
let ate_colon = self.eat(&token::Colon);
@@ -1254,7 +1289,7 @@
self.parse_expr()
}?;
- if !ate_colon {
+ if !ate_colon && consume_colon {
self.error_labeled_expr_must_be_followed_by_colon(lo, expr.span);
}
@@ -1598,10 +1633,6 @@
} else {
Async::No
};
- if let Async::Yes { span, .. } = asyncness {
- // Feature-gate `async ||` closures.
- self.sess.gated_spans.gate(sym::async_closure, span);
- }
let capture_clause = self.parse_capture_clause()?;
let decl = self.parse_fn_block_decl()?;
@@ -1618,6 +1649,11 @@
}
};
+ if let Async::Yes { span, .. } = asyncness {
+ // Feature-gate `async ||` closures.
+ self.sess.gated_spans.gate(sym::async_closure, span);
+ }
+
Ok(self.mk_expr(
lo.to(body.span),
ExprKind::Closure(capture_clause, asyncness, movability, decl, body, lo.to(decl_hi)),
@@ -2108,8 +2144,8 @@
let mut async_block_err = |e: &mut DiagnosticBuilder<'_>, span: Span| {
recover_async = true;
- e.span_label(span, "`async` blocks are only allowed in the 2018 edition");
- e.help("set `edition = \"2018\"` in `Cargo.toml`");
+ e.span_label(span, "`async` blocks are only allowed in Rust 2018 or later");
+ e.help(&format!("set `edition = \"{}\"` in `Cargo.toml`", LATEST_STABLE_EDITION));
e.note("for more on editions, read https://doc.rust-lang.org/edition-guide");
};
diff --git a/compiler/rustc_parse/src/parser/generics.rs b/compiler/rustc_parse/src/parser/generics.rs
index ed8d4f7..42a1337 100644
--- a/compiler/rustc_parse/src/parser/generics.rs
+++ b/compiler/rustc_parse/src/parser/generics.rs
@@ -56,14 +56,26 @@
self.expect(&token::Colon)?;
let ty = self.parse_ty()?;
- self.sess.gated_spans.gate(sym::min_const_generics, const_span.to(self.prev_token.span));
+ // Parse optional const generics default value, taking care of feature gating the spans
+ // with the unstable syntax mechanism.
+ let default = if self.eat(&token::Eq) {
+ // The gated span goes from the `=` to the end of the const argument that follows (and
+ // which could be a block expression).
+ let start = self.prev_token.span;
+ let const_arg = self.parse_const_arg()?;
+ let span = start.to(const_arg.value.span);
+ self.sess.gated_spans.gate(sym::const_generics_defaults, span);
+ Some(const_arg)
+ } else {
+ None
+ };
Ok(GenericParam {
ident,
id: ast::DUMMY_NODE_ID,
attrs: preceding_attrs.into(),
bounds: Vec::new(),
- kind: GenericParamKind::Const { ty, kw_span: const_span },
+ kind: GenericParamKind::Const { ty, kw_span: const_span, default },
is_placeholder: false,
})
}
diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs
index 634cce4..ee24286 100644
--- a/compiler/rustc_parse/src/parser/item.rs
+++ b/compiler/rustc_parse/src/parser/item.rs
@@ -1,14 +1,14 @@
use super::diagnostics::{dummy_arg, ConsumeClosingDelim, Error};
use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign};
-use super::{FollowedByType, Parser, PathStyle};
+use super::{FollowedByType, ForceCollect, Parser, PathStyle, TrailingToken};
-use crate::maybe_whole;
+use crate::{maybe_collect_tokens, maybe_whole};
+use rustc_ast::ast::*;
use rustc_ast::ptr::P;
use rustc_ast::token::{self, TokenKind};
use rustc_ast::tokenstream::{DelimSpan, TokenStream, TokenTree};
use rustc_ast::{self as ast, AttrVec, Attribute, DUMMY_NODE_ID};
-use rustc_ast::{AssocItem, AssocItemKind, ForeignItemKind, Item, ItemKind, Mod};
use rustc_ast::{Async, Const, Defaultness, IsAuto, Mutability, Unsafe, UseTree, UseTreeKind};
use rustc_ast::{BindingMode, Block, FnDecl, FnSig, Param, SelfKind};
use rustc_ast::{EnumDef, Generics, StructField, TraitRef, Ty, TyKind, Variant, VariantData};
@@ -16,7 +16,7 @@
use rustc_ast::{MacArgs, MacCall, MacDelimiter};
use rustc_ast_pretty::pprust;
use rustc_errors::{struct_span_err, Applicability, PResult, StashKey};
-use rustc_span::edition::Edition;
+use rustc_span::edition::{Edition, LATEST_STABLE_EDITION};
use rustc_span::source_map::{self, Span};
use rustc_span::symbol::{kw, sym, Ident, Symbol};
@@ -69,7 +69,7 @@
unsafety: Unsafe,
) -> PResult<'a, Mod> {
let mut items = vec![];
- while let Some(item) = self.parse_item()? {
+ while let Some(item) = self.parse_item(ForceCollect::No)? {
items.push(item);
self.maybe_consume_incorrect_semicolon(&items);
}
@@ -93,13 +93,17 @@
pub(super) type ItemInfo = (Ident, ItemKind);
impl<'a> Parser<'a> {
- pub fn parse_item(&mut self) -> PResult<'a, Option<P<Item>>> {
- self.parse_item_(|_| true).map(|i| i.map(P))
+ pub fn parse_item(&mut self, force_collect: ForceCollect) -> PResult<'a, Option<P<Item>>> {
+ self.parse_item_(|_| true, force_collect).map(|i| i.map(P))
}
- fn parse_item_(&mut self, req_name: ReqName) -> PResult<'a, Option<Item>> {
+ fn parse_item_(
+ &mut self,
+ req_name: ReqName,
+ force_collect: ForceCollect,
+ ) -> PResult<'a, Option<Item>> {
let attrs = self.parse_outer_attributes()?;
- self.parse_item_common(attrs, true, false, req_name)
+ self.parse_item_common(attrs, true, false, req_name, force_collect)
}
pub(super) fn parse_item_common(
@@ -108,6 +112,7 @@
mac_allowed: bool,
attrs_allowed: bool,
req_name: ReqName,
+ force_collect: ForceCollect,
) -> PResult<'a, Option<Item>> {
maybe_whole!(self, NtItem, |item| {
let mut item = item;
@@ -116,28 +121,12 @@
Some(item.into_inner())
});
- let needs_tokens = super::attr::maybe_needs_tokens(&attrs);
-
let mut unclosed_delims = vec![];
- let parse_item = |this: &mut Self| {
+ let item = maybe_collect_tokens!(self, force_collect, &attrs, |this: &mut Self| {
let item = this.parse_item_common_(attrs, mac_allowed, attrs_allowed, req_name);
unclosed_delims.append(&mut this.unclosed_delims);
- item
- };
-
- let (mut item, tokens) = if needs_tokens {
- let (item, tokens) = self.collect_tokens(parse_item)?;
- (item, tokens)
- } else {
- (parse_item(self)?, None)
- };
- if let Some(item) = &mut item {
- // If we captured tokens during parsing (due to encountering an `NtItem`),
- // use those instead
- if item.tokens.is_none() {
- item.tokens = tokens;
- }
- }
+ Ok((item?, TrailingToken::None))
+ })?;
self.unclosed_delims.append(&mut unclosed_delims);
Ok(item)
@@ -220,12 +209,27 @@
let info = if self.eat_keyword(kw::Use) {
// USE ITEM
let tree = self.parse_use_tree()?;
- self.expect_semi()?;
+
+ // If wildcard or glob-like brace syntax doesn't have `;`,
+ // the user may not know `*` or `{}` should be the last.
+ if let Err(mut e) = self.expect_semi() {
+ match tree.kind {
+ UseTreeKind::Glob => {
+ e.note("the wildcard token must be last on the path").emit();
+ }
+ UseTreeKind::Nested(..) => {
+ e.note("glob-like brace syntax must be last on the path").emit();
+ }
+ _ => (),
+ }
+ return Err(e);
+ }
+
(Ident::invalid(), ItemKind::Use(P(tree)))
} else if self.check_fn_front_matter() {
// FUNCTION ITEM
let (ident, sig, generics, body) = self.parse_fn(attrs, req_name, lo)?;
- (ident, ItemKind::Fn(def(), sig, generics, body))
+ (ident, ItemKind::Fn(box FnKind(def(), sig, generics, body)))
} else if self.eat_keyword(kw::Extern) {
if self.eat_keyword(kw::Crate) {
// EXTERN CRATE
@@ -494,7 +498,7 @@
let polarity = self.parse_polarity();
// Parse both types and traits as a type, then reinterpret if necessary.
- let err_path = |span| ast::Path::from_ident(Ident::new(kw::Invalid, span));
+ let err_path = |span| ast::Path::from_ident(Ident::new(kw::Empty, span));
let ty_first = if self.token.is_keyword(kw::For) && self.look_ahead(1, |t| t != &token::Lt)
{
let span = self.prev_token.span.between(self.token.span);
@@ -552,7 +556,7 @@
};
let trait_ref = TraitRef { path, ref_id: ty_first.id };
- ItemKind::Impl {
+ ItemKind::Impl(box ImplKind {
unsafety,
polarity,
defaultness,
@@ -561,11 +565,11 @@
of_trait: Some(trait_ref),
self_ty: ty_second,
items: impl_items,
- }
+ })
}
None => {
// impl Type
- ItemKind::Impl {
+ ItemKind::Impl(box ImplKind {
unsafety,
polarity,
defaultness,
@@ -574,7 +578,7 @@
of_trait: None,
self_ty: ty_first,
items: impl_items,
- }
+ })
}
};
@@ -714,7 +718,7 @@
// It's a normal trait.
tps.where_clause = self.parse_where_clause()?;
let items = self.parse_item_list(attrs, |p| p.parse_trait_item())?;
- Ok((ident, ItemKind::Trait(is_auto, unsafety, tps, bounds, items)))
+ Ok((ident, ItemKind::Trait(box TraitKind(is_auto, unsafety, tps, bounds, items))))
}
}
@@ -728,20 +732,22 @@
/// Parses associated items.
fn parse_assoc_item(&mut self, req_name: ReqName) -> PResult<'a, Option<Option<P<AssocItem>>>> {
- Ok(self.parse_item_(req_name)?.map(|Item { attrs, id, span, vis, ident, kind, tokens }| {
- let kind = match AssocItemKind::try_from(kind) {
- Ok(kind) => kind,
- Err(kind) => match kind {
- ItemKind::Static(a, _, b) => {
- self.struct_span_err(span, "associated `static` items are not allowed")
- .emit();
- AssocItemKind::Const(Defaultness::Final, a, b)
- }
- _ => return self.error_bad_item_kind(span, &kind, "`trait`s or `impl`s"),
- },
- };
- Some(P(Item { attrs, id, span, vis, ident, kind, tokens }))
- }))
+ Ok(self.parse_item_(req_name, ForceCollect::No)?.map(
+ |Item { attrs, id, span, vis, ident, kind, tokens }| {
+ let kind = match AssocItemKind::try_from(kind) {
+ Ok(kind) => kind,
+ Err(kind) => match kind {
+ ItemKind::Static(a, _, b) => {
+ self.struct_span_err(span, "associated `static` items are not allowed")
+ .emit();
+ AssocItemKind::Const(Defaultness::Final, a, b)
+ }
+ _ => return self.error_bad_item_kind(span, &kind, "`trait`s or `impl`s"),
+ },
+ };
+ Some(P(Item { attrs, id, span, vis, ident, kind, tokens }))
+ },
+ ))
}
/// Parses a `type` alias with the following grammar:
@@ -761,7 +767,7 @@
let default = if self.eat(&token::Eq) { Some(self.parse_ty()?) } else { None };
self.expect_semi()?;
- Ok((ident, ItemKind::TyAlias(def, generics, bounds, default)))
+ Ok((ident, ItemKind::TyAlias(box TyAliasKind(def, generics, bounds, default))))
}
/// Parses a `UseTree`.
@@ -918,19 +924,21 @@
/// Parses a foreign item (one in an `extern { ... }` block).
pub fn parse_foreign_item(&mut self) -> PResult<'a, Option<Option<P<ForeignItem>>>> {
- Ok(self.parse_item_(|_| true)?.map(|Item { attrs, id, span, vis, ident, kind, tokens }| {
- let kind = match ForeignItemKind::try_from(kind) {
- Ok(kind) => kind,
- Err(kind) => match kind {
- ItemKind::Const(_, a, b) => {
- self.error_on_foreign_const(span, ident);
- ForeignItemKind::Static(a, Mutability::Not, b)
- }
- _ => return self.error_bad_item_kind(span, &kind, "`extern` blocks"),
- },
- };
- Some(P(Item { attrs, id, span, vis, ident, kind, tokens }))
- }))
+ Ok(self.parse_item_(|_| true, ForceCollect::No)?.map(
+ |Item { attrs, id, span, vis, ident, kind, tokens }| {
+ let kind = match ForeignItemKind::try_from(kind) {
+ Ok(kind) => kind,
+ Err(kind) => match kind {
+ ItemKind::Const(_, a, b) => {
+ self.error_on_foreign_const(span, ident);
+ ForeignItemKind::Static(a, Mutability::Not, b)
+ }
+ _ => return self.error_bad_item_kind(span, &kind, "`extern` blocks"),
+ },
+ };
+ Some(P(Item { attrs, id, span, vis, ident, kind, tokens }))
+ },
+ ))
}
fn error_bad_item_kind<T>(&self, span: Span, kind: &ItemKind, ctx: &str) -> Option<T> {
@@ -1002,10 +1010,21 @@
) -> PResult<'a, ItemInfo> {
let impl_span = self.token.span;
let mut err = self.expected_ident_found();
- let mut impl_info = self.parse_item_impl(attrs, defaultness)?;
+
+ // Only try to recover if this is implementing a trait for a type
+ let mut impl_info = match self.parse_item_impl(attrs, defaultness) {
+ Ok(impl_info) => impl_info,
+ Err(mut recovery_error) => {
+ // Recovery failed, raise the "expected identifier" error
+ recovery_error.cancel();
+ return Err(err);
+ }
+ };
+
match impl_info.1 {
- // only try to recover if this is implementing a trait for a type
- ItemKind::Impl { of_trait: Some(ref trai), ref mut constness, .. } => {
+ ItemKind::Impl(box ImplKind {
+ of_trait: Some(ref trai), ref mut constness, ..
+ }) => {
*constness = Const::Yes(const_span);
let before_trait = trai.path.span.shrink_to_lo();
@@ -1020,6 +1039,7 @@
ItemKind::Impl { .. } => return Err(err),
_ => unreachable!(),
}
+
Ok(impl_info)
}
@@ -1512,7 +1532,7 @@
{
let kw_token = self.token.clone();
let kw_str = pprust::token_to_string(&kw_token);
- let item = self.parse_item()?;
+ let item = self.parse_item(ForceCollect::No)?;
self.struct_span_err(
kw_token.span,
@@ -1667,9 +1687,9 @@
fn ban_async_in_2015(&self, span: Span) {
if span.rust_2015() {
let diag = self.diagnostic();
- struct_span_err!(diag, span, E0670, "`async fn` is not permitted in the 2015 edition")
- .span_label(span, "to use `async fn`, switch to Rust 2018")
- .help("set `edition = \"2018\"` in `Cargo.toml`")
+ struct_span_err!(diag, span, E0670, "`async fn` is not permitted in Rust 2015")
+ .span_label(span, "to use `async fn`, switch to Rust 2018 or later")
+ .help(&format!("set `edition = \"{}\"` in `Cargo.toml`", LATEST_STABLE_EDITION))
.note("for more on editions, read https://doc.rust-lang.org/edition-guide")
.emit();
}
@@ -1699,7 +1719,7 @@
// Skip every token until next possible arg or end.
p.eat_to_tokens(&[&token::Comma, &token::CloseDelim(token::Paren)]);
// Create a placeholder argument for proper arg count (issue #34264).
- Ok(dummy_arg(Ident::new(kw::Invalid, lo.to(p.prev_token.span))))
+ Ok(dummy_arg(Ident::new(kw::Empty, lo.to(p.prev_token.span))))
});
// ...now that we've parsed the first argument, `self` is no longer allowed.
first_param = false;
@@ -1759,7 +1779,7 @@
}
match ty {
Ok(ty) => {
- let ident = Ident::new(kw::Invalid, self.prev_token.span);
+ let ident = Ident::new(kw::Empty, self.prev_token.span);
let bm = BindingMode::ByValue(Mutability::Not);
let pat = self.mk_pat_ident(ty.span, bm, ident);
(pat, ty)
diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs
index e19ebb8..e2af63d 100644
--- a/compiler/rustc_parse/src/parser/mod.rs
+++ b/compiler/rustc_parse/src/parser/mod.rs
@@ -12,7 +12,6 @@
use crate::lexer::UnmatchedBrace;
pub use diagnostics::AttemptLocalParseRecovery;
use diagnostics::Error;
-pub use pat::OrPatNonterminalMode;
pub use path::PathStyle;
use rustc_ast::ptr::P;
@@ -20,8 +19,8 @@
use rustc_ast::tokenstream::{self, DelimSpan, LazyTokenStream, Spacing};
use rustc_ast::tokenstream::{CreateTokenStream, TokenStream, TokenTree, TreeAndSpacing};
use rustc_ast::DUMMY_NODE_ID;
-use rustc_ast::{self as ast, AnonConst, AttrStyle, AttrVec, Const, CrateSugar, Extern, Unsafe};
-use rustc_ast::{Async, Expr, ExprKind, MacArgs, MacDelimiter, Mutability, StrLit};
+use rustc_ast::{self as ast, AnonConst, AttrStyle, AttrVec, Const, CrateSugar, Extern, HasTokens};
+use rustc_ast::{Async, Expr, ExprKind, MacArgs, MacDelimiter, Mutability, StrLit, Unsafe};
use rustc_ast::{Visibility, VisibilityKind};
use rustc_ast_pretty::pprust;
use rustc_data_structures::sync::Lrc;
@@ -55,6 +54,18 @@
Ignore,
}
+/// Whether or not we should force collection of tokens for an AST node,
+/// regardless of whether or not it has attributes
+pub enum ForceCollect {
+ Yes,
+ No,
+}
+
+pub enum TrailingToken {
+ None,
+ Semi,
+}
+
/// Like `maybe_whole_expr`, but for things other than expressions.
#[macro_export]
macro_rules! maybe_whole {
@@ -266,7 +277,7 @@
}
}
-#[derive(Clone, PartialEq)]
+#[derive(Debug, Clone, PartialEq)]
enum TokenType {
Token(TokenKind),
Keyword(Symbol),
@@ -721,13 +732,9 @@
Ok(t) => {
// Parsed successfully, therefore most probably the code only
// misses a separator.
- let mut exp_span = self.sess.source_map().next_point(sp);
- if self.sess.source_map().is_multiline(exp_span) {
- exp_span = sp;
- }
expect_err
.span_suggestion_short(
- exp_span,
+ sp,
&format!("missing `{}`", token_str),
token_str,
Applicability::MaybeIncorrect,
@@ -973,12 +980,8 @@
}
}
- // The value here is never passed to macros as tokens by itself (not as a part
- // of the whole attribute), so we don't collect tokens here. If this changes,
- // then token will need to be collected. One catch here is that we are using
- // a nonterminal for keeping the expression, but this nonterminal should not
- // be wrapped into a group when converting to token stream.
- let expr = self.parse_expr()?;
+ // Collect tokens because they are used during lowering to HIR.
+ let expr = self.collect_tokens(|this| this.parse_expr())?;
let span = expr.span;
match &expr.kind {
@@ -988,8 +991,8 @@
_ => self.sess.gated_spans.gate(sym::extended_key_value_attributes, span),
}
- let token = token::Interpolated(Lrc::new(token::NtExpr(expr)));
- MacArgs::Eq(eq_span, TokenTree::token(token, span).into())
+ let token_kind = token::Interpolated(Lrc::new(token::NtExpr(expr)));
+ MacArgs::Eq(eq_span, Token::new(token_kind, span))
} else {
MacArgs::Empty
}
@@ -1223,6 +1226,13 @@
}
}
+ pub fn collect_tokens<R: HasTokens>(
+ &mut self,
+ f: impl FnOnce(&mut Self) -> PResult<'a, R>,
+ ) -> PResult<'a, R> {
+ self.collect_tokens_trailing_token(|this| Ok((f(this)?, TrailingToken::None)))
+ }
+
/// Records all tokens consumed by the provided callback,
/// including the current token. These tokens are collected
/// into a `LazyTokenStream`, and returned along with the result
@@ -1239,14 +1249,14 @@
/// This restriction shouldn't be an issue in practice,
/// since this function is used to record the tokens for
/// a parsed AST item, which always has matching delimiters.
- pub fn collect_tokens<R>(
+ pub fn collect_tokens_trailing_token<R: HasTokens>(
&mut self,
- f: impl FnOnce(&mut Self) -> PResult<'a, R>,
- ) -> PResult<'a, (R, Option<LazyTokenStream>)> {
+ f: impl FnOnce(&mut Self) -> PResult<'a, (R, TrailingToken)>,
+ ) -> PResult<'a, R> {
let start_token = (self.token.clone(), self.token_spacing);
let cursor_snapshot = self.token_cursor.clone();
- let ret = f(self)?;
+ let (mut ret, trailing_token) = f(self)?;
// Produces a `TokenStream` on-demand. Using `cursor_snapshot`
// and `num_calls`, we can reconstruct the `TokenStream` seen
@@ -1265,15 +1275,10 @@
cursor_snapshot: TokenCursor,
num_calls: usize,
desugar_doc_comments: bool,
- trailing_semi: bool,
append_unglued_token: Option<TreeAndSpacing>,
}
impl CreateTokenStream for LazyTokenStreamImpl {
fn create_token_stream(&self) -> TokenStream {
- let mut num_calls = self.num_calls;
- if self.trailing_semi {
- num_calls += 1;
- }
// The token produced by the final call to `next` or `next_desugared`
// was not actually consumed by the callback. The combination
// of chaining the initial token and using `take` produces the desired
@@ -1281,42 +1286,37 @@
// and omit the final token otherwise.
let mut cursor_snapshot = self.cursor_snapshot.clone();
let tokens = std::iter::once(self.start_token.clone())
- .chain((0..num_calls).map(|_| {
+ .chain((0..self.num_calls).map(|_| {
if self.desugar_doc_comments {
cursor_snapshot.next_desugared()
} else {
cursor_snapshot.next()
}
}))
- .take(num_calls);
+ .take(self.num_calls);
make_token_stream(tokens, self.append_unglued_token.clone())
}
- fn add_trailing_semi(&self) -> Box<dyn CreateTokenStream> {
- if self.trailing_semi {
- panic!("Called `add_trailing_semi` twice!");
- }
- if self.append_unglued_token.is_some() {
- panic!(
- "Cannot call `add_trailing_semi` when we have an unglued token {:?}",
- self.append_unglued_token
- );
- }
- let mut new = self.clone();
- new.trailing_semi = true;
- Box::new(new)
+ }
+
+ let mut num_calls = self.token_cursor.num_next_calls - cursor_snapshot.num_next_calls;
+ match trailing_token {
+ TrailingToken::None => {}
+ TrailingToken::Semi => {
+ assert_eq!(self.token.kind, token::Semi);
+ num_calls += 1;
}
}
let lazy_impl = LazyTokenStreamImpl {
start_token,
- num_calls: self.token_cursor.num_next_calls - cursor_snapshot.num_next_calls,
+ num_calls,
cursor_snapshot,
desugar_doc_comments: self.desugar_doc_comments,
- trailing_semi: false,
append_unglued_token: self.token_cursor.append_unglued_token.clone(),
};
- Ok((ret, Some(LazyTokenStream::new(lazy_impl))))
+ ret.finalize_tokens(LazyTokenStream::new(lazy_impl));
+ Ok(ret)
}
/// `::{` or `::*`
@@ -1409,3 +1409,16 @@
assert!(stack.is_empty(), "Stack should be empty: final_buf={:?} stack={:?}", final_buf, stack);
TokenStream::new(final_buf.inner)
}
+
+#[macro_export]
+macro_rules! maybe_collect_tokens {
+ ($self:ident, $force_collect:expr, $attrs:expr, $f:expr) => {
+ if matches!($force_collect, ForceCollect::Yes)
+ || $crate::parser::attr::maybe_needs_tokens($attrs)
+ {
+ $self.collect_tokens_trailing_token($f)
+ } else {
+ Ok($f($self)?.0)
+ }
+ };
+}
diff --git a/compiler/rustc_parse/src/parser/nonterminal.rs b/compiler/rustc_parse/src/parser/nonterminal.rs
index a6b9ac1..6e25209 100644
--- a/compiler/rustc_parse/src/parser/nonterminal.rs
+++ b/compiler/rustc_parse/src/parser/nonterminal.rs
@@ -4,19 +4,15 @@
use rustc_errors::PResult;
use rustc_span::symbol::{kw, Ident};
-use crate::parser::pat::{GateOr, OrPatNonterminalMode, RecoverComma};
-use crate::parser::{FollowedByType, Parser, PathStyle};
+use crate::parser::pat::{GateOr, RecoverComma};
+use crate::parser::{FollowedByType, ForceCollect, Parser, PathStyle};
impl<'a> Parser<'a> {
/// Checks whether a non-terminal may begin with a particular token.
///
/// Returning `false` is a *stability guarantee* that such a matcher will *never* begin with that
/// token. Be conservative (return true) if not sure.
- pub fn nonterminal_may_begin_with(
- kind: NonterminalKind,
- token: &Token,
- or_pat_mode: OrPatNonterminalMode,
- ) -> bool {
+ pub fn nonterminal_may_begin_with(kind: NonterminalKind, token: &Token) -> bool {
/// Checks whether the non-terminal may contain a single (non-keyword) identifier.
fn may_be_ident(nt: &token::Nonterminal) -> bool {
match *nt {
@@ -45,13 +41,16 @@
},
NonterminalKind::Block => match token.kind {
token::OpenDelim(token::Brace) => true,
- token::Interpolated(ref nt) => !matches!(**nt, token::NtItem(_)
- | token::NtPat(_)
- | token::NtTy(_)
- | token::NtIdent(..)
- | token::NtMeta(_)
- | token::NtPath(_)
- | token::NtVis(_)),
+ token::Interpolated(ref nt) => !matches!(
+ **nt,
+ token::NtItem(_)
+ | token::NtPat(_)
+ | token::NtTy(_)
+ | token::NtIdent(..)
+ | token::NtMeta(_)
+ | token::NtPath(_)
+ | token::NtVis(_)
+ ),
_ => false,
},
NonterminalKind::Path | NonterminalKind::Meta => match token.kind {
@@ -62,7 +61,7 @@
},
_ => false,
},
- NonterminalKind::Pat => match token.kind {
+ NonterminalKind::Pat2018 { .. } | NonterminalKind::Pat2021 { .. } => match token.kind {
token::Ident(..) | // box, ref, mut, and other identifiers (can stricten)
token::OpenDelim(token::Paren) | // tuple pattern
token::OpenDelim(token::Bracket) | // slice pattern
@@ -76,7 +75,7 @@
token::Lt | // path (UFCS constant)
token::BinOp(token::Shl) => true, // path (double UFCS)
// leading vert `|` or-pattern
- token::BinOp(token::Or) => matches!(or_pat_mode, OrPatNonterminalMode::TopPat),
+ token::BinOp(token::Or) => matches!(kind, NonterminalKind::Pat2021 {..}),
token::Interpolated(ref nt) => may_be_ident(nt),
_ => false,
},
@@ -94,11 +93,7 @@
}
/// Parse a non-terminal (e.g. MBE `:pat` or `:ident`).
- pub fn parse_nonterminal(
- &mut self,
- kind: NonterminalKind,
- or_pat_mode: OrPatNonterminalMode,
- ) -> PResult<'a, Nonterminal> {
+ pub fn parse_nonterminal(&mut self, kind: NonterminalKind) -> PResult<'a, Nonterminal> {
// Any `Nonterminal` which stores its tokens (currently `NtItem` and `NtExpr`)
// needs to have them force-captured here.
// A `macro_rules!` invocation may pass a captured item/expr to a proc-macro,
@@ -106,80 +101,35 @@
// in advance whether or not a proc-macro will be (transitively) invoked,
// we always capture tokens for any `Nonterminal` which needs them.
Ok(match kind {
- NonterminalKind::Item => match self.collect_tokens(|this| this.parse_item())? {
- (Some(mut item), tokens) => {
- // If we captured tokens during parsing (due to outer attributes),
- // use those.
- if item.tokens.is_none() {
- item.tokens = tokens;
- }
- token::NtItem(item)
- }
- (None, _) => {
+ NonterminalKind::Item => match self.parse_item(ForceCollect::Yes)? {
+ Some(item) => token::NtItem(item),
+ None => {
return Err(self.struct_span_err(self.token.span, "expected an item keyword"));
}
},
NonterminalKind::Block => {
- let (mut block, tokens) = self.collect_tokens(|this| this.parse_block())?;
- // We have have eaten an NtBlock, which could already have tokens
- if block.tokens.is_none() {
- block.tokens = tokens;
- }
- token::NtBlock(block)
+ token::NtBlock(self.collect_tokens(|this| this.parse_block())?)
}
- NonterminalKind::Stmt => {
- let (stmt, tokens) = self.collect_tokens(|this| this.parse_stmt())?;
- match stmt {
- Some(mut s) => {
- if s.tokens().is_none() {
- s.set_tokens(tokens);
- }
- token::NtStmt(s)
- }
- None => {
- return Err(self.struct_span_err(self.token.span, "expected a statement"));
- }
+ NonterminalKind::Stmt => match self.parse_stmt(ForceCollect::Yes)? {
+ Some(s) => token::NtStmt(s),
+ None => {
+ return Err(self.struct_span_err(self.token.span, "expected a statement"));
}
- }
- NonterminalKind::Pat => {
- let (mut pat, tokens) = self.collect_tokens(|this| match or_pat_mode {
- OrPatNonterminalMode::TopPat => {
+ },
+ NonterminalKind::Pat2018 { .. } | NonterminalKind::Pat2021 { .. } => {
+ token::NtPat(self.collect_tokens(|this| match kind {
+ NonterminalKind::Pat2018 { .. } => this.parse_pat(None),
+ NonterminalKind::Pat2021 { .. } => {
this.parse_top_pat(GateOr::Yes, RecoverComma::No)
}
- OrPatNonterminalMode::NoTopAlt => this.parse_pat(None),
- })?;
- // We have have eaten an NtPat, which could already have tokens
- if pat.tokens.is_none() {
- pat.tokens = tokens;
- }
- token::NtPat(pat)
+ _ => unreachable!(),
+ })?)
}
- NonterminalKind::Expr => {
- let (mut expr, tokens) = self.collect_tokens(|this| this.parse_expr())?;
- // If we captured tokens during parsing (due to outer attributes),
- // use those.
- if expr.tokens.is_none() {
- expr.tokens = tokens;
- }
- token::NtExpr(expr)
- }
+ NonterminalKind::Expr => token::NtExpr(self.collect_tokens(|this| this.parse_expr())?),
NonterminalKind::Literal => {
- let (mut lit, tokens) =
- self.collect_tokens(|this| this.parse_literal_maybe_minus())?;
- // We have have eaten a nonterminal, which could already have tokens
- if lit.tokens.is_none() {
- lit.tokens = tokens;
- }
- token::NtLiteral(lit)
+ token::NtLiteral(self.collect_tokens(|this| this.parse_literal_maybe_minus())?)
}
- NonterminalKind::Ty => {
- let (mut ty, tokens) = self.collect_tokens(|this| this.parse_ty())?;
- // We have an eaten an NtTy, which could already have tokens
- if ty.tokens.is_none() {
- ty.tokens = tokens;
- }
- token::NtTy(ty)
- }
+ NonterminalKind::Ty => token::NtTy(self.collect_tokens(|this| this.parse_ty())?),
// this could be handled like a token, since it is one
NonterminalKind::Ident => {
if let Some((ident, is_raw)) = get_macro_ident(&self.token) {
@@ -192,32 +142,15 @@
}
}
NonterminalKind::Path => {
- let (mut path, tokens) =
- self.collect_tokens(|this| this.parse_path(PathStyle::Type))?;
- // We have have eaten an NtPath, which could already have tokens
- if path.tokens.is_none() {
- path.tokens = tokens;
- }
- token::NtPath(path)
+ token::NtPath(self.collect_tokens(|this| this.parse_path(PathStyle::Type))?)
}
NonterminalKind::Meta => {
- let (mut attr, tokens) = self.collect_tokens(|this| this.parse_attr_item(false))?;
- // We may have eaten a nonterminal, which could already have tokens
- if attr.tokens.is_none() {
- attr.tokens = tokens;
- }
- token::NtMeta(P(attr))
+ token::NtMeta(P(self.collect_tokens(|this| this.parse_attr_item(false))?))
}
NonterminalKind::TT => token::NtTT(self.parse_token_tree()),
- NonterminalKind::Vis => {
- let (mut vis, tokens) =
- self.collect_tokens(|this| this.parse_visibility(FollowedByType::Yes))?;
- // We may have etan an `NtVis`, which could already have tokens
- if vis.tokens.is_none() {
- vis.tokens = tokens;
- }
- token::NtVis(vis)
- }
+ NonterminalKind::Vis => token::NtVis(
+ self.collect_tokens(|this| this.parse_visibility(FollowedByType::Yes))?,
+ ),
NonterminalKind::Lifetime => {
if self.check_lifetime() {
token::NtLifetime(self.expect_lifetime().ident)
diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs
index 1da371e..d888514 100644
--- a/compiler/rustc_parse/src/parser/pat.rs
+++ b/compiler/rustc_parse/src/parser/pat.rs
@@ -31,13 +31,6 @@
No,
}
-/// Used when parsing a non-terminal (see `parse_nonterminal`) to determine if `:pat` should match
-/// `top_pat` or `pat<no_top_alt>`. See issue <https://github.com/rust-lang/rust/pull/78935>.
-pub enum OrPatNonterminalMode {
- TopPat,
- NoTopAlt,
-}
-
impl<'a> Parser<'a> {
/// Parses a pattern.
///
@@ -247,7 +240,7 @@
Err(err)
}
- /// Parse and throw away a parentesized comma separated
+ /// Parse and throw away a parenthesized comma separated
/// sequence of patterns until `)` is reached.
fn skip_pat_list(&mut self) -> PResult<'a, ()> {
while !self.check(&token::CloseDelim(token::Paren)) {
diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs
index 4510e86e..6b7059e 100644
--- a/compiler/rustc_parse/src/parser/path.rs
+++ b/compiler/rustc_parse/src/parser/path.rs
@@ -133,7 +133,15 @@
maybe_whole!(self, NtPath, |path| {
if style == PathStyle::Mod && path.segments.iter().any(|segment| segment.args.is_some())
{
- self.struct_span_err(path.span, "unexpected generic arguments in path").emit();
+ self.struct_span_err(
+ path.segments
+ .iter()
+ .filter_map(|segment| segment.args.as_ref())
+ .map(|arg| arg.span())
+ .collect::<Vec<_>>(),
+ "unexpected generic arguments in path",
+ )
+ .emit();
}
path
});
@@ -185,7 +193,6 @@
pub(super) fn parse_path_segment(&mut self, style: PathStyle) -> PResult<'a, PathSegment> {
let ident = self.parse_path_segment_ident()?;
-
let is_args_start = |token: &Token| {
matches!(
token.kind,
@@ -230,10 +237,11 @@
} else {
// `(T, U) -> R`
let (inputs, _) = self.parse_paren_comma_seq(|p| p.parse_ty())?;
+ let inputs_span = lo.to(self.prev_token.span);
let span = ident.span.to(self.prev_token.span);
let output =
self.parse_ret_ty(AllowPlus::No, RecoverQPath::No, RecoverReturnSign::No)?;
- ParenthesizedArgs { inputs, output, span }.into()
+ ParenthesizedArgs { span, inputs, inputs_span, output }.into()
};
PathSegment { ident, args, id: ast::DUMMY_NODE_ID }
@@ -419,7 +427,10 @@
match arg {
Some(arg) => {
if self.check(&token::Colon) | self.check(&token::Eq) {
- let (ident, gen_args) = self.get_ident_from_generic_arg(arg, lo)?;
+ let (ident, gen_args) = match self.get_ident_from_generic_arg(arg) {
+ Ok(ident_gen_args) => ident_gen_args,
+ Err(arg) => return Ok(Some(AngleBracketedArg::Arg(arg))),
+ };
let kind = if self.eat(&token::Colon) {
// Parse associated type constraint bound.
@@ -501,10 +512,9 @@
pub(super) fn expr_is_valid_const_arg(&self, expr: &P<rustc_ast::Expr>) -> bool {
match &expr.kind {
ast::ExprKind::Block(_, _) | ast::ExprKind::Lit(_) => true,
- ast::ExprKind::Unary(ast::UnOp::Neg, expr) => match &expr.kind {
- ast::ExprKind::Lit(_) => true,
- _ => false,
- },
+ ast::ExprKind::Unary(ast::UnOp::Neg, expr) => {
+ matches!(expr.kind, ast::ExprKind::Lit(_))
+ }
// We can only resolve single-segment paths at the moment, because multi-segment paths
// require type-checking: see `visit_generic_arg` in `src/librustc_resolve/late.rs`.
ast::ExprKind::Path(None, path)
@@ -516,6 +526,23 @@
}
}
+ /// Parse a const argument, e.g. `<3>`. It is assumed the angle brackets will be parsed by
+ /// the caller.
+ pub(super) fn parse_const_arg(&mut self) -> PResult<'a, AnonConst> {
+ // Parse const argument.
+ let value = if let token::OpenDelim(token::Brace) = self.token.kind {
+ self.parse_block_expr(
+ None,
+ self.token.span,
+ BlockCheckMode::Default,
+ ast::AttrVec::new(),
+ )?
+ } else {
+ self.handle_unambiguous_unbraced_const_arg()?
+ };
+ Ok(AnonConst { id: ast::DUMMY_NODE_ID, value })
+ }
+
/// Parse a generic argument in a path segment.
/// This does not include constraints, e.g., `Item = u8`, which is handled in `parse_angle_arg`.
fn parse_generic_arg(&mut self) -> PResult<'a, Option<GenericArg>> {
@@ -525,17 +552,7 @@
GenericArg::Lifetime(self.expect_lifetime())
} else if self.check_const_arg() {
// Parse const argument.
- let value = if let token::OpenDelim(token::Brace) = self.token.kind {
- self.parse_block_expr(
- None,
- self.token.span,
- BlockCheckMode::Default,
- ast::AttrVec::new(),
- )?
- } else {
- self.handle_unambiguous_unbraced_const_arg()?
- };
- GenericArg::Const(AnonConst { id: ast::DUMMY_NODE_ID, value })
+ GenericArg::Const(self.parse_const_arg()?)
} else if self.check_type() {
// Parse type argument.
match self.parse_ty() {
@@ -554,50 +571,15 @@
fn get_ident_from_generic_arg(
&self,
gen_arg: GenericArg,
- lo: Span,
- ) -> PResult<'a, (Ident, Option<GenericArgs>)> {
- let gen_arg_span = gen_arg.span();
- match gen_arg {
- GenericArg::Type(t) => match t.into_inner().kind {
- ast::TyKind::Path(qself, mut path) => {
- if let Some(qself) = qself {
- let mut err = self.struct_span_err(
- gen_arg_span,
- "qualified paths cannot be used in associated type constraints",
- );
- err.span_label(
- qself.path_span,
- "not allowed in associated type constraints",
- );
- return Err(err);
- }
- if path.segments.len() == 1 {
- let path_seg = path.segments.remove(0);
- let ident = path_seg.ident;
- let gen_args = path_seg.args.map(|args| args.into_inner());
- return Ok((ident, gen_args));
- }
- let err = self.struct_span_err(
- path.span,
- "paths with multiple segments cannot be used in associated type constraints",
- );
- return Err(err);
+ ) -> Result<(Ident, Option<GenericArgs>), GenericArg> {
+ if let GenericArg::Type(ty) = &gen_arg {
+ if let ast::TyKind::Path(qself, path) = &ty.kind {
+ if qself.is_none() && path.segments.len() == 1 {
+ let seg = &path.segments[0];
+ return Ok((seg.ident, seg.args.as_deref().cloned()));
}
- _ => {
- let span = lo.to(self.prev_token.span);
- let err = self.struct_span_err(
- span,
- "only path types can be used in associated type constraints",
- );
- return Err(err);
- }
- },
- _ => {
- let span = lo.to(self.prev_token.span);
- let err = self
- .struct_span_err(span, "only types can be used in associated type constraints");
- return Err(err);
}
}
+ Err(gen_arg)
}
}
diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs
index 2942747..8373f6a 100644
--- a/compiler/rustc_parse/src/parser/stmt.rs
+++ b/compiler/rustc_parse/src/parser/stmt.rs
@@ -3,14 +3,13 @@
use super::expr::LhsExpr;
use super::pat::{GateOr, RecoverComma};
use super::path::PathStyle;
-use super::{BlockMode, Parser, Restrictions, SemiColonMode};
-use crate::maybe_whole;
+use super::{BlockMode, ForceCollect, Parser, Restrictions, SemiColonMode, TrailingToken};
+use crate::{maybe_collect_tokens, maybe_whole};
use rustc_ast as ast;
use rustc_ast::attr::HasAttrs;
use rustc_ast::ptr::P;
use rustc_ast::token::{self, TokenKind};
-use rustc_ast::tokenstream::LazyTokenStream;
use rustc_ast::util::classify;
use rustc_ast::{AttrStyle, AttrVec, Attribute, MacCall, MacCallStmt, MacStmtStyle};
use rustc_ast::{Block, BlockCheckMode, Expr, ExprKind, Local, Stmt, StmtKind, DUMMY_NODE_ID};
@@ -24,17 +23,22 @@
/// Parses a statement. This stops just before trailing semicolons on everything but items.
/// e.g., a `StmtKind::Semi` parses to a `StmtKind::Expr`, leaving the trailing `;` unconsumed.
// Public for rustfmt usage.
- pub fn parse_stmt(&mut self) -> PResult<'a, Option<Stmt>> {
- Ok(self.parse_stmt_without_recovery().unwrap_or_else(|mut e| {
+ pub fn parse_stmt(&mut self, force_collect: ForceCollect) -> PResult<'a, Option<Stmt>> {
+ Ok(self.parse_stmt_without_recovery(false, force_collect).unwrap_or_else(|mut e| {
e.emit();
self.recover_stmt_(SemiColonMode::Break, BlockMode::Ignore);
None
}))
}
- fn parse_stmt_without_recovery(&mut self) -> PResult<'a, Option<Stmt>> {
+ /// If `force_capture` is true, forces collection of tokens regardless of whether
+ /// or not we have attributes
+ fn parse_stmt_without_recovery(
+ &mut self,
+ capture_semi: bool,
+ force_collect: ForceCollect,
+ ) -> PResult<'a, Option<Stmt>> {
let mut attrs = self.parse_outer_attributes()?;
- let has_attrs = !attrs.is_empty();
let lo = self.token.span;
maybe_whole!(self, NtStmt, |stmt| {
@@ -46,83 +50,77 @@
Some(stmt)
});
- let parse_stmt_inner = |this: &mut Self| {
- let stmt = if this.eat_keyword(kw::Let) {
- this.parse_local_mk(lo, attrs.into())?
- } else if this.is_kw_followed_by_ident(kw::Mut) {
- this.recover_stmt_local(lo, attrs.into(), "missing keyword", "let mut")?
- } else if this.is_kw_followed_by_ident(kw::Auto) {
- this.bump(); // `auto`
- let msg = "write `let` instead of `auto` to introduce a new variable";
- this.recover_stmt_local(lo, attrs.into(), msg, "let")?
- } else if this.is_kw_followed_by_ident(sym::var) {
- this.bump(); // `var`
- let msg = "write `let` instead of `var` to introduce a new variable";
- this.recover_stmt_local(lo, attrs.into(), msg, "let")?
- } else if this.check_path()
- && !this.token.is_qpath_start()
- && !this.is_path_start_item()
- {
- // We have avoided contextual keywords like `union`, items with `crate` visibility,
- // or `auto trait` items. We aim to parse an arbitrary path `a::b` but not something
- // that starts like a path (1 token), but it fact not a path.
- // Also, we avoid stealing syntax from `parse_item_`.
- this.parse_stmt_path_start(lo, attrs)?
- } else if let Some(item) =
- this.parse_item_common(attrs.clone(), false, true, |_| true)?
- {
- // FIXME: Bad copy of attrs
- this.mk_stmt(lo.to(item.span), StmtKind::Item(P(item)))
- } else if this.eat(&token::Semi) {
- // Do not attempt to parse an expression if we're done here.
- this.error_outer_attrs(&attrs);
- this.mk_stmt(lo, StmtKind::Empty)
- } else if this.token != token::CloseDelim(token::Brace) {
- // Remainder are line-expr stmts.
- let e = this.parse_expr_res(Restrictions::STMT_EXPR, Some(attrs.into()))?;
- this.mk_stmt(lo.to(e.span), StmtKind::Expr(e))
- } else {
- this.error_outer_attrs(&attrs);
- return Ok(None);
- };
- Ok(Some(stmt))
- };
-
- let stmt = if has_attrs {
- let (mut stmt, tokens) = self.collect_tokens(parse_stmt_inner)?;
- if let Some(stmt) = &mut stmt {
- // If we already have tokens (e.g. due to encounting an `NtStmt`),
- // use those instead.
- if stmt.tokens().is_none() {
- stmt.set_tokens(tokens);
- }
- }
- stmt
+ Ok(Some(if self.token.is_keyword(kw::Let) {
+ self.parse_local_mk(lo, attrs.into(), capture_semi, force_collect)?
+ } else if self.is_kw_followed_by_ident(kw::Mut) {
+ self.recover_stmt_local(lo, attrs.into(), "missing keyword", "let mut")?
+ } else if self.is_kw_followed_by_ident(kw::Auto) {
+ self.bump(); // `auto`
+ let msg = "write `let` instead of `auto` to introduce a new variable";
+ self.recover_stmt_local(lo, attrs.into(), msg, "let")?
+ } else if self.is_kw_followed_by_ident(sym::var) {
+ self.bump(); // `var`
+ let msg = "write `let` instead of `var` to introduce a new variable";
+ self.recover_stmt_local(lo, attrs.into(), msg, "let")?
+ } else if self.check_path() && !self.token.is_qpath_start() && !self.is_path_start_item() {
+ // We have avoided contextual keywords like `union`, items with `crate` visibility,
+ // or `auto trait` items. We aim to parse an arbitrary path `a::b` but not something
+ // that starts like a path (1 token), but it fact not a path.
+ // Also, we avoid stealing syntax from `parse_item_`.
+ self.parse_stmt_path_start(lo, attrs, force_collect)?
+ } else if let Some(item) =
+ self.parse_item_common(attrs.clone(), false, true, |_| true, force_collect)?
+ {
+ // FIXME: Bad copy of attrs
+ self.mk_stmt(lo.to(item.span), StmtKind::Item(P(item)))
+ } else if self.eat(&token::Semi) {
+ // Do not attempt to parse an expression if we're done here.
+ self.error_outer_attrs(&attrs);
+ self.mk_stmt(lo, StmtKind::Empty)
+ } else if self.token != token::CloseDelim(token::Brace) {
+ // Remainder are line-expr stmts.
+ let e = self.parse_expr_res(Restrictions::STMT_EXPR, Some(attrs.into()))?;
+ self.mk_stmt(lo.to(e.span), StmtKind::Expr(e))
} else {
- parse_stmt_inner(self)?
- };
- Ok(stmt)
+ self.error_outer_attrs(&attrs);
+ return Ok(None);
+ }))
}
- fn parse_stmt_path_start(&mut self, lo: Span, attrs: Vec<Attribute>) -> PResult<'a, Stmt> {
- let path = self.parse_path(PathStyle::Expr)?;
+ fn parse_stmt_path_start(
+ &mut self,
+ lo: Span,
+ attrs: Vec<Attribute>,
+ force_collect: ForceCollect,
+ ) -> PResult<'a, Stmt> {
+ maybe_collect_tokens!(self, force_collect, &attrs, |this: &mut Parser<'a>| {
+ let path = this.parse_path(PathStyle::Expr)?;
- if self.eat(&token::Not) {
- return self.parse_stmt_mac(lo, attrs.into(), path);
- }
+ if this.eat(&token::Not) {
+ let stmt_mac = this.parse_stmt_mac(lo, attrs.into(), path)?;
+ if this.token == token::Semi {
+ return Ok((stmt_mac, TrailingToken::Semi));
+ } else {
+ return Ok((stmt_mac, TrailingToken::None));
+ }
+ }
- let expr = if self.eat(&token::OpenDelim(token::Brace)) {
- self.parse_struct_expr(path, AttrVec::new(), true)?
- } else {
- let hi = self.prev_token.span;
- self.mk_expr(lo.to(hi), ExprKind::Path(None, path), AttrVec::new())
- };
+ let expr = if this.eat(&token::OpenDelim(token::Brace)) {
+ this.parse_struct_expr(path, AttrVec::new(), true)?
+ } else {
+ let hi = this.prev_token.span;
+ this.mk_expr(lo.to(hi), ExprKind::Path(None, path), AttrVec::new())
+ };
- let expr = self.with_res(Restrictions::STMT_EXPR, |this| {
- let expr = this.parse_dot_or_call_expr_with(expr, lo, attrs.into())?;
- this.parse_assoc_expr_with(0, LhsExpr::AlreadyParsed(expr))
- })?;
- Ok(self.mk_stmt(lo.to(self.prev_token.span), StmtKind::Expr(expr)))
+ let expr = this.with_res(Restrictions::STMT_EXPR, |this| {
+ let expr = this.parse_dot_or_call_expr_with(expr, lo, attrs.into())?;
+ this.parse_assoc_expr_with(0, LhsExpr::AlreadyParsed(expr))
+ })?;
+ Ok((
+ this.mk_stmt(lo.to(this.prev_token.span), StmtKind::Expr(expr)),
+ TrailingToken::None,
+ ))
+ })
}
/// Parses a statement macro `mac!(args)` provided a `path` representing `mac`.
@@ -170,15 +168,34 @@
msg: &str,
sugg: &str,
) -> PResult<'a, Stmt> {
- let stmt = self.parse_local_mk(lo, attrs)?;
+ let stmt = self.recover_local_after_let(lo, attrs)?;
self.struct_span_err(lo, "invalid variable declaration")
.span_suggestion(lo, msg, sugg.to_string(), Applicability::MachineApplicable)
.emit();
Ok(stmt)
}
- fn parse_local_mk(&mut self, lo: Span, attrs: AttrVec) -> PResult<'a, Stmt> {
- let local = self.parse_local(attrs)?;
+ fn parse_local_mk(
+ &mut self,
+ lo: Span,
+ attrs: AttrVec,
+ capture_semi: bool,
+ force_collect: ForceCollect,
+ ) -> PResult<'a, Stmt> {
+ maybe_collect_tokens!(self, force_collect, &attrs, |this: &mut Parser<'a>| {
+ this.expect_keyword(kw::Let)?;
+ let local = this.parse_local(attrs.into())?;
+ let trailing = if capture_semi && this.token.kind == token::Semi {
+ TrailingToken::Semi
+ } else {
+ TrailingToken::None
+ };
+ Ok((this.mk_stmt(lo.to(this.prev_token.span), StmtKind::Local(local)), trailing))
+ })
+ }
+
+ fn recover_local_after_let(&mut self, lo: Span, attrs: AttrVec) -> PResult<'a, Stmt> {
+ let local = self.parse_local(attrs.into())?;
Ok(self.mk_stmt(lo.to(self.prev_token.span), StmtKind::Local(local)))
}
@@ -300,7 +317,7 @@
// bar;
//
// which is valid in other languages, but not Rust.
- match self.parse_stmt_without_recovery() {
+ match self.parse_stmt_without_recovery(false, ForceCollect::No) {
// If the next token is an open brace (e.g., `if a b {`), the place-
// inside-a-block suggestion would be more likely wrong than right.
Ok(Some(_))
@@ -403,17 +420,11 @@
// Skip looking for a trailing semicolon when we have an interpolated statement.
maybe_whole!(self, NtStmt, |x| Some(x));
- let mut stmt = match self.parse_stmt_without_recovery()? {
+ let mut stmt = match self.parse_stmt_without_recovery(true, ForceCollect::No)? {
Some(stmt) => stmt,
None => return Ok(None),
};
- let add_semi_token = |tokens: Option<&mut LazyTokenStream>| {
- if let Some(tokens) = tokens {
- *tokens = tokens.add_trailing_semi();
- }
- };
-
let mut eat_semi = true;
match stmt.kind {
// Expression without semicolon.
@@ -469,18 +480,12 @@
}
}
eat_semi = false;
- // We just checked that there's a semicolon in the tokenstream,
- // so capture it
- add_semi_token(local.tokens.as_mut());
}
StmtKind::Empty | StmtKind::Item(_) | StmtKind::Semi(_) => eat_semi = false,
}
if eat_semi && self.eat(&token::Semi) {
stmt = stmt.add_trailing_semicolon();
- // We just checked that we have a semicolon in the tokenstream,
- // so capture it
- add_semi_token(stmt.tokens_mut());
}
stmt.span = stmt.span.to(self.prev_token.span);
Ok(Some(stmt))
diff --git a/compiler/rustc_parse/src/validate_attr.rs b/compiler/rustc_parse/src/validate_attr.rs
index f4bb961..2137272 100644
--- a/compiler/rustc_parse/src/validate_attr.rs
+++ b/compiler/rustc_parse/src/validate_attr.rs
@@ -2,7 +2,7 @@
use crate::parse_in;
-use rustc_ast::tokenstream::DelimSpan;
+use rustc_ast::tokenstream::{DelimSpan, TokenTree};
use rustc_ast::{self as ast, Attribute, MacArgs, MacDelimiter, MetaItem, MetaItemKind};
use rustc_errors::{Applicability, PResult};
use rustc_feature::{AttributeTemplate, BUILTIN_ATTRIBUTE_MAP};
@@ -45,7 +45,8 @@
kind: match &item.args {
MacArgs::Empty => MetaItemKind::Word,
MacArgs::Eq(_, t) => {
- let v = parse_in(sess, t.clone(), "name value", |p| p.parse_unsuffixed_lit())?;
+ let t = TokenTree::Token(t.clone()).into();
+ let v = parse_in(sess, t, "name value", |p| p.parse_unsuffixed_lit())?;
MetaItemKind::NameValue(v)
}
MacArgs::Delimited(dspan, delim, t) => {
diff --git a/compiler/rustc_parse_format/src/lib.rs b/compiler/rustc_parse_format/src/lib.rs
index 25e3e67..f150f7a 100644
--- a/compiler/rustc_parse_format/src/lib.rs
+++ b/compiler/rustc_parse_format/src/lib.rs
@@ -347,7 +347,7 @@
let mut pos = pos;
// This handles the raw string case, the raw argument is the number of #
// in r###"..."### (we need to add one because of the `r`).
- let raw = self.style.map(|raw| raw + 1).unwrap_or(0);
+ let raw = self.style.map_or(0, |raw| raw + 1);
for skip in &self.skips {
if pos > *skip {
pos += 1;
@@ -736,7 +736,7 @@
fn find_skips(snippet: &str, is_raw: bool) -> Vec<usize> {
let mut eat_ws = false;
- let mut s = snippet.chars().enumerate().peekable();
+ let mut s = snippet.char_indices().peekable();
let mut skips = vec![];
while let Some((pos, c)) = s.next() {
match (c, s.peek()) {
@@ -814,7 +814,7 @@
skips
}
- let r_start = str_style.map(|r| r + 1).unwrap_or(0);
+ let r_start = str_style.map_or(0, |r| r + 1);
let r_end = str_style.unwrap_or(0);
let s = &snippet[r_start + 1..snippet.len() - r_end - 1];
(find_skips(s, str_style.is_some()), true)
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index aeaa862..0e3a722 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -32,7 +32,7 @@
let parent_hir_id = tcx.hir().get_parent_item(impl_item.hir_id);
let containing_item = tcx.hir().expect_item(parent_hir_id);
let containing_impl_is_for_trait = match &containing_item.kind {
- hir::ItemKind::Impl { ref of_trait, .. } => of_trait.is_some(),
+ hir::ItemKind::Impl(impl_) => impl_.of_trait.is_some(),
_ => bug!("parent of an ImplItem must be an Impl"),
};
if containing_impl_is_for_trait {
@@ -70,27 +70,27 @@
is_valid &= if self.tcx.sess.check_name(attr, sym::inline) {
self.check_inline(hir_id, attr, span, target)
} else if self.tcx.sess.check_name(attr, sym::non_exhaustive) {
- self.check_non_exhaustive(attr, span, target)
+ self.check_non_exhaustive(hir_id, attr, span, target)
} else if self.tcx.sess.check_name(attr, sym::marker) {
- self.check_marker(attr, span, target)
+ self.check_marker(hir_id, attr, span, target)
} else if self.tcx.sess.check_name(attr, sym::target_feature) {
self.check_target_feature(hir_id, attr, span, target)
} else if self.tcx.sess.check_name(attr, sym::track_caller) {
- self.check_track_caller(&attr.span, attrs, span, target)
+ self.check_track_caller(hir_id, &attr.span, attrs, span, target)
} else if self.tcx.sess.check_name(attr, sym::doc) {
self.check_doc_attrs(attr, hir_id, target)
} else if self.tcx.sess.check_name(attr, sym::no_link) {
- self.check_no_link(&attr, span, target)
+ self.check_no_link(hir_id, &attr, span, target)
} else if self.tcx.sess.check_name(attr, sym::export_name) {
- self.check_export_name(&attr, span, target)
+ self.check_export_name(hir_id, &attr, span, target)
} else if self.tcx.sess.check_name(attr, sym::rustc_args_required_const) {
self.check_rustc_args_required_const(&attr, span, target, item)
} else if self.tcx.sess.check_name(attr, sym::allow_internal_unstable) {
- self.check_allow_internal_unstable(&attr, span, target, &attrs)
+ self.check_allow_internal_unstable(hir_id, &attr, span, target, &attrs)
} else if self.tcx.sess.check_name(attr, sym::rustc_allow_const_fn_unstable) {
self.check_rustc_allow_const_fn_unstable(hir_id, &attr, span, target)
} else if self.tcx.sess.check_name(attr, sym::naked) {
- self.check_naked(attr, span, target)
+ self.check_naked(hir_id, attr, span, target)
} else {
// lint-only checks
if self.tcx.sess.check_name(attr, sym::cold) {
@@ -118,6 +118,41 @@
self.check_used(attrs, target);
}
+ fn inline_attr_str_error_with_macro_def(&self, hir_id: HirId, attr: &Attribute, sym: &str) {
+ self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| {
+ lint.build(&format!(
+ "`#[{}]` is ignored on struct fields, match arms and macro defs",
+ sym,
+ ))
+ .warn(
+ "this was previously accepted by the compiler but is \
+ being phased out; it will become a hard error in \
+ a future release!",
+ )
+ .note(
+ "see issue #80564 <https://github.com/rust-lang/rust/issues/80564> \
+ for more information",
+ )
+ .emit();
+ });
+ }
+
+ fn inline_attr_str_error_without_macro_def(&self, hir_id: HirId, attr: &Attribute, sym: &str) {
+ self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| {
+ lint.build(&format!("`#[{}]` is ignored on struct fields and match arms", sym))
+ .warn(
+ "this was previously accepted by the compiler but is \
+ being phased out; it will become a hard error in \
+ a future release!",
+ )
+ .note(
+ "see issue #80564 <https://github.com/rust-lang/rust/issues/80564> \
+ for more information",
+ )
+ .emit();
+ });
+ }
+
/// Checks if an `#[inline]` is applied to a function or a closure. Returns `true` if valid.
fn check_inline(&self, hir_id: HirId, attr: &Attribute, span: &Span, target: Target) -> bool {
match target {
@@ -150,6 +185,11 @@
});
true
}
+ // FIXME(#80564): Same for fields, arms, and macro defs
+ Target::Field | Target::Arm | Target::MacroDef => {
+ self.inline_attr_str_error_with_macro_def(hir_id, attr, "inline");
+ true
+ }
_ => {
struct_span_err!(
self.tcx.sess,
@@ -165,10 +205,18 @@
}
/// Checks if `#[naked]` is applied to a function definition.
- fn check_naked(&self, attr: &Attribute, span: &Span, target: Target) -> bool {
+ fn check_naked(&self, hir_id: HirId, attr: &Attribute, span: &Span, target: Target) -> bool {
match target {
Target::Fn
| Target::Method(MethodKind::Trait { body: true } | MethodKind::Inherent) => true,
+ // FIXME(#80564): We permit struct fields, match arms and macro defs to have an
+ // `#[allow_internal_unstable]` attribute with just a lint, because we previously
+ // erroneously allowed it and some crates used it accidentally, to to be compatible
+ // with crates depending on them, we can't throw an error here.
+ Target::Field | Target::Arm | Target::MacroDef => {
+ self.inline_attr_str_error_with_macro_def(hir_id, attr, "naked");
+ true
+ }
_ => {
self.tcx
.sess
@@ -186,6 +234,7 @@
/// Checks if a `#[track_caller]` is applied to a non-naked function. Returns `true` if valid.
fn check_track_caller(
&self,
+ hir_id: HirId,
attr_span: &Span,
attrs: &'hir [Attribute],
span: &Span,
@@ -203,6 +252,16 @@
false
}
Target::Fn | Target::Method(..) | Target::ForeignFn | Target::Closure => true,
+ // FIXME(#80564): We permit struct fields, match arms and macro defs to have an
+ // `#[track_caller]` attribute with just a lint, because we previously
+ // erroneously allowed it and some crates used it accidentally, to to be compatible
+ // with crates depending on them, we can't throw an error here.
+ Target::Field | Target::Arm | Target::MacroDef => {
+ for attr in attrs {
+ self.inline_attr_str_error_with_macro_def(hir_id, attr, "track_caller");
+ }
+ true
+ }
_ => {
struct_span_err!(
self.tcx.sess,
@@ -218,9 +277,23 @@
}
/// Checks if the `#[non_exhaustive]` attribute on an `item` is valid. Returns `true` if valid.
- fn check_non_exhaustive(&self, attr: &Attribute, span: &Span, target: Target) -> bool {
+ fn check_non_exhaustive(
+ &self,
+ hir_id: HirId,
+ attr: &Attribute,
+ span: &Span,
+ target: Target,
+ ) -> bool {
match target {
Target::Struct | Target::Enum | Target::Variant => true,
+ // FIXME(#80564): We permit struct fields, match arms and macro defs to have an
+ // `#[non_exhaustive]` attribute with just a lint, because we previously
+ // erroneously allowed it and some crates used it accidentally, to to be compatible
+ // with crates depending on them, we can't throw an error here.
+ Target::Field | Target::Arm | Target::MacroDef => {
+ self.inline_attr_str_error_with_macro_def(hir_id, attr, "non_exhaustive");
+ true
+ }
_ => {
struct_span_err!(
self.tcx.sess,
@@ -236,9 +309,17 @@
}
/// Checks if the `#[marker]` attribute on an `item` is valid. Returns `true` if valid.
- fn check_marker(&self, attr: &Attribute, span: &Span, target: Target) -> bool {
+ fn check_marker(&self, hir_id: HirId, attr: &Attribute, span: &Span, target: Target) -> bool {
match target {
Target::Trait => true,
+ // FIXME(#80564): We permit struct fields, match arms and macro defs to have an
+ // `#[marker]` attribute with just a lint, because we previously
+ // erroneously allowed it and some crates used it accidentally, to to be compatible
+ // with crates depending on them, we can't throw an error here.
+ Target::Field | Target::Arm | Target::MacroDef => {
+ self.inline_attr_str_error_with_macro_def(hir_id, attr, "marker");
+ true
+ }
_ => {
self.tcx
.sess
@@ -276,6 +357,14 @@
});
true
}
+ // FIXME(#80564): We permit struct fields, match arms and macro defs to have an
+ // `#[target_feature]` attribute with just a lint, because we previously
+ // erroneously allowed it and some crates used it accidentally, to to be compatible
+ // with crates depending on them, we can't throw an error here.
+ Target::Field | Target::Arm | Target::MacroDef => {
+ self.inline_attr_str_error_with_macro_def(hir_id, attr, "target_feature");
+ true
+ }
_ => {
self.tcx
.sess
@@ -310,7 +399,7 @@
.sess
.struct_span_err(
meta.name_value_literal_span().unwrap_or_else(|| meta.span()),
- &format!("{:?} character isn't allowed in `#[doc(alias = \"...\")]`", c,),
+ &format!("{:?} character isn't allowed in `#[doc(alias = \"...\")]`", c),
)
.emit();
return false;
@@ -343,7 +432,7 @@
// We can't link to trait impl's consts.
let err = "associated constant in trait implementation block";
match containing_item.kind {
- ItemKind::Impl { of_trait: Some(_), .. } => Some(err),
+ ItemKind::Impl(hir::Impl { of_trait: Some(_), .. }) => Some(err),
_ => None,
}
}
@@ -358,6 +447,17 @@
.emit();
return false;
}
+ let item_name = self.tcx.hir().name(hir_id);
+ if &*item_name.as_str() == doc_alias {
+ self.tcx
+ .sess
+ .struct_span_err(
+ meta.span(),
+ &format!("`#[doc(alias = \"...\")]` is the same as the item's name"),
+ )
+ .emit();
+ return false;
+ }
true
}
@@ -453,6 +553,13 @@
fn check_cold(&self, hir_id: HirId, attr: &Attribute, span: &Span, target: Target) {
match target {
Target::Fn | Target::Method(..) | Target::ForeignFn | Target::Closure => {}
+ // FIXME(#80564): We permit struct fields, match arms and macro defs to have an
+ // `#[cold]` attribute with just a lint, because we previously
+ // erroneously allowed it and some crates used it accidentally, to to be compatible
+ // with crates depending on them, we can't throw an error here.
+ Target::Field | Target::Arm | Target::MacroDef => {
+ self.inline_attr_str_error_with_macro_def(hir_id, attr, "cold");
+ }
_ => {
// FIXME: #[cold] was previously allowed on non-functions and some crates used
// this, so only emit a warning.
@@ -474,6 +581,13 @@
fn check_link_name(&self, hir_id: HirId, attr: &Attribute, span: &Span, target: Target) {
match target {
Target::ForeignFn | Target::ForeignStatic => {}
+ // FIXME(#80564): We permit struct fields, match arms and macro defs to have an
+ // `#[link_name]` attribute with just a lint, because we previously
+ // erroneously allowed it and some crates used it accidentally, to to be compatible
+ // with crates depending on them, we can't throw an error here.
+ Target::Field | Target::Arm | Target::MacroDef => {
+ self.inline_attr_str_error_with_macro_def(hir_id, attr, "link_name");
+ }
_ => {
// FIXME: #[cold] was previously allowed on non-functions/statics and some crates
// used this, so only emit a warning.
@@ -506,23 +620,49 @@
}
/// Checks if `#[no_link]` is applied to an `extern crate`. Returns `true` if valid.
- fn check_no_link(&self, attr: &Attribute, span: &Span, target: Target) -> bool {
- if target == Target::ExternCrate {
- true
- } else {
- self.tcx
- .sess
- .struct_span_err(attr.span, "attribute should be applied to an `extern crate` item")
- .span_label(*span, "not an `extern crate` item")
- .emit();
- false
+ fn check_no_link(&self, hir_id: HirId, attr: &Attribute, span: &Span, target: Target) -> bool {
+ match target {
+ Target::ExternCrate => true,
+ // FIXME(#80564): We permit struct fields, match arms and macro defs to have an
+ // `#[no_link]` attribute with just a lint, because we previously
+ // erroneously allowed it and some crates used it accidentally, to to be compatible
+ // with crates depending on them, we can't throw an error here.
+ Target::Field | Target::Arm | Target::MacroDef => {
+ self.inline_attr_str_error_with_macro_def(hir_id, attr, "no_link");
+ true
+ }
+ _ => {
+ self.tcx
+ .sess
+ .struct_span_err(
+ attr.span,
+ "attribute should be applied to an `extern crate` item",
+ )
+ .span_label(*span, "not an `extern crate` item")
+ .emit();
+ false
+ }
}
}
/// Checks if `#[export_name]` is applied to a function or static. Returns `true` if valid.
- fn check_export_name(&self, attr: &Attribute, span: &Span, target: Target) -> bool {
+ fn check_export_name(
+ &self,
+ hir_id: HirId,
+ attr: &Attribute,
+ span: &Span,
+ target: Target,
+ ) -> bool {
match target {
Target::Static | Target::Fn | Target::Method(..) => true,
+ // FIXME(#80564): We permit struct fields, match arms and macro defs to have an
+ // `#[export_name]` attribute with just a lint, because we previously
+ // erroneously allowed it and some crates used it accidentally, to to be compatible
+ // with crates depending on them, we can't throw an error here.
+ Target::Field | Target::Arm | Target::MacroDef => {
+ self.inline_attr_str_error_with_macro_def(hir_id, attr, "export_name");
+ true
+ }
_ => {
self.tcx
.sess
@@ -614,6 +754,13 @@
fn check_link_section(&self, hir_id: HirId, attr: &Attribute, span: &Span, target: Target) {
match target {
Target::Static | Target::Fn | Target::Method(..) => {}
+ // FIXME(#80564): We permit struct fields, match arms and macro defs to have an
+ // `#[link_section]` attribute with just a lint, because we previously
+ // erroneously allowed it and some crates used it accidentally, to to be compatible
+ // with crates depending on them, we can't throw an error here.
+ Target::Field | Target::Arm | Target::MacroDef => {
+ self.inline_attr_str_error_with_macro_def(hir_id, attr, "link_section");
+ }
_ => {
// FIXME: #[link_section] was previously allowed on non-functions/statics and some
// crates used this, so only emit a warning.
@@ -635,6 +782,13 @@
fn check_no_mangle(&self, hir_id: HirId, attr: &Attribute, span: &Span, target: Target) {
match target {
Target::Static | Target::Fn | Target::Method(..) => {}
+ // FIXME(#80564): We permit struct fields, match arms and macro defs to have an
+ // `#[no_mangle]` attribute with just a lint, because we previously
+ // erroneously allowed it and some crates used it accidentally, to to be compatible
+ // with crates depending on them, we can't throw an error here.
+ Target::Field | Target::Arm | Target::MacroDef => {
+ self.inline_attr_str_error_with_macro_def(hir_id, attr, "no_mangle");
+ }
_ => {
// FIXME: #[no_mangle] was previously allowed on non-functions/statics and some
// crates used this, so only emit a warning.
@@ -817,27 +971,46 @@
/// (Allows proc_macro functions)
fn check_allow_internal_unstable(
&self,
+ hir_id: HirId,
attr: &Attribute,
span: &Span,
target: Target,
attrs: &[Attribute],
) -> bool {
debug!("Checking target: {:?}", target);
- if target == Target::Fn {
- for attr in attrs {
- if self.tcx.sess.is_proc_macro_attr(attr) {
- debug!("Is proc macro attr");
- return true;
+ match target {
+ Target::Fn => {
+ for attr in attrs {
+ if self.tcx.sess.is_proc_macro_attr(attr) {
+ debug!("Is proc macro attr");
+ return true;
+ }
}
+ debug!("Is not proc macro attr");
+ false
}
- debug!("Is not proc macro attr");
+ Target::MacroDef => true,
+ // FIXME(#80564): We permit struct fields and match arms to have an
+ // `#[allow_internal_unstable]` attribute with just a lint, because we previously
+ // erroneously allowed it and some crates used it accidentally, to to be compatible
+ // with crates depending on them, we can't throw an error here.
+ Target::Field | Target::Arm => {
+ self.inline_attr_str_error_without_macro_def(
+ hir_id,
+ attr,
+ "allow_internal_unstable",
+ );
+ true
+ }
+ _ => {
+ self.tcx
+ .sess
+ .struct_span_err(attr.span, "attribute should be applied to a macro")
+ .span_label(*span, "not a macro")
+ .emit();
+ false
+ }
}
- self.tcx
- .sess
- .struct_span_err(attr.span, "attribute should be applied to a macro")
- .span_label(*span, "not a macro")
- .emit();
- false
}
/// Outputs an error for `#[allow_internal_unstable]` which can only be applied to macros.
@@ -849,17 +1022,29 @@
span: &Span,
target: Target,
) -> bool {
- if let Target::Fn | Target::Method(_) = target {
- if self.tcx.is_const_fn_raw(self.tcx.hir().local_def_id(hir_id)) {
- return true;
+ match target {
+ Target::Fn | Target::Method(_)
+ if self.tcx.is_const_fn_raw(self.tcx.hir().local_def_id(hir_id)) =>
+ {
+ true
+ }
+ // FIXME(#80564): We permit struct fields and match arms to have an
+ // `#[allow_internal_unstable]` attribute with just a lint, because we previously
+ // erroneously allowed it and some crates used it accidentally, to to be compatible
+ // with crates depending on them, we can't throw an error here.
+ Target::Field | Target::Arm | Target::MacroDef => {
+ self.inline_attr_str_error_with_macro_def(hir_id, attr, "allow_internal_unstable");
+ true
+ }
+ _ => {
+ self.tcx
+ .sess
+ .struct_span_err(attr.span, "attribute should be applied to `const fn`")
+ .span_label(*span, "not a `const fn`")
+ .emit();
+ false
}
}
- self.tcx
- .sess
- .struct_span_err(attr.span, "attribute should be applied to `const fn`")
- .span_label(*span, "not a `const fn`")
- .emit();
- false
}
}
@@ -900,6 +1085,33 @@
intravisit::walk_trait_item(self, trait_item)
}
+ fn visit_struct_field(&mut self, struct_field: &'tcx hir::StructField<'tcx>) {
+ self.check_attributes(
+ struct_field.hir_id,
+ &struct_field.attrs,
+ &struct_field.span,
+ Target::Field,
+ None,
+ );
+ intravisit::walk_struct_field(self, struct_field);
+ }
+
+ fn visit_arm(&mut self, arm: &'tcx hir::Arm<'tcx>) {
+ self.check_attributes(arm.hir_id, &arm.attrs, &arm.span, Target::Arm, None);
+ intravisit::walk_arm(self, arm);
+ }
+
+ fn visit_macro_def(&mut self, macro_def: &'tcx hir::MacroDef<'tcx>) {
+ self.check_attributes(
+ macro_def.hir_id,
+ ¯o_def.attrs,
+ ¯o_def.span,
+ Target::MacroDef,
+ None,
+ );
+ intravisit::walk_macro_def(self, macro_def);
+ }
+
fn visit_foreign_item(&mut self, f_item: &'tcx ForeignItem<'tcx>) {
let target = Target::from_foreign_item(f_item);
self.check_attributes(
@@ -988,11 +1200,28 @@
}
}
+fn check_invalid_macro_level_attr(tcx: TyCtxt<'_>, attrs: &[Attribute]) {
+ for attr in attrs {
+ if tcx.sess.check_name(attr, sym::inline) {
+ struct_span_err!(
+ tcx.sess,
+ attr.span,
+ E0518,
+ "attribute should be applied to function or closure",
+ )
+ .span_label(attr.span, "not a function or closure")
+ .emit();
+ }
+ }
+}
+
fn check_mod_attrs(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
- tcx.hir()
- .visit_item_likes_in_module(module_def_id, &mut CheckAttrVisitor { tcx }.as_deep_visitor());
+ let check_attr_visitor = &mut CheckAttrVisitor { tcx };
+ tcx.hir().visit_item_likes_in_module(module_def_id, &mut check_attr_visitor.as_deep_visitor());
+ tcx.hir().visit_exported_macros_in_krate(check_attr_visitor);
+ check_invalid_macro_level_attr(tcx, tcx.hir().krate().non_exported_macro_attrs);
if module_def_id.is_top_level_module() {
- CheckAttrVisitor { tcx }.check_attributes(
+ check_attr_visitor.check_attributes(
CRATE_HIR_ID,
tcx.hir().krate_attrs(),
&DUMMY_SP,
diff --git a/compiler/rustc_passes/src/check_const.rs b/compiler/rustc_passes/src/check_const.rs
index 2d6bbff..8950f9b 100644
--- a/compiler/rustc_passes/src/check_const.rs
+++ b/compiler/rustc_passes/src/check_const.rs
@@ -49,9 +49,7 @@
// All other expressions are allowed.
Self::Loop(Loop | While | WhileLet)
- | Self::Match(
- WhileDesugar | WhileLetDesugar | Normal | IfDesugar { .. } | IfLetDesugar { .. },
- ) => &[],
+ | Self::Match(WhileDesugar | WhileLetDesugar | Normal | IfLetDesugar { .. }) => &[],
};
Some(gates)
@@ -201,7 +199,7 @@
// Skip the following checks if we are not currently in a const context.
_ if self.const_kind.is_none() => {}
- hir::ExprKind::Loop(_, _, source) => {
+ hir::ExprKind::Loop(_, _, source, _) => {
self.const_check_violated(NonConstExpr::Loop(*source), e.span);
}
diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs
index 0015287..3b1b535 100644
--- a/compiler/rustc_passes/src/dead.rs
+++ b/compiler/rustc_passes/src/dead.rs
@@ -23,18 +23,18 @@
// function, then we should explore its block to check for codes that
// may need to be marked as live.
fn should_explore(tcx: TyCtxt<'_>, hir_id: hir::HirId) -> bool {
- match tcx.hir().find(hir_id) {
+ matches!(
+ tcx.hir().find(hir_id),
Some(
Node::Item(..)
- | Node::ImplItem(..)
- | Node::ForeignItem(..)
- | Node::TraitItem(..)
- | Node::Variant(..)
- | Node::AnonConst(..)
- | Node::Pat(..),
- ) => true,
- _ => false,
- }
+ | Node::ImplItem(..)
+ | Node::ForeignItem(..)
+ | Node::TraitItem(..)
+ | Node::Variant(..)
+ | Node::AnonConst(..)
+ | Node::Pat(..),
+ )
+ )
}
struct MarkSymbolVisitor<'tcx> {
@@ -290,6 +290,7 @@
}
fn visit_pat(&mut self, pat: &'tcx hir::Pat<'tcx>) {
+ self.in_pat = true;
match pat.kind {
PatKind::Struct(ref path, ref fields, _) => {
let res = self.typeck_results().qpath_res(path, pat.hir_id);
@@ -302,7 +303,6 @@
_ => (),
}
- self.in_pat = true;
intravisit::walk_pat(self, pat);
self.in_pat = false;
}
@@ -396,7 +396,7 @@
}
}
}
- hir::ItemKind::Impl { ref of_trait, items, .. } => {
+ hir::ItemKind::Impl(hir::Impl { ref of_trait, items, .. }) => {
if of_trait.is_some() {
self.worklist.push(item.hir_id);
}
@@ -500,16 +500,16 @@
impl DeadVisitor<'tcx> {
fn should_warn_about_item(&mut self, item: &hir::Item<'_>) -> bool {
- let should_warn = match item.kind {
+ let should_warn = matches!(
+ item.kind,
hir::ItemKind::Static(..)
- | hir::ItemKind::Const(..)
- | hir::ItemKind::Fn(..)
- | hir::ItemKind::TyAlias(..)
- | hir::ItemKind::Enum(..)
- | hir::ItemKind::Struct(..)
- | hir::ItemKind::Union(..) => true,
- _ => false,
- };
+ | hir::ItemKind::Const(..)
+ | hir::ItemKind::Fn(..)
+ | hir::ItemKind::TyAlias(..)
+ | hir::ItemKind::Enum(..)
+ | hir::ItemKind::Struct(..)
+ | hir::ItemKind::Union(..)
+ );
should_warn && !self.symbol_is_live(item.hir_id)
}
diff --git a/compiler/rustc_passes/src/intrinsicck.rs b/compiler/rustc_passes/src/intrinsicck.rs
index 711e8e8..0f4bb635 100644
--- a/compiler/rustc_passes/src/intrinsicck.rs
+++ b/compiler/rustc_passes/src/intrinsicck.rs
@@ -1,4 +1,4 @@
-use rustc_ast::{FloatTy, InlineAsmTemplatePiece, IntTy, UintTy};
+use rustc_ast::InlineAsmTemplatePiece;
use rustc_errors::struct_span_err;
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
@@ -7,7 +7,7 @@
use rustc_index::vec::Idx;
use rustc_middle::ty::layout::{LayoutError, SizeSkeleton};
use rustc_middle::ty::query::Providers;
-use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_middle::ty::{self, FloatTy, IntTy, Ty, TyCtxt, UintTy};
use rustc_session::lint;
use rustc_span::{sym, Span, Symbol, DUMMY_SP};
use rustc_target::abi::{Pointer, VariantIdx};
@@ -78,7 +78,7 @@
return;
}
- // Special-case transmutting from `typeof(function)` and
+ // Special-case transmuting from `typeof(function)` and
// `Option<typeof(function)>` to present a clearer error.
let from = unpack_option_like(self.tcx, from);
if let (&ty::FnDef(..), SizeSkeleton::Known(size_to)) = (from.kind(), sk_to) {
diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs
index 86ce35c..c11dc231 100644
--- a/compiler/rustc_passes/src/liveness.rs
+++ b/compiler/rustc_passes/src/liveness.rs
@@ -367,10 +367,7 @@
}
fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) {
- let is_shorthand = match param.pat.kind {
- rustc_hir::PatKind::Struct(..) => true,
- _ => false,
- };
+ let is_shorthand = matches!(param.pat.kind, rustc_hir::PatKind::Struct(..));
param.pat.each_binding(|_bm, hir_id, _x, ident| {
let var = if is_shorthand {
Local(LocalInfo { id: hir_id, name: ident.name, is_shorthand: true })
@@ -422,7 +419,7 @@
}
// live nodes required for interesting control flow:
- hir::ExprKind::Match(..) | hir::ExprKind::Loop(..) => {
+ hir::ExprKind::If(..) | hir::ExprKind::Match(..) | hir::ExprKind::Loop(..) => {
self.add_live_node_for_node(expr.hir_id, ExprNode(expr.span));
intravisit::walk_expr(self, expr);
}
@@ -847,7 +844,30 @@
// Note that labels have been resolved, so we don't need to look
// at the label ident
- hir::ExprKind::Loop(ref blk, _, _) => self.propagate_through_loop(expr, &blk, succ),
+ hir::ExprKind::Loop(ref blk, ..) => self.propagate_through_loop(expr, &blk, succ),
+
+ hir::ExprKind::If(ref cond, ref then, ref else_opt) => {
+ //
+ // (cond)
+ // |
+ // v
+ // (expr)
+ // / \
+ // | |
+ // v v
+ // (then)(els)
+ // | |
+ // v v
+ // ( succ )
+ //
+ let else_ln =
+ self.propagate_through_opt_expr(else_opt.as_ref().map(|e| &**e), succ);
+ let then_ln = self.propagate_through_expr(&then, succ);
+ let ln = self.live_node(expr.hir_id, expr.span);
+ self.init_from_succ(ln, else_ln);
+ self.merge_from_succ(ln, then_ln);
+ self.propagate_through_expr(&cond, ln)
+ }
hir::ExprKind::Match(ref e, arms, _) => {
//
@@ -1339,6 +1359,7 @@
| hir::ExprKind::Tup(..)
| hir::ExprKind::Binary(..)
| hir::ExprKind::Cast(..)
+ | hir::ExprKind::If(..)
| hir::ExprKind::DropTemps(..)
| hir::ExprKind::Unary(..)
| hir::ExprKind::Ret(..)
@@ -1385,7 +1406,7 @@
fn should_warn(&self, var: Variable) -> Option<String> {
let name = self.ir.variable_name(var);
- if name == kw::Invalid {
+ if name == kw::Empty {
return None;
}
let name: &str = &name.as_str();
diff --git a/compiler/rustc_passes/src/loops.rs b/compiler/rustc_passes/src/loops.rs
index 9b4da71..4bfac1b 100644
--- a/compiler/rustc_passes/src/loops.rs
+++ b/compiler/rustc_passes/src/loops.rs
@@ -53,7 +53,7 @@
fn visit_expr(&mut self, e: &'hir hir::Expr<'hir>) {
match e.kind {
- hir::ExprKind::Loop(ref b, _, source) => {
+ hir::ExprKind::Loop(ref b, _, source, _) => {
self.with_context(Loop(source), |v| v.visit_block(&b));
}
hir::ExprKind::Closure(_, ref function_decl, b, span, movability) => {
@@ -68,18 +68,18 @@
hir::ExprKind::Block(ref b, Some(_label)) => {
self.with_context(LabeledBlock, |v| v.visit_block(&b));
}
- hir::ExprKind::Break(label, ref opt_expr) => {
+ hir::ExprKind::Break(break_label, ref opt_expr) => {
if let Some(e) = opt_expr {
self.visit_expr(e);
}
- if self.require_label_in_labeled_block(e.span, &label, "break") {
+ if self.require_label_in_labeled_block(e.span, &break_label, "break") {
// If we emitted an error about an unlabeled break in a labeled
// block, we don't need any further checking for this break any more
return;
}
- let loop_id = match label.target_id {
+ let loop_id = match break_label.target_id {
Ok(loop_id) => Some(loop_id),
Err(hir::LoopIdError::OutsideLoopScope) => None,
Err(hir::LoopIdError::UnlabeledCfInWhileCondition) => {
@@ -89,49 +89,89 @@
Err(hir::LoopIdError::UnresolvedLabel) => None,
};
- if let Some(loop_id) = loop_id {
- if let Node::Block(_) = self.hir_map.find(loop_id).unwrap() {
- return;
- }
+ if let Some(Node::Block(_)) = loop_id.and_then(|id| self.hir_map.find(id)) {
+ return;
}
- if opt_expr.is_some() {
- let loop_kind = if let Some(loop_id) = loop_id {
- Some(match self.hir_map.expect_expr(loop_id).kind {
- hir::ExprKind::Loop(_, _, source) => source,
+ if let Some(break_expr) = opt_expr {
+ let (head, loop_label, loop_kind) = if let Some(loop_id) = loop_id {
+ match self.hir_map.expect_expr(loop_id).kind {
+ hir::ExprKind::Loop(_, label, source, sp) => {
+ (Some(sp), label, Some(source))
+ }
ref r => {
span_bug!(e.span, "break label resolved to a non-loop: {:?}", r)
}
- })
+ }
} else {
- None
+ (None, None, None)
};
match loop_kind {
None | Some(hir::LoopSource::Loop) => (),
Some(kind) => {
- struct_span_err!(
+ let mut err = struct_span_err!(
self.sess,
e.span,
E0571,
"`break` with value from a `{}` loop",
kind.name()
- )
- .span_label(
+ );
+ err.span_label(
e.span,
- "can only break with a value inside \
- `loop` or breakable block",
- )
- .span_suggestion(
+ "can only break with a value inside `loop` or breakable block",
+ );
+ if let Some(head) = head {
+ err.span_label(
+ head,
+ &format!(
+ "you can't `break` with a value in a `{}` loop",
+ kind.name()
+ ),
+ );
+ }
+ err.span_suggestion(
e.span,
&format!(
- "instead, use `break` on its own \
- without a value inside this `{}` loop",
- kind.name()
+ "use `break` on its own without a value inside this `{}` loop",
+ kind.name(),
),
- "break".to_string(),
+ format!(
+ "break{}",
+ break_label
+ .label
+ .map_or_else(String::new, |l| format!(" {}", l.ident))
+ ),
Applicability::MaybeIncorrect,
- )
- .emit();
+ );
+ if let (Some(label), None) = (loop_label, break_label.label) {
+ match break_expr.kind {
+ hir::ExprKind::Path(hir::QPath::Resolved(
+ None,
+ hir::Path {
+ segments: [segment],
+ res: hir::def::Res::Err,
+ ..
+ },
+ )) if label.ident.to_string()
+ == format!("'{}", segment.ident) =>
+ {
+ // This error is redundant, we will have already emitted a
+ // suggestion to use the label when `segment` wasn't found
+ // (hence the `Res::Err` check).
+ err.delay_as_bug();
+ }
+ _ => {
+ err.span_suggestion(
+ break_expr.span,
+ "alternatively, you might have meant to use the \
+ available loop label",
+ label.ident.to_string(),
+ Applicability::MaybeIncorrect,
+ );
+ }
+ }
+ }
+ err.emit();
}
}
}
diff --git a/compiler/rustc_passes/src/naked_functions.rs b/compiler/rustc_passes/src/naked_functions.rs
index 5b50ef8..93fb23c0 100644
--- a/compiler/rustc_passes/src/naked_functions.rs
+++ b/compiler/rustc_passes/src/naked_functions.rs
@@ -149,7 +149,7 @@
fn check_asm<'tcx>(tcx: TyCtxt<'tcx>, hir_id: HirId, body: &'tcx hir::Body<'tcx>, fn_span: Span) {
let mut this = CheckInlineAssembly { tcx, items: Vec::new() };
this.visit_body(body);
- if let &[(ItemKind::Asm, _)] = &this.items[..] {
+ if let [(ItemKind::Asm, _)] = this.items[..] {
// Ok.
} else {
tcx.struct_span_lint_hir(UNSUPPORTED_NAKED_FUNCTIONS, hir_id, fn_span, |lint| {
@@ -201,6 +201,7 @@
| ExprKind::Type(..)
| ExprKind::Loop(..)
| ExprKind::Match(..)
+ | ExprKind::If(..)
| ExprKind::Closure(..)
| ExprKind::Assign(..)
| ExprKind::AssignOp(..)
diff --git a/compiler/rustc_passes/src/reachable.rs b/compiler/rustc_passes/src/reachable.rs
index fde83af..eb24c51 100644
--- a/compiler/rustc_passes/src/reachable.rs
+++ b/compiler/rustc_passes/src/reachable.rs
@@ -307,6 +307,7 @@
| Node::Ctor(..)
| Node::Field(_)
| Node::Ty(_)
+ | Node::Crate(_)
| Node::MacroDef(_) => {}
_ => {
bug!(
@@ -349,7 +350,9 @@
}
// We need only trait impls here, not inherent impls, and only non-exported ones
- if let hir::ItemKind::Impl { of_trait: Some(ref trait_ref), ref items, .. } = item.kind {
+ if let hir::ItemKind::Impl(hir::Impl { of_trait: Some(ref trait_ref), ref items, .. }) =
+ item.kind
+ {
if !self.access_levels.is_reachable(item.hir_id) {
// FIXME(#53488) remove `let`
let tcx = self.tcx;
diff --git a/compiler/rustc_passes/src/region.rs b/compiler/rustc_passes/src/region.rs
index 1af79ab..64356f7 100644
--- a/compiler/rustc_passes/src/region.rs
+++ b/compiler/rustc_passes/src/region.rs
@@ -241,7 +241,18 @@
terminating(r.hir_id.local_id);
}
- hir::ExprKind::Loop(ref body, _, _) => {
+ hir::ExprKind::If(ref expr, ref then, Some(ref otherwise)) => {
+ terminating(expr.hir_id.local_id);
+ terminating(then.hir_id.local_id);
+ terminating(otherwise.hir_id.local_id);
+ }
+
+ hir::ExprKind::If(ref expr, ref then, None) => {
+ terminating(expr.hir_id.local_id);
+ terminating(then.hir_id.local_id);
+ }
+
+ hir::ExprKind::Loop(ref body, _, _, _) => {
terminating(body.hir_id.local_id);
}
diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs
index 3c2462a..e1d03e3 100644
--- a/compiler/rustc_passes/src/stability.rs
+++ b/compiler/rustc_passes/src/stability.rs
@@ -55,6 +55,21 @@
}
}
+/// Whether to inherit const stability flags for nested items. In most cases, we do not want to
+/// inherit const stability: just because an enclosing `fn` is const-stable does not mean
+/// all `extern` imports declared in it should be const-stable! However, trait methods
+/// inherit const stability attributes from their parent and do not have their own.
+enum InheritConstStability {
+ Yes,
+ No,
+}
+
+impl InheritConstStability {
+ fn yes(&self) -> bool {
+ matches!(self, InheritConstStability::Yes)
+ }
+}
+
// A private tree-walker for producing an Index.
struct Annotator<'a, 'tcx> {
tcx: TyCtxt<'tcx>,
@@ -75,6 +90,7 @@
item_sp: Span,
kind: AnnotationKind,
inherit_deprecation: InheritDeprecation,
+ inherit_const_stability: InheritConstStability,
visit_children: F,
) where
F: FnOnce(&mut Self),
@@ -140,6 +156,8 @@
const_stab
});
+ // `impl const Trait for Type` items forward their const stability to their
+ // immediate children.
if const_stab.is_none() {
debug!("annotate: const_stab not found, parent = {:?}", self.parent_const_stab);
if let Some(parent) = self.parent_const_stab {
@@ -228,7 +246,7 @@
self.recurse_with_stability_attrs(
depr.map(|(d, _)| DeprecationEntry::local(d, hir_id)),
stab,
- const_stab,
+ if inherit_const_stability.yes() { const_stab } else { None },
visit_children,
);
}
@@ -325,18 +343,21 @@
fn visit_item(&mut self, i: &'tcx Item<'tcx>) {
let orig_in_trait_impl = self.in_trait_impl;
let mut kind = AnnotationKind::Required;
+ let mut const_stab_inherit = InheritConstStability::No;
match i.kind {
// Inherent impls and foreign modules serve only as containers for other items,
// they don't have their own stability. They still can be annotated as unstable
// and propagate this unstability to children, but this annotation is completely
// optional. They inherit stability from their parents when unannotated.
- hir::ItemKind::Impl { of_trait: None, .. } | hir::ItemKind::ForeignMod { .. } => {
+ hir::ItemKind::Impl(hir::Impl { of_trait: None, .. })
+ | hir::ItemKind::ForeignMod { .. } => {
self.in_trait_impl = false;
kind = AnnotationKind::Container;
}
- hir::ItemKind::Impl { of_trait: Some(_), .. } => {
+ hir::ItemKind::Impl(hir::Impl { of_trait: Some(_), .. }) => {
self.in_trait_impl = true;
kind = AnnotationKind::DeprecationProhibited;
+ const_stab_inherit = InheritConstStability::Yes;
}
hir::ItemKind::Struct(ref sd, _) => {
if let Some(ctor_hir_id) = sd.ctor_hir_id() {
@@ -346,6 +367,7 @@
i.span,
AnnotationKind::Required,
InheritDeprecation::Yes,
+ InheritConstStability::No,
|_| {},
)
}
@@ -353,9 +375,15 @@
_ => {}
}
- self.annotate(i.hir_id, &i.attrs, i.span, kind, InheritDeprecation::Yes, |v| {
- intravisit::walk_item(v, i)
- });
+ self.annotate(
+ i.hir_id,
+ &i.attrs,
+ i.span,
+ kind,
+ InheritDeprecation::Yes,
+ const_stab_inherit,
+ |v| intravisit::walk_item(v, i),
+ );
self.in_trait_impl = orig_in_trait_impl;
}
@@ -366,6 +394,7 @@
ti.span,
AnnotationKind::Required,
InheritDeprecation::Yes,
+ InheritConstStability::No,
|v| {
intravisit::walk_trait_item(v, ti);
},
@@ -375,9 +404,17 @@
fn visit_impl_item(&mut self, ii: &'tcx hir::ImplItem<'tcx>) {
let kind =
if self.in_trait_impl { AnnotationKind::Prohibited } else { AnnotationKind::Required };
- self.annotate(ii.hir_id, &ii.attrs, ii.span, kind, InheritDeprecation::Yes, |v| {
- intravisit::walk_impl_item(v, ii);
- });
+ self.annotate(
+ ii.hir_id,
+ &ii.attrs,
+ ii.span,
+ kind,
+ InheritDeprecation::Yes,
+ InheritConstStability::No,
+ |v| {
+ intravisit::walk_impl_item(v, ii);
+ },
+ );
}
fn visit_variant(&mut self, var: &'tcx Variant<'tcx>, g: &'tcx Generics<'tcx>, item_id: HirId) {
@@ -387,6 +424,7 @@
var.span,
AnnotationKind::Required,
InheritDeprecation::Yes,
+ InheritConstStability::No,
|v| {
if let Some(ctor_hir_id) = var.data.ctor_hir_id() {
v.annotate(
@@ -395,6 +433,7 @@
var.span,
AnnotationKind::Required,
InheritDeprecation::Yes,
+ InheritConstStability::No,
|_| {},
);
}
@@ -411,6 +450,7 @@
s.span,
AnnotationKind::Required,
InheritDeprecation::Yes,
+ InheritConstStability::No,
|v| {
intravisit::walk_struct_field(v, s);
},
@@ -424,6 +464,7 @@
i.span,
AnnotationKind::Required,
InheritDeprecation::Yes,
+ InheritConstStability::No,
|v| {
intravisit::walk_foreign_item(v, i);
},
@@ -437,22 +478,31 @@
md.span,
AnnotationKind::Required,
InheritDeprecation::Yes,
+ InheritConstStability::No,
|_| {},
);
}
fn visit_generic_param(&mut self, p: &'tcx hir::GenericParam<'tcx>) {
let kind = match &p.kind {
- // FIXME(const_generics:defaults)
+ // FIXME(const_generics_defaults)
hir::GenericParamKind::Type { default, .. } if default.is_some() => {
AnnotationKind::Container
}
_ => AnnotationKind::Prohibited,
};
- self.annotate(p.hir_id, &p.attrs, p.span, kind, InheritDeprecation::No, |v| {
- intravisit::walk_generic_param(v, p);
- });
+ self.annotate(
+ p.hir_id,
+ &p.attrs,
+ p.span,
+ kind,
+ InheritDeprecation::No,
+ InheritConstStability::No,
+ |v| {
+ intravisit::walk_generic_param(v, p);
+ },
+ );
}
}
@@ -503,7 +553,8 @@
// optional. They inherit stability from their parents when unannotated.
if !matches!(
i.kind,
- hir::ItemKind::Impl { of_trait: None, .. } | hir::ItemKind::ForeignMod { .. }
+ hir::ItemKind::Impl(hir::Impl { of_trait: None, .. })
+ | hir::ItemKind::ForeignMod { .. }
) {
self.check_missing_stability(i.hir_id, i.span);
}
@@ -617,6 +668,7 @@
krate.item.span,
AnnotationKind::Required,
InheritDeprecation::Yes,
+ InheritConstStability::No,
|v| intravisit::walk_crate(v, krate),
);
}
@@ -672,7 +724,7 @@
// For implementations of traits, check the stability of each item
// individually as it's possible to have a stable trait with unstable
// items.
- hir::ItemKind::Impl { of_trait: Some(ref t), self_ty, items, .. } => {
+ hir::ItemKind::Impl(hir::Impl { of_trait: Some(ref t), self_ty, items, .. }) => {
if self.tcx.features().staged_api {
// If this impl block has an #[unstable] attribute, give an
// error if all involved types and traits are stable, because
diff --git a/compiler/rustc_passes/src/weak_lang_items.rs b/compiler/rustc_passes/src/weak_lang_items.rs
index 4273d60..daff94c 100644
--- a/compiler/rustc_passes/src/weak_lang_items.rs
+++ b/compiler/rustc_passes/src/weak_lang_items.rs
@@ -59,7 +59,7 @@
}
}
- for (name, &item) in WEAK_ITEMS_REFS.iter() {
+ for (name, item) in WEAK_ITEMS_REFS.clone().into_sorted_vector().into_iter() {
if missing.contains(&item) && required(tcx, item) && items.require(item).is_err() {
if item == LangItem::PanicImpl {
tcx.sess.err("`#[panic_handler]` function required, but not found");
diff --git a/compiler/rustc_privacy/Cargo.toml b/compiler/rustc_privacy/Cargo.toml
index ce83dc1..85e584d 100644
--- a/compiler/rustc_privacy/Cargo.toml
+++ b/compiler/rustc_privacy/Cargo.toml
@@ -13,4 +13,5 @@
rustc_session = { path = "../rustc_session" }
rustc_span = { path = "../rustc_span" }
rustc_data_structures = { path = "../rustc_data_structures" }
+rustc_trait_selection = { path = "../rustc_trait_selection" }
tracing = "0.1"
diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs
index 3b4249a..631dcb6 100644
--- a/compiler/rustc_privacy/src/lib.rs
+++ b/compiler/rustc_privacy/src/lib.rs
@@ -18,15 +18,17 @@
use rustc_middle::bug;
use rustc_middle::hir::map::Map;
use rustc_middle::middle::privacy::{AccessLevel, AccessLevels};
+use rustc_middle::mir::abstract_const::Node as ACNode;
use rustc_middle::span_bug;
use rustc_middle::ty::fold::TypeVisitor;
use rustc_middle::ty::query::Providers;
-use rustc_middle::ty::subst::InternalSubsts;
-use rustc_middle::ty::{self, GenericParamDefKind, TraitRef, Ty, TyCtxt, TypeFoldable};
+use rustc_middle::ty::subst::{InternalSubsts, Subst};
+use rustc_middle::ty::{self, Const, GenericParamDefKind, TraitRef, Ty, TyCtxt, TypeFoldable};
use rustc_session::lint;
use rustc_span::hygiene::Transparency;
use rustc_span::symbol::{kw, Ident};
use rustc_span::Span;
+use rustc_trait_selection::traits::const_evaluatable::{self, AbstractConst};
use std::marker::PhantomData;
use std::ops::ControlFlow;
@@ -100,31 +102,47 @@
}
fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ControlFlow<V::BreakTy> {
- match predicate.skip_binders() {
- ty::PredicateAtom::Trait(ty::TraitPredicate { trait_ref }, _) => {
+ match predicate.kind().skip_binder() {
+ ty::PredicateKind::Trait(ty::TraitPredicate { trait_ref }, _) => {
self.visit_trait(trait_ref)
}
- ty::PredicateAtom::Projection(ty::ProjectionPredicate { projection_ty, ty }) => {
+ ty::PredicateKind::Projection(ty::ProjectionPredicate { projection_ty, ty }) => {
ty.visit_with(self)?;
self.visit_trait(projection_ty.trait_ref(self.def_id_visitor.tcx()))
}
- ty::PredicateAtom::TypeOutlives(ty::OutlivesPredicate(ty, _region)) => {
+ ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(ty, _region)) => {
ty.visit_with(self)
}
- ty::PredicateAtom::RegionOutlives(..) => ControlFlow::CONTINUE,
- ty::PredicateAtom::ConstEvaluatable(..)
+ ty::PredicateKind::RegionOutlives(..) => ControlFlow::CONTINUE,
+ ty::PredicateKind::ConstEvaluatable(defs, substs)
if self.def_id_visitor.tcx().features().const_evaluatable_checked =>
{
- // FIXME(const_evaluatable_checked): If the constant used here depends on a
- // private function we may have to do something here...
- //
- // For now, let's just pretend that everything is fine.
+ let tcx = self.def_id_visitor.tcx();
+ if let Ok(Some(ct)) = AbstractConst::new(tcx, defs, substs) {
+ self.visit_abstract_const_expr(tcx, ct)?;
+ }
ControlFlow::CONTINUE
}
_ => bug!("unexpected predicate: {:?}", predicate),
}
}
+ fn visit_abstract_const_expr(
+ &mut self,
+ tcx: TyCtxt<'tcx>,
+ ct: AbstractConst<'tcx>,
+ ) -> ControlFlow<V::BreakTy> {
+ const_evaluatable::walk_abstract_const(tcx, ct, |node| match node.root() {
+ ACNode::Leaf(leaf) => {
+ let leaf = leaf.subst(tcx, ct.substs);
+ self.visit_const(leaf)
+ }
+ ACNode::Binop(..) | ACNode::UnaryOp(..) | ACNode::FunctionCall(_, _) => {
+ ControlFlow::CONTINUE
+ }
+ })
+ }
+
fn visit_predicates(
&mut self,
predicates: ty::GenericPredicates<'tcx>,
@@ -241,6 +259,15 @@
ty.super_visit_with(self)
}
}
+
+ fn visit_const(&mut self, c: &'tcx Const<'tcx>) -> ControlFlow<Self::BreakTy> {
+ self.visit_ty(c.ty)?;
+ let tcx = self.def_id_visitor.tcx();
+ if let Ok(Some(ct)) = AbstractConst::from_const(tcx, c) {
+ self.visit_abstract_const_expr(tcx, ct)?;
+ }
+ ControlFlow::CONTINUE
+ }
}
fn min(vis1: ty::Visibility, vis2: ty::Visibility, tcx: TyCtxt<'_>) -> ty::Visibility {
@@ -632,9 +659,9 @@
}
}
}
- hir::ItemKind::Impl { ref of_trait, items, .. } => {
- for impl_item_ref in items {
- if of_trait.is_some() || impl_item_ref.vis.node.is_pub() {
+ hir::ItemKind::Impl(ref impl_) => {
+ for impl_item_ref in impl_.items {
+ if impl_.of_trait.is_some() || impl_item_ref.vis.node.is_pub() {
self.update(impl_item_ref.id.hir_id, item_level);
}
}
@@ -736,11 +763,11 @@
}
}
// Visit everything except for private impl items.
- hir::ItemKind::Impl { items, .. } => {
+ hir::ItemKind::Impl(ref impl_) => {
if item_level.is_some() {
self.reach(item.hir_id, item_level).generics().predicates().ty().trait_ref();
- for impl_item_ref in items {
+ for impl_item_ref in impl_.items {
let impl_item_level = self.get(impl_item_ref.id.hir_id);
if impl_item_level.is_some() {
self.reach(impl_item_ref.id.hir_id, impl_item_level)
@@ -832,21 +859,24 @@
}
fn visit_macro_def(&mut self, md: &'tcx hir::MacroDef<'tcx>) {
+ // Non-opaque macros cannot make other items more accessible than they already are.
if attr::find_transparency(&self.tcx.sess, &md.attrs, md.ast.macro_rules).0
!= Transparency::Opaque
{
- self.update(md.hir_id, Some(AccessLevel::Public));
+ // `#[macro_export]`-ed `macro_rules!` are `Public` since they
+ // ignore their containing path to always appear at the crate root.
+ if md.ast.macro_rules {
+ self.update(md.hir_id, Some(AccessLevel::Public));
+ }
return;
}
let macro_module_def_id =
ty::DefIdTree::parent(self.tcx, self.tcx.hir().local_def_id(md.hir_id).to_def_id())
.unwrap();
- // FIXME(#71104) Should really be using just `as_local_hir_id` but
- // some `DefId` do not seem to have a corresponding HirId.
let hir_id = macro_module_def_id
.as_local()
- .and_then(|def_id| self.tcx.hir().opt_local_def_id_to_hir_id(def_id));
+ .map(|def_id| self.tcx.hir().local_def_id_to_hir_id(def_id));
let mut module_id = match hir_id {
Some(module_id) if self.tcx.hir().is_hir_id_module(module_id) => module_id,
// `module_id` doesn't correspond to a `mod`, return early (#63164, #65252).
@@ -959,7 +989,7 @@
in_update_syntax: bool,
) {
// definition of the field
- let ident = Ident::new(kw::Invalid, use_ctxt);
+ let ident = Ident::new(kw::Empty, use_ctxt);
let current_hir = self.current_item.unwrap();
let def_id = self.tcx.adjust_ident_and_get_scope(ident, def.did, current_hir).1;
if !def.is_enum() && !field.vis.is_accessible_from(def_id, self.tcx) {
@@ -1447,7 +1477,7 @@
// (i.e., we could just return here to not check them at
// all, or some worse estimation of whether an impl is
// publicly visible).
- hir::ItemKind::Impl { generics: ref g, ref of_trait, ref self_ty, items, .. } => {
+ hir::ItemKind::Impl(ref impl_) => {
// `impl [... for] Private` is never visible.
let self_contains_private;
// `impl [... for] Public<...>`, but not `impl [... for]
@@ -1462,7 +1492,7 @@
at_outer_type: true,
outer_type_is_public_path: false,
};
- visitor.visit_ty(&self_ty);
+ visitor.visit_ty(&impl_.self_ty);
self_contains_private = visitor.contains_private;
self_is_public_path = visitor.outer_type_is_public_path;
}
@@ -1470,7 +1500,7 @@
// Miscellaneous info about the impl:
// `true` iff this is `impl Private for ...`.
- let not_private_trait = of_trait.as_ref().map_or(
+ let not_private_trait = impl_.of_trait.as_ref().map_or(
true, // no trait counts as public trait
|tr| {
let did = tr.path.res.def_id();
@@ -1491,8 +1521,8 @@
// directly because we might have `impl<T: Foo<Private>> ...`,
// and we shouldn't warn about the generics if all the methods
// are private (because `T` won't be visible externally).
- let trait_or_some_public_method = of_trait.is_some()
- || items.iter().any(|impl_item_ref| {
+ let trait_or_some_public_method = impl_.of_trait.is_some()
+ || impl_.items.iter().any(|impl_item_ref| {
let impl_item = self.tcx.hir().impl_item(impl_item_ref.id);
match impl_item.kind {
hir::ImplItemKind::Const(..) | hir::ImplItemKind::Fn(..) => {
@@ -1503,11 +1533,11 @@
});
if !self_contains_private && not_private_trait && trait_or_some_public_method {
- intravisit::walk_generics(self, g);
+ intravisit::walk_generics(self, &impl_.generics);
- match of_trait {
+ match impl_.of_trait {
None => {
- for impl_item_ref in items {
+ for impl_item_ref in impl_.items {
// This is where we choose whether to walk down
// further into the impl to check its items. We
// should only walk into public items so that we
@@ -1528,7 +1558,7 @@
}
}
}
- Some(tr) => {
+ Some(ref tr) => {
// Any private types in a trait impl fall into three
// categories.
// 1. mentioned in the trait definition
@@ -1545,7 +1575,7 @@
intravisit::walk_path(self, &tr.path);
// Those in 3. are warned with this call.
- for impl_item_ref in items {
+ for impl_item_ref in impl_.items {
let impl_item = self.tcx.hir().impl_item(impl_item_ref.id);
if let hir::ImplItemKind::TyAlias(ref ty) = impl_item.kind {
self.visit_ty(ty);
@@ -1553,11 +1583,11 @@
}
}
}
- } else if of_trait.is_none() && self_is_public_path {
+ } else if impl_.of_trait.is_none() && self_is_public_path {
// `impl Public<Private> { ... }`. Any public static
// methods will be visible as `Public::foo`.
let mut found_pub_static = false;
- for impl_item_ref in items {
+ for impl_item_ref in impl_.items {
if self.item_is_public(&impl_item_ref.id.hir_id, &impl_item_ref.vis) {
let impl_item = self.tcx.hir().impl_item(impl_item_ref.id);
match impl_item_ref.kind {
@@ -1574,7 +1604,7 @@
}
}
if found_pub_static {
- intravisit::walk_generics(self, g)
+ intravisit::walk_generics(self, &impl_.generics)
}
}
return;
@@ -1967,11 +1997,11 @@
// Subitems of inherent impls have their own publicity.
// A trait impl is public when both its type and its trait are public
// Subitems of trait impls have inherited publicity.
- hir::ItemKind::Impl { ref of_trait, items, .. } => {
+ hir::ItemKind::Impl(ref impl_) => {
let impl_vis = ty::Visibility::of_impl(item.hir_id, tcx, &Default::default());
self.check(item.hir_id, impl_vis).generics().predicates();
- for impl_item_ref in items {
- let impl_item_vis = if of_trait.is_none() {
+ for impl_item_ref in impl_.items {
+ let impl_item_vis = if impl_.of_trait.is_none() {
min(
tcx.visibility(tcx.hir().local_def_id(impl_item_ref.id.hir_id)),
impl_vis,
@@ -2029,7 +2059,7 @@
Node::ImplItem(impl_item) => {
match tcx.hir().get(tcx.hir().get_parent_item(hir_id)) {
Node::Item(hir::Item {
- kind: hir::ItemKind::Impl { of_trait: Some(tr), .. },
+ kind: hir::ItemKind::Impl(hir::Impl { of_trait: Some(tr), .. }),
..
}) => tr.path.res.opt_def_id().map_or_else(
|| {
diff --git a/compiler/rustc_query_system/src/dep_graph/dep_node.rs b/compiler/rustc_query_system/src/dep_graph/dep_node.rs
index ff52fda..64aba87 100644
--- a/compiler/rustc_query_system/src/dep_graph/dep_node.rs
+++ b/compiler/rustc_query_system/src/dep_graph/dep_node.rs
@@ -153,12 +153,6 @@
}
}
-impl<Ctxt: DepContext> DepNodeParams<Ctxt> for () {
- fn to_fingerprint(&self, _: Ctxt) -> Fingerprint {
- Fingerprint::ZERO
- }
-}
-
/// A "work product" corresponds to a `.o` (or other) file that we
/// save in between runs. These IDs do not have a `DefId` but rather
/// some independent path or string that persists between runs without
diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs
index 605d7ae..4fb3a68 100644
--- a/compiler/rustc_query_system/src/dep_graph/graph.rs
+++ b/compiler/rustc_query_system/src/dep_graph/graph.rs
@@ -7,6 +7,7 @@
use rustc_data_structures::unlikely;
use rustc_errors::Diagnostic;
use rustc_index::vec::{Idx, IndexVec};
+use rustc_serialize::{Encodable, Encoder};
use parking_lot::{Condvar, Mutex};
use smallvec::{smallvec, SmallVec};
@@ -21,7 +22,7 @@
use super::debug::EdgeFilter;
use super::prev::PreviousDepGraph;
use super::query::DepGraphQuery;
-use super::serialized::{SerializedDepGraph, SerializedDepNodeIndex};
+use super::serialized::SerializedDepNodeIndex;
use super::{DepContext, DepKind, DepNode, WorkProductId};
#[derive(Clone)]
@@ -148,7 +149,7 @@
let mut edge_list_indices = Vec::with_capacity(node_count);
let mut edge_list_data = Vec::with_capacity(edge_count);
- // See `serialize` for notes on the approach used here.
+ // See `DepGraph`'s `Encodable` implementation for notes on the approach used here.
edge_list_data.extend(data.unshared_edges.iter().map(|i| i.index()));
@@ -551,19 +552,6 @@
self.data.as_ref()?.dep_node_debug.borrow().get(&dep_node).cloned()
}
- pub fn edge_deduplication_data(&self) -> Option<(u64, u64)> {
- if cfg!(debug_assertions) {
- let current_dep_graph = &self.data.as_ref().unwrap().current;
-
- Some((
- current_dep_graph.total_read_count.load(Relaxed),
- current_dep_graph.total_duplicate_read_count.load(Relaxed),
- ))
- } else {
- None
- }
- }
-
fn edge_count(&self, node_data: &LockGuard<'_, DepNodeData<K>>) -> usize {
let data = self.data.as_ref().unwrap();
let previous = &data.previous;
@@ -579,84 +567,6 @@
edge_count
}
- pub fn serialize(&self) -> SerializedDepGraph<K> {
- type SDNI = SerializedDepNodeIndex;
-
- let data = self.data.as_ref().unwrap();
- let previous = &data.previous;
-
- // Note locking order: `prev_index_to_index`, then `data`.
- let prev_index_to_index = data.current.prev_index_to_index.lock();
- let data = data.current.data.lock();
- let node_count = data.hybrid_indices.len();
- let edge_count = self.edge_count(&data);
-
- let mut nodes = IndexVec::with_capacity(node_count);
- let mut fingerprints = IndexVec::with_capacity(node_count);
- let mut edge_list_indices = IndexVec::with_capacity(node_count);
- let mut edge_list_data = Vec::with_capacity(edge_count);
-
- // `rustc_middle::ty::query::OnDiskCache` expects nodes to be in
- // `DepNodeIndex` order. The edges in `edge_list_data`, on the other
- // hand, don't need to be in a particular order, as long as each node
- // can reference its edges as a contiguous range within it. This is why
- // we're able to copy `unshared_edges` directly into `edge_list_data`.
- // It meets the above requirements, and each non-dark-green node already
- // knows the range of edges to reference within it, which they'll push
- // onto `edge_list_indices`. Dark green nodes, however, don't have their
- // edges in `unshared_edges`, so need to add them to `edge_list_data`.
-
- edge_list_data.extend(data.unshared_edges.iter().map(|i| SDNI::new(i.index())));
-
- for &hybrid_index in data.hybrid_indices.iter() {
- match hybrid_index.into() {
- HybridIndex::New(i) => {
- let new = &data.new;
- nodes.push(new.nodes[i]);
- fingerprints.push(new.fingerprints[i]);
- let edges = &new.edges[i];
- edge_list_indices.push((edges.start.as_u32(), edges.end.as_u32()));
- }
- HybridIndex::Red(i) => {
- let red = &data.red;
- nodes.push(previous.index_to_node(red.node_indices[i]));
- fingerprints.push(red.fingerprints[i]);
- let edges = &red.edges[i];
- edge_list_indices.push((edges.start.as_u32(), edges.end.as_u32()));
- }
- HybridIndex::LightGreen(i) => {
- let lg = &data.light_green;
- nodes.push(previous.index_to_node(lg.node_indices[i]));
- fingerprints.push(previous.fingerprint_by_index(lg.node_indices[i]));
- let edges = &lg.edges[i];
- edge_list_indices.push((edges.start.as_u32(), edges.end.as_u32()));
- }
- HybridIndex::DarkGreen(prev_index) => {
- nodes.push(previous.index_to_node(prev_index));
- fingerprints.push(previous.fingerprint_by_index(prev_index));
-
- let edges_iter = previous
- .edge_targets_from(prev_index)
- .iter()
- .map(|&dst| prev_index_to_index[dst].as_ref().unwrap());
-
- let start = edge_list_data.len() as u32;
- edge_list_data.extend(edges_iter.map(|i| SDNI::new(i.index())));
- let end = edge_list_data.len() as u32;
- edge_list_indices.push((start, end));
- }
- }
- }
-
- debug_assert_eq!(nodes.len(), node_count);
- debug_assert_eq!(fingerprints.len(), node_count);
- debug_assert_eq!(edge_list_indices.len(), node_count);
- debug_assert_eq!(edge_list_data.len(), edge_count);
- debug_assert!(edge_list_data.len() <= u32::MAX as usize);
-
- SerializedDepGraph { nodes, fingerprints, edge_list_indices, edge_list_data }
- }
-
pub fn node_color(&self, dep_node: &DepNode<K>) -> Option<DepNodeColor> {
if let Some(ref data) = self.data {
if let Some(prev_index) = data.previous.node_to_index_opt(dep_node) {
@@ -953,7 +863,7 @@
// Returns true if the given node has been marked as green during the
// current compilation session. Used in various assertions
pub fn is_green(&self, dep_node: &DepNode<K>) -> bool {
- self.node_color(dep_node).map(|c| c.is_green()).unwrap_or(false)
+ self.node_color(dep_node).map_or(false, |c| c.is_green())
}
// This method loads all on-disk cacheable query results into memory, so
@@ -997,12 +907,251 @@
}
}
+ pub fn print_incremental_info(&self) {
+ #[derive(Clone)]
+ struct Stat<Kind: DepKind> {
+ kind: Kind,
+ node_counter: u64,
+ edge_counter: u64,
+ }
+
+ let data = self.data.as_ref().unwrap();
+ let prev = &data.previous;
+ let current = &data.current;
+ let data = current.data.lock();
+
+ let mut stats: FxHashMap<_, Stat<K>> = FxHashMap::with_hasher(Default::default());
+
+ for &hybrid_index in data.hybrid_indices.iter() {
+ let (kind, edge_count) = match hybrid_index.into() {
+ HybridIndex::New(new_index) => {
+ let kind = data.new.nodes[new_index].kind;
+ let edge_range = &data.new.edges[new_index];
+ (kind, edge_range.end.as_usize() - edge_range.start.as_usize())
+ }
+ HybridIndex::Red(red_index) => {
+ let kind = prev.index_to_node(data.red.node_indices[red_index]).kind;
+ let edge_range = &data.red.edges[red_index];
+ (kind, edge_range.end.as_usize() - edge_range.start.as_usize())
+ }
+ HybridIndex::LightGreen(lg_index) => {
+ let kind = prev.index_to_node(data.light_green.node_indices[lg_index]).kind;
+ let edge_range = &data.light_green.edges[lg_index];
+ (kind, edge_range.end.as_usize() - edge_range.start.as_usize())
+ }
+ HybridIndex::DarkGreen(prev_index) => {
+ let kind = prev.index_to_node(prev_index).kind;
+ let edge_count = prev.edge_targets_from(prev_index).len();
+ (kind, edge_count)
+ }
+ };
+
+ let stat = stats.entry(kind).or_insert(Stat { kind, node_counter: 0, edge_counter: 0 });
+ stat.node_counter += 1;
+ stat.edge_counter += edge_count as u64;
+ }
+
+ let total_node_count = data.hybrid_indices.len();
+ let total_edge_count = self.edge_count(&data);
+
+ // Drop the lock guard.
+ std::mem::drop(data);
+
+ let mut stats: Vec<_> = stats.values().cloned().collect();
+ stats.sort_by_key(|s| -(s.node_counter as i64));
+
+ const SEPARATOR: &str = "[incremental] --------------------------------\
+ ----------------------------------------------\
+ ------------";
+
+ println!("[incremental]");
+ println!("[incremental] DepGraph Statistics");
+ println!("{}", SEPARATOR);
+ println!("[incremental]");
+ println!("[incremental] Total Node Count: {}", total_node_count);
+ println!("[incremental] Total Edge Count: {}", total_edge_count);
+
+ if cfg!(debug_assertions) {
+ let total_edge_reads = current.total_read_count.load(Relaxed);
+ let total_duplicate_edge_reads = current.total_duplicate_read_count.load(Relaxed);
+
+ println!("[incremental] Total Edge Reads: {}", total_edge_reads);
+ println!("[incremental] Total Duplicate Edge Reads: {}", total_duplicate_edge_reads);
+ }
+
+ println!("[incremental]");
+
+ println!(
+ "[incremental] {:<36}| {:<17}| {:<12}| {:<17}|",
+ "Node Kind", "Node Frequency", "Node Count", "Avg. Edge Count"
+ );
+
+ println!(
+ "[incremental] -------------------------------------\
+ |------------------\
+ |-------------\
+ |------------------|"
+ );
+
+ for stat in stats {
+ let node_kind_ratio = (100.0 * (stat.node_counter as f64)) / (total_node_count as f64);
+ let node_kind_avg_edges = (stat.edge_counter as f64) / (stat.node_counter as f64);
+
+ println!(
+ "[incremental] {:<36}|{:>16.1}% |{:>12} |{:>17.1} |",
+ format!("{:?}", stat.kind),
+ node_kind_ratio,
+ stat.node_counter,
+ node_kind_avg_edges,
+ );
+ }
+
+ println!("{}", SEPARATOR);
+ println!("[incremental]");
+ }
+
fn next_virtual_depnode_index(&self) -> DepNodeIndex {
let index = self.virtual_dep_node_index.fetch_add(1, Relaxed);
DepNodeIndex::from_u32(index)
}
}
+impl<E: Encoder, K: DepKind + Encodable<E>> Encodable<E> for DepGraph<K> {
+ fn encode(&self, e: &mut E) -> Result<(), E::Error> {
+ // We used to serialize the dep graph by creating and serializing a `SerializedDepGraph`
+ // using data copied from the `DepGraph`. But copying created a large memory spike, so we
+ // now serialize directly from the `DepGraph` as if it's a `SerializedDepGraph`. Because we
+ // deserialize that data into a `SerializedDepGraph` in the next compilation session, we
+ // need `DepGraph`'s `Encodable` and `SerializedDepGraph`'s `Decodable` implementations to
+ // be in sync. If you update this encoding, be sure to update the decoding, and vice-versa.
+
+ let data = self.data.as_ref().unwrap();
+ let prev = &data.previous;
+
+ // Note locking order: `prev_index_to_index`, then `data`.
+ let prev_index_to_index = data.current.prev_index_to_index.lock();
+ let data = data.current.data.lock();
+ let new = &data.new;
+ let red = &data.red;
+ let lg = &data.light_green;
+
+ let node_count = data.hybrid_indices.len();
+ let edge_count = self.edge_count(&data);
+
+ // `rustc_middle::ty::query::OnDiskCache` expects nodes to be encoded in `DepNodeIndex`
+ // order. The edges in `edge_list_data` don't need to be in a particular order, as long as
+ // each node references its edges as a contiguous range within it. Therefore, we can encode
+ // `edge_list_data` directly from `unshared_edges`. It meets the above requirements, as
+ // each non-dark-green node already knows the range of edges to reference within it, which
+ // they'll encode in `edge_list_indices`. Dark green nodes, however, don't have their edges
+ // in `unshared_edges`, so need to add them to `edge_list_data`.
+
+ use HybridIndex::*;
+
+ // Encoded values (nodes, etc.) are explicitly typed below to avoid inadvertently
+ // serializing data in the wrong format (i.e. one incompatible with `SerializedDepGraph`).
+ e.emit_struct("SerializedDepGraph", 4, |e| {
+ e.emit_struct_field("nodes", 0, |e| {
+ // `SerializedDepGraph` expects this to be encoded as a sequence of `DepNode`s.
+ e.emit_seq(node_count, |e| {
+ for (seq_index, &hybrid_index) in data.hybrid_indices.iter().enumerate() {
+ let node: DepNode<K> = match hybrid_index.into() {
+ New(i) => new.nodes[i],
+ Red(i) => prev.index_to_node(red.node_indices[i]),
+ LightGreen(i) => prev.index_to_node(lg.node_indices[i]),
+ DarkGreen(prev_index) => prev.index_to_node(prev_index),
+ };
+
+ e.emit_seq_elt(seq_index, |e| node.encode(e))?;
+ }
+
+ Ok(())
+ })
+ })?;
+
+ e.emit_struct_field("fingerprints", 1, |e| {
+ // `SerializedDepGraph` expects this to be encoded as a sequence of `Fingerprints`s.
+ e.emit_seq(node_count, |e| {
+ for (seq_index, &hybrid_index) in data.hybrid_indices.iter().enumerate() {
+ let fingerprint: Fingerprint = match hybrid_index.into() {
+ New(i) => new.fingerprints[i],
+ Red(i) => red.fingerprints[i],
+ LightGreen(i) => prev.fingerprint_by_index(lg.node_indices[i]),
+ DarkGreen(prev_index) => prev.fingerprint_by_index(prev_index),
+ };
+
+ e.emit_seq_elt(seq_index, |e| fingerprint.encode(e))?;
+ }
+
+ Ok(())
+ })
+ })?;
+
+ e.emit_struct_field("edge_list_indices", 2, |e| {
+ // `SerializedDepGraph` expects this to be encoded as a sequence of `(u32, u32)`s.
+ e.emit_seq(node_count, |e| {
+ // Dark green node edges start after the unshared (all other nodes') edges.
+ let mut dark_green_edge_index = data.unshared_edges.len();
+
+ for (seq_index, &hybrid_index) in data.hybrid_indices.iter().enumerate() {
+ let edge_indices: (u32, u32) = match hybrid_index.into() {
+ New(i) => (new.edges[i].start.as_u32(), new.edges[i].end.as_u32()),
+ Red(i) => (red.edges[i].start.as_u32(), red.edges[i].end.as_u32()),
+ LightGreen(i) => (lg.edges[i].start.as_u32(), lg.edges[i].end.as_u32()),
+ DarkGreen(prev_index) => {
+ let edge_count = prev.edge_targets_from(prev_index).len();
+ let start = dark_green_edge_index as u32;
+ dark_green_edge_index += edge_count;
+ let end = dark_green_edge_index as u32;
+ (start, end)
+ }
+ };
+
+ e.emit_seq_elt(seq_index, |e| edge_indices.encode(e))?;
+ }
+
+ assert_eq!(dark_green_edge_index, edge_count);
+
+ Ok(())
+ })
+ })?;
+
+ e.emit_struct_field("edge_list_data", 3, |e| {
+ // `SerializedDepGraph` expects this to be encoded as a sequence of
+ // `SerializedDepNodeIndex`.
+ e.emit_seq(edge_count, |e| {
+ for (seq_index, &edge) in data.unshared_edges.iter().enumerate() {
+ let serialized_edge = SerializedDepNodeIndex::new(edge.index());
+ e.emit_seq_elt(seq_index, |e| serialized_edge.encode(e))?;
+ }
+
+ let mut seq_index = data.unshared_edges.len();
+
+ for &hybrid_index in data.hybrid_indices.iter() {
+ if let DarkGreen(prev_index) = hybrid_index.into() {
+ for &edge in prev.edge_targets_from(prev_index) {
+ // Dark green node edges are stored in the previous graph
+ // and must be converted to edges in the current graph,
+ // and then serialized as `SerializedDepNodeIndex`.
+ let serialized_edge = SerializedDepNodeIndex::new(
+ prev_index_to_index[edge].as_ref().unwrap().index(),
+ );
+
+ e.emit_seq_elt(seq_index, |e| serialized_edge.encode(e))?;
+ seq_index += 1;
+ }
+ }
+ }
+
+ assert_eq!(seq_index, edge_count);
+
+ Ok(())
+ })
+ })
+ })
+ }
+}
+
/// A "work product" is an intermediate result that we save into the
/// incremental directory for later re-use. The primary example are
/// the object files that we save for each partition at code
diff --git a/compiler/rustc_query_system/src/dep_graph/mod.rs b/compiler/rustc_query_system/src/dep_graph/mod.rs
index da0b5aa..b1c9016 100644
--- a/compiler/rustc_query_system/src/dep_graph/mod.rs
+++ b/compiler/rustc_query_system/src/dep_graph/mod.rs
@@ -61,7 +61,7 @@
}
/// Describe the different families of dependency nodes.
-pub trait DepKind: Copy + fmt::Debug + Eq + Ord + Hash {
+pub trait DepKind: Copy + fmt::Debug + Eq + Hash {
const NULL: Self;
/// Return whether this kind always require evaluation.
diff --git a/compiler/rustc_query_system/src/dep_graph/prev.rs b/compiler/rustc_query_system/src/dep_graph/prev.rs
index 29357ce..c3d0f79 100644
--- a/compiler/rustc_query_system/src/dep_graph/prev.rs
+++ b/compiler/rustc_query_system/src/dep_graph/prev.rs
@@ -3,7 +3,7 @@
use rustc_data_structures::fingerprint::Fingerprint;
use rustc_data_structures::fx::FxHashMap;
-#[derive(Debug, Encodable, Decodable)]
+#[derive(Debug)]
pub struct PreviousDepGraph<K: DepKind> {
data: SerializedDepGraph<K>,
index: FxHashMap<DepNode<K>, SerializedDepNodeIndex>,
diff --git a/compiler/rustc_query_system/src/dep_graph/serialized.rs b/compiler/rustc_query_system/src/dep_graph/serialized.rs
index 28e0740..9bb922b 100644
--- a/compiler/rustc_query_system/src/dep_graph/serialized.rs
+++ b/compiler/rustc_query_system/src/dep_graph/serialized.rs
@@ -3,6 +3,7 @@
use super::{DepKind, DepNode};
use rustc_data_structures::fingerprint::Fingerprint;
use rustc_index::vec::IndexVec;
+use rustc_serialize::{Decodable, Decoder};
// The maximum value of `SerializedDepNodeIndex` leaves the upper two bits
// unused so that we can store multiple index types in `CompressedHybridIndex`,
@@ -14,7 +15,7 @@
}
/// Data for use when recompiling the **current crate**.
-#[derive(Debug, Encodable, Decodable)]
+#[derive(Debug)]
pub struct SerializedDepGraph<K: DepKind> {
/// The set of all DepNodes in the graph
pub nodes: IndexVec<SerializedDepNodeIndex, DepNode<K>>,
@@ -48,3 +49,79 @@
&self.edge_list_data[targets.0 as usize..targets.1 as usize]
}
}
+
+impl<D: Decoder, K: DepKind + Decodable<D>> Decodable<D> for SerializedDepGraph<K> {
+ fn decode(d: &mut D) -> Result<SerializedDepGraph<K>, D::Error> {
+ // We used to serialize the dep graph by creating and serializing a `SerializedDepGraph`
+ // using data copied from the `DepGraph`. But copying created a large memory spike, so we
+ // now serialize directly from the `DepGraph` as if it's a `SerializedDepGraph`. Because we
+ // deserialize that data into a `SerializedDepGraph` in the next compilation session, we
+ // need `DepGraph`'s `Encodable` and `SerializedDepGraph`'s `Decodable` implementations to
+ // be in sync. If you update this decoding, be sure to update the encoding, and vice-versa.
+ //
+ // We mimic the sequence of `Encode` and `Encodable` method calls used by the `DepGraph`'s
+ // `Encodable` implementation with the corresponding sequence of `Decode` and `Decodable`
+ // method calls. E.g. `Decode::read_struct` pairs with `Encode::emit_struct`, `DepNode`'s
+ // `decode` pairs with `DepNode`'s `encode`, and so on. Any decoding methods not associated
+ // with corresponding encoding methods called in `DepGraph`'s `Encodable` implementation
+ // are off limits, because we'd be relying on their implementation details.
+ //
+ // For example, because we know it happens to do the right thing, its tempting to just use
+ // `IndexVec`'s `Decodable` implementation to decode into some of the collections below,
+ // even though `DepGraph` doesn't use its `Encodable` implementation. But the `IndexVec`
+ // implementation could change, and we'd have a bug.
+ //
+ // Variables below are explicitly typed so that anyone who changes the `SerializedDepGraph`
+ // representation without updating this function will encounter a compilation error, and
+ // know to update this and possibly the `DepGraph` `Encodable` implementation accordingly
+ // (the latter should serialize data in a format compatible with our representation).
+
+ d.read_struct("SerializedDepGraph", 4, |d| {
+ let nodes: IndexVec<SerializedDepNodeIndex, DepNode<K>> =
+ d.read_struct_field("nodes", 0, |d| {
+ d.read_seq(|d, len| {
+ let mut v = IndexVec::with_capacity(len);
+ for i in 0..len {
+ v.push(d.read_seq_elt(i, |d| Decodable::decode(d))?);
+ }
+ Ok(v)
+ })
+ })?;
+
+ let fingerprints: IndexVec<SerializedDepNodeIndex, Fingerprint> =
+ d.read_struct_field("fingerprints", 1, |d| {
+ d.read_seq(|d, len| {
+ let mut v = IndexVec::with_capacity(len);
+ for i in 0..len {
+ v.push(d.read_seq_elt(i, |d| Decodable::decode(d))?);
+ }
+ Ok(v)
+ })
+ })?;
+
+ let edge_list_indices: IndexVec<SerializedDepNodeIndex, (u32, u32)> = d
+ .read_struct_field("edge_list_indices", 2, |d| {
+ d.read_seq(|d, len| {
+ let mut v = IndexVec::with_capacity(len);
+ for i in 0..len {
+ v.push(d.read_seq_elt(i, |d| Decodable::decode(d))?);
+ }
+ Ok(v)
+ })
+ })?;
+
+ let edge_list_data: Vec<SerializedDepNodeIndex> =
+ d.read_struct_field("edge_list_data", 3, |d| {
+ d.read_seq(|d, len| {
+ let mut v = Vec::with_capacity(len);
+ for i in 0..len {
+ v.push(d.read_seq_elt(i, |d| Decodable::decode(d))?);
+ }
+ Ok(v)
+ })
+ })?;
+
+ Ok(SerializedDepGraph { nodes, fingerprints, edge_list_indices, edge_list_data })
+ })
+ }
+}
diff --git a/compiler/rustc_query_system/src/query/caches.rs b/compiler/rustc_query_system/src/query/caches.rs
index 7bc6ae1..1d2bc1a 100644
--- a/compiler/rustc_query_system/src/query/caches.rs
+++ b/compiler/rustc_query_system/src/query/caches.rs
@@ -15,7 +15,7 @@
}
pub trait QueryStorage: Default {
- type Value;
+ type Value: Debug;
type Stored: Clone;
/// Store a value without putting it in the cache.
@@ -75,7 +75,7 @@
}
}
-impl<K: Eq + Hash, V: Clone> QueryStorage for DefaultCache<K, V> {
+impl<K: Eq + Hash, V: Clone + Debug> QueryStorage for DefaultCache<K, V> {
type Value = V;
type Stored = V;
@@ -89,7 +89,7 @@
impl<K, V> QueryCache for DefaultCache<K, V>
where
K: Eq + Hash + Clone + Debug,
- V: Clone,
+ V: Clone + Debug,
{
type Key = K;
type Sharded = FxHashMap<K, (V, DepNodeIndex)>;
@@ -156,7 +156,7 @@
}
}
-impl<'tcx, K: Eq + Hash, V: 'tcx> QueryStorage for ArenaCache<'tcx, K, V> {
+impl<'tcx, K: Eq + Hash, V: Debug + 'tcx> QueryStorage for ArenaCache<'tcx, K, V> {
type Value = V;
type Stored = &'tcx V;
@@ -171,6 +171,7 @@
impl<'tcx, K, V: 'tcx> QueryCache for ArenaCache<'tcx, K, V>
where
K: Eq + Hash + Clone + Debug,
+ V: Debug,
{
type Key = K;
type Sharded = FxHashMap<K, &'tcx (V, DepNodeIndex)>;
diff --git a/compiler/rustc_query_system/src/query/plumbing.rs b/compiler/rustc_query_system/src/query/plumbing.rs
index 426f5bb..3653213 100644
--- a/compiler/rustc_query_system/src/query/plumbing.rs
+++ b/compiler/rustc_query_system/src/query/plumbing.rs
@@ -20,6 +20,7 @@
use rustc_span::source_map::DUMMY_SP;
use rustc_span::Span;
use std::collections::hash_map::Entry;
+use std::fmt::Debug;
use std::hash::{Hash, Hasher};
use std::mem;
use std::num::NonZeroU32;
@@ -478,7 +479,7 @@
result
}
-fn load_from_disk_and_cache_in_memory<CTX, K, V>(
+fn load_from_disk_and_cache_in_memory<CTX, K, V: Debug>(
tcx: CTX,
key: K,
prev_dep_node_index: SerializedDepNodeIndex,
@@ -539,7 +540,7 @@
#[inline(never)]
#[cold]
-fn incremental_verify_ich<CTX, K, V>(
+fn incremental_verify_ich<CTX, K, V: Debug>(
tcx: CTX,
result: &V,
dep_node: &DepNode<CTX::DepKind>,
@@ -566,7 +567,6 @@
assert!(new_hash == old_hash, "found unstable fingerprints for {:?}", dep_node,);
}
-#[inline(always)]
fn force_query_with_job<C, CTX>(
tcx: CTX,
key: C::Key,
diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs
index 06e9969..c4ee4df 100644
--- a/compiler/rustc_resolve/src/build_reduced_graph.rs
+++ b/compiler/rustc_resolve/src/build_reduced_graph.rs
@@ -16,8 +16,8 @@
use crate::{Module, ModuleData, ModuleKind, NameBinding, NameBindingKind, Segment, ToNameBinding};
use rustc_ast::visit::{self, AssocCtxt, Visitor};
-use rustc_ast::{self as ast, Block, ForeignItem, ForeignItemKind, Item, ItemKind, NodeId};
-use rustc_ast::{AssocItem, AssocItemKind, MetaItemKind, StmtKind};
+use rustc_ast::{self as ast, AssocItem, AssocItemKind, MetaItemKind, StmtKind};
+use rustc_ast::{Block, FnKind, ForeignItem, ForeignItemKind, ImplKind, Item, ItemKind, NodeId};
use rustc_ast_lowering::ResolverAstLowering;
use rustc_attr as attr;
use rustc_data_structures::sync::Lrc;
@@ -96,7 +96,7 @@
/// Walks up the tree of definitions starting at `def_id`,
/// stopping at the first `DefKind::Mod` encountered
- fn nearest_mod_parent(&mut self, def_id: DefId) -> Module<'a> {
+ fn nearest_parent_mod(&mut self, def_id: DefId) -> Module<'a> {
let def_key = self.cstore().def_key(def_id);
let mut parent_id = DefId {
@@ -115,7 +115,7 @@
self.get_module(parent_id)
}
- crate fn get_module(&mut self, def_id: DefId) -> Module<'a> {
+ pub fn get_module(&mut self, def_id: DefId) -> Module<'a> {
// If this is a local module, it will be in `module_map`, no need to recalculate it.
if let Some(def_id) = def_id.as_local() {
return self.module_map[&def_id];
@@ -137,7 +137,7 @@
.get_opt_name()
.expect("given a DefId that wasn't a module");
- let parent = Some(self.nearest_mod_parent(def_id));
+ let parent = Some(self.nearest_parent_mod(def_id));
(name, parent)
};
@@ -179,21 +179,21 @@
// so this hopefully won't be a problem.
//
// See https://github.com/rust-lang/rust/pull/77984#issuecomment-712445508
- self.nearest_mod_parent(def_id)
+ self.nearest_parent_mod(def_id)
}
}
crate fn get_macro(&mut self, res: Res) -> Option<Lrc<SyntaxExtension>> {
match res {
- Res::Def(DefKind::Macro(..), def_id) => self.get_macro_by_def_id(def_id),
+ Res::Def(DefKind::Macro(..), def_id) => Some(self.get_macro_by_def_id(def_id)),
Res::NonMacroAttr(attr_kind) => Some(self.non_macro_attr(attr_kind.is_used())),
_ => None,
}
}
- crate fn get_macro_by_def_id(&mut self, def_id: DefId) -> Option<Lrc<SyntaxExtension>> {
+ crate fn get_macro_by_def_id(&mut self, def_id: DefId) -> Lrc<SyntaxExtension> {
if let Some(ext) = self.macro_map.get(&def_id) {
- return Some(ext.clone());
+ return ext.clone();
}
let ext = Lrc::new(match self.cstore().load_macro_untracked(def_id, &self.session) {
@@ -202,7 +202,7 @@
});
self.macro_map.insert(def_id, ext.clone());
- Some(ext)
+ ext
}
crate fn build_reduced_graph(
@@ -266,7 +266,7 @@
} else {
// If it's not in an enum, its visibility is restricted to the `mod` item
// that it's defined in.
- Ok(ty::Visibility::Restricted(self.parent_scope.module.normal_ancestor_id))
+ Ok(ty::Visibility::Restricted(self.parent_scope.module.nearest_parent_mod))
}
}
ast::VisibilityKind::Restricted { ref path, id, .. } => {
@@ -342,7 +342,7 @@
let field_names = vdata
.fields()
.iter()
- .map(|field| respan(field.span, field.ident.map_or(kw::Invalid, |ident| ident.name)))
+ .map(|field| respan(field.span, field.ident.map_or(kw::Empty, |ident| ident.name)))
.collect();
self.insert_field_names(def_id, field_names);
}
@@ -525,9 +525,9 @@
ModuleKind::Block(..) => unreachable!(),
};
// HACK(eddyb) unclear how good this is, but keeping `$crate`
- // in `source` breaks `src/test/compile-fail/import-crate-var.rs`,
+ // in `source` breaks `src/test/ui/imports/import-crate-var.rs`,
// while the current crate doesn't have a valid `crate_name`.
- if crate_name != kw::Invalid {
+ if crate_name != kw::Empty {
// `crate_name` should not be interpreted as relative.
module_path.push(Segment {
ident: Ident { name: kw::PathRoot, span: source.ident.span },
@@ -656,7 +656,7 @@
/// Constructs the reduced graph for one item.
fn build_reduced_graph_for_item(&mut self, item: &'b Item) {
- if matches!(item.kind, ItemKind::Mod(..)) && item.ident.name == kw::Invalid {
+ if matches!(item.kind, ItemKind::Mod(..)) && item.ident.name == kw::Empty {
// Fake crate root item from expand.
return;
}
@@ -803,7 +803,7 @@
let module = self.r.new_module(
parent,
module_kind,
- parent.normal_ancestor_id,
+ parent.nearest_parent_mod,
expansion,
item.span,
);
@@ -878,7 +878,7 @@
let module = self.r.new_module(
parent,
module_kind,
- parent.normal_ancestor_id,
+ parent.nearest_parent_mod,
expansion,
item.span,
);
@@ -887,7 +887,7 @@
}
// These items do not add names to modules.
- ItemKind::Impl { of_trait: Some(..), .. } => {
+ ItemKind::Impl(box ImplKind { of_trait: Some(..), .. }) => {
self.r.trait_impl_items.insert(local_def_id);
}
ItemKind::Impl { .. } | ItemKind::ForeignMod(..) | ItemKind::GlobalAsm(..) => {}
@@ -921,7 +921,7 @@
let module = self.r.new_module(
parent,
ModuleKind::Block(block.id),
- parent.normal_ancestor_id,
+ parent.nearest_parent_mod,
expansion,
block.span,
);
@@ -1298,26 +1298,31 @@
method!(visit_ty: ast::Ty, ast::TyKind::MacCall, walk_ty);
fn visit_item(&mut self, item: &'b Item) {
- let macro_use = match item.kind {
+ let orig_module_scope = self.parent_scope.module;
+ self.parent_scope.macro_rules = match item.kind {
ItemKind::MacroDef(..) => {
- self.parent_scope.macro_rules = self.define_macro(item);
- return;
+ let macro_rules_scope = self.define_macro(item);
+ visit::walk_item(self, item);
+ macro_rules_scope
}
ItemKind::MacCall(..) => {
- self.parent_scope.macro_rules = self.visit_invoc_in_module(item.id);
- return;
+ let macro_rules_scope = self.visit_invoc_in_module(item.id);
+ visit::walk_item(self, item);
+ macro_rules_scope
}
- ItemKind::Mod(..) => self.contains_macro_use(&item.attrs),
- _ => false,
+ _ => {
+ let orig_macro_rules_scope = self.parent_scope.macro_rules;
+ self.build_reduced_graph_for_item(item);
+ visit::walk_item(self, item);
+ match item.kind {
+ ItemKind::Mod(..) if self.contains_macro_use(&item.attrs) => {
+ self.parent_scope.macro_rules
+ }
+ _ => orig_macro_rules_scope,
+ }
+ }
};
- let orig_current_module = self.parent_scope.module;
- let orig_current_macro_rules_scope = self.parent_scope.macro_rules;
- self.build_reduced_graph_for_item(item);
- visit::walk_item(self, item);
- self.parent_scope.module = orig_current_module;
- if !macro_use {
- self.parent_scope.macro_rules = orig_current_macro_rules_scope;
- }
+ self.parent_scope.module = orig_module_scope;
}
fn visit_stmt(&mut self, stmt: &'b ast::Stmt) {
@@ -1366,7 +1371,7 @@
AssocCtxt::Trait => {
let (def_kind, ns) = match item.kind {
AssocItemKind::Const(..) => (DefKind::AssocConst, ValueNS),
- AssocItemKind::Fn(_, ref sig, _, _) => {
+ AssocItemKind::Fn(box FnKind(_, ref sig, _, _)) => {
if sig.decl.has_self() {
self.r.has_self.insert(def_id);
}
diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs
index 69773ba..727d6ab 100644
--- a/compiler/rustc_resolve/src/def_collector.rs
+++ b/compiler/rustc_resolve/src/def_collector.rs
@@ -74,7 +74,7 @@
// information we encapsulate into, the better
let def_data = match &i.kind {
ItemKind::Impl { .. } => DefPathData::Impl,
- ItemKind::Mod(..) if i.ident.name == kw::Invalid => {
+ ItemKind::Mod(..) if i.ident.name == kw::Empty => {
// Fake crate root item from expand.
return visit::walk_item(self, i);
}
@@ -91,7 +91,10 @@
DefPathData::ValueNs(i.ident.name)
}
ItemKind::MacroDef(..) => DefPathData::MacroNs(i.ident.name),
- ItemKind::MacCall(..) => return self.visit_macro_invoc(i.id),
+ ItemKind::MacCall(..) => {
+ visit::walk_item(self, i);
+ return self.visit_macro_invoc(i.id);
+ }
ItemKind::GlobalAsm(..) => DefPathData::Misc,
ItemKind::Use(..) => {
return visit::walk_item(self, i);
diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs
index 809de9b..3b02f74 100644
--- a/compiler/rustc_resolve/src/diagnostics.rs
+++ b/compiler/rustc_resolve/src/diagnostics.rs
@@ -398,14 +398,30 @@
err.help("use the `|| { ... }` closure form instead");
err
}
- ResolutionError::AttemptToUseNonConstantValueInConstant => {
+ ResolutionError::AttemptToUseNonConstantValueInConstant(ident, sugg, current) => {
let mut err = struct_span_err!(
self.session,
span,
E0435,
"attempt to use a non-constant value in a constant"
);
- err.span_label(span, "non-constant value");
+ // let foo =...
+ // ^^^ given this Span
+ // ------- get this Span to have an applicable suggestion
+ let sp =
+ self.session.source_map().span_extend_to_prev_str(ident.span, current, true);
+ if sp.lo().0 == 0 {
+ err.span_label(ident.span, &format!("this would need to be a `{}`", sugg));
+ } else {
+ let sp = sp.with_lo(BytePos(sp.lo().0 - current.len() as u32));
+ err.span_suggestion(
+ sp,
+ &format!("consider using `{}` instead of `{}`", sugg, current),
+ format!("{} {}", sugg, ident),
+ Applicability::MaybeIncorrect,
+ );
+ err.span_label(span, "non-constant value");
+ }
err
}
ResolutionError::BindingShadowsSomethingUnacceptable(what_binding, name, binding) => {
@@ -595,7 +611,8 @@
filter_fn: &impl Fn(Res) -> bool,
) -> Option<TypoSuggestion> {
let mut suggestions = Vec::new();
- self.visit_scopes(scope_set, parent_scope, ident, |this, scope, use_prelude, _| {
+ let ctxt = ident.span.ctxt();
+ self.visit_scopes(scope_set, parent_scope, ctxt, |this, scope, use_prelude, _| {
match scope {
Scope::DeriveHelpers(expn_id) => {
let res = Res::NonMacroAttr(NonMacroAttrKind::DeriveHelper);
@@ -666,7 +683,7 @@
));
}
Scope::BuiltinAttrs => {
- let res = Res::NonMacroAttr(NonMacroAttrKind::Builtin);
+ let res = Res::NonMacroAttr(NonMacroAttrKind::Builtin(kw::Empty));
if filter_fn(res) {
suggestions.extend(
BUILTIN_ATTRIBUTES
@@ -960,7 +977,7 @@
});
if let Some(def_span) = def_span {
if span.overlaps(def_span) {
- // Don't suggest typo suggestion for itself like in the followoing:
+ // Don't suggest typo suggestion for itself like in the following:
// error[E0423]: expected function, tuple struct or tuple variant, found struct `X`
// --> $DIR/issue-64792-bad-unicode-ctor.rs:3:14
// |
@@ -1094,10 +1111,9 @@
_,
) = binding.kind
{
- let def_id = (&*self).parent(ctor_def_id).expect("no parent for a constructor");
+ let def_id = self.parent(ctor_def_id).expect("no parent for a constructor");
let fields = self.field_names.get(&def_id)?;
- let first_field = fields.first()?; // Handle `struct Foo()`
- return Some(fields.iter().fold(first_field.span, |acc, field| acc.to(field.span)));
+ return fields.iter().map(|name| name.span).reduce(Span::to); // None for `struct Foo()`
}
None
}
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index b134625..e5d6aeb 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -14,7 +14,6 @@
use rustc_ast::ptr::P;
use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor};
use rustc_ast::*;
-use rustc_ast::{unwrap_or, walk_list};
use rustc_ast_lowering::ResolverAstLowering;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_errors::DiagnosticId;
@@ -92,6 +91,12 @@
No,
}
+#[derive(Copy, Clone, Debug, Eq, PartialEq)]
+crate enum ConstantItemKind {
+ Const,
+ Static,
+}
+
/// The rib kind restricts certain accesses,
/// e.g. to a `Res::Local` of an outer item.
#[derive(Copy, Clone, Debug)]
@@ -119,7 +124,7 @@
///
/// The `bool` indicates if this constant may reference generic parameters
/// and is used to only allow generic parameters to be used in trivial constant expressions.
- ConstantItemRibKind(bool),
+ ConstantItemRibKind(bool, Option<(Ident, ConstantItemKind)>),
/// We passed through a module.
ModuleRibKind(Module<'a>),
@@ -145,7 +150,7 @@
NormalRibKind
| ClosureOrAsyncRibKind
| FnItemRibKind
- | ConstantItemRibKind(_)
+ | ConstantItemRibKind(..)
| ModuleRibKind(_)
| MacroDefinition(_)
| ConstParamTyRibKind => false,
@@ -238,6 +243,13 @@
// "function" here means "anything callable" rather than `DefKind::Fn`,
// this is not precise but usually more helpful than just "value".
Some(ExprKind::Call(call_expr, _)) => match &call_expr.kind {
+ // the case of `::some_crate()`
+ ExprKind::Path(_, path)
+ if path.segments.len() == 2
+ && path.segments[0].ident.name == kw::PathRoot =>
+ {
+ "external crate"
+ }
ExprKind::Path(_, path) => {
let mut msg = "function";
if let Some(segment) = path.segments.iter().last() {
@@ -262,52 +274,60 @@
crate fn is_expected(self, res: Res) -> bool {
match self {
- PathSource::Type => matches!(res, Res::Def(
+ PathSource::Type => matches!(
+ res,
+ Res::Def(
DefKind::Struct
- | DefKind::Union
- | DefKind::Enum
- | DefKind::Trait
- | DefKind::TraitAlias
- | DefKind::TyAlias
- | DefKind::AssocTy
- | DefKind::TyParam
- | DefKind::OpaqueTy
- | DefKind::ForeignTy,
+ | DefKind::Union
+ | DefKind::Enum
+ | DefKind::Trait
+ | DefKind::TraitAlias
+ | DefKind::TyAlias
+ | DefKind::AssocTy
+ | DefKind::TyParam
+ | DefKind::OpaqueTy
+ | DefKind::ForeignTy,
_,
- )
- | Res::PrimTy(..)
- | Res::SelfTy(..)),
+ ) | Res::PrimTy(..)
+ | Res::SelfTy(..)
+ ),
PathSource::Trait(AliasPossibility::No) => matches!(res, Res::Def(DefKind::Trait, _)),
PathSource::Trait(AliasPossibility::Maybe) => {
matches!(res, Res::Def(DefKind::Trait | DefKind::TraitAlias, _))
}
- PathSource::Expr(..) => matches!(res, Res::Def(
+ PathSource::Expr(..) => matches!(
+ res,
+ Res::Def(
DefKind::Ctor(_, CtorKind::Const | CtorKind::Fn)
- | DefKind::Const
- | DefKind::Static
- | DefKind::Fn
- | DefKind::AssocFn
- | DefKind::AssocConst
- | DefKind::ConstParam,
+ | DefKind::Const
+ | DefKind::Static
+ | DefKind::Fn
+ | DefKind::AssocFn
+ | DefKind::AssocConst
+ | DefKind::ConstParam,
_,
- )
- | Res::Local(..)
- | Res::SelfCtor(..)),
- PathSource::Pat => matches!(res, Res::Def(
+ ) | Res::Local(..)
+ | Res::SelfCtor(..)
+ ),
+ PathSource::Pat => matches!(
+ res,
+ Res::Def(
DefKind::Ctor(_, CtorKind::Const) | DefKind::Const | DefKind::AssocConst,
_,
- )
- | Res::SelfCtor(..)),
+ ) | Res::SelfCtor(..)
+ ),
PathSource::TupleStruct(..) => res.expected_in_tuple_struct_pat(),
- PathSource::Struct => matches!(res, Res::Def(
+ PathSource::Struct => matches!(
+ res,
+ Res::Def(
DefKind::Struct
- | DefKind::Union
- | DefKind::Variant
- | DefKind::TyAlias
- | DefKind::AssocTy,
+ | DefKind::Union
+ | DefKind::Variant
+ | DefKind::TyAlias
+ | DefKind::AssocTy,
_,
- )
- | Res::SelfTy(..)),
+ ) | Res::SelfTy(..)
+ ),
PathSource::TraitItem(ns) => match res {
Res::Def(DefKind::AssocConst | DefKind::AssocFn, _) if ns == ValueNS => true,
Res::Def(DefKind::AssocTy, _) if ns == TypeNS => true,
@@ -473,8 +493,8 @@
}
fn visit_foreign_item(&mut self, foreign_item: &'ast ForeignItem) {
match foreign_item.kind {
- ForeignItemKind::Fn(_, _, ref generics, _)
- | ForeignItemKind::TyAlias(_, ref generics, ..) => {
+ ForeignItemKind::Fn(box FnKind(_, _, ref generics, _))
+ | ForeignItemKind::TyAlias(box TyAliasKind(_, ref generics, ..)) => {
self.with_generic_param_rib(generics, ItemRibKind(HasGenericParams::Yes), |this| {
visit::walk_foreign_item(this, foreign_item);
});
@@ -586,7 +606,8 @@
// Allow all following defaults to refer to this type parameter.
default_ban_rib.bindings.remove(&Ident::with_dummy_span(param.ident.name));
}
- GenericParamKind::Const { ref ty, kw_span: _ } => {
+ GenericParamKind::Const { ref ty, kw_span: _, default: _ } => {
+ // FIXME(const_generics_defaults): handle `default` value here
for bound in ¶m.bounds {
self.visit_param_bound(bound);
}
@@ -633,7 +654,7 @@
// Note that we might not be inside of an repeat expression here,
// but considering that `IsRepeatExpr` is only relevant for
// non-trivial constants this is doesn't matter.
- self.with_constant_rib(IsRepeatExpr::No, true, |this| {
+ self.with_constant_rib(IsRepeatExpr::No, true, None, |this| {
this.smart_resolve_path(
ty.id,
qself.as_ref(),
@@ -842,7 +863,7 @@
| ClosureOrAsyncRibKind
| FnItemRibKind
| ItemRibKind(..)
- | ConstantItemRibKind(_)
+ | ConstantItemRibKind(..)
| ModuleRibKind(..)
| ForwardTyParamBanRibKind
| ConstParamTyRibKind => {
@@ -917,7 +938,8 @@
debug!("(resolving item) resolving {} ({:?})", name, item.kind);
match item.kind {
- ItemKind::TyAlias(_, ref generics, _, _) | ItemKind::Fn(_, _, ref generics, _) => {
+ ItemKind::TyAlias(box TyAliasKind(_, ref generics, _, _))
+ | ItemKind::Fn(box FnKind(_, _, ref generics, _)) => {
self.with_generic_param_rib(generics, ItemRibKind(HasGenericParams::Yes), |this| {
visit::walk_item(this, item)
});
@@ -929,17 +951,17 @@
self.resolve_adt(item, generics);
}
- ItemKind::Impl {
+ ItemKind::Impl(box ImplKind {
ref generics,
ref of_trait,
ref self_ty,
items: ref impl_items,
..
- } => {
+ }) => {
self.resolve_implementation(generics, of_trait, &self_ty, item.id, impl_items);
}
- ItemKind::Trait(.., ref generics, ref bounds, ref trait_items) => {
+ ItemKind::Trait(box TraitKind(.., ref generics, ref bounds, ref trait_items)) => {
// Create a new rib for the trait-wide type parameters.
self.with_generic_param_rib(generics, ItemRibKind(HasGenericParams::Yes), |this| {
let local_def_id = this.r.local_def_id(item.id).to_def_id();
@@ -969,14 +991,15 @@
this.with_constant_rib(
IsRepeatExpr::No,
true,
+ None,
|this| this.visit_expr(expr),
);
}
}
- AssocItemKind::Fn(_, _, generics, _) => {
+ AssocItemKind::Fn(box FnKind(_, _, generics, _)) => {
walk_assoc_item(this, generics, item);
}
- AssocItemKind::TyAlias(_, generics, _, _) => {
+ AssocItemKind::TyAlias(box TyAliasKind(_, generics, _, _)) => {
walk_assoc_item(this, generics, item);
}
AssocItemKind::MacCall(_) => {
@@ -1011,11 +1034,19 @@
self.with_item_rib(HasGenericParams::No, |this| {
this.visit_ty(ty);
if let Some(expr) = expr {
+ let constant_item_kind = match item.kind {
+ ItemKind::Const(..) => ConstantItemKind::Const,
+ ItemKind::Static(..) => ConstantItemKind::Static,
+ _ => unreachable!(),
+ };
// We already forbid generic params because of the above item rib,
// so it doesn't matter whether this is a trivial constant.
- this.with_constant_rib(IsRepeatExpr::No, true, |this| {
- this.visit_expr(expr)
- });
+ this.with_constant_rib(
+ IsRepeatExpr::No,
+ true,
+ Some((item.ident, constant_item_kind)),
+ |this| this.visit_expr(expr),
+ );
}
});
}
@@ -1117,15 +1148,16 @@
&mut self,
is_repeat: IsRepeatExpr,
is_trivial: bool,
+ item: Option<(Ident, ConstantItemKind)>,
f: impl FnOnce(&mut Self),
) {
debug!("with_constant_rib: is_repeat={:?} is_trivial={}", is_repeat, is_trivial);
- self.with_rib(ValueNS, ConstantItemRibKind(is_trivial), |this| {
+ self.with_rib(ValueNS, ConstantItemRibKind(is_trivial, item), |this| {
this.with_rib(
TypeNS,
- ConstantItemRibKind(is_repeat == IsRepeatExpr::Yes || is_trivial),
+ ConstantItemRibKind(is_repeat == IsRepeatExpr::Yes || is_trivial, item),
|this| {
- this.with_label_rib(ConstantItemRibKind(is_trivial), f);
+ this.with_label_rib(ConstantItemRibKind(is_trivial, item), f);
},
)
});
@@ -1151,13 +1183,11 @@
/// When evaluating a `trait` use its associated types' idents for suggestions in E0412.
fn with_trait_items<T>(
&mut self,
- trait_items: &'ast Vec<P<AssocItem>>,
+ trait_items: &'ast [P<AssocItem>],
f: impl FnOnce(&mut Self) -> T,
) -> T {
- let trait_assoc_items = replace(
- &mut self.diagnostic_metadata.current_trait_assoc_items,
- Some(&trait_items[..]),
- );
+ let trait_assoc_items =
+ replace(&mut self.diagnostic_metadata.current_trait_assoc_items, Some(&trait_items));
let result = f(self);
self.diagnostic_metadata.current_trait_assoc_items = trait_assoc_items;
result
@@ -1267,6 +1297,7 @@
this.with_constant_rib(
IsRepeatExpr::No,
true,
+ None,
|this| {
visit::walk_assoc_item(
this,
@@ -1276,7 +1307,7 @@
},
);
}
- AssocItemKind::Fn(_, _, generics, _) => {
+ AssocItemKind::Fn(box FnKind(.., generics, _)) => {
// We also need a new scope for the impl item type parameters.
this.with_generic_param_rib(
generics,
@@ -1299,7 +1330,12 @@
},
);
}
- AssocItemKind::TyAlias(_, generics, _, _) => {
+ AssocItemKind::TyAlias(box TyAliasKind(
+ _,
+ generics,
+ _,
+ _,
+ )) => {
// We also need a new scope for the impl item type parameters.
this.with_generic_param_rib(
generics,
@@ -1641,7 +1677,7 @@
}
// Record as bound if it's valid:
- let ident_valid = ident.name != kw::Invalid;
+ let ident_valid = ident.name != kw::Empty;
if ident_valid {
bindings.last_mut().unwrap().1.insert(ident);
}
@@ -1765,7 +1801,7 @@
crate_lint: CrateLint,
) -> PartialRes {
tracing::debug!(
- "smart_resolve_path_fragment(id={:?},qself={:?},path={:?}",
+ "smart_resolve_path_fragment(id={:?}, qself={:?}, path={:?})",
id,
qself,
path
@@ -1776,7 +1812,7 @@
if this.should_report_errs() {
let (err, candidates) = this.smart_resolve_report_errors(path, span, source, res);
- let def_id = this.parent_scope.module.normal_ancestor_id;
+ let def_id = this.parent_scope.module.nearest_parent_mod;
let instead = res.is_some();
let suggestion =
if res.is_none() { this.report_missing_type_error(path) } else { None };
@@ -1805,11 +1841,10 @@
// Before we start looking for candidates, we have to get our hands
// on the type user is trying to perform invocation on; basically:
- // we're transforming `HashMap::new` into just `HashMap`
- let path = if let Some((_, path)) = path.split_last() {
- path
- } else {
- return Some(parent_err);
+ // we're transforming `HashMap::new` into just `HashMap`.
+ let path = match path.split_last() {
+ Some((_, path)) if !path.is_empty() => path,
+ _ => return Some(parent_err),
};
let (mut err, candidates) =
@@ -1844,7 +1879,7 @@
drop(parent_err);
- let def_id = this.parent_scope.module.normal_ancestor_id;
+ let def_id = this.parent_scope.module.nearest_parent_mod;
if this.should_report_errs() {
this.r.use_injections.push(UseError {
@@ -1887,7 +1922,7 @@
// it needs to be added to the trait map.
if ns == ValueNS {
let item_name = path.last().unwrap().ident;
- let traits = self.get_traits_containing_item(item_name, ns);
+ let traits = self.traits_in_scope(item_name, ns);
self.r.trait_map.insert(id, traits);
}
@@ -1901,7 +1936,7 @@
{
// Check if we wrote `str::from_utf8` instead of `std::str::from_utf8`
let item_span =
- path.iter().last().map(|segment| segment.ident.span).unwrap_or(span);
+ path.iter().last().map_or(span, |segment| segment.ident.span);
let mut hm = self.r.session.confused_type_with_std_module.borrow_mut();
hm.insert(item_span, span);
@@ -1923,8 +1958,7 @@
_ => report_errors(self, None),
};
- if let PathSource::TraitItem(..) = source {
- } else {
+ if !matches!(source, PathSource::TraitItem(..)) {
// Avoid recording definition of `A::B` in `<T as A>::B::C`.
self.r.record_partial_res(id, partial_res);
}
@@ -2201,6 +2235,7 @@
self.with_constant_rib(
is_repeat,
constant.value.is_potential_trivial_const_param(),
+ None,
|this| {
visit::walk_anon_const(this, constant);
},
@@ -2236,6 +2271,12 @@
visit::walk_expr(self, expr);
}
+ ExprKind::Break(None, Some(ref e)) => {
+ // We use this instead of `visit::walk_expr` to keep the parent expr around for
+ // better diagnostics.
+ self.resolve_expr(e, Some(&expr));
+ }
+
ExprKind::Let(ref pat, ref scrutinee) => {
self.visit_expr(scrutinee);
self.resolve_pattern_top(pat, PatternSource::Let);
@@ -2347,12 +2388,12 @@
// field, we need to add any trait methods we find that match
// the field name so that we can do some nice error reporting
// later on in typeck.
- let traits = self.get_traits_containing_item(ident, ValueNS);
+ let traits = self.traits_in_scope(ident, ValueNS);
self.r.trait_map.insert(expr.id, traits);
}
ExprKind::MethodCall(ref segment, ..) => {
debug!("(recording candidate traits for expr) recording traits for {}", expr.id);
- let traits = self.get_traits_containing_item(segment.ident, ValueNS);
+ let traits = self.traits_in_scope(segment.ident, ValueNS);
self.r.trait_map.insert(expr.id, traits);
}
_ => {
@@ -2361,60 +2402,13 @@
}
}
- fn get_traits_containing_item(
- &mut self,
- mut ident: Ident,
- ns: Namespace,
- ) -> Vec<TraitCandidate> {
- debug!("(getting traits containing item) looking for '{}'", ident.name);
-
- let mut found_traits = Vec::new();
- // Look for the current trait.
- if let Some((module, _)) = self.current_trait_ref {
- if self
- .r
- .resolve_ident_in_module(
- ModuleOrUniformRoot::Module(module),
- ident,
- ns,
- &self.parent_scope,
- false,
- module.span,
- )
- .is_ok()
- {
- let def_id = module.def_id().unwrap();
- found_traits.push(TraitCandidate { def_id, import_ids: smallvec![] });
- }
- }
-
- ident.span = ident.span.normalize_to_macros_2_0();
- let mut search_module = self.parent_scope.module;
- loop {
- self.r.get_traits_in_module_containing_item(
- ident,
- ns,
- search_module,
- &mut found_traits,
- &self.parent_scope,
- );
- search_module =
- unwrap_or!(self.r.hygienic_lexical_parent(search_module, &mut ident.span), break);
- }
-
- if let Some(prelude) = self.r.prelude {
- if !search_module.no_implicit_prelude {
- self.r.get_traits_in_module_containing_item(
- ident,
- ns,
- prelude,
- &mut found_traits,
- &self.parent_scope,
- );
- }
- }
-
- found_traits
+ fn traits_in_scope(&mut self, ident: Ident, ns: Namespace) -> Vec<TraitCandidate> {
+ self.r.traits_in_scope(
+ self.current_trait_ref.as_ref().map(|(module, _)| *module),
+ &self.parent_scope,
+ ident.span.ctxt(),
+ Some((ident.name, ns)),
+ )
}
}
diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs
index 68f59ba..927535b 100644
--- a/compiler/rustc_resolve/src/late/diagnostics.rs
+++ b/compiler/rustc_resolve/src/late/diagnostics.rs
@@ -180,7 +180,7 @@
(
format!("cannot find {} `{}` in {}{}", expected, item_str, mod_prefix, mod_str),
if path_str == "async" && expected.starts_with("struct") {
- "`async` blocks are only allowed in the 2018 edition".to_string()
+ "`async` blocks are only allowed in Rust 2018 or later".to_string()
} else {
format!("not found in {}", mod_str)
},
@@ -264,7 +264,7 @@
// The current function has a `self' parameter, but we were unable to resolve
// a reference to `self`. This can only happen if the `self` identifier we
// are resolving came from a different hygiene context.
- if fn_kind.decl().inputs.get(0).map(|p| p.is_self()).unwrap_or(false) {
+ if fn_kind.decl().inputs.get(0).map_or(false, |p| p.is_self()) {
err.span_label(*span, "this function has a `self` parameter, but a macro invocation can only access identifiers it receives from parameters");
} else {
let doesnt = if is_assoc_fn {
@@ -545,17 +545,23 @@
if let Some(err_code) = &err.code {
if err_code == &rustc_errors::error_code!(E0425) {
for label_rib in &self.label_ribs {
- for (label_ident, _) in &label_rib.bindings {
+ for (label_ident, node_id) in &label_rib.bindings {
if format!("'{}", ident) == label_ident.to_string() {
- let msg = "a label with a similar name exists";
- // FIXME: consider only emitting this suggestion if a label would be valid here
- // which is pretty much only the case for `break` expressions.
- err.span_suggestion(
- span,
- &msg,
- label_ident.name.to_string(),
- Applicability::MaybeIncorrect,
- );
+ err.span_label(label_ident.span, "a label with a similar name exists");
+ if let PathSource::Expr(Some(Expr {
+ kind: ExprKind::Break(None, Some(_)),
+ ..
+ })) = source
+ {
+ err.span_suggestion(
+ span,
+ "use the similarly named label",
+ label_ident.name.to_string(),
+ Applicability::MaybeIncorrect,
+ );
+ // Do not lint against unused label when we suggest them.
+ self.diagnostic_metadata.unused_labels.remove(node_id);
+ }
}
}
}
@@ -904,7 +910,7 @@
Applicability::MaybeIncorrect,
);
if path_str == "try" && span.rust_2015() {
- err.note("if you want the `try` keyword, you need to be in the 2018 edition");
+ err.note("if you want the `try` keyword, you need Rust 2018 or later");
}
}
(Res::Def(DefKind::TyAlias, def_id), PathSource::Trait(_)) => {
@@ -1103,7 +1109,9 @@
if assoc_item.ident == ident {
return Some(match &assoc_item.kind {
ast::AssocItemKind::Const(..) => AssocSuggestion::AssocConst,
- ast::AssocItemKind::Fn(_, sig, ..) if sig.decl.has_self() => {
+ ast::AssocItemKind::Fn(box ast::FnKind(_, sig, ..))
+ if sig.decl.has_self() =>
+ {
AssocSuggestion::MethodWithSelf
}
ast::AssocItemKind::Fn(..) => AssocSuggestion::AssocFn,
@@ -1452,8 +1460,7 @@
}
} else {
let needs_placeholder = |def_id: DefId, kind: CtorKind| {
- let has_no_fields =
- self.r.field_names.get(&def_id).map(|f| f.is_empty()).unwrap_or(false);
+ let has_no_fields = self.r.field_names.get(&def_id).map_or(false, |f| f.is_empty());
match kind {
CtorKind::Const => false,
CtorKind::Fn | CtorKind::Fictive if has_no_fields => false,
@@ -1653,17 +1660,17 @@
for missing in &self.missing_named_lifetime_spots {
match missing {
MissingLifetimeSpot::Generics(generics) => {
- let (span, sugg) = if let Some(param) =
- generics.params.iter().find(|p| match p.kind {
+ let (span, sugg) = if let Some(param) = generics.params.iter().find(|p| {
+ !matches!(
+ p.kind,
hir::GenericParamKind::Type {
synthetic: Some(hir::SyntheticTyParamKind::ImplTrait),
..
- } => false,
- hir::GenericParamKind::Lifetime {
+ } | hir::GenericParamKind::Lifetime {
kind: hir::LifetimeParamKind::Elided,
- } => false,
- _ => true,
- }) {
+ }
+ )
+ }) {
(param.span.shrink_to_lo(), format!("{}, ", lifetime_ref))
} else {
suggests_in_band = true;
@@ -1842,10 +1849,13 @@
msg = "consider introducing a named lifetime parameter".to_string();
should_break = true;
if let Some(param) = generics.params.iter().find(|p| {
- !matches!(p.kind, hir::GenericParamKind::Type {
- synthetic: Some(hir::SyntheticTyParamKind::ImplTrait),
- ..
- })
+ !matches!(
+ p.kind,
+ hir::GenericParamKind::Type {
+ synthetic: Some(hir::SyntheticTyParamKind::ImplTrait),
+ ..
+ }
+ )
}) {
(param.span.shrink_to_lo(), "'a, ".to_string())
} else {
@@ -1985,8 +1995,8 @@
}
}
- /// Non-static lifetimes are prohibited in anonymous constants under `min_const_generics` so
- /// this function will emit an error if `min_const_generics` is enabled, the body identified by
+ /// Non-static lifetimes are prohibited in anonymous constants under `min_const_generics`.
+ /// This function will emit an error if `const_generics` is not enabled, the body identified by
/// `body_id` is an anonymous constant and `lifetime_ref` is non-static.
crate fn maybe_emit_forbidden_non_static_lifetime_error(
&self,
@@ -2002,7 +2012,7 @@
hir::LifetimeName::Implicit | hir::LifetimeName::Static | hir::LifetimeName::Underscore
);
- if self.tcx.features().min_const_generics && is_anon_const && !is_allowed_lifetime {
+ if !self.tcx.lazy_normalization() && is_anon_const && !is_allowed_lifetime {
feature_err(
&self.tcx.sess.parse_sess,
sym::const_generics,
diff --git a/compiler/rustc_resolve/src/late/lifetimes.rs b/compiler/rustc_resolve/src/late/lifetimes.rs
index 69f2804..0bab339 100644
--- a/compiler/rustc_resolve/src/late/lifetimes.rs
+++ b/compiler/rustc_resolve/src/late/lifetimes.rs
@@ -11,7 +11,8 @@
use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder};
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
-use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LOCAL_CRATE};
+use rustc_hir::def_id::{CrateNum, DefIdMap, LOCAL_CRATE};
+use rustc_hir::hir_id::ItemLocalId;
use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
use rustc_hir::{GenericArg, GenericParam, LifetimeName, Node, ParamName, QPath};
use rustc_hir::{GenericParamKind, HirIdMap, HirIdSet, LifetimeParamKind};
@@ -20,6 +21,7 @@
use rustc_middle::ty::{self, DefIdTree, GenericParamDefKind, TyCtxt};
use rustc_middle::{bug, span_bug};
use rustc_session::lint;
+use rustc_span::def_id::{DefId, LocalDefId};
use rustc_span::symbol::{kw, sym, Ident, Symbol};
use rustc_span::Span;
use std::borrow::Cow;
@@ -284,7 +286,7 @@
resolve_lifetimes,
named_region_map: |tcx, id| tcx.resolve_lifetimes(LOCAL_CRATE).defs.get(&id),
- is_late_bound_map: |tcx, id| tcx.resolve_lifetimes(LOCAL_CRATE).late_bound.get(&id),
+ is_late_bound_map,
object_lifetime_defaults_map: |tcx, id| {
tcx.resolve_lifetimes(LOCAL_CRATE).object_lifetime_defaults.get(&id)
},
@@ -320,6 +322,32 @@
rl
}
+fn is_late_bound_map<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ def_id: LocalDefId,
+) -> Option<(LocalDefId, &'tcx FxHashSet<ItemLocalId>)> {
+ match tcx.def_kind(def_id) {
+ DefKind::AnonConst => {
+ let mut def_id = tcx
+ .parent(def_id.to_def_id())
+ .unwrap_or_else(|| bug!("anon const or closure without a parent"));
+ // We search for the next outer anon const or fn here
+ // while skipping closures.
+ //
+ // Note that for `AnonConst` we still just recurse until we
+ // find a function body, but who cares :shrug:
+ while tcx.is_closure(def_id) {
+ def_id = tcx
+ .parent(def_id)
+ .unwrap_or_else(|| bug!("anon const or closure without a parent"));
+ }
+
+ tcx.is_late_bound_map(def_id.expect_local())
+ }
+ _ => tcx.resolve_lifetimes(LOCAL_CRATE).late_bound.get(&def_id).map(|lt| (def_id, lt)),
+ }
+}
+
fn krate(tcx: TyCtxt<'_>) -> NamedRegionMap {
let krate = tcx.hir().krate();
let mut map = NamedRegionMap {
@@ -409,11 +437,11 @@
| hir::ItemKind::Union(_, ref generics)
| hir::ItemKind::Trait(_, _, ref generics, ..)
| hir::ItemKind::TraitAlias(ref generics, ..)
- | hir::ItemKind::Impl { ref generics, .. } => {
+ | hir::ItemKind::Impl(hir::Impl { ref generics, .. }) => {
self.missing_named_lifetime_spots.push(generics.into());
// Impls permit `'_` to be used and it is equivalent to "some fresh lifetime name".
- // This is not true for other kinds of items.x
+ // This is not true for other kinds of items.
let track_lifetime_uses = matches!(item.kind, hir::ItemKind::Impl { .. });
// These kinds of items have only early-bound lifetime parameters.
let mut index = if sub_items_have_self_param(&item.kind) {
@@ -644,17 +672,17 @@
} else {
bug!();
};
- if let hir::ParamName::Plain(param_name) = name {
- if param_name.name == kw::UnderscoreLifetime {
- // Pick the elided lifetime "definition" if one exists
- // and use it to make an elision scope.
- self.lifetime_uses.insert(def_id, LifetimeUseSet::Many);
- elision = Some(reg);
- } else {
- lifetimes.insert(name, reg);
- }
+ // We cannot predict what lifetimes are unused in opaque type.
+ self.lifetime_uses.insert(def_id, LifetimeUseSet::Many);
+ if let hir::ParamName::Plain(Ident {
+ name: kw::UnderscoreLifetime,
+ ..
+ }) = name
+ {
+ // Pick the elided lifetime "definition" if one exists
+ // and use it to make an elision scope.
+ elision = Some(reg);
} else {
- self.lifetime_uses.insert(def_id, LifetimeUseSet::Many);
lifetimes.insert(name, reg);
}
}
@@ -1145,7 +1173,7 @@
}
fn expression_label(ex: &hir::Expr<'_>) -> Option<Ident> {
- if let hir::ExprKind::Loop(_, Some(label), _) = ex.kind { Some(label.ident) } else { None }
+ if let hir::ExprKind::Loop(_, Some(label), ..) = ex.kind { Some(label.ident) } else { None }
}
fn check_if_label_shadows_lifetime(tcx: TyCtxt<'_>, mut scope: ScopeRef<'_>, label: Ident) {
@@ -1370,12 +1398,10 @@
fn lifetime_deletion_span(&self, name: Ident, generics: &hir::Generics<'_>) -> Option<Span> {
generics.params.iter().enumerate().find_map(|(i, param)| {
if param.name.ident() == name {
- let mut in_band = false;
- if let hir::GenericParamKind::Lifetime { kind } = param.kind {
- if let hir::LifetimeParamKind::InBand = kind {
- in_band = true;
- }
- }
+ let in_band = matches!(
+ param.kind,
+ hir::GenericParamKind::Lifetime { kind: hir::LifetimeParamKind::InBand }
+ );
if in_band {
Some(param.span)
} else if generics.params.len() == 1 {
@@ -1405,12 +1431,11 @@
lifetime: &hir::Lifetime,
) {
let name = lifetime.name.ident();
- let mut remove_decl = None;
- if let Some(parent_def_id) = self.tcx.parent(def_id) {
- if let Some(generics) = self.tcx.hir().get_generics(parent_def_id) {
- remove_decl = self.lifetime_deletion_span(name, generics);
- }
- }
+ let remove_decl = self
+ .tcx
+ .parent(def_id)
+ .and_then(|parent_def_id| self.tcx.hir().get_generics(parent_def_id))
+ .and_then(|generics| self.lifetime_deletion_span(name, generics));
let mut remove_use = None;
let mut elide_use = None;
@@ -1433,7 +1458,7 @@
hir::TyKind::Path(ref qpath) => {
if let QPath::Resolved(_, path) = qpath {
let last_segment = &path.segments[path.segments.len() - 1];
- let generics = last_segment.generic_args();
+ let generics = last_segment.args();
for arg in generics.args.iter() {
if let GenericArg::Lifetime(lt) = arg {
if lt.name.ident() == name {
@@ -1677,7 +1702,7 @@
}
match parent.kind {
hir::ItemKind::Trait(_, _, ref generics, ..)
- | hir::ItemKind::Impl { ref generics, .. } => {
+ | hir::ItemKind::Impl(hir::Impl { ref generics, .. }) => {
index += generics.params.len() as u32;
}
_ => {}
@@ -1769,8 +1794,8 @@
let result = loop {
match *scope {
Scope::Body { id, s } => {
- // Non-static lifetimes are prohibited in anonymous constants under
- // `min_const_generics`.
+ // Non-static lifetimes are prohibited in anonymous constants without
+ // `const_generics`.
self.maybe_emit_forbidden_non_static_lifetime_error(id, lifetime_ref);
outermost_body = Some(id);
@@ -2058,18 +2083,11 @@
output: Option<&'tcx hir::Ty<'tcx>>,
) {
debug!("visit_fn_like_elision: enter");
- let mut arg_elide = Elide::FreshLateAnon(Cell::new(0));
- let arg_scope = Scope::Elision { elide: arg_elide.clone(), s: self.scope };
+ let arg_scope = Scope::Elision { elide: Elide::FreshLateAnon(Cell::new(0)), s: self.scope };
self.with(arg_scope, |_, this| {
for input in inputs {
this.visit_ty(input);
}
- match *this.scope {
- Scope::Elision { ref elide, .. } => {
- arg_elide = elide.clone();
- }
- _ => bug!(),
- }
});
let output = match output {
@@ -2102,7 +2120,7 @@
}
Node::ImplItem(&hir::ImplItem { kind: hir::ImplItemKind::Fn(_, body), .. }) => {
- if let hir::ItemKind::Impl { ref self_ty, ref items, .. } =
+ if let hir::ItemKind::Impl(hir::Impl { ref self_ty, ref items, .. }) =
self.tcx.hir().expect_item(self.tcx.hir().get_parent_item(parent)).kind
{
impl_self = Some(self_ty);
@@ -2397,7 +2415,7 @@
_ => break,
}
}
- break Some(e);
+ break Some(&e[..]);
}
Elide::Forbid => break None,
};
@@ -2427,7 +2445,7 @@
lifetime_refs.len(),
&lifetime_names,
lifetime_spans,
- error.map(|p| &p[..]).unwrap_or(&[]),
+ error.unwrap_or(&[]),
);
err.emit();
}
diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs
index f764fbc..b19990e 100644
--- a/compiler/rustc_resolve/src/lib.rs
+++ b/compiler/rustc_resolve/src/lib.rs
@@ -9,6 +9,7 @@
//! Type-relative name resolution (methods, fields, associated items) happens in `librustc_typeck`.
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
+#![feature(box_patterns)]
#![feature(bool_to_option)]
#![feature(crate_visibility_modifier)]
#![feature(format_args_capture)]
@@ -33,7 +34,7 @@
use rustc_data_structures::ptr_key::PtrKey;
use rustc_data_structures::sync::Lrc;
use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder};
-use rustc_expand::base::SyntaxExtension;
+use rustc_expand::base::{SyntaxExtension, SyntaxExtensionKind};
use rustc_hir::def::Namespace::*;
use rustc_hir::def::{self, CtorOf, DefKind, NonMacroAttrKind, PartialRes};
use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, CRATE_DEF_INDEX};
@@ -44,12 +45,13 @@
use rustc_metadata::creader::{CStore, CrateLoader};
use rustc_middle::hir::exports::ExportMap;
use rustc_middle::middle::cstore::{CrateStore, MetadataLoaderDyn};
+use rustc_middle::span_bug;
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::{self, DefIdTree, ResolverOutputs};
-use rustc_middle::{bug, span_bug};
use rustc_session::lint;
use rustc_session::lint::{BuiltinLintDiagnostics, LintBuffer};
use rustc_session::Session;
+use rustc_span::edition::Edition;
use rustc_span::hygiene::{ExpnId, ExpnKind, MacroKind, SyntaxContext, Transparency};
use rustc_span::source_map::Spanned;
use rustc_span::symbol::{kw, sym, Ident, Symbol};
@@ -64,7 +66,7 @@
use diagnostics::{extend_span_to_previous_binding, find_span_of_binding_until_next_binding};
use diagnostics::{ImportSuggestion, LabelSuggestion, Suggestion};
use imports::{Import, ImportKind, ImportResolver, NameResolution};
-use late::{HasGenericParams, PathSource, Rib, RibKind::*};
+use late::{ConstantItemKind, HasGenericParams, PathSource, Rib, RibKind::*};
use macros::{MacroRulesBinding, MacroRulesScope, MacroRulesScopeRef};
type Res = def::Res<NodeId>;
@@ -210,11 +212,15 @@
/// Error E0434: can't capture dynamic environment in a fn item.
CannotCaptureDynamicEnvironmentInFnItem,
/// Error E0435: attempt to use a non-constant value in a constant.
- AttemptToUseNonConstantValueInConstant,
+ AttemptToUseNonConstantValueInConstant(
+ Ident,
+ /* suggestion */ &'static str,
+ /* current */ &'static str,
+ ),
/// Error E0530: `X` bindings cannot shadow `Y`s.
BindingShadowsSomethingUnacceptable(&'static str, Symbol, &'a NameBinding<'a>),
/// Error E0128: type parameters with a default cannot use forward-declared identifiers.
- ForwardDeclaredTyParam, // FIXME(const_generics:defaults)
+ ForwardDeclaredTyParam, // FIXME(const_generics_defaults)
/// ERROR E0770: the type of const parameters must not depend on other generic parameters.
ParamInTyOfConstParam(Symbol),
/// constant values inside of type parameter defaults must not depend on generic parameters.
@@ -422,7 +428,9 @@
///
/// This could be:
///
- /// * A normal module ‒ either `mod from_file;` or `mod from_block { }`.
+ /// * A normal module – either `mod from_file;` or `mod from_block { }` –
+ /// or the crate root (which is conceptually a top-level module).
+ /// Note that the crate root's [name][Self::name] will be [`kw::Empty`].
/// * A trait or an enum (it implicitly contains associated types, methods and variant
/// constructors).
Def(DefKind, DefId, Symbol),
@@ -456,28 +464,42 @@
type Resolutions<'a> = RefCell<FxIndexMap<BindingKey, &'a RefCell<NameResolution<'a>>>>;
/// One node in the tree of modules.
+///
+/// Note that a "module" in resolve is broader than a `mod` that you declare in Rust code. It may be one of these:
+///
+/// * `mod`
+/// * crate root (aka, top-level anonymous module)
+/// * `enum`
+/// * `trait`
+/// * curly-braced block with statements
+///
+/// You can use [`ModuleData::kind`] to determine the kind of module this is.
pub struct ModuleData<'a> {
+ /// The direct parent module (it may not be a `mod`, however).
parent: Option<Module<'a>>,
+ /// What kind of module this is, because this may not be a `mod`.
kind: ModuleKind,
- // The def id of the closest normal module (`mod`) ancestor (including this module).
- normal_ancestor_id: DefId,
+ /// The [`DefId`] of the nearest `mod` item ancestor (which may be this module).
+ /// This may be the crate root.
+ nearest_parent_mod: DefId,
- // Mapping between names and their (possibly in-progress) resolutions in this module.
- // Resolutions in modules from other crates are not populated until accessed.
+ /// Mapping between names and their (possibly in-progress) resolutions in this module.
+ /// Resolutions in modules from other crates are not populated until accessed.
lazy_resolutions: Resolutions<'a>,
- // True if this is a module from other crate that needs to be populated on access.
+ /// True if this is a module from other crate that needs to be populated on access.
populate_on_access: Cell<bool>,
- // Macro invocations that can expand into items in this module.
+ /// Macro invocations that can expand into items in this module.
unexpanded_invocations: RefCell<FxHashSet<ExpnId>>,
+ /// Whether `#[no_implicit_prelude]` is active.
no_implicit_prelude: bool,
glob_importers: RefCell<Vec<&'a Import<'a>>>,
globs: RefCell<Vec<&'a Import<'a>>>,
- // Used to memoize the traits in this module for faster searches through all traits in scope.
+ /// Used to memoize the traits in this module for faster searches through all traits in scope.
traits: RefCell<Option<Box<[(Ident, &'a NameBinding<'a>)]>>>,
/// Span of the module itself. Used for error reporting.
@@ -492,16 +514,16 @@
fn new(
parent: Option<Module<'a>>,
kind: ModuleKind,
- normal_ancestor_id: DefId,
+ nearest_parent_mod: DefId,
expansion: ExpnId,
span: Span,
) -> Self {
ModuleData {
parent,
kind,
- normal_ancestor_id,
+ nearest_parent_mod,
lazy_resolutions: Default::default(),
- populate_on_access: Cell::new(!normal_ancestor_id.is_local()),
+ populate_on_access: Cell::new(!nearest_parent_mod.is_local()),
unexpanded_invocations: Default::default(),
no_implicit_prelude: false,
glob_importers: RefCell::new(Vec::new()),
@@ -743,10 +765,13 @@
}
fn is_variant(&self) -> bool {
- matches!(self.kind, NameBindingKind::Res(
+ matches!(
+ self.kind,
+ NameBindingKind::Res(
Res::Def(DefKind::Variant | DefKind::Ctor(CtorOf::Variant, ..), _),
_,
- ))
+ )
+ )
}
fn is_extern_crate(&self) -> bool {
@@ -850,7 +875,7 @@
/// Used for better errors for E0773
enum BuiltinMacroState {
- NotYetSeen(SyntaxExtension),
+ NotYetSeen(SyntaxExtensionKind),
AlreadySeen(Span),
}
@@ -1028,7 +1053,7 @@
impl<'a> ResolverArenas<'a> {
fn alloc_module(&'a self, module: ModuleData<'a>) -> Module<'a> {
let module = self.modules.alloc(module);
- if module.def_id().map(|def_id| def_id.is_local()).unwrap_or(true) {
+ if module.def_id().map_or(true, |def_id| def_id.is_local()) {
self.local_modules.borrow_mut().push(module);
}
module
@@ -1182,12 +1207,12 @@
) -> Resolver<'a> {
let root_local_def_id = LocalDefId { local_def_index: CRATE_DEF_INDEX };
let root_def_id = root_local_def_id.to_def_id();
- let root_module_kind = ModuleKind::Def(DefKind::Mod, root_def_id, kw::Invalid);
+ let root_module_kind = ModuleKind::Def(DefKind::Mod, root_def_id, kw::Empty);
let graph_root = arenas.alloc_module(ModuleData {
no_implicit_prelude: session.contains_name(&krate.attrs, sym::no_implicit_prelude),
..ModuleData::new(None, root_module_kind, root_def_id, ExpnId::root(), krate.span)
});
- let empty_module_kind = ModuleKind::Def(DefKind::Mod, root_def_id, kw::Invalid);
+ let empty_module_kind = ModuleKind::Def(DefKind::Mod, root_def_id, kw::Empty);
let empty_module = arenas.alloc_module(ModuleData {
no_implicit_prelude: true,
..ModuleData::new(
@@ -1427,7 +1452,7 @@
}
fn is_builtin_macro(&mut self, res: Res) -> bool {
- self.get_macro(res).map_or(false, |ext| ext.is_builtin)
+ self.get_macro(res).map_or(false, |ext| ext.builtin_name.is_some())
}
fn macro_def(&self, mut ctxt: SyntaxContext) -> DefId {
@@ -1441,64 +1466,89 @@
/// Entry point to crate resolution.
pub fn resolve_crate(&mut self, krate: &Crate) {
- let _prof_timer = self.session.prof.generic_activity("resolve_crate");
-
- ImportResolver { r: self }.finalize_imports();
- self.finalize_macro_resolutions();
-
- self.late_resolve_crate(krate);
-
- self.check_unused(krate);
- self.report_errors(krate);
- self.crate_loader.postprocess(krate);
+ self.session.time("resolve_crate", || {
+ self.session.time("finalize_imports", || ImportResolver { r: self }.finalize_imports());
+ self.session.time("finalize_macro_resolutions", || self.finalize_macro_resolutions());
+ self.session.time("late_resolve_crate", || self.late_resolve_crate(krate));
+ self.session.time("resolve_check_unused", || self.check_unused(krate));
+ self.session.time("resolve_report_errors", || self.report_errors(krate));
+ self.session.time("resolve_postprocess", || self.crate_loader.postprocess(krate));
+ });
}
- fn get_traits_in_module_containing_item(
+ pub fn traits_in_scope(
&mut self,
- ident: Ident,
- ns: Namespace,
- module: Module<'a>,
- found_traits: &mut Vec<TraitCandidate>,
+ current_trait: Option<Module<'a>>,
parent_scope: &ParentScope<'a>,
+ ctxt: SyntaxContext,
+ assoc_item: Option<(Symbol, Namespace)>,
+ ) -> Vec<TraitCandidate> {
+ let mut found_traits = Vec::new();
+
+ if let Some(module) = current_trait {
+ if self.trait_may_have_item(Some(module), assoc_item) {
+ let def_id = module.def_id().unwrap();
+ found_traits.push(TraitCandidate { def_id, import_ids: smallvec![] });
+ }
+ }
+
+ self.visit_scopes(ScopeSet::All(TypeNS, false), parent_scope, ctxt, |this, scope, _, _| {
+ match scope {
+ Scope::Module(module) => {
+ this.traits_in_module(module, assoc_item, &mut found_traits);
+ }
+ Scope::StdLibPrelude => {
+ if let Some(module) = this.prelude {
+ this.traits_in_module(module, assoc_item, &mut found_traits);
+ }
+ }
+ Scope::ExternPrelude | Scope::ToolPrelude | Scope::BuiltinTypes => {}
+ _ => unreachable!(),
+ }
+ None::<()>
+ });
+
+ found_traits
+ }
+
+ fn traits_in_module(
+ &mut self,
+ module: Module<'a>,
+ assoc_item: Option<(Symbol, Namespace)>,
+ found_traits: &mut Vec<TraitCandidate>,
) {
- assert!(ns == TypeNS || ns == ValueNS);
module.ensure_traits(self);
let traits = module.traits.borrow();
-
- for &(trait_name, binding) in traits.as_ref().unwrap().iter() {
- // Traits have pseudo-modules that can be used to search for the given ident.
- if let Some(module) = binding.module() {
- let mut ident = ident;
- if ident.span.glob_adjust(module.expansion, binding.span).is_none() {
- continue;
- }
- if self
- .resolve_ident_in_module_unadjusted(
- ModuleOrUniformRoot::Module(module),
- ident,
- ns,
- parent_scope,
- false,
- module.span,
- )
- .is_ok()
- {
- let import_ids = self.find_transitive_imports(&binding.kind, trait_name);
- let trait_def_id = module.def_id().unwrap();
- found_traits.push(TraitCandidate { def_id: trait_def_id, import_ids });
- }
- } else if let Res::Def(DefKind::TraitAlias, _) = binding.res() {
- // For now, just treat all trait aliases as possible candidates, since we don't
- // know if the ident is somewhere in the transitive bounds.
- let import_ids = self.find_transitive_imports(&binding.kind, trait_name);
- let trait_def_id = binding.res().def_id();
- found_traits.push(TraitCandidate { def_id: trait_def_id, import_ids });
- } else {
- bug!("candidate is not trait or trait alias?")
+ for (trait_name, trait_binding) in traits.as_ref().unwrap().iter() {
+ if self.trait_may_have_item(trait_binding.module(), assoc_item) {
+ let def_id = trait_binding.res().def_id();
+ let import_ids = self.find_transitive_imports(&trait_binding.kind, *trait_name);
+ found_traits.push(TraitCandidate { def_id, import_ids });
}
}
}
+ // List of traits in scope is pruned on best effort basis. We reject traits not having an
+ // associated item with the given name and namespace (if specified). This is a conservative
+ // optimization, proper hygienic type-based resolution of associated items is done in typeck.
+ // We don't reject trait aliases (`trait_module == None`) because we don't have access to their
+ // associated items.
+ fn trait_may_have_item(
+ &mut self,
+ trait_module: Option<Module<'a>>,
+ assoc_item: Option<(Symbol, Namespace)>,
+ ) -> bool {
+ match (trait_module, assoc_item) {
+ (Some(trait_module), Some((name, ns))) => {
+ self.resolutions(trait_module).borrow().iter().any(|resolution| {
+ let (&BindingKey { ident: assoc_ident, ns: assoc_ns, .. }, _) = resolution;
+ assoc_ns == ns && assoc_ident.name == name
+ })
+ }
+ _ => true,
+ }
+ }
+
fn find_transitive_imports(
&mut self,
mut kind: &NameBindingKind<'_>,
@@ -1519,11 +1569,11 @@
&self,
parent: Module<'a>,
kind: ModuleKind,
- normal_ancestor_id: DefId,
+ nearest_parent_mod: DefId,
expn_id: ExpnId,
span: Span,
) -> Module<'a> {
- let module = ModuleData::new(Some(parent), kind, normal_ancestor_id, expn_id, span);
+ let module = ModuleData::new(Some(parent), kind, nearest_parent_mod, expn_id, span);
self.arenas.alloc_module(module)
}
@@ -1610,8 +1660,13 @@
&mut self,
scope_set: ScopeSet,
parent_scope: &ParentScope<'a>,
- ident: Ident,
- mut visitor: impl FnMut(&mut Self, Scope<'a>, /*use_prelude*/ bool, Ident) -> Option<T>,
+ ctxt: SyntaxContext,
+ mut visitor: impl FnMut(
+ &mut Self,
+ Scope<'a>,
+ /*use_prelude*/ bool,
+ SyntaxContext,
+ ) -> Option<T>,
) -> Option<T> {
// General principles:
// 1. Not controlled (user-defined) names should have higher priority than controlled names
@@ -1654,7 +1709,7 @@
// 4c. Standard library prelude (de-facto closed, controlled).
// 6. Language prelude: builtin attributes (closed, controlled).
- let rust_2015 = ident.span.rust_2015();
+ let rust_2015 = ctxt.edition() == Edition::Edition2015;
let (ns, macro_kind, is_absolute_path) = match scope_set {
ScopeSet::All(ns, _) => (ns, None, false),
ScopeSet::AbsolutePath(ns) => (ns, None, true),
@@ -1667,7 +1722,7 @@
TypeNS | ValueNS => Scope::Module(module),
MacroNS => Scope::DeriveHelpers(parent_scope.expansion),
};
- let mut ident = ident.normalize_to_macros_2_0();
+ let mut ctxt = ctxt.normalize_to_macros_2_0();
let mut use_prelude = !module.no_implicit_prelude;
loop {
@@ -1703,7 +1758,7 @@
};
if visit {
- if let break_result @ Some(..) = visitor(self, scope, use_prelude, ident) {
+ if let break_result @ Some(..) = visitor(self, scope, use_prelude, ctxt) {
return break_result;
}
}
@@ -1733,17 +1788,17 @@
},
Scope::CrateRoot => match ns {
TypeNS => {
- ident.span.adjust(ExpnId::root());
+ ctxt.adjust(ExpnId::root());
Scope::ExternPrelude
}
ValueNS | MacroNS => break,
},
Scope::Module(module) => {
use_prelude = !module.no_implicit_prelude;
- match self.hygienic_lexical_parent(module, &mut ident.span) {
+ match self.hygienic_lexical_parent(module, &mut ctxt) {
Some(parent_module) => Scope::Module(parent_module),
None => {
- ident.span.adjust(ExpnId::root());
+ ctxt.adjust(ExpnId::root());
match ns {
TypeNS => Scope::ExternPrelude,
ValueNS => Scope::StdLibPrelude,
@@ -1797,7 +1852,7 @@
ribs: &[Rib<'a>],
) -> Option<LexicalScopeBinding<'a>> {
assert!(ns == TypeNS || ns == ValueNS);
- if ident.name == kw::Invalid {
+ if ident.name == kw::Empty {
return Some(LexicalScopeBinding::Res(Res::Err));
}
let (general_span, normalized_span) = if ident.name == kw::SelfUpper {
@@ -1821,14 +1876,16 @@
// Use the rib kind to determine whether we are resolving parameters
// (macro 2.0 hygiene) or local variables (`macro_rules` hygiene).
let rib_ident = if ribs[i].kind.contains_params() { normalized_ident } else { ident };
- if let Some(res) = ribs[i].bindings.get(&rib_ident).cloned() {
+ if let Some((original_rib_ident_def, res)) = ribs[i].bindings.get_key_value(&rib_ident)
+ {
// The ident resolves to a type parameter or local variable.
return Some(LexicalScopeBinding::Res(self.validate_res_from_ribs(
i,
rib_ident,
- res,
+ *res,
record_used,
path_span,
+ *original_rib_ident_def,
ribs,
)));
}
@@ -1866,16 +1923,18 @@
ident = normalized_ident;
let mut poisoned = None;
loop {
+ let mut span_data = ident.span.data();
let opt_module = if let Some(node_id) = record_used_id {
self.hygienic_lexical_parent_with_compatibility_fallback(
module,
- &mut ident.span,
+ &mut span_data.ctxt,
node_id,
&mut poisoned,
)
} else {
- self.hygienic_lexical_parent(module, &mut ident.span)
+ self.hygienic_lexical_parent(module, &mut span_data.ctxt)
};
+ ident.span = span_data.span();
module = unwrap_or!(opt_module, break);
let adjusted_parent_scope = &ParentScope { module, ..*parent_scope };
let result = self.resolve_ident_in_module_unadjusted(
@@ -1949,10 +2008,10 @@
fn hygienic_lexical_parent(
&mut self,
module: Module<'a>,
- span: &mut Span,
+ ctxt: &mut SyntaxContext,
) -> Option<Module<'a>> {
- if !module.expansion.outer_expn_is_descendant_of(span.ctxt()) {
- return Some(self.macro_def_scope(span.remove_mark()));
+ if !module.expansion.outer_expn_is_descendant_of(*ctxt) {
+ return Some(self.macro_def_scope(ctxt.remove_mark()));
}
if let ModuleKind::Block(..) = module.kind {
@@ -1965,11 +2024,11 @@
fn hygienic_lexical_parent_with_compatibility_fallback(
&mut self,
module: Module<'a>,
- span: &mut Span,
+ ctxt: &mut SyntaxContext,
node_id: NodeId,
poisoned: &mut Option<NodeId>,
) -> Option<Module<'a>> {
- if let module @ Some(..) = self.hygienic_lexical_parent(module, span) {
+ if let module @ Some(..) = self.hygienic_lexical_parent(module, ctxt) {
return module;
}
@@ -1991,14 +2050,13 @@
{
// The macro is a proc macro derive
if let Some(def_id) = module.expansion.expn_data().macro_def_id {
- if let Some(ext) = self.get_macro_by_def_id(def_id) {
- if !ext.is_builtin
- && ext.macro_kind() == MacroKind::Derive
- && parent.expansion.outer_expn_is_descendant_of(span.ctxt())
- {
- *poisoned = Some(node_id);
- return module.parent;
- }
+ let ext = self.get_macro_by_def_id(def_id);
+ if ext.builtin_name.is_none()
+ && ext.macro_kind() == MacroKind::Derive
+ && parent.expansion.outer_expn_is_descendant_of(*ctxt)
+ {
+ *poisoned = Some(node_id);
+ return module.parent;
}
}
}
@@ -2117,7 +2175,7 @@
return self.graph_root;
}
};
- let module = self.get_module(DefId { index: CRATE_DEF_INDEX, ..module.normal_ancestor_id });
+ let module = self.get_module(DefId { index: CRATE_DEF_INDEX, ..module.nearest_parent_mod });
debug!(
"resolve_crate_root({:?}): got module {:?} ({:?}) (ident.span = {:?})",
ident,
@@ -2129,10 +2187,10 @@
}
fn resolve_self(&mut self, ctxt: &mut SyntaxContext, module: Module<'a>) -> Module<'a> {
- let mut module = self.get_module(module.normal_ancestor_id);
+ let mut module = self.get_module(module.nearest_parent_mod);
while module.span.ctxt().normalize_to_macros_2_0() != *ctxt {
let parent = module.parent.unwrap_or_else(|| self.macro_def_scope(ctxt.remove_mark()));
- module = self.get_module(parent.normal_ancestor_id);
+ module = self.get_module(parent.nearest_parent_mod);
}
module
}
@@ -2416,15 +2474,24 @@
} else if i == 0 {
if ident
.name
- .with(|n| n.chars().next().map_or(false, |c| c.is_ascii_uppercase()))
+ .as_str()
+ .chars()
+ .next()
+ .map_or(false, |c| c.is_ascii_uppercase())
{
(format!("use of undeclared type `{}`", ident), None)
} else {
(format!("use of undeclared crate or module `{}`", ident), None)
}
} else {
- let mut msg =
- format!("could not find `{}` in `{}`", ident, path[i - 1].ident);
+ let parent = path[i - 1].ident.name;
+ let parent = if parent == kw::PathRoot {
+ "crate root".to_owned()
+ } else {
+ format!("`{}`", parent)
+ };
+
+ let mut msg = format!("could not find `{}` in {}", ident, parent);
if ns == TypeNS || ns == ValueNS {
let ns_to_try = if ns == TypeNS { ValueNS } else { TypeNS };
if let FindBindingResult::Binding(Ok(binding)) =
@@ -2432,11 +2499,11 @@
{
let mut found = |what| {
msg = format!(
- "expected {}, found {} `{}` in `{}`",
+ "expected {}, found {} `{}` in {}",
ns.descr(),
what,
ident,
- path[i - 1].ident
+ parent
)
};
if binding.module().is_some() {
@@ -2538,6 +2605,7 @@
mut res: Res,
record_used: bool,
span: Span,
+ original_rib_ident_def: Ident,
all_ribs: &[Rib<'a>],
) -> Res {
const CG_BUG_STR: &str = "min_const_generics resolve check didn't stop compilation";
@@ -2584,10 +2652,32 @@
res_err = Some(CannotCaptureDynamicEnvironmentInFnItem);
}
}
- ConstantItemRibKind(_) => {
+ ConstantItemRibKind(_, item) => {
// Still doesn't deal with upvars
if record_used {
- self.report_error(span, AttemptToUseNonConstantValueInConstant);
+ let (span, resolution_error) =
+ if let Some((ident, constant_item_kind)) = item {
+ let kind_str = match constant_item_kind {
+ ConstantItemKind::Const => "const",
+ ConstantItemKind::Static => "static",
+ };
+ (
+ span,
+ AttemptToUseNonConstantValueInConstant(
+ ident, "let", kind_str,
+ ),
+ )
+ } else {
+ (
+ rib_ident.span,
+ AttemptToUseNonConstantValueInConstant(
+ original_rib_ident_def,
+ "const",
+ "let",
+ ),
+ )
+ };
+ self.report_error(span, resolution_error);
}
return Res::Err;
}
@@ -2623,9 +2713,13 @@
in_ty_param_default = true;
continue;
}
- ConstantItemRibKind(trivial) => {
+ ConstantItemRibKind(trivial, _) => {
+ let features = self.session.features_untracked();
// HACK(min_const_generics): We currently only allow `N` or `{ N }`.
- if !trivial && self.session.features_untracked().min_const_generics {
+ if !(trivial
+ || features.const_generics
+ || features.lazy_normalization_consts)
+ {
// HACK(min_const_generics): If we encounter `Self` in an anonymous constant
// we can't easily tell if it's generic at this stage, so we instead remember
// this and then enforce the self type to be concrete later on.
@@ -2712,9 +2806,13 @@
in_ty_param_default = true;
continue;
}
- ConstantItemRibKind(trivial) => {
+ ConstantItemRibKind(trivial, _) => {
+ let features = self.session.features_untracked();
// HACK(min_const_generics): We currently only allow `N` or `{ N }`.
- if !trivial && self.session.features_untracked().min_const_generics {
+ if !(trivial
+ || features.const_generics
+ || features.lazy_normalization_consts)
+ {
if record_used {
self.report_error(
span,
@@ -2783,7 +2881,7 @@
}
fn is_accessible_from(&self, vis: ty::Visibility, module: Module<'a>) -> bool {
- vis.is_accessible_from(module.normal_ancestor_id, self)
+ vis.is_accessible_from(module.nearest_parent_mod, self)
}
fn set_binding_parent_module(&mut self, binding: &'a NameBinding<'a>, module: Module<'a>) {
@@ -2807,7 +2905,7 @@
self.binding_parent_modules.get(&PtrKey(modularized)),
) {
(Some(macro_rules), Some(modularized)) => {
- macro_rules.normal_ancestor_id == modularized.normal_ancestor_id
+ macro_rules.nearest_parent_mod == modularized.nearest_parent_mod
&& modularized.is_ancestor_of(macro_rules)
}
_ => false,
@@ -2965,7 +3063,7 @@
let duplicate = new_binding.res().opt_def_id() == old_binding.res().opt_def_id();
let has_dummy_span = new_binding.span.is_dummy() || old_binding.span.is_dummy();
let from_item =
- self.extern_prelude.get(&ident).map(|entry| entry.introduced_by_item).unwrap_or(true);
+ self.extern_prelude.get(&ident).map_or(true, |entry| entry.introduced_by_item);
// Only suggest removing an import if both bindings are to the same def, if both spans
// aren't dummy spans. Further, if both bindings are imports, then the ident must have
// been introduced by a item.
@@ -3161,34 +3259,6 @@
})
}
- /// This is equivalent to `get_traits_in_module_containing_item`, but without filtering by the associated item.
- ///
- /// This is used by rustdoc for intra-doc links.
- pub fn traits_in_scope(&mut self, module_id: DefId) -> Vec<TraitCandidate> {
- let module = self.get_module(module_id);
- module.ensure_traits(self);
- let traits = module.traits.borrow();
- let to_candidate =
- |this: &mut Self, &(trait_name, binding): &(Ident, &NameBinding<'_>)| TraitCandidate {
- def_id: binding.res().def_id(),
- import_ids: this.find_transitive_imports(&binding.kind, trait_name),
- };
-
- let mut candidates: Vec<_> =
- traits.as_ref().unwrap().iter().map(|x| to_candidate(self, x)).collect();
-
- if let Some(prelude) = self.prelude {
- if !module.no_implicit_prelude {
- prelude.ensure_traits(self);
- candidates.extend(
- prelude.traits.borrow().as_ref().unwrap().iter().map(|x| to_candidate(self, x)),
- );
- }
- }
-
- candidates
- }
-
/// Rustdoc uses this to resolve things in a recoverable way. `ResolutionError<'a>`
/// isn't something that can be returned because it can't be made to live that long,
/// and also it's a private type. Fortunately rustdoc doesn't need to know the error,
diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs
index c8dbe68..d0adee2 100644
--- a/compiler/rustc_resolve/src/macros.rs
+++ b/compiler/rustc_resolve/src/macros.rs
@@ -14,7 +14,8 @@
use rustc_data_structures::ptr_key::PtrKey;
use rustc_data_structures::sync::Lrc;
use rustc_errors::struct_span_err;
-use rustc_expand::base::{Indeterminate, InvocationRes, ResolverExpand, SyntaxExtension};
+use rustc_expand::base::{Indeterminate, InvocationRes, ResolverExpand};
+use rustc_expand::base::{SyntaxExtension, SyntaxExtensionKind};
use rustc_expand::compile_declarative_macro;
use rustc_expand::expand::{AstFragment, Invocation, InvocationKind};
use rustc_feature::is_builtin_attr_name;
@@ -160,7 +161,7 @@
hygiene::update_dollar_crate_names(|ctxt| {
let ident = Ident::new(kw::DollarCrate, DUMMY_SP.with_ctxt(ctxt));
match self.resolve_crate_root(ident).kind {
- ModuleKind::Def(.., name) if name != kw::Invalid => name,
+ ModuleKind::Def(.., name) if name != kw::Empty => name,
_ => kw::Crate,
}
});
@@ -176,10 +177,11 @@
parent_scope.module.unexpanded_invocations.borrow_mut().remove(&expansion);
}
- fn register_builtin_macro(&mut self, ident: Ident, ext: SyntaxExtension) {
- if self.builtin_macros.insert(ident.name, BuiltinMacroState::NotYetSeen(ext)).is_some() {
+ fn register_builtin_macro(&mut self, name: Symbol, ext: SyntaxExtensionKind) {
+ if self.builtin_macros.insert(name, BuiltinMacroState::NotYetSeen(ext)).is_some() {
self.session
- .span_err(ident.span, &format!("built-in macro `{}` was already defined", ident));
+ .diagnostic()
+ .bug(&format!("built-in macro `{}` was already registered", name));
}
}
@@ -285,7 +287,7 @@
helper_attrs.extend(
ext.helper_attrs.iter().map(|name| Ident::new(*name, span)),
);
- if ext.is_derive_copy {
+ if ext.builtin_name == Some(sym::Copy) {
self.containers_deriving_copy.insert(invoc_id);
}
ext
@@ -328,7 +330,7 @@
if after_derive {
self.session.span_err(span, "macro attributes must be placed before `#[derive]`");
}
- let normal_module_def_id = self.macro_def_scope(invoc_id).normal_ancestor_id;
+ let normal_module_def_id = self.macro_def_scope(invoc_id).nearest_parent_mod;
self.definitions.add_parent_module_of_macro_def(invoc_id, normal_module_def_id);
}
@@ -342,6 +344,8 @@
}
fn lint_node_id(&mut self, expn_id: ExpnId) -> NodeId {
+ // FIXME - make this more precise. This currently returns the NodeId of the
+ // nearest closing item - we should try to return the closest parent of the ExpnId
self.invocation_parents
.get(&expn_id)
.map_or(ast::CRATE_NODE_ID, |id| self.def_id_to_node_id[*id])
@@ -618,8 +622,9 @@
let break_result = self.visit_scopes(
scope_set,
parent_scope,
- orig_ident,
- |this, scope, use_prelude, ident| {
+ orig_ident.span.ctxt(),
+ |this, scope, use_prelude, ctxt| {
+ let ident = Ident::new(orig_ident.name, orig_ident.span.with_ctxt(ctxt));
let ok = |res, span, arenas| {
Ok((
(res, ty::Visibility::Public, span, ExpnId::root()).to_name_binding(arenas),
@@ -754,7 +759,11 @@
}
Scope::BuiltinAttrs => {
if is_builtin_attr_name(ident.name) {
- ok(Res::NonMacroAttr(NonMacroAttrKind::Builtin), DUMMY_SP, this.arenas)
+ ok(
+ Res::NonMacroAttr(NonMacroAttrKind::Builtin(ident.name)),
+ DUMMY_SP,
+ this.arenas,
+ )
} else {
Err(Determinacy::Determined)
}
@@ -807,13 +816,15 @@
// Found another solution, if the first one was "weak", report an error.
let (res, innermost_res) = (binding.res(), innermost_binding.res());
if res != innermost_res {
- let builtin = Res::NonMacroAttr(NonMacroAttrKind::Builtin);
+ let is_builtin = |res| {
+ matches!(res, Res::NonMacroAttr(NonMacroAttrKind::Builtin(..)))
+ };
let derive_helper_compat =
Res::NonMacroAttr(NonMacroAttrKind::DeriveHelperCompat);
let ambiguity_error_kind = if is_import {
Some(AmbiguityKind::Import)
- } else if innermost_res == builtin || res == builtin {
+ } else if is_builtin(innermost_res) || is_builtin(res) {
Some(AmbiguityKind::BuiltinAttr)
} else if innermost_res == derive_helper_compat
|| res == derive_helper_compat
@@ -1089,14 +1100,14 @@
edition,
);
- if result.is_builtin {
+ if let Some(builtin_name) = result.builtin_name {
// The macro was marked with `#[rustc_builtin_macro]`.
- if let Some(builtin_macro) = self.builtin_macros.get_mut(&item.ident.name) {
+ if let Some(builtin_macro) = self.builtin_macros.get_mut(&builtin_name) {
// The macro is a built-in, replace its expander function
// while still taking everything else from the source code.
// If we already loaded this builtin macro, give a better error message than 'no such builtin macro'.
match mem::replace(builtin_macro, BuiltinMacroState::AlreadySeen(item.span)) {
- BuiltinMacroState::NotYetSeen(ext) => result.kind = ext.kind,
+ BuiltinMacroState::NotYetSeen(ext) => result.kind = ext,
BuiltinMacroState::AlreadySeen(span) => {
struct_span_err!(
self.session,
diff --git a/compiler/rustc_save_analysis/src/dump_visitor.rs b/compiler/rustc_save_analysis/src/dump_visitor.rs
index 40d60a8..2834e7b 100644
--- a/compiler/rustc_save_analysis/src/dump_visitor.rs
+++ b/compiler/rustc_save_analysis/src/dump_visitor.rs
@@ -582,7 +582,7 @@
}
ref v => {
let mut value = format!("{}::{}", enum_data.name, name);
- if let &hir::VariantData::Tuple(ref fields, _) = v {
+ if let hir::VariantData::Tuple(fields, _) = v {
value.push('(');
value.push_str(
&fields
@@ -631,14 +631,7 @@
self.dumper.dump_def(&access, enum_data);
}
- fn process_impl(
- &mut self,
- item: &'tcx hir::Item<'tcx>,
- generics: &'tcx hir::Generics<'tcx>,
- trait_ref: &'tcx Option<hir::TraitRef<'tcx>>,
- typ: &'tcx hir::Ty<'tcx>,
- impl_items: &'tcx [hir::ImplItemRef<'tcx>],
- ) {
+ fn process_impl(&mut self, item: &'tcx hir::Item<'tcx>, impl_: &'tcx hir::Impl<'tcx>) {
if let Some(impl_data) = self.save_ctxt.get_item_data(item) {
if !self.span.filter_generated(item.span) {
if let super::Data::RelationData(rel, imp) = impl_data {
@@ -652,12 +645,12 @@
let map = &self.tcx.hir();
self.nest_typeck_results(map.local_def_id(item.hir_id), |v| {
- v.visit_ty(&typ);
- if let &Some(ref trait_ref) = trait_ref {
+ v.visit_ty(&impl_.self_ty);
+ if let Some(trait_ref) = &impl_.of_trait {
v.process_path(trait_ref.hir_ref_id, &hir::QPath::Resolved(None, &trait_ref.path));
}
- v.process_generic_params(generics, "", item.hir_id);
- for impl_item in impl_items {
+ v.process_generic_params(&impl_.generics, "", item.hir_id);
+ for impl_item in impl_.items {
v.process_impl_item(
map.impl_item(impl_item.id),
map.local_def_id(item.hir_id).to_def_id(),
@@ -1082,7 +1075,7 @@
);
}
- if let &Some(ref default_ty) = default_ty {
+ if let Some(default_ty) = default_ty {
self.visit_ty(default_ty)
}
}
@@ -1287,9 +1280,7 @@
self.process_struct(item, def, ty_params)
}
hir::ItemKind::Enum(ref def, ref ty_params) => self.process_enum(item, def, ty_params),
- hir::ItemKind::Impl { ref generics, ref of_trait, ref self_ty, ref items, .. } => {
- self.process_impl(item, generics, of_trait, &self_ty, items)
- }
+ hir::ItemKind::Impl(ref impl_) => self.process_impl(item, impl_),
hir::ItemKind::Trait(_, _, ref generics, ref trait_refs, methods) => {
self.process_trait(item, generics, trait_refs, methods)
}
@@ -1343,9 +1334,12 @@
self.visit_ty(ty);
}
}
- hir::GenericParamKind::Const { ref ty } => {
+ hir::GenericParamKind::Const { ref ty, ref default } => {
self.process_bounds(param.bounds);
self.visit_ty(ty);
+ if let Some(default) = default {
+ self.visit_anon_const(default);
+ }
}
}
}
diff --git a/compiler/rustc_save_analysis/src/lib.rs b/compiler/rustc_save_analysis/src/lib.rs
index 056c0b3..1291233 100644
--- a/compiler/rustc_save_analysis/src/lib.rs
+++ b/compiler/rustc_save_analysis/src/lib.rs
@@ -318,7 +318,7 @@
attributes: lower_attributes(item.attrs.to_vec(), self),
}))
}
- hir::ItemKind::Impl { ref of_trait, ref self_ty, ref items, .. } => {
+ hir::ItemKind::Impl(hir::Impl { ref of_trait, ref self_ty, ref items, .. }) => {
if let hir::TyKind::Path(hir::QPath::Resolved(_, ref path)) = self_ty.kind {
// Common case impl for a struct or something basic.
if generated_code(path.span) {
@@ -410,7 +410,7 @@
match self.tcx.impl_of_method(def_id) {
Some(impl_id) => match self.tcx.hir().get_if_local(impl_id) {
Some(Node::Item(item)) => match item.kind {
- hir::ItemKind::Impl { ref self_ty, .. } => {
+ hir::ItemKind::Impl(hir::Impl { ref self_ty, .. }) => {
let hir = self.tcx.hir();
let mut qualname = String::from("<");
@@ -670,7 +670,7 @@
) -> Option<Ref> {
// Returns true if the path is function type sugar, e.g., `Fn(A) -> B`.
fn fn_type(seg: &hir::PathSegment<'_>) -> bool {
- seg.args.map(|args| args.parenthesized).unwrap_or(false)
+ seg.args.map_or(false, |args| args.parenthesized)
}
let res = self.get_path_res(id);
diff --git a/compiler/rustc_save_analysis/src/sig.rs b/compiler/rustc_save_analysis/src/sig.rs
index ff445d7..8ada7e3 100644
--- a/compiler/rustc_save_analysis/src/sig.rs
+++ b/compiler/rustc_save_analysis/src/sig.rs
@@ -501,7 +501,7 @@
Ok(sig)
}
- hir::ItemKind::Impl {
+ hir::ItemKind::Impl(hir::Impl {
unsafety,
polarity,
defaultness,
@@ -511,7 +511,7 @@
ref of_trait,
ref self_ty,
items: _,
- } => {
+ }) => {
let mut text = String::new();
if let hir::Defaultness::Default { .. } = defaultness {
text.push_str("default ");
@@ -614,9 +614,12 @@
start: offset + text.len(),
end: offset + text.len() + param_text.as_str().len(),
});
- if let hir::GenericParamKind::Const { ref ty } = param.kind {
+ if let hir::GenericParamKind::Const { ref ty, ref default } = param.kind {
param_text.push_str(": ");
param_text.push_str(&ty_to_string(&ty));
+ if let Some(ref _default) = default {
+ // FIXME(const_generics_defaults): push the `default` value here
+ }
}
if !param.bounds.is_empty() {
param_text.push_str(": ");
diff --git a/compiler/rustc_serialize/src/collection_impls.rs b/compiler/rustc_serialize/src/collection_impls.rs
index 3d274cb..ae6d27e 100644
--- a/compiler/rustc_serialize/src/collection_impls.rs
+++ b/compiler/rustc_serialize/src/collection_impls.rs
@@ -11,12 +11,8 @@
impl<S: Encoder, A: Array<Item: Encodable<S>>> Encodable<S> for SmallVec<A> {
fn encode(&self, s: &mut S) -> Result<(), S::Error> {
- s.emit_seq(self.len(), |s| {
- for (i, e) in self.iter().enumerate() {
- s.emit_seq_elt(i, |s| e.encode(s))?;
- }
- Ok(())
- })
+ let slice: &[A::Item] = self;
+ slice.encode(s)
}
}
@@ -292,46 +288,28 @@
impl<E: Encoder, T: Encodable<E>> Encodable<E> for Rc<[T]> {
fn encode(&self, s: &mut E) -> Result<(), E::Error> {
- s.emit_seq(self.len(), |s| {
- for (index, e) in self.iter().enumerate() {
- s.emit_seq_elt(index, |s| e.encode(s))?;
- }
- Ok(())
- })
+ let slice: &[T] = self;
+ slice.encode(s)
}
}
impl<D: Decoder, T: Decodable<D>> Decodable<D> for Rc<[T]> {
fn decode(d: &mut D) -> Result<Rc<[T]>, D::Error> {
- d.read_seq(|d, len| {
- let mut vec = Vec::with_capacity(len);
- for index in 0..len {
- vec.push(d.read_seq_elt(index, |d| Decodable::decode(d))?);
- }
- Ok(vec.into())
- })
+ let vec: Vec<T> = Decodable::decode(d)?;
+ Ok(vec.into())
}
}
impl<E: Encoder, T: Encodable<E>> Encodable<E> for Arc<[T]> {
fn encode(&self, s: &mut E) -> Result<(), E::Error> {
- s.emit_seq(self.len(), |s| {
- for (index, e) in self.iter().enumerate() {
- s.emit_seq_elt(index, |s| e.encode(s))?;
- }
- Ok(())
- })
+ let slice: &[T] = self;
+ slice.encode(s)
}
}
impl<D: Decoder, T: Decodable<D>> Decodable<D> for Arc<[T]> {
fn decode(d: &mut D) -> Result<Arc<[T]>, D::Error> {
- d.read_seq(|d, len| {
- let mut vec = Vec::with_capacity(len);
- for index in 0..len {
- vec.push(d.read_seq_elt(index, |d| Decodable::decode(d))?);
- }
- Ok(vec.into())
- })
+ let vec: Vec<T> = Decodable::decode(d)?;
+ Ok(vec.into())
}
}
diff --git a/compiler/rustc_serialize/src/leb128.rs b/compiler/rustc_serialize/src/leb128.rs
index 1fe6a30..ea2df80 100644
--- a/compiler/rustc_serialize/src/leb128.rs
+++ b/compiler/rustc_serialize/src/leb128.rs
@@ -1,16 +1,45 @@
+#![macro_use]
+
+macro_rules! max_leb128_len {
+ ($int_ty:ty) => {
+ // The longest LEB128 encoding for an integer uses 7 bits per byte.
+ (std::mem::size_of::<$int_ty>() * 8 + 6) / 7
+ };
+}
+
+// Returns the longest LEB128 encoding of all supported integer types.
+pub const fn max_leb128_len() -> usize {
+ max_leb128_len!(u128)
+}
+
macro_rules! impl_write_unsigned_leb128 {
- ($fn_name:ident, $int_ty:ident) => {
+ ($fn_name:ident, $int_ty:ty) => {
#[inline]
- pub fn $fn_name(out: &mut Vec<u8>, mut value: $int_ty) {
+ pub fn $fn_name(
+ out: &mut [::std::mem::MaybeUninit<u8>; max_leb128_len!($int_ty)],
+ mut value: $int_ty,
+ ) -> &[u8] {
+ let mut i = 0;
+
loop {
if value < 0x80 {
- out.push(value as u8);
+ unsafe {
+ *out.get_unchecked_mut(i).as_mut_ptr() = value as u8;
+ }
+
+ i += 1;
break;
} else {
- out.push(((value & 0x7f) | 0x80) as u8);
+ unsafe {
+ *out.get_unchecked_mut(i).as_mut_ptr() = ((value & 0x7f) | 0x80) as u8;
+ }
+
value >>= 7;
+ i += 1;
}
}
+
+ unsafe { ::std::mem::MaybeUninit::slice_assume_init_ref(&out.get_unchecked(..i)) }
}
};
}
@@ -22,7 +51,7 @@
impl_write_unsigned_leb128!(write_usize_leb128, usize);
macro_rules! impl_read_unsigned_leb128 {
- ($fn_name:ident, $int_ty:ident) => {
+ ($fn_name:ident, $int_ty:ty) => {
#[inline]
pub fn $fn_name(slice: &[u8]) -> ($int_ty, usize) {
let mut result = 0;
@@ -49,62 +78,79 @@
impl_read_unsigned_leb128!(read_u128_leb128, u128);
impl_read_unsigned_leb128!(read_usize_leb128, usize);
-#[inline]
-/// encodes an integer using signed leb128 encoding and stores
-/// the result using a callback function.
-///
-/// The callback `write` is called once for each position
-/// that is to be written to with the byte to be encoded
-/// at that position.
-pub fn write_signed_leb128_to<W>(mut value: i128, mut write: W)
-where
- W: FnMut(u8),
-{
- loop {
- let mut byte = (value as u8) & 0x7f;
- value >>= 7;
- let more =
- !(((value == 0) && ((byte & 0x40) == 0)) || ((value == -1) && ((byte & 0x40) != 0)));
+macro_rules! impl_write_signed_leb128 {
+ ($fn_name:ident, $int_ty:ty) => {
+ #[inline]
+ pub fn $fn_name(
+ out: &mut [::std::mem::MaybeUninit<u8>; max_leb128_len!($int_ty)],
+ mut value: $int_ty,
+ ) -> &[u8] {
+ let mut i = 0;
- if more {
- byte |= 0x80; // Mark this byte to show that more bytes will follow.
+ loop {
+ let mut byte = (value as u8) & 0x7f;
+ value >>= 7;
+ let more = !(((value == 0) && ((byte & 0x40) == 0))
+ || ((value == -1) && ((byte & 0x40) != 0)));
+
+ if more {
+ byte |= 0x80; // Mark this byte to show that more bytes will follow.
+ }
+
+ unsafe {
+ *out.get_unchecked_mut(i).as_mut_ptr() = byte;
+ }
+
+ i += 1;
+
+ if !more {
+ break;
+ }
+ }
+
+ unsafe { ::std::mem::MaybeUninit::slice_assume_init_ref(&out.get_unchecked(..i)) }
}
-
- write(byte);
-
- if !more {
- break;
- }
- }
+ };
}
-#[inline]
-pub fn write_signed_leb128(out: &mut Vec<u8>, value: i128) {
- write_signed_leb128_to(value, |v| out.push(v))
-}
+impl_write_signed_leb128!(write_i16_leb128, i16);
+impl_write_signed_leb128!(write_i32_leb128, i32);
+impl_write_signed_leb128!(write_i64_leb128, i64);
+impl_write_signed_leb128!(write_i128_leb128, i128);
+impl_write_signed_leb128!(write_isize_leb128, isize);
-#[inline]
-pub fn read_signed_leb128(data: &[u8], start_position: usize) -> (i128, usize) {
- let mut result = 0;
- let mut shift = 0;
- let mut position = start_position;
- let mut byte;
+macro_rules! impl_read_signed_leb128 {
+ ($fn_name:ident, $int_ty:ty) => {
+ #[inline]
+ pub fn $fn_name(slice: &[u8]) -> ($int_ty, usize) {
+ let mut result = 0;
+ let mut shift = 0;
+ let mut position = 0;
+ let mut byte;
- loop {
- byte = data[position];
- position += 1;
- result |= i128::from(byte & 0x7F) << shift;
- shift += 7;
+ loop {
+ byte = slice[position];
+ position += 1;
+ result |= <$int_ty>::from(byte & 0x7F) << shift;
+ shift += 7;
- if (byte & 0x80) == 0 {
- break;
+ if (byte & 0x80) == 0 {
+ break;
+ }
+ }
+
+ if (shift < <$int_ty>::BITS) && ((byte & 0x40) != 0) {
+ // sign extend
+ result |= (!0 << shift);
+ }
+
+ (result, position)
}
- }
-
- if (shift < 64) && ((byte & 0x40) != 0) {
- // sign extend
- result |= -(1 << shift);
- }
-
- (result, position - start_position)
+ };
}
+
+impl_read_signed_leb128!(read_i16_leb128, i16);
+impl_read_signed_leb128!(read_i32_leb128, i32);
+impl_read_signed_leb128!(read_i64_leb128, i64);
+impl_read_signed_leb128!(read_i128_leb128, i128);
+impl_read_signed_leb128!(read_isize_leb128, isize);
diff --git a/compiler/rustc_serialize/src/lib.rs b/compiler/rustc_serialize/src/lib.rs
index fab29f2..53c3adc 100644
--- a/compiler/rustc_serialize/src/lib.rs
+++ b/compiler/rustc_serialize/src/lib.rs
@@ -13,7 +13,13 @@
#![feature(never_type)]
#![feature(nll)]
#![feature(associated_type_bounds)]
-#![feature(min_const_generics)]
+#![cfg_attr(bootstrap, feature(min_const_generics))]
+#![feature(min_specialization)]
+#![feature(vec_spare_capacity)]
+#![feature(core_intrinsics)]
+#![feature(int_bits_const)]
+#![feature(maybe_uninit_slice)]
+#![feature(new_uninit)]
#![cfg_attr(test, feature(test))]
#![allow(rustc::internal)]
diff --git a/compiler/rustc_serialize/src/opaque.rs b/compiler/rustc_serialize/src/opaque.rs
index 8b79c93..3e37fc8 100644
--- a/compiler/rustc_serialize/src/opaque.rs
+++ b/compiler/rustc_serialize/src/opaque.rs
@@ -1,6 +1,11 @@
-use crate::leb128::{self, read_signed_leb128, write_signed_leb128};
+use crate::leb128::{self, max_leb128_len};
use crate::serialize;
use std::borrow::Cow;
+use std::fs::File;
+use std::io::{self, Write};
+use std::mem::MaybeUninit;
+use std::path::Path;
+use std::ptr;
// -----------------------------------------------------------------------------
// Encoder
@@ -22,21 +27,34 @@
}
#[inline]
+ pub fn position(&self) -> usize {
+ self.data.len()
+ }
+
+ #[inline]
pub fn emit_raw_bytes(&mut self, s: &[u8]) {
self.data.extend_from_slice(s);
}
}
-macro_rules! write_uleb128 {
- ($enc:expr, $value:expr, $fun:ident) => {{
- leb128::$fun(&mut $enc.data, $value);
- Ok(())
- }};
-}
+macro_rules! write_leb128 {
+ ($enc:expr, $value:expr, $int_ty:ty, $fun:ident) => {{
+ const MAX_ENCODED_LEN: usize = max_leb128_len!($int_ty);
+ let old_len = $enc.data.len();
-macro_rules! write_sleb128 {
- ($enc:expr, $value:expr) => {{
- write_signed_leb128(&mut $enc.data, $value as i128);
+ if MAX_ENCODED_LEN > $enc.data.capacity() - old_len {
+ $enc.data.reserve(MAX_ENCODED_LEN);
+ }
+
+ // SAFETY: The above check and `reserve` ensures that there is enough
+ // room to write the encoded value to the vector's internal buffer.
+ unsafe {
+ let buf = &mut *($enc.data.as_mut_ptr().add(old_len)
+ as *mut [MaybeUninit<u8>; MAX_ENCODED_LEN]);
+ let encoded = leb128::$fun(buf, $value);
+ $enc.data.set_len(old_len + encoded.len());
+ }
+
Ok(())
}};
}
@@ -51,27 +69,27 @@
#[inline]
fn emit_usize(&mut self, v: usize) -> EncodeResult {
- write_uleb128!(self, v, write_usize_leb128)
+ write_leb128!(self, v, usize, write_usize_leb128)
}
#[inline]
fn emit_u128(&mut self, v: u128) -> EncodeResult {
- write_uleb128!(self, v, write_u128_leb128)
+ write_leb128!(self, v, u128, write_u128_leb128)
}
#[inline]
fn emit_u64(&mut self, v: u64) -> EncodeResult {
- write_uleb128!(self, v, write_u64_leb128)
+ write_leb128!(self, v, u64, write_u64_leb128)
}
#[inline]
fn emit_u32(&mut self, v: u32) -> EncodeResult {
- write_uleb128!(self, v, write_u32_leb128)
+ write_leb128!(self, v, u32, write_u32_leb128)
}
#[inline]
fn emit_u16(&mut self, v: u16) -> EncodeResult {
- write_uleb128!(self, v, write_u16_leb128)
+ write_leb128!(self, v, u16, write_u16_leb128)
}
#[inline]
@@ -82,27 +100,27 @@
#[inline]
fn emit_isize(&mut self, v: isize) -> EncodeResult {
- write_sleb128!(self, v)
+ write_leb128!(self, v, isize, write_isize_leb128)
}
#[inline]
fn emit_i128(&mut self, v: i128) -> EncodeResult {
- write_sleb128!(self, v)
+ write_leb128!(self, v, i128, write_i128_leb128)
}
#[inline]
fn emit_i64(&mut self, v: i64) -> EncodeResult {
- write_sleb128!(self, v)
+ write_leb128!(self, v, i64, write_i64_leb128)
}
#[inline]
fn emit_i32(&mut self, v: i32) -> EncodeResult {
- write_sleb128!(self, v)
+ write_leb128!(self, v, i32, write_i32_leb128)
}
#[inline]
fn emit_i16(&mut self, v: i16) -> EncodeResult {
- write_sleb128!(self, v)
+ write_leb128!(self, v, i16, write_i16_leb128)
}
#[inline]
@@ -141,10 +159,354 @@
}
}
-impl Encoder {
+pub type FileEncodeResult = Result<(), io::Error>;
+
+// `FileEncoder` encodes data to file via fixed-size buffer.
+//
+// When encoding large amounts of data to a file, using `FileEncoder` may be
+// preferred over using `Encoder` to encode to a `Vec`, and then writing the
+// `Vec` to file, as the latter uses as much memory as there is encoded data,
+// while the former uses the fixed amount of memory allocated to the buffer.
+// `FileEncoder` also has the advantage of not needing to reallocate as data
+// is appended to it, but the disadvantage of requiring more error handling,
+// which has some runtime overhead.
+pub struct FileEncoder {
+ // The input buffer. For adequate performance, we need more control over
+ // buffering than `BufWriter` offers. If `BufWriter` ever offers a raw
+ // buffer access API, we can use it, and remove `buf` and `buffered`.
+ buf: Box<[MaybeUninit<u8>]>,
+ buffered: usize,
+ flushed: usize,
+ file: File,
+}
+
+impl FileEncoder {
+ pub fn new<P: AsRef<Path>>(path: P) -> io::Result<Self> {
+ const DEFAULT_BUF_SIZE: usize = 8192;
+ FileEncoder::with_capacity(path, DEFAULT_BUF_SIZE)
+ }
+
+ pub fn with_capacity<P: AsRef<Path>>(path: P, capacity: usize) -> io::Result<Self> {
+ // Require capacity at least as large as the largest LEB128 encoding
+ // here, so that we don't have to check or handle this on every write.
+ assert!(capacity >= max_leb128_len());
+
+ // Require capacity small enough such that some capacity checks can be
+ // done using guaranteed non-overflowing add rather than sub, which
+ // shaves an instruction off those code paths (on x86 at least).
+ assert!(capacity <= usize::MAX - max_leb128_len());
+
+ let file = File::create(path)?;
+
+ Ok(FileEncoder { buf: Box::new_uninit_slice(capacity), buffered: 0, flushed: 0, file })
+ }
+
#[inline]
pub fn position(&self) -> usize {
- self.data.len()
+ // Tracking position this way instead of having a `self.position` field
+ // means that we don't have to update the position on every write call.
+ self.flushed + self.buffered
+ }
+
+ #[inline]
+ pub fn emit_raw_bytes(&mut self, s: &[u8]) -> FileEncodeResult {
+ self.write_all(s)
+ }
+
+ pub fn flush(&mut self) -> FileEncodeResult {
+ // This is basically a copy of `BufWriter::flush`. If `BufWriter` ever
+ // offers a raw buffer access API, we can use it, and remove this.
+
+ /// Helper struct to ensure the buffer is updated after all the writes
+ /// are complete. It tracks the number of written bytes and drains them
+ /// all from the front of the buffer when dropped.
+ struct BufGuard<'a> {
+ buffer: &'a mut [u8],
+ encoder_buffered: &'a mut usize,
+ encoder_flushed: &'a mut usize,
+ flushed: usize,
+ }
+
+ impl<'a> BufGuard<'a> {
+ fn new(
+ buffer: &'a mut [u8],
+ encoder_buffered: &'a mut usize,
+ encoder_flushed: &'a mut usize,
+ ) -> Self {
+ assert_eq!(buffer.len(), *encoder_buffered);
+ Self { buffer, encoder_buffered, encoder_flushed, flushed: 0 }
+ }
+
+ /// The unwritten part of the buffer
+ fn remaining(&self) -> &[u8] {
+ &self.buffer[self.flushed..]
+ }
+
+ /// Flag some bytes as removed from the front of the buffer
+ fn consume(&mut self, amt: usize) {
+ self.flushed += amt;
+ }
+
+ /// true if all of the bytes have been written
+ fn done(&self) -> bool {
+ self.flushed >= *self.encoder_buffered
+ }
+ }
+
+ impl Drop for BufGuard<'_> {
+ fn drop(&mut self) {
+ if self.flushed > 0 {
+ if self.done() {
+ *self.encoder_flushed += *self.encoder_buffered;
+ *self.encoder_buffered = 0;
+ } else {
+ self.buffer.copy_within(self.flushed.., 0);
+ *self.encoder_flushed += self.flushed;
+ *self.encoder_buffered -= self.flushed;
+ }
+ }
+ }
+ }
+
+ let mut guard = BufGuard::new(
+ unsafe { MaybeUninit::slice_assume_init_mut(&mut self.buf[..self.buffered]) },
+ &mut self.buffered,
+ &mut self.flushed,
+ );
+
+ while !guard.done() {
+ match self.file.write(guard.remaining()) {
+ Ok(0) => {
+ return Err(io::Error::new(
+ io::ErrorKind::WriteZero,
+ "failed to write the buffered data",
+ ));
+ }
+ Ok(n) => guard.consume(n),
+ Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {}
+ Err(e) => return Err(e),
+ }
+ }
+
+ Ok(())
+ }
+
+ #[inline]
+ fn capacity(&self) -> usize {
+ self.buf.len()
+ }
+
+ #[inline]
+ fn write_one(&mut self, value: u8) -> FileEncodeResult {
+ // We ensure this during `FileEncoder` construction.
+ debug_assert!(self.capacity() >= 1);
+
+ let mut buffered = self.buffered;
+
+ if std::intrinsics::unlikely(buffered >= self.capacity()) {
+ self.flush()?;
+ buffered = 0;
+ }
+
+ // SAFETY: The above check and `flush` ensures that there is enough
+ // room to write the input to the buffer.
+ unsafe {
+ *MaybeUninit::slice_as_mut_ptr(&mut self.buf).add(buffered) = value;
+ }
+
+ self.buffered = buffered + 1;
+
+ Ok(())
+ }
+
+ #[inline]
+ fn write_all(&mut self, buf: &[u8]) -> FileEncodeResult {
+ let capacity = self.capacity();
+ let buf_len = buf.len();
+
+ if std::intrinsics::likely(buf_len <= capacity) {
+ let mut buffered = self.buffered;
+
+ if std::intrinsics::unlikely(buf_len > capacity - buffered) {
+ self.flush()?;
+ buffered = 0;
+ }
+
+ // SAFETY: The above check and `flush` ensures that there is enough
+ // room to write the input to the buffer.
+ unsafe {
+ let src = buf.as_ptr();
+ let dst = MaybeUninit::slice_as_mut_ptr(&mut self.buf).add(buffered);
+ ptr::copy_nonoverlapping(src, dst, buf_len);
+ }
+
+ self.buffered = buffered + buf_len;
+
+ Ok(())
+ } else {
+ self.write_all_unbuffered(buf)
+ }
+ }
+
+ fn write_all_unbuffered(&mut self, mut buf: &[u8]) -> FileEncodeResult {
+ if self.buffered > 0 {
+ self.flush()?;
+ }
+
+ // This is basically a copy of `Write::write_all` but also updates our
+ // `self.flushed`. It's necessary because `Write::write_all` does not
+ // return the number of bytes written when an error is encountered, and
+ // without that, we cannot accurately update `self.flushed` on error.
+ while !buf.is_empty() {
+ match self.file.write(buf) {
+ Ok(0) => {
+ return Err(io::Error::new(
+ io::ErrorKind::WriteZero,
+ "failed to write whole buffer",
+ ));
+ }
+ Ok(n) => {
+ buf = &buf[n..];
+ self.flushed += n;
+ }
+ Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {}
+ Err(e) => return Err(e),
+ }
+ }
+
+ Ok(())
+ }
+}
+
+impl Drop for FileEncoder {
+ fn drop(&mut self) {
+ let _result = self.flush();
+ }
+}
+
+macro_rules! file_encoder_write_leb128 {
+ ($enc:expr, $value:expr, $int_ty:ty, $fun:ident) => {{
+ const MAX_ENCODED_LEN: usize = max_leb128_len!($int_ty);
+
+ // We ensure this during `FileEncoder` construction.
+ debug_assert!($enc.capacity() >= MAX_ENCODED_LEN);
+
+ let mut buffered = $enc.buffered;
+
+ // This can't overflow. See assertion in `FileEncoder::with_capacity`.
+ if std::intrinsics::unlikely(buffered + MAX_ENCODED_LEN > $enc.capacity()) {
+ $enc.flush()?;
+ buffered = 0;
+ }
+
+ // SAFETY: The above check and flush ensures that there is enough
+ // room to write the encoded value to the buffer.
+ let buf = unsafe {
+ &mut *($enc.buf.as_mut_ptr().add(buffered) as *mut [MaybeUninit<u8>; MAX_ENCODED_LEN])
+ };
+
+ let encoded = leb128::$fun(buf, $value);
+ $enc.buffered = buffered + encoded.len();
+
+ Ok(())
+ }};
+}
+
+impl serialize::Encoder for FileEncoder {
+ type Error = io::Error;
+
+ #[inline]
+ fn emit_unit(&mut self) -> FileEncodeResult {
+ Ok(())
+ }
+
+ #[inline]
+ fn emit_usize(&mut self, v: usize) -> FileEncodeResult {
+ file_encoder_write_leb128!(self, v, usize, write_usize_leb128)
+ }
+
+ #[inline]
+ fn emit_u128(&mut self, v: u128) -> FileEncodeResult {
+ file_encoder_write_leb128!(self, v, u128, write_u128_leb128)
+ }
+
+ #[inline]
+ fn emit_u64(&mut self, v: u64) -> FileEncodeResult {
+ file_encoder_write_leb128!(self, v, u64, write_u64_leb128)
+ }
+
+ #[inline]
+ fn emit_u32(&mut self, v: u32) -> FileEncodeResult {
+ file_encoder_write_leb128!(self, v, u32, write_u32_leb128)
+ }
+
+ #[inline]
+ fn emit_u16(&mut self, v: u16) -> FileEncodeResult {
+ file_encoder_write_leb128!(self, v, u16, write_u16_leb128)
+ }
+
+ #[inline]
+ fn emit_u8(&mut self, v: u8) -> FileEncodeResult {
+ self.write_one(v)
+ }
+
+ #[inline]
+ fn emit_isize(&mut self, v: isize) -> FileEncodeResult {
+ file_encoder_write_leb128!(self, v, isize, write_isize_leb128)
+ }
+
+ #[inline]
+ fn emit_i128(&mut self, v: i128) -> FileEncodeResult {
+ file_encoder_write_leb128!(self, v, i128, write_i128_leb128)
+ }
+
+ #[inline]
+ fn emit_i64(&mut self, v: i64) -> FileEncodeResult {
+ file_encoder_write_leb128!(self, v, i64, write_i64_leb128)
+ }
+
+ #[inline]
+ fn emit_i32(&mut self, v: i32) -> FileEncodeResult {
+ file_encoder_write_leb128!(self, v, i32, write_i32_leb128)
+ }
+
+ #[inline]
+ fn emit_i16(&mut self, v: i16) -> FileEncodeResult {
+ file_encoder_write_leb128!(self, v, i16, write_i16_leb128)
+ }
+
+ #[inline]
+ fn emit_i8(&mut self, v: i8) -> FileEncodeResult {
+ let as_u8: u8 = unsafe { std::mem::transmute(v) };
+ self.emit_u8(as_u8)
+ }
+
+ #[inline]
+ fn emit_bool(&mut self, v: bool) -> FileEncodeResult {
+ self.emit_u8(if v { 1 } else { 0 })
+ }
+
+ #[inline]
+ fn emit_f64(&mut self, v: f64) -> FileEncodeResult {
+ let as_u64: u64 = v.to_bits();
+ self.emit_u64(as_u64)
+ }
+
+ #[inline]
+ fn emit_f32(&mut self, v: f32) -> FileEncodeResult {
+ let as_u32: u32 = v.to_bits();
+ self.emit_u32(as_u32)
+ }
+
+ #[inline]
+ fn emit_char(&mut self, v: char) -> FileEncodeResult {
+ self.emit_u32(v as u32)
+ }
+
+ #[inline]
+ fn emit_str(&mut self, v: &str) -> FileEncodeResult {
+ self.emit_usize(v.len())?;
+ self.emit_raw_bytes(v.as_bytes())
}
}
@@ -179,11 +541,19 @@
}
#[inline]
- pub fn read_raw_bytes(&mut self, s: &mut [u8]) -> Result<(), String> {
+ pub fn read_raw_bytes(&mut self, s: &mut [MaybeUninit<u8>]) -> Result<(), String> {
let start = self.position;
let end = start + s.len();
+ assert!(end <= self.data.len());
- s.copy_from_slice(&self.data[start..end]);
+ // SAFETY: Both `src` and `dst` point to at least `s.len()` elements:
+ // `src` points to at least `s.len()` elements by above assert, and
+ // `dst` points to `s.len()` elements by derivation from `s`.
+ unsafe {
+ let src = self.data.as_ptr().add(start);
+ let dst = s.as_mut_ptr() as *mut u8;
+ ptr::copy_nonoverlapping(src, dst, s.len());
+ }
self.position = end;
@@ -191,7 +561,7 @@
}
}
-macro_rules! read_uleb128 {
+macro_rules! read_leb128 {
($dec:expr, $fun:ident) => {{
let (value, bytes_read) = leb128::$fun(&$dec.data[$dec.position..]);
$dec.position += bytes_read;
@@ -199,14 +569,6 @@
}};
}
-macro_rules! read_sleb128 {
- ($dec:expr, $t:ty) => {{
- let (value, bytes_read) = read_signed_leb128($dec.data, $dec.position);
- $dec.position += bytes_read;
- Ok(value as $t)
- }};
-}
-
impl<'a> serialize::Decoder for Decoder<'a> {
type Error = String;
@@ -217,22 +579,22 @@
#[inline]
fn read_u128(&mut self) -> Result<u128, Self::Error> {
- read_uleb128!(self, read_u128_leb128)
+ read_leb128!(self, read_u128_leb128)
}
#[inline]
fn read_u64(&mut self) -> Result<u64, Self::Error> {
- read_uleb128!(self, read_u64_leb128)
+ read_leb128!(self, read_u64_leb128)
}
#[inline]
fn read_u32(&mut self) -> Result<u32, Self::Error> {
- read_uleb128!(self, read_u32_leb128)
+ read_leb128!(self, read_u32_leb128)
}
#[inline]
fn read_u16(&mut self) -> Result<u16, Self::Error> {
- read_uleb128!(self, read_u16_leb128)
+ read_leb128!(self, read_u16_leb128)
}
#[inline]
@@ -244,27 +606,27 @@
#[inline]
fn read_usize(&mut self) -> Result<usize, Self::Error> {
- read_uleb128!(self, read_usize_leb128)
+ read_leb128!(self, read_usize_leb128)
}
#[inline]
fn read_i128(&mut self) -> Result<i128, Self::Error> {
- read_sleb128!(self, i128)
+ read_leb128!(self, read_i128_leb128)
}
#[inline]
fn read_i64(&mut self) -> Result<i64, Self::Error> {
- read_sleb128!(self, i64)
+ read_leb128!(self, read_i64_leb128)
}
#[inline]
fn read_i32(&mut self) -> Result<i32, Self::Error> {
- read_sleb128!(self, i32)
+ read_leb128!(self, read_i32_leb128)
}
#[inline]
fn read_i16(&mut self) -> Result<i16, Self::Error> {
- read_sleb128!(self, i16)
+ read_leb128!(self, read_i16_leb128)
}
#[inline]
@@ -276,7 +638,7 @@
#[inline]
fn read_isize(&mut self) -> Result<isize, Self::Error> {
- read_sleb128!(self, isize)
+ read_leb128!(self, read_isize_leb128)
}
#[inline]
@@ -316,3 +678,43 @@
err.to_string()
}
}
+
+// Specializations for contiguous byte sequences follow. The default implementations for slices
+// encode and decode each element individually. This isn't necessary for `u8` slices when using
+// opaque encoders and decoders, because each `u8` is unchanged by encoding and decoding.
+// Therefore, we can use more efficient implementations that process the entire sequence at once.
+
+// Specialize encoding byte slices. This specialization also applies to encoding `Vec<u8>`s, etc.,
+// since the default implementations call `encode` on their slices internally.
+impl serialize::Encodable<Encoder> for [u8] {
+ fn encode(&self, e: &mut Encoder) -> EncodeResult {
+ serialize::Encoder::emit_usize(e, self.len())?;
+ e.emit_raw_bytes(self);
+ Ok(())
+ }
+}
+
+impl serialize::Encodable<FileEncoder> for [u8] {
+ fn encode(&self, e: &mut FileEncoder) -> FileEncodeResult {
+ serialize::Encoder::emit_usize(e, self.len())?;
+ e.emit_raw_bytes(self)
+ }
+}
+
+// Specialize decoding `Vec<u8>`. This specialization also applies to decoding `Box<[u8]>`s, etc.,
+// since the default implementations call `decode` to produce a `Vec<u8>` internally.
+impl<'a> serialize::Decodable<Decoder<'a>> for Vec<u8> {
+ fn decode(d: &mut Decoder<'a>) -> Result<Self, String> {
+ let len = serialize::Decoder::read_usize(d)?;
+
+ let mut v = Vec::with_capacity(len);
+ let buf = &mut v.spare_capacity_mut()[..len];
+ d.read_raw_bytes(buf)?;
+
+ unsafe {
+ v.set_len(len);
+ }
+
+ Ok(v)
+ }
+}
diff --git a/compiler/rustc_serialize/src/serialize.rs b/compiler/rustc_serialize/src/serialize.rs
index aa305f3..47aad5b 100644
--- a/compiler/rustc_serialize/src/serialize.rs
+++ b/compiler/rustc_serialize/src/serialize.rs
@@ -527,7 +527,7 @@
}
impl<S: Encoder, T: Encodable<S>> Encodable<S> for [T] {
- fn encode(&self, s: &mut S) -> Result<(), S::Error> {
+ default fn encode(&self, s: &mut S) -> Result<(), S::Error> {
s.emit_seq(self.len(), |s| {
for (i, e) in self.iter().enumerate() {
s.emit_seq_elt(i, |s| e.encode(s))?
@@ -545,7 +545,7 @@
}
impl<D: Decoder, T: Decodable<D>> Decodable<D> for Vec<T> {
- fn decode(d: &mut D) -> Result<Vec<T>, D::Error> {
+ default fn decode(d: &mut D) -> Result<Vec<T>, D::Error> {
d.read_seq(|d, len| {
let mut v = Vec::with_capacity(len);
for i in 0..len {
@@ -591,13 +591,8 @@
[T]: ToOwned<Owned = Vec<T>>,
{
fn decode(d: &mut D) -> Result<Cow<'static, [T]>, D::Error> {
- d.read_seq(|d, len| {
- let mut v = Vec::with_capacity(len);
- for i in 0..len {
- v.push(d.read_seq_elt(i, |d| Decodable::decode(d))?);
- }
- Ok(Cow::Owned(v))
- })
+ let v: Vec<T> = Decodable::decode(d)?;
+ Ok(Cow::Owned(v))
}
}
diff --git a/compiler/rustc_serialize/tests/leb128.rs b/compiler/rustc_serialize/tests/leb128.rs
index b0f7e78..a2bcf2c 100644
--- a/compiler/rustc_serialize/tests/leb128.rs
+++ b/compiler/rustc_serialize/tests/leb128.rs
@@ -1,18 +1,36 @@
+#![feature(int_bits_const)]
+#![feature(maybe_uninit_slice)]
+#![feature(maybe_uninit_uninit_array)]
+
use rustc_serialize::leb128::*;
+use std::mem::MaybeUninit;
macro_rules! impl_test_unsigned_leb128 {
($test_name:ident, $write_fn_name:ident, $read_fn_name:ident, $int_ty:ident) => {
#[test]
fn $test_name() {
+ // Test 256 evenly spaced values of integer range,
+ // integer max value, and some "random" numbers.
+ let mut values = Vec::new();
+
+ let increment = (1 as $int_ty) << ($int_ty::BITS - 8);
+ values.extend((0..256).map(|i| $int_ty::MIN + i * increment));
+
+ values.push($int_ty::MAX);
+
+ values.extend(
+ (-500..500).map(|i| (i as $int_ty).wrapping_mul(0x12345789ABCDEFu64 as $int_ty)),
+ );
+
let mut stream = Vec::new();
- for x in 0..62 {
- $write_fn_name(&mut stream, (3u64 << x) as $int_ty);
+ for &x in &values {
+ let mut buf = MaybeUninit::uninit_array();
+ stream.extend($write_fn_name(&mut buf, x));
}
let mut position = 0;
- for x in 0..62 {
- let expected = (3u64 << x) as $int_ty;
+ for &expected in &values {
let (actual, bytes_read) = $read_fn_name(&stream[position..]);
assert_eq!(expected, actual);
position += bytes_read;
@@ -28,18 +46,49 @@
impl_test_unsigned_leb128!(test_u128_leb128, write_u128_leb128, read_u128_leb128, u128);
impl_test_unsigned_leb128!(test_usize_leb128, write_usize_leb128, read_usize_leb128, usize);
-#[test]
-fn test_signed_leb128() {
- let values: Vec<_> = (-500..500).map(|i| i * 0x12345789ABCDEF).collect();
- let mut stream = Vec::new();
- for &x in &values {
- write_signed_leb128(&mut stream, x);
- }
- let mut pos = 0;
- for &x in &values {
- let (value, bytes_read) = read_signed_leb128(&mut stream, pos);
- pos += bytes_read;
- assert_eq!(x, value);
- }
- assert_eq!(pos, stream.len());
+macro_rules! impl_test_signed_leb128 {
+ ($test_name:ident, $write_fn_name:ident, $read_fn_name:ident, $int_ty:ident) => {
+ #[test]
+ fn $test_name() {
+ // Test 256 evenly spaced values of integer range,
+ // integer max value, and some "random" numbers.
+ let mut values = Vec::new();
+
+ let mut value = $int_ty::MIN;
+ let increment = (1 as $int_ty) << ($int_ty::BITS - 8);
+
+ for _ in 0..256 {
+ values.push(value);
+ // The addition in the last loop iteration overflows.
+ value = value.wrapping_add(increment);
+ }
+
+ values.push($int_ty::MAX);
+
+ values.extend(
+ (-500..500).map(|i| (i as $int_ty).wrapping_mul(0x12345789ABCDEFi64 as $int_ty)),
+ );
+
+ let mut stream = Vec::new();
+
+ for &x in &values {
+ let mut buf = MaybeUninit::uninit_array();
+ stream.extend($write_fn_name(&mut buf, x));
+ }
+
+ let mut position = 0;
+ for &expected in &values {
+ let (actual, bytes_read) = $read_fn_name(&stream[position..]);
+ assert_eq!(expected, actual);
+ position += bytes_read;
+ }
+ assert_eq!(stream.len(), position);
+ }
+ };
}
+
+impl_test_signed_leb128!(test_i16_leb128, write_i16_leb128, read_i16_leb128, i16);
+impl_test_signed_leb128!(test_i32_leb128, write_i32_leb128, read_i32_leb128, i32);
+impl_test_signed_leb128!(test_i64_leb128, write_i64_leb128, read_i64_leb128, i64);
+impl_test_signed_leb128!(test_i128_leb128, write_i128_leb128, read_i128_leb128, i128);
+impl_test_signed_leb128!(test_isize_leb128, write_isize_leb128, read_isize_leb128, isize);
diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs
index c9ddcbd..a6d4dcb 100644
--- a/compiler/rustc_session/src/config.rs
+++ b/compiler/rustc_session/src/config.rs
@@ -5,7 +5,7 @@
use crate::lint;
use crate::search_paths::SearchPath;
-use crate::utils::NativeLibKind;
+use crate::utils::{CanonicalizedPath, NativeLibKind};
use crate::{early_error, early_warn, Session};
use rustc_data_structures::fx::FxHashSet;
@@ -13,7 +13,7 @@
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_target::abi::{Align, TargetDataLayout};
-use rustc_target::spec::{Target, TargetTriple};
+use rustc_target::spec::{SplitDebuginfo, Target, TargetTriple};
use crate::parse::CrateConfig;
use rustc_feature::UnstableFeatures;
@@ -221,23 +221,6 @@
Full,
}
-/// Some debuginfo 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 into DWARF object files, or 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 {
- /// Disabled.
- None,
- /// Sections which do not require relocation are written into the object file but ignored
- /// by the linker.
- Single,
- /// Sections which do not require relocation are written into a DWARF object (`.dwo`) file,
- /// which is skipped by the linker by virtue of being a different file.
- Split,
-}
-
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, PartialOrd, Ord)]
#[derive(Encodable, Decodable)]
pub enum OutputType {
@@ -361,7 +344,7 @@
/// Use tree-based collections to cheaply get a deterministic `Hash` implementation.
/// *Do not* switch `BTreeMap` out for an unsorted container type! That would break
/// dependency tracking for command-line arguments.
-#[derive(Clone, Hash)]
+#[derive(Clone, Hash, Debug)]
pub struct OutputTypes(BTreeMap<OutputType, Option<PathBuf>>);
impl_stable_hash_via_hash!(OutputTypes);
@@ -403,6 +386,20 @@
OutputType::Metadata | OutputType::DepInfo => false,
})
}
+
+ // 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
+ | OutputType::Assembly
+ | OutputType::LlvmAssembly
+ | OutputType::Mir
+ | OutputType::Metadata
+ | OutputType::Object
+ | OutputType::DepInfo => false,
+ OutputType::Exe => true,
+ })
+ }
}
/// Use tree-based collections to cheaply get a deterministic `Hash` implementation.
@@ -439,7 +436,7 @@
/// which one to use.
///
/// Added via `--extern prelude_name=some_file.rlib`
- ExactPaths(BTreeSet<String>),
+ ExactPaths(BTreeSet<CanonicalizedPath>),
}
impl Externs {
@@ -461,7 +458,7 @@
ExternEntry { location, is_private_dep: false, add_prelude: false }
}
- pub fn files(&self) -> Option<impl Iterator<Item = &String>> {
+ pub fn files(&self) -> Option<impl Iterator<Item = &CanonicalizedPath>> {
match &self.location {
ExternLocation::ExactPaths(set) => Some(set.iter()),
_ => None,
@@ -538,7 +535,7 @@
}
}
-#[derive(Clone, Hash)]
+#[derive(Clone, Hash, Debug)]
pub struct OutputFilenames {
pub out_directory: PathBuf,
filestem: String,
@@ -621,10 +618,10 @@
/// mode is being used, which is the logic that this function is intended to encapsulate.
pub fn split_dwarf_filename(
&self,
- split_dwarf_kind: SplitDwarfKind,
+ split_debuginfo_kind: SplitDebuginfo,
cgu_name: Option<&str>,
) -> Option<PathBuf> {
- self.split_dwarf_path(split_dwarf_kind, cgu_name)
+ self.split_dwarf_path(split_debuginfo_kind, cgu_name)
.map(|path| path.strip_prefix(&self.out_directory).unwrap_or(&path).to_path_buf())
}
@@ -632,19 +629,19 @@
/// mode is being used, which is the logic that this function is intended to encapsulate.
pub fn split_dwarf_path(
&self,
- split_dwarf_kind: SplitDwarfKind,
+ split_debuginfo_kind: SplitDebuginfo,
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_dwarf_kind {
- SplitDwarfKind::None => None,
+ match split_debuginfo_kind {
+ SplitDebuginfo::Off => 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.
- SplitDwarfKind::Single => Some(obj_out),
+ SplitDebuginfo::Packed => Some(obj_out),
// Split mode emits the DWARF into a different file, use that path.
- SplitDwarfKind::Split => Some(dwo_out),
+ SplitDebuginfo::Unpacked => Some(dwo_out),
}
}
}
@@ -819,7 +816,7 @@
}
}
ret.insert((sym::target_arch, Some(Symbol::intern(arch))));
- ret.insert((sym::target_endian, Some(Symbol::intern(end))));
+ ret.insert((sym::target_endian, Some(Symbol::intern(end.as_str()))));
ret.insert((sym::target_pointer_width, Some(Symbol::intern(&wordsz))));
ret.insert((sym::target_env, Some(Symbol::intern(env))));
ret.insert((sym::target_vendor, Some(Symbol::intern(vendor))));
@@ -1293,7 +1290,7 @@
error_format
}
-fn parse_crate_edition(matches: &getopts::Matches) -> Edition {
+pub fn parse_crate_edition(matches: &getopts::Matches) -> Edition {
let edition = match matches.opt_str("edition") {
Some(arg) => Edition::from_str(&arg).unwrap_or_else(|_| {
early_error(
@@ -1308,12 +1305,11 @@
None => DEFAULT_EDITION,
};
- if !edition.is_stable() && !nightly_options::match_is_nightly_build(matches) {
+ if !edition.is_stable() && !nightly_options::is_unstable_enabled(matches) {
early_error(
ErrorOutputType::default(),
&format!(
- "edition {} is unstable and only \
- available for nightly builds of rustc.",
+ "edition {} is unstable and only available with -Z unstable-options.",
edition,
),
)
@@ -1643,13 +1639,15 @@
for arg in matches.opt_strs("extern") {
let (name, path) = match arg.split_once('=') {
None => (arg, None),
- Some((name, path)) => (name.to_string(), Some(path.to_string())),
+ Some((name, path)) => (name.to_string(), Some(Path::new(path))),
};
let (options, name) = match name.split_once(':') {
None => (None, name),
Some((opts, name)) => (Some(opts), name.to_string()),
};
+ let path = path.map(|p| CanonicalizedPath::new(p));
+
let entry = externs.entry(name.to_owned());
use std::collections::btree_map::Entry;
@@ -1830,11 +1828,17 @@
}
if debugging_opts.mir_opt_level > 1 {
+ // Functions inlined during MIR transform can, at best, make it impossible to
+ // effectively cover inlined functions, and, at worst, break coverage map generation
+ // during LLVM codegen. For example, function counter IDs are only unique within a
+ // function. Inlining after these counters are injected can produce duplicate counters,
+ // resulting in an invalid coverage map (and ICE); so this option combination is not
+ // allowed.
early_warn(
error_format,
&format!(
- "`-Z mir-opt-level={}` (any level > 1) enables function inlining, which \
- limits the effectiveness of `-Z instrument-coverage`.",
+ "`-Z mir-opt-level={}` (or any level > 1) enables function inlining, which \
+ is incompatible with `-Z instrument-coverage`. Inlining will be disabled.",
debugging_opts.mir_opt_level,
),
);
@@ -1891,6 +1895,15 @@
let pretty = parse_pretty(matches, &debugging_opts, error_format);
+ if !debugging_opts.unstable_options
+ && !target_triple.triple().contains("apple")
+ && cg.split_debuginfo.is_some()
+ {
+ {
+ early_error(error_format, "`-Csplit-debuginfo` is unstable on this platform");
+ }
+ }
+
Options {
crate_types,
optimize: opt_level,
@@ -2167,11 +2180,12 @@
SymbolManglingVersion, TrimmedDefPaths,
};
use crate::lint;
+ use crate::options::WasiExecModel;
use crate::utils::NativeLibKind;
use rustc_feature::UnstableFeatures;
use rustc_span::edition::Edition;
use rustc_target::spec::{CodeModel, MergeFunctions, PanicStrategy, RelocModel};
- use rustc_target::spec::{RelroLevel, TargetTriple, TlsModel};
+ use rustc_target::spec::{RelroLevel, SplitDebuginfo, TargetTriple, TlsModel};
use std::collections::hash_map::DefaultHasher;
use std::collections::BTreeMap;
use std::hash::Hash;
@@ -2222,6 +2236,7 @@
impl_dep_tracking_hash_via_hash!(Option<RelocModel>);
impl_dep_tracking_hash_via_hash!(Option<CodeModel>);
impl_dep_tracking_hash_via_hash!(Option<TlsModel>);
+ impl_dep_tracking_hash_via_hash!(Option<WasiExecModel>);
impl_dep_tracking_hash_via_hash!(Option<PanicStrategy>);
impl_dep_tracking_hash_via_hash!(Option<RelroLevel>);
impl_dep_tracking_hash_via_hash!(Option<lint::Level>);
@@ -2242,6 +2257,7 @@
impl_dep_tracking_hash_via_hash!(TargetTriple);
impl_dep_tracking_hash_via_hash!(Edition);
impl_dep_tracking_hash_via_hash!(LinkerPluginLto);
+ impl_dep_tracking_hash_via_hash!(Option<SplitDebuginfo>);
impl_dep_tracking_hash_via_hash!(SwitchWithOptPath);
impl_dep_tracking_hash_via_hash!(Option<SymbolManglingVersion>);
impl_dep_tracking_hash_via_hash!(Option<SourceFileHashAlgorithm>);
diff --git a/compiler/rustc_session/src/filesearch.rs b/compiler/rustc_session/src/filesearch.rs
index 55ee4e5..47f14fa 100644
--- a/compiler/rustc_session/src/filesearch.rs
+++ b/compiler/rustc_session/src/filesearch.rs
@@ -76,7 +76,7 @@
pub fn new(
sysroot: &'a Path,
triple: &'a str,
- search_paths: &'a Vec<SearchPath>,
+ search_paths: &'a [SearchPath],
tlib_path: &'a SearchPath,
kind: PathKind,
) -> FileSearch<'a> {
@@ -113,6 +113,8 @@
sysroot.join(&relative_target_lib_path(sysroot, target_triple))
}
+// This function checks if sysroot is found using env::args().next(), and if it
+// is not found, uses env::current_exe() to imply sysroot.
pub fn get_or_default_sysroot() -> PathBuf {
// Follow symlinks. If the resolved path is relative, make it absolute.
fn canonicalize(path: PathBuf) -> PathBuf {
@@ -123,15 +125,51 @@
fix_windows_verbatim_for_gcc(&path)
}
- match env::current_exe() {
- Ok(exe) => {
- let mut p = canonicalize(exe);
- p.pop();
- p.pop();
- p
+ // Use env::current_exe() to get the path of the executable following
+ // symlinks/canonicalizing components.
+ fn from_current_exe() -> PathBuf {
+ match env::current_exe() {
+ Ok(exe) => {
+ let mut p = canonicalize(exe);
+ p.pop();
+ p.pop();
+ p
+ }
+ Err(e) => panic!("failed to get current_exe: {}", e),
}
- Err(e) => panic!("failed to get current_exe: {}", e),
}
+
+ // Use env::args().next() to get the path of the executable without
+ // following symlinks/canonicalizing any component. This makes the rustc
+ // binary able to locate Rust libraries in systems using content-addressable
+ // storage (CAS).
+ fn from_env_args_next() -> Option<PathBuf> {
+ match env::args_os().next() {
+ Some(first_arg) => {
+ let mut p = PathBuf::from(first_arg);
+
+ // Check if sysroot is found using env::args().next() only if the rustc in argv[0]
+ // is a symlink (see #79253). We might want to change/remove it to conform with
+ // https://www.gnu.org/prep/standards/standards.html#Finding-Program-Files in the
+ // future.
+ if fs::read_link(&p).is_err() {
+ // Path is not a symbolic link or does not exist.
+ return None;
+ }
+
+ p.pop();
+ p.pop();
+ let mut libdir = PathBuf::from(&p);
+ libdir.push(find_libdir(&p).as_ref());
+ if libdir.exists() { Some(p) } else { None }
+ }
+ None => None,
+ }
+ }
+
+ // Check if sysroot is found using env::args().next(), and if is not found,
+ // use env::current_exe() to imply sysroot.
+ from_env_args_next().unwrap_or(from_current_exe())
}
// The name of the directory rustc expects libraries to be located.
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index 81f79f4..779e042 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -6,7 +6,7 @@
use crate::utils::NativeLibKind;
use rustc_target::spec::{CodeModel, LinkerFlavor, MergeFunctions, PanicStrategy};
-use rustc_target::spec::{RelocModel, RelroLevel, TargetTriple, TlsModel};
+use rustc_target::spec::{RelocModel, RelroLevel, SplitDebuginfo, TargetTriple, TlsModel};
use rustc_feature::UnstableFeatures;
use rustc_span::edition::Edition;
@@ -269,7 +269,6 @@
pub const parse_switch_with_opt_path: &str =
"an optional path to the profiling data output directory";
pub const parse_merge_functions: &str = "one of: `disabled`, `trampolines`, or `aliases`";
- pub const parse_split_dwarf_kind: &str = "one of: `none`, `single` or `split`";
pub const parse_symbol_mangling_version: &str = "either `legacy` or `v0` (RFC 2603)";
pub const parse_src_file_hash: &str = "either `md5` or `sha1`";
pub const parse_relocation_model: &str =
@@ -279,6 +278,9 @@
pub const parse_tls_model: &str =
"one of supported TLS models (`rustc --print tls-models`)";
pub const parse_target_feature: &str = parse_string;
+ pub const parse_wasi_exec_model: &str = "either `command` or `reactor`";
+ pub const parse_split_debuginfo: &str =
+ "one of supported split-debuginfo modes (`off` or `dsymutil`)";
}
#[allow(dead_code)]
@@ -677,19 +679,6 @@
true
}
- fn parse_split_dwarf_kind(
- slot: &mut SplitDwarfKind,
- v: Option<&str>,
- ) -> bool {
- *slot = match v {
- Some("none") => SplitDwarfKind::None,
- Some("split") => SplitDwarfKind::Split,
- Some("single") => SplitDwarfKind::Single,
- _ => return false,
- };
- true
- }
-
fn parse_symbol_mangling_version(
slot: &mut Option<SymbolManglingVersion>,
v: Option<&str>,
@@ -722,6 +711,23 @@
None => false,
}
}
+
+ fn parse_wasi_exec_model(slot: &mut Option<WasiExecModel>, v: Option<&str>) -> bool {
+ match v {
+ Some("command") => *slot = Some(WasiExecModel::Command),
+ Some("reactor") => *slot = Some(WasiExecModel::Reactor),
+ _ => return false,
+ }
+ true
+ }
+
+ fn parse_split_debuginfo(slot: &mut Option<SplitDebuginfo>, v: Option<&str>) -> bool {
+ match v.and_then(|s| SplitDebuginfo::from_str(s).ok()) {
+ Some(e) => *slot = Some(e),
+ _ => return false,
+ }
+ true
+ }
}
) }
@@ -820,6 +826,8 @@
"save all temporary output files during compilation (default: no)"),
soft_float: bool = (false, parse_bool, [TRACKED],
"use soft float ABI (*eabihf targets only) (default: no)"),
+ split_debuginfo: Option<SplitDebuginfo> = (None, parse_split_debuginfo, [TRACKED],
+ "how to handle split-debuginfo, a platform-specific option"),
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],
@@ -846,6 +854,8 @@
"only allow the listed language features to be enabled in code (space separated)"),
always_encode_mir: bool = (false, parse_bool, [TRACKED],
"encode MIR of all functions into the crate metadata (default: no)"),
+ assume_incomplete_release: bool = (false, parse_bool, [TRACKED],
+ "make cfg(version) treat the current version as incomplete (default: no)"),
asm_comments: bool = (false, parse_bool, [TRACKED],
"generate comments into the assembly (may change behavior) (default: no)"),
ast_json: bool = (false, parse_bool, [UNTRACKED],
@@ -1063,11 +1073,6 @@
"choose which RELRO level to use"),
report_delayed_bugs: bool = (false, parse_bool, [TRACKED],
"immediately print bugs registered with `delay_span_bug` (default: no)"),
- // The default historical behavior was to always run dsymutil, so we're
- // preserving that temporarily, but we're likely to switch the default
- // soon.
- run_dsymutil: bool = (true, parse_bool, [TRACKED],
- "if on Mac, run `dsymutil` and delete intermediate object files (default: yes)"),
sanitizer: SanitizerSet = (SanitizerSet::empty(), parse_sanitizers, [TRACKED],
"use a sanitizer"),
sanitizer_memory_track_origins: usize = (0, parse_sanitizer_memory_track_origins, [TRACKED],
@@ -1102,8 +1107,6 @@
"hash algorithm of source files in debug info (`md5`, `sha1`, or `sha256`)"),
strip: Strip = (Strip::None, parse_strip, [UNTRACKED],
"tell the linker which information to strip (`none` (default), `debuginfo` or `symbols`)"),
- split_dwarf: SplitDwarfKind = (SplitDwarfKind::None, parse_split_dwarf_kind, [UNTRACKED],
- "enable generation of split dwarf"),
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"),
@@ -1166,9 +1169,17 @@
"in general, enable more debug printouts (default: no)"),
verify_llvm_ir: bool = (false, parse_bool, [TRACKED],
"verify LLVM IR (default: no)"),
+ wasi_exec_model: Option<WasiExecModel> = (None, parse_wasi_exec_model, [TRACKED],
+ "whether to build a wasi command or reactor"),
// This list is in alphabetical order.
//
// If you add a new option, please update:
- // - src/librustc_interface/tests.rs
+ // - compiler/rustc_interface/src/tests.rs
+}
+
+#[derive(Clone, Hash)]
+pub enum WasiExecModel {
+ Command,
+ Reactor,
}
diff --git a/compiler/rustc_session/src/parse.rs b/compiler/rustc_session/src/parse.rs
index b1a4834..81b3834 100644
--- a/compiler/rustc_session/src/parse.rs
+++ b/compiler/rustc_session/src/parse.rs
@@ -138,6 +138,8 @@
pub env_depinfo: Lock<FxHashSet<(Symbol, Option<Symbol>)>>,
/// All the type ascriptions expressions that have had a suggestion for likely path typo.
pub type_ascription_path_suggestions: Lock<FxHashSet<Span>>,
+ /// Whether cfg(version) should treat the current release as incomplete
+ pub assume_incomplete_release: bool,
}
impl ParseSess {
@@ -164,6 +166,7 @@
reached_eof: Lock::new(false),
env_depinfo: Default::default(),
type_ascription_path_suggestions: Default::default(),
+ assume_incomplete_release: false,
}
}
diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs
index 75faab1..69aa72d 100644
--- a/compiler/rustc_session/src/session.rs
+++ b/compiler/rustc_session/src/session.rs
@@ -28,7 +28,7 @@
use rustc_span::{sym, SourceFileHashAlgorithm, Symbol};
use rustc_target::asm::InlineAsmArch;
use rustc_target::spec::{CodeModel, PanicStrategy, RelocModel, RelroLevel};
-use rustc_target::spec::{Target, TargetTriple, TlsModel};
+use rustc_target::spec::{SplitDebuginfo, Target, TargetTriple, TlsModel};
use std::cell::{self, RefCell};
use std::env;
@@ -796,6 +796,22 @@
self.opts.debugging_opts.tls_model.unwrap_or(self.target.tls_model)
}
+ pub fn is_wasi_reactor(&self) -> bool {
+ self.target.options.os == "wasi"
+ && matches!(
+ self.opts.debugging_opts.wasi_exec_model,
+ Some(config::WasiExecModel::Reactor)
+ )
+ }
+
+ pub fn split_debuginfo(&self) -> SplitDebuginfo {
+ self.opts.cg.split_debuginfo.unwrap_or(self.target.split_debuginfo)
+ }
+
+ pub fn target_can_use_split_dwarf(&self) -> bool {
+ !self.target.is_like_windows && !self.target.is_like_osx
+ }
+
pub fn must_not_eliminate_frame_pointers(&self) -> bool {
// "mcount" function relies on stack pointer.
// See <https://sourceware.org/binutils/docs/gprof/Implementation.html>.
@@ -1076,6 +1092,11 @@
self.opts.edition >= Edition::Edition2018
}
+ /// Are we allowed to use features from the Rust 2021 edition?
+ pub fn rust_2021(&self) -> bool {
+ self.opts.edition >= Edition::Edition2021
+ }
+
pub fn edition(&self) -> Edition {
self.opts.edition
}
@@ -1323,7 +1344,8 @@
None
};
- let parse_sess = ParseSess::with_span_handler(span_diagnostic, source_map);
+ let mut parse_sess = ParseSess::with_span_handler(span_diagnostic, source_map);
+ parse_sess.assume_incomplete_release = sopts.debugging_opts.assume_incomplete_release;
let sysroot = match &sopts.maybe_sysroot {
Some(sysroot) => sysroot.clone(),
None => filesearch::get_or_default_sysroot(),
@@ -1345,7 +1367,7 @@
let optimization_fuel_crate = sopts.debugging_opts.fuel.as_ref().map(|i| i.0.clone());
let optimization_fuel = Lock::new(OptimizationFuel {
- remaining: sopts.debugging_opts.fuel.as_ref().map(|i| i.1).unwrap_or(0),
+ remaining: sopts.debugging_opts.fuel.as_ref().map_or(0, |i| i.1),
out_of_fuel: false,
});
let print_fuel_crate = sopts.debugging_opts.print_fuel.clone();
@@ -1517,6 +1539,7 @@
}
const ASAN_SUPPORTED_TARGETS: &[&str] = &[
+ "aarch64-apple-darwin",
"aarch64-fuchsia",
"aarch64-unknown-linux-gnu",
"x86_64-apple-darwin",
@@ -1524,11 +1547,16 @@
"x86_64-unknown-freebsd",
"x86_64-unknown-linux-gnu",
];
- const LSAN_SUPPORTED_TARGETS: &[&str] =
- &["aarch64-unknown-linux-gnu", "x86_64-apple-darwin", "x86_64-unknown-linux-gnu"];
+ const LSAN_SUPPORTED_TARGETS: &[&str] = &[
+ "aarch64-apple-darwin",
+ "aarch64-unknown-linux-gnu",
+ "x86_64-apple-darwin",
+ "x86_64-unknown-linux-gnu",
+ ];
const MSAN_SUPPORTED_TARGETS: &[&str] =
&["aarch64-unknown-linux-gnu", "x86_64-unknown-freebsd", "x86_64-unknown-linux-gnu"];
const TSAN_SUPPORTED_TARGETS: &[&str] = &[
+ "aarch64-apple-darwin",
"aarch64-unknown-linux-gnu",
"x86_64-apple-darwin",
"x86_64-unknown-freebsd",
diff --git a/compiler/rustc_session/src/utils.rs b/compiler/rustc_session/src/utils.rs
index 15447c0..f3d3330 100644
--- a/compiler/rustc_session/src/utils.rs
+++ b/compiler/rustc_session/src/utils.rs
@@ -1,5 +1,6 @@
use crate::session::Session;
use rustc_data_structures::profiling::VerboseTimingGuard;
+use std::path::{Path, PathBuf};
impl Session {
pub fn timer<'a>(&'a self, what: &'static str) -> VerboseTimingGuard<'a> {
@@ -30,3 +31,25 @@
}
rustc_data_structures::impl_stable_hash_via_hash!(NativeLibKind);
+
+/// A path that has been canonicalized along with its original, non-canonicalized form
+#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
+pub struct CanonicalizedPath {
+ // Optional since canonicalization can sometimes fail
+ canonicalized: Option<PathBuf>,
+ original: PathBuf,
+}
+
+impl CanonicalizedPath {
+ pub fn new(path: &Path) -> Self {
+ Self { original: path.to_owned(), canonicalized: std::fs::canonicalize(path).ok() }
+ }
+
+ pub fn canonicalized(&self) -> &PathBuf {
+ self.canonicalized.as_ref().unwrap_or(self.original())
+ }
+
+ pub fn original(&self) -> &PathBuf {
+ &self.original
+ }
+}
diff --git a/compiler/rustc_span/src/analyze_source_file/tests.rs b/compiler/rustc_span/src/analyze_source_file/tests.rs
index cb418a4..66aefc9 100644
--- a/compiler/rustc_span/src/analyze_source_file/tests.rs
+++ b/compiler/rustc_span/src/analyze_source_file/tests.rs
@@ -12,7 +12,7 @@
let (lines, multi_byte_chars, non_narrow_chars) =
analyze_source_file($text, BytePos($source_file_start_pos));
- let expected_lines: Vec<BytePos> = $lines.into_iter().map(|pos| BytePos(pos)).collect();
+ let expected_lines: Vec<BytePos> = $lines.into_iter().map(BytePos).collect();
assert_eq!(lines, expected_lines);
diff --git a/compiler/rustc_span/src/caching_source_map_view.rs b/compiler/rustc_span/src/caching_source_map_view.rs
index 15dd00f..8e21b9f 100644
--- a/compiler/rustc_span/src/caching_source_map_view.rs
+++ b/compiler/rustc_span/src/caching_source_map_view.rs
@@ -1,5 +1,5 @@
use crate::source_map::SourceMap;
-use crate::{BytePos, SourceFile};
+use crate::{BytePos, SourceFile, SpanData};
use rustc_data_structures::sync::Lrc;
use std::ops::Range;
@@ -24,6 +24,32 @@
file_index: usize,
}
+impl CacheEntry {
+ #[inline]
+ fn update(
+ &mut self,
+ new_file_and_idx: Option<(Lrc<SourceFile>, usize)>,
+ pos: BytePos,
+ time_stamp: usize,
+ ) {
+ if let Some((file, file_idx)) = new_file_and_idx {
+ self.file = file;
+ self.file_index = file_idx;
+ }
+
+ let line_index = self.file.lookup_line(pos).unwrap();
+ let line_bounds = self.file.line_bounds(line_index);
+ self.line_number = line_index + 1;
+ self.line = line_bounds;
+ self.touch(time_stamp);
+ }
+
+ #[inline]
+ fn touch(&mut self, time_stamp: usize) {
+ self.time_stamp = time_stamp;
+ }
+}
+
#[derive(Clone)]
pub struct CachingSourceMapView<'sm> {
source_map: &'sm SourceMap,
@@ -57,59 +83,202 @@
self.time_stamp += 1;
// Check if the position is in one of the cached lines
- for cache_entry in self.line_cache.iter_mut() {
- if cache_entry.line.contains(&pos) {
- cache_entry.time_stamp = self.time_stamp;
+ let cache_idx = self.cache_entry_index(pos);
+ if cache_idx != -1 {
+ let cache_entry = &mut self.line_cache[cache_idx as usize];
+ cache_entry.touch(self.time_stamp);
- return Some((
- cache_entry.file.clone(),
- cache_entry.line_number,
- pos - cache_entry.line.start,
- ));
- }
+ return Some((
+ cache_entry.file.clone(),
+ cache_entry.line_number,
+ pos - cache_entry.line.start,
+ ));
}
// No cache hit ...
- let mut oldest = 0;
- for index in 1..self.line_cache.len() {
- if self.line_cache[index].time_stamp < self.line_cache[oldest].time_stamp {
- oldest = index;
- }
- }
+ let oldest = self.oldest_cache_entry_index();
+
+ // If the entry doesn't point to the correct file, get the new file and index.
+ let new_file_and_idx = if !file_contains(&self.line_cache[oldest].file, pos) {
+ Some(self.file_for_position(pos)?)
+ } else {
+ None
+ };
let cache_entry = &mut self.line_cache[oldest];
+ cache_entry.update(new_file_and_idx, pos, self.time_stamp);
- // If the entry doesn't point to the correct file, fix it up
- if !file_contains(&cache_entry.file, pos) {
- let file_valid;
- if self.source_map.files().len() > 0 {
- let file_index = self.source_map.lookup_source_file_idx(pos);
- let file = self.source_map.files()[file_index].clone();
+ Some((cache_entry.file.clone(), cache_entry.line_number, pos - cache_entry.line.start))
+ }
- if file_contains(&file, pos) {
- cache_entry.file = file;
- cache_entry.file_index = file_index;
- file_valid = true;
- } else {
- file_valid = false;
+ pub fn span_data_to_lines_and_cols(
+ &mut self,
+ span_data: &SpanData,
+ ) -> Option<(Lrc<SourceFile>, usize, BytePos, usize, BytePos)> {
+ self.time_stamp += 1;
+
+ // Check if lo and hi are in the cached lines.
+ let lo_cache_idx = self.cache_entry_index(span_data.lo);
+ let hi_cache_idx = self.cache_entry_index(span_data.hi);
+
+ if lo_cache_idx != -1 && hi_cache_idx != -1 {
+ // Cache hit for span lo and hi. Check if they belong to the same file.
+ let result = {
+ let lo = &self.line_cache[lo_cache_idx as usize];
+ let hi = &self.line_cache[hi_cache_idx as usize];
+
+ if lo.file_index != hi.file_index {
+ return None;
}
- } else {
- file_valid = false;
+
+ (
+ lo.file.clone(),
+ lo.line_number,
+ span_data.lo - lo.line.start,
+ hi.line_number,
+ span_data.hi - hi.line.start,
+ )
+ };
+
+ self.line_cache[lo_cache_idx as usize].touch(self.time_stamp);
+ self.line_cache[hi_cache_idx as usize].touch(self.time_stamp);
+
+ return Some(result);
+ }
+
+ // No cache hit or cache hit for only one of span lo and hi.
+ let oldest = if lo_cache_idx != -1 || hi_cache_idx != -1 {
+ let avoid_idx = if lo_cache_idx != -1 { lo_cache_idx } else { hi_cache_idx };
+ self.oldest_cache_entry_index_avoid(avoid_idx as usize)
+ } else {
+ self.oldest_cache_entry_index()
+ };
+
+ // If the entry doesn't point to the correct file, get the new file and index.
+ // Return early if the file containing beginning of span doesn't contain end of span.
+ let new_file_and_idx = if !file_contains(&self.line_cache[oldest].file, span_data.lo) {
+ let new_file_and_idx = self.file_for_position(span_data.lo)?;
+ if !file_contains(&new_file_and_idx.0, span_data.hi) {
+ return None;
}
- if !file_valid {
+ Some(new_file_and_idx)
+ } else {
+ let file = &self.line_cache[oldest].file;
+ if !file_contains(&file, span_data.hi) {
return None;
}
+
+ None
+ };
+
+ // Update the cache entries.
+ let (lo_idx, hi_idx) = match (lo_cache_idx, hi_cache_idx) {
+ // Oldest cache entry is for span_data.lo line.
+ (-1, -1) => {
+ let lo = &mut self.line_cache[oldest];
+ lo.update(new_file_and_idx, span_data.lo, self.time_stamp);
+
+ if !lo.line.contains(&span_data.hi) {
+ let new_file_and_idx = Some((lo.file.clone(), lo.file_index));
+ let next_oldest = self.oldest_cache_entry_index_avoid(oldest);
+ let hi = &mut self.line_cache[next_oldest];
+ hi.update(new_file_and_idx, span_data.hi, self.time_stamp);
+ (oldest, next_oldest)
+ } else {
+ (oldest, oldest)
+ }
+ }
+ // Oldest cache entry is for span_data.lo line.
+ (-1, _) => {
+ let lo = &mut self.line_cache[oldest];
+ lo.update(new_file_and_idx, span_data.lo, self.time_stamp);
+ let hi = &mut self.line_cache[hi_cache_idx as usize];
+ hi.touch(self.time_stamp);
+ (oldest, hi_cache_idx as usize)
+ }
+ // Oldest cache entry is for span_data.hi line.
+ (_, -1) => {
+ let hi = &mut self.line_cache[oldest];
+ hi.update(new_file_and_idx, span_data.hi, self.time_stamp);
+ let lo = &mut self.line_cache[lo_cache_idx as usize];
+ lo.touch(self.time_stamp);
+ (lo_cache_idx as usize, oldest)
+ }
+ _ => {
+ panic!();
+ }
+ };
+
+ let lo = &self.line_cache[lo_idx];
+ let hi = &self.line_cache[hi_idx];
+
+ // Span lo and hi may equal line end when last line doesn't
+ // end in newline, hence the inclusive upper bounds below.
+ debug_assert!(span_data.lo >= lo.line.start);
+ debug_assert!(span_data.lo <= lo.line.end);
+ debug_assert!(span_data.hi >= hi.line.start);
+ debug_assert!(span_data.hi <= hi.line.end);
+ debug_assert!(lo.file.contains(span_data.lo));
+ debug_assert!(lo.file.contains(span_data.hi));
+ debug_assert_eq!(lo.file_index, hi.file_index);
+
+ Some((
+ lo.file.clone(),
+ lo.line_number,
+ span_data.lo - lo.line.start,
+ hi.line_number,
+ span_data.hi - hi.line.start,
+ ))
+ }
+
+ fn cache_entry_index(&self, pos: BytePos) -> isize {
+ for (idx, cache_entry) in self.line_cache.iter().enumerate() {
+ if cache_entry.line.contains(&pos) {
+ return idx as isize;
+ }
}
- let line_index = cache_entry.file.lookup_line(pos).unwrap();
- let line_bounds = cache_entry.file.line_bounds(line_index);
+ -1
+ }
- cache_entry.line_number = line_index + 1;
- cache_entry.line = line_bounds;
- cache_entry.time_stamp = self.time_stamp;
+ fn oldest_cache_entry_index(&self) -> usize {
+ let mut oldest = 0;
- Some((cache_entry.file.clone(), cache_entry.line_number, pos - cache_entry.line.start))
+ for idx in 1..self.line_cache.len() {
+ if self.line_cache[idx].time_stamp < self.line_cache[oldest].time_stamp {
+ oldest = idx;
+ }
+ }
+
+ oldest
+ }
+
+ fn oldest_cache_entry_index_avoid(&self, avoid_idx: usize) -> usize {
+ let mut oldest = if avoid_idx != 0 { 0 } else { 1 };
+
+ for idx in 0..self.line_cache.len() {
+ if idx != avoid_idx
+ && self.line_cache[idx].time_stamp < self.line_cache[oldest].time_stamp
+ {
+ oldest = idx;
+ }
+ }
+
+ oldest
+ }
+
+ fn file_for_position(&self, pos: BytePos) -> Option<(Lrc<SourceFile>, usize)> {
+ if !self.source_map.files().is_empty() {
+ let file_idx = self.source_map.lookup_source_file_idx(pos);
+ let file = &self.source_map.files()[file_idx];
+
+ if file_contains(file, pos) {
+ return Some((file.clone(), file_idx));
+ }
+ }
+
+ None
}
}
diff --git a/compiler/rustc_span/src/edition.rs b/compiler/rustc_span/src/edition.rs
index 4d0c92f..a9200dd 100644
--- a/compiler/rustc_span/src/edition.rs
+++ b/compiler/rustc_span/src/edition.rs
@@ -4,35 +4,42 @@
use rustc_macros::HashStable_Generic;
-/// The edition of the compiler (RFC 2052)
+/// The edition of the compiler. (See [RFC 2052](https://github.com/rust-lang/rfcs/blob/master/text/2052-epochs.md).)
#[derive(Clone, Copy, Hash, PartialEq, PartialOrd, Debug, Encodable, Decodable, Eq)]
#[derive(HashStable_Generic)]
pub enum Edition {
- // editions must be kept in order, oldest to newest
+ // When adding new editions, be sure to do the following:
+ //
+ // - update the `ALL_EDITIONS` const
+ // - update the `EDITION_NAME_LIST` const
+ // - add a `rust_####()` function to the session
+ // - update the enum in Cargo's sources as well
+ //
+ // Editions *must* be kept in order, oldest to newest.
/// The 2015 edition
Edition2015,
/// The 2018 edition
Edition2018,
- // when adding new editions, be sure to update:
- //
- // - Update the `ALL_EDITIONS` const
- // - Update the EDITION_NAME_LIST const
- // - add a `rust_####()` function to the session
- // - update the enum in Cargo's sources as well
+ /// The 2021 ediiton
+ Edition2021,
}
-// must be in order from oldest to newest
-pub const ALL_EDITIONS: &[Edition] = &[Edition::Edition2015, Edition::Edition2018];
+// Must be in order from oldest to newest.
+pub const ALL_EDITIONS: &[Edition] =
+ &[Edition::Edition2015, Edition::Edition2018, Edition::Edition2021];
-pub const EDITION_NAME_LIST: &str = "2015|2018";
+pub const EDITION_NAME_LIST: &str = "2015|2018|2021";
pub const DEFAULT_EDITION: Edition = Edition::Edition2015;
+pub const LATEST_STABLE_EDITION: Edition = Edition::Edition2018;
+
impl fmt::Display for Edition {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let s = match *self {
Edition::Edition2015 => "2015",
Edition::Edition2018 => "2018",
+ Edition::Edition2021 => "2021",
};
write!(f, "{}", s)
}
@@ -43,6 +50,7 @@
match *self {
Edition::Edition2015 => "rust_2015_compatibility",
Edition::Edition2018 => "rust_2018_compatibility",
+ Edition::Edition2021 => "rust_2021_compatibility",
}
}
@@ -50,6 +58,7 @@
match *self {
Edition::Edition2015 => sym::rust_2015_preview,
Edition::Edition2018 => sym::rust_2018_preview,
+ Edition::Edition2021 => sym::rust_2021_preview,
}
}
@@ -57,6 +66,7 @@
match *self {
Edition::Edition2015 => true,
Edition::Edition2018 => true,
+ Edition::Edition2021 => false,
}
}
}
@@ -67,6 +77,7 @@
match s {
"2015" => Ok(Edition::Edition2015),
"2018" => Ok(Edition::Edition2018),
+ "2021" => Ok(Edition::Edition2021),
_ => Err(()),
}
}
diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs
index 0f82db1..9f265f3 100644
--- a/compiler/rustc_span/src/hygiene.rs
+++ b/compiler/rustc_span/src/hygiene.rs
@@ -27,14 +27,18 @@
use crate::edition::Edition;
use crate::symbol::{kw, sym, Symbol};
use crate::SESSION_GLOBALS;
-use crate::{Span, DUMMY_SP};
+use crate::{BytePos, CachingSourceMapView, ExpnIdCache, SourceFile, Span, DUMMY_SP};
use crate::def_id::{CrateNum, DefId, CRATE_DEF_INDEX, LOCAL_CRATE};
+use rustc_data_structures::fingerprint::Fingerprint;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_data_structures::sync::{Lock, Lrc};
use rustc_macros::HashStable_Generic;
use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
use std::fmt;
+use std::hash::Hash;
+use std::thread::LocalKey;
use tracing::*;
/// A `SyntaxContext` represents a chain of pairs `(ExpnId, Transparency)` named "marks".
@@ -80,7 +84,12 @@
impl ExpnId {
pub fn fresh(expn_data: Option<ExpnData>) -> Self {
- HygieneData::with(|data| data.fresh_expn(expn_data))
+ let has_data = expn_data.is_some();
+ let expn_id = HygieneData::with(|data| data.fresh_expn(expn_data));
+ if has_data {
+ update_disambiguator(expn_id);
+ }
+ expn_id
}
/// The ID of the theoretical expansion that generates freshly parsed, unexpanded AST.
@@ -111,7 +120,8 @@
assert!(old_expn_data.is_none(), "expansion data is reset for an expansion ID");
expn_data.orig_id.replace(self.as_u32()).expect_none("orig_id should be None");
*old_expn_data = Some(expn_data);
- })
+ });
+ update_disambiguator(self)
}
pub fn is_descendant_of(self, ancestor: ExpnId) -> bool {
@@ -152,6 +162,12 @@
expn_data: Vec<Option<ExpnData>>,
syntax_context_data: Vec<SyntaxContextData>,
syntax_context_map: FxHashMap<(SyntaxContext, ExpnId, Transparency), SyntaxContext>,
+ /// Maps the `Fingerprint` of an `ExpnData` to the next disambiguator value.
+ /// This is used by `update_disambiguator` to keep track of which `ExpnData`s
+ /// would have collisions without a disambiguator.
+ /// The keys of this map are always computed with `ExpnData.disambiguator`
+ /// set to 0.
+ expn_data_disambiguators: FxHashMap<Fingerprint, u32>,
}
impl HygieneData {
@@ -175,6 +191,7 @@
dollar_crate_name: kw::DollarCrate,
}],
syntax_context_map: FxHashMap::default(),
+ expn_data_disambiguators: FxHashMap::default(),
}
}
@@ -622,6 +639,10 @@
pub fn dollar_crate_name(self) -> Symbol {
HygieneData::with(|data| data.syntax_context_data[self.0 as usize].dollar_crate_name)
}
+
+ pub fn edition(self) -> Edition {
+ self.outer_expn_data().edition
+ }
}
impl fmt::Debug for SyntaxContext {
@@ -645,11 +666,25 @@
expn_data: ExpnData,
transparency: Transparency,
) -> Span {
+ let expn_id = ExpnId::fresh(Some(expn_data));
HygieneData::with(|data| {
- let expn_id = data.fresh_expn(Some(expn_data));
self.with_ctxt(data.apply_mark(SyntaxContext::root(), expn_id, transparency))
})
}
+
+ /// Reuses the span but adds information like the kind of the desugaring and features that are
+ /// allowed inside this span.
+ pub fn mark_with_reason(
+ self,
+ allow_internal_unstable: Option<Lrc<[Symbol]>>,
+ reason: DesugaringKind,
+ edition: Edition,
+ ) -> Span {
+ self.fresh_expansion(ExpnData {
+ allow_internal_unstable,
+ ..ExpnData::default(ExpnKind::Desugaring(reason), self, edition, None)
+ })
+ }
}
/// A subset of properties from both macro definition and macro call available through global data.
@@ -699,7 +734,7 @@
/// created locally - when our serialized metadata is decoded,
/// foreign `ExpnId`s will have their `ExpnData` looked up
/// from the crate specified by `Crate
- pub krate: CrateNum,
+ krate: CrateNum,
/// The raw that this `ExpnData` had in its original crate.
/// An `ExpnData` can be created before being assigned an `ExpnId`,
/// so this might be `None` until `set_expn_data` is called
@@ -707,13 +742,53 @@
// two `ExpnData`s that differ only in their `orig_id` should
// be considered equivalent.
#[stable_hasher(ignore)]
- pub orig_id: Option<u32>,
+ orig_id: Option<u32>,
+
+ /// Used to force two `ExpnData`s to have different `Fingerprint`s.
+ /// Due to macro expansion, it's possible to end up with two `ExpnId`s
+ /// that have identical `ExpnData`s. This violates the constract of `HashStable`
+ /// - the two `ExpnId`s are not equal, but their `Fingerprint`s are equal
+ /// (since the numerical `ExpnId` value is not considered by the `HashStable`
+ /// implementation).
+ ///
+ /// The `disambiguator` field is set by `update_disambiguator` when two distinct
+ /// `ExpnId`s would end up with the same `Fingerprint`. Since `ExpnData` includes
+ /// a `krate` field, this value only needs to be unique within a single crate.
+ disambiguator: u32,
}
-// This would require special handling of `orig_id` and `parent`
+// These would require special handling of `orig_id`.
impl !PartialEq for ExpnData {}
+impl !Hash for ExpnData {}
impl ExpnData {
+ pub fn new(
+ kind: ExpnKind,
+ parent: ExpnId,
+ call_site: Span,
+ def_site: Span,
+ allow_internal_unstable: Option<Lrc<[Symbol]>>,
+ allow_internal_unsafe: bool,
+ local_inner_macros: bool,
+ edition: Edition,
+ macro_def_id: Option<DefId>,
+ ) -> ExpnData {
+ ExpnData {
+ kind,
+ parent,
+ call_site,
+ def_site,
+ allow_internal_unstable,
+ allow_internal_unsafe,
+ local_inner_macros,
+ edition,
+ macro_def_id,
+ krate: LOCAL_CRATE,
+ orig_id: None,
+ disambiguator: 0,
+ }
+ }
+
/// Constructs expansion data with default properties.
pub fn default(
kind: ExpnKind,
@@ -733,6 +808,7 @@
macro_def_id,
krate: LOCAL_CRATE,
orig_id: None,
+ disambiguator: 0,
}
}
@@ -1065,7 +1141,7 @@
parent: SyntaxContext::root(),
opaque: SyntaxContext::root(),
opaque_and_semitransparent: SyntaxContext::root(),
- dollar_crate_name: kw::Invalid,
+ dollar_crate_name: kw::Empty,
});
let mut ctxts = outer_ctxts.lock();
let new_len = raw_id as usize + 1;
@@ -1092,7 +1168,7 @@
ctxt_data,
);
// Make sure nothing weird happening while `decode_data` was running
- assert_eq!(dummy.dollar_crate_name, kw::Invalid);
+ assert_eq!(dummy.dollar_crate_name, kw::Empty);
});
Ok(new_ctxt)
@@ -1232,3 +1308,118 @@
panic!("cannot decode `SyntaxContext` with `{}`", std::any::type_name::<D>());
}
}
+
+/// Updates the `disambiguator` field of the corresponding `ExpnData`
+/// such that the `Fingerprint` of the `ExpnData` does not collide with
+/// any other `ExpnIds`.
+///
+/// This method is called only when an `ExpnData` is first associated
+/// with an `ExpnId` (when the `ExpnId` is initially constructed, or via
+/// `set_expn_data`). It is *not* called for foreign `ExpnId`s deserialized
+/// from another crate's metadata - since `ExpnData` includes a `krate` field,
+/// collisions are only possible between `ExpnId`s within the same crate.
+fn update_disambiguator(expn_id: ExpnId) {
+ /// A `HashStableContext` which hashes the raw id values for `DefId`
+ /// and `CrateNum`, rather than using their computed stable hash.
+ ///
+ /// This allows us to use the `HashStable` implementation on `ExpnId`
+ /// early on in compilation, before we've constructed a `TyCtxt`.
+ /// The `Fingerprint`s created by this context are not 'stable', since
+ /// the raw `CrateNum` and `DefId` values for an item may change between
+ /// sessions due to unrelated changes (e.g. adding/removing an different item).
+ ///
+ /// However, this is fine for our purposes - we only need to detect
+ /// when two `ExpnData`s have the same `Fingerprint`. Since the hashes produced
+ /// by this context still obey the properties of `HashStable`, we have
+ /// that
+ /// `hash_stable(expn1, DummyHashStableContext) == hash_stable(expn2, DummyHashStableContext)`
+ /// iff `hash_stable(expn1, StableHashingContext) == hash_stable(expn2, StableHasingContext)`.
+ ///
+ /// This is sufficient for determining when we need to update the disambiguator.
+ struct DummyHashStableContext<'a> {
+ caching_source_map: CachingSourceMapView<'a>,
+ }
+
+ impl<'a> crate::HashStableContext for DummyHashStableContext<'a> {
+ fn hash_def_id(&mut self, def_id: DefId, hasher: &mut StableHasher) {
+ def_id.krate.as_u32().hash_stable(self, hasher);
+ def_id.index.as_u32().hash_stable(self, hasher);
+ }
+
+ fn expn_id_cache() -> &'static LocalKey<ExpnIdCache> {
+ // This cache is only used by `DummyHashStableContext`,
+ // so we won't pollute the cache values of the normal `StableHashingContext`
+ thread_local! {
+ static CACHE: ExpnIdCache = Default::default();
+ }
+
+ &CACHE
+ }
+
+ fn hash_crate_num(&mut self, krate: CrateNum, hasher: &mut StableHasher) {
+ krate.as_u32().hash_stable(self, hasher);
+ }
+ fn hash_spans(&self) -> bool {
+ true
+ }
+ fn byte_pos_to_line_and_col(
+ &mut self,
+ byte: BytePos,
+ ) -> Option<(Lrc<SourceFile>, usize, BytePos)> {
+ self.caching_source_map.byte_pos_to_line_and_col(byte)
+ }
+ fn span_data_to_lines_and_cols(
+ &mut self,
+ span: &crate::SpanData,
+ ) -> Option<(Lrc<SourceFile>, usize, BytePos, usize, BytePos)> {
+ self.caching_source_map.span_data_to_lines_and_cols(span)
+ }
+ }
+
+ let source_map = SESSION_GLOBALS
+ .with(|session_globals| session_globals.source_map.borrow().as_ref().unwrap().clone());
+
+ let mut ctx =
+ DummyHashStableContext { caching_source_map: CachingSourceMapView::new(&source_map) };
+
+ let mut hasher = StableHasher::new();
+
+ let expn_data = expn_id.expn_data();
+ // This disambiguator should not have been set yet.
+ assert_eq!(
+ expn_data.disambiguator, 0,
+ "Already set disambiguator for ExpnData: {:?}",
+ expn_data
+ );
+ expn_data.hash_stable(&mut ctx, &mut hasher);
+ let first_hash = hasher.finish();
+
+ let modified = HygieneData::with(|data| {
+ // If this is the first ExpnData with a given hash, then keep our
+ // disambiguator at 0 (the default u32 value)
+ let disambig = data.expn_data_disambiguators.entry(first_hash).or_default();
+ data.expn_data[expn_id.0 as usize].as_mut().unwrap().disambiguator = *disambig;
+ *disambig += 1;
+
+ *disambig != 1
+ });
+
+ if modified {
+ info!("Set disambiguator for {:?} (hash {:?})", expn_id, first_hash);
+ info!("expn_data = {:?}", expn_id.expn_data());
+
+ // Verify that the new disambiguator makes the hash unique
+ #[cfg(debug_assertions)]
+ {
+ hasher = StableHasher::new();
+ expn_id.expn_data().hash_stable(&mut ctx, &mut hasher);
+ let new_hash: Fingerprint = hasher.finish();
+
+ HygieneData::with(|data| {
+ data.expn_data_disambiguators
+ .get(&new_hash)
+ .expect_none("Hash collision after disambiguator update!");
+ });
+ };
+ }
+}
diff --git a/compiler/rustc_span/src/lev_distance.rs b/compiler/rustc_span/src/lev_distance.rs
index edc6625..cea7871 100644
--- a/compiler/rustc_span/src/lev_distance.rs
+++ b/compiler/rustc_span/src/lev_distance.rs
@@ -1,10 +1,16 @@
+//! Levenshtein distances.
+//!
+//! The [Levenshtein distance] is a metric for measuring the difference between two strings.
+//!
+//! [Levenshtein distance]: https://en.wikipedia.org/wiki/Levenshtein_distance
+
use crate::symbol::Symbol;
use std::cmp;
#[cfg(test)]
mod tests;
-/// Finds the Levenshtein distance between two strings
+/// Finds the Levenshtein distance between two strings.
pub fn lev_distance(a: &str, b: &str) -> usize {
// cases which don't require further computation
if a.is_empty() {
@@ -35,14 +41,14 @@
dcol[t_last + 1]
}
-/// Finds the best match for a given word in the given iterator
+/// Finds the best match for a given word in the given iterator.
///
/// As a loose rule to avoid the obviously incorrect suggestions, it takes
/// an optional limit for the maximum allowable edit distance, which defaults
/// to one-third of the given word.
///
-/// Besides Levenshtein, we use case insensitive comparison to improve accuracy on an edge case with
-/// a lower(upper)case letters mismatch.
+/// Besides Levenshtein, we use case insensitive comparison to improve accuracy
+/// on an edge case with a lower(upper)case letters mismatch.
#[cold]
pub fn find_best_match_for_name(
name_vec: &[Symbol],
@@ -98,7 +104,7 @@
fn sort_by_words(name: &str) -> String {
let mut split_words: Vec<&str> = name.split('_').collect();
- // We are sorting primitive &strs and can use unstable sort here
+ // We are sorting primitive &strs and can use unstable sort here.
split_words.sort_unstable();
split_words.join("_")
}
diff --git a/compiler/rustc_span/src/lev_distance/tests.rs b/compiler/rustc_span/src/lev_distance/tests.rs
index 7aa01cb..90e20af 100644
--- a/compiler/rustc_span/src/lev_distance/tests.rs
+++ b/compiler/rustc_span/src/lev_distance/tests.rs
@@ -4,7 +4,7 @@
fn test_lev_distance() {
use std::char::{from_u32, MAX};
// Test bytelength agnosticity
- for c in (0..MAX as u32).filter_map(|i| from_u32(i)).map(|i| i.to_string()) {
+ for c in (0..MAX as u32).filter_map(from_u32).map(|i| i.to_string()) {
assert_eq!(lev_distance(&c[..], &c[..]), 0);
}
diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs
index fbef4d0..f3d876a 100644
--- a/compiler/rustc_span/src/lib.rs
+++ b/compiler/rustc_span/src/lib.rs
@@ -1,4 +1,13 @@
-//! The source positions and related helper functions.
+//! Source positions and related helper functions.
+//!
+//! Important concepts in this module include:
+//!
+//! - the *span*, represented by [`SpanData`] and related types;
+//! - source code as represented by a [`SourceMap`]; and
+//! - interned strings, represented by [`Symbol`]s, with some common symbols available statically in the [`sym`] module.
+//!
+//! Unlike most compilers, the span contains not only the position in the source code, but also various other metadata,
+//! such as the edition and macro hygiene. This metadata is stored in [`SyntaxContext`] and [`ExpnData`].
//!
//! ## Note
//!
@@ -56,6 +65,7 @@
use std::ops::{Add, Range, Sub};
use std::path::{Path, PathBuf};
use std::str::FromStr;
+use std::thread::LocalKey;
use md5::Md5;
use sha1::Digest;
@@ -124,7 +134,7 @@
impl RealFileName {
/// Returns the path suitable for reading from the file system on the local host.
- /// Avoid embedding this in build artifacts; see `stable_name` for that.
+ /// Avoid embedding this in build artifacts; see `stable_name()` for that.
pub fn local_path(&self) -> &Path {
match self {
RealFileName::Named(p)
@@ -133,7 +143,7 @@
}
/// Returns the path suitable for reading from the file system on the local host.
- /// Avoid embedding this in build artifacts; see `stable_name` for that.
+ /// Avoid embedding this in build artifacts; see `stable_name()` for that.
pub fn into_local_path(self) -> PathBuf {
match self {
RealFileName::Named(p)
@@ -143,7 +153,7 @@
/// Returns the path suitable for embedding into build artifacts. Note that
/// a virtualized path will not correspond to a valid file system path; see
- /// `local_path` for something that is more likely to return paths into the
+ /// `local_path()` for something that is more likely to return paths into the
/// local host file system.
pub fn stable_name(&self) -> &Path {
match self {
@@ -173,7 +183,7 @@
/// Custom sources for explicit parser calls from plugins and drivers.
Custom(String),
DocTest(PathBuf, isize),
- /// Post-substitution inline assembly from LLVM
+ /// Post-substitution inline assembly from LLVM.
InlineAsm(u64),
}
@@ -266,14 +276,17 @@
}
}
+/// Represents a span.
+///
/// Spans represent a region of code, used for error reporting. Positions in spans
-/// are *absolute* positions from the beginning of the source_map, not positions
-/// relative to `SourceFile`s. Methods on the `SourceMap` can be used to relate spans back
+/// are *absolute* positions from the beginning of the [`SourceMap`], not positions
+/// relative to [`SourceFile`]s. Methods on the `SourceMap` can be used to relate spans back
/// to the original source.
-/// You must be careful if the span crosses more than one file - you will not be
+///
+/// You must be careful if the span crosses more than one file, since you will not be
/// able to use many of the functions on spans in source_map and you cannot assume
-/// that the length of the `span = hi - lo`; there may be space in the `BytePos`
-/// range between files.
+/// that the length of the span is equal to `span.hi - span.lo`; there may be space in the
+/// [`BytePos`] range between files.
///
/// `SpanData` is public because `Span` uses a thread-local interner and can't be
/// sent to other threads, but some pieces of performance infra run in a separate thread.
@@ -289,6 +302,10 @@
impl SpanData {
#[inline]
+ pub fn span(&self) -> Span {
+ Span::new(self.lo, self.hi, self.ctxt)
+ }
+ #[inline]
pub fn with_lo(&self, lo: BytePos) -> Span {
Span::new(lo, self.hi, self.ctxt)
}
@@ -384,7 +401,7 @@
Span::new(lo, hi, SyntaxContext::root())
}
- /// Returns a new span representing an empty span at the beginning of this span
+ /// Returns a new span representing an empty span at the beginning of this span.
#[inline]
pub fn shrink_to_lo(self) -> Span {
let span = self.data();
@@ -398,7 +415,7 @@
}
#[inline]
- /// Returns true if hi == lo
+ /// Returns `true` if `hi == lo`.
pub fn is_empty(&self) -> bool {
let span = self.data();
span.hi == span.lo
@@ -456,7 +473,7 @@
/// Edition of the crate from which this span came.
pub fn edition(self) -> edition::Edition {
- self.ctxt().outer_expn_data().edition
+ self.ctxt().edition()
}
#[inline]
@@ -469,6 +486,11 @@
self.edition() >= edition::Edition::Edition2018
}
+ #[inline]
+ pub fn rust_2021(&self) -> bool {
+ self.edition() >= edition::Edition::Edition2021
+ }
+
/// Returns the source callee.
///
/// Returns `None` if the supplied span has no expansion trace,
@@ -512,7 +534,7 @@
}
/// Checks if a span is "internal" to a macro in which `unsafe`
- /// can be used without triggering the `unsafe_code` lint
+ /// can be used without triggering the `unsafe_code` lint.
// (that is, a macro marked with `#[allow_internal_unsafe]`).
pub fn allows_unsafe(&self) -> bool {
self.ctxt().outer_expn_data().allow_internal_unsafe
@@ -700,6 +722,7 @@
}
}
+/// A span together with some additional data.
#[derive(Clone, Debug)]
pub struct SpanLabel {
/// The span we are going to include in the final snippet.
@@ -743,7 +766,7 @@
/// any spans that are debug-printed during the closure's execution.
///
/// Normally, the global `TyCtxt` is used to retrieve the `SourceMap`
-/// (see `rustc_interface::callbacks::span_debug1). However, some parts
+/// (see `rustc_interface::callbacks::span_debug1`). However, some parts
/// of the compiler (e.g. `rustc_parse`) may debug-print `Span`s before
/// a `TyCtxt` is available. In this case, we fall back to
/// the `SourceMap` provided to this function. If that is not available,
@@ -994,9 +1017,9 @@
Unneeded,
Foreign {
kind: ExternalSourceKind,
- /// This SourceFile's byte-offset within the source_map of its original crate
+ /// This SourceFile's byte-offset within the source_map of its original crate.
original_start_pos: BytePos,
- /// The end of this SourceFile within the source_map of its original crate
+ /// The end of this SourceFile within the source_map of its original crate.
original_end_pos: BytePos,
},
}
@@ -1099,7 +1122,7 @@
}
}
-/// A single source in the `SourceMap`.
+/// A single source in the [`SourceMap`].
#[derive(Clone)]
pub struct SourceFile {
/// The name of the file that the source came from. Source that doesn't
@@ -1580,7 +1603,7 @@
/// Replaces `\r\n` with `\n` in-place in `src`.
///
-/// Returns error if there's a lone `\r` in the string
+/// Returns error if there's a lone `\r` in the string.
fn normalize_newlines(src: &mut String, normalized_pos: &mut Vec<NormalizedPos>) {
if !src.as_bytes().contains(&b'\r') {
return;
@@ -1705,13 +1728,16 @@
}
impl_pos! {
- /// A byte offset. Keep this small (currently 32-bits), as AST contains
- /// a lot of them.
+ /// A byte offset.
+ ///
+ /// Keep this small (currently 32-bits), as AST contains a lot of them.
#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)]
pub struct BytePos(pub u32);
- /// A character offset. Because of multibyte UTF-8 characters, a byte offset
- /// is not equivalent to a character offset. The `SourceMap` will convert `BytePos`
+ /// A character offset.
+ ///
+ /// Because of multibyte UTF-8 characters, a byte offset
+ /// is not equivalent to a character offset. The [`SourceMap`] will convert [`BytePos`]
/// values to `CharPos` values as necessary.
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)]
pub struct CharPos(pub usize);
@@ -1835,16 +1861,26 @@
}
/// Requirements for a `StableHashingContext` to be used in this crate.
-/// This is a hack to allow using the `HashStable_Generic` derive macro
-/// instead of implementing everything in librustc_middle.
+///
+/// This is a hack to allow using the [`HashStable_Generic`] derive macro
+/// instead of implementing everything in rustc_middle.
pub trait HashStableContext {
fn hash_def_id(&mut self, _: DefId, hasher: &mut StableHasher);
+ /// Obtains a cache for storing the `Fingerprint` of an `ExpnId`.
+ /// This method allows us to have multiple `HashStableContext` implementations
+ /// that hash things in a different way, without the results of one polluting
+ /// the cache of the other.
+ fn expn_id_cache() -> &'static LocalKey<ExpnIdCache>;
fn hash_crate_num(&mut self, _: CrateNum, hasher: &mut StableHasher);
fn hash_spans(&self) -> bool;
fn byte_pos_to_line_and_col(
&mut self,
byte: BytePos,
) -> Option<(Lrc<SourceFile>, usize, BytePos)>;
+ fn span_data_to_lines_and_cols(
+ &mut self,
+ span: &SpanData,
+ ) -> Option<(Lrc<SourceFile>, usize, BytePos, usize, BytePos)>;
}
impl<CTX> HashStable<CTX> for Span
@@ -1856,6 +1892,7 @@
/// offsets into the `SourceMap`). Instead, we hash the (file name, line, column)
/// triple, which stays the same even if the containing `SourceFile` has moved
/// within the `SourceMap`.
+ ///
/// Also note that we are hashing byte offsets for the column, not unicode
/// codepoint offsets. For the purpose of the hash that's sufficient.
/// Also, hashing filenames is expensive so we avoid doing it twice when the
@@ -1868,8 +1905,9 @@
return;
}
- if *self == DUMMY_SP {
+ if self.is_dummy() {
Hash::hash(&TAG_INVALID_SPAN, hasher);
+ self.ctxt().hash_stable(ctx, hasher);
return;
}
@@ -1877,22 +1915,8 @@
// position that belongs to it, as opposed to hashing the first
// position past it.
let span = self.data();
- let (file_lo, line_lo, col_lo) = match ctx.byte_pos_to_line_and_col(span.lo) {
- Some(pos) => pos,
- None => {
- Hash::hash(&TAG_INVALID_SPAN, hasher);
- span.ctxt.hash_stable(ctx, hasher);
- return;
- }
- };
-
- if !file_lo.contains(span.hi) {
- Hash::hash(&TAG_INVALID_SPAN, hasher);
- span.ctxt.hash_stable(ctx, hasher);
- return;
- }
-
- let (_, line_hi, col_hi) = match ctx.byte_pos_to_line_and_col(span.hi) {
+ let (file, line_lo, col_lo, line_hi, col_hi) = match ctx.span_data_to_lines_and_cols(&span)
+ {
Some(pos) => pos,
None => {
Hash::hash(&TAG_INVALID_SPAN, hasher);
@@ -1904,7 +1928,7 @@
Hash::hash(&TAG_VALID_SPAN, hasher);
// We truncate the stable ID hash and line and column numbers. The chances
// of causing a collision this way should be minimal.
- Hash::hash(&(file_lo.name_hash as u64), hasher);
+ Hash::hash(&(file.name_hash as u64), hasher);
// Hash both the length and the end location (line/column) of a span. If we
// hash only the length, for example, then two otherwise equal spans with
@@ -1943,15 +1967,10 @@
}
}
+pub type ExpnIdCache = RefCell<Vec<Option<Fingerprint>>>;
+
impl<CTX: HashStableContext> HashStable<CTX> for ExpnId {
fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
- // Since the same expansion context is usually referenced many
- // times, we cache a stable hash of it and hash that instead of
- // recursing every time.
- thread_local! {
- static CACHE: RefCell<Vec<Option<Fingerprint>>> = Default::default();
- }
-
const TAG_ROOT: u8 = 0;
const TAG_NOT_ROOT: u8 = 1;
@@ -1960,8 +1979,11 @@
return;
}
+ // Since the same expansion context is usually referenced many
+ // times, we cache a stable hash of it and hash that instead of
+ // recursing every time.
let index = self.as_u32() as usize;
- let res = CACHE.with(|cache| cache.borrow().get(index).copied().flatten());
+ let res = CTX::expn_id_cache().with(|cache| cache.borrow().get(index).copied().flatten());
if let Some(res) = res {
res.hash_stable(ctx, hasher);
@@ -1973,7 +1995,7 @@
self.expn_data().hash_stable(ctx, &mut sub_hasher);
let sub_hash: Fingerprint = sub_hasher.finish();
- CACHE.with(|cache| {
+ CTX::expn_id_cache().with(|cache| {
let mut cache = cache.borrow_mut();
if cache.len() < new_len {
cache.resize(new_len, None);
diff --git a/compiler/rustc_span/src/source_map.rs b/compiler/rustc_span/src/source_map.rs
index e9b4eb6..2b42937 100644
--- a/compiler/rustc_span/src/source_map.rs
+++ b/compiler/rustc_span/src/source_map.rs
@@ -1,9 +1,11 @@
-//! The `SourceMap` tracks all the source code used within a single crate, mapping
+//! Types for tracking pieces of source code within a crate.
+//!
+//! The [`SourceMap`] tracks all the source code used within a single crate, mapping
//! from integer byte positions to the original source code location. Each bit
//! of source parsed during crate parsing (typically files, in-memory strings,
//! or various bits of macro expansion) cover a continuous range of bytes in the
-//! `SourceMap` and are represented by `SourceFile`s. Byte positions are stored in
-//! `Span` and used pervasively in the compiler. They are absolute positions
+//! `SourceMap` and are represented by [`SourceFile`]s. Byte positions are stored in
+//! [`Span`] and used pervasively in the compiler. They are absolute positions
//! within the `SourceMap`, which upon request can be converted to line and column
//! information, source code snippets, etc.
@@ -537,7 +539,7 @@
pub fn is_line_before_span_empty(&self, sp: Span) -> bool {
match self.span_to_prev_source(sp) {
- Ok(s) => s.split('\n').last().map(|l| l.trim_start().is_empty()).unwrap_or(false),
+ Ok(s) => s.split('\n').last().map_or(false, |l| l.trim_start().is_empty()),
Err(_) => false,
}
}
@@ -566,7 +568,7 @@
// asserting that the line numbers here are all indeed 1-based.
let hi_line = hi.line.saturating_sub(1);
for line_index in lo.line.saturating_sub(1)..hi_line {
- let line_len = lo.file.get_line(line_index).map(|s| s.chars().count()).unwrap_or(0);
+ let line_len = lo.file.get_line(line_index).map_or(0, |s| s.chars().count());
lines.push(LineInfo { line_index, start_col, end_col: CharPos::from_usize(line_len) });
start_col = CharPos::from_usize(0);
}
@@ -580,9 +582,9 @@
/// Extracts the source surrounding the given `Span` using the `extract_source` function. The
/// extract function takes three arguments: a string slice containing the source, an index in
/// the slice for the beginning of the span and an index in the slice for the end of the span.
- fn span_to_source<F>(&self, sp: Span, extract_source: F) -> Result<String, SpanSnippetError>
+ fn span_to_source<F, T>(&self, sp: Span, extract_source: F) -> Result<T, SpanSnippetError>
where
- F: Fn(&str, usize, usize) -> Result<String, SpanSnippetError>,
+ F: Fn(&str, usize, usize) -> Result<T, SpanSnippetError>,
{
let local_begin = self.lookup_byte_offset(sp.lo());
let local_end = self.lookup_byte_offset(sp.hi());
@@ -646,10 +648,10 @@
/// Extends the given `Span` to just after the previous occurrence of `c`. Return the same span
/// if no character could be found or if an error occurred while retrieving the code snippet.
- pub fn span_extend_to_prev_char(&self, sp: Span, c: char) -> Span {
+ pub fn span_extend_to_prev_char(&self, sp: Span, c: char, accept_newlines: bool) -> Span {
if let Ok(prev_source) = self.span_to_prev_source(sp) {
- let prev_source = prev_source.rsplit(c).next().unwrap_or("").trim_start();
- if !prev_source.is_empty() && !prev_source.contains('\n') {
+ let prev_source = prev_source.rsplit(c).next().unwrap_or("");
+ if !prev_source.is_empty() && (!prev_source.contains('\n') || accept_newlines) {
return sp.with_lo(BytePos(sp.lo().0 - prev_source.len() as u32));
}
}
@@ -669,7 +671,9 @@
let pat = pat.to_owned() + ws;
if let Ok(prev_source) = self.span_to_prev_source(sp) {
let prev_source = prev_source.rsplit(&pat).next().unwrap_or("").trim_start();
- if !prev_source.is_empty() && (!prev_source.contains('\n') || accept_newlines) {
+ if prev_source.is_empty() && sp.lo().0 != 0 {
+ return sp.with_lo(BytePos(sp.lo().0 - 1));
+ } else if !prev_source.contains('\n') || accept_newlines {
return sp.with_lo(BytePos(sp.lo().0 - prev_source.len() as u32));
}
}
@@ -678,6 +682,25 @@
sp
}
+ /// Returns the source snippet as `String` after the given `Span`.
+ pub fn span_to_next_source(&self, sp: Span) -> Result<String, SpanSnippetError> {
+ self.span_to_source(sp, |src, _, end_index| {
+ src.get(end_index..).map(|s| s.to_string()).ok_or(SpanSnippetError::IllFormedSpan(sp))
+ })
+ }
+
+ /// Extends the given `Span` to just after the next occurrence of `c`.
+ pub fn span_extend_to_next_char(&self, sp: Span, c: char, accept_newlines: bool) -> Span {
+ if let Ok(next_source) = self.span_to_next_source(sp) {
+ let next_source = next_source.split(c).next().unwrap_or("");
+ if !next_source.is_empty() && (!next_source.contains('\n') || accept_newlines) {
+ return sp.with_hi(BytePos(sp.hi().0 + next_source.len() as u32));
+ }
+ }
+
+ sp
+ }
+
/// Given a `Span`, tries to get a shorter span ending before the first occurrence of `char`
/// `c`.
pub fn span_until_char(&self, sp: Span, c: char) -> Span {
@@ -776,6 +799,9 @@
/// Returns a new span representing the next character after the end-point of this span.
pub fn next_point(&self, sp: Span) -> Span {
+ if sp.is_dummy() {
+ return sp;
+ }
let start_of_next_point = sp.hi().0;
let width = self.find_width_of_character_at_span(sp.shrink_to_hi(), true);
@@ -868,8 +894,10 @@
}
pub fn get_source_file(&self, filename: &FileName) -> Option<Lrc<SourceFile>> {
+ // Remap filename before lookup
+ let filename = self.path_mapping().map_filename_prefix(filename).0;
for sf in self.files.borrow().source_files.iter() {
- if *filename == sf.name {
+ if filename == sf.name {
return Some(sf.clone());
}
}
@@ -1037,4 +1065,15 @@
(path, false)
}
+
+ fn map_filename_prefix(&self, file: &FileName) -> (FileName, bool) {
+ match file {
+ FileName::Real(realfile) => {
+ let path = realfile.local_path();
+ let (path, mapped) = self.map_prefix(path.to_path_buf());
+ (FileName::Real(RealFileName::Named(path)), mapped)
+ }
+ other => (other.clone(), false),
+ }
+ }
}
diff --git a/compiler/rustc_span/src/source_map/tests.rs b/compiler/rustc_span/src/source_map/tests.rs
index b8459ee..3f22829 100644
--- a/compiler/rustc_span/src/source_map/tests.rs
+++ b/compiler/rustc_span/src/source_map/tests.rs
@@ -107,7 +107,7 @@
fn span_from_selection(input: &str, selection: &str) -> Span {
assert_eq!(input.len(), selection.len());
let left_index = selection.find('~').unwrap() as u32;
- let right_index = selection.rfind('~').map(|x| x as u32).unwrap_or(left_index);
+ let right_index = selection.rfind('~').map_or(left_index, |x| x as u32);
Span::with_root_ctxt(BytePos(left_index), BytePos(right_index + 1))
}
diff --git a/compiler/rustc_span/src/span_encoding.rs b/compiler/rustc_span/src/span_encoding.rs
index b05e01d..ceb9b59 100644
--- a/compiler/rustc_span/src/span_encoding.rs
+++ b/compiler/rustc_span/src/span_encoding.rs
@@ -12,7 +12,7 @@
/// A compressed span.
///
-/// `SpanData` is 12 bytes, which is a bit too big to stick everywhere. `Span`
+/// Whereas [`SpanData`] is 12 bytes, which is a bit too big to stick everywhere, `Span`
/// is a form that only takes up 8 bytes, with less space for the length and
/// context. The vast majority (99.9%+) of `SpanData` instances will fit within
/// those 8 bytes; any `SpanData` whose fields don't fit into a `Span` are
@@ -42,13 +42,11 @@
/// - `base` is 32 bits in both `Span` and `SpanData`, which means that `base`
/// values never cause interning. The number of bits needed for `base`
/// depends on the crate size. 32 bits allows up to 4 GiB of code in a crate.
-/// `script-servo` is the largest crate in `rustc-perf`, requiring 26 bits
-/// for some spans.
/// - `len` is 15 bits in `Span` (a u16, minus 1 bit for the tag) and 32 bits
/// in `SpanData`, which means that large `len` values will cause interning.
/// The number of bits needed for `len` does not depend on the crate size.
-/// The most common number of bits for `len` are 0--7, with a peak usually at
-/// 3 or 4, and then it drops off quickly from 8 onwards. 15 bits is enough
+/// The most common numbers of bits for `len` are from 0 to 7, with a peak usually
+/// at 3 or 4, and then it drops off quickly from 8 onwards. 15 bits is enough
/// for 99.99%+ of cases, but larger values (sometimes 20+ bits) might occur
/// dozens of times in a typical crate.
/// - `ctxt` is 16 bits in `Span` and 32 bits in `SpanData`, which means that
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 99a523c..86f8061 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -25,7 +25,7 @@
Keywords {
// Special reserved identifiers used internally for elided lifetimes,
// unnamed method parameters, crate root module, error recovery etc.
- Invalid: "",
+ Empty: "",
PathRoot: "{{root}}",
DollarCrate: "$crate",
Underscore: "_",
@@ -133,6 +133,8 @@
Copy,
Count,
Debug,
+ DebugStruct,
+ DebugTuple,
Decodable,
Decoder,
Default,
@@ -218,6 +220,7 @@
abi,
abi_amdgpu_kernel,
abi_avr_interrupt,
+ abi_c_cmse_nonsecure_call,
abi_efiapi,
abi_msp430_interrupt,
abi_ptx,
@@ -368,6 +371,7 @@
const_fn_transmute,
const_fn_union,
const_generics,
+ const_generics_defaults,
const_if_match,
const_impl_trait,
const_in_array_repeat_expressions,
@@ -380,6 +384,7 @@
const_ptr,
const_raw_ptr_deref,
const_raw_ptr_to_usize_cast,
+ const_refs_to_cell,
const_slice_ptr,
const_trait_bound_opt_out,
const_trait_impl,
@@ -396,6 +401,8 @@
copysignf64,
core,
core_intrinsics,
+ core_panic,
+ core_panic_2015_macro,
core_panic_macro,
cosf32,
cosf64,
@@ -470,6 +477,7 @@
dropck_parametricity,
dylib,
dyn_trait,
+ edition_macro_pats,
eh_catch_typeinfo,
eh_personality,
emit_enum,
@@ -619,6 +627,8 @@
intel,
into_iter,
into_result,
+ into_trait,
+ intra_doc_pointers,
intrinsics,
irrefutable_let_patterns,
isa_attribute,
@@ -713,7 +723,6 @@
more_struct_aliases,
movbe_target_feature,
move_ref_pattern,
- move_val_init,
mul,
mul_assign,
mul_with_overflow,
@@ -791,6 +800,8 @@
owned_box,
packed,
panic,
+ panic_2015,
+ panic_2021,
panic_abort,
panic_bounds_check,
panic_handler,
@@ -808,6 +819,8 @@
partial_ord,
passes,
pat,
+ pat2018,
+ pat2021,
path,
pattern_parentheses,
phantom_data,
@@ -894,6 +907,7 @@
register_attr,
register_tool,
relaxed_adts,
+ relaxed_struct_unsize,
rem,
rem_assign,
repr,
@@ -920,6 +934,7 @@
rust,
rust_2015_preview,
rust_2018_preview,
+ rust_2021_preview,
rust_begin_unwind,
rust_eh_catch_typeinfo,
rust_eh_personality,
@@ -1089,6 +1104,8 @@
staticlib,
std,
std_inject,
+ std_panic,
+ std_panic_2015_macro,
std_panic_macro,
stmt,
stmt_expr_attributes,
@@ -1153,6 +1170,8 @@
truncf32,
truncf64,
try_blocks,
+ try_from_trait,
+ try_into_trait,
try_trait,
tt,
tuple,
@@ -1273,7 +1292,7 @@
#[inline]
pub fn invalid() -> Ident {
- Ident::with_dummy_span(kw::Invalid)
+ Ident::with_dummy_span(kw::Empty)
}
/// Maps a string to an identifier with a dummy span.
@@ -1451,12 +1470,6 @@
with_interner(|interner| interner.intern(string))
}
- /// Access the symbol's chars. This is a slowish operation because it
- /// requires locking the symbol interner.
- pub fn with<F: FnOnce(&str) -> R, R>(self, f: F) -> R {
- with_interner(|interner| f(interner.get(self)))
- }
-
/// Convert to a `SymbolStr`. This is a slowish operation because it
/// requires locking the symbol interner.
pub fn as_str(self) -> SymbolStr {
@@ -1470,7 +1483,7 @@
}
pub fn is_empty(self) -> bool {
- self == kw::Invalid
+ self == kw::Empty
}
/// This method is supposed to be used in error messages, so it's expected to be
@@ -1484,19 +1497,19 @@
impl fmt::Debug for Symbol {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- self.with(|str| fmt::Debug::fmt(&str, f))
+ fmt::Debug::fmt(&self.as_str(), f)
}
}
impl fmt::Display for Symbol {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- self.with(|str| fmt::Display::fmt(&str, f))
+ fmt::Display::fmt(&self.as_str(), f)
}
}
impl<S: Encoder> Encodable<S> for Symbol {
fn encode(&self, s: &mut S) -> Result<(), S::Error> {
- self.with(|string| s.emit_str(string))
+ s.emit_str(&self.as_str())
}
}
@@ -1654,7 +1667,7 @@
/// Returns `true` if this symbol can be a raw identifier.
pub fn can_be_raw(self) -> bool {
- self != kw::Invalid && self != kw::Underscore && !self.is_path_segment_keyword()
+ self != kw::Empty && self != kw::Underscore && !self.is_path_segment_keyword()
}
}
diff --git a/compiler/rustc_symbol_mangling/src/legacy.rs b/compiler/rustc_symbol_mangling/src/legacy.rs
index 6356a7e..b0d5f34 100644
--- a/compiler/rustc_symbol_mangling/src/legacy.rs
+++ b/compiler/rustc_symbol_mangling/src/legacy.rs
@@ -56,7 +56,15 @@
let hash = get_symbol_hash(tcx, instance, instance_ty, instantiating_crate);
let mut printer = SymbolPrinter { tcx, path: SymbolPath::new(), keep_within_component: false }
- .print_def_path(def_id, &[])
+ .print_def_path(
+ def_id,
+ if let ty::InstanceDef::DropGlue(_, _) = instance.def {
+ // Add the name of the dropped type to the symbol name
+ &*instance.substs
+ } else {
+ &[]
+ },
+ )
.unwrap();
if let ty::InstanceDef::VtableShim(..) = instance.def {
diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs
index 7b6e6ad..bbf7ecc 100644
--- a/compiler/rustc_symbol_mangling/src/v0.rs
+++ b/compiler/rustc_symbol_mangling/src/v0.rs
@@ -1,4 +1,3 @@
-use rustc_ast::{FloatTy, IntTy, UintTy};
use rustc_data_structures::base_n;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_hir as hir;
@@ -6,7 +5,7 @@
use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData};
use rustc_middle::ty::print::{Print, Printer};
use rustc_middle::ty::subst::{GenericArg, GenericArgKind, Subst};
-use rustc_middle::ty::{self, Instance, Ty, TyCtxt, TypeFoldable};
+use rustc_middle::ty::{self, FloatTy, Instance, IntTy, Ty, TyCtxt, TypeFoldable, UintTy};
use rustc_target::spec::abi::Abi;
use std::fmt::Write;
@@ -531,7 +530,7 @@
if val < 0 {
neg = true;
}
- Some(val.wrapping_abs() as u128)
+ Some(val.unsigned_abs())
})
}
_ => {
diff --git a/compiler/rustc_target/src/abi/call/aarch64.rs b/compiler/rustc_target/src/abi/call/aarch64.rs
index 1ab7722..a5e985d 100644
--- a/compiler/rustc_target/src/abi/call/aarch64.rs
+++ b/compiler/rustc_target/src/abi/call/aarch64.rs
@@ -40,17 +40,7 @@
let size = ret.layout.size;
let bits = size.bits();
if bits <= 128 {
- let unit = if bits <= 8 {
- Reg::i8()
- } else if bits <= 16 {
- Reg::i16()
- } else if bits <= 32 {
- Reg::i32()
- } else {
- Reg::i64()
- };
-
- ret.cast_to(Uniform { unit, total: size });
+ ret.cast_to(Uniform { unit: Reg::i64(), total: size });
return;
}
ret.make_indirect();
@@ -72,17 +62,7 @@
let size = arg.layout.size;
let bits = size.bits();
if bits <= 128 {
- let unit = if bits <= 8 {
- Reg::i8()
- } else if bits <= 16 {
- Reg::i16()
- } else if bits <= 32 {
- Reg::i32()
- } else {
- Reg::i64()
- };
-
- arg.cast_to(Uniform { unit, total: size });
+ arg.cast_to(Uniform { unit: Reg::i64(), total: size });
return;
}
arg.make_indirect();
diff --git a/compiler/rustc_target/src/abi/call/arm.rs b/compiler/rustc_target/src/abi/call/arm.rs
index 26fed3b..b560e11 100644
--- a/compiler/rustc_target/src/abi/call/arm.rs
+++ b/compiler/rustc_target/src/abi/call/arm.rs
@@ -45,14 +45,7 @@
let size = ret.layout.size;
let bits = size.bits();
if bits <= 32 {
- let unit = if bits <= 8 {
- Reg::i8()
- } else if bits <= 16 {
- Reg::i16()
- } else {
- Reg::i32()
- };
- ret.cast_to(Uniform { unit, total: size });
+ ret.cast_to(Uniform { unit: Reg::i32(), total: size });
return;
}
ret.make_indirect();
diff --git a/compiler/rustc_target/src/abi/call/mod.rs b/compiler/rustc_target/src/abi/call/mod.rs
index 5de9a8d..9c49922 100644
--- a/compiler/rustc_target/src/abi/call/mod.rs
+++ b/compiler/rustc_target/src/abi/call/mod.rs
@@ -27,10 +27,16 @@
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum PassMode {
/// Ignore the argument.
+ ///
+ /// The argument is either uninhabited or a ZST.
Ignore,
/// Pass the argument directly.
+ ///
+ /// The argument has a layout abi of `Scalar`, `Vector` or in rare cases `Aggregate`.
Direct(ArgAttributes),
/// Pass a pair's elements directly in two arguments.
+ ///
+ /// The argument has a layout abi of `ScalarPair`.
Pair(ArgAttributes, ArgAttributes),
/// Pass the argument after casting it, to either
/// a single uniform or a pair of registers.
@@ -97,7 +103,12 @@
}
pub fn ext(&mut self, ext: ArgExtension) -> &mut Self {
- assert!(self.arg_ext == ArgExtension::None || self.arg_ext == ext);
+ assert!(
+ self.arg_ext == ArgExtension::None || self.arg_ext == ext,
+ "cannot set {:?} when {:?} is already set",
+ ext,
+ self.arg_ext
+ );
self.arg_ext = ext;
self
}
@@ -434,28 +445,49 @@
}
impl<'a, Ty> ArgAbi<'a, Ty> {
- pub fn new(layout: TyAndLayout<'a, Ty>) -> Self {
- ArgAbi { layout, pad: None, mode: PassMode::Direct(ArgAttributes::new()) }
+ pub fn new(
+ cx: &impl HasDataLayout,
+ layout: TyAndLayout<'a, Ty>,
+ scalar_attrs: impl Fn(&TyAndLayout<'a, Ty>, &abi::Scalar, Size) -> ArgAttributes,
+ ) -> Self {
+ let mode = match &layout.abi {
+ Abi::Uninhabited => PassMode::Ignore,
+ Abi::Scalar(scalar) => PassMode::Direct(scalar_attrs(&layout, scalar, Size::ZERO)),
+ Abi::ScalarPair(a, b) => PassMode::Pair(
+ scalar_attrs(&layout, a, Size::ZERO),
+ scalar_attrs(&layout, b, a.value.size(cx).align_to(b.value.align(cx).abi)),
+ ),
+ Abi::Vector { .. } => PassMode::Direct(ArgAttributes::new()),
+ Abi::Aggregate { .. } => PassMode::Direct(ArgAttributes::new()),
+ };
+ ArgAbi { layout, pad: None, mode }
}
- pub fn make_indirect(&mut self) {
- assert_eq!(self.mode, PassMode::Direct(ArgAttributes::new()));
-
- // Start with fresh attributes for the pointer.
+ fn indirect_pass_mode(layout: &TyAndLayout<'a, Ty>) -> PassMode {
let mut attrs = ArgAttributes::new();
// For non-immediate arguments the callee gets its own copy of
// the value on the stack, so there are no aliases. It's also
// program-invisible so can't possibly capture
attrs.set(ArgAttribute::NoAlias).set(ArgAttribute::NoCapture).set(ArgAttribute::NonNull);
- attrs.pointee_size = self.layout.size;
+ attrs.pointee_size = layout.size;
// FIXME(eddyb) We should be doing this, but at least on
// i686-pc-windows-msvc, it results in wrong stack offsets.
- // attrs.pointee_align = Some(self.layout.align.abi);
+ // attrs.pointee_align = Some(layout.align.abi);
- let extra_attrs = self.layout.is_unsized().then_some(ArgAttributes::new());
+ let extra_attrs = layout.is_unsized().then_some(ArgAttributes::new());
- self.mode = PassMode::Indirect { attrs, extra_attrs, on_stack: false };
+ PassMode::Indirect { attrs, extra_attrs, on_stack: false }
+ }
+
+ pub fn make_indirect(&mut self) {
+ match self.mode {
+ PassMode::Direct(_) | PassMode::Pair(_, _) => {}
+ PassMode::Indirect { attrs: _, extra_attrs: None, on_stack: false } => return,
+ _ => panic!("Tried to make {:?} indirect", self.mode),
+ }
+
+ self.mode = Self::indirect_pass_mode(&self.layout);
}
pub fn make_indirect_byval(&mut self) {
@@ -486,7 +518,6 @@
}
pub fn cast_to<T: Into<CastTarget>>(&mut self, target: T) {
- assert_eq!(self.mode, PassMode::Direct(ArgAttributes::new()));
self.mode = PassMode::Cast(target.into());
}
@@ -495,7 +526,7 @@
}
pub fn is_indirect(&self) -> bool {
- matches!(self.mode, PassMode::Indirect {..})
+ matches!(self.mode, PassMode::Indirect { .. })
}
pub fn is_sized_indirect(&self) -> bool {
@@ -520,6 +551,7 @@
// Target-specific calling conventions.
ArmAapcs,
+ CCmseNonSecureCall,
Msp430Intr,
@@ -605,10 +637,11 @@
"nvptx64" => nvptx64::compute_abi_info(self),
"hexagon" => hexagon::compute_abi_info(self),
"riscv32" | "riscv64" => riscv::compute_abi_info(cx, self),
- "wasm32" if cx.target_spec().os != "emscripten" => {
- wasm32_bindgen_compat::compute_abi_info(self)
- }
- "wasm32" | "asmjs" => wasm32::compute_abi_info(cx, self),
+ "wasm32" => match cx.target_spec().os.as_str() {
+ "emscripten" | "wasi" => wasm32::compute_abi_info(cx, self),
+ _ => wasm32_bindgen_compat::compute_abi_info(self),
+ },
+ "asmjs" => wasm32::compute_abi_info(cx, self),
a => return Err(format!("unrecognized arch \"{}\" in target specification", a)),
}
diff --git a/compiler/rustc_target/src/abi/mod.rs b/compiler/rustc_target/src/abi/mod.rs
index a43080b..b14b1ef 100644
--- a/compiler/rustc_target/src/abi/mod.rs
+++ b/compiler/rustc_target/src/abi/mod.rs
@@ -4,11 +4,14 @@
use crate::spec::Target;
use std::convert::{TryFrom, TryInto};
+use std::fmt;
use std::num::NonZeroUsize;
use std::ops::{Add, AddAssign, Deref, Mul, Range, RangeInclusive, Sub};
+use std::str::FromStr;
use rustc_index::vec::{Idx, IndexVec};
use rustc_macros::HashStable_Generic;
+use rustc_serialize::json::{Json, ToJson};
use rustc_span::Span;
pub mod call;
@@ -152,22 +155,19 @@
}
// Perform consistency checks against the Target information.
- let endian_str = match dl.endian {
- Endian::Little => "little",
- Endian::Big => "big",
- };
- if endian_str != target.endian {
+ if dl.endian != target.endian {
return Err(format!(
"inconsistent target specification: \"data-layout\" claims \
- architecture is {}-endian, while \"target-endian\" is `{}`",
- endian_str, target.endian
+ architecture is {}-endian, while \"target-endian\" is `{}`",
+ dl.endian.as_str(),
+ target.endian.as_str(),
));
}
if dl.pointer_size.bits() != target.pointer_width.into() {
return Err(format!(
"inconsistent target specification: \"data-layout\" claims \
- pointers are {}-bit, while \"target-pointer-width\" is `{}`",
+ pointers are {}-bit, while \"target-pointer-width\" is `{}`",
dl.pointer_size.bits(),
target.pointer_width
));
@@ -234,26 +234,75 @@
Big,
}
+impl Endian {
+ pub fn as_str(&self) -> &'static str {
+ match self {
+ Self::Little => "little",
+ Self::Big => "big",
+ }
+ }
+}
+
+impl fmt::Debug for Endian {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.write_str(self.as_str())
+ }
+}
+
+impl FromStr for Endian {
+ type Err = String;
+
+ fn from_str(s: &str) -> Result<Self, Self::Err> {
+ match s {
+ "little" => Ok(Self::Little),
+ "big" => Ok(Self::Big),
+ _ => Err(format!(r#"unknown endian: "{}""#, s)),
+ }
+ }
+}
+
+impl ToJson for Endian {
+ fn to_json(&self) -> Json {
+ self.as_str().to_json()
+ }
+}
+
/// Size of a type in bytes.
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Encodable, Decodable)]
#[derive(HashStable_Generic)]
pub struct Size {
+ // The top 3 bits are ALWAYS zero.
raw: u64,
}
impl Size {
pub const ZERO: Size = Size { raw: 0 };
- #[inline]
+ /// Rounds `bits` up to the next-higher byte boundary, if `bits` is
+ /// is not aligned.
pub fn from_bits(bits: impl TryInto<u64>) -> Size {
let bits = bits.try_into().ok().unwrap();
+
+ #[cold]
+ fn overflow(bits: u64) -> ! {
+ panic!("Size::from_bits({}) has overflowed", bits);
+ }
+
+ // This is the largest value of `bits` that does not cause overflow
+ // during rounding, and guarantees that the resulting number of bytes
+ // cannot cause overflow when multiplied by 8.
+ if bits > 0xffff_ffff_ffff_fff8 {
+ overflow(bits);
+ }
+
// Avoid potential overflow from `bits + 7`.
- Size::from_bytes(bits / 8 + ((bits % 8) + 7) / 8)
+ Size { raw: bits / 8 + ((bits % 8) + 7) / 8 }
}
#[inline]
pub fn from_bytes(bytes: impl TryInto<u64>) -> Size {
- Size { raw: bytes.try_into().ok().unwrap() }
+ let bytes: u64 = bytes.try_into().ok().unwrap();
+ Size { raw: bytes }
}
#[inline]
@@ -268,9 +317,7 @@
#[inline]
pub fn bits(self) -> u64 {
- self.bytes().checked_mul(8).unwrap_or_else(|| {
- panic!("Size::bits: {} bytes in bits doesn't fit in u64", self.bytes())
- })
+ self.raw << 3
}
#[inline]
@@ -394,16 +441,28 @@
}
impl Align {
+ #[inline]
pub fn from_bits(bits: u64) -> Result<Align, String> {
Align::from_bytes(Size::from_bits(bits).bytes())
}
+ #[inline]
pub fn from_bytes(align: u64) -> Result<Align, String> {
// Treat an alignment of 0 bytes like 1-byte alignment.
if align == 0 {
return Ok(Align { pow2: 0 });
}
+ #[cold]
+ fn not_power_of_2(align: u64) -> String {
+ format!("`{}` is not a power of 2", align)
+ }
+
+ #[cold]
+ fn too_large(align: u64) -> String {
+ format!("`{}` is too large", align)
+ }
+
let mut bytes = align;
let mut pow2: u8 = 0;
while (bytes & 1) == 0 {
@@ -411,19 +470,21 @@
bytes >>= 1;
}
if bytes != 1 {
- return Err(format!("`{}` is not a power of 2", align));
+ return Err(not_power_of_2(align));
}
if pow2 > 29 {
- return Err(format!("`{}` is too large", align));
+ return Err(too_large(align));
}
Ok(Align { pow2 })
}
+ #[inline]
pub fn bytes(self) -> u64 {
1 << self.pow2
}
+ #[inline]
pub fn bits(self) -> u64 {
self.bytes() * 8
}
@@ -432,12 +493,14 @@
/// (the largest power of two that the offset is a multiple of).
///
/// N.B., for an offset of `0`, this happens to return `2^64`.
+ #[inline]
pub fn max_for_offset(offset: Size) -> Align {
Align { pow2: offset.bytes().trailing_zeros() as u8 }
}
/// Lower the alignment, if necessary, such that the given offset
/// is aligned to it (the offset is a multiple of the alignment).
+ #[inline]
pub fn restrict_for_offset(self, offset: Size) -> Align {
self.min(Align::max_for_offset(offset))
}
@@ -619,7 +682,7 @@
impl Scalar {
pub fn is_bool(&self) -> bool {
- if let Int(I8, _) = self.value { self.valid_range == (0..=1) } else { false }
+ matches!(self.value, Int(I8, false)) && self.valid_range == (0..=1)
}
/// Returns the valid range as a `x..y` range.
diff --git a/compiler/rustc_target/src/spec/aarch64_be_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/aarch64_be_unknown_linux_gnu.rs
new file mode 100644
index 0000000..192c466
--- /dev/null
+++ b/compiler/rustc_target/src/spec/aarch64_be_unknown_linux_gnu.rs
@@ -0,0 +1,20 @@
+use crate::abi::Endian;
+use crate::spec::{Target, TargetOptions};
+
+pub fn target() -> Target {
+ let mut base = super::linux_gnu_base::opts();
+ base.max_atomic_width = Some(128);
+
+ Target {
+ llvm_target: "aarch64_be-unknown-linux-gnu".to_string(),
+ pointer_width: 64,
+ data_layout: "E-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".to_string(),
+ arch: "aarch64".to_string(),
+ options: TargetOptions {
+ unsupported_abis: super::arm_base::unsupported_abis(),
+ mcount: "\u{1}_mcount".to_string(),
+ endian: Endian::Big,
+ ..base
+ },
+ }
+}
diff --git a/compiler/rustc_target/src/spec/aarch64_be_unknown_linux_gnu_ilp32.rs b/compiler/rustc_target/src/spec/aarch64_be_unknown_linux_gnu_ilp32.rs
new file mode 100644
index 0000000..5b9e9c9
--- /dev/null
+++ b/compiler/rustc_target/src/spec/aarch64_be_unknown_linux_gnu_ilp32.rs
@@ -0,0 +1,20 @@
+use crate::abi::Endian;
+use crate::spec::{Target, TargetOptions};
+
+pub fn target() -> Target {
+ let mut base = super::linux_gnu_base::opts();
+ base.max_atomic_width = Some(128);
+
+ Target {
+ llvm_target: "aarch64_be-unknown-linux-gnu_ilp32".to_string(),
+ pointer_width: 32,
+ data_layout: "E-m:e-p:32:32-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".to_string(),
+ arch: "aarch64".to_string(),
+ options: TargetOptions {
+ unsupported_abis: super::arm_base::unsupported_abis(),
+ mcount: "\u{1}_mcount".to_string(),
+ endian: Endian::Big,
+ ..base
+ },
+ }
+}
diff --git a/compiler/rustc_target/src/spec/aarch64_unknown_linux_gnu_ilp32.rs b/compiler/rustc_target/src/spec/aarch64_unknown_linux_gnu_ilp32.rs
new file mode 100644
index 0000000..f2d7576
--- /dev/null
+++ b/compiler/rustc_target/src/spec/aarch64_unknown_linux_gnu_ilp32.rs
@@ -0,0 +1,18 @@
+use crate::spec::{Target, TargetOptions};
+
+pub fn target() -> Target {
+ let mut base = super::linux_gnu_base::opts();
+ base.max_atomic_width = Some(128);
+
+ Target {
+ llvm_target: "aarch64-unknown-linux-gnu_ilp32".to_string(),
+ pointer_width: 32,
+ data_layout: "e-m:e-p:32:32-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".to_string(),
+ arch: "aarch64".to_string(),
+ options: TargetOptions {
+ unsupported_abis: super::arm_base::unsupported_abis(),
+ mcount: "\u{1}_mcount".to_string(),
+ ..base
+ },
+ }
+}
diff --git a/compiler/rustc_target/src/spec/abi.rs b/compiler/rustc_target/src/spec/abi.rs
index 1e45739..65e8a4e 100644
--- a/compiler/rustc_target/src/spec/abi.rs
+++ b/compiler/rustc_target/src/spec/abi.rs
@@ -36,6 +36,7 @@
EfiApi,
AvrInterrupt,
AvrNonBlockingInterrupt,
+ CCmseNonSecureCall,
// Multiplatform / generic ABIs
System,
@@ -81,6 +82,7 @@
name: "avr-non-blocking-interrupt",
generic: false,
},
+ AbiData { abi: Abi::CCmseNonSecureCall, name: "C-cmse-nonsecure-call", generic: false },
// Cross-platform ABIs
AbiData { abi: Abi::System, name: "system", generic: true },
AbiData { abi: Abi::RustIntrinsic, name: "rust-intrinsic", generic: true },
diff --git a/compiler/rustc_target/src/spec/apple_base.rs b/compiler/rustc_target/src/spec/apple_base.rs
index 8842239..3b45896 100644
--- a/compiler/rustc_target/src/spec/apple_base.rs
+++ b/compiler/rustc_target/src/spec/apple_base.rs
@@ -1,6 +1,6 @@
use std::env;
-use crate::spec::{LinkArgs, TargetOptions};
+use crate::spec::{LinkArgs, SplitDebuginfo, TargetOptions};
pub fn opts(os: &str) -> TargetOptions {
// ELF TLS is only available in macOS 10.7+. If you try to compile for 10.6
@@ -36,6 +36,10 @@
emit_debug_gdb_scripts: false,
eh_frame_header: false,
+ // The historical default for macOS targets is to run `dsymutil` which
+ // generates a packed version of debuginfo split from the main file.
+ split_debuginfo: SplitDebuginfo::Packed,
+
// This environment variable is pretty magical but is intended for
// producing deterministic builds. This was first discovered to be used
// by the `ar` tool as a way to control whether or not mtime entries in
diff --git a/compiler/rustc_target/src/spec/armebv7r_none_eabi.rs b/compiler/rustc_target/src/spec/armebv7r_none_eabi.rs
index c6586b7..255740c 100644
--- a/compiler/rustc_target/src/spec/armebv7r_none_eabi.rs
+++ b/compiler/rustc_target/src/spec/armebv7r_none_eabi.rs
@@ -1,5 +1,6 @@
// Targets the Big endian Cortex-R4/R5 processor (ARMv7-R)
+use crate::abi::Endian;
use crate::spec::{LinkerFlavor, LldFlavor, PanicStrategy, RelocModel};
use crate::spec::{Target, TargetOptions};
@@ -11,7 +12,7 @@
arch: "arm".to_string(),
options: TargetOptions {
- endian: "big".to_string(),
+ endian: Endian::Big,
linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
executables: true,
linker: Some("rust-lld".to_owned()),
diff --git a/compiler/rustc_target/src/spec/armebv7r_none_eabihf.rs b/compiler/rustc_target/src/spec/armebv7r_none_eabihf.rs
index e3d4397..eb82e4d 100644
--- a/compiler/rustc_target/src/spec/armebv7r_none_eabihf.rs
+++ b/compiler/rustc_target/src/spec/armebv7r_none_eabihf.rs
@@ -1,5 +1,6 @@
// Targets the Cortex-R4F/R5F processor (ARMv7-R)
+use crate::abi::Endian;
use crate::spec::{LinkerFlavor, LldFlavor, PanicStrategy, RelocModel};
use crate::spec::{Target, TargetOptions};
@@ -11,7 +12,7 @@
arch: "arm".to_string(),
options: TargetOptions {
- endian: "big".to_string(),
+ endian: Endian::Big,
linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
executables: true,
linker: Some("rust-lld".to_owned()),
diff --git a/compiler/rustc_target/src/spec/crt_objects.rs b/compiler/rustc_target/src/spec/crt_objects.rs
index 76c0bf4..32da16a 100644
--- a/compiler/rustc_target/src/spec/crt_objects.rs
+++ b/compiler/rustc_target/src/spec/crt_objects.rs
@@ -5,15 +5,16 @@
//! The `crtx` ones are generally distributed with libc and the `begin/end` ones with gcc.
//! See <https://dev.gentoo.org/~vapier/crt.txt> for some more details.
//!
-//! | Pre-link CRT objects | glibc | musl | bionic | mingw | wasi |
-//! |----------------------|------------------------|------------------------|------------------|-------------------|------|
-//! | dynamic-nopic-exe | crt1, crti, crtbegin | crt1, crti, crtbegin | crtbegin_dynamic | crt2, crtbegin | crt1 |
-//! | dynamic-pic-exe | Scrt1, crti, crtbeginS | Scrt1, crti, crtbeginS | crtbegin_dynamic | crt2, crtbegin | crt1 |
-//! | static-nopic-exe | crt1, crti, crtbeginT | crt1, crti, crtbegin | crtbegin_static | crt2, crtbegin | crt1 |
-//! | static-pic-exe | rcrt1, crti, crtbeginS | rcrt1, crti, crtbeginS | crtbegin_dynamic | crt2, crtbegin | crt1 |
-//! | dynamic-dylib | crti, crtbeginS | crti, crtbeginS | crtbegin_so | dllcrt2, crtbegin | - |
-//! | static-dylib (gcc) | crti, crtbeginT | crti, crtbeginS | crtbegin_so | dllcrt2, crtbegin | - |
-//! | static-dylib (clang) | crti, crtbeginT | N/A | crtbegin_static | dllcrt2, crtbegin | - |
+//! | Pre-link CRT objects | glibc | musl | bionic | mingw | wasi |
+//! |----------------------|------------------------|------------------------|------------------|-------------------|--------------|
+//! | dynamic-nopic-exe | crt1, crti, crtbegin | crt1, crti, crtbegin | crtbegin_dynamic | crt2, crtbegin | crt1 |
+//! | dynamic-pic-exe | Scrt1, crti, crtbeginS | Scrt1, crti, crtbeginS | crtbegin_dynamic | crt2, crtbegin | crt1 |
+//! | static-nopic-exe | crt1, crti, crtbeginT | crt1, crti, crtbegin | crtbegin_static | crt2, crtbegin | crt1 |
+//! | static-pic-exe | rcrt1, crti, crtbeginS | rcrt1, crti, crtbeginS | crtbegin_dynamic | crt2, crtbegin | crt1 |
+//! | dynamic-dylib | crti, crtbeginS | crti, crtbeginS | crtbegin_so | dllcrt2, crtbegin | - |
+//! | static-dylib (gcc) | crti, crtbeginT | crti, crtbeginS | crtbegin_so | dllcrt2, crtbegin | - |
+//! | static-dylib (clang) | crti, crtbeginT | N/A | crtbegin_static | dllcrt2, crtbegin | - |
+//! | wasi-reactor-exe | N/A | N/A | N/A | N/A | crt1-reactor |
//!
//! | Post-link CRT objects | glibc | musl | bionic | mingw | wasi |
//! |-----------------------|---------------|---------------|----------------|--------|------|
@@ -105,6 +106,7 @@
(LinkOutputKind::DynamicPicExe, &["crt1.o"]),
(LinkOutputKind::StaticNoPicExe, &["crt1.o"]),
(LinkOutputKind::StaticPicExe, &["crt1.o"]),
+ (LinkOutputKind::WasiReactorExe, &["crt1-reactor.o"]),
])
}
diff --git a/compiler/rustc_target/src/spec/i386_apple_ios.rs b/compiler/rustc_target/src/spec/i386_apple_ios.rs
index 302306e..2f94fbc 100644
--- a/compiler/rustc_target/src/spec/i386_apple_ios.rs
+++ b/compiler/rustc_target/src/spec/i386_apple_ios.rs
@@ -1,5 +1,5 @@
use super::apple_sdk_base::{opts, Arch};
-use crate::spec::{Target, TargetOptions};
+use crate::spec::{StackProbeType, Target, TargetOptions};
pub fn target() -> Target {
let base = opts("ios", Arch::I386);
@@ -10,6 +10,11 @@
f64:32:64-f80:128-n8:16:32-S128"
.to_string(),
arch: "x86".to_string(),
- options: TargetOptions { max_atomic_width: Some(64), stack_probes: true, ..base },
+ options: TargetOptions {
+ max_atomic_width: Some(64),
+ // don't use probe-stack=inline-asm until rust-lang/rust#83139 is resolved.
+ stack_probes: StackProbeType::Call,
+ ..base
+ },
}
}
diff --git a/compiler/rustc_target/src/spec/i386_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/i386_unknown_linux_gnu.rs
new file mode 100644
index 0000000..f329b2d
--- /dev/null
+++ b/compiler/rustc_target/src/spec/i386_unknown_linux_gnu.rs
@@ -0,0 +1,8 @@
+use crate::spec::Target;
+
+pub fn target() -> Target {
+ let mut base = super::i686_unknown_linux_gnu::target();
+ base.cpu = "i386".to_string();
+ base.llvm_target = "i386-unknown-linux-gnu".to_string();
+ base
+}
diff --git a/compiler/rustc_target/src/spec/i486_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/i486_unknown_linux_gnu.rs
new file mode 100644
index 0000000..5d96a55
--- /dev/null
+++ b/compiler/rustc_target/src/spec/i486_unknown_linux_gnu.rs
@@ -0,0 +1,8 @@
+use crate::spec::Target;
+
+pub fn target() -> Target {
+ let mut base = super::i686_unknown_linux_gnu::target();
+ base.cpu = "i486".to_string();
+ base.llvm_target = "i486-unknown-linux-gnu".to_string();
+ base
+}
diff --git a/compiler/rustc_target/src/spec/i686_apple_darwin.rs b/compiler/rustc_target/src/spec/i686_apple_darwin.rs
index 0ab4034..3181308 100644
--- a/compiler/rustc_target/src/spec/i686_apple_darwin.rs
+++ b/compiler/rustc_target/src/spec/i686_apple_darwin.rs
@@ -1,4 +1,4 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions};
+use crate::spec::{LinkerFlavor, StackProbeType, Target, TargetOptions};
pub fn target() -> Target {
let mut base = super::apple_base::opts("macos");
@@ -6,7 +6,8 @@
base.max_atomic_width = Some(64);
base.pre_link_args.insert(LinkerFlavor::Gcc, vec!["-m32".to_string()]);
base.link_env_remove.extend(super::apple_base::macos_link_env_remove());
- base.stack_probes = true;
+ // don't use probe-stack=inline-asm until rust-lang/rust#83139 is resolved.
+ base.stack_probes = StackProbeType::Call;
base.eliminate_frame_pointer = false;
// Clang automatically chooses a more specific target based on
diff --git a/compiler/rustc_target/src/spec/i686_linux_android.rs b/compiler/rustc_target/src/spec/i686_linux_android.rs
index 52059b9..89eb41e 100644
--- a/compiler/rustc_target/src/spec/i686_linux_android.rs
+++ b/compiler/rustc_target/src/spec/i686_linux_android.rs
@@ -1,4 +1,4 @@
-use crate::spec::Target;
+use crate::spec::{StackProbeType, Target};
// See https://developer.android.com/ndk/guides/abis.html#x86
// for target ABI requirements.
@@ -11,7 +11,8 @@
// http://developer.android.com/ndk/guides/abis.html#x86
base.cpu = "pentiumpro".to_string();
base.features = "+mmx,+sse,+sse2,+sse3,+ssse3".to_string();
- base.stack_probes = true;
+ // don't use probe-stack=inline-asm until rust-lang/rust#83139 is resolved.
+ base.stack_probes = StackProbeType::Call;
Target {
llvm_target: "i686-linux-android".to_string(),
diff --git a/compiler/rustc_target/src/spec/i686_unknown_freebsd.rs b/compiler/rustc_target/src/spec/i686_unknown_freebsd.rs
index fc1c860..a8cc099 100644
--- a/compiler/rustc_target/src/spec/i686_unknown_freebsd.rs
+++ b/compiler/rustc_target/src/spec/i686_unknown_freebsd.rs
@@ -1,4 +1,4 @@
-use crate::spec::{LinkerFlavor, Target};
+use crate::spec::{LinkerFlavor, StackProbeType, Target};
pub fn target() -> Target {
let mut base = super::freebsd_base::opts();
@@ -7,7 +7,9 @@
let pre_link_args = base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap();
pre_link_args.push("-m32".to_string());
pre_link_args.push("-Wl,-znotext".to_string());
- base.stack_probes = true;
+
+ // don't use probe-stack=inline-asm until rust-lang/rust#83139 is resolved.
+ base.stack_probes = StackProbeType::Call;
Target {
llvm_target: "i686-unknown-freebsd".to_string(),
diff --git a/compiler/rustc_target/src/spec/i686_unknown_haiku.rs b/compiler/rustc_target/src/spec/i686_unknown_haiku.rs
index 22c8ba5..0807913 100644
--- a/compiler/rustc_target/src/spec/i686_unknown_haiku.rs
+++ b/compiler/rustc_target/src/spec/i686_unknown_haiku.rs
@@ -1,11 +1,12 @@
-use crate::spec::{LinkerFlavor, Target};
+use crate::spec::{LinkerFlavor, StackProbeType, Target};
pub fn target() -> Target {
let mut base = super::haiku_base::opts();
base.cpu = "pentium4".to_string();
base.max_atomic_width = Some(64);
base.pre_link_args.insert(LinkerFlavor::Gcc, vec!["-m32".to_string()]);
- base.stack_probes = true;
+ // don't use probe-stack=inline-asm until rust-lang/rust#83139 is resolved.
+ base.stack_probes = StackProbeType::Call;
Target {
llvm_target: "i686-unknown-haiku".to_string(),
diff --git a/compiler/rustc_target/src/spec/i686_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/i686_unknown_linux_gnu.rs
index 083c115..656136c 100644
--- a/compiler/rustc_target/src/spec/i686_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/i686_unknown_linux_gnu.rs
@@ -1,11 +1,12 @@
-use crate::spec::{LinkerFlavor, Target};
+use crate::spec::{LinkerFlavor, StackProbeType, Target};
pub fn target() -> Target {
let mut base = super::linux_gnu_base::opts();
base.cpu = "pentium4".to_string();
base.max_atomic_width = Some(64);
base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m32".to_string());
- base.stack_probes = true;
+ // don't use probe-stack=inline-asm until rust-lang/rust#83139 is resolved.
+ base.stack_probes = StackProbeType::Call;
Target {
llvm_target: "i686-unknown-linux-gnu".to_string(),
diff --git a/compiler/rustc_target/src/spec/i686_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/i686_unknown_linux_musl.rs
index 1673b2a..cb154b7 100644
--- a/compiler/rustc_target/src/spec/i686_unknown_linux_musl.rs
+++ b/compiler/rustc_target/src/spec/i686_unknown_linux_musl.rs
@@ -1,4 +1,4 @@
-use crate::spec::{LinkerFlavor, Target};
+use crate::spec::{LinkerFlavor, StackProbeType, Target};
pub fn target() -> Target {
let mut base = super::linux_musl_base::opts();
@@ -6,7 +6,8 @@
base.max_atomic_width = Some(64);
base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m32".to_string());
base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-Wl,-melf_i386".to_string());
- base.stack_probes = true;
+ // don't use probe-stack=inline-asm until rust-lang/rust#83139 is resolved.
+ base.stack_probes = StackProbeType::Call;
// The unwinder used by i686-unknown-linux-musl, the LLVM libunwind
// implementation, apparently relies on frame pointers existing... somehow.
diff --git a/compiler/rustc_target/src/spec/i686_unknown_netbsd.rs b/compiler/rustc_target/src/spec/i686_unknown_netbsd.rs
index c22139b..26bdc04 100644
--- a/compiler/rustc_target/src/spec/i686_unknown_netbsd.rs
+++ b/compiler/rustc_target/src/spec/i686_unknown_netbsd.rs
@@ -1,11 +1,12 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions};
+use crate::spec::{LinkerFlavor, StackProbeType, Target, TargetOptions};
pub fn target() -> Target {
let mut base = super::netbsd_base::opts();
base.cpu = "pentium4".to_string();
base.max_atomic_width = Some(64);
base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m32".to_string());
- base.stack_probes = true;
+ // don't use probe-stack=inline-asm until rust-lang/rust#83139 is resolved.
+ base.stack_probes = StackProbeType::Call;
Target {
llvm_target: "i686-unknown-netbsdelf".to_string(),
diff --git a/compiler/rustc_target/src/spec/i686_unknown_openbsd.rs b/compiler/rustc_target/src/spec/i686_unknown_openbsd.rs
index 87642ef..e6a244c 100644
--- a/compiler/rustc_target/src/spec/i686_unknown_openbsd.rs
+++ b/compiler/rustc_target/src/spec/i686_unknown_openbsd.rs
@@ -1,4 +1,4 @@
-use crate::spec::{LinkerFlavor, Target};
+use crate::spec::{LinkerFlavor, StackProbeType, Target};
pub fn target() -> Target {
let mut base = super::openbsd_base::opts();
@@ -6,7 +6,8 @@
base.max_atomic_width = Some(64);
base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m32".to_string());
base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-fuse-ld=lld".to_string());
- base.stack_probes = true;
+ // don't use probe-stack=inline-asm until rust-lang/rust#83139 is resolved.
+ base.stack_probes = StackProbeType::Call;
Target {
llvm_target: "i686-unknown-openbsd".to_string(),
diff --git a/compiler/rustc_target/src/spec/i686_wrs_vxworks.rs b/compiler/rustc_target/src/spec/i686_wrs_vxworks.rs
index c082535..8732b47 100644
--- a/compiler/rustc_target/src/spec/i686_wrs_vxworks.rs
+++ b/compiler/rustc_target/src/spec/i686_wrs_vxworks.rs
@@ -1,11 +1,12 @@
-use crate::spec::{LinkerFlavor, Target};
+use crate::spec::{LinkerFlavor, StackProbeType, Target};
pub fn target() -> Target {
let mut base = super::vxworks_base::opts();
base.cpu = "pentium4".to_string();
base.max_atomic_width = Some(64);
base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m32".to_string());
- base.stack_probes = true;
+ // don't use probe-stack=inline-asm until rust-lang/rust#83139 is resolved.
+ base.stack_probes = StackProbeType::Call;
Target {
llvm_target: "i686-unknown-linux-gnu".to_string(),
diff --git a/compiler/rustc_target/src/spec/linux_kernel_base.rs b/compiler/rustc_target/src/spec/linux_kernel_base.rs
index a5fc164..ddb9a7b 100644
--- a/compiler/rustc_target/src/spec/linux_kernel_base.rs
+++ b/compiler/rustc_target/src/spec/linux_kernel_base.rs
@@ -1,4 +1,6 @@
-use crate::spec::{LinkArgs, LinkerFlavor, PanicStrategy, RelocModel, RelroLevel, TargetOptions};
+use crate::spec::{
+ LinkArgs, LinkerFlavor, PanicStrategy, RelocModel, RelroLevel, StackProbeType, TargetOptions,
+};
pub fn opts() -> TargetOptions {
let mut pre_link_args = LinkArgs::new();
@@ -11,7 +13,8 @@
env: "gnu".to_string(),
disable_redzone: true,
panic_strategy: PanicStrategy::Abort,
- stack_probes: true,
+ // don't use probe-stack=inline-asm until rust-lang/rust#83139 is resolved.
+ stack_probes: StackProbeType::Call,
eliminate_frame_pointer: false,
linker_is_gnu: true,
position_independent_executables: true,
diff --git a/compiler/rustc_target/src/spec/mips64_unknown_linux_gnuabi64.rs b/compiler/rustc_target/src/spec/mips64_unknown_linux_gnuabi64.rs
index daa0d9d..5339853 100644
--- a/compiler/rustc_target/src/spec/mips64_unknown_linux_gnuabi64.rs
+++ b/compiler/rustc_target/src/spec/mips64_unknown_linux_gnuabi64.rs
@@ -1,3 +1,4 @@
+use crate::abi::Endian;
use crate::spec::{Target, TargetOptions};
pub fn target() -> Target {
@@ -7,7 +8,7 @@
data_layout: "E-m:e-i8:8:32-i16:16:32-i64:64-n32:64-S128".to_string(),
arch: "mips64".to_string(),
options: TargetOptions {
- endian: "big".to_string(),
+ endian: Endian::Big,
// NOTE(mips64r2) matches C toolchain
cpu: "mips64r2".to_string(),
features: "+mips64r2".to_string(),
diff --git a/compiler/rustc_target/src/spec/mips64_unknown_linux_muslabi64.rs b/compiler/rustc_target/src/spec/mips64_unknown_linux_muslabi64.rs
index db8d0c0..329fbd2 100644
--- a/compiler/rustc_target/src/spec/mips64_unknown_linux_muslabi64.rs
+++ b/compiler/rustc_target/src/spec/mips64_unknown_linux_muslabi64.rs
@@ -1,3 +1,4 @@
+use crate::abi::Endian;
use crate::spec::{Target, TargetOptions};
pub fn target() -> Target {
@@ -11,6 +12,6 @@
pointer_width: 64,
data_layout: "E-m:e-i8:8:32-i16:16:32-i64:64-n32:64-S128".to_string(),
arch: "mips64".to_string(),
- options: TargetOptions { endian: "big".to_string(), mcount: "_mcount".to_string(), ..base },
+ options: TargetOptions { endian: Endian::Big, mcount: "_mcount".to_string(), ..base },
}
}
diff --git a/compiler/rustc_target/src/spec/mips_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/mips_unknown_linux_gnu.rs
index a7ec1f1..b41b28cb 100644
--- a/compiler/rustc_target/src/spec/mips_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/mips_unknown_linux_gnu.rs
@@ -1,3 +1,4 @@
+use crate::abi::Endian;
use crate::spec::{Target, TargetOptions};
pub fn target() -> Target {
@@ -7,7 +8,7 @@
data_layout: "E-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64".to_string(),
arch: "mips".to_string(),
options: TargetOptions {
- endian: "big".to_string(),
+ endian: Endian::Big,
cpu: "mips32r2".to_string(),
features: "+mips32r2,+fpxx,+nooddspreg".to_string(),
max_atomic_width: Some(32),
diff --git a/compiler/rustc_target/src/spec/mips_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/mips_unknown_linux_musl.rs
index 1ebe577..3713af4 100644
--- a/compiler/rustc_target/src/spec/mips_unknown_linux_musl.rs
+++ b/compiler/rustc_target/src/spec/mips_unknown_linux_musl.rs
@@ -1,3 +1,4 @@
+use crate::abi::Endian;
use crate::spec::{Target, TargetOptions};
pub fn target() -> Target {
@@ -11,6 +12,6 @@
pointer_width: 32,
data_layout: "E-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64".to_string(),
arch: "mips".to_string(),
- options: TargetOptions { endian: "big".to_string(), mcount: "_mcount".to_string(), ..base },
+ options: TargetOptions { endian: Endian::Big, mcount: "_mcount".to_string(), ..base },
}
}
diff --git a/compiler/rustc_target/src/spec/mips_unknown_linux_uclibc.rs b/compiler/rustc_target/src/spec/mips_unknown_linux_uclibc.rs
index 2123d5e..042ec91 100644
--- a/compiler/rustc_target/src/spec/mips_unknown_linux_uclibc.rs
+++ b/compiler/rustc_target/src/spec/mips_unknown_linux_uclibc.rs
@@ -1,3 +1,4 @@
+use crate::abi::Endian;
use crate::spec::{Target, TargetOptions};
pub fn target() -> Target {
@@ -7,7 +8,7 @@
data_layout: "E-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64".to_string(),
arch: "mips".to_string(),
options: TargetOptions {
- endian: "big".to_string(),
+ endian: Endian::Big,
cpu: "mips32r2".to_string(),
features: "+mips32r2,+soft-float".to_string(),
max_atomic_width: Some(32),
diff --git a/compiler/rustc_target/src/spec/mipsisa32r6_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/mipsisa32r6_unknown_linux_gnu.rs
index 11b3734..a81c90f 100644
--- a/compiler/rustc_target/src/spec/mipsisa32r6_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/mipsisa32r6_unknown_linux_gnu.rs
@@ -1,3 +1,4 @@
+use crate::abi::Endian;
use crate::spec::{Target, TargetOptions};
pub fn target() -> Target {
@@ -7,7 +8,7 @@
data_layout: "E-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64".to_string(),
arch: "mips".to_string(),
options: TargetOptions {
- endian: "big".to_string(),
+ endian: Endian::Big,
cpu: "mips32r6".to_string(),
features: "+mips32r6".to_string(),
max_atomic_width: Some(32),
diff --git a/compiler/rustc_target/src/spec/mipsisa64r6_unknown_linux_gnuabi64.rs b/compiler/rustc_target/src/spec/mipsisa64r6_unknown_linux_gnuabi64.rs
index 6282c9e..3bf837f 100644
--- a/compiler/rustc_target/src/spec/mipsisa64r6_unknown_linux_gnuabi64.rs
+++ b/compiler/rustc_target/src/spec/mipsisa64r6_unknown_linux_gnuabi64.rs
@@ -1,3 +1,4 @@
+use crate::abi::Endian;
use crate::spec::{Target, TargetOptions};
pub fn target() -> Target {
@@ -7,7 +8,7 @@
data_layout: "E-m:e-i8:8:32-i16:16:32-i64:64-n32:64-S128".to_string(),
arch: "mips64".to_string(),
options: TargetOptions {
- endian: "big".to_string(),
+ endian: Endian::Big,
// NOTE(mips64r6) matches C toolchain
cpu: "mips64r6".to_string(),
features: "+mips64r6".to_string(),
diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs
index 8d72df6..7a93bac 100644
--- a/compiler/rustc_target/src/spec/mod.rs
+++ b/compiler/rustc_target/src/spec/mod.rs
@@ -34,11 +34,13 @@
//! the target's settings, though `target-feature` and `link-args` will *add*
//! to the list specified by the target, rather than replace.
+use crate::abi::Endian;
use crate::spec::abi::{lookup as lookup_abi, Abi};
use crate::spec::crt_objects::{CrtObjects, CrtObjectsFallback};
use rustc_serialize::json::{Json, ToJson};
use rustc_span::symbol::{sym, Symbol};
use std::collections::BTreeMap;
+use std::convert::TryFrom;
use std::ops::{Deref, DerefMut};
use std::path::{Path, PathBuf};
use std::str::FromStr;
@@ -407,6 +409,8 @@
DynamicDylib,
/// Dynamic library with bundled libc ("statically linked").
StaticDylib,
+ /// WASI module with a lifetime past the _initialize entry point
+ WasiReactorExe,
}
impl LinkOutputKind {
@@ -418,6 +422,7 @@
LinkOutputKind::StaticPicExe => "static-pic-exe",
LinkOutputKind::DynamicDylib => "dynamic-dylib",
LinkOutputKind::StaticDylib => "static-dylib",
+ LinkOutputKind::WasiReactorExe => "wasi-reactor-exe",
}
}
@@ -429,6 +434,7 @@
"static-pic-exe" => LinkOutputKind::StaticPicExe,
"dynamic-dylib" => LinkOutputKind::DynamicDylib,
"static-dylib" => LinkOutputKind::StaticDylib,
+ "wasi-reactor-exe" => LinkOutputKind::WasiReactorExe,
_ => return None,
})
}
@@ -442,6 +448,69 @@
pub type LinkArgs = BTreeMap<LinkerFlavor, Vec<String>>;
+#[derive(Clone, Copy, Hash, Debug, PartialEq, Eq)]
+pub enum SplitDebuginfo {
+ /// Split debug-information is disabled, meaning that on supported platforms
+ /// you can find all debug information in the executable itself. This is
+ /// only supported for ELF effectively.
+ ///
+ /// * Windows - not supported
+ /// * macOS - don't run `dsymutil`
+ /// * ELF - `.dwarf_*` sections
+ Off,
+
+ /// Split debug-information can be found in a "packed" location separate
+ /// from the final artifact. This is supported on all platforms.
+ ///
+ /// * Windows - `*.pdb`
+ /// * macOS - `*.dSYM` (run `dsymutil`)
+ /// * ELF - `*.dwp` (run `rust-llvm-dwp`)
+ Packed,
+
+ /// Split debug-information can be found in individual object files on the
+ /// filesystem. The main executable may point to the object files.
+ ///
+ /// * Windows - not supported
+ /// * macOS - supported, scattered object files
+ /// * ELF - supported, scattered `*.dwo` files
+ Unpacked,
+}
+
+impl SplitDebuginfo {
+ fn as_str(&self) -> &'static str {
+ match self {
+ SplitDebuginfo::Off => "off",
+ SplitDebuginfo::Packed => "packed",
+ SplitDebuginfo::Unpacked => "unpacked",
+ }
+ }
+}
+
+impl FromStr for SplitDebuginfo {
+ type Err = ();
+
+ fn from_str(s: &str) -> Result<SplitDebuginfo, ()> {
+ Ok(match s {
+ "off" => SplitDebuginfo::Off,
+ "unpacked" => SplitDebuginfo::Unpacked,
+ "packed" => SplitDebuginfo::Packed,
+ _ => return Err(()),
+ })
+ }
+}
+
+impl ToJson for SplitDebuginfo {
+ fn to_json(&self) -> Json {
+ self.as_str().to_json()
+ }
+}
+
+impl fmt::Display for SplitDebuginfo {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.write_str(self.as_str())
+ }
+}
+
macro_rules! supported_targets {
( $(($( $triple:literal, )+ $module:ident ),)+ ) => {
$(mod $module;)+
@@ -474,6 +543,83 @@
};
}
+#[derive(Clone, Debug, PartialEq, Eq)]
+pub enum StackProbeType {
+ /// Don't emit any stack probes.
+ None,
+ /// It is harmless to use this option even on targets that do not have backend support for
+ /// stack probes as the failure mode is the same as if no stack-probe option was specified in
+ /// the first place.
+ Inline,
+ /// Call `__rust_probestack` whenever stack needs to be probed.
+ Call,
+ /// Use inline option for LLVM versions later than specified in `min_llvm_version_for_inline`
+ /// and call `__rust_probestack` otherwise.
+ InlineOrCall { min_llvm_version_for_inline: (u32, u32, u32) },
+}
+
+impl StackProbeType {
+ fn from_json(json: &Json) -> Result<Self, String> {
+ let object = json.as_object().ok_or_else(|| "expected a JSON object")?;
+ let kind = object
+ .get("kind")
+ .and_then(|o| o.as_string())
+ .ok_or_else(|| "expected `kind` to be a string")?;
+ match kind {
+ "none" => Ok(StackProbeType::None),
+ "inline" => Ok(StackProbeType::Inline),
+ "call" => Ok(StackProbeType::Call),
+ "inline-or-call" => {
+ let min_version = object
+ .get("min-llvm-version-for-inline")
+ .and_then(|o| o.as_array())
+ .ok_or_else(|| "expected `min-llvm-version-for-inline` to be an array")?;
+ let mut iter = min_version.into_iter().map(|v| {
+ let int = v.as_u64().ok_or_else(
+ || "expected `min-llvm-version-for-inline` values to be integers",
+ )?;
+ u32::try_from(int)
+ .map_err(|_| "`min-llvm-version-for-inline` values don't convert to u32")
+ });
+ let min_llvm_version_for_inline = (
+ iter.next().unwrap_or(Ok(11))?,
+ iter.next().unwrap_or(Ok(0))?,
+ iter.next().unwrap_or(Ok(0))?,
+ );
+ Ok(StackProbeType::InlineOrCall { min_llvm_version_for_inline })
+ }
+ _ => Err(String::from(
+ "`kind` expected to be one of `inline-or-none`, `call` or `inline-or-call`",
+ )),
+ }
+ }
+}
+
+impl ToJson for StackProbeType {
+ fn to_json(&self) -> Json {
+ Json::Object(match self {
+ StackProbeType::None => {
+ vec![(String::from("kind"), "none".to_json())].into_iter().collect()
+ }
+ StackProbeType::Inline => {
+ vec![(String::from("kind"), "inline".to_json())].into_iter().collect()
+ }
+ StackProbeType::Call => {
+ vec![(String::from("kind"), "call".to_json())].into_iter().collect()
+ }
+ StackProbeType::InlineOrCall { min_llvm_version_for_inline } => vec![
+ (String::from("kind"), "inline-or-call".to_json()),
+ (
+ String::from("min-llvm-version-for-inline"),
+ min_llvm_version_for_inline.to_json(),
+ ),
+ ]
+ .into_iter()
+ .collect(),
+ })
+ }
+}
+
supported_targets! {
("x86_64-unknown-linux-gnu", x86_64_unknown_linux_gnu),
("x86_64-unknown-linux-gnux32", x86_64_unknown_linux_gnux32),
@@ -662,6 +808,10 @@
("mipsel-sony-psp", mipsel_sony_psp),
("mipsel-unknown-none", mipsel_unknown_none),
("thumbv4t-none-eabi", thumbv4t_none_eabi),
+
+ ("aarch64_be-unknown-linux-gnu", aarch64_be_unknown_linux_gnu),
+ ("aarch64-unknown-linux-gnu_ilp32", aarch64_unknown_linux_gnu_ilp32),
+ ("aarch64_be-unknown-linux-gnu_ilp32", aarch64_be_unknown_linux_gnu_ilp32),
}
/// Everything `rustc` knows about how to compile for a specific target.
@@ -705,8 +855,8 @@
/// Whether the target is built-in or loaded from a custom target specification.
pub is_builtin: bool,
- /// String to use as the `target_endian` `cfg` variable. Defaults to "little".
- pub endian: String,
+ /// Used as the `target_endian` `cfg` variable. Defaults to little endian.
+ pub endian: Endian,
/// Width of c_int type. Defaults to "32".
pub c_int_width: String,
/// OS name to use for conditional compilation (`target_os`). Defaults to "none".
@@ -921,8 +1071,8 @@
/// Whether or not crt-static is respected by the compiler (or is a no-op).
pub crt_static_respected: bool,
- /// Whether or not stack probes (__rust_probestack) are enabled
- pub stack_probes: bool,
+ /// The implementation of stack probes to use.
+ pub stack_probes: StackProbeType,
/// The minimum alignment for global symbols.
pub min_global_align: Option<u64>,
@@ -1002,6 +1152,10 @@
/// Is true if the target is an ARM architecture using thumb v1 which allows for
/// thumb and arm interworking.
pub has_thumb_interworking: bool,
+
+ /// How to handle split debug information, if at all. Specifying `None` has
+ /// target-specific meaning.
+ pub split_debuginfo: SplitDebuginfo,
}
impl Default for TargetOptions {
@@ -1010,7 +1164,7 @@
fn default() -> TargetOptions {
TargetOptions {
is_builtin: false,
- endian: "little".to_string(),
+ endian: Endian::Little,
c_int_width: "32".to_string(),
os: "none".to_string(),
env: String::new(),
@@ -1080,7 +1234,7 @@
crt_static_allows_dylibs: false,
crt_static_default: false,
crt_static_respected: false,
- stack_probes: false,
+ stack_probes: StackProbeType::None,
min_global_align: None,
default_codegen_units: None,
trap_unreachable: true,
@@ -1101,6 +1255,7 @@
use_ctors_section: false,
eh_frame_header: true,
has_thumb_interworking: false,
+ split_debuginfo: SplitDebuginfo::Off,
}
}
}
@@ -1299,6 +1454,18 @@
Some(Ok(()))
})).unwrap_or(Ok(()))
} );
+ ($key_name:ident, SplitDebuginfo) => ( {
+ let name = (stringify!($key_name)).replace("_", "-");
+ obj.find(&name[..]).and_then(|o| o.as_string().and_then(|s| {
+ match s.parse::<SplitDebuginfo>() {
+ Ok(level) => base.$key_name = level,
+ _ => return Some(Err(format!("'{}' is not a valid value for \
+ split-debuginfo. Use 'off' or 'dsymutil'.",
+ s))),
+ }
+ Some(Ok(()))
+ })).unwrap_or(Ok(()))
+ } );
($key_name:ident, list) => ( {
let name = (stringify!($key_name)).replace("_", "-");
if let Some(v) = obj.find(&name).and_then(Json::as_array) {
@@ -1356,6 +1523,18 @@
Some(Ok(()))
})).unwrap_or(Ok(()))
} );
+ ($key_name:ident, StackProbeType) => ( {
+ let name = (stringify!($key_name)).replace("_", "-");
+ obj.find(&name[..]).and_then(|o| match StackProbeType::from_json(o) {
+ Ok(v) => {
+ base.$key_name = v;
+ Some(Ok(()))
+ },
+ Err(s) => Some(Err(
+ format!("`{:?}` is not a valid value for `{}`: {}", o, name, s)
+ )),
+ }).unwrap_or(Ok(()))
+ } );
($key_name:ident, crt_objects_fallback) => ( {
let name = (stringify!($key_name)).replace("_", "-");
obj.find(&name[..]).and_then(|o| o.as_string().and_then(|s| {
@@ -1377,7 +1556,7 @@
let kind = LinkOutputKind::from_str(&k).ok_or_else(|| {
format!("{}: '{}' is not a valid value for CRT object kind. \
Use '(dynamic,static)-(nopic,pic)-exe' or \
- '(dynamic,static)-dylib'", name, k)
+ '(dynamic,static)-dylib' or 'wasi-reactor-exe'", name, k)
})?;
let v = v.as_array().ok_or_else(||
@@ -1439,8 +1618,10 @@
} );
}
+ if let Some(s) = obj.find("target-endian").and_then(Json::as_string) {
+ base.endian = s.parse()?;
+ }
key!(is_builtin, bool);
- key!(endian = "target-endian");
key!(c_int_width = "target-c-int-width");
key!(os);
key!(env);
@@ -1509,7 +1690,7 @@
key!(crt_static_allows_dylibs, bool);
key!(crt_static_default, bool);
key!(crt_static_respected, bool);
- key!(stack_probes, bool);
+ key!(stack_probes, StackProbeType)?;
key!(min_global_align, Option<u64>);
key!(default_codegen_units, Option<u64>);
key!(trap_unreachable, bool);
@@ -1530,6 +1711,7 @@
key!(use_ctors_section, bool);
key!(eh_frame_header, bool);
key!(has_thumb_interworking, bool);
+ key!(split_debuginfo, SplitDebuginfo)?;
// NB: The old name is deprecated, but support for it is retained for
// compatibility.
@@ -1765,6 +1947,7 @@
target_option_val!(use_ctors_section);
target_option_val!(eh_frame_header);
target_option_val!(has_thumb_interworking);
+ target_option_val!(split_debuginfo);
if default.unsupported_abis != self.unsupported_abis {
d.insert(
diff --git a/compiler/rustc_target/src/spec/msvc_base.rs b/compiler/rustc_target/src/spec/msvc_base.rs
index 8cd6735..39c0d5f 100644
--- a/compiler/rustc_target/src/spec/msvc_base.rs
+++ b/compiler/rustc_target/src/spec/msvc_base.rs
@@ -1,4 +1,4 @@
-use crate::spec::{LinkArgs, LinkerFlavor, LldFlavor, TargetOptions};
+use crate::spec::{LinkArgs, LinkerFlavor, LldFlavor, SplitDebuginfo, TargetOptions};
pub fn opts() -> TargetOptions {
let pre_link_args_msvc = vec![
@@ -27,6 +27,10 @@
abi_return_struct_as_int: true,
emit_debug_gdb_scripts: false,
+ // Currently this is the only supported method of debuginfo on MSVC
+ // where `*.pdb` files show up next to the final artifact.
+ split_debuginfo: SplitDebuginfo::Packed,
+
..Default::default()
}
}
diff --git a/compiler/rustc_target/src/spec/powerpc64_unknown_freebsd.rs b/compiler/rustc_target/src/spec/powerpc64_unknown_freebsd.rs
index 626865a..3dddeb1 100644
--- a/compiler/rustc_target/src/spec/powerpc64_unknown_freebsd.rs
+++ b/compiler/rustc_target/src/spec/powerpc64_unknown_freebsd.rs
@@ -1,3 +1,4 @@
+use crate::abi::Endian;
use crate::spec::{LinkerFlavor, Target, TargetOptions};
pub fn target() -> Target {
@@ -11,6 +12,6 @@
pointer_width: 64,
data_layout: "E-m:e-i64:64-n32:64".to_string(),
arch: "powerpc64".to_string(),
- options: TargetOptions { endian: "big".to_string(), mcount: "_mcount".to_string(), ..base },
+ options: TargetOptions { endian: Endian::Big, mcount: "_mcount".to_string(), ..base },
}
}
diff --git a/compiler/rustc_target/src/spec/powerpc64_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/powerpc64_unknown_linux_gnu.rs
index 0332281..751022c 100644
--- a/compiler/rustc_target/src/spec/powerpc64_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/powerpc64_unknown_linux_gnu.rs
@@ -1,3 +1,4 @@
+use crate::abi::Endian;
use crate::spec::{LinkerFlavor, RelroLevel, Target, TargetOptions};
pub fn target() -> Target {
@@ -15,6 +16,6 @@
pointer_width: 64,
data_layout: "E-m:e-i64:64-n32:64".to_string(),
arch: "powerpc64".to_string(),
- options: TargetOptions { endian: "big".to_string(), mcount: "_mcount".to_string(), ..base },
+ options: TargetOptions { endian: Endian::Big, mcount: "_mcount".to_string(), ..base },
}
}
diff --git a/compiler/rustc_target/src/spec/powerpc64_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/powerpc64_unknown_linux_musl.rs
index 2315397..546dfba 100644
--- a/compiler/rustc_target/src/spec/powerpc64_unknown_linux_musl.rs
+++ b/compiler/rustc_target/src/spec/powerpc64_unknown_linux_musl.rs
@@ -1,3 +1,4 @@
+use crate::abi::Endian;
use crate::spec::{LinkerFlavor, Target, TargetOptions};
pub fn target() -> Target {
@@ -11,6 +12,6 @@
pointer_width: 64,
data_layout: "E-m:e-i64:64-n32:64".to_string(),
arch: "powerpc64".to_string(),
- options: TargetOptions { endian: "big".to_string(), mcount: "_mcount".to_string(), ..base },
+ options: TargetOptions { endian: Endian::Big, mcount: "_mcount".to_string(), ..base },
}
}
diff --git a/compiler/rustc_target/src/spec/powerpc64_wrs_vxworks.rs b/compiler/rustc_target/src/spec/powerpc64_wrs_vxworks.rs
index 1c83e3e..bb55872 100644
--- a/compiler/rustc_target/src/spec/powerpc64_wrs_vxworks.rs
+++ b/compiler/rustc_target/src/spec/powerpc64_wrs_vxworks.rs
@@ -1,3 +1,4 @@
+use crate::abi::Endian;
use crate::spec::{LinkerFlavor, Target, TargetOptions};
pub fn target() -> Target {
@@ -11,6 +12,6 @@
pointer_width: 64,
data_layout: "E-m:e-i64:64-n32:64".to_string(),
arch: "powerpc64".to_string(),
- options: TargetOptions { endian: "big".to_string(), ..base },
+ options: TargetOptions { endian: Endian::Big, ..base },
}
}
diff --git a/compiler/rustc_target/src/spec/powerpc_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/powerpc_unknown_linux_gnu.rs
index 3a92712..70dd0b2 100644
--- a/compiler/rustc_target/src/spec/powerpc_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/powerpc_unknown_linux_gnu.rs
@@ -1,3 +1,4 @@
+use crate::abi::Endian;
use crate::spec::{LinkerFlavor, Target, TargetOptions};
pub fn target() -> Target {
@@ -10,6 +11,6 @@
pointer_width: 32,
data_layout: "E-m:e-p:32:32-i64:64-n32".to_string(),
arch: "powerpc".to_string(),
- options: TargetOptions { endian: "big".to_string(), mcount: "_mcount".to_string(), ..base },
+ options: TargetOptions { endian: Endian::Big, mcount: "_mcount".to_string(), ..base },
}
}
diff --git a/compiler/rustc_target/src/spec/powerpc_unknown_linux_gnuspe.rs b/compiler/rustc_target/src/spec/powerpc_unknown_linux_gnuspe.rs
index 105a0b2..66118b7 100644
--- a/compiler/rustc_target/src/spec/powerpc_unknown_linux_gnuspe.rs
+++ b/compiler/rustc_target/src/spec/powerpc_unknown_linux_gnuspe.rs
@@ -1,3 +1,4 @@
+use crate::abi::Endian;
use crate::spec::{LinkerFlavor, Target, TargetOptions};
pub fn target() -> Target {
@@ -10,6 +11,6 @@
pointer_width: 32,
data_layout: "E-m:e-p:32:32-i64:64-n32".to_string(),
arch: "powerpc".to_string(),
- options: TargetOptions { endian: "big".to_string(), mcount: "_mcount".to_string(), ..base },
+ options: TargetOptions { endian: Endian::Big, mcount: "_mcount".to_string(), ..base },
}
}
diff --git a/compiler/rustc_target/src/spec/powerpc_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/powerpc_unknown_linux_musl.rs
index 49d3294..679a3a2 100644
--- a/compiler/rustc_target/src/spec/powerpc_unknown_linux_musl.rs
+++ b/compiler/rustc_target/src/spec/powerpc_unknown_linux_musl.rs
@@ -1,3 +1,4 @@
+use crate::abi::Endian;
use crate::spec::{LinkerFlavor, Target, TargetOptions};
pub fn target() -> Target {
@@ -10,6 +11,6 @@
pointer_width: 32,
data_layout: "E-m:e-p:32:32-i64:64-n32".to_string(),
arch: "powerpc".to_string(),
- options: TargetOptions { endian: "big".to_string(), mcount: "_mcount".to_string(), ..base },
+ options: TargetOptions { endian: Endian::Big, mcount: "_mcount".to_string(), ..base },
}
}
diff --git a/compiler/rustc_target/src/spec/powerpc_unknown_netbsd.rs b/compiler/rustc_target/src/spec/powerpc_unknown_netbsd.rs
index 387d6cd..1245098 100644
--- a/compiler/rustc_target/src/spec/powerpc_unknown_netbsd.rs
+++ b/compiler/rustc_target/src/spec/powerpc_unknown_netbsd.rs
@@ -1,3 +1,4 @@
+use crate::abi::Endian;
use crate::spec::{LinkerFlavor, Target, TargetOptions};
pub fn target() -> Target {
@@ -10,10 +11,6 @@
pointer_width: 32,
data_layout: "E-m:e-p:32:32-i64:64-n32".to_string(),
arch: "powerpc".to_string(),
- options: TargetOptions {
- endian: "big".to_string(),
- mcount: "__mcount".to_string(),
- ..base
- },
+ options: TargetOptions { endian: Endian::Big, mcount: "__mcount".to_string(), ..base },
}
}
diff --git a/compiler/rustc_target/src/spec/powerpc_wrs_vxworks.rs b/compiler/rustc_target/src/spec/powerpc_wrs_vxworks.rs
index 20ffa07..bb943a8 100644
--- a/compiler/rustc_target/src/spec/powerpc_wrs_vxworks.rs
+++ b/compiler/rustc_target/src/spec/powerpc_wrs_vxworks.rs
@@ -1,3 +1,4 @@
+use crate::abi::Endian;
use crate::spec::{LinkerFlavor, Target, TargetOptions};
pub fn target() -> Target {
@@ -11,10 +12,6 @@
pointer_width: 32,
data_layout: "E-m:e-p:32:32-i64:64-n32".to_string(),
arch: "powerpc".to_string(),
- options: TargetOptions {
- endian: "big".to_string(),
- features: "+secure-plt".to_string(),
- ..base
- },
+ options: TargetOptions { endian: Endian::Big, features: "+secure-plt".to_string(), ..base },
}
}
diff --git a/compiler/rustc_target/src/spec/powerpc_wrs_vxworks_spe.rs b/compiler/rustc_target/src/spec/powerpc_wrs_vxworks_spe.rs
index 0e713fc..4b4f118 100644
--- a/compiler/rustc_target/src/spec/powerpc_wrs_vxworks_spe.rs
+++ b/compiler/rustc_target/src/spec/powerpc_wrs_vxworks_spe.rs
@@ -1,3 +1,4 @@
+use crate::abi::Endian;
use crate::spec::{LinkerFlavor, Target, TargetOptions};
pub fn target() -> Target {
@@ -12,7 +13,7 @@
data_layout: "E-m:e-p:32:32-i64:64-n32".to_string(),
arch: "powerpc".to_string(),
options: TargetOptions {
- endian: "big".to_string(),
+ endian: Endian::Big,
// feature msync would disable instruction 'fsync' which is not supported by fsl_p1p2
features: "+secure-plt,+msync".to_string(),
..base
diff --git a/compiler/rustc_target/src/spec/s390x_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/s390x_unknown_linux_gnu.rs
index d6e8e6e..4eeea9b 100644
--- a/compiler/rustc_target/src/spec/s390x_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/s390x_unknown_linux_gnu.rs
@@ -1,8 +1,9 @@
+use crate::abi::Endian;
use crate::spec::Target;
pub fn target() -> Target {
let mut base = super::linux_gnu_base::opts();
- base.endian = "big".to_string();
+ base.endian = Endian::Big;
// z10 is the oldest CPU supported by LLVM
base.cpu = "z10".to_string();
// FIXME: The data_layout string below and the ABI implementation in
diff --git a/compiler/rustc_target/src/spec/sparc64_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/sparc64_unknown_linux_gnu.rs
index e9b5520..e1aa488 100644
--- a/compiler/rustc_target/src/spec/sparc64_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/sparc64_unknown_linux_gnu.rs
@@ -1,8 +1,9 @@
+use crate::abi::Endian;
use crate::spec::Target;
pub fn target() -> Target {
let mut base = super::linux_gnu_base::opts();
- base.endian = "big".to_string();
+ base.endian = Endian::Big;
base.cpu = "v9".to_string();
base.max_atomic_width = Some(64);
diff --git a/compiler/rustc_target/src/spec/sparc64_unknown_netbsd.rs b/compiler/rustc_target/src/spec/sparc64_unknown_netbsd.rs
index c8e90f8..7d685c8 100644
--- a/compiler/rustc_target/src/spec/sparc64_unknown_netbsd.rs
+++ b/compiler/rustc_target/src/spec/sparc64_unknown_netbsd.rs
@@ -1,3 +1,4 @@
+use crate::abi::Endian;
use crate::spec::{LinkerFlavor, Target, TargetOptions};
pub fn target() -> Target {
@@ -11,10 +12,6 @@
pointer_width: 64,
data_layout: "E-m:e-i64:64-n32:64-S128".to_string(),
arch: "sparc64".to_string(),
- options: TargetOptions {
- endian: "big".to_string(),
- mcount: "__mcount".to_string(),
- ..base
- },
+ options: TargetOptions { endian: Endian::Big, mcount: "__mcount".to_string(), ..base },
}
}
diff --git a/compiler/rustc_target/src/spec/sparc64_unknown_openbsd.rs b/compiler/rustc_target/src/spec/sparc64_unknown_openbsd.rs
index 630ce61..63b13fa 100644
--- a/compiler/rustc_target/src/spec/sparc64_unknown_openbsd.rs
+++ b/compiler/rustc_target/src/spec/sparc64_unknown_openbsd.rs
@@ -1,8 +1,9 @@
+use crate::abi::Endian;
use crate::spec::{LinkerFlavor, Target};
pub fn target() -> Target {
let mut base = super::openbsd_base::opts();
- base.endian = "big".to_string();
+ base.endian = Endian::Big;
base.cpu = "v9".to_string();
base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string());
base.max_atomic_width = Some(64);
diff --git a/compiler/rustc_target/src/spec/sparc_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/sparc_unknown_linux_gnu.rs
index aae186b..9e8fbff 100644
--- a/compiler/rustc_target/src/spec/sparc_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/sparc_unknown_linux_gnu.rs
@@ -1,8 +1,9 @@
+use crate::abi::Endian;
use crate::spec::{LinkerFlavor, Target};
pub fn target() -> Target {
let mut base = super::linux_gnu_base::opts();
- base.endian = "big".to_string();
+ base.endian = Endian::Big;
base.cpu = "v9".to_string();
base.max_atomic_width = Some(64);
base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-mv8plus".to_string());
diff --git a/compiler/rustc_target/src/spec/sparcv9_sun_solaris.rs b/compiler/rustc_target/src/spec/sparcv9_sun_solaris.rs
index 5f99e0b..9ac56ca 100644
--- a/compiler/rustc_target/src/spec/sparcv9_sun_solaris.rs
+++ b/compiler/rustc_target/src/spec/sparcv9_sun_solaris.rs
@@ -1,8 +1,9 @@
+use crate::abi::Endian;
use crate::spec::{LinkerFlavor, Target};
pub fn target() -> Target {
let mut base = super::solaris_base::opts();
- base.endian = "big".to_string();
+ base.endian = Endian::Big;
base.pre_link_args.insert(LinkerFlavor::Gcc, vec!["-m64".to_string()]);
// llvm calls this "v9"
base.cpu = "v9".to_string();
diff --git a/compiler/rustc_target/src/spec/uefi_msvc_base.rs b/compiler/rustc_target/src/spec/uefi_msvc_base.rs
index 322b6f5..b9ff16b 100644
--- a/compiler/rustc_target/src/spec/uefi_msvc_base.rs
+++ b/compiler/rustc_target/src/spec/uefi_msvc_base.rs
@@ -9,7 +9,7 @@
// the timer-interrupt. Device-drivers are required to use polling-based models. Furthermore, all
// code runs in the same environment, no process separation is supported.
-use crate::spec::{LinkerFlavor, LldFlavor, PanicStrategy, TargetOptions};
+use crate::spec::{LinkerFlavor, LldFlavor, PanicStrategy, StackProbeType, TargetOptions};
pub fn opts() -> TargetOptions {
let mut base = super::msvc_base::opts();
@@ -43,7 +43,9 @@
exe_suffix: ".efi".to_string(),
allows_weak_linkage: false,
panic_strategy: PanicStrategy::Abort,
- stack_probes: true,
+ // LLVM does not emit inline assembly because the LLVM target does not get considered as…
+ // "Windows".
+ stack_probes: StackProbeType::Call,
singlethread: true,
linker: Some("rust-lld".to_string()),
..base
diff --git a/compiler/rustc_target/src/spec/wasm32_base.rs b/compiler/rustc_target/src/spec/wasm32_base.rs
index a7957d8..bfef3d3 100644
--- a/compiler/rustc_target/src/spec/wasm32_base.rs
+++ b/compiler/rustc_target/src/spec/wasm32_base.rs
@@ -55,15 +55,6 @@
// to do so.
arg("--no-demangle");
- // The symbol visibility story is a bit in flux right now with LLD.
- // It's... not entirely clear to me what's going on, but this looks to
- // make everything work when `export_symbols` isn't otherwise called for
- // things like executables.
- //
- // This is really only here to get things working. If it can be removed and
- // basic tests still work, then sounds like it should be removed!
- arg("--export-dynamic");
-
let mut pre_link_args = BTreeMap::new();
pre_link_args.insert(LinkerFlavor::Lld(LldFlavor::Wasm), lld_args);
pre_link_args.insert(LinkerFlavor::Gcc, clang_args);
diff --git a/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs b/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs
index c12757b..9f69ce1 100644
--- a/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs
+++ b/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs
@@ -2,6 +2,17 @@
use super::{LinkArgs, LinkerFlavor, PanicStrategy, Target, TargetOptions};
pub fn target() -> Target {
+ let mut options = wasm32_base::options();
+
+ let clang_args = options.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap();
+
+ // Rust really needs a way for users to specify exports and imports in
+ // the source code. --export-dynamic isn't the right tool for this job,
+ // however it does have the side effect of automatically exporting a lot
+ // of symbols, which approximates what people want when compiling for
+ // wasm32-unknown-unknown expect, so use it for now.
+ clang_args.push("--export-dynamic".to_string());
+
let mut post_link_args = LinkArgs::new();
post_link_args.insert(
LinkerFlavor::Em,
@@ -28,7 +39,7 @@
panic_strategy: PanicStrategy::Unwind,
post_link_args,
os_family: Some("unix".to_string()),
- ..wasm32_base::options()
+ ..options
};
Target {
llvm_target: "wasm32-unknown-emscripten".to_string(),
diff --git a/compiler/rustc_target/src/spec/wasm32_unknown_unknown.rs b/compiler/rustc_target/src/spec/wasm32_unknown_unknown.rs
index 6037aa5..5e89ba2 100644
--- a/compiler/rustc_target/src/spec/wasm32_unknown_unknown.rs
+++ b/compiler/rustc_target/src/spec/wasm32_unknown_unknown.rs
@@ -26,11 +26,18 @@
// For now this target just never has an entry symbol no matter the output
// type, so unconditionally pass this.
clang_args.push("-Wl,--no-entry".to_string());
- options
- .pre_link_args
- .get_mut(&LinkerFlavor::Lld(LldFlavor::Wasm))
- .unwrap()
- .push("--no-entry".to_string());
+
+ // Rust really needs a way for users to specify exports and imports in
+ // the source code. --export-dynamic isn't the right tool for this job,
+ // however it does have the side effect of automatically exporting a lot
+ // of symbols, which approximates what people want when compiling for
+ // wasm32-unknown-unknown expect, so use it for now.
+ clang_args.push("-Wl,--export-dynamic".to_string());
+
+ // Add the flags to wasm-ld's args too.
+ let lld_args = options.pre_link_args.get_mut(&LinkerFlavor::Lld(LldFlavor::Wasm)).unwrap();
+ lld_args.push("--no-entry".to_string());
+ lld_args.push("--export-dynamic".to_string());
Target {
llvm_target: "wasm32-unknown-unknown".to_string(),
diff --git a/compiler/rustc_target/src/spec/x86_64_apple_darwin.rs b/compiler/rustc_target/src/spec/x86_64_apple_darwin.rs
index edb33fe..6affd7f 100644
--- a/compiler/rustc_target/src/spec/x86_64_apple_darwin.rs
+++ b/compiler/rustc_target/src/spec/x86_64_apple_darwin.rs
@@ -1,4 +1,4 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions};
+use crate::spec::{LinkerFlavor, StackProbeType, Target, TargetOptions};
pub fn target() -> Target {
let mut base = super::apple_base::opts("macos");
@@ -10,7 +10,8 @@
vec!["-m64".to_string(), "-arch".to_string(), "x86_64".to_string()],
);
base.link_env_remove.extend(super::apple_base::macos_link_env_remove());
- base.stack_probes = true;
+ // don't use probe-stack=inline-asm until rust-lang/rust#83139 is resolved.
+ base.stack_probes = StackProbeType::Call;
// Clang automatically chooses a more specific target based on
// MACOSX_DEPLOYMENT_TARGET. To enable cross-language LTO to work
diff --git a/compiler/rustc_target/src/spec/x86_64_apple_ios.rs b/compiler/rustc_target/src/spec/x86_64_apple_ios.rs
index c9c7eeb..ddf6870 100644
--- a/compiler/rustc_target/src/spec/x86_64_apple_ios.rs
+++ b/compiler/rustc_target/src/spec/x86_64_apple_ios.rs
@@ -1,5 +1,5 @@
use super::apple_sdk_base::{opts, Arch};
-use crate::spec::{Target, TargetOptions};
+use crate::spec::{StackProbeType, Target, TargetOptions};
pub fn target() -> Target {
let base = opts("ios", Arch::X86_64);
@@ -9,6 +9,11 @@
data_layout: "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
.to_string(),
arch: "x86_64".to_string(),
- options: TargetOptions { max_atomic_width: Some(64), stack_probes: true, ..base },
+ options: TargetOptions {
+ max_atomic_width: Some(64),
+ // don't use probe-stack=inline-asm until rust-lang/rust#83139 is resolved.
+ stack_probes: StackProbeType::Call,
+ ..base
+ },
}
}
diff --git a/compiler/rustc_target/src/spec/x86_64_apple_ios_macabi.rs b/compiler/rustc_target/src/spec/x86_64_apple_ios_macabi.rs
index 6b360e5..e7c3d66 100644
--- a/compiler/rustc_target/src/spec/x86_64_apple_ios_macabi.rs
+++ b/compiler/rustc_target/src/spec/x86_64_apple_ios_macabi.rs
@@ -1,5 +1,5 @@
use super::apple_sdk_base::{opts, Arch};
-use crate::spec::{Target, TargetOptions};
+use crate::spec::{StackProbeType, Target, TargetOptions};
pub fn target() -> Target {
let base = opts("ios", Arch::X86_64_macabi);
@@ -9,6 +9,11 @@
data_layout: "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
.to_string(),
arch: "x86_64".to_string(),
- options: TargetOptions { max_atomic_width: Some(64), stack_probes: true, ..base },
+ options: TargetOptions {
+ max_atomic_width: Some(64),
+ // don't use probe-stack=inline-asm until rust-lang/rust#83139 is resolved.
+ stack_probes: StackProbeType::Call,
+ ..base
+ },
}
}
diff --git a/compiler/rustc_target/src/spec/x86_64_apple_tvos.rs b/compiler/rustc_target/src/spec/x86_64_apple_tvos.rs
index 5b2a62a..8727e48 100644
--- a/compiler/rustc_target/src/spec/x86_64_apple_tvos.rs
+++ b/compiler/rustc_target/src/spec/x86_64_apple_tvos.rs
@@ -1,5 +1,5 @@
use super::apple_sdk_base::{opts, Arch};
-use crate::spec::{Target, TargetOptions};
+use crate::spec::{StackProbeType, Target, TargetOptions};
pub fn target() -> Target {
let base = opts("tvos", Arch::X86_64);
@@ -8,6 +8,11 @@
pointer_width: 64,
data_layout: "e-m:o-i64:64-f80:128-n8:16:32:64-S128".to_string(),
arch: "x86_64".to_string(),
- options: TargetOptions { max_atomic_width: Some(64), stack_probes: true, ..base },
+ options: TargetOptions {
+ max_atomic_width: Some(64),
+ // don't use probe-stack=inline-asm until rust-lang/rust#83139 is resolved.
+ stack_probes: StackProbeType::Call,
+ ..base
+ },
}
}
diff --git a/compiler/rustc_target/src/spec/x86_64_fuchsia.rs b/compiler/rustc_target/src/spec/x86_64_fuchsia.rs
index 6c049c2..b838b04 100644
--- a/compiler/rustc_target/src/spec/x86_64_fuchsia.rs
+++ b/compiler/rustc_target/src/spec/x86_64_fuchsia.rs
@@ -1,10 +1,11 @@
-use crate::spec::Target;
+use crate::spec::{StackProbeType, Target};
pub fn target() -> Target {
let mut base = super::fuchsia_base::opts();
base.cpu = "x86-64".to_string();
base.max_atomic_width = Some(64);
- base.stack_probes = true;
+ // don't use probe-stack=inline-asm until rust-lang/rust#83139 is resolved.
+ base.stack_probes = StackProbeType::Call;
Target {
llvm_target: "x86_64-fuchsia".to_string(),
diff --git a/compiler/rustc_target/src/spec/x86_64_linux_android.rs b/compiler/rustc_target/src/spec/x86_64_linux_android.rs
index 2732716..f328188 100644
--- a/compiler/rustc_target/src/spec/x86_64_linux_android.rs
+++ b/compiler/rustc_target/src/spec/x86_64_linux_android.rs
@@ -1,4 +1,4 @@
-use crate::spec::{LinkerFlavor, Target};
+use crate::spec::{LinkerFlavor, StackProbeType, Target};
pub fn target() -> Target {
let mut base = super::android_base::opts();
@@ -7,7 +7,8 @@
base.features = "+mmx,+sse,+sse2,+sse3,+ssse3,+sse4.1,+sse4.2,+popcnt".to_string();
base.max_atomic_width = Some(64);
base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string());
- base.stack_probes = true;
+ // don't use probe-stack=inline-asm until rust-lang/rust#83139 is resolved.
+ base.stack_probes = StackProbeType::Call;
Target {
llvm_target: "x86_64-linux-android".to_string(),
diff --git a/compiler/rustc_target/src/spec/x86_64_rumprun_netbsd.rs b/compiler/rustc_target/src/spec/x86_64_rumprun_netbsd.rs
index 095c6f1..b1dce60 100644
--- a/compiler/rustc_target/src/spec/x86_64_rumprun_netbsd.rs
+++ b/compiler/rustc_target/src/spec/x86_64_rumprun_netbsd.rs
@@ -1,4 +1,4 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions};
+use crate::spec::{LinkerFlavor, StackProbeType, Target, TargetOptions};
pub fn target() -> Target {
let mut base = super::netbsd_base::opts();
@@ -12,7 +12,8 @@
base.has_rpath = false;
base.position_independent_executables = false;
base.disable_redzone = true;
- base.stack_probes = true;
+ // don't use probe-stack=inline-asm until rust-lang/rust#83139 is resolved.
+ base.stack_probes = StackProbeType::Call;
Target {
llvm_target: "x86_64-rumprun-netbsd".to_string(),
diff --git a/compiler/rustc_target/src/spec/x86_64_sun_solaris.rs b/compiler/rustc_target/src/spec/x86_64_sun_solaris.rs
index 6ccf784..0f7422d 100644
--- a/compiler/rustc_target/src/spec/x86_64_sun_solaris.rs
+++ b/compiler/rustc_target/src/spec/x86_64_sun_solaris.rs
@@ -1,11 +1,12 @@
-use crate::spec::{LinkerFlavor, Target};
+use crate::spec::{LinkerFlavor, StackProbeType, Target};
pub fn target() -> Target {
let mut base = super::solaris_base::opts();
base.pre_link_args.insert(LinkerFlavor::Gcc, vec!["-m64".to_string()]);
base.cpu = "x86-64".to_string();
base.max_atomic_width = Some(64);
- base.stack_probes = true;
+ // don't use probe-stack=inline-asm until rust-lang/rust#83139 is resolved.
+ base.stack_probes = StackProbeType::Call;
Target {
llvm_target: "x86_64-pc-solaris".to_string(),
diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_dragonfly.rs b/compiler/rustc_target/src/spec/x86_64_unknown_dragonfly.rs
index 30aa290..754f473 100644
--- a/compiler/rustc_target/src/spec/x86_64_unknown_dragonfly.rs
+++ b/compiler/rustc_target/src/spec/x86_64_unknown_dragonfly.rs
@@ -1,11 +1,12 @@
-use crate::spec::{LinkerFlavor, Target};
+use crate::spec::{LinkerFlavor, StackProbeType, Target};
pub fn target() -> Target {
let mut base = super::dragonfly_base::opts();
base.cpu = "x86-64".to_string();
base.max_atomic_width = Some(64);
base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string());
- base.stack_probes = true;
+ // don't use probe-stack=inline-asm until rust-lang/rust#83139 is resolved.
+ base.stack_probes = StackProbeType::Call;
Target {
llvm_target: "x86_64-unknown-dragonfly".to_string(),
diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_freebsd.rs b/compiler/rustc_target/src/spec/x86_64_unknown_freebsd.rs
index ee904d7..055602c 100644
--- a/compiler/rustc_target/src/spec/x86_64_unknown_freebsd.rs
+++ b/compiler/rustc_target/src/spec/x86_64_unknown_freebsd.rs
@@ -1,11 +1,12 @@
-use crate::spec::{LinkerFlavor, Target};
+use crate::spec::{LinkerFlavor, StackProbeType, Target};
pub fn target() -> Target {
let mut base = super::freebsd_base::opts();
base.cpu = "x86-64".to_string();
base.max_atomic_width = Some(64);
base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string());
- base.stack_probes = true;
+ // don't use probe-stack=inline-asm until rust-lang/rust#83139 is resolved.
+ base.stack_probes = StackProbeType::Call;
Target {
llvm_target: "x86_64-unknown-freebsd".to_string(),
diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_haiku.rs b/compiler/rustc_target/src/spec/x86_64_unknown_haiku.rs
index ea7e068..8b3c9f5 100644
--- a/compiler/rustc_target/src/spec/x86_64_unknown_haiku.rs
+++ b/compiler/rustc_target/src/spec/x86_64_unknown_haiku.rs
@@ -1,11 +1,12 @@
-use crate::spec::{LinkerFlavor, Target};
+use crate::spec::{LinkerFlavor, StackProbeType, Target};
pub fn target() -> Target {
let mut base = super::haiku_base::opts();
base.cpu = "x86-64".to_string();
base.max_atomic_width = Some(64);
base.pre_link_args.insert(LinkerFlavor::Gcc, vec!["-m64".to_string()]);
- base.stack_probes = true;
+ // don't use probe-stack=inline-asm until rust-lang/rust#83139 is resolved.
+ base.stack_probes = StackProbeType::Call;
// This option is required to build executables on Haiku x86_64
base.position_independent_executables = true;
diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_hermit.rs b/compiler/rustc_target/src/spec/x86_64_unknown_hermit.rs
index 4005aaf..69fcb46 100644
--- a/compiler/rustc_target/src/spec/x86_64_unknown_hermit.rs
+++ b/compiler/rustc_target/src/spec/x86_64_unknown_hermit.rs
@@ -1,11 +1,12 @@
-use crate::spec::Target;
+use crate::spec::{StackProbeType, Target};
pub fn target() -> Target {
let mut base = super::hermit_base::opts();
base.cpu = "x86-64".to_string();
base.max_atomic_width = Some(64);
base.features = "+rdrnd,+rdseed".to_string();
- base.stack_probes = true;
+ // don't use probe-stack=inline-asm until rust-lang/rust#83139 is resolved.
+ base.stack_probes = StackProbeType::Call;
Target {
llvm_target: "x86_64-unknown-hermit".to_string(),
diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_hermit_kernel.rs b/compiler/rustc_target/src/spec/x86_64_unknown_hermit_kernel.rs
index b72d529..e2c18d3 100644
--- a/compiler/rustc_target/src/spec/x86_64_unknown_hermit_kernel.rs
+++ b/compiler/rustc_target/src/spec/x86_64_unknown_hermit_kernel.rs
@@ -1,4 +1,4 @@
-use crate::spec::Target;
+use crate::spec::{StackProbeType, Target};
pub fn target() -> Target {
let mut base = super::hermit_kernel_base::opts();
@@ -7,7 +7,8 @@
base.features =
"-mmx,-sse,-sse2,-sse3,-ssse3,-sse4.1,-sse4.2,-3dnow,-3dnowa,-avx,-avx2,+soft-float"
.to_string();
- base.stack_probes = true;
+ // don't use probe-stack=inline-asm until rust-lang/rust#83139 is resolved.
+ base.stack_probes = StackProbeType::Call;
Target {
llvm_target: "x86_64-unknown-hermit".to_string(),
diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnu.rs
index f127dd4..2ba6d36 100644
--- a/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnu.rs
@@ -1,11 +1,12 @@
-use crate::spec::{LinkerFlavor, Target};
+use crate::spec::{LinkerFlavor, StackProbeType, Target};
pub fn target() -> Target {
let mut base = super::linux_gnu_base::opts();
base.cpu = "x86-64".to_string();
base.max_atomic_width = Some(64);
base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string());
- base.stack_probes = true;
+ // don't use probe-stack=inline-asm until rust-lang/rust#83139 is resolved.
+ base.stack_probes = StackProbeType::Call;
Target {
llvm_target: "x86_64-unknown-linux-gnu".to_string(),
diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnux32.rs b/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnux32.rs
index 0cae575..268f231 100644
--- a/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnux32.rs
+++ b/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnux32.rs
@@ -1,11 +1,12 @@
-use crate::spec::{LinkerFlavor, Target};
+use crate::spec::{LinkerFlavor, StackProbeType, Target};
pub fn target() -> Target {
let mut base = super::linux_gnu_base::opts();
base.cpu = "x86-64".to_string();
base.max_atomic_width = Some(64);
base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-mx32".to_string());
- base.stack_probes = true;
+ // don't use probe-stack=inline-asm until rust-lang/rust#83139 is resolved.
+ base.stack_probes = StackProbeType::Call;
base.has_elf_tls = false;
// BUG(GabrielMajeri): disabling the PLT on x86_64 Linux with x32 ABI
// breaks code gen. See LLVM bug 36743
diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/x86_64_unknown_linux_musl.rs
index 3669c10..b4d704f 100644
--- a/compiler/rustc_target/src/spec/x86_64_unknown_linux_musl.rs
+++ b/compiler/rustc_target/src/spec/x86_64_unknown_linux_musl.rs
@@ -1,11 +1,13 @@
-use crate::spec::{LinkerFlavor, Target};
+use crate::spec::{LinkerFlavor, StackProbeType, Target};
pub fn target() -> Target {
let mut base = super::linux_musl_base::opts();
base.cpu = "x86-64".to_string();
base.max_atomic_width = Some(64);
base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string());
- base.stack_probes = true;
+ // don't use probe-stack=inline-asm until rust-lang/rust#83139 is resolved.
+ base.stack_probes = StackProbeType::Call;
+
base.static_position_independent_executables = true;
Target {
diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_netbsd.rs b/compiler/rustc_target/src/spec/x86_64_unknown_netbsd.rs
index 7e91a6d..a5d8800 100644
--- a/compiler/rustc_target/src/spec/x86_64_unknown_netbsd.rs
+++ b/compiler/rustc_target/src/spec/x86_64_unknown_netbsd.rs
@@ -1,11 +1,12 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions};
+use crate::spec::{LinkerFlavor, StackProbeType, Target, TargetOptions};
pub fn target() -> Target {
let mut base = super::netbsd_base::opts();
base.cpu = "x86-64".to_string();
base.max_atomic_width = Some(64);
base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string());
- base.stack_probes = true;
+ // don't use probe-stack=inline-asm until rust-lang/rust#83139 is resolved.
+ base.stack_probes = StackProbeType::Call;
Target {
llvm_target: "x86_64-unknown-netbsd".to_string(),
diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_openbsd.rs b/compiler/rustc_target/src/spec/x86_64_unknown_openbsd.rs
index 0fe01f0..fa0b667 100644
--- a/compiler/rustc_target/src/spec/x86_64_unknown_openbsd.rs
+++ b/compiler/rustc_target/src/spec/x86_64_unknown_openbsd.rs
@@ -1,11 +1,12 @@
-use crate::spec::{LinkerFlavor, Target};
+use crate::spec::{LinkerFlavor, StackProbeType, Target};
pub fn target() -> Target {
let mut base = super::openbsd_base::opts();
base.cpu = "x86-64".to_string();
base.max_atomic_width = Some(64);
base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string());
- base.stack_probes = true;
+ // don't use probe-stack=inline-asm until rust-lang/rust#83139 is resolved.
+ base.stack_probes = StackProbeType::Call;
Target {
llvm_target: "x86_64-unknown-openbsd".to_string(),
diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_redox.rs b/compiler/rustc_target/src/spec/x86_64_unknown_redox.rs
index cdd445b..0a8d7b2 100644
--- a/compiler/rustc_target/src/spec/x86_64_unknown_redox.rs
+++ b/compiler/rustc_target/src/spec/x86_64_unknown_redox.rs
@@ -1,11 +1,12 @@
-use crate::spec::{LinkerFlavor, Target};
+use crate::spec::{LinkerFlavor, StackProbeType, Target};
pub fn target() -> Target {
let mut base = super::redox_base::opts();
base.cpu = "x86-64".to_string();
base.max_atomic_width = Some(64);
base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string());
- base.stack_probes = true;
+ // don't use probe-stack=inline-asm until rust-lang/rust#83139 is resolved.
+ base.stack_probes = StackProbeType::Call;
Target {
llvm_target: "x86_64-unknown-redox".to_string(),
diff --git a/compiler/rustc_target/src/spec/x86_64_wrs_vxworks.rs b/compiler/rustc_target/src/spec/x86_64_wrs_vxworks.rs
index 163af6f..a066f11 100644
--- a/compiler/rustc_target/src/spec/x86_64_wrs_vxworks.rs
+++ b/compiler/rustc_target/src/spec/x86_64_wrs_vxworks.rs
@@ -1,11 +1,12 @@
-use crate::spec::{LinkerFlavor, Target};
+use crate::spec::{LinkerFlavor, StackProbeType, Target};
pub fn target() -> Target {
let mut base = super::vxworks_base::opts();
base.cpu = "x86-64".to_string();
base.max_atomic_width = Some(64);
base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string());
- base.stack_probes = true;
+ // don't use probe-stack=inline-asm until rust-lang/rust#83139 is resolved.
+ base.stack_probes = StackProbeType::Call;
base.disable_redzone = true;
Target {
diff --git a/compiler/rustc_trait_selection/src/infer.rs b/compiler/rustc_trait_selection/src/infer.rs
index 41184ce..da66fbc 100644
--- a/compiler/rustc_trait_selection/src/infer.rs
+++ b/compiler/rustc_trait_selection/src/infer.rs
@@ -162,7 +162,7 @@
/// 'b` (and hence, transitively, that `T: 'a`). This method would
/// add those assumptions into the outlives-environment.
///
- /// Tests: `src/test/compile-fail/regions-free-region-ordering-*.rs`
+ /// Tests: `src/test/ui/regions/regions-free-region-ordering-*.rs`
fn add_implied_bounds(
&mut self,
infcx: &InferCtxt<'a, 'tcx>,
diff --git a/compiler/rustc_trait_selection/src/lib.rs b/compiler/rustc_trait_selection/src/lib.rs
index 42509cd..e1f8d59 100644
--- a/compiler/rustc_trait_selection/src/lib.rs
+++ b/compiler/rustc_trait_selection/src/lib.rs
@@ -11,7 +11,6 @@
//! This API is completely unstable and subject to change.
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
-#![feature(array_value_iter)]
#![feature(bool_to_option)]
#![feature(box_patterns)]
#![feature(drain_filter)]
diff --git a/compiler/rustc_trait_selection/src/opaque_types.rs b/compiler/rustc_trait_selection/src/opaque_types.rs
index f5bc90e..25ba489 100644
--- a/compiler/rustc_trait_selection/src/opaque_types.rs
+++ b/compiler/rustc_trait_selection/src/opaque_types.rs
@@ -1153,7 +1153,7 @@
debug!("instantiate_opaque_types: ty_var={:?}", ty_var);
for predicate in &bounds {
- if let ty::PredicateAtom::Projection(projection) = predicate.skip_binders() {
+ if let ty::PredicateKind::Projection(projection) = predicate.kind().skip_binder() {
if projection.ty.references_error() {
// No point on adding these obligations since there's a type error involved.
return ty_var;
@@ -1251,18 +1251,18 @@
traits::elaborate_predicates(tcx, predicates)
.filter_map(|obligation| {
debug!("required_region_bounds(obligation={:?})", obligation);
- match obligation.predicate.skip_binders() {
- ty::PredicateAtom::Projection(..)
- | ty::PredicateAtom::Trait(..)
- | ty::PredicateAtom::Subtype(..)
- | ty::PredicateAtom::WellFormed(..)
- | ty::PredicateAtom::ObjectSafe(..)
- | ty::PredicateAtom::ClosureKind(..)
- | ty::PredicateAtom::RegionOutlives(..)
- | ty::PredicateAtom::ConstEvaluatable(..)
- | ty::PredicateAtom::ConstEquate(..)
- | ty::PredicateAtom::TypeWellFormedFromEnv(..) => None,
- ty::PredicateAtom::TypeOutlives(ty::OutlivesPredicate(ref t, ref r)) => {
+ match obligation.predicate.kind().skip_binder() {
+ ty::PredicateKind::Projection(..)
+ | ty::PredicateKind::Trait(..)
+ | ty::PredicateKind::Subtype(..)
+ | ty::PredicateKind::WellFormed(..)
+ | ty::PredicateKind::ObjectSafe(..)
+ | ty::PredicateKind::ClosureKind(..)
+ | ty::PredicateKind::RegionOutlives(..)
+ | ty::PredicateKind::ConstEvaluatable(..)
+ | ty::PredicateKind::ConstEquate(..)
+ | ty::PredicateKind::TypeWellFormedFromEnv(..) => None,
+ ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(ref t, ref r)) => {
// Search for a bound of the form `erased_self_ty
// : 'a`, but be wary of something like `for<'a>
// erased_self_ty : 'a` (we interpret a
diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
index 6ab1688..6593c10 100644
--- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs
+++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
@@ -35,10 +35,7 @@
#[allow(dead_code)]
impl<A> AutoTraitResult<A> {
fn is_auto(&self) -> bool {
- match *self {
- AutoTraitResult::PositiveImpl(_) | AutoTraitResult::NegativeImpl => true,
- _ => false,
- }
+ matches!(self, AutoTraitResult::PositiveImpl(_) | AutoTraitResult::NegativeImpl)
}
}
@@ -308,8 +305,8 @@
infcx.resolve_vars_if_possible(Obligation::new(dummy_cause.clone(), new_env, pred));
let result = select.select(&obligation);
- match &result {
- &Ok(Some(ref impl_source)) => {
+ match result {
+ Ok(Some(ref impl_source)) => {
// If we see an explicit negative impl (e.g., `impl !Send for MyStruct`),
// we immediately bail out, since it's impossible for us to continue.
@@ -342,8 +339,8 @@
return None;
}
}
- &Ok(None) => {}
- &Err(SelectionError::Unimplemented) => {
+ Ok(None) => {}
+ Err(SelectionError::Unimplemented) => {
if self.is_param_no_infer(pred.skip_binder().trait_ref.substs) {
already_visited.remove(&pred);
self.add_user_pred(
@@ -417,9 +414,9 @@
let mut should_add_new = true;
user_computed_preds.retain(|&old_pred| {
if let (
- ty::PredicateAtom::Trait(new_trait, _),
- ty::PredicateAtom::Trait(old_trait, _),
- ) = (new_pred.skip_binders(), old_pred.skip_binders())
+ ty::PredicateKind::Trait(new_trait, _),
+ ty::PredicateKind::Trait(old_trait, _),
+ ) = (new_pred.kind().skip_binder(), old_pred.kind().skip_binder())
{
if new_trait.def_id() == old_trait.def_id() {
let new_substs = new_trait.trait_ref.substs;
@@ -601,10 +598,7 @@
}
fn is_self_referential_projection(&self, p: ty::PolyProjectionPredicate<'_>) -> bool {
- match *p.ty().skip_binder().kind() {
- ty::Projection(proj) if proj == p.skip_binder().projection_ty => true,
- _ => false,
- }
+ matches!(*p.ty().skip_binder().kind(), ty::Projection(proj) if proj == p.skip_binder().projection_ty)
}
fn evaluate_nested_obligations(
@@ -639,18 +633,16 @@
// We check this by calling is_of_param on the relevant types
// from the various possible predicates
- let bound_predicate = predicate.bound_atom();
+ let bound_predicate = predicate.kind();
match bound_predicate.skip_binder() {
- ty::PredicateAtom::Trait(p, _) => {
- if self.is_param_no_infer(p.trait_ref.substs)
- && !only_projections
- && is_new_pred
- {
- self.add_user_pred(computed_preds, predicate);
- }
+ ty::PredicateKind::Trait(p, _) => {
+ // Add this to `predicates` so that we end up calling `select`
+ // with it. If this predicate ends up being unimplemented,
+ // then `evaluate_predicates` will handle adding it the `ParamEnv`
+ // if possible.
predicates.push_back(bound_predicate.rebind(p));
}
- ty::PredicateAtom::Projection(p) => {
+ ty::PredicateKind::Projection(p) => {
let p = bound_predicate.rebind(p);
debug!(
"evaluate_nested_obligations: examining projection predicate {:?}",
@@ -780,13 +772,13 @@
}
}
}
- ty::PredicateAtom::RegionOutlives(binder) => {
+ ty::PredicateKind::RegionOutlives(binder) => {
let binder = bound_predicate.rebind(binder);
if select.infcx().region_outlives_predicate(&dummy_cause, binder).is_err() {
return false;
}
}
- ty::PredicateAtom::TypeOutlives(binder) => {
+ ty::PredicateKind::TypeOutlives(binder) => {
let binder = bound_predicate.rebind(binder);
match (
binder.no_bound_vars(),
@@ -809,7 +801,7 @@
_ => {}
};
}
- ty::PredicateAtom::ConstEquate(c1, c2) => {
+ ty::PredicateKind::ConstEquate(c1, c2) => {
let evaluate = |c: &'tcx ty::Const<'tcx>| {
if let ty::ConstKind::Unevaluated(def, substs, promoted) = c.val {
match select.infcx().const_eval_resolve(
@@ -869,7 +861,7 @@
fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
(match r {
- &ty::ReVar(vid) => self.vid_to_region.get(&vid).cloned(),
+ ty::ReVar(vid) => self.vid_to_region.get(vid).cloned(),
_ => None,
})
.unwrap_or_else(|| r.super_fold_with(self))
diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs
index 9324d55..99b96f6 100644
--- a/compiler/rustc_trait_selection/src/traits/coherence.rs
+++ b/compiler/rustc_trait_selection/src/traits/coherence.rs
@@ -193,10 +193,8 @@
let intercrate_ambiguity_causes = selcx.take_intercrate_ambiguity_causes();
debug!("overlap: intercrate_ambiguity_causes={:#?}", intercrate_ambiguity_causes);
- let involves_placeholder = match selcx.infcx().region_constraints_added_in_snapshot(snapshot) {
- Some(true) => true,
- _ => false,
- };
+ let involves_placeholder =
+ matches!(selcx.infcx().region_constraints_added_in_snapshot(snapshot), Some(true));
Some(OverlapResult { impl_header, intercrate_ambiguity_causes, involves_placeholder })
}
diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
index fdb2361..89820bb 100644
--- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
+++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
@@ -16,8 +16,7 @@
use rustc_middle::mir::abstract_const::{Node, NodeId};
use rustc_middle::mir::interpret::ErrorHandled;
use rustc_middle::mir::{self, Rvalue, StatementKind, TerminatorKind};
-use rustc_middle::ty::subst::Subst;
-use rustc_middle::ty::subst::SubstsRef;
+use rustc_middle::ty::subst::{Subst, SubstsRef};
use rustc_middle::ty::{self, TyCtxt, TypeFoldable};
use rustc_session::lint;
use rustc_span::def_id::{DefId, LocalDefId};
@@ -41,20 +40,29 @@
// We are looking at a generic abstract constant.
Some(ct) => {
for pred in param_env.caller_bounds() {
- match pred.skip_binders() {
- ty::PredicateAtom::ConstEvaluatable(b_def, b_substs) => {
- debug!(
- "is_const_evaluatable: caller_bound={:?}, {:?}",
- b_def, b_substs
- );
+ match pred.kind().skip_binder() {
+ ty::PredicateKind::ConstEvaluatable(b_def, b_substs) => {
if b_def == def && b_substs == substs {
debug!("is_const_evaluatable: caller_bound ~~> ok");
return Ok(());
- } else if AbstractConst::new(tcx, b_def, b_substs)?
- .map_or(false, |b_ct| try_unify(tcx, ct, b_ct))
- {
- debug!("is_const_evaluatable: abstract_const ~~> ok");
- return Ok(());
+ }
+
+ if let Some(b_ct) = AbstractConst::new(tcx, b_def, b_substs)? {
+ // Try to unify with each subtree in the AbstractConst to allow for
+ // `N + 1` being const evaluatable even if theres only a `ConstEvaluatable`
+ // predicate for `(N + 1) * 2`
+ let result =
+ walk_abstract_const(tcx, b_ct, |b_ct| {
+ match try_unify(tcx, ct, b_ct) {
+ true => ControlFlow::BREAK,
+ false => ControlFlow::CONTINUE,
+ }
+ });
+
+ if let ControlFlow::Break(()) = result {
+ debug!("is_const_evaluatable: abstract_const ~~> ok");
+ return Ok(());
+ }
}
}
_ => {} // don't care
@@ -78,7 +86,7 @@
Concrete,
}
let mut failure_kind = FailureKind::Concrete;
- walk_abstract_const::<!, _>(tcx, ct, |node| match node {
+ walk_abstract_const::<!, _>(tcx, ct, |node| match node.root() {
Node::Leaf(leaf) => {
let leaf = leaf.subst(tcx, ct.substs);
if leaf.has_infer_types_or_consts() {
@@ -100,15 +108,24 @@
}
FailureKind::MentionsParam => {
// FIXME(const_evaluatable_checked): Better error message.
- infcx
- .tcx
- .sess
- .struct_span_err(span, "unconstrained generic constant")
- .span_help(
+ let mut err =
+ infcx.tcx.sess.struct_span_err(span, "unconstrained generic constant");
+ let const_span = tcx.def_span(def.did);
+ // FIXME(const_evaluatable_checked): Update this suggestion once
+ // explicit const evaluatable bounds are implemented.
+ if let Ok(snippet) = infcx.tcx.sess.source_map().span_to_snippet(const_span)
+ {
+ err.span_help(
tcx.def_span(def.did),
+ &format!("try adding a `where` bound using this expression: where [u8; {}]: Sized", snippet),
+ );
+ } else {
+ err.span_help(
+ const_span,
"consider adding a `where` bound for this expression",
- )
- .emit();
+ );
+ }
+ err.emit();
return Err(ErrorHandled::Reported(ErrorReported));
}
FailureKind::Concrete => {
@@ -152,7 +169,7 @@
if concrete.is_ok() && substs.has_param_types_or_consts() {
match infcx.tcx.def_kind(def.did) {
DefKind::AnonConst => {
- let mir_body = infcx.tcx.optimized_mir_opt_const_arg(def);
+ let mir_body = infcx.tcx.mir_for_ctfe_opt_const_arg(def);
if mir_body.is_polymorphic {
future_compat_lint();
@@ -580,15 +597,15 @@
mut f: F,
) -> ControlFlow<R>
where
- F: FnMut(Node<'tcx>) -> ControlFlow<R>,
+ F: FnMut(AbstractConst<'tcx>) -> ControlFlow<R>,
{
fn recurse<'tcx, R>(
tcx: TyCtxt<'tcx>,
ct: AbstractConst<'tcx>,
- f: &mut dyn FnMut(Node<'tcx>) -> ControlFlow<R>,
+ f: &mut dyn FnMut(AbstractConst<'tcx>) -> ControlFlow<R>,
) -> ControlFlow<R> {
+ f(ct)?;
let root = ct.root();
- f(root)?;
match root {
Node::Leaf(_) => ControlFlow::CONTINUE,
Node::Binop(_, l, r) => {
@@ -609,9 +626,29 @@
/// Tries to unify two abstract constants using structural equality.
pub(super) fn try_unify<'tcx>(
tcx: TyCtxt<'tcx>,
- a: AbstractConst<'tcx>,
- b: AbstractConst<'tcx>,
+ mut a: AbstractConst<'tcx>,
+ mut b: AbstractConst<'tcx>,
) -> bool {
+ // We substitute generics repeatedly to allow AbstractConsts to unify where a
+ // ConstKind::Unevalated could be turned into an AbstractConst that would unify e.g.
+ // Param(N) should unify with Param(T), substs: [Unevaluated("T2", [Unevaluated("T3", [Param(N)])])]
+ while let Node::Leaf(a_ct) = a.root() {
+ let a_ct = a_ct.subst(tcx, a.substs);
+ match AbstractConst::from_const(tcx, a_ct) {
+ Ok(Some(a_act)) => a = a_act,
+ Ok(None) => break,
+ Err(_) => return true,
+ }
+ }
+ while let Node::Leaf(b_ct) = b.root() {
+ let b_ct = b_ct.subst(tcx, b.substs);
+ match AbstractConst::from_const(tcx, b_ct) {
+ Ok(Some(b_act)) => b = b_act,
+ Ok(None) => break,
+ Err(_) => return true,
+ }
+ }
+
match (a.root(), b.root()) {
(Node::Leaf(a_ct), Node::Leaf(b_ct)) => {
let a_ct = a_ct.subst(tcx, a.substs);
@@ -632,8 +669,6 @@
// we do not want to use `assert_eq!(a(), b())` to infer that `N` and `M` have to be `1`. This
// means that we only allow inference variables if they are equal.
(ty::ConstKind::Infer(a_val), ty::ConstKind::Infer(b_val)) => a_val == b_val,
- // We may want to instead recurse into unevaluated constants here. That may require some
- // care to prevent infinite recursion, so let's just ignore this for now.
(
ty::ConstKind::Unevaluated(a_def, a_substs, None),
ty::ConstKind::Unevaluated(b_def, b_substs, None),
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 9feba7b..d3b3403 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
@@ -256,9 +256,9 @@
return;
}
- let bound_predicate = obligation.predicate.bound_atom();
+ let bound_predicate = obligation.predicate.kind();
match bound_predicate.skip_binder() {
- ty::PredicateAtom::Trait(trait_predicate, _) => {
+ ty::PredicateKind::Trait(trait_predicate, _) => {
let trait_predicate = bound_predicate.rebind(trait_predicate);
let trait_predicate = self.resolve_vars_if_possible(trait_predicate);
@@ -280,18 +280,10 @@
let OnUnimplementedNote { message, label, note, enclosing_scope } =
self.on_unimplemented_note(trait_ref, obligation);
let have_alt_message = message.is_some() || label.is_some();
- let is_try = self
- .tcx
- .sess
- .source_map()
- .span_to_snippet(span)
- .map(|s| &s == "?")
- .unwrap_or(false);
- let is_from = self.tcx.get_diagnostic_item(sym::from_trait)
- == Some(trait_ref.def_id());
+ let is_try_conversion = self.is_try_conversion(span, trait_ref.def_id());
let is_unsize =
{ Some(trait_ref.def_id()) == self.tcx.lang_items().unsize_trait() };
- let (message, note) = if is_try && is_from {
+ let (message, note) = if is_try_conversion {
(
Some(format!(
"`?` couldn't convert the error to `{}`",
@@ -319,7 +311,7 @@
))
);
- if is_try && is_from {
+ if is_try_conversion {
let none_error = self
.tcx
.get_diagnostic_item(sym::none_error)
@@ -525,14 +517,14 @@
err
}
- ty::PredicateAtom::Subtype(predicate) => {
+ ty::PredicateKind::Subtype(predicate) => {
// Errors for Subtype predicates show up as
// `FulfillmentErrorCode::CodeSubtypeError`,
// not selection error.
span_bug!(span, "subtype requirement gave wrong error: `{:?}`", predicate)
}
- ty::PredicateAtom::RegionOutlives(predicate) => {
+ ty::PredicateKind::RegionOutlives(predicate) => {
let predicate = bound_predicate.rebind(predicate);
let predicate = self.resolve_vars_if_possible(predicate);
let err = self
@@ -549,7 +541,7 @@
)
}
- ty::PredicateAtom::Projection(..) | ty::PredicateAtom::TypeOutlives(..) => {
+ ty::PredicateKind::Projection(..) | ty::PredicateKind::TypeOutlives(..) => {
let predicate = self.resolve_vars_if_possible(obligation.predicate);
struct_span_err!(
self.tcx.sess,
@@ -560,12 +552,12 @@
)
}
- ty::PredicateAtom::ObjectSafe(trait_def_id) => {
+ ty::PredicateKind::ObjectSafe(trait_def_id) => {
let violations = self.tcx.object_safety_violations(trait_def_id);
report_object_safety_error(self.tcx, span, trait_def_id, violations)
}
- ty::PredicateAtom::ClosureKind(closure_def_id, closure_substs, kind) => {
+ ty::PredicateKind::ClosureKind(closure_def_id, closure_substs, kind) => {
let found_kind = self.closure_kind(closure_substs).unwrap();
let closure_span =
self.tcx.sess.source_map().guess_head_span(
@@ -597,23 +589,23 @@
if let Some(typeck_results) = self.in_progress_typeck_results {
let typeck_results = typeck_results.borrow();
match (found_kind, typeck_results.closure_kind_origins().get(hir_id)) {
- (ty::ClosureKind::FnOnce, Some((span, name))) => {
+ (ty::ClosureKind::FnOnce, Some((span, place))) => {
err.span_label(
*span,
format!(
"closure is `FnOnce` because it moves the \
variable `{}` out of its environment",
- name
+ ty::place_to_string_for_capture(tcx, place)
),
);
}
- (ty::ClosureKind::FnMut, Some((span, name))) => {
+ (ty::ClosureKind::FnMut, Some((span, place))) => {
err.span_label(
*span,
format!(
"closure is `FnMut` because it mutates the \
variable `{}` here",
- name
+ ty::place_to_string_for_capture(tcx, place)
),
);
}
@@ -625,7 +617,7 @@
return;
}
- ty::PredicateAtom::WellFormed(ty) => {
+ ty::PredicateKind::WellFormed(ty) => {
if !self.tcx.sess.opts.debugging_opts.chalk {
// WF predicates cannot themselves make
// errors. They can only block due to
@@ -643,7 +635,7 @@
}
}
- ty::PredicateAtom::ConstEvaluatable(..) => {
+ ty::PredicateKind::ConstEvaluatable(..) => {
// Errors for `ConstEvaluatable` predicates show up as
// `SelectionError::ConstEvalFailure`,
// not `Unimplemented`.
@@ -654,7 +646,7 @@
)
}
- ty::PredicateAtom::ConstEquate(..) => {
+ ty::PredicateKind::ConstEquate(..) => {
// Errors for `ConstEquate` predicates show up as
// `SelectionError::ConstEvalFailure`,
// not `Unimplemented`.
@@ -665,7 +657,7 @@
)
}
- ty::PredicateAtom::TypeWellFormedFromEnv(..) => span_bug!(
+ ty::PredicateKind::TypeWellFormedFromEnv(..) => span_bug!(
span,
"TypeWellFormedFromEnv predicate should only exist in the environment"
),
@@ -838,7 +830,7 @@
.collect::<Vec<ArgKind>>(),
),
Node::Ctor(ref variant_data) => {
- let span = variant_data.ctor_hir_id().map(|id| hir.span(id)).unwrap_or(DUMMY_SP);
+ let span = variant_data.ctor_hir_id().map_or(DUMMY_SP, |id| hir.span(id));
let span = sm.guess_head_span(span);
(span, vec![ArgKind::empty(); variant_data.fields().len()])
}
@@ -861,10 +853,7 @@
let args_str = |arguments: &[ArgKind], other: &[ArgKind]| {
let arg_length = arguments.len();
- let distinct = match &other[..] {
- &[ArgKind::Tuple(..)] => true,
- _ => false,
- };
+ let distinct = matches!(other, &[ArgKind::Tuple(..)]);
match (arg_length, arguments.get(0)) {
(1, Some(&ArgKind::Tuple(_, ref fields))) => {
format!("a single {}-tuple as argument", fields.len())
@@ -1080,9 +1069,9 @@
}
// FIXME: It should be possible to deal with `ForAll` in a cleaner way.
- let bound_error = error.bound_atom();
- let (cond, error) = match (cond.skip_binders(), bound_error.skip_binder()) {
- (ty::PredicateAtom::Trait(..), ty::PredicateAtom::Trait(error, _)) => {
+ let bound_error = error.kind();
+ let (cond, error) = match (cond.kind().skip_binder(), bound_error.skip_binder()) {
+ (ty::PredicateKind::Trait(..), ty::PredicateKind::Trait(error, _)) => {
(cond, bound_error.rebind(error))
}
_ => {
@@ -1092,8 +1081,8 @@
};
for obligation in super::elaborate_predicates(self.tcx, std::iter::once(cond)) {
- let bound_predicate = obligation.predicate.bound_atom();
- if let ty::PredicateAtom::Trait(implication, _) = bound_predicate.skip_binder() {
+ let bound_predicate = obligation.predicate.kind();
+ if let ty::PredicateKind::Trait(implication, _) = bound_predicate.skip_binder() {
let error = error.to_poly_trait_ref();
let implication = bound_predicate.rebind(implication.trait_ref);
// FIXME: I'm just not taking associated types at all here.
@@ -1173,8 +1162,8 @@
//
// this can fail if the problem was higher-ranked, in which
// cause I have no idea for a good error message.
- let bound_predicate = predicate.bound_atom();
- if let ty::PredicateAtom::Projection(data) = bound_predicate.skip_binder() {
+ let bound_predicate = predicate.kind();
+ if let ty::PredicateKind::Projection(data) = bound_predicate.skip_binder() {
let mut selcx = SelectionContext::new(self);
let (data, _) = self.replace_bound_vars_with_fresh_vars(
obligation.cause.span,
@@ -1201,12 +1190,12 @@
normalized_ty, data.ty
);
- let is_normalized_ty_expected = match &obligation.cause.code {
+ let is_normalized_ty_expected = !matches!(
+ obligation.cause.code,
ObligationCauseCode::ItemObligation(_)
- | ObligationCauseCode::BindingObligation(_, _)
- | ObligationCauseCode::ObjectCastObligation(_) => false,
- _ => true,
- };
+ | ObligationCauseCode::BindingObligation(_, _)
+ | ObligationCauseCode::ObjectCastObligation(_)
+ );
if let Err(error) = self.at(&obligation.cause, obligation.param_env).eq_exp(
is_normalized_ty_expected,
@@ -1374,7 +1363,7 @@
code: &ObligationCauseCode<'tcx>,
) -> Option<(String, Option<Span>)> {
match code {
- &ObligationCauseCode::BuiltinDerivedObligation(ref data) => {
+ ObligationCauseCode::BuiltinDerivedObligation(data) => {
let parent_trait_ref = self.resolve_vars_if_possible(data.parent_trait_ref);
match self.get_parent_trait_ref(&data.parent_code) {
Some(t) => Some(t),
@@ -1466,9 +1455,9 @@
return;
}
- let bound_predicate = predicate.bound_atom();
+ let bound_predicate = predicate.kind();
let mut err = match bound_predicate.skip_binder() {
- ty::PredicateAtom::Trait(data, _) => {
+ ty::PredicateKind::Trait(data, _) => {
let trait_ref = bound_predicate.rebind(data.trait_ref);
debug!("trait_ref {:?}", trait_ref);
@@ -1512,11 +1501,18 @@
// check upstream for type errors and don't add the obligations to
// begin with in those cases.
if self.tcx.lang_items().sized_trait() == Some(trait_ref.def_id()) {
- self.emit_inference_failure_err(body_id, span, subst, ErrorCode::E0282).emit();
+ self.emit_inference_failure_err(body_id, span, subst, vec![], ErrorCode::E0282)
+ .emit();
return;
}
- let mut err =
- self.emit_inference_failure_err(body_id, span, subst, ErrorCode::E0283);
+ let impl_candidates = self.find_similar_impl_candidates(trait_ref);
+ let mut err = self.emit_inference_failure_err(
+ body_id,
+ span,
+ subst,
+ impl_candidates,
+ ErrorCode::E0283,
+ );
err.note(&format!("cannot satisfy `{}`", predicate));
if let ObligationCauseCode::ItemObligation(def_id) = obligation.cause.code {
self.suggest_fully_qualified_path(&mut err, def_id, span, trait_ref.def_id());
@@ -1573,17 +1569,17 @@
err
}
- ty::PredicateAtom::WellFormed(arg) => {
+ ty::PredicateKind::WellFormed(arg) => {
// Same hacky approach as above to avoid deluging user
// with error messages.
if arg.references_error() || self.tcx.sess.has_errors() {
return;
}
- self.emit_inference_failure_err(body_id, span, arg, ErrorCode::E0282)
+ self.emit_inference_failure_err(body_id, span, arg, vec![], ErrorCode::E0282)
}
- ty::PredicateAtom::Subtype(data) => {
+ ty::PredicateKind::Subtype(data) => {
if data.references_error() || self.tcx.sess.has_errors() {
// no need to overload user in such cases
return;
@@ -1591,9 +1587,9 @@
let SubtypePredicate { a_is_expected: _, a, b } = data;
// both must be type variables, or the other would've been instantiated
assert!(a.is_ty_var() && b.is_ty_var());
- self.emit_inference_failure_err(body_id, span, a.into(), ErrorCode::E0282)
+ self.emit_inference_failure_err(body_id, span, a.into(), vec![], ErrorCode::E0282)
}
- ty::PredicateAtom::Projection(data) => {
+ ty::PredicateKind::Projection(data) => {
let trait_ref = bound_predicate.rebind(data).to_poly_trait_ref(self.tcx);
let self_ty = trait_ref.skip_binder().self_ty();
let ty = data.ty;
@@ -1606,6 +1602,7 @@
body_id,
span,
self_ty.into(),
+ vec![],
ErrorCode::E0284,
);
err.note(&format!("cannot satisfy `{}`", predicate));
@@ -1723,9 +1720,10 @@
obligation: &PredicateObligation<'tcx>,
) {
let (pred, item_def_id, span) =
- match (obligation.predicate.skip_binders(), obligation.cause.code.peel_derives()) {
+ match (obligation.predicate.kind().skip_binder(), obligation.cause.code.peel_derives())
+ {
(
- ty::PredicateAtom::Trait(pred, _),
+ ty::PredicateKind::Trait(pred, _),
&ObligationCauseCode::BindingObligation(item_def_id, span),
) => (pred, item_def_id, span),
_ => return,
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
index 79fea83..2182800 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -286,21 +286,32 @@
);
} else {
// Trivial case: `T` needs an extra bound: `T: Bound`.
- let (sp, suggestion) = match super_traits {
- None => predicate_constraint(
+ let (sp, suggestion) = match (
+ generics
+ .params
+ .iter()
+ .filter(|p| {
+ !matches!(p.kind, hir::GenericParamKind::Type { synthetic: Some(_), .. })
+ })
+ .next(),
+ super_traits,
+ ) {
+ (_, None) => predicate_constraint(
generics,
trait_ref.without_const().to_predicate(tcx).to_string(),
),
- Some((ident, bounds)) => match bounds {
- [.., bound] => (
- bound.span().shrink_to_hi(),
- format!(" + {}", trait_ref.print_only_trait_path().to_string()),
- ),
- [] => (
- ident.span.shrink_to_hi(),
- format!(": {}", trait_ref.print_only_trait_path().to_string()),
- ),
- },
+ (None, Some((ident, []))) => (
+ ident.span.shrink_to_hi(),
+ format!(": {}", trait_ref.print_only_trait_path().to_string()),
+ ),
+ (_, Some((_, [.., bounds]))) => (
+ bounds.span().shrink_to_hi(),
+ format!(" + {}", trait_ref.print_only_trait_path().to_string()),
+ ),
+ (Some(_), Some((_, []))) => (
+ generics.span.shrink_to_hi(),
+ format!(": {}", trait_ref.print_only_trait_path().to_string()),
+ ),
};
err.span_suggestion_verbose(
@@ -393,7 +404,7 @@
hir::Node::Item(hir::Item {
kind:
hir::ItemKind::Trait(_, _, generics, _, _)
- | hir::ItemKind::Impl { generics, .. },
+ | hir::ItemKind::Impl(hir::Impl { generics, .. }),
..
}) if projection.is_some() => {
// Missing restriction on associated type of type parameter (unmet projection).
@@ -416,7 +427,7 @@
| hir::ItemKind::Enum(_, generics)
| hir::ItemKind::Union(_, generics)
| hir::ItemKind::Trait(_, _, generics, ..)
- | hir::ItemKind::Impl { generics, .. }
+ | hir::ItemKind::Impl(hir::Impl { generics, .. })
| hir::ItemKind::Fn(_, generics, _)
| hir::ItemKind::TyAlias(_, generics)
| hir::ItemKind::TraitAlias(generics, _)
@@ -888,8 +899,10 @@
// no return, suggest removal of semicolon on last statement.
// Once that is added, close #54771.
if let Some(ref stmt) = blk.stmts.last() {
- let sp = self.tcx.sess.source_map().end_point(stmt.span);
- err.span_label(sp, "consider removing this semicolon");
+ if let hir::StmtKind::Semi(_) = stmt.kind {
+ let sp = self.tcx.sess.source_map().end_point(stmt.span);
+ err.span_label(sp, "consider removing this semicolon");
+ }
}
}
}
@@ -1292,8 +1305,8 @@
// the type. The last generator (`outer_generator` below) has information about where the
// bound was introduced. At least one generator should be present for this diagnostic to be
// modified.
- let (mut trait_ref, mut target_ty) = match obligation.predicate.skip_binders() {
- ty::PredicateAtom::Trait(p, _) => (Some(p.trait_ref), Some(p.self_ty())),
+ let (mut trait_ref, mut target_ty) = match obligation.predicate.kind().skip_binder() {
+ ty::PredicateKind::Trait(p, _) => (Some(p.trait_ref), Some(p.self_ty())),
_ => (None, None),
};
let mut generator = None;
@@ -1868,23 +1881,10 @@
ObligationCauseCode::Coercion { source: _, target } => {
err.note(&format!("required by cast to type `{}`", self.ty_to_string(target)));
}
- ObligationCauseCode::RepeatVec(suggest_const_in_array_repeat_expressions) => {
+ ObligationCauseCode::RepeatVec => {
err.note(
"the `Copy` trait is required because the repeated element will be copied",
);
- if suggest_const_in_array_repeat_expressions {
- err.note(
- "this array initializer can be evaluated at compile-time, see issue \
- #49147 <https://github.com/rust-lang/rust/issues/49147> \
- for more information",
- );
- if tcx.sess.opts.unstable_features.is_nightly_build() {
- err.help(
- "add `#![feature(const_in_array_repeat_expressions)]` to the \
- crate attributes to enable",
- );
- }
- }
}
ObligationCauseCode::VariableType(hir_id) => {
let parent_node = self.tcx.hir().get_parent_node(hir_id);
@@ -2278,6 +2278,12 @@
self.visit_expr(expr);
}
}
+ hir::ExprKind::If(_, then, else_opt) if self.in_block_tail => {
+ self.visit_expr(then);
+ if let Some(el) = else_opt {
+ self.visit_expr(el);
+ }
+ }
hir::ExprKind::Match(_, arms, _) if self.in_block_tail => {
for arm in arms {
self.visit_expr(arm.body);
diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs
index a04f816..d4ced20 100644
--- a/compiler/rustc_trait_selection/src/traits/fulfill.rs
+++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs
@@ -345,12 +345,13 @@
let infcx = self.selcx.infcx();
- match *obligation.predicate.kind() {
- ty::PredicateKind::ForAll(binder) => match binder.skip_binder() {
+ let binder = obligation.predicate.kind();
+ match binder.no_bound_vars() {
+ None => match binder.skip_binder() {
// Evaluation will discard candidates using the leak check.
// This means we need to pass it the bound version of our
// predicate.
- ty::PredicateAtom::Trait(trait_ref, _constness) => {
+ ty::PredicateKind::Trait(trait_ref, _constness) => {
let trait_obligation = obligation.with(binder.rebind(trait_ref));
self.process_trait_obligation(
@@ -359,7 +360,7 @@
&mut pending_obligation.stalled_on,
)
}
- ty::PredicateAtom::Projection(data) => {
+ ty::PredicateKind::Projection(data) => {
let project_obligation = obligation.with(binder.rebind(data));
self.process_projection_obligation(
@@ -367,25 +368,25 @@
&mut pending_obligation.stalled_on,
)
}
- ty::PredicateAtom::RegionOutlives(_)
- | ty::PredicateAtom::TypeOutlives(_)
- | ty::PredicateAtom::WellFormed(_)
- | ty::PredicateAtom::ObjectSafe(_)
- | ty::PredicateAtom::ClosureKind(..)
- | ty::PredicateAtom::Subtype(_)
- | ty::PredicateAtom::ConstEvaluatable(..)
- | ty::PredicateAtom::ConstEquate(..) => {
+ ty::PredicateKind::RegionOutlives(_)
+ | ty::PredicateKind::TypeOutlives(_)
+ | ty::PredicateKind::WellFormed(_)
+ | ty::PredicateKind::ObjectSafe(_)
+ | ty::PredicateKind::ClosureKind(..)
+ | ty::PredicateKind::Subtype(_)
+ | ty::PredicateKind::ConstEvaluatable(..)
+ | ty::PredicateKind::ConstEquate(..) => {
let pred = infcx.replace_bound_vars_with_placeholders(binder);
ProcessResult::Changed(mk_pending(vec![
obligation.with(pred.to_predicate(self.selcx.tcx())),
]))
}
- ty::PredicateAtom::TypeWellFormedFromEnv(..) => {
+ ty::PredicateKind::TypeWellFormedFromEnv(..) => {
bug!("TypeWellFormedFromEnv is only used for Chalk")
}
},
- ty::PredicateKind::Atom(atom) => match atom {
- ty::PredicateAtom::Trait(data, _) => {
+ Some(pred) => match pred {
+ ty::PredicateKind::Trait(data, _) => {
let trait_obligation = obligation.with(Binder::dummy(data));
self.process_trait_obligation(
@@ -395,14 +396,14 @@
)
}
- ty::PredicateAtom::RegionOutlives(data) => {
+ ty::PredicateKind::RegionOutlives(data) => {
match infcx.region_outlives_predicate(&obligation.cause, Binder::dummy(data)) {
Ok(()) => ProcessResult::Changed(vec![]),
Err(_) => ProcessResult::Error(CodeSelectionError(Unimplemented)),
}
}
- ty::PredicateAtom::TypeOutlives(ty::OutlivesPredicate(t_a, r_b)) => {
+ ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(t_a, r_b)) => {
if self.register_region_obligations {
self.selcx.infcx().register_region_obligation_with_cause(
t_a,
@@ -413,7 +414,7 @@
ProcessResult::Changed(vec![])
}
- ty::PredicateAtom::Projection(ref data) => {
+ ty::PredicateKind::Projection(ref data) => {
let project_obligation = obligation.with(Binder::dummy(*data));
self.process_projection_obligation(
@@ -422,7 +423,7 @@
)
}
- ty::PredicateAtom::ObjectSafe(trait_def_id) => {
+ ty::PredicateKind::ObjectSafe(trait_def_id) => {
if !self.selcx.tcx().is_object_safe(trait_def_id) {
ProcessResult::Error(CodeSelectionError(Unimplemented))
} else {
@@ -430,7 +431,7 @@
}
}
- ty::PredicateAtom::ClosureKind(_, closure_substs, kind) => {
+ ty::PredicateKind::ClosureKind(_, closure_substs, kind) => {
match self.selcx.infcx().closure_kind(closure_substs) {
Some(closure_kind) => {
if closure_kind.extends(kind) {
@@ -443,7 +444,7 @@
}
}
- ty::PredicateAtom::WellFormed(arg) => {
+ ty::PredicateKind::WellFormed(arg) => {
match wf::obligations(
self.selcx.infcx(),
obligation.param_env,
@@ -461,7 +462,7 @@
}
}
- ty::PredicateAtom::Subtype(subtype) => {
+ ty::PredicateKind::Subtype(subtype) => {
match self.selcx.infcx().subtype_predicate(
&obligation.cause,
obligation.param_env,
@@ -487,7 +488,7 @@
}
}
- ty::PredicateAtom::ConstEvaluatable(def_id, substs) => {
+ ty::PredicateKind::ConstEvaluatable(def_id, substs) => {
match const_evaluatable::is_const_evaluatable(
self.selcx.infcx(),
def_id,
@@ -507,7 +508,7 @@
}
}
- ty::PredicateAtom::ConstEquate(c1, c2) => {
+ ty::PredicateKind::ConstEquate(c1, c2) => {
debug!(?c1, ?c2, "equating consts");
if self.selcx.tcx().features().const_evaluatable_checked {
// FIXME: we probably should only try to unify abstract constants
@@ -593,7 +594,7 @@
}
}
}
- ty::PredicateAtom::TypeWellFormedFromEnv(..) => {
+ ty::PredicateKind::TypeWellFormedFromEnv(..) => {
bug!("TypeWellFormedFromEnv is only used for Chalk")
}
},
diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs
index 2fb9b3c..f7c0baf 100644
--- a/compiler/rustc_trait_selection/src/traits/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/mod.rs
@@ -6,7 +6,7 @@
mod chalk_fulfill;
pub mod codegen;
mod coherence;
-mod const_evaluatable;
+pub mod const_evaluatable;
mod engine;
pub mod error_reporting;
mod fulfill;
@@ -323,9 +323,8 @@
// This works fairly well because trait matching does not actually care about param-env
// TypeOutlives predicates - these are normally used by regionck.
let outlives_predicates: Vec<_> = predicates
- .drain_filter(|predicate| match predicate.skip_binders() {
- ty::PredicateAtom::TypeOutlives(..) => true,
- _ => false,
+ .drain_filter(|predicate| {
+ matches!(predicate.kind().skip_binder(), ty::PredicateKind::TypeOutlives(..))
})
.collect();
diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs
index 8b6e30f..e155f03 100644
--- a/compiler/rustc_trait_selection/src/traits/object_safety.rs
+++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs
@@ -257,13 +257,11 @@
}
fn bounds_reference_self(tcx: TyCtxt<'_>, trait_def_id: DefId) -> SmallVec<[Span; 1]> {
- let trait_ref = ty::Binder::dummy(ty::TraitRef::identity(tcx, trait_def_id));
tcx.associated_items(trait_def_id)
.in_definition_order()
.filter(|item| item.kind == ty::AssocKind::Type)
.flat_map(|item| tcx.explicit_item_bounds(item.def_id))
- .map(|&(predicate, sp)| (predicate.subst_supertrait(tcx, &trait_ref), sp))
- .filter_map(|predicate| predicate_references_self(tcx, predicate))
+ .filter_map(|pred_span| predicate_references_self(tcx, *pred_span))
.collect()
}
@@ -273,12 +271,12 @@
) -> Option<Span> {
let self_ty = tcx.types.self_param;
let has_self_ty = |arg: &GenericArg<'_>| arg.walk().any(|arg| arg == self_ty.into());
- match predicate.skip_binders() {
- ty::PredicateAtom::Trait(ref data, _) => {
+ match predicate.kind().skip_binder() {
+ ty::PredicateKind::Trait(ref data, _) => {
// In the case of a trait predicate, we can skip the "self" type.
if data.trait_ref.substs[1..].iter().any(has_self_ty) { Some(sp) } else { None }
}
- ty::PredicateAtom::Projection(ref data) => {
+ ty::PredicateKind::Projection(ref data) => {
// And similarly for projections. This should be redundant with
// the previous check because any projection should have a
// matching `Trait` predicate with the same inputs, but we do
@@ -300,15 +298,15 @@
None
}
}
- ty::PredicateAtom::WellFormed(..)
- | ty::PredicateAtom::ObjectSafe(..)
- | ty::PredicateAtom::TypeOutlives(..)
- | ty::PredicateAtom::RegionOutlives(..)
- | ty::PredicateAtom::ClosureKind(..)
- | ty::PredicateAtom::Subtype(..)
- | ty::PredicateAtom::ConstEvaluatable(..)
- | ty::PredicateAtom::ConstEquate(..)
- | ty::PredicateAtom::TypeWellFormedFromEnv(..) => None,
+ ty::PredicateKind::WellFormed(..)
+ | ty::PredicateKind::ObjectSafe(..)
+ | ty::PredicateKind::TypeOutlives(..)
+ | ty::PredicateKind::RegionOutlives(..)
+ | ty::PredicateKind::ClosureKind(..)
+ | ty::PredicateKind::Subtype(..)
+ | ty::PredicateKind::ConstEvaluatable(..)
+ | ty::PredicateKind::ConstEquate(..)
+ | ty::PredicateKind::TypeWellFormedFromEnv(..) => None,
}
}
@@ -328,20 +326,20 @@
let predicates = tcx.predicates_of(def_id);
let predicates = predicates.instantiate_identity(tcx).predicates;
elaborate_predicates(tcx, predicates.into_iter()).any(|obligation| {
- match obligation.predicate.skip_binders() {
- ty::PredicateAtom::Trait(ref trait_pred, _) => {
+ match obligation.predicate.kind().skip_binder() {
+ ty::PredicateKind::Trait(ref trait_pred, _) => {
trait_pred.def_id() == sized_def_id && trait_pred.self_ty().is_param(0)
}
- ty::PredicateAtom::Projection(..)
- | ty::PredicateAtom::Subtype(..)
- | ty::PredicateAtom::RegionOutlives(..)
- | ty::PredicateAtom::WellFormed(..)
- | ty::PredicateAtom::ObjectSafe(..)
- | ty::PredicateAtom::ClosureKind(..)
- | ty::PredicateAtom::TypeOutlives(..)
- | ty::PredicateAtom::ConstEvaluatable(..)
- | ty::PredicateAtom::ConstEquate(..)
- | ty::PredicateAtom::TypeWellFormedFromEnv(..) => false,
+ ty::PredicateKind::Projection(..)
+ | ty::PredicateKind::Subtype(..)
+ | ty::PredicateKind::RegionOutlives(..)
+ | ty::PredicateKind::WellFormed(..)
+ | ty::PredicateKind::ObjectSafe(..)
+ | ty::PredicateKind::ClosureKind(..)
+ | ty::PredicateKind::TypeOutlives(..)
+ | ty::PredicateKind::ConstEvaluatable(..)
+ | ty::PredicateKind::ConstEquate(..)
+ | ty::PredicateKind::TypeWellFormedFromEnv(..) => false,
}
})
}
@@ -828,7 +826,7 @@
// constants which are not considered const evaluatable.
use rustc_middle::mir::abstract_const::Node;
if let Ok(Some(ct)) = AbstractConst::from_const(self.tcx, ct) {
- const_evaluatable::walk_abstract_const(self.tcx, ct, |node| match node {
+ const_evaluatable::walk_abstract_const(self.tcx, ct, |node| match node.root() {
Node::Leaf(leaf) => {
let leaf = leaf.subst(self.tcx, ct.substs);
self.visit_const(leaf)
@@ -843,13 +841,13 @@
}
fn visit_predicate(&mut self, pred: ty::Predicate<'tcx>) -> ControlFlow<Self::BreakTy> {
- if let ty::PredicateAtom::ConstEvaluatable(def, substs) = pred.skip_binders() {
+ if let ty::PredicateKind::ConstEvaluatable(def, substs) = pred.kind().skip_binder() {
// FIXME(const_evaluatable_checked): We should probably deduplicate the logic for
// `AbstractConst`s here, it might make sense to change `ConstEvaluatable` to
// take a `ty::Const` instead.
use rustc_middle::mir::abstract_const::Node;
if let Ok(Some(ct)) = AbstractConst::new(self.tcx, def, substs) {
- const_evaluatable::walk_abstract_const(self.tcx, ct, |node| match node {
+ const_evaluatable::walk_abstract_const(self.tcx, ct, |node| match node.root() {
Node::Leaf(leaf) => {
let leaf = leaf.subst(self.tcx, ct.substs);
self.visit_const(leaf)
diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs
index f22b5b9..6908480 100644
--- a/compiler/rustc_trait_selection/src/traits/project.rs
+++ b/compiler/rustc_trait_selection/src/traits/project.rs
@@ -625,7 +625,7 @@
.obligations
.iter()
.filter(|obligation| {
- let bound_predicate = obligation.predicate.bound_atom();
+ let bound_predicate = obligation.predicate.kind();
match bound_predicate.skip_binder() {
// We found a `T: Foo<X = U>` predicate, let's check
// if `U` references any unresolved type
@@ -636,7 +636,7 @@
// indirect obligations (e.g., we project to `?0`,
// but we have `T: Foo<X = ?1>` and `?1: Bar<X =
// ?0>`).
- ty::PredicateAtom::Projection(data) => {
+ ty::PredicateKind::Projection(data) => {
infcx.unresolved_type_vars(&bound_predicate.rebind(data.ty)).is_some()
}
@@ -912,8 +912,8 @@
let infcx = selcx.infcx();
for predicate in env_predicates {
debug!(?predicate);
- let bound_predicate = predicate.bound_atom();
- if let ty::PredicateAtom::Projection(data) = predicate.skip_binders() {
+ let bound_predicate = predicate.kind();
+ if let ty::PredicateKind::Projection(data) = predicate.kind().skip_binder() {
let data = bound_predicate.rebind(data);
let same_def_id = data.projection_def_id() == obligation.predicate.item_def_id;
diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs
index 93ddcb6..de538c6 100644
--- a/compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs
@@ -15,7 +15,7 @@
// `&T`, accounts for about 60% percentage of the predicates
// we have to prove. No need to canonicalize and all that for
// such cases.
- if let ty::PredicateAtom::Trait(trait_ref, _) = key.value.predicate.skip_binders() {
+ if let ty::PredicateKind::Trait(trait_ref, _) = key.value.predicate.kind().skip_binder() {
if let Some(sized_def_id) = tcx.lang_items().sized_trait() {
if trait_ref.def_id() == sized_def_id {
if trait_ref.self_ty().is_trivially_sized(tcx) {
diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
index ca3369b..f09ce8d 100644
--- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
@@ -247,7 +247,7 @@
let mut candidates = SelectionCandidateSet { vec: Vec::new(), ambiguous: false };
- self.assemble_candidates_for_trait_alias(obligation, &mut candidates)?;
+ self.assemble_candidates_for_trait_alias(obligation, &mut candidates);
// Other bounds. Consider both in-scope bounds from fn decl
// and applicable impls. There is a certain set of precedence rules here.
@@ -259,11 +259,11 @@
// User-defined copy impls are permitted, but only for
// structs and enums.
- self.assemble_candidates_from_impls(obligation, &mut candidates)?;
+ self.assemble_candidates_from_impls(obligation, &mut candidates);
// For other types, we'll use the builtin rules.
let copy_conditions = self.copy_clone_conditions(obligation);
- self.assemble_builtin_bound_candidates(copy_conditions, &mut candidates)?;
+ self.assemble_builtin_bound_candidates(copy_conditions, &mut candidates);
} else if lang_items.discriminant_kind_trait() == Some(def_id) {
// `DiscriminantKind` is automatically implemented for every type.
candidates.vec.push(DiscriminantKindCandidate);
@@ -271,7 +271,7 @@
// Sized is never implementable by end-users, it is
// always automatically computed.
let sized_conditions = self.sized_conditions(obligation);
- self.assemble_builtin_bound_candidates(sized_conditions, &mut candidates)?;
+ self.assemble_builtin_bound_candidates(sized_conditions, &mut candidates);
} else if lang_items.unsize_trait() == Some(def_id) {
self.assemble_candidates_for_unsizing(obligation, &mut candidates);
} else {
@@ -280,13 +280,13 @@
// for `Copy` also has builtin support for `Clone`, and tuples/arrays of `Clone`
// types have builtin support for `Clone`.
let clone_conditions = self.copy_clone_conditions(obligation);
- self.assemble_builtin_bound_candidates(clone_conditions, &mut candidates)?;
+ self.assemble_builtin_bound_candidates(clone_conditions, &mut candidates);
}
- self.assemble_generator_candidates(obligation, &mut candidates)?;
- self.assemble_closure_candidates(obligation, &mut candidates)?;
- self.assemble_fn_pointer_candidates(obligation, &mut candidates)?;
- self.assemble_candidates_from_impls(obligation, &mut candidates)?;
+ self.assemble_generator_candidates(obligation, &mut candidates);
+ self.assemble_closure_candidates(obligation, &mut candidates);
+ self.assemble_fn_pointer_candidates(obligation, &mut candidates);
+ self.assemble_candidates_from_impls(obligation, &mut candidates);
self.assemble_candidates_from_object_ty(obligation, &mut candidates);
}
@@ -295,7 +295,7 @@
// Auto implementations have lower priority, so we only
// consider triggering a default if there is no other impl that can apply.
if candidates.vec.is_empty() {
- self.assemble_candidates_from_auto_impls(obligation, &mut candidates)?;
+ self.assemble_candidates_from_auto_impls(obligation, &mut candidates);
}
debug!("candidate list size: {}", candidates.vec.len());
Ok(candidates)
@@ -367,9 +367,9 @@
&mut self,
obligation: &TraitObligation<'tcx>,
candidates: &mut SelectionCandidateSet<'tcx>,
- ) -> Result<(), SelectionError<'tcx>> {
+ ) {
if self.tcx().lang_items().gen_trait() != Some(obligation.predicate.def_id()) {
- return Ok(());
+ return;
}
// Okay to skip binder because the substs on generator types never
@@ -388,8 +388,6 @@
}
_ => {}
}
-
- Ok(())
}
/// Checks for the artificial impl that the compiler will create for an obligation like `X :
@@ -402,11 +400,11 @@
&mut self,
obligation: &TraitObligation<'tcx>,
candidates: &mut SelectionCandidateSet<'tcx>,
- ) -> Result<(), SelectionError<'tcx>> {
+ ) {
let kind = match self.tcx().fn_trait_kind_from_lang_item(obligation.predicate.def_id()) {
Some(k) => k,
None => {
- return Ok(());
+ return;
}
};
@@ -435,8 +433,6 @@
}
_ => {}
}
-
- Ok(())
}
/// Implements one of the `Fn()` family for a fn pointer.
@@ -444,10 +440,10 @@
&mut self,
obligation: &TraitObligation<'tcx>,
candidates: &mut SelectionCandidateSet<'tcx>,
- ) -> Result<(), SelectionError<'tcx>> {
+ ) {
// We provide impl of all fn traits for fn pointers.
if self.tcx().fn_trait_kind_from_lang_item(obligation.predicate.def_id()).is_none() {
- return Ok(());
+ return;
}
// Okay to skip binder because what we are inspecting doesn't involve bound regions.
@@ -485,8 +481,6 @@
}
_ => {}
}
-
- Ok(())
}
/// Searches for impls that might apply to `obligation`.
@@ -494,7 +488,7 @@
&mut self,
obligation: &TraitObligation<'tcx>,
candidates: &mut SelectionCandidateSet<'tcx>,
- ) -> Result<(), SelectionError<'tcx>> {
+ ) {
debug!(?obligation, "assemble_candidates_from_impls");
// Essentially any user-written impl will match with an error type,
@@ -504,7 +498,7 @@
// Since compilation is already guaranteed to fail, this is just
// to try to show the 'nicest' possible errors to the user.
if obligation.references_error() {
- return Ok(());
+ return;
}
self.tcx().for_each_relevant_impl(
@@ -518,15 +512,13 @@
});
},
);
-
- Ok(())
}
fn assemble_candidates_from_auto_impls(
&mut self,
obligation: &TraitObligation<'tcx>,
candidates: &mut SelectionCandidateSet<'tcx>,
- ) -> Result<(), SelectionError<'tcx>> {
+ ) {
// Okay to skip binder here because the tests we do below do not involve bound regions.
let self_ty = obligation.self_ty().skip_binder();
debug!(?self_ty, "assemble_candidates_from_auto_impls");
@@ -558,7 +550,7 @@
// where-clause or, in the case of an object type,
// it could be that the object type lists the
// trait (e.g., `Foo+Send : Send`). See
- // `compile-fail/typeck-default-trait-impl-send-param.rs`
+ // `ui/typeck/typeck-default-trait-impl-send-param.rs`
// for an example of a test case that exercises
// this path.
}
@@ -585,8 +577,6 @@
_ => candidates.vec.push(AutoImplCandidate(def_id)),
}
}
-
- Ok(())
}
/// Searches for impls that might apply to `obligation`.
@@ -753,7 +743,7 @@
&mut self,
obligation: &TraitObligation<'tcx>,
candidates: &mut SelectionCandidateSet<'tcx>,
- ) -> Result<(), SelectionError<'tcx>> {
+ ) {
// Okay to skip binder here because the tests we do below do not involve bound regions.
let self_ty = obligation.self_ty().skip_binder();
debug!(?self_ty, "assemble_candidates_for_trait_alias");
@@ -763,8 +753,6 @@
if self.tcx().is_trait_alias(def_id) {
candidates.vec.push(TraitAliasCandidate(def_id));
}
-
- Ok(())
}
/// Assembles the trait which are built-in to the language itself:
@@ -773,7 +761,7 @@
&mut self,
conditions: BuiltinImplConditions<'tcx>,
candidates: &mut SelectionCandidateSet<'tcx>,
- ) -> Result<(), SelectionError<'tcx>> {
+ ) {
match conditions {
BuiltinImplConditions::Where(nested) => {
debug!(?nested, "builtin_bound");
@@ -787,7 +775,5 @@
candidates.ambiguous = true;
}
}
-
- Ok(())
}
}
diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
index 030c291..ed3e117 100644
--- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
@@ -432,7 +432,7 @@
.predicates
.into_iter()
{
- if let ty::PredicateAtom::Trait(..) = super_trait.skip_binders() {
+ if let ty::PredicateKind::Trait(..) = super_trait.kind().skip_binder() {
let normalized_super_trait = normalize_with_depth_to(
self,
obligation.param_env,
@@ -641,7 +641,7 @@
obligations.push(Obligation::new(
obligation.cause.clone(),
obligation.param_env,
- ty::PredicateAtom::ClosureKind(closure_def_id, substs, kind)
+ ty::PredicateKind::ClosureKind(closure_def_id, substs, kind)
.to_predicate(self.tcx()),
));
}
@@ -823,33 +823,59 @@
},
};
+ // FIXME(eddyb) cache this (including computing `unsizing_params`)
+ // by putting it in a query; it would only need the `DefId` as it
+ // looks at declared field types, not anything substituted.
+
// The last field of the structure has to exist and contain type/const parameters.
let (tail_field, prefix_fields) =
def.non_enum_variant().fields.split_last().ok_or(Unimplemented)?;
let tail_field_ty = tcx.type_of(tail_field.did);
let mut unsizing_params = GrowableBitSet::new_empty();
- let mut found = false;
- for arg in tail_field_ty.walk() {
- if let Some(i) = maybe_unsizing_param_idx(arg) {
- unsizing_params.insert(i);
- found = true;
- }
- }
- if !found {
- return Err(Unimplemented);
- }
-
- // Ensure none of the other fields mention the parameters used
- // in unsizing.
- // FIXME(eddyb) cache this (including computing `unsizing_params`)
- // by putting it in a query; it would only need the `DefId` as it
- // looks at declared field types, not anything substituted.
- for field in prefix_fields {
- for arg in tcx.type_of(field.did).walk() {
+ if tcx.features().relaxed_struct_unsize {
+ for arg in tail_field_ty.walk() {
if let Some(i) = maybe_unsizing_param_idx(arg) {
- if unsizing_params.contains(i) {
- return Err(Unimplemented);
+ unsizing_params.insert(i);
+ }
+ }
+
+ // Ensure none of the other fields mention the parameters used
+ // in unsizing.
+ for field in prefix_fields {
+ for arg in tcx.type_of(field.did).walk() {
+ if let Some(i) = maybe_unsizing_param_idx(arg) {
+ unsizing_params.remove(i);
+ }
+ }
+ }
+
+ if unsizing_params.is_empty() {
+ return Err(Unimplemented);
+ }
+ } else {
+ let mut found = false;
+ for arg in tail_field_ty.walk() {
+ if let Some(i) = maybe_unsizing_param_idx(arg) {
+ unsizing_params.insert(i);
+ found = true;
+ }
+ }
+ if !found {
+ return Err(Unimplemented);
+ }
+
+ // Ensure none of the other fields mention the parameters used
+ // in unsizing.
+ // FIXME(eddyb) cache this (including computing `unsizing_params`)
+ // by putting it in a query; it would only need the `DefId` as it
+ // looks at declared field types, not anything substituted.
+ for field in prefix_fields {
+ for arg in tcx.type_of(field.did).walk() {
+ if let Some(i) = maybe_unsizing_param_idx(arg) {
+ if unsizing_params.contains(i) {
+ return Err(Unimplemented);
+ }
}
}
}
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index f1c86ea..87c8099 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -69,16 +69,16 @@
pub fn intercrate_ambiguity_hint(&self) -> String {
match self {
- &IntercrateAmbiguityCause::DownstreamCrate { ref trait_desc, ref self_desc } => {
- let self_desc = if let &Some(ref ty) = self_desc {
+ IntercrateAmbiguityCause::DownstreamCrate { trait_desc, self_desc } => {
+ let self_desc = if let Some(ty) = self_desc {
format!(" for type `{}`", ty)
} else {
String::new()
};
format!("downstream crates may implement trait `{}`{}", trait_desc, self_desc)
}
- &IntercrateAmbiguityCause::UpstreamCrateUpdate { ref trait_desc, ref self_desc } => {
- let self_desc = if let &Some(ref ty) = self_desc {
+ IntercrateAmbiguityCause::UpstreamCrateUpdate { trait_desc, self_desc } => {
+ let self_desc = if let Some(ty) = self_desc {
format!(" for type `{}`", ty)
} else {
String::new()
@@ -89,7 +89,7 @@
trait_desc, self_desc
)
}
- &IntercrateAmbiguityCause::ReservationImpl { ref message } => message.clone(),
+ IntercrateAmbiguityCause::ReservationImpl { message } => message.clone(),
}
}
}
@@ -450,16 +450,16 @@
}
let result = ensure_sufficient_stack(|| {
- let bound_predicate = obligation.predicate.bound_atom();
+ let bound_predicate = obligation.predicate.kind();
match bound_predicate.skip_binder() {
- ty::PredicateAtom::Trait(t, _) => {
+ ty::PredicateKind::Trait(t, _) => {
let t = bound_predicate.rebind(t);
debug_assert!(!t.has_escaping_bound_vars());
let obligation = obligation.with(t);
self.evaluate_trait_predicate_recursively(previous_stack, obligation)
}
- ty::PredicateAtom::Subtype(p) => {
+ ty::PredicateKind::Subtype(p) => {
let p = bound_predicate.rebind(p);
// Does this code ever run?
match self.infcx.subtype_predicate(&obligation.cause, obligation.param_env, p) {
@@ -475,7 +475,7 @@
}
}
- ty::PredicateAtom::WellFormed(arg) => match wf::obligations(
+ ty::PredicateKind::WellFormed(arg) => match wf::obligations(
self.infcx,
obligation.param_env,
obligation.cause.body_id,
@@ -490,12 +490,12 @@
None => Ok(EvaluatedToAmbig),
},
- ty::PredicateAtom::TypeOutlives(..) | ty::PredicateAtom::RegionOutlives(..) => {
+ ty::PredicateKind::TypeOutlives(..) | ty::PredicateKind::RegionOutlives(..) => {
// We do not consider region relationships when evaluating trait matches.
Ok(EvaluatedToOkModuloRegions)
}
- ty::PredicateAtom::ObjectSafe(trait_def_id) => {
+ ty::PredicateKind::ObjectSafe(trait_def_id) => {
if self.tcx().is_object_safe(trait_def_id) {
Ok(EvaluatedToOk)
} else {
@@ -503,7 +503,7 @@
}
}
- ty::PredicateAtom::Projection(data) => {
+ ty::PredicateKind::Projection(data) => {
let data = bound_predicate.rebind(data);
let project_obligation = obligation.with(data);
match project::poly_project_and_unify_type(self, &project_obligation) {
@@ -524,7 +524,7 @@
}
}
- ty::PredicateAtom::ClosureKind(_, closure_substs, kind) => {
+ ty::PredicateKind::ClosureKind(_, closure_substs, kind) => {
match self.infcx.closure_kind(closure_substs) {
Some(closure_kind) => {
if closure_kind.extends(kind) {
@@ -537,7 +537,7 @@
}
}
- ty::PredicateAtom::ConstEvaluatable(def_id, substs) => {
+ ty::PredicateKind::ConstEvaluatable(def_id, substs) => {
match const_evaluatable::is_const_evaluatable(
self.infcx,
def_id,
@@ -551,7 +551,7 @@
}
}
- ty::PredicateAtom::ConstEquate(c1, c2) => {
+ ty::PredicateKind::ConstEquate(c1, c2) => {
debug!(?c1, ?c2, "evaluate_predicate_recursively: equating consts");
let evaluate = |c: &'tcx ty::Const<'tcx>| {
@@ -594,7 +594,7 @@
}
}
}
- ty::PredicateAtom::TypeWellFormedFromEnv(..) => {
+ ty::PredicateKind::TypeWellFormedFromEnv(..) => {
bug!("TypeWellFormedFromEnv is only used for chalk")
}
}
@@ -841,8 +841,8 @@
}
fn coinductive_predicate(&self, predicate: ty::Predicate<'tcx>) -> bool {
- let result = match predicate.skip_binders() {
- ty::PredicateAtom::Trait(ref data, _) => self.tcx().trait_is_auto(data.def_id()),
+ let result = match predicate.kind().skip_binder() {
+ ty::PredicateKind::Trait(ref data, _) => self.tcx().trait_is_auto(data.def_id()),
_ => false,
};
debug!(?predicate, ?result, "coinductive_predicate");
@@ -1170,8 +1170,8 @@
.iter()
.enumerate()
.filter_map(|(idx, bound)| {
- let bound_predicate = bound.bound_atom();
- if let ty::PredicateAtom::Trait(pred, _) = bound_predicate.skip_binder() {
+ let bound_predicate = bound.kind();
+ if let ty::PredicateKind::Trait(pred, _) = bound_predicate.skip_binder() {
let bound = bound_predicate.rebind(pred.trait_ref);
if self.infcx.probe(|_| {
match self.match_normalize_trait_ref(
diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs
index 3f58fd7..e6ef9b1 100644
--- a/compiler/rustc_trait_selection/src/traits/wf.rs
+++ b/compiler/rustc_trait_selection/src/traits/wf.rs
@@ -106,28 +106,28 @@
};
// It's ok to skip the binder here because wf code is prepared for it
- match predicate.skip_binders() {
- ty::PredicateAtom::Trait(t, _) => {
+ match predicate.kind().skip_binder() {
+ ty::PredicateKind::Trait(t, _) => {
wf.compute_trait_ref(&t.trait_ref, Elaborate::None);
}
- ty::PredicateAtom::RegionOutlives(..) => {}
- ty::PredicateAtom::TypeOutlives(ty::OutlivesPredicate(ty, _reg)) => {
+ ty::PredicateKind::RegionOutlives(..) => {}
+ ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(ty, _reg)) => {
wf.compute(ty.into());
}
- ty::PredicateAtom::Projection(t) => {
+ ty::PredicateKind::Projection(t) => {
wf.compute_projection(t.projection_ty);
wf.compute(t.ty.into());
}
- ty::PredicateAtom::WellFormed(arg) => {
+ ty::PredicateKind::WellFormed(arg) => {
wf.compute(arg);
}
- ty::PredicateAtom::ObjectSafe(_) => {}
- ty::PredicateAtom::ClosureKind(..) => {}
- ty::PredicateAtom::Subtype(ty::SubtypePredicate { a, b, a_is_expected: _ }) => {
+ ty::PredicateKind::ObjectSafe(_) => {}
+ ty::PredicateKind::ClosureKind(..) => {}
+ ty::PredicateKind::Subtype(ty::SubtypePredicate { a, b, a_is_expected: _ }) => {
wf.compute(a.into());
wf.compute(b.into());
}
- ty::PredicateAtom::ConstEvaluatable(def, substs) => {
+ ty::PredicateKind::ConstEvaluatable(def, substs) => {
let obligations = wf.nominal_obligations(def.did, substs);
wf.out.extend(obligations);
@@ -135,11 +135,11 @@
wf.compute(arg);
}
}
- ty::PredicateAtom::ConstEquate(c1, c2) => {
+ ty::PredicateKind::ConstEquate(c1, c2) => {
wf.compute(c1.into());
wf.compute(c2.into());
}
- ty::PredicateAtom::TypeWellFormedFromEnv(..) => {
+ ty::PredicateKind::TypeWellFormedFromEnv(..) => {
bug!("TypeWellFormedFromEnv is only used for Chalk")
}
}
@@ -199,7 +199,7 @@
trait_ref, item, cause, pred
);
let items = match item {
- Some(hir::Item { kind: hir::ItemKind::Impl { items, .. }, .. }) => items,
+ Some(hir::Item { kind: hir::ItemKind::Impl(impl_), .. }) => impl_.items,
_ => return,
};
let fix_span =
@@ -209,8 +209,8 @@
};
// It is fine to skip the binder as we don't care about regions here.
- match pred.skip_binders() {
- ty::PredicateAtom::Projection(proj) => {
+ match pred.kind().skip_binder() {
+ ty::PredicateKind::Projection(proj) => {
// The obligation comes not from the current `impl` nor the `trait` being implemented,
// but rather from a "second order" obligation, where an associated type has a
// projection coming from another associated type. See
@@ -225,7 +225,7 @@
}
}
}
- ty::PredicateAtom::Trait(pred, _) => {
+ ty::PredicateKind::Trait(pred, _) => {
// An associated item obligation born out of the `trait` failed to be met. An example
// 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);
@@ -333,7 +333,9 @@
let mut new_cause = cause.clone();
// The first subst is the self ty - use the correct span for it.
if i == 0 {
- if let Some(hir::ItemKind::Impl { self_ty, .. }) = item.map(|i| &i.kind) {
+ if let Some(hir::ItemKind::Impl(hir::Impl { self_ty, .. })) =
+ item.map(|i| &i.kind)
+ {
new_cause.make_mut().span = self_ty.span;
}
}
@@ -341,7 +343,7 @@
new_cause,
depth,
param_env,
- ty::PredicateAtom::WellFormed(arg).to_predicate(tcx),
+ ty::PredicateKind::WellFormed(arg).to_predicate(tcx),
)
}),
);
@@ -391,7 +393,7 @@
cause.clone(),
depth,
param_env,
- ty::PredicateAtom::WellFormed(arg).to_predicate(tcx),
+ ty::PredicateKind::WellFormed(arg).to_predicate(tcx),
)
}),
);
@@ -434,7 +436,7 @@
let obligations = self.nominal_obligations(def.did, substs);
self.out.extend(obligations);
- let predicate = ty::PredicateAtom::ConstEvaluatable(def, substs)
+ let predicate = ty::PredicateKind::ConstEvaluatable(def, substs)
.to_predicate(self.tcx());
let cause = self.cause(traits::MiscObligation);
self.out.push(traits::Obligation::with_depth(
@@ -458,7 +460,7 @@
cause,
self.recursion_depth,
self.param_env,
- ty::PredicateAtom::WellFormed(resolved_constant.into())
+ ty::PredicateKind::WellFormed(resolved_constant.into())
.to_predicate(self.tcx()),
));
}
@@ -545,7 +547,7 @@
cause,
depth,
param_env,
- ty::PredicateAtom::TypeOutlives(ty::OutlivesPredicate(rty, r))
+ ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(rty, r))
.to_predicate(self.tcx()),
));
}
@@ -635,7 +637,7 @@
cause.clone(),
depth,
param_env,
- ty::PredicateAtom::ObjectSafe(did).to_predicate(tcx),
+ ty::PredicateKind::ObjectSafe(did).to_predicate(tcx),
)
}));
}
@@ -662,7 +664,7 @@
cause,
self.recursion_depth,
param_env,
- ty::PredicateAtom::WellFormed(ty.into()).to_predicate(self.tcx()),
+ ty::PredicateKind::WellFormed(ty.into()).to_predicate(self.tcx()),
));
} else {
// Yes, resolved, proceed with the result.
diff --git a/compiler/rustc_traits/Cargo.toml b/compiler/rustc_traits/Cargo.toml
index 8bd9e29..8fdbc3b 100644
--- a/compiler/rustc_traits/Cargo.toml
+++ b/compiler/rustc_traits/Cargo.toml
@@ -6,15 +6,16 @@
[dependencies]
tracing = "0.1"
+rustc_attr = { path = "../rustc_attr" }
rustc_middle = { path = "../rustc_middle" }
rustc_data_structures = { path = "../rustc_data_structures" }
rustc_hir = { path = "../rustc_hir" }
rustc_index = { path = "../rustc_index" }
rustc_ast = { path = "../rustc_ast" }
rustc_span = { path = "../rustc_span" }
-chalk-ir = "0.36.0"
-chalk-solve = "0.36.0"
-chalk-engine = "0.36.0"
+chalk-ir = "0.55.0"
+chalk-solve = "0.55.0"
+chalk-engine = "0.55.0"
smallvec = { version = "1.0", features = ["union", "may_dangle"] }
rustc_infer = { path = "../rustc_infer" }
rustc_trait_selection = { path = "../rustc_trait_selection" }
diff --git a/compiler/rustc_traits/src/chalk/db.rs b/compiler/rustc_traits/src/chalk/db.rs
index 1893d74..916186f 100644
--- a/compiler/rustc_traits/src/chalk/db.rs
+++ b/compiler/rustc_traits/src/chalk/db.rs
@@ -10,6 +10,9 @@
use rustc_middle::ty::subst::{InternalSubsts, Subst, SubstsRef};
use rustc_middle::ty::{self, AssocItemContainer, AssocKind, TyCtxt, TypeFoldable};
+use rustc_ast::ast;
+use rustc_attr as attr;
+
use rustc_hir::def_id::DefId;
use rustc_span::symbol::sym;
@@ -18,7 +21,6 @@
use std::sync::Arc;
use crate::chalk::lowering::{self, LowerInto};
-use rustc_ast::ast;
pub struct RustIrDatabase<'tcx> {
pub(crate) interner: RustInterner<'tcx>,
@@ -205,12 +207,32 @@
fn adt_repr(
&self,
adt_id: chalk_ir::AdtId<RustInterner<'tcx>>,
- ) -> chalk_solve::rust_ir::AdtRepr {
+ ) -> Arc<chalk_solve::rust_ir::AdtRepr<RustInterner<'tcx>>> {
let adt_def = adt_id.0;
- chalk_solve::rust_ir::AdtRepr {
- repr_c: adt_def.repr.c(),
- repr_packed: adt_def.repr.packed(),
- }
+ let int = |i| chalk_ir::TyKind::Scalar(chalk_ir::Scalar::Int(i)).intern(&self.interner);
+ let uint = |i| chalk_ir::TyKind::Scalar(chalk_ir::Scalar::Uint(i)).intern(&self.interner);
+ Arc::new(chalk_solve::rust_ir::AdtRepr {
+ c: adt_def.repr.c(),
+ packed: adt_def.repr.packed(),
+ int: adt_def.repr.int.map(|i| match i {
+ attr::IntType::SignedInt(ty) => match ty {
+ ast::IntTy::Isize => int(chalk_ir::IntTy::Isize),
+ ast::IntTy::I8 => int(chalk_ir::IntTy::I8),
+ ast::IntTy::I16 => int(chalk_ir::IntTy::I16),
+ ast::IntTy::I32 => int(chalk_ir::IntTy::I32),
+ ast::IntTy::I64 => int(chalk_ir::IntTy::I64),
+ ast::IntTy::I128 => int(chalk_ir::IntTy::I128),
+ },
+ attr::IntType::UnsignedInt(ty) => match ty {
+ ast::UintTy::Usize => uint(chalk_ir::UintTy::Usize),
+ ast::UintTy::U8 => uint(chalk_ir::UintTy::U8),
+ ast::UintTy::U16 => uint(chalk_ir::UintTy::U16),
+ ast::UintTy::U32 => uint(chalk_ir::UintTy::U32),
+ ast::UintTy::U64 => uint(chalk_ir::UintTy::U64),
+ ast::UintTy::U128 => uint(chalk_ir::UintTy::U128),
+ },
+ }),
+ })
}
fn fn_def_datum(
@@ -316,7 +338,11 @@
let self_ty = self_ty.fold_with(&mut regions_substitutor);
let lowered_ty = self_ty.lower_into(&self.interner);
- parameters[0].assert_ty_ref(&self.interner).could_match(&self.interner, &lowered_ty)
+ parameters[0].assert_ty_ref(&self.interner).could_match(
+ &self.interner,
+ self.unification_database(),
+ &lowered_ty,
+ )
});
let impls = matched_impls.map(chalk_ir::ImplId).collect();
@@ -346,26 +372,26 @@
(ty::Char, Scalar(Char)) => true,
(ty::Int(ty1), Scalar(Int(ty2))) => matches!(
(ty1, ty2),
- (ast::IntTy::Isize, chalk_ir::IntTy::Isize)
- | (ast::IntTy::I8, chalk_ir::IntTy::I8)
- | (ast::IntTy::I16, chalk_ir::IntTy::I16)
- | (ast::IntTy::I32, chalk_ir::IntTy::I32)
- | (ast::IntTy::I64, chalk_ir::IntTy::I64)
- | (ast::IntTy::I128, chalk_ir::IntTy::I128)
+ (ty::IntTy::Isize, chalk_ir::IntTy::Isize)
+ | (ty::IntTy::I8, chalk_ir::IntTy::I8)
+ | (ty::IntTy::I16, chalk_ir::IntTy::I16)
+ | (ty::IntTy::I32, chalk_ir::IntTy::I32)
+ | (ty::IntTy::I64, chalk_ir::IntTy::I64)
+ | (ty::IntTy::I128, chalk_ir::IntTy::I128)
),
(ty::Uint(ty1), Scalar(Uint(ty2))) => matches!(
(ty1, ty2),
- (ast::UintTy::Usize, chalk_ir::UintTy::Usize)
- | (ast::UintTy::U8, chalk_ir::UintTy::U8)
- | (ast::UintTy::U16, chalk_ir::UintTy::U16)
- | (ast::UintTy::U32, chalk_ir::UintTy::U32)
- | (ast::UintTy::U64, chalk_ir::UintTy::U64)
- | (ast::UintTy::U128, chalk_ir::UintTy::U128)
+ (ty::UintTy::Usize, chalk_ir::UintTy::Usize)
+ | (ty::UintTy::U8, chalk_ir::UintTy::U8)
+ | (ty::UintTy::U16, chalk_ir::UintTy::U16)
+ | (ty::UintTy::U32, chalk_ir::UintTy::U32)
+ | (ty::UintTy::U64, chalk_ir::UintTy::U64)
+ | (ty::UintTy::U128, chalk_ir::UintTy::U128)
),
(ty::Float(ty1), Scalar(Float(ty2))) => matches!(
(ty1, ty2),
- (ast::FloatTy::F32, chalk_ir::FloatTy::F32)
- | (ast::FloatTy::F64, chalk_ir::FloatTy::F64)
+ (ty::FloatTy::F32, chalk_ir::FloatTy::F32)
+ | (ty::FloatTy::F64, chalk_ir::FloatTy::F64)
),
(&ty::Tuple(substs), Tuple(len, _)) => substs.len() == *len,
(&ty::Array(..), Array(..)) => true,
@@ -541,6 +567,7 @@
Unsize => lang_items.unsize_trait(),
Unpin => lang_items.unpin_trait(),
CoerceUnsized => lang_items.coerce_unsized_trait(),
+ DiscriminantKind => lang_items.discriminant_kind_trait(),
};
def_id.map(chalk_ir::TraitId)
}
@@ -586,7 +613,7 @@
let sig = &substs.as_slice(&self.interner)[substs.len(&self.interner) - 2];
match sig.assert_ty_ref(&self.interner).kind(&self.interner) {
chalk_ir::TyKind::Function(f) => {
- let substitution = f.substitution.as_slice(&self.interner);
+ let substitution = f.substitution.0.as_slice(&self.interner);
let return_type =
substitution.last().unwrap().assert_ty_ref(&self.interner).clone();
// Closure arguments are tupled
@@ -644,6 +671,51 @@
) -> Arc<chalk_solve::rust_ir::GeneratorWitnessDatum<RustInterner<'tcx>>> {
unimplemented!()
}
+
+ fn unification_database(&self) -> &dyn chalk_ir::UnificationDatabase<RustInterner<'tcx>> {
+ self
+ }
+
+ fn discriminant_type(
+ &self,
+ _: chalk_ir::Ty<RustInterner<'tcx>>,
+ ) -> chalk_ir::Ty<RustInterner<'tcx>> {
+ unimplemented!()
+ }
+}
+
+impl<'tcx> chalk_ir::UnificationDatabase<RustInterner<'tcx>> for RustIrDatabase<'tcx> {
+ fn fn_def_variance(
+ &self,
+ def_id: chalk_ir::FnDefId<RustInterner<'tcx>>,
+ ) -> chalk_ir::Variances<RustInterner<'tcx>> {
+ let variances = self.interner.tcx.variances_of(def_id.0);
+ chalk_ir::Variances::from_iter(
+ &self.interner,
+ variances.iter().map(|v| match v {
+ ty::Variance::Invariant => chalk_ir::Variance::Invariant,
+ ty::Variance::Covariant => chalk_ir::Variance::Covariant,
+ ty::Variance::Contravariant => chalk_ir::Variance::Contravariant,
+ ty::Variance::Bivariant => unimplemented!(),
+ }),
+ )
+ }
+
+ fn adt_variance(
+ &self,
+ def_id: chalk_ir::AdtId<RustInterner<'tcx>>,
+ ) -> chalk_ir::Variances<RustInterner<'tcx>> {
+ let variances = self.interner.tcx.variances_of(def_id.0.did);
+ chalk_ir::Variances::from_iter(
+ &self.interner,
+ variances.iter().map(|v| match v {
+ ty::Variance::Invariant => chalk_ir::Variance::Invariant,
+ ty::Variance::Covariant => chalk_ir::Variance::Covariant,
+ ty::Variance::Contravariant => chalk_ir::Variance::Contravariant,
+ ty::Variance::Bivariant => unimplemented!(),
+ }),
+ )
+ }
}
/// Creates a `InternalSubsts` that maps each generic parameter to a higher-ranked
diff --git a/compiler/rustc_traits/src/chalk/lowering.rs b/compiler/rustc_traits/src/chalk/lowering.rs
index 8aa68e5..7d3589c 100644
--- a/compiler/rustc_traits/src/chalk/lowering.rs
+++ b/compiler/rustc_traits/src/chalk/lowering.rs
@@ -81,39 +81,36 @@
interner: &RustInterner<'tcx>,
) -> chalk_ir::InEnvironment<chalk_ir::Goal<RustInterner<'tcx>>> {
let clauses = self.environment.into_iter().map(|predicate| {
- let (predicate, binders, _named_regions) = collect_bound_vars(
- interner,
- interner.tcx,
- predicate.bound_atom_with_opt_escaping(interner.tcx),
- );
+ let (predicate, binders, _named_regions) =
+ collect_bound_vars(interner, interner.tcx, predicate.kind());
let consequence = match predicate {
- ty::PredicateAtom::TypeWellFormedFromEnv(ty) => {
+ ty::PredicateKind::TypeWellFormedFromEnv(ty) => {
chalk_ir::DomainGoal::FromEnv(chalk_ir::FromEnv::Ty(ty.lower_into(interner)))
}
- ty::PredicateAtom::Trait(predicate, _) => chalk_ir::DomainGoal::FromEnv(
+ ty::PredicateKind::Trait(predicate, _) => chalk_ir::DomainGoal::FromEnv(
chalk_ir::FromEnv::Trait(predicate.trait_ref.lower_into(interner)),
),
- ty::PredicateAtom::RegionOutlives(predicate) => chalk_ir::DomainGoal::Holds(
+ ty::PredicateKind::RegionOutlives(predicate) => chalk_ir::DomainGoal::Holds(
chalk_ir::WhereClause::LifetimeOutlives(chalk_ir::LifetimeOutlives {
a: predicate.0.lower_into(interner),
b: predicate.1.lower_into(interner),
}),
),
- ty::PredicateAtom::TypeOutlives(predicate) => chalk_ir::DomainGoal::Holds(
+ ty::PredicateKind::TypeOutlives(predicate) => chalk_ir::DomainGoal::Holds(
chalk_ir::WhereClause::TypeOutlives(chalk_ir::TypeOutlives {
ty: predicate.0.lower_into(interner),
lifetime: predicate.1.lower_into(interner),
}),
),
- ty::PredicateAtom::Projection(predicate) => chalk_ir::DomainGoal::Holds(
+ ty::PredicateKind::Projection(predicate) => chalk_ir::DomainGoal::Holds(
chalk_ir::WhereClause::AliasEq(predicate.lower_into(interner)),
),
- ty::PredicateAtom::WellFormed(..)
- | ty::PredicateAtom::ObjectSafe(..)
- | ty::PredicateAtom::ClosureKind(..)
- | ty::PredicateAtom::Subtype(..)
- | ty::PredicateAtom::ConstEvaluatable(..)
- | ty::PredicateAtom::ConstEquate(..) => bug!("unexpected predicate {}", predicate),
+ ty::PredicateKind::WellFormed(..)
+ | ty::PredicateKind::ObjectSafe(..)
+ | ty::PredicateKind::ClosureKind(..)
+ | ty::PredicateKind::Subtype(..)
+ | ty::PredicateKind::ConstEvaluatable(..)
+ | ty::PredicateKind::ConstEquate(..) => bug!("unexpected predicate {}", predicate),
};
let value = chalk_ir::ProgramClauseImplication {
consequence,
@@ -136,19 +133,16 @@
impl<'tcx> LowerInto<'tcx, chalk_ir::GoalData<RustInterner<'tcx>>> for ty::Predicate<'tcx> {
fn lower_into(self, interner: &RustInterner<'tcx>) -> chalk_ir::GoalData<RustInterner<'tcx>> {
- let (predicate, binders, _named_regions) = collect_bound_vars(
- interner,
- interner.tcx,
- self.bound_atom_with_opt_escaping(interner.tcx),
- );
+ let (predicate, binders, _named_regions) =
+ collect_bound_vars(interner, interner.tcx, self.kind());
let value = match predicate {
- ty::PredicateAtom::Trait(predicate, _) => {
+ ty::PredicateKind::Trait(predicate, _) => {
chalk_ir::GoalData::DomainGoal(chalk_ir::DomainGoal::Holds(
chalk_ir::WhereClause::Implemented(predicate.trait_ref.lower_into(interner)),
))
}
- ty::PredicateAtom::RegionOutlives(predicate) => {
+ ty::PredicateKind::RegionOutlives(predicate) => {
chalk_ir::GoalData::DomainGoal(chalk_ir::DomainGoal::Holds(
chalk_ir::WhereClause::LifetimeOutlives(chalk_ir::LifetimeOutlives {
a: predicate.0.lower_into(interner),
@@ -156,7 +150,7 @@
}),
))
}
- ty::PredicateAtom::TypeOutlives(predicate) => {
+ ty::PredicateKind::TypeOutlives(predicate) => {
chalk_ir::GoalData::DomainGoal(chalk_ir::DomainGoal::Holds(
chalk_ir::WhereClause::TypeOutlives(chalk_ir::TypeOutlives {
ty: predicate.0.lower_into(interner),
@@ -164,12 +158,12 @@
}),
))
}
- ty::PredicateAtom::Projection(predicate) => {
+ ty::PredicateKind::Projection(predicate) => {
chalk_ir::GoalData::DomainGoal(chalk_ir::DomainGoal::Holds(
chalk_ir::WhereClause::AliasEq(predicate.lower_into(interner)),
))
}
- ty::PredicateAtom::WellFormed(arg) => match arg.unpack() {
+ ty::PredicateKind::WellFormed(arg) => match arg.unpack() {
GenericArgKind::Type(ty) => match ty.kind() {
// FIXME(chalk): In Chalk, a placeholder is WellFormed if it
// `FromEnv`. However, when we "lower" Params, we don't update
@@ -189,7 +183,7 @@
GenericArgKind::Lifetime(lt) => bug!("unexpect well formed predicate: {:?}", lt),
},
- ty::PredicateAtom::ObjectSafe(t) => chalk_ir::GoalData::DomainGoal(
+ ty::PredicateKind::ObjectSafe(t) => chalk_ir::GoalData::DomainGoal(
chalk_ir::DomainGoal::ObjectSafe(chalk_ir::TraitId(t)),
),
@@ -197,13 +191,13 @@
//
// We can defer this, but ultimately we'll want to express
// some of these in terms of chalk operations.
- ty::PredicateAtom::ClosureKind(..)
- | ty::PredicateAtom::Subtype(..)
- | ty::PredicateAtom::ConstEvaluatable(..)
- | ty::PredicateAtom::ConstEquate(..) => {
+ ty::PredicateKind::ClosureKind(..)
+ | ty::PredicateKind::Subtype(..)
+ | ty::PredicateKind::ConstEvaluatable(..)
+ | ty::PredicateKind::ConstEquate(..) => {
chalk_ir::GoalData::All(chalk_ir::Goals::empty(interner))
}
- ty::PredicateAtom::TypeWellFormedFromEnv(ty) => chalk_ir::GoalData::DomainGoal(
+ ty::PredicateKind::TypeWellFormedFromEnv(ty) => chalk_ir::GoalData::DomainGoal(
chalk_ir::DomainGoal::FromEnv(chalk_ir::FromEnv::Ty(ty.lower_into(interner))),
),
};
@@ -239,8 +233,6 @@
impl<'tcx> LowerInto<'tcx, chalk_ir::Ty<RustInterner<'tcx>>> for Ty<'tcx> {
fn lower_into(self, interner: &RustInterner<'tcx>) -> chalk_ir::Ty<RustInterner<'tcx>> {
- use rustc_ast as ast;
-
let int = |i| chalk_ir::TyKind::Scalar(chalk_ir::Scalar::Int(i));
let uint = |i| chalk_ir::TyKind::Scalar(chalk_ir::Scalar::Uint(i));
let float = |f| chalk_ir::TyKind::Scalar(chalk_ir::Scalar::Float(f));
@@ -249,24 +241,24 @@
ty::Bool => chalk_ir::TyKind::Scalar(chalk_ir::Scalar::Bool),
ty::Char => chalk_ir::TyKind::Scalar(chalk_ir::Scalar::Char),
ty::Int(ty) => match ty {
- ast::IntTy::Isize => int(chalk_ir::IntTy::Isize),
- ast::IntTy::I8 => int(chalk_ir::IntTy::I8),
- ast::IntTy::I16 => int(chalk_ir::IntTy::I16),
- ast::IntTy::I32 => int(chalk_ir::IntTy::I32),
- ast::IntTy::I64 => int(chalk_ir::IntTy::I64),
- ast::IntTy::I128 => int(chalk_ir::IntTy::I128),
+ ty::IntTy::Isize => int(chalk_ir::IntTy::Isize),
+ ty::IntTy::I8 => int(chalk_ir::IntTy::I8),
+ ty::IntTy::I16 => int(chalk_ir::IntTy::I16),
+ ty::IntTy::I32 => int(chalk_ir::IntTy::I32),
+ ty::IntTy::I64 => int(chalk_ir::IntTy::I64),
+ ty::IntTy::I128 => int(chalk_ir::IntTy::I128),
},
ty::Uint(ty) => match ty {
- ast::UintTy::Usize => uint(chalk_ir::UintTy::Usize),
- ast::UintTy::U8 => uint(chalk_ir::UintTy::U8),
- ast::UintTy::U16 => uint(chalk_ir::UintTy::U16),
- ast::UintTy::U32 => uint(chalk_ir::UintTy::U32),
- ast::UintTy::U64 => uint(chalk_ir::UintTy::U64),
- ast::UintTy::U128 => uint(chalk_ir::UintTy::U128),
+ ty::UintTy::Usize => uint(chalk_ir::UintTy::Usize),
+ ty::UintTy::U8 => uint(chalk_ir::UintTy::U8),
+ ty::UintTy::U16 => uint(chalk_ir::UintTy::U16),
+ ty::UintTy::U32 => uint(chalk_ir::UintTy::U32),
+ ty::UintTy::U64 => uint(chalk_ir::UintTy::U64),
+ ty::UintTy::U128 => uint(chalk_ir::UintTy::U128),
},
ty::Float(ty) => match ty {
- ast::FloatTy::F32 => float(chalk_ir::FloatTy::F32),
- ast::FloatTy::F64 => float(chalk_ir::FloatTy::F64),
+ ty::FloatTy::F32 => float(chalk_ir::FloatTy::F32),
+ ty::FloatTy::F64 => float(chalk_ir::FloatTy::F64),
},
ty::Adt(def, substs) => {
chalk_ir::TyKind::Adt(chalk_ir::AdtId(def), substs.lower_into(interner))
@@ -295,12 +287,12 @@
chalk_ir::TyKind::Function(chalk_ir::FnPointer {
num_binders: binders.len(interner),
sig: sig.lower_into(interner),
- substitution: chalk_ir::Substitution::from_iter(
+ substitution: chalk_ir::FnSubst(chalk_ir::Substitution::from_iter(
interner,
inputs_and_outputs.iter().map(|ty| {
chalk_ir::GenericArgData::Ty(ty.lower_into(interner)).intern(interner)
}),
- ),
+ )),
})
}
ty::Dynamic(predicates, region) => chalk_ir::TyKind::Dyn(chalk_ir::DynTy {
@@ -353,24 +345,24 @@
chalk_ir::Scalar::Bool => ty::Bool,
chalk_ir::Scalar::Char => ty::Char,
chalk_ir::Scalar::Int(int_ty) => match int_ty {
- chalk_ir::IntTy::Isize => ty::Int(ast::IntTy::Isize),
- chalk_ir::IntTy::I8 => ty::Int(ast::IntTy::I8),
- chalk_ir::IntTy::I16 => ty::Int(ast::IntTy::I16),
- chalk_ir::IntTy::I32 => ty::Int(ast::IntTy::I32),
- chalk_ir::IntTy::I64 => ty::Int(ast::IntTy::I64),
- chalk_ir::IntTy::I128 => ty::Int(ast::IntTy::I128),
+ chalk_ir::IntTy::Isize => ty::Int(ty::IntTy::Isize),
+ chalk_ir::IntTy::I8 => ty::Int(ty::IntTy::I8),
+ chalk_ir::IntTy::I16 => ty::Int(ty::IntTy::I16),
+ chalk_ir::IntTy::I32 => ty::Int(ty::IntTy::I32),
+ chalk_ir::IntTy::I64 => ty::Int(ty::IntTy::I64),
+ chalk_ir::IntTy::I128 => ty::Int(ty::IntTy::I128),
},
chalk_ir::Scalar::Uint(int_ty) => match int_ty {
- chalk_ir::UintTy::Usize => ty::Uint(ast::UintTy::Usize),
- chalk_ir::UintTy::U8 => ty::Uint(ast::UintTy::U8),
- chalk_ir::UintTy::U16 => ty::Uint(ast::UintTy::U16),
- chalk_ir::UintTy::U32 => ty::Uint(ast::UintTy::U32),
- chalk_ir::UintTy::U64 => ty::Uint(ast::UintTy::U64),
- chalk_ir::UintTy::U128 => ty::Uint(ast::UintTy::U128),
+ chalk_ir::UintTy::Usize => ty::Uint(ty::UintTy::Usize),
+ chalk_ir::UintTy::U8 => ty::Uint(ty::UintTy::U8),
+ chalk_ir::UintTy::U16 => ty::Uint(ty::UintTy::U16),
+ chalk_ir::UintTy::U32 => ty::Uint(ty::UintTy::U32),
+ chalk_ir::UintTy::U64 => ty::Uint(ty::UintTy::U64),
+ chalk_ir::UintTy::U128 => ty::Uint(ty::UintTy::U128),
},
chalk_ir::Scalar::Float(float_ty) => match float_ty {
- chalk_ir::FloatTy::F32 => ty::Float(ast::FloatTy::F32),
- chalk_ir::FloatTy::F64 => ty::Float(ast::FloatTy::F64),
+ chalk_ir::FloatTy::F32 => ty::Float(ty::FloatTy::F32),
+ chalk_ir::FloatTy::F64 => ty::Float(ty::FloatTy::F64),
},
},
TyKind::Array(ty, c) => {
@@ -486,6 +478,10 @@
}
chalk_ir::LifetimeData::Static => ty::RegionKind::ReStatic,
chalk_ir::LifetimeData::Phantom(_, _) => unimplemented!(),
+ chalk_ir::LifetimeData::Empty(ui) => {
+ ty::RegionKind::ReEmpty(ty::UniverseIndex::from_usize(ui.counter))
+ }
+ chalk_ir::LifetimeData::Erased => ty::RegionKind::ReErased,
};
interner.tcx.mk_region(kind)
}
@@ -573,38 +569,35 @@
self,
interner: &RustInterner<'tcx>,
) -> Option<chalk_ir::QuantifiedWhereClause<RustInterner<'tcx>>> {
- let (predicate, binders, _named_regions) = collect_bound_vars(
- interner,
- interner.tcx,
- self.bound_atom_with_opt_escaping(interner.tcx),
- );
+ let (predicate, binders, _named_regions) =
+ collect_bound_vars(interner, interner.tcx, self.kind());
let value = match predicate {
- ty::PredicateAtom::Trait(predicate, _) => {
+ ty::PredicateKind::Trait(predicate, _) => {
Some(chalk_ir::WhereClause::Implemented(predicate.trait_ref.lower_into(interner)))
}
- ty::PredicateAtom::RegionOutlives(predicate) => {
+ ty::PredicateKind::RegionOutlives(predicate) => {
Some(chalk_ir::WhereClause::LifetimeOutlives(chalk_ir::LifetimeOutlives {
a: predicate.0.lower_into(interner),
b: predicate.1.lower_into(interner),
}))
}
- ty::PredicateAtom::TypeOutlives(predicate) => {
+ ty::PredicateKind::TypeOutlives(predicate) => {
Some(chalk_ir::WhereClause::TypeOutlives(chalk_ir::TypeOutlives {
ty: predicate.0.lower_into(interner),
lifetime: predicate.1.lower_into(interner),
}))
}
- ty::PredicateAtom::Projection(predicate) => {
+ ty::PredicateKind::Projection(predicate) => {
Some(chalk_ir::WhereClause::AliasEq(predicate.lower_into(interner)))
}
- ty::PredicateAtom::WellFormed(_ty) => None,
+ ty::PredicateKind::WellFormed(_ty) => None,
- ty::PredicateAtom::ObjectSafe(..)
- | ty::PredicateAtom::ClosureKind(..)
- | ty::PredicateAtom::Subtype(..)
- | ty::PredicateAtom::ConstEvaluatable(..)
- | ty::PredicateAtom::ConstEquate(..)
- | ty::PredicateAtom::TypeWellFormedFromEnv(..) => {
+ ty::PredicateKind::ObjectSafe(..)
+ | ty::PredicateKind::ClosureKind(..)
+ | ty::PredicateKind::Subtype(..)
+ | ty::PredicateKind::ConstEvaluatable(..)
+ | ty::PredicateKind::ConstEquate(..)
+ | ty::PredicateKind::TypeWellFormedFromEnv(..) => {
bug!("unexpected predicate {}", &self)
}
};
@@ -707,32 +700,29 @@
self,
interner: &RustInterner<'tcx>,
) -> Option<chalk_solve::rust_ir::QuantifiedInlineBound<RustInterner<'tcx>>> {
- let (predicate, binders, _named_regions) = collect_bound_vars(
- interner,
- interner.tcx,
- self.bound_atom_with_opt_escaping(interner.tcx),
- );
+ let (predicate, binders, _named_regions) =
+ collect_bound_vars(interner, interner.tcx, self.kind());
match predicate {
- ty::PredicateAtom::Trait(predicate, _) => Some(chalk_ir::Binders::new(
+ ty::PredicateKind::Trait(predicate, _) => Some(chalk_ir::Binders::new(
binders,
chalk_solve::rust_ir::InlineBound::TraitBound(
predicate.trait_ref.lower_into(interner),
),
)),
- ty::PredicateAtom::Projection(predicate) => Some(chalk_ir::Binders::new(
+ ty::PredicateKind::Projection(predicate) => Some(chalk_ir::Binders::new(
binders,
chalk_solve::rust_ir::InlineBound::AliasEqBound(predicate.lower_into(interner)),
)),
- ty::PredicateAtom::TypeOutlives(_predicate) => None,
- ty::PredicateAtom::WellFormed(_ty) => None,
+ ty::PredicateKind::TypeOutlives(_predicate) => None,
+ ty::PredicateKind::WellFormed(_ty) => None,
- ty::PredicateAtom::RegionOutlives(..)
- | ty::PredicateAtom::ObjectSafe(..)
- | ty::PredicateAtom::ClosureKind(..)
- | ty::PredicateAtom::Subtype(..)
- | ty::PredicateAtom::ConstEvaluatable(..)
- | ty::PredicateAtom::ConstEquate(..)
- | ty::PredicateAtom::TypeWellFormedFromEnv(..) => {
+ ty::PredicateKind::RegionOutlives(..)
+ | ty::PredicateKind::ObjectSafe(..)
+ | ty::PredicateKind::ClosureKind(..)
+ | ty::PredicateKind::Subtype(..)
+ | ty::PredicateKind::ConstEvaluatable(..)
+ | ty::PredicateKind::ConstEquate(..)
+ | ty::PredicateKind::TypeWellFormedFromEnv(..) => {
bug!("unexpected predicate {}", &self)
}
}
diff --git a/compiler/rustc_traits/src/chalk/mod.rs b/compiler/rustc_traits/src/chalk/mod.rs
index f3a55fe..d98f181 100644
--- a/compiler/rustc_traits/src/chalk/mod.rs
+++ b/compiler/rustc_traits/src/chalk/mod.rs
@@ -98,21 +98,47 @@
let mut solver = chalk_engine::solve::SLGSolver::new(32, None);
let db = ChalkRustIrDatabase { interner, reempty_placeholder };
let solution = solver.solve(&db, &lowered_goal);
- debug!(?obligation, ?solution, "evaluatate goal");
+ debug!(?obligation, ?solution, "evaluate goal");
// Ideally, the code to convert *back* to rustc types would live close to
// the code to convert *from* rustc types. Right now though, we don't
// really need this and so it's really minimal.
// Right now, we also treat a `Unique` solution the same as
// `Ambig(Definite)`. This really isn't right.
- let make_solution = |subst: chalk_ir::Substitution<_>| {
+ let make_solution = |subst: chalk_ir::Substitution<_>,
+ binders: chalk_ir::CanonicalVarKinds<_>| {
+ use rustc_middle::infer::canonical::CanonicalVarInfo;
+
let mut var_values: IndexVec<BoundVar, GenericArg<'tcx>> = IndexVec::new();
subst.as_slice(&interner).iter().for_each(|p| {
var_values.push(p.lower_into(&interner));
});
+ let variables: Vec<_> = binders
+ .iter(&interner)
+ .map(|var| {
+ let kind = match var.kind {
+ chalk_ir::VariableKind::Ty(ty_kind) => CanonicalVarKind::Ty(match ty_kind {
+ chalk_ir::TyVariableKind::General => CanonicalTyVarKind::General(
+ ty::UniverseIndex::from_usize(var.skip_kind().counter),
+ ),
+ chalk_ir::TyVariableKind::Integer => CanonicalTyVarKind::Int,
+ chalk_ir::TyVariableKind::Float => CanonicalTyVarKind::Float,
+ }),
+ chalk_ir::VariableKind::Lifetime => CanonicalVarKind::Region(
+ ty::UniverseIndex::from_usize(var.skip_kind().counter),
+ ),
+ chalk_ir::VariableKind::Const(_) => CanonicalVarKind::Const(
+ ty::UniverseIndex::from_usize(var.skip_kind().counter),
+ ),
+ };
+ CanonicalVarInfo { kind }
+ })
+ .collect();
+ let max_universe =
+ binders.iter(&interner).map(|v| v.skip_kind().counter).max().unwrap_or(0);
let sol = Canonical {
- max_universe: ty::UniverseIndex::from_usize(0),
- variables: obligation.variables.clone(),
+ max_universe: ty::UniverseIndex::from_usize(max_universe),
+ variables: tcx.intern_canonical_var_infos(&variables),
value: QueryResponse {
var_values: CanonicalVarValues { var_values },
region_constraints: QueryRegionConstraints::default(),
@@ -126,11 +152,13 @@
.map(|s| match s {
Solution::Unique(subst) => {
// FIXME(chalk): handle constraints
- make_solution(subst.value.subst)
+ make_solution(subst.value.subst, subst.binders)
}
Solution::Ambig(guidance) => {
match guidance {
- chalk_solve::Guidance::Definite(subst) => make_solution(subst.value),
+ chalk_solve::Guidance::Definite(subst) => {
+ make_solution(subst.value, subst.binders)
+ }
chalk_solve::Guidance::Suggested(_) => unimplemented!(),
chalk_solve::Guidance::Unknown => {
// chalk_fulfill doesn't use the var_values here, so
diff --git a/compiler/rustc_traits/src/implied_outlives_bounds.rs b/compiler/rustc_traits/src/implied_outlives_bounds.rs
index 97017fb..90ba902 100644
--- a/compiler/rustc_traits/src/implied_outlives_bounds.rs
+++ b/compiler/rustc_traits/src/implied_outlives_bounds.rs
@@ -94,27 +94,27 @@
// region relationships.
implied_bounds.extend(obligations.into_iter().flat_map(|obligation| {
assert!(!obligation.has_escaping_bound_vars());
- match obligation.predicate.kind() {
- &ty::PredicateKind::ForAll(..) => vec![],
- &ty::PredicateKind::Atom(atom) => match atom {
- ty::PredicateAtom::Trait(..)
- | ty::PredicateAtom::Subtype(..)
- | ty::PredicateAtom::Projection(..)
- | ty::PredicateAtom::ClosureKind(..)
- | ty::PredicateAtom::ObjectSafe(..)
- | ty::PredicateAtom::ConstEvaluatable(..)
- | ty::PredicateAtom::ConstEquate(..)
- | ty::PredicateAtom::TypeWellFormedFromEnv(..) => vec![],
- ty::PredicateAtom::WellFormed(arg) => {
+ match obligation.predicate.kind().no_bound_vars() {
+ None => vec![],
+ Some(pred) => match pred {
+ ty::PredicateKind::Trait(..)
+ | ty::PredicateKind::Subtype(..)
+ | ty::PredicateKind::Projection(..)
+ | ty::PredicateKind::ClosureKind(..)
+ | ty::PredicateKind::ObjectSafe(..)
+ | ty::PredicateKind::ConstEvaluatable(..)
+ | ty::PredicateKind::ConstEquate(..)
+ | ty::PredicateKind::TypeWellFormedFromEnv(..) => vec![],
+ ty::PredicateKind::WellFormed(arg) => {
wf_args.push(arg);
vec![]
}
- ty::PredicateAtom::RegionOutlives(ty::OutlivesPredicate(r_a, r_b)) => {
+ ty::PredicateKind::RegionOutlives(ty::OutlivesPredicate(r_a, r_b)) => {
vec![OutlivesBound::RegionSubRegion(r_b, r_a)]
}
- ty::PredicateAtom::TypeOutlives(ty::OutlivesPredicate(ty_a, r_b)) => {
+ ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(ty_a, r_b)) => {
let ty_a = infcx.resolve_vars_if_possible(ty_a);
let mut components = smallvec![];
tcx.push_outlives_components(ty_a, &mut components);
diff --git a/compiler/rustc_traits/src/normalize_erasing_regions.rs b/compiler/rustc_traits/src/normalize_erasing_regions.rs
index 4841e42..1213e55 100644
--- a/compiler/rustc_traits/src/normalize_erasing_regions.rs
+++ b/compiler/rustc_traits/src/normalize_erasing_regions.rs
@@ -46,16 +46,16 @@
}
fn not_outlives_predicate(p: &ty::Predicate<'tcx>) -> bool {
- match p.skip_binders() {
- ty::PredicateAtom::RegionOutlives(..) | ty::PredicateAtom::TypeOutlives(..) => false,
- ty::PredicateAtom::Trait(..)
- | ty::PredicateAtom::Projection(..)
- | ty::PredicateAtom::WellFormed(..)
- | ty::PredicateAtom::ObjectSafe(..)
- | ty::PredicateAtom::ClosureKind(..)
- | ty::PredicateAtom::Subtype(..)
- | ty::PredicateAtom::ConstEvaluatable(..)
- | ty::PredicateAtom::ConstEquate(..)
- | ty::PredicateAtom::TypeWellFormedFromEnv(..) => true,
+ match p.kind().skip_binder() {
+ ty::PredicateKind::RegionOutlives(..) | ty::PredicateKind::TypeOutlives(..) => false,
+ ty::PredicateKind::Trait(..)
+ | ty::PredicateKind::Projection(..)
+ | ty::PredicateKind::WellFormed(..)
+ | ty::PredicateKind::ObjectSafe(..)
+ | ty::PredicateKind::ClosureKind(..)
+ | ty::PredicateKind::Subtype(..)
+ | ty::PredicateKind::ConstEvaluatable(..)
+ | ty::PredicateKind::ConstEquate(..)
+ | ty::PredicateKind::TypeWellFormedFromEnv(..) => true,
}
}
diff --git a/compiler/rustc_traits/src/type_op.rs b/compiler/rustc_traits/src/type_op.rs
index 0addde5..6304f69 100644
--- a/compiler/rustc_traits/src/type_op.rs
+++ b/compiler/rustc_traits/src/type_op.rs
@@ -140,7 +140,7 @@
self.relate(self_ty, Variance::Invariant, impl_self_ty)?;
self.prove_predicate(
- ty::PredicateAtom::WellFormed(impl_self_ty.into()).to_predicate(self.tcx()),
+ ty::PredicateKind::WellFormed(impl_self_ty.into()).to_predicate(self.tcx()),
);
}
@@ -155,7 +155,7 @@
// them? This would only be relevant if some input
// type were ill-formed but did not appear in `ty`,
// which...could happen with normalization...
- self.prove_predicate(ty::PredicateAtom::WellFormed(ty.into()).to_predicate(self.tcx()));
+ self.prove_predicate(ty::PredicateKind::WellFormed(ty.into()).to_predicate(self.tcx()));
Ok(())
}
}
diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs
index aa1de6d..77aa441 100644
--- a/compiler/rustc_ty_utils/src/ty.rs
+++ b/compiler/rustc_ty_utils/src/ty.rs
@@ -5,7 +5,7 @@
use rustc_middle::hir::map as hir_map;
use rustc_middle::ty::subst::Subst;
use rustc_middle::ty::{
- self, Binder, Predicate, PredicateAtom, PredicateKind, ToPredicate, Ty, TyCtxt, WithConstness,
+ self, Binder, Predicate, PredicateKind, ToPredicate, Ty, TyCtxt, WithConstness,
};
use rustc_session::CrateDisambiguator;
use rustc_span::symbol::Symbol;
@@ -129,8 +129,8 @@
let parent_def_id = tcx.hir().local_def_id(parent_id);
let parent_item = tcx.hir().expect_item(parent_id);
match parent_item.kind {
- hir::ItemKind::Impl { ref items, .. } => {
- if let Some(impl_item_ref) = items.iter().find(|i| i.id.hir_id == id) {
+ hir::ItemKind::Impl(ref impl_) => {
+ if let Some(impl_item_ref) = impl_.items.iter().find(|i| i.id.hir_id == 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);
@@ -160,8 +160,8 @@
fn impl_defaultness(tcx: TyCtxt<'_>, def_id: DefId) -> hir::Defaultness {
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
let item = tcx.hir().expect_item(hir_id);
- if let hir::ItemKind::Impl { defaultness, .. } = item.kind {
- defaultness
+ if let hir::ItemKind::Impl(impl_) = &item.kind {
+ impl_.defaultness
} else {
bug!("`impl_defaultness` called on {:?}", item);
}
@@ -201,8 +201,9 @@
.map(|trait_item_ref| trait_item_ref.id)
.map(|id| tcx.hir().local_def_id(id.hir_id).to_def_id()),
),
- hir::ItemKind::Impl { ref items, .. } => tcx.arena.alloc_from_iter(
- items
+ hir::ItemKind::Impl(ref impl_) => tcx.arena.alloc_from_iter(
+ impl_
+ .items
.iter()
.map(|impl_item_ref| impl_item_ref.id)
.map(|id| tcx.hir().local_def_id(id.hir_id).to_def_id()),
@@ -217,8 +218,8 @@
ty::AssociatedItems::new(items)
}
-fn def_span(tcx: TyCtxt<'_>, def_id: DefId) -> Span {
- tcx.hir().span_if_local(def_id).unwrap()
+fn def_ident_span(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Span> {
+ tcx.hir().get_if_local(def_id).and_then(|node| node.ident()).map(|ident| ident.span)
}
/// If the given `DefId` describes an item belonging to a trait,
@@ -323,8 +324,8 @@
},
Node::Item(item) => match item.kind {
- ItemKind::Impl { of_trait: Some(_), .. } => NodeKind::TraitImpl,
- ItemKind::Impl { of_trait: None, .. } => NodeKind::InherentImpl,
+ ItemKind::Impl(hir::Impl { of_trait: Some(_), .. }) => NodeKind::TraitImpl,
+ ItemKind::Impl(hir::Impl { of_trait: None, .. }) => NodeKind::InherentImpl,
ItemKind::Fn(..) => NodeKind::Fn,
_ => NodeKind::Other,
},
@@ -373,8 +374,8 @@
let input_clauses = inputs.into_iter().filter_map(|arg| {
match arg.unpack() {
GenericArgKind::Type(ty) => {
- let binder = Binder::dummy(PredicateAtom::TypeWellFormedFromEnv(ty));
- Some(tcx.mk_predicate(PredicateKind::ForAll(binder)))
+ let binder = Binder::dummy(PredicateKind::TypeWellFormedFromEnv(ty));
+ Some(tcx.mk_predicate(binder))
}
// FIXME(eddyb) no WF conditions from lifetimes?
@@ -490,7 +491,7 @@
associated_item_def_ids,
associated_items,
adt_sized_constraint,
- def_span,
+ def_ident_span,
param_env,
param_env_reveal_all_normalized,
trait_of_item,
diff --git a/compiler/rustc_type_ir/Cargo.toml b/compiler/rustc_type_ir/Cargo.toml
index d50451b..3f64bd8 100644
--- a/compiler/rustc_type_ir/Cargo.toml
+++ b/compiler/rustc_type_ir/Cargo.toml
@@ -12,3 +12,4 @@
rustc_index = { path = "../rustc_index" }
rustc_serialize = { path = "../rustc_serialize" }
rustc_data_structures = { path = "../rustc_data_structures" }
+rustc_macros = { path = "../rustc_macros" }
diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs
index 37abb44..7e70af2 100644
--- a/compiler/rustc_type_ir/src/lib.rs
+++ b/compiler/rustc_type_ir/src/lib.rs
@@ -4,8 +4,13 @@
#[macro_use]
extern crate bitflags;
+#[macro_use]
+extern crate rustc_macros;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
+use rustc_data_structures::unify::{EqUnifyValue, UnifyKey};
+use std::fmt;
+use std::mem::discriminant;
bitflags! {
/// Flags that we track on types. These flags are propagated upwards
@@ -197,8 +202,409 @@
}
}
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
+#[derive(Encodable, Decodable)]
+pub enum IntTy {
+ Isize,
+ I8,
+ I16,
+ I32,
+ I64,
+ I128,
+}
+
+impl IntTy {
+ pub fn name_str(&self) -> &'static str {
+ match *self {
+ IntTy::Isize => "isize",
+ IntTy::I8 => "i8",
+ IntTy::I16 => "i16",
+ IntTy::I32 => "i32",
+ IntTy::I64 => "i64",
+ IntTy::I128 => "i128",
+ }
+ }
+
+ pub fn bit_width(&self) -> Option<u64> {
+ Some(match *self {
+ IntTy::Isize => return None,
+ IntTy::I8 => 8,
+ IntTy::I16 => 16,
+ IntTy::I32 => 32,
+ IntTy::I64 => 64,
+ IntTy::I128 => 128,
+ })
+ }
+
+ pub fn normalize(&self, target_width: u32) -> Self {
+ match self {
+ IntTy::Isize => match target_width {
+ 16 => IntTy::I16,
+ 32 => IntTy::I32,
+ 64 => IntTy::I64,
+ _ => unreachable!(),
+ },
+ _ => *self,
+ }
+ }
+}
+
+#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, Debug)]
+#[derive(Encodable, Decodable)]
+pub enum UintTy {
+ Usize,
+ U8,
+ U16,
+ U32,
+ U64,
+ U128,
+}
+
+impl UintTy {
+ pub fn name_str(&self) -> &'static str {
+ match *self {
+ UintTy::Usize => "usize",
+ UintTy::U8 => "u8",
+ UintTy::U16 => "u16",
+ UintTy::U32 => "u32",
+ UintTy::U64 => "u64",
+ UintTy::U128 => "u128",
+ }
+ }
+
+ pub fn bit_width(&self) -> Option<u64> {
+ Some(match *self {
+ UintTy::Usize => return None,
+ UintTy::U8 => 8,
+ UintTy::U16 => 16,
+ UintTy::U32 => 32,
+ UintTy::U64 => 64,
+ UintTy::U128 => 128,
+ })
+ }
+
+ pub fn normalize(&self, target_width: u32) -> Self {
+ match self {
+ UintTy::Usize => match target_width {
+ 16 => UintTy::U16,
+ 32 => UintTy::U32,
+ 64 => UintTy::U64,
+ _ => unreachable!(),
+ },
+ _ => *self,
+ }
+ }
+}
+
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
+#[derive(Encodable, Decodable)]
+pub enum FloatTy {
+ F32,
+ F64,
+}
+
+impl FloatTy {
+ pub fn name_str(self) -> &'static str {
+ match self {
+ FloatTy::F32 => "f32",
+ FloatTy::F64 => "f64",
+ }
+ }
+
+ pub fn bit_width(self) -> u64 {
+ match self {
+ FloatTy::F32 => 32,
+ FloatTy::F64 => 64,
+ }
+ }
+}
+
+#[derive(Clone, Copy, PartialEq, Eq)]
+pub enum IntVarValue {
+ IntType(IntTy),
+ UintType(UintTy),
+}
+
+#[derive(Clone, Copy, PartialEq, Eq)]
+pub struct FloatVarValue(pub FloatTy);
+
+/// A **ty**pe **v**ariable **ID**.
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Encodable, Decodable)]
+pub struct TyVid {
+ pub index: u32,
+}
+
+/// An **int**egral (`u32`, `i32`, `usize`, etc.) type **v**ariable **ID**.
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Encodable, Decodable)]
+pub struct IntVid {
+ pub index: u32,
+}
+
+/// An **float**ing-point (`f32` or `f64`) type **v**ariable **ID**.
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Encodable, Decodable)]
+pub struct FloatVid {
+ pub index: u32,
+}
+
+/// A placeholder for a type that hasn't been inferred yet.
+///
+/// E.g., if we have an empty array (`[]`), then we create a fresh
+/// type variable for the element type since we won't know until it's
+/// used what the element type is supposed to be.
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Encodable, Decodable)]
+pub enum InferTy {
+ /// A type variable.
+ TyVar(TyVid),
+ /// An integral type variable (`{integer}`).
+ ///
+ /// These are created when the compiler sees an integer literal like
+ /// `1` that could be several different types (`u8`, `i32`, `u32`, etc.).
+ /// We don't know until it's used what type it's supposed to be, so
+ /// we create a fresh type variable.
+ IntVar(IntVid),
+ /// A floating-point type variable (`{float}`).
+ ///
+ /// These are created when the compiler sees an float literal like
+ /// `1.0` that could be either an `f32` or an `f64`.
+ /// We don't know until it's used what type it's supposed to be, so
+ /// we create a fresh type variable.
+ FloatVar(FloatVid),
+
+ /// A [`FreshTy`][Self::FreshTy] is one that is generated as a replacement
+ /// for an unbound type variable. This is convenient for caching etc. See
+ /// `rustc_infer::infer::freshen` for more details.
+ ///
+ /// Compare with [`TyVar`][Self::TyVar].
+ FreshTy(u32),
+ /// Like [`FreshTy`][Self::FreshTy], but as a replacement for [`IntVar`][Self::IntVar].
+ FreshIntTy(u32),
+ /// Like [`FreshTy`][Self::FreshTy], but as a replacement for [`FloatVar`][Self::FloatVar].
+ FreshFloatTy(u32),
+}
+
+/// Raw `TyVid` are used as the unification key for `sub_relations`;
+/// they carry no values.
+impl UnifyKey for TyVid {
+ type Value = ();
+ fn index(&self) -> u32 {
+ self.index
+ }
+ fn from_index(i: u32) -> TyVid {
+ TyVid { index: i }
+ }
+ fn tag() -> &'static str {
+ "TyVid"
+ }
+}
+
+impl EqUnifyValue for IntVarValue {}
+
+impl UnifyKey for IntVid {
+ type Value = Option<IntVarValue>;
+ fn index(&self) -> u32 {
+ self.index
+ }
+ fn from_index(i: u32) -> IntVid {
+ IntVid { index: i }
+ }
+ fn tag() -> &'static str {
+ "IntVid"
+ }
+}
+
+impl EqUnifyValue for FloatVarValue {}
+
+impl UnifyKey for FloatVid {
+ type Value = Option<FloatVarValue>;
+ fn index(&self) -> u32 {
+ self.index
+ }
+ fn from_index(i: u32) -> FloatVid {
+ FloatVid { index: i }
+ }
+ fn tag() -> &'static str {
+ "FloatVid"
+ }
+}
+
+#[derive(Copy, Clone, PartialEq, Decodable, Encodable)]
+pub enum Variance {
+ Covariant, // T<A> <: T<B> iff A <: B -- e.g., function return type
+ Invariant, // T<A> <: T<B> iff B == A -- e.g., type of mutable cell
+ Contravariant, // T<A> <: T<B> iff B <: A -- e.g., function param type
+ Bivariant, // T<A> <: T<B> -- e.g., unused type parameter
+}
+
+impl Variance {
+ /// `a.xform(b)` combines the variance of a context with the
+ /// variance of a type with the following meaning. If we are in a
+ /// context with variance `a`, and we encounter a type argument in
+ /// a position with variance `b`, then `a.xform(b)` is the new
+ /// variance with which the argument appears.
+ ///
+ /// Example 1:
+ ///
+ /// *mut Vec<i32>
+ ///
+ /// Here, the "ambient" variance starts as covariant. `*mut T` is
+ /// invariant with respect to `T`, so the variance in which the
+ /// `Vec<i32>` appears is `Covariant.xform(Invariant)`, which
+ /// yields `Invariant`. Now, the type `Vec<T>` is covariant with
+ /// respect to its type argument `T`, and hence the variance of
+ /// the `i32` here is `Invariant.xform(Covariant)`, which results
+ /// (again) in `Invariant`.
+ ///
+ /// Example 2:
+ ///
+ /// fn(*const Vec<i32>, *mut Vec<i32)
+ ///
+ /// The ambient variance is covariant. A `fn` type is
+ /// contravariant with respect to its parameters, so the variance
+ /// within which both pointer types appear is
+ /// `Covariant.xform(Contravariant)`, or `Contravariant`. `*const
+ /// T` is covariant with respect to `T`, so the variance within
+ /// which the first `Vec<i32>` appears is
+ /// `Contravariant.xform(Covariant)` or `Contravariant`. The same
+ /// is true for its `i32` argument. In the `*mut T` case, the
+ /// variance of `Vec<i32>` is `Contravariant.xform(Invariant)`,
+ /// and hence the outermost type is `Invariant` with respect to
+ /// `Vec<i32>` (and its `i32` argument).
+ ///
+ /// Source: Figure 1 of "Taming the Wildcards:
+ /// Combining Definition- and Use-Site Variance" published in PLDI'11.
+ pub fn xform(self, v: Variance) -> Variance {
+ match (self, v) {
+ // Figure 1, column 1.
+ (Variance::Covariant, Variance::Covariant) => Variance::Covariant,
+ (Variance::Covariant, Variance::Contravariant) => Variance::Contravariant,
+ (Variance::Covariant, Variance::Invariant) => Variance::Invariant,
+ (Variance::Covariant, Variance::Bivariant) => Variance::Bivariant,
+
+ // Figure 1, column 2.
+ (Variance::Contravariant, Variance::Covariant) => Variance::Contravariant,
+ (Variance::Contravariant, Variance::Contravariant) => Variance::Covariant,
+ (Variance::Contravariant, Variance::Invariant) => Variance::Invariant,
+ (Variance::Contravariant, Variance::Bivariant) => Variance::Bivariant,
+
+ // Figure 1, column 3.
+ (Variance::Invariant, _) => Variance::Invariant,
+
+ // Figure 1, column 4.
+ (Variance::Bivariant, _) => Variance::Bivariant,
+ }
+ }
+}
+
impl<CTX> HashStable<CTX> for DebruijnIndex {
fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
self.as_u32().hash_stable(ctx, hasher);
}
}
+
+impl<CTX> HashStable<CTX> for IntTy {
+ fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
+ discriminant(self).hash_stable(ctx, hasher);
+ }
+}
+
+impl<CTX> HashStable<CTX> for UintTy {
+ fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
+ discriminant(self).hash_stable(ctx, hasher);
+ }
+}
+
+impl<CTX> HashStable<CTX> for FloatTy {
+ fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
+ discriminant(self).hash_stable(ctx, hasher);
+ }
+}
+
+impl<CTX> HashStable<CTX> for InferTy {
+ fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
+ use InferTy::*;
+ match self {
+ TyVar(v) => v.index.hash_stable(ctx, hasher),
+ IntVar(v) => v.index.hash_stable(ctx, hasher),
+ FloatVar(v) => v.index.hash_stable(ctx, hasher),
+ FreshTy(v) | FreshIntTy(v) | FreshFloatTy(v) => v.hash_stable(ctx, hasher),
+ }
+ }
+}
+
+impl<CTX> HashStable<CTX> for Variance {
+ fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
+ discriminant(self).hash_stable(ctx, hasher);
+ }
+}
+
+impl fmt::Debug for IntVarValue {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match *self {
+ IntVarValue::IntType(ref v) => v.fmt(f),
+ IntVarValue::UintType(ref v) => v.fmt(f),
+ }
+ }
+}
+
+impl fmt::Debug for FloatVarValue {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ self.0.fmt(f)
+ }
+}
+
+impl fmt::Debug for TyVid {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "_#{}t", self.index)
+ }
+}
+
+impl fmt::Debug for IntVid {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "_#{}i", self.index)
+ }
+}
+
+impl fmt::Debug for FloatVid {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "_#{}f", self.index)
+ }
+}
+
+impl fmt::Debug for InferTy {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ use InferTy::*;
+ match *self {
+ TyVar(ref v) => v.fmt(f),
+ IntVar(ref v) => v.fmt(f),
+ FloatVar(ref v) => v.fmt(f),
+ FreshTy(v) => write!(f, "FreshTy({:?})", v),
+ FreshIntTy(v) => write!(f, "FreshIntTy({:?})", v),
+ FreshFloatTy(v) => write!(f, "FreshFloatTy({:?})", v),
+ }
+ }
+}
+
+impl fmt::Debug for Variance {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.write_str(match *self {
+ Variance::Covariant => "+",
+ Variance::Contravariant => "-",
+ Variance::Invariant => "o",
+ Variance::Bivariant => "*",
+ })
+ }
+}
+
+impl fmt::Display for InferTy {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ use InferTy::*;
+ match *self {
+ TyVar(_) => write!(f, "_"),
+ IntVar(_) => write!(f, "{}", "{integer}"),
+ FloatVar(_) => write!(f, "{}", "{float}"),
+ FreshTy(v) => write!(f, "FreshTy({})", v),
+ FreshIntTy(v) => write!(f, "FreshIntTy({})", v),
+ FreshFloatTy(v) => write!(f, "FreshFloatTy({})", v),
+ }
+ }
+}
diff --git a/compiler/rustc_typeck/src/astconv/errors.rs b/compiler/rustc_typeck/src/astconv/errors.rs
index b04acd9..545c301 100644
--- a/compiler/rustc_typeck/src/astconv/errors.rs
+++ b/compiler/rustc_typeck/src/astconv/errors.rs
@@ -96,7 +96,7 @@
let trait_def = self.tcx().trait_def(trait_def_id);
if !self.tcx().features().unboxed_closures
- && trait_segment.generic_args().parenthesized != trait_def.paren_sugar
+ && trait_segment.args().parenthesized != trait_def.paren_sugar
{
let sess = &self.tcx().sess.parse_sess;
// For now, require that parenthetical notation be used only with `Fn()` etc.
@@ -126,7 +126,7 @@
})
.unwrap_or_else(|| "()".to_string()),
trait_segment
- .generic_args()
+ .args()
.bindings
.iter()
.find_map(|b| match (b.ident.name == sym::Output, &b.kind) {
diff --git a/compiler/rustc_typeck/src/astconv/generics.rs b/compiler/rustc_typeck/src/astconv/generics.rs
index b7e77f3..67e37ca 100644
--- a/compiler/rustc_typeck/src/astconv/generics.rs
+++ b/compiler/rustc_typeck/src/astconv/generics.rs
@@ -1,81 +1,92 @@
+use super::IsMethodCall;
use crate::astconv::{
AstConv, CreateSubstsForGenericArgsCtxt, ExplicitLateBound, GenericArgCountMismatch,
GenericArgCountResult, GenericArgPosition,
};
use crate::errors::AssocTypeBindingNotAllowed;
+use crate::structured_errors::{StructuredDiagnostic, WrongNumberOfGenericArgs};
use rustc_ast::ast::ParamKindOrd;
-use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticId, ErrorReported};
+use rustc_errors::{struct_span_err, Applicability, ErrorReported};
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_hir::GenericArg;
use rustc_middle::ty::{
self, subst, subst::SubstsRef, GenericParamDef, GenericParamDefKind, Ty, TyCtxt,
};
-use rustc_session::{lint::builtin::LATE_BOUND_LIFETIME_ARGUMENTS, Session};
+use rustc_session::lint::builtin::LATE_BOUND_LIFETIME_ARGUMENTS;
use rustc_span::{symbol::kw, MultiSpan, Span};
-
use smallvec::SmallVec;
impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
/// Report an error that a generic argument did not match the generic parameter that was
/// expected.
fn generic_arg_mismatch_err(
- sess: &Session,
+ tcx: TyCtxt<'_>,
arg: &GenericArg<'_>,
- kind: &'static str,
+ param: &GenericParamDef,
possible_ordering_error: bool,
help: Option<&str>,
) {
+ let sess = tcx.sess;
let mut err = struct_span_err!(
sess,
arg.span(),
E0747,
"{} provided when a {} was expected",
arg.descr(),
- kind,
+ param.kind.descr(),
);
- let unordered = sess.features_untracked().const_generics;
- let kind_ord = match kind {
- "lifetime" => ParamKindOrd::Lifetime,
- "type" => ParamKindOrd::Type,
- "constant" => ParamKindOrd::Const { unordered },
- // It's more concise to match on the string representation, though it means
- // the match is non-exhaustive.
- _ => bug!("invalid generic parameter kind {}", kind),
- };
-
- if let ParamKindOrd::Const { .. } = kind_ord {
+ if let GenericParamDefKind::Const { .. } = param.kind {
if let GenericArg::Type(hir::Ty { kind: hir::TyKind::Infer, .. }) = arg {
err.help("const arguments cannot yet be inferred with `_`");
}
}
- let arg_ord = match arg {
- GenericArg::Lifetime(_) => ParamKindOrd::Lifetime,
- GenericArg::Type(_) => ParamKindOrd::Type,
- GenericArg::Const(_) => ParamKindOrd::Const { unordered },
- };
-
- if matches!(arg, GenericArg::Type(hir::Ty { kind: hir::TyKind::Path { .. }, .. }))
- && matches!(kind_ord, ParamKindOrd::Const { .. })
- {
- let suggestions = vec![
- (arg.span().shrink_to_lo(), String::from("{ ")),
- (arg.span().shrink_to_hi(), String::from(" }")),
- ];
- err.multipart_suggestion(
- "if this generic argument was intended as a const parameter, \
+ // Specific suggestion set for diagnostics
+ match (arg, ¶m.kind) {
+ (
+ GenericArg::Type(hir::Ty { kind: hir::TyKind::Path { .. }, .. }),
+ GenericParamDefKind::Const { .. },
+ ) => {
+ let suggestions = vec![
+ (arg.span().shrink_to_lo(), String::from("{ ")),
+ (arg.span().shrink_to_hi(), String::from(" }")),
+ ];
+ err.multipart_suggestion(
+ "if this generic argument was intended as a const parameter, \
try surrounding it with braces:",
- suggestions,
- Applicability::MaybeIncorrect,
- );
+ suggestions,
+ Applicability::MaybeIncorrect,
+ );
+ }
+ (
+ 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));
+ if let Ok(snippet) = snippet {
+ err.span_suggestion(
+ arg.span(),
+ "array type provided where a `usize` was expected, try",
+ format!("{{ {} }}", snippet),
+ Applicability::MaybeIncorrect,
+ );
+ }
+ }
+ _ => {}
}
+ let kind_ord = param.kind.to_ord(tcx);
+ let arg_ord = arg.to_ord(&tcx.features());
+
// This note is only true when generic parameters are strictly ordered by their kind.
if possible_ordering_error && kind_ord.cmp(&arg_ord) != core::cmp::Ordering::Equal {
- let (first, last) =
- if kind_ord < arg_ord { (kind, arg.descr()) } else { (arg.descr(), kind) };
+ let (first, last) = if kind_ord < arg_ord {
+ (param.kind.descr(), arg.descr())
+ } else {
+ (arg.descr(), param.kind.descr())
+ };
err.note(&format!("{} arguments must be provided before {} arguments", first, last));
if let Some(help) = help {
err.help(help);
@@ -203,7 +214,7 @@
// We expected a lifetime argument, but got a type or const
// argument. That means we're inferring the lifetimes.
substs.push(ctx.inferred_kind(None, param, infer_args));
- force_infer_lt = Some(arg);
+ force_infer_lt = Some((arg, param));
params.next();
}
(GenericArg::Lifetime(_), _, ExplicitLateBound::Yes) => {
@@ -213,7 +224,7 @@
// ignore it.
args.next();
}
- (_, kind, _) => {
+ (_, _, _) => {
// We expected one kind of parameter, but the user provided
// another. This is an error. However, if we already know that
// the arguments don't match up with the parameters, we won't issue
@@ -256,9 +267,9 @@
param_types_present.dedup();
Self::generic_arg_mismatch_err(
- tcx.sess,
+ tcx,
arg,
- kind.descr(),
+ param,
!args_iter.clone().is_sorted_by_key(|arg| match arg {
GenericArg::Lifetime(_) => ParamKindOrd::Lifetime,
GenericArg::Type(_) => ParamKindOrd::Type,
@@ -315,9 +326,9 @@
{
let kind = arg.descr();
assert_eq!(kind, "lifetime");
- let provided =
+ let (provided_arg, param) =
force_infer_lt.expect("lifetimes ought to have been inferred");
- Self::generic_arg_mismatch_err(tcx.sess, provided, kind, false, None);
+ Self::generic_arg_mismatch_err(tcx, provided_arg, param, false, None);
}
break;
@@ -343,20 +354,25 @@
pub fn check_generic_arg_count_for_call(
tcx: TyCtxt<'_>,
span: Span,
- def: &ty::Generics,
+ def_id: DefId,
+ generics: &ty::Generics,
seg: &hir::PathSegment<'_>,
- is_method_call: bool,
+ is_method_call: IsMethodCall,
) -> GenericArgCountResult {
let empty_args = hir::GenericArgs::none();
- let suppress_mismatch = Self::check_impl_trait(tcx, seg, &def);
+ let suppress_mismatch = Self::check_impl_trait(tcx, seg, &generics);
+
+ let gen_args = seg.args.unwrap_or(&empty_args);
+ let gen_pos = if is_method_call == IsMethodCall::Yes {
+ GenericArgPosition::MethodCall
+ } else {
+ GenericArgPosition::Value
+ };
+ let has_self = generics.parent.is_none() && generics.has_self;
+ let infer_args = seg.infer_args || suppress_mismatch;
+
Self::check_generic_arg_count(
- tcx,
- span,
- def,
- if let Some(ref args) = seg.args { args } else { &empty_args },
- if is_method_call { GenericArgPosition::MethodCall } else { GenericArgPosition::Value },
- def.parent.is_none() && def.has_self, // `has_self`
- seg.infer_args || suppress_mismatch, // `infer_args`
+ tcx, span, def_id, seg, generics, gen_args, gen_pos, has_self, infer_args,
)
}
@@ -365,156 +381,109 @@
pub(crate) fn check_generic_arg_count(
tcx: TyCtxt<'_>,
span: Span,
- def: &ty::Generics,
- args: &hir::GenericArgs<'_>,
- position: GenericArgPosition,
+ def_id: DefId,
+ seg: &hir::PathSegment<'_>,
+ gen_params: &ty::Generics,
+ gen_args: &hir::GenericArgs<'_>,
+ gen_pos: GenericArgPosition,
has_self: bool,
infer_args: bool,
) -> GenericArgCountResult {
- // At this stage we are guaranteed that the generic arguments are in the correct order, e.g.
- // that lifetimes will proceed types. So it suffices to check the number of each generic
- // arguments in order to validate them with respect to the generic parameters.
- let param_counts = def.own_counts();
+ let default_counts = gen_params.own_defaults();
+ let param_counts = gen_params.own_counts();
let named_type_param_count = param_counts.types - has_self as usize;
- let arg_counts = args.own_counts();
- let infer_lifetimes = position != GenericArgPosition::Type && arg_counts.lifetimes == 0;
+ let arg_counts = gen_args.own_counts();
+ let infer_lifetimes = gen_pos != GenericArgPosition::Type && arg_counts.lifetimes == 0;
- let mut defaults: ty::GenericParamCount = Default::default();
- for param in &def.params {
- match param.kind {
- GenericParamDefKind::Lifetime => {}
- GenericParamDefKind::Type { has_default, .. } => {
- defaults.types += has_default as usize
- }
- GenericParamDefKind::Const => {
- // FIXME(const_generics:defaults)
- }
- };
- }
-
- if position != GenericArgPosition::Type && !args.bindings.is_empty() {
- AstConv::prohibit_assoc_ty_binding(tcx, args.bindings[0].span);
+ if gen_pos != GenericArgPosition::Type && !gen_args.bindings.is_empty() {
+ Self::prohibit_assoc_ty_binding(tcx, gen_args.bindings[0].span);
}
let explicit_late_bound =
- Self::prohibit_explicit_late_bound_lifetimes(tcx, def, args, position);
+ Self::prohibit_explicit_late_bound_lifetimes(tcx, gen_params, gen_args, gen_pos);
- let check_kind_count = |kind,
- required,
- permitted,
- provided,
- offset,
- unexpected_spans: &mut Vec<Span>,
- silent| {
- debug!(
- "check_kind_count: kind: {} required: {} permitted: {} provided: {} offset: {}",
- kind, required, permitted, provided, offset
- );
- // We enforce the following: `required` <= `provided` <= `permitted`.
- // For kinds without defaults (e.g.., lifetimes), `required == permitted`.
- // For other kinds (i.e., types), `permitted` may be greater than `required`.
- if required <= provided && provided <= permitted {
- return true;
- }
+ let mut invalid_args = vec![];
- if silent {
- return false;
- }
-
- // Unfortunately lifetime and type parameter mismatches are typically styled
- // differently in diagnostics, which means we have a few cases to consider here.
- let (bound, quantifier) = if required != permitted {
- if provided < required {
- (required, "at least ")
- } else {
- // provided > permitted
- (permitted, "at most ")
+ let mut check_generics =
+ |kind, expected_min, expected_max, provided, params_offset, args_offset, silent| {
+ if (expected_min..=expected_max).contains(&provided) {
+ return true;
}
- } else {
- (required, "")
+
+ if silent {
+ return false;
+ }
+
+ if provided > expected_max {
+ invalid_args.extend(
+ gen_args.args[args_offset + expected_max..args_offset + provided]
+ .iter()
+ .map(|arg| arg.span()),
+ );
+ };
+
+ WrongNumberOfGenericArgs {
+ tcx,
+ kind,
+ expected_min,
+ expected_max,
+ provided,
+ params_offset,
+ args_offset,
+ path_segment: seg,
+ gen_params,
+ gen_args,
+ def_id,
+ span,
+ }
+ .diagnostic()
+ .emit();
+
+ false
};
- let (spans, labels) = if provided > permitted {
- // In the case when the user has provided too many arguments,
- // we want to point to the unexpected arguments.
- let (spans, labels): (Vec<Span>, Vec<String>) = args.args
- [offset + permitted..offset + provided]
- .iter()
- .map(|arg| (arg.span(), format!("unexpected {} argument", arg.short_descr())))
- .unzip();
- unexpected_spans.extend(spans.clone());
- (spans, labels)
- } else {
- (
- vec![span],
- vec![format!(
- "expected {}{} {} argument{}",
- quantifier,
- bound,
- kind,
- pluralize!(bound),
- )],
- )
- };
-
- let mut err = tcx.sess.struct_span_err_with_code(
- spans.clone(),
- &format!(
- "wrong number of {} arguments: expected {}{}, found {}",
- kind, quantifier, bound, provided,
- ),
- DiagnosticId::Error("E0107".into()),
- );
- for (span, label) in spans.into_iter().zip(labels) {
- err.span_label(span, label.as_str());
- }
- err.emit();
- false
- };
-
- let mut unexpected_spans = vec![];
-
- let lifetime_count_correct = check_kind_count(
+ let lifetimes_correct = check_generics(
"lifetime",
if infer_lifetimes { 0 } else { param_counts.lifetimes },
param_counts.lifetimes,
arg_counts.lifetimes,
+ has_self as usize,
0,
- &mut unexpected_spans,
explicit_late_bound == ExplicitLateBound::Yes,
);
- let kind_str = if param_counts.consts + arg_counts.consts == 0 {
- "type"
- } else if named_type_param_count + arg_counts.types == 0 {
- "const"
- } else {
- "generic"
- };
+ let args_correct = {
+ let kind = if param_counts.consts + arg_counts.consts == 0 {
+ "type"
+ } else if named_type_param_count + arg_counts.types == 0 {
+ "const"
+ } else {
+ "generic"
+ };
- let arg_count_correct = check_kind_count(
- kind_str,
- if infer_args {
+ let expected_min = if infer_args {
0
} else {
- param_counts.consts + named_type_param_count - defaults.types
- },
- param_counts.consts + named_type_param_count,
- arg_counts.consts + arg_counts.types,
- arg_counts.lifetimes,
- &mut unexpected_spans,
- false,
- );
+ param_counts.consts + named_type_param_count - default_counts.types
+ };
+
+ check_generics(
+ kind,
+ expected_min,
+ param_counts.consts + named_type_param_count,
+ arg_counts.consts + arg_counts.types,
+ param_counts.lifetimes + has_self as usize,
+ arg_counts.lifetimes,
+ false,
+ )
+ };
GenericArgCountResult {
explicit_late_bound,
- correct: if lifetime_count_correct && arg_count_correct {
+ correct: if lifetimes_correct && args_correct {
Ok(())
} else {
- Err(GenericArgCountMismatch {
- reported: Some(ErrorReported),
- invalid_args: unexpected_spans,
- })
+ Err(GenericArgCountMismatch { reported: Some(ErrorReported), invalid_args })
},
}
}
@@ -526,22 +495,21 @@
generics: &ty::Generics,
) -> bool {
let explicit = !seg.infer_args;
- let impl_trait =
- generics.params.iter().any(|param| match param.kind {
+ let impl_trait = generics.params.iter().any(|param| {
+ matches!(
+ param.kind,
ty::GenericParamDefKind::Type {
- synthetic:
- Some(
- hir::SyntheticTyParamKind::ImplTrait
- | hir::SyntheticTyParamKind::FromAttr,
- ),
+ synthetic: Some(
+ hir::SyntheticTyParamKind::ImplTrait | hir::SyntheticTyParamKind::FromAttr,
+ ),
..
- } => true,
- _ => false,
- });
+ }
+ )
+ });
if explicit && impl_trait {
let spans = seg
- .generic_args()
+ .args()
.args
.iter()
.filter_map(|arg| match arg {
@@ -586,12 +554,15 @@
let infer_lifetimes = position != GenericArgPosition::Type && arg_counts.lifetimes == 0;
if infer_lifetimes {
- ExplicitLateBound::No
- } else if let Some(span_late) = def.has_late_bound_regions {
+ return ExplicitLateBound::No;
+ }
+
+ if let Some(span_late) = def.has_late_bound_regions {
let msg = "cannot specify lifetime arguments explicitly \
if late bound lifetime parameters are present";
let note = "the late bound lifetime parameter is introduced here";
let span = args.args[0].span();
+
if position == GenericArgPosition::Value
&& arg_counts.lifetimes != param_counts.lifetimes
{
@@ -608,6 +579,7 @@
|lint| lint.build(msg).emit(),
);
}
+
ExplicitLateBound::Yes
} else {
ExplicitLateBound::No
diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs
index 38d33e5..5659345 100644
--- a/compiler/rustc_typeck/src/astconv/mod.rs
+++ b/compiler/rustc_typeck/src/astconv/mod.rs
@@ -112,12 +112,15 @@
No,
}
+#[derive(Debug)]
struct ConvertedBinding<'a, 'tcx> {
item_name: Ident,
kind: ConvertedBindingKind<'a, 'tcx>,
+ gen_args: &'a GenericArgs<'a>,
span: Span,
}
+#[derive(Debug)]
enum ConvertedBindingKind<'a, 'tcx> {
Equality(Ty<'tcx>),
Constraint(&'a [hir::GenericBound<'a>]),
@@ -138,6 +141,12 @@
No,
}
+#[derive(Copy, Clone, PartialEq)]
+pub enum IsMethodCall {
+ Yes,
+ No,
+}
+
/// Denotes the "position" of a generic argument, indicating if it is a generic type,
/// generic function or generic method call.
#[derive(Copy, Clone, PartialEq)]
@@ -252,7 +261,8 @@
span,
def_id,
&[],
- item_segment.generic_args(),
+ item_segment,
+ item_segment.args(),
item_segment.infer_args,
None,
);
@@ -300,6 +310,7 @@
span: Span,
def_id: DefId,
parent_substs: &[subst::GenericArg<'tcx>],
+ seg: &hir::PathSegment<'_>,
generic_args: &'a hir::GenericArgs<'_>,
infer_args: bool,
self_ty: Option<Ty<'tcx>>,
@@ -314,10 +325,11 @@
);
let tcx = self.tcx();
- let generic_params = tcx.generics_of(def_id);
+ let generics = tcx.generics_of(def_id);
+ debug!("generics: {:?}", generics);
- if generic_params.has_self {
- if generic_params.parent.is_some() {
+ if generics.has_self {
+ if generics.parent.is_some() {
// The parent is a trait so it should have at least one subst
// for the `Self` type.
assert!(!parent_substs.is_empty())
@@ -332,7 +344,9 @@
let arg_count = Self::check_generic_arg_count(
tcx,
span,
- &generic_params,
+ def_id,
+ seg,
+ &generics,
&generic_args,
GenericArgPosition::Type,
self_ty.is_some(),
@@ -343,7 +357,7 @@
// Traits always have `Self` as a generic parameter, which means they will not return early
// here and so associated type bindings will be handled regardless of whether there are any
// non-`Self` generic parameters.
- if generic_params.params.len() == 0 {
+ if generics.params.len() == 0 {
return (tcx.intern_substs(&[]), vec![], arg_count);
}
@@ -486,7 +500,7 @@
}
GenericParamDefKind::Const => {
let ty = tcx.at(self.span).type_of(param.def_id);
- // FIXME(const_generics:defaults)
+ // FIXME(const_generics_defaults)
if infer_args {
// No const parameters were provided, we can infer all.
self.astconv.ct_infer(ty, Some(param), self.span).into()
@@ -547,13 +561,18 @@
ConvertedBindingKind::Constraint(bounds)
}
};
- ConvertedBinding { item_name: binding.ident, kind, span: binding.span }
+ ConvertedBinding {
+ item_name: binding.ident,
+ kind,
+ gen_args: binding.gen_args,
+ span: binding.span,
+ }
})
.collect();
debug!(
"create_substs_for_ast_path(generic_params={:?}, self_ty={:?}) -> {:?}",
- generic_params, self_ty, substs
+ generics, self_ty, substs
);
(substs, assoc_bindings, arg_count)
@@ -576,7 +595,8 @@
span,
item_def_id,
parent_substs,
- item_segment.generic_args(),
+ item_segment,
+ item_segment.args(),
item_segment.infer_args,
None,
)
@@ -701,8 +721,15 @@
) {
let trait_def_id = self.tcx().require_lang_item(lang_item, Some(span));
- let (substs, assoc_bindings, _) =
- self.create_substs_for_ast_path(span, trait_def_id, &[], args, false, Some(self_ty));
+ let (substs, assoc_bindings, _) = self.create_substs_for_ast_path(
+ span,
+ trait_def_id,
+ &[],
+ &hir::PathSegment::invalid(),
+ args,
+ false,
+ Some(self_ty),
+ );
let poly_trait_ref = ty::Binder::bind(ty::TraitRef::new(trait_def_id, substs));
bounds.trait_bounds.push((poly_trait_ref, span, Constness::NotConst));
@@ -750,7 +777,8 @@
span,
trait_def_id,
&[],
- trait_segment.generic_args(),
+ trait_segment,
+ trait_segment.args(),
trait_segment.infer_args,
Some(self_ty),
)
@@ -770,7 +798,7 @@
// Try to find an unbound in bounds.
let mut unbound = None;
for ab in ast_bounds {
- if let &hir::GenericBound::Trait(ref ptr, hir::TraitBoundModifier::Maybe) = ab {
+ if let hir::GenericBound::Trait(ptr, hir::TraitBoundModifier::Maybe) = ab {
if unbound.is_none() {
unbound = Some(&ptr.trait_ref);
} else {
@@ -899,61 +927,28 @@
dup_bindings: &mut FxHashMap<DefId, Span>,
path_span: Span,
) -> Result<(), ErrorReported> {
+ // Given something like `U: SomeTrait<T = X>`, we want to produce a
+ // predicate like `<U as SomeTrait>::T = X`. This is somewhat
+ // subtle in the event that `T` is defined in a supertrait of
+ // `SomeTrait`, because in that case we need to upcast.
+ //
+ // That is, consider this case:
+ //
+ // ```
+ // trait SubTrait: SuperTrait<i32> { }
+ // trait SuperTrait<A> { type T; }
+ //
+ // ... B: SubTrait<T = foo> ...
+ // ```
+ //
+ // We want to produce `<B as SuperTrait<i32>>::T == foo`.
+
+ debug!(
+ "add_predicates_for_ast_type_binding(hir_ref_id {:?}, trait_ref {:?}, binding {:?}, bounds {:?}",
+ hir_ref_id, trait_ref, binding, bounds
+ );
let tcx = self.tcx();
- if !speculative {
- // Given something like `U: SomeTrait<T = X>`, we want to produce a
- // predicate like `<U as SomeTrait>::T = X`. This is somewhat
- // subtle in the event that `T` is defined in a supertrait of
- // `SomeTrait`, because in that case we need to upcast.
- //
- // That is, consider this case:
- //
- // ```
- // trait SubTrait: SuperTrait<i32> { }
- // trait SuperTrait<A> { type T; }
- //
- // ... B: SubTrait<T = foo> ...
- // ```
- //
- // We want to produce `<B as SuperTrait<i32>>::T == foo`.
-
- // Find any late-bound regions declared in `ty` that are not
- // declared in the trait-ref. These are not well-formed.
- //
- // Example:
- //
- // for<'a> <T as Iterator>::Item = &'a str // <-- 'a is bad
- // for<'a> <T as FnMut<(&'a u32,)>>::Output = &'a str // <-- 'a is ok
- if let ConvertedBindingKind::Equality(ty) = binding.kind {
- let late_bound_in_trait_ref =
- tcx.collect_constrained_late_bound_regions(&trait_ref);
- let late_bound_in_ty =
- tcx.collect_referenced_late_bound_regions(&ty::Binder::bind(ty));
- debug!("late_bound_in_trait_ref = {:?}", late_bound_in_trait_ref);
- debug!("late_bound_in_ty = {:?}", late_bound_in_ty);
-
- // FIXME: point at the type params that don't have appropriate lifetimes:
- // struct S1<F: for<'a> Fn(&i32, &i32) -> &'a i32>(F);
- // ---- ---- ^^^^^^^
- self.validate_late_bound_regions(
- late_bound_in_trait_ref,
- late_bound_in_ty,
- |br_name| {
- struct_span_err!(
- tcx.sess,
- binding.span,
- E0582,
- "binding for associated type `{}` references {}, \
- which does not appear in the trait input types",
- binding.item_name,
- br_name
- )
- },
- );
- }
- }
-
let candidate =
if self.trait_defines_associated_type_named(trait_ref.def_id(), binding.item_name) {
// Simple case: X is defined in the current trait.
@@ -1011,6 +1006,72 @@
.or_insert(binding.span);
}
+ // Include substitutions for generic parameters of associated types
+ let projection_ty = candidate.map_bound(|trait_ref| {
+ let item_segment = hir::PathSegment {
+ ident: assoc_ty.ident,
+ hir_id: None,
+ res: None,
+ args: Some(binding.gen_args),
+ infer_args: false,
+ };
+
+ let substs_trait_ref_and_assoc_item = self.create_substs_for_associated_item(
+ tcx,
+ path_span,
+ assoc_ty.def_id,
+ &item_segment,
+ trait_ref.substs,
+ );
+
+ debug!(
+ "add_predicates_for_ast_type_binding: substs for trait-ref and assoc_item: {:?}",
+ substs_trait_ref_and_assoc_item
+ );
+
+ ty::ProjectionTy {
+ item_def_id: assoc_ty.def_id,
+ substs: substs_trait_ref_and_assoc_item,
+ }
+ });
+
+ if !speculative {
+ // Find any late-bound regions declared in `ty` that are not
+ // declared in the trait-ref or assoc_ty. These are not well-formed.
+ //
+ // Example:
+ //
+ // for<'a> <T as Iterator>::Item = &'a str // <-- 'a is bad
+ // for<'a> <T as FnMut<(&'a u32,)>>::Output = &'a str // <-- 'a is ok
+ if let ConvertedBindingKind::Equality(ty) = binding.kind {
+ let late_bound_in_trait_ref =
+ tcx.collect_constrained_late_bound_regions(&projection_ty);
+ let late_bound_in_ty =
+ tcx.collect_referenced_late_bound_regions(&ty::Binder::bind(ty));
+ debug!("late_bound_in_trait_ref = {:?}", late_bound_in_trait_ref);
+ debug!("late_bound_in_ty = {:?}", late_bound_in_ty);
+
+ // FIXME: point at the type params that don't have appropriate lifetimes:
+ // struct S1<F: for<'a> Fn(&i32, &i32) -> &'a i32>(F);
+ // ---- ---- ^^^^^^^
+ self.validate_late_bound_regions(
+ late_bound_in_trait_ref,
+ late_bound_in_ty,
+ |br_name| {
+ struct_span_err!(
+ tcx.sess,
+ binding.span,
+ E0582,
+ "binding for associated type `{}` references {}, \
+ which does not appear in the trait input types",
+ binding.item_name,
+ br_name
+ )
+ },
+ );
+ }
+ }
+
match binding.kind {
ConvertedBindingKind::Equality(ref ty) => {
// "Desugar" a constraint like `T: Iterator<Item = u32>` this to
@@ -1018,13 +1079,12 @@
//
// `<T as Iterator>::Item = u32`
bounds.projection_bounds.push((
- candidate.map_bound(|trait_ref| ty::ProjectionPredicate {
- projection_ty: ty::ProjectionTy::from_ref_and_name(
- tcx,
- trait_ref,
- binding.item_name,
- ),
- ty,
+ projection_ty.map_bound(|projection_ty| {
+ debug!(
+ "add_predicates_for_ast_type_binding: projection_ty {:?}, substs: {:?}",
+ projection_ty, projection_ty.substs
+ );
+ ty::ProjectionPredicate { projection_ty, ty }
}),
binding.span,
));
@@ -1036,7 +1096,8 @@
//
// Calling `skip_binder` is okay, because `add_bounds` expects the `param_ty`
// parameter to have a skipped binder.
- let param_ty = tcx.mk_projection(assoc_ty.def_id, candidate.skip_binder().substs);
+ let param_ty =
+ tcx.mk_projection(assoc_ty.def_id, projection_ty.skip_binder().substs);
self.add_bounds(param_ty, ast_bounds, bounds);
}
}
@@ -1076,7 +1137,7 @@
dummy_self,
&mut bounds,
) {
- potential_assoc_types.extend(cur_potential_assoc_types.into_iter());
+ potential_assoc_types.extend(cur_potential_assoc_types);
}
}
@@ -1158,9 +1219,9 @@
obligation.predicate
);
- let bound_predicate = obligation.predicate.bound_atom();
+ let bound_predicate = obligation.predicate.kind();
match bound_predicate.skip_binder() {
- ty::PredicateAtom::Trait(pred, _) => {
+ ty::PredicateKind::Trait(pred, _) => {
let pred = bound_predicate.rebind(pred);
associated_types.entry(span).or_default().extend(
tcx.associated_items(pred.def_id())
@@ -1169,7 +1230,7 @@
.map(|item| item.def_id),
);
}
- ty::PredicateAtom::Projection(pred) => {
+ ty::PredicateKind::Projection(pred) => {
let pred = bound_predicate.rebind(pred);
// A `Self` within the original bound will be substituted with a
// `trait_object_dummy_self`, so check for that.
@@ -1256,17 +1317,15 @@
})
});
- let regular_trait_predicates = existential_trait_refs.map(|trait_ref| {
- trait_ref.map_bound(|trait_ref| ty::ExistentialPredicate::Trait(trait_ref))
- });
+ let regular_trait_predicates = existential_trait_refs
+ .map(|trait_ref| trait_ref.map_bound(ty::ExistentialPredicate::Trait));
let auto_trait_predicates = auto_traits.into_iter().map(|trait_ref| {
ty::Binder::dummy(ty::ExistentialPredicate::AutoTrait(trait_ref.trait_ref().def_id()))
});
let mut v = regular_trait_predicates
.chain(auto_trait_predicates)
.chain(
- existential_projections
- .map(|x| x.map_bound(|x| ty::ExistentialPredicate::Projection(x))),
+ existential_projections.map(|x| x.map_bound(ty::ExistentialPredicate::Projection)),
)
.collect::<SmallVec<[_; 8]>>();
v.sort_by(|a, b| a.skip_binder().stable_cmp(tcx, &b.skip_binder()));
@@ -1753,7 +1812,7 @@
let mut has_err = false;
for segment in segments {
let (mut err_for_lt, mut err_for_ty, mut err_for_ct) = (false, false, false);
- for arg in segment.generic_args().args {
+ for arg in segment.args().args {
let (span, kind) = match arg {
hir::GenericArg::Lifetime(lt) => {
if err_for_lt {
@@ -1795,7 +1854,7 @@
}
// Only emit the first error to avoid overloading the user with error messages.
- if let [binding, ..] = segment.generic_args().bindings {
+ if let [binding, ..] = segment.args().bindings {
has_err = true;
Self::prohibit_assoc_ty_binding(self.tcx(), binding.span);
}
@@ -2013,11 +2072,11 @@
"generic `Self` types are currently not permitted in anonymous constants",
);
if let Some(hir::Node::Item(&hir::Item {
- kind: hir::ItemKind::Impl { self_ty, .. },
+ kind: hir::ItemKind::Impl(ref impl_),
..
})) = tcx.hir().get_if_local(def_id)
{
- err.span_note(self_ty.span, "not a concrete type");
+ err.span_note(impl_.self_ty.span, "not a concrete type");
}
err.emit();
tcx.ty_error()
@@ -2042,9 +2101,9 @@
match prim_ty {
hir::PrimTy::Bool => tcx.types.bool,
hir::PrimTy::Char => tcx.types.char,
- hir::PrimTy::Int(it) => tcx.mk_mach_int(it),
- hir::PrimTy::Uint(uit) => tcx.mk_mach_uint(uit),
- hir::PrimTy::Float(ft) => tcx.mk_mach_float(ft),
+ hir::PrimTy::Int(it) => tcx.mk_mach_int(ty::int_ty(it)),
+ hir::PrimTy::Uint(uit) => tcx.mk_mach_uint(ty::uint_ty(uit)),
+ hir::PrimTy::Float(ft) => tcx.mk_mach_float(ty::float_ty(ft)),
hir::PrimTy::Str => tcx.types.str_,
}
}
@@ -2132,6 +2191,7 @@
span,
def_id,
&[],
+ &hir::PathSegment::invalid(),
&GenericArgs::none(),
true,
None,
diff --git a/compiler/rustc_typeck/src/check/_match.rs b/compiler/rustc_typeck/src/check/_match.rs
index 6467e04..30e0e3e 100644
--- a/compiler/rustc_typeck/src/check/_match.rs
+++ b/compiler/rustc_typeck/src/check/_match.rs
@@ -1,9 +1,9 @@
-use crate::check::coercion::CoerceMany;
+use crate::check::coercion::{AsCoercionSite, CoerceMany};
use crate::check::{Diverges, Expectation, FnCtxt, Needs};
use rustc_hir::{self as hir, ExprKind};
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_infer::traits::Obligation;
-use rustc_middle::ty::{self, ToPredicate, Ty};
+use rustc_middle::ty::{self, ToPredicate, Ty, TyS};
use rustc_span::Span;
use rustc_trait_selection::opaque_types::InferCtxtExt as _;
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
@@ -12,6 +12,41 @@
StatementAsExpression,
};
+macro_rules! create_maybe_get_coercion_reason {
+ ($fn_name:ident, $node:expr) => {
+ pub(crate) fn $fn_name(&self, hir_id: hir::HirId, sp: Span) -> Option<(Span, String)> {
+ let node = $node(self.tcx.hir(), hir_id);
+ if let hir::Node::Block(block) = node {
+ // check that the body's parent is an fn
+ let parent = self.tcx.hir().get(
+ self.tcx.hir().get_parent_node(self.tcx.hir().get_parent_node(block.hir_id)),
+ );
+ if let (
+ Some(expr),
+ hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(..), .. }),
+ ) = (&block.expr, parent)
+ {
+ // check that the `if` expr without `else` is the fn body's expr
+ if expr.span == sp {
+ return self.get_fn_decl(hir_id).and_then(|(fn_decl, _)| {
+ let span = fn_decl.output.span();
+ let snippet = self.tcx.sess.source_map().span_to_snippet(span).ok()?;
+ Some((
+ span,
+ format!("expected `{}` because of this return type", snippet),
+ ))
+ });
+ }
+ }
+ }
+ if let hir::Node::Local(hir::Local { ty: Some(_), pat, .. }) = node {
+ return Some((pat.span, "expected because of this assignment".to_string()));
+ }
+ None
+ }
+ };
+}
+
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
pub fn check_match(
&self,
@@ -25,7 +60,6 @@
use hir::MatchSource::*;
let (source_if, if_no_else, force_scrutinee_bool) = match match_src {
- IfDesugar { contains_else_clause } => (true, !contains_else_clause, true),
IfLetDesugar { contains_else_clause, .. } => (true, !contains_else_clause, false),
WhileDesugar => (false, false, true),
_ => (false, false, false),
@@ -115,8 +149,12 @@
let arm_ty = if source_if
&& if_no_else
&& i != 0
- && self.if_fallback_coercion(expr.span, &arms[0].body, &mut coercion)
- {
+ && self.if_fallback_coercion(
+ expr.span,
+ &arms[0].body,
+ &mut coercion,
+ |hir_id, span| self.maybe_get_coercion_reason(hir_id, span),
+ ) {
tcx.ty_error()
} else {
// Only call this if this is not an `if` expr with an expected type and no `else`
@@ -125,58 +163,8 @@
};
all_arms_diverge &= self.diverges.get();
- // When we have a `match` as a tail expression in a `fn` with a returned `impl Trait`
- // we check if the different arms would work with boxed trait objects instead and
- // provide a structured suggestion in that case.
- let opt_suggest_box_span = match (
- orig_expected,
- self.ret_coercion_impl_trait.map(|ty| (self.body_id.owner, ty)),
- ) {
- (Expectation::ExpectHasType(expected), Some((id, ty)))
- if self.in_tail_expr && self.can_coerce(arm_ty, expected) =>
- {
- let impl_trait_ret_ty = self.infcx.instantiate_opaque_types(
- id,
- self.body_id,
- self.param_env,
- ty,
- arm.body.span,
- );
- let mut suggest_box = !impl_trait_ret_ty.obligations.is_empty();
- for o in impl_trait_ret_ty.obligations {
- match o.predicate.skip_binders_unchecked() {
- ty::PredicateAtom::Trait(t, constness) => {
- let pred = ty::PredicateAtom::Trait(
- ty::TraitPredicate {
- trait_ref: ty::TraitRef {
- def_id: t.def_id(),
- substs: self.infcx.tcx.mk_substs_trait(arm_ty, &[]),
- },
- },
- constness,
- );
- let obl = Obligation::new(
- o.cause.clone(),
- self.param_env,
- pred.to_predicate(self.infcx.tcx),
- );
- suggest_box &= self.infcx.predicate_must_hold_modulo_regions(&obl);
- if !suggest_box {
- // We've encountered some obligation that didn't hold, so the
- // return expression can't just be boxed. We don't need to
- // evaluate the rest of the obligations.
- break;
- }
- }
- _ => {}
- }
- }
- // If all the obligations hold (or there are no obligations) the tail expression
- // we can suggest to return a boxed trait object instead of an opaque type.
- if suggest_box { self.ret_type_span } else { None }
- }
- _ => None,
- };
+ let opt_suggest_box_span =
+ self.opt_suggest_box_span(arm.body.span, arm_ty, orig_expected);
if source_if {
let then_expr = &arms[0].body;
@@ -279,7 +267,7 @@
) {
use hir::MatchSource::*;
let msg = match source {
- IfDesugar { .. } | IfLetDesugar { .. } => "block in `if` expression",
+ IfLetDesugar { .. } => "block in `if` expression",
WhileDesugar { .. } | WhileLetDesugar { .. } => "block in `while` expression",
_ => "arm",
};
@@ -291,15 +279,20 @@
/// Handle the fallback arm of a desugared if(-let) like a missing else.
///
/// Returns `true` if there was an error forcing the coercion to the `()` type.
- fn if_fallback_coercion(
+ pub(crate) fn if_fallback_coercion<F, T>(
&self,
span: Span,
then_expr: &'tcx hir::Expr<'tcx>,
- coercion: &mut CoerceMany<'tcx, '_, rustc_hir::Arm<'tcx>>,
- ) -> bool {
+ coercion: &mut CoerceMany<'tcx, '_, T>,
+ ret_reason: F,
+ ) -> bool
+ where
+ F: Fn(hir::HirId, Span) -> Option<(Span, String)>,
+ T: AsCoercionSite,
+ {
// If this `if` expr is the parent's function return expr,
// the cause of the type coercion is the return type, point at it. (#25228)
- let ret_reason = self.maybe_get_coercion_reason(then_expr.hir_id, span);
+ let ret_reason = ret_reason(then_expr.hir_id, span);
let cause = self.cause(span, ObligationCauseCode::IfExpressionWithNoElse);
let mut error = false;
coercion.coerce_forced_unit(
@@ -322,38 +315,25 @@
error
}
- fn maybe_get_coercion_reason(&self, hir_id: hir::HirId, span: Span) -> Option<(Span, String)> {
- use hir::Node::{Block, Item, Local};
-
- let hir = self.tcx.hir();
- let arm_id = hir.get_parent_node(hir_id);
- let match_id = hir.get_parent_node(arm_id);
- let containing_id = hir.get_parent_node(match_id);
-
- let node = hir.get(containing_id);
- if let Block(block) = node {
- // check that the body's parent is an fn
- let parent = hir.get(hir.get_parent_node(hir.get_parent_node(block.hir_id)));
- if let (Some(expr), Item(hir::Item { kind: hir::ItemKind::Fn(..), .. })) =
- (&block.expr, parent)
- {
- // check that the `if` expr without `else` is the fn body's expr
- if expr.span == span {
- return self.get_fn_decl(hir_id).and_then(|(fn_decl, _)| {
- let span = fn_decl.output.span();
- let snippet = self.tcx.sess.source_map().span_to_snippet(span).ok()?;
- Some((span, format!("expected `{}` because of this return type", snippet)))
- });
- }
- }
+ create_maybe_get_coercion_reason!(
+ maybe_get_coercion_reason,
+ |hir: rustc_middle::hir::map::Map<'a>, id| {
+ let arm_id = hir.get_parent_node(id);
+ let match_id = hir.get_parent_node(arm_id);
+ let containing_id = hir.get_parent_node(match_id);
+ hir.get(containing_id)
}
- if let Local(hir::Local { ty: Some(_), pat, .. }) = node {
- return Some((pat.span, "expected because of this assignment".to_string()));
- }
- None
- }
+ );
- fn if_cause(
+ create_maybe_get_coercion_reason!(
+ maybe_get_coercion_reason_if,
+ |hir: rustc_middle::hir::map::Map<'a>, id| {
+ let rslt = hir.get_parent_node(hir.get_parent_node(id));
+ hir.get(rslt)
+ }
+ );
+
+ pub(crate) fn if_cause(
&self,
span: Span,
then_expr: &'tcx hir::Expr<'tcx>,
@@ -546,6 +526,58 @@
(block.span, None)
}
}
+
+ // When we have a `match` as a tail expression in a `fn` with a returned `impl Trait`
+ // we check if the different arms would work with boxed trait objects instead and
+ // provide a structured suggestion in that case.
+ pub(crate) fn opt_suggest_box_span(
+ &self,
+ span: Span,
+ outer_ty: &'tcx TyS<'tcx>,
+ orig_expected: Expectation<'tcx>,
+ ) -> Option<Span> {
+ match (orig_expected, self.ret_coercion_impl_trait.map(|ty| (self.body_id.owner, ty))) {
+ (Expectation::ExpectHasType(expected), Some((id, ty)))
+ if self.in_tail_expr && self.can_coerce(outer_ty, expected) =>
+ {
+ let impl_trait_ret_ty =
+ self.infcx.instantiate_opaque_types(id, self.body_id, self.param_env, ty, span);
+ let mut suggest_box = !impl_trait_ret_ty.obligations.is_empty();
+ for o in impl_trait_ret_ty.obligations {
+ match o.predicate.kind().skip_binder() {
+ ty::PredicateKind::Trait(t, constness) => {
+ let pred = ty::PredicateKind::Trait(
+ ty::TraitPredicate {
+ trait_ref: ty::TraitRef {
+ def_id: t.def_id(),
+ substs: self.infcx.tcx.mk_substs_trait(outer_ty, &[]),
+ },
+ },
+ constness,
+ );
+ let obl = Obligation::new(
+ o.cause.clone(),
+ self.param_env,
+ pred.to_predicate(self.infcx.tcx),
+ );
+ suggest_box &= self.infcx.predicate_must_hold_modulo_regions(&obl);
+ if !suggest_box {
+ // We've encountered some obligation that didn't hold, so the
+ // return expression can't just be boxed. We don't need to
+ // evaluate the rest of the obligations.
+ break;
+ }
+ }
+ _ => {}
+ }
+ }
+ // If all the obligations hold (or there are no obligations) the tail expression
+ // we can suggest to return a boxed trait object instead of an opaque type.
+ if suggest_box { self.ret_type_span } else { None }
+ }
+ _ => None,
+ }
+ }
}
fn arms_contain_ref_bindings(arms: &'tcx [hir::Arm<'tcx>]) -> Option<hir::Mutability> {
diff --git a/compiler/rustc_typeck/src/check/callee.rs b/compiler/rustc_typeck/src/check/callee.rs
index 22e2873..4836418 100644
--- a/compiler/rustc_typeck/src/check/callee.rs
+++ b/compiler/rustc_typeck/src/check/callee.rs
@@ -25,24 +25,24 @@
tcx: TyCtxt<'_>,
span: Span,
receiver: Option<Span>,
+ expr_span: Span,
trait_id: DefId,
) {
if tcx.lang_items().drop_trait() == Some(trait_id) {
let mut err = struct_span_err!(tcx.sess, span, E0040, "explicit use of destructor method");
err.span_label(span, "explicit destructor calls not allowed");
- let snippet = receiver
+ let (sp, suggestion) = receiver
.and_then(|s| tcx.sess.source_map().span_to_snippet(s).ok())
- .unwrap_or_default();
-
- let suggestion =
- if snippet.is_empty() { "drop".to_string() } else { format!("drop({})", snippet) };
+ .filter(|snippet| !snippet.is_empty())
+ .map(|snippet| (expr_span, format!("drop({})", snippet)))
+ .unwrap_or_else(|| (span, "drop".to_string()));
err.span_suggestion(
- span,
- &format!("consider using `drop` function: `{}`", suggestion),
- String::new(),
- Applicability::Unspecified,
+ sp,
+ "consider using `drop` function",
+ suggestion,
+ Applicability::MaybeIncorrect,
);
err.emit();
@@ -290,16 +290,16 @@
ty::FnPtr(sig) => (sig, None),
ref t => {
let mut unit_variant = None;
- if let &ty::Adt(adt_def, ..) = t {
+ if let ty::Adt(adt_def, ..) = t {
if adt_def.is_enum() {
- if let hir::ExprKind::Call(ref expr, _) = call_expr.kind {
+ if let hir::ExprKind::Call(expr, _) = call_expr.kind {
unit_variant =
self.tcx.sess.source_map().span_to_snippet(expr.span).ok();
}
}
}
- if let hir::ExprKind::Call(ref callee, _) = call_expr.kind {
+ if let hir::ExprKind::Call(callee, _) = call_expr.kind {
let mut err = type_error_struct!(
self.tcx.sess,
callee.span,
diff --git a/compiler/rustc_typeck/src/check/cast.rs b/compiler/rustc_typeck/src/check/cast.rs
index 36240a9..7924ffe 100644
--- a/compiler/rustc_typeck/src/check/cast.rs
+++ b/compiler/rustc_typeck/src/check/cast.rs
@@ -32,7 +32,6 @@
use crate::hir::def_id::DefId;
use crate::type_error_struct;
-use rustc_ast as ast;
use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorReported};
use rustc_hir as hir;
use rustc_hir::lang_items::LangItem;
@@ -418,13 +417,14 @@
err.emit();
}
CastError::SizedUnsizedCast => {
- use crate::structured_errors::{SizedUnsizedCastError, StructuredDiagnostic};
- SizedUnsizedCastError::new(
- &fcx.tcx.sess,
- self.span,
- self.expr_ty,
- fcx.ty_to_string(self.cast_ty),
- )
+ use crate::structured_errors::{SizedUnsizedCast, StructuredDiagnostic};
+
+ SizedUnsizedCast {
+ sess: &fcx.tcx.sess,
+ span: self.span,
+ expr_ty: self.expr_ty,
+ cast_ty: fcx.ty_to_string(self.cast_ty),
+ }
.diagnostic()
.emit();
}
@@ -659,7 +659,7 @@
(_, Int(Bool)) => Err(CastError::CastToBool),
// * -> Char
- (Int(U(ast::UintTy::U8)), Int(Char)) => Ok(CastKind::U8CharCast), // u8-char-cast
+ (Int(U(ty::UintTy::U8)), Int(Char)) => Ok(CastKind::U8CharCast), // u8-char-cast
(_, Int(Char)) => Err(CastError::CastToChar),
// prim -> float,ptr
diff --git a/compiler/rustc_typeck/src/check/check.rs b/compiler/rustc_typeck/src/check/check.rs
index d235ad2..8e2b0bf 100644
--- a/compiler/rustc_typeck/src/check/check.rs
+++ b/compiler/rustc_typeck/src/check/check.rs
@@ -42,6 +42,17 @@
)
.emit()
}
+
+ // This ABI is only allowed on function pointers
+ if abi == Abi::CCmseNonSecureCall {
+ struct_span_err!(
+ tcx.sess,
+ span,
+ E0781,
+ "the `\"C-cmse-nonsecure-call\"` ABI is only allowed on function pointers."
+ )
+ .emit()
+ }
}
/// Helper used for fns and closures. Does the grungy work of checking a function
@@ -66,7 +77,7 @@
// Create the function context. This is either derived from scratch or,
// in the case of closures, based on the outer context.
let mut fcx = FnCtxt::new(inherited, param_env, body.value.hir_id);
- *fcx.ps.borrow_mut() = UnsafetyState::function(fn_sig.unsafety, fn_id);
+ fcx.ps.set(UnsafetyState::function(fn_sig.unsafety, fn_id));
let tcx = fcx.tcx;
let sess = tcx.sess;
@@ -103,13 +114,17 @@
Node::ImplItem(hir::ImplItem {
kind: hir::ImplItemKind::Fn(header, ..), ..
}) => Some(header),
+ Node::TraitItem(hir::TraitItem {
+ kind: hir::TraitItemKind::Fn(header, ..),
+ ..
+ }) => Some(header),
// Closures are RustCall, but they tuple their arguments, so shouldn't be checked
Node::Expr(hir::Expr { kind: hir::ExprKind::Closure(..), .. }) => None,
node => bug!("Item being checked wasn't a function/closure: {:?}", node),
};
if let Some(header) = item {
- tcx.sess.span_err(header.span, "A function with the \"rust-call\" ABI must take a single non-self argument that is a tuple")
+ tcx.sess.span_err(header.span, "functions with the \"rust-call\" ABI must take a single non-self argument that is a tuple")
}
};
@@ -542,10 +557,9 @@
if let Some(ty) = prohibit_opaque.break_value() {
let is_async = match item.kind {
- ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) => match origin {
- hir::OpaqueTyOrigin::AsyncFn => true,
- _ => false,
- },
+ ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) => {
+ matches!(origin, hir::OpaqueTyOrigin::AsyncFn)
+ }
_ => unreachable!(),
};
@@ -688,11 +702,17 @@
check_enum(tcx, it.span, &enum_definition.variants, it.hir_id);
}
hir::ItemKind::Fn(..) => {} // entirely within check_item_body
- hir::ItemKind::Impl { ref items, .. } => {
+ hir::ItemKind::Impl(ref impl_) => {
debug!("ItemKind::Impl {} with id {}", it.ident, it.hir_id);
let impl_def_id = tcx.hir().local_def_id(it.hir_id);
if let Some(impl_trait_ref) = tcx.impl_trait_ref(impl_def_id) {
- check_impl_items_against_trait(tcx, it.span, impl_def_id, impl_trait_ref, items);
+ check_impl_items_against_trait(
+ tcx,
+ it.span,
+ impl_def_id,
+ impl_trait_ref,
+ &impl_.items,
+ );
let trait_def_id = impl_trait_ref.def_id;
check_on_unimplemented(tcx, trait_def_id, it);
}
@@ -836,21 +856,13 @@
Ok(ancestors) => ancestors,
Err(_) => return,
};
- let mut ancestor_impls = ancestors
- .skip(1)
- .filter_map(|parent| {
- if parent.is_from_trait() {
- None
- } else {
- Some((parent, parent.item(tcx, trait_item.ident, kind, trait_def.def_id)))
- }
- })
- .peekable();
-
- if ancestor_impls.peek().is_none() {
- // No parent, nothing to specialize.
- return;
- }
+ let mut ancestor_impls = ancestors.skip(1).filter_map(|parent| {
+ if parent.is_from_trait() {
+ None
+ } else {
+ Some((parent, parent.item(tcx, trait_item.ident, kind, trait_def.def_id)))
+ }
+ });
let opt_result = ancestor_impls.find_map(|(parent_impl, parent_item)| {
match parent_item {
@@ -892,8 +904,6 @@
impl_trait_ref: ty::TraitRef<'tcx>,
impl_item_refs: &[hir::ImplItemRef<'_>],
) {
- let impl_span = tcx.sess.source_map().guess_head_span(full_impl_span);
-
// 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.
@@ -921,111 +931,75 @@
// 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 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 namespace = impl_item.kind.namespace();
+ for impl_item in impl_items {
let ty_impl_item = tcx.associated_item(tcx.hir().local_def_id(impl_item.hir_id));
- let ty_trait_item = tcx
- .associated_items(impl_trait_ref.def_id)
- .find_by_name_and_namespace(tcx, ty_impl_item.ident, namespace, impl_trait_ref.def_id)
- .or_else(|| {
- // Not compatible, but needed for the error message
- tcx.associated_items(impl_trait_ref.def_id)
- .filter_by_name(tcx, ty_impl_item.ident, impl_trait_ref.def_id)
- .next()
- });
- // Check that impl definition matches trait definition
- if let Some(ty_trait_item) = ty_trait_item {
+ 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)
+ } else {
+ continue;
+ };
+
+ if compatible_kind {
match impl_item.kind {
hir::ImplItemKind::Const(..) => {
// Find associated const definition.
- if ty_trait_item.kind == ty::AssocKind::Const {
- compare_const_impl(
- tcx,
- &ty_impl_item,
- impl_item.span,
- &ty_trait_item,
- impl_trait_ref,
- );
- } else {
- let mut err = 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()
- );
- err.span_label(impl_item.span, "does not match trait");
- // We can only get the spans from local trait definition
- // Same for E0324 and E0325
- if let Some(trait_span) = tcx.hir().span_if_local(ty_trait_item.def_id) {
- err.span_label(trait_span, "item in trait");
- }
- err.emit()
- }
+ 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);
- if ty_trait_item.kind == ty::AssocKind::Fn {
- compare_impl_method(
- tcx,
- &ty_impl_item,
- impl_item.span,
- &ty_trait_item,
- impl_trait_ref,
- opt_trait_span,
- );
- } else {
- let mut err = 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()
- );
- err.span_label(impl_item.span, "does not match trait");
- if let Some(trait_span) = opt_trait_span {
- err.span_label(trait_span, "item in trait");
- }
- err.emit()
- }
+ compare_impl_method(
+ tcx,
+ &ty_impl_item,
+ impl_item.span,
+ &ty_trait_item,
+ impl_trait_ref,
+ opt_trait_span,
+ );
}
hir::ImplItemKind::TyAlias(_) => {
let opt_trait_span = tcx.hir().span_if_local(ty_trait_item.def_id);
- if ty_trait_item.kind == ty::AssocKind::Type {
- compare_ty_impl(
- tcx,
- &ty_impl_item,
- impl_item.span,
- &ty_trait_item,
- impl_trait_ref,
- opt_trait_span,
- );
- } else {
- let mut err = 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) = opt_trait_span {
- err.span_label(trait_span, "item in trait");
- }
- err.emit()
- }
+ compare_ty_impl(
+ tcx,
+ &ty_impl_item,
+ impl_item.span,
+ &ty_trait_item,
+ impl_trait_ref,
+ opt_trait_span,
+ );
}
}
@@ -1036,12 +1010,22 @@
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 for missing items from trait
- let mut missing_items = Vec::new();
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() {
let is_implemented = ancestors
.leaf_def(tcx, trait_item.ident, trait_item.kind)
@@ -1054,13 +1038,65 @@
}
}
}
- }
- if !missing_items.is_empty() {
- missing_items_err(tcx, impl_span, &missing_items, full_impl_span);
+ if !missing_items.is_empty() {
+ 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.
@@ -1249,8 +1285,8 @@
let layout = tcx.layout_of(param_env.and(ty));
// We are currently checking the type this field came from, so it must be local
let span = tcx.hir().span_if_local(field.did).unwrap();
- let zst = layout.map(|layout| layout.is_zst()).unwrap_or(false);
- let align1 = layout.map(|layout| layout.align.abi.bytes() == 1).unwrap_or(false);
+ let zst = layout.map_or(false, |layout| layout.is_zst());
+ let align1 = layout.map_or(false, |layout| layout.align.abi.bytes() == 1);
(span, zst, align1)
});
@@ -1320,10 +1356,7 @@
}
if tcx.adt_def(def_id).repr.int.is_none() && tcx.features().arbitrary_enum_discriminant {
- let is_unit = |var: &hir::Variant<'_>| match var.data {
- hir::VariantData::Unit(..) => true,
- _ => false,
- };
+ let is_unit = |var: &hir::Variant<'_>| matches!(var.data, hir::VariantData::Unit(..));
let has_disr = |var: &hir::Variant<'_>| var.disr_expr.is_some();
let has_non_units = vs.iter().any(|var| !is_unit(var));
diff --git a/compiler/rustc_typeck/src/check/closure.rs b/compiler/rustc_typeck/src/check/closure.rs
index 7470c1a..f34aaec 100644
--- a/compiler/rustc_typeck/src/check/closure.rs
+++ b/compiler/rustc_typeck/src/check/closure.rs
@@ -192,9 +192,9 @@
obligation.predicate
);
- let bound_predicate = obligation.predicate.bound_atom();
- if let ty::PredicateAtom::Projection(proj_predicate) =
- obligation.predicate.skip_binders()
+ let bound_predicate = obligation.predicate.kind();
+ if let ty::PredicateKind::Projection(proj_predicate) =
+ obligation.predicate.kind().skip_binder()
{
// Given a Projection predicate, we can potentially infer
// the complete signature.
@@ -622,8 +622,8 @@
// where R is the return type we are expecting. This type `T`
// will be our output.
let output_ty = self.obligations_for_self_ty(ret_vid).find_map(|(_, obligation)| {
- let bound_predicate = obligation.predicate.bound_atom();
- if let ty::PredicateAtom::Projection(proj_predicate) = bound_predicate.skip_binder() {
+ let bound_predicate = obligation.predicate.kind();
+ if let ty::PredicateKind::Projection(proj_predicate) = bound_predicate.skip_binder() {
self.deduce_future_output_from_projection(
obligation.cause.span,
bound_predicate.rebind(proj_predicate),
diff --git a/compiler/rustc_typeck/src/check/coercion.rs b/compiler/rustc_typeck/src/check/coercion.rs
index 0f5f0ab..b2395b7 100644
--- a/compiler/rustc_typeck/src/check/coercion.rs
+++ b/compiler/rustc_typeck/src/check/coercion.rs
@@ -583,9 +583,9 @@
while !queue.is_empty() {
let obligation = queue.remove(0);
debug!("coerce_unsized resolve step: {:?}", obligation);
- let bound_predicate = obligation.predicate.bound_atom();
+ let bound_predicate = obligation.predicate.kind();
let trait_pred = match bound_predicate.skip_binder() {
- ty::PredicateAtom::Trait(trait_pred, _)
+ ty::PredicateKind::Trait(trait_pred, _)
if traits.contains(&trait_pred.def_id()) =>
{
if unsize_did == trait_pred.def_id() {
@@ -926,11 +926,11 @@
false
}
};
- if is_capturing_closure(&prev_ty.kind()) || is_capturing_closure(&new_ty.kind()) {
+ if is_capturing_closure(prev_ty.kind()) || is_capturing_closure(new_ty.kind()) {
(None, None)
} else {
- match (&prev_ty.kind(), &new_ty.kind()) {
- (&ty::FnDef(..), &ty::FnDef(..)) => {
+ match (prev_ty.kind(), new_ty.kind()) {
+ (ty::FnDef(..), ty::FnDef(..)) => {
// Don't reify if the function types have a LUB, i.e., they
// are the same function and their parameters have a LUB.
match self
@@ -943,21 +943,21 @@
}
}
}
- (&ty::Closure(_, substs), &ty::FnDef(..)) => {
+ (ty::Closure(_, substs), ty::FnDef(..)) => {
let b_sig = new_ty.fn_sig(self.tcx);
let a_sig = self
.tcx
.signature_unclosure(substs.as_closure().sig(), b_sig.unsafety());
(Some(a_sig), Some(b_sig))
}
- (&ty::FnDef(..), &ty::Closure(_, substs)) => {
+ (ty::FnDef(..), ty::Closure(_, substs)) => {
let a_sig = prev_ty.fn_sig(self.tcx);
let b_sig = self
.tcx
.signature_unclosure(substs.as_closure().sig(), a_sig.unsafety());
(Some(a_sig), Some(b_sig))
}
- (&ty::Closure(_, substs_a), &ty::Closure(_, substs_b)) => (
+ (ty::Closure(_, substs_a), ty::Closure(_, substs_b)) => (
Some(self.tcx.signature_unclosure(
substs_a.as_closure().sig(),
hir::Unsafety::Normal,
@@ -1443,14 +1443,14 @@
&mut err, expr, expected, found, cause.span, blk_id,
);
let parent = fcx.tcx.hir().get(parent_id);
- if let (Some(match_expr), true, false) = (
- fcx.tcx.hir().get_match_if_cause(expr.hir_id),
+ if let (Some(cond_expr), true, false) = (
+ fcx.tcx.hir().get_if_cause(expr.hir_id),
expected.is_unit(),
pointing_at_return_type,
) {
- if match_expr.span.desugaring_kind().is_none() {
- err.span_label(match_expr.span, "expected this to be `()`");
- fcx.suggest_semicolon_at_end(match_expr.span, &mut err);
+ if cond_expr.span.desugaring_kind().is_none() {
+ err.span_label(cond_expr.span, "expected this to be `()`");
+ fcx.suggest_semicolon_at_end(cond_expr.span, &mut err);
}
}
fcx.get_node_fn_decl(parent).map(|(fn_decl, _, is_main)| (fn_decl, is_main))
@@ -1472,22 +1472,22 @@
fn_output = Some(&fn_decl.output); // `impl Trait` return type
}
}
- if let (Some(sp), Some(fn_output)) = (fcx.ret_coercion_span.borrow().as_ref(), fn_output) {
- self.add_impl_trait_explanation(&mut err, cause, fcx, expected, *sp, fn_output);
+ if let (Some(sp), Some(fn_output)) = (fcx.ret_coercion_span.get(), fn_output) {
+ self.add_impl_trait_explanation(&mut err, cause, fcx, expected, sp, fn_output);
}
- if let Some(sp) = fcx.ret_coercion_span.borrow().as_ref() {
+ if let Some(sp) = fcx.ret_coercion_span.get() {
// If the closure has an explicit return type annotation,
// then a type error may occur at the first return expression we
// see in the closure (if it conflicts with the declared
// return type). Skip adding a note in this case, since it
// would be incorrect.
- if !err.span.primary_spans().iter().any(|span| span == sp) {
+ if !err.span.primary_spans().iter().any(|&span| span == sp) {
let hir = fcx.tcx.hir();
let body_owner = hir.body_owned_by(hir.enclosing_body_owner(fcx.body_id));
if fcx.tcx.is_closure(hir.body_owner_def_id(body_owner).to_def_id()) {
err.span_note(
- *sp,
+ sp,
&format!(
"return type inferred to be `{}` here",
fcx.resolve_vars_if_possible(expected)
diff --git a/compiler/rustc_typeck/src/check/compare_method.rs b/compiler/rustc_typeck/src/check/compare_method.rs
index bb324d0..d37d6bc 100644
--- a/compiler/rustc_typeck/src/check/compare_method.rs
+++ b/compiler/rustc_typeck/src/check/compare_method.rs
@@ -296,7 +296,7 @@
{
diag.span_suggestion(
impl_err_span,
- "consider change the type to match the mutability in trait",
+ "consider changing the mutability to match the trait",
trait_err_str,
Applicability::MachineApplicable,
);
@@ -364,13 +364,12 @@
if trait_params != impl_params {
let item_kind = assoc_item_kind_str(impl_m);
let def_span = tcx.sess.source_map().guess_head_span(span);
- let span = tcx.hir().get_generics(impl_m.def_id).map(|g| g.span).unwrap_or(def_span);
- let generics_span = if let Some(sp) = tcx.hir().span_if_local(trait_m.def_id) {
+ let span = tcx.hir().get_generics(impl_m.def_id).map_or(def_span, |g| g.span);
+ let generics_span = tcx.hir().span_if_local(trait_m.def_id).map(|sp| {
let def_sp = tcx.sess.source_map().guess_head_span(sp);
- Some(tcx.hir().get_generics(trait_m.def_id).map(|g| g.span).unwrap_or(def_sp))
- } else {
- None
- };
+ tcx.hir().get_generics(trait_m.def_id).map_or(def_sp, |g| g.span)
+ });
+
tcx.sess.emit_err(LifetimesOrBoundsMismatchOnTrait {
span,
item_kind,
diff --git a/compiler/rustc_typeck/src/check/demand.rs b/compiler/rustc_typeck/src/check/demand.rs
index 2728e03..3c9c683 100644
--- a/compiler/rustc_typeck/src/check/demand.rs
+++ b/compiler/rustc_typeck/src/check/demand.rs
@@ -32,6 +32,7 @@
if self.suggest_calling_boxed_future_when_appropriate(err, expr, expected, expr_ty) {
return;
}
+ self.suggest_no_capture_closure(err, expected, expr_ty);
self.suggest_boxing_when_appropriate(err, expr, expected, expr_ty);
self.suggest_missing_parentheses(err, expr);
self.note_need_for_fn_pointer(err, expected, expr_ty);
@@ -815,6 +816,13 @@
|err: &mut DiagnosticBuilder<'_>,
found_to_exp_is_fallible: bool,
exp_to_found_is_fallible: bool| {
+ let exp_is_lhs =
+ expected_ty_expr.map(|e| self.tcx.hir().is_lhs(e.hir_id)).unwrap_or(false);
+
+ if exp_is_lhs {
+ return;
+ }
+
let always_fallible = found_to_exp_is_fallible
&& (exp_to_found_is_fallible || expected_ty_expr.is_none());
let msg = if literal_is_ty_suffixed(expr) {
diff --git a/compiler/rustc_typeck/src/check/dropck.rs b/compiler/rustc_typeck/src/check/dropck.rs
index ad675f1..4c3c4fd 100644
--- a/compiler/rustc_typeck/src/check/dropck.rs
+++ b/compiler/rustc_typeck/src/check/dropck.rs
@@ -226,13 +226,13 @@
// could be extended easily also to the other `Predicate`.
let predicate_matches_closure = |p: Predicate<'tcx>| {
let mut relator: SimpleEqRelation<'tcx> = SimpleEqRelation::new(tcx, self_param_env);
- let predicate = predicate.bound_atom();
- let p = p.bound_atom();
+ let predicate = predicate.kind();
+ let p = p.kind();
match (predicate.skip_binder(), p.skip_binder()) {
- (ty::PredicateAtom::Trait(a, _), ty::PredicateAtom::Trait(b, _)) => {
+ (ty::PredicateKind::Trait(a, _), ty::PredicateKind::Trait(b, _)) => {
relator.relate(predicate.rebind(a), p.rebind(b)).is_ok()
}
- (ty::PredicateAtom::Projection(a), ty::PredicateAtom::Projection(b)) => {
+ (ty::PredicateKind::Projection(a), ty::PredicateKind::Projection(b)) => {
relator.relate(predicate.rebind(a), p.rebind(b)).is_ok()
}
_ => predicate == p,
@@ -267,15 +267,13 @@
ty: Ty<'tcx>,
span: Span,
body_id: hir::HirId,
-) -> Result<(), ErrorReported> {
+) {
debug!("check_drop_obligations typ: {:?}", ty);
let cause = &ObligationCause::misc(span, body_id);
let infer_ok = rcx.infcx.at(cause, rcx.fcx.param_env).dropck_outlives(ty);
debug!("dropck_outlives = {:#?}", infer_ok);
rcx.fcx.register_infer_ok_obligations(infer_ok);
-
- Ok(())
}
// This is an implementation of the TypeRelation trait with the
diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs
index ec0e039..33b1c0b 100644
--- a/compiler/rustc_typeck/src/check/expr.rs
+++ b/compiler/rustc_typeck/src/check/expr.rs
@@ -10,6 +10,7 @@
use crate::check::report_unexpected_variant_res;
use crate::check::BreakableCtxt;
use crate::check::Diverges;
+use crate::check::DynamicCoerceMany;
use crate::check::Expectation::{self, ExpectCastableToType, ExpectHasType, NoExpectation};
use crate::check::FnCtxt;
use crate::check::Needs;
@@ -35,17 +36,17 @@
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_middle::ty;
use rustc_middle::ty::adjustment::{Adjust, Adjustment, AllowTwoPhase};
+use rustc_middle::ty::subst::SubstsRef;
use rustc_middle::ty::Ty;
use rustc_middle::ty::TypeFoldable;
use rustc_middle::ty::{AdtKind, Visibility};
+use rustc_span::edition::LATEST_STABLE_EDITION;
use rustc_span::hygiene::DesugaringKind;
use rustc_span::lev_distance::find_best_match_for_name;
use rustc_span::source_map::Span;
use rustc_span::symbol::{kw, sym, Ident, Symbol};
use rustc_trait_selection::traits::{self, ObligationCauseCode};
-use std::fmt::Display;
-
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
fn check_expr_eq_type(&self, expr: &'tcx hir::Expr<'tcx>, expected: Ty<'tcx>) {
let ty = self.check_expr_with_hint(expr, expected);
@@ -187,7 +188,7 @@
// Warn for non-block expressions with diverging children.
match expr.kind {
- ExprKind::Block(..) | ExprKind::Loop(..) | ExprKind::Match(..) => {}
+ ExprKind::Block(..) | ExprKind::If(..) | ExprKind::Loop(..) | ExprKind::Match(..) => {}
// If `expr` is a result of desugaring the try block and is an ok-wrapped
// diverging expression (e.g. it arose from desugaring of `try { return }`),
// we skip issuing a warning because it is autogenerated code.
@@ -264,7 +265,7 @@
}
}
ExprKind::Ret(ref expr_opt) => self.check_expr_return(expr_opt.as_deref(), expr),
- ExprKind::Loop(ref body, _, source) => {
+ ExprKind::Loop(ref body, _, source, _) => {
self.check_expr_loop(body, source, expected, expr)
}
ExprKind::Match(ref discrim, ref arms, match_src) => {
@@ -284,6 +285,13 @@
self.check_expr_eq_type(&e, ty);
ty
}
+ ExprKind::If(ref cond, ref then_expr, ref opt_else_expr) => self.check_then_else(
+ &cond,
+ then_expr,
+ opt_else_expr.as_ref().map(|e| &**e),
+ expr.span,
+ expected,
+ ),
ExprKind::DropTemps(ref e) => self.check_expr_with_expectation(e, expected),
ExprKind::Array(ref args) => self.check_expr_array(args, expected, expr),
ExprKind::ConstBlock(ref anon_const) => self.to_const(anon_const).ty,
@@ -671,14 +679,14 @@
if self.ret_coercion.is_none() {
self.tcx.sess.emit_err(ReturnStmtOutsideOfFnBody { span: expr.span });
} else if let Some(ref e) = expr_opt {
- if self.ret_coercion_span.borrow().is_none() {
- *self.ret_coercion_span.borrow_mut() = Some(e.span);
+ if self.ret_coercion_span.get().is_none() {
+ self.ret_coercion_span.set(Some(e.span));
}
self.check_return_expr(e);
} else {
let mut coercion = self.ret_coercion.as_ref().unwrap().borrow_mut();
- if self.ret_coercion_span.borrow().is_none() {
- *self.ret_coercion_span.borrow_mut() = Some(expr.span);
+ if self.ret_coercion_span.get().is_none() {
+ self.ret_coercion_span.set(Some(expr.span));
}
let cause = self.cause(expr.span, ObligationCauseCode::ReturnNoExpression);
if let Some((fn_decl, _)) = self.get_fn_decl(expr.hir_id) {
@@ -738,8 +746,67 @@
err.emit();
}
+ // A generic function for checking the 'then' and 'else' clauses in an 'if'
+ // or 'if-else' expression.
+ fn check_then_else(
+ &self,
+ cond_expr: &'tcx hir::Expr<'tcx>,
+ then_expr: &'tcx hir::Expr<'tcx>,
+ opt_else_expr: Option<&'tcx hir::Expr<'tcx>>,
+ sp: Span,
+ orig_expected: Expectation<'tcx>,
+ ) -> Ty<'tcx> {
+ let cond_ty = self.check_expr_has_type_or_error(cond_expr, self.tcx.types.bool, |_| {});
+
+ self.warn_if_unreachable(cond_expr.hir_id, then_expr.span, "block in `if` expression");
+
+ let cond_diverges = self.diverges.get();
+ self.diverges.set(Diverges::Maybe);
+
+ let expected = orig_expected.adjust_for_branches(self);
+ let then_ty = self.check_expr_with_expectation(then_expr, expected);
+ let then_diverges = self.diverges.get();
+ self.diverges.set(Diverges::Maybe);
+
+ // We've already taken the expected type's preferences
+ // into account when typing the `then` branch. To figure
+ // out the initial shot at a LUB, we thus only consider
+ // `expected` if it represents a *hard* constraint
+ // (`only_has_type`); otherwise, we just go with a
+ // fresh type variable.
+ let coerce_to_ty = expected.coercion_target_type(self, sp);
+ let mut coerce: DynamicCoerceMany<'_> = CoerceMany::new(coerce_to_ty);
+
+ coerce.coerce(self, &self.misc(sp), then_expr, then_ty);
+
+ if let Some(else_expr) = opt_else_expr {
+ let else_ty = self.check_expr_with_expectation(else_expr, expected);
+ let else_diverges = self.diverges.get();
+
+ let opt_suggest_box_span =
+ self.opt_suggest_box_span(else_expr.span, else_ty, orig_expected);
+ let if_cause =
+ self.if_cause(sp, then_expr, else_expr, then_ty, else_ty, opt_suggest_box_span);
+
+ coerce.coerce(self, &if_cause, else_expr, else_ty);
+
+ // We won't diverge unless both branches do (or the condition does).
+ self.diverges.set(cond_diverges | then_diverges & else_diverges);
+ } else {
+ self.if_fallback_coercion(sp, then_expr, &mut coerce, |hir_id, span| {
+ self.maybe_get_coercion_reason_if(hir_id, span)
+ });
+
+ // If the condition is false we can't diverge.
+ self.diverges.set(cond_diverges);
+ }
+
+ let result_ty = coerce.complete(self);
+ if cond_ty.references_error() { self.tcx.ty_error() } else { result_ty }
+ }
+
/// Type check assignment expression `expr` of form `lhs = rhs`.
- /// The expected type is `()` and is passsed to the function for the purposes of diagnostics.
+ /// The expected type is `()` and is passed to the function for the purposes of diagnostics.
fn check_expr_assign(
&self,
expr: &'tcx hir::Expr<'tcx>,
@@ -764,17 +831,7 @@
};
if !lhs.is_syntactic_place_expr() {
// Do not suggest `if let x = y` as `==` is way more likely to be the intention.
- if let hir::Node::Expr(hir::Expr {
- kind:
- ExprKind::Match(
- _,
- _,
- hir::MatchSource::IfDesugar { .. } | hir::MatchSource::WhileDesugar,
- ),
- ..
- }) = self.tcx.hir().get(
- self.tcx.hir().get_parent_node(self.tcx.hir().get_parent_node(expr.hir_id)),
- ) {
+ let mut span_err = || {
// Likely `if let` intended.
err.span_suggestion_verbose(
expr.span.shrink_to_lo(),
@@ -782,6 +839,18 @@
"let ".to_string(),
applicability,
);
+ };
+ if let hir::Node::Expr(hir::Expr {
+ kind: ExprKind::Match(_, _, hir::MatchSource::WhileDesugar),
+ ..
+ }) = self.tcx.hir().get(
+ self.tcx.hir().get_parent_node(self.tcx.hir().get_parent_node(expr.hir_id)),
+ ) {
+ span_err();
+ } else if let hir::Node::Expr(hir::Expr { kind: ExprKind::If { .. }, .. }) =
+ self.tcx.hir().get(self.tcx.hir().get_parent_node(expr.hir_id))
+ {
+ span_err();
}
}
if eq {
@@ -883,7 +952,7 @@
Ok(method)
}
Err(error) => {
- if segment.ident.name != kw::Invalid {
+ if segment.ident.name != kw::Empty {
self.report_extended_method_error(segment, span, args, rcvr_t, error);
}
Err(())
@@ -1124,7 +1193,7 @@
fields,
base_expr.is_none(),
);
- if let &Some(ref base_expr) = base_expr {
+ if let Some(base_expr) = base_expr {
// If check_expr_struct_fields hit an error, do not attempt to populate
// the fields with the base_expr. This could cause us to hit errors later
// when certain fields are assumed to exist that in fact do not.
@@ -1181,8 +1250,8 @@
// re-link the regions that EIfEO can erase.
self.demand_eqtype(span, adt_ty_hint, adt_ty);
- let (substs, adt_kind, kind_name) = match &adt_ty.kind() {
- &ty::Adt(adt, substs) => (substs, adt.adt_kind(), adt.variant_descr()),
+ let (substs, adt_kind, kind_name) = match adt_ty.kind() {
+ ty::Adt(adt, substs) => (substs, adt.adt_kind(), adt.variant_descr()),
_ => span_bug!(span, "non-ADT passed to check_expr_struct_fields"),
};
@@ -1380,19 +1449,42 @@
ty,
);
match variant.ctor_kind {
- CtorKind::Fn => {
- err.span_label(variant.ident.span, format!("`{adt}` defined here", adt = ty));
- err.span_label(field.ident.span, "field does not exist");
- err.span_label(
- ty_span,
- format!(
- "`{adt}` is a tuple {kind_name}, \
- use the appropriate syntax: `{adt}(/* fields */)`",
- adt = ty,
- kind_name = kind_name
- ),
- );
- }
+ CtorKind::Fn => match ty.kind() {
+ ty::Adt(adt, ..) if adt.is_enum() => {
+ err.span_label(
+ variant.ident.span,
+ format!(
+ "`{adt}::{variant}` defined here",
+ adt = ty,
+ variant = variant.ident,
+ ),
+ );
+ err.span_label(field.ident.span, "field does not exist");
+ err.span_label(
+ ty_span,
+ format!(
+ "`{adt}::{variant}` is a tuple {kind_name}, \
+ use the appropriate syntax: `{adt}::{variant}(/* fields */)`",
+ adt = ty,
+ variant = variant.ident,
+ kind_name = kind_name
+ ),
+ );
+ }
+ _ => {
+ err.span_label(variant.ident.span, format!("`{adt}` defined here", adt = ty));
+ err.span_label(field.ident.span, "field does not exist");
+ err.span_label(
+ ty_span,
+ format!(
+ "`{adt}` is a tuple {kind_name}, \
+ use the appropriate syntax: `{adt}(/* fields */)`",
+ adt = ty,
+ kind_name = kind_name
+ ),
+ );
+ }
+ },
_ => {
// prevent all specified fields from being suggested
let skip_fields = skip_fields.iter().map(|ref x| x.ident.name);
@@ -1492,11 +1584,13 @@
base: &'tcx hir::Expr<'tcx>,
field: Ident,
) -> Ty<'tcx> {
+ debug!("check_field(expr: {:?}, base: {:?}, field: {:?})", expr, base, field);
let expr_t = self.check_expr(base);
let expr_t = self.structurally_resolved_type(base.span, expr_t);
let mut private_candidate = None;
let mut autoderef = self.autoderef(expr.span, expr_t);
while let Some((base_t, _)) = autoderef.next() {
+ debug!("base_t: {:?}", base_t);
match base_t.kind() {
ty::Adt(base_def, substs) if !base_def.is_enum() => {
debug!("struct named {:?}", base_t);
@@ -1547,7 +1641,7 @@
return field_ty;
}
- if field.name == kw::Invalid {
+ if field.name == kw::Empty {
} else if self.method_exists(field, expr_t, expr.hir_id, true) {
self.ban_take_value_of_method(expr, expr_t, field);
} else if !expr_t.is_primitive_ty() {
@@ -1613,7 +1707,7 @@
"ban_nonexisting_field: field={:?}, base={:?}, expr={:?}, expr_ty={:?}",
field, base, expr, expr_t
);
- let mut err = self.no_such_field_err(field.span, field, expr_t);
+ let mut err = self.no_such_field_err(field, expr_t);
match *expr_t.peel_refs().kind() {
ty::Array(_, len) => {
@@ -1637,8 +1731,8 @@
if field.name == kw::Await {
// We know by construction that `<expr>.await` is either on Rust 2015
// or results in `ExprKind::Await`. Suggest switching the edition to 2018.
- err.note("to `.await` a `Future`, switch to Rust 2018");
- err.help("set `edition = \"2018\"` in `Cargo.toml`");
+ err.note("to `.await` a `Future`, switch to Rust 2018 or later");
+ err.help(&format!("set `edition = \"{}\"` in `Cargo.toml`", LATEST_STABLE_EDITION));
err.note("for more on editions, read https://doc.rust-lang.org/edition-guide");
}
@@ -1787,21 +1881,120 @@
}
}
- fn no_such_field_err<T: Display>(
+ fn no_such_field_err(
&self,
- span: Span,
- field: T,
- expr_t: &ty::TyS<'_>,
+ field: Ident,
+ expr_t: &'tcx ty::TyS<'tcx>,
) -> DiagnosticBuilder<'_> {
- type_error_struct!(
+ let span = field.span;
+ debug!("no_such_field_err(span: {:?}, field: {:?}, expr_t: {:?})", span, field, expr_t);
+
+ let mut err = type_error_struct!(
self.tcx().sess,
- span,
+ field.span,
expr_t,
E0609,
"no field `{}` on type `{}`",
field,
expr_t
- )
+ );
+
+ // try to add a suggestion in case the field is a nested field of a field of the Adt
+ if let Some((fields, substs)) = self.get_field_candidates(span, &expr_t) {
+ for candidate_field in fields.iter() {
+ if let Some(field_path) =
+ self.check_for_nested_field(span, field, candidate_field, substs, vec![])
+ {
+ let field_path_str = field_path
+ .iter()
+ .map(|id| id.name.to_ident_string())
+ .collect::<Vec<String>>()
+ .join(".");
+ debug!("field_path_str: {:?}", field_path_str);
+
+ err.span_suggestion_verbose(
+ field.span.shrink_to_lo(),
+ "one of the expressions' fields has a field of the same name",
+ format!("{}.", field_path_str),
+ Applicability::MaybeIncorrect,
+ );
+ }
+ }
+ }
+ err
+ }
+
+ fn get_field_candidates(
+ &self,
+ span: Span,
+ base_t: Ty<'tcx>,
+ ) -> Option<(&Vec<ty::FieldDef>, SubstsRef<'tcx>)> {
+ debug!("get_field_candidates(span: {:?}, base_t: {:?}", span, base_t);
+
+ let mut autoderef = self.autoderef(span, base_t);
+ while let Some((base_t, _)) = autoderef.next() {
+ match base_t.kind() {
+ ty::Adt(base_def, substs) if !base_def.is_enum() => {
+ let fields = &base_def.non_enum_variant().fields;
+ // For compile-time reasons put a limit on number of fields we search
+ if fields.len() > 100 {
+ return None;
+ }
+ return Some((fields, substs));
+ }
+ _ => {}
+ }
+ }
+ None
+ }
+
+ /// This method is called after we have encountered a missing field error to recursively
+ /// search for the field
+ fn check_for_nested_field(
+ &self,
+ span: Span,
+ target_field: Ident,
+ candidate_field: &ty::FieldDef,
+ subst: SubstsRef<'tcx>,
+ mut field_path: Vec<Ident>,
+ ) -> Option<Vec<Ident>> {
+ debug!(
+ "check_for_nested_field(span: {:?}, candidate_field: {:?}, field_path: {:?}",
+ span, candidate_field, field_path
+ );
+
+ if candidate_field.ident == target_field {
+ Some(field_path)
+ } else if field_path.len() > 3 {
+ // For compile-time reasons and to avoid infinite recursion we only check for fields
+ // up to a depth of three
+ None
+ } else {
+ // recursively search fields of `candidate_field` if it's a ty::Adt
+
+ field_path.push(candidate_field.ident.normalize_to_macros_2_0());
+ let field_ty = candidate_field.ty(self.tcx, subst);
+ if let Some((nested_fields, subst)) = self.get_field_candidates(span, &field_ty) {
+ for field in nested_fields.iter() {
+ let ident = field.ident.normalize_to_macros_2_0();
+ if ident == target_field {
+ return Some(field_path);
+ } else {
+ let field_path = field_path.clone();
+ if let Some(path) = self.check_for_nested_field(
+ span,
+ target_field,
+ field,
+ subst,
+ field_path,
+ ) {
+ return Some(path);
+ }
+ }
+ }
+ }
+ None
+ }
}
fn check_expr_index(
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
index 41a403a..bc1a078 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
@@ -1,6 +1,6 @@
use crate::astconv::{
AstConv, CreateSubstsForGenericArgsCtxt, ExplicitLateBound, GenericArgCountMismatch,
- GenericArgCountResult, PathSeg,
+ GenericArgCountResult, IsMethodCall, PathSeg,
};
use crate::check::callee::{self, DeferredCallResolution};
use crate::check::method::{self, MethodCallee, SelfSource};
@@ -274,10 +274,13 @@
}
let autoborrow_mut = adj.iter().any(|adj| {
- matches!(adj, &Adjustment {
- kind: Adjust::Borrow(AutoBorrow::Ref(_, AutoBorrowMutability::Mut { .. })),
- ..
- })
+ matches!(
+ adj,
+ &Adjustment {
+ kind: Adjust::Borrow(AutoBorrow::Ref(_, AutoBorrowMutability::Mut { .. })),
+ ..
+ }
+ )
});
match self.typeck_results.borrow_mut().adjustments_mut().entry(expr.hir_id) {
@@ -542,7 +545,7 @@
self.register_predicate(traits::Obligation::new(
cause,
self.param_env,
- ty::PredicateAtom::WellFormed(arg).to_predicate(self.tcx),
+ ty::PredicateKind::WellFormed(arg).to_predicate(self.tcx),
));
}
@@ -764,21 +767,21 @@
.pending_obligations()
.into_iter()
.filter_map(move |obligation| {
- let bound_predicate = obligation.predicate.bound_atom();
+ let bound_predicate = obligation.predicate.kind();
match bound_predicate.skip_binder() {
- ty::PredicateAtom::Projection(data) => {
+ ty::PredicateKind::Projection(data) => {
Some((bound_predicate.rebind(data).to_poly_trait_ref(self.tcx), obligation))
}
- ty::PredicateAtom::Trait(data, _) => {
+ ty::PredicateKind::Trait(data, _) => {
Some((bound_predicate.rebind(data).to_poly_trait_ref(), obligation))
}
- ty::PredicateAtom::Subtype(..) => None,
- ty::PredicateAtom::RegionOutlives(..) => None,
- ty::PredicateAtom::TypeOutlives(..) => None,
- ty::PredicateAtom::WellFormed(..) => None,
- ty::PredicateAtom::ObjectSafe(..) => None,
- ty::PredicateAtom::ConstEvaluatable(..) => None,
- ty::PredicateAtom::ConstEquate(..) => None,
+ ty::PredicateKind::Subtype(..) => None,
+ ty::PredicateKind::RegionOutlives(..) => None,
+ ty::PredicateKind::TypeOutlives(..) => None,
+ ty::PredicateKind::WellFormed(..) => None,
+ ty::PredicateKind::ObjectSafe(..) => None,
+ ty::PredicateKind::ConstEvaluatable(..) => None,
+ ty::PredicateKind::ConstEquate(..) => None,
// N.B., this predicate is created by breaking down a
// `ClosureType: FnFoo()` predicate, where
// `ClosureType` represents some `Closure`. It can't
@@ -787,8 +790,8 @@
// this closure yet; this is exactly why the other
// code is looking for a self type of a unresolved
// inference variable.
- ty::PredicateAtom::ClosureKind(..) => None,
- ty::PredicateAtom::TypeWellFormedFromEnv(..) => None,
+ ty::PredicateKind::ClosureKind(..) => None,
+ ty::PredicateKind::TypeWellFormedFromEnv(..) => None,
}
})
.filter(move |(tr, _)| self.self_type_matches_expected_vid(*tr, ty_var_root))
@@ -904,8 +907,7 @@
{
// Return directly on cache hit. This is useful to avoid doubly reporting
// errors with default match binding modes. See #44614.
- let def =
- cached_result.map(|(kind, def_id)| Res::Def(kind, def_id)).unwrap_or(Res::Err);
+ let def = cached_result.map_or(Res::Err, |(kind, def_id)| Res::Def(kind, def_id));
return (def, Some(ty), slice::from_ref(&**item_segment));
}
let item_name = item_segment.ident;
@@ -914,7 +916,7 @@
method::MethodError::PrivateMatch(kind, def_id, _) => Ok((kind, def_id)),
_ => Err(ErrorReported),
};
- if item_name.name != kw::Invalid {
+ if item_name.name != kw::Empty {
if let Some(mut e) = self.report_method_error(
span,
ty,
@@ -932,7 +934,7 @@
// Write back the new resolution.
self.write_resolution(hir_id, result);
(
- result.map(|(kind, def_id)| Res::Def(kind, def_id)).unwrap_or(Res::Err),
+ result.map_or(Res::Err, |(kind, def_id)| Res::Def(kind, def_id)),
Some(ty),
slice::from_ref(&**item_segment),
)
@@ -1164,7 +1166,7 @@
debug!("instantiate_value_path: def_id={:?} container={:?}", def_id, container);
match container {
ty::TraitContainer(trait_did) => {
- callee::check_legal_trait_for_method_call(tcx, span, None, trait_did)
+ callee::check_legal_trait_for_method_call(tcx, span, None, span, trait_did)
}
ty::ImplContainer(impl_def_id) => {
if segments.len() == 1 {
@@ -1219,18 +1221,25 @@
// a problem.
let mut infer_args_for_err = FxHashSet::default();
+
for &PathSeg(def_id, index) in &path_segs {
let seg = &segments[index];
let generics = tcx.generics_of(def_id);
+
// Argument-position `impl Trait` is treated as a normal generic
// parameter internally, but we don't allow users to specify the
// parameter's value explicitly, so we have to do some error-
// checking here.
if let GenericArgCountResult {
- correct: Err(GenericArgCountMismatch { reported: Some(ErrorReported), .. }),
+ correct: Err(GenericArgCountMismatch { reported: Some(_), .. }),
..
} = AstConv::check_generic_arg_count_for_call(
- tcx, span, &generics, &seg, false, // `is_method_call`
+ tcx,
+ span,
+ def_id,
+ &generics,
+ seg,
+ IsMethodCall::No,
) {
infer_args_for_err.insert(index);
self.set_tainted_by_errors(); // See issue #53251.
@@ -1376,7 +1385,7 @@
}
}
GenericParamDefKind::Const => {
- // FIXME(const_generics:defaults)
+ // FIXME(const_generics_defaults)
// No const parameters were provided, we have to infer them.
self.fcx.var_for_def(self.span, param)
}
@@ -1473,7 +1482,7 @@
ty
} else {
if !self.is_tainted_by_errors() {
- self.emit_inference_failure_err((**self).body_id, sp, ty.into(), E0282)
+ self.emit_inference_failure_err((**self).body_id, sp, ty.into(), vec![], E0282)
.note("type must be known at this point")
.emit();
}
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
index 333bda0..3326be7 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
@@ -22,7 +22,7 @@
use rustc_span::{self, MultiSpan, Span};
use rustc_trait_selection::traits::{self, ObligationCauseCode, StatementAsExpression};
-use std::mem::replace;
+use crate::structured_errors::StructuredDiagnostic;
use std::slice;
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
@@ -173,18 +173,19 @@
}
if let Some(def_id) = def_id {
- if let Some(node) = tcx.hir().get_if_local(def_id) {
- let mut spans: MultiSpan = node
- .ident()
- .map(|ident| ident.span)
- .unwrap_or_else(|| tcx.hir().span(node.hir_id().unwrap()))
- .into();
+ if let Some(def_span) = tcx.def_ident_span(def_id) {
+ let mut spans: MultiSpan = def_span.into();
- if let Some(id) = node.body_id() {
- let body = tcx.hir().body(id);
- for param in body.params {
- spans.push_span_label(param.span, String::new());
- }
+ let params = tcx
+ .hir()
+ .get_if_local(def_id)
+ .and_then(|node| node.body_id())
+ .into_iter()
+ .map(|id| tcx.hir().body(id).params)
+ .flatten();
+
+ for param in params {
+ spans.push_span_label(param.span, String::new());
}
let def_kind = tcx.def_kind(def_id);
@@ -325,10 +326,7 @@
self.warn_if_unreachable(arg.hir_id, arg.span, "expression");
}
- let is_closure = match arg.kind {
- ExprKind::Closure(..) => true,
- _ => false,
- };
+ let is_closure = matches!(arg.kind, ExprKind::Closure(..));
if is_closure != check_closures {
continue;
@@ -361,9 +359,10 @@
// We also need to make sure we at least write the ty of the other
// arguments which we skipped above.
if c_variadic {
- fn variadic_error<'tcx>(s: &Session, span: Span, t: Ty<'tcx>, cast_ty: &str) {
- use crate::structured_errors::{StructuredDiagnostic, VariadicError};
- VariadicError::new(s, span, t, cast_ty).diagnostic().emit();
+ fn variadic_error<'tcx>(sess: &Session, span: Span, ty: Ty<'tcx>, cast_ty: &str) {
+ use crate::structured_errors::MissingCastForVariadicArg;
+
+ MissingCastForVariadicArg { sess, span, ty, cast_ty }.diagnostic().emit()
}
for arg in args.iter().skip(expected_arg_count) {
@@ -373,13 +372,13 @@
// in C but we just error out instead and require explicit casts.
let arg_ty = self.structurally_resolved_type(arg.span, arg_ty);
match arg_ty.kind() {
- ty::Float(ast::FloatTy::F32) => {
+ ty::Float(ty::FloatTy::F32) => {
variadic_error(tcx.sess, arg.span, arg_ty, "c_double");
}
- ty::Int(ast::IntTy::I8 | ast::IntTy::I16) | ty::Bool => {
+ ty::Int(ty::IntTy::I8 | ty::IntTy::I16) | ty::Bool => {
variadic_error(tcx.sess, arg.span, arg_ty, "c_int");
}
- ty::Uint(ast::UintTy::U8 | ast::UintTy::U16) => {
+ ty::Uint(ty::UintTy::U8 | ty::UintTy::U16) => {
variadic_error(tcx.sess, arg.span, arg_ty, "c_uint");
}
ty::FnDef(..) => {
@@ -408,8 +407,8 @@
}
ast::LitKind::Byte(_) => tcx.types.u8,
ast::LitKind::Char(_) => tcx.types.char,
- ast::LitKind::Int(_, ast::LitIntType::Signed(t)) => tcx.mk_mach_int(t),
- ast::LitKind::Int(_, ast::LitIntType::Unsigned(t)) => tcx.mk_mach_uint(t),
+ ast::LitKind::Int(_, ast::LitIntType::Signed(t)) => tcx.mk_mach_int(ty::int_ty(t)),
+ ast::LitKind::Int(_, ast::LitIntType::Unsigned(t)) => tcx.mk_mach_uint(ty::uint_ty(t)),
ast::LitKind::Int(_, ast::LitIntType::Unsuffixed) => {
let opt_ty = expected.to_option(self).and_then(|ty| match ty.kind() {
ty::Int(_) | ty::Uint(_) => Some(ty),
@@ -420,7 +419,9 @@
});
opt_ty.unwrap_or_else(|| self.next_int_var())
}
- ast::LitKind::Float(_, ast::LitFloatType::Suffixed(t)) => tcx.mk_mach_float(t),
+ ast::LitKind::Float(_, ast::LitFloatType::Suffixed(t)) => {
+ tcx.mk_mach_float(ty::float_ty(t))
+ }
ast::LitKind::Float(_, ast::LitFloatType::Unsuffixed) => {
let opt_ty = expected.to_option(self).and_then(|ty| match ty.kind() {
ty::Float(_) => Some(ty),
@@ -589,11 +590,7 @@
blk: &'tcx hir::Block<'tcx>,
expected: Expectation<'tcx>,
) -> Ty<'tcx> {
- let prev = {
- let mut fcx_ps = self.ps.borrow_mut();
- let unsafety_state = fcx_ps.recurse(blk);
- replace(&mut *fcx_ps, unsafety_state)
- };
+ let prev = self.ps.replace(self.ps.get().recurse(blk));
// In some cases, blocks have just one exit, but other blocks
// can be targeted by multiple breaks. This can happen both
@@ -709,7 +706,7 @@
self.write_ty(blk.hir_id, ty);
- *self.ps.borrow_mut() = prev;
+ self.ps.set(prev);
ty
}
@@ -806,33 +803,39 @@
/// // ^^^^ point at this instead of the whole `if` expression
/// ```
fn get_expr_coercion_span(&self, expr: &hir::Expr<'_>) -> rustc_span::Span {
- if let hir::ExprKind::Match(_, arms, _) = &expr.kind {
- let arm_spans: Vec<Span> = arms
- .iter()
- .filter_map(|arm| {
- self.in_progress_typeck_results
- .and_then(|typeck_results| {
- typeck_results.borrow().node_type_opt(arm.body.hir_id)
- })
- .and_then(|arm_ty| {
- if arm_ty.is_never() {
- None
- } else {
- Some(match &arm.body.kind {
- // Point at the tail expression when possible.
- hir::ExprKind::Block(block, _) => {
- block.expr.as_ref().map(|e| e.span).unwrap_or(block.span)
- }
- _ => arm.body.span,
- })
+ let check_in_progress = |elem: &hir::Expr<'_>| {
+ self.in_progress_typeck_results
+ .and_then(|typeck_results| typeck_results.borrow().node_type_opt(elem.hir_id))
+ .and_then(|ty| {
+ if ty.is_never() {
+ None
+ } else {
+ Some(match elem.kind {
+ // Point at the tail expression when possible.
+ hir::ExprKind::Block(block, _) => {
+ block.expr.map_or(block.span, |e| e.span)
}
+ _ => elem.span,
})
+ }
})
- .collect();
- if arm_spans.len() == 1 {
- return arm_spans[0];
+ };
+
+ if let hir::ExprKind::If(_, _, Some(el)) = expr.kind {
+ if let Some(rslt) = check_in_progress(el) {
+ return rslt;
}
}
+
+ if let hir::ExprKind::Match(_, arms, _) = expr.kind {
+ let mut iter = arms.iter().filter_map(|arm| check_in_progress(arm.body));
+ if let Some(span) = iter.next() {
+ if iter.next().is_none() {
+ return span;
+ }
+ }
+ }
+
expr.span
}
@@ -882,7 +885,7 @@
// Write back the new resolution.
self.write_resolution(hir_id, result);
- (result.map(|(kind, def_id)| Res::Def(kind, def_id)).unwrap_or(Res::Err), ty)
+ (result.map_or(Res::Err, |(kind, def_id)| Res::Def(kind, def_id)), ty)
}
QPath::LangItem(lang_item, span) => {
self.resolve_lang_item_path(lang_item, span, hir_id)
@@ -917,8 +920,8 @@
continue;
}
- if let ty::PredicateAtom::Trait(predicate, _) =
- error.obligation.predicate.skip_binders()
+ if let ty::PredicateKind::Trait(predicate, _) =
+ error.obligation.predicate.kind().skip_binder()
{
// Collect the argument position for all arguments that could have caused this
// `FulfillmentError`.
@@ -968,8 +971,8 @@
if let hir::ExprKind::Path(qpath) = &path.kind {
if let hir::QPath::Resolved(_, path) = &qpath {
for error in errors {
- if let ty::PredicateAtom::Trait(predicate, _) =
- error.obligation.predicate.skip_binders()
+ if let ty::PredicateKind::Trait(predicate, _) =
+ error.obligation.predicate.kind().skip_binder()
{
// If any of the type arguments in this path segment caused the
// `FullfillmentError`, point at its span (#61860).
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs b/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs
index f635e0b..e9223f7 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs
@@ -66,11 +66,11 @@
pub(super) in_tail_expr: bool,
/// First span of a return site that we find. Used in error messages.
- pub(super) ret_coercion_span: RefCell<Option<Span>>,
+ pub(super) ret_coercion_span: Cell<Option<Span>>,
pub(super) resume_yield_tys: Option<(Ty<'tcx>, Ty<'tcx>)>,
- pub(super) ps: RefCell<UnsafetyState>,
+ pub(super) ps: Cell<UnsafetyState>,
/// Whether the last checked node generates a divergence (e.g.,
/// `return` will set this to `Always`). In general, when entering
@@ -127,9 +127,9 @@
ret_coercion_impl_trait: None,
ret_type_span: None,
in_tail_expr: false,
- ret_coercion_span: RefCell::new(None),
+ ret_coercion_span: Cell::new(None),
resume_yield_tys: None,
- ps: RefCell::new(UnsafetyState::function(hir::Unsafety::Normal, hir::CRATE_HIR_ID)),
+ ps: Cell::new(UnsafetyState::function(hir::Unsafety::Normal, hir::CRATE_HIR_ID)),
diverges: Cell::new(Diverges::Maybe),
has_errors: Cell::new(false),
enclosing_breakables: RefCell::new(EnclosingBreakables {
@@ -194,8 +194,8 @@
parent: None,
predicates: tcx.arena.alloc_from_iter(
self.param_env.caller_bounds().iter().filter_map(|predicate| {
- match predicate.skip_binders() {
- ty::PredicateAtom::Trait(data, _) if data.self_ty().is_param(index) => {
+ match predicate.kind().skip_binder() {
+ ty::PredicateKind::Trait(data, _) if data.self_ty().is_param(index) => {
// HACK(eddyb) should get the original `Span`.
let span = tcx.def_span(def_id);
Some((predicate, span))
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs
index 17dbf98..a0465ca 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs
@@ -2,7 +2,7 @@
use crate::astconv::AstConv;
use rustc_ast::util::parser::ExprPrecedence;
-use rustc_span::{self, Span};
+use rustc_span::{self, MultiSpan, Span};
use rustc_errors::{Applicability, DiagnosticBuilder};
use rustc_hir as hir;
@@ -287,6 +287,38 @@
}
}
+ /// When encountering a closure that captures variables, where a FnPtr is expected,
+ /// suggest a non-capturing closure
+ pub(in super::super) fn suggest_no_capture_closure(
+ &self,
+ err: &mut DiagnosticBuilder<'_>,
+ expected: Ty<'tcx>,
+ found: Ty<'tcx>,
+ ) {
+ if let (ty::FnPtr(_), ty::Closure(def_id, _)) = (expected.kind(), found.kind()) {
+ if let Some(upvars) = self.tcx.upvars_mentioned(*def_id) {
+ // Report upto four upvars being captured to reduce the amount error messages
+ // reported back to the user.
+ let spans_and_labels = upvars
+ .iter()
+ .take(4)
+ .map(|(var_hir_id, upvar)| {
+ let var_name = self.tcx.hir().name(*var_hir_id).to_string();
+ let msg = format!("`{}` captured here", var_name);
+ (upvar.span, msg)
+ })
+ .collect::<Vec<_>>();
+
+ let mut multi_span: MultiSpan =
+ spans_and_labels.iter().map(|(sp, _)| *sp).collect::<Vec<_>>().into();
+ for (sp, label) in spans_and_labels {
+ multi_span.push_span_label(sp, label);
+ }
+ err.span_note(multi_span, "closures can only be coerced to `fn` types if they do not capture any variables");
+ }
+ }
+ }
+
/// When encountering an `impl Future` where `BoxFuture` is expected, suggest `Box::pin`.
pub(in super::super) fn suggest_calling_boxed_future_when_appropriate(
&self,
@@ -358,6 +390,7 @@
ExprKind::Call(..)
| ExprKind::MethodCall(..)
| ExprKind::Loop(..)
+ | ExprKind::If(..)
| ExprKind::Match(..)
| ExprKind::Block(..) => {
err.span_suggestion(
diff --git a/compiler/rustc_typeck/src/check/intrinsic.rs b/compiler/rustc_typeck/src/check/intrinsic.rs
index c3b0fc6..e99db7a 100644
--- a/compiler/rustc_typeck/src/check/intrinsic.rs
+++ b/compiler/rustc_typeck/src/check/intrinsic.rs
@@ -63,8 +63,6 @@
| sym::min_align_of
| sym::needs_drop
| sym::caller_location
- | sym::size_of_val
- | sym::min_align_of_val
| sym::add_with_overflow
| sym::sub_with_overflow
| sym::mul_with_overflow
@@ -92,6 +90,7 @@
| sym::rustc_peek
| sym::maxnumf64
| sym::type_name
+ | sym::forget
| sym::variant_count => hir::Unsafety::Normal,
_ => hir::Unsafety::Unsafe,
}
@@ -158,7 +157,6 @@
}
sym::forget => (1, vec![param(0)], tcx.mk_unit()),
sym::transmute => (2, vec![param(0)], param(1)),
- sym::move_val_init => (1, vec![tcx.mk_mut_ptr(param(0)), param(0)], tcx.mk_unit()),
sym::prefetch_read_data
| sym::prefetch_write_data
| sym::prefetch_read_instruction
diff --git a/compiler/rustc_typeck/src/check/method/confirm.rs b/compiler/rustc_typeck/src/check/method/confirm.rs
index 8ef723d..e5f1928 100644
--- a/compiler/rustc_typeck/src/check/method/confirm.rs
+++ b/compiler/rustc_typeck/src/check/method/confirm.rs
@@ -1,6 +1,6 @@
use super::{probe, MethodCallee};
-use crate::astconv::{AstConv, CreateSubstsForGenericArgsCtxt};
+use crate::astconv::{AstConv, CreateSubstsForGenericArgsCtxt, IsMethodCall};
use crate::check::{callee, FnCtxt};
use crate::hir::def_id::DefId;
use crate::hir::GenericArg;
@@ -31,6 +31,7 @@
}
}
+#[derive(Debug)]
pub struct ConfirmResult<'tcx> {
pub callee: MethodCallee<'tcx>,
pub illegal_sized_bound: Option<Span>,
@@ -298,8 +299,14 @@
// If they were not explicitly supplied, just construct fresh
// variables.
let generics = self.tcx.generics_of(pick.item.def_id);
+
let arg_count_correct = AstConv::check_generic_arg_count_for_call(
- self.tcx, self.span, &generics, &seg, true, // `is_method_call`
+ self.tcx,
+ self.span,
+ pick.item.def_id,
+ &generics,
+ seg,
+ IsMethodCall::Yes,
);
// Create subst for early-bound lifetime parameters, combining
@@ -472,8 +479,8 @@
traits::elaborate_predicates(self.tcx, predicates.predicates.iter().copied())
// We don't care about regions here.
- .filter_map(|obligation| match obligation.predicate.skip_binders() {
- ty::PredicateAtom::Trait(trait_pred, _) if trait_pred.def_id() == sized_def_id => {
+ .filter_map(|obligation| match obligation.predicate.kind().skip_binder() {
+ ty::PredicateKind::Trait(trait_pred, _) if trait_pred.def_id() == sized_def_id => {
let span = predicates
.predicates
.iter()
@@ -501,6 +508,7 @@
self.tcx,
self.span,
Some(self.self_expr.span),
+ self.call_expr.span,
trait_def_id,
),
ty::ImplContainer(..) => {}
diff --git a/compiler/rustc_typeck/src/check/method/mod.rs b/compiler/rustc_typeck/src/check/method/mod.rs
index 8e13b37..9a3d1e4 100644
--- a/compiler/rustc_typeck/src/check/method/mod.rs
+++ b/compiler/rustc_typeck/src/check/method/mod.rs
@@ -102,6 +102,7 @@
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
/// Determines whether the type `self_ty` supports a method name `method_name` or not.
+ #[instrument(level = "debug", skip(self))]
pub fn method_exists(
&self,
method_name: Ident,
@@ -129,6 +130,7 @@
}
/// Adds a suggestion to call the given method to the provided diagnostic.
+ #[instrument(level = "debug", skip(self, err, call_expr))]
crate fn suggest_method_call(
&self,
err: &mut DiagnosticBuilder<'a>,
@@ -177,6 +179,7 @@
/// * `span`: the span for the method call
/// * `call_expr`: the complete method call: (`foo.bar::<T1,...Tn>(...)`)
/// * `self_expr`: the self expression (`foo`)
+ #[instrument(level = "debug", skip(self, call_expr, self_expr))]
pub fn lookup_method(
&self,
self_ty: Ty<'tcx>,
@@ -204,6 +207,7 @@
let result =
self.confirm_method(span, self_expr, call_expr, self_ty, pick.clone(), segment);
+ debug!("result = {:?}", result);
if let Some(span) = result.illegal_sized_bound {
let mut needs_mut = false;
@@ -256,6 +260,7 @@
Ok(result.callee)
}
+ #[instrument(level = "debug", skip(self, call_expr))]
pub fn lookup_probe(
&self,
span: Span,
@@ -286,6 +291,7 @@
// FIXME(#18741): it seems likely that we can consolidate some of this
// code with the other method-lookup code. In particular, the second half
// of this method is basically the same as confirmation.
+ #[instrument(level = "debug", skip(self, span, opt_input_types))]
pub fn lookup_method_in_trait(
&self,
span: Span,
@@ -399,7 +405,7 @@
obligations.push(traits::Obligation::new(
cause,
self.param_env,
- ty::PredicateAtom::WellFormed(method_ty.into()).to_predicate(tcx),
+ ty::PredicateKind::WellFormed(method_ty.into()).to_predicate(tcx),
));
let callee = MethodCallee { def_id, substs: trait_ref.substs, sig: fn_sig };
@@ -409,6 +415,7 @@
Some(InferOk { obligations, value: callee })
}
+ #[instrument(level = "debug", skip(self))]
pub fn resolve_ufcs(
&self,
span: Span,
diff --git a/compiler/rustc_typeck/src/check/method/probe.rs b/compiler/rustc_typeck/src/check/method/probe.rs
index 891dd8b..158c214 100644
--- a/compiler/rustc_typeck/src/check/method/probe.rs
+++ b/compiler/rustc_typeck/src/check/method/probe.rs
@@ -8,7 +8,6 @@
use crate::hir::def::DefKind;
use crate::hir::def_id::DefId;
-use rustc_ast as ast;
use rustc_data_structures::fx::FxHashSet;
use rustc_data_structures::sync::Lrc;
use rustc_hir as hir;
@@ -48,7 +47,7 @@
/// Boolean flag used to indicate if this search is for a suggestion
/// or not. If true, we can allow ambiguity and so forth.
-#[derive(Clone, Copy)]
+#[derive(Clone, Copy, Debug)]
pub struct IsSuggestion(pub bool);
struct ProbeContext<'a, 'tcx> {
@@ -219,6 +218,7 @@
/// would result in an error (basically, the same criteria we
/// would use to decide if a method is a plausible fit for
/// ambiguity purposes).
+ #[instrument(level = "debug", skip(self, scope_expr_id))]
pub fn probe_for_return_type(
&self,
span: Span,
@@ -264,6 +264,7 @@
.collect()
}
+ #[instrument(level = "debug", skip(self, scope_expr_id))]
pub fn probe_for_name(
&self,
span: Span,
@@ -423,9 +424,9 @@
probe_cx.assemble_inherent_candidates();
match scope {
ProbeScope::TraitsInScope => {
- probe_cx.assemble_extension_candidates_for_traits_in_scope(scope_expr_id)?
+ probe_cx.assemble_extension_candidates_for_traits_in_scope(scope_expr_id)
}
- ProbeScope::AllTraits => probe_cx.assemble_extension_candidates_for_all_traits()?,
+ ProbeScope::AllTraits => probe_cx.assemble_extension_candidates_for_all_traits(),
};
op(probe_cx)
})
@@ -660,30 +661,30 @@
}
ty::Int(i) => {
let lang_def_id = match i {
- ast::IntTy::I8 => lang_items.i8_impl(),
- ast::IntTy::I16 => lang_items.i16_impl(),
- ast::IntTy::I32 => lang_items.i32_impl(),
- ast::IntTy::I64 => lang_items.i64_impl(),
- ast::IntTy::I128 => lang_items.i128_impl(),
- ast::IntTy::Isize => lang_items.isize_impl(),
+ ty::IntTy::I8 => lang_items.i8_impl(),
+ ty::IntTy::I16 => lang_items.i16_impl(),
+ ty::IntTy::I32 => lang_items.i32_impl(),
+ ty::IntTy::I64 => lang_items.i64_impl(),
+ ty::IntTy::I128 => lang_items.i128_impl(),
+ ty::IntTy::Isize => lang_items.isize_impl(),
};
self.assemble_inherent_impl_for_primitive(lang_def_id);
}
ty::Uint(i) => {
let lang_def_id = match i {
- ast::UintTy::U8 => lang_items.u8_impl(),
- ast::UintTy::U16 => lang_items.u16_impl(),
- ast::UintTy::U32 => lang_items.u32_impl(),
- ast::UintTy::U64 => lang_items.u64_impl(),
- ast::UintTy::U128 => lang_items.u128_impl(),
- ast::UintTy::Usize => lang_items.usize_impl(),
+ ty::UintTy::U8 => lang_items.u8_impl(),
+ ty::UintTy::U16 => lang_items.u16_impl(),
+ ty::UintTy::U32 => lang_items.u32_impl(),
+ ty::UintTy::U64 => lang_items.u64_impl(),
+ ty::UintTy::U128 => lang_items.u128_impl(),
+ ty::UintTy::Usize => lang_items.usize_impl(),
};
self.assemble_inherent_impl_for_primitive(lang_def_id);
}
ty::Float(f) => {
let (lang_def_id1, lang_def_id2) = match f {
- ast::FloatTy::F32 => (lang_items.f32_impl(), lang_items.f32_runtime_impl()),
- ast::FloatTy::F64 => (lang_items.f64_impl(), lang_items.f64_runtime_impl()),
+ ty::FloatTy::F32 => (lang_items.f32_impl(), lang_items.f32_runtime_impl()),
+ ty::FloatTy::F64 => (lang_items.f64_impl(), lang_items.f64_runtime_impl()),
};
self.assemble_inherent_impl_for_primitive(lang_def_id1);
self.assemble_inherent_impl_for_primitive(lang_def_id2);
@@ -770,7 +771,7 @@
// will be reported by `object_safety.rs` if the method refers to the
// `Self` type anywhere other than the receiver. Here, we use a
// substitution that replaces `Self` with the object type itself. Hence,
- // a `&self` method will wind up with an argument type like `&Trait`.
+ // a `&self` method will wind up with an argument type like `&dyn Trait`.
let trait_ref = principal.with_self_ty(self.tcx, self_ty);
self.elaborate_bounds(iter::once(trait_ref), |this, new_trait_ref, item| {
let new_trait_ref = this.erase_late_bound_regions(new_trait_ref);
@@ -795,9 +796,9 @@
debug!("assemble_inherent_candidates_from_param(param_ty={:?})", param_ty);
let bounds = self.param_env.caller_bounds().iter().filter_map(|predicate| {
- let bound_predicate = predicate.bound_atom();
+ let bound_predicate = predicate.kind();
match bound_predicate.skip_binder() {
- ty::PredicateAtom::Trait(trait_predicate, _) => {
+ ty::PredicateKind::Trait(trait_predicate, _) => {
match *trait_predicate.trait_ref.self_ty().kind() {
ty::Param(p) if p == param_ty => {
Some(bound_predicate.rebind(trait_predicate.trait_ref))
@@ -805,16 +806,16 @@
_ => None,
}
}
- ty::PredicateAtom::Subtype(..)
- | ty::PredicateAtom::Projection(..)
- | ty::PredicateAtom::RegionOutlives(..)
- | ty::PredicateAtom::WellFormed(..)
- | ty::PredicateAtom::ObjectSafe(..)
- | ty::PredicateAtom::ClosureKind(..)
- | ty::PredicateAtom::TypeOutlives(..)
- | ty::PredicateAtom::ConstEvaluatable(..)
- | ty::PredicateAtom::ConstEquate(..)
- | ty::PredicateAtom::TypeWellFormedFromEnv(..) => None,
+ ty::PredicateKind::Subtype(..)
+ | ty::PredicateKind::Projection(..)
+ | ty::PredicateKind::RegionOutlives(..)
+ | ty::PredicateKind::WellFormed(..)
+ | ty::PredicateKind::ObjectSafe(..)
+ | ty::PredicateKind::ClosureKind(..)
+ | ty::PredicateKind::TypeOutlives(..)
+ | ty::PredicateKind::ConstEvaluatable(..)
+ | ty::PredicateKind::ConstEquate(..)
+ | ty::PredicateKind::TypeWellFormedFromEnv(..) => None,
}
});
@@ -866,35 +867,29 @@
}
}
- fn assemble_extension_candidates_for_traits_in_scope(
- &mut self,
- expr_hir_id: hir::HirId,
- ) -> Result<(), MethodError<'tcx>> {
+ fn assemble_extension_candidates_for_traits_in_scope(&mut self, expr_hir_id: hir::HirId) {
let mut duplicates = FxHashSet::default();
let opt_applicable_traits = self.tcx.in_scope_traits(expr_hir_id);
if let Some(applicable_traits) = opt_applicable_traits {
for trait_candidate in applicable_traits.iter() {
let trait_did = trait_candidate.def_id;
if duplicates.insert(trait_did) {
- let result = self.assemble_extension_candidates_for_trait(
+ self.assemble_extension_candidates_for_trait(
&trait_candidate.import_ids,
trait_did,
);
- result?;
}
}
}
- Ok(())
}
- fn assemble_extension_candidates_for_all_traits(&mut self) -> Result<(), MethodError<'tcx>> {
+ fn assemble_extension_candidates_for_all_traits(&mut self) {
let mut duplicates = FxHashSet::default();
for trait_info in suggest::all_traits(self.tcx) {
if duplicates.insert(trait_info.def_id) {
- self.assemble_extension_candidates_for_trait(&smallvec![], trait_info.def_id)?;
+ self.assemble_extension_candidates_for_trait(&smallvec![], trait_info.def_id);
}
}
- Ok(())
}
pub fn matches_return_type(
@@ -932,7 +927,7 @@
&mut self,
import_ids: &SmallVec<[LocalDefId; 1]>,
trait_def_id: DefId,
- ) -> Result<(), MethodError<'tcx>> {
+ ) {
debug!("assemble_extension_candidates_for_trait(trait_def_id={:?})", trait_def_id);
let trait_substs = self.fresh_item_substs(trait_def_id);
let trait_ref = ty::TraitRef::new(trait_def_id, trait_substs);
@@ -980,7 +975,6 @@
);
}
}
- Ok(())
}
fn candidate_method_names(&self) -> Vec<Ident> {
@@ -1027,7 +1021,7 @@
let span = self.span;
let tcx = self.tcx;
- self.assemble_extension_candidates_for_all_traits()?;
+ self.assemble_extension_candidates_for_all_traits();
let out_of_scope_traits = match self.pick_core() {
Some(Ok(p)) => vec![p.item.container.id()],
diff --git a/compiler/rustc_typeck/src/check/method/suggest.rs b/compiler/rustc_typeck/src/check/method/suggest.rs
index 3bf4198..d49c7ca 100644
--- a/compiler/rustc_typeck/src/check/method/suggest.rs
+++ b/compiler/rustc_typeck/src/check/method/suggest.rs
@@ -333,7 +333,7 @@
}
ExprKind::Path(ref qpath) => {
// local binding
- if let &QPath::Resolved(_, ref path) = &qpath {
+ if let QPath::Resolved(_, path) = qpath {
if let hir::def::Res::Local(hir_id) = path.res {
let span = tcx.hir().span(hir_id);
let snippet = tcx.sess.source_map().span_to_snippet(span);
@@ -446,6 +446,15 @@
}
}
+ let mut label_span_not_found = || {
+ if unsatisfied_predicates.is_empty() {
+ err.span_label(span, format!("{item_kind} not found in `{ty_str}`"));
+ } else {
+ err.span_label(span, format!("{item_kind} cannot be called on `{ty_str}` due to unsatisfied trait bounds"));
+ }
+ self.tcx.sess.trait_methods_not_found.borrow_mut().insert(orig_span);
+ };
+
// If the method name is the name of a field with a function or closure type,
// give a helping note that it has to be called as `(x.f)(...)`.
if let SelfSource::MethodCall(expr) = source {
@@ -501,12 +510,10 @@
let field_kind = if is_accessible { "field" } else { "private field" };
err.span_label(item_name.span, format!("{}, not a method", field_kind));
} else if lev_candidate.is_none() && static_sources.is_empty() {
- err.span_label(span, format!("{} not found in `{}`", item_kind, ty_str));
- self.tcx.sess.trait_methods_not_found.borrow_mut().insert(orig_span);
+ label_span_not_found();
}
} else {
- err.span_label(span, format!("{} not found in `{}`", item_kind, ty_str));
- self.tcx.sess.trait_methods_not_found.borrow_mut().insert(orig_span);
+ label_span_not_found();
}
if self.is_fn_ty(&rcvr_ty, span) {
@@ -582,8 +589,8 @@
let mut collect_type_param_suggestions =
|self_ty: Ty<'tcx>, parent_pred: &ty::Predicate<'tcx>, obligation: &str| {
// We don't care about regions here, so it's fine to skip the binder here.
- if let (ty::Param(_), ty::PredicateAtom::Trait(p, _)) =
- (self_ty.kind(), parent_pred.skip_binders())
+ if let (ty::Param(_), ty::PredicateKind::Trait(p, _)) =
+ (self_ty.kind(), parent_pred.kind().skip_binder())
{
if let ty::Adt(def, _) = p.trait_ref.self_ty().kind() {
let node = def.did.as_local().map(|def_id| {
@@ -637,9 +644,9 @@
}
};
let mut format_pred = |pred: ty::Predicate<'tcx>| {
- let bound_predicate = pred.bound_atom();
+ let bound_predicate = pred.kind();
match bound_predicate.skip_binder() {
- ty::PredicateAtom::Projection(pred) => {
+ ty::PredicateKind::Projection(pred) => {
let pred = bound_predicate.rebind(pred);
// `<Foo as Iterator>::Item = String`.
let trait_ref =
@@ -658,7 +665,7 @@
bound_span_label(trait_ref.self_ty(), &obligation, &quiet);
Some((obligation, trait_ref.self_ty()))
}
- ty::PredicateAtom::Trait(poly_trait_ref, _) => {
+ ty::PredicateKind::Trait(poly_trait_ref, _) => {
let p = poly_trait_ref.trait_ref;
let self_ty = p.self_ty();
let path = p.print_only_trait_path();
@@ -721,10 +728,12 @@
.map(|(_, path)| path)
.collect::<Vec<_>>()
.join("\n");
+ let actual_prefix = actual.prefix_string();
+ err.set_primary_message(&format!(
+ "the {item_kind} `{item_name}` exists for {actual_prefix} `{ty_str}`, but its trait bounds were not satisfied"
+ ));
err.note(&format!(
- "the method `{}` exists but the following trait bounds were not \
- satisfied:\n{}",
- item_name, bound_list
+ "the following trait bounds were not satisfied:\n{bound_list}"
));
}
}
@@ -742,7 +751,9 @@
);
}
- if actual.is_enum() {
+ // Don't emit a suggestion if we found an actual method
+ // that had unsatisfied trait bounds
+ if unsatisfied_predicates.is_empty() && actual.is_enum() {
let adt_def = actual.ty_adt_def().expect("enum is not an ADT");
if let Some(suggestion) = lev_distance::find_best_match_for_name(
&adt_def.variants.iter().map(|s| s.ident.name).collect::<Vec<_>>(),
@@ -778,17 +789,21 @@
err.span_label(span, msg);
}
} else if let Some(lev_candidate) = lev_candidate {
- let def_kind = lev_candidate.kind.as_def_kind();
- err.span_suggestion(
- span,
- &format!(
- "there is {} {} with a similar name",
- def_kind.article(),
- def_kind.descr(lev_candidate.def_id),
- ),
- lev_candidate.ident.to_string(),
- Applicability::MaybeIncorrect,
- );
+ // Don't emit a suggestion if we found an actual method
+ // that had unsatisfied trait bounds
+ if unsatisfied_predicates.is_empty() {
+ let def_kind = lev_candidate.kind.as_def_kind();
+ err.span_suggestion(
+ span,
+ &format!(
+ "there is {} {} with a similar name",
+ def_kind.article(),
+ def_kind.descr(lev_candidate.def_id),
+ ),
+ lev_candidate.ident.to_string(),
+ Applicability::MaybeIncorrect,
+ );
+ }
}
return Some(err);
@@ -992,11 +1007,11 @@
// implementing a trait would be legal but is rejected
// here).
unsatisfied_predicates.iter().all(|(p, _)| {
- match p.skip_binders() {
+ match p.kind().skip_binder() {
// Hide traits if they are present in predicates as they can be fixed without
// having to implement them.
- ty::PredicateAtom::Trait(t, _) => t.def_id() == info.def_id,
- ty::PredicateAtom::Projection(p) => {
+ ty::PredicateKind::Trait(t, _) => t.def_id() == info.def_id,
+ ty::PredicateKind::Projection(p) => {
p.projection_ty.item_def_id == info.def_id
}
_ => false,
@@ -1193,7 +1208,7 @@
.any(|imp_did| {
let imp = self.tcx.impl_trait_ref(imp_did).unwrap();
let imp_simp = simplify_type(self.tcx, imp.self_ty(), true);
- imp_simp.map(|s| s == simp_rcvr_ty).unwrap_or(false)
+ imp_simp.map_or(false, |s| s == simp_rcvr_ty)
})
{
explicitly_negative.push(candidate);
@@ -1270,11 +1285,7 @@
match ty.kind() {
ty::Adt(def, _) => def.did.is_local(),
ty::Foreign(did) => did.is_local(),
-
- ty::Dynamic(ref tr, ..) => {
- tr.principal().map(|d| d.def_id().is_local()).unwrap_or(false)
- }
-
+ ty::Dynamic(ref tr, ..) => tr.principal().map_or(false, |d| d.def_id().is_local()),
ty::Param(_) => true,
// Everything else (primitive types, etc.) is effectively
diff --git a/compiler/rustc_typeck/src/check/mod.rs b/compiler/rustc_typeck/src/check/mod.rs
index 8177b36..dc3e3b4 100644
--- a/compiler/rustc_typeck/src/check/mod.rs
+++ b/compiler/rustc_typeck/src/check/mod.rs
@@ -52,13 +52,13 @@
variables, are stored directly into the `tcx` typeck_results.
N.B., a type variable is not the same thing as a type parameter. A
-type variable is rather an "instance" of a type parameter: that is,
-given a generic function `fn foo<T>(t: T)`: while checking the
+type variable is an instance of a type parameter. That is,
+given a generic function `fn foo<T>(t: T)`, while checking the
function `foo`, the type `ty_param(0)` refers to the type `T`, which
-is treated in abstract. When `foo()` is called, however, `T` will be
+is treated in abstract. However, when `foo()` is called, `T` will be
substituted for a fresh type variable `N`. This variable will
eventually be resolved to some concrete type (which might itself be
-type parameter).
+a type parameter).
*/
@@ -184,14 +184,14 @@
UnsafetyState { def, unsafety, unsafe_push_count: 0, from_fn: true }
}
- pub fn recurse(&mut self, blk: &hir::Block<'_>) -> UnsafetyState {
+ pub fn recurse(self, blk: &hir::Block<'_>) -> UnsafetyState {
use hir::BlockCheckMode;
match self.unsafety {
// If this unsafe, then if the outer function was already marked as
// unsafe we shouldn't attribute the unsafe'ness to the block. This
// way the block can be warned about instead of ignoring this
// extraneous block (functions are never warned about).
- hir::Unsafety::Unsafe if self.from_fn => *self,
+ hir::Unsafety::Unsafe if self.from_fn => self,
unsafety => {
let (unsafety, def, count) = match blk.rules {
@@ -864,9 +864,9 @@
let mut projections = vec![];
for (predicate, _) in predicates.predicates {
debug!("predicate {:?}", predicate);
- let bound_predicate = predicate.bound_atom();
+ let bound_predicate = predicate.kind();
match bound_predicate.skip_binder() {
- ty::PredicateAtom::Trait(trait_predicate, _) => {
+ ty::PredicateKind::Trait(trait_predicate, _) => {
let entry = types.entry(trait_predicate.self_ty()).or_default();
let def_id = trait_predicate.def_id();
if Some(def_id) != tcx.lang_items().sized_trait() {
@@ -875,7 +875,7 @@
entry.push(trait_predicate.def_id());
}
}
- ty::PredicateAtom::Projection(projection_pred) => {
+ ty::PredicateKind::Projection(projection_pred) => {
projections.push(bound_predicate.rebind(projection_pred));
}
_ => {}
diff --git a/compiler/rustc_typeck/src/check/pat.rs b/compiler/rustc_typeck/src/check/pat.rs
index 5fc573a..d7e6966 100644
--- a/compiler/rustc_typeck/src/check/pat.rs
+++ b/compiler/rustc_typeck/src/check/pat.rs
@@ -15,6 +15,7 @@
use rustc_span::lev_distance::find_best_match_for_name;
use rustc_span::source_map::{Span, Spanned};
use rustc_span::symbol::Ident;
+use rustc_span::{BytePos, DUMMY_SP};
use rustc_trait_selection::traits::{ObligationCause, Pattern};
use std::cmp;
@@ -1001,7 +1002,7 @@
// More generally, the expected type wants a tuple variant with one field of an
// N-arity-tuple, e.g., `V_i((p_0, .., p_N))`. Meanwhile, the user supplied a pattern
// with the subpatterns directly in the tuple variant pattern, e.g., `V_i(p_0, .., p_N)`.
- let missing_parenthesis = match (&expected.kind(), fields, had_err) {
+ let missing_parentheses = match (&expected.kind(), fields, had_err) {
// #67037: only do this if we could successfully type-check the expected type against
// the tuple struct pattern. Otherwise the substs could get out of range on e.g.,
// `let P() = U;` where `P != U` with `struct P<T>(T);`.
@@ -1014,13 +1015,13 @@
}
_ => false,
};
- if missing_parenthesis {
+ if missing_parentheses {
let (left, right) = match subpats {
// This is the zero case; we aim to get the "hi" part of the `QPath`'s
// span as the "lo" and then the "hi" part of the pattern's span as the "hi".
// This looks like:
//
- // help: missing parenthesis
+ // help: missing parentheses
// |
// L | let A(()) = A(());
// | ^ ^
@@ -1029,17 +1030,71 @@
// last sub-pattern. In the case of `A(x)` the first and last may coincide.
// This looks like:
//
- // help: missing parenthesis
+ // help: missing parentheses
// |
// L | let A((x, y)) = A((1, 2));
// | ^ ^
[first, ..] => (first.span.shrink_to_lo(), subpats.last().unwrap().span),
};
err.multipart_suggestion(
- "missing parenthesis",
+ "missing parentheses",
vec![(left, "(".to_string()), (right.shrink_to_hi(), ")".to_string())],
Applicability::MachineApplicable,
);
+ } else if fields.len() > subpats.len() && pat_span != DUMMY_SP {
+ let after_fields_span = pat_span.with_hi(pat_span.hi() - BytePos(1)).shrink_to_hi();
+ let all_fields_span = match subpats {
+ [] => after_fields_span,
+ [field] => field.span,
+ [first, .., last] => first.span.to(last.span),
+ };
+
+ // Check if all the fields in the pattern are wildcards.
+ let all_wildcards = subpats.iter().all(|pat| matches!(pat.kind, PatKind::Wild));
+ let first_tail_wildcard =
+ subpats.iter().enumerate().fold(None, |acc, (pos, pat)| match (acc, &pat.kind) {
+ (None, PatKind::Wild) => Some(pos),
+ (Some(_), PatKind::Wild) => acc,
+ _ => None,
+ });
+ let tail_span = match first_tail_wildcard {
+ None => after_fields_span,
+ Some(0) => subpats[0].span.to(after_fields_span),
+ Some(pos) => subpats[pos - 1].span.shrink_to_hi().to(after_fields_span),
+ };
+
+ // FIXME: heuristic-based suggestion to check current types for where to add `_`.
+ let mut wildcard_sugg = vec!["_"; fields.len() - subpats.len()].join(", ");
+ if !subpats.is_empty() {
+ wildcard_sugg = String::from(", ") + &wildcard_sugg;
+ }
+
+ err.span_suggestion_verbose(
+ after_fields_span,
+ "use `_` to explicitly ignore each field",
+ wildcard_sugg,
+ Applicability::MaybeIncorrect,
+ );
+
+ // Only suggest `..` if more than one field is missing
+ // or the pattern consists of all wildcards.
+ if fields.len() - subpats.len() > 1 || all_wildcards {
+ if subpats.is_empty() || all_wildcards {
+ err.span_suggestion_verbose(
+ all_fields_span,
+ "use `..` to ignore all fields",
+ String::from(".."),
+ Applicability::MaybeIncorrect,
+ );
+ } else {
+ err.span_suggestion_verbose(
+ tail_span,
+ "use `..` to ignore the rest of the fields",
+ String::from(", .."),
+ Applicability::MaybeIncorrect,
+ );
+ }
+ }
}
err.emit();
@@ -1439,11 +1494,11 @@
/// Returns a diagnostic reporting a struct pattern which does not mention some fields.
///
/// ```text
- /// error[E0027]: pattern does not mention field `you_cant_use_this_field`
+ /// error[E0027]: pattern does not mention field `bar`
/// --> src/main.rs:15:9
/// |
/// LL | let foo::Foo {} = foo::Foo::new();
- /// | ^^^^^^^^^^^ missing field `you_cant_use_this_field`
+ /// | ^^^^^^^^^^^ missing field `bar`
/// ```
fn error_unmentioned_fields(
&self,
@@ -1477,14 +1532,15 @@
}
_ => return err,
},
- [.., field] => (
- match pat.kind {
- PatKind::Struct(_, [_, ..], _) => ", ",
- _ => "",
- },
- "",
- field.span.shrink_to_hi(),
- ),
+ [.., field] => {
+ // Account for last field having a trailing comma or parse recovery at the tail of
+ // the pattern to avoid invalid suggestion (#78511).
+ let tail = field.span.shrink_to_hi().with_hi(pat.span.hi());
+ match &pat.kind {
+ PatKind::Struct(..) => (", ", " }", tail),
+ _ => return err,
+ }
+ }
};
err.span_suggestion(
sp,
diff --git a/compiler/rustc_typeck/src/check/regionck.rs b/compiler/rustc_typeck/src/check/regionck.rs
index b8b98ce..88e8dd3 100644
--- a/compiler/rustc_typeck/src/check/regionck.rs
+++ b/compiler/rustc_typeck/src/check/regionck.rs
@@ -325,7 +325,7 @@
pat.each_binding(|_, hir_id, span, _| {
let typ = self.resolve_node_type(hir_id);
let body_id = self.body_id;
- let _ = dropck::check_drop_obligations(self, typ, span, body_id);
+ dropck::check_drop_obligations(self, typ, span, body_id);
})
}
}
@@ -354,10 +354,7 @@
hir_id: hir::HirId,
) {
assert!(
- match fk {
- intravisit::FnKind::Closure(..) => true,
- _ => false,
- },
+ matches!(fk, intravisit::FnKind::Closure(..)),
"visit_fn invoked for something other than a closure"
);
@@ -491,7 +488,7 @@
if place_with_id.place.projections.is_empty() {
let typ = self.resolve_type(place_with_id.place.ty());
let body_id = self.body_id;
- let _ = dropck::check_drop_obligations(self, typ, span, body_id);
+ dropck::check_drop_obligations(self, typ, span, body_id);
}
}
}
diff --git a/compiler/rustc_typeck/src/check/upvar.rs b/compiler/rustc_typeck/src/check/upvar.rs
index 0f084c5..04a9e65 100644
--- a/compiler/rustc_typeck/src/check/upvar.rs
+++ b/compiler/rustc_typeck/src/check/upvar.rs
@@ -30,6 +30,7 @@
//! then mean that all later passes would have to check for these figments
//! and report an error, and it just seems like more mess in the end.)
+use super::writeback::Resolver;
use super::FnCtxt;
use crate::expr_use_visitor as euv;
@@ -40,9 +41,11 @@
use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
use rustc_infer::infer::UpvarRegion;
use rustc_middle::hir::place::{Place, PlaceBase, PlaceWithHirId, ProjectionKind};
-use rustc_middle::ty::{self, Ty, TyCtxt, UpvarSubsts};
+use rustc_middle::ty::fold::TypeFoldable;
+use rustc_middle::ty::{self, Ty, TyCtxt, TypeckResults, UpvarSubsts};
+use rustc_session::lint;
use rustc_span::sym;
-use rustc_span::{Span, Symbol};
+use rustc_span::{MultiSpan, Span, Symbol};
/// Describe the relationship between the paths of two places
/// eg:
@@ -55,6 +58,11 @@
Divergent,
}
+/// Intermediate format to store a captured `Place` and associated `ty::CaptureInfo`
+/// during capture analysis. Information in this map feeds into the minimum capture
+/// analysis pass.
+type InferredCaptureInformation<'tcx> = FxIndexMap<Place<'tcx>, ty::CaptureInfo<'tcx>>;
+
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
pub fn closure_analyze(&self, body: &'tcx hir::Body<'tcx>) {
InferBorrowKindVisitor { fcx: self }.visit_body(body);
@@ -92,7 +100,7 @@
&self,
closure_hir_id: hir::HirId,
span: Span,
- body: &hir::Body<'_>,
+ body: &'tcx hir::Body<'tcx>,
capture_clause: hir::CaptureBy,
) {
debug!("analyze_closure(id={:?}, body.id={:?})", closure_hir_id, body.id());
@@ -124,24 +132,6 @@
let local_def_id = closure_def_id.expect_local();
- let mut capture_information: FxIndexMap<Place<'tcx>, ty::CaptureInfo<'tcx>> =
- Default::default();
- if !self.tcx.features().capture_disjoint_fields {
- if let Some(upvars) = self.tcx.upvars_mentioned(closure_def_id) {
- for (&var_hir_id, _) in upvars.iter() {
- let place = self.place_for_root_variable(local_def_id, var_hir_id);
-
- debug!("seed place {:?}", place);
-
- let upvar_id = ty::UpvarId::new(var_hir_id, local_def_id);
- let capture_kind = self.init_capture_kind(capture_clause, upvar_id, span);
- let info = ty::CaptureInfo { expr_id: None, capture_kind };
-
- capture_information.insert(place, info);
- }
- }
- }
-
let body_owner_def_id = self.tcx.hir().body_owner_def_id(body.id());
assert_eq!(body_owner_def_id.to_def_id(), closure_def_id);
let mut delegate = InferBorrowKind {
@@ -151,7 +141,7 @@
capture_clause,
current_closure_kind: ty::ClosureKind::LATTICE_BOTTOM,
current_origin: None,
- capture_information,
+ capture_information: Default::default(),
};
euv::ExprUseVisitor::new(
&mut delegate,
@@ -168,6 +158,40 @@
);
self.log_capture_analysis_first_pass(closure_def_id, &delegate.capture_information, span);
+ self.compute_min_captures(closure_def_id, delegate.capture_information);
+
+ let closure_hir_id = self.tcx.hir().local_def_id_to_hir_id(local_def_id);
+ if should_do_migration_analysis(self.tcx, closure_hir_id) {
+ self.perform_2229_migration_anaysis(closure_def_id, capture_clause, span, body);
+ }
+
+ // We now fake capture information for all variables that are mentioned within the closure
+ // We do this after handling migrations so that min_captures computes before
+ if !self.tcx.features().capture_disjoint_fields {
+ let mut capture_information: InferredCaptureInformation<'tcx> = Default::default();
+
+ if let Some(upvars) = self.tcx.upvars_mentioned(closure_def_id) {
+ for var_hir_id in upvars.keys() {
+ let place = self.place_for_root_variable(local_def_id, *var_hir_id);
+
+ debug!("seed place {:?}", place);
+
+ let upvar_id = ty::UpvarId::new(*var_hir_id, local_def_id);
+ let capture_kind = self.init_capture_kind(capture_clause, upvar_id, span);
+ let fake_info = ty::CaptureInfo {
+ capture_kind_expr_id: None,
+ path_expr_id: None,
+ capture_kind,
+ };
+
+ capture_information.insert(place, fake_info);
+ }
+ }
+
+ // This will update the min captures based on this new fake information.
+ self.compute_min_captures(closure_def_id, capture_information);
+ }
+
if let Some(closure_substs) = infer_kind {
// Unify the (as yet unbound) type variable in the closure
// substs with the kind we inferred.
@@ -176,7 +200,16 @@
self.demand_eqtype(span, inferred_kind.to_ty(self.tcx), closure_kind_ty);
// If we have an origin, store it.
- if let Some(origin) = delegate.current_origin {
+ if let Some(origin) = delegate.current_origin.clone() {
+ let origin = if self.tcx.features().capture_disjoint_fields {
+ origin
+ } else {
+ // FIXME(project-rfc-2229#31): Once the changes to support reborrowing are
+ // made, make sure we are selecting and restricting
+ // the origin correctly.
+ (origin.0, Place { projections: vec![], ..origin.1 })
+ };
+
self.typeck_results
.borrow_mut()
.closure_kind_origins_mut()
@@ -184,7 +217,6 @@
}
}
- self.compute_min_captures(closure_def_id, delegate);
self.log_closure_min_capture_info(closure_def_id, span);
self.min_captures_to_closure_captures_bridge(closure_def_id);
@@ -238,8 +270,8 @@
let capture = captured_place.info.capture_kind;
debug!(
- "place={:?} upvar_ty={:?} capture={:?}",
- captured_place.place, upvar_ty, capture
+ "final_upvar_tys: place={:?} upvar_ty={:?} capture={:?}, mutability={:?}",
+ captured_place.place, upvar_ty, capture, captured_place.mutability,
);
match capture {
@@ -298,8 +330,11 @@
if let Some(capture_kind) = upvar_capture_map.get(&upvar_id) {
// upvar_capture_map only stores the UpvarCapture (CaptureKind),
// so we create a fake capture info with no expression.
- let fake_capture_info =
- ty::CaptureInfo { expr_id: None, capture_kind: *capture_kind };
+ let fake_capture_info = ty::CaptureInfo {
+ capture_kind_expr_id: None,
+ path_expr_id: None,
+ capture_kind: *capture_kind,
+ };
determine_capture_info(fake_capture_info, capture_info).capture_kind
} else {
capture_info.capture_kind
@@ -328,6 +363,10 @@
/// Places (and corresponding capture kind) that we need to keep track of to support all
/// the required captured paths.
///
+ ///
+ /// Note: If this function is called multiple times for the same closure, it will update
+ /// the existing min_capture map that is stored in TypeckResults.
+ ///
/// Eg:
/// ```rust,no_run
/// struct Point { x: i32, y: i32 }
@@ -349,48 +388,73 @@
///
/// ```
/// {
- /// Place(base: hir_id_s, projections: [], ....) -> (hir_id_L5, ByValue),
- /// Place(base: hir_id_p, projections: [Field(0, 0)], ...) -> (hir_id_L2, ByRef(MutBorrow))
- /// Place(base: hir_id_p, projections: [Field(1, 0)], ...) -> (hir_id_L3, ByRef(ImmutBorrow))
- /// Place(base: hir_id_p, projections: [], ...) -> (hir_id_L4, ByRef(ImmutBorrow))
+ /// Place(base: hir_id_s, projections: [], ....) -> {
+ /// capture_kind_expr: hir_id_L5,
+ /// path_expr_id: hir_id_L5,
+ /// capture_kind: ByValue
+ /// },
+ /// Place(base: hir_id_p, projections: [Field(0, 0)], ...) -> {
+ /// capture_kind_expr: hir_id_L2,
+ /// path_expr_id: hir_id_L2,
+ /// capture_kind: ByValue
+ /// },
+ /// Place(base: hir_id_p, projections: [Field(1, 0)], ...) -> {
+ /// capture_kind_expr: hir_id_L3,
+ /// path_expr_id: hir_id_L3,
+ /// capture_kind: ByValue
+ /// },
+ /// Place(base: hir_id_p, projections: [], ...) -> {
+ /// capture_kind_expr: hir_id_L4,
+ /// path_expr_id: hir_id_L4,
+ /// capture_kind: ByValue
+ /// },
/// ```
///
/// After the min capture analysis, we get:
/// ```
/// {
/// hir_id_s -> [
- /// Place(base: hir_id_s, projections: [], ....) -> (hir_id_L4, ByValue)
+ /// Place(base: hir_id_s, projections: [], ....) -> {
+ /// capture_kind_expr: hir_id_L5,
+ /// path_expr_id: hir_id_L5,
+ /// capture_kind: ByValue
+ /// },
/// ],
/// hir_id_p -> [
- /// Place(base: hir_id_p, projections: [], ...) -> (hir_id_L2, ByRef(MutBorrow)),
+ /// Place(base: hir_id_p, projections: [], ...) -> {
+ /// capture_kind_expr: hir_id_L2,
+ /// path_expr_id: hir_id_L4,
+ /// capture_kind: ByValue
+ /// },
/// ],
/// ```
fn compute_min_captures(
&self,
closure_def_id: DefId,
- inferred_info: InferBorrowKind<'_, 'tcx>,
+ capture_information: InferredCaptureInformation<'tcx>,
) {
- let mut root_var_min_capture_list: ty::RootVariableMinCaptureList<'_> = Default::default();
+ if capture_information.is_empty() {
+ return;
+ }
- for (place, capture_info) in inferred_info.capture_information.into_iter() {
+ let mut typeck_results = self.typeck_results.borrow_mut();
+
+ let mut root_var_min_capture_list =
+ typeck_results.closure_min_captures.remove(&closure_def_id).unwrap_or_default();
+
+ for (place, capture_info) in capture_information.into_iter() {
let var_hir_id = match place.base {
PlaceBase::Upvar(upvar_id) => upvar_id.var_path.hir_id,
base => bug!("Expected upvar, found={:?}", base),
};
- // Arrays are captured in entirety, drop Index projections and projections
- // after Index projections.
- let first_index_projection =
- place.projections.split(|proj| ProjectionKind::Index == proj.kind).next();
- let place = Place {
- base_ty: place.base_ty,
- base: place.base,
- projections: first_index_projection.map_or(Vec::new(), |p| p.to_vec()),
- };
+ let place = restrict_capture_precision(place, capture_info.capture_kind);
let min_cap_list = match root_var_min_capture_list.get_mut(&var_hir_id) {
None => {
- let min_cap_list = vec![ty::CapturedPlace { place: place, info: capture_info }];
+ let mutability = self.determine_capture_mutability(&typeck_results, &place);
+ let min_cap_list =
+ vec![ty::CapturedPlace { place, info: capture_info, mutability }];
root_var_min_capture_list.insert(var_hir_id, min_cap_list);
continue;
}
@@ -415,8 +479,13 @@
// current place is ancestor of possible_descendant
PlaceAncestryRelation::Ancestor => {
descendant_found = true;
+ let backup_path_expr_id = updated_capture_info.path_expr_id;
+
updated_capture_info =
determine_capture_info(updated_capture_info, possible_descendant.info);
+
+ // we need to keep the ancestor's `path_expr_id`
+ updated_capture_info.path_expr_id = backup_path_expr_id;
false
}
@@ -431,9 +500,13 @@
// current place is descendant of possible_ancestor
PlaceAncestryRelation::Descendant => {
ancestor_found = true;
+ let backup_path_expr_id = possible_ancestor.info.path_expr_id;
possible_ancestor.info =
determine_capture_info(possible_ancestor.info, capture_info);
+ // we need to keep the ancestor's `path_expr_id`
+ possible_ancestor.info.path_expr_id = backup_path_expr_id;
+
// Only one ancestor of the current place will be in the list.
break;
}
@@ -444,22 +517,131 @@
// Only need to insert when we don't have an ancestor in the existing min capture list
if !ancestor_found {
+ let mutability = self.determine_capture_mutability(&typeck_results, &place);
let captured_place =
- ty::CapturedPlace { place: place.clone(), info: updated_capture_info };
+ ty::CapturedPlace { place, info: updated_capture_info, mutability };
min_cap_list.push(captured_place);
}
}
debug!("For closure={:?}, min_captures={:#?}", closure_def_id, root_var_min_capture_list);
+ typeck_results.closure_min_captures.insert(closure_def_id, root_var_min_capture_list);
+ }
- if !root_var_min_capture_list.is_empty() {
- self.typeck_results
- .borrow_mut()
- .closure_min_captures
- .insert(closure_def_id, root_var_min_capture_list);
+ /// Perform the migration analysis for RFC 2229, and emit lint
+ /// `disjoint_capture_drop_reorder` if needed.
+ fn perform_2229_migration_anaysis(
+ &self,
+ closure_def_id: DefId,
+ capture_clause: hir::CaptureBy,
+ span: Span,
+ body: &'tcx hir::Body<'tcx>,
+ ) {
+ let need_migrations = self.compute_2229_migrations_first_pass(
+ closure_def_id,
+ span,
+ capture_clause,
+ body,
+ self.typeck_results.borrow().closure_min_captures.get(&closure_def_id),
+ );
+
+ if !need_migrations.is_empty() {
+ let need_migrations_hir_id = need_migrations.iter().map(|m| m.0).collect::<Vec<_>>();
+
+ let migrations_text = migration_suggestion_for_2229(self.tcx, &need_migrations_hir_id);
+
+ let local_def_id = closure_def_id.expect_local();
+ let closure_hir_id = self.tcx.hir().local_def_id_to_hir_id(local_def_id);
+ self.tcx.struct_span_lint_hir(
+ lint::builtin::DISJOINT_CAPTURE_DROP_REORDER,
+ closure_hir_id,
+ span,
+ |lint| {
+ let mut diagnostics_builder = lint.build(
+ "drop order affected for closure because of `capture_disjoint_fields`",
+ );
+ diagnostics_builder.note(&migrations_text);
+ diagnostics_builder.emit();
+ },
+ );
}
}
+ /// Figures out the list of root variables (and their types) that aren't completely
+ /// captured by the closure when `capture_disjoint_fields` is enabled and drop order of
+ /// some path starting at that root variable **might** be affected.
+ ///
+ /// The output list would include a root variable if:
+ /// - It would have been moved into the closure when `capture_disjoint_fields` wasn't
+ /// enabled, **and**
+ /// - It wasn't completely captured by the closure, **and**
+ /// - The type of the root variable needs Drop.
+ fn compute_2229_migrations_first_pass(
+ &self,
+ closure_def_id: DefId,
+ closure_span: Span,
+ closure_clause: hir::CaptureBy,
+ body: &'tcx hir::Body<'tcx>,
+ min_captures: Option<&ty::RootVariableMinCaptureList<'tcx>>,
+ ) -> Vec<(hir::HirId, Ty<'tcx>)> {
+ fn resolve_ty<T: TypeFoldable<'tcx>>(
+ fcx: &FnCtxt<'_, 'tcx>,
+ span: Span,
+ body: &'tcx hir::Body<'tcx>,
+ ty: T,
+ ) -> T {
+ let mut resolver = Resolver::new(fcx, &span, body);
+ ty.fold_with(&mut resolver)
+ }
+
+ let upvars = if let Some(upvars) = self.tcx.upvars_mentioned(closure_def_id) {
+ upvars
+ } else {
+ return vec![];
+ };
+
+ let mut need_migrations = Vec::new();
+
+ for (&var_hir_id, _) in upvars.iter() {
+ let ty = resolve_ty(self, closure_span, body, self.node_ty(var_hir_id));
+
+ if !ty.needs_drop(self.tcx, self.tcx.param_env(closure_def_id.expect_local())) {
+ continue;
+ }
+
+ let root_var_min_capture_list = if let Some(root_var_min_capture_list) =
+ min_captures.and_then(|m| m.get(&var_hir_id))
+ {
+ root_var_min_capture_list
+ } else {
+ // The upvar is mentioned within the closure but no path starting from it is
+ // used.
+
+ match closure_clause {
+ // Only migrate if closure is a move closure
+ hir::CaptureBy::Value => need_migrations.push((var_hir_id, ty)),
+
+ hir::CaptureBy::Ref => {}
+ }
+
+ continue;
+ };
+
+ let is_moved = root_var_min_capture_list
+ .iter()
+ .any(|capture| matches!(capture.info.capture_kind, ty::UpvarCapture::ByValue(_)));
+
+ let is_not_completely_captured =
+ root_var_min_capture_list.iter().any(|capture| capture.place.projections.len() > 0);
+
+ if is_moved && is_not_completely_captured {
+ need_migrations.push((var_hir_id, ty));
+ }
+ }
+
+ need_migrations
+ }
+
fn init_capture_kind(
&self,
capture_clause: hir::CaptureBy,
@@ -508,7 +690,8 @@
let capture_str = construct_capture_info_string(self.tcx, place, capture_info);
let output_str = format!("Capturing {}", capture_str);
- let span = capture_info.expr_id.map_or(closure_span, |e| self.tcx.hir().span(e));
+ let span =
+ capture_info.path_expr_id.map_or(closure_span, |e| self.tcx.hir().span(e));
diag.span_note(span, &output_str);
}
diag.emit();
@@ -532,15 +715,80 @@
construct_capture_info_string(self.tcx, place, capture_info);
let output_str = format!("Min Capture {}", capture_str);
- let span =
- capture_info.expr_id.map_or(closure_span, |e| self.tcx.hir().span(e));
- diag.span_note(span, &output_str);
+ if capture.info.path_expr_id != capture.info.capture_kind_expr_id {
+ let path_span = capture_info
+ .path_expr_id
+ .map_or(closure_span, |e| self.tcx.hir().span(e));
+ let capture_kind_span = capture_info
+ .capture_kind_expr_id
+ .map_or(closure_span, |e| self.tcx.hir().span(e));
+
+ let mut multi_span: MultiSpan =
+ MultiSpan::from_spans(vec![path_span, capture_kind_span]);
+
+ let capture_kind_label =
+ construct_capture_kind_reason_string(self.tcx, place, capture_info);
+ let path_label = construct_path_string(self.tcx, place);
+
+ multi_span.push_span_label(path_span, path_label);
+ multi_span.push_span_label(capture_kind_span, capture_kind_label);
+
+ diag.span_note(multi_span, &output_str);
+ } else {
+ let span = capture_info
+ .path_expr_id
+ .map_or(closure_span, |e| self.tcx.hir().span(e));
+
+ diag.span_note(span, &output_str);
+ };
}
}
diag.emit();
}
}
}
+
+ /// A captured place is mutable if
+ /// 1. Projections don't include a Deref of an immut-borrow, **and**
+ /// 2. PlaceBase is mut or projections include a Deref of a mut-borrow.
+ fn determine_capture_mutability(
+ &self,
+ typeck_results: &'a TypeckResults<'tcx>,
+ place: &Place<'tcx>,
+ ) -> hir::Mutability {
+ let var_hir_id = match place.base {
+ PlaceBase::Upvar(upvar_id) => upvar_id.var_path.hir_id,
+ _ => unreachable!(),
+ };
+
+ let bm = *typeck_results.pat_binding_modes().get(var_hir_id).expect("missing binding mode");
+
+ let mut is_mutbl = match bm {
+ ty::BindByValue(mutability) => mutability,
+ ty::BindByReference(_) => hir::Mutability::Not,
+ };
+
+ for pointer_ty in place.deref_tys() {
+ match pointer_ty.kind() {
+ // We don't capture derefs of raw ptrs
+ ty::RawPtr(_) => unreachable!(),
+
+ // Derefencing a mut-ref allows us to mut the Place if we don't deref
+ // an immut-ref after on top of this.
+ ty::Ref(.., hir::Mutability::Mut) => is_mutbl = hir::Mutability::Mut,
+
+ // The place isn't mutable once we dereference a immutable reference.
+ ty::Ref(.., hir::Mutability::Not) => return hir::Mutability::Not,
+
+ // Dereferencing a box doesn't change mutability
+ ty::Adt(def, ..) if def.is_box() => {}
+
+ unexpected_ty => bug!("deref of unexpected pointer type {:?}", unexpected_ty),
+ }
+ }
+
+ is_mutbl
+ }
}
struct InferBorrowKind<'a, 'tcx> {
@@ -563,7 +811,7 @@
// If we modified `current_closure_kind`, this field contains a `Some()` with the
// variable access that caused us to do so.
- current_origin: Option<(Span, Symbol)>,
+ current_origin: Option<(Span, Place<'tcx>)>,
/// For each Place that is captured by the closure, we track the minimal kind of
/// access we need (ref, ref mut, move, etc) and the expression that resulted in such access.
@@ -587,9 +835,11 @@
///
/// For closure `fix_s`, (at a high level) the map contains
///
+ /// ```
/// Place { V1, [ProjectionKind::Field(Index=0, Variant=0)] } : CaptureKind { E1, ImmutableBorrow }
/// Place { V1, [ProjectionKind::Field(Index=1, Variant=0)] } : CaptureKind { E2, MutableBorrow }
- capture_information: FxIndexMap<Place<'tcx>, ty::CaptureInfo<'tcx>>,
+ /// ```
+ capture_information: InferredCaptureInformation<'tcx>,
}
impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> {
@@ -628,11 +878,12 @@
upvar_id.closure_expr_id,
ty::ClosureKind::FnOnce,
usage_span,
- var_name(tcx, upvar_id.var_path.hir_id),
+ place_with_id.place.clone(),
);
let capture_info = ty::CaptureInfo {
- expr_id: Some(diag_expr_id),
+ capture_kind_expr_id: Some(diag_expr_id),
+ path_expr_id: Some(diag_expr_id),
capture_kind: ty::UpvarCapture::ByValue(Some(usage_span)),
};
@@ -720,7 +971,7 @@
upvar_id.closure_expr_id,
ty::ClosureKind::FnMut,
tcx.hir().span(diag_expr_id),
- var_name(tcx, upvar_id.var_path.hir_id),
+ place_with_id.place.clone(),
);
}
}
@@ -752,7 +1003,8 @@
let new_upvar_borrow = ty::UpvarBorrow { kind, region: curr_upvar_borrow.region };
let capture_info = ty::CaptureInfo {
- expr_id: Some(diag_expr_id),
+ capture_kind_expr_id: Some(diag_expr_id),
+ path_expr_id: Some(diag_expr_id),
capture_kind: ty::UpvarCapture::ByRef(new_upvar_borrow),
};
let updated_info = determine_capture_info(curr_capture_info, capture_info);
@@ -765,11 +1017,11 @@
closure_id: LocalDefId,
new_kind: ty::ClosureKind,
upvar_span: Span,
- var_name: Symbol,
+ place: Place<'tcx>,
) {
debug!(
- "adjust_closure_kind(closure_id={:?}, new_kind={:?}, upvar_span={:?}, var_name={})",
- closure_id, new_kind, upvar_span, var_name
+ "adjust_closure_kind(closure_id={:?}, new_kind={:?}, upvar_span={:?}, place={:?})",
+ closure_id, new_kind, upvar_span, place
);
// Is this the closure whose kind is currently being inferred?
@@ -797,7 +1049,7 @@
| (ty::ClosureKind::FnMut, ty::ClosureKind::FnOnce) => {
// new kind is stronger than the old kind
self.current_closure_kind = new_kind;
- self.current_origin = Some((upvar_span, var_name));
+ self.current_origin = Some((upvar_span, place));
}
}
}
@@ -814,7 +1066,11 @@
self.fcx.init_capture_kind(self.capture_clause, upvar_id, self.closure_span);
let expr_id = Some(diag_expr_id);
- let capture_info = ty::CaptureInfo { expr_id, capture_kind };
+ let capture_info = ty::CaptureInfo {
+ capture_kind_expr_id: expr_id,
+ path_expr_id: expr_id,
+ capture_kind,
+ };
debug!("Capturing new place {:?}, capture_info={:?}", place_with_id, capture_info);
@@ -880,11 +1136,67 @@
}
}
-fn construct_capture_info_string(
- tcx: TyCtxt<'_>,
- place: &Place<'tcx>,
- capture_info: &ty::CaptureInfo<'tcx>,
-) -> String {
+/// Truncate projections so that following rules are obeyed by the captured `place`:
+///
+/// - No Derefs in move closure, this will result in value behind a reference getting moved.
+/// - No projections are applied to raw pointers, since these require unsafe blocks. We capture
+/// them completely.
+/// - No Index projections are captured, since arrays are captured completely.
+fn restrict_capture_precision<'tcx>(
+ mut place: Place<'tcx>,
+ capture_kind: ty::UpvarCapture<'tcx>,
+) -> Place<'tcx> {
+ if place.projections.is_empty() {
+ // Nothing to do here
+ return place;
+ }
+
+ if place.base_ty.is_unsafe_ptr() {
+ place.projections.truncate(0);
+ return place;
+ }
+
+ let mut truncated_length = usize::MAX;
+ let mut first_deref_projection = usize::MAX;
+
+ for (i, proj) in place.projections.iter().enumerate() {
+ if proj.ty.is_unsafe_ptr() {
+ // Don't apply any projections on top of an unsafe ptr
+ truncated_length = truncated_length.min(i + 1);
+ break;
+ }
+ match proj.kind {
+ ProjectionKind::Index => {
+ // Arrays are completely captured, so we drop Index projections
+ truncated_length = truncated_length.min(i);
+ break;
+ }
+ ProjectionKind::Deref => {
+ // We only drop Derefs in case of move closures
+ // There might be an index projection or raw ptr ahead, so we don't stop here.
+ first_deref_projection = first_deref_projection.min(i);
+ }
+ ProjectionKind::Field(..) => {} // ignore
+ ProjectionKind::Subslice => {} // We never capture this
+ }
+ }
+
+ let length = place
+ .projections
+ .len()
+ .min(truncated_length)
+ // In case of capture `ByValue` we want to not capture derefs
+ .min(match capture_kind {
+ ty::UpvarCapture::ByValue(..) => first_deref_projection,
+ ty::UpvarCapture::ByRef(..) => usize::MAX,
+ });
+
+ place.projections.truncate(length);
+
+ place
+}
+
+fn construct_place_string(tcx: TyCtxt<'_>, place: &Place<'tcx>) -> String {
let variable_name = match place.base {
PlaceBase::Upvar(upvar_id) => var_name(tcx, upvar_id.var_path.hir_id).to_string(),
_ => bug!("Capture_information should only contain upvars"),
@@ -904,23 +1216,71 @@
projections_str.push_str(proj.as_str());
}
+ format!("{}[{}]", variable_name, projections_str)
+}
+
+fn construct_capture_kind_reason_string(
+ tcx: TyCtxt<'_>,
+ place: &Place<'tcx>,
+ capture_info: &ty::CaptureInfo<'tcx>,
+) -> String {
+ let place_str = construct_place_string(tcx, &place);
+
let capture_kind_str = match capture_info.capture_kind {
ty::UpvarCapture::ByValue(_) => "ByValue".into(),
ty::UpvarCapture::ByRef(borrow) => format!("{:?}", borrow.kind),
};
- format!("{}[{}] -> {}", variable_name, projections_str, capture_kind_str)
+
+ format!("{} captured as {} here", place_str, capture_kind_str)
+}
+
+fn construct_path_string(tcx: TyCtxt<'_>, place: &Place<'tcx>) -> String {
+ let place_str = construct_place_string(tcx, &place);
+
+ format!("{} used here", place_str)
+}
+
+fn construct_capture_info_string(
+ tcx: TyCtxt<'_>,
+ place: &Place<'tcx>,
+ capture_info: &ty::CaptureInfo<'tcx>,
+) -> String {
+ let place_str = construct_place_string(tcx, &place);
+
+ let capture_kind_str = match capture_info.capture_kind {
+ ty::UpvarCapture::ByValue(_) => "ByValue".into(),
+ ty::UpvarCapture::ByRef(borrow) => format!("{:?}", borrow.kind),
+ };
+ format!("{} -> {}", place_str, capture_kind_str)
}
fn var_name(tcx: TyCtxt<'_>, var_hir_id: hir::HirId) -> Symbol {
tcx.hir().name(var_hir_id)
}
+fn should_do_migration_analysis(tcx: TyCtxt<'_>, closure_id: hir::HirId) -> bool {
+ let (level, _) =
+ tcx.lint_level_at_node(lint::builtin::DISJOINT_CAPTURE_DROP_REORDER, closure_id);
+
+ !matches!(level, lint::Level::Allow)
+}
+
+fn migration_suggestion_for_2229(tcx: TyCtxt<'_>, need_migrations: &Vec<hir::HirId>) -> String {
+ let need_migrations_strings =
+ need_migrations.iter().map(|v| format!("{}", var_name(tcx, *v))).collect::<Vec<_>>();
+ let migrations_list_concat = need_migrations_strings.join(", ");
+
+ format!("drop(&({}));", migrations_list_concat)
+}
+
/// Helper function to determine if we need to escalate CaptureKind from
/// CaptureInfo A to B and returns the escalated CaptureInfo.
/// (Note: CaptureInfo contains CaptureKind and an expression that led to capture it in that way)
///
/// If both `CaptureKind`s are considered equivalent, then the CaptureInfo is selected based
-/// on the `CaptureInfo` containing an associated expression id.
+/// on the `CaptureInfo` containing an associated `capture_kind_expr_id`.
+///
+/// It is the caller's duty to figure out which path_expr_id to use.
///
/// If both the CaptureKind and Expression are considered to be equivalent,
/// then `CaptureInfo` A is preferred. This can be useful in cases where we want to priortize
@@ -971,7 +1331,7 @@
};
if eq_capture_kind {
- match (capture_info_a.expr_id, capture_info_b.expr_id) {
+ match (capture_info_a.capture_kind_expr_id, capture_info_b.capture_kind_expr_id) {
(Some(_), _) | (None, None) => capture_info_a,
(None, Some(_)) => capture_info_b,
}
diff --git a/compiler/rustc_typeck/src/check/wfcheck.rs b/compiler/rustc_typeck/src/check/wfcheck.rs
index c09f8cc..c90db47 100644
--- a/compiler/rustc_typeck/src/check/wfcheck.rs
+++ b/compiler/rustc_typeck/src/check/wfcheck.rs
@@ -51,7 +51,7 @@
let fcx = FnCtxt::new(&inh, param_env, id);
if !inh.tcx.features().trivial_bounds {
// As predicates are cached rather than obligations, this
- // needsto be called first so that they are checked with an
+ // needs to be called first so that they are checked with an
// empty `param_env`.
check_false_global_bounds(&fcx, span, id);
}
@@ -103,35 +103,28 @@
//
// won't be allowed unless there's an *explicit* implementation of `Send`
// for `T`
- hir::ItemKind::Impl {
- defaultness,
- defaultness_span,
- polarity,
- ref of_trait,
- ref self_ty,
- ..
- } => {
+ hir::ItemKind::Impl(ref impl_) => {
let is_auto = tcx
.impl_trait_ref(tcx.hir().local_def_id(item.hir_id))
.map_or(false, |trait_ref| tcx.trait_is_auto(trait_ref.def_id));
- if let (hir::Defaultness::Default { .. }, true) = (defaultness, is_auto) {
- let sp = of_trait.as_ref().map(|t| t.path.span).unwrap_or(item.span);
+ if let (hir::Defaultness::Default { .. }, true) = (impl_.defaultness, is_auto) {
+ let sp = impl_.of_trait.as_ref().map_or(item.span, |t| t.path.span);
let mut err =
tcx.sess.struct_span_err(sp, "impls of auto traits cannot be default");
- err.span_labels(defaultness_span, "default because of this");
+ err.span_labels(impl_.defaultness_span, "default because of this");
err.span_label(sp, "auto trait");
err.emit();
}
// We match on both `ty::ImplPolarity` and `ast::ImplPolarity` just to get the `!` span.
- match (tcx.impl_polarity(def_id), polarity) {
+ match (tcx.impl_polarity(def_id), impl_.polarity) {
(ty::ImplPolarity::Positive, _) => {
- check_impl(tcx, item, self_ty, of_trait);
+ check_impl(tcx, item, impl_.self_ty, &impl_.of_trait);
}
(ty::ImplPolarity::Negative, ast::ImplPolarity::Negative(span)) => {
// FIXME(#27579): what amount of WF checking do we need for neg impls?
- if let hir::Defaultness::Default { .. } = defaultness {
+ if let hir::Defaultness::Default { .. } = impl_.defaultness {
let mut spans = vec![span];
- spans.extend(defaultness_span);
+ spans.extend(impl_.defaultness_span);
struct_span_err!(
tcx.sess,
spans,
@@ -286,14 +279,20 @@
// We currently only check wf of const params here.
hir::GenericParamKind::Lifetime { .. } | hir::GenericParamKind::Type { .. } => (),
- // Const parameters are well formed if their
- // type is structural match.
- hir::GenericParamKind::Const { ty: hir_ty } => {
+ // Const parameters are well formed if their type is structural match.
+ // FIXME(const_generics_defaults): we also need to check that the `default` is wf.
+ hir::GenericParamKind::Const { ty: hir_ty, default: _ } => {
let ty = tcx.type_of(tcx.hir().local_def_id(param.hir_id));
let err_ty_str;
let mut is_ptr = true;
- let err = if tcx.features().min_const_generics {
+ let err = if tcx.features().const_generics {
+ match ty.peel_refs().kind() {
+ ty::FnPtr(_) => Some("function pointers"),
+ ty::RawPtr(_) => Some("raw pointers"),
+ _ => None,
+ }
+ } else {
match ty.kind() {
ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Error(_) => None,
ty::FnPtr(_) => Some("function pointers"),
@@ -304,12 +303,6 @@
Some(err_ty_str.as_str())
}
}
- } else {
- match ty.peel_refs().kind() {
- ty::FnPtr(_) => Some("function pointers"),
- ty::RawPtr(_) => Some("raw pointers"),
- _ => None,
- }
};
if let Some(unsupported_type) = err {
if is_ptr {
@@ -330,7 +323,7 @@
),
)
.note("the only supported types are integers, `bool` and `char`")
- .help("more complex types are supported with `#[feature(const_generics)]`")
+ .help("more complex types are supported with `#![feature(const_generics)]`")
.emit()
}
};
@@ -539,7 +532,7 @@
fcx.register_predicate(traits::Obligation::new(
cause,
fcx.param_env,
- ty::PredicateAtom::ConstEvaluatable(
+ ty::PredicateKind::ConstEvaluatable(
ty::WithOptConstParam::unknown(discr_def_id.to_def_id()),
discr_substs,
)
@@ -785,7 +778,7 @@
}
GenericParamDefKind::Const => {
- // FIXME(const_generics:defaults)
+ // FIXME(const_generics_defaults)
fcx.tcx.mk_param_from_def(param)
}
}
diff --git a/compiler/rustc_typeck/src/check/writeback.rs b/compiler/rustc_typeck/src/check/writeback.rs
index 7c9cfe6..4d18b2c 100644
--- a/compiler/rustc_typeck/src/check/writeback.rs
+++ b/compiler/rustc_typeck/src/check/writeback.rs
@@ -348,7 +348,7 @@
let min_list_wb = min_list
.iter()
.map(|captured_place| {
- let locatable = captured_place.info.expr_id.unwrap_or(
+ let locatable = captured_place.info.path_expr_id.unwrap_or(
self.tcx().hir().local_def_id_to_hir_id(closure_def_id.expect_local()),
);
@@ -384,9 +384,11 @@
assert_eq!(fcx_typeck_results.hir_owner, self.typeck_results.hir_owner);
let common_hir_owner = fcx_typeck_results.hir_owner;
- for (&id, &origin) in fcx_typeck_results.closure_kind_origins().iter() {
- let hir_id = hir::HirId { owner: common_hir_owner, local_id: id };
- self.typeck_results.closure_kind_origins_mut().insert(hir_id, origin);
+ for (id, origin) in fcx_typeck_results.closure_kind_origins().iter() {
+ let hir_id = hir::HirId { owner: common_hir_owner, local_id: *id };
+ let place_span = origin.0;
+ let place = self.resolve(origin.1.clone(), &place_span);
+ self.typeck_results.closure_kind_origins_mut().insert(hir_id, (place_span, place));
}
}
@@ -648,7 +650,7 @@
}
}
-trait Locatable {
+crate trait Locatable {
fn to_span(&self, tcx: TyCtxt<'_>) -> Span;
}
@@ -666,7 +668,7 @@
/// The Resolver. This is the type folding engine that detects
/// unresolved types and so forth.
-struct Resolver<'cx, 'tcx> {
+crate struct Resolver<'cx, 'tcx> {
tcx: TyCtxt<'tcx>,
infcx: &'cx InferCtxt<'cx, 'tcx>,
span: &'cx dyn Locatable,
@@ -677,7 +679,7 @@
}
impl<'cx, 'tcx> Resolver<'cx, 'tcx> {
- fn new(
+ crate fn new(
fcx: &'cx FnCtxt<'cx, 'tcx>,
span: &'cx dyn Locatable,
body: &'tcx hir::Body<'tcx>,
@@ -692,6 +694,7 @@
Some(self.body.id()),
self.span.to_span(self.tcx),
t.into(),
+ vec![],
E0282,
)
.emit();
@@ -705,6 +708,7 @@
Some(self.body.id()),
self.span.to_span(self.tcx),
c.into(),
+ vec![],
E0282,
)
.emit();
diff --git a/compiler/rustc_typeck/src/coherence/builtin.rs b/compiler/rustc_typeck/src/coherence/builtin.rs
index 89270fb..6726b9b 100644
--- a/compiler/rustc_typeck/src/coherence/builtin.rs
+++ b/compiler/rustc_typeck/src/coherence/builtin.rs
@@ -55,7 +55,7 @@
let impl_hir_id = tcx.hir().local_def_id_to_hir_id(impl_did);
let sp = match tcx.hir().expect_item(impl_hir_id).kind {
- ItemKind::Impl { self_ty, .. } => self_ty.span,
+ ItemKind::Impl(ref impl_) => impl_.self_ty.span,
_ => bug!("expected Drop impl item"),
};
@@ -80,7 +80,7 @@
Ok(()) => {}
Err(CopyImplementationError::InfrigingFields(fields)) => {
let item = tcx.hir().expect_item(impl_hir_id);
- let span = if let ItemKind::Impl { of_trait: Some(ref tr), .. } = item.kind {
+ let span = if let ItemKind::Impl(hir::Impl { of_trait: Some(ref tr), .. }) = item.kind {
tr.path.span
} else {
span
@@ -100,7 +100,7 @@
Err(CopyImplementationError::NotAnAdt) => {
let item = tcx.hir().expect_item(impl_hir_id);
let span =
- if let ItemKind::Impl { self_ty, .. } = item.kind { self_ty.span } else { span };
+ if let ItemKind::Impl(ref impl_) = item.kind { impl_.self_ty.span } else { span };
tcx.sess.emit_err(CopyImplOnNonAdt { span });
}
@@ -453,7 +453,9 @@
return err_info;
} else if diff_fields.len() > 1 {
let item = tcx.hir().expect_item(impl_hir_id);
- let span = if let ItemKind::Impl { of_trait: Some(ref t), .. } = item.kind {
+ let span = if let ItemKind::Impl(hir::Impl { of_trait: Some(ref t), .. }) =
+ item.kind
+ {
t.path.span
} else {
tcx.hir().span(impl_hir_id)
diff --git a/compiler/rustc_typeck/src/coherence/inherent_impls.rs b/compiler/rustc_typeck/src/coherence/inherent_impls.rs
index 0c15784..8a50085 100644
--- a/compiler/rustc_typeck/src/coherence/inherent_impls.rs
+++ b/compiler/rustc_typeck/src/coherence/inherent_impls.rs
@@ -13,7 +13,6 @@
use rustc_hir::itemlikevisit::ItemLikeVisitor;
use rustc_middle::ty::{self, CrateInherentImpls, TyCtxt};
-use rustc_ast as ast;
use rustc_span::Span;
/// On-demand query: yields a map containing all types mapped to their inherent impls.
@@ -45,7 +44,9 @@
impl ItemLikeVisitor<'v> for InherentCollect<'tcx> {
fn visit_item(&mut self, item: &hir::Item<'_>) {
let (ty, assoc_items) = match item.kind {
- hir::ItemKind::Impl { of_trait: None, ref self_ty, items, .. } => (self_ty, items),
+ hir::ItemKind::Impl(hir::Impl { of_trait: None, ref self_ty, items, .. }) => {
+ (self_ty, items)
+ }
_ => return,
};
@@ -176,7 +177,7 @@
assoc_items,
);
}
- ty::Int(ast::IntTy::I8) => {
+ ty::Int(ty::IntTy::I8) => {
self.check_primitive_impl(
def_id,
lang_items.i8_impl(),
@@ -187,7 +188,7 @@
assoc_items,
);
}
- ty::Int(ast::IntTy::I16) => {
+ ty::Int(ty::IntTy::I16) => {
self.check_primitive_impl(
def_id,
lang_items.i16_impl(),
@@ -198,7 +199,7 @@
assoc_items,
);
}
- ty::Int(ast::IntTy::I32) => {
+ ty::Int(ty::IntTy::I32) => {
self.check_primitive_impl(
def_id,
lang_items.i32_impl(),
@@ -209,7 +210,7 @@
assoc_items,
);
}
- ty::Int(ast::IntTy::I64) => {
+ ty::Int(ty::IntTy::I64) => {
self.check_primitive_impl(
def_id,
lang_items.i64_impl(),
@@ -220,7 +221,7 @@
assoc_items,
);
}
- ty::Int(ast::IntTy::I128) => {
+ ty::Int(ty::IntTy::I128) => {
self.check_primitive_impl(
def_id,
lang_items.i128_impl(),
@@ -231,7 +232,7 @@
assoc_items,
);
}
- ty::Int(ast::IntTy::Isize) => {
+ ty::Int(ty::IntTy::Isize) => {
self.check_primitive_impl(
def_id,
lang_items.isize_impl(),
@@ -242,7 +243,7 @@
assoc_items,
);
}
- ty::Uint(ast::UintTy::U8) => {
+ ty::Uint(ty::UintTy::U8) => {
self.check_primitive_impl(
def_id,
lang_items.u8_impl(),
@@ -253,7 +254,7 @@
assoc_items,
);
}
- ty::Uint(ast::UintTy::U16) => {
+ ty::Uint(ty::UintTy::U16) => {
self.check_primitive_impl(
def_id,
lang_items.u16_impl(),
@@ -264,7 +265,7 @@
assoc_items,
);
}
- ty::Uint(ast::UintTy::U32) => {
+ ty::Uint(ty::UintTy::U32) => {
self.check_primitive_impl(
def_id,
lang_items.u32_impl(),
@@ -275,7 +276,7 @@
assoc_items,
);
}
- ty::Uint(ast::UintTy::U64) => {
+ ty::Uint(ty::UintTy::U64) => {
self.check_primitive_impl(
def_id,
lang_items.u64_impl(),
@@ -286,7 +287,7 @@
assoc_items,
);
}
- ty::Uint(ast::UintTy::U128) => {
+ ty::Uint(ty::UintTy::U128) => {
self.check_primitive_impl(
def_id,
lang_items.u128_impl(),
@@ -297,7 +298,7 @@
assoc_items,
);
}
- ty::Uint(ast::UintTy::Usize) => {
+ ty::Uint(ty::UintTy::Usize) => {
self.check_primitive_impl(
def_id,
lang_items.usize_impl(),
@@ -308,7 +309,7 @@
assoc_items,
);
}
- ty::Float(ast::FloatTy::F32) => {
+ ty::Float(ty::FloatTy::F32) => {
self.check_primitive_impl(
def_id,
lang_items.f32_impl(),
@@ -319,7 +320,7 @@
assoc_items,
);
}
- ty::Float(ast::FloatTy::F64) => {
+ ty::Float(ty::FloatTy::F64) => {
self.check_primitive_impl(
def_id,
lang_items.f64_impl(),
diff --git a/compiler/rustc_typeck/src/coherence/orphan.rs b/compiler/rustc_typeck/src/coherence/orphan.rs
index 253dcf0..9333aac 100644
--- a/compiler/rustc_typeck/src/coherence/orphan.rs
+++ b/compiler/rustc_typeck/src/coherence/orphan.rs
@@ -26,7 +26,10 @@
fn visit_item(&mut self, item: &hir::Item<'_>) {
let def_id = self.tcx.hir().local_def_id(item.hir_id);
// "Trait" impl
- if let hir::ItemKind::Impl { generics, of_trait: Some(ref tr), self_ty, .. } = &item.kind {
+ if let hir::ItemKind::Impl(hir::Impl {
+ generics, of_trait: Some(ref tr), self_ty, ..
+ }) = &item.kind
+ {
debug!(
"coherence2::orphan check: trait impl {}",
self.tcx.hir().node_to_string(item.hir_id)
diff --git a/compiler/rustc_typeck/src/coherence/unsafety.rs b/compiler/rustc_typeck/src/coherence/unsafety.rs
index 2d9128e..3a290b7 100644
--- a/compiler/rustc_typeck/src/coherence/unsafety.rs
+++ b/compiler/rustc_typeck/src/coherence/unsafety.rs
@@ -86,8 +86,13 @@
impl ItemLikeVisitor<'v> for UnsafetyChecker<'tcx> {
fn visit_item(&mut self, item: &'v hir::Item<'v>) {
- if let hir::ItemKind::Impl { unsafety, polarity, ref generics, .. } = item.kind {
- self.check_unsafety_coherence(item, Some(generics), unsafety, polarity);
+ if let hir::ItemKind::Impl(ref impl_) = item.kind {
+ self.check_unsafety_coherence(
+ item,
+ Some(&impl_.generics),
+ impl_.unsafety,
+ impl_.polarity,
+ );
}
}
diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs
index bc6b203..c6cc54d 100644
--- a/compiler/rustc_typeck/src/collect.rs
+++ b/compiler/rustc_typeck/src/collect.rs
@@ -50,8 +50,6 @@
use rustc_target::spec::abi;
use rustc_trait_selection::traits::error_reporting::suggestions::NextTypeParamName;
-use std::ops::ControlFlow;
-
mod item_bounds;
mod type_of;
@@ -156,10 +154,10 @@
if let Some(span) = span {
sugg.push((span, format!("<{}>", type_name)));
}
- } else if let Some(arg) = generics.iter().find(|arg| match arg.name {
- hir::ParamName::Plain(Ident { name: kw::Underscore, .. }) => true,
- _ => false,
- }) {
+ } else if let Some(arg) = generics
+ .iter()
+ .find(|arg| matches!(arg.name, hir::ParamName::Plain(Ident { name: kw::Underscore, .. })))
+ {
// Account for `_` already present in cases like `struct S<_>(_);` and suggest
// `struct S<T>(T);` instead of `struct S<_, T>(T);`.
sugg.push((arg.span, (*type_name).to_string()));
@@ -189,7 +187,7 @@
| hir::ItemKind::Enum(_, generics)
| hir::ItemKind::TraitAlias(generics, _)
| hir::ItemKind::Trait(_, _, generics, ..)
- | hir::ItemKind::Impl { generics, .. }
+ | hir::ItemKind::Impl(hir::Impl { generics, .. })
| hir::ItemKind::Struct(_, generics) => (generics, true),
hir::ItemKind::OpaqueTy(hir::OpaqueTy { generics, .. })
| hir::ItemKind::TyAlias(_, generics) => (generics, false),
@@ -228,7 +226,7 @@
hir::GenericParamKind::Const { .. } => {
let def_id = self.tcx.hir().local_def_id(param.hir_id);
self.tcx.ensure().type_of(def_id);
- // FIXME(const_generics:defaults)
+ // FIXME(const_generics_defaults)
}
}
}
@@ -333,6 +331,11 @@
span: Span,
) -> &'tcx Const<'tcx> {
bad_placeholder_type(self.tcx(), vec![span]).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,
+ _ => r,
+ });
self.tcx().const_error(ty)
}
@@ -531,7 +534,7 @@
Node::Item(item) => {
match item.kind {
ItemKind::Fn(.., ref generics, _)
- | ItemKind::Impl { ref generics, .. }
+ | ItemKind::Impl(hir::Impl { ref generics, .. })
| ItemKind::TyAlias(_, ref generics)
| ItemKind::OpaqueTy(OpaqueTy { ref generics, impl_trait_fn: None, .. })
| ItemKind::Enum(_, ref generics)
@@ -562,8 +565,8 @@
let extra_predicates = extend.into_iter().chain(
icx.type_parameter_bounds_in_generics(ast_generics, param_id, ty, OnlySelfBounds(true))
.into_iter()
- .filter(|(predicate, _)| match predicate.skip_binders() {
- ty::PredicateAtom::Trait(data, _) => data.self_ty().is_param(index),
+ .filter(|(predicate, _)| match predicate.kind().skip_binder() {
+ ty::PredicateKind::Trait(data, _) => data.self_ty().is_param(index),
_ => false,
}),
);
@@ -1027,7 +1030,7 @@
// which will, in turn, reach indirect supertraits.
for &(pred, span) in superbounds {
debug!("superbound: {:?}", pred);
- if let ty::PredicateAtom::Trait(bound, _) = pred.skip_binders() {
+ if let ty::PredicateKind::Trait(bound, _) = pred.kind().skip_binder() {
tcx.at(span).super_predicates_of(bound.def_id());
}
}
@@ -1260,7 +1263,7 @@
// used with const generics, e.g. `Foo<{N+1}>`, can work at all.
//
// Note that we do not supply the parent generics when using
- // `feature(min_const_generics)`.
+ // `min_const_generics`.
Some(parent_def_id.to_def_id())
} else {
let parent_node = tcx.hir().get(tcx.hir().get_parent_node(hir_id));
@@ -1310,7 +1313,8 @@
Node::Item(item) => {
match item.kind {
- ItemKind::Fn(.., ref generics, _) | ItemKind::Impl { ref generics, .. } => generics,
+ ItemKind::Fn(.., ref generics, _)
+ | ItemKind::Impl(hir::Impl { ref generics, .. }) => generics,
ItemKind::TyAlias(_, ref generics)
| ItemKind::Enum(_, ref generics)
@@ -1497,13 +1501,11 @@
Ptr(mut_ty) | Rptr(_, mut_ty) => is_suggestable_infer_ty(mut_ty.ty),
OpaqueDef(_, generic_args) => are_suggestable_generic_args(generic_args),
Path(hir::QPath::TypeRelative(ty, segment)) => {
- is_suggestable_infer_ty(ty) || are_suggestable_generic_args(segment.generic_args().args)
+ is_suggestable_infer_ty(ty) || are_suggestable_generic_args(segment.args().args)
}
Path(hir::QPath::Resolved(ty_opt, hir::Path { segments, .. })) => {
ty_opt.map_or(false, is_suggestable_infer_ty)
- || segments
- .iter()
- .any(|segment| are_suggestable_generic_args(segment.generic_args().args))
+ || segments.iter().any(|segment| are_suggestable_generic_args(segment.args().args))
}
_ => false,
}
@@ -1539,19 +1541,41 @@
match get_infer_ret_ty(&sig.decl.output) {
Some(ty) => {
let fn_sig = tcx.typeck(def_id).liberated_fn_sigs()[hir_id];
+ // Typeck doesn't expect erased regions to be returned from `type_of`.
+ let fn_sig = tcx.fold_regions(fn_sig, &mut false, |r, _| match r {
+ ty::ReErased => tcx.lifetimes.re_static,
+ _ => r,
+ });
+
let mut visitor = PlaceholderHirTyCollector::default();
visitor.visit_ty(ty);
let mut diag = bad_placeholder_type(tcx, visitor.0);
let ret_ty = fn_sig.output();
if ret_ty != tcx.ty_error() {
- diag.span_suggestion(
- ty.span,
- "replace with the correct return type",
- ret_ty.to_string(),
- Applicability::MaybeIncorrect,
- );
+ if !ret_ty.is_closure() {
+ let ret_ty_str = match ret_ty.kind() {
+ // Suggest a function pointer return type instead of a unique function definition
+ // (e.g. `fn() -> i32` instead of `fn() -> i32 { f }`, the latter of which is invalid
+ // syntax)
+ ty::FnDef(..) => ret_ty.fn_sig(tcx).to_string(),
+ _ => ret_ty.to_string(),
+ };
+ diag.span_suggestion(
+ ty.span,
+ "replace with the correct return type",
+ ret_ty_str,
+ Applicability::MaybeIncorrect,
+ );
+ } else {
+ // We're dealing with a closure, so we should suggest using `impl Fn` or trait bounds
+ // to prevent the user from getting a papercut while trying to use the unique closure
+ // syntax (e.g. `[closure@src/lib.rs:2:5: 2:9]`).
+ diag.help("consider using an `Fn`, `FnMut`, or `FnOnce` trait bound");
+ diag.note("for more information on `Fn` traits and closure types, see https://doc.rust-lang.org/book/ch13-01-closures.html");
+ }
}
diag.emit();
+
ty::Binder::bind(fn_sig)
}
None => AstConv::ty_of_fn(
@@ -1623,7 +1647,7 @@
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
match tcx.hir().expect_item(hir_id).kind {
- hir::ItemKind::Impl { ref of_trait, .. } => of_trait.as_ref().map(|ast_trait_ref| {
+ hir::ItemKind::Impl(ref impl_) => impl_.of_trait.as_ref().map(|ast_trait_ref| {
let selfty = tcx.type_of(def_id);
AstConv::instantiate_mono_trait_ref(&icx, ast_trait_ref, selfty)
}),
@@ -1636,29 +1660,39 @@
let is_rustc_reservation = tcx.has_attr(def_id, sym::rustc_reservation_impl);
let item = tcx.hir().expect_item(hir_id);
match &item.kind {
- hir::ItemKind::Impl { polarity: hir::ImplPolarity::Negative(span), of_trait, .. } => {
+ hir::ItemKind::Impl(hir::Impl {
+ polarity: hir::ImplPolarity::Negative(span),
+ of_trait,
+ ..
+ }) => {
if is_rustc_reservation {
- let span = span.to(of_trait.as_ref().map(|t| t.path.span).unwrap_or(*span));
+ let span = span.to(of_trait.as_ref().map_or(*span, |t| t.path.span));
tcx.sess.span_err(span, "reservation impls can't be negative");
}
ty::ImplPolarity::Negative
}
- hir::ItemKind::Impl { polarity: hir::ImplPolarity::Positive, of_trait: None, .. } => {
+ hir::ItemKind::Impl(hir::Impl {
+ polarity: hir::ImplPolarity::Positive,
+ of_trait: None,
+ ..
+ }) => {
if is_rustc_reservation {
tcx.sess.span_err(item.span, "reservation impls can't be inherent");
}
ty::ImplPolarity::Positive
}
- hir::ItemKind::Impl {
- polarity: hir::ImplPolarity::Positive, of_trait: Some(_), ..
- } => {
+ hir::ItemKind::Impl(hir::Impl {
+ polarity: hir::ImplPolarity::Positive,
+ of_trait: Some(_),
+ ..
+ }) => {
if is_rustc_reservation {
ty::ImplPolarity::Reservation
} else {
ty::ImplPolarity::Positive
}
}
- ref item => bug!("impl_polarity: {:?} not an impl", item),
+ item => bug!("impl_polarity: {:?} not an impl", item),
}
}
@@ -1752,8 +1786,7 @@
const NO_GENERICS: &hir::Generics<'_> = &hir::Generics::empty();
// We use an `IndexSet` to preserves order of insertion.
- // Preserving the order of insertion is important here so as not to break
- // compile-fail UI tests.
+ // Preserving the order of insertion is important here so as not to break UI tests.
let mut predicates: FxIndexSet<(ty::Predicate<'_>, Span)> = FxIndexSet::default();
let ast_generics = match node {
@@ -1763,11 +1796,11 @@
Node::Item(item) => {
match item.kind {
- ItemKind::Impl { defaultness, ref generics, .. } => {
- if defaultness.is_default() {
+ ItemKind::Impl(ref impl_) => {
+ if impl_.defaultness.is_default() {
is_default_impl_trait = tcx.impl_trait_ref(def_id);
}
- generics
+ &impl_.generics
}
ItemKind::Fn(.., ref generics, _)
| ItemKind::TyAlias(_, ref generics)
@@ -1906,7 +1939,7 @@
let where_clause = &ast_generics.where_clause;
for predicate in where_clause.predicates {
match predicate {
- &hir::WherePredicate::BoundPredicate(ref bound_pred) => {
+ hir::WherePredicate::BoundPredicate(bound_pred) => {
let ty = icx.to_ty(&bound_pred.bounded_ty);
// Keep the type around in a dummy predicate, in case of no bounds.
@@ -1923,19 +1956,16 @@
} else {
let span = bound_pred.bounded_ty.span;
let re_root_empty = tcx.lifetimes.re_root_empty;
- let predicate = ty::Binder::bind(ty::PredicateAtom::TypeOutlives(
+ let predicate = ty::Binder::bind(ty::PredicateKind::TypeOutlives(
ty::OutlivesPredicate(ty, re_root_empty),
));
- predicates.insert((
- predicate.potentially_quantified(tcx, ty::PredicateKind::ForAll),
- span,
- ));
+ predicates.insert((predicate.to_predicate(tcx), span));
}
}
for bound in bound_pred.bounds.iter() {
match bound {
- &hir::GenericBound::Trait(ref poly_trait_ref, modifier) => {
+ hir::GenericBound::Trait(poly_trait_ref, modifier) => {
let constness = match modifier {
hir::TraitBoundModifier::MaybeConst => hir::Constness::NotConst,
hir::TraitBoundModifier::None => constness,
@@ -1945,7 +1975,7 @@
let mut bounds = Bounds::default();
let _ = AstConv::instantiate_poly_trait_ref(
&icx,
- poly_trait_ref,
+ &poly_trait_ref,
constness,
ty,
&mut bounds,
@@ -1967,13 +1997,13 @@
predicates.extend(bounds.predicates(tcx, ty));
}
- &hir::GenericBound::Outlives(ref lifetime) => {
+ hir::GenericBound::Outlives(lifetime) => {
let region = AstConv::ast_region_to_region(&icx, lifetime, None);
predicates.insert((
- ty::Binder::bind(ty::PredicateAtom::TypeOutlives(
+ ty::Binder::bind(ty::PredicateKind::TypeOutlives(
ty::OutlivesPredicate(ty, region),
))
- .potentially_quantified(tcx, ty::PredicateKind::ForAll),
+ .to_predicate(tcx),
lifetime.span,
));
}
@@ -1981,7 +2011,7 @@
}
}
- &hir::WherePredicate::RegionPredicate(ref region_pred) => {
+ hir::WherePredicate::RegionPredicate(region_pred) => {
let r1 = AstConv::ast_region_to_region(&icx, ®ion_pred.lifetime, None);
predicates.extend(region_pred.bounds.iter().map(|bound| {
let (r2, span) = match bound {
@@ -1990,14 +2020,14 @@
}
_ => bug!(),
};
- let pred = ty::PredicateAtom::RegionOutlives(ty::OutlivesPredicate(r1, r2))
+ let pred = ty::PredicateKind::RegionOutlives(ty::OutlivesPredicate(r1, r2))
.to_predicate(icx.tcx);
(pred, span)
}))
}
- &hir::WherePredicate::EqPredicate(..) => {
+ hir::WherePredicate::EqPredicate(..) => {
// FIXME(#20041)
}
}
@@ -2055,43 +2085,11 @@
if let ty::ConstKind::Unevaluated(def, substs, None) = ct.val {
let span = self.tcx.hir().span(c.hir_id);
self.preds.insert((
- ty::PredicateAtom::ConstEvaluatable(def, substs).to_predicate(self.tcx),
+ ty::PredicateKind::ConstEvaluatable(def, substs).to_predicate(self.tcx),
span,
));
}
}
-
- // Look into `TyAlias`.
- fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) {
- use ty::fold::{TypeFoldable, TypeVisitor};
- struct TyAliasVisitor<'a, 'tcx> {
- tcx: TyCtxt<'tcx>,
- preds: &'a mut FxIndexSet<(ty::Predicate<'tcx>, Span)>,
- span: Span,
- }
-
- impl<'a, 'tcx> TypeVisitor<'tcx> for TyAliasVisitor<'a, 'tcx> {
- fn visit_const(&mut self, ct: &'tcx Const<'tcx>) -> ControlFlow<Self::BreakTy> {
- if let ty::ConstKind::Unevaluated(def, substs, None) = ct.val {
- self.preds.insert((
- ty::PredicateAtom::ConstEvaluatable(def, substs).to_predicate(self.tcx),
- self.span,
- ));
- }
- ControlFlow::CONTINUE
- }
- }
-
- if let hir::TyKind::Path(hir::QPath::Resolved(None, path)) = ty.kind {
- if let Res::Def(DefKind::TyAlias, def_id) = path.res {
- let mut visitor =
- TyAliasVisitor { tcx: self.tcx, preds: &mut self.preds, span: path.span };
- self.tcx.type_of(def_id).visit_with(&mut visitor);
- }
- }
-
- intravisit::walk_ty(self, ty)
- }
}
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
@@ -2099,14 +2097,14 @@
let mut collector = ConstCollector { tcx, preds: FxIndexSet::default() };
if let hir::Node::Item(item) = node {
- if let hir::ItemKind::Impl { ref of_trait, ref self_ty, .. } = item.kind {
- if let Some(of_trait) = of_trait {
+ if let hir::ItemKind::Impl(ref impl_) = item.kind {
+ if let Some(of_trait) = &impl_.of_trait {
debug!("const_evaluatable_predicates_of({:?}): visit impl trait_ref", def_id);
collector.visit_trait_ref(of_trait);
}
debug!("const_evaluatable_predicates_of({:?}): visit_self_ty", def_id);
- collector.visit_ty(self_ty);
+ collector.visit_ty(impl_.self_ty);
}
}
@@ -2160,12 +2158,12 @@
.predicates
.iter()
.copied()
- .filter(|(pred, _)| match pred.skip_binders() {
- ty::PredicateAtom::Trait(tr, _) => !is_assoc_item_ty(tr.self_ty()),
- ty::PredicateAtom::Projection(proj) => {
+ .filter(|(pred, _)| match pred.kind().skip_binder() {
+ ty::PredicateKind::Trait(tr, _) => !is_assoc_item_ty(tr.self_ty()),
+ ty::PredicateKind::Projection(proj) => {
!is_assoc_item_ty(proj.projection_ty.self_ty())
}
- ty::PredicateAtom::TypeOutlives(outlives) => !is_assoc_item_ty(outlives.0),
+ ty::PredicateKind::TypeOutlives(outlives) => !is_assoc_item_ty(outlives.0),
_ => true,
})
.collect();
@@ -2194,7 +2192,8 @@
let (ty_def_id, item_def_id) = key;
let mut projection_ty = None;
for (predicate, _) in tcx.predicates_of(ty_def_id).predicates {
- if let ty::PredicateAtom::Projection(projection_predicate) = predicate.skip_binders() {
+ if let ty::PredicateKind::Projection(projection_predicate) = predicate.kind().skip_binder()
+ {
if item_def_id == projection_predicate.projection_ty.item_def_id {
projection_ty = Some(projection_predicate.projection_ty);
break;
@@ -2241,7 +2240,7 @@
}
hir::GenericBound::Outlives(ref lifetime) => {
let region = astconv.ast_region_to_region(lifetime, None);
- let pred = ty::PredicateAtom::TypeOutlives(ty::OutlivesPredicate(param_ty, region))
+ let pred = ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(param_ty, region))
.to_predicate(astconv.tcx());
vec![(pred, lifetime.span)]
}
@@ -2938,7 +2937,7 @@
if let Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Fn(..), .. }) = node {
let parent_id = tcx.hir().get_parent_item(hir_id);
let parent_item = tcx.hir().expect_item(parent_id);
- if let hir::ItemKind::Impl { of_trait: Some(_), .. } = parent_item.kind {
+ if let hir::ItemKind::Impl(hir::Impl { of_trait: Some(_), .. }) = parent_item.kind {
tcx.sess
.struct_span_err(
attr_span,
diff --git a/compiler/rustc_typeck/src/collect/item_bounds.rs b/compiler/rustc_typeck/src/collect/item_bounds.rs
index e596dd1..537a583 100644
--- a/compiler/rustc_typeck/src/collect/item_bounds.rs
+++ b/compiler/rustc_typeck/src/collect/item_bounds.rs
@@ -36,13 +36,14 @@
let trait_def_id = tcx.associated_item(assoc_item_def_id).container.id();
let trait_predicates = tcx.trait_explicit_predicates_and_bounds(trait_def_id.expect_local());
- let bounds_from_parent =
- trait_predicates.predicates.iter().copied().filter(|(pred, _)| match pred.skip_binders() {
- ty::PredicateAtom::Trait(tr, _) => tr.self_ty() == item_ty,
- ty::PredicateAtom::Projection(proj) => proj.projection_ty.self_ty() == item_ty,
- ty::PredicateAtom::TypeOutlives(outlives) => outlives.0 == item_ty,
+ let bounds_from_parent = trait_predicates.predicates.iter().copied().filter(|(pred, _)| {
+ match pred.kind().skip_binder() {
+ ty::PredicateKind::Trait(tr, _) => tr.self_ty() == item_ty,
+ ty::PredicateKind::Projection(proj) => proj.projection_ty.self_ty() == item_ty,
+ ty::PredicateKind::TypeOutlives(outlives) => outlives.0 == item_ty,
_ => false,
- });
+ }
+ });
let all_bounds = tcx
.arena
diff --git a/compiler/rustc_typeck/src/collect/type_of.rs b/compiler/rustc_typeck/src/collect/type_of.rs
index 88ba578..e4eabca 100644
--- a/compiler/rustc_typeck/src/collect/type_of.rs
+++ b/compiler/rustc_typeck/src/collect/type_of.rs
@@ -6,7 +6,7 @@
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::intravisit;
use rustc_hir::intravisit::Visitor;
-use rustc_hir::Node;
+use rustc_hir::{HirId, Node};
use rustc_middle::hir::map::Map;
use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts};
use rustc_middle::ty::util::IntTypeExt;
@@ -22,7 +22,6 @@
/// This should be called using the query `tcx.opt_const_param_of`.
pub(super) fn opt_const_param_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<DefId> {
use hir::*;
-
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
if let Node::AnonConst(_) = tcx.hir().get(hir_id) {
@@ -62,9 +61,9 @@
}
Node::Ty(&Ty { kind: TyKind::Path(_), .. })
- | Node::Expr(&Expr { kind: ExprKind::Struct(..), .. })
- | Node::Expr(&Expr { kind: ExprKind::Path(_), .. })
- | Node::TraitRef(..) => {
+ | Node::Expr(&Expr { kind: ExprKind::Path(_) | ExprKind::Struct(..), .. })
+ | Node::TraitRef(..)
+ | Node::Pat(_) => {
let path = match parent_node {
Node::Ty(&Ty { kind: TyKind::Path(QPath::Resolved(_, path)), .. })
| Node::TraitRef(&TraitRef { path, .. }) => &*path,
@@ -79,6 +78,20 @@
let _tables = tcx.typeck(body_owner);
&*path
}
+ Node::Pat(pat) => {
+ if let Some(path) = get_path_containing_arg_in_pat(pat, hir_id) {
+ path
+ } else {
+ tcx.sess.delay_span_bug(
+ tcx.def_span(def_id),
+ &format!(
+ "unable to find const parent for {} in pat {:?}",
+ hir_id, pat
+ ),
+ );
+ return None;
+ }
+ }
_ => {
tcx.sess.delay_span_bug(
tcx.def_span(def_id),
@@ -91,7 +104,6 @@
// We've encountered an `AnonConst` in some path, so we need to
// figure out which generic parameter it corresponds to and return
// the relevant type.
-
let (arg_index, segment) = path
.segments
.iter()
@@ -144,6 +156,34 @@
}
}
+fn get_path_containing_arg_in_pat<'hir>(
+ pat: &'hir hir::Pat<'hir>,
+ arg_id: HirId,
+) -> Option<&'hir hir::Path<'hir>> {
+ use hir::*;
+
+ let is_arg_in_path = |p: &hir::Path<'_>| {
+ p.segments
+ .iter()
+ .filter_map(|seg| seg.args)
+ .flat_map(|args| args.args)
+ .any(|arg| arg.id() == arg_id)
+ };
+ let mut arg_path = None;
+ pat.walk(|pat| match pat.kind {
+ PatKind::Struct(QPath::Resolved(_, path), _, _)
+ | PatKind::TupleStruct(QPath::Resolved(_, path), _, _)
+ | PatKind::Path(QPath::Resolved(_, path))
+ if is_arg_in_path(path) =>
+ {
+ arg_path = Some(path);
+ false
+ }
+ _ => true,
+ });
+ arg_path
+}
+
pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
let def_id = def_id.expect_local();
use rustc_hir::*;
@@ -203,9 +243,8 @@
icx.to_ty(ty)
}
}
- ItemKind::TyAlias(ref self_ty, _) | ItemKind::Impl { ref self_ty, .. } => {
- icx.to_ty(self_ty)
- }
+ ItemKind::TyAlias(ref self_ty, _)
+ | ItemKind::Impl(hir::Impl { ref self_ty, .. }) => icx.to_ty(self_ty),
ItemKind::Fn(..) => {
let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id());
tcx.mk_fn_def(def_id.to_def_id(), substs)
diff --git a/compiler/rustc_typeck/src/constrained_generic_params.rs b/compiler/rustc_typeck/src/constrained_generic_params.rs
index e389fd4..95670b9 100644
--- a/compiler/rustc_typeck/src/constrained_generic_params.rs
+++ b/compiler/rustc_typeck/src/constrained_generic_params.rs
@@ -183,7 +183,8 @@
for j in i..predicates.len() {
// Note that we don't have to care about binders here,
// as the impl trait ref never contains any late-bound regions.
- if let ty::PredicateAtom::Projection(projection) = predicates[j].0.skip_binders() {
+ if let ty::PredicateKind::Projection(projection) = predicates[j].0.kind().skip_binder()
+ {
// Special case: watch out for some kind of sneaky attempt
// to project out an associated type defined by this very
// trait.
diff --git a/compiler/rustc_typeck/src/expr_use_visitor.rs b/compiler/rustc_typeck/src/expr_use_visitor.rs
index ce9fd55..bd2c266 100644
--- a/compiler/rustc_typeck/src/expr_use_visitor.rs
+++ b/compiler/rustc_typeck/src/expr_use_visitor.rs
@@ -219,6 +219,14 @@
self.consume_exprs(exprs);
}
+ hir::ExprKind::If(ref cond_expr, ref then_expr, ref opt_else_expr) => {
+ self.consume_expr(&cond_expr);
+ self.consume_expr(&then_expr);
+ if let Some(ref else_expr) = *opt_else_expr {
+ self.consume_expr(&else_expr);
+ }
+ }
+
hir::ExprKind::Match(ref discr, arms, _) => {
let discr_place = return_if_err!(self.mc.cat_expr(&discr));
self.borrow_expr(&discr, ty::ImmBorrow);
@@ -281,7 +289,7 @@
| hir::ExprKind::ConstBlock(..)
| hir::ExprKind::Err => {}
- hir::ExprKind::Loop(ref blk, _, _) => {
+ hir::ExprKind::Loop(ref blk, ..) => {
self.walk_block(blk);
}
@@ -595,10 +603,10 @@
let upvars = self.tcx().upvars_mentioned(self.body_owner);
// For purposes of this function, generator and closures are equivalent.
- let body_owner_is_closure = match self.tcx().type_of(self.body_owner.to_def_id()).kind() {
- ty::Closure(..) | ty::Generator(..) => true,
- _ => false,
- };
+ let body_owner_is_closure = matches!(
+ self.tcx().type_of(self.body_owner.to_def_id()).kind(),
+ ty::Closure(..) | ty::Generator(..)
+ );
if let Some(min_captures) = self.mc.typeck_results.closure_min_captures.get(&closure_def_id)
{
@@ -622,7 +630,7 @@
PlaceBase::Local(*var_hir_id)
};
let place_with_id = PlaceWithHirId::new(
- capture_info.expr_id.unwrap_or(closure_expr.hir_id),
+ capture_info.path_expr_id.unwrap_or(closure_expr.hir_id),
place.base_ty,
place_base,
place.projections.clone(),
diff --git a/compiler/rustc_typeck/src/impl_wf_check.rs b/compiler/rustc_typeck/src/impl_wf_check.rs
index 14daa97..0bdcbaa 100644
--- a/compiler/rustc_typeck/src/impl_wf_check.rs
+++ b/compiler/rustc_typeck/src/impl_wf_check.rs
@@ -80,10 +80,10 @@
impl ItemLikeVisitor<'tcx> for ImplWfCheck<'tcx> {
fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
- if let hir::ItemKind::Impl { ref items, .. } = item.kind {
+ if let hir::ItemKind::Impl(ref impl_) = item.kind {
let impl_def_id = self.tcx.hir().local_def_id(item.hir_id);
- enforce_impl_params_are_constrained(self.tcx, impl_def_id, items);
- enforce_impl_items_are_distinct(self.tcx, items);
+ enforce_impl_params_are_constrained(self.tcx, impl_def_id, impl_.items);
+ enforce_impl_items_are_distinct(self.tcx, impl_.items);
if self.min_specialization {
check_min_specialization(self.tcx, impl_def_id.to_def_id(), item.span);
}
diff --git a/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs b/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs
index 5db9ff9..505d9a5 100644
--- a/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs
+++ b/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs
@@ -198,7 +198,7 @@
// the functions in `cgp` add the constrained parameters to a list of
// unconstrained parameters.
for (predicate, _) in impl_generic_predicates.predicates.iter() {
- if let ty::PredicateAtom::Projection(proj) = predicate.skip_binders() {
+ if let ty::PredicateKind::Projection(proj) = predicate.kind().skip_binder() {
let projection_ty = proj.projection_ty;
let projected_ty = proj.ty;
@@ -360,13 +360,13 @@
fn check_specialization_on<'tcx>(tcx: TyCtxt<'tcx>, predicate: ty::Predicate<'tcx>, span: Span) {
debug!("can_specialize_on(predicate = {:?})", predicate);
- match predicate.skip_binders() {
+ match predicate.kind().skip_binder() {
// Global predicates are either always true or always false, so we
// are fine to specialize on.
_ if predicate.is_global() => (),
// We allow specializing on explicitly marked traits with no associated
// items.
- ty::PredicateAtom::Trait(pred, hir::Constness::NotConst) => {
+ ty::PredicateKind::Trait(pred, hir::Constness::NotConst) => {
if !matches!(
trait_predicate_kind(tcx, predicate),
Some(TraitSpecializationKind::Marker)
@@ -393,20 +393,20 @@
tcx: TyCtxt<'tcx>,
predicate: ty::Predicate<'tcx>,
) -> Option<TraitSpecializationKind> {
- match predicate.skip_binders() {
- ty::PredicateAtom::Trait(pred, hir::Constness::NotConst) => {
+ match predicate.kind().skip_binder() {
+ ty::PredicateKind::Trait(pred, hir::Constness::NotConst) => {
Some(tcx.trait_def(pred.def_id()).specialization_kind)
}
- ty::PredicateAtom::Trait(_, hir::Constness::Const)
- | ty::PredicateAtom::RegionOutlives(_)
- | ty::PredicateAtom::TypeOutlives(_)
- | ty::PredicateAtom::Projection(_)
- | ty::PredicateAtom::WellFormed(_)
- | ty::PredicateAtom::Subtype(_)
- | ty::PredicateAtom::ObjectSafe(_)
- | ty::PredicateAtom::ClosureKind(..)
- | ty::PredicateAtom::ConstEvaluatable(..)
- | ty::PredicateAtom::ConstEquate(..)
- | ty::PredicateAtom::TypeWellFormedFromEnv(..) => None,
+ ty::PredicateKind::Trait(_, hir::Constness::Const)
+ | ty::PredicateKind::RegionOutlives(_)
+ | ty::PredicateKind::TypeOutlives(_)
+ | ty::PredicateKind::Projection(_)
+ | ty::PredicateKind::WellFormed(_)
+ | ty::PredicateKind::Subtype(_)
+ | ty::PredicateKind::ObjectSafe(_)
+ | ty::PredicateKind::ClosureKind(..)
+ | ty::PredicateKind::ConstEvaluatable(..)
+ | ty::PredicateKind::ConstEquate(..)
+ | ty::PredicateKind::TypeWellFormedFromEnv(..) => None,
}
}
diff --git a/compiler/rustc_typeck/src/lib.rs b/compiler/rustc_typeck/src/lib.rs
index dde4a62..fd44baf 100644
--- a/compiler/rustc_typeck/src/lib.rs
+++ b/compiler/rustc_typeck/src/lib.rs
@@ -7,9 +7,9 @@
1. Determining the type of each expression.
2. Resolving methods and traits.
3. Guaranteeing that most type rules are met. ("Most?", you say, "why most?"
- Well, dear reader, read on)
+ Well, dear reader, read on.)
-The main entry point is `check_crate()`. Type checking operates in
+The main entry point is [`check_crate()`]. Type checking operates in
several major phases:
1. The collect phase first passes over all items and determines their
@@ -25,7 +25,7 @@
containing function). Inference is used to supply types wherever
they are unknown. The actual checking of a function itself has
several phases (check, regionck, writeback), as discussed in the
- documentation for the `check` module.
+ documentation for the [`check`] module.
The type checker is defined into various submodules which are documented
independently:
@@ -56,10 +56,10 @@
*/
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
-#![feature(array_value_iter)]
#![feature(bool_to_option)]
#![feature(box_syntax)]
#![feature(crate_visibility_modifier)]
+#![feature(format_args_capture)]
#![feature(in_band_lifetimes)]
#![feature(is_sorted)]
#![feature(nll)]
diff --git a/compiler/rustc_typeck/src/mem_categorization.rs b/compiler/rustc_typeck/src/mem_categorization.rs
index 9992094..fef52a3 100644
--- a/compiler/rustc_typeck/src/mem_categorization.rs
+++ b/compiler/rustc_typeck/src/mem_categorization.rs
@@ -364,6 +364,7 @@
| hir::ExprKind::Cast(..)
| hir::ExprKind::DropTemps(..)
| hir::ExprKind::Array(..)
+ | hir::ExprKind::If(..)
| hir::ExprKind::Tup(..)
| hir::ExprKind::Binary(..)
| hir::ExprKind::Block(..)
@@ -459,7 +460,7 @@
kind: ProjectionKind,
) -> PlaceWithHirId<'tcx> {
let mut projections = base_place.place.projections;
- projections.push(Projection { kind: kind, ty: ty });
+ projections.push(Projection { kind, ty });
let ret = PlaceWithHirId::new(
node.hir_id(),
base_place.place.base_ty,
@@ -653,9 +654,7 @@
// Then we see that to get the same result, we must start with
// `deref { deref { place_foo }}` instead of `place_foo` since the pattern is now `Some(x,)`
// and not `&&Some(x,)`, even though its assigned type is that of `&&Some(x,)`.
- for _ in
- 0..self.typeck_results.pat_adjustments().get(pat.hir_id).map(|v| v.len()).unwrap_or(0)
- {
+ for _ in 0..self.typeck_results.pat_adjustments().get(pat.hir_id).map_or(0, |v| v.len()) {
debug!("cat_pattern: applying adjustment to place_with_id={:?}", place_with_id);
place_with_id = self.cat_deref(pat, place_with_id)?;
}
diff --git a/compiler/rustc_typeck/src/outlives/explicit.rs b/compiler/rustc_typeck/src/outlives/explicit.rs
index ae336cc..6e5be87 100644
--- a/compiler/rustc_typeck/src/outlives/explicit.rs
+++ b/compiler/rustc_typeck/src/outlives/explicit.rs
@@ -29,8 +29,8 @@
// process predicates and convert to `RequiredPredicates` entry, see below
for &(predicate, span) in predicates.predicates {
- match predicate.skip_binders() {
- ty::PredicateAtom::TypeOutlives(OutlivesPredicate(ref ty, ref reg)) => {
+ match predicate.kind().skip_binder() {
+ ty::PredicateKind::TypeOutlives(OutlivesPredicate(ref ty, ref reg)) => {
insert_outlives_predicate(
tcx,
(*ty).into(),
@@ -40,7 +40,7 @@
)
}
- ty::PredicateAtom::RegionOutlives(OutlivesPredicate(ref reg1, ref reg2)) => {
+ ty::PredicateKind::RegionOutlives(OutlivesPredicate(ref reg1, ref reg2)) => {
insert_outlives_predicate(
tcx,
(*reg1).into(),
@@ -50,15 +50,15 @@
)
}
- ty::PredicateAtom::Trait(..)
- | ty::PredicateAtom::Projection(..)
- | ty::PredicateAtom::WellFormed(..)
- | ty::PredicateAtom::ObjectSafe(..)
- | ty::PredicateAtom::ClosureKind(..)
- | ty::PredicateAtom::Subtype(..)
- | ty::PredicateAtom::ConstEvaluatable(..)
- | ty::PredicateAtom::ConstEquate(..)
- | ty::PredicateAtom::TypeWellFormedFromEnv(..) => (),
+ ty::PredicateKind::Trait(..)
+ | ty::PredicateKind::Projection(..)
+ | ty::PredicateKind::WellFormed(..)
+ | ty::PredicateKind::ObjectSafe(..)
+ | ty::PredicateKind::ClosureKind(..)
+ | ty::PredicateKind::Subtype(..)
+ | ty::PredicateKind::ConstEvaluatable(..)
+ | ty::PredicateKind::ConstEquate(..)
+ | ty::PredicateKind::TypeWellFormedFromEnv(..) => (),
}
}
diff --git a/compiler/rustc_typeck/src/outlives/implicit_infer.rs b/compiler/rustc_typeck/src/outlives/implicit_infer.rs
index 3d0635e..02008e1 100644
--- a/compiler/rustc_typeck/src/outlives/implicit_infer.rs
+++ b/compiler/rustc_typeck/src/outlives/implicit_infer.rs
@@ -99,7 +99,7 @@
// we walk the crates again and re-calculate predicates for all
// items.
let item_predicates_len: usize =
- self.global_inferred_outlives.get(&item_did.to_def_id()).map(|p| p.len()).unwrap_or(0);
+ self.global_inferred_outlives.get(&item_did.to_def_id()).map_or(0, |p| p.len());
if item_required_predicates.len() > item_predicates_len {
*self.predicates_added = true;
self.global_inferred_outlives.insert(item_did.to_def_id(), item_required_predicates);
diff --git a/compiler/rustc_typeck/src/outlives/mod.rs b/compiler/rustc_typeck/src/outlives/mod.rs
index b1f7933..e94b845 100644
--- a/compiler/rustc_typeck/src/outlives/mod.rs
+++ b/compiler/rustc_typeck/src/outlives/mod.rs
@@ -30,13 +30,9 @@
if tcx.has_attr(item_def_id, sym::rustc_outlives) {
let mut pred: Vec<String> = predicates
.iter()
- .map(|(out_pred, _)| match out_pred.kind() {
- ty::PredicateKind::Atom(ty::PredicateAtom::RegionOutlives(p)) => {
- p.to_string()
- }
- ty::PredicateKind::Atom(ty::PredicateAtom::TypeOutlives(p)) => {
- p.to_string()
- }
+ .map(|(out_pred, _)| match out_pred.kind().skip_binder() {
+ ty::PredicateKind::RegionOutlives(p) => p.to_string(),
+ ty::PredicateKind::TypeOutlives(p) => p.to_string(),
err => bug!("unexpected predicate {:?}", err),
})
.collect();
@@ -89,12 +85,12 @@
|(ty::OutlivesPredicate(kind1, region2), &span)| {
match kind1.unpack() {
GenericArgKind::Type(ty1) => Some((
- ty::PredicateAtom::TypeOutlives(ty::OutlivesPredicate(ty1, region2))
+ ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(ty1, region2))
.to_predicate(tcx),
span,
)),
GenericArgKind::Lifetime(region1) => Some((
- ty::PredicateAtom::RegionOutlives(ty::OutlivesPredicate(
+ ty::PredicateKind::RegionOutlives(ty::OutlivesPredicate(
region1, region2,
))
.to_predicate(tcx),
diff --git a/compiler/rustc_typeck/src/structured_errors.rs b/compiler/rustc_typeck/src/structured_errors.rs
index 83125a3..04d0430 100644
--- a/compiler/rustc_typeck/src/structured_errors.rs
+++ b/compiler/rustc_typeck/src/structured_errors.rs
@@ -1,149 +1,36 @@
-use rustc_errors::{Applicability, DiagnosticBuilder, DiagnosticId};
-use rustc_middle::ty::{Ty, TypeFoldable};
+mod missing_cast_for_variadic_arg;
+mod sized_unsized_cast;
+mod wrong_number_of_generic_args;
+
+pub use self::{
+ missing_cast_for_variadic_arg::*, sized_unsized_cast::*, wrong_number_of_generic_args::*,
+};
+
+use rustc_errors::{DiagnosticBuilder, DiagnosticId};
use rustc_session::Session;
-use rustc_span::Span;
pub trait StructuredDiagnostic<'tcx> {
fn session(&self) -> &Session;
fn code(&self) -> DiagnosticId;
- fn common(&self) -> DiagnosticBuilder<'tcx>;
-
fn diagnostic(&self) -> DiagnosticBuilder<'tcx> {
- let err = self.common();
- if self.session().teach(&self.code()) { self.extended(err) } else { self.regular(err) }
- }
+ let err = self.diagnostic_common();
- fn regular(&self, err: DiagnosticBuilder<'tcx>) -> DiagnosticBuilder<'tcx> {
- err
- }
-
- fn extended(&self, err: DiagnosticBuilder<'tcx>) -> DiagnosticBuilder<'tcx> {
- err
- }
-}
-
-pub struct VariadicError<'tcx> {
- sess: &'tcx Session,
- span: Span,
- t: Ty<'tcx>,
- cast_ty: &'tcx str,
-}
-
-impl<'tcx> VariadicError<'tcx> {
- pub fn new(
- sess: &'tcx Session,
- span: Span,
- t: Ty<'tcx>,
- cast_ty: &'tcx str,
- ) -> VariadicError<'tcx> {
- VariadicError { sess, span, t, cast_ty }
- }
-}
-
-impl<'tcx> StructuredDiagnostic<'tcx> for VariadicError<'tcx> {
- fn session(&self) -> &Session {
- self.sess
- }
-
- fn code(&self) -> DiagnosticId {
- rustc_errors::error_code!(E0617)
- }
-
- fn common(&self) -> DiagnosticBuilder<'tcx> {
- let mut err = if self.t.references_error() {
- self.sess.diagnostic().struct_dummy()
+ if self.session().teach(&self.code()) {
+ self.diagnostic_extended(err)
} else {
- self.sess.struct_span_fatal_with_code(
- self.span,
- &format!("can't pass `{}` to variadic function", self.t),
- self.code(),
- )
- };
- if let Ok(snippet) = self.sess.source_map().span_to_snippet(self.span) {
- err.span_suggestion(
- self.span,
- &format!("cast the value to `{}`", self.cast_ty),
- format!("{} as {}", snippet, self.cast_ty),
- Applicability::MachineApplicable,
- );
- } else {
- err.help(&format!("cast the value to `{}`", self.cast_ty));
- }
- err
- }
-
- fn extended(&self, mut err: DiagnosticBuilder<'tcx>) -> DiagnosticBuilder<'tcx> {
- err.note(&format!(
- "certain types, like `{}`, must be cast before passing them to a \
- variadic function, because of arcane ABI rules dictated by the C \
- standard",
- self.t
- ));
- err
- }
-}
-
-pub struct SizedUnsizedCastError<'tcx> {
- sess: &'tcx Session,
- span: Span,
- expr_ty: Ty<'tcx>,
- cast_ty: String,
-}
-
-impl<'tcx> SizedUnsizedCastError<'tcx> {
- pub fn new(
- sess: &'tcx Session,
- span: Span,
- expr_ty: Ty<'tcx>,
- cast_ty: String,
- ) -> SizedUnsizedCastError<'tcx> {
- SizedUnsizedCastError { sess, span, expr_ty, cast_ty }
- }
-}
-
-impl<'tcx> StructuredDiagnostic<'tcx> for SizedUnsizedCastError<'tcx> {
- fn session(&self) -> &Session {
- self.sess
- }
-
- fn code(&self) -> DiagnosticId {
- rustc_errors::error_code!(E0607)
- }
-
- fn common(&self) -> DiagnosticBuilder<'tcx> {
- if self.expr_ty.references_error() {
- self.sess.diagnostic().struct_dummy()
- } else {
- self.sess.struct_span_fatal_with_code(
- self.span,
- &format!(
- "cannot cast thin pointer `{}` to fat pointer `{}`",
- self.expr_ty, self.cast_ty
- ),
- self.code(),
- )
+ self.diagnostic_regular(err)
}
}
- fn extended(&self, mut err: DiagnosticBuilder<'tcx>) -> DiagnosticBuilder<'tcx> {
- err.help(
- "Thin pointers are \"simple\" pointers: they are purely a reference to a
-memory address.
+ fn diagnostic_common(&self) -> DiagnosticBuilder<'tcx>;
-Fat pointers are pointers referencing \"Dynamically Sized Types\" (also
-called DST). DST don't have a statically known size, therefore they can
-only exist behind some kind of pointers that contain additional
-information. Slices and trait objects are DSTs. In the case of slices,
-the additional information the fat pointer holds is their size.
+ fn diagnostic_regular(&self, err: DiagnosticBuilder<'tcx>) -> DiagnosticBuilder<'tcx> {
+ err
+ }
-To fix this error, don't try to cast directly between thin and fat
-pointers.
-
-For more information about casts, take a look at The Book:
-https://doc.rust-lang.org/reference/expressions/operator-expr.html#type-cast-expressions",
- );
+ fn diagnostic_extended(&self, err: DiagnosticBuilder<'tcx>) -> DiagnosticBuilder<'tcx> {
err
}
}
diff --git a/compiler/rustc_typeck/src/structured_errors/missing_cast_for_variadic_arg.rs b/compiler/rustc_typeck/src/structured_errors/missing_cast_for_variadic_arg.rs
new file mode 100644
index 0000000..674b0e4
--- /dev/null
+++ b/compiler/rustc_typeck/src/structured_errors/missing_cast_for_variadic_arg.rs
@@ -0,0 +1,58 @@
+use crate::structured_errors::StructuredDiagnostic;
+use rustc_errors::{Applicability, DiagnosticBuilder, DiagnosticId};
+use rustc_middle::ty::{Ty, TypeFoldable};
+use rustc_session::Session;
+use rustc_span::Span;
+
+pub struct MissingCastForVariadicArg<'tcx> {
+ pub sess: &'tcx Session,
+ pub span: Span,
+ pub ty: Ty<'tcx>,
+ pub cast_ty: &'tcx str,
+}
+
+impl<'tcx> StructuredDiagnostic<'tcx> for MissingCastForVariadicArg<'tcx> {
+ fn session(&self) -> &Session {
+ self.sess
+ }
+
+ fn code(&self) -> DiagnosticId {
+ rustc_errors::error_code!(E0617)
+ }
+
+ fn diagnostic_common(&self) -> DiagnosticBuilder<'tcx> {
+ let mut err = if self.ty.references_error() {
+ self.sess.diagnostic().struct_dummy()
+ } else {
+ self.sess.struct_span_fatal_with_code(
+ self.span,
+ &format!("can't pass `{}` to variadic function", self.ty),
+ self.code(),
+ )
+ };
+
+ if let Ok(snippet) = self.sess.source_map().span_to_snippet(self.span) {
+ err.span_suggestion(
+ self.span,
+ &format!("cast the value to `{}`", self.cast_ty),
+ format!("{} as {}", snippet, self.cast_ty),
+ Applicability::MachineApplicable,
+ );
+ } else {
+ err.help(&format!("cast the value to `{}`", self.cast_ty));
+ }
+
+ err
+ }
+
+ fn diagnostic_extended(&self, mut err: DiagnosticBuilder<'tcx>) -> DiagnosticBuilder<'tcx> {
+ err.note(&format!(
+ "certain types, like `{}`, must be casted before passing them to a \
+ variadic function, because of arcane ABI rules dictated by the C \
+ standard",
+ self.ty
+ ));
+
+ err
+ }
+}
diff --git a/compiler/rustc_typeck/src/structured_errors/sized_unsized_cast.rs b/compiler/rustc_typeck/src/structured_errors/sized_unsized_cast.rs
new file mode 100644
index 0000000..d0477a3
--- /dev/null
+++ b/compiler/rustc_typeck/src/structured_errors/sized_unsized_cast.rs
@@ -0,0 +1,57 @@
+use crate::structured_errors::StructuredDiagnostic;
+use rustc_errors::{DiagnosticBuilder, DiagnosticId};
+use rustc_middle::ty::{Ty, TypeFoldable};
+use rustc_session::Session;
+use rustc_span::Span;
+
+pub struct SizedUnsizedCast<'tcx> {
+ pub sess: &'tcx Session,
+ pub span: Span,
+ pub expr_ty: Ty<'tcx>,
+ pub cast_ty: String,
+}
+
+impl<'tcx> StructuredDiagnostic<'tcx> for SizedUnsizedCast<'tcx> {
+ fn session(&self) -> &Session {
+ self.sess
+ }
+
+ fn code(&self) -> DiagnosticId {
+ rustc_errors::error_code!(E0607)
+ }
+
+ fn diagnostic_common(&self) -> DiagnosticBuilder<'tcx> {
+ if self.expr_ty.references_error() {
+ self.sess.diagnostic().struct_dummy()
+ } else {
+ self.sess.struct_span_fatal_with_code(
+ self.span,
+ &format!(
+ "cannot cast thin pointer `{}` to fat pointer `{}`",
+ self.expr_ty, self.cast_ty
+ ),
+ self.code(),
+ )
+ }
+ }
+
+ fn diagnostic_extended(&self, mut err: DiagnosticBuilder<'tcx>) -> DiagnosticBuilder<'tcx> {
+ err.help(
+ "Thin pointers are \"simple\" pointers: they are purely a reference to a
+memory address.
+
+Fat pointers are pointers referencing \"Dynamically Sized Types\" (also
+called DST). DST don't have a statically known size, therefore they can
+only exist behind some kind of pointers that contain additional
+information. Slices and trait objects are DSTs. In the case of slices,
+the additional information the fat pointer holds is their size.
+
+To fix this error, don't try to cast directly between thin and fat
+pointers.
+
+For more information about casts, take a look at The Book:
+https://doc.rust-lang.org/reference/expressions/operator-expr.html#type-cast-expressions",
+ );
+ err
+ }
+}
diff --git a/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs b/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs
new file mode 100644
index 0000000..e35c155
--- /dev/null
+++ b/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs
@@ -0,0 +1,393 @@
+use crate::structured_errors::StructuredDiagnostic;
+use hir::def::DefKind;
+use rustc_errors::{pluralize, Applicability, DiagnosticBuilder, DiagnosticId};
+use rustc_hir as hir;
+use rustc_middle::ty::{self as ty, TyCtxt};
+use rustc_session::Session;
+use rustc_span::Span;
+use rustc_span::{def_id::DefId, MultiSpan};
+
+/// Handles the `wrong number of type / lifetime / ... arguments` family of error messages.
+pub struct WrongNumberOfGenericArgs<'a, 'tcx> {
+ crate tcx: TyCtxt<'tcx>,
+
+ /// "type", "lifetime" etc., put verbatim into the message
+ crate kind: &'static str,
+
+ /// Minimum number of expected generic arguments (e.g. `2` for `HashMap`)
+ crate expected_min: usize,
+
+ /// Maximum number of expected generic arguments (e.g. `3` for `HashMap`)
+ crate expected_max: usize,
+
+ /// Number of generic arguments provided by the user
+ crate provided: usize,
+
+ /// Offset into `gen_params` - depends on the `kind`; might be different than `args_offset` when
+ /// user passed e.g. more arguments than was actually expected
+ crate params_offset: usize,
+
+ /// Offset into `gen_args` - depends on the `kind`
+ crate args_offset: usize,
+
+ /// Offending path segment
+ crate path_segment: &'a hir::PathSegment<'a>,
+
+ /// Generic parameters as expected by type or trait
+ crate gen_params: &'a ty::Generics,
+
+ /// Generic arguments as provided by user
+ crate gen_args: &'a hir::GenericArgs<'a>,
+
+ /// DefId of the generic type
+ crate def_id: DefId,
+
+ /// Offending place where the generic type has been misused
+ crate span: Span,
+}
+
+impl<'tcx> WrongNumberOfGenericArgs<'_, 'tcx> {
+ fn quantifier_and_bound(&self) -> (&'static str, usize) {
+ if self.expected_min == self.expected_max {
+ ("", self.expected_min)
+ } else if self.provided < self.expected_min {
+ ("at least ", self.expected_min)
+ } else {
+ ("at most ", self.expected_max)
+ }
+ }
+
+ fn start_diagnostics(&self) -> DiagnosticBuilder<'tcx> {
+ let span = self.path_segment.ident.span;
+
+ let msg = {
+ let def_path = self.tcx.def_path_str(self.def_id);
+ let def_kind = self.tcx.def_kind(self.def_id).descr(self.def_id);
+ let (quantifier, bound) = self.quantifier_and_bound();
+
+ if self.gen_args.span().is_some() {
+ format!(
+ "this {} takes {}{} {} argument{} but {}{} {} argument{} {} supplied",
+ def_kind,
+ quantifier,
+ bound,
+ self.kind,
+ pluralize!(bound),
+ if self.provided > 0 && self.provided < self.expected_min {
+ "only "
+ } else {
+ ""
+ },
+ self.provided,
+ self.kind,
+ pluralize!(self.provided),
+ if self.provided == 1 { "was" } else { "were" },
+ )
+ } else {
+ format!("missing generics for {} `{}`", def_kind, def_path)
+ }
+ };
+
+ self.tcx.sess.struct_span_err_with_code(span, &msg, self.code())
+ }
+
+ /// Builds the `expected 1 type argument / supplied 2 type arguments` message.
+ fn notify(&self, err: &mut DiagnosticBuilder<'_>) {
+ let (quantifier, bound) = self.quantifier_and_bound();
+
+ err.span_label(
+ self.path_segment.ident.span,
+ format!(
+ "expected {}{} {} argument{}",
+ quantifier,
+ bound,
+ self.kind,
+ pluralize!(bound),
+ ),
+ );
+
+ // When user's provided too many arguments, we don't highlight each of them, because it
+ // would overlap with the suggestion to remove them:
+ //
+ // ```
+ // type Foo = Bar<usize, usize>;
+ // ----- ----- supplied 2 type arguments
+ // ^^^^^^^ remove this type argument
+ // ```
+ if self.provided > self.expected_max {
+ return;
+ }
+
+ let args = self.gen_args.args.iter().skip(self.args_offset).take(self.provided).enumerate();
+
+ for (i, arg) in args {
+ err.span_label(
+ arg.span(),
+ if i + 1 == self.provided {
+ format!(
+ "supplied {} {} argument{}",
+ self.provided,
+ self.kind,
+ pluralize!(self.provided)
+ )
+ } else {
+ String::new()
+ },
+ );
+ }
+ }
+
+ fn suggest(&self, err: &mut DiagnosticBuilder<'_>) {
+ if self.provided == 0 {
+ if self.gen_args.span().is_some() {
+ self.suggest_adding_args(err);
+ } else {
+ self.suggest_creating_generics(err);
+ }
+ } else if self.provided < self.expected_min {
+ self.suggest_adding_args(err);
+ } else {
+ self.suggest_removing_args_or_generics(err);
+ }
+ }
+
+ /// Suggests to create generics (`<...>`) when current invocation site contains no generics at
+ /// all:
+ ///
+ /// ```text
+ /// type Map = HashMap;
+ /// ```
+ fn suggest_creating_generics(&self, err: &mut DiagnosticBuilder<'_>) {
+ let params = self
+ .gen_params
+ .params
+ .iter()
+ .skip(self.params_offset)
+ .take(self.expected_min)
+ .map(|param| param.name.to_string())
+ .collect::<Vec<_>>()
+ .join(", ");
+
+ let def_kind = self.tcx.def_kind(self.def_id);
+
+ let sugg = if matches!(def_kind, DefKind::Fn | DefKind::AssocFn) {
+ format!("::<{}>", params)
+ } else {
+ format!("<{}>", params)
+ };
+
+ let msg = format!(
+ "use angle brackets to add missing {} argument{}",
+ self.kind,
+ pluralize!(self.expected_min),
+ );
+
+ err.span_suggestion_verbose(
+ self.path_segment.ident.span.shrink_to_hi(),
+ &msg,
+ sugg,
+ Applicability::HasPlaceholders,
+ );
+ }
+
+ /// Suggests to add missing argument(s) when current invocation site already contains some
+ /// generics:
+ ///
+ /// ```text
+ /// type Map = HashMap<String>;
+ /// ```
+ fn suggest_adding_args(&self, err: &mut DiagnosticBuilder<'_>) {
+ assert!(!self.gen_args.is_empty());
+
+ if self.gen_args.parenthesized {
+ return;
+ }
+
+ let missing_arg_count = self.expected_min - self.provided;
+
+ let (span, sugg_prefix) = if self.args_offset + self.provided == 0 {
+ let span = self.gen_args.args[0].span().shrink_to_lo();
+ (span, "")
+ } else {
+ let span =
+ self.gen_args.args[self.args_offset + self.provided - 1].span().shrink_to_hi();
+ (span, ", ")
+ };
+
+ let msg = format!("add missing {} argument{}", self.kind, pluralize!(missing_arg_count));
+
+ let sugg = self
+ .gen_params
+ .params
+ .iter()
+ .skip(self.params_offset + self.provided)
+ .take(missing_arg_count)
+ .map(|param| param.name.to_string())
+ .collect::<Vec<_>>()
+ .join(", ");
+
+ let sugg = format!("{}{}", sugg_prefix, sugg);
+
+ err.span_suggestion_verbose(span, &msg, sugg, Applicability::HasPlaceholders);
+ }
+
+ /// Suggests to remove redundant argument(s):
+ ///
+ /// ```text
+ /// type Map = HashMap<String, String, String, String>;
+ /// ```
+ fn suggest_removing_args_or_generics(&self, err: &mut DiagnosticBuilder<'_>) {
+ assert!(self.provided > 0);
+
+ let redundant_args_count = self.provided - self.expected_max;
+ let remove_entire_generics = redundant_args_count >= self.gen_args.args.len();
+
+ let (span, msg) = if remove_entire_generics {
+ let sm = self.tcx.sess.source_map();
+
+ let span = self
+ .path_segment
+ .args
+ .unwrap()
+ .span_ext(sm)
+ .unwrap()
+ .with_lo(self.path_segment.ident.span.hi());
+
+ let msg = format!(
+ "remove these {}generics",
+ if self.gen_args.parenthesized { "parenthetical " } else { "" },
+ );
+
+ (span, msg)
+ } else {
+ // When it comes to removing particular argument(s) from the generics, there are two
+ // edge cases we have to consider:
+ //
+ // When the first redundant argument is at the beginning or in the middle of the
+ // generics, like so:
+ //
+ // ```
+ // type Map = HashMap<String, String, String, String>;
+ // ^^^^^^^^^^^^^^^^
+ // | span must start with the argument
+ // ```
+ //
+ // When the last redundant argument is at the ending of the generics, like so:
+ //
+ // ```
+ // type Map = HashMap<String, String, String, String>;
+ // ^^^^^^^^^^^^^^^^
+ // | span must start with the comma
+ // ```
+
+ // Index of the first redundant argument
+ let from_idx = self.args_offset + self.expected_max;
+
+ // Index of the last redundant argument
+ let to_idx = self.args_offset + self.provided - 1;
+
+ assert!(from_idx <= to_idx);
+
+ let (from, comma_eaten) = {
+ let first_argument_starts_generics = from_idx == 0;
+ let last_argument_ends_generics = to_idx + 1 == self.gen_args.args.len();
+
+ if !first_argument_starts_generics && last_argument_ends_generics {
+ (self.gen_args.args[from_idx - 1].span().hi(), true)
+ } else {
+ (self.gen_args.args[from_idx].span().lo(), false)
+ }
+ };
+
+ let to = {
+ let hi = self.gen_args.args[to_idx].span().hi();
+
+ if comma_eaten {
+ hi
+ } else {
+ self.gen_args.args.get(to_idx + 1).map(|arg| arg.span().lo()).unwrap_or(hi)
+ }
+ };
+
+ let span = Span::new(from, to, self.span.ctxt());
+
+ let msg = format!(
+ "remove {} {} argument{}",
+ if redundant_args_count == 1 { "this" } else { "these" },
+ self.kind,
+ pluralize!(redundant_args_count),
+ );
+
+ (span, msg)
+ };
+
+ err.span_suggestion(span, &msg, String::new(), Applicability::MaybeIncorrect);
+ }
+
+ /// Builds the `type defined here` message.
+ fn show_definition(&self, err: &mut DiagnosticBuilder<'_>) {
+ let mut spans: MultiSpan = if let Some(def_span) = self.tcx.def_ident_span(self.def_id) {
+ def_span.into()
+ } else {
+ return;
+ };
+
+ let msg = {
+ let def_kind = self.tcx.def_kind(self.def_id).descr(self.def_id);
+ let (quantifier, bound) = self.quantifier_and_bound();
+
+ let params = if bound == 0 {
+ String::new()
+ } else {
+ let params = self
+ .gen_params
+ .params
+ .iter()
+ .skip(self.params_offset)
+ .take(bound)
+ .map(|param| {
+ let span = self.tcx.def_span(param.def_id);
+ spans.push_span_label(span, String::new());
+ param
+ })
+ .map(|param| format!("`{}`", param.name))
+ .collect::<Vec<_>>()
+ .join(", ");
+
+ format!(": {}", params)
+ };
+
+ format!(
+ "{} defined here, with {}{} {} parameter{}{}",
+ def_kind,
+ quantifier,
+ bound,
+ self.kind,
+ pluralize!(bound),
+ params,
+ )
+ };
+
+ err.span_note(spans, &msg);
+ }
+}
+
+impl<'tcx> StructuredDiagnostic<'tcx> for WrongNumberOfGenericArgs<'_, 'tcx> {
+ fn session(&self) -> &Session {
+ self.tcx.sess
+ }
+
+ fn code(&self) -> DiagnosticId {
+ rustc_errors::error_code!(E0107)
+ }
+
+ fn diagnostic_common(&self) -> DiagnosticBuilder<'tcx> {
+ let mut err = self.start_diagnostics();
+
+ self.notify(&mut err);
+ self.suggest(&mut err);
+ self.show_definition(&mut err);
+
+ err
+ }
+}
diff --git a/compiler/rustc_typeck/src/variance/constraints.rs b/compiler/rustc_typeck/src/variance/constraints.rs
index a8fbdfb..339eb5f 100644
--- a/compiler/rustc_typeck/src/variance/constraints.rs
+++ b/compiler/rustc_typeck/src/variance/constraints.rs
@@ -207,27 +207,13 @@
}
}
- fn add_constraints_from_trait_ref(
- &mut self,
- current: &CurrentItem,
- trait_ref: ty::TraitRef<'tcx>,
- variance: VarianceTermPtr<'a>,
- ) {
- debug!("add_constraints_from_trait_ref: trait_ref={:?} variance={:?}", trait_ref, variance);
- self.add_constraints_from_invariant_substs(current, trait_ref.substs, variance);
- }
-
+ #[instrument(skip(self, current))]
fn add_constraints_from_invariant_substs(
&mut self,
current: &CurrentItem,
substs: SubstsRef<'tcx>,
variance: VarianceTermPtr<'a>,
) {
- debug!(
- "add_constraints_from_invariant_substs: substs={:?} variance={:?}",
- substs, variance
- );
-
// Trait are always invariant so we can take advantage of that.
let variance_i = self.invariant(variance);
@@ -300,8 +286,7 @@
}
ty::Projection(ref data) => {
- let tcx = self.tcx();
- self.add_constraints_from_trait_ref(current, data.trait_ref(tcx), variance);
+ self.add_constraints_from_invariant_substs(current, data.substs, variance);
}
ty::Opaque(_, substs) => {