Importing rustc-1.56.0
Change-Id: I98941481270706fa55f8fb2cb91686ae3bd30f38
diff --git a/compiler/rustc/Cargo.toml b/compiler/rustc/Cargo.toml
index ca6055c..37f90bf 100644
--- a/compiler/rustc/Cargo.toml
+++ b/compiler/rustc/Cargo.toml
@@ -1,5 +1,4 @@
[package]
-authors = ["The Rust Project Developers"]
name = "rustc-main"
version = "0.0.0"
edition = '2018'
diff --git a/compiler/rustc_apfloat/Cargo.toml b/compiler/rustc_apfloat/Cargo.toml
index 103e64b..9f266b1 100644
--- a/compiler/rustc_apfloat/Cargo.toml
+++ b/compiler/rustc_apfloat/Cargo.toml
@@ -1,5 +1,4 @@
[package]
-authors = ["The Rust Project Developers"]
name = "rustc_apfloat"
version = "0.0.0"
edition = "2018"
diff --git a/compiler/rustc_arena/Cargo.toml b/compiler/rustc_arena/Cargo.toml
index 5d4d475..eba8a2a 100644
--- a/compiler/rustc_arena/Cargo.toml
+++ b/compiler/rustc_arena/Cargo.toml
@@ -1,5 +1,4 @@
[package]
-authors = ["The Rust Project Developers"]
name = "rustc_arena"
version = "0.0.0"
edition = "2018"
diff --git a/compiler/rustc_arena/src/lib.rs b/compiler/rustc_arena/src/lib.rs
index c3e4945..6d5f47a 100644
--- a/compiler/rustc_arena/src/lib.rs
+++ b/compiler/rustc_arena/src/lib.rs
@@ -15,6 +15,8 @@
#![feature(new_uninit)]
#![feature(maybe_uninit_slice)]
#![feature(min_specialization)]
+#![feature(decl_macro)]
+#![feature(rustc_attrs)]
#![cfg_attr(test, feature(test))]
use rustc_data_structures::sync;
@@ -608,117 +610,113 @@
}
}
-#[macro_export]
-macro_rules! arena_for_type {
+pub macro arena_for_type {
([][$ty:ty]) => {
$crate::TypedArena<$ty>
- };
+ },
([few $(, $attrs:ident)*][$ty:ty]) => {
::std::marker::PhantomData<$ty>
- };
+ },
([$ignore:ident $(, $attrs:ident)*]$args:tt) => {
$crate::arena_for_type!([$($attrs),*]$args)
- };
+ },
}
-#[macro_export]
-macro_rules! which_arena_for_type {
+pub macro which_arena_for_type {
([][$arena:expr]) => {
::std::option::Option::Some($arena)
- };
+ },
([few$(, $attrs:ident)*][$arena:expr]) => {
::std::option::Option::None
- };
+ },
([$ignore:ident$(, $attrs:ident)*]$args:tt) => {
$crate::which_arena_for_type!([$($attrs),*]$args)
- };
+ },
}
-#[macro_export]
-macro_rules! declare_arena {
- ([], [$($a:tt $name:ident: $ty:ty,)*], $tcx:lifetime) => {
- #[derive(Default)]
- pub struct Arena<$tcx> {
- pub dropless: $crate::DroplessArena,
- drop: $crate::DropArena,
- $($name: $crate::arena_for_type!($a[$ty]),)*
+#[rustc_macro_transparency = "semitransparent"]
+pub macro declare_arena([$($a:tt $name:ident: $ty:ty,)*], $tcx:lifetime) {
+ #[derive(Default)]
+ pub struct Arena<$tcx> {
+ pub dropless: $crate::DroplessArena,
+ drop: $crate::DropArena,
+ $($name: $crate::arena_for_type!($a[$ty]),)*
+ }
+
+ pub trait ArenaAllocatable<'tcx, T = Self>: Sized {
+ fn allocate_on<'a>(self, arena: &'a Arena<'tcx>) -> &'a mut Self;
+ fn allocate_from_iter<'a>(
+ arena: &'a Arena<'tcx>,
+ iter: impl ::std::iter::IntoIterator<Item = Self>,
+ ) -> &'a mut [Self];
+ }
+
+ impl<'tcx, T: Copy> ArenaAllocatable<'tcx, ()> for T {
+ #[inline]
+ fn allocate_on<'a>(self, arena: &'a Arena<'tcx>) -> &'a mut Self {
+ arena.dropless.alloc(self)
+ }
+ #[inline]
+ fn allocate_from_iter<'a>(
+ arena: &'a Arena<'tcx>,
+ iter: impl ::std::iter::IntoIterator<Item = Self>,
+ ) -> &'a mut [Self] {
+ arena.dropless.alloc_from_iter(iter)
}
- pub trait ArenaAllocatable<'tcx, T = Self>: Sized {
- fn allocate_on<'a>(self, arena: &'a Arena<'tcx>) -> &'a mut Self;
- fn allocate_from_iter<'a>(
- arena: &'a Arena<'tcx>,
- iter: impl ::std::iter::IntoIterator<Item = Self>,
- ) -> &'a mut [Self];
- }
-
- impl<'tcx, T: Copy> ArenaAllocatable<'tcx, ()> for T {
+ }
+ $(
+ impl<$tcx> ArenaAllocatable<$tcx, $ty> for $ty {
#[inline]
- fn allocate_on<'a>(self, arena: &'a Arena<'tcx>) -> &'a mut Self {
- arena.dropless.alloc(self)
+ fn allocate_on<'a>(self, arena: &'a Arena<$tcx>) -> &'a mut Self {
+ if !::std::mem::needs_drop::<Self>() {
+ return arena.dropless.alloc(self);
+ }
+ match $crate::which_arena_for_type!($a[&arena.$name]) {
+ ::std::option::Option::<&$crate::TypedArena<Self>>::Some(ty_arena) => {
+ ty_arena.alloc(self)
+ }
+ ::std::option::Option::None => unsafe { arena.drop.alloc(self) },
+ }
}
+
#[inline]
fn allocate_from_iter<'a>(
- arena: &'a Arena<'tcx>,
+ arena: &'a Arena<$tcx>,
iter: impl ::std::iter::IntoIterator<Item = Self>,
) -> &'a mut [Self] {
- arena.dropless.alloc_from_iter(iter)
+ if !::std::mem::needs_drop::<Self>() {
+ return arena.dropless.alloc_from_iter(iter);
+ }
+ match $crate::which_arena_for_type!($a[&arena.$name]) {
+ ::std::option::Option::<&$crate::TypedArena<Self>>::Some(ty_arena) => {
+ ty_arena.alloc_from_iter(iter)
+ }
+ ::std::option::Option::None => unsafe { arena.drop.alloc_from_iter(iter) },
+ }
}
-
}
- $(
- impl<$tcx> ArenaAllocatable<$tcx, $ty> for $ty {
- #[inline]
- fn allocate_on<'a>(self, arena: &'a Arena<$tcx>) -> &'a mut Self {
- if !::std::mem::needs_drop::<Self>() {
- return arena.dropless.alloc(self);
- }
- match $crate::which_arena_for_type!($a[&arena.$name]) {
- ::std::option::Option::<&$crate::TypedArena<Self>>::Some(ty_arena) => {
- ty_arena.alloc(self)
- }
- ::std::option::Option::None => unsafe { arena.drop.alloc(self) },
- }
- }
+ )*
- #[inline]
- fn allocate_from_iter<'a>(
- arena: &'a Arena<$tcx>,
- iter: impl ::std::iter::IntoIterator<Item = Self>,
- ) -> &'a mut [Self] {
- if !::std::mem::needs_drop::<Self>() {
- return arena.dropless.alloc_from_iter(iter);
- }
- match $crate::which_arena_for_type!($a[&arena.$name]) {
- ::std::option::Option::<&$crate::TypedArena<Self>>::Some(ty_arena) => {
- ty_arena.alloc_from_iter(iter)
- }
- ::std::option::Option::None => unsafe { arena.drop.alloc_from_iter(iter) },
- }
- }
- }
- )*
+ impl<'tcx> Arena<'tcx> {
+ #[inline]
+ pub fn alloc<T: ArenaAllocatable<'tcx, U>, U>(&self, value: T) -> &mut T {
+ value.allocate_on(self)
+ }
- impl<'tcx> Arena<'tcx> {
- #[inline]
- pub fn alloc<T: ArenaAllocatable<'tcx, U>, U>(&self, value: T) -> &mut T {
- value.allocate_on(self)
+ #[inline]
+ pub fn alloc_slice<T: ::std::marker::Copy>(&self, value: &[T]) -> &mut [T] {
+ if value.is_empty() {
+ return &mut [];
}
+ self.dropless.alloc_slice(value)
+ }
- #[inline]
- pub fn alloc_slice<T: ::std::marker::Copy>(&self, value: &[T]) -> &mut [T] {
- if value.is_empty() {
- return &mut [];
- }
- self.dropless.alloc_slice(value)
- }
-
- pub fn alloc_from_iter<'a, T: ArenaAllocatable<'tcx, U>, U>(
- &'a self,
- iter: impl ::std::iter::IntoIterator<Item = T>,
- ) -> &'a mut [T] {
- T::allocate_from_iter(self, iter)
- }
+ pub fn alloc_from_iter<'a, T: ArenaAllocatable<'tcx, U>, U>(
+ &'a self,
+ iter: impl ::std::iter::IntoIterator<Item = T>,
+ ) -> &'a mut [T] {
+ T::allocate_from_iter(self, iter)
}
}
}
diff --git a/compiler/rustc_ast/Cargo.toml b/compiler/rustc_ast/Cargo.toml
index 6b9b9e8..67cf5d9 100644
--- a/compiler/rustc_ast/Cargo.toml
+++ b/compiler/rustc_ast/Cargo.toml
@@ -1,5 +1,4 @@
[package]
-authors = ["The Rust Project Developers"]
name = "rustc_ast"
version = "0.0.0"
edition = "2018"
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index f851725..c27ab81 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -284,7 +284,7 @@
pub use crate::node_id::{NodeId, CRATE_NODE_ID, DUMMY_NODE_ID};
-/// A modifier on a bound, e.g., `?Sized` or `?const Trait`.
+/// A modifier on a bound, e.g., `?Sized` or `~const Trait`.
///
/// Negative bounds should also be handled here.
#[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Debug)]
@@ -295,10 +295,10 @@
/// `?Trait`
Maybe,
- /// `?const Trait`
+ /// `~const Trait`
MaybeConst,
- /// `?const ?Trait`
+ /// `~const ?Trait`
//
// This parses but will be rejected during AST validation.
MaybeConstMaybe,
@@ -332,10 +332,13 @@
pub enum ParamKindOrd {
Lifetime,
Type,
- // `unordered` is only `true` if `sess.has_features().const_generics`
- // is active. Specifically, if it's only `min_const_generics`, it will still require
+ // `unordered` is only `true` if `sess.unordered_const_ty_params()`
+ // returns true. Specifically, if it's only `min_const_generics`, it will still require
// ordering consts after types.
Const { unordered: bool },
+ // `Infer` is not actually constructed directly from the AST, but is implicitly constructed
+ // during HIR lowering, and `ParamKindOrd` will implicitly order inferred variables last.
+ Infer,
}
impl Ord for ParamKindOrd {
@@ -343,7 +346,7 @@
use ParamKindOrd::*;
let to_int = |v| match v {
Lifetime => 0,
- Type | Const { unordered: true } => 1,
+ Infer | Type | Const { unordered: true } => 1,
// technically both consts should be ordered equally,
// but only one is ever encountered at a time, so this is
// fine.
@@ -371,6 +374,7 @@
ParamKindOrd::Lifetime => "lifetime".fmt(f),
ParamKindOrd::Type => "type".fmt(f),
ParamKindOrd::Const { .. } => "const".fmt(f),
+ ParamKindOrd::Infer => "infer".fmt(f),
}
}
}
@@ -498,13 +502,6 @@
pub attrs: Vec<Attribute>,
pub items: Vec<P<Item>>,
pub span: Span,
- /// The order of items in the HIR is unrelated to the order of
- /// items in the AST. However, we generate proc macro harnesses
- /// based on the AST order, and later refer to these harnesses
- /// from the HIR. This field keeps track of the order in which
- /// we generated proc macros harnesses, so that we can map
- /// HIR proc macros items back to their harness items.
- pub proc_macros: Vec<NodeId>,
}
/// Possible values inside of compile-time attribute lists.
@@ -561,6 +558,14 @@
pub rules: BlockCheckMode,
pub span: Span,
pub tokens: Option<LazyTokenStream>,
+ /// The following *isn't* a parse error, but will cause multiple errors in following stages.
+ /// ```
+ /// let x = {
+ /// foo: var
+ /// };
+ /// ```
+ /// #34255
+ pub could_be_bare_literal: bool,
}
/// A match pattern.
@@ -1001,13 +1006,42 @@
pub id: NodeId,
pub pat: P<Pat>,
pub ty: Option<P<Ty>>,
- /// Initializer expression to set the value, if any.
- pub init: Option<P<Expr>>,
+ pub kind: LocalKind,
pub span: Span,
pub attrs: AttrVec,
pub tokens: Option<LazyTokenStream>,
}
+#[derive(Clone, Encodable, Decodable, Debug)]
+pub enum LocalKind {
+ /// Local declaration.
+ /// Example: `let x;`
+ Decl,
+ /// Local declaration with an initializer.
+ /// Example: `let x = y;`
+ Init(P<Expr>),
+ /// Local declaration with an initializer and an `else` clause.
+ /// Example: `let Some(x) = y else { return };`
+ InitElse(P<Expr>, P<Block>),
+}
+
+impl LocalKind {
+ pub fn init(&self) -> Option<&Expr> {
+ match self {
+ Self::Decl => None,
+ Self::Init(i) | Self::InitElse(i, _) => Some(i),
+ }
+ }
+
+ pub fn init_else_opt(&self) -> Option<(&Expr, Option<&Block>)> {
+ match self {
+ Self::Decl => None,
+ Self::Init(init) => Some((init, None)),
+ Self::InitElse(init, els) => Some((init, Some(els))),
+ }
+ }
+}
+
/// An arm of a 'match'.
///
/// E.g., `0..=10 => { println!("match!") }` as in
@@ -1298,7 +1332,9 @@
Type(P<Expr>, P<Ty>),
/// A `let pat = expr` expression that is only semantically allowed in the condition
/// of `if` / `while` expressions. (e.g., `if let 0 = x { .. }`).
- Let(P<Pat>, P<Expr>),
+ ///
+ /// `Span` represents the whole `let pat = expr` statement.
+ Let(P<Pat>, P<Expr>, Span),
/// An `if` block, with an optional `else` block.
///
/// `if expr { block } else { expr }`
@@ -1866,10 +1902,6 @@
Never,
/// A tuple (`(A, B, C, D,...)`).
Tup(Vec<P<Ty>>),
- /// An anonymous struct type i.e. `struct { foo: Type }`
- AnonymousStruct(Vec<FieldDef>, bool),
- /// An anonymous union type i.e. `union { bar: Type }`
- AnonymousUnion(Vec<FieldDef>, bool),
/// A path (`module::module::...::Type`), optionally
/// "qualified", e.g., `<Vec<T> as SomeTrait>::SomeType`.
///
@@ -2022,7 +2054,9 @@
#[derive(Clone, Encodable, Decodable, Debug)]
pub struct InlineAsm {
pub template: Vec<InlineAsmTemplatePiece>,
+ pub template_strs: Box<[(Symbol, Option<Symbol>, Span)]>,
pub operands: Vec<(InlineAsmOperand, Span)>,
+ pub clobber_abi: Option<(Symbol, Span)>,
pub options: InlineAsmOptions,
pub line_spans: Vec<Span>,
}
diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs
index 41121d0..81195f7 100644
--- a/compiler/rustc_ast/src/attr/mod.rs
+++ b/compiler/rustc_ast/src/attr/mod.rs
@@ -564,11 +564,11 @@
I: Iterator<Item = TokenTree>,
{
match tokens.peek() {
- Some(TokenTree::Token(token)) => {
- if let Ok(lit) = Lit::from_token(token) {
- tokens.next();
- return Some(NestedMetaItem::Literal(lit));
- }
+ Some(TokenTree::Token(token))
+ if let Ok(lit) = Lit::from_token(token) =>
+ {
+ tokens.next();
+ return Some(NestedMetaItem::Literal(lit));
}
Some(TokenTree::Delimited(_, token::NoDelim, inner_tokens)) => {
let inner_tokens = inner_tokens.clone();
diff --git a/compiler/rustc_ast/src/lib.rs b/compiler/rustc_ast/src/lib.rs
index 3207aee..ef3f603 100644
--- a/compiler/rustc_ast/src/lib.rs
+++ b/compiler/rustc_ast/src/lib.rs
@@ -8,14 +8,15 @@
html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/",
test(attr(deny(warnings)))
)]
-#![feature(box_syntax)]
#![feature(box_patterns)]
-#![feature(const_fn_transmute)]
+#![cfg_attr(bootstrap, feature(const_fn_transmute))]
#![feature(crate_visibility_modifier)]
+#![feature(if_let_guard)]
#![feature(iter_zip)]
#![feature(label_break_value)]
#![feature(nll)]
#![feature(min_specialization)]
+#![cfg_attr(bootstrap, allow(incomplete_features))] // if_let_guard
#![recursion_limit = "256"]
#[macro_use]
diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs
index 87950b4..ba86036 100644
--- a/compiler/rustc_ast/src/mut_visit.rs
+++ b/compiler/rustc_ast/src/mut_visit.rs
@@ -484,9 +484,6 @@
visit_vec(bounds, |bound| vis.visit_param_bound(bound));
}
TyKind::MacCall(mac) => vis.visit_mac_call(mac),
- TyKind::AnonymousStruct(fields, ..) | TyKind::AnonymousUnion(fields, ..) => {
- fields.flat_map_in_place(|field| vis.flat_map_field_def(field));
- }
}
vis.visit_span(span);
visit_lazy_tts(tokens, vis);
@@ -571,11 +568,20 @@
}
pub fn noop_visit_local<T: MutVisitor>(local: &mut P<Local>, vis: &mut T) {
- let Local { id, pat, ty, init, span, attrs, tokens } = local.deref_mut();
+ let Local { id, pat, ty, kind, span, attrs, tokens } = local.deref_mut();
vis.visit_id(id);
vis.visit_pat(pat);
visit_opt(ty, |ty| vis.visit_ty(ty));
- visit_opt(init, |init| vis.visit_expr(init));
+ match kind {
+ LocalKind::Decl => {}
+ LocalKind::Init(init) => {
+ vis.visit_expr(init);
+ }
+ LocalKind::InitElse(init, els) => {
+ vis.visit_expr(init);
+ vis.visit_block(els);
+ }
+ }
vis.visit_span(span);
visit_thin_attrs(attrs, vis);
visit_lazy_tts(tokens, vis);
@@ -940,7 +946,7 @@
}
pub fn noop_visit_block<T: MutVisitor>(block: &mut P<Block>, vis: &mut T) {
- let Block { id, stmts, rules: _, span, tokens } = block.deref_mut();
+ let Block { id, stmts, rules: _, span, tokens, could_be_bare_literal: _ } = block.deref_mut();
vis.visit_id(id);
stmts.flat_map_in_place(|stmt| vis.flat_map_stmt(stmt));
vis.visit_span(span);
@@ -1050,7 +1056,7 @@
// FIXME: Avoid visiting the crate as a `Mod` item, flat map only the inner items if possible,
// or make crate visiting first class if necessary.
pub fn noop_visit_crate<T: MutVisitor>(krate: &mut Crate, vis: &mut T) {
- visit_clobber(krate, |Crate { attrs, items, span, proc_macros }| {
+ visit_clobber(krate, |Crate { attrs, items, span }| {
let item_vis =
Visibility { kind: VisibilityKind::Public, span: span.shrink_to_lo(), tokens: None };
let item = P(Item {
@@ -1066,13 +1072,11 @@
let len = items.len();
if len == 0 {
- Crate { attrs: vec![], items: vec![], span, proc_macros }
+ Crate { attrs: vec![], items: vec![], span }
} else if len == 1 {
let Item { attrs, span, kind, .. } = items.into_iter().next().unwrap().into_inner();
match kind {
- ItemKind::Mod(_, ModKind::Loaded(items, ..)) => {
- Crate { attrs, items, span, proc_macros }
- }
+ ItemKind::Mod(_, ModKind::Loaded(items, ..)) => Crate { attrs, items, span },
_ => panic!("visitor converted a module to not a module"),
}
} else {
@@ -1179,13 +1183,10 @@
for (op, _) in &mut asm.operands {
match op {
InlineAsmOperand::In { expr, .. }
+ | InlineAsmOperand::Out { expr: Some(expr), .. }
| InlineAsmOperand::InOut { expr, .. }
| InlineAsmOperand::Sym { expr, .. } => vis.visit_expr(expr),
- InlineAsmOperand::Out { expr, .. } => {
- if let Some(expr) = expr {
- vis.visit_expr(expr);
- }
- }
+ InlineAsmOperand::Out { expr: None, .. } => {}
InlineAsmOperand::SplitInOut { in_expr, out_expr, .. } => {
vis.visit_expr(in_expr);
if let Some(out_expr) = out_expr {
@@ -1237,7 +1238,7 @@
vis.visit_ty(ty);
}
ExprKind::AddrOf(_, _, ohs) => vis.visit_expr(ohs),
- ExprKind::Let(pat, scrutinee) => {
+ ExprKind::Let(pat, scrutinee, _) => {
vis.visit_pat(pat);
vis.visit_expr(scrutinee);
}
@@ -1374,7 +1375,17 @@
) -> SmallVec<[Stmt; 1]> {
vis.visit_id(&mut id);
vis.visit_span(&mut span);
- noop_flat_map_stmt_kind(kind, vis).into_iter().map(|kind| Stmt { id, kind, span }).collect()
+ let stmts: SmallVec<_> = noop_flat_map_stmt_kind(kind, vis)
+ .into_iter()
+ .map(|kind| Stmt { id, kind, span })
+ .collect();
+ if stmts.len() > 1 {
+ panic!(
+ "cloning statement `NodeId`s is prohibited by default, \
+ the visitor should implement custom statement visiting"
+ );
+ }
+ stmts
}
pub fn noop_flat_map_stmt_kind<T: MutVisitor>(
diff --git a/compiler/rustc_ast/src/ptr.rs b/compiler/rustc_ast/src/ptr.rs
index e4a3ccc..9fe87a0 100644
--- a/compiler/rustc_ast/src/ptr.rs
+++ b/compiler/rustc_ast/src/ptr.rs
@@ -37,7 +37,7 @@
/// Construct a `P<T>` from a `T` value.
#[allow(non_snake_case)]
pub fn P<T: 'static>(value: T) -> P<T> {
- P { ptr: box value }
+ P { ptr: Box::new(value) }
}
impl<T: 'static> P<T> {
diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs
index 15f46ef..710a592 100644
--- a/compiler/rustc_ast/src/token.rs
+++ b/compiler/rustc_ast/src/token.rs
@@ -495,7 +495,7 @@
self.lifetime().is_some()
}
- /// Returns `true` if the token is a identifier whose name is the given
+ /// Returns `true` if the token is an identifier whose name is the given
/// string slice.
pub fn is_ident_named(&self, name: Symbol) -> bool {
self.ident().map_or(false, |(ident, _)| ident.name == name)
diff --git a/compiler/rustc_ast/src/util/classify.rs b/compiler/rustc_ast/src/util/classify.rs
index 9078652..6ea3db6 100644
--- a/compiler/rustc_ast/src/util/classify.rs
+++ b/compiler/rustc_ast/src/util/classify.rs
@@ -23,3 +23,30 @@
| ast::ExprKind::TryBlock(..)
)
}
+
+/// If an expression ends with `}`, returns the innermost expression ending in the `}`
+pub fn expr_trailing_brace(mut expr: &ast::Expr) -> Option<&ast::Expr> {
+ use ast::ExprKind::*;
+
+ loop {
+ match &expr.kind {
+ AddrOf(_, _, e)
+ | Assign(_, e, _)
+ | AssignOp(_, _, e)
+ | Binary(_, _, e)
+ | Box(e)
+ | Break(_, Some(e))
+ | Closure(.., e, _)
+ | Let(_, e, _)
+ | Range(_, Some(e), _)
+ | Ret(Some(e))
+ | Unary(_, e)
+ | Yield(Some(e)) => {
+ expr = e;
+ }
+ Async(..) | Block(..) | ForLoop(..) | If(..) | Loop(..) | Match(..) | Struct(..)
+ | TryBlock(..) | While(..) => break Some(expr),
+ _ => break None,
+ }
+ }
+}
diff --git a/compiler/rustc_ast/src/util/literal.rs b/compiler/rustc_ast/src/util/literal.rs
index 2124f1e..9c6ad47 100644
--- a/compiler/rustc_ast/src/util/literal.rs
+++ b/compiler/rustc_ast/src/util/literal.rs
@@ -63,7 +63,11 @@
unescape_literal(&s, Mode::Str, &mut |_, unescaped_char| {
match unescaped_char {
Ok(c) => buf.push(c),
- Err(_) => error = Err(LitError::LexerError),
+ Err(err) => {
+ if err.is_fatal() {
+ error = Err(LitError::LexerError);
+ }
+ }
}
});
error?;
@@ -83,7 +87,11 @@
unescape_literal(&s, Mode::RawStr, &mut |_, unescaped_char| {
match unescaped_char {
Ok(c) => buf.push(c),
- Err(_) => error = Err(LitError::LexerError),
+ Err(err) => {
+ if err.is_fatal() {
+ error = Err(LitError::LexerError);
+ }
+ }
}
});
error?;
@@ -100,7 +108,11 @@
unescape_byte_literal(&s, Mode::ByteStr, &mut |_, unescaped_byte| {
match unescaped_byte {
Ok(c) => buf.push(c),
- Err(_) => error = Err(LitError::LexerError),
+ Err(err) => {
+ if err.is_fatal() {
+ error = Err(LitError::LexerError);
+ }
+ }
}
});
error?;
@@ -114,7 +126,11 @@
unescape_byte_literal(&s, Mode::RawByteStr, &mut |_, unescaped_byte| {
match unescaped_byte {
Ok(c) => buf.push(c),
- Err(_) => error = Err(LitError::LexerError),
+ Err(err) => {
+ if err.is_fatal() {
+ error = Err(LitError::LexerError);
+ }
+ }
}
});
error?;
diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs
index 1ebfcf3..b380310 100644
--- a/compiler/rustc_ast/src/visit.rs
+++ b/compiler/rustc_ast/src/visit.rs
@@ -19,20 +19,20 @@
use rustc_span::symbol::{Ident, Symbol};
use rustc_span::Span;
-#[derive(Copy, Clone, PartialEq)]
+#[derive(Copy, Clone, Debug, PartialEq)]
pub enum AssocCtxt {
Trait,
Impl,
}
-#[derive(Copy, Clone, PartialEq)]
+#[derive(Copy, Clone, Debug, PartialEq)]
pub enum FnCtxt {
Free,
Foreign,
Assoc(AssocCtxt),
}
-#[derive(Copy, Clone)]
+#[derive(Copy, Clone, Debug)]
pub enum FnKind<'a> {
/// E.g., `fn foo()`, `fn foo(&self)`, or `extern "Abi" fn foo()`.
Fn(FnCtxt, Ident, &'a FnSig, &'a Visibility, Option<&'a Block>),
@@ -242,7 +242,10 @@
}
visitor.visit_pat(&local.pat);
walk_list!(visitor, visit_ty, &local.ty);
- walk_list!(visitor, visit_expr, &local.init);
+ if let Some((init, els)) = local.kind.init_else_opt() {
+ visitor.visit_expr(init);
+ walk_list!(visitor, visit_block, els);
+ }
}
pub fn walk_label<'a, V: Visitor<'a>>(visitor: &mut V, label: &'a Label) {
@@ -404,9 +407,6 @@
TyKind::Typeof(ref expression) => visitor.visit_anon_const(expression),
TyKind::Infer | TyKind::ImplicitSelf | TyKind::Err => {}
TyKind::MacCall(ref mac) => visitor.visit_mac_call(mac),
- TyKind::AnonymousStruct(ref fields, ..) | TyKind::AnonymousUnion(ref fields, ..) => {
- walk_list!(visitor, visit_field_def, fields)
- }
TyKind::Never | TyKind::CVarArgs => {}
}
}
@@ -714,13 +714,10 @@
for (op, _) in &asm.operands {
match op {
InlineAsmOperand::In { expr, .. }
+ | InlineAsmOperand::Out { expr: Some(expr), .. }
| InlineAsmOperand::InOut { expr, .. }
| InlineAsmOperand::Sym { expr, .. } => visitor.visit_expr(expr),
- InlineAsmOperand::Out { expr, .. } => {
- if let Some(expr) = expr {
- visitor.visit_expr(expr);
- }
- }
+ InlineAsmOperand::Out { expr: None, .. } => {}
InlineAsmOperand::SplitInOut { in_expr, out_expr, .. } => {
visitor.visit_expr(in_expr);
if let Some(out_expr) = out_expr {
@@ -779,9 +776,9 @@
visitor.visit_expr(subexpression);
visitor.visit_ty(typ)
}
- ExprKind::Let(ref pat, ref scrutinee) => {
+ ExprKind::Let(ref pat, ref expr, _) => {
visitor.visit_pat(pat);
- visitor.visit_expr(scrutinee);
+ visitor.visit_expr(expr);
}
ExprKind::If(ref head_expression, ref if_block, ref optional_else) => {
visitor.visit_expr(head_expression);
diff --git a/compiler/rustc_ast_lowering/Cargo.toml b/compiler/rustc_ast_lowering/Cargo.toml
index 0cced00..4e848a6 100644
--- a/compiler/rustc_ast_lowering/Cargo.toml
+++ b/compiler/rustc_ast_lowering/Cargo.toml
@@ -1,5 +1,4 @@
[package]
-authors = ["The Rust Project Developers"]
name = "rustc_ast_lowering"
version = "0.0.0"
edition = "2018"
diff --git a/compiler/rustc_ast_lowering/src/asm.rs b/compiler/rustc_ast_lowering/src/asm.rs
index 9ea09a2..7165b3b 100644
--- a/compiler/rustc_ast_lowering/src/asm.rs
+++ b/compiler/rustc_ast_lowering/src/asm.rs
@@ -27,11 +27,41 @@
.emit();
}
+ let mut clobber_abi = None;
+ if let Some(asm_arch) = asm_arch {
+ if let Some((abi_name, abi_span)) = asm.clobber_abi {
+ match asm::InlineAsmClobberAbi::parse(asm_arch, &self.sess.target, abi_name) {
+ Ok(abi) => clobber_abi = Some((abi, abi_span)),
+ Err(&[]) => {
+ self.sess
+ .struct_span_err(
+ abi_span,
+ "`clobber_abi` is not supported on this target",
+ )
+ .emit();
+ }
+ Err(supported_abis) => {
+ let mut err =
+ self.sess.struct_span_err(abi_span, "invalid ABI for `clobber_abi`");
+ let mut abis = format!("`{}`", supported_abis[0]);
+ for m in &supported_abis[1..] {
+ let _ = write!(abis, ", `{}`", m);
+ }
+ err.note(&format!(
+ "the following ABIs are supported on this target: {}",
+ abis
+ ));
+ err.emit();
+ }
+ }
+ }
+ }
+
// Lower operands to HIR. We use dummy register classes if an error
// occurs during lowering because we still need to be able to produce a
// valid HIR.
let sess = self.sess;
- let operands: Vec<_> = asm
+ let mut operands: Vec<_> = asm
.operands
.iter()
.map(|(op, op_sp)| {
@@ -98,7 +128,7 @@
hir::InlineAsmOperand::Sym { expr: self.lower_expr_mut(expr) }
}
};
- (op, *op_sp)
+ (op, self.lower_span(*op_sp))
})
.collect();
@@ -336,10 +366,41 @@
}
}
+ // If a clobber_abi is specified, add the necessary clobbers to the
+ // operands list.
+ if let Some((abi, abi_span)) = clobber_abi {
+ for &clobber in abi.clobbered_regs() {
+ let mut output_used = false;
+ clobber.overlapping_regs(|reg| {
+ if used_output_regs.contains_key(®) {
+ output_used = true;
+ }
+ });
+
+ if !output_used {
+ operands.push((
+ hir::InlineAsmOperand::Out {
+ reg: asm::InlineAsmRegOrRegClass::Reg(clobber),
+ late: true,
+ expr: None,
+ },
+ self.lower_span(abi_span),
+ ));
+ }
+ }
+ }
+
let operands = self.arena.alloc_from_iter(operands);
let template = self.arena.alloc_from_iter(asm.template.iter().cloned());
- let line_spans = self.arena.alloc_slice(&asm.line_spans[..]);
- let hir_asm = hir::InlineAsm { template, operands, options: asm.options, line_spans };
+ let template_strs = self.arena.alloc_from_iter(
+ asm.template_strs
+ .iter()
+ .map(|(sym, snippet, span)| (*sym, *snippet, self.lower_span(*span))),
+ );
+ let line_spans =
+ self.arena.alloc_from_iter(asm.line_spans.iter().map(|span| self.lower_span(*span)));
+ let hir_asm =
+ hir::InlineAsm { template, template_strs, operands, options: asm.options, line_spans };
self.arena.alloc(hir_asm)
}
}
diff --git a/compiler/rustc_ast_lowering/src/block.rs b/compiler/rustc_ast_lowering/src/block.rs
new file mode 100644
index 0000000..ca804ec
--- /dev/null
+++ b/compiler/rustc_ast_lowering/src/block.rs
@@ -0,0 +1,185 @@
+use crate::{ImplTraitContext, ImplTraitPosition, LoweringContext};
+use rustc_ast::{AttrVec, Block, BlockCheckMode, Expr, Local, LocalKind, Stmt, StmtKind};
+use rustc_hir as hir;
+use rustc_session::parse::feature_err;
+use rustc_span::symbol::Ident;
+use rustc_span::{sym, DesugaringKind};
+
+use smallvec::SmallVec;
+
+impl<'a, 'hir> LoweringContext<'a, 'hir> {
+ pub(super) fn lower_block(
+ &mut self,
+ b: &Block,
+ targeted_by_break: bool,
+ ) -> &'hir hir::Block<'hir> {
+ self.arena.alloc(self.lower_block_noalloc(b, targeted_by_break))
+ }
+
+ pub(super) fn lower_block_noalloc(
+ &mut self,
+ b: &Block,
+ targeted_by_break: bool,
+ ) -> hir::Block<'hir> {
+ let (stmts, expr) = self.lower_stmts(&b.stmts);
+ let rules = self.lower_block_check_mode(&b.rules);
+ let hir_id = self.lower_node_id(b.id);
+ hir::Block { hir_id, stmts, expr, rules, span: self.lower_span(b.span), targeted_by_break }
+ }
+
+ fn lower_stmts(
+ &mut self,
+ mut ast_stmts: &[Stmt],
+ ) -> (&'hir [hir::Stmt<'hir>], Option<&'hir hir::Expr<'hir>>) {
+ let mut stmts = SmallVec::<[hir::Stmt<'hir>; 8]>::new();
+ let mut expr = None;
+ while let [s, tail @ ..] = ast_stmts {
+ match s.kind {
+ StmtKind::Local(ref local) => {
+ let hir_id = self.lower_node_id(s.id);
+ match &local.kind {
+ LocalKind::InitElse(init, els) => {
+ let (s, e) = self.lower_let_else(hir_id, local, init, els, tail);
+ stmts.push(s);
+ expr = Some(e);
+ // remaining statements are in let-else expression
+ break;
+ }
+ _ => {
+ let local = self.lower_local(local);
+ self.alias_attrs(hir_id, local.hir_id);
+ let kind = hir::StmtKind::Local(local);
+ let span = self.lower_span(s.span);
+ stmts.push(hir::Stmt { hir_id, kind, span });
+ }
+ }
+ }
+ StmtKind::Item(ref it) => {
+ stmts.extend(self.lower_item_id(it).into_iter().enumerate().map(
+ |(i, item_id)| {
+ let hir_id = match i {
+ 0 => self.lower_node_id(s.id),
+ _ => self.next_id(),
+ };
+ let kind = hir::StmtKind::Item(item_id);
+ let span = self.lower_span(s.span);
+ hir::Stmt { hir_id, kind, span }
+ },
+ ));
+ }
+ StmtKind::Expr(ref e) => {
+ let e = self.lower_expr(e);
+ if tail.is_empty() {
+ expr = Some(e);
+ } else {
+ let hir_id = self.lower_node_id(s.id);
+ self.alias_attrs(hir_id, e.hir_id);
+ let kind = hir::StmtKind::Expr(e);
+ let span = self.lower_span(s.span);
+ stmts.push(hir::Stmt { hir_id, kind, span });
+ }
+ }
+ StmtKind::Semi(ref e) => {
+ let e = self.lower_expr(e);
+ let hir_id = self.lower_node_id(s.id);
+ self.alias_attrs(hir_id, e.hir_id);
+ let kind = hir::StmtKind::Semi(e);
+ let span = self.lower_span(s.span);
+ stmts.push(hir::Stmt { hir_id, kind, span });
+ }
+ StmtKind::Empty => {}
+ StmtKind::MacCall(..) => panic!("shouldn't exist here"),
+ }
+ ast_stmts = &ast_stmts[1..];
+ }
+ (self.arena.alloc_from_iter(stmts), expr)
+ }
+
+ fn lower_local(&mut self, l: &Local) -> &'hir hir::Local<'hir> {
+ let ty = l
+ .ty
+ .as_ref()
+ .map(|t| self.lower_ty(t, ImplTraitContext::Disallowed(ImplTraitPosition::Binding)));
+ let init = l.kind.init().map(|init| self.lower_expr(init));
+ let hir_id = self.lower_node_id(l.id);
+ let pat = self.lower_pat(&l.pat);
+ let span = self.lower_span(l.span);
+ let source = hir::LocalSource::Normal;
+ self.lower_attrs(hir_id, &l.attrs);
+ self.arena.alloc(hir::Local { hir_id, ty, pat, init, span, source })
+ }
+
+ fn lower_block_check_mode(&mut self, b: &BlockCheckMode) -> hir::BlockCheckMode {
+ match *b {
+ BlockCheckMode::Default => hir::BlockCheckMode::DefaultBlock,
+ BlockCheckMode::Unsafe(u) => {
+ hir::BlockCheckMode::UnsafeBlock(self.lower_unsafe_source(u))
+ }
+ }
+ }
+
+ fn lower_let_else(
+ &mut self,
+ stmt_hir_id: hir::HirId,
+ local: &Local,
+ init: &Expr,
+ els: &Block,
+ tail: &[Stmt],
+ ) -> (hir::Stmt<'hir>, &'hir hir::Expr<'hir>) {
+ let ty = local
+ .ty
+ .as_ref()
+ .map(|t| self.lower_ty(t, ImplTraitContext::Disallowed(ImplTraitPosition::Binding)));
+ let span = self.lower_span(local.span);
+ let span = self.mark_span_with_reason(DesugaringKind::LetElse, span, None);
+ let init = Some(self.lower_expr(init));
+ let val = Ident::with_dummy_span(sym::val);
+ let (pat, val_id) =
+ self.pat_ident_binding_mode(span, val, hir::BindingAnnotation::Unannotated);
+ let local_hir_id = self.lower_node_id(local.id);
+ self.lower_attrs(local_hir_id, &local.attrs);
+ // first statement which basically exists for the type annotation
+ let stmt = {
+ let local = self.arena.alloc(hir::Local {
+ hir_id: local_hir_id,
+ ty,
+ pat,
+ init,
+ span,
+ source: hir::LocalSource::Normal,
+ });
+ let kind = hir::StmtKind::Local(local);
+ hir::Stmt { hir_id: stmt_hir_id, kind, span }
+ };
+ let let_expr = {
+ let scrutinee = self.expr_ident(span, val, val_id);
+ let let_kind = hir::ExprKind::Let(self.lower_pat(&local.pat), scrutinee, span);
+ self.arena.alloc(self.expr(span, let_kind, AttrVec::new()))
+ };
+ let then_expr = {
+ let (stmts, expr) = self.lower_stmts(tail);
+ let block = self.block_all(span, stmts, expr);
+ self.arena.alloc(self.expr_block(block, AttrVec::new()))
+ };
+ let else_expr = {
+ let block = self.lower_block(els, false);
+ self.arena.alloc(self.expr_block(block, AttrVec::new()))
+ };
+ self.alias_attrs(else_expr.hir_id, local_hir_id);
+ let if_expr = self.arena.alloc(hir::Expr {
+ hir_id: self.next_id(),
+ span,
+ kind: hir::ExprKind::If(let_expr, then_expr, Some(else_expr)),
+ });
+ if !self.sess.features_untracked().let_else {
+ feature_err(
+ &self.sess.parse_sess,
+ sym::let_else,
+ local.span,
+ "`let...else` statements are unstable",
+ )
+ .emit();
+ }
+ (stmt, if_expr)
+ }
+}
diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs
index 7fecf53..80633e1 100644
--- a/compiler/rustc_ast_lowering/src/expr.rs
+++ b/compiler/rustc_ast_lowering/src/expr.rs
@@ -58,7 +58,12 @@
None,
));
let args = self.lower_exprs(args);
- hir::ExprKind::MethodCall(hir_seg, seg.ident.span, args, span)
+ hir::ExprKind::MethodCall(
+ hir_seg,
+ self.lower_span(seg.ident.span),
+ args,
+ self.lower_span(span),
+ )
}
ExprKind::Binary(binop, ref lhs, ref rhs) => {
let binop = self.lower_binop(binop);
@@ -71,7 +76,9 @@
let ohs = self.lower_expr(ohs);
hir::ExprKind::Unary(op, ohs)
}
- ExprKind::Lit(ref l) => hir::ExprKind::Lit(respan(l.span, l.kind.clone())),
+ ExprKind::Lit(ref l) => {
+ hir::ExprKind::Lit(respan(self.lower_span(l.span), l.kind.clone()))
+ }
ExprKind::Cast(ref expr, ref ty) => {
let expr = self.lower_expr(expr);
let ty = self.lower_ty(ty, ImplTraitContext::disallowed());
@@ -86,32 +93,14 @@
let ohs = self.lower_expr(ohs);
hir::ExprKind::AddrOf(k, m, ohs)
}
- ExprKind::Let(ref pat, ref scrutinee) => {
- self.lower_expr_let(e.span, pat, scrutinee)
+ ExprKind::Let(ref pat, ref scrutinee, span) => hir::ExprKind::Let(
+ self.lower_pat(pat),
+ self.lower_expr(scrutinee),
+ self.lower_span(span),
+ ),
+ ExprKind::If(ref cond, ref then, ref else_opt) => {
+ self.lower_expr_if(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())
- }
- ExprKind::Paren(ref paren) => match paren.peel_parens().kind {
- ExprKind::Let(ref pat, ref scrutinee) => {
- // A user has written `if (let Some(x) = foo) {`, we want to avoid
- // confusing them with mentions of nightly features.
- // If this logic is changed, you will also likely need to touch
- // `unused::UnusedParens::check_expr`.
- self.if_let_expr_with_parens(cond, &paren.peel_parens());
- self.lower_expr_if_let(
- e.span,
- pat,
- scrutinee,
- then,
- else_opt.as_deref(),
- )
- }
- _ => self.lower_expr_if(cond, 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)
@@ -119,7 +108,7 @@
ExprKind::Loop(ref body, opt_label) => self.with_loop_scope(e.id, |this| {
hir::ExprKind::Loop(
this.lower_block(body, false),
- opt_label,
+ this.lower_label(opt_label),
hir::LoopSource::Loop,
DUMMY_SP,
)
@@ -167,6 +156,7 @@
}
}
ExprKind::Block(ref blk, opt_label) => {
+ let opt_label = self.lower_label(opt_label);
hir::ExprKind::Block(self.lower_block(blk, opt_label.is_some()), opt_label)
}
ExprKind::Assign(ref el, ref er, span) => {
@@ -177,7 +167,9 @@
self.lower_expr(el),
self.lower_expr(er),
),
- ExprKind::Field(ref el, ident) => hir::ExprKind::Field(self.lower_expr(el), ident),
+ ExprKind::Field(ref el, ident) => {
+ hir::ExprKind::Field(self.lower_expr(el), self.lower_ident(ident))
+ }
ExprKind::Index(ref el, ref er) => {
hir::ExprKind::Index(self.lower_expr(el), self.lower_expr(er))
}
@@ -254,7 +246,7 @@
let mut ex = self.lower_expr_mut(ex);
// Include parens in span, but only if it is a super-span.
if e.span.contains(ex.span) {
- ex.span = e.span;
+ ex.span = self.lower_span(e.span);
}
// Merge attributes into the inner expression.
if !e.attrs.is_empty() {
@@ -282,7 +274,7 @@
let hir_id = self.lower_node_id(e.id);
self.lower_attrs(hir_id, &e.attrs);
- hir::Expr { hir_id, kind, span: e.span }
+ hir::Expr { hir_id, kind, span: self.lower_span(e.span) }
})
}
@@ -316,7 +308,7 @@
BinOpKind::Ge => hir::BinOpKind::Ge,
BinOpKind::Gt => hir::BinOpKind::Gt,
},
- span: b.span,
+ span: self.lower_span(b.span),
}
}
@@ -368,123 +360,51 @@
hir::ExprKind::Call(f, self.lower_exprs(&real_args))
}
- fn if_let_expr_with_parens(&mut self, cond: &Expr, paren: &Expr) {
- let start = cond.span.until(paren.span);
- let end = paren.span.shrink_to_hi().until(cond.span.shrink_to_hi());
- self.sess
- .struct_span_err(
- vec![start, end],
- "invalid parentheses around `let` expression in `if let`",
- )
- .multipart_suggestion(
- "`if let` needs to be written without parentheses",
- vec![(start, String::new()), (end, String::new())],
- rustc_errors::Applicability::MachineApplicable,
- )
- .emit();
- // Ideally, we'd remove the feature gating of a `let` expression since we are already
- // complaining about it here, but `feature_gate::check_crate` has already run by now:
- // self.sess.parse_sess.gated_spans.ungate_last(sym::let_chains, paren.span);
- }
-
- /// Emit an error and lower `ast::ExprKind::Let(pat, scrutinee)` into:
- /// ```rust
- /// match scrutinee { pats => true, _ => false }
- /// ```
- fn lower_expr_let(&mut self, span: Span, pat: &Pat, scrutinee: &Expr) -> hir::ExprKind<'hir> {
- // If we got here, the `let` expression is not allowed.
-
- if self.sess.opts.unstable_features.is_nightly_build() {
- self.sess
- .struct_span_err(span, "`let` expressions are not supported here")
- .note(
- "only supported directly without parentheses in conditions of `if`- and \
- `while`-expressions, as well as in `let` chains within parentheses",
- )
- .emit();
- } else {
- self.sess
- .struct_span_err(span, "expected expression, found statement (`let`)")
- .note("variable declaration using `let` is a statement")
- .emit();
- }
-
- // For better recovery, we emit:
- // ```
- // match scrutinee { pat => true, _ => false }
- // ```
- // While this doesn't fully match the user's intent, it has key advantages:
- // 1. We can avoid using `abort_if_errors`.
- // 2. We can typeck both `pat` and `scrutinee`.
- // 3. `pat` is allowed to be refutable.
- // 4. The return type of the block is `bool` which seems like what the user wanted.
- let scrutinee = self.lower_expr(scrutinee);
- let then_arm = {
- let pat = self.lower_pat(pat);
- let expr = self.expr_bool(span, true);
- self.arm(pat, expr)
- };
- let else_arm = {
- let pat = self.pat_wild(span);
- let expr = self.expr_bool(span, false);
- self.arm(pat, expr)
- };
- hir::ExprKind::Match(
- scrutinee,
- arena_vec![self; then_arm, else_arm],
- hir::MatchSource::Normal,
- )
- }
-
fn lower_expr_if(
&mut self,
cond: &Expr,
then: &Block,
else_opt: Option<&Expr>,
) -> hir::ExprKind<'hir> {
- macro_rules! make_if {
- ($opt:expr) => {{
- let cond = self.lower_expr(cond);
- let then_expr = self.lower_block_expr(then);
- hir::ExprKind::If(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`:
- let else_pat = self.pat_wild(span);
- let (else_expr, contains_else_clause) = match else_opt {
- None => (self.expr_block_empty(span.shrink_to_hi()), false),
- Some(els) => (self.lower_expr(els), true),
- };
- let else_arm = self.arm(else_pat, else_expr);
-
- // Handle then + scrutinee:
- let scrutinee = self.lower_expr(scrutinee);
- let then_pat = self.lower_pat(pat);
-
+ let lowered_cond = self.lower_expr(cond);
+ let new_cond = self.manage_let_cond(lowered_cond);
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)
+ if let Some(rslt) = else_opt {
+ hir::ExprKind::If(new_cond, self.arena.alloc(then_expr), Some(self.lower_expr(rslt)))
+ } else {
+ hir::ExprKind::If(new_cond, self.arena.alloc(then_expr), None)
+ }
}
+ // If `cond` kind is `let`, returns `let`. Otherwise, wraps and returns `cond`
+ // in a temporary block.
+ fn manage_let_cond(&mut self, cond: &'hir hir::Expr<'hir>) -> &'hir hir::Expr<'hir> {
+ match cond.kind {
+ hir::ExprKind::Let(..) => cond,
+ _ => {
+ let span_block =
+ self.mark_span_with_reason(DesugaringKind::CondTemporary, cond.span, None);
+ self.expr_drop_temps(span_block, cond, AttrVec::new())
+ }
+ }
+ }
+
+ // We desugar: `'label: while $cond $body` into:
+ //
+ // ```
+ // 'label: loop {
+ // if { let _t = $cond; _t } {
+ // $body
+ // }
+ // else {
+ // break;
+ // }
+ // }
+ // ```
+ //
+ // Wrap in a construct equivalent to `{ let _t = $cond; _t }`
+ // to preserve drop semantics since `while $cond { ... }` does not
+ // let temporaries live outside of `cond`.
fn lower_expr_while_in_loop_scope(
&mut self,
span: Span,
@@ -492,72 +412,17 @@
body: &Block,
opt_label: Option<Label>,
) -> hir::ExprKind<'hir> {
- // FIXME(#53667): handle lowering of && and parens.
-
- // Note that the block AND the condition are evaluated in the loop scope.
- // This is done to allow `break` from inside the condition of the loop.
-
- // `_ => break`:
- let else_arm = {
- let else_pat = self.pat_wild(span);
- let else_expr = self.expr_break(span, ThinVec::new());
- self.arm(else_pat, else_expr)
- };
-
- // Handle then + scrutinee:
- let (then_pat, scrutinee, desugar, source) = match cond.kind {
- ExprKind::Let(ref pat, ref scrutinee) => {
- // to:
- //
- // [opt_ident]: loop {
- // match <sub_expr> {
- // <pat> => <body>,
- // _ => break
- // }
- // }
- let scrutinee = self.with_loop_condition_scope(|t| t.lower_expr(scrutinee));
- let pat = self.lower_pat(pat);
- (pat, scrutinee, hir::MatchSource::WhileLetDesugar, hir::LoopSource::WhileLet)
- }
- _ => {
- // We desugar: `'label: while $cond $body` into:
- //
- // ```
- // 'label: loop {
- // match drop-temps { $cond } {
- // true => $body,
- // _ => break,
- // }
- // }
- // ```
-
- // Lower condition:
- let cond = self.with_loop_condition_scope(|this| this.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 `while cond { ... }` does not
- // let temporaries live outside of `cond`.
- let cond = self.expr_drop_temps(span_block, cond, ThinVec::new());
- // `true => <then>`:
- let pat = self.pat_bool(span, true);
- (pat, cond, hir::MatchSource::WhileDesugar, hir::LoopSource::While)
- }
- };
- let then_expr = self.lower_block_expr(body);
- let then_arm = self.arm(then_pat, self.arena.alloc(then_expr));
-
- // `match <scrutinee> { ... }`
- let match_expr =
- 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,
- span.with_hi(cond.span.hi()),
- )
+ let lowered_cond = self.with_loop_condition_scope(|t| t.lower_expr(cond));
+ let new_cond = self.manage_let_cond(lowered_cond);
+ let then = self.lower_block_expr(body);
+ let expr_break = self.expr_break(span, ThinVec::new());
+ let stmt_break = self.stmt_expr(span, expr_break);
+ let else_blk = self.block_all(span, arena_vec![self; stmt_break], None);
+ let else_expr = self.arena.alloc(self.expr_block(else_blk, ThinVec::new()));
+ let if_kind = hir::ExprKind::If(new_cond, self.arena.alloc(then), Some(else_expr));
+ let if_expr = self.expr(span, if_kind, ThinVec::new());
+ let block = self.block_expr(self.arena.alloc(if_expr));
+ hir::ExprKind::Loop(block, opt_label, hir::LoopSource::While, span.with_hi(cond.span.hi()))
}
/// Desugar `try { <stmts>; <expr> }` into `{ <stmts>; ::std::ops::Try::from_output(<expr>) }`,
@@ -617,7 +482,7 @@
fn lower_arm(&mut self, arm: &Arm) -> hir::Arm<'hir> {
let pat = self.lower_pat(&arm.pat);
let guard = arm.guard.as_ref().map(|cond| {
- if let ExprKind::Let(ref pat, ref scrutinee) = cond.kind {
+ if let ExprKind::Let(ref pat, ref scrutinee, _) = cond.kind {
hir::Guard::IfLet(self.lower_pat(pat), self.lower_expr(scrutinee))
} else {
hir::Guard::If(self.lower_expr(cond))
@@ -625,7 +490,13 @@
});
let hir_id = self.next_id();
self.lower_attrs(hir_id, &arm.attrs);
- hir::Arm { hir_id, pat, guard, body: self.lower_expr(&arm.body), span: arm.span }
+ hir::Arm {
+ hir_id,
+ pat,
+ guard,
+ body: self.lower_expr(&arm.body),
+ span: self.lower_span(arm.span),
+ }
}
/// Lower an `async` construct to a generator that is then wrapped so it implements `Future`.
@@ -648,12 +519,16 @@
) -> hir::ExprKind<'hir> {
let output = match ret_ty {
Some(ty) => hir::FnRetTy::Return(self.lower_ty(&ty, ImplTraitContext::disallowed())),
- None => hir::FnRetTy::DefaultReturn(span),
+ None => hir::FnRetTy::DefaultReturn(self.lower_span(span)),
};
// Resume argument type. We let the compiler infer this to simplify the lowering. It is
// fully constrained by `future::from_generator`.
- let input_ty = hir::Ty { hir_id: self.next_id(), kind: hir::TyKind::Infer, span };
+ let input_ty = hir::Ty {
+ hir_id: self.next_id(),
+ kind: hir::TyKind::Infer,
+ span: self.lower_span(span),
+ };
// The closure/generator `FnDecl` takes a single (resume) argument of type `input_ty`.
let decl = self.arena.alloc(hir::FnDecl {
@@ -669,7 +544,12 @@
Ident::with_dummy_span(sym::_task_context),
hir::BindingAnnotation::Mutable,
);
- let param = hir::Param { hir_id: self.next_id(), pat, ty_span: span, span };
+ let param = hir::Param {
+ hir_id: self.next_id(),
+ pat,
+ ty_span: self.lower_span(span),
+ span: self.lower_span(span),
+ };
let params = arena_vec![self; param];
let body_id = self.lower_body(move |this| {
@@ -687,11 +567,14 @@
capture_clause,
decl,
body_id,
- span,
+ self.lower_span(span),
Some(hir::Movability::Static),
);
- let generator =
- hir::Expr { hir_id: self.lower_node_id(closure_node_id), kind: generator_kind, span };
+ let generator = hir::Expr {
+ hir_id: self.lower_node_id(closure_node_id),
+ kind: generator_kind,
+ span: self.lower_span(span),
+ };
// `future::from_generator`:
let unstable_span =
@@ -828,8 +711,11 @@
if let Some(task_context_hid) = self.task_context {
let lhs = self.expr_ident(span, task_context_ident, task_context_hid);
- let assign =
- self.expr(span, hir::ExprKind::Assign(lhs, yield_expr, span), AttrVec::new());
+ let assign = self.expr(
+ span,
+ hir::ExprKind::Assign(lhs, yield_expr, self.lower_span(span)),
+ AttrVec::new(),
+ );
self.stmt_expr(span, assign)
} else {
// Use of `await` outside of an async context. Return `yield_expr` so that we can
@@ -843,8 +729,13 @@
// loop { .. }
let loop_expr = self.arena.alloc(hir::Expr {
hir_id: loop_hir_id,
- kind: hir::ExprKind::Loop(loop_block, None, hir::LoopSource::Loop, span),
- span,
+ kind: hir::ExprKind::Loop(
+ loop_block,
+ None,
+ hir::LoopSource::Loop,
+ self.lower_span(span),
+ ),
+ span: self.lower_span(span),
});
// mut pinned => loop { ... }
@@ -882,7 +773,13 @@
// 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)
+ hir::ExprKind::Closure(
+ capture_clause,
+ fn_decl,
+ body_id,
+ self.lower_span(fn_decl_span),
+ generator_option,
+ )
}
fn generator_movability_for_fn(
@@ -968,7 +865,13 @@
// 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)
+ hir::ExprKind::Closure(
+ capture_clause,
+ fn_decl,
+ body_id,
+ self.lower_span(fn_decl_span),
+ None,
+ )
}
/// Destructure the LHS of complex assignments.
@@ -1000,7 +903,11 @@
}
}
if is_ordinary(self, lhs) {
- return hir::ExprKind::Assign(self.lower_expr(lhs), self.lower_expr(rhs), eq_sign_span);
+ return hir::ExprKind::Assign(
+ self.lower_expr(lhs),
+ self.lower_expr(rhs),
+ self.lower_span(eq_sign_span),
+ );
}
if !self.sess.features_untracked().destructuring_assignment {
feature_err(
@@ -1025,7 +932,7 @@
whole_span,
Some(rhs),
pat,
- hir::LocalSource::AssignDesugar(eq_sign_span),
+ hir::LocalSource::AssignDesugar(self.lower_span(eq_sign_span)),
);
// `a = lhs1; b = lhs2;`.
@@ -1125,10 +1032,10 @@
let pat = self.destructure_assign(&f.expr, eq_sign_span, assignments);
hir::PatField {
hir_id: self.next_id(),
- ident: f.ident,
+ ident: self.lower_ident(f.ident),
pat,
is_shorthand: f.is_shorthand,
- span: f.span,
+ span: self.lower_span(f.span),
}
}));
let qpath = self.lower_qpath(
@@ -1180,10 +1087,11 @@
_ => {}
}
// Treat all other cases as normal lvalue.
- let ident = Ident::new(sym::lhs, lhs.span);
+ let ident = Ident::new(sym::lhs, self.lower_span(lhs.span));
let (pat, binding) = self.pat_ident_mut(lhs.span, ident);
let ident = self.expr_ident(lhs.span, ident, binding);
- let assign = hir::ExprKind::Assign(self.lower_expr(lhs), ident, eq_sign_span);
+ let assign =
+ hir::ExprKind::Assign(self.lower_expr(lhs), ident, self.lower_span(eq_sign_span));
let expr = self.expr(lhs.span, assign, ThinVec::new());
assignments.push(self.stmt_expr(lhs.span, expr));
pat
@@ -1223,7 +1131,7 @@
fn lower_expr_range_closed(&mut self, span: Span, e1: &Expr, e2: &Expr) -> hir::ExprKind<'hir> {
let e1 = self.lower_expr_mut(e1);
let e2 = self.lower_expr_mut(e2);
- let fn_path = hir::QPath::LangItem(hir::LangItem::RangeInclusiveNew, span);
+ let fn_path = hir::QPath::LangItem(hir::LangItem::RangeInclusiveNew, self.lower_span(span));
let fn_expr =
self.arena.alloc(self.expr(span, hir::ExprKind::Path(fn_path), ThinVec::new()));
hir::ExprKind::Call(fn_expr, arena_vec![self; e1, e2])
@@ -1251,12 +1159,21 @@
let fields = self.arena.alloc_from_iter(
e1.iter().map(|e| ("start", e)).chain(e2.iter().map(|e| ("end", e))).map(|(s, e)| {
let expr = self.lower_expr(&e);
- let ident = Ident::new(Symbol::intern(s), e.span);
+ let ident = Ident::new(Symbol::intern(s), self.lower_span(e.span));
self.expr_field(ident, expr, e.span)
}),
);
- hir::ExprKind::Struct(self.arena.alloc(hir::QPath::LangItem(lang_item, span)), fields, None)
+ hir::ExprKind::Struct(
+ self.arena.alloc(hir::QPath::LangItem(lang_item, self.lower_span(span))),
+ fields,
+ None,
+ )
+ }
+
+ fn lower_label(&self, opt_label: Option<Label>) -> Option<Label> {
+ let label = opt_label?;
+ Some(Label { ident: self.lower_ident(label.ident) })
}
fn lower_loop_destination(&mut self, destination: Option<(NodeId, Label)>) -> hir::Destination {
@@ -1275,7 +1192,8 @@
.map(|id| Ok(self.lower_node_id(id)))
.unwrap_or(Err(hir::LoopIdError::OutsideLoopScope)),
};
- hir::Destination { label: destination.map(|(_, label)| label), target_id }
+ let label = self.lower_label(destination.map(|(_, label)| label));
+ hir::Destination { label, target_id }
}
fn lower_jump_destination(&mut self, id: NodeId, opt_label: Option<Label>) -> hir::Destination {
@@ -1348,7 +1266,7 @@
constraint: out.constraint,
is_rw: out.is_rw,
is_indirect: out.is_indirect,
- span: out.expr.span,
+ span: self.lower_span(out.expr.span),
})
.collect(),
asm: asm.asm,
@@ -1373,9 +1291,9 @@
fn lower_expr_field(&mut self, f: &ExprField) -> hir::ExprField<'hir> {
hir::ExprField {
hir_id: self.next_id(),
- ident: f.ident,
+ ident: self.lower_ident(f.ident),
expr: self.lower_expr(&f.expr),
- span: f.span,
+ span: self.lower_span(f.span),
is_shorthand: f.is_shorthand,
}
}
@@ -1436,7 +1354,7 @@
orig_head_span,
None,
);
- head.span = desugared_span;
+ head.span = self.lower_span(desugared_span);
let iter = Ident::with_dummy_span(sym::iter);
@@ -1455,7 +1373,7 @@
let next_expr = self.expr_ident(pat.span, next_ident, next_pat_hid);
let assign = self.arena.alloc(self.expr(
pat.span,
- hir::ExprKind::Assign(next_expr, val_expr, pat.span),
+ hir::ExprKind::Assign(next_expr, val_expr, self.lower_span(pat.span)),
ThinVec::new(),
));
let some_pat = self.pat_some(pat.span, val_pat);
@@ -1465,7 +1383,7 @@
// `::std::option::Option::None => break`
let break_arm = {
let break_expr =
- self.with_loop_scope(e.id, |this| this.expr_break(e.span, ThinVec::new()));
+ self.with_loop_scope(e.id, |this| this.expr_break_alloc(e.span, ThinVec::new()));
let pat = self.pat_none(e.span);
self.arm(pat, break_expr)
};
@@ -1523,12 +1441,15 @@
// `[opt_ident]: loop { ... }`
let kind = hir::ExprKind::Loop(
loop_block,
- opt_label,
+ self.lower_label(opt_label),
hir::LoopSource::ForLoop,
- e.span.with_hi(orig_head_span.hi()),
+ self.lower_span(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, span: e.span });
+ let loop_expr = self.arena.alloc(hir::Expr {
+ hir_id: self.lower_node_id(e.id),
+ kind,
+ span: self.lower_span(e.span),
+ });
// `mut iter => { ... }`
let iter_arm = self.arm(iter_pat, loop_expr);
@@ -1607,8 +1528,8 @@
let attr = {
// `allow(unreachable_code)`
let allow = {
- let allow_ident = Ident::new(sym::allow, span);
- let uc_ident = Ident::new(sym::unreachable_code, span);
+ let allow_ident = Ident::new(sym::allow, self.lower_span(span));
+ let uc_ident = Ident::new(sym::unreachable_code, self.lower_span(span));
let uc_nested = attr::mk_nested_word_item(uc_ident);
attr::mk_list_item(allow_ident, vec![uc_nested])
};
@@ -1678,12 +1599,6 @@
// Helper methods for building HIR.
// =========================================================================
- /// Constructs a `true` or `false` literal expression.
- pub(super) fn expr_bool(&mut self, span: Span, val: bool) -> &'hir hir::Expr<'hir> {
- let lit = Spanned { span, node: LitKind::Bool(val) };
- self.arena.alloc(self.expr(span, hir::ExprKind::Lit(lit), ThinVec::new()))
- }
-
/// Wrap the given `expr` in a terminating scope using `hir::ExprKind::DropTemps`.
///
/// In terms of drop order, it has the same effect as wrapping `expr` in
@@ -1718,9 +1633,14 @@
self.expr(span, hir::ExprKind::Match(arg, arms, source), ThinVec::new())
}
- fn expr_break(&mut self, span: Span, attrs: AttrVec) -> &'hir hir::Expr<'hir> {
+ fn expr_break(&mut self, span: Span, attrs: AttrVec) -> hir::Expr<'hir> {
let expr_break = hir::ExprKind::Break(self.lower_loop_destination(None), None);
- self.arena.alloc(self.expr(span, expr_break, attrs))
+ self.expr(span, expr_break, attrs)
+ }
+
+ fn expr_break_alloc(&mut self, span: Span, attrs: AttrVec) -> &'hir hir::Expr<'hir> {
+ let expr_break = self.expr_break(span, attrs);
+ self.arena.alloc(expr_break)
}
fn expr_mut_addr_of(&mut self, span: Span, e: &'hir hir::Expr<'hir>) -> hir::Expr<'hir> {
@@ -1778,7 +1698,11 @@
lang_item: hir::LangItem,
attrs: AttrVec,
) -> hir::Expr<'hir> {
- self.expr(span, hir::ExprKind::Path(hir::QPath::LangItem(lang_item, span)), attrs)
+ self.expr(
+ span,
+ hir::ExprKind::Path(hir::QPath::LangItem(lang_item, self.lower_span(span))),
+ attrs,
+ )
}
pub(super) fn expr_ident(
@@ -1809,7 +1733,7 @@
let expr_path = hir::ExprKind::Path(hir::QPath::Resolved(
None,
self.arena.alloc(hir::Path {
- span,
+ span: self.lower_span(span),
res: Res::Local(binding),
segments: arena_vec![self; hir::PathSegment::from_ident(ident)],
}),
@@ -1829,7 +1753,7 @@
expr: Some(expr),
hir_id,
rules: hir::BlockCheckMode::UnsafeBlock(hir::UnsafeSource::CompilerGenerated),
- span,
+ span: self.lower_span(span),
targeted_by_break: false,
}),
None,
@@ -1860,7 +1784,7 @@
) -> hir::Expr<'hir> {
let hir_id = self.next_id();
self.lower_attrs(hir_id, &attrs);
- hir::Expr { hir_id, kind, span }
+ hir::Expr { hir_id, kind, span: self.lower_span(span) }
}
fn expr_field(
@@ -1869,10 +1793,22 @@
expr: &'hir hir::Expr<'hir>,
span: Span,
) -> hir::ExprField<'hir> {
- hir::ExprField { hir_id: self.next_id(), ident, span, expr, is_shorthand: false }
+ hir::ExprField {
+ hir_id: self.next_id(),
+ ident,
+ span: self.lower_span(span),
+ expr,
+ is_shorthand: false,
+ }
}
fn arm(&mut self, pat: &'hir hir::Pat<'hir>, expr: &'hir hir::Expr<'hir>) -> hir::Arm<'hir> {
- hir::Arm { hir_id: self.next_id(), pat, guard: None, span: expr.span, body: expr }
+ hir::Arm {
+ hir_id: self.next_id(),
+ pat,
+ guard: None,
+ span: self.lower_span(expr.span),
+ body: expr,
+ }
}
}
diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs
index 8806925..f8aedfd 100644
--- a/compiler/rustc_ast_lowering/src/item.rs
+++ b/compiler/rustc_ast_lowering/src/item.rs
@@ -26,44 +26,43 @@
}
impl ItemLowerer<'_, '_, '_> {
- fn with_trait_impl_ref(&mut self, impl_ref: &Option<TraitRef>, f: impl FnOnce(&mut Self)) {
+ fn with_trait_impl_ref<T>(
+ &mut self,
+ impl_ref: &Option<TraitRef>,
+ f: impl FnOnce(&mut Self) -> T,
+ ) -> T {
let old = self.lctx.is_in_trait_impl;
self.lctx.is_in_trait_impl = impl_ref.is_some();
- f(self);
+ let ret = f(self);
self.lctx.is_in_trait_impl = old;
+ ret
}
}
impl<'a> Visitor<'a> for ItemLowerer<'a, '_, '_> {
fn visit_item(&mut self, item: &'a Item) {
- let mut item_hir_id = None;
- self.lctx.with_hir_id_owner(item.id, |lctx| {
+ let hir_id = self.lctx.with_hir_id_owner(item.id, |lctx| {
lctx.without_in_scope_lifetime_defs(|lctx| {
- if let Some(hir_item) = lctx.lower_item(item) {
- let id = lctx.insert_item(hir_item);
- item_hir_id = Some(id);
- }
+ let hir_item = lctx.lower_item(item);
+ lctx.insert_item(hir_item)
})
});
- if let Some(hir_id) = item_hir_id {
- self.lctx.with_parent_item_lifetime_defs(hir_id, |this| {
- let this = &mut ItemLowerer { lctx: this };
- match item.kind {
- ItemKind::Mod(..) => {
- let def_id = this.lctx.lower_node_id(item.id).expect_owner();
- let old_current_module =
- mem::replace(&mut this.lctx.current_module, def_id);
- visit::walk_item(this, item);
- this.lctx.current_module = old_current_module;
- }
- ItemKind::Impl(box ImplKind { ref of_trait, .. }) => {
- this.with_trait_impl_ref(of_trait, |this| visit::walk_item(this, item));
- }
- _ => visit::walk_item(this, item),
+ self.lctx.with_parent_item_lifetime_defs(hir_id, |this| {
+ let this = &mut ItemLowerer { lctx: this };
+ match item.kind {
+ ItemKind::Mod(..) => {
+ let def_id = this.lctx.lower_node_id(item.id).expect_owner();
+ let old_current_module = mem::replace(&mut this.lctx.current_module, def_id);
+ visit::walk_item(this, item);
+ this.lctx.current_module = old_current_module;
}
- });
- }
+ ItemKind::Impl(box ImplKind { ref of_trait, .. }) => {
+ this.with_trait_impl_ref(of_trait, |this| visit::walk_item(this, item));
+ }
+ _ => visit::walk_item(this, item),
+ }
+ });
}
fn visit_fn(&mut self, fk: FnKind<'a>, sp: Span, _: NodeId) {
@@ -82,15 +81,11 @@
self.lctx.with_hir_id_owner(item.id, |lctx| match ctxt {
AssocCtxt::Trait => {
let hir_item = lctx.lower_trait_item(item);
- let id = hir_item.trait_item_id();
- lctx.trait_items.insert(id, hir_item);
- lctx.modules.entry(lctx.current_module).or_default().trait_items.insert(id);
+ lctx.insert_trait_item(hir_item);
}
AssocCtxt::Impl => {
let hir_item = lctx.lower_impl_item(item);
- let id = hir_item.impl_item_id();
- lctx.impl_items.insert(id, hir_item);
- lctx.modules.entry(lctx.current_module).or_default().impl_items.insert(id);
+ lctx.insert_impl_item(hir_item);
}
});
@@ -101,9 +96,7 @@
self.lctx.allocate_hir_id_counter(item.id);
self.lctx.with_hir_id_owner(item.id, |lctx| {
let hir_item = lctx.lower_foreign_item(item);
- let id = hir_item.foreign_item_id();
- lctx.foreign_items.insert(id, hir_item);
- lctx.modules.entry(lctx.current_module).or_default().foreign_items.insert(id);
+ lctx.insert_foreign_item(hir_item);
});
visit::walk_foreign_item(self, item);
@@ -119,11 +112,11 @@
fn with_parent_item_lifetime_defs<T>(
&mut self,
parent_hir_id: hir::ItemId,
- f: impl FnOnce(&mut LoweringContext<'_, '_>) -> T,
+ f: impl FnOnce(&mut Self) -> T,
) -> T {
let old_len = self.in_scope_lifetimes.len();
- let parent_generics = match self.items.get(&parent_hir_id).unwrap().kind {
+ let parent_generics = match self.owners[parent_hir_id.def_id].unwrap().expect_item().kind {
hir::ItemKind::Impl(hir::Impl { ref generics, .. })
| hir::ItemKind::Trait(_, _, ref generics, ..) => generics.params,
_ => &[],
@@ -143,10 +136,7 @@
// Clears (and restores) the `in_scope_lifetimes` field. Used when
// visiting nested items, which never inherit in-scope lifetimes
// from their surrounding environment.
- fn without_in_scope_lifetime_defs<T>(
- &mut self,
- f: impl FnOnce(&mut LoweringContext<'_, '_>) -> T,
- ) -> T {
+ fn without_in_scope_lifetime_defs<T>(&mut self, f: impl FnOnce(&mut Self) -> T) -> T {
let old_in_scope_lifetimes = mem::replace(&mut self.in_scope_lifetimes, vec![]);
// this vector is only used when walking over impl headers,
@@ -164,7 +154,7 @@
pub(super) fn lower_mod(&mut self, items: &[P<Item>], inner: Span) -> hir::Mod<'hir> {
hir::Mod {
- inner,
+ inner: self.lower_span(inner),
item_ids: self.arena.alloc_from_iter(items.iter().flat_map(|x| self.lower_item_id(x))),
}
}
@@ -176,7 +166,6 @@
self.lower_item_id_use_tree(use_tree, i.id, &mut vec);
vec
}
- ItemKind::MacroDef(..) => SmallVec::new(),
ItemKind::Fn(..) | ItemKind::Impl(box ImplKind { of_trait: None, .. }) => {
smallvec![i.id]
}
@@ -215,35 +204,19 @@
}
}
- pub fn lower_item(&mut self, i: &Item) -> Option<hir::Item<'hir>> {
+ pub fn lower_item(&mut self, i: &Item) -> hir::Item<'hir> {
let mut ident = i.ident;
let mut vis = self.lower_visibility(&i.vis, None);
-
- if let ItemKind::MacroDef(MacroDef { ref body, macro_rules }) = i.kind {
- if !macro_rules || self.sess.contains_name(&i.attrs, sym::macro_export) {
- let hir_id = self.lower_node_id(i.id);
- self.lower_attrs(hir_id, &i.attrs);
- let body = P(self.lower_mac_args(body));
- self.exported_macros.push(hir::MacroDef {
- ident,
- vis,
- def_id: hir_id.expect_owner(),
- span: i.span,
- ast: MacroDef { body, macro_rules },
- });
- } else {
- for a in i.attrs.iter() {
- let a = self.lower_attr(a);
- self.non_exported_macro_attrs.push(a);
- }
- }
- return None;
- }
-
let hir_id = self.lower_node_id(i.id);
let attrs = self.lower_attrs(hir_id, &i.attrs);
let kind = self.lower_item_kind(i.span, i.id, hir_id, &mut ident, attrs, &mut vis, &i.kind);
- Some(hir::Item { def_id: hir_id.expect_owner(), ident, kind, vis, span: i.span })
+ hir::Item {
+ def_id: hir_id.expect_owner(),
+ ident: self.lower_ident(ident),
+ kind,
+ vis,
+ span: self.lower_span(i.span),
+ }
}
fn lower_item_kind(
@@ -306,8 +279,8 @@
);
let sig = hir::FnSig {
decl,
- header: this.lower_fn_header(header, fn_sig_span, id),
- span: fn_sig_span,
+ header: this.lower_fn_header(header),
+ span: this.lower_span(fn_sig_span),
};
hir::ItemKind::Fn(sig, generics, body_id)
})
@@ -318,17 +291,12 @@
}
ModKind::Unloaded => panic!("`mod` items should have been loaded by now"),
},
- ItemKind::ForeignMod(ref fm) => {
- if fm.abi.is_none() {
- self.maybe_lint_missing_abi(span, id, abi::Abi::C { unwind: false });
- }
- hir::ItemKind::ForeignMod {
- abi: fm.abi.map_or(abi::Abi::C { unwind: false }, |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) => hir::ItemKind::ForeignMod {
+ abi: fm.abi.map_or(abi::Abi::FALLBACK, |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 asm) => {
hir::ItemKind::GlobalAsm(self.lower_inline_asm(span, asm))
}
@@ -410,15 +378,6 @@
this.lower_trait_ref(trait_ref, ImplTraitContext::disallowed())
});
- if let Some(ref trait_ref) = trait_ref {
- if let Res::Def(DefKind::Trait, def_id) = trait_ref.path.res {
- this.trait_impls
- .entry(def_id)
- .or_default()
- .push(lowered_trait_def_id);
- }
- }
-
let lowered_ty = this.lower_ty(ty, ImplTraitContext::disallowed());
(trait_ref, lowered_ty)
@@ -436,6 +395,10 @@
// 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);
+ let polarity = match polarity {
+ ImplPolarity::Positive => ImplPolarity::Positive,
+ ImplPolarity::Negative(s) => ImplPolarity::Negative(self.lower_span(s)),
+ };
hir::ItemKind::Impl(hir::Impl {
unsafety: self.lower_unsafety(unsafety),
polarity,
@@ -471,7 +434,12 @@
self.lower_generics(generics, ImplTraitContext::disallowed()),
self.lower_param_bounds(bounds, ImplTraitContext::disallowed()),
),
- ItemKind::MacroDef(..) | ItemKind::MacCall(..) => {
+ ItemKind::MacroDef(MacroDef { ref body, macro_rules }) => {
+ let body = P(self.lower_mac_args(body));
+
+ hir::ItemKind::Macro(ast::MacroDef { body, macro_rules })
+ }
+ ItemKind::MacCall(..) => {
panic!("`TyMac` should have been expanded by now")
}
}
@@ -549,10 +517,10 @@
this.insert_item(hir::Item {
def_id: new_id.expect_owner(),
- ident,
+ ident: this.lower_ident(ident),
kind,
vis,
- span,
+ span: this.lower_span(span),
});
});
}
@@ -623,10 +591,10 @@
this.insert_item(hir::Item {
def_id: new_hir_id.expect_owner(),
- ident,
+ ident: this.lower_ident(ident),
kind,
vis,
- span: use_tree.span,
+ span: this.lower_span(use_tree.span),
});
});
}
@@ -645,7 +613,10 @@
hir::VisibilityKind::Public
| hir::VisibilityKind::Crate(_)
| hir::VisibilityKind::Inherited => {
- *vis = respan(prefix.span.shrink_to_lo(), hir::VisibilityKind::Inherited);
+ *vis = respan(
+ self.lower_span(prefix.span.shrink_to_lo()),
+ hir::VisibilityKind::Inherited,
+ );
}
hir::VisibilityKind::Restricted { .. } => {
// Do nothing here, as described in the comment on the match.
@@ -688,7 +659,7 @@
}
}
};
- respan(vis.span, vis_kind)
+ respan(self.lower_span(vis.span), vis_kind)
}
fn lower_foreign_item(&mut self, i: &ForeignItem) -> hir::ForeignItem<'hir> {
@@ -697,7 +668,7 @@
self.lower_attrs(hir_id, &i.attrs);
hir::ForeignItem {
def_id,
- ident: i.ident,
+ ident: self.lower_ident(i.ident),
kind: match i.kind {
ForeignItemKind::Fn(box FnKind(_, ref sig, ref generics, _)) => {
let fdec = &sig.decl;
@@ -724,15 +695,15 @@
ForeignItemKind::MacCall(_) => panic!("macro shouldn't exist here"),
},
vis: self.lower_visibility(&i.vis, None),
- span: i.span,
+ span: self.lower_span(i.span),
}
}
fn lower_foreign_item_ref(&mut self, i: &ForeignItem) -> hir::ForeignItemRef<'hir> {
hir::ForeignItemRef {
id: hir::ForeignItemId { def_id: self.lower_node_id(i.id).expect_owner() },
- ident: i.ident,
- span: i.span,
+ ident: self.lower_ident(i.ident),
+ span: self.lower_span(i.span),
vis: self.lower_visibility(&i.vis, Some(i.id)),
}
}
@@ -744,8 +715,8 @@
id,
data: self.lower_variant_data(id, &v.data),
disr_expr: v.disr_expr.as_ref().map(|e| self.lower_anon_const(e)),
- ident: v.ident,
- span: v.span,
+ ident: self.lower_ident(v.ident),
+ span: self.lower_span(v.span),
}
}
@@ -778,10 +749,7 @@
}
}
- pub(super) fn lower_field_def(
- &mut self,
- (index, f): (usize, &FieldDef),
- ) -> hir::FieldDef<'hir> {
+ fn lower_field_def(&mut self, (index, f): (usize, &FieldDef)) -> hir::FieldDef<'hir> {
let ty = if let TyKind::Path(ref qself, ref path) = f.ty.kind {
let t = self.lower_path_ty(
&f.ty,
@@ -797,12 +765,12 @@
let hir_id = self.lower_node_id(f.id);
self.lower_attrs(hir_id, &f.attrs);
hir::FieldDef {
- span: f.span,
+ span: self.lower_span(f.span),
hir_id,
ident: match f.ident {
- Some(ident) => ident,
+ Some(ident) => self.lower_ident(ident),
// FIXME(jseyfried): positional field hygiene.
- None => Ident::new(sym::integer(index), f.span),
+ None => Ident::new(sym::integer(index), self.lower_span(f.span)),
},
vis: self.lower_visibility(&f.vis, None),
ty,
@@ -822,7 +790,7 @@
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, i.id);
+ self.lower_method_sig(generics, sig, trait_item_def_id, false, None);
(generics, hir::TraitItemKind::Fn(sig, hir::TraitFn::Required(names)))
}
AssocItemKind::Fn(box FnKind(_, ref sig, ref generics, Some(ref body))) => {
@@ -835,7 +803,6 @@
trait_item_def_id,
false,
asyncness.opt_return_id(),
- i.id,
);
(generics, hir::TraitItemKind::Fn(sig, hir::TraitFn::Provided(body_id)))
}
@@ -853,7 +820,13 @@
};
self.lower_attrs(hir_id, &i.attrs);
- hir::TraitItem { def_id: trait_item_def_id, ident: i.ident, generics, kind, span: i.span }
+ hir::TraitItem {
+ def_id: trait_item_def_id,
+ ident: self.lower_ident(i.ident),
+ generics,
+ kind,
+ span: self.lower_span(i.span),
+ }
}
fn lower_trait_item_ref(&mut self, i: &AssocItem) -> hir::TraitItemRef {
@@ -869,7 +842,13 @@
};
let id = hir::TraitItemId { def_id: self.lower_node_id(i.id).expect_owner() };
let defaultness = hir::Defaultness::Default { has_value: has_default };
- hir::TraitItemRef { id, ident: i.ident, span: i.span, defaultness, kind }
+ hir::TraitItemRef {
+ id,
+ ident: self.lower_ident(i.ident),
+ span: self.lower_span(i.span),
+ defaultness,
+ kind,
+ }
}
/// Construct `ExprKind::Err` for the given `span`.
@@ -900,7 +879,6 @@
impl_item_def_id,
impl_trait_return_allow,
asyncness.opt_return_id(),
- i.id,
);
(generics, hir::ImplItemKind::Fn(sig, body_id))
@@ -934,12 +912,12 @@
self.lower_attrs(hir_id, &i.attrs);
hir::ImplItem {
def_id: hir_id.expect_owner(),
- ident: i.ident,
+ ident: self.lower_ident(i.ident),
generics,
vis: self.lower_visibility(&i.vis, None),
defaultness,
kind,
- span: i.span,
+ span: self.lower_span(i.span),
}
}
@@ -949,8 +927,8 @@
let (defaultness, _) = self.lower_defaultness(i.kind.defaultness(), has_value);
hir::ImplItemRef {
id: hir::ImplItemId { def_id: self.lower_node_id(i.id).expect_owner() },
- ident: i.ident,
- span: i.span,
+ ident: self.lower_ident(i.ident),
+ span: self.lower_span(i.span),
vis: self.lower_visibility(&i.vis, Some(i.id)),
defaultness,
kind: match &i.kind {
@@ -993,7 +971,7 @@
}
VisibilityKind::Inherited => hir::VisibilityKind::Inherited,
};
- respan(v.span, node)
+ respan(self.lower_span(v.span), node)
}
fn lower_defaultness(
@@ -1002,7 +980,9 @@
has_value: bool,
) -> (hir::Defaultness, Option<Span>) {
match d {
- Defaultness::Default(sp) => (hir::Defaultness::Default { has_value }, Some(sp)),
+ Defaultness::Default(sp) => {
+ (hir::Defaultness::Default { has_value }, Some(self.lower_span(sp)))
+ }
Defaultness::Final => {
assert!(has_value);
(hir::Defaultness::Final, None)
@@ -1040,8 +1020,8 @@
hir::Param {
hir_id,
pat: self.lower_pat(¶m.pat),
- ty_span: param.ty.span,
- span: param.span,
+ ty_span: self.lower_span(param.ty.span),
+ span: self.lower_span(param.span),
}
}
@@ -1175,8 +1155,8 @@
let new_parameter = hir::Param {
hir_id: parameter.hir_id,
pat: new_parameter_pat,
- ty_span: parameter.ty_span,
- span: parameter.span,
+ ty_span: this.lower_span(parameter.ty_span),
+ span: this.lower_span(parameter.span),
};
if is_simple_parameter {
@@ -1293,9 +1273,8 @@
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, sig.span, id);
+ let header = self.lower_fn_header(sig.header);
let (generics, decl) = self.add_in_band_defs(
generics,
fn_def_id,
@@ -1309,15 +1288,15 @@
)
},
);
- (generics, hir::FnSig { header, decl, span: sig.span })
+ (generics, hir::FnSig { header, decl, span: self.lower_span(sig.span) })
}
- fn lower_fn_header(&mut self, h: FnHeader, span: Span, id: NodeId) -> hir::FnHeader {
+ fn lower_fn_header(&mut self, h: FnHeader) -> 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, span, id),
+ abi: self.lower_extern(h.ext),
}
}
@@ -1328,13 +1307,10 @@
})
}
- pub(super) fn lower_extern(&mut self, ext: Extern, span: Span, id: NodeId) -> abi::Abi {
+ pub(super) fn lower_extern(&mut self, ext: Extern) -> abi::Abi {
match ext {
Extern::None => abi::Abi::Rust,
- Extern::Implicit => {
- self.maybe_lint_missing_abi(span, id, abi::Abi::C { unwind: false });
- abi::Abi::C { unwind: false }
- }
+ Extern::Implicit => abi::Abi::FALLBACK,
Extern::Explicit(abi) => self.lower_abi(abi),
}
}
@@ -1409,7 +1385,7 @@
GenericsCtor {
params: self.lower_generic_params_mut(&generics.params, &add_bounds, itctx).collect(),
where_clause: self.lower_where_clause(&generics.where_clause),
- span: generics.span,
+ span: self.lower_span(generics.span),
}
}
@@ -1428,7 +1404,7 @@
predicates: this.arena.alloc_from_iter(
wc.predicates.iter().map(|predicate| this.lower_where_predicate(predicate)),
),
- span: wc.span,
+ span: this.lower_span(wc.span),
}
})
}
@@ -1449,17 +1425,20 @@
ImplTraitContext::disallowed(),
),
bounded_ty: this.lower_ty(bounded_ty, ImplTraitContext::disallowed()),
- bounds: this.arena.alloc_from_iter(bounds.iter().filter_map(|bound| {
- match *bound {
- // Ignore `?Trait` bounds.
- // They were copied into type parameters already.
- GenericBound::Trait(_, TraitBoundModifier::Maybe) => None,
- _ => Some(
- this.lower_param_bound(bound, ImplTraitContext::disallowed()),
- ),
- }
- })),
- span,
+ bounds: this.arena.alloc_from_iter(bounds.iter().map(
+ |bound| match bound {
+ // We used to ignore `?Trait` bounds, as they were copied into type
+ // parameters already, but we need to keep them around only for
+ // diagnostics when we suggest removal of `?Sized` bounds. See
+ // `suggest_constraining_type_param`. This will need to change if
+ // we ever allow something *other* than `?Sized`.
+ GenericBound::Trait(p, TraitBoundModifier::Maybe) => {
+ hir::GenericBound::Unsized(this.lower_span(p.span))
+ }
+ _ => this.lower_param_bound(bound, ImplTraitContext::disallowed()),
+ },
+ )),
+ span: this.lower_span(span),
})
})
}
@@ -1468,7 +1447,7 @@
ref bounds,
span,
}) => hir::WherePredicate::RegionPredicate(hir::WhereRegionPredicate {
- span,
+ span: self.lower_span(span),
lifetime: self.lower_lifetime(lifetime),
bounds: self.lower_param_bounds(bounds, ImplTraitContext::disallowed()),
}),
@@ -1477,7 +1456,7 @@
hir_id: self.lower_node_id(id),
lhs_ty: self.lower_ty(lhs_ty, ImplTraitContext::disallowed()),
rhs_ty: self.lower_ty(rhs_ty, ImplTraitContext::disallowed()),
- span,
+ span: self.lower_span(span),
})
}
}
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index d4caba9..41ae115 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -39,7 +39,6 @@
use rustc_ast::token::{self, Token};
use rustc_ast::tokenstream::{CanSynthesizeMissingTokens, TokenStream, TokenTree};
use rustc_ast::visit::{self, AssocCtxt, Visitor};
-use rustc_ast::walk_list;
use rustc_ast::{self as ast, *};
use rustc_ast_pretty::pprust;
use rustc_data_structures::captures::Captures;
@@ -48,12 +47,12 @@
use rustc_errors::{struct_span_err, Applicability};
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Namespace, PartialRes, PerNS, Res};
-use rustc_hir::def_id::{DefId, DefIdMap, DefPathHash, LocalDefId, CRATE_DEF_ID};
+use rustc_hir::def_id::{DefId, DefPathHash, LocalDefId, CRATE_DEF_ID};
use rustc_hir::definitions::{DefKey, DefPathData, Definitions};
use rustc_hir::intravisit;
-use rustc_hir::{ConstArg, GenericArg, ParamName};
+use rustc_hir::{ConstArg, GenericArg, InferKind, ParamName};
use rustc_index::vec::{Idx, IndexVec};
-use rustc_session::lint::builtin::{BARE_TRAIT_OBJECTS, MISSING_ABI};
+use rustc_session::lint::builtin::BARE_TRAIT_OBJECTS;
use rustc_session::lint::{BuiltinLintDiagnostics, LintBuffer};
use rustc_session::utils::{FlattenNonterminals, NtToTokenstream};
use rustc_session::Session;
@@ -62,9 +61,8 @@
use rustc_span::source_map::{respan, CachingSourceMapView, DesugaringKind};
use rustc_span::symbol::{kw, sym, Ident, Symbol};
use rustc_span::{Span, DUMMY_SP};
-use rustc_target::spec::abi::Abi;
-use smallvec::{smallvec, SmallVec};
+use smallvec::SmallVec;
use std::collections::BTreeMap;
use std::mem;
use tracing::{debug, trace};
@@ -77,6 +75,7 @@
}
mod asm;
+mod block;
mod expr;
mod item;
mod pat;
@@ -84,7 +83,7 @@
const HIR_ID_COUNTER_LOCKED: u32 = 0xFFFFFFFF;
-rustc_hir::arena_types!(rustc_arena::declare_arena, [], 'tcx);
+rustc_hir::arena_types!(rustc_arena::declare_arena, 'tcx);
struct LoweringContext<'a, 'hir: 'a> {
/// Used to assign IDs to HIR nodes that do not directly correspond to AST nodes.
@@ -101,16 +100,8 @@
arena: &'hir Arena<'hir>,
/// The items being lowered are collected here.
- items: BTreeMap<hir::ItemId, hir::Item<'hir>>,
-
- trait_items: BTreeMap<hir::TraitItemId, hir::TraitItem<'hir>>,
- impl_items: BTreeMap<hir::ImplItemId, hir::ImplItem<'hir>>,
- foreign_items: BTreeMap<hir::ForeignItemId, hir::ForeignItem<'hir>>,
+ owners: IndexVec<LocalDefId, Option<hir::OwnerNode<'hir>>>,
bodies: BTreeMap<hir::BodyId, hir::Body<'hir>>,
- exported_macros: Vec<hir::MacroDef<'hir>>,
- non_exported_macro_attrs: Vec<ast::Attribute>,
-
- trait_impls: BTreeMap<DefId, Vec<LocalDefId>>,
modules: BTreeMap<LocalDefId, hir::ModuleItems>,
@@ -164,8 +155,6 @@
current_module: LocalDefId,
- type_def_lifetime_params: DefIdMap<usize>,
-
current_hir_id_owner: (LocalDefId, u32),
item_local_id_counters: NodeMap<u32>,
node_id_to_hir_id: IndexVec<NodeId, Option<hir::HirId>>,
@@ -177,7 +166,7 @@
pub trait ResolverAstLowering {
fn def_key(&mut self, id: DefId) -> DefKey;
- fn item_generics_num_lifetimes(&self, def: DefId, sess: &Session) -> usize;
+ fn item_generics_num_lifetimes(&self, def: DefId) -> usize;
fn legacy_const_generic_args(&mut self, expr: &Expr) -> Option<Vec<usize>>;
@@ -330,23 +319,16 @@
resolver,
nt_to_tokenstream,
arena,
- items: BTreeMap::new(),
- trait_items: BTreeMap::new(),
- impl_items: BTreeMap::new(),
- foreign_items: BTreeMap::new(),
+ owners: IndexVec::default(),
bodies: BTreeMap::new(),
- trait_impls: BTreeMap::new(),
modules: BTreeMap::new(),
attrs: BTreeMap::default(),
- exported_macros: Vec::new(),
- non_exported_macro_attrs: Vec::new(),
catch_scopes: Vec::new(),
loop_scopes: Vec::new(),
is_in_loop_condition: false,
is_in_trait_impl: false,
is_in_dyn_type: false,
anonymous_lifetime_mode: AnonymousLifetimeMode::PassThrough,
- type_def_lifetime_params: Default::default(),
current_module: CRATE_DEF_ID,
current_hir_id_owner: (CRATE_DEF_ID, 0),
item_local_id_counters: Default::default(),
@@ -462,26 +444,8 @@
fn visit_item(&mut self, item: &'tcx Item) {
self.lctx.allocate_hir_id_counter(item.id);
- match item.kind {
- ItemKind::Struct(_, ref generics)
- | ItemKind::Union(_, ref generics)
- | ItemKind::Enum(_, 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 { .. })
- })
- .count();
- self.lctx.type_def_lifetime_params.insert(def_id.to_def_id(), count);
- }
- ItemKind::Use(ref use_tree) => {
- self.allocate_use_tree_hir_id_counters(use_tree);
- }
- _ => {}
+ if let ItemKind::Use(ref use_tree) = item.kind {
+ self.allocate_use_tree_hir_id_counters(use_tree);
}
visit::walk_item(self, item);
@@ -496,23 +460,6 @@
self.lctx.allocate_hir_id_counter(item.id);
visit::walk_foreign_item(self, item);
}
-
- fn visit_ty(&mut self, t: &'tcx Ty) {
- match t.kind {
- // Mirrors the case in visit::walk_ty
- TyKind::BareFn(ref f) => {
- walk_list!(self, visit_generic_param, &f.generic_params);
- // Mirrors visit::walk_fn_decl
- for parameter in &f.decl.inputs {
- // We don't lower the ids of argument patterns
- self.visit_pat(¶meter.pat);
- self.visit_ty(¶meter.ty)
- }
- self.visit_fn_ret_ty(&f.decl.output)
- }
- _ => visit::walk_ty(self, t),
- }
- }
}
self.lower_node_id(CRATE_NODE_ID);
@@ -521,11 +468,10 @@
visit::walk_crate(&mut MiscCollector { lctx: &mut self }, c);
visit::walk_crate(&mut item::ItemLowerer { lctx: &mut self }, c);
- let module = self.lower_mod(&c.items, c.span);
+ let module = self.arena.alloc(self.lower_mod(&c.items, c.span));
self.lower_attrs(hir::CRATE_HIR_ID, &c.attrs);
- let body_ids = body_ids(&self.bodies);
- let proc_macros =
- c.proc_macros.iter().map(|id| self.node_id_to_hir_id[*id].unwrap()).collect();
+ self.owners.ensure_contains_elem(CRATE_DEF_ID, || None);
+ self.owners[CRATE_DEF_ID] = Some(hir::OwnerNode::Crate(module));
let mut trait_map: FxHashMap<_, FxHashMap<_, _>> = FxHashMap::default();
for (k, v) in self.resolver.take_trait_map().into_iter() {
@@ -557,18 +503,9 @@
}
let krate = hir::Crate {
- item: module,
- exported_macros: self.arena.alloc_from_iter(self.exported_macros),
- non_exported_macro_attrs: self.arena.alloc_from_iter(self.non_exported_macro_attrs),
- items: self.items,
- trait_items: self.trait_items,
- impl_items: self.impl_items,
- foreign_items: self.foreign_items,
+ owners: self.owners,
bodies: self.bodies,
- body_ids,
- trait_impls: self.trait_impls,
modules: self.modules,
- proc_macros,
trait_map,
attrs: self.attrs,
};
@@ -576,12 +513,41 @@
}
fn insert_item(&mut self, item: hir::Item<'hir>) -> hir::ItemId {
- let id = hir::ItemId { def_id: item.def_id };
- self.items.insert(id, item);
+ let id = item.item_id();
+ let item = self.arena.alloc(item);
+ self.owners.ensure_contains_elem(id.def_id, || None);
+ self.owners[id.def_id] = Some(hir::OwnerNode::Item(item));
self.modules.entry(self.current_module).or_default().items.insert(id);
id
}
+ fn insert_foreign_item(&mut self, item: hir::ForeignItem<'hir>) -> hir::ForeignItemId {
+ let id = item.foreign_item_id();
+ let item = self.arena.alloc(item);
+ self.owners.ensure_contains_elem(id.def_id, || None);
+ self.owners[id.def_id] = Some(hir::OwnerNode::ForeignItem(item));
+ self.modules.entry(self.current_module).or_default().foreign_items.insert(id);
+ id
+ }
+
+ fn insert_impl_item(&mut self, item: hir::ImplItem<'hir>) -> hir::ImplItemId {
+ let id = item.impl_item_id();
+ let item = self.arena.alloc(item);
+ self.owners.ensure_contains_elem(id.def_id, || None);
+ self.owners[id.def_id] = Some(hir::OwnerNode::ImplItem(item));
+ self.modules.entry(self.current_module).or_default().impl_items.insert(id);
+ id
+ }
+
+ fn insert_trait_item(&mut self, item: hir::TraitItem<'hir>) -> hir::TraitItemId {
+ let id = item.trait_item_id();
+ let item = self.arena.alloc(item);
+ self.owners.ensure_contains_elem(id.def_id, || None);
+ self.owners[id.def_id] = Some(hir::OwnerNode::TraitItem(item));
+ self.modules.entry(self.current_module).or_default().trait_items.insert(id);
+ id
+ }
+
fn allocate_hir_id_counter(&mut self, owner: NodeId) -> hir::HirId {
// Set up the counter if needed.
self.item_local_id_counters.entry(owner).or_insert(0);
@@ -745,6 +711,16 @@
result
}
+ /// Intercept all spans entering HIR.
+ /// For now we are not doing anything with the intercepted spans.
+ fn lower_span(&self, span: Span) -> Span {
+ span
+ }
+
+ fn lower_ident(&self, ident: Ident) -> Ident {
+ Ident::new(ident.name, self.lower_span(ident.span))
+ }
+
/// Creates a new `hir::GenericParam` for every new lifetime and
/// type parameter encountered while evaluating `f`. Definitions
/// are created with the parent provided. If no `parent_id` is
@@ -813,7 +789,7 @@
hir_id: self.lower_node_id(node_id),
name: hir_name,
bounds: &[],
- span,
+ span: self.lower_span(span),
pure_wrt_drop: false,
kind: hir::GenericParamKind::Lifetime { kind },
}
@@ -974,7 +950,7 @@
AttrKind::DocComment(comment_kind, data) => AttrKind::DocComment(comment_kind, data),
};
- Attribute { kind, id: attr.id, style: attr.style, span: attr.span }
+ Attribute { kind, id: attr.id, style: attr.style, span: self.lower_span(attr.span) }
}
fn alias_attrs(&mut self, id: hir::HirId, target_id: hir::HirId) {
@@ -1102,7 +1078,7 @@
.0
}
};
- self.arena.alloc(gen_args_ctor.into_generic_args(&self.arena))
+ gen_args_ctor.into_generic_args(self)
} else {
self.arena.alloc(hir::GenericArgs::none())
};
@@ -1183,7 +1159,7 @@
&Ty {
id: node_id,
kind: TyKind::ImplTrait(impl_trait_node_id, bounds.clone()),
- span: constraint.span,
+ span: this.lower_span(constraint.span),
tokens: None,
},
itctx,
@@ -1203,10 +1179,10 @@
hir::TypeBinding {
hir_id: self.lower_node_id(constraint.id),
- ident: constraint.ident,
+ ident: self.lower_ident(constraint.ident),
gen_args,
kind,
- span: constraint.span,
+ span: self.lower_span(constraint.span),
}
}
@@ -1218,54 +1194,65 @@
match arg {
ast::GenericArg::Lifetime(lt) => GenericArg::Lifetime(self.lower_lifetime(<)),
ast::GenericArg::Type(ty) => {
- // We parse const arguments as path types as we cannot distinguish them during
- // parsing. We try to resolve that ambiguity by attempting resolution in both the
- // type and value namespaces. If we resolved the path in the value namespace, we
- // transform it into a generic const argument.
- if let TyKind::Path(ref qself, ref path) = ty.kind {
- if let Some(partial_res) = self.resolver.get_partial_res(ty.id) {
- let res = partial_res.base_res();
- if !res.matches_ns(Namespace::TypeNS) {
- debug!(
- "lower_generic_arg: Lowering type argument as const argument: {:?}",
- ty,
- );
+ match ty.kind {
+ TyKind::Infer if self.sess.features_untracked().generic_arg_infer => {
+ return GenericArg::Infer(hir::InferArg {
+ hir_id: self.lower_node_id(ty.id),
+ span: self.lower_span(ty.span),
+ kind: InferKind::Type,
+ });
+ }
+ // We parse const arguments as path types as we cannot distinguish them during
+ // parsing. We try to resolve that ambiguity by attempting resolution in both the
+ // type and value namespaces. If we resolved the path in the value namespace, we
+ // transform it into a generic const argument.
+ TyKind::Path(ref qself, ref path) => {
+ if let Some(partial_res) = self.resolver.get_partial_res(ty.id) {
+ let res = partial_res.base_res();
+ if !res.matches_ns(Namespace::TypeNS) {
+ debug!(
+ "lower_generic_arg: Lowering type argument as const argument: {:?}",
+ ty,
+ );
- // Construct a AnonConst where the expr is the "ty"'s path.
+ // Construct an AnonConst where the expr is the "ty"'s path.
- let parent_def_id = self.current_hir_id_owner.0;
- let node_id = self.resolver.next_node_id();
+ let parent_def_id = self.current_hir_id_owner.0;
+ let node_id = self.resolver.next_node_id();
- // Add a definition for the in-band const def.
- self.resolver.create_def(
- parent_def_id,
- node_id,
- DefPathData::AnonConst,
- ExpnId::root(),
- ty.span,
- );
+ // Add a definition for the in-band const def.
+ self.resolver.create_def(
+ parent_def_id,
+ node_id,
+ DefPathData::AnonConst,
+ ExpnId::root(),
+ ty.span,
+ );
- let path_expr = Expr {
- id: ty.id,
- kind: ExprKind::Path(qself.clone(), path.clone()),
- span: ty.span,
- attrs: AttrVec::new(),
- tokens: None,
- };
+ let span = self.lower_span(ty.span);
+ let path_expr = Expr {
+ id: ty.id,
+ kind: ExprKind::Path(qself.clone(), path.clone()),
+ span,
+ attrs: AttrVec::new(),
+ tokens: None,
+ };
- let ct = self.with_new_scopes(|this| hir::AnonConst {
- hir_id: this.lower_node_id(node_id),
- body: this.lower_const_body(path_expr.span, Some(&path_expr)),
- });
- return GenericArg::Const(ConstArg { value: ct, span: ty.span });
+ let ct = self.with_new_scopes(|this| hir::AnonConst {
+ hir_id: this.lower_node_id(node_id),
+ body: this.lower_const_body(path_expr.span, Some(&path_expr)),
+ });
+ return GenericArg::Const(ConstArg { value: ct, span });
+ }
}
}
+ _ => {}
}
GenericArg::Type(self.lower_ty_direct(&ty, itctx))
}
ast::GenericArg::Const(ct) => GenericArg::Const(ConstArg {
value: self.lower_anon_const(&ct),
- span: ct.value.span,
+ span: self.lower_span(ct.value.span),
}),
}
}
@@ -1292,7 +1279,7 @@
}
fn ty(&mut self, span: Span, kind: hir::TyKind<'hir>) -> hir::Ty<'hir> {
- hir::Ty { hir_id: self.next_id(), kind, span }
+ hir::Ty { hir_id: self.next_id(), kind, span: self.lower_span(span) }
}
fn ty_tup(&mut self, span: Span, tys: &'hir [hir::Ty<'hir>]) -> hir::Ty<'hir> {
@@ -1303,15 +1290,6 @@
let kind = match t.kind {
TyKind::Infer => hir::TyKind::Infer,
TyKind::Err => hir::TyKind::Err,
- // FIXME(unnamed_fields): IMPLEMENTATION IN PROGRESS
- TyKind::AnonymousStruct(ref _fields, _recovered) => {
- self.sess.struct_span_err(t.span, "anonymous structs are unimplemented").emit();
- hir::TyKind::Err
- }
- TyKind::AnonymousUnion(ref _fields, _recovered) => {
- self.sess.struct_span_err(t.span, "anonymous unions are unimplemented").emit();
- hir::TyKind::Err
- }
TyKind::Slice(ref ty) => hir::TyKind::Slice(self.lower_ty(ty, itctx)),
TyKind::Ptr(ref mt) => hir::TyKind::Ptr(self.lower_mt(mt, itctx)),
TyKind::Rptr(ref region, ref mt) => {
@@ -1324,7 +1302,6 @@
}
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,
@@ -1332,7 +1309,7 @@
ImplTraitContext::disallowed(),
),
unsafety: this.lower_unsafety(f.unsafety),
- abi: this.lower_extern(f.ext, span, t.id),
+ abi: this.lower_extern(f.ext),
decl: this.lower_fn_decl(&f.decl, None, false, None),
param_names: this.lower_fn_params_to_names(&f.decl),
}))
@@ -1360,7 +1337,7 @@
segments: arena_vec![self; hir::PathSegment::from_ident(
Ident::with_dummy_span(kw::SelfUpper)
)],
- span: t.span,
+ span: self.lower_span(t.span),
}),
))
}
@@ -1378,7 +1355,7 @@
ref ty,
TraitBoundModifier::None | TraitBoundModifier::MaybeConst,
) => Some(this.lower_poly_trait_ref(ty, itctx.reborrow())),
- // `?const ?Bound` will cause an error during AST validation
+ // `~const ?Bound` will cause an error during AST validation
// anyways, so treat it like `?Bound` as compilation proceeds.
GenericBound::Trait(
_,
@@ -1441,10 +1418,10 @@
let ident = Ident::from_str_and_span(&pprust::ty_to_string(t), span);
in_band_ty_params.push(hir::GenericParam {
hir_id: self.lower_node_id(def_node_id),
- name: ParamName::Plain(ident),
+ name: ParamName::Plain(self.lower_ident(ident)),
pure_wrt_drop: false,
bounds: hir_bounds,
- span,
+ span: self.lower_span(span),
kind: hir::GenericParamKind::Type {
default: None,
synthetic: Some(hir::SyntheticTyParamKind::ImplTrait),
@@ -1454,9 +1431,9 @@
hir::TyKind::Path(hir::QPath::Resolved(
None,
self.arena.alloc(hir::Path {
- span,
+ span: self.lower_span(span),
res: Res::Def(DefKind::TyParam, def_id.to_def_id()),
- segments: arena_vec![self; hir::PathSegment::from_ident(ident)],
+ segments: arena_vec![self; hir::PathSegment::from_ident(self.lower_ident(ident))],
}),
))
}
@@ -1483,7 +1460,7 @@
}
};
- hir::Ty { kind, span: t.span, hir_id: self.lower_node_id(t.id) }
+ hir::Ty { kind, span: self.lower_span(t.span), hir_id: self.lower_node_id(t.id) }
}
fn lower_opaque_impl_trait(
@@ -1528,8 +1505,8 @@
let opaque_ty_item = hir::OpaqueTy {
generics: hir::Generics {
params: lifetime_defs,
- where_clause: hir::WhereClause { predicates: &[], span },
- span,
+ where_clause: hir::WhereClause { predicates: &[], span: lctx.lower_span(span) },
+ span: lctx.lower_span(span),
},
bounds: hir_bounds,
impl_trait_fn: fn_def_id,
@@ -1560,8 +1537,8 @@
def_id: opaque_ty_id,
ident: Ident::invalid(),
kind: opaque_ty_item_kind,
- vis: respan(span.shrink_to_lo(), hir::VisibilityKind::Inherited),
- span: opaque_ty_span,
+ vis: respan(self.lower_span(span.shrink_to_lo()), hir::VisibilityKind::Inherited),
+ span: self.lower_span(opaque_ty_span),
};
// Insert the item into the global item list. This usually happens
@@ -1688,7 +1665,7 @@
self.output_lifetimes.push(hir::GenericArg::Lifetime(hir::Lifetime {
hir_id: self.context.next_id(),
- span: lifetime.span,
+ span: self.context.lower_span(lifetime.span),
name,
}));
@@ -1713,11 +1690,17 @@
}
_ => panic!("expected `LifetimeName::Param` or `ParamName::Plain`"),
};
+ let name = match name {
+ hir::ParamName::Plain(ident) => {
+ hir::ParamName::Plain(self.context.lower_ident(ident))
+ }
+ name => name,
+ };
self.output_lifetime_params.push(hir::GenericParam {
hir_id,
name,
- span: lifetime.span,
+ span: self.context.lower_span(lifetime.span),
pure_wrt_drop: false,
bounds: &[],
kind: hir::GenericParamKind::Lifetime { kind },
@@ -1751,24 +1734,6 @@
)
}
- fn lower_local(&mut self, l: &Local) -> hir::Local<'hir> {
- let ty = l
- .ty
- .as_ref()
- .map(|t| self.lower_ty(t, ImplTraitContext::Disallowed(ImplTraitPosition::Binding)));
- let init = l.init.as_ref().map(|e| self.lower_expr(e));
- let hir_id = self.lower_node_id(l.id);
- self.lower_attrs(hir_id, &l.attrs);
- hir::Local {
- hir_id,
- ty,
- pat: self.lower_pat(&l.pat),
- init,
- span: l.span,
- source: hir::LocalSource::Normal,
- }
- }
-
fn lower_fn_params_to_names(&mut self, decl: &FnDecl) -> &'hir [Ident] {
// Skip the `...` (`CVarArgs`) trailing arguments from the AST,
// as they are not explicit in HIR/Ty function signatures.
@@ -1778,8 +1743,8 @@
inputs = &inputs[..inputs.len() - 1];
}
self.arena.alloc_from_iter(inputs.iter().map(|param| match param.pat.kind {
- PatKind::Ident(_, ident, _) => ident,
- _ => Ident::new(kw::Empty, param.pat.span),
+ PatKind::Ident(_, ident, _) => self.lower_ident(ident),
+ _ => Ident::new(kw::Empty, self.lower_span(param.pat.span)),
}))
}
@@ -1863,7 +1828,7 @@
};
hir::FnRetTy::Return(self.lower_ty(ty, context))
}
- FnRetTy::Default(span) => hir::FnRetTy::DefaultReturn(span),
+ FnRetTy::Default(span) => hir::FnRetTy::DefaultReturn(self.lower_span(span)),
}
};
@@ -2020,8 +1985,8 @@
let opaque_ty_item = hir::OpaqueTy {
generics: hir::Generics {
params: generic_params,
- where_clause: hir::WhereClause { predicates: &[], span },
- span,
+ where_clause: hir::WhereClause { predicates: &[], span: this.lower_span(span) },
+ span: this.lower_span(span),
},
bounds: arena_vec![this; future_bound],
impl_trait_fn: Some(fn_def_id),
@@ -2056,7 +2021,7 @@
// Input lifetime like `'a` or `'1`:
GenericArg::Lifetime(hir::Lifetime {
hir_id: self.next_id(),
- span,
+ span: self.lower_span(span),
name: hir::LifetimeName::Param(hir_name),
})
},
@@ -2065,7 +2030,7 @@
// Output lifetime like `'_`.
GenericArg::Lifetime(hir::Lifetime {
hir_id: self.next_id(),
- span,
+ span: self.lower_span(span),
name: hir::LifetimeName::Implicit,
})));
let generic_args = self.arena.alloc_from_iter(generic_args);
@@ -2113,7 +2078,7 @@
hir::GenericBound::LangItemTrait(
// ::std::future::Future<future_params>
hir::LangItem::Future,
- span,
+ self.lower_span(span),
self.next_id(),
future_args,
)
@@ -2124,19 +2089,19 @@
tpb: &GenericBound,
itctx: ImplTraitContext<'_, 'hir>,
) -> hir::GenericBound<'hir> {
- match *tpb {
- GenericBound::Trait(ref ty, modifier) => hir::GenericBound::Trait(
- self.lower_poly_trait_ref(ty, itctx),
- self.lower_trait_bound_modifier(modifier),
+ match tpb {
+ GenericBound::Trait(p, modifier) => hir::GenericBound::Trait(
+ self.lower_poly_trait_ref(p, itctx),
+ self.lower_trait_bound_modifier(*modifier),
),
- GenericBound::Outlives(ref lifetime) => {
+ GenericBound::Outlives(lifetime) => {
hir::GenericBound::Outlives(self.lower_lifetime(lifetime))
}
}
}
fn lower_lifetime(&mut self, l: &Lifetime) -> hir::Lifetime {
- let span = l.ident.span;
+ let span = self.lower_span(l.ident.span);
match l.ident {
ident if ident.name == kw::StaticLifetime => {
self.new_named_lifetime(l.id, span, hir::LifetimeName::Static)
@@ -2155,7 +2120,7 @@
},
ident => {
self.maybe_collect_in_band_lifetime(ident);
- let param_name = ParamName::Plain(ident);
+ let param_name = ParamName::Plain(self.lower_ident(ident));
self.new_named_lifetime(l.id, span, hir::LifetimeName::Param(param_name))
}
}
@@ -2167,7 +2132,7 @@
span: Span,
name: hir::LifetimeName,
) -> hir::Lifetime {
- hir::Lifetime { hir_id: self.lower_node_id(id), span, name }
+ hir::Lifetime { hir_id: self.lower_node_id(id), span: self.lower_span(span), name }
}
fn lower_generic_params_mut<'s>(
@@ -2245,12 +2210,12 @@
synthetic: param
.attrs
.iter()
- .filter(|attr| self.sess.check_name(attr, sym::rustc_synthetic))
+ .filter(|attr| attr.has_name(sym::rustc_synthetic))
.map(|_| hir::SyntheticTyParamKind::FromAttr)
.next(),
};
- (hir::ParamName::Plain(param.ident), kind)
+ (hir::ParamName::Plain(self.lower_ident(param.ident)), kind)
}
GenericParamKind::Const { ref ty, kw_span: _, ref default } => {
let ty = self
@@ -2258,16 +2223,23 @@
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, default })
+ (
+ hir::ParamName::Plain(self.lower_ident(param.ident)),
+ hir::GenericParamKind::Const { ty, default },
+ )
}
};
+ let name = match name {
+ hir::ParamName::Plain(ident) => hir::ParamName::Plain(self.lower_ident(ident)),
+ name => name,
+ };
let hir_id = self.lower_node_id(param.id);
self.lower_attrs(hir_id, ¶m.attrs);
hir::GenericParam {
hir_id,
name,
- span: param.ident.span,
+ span: self.lower_span(param.ident.span),
pure_wrt_drop: self.sess.contains_name(¶m.attrs, sym::may_dangle),
bounds: self.arena.alloc_from_iter(bounds),
kind,
@@ -2324,7 +2296,7 @@
res
});
- hir::PolyTraitRef { bound_generic_params, trait_ref, span: p.span }
+ hir::PolyTraitRef { bound_generic_params, trait_ref, span: self.lower_span(p.span) }
}
fn lower_mt(&mut self, mt: &MutTy, itctx: ImplTraitContext<'_, 'hir>) -> hir::MutTy<'hir> {
@@ -2347,23 +2319,6 @@
bounds.iter().map(move |bound| self.lower_param_bound(bound, itctx.reborrow()))
}
- fn lower_block(&mut self, b: &Block, targeted_by_break: bool) -> &'hir hir::Block<'hir> {
- self.arena.alloc(self.lower_block_noalloc(b, targeted_by_break))
- }
-
- fn lower_block_noalloc(&mut self, b: &Block, targeted_by_break: bool) -> hir::Block<'hir> {
- let (stmts, expr) = match &*b.stmts {
- [stmts @ .., Stmt { kind: StmtKind::Expr(e), .. }] => (stmts, Some(&*e)),
- stmts => (stmts, None),
- };
- let stmts = self.arena.alloc_from_iter(stmts.iter().flat_map(|stmt| self.lower_stmt(stmt)));
- let expr = expr.map(|e| self.lower_expr(e));
- let rules = self.lower_block_check_mode(&b.rules);
- let hir_id = self.lower_node_id(b.id);
-
- hir::Block { hir_id, stmts, expr, rules, span: b.span, targeted_by_break }
- }
-
/// Lowers a block directly to an expression, presuming that it
/// has no attributes and is not targeted by a `break`.
fn lower_block_expr(&mut self, b: &Block) -> hir::Expr<'hir> {
@@ -2378,61 +2333,6 @@
})
}
- fn lower_stmt(&mut self, s: &Stmt) -> SmallVec<[hir::Stmt<'hir>; 1]> {
- let (hir_id, kind) = match s.kind {
- StmtKind::Local(ref l) => {
- let l = self.lower_local(l);
- let hir_id = self.lower_node_id(s.id);
- self.alias_attrs(hir_id, l.hir_id);
- return smallvec![hir::Stmt {
- hir_id,
- kind: hir::StmtKind::Local(self.arena.alloc(l)),
- span: s.span,
- }];
- }
- StmtKind::Item(ref it) => {
- // Can only use the ID once.
- let mut id = Some(s.id);
- return self
- .lower_item_id(it)
- .into_iter()
- .map(|item_id| {
- let hir_id = id
- .take()
- .map(|id| self.lower_node_id(id))
- .unwrap_or_else(|| self.next_id());
-
- hir::Stmt { hir_id, kind: hir::StmtKind::Item(item_id), span: s.span }
- })
- .collect();
- }
- StmtKind::Expr(ref e) => {
- let e = self.lower_expr(e);
- let hir_id = self.lower_node_id(s.id);
- self.alias_attrs(hir_id, e.hir_id);
- (hir_id, hir::StmtKind::Expr(e))
- }
- StmtKind::Semi(ref e) => {
- let e = self.lower_expr(e);
- let hir_id = self.lower_node_id(s.id);
- self.alias_attrs(hir_id, e.hir_id);
- (hir_id, hir::StmtKind::Semi(e))
- }
- StmtKind::Empty => return smallvec![],
- StmtKind::MacCall(..) => panic!("shouldn't exist here"),
- };
- smallvec![hir::Stmt { hir_id, kind, span: s.span }]
- }
-
- fn lower_block_check_mode(&mut self, b: &BlockCheckMode) -> hir::BlockCheckMode {
- match *b {
- BlockCheckMode::Default => hir::BlockCheckMode::DefaultBlock,
- BlockCheckMode::Unsafe(u) => {
- hir::BlockCheckMode::UnsafeBlock(self.lower_unsafe_source(u))
- }
- }
- }
-
fn lower_unsafe_source(&mut self, u: UnsafeSource) -> hir::UnsafeSource {
match u {
CompilerGenerated => hir::UnsafeSource::CompilerGenerated,
@@ -2456,7 +2356,7 @@
// Helper methods for building HIR.
fn stmt(&mut self, span: Span, kind: hir::StmtKind<'hir>) -> hir::Stmt<'hir> {
- hir::Stmt { span, kind, hir_id: self.next_id() }
+ hir::Stmt { span: self.lower_span(span), kind, hir_id: self.next_id() }
}
fn stmt_expr(&mut self, span: Span, expr: hir::Expr<'hir>) -> hir::Stmt<'hir> {
@@ -2476,7 +2376,7 @@
debug_assert!(!a.is_empty());
self.attrs.insert(hir_id, a);
}
- let local = hir::Local { hir_id, init, pat, source, span, ty: None };
+ let local = hir::Local { hir_id, init, pat, source, span: self.lower_span(span), ty: None };
self.stmt(span, hir::StmtKind::Local(self.arena.alloc(local)))
}
@@ -2495,18 +2395,12 @@
expr,
hir_id: self.next_id(),
rules: hir::BlockCheckMode::DefaultBlock,
- span,
+ span: self.lower_span(span),
targeted_by_break: false,
};
self.arena.alloc(blk)
}
- /// Constructs a `true` or `false` literal pattern.
- fn pat_bool(&mut self, span: Span, val: bool) -> &'hir hir::Pat<'hir> {
- let expr = self.expr_bool(span, val);
- self.pat(span, hir::PatKind::Lit(expr))
- }
-
fn pat_cf_continue(&mut self, span: Span, pat: &'hir hir::Pat<'hir>) -> &'hir hir::Pat<'hir> {
let field = self.single_pat_field(span, pat);
self.pat_lang_item_variant(span, hir::LangItem::ControlFlowContinue, field)
@@ -2533,10 +2427,10 @@
) -> &'hir [hir::PatField<'hir>] {
let field = hir::PatField {
hir_id: self.next_id(),
- ident: Ident::new(sym::integer(0), span),
+ ident: Ident::new(sym::integer(0), self.lower_span(span)),
is_shorthand: false,
pat,
- span,
+ span: self.lower_span(span),
};
arena_vec![self; field]
}
@@ -2547,7 +2441,7 @@
lang_item: hir::LangItem,
fields: &'hir [hir::PatField<'hir>],
) -> &'hir hir::Pat<'hir> {
- let qpath = hir::QPath::LangItem(lang_item, span);
+ let qpath = hir::QPath::LangItem(lang_item, self.lower_span(span));
self.pat(span, hir::PatKind::Struct(qpath, fields, false))
}
@@ -2580,29 +2474,30 @@
(
hir::Pat {
hir_id,
- kind: hir::PatKind::Binding(bm, hir_id, ident.with_span_pos(span), None),
- span,
+ kind: hir::PatKind::Binding(bm, hir_id, self.lower_ident(ident), None),
+ span: self.lower_span(span),
default_binding_modes: true,
},
hir_id,
)
}
- fn pat_wild(&mut self, span: Span) -> &'hir hir::Pat<'hir> {
- self.pat(span, hir::PatKind::Wild)
- }
-
fn pat(&mut self, span: Span, kind: hir::PatKind<'hir>) -> &'hir hir::Pat<'hir> {
self.arena.alloc(hir::Pat {
hir_id: self.next_id(),
kind,
- span,
+ span: self.lower_span(span),
default_binding_modes: true,
})
}
fn pat_without_dbm(&mut self, span: Span, kind: hir::PatKind<'hir>) -> hir::Pat<'hir> {
- hir::Pat { hir_id: self.next_id(), kind, span, default_binding_modes: false }
+ hir::Pat {
+ hir_id: self.next_id(),
+ kind,
+ span: self.lower_span(span),
+ default_binding_modes: false,
+ }
}
fn ty_path(
@@ -2619,7 +2514,7 @@
let principal = hir::PolyTraitRef {
bound_generic_params: &[],
trait_ref: hir::TraitRef { path, hir_ref_id: hir_id },
- span,
+ span: self.lower_span(span),
};
// The original ID is taken by the `PolyTraitRef`,
@@ -2637,7 +2532,7 @@
_ => hir::TyKind::Path(qpath),
};
- hir::Ty { hir_id, kind, span }
+ hir::Ty { hir_id, kind, span: self.lower_span(span) }
}
/// Invoked to create the lifetime argument for a type `&T`
@@ -2652,7 +2547,7 @@
let fresh_name = self.collect_fresh_in_band_lifetime(span);
hir::Lifetime {
hir_id: self.next_id(),
- span,
+ span: self.lower_span(span),
name: hir::LifetimeName::Param(fresh_name),
}
}
@@ -2664,7 +2559,7 @@
}
/// Report an error on illegal use of `'_` or a `&T` with no explicit lifetime;
- /// return a "error lifetime".
+ /// return an "error lifetime".
fn new_error_lifetime(&mut self, id: Option<NodeId>, span: Span) -> hir::Lifetime {
let (id, msg, label) = match id {
Some(id) => (id, "`'_` cannot be used here", "`'_` is a reserved lifetime name"),
@@ -2747,7 +2642,7 @@
let r = hir::Lifetime {
hir_id: self.next_id(),
- span,
+ span: self.lower_span(span),
name: hir::LifetimeName::ImplicitObjectLifetimeDefault,
};
debug!("elided_dyn_bound: r={:?}", r);
@@ -2755,7 +2650,11 @@
}
fn new_implicit_lifetime(&mut self, span: Span) -> hir::Lifetime {
- hir::Lifetime { hir_id: self.next_id(), span, name: hir::LifetimeName::Implicit }
+ hir::Lifetime {
+ hir_id: self.next_id(),
+ span: self.lower_span(span),
+ name: hir::LifetimeName::Implicit,
+ }
}
fn maybe_lint_bare_trait(&mut self, span: Span, id: NodeId, is_global: bool) {
@@ -2790,34 +2689,6 @@
}
}
}
-
- 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> {
- // Sorting by span ensures that we get things in order within a
- // file, and also puts the files in a sensible order.
- let mut body_ids: Vec<_> = bodies.keys().cloned().collect();
- body_ids.sort_by_key(|b| bodies[b].value.span);
- body_ids
}
/// Helper struct for delayed construction of GenericArgs.
@@ -2833,12 +2704,13 @@
self.args.is_empty() && self.bindings.is_empty() && !self.parenthesized
}
- fn into_generic_args(self, arena: &'hir Arena<'hir>) -> hir::GenericArgs<'hir> {
- hir::GenericArgs {
- args: arena.alloc_from_iter(self.args),
+ fn into_generic_args(self, this: &LoweringContext<'_, 'hir>) -> &'hir hir::GenericArgs<'hir> {
+ let ga = hir::GenericArgs {
+ args: this.arena.alloc_from_iter(self.args),
bindings: self.bindings,
parenthesized: self.parenthesized,
- span_ext: self.span,
- }
+ span_ext: this.lower_span(self.span),
+ };
+ this.arena.alloc(ga)
}
}
diff --git a/compiler/rustc_ast_lowering/src/pat.rs b/compiler/rustc_ast_lowering/src/pat.rs
index d81ddd2..0a9b264 100644
--- a/compiler/rustc_ast_lowering/src/pat.rs
+++ b/compiler/rustc_ast_lowering/src/pat.rs
@@ -62,10 +62,10 @@
let fs = self.arena.alloc_from_iter(fields.iter().map(|f| hir::PatField {
hir_id: self.next_id(),
- ident: f.ident,
+ ident: self.lower_ident(f.ident),
pat: self.lower_pat(&f.pat),
is_shorthand: f.is_shorthand,
- span: f.span,
+ span: self.lower_span(f.span),
}));
break hir::PatKind::Struct(qpath, fs, etc);
}
@@ -247,16 +247,16 @@
hir::PatKind::Binding(
self.lower_binding_mode(binding_mode),
self.lower_node_id(canonical_id),
- ident,
+ self.lower_ident(ident),
lower_sub(self),
)
}
Some(res) => hir::PatKind::Path(hir::QPath::Resolved(
None,
self.arena.alloc(hir::Path {
- span: ident.span,
+ span: self.lower_span(ident.span),
res: self.lower_res(res),
- segments: arena_vec![self; hir::PathSegment::from_ident(ident)],
+ segments: arena_vec![self; hir::PathSegment::from_ident(self.lower_ident(ident))],
}),
)),
}
@@ -280,7 +280,7 @@
hir::Pat {
hir_id: self.lower_node_id(p.id),
kind,
- span: p.span,
+ span: self.lower_span(p.span),
default_binding_modes: true,
}
}
diff --git a/compiler/rustc_ast_lowering/src/path.rs b/compiler/rustc_ast_lowering/src/path.rs
index 55173c6..90a22b5 100644
--- a/compiler/rustc_ast_lowering/src/path.rs
+++ b/compiler/rustc_ast_lowering/src/path.rs
@@ -90,15 +90,8 @@
_ => ParenthesizedGenericArgs::Err,
};
- let num_lifetimes = type_def_id.map_or(0, |def_id| {
- if let Some(&n) = self.type_def_lifetime_params.get(&def_id) {
- return n;
- }
- assert!(!def_id.is_local());
- let n = self.resolver.item_generics_num_lifetimes(def_id, self.sess);
- self.type_def_lifetime_params.insert(def_id, n);
- n
- });
+ let num_lifetimes = type_def_id
+ .map_or(0, |def_id| self.resolver.item_generics_num_lifetimes(def_id));
self.lower_path_segment(
p.span,
segment,
@@ -110,9 +103,11 @@
)
},
)),
- span: p.segments[..proj_start]
- .last()
- .map_or(path_span_lo, |segment| path_span_lo.to(segment.span())),
+ span: self.lower_span(
+ p.segments[..proj_start]
+ .last()
+ .map_or(path_span_lo, |segment| path_span_lo.to(segment.span())),
+ ),
});
// Simple case, either no projections, or only fully-qualified.
@@ -198,7 +193,7 @@
explicit_owner,
)
})),
- span: p.span,
+ span: self.lower_span(p.span),
})
}
@@ -370,14 +365,14 @@
);
hir::PathSegment {
- ident: segment.ident,
+ ident: self.lower_ident(segment.ident),
hir_id: Some(id),
res: Some(self.lower_res(res)),
infer_args,
args: if generic_args.is_empty() && generic_args.span.is_empty() {
None
} else {
- Some(self.arena.alloc(generic_args.into_generic_args(self.arena)))
+ Some(generic_args.into_generic_args(self))
},
}
}
@@ -459,6 +454,12 @@
parenthesized: false,
span_ext: DUMMY_SP,
});
- hir::TypeBinding { hir_id: self.next_id(), gen_args, span, ident, kind }
+ hir::TypeBinding {
+ hir_id: self.next_id(),
+ gen_args,
+ span: self.lower_span(span),
+ ident,
+ kind,
+ }
}
}
diff --git a/compiler/rustc_ast_passes/Cargo.toml b/compiler/rustc_ast_passes/Cargo.toml
index 9ed6bdc..4a6eb80 100644
--- a/compiler/rustc_ast_passes/Cargo.toml
+++ b/compiler/rustc_ast_passes/Cargo.toml
@@ -1,5 +1,4 @@
[package]
-authors = ["The Rust Project Developers"]
name = "rustc_ast_passes"
version = "0.0.0"
edition = "2018"
@@ -15,4 +14,5 @@
rustc_parse = { path = "../rustc_parse" }
rustc_session = { path = "../rustc_session" }
rustc_span = { path = "../rustc_span" }
+rustc_target = { path = "../rustc_target" }
rustc_ast = { path = "../rustc_ast" }
diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs
index acc41d9f..07f721d 100644
--- a/compiler/rustc_ast_passes/src/ast_validation.rs
+++ b/compiler/rustc_ast_passes/src/ast_validation.rs
@@ -15,11 +15,13 @@
use rustc_data_structures::fx::FxHashMap;
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::builtin::{MISSING_ABI, PATTERNS_IN_FNS_WITHOUT_BODY};
use rustc_session::lint::{BuiltinLintDiagnostics, LintBuffer};
use rustc_session::Session;
+use rustc_span::source_map::Spanned;
use rustc_span::symbol::{kw, sym, Ident};
use rustc_span::Span;
+use rustc_target::spec::abi;
use std::mem;
use std::ops::DerefMut;
@@ -32,24 +34,6 @@
No,
}
-/// A syntactic context that disallows certain kinds of bounds (e.g., `?Trait` or `?const Trait`).
-#[derive(Clone, Copy)]
-enum BoundContext {
- ImplTrait,
- TraitBounds,
- TraitObject,
-}
-
-impl BoundContext {
- fn description(&self) -> &'static str {
- match self {
- Self::ImplTrait => "`impl Trait`",
- Self::TraitBounds => "supertraits",
- Self::TraitObject => "trait objects",
- }
- }
-}
-
struct AstValidator<'a> {
session: &'a Session,
@@ -59,6 +43,8 @@
/// Are we inside a trait impl?
in_trait_impl: bool,
+ in_const_trait_impl: bool,
+
has_proc_macro_decls: bool,
/// Used to ban nested `impl Trait`, e.g., `impl Into<impl Debug>`.
@@ -66,11 +52,7 @@
/// e.g., `impl Iterator<Item = impl Debug>`.
outer_impl_trait: Option<Span>,
- /// Keeps track of the `BoundContext` as we recurse.
- ///
- /// This is used to forbid `?const Trait` bounds in, e.g.,
- /// `impl Iterator<Item = Box<dyn ?const Trait>`.
- bound_context: Option<BoundContext>,
+ is_tilde_const_allowed: bool,
/// Used to ban `impl Trait` in path projections like `<impl Iterator>::Item`
/// or `Foo::Bar<impl Trait>`
@@ -80,14 +62,25 @@
/// certain positions.
is_assoc_ty_bound_banned: bool,
+ /// Used to allow `let` expressions in certain syntactic locations.
+ is_let_allowed: bool,
+
lint_buffer: &'a mut LintBuffer,
}
impl<'a> AstValidator<'a> {
- fn with_in_trait_impl(&mut self, is_in: bool, f: impl FnOnce(&mut Self)) {
+ fn with_in_trait_impl(
+ &mut self,
+ is_in: bool,
+ constness: Option<Const>,
+ f: impl FnOnce(&mut Self),
+ ) {
let old = mem::replace(&mut self.in_trait_impl, is_in);
+ let old_const =
+ mem::replace(&mut self.in_const_trait_impl, matches!(constness, Some(Const::Yes(_))));
f(self);
self.in_trait_impl = old;
+ self.in_const_trait_impl = old_const;
}
fn with_banned_impl_trait(&mut self, f: impl FnOnce(&mut Self)) {
@@ -96,6 +89,39 @@
self.is_impl_trait_banned = old;
}
+ fn with_tilde_const_allowed(&mut self, f: impl FnOnce(&mut Self)) {
+ let old = mem::replace(&mut self.is_tilde_const_allowed, true);
+ f(self);
+ self.is_tilde_const_allowed = old;
+ }
+
+ fn with_banned_tilde_const(&mut self, f: impl FnOnce(&mut Self)) {
+ let old = mem::replace(&mut self.is_tilde_const_allowed, false);
+ f(self);
+ self.is_tilde_const_allowed = old;
+ }
+
+ fn with_let_allowed(&mut self, allowed: bool, f: impl FnOnce(&mut Self, bool)) {
+ let old = mem::replace(&mut self.is_let_allowed, allowed);
+ f(self, old);
+ self.is_let_allowed = old;
+ }
+
+ /// Emits an error banning the `let` expression provided in the given location.
+ fn ban_let_expr(&self, expr: &'a Expr) {
+ let sess = &self.session;
+ if sess.opts.unstable_features.is_nightly_build() {
+ sess.struct_span_err(expr.span, "`let` expressions are not supported here")
+ .note("only supported directly in conditions of `if`- and `while`-expressions")
+ .note("as well as when nested within `&&` and parenthesis in those conditions")
+ .emit();
+ } else {
+ sess.struct_span_err(expr.span, "expected expression, found statement (`let`)")
+ .note("variable declaration using `let` is a statement")
+ .emit();
+ }
+ }
+
fn with_banned_assoc_ty_bound(&mut self, f: impl FnOnce(&mut Self)) {
let old = mem::replace(&mut self.is_assoc_ty_bound_banned, true);
f(self);
@@ -105,19 +131,13 @@
fn with_impl_trait(&mut self, outer: Option<Span>, f: impl FnOnce(&mut Self)) {
let old = mem::replace(&mut self.outer_impl_trait, outer);
if outer.is_some() {
- self.with_bound_context(BoundContext::ImplTrait, |this| f(this));
+ self.with_banned_tilde_const(f);
} else {
- f(self)
+ f(self);
}
self.outer_impl_trait = old;
}
- fn with_bound_context(&mut self, ctx: BoundContext, f: impl FnOnce(&mut Self)) {
- let old = self.bound_context.replace(ctx);
- f(self);
- self.bound_context = old;
- }
-
fn visit_assoc_ty_constraint_from_generic_args(&mut self, constraint: &'a AssocTyConstraint) {
match constraint.kind {
AssocTyConstraintKind::Equality { .. } => {}
@@ -139,9 +159,7 @@
TyKind::ImplTrait(..) => {
self.with_impl_trait(Some(t.span), |this| visit::walk_ty(this, t))
}
- TyKind::TraitObject(..) => {
- self.with_bound_context(BoundContext::TraitObject, |this| visit::walk_ty(this, t));
- }
+ TyKind::TraitObject(..) => self.with_banned_tilde_const(|this| visit::walk_ty(this, t)),
TyKind::Path(ref qself, ref path) => {
// We allow these:
// - `Option<impl Trait>`
@@ -175,11 +193,6 @@
}
}
}
- TyKind::AnonymousStruct(ref fields, ..) | TyKind::AnonymousUnion(ref fields, ..) => {
- self.with_banned_assoc_ty_bound(|this| {
- walk_list!(this, visit_struct_field_def, fields)
- });
- }
_ => visit::walk_ty(self, t),
}
}
@@ -187,7 +200,6 @@
fn visit_struct_field_def(&mut self, field: &'a FieldDef) {
if let Some(ident) = field.ident {
if ident.name == kw::Underscore {
- self.check_anonymous_field(field);
self.visit_vis(&field.vis);
self.visit_ident(ident);
self.visit_ty_common(&field.ty);
@@ -233,66 +245,6 @@
err.emit();
}
- fn check_anonymous_field(&self, field: &FieldDef) {
- let FieldDef { ty, .. } = field;
- match &ty.kind {
- TyKind::AnonymousStruct(..) | TyKind::AnonymousUnion(..) => {
- // We already checked for `kw::Underscore` before calling this function,
- // so skip the check
- }
- TyKind::Path(..) => {
- // If the anonymous field contains a Path as type, we can't determine
- // if the path is a valid struct or union, so skip the check
- }
- _ => {
- let msg = "unnamed fields can only have struct or union types";
- let label = "not a struct or union";
- self.err_handler()
- .struct_span_err(field.span, msg)
- .span_label(ty.span, label)
- .emit();
- }
- }
- }
-
- fn deny_anonymous_struct(&self, ty: &Ty) {
- match &ty.kind {
- TyKind::AnonymousStruct(..) => {
- self.err_handler()
- .struct_span_err(
- ty.span,
- "anonymous structs are not allowed outside of unnamed struct or union fields",
- )
- .span_label(ty.span, "anonymous struct declared here")
- .emit();
- }
- TyKind::AnonymousUnion(..) => {
- self.err_handler()
- .struct_span_err(
- ty.span,
- "anonymous unions are not allowed outside of unnamed struct or union fields",
- )
- .span_label(ty.span, "anonymous union declared here")
- .emit();
- }
- _ => {}
- }
- }
-
- fn deny_anonymous_field(&self, field: &FieldDef) {
- if let Some(ident) = field.ident {
- if ident.name == kw::Underscore {
- self.err_handler()
- .struct_span_err(
- field.span,
- "anonymous fields are not allowed outside of structs or unions",
- )
- .span_label(ident.span, "anonymous field declared here")
- .emit()
- }
- }
- }
-
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 {
@@ -827,6 +779,10 @@
.emit();
});
self.check_late_bound_lifetime_defs(&bfty.generic_params);
+ if let Extern::Implicit = bfty.ext {
+ let sig_span = self.session.source_map().next_point(ty.span.shrink_to_lo());
+ self.maybe_lint_missing_abi(sig_span, ty.id);
+ }
}
TyKind::TraitObject(ref bounds, ..) => {
let mut any_lifetime_bounds = false;
@@ -877,6 +833,26 @@
_ => {}
}
}
+
+ fn maybe_lint_missing_abi(&mut self, span: Span, id: NodeId) {
+ // 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
+ .session
+ .source_map()
+ .span_to_snippet(span)
+ .map(|snippet| snippet.starts_with("#["))
+ .unwrap_or(true);
+ if !is_macro_callsite {
+ self.lint_buffer.buffer_lint_with_diagnostic(
+ MISSING_ABI,
+ id,
+ span,
+ "extern declarations without an explicit ABI are deprecated",
+ BuiltinLintDiagnostics::MissingAbi(span, abi::Abi::FALLBACK),
+ )
+ }
+ }
}
/// Checks that generic parameters are in the correct order,
@@ -978,25 +954,53 @@
}
fn visit_expr(&mut self, expr: &'a Expr) {
- match &expr.kind {
- ExprKind::LlvmInlineAsm(..) if !self.session.target.allow_asm => {
+ self.with_let_allowed(false, |this, let_allowed| match &expr.kind {
+ ExprKind::If(cond, then, opt_else) => {
+ this.visit_block(then);
+ walk_list!(this, visit_expr, opt_else);
+ this.with_let_allowed(true, |this, _| this.visit_expr(cond));
+ return;
+ }
+ ExprKind::Let(..) if !let_allowed => this.ban_let_expr(expr),
+ ExprKind::LlvmInlineAsm(..) if !this.session.target.allow_asm => {
struct_span_err!(
- self.session,
+ this.session,
expr.span,
E0472,
"llvm_asm! is unsupported on this target"
)
.emit();
}
- _ => {}
- }
-
- visit::walk_expr(self, expr);
+ ExprKind::Match(expr, arms) => {
+ this.visit_expr(expr);
+ for arm in arms {
+ this.visit_expr(&arm.body);
+ this.visit_pat(&arm.pat);
+ walk_list!(this, visit_attribute, &arm.attrs);
+ if let Some(ref guard) = arm.guard {
+ if let ExprKind::Let(_, ref expr, _) = guard.kind {
+ this.with_let_allowed(true, |this, _| this.visit_expr(expr));
+ return;
+ }
+ }
+ }
+ }
+ ExprKind::Paren(_) | ExprKind::Binary(Spanned { node: BinOpKind::And, .. }, ..) => {
+ this.with_let_allowed(let_allowed, |this, _| visit::walk_expr(this, expr));
+ return;
+ }
+ ExprKind::While(cond, then, opt_label) => {
+ walk_list!(this, visit_label, opt_label);
+ this.visit_block(then);
+ this.with_let_allowed(true, |this, _| this.visit_expr(cond));
+ return;
+ }
+ _ => visit::walk_expr(this, expr),
+ });
}
fn visit_ty(&mut self, ty: &'a Ty) {
self.visit_ty_common(ty);
- self.deny_anonymous_struct(ty);
self.walk_ty(ty)
}
@@ -1011,7 +1015,6 @@
}
fn visit_field_def(&mut self, s: &'a FieldDef) {
- self.deny_anonymous_field(s);
visit::walk_field_def(self, s)
}
@@ -1029,13 +1032,13 @@
unsafety,
polarity,
defaultness: _,
- constness: _,
- generics: _,
+ constness,
+ ref generics,
of_trait: Some(ref t),
ref self_ty,
- items: _,
+ ref items,
}) => {
- self.with_in_trait_impl(true, |this| {
+ self.with_in_trait_impl(true, Some(constness), |this| {
this.invalid_visibility(&item.vis, None);
if let TyKind::Err = self_ty.kind {
this.err_handler()
@@ -1058,7 +1061,17 @@
.emit();
}
- visit::walk_item(this, item);
+ this.visit_vis(&item.vis);
+ this.visit_ident(item.ident);
+ if let Const::Yes(_) = constness {
+ this.with_tilde_const_allowed(|this| this.visit_generics(generics));
+ } else {
+ this.visit_generics(generics);
+ }
+ this.visit_trait_ref(t);
+ this.visit_ty(self_ty);
+
+ walk_list!(this, visit_assoc_item, items, AssocCtxt::Impl);
});
return; // Avoid visiting again.
}
@@ -1103,15 +1116,26 @@
.emit();
}
}
- ItemKind::Fn(box FnKind(def, _, _, ref body)) => {
+ ItemKind::Fn(box FnKind(def, ref sig, ref generics, ref body)) => {
self.check_defaultness(item.span, def);
if body.is_none() {
let msg = "free function without a body";
self.error_item_without_body(item.span, "function", msg, " { <body> }");
}
+ self.visit_vis(&item.vis);
+ self.visit_ident(item.ident);
+ if let Const::Yes(_) = sig.header.constness {
+ self.with_tilde_const_allowed(|this| this.visit_generics(generics));
+ } else {
+ self.visit_generics(generics);
+ }
+ let kind = FnKind::Fn(FnCtxt::Free, item.ident, sig, &item.vis, body.as_deref());
+ self.visit_fn(kind, item.span, item.id);
+ walk_list!(self, visit_attribute, &item.attrs);
+ return; // Avoid visiting again.
}
- ItemKind::ForeignMod(ForeignMod { unsafety, .. }) => {
+ ItemKind::ForeignMod(ForeignMod { abi, unsafety, .. }) => {
let old_item = mem::replace(&mut self.extern_mod, Some(item));
self.invalid_visibility(
&item.vis,
@@ -1120,6 +1144,9 @@
if let Unsafe::Yes(span) = unsafety {
self.err_handler().span_err(span, "extern block cannot be declared unsafe");
}
+ if abi.is_none() {
+ self.maybe_lint_missing_abi(item.span, item.id);
+ }
visit::walk_item(self, item);
self.extern_mod = old_item;
return; // Avoid visiting again.
@@ -1152,9 +1179,7 @@
self.visit_vis(&item.vis);
self.visit_ident(item.ident);
self.visit_generics(generics);
- self.with_bound_context(BoundContext::TraitBounds, |this| {
- walk_list!(this, visit_param_bound, bounds);
- });
+ self.with_banned_tilde_const(|this| walk_list!(this, visit_param_bound, bounds));
walk_list!(self, visit_assoc_item, trait_items, AssocCtxt::Trait);
walk_list!(self, visit_attribute, &item.attrs);
return;
@@ -1227,7 +1252,7 @@
_ => {}
}
- visit::walk_item(self, item)
+ visit::walk_item(self, item);
}
fn visit_foreign_item(&mut self, fi: &'a ForeignItem) {
@@ -1286,7 +1311,7 @@
}
fn visit_generics(&mut self, generics: &'a Generics) {
- let cg_defaults = self.session.features_untracked().const_generics_defaults;
+ let cg_defaults = self.session.features_untracked().unordered_const_ty_params();
let mut prev_param_default = None;
for param in &generics.params {
@@ -1374,15 +1399,17 @@
fn visit_param_bound(&mut self, bound: &'a GenericBound) {
match bound {
GenericBound::Trait(_, TraitBoundModifier::MaybeConst) => {
- if let Some(ctx) = self.bound_context {
- let msg = format!("`?const` is not permitted in {}", ctx.description());
- self.err_handler().span_err(bound.span(), &msg);
+ if !self.is_tilde_const_allowed {
+ self.err_handler()
+ .struct_span_err(bound.span(), "`~const` is not allowed here")
+ .note("only allowed on bounds on traits' associated types and functions, const fns, const impls and its associated functions")
+ .emit();
}
}
GenericBound::Trait(_, TraitBoundModifier::MaybeConstMaybe) => {
self.err_handler()
- .span_err(bound.span(), "`?const` and `?` are mutually exclusive");
+ .span_err(bound.span(), "`~const` and `?` are mutually exclusive");
}
_ => {}
@@ -1459,6 +1486,17 @@
.emit();
}
+ if let FnKind::Fn(
+ _,
+ _,
+ FnSig { span: sig_span, header: FnHeader { ext: Extern::Implicit, .. }, .. },
+ _,
+ _,
+ ) = fk
+ {
+ self.maybe_lint_missing_abi(*sig_span, id);
+ }
+
// Functions without bodies cannot have patterns.
if let FnKind::Fn(ctxt, _, sig, _, None) = fk {
Self::check_decl_no_pat(&sig.decl, |span, ident, mut_ident| {
@@ -1499,6 +1537,10 @@
}
fn visit_assoc_item(&mut self, item: &'a AssocItem, ctxt: AssocCtxt) {
+ if self.session.contains_name(&item.attrs, sym::no_mangle) {
+ self.check_nomangle_item_asciionly(item.ident, item.span);
+ }
+
if ctxt == AssocCtxt::Trait || !self.in_trait_impl {
self.check_defaultness(item.span, item.kind.defaultness());
}
@@ -1531,7 +1573,32 @@
self.check_item_named(item.ident, "const");
}
- self.with_in_trait_impl(false, |this| visit::walk_assoc_item(this, item, ctxt));
+ match item.kind {
+ AssocItemKind::TyAlias(box TyAliasKind(_, ref generics, ref bounds, ref ty))
+ if ctxt == AssocCtxt::Trait =>
+ {
+ self.visit_vis(&item.vis);
+ self.visit_ident(item.ident);
+ walk_list!(self, visit_attribute, &item.attrs);
+ self.with_tilde_const_allowed(|this| {
+ this.visit_generics(generics);
+ walk_list!(this, visit_param_bound, bounds);
+ });
+ walk_list!(self, visit_ty, ty);
+ }
+ AssocItemKind::Fn(box FnKind(_, ref sig, ref generics, ref body))
+ if self.in_const_trait_impl || ctxt == AssocCtxt::Trait =>
+ {
+ self.visit_vis(&item.vis);
+ self.visit_ident(item.ident);
+ self.with_tilde_const_allowed(|this| this.visit_generics(generics));
+ let kind =
+ FnKind::Fn(FnCtxt::Assoc(ctxt), item.ident, sig, &item.vis, body.as_deref());
+ self.visit_fn(kind, item.span, item.id);
+ }
+ _ => self
+ .with_in_trait_impl(false, None, |this| visit::walk_assoc_item(this, item, ctxt)),
+ }
}
}
@@ -1625,11 +1692,13 @@
session,
extern_mod: None,
in_trait_impl: false,
+ in_const_trait_impl: false,
has_proc_macro_decls: false,
outer_impl_trait: None,
- bound_context: None,
+ is_tilde_const_allowed: false,
is_impl_trait_banned: false,
is_assoc_ty_bound_banned: false,
+ is_let_allowed: false,
lint_buffer: lints,
};
visit::walk_crate(&mut validator, krate);
diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs
index 3e757e3..038d31e 100644
--- a/compiler/rustc_ast_passes/src/feature_gate.rs
+++ b/compiler/rustc_ast_passes/src/feature_gate.rs
@@ -287,7 +287,7 @@
if let ast::TyKind::ImplTrait(..) = ty.kind {
gate_feature_post!(
&self.vis,
- min_type_alias_impl_trait,
+ type_alias_impl_trait,
ty.span,
"`impl Trait` in type aliases is unstable"
);
@@ -308,7 +308,7 @@
gate_feature_fn!(self, has_feature, attr.span, name, descr);
}
// Check unstable flavors of the `#[doc]` attribute.
- if self.sess.check_name(attr, sym::doc) {
+ if attr.has_name(sym::doc) {
for nested_meta in attr.meta_item_list().unwrap_or_default() {
macro_rules! gate_doc { ($($name:ident => $feature:ident)*) => {
$(if nested_meta.has_name(sym::$name) {
@@ -327,7 +327,7 @@
}
// Check for unstable modifiers on `#[link(..)]` attribute
- if self.sess.check_name(attr, sym::link) {
+ if attr.has_name(sym::link) {
for nested_meta in attr.meta_item_list().unwrap_or_default() {
if nested_meta.has_name(sym::modifiers) {
gate_feature_post!(
@@ -375,14 +375,6 @@
}
ast::ItemKind::Fn(..) => {
- if self.sess.contains_name(&i.attrs[..], sym::plugin_registrar) {
- gate_feature_post!(
- &self,
- plugin_registrar,
- i.span,
- "compiler plugins are experimental and possibly buggy"
- );
- }
if self.sess.contains_name(&i.attrs[..], sym::start) {
gate_feature_post!(
&self,
@@ -724,7 +716,6 @@
gate_all!(more_qualified_paths, "usage of qualified paths in this context is experimental");
gate_all!(generators, "yield syntax is experimental");
gate_all!(raw_ref_op, "raw address of syntax is experimental");
- gate_all!(const_trait_bound_opt_out, "`?const` on trait bounds is experimental");
gate_all!(const_trait_impl, "const trait impls are experimental");
gate_all!(half_open_range_patterns, "half-open range patterns are unstable");
gate_all!(inline_const, "inline-const is experimental");
@@ -737,7 +728,6 @@
// involved, so we only emit errors where there are no other parsing errors.
gate_all!(destructuring_assignment, "destructuring assignments are unstable");
}
- gate_all!(unnamed_fields, "unnamed fields are not yet fully implemented");
// All uses of `gate_all!` below this point were added in #65742,
// and subsequently disabled (with the non-early gating readded).
@@ -756,7 +746,6 @@
gate_all!(trait_alias, "trait aliases are experimental");
gate_all!(associated_type_bounds, "associated type bounds are unstable");
gate_all!(crate_visibility_modifier, "`crate` visibility modifier is experimental");
- gate_all!(const_generics, "const generics are unstable");
gate_all!(decl_macro, "`macro` is experimental");
gate_all!(box_patterns, "box pattern syntax is experimental");
gate_all!(exclusive_range_pattern, "exclusive range pattern syntax is experimental");
@@ -777,7 +766,7 @@
if !sess.opts.unstable_features.is_nightly_build() {
let lang_features = &sess.features_untracked().declared_lang_features;
- for attr in krate.attrs.iter().filter(|attr| sess.check_name(attr, sym::feature)) {
+ for attr in krate.attrs.iter().filter(|attr| attr.has_name(sym::feature)) {
let mut err = struct_span_err!(
sess.parse_sess.span_diagnostic,
attr.span,
diff --git a/compiler/rustc_ast_passes/src/lib.rs b/compiler/rustc_ast_passes/src/lib.rs
index 26da18b..6cde7d2 100644
--- a/compiler/rustc_ast_passes/src/lib.rs
+++ b/compiler/rustc_ast_passes/src/lib.rs
@@ -4,7 +4,7 @@
//!
//! The crate also contains other misc AST visitors, e.g. `node_count` and `show_span`.
-#![feature(bindings_after_at)]
+#![cfg_attr(bootstrap, feature(bindings_after_at))]
#![feature(iter_is_partitioned)]
#![feature(box_patterns)]
#![recursion_limit = "256"]
diff --git a/compiler/rustc_ast_pretty/Cargo.toml b/compiler/rustc_ast_pretty/Cargo.toml
index 6ea942a..fa88740 100644
--- a/compiler/rustc_ast_pretty/Cargo.toml
+++ b/compiler/rustc_ast_pretty/Cargo.toml
@@ -1,5 +1,4 @@
[package]
-authors = ["The Rust Project Developers"]
name = "rustc_ast_pretty"
version = "0.0.0"
edition = "2018"
diff --git a/compiler/rustc_ast_pretty/src/pprust/mod.rs b/compiler/rustc_ast_pretty/src/pprust/mod.rs
index 976725b..e74f38d 100644
--- a/compiler/rustc_ast_pretty/src/pprust/mod.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/mod.rs
@@ -8,17 +8,19 @@
use rustc_ast::token::{Nonterminal, Token, TokenKind};
use rustc_ast::tokenstream::{TokenStream, TokenTree};
+use std::borrow::Cow;
+
pub fn nonterminal_to_string(nt: &Nonterminal) -> String {
State::new().nonterminal_to_string(nt)
}
/// Print the token kind precisely, without converting `$crate` into its respective crate name.
-pub fn token_kind_to_string(tok: &TokenKind) -> String {
+pub fn token_kind_to_string(tok: &TokenKind) -> Cow<'static, str> {
State::new().token_kind_to_string(tok)
}
/// Print the token precisely, without converting `$crate` into its respective crate name.
-pub fn token_to_string(token: &Token) -> String {
+pub fn token_to_string(token: &Token) -> Cow<'static, str> {
State::new().token_to_string(token)
}
diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs
index 8b7b306..c248820 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state.rs
@@ -578,6 +578,33 @@
}
}
+ fn print_mac_def(
+ &mut self,
+ macro_def: &ast::MacroDef,
+ ident: &Ident,
+ sp: &Span,
+ print_visibility: impl FnOnce(&mut Self),
+ ) {
+ let (kw, has_bang) = if macro_def.macro_rules {
+ ("macro_rules", true)
+ } else {
+ print_visibility(self);
+ ("macro", false)
+ };
+ self.print_mac_common(
+ Some(MacHeader::Keyword(kw)),
+ has_bang,
+ Some(*ident),
+ macro_def.body.delim(),
+ ¯o_def.body.inner_tokens(),
+ true,
+ *sp,
+ );
+ if macro_def.body.need_semicolon() {
+ self.word(";");
+ }
+ }
+
fn print_path(&mut self, path: &ast::Path, colons_before_params: bool, depth: usize) {
self.maybe_print_comment(path.span.lo());
@@ -658,7 +685,7 @@
}
/// Print the token kind precisely, without converting `$crate` into its respective crate name.
- fn token_kind_to_string(&self, tok: &TokenKind) -> String {
+ fn token_kind_to_string(&self, tok: &TokenKind) -> Cow<'static, str> {
self.token_kind_to_string_ext(tok, None)
}
@@ -666,72 +693,72 @@
&self,
tok: &TokenKind,
convert_dollar_crate: Option<Span>,
- ) -> String {
+ ) -> Cow<'static, str> {
match *tok {
- token::Eq => "=".to_string(),
- token::Lt => "<".to_string(),
- token::Le => "<=".to_string(),
- token::EqEq => "==".to_string(),
- token::Ne => "!=".to_string(),
- token::Ge => ">=".to_string(),
- token::Gt => ">".to_string(),
- token::Not => "!".to_string(),
- token::Tilde => "~".to_string(),
- token::OrOr => "||".to_string(),
- token::AndAnd => "&&".to_string(),
- token::BinOp(op) => binop_to_string(op).to_string(),
- token::BinOpEq(op) => format!("{}=", binop_to_string(op)),
+ token::Eq => "=".into(),
+ token::Lt => "<".into(),
+ token::Le => "<=".into(),
+ token::EqEq => "==".into(),
+ token::Ne => "!=".into(),
+ token::Ge => ">=".into(),
+ token::Gt => ">".into(),
+ token::Not => "!".into(),
+ token::Tilde => "~".into(),
+ token::OrOr => "||".into(),
+ token::AndAnd => "&&".into(),
+ token::BinOp(op) => binop_to_string(op).into(),
+ token::BinOpEq(op) => format!("{}=", binop_to_string(op)).into(),
/* Structural symbols */
- token::At => "@".to_string(),
- token::Dot => ".".to_string(),
- token::DotDot => "..".to_string(),
- token::DotDotDot => "...".to_string(),
- token::DotDotEq => "..=".to_string(),
- token::Comma => ",".to_string(),
- token::Semi => ";".to_string(),
- token::Colon => ":".to_string(),
- token::ModSep => "::".to_string(),
- token::RArrow => "->".to_string(),
- token::LArrow => "<-".to_string(),
- token::FatArrow => "=>".to_string(),
- token::OpenDelim(token::Paren) => "(".to_string(),
- token::CloseDelim(token::Paren) => ")".to_string(),
- token::OpenDelim(token::Bracket) => "[".to_string(),
- token::CloseDelim(token::Bracket) => "]".to_string(),
- token::OpenDelim(token::Brace) => "{".to_string(),
- token::CloseDelim(token::Brace) => "}".to_string(),
- token::OpenDelim(token::NoDelim) | token::CloseDelim(token::NoDelim) => "".to_string(),
- token::Pound => "#".to_string(),
- token::Dollar => "$".to_string(),
- token::Question => "?".to_string(),
- token::SingleQuote => "'".to_string(),
+ token::At => "@".into(),
+ token::Dot => ".".into(),
+ token::DotDot => "..".into(),
+ token::DotDotDot => "...".into(),
+ token::DotDotEq => "..=".into(),
+ token::Comma => ",".into(),
+ token::Semi => ";".into(),
+ token::Colon => ":".into(),
+ token::ModSep => "::".into(),
+ token::RArrow => "->".into(),
+ token::LArrow => "<-".into(),
+ token::FatArrow => "=>".into(),
+ token::OpenDelim(token::Paren) => "(".into(),
+ token::CloseDelim(token::Paren) => ")".into(),
+ token::OpenDelim(token::Bracket) => "[".into(),
+ token::CloseDelim(token::Bracket) => "]".into(),
+ token::OpenDelim(token::Brace) => "{".into(),
+ token::CloseDelim(token::Brace) => "}".into(),
+ token::OpenDelim(token::NoDelim) | token::CloseDelim(token::NoDelim) => "".into(),
+ token::Pound => "#".into(),
+ token::Dollar => "$".into(),
+ token::Question => "?".into(),
+ token::SingleQuote => "'".into(),
/* Literals */
- token::Literal(lit) => literal_to_string(lit),
+ token::Literal(lit) => literal_to_string(lit).into(),
/* Name components */
token::Ident(s, is_raw) => {
- IdentPrinter::new(s, is_raw, convert_dollar_crate).to_string()
+ IdentPrinter::new(s, is_raw, convert_dollar_crate).to_string().into()
}
- token::Lifetime(s) => s.to_string(),
+ token::Lifetime(s) => s.to_string().into(),
/* Other */
token::DocComment(comment_kind, attr_style, data) => {
- doc_comment_to_string(comment_kind, attr_style, data)
+ doc_comment_to_string(comment_kind, attr_style, data).into()
}
- token::Eof => "<eof>".to_string(),
+ token::Eof => "<eof>".into(),
- token::Interpolated(ref nt) => self.nonterminal_to_string(nt),
+ token::Interpolated(ref nt) => self.nonterminal_to_string(nt).into(),
}
}
/// Print the token precisely, without converting `$crate` into its respective crate name.
- fn token_to_string(&self, token: &Token) -> String {
+ fn token_to_string(&self, token: &Token) -> Cow<'static, str> {
self.token_to_string_ext(token, false)
}
- fn token_to_string_ext(&self, token: &Token, convert_dollar_crate: bool) -> String {
+ fn token_to_string_ext(&self, token: &Token, convert_dollar_crate: bool) -> Cow<'static, str> {
let convert_dollar_crate = convert_dollar_crate.then_some(token.span);
self.token_kind_to_string_ext(&token.kind, convert_dollar_crate)
}
@@ -958,14 +985,6 @@
}
self.pclose();
}
- ast::TyKind::AnonymousStruct(ref fields, ..) => {
- self.head("struct");
- self.print_record_struct_body(&fields, ty.span);
- }
- ast::TyKind::AnonymousUnion(ref fields, ..) => {
- self.head("union");
- self.print_record_struct_body(&fields, ty.span);
- }
ast::TyKind::Paren(ref typ) => {
self.popen();
self.print_type(typ);
@@ -1305,24 +1324,9 @@
}
}
ast::ItemKind::MacroDef(ref macro_def) => {
- let (kw, has_bang) = if macro_def.macro_rules {
- ("macro_rules", true)
- } else {
- self.print_visibility(&item.vis);
- ("macro", false)
- };
- self.print_mac_common(
- Some(MacHeader::Keyword(kw)),
- has_bang,
- Some(item.ident),
- macro_def.body.delim(),
- ¯o_def.body.inner_tokens(),
- true,
- item.span,
- );
- if macro_def.body.need_semicolon() {
- self.word(";");
- }
+ self.print_mac_def(macro_def, &item.ident, &item.span, |state| {
+ state.print_visibility(&item.vis)
+ });
}
}
self.ann.post(self, AnnNode::Item(item))
@@ -1401,7 +1405,12 @@
}
}
- crate fn print_record_struct_body(&mut self, fields: &[ast::FieldDef], span: rustc_span::Span) {
+ crate fn print_record_struct_body(
+ &mut self,
+ fields: &Vec<ast::FieldDef>,
+ span: rustc_span::Span,
+ ) {
+ self.nbsp();
self.bopen();
self.hardbreak_if_not_bol();
@@ -1450,7 +1459,6 @@
}
ast::VariantData::Struct(ref fields, ..) => {
self.print_where_clause(&generics.where_clause);
- self.nbsp();
self.print_record_struct_body(fields, span);
}
}
@@ -1506,13 +1514,19 @@
self.ibox(INDENT_UNIT);
self.print_local_decl(loc);
self.end();
- if let Some(ref init) = loc.init {
+ if let Some((init, els)) = loc.kind.init_else_opt() {
self.nbsp();
self.word_space("=");
self.print_expr(init);
+ if let Some(els) = els {
+ self.cbox(INDENT_UNIT);
+ self.ibox(INDENT_UNIT);
+ self.s.word(" else ");
+ self.print_block(els);
+ }
}
self.s.word(";");
- self.end();
+ self.end(); // `let` ibox
}
ast::StmtKind::Item(ref item) => self.print_item(item),
ast::StmtKind::Expr(ref expr) => {
@@ -1587,19 +1601,14 @@
self.ann.post(self, AnnNode::Block(blk))
}
- /// Print a `let pat = scrutinee` expression.
- crate fn print_let(&mut self, pat: &ast::Pat, scrutinee: &ast::Expr) {
+ /// Print a `let pat = expr` expression.
+ crate fn print_let(&mut self, pat: &ast::Pat, expr: &ast::Expr) {
self.s.word("let ");
-
self.print_pat(pat);
self.s.space();
-
self.word_space("=");
- self.print_expr_cond_paren(
- scrutinee,
- Self::cond_needs_par(scrutinee)
- || parser::needs_par_as_let_scrutinee(scrutinee.precedence().order()),
- )
+ let npals = || parser::needs_par_as_let_scrutinee(expr.precedence().order());
+ self.print_expr_cond_paren(expr, Self::cond_needs_par(expr) || npals())
}
fn print_else(&mut self, els: Option<&ast::Expr>) {
@@ -1632,10 +1641,8 @@
crate fn print_if(&mut self, test: &ast::Expr, blk: &ast::Block, elseopt: Option<&ast::Expr>) {
self.head("if");
-
self.print_expr_as_cond(test);
self.s.space();
-
self.print_block(blk);
self.print_else(elseopt)
}
@@ -1668,13 +1675,13 @@
self.print_expr_cond_paren(expr, Self::cond_needs_par(expr))
}
- /// Does `expr` need parenthesis when printed in a condition position?
+ // Does `expr` need parenthesis when printed in a condition position?
+ //
+ // These cases need parens due to the parse error observed in #26461: `if return {}`
+ // parses as the erroneous construct `if (return {})`, not `if (return) {}`.
fn cond_needs_par(expr: &ast::Expr) -> bool {
match expr.kind {
- // These cases need parens due to the parse error observed in #26461: `if return {}`
- // parses as the erroneous construct `if (return {})`, not `if (return) {}`.
- ast::ExprKind::Closure(..) | ast::ExprKind::Ret(..) | ast::ExprKind::Break(..) => true,
-
+ ast::ExprKind::Break(..) | ast::ExprKind::Closure(..) | ast::ExprKind::Ret(..) => true,
_ => parser::contains_exterior_struct_lit(expr),
}
}
@@ -1919,7 +1926,7 @@
self.word_space(":");
self.print_type(ty);
}
- ast::ExprKind::Let(ref pat, ref scrutinee) => {
+ ast::ExprKind::Let(ref pat, ref scrutinee, _) => {
self.print_let(pat, scrutinee);
}
ast::ExprKind::If(ref test, ref blk, ref elseopt) => {
@@ -2186,12 +2193,15 @@
enum AsmArg<'a> {
Template(String),
Operand(&'a InlineAsmOperand),
+ ClobberAbi(Symbol),
Options(InlineAsmOptions),
}
- let mut args = vec![];
- args.push(AsmArg::Template(InlineAsmTemplatePiece::to_string(&asm.template)));
+ let mut args = vec![AsmArg::Template(InlineAsmTemplatePiece::to_string(&asm.template))];
args.extend(asm.operands.iter().map(|(o, _)| AsmArg::Operand(o)));
+ if let Some((abi, _)) = asm.clobber_abi {
+ args.push(AsmArg::ClobberAbi(abi));
+ }
if !asm.options.is_empty() {
args.push(AsmArg::Options(asm.options));
}
@@ -2258,6 +2268,12 @@
}
}
}
+ AsmArg::ClobberAbi(abi) => {
+ s.word("clobber_abi");
+ s.popen();
+ s.print_symbol(*abi, ast::StrStyle::Cooked);
+ s.pclose();
+ }
AsmArg::Options(opts) => {
s.word("options");
s.popen();
diff --git a/compiler/rustc_attr/Cargo.toml b/compiler/rustc_attr/Cargo.toml
index dc0711a..0566379 100644
--- a/compiler/rustc_attr/Cargo.toml
+++ b/compiler/rustc_attr/Cargo.toml
@@ -1,5 +1,4 @@
[package]
-authors = ["The Rust Project Developers"]
name = "rustc_attr"
version = "0.0.0"
edition = "2018"
diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs
index b7b053c..0ab452f 100644
--- a/compiler/rustc_attr/src/builtin.rs
+++ b/compiler/rustc_attr/src/builtin.rs
@@ -87,50 +87,6 @@
Size,
}
-#[derive(Copy, Clone, PartialEq)]
-pub enum UnwindAttr {
- Allowed,
- Aborts,
-}
-
-/// Determine what `#[unwind]` attribute is present in `attrs`, if any.
-pub fn find_unwind_attr(sess: &Session, attrs: &[Attribute]) -> Option<UnwindAttr> {
- attrs.iter().fold(None, |ia, attr| {
- if sess.check_name(attr, sym::unwind) {
- if let Some(meta) = attr.meta() {
- if let MetaItemKind::List(items) = meta.kind {
- if items.len() == 1 {
- if items[0].has_name(sym::allowed) {
- return Some(UnwindAttr::Allowed);
- } else if items[0].has_name(sym::aborts) {
- return Some(UnwindAttr::Aborts);
- }
- }
-
- struct_span_err!(
- sess.diagnostic(),
- attr.span,
- E0633,
- "malformed `unwind` attribute input"
- )
- .span_label(attr.span, "invalid argument")
- .span_suggestions(
- attr.span,
- "the allowed arguments are `allowed` and `aborts`",
- (vec!["allowed", "aborts"])
- .into_iter()
- .map(|s| format!("#[unwind({})]", s)),
- Applicability::MachineApplicable,
- )
- .emit();
- }
- }
- }
-
- ia
- })
-}
-
/// Represents the following attributes:
///
/// - `#[stable]`
@@ -210,8 +166,6 @@
continue; // not a stability level
}
- sess.mark_attr_used(attr);
-
let meta = attr.meta();
if attr.has_name(sym::rustc_promotable) {
@@ -680,8 +634,7 @@
let diagnostic = &sess.parse_sess.span_diagnostic;
'outer: for attr in attrs_iter {
- if !(sess.check_name(attr, sym::deprecated) || sess.check_name(attr, sym::rustc_deprecated))
- {
+ if !(attr.has_name(sym::deprecated) || attr.has_name(sym::rustc_deprecated)) {
continue;
}
@@ -744,17 +697,17 @@
continue 'outer;
}
}
- sym::note if sess.check_name(attr, sym::deprecated) => {
+ sym::note if attr.has_name(sym::deprecated) => {
if !get(mi, &mut note) {
continue 'outer;
}
}
- sym::reason if sess.check_name(attr, sym::rustc_deprecated) => {
+ sym::reason if attr.has_name(sym::rustc_deprecated) => {
if !get(mi, &mut note) {
continue 'outer;
}
}
- sym::suggestion if sess.check_name(attr, sym::rustc_deprecated) => {
+ sym::suggestion if attr.has_name(sym::rustc_deprecated) => {
if !get(mi, &mut suggestion) {
continue 'outer;
}
@@ -765,7 +718,7 @@
meta.span(),
AttrError::UnknownMetaItem(
pprust::path_to_string(&mi.path),
- if sess.check_name(attr, sym::deprecated) {
+ if attr.has_name(sym::deprecated) {
&["since", "note"]
} else {
&["since", "reason", "suggestion"]
@@ -791,11 +744,11 @@
}
}
- if suggestion.is_some() && sess.check_name(attr, sym::deprecated) {
+ if suggestion.is_some() && attr.has_name(sym::deprecated) {
unreachable!("only allowed on rustc_deprecated")
}
- if sess.check_name(attr, sym::rustc_deprecated) {
+ if attr.has_name(sym::rustc_deprecated) {
if since.is_none() {
handle_errors(&sess.parse_sess, attr.span, AttrError::MissingSince);
continue;
@@ -807,9 +760,7 @@
}
}
- sess.mark_attr_used(&attr);
-
- let is_since_rustc_version = sess.check_name(attr, sym::rustc_deprecated);
+ let is_since_rustc_version = attr.has_name(sym::rustc_deprecated);
depr = Some((Deprecation { since, note, suggestion, is_since_rustc_version }, attr.span));
}
@@ -860,7 +811,6 @@
let diagnostic = &sess.parse_sess.span_diagnostic;
if attr.has_name(sym::repr) {
if let Some(items) = attr.meta_item_list() {
- sess.mark_attr_used(attr);
for item in items {
let mut recognised = false;
if item.is_word() {
@@ -1059,14 +1009,13 @@
}
pub fn find_transparency(
- sess: &Session,
attrs: &[Attribute],
macro_rules: bool,
) -> (Transparency, Option<TransparencyError>) {
let mut transparency = None;
let mut error = None;
for attr in attrs {
- if sess.check_name(attr, sym::rustc_macro_transparency) {
+ if attr.has_name(sym::rustc_macro_transparency) {
if let Some((_, old_span)) = transparency {
error = Some(TransparencyError::MultipleTransparencyAttrs(old_span, attr.span));
break;
diff --git a/compiler/rustc_builtin_macros/Cargo.toml b/compiler/rustc_builtin_macros/Cargo.toml
index 962dfba..2370ac2 100644
--- a/compiler/rustc_builtin_macros/Cargo.toml
+++ b/compiler/rustc_builtin_macros/Cargo.toml
@@ -1,5 +1,4 @@
[package]
-authors = ["The Rust Project Developers"]
name = "rustc_builtin_macros"
version = "0.0.0"
edition = "2018"
diff --git a/compiler/rustc_builtin_macros/src/asm.rs b/compiler/rustc_builtin_macros/src/asm.rs
index ff13f0d..652165f 100644
--- a/compiler/rustc_builtin_macros/src/asm.rs
+++ b/compiler/rustc_builtin_macros/src/asm.rs
@@ -19,6 +19,7 @@
operands: Vec<(ast::InlineAsmOperand, Span)>,
named_args: FxHashMap<Symbol, usize>,
reg_args: FxHashSet<usize>,
+ clobber_abi: Option<(Symbol, Span)>,
options: ast::InlineAsmOptions,
options_spans: Vec<Span>,
}
@@ -63,6 +64,7 @@
operands: vec![],
named_args: FxHashMap::default(),
reg_args: FxHashSet::default(),
+ clobber_abi: None,
options: ast::InlineAsmOptions::empty(),
options_spans: vec![],
};
@@ -85,6 +87,13 @@
break;
} // accept trailing commas
+ // Parse clobber_abi
+ if p.eat_keyword(sym::clobber_abi) {
+ parse_clobber_abi(&mut p, &mut args)?;
+ allow_templates = false;
+ continue;
+ }
+
// Parse options
if p.eat_keyword(sym::options) {
parse_options(&mut p, &mut args, is_global_asm)?;
@@ -160,7 +169,11 @@
ast::ExprKind::Lit(ast::Lit { kind: ast::LitKind::Str(..), .. }) => {}
ast::ExprKind::MacCall(..) => {}
_ => {
- let errstr = "expected operand, options, or additional template string";
+ let errstr = if is_global_asm {
+ "expected operand, options, or additional template string"
+ } else {
+ "expected operand, clobber_abi, options, or additional template string"
+ };
let mut err = ecx.struct_span_err(template.span, errstr);
err.span_label(template.span, errstr);
return Err(err);
@@ -177,13 +190,19 @@
let slot = args.operands.len();
args.operands.push((op, span));
- // Validate the order of named, positional & explicit register operands and options. We do
- // this at the end once we have the full span of the argument available.
+ // Validate the order of named, positional & explicit register operands and
+ // clobber_abi/options. We do this at the end once we have the full span
+ // of the argument available.
if !args.options_spans.is_empty() {
ecx.struct_span_err(span, "arguments are not allowed after options")
.span_labels(args.options_spans.clone(), "previous options")
.span_label(span, "argument")
.emit();
+ } else if let Some((_, abi_span)) = args.clobber_abi {
+ ecx.struct_span_err(span, "arguments are not allowed after clobber_abi")
+ .span_label(abi_span, "clobber_abi")
+ .span_label(span, "argument")
+ .emit();
}
if explicit_reg {
if name.is_some() {
@@ -256,16 +275,23 @@
let mut have_real_output = false;
let mut outputs_sp = vec![];
+ let mut regclass_outputs = vec![];
for (op, op_sp) in &args.operands {
match op {
- ast::InlineAsmOperand::Out { expr, .. }
- | ast::InlineAsmOperand::SplitInOut { out_expr: expr, .. } => {
+ ast::InlineAsmOperand::Out { reg, expr, .. }
+ | ast::InlineAsmOperand::SplitInOut { reg, out_expr: expr, .. } => {
outputs_sp.push(*op_sp);
have_real_output |= expr.is_some();
+ if let ast::InlineAsmRegOrRegClass::RegClass(_) = reg {
+ regclass_outputs.push(*op_sp);
+ }
}
- ast::InlineAsmOperand::InOut { .. } => {
+ ast::InlineAsmOperand::InOut { reg, .. } => {
outputs_sp.push(*op_sp);
have_real_output = true;
+ if let ast::InlineAsmRegOrRegClass::RegClass(_) = reg {
+ regclass_outputs.push(*op_sp);
+ }
}
_ => {}
}
@@ -273,7 +299,7 @@
if args.options.contains(ast::InlineAsmOptions::PURE) && !have_real_output {
ecx.struct_span_err(
args.options_spans.clone(),
- "asm with `pure` option must have at least one output",
+ "asm with the `pure` option must have at least one output",
)
.emit();
}
@@ -284,6 +310,24 @@
// Bail out now since this is likely to confuse MIR
return Err(err);
}
+ if let Some((_, abi_span)) = args.clobber_abi {
+ if is_global_asm {
+ let err =
+ ecx.struct_span_err(abi_span, "`clobber_abi` cannot be used with `global_asm!`");
+
+ // Bail out now since this is likely to confuse later stages
+ return Err(err);
+ }
+ if !regclass_outputs.is_empty() {
+ ecx.struct_span_err(
+ regclass_outputs.clone(),
+ "asm with `clobber_abi` must specify explicit registers for outputs",
+ )
+ .span_label(abi_span, "clobber_abi")
+ .span_labels(regclass_outputs, "generic outputs")
+ .emit();
+ }
+ }
Ok(args)
}
@@ -375,6 +419,49 @@
Ok(())
}
+fn parse_clobber_abi<'a>(
+ p: &mut Parser<'a>,
+ args: &mut AsmArgs,
+) -> Result<(), DiagnosticBuilder<'a>> {
+ let span_start = p.prev_token.span;
+
+ p.expect(&token::OpenDelim(token::DelimToken::Paren))?;
+
+ let clobber_abi = match p.parse_str_lit() {
+ Ok(str_lit) => str_lit.symbol_unescaped,
+ Err(opt_lit) => {
+ let span = opt_lit.map_or(p.token.span, |lit| lit.span);
+ let mut err = p.sess.span_diagnostic.struct_span_err(span, "expected string literal");
+ err.span_label(span, "not a string literal");
+ return Err(err);
+ }
+ };
+
+ p.expect(&token::CloseDelim(token::DelimToken::Paren))?;
+
+ let new_span = span_start.to(p.prev_token.span);
+
+ if let Some((_, prev_span)) = args.clobber_abi {
+ let mut err = p
+ .sess
+ .span_diagnostic
+ .struct_span_err(new_span, "clobber_abi specified multiple times");
+ err.span_label(prev_span, "clobber_abi previously specified here");
+ return Err(err);
+ } else if !args.options_spans.is_empty() {
+ let mut err = p
+ .sess
+ .span_diagnostic
+ .struct_span_err(new_span, "clobber_abi is not allowed after options");
+ err.span_labels(args.options_spans.clone(), "options");
+ return Err(err);
+ }
+
+ args.clobber_abi = Some((clobber_abi, new_span));
+
+ Ok(())
+}
+
fn parse_reg<'a>(
p: &mut Parser<'a>,
explicit_reg: &mut bool,
@@ -410,6 +497,8 @@
let mut line_spans = Vec::with_capacity(args.templates.len());
let mut curarg = 0;
+ let mut template_strs = Vec::with_capacity(args.templates.len());
+
for template_expr in args.templates.into_iter() {
if !template.is_empty() {
template.push(ast::InlineAsmTemplatePiece::String("\n".to_string()));
@@ -433,8 +522,13 @@
ast::StrStyle::Raw(raw) => Some(raw as usize),
};
- let template_str = &template_str.as_str();
let template_snippet = ecx.source_map().span_to_snippet(template_sp).ok();
+ template_strs.push((
+ template_str,
+ template_snippet.as_ref().map(|s| Symbol::intern(s)),
+ template_sp,
+ ));
+ let template_str = &template_str.as_str();
if let Some(InlineAsmArch::X86 | InlineAsmArch::X86_64) = ecx.sess.asm_arch {
let find_span = |needle: &str| -> Span {
@@ -660,7 +754,14 @@
}
}
- Some(ast::InlineAsm { template, operands: args.operands, options: args.options, line_spans })
+ Some(ast::InlineAsm {
+ template,
+ template_strs: template_strs.into_boxed_slice(),
+ operands: args.operands,
+ clobber_abi: args.clobber_abi,
+ options: args.options,
+ line_spans,
+ })
}
pub fn expand_asm<'cx>(
diff --git a/compiler/rustc_builtin_macros/src/assert.rs b/compiler/rustc_builtin_macros/src/assert.rs
index 93ba54d..1e2646e 100644
--- a/compiler/rustc_builtin_macros/src/assert.rs
+++ b/compiler/rustc_builtin_macros/src/assert.rs
@@ -1,10 +1,10 @@
-use rustc_errors::{Applicability, DiagnosticBuilder};
-
+use crate::panic::use_panic_2021;
use rustc_ast::ptr::P;
use rustc_ast::token;
use rustc_ast::tokenstream::{DelimSpan, TokenStream};
use rustc_ast::{self as ast, *};
use rustc_ast_pretty::pprust;
+use rustc_errors::{Applicability, DiagnosticBuilder};
use rustc_expand::base::*;
use rustc_parse::parser::Parser;
use rustc_span::symbol::{sym, Ident, Symbol};
@@ -28,7 +28,7 @@
let sp = cx.with_call_site_ctxt(span);
let panic_call = if let Some(tokens) = custom_message {
- let path = if span.rust_2021() {
+ let path = if use_panic_2021(span) {
// On edition 2021, we always call `$crate::panic::panic_2021!()`.
Path {
span: sp,
diff --git a/compiler/rustc_builtin_macros/src/deriving/debug.rs b/compiler/rustc_builtin_macros/src/deriving/debug.rs
index cc6dac5..14506f2 100644
--- a/compiler/rustc_builtin_macros/src/deriving/debug.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/debug.rs
@@ -3,7 +3,7 @@
use crate::deriving::path_std;
use rustc_ast::ptr::P;
-use rustc_ast::{self as ast, Expr, MetaItem};
+use rustc_ast::{self as ast, Expr, LocalKind, MetaItem};
use rustc_expand::base::{Annotatable, ExtCtxt};
use rustc_span::symbol::{sym, Ident};
use rustc_span::{Span, DUMMY_SP};
@@ -135,8 +135,8 @@
let local = P(ast::Local {
pat: cx.pat_wild(sp),
ty: None,
- init: Some(expr),
id: ast::DUMMY_NODE_ID,
+ kind: LocalKind::Init(expr),
span: sp,
attrs: ast::AttrVec::new(),
tokens: None,
diff --git a/compiler/rustc_builtin_macros/src/deriving/default.rs b/compiler/rustc_builtin_macros/src/deriving/default.rs
index 980be3a..8c53094 100644
--- a/compiler/rustc_builtin_macros/src/deriving/default.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/default.rs
@@ -2,11 +2,16 @@
use crate::deriving::generic::*;
use rustc_ast::ptr::P;
+use rustc_ast::walk_list;
+use rustc_ast::EnumDef;
+use rustc_ast::VariantData;
use rustc_ast::{Expr, MetaItem};
-use rustc_errors::struct_span_err;
+use rustc_errors::Applicability;
use rustc_expand::base::{Annotatable, DummyResult, ExtCtxt};
+use rustc_span::symbol::Ident;
use rustc_span::symbol::{kw, sym};
use rustc_span::Span;
+use smallvec::SmallVec;
pub fn expand_deriving_default(
cx: &mut ExtCtxt<'_>,
@@ -15,6 +20,8 @@
item: &Annotatable,
push: &mut dyn FnMut(Annotatable),
) {
+ item.visit_with(&mut DetectNonVariantDefaultAttr { cx });
+
let inline = cx.meta_word(span, sym::inline);
let attrs = vec![cx.attribute(inline)];
let trait_def = TraitDef {
@@ -34,8 +41,25 @@
attributes: attrs,
is_unsafe: false,
unify_fieldless_variants: false,
- combine_substructure: combine_substructure(Box::new(|a, b, c| {
- default_substructure(a, b, c)
+ combine_substructure: combine_substructure(Box::new(|cx, trait_span, substr| {
+ match substr.fields {
+ StaticStruct(_, fields) => {
+ default_struct_substructure(cx, trait_span, substr, fields)
+ }
+ StaticEnum(enum_def, _) => {
+ if !cx.sess.features_untracked().derive_default_enum {
+ rustc_session::parse::feature_err(
+ cx.parse_sess(),
+ sym::derive_default_enum,
+ span,
+ "deriving `Default` on enums is experimental",
+ )
+ .emit();
+ }
+ default_enum_substructure(cx, trait_span, enum_def)
+ }
+ _ => cx.span_bug(trait_span, "method in `derive(Default)`"),
+ }
})),
}],
associated_types: Vec::new(),
@@ -43,44 +67,223 @@
trait_def.expand(cx, mitem, item, push)
}
-fn default_substructure(
+fn default_struct_substructure(
cx: &mut ExtCtxt<'_>,
trait_span: Span,
substr: &Substructure<'_>,
+ summary: &StaticFields,
) -> P<Expr> {
// Note that `kw::Default` is "default" and `sym::Default` is "Default"!
let default_ident = cx.std_path(&[kw::Default, sym::Default, kw::Default]);
let default_call = |span| cx.expr_call_global(span, default_ident.clone(), Vec::new());
- match *substr.fields {
- StaticStruct(_, ref summary) => match *summary {
- Unnamed(ref fields, is_tuple) => {
- if !is_tuple {
- cx.expr_ident(trait_span, substr.type_ident)
- } else {
- let exprs = fields.iter().map(|sp| default_call(*sp)).collect();
- cx.expr_call_ident(trait_span, substr.type_ident, exprs)
- }
+ match summary {
+ Unnamed(ref fields, is_tuple) => {
+ if !is_tuple {
+ cx.expr_ident(trait_span, substr.type_ident)
+ } else {
+ let exprs = fields.iter().map(|sp| default_call(*sp)).collect();
+ cx.expr_call_ident(trait_span, substr.type_ident, exprs)
}
- Named(ref fields) => {
- let default_fields = fields
+ }
+ Named(ref fields) => {
+ let default_fields = fields
+ .iter()
+ .map(|&(ident, span)| cx.field_imm(span, ident, default_call(span)))
+ .collect();
+ cx.expr_struct_ident(trait_span, substr.type_ident, default_fields)
+ }
+ }
+}
+
+fn default_enum_substructure(
+ cx: &mut ExtCtxt<'_>,
+ trait_span: Span,
+ enum_def: &EnumDef,
+) -> P<Expr> {
+ let default_variant = match extract_default_variant(cx, enum_def, trait_span) {
+ Ok(value) => value,
+ Err(()) => return DummyResult::raw_expr(trait_span, true),
+ };
+
+ // At this point, we know that there is exactly one variant with a `#[default]` attribute. The
+ // attribute hasn't yet been validated.
+
+ if let Err(()) = validate_default_attribute(cx, default_variant) {
+ return DummyResult::raw_expr(trait_span, true);
+ }
+
+ // We now know there is exactly one unit variant with exactly one `#[default]` attribute.
+
+ cx.expr_path(cx.path(
+ default_variant.span,
+ vec![Ident::new(kw::SelfUpper, default_variant.span), default_variant.ident],
+ ))
+}
+
+fn extract_default_variant<'a>(
+ cx: &mut ExtCtxt<'_>,
+ enum_def: &'a EnumDef,
+ trait_span: Span,
+) -> Result<&'a rustc_ast::Variant, ()> {
+ let default_variants: SmallVec<[_; 1]> = enum_def
+ .variants
+ .iter()
+ .filter(|variant| cx.sess.contains_name(&variant.attrs, kw::Default))
+ .collect();
+
+ let variant = match default_variants.as_slice() {
+ [variant] => variant,
+ [] => {
+ let possible_defaults = enum_def
+ .variants
+ .iter()
+ .filter(|variant| matches!(variant.data, VariantData::Unit(..)))
+ .filter(|variant| !cx.sess.contains_name(&variant.attrs, sym::non_exhaustive));
+
+ let mut diag = cx.struct_span_err(trait_span, "no default declared");
+ diag.help("make a unit variant default by placing `#[default]` above it");
+ for variant in possible_defaults {
+ // Suggest making each unit variant default.
+ diag.tool_only_span_suggestion(
+ variant.span,
+ &format!("make `{}` default", variant.ident),
+ format!("#[default] {}", variant.ident),
+ Applicability::MaybeIncorrect,
+ );
+ }
+ diag.emit();
+
+ return Err(());
+ }
+ [first, rest @ ..] => {
+ let mut diag = cx.struct_span_err(trait_span, "multiple declared defaults");
+ diag.span_label(first.span, "first default");
+ diag.span_labels(rest.iter().map(|variant| variant.span), "additional default");
+ diag.note("only one variant can be default");
+ for variant in &default_variants {
+ // Suggest making each variant already tagged default.
+ let suggestion = default_variants
.iter()
- .map(|&(ident, span)| cx.field_imm(span, ident, default_call(span)))
+ .filter_map(|v| {
+ if v.ident == variant.ident {
+ None
+ } else {
+ Some((cx.sess.find_by_name(&v.attrs, kw::Default)?.span, String::new()))
+ }
+ })
.collect();
- cx.expr_struct_ident(trait_span, substr.type_ident, default_fields)
+
+ diag.tool_only_multipart_suggestion(
+ &format!("make `{}` default", variant.ident),
+ suggestion,
+ Applicability::MaybeIncorrect,
+ );
}
- },
- StaticEnum(..) => {
- struct_span_err!(
- &cx.sess.parse_sess.span_diagnostic,
- trait_span,
- E0665,
- "`Default` cannot be derived for enums, only structs"
+ diag.emit();
+
+ return Err(());
+ }
+ };
+
+ if !matches!(variant.data, VariantData::Unit(..)) {
+ cx.struct_span_err(
+ variant.ident.span,
+ "the `#[default]` attribute may only be used on unit enum variants",
+ )
+ .help("consider a manual implementation of `Default`")
+ .emit();
+
+ return Err(());
+ }
+
+ if let Some(non_exhaustive_attr) = cx.sess.find_by_name(&variant.attrs, sym::non_exhaustive) {
+ cx.struct_span_err(variant.ident.span, "default variant must be exhaustive")
+ .span_label(non_exhaustive_attr.span, "declared `#[non_exhaustive]` here")
+ .help("consider a manual implementation of `Default`")
+ .emit();
+
+ return Err(());
+ }
+
+ Ok(variant)
+}
+
+fn validate_default_attribute(
+ cx: &mut ExtCtxt<'_>,
+ default_variant: &rustc_ast::Variant,
+) -> Result<(), ()> {
+ let attrs: SmallVec<[_; 1]> =
+ cx.sess.filter_by_name(&default_variant.attrs, kw::Default).collect();
+
+ let attr = match attrs.as_slice() {
+ [attr] => attr,
+ [] => cx.bug(
+ "this method must only be called with a variant that has a `#[default]` attribute",
+ ),
+ [first, rest @ ..] => {
+ // FIXME(jhpratt) Do we want to perform this check? It doesn't exist
+ // for `#[inline]`, `#[non_exhaustive]`, and presumably others.
+
+ let suggestion_text =
+ if rest.len() == 1 { "try removing this" } else { "try removing these" };
+
+ cx.struct_span_err(default_variant.ident.span, "multiple `#[default]` attributes")
+ .note("only one `#[default]` attribute is needed")
+ .span_label(first.span, "`#[default]` used here")
+ .span_label(rest[0].span, "`#[default]` used again here")
+ .span_help(rest.iter().map(|attr| attr.span).collect::<Vec<_>>(), suggestion_text)
+ // This would otherwise display the empty replacement, hence the otherwise
+ // repetitive `.span_help` call above.
+ .tool_only_multipart_suggestion(
+ suggestion_text,
+ rest.iter().map(|attr| (attr.span, String::new())).collect(),
+ Applicability::MachineApplicable,
+ )
+ .emit();
+
+ return Err(());
+ }
+ };
+ if !attr.is_word() {
+ cx.struct_span_err(attr.span, "`#[default]` attribute does not accept a value")
+ .span_suggestion_hidden(
+ attr.span,
+ "try using `#[default]`",
+ "#[default]".into(),
+ Applicability::MaybeIncorrect,
)
.emit();
- // let compilation continue
- DummyResult::raw_expr(trait_span, true)
+
+ return Err(());
+ }
+ Ok(())
+}
+
+struct DetectNonVariantDefaultAttr<'a, 'b> {
+ cx: &'a ExtCtxt<'b>,
+}
+
+impl<'a, 'b> rustc_ast::visit::Visitor<'a> for DetectNonVariantDefaultAttr<'a, 'b> {
+ fn visit_attribute(&mut self, attr: &'a rustc_ast::Attribute) {
+ if attr.has_name(kw::Default) {
+ self.cx
+ .struct_span_err(
+ attr.span,
+ "the `#[default]` attribute may only be used on unit enum variants",
+ )
+ .emit();
}
- _ => cx.span_bug(trait_span, "method in `derive(Default)`"),
+
+ rustc_ast::visit::walk_attribute(self, attr);
+ }
+ fn visit_variant(&mut self, v: &'a rustc_ast::Variant) {
+ self.visit_ident(v.ident);
+ self.visit_vis(&v.vis);
+ self.visit_variant_data(&v.data);
+ walk_list!(self, visit_anon_const, &v.disr_expr);
+ for attr in &v.attrs {
+ rustc_ast::visit::walk_attribute(self, attr);
+ }
}
}
diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
index 417deda..59f933d4 100644
--- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
@@ -527,12 +527,12 @@
tokens: None,
},
attrs: Vec::new(),
- kind: ast::AssocItemKind::TyAlias(box ast::TyAliasKind(
+ kind: ast::AssocItemKind::TyAlias(Box::new(ast::TyAliasKind(
ast::Defaultness::Final,
Generics::default(),
Vec::new(),
Some(type_def.to_ty(cx, self.span, type_ident, generics)),
- )),
+ ))),
tokens: None,
})
});
@@ -677,8 +677,6 @@
let self_type = cx.ty_path(path);
let attr = cx.attribute(cx.meta_word(self.span, sym::automatically_derived));
- // Just mark it now since we know that it'll end up used downstream
- cx.sess.mark_attr_used(&attr);
let opt_trait_ref = Some(trait_ref);
let unused_qual = {
let word = rustc_ast::attr::mk_nested_word_item(Ident::new(
@@ -698,7 +696,7 @@
self.span,
Ident::invalid(),
a,
- ast::ItemKind::Impl(box ast::ImplKind {
+ ast::ItemKind::Impl(Box::new(ast::ImplKind {
unsafety,
polarity: ast::ImplPolarity::Positive,
defaultness: ast::Defaultness::Final,
@@ -707,7 +705,7 @@
of_trait: opt_trait_ref,
self_ty: self_type,
items: methods.into_iter().chain(associated_types).collect(),
- }),
+ })),
)
}
@@ -940,7 +938,12 @@
tokens: None,
},
ident: method_ident,
- kind: ast::AssocItemKind::Fn(box ast::FnKind(def, sig, fn_generics, Some(body_block))),
+ kind: ast::AssocItemKind::Fn(Box::new(ast::FnKind(
+ def,
+ sig,
+ fn_generics,
+ Some(body_block),
+ ))),
tokens: None,
})
}
@@ -1695,7 +1698,7 @@
/// One or more fields: call the base case function on the first value (which depends on
/// `use_fold`), and use that as the base case. Then perform `cs_fold` on the remainder of the
/// fields.
-/// When the `substructure` is a `EnumNonMatchingCollapsed`, the result of `enum_nonmatch_f`
+/// When the `substructure` is an `EnumNonMatchingCollapsed`, the result of `enum_nonmatch_f`
/// is returned. Statics may not be folded over.
/// See `cs_op` in `partial_ord.rs` for a model example.
pub fn cs_fold1<F, B>(
diff --git a/compiler/rustc_builtin_macros/src/deriving/mod.rs b/compiler/rustc_builtin_macros/src/deriving/mod.rs
index 7dea609..bcf9571 100644
--- a/compiler/rustc_builtin_macros/src/deriving/mod.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/mod.rs
@@ -102,6 +102,7 @@
rules: ast::BlockCheckMode::Unsafe(ast::CompilerGenerated),
span,
tokens: None,
+ could_be_bare_literal: false,
}))
}
@@ -179,7 +180,7 @@
span,
Ident::invalid(),
attrs,
- ItemKind::Impl(box ImplKind {
+ ItemKind::Impl(Box::new(ImplKind {
unsafety: ast::Unsafe::No,
polarity: ast::ImplPolarity::Positive,
defaultness: ast::Defaultness::Final,
@@ -188,7 +189,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 00f2f37..8508b3b 100644
--- a/compiler/rustc_builtin_macros/src/format.rs
+++ b/compiler/rustc_builtin_macros/src/format.rs
@@ -3,8 +3,8 @@
use rustc_ast as ast;
use rustc_ast::ptr::P;
-use rustc_ast::token;
use rustc_ast::tokenstream::TokenStream;
+use rustc_ast::{token, BlockCheckMode, UnsafeSource};
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_errors::{pluralize, Applicability, DiagnosticBuilder};
use rustc_expand::base::{self, *};
@@ -838,12 +838,15 @@
//
// But the nested match expression is proved to perform not as well
// as series of let's; the first approach does.
- let pat = self.ecx.pat_tuple(self.macsp, pats);
- let arm = self.ecx.arm(self.macsp, pat, args_array);
- let head = self.ecx.expr(self.macsp, ast::ExprKind::Tup(heads));
- let result = self.ecx.expr_match(self.macsp, head, vec![arm]);
+ let args_match = {
+ let pat = self.ecx.pat_tuple(self.macsp, pats);
+ let arm = self.ecx.arm(self.macsp, pat, args_array);
+ let head = self.ecx.expr(self.macsp, ast::ExprKind::Tup(heads));
+ self.ecx.expr_match(self.macsp, head, vec![arm])
+ };
- let args_slice = self.ecx.expr_addr_of(self.macsp, result);
+ let ident = Ident::from_str_and_span("args", self.macsp);
+ let args_slice = self.ecx.expr_ident(self.macsp, ident);
// Now create the fmt::Arguments struct with all our locals we created.
let (fn_name, fn_args) = if self.all_pieces_simple {
@@ -857,7 +860,21 @@
};
let path = self.ecx.std_path(&[sym::fmt, sym::Arguments, Symbol::intern(fn_name)]);
- self.ecx.expr_call_global(self.macsp, path, fn_args)
+ let arguments = self.ecx.expr_call_global(self.macsp, path, fn_args);
+ let body = self.ecx.expr_block(P(ast::Block {
+ stmts: vec![self.ecx.stmt_expr(arguments)],
+ id: ast::DUMMY_NODE_ID,
+ rules: BlockCheckMode::Unsafe(UnsafeSource::CompilerGenerated),
+ span: self.macsp,
+ tokens: None,
+ could_be_bare_literal: false,
+ }));
+
+ let ident = Ident::from_str_and_span("args", self.macsp);
+ let binding_mode = ast::BindingMode::ByRef(ast::Mutability::Not);
+ let pat = self.ecx.pat_ident_binding_mode(self.macsp, ident, binding_mode);
+ let arm = self.ecx.arm(self.macsp, pat, body);
+ self.ecx.expr_match(self.macsp, args_match, vec![arm])
}
fn format_arg(
diff --git a/compiler/rustc_builtin_macros/src/global_allocator.rs b/compiler/rustc_builtin_macros/src/global_allocator.rs
index a97cac7..3f71ee6 100644
--- a/compiler/rustc_builtin_macros/src/global_allocator.rs
+++ b/compiler/rustc_builtin_macros/src/global_allocator.rs
@@ -85,8 +85,12 @@
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(box FnKind(ast::Defaultness::Final, sig, Generics::default(), block));
+ let kind = ItemKind::Fn(Box::new(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 ba27f10..d1d2769 100644
--- a/compiler/rustc_builtin_macros/src/lib.rs
+++ b/compiler/rustc_builtin_macros/src/lib.rs
@@ -3,7 +3,6 @@
#![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)]
@@ -72,6 +71,7 @@
file: source_util::expand_file,
format_args_nl: format::expand_format_args_nl,
format_args: format::expand_format_args,
+ const_format_args: format::expand_format_args,
global_asm: asm::expand_global_asm,
include_bytes: source_util::expand_include_bytes,
include_str: source_util::expand_include_str,
diff --git a/compiler/rustc_builtin_macros/src/panic.rs b/compiler/rustc_builtin_macros/src/panic.rs
index 6f5962d..54ab596 100644
--- a/compiler/rustc_builtin_macros/src/panic.rs
+++ b/compiler/rustc_builtin_macros/src/panic.rs
@@ -2,6 +2,7 @@
use rustc_ast::tokenstream::{DelimSpan, TokenStream};
use rustc_ast::*;
use rustc_expand::base::*;
+use rustc_span::edition::Edition;
use rustc_span::symbol::sym;
use rustc_span::Span;
@@ -19,7 +20,7 @@
sp: Span,
tts: TokenStream,
) -> Box<dyn MacResult + 'cx> {
- let panic = if sp.rust_2021() { sym::panic_2021 } else { sym::panic_2015 };
+ let panic = if use_panic_2021(sp) { sym::panic_2021 } else { sym::panic_2015 };
let sp = cx.with_call_site_ctxt(sp);
@@ -46,3 +47,19 @@
),
)
}
+
+pub fn use_panic_2021(mut span: Span) -> bool {
+ // To determine the editon, we check the first span up the expansion
+ // stack that does not have #[allow_internal_unstable(edition_panic)].
+ // (To avoid using the edition of e.g. the assert!() or debug_assert!() definition.)
+ loop {
+ let expn = span.ctxt().outer_expn_data();
+ if let Some(features) = expn.allow_internal_unstable {
+ if features.iter().any(|&f| f == sym::edition_panic) {
+ span = expn.call_site;
+ continue;
+ }
+ }
+ break expn.edition >= Edition::Edition2021;
+ }
+}
diff --git a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs
index f83329ec..6f61e4c 100644
--- a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs
+++ b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs
@@ -13,7 +13,6 @@
use rustc_span::symbol::{kw, sym, Ident, Symbol};
use rustc_span::{Span, DUMMY_SP};
use smallvec::smallvec;
-use std::cell::RefCell;
struct ProcMacroDerive {
id: NodeId,
@@ -90,7 +89,7 @@
return krate;
}
- let decls = mk_decls(&mut krate, &mut cx, ¯os);
+ let decls = mk_decls(&mut cx, ¯os);
krate.items.push(decls);
krate
@@ -260,11 +259,11 @@
return;
}
- if self.sess.check_name(attr, sym::proc_macro_derive) {
+ if attr.has_name(sym::proc_macro_derive) {
self.collect_custom_derive(item, attr);
- } else if self.sess.check_name(attr, sym::proc_macro_attribute) {
+ } else if attr.has_name(sym::proc_macro_attribute) {
self.collect_attr_proc_macro(item);
- } else if self.sess.check_name(attr, sym::proc_macro) {
+ } else if attr.has_name(sym::proc_macro) {
self.collect_bang_proc_macro(item);
};
@@ -289,15 +288,7 @@
// // ...
// ];
// }
-fn mk_decls(
- ast_krate: &mut ast::Crate,
- cx: &mut ExtCtxt<'_>,
- macros: &[ProcMacro],
-) -> P<ast::Item> {
- // We're the ones filling in this Vec,
- // so it should be empty to start with
- assert!(ast_krate.proc_macros.is_empty());
-
+fn mk_decls(cx: &mut ExtCtxt<'_>, macros: &[ProcMacro]) -> P<ast::Item> {
let expn_id = cx.resolver.expansion_for_ast_pass(
DUMMY_SP,
AstPass::ProcMacroHarness,
@@ -316,26 +307,25 @@
let attr = Ident::new(sym::attr, span);
let bang = Ident::new(sym::bang, span);
- let krate_ref = RefCell::new(ast_krate);
-
- // We add NodeIds to 'krate.proc_macros' in the order
+ // We add NodeIds to 'resolver.proc_macros' in the order
// that we generate expressions. The position of each NodeId
// in the 'proc_macros' Vec corresponds to its position
// in the static array that will be generated
let decls = {
- let local_path =
- |sp: Span, name| cx.expr_path(cx.path(sp.with_ctxt(span.ctxt()), vec![name]));
- let proc_macro_ty_method_path = |method| {
+ let local_path = |cx: &ExtCtxt<'_>, sp: Span, name| {
+ cx.expr_path(cx.path(sp.with_ctxt(span.ctxt()), vec![name]))
+ };
+ let proc_macro_ty_method_path = |cx: &ExtCtxt<'_>, method| {
cx.expr_path(cx.path(span, vec![proc_macro, bridge, client, proc_macro_ty, method]))
};
macros
.iter()
.map(|m| match m {
ProcMacro::Derive(cd) => {
- krate_ref.borrow_mut().proc_macros.push(cd.id);
+ cx.resolver.declare_proc_macro(cd.id);
cx.expr_call(
span,
- proc_macro_ty_method_path(custom_derive),
+ proc_macro_ty_method_path(cx, custom_derive),
vec![
cx.expr_str(cd.span, cd.trait_name),
cx.expr_vec_slice(
@@ -345,12 +335,12 @@
.map(|&s| cx.expr_str(cd.span, s))
.collect::<Vec<_>>(),
),
- local_path(cd.span, cd.function_name),
+ local_path(cx, cd.span, cd.function_name),
],
)
}
ProcMacro::Def(ca) => {
- krate_ref.borrow_mut().proc_macros.push(ca.id);
+ cx.resolver.declare_proc_macro(ca.id);
let ident = match ca.def_type {
ProcMacroDefType::Attr => attr,
ProcMacroDefType::Bang => bang,
@@ -358,10 +348,10 @@
cx.expr_call(
span,
- proc_macro_ty_method_path(ident),
+ proc_macro_ty_method_path(cx, ident),
vec![
cx.expr_str(ca.span, ca.function_name.name),
- local_path(ca.span, ca.function_name),
+ local_path(cx, ca.span, ca.function_name),
],
)
}
diff --git a/compiler/rustc_builtin_macros/src/test_harness.rs b/compiler/rustc_builtin_macros/src/test_harness.rs
index 74a97a4..d791677 100644
--- a/compiler/rustc_builtin_macros/src/test_harness.rs
+++ b/compiler/rustc_builtin_macros/src/test_harness.rs
@@ -188,8 +188,7 @@
let attrs = attrs
.into_iter()
.filter(|attr| {
- !self.sess.check_name(attr, sym::rustc_main)
- && !self.sess.check_name(attr, sym::start)
+ !attr.has_name(sym::rustc_main) && !attr.has_name(sym::start)
})
.chain(iter::once(allow_dead_code))
.collect();
@@ -315,8 +314,12 @@
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(box ast::FnKind(def, sig, ast::Generics::default(), Some(main_body)));
+ let main = ast::ItemKind::Fn(Box::new(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 f81ac87..f524b42 100644
--- a/compiler/rustc_codegen_cranelift/.github/workflows/main.yml
+++ b/compiler/rustc_codegen_cranelift/.github/workflows/main.yml
@@ -49,12 +49,14 @@
- name: Install MinGW toolchain and wine
if: matrix.os == 'ubuntu-latest' && matrix.env.TARGET_TRIPLE == 'x86_64-pc-windows-gnu'
run: |
+ sudo apt-get update
sudo apt-get install -y gcc-mingw-w64-x86-64 wine-stable
rustup target add x86_64-pc-windows-gnu
- name: Install AArch64 toolchain and qemu
if: matrix.os == 'ubuntu-latest' && matrix.env.TARGET_TRIPLE == 'aarch64-unknown-linux-gnu'
run: |
+ sudo apt-get update
sudo apt-get install -y gcc-aarch64-linux-gnu qemu-user
- name: Prepare dependencies
diff --git a/compiler/rustc_codegen_cranelift/Cargo.lock b/compiler/rustc_codegen_cranelift/Cargo.lock
index 56d0974b..23c1fdc6 100644
--- a/compiler/rustc_codegen_cranelift/Cargo.lock
+++ b/compiler/rustc_codegen_cranelift/Cargo.lock
@@ -4,9 +4,9 @@
[[package]]
name = "anyhow"
-version = "1.0.38"
+version = "1.0.42"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "afddf7f520a80dbf76e6f50a35bca42a2331ef227a28b3b6dc5c2e2338d114b1"
+checksum = "595d3cfa7a60d4555cb5067b99f07142a08ea778de5cf993f7b75c7d8fabc486"
[[package]]
name = "ar"
@@ -34,7 +34,7 @@
[[package]]
name = "cranelift-bforest"
version = "0.75.0"
-source = "git+https://github.com/bytecodealliance/wasmtime.git?branch=main#c71ad9490e7f3e19bbcae7e28bbe50f8a0b4a5d8"
+source = "git+https://github.com/bytecodealliance/wasmtime.git#5deda279775dca5e37449c829cda1f6276d6542b"
dependencies = [
"cranelift-entity",
]
@@ -42,7 +42,7 @@
[[package]]
name = "cranelift-codegen"
version = "0.75.0"
-source = "git+https://github.com/bytecodealliance/wasmtime.git?branch=main#c71ad9490e7f3e19bbcae7e28bbe50f8a0b4a5d8"
+source = "git+https://github.com/bytecodealliance/wasmtime.git#5deda279775dca5e37449c829cda1f6276d6542b"
dependencies = [
"cranelift-bforest",
"cranelift-codegen-meta",
@@ -58,7 +58,7 @@
[[package]]
name = "cranelift-codegen-meta"
version = "0.75.0"
-source = "git+https://github.com/bytecodealliance/wasmtime.git?branch=main#c71ad9490e7f3e19bbcae7e28bbe50f8a0b4a5d8"
+source = "git+https://github.com/bytecodealliance/wasmtime.git#5deda279775dca5e37449c829cda1f6276d6542b"
dependencies = [
"cranelift-codegen-shared",
"cranelift-entity",
@@ -67,17 +67,17 @@
[[package]]
name = "cranelift-codegen-shared"
version = "0.75.0"
-source = "git+https://github.com/bytecodealliance/wasmtime.git?branch=main#c71ad9490e7f3e19bbcae7e28bbe50f8a0b4a5d8"
+source = "git+https://github.com/bytecodealliance/wasmtime.git#5deda279775dca5e37449c829cda1f6276d6542b"
[[package]]
name = "cranelift-entity"
version = "0.75.0"
-source = "git+https://github.com/bytecodealliance/wasmtime.git?branch=main#c71ad9490e7f3e19bbcae7e28bbe50f8a0b4a5d8"
+source = "git+https://github.com/bytecodealliance/wasmtime.git#5deda279775dca5e37449c829cda1f6276d6542b"
[[package]]
name = "cranelift-frontend"
version = "0.75.0"
-source = "git+https://github.com/bytecodealliance/wasmtime.git?branch=main#c71ad9490e7f3e19bbcae7e28bbe50f8a0b4a5d8"
+source = "git+https://github.com/bytecodealliance/wasmtime.git#5deda279775dca5e37449c829cda1f6276d6542b"
dependencies = [
"cranelift-codegen",
"log",
@@ -88,7 +88,7 @@
[[package]]
name = "cranelift-jit"
version = "0.75.0"
-source = "git+https://github.com/bytecodealliance/wasmtime.git?branch=main#c71ad9490e7f3e19bbcae7e28bbe50f8a0b4a5d8"
+source = "git+https://github.com/bytecodealliance/wasmtime.git#5deda279775dca5e37449c829cda1f6276d6542b"
dependencies = [
"anyhow",
"cranelift-codegen",
@@ -105,7 +105,7 @@
[[package]]
name = "cranelift-module"
version = "0.75.0"
-source = "git+https://github.com/bytecodealliance/wasmtime.git?branch=main#c71ad9490e7f3e19bbcae7e28bbe50f8a0b4a5d8"
+source = "git+https://github.com/bytecodealliance/wasmtime.git#5deda279775dca5e37449c829cda1f6276d6542b"
dependencies = [
"anyhow",
"cranelift-codegen",
@@ -116,7 +116,7 @@
[[package]]
name = "cranelift-native"
version = "0.75.0"
-source = "git+https://github.com/bytecodealliance/wasmtime.git?branch=main#c71ad9490e7f3e19bbcae7e28bbe50f8a0b4a5d8"
+source = "git+https://github.com/bytecodealliance/wasmtime.git#5deda279775dca5e37449c829cda1f6276d6542b"
dependencies = [
"cranelift-codegen",
"libc",
@@ -126,7 +126,7 @@
[[package]]
name = "cranelift-object"
version = "0.75.0"
-source = "git+https://github.com/bytecodealliance/wasmtime.git?branch=main#c71ad9490e7f3e19bbcae7e28bbe50f8a0b4a5d8"
+source = "git+https://github.com/bytecodealliance/wasmtime.git#5deda279775dca5e37449c829cda1f6276d6542b"
dependencies = [
"anyhow",
"cranelift-codegen",
@@ -147,24 +147,24 @@
[[package]]
name = "gimli"
-version = "0.24.0"
+version = "0.25.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0e4075386626662786ddb0ec9081e7c7eeb1ba31951f447ca780ef9f5d568189"
+checksum = "f0a01e0497841a3b2db4f8afa483cce65f7e96a3498bd6c541734792aeac8fe7"
dependencies = [
"indexmap",
]
[[package]]
name = "hashbrown"
-version = "0.9.1"
+version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04"
+checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e"
[[package]]
name = "indexmap"
-version = "1.6.1"
+version = "1.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4fb1fa934250de4de8aef298d81c729a7d33d8c239daa3a7575e6b92bfc7313b"
+checksum = "bc633605454125dec4b66843673f01c7df2b89479b32e0ed634e43a91cff62a5"
dependencies = [
"autocfg",
"hashbrown",
@@ -172,9 +172,9 @@
[[package]]
name = "libc"
-version = "0.2.97"
+version = "0.2.98"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "12b8adadd720df158f4d70dfe7ccc6adb0472d7c55ca83445f6a5ab3e36f8fb6"
+checksum = "320cfe77175da3a483efed4bc0adc1968ca050b098ce4f2f1c13a56626128790"
[[package]]
name = "libloading"
@@ -212,9 +212,9 @@
[[package]]
name = "object"
-version = "0.25.3"
+version = "0.26.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a38f2be3697a57b4060074ff41b44c16870d916ad7877c17696e063257482bc7"
+checksum = "c55827317fb4c08822499848a14237d2874d6f139828893017237e7ab93eb386"
dependencies = [
"crc32fast",
"indexmap",
@@ -277,9 +277,9 @@
[[package]]
name = "target-lexicon"
-version = "0.12.0"
+version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "64ae3b39281e4b14b8123bdbaddd472b7dfe215e444181f2f9d2443c2444f834"
+checksum = "b0652da4c4121005e9ed22b79f6c5f2d9e2752906b53a33e9490489ba421a6fb"
[[package]]
name = "winapi"
diff --git a/compiler/rustc_codegen_cranelift/Cargo.toml b/compiler/rustc_codegen_cranelift/Cargo.toml
index ef68d7e..6f40fc0 100644
--- a/compiler/rustc_codegen_cranelift/Cargo.toml
+++ b/compiler/rustc_codegen_cranelift/Cargo.toml
@@ -1,7 +1,6 @@
[package]
name = "rustc_codegen_cranelift"
version = "0.1.0"
-authors = ["bjorn3 <[email protected]>"]
edition = "2018"
[lib]
@@ -9,15 +8,15 @@
[dependencies]
# These have to be in sync with each other
-cranelift-codegen = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "main", features = ["unwind", "all-arch"] }
-cranelift-frontend = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "main" }
-cranelift-module = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "main" }
-cranelift-native = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "main" }
-cranelift-jit = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "main", optional = true }
-cranelift-object = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "main" }
+cranelift-codegen = { git = "https://github.com/bytecodealliance/wasmtime.git", features = ["unwind", "all-arch"] }
+cranelift-frontend = { git = "https://github.com/bytecodealliance/wasmtime.git" }
+cranelift-module = { git = "https://github.com/bytecodealliance/wasmtime.git" }
+cranelift-native = { git = "https://github.com/bytecodealliance/wasmtime.git" }
+cranelift-jit = { git = "https://github.com/bytecodealliance/wasmtime.git", optional = true }
+cranelift-object = { git = "https://github.com/bytecodealliance/wasmtime.git" }
target-lexicon = "0.12.0"
-gimli = { version = "0.24.0", default-features = false, features = ["write"]}
-object = { version = "0.25.0", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] }
+gimli = { version = "0.25.0", default-features = false, features = ["write"]}
+object = { version = "0.26.0", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] }
ar = { git = "https://github.com/bjorn3/rust-ar.git", branch = "do_not_remove_cg_clif_ranlib" }
indexmap = "1.0.2"
@@ -37,7 +36,8 @@
#gimli = { path = "../" }
[features]
-default = ["jit", "inline_asm"]
+# Enable features not ready to be enabled when compiling as part of rustc
+unstable-features = ["jit", "inline_asm"]
jit = ["cranelift-jit", "libloading"]
inline_asm = []
diff --git a/compiler/rustc_codegen_cranelift/build_sysroot/Cargo.lock b/compiler/rustc_codegen_cranelift/build_sysroot/Cargo.lock
index 46f6611..e068f08 100644
--- a/compiler/rustc_codegen_cranelift/build_sysroot/Cargo.lock
+++ b/compiler/rustc_codegen_cranelift/build_sysroot/Cargo.lock
@@ -40,9 +40,9 @@
[[package]]
name = "cc"
-version = "1.0.68"
+version = "1.0.69"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4a72c244c1ff497a746a7e1fb3d14bd08420ecda70c8f25c7112f2781652d787"
+checksum = "e70cc2f62c6ce1868963827bd677764c62d07c3d9a3e1fb1177ee1a9ab199eb2"
[[package]]
name = "cfg-if"
@@ -132,9 +132,9 @@
[[package]]
name = "libc"
-version = "0.2.97"
+version = "0.2.98"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "12b8adadd720df158f4d70dfe7ccc6adb0472d7c55ca83445f6a5ab3e36f8fb6"
+checksum = "320cfe77175da3a483efed4bc0adc1968ca050b098ce4f2f1c13a56626128790"
dependencies = [
"rustc-std-workspace-core",
]
@@ -271,14 +271,6 @@
]
[[package]]
-name = "term"
-version = "0.0.0"
-dependencies = [
- "core",
- "std",
-]
-
-[[package]]
name = "test"
version = "0.0.0"
dependencies = [
@@ -290,7 +282,6 @@
"panic_unwind",
"proc_macro",
"std",
- "term",
]
[[package]]
diff --git a/compiler/rustc_codegen_cranelift/build_sysroot/Cargo.toml b/compiler/rustc_codegen_cranelift/build_sysroot/Cargo.toml
index 04748d5..f25d87e 100644
--- a/compiler/rustc_codegen_cranelift/build_sysroot/Cargo.toml
+++ b/compiler/rustc_codegen_cranelift/build_sysroot/Cargo.toml
@@ -1,5 +1,4 @@
[package]
-authors = ["bjorn3 <[email protected]>"]
name = "sysroot"
version = "0.0.0"
diff --git a/compiler/rustc_codegen_cranelift/build_system/build_backend.rs b/compiler/rustc_codegen_cranelift/build_system/build_backend.rs
index 1df2bcc..150b6d01 100644
--- a/compiler/rustc_codegen_cranelift/build_system/build_backend.rs
+++ b/compiler/rustc_codegen_cranelift/build_system/build_backend.rs
@@ -4,7 +4,7 @@
pub(crate) fn build_backend(channel: &str, host_triple: &str) -> PathBuf {
let mut cmd = Command::new("cargo");
- cmd.arg("build").arg("--target").arg(host_triple);
+ cmd.arg("build").arg("--target").arg(host_triple).arg("--features").arg("unstable-features");
match channel {
"debug" => {}
diff --git a/compiler/rustc_codegen_cranelift/build_system/build_sysroot.rs b/compiler/rustc_codegen_cranelift/build_system/build_sysroot.rs
index 9fb88c2..642abc4 100644
--- a/compiler/rustc_codegen_cranelift/build_system/build_sysroot.rs
+++ b/compiler/rustc_codegen_cranelift/build_system/build_sysroot.rs
@@ -91,7 +91,9 @@
{
let file = file.unwrap().path();
let file_name_str = file.file_name().unwrap().to_str().unwrap();
- if file_name_str.contains("rustc_")
+ if (file_name_str.contains("rustc_")
+ && !file_name_str.contains("rustc_std_workspace_")
+ && !file_name_str.contains("rustc_demangle"))
|| file_name_str.contains("chalk")
|| file_name_str.contains("tracing")
|| file_name_str.contains("regex")
diff --git a/compiler/rustc_codegen_cranelift/build_system/prepare.rs b/compiler/rustc_codegen_cranelift/build_system/prepare.rs
index 401b827..4b2051b 100644
--- a/compiler/rustc_codegen_cranelift/build_system/prepare.rs
+++ b/compiler/rustc_codegen_cranelift/build_system/prepare.rs
@@ -28,6 +28,13 @@
);
clone_repo(
+ "stdsimd",
+ "https://github.com/rust-lang/stdsimd",
+ "be96995d8ddec03fac9a0caf4d4c51c7fbc33507",
+ );
+ apply_patches("stdsimd", Path::new("stdsimd"));
+
+ clone_repo(
"simple-raytracer",
"https://github.com/ebobby/simple-raytracer",
"804a7a21b9e673a482797aa289a18ed480e4d813",
@@ -60,11 +67,7 @@
copy_dir_recursively(&sysroot_src_orig.join("library"), &sysroot_src.join("library"));
let rustc_version = get_rustc_version();
- fs::write(
- Path::new("build_sysroot").join("rustc_version"),
- &rustc_version,
- )
- .unwrap();
+ fs::write(Path::new("build_sysroot").join("rustc_version"), &rustc_version).unwrap();
eprintln!("[GIT] init");
let mut git_init_cmd = Command::new("git");
diff --git a/compiler/rustc_codegen_cranelift/clean_all.sh b/compiler/rustc_codegen_cranelift/clean_all.sh
index f4f8c82..23e5bf2 100755
--- a/compiler/rustc_codegen_cranelift/clean_all.sh
+++ b/compiler/rustc_codegen_cranelift/clean_all.sh
@@ -3,4 +3,4 @@
rm -rf build_sysroot/{sysroot_src/,target/,compiler-builtins/,rustc_version}
rm -rf target/ build/ perf.data{,.old}
-rm -rf rand/ regex/ simple-raytracer/
+rm -rf rand/ regex/ simple-raytracer/ stdsimd/
diff --git a/compiler/rustc_codegen_cranelift/docs/usage.md b/compiler/rustc_codegen_cranelift/docs/usage.md
index 956d590..87eec0e 100644
--- a/compiler/rustc_codegen_cranelift/docs/usage.md
+++ b/compiler/rustc_codegen_cranelift/docs/usage.md
@@ -36,7 +36,7 @@
or
```bash
-$ $cg_clif_dir/build/bin/cg_clif -Cllvm-args=mode=jit -Cprefer-dynamic my_crate.rs
+$ $cg_clif_dir/build/bin/cg_clif -Zunstable-features -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
@@ -52,7 +52,7 @@
```bash
function jit_naked() {
- echo "$@" | $cg_clif_dir/build/bin/cg_clif - -Cllvm-args=mode=jit -Cprefer-dynamic
+ echo "$@" | $cg_clif_dir/build/bin/cg_clif - -Zunstable-features -Cllvm-args=mode=jit -Cprefer-dynamic
}
function jit() {
diff --git a/compiler/rustc_codegen_cranelift/example/alloc_example.rs b/compiler/rustc_codegen_cranelift/example/alloc_example.rs
index 71e93e8..2a9f7e5 100644
--- a/compiler/rustc_codegen_cranelift/example/alloc_example.rs
+++ b/compiler/rustc_codegen_cranelift/example/alloc_example.rs
@@ -1,4 +1,4 @@
-#![feature(start, box_syntax, core_intrinsics, alloc_prelude, alloc_error_handler)]
+#![feature(start, core_intrinsics, alloc_prelude, alloc_error_handler)]
#![no_std]
extern crate alloc;
diff --git a/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs b/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs
index d997ce6..6e13e4d 100644
--- a/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs
+++ b/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs
@@ -1,4 +1,4 @@
-#![feature(no_core, lang_items, box_syntax, never_type, linkage, extern_types, thread_local)]
+#![feature(no_core, lang_items, never_type, linkage, extern_types, thread_local)]
#![no_core]
#![allow(dead_code, non_camel_case_types)]
diff --git a/compiler/rustc_codegen_cranelift/example/mod_bench.rs b/compiler/rustc_codegen_cranelift/example/mod_bench.rs
index 152041a..e3e8a3c 100644
--- a/compiler/rustc_codegen_cranelift/example/mod_bench.rs
+++ b/compiler/rustc_codegen_cranelift/example/mod_bench.rs
@@ -1,4 +1,4 @@
-#![feature(start, box_syntax, core_intrinsics, lang_items)]
+#![feature(start, core_intrinsics, lang_items)]
#![no_std]
#[cfg_attr(unix, link(name = "c"))]
diff --git a/compiler/rustc_codegen_cranelift/patches/0001-stdsimd-Disable-unsupported-tests.patch b/compiler/rustc_codegen_cranelift/patches/0001-stdsimd-Disable-unsupported-tests.patch
new file mode 100644
index 0000000..731c60f
--- /dev/null
+++ b/compiler/rustc_codegen_cranelift/patches/0001-stdsimd-Disable-unsupported-tests.patch
@@ -0,0 +1,165 @@
+From 6bfce5dc2cbf834c74dbccb7538adc08c6eb57e7 Mon Sep 17 00:00:00 2001
+From: bjorn3 <[email protected]>
+Date: Sun, 25 Jul 2021 18:39:31 +0200
+Subject: [PATCH] Disable unsupported tests
+
+---
+ crates/core_simd/src/array.rs | 2 ++
+ crates/core_simd/src/lib.rs | 2 +-
+ crates/core_simd/src/math.rs | 4 ++++
+ crates/core_simd/tests/masks.rs | 12 ------------
+ crates/core_simd/tests/ops_macros.rs | 6 ++++++
+ crates/core_simd/tests/round.rs | 2 ++
+ 6 files changed, 15 insertions(+), 13 deletions(-)
+
+diff --git a/crates/core_simd/src/array.rs b/crates/core_simd/src/array.rs
+index 25c5309..2b3d819 100644
+--- a/crates/core_simd/src/array.rs
++++ b/crates/core_simd/src/array.rs
+@@ -22,6 +22,7 @@ where
+ #[must_use]
+ fn splat(val: Self::Scalar) -> Self;
+
++ /*
+ /// SIMD gather: construct a SIMD vector by reading from a slice, using potentially discontiguous indices.
+ /// If an index is out of bounds, that lane instead selects the value from the "or" vector.
+ /// ```
+@@ -150,6 +151,7 @@ where
+ // Cleared ☢️ *mut T Zone
+ }
+ }
++ */
+ }
+
+ macro_rules! impl_simdarray_for {
+diff --git a/crates/core_simd/src/lib.rs b/crates/core_simd/src/lib.rs
+index a64904d..299eb11 100644
+--- a/crates/core_simd/src/lib.rs
++++ b/crates/core_simd/src/lib.rs
+@@ -1,7 +1,7 @@
+ #![no_std]
+ #![allow(incomplete_features)]
+ #![feature(
+- const_generics,
++ const_generics,
+ platform_intrinsics,
+ repr_simd,
+ simd_ffi,
+diff --git a/crates/core_simd/src/math.rs b/crates/core_simd/src/math.rs
+index 7290a28..e394730 100644
+--- a/crates/core_simd/src/math.rs
++++ b/crates/core_simd/src/math.rs
+@@ -2,6 +2,7 @@ macro_rules! impl_uint_arith {
+ ($(($name:ident, $n:ident)),+) => {
+ $( impl<const LANES: usize> $name<LANES> where Self: crate::LanesAtMost32 {
+
++ /*
+ /// Lanewise saturating add.
+ ///
+ /// # Examples
+@@ -38,6 +39,7 @@ macro_rules! impl_uint_arith {
+ pub fn saturating_sub(self, second: Self) -> Self {
+ unsafe { crate::intrinsics::simd_saturating_sub(self, second) }
+ }
++ */
+ })+
+ }
+ }
+@@ -46,6 +48,7 @@ macro_rules! impl_int_arith {
+ ($(($name:ident, $n:ident)),+) => {
+ $( impl<const LANES: usize> $name<LANES> where Self: crate::LanesAtMost32 {
+
++ /*
+ /// Lanewise saturating add.
+ ///
+ /// # Examples
+@@ -141,6 +144,7 @@ macro_rules! impl_int_arith {
+ pub fn saturating_neg(self) -> Self {
+ Self::splat(0).saturating_sub(self)
+ }
++ */
+ })+
+ }
+ }
+diff --git a/crates/core_simd/tests/masks.rs b/crates/core_simd/tests/masks.rs
+index 61d8e44..2bccae2 100644
+--- a/crates/core_simd/tests/masks.rs
++++ b/crates/core_simd/tests/masks.rs
+@@ -67,18 +67,6 @@ macro_rules! test_mask_api {
+ assert_eq!(int.to_array(), [-1, 0, 0, -1, 0, 0, -1, 0]);
+ assert_eq!(core_simd::$name::<8>::from_int(int), mask);
+ }
+-
+- #[test]
+- fn roundtrip_bitmask_conversion() {
+- let values = [
+- true, false, false, true, false, false, true, false,
+- true, true, false, false, false, false, false, true,
+- ];
+- let mask = core_simd::$name::<16>::from_array(values);
+- let bitmask = mask.to_bitmask();
+- assert_eq!(bitmask, [0b01001001, 0b10000011]);
+- assert_eq!(core_simd::$name::<16>::from_bitmask(bitmask), mask);
+- }
+ }
+ }
+ }
+diff --git a/crates/core_simd/tests/ops_macros.rs b/crates/core_simd/tests/ops_macros.rs
+index cb39e73..fc0ebe1 100644
+--- a/crates/core_simd/tests/ops_macros.rs
++++ b/crates/core_simd/tests/ops_macros.rs
+@@ -435,6 +435,7 @@ macro_rules! impl_float_tests {
+ )
+ }
+
++ /*
+ fn mul_add<const LANES: usize>() {
+ test_helpers::test_ternary_elementwise(
+ &Vector::<LANES>::mul_add,
+@@ -442,6 +443,7 @@ macro_rules! impl_float_tests {
+ &|_, _, _| true,
+ )
+ }
++ */
+
+ fn sqrt<const LANES: usize>() {
+ test_helpers::test_unary_elementwise(
+@@ -581,6 +585,7 @@ macro_rules! impl_float_tests {
+ });
+ }
+
++ /*
+ fn horizontal_max<const LANES: usize>() {
+ test_helpers::test_1(&|x| {
+ let vmax = Vector::<LANES>::from_array(x).horizontal_max();
+@@ -604,6 +609,7 @@ macro_rules! impl_float_tests {
+ Ok(())
+ });
+ }
++ */
+ }
+ }
+ }
+diff --git a/crates/core_simd/tests/round.rs b/crates/core_simd/tests/round.rs
+index 37044a7..4cdc6b7 100644
+--- a/crates/core_simd/tests/round.rs
++++ b/crates/core_simd/tests/round.rs
+@@ -25,6 +25,7 @@ macro_rules! float_rounding_test {
+ )
+ }
+
++ /*
+ fn round<const LANES: usize>() {
+ test_helpers::test_unary_elementwise(
+ &Vector::<LANES>::round,
+@@ -32,6 +33,7 @@ macro_rules! float_rounding_test {
+ &|_| true,
+ )
+ }
++ */
+
+ fn trunc<const LANES: usize>() {
+ test_helpers::test_unary_elementwise(
+--
+2.26.2.7.g19db9cfb68
+
diff --git a/compiler/rustc_codegen_cranelift/patches/0022-sysroot-Disable-not-compiling-tests.patch b/compiler/rustc_codegen_cranelift/patches/0022-sysroot-Disable-not-compiling-tests.patch
index ba0eaac..25a315f 100644
--- a/compiler/rustc_codegen_cranelift/patches/0022-sysroot-Disable-not-compiling-tests.patch
+++ b/compiler/rustc_codegen_cranelift/patches/0022-sysroot-Disable-not-compiling-tests.patch
@@ -51,14 +51,14 @@
#[test]
#[allow(warnings)]
// Have a symbol for the test below. It doesn’t need to be an actual variadic function, match the
-@@ -289,6 +290,7 @@ fn write_unaligned_drop() {
- }
- DROPS.with(|d| assert_eq!(*d.borrow(), [0]));
+@@ -277,6 +277,7 @@ pub fn test_variadic_fnptr() {
+ let mut s = SipHasher::new();
+ assert_eq!(p.hash(&mut s), q.hash(&mut s));
}
+*/
#[test]
- fn align_offset_zst() {
+ fn write_unaligned_drop() {
diff --git a/library/core/tests/slice.rs b/library/core/tests/slice.rs
index 6609bc3..241b497 100644
--- a/library/core/tests/slice.rs
diff --git a/compiler/rustc_codegen_cranelift/patches/0023-sysroot-Ignore-failing-tests.patch b/compiler/rustc_codegen_cranelift/patches/0023-sysroot-Ignore-failing-tests.patch
index 5d2c304..50ef0bd 100644
--- a/compiler/rustc_codegen_cranelift/patches/0023-sysroot-Ignore-failing-tests.patch
+++ b/compiler/rustc_codegen_cranelift/patches/0023-sysroot-Ignore-failing-tests.patch
@@ -46,45 +46,5 @@
#[test]
fn cell_allows_array_cycle() {
-diff --git a/library/core/tests/num/mod.rs b/library/core/tests/num/mod.rs
-index a17c094..5bb11d2 100644
---- a/library/core/tests/num/mod.rs
-+++ b/library/core/tests/num/mod.rs
-@@ -651,11 +651,12 @@ macro_rules! test_float {
- assert_eq!((9.0 as $fty).min($neginf), $neginf);
- assert_eq!(($neginf as $fty).min(-9.0), $neginf);
- assert_eq!((-9.0 as $fty).min($neginf), $neginf);
-- assert_eq!(($nan as $fty).min(9.0), 9.0);
-- assert_eq!(($nan as $fty).min(-9.0), -9.0);
-- assert_eq!((9.0 as $fty).min($nan), 9.0);
-- assert_eq!((-9.0 as $fty).min($nan), -9.0);
-- assert!(($nan as $fty).min($nan).is_nan());
-+ // Cranelift fmin has NaN propagation
-+ //assert_eq!(($nan as $fty).min(9.0), 9.0);
-+ //assert_eq!(($nan as $fty).min(-9.0), -9.0);
-+ //assert_eq!((9.0 as $fty).min($nan), 9.0);
-+ //assert_eq!((-9.0 as $fty).min($nan), -9.0);
-+ //assert!(($nan as $fty).min($nan).is_nan());
- }
- #[test]
- fn max() {
-@@ -673,11 +674,12 @@ macro_rules! test_float {
- assert_eq!((9.0 as $fty).max($neginf), 9.0);
- assert_eq!(($neginf as $fty).max(-9.0), -9.0);
- assert_eq!((-9.0 as $fty).max($neginf), -9.0);
-- assert_eq!(($nan as $fty).max(9.0), 9.0);
-- assert_eq!(($nan as $fty).max(-9.0), -9.0);
-- assert_eq!((9.0 as $fty).max($nan), 9.0);
-- assert_eq!((-9.0 as $fty).max($nan), -9.0);
-- assert!(($nan as $fty).max($nan).is_nan());
-+ // Cranelift fmax has NaN propagation
-+ //assert_eq!(($nan as $fty).max(9.0), 9.0);
-+ //assert_eq!(($nan as $fty).max(-9.0), -9.0);
-+ //assert_eq!((9.0 as $fty).max($nan), 9.0);
-+ //assert_eq!((-9.0 as $fty).max($nan), -9.0);
-+ //assert!(($nan as $fty).max($nan).is_nan());
- }
- #[test]
- fn rem_euclid() {
--
2.21.0 (Apple Git-122)
diff --git a/compiler/rustc_codegen_cranelift/patches/0027-sysroot-128bit-atomic-operations.patch b/compiler/rustc_codegen_cranelift/patches/0027-sysroot-128bit-atomic-operations.patch
index 32e5930..cda8153 100644
--- a/compiler/rustc_codegen_cranelift/patches/0027-sysroot-128bit-atomic-operations.patch
+++ b/compiler/rustc_codegen_cranelift/patches/0027-sysroot-128bit-atomic-operations.patch
@@ -1,20 +1,44 @@
-From 894e07dfec2624ba539129b1c1d63e1d7d812bda Mon Sep 17 00:00:00 2001
+From 6a4e6f5dc8c8a529a822eb9b57f9e57519595439 Mon Sep 17 00:00:00 2001
From: bjorn3 <[email protected]>
Date: Thu, 18 Feb 2021 18:45:28 +0100
Subject: [PATCH] Disable 128bit atomic operations
Cranelift doesn't support them yet
---
- library/core/src/sync/atomic.rs | 38 ---------------------------------
- library/core/tests/atomic.rs | 4 ----
- library/std/src/panic.rs | 6 ------
+ library/core/src/panic/unwind_safe.rs | 6 -----
+ library/core/src/sync/atomic.rs | 38 ---------------------------
+ library/core/tests/atomic.rs | 4 ---
3 files changed, 48 deletions(-)
+diff --git a/library/core/src/panic/unwind_safe.rs b/library/core/src/panic/unwind_safe.rs
+index 092b7cf..158cf71 100644
+--- a/library/core/src/panic/unwind_safe.rs
++++ b/library/core/src/panic/unwind_safe.rs
+@@ -216,9 +216,6 @@ impl RefUnwindSafe for crate::sync::atomic::AtomicI32 {}
+ #[cfg(target_has_atomic_load_store = "64")]
+ #[stable(feature = "integer_atomics_stable", since = "1.34.0")]
+ impl RefUnwindSafe for crate::sync::atomic::AtomicI64 {}
+-#[cfg(target_has_atomic_load_store = "128")]
+-#[unstable(feature = "integer_atomics", issue = "32976")]
+-impl RefUnwindSafe for crate::sync::atomic::AtomicI128 {}
+
+ #[cfg(target_has_atomic_load_store = "ptr")]
+ #[stable(feature = "unwind_safe_atomic_refs", since = "1.14.0")]
+@@ -235,9 +232,6 @@ impl RefUnwindSafe for crate::sync::atomic::AtomicU32 {}
+ #[cfg(target_has_atomic_load_store = "64")]
+ #[stable(feature = "integer_atomics_stable", since = "1.34.0")]
+ impl RefUnwindSafe for crate::sync::atomic::AtomicU64 {}
+-#[cfg(target_has_atomic_load_store = "128")]
+-#[unstable(feature = "integer_atomics", issue = "32976")]
+-impl RefUnwindSafe for crate::sync::atomic::AtomicU128 {}
+
+ #[cfg(target_has_atomic_load_store = "8")]
+ #[stable(feature = "unwind_safe_atomic_refs", since = "1.14.0")]
diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs
-index 81c9e1d..65c9503 100644
+index 0194c58..25a0038 100644
--- a/library/core/src/sync/atomic.rs
+++ b/library/core/src/sync/atomic.rs
-@@ -2228,44 +2228,6 @@ atomic_int! {
+@@ -2229,44 +2229,6 @@ atomic_int! {
"AtomicU64::new(0)",
u64 AtomicU64 ATOMIC_U64_INIT
}
@@ -60,10 +84,10 @@
macro_rules! atomic_int_ptr_sized {
( $($target_pointer_width:literal $align:literal)* ) => { $(
diff --git a/library/core/tests/atomic.rs b/library/core/tests/atomic.rs
-index 2d1e449..cb6da5d 100644
+index b735957..ea728b6 100644
--- a/library/core/tests/atomic.rs
+++ b/library/core/tests/atomic.rs
-@@ -145,10 +145,6 @@ fn atomic_alignment() {
+@@ -185,10 +185,6 @@ fn atomic_alignment() {
assert_eq!(align_of::<AtomicU64>(), size_of::<AtomicU64>());
#[cfg(target_has_atomic = "64")]
assert_eq!(align_of::<AtomicI64>(), size_of::<AtomicI64>());
@@ -74,30 +98,6 @@
#[cfg(target_has_atomic = "ptr")]
assert_eq!(align_of::<AtomicUsize>(), size_of::<AtomicUsize>());
#[cfg(target_has_atomic = "ptr")]
-diff --git a/library/std/src/panic.rs b/library/std/src/panic.rs
-index 89a822a..779fd88 100644
---- a/library/std/src/panic.rs
-+++ b/library/std/src/panic.rs
-@@ -279,9 +279,6 @@ impl RefUnwindSafe for atomic::AtomicI32 {}
- #[cfg(target_has_atomic_load_store = "64")]
- #[stable(feature = "integer_atomics_stable", since = "1.34.0")]
- impl RefUnwindSafe for atomic::AtomicI64 {}
--#[cfg(target_has_atomic_load_store = "128")]
--#[unstable(feature = "integer_atomics", issue = "32976")]
--impl RefUnwindSafe for atomic::AtomicI128 {}
-
- #[cfg(target_has_atomic_load_store = "ptr")]
- #[stable(feature = "unwind_safe_atomic_refs", since = "1.14.0")]
-@@ -298,9 +295,6 @@ impl RefUnwindSafe for atomic::AtomicU32 {}
- #[cfg(target_has_atomic_load_store = "64")]
- #[stable(feature = "integer_atomics_stable", since = "1.34.0")]
- impl RefUnwindSafe for atomic::AtomicU64 {}
--#[cfg(target_has_atomic_load_store = "128")]
--#[unstable(feature = "integer_atomics", issue = "32976")]
--impl RefUnwindSafe for atomic::AtomicU128 {}
-
- #[cfg(target_has_atomic_load_store = "8")]
- #[stable(feature = "unwind_safe_atomic_refs", since = "1.14.0")]
--
2.26.2.7.g19db9cfb68
diff --git a/compiler/rustc_codegen_cranelift/rust-toolchain b/compiler/rustc_codegen_cranelift/rust-toolchain
index f806f7b..f074ebe 100644
--- a/compiler/rustc_codegen_cranelift/rust-toolchain
+++ b/compiler/rustc_codegen_cranelift/rust-toolchain
@@ -1,3 +1,3 @@
[toolchain]
-channel = "nightly-2021-07-07"
+channel = "nightly-2021-08-05"
components = ["rust-src", "rustc-dev", "llvm-tools-preview"]
diff --git a/compiler/rustc_codegen_cranelift/scripts/cargo.rs b/compiler/rustc_codegen_cranelift/scripts/cargo.rs
index b7e8dd4..89ec8da 100644
--- a/compiler/rustc_codegen_cranelift/scripts/cargo.rs
+++ b/compiler/rustc_codegen_cranelift/scripts/cargo.rs
@@ -44,7 +44,11 @@
);
std::array::IntoIter::new(["rustc".to_string()])
.chain(env::args().skip(2))
- .chain(["--".to_string(), "-Cllvm-args=mode=jit".to_string()])
+ .chain([
+ "--".to_string(),
+ "-Zunstable-features".to_string(),
+ "-Cllvm-args=mode=jit".to_string(),
+ ])
.collect()
}
Some("lazy-jit") => {
@@ -54,7 +58,11 @@
);
std::array::IntoIter::new(["rustc".to_string()])
.chain(env::args().skip(2))
- .chain(["--".to_string(), "-Cllvm-args=mode=jit-lazy".to_string()])
+ .chain([
+ "--".to_string(),
+ "-Zunstable-features".to_string(),
+ "-Cllvm-args=mode=jit-lazy".to_string(),
+ ])
.collect()
}
_ => env::args().skip(1).collect(),
diff --git a/compiler/rustc_codegen_cranelift/scripts/filter_profile.rs b/compiler/rustc_codegen_cranelift/scripts/filter_profile.rs
index 9e196af..c4801a0a 100755
--- a/compiler/rustc_codegen_cranelift/scripts/filter_profile.rs
+++ b/compiler/rustc_codegen_cranelift/scripts/filter_profile.rs
@@ -5,7 +5,7 @@
source scripts/config.sh
RUSTC="$(pwd)/build/bin/cg_clif"
popd
-PROFILE=$1 OUTPUT=$2 exec $RUSTC -Cllvm-args=mode=jit -Cprefer-dynamic $0
+PROFILE=$1 OUTPUT=$2 exec $RUSTC -Zunstable-options -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/setup_rust_fork.sh b/compiler/rustc_codegen_cranelift/scripts/setup_rust_fork.sh
index 52adaaa..ca83e70 100644
--- a/compiler/rustc_codegen_cranelift/scripts/setup_rust_fork.sh
+++ b/compiler/rustc_codegen_cranelift/scripts/setup_rust_fork.sh
@@ -33,7 +33,7 @@
[dependencies]
core = { path = "../core" }
-compiler_builtins = { version = "0.1.40", features = ['rustc-dep-of-std'] }
-+compiler_builtins = { version = "0.1.45", features = ['rustc-dep-of-std', 'no-asm'] }
++compiler_builtins = { version = "0.1.46", features = ['rustc-dep-of-std', 'no-asm'] }
[dev-dependencies]
rand = "0.7"
diff --git a/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh b/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh
index 2f5c2cf..0ac49dd 100755
--- a/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh
+++ b/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh
@@ -79,7 +79,6 @@
rm src/test/ui/allocator/no_std-alloc-error-handler-default.rs # missing rust_oom definition
rm src/test/ui/cfg/cfg-panic.rs
-rm src/test/ui/default-alloc-error-hook.rs
rm -r src/test/ui/hygiene/
rm -r src/test/ui/polymorphization/ # polymorphization not yet supported
diff --git a/compiler/rustc_codegen_cranelift/scripts/tests.sh b/compiler/rustc_codegen_cranelift/scripts/tests.sh
index 5df04c5..0eef710 100755
--- a/compiler/rustc_codegen_cranelift/scripts/tests.sh
+++ b/compiler/rustc_codegen_cranelift/scripts/tests.sh
@@ -16,10 +16,10 @@
if [[ "$JIT_SUPPORTED" = "1" ]]; then
echo "[JIT] mini_core_hello_world"
- 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"
+ CG_CLIF_JIT_ARGS="abc bcd" $MY_RUSTC -Zunstable-options -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"
+ CG_CLIF_JIT_ARGS="abc bcd" $MY_RUSTC -Zunstable-options -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
@@ -44,10 +44,10 @@
if [[ "$JIT_SUPPORTED" = "1" ]]; then
echo "[JIT] std_example"
- $MY_RUSTC -Cllvm-args=mode=jit -Cprefer-dynamic example/std_example.rs --target "$HOST_TRIPLE"
+ $MY_RUSTC -Zunstable-options -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 --target "$HOST_TRIPLE"
+ $MY_RUSTC -Zunstable-options -Cllvm-args=mode=jit-lazy -Cprefer-dynamic example/std_example.rs --target "$HOST_TRIPLE"
else
echo "[JIT] std_example (skipped)"
fi
@@ -136,6 +136,15 @@
../build/cargo build --tests --target $TARGET_TRIPLE
fi
popd
+
+ pushd stdsimd
+ echo "[TEST] rust-lang/stdsimd"
+ ../build/cargo clean
+ ../build/cargo build --all-targets --target $TARGET_TRIPLE
+ if [[ "$HOST_TRIPLE" = "$TARGET_TRIPLE" ]]; then
+ ../build/cargo test -q
+ fi
+ popd
}
case "$1" in
diff --git a/compiler/rustc_codegen_cranelift/src/abi/mod.rs b/compiler/rustc_codegen_cranelift/src/abi/mod.rs
index 54c8fb0..13790409 100644
--- a/compiler/rustc_codegen_cranelift/src/abi/mod.rs
+++ b/compiler/rustc_codegen_cranelift/src/abi/mod.rs
@@ -9,13 +9,12 @@
use rustc_target::abi::call::{Conv, FnAbi};
use rustc_target::spec::abi::Abi;
-use cranelift_codegen::ir::AbiParam;
-use smallvec::smallvec;
+use cranelift_codegen::ir::{AbiParam, SigRef};
use self::pass_mode::*;
use crate::prelude::*;
-pub(crate) use self::returning::{can_return_to_ssa_var, codegen_return};
+pub(crate) use self::returning::codegen_return;
fn clif_sig_from_fn_abi<'tcx>(
tcx: TyCtxt<'tcx>,
@@ -236,27 +235,20 @@
// not mutated by the current function, this is necessary to support unsized arguments.
if let ArgKind::Normal(Some(val)) = arg_kind {
if let Some((addr, meta)) = val.try_to_ptr() {
- let local_decl = &fx.mir.local_decls[local];
- // v this ! is important
- let internally_mutable = !val
- .layout()
- .ty
- .is_freeze(fx.tcx.at(local_decl.source_info.span), ParamEnv::reveal_all());
- if local_decl.mutability == mir::Mutability::Not && !internally_mutable {
- // We wont mutate this argument, so it is fine to borrow the backing storage
- // of this argument, to prevent a copy.
+ // Ownership of the value at the backing storage for an argument is passed to the
+ // callee per the ABI, so it is fine to borrow the backing storage of this argument
+ // to prevent a copy.
- let place = if let Some(meta) = meta {
- CPlace::for_ptr_with_extra(addr, meta, val.layout())
- } else {
- CPlace::for_ptr(addr, val.layout())
- };
+ let place = if let Some(meta) = meta {
+ CPlace::for_ptr_with_extra(addr, meta, val.layout())
+ } else {
+ CPlace::for_ptr(addr, val.layout())
+ };
- self::comments::add_local_place_comments(fx, place, local);
+ self::comments::add_local_place_comments(fx, place, local);
- assert_eq!(fx.local_map.push(place), local);
- continue;
- }
+ assert_eq!(fx.local_map.push(place), local);
+ continue;
}
}
@@ -292,6 +284,22 @@
fx.bcx.ins().jump(*fx.block_map.get(START_BLOCK).unwrap(), &[]);
}
+struct CallArgument<'tcx> {
+ value: CValue<'tcx>,
+ is_owned: bool,
+}
+
+// FIXME avoid intermediate `CValue` before calling `adjust_arg_for_abi`
+fn codegen_call_argument_operand<'tcx>(
+ fx: &mut FunctionCx<'_, '_, 'tcx>,
+ operand: &Operand<'tcx>,
+) -> CallArgument<'tcx> {
+ CallArgument {
+ value: codegen_operand(fx, operand),
+ is_owned: matches!(operand, Operand::Move(_)),
+ }
+}
+
pub(crate) fn codegen_terminator_call<'tcx>(
fx: &mut FunctionCx<'_, '_, 'tcx>,
span: Span,
@@ -360,12 +368,12 @@
}
// Unpack arguments tuple for closures
- let args = if fn_sig.abi == Abi::RustCall {
+ let mut args = if fn_sig.abi == Abi::RustCall {
assert_eq!(args.len(), 2, "rust-call abi requires two arguments");
- let self_arg = codegen_operand(fx, &args[0]);
- let pack_arg = codegen_operand(fx, &args[1]);
+ let self_arg = codegen_call_argument_operand(fx, &args[0]);
+ let pack_arg = codegen_call_argument_operand(fx, &args[1]);
- let tupled_arguments = match pack_arg.layout().ty.kind() {
+ let tupled_arguments = match pack_arg.value.layout().ty.kind() {
ty::Tuple(ref tupled_arguments) => tupled_arguments,
_ => bug!("argument to function with \"rust-call\" ABI is not a tuple"),
};
@@ -373,37 +381,53 @@
let mut args = Vec::with_capacity(1 + tupled_arguments.len());
args.push(self_arg);
for i in 0..tupled_arguments.len() {
- args.push(pack_arg.value_field(fx, mir::Field::new(i)));
+ args.push(CallArgument {
+ value: pack_arg.value.value_field(fx, mir::Field::new(i)),
+ is_owned: pack_arg.is_owned,
+ });
}
args
} else {
- args.iter().map(|arg| codegen_operand(fx, arg)).collect::<Vec<_>>()
+ args.iter().map(|arg| codegen_call_argument_operand(fx, arg)).collect::<Vec<_>>()
};
- // | indirect call target
- // | | the first argument to be passed
- // v v
- let (func_ref, first_arg) = match instance {
+ // Pass the caller location for `#[track_caller]`.
+ if instance.map(|inst| inst.def.requires_caller_location(fx.tcx)).unwrap_or(false) {
+ let caller_location = fx.get_caller_location(span);
+ args.push(CallArgument { value: caller_location, is_owned: false });
+ }
+
+ let args = args;
+ assert_eq!(fn_abi.args.len(), args.len());
+
+ enum CallTarget {
+ Direct(FuncRef),
+ Indirect(SigRef, Value),
+ }
+
+ let (func_ref, first_arg_override) = match instance {
// Trait object call
Some(Instance { def: InstanceDef::Virtual(_, idx), .. }) => {
if fx.clif_comments.enabled() {
let nop_inst = fx.bcx.ins().nop();
fx.add_comment(
nop_inst,
- format!("virtual call; self arg pass mode: {:?}", &fn_abi.args[0],),
+ 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), smallvec![ptr])
+
+ let (ptr, method) = crate::vtable::get_ptr_and_method_ref(fx, args[0].value, idx);
+ let sig = clif_sig_from_fn_abi(fx.tcx, fx.triple(), &fn_abi);
+ let sig = fx.bcx.import_signature(sig);
+
+ (CallTarget::Indirect(sig, method), Some(ptr))
}
// Normal call
- Some(_) => (
- None,
- args.get(0)
- .map(|arg| adjust_arg_for_abi(fx, *arg, &fn_abi.args[0]))
- .unwrap_or(smallvec![]),
- ),
+ Some(instance) => {
+ let func_ref = fx.get_function_ref(instance);
+ (CallTarget::Direct(func_ref), None)
+ }
// Indirect call
None => {
@@ -411,80 +435,64 @@
let nop_inst = fx.bcx.ins().nop();
fx.add_comment(nop_inst, "indirect call");
}
+
let func = codegen_operand(fx, func).load_scalar(fx);
- (
- Some(func),
- args.get(0)
- .map(|arg| adjust_arg_for_abi(fx, *arg, &fn_abi.args[0]))
- .unwrap_or(smallvec![]),
- )
+ let sig = clif_sig_from_fn_abi(fx.tcx, fx.triple(), &fn_abi);
+ let sig = fx.bcx.import_signature(sig);
+
+ (CallTarget::Indirect(sig, func), None)
}
};
let ret_place = destination.map(|(place, _)| place);
- 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(|(i, arg)| adjust_arg_for_abi(fx, arg, &fn_abi.args[i]).into_iter())
- .flatten(),
- )
- .collect::<Vec<_>>();
-
- if instance.map(|inst| inst.def.requires_caller_location(fx.tcx)).unwrap_or(false) {
- // 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, &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_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 {
- let func_ref =
- fx.get_function_ref(instance.expect("non-indirect call on non-FnDef type"));
- fx.bcx.ins().call(func_ref, &call_args)
- };
-
- (call_inst, call_args)
- },
- );
-
- // FIXME find a cleaner way to support varargs
- if fn_sig.c_variadic {
- if !matches!(fn_sig.abi, Abi::C { .. }) {
- fx.tcx.sess.span_fatal(span, &format!("Variadic call for non-C abi {:?}", fn_sig.abi));
- }
- let sig_ref = fx.bcx.func.dfg.call_signature(call_inst).unwrap();
- let abi_params = call_args
+ self::returning::codegen_with_call_return_arg(fx, &fn_abi.ret, ret_place, |fx, return_ptr| {
+ let call_args = return_ptr
.into_iter()
- .map(|arg| {
- let ty = fx.bcx.func.dfg.value_type(arg);
- if !ty.is_int() {
- // FIXME set %al to upperbound on float args once floats are supported
- fx.tcx.sess.span_fatal(span, &format!("Non int ty {:?} for variadic call", ty));
- }
- AbiParam::new(ty)
- })
- .collect::<Vec<AbiParam>>();
- fx.bcx.func.dfg.signatures[sig_ref].params = abi_params;
- }
+ .chain(first_arg_override.into_iter())
+ .chain(
+ args.into_iter()
+ .enumerate()
+ .skip(if first_arg_override.is_some() { 1 } else { 0 })
+ .map(|(i, arg)| {
+ adjust_arg_for_abi(fx, arg.value, &fn_abi.args[i], arg.is_owned).into_iter()
+ })
+ .flatten(),
+ )
+ .collect::<Vec<Value>>();
+
+ let call_inst = match func_ref {
+ CallTarget::Direct(func_ref) => fx.bcx.ins().call(func_ref, &call_args),
+ CallTarget::Indirect(sig, func_ptr) => {
+ fx.bcx.ins().call_indirect(sig, func_ptr, &call_args)
+ }
+ };
+
+ // FIXME find a cleaner way to support varargs
+ if fn_sig.c_variadic {
+ if !matches!(fn_sig.abi, Abi::C { .. }) {
+ fx.tcx
+ .sess
+ .span_fatal(span, &format!("Variadic call for non-C abi {:?}", fn_sig.abi));
+ }
+ let sig_ref = fx.bcx.func.dfg.call_signature(call_inst).unwrap();
+ let abi_params = call_args
+ .into_iter()
+ .map(|arg| {
+ let ty = fx.bcx.func.dfg.value_type(arg);
+ if !ty.is_int() {
+ // FIXME set %al to upperbound on float args once floats are supported
+ fx.tcx
+ .sess
+ .span_fatal(span, &format!("Non int ty {:?} for variadic call", ty));
+ }
+ AbiParam::new(ty)
+ })
+ .collect::<Vec<AbiParam>>();
+ fx.bcx.func.dfg.signatures[sig_ref].params = abi_params;
+ }
+
+ call_inst
+ });
if let Some((_, dest)) = destination {
let ret_block = fx.get_block(dest);
@@ -535,7 +543,7 @@
TypeAndMut { ty, mutbl: crate::rustc_hir::Mutability::Mut },
)),
);
- let arg_value = adjust_arg_for_abi(fx, arg_value, &fn_abi.args[0]);
+ let arg_value = adjust_arg_for_abi(fx, arg_value, &fn_abi.args[0], true);
let mut call_args: Vec<Value> = arg_value.into_iter().collect::<Vec<_>>();
@@ -543,7 +551,7 @@
// 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, &fn_abi.args[1]).into_iter(),
+ adjust_arg_for_abi(fx, caller_location, &fn_abi.args[1], false).into_iter(),
);
}
diff --git a/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs b/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs
index 7c27596..44eae70 100644
--- a/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs
+++ b/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs
@@ -227,6 +227,7 @@
fx: &mut FunctionCx<'_, '_, 'tcx>,
arg: CValue<'tcx>,
arg_abi: &ArgAbi<'tcx, Ty<'tcx>>,
+ is_owned: bool,
) -> SmallVec<[Value; 2]> {
assert_assignable(fx, arg.layout().ty, arg_abi.layout.ty);
match arg_abi.mode {
@@ -237,10 +238,21 @@
smallvec![a, b]
}
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],
- },
+ PassMode::Indirect { .. } => {
+ if is_owned {
+ match arg.force_stack(fx) {
+ (ptr, None) => smallvec![ptr.get_addr(fx)],
+ (ptr, Some(meta)) => smallvec![ptr.get_addr(fx), meta],
+ }
+ } else {
+ // Ownership of the value at the backing storage for an argument is passed to the
+ // callee per the ABI, so we must make a copy of the argument unless the argument
+ // local is moved.
+ let place = CPlace::new_stack_slot(fx, arg.layout());
+ place.write_cvalue(fx, arg);
+ smallvec![place.to_ptr().get_addr(fx)]
+ }
+ }
}
}
diff --git a/compiler/rustc_codegen_cranelift/src/abi/returning.rs b/compiler/rustc_codegen_cranelift/src/abi/returning.rs
index e1c5322..c1bdba4 100644
--- a/compiler/rustc_codegen_cranelift/src/abi/returning.rs
+++ b/compiler/rustc_codegen_cranelift/src/abi/returning.rs
@@ -2,54 +2,9 @@
use crate::prelude::*;
-use rustc_middle::ty::layout::FnAbiExt;
-use rustc_target::abi::call::{ArgAbi, FnAbi, PassMode};
+use rustc_target::abi::call::{ArgAbi, 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>(
- fx: &FunctionCx<'_, '_, 'tcx>,
- func: &mir::Operand<'tcx>,
- args: &[mir::Operand<'tcx>],
-) -> bool {
- 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,
- }
-}
-
/// Return a place where the return value of the current function can be written to. If necessary
/// this adds an extra parameter pointing to where the return value needs to be stored.
pub(super) fn codegen_return_param<'tcx>(
@@ -58,8 +13,7 @@
block_params_iter: &mut impl Iterator<Item = Value>,
) -> CPlace<'tcx> {
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(_) => {
+ PassMode::Ignore | PassMode::Direct(_) | PassMode::Pair(_, _) | PassMode::Cast(_) => {
let is_ssa = ssa_analyzed[RETURN_PLACE] == crate::analyze::SsaKind::Ssa;
(
super::make_local_place(
@@ -73,7 +27,7 @@
}
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));
+ assert_eq!(fx.bcx.func.dfg.value_type(ret_param), fx.pointer_type);
(
CPlace::for_ptr(Pointer::new(ret_param), fx.fn_abi.as_ref().unwrap().ret.layout),
smallvec![ret_param],
@@ -99,25 +53,33 @@
/// Invokes the closure with if necessary a value representing the return pointer. When the closure
/// returns the call return value(s) if any are written to the correct place.
-pub(super) fn codegen_with_call_return_arg<'tcx, T>(
+pub(super) fn codegen_with_call_return_arg<'tcx>(
fx: &mut FunctionCx<'_, '_, 'tcx>,
ret_arg_abi: &ArgAbi<'tcx, Ty<'tcx>>,
ret_place: Option<CPlace<'tcx>>,
- f: impl FnOnce(&mut FunctionCx<'_, '_, 'tcx>, Option<Value>) -> (Inst, T),
-) -> (Inst, T) {
- let return_ptr = match ret_arg_abi.mode {
- PassMode::Ignore => None,
+ f: impl FnOnce(&mut FunctionCx<'_, '_, 'tcx>, Option<Value>) -> Inst,
+) {
+ let (ret_temp_place, return_ptr) = match ret_arg_abi.mode {
+ PassMode::Ignore => (None, 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
+ Some(ret_place) if matches!(ret_place.inner(), CPlaceInner::Addr(_, None)) => {
+ // This is an optimization to prevent unnecessary copies of the return value when
+ // the return place is already a memory place as opposed to a register.
+ // This match arm can be safely removed.
+ (None, Some(ret_place.to_ptr().get_addr(fx)))
+ }
+ _ => {
+ let place = CPlace::new_stack_slot(fx, ret_arg_abi.layout);
+ (Some(place), Some(place.to_ptr().get_addr(fx)))
+ }
},
PassMode::Indirect { attrs: _, extra_attrs: Some(_), on_stack: _ } => {
unreachable!("unsized return value")
}
- PassMode::Direct(_) | PassMode::Pair(_, _) | PassMode::Cast(_) => None,
+ PassMode::Direct(_) | PassMode::Pair(_, _) | PassMode::Cast(_) => (None, None),
};
- let (call_inst, meta) = f(fx, return_ptr);
+ let call_inst = f(fx, return_ptr);
match ret_arg_abi.mode {
PassMode::Ignore => {}
@@ -150,13 +112,19 @@
ret_place.write_cvalue(fx, result);
}
}
- PassMode::Indirect { attrs: _, extra_attrs: None, on_stack: _ } => {}
+ PassMode::Indirect { attrs: _, extra_attrs: None, on_stack: _ } => {
+ if let (Some(ret_place), Some(ret_temp_place)) = (ret_place, ret_temp_place) {
+ // Both ret_place and ret_temp_place must be Some. If ret_place is None, this is
+ // a non-returning call. If ret_temp_place is None, it is not necessary to copy the
+ // return value.
+ let ret_temp_value = ret_temp_place.to_cvalue(fx);
+ ret_place.write_cvalue(fx, ret_temp_value);
+ }
+ }
PassMode::Indirect { attrs: _, extra_attrs: Some(_), on_stack: _ } => {
unreachable!("unsized return value")
}
}
-
- (call_inst, meta)
}
/// Codegen a return instruction with the right return value(s) if any.
diff --git a/compiler/rustc_codegen_cranelift/src/allocator.rs b/compiler/rustc_codegen_cranelift/src/allocator.rs
index d39486c..637d30f 100644
--- a/compiler/rustc_codegen_cranelift/src/allocator.rs
+++ b/compiler/rustc_codegen_cranelift/src/allocator.rs
@@ -5,7 +5,6 @@
use cranelift_codegen::binemit::{NullStackMapSink, NullTrapSink};
use rustc_ast::expand::allocator::{AllocatorKind, AllocatorTy, ALLOCATOR_METHODS};
-use rustc_span::symbol::sym;
/// Returns whether an allocator shim was created
pub(crate) fn codegen(
@@ -20,7 +19,7 @@
if any_dynamic_crate {
false
} else if let Some(kind) = tcx.allocator_kind(()) {
- codegen_inner(module, unwind_context, kind);
+ codegen_inner(module, unwind_context, kind, tcx.lang_items().oom().is_some());
true
} else {
false
@@ -31,6 +30,7 @@
module: &mut impl Module,
unwind_context: &mut UnwindContext,
kind: AllocatorKind,
+ has_alloc_error_handler: bool,
) {
let usize_ty = module.target_config().pointer_type();
@@ -65,7 +65,6 @@
let caller_name = format!("__rust_{}", method.name);
let callee_name = kind.fn_name(method.name);
- //eprintln!("Codegen allocator shim {} -> {} ({:?} -> {:?})", caller_name, callee_name, sig.params, sig.returns);
let func_id = module.declare_function(&caller_name, Linkage::Export, &sig).unwrap();
@@ -104,13 +103,12 @@
returns: vec![],
};
- let callee_name = kind.fn_name(sym::oom);
- //eprintln!("Codegen allocator shim {} -> {} ({:?} -> {:?})", caller_name, callee_name, sig.params, sig.returns);
+ let callee_name = if has_alloc_error_handler { "__rg_oom" } else { "__rdl_oom" };
let func_id =
module.declare_function("__rust_alloc_error_handler", Linkage::Export, &sig).unwrap();
- let callee_func_id = module.declare_function(&callee_name, Linkage::Import, &sig).unwrap();
+ let callee_func_id = module.declare_function(callee_name, Linkage::Import, &sig).unwrap();
let mut ctx = Context::new();
ctx.func = Function::with_name_signature(ExternalName::user(0, 0), sig);
diff --git a/compiler/rustc_codegen_cranelift/src/analyze.rs b/compiler/rustc_codegen_cranelift/src/analyze.rs
index efead25..35b8935 100644
--- a/compiler/rustc_codegen_cranelift/src/analyze.rs
+++ b/compiler/rustc_codegen_cranelift/src/analyze.rs
@@ -38,17 +38,6 @@
_ => {}
}
}
-
- match &bb.terminator().kind {
- TerminatorKind::Call { destination, func, args, .. } => {
- if let Some((dest_place, _dest_bb)) = destination {
- if !crate::abi::can_return_to_ssa_var(fx, func, args) {
- not_ssa(&mut flag_map, dest_place.local)
- }
- }
- }
- _ => {}
- }
}
flag_map
diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs
index 3d78eed..e99a227 100644
--- a/compiler/rustc_codegen_cranelift/src/base.rs
+++ b/compiler/rustc_codegen_cranelift/src/base.rs
@@ -334,8 +334,6 @@
crate::optimize::peephole::maybe_unwrap_bool_not(&mut fx.bcx, discr);
let test_zero = if is_inverted { !test_zero } else { test_zero };
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 let Some(taken) = crate::optimize::peephole::maybe_known_branch_taken(
&fx.bcx, discr, test_zero,
) {
diff --git a/compiler/rustc_codegen_cranelift/src/cast.rs b/compiler/rustc_codegen_cranelift/src/cast.rs
index 74c5e09..e7e6afe 100644
--- a/compiler/rustc_codegen_cranelift/src/cast.rs
+++ b/compiler/rustc_codegen_cranelift/src/cast.rs
@@ -14,21 +14,6 @@
(_, _) if from == to => val,
// extend
- (_, types::I128) => {
- let lo = if from == types::I64 {
- val
- } else if signed {
- fx.bcx.ins().sextend(types::I64, val)
- } else {
- fx.bcx.ins().uextend(types::I64, val)
- };
- let hi = if signed {
- fx.bcx.ins().sshr_imm(lo, 63)
- } else {
- fx.bcx.ins().iconst(types::I64, 0)
- };
- fx.bcx.ins().iconcat(lo, hi)
- }
(_, _) if to.wider_or_equal(from) => {
if signed {
fx.bcx.ins().sextend(to, val)
@@ -38,10 +23,6 @@
}
// reduce
- (types::I128, _) => {
- let (lsb, _msb) = fx.bcx.ins().isplit(val);
- if to == types::I64 { lsb } else { fx.bcx.ins().ireduce(to, lsb) }
- }
(_, _) => fx.bcx.ins().ireduce(to, val),
}
}
diff --git a/compiler/rustc_codegen_cranelift/src/codegen_i128.rs b/compiler/rustc_codegen_cranelift/src/codegen_i128.rs
index ffe1922..638b2d5 100644
--- a/compiler/rustc_codegen_cranelift/src/codegen_i128.rs
+++ b/compiler/rustc_codegen_cranelift/src/codegen_i128.rs
@@ -19,9 +19,6 @@
return None;
}
- let lhs_val = lhs.load_scalar(fx);
- let rhs_val = rhs.load_scalar(fx);
-
let is_signed = type_sign(lhs.layout().ty);
match bin_op {
@@ -30,29 +27,53 @@
None
}
BinOp::Add | BinOp::Sub if !checked => None,
- BinOp::Mul if !checked => {
- let val_ty = if is_signed { fx.tcx.types.i128 } else { fx.tcx.types.u128 };
- if fx.tcx.sess.target.is_like_windows {
- let ret_place = CPlace::new_stack_slot(fx, lhs.layout());
- let (lhs_ptr, lhs_extra) = lhs.force_stack(fx);
- let (rhs_ptr, rhs_extra) = rhs.force_stack(fx);
- assert!(lhs_extra.is_none());
- assert!(rhs_extra.is_none());
- let args =
- [ret_place.to_ptr().get_addr(fx), lhs_ptr.get_addr(fx), rhs_ptr.get_addr(fx)];
- fx.lib_call(
- "__multi3",
- vec![
- AbiParam::special(pointer_ty(fx.tcx), ArgumentPurpose::StructReturn),
- AbiParam::new(pointer_ty(fx.tcx)),
- AbiParam::new(pointer_ty(fx.tcx)),
- ],
- vec![],
- &args,
- );
- Some(ret_place.to_cvalue(fx))
+ BinOp::Mul if !checked || is_signed => {
+ if !checked {
+ let val_ty = if is_signed { fx.tcx.types.i128 } else { fx.tcx.types.u128 };
+ if fx.tcx.sess.target.is_like_windows {
+ let ret_place = CPlace::new_stack_slot(fx, lhs.layout());
+ let (lhs_ptr, lhs_extra) = lhs.force_stack(fx);
+ let (rhs_ptr, rhs_extra) = rhs.force_stack(fx);
+ assert!(lhs_extra.is_none());
+ assert!(rhs_extra.is_none());
+ let args = [
+ ret_place.to_ptr().get_addr(fx),
+ lhs_ptr.get_addr(fx),
+ rhs_ptr.get_addr(fx),
+ ];
+ fx.lib_call(
+ "__multi3",
+ vec![
+ AbiParam::special(fx.pointer_type, ArgumentPurpose::StructReturn),
+ AbiParam::new(fx.pointer_type),
+ AbiParam::new(fx.pointer_type),
+ ],
+ vec![],
+ &args,
+ );
+ Some(ret_place.to_cvalue(fx))
+ } else {
+ Some(fx.easy_call("__multi3", &[lhs, rhs], val_ty))
+ }
} else {
- Some(fx.easy_call("__multi3", &[lhs, rhs], val_ty))
+ let out_ty = fx.tcx.mk_tup([lhs.layout().ty, fx.tcx.types.bool].iter());
+ let oflow = CPlace::new_stack_slot(fx, fx.layout_of(fx.tcx.types.i32));
+ let lhs = lhs.load_scalar(fx);
+ let rhs = rhs.load_scalar(fx);
+ let oflow_ptr = oflow.to_ptr().get_addr(fx);
+ let res = fx.lib_call(
+ "__muloti4",
+ vec![
+ AbiParam::new(types::I128),
+ AbiParam::new(types::I128),
+ AbiParam::new(fx.pointer_type),
+ ],
+ vec![AbiParam::new(types::I128)],
+ &[lhs, rhs, oflow_ptr],
+ )[0];
+ let oflow = oflow.to_cvalue(fx).load_scalar(fx);
+ let oflow = fx.bcx.ins().ireduce(types::I8, oflow);
+ Some(CValue::by_val_pair(res, oflow, fx.layout_of(out_ty)))
}
}
BinOp::Add | BinOp::Sub | BinOp::Mul => {
@@ -66,16 +87,16 @@
assert!(rhs_extra.is_none());
(
vec![
- AbiParam::special(pointer_ty(fx.tcx), ArgumentPurpose::StructReturn),
- AbiParam::new(pointer_ty(fx.tcx)),
- AbiParam::new(pointer_ty(fx.tcx)),
+ AbiParam::special(fx.pointer_type, ArgumentPurpose::StructReturn),
+ AbiParam::new(fx.pointer_type),
+ AbiParam::new(fx.pointer_type),
],
[out_place.to_ptr().get_addr(fx), lhs_ptr.get_addr(fx), rhs_ptr.get_addr(fx)],
)
} else {
(
vec![
- AbiParam::special(pointer_ty(fx.tcx), ArgumentPurpose::StructReturn),
+ AbiParam::special(fx.pointer_type, ArgumentPurpose::StructReturn),
AbiParam::new(types::I128),
AbiParam::new(types::I128),
],
@@ -88,7 +109,6 @@
(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);
@@ -112,7 +132,7 @@
let args = [lhs_ptr.get_addr(fx), rhs_ptr.get_addr(fx)];
let ret = fx.lib_call(
name,
- vec![AbiParam::new(pointer_ty(fx.tcx)), AbiParam::new(pointer_ty(fx.tcx))],
+ vec![AbiParam::new(fx.pointer_type), AbiParam::new(fx.pointer_type)],
vec![AbiParam::new(types::I64X2)],
&args,
)[0];
@@ -128,40 +148,6 @@
assert!(!checked);
None
}
- BinOp::Shl | BinOp::Shr => {
- let is_overflow = if checked {
- // rhs >= 128
-
- // FIXME support non 128bit rhs
- /*let (rhs_lsb, rhs_msb) = fx.bcx.ins().isplit(rhs_val);
- let rhs_msb_gt_0 = fx.bcx.ins().icmp_imm(IntCC::NotEqual, rhs_msb, 0);
- let rhs_lsb_ge_128 = fx.bcx.ins().icmp_imm(IntCC::SignedGreaterThan, rhs_lsb, 127);
- let is_overflow = fx.bcx.ins().bor(rhs_msb_gt_0, rhs_lsb_ge_128);*/
- let is_overflow = fx.bcx.ins().bconst(types::B1, false);
-
- Some(fx.bcx.ins().bint(types::I8, is_overflow))
- } else {
- None
- };
-
- let truncated_rhs = clif_intcast(fx, rhs_val, types::I32, false);
- let val = match bin_op {
- BinOp::Shl => fx.bcx.ins().ishl(lhs_val, truncated_rhs),
- BinOp::Shr => {
- if is_signed {
- fx.bcx.ins().sshr(lhs_val, truncated_rhs)
- } else {
- fx.bcx.ins().ushr(lhs_val, truncated_rhs)
- }
- }
- _ => unreachable!(),
- };
- if let Some(is_overflow) = is_overflow {
- let out_ty = fx.tcx.mk_tup([lhs.layout().ty, fx.tcx.types.bool].iter());
- Some(CValue::by_val_pair(val, is_overflow, fx.layout_of(out_ty)))
- } else {
- Some(CValue::by_val(val, lhs.layout()))
- }
- }
+ BinOp::Shl | BinOp::Shr => None,
}
}
diff --git a/compiler/rustc_codegen_cranelift/src/common.rs b/compiler/rustc_codegen_cranelift/src/common.rs
index 892ccf2..03f462a 100644
--- a/compiler/rustc_codegen_cranelift/src/common.rs
+++ b/compiler/rustc_codegen_cranelift/src/common.rs
@@ -256,7 +256,7 @@
pub(crate) inline_asm_index: u32,
}
-impl<'tcx> LayoutOf for FunctionCx<'_, '_, 'tcx> {
+impl<'tcx> LayoutOf<'tcx> for FunctionCx<'_, '_, 'tcx> {
type Ty = Ty<'tcx>;
type TyAndLayout = TyAndLayout<'tcx>;
@@ -364,7 +364,7 @@
pub(crate) struct RevealAllLayoutCx<'tcx>(pub(crate) TyCtxt<'tcx>);
-impl<'tcx> LayoutOf for RevealAllLayoutCx<'tcx> {
+impl<'tcx> LayoutOf<'tcx> for RevealAllLayoutCx<'tcx> {
type Ty = Ty<'tcx>;
type TyAndLayout = TyAndLayout<'tcx>;
diff --git a/compiler/rustc_codegen_cranelift/src/constant.rs b/compiler/rustc_codegen_cranelift/src/constant.rs
index c87309e..424a0d7 100644
--- a/compiler/rustc_codegen_cranelift/src/constant.rs
+++ b/compiler/rustc_codegen_cranelift/src/constant.rs
@@ -129,13 +129,13 @@
};
let const_val = match const_.val {
ConstKind::Value(const_val) => const_val,
- ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted })
- if fx.tcx.is_static(def.did) =>
+ ConstKind::Unevaluated(uv)
+ if fx.tcx.is_static(uv.def.did) =>
{
- assert!(substs.is_empty());
- assert!(promoted.is_none());
+ assert!(uv.substs(fx.tcx).is_empty());
+ assert!(uv.promoted.is_none());
- return codegen_static_ref(fx, def.did, fx.layout_of(const_.ty)).to_cvalue(fx);
+ return codegen_static_ref(fx, uv.def.did, fx.layout_of(const_.ty)).to_cvalue(fx);
}
ConstKind::Unevaluated(unevaluated) => {
match fx.tcx.const_eval_resolve(ParamEnv::reveal_all(), unevaluated, None) {
diff --git a/compiler/rustc_codegen_cranelift/src/debuginfo/emit.rs b/compiler/rustc_codegen_cranelift/src/debuginfo/emit.rs
index 6018eef..fb6ccd7 100644
--- a/compiler/rustc_codegen_cranelift/src/debuginfo/emit.rs
+++ b/compiler/rustc_codegen_cranelift/src/debuginfo/emit.rs
@@ -160,7 +160,7 @@
let val = match eh_pe.application() {
gimli::DW_EH_PE_absptr => val,
gimli::DW_EH_PE_pcrel => {
- // TODO: better handling of sign
+ // FIXME better handling of sign
let offset = self.len() as u64;
offset.wrapping_sub(val)
}
diff --git a/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs b/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs
index c67336e..cabe3e4 100644
--- a/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs
+++ b/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs
@@ -46,7 +46,7 @@
pub(crate) fn new(tcx: TyCtxt<'tcx>, isa: &dyn TargetIsa) -> Self {
let encoding = Encoding {
format: Format::Dwarf32,
- // TODO: this should be configurable
+ // FIXME this should be configurable
// macOS doesn't seem to support DWARF > 3
// 5 version is required for md5 file hash
version: if tcx.sess.target.is_like_osx {
@@ -66,7 +66,7 @@
rustc_interface::util::version_str().unwrap_or("unknown version"),
cranelift_codegen::VERSION,
);
- let comp_dir = tcx.sess.working_dir.to_string_lossy(false).into_owned();
+ let comp_dir = tcx.sess.opts.working_dir.to_string_lossy(FileNameDisplayPreference::Remapped).into_owned();
let (name, file_info) = match tcx.sess.local_crate_source_file.clone() {
Some(path) => {
let name = path.to_string_lossy().into_owned();
@@ -160,12 +160,10 @@
for (field_idx, field_def) in variant.fields.iter().enumerate() {
let field_offset = layout.fields.offset(field_idx);
- let field_layout = layout
- .field(
- &layout::LayoutCx { tcx: self.tcx, param_env: ParamEnv::reveal_all() },
- field_idx,
- )
- .unwrap();
+ let field_layout = layout.field(
+ &layout::LayoutCx { tcx: self.tcx, param_env: ParamEnv::reveal_all() },
+ field_idx,
+ );
let field_type = self.dwarf_ty(field_layout.ty);
diff --git a/compiler/rustc_codegen_cranelift/src/driver/aot.rs b/compiler/rustc_codegen_cranelift/src/driver/aot.rs
index a8b802f..3de706e 100644
--- a/compiler/rustc_codegen_cranelift/src/driver/aot.rs
+++ b/compiler/rustc_codegen_cranelift/src/driver/aot.rs
@@ -68,14 +68,13 @@
cgu: &CodegenUnit<'_>,
work_products: &mut FxHashMap<WorkProductId, WorkProduct>,
) -> CompiledModule {
- let incr_comp_session_dir = tcx.sess.incr_comp_session_dir();
let mut object = None;
let work_product = cgu.work_product(tcx);
if let Some(saved_file) = &work_product.saved_file {
let obj_out =
tcx.output_filenames(()).temp_path(OutputType::Object, Some(&cgu.name().as_str()));
object = Some(obj_out.clone());
- let source_file = rustc_incremental::in_incr_comp_dir(&incr_comp_session_dir, &saved_file);
+ let source_file = rustc_incremental::in_incr_comp_dir_sess(&tcx.sess, &saved_file);
if let Err(err) = rustc_fs_util::link_or_copy(&source_file, &obj_out) {
tcx.sess.err(&format!(
"unable to copy {} to {}: {}",
diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
index 3979886..12f61e0 100644
--- a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
+++ b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
@@ -175,12 +175,11 @@
assert_eq!(lane_count, ret_lane_count);
for lane_idx in 0..lane_count {
- let lane_idx = mir::Field::new(lane_idx.try_into().unwrap());
- let lane = val.value_field(fx, lane_idx).load_scalar(fx);
+ let lane = val.value_lane(fx, lane_idx).load_scalar(fx);
let res_lane = f(fx, lane_layout, ret_lane_layout, lane);
- ret.place_field(fx, lane_idx).write_cvalue(fx, res_lane);
+ ret.place_lane(fx, lane_idx).write_cvalue(fx, res_lane);
}
}
@@ -206,20 +205,20 @@
let ret_lane_layout = fx.layout_of(ret_lane_ty);
assert_eq!(lane_count, ret_lane_count);
- for lane in 0..lane_count {
- let lane = mir::Field::new(lane.try_into().unwrap());
- let x_lane = x.value_field(fx, lane).load_scalar(fx);
- let y_lane = y.value_field(fx, lane).load_scalar(fx);
+ for lane_idx in 0..lane_count {
+ let x_lane = x.value_lane(fx, lane_idx).load_scalar(fx);
+ let y_lane = y.value_lane(fx, lane_idx).load_scalar(fx);
let res_lane = f(fx, lane_layout, ret_lane_layout, x_lane, y_lane);
- ret.place_field(fx, lane).write_cvalue(fx, res_lane);
+ ret.place_lane(fx, lane_idx).write_cvalue(fx, res_lane);
}
}
fn simd_reduce<'tcx>(
fx: &mut FunctionCx<'_, '_, 'tcx>,
val: CValue<'tcx>,
+ acc: Option<Value>,
ret: CPlace<'tcx>,
f: impl Fn(&mut FunctionCx<'_, '_, 'tcx>, TyAndLayout<'tcx>, Value, Value) -> Value,
) {
@@ -227,16 +226,17 @@
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.try_into().unwrap())).load_scalar(fx);
+ let (mut res_val, start_lane) =
+ if let Some(acc) = acc { (acc, 0) } else { (val.value_lane(fx, 0).load_scalar(fx), 1) };
+ for lane_idx in start_lane..lane_count {
+ let lane = val.value_lane(fx, lane_idx).load_scalar(fx);
res_val = f(fx, lane_layout, res_val, lane);
}
let res = CValue::by_val(res_val, lane_layout);
ret.write_cvalue(fx, res);
}
+// FIXME move all uses to `simd_reduce`
fn simd_reduce_bool<'tcx>(
fx: &mut FunctionCx<'_, '_, 'tcx>,
val: CValue<'tcx>,
@@ -246,14 +246,18 @@
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 res_val = val.value_lane(fx, 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.try_into().unwrap())).load_scalar(fx);
+ let lane = val.value_lane(fx, lane_idx).load_scalar(fx);
let lane = fx.bcx.ins().band_imm(lane, 1); // mask to boolean
res_val = f(fx, res_val, lane);
}
+ let res_val = if fx.bcx.func.dfg.value_type(res_val) != types::I8 {
+ fx.bcx.ins().ireduce(types::I8, res_val)
+ } else {
+ res_val
+ };
let res = CValue::by_val(res_val, ret.layout());
ret.write_cvalue(fx, res);
}
@@ -288,7 +292,11 @@
if let Some(vector_ty) = vector_ty {
let x = $x.load_scalar($fx);
let y = $y.load_scalar($fx);
- let val = $fx.bcx.ins().icmp(IntCC::$cc, x, y);
+ let val = if vector_ty.lane_type().is_float() {
+ $fx.bcx.ins().fcmp(FloatCC::$cc_f, x, y)
+ } else {
+ $fx.bcx.ins().icmp(IntCC::$cc, x, y)
+ };
// HACK This depends on the fact that icmp for vectors represents bools as 0 and !0, not 0 and 1.
let val = $fx.bcx.ins().raw_bitcast(vector_ty, val);
@@ -603,9 +611,6 @@
let (val, has_overflow) = checked_res.load_scalar_pair(fx);
let clif_ty = fx.clif_type(T).unwrap();
- // `select.i8` is not implemented by Cranelift.
- let has_overflow = fx.bcx.ins().uextend(types::I32, has_overflow);
-
let (min, max) = type_min_max_value(&mut fx.bcx, clif_ty, signed);
let val = match (intrinsic, signed) {
@@ -632,21 +637,11 @@
};
rotate_left, <T>(v x, v y) {
let layout = fx.layout_of(T);
- let y = if fx.bcx.func.dfg.value_type(y) == types::I128 {
- fx.bcx.ins().ireduce(types::I64, y)
- } else {
- y
- };
let res = fx.bcx.ins().rotl(x, y);
ret.write_cvalue(fx, CValue::by_val(res, layout));
};
rotate_right, <T>(v x, v y) {
let layout = fx.layout_of(T);
- let y = if fx.bcx.func.dfg.value_type(y) == types::I128 {
- fx.bcx.ins().ireduce(types::I64, y)
- } else {
- y
- };
let res = fx.bcx.ins().rotr(x, y);
ret.write_cvalue(fx, CValue::by_val(res, layout));
};
@@ -684,35 +679,13 @@
};
ctlz | ctlz_nonzero, <T> (v arg) {
// FIXME trap on `ctlz_nonzero` with zero arg.
- let res = if T == fx.tcx.types.u128 || T == fx.tcx.types.i128 {
- // FIXME verify this algorithm is correct
- let (lsb, msb) = fx.bcx.ins().isplit(arg);
- let lsb_lz = fx.bcx.ins().clz(lsb);
- let msb_lz = fx.bcx.ins().clz(msb);
- let msb_is_zero = fx.bcx.ins().icmp_imm(IntCC::Equal, msb, 0);
- let lsb_lz_plus_64 = fx.bcx.ins().iadd_imm(lsb_lz, 64);
- let res = fx.bcx.ins().select(msb_is_zero, lsb_lz_plus_64, msb_lz);
- fx.bcx.ins().uextend(types::I128, res)
- } else {
- fx.bcx.ins().clz(arg)
- };
+ let res = fx.bcx.ins().clz(arg);
let res = CValue::by_val(res, fx.layout_of(T));
ret.write_cvalue(fx, res);
};
cttz | cttz_nonzero, <T> (v arg) {
// FIXME trap on `cttz_nonzero` with zero arg.
- let res = if T == fx.tcx.types.u128 || T == fx.tcx.types.i128 {
- // FIXME verify this algorithm is correct
- let (lsb, msb) = fx.bcx.ins().isplit(arg);
- let lsb_tz = fx.bcx.ins().ctz(lsb);
- let msb_tz = fx.bcx.ins().ctz(msb);
- let lsb_is_zero = fx.bcx.ins().icmp_imm(IntCC::Equal, lsb, 0);
- let msb_tz_plus_64 = fx.bcx.ins().iadd_imm(msb_tz, 64);
- let res = fx.bcx.ins().select(lsb_is_zero, msb_tz_plus_64, lsb_tz);
- fx.bcx.ins().uextend(types::I128, res)
- } else {
- fx.bcx.ins().ctz(arg)
- };
+ let res = fx.bcx.ins().ctz(arg);
let res = CValue::by_val(res, fx.layout_of(T));
ret.write_cvalue(fx, res);
};
@@ -816,7 +789,7 @@
return;
}
- if intrinsic == sym::assert_zero_valid && !layout.might_permit_raw_init(fx, /*zero:*/ true).unwrap() {
+ if intrinsic == sym::assert_zero_valid && !layout.might_permit_raw_init(fx, /*zero:*/ true) {
with_no_trimmed_paths(|| crate::base::codegen_panic(
fx,
&format!("attempted to zero-initialize type `{}`, which is invalid", T),
@@ -825,7 +798,7 @@
return;
}
- if intrinsic == sym::assert_uninit_valid && !layout.might_permit_raw_init(fx, /*zero:*/ false).unwrap() {
+ if intrinsic == sym::assert_uninit_valid && !layout.might_permit_raw_init(fx, /*zero:*/ false) {
with_no_trimmed_paths(|| crate::base::codegen_panic(
fx,
&format!("attempted to leave type `{}` uninitialized, which is invalid", T),
@@ -995,8 +968,6 @@
let old = CValue::by_val(old, layout);
ret.write_cvalue(fx, old);
};
-
- // FIXME https://github.com/bytecodealliance/wasmtime/issues/2647
_ if intrinsic.as_str().starts_with("atomic_nand"), (v ptr, c src) {
let layout = src.layout();
validate_atomic_type!(fx, intrinsic, span, layout.ty);
@@ -1058,23 +1029,39 @@
ret.write_cvalue(fx, old);
};
+ // In Rust floating point min and max don't propagate NaN. In Cranelift they do however.
+ // For this reason it is necessary to use `a.is_nan() ? b : (a >= b ? b : a)` for `minnumf*`
+ // and `a.is_nan() ? b : (a <= b ? b : a)` for `maxnumf*`. NaN checks are done by comparing
+ // a float against itself. Only in case of NaN is it not equal to itself.
minnumf32, (v a, v b) {
- let val = fx.bcx.ins().fmin(a, b);
+ let a_is_nan = fx.bcx.ins().fcmp(FloatCC::NotEqual, a, a);
+ let a_ge_b = fx.bcx.ins().fcmp(FloatCC::GreaterThanOrEqual, a, b);
+ let temp = fx.bcx.ins().select(a_ge_b, b, a);
+ let val = fx.bcx.ins().select(a_is_nan, b, temp);
let val = CValue::by_val(val, fx.layout_of(fx.tcx.types.f32));
ret.write_cvalue(fx, val);
};
minnumf64, (v a, v b) {
- let val = fx.bcx.ins().fmin(a, b);
+ let a_is_nan = fx.bcx.ins().fcmp(FloatCC::NotEqual, a, a);
+ let a_ge_b = fx.bcx.ins().fcmp(FloatCC::GreaterThanOrEqual, a, b);
+ let temp = fx.bcx.ins().select(a_ge_b, b, a);
+ let val = fx.bcx.ins().select(a_is_nan, b, temp);
let val = CValue::by_val(val, fx.layout_of(fx.tcx.types.f64));
ret.write_cvalue(fx, val);
};
maxnumf32, (v a, v b) {
- let val = fx.bcx.ins().fmax(a, b);
+ let a_is_nan = fx.bcx.ins().fcmp(FloatCC::NotEqual, a, a);
+ let a_le_b = fx.bcx.ins().fcmp(FloatCC::LessThanOrEqual, a, b);
+ let temp = fx.bcx.ins().select(a_le_b, b, a);
+ let val = fx.bcx.ins().select(a_is_nan, b, temp);
let val = CValue::by_val(val, fx.layout_of(fx.tcx.types.f32));
ret.write_cvalue(fx, val);
};
maxnumf64, (v a, v b) {
- let val = fx.bcx.ins().fmax(a, b);
+ let a_is_nan = fx.bcx.ins().fcmp(FloatCC::NotEqual, a, a);
+ let a_le_b = fx.bcx.ins().fcmp(FloatCC::LessThanOrEqual, a, b);
+ let temp = fx.bcx.ins().select(a_le_b, b, a);
+ let val = fx.bcx.ins().select(a_is_nan, b, temp);
let val = CValue::by_val(val, fx.layout_of(fx.tcx.types.f64));
ret.write_cvalue(fx, val);
};
@@ -1122,6 +1109,7 @@
}
let size = fx.layout_of(T).layout.size;
+ // FIXME add and use emit_small_memcmp
let is_eq_value =
if size == Size::ZERO {
// No bytes means they're trivially equal
@@ -1137,10 +1125,9 @@
} else {
// Just call `memcmp` (like slices do in core) when the
// size is too large or it's not a power-of-two.
- let ptr_ty = pointer_ty(fx.tcx);
let signed_bytes = i64::try_from(size.bytes()).unwrap();
- let bytes_val = fx.bcx.ins().iconst(ptr_ty, signed_bytes);
- let params = vec![AbiParam::new(ptr_ty); 3];
+ let bytes_val = fx.bcx.ins().iconst(fx.pointer_type, signed_bytes);
+ let params = vec![AbiParam::new(fx.pointer_type); 3];
let returns = vec![AbiParam::new(types::I32)];
let args = &[lhs_ref, rhs_ref, bytes_val];
let cmp = fx.lib_call("memcmp", params, returns, args)[0];
@@ -1149,6 +1136,11 @@
};
ret.write_cvalue(fx, CValue::by_val(is_eq_value, ret.layout()));
};
+
+ black_box, (c a) {
+ // FIXME implement black_box semantics
+ ret.write_cvalue(fx, a);
+ };
}
if let Some((_, dest)) = destination {
diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs
index c2f469f..43e68b4 100644
--- a/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs
+++ b/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs
@@ -108,11 +108,11 @@
for (out_idx, in_idx) in indexes.into_iter().enumerate() {
let in_lane = if u64::from(in_idx) < lane_count {
- x.value_field(fx, mir::Field::new(in_idx.into()))
+ x.value_lane(fx, in_idx.into())
} else {
- y.value_field(fx, mir::Field::new(usize::from(in_idx) - usize::try_from(lane_count).unwrap()))
+ y.value_lane(fx, u64::from(in_idx) - lane_count)
};
- let out_lane = ret.place_field(fx, mir::Field::new(out_idx));
+ let out_lane = ret.place_lane(fx, u64::try_from(out_idx).unwrap());
out_lane.write_cvalue(fx, in_lane);
}
};
@@ -163,10 +163,38 @@
fx.tcx.sess.span_fatal(fx.mir.span, &format!("[simd_extract] idx {} >= lane_count {}", idx, lane_count));
}
- let ret_lane = v.value_field(fx, mir::Field::new(idx.try_into().unwrap()));
+ let ret_lane = v.value_lane(fx, idx.try_into().unwrap());
ret.write_cvalue(fx, ret_lane);
};
+ simd_neg, (c a) {
+ validate_simd_type!(fx, intrinsic, span, a.layout().ty);
+ simd_for_each_lane(fx, a, ret, |fx, lane_layout, ret_lane_layout, lane| {
+ let ret_lane = match lane_layout.ty.kind() {
+ ty::Int(_) => fx.bcx.ins().ineg(lane),
+ ty::Float(_) => fx.bcx.ins().fneg(lane),
+ _ => unreachable!(),
+ };
+ CValue::by_val(ret_lane, ret_lane_layout)
+ });
+ };
+
+ simd_fabs, (c a) {
+ validate_simd_type!(fx, intrinsic, span, a.layout().ty);
+ simd_for_each_lane(fx, a, ret, |fx, _lane_layout, ret_lane_layout, lane| {
+ let ret_lane = fx.bcx.ins().fabs(lane);
+ CValue::by_val(ret_lane, ret_lane_layout)
+ });
+ };
+
+ simd_fsqrt, (c a) {
+ validate_simd_type!(fx, intrinsic, span, a.layout().ty);
+ simd_for_each_lane(fx, a, ret, |fx, _lane_layout, ret_lane_layout, lane| {
+ let ret_lane = fx.bcx.ins().sqrt(lane);
+ CValue::by_val(ret_lane, ret_lane_layout)
+ });
+ };
+
simd_add, (c x, c y) {
validate_simd_type!(fx, intrinsic, span, x.layout().ty);
simd_int_flt_binop!(fx, iadd|fadd(x, y) -> ret);
@@ -183,6 +211,29 @@
validate_simd_type!(fx, intrinsic, span, x.layout().ty);
simd_int_flt_binop!(fx, udiv|sdiv|fdiv(x, y) -> ret);
};
+ simd_rem, (c x, c y) {
+ validate_simd_type!(fx, intrinsic, span, x.layout().ty);
+ simd_pair_for_each_lane(fx, x, y, ret, |fx, lane_layout, ret_lane_layout, x_lane, y_lane| {
+ let res_lane = match lane_layout.ty.kind() {
+ ty::Uint(_) => fx.bcx.ins().urem(x_lane, y_lane),
+ ty::Int(_) => fx.bcx.ins().srem(x_lane, y_lane),
+ ty::Float(FloatTy::F32) => fx.lib_call(
+ "fmodf",
+ vec![AbiParam::new(types::F32), AbiParam::new(types::F32)],
+ vec![AbiParam::new(types::F32)],
+ &[x_lane, y_lane],
+ )[0],
+ ty::Float(FloatTy::F64) => fx.lib_call(
+ "fmod",
+ vec![AbiParam::new(types::F64), AbiParam::new(types::F64)],
+ vec![AbiParam::new(types::F64)],
+ &[x_lane, y_lane],
+ )[0],
+ _ => unreachable!("{:?}", lane_layout.ty),
+ };
+ CValue::by_val(res_lane, ret_lane_layout)
+ });
+ };
simd_shl, (c x, c y) {
validate_simd_type!(fx, intrinsic, span, x.layout().ty);
simd_int_binop!(fx, ishl(x, y) -> ret);
@@ -216,15 +267,14 @@
let ret_lane_layout = fx.layout_of(ret_lane_ty);
for lane in 0..lane_count {
- 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);
+ let a_lane = a.value_lane(fx, lane).load_scalar(fx);
+ let b_lane = b.value_lane(fx, lane).load_scalar(fx);
+ let c_lane = c.value_lane(fx, lane).load_scalar(fx);
let mul_lane = fx.bcx.ins().fmul(a_lane, b_lane);
let res_lane = CValue::by_val(fx.bcx.ins().fadd(mul_lane, c_lane), ret_lane_layout);
- ret.place_field(fx, lane).write_cvalue(fx, res_lane);
+ ret.place_lane(fx, lane).write_cvalue(fx, res_lane);
}
};
@@ -237,9 +287,52 @@
simd_flt_binop!(fx, fmax(x, y) -> ret);
};
- simd_reduce_add_ordered | simd_reduce_add_unordered, (c v) {
+ simd_round, (c a) {
+ validate_simd_type!(fx, intrinsic, span, a.layout().ty);
+ simd_for_each_lane(fx, a, ret, |fx, lane_layout, ret_lane_layout, lane| {
+ let res_lane = match lane_layout.ty.kind() {
+ ty::Float(FloatTy::F32) => fx.lib_call(
+ "roundf",
+ vec![AbiParam::new(types::F32)],
+ vec![AbiParam::new(types::F32)],
+ &[lane],
+ )[0],
+ ty::Float(FloatTy::F64) => fx.lib_call(
+ "round",
+ vec![AbiParam::new(types::F64)],
+ vec![AbiParam::new(types::F64)],
+ &[lane],
+ )[0],
+ _ => unreachable!("{:?}", lane_layout.ty),
+ };
+ CValue::by_val(res_lane, ret_lane_layout)
+ });
+ };
+ simd_ceil, (c a) {
+ validate_simd_type!(fx, intrinsic, span, a.layout().ty);
+ simd_for_each_lane(fx, a, ret, |fx, _lane_layout, ret_lane_layout, lane| {
+ let ret_lane = fx.bcx.ins().ceil(lane);
+ CValue::by_val(ret_lane, ret_lane_layout)
+ });
+ };
+ simd_floor, (c a) {
+ validate_simd_type!(fx, intrinsic, span, a.layout().ty);
+ simd_for_each_lane(fx, a, ret, |fx, _lane_layout, ret_lane_layout, lane| {
+ let ret_lane = fx.bcx.ins().floor(lane);
+ CValue::by_val(ret_lane, ret_lane_layout)
+ });
+ };
+ simd_trunc, (c a) {
+ validate_simd_type!(fx, intrinsic, span, a.layout().ty);
+ simd_for_each_lane(fx, a, ret, |fx, _lane_layout, ret_lane_layout, lane| {
+ let ret_lane = fx.bcx.ins().trunc(lane);
+ CValue::by_val(ret_lane, ret_lane_layout)
+ });
+ };
+
+ simd_reduce_add_ordered | simd_reduce_add_unordered, (c v, v acc) {
validate_simd_type!(fx, intrinsic, span, v.layout().ty);
- simd_reduce(fx, v, ret, |fx, lane_layout, a, b| {
+ simd_reduce(fx, v, Some(acc), ret, |fx, lane_layout, a, b| {
if lane_layout.ty.is_floating_point() {
fx.bcx.ins().fadd(a, b)
} else {
@@ -248,9 +341,9 @@
});
};
- simd_reduce_mul_ordered | simd_reduce_mul_unordered, (c v) {
+ simd_reduce_mul_ordered | simd_reduce_mul_unordered, (c v, v acc) {
validate_simd_type!(fx, intrinsic, span, v.layout().ty);
- simd_reduce(fx, v, ret, |fx, lane_layout, a, b| {
+ simd_reduce(fx, v, Some(acc), ret, |fx, lane_layout, a, b| {
if lane_layout.ty.is_floating_point() {
fx.bcx.ins().fmul(a, b)
} else {
@@ -269,13 +362,70 @@
simd_reduce_bool(fx, v, ret, |fx, a, b| fx.bcx.ins().bor(a, b));
};
- // simd_fabs
- // simd_saturating_add
+ simd_reduce_and, (c v) {
+ validate_simd_type!(fx, intrinsic, span, v.layout().ty);
+ simd_reduce(fx, v, None, ret, |fx, _layout, a, b| fx.bcx.ins().band(a, b));
+ };
+
+ simd_reduce_or, (c v) {
+ validate_simd_type!(fx, intrinsic, span, v.layout().ty);
+ simd_reduce(fx, v, None, ret, |fx, _layout, a, b| fx.bcx.ins().bor(a, b));
+ };
+
+ simd_reduce_xor, (c v) {
+ validate_simd_type!(fx, intrinsic, span, v.layout().ty);
+ simd_reduce(fx, v, None, ret, |fx, _layout, a, b| fx.bcx.ins().bxor(a, b));
+ };
+
+ simd_reduce_min, (c v) {
+ // FIXME support floats
+ validate_simd_type!(fx, intrinsic, span, v.layout().ty);
+ simd_reduce(fx, v, None, ret, |fx, layout, a, b| {
+ let lt = fx.bcx.ins().icmp(if layout.ty.is_signed() {
+ IntCC::SignedLessThan
+ } else {
+ IntCC::UnsignedLessThan
+ }, a, b);
+ fx.bcx.ins().select(lt, a, b)
+ });
+ };
+
+ simd_reduce_max, (c v) {
+ // FIXME support floats
+ validate_simd_type!(fx, intrinsic, span, v.layout().ty);
+ simd_reduce(fx, v, None, ret, |fx, layout, a, b| {
+ let gt = fx.bcx.ins().icmp(if layout.ty.is_signed() {
+ IntCC::SignedGreaterThan
+ } else {
+ IntCC::UnsignedGreaterThan
+ }, a, b);
+ fx.bcx.ins().select(gt, a, b)
+ });
+ };
+
+ simd_select, (c m, c a, c b) {
+ validate_simd_type!(fx, intrinsic, span, m.layout().ty);
+ validate_simd_type!(fx, intrinsic, span, a.layout().ty);
+ assert_eq!(a.layout(), b.layout());
+
+ let (lane_count, lane_ty) = a.layout().ty.simd_size_and_type(fx.tcx);
+ let lane_layout = fx.layout_of(lane_ty);
+
+ for lane in 0..lane_count {
+ let m_lane = m.value_lane(fx, lane).load_scalar(fx);
+ let a_lane = a.value_lane(fx, lane).load_scalar(fx);
+ let b_lane = b.value_lane(fx, lane).load_scalar(fx);
+
+ let m_lane = fx.bcx.ins().icmp_imm(IntCC::Equal, m_lane, 0);
+ let res_lane = CValue::by_val(fx.bcx.ins().select(m_lane, b_lane, a_lane), lane_layout);
+
+ ret.place_lane(fx, lane).write_cvalue(fx, res_lane);
+ }
+ };
+
+ // simd_saturating_*
// simd_bitmask
- // simd_select
- // simd_rem
- // simd_neg
- // simd_trunc
- // simd_floor
+ // simd_scatter
+ // simd_gather
}
}
diff --git a/compiler/rustc_codegen_cranelift/src/lib.rs b/compiler/rustc_codegen_cranelift/src/lib.rs
index e32dae4..6c7c8cb 100644
--- a/compiler/rustc_codegen_cranelift/src/lib.rs
+++ b/compiler/rustc_codegen_cranelift/src/lib.rs
@@ -74,7 +74,7 @@
mod prelude {
pub(crate) use std::convert::{TryFrom, TryInto};
- pub(crate) use rustc_span::Span;
+ pub(crate) use rustc_span::{Span, FileNameDisplayPreference};
pub(crate) use rustc_hir::def_id::{DefId, LOCAL_CRATE};
pub(crate) use rustc_middle::bug;
@@ -184,6 +184,9 @@
let config = if let Some(config) = self.config.clone() {
config
} else {
+ if !tcx.sess.unstable_options() && !tcx.sess.opts.cg.llvm_args.is_empty() {
+ tcx.sess.fatal("`-Z unstable-options` must be passed to allow configuring cg_clif");
+ }
BackendConfig::from_opts(&tcx.sess.opts.cg.llvm_args)
.unwrap_or_else(|err| tcx.sess.fatal(&err))
};
@@ -217,16 +220,15 @@
) -> Result<(), ErrorReported> {
use rustc_codegen_ssa::back::link::link_binary;
- link_binary::<crate::archive::ArArchiveBuilder<'_>>(
- sess,
- &codegen_results,
- outputs,
- )
+ link_binary::<crate::archive::ArArchiveBuilder<'_>>(sess, &codegen_results, outputs)
}
}
fn target_triple(sess: &Session) -> target_lexicon::Triple {
- sess.target.llvm_target.parse().unwrap()
+ match sess.target.llvm_target.parse() {
+ Ok(triple) => triple,
+ Err(err) => sess.fatal(&format!("target not recognized: {}", err)),
+ }
}
fn build_isa(sess: &Session, backend_config: &BackendConfig) -> Box<dyn isa::TargetIsa + 'static> {
@@ -276,15 +278,21 @@
}
Some(value) => {
let mut builder =
- cranelift_codegen::isa::lookup_variant(target_triple, variant).unwrap();
+ cranelift_codegen::isa::lookup_variant(target_triple.clone(), variant)
+ .unwrap_or_else(|err| {
+ sess.fatal(&format!("can't compile for {}: {}", target_triple, err));
+ });
if let Err(_) = builder.enable(value) {
- sess.fatal("The specified target cpu isn't currently supported by Cranelift.");
+ sess.fatal("the specified target cpu isn't currently supported by Cranelift.");
}
builder
}
None => {
let mut builder =
- cranelift_codegen::isa::lookup_variant(target_triple.clone(), variant).unwrap();
+ cranelift_codegen::isa::lookup_variant(target_triple.clone(), variant)
+ .unwrap_or_else(|err| {
+ sess.fatal(&format!("can't compile for {}: {}", target_triple, err));
+ });
if target_triple.architecture == target_lexicon::Architecture::X86_64 {
// Don't use "haswell" as the default, as it implies `has_lzcnt`.
// macOS CI is still at Ivy Bridge EP, so `lzcnt` is interpreted as `bsr`.
diff --git a/compiler/rustc_codegen_cranelift/src/num.rs b/compiler/rustc_codegen_cranelift/src/num.rs
index b6d378a..545d390 100644
--- a/compiler/rustc_codegen_cranelift/src/num.rs
+++ b/compiler/rustc_codegen_cranelift/src/num.rs
@@ -67,19 +67,6 @@
let lhs = in_lhs.load_scalar(fx);
let rhs = in_rhs.load_scalar(fx);
- let (lhs, rhs) = if (bin_op == BinOp::Eq || bin_op == BinOp::Ne)
- && (in_lhs.layout().ty.kind() == fx.tcx.types.i8.kind()
- || in_lhs.layout().ty.kind() == fx.tcx.types.i16.kind())
- {
- // FIXME(CraneStation/cranelift#896) icmp_imm.i8/i16 with eq/ne for signed ints is implemented wrong.
- (
- fx.bcx.ins().sextend(types::I32, lhs),
- fx.bcx.ins().sextend(types::I32, rhs),
- )
- } else {
- (lhs, rhs)
- };
-
return codegen_compare_bin_op(fx, bin_op, signed, lhs, rhs);
}
_ => {}
@@ -293,9 +280,8 @@
}
BinOp::Shl => {
let lhs_ty = fx.bcx.func.dfg.value_type(lhs);
- let actual_shift = fx.bcx.ins().band_imm(rhs, i64::from(lhs_ty.bits() - 1));
- let actual_shift = clif_intcast(fx, actual_shift, types::I8, false);
- let val = fx.bcx.ins().ishl(lhs, actual_shift);
+ let masked_shift = fx.bcx.ins().band_imm(rhs, i64::from(lhs_ty.bits() - 1));
+ let val = fx.bcx.ins().ishl(lhs, masked_shift);
let ty = fx.bcx.func.dfg.value_type(val);
let max_shift = i64::from(ty.bits()) - 1;
let has_overflow = fx.bcx.ins().icmp_imm(IntCC::UnsignedGreaterThan, rhs, max_shift);
@@ -303,12 +289,11 @@
}
BinOp::Shr => {
let lhs_ty = fx.bcx.func.dfg.value_type(lhs);
- let actual_shift = fx.bcx.ins().band_imm(rhs, i64::from(lhs_ty.bits() - 1));
- let actual_shift = clif_intcast(fx, actual_shift, types::I8, false);
+ let masked_shift = fx.bcx.ins().band_imm(rhs, i64::from(lhs_ty.bits() - 1));
let val = if !signed {
- fx.bcx.ins().ushr(lhs, actual_shift)
+ fx.bcx.ins().ushr(lhs, masked_shift)
} else {
- fx.bcx.ins().sshr(lhs, actual_shift)
+ fx.bcx.ins().sshr(lhs, masked_shift)
};
let ty = fx.bcx.func.dfg.value_type(val);
let max_shift = i64::from(ty.bits()) - 1;
diff --git a/compiler/rustc_codegen_cranelift/src/optimize/peephole.rs b/compiler/rustc_codegen_cranelift/src/optimize/peephole.rs
index b95e2d7..d637b4d 100644
--- a/compiler/rustc_codegen_cranelift/src/optimize/peephole.rs
+++ b/compiler/rustc_codegen_cranelift/src/optimize/peephole.rs
@@ -1,8 +1,6 @@
//! Peephole optimizations that can be performed while creating clif ir.
-use cranelift_codegen::ir::{
- condcodes::IntCC, types, InstBuilder, InstructionData, Opcode, Value, ValueDef,
-};
+use cranelift_codegen::ir::{condcodes::IntCC, InstructionData, Opcode, Value, ValueDef};
use cranelift_frontend::FunctionBuilder;
/// If the given value was produced by a `bint` instruction, return it's input, otherwise return the
@@ -37,43 +35,6 @@
}
}
-pub(crate) fn make_branchable_value(bcx: &mut FunctionBuilder<'_>, arg: Value) -> Value {
- if bcx.func.dfg.value_type(arg).is_bool() {
- return arg;
- }
-
- (|| {
- 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] {
- // This is the lowering of Rvalue::Not
- InstructionData::Load { opcode: Opcode::Load, arg: ptr, flags, offset } => {
- // Using `load.i8 + uextend.i32` would legalize to `uload8 + ireduce.i8 +
- // uextend.i32`. Just `uload8` is much faster.
- match bcx.func.dfg.ctrl_typevar(arg_inst) {
- types::I8 => Some(bcx.ins().uload8(types::I32, flags, ptr, offset)),
- types::I16 => Some(bcx.ins().uload16(types::I32, flags, ptr, offset)),
- _ => None,
- }
- }
- _ => None,
- }
- })()
- .unwrap_or_else(|| {
- match bcx.func.dfg.value_type(arg) {
- types::I8 | types::I16 => {
- // WORKAROUND for brz.i8 and brnz.i8 not yet being implemented
- bcx.ins().uextend(types::I32, arg)
- }
- _ => arg,
- }
- })
-}
-
/// 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<'_>,
diff --git a/compiler/rustc_codegen_cranelift/src/trap.rs b/compiler/rustc_codegen_cranelift/src/trap.rs
index 21d3e68..fe8d20f 100644
--- a/compiler/rustc_codegen_cranelift/src/trap.rs
+++ b/compiler/rustc_codegen_cranelift/src/trap.rs
@@ -10,7 +10,7 @@
Linkage::Import,
&Signature {
call_conv: CallConv::triple_default(fx.triple()),
- params: vec![AbiParam::new(pointer_ty(fx.tcx))],
+ params: vec![AbiParam::new(fx.pointer_type)],
returns: vec![AbiParam::new(types::I32)],
},
)
diff --git a/compiler/rustc_codegen_cranelift/src/unsize.rs b/compiler/rustc_codegen_cranelift/src/unsize.rs
index b9d379c..fd96858 100644
--- a/compiler/rustc_codegen_cranelift/src/unsize.rs
+++ b/compiler/rustc_codegen_cranelift/src/unsize.rs
@@ -25,39 +25,60 @@
.bcx
.ins()
.iconst(fx.pointer_type, len.eval_usize(fx.tcx, ParamEnv::reveal_all()) as i64),
- (&ty::Dynamic(..), &ty::Dynamic(..)) => {
- // For now, upcasts are limited to changes in marker
- // traits, and hence never actually require an actual
- // change to the vtable.
- old_info.expect("unsized_info: missing old info for trait upcast")
+ (&ty::Dynamic(ref data_a, ..), &ty::Dynamic(ref data_b, ..)) => {
+ let old_info =
+ old_info.expect("unsized_info: missing old info for trait upcasting coercion");
+ if data_a.principal_def_id() == data_b.principal_def_id() {
+ return old_info;
+ }
+
+ // trait upcasting coercion
+ let vptr_entry_idx =
+ fx.tcx.vtable_trait_upcasting_coercion_new_vptr_slot((source, target));
+
+ if let Some(entry_idx) = vptr_entry_idx {
+ let entry_idx = u32::try_from(entry_idx).unwrap();
+ let entry_offset = entry_idx * fx.pointer_type.bytes();
+ let vptr_ptr = Pointer::new(old_info).offset_i64(fx, entry_offset.into()).load(
+ fx,
+ fx.pointer_type,
+ crate::vtable::vtable_memflags(),
+ );
+ vptr_ptr
+ } else {
+ old_info
+ }
}
(_, &ty::Dynamic(ref data, ..)) => crate::vtable::get_vtable(fx, source, data.principal()),
_ => bug!("unsized_info: invalid unsizing {:?} -> {:?}", source, target),
}
}
-/// Coerce `src` to `dst_ty`. `src_ty` must be a thin pointer.
-fn unsize_thin_ptr<'tcx>(
+/// Coerce `src` to `dst_ty`.
+fn unsize_ptr<'tcx>(
fx: &mut FunctionCx<'_, '_, 'tcx>,
src: Value,
src_layout: TyAndLayout<'tcx>,
dst_layout: TyAndLayout<'tcx>,
+ old_info: Option<Value>,
) -> (Value, Value) {
match (&src_layout.ty.kind(), &dst_layout.ty.kind()) {
(&ty::Ref(_, a, _), &ty::Ref(_, b, _))
| (&ty::Ref(_, a, _), &ty::RawPtr(ty::TypeAndMut { ty: b, .. }))
| (&ty::RawPtr(ty::TypeAndMut { ty: a, .. }), &ty::RawPtr(ty::TypeAndMut { ty: b, .. })) => {
- assert!(!fx.layout_of(a).is_unsized());
- (src, unsized_info(fx, a, b, None))
+ (src, unsized_info(fx, a, b, old_info))
}
(&ty::Adt(def_a, _), &ty::Adt(def_b, _)) if def_a.is_box() && def_b.is_box() => {
let (a, b) = (src_layout.ty.boxed_ty(), dst_layout.ty.boxed_ty());
- assert!(!fx.layout_of(a).is_unsized());
- (src, unsized_info(fx, a, b, None))
+ (src, unsized_info(fx, a, b, old_info))
}
(&ty::Adt(def_a, _), &ty::Adt(def_b, _)) => {
assert_eq!(def_a, def_b);
+ if src_layout == dst_layout {
+ return (src, old_info.unwrap());
+ }
+
let mut result = None;
for i in 0..src_layout.fields.count() {
let src_f = src_layout.field(fx, i);
@@ -71,11 +92,11 @@
let dst_f = dst_layout.field(fx, i);
assert_ne!(src_f.ty, dst_f.ty);
assert_eq!(result, None);
- result = Some(unsize_thin_ptr(fx, src, src_f, dst_f));
+ result = Some(unsize_ptr(fx, src, src_f, dst_f, old_info));
}
result.unwrap()
}
- _ => bug!("unsize_thin_ptr: called on bad types"),
+ _ => bug!("unsize_ptr: called on bad types"),
}
}
@@ -91,12 +112,11 @@
let mut coerce_ptr = || {
let (base, info) =
if fx.layout_of(src.layout().ty.builtin_deref(true).unwrap().ty).is_unsized() {
- // fat-ptr to fat-ptr unsize preserves the vtable
- // i.e., &'a fmt::Debug+Send => &'a fmt::Debug
- src.load_scalar_pair(fx)
+ let (old_base, old_info) = src.load_scalar_pair(fx);
+ unsize_ptr(fx, old_base, src.layout(), dst.layout(), Some(old_info))
} else {
let base = src.load_scalar(fx);
- unsize_thin_ptr(fx, base, src.layout(), dst.layout())
+ unsize_ptr(fx, base, src.layout(), dst.layout(), None)
};
dst.write_cvalue(fx, CValue::by_val_pair(base, info, dst.layout()));
};
diff --git a/compiler/rustc_codegen_cranelift/src/value_and_place.rs b/compiler/rustc_codegen_cranelift/src/value_and_place.rs
index ae8ccc6..364b3da 100644
--- a/compiler/rustc_codegen_cranelift/src/value_and_place.rs
+++ b/compiler/rustc_codegen_cranelift/src/value_and_place.rs
@@ -34,10 +34,10 @@
let (_, unsized_align) =
crate::unsize::size_and_align_of_dst(fx, field_layout, extra);
- let one = fx.bcx.ins().iconst(pointer_ty(fx.tcx), 1);
+ let one = fx.bcx.ins().iconst(fx.pointer_type, 1);
let align_sub_1 = fx.bcx.ins().isub(unsized_align, one);
let and_lhs = fx.bcx.ins().iadd_imm(align_sub_1, unaligned_offset as i64);
- let zero = fx.bcx.ins().iconst(pointer_ty(fx.tcx), 0);
+ let zero = fx.bcx.ins().iconst(fx.pointer_type, 0);
let and_rhs = fx.bcx.ins().isub(zero, unsized_align);
let offset = fx.bcx.ins().band(and_lhs, and_rhs);
@@ -206,6 +206,38 @@
}
}
+ /// Like [`CValue::value_field`] except handling ADTs containing a single array field in a way
+ /// such that you can access individual lanes.
+ pub(crate) fn value_lane(
+ self,
+ fx: &mut FunctionCx<'_, '_, 'tcx>,
+ lane_idx: u64,
+ ) -> CValue<'tcx> {
+ let layout = self.1;
+ assert!(layout.ty.is_simd());
+ let (lane_count, lane_ty) = layout.ty.simd_size_and_type(fx.tcx);
+ let lane_layout = fx.layout_of(lane_ty);
+ assert!(lane_idx < lane_count);
+ match self.0 {
+ CValueInner::ByVal(val) => match layout.abi {
+ Abi::Vector { element: _, count: _ } => {
+ assert!(lane_count <= u8::MAX.into(), "SIMD type with more than 255 lanes???");
+ let lane_idx = u8::try_from(lane_idx).unwrap();
+ let lane = fx.bcx.ins().extractlane(val, lane_idx);
+ CValue::by_val(lane, lane_layout)
+ }
+ _ => unreachable!("value_lane for ByVal with abi {:?}", layout.abi),
+ },
+ CValueInner::ByValPair(_, _) => unreachable!(),
+ CValueInner::ByRef(ptr, None) => {
+ let field_offset = lane_layout.size * lane_idx;
+ let field_ptr = ptr.offset_i64(fx, i64::try_from(field_offset.bytes()).unwrap());
+ CValue::by_ref(field_ptr, lane_layout)
+ }
+ CValueInner::ByRef(_, Some(_)) => unreachable!(),
+ }
+ }
+
pub(crate) fn unsize_value(self, fx: &mut FunctionCx<'_, '_, 'tcx>, dest: CPlace<'tcx>) {
crate::unsize::coerce_unsized_into(fx, self, dest);
}
@@ -286,17 +318,16 @@
&self.inner
}
- pub(crate) fn no_place(layout: TyAndLayout<'tcx>) -> CPlace<'tcx> {
- CPlace { inner: CPlaceInner::Addr(Pointer::dangling(layout.align.pref), None), layout }
- }
-
pub(crate) fn new_stack_slot(
fx: &mut FunctionCx<'_, '_, 'tcx>,
layout: TyAndLayout<'tcx>,
) -> CPlace<'tcx> {
assert!(!layout.is_unsized());
if layout.size.bytes() == 0 {
- return CPlace::no_place(layout);
+ return CPlace {
+ inner: CPlaceInner::Addr(Pointer::dangling(layout.align.pref), None),
+ layout,
+ };
}
let stack_slot = fx.bcx.create_stack_slot(StackSlotData {
@@ -610,6 +641,38 @@
}
}
+ /// Like [`CPlace::place_field`] except handling ADTs containing a single array field in a way
+ /// such that you can access individual lanes.
+ pub(crate) fn place_lane(
+ self,
+ fx: &mut FunctionCx<'_, '_, 'tcx>,
+ lane_idx: u64,
+ ) -> CPlace<'tcx> {
+ let layout = self.layout();
+ assert!(layout.ty.is_simd());
+ let (lane_count, lane_ty) = layout.ty.simd_size_and_type(fx.tcx);
+ let lane_layout = fx.layout_of(lane_ty);
+ assert!(lane_idx < lane_count);
+
+ match self.inner {
+ CPlaceInner::Var(local, var) => {
+ assert!(matches!(layout.abi, Abi::Vector { .. }));
+ CPlace {
+ inner: CPlaceInner::VarLane(local, var, lane_idx.try_into().unwrap()),
+ layout: lane_layout,
+ }
+ }
+ CPlaceInner::VarPair(_, _, _) => unreachable!(),
+ CPlaceInner::VarLane(_, _, _) => unreachable!(),
+ CPlaceInner::Addr(ptr, None) => {
+ let field_offset = lane_layout.size * lane_idx;
+ let field_ptr = ptr.offset_i64(fx, i64::try_from(field_offset.bytes()).unwrap());
+ CPlace::for_ptr(field_ptr, lane_layout)
+ }
+ CPlaceInner::Addr(_, Some(_)) => unreachable!(),
+ }
+ }
+
pub(crate) fn place_index(
self,
fx: &mut FunctionCx<'_, '_, 'tcx>,
diff --git a/compiler/rustc_codegen_cranelift/src/vtable.rs b/compiler/rustc_codegen_cranelift/src/vtable.rs
index 4a5f9f1..36b3725 100644
--- a/compiler/rustc_codegen_cranelift/src/vtable.rs
+++ b/compiler/rustc_codegen_cranelift/src/vtable.rs
@@ -5,7 +5,7 @@
use crate::constant::data_id_for_alloc_id;
use crate::prelude::*;
-fn vtable_memflags() -> MemFlags {
+pub(crate) fn vtable_memflags() -> MemFlags {
let mut flags = MemFlags::trusted(); // A vtable access is always aligned and will never trap.
flags.set_readonly(); // A vtable is always read-only.
flags
@@ -14,7 +14,7 @@
pub(crate) fn drop_fn_of_obj(fx: &mut FunctionCx<'_, '_, '_>, vtable: Value) -> Value {
let usize_size = fx.layout_of(fx.tcx.types.usize).size.bytes() as usize;
fx.bcx.ins().load(
- pointer_ty(fx.tcx),
+ fx.pointer_type,
vtable_memflags(),
vtable,
(ty::COMMON_VTABLE_ENTRIES_DROPINPLACE * usize_size) as i32,
@@ -24,7 +24,7 @@
pub(crate) fn size_of_obj(fx: &mut FunctionCx<'_, '_, '_>, vtable: Value) -> Value {
let usize_size = fx.layout_of(fx.tcx.types.usize).size.bytes() as usize;
fx.bcx.ins().load(
- pointer_ty(fx.tcx),
+ fx.pointer_type,
vtable_memflags(),
vtable,
(ty::COMMON_VTABLE_ENTRIES_SIZE * usize_size) as i32,
@@ -34,7 +34,7 @@
pub(crate) fn min_align_of_obj(fx: &mut FunctionCx<'_, '_, '_>, vtable: Value) -> Value {
let usize_size = fx.layout_of(fx.tcx.types.usize).size.bytes() as usize;
fx.bcx.ins().load(
- pointer_ty(fx.tcx),
+ fx.pointer_type,
vtable_memflags(),
vtable,
(ty::COMMON_VTABLE_ENTRIES_ALIGN * usize_size) as i32,
@@ -55,7 +55,7 @@
let usize_size = fx.layout_of(fx.tcx.types.usize).size.bytes();
let func_ref = fx.bcx.ins().load(
- pointer_ty(fx.tcx),
+ fx.pointer_type,
vtable_memflags(),
vtable,
(idx * usize_size as usize) as i32,
@@ -68,7 +68,7 @@
ty: Ty<'tcx>,
trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>,
) -> Value {
- let alloc_id = fx.tcx.vtable_allocation(ty, trait_ref);
+ let alloc_id = fx.tcx.vtable_allocation((ty, trait_ref));
let data_id =
data_id_for_alloc_id(&mut fx.constants_cx, &mut *fx.module, alloc_id, Mutability::Not);
let local_data_id = fx.module.declare_data_in_func(data_id, &mut fx.bcx.func);
diff --git a/compiler/rustc_codegen_cranelift/y.rs b/compiler/rustc_codegen_cranelift/y.rs
index 4393758..2660500 100755
--- a/compiler/rustc_codegen_cranelift/y.rs
+++ b/compiler/rustc_codegen_cranelift/y.rs
@@ -15,8 +15,8 @@
//! for example:
//!
//! ```shell
-//! $ rustc y.rs -o build/y.bin
-//! $ build/y.bin
+//! $ rustc y.rs -o y.bin
+//! $ ./y.bin
//! ```
//!
//! # Naming
diff --git a/compiler/rustc_codegen_llvm/Cargo.toml b/compiler/rustc_codegen_llvm/Cargo.toml
index d78af9d..521ce34 100644
--- a/compiler/rustc_codegen_llvm/Cargo.toml
+++ b/compiler/rustc_codegen_llvm/Cargo.toml
@@ -1,5 +1,4 @@
[package]
-authors = ["The Rust Project Developers"]
name = "rustc_codegen_llvm"
version = "0.0.0"
edition = "2018"
@@ -16,7 +15,7 @@
snap = "1"
tracing = "0.1"
rustc_middle = { path = "../rustc_middle" }
-rustc-demangle = "0.1.18"
+rustc-demangle = "0.1.21"
rustc_attr = { path = "../rustc_attr" }
rustc_codegen_ssa = { path = "../rustc_codegen_ssa" }
rustc_data_structures = { path = "../rustc_data_structures" }
diff --git a/compiler/rustc_codegen_llvm/src/abi.rs b/compiler/rustc_codegen_llvm/src/abi.rs
index 854e3cc..abf0ea8 100644
--- a/compiler/rustc_codegen_llvm/src/abi.rs
+++ b/compiler/rustc_codegen_llvm/src/abi.rs
@@ -353,7 +353,11 @@
impl<'tcx> FnAbiLlvmExt<'tcx> for FnAbi<'tcx, Ty<'tcx>> {
fn llvm_type(&self, cx: &CodegenCx<'ll, 'tcx>) -> &'ll Type {
- let args_capacity: usize = self.args.iter().map(|arg|
+ // Ignore "extra" args from the call site for C variadic functions.
+ // Only the "fixed" args are part of the LLVM function signature.
+ let args = if self.c_variadic { &self.args[..self.fixed_count] } else { &self.args };
+
+ let args_capacity: usize = args.iter().map(|arg|
if arg.pad.is_some() { 1 } else { 0 } +
if let PassMode::Pair(_, _) = arg.mode { 2 } else { 1 }
).sum();
@@ -371,7 +375,7 @@
}
};
- for arg in &self.args {
+ for arg in args {
// add padding
if let Some(ty) = arg.pad {
llargument_tys.push(ty.llvm_type(cx));
diff --git a/compiler/rustc_codegen_llvm/src/allocator.rs b/compiler/rustc_codegen_llvm/src/allocator.rs
index 068e5e9..2d79b73 100644
--- a/compiler/rustc_codegen_llvm/src/allocator.rs
+++ b/compiler/rustc_codegen_llvm/src/allocator.rs
@@ -78,8 +78,14 @@
.enumerate()
.map(|(i, _)| llvm::LLVMGetParam(llfn, i as c_uint))
.collect::<Vec<_>>();
- let ret =
- llvm::LLVMRustBuildCall(llbuilder, callee, args.as_ptr(), args.len() as c_uint, None);
+ let ret = llvm::LLVMRustBuildCall(
+ llbuilder,
+ ty,
+ callee,
+ args.as_ptr(),
+ args.len() as c_uint,
+ None,
+ );
llvm::LLVMSetTailCall(ret, True);
if output.is_some() {
llvm::LLVMBuildRet(llbuilder, ret);
@@ -121,7 +127,8 @@
.enumerate()
.map(|(i, _)| llvm::LLVMGetParam(llfn, i as c_uint))
.collect::<Vec<_>>();
- let ret = llvm::LLVMRustBuildCall(llbuilder, callee, args.as_ptr(), args.len() as c_uint, None);
+ let ret =
+ llvm::LLVMRustBuildCall(llbuilder, ty, callee, args.as_ptr(), args.len() as c_uint, None);
llvm::LLVMSetTailCall(ret, True);
llvm::LLVMBuildRetVoid(llbuilder);
llvm::LLVMDisposeBuilder(llbuilder);
diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs
index 7bd9397..e0d3127 100644
--- a/compiler/rustc_codegen_llvm/src/asm.rs
+++ b/compiler/rustc_codegen_llvm/src/asm.rs
@@ -302,11 +302,19 @@
"~{flags}".to_string(),
]);
}
- InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => {}
+ InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => {
+ constraints.extend_from_slice(&[
+ "~{vtype}".to_string(),
+ "~{vl}".to_string(),
+ "~{vxsat}".to_string(),
+ "~{vxrm}".to_string(),
+ ]);
+ }
InlineAsmArch::Nvptx64 => {}
InlineAsmArch::PowerPC | InlineAsmArch::PowerPC64 => {}
InlineAsmArch::Hexagon => {}
InlineAsmArch::Mips | InlineAsmArch::Mips64 => {}
+ InlineAsmArch::S390x => {}
InlineAsmArch::SpirV => {}
InlineAsmArch::Wasm32 => {}
InlineAsmArch::Bpf => {}
@@ -425,7 +433,7 @@
}
}
-fn inline_asm_call(
+pub(crate) fn inline_asm_call(
bx: &mut Builder<'a, 'll, 'tcx>,
asm: &str,
cons: &str,
@@ -464,7 +472,7 @@
alignstack,
llvm::AsmDialect::from_generic(dia),
);
- let call = bx.call(v, inputs, None);
+ let call = bx.call(fty, v, inputs, None);
// Store mark in a metadata node so we can map LLVM errors
// back to source locations. See #17552.
@@ -608,6 +616,10 @@
InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::reg) => "r",
InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::reg_nonzero) => "b",
InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::freg) => "f",
+ InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::cr)
+ | InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::xer) => {
+ unreachable!("clobber-only")
+ }
InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::reg) => "r",
InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::freg) => "f",
InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::vreg) => {
@@ -626,6 +638,8 @@
InlineAsmRegClass::Wasm(WasmInlineAsmRegClass::local) => "r",
InlineAsmRegClass::Bpf(BpfInlineAsmRegClass::reg) => "r",
InlineAsmRegClass::Bpf(BpfInlineAsmRegClass::wreg) => "w",
+ InlineAsmRegClass::S390x(S390xInlineAsmRegClass::reg) => "r",
+ InlineAsmRegClass::S390x(S390xInlineAsmRegClass::freg) => "f",
InlineAsmRegClass::SpirV(SpirVInlineAsmRegClass::reg) => {
bug!("LLVM backend does not support SPIR-V")
}
@@ -704,6 +718,7 @@
}
InlineAsmRegClass::Wasm(WasmInlineAsmRegClass::local) => None,
InlineAsmRegClass::Bpf(_) => None,
+ InlineAsmRegClass::S390x(_) => None,
InlineAsmRegClass::SpirV(SpirVInlineAsmRegClass::reg) => {
bug!("LLVM backend does not support SPIR-V")
}
@@ -744,6 +759,10 @@
InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::reg) => cx.type_i32(),
InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::reg_nonzero) => cx.type_i32(),
InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::freg) => cx.type_f64(),
+ InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::cr)
+ | InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::xer) => {
+ unreachable!("clobber-only")
+ }
InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::reg) => cx.type_i32(),
InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::freg) => cx.type_f32(),
InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::vreg) => {
@@ -762,6 +781,8 @@
InlineAsmRegClass::Wasm(WasmInlineAsmRegClass::local) => cx.type_i32(),
InlineAsmRegClass::Bpf(BpfInlineAsmRegClass::reg) => cx.type_i64(),
InlineAsmRegClass::Bpf(BpfInlineAsmRegClass::wreg) => cx.type_i32(),
+ InlineAsmRegClass::S390x(S390xInlineAsmRegClass::reg) => cx.type_i32(),
+ InlineAsmRegClass::S390x(S390xInlineAsmRegClass::freg) => cx.type_f64(),
InlineAsmRegClass::SpirV(SpirVInlineAsmRegClass::reg) => {
bug!("LLVM backend does not support SPIR-V")
}
diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs
index 5b4a187..791604a 100644
--- a/compiler/rustc_codegen_llvm/src/back/write.rs
+++ b/compiler/rustc_codegen_llvm/src/back/write.rs
@@ -296,39 +296,8 @@
}
let (cgcx, _) = *(user as *const (&CodegenContext<LlvmCodegenBackend>, &Handler));
- // Recover the post-substitution assembly code from LLVM for better
- // diagnostics.
- let mut have_source = false;
- let mut buffer = String::new();
- let mut level = llvm::DiagnosticLevel::Error;
- let mut loc = 0;
- let mut ranges = [0; 8];
- let mut num_ranges = ranges.len() / 2;
- let msg = llvm::build_string(|msg| {
- buffer = llvm::build_string(|buffer| {
- have_source = llvm::LLVMRustUnpackSMDiagnostic(
- diag,
- msg,
- buffer,
- &mut level,
- &mut loc,
- ranges.as_mut_ptr(),
- &mut num_ranges,
- );
- })
- .expect("non-UTF8 inline asm");
- })
- .expect("non-UTF8 SMDiagnostic");
-
- let source = have_source.then(|| {
- let mut spans = vec![InnerSpan::new(loc as usize, loc as usize)];
- for i in 0..num_ranges {
- spans.push(InnerSpan::new(ranges[i * 2] as usize, ranges[i * 2 + 1] as usize));
- }
- (buffer, spans)
- });
-
- report_inline_asm(cgcx, msg, level, cookie, source);
+ let smdiag = llvm::diagnostic::SrcMgrDiagnostic::unpack(diag);
+ report_inline_asm(cgcx, smdiag.message, smdiag.level, cookie, smdiag.source);
}
unsafe extern "C" fn diagnostic_handler(info: &DiagnosticInfo, user: *mut c_void) {
@@ -339,13 +308,7 @@
match llvm::diagnostic::Diagnostic::unpack(info) {
llvm::diagnostic::InlineAsm(inline) => {
- report_inline_asm(
- cgcx,
- llvm::twine_to_string(inline.message),
- inline.level,
- inline.cookie,
- None,
- );
+ report_inline_asm(cgcx, inline.message, inline.level, inline.cookie, inline.source);
}
llvm::diagnostic::Optimization(opt) => {
diff --git a/compiler/rustc_codegen_llvm/src/base.rs b/compiler/rustc_codegen_llvm/src/base.rs
index cc3cbea..a6bdbd1 100644
--- a/compiler/rustc_codegen_llvm/src/base.rs
+++ b/compiler/rustc_codegen_llvm/src/base.rs
@@ -157,16 +157,18 @@
}
// Finalize code coverage by injecting the coverage map. Note, the coverage map will
- // also be added to the `llvm.used` variable, created next.
+ // also be added to the `llvm.compiler.used` variable, created next.
if cx.sess().instrument_coverage() {
cx.coverageinfo_finalize();
}
- // Create the llvm.used variable
- // This variable has type [N x i8*] and is stored in the llvm.metadata section
+ // Create the llvm.used and llvm.compiler.used variables.
if !cx.used_statics().borrow().is_empty() {
cx.create_used_variable()
}
+ if !cx.compiler_used_statics().borrow().is_empty() {
+ cx.create_compiler_used_variable()
+ }
// Finalize debuginfo
if cx.sess().opts.debuginfo != DebugInfo::None {
diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs
index 5675a5d..47529f7 100644
--- a/compiler/rustc_codegen_llvm/src/builder.rs
+++ b/compiler/rustc_codegen_llvm/src/builder.rs
@@ -88,7 +88,7 @@
}
}
-impl abi::LayoutOf for Builder<'_, '_, 'tcx> {
+impl abi::LayoutOf<'tcx> for Builder<'_, '_, 'tcx> {
type Ty = Ty<'tcx>;
type TyAndLayout = TyAndLayout<'tcx>;
@@ -200,6 +200,7 @@
fn invoke(
&mut self,
+ llty: &'ll Type,
llfn: &'ll Value,
args: &[&'ll Value],
then: &'ll BasicBlock,
@@ -208,13 +209,14 @@
) -> &'ll Value {
debug!("invoke {:?} with args ({:?})", llfn, args);
- let args = self.check_call("invoke", llfn, args);
+ let args = self.check_call("invoke", llty, llfn, args);
let bundle = funclet.map(|funclet| funclet.bundle());
let bundle = bundle.as_ref().map(|b| &*b.raw);
unsafe {
llvm::LLVMRustBuildInvoke(
self.llbuilder,
+ llty,
llfn,
args.as_ptr(),
args.len() as c_uint,
@@ -369,8 +371,7 @@
},
};
- let intrinsic = self.get_intrinsic(&name);
- let res = self.call(intrinsic, &[lhs, rhs], None);
+ let res = self.call_intrinsic(name, &[lhs, rhs]);
(self.extract_value(res, 0), self.extract_value(res, 1))
}
@@ -461,7 +462,6 @@
load: &'ll Value,
scalar: &abi::Scalar,
) {
- let vr = scalar.valid_range.clone();
match scalar.value {
abi::Int(..) => {
let range = scalar.valid_range_exclusive(bx);
@@ -469,7 +469,7 @@
bx.range_metadata(load, range);
}
}
- abi::Pointer if vr.start() < vr.end() && !vr.contains(&0) => {
+ abi::Pointer if !scalar.valid_range.contains_zero() => {
bx.nonnull_metadata(load);
}
_ => {}
@@ -497,9 +497,10 @@
OperandValue::Immediate(self.to_immediate(llval, place.layout))
} else if let abi::Abi::ScalarPair(ref a, ref b) = place.layout.abi {
let b_offset = a.value.size(self).align_to(b.value.align(self).abi);
+ let pair_ty = place.layout.llvm_type(self);
let mut load = |i, scalar: &abi::Scalar, align| {
- let llptr = self.struct_gep(place.llval, i as u64);
+ let llptr = self.struct_gep(pair_ty, place.llval, i as u64);
let llty = place.layout.scalar_pair_element_llvm_type(self, i, false);
let load = self.load(llty, llptr, align);
scalar_load_metadata(self, load, scalar);
@@ -543,7 +544,11 @@
.val
.store(&mut body_bx, PlaceRef::new_sized_aligned(current, cg_elem.layout, align));
- let next = body_bx.inbounds_gep(current, &[self.const_usize(1)]);
+ let next = body_bx.inbounds_gep(
+ self.backend_type(cg_elem.layout),
+ current,
+ &[self.const_usize(1)],
+ );
body_bx.br(header_bx.llbb());
header_bx.add_incoming_to_phi(current, next, body_bx.llbb());
@@ -552,7 +557,7 @@
fn range_metadata(&mut self, load: &'ll Value, range: Range<u128>) {
if self.sess().target.arch == "amdgpu" {
- // amdgpu/LLVM does something weird and thinks a i64 value is
+ // amdgpu/LLVM does something weird and thinks an i64 value is
// split into a v2i32, halving the bitwidth LLVM expects,
// tripping an assertion. So, for now, just disable this
// optimization.
@@ -639,10 +644,11 @@
}
}
- fn gep(&mut self, ptr: &'ll Value, indices: &[&'ll Value]) -> &'ll Value {
+ fn gep(&mut self, ty: &'ll Type, ptr: &'ll Value, indices: &[&'ll Value]) -> &'ll Value {
unsafe {
- llvm::LLVMBuildGEP(
+ llvm::LLVMBuildGEP2(
self.llbuilder,
+ ty,
ptr,
indices.as_ptr(),
indices.len() as c_uint,
@@ -651,10 +657,16 @@
}
}
- fn inbounds_gep(&mut self, ptr: &'ll Value, indices: &[&'ll Value]) -> &'ll Value {
+ fn inbounds_gep(
+ &mut self,
+ ty: &'ll Type,
+ ptr: &'ll Value,
+ indices: &[&'ll Value],
+ ) -> &'ll Value {
unsafe {
- llvm::LLVMBuildInBoundsGEP(
+ llvm::LLVMBuildInBoundsGEP2(
self.llbuilder,
+ ty,
ptr,
indices.as_ptr(),
indices.len() as c_uint,
@@ -663,9 +675,9 @@
}
}
- fn struct_gep(&mut self, ptr: &'ll Value, idx: u64) -> &'ll Value {
+ fn struct_gep(&mut self, ty: &'ll Type, ptr: &'ll Value, idx: u64) -> &'ll Value {
assert_eq!(idx as c_uint as u64, idx);
- unsafe { llvm::LLVMBuildStructGEP(self.llbuilder, ptr, idx as c_uint, UNNAMED) }
+ unsafe { llvm::LLVMBuildStructGEP2(self.llbuilder, ty, ptr, idx as c_uint, UNNAMED) }
}
/* Casts */
@@ -683,8 +695,7 @@
let float_width = self.cx.float_width(src_ty);
let int_width = self.cx.int_width(dest_ty);
let name = format!("llvm.fptoui.sat.i{}.f{}", int_width, float_width);
- let intrinsic = self.get_intrinsic(&name);
- return Some(self.call(intrinsic, &[val], None));
+ return Some(self.call_intrinsic(&name, &[val]));
}
None
@@ -696,8 +707,7 @@
let float_width = self.cx.float_width(src_ty);
let int_width = self.cx.int_width(dest_ty);
let name = format!("llvm.fptosi.sat.i{}.f{}", int_width, float_width);
- let intrinsic = self.get_intrinsic(&name);
- return Some(self.call(intrinsic, &[val], None));
+ return Some(self.call_intrinsic(&name, &[val]));
}
None
@@ -731,8 +741,7 @@
_ => None,
};
if let Some(name) = name {
- let intrinsic = self.get_intrinsic(name);
- return self.call(intrinsic, &[val], None);
+ return self.call_intrinsic(name, &[val]);
}
}
}
@@ -754,8 +763,7 @@
_ => None,
};
if let Some(name) = name {
- let intrinsic = self.get_intrinsic(name);
- return self.call(intrinsic, &[val], None);
+ return self.call_intrinsic(name, &[val]);
}
}
}
@@ -1103,12 +1111,17 @@
);
let llfn = unsafe { llvm::LLVMRustGetInstrProfIncrementIntrinsic(self.cx().llmod) };
+ let llty = self.cx.type_func(
+ &[self.cx.type_i8p(), self.cx.type_i64(), self.cx.type_i32(), self.cx.type_i32()],
+ self.cx.type_void(),
+ );
let args = &[fn_name, hash, num_counters, index];
- let args = self.check_call("call", llfn, args);
+ let args = self.check_call("call", llty, llfn, args);
unsafe {
let _ = llvm::LLVMRustBuildCall(
self.llbuilder,
+ llty,
llfn,
args.as_ptr() as *const &llvm::Value,
args.len() as c_uint,
@@ -1119,19 +1132,21 @@
fn call(
&mut self,
+ llty: &'ll Type,
llfn: &'ll Value,
args: &[&'ll Value],
funclet: Option<&Funclet<'ll>>,
) -> &'ll Value {
debug!("call {:?} with args ({:?})", llfn, args);
- let args = self.check_call("call", llfn, args);
+ let args = self.check_call("call", llty, llfn, args);
let bundle = funclet.map(|funclet| funclet.bundle());
let bundle = bundle.as_ref().map(|b| &*b.raw);
unsafe {
llvm::LLVMRustBuildCall(
self.llbuilder,
+ llty,
llfn,
args.as_ptr() as *const &llvm::Value,
args.len() as c_uint,
@@ -1301,15 +1316,10 @@
fn check_call<'b>(
&mut self,
typ: &str,
+ fn_ty: &'ll Type,
llfn: &'ll Value,
args: &'b [&'ll Value],
) -> Cow<'b, [&'ll Value]> {
- let mut fn_ty = self.cx.val_ty(llfn);
- // Strip off pointers
- while self.cx.type_kind(fn_ty) == TypeKind::Pointer {
- fn_ty = self.cx.element_type(fn_ty);
- }
-
assert!(
self.cx.type_kind(fn_ty) == TypeKind::Function,
"builder::{} not passed a function, but {:?}",
@@ -1350,6 +1360,11 @@
unsafe { llvm::LLVMBuildVAArg(self.llbuilder, list, ty, UNNAMED) }
}
+ crate fn call_intrinsic(&mut self, intrinsic: &str, args: &[&'ll Value]) -> &'ll Value {
+ let (ty, f) = self.cx.get_intrinsic(intrinsic);
+ self.call(ty, f, args, None)
+ }
+
fn call_lifetime_intrinsic(&mut self, intrinsic: &str, ptr: &'ll Value, size: Size) {
let size = size.bytes();
if size == 0 {
@@ -1360,10 +1375,8 @@
return;
}
- let lifetime_intrinsic = self.cx.get_intrinsic(intrinsic);
-
let ptr = self.pointercast(ptr, self.cx.type_i8p());
- self.call(lifetime_intrinsic, &[self.cx.const_u64(size), ptr], None);
+ self.call_intrinsic(intrinsic, &[self.cx.const_u64(size), ptr]);
}
pub(crate) fn phi(
diff --git a/compiler/rustc_codegen_llvm/src/common.rs b/compiler/rustc_codegen_llvm/src/common.rs
index 35e7262..5532f53 100644
--- a/compiler/rustc_codegen_llvm/src/common.rs
+++ b/compiler/rustc_codegen_llvm/src/common.rs
@@ -268,7 +268,8 @@
}
};
let llval = unsafe {
- llvm::LLVMConstInBoundsGEP(
+ llvm::LLVMRustConstInBoundsGEP2(
+ self.type_i8(),
self.const_bitcast(base_addr, self.type_i8p_ext(base_addr_space)),
&self.const_usize(offset.bytes()),
1,
@@ -303,7 +304,8 @@
let base_addr = self.static_addr_of(init, alloc.align, None);
let llval = unsafe {
- llvm::LLVMConstInBoundsGEP(
+ llvm::LLVMRustConstInBoundsGEP2(
+ self.type_i8(),
self.const_bitcast(base_addr, self.type_i8p()),
&self.const_usize(offset.bytes()),
1,
diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs
index 3ca295f..a4e4fc4 100644
--- a/compiler/rustc_codegen_llvm/src/consts.rs
+++ b/compiler/rustc_codegen_llvm/src/consts.rs
@@ -11,12 +11,16 @@
use rustc_hir::def_id::DefId;
use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs};
use rustc_middle::mir::interpret::{
- read_target_uint, Allocation, ErrorHandled, GlobalAlloc, Pointer, Scalar as InterpScalar,
+ read_target_uint, Allocation, ErrorHandled, GlobalAlloc, InitChunk, Pointer,
+ Scalar as InterpScalar,
};
use rustc_middle::mir::mono::MonoItem;
use rustc_middle::ty::{self, Instance, Ty};
use rustc_middle::{bug, span_bug};
-use rustc_target::abi::{AddressSpace, Align, HasDataLayout, LayoutOf, Primitive, Scalar, Size};
+use rustc_target::abi::{
+ AddressSpace, Align, HasDataLayout, LayoutOf, Primitive, Scalar, Size, WrappingRange,
+};
+use std::ops::Range;
use tracing::debug;
pub fn const_alloc_to_llvm(cx: &CodegenCx<'ll, '_>, alloc: &Allocation) -> &'ll Value {
@@ -24,6 +28,57 @@
let dl = cx.data_layout();
let pointer_size = dl.pointer_size.bytes() as usize;
+ // Note: this function may call `inspect_with_uninit_and_ptr_outside_interpreter`,
+ // so `range` must be within the bounds of `alloc` and not contain or overlap a relocation.
+ fn append_chunks_of_init_and_uninit_bytes<'ll, 'a, 'b>(
+ llvals: &mut Vec<&'ll Value>,
+ cx: &'a CodegenCx<'ll, 'b>,
+ alloc: &'a Allocation,
+ range: Range<usize>,
+ ) {
+ let mut chunks = alloc
+ .init_mask()
+ .range_as_init_chunks(Size::from_bytes(range.start), Size::from_bytes(range.end));
+
+ let chunk_to_llval = move |chunk| match chunk {
+ InitChunk::Init(range) => {
+ let range = (range.start.bytes() as usize)..(range.end.bytes() as usize);
+ let bytes = alloc.inspect_with_uninit_and_ptr_outside_interpreter(range);
+ cx.const_bytes(bytes)
+ }
+ InitChunk::Uninit(range) => {
+ let len = range.end.bytes() - range.start.bytes();
+ cx.const_undef(cx.type_array(cx.type_i8(), len))
+ }
+ };
+
+ // Generating partially-uninit consts inhibits optimizations, so it is disabled by default.
+ // See https://github.com/rust-lang/rust/issues/84565.
+ let allow_partially_uninit =
+ match cx.sess().opts.debugging_opts.partially_uninit_const_threshold {
+ Some(max) => range.len() <= max,
+ None => false,
+ };
+
+ if allow_partially_uninit {
+ llvals.extend(chunks.map(chunk_to_llval));
+ } else {
+ let llval = match (chunks.next(), chunks.next()) {
+ (Some(chunk), None) => {
+ // exactly one chunk, either fully init or fully uninit
+ chunk_to_llval(chunk)
+ }
+ _ => {
+ // partially uninit, codegen as if it was initialized
+ // (using some arbitrary value for uninit bytes)
+ let bytes = alloc.inspect_with_uninit_and_ptr_outside_interpreter(range);
+ cx.const_bytes(bytes)
+ }
+ };
+ llvals.push(llval);
+ }
+ }
+
let mut next_offset = 0;
for &(offset, alloc_id) in alloc.relocations().iter() {
let offset = offset.bytes();
@@ -32,12 +87,8 @@
if offset > next_offset {
// This `inspect` is okay since we have checked that it is not within a relocation, it
// is within the bounds of the allocation, and it doesn't affect interpreter execution
- // (we inspect the result after interpreter execution). Any undef byte is replaced with
- // some arbitrary byte value.
- //
- // FIXME: relay undef bytes to codegen as undef const bytes
- let bytes = alloc.inspect_with_uninit_and_ptr_outside_interpreter(next_offset..offset);
- llvals.push(cx.const_bytes(bytes));
+ // (we inspect the result after interpreter execution).
+ append_chunks_of_init_and_uninit_bytes(&mut llvals, cx, alloc, next_offset..offset);
}
let ptr_offset = read_target_uint(
dl.endian,
@@ -59,7 +110,7 @@
Pointer::new(alloc_id, Size::from_bytes(ptr_offset)),
&cx.tcx,
),
- &Scalar { value: Primitive::Pointer, valid_range: 0..=!0 },
+ &Scalar { value: Primitive::Pointer, valid_range: WrappingRange { start: 0, end: !0 } },
cx.type_i8p_ext(address_space),
));
next_offset = offset + pointer_size;
@@ -68,12 +119,8 @@
let range = next_offset..alloc.len();
// This `inspect` is okay since we have check that it is after all relocations, it is
// within the bounds of the allocation, and it doesn't affect interpreter execution (we
- // inspect the result after interpreter execution). Any undef byte is replaced with some
- // arbitrary byte value.
- //
- // FIXME: relay undef bytes to codegen as undef const bytes
- let bytes = alloc.inspect_with_uninit_and_ptr_outside_interpreter(range);
- llvals.push(cx.const_bytes(bytes));
+ // inspect the result after interpreter execution).
+ append_chunks_of_init_and_uninit_bytes(&mut llvals, cx, alloc, range);
}
cx.const_struct(&llvals, true)
@@ -474,7 +521,13 @@
}
if attrs.flags.contains(CodegenFnAttrFlags::USED) {
- self.add_used_global(g);
+ // The semantics of #[used] in Rust only require the symbol to make it into the
+ // object file. It is explicitly allowed for the linker to strip the symbol if it
+ // is dead. As such, use llvm.compiler.used instead of llvm.used.
+ // Additionally, https://reviews.llvm.org/D97448 in LLVM 13 started emitting unique
+ // sections with SHF_GNU_RETAIN flag for llvm.used symbols, which may trigger bugs
+ // in some versions of the gold linker.
+ self.add_compiler_used_global(g);
}
}
}
@@ -484,4 +537,11 @@
let cast = unsafe { llvm::LLVMConstPointerCast(global, self.type_i8p()) };
self.used_statics.borrow_mut().push(cast);
}
+
+ /// Add a global value to a list to be stored in the `llvm.compiler.used` variable,
+ /// an array of i8*.
+ fn add_compiler_used_global(&self, global: &'ll Value) {
+ let cast = unsafe { llvm::LLVMConstPointerCast(global, self.type_i8p()) };
+ self.compiler_used_statics.borrow_mut().push(cast);
+ }
}
diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs
index 5925985..45da18d 100644
--- a/compiler/rustc_codegen_llvm/src/context.rs
+++ b/compiler/rustc_codegen_llvm/src/context.rs
@@ -24,6 +24,7 @@
use rustc_span::symbol::Symbol;
use rustc_target::abi::{HasDataLayout, LayoutOf, PointeeInfo, Size, TargetDataLayout, VariantIdx};
use rustc_target::spec::{HasTargetSpec, RelocModel, Target, TlsModel};
+use smallvec::SmallVec;
use std::cell::{Cell, RefCell};
use std::ffi::CStr;
@@ -74,8 +75,16 @@
/// See <https://llvm.org/docs/LangRef.html#the-llvm-used-global-variable> for details
pub used_statics: RefCell<Vec<&'ll Value>>,
- pub lltypes: RefCell<FxHashMap<(Ty<'tcx>, Option<VariantIdx>), &'ll Type>>,
+ /// Statics that will be placed in the llvm.compiler.used variable
+ /// See <https://llvm.org/docs/LangRef.html#the-llvm-compiler-used-global-variable> for details
+ pub compiler_used_statics: RefCell<Vec<&'ll Value>>,
+
+ /// Mapping of non-scalar types to llvm types and field remapping if needed.
+ pub type_lowering: RefCell<FxHashMap<(Ty<'tcx>, Option<VariantIdx>), TypeLowering<'ll>>>,
+
+ /// Mapping of scalar types to llvm types.
pub scalar_lltypes: RefCell<FxHashMap<Ty<'tcx>, &'ll Type>>,
+
pub pointee_infos: RefCell<FxHashMap<(Ty<'tcx>, Size), Option<PointeeInfo>>>,
pub isize_ty: &'ll Type,
@@ -84,14 +93,23 @@
eh_personality: Cell<Option<&'ll Value>>,
eh_catch_typeinfo: Cell<Option<&'ll Value>>,
- pub rust_try_fn: Cell<Option<&'ll Value>>,
+ pub rust_try_fn: Cell<Option<(&'ll Type, &'ll Value)>>,
- intrinsics: RefCell<FxHashMap<&'static str, &'ll Value>>,
+ intrinsics: RefCell<FxHashMap<&'static str, (&'ll Type, &'ll Value)>>,
/// A counter that is used for generating local symbol names
local_gen_sym_counter: Cell<usize>,
}
+pub struct TypeLowering<'ll> {
+ /// Associated LLVM type
+ pub lltype: &'ll Type,
+
+ /// If padding is used the slice maps fields from source order
+ /// to llvm order.
+ pub field_remapping: Option<SmallVec<[u32; 4]>>,
+}
+
fn to_llvm_tls_model(tls_model: TlsModel) -> llvm::ThreadLocalMode {
match tls_model {
TlsModel::GeneralDynamic => llvm::ThreadLocalMode::GeneralDynamic,
@@ -101,10 +119,6 @@
}
}
-fn strip_powerpc64_vectors(data_layout: String) -> String {
- data_layout.replace("-v256:256:256-v512:512:512", "")
-}
-
pub unsafe fn create_module(
tcx: TyCtxt<'_>,
llcx: &'ll llvm::Context,
@@ -116,7 +130,18 @@
let mut target_data_layout = sess.target.data_layout.clone();
if llvm_util::get_version() < (12, 0, 0) && sess.target.arch == "powerpc64" {
- target_data_layout = strip_powerpc64_vectors(target_data_layout);
+ target_data_layout = target_data_layout.replace("-v256:256:256-v512:512:512", "");
+ }
+ if llvm_util::get_version() < (13, 0, 0) {
+ if sess.target.arch == "powerpc64" {
+ target_data_layout = target_data_layout.replace("-S128", "");
+ }
+ if sess.target.arch == "wasm32" {
+ target_data_layout = "e-m:e-p:32:32-i64:64-n32:64-S128".to_string();
+ }
+ if sess.target.arch == "wasm64" {
+ target_data_layout = "e-m:e-p:64:64-i64:64-n32:64-S128".to_string();
+ }
}
// Ensure the data-layout values hardcoded remain the defaults.
@@ -304,7 +329,8 @@
const_globals: Default::default(),
statics_to_rauw: RefCell::new(Vec::new()),
used_statics: RefCell::new(Vec::new()),
- lltypes: Default::default(),
+ compiler_used_statics: RefCell::new(Vec::new()),
+ type_lowering: Default::default(),
scalar_lltypes: Default::default(),
pointee_infos: Default::default(),
isize_ty,
@@ -326,6 +352,18 @@
pub fn coverage_context(&'a self) -> Option<&'a coverageinfo::CrateCoverageContext<'ll, 'tcx>> {
self.coverage_cx.as_ref()
}
+
+ fn create_used_variable_impl(&self, name: &'static CStr, values: &[&'ll Value]) {
+ let section = cstr!("llvm.metadata");
+ let array = self.const_array(&self.type_ptr_to(self.type_i8()), values);
+
+ unsafe {
+ let g = llvm::LLVMAddGlobal(self.llmod, self.val_ty(array), name.as_ptr());
+ llvm::LLVMSetInitializer(g, array);
+ llvm::LLVMRustSetLinkage(g, llvm::Linkage::AppendingLinkage);
+ llvm::LLVMSetSection(g, section.as_ptr());
+ }
+ }
}
impl MiscMethods<'tcx> for CodegenCx<'ll, 'tcx> {
@@ -416,6 +454,10 @@
&self.used_statics
}
+ fn compiler_used_statics(&self) -> &RefCell<Vec<&'ll Value>> {
+ &self.compiler_used_statics
+ }
+
fn set_frame_pointer_type(&self, llfn: &'ll Value) {
attributes::set_frame_pointer_type(self, llfn)
}
@@ -426,17 +468,14 @@
}
fn create_used_variable(&self) {
- let name = cstr!("llvm.used");
- let section = cstr!("llvm.metadata");
- let array =
- self.const_array(&self.type_ptr_to(self.type_i8()), &*self.used_statics.borrow());
+ self.create_used_variable_impl(cstr!("llvm.used"), &*self.used_statics.borrow());
+ }
- unsafe {
- let g = llvm::LLVMAddGlobal(self.llmod, self.val_ty(array), name.as_ptr());
- llvm::LLVMSetInitializer(g, array);
- llvm::LLVMRustSetLinkage(g, llvm::Linkage::AppendingLinkage);
- llvm::LLVMSetSection(g, section.as_ptr());
- }
+ fn create_compiler_used_variable(&self) {
+ self.create_used_variable_impl(
+ cstr!("llvm.compiler.used"),
+ &*self.compiler_used_statics.borrow(),
+ );
}
fn declare_c_main(&self, fn_type: Self::Type) -> Option<Self::Function> {
@@ -452,7 +491,7 @@
}
impl CodegenCx<'b, 'tcx> {
- crate fn get_intrinsic(&self, key: &str) -> &'b Value {
+ crate fn get_intrinsic(&self, key: &str) -> (&'b Type, &'b Value) {
if let Some(v) = self.intrinsics.borrow().get(key).cloned() {
return v;
}
@@ -465,18 +504,18 @@
name: &'static str,
args: Option<&[&'b llvm::Type]>,
ret: &'b llvm::Type,
- ) -> &'b llvm::Value {
+ ) -> (&'b llvm::Type, &'b llvm::Value) {
let fn_ty = if let Some(args) = args {
self.type_func(args, ret)
} else {
self.type_variadic_func(&[], ret)
};
let f = self.declare_cfn(name, llvm::UnnamedAddr::No, fn_ty);
- self.intrinsics.borrow_mut().insert(name, f);
- f
+ self.intrinsics.borrow_mut().insert(name, (fn_ty, f));
+ (fn_ty, f)
}
- fn declare_intrinsic(&self, key: &str) -> Option<&'b Value> {
+ fn declare_intrinsic(&self, key: &str) -> Option<(&'b Type, &'b Value)> {
macro_rules! ifn {
($name:expr, fn() -> $ret:expr) => (
if key == $name {
@@ -796,7 +835,7 @@
}
}
-impl LayoutOf for CodegenCx<'ll, 'tcx> {
+impl LayoutOf<'tcx> for CodegenCx<'ll, 'tcx> {
type Ty = Ty<'tcx>;
type TyAndLayout = TyAndLayout<'tcx>;
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs b/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs
index de3f719..c33d35c 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs
@@ -15,12 +15,11 @@
/// .debug_gdb_scripts global is referenced, so it isn't removed by the linker.
pub fn insert_reference_to_gdb_debug_scripts_section_global(bx: &mut Builder<'_, '_, '_>) {
if needs_gdb_debug_scripts_section(bx) {
- let gdb_debug_scripts_section = get_or_insert_gdb_debug_scripts_section_global(bx);
+ let gdb_debug_scripts_section =
+ bx.const_bitcast(get_or_insert_gdb_debug_scripts_section_global(bx), bx.type_i8p());
// Load just the first byte as that's all that's necessary to force
// LLVM to keep around the reference to the global.
- let indices = [bx.const_i32(0), bx.const_i32(0)];
- let element = bx.inbounds_gep(gdb_debug_scripts_section, &indices);
- let volative_load_instruction = bx.volatile_load(bx.type_i8(), element);
+ let volative_load_instruction = bx.volatile_load(bx.type_i8(), gdb_debug_scripts_section);
unsafe {
llvm::LLVMSetAlignment(volative_load_instruction, 1);
}
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
index 7e136c1..346c51c 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
@@ -35,6 +35,7 @@
use rustc_middle::{bug, span_bug};
use rustc_session::config::{self, DebugInfo};
use rustc_span::symbol::{Interner, Symbol};
+use rustc_span::FileNameDisplayPreference;
use rustc_span::{self, SourceFile, SourceFileHash, Span};
use rustc_target::abi::{Abi, Align, HasDataLayout, Integer, LayoutOf, TagEncoding};
use rustc_target::abi::{Int, Pointer, F32, F64};
@@ -771,7 +772,13 @@
let hash = Some(&source_file.src_hash);
let file_name = Some(source_file.name.prefer_remapped().to_string());
let directory = if source_file.is_real_file() && !source_file.is_imported() {
- Some(cx.sess().working_dir.to_string_lossy(false).to_string())
+ Some(
+ cx.sess()
+ .opts
+ .working_dir
+ .to_string_lossy(FileNameDisplayPreference::Remapped)
+ .to_string(),
+ )
} else {
// If the path comes from an upstream crate we assume it has been made
// independent of the compiler's working directory one way or another.
@@ -999,7 +1006,7 @@
let producer = format!("clang LLVM ({})", rustc_producer);
let name_in_debuginfo = name_in_debuginfo.to_string_lossy();
- let work_dir = tcx.sess.working_dir.to_string_lossy(false);
+ let work_dir = tcx.sess.opts.working_dir.to_string_lossy(FileNameDisplayPreference::Remapped);
let flags = "\0";
let output_filenames = tcx.output_filenames(());
let out_dir = &output_filenames.out_directory;
@@ -1280,6 +1287,31 @@
// Tuples
//=-----------------------------------------------------------------------------
+/// Returns names of captured upvars for closures and generators.
+///
+/// Here are some examples:
+/// - `name__field1__field2` when the upvar is captured by value.
+/// - `_ref__name__field` when the upvar is captured by reference.
+fn closure_saved_names_of_captured_variables(tcx: TyCtxt<'tcx>, def_id: DefId) -> Vec<String> {
+ let body = tcx.optimized_mir(def_id);
+
+ body.var_debug_info
+ .iter()
+ .filter_map(|var| {
+ let is_ref = match var.value {
+ mir::VarDebugInfoContents::Place(place) if place.local == mir::Local::new(1) => {
+ // The projection is either `[.., Field, Deref]` or `[.., Field]`. It
+ // implies whether the variable is captured by value or by reference.
+ matches!(place.projection.last().unwrap(), mir::ProjectionElem::Deref)
+ }
+ _ => return None,
+ };
+ let prefix = if is_ref { "_ref__" } else { "" };
+ Some(prefix.to_owned() + &var.name.as_str())
+ })
+ .collect::<Vec<_>>()
+}
+
/// Creates `MemberDescription`s for the fields of a tuple.
struct TupleMemberDescriptionFactory<'tcx> {
ty: Ty<'tcx>,
@@ -1289,14 +1321,25 @@
impl<'tcx> TupleMemberDescriptionFactory<'tcx> {
fn create_member_descriptions(&self, cx: &CodegenCx<'ll, 'tcx>) -> Vec<MemberDescription<'ll>> {
+ let mut capture_names = match *self.ty.kind() {
+ ty::Generator(def_id, ..) | ty::Closure(def_id, ..) => {
+ Some(closure_saved_names_of_captured_variables(cx.tcx, def_id).into_iter())
+ }
+ _ => None,
+ };
let layout = cx.layout_of(self.ty);
self.component_types
.iter()
.enumerate()
.map(|(i, &component_type)| {
let (size, align) = cx.size_and_align_of(component_type);
+ let name = if let Some(names) = capture_names.as_mut() {
+ names.next().unwrap()
+ } else {
+ format!("__{}", i)
+ };
MemberDescription {
- name: format!("__{}", i),
+ name,
type_metadata: type_metadata(cx, component_type, self.span),
offset: layout.fields.offset(i),
size,
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
index 8375d4c..914376d 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
@@ -499,7 +499,7 @@
ty::Adt(def, ..) if !def.is_box() => {
// Again, only create type information if full debuginfo is enabled
if cx.sess().opts.debuginfo == DebugInfo::Full
- && !impl_self_ty.needs_subst()
+ && !impl_self_ty.definitely_needs_subst(cx.tcx)
{
Some(type_metadata(cx, impl_self_ty, rustc_span::DUMMY_SP))
} else {
diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs
index a48a694..e30c492 100644
--- a/compiler/rustc_codegen_llvm/src/intrinsic.rs
+++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs
@@ -1,4 +1,4 @@
-use crate::abi::{Abi, FnAbi, LlvmType, PassMode};
+use crate::abi::{Abi, FnAbi, FnAbiLlvmExt, LlvmType, PassMode};
use crate::builder::Builder;
use crate::context::CodegenCx;
use crate::llvm;
@@ -7,6 +7,7 @@
use crate::va_arg::emit_va_arg;
use crate::value::Value;
+use rustc_ast as ast;
use rustc_codegen_ssa::base::{compare_simd_types, wants_msvc_seh};
use rustc_codegen_ssa::common::span_invalid_monomorphization_error;
use rustc_codegen_ssa::common::{IntPredicate, TypeKind};
@@ -24,7 +25,7 @@
use std::cmp::Ordering;
use std::iter;
-fn get_simple_intrinsic(cx: &CodegenCx<'ll, '_>, name: Symbol) -> Option<&'ll Value> {
+fn get_simple_intrinsic(cx: &CodegenCx<'ll, '_>, name: Symbol) -> Option<(&'ll Type, &'ll Value)> {
let llvm_name = match name {
sym::sqrtf32 => "llvm.sqrt.f32",
sym::sqrtf64 => "llvm.sqrt.f64",
@@ -102,19 +103,20 @@
let simple = get_simple_intrinsic(self, name);
let llval = match name {
- _ if simple.is_some() => self.call(
- simple.unwrap(),
- &args.iter().map(|arg| arg.immediate()).collect::<Vec<_>>(),
- None,
- ),
+ _ if simple.is_some() => {
+ let (simple_ty, simple_fn) = simple.unwrap();
+ self.call(
+ simple_ty,
+ simple_fn,
+ &args.iter().map(|arg| arg.immediate()).collect::<Vec<_>>(),
+ None,
+ )
+ }
sym::likely => {
- let expect = self.get_intrinsic(&("llvm.expect.i1"));
- self.call(expect, &[args[0].immediate(), self.const_bool(true)], None)
+ self.call_intrinsic("llvm.expect.i1", &[args[0].immediate(), self.const_bool(true)])
}
- sym::unlikely => {
- let expect = self.get_intrinsic(&("llvm.expect.i1"));
- self.call(expect, &[args[0].immediate(), self.const_bool(false)], None)
- }
+ sym::unlikely => self
+ .call_intrinsic("llvm.expect.i1", &[args[0].immediate(), self.const_bool(false)]),
kw::Try => {
try_intrinsic(
self,
@@ -125,13 +127,9 @@
);
return;
}
- sym::breakpoint => {
- let llfn = self.get_intrinsic(&("llvm.debugtrap"));
- self.call(llfn, &[], None)
- }
+ sym::breakpoint => self.call_intrinsic("llvm.debugtrap", &[]),
sym::va_copy => {
- let intrinsic = self.cx().get_intrinsic(&("llvm.va_copy"));
- self.call(intrinsic, &[args[0].immediate(), args[1].immediate()], None)
+ self.call_intrinsic("llvm.va_copy", &[args[0].immediate(), args[1].immediate()])
}
sym::va_arg => {
match fn_abi.ret.layout.abi {
@@ -139,9 +137,9 @@
match scalar.value {
Primitive::Int(..) => {
if self.cx().size_of(ret_ty).bytes() < 4 {
- // `va_arg` should not be called on a integer type
+ // `va_arg` should not be called on an integer type
// less than 4 bytes in length. If it is, promote
- // the integer to a `i32` and truncate the result
+ // the integer to an `i32` and truncate the result
// back to the smaller type.
let promoted_result = emit_va_arg(self, args[0], tcx.types.i32);
self.trunc(promoted_result, llret_ty)
@@ -194,7 +192,6 @@
| sym::prefetch_write_data
| sym::prefetch_read_instruction
| sym::prefetch_write_instruction => {
- let expect = self.get_intrinsic(&("llvm.prefetch"));
let (rw, cache_type) = match name {
sym::prefetch_read_data => (0, 1),
sym::prefetch_write_data => (1, 1),
@@ -202,15 +199,14 @@
sym::prefetch_write_instruction => (1, 0),
_ => bug!(),
};
- self.call(
- expect,
+ self.call_intrinsic(
+ "llvm.prefetch",
&[
args[0].immediate(),
self.const_i32(rw),
args[1].immediate(),
self.const_i32(cache_type),
],
- None,
)
}
sym::ctlz
@@ -229,35 +225,33 @@
Some((width, signed)) => match name {
sym::ctlz | sym::cttz => {
let y = self.const_bool(false);
- let llfn = self.get_intrinsic(&format!("llvm.{}.i{}", name, width));
- self.call(llfn, &[args[0].immediate(), y], None)
+ self.call_intrinsic(
+ &format!("llvm.{}.i{}", name, width),
+ &[args[0].immediate(), y],
+ )
}
sym::ctlz_nonzero | sym::cttz_nonzero => {
let y = self.const_bool(true);
let llvm_name = &format!("llvm.{}.i{}", &name_str[..4], width);
- let llfn = self.get_intrinsic(llvm_name);
- self.call(llfn, &[args[0].immediate(), y], None)
+ self.call_intrinsic(llvm_name, &[args[0].immediate(), y])
}
- sym::ctpop => self.call(
- self.get_intrinsic(&format!("llvm.ctpop.i{}", width)),
+ sym::ctpop => self.call_intrinsic(
+ &format!("llvm.ctpop.i{}", width),
&[args[0].immediate()],
- None,
),
sym::bswap => {
if width == 8 {
args[0].immediate() // byte swap a u8/i8 is just a no-op
} else {
- self.call(
- self.get_intrinsic(&format!("llvm.bswap.i{}", width)),
+ self.call_intrinsic(
+ &format!("llvm.bswap.i{}", width),
&[args[0].immediate()],
- None,
)
}
}
- sym::bitreverse => self.call(
- self.get_intrinsic(&format!("llvm.bitreverse.i{}", width)),
+ sym::bitreverse => self.call_intrinsic(
+ &format!("llvm.bitreverse.i{}", width),
&[args[0].immediate()],
- None,
),
sym::rotate_left | sym::rotate_right => {
let is_left = name == sym::rotate_left;
@@ -266,8 +260,7 @@
// rotate = funnel shift with first two args the same
let llvm_name =
&format!("llvm.fsh{}.i{}", if is_left { 'l' } else { 'r' }, width);
- let llfn = self.get_intrinsic(llvm_name);
- self.call(llfn, &[val, val, raw_shift], None)
+ self.call_intrinsic(llvm_name, &[val, val, raw_shift])
}
sym::saturating_add | sym::saturating_sub => {
let is_add = name == sym::saturating_add;
@@ -279,8 +272,7 @@
if is_add { "add" } else { "sub" },
width
);
- let llfn = self.get_intrinsic(llvm_name);
- self.call(llfn, &[lhs, rhs], None)
+ self.call_intrinsic(llvm_name, &[lhs, rhs])
}
_ => bug!(),
},
@@ -331,12 +323,36 @@
let a_ptr = self.bitcast(a, i8p_ty);
let b_ptr = self.bitcast(b, i8p_ty);
let n = self.const_usize(layout.size.bytes());
- let llfn = self.get_intrinsic("memcmp");
- let cmp = self.call(llfn, &[a_ptr, b_ptr, n], None);
+ let cmp = self.call_intrinsic("memcmp", &[a_ptr, b_ptr, n]);
self.icmp(IntPredicate::IntEQ, cmp, self.const_i32(0))
}
}
+ sym::black_box => {
+ args[0].val.store(self, result);
+
+ // We need to "use" the argument in some way LLVM can't introspect, and on
+ // targets that support it we can typically leverage inline assembly to do
+ // this. LLVM's interpretation of inline assembly is that it's, well, a black
+ // box. This isn't the greatest implementation since it probably deoptimizes
+ // more than we want, but it's so far good enough.
+ crate::asm::inline_asm_call(
+ self,
+ "",
+ "r,~{memory}",
+ &[result.llval],
+ self.type_void(),
+ true,
+ false,
+ ast::LlvmAsmDialect::Att,
+ &[span],
+ )
+ .unwrap_or_else(|| bug!("failed to generate inline asm call for `black_box`"));
+
+ // We have copied the value to `result` already.
+ return;
+ }
+
_ if name_str.starts_with("simd_") => {
match generic_simd_intrinsic(self, name, callee_ty, args, ret_ty, llret_ty, span) {
Ok(llval) => llval,
@@ -361,18 +377,15 @@
}
fn abort(&mut self) {
- let fnname = self.get_intrinsic(&("llvm.trap"));
- self.call(fnname, &[], None);
+ self.call_intrinsic("llvm.trap", &[]);
}
fn assume(&mut self, val: Self::Value) {
- let assume_intrinsic = self.get_intrinsic("llvm.assume");
- self.call(assume_intrinsic, &[val], None);
+ self.call_intrinsic("llvm.assume", &[val]);
}
fn expect(&mut self, cond: Self::Value, expected: bool) -> Self::Value {
- let expect = self.get_intrinsic(&"llvm.expect.i1");
- self.call(expect, &[cond, self.const_bool(expected)], None)
+ self.call_intrinsic("llvm.expect.i1", &[cond, self.const_bool(expected)])
}
fn sideeffect(&mut self) {
@@ -380,19 +393,16 @@
// caller of this function is in `rustc_codegen_ssa`, which is agnostic to whether LLVM
// codegen backend being used, and so is unable to check the LLVM version.
if unsafe { llvm::LLVMRustVersionMajor() } < 12 {
- let fnname = self.get_intrinsic(&("llvm.sideeffect"));
- self.call(fnname, &[], None);
+ self.call_intrinsic("llvm.sideeffect", &[]);
}
}
fn va_start(&mut self, va_list: &'ll Value) -> &'ll Value {
- let intrinsic = self.cx().get_intrinsic("llvm.va_start");
- self.call(intrinsic, &[va_list], None)
+ self.call_intrinsic("llvm.va_start", &[va_list])
}
fn va_end(&mut self, va_list: &'ll Value) -> &'ll Value {
- let intrinsic = self.cx().get_intrinsic("llvm.va_end");
- self.call(intrinsic, &[va_list], None)
+ self.call_intrinsic("llvm.va_end", &[va_list])
}
}
@@ -404,7 +414,8 @@
dest: &'ll Value,
) {
if bx.sess().panic_strategy() == PanicStrategy::Abort {
- bx.call(try_func, &[data], None);
+ let try_func_ty = bx.type_func(&[bx.type_i8p()], bx.type_void());
+ bx.call(try_func_ty, try_func, &[data], None);
// Return 0 unconditionally from the intrinsic call;
// we can never unwind.
let ret_align = bx.tcx().data_layout.i32_align.abi;
@@ -432,7 +443,7 @@
catch_func: &'ll Value,
dest: &'ll Value,
) {
- let llfn = get_rust_try_fn(bx, &mut |mut bx| {
+ let (llty, llfn) = get_rust_try_fn(bx, &mut |mut bx| {
bx.set_personality_fn(bx.eh_personality());
let mut normal = bx.build_sibling_block("normal");
@@ -502,7 +513,8 @@
// More information can be found in libstd's seh.rs implementation.
let ptr_align = bx.tcx().data_layout.pointer_align.abi;
let slot = bx.alloca(bx.type_i8p(), ptr_align);
- bx.invoke(try_func, &[data], normal.llbb(), catchswitch.llbb(), None);
+ let try_func_ty = bx.type_func(&[bx.type_i8p()], bx.type_void());
+ bx.invoke(try_func_ty, try_func, &[data], normal.llbb(), catchswitch.llbb(), None);
normal.ret(bx.const_i32(0));
@@ -544,14 +556,15 @@
let flags = bx.const_i32(8);
let funclet = catchpad_rust.catch_pad(cs, &[tydesc, flags, slot]);
let ptr = catchpad_rust.load(bx.type_i8p(), slot, ptr_align);
- catchpad_rust.call(catch_func, &[data, ptr], Some(&funclet));
+ let catch_ty = bx.type_func(&[bx.type_i8p(), bx.type_i8p()], bx.type_void());
+ catchpad_rust.call(catch_ty, catch_func, &[data, ptr], Some(&funclet));
catchpad_rust.catch_ret(&funclet, caught.llbb());
// The flag value of 64 indicates a "catch-all".
let flags = bx.const_i32(64);
let null = bx.const_null(bx.type_i8p());
let funclet = catchpad_foreign.catch_pad(cs, &[null, flags, null]);
- catchpad_foreign.call(catch_func, &[data, null], Some(&funclet));
+ catchpad_foreign.call(catch_ty, catch_func, &[data, null], Some(&funclet));
catchpad_foreign.catch_ret(&funclet, caught.llbb());
caught.ret(bx.const_i32(1));
@@ -559,7 +572,7 @@
// Note that no invoke is used here because by definition this function
// can't panic (that's what it's catching).
- let ret = bx.call(llfn, &[try_func, data, catch_func], None);
+ let ret = bx.call(llty, llfn, &[try_func, data, catch_func], None);
let i32_align = bx.tcx().data_layout.i32_align.abi;
bx.store(ret, dest, i32_align);
}
@@ -582,7 +595,7 @@
catch_func: &'ll Value,
dest: &'ll Value,
) {
- let llfn = get_rust_try_fn(bx, &mut |mut bx| {
+ let (llty, llfn) = get_rust_try_fn(bx, &mut |mut bx| {
// Codegens the shims described above:
//
// bx:
@@ -601,7 +614,8 @@
let try_func = llvm::get_param(bx.llfn(), 0);
let data = llvm::get_param(bx.llfn(), 1);
let catch_func = llvm::get_param(bx.llfn(), 2);
- bx.invoke(try_func, &[data], then.llbb(), catch.llbb(), None);
+ let try_func_ty = bx.type_func(&[bx.type_i8p()], bx.type_void());
+ bx.invoke(try_func_ty, try_func, &[data], then.llbb(), catch.llbb(), None);
then.ret(bx.const_i32(0));
// Type indicator for the exception being thrown.
@@ -615,13 +629,14 @@
let tydesc = bx.const_null(bx.type_i8p());
catch.add_clause(vals, tydesc);
let ptr = catch.extract_value(vals, 0);
- catch.call(catch_func, &[data, ptr], None);
+ let catch_ty = bx.type_func(&[bx.type_i8p(), bx.type_i8p()], bx.type_void());
+ catch.call(catch_ty, catch_func, &[data, ptr], None);
catch.ret(bx.const_i32(1));
});
// Note that no invoke is used here because by definition this function
// can't panic (that's what it's catching).
- let ret = bx.call(llfn, &[try_func, data, catch_func], None);
+ let ret = bx.call(llty, llfn, &[try_func, data, catch_func], None);
let i32_align = bx.tcx().data_layout.i32_align.abi;
bx.store(ret, dest, i32_align);
}
@@ -636,7 +651,7 @@
catch_func: &'ll Value,
dest: &'ll Value,
) {
- let llfn = get_rust_try_fn(bx, &mut |mut bx| {
+ let (llty, llfn) = get_rust_try_fn(bx, &mut |mut bx| {
// Codegens the shims described above:
//
// bx:
@@ -660,7 +675,8 @@
let try_func = llvm::get_param(bx.llfn(), 0);
let data = llvm::get_param(bx.llfn(), 1);
let catch_func = llvm::get_param(bx.llfn(), 2);
- bx.invoke(try_func, &[data], then.llbb(), catch.llbb(), None);
+ let try_func_ty = bx.type_func(&[bx.type_i8p()], bx.type_void());
+ bx.invoke(try_func_ty, try_func, &[data], then.llbb(), catch.llbb(), None);
then.ret(bx.const_i32(0));
// Type indicator for the exception being thrown.
@@ -677,8 +693,7 @@
let selector = catch.extract_value(vals, 1);
// Check if the typeid we got is the one for a Rust panic.
- let llvm_eh_typeid_for = bx.get_intrinsic("llvm.eh.typeid.for");
- let rust_typeid = catch.call(llvm_eh_typeid_for, &[tydesc], None);
+ let rust_typeid = catch.call_intrinsic("llvm.eh.typeid.for", &[tydesc]);
let is_rust_panic = catch.icmp(IntPredicate::IntEQ, selector, rust_typeid);
let is_rust_panic = catch.zext(is_rust_panic, bx.type_bool());
@@ -686,21 +701,30 @@
// create an alloca and pass a pointer to that.
let ptr_align = bx.tcx().data_layout.pointer_align.abi;
let i8_align = bx.tcx().data_layout.i8_align.abi;
- let catch_data =
- catch.alloca(bx.type_struct(&[bx.type_i8p(), bx.type_bool()], false), ptr_align);
- let catch_data_0 = catch.inbounds_gep(catch_data, &[bx.const_usize(0), bx.const_usize(0)]);
+ let catch_data_type = bx.type_struct(&[bx.type_i8p(), bx.type_bool()], false);
+ let catch_data = catch.alloca(catch_data_type, ptr_align);
+ let catch_data_0 = catch.inbounds_gep(
+ catch_data_type,
+ catch_data,
+ &[bx.const_usize(0), bx.const_usize(0)],
+ );
catch.store(ptr, catch_data_0, ptr_align);
- let catch_data_1 = catch.inbounds_gep(catch_data, &[bx.const_usize(0), bx.const_usize(1)]);
+ let catch_data_1 = catch.inbounds_gep(
+ catch_data_type,
+ catch_data,
+ &[bx.const_usize(0), bx.const_usize(1)],
+ );
catch.store(is_rust_panic, catch_data_1, i8_align);
let catch_data = catch.bitcast(catch_data, bx.type_i8p());
- catch.call(catch_func, &[data, catch_data], None);
+ let catch_ty = bx.type_func(&[bx.type_i8p(), bx.type_i8p()], bx.type_void());
+ catch.call(catch_ty, catch_func, &[data, catch_data], None);
catch.ret(bx.const_i32(1));
});
// Note that no invoke is used here because by definition this function
// can't panic (that's what it's catching).
- let ret = bx.call(llfn, &[try_func, data, catch_func], None);
+ let ret = bx.call(llty, llfn, &[try_func, data, catch_func], None);
let i32_align = bx.tcx().data_layout.i32_align.abi;
bx.store(ret, dest, i32_align);
}
@@ -712,8 +736,9 @@
name: &str,
rust_fn_sig: ty::PolyFnSig<'tcx>,
codegen: &mut dyn FnMut(Builder<'_, 'll, 'tcx>),
-) -> &'ll Value {
+) -> (&'ll Type, &'ll Value) {
let fn_abi = FnAbi::of_fn_ptr(cx, rust_fn_sig, &[]);
+ let llty = fn_abi.llvm_type(cx);
let llfn = cx.declare_fn(name, &fn_abi);
cx.set_frame_pointer_type(llfn);
cx.apply_target_cpu_attr(llfn);
@@ -722,7 +747,7 @@
let llbb = Builder::append_block(cx, llfn, "entry-block");
let bx = Builder::build(cx, llbb);
codegen(bx);
- llfn
+ (llty, llfn)
}
// Helper function used to get a handle to the `__rust_try` function used to
@@ -732,7 +757,7 @@
fn get_rust_try_fn<'ll, 'tcx>(
cx: &CodegenCx<'ll, 'tcx>,
codegen: &mut dyn FnMut(Builder<'_, 'll, 'tcx>),
-) -> &'ll Value {
+) -> (&'ll Type, &'ll Value) {
if let Some(llfn) = cx.rust_try_fn.get() {
return llfn;
}
@@ -1006,7 +1031,7 @@
// vector mask and returns an unsigned integer containing the most
// significant bit (MSB) of each lane.
- // If the vector has less than 8 lanes, an u8 is returned with zeroed
+ // If the vector has less than 8 lanes, a u8 is returned with zeroed
// trailing bits.
let expected_int_bits = in_len.max(8);
match ret_ty.kind() {
@@ -1115,7 +1140,8 @@
};
let llvm_name = &format!("llvm.{0}.v{1}{2}", intr_name, in_len, elem_ty_str);
let f = bx.declare_cfn(&llvm_name, llvm::UnnamedAddr::No, fn_ty);
- let c = bx.call(f, &args.iter().map(|arg| arg.immediate()).collect::<Vec<_>>(), None);
+ let c =
+ bx.call(fn_ty, f, &args.iter().map(|arg| arg.immediate()).collect::<Vec<_>>(), None);
Ok(c)
}
@@ -1292,15 +1318,13 @@
let llvm_intrinsic =
format!("llvm.masked.gather.{}.{}", llvm_elem_vec_str, llvm_pointer_vec_str);
- let f = bx.declare_cfn(
- &llvm_intrinsic,
- llvm::UnnamedAddr::No,
- bx.type_func(
- &[llvm_pointer_vec_ty, alignment_ty, mask_ty, llvm_elem_vec_ty],
- llvm_elem_vec_ty,
- ),
+ let fn_ty = bx.type_func(
+ &[llvm_pointer_vec_ty, alignment_ty, mask_ty, llvm_elem_vec_ty],
+ llvm_elem_vec_ty,
);
- let v = bx.call(f, &[args[1].immediate(), alignment, mask, args[0].immediate()], None);
+ let f = bx.declare_cfn(&llvm_intrinsic, llvm::UnnamedAddr::No, fn_ty);
+ let v =
+ bx.call(fn_ty, f, &[args[1].immediate(), alignment, mask, args[0].immediate()], None);
return Ok(v);
}
@@ -1422,12 +1446,11 @@
let llvm_intrinsic =
format!("llvm.masked.scatter.{}.{}", llvm_elem_vec_str, llvm_pointer_vec_str);
- let f = bx.declare_cfn(
- &llvm_intrinsic,
- llvm::UnnamedAddr::No,
- bx.type_func(&[llvm_elem_vec_ty, llvm_pointer_vec_ty, alignment_ty, mask_ty], ret_t),
- );
- let v = bx.call(f, &[args[0].immediate(), args[1].immediate(), alignment, mask], None);
+ let fn_ty =
+ bx.type_func(&[llvm_elem_vec_ty, llvm_pointer_vec_ty, alignment_ty, mask_ty], ret_t);
+ let f = bx.declare_cfn(&llvm_intrinsic, llvm::UnnamedAddr::No, fn_ty);
+ let v =
+ bx.call(fn_ty, f, &[args[0].immediate(), args[1].immediate(), alignment, mask], None);
return Ok(v);
}
@@ -1749,12 +1772,9 @@
);
let vec_ty = bx.cx.type_vector(elem_ty, in_len as u64);
- let f = bx.declare_cfn(
- &llvm_intrinsic,
- llvm::UnnamedAddr::No,
- bx.type_func(&[vec_ty, vec_ty], vec_ty),
- );
- let v = bx.call(f, &[lhs, rhs], None);
+ let fn_ty = bx.type_func(&[vec_ty, vec_ty], vec_ty);
+ let f = bx.declare_cfn(&llvm_intrinsic, llvm::UnnamedAddr::No, fn_ty);
+ let v = bx.call(fn_ty, f, &[lhs, rhs], None);
return Ok(v);
}
diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs
index aa4db16..1e6e525 100644
--- a/compiler/rustc_codegen_llvm/src/lib.rs
+++ b/compiler/rustc_codegen_llvm/src/lib.rs
@@ -352,8 +352,8 @@
impl Drop for ModuleLlvm {
fn drop(&mut self) {
unsafe {
- llvm::LLVMContextDispose(&mut *(self.llcx as *mut _));
llvm::LLVMRustDisposeTargetMachine(&mut *(self.tm as *mut _));
+ llvm::LLVMContextDispose(&mut *(self.llcx as *mut _));
}
}
}
diff --git a/compiler/rustc_codegen_llvm/src/llvm/diagnostic.rs b/compiler/rustc_codegen_llvm/src/llvm/diagnostic.rs
index ccd3e42..36aa022 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/diagnostic.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/diagnostic.rs
@@ -6,7 +6,8 @@
use crate::value::Value;
use libc::c_uint;
-use super::{DiagnosticInfo, Twine};
+use super::{DiagnosticInfo, SMDiagnostic};
+use rustc_span::InnerSpan;
#[derive(Copy, Clone)]
pub enum OptimizationDiagnosticKind {
@@ -86,36 +87,91 @@
}
}
-#[derive(Copy, Clone)]
-pub struct InlineAsmDiagnostic<'ll> {
+pub struct SrcMgrDiagnostic {
pub level: super::DiagnosticLevel,
- pub cookie: c_uint,
- pub message: &'ll Twine,
- pub instruction: Option<&'ll Value>,
+ pub message: String,
+ pub source: Option<(String, Vec<InnerSpan>)>,
}
-impl InlineAsmDiagnostic<'ll> {
- unsafe fn unpack(di: &'ll DiagnosticInfo) -> Self {
+impl SrcMgrDiagnostic {
+ pub unsafe fn unpack(diag: &SMDiagnostic) -> SrcMgrDiagnostic {
+ // Recover the post-substitution assembly code from LLVM for better
+ // diagnostics.
+ let mut have_source = false;
+ let mut buffer = String::new();
+ let mut level = super::DiagnosticLevel::Error;
+ let mut loc = 0;
+ let mut ranges = [0; 8];
+ let mut num_ranges = ranges.len() / 2;
+ let message = super::build_string(|message| {
+ buffer = super::build_string(|buffer| {
+ have_source = super::LLVMRustUnpackSMDiagnostic(
+ diag,
+ message,
+ buffer,
+ &mut level,
+ &mut loc,
+ ranges.as_mut_ptr(),
+ &mut num_ranges,
+ );
+ })
+ .expect("non-UTF8 inline asm");
+ })
+ .expect("non-UTF8 SMDiagnostic");
+
+ SrcMgrDiagnostic {
+ message,
+ level,
+ source: have_source.then(|| {
+ let mut spans = vec![InnerSpan::new(loc as usize, loc as usize)];
+ for i in 0..num_ranges {
+ spans.push(InnerSpan::new(ranges[i * 2] as usize, ranges[i * 2 + 1] as usize));
+ }
+ (buffer, spans)
+ }),
+ }
+ }
+}
+
+#[derive(Clone)]
+pub struct InlineAsmDiagnostic {
+ pub level: super::DiagnosticLevel,
+ pub cookie: c_uint,
+ pub message: String,
+ pub source: Option<(String, Vec<InnerSpan>)>,
+}
+
+impl InlineAsmDiagnostic {
+ unsafe fn unpackInlineAsm(di: &'ll DiagnosticInfo) -> Self {
let mut cookie = 0;
let mut message = None;
- let mut instruction = None;
let mut level = super::DiagnosticLevel::Error;
- super::LLVMRustUnpackInlineAsmDiagnostic(
- di,
- &mut level,
- &mut cookie,
- &mut message,
- &mut instruction,
- );
+ super::LLVMRustUnpackInlineAsmDiagnostic(di, &mut level, &mut cookie, &mut message);
- InlineAsmDiagnostic { level, cookie, message: message.unwrap(), instruction }
+ InlineAsmDiagnostic {
+ level,
+ cookie,
+ message: super::twine_to_string(message.unwrap()),
+ source: None,
+ }
+ }
+
+ unsafe fn unpackSrcMgr(di: &'ll DiagnosticInfo) -> Self {
+ let mut cookie = 0;
+ let smdiag = SrcMgrDiagnostic::unpack(super::LLVMRustGetSMDiagnostic(di, &mut cookie));
+ InlineAsmDiagnostic {
+ level: smdiag.level,
+ cookie,
+ message: smdiag.message,
+ source: smdiag.source,
+ }
}
}
pub enum Diagnostic<'ll> {
Optimization(OptimizationDiagnostic<'ll>),
- InlineAsm(InlineAsmDiagnostic<'ll>),
+ InlineAsm(InlineAsmDiagnostic),
PGO(&'ll DiagnosticInfo),
Linker(&'ll DiagnosticInfo),
Unsupported(&'ll DiagnosticInfo),
@@ -130,7 +186,7 @@
let kind = super::LLVMRustGetDiagInfoKind(di);
match kind {
- Dk::InlineAsm => InlineAsm(InlineAsmDiagnostic::unpack(di)),
+ Dk::InlineAsm => InlineAsm(InlineAsmDiagnostic::unpackInlineAsm(di)),
Dk::OptimizationRemark => {
Optimization(OptimizationDiagnostic::unpack(OptimizationRemark, di))
@@ -162,6 +218,8 @@
Dk::Linker => Linker(di),
Dk::Unsupported => Unsupported(di),
+ Dk::SrcMgr => InlineAsm(InlineAsmDiagnostic::unpackSrcMgr(di)),
+
_ => UnknownDiagnostic(di),
}
}
diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
index 68d566c..3f2ed02 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
@@ -490,6 +490,7 @@
PGOProfile,
Linker,
Unsupported,
+ SrcMgr,
}
/// LLVMRustDiagnosticLevel
@@ -1011,7 +1012,8 @@
pub fn LLVMConstVector(ScalarConstantVals: *const &Value, Size: c_uint) -> &Value;
// Constant expressions
- pub fn LLVMConstInBoundsGEP(
+ pub fn LLVMRustConstInBoundsGEP2(
+ ty: &'a Type,
ConstantVal: &'a Value,
ConstantIndices: *const &'a Value,
NumIndices: c_uint,
@@ -1154,6 +1156,7 @@
) -> &'a Value;
pub fn LLVMRustBuildInvoke(
B: &Builder<'a>,
+ Ty: &'a Type,
Fn: &'a Value,
Args: *const &'a Value,
NumArgs: c_uint,
@@ -1394,22 +1397,25 @@
pub fn LLVMBuildStore(B: &Builder<'a>, Val: &'a Value, Ptr: &'a Value) -> &'a Value;
- pub fn LLVMBuildGEP(
+ pub fn LLVMBuildGEP2(
B: &Builder<'a>,
+ Ty: &'a Type,
Pointer: &'a Value,
Indices: *const &'a Value,
NumIndices: c_uint,
Name: *const c_char,
) -> &'a Value;
- pub fn LLVMBuildInBoundsGEP(
+ pub fn LLVMBuildInBoundsGEP2(
B: &Builder<'a>,
+ Ty: &'a Type,
Pointer: &'a Value,
Indices: *const &'a Value,
NumIndices: c_uint,
Name: *const c_char,
) -> &'a Value;
- pub fn LLVMBuildStructGEP(
+ pub fn LLVMBuildStructGEP2(
B: &Builder<'a>,
+ Ty: &'a Type,
Pointer: &'a Value,
Idx: c_uint,
Name: *const c_char,
@@ -1522,6 +1528,7 @@
pub fn LLVMRustGetInstrProfIncrementIntrinsic(M: &Module) -> &'a Value;
pub fn LLVMRustBuildCall(
B: &Builder<'a>,
+ Ty: &'a Type,
Fn: &'a Value,
Args: *const &'a Value,
NumArgs: c_uint,
@@ -2258,13 +2265,17 @@
level_out: &mut DiagnosticLevel,
cookie_out: &mut c_uint,
message_out: &mut Option<&'a Twine>,
- instruction_out: &mut Option<&'a Value>,
);
#[allow(improper_ctypes)]
pub fn LLVMRustWriteDiagnosticInfoToString(DI: &DiagnosticInfo, s: &RustString);
pub fn LLVMRustGetDiagInfoKind(DI: &DiagnosticInfo) -> DiagnosticKind;
+ pub fn LLVMRustGetSMDiagnostic(
+ DI: &'a DiagnosticInfo,
+ cookie_out: &mut c_uint,
+ ) -> &'a SMDiagnostic;
+
pub fn LLVMRustSetInlineAsmDiagnosticHandler(
C: &Context,
H: InlineAsmDiagHandler,
diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs
index cb9c626..3b64ec1 100644
--- a/compiler/rustc_codegen_llvm/src/llvm_util.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs
@@ -89,13 +89,14 @@
add("-generate-arange-section", false);
}
- // FIXME(nagisa): disable the machine outliner by default in LLVM versions 11, where it was
- // introduced and up.
+ // Disable the machine outliner by default in LLVM versions 11 and LLVM
+ // version 12, where it leads to miscompilation.
//
- // This should remain in place until https://reviews.llvm.org/D103167 is fixed. If LLVM
- // has been upgraded since, consider adjusting the version check below to contain an upper
- // bound.
- if llvm_util::get_version() >= (11, 0, 0) {
+ // Ref:
+ // - https://github.com/rust-lang/rust/issues/85351
+ // - https://reviews.llvm.org/D103167
+ let llvm_version = llvm_util::get_version();
+ if llvm_version >= (11, 0, 0) && llvm_version < (13, 0, 0) {
add("-enable-machine-outliner=never", false);
}
@@ -365,7 +366,7 @@
features_string
};
- features.extend(features_string.split(",").map(String::from));
+ features.extend(features_string.split(',').map(String::from));
}
Some(_) | None => {}
};
@@ -374,7 +375,7 @@
if s.is_empty() {
return None;
}
- let feature = if s.starts_with("+") || s.starts_with("-") {
+ let feature = if s.starts_with('+') || s.starts_with('-') {
&s[1..]
} else {
return Some(s.to_string());
diff --git a/compiler/rustc_codegen_llvm/src/mono_item.rs b/compiler/rustc_codegen_llvm/src/mono_item.rs
index 9345644..8a8ece6 100644
--- a/compiler/rustc_codegen_llvm/src/mono_item.rs
+++ b/compiler/rustc_codegen_llvm/src/mono_item.rs
@@ -135,6 +135,11 @@
return false;
}
+ // Match clang by only supporting COFF and ELF for now.
+ if self.tcx.sess.target.is_like_osx {
+ return false;
+ }
+
// Static relocation model should force copy relocations everywhere.
if self.tcx.sess.relocation_model() == RelocModel::Static {
return true;
diff --git a/compiler/rustc_codegen_llvm/src/type_.rs b/compiler/rustc_codegen_llvm/src/type_.rs
index 8fd0caae..c7f4287 100644
--- a/compiler/rustc_codegen_llvm/src/type_.rs
+++ b/compiler/rustc_codegen_llvm/src/type_.rs
@@ -203,7 +203,11 @@
}
fn element_type(&self, ty: &'ll Type) -> &'ll Type {
- unsafe { llvm::LLVMGetElementType(ty) }
+ match self.type_kind(ty) {
+ TypeKind::Array | TypeKind::Vector => unsafe { llvm::LLVMGetElementType(ty) },
+ TypeKind::Pointer => bug!("element_type is not supported for opaque pointers"),
+ other => bug!("element_type called on unsupported type {:?}", other),
+ }
}
fn vector_length(&self, ty: &'ll Type) -> usize {
@@ -262,7 +266,7 @@
layout.is_llvm_scalar_pair()
}
fn backend_field_index(&self, layout: TyAndLayout<'tcx>, index: usize) -> u64 {
- layout.llvm_field_index(index)
+ layout.llvm_field_index(self, index)
}
fn scalar_pair_element_backend_type(
&self,
@@ -275,6 +279,9 @@
fn cast_backend_type(&self, ty: &CastTarget) -> &'ll Type {
ty.llvm_type(self)
}
+ fn fn_decl_backend_type(&self, fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> &'ll Type {
+ fn_abi.llvm_type(self)
+ }
fn fn_ptr_backend_type(&self, fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> &'ll Type {
fn_abi.ptr_to_llvm_type(self)
}
diff --git a/compiler/rustc_codegen_llvm/src/type_of.rs b/compiler/rustc_codegen_llvm/src/type_of.rs
index 0876907..9818905 100644
--- a/compiler/rustc_codegen_llvm/src/type_of.rs
+++ b/compiler/rustc_codegen_llvm/src/type_of.rs
@@ -1,5 +1,6 @@
use crate::abi::FnAbi;
use crate::common::*;
+use crate::context::TypeLowering;
use crate::type_::Type;
use rustc_codegen_ssa::traits::*;
use rustc_middle::bug;
@@ -8,7 +9,8 @@
use rustc_middle::ty::{self, Ty, TypeFoldable};
use rustc_target::abi::{Abi, AddressSpace, Align, FieldsShape};
use rustc_target::abi::{Int, Pointer, F32, F64};
-use rustc_target::abi::{LayoutOf, PointeeInfo, Scalar, Size, TyAndLayoutMethods, Variants};
+use rustc_target::abi::{LayoutOf, PointeeInfo, Scalar, Size, TyAbiInterface, Variants};
+use smallvec::{smallvec, SmallVec};
use tracing::debug;
use std::fmt::Write;
@@ -17,6 +19,7 @@
cx: &CodegenCx<'a, 'tcx>,
layout: TyAndLayout<'tcx>,
defer: &mut Option<(&'a Type, TyAndLayout<'tcx>)>,
+ field_remapping: &mut Option<SmallVec<[u32; 4]>>,
) -> &'a Type {
match layout.abi {
Abi::Scalar(_) => bug!("handled elsewhere"),
@@ -75,7 +78,8 @@
FieldsShape::Array { count, .. } => cx.type_array(layout.field(cx, 0).llvm_type(cx), count),
FieldsShape::Arbitrary { .. } => match name {
None => {
- let (llfields, packed) = struct_llfields(cx, layout);
+ let (llfields, packed, new_field_remapping) = struct_llfields(cx, layout);
+ *field_remapping = new_field_remapping;
cx.type_struct(&llfields, packed)
}
Some(ref name) => {
@@ -90,7 +94,7 @@
fn struct_llfields<'a, 'tcx>(
cx: &CodegenCx<'a, 'tcx>,
layout: TyAndLayout<'tcx>,
-) -> (Vec<&'a Type>, bool) {
+) -> (Vec<&'a Type>, bool, Option<SmallVec<[u32; 4]>>) {
debug!("struct_llfields: {:#?}", layout);
let field_count = layout.fields.count();
@@ -98,6 +102,7 @@
let mut offset = Size::ZERO;
let mut prev_effective_align = layout.align.abi;
let mut result: Vec<_> = Vec::with_capacity(1 + field_count * 2);
+ let mut field_remapping = smallvec![0; field_count];
for i in layout.fields.index_by_increasing_offset() {
let target_offset = layout.fields.offset(i as usize);
let field = layout.field(cx, i);
@@ -116,33 +121,37 @@
);
assert!(target_offset >= offset);
let padding = target_offset - offset;
- let padding_align = prev_effective_align.min(effective_field_align);
- assert_eq!(offset.align_to(padding_align) + padding, target_offset);
- result.push(cx.type_padding_filler(padding, padding_align));
- debug!(" padding before: {:?}", padding);
-
+ if padding != Size::ZERO {
+ let padding_align = prev_effective_align.min(effective_field_align);
+ assert_eq!(offset.align_to(padding_align) + padding, target_offset);
+ result.push(cx.type_padding_filler(padding, padding_align));
+ debug!(" padding before: {:?}", padding);
+ }
+ field_remapping[i] = result.len() as u32;
result.push(field.llvm_type(cx));
offset = target_offset + field.size;
prev_effective_align = effective_field_align;
}
+ let padding_used = result.len() > field_count;
if !layout.is_unsized() && field_count > 0 {
if offset > layout.size {
bug!("layout: {:#?} stride: {:?} offset: {:?}", layout, layout.size, offset);
}
let padding = layout.size - offset;
- let padding_align = prev_effective_align;
- assert_eq!(offset.align_to(padding_align) + padding, layout.size);
- debug!(
- "struct_llfields: pad_bytes: {:?} offset: {:?} stride: {:?}",
- padding, offset, layout.size
- );
- result.push(cx.type_padding_filler(padding, padding_align));
- assert_eq!(result.len(), 1 + field_count * 2);
+ if padding != Size::ZERO {
+ let padding_align = prev_effective_align;
+ assert_eq!(offset.align_to(padding_align) + padding, layout.size);
+ debug!(
+ "struct_llfields: pad_bytes: {:?} offset: {:?} stride: {:?}",
+ padding, offset, layout.size
+ );
+ result.push(cx.type_padding_filler(padding, padding_align));
+ }
} else {
debug!("struct_llfields: offset: {:?} stride: {:?}", offset, layout.size);
}
-
- (result, packed)
+ let field_remapping = if padding_used { Some(field_remapping) } else { None };
+ (result, packed, field_remapping)
}
impl<'a, 'tcx> CodegenCx<'a, 'tcx> {
@@ -177,7 +186,7 @@
index: usize,
immediate: bool,
) -> &'a Type;
- fn llvm_field_index(&self, index: usize) -> u64;
+ fn llvm_field_index<'a>(&self, cx: &CodegenCx<'a, 'tcx>, index: usize) -> u64;
fn pointee_info_at<'a>(&self, cx: &CodegenCx<'a, 'tcx>, offset: Size) -> Option<PointeeInfo>;
}
@@ -234,8 +243,8 @@
Variants::Single { index } => Some(index),
_ => None,
};
- if let Some(&llty) = cx.lltypes.borrow().get(&(self.ty, variant_index)) {
- return llty;
+ if let Some(ref llty) = cx.type_lowering.borrow().get(&(self.ty, variant_index)) {
+ return llty.lltype;
}
debug!("llvm_type({:#?})", self);
@@ -247,6 +256,7 @@
let normal_ty = cx.tcx.erase_regions(self.ty);
let mut defer = None;
+ let mut field_remapping = None;
let llty = if self.ty != normal_ty {
let mut layout = cx.layout_of(normal_ty);
if let Some(v) = variant_index {
@@ -254,17 +264,24 @@
}
layout.llvm_type(cx)
} else {
- uncached_llvm_type(cx, *self, &mut defer)
+ uncached_llvm_type(cx, *self, &mut defer, &mut field_remapping)
};
debug!("--> mapped {:#?} to llty={:?}", self, llty);
- cx.lltypes.borrow_mut().insert((self.ty, variant_index), llty);
+ cx.type_lowering.borrow_mut().insert(
+ (self.ty, variant_index),
+ TypeLowering { lltype: llty, field_remapping: field_remapping },
+ );
if let Some((llty, layout)) = defer {
- let (llfields, packed) = struct_llfields(cx, layout);
- cx.set_struct_body(llty, &llfields, packed)
+ let (llfields, packed, new_field_remapping) = struct_llfields(cx, layout);
+ cx.set_struct_body(llty, &llfields, packed);
+ cx.type_lowering
+ .borrow_mut()
+ .get_mut(&(self.ty, variant_index))
+ .unwrap()
+ .field_remapping = new_field_remapping;
}
-
llty
}
@@ -340,7 +357,7 @@
self.scalar_llvm_type_at(cx, scalar, offset)
}
- fn llvm_field_index(&self, index: usize) -> u64 {
+ fn llvm_field_index<'a>(&self, cx: &CodegenCx<'a, 'tcx>, index: usize) -> u64 {
match self.abi {
Abi::Scalar(_) | Abi::ScalarPair(..) => {
bug!("TyAndLayout::llvm_field_index({:?}): not applicable", self)
@@ -354,16 +371,37 @@
FieldsShape::Array { .. } => index as u64,
- FieldsShape::Arbitrary { .. } => 1 + (self.fields.memory_index(index) as u64) * 2,
+ FieldsShape::Arbitrary { .. } => {
+ let variant_index = match self.variants {
+ Variants::Single { index } => Some(index),
+ _ => None,
+ };
+
+ // Look up llvm field if indexes do not match memory order due to padding. If
+ // `field_remapping` is `None` no padding was used and the llvm field index
+ // matches the memory index.
+ match cx.type_lowering.borrow().get(&(self.ty, variant_index)) {
+ Some(TypeLowering { field_remapping: Some(ref remap), .. }) => {
+ remap[index] as u64
+ }
+ Some(_) => self.fields.memory_index(index) as u64,
+ None => {
+ bug!("TyAndLayout::llvm_field_index({:?}): type info not found", self)
+ }
+ }
+ }
}
}
+ // FIXME(eddyb) this having the same name as `TyAndLayout::pointee_info_at`
+ // (the inherent method, which is lacking this caching logic) can result in
+ // the uncached version being called - not wrong, but potentially inefficient.
fn pointee_info_at<'a>(&self, cx: &CodegenCx<'a, 'tcx>, offset: Size) -> Option<PointeeInfo> {
if let Some(&pointee) = cx.pointee_infos.borrow().get(&(self.ty, offset)) {
return pointee;
}
- let result = Ty::pointee_info_at(*self, cx, offset);
+ let result = Ty::ty_and_layout_pointee_info_at(*self, cx, offset);
cx.pointee_infos.borrow_mut().insert((self.ty, offset), result);
result
diff --git a/compiler/rustc_codegen_llvm/src/va_arg.rs b/compiler/rustc_codegen_llvm/src/va_arg.rs
index 9df1bd7..2208ec3 100644
--- a/compiler/rustc_codegen_llvm/src/va_arg.rs
+++ b/compiler/rustc_codegen_llvm/src/va_arg.rs
@@ -50,12 +50,12 @@
let aligned_size = size.align_to(slot_size).bytes() as i32;
let full_direct_size = bx.cx().const_i32(aligned_size);
- let next = bx.inbounds_gep(addr, &[full_direct_size]);
+ let next = bx.inbounds_gep(bx.type_i8(), 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 == Endian::Big {
let adjusted_size = bx.cx().const_i32((slot_size.bytes() - size.bytes()) as i32);
- let adjusted = bx.inbounds_gep(addr, &[adjusted_size]);
+ let adjusted = bx.inbounds_gep(bx.type_i8(), addr, &[adjusted_size]);
(bx.bitcast(adjusted, bx.cx().type_ptr_to(llty)), addr_align)
} else {
(bx.bitcast(addr, bx.cx().type_ptr_to(llty)), addr_align)
@@ -98,6 +98,8 @@
// Implementation of the AAPCS64 calling convention for va_args see
// https://github.com/ARM-software/abi-aa/blob/master/aapcs64/aapcs64.rst
let va_list_addr = list.immediate();
+ let va_list_layout = list.deref(bx.cx).layout;
+ let va_list_ty = va_list_layout.llvm_type(bx);
let layout = bx.cx.layout_of(target_ty);
let mut maybe_reg = bx.build_sibling_block("va_arg.maybe_reg");
@@ -109,13 +111,15 @@
let gr_type = target_ty.is_any_ptr() || target_ty.is_integral();
let (reg_off, reg_top_index, slot_size) = if gr_type {
- let gr_offs = bx.struct_gep(va_list_addr, 7);
+ let gr_offs =
+ bx.struct_gep(va_list_ty, va_list_addr, va_list_layout.llvm_field_index(bx.cx, 3));
let nreg = (layout.size.bytes() + 7) / 8;
- (gr_offs, 3, nreg * 8)
+ (gr_offs, va_list_layout.llvm_field_index(bx.cx, 1), nreg * 8)
} else {
- let vr_off = bx.struct_gep(va_list_addr, 9);
+ let vr_off =
+ bx.struct_gep(va_list_ty, va_list_addr, va_list_layout.llvm_field_index(bx.cx, 4));
let nreg = (layout.size.bytes() + 15) / 16;
- (vr_off, 5, nreg * 16)
+ (vr_off, va_list_layout.llvm_field_index(bx.cx, 2), nreg * 16)
};
// if the offset >= 0 then the value will be on the stack
@@ -141,15 +145,15 @@
maybe_reg.cond_br(use_stack, &on_stack.llbb(), &in_reg.llbb());
let top_type = bx.type_i8p();
- let top = in_reg.struct_gep(va_list_addr, reg_top_index);
+ let top = in_reg.struct_gep(va_list_ty, va_list_addr, reg_top_index);
let top = in_reg.load(top_type, top, bx.tcx().data_layout.pointer_align.abi);
// reg_value = *(@top + reg_off_v);
- let mut reg_addr = in_reg.gep(top, &[reg_off_v]);
+ let mut reg_addr = in_reg.gep(bx.type_i8(), 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]);
+ reg_addr = in_reg.gep(bx.type_i8(), reg_addr, &[offset]);
}
let reg_type = layout.llvm_type(bx);
let reg_addr = in_reg.bitcast(reg_addr, bx.cx.type_ptr_to(reg_type));
diff --git a/compiler/rustc_codegen_ssa/Cargo.toml b/compiler/rustc_codegen_ssa/Cargo.toml
index f1e412d..1446624 100644
--- a/compiler/rustc_codegen_ssa/Cargo.toml
+++ b/compiler/rustc_codegen_ssa/Cargo.toml
@@ -1,5 +1,4 @@
[package]
-authors = ["The Rust Project Developers"]
name = "rustc_codegen_ssa"
version = "0.0.0"
edition = "2018"
@@ -17,6 +16,7 @@
tempfile = "3.2"
pathdiff = "0.2.0"
smallvec = { version = "1.6.1", features = ["union", "may_dangle"] }
+regex = "1.4"
rustc_serialize = { path = "../rustc_serialize" }
rustc_ast = { path = "../rustc_ast" }
diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs
index ab211e9..f5463bc 100644
--- a/compiler/rustc_codegen_ssa/src/back/link.rs
+++ b/compiler/rustc_codegen_ssa/src/back/link.rs
@@ -32,6 +32,7 @@
use object::elf;
use object::write::Object;
use object::{Architecture, BinaryFormat, Endianness, FileFlags, SectionFlags, SectionKind};
+use regex::Regex;
use tempfile::Builder as TempFileBuilder;
use std::ffi::OsString;
@@ -672,6 +673,8 @@
// Invoke the system linker
info!("{:?}", &cmd);
let retry_on_segfault = env::var("RUSTC_RETRY_LINKER_ON_SEGFAULT").is_ok();
+ let unknown_arg_regex =
+ Regex::new(r"(unknown|unrecognized) (command line )?(option|argument)").unwrap();
let mut prog;
let mut i = 0;
loop {
@@ -688,16 +691,15 @@
out.extend(&output.stdout);
let out = String::from_utf8_lossy(&out);
- // Check to see if the link failed with "unrecognized command line option:
- // '-no-pie'" for gcc or "unknown argument: '-no-pie'" for clang. If so,
- // reperform the link step without the -no-pie option. This is safe because
- // if the linker doesn't support -no-pie then it should not default to
- // linking executables as pie. Different versions of gcc seem to use
- // different quotes in the error message so don't check for them.
+ // Check to see if the link failed with an error message that indicates it
+ // doesn't recognize the -no-pie option. If so, reperform the link step
+ // without it. This is safe because if the linker doesn't support -no-pie
+ // then it should not default to linking executables as pie. Different
+ // versions of gcc seem to use different quotes in the error message so
+ // don't check for them.
if sess.target.linker_is_gnu
&& flavor != LinkerFlavor::Ld
- && (out.contains("unrecognized command line option")
- || out.contains("unknown argument"))
+ && unknown_arg_regex.is_match(&out)
&& out.contains("-no-pie")
&& cmd.get_args().iter().any(|e| e.to_string_lossy() == "-no-pie")
{
@@ -716,8 +718,7 @@
// Fallback from '-static-pie' to '-static' in that case.
if sess.target.linker_is_gnu
&& flavor != LinkerFlavor::Ld
- && (out.contains("unrecognized command line option")
- || out.contains("unknown argument"))
+ && unknown_arg_regex.is_match(&out)
&& (out.contains("-static-pie") || out.contains("--no-dynamic-linker"))
&& cmd.get_args().iter().any(|e| e.to_string_lossy() == "-static-pie")
{
@@ -1802,15 +1803,16 @@
add_local_native_libraries(cmd, sess, codegen_results);
}
- // Rust libraries.
+ // Upstream rust libraries and their nobundle static libraries
add_upstream_rust_crates::<B>(cmd, sess, codegen_results, crate_type, tmpdir);
- // Native libraries linked with `#[link]` attributes at and `-l` command line options.
+ // Upstream dymamic native libraries linked with `#[link]` attributes at and `-l`
+ // command line options.
// If -Zlink-native-libraries=false is set, then the assumption is that an
// external build system already has the native dependencies defined, and it
// will provide them to the linker itself.
if sess.opts.debugging_opts.link_native_libraries {
- add_upstream_native_libraries(cmd, sess, codegen_results, crate_type);
+ add_upstream_native_libraries(cmd, sess, codegen_results);
}
// Library linking above uses some global state for things like `-Bstatic`/`-Bdynamic` to make
@@ -2032,7 +2034,7 @@
}
}
-/// # Rust Crate linking
+/// # Linking Rust crates and their nobundle static libraries
///
/// Rust crates are not considered at all when creating an rlib output. All dependencies will be
/// linked when producing the final output (instead of the intermediate rlib version).
@@ -2137,6 +2139,29 @@
Linkage::NotLinked | Linkage::IncludedFromDylib => {}
Linkage::Static => {
add_static_crate::<B>(cmd, sess, codegen_results, tmpdir, crate_type, cnum);
+
+ // Link static native libs with "-bundle" modifier only if the crate they originate from
+ // is being linked statically to the current crate. If it's linked dynamically
+ // or is an rlib already included via some other dylib crate, the symbols from
+ // native libs will have already been included in that dylib.
+ //
+ // If -Zlink-native-libraries=false is set, then the assumption is that an
+ // external build system already has the native dependencies defined, and it
+ // will provide them to the linker itself.
+ if sess.opts.debugging_opts.link_native_libraries {
+ // Skip if this library is the same as the last.
+ let mut last = None;
+ for lib in &codegen_results.crate_info.native_libraries[&cnum] {
+ if lib.name.is_some()
+ && relevant_lib(sess, lib)
+ && matches!(lib.kind, NativeLibKind::Static { bundle: Some(false), .. })
+ && last != lib.name
+ {
+ cmd.link_staticlib(lib.name.unwrap(), lib.verbatim.unwrap_or(false));
+ last = lib.name;
+ }
+ }
+ }
}
Linkage::Dynamic => add_dynamic_crate(cmd, sess, &src.dylib.as_ref().unwrap().0),
}
@@ -2309,27 +2334,9 @@
cmd: &mut dyn Linker,
sess: &Session,
codegen_results: &CodegenResults,
- crate_type: CrateType,
) {
- // Be sure to use a topological sorting of crates because there may be
- // interdependencies between native libraries. When passing -nodefaultlibs,
- // for example, almost all native libraries depend on libc, so we have to
- // make sure that's all the way at the right (liblibc is near the base of
- // the dependency chain).
- //
- // This passes RequireStatic, but the actual requirement doesn't matter,
- // we're just getting an ordering of crate numbers, we're not worried about
- // the paths.
- let (_, data) = codegen_results
- .crate_info
- .dependency_formats
- .iter()
- .find(|(ty, _)| *ty == crate_type)
- .expect("failed to find crate type in dependency format list");
-
- let crates = &codegen_results.crate_info.used_crates;
let mut last = (NativeLibKind::Unspecified, None);
- for &cnum in crates {
+ for &cnum in &codegen_results.crate_info.used_crates {
for lib in codegen_results.crate_info.native_libraries[&cnum].iter() {
let name = match lib.name {
Some(l) => l,
@@ -2351,19 +2358,10 @@
NativeLibKind::Framework { as_needed } => {
cmd.link_framework(name, as_needed.unwrap_or(true))
}
- NativeLibKind::Static { bundle: Some(false), .. } => {
- // Link "static-nobundle" native libs only if the crate they originate from
- // is being linked statically to the current crate. If it's linked dynamically
- // or is an rlib already included via some other dylib crate, the symbols from
- // native libs will have already been included in that dylib.
- if data[cnum.as_usize() - 1] == Linkage::Static {
- cmd.link_staticlib(name, verbatim)
- }
- }
- // ignore statically included native libraries here as we've
- // already included them when we included the rust library
- // previously
- NativeLibKind::Static { bundle: None | Some(true), .. } => {}
+ // ignore static native libraries here as we've
+ // already included them in add_local_native_libraries and
+ // add_upstream_rust_crates
+ NativeLibKind::Static { .. } => {}
NativeLibKind::RawDylib => {}
}
}
@@ -2484,20 +2482,39 @@
if let LinkerFlavor::Gcc = flavor {
match ld_impl {
LdImpl::Lld => {
- let tools_path =
- sess.host_filesearch(PathKind::All).get_tools_search_paths(false);
- let lld_path = tools_path
- .into_iter()
- .map(|p| p.join("gcc-ld"))
- .find(|p| {
- p.join(if sess.host.is_like_windows { "ld.exe" } else { "ld" }).exists()
- })
- .unwrap_or_else(|| sess.fatal("rust-lld (as ld) not found"));
- cmd.cmd().arg({
- let mut arg = OsString::from("-B");
- arg.push(lld_path);
- arg
- });
+ if sess.target.lld_flavor == LldFlavor::Ld64 {
+ let tools_path =
+ sess.host_filesearch(PathKind::All).get_tools_search_paths(false);
+ let ld64_exe = tools_path
+ .into_iter()
+ .map(|p| p.join("gcc-ld"))
+ .map(|p| {
+ p.join(if sess.host.is_like_windows { "ld64.exe" } else { "ld64" })
+ })
+ .find(|p| p.exists())
+ .unwrap_or_else(|| sess.fatal("rust-lld (as ld64) not found"));
+ cmd.cmd().arg({
+ let mut arg = OsString::from("-fuse-ld=");
+ arg.push(ld64_exe);
+ arg
+ });
+ } else {
+ let tools_path =
+ sess.host_filesearch(PathKind::All).get_tools_search_paths(false);
+ let lld_path = tools_path
+ .into_iter()
+ .map(|p| p.join("gcc-ld"))
+ .find(|p| {
+ p.join(if sess.host.is_like_windows { "ld.exe" } else { "ld" })
+ .exists()
+ })
+ .unwrap_or_else(|| sess.fatal("rust-lld (as ld) not found"));
+ cmd.cmd().arg({
+ let mut arg = OsString::from("-B");
+ arg.push(lld_path);
+ arg
+ });
+ }
}
}
} else {
diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs
index 4ef2144..4a7090b3 100644
--- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs
+++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs
@@ -137,10 +137,6 @@
reachable_non_generics.insert(id.to_def_id(), SymbolExportLevel::C);
}
- if let Some(id) = tcx.plugin_registrar_fn(()) {
- reachable_non_generics.insert(id.to_def_id(), SymbolExportLevel::C);
- }
-
reachable_non_generics
}
diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs
index be2bf8b..a5143a7 100644
--- a/compiler/rustc_codegen_ssa/src/base.rs
+++ b/compiler/rustc_codegen_ssa/src/base.rs
@@ -23,7 +23,6 @@
use rustc_middle::middle::lang_items;
use rustc_middle::mir::mono::{CodegenUnit, CodegenUnitNameBuilder, MonoItem};
use rustc_middle::ty::layout::{HasTyCtxt, TyAndLayout};
-use rustc_middle::ty::layout::{FAT_PTR_ADDR, FAT_PTR_EXTRA};
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::{self, Instance, Ty, TyCtxt};
use rustc_session::cgu_reuse_tracker::CguReuse;
@@ -32,6 +31,7 @@
use rustc_span::symbol::sym;
use rustc_target::abi::{Align, LayoutOf, VariantIdx};
+use std::convert::TryFrom;
use std::ops::{Deref, DerefMut};
use std::time::{Duration, Instant};
@@ -128,55 +128,84 @@
///
/// The `old_info` argument is a bit odd. It is intended for use in an upcast,
/// where the new vtable for an object will be derived from the old one.
-pub fn unsized_info<'tcx, Cx: CodegenMethods<'tcx>>(
- cx: &Cx,
+pub fn unsized_info<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
+ bx: &mut Bx,
source: Ty<'tcx>,
target: Ty<'tcx>,
- old_info: Option<Cx::Value>,
-) -> Cx::Value {
+ old_info: Option<Bx::Value>,
+) -> Bx::Value {
+ let cx = bx.cx();
let (source, target) =
- cx.tcx().struct_lockstep_tails_erasing_lifetimes(source, target, cx.param_env());
+ cx.tcx().struct_lockstep_tails_erasing_lifetimes(source, target, bx.param_env());
match (source.kind(), target.kind()) {
(&ty::Array(_, len), &ty::Slice(_)) => {
cx.const_usize(len.eval_usize(cx.tcx(), ty::ParamEnv::reveal_all()))
}
- (&ty::Dynamic(..), &ty::Dynamic(..)) => {
- // For now, upcasts are limited to changes in marker
- // traits, and hence never actually require an actual
- // change to the vtable.
- old_info.expect("unsized_info: missing old info for trait upcast")
+ (&ty::Dynamic(ref data_a, ..), &ty::Dynamic(ref data_b, ..)) => {
+ let old_info =
+ old_info.expect("unsized_info: missing old info for trait upcasting coercion");
+ if data_a.principal_def_id() == data_b.principal_def_id() {
+ return old_info;
+ }
+
+ // trait upcasting coercion
+
+ let vptr_entry_idx =
+ cx.tcx().vtable_trait_upcasting_coercion_new_vptr_slot((source, target));
+
+ if let Some(entry_idx) = vptr_entry_idx {
+ let ptr_ty = cx.type_i8p();
+ let ptr_align = cx.tcx().data_layout.pointer_align.abi;
+ let llvtable = bx.pointercast(old_info, bx.type_ptr_to(ptr_ty));
+ let gep = bx.inbounds_gep(
+ ptr_ty,
+ llvtable,
+ &[bx.const_usize(u64::try_from(entry_idx).unwrap())],
+ );
+ let new_vptr = bx.load(ptr_ty, gep, ptr_align);
+ bx.nonnull_metadata(new_vptr);
+ // Vtable loads are invariant.
+ bx.set_invariant_load(new_vptr);
+ new_vptr
+ } else {
+ old_info
+ }
}
(_, &ty::Dynamic(ref data, ..)) => {
- let vtable_ptr = cx.layout_of(cx.tcx().mk_mut_ptr(target)).field(cx, FAT_PTR_EXTRA);
- cx.const_ptrcast(
- meth::get_vtable(cx, source, data.principal()),
- cx.backend_type(vtable_ptr),
- )
+ let vtable_ptr_ty = cx.scalar_pair_element_backend_type(
+ cx.layout_of(cx.tcx().mk_mut_ptr(target)),
+ 1,
+ true,
+ );
+ cx.const_ptrcast(meth::get_vtable(cx, source, data.principal()), vtable_ptr_ty)
}
_ => bug!("unsized_info: invalid unsizing {:?} -> {:?}", source, target),
}
}
-/// Coerces `src` to `dst_ty`. `src_ty` must be a thin pointer.
-pub fn unsize_thin_ptr<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
+/// Coerces `src` to `dst_ty`. `src_ty` must be a pointer.
+pub fn unsize_ptr<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
bx: &mut Bx,
src: Bx::Value,
src_ty: Ty<'tcx>,
dst_ty: Ty<'tcx>,
+ old_info: Option<Bx::Value>,
) -> (Bx::Value, Bx::Value) {
- debug!("unsize_thin_ptr: {:?} => {:?}", src_ty, dst_ty);
+ debug!("unsize_ptr: {:?} => {:?}", src_ty, dst_ty);
match (src_ty.kind(), dst_ty.kind()) {
(&ty::Ref(_, a, _), &ty::Ref(_, b, _) | &ty::RawPtr(ty::TypeAndMut { ty: b, .. }))
| (&ty::RawPtr(ty::TypeAndMut { ty: a, .. }), &ty::RawPtr(ty::TypeAndMut { ty: b, .. })) => {
- assert!(bx.cx().type_is_sized(a));
+ assert_eq!(bx.cx().type_is_sized(a), old_info.is_none());
let ptr_ty = bx.cx().type_ptr_to(bx.cx().backend_type(bx.cx().layout_of(b)));
- (bx.pointercast(src, ptr_ty), unsized_info(bx.cx(), a, b, None))
+ (bx.pointercast(src, ptr_ty), unsized_info(bx, a, b, old_info))
}
(&ty::Adt(def_a, _), &ty::Adt(def_b, _)) => {
assert_eq!(def_a, def_b);
-
let src_layout = bx.cx().layout_of(src_ty);
let dst_layout = bx.cx().layout_of(dst_ty);
+ if src_ty == dst_ty {
+ return (src, old_info.unwrap());
+ }
let mut result = None;
for i in 0..src_layout.fields.count() {
let src_f = src_layout.field(bx.cx(), i);
@@ -190,18 +219,15 @@
let dst_f = dst_layout.field(bx.cx(), i);
assert_ne!(src_f.ty, dst_f.ty);
assert_eq!(result, None);
- result = Some(unsize_thin_ptr(bx, src, src_f.ty, dst_f.ty));
+ result = Some(unsize_ptr(bx, src, src_f.ty, dst_f.ty, old_info));
}
let (lldata, llextra) = result.unwrap();
+ let lldata_ty = bx.cx().scalar_pair_element_backend_type(dst_layout, 0, true);
+ let llextra_ty = bx.cx().scalar_pair_element_backend_type(dst_layout, 1, true);
// HACK(eddyb) have to bitcast pointers until LLVM removes pointee types.
- // FIXME(eddyb) move these out of this `match` arm, so they're always
- // applied, uniformly, no matter the source/destination types.
- (
- bx.bitcast(lldata, bx.cx().scalar_pair_element_backend_type(dst_layout, 0, true)),
- bx.bitcast(llextra, bx.cx().scalar_pair_element_backend_type(dst_layout, 1, true)),
- )
+ (bx.bitcast(lldata, lldata_ty), bx.bitcast(llextra, llextra_ty))
}
- _ => bug!("unsize_thin_ptr: called on bad types"),
+ _ => bug!("unsize_ptr: called on bad types"),
}
}
@@ -217,17 +243,8 @@
match (src_ty.kind(), dst_ty.kind()) {
(&ty::Ref(..), &ty::Ref(..) | &ty::RawPtr(..)) | (&ty::RawPtr(..), &ty::RawPtr(..)) => {
let (base, info) = match bx.load_operand(src).val {
- OperandValue::Pair(base, info) => {
- // fat-ptr to fat-ptr unsize preserves the vtable
- // i.e., &'a fmt::Debug+Send => &'a fmt::Debug
- // So we need to pointercast the base to ensure
- // the types match up.
- // FIXME(eddyb) use `scalar_pair_element_backend_type` here,
- // like `unsize_thin_ptr` does.
- let thin_ptr = dst.layout.field(bx.cx(), FAT_PTR_ADDR);
- (bx.pointercast(base, bx.cx().backend_type(thin_ptr)), info)
- }
- OperandValue::Immediate(base) => unsize_thin_ptr(bx, base, src_ty, dst_ty),
+ OperandValue::Pair(base, info) => unsize_ptr(bx, base, src_ty, dst_ty, Some(info)),
+ OperandValue::Immediate(base) => unsize_ptr(bx, base, src_ty, dst_ty, None),
OperandValue::Ref(..) => bug!(),
};
OperandValue::Pair(base, info).store(bx, dst);
@@ -413,9 +430,11 @@
bx.insert_reference_to_gdb_debug_scripts_section_global();
+ let isize_ty = cx.type_isize();
+ let i8pp_ty = cx.type_ptr_to(cx.type_i8p());
let (arg_argc, arg_argv) = get_argc_argv(cx, &mut bx);
- let (start_fn, args) = if use_start_lang_item {
+ let (start_fn, start_ty, args) = if use_start_lang_item {
let start_def_id = cx.tcx().require_lang_item(LangItem::Start, None);
let start_fn = cx.get_fn_addr(
ty::Instance::resolve(
@@ -427,16 +446,15 @@
.unwrap()
.unwrap(),
);
- (
- start_fn,
- vec![bx.pointercast(rust_main, cx.type_ptr_to(cx.type_i8p())), arg_argc, arg_argv],
- )
+ let start_ty = cx.type_func(&[cx.val_ty(rust_main), isize_ty, i8pp_ty], isize_ty);
+ (start_fn, start_ty, vec![rust_main, arg_argc, arg_argv])
} else {
debug!("using user-defined start fn");
- (rust_main, vec![arg_argc, arg_argv])
+ let start_ty = cx.type_func(&[isize_ty, i8pp_ty], isize_ty);
+ (rust_main, start_ty, vec![arg_argc, arg_argv])
};
- let result = bx.call(start_fn, &args, None);
+ let result = bx.call(start_ty, start_fn, &args, None);
let cast = bx.intcast(result, cx.type_int(), true);
bx.ret(cast);
diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
index 81e905b..f0b32c9 100644
--- a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
+++ b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
@@ -406,11 +406,11 @@
let dataful_discriminant_range =
&dataful_variant_layout.largest_niche.as_ref().unwrap().scalar.valid_range;
- let min = dataful_discriminant_range.start();
- let min = tag.value.size(&tcx).truncate(*min);
+ let min = dataful_discriminant_range.start;
+ let min = tag.value.size(&tcx).truncate(min);
- let max = dataful_discriminant_range.end();
- let max = tag.value.size(&tcx).truncate(*max);
+ let max = dataful_discriminant_range.end;
+ let max = tag.value.size(&tcx).truncate(max);
let dataful_variant_name = def.variants[*dataful_variant].ident.as_str();
diff --git a/compiler/rustc_codegen_ssa/src/meth.rs b/compiler/rustc_codegen_ssa/src/meth.rs
index b392b2c..3267d32 100644
--- a/compiler/rustc_codegen_ssa/src/meth.rs
+++ b/compiler/rustc_codegen_ssa/src/meth.rs
@@ -23,7 +23,7 @@
let llty = bx.fn_ptr_backend_type(fn_abi);
let llvtable = bx.pointercast(llvtable, bx.type_ptr_to(llty));
let ptr_align = bx.tcx().data_layout.pointer_align.abi;
- let gep = bx.inbounds_gep(llvtable, &[bx.const_usize(self.0)]);
+ let gep = bx.inbounds_gep(llty, llvtable, &[bx.const_usize(self.0)]);
let ptr = bx.load(llty, gep, ptr_align);
bx.nonnull_metadata(ptr);
// Vtable loads are invariant.
@@ -42,7 +42,7 @@
let llty = bx.type_isize();
let llvtable = bx.pointercast(llvtable, bx.type_ptr_to(llty));
let usize_align = bx.tcx().data_layout.pointer_align.abi;
- let gep = bx.inbounds_gep(llvtable, &[bx.const_usize(self.0)]);
+ let gep = bx.inbounds_gep(llty, llvtable, &[bx.const_usize(self.0)]);
let ptr = bx.load(llty, gep, usize_align);
// Vtable loads are invariant.
bx.set_invariant_load(ptr);
@@ -72,7 +72,7 @@
return val;
}
- let vtable_alloc_id = tcx.vtable_allocation(ty, trait_ref);
+ let vtable_alloc_id = tcx.vtable_allocation((ty, trait_ref));
let vtable_allocation = tcx.global_alloc(vtable_alloc_id).unwrap_memory();
let vtable_const = cx.const_data_from_alloc(vtable_allocation);
let align = cx.data_layout().pointer_align.abi;
diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs
index b584801..2a76ad0 100644
--- a/compiler/rustc_codegen_ssa/src/mir/block.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/block.rs
@@ -132,14 +132,21 @@
) {
// If there is a cleanup block and the function we're calling can unwind, then
// do an invoke, otherwise do a call.
+ let fn_ty = bx.fn_decl_backend_type(&fn_abi);
if let Some(cleanup) = cleanup.filter(|_| fn_abi.can_unwind) {
let ret_llbb = if let Some((_, target)) = destination {
fx.llbb(target)
} else {
fx.unreachable_block()
};
- let invokeret =
- bx.invoke(fn_ptr, &llargs, ret_llbb, self.llblock(fx, cleanup), self.funclet(fx));
+ let invokeret = bx.invoke(
+ fn_ty,
+ fn_ptr,
+ &llargs,
+ ret_llbb,
+ self.llblock(fx, cleanup),
+ self.funclet(fx),
+ );
bx.apply_attrs_callsite(&fn_abi, invokeret);
if let Some((ret_dest, target)) = destination {
@@ -148,7 +155,7 @@
fx.store_return(&mut ret_bx, ret_dest, &fn_abi.ret, invokeret);
}
} else {
- let llret = bx.call(fn_ptr, &llargs, self.funclet(fx));
+ let llret = bx.call(fn_ty, fn_ptr, &llargs, self.funclet(fx));
bx.apply_attrs_callsite(&fn_abi, llret);
if fx.mir[self.bb].is_cleanup {
// Cleanup is always the cold path. Don't inline
@@ -465,10 +472,8 @@
let layout = bx.layout_of(ty);
let do_panic = match intrinsic {
Inhabited => layout.abi.is_uninhabited(),
- // We unwrap as the error type is `!`.
- ZeroValid => !layout.might_permit_raw_init(bx, /*zero:*/ true).unwrap(),
- // We unwrap as the error type is `!`.
- UninitValid => !layout.might_permit_raw_init(bx, /*zero:*/ false).unwrap(),
+ ZeroValid => !layout.might_permit_raw_init(bx, /*zero:*/ true),
+ UninitValid => !layout.might_permit_raw_init(bx, /*zero:*/ false),
};
if do_panic {
let msg_str = with_no_trimmed_paths(|| {
@@ -1391,7 +1396,7 @@
LocalRef::UnsizedPlace(_) => bug!("transmute must not involve unsized locals"),
LocalRef::Operand(None) => {
let dst_layout = bx.layout_of(self.monomorphized_place_ty(dst.as_ref()));
- assert!(!dst_layout.ty.has_erasable_regions());
+ assert!(!dst_layout.ty.has_erasable_regions(self.cx.tcx()));
let place = PlaceRef::alloca(bx, dst_layout);
place.storage_live(bx);
self.codegen_transmute_into(bx, src, place);
diff --git a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
index 56ff1b3..7599922 100644
--- a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
@@ -116,14 +116,18 @@
OperandRef::from_const(bx, value, ret_ty).immediate_or_packed_pair(bx)
}
sym::offset => {
+ let ty = substs.type_at(0);
+ let layout = bx.layout_of(ty);
let ptr = args[0].immediate();
let offset = args[1].immediate();
- bx.inbounds_gep(ptr, &[offset])
+ bx.inbounds_gep(bx.backend_type(layout), ptr, &[offset])
}
sym::arith_offset => {
+ let ty = substs.type_at(0);
+ let layout = bx.layout_of(ty);
let ptr = args[0].immediate();
let offset = args[1].immediate();
- bx.gep(ptr, &[offset])
+ bx.gep(bx.backend_type(layout), ptr, &[offset])
}
sym::copy => {
copy_intrinsic(
diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs
index 3bbc481..e2edd44 100644
--- a/compiler/rustc_codegen_ssa/src/mir/mod.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs
@@ -216,7 +216,7 @@
let mut allocate_local = |local| {
let decl = &mir.local_decls[local];
let layout = bx.layout_of(fx.monomorphize(decl.ty));
- assert!(!layout.ty.has_erasable_regions());
+ assert!(!layout.ty.has_erasable_regions(cx.tcx()));
if local == mir::RETURN_PLACE && fx.fn_abi.ret.is_indirect() {
debug!("alloc: {:?} (return place) -> place", local);
diff --git a/compiler/rustc_codegen_ssa/src/mir/operand.rs b/compiler/rustc_codegen_ssa/src/mir/operand.rs
index 3e8386b..cfb2bef 100644
--- a/compiler/rustc_codegen_ssa/src/mir/operand.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/operand.rs
@@ -311,14 +311,15 @@
Abi::ScalarPair(ref a, ref b) => (a, b),
_ => bug!("store_with_flags: invalid ScalarPair layout: {:#?}", dest.layout),
};
+ let ty = bx.backend_type(dest.layout);
let b_offset = a_scalar.value.size(bx).align_to(b_scalar.value.align(bx).abi);
- let llptr = bx.struct_gep(dest.llval, 0);
+ let llptr = bx.struct_gep(ty, dest.llval, 0);
let val = bx.from_immediate(a);
let align = dest.align;
bx.store_with_flags(val, llptr, align, flags);
- let llptr = bx.struct_gep(dest.llval, 1);
+ let llptr = bx.struct_gep(ty, dest.llval, 1);
let val = bx.from_immediate(b);
let align = dest.align.restrict_for_offset(b_offset);
bx.store_with_flags(val, llptr, align, flags);
diff --git a/compiler/rustc_codegen_ssa/src/mir/place.rs b/compiler/rustc_codegen_ssa/src/mir/place.rs
index 66d9d1a..20be466 100644
--- a/compiler/rustc_codegen_ssa/src/mir/place.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/place.rs
@@ -103,12 +103,13 @@
if offset == a.value.size(bx.cx()).align_to(b.value.align(bx.cx()).abi) =>
{
// Offset matches second field.
- bx.struct_gep(self.llval, 1)
+ let ty = bx.backend_type(self.layout);
+ bx.struct_gep(ty, self.llval, 1)
}
Abi::Scalar(_) | Abi::ScalarPair(..) | Abi::Vector { .. } if field.is_zst() => {
// ZST fields are not included in Scalar, ScalarPair, and Vector layouts, so manually offset the pointer.
let byte_ptr = bx.pointercast(self.llval, bx.cx().type_i8p());
- bx.gep(byte_ptr, &[bx.const_usize(offset.bytes())])
+ bx.gep(bx.cx().type_i8(), byte_ptr, &[bx.const_usize(offset.bytes())])
}
Abi::Scalar(_) | Abi::ScalarPair(..) => {
// All fields of Scalar and ScalarPair layouts must have been handled by this point.
@@ -119,7 +120,10 @@
self.layout
);
}
- _ => bx.struct_gep(self.llval, bx.cx().backend_field_index(self.layout, ix)),
+ _ => {
+ let ty = bx.backend_type(self.layout);
+ bx.struct_gep(ty, self.llval, bx.cx().backend_field_index(self.layout, ix))
+ }
};
PlaceRef {
// HACK(eddyb): have to bitcast pointers until LLVM removes pointee types.
@@ -185,7 +189,7 @@
// Cast and adjust pointer.
let byte_ptr = bx.pointercast(self.llval, bx.cx().type_i8p());
- let byte_ptr = bx.gep(byte_ptr, &[offset]);
+ let byte_ptr = bx.gep(bx.cx().type_i8(), byte_ptr, &[offset]);
// Finally, cast back to the type expected.
let ll_fty = bx.cx().backend_type(field);
@@ -380,7 +384,11 @@
};
PlaceRef {
- llval: bx.inbounds_gep(self.llval, &[bx.cx().const_usize(0), llindex]),
+ llval: bx.inbounds_gep(
+ bx.cx().backend_type(self.layout),
+ self.llval,
+ &[bx.cx().const_usize(0), llindex],
+ ),
llextra: None,
layout,
align: self.align.restrict_for_offset(offset),
diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
index 530de3d..02e2db5 100644
--- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
@@ -220,34 +220,23 @@
}
mir::CastKind::Pointer(PointerCast::Unsize) => {
assert!(bx.cx().is_backend_scalar_pair(cast));
- match operand.val {
+ let (lldata, llextra) = match operand.val {
OperandValue::Pair(lldata, llextra) => {
// unsize from a fat pointer -- this is a
- // "trait-object-to-supertrait" coercion, for
- // example, `&'a fmt::Debug + Send => &'a fmt::Debug`.
-
- // HACK(eddyb) have to bitcast pointers
- // until LLVM removes pointee types.
- let lldata = bx.pointercast(
- lldata,
- bx.cx().scalar_pair_element_backend_type(cast, 0, true),
- );
- OperandValue::Pair(lldata, llextra)
+ // "trait-object-to-supertrait" coercion.
+ (lldata, Some(llextra))
}
OperandValue::Immediate(lldata) => {
// "standard" unsize
- let (lldata, llextra) = base::unsize_thin_ptr(
- &mut bx,
- lldata,
- operand.layout.ty,
- cast.ty,
- );
- OperandValue::Pair(lldata, llextra)
+ (lldata, None)
}
OperandValue::Ref(..) => {
bug!("by-ref operand {:?} in `codegen_rvalue_operand`", operand);
}
- }
+ };
+ let (lldata, llextra) =
+ base::unsize_ptr(&mut bx, lldata, operand.layout.ty, cast.ty, llextra);
+ OperandValue::Pair(lldata, llextra)
}
mir::CastKind::Pointer(PointerCast::MutToConstPointer)
| mir::CastKind::Misc
@@ -321,15 +310,15 @@
let er = scalar.valid_range_exclusive(bx.cx());
if er.end != er.start
- && scalar.valid_range.end() >= scalar.valid_range.start()
+ && scalar.valid_range.end >= scalar.valid_range.start
{
// We want `table[e as usize ± k]` to not
// have bound checks, and this is the most
// convenient place to put the `assume`s.
- if *scalar.valid_range.start() > 0 {
+ if scalar.valid_range.start > 0 {
let enum_value_lower_bound = bx
.cx()
- .const_uint_big(ll_t_in, *scalar.valid_range.start());
+ .const_uint_big(ll_t_in, scalar.valid_range.start);
let cmp_start = bx.icmp(
IntPredicate::IntUGE,
llval,
@@ -339,7 +328,7 @@
}
let enum_value_upper_bound =
- bx.cx().const_uint_big(ll_t_in, *scalar.valid_range.end());
+ bx.cx().const_uint_big(ll_t_in, scalar.valid_range.end);
let cmp_end = bx.icmp(
IntPredicate::IntULE,
llval,
@@ -529,7 +518,8 @@
};
let instance = ty::Instance::mono(bx.tcx(), def_id);
let r = bx.cx().get_fn_addr(instance);
- let call = bx.call(r, &[llsize, llalign], None);
+ let ty = bx.type_func(&[bx.type_isize(), bx.type_isize()], bx.type_i8p());
+ let call = bx.call(ty, r, &[llsize, llalign], None);
let val = bx.pointercast(call, llty_ptr);
let operand = OperandRef { val: OperandValue::Immediate(val), layout: box_layout };
@@ -647,7 +637,14 @@
mir::BinOp::BitOr => bx.or(lhs, rhs),
mir::BinOp::BitAnd => bx.and(lhs, rhs),
mir::BinOp::BitXor => bx.xor(lhs, rhs),
- mir::BinOp::Offset => bx.inbounds_gep(lhs, &[rhs]),
+ mir::BinOp::Offset => {
+ let pointee_type = input_ty
+ .builtin_deref(true)
+ .unwrap_or_else(|| bug!("deref of non-pointer {:?}", input_ty))
+ .ty;
+ let llty = bx.cx().backend_type(bx.cx().layout_of(pointee_type));
+ bx.inbounds_gep(llty, lhs, &[rhs])
+ }
mir::BinOp::Shl => common::build_unchecked_lshift(bx, lhs, rhs),
mir::BinOp::Shr => common::build_unchecked_rshift(bx, input_ty, lhs, rhs),
mir::BinOp::Ne
@@ -904,7 +901,7 @@
//
// Performance note: Unordered comparison can be lowered to a "flipped"
// comparison and a negation, and the negation can be merged into the
- // select. Therefore, it not necessarily any more expensive than a
+ // select. Therefore, it not necessarily any more expensive than an
// ordered ("normal") comparison. Whether these optimizations will be
// performed is ultimately up to the backend, but at least x86 does
// perform them.
diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs
index c89d42e..8d7e961 100644
--- a/compiler/rustc_codegen_ssa/src/target_features.rs
+++ b/compiler/rustc_codegen_ssa/src/target_features.rs
@@ -47,8 +47,6 @@
("sve", Some(sym::aarch64_target_feature)),
// FEAT_CRC
("crc", Some(sym::aarch64_target_feature)),
- // Cryptographic extension
- ("crypto", Some(sym::aarch64_target_feature)),
// FEAT_RAS
("ras", Some(sym::aarch64_target_feature)),
// FEAT_LSE
diff --git a/compiler/rustc_codegen_ssa/src/traits/backend.rs b/compiler/rustc_codegen_ssa/src/traits/backend.rs
index dc4146e..1393fc7 100644
--- a/compiler/rustc_codegen_ssa/src/traits/backend.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/backend.rs
@@ -39,12 +39,17 @@
}
pub trait Backend<'tcx>:
- Sized + BackendTypes + HasTyCtxt<'tcx> + LayoutOf<Ty = Ty<'tcx>, TyAndLayout = TyAndLayout<'tcx>>
+ Sized
+ + BackendTypes
+ + HasTyCtxt<'tcx>
+ + LayoutOf<'tcx, Ty = Ty<'tcx>, TyAndLayout = TyAndLayout<'tcx>>
{
}
impl<'tcx, T> Backend<'tcx> for T where
- Self: BackendTypes + HasTyCtxt<'tcx> + LayoutOf<Ty = Ty<'tcx>, TyAndLayout = TyAndLayout<'tcx>>
+ Self: BackendTypes
+ + HasTyCtxt<'tcx>
+ + LayoutOf<'tcx, Ty = Ty<'tcx>, TyAndLayout = TyAndLayout<'tcx>>
{
}
diff --git a/compiler/rustc_codegen_ssa/src/traits/builder.rs b/compiler/rustc_codegen_ssa/src/traits/builder.rs
index f0c232a..afb8ee3 100644
--- a/compiler/rustc_codegen_ssa/src/traits/builder.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/builder.rs
@@ -72,6 +72,7 @@
);
fn invoke(
&mut self,
+ llty: Self::Type,
llfn: Self::Value,
args: &[Self::Value],
then: Self::BasicBlock,
@@ -176,9 +177,14 @@
size: Size,
);
- fn gep(&mut self, ptr: Self::Value, indices: &[Self::Value]) -> Self::Value;
- fn inbounds_gep(&mut self, ptr: Self::Value, indices: &[Self::Value]) -> Self::Value;
- fn struct_gep(&mut self, ptr: Self::Value, idx: u64) -> Self::Value;
+ fn gep(&mut self, ty: Self::Type, ptr: Self::Value, indices: &[Self::Value]) -> Self::Value;
+ fn inbounds_gep(
+ &mut self,
+ ty: Self::Type,
+ ptr: Self::Value,
+ indices: &[Self::Value],
+ ) -> Self::Value;
+ fn struct_gep(&mut self, ty: Self::Type, ptr: Self::Value, idx: u64) -> Self::Value;
fn trunc(&mut self, val: Self::Value, dest_ty: Self::Type) -> Self::Value;
fn sext(&mut self, val: Self::Value, dest_ty: Self::Type) -> Self::Value;
@@ -298,6 +304,7 @@
fn call(
&mut self,
+ llty: Self::Type,
llfn: Self::Value,
args: &[Self::Value],
funclet: Option<&Self::Funclet>,
diff --git a/compiler/rustc_codegen_ssa/src/traits/misc.rs b/compiler/rustc_codegen_ssa/src/traits/misc.rs
index 46f2adb..4266e42 100644
--- a/compiler/rustc_codegen_ssa/src/traits/misc.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/misc.rs
@@ -16,9 +16,11 @@
fn sess(&self) -> &Session;
fn codegen_unit(&self) -> &'tcx CodegenUnit<'tcx>;
fn used_statics(&self) -> &RefCell<Vec<Self::Value>>;
+ fn compiler_used_statics(&self) -> &RefCell<Vec<Self::Value>>;
fn set_frame_pointer_type(&self, llfn: Self::Function);
fn apply_target_cpu_attr(&self, llfn: Self::Function);
fn create_used_variable(&self);
+ fn create_compiler_used_variable(&self);
/// Declares the extern "C" main function for the entry point. Returns None if the symbol already exists.
fn declare_c_main(&self, fn_type: Self::Type) -> Option<Self::Function>;
}
diff --git a/compiler/rustc_codegen_ssa/src/traits/statics.rs b/compiler/rustc_codegen_ssa/src/traits/statics.rs
index 817fc02..a2a3cb5 100644
--- a/compiler/rustc_codegen_ssa/src/traits/statics.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/statics.rs
@@ -6,17 +6,15 @@
fn static_addr_of(&self, cv: Self::Value, align: Align, kind: Option<&str>) -> Self::Value;
fn codegen_static(&self, def_id: DefId, is_mutable: bool);
- /// Mark the given global value as "used", to prevent a backend from potentially removing a
- /// static variable that may otherwise appear unused.
- ///
- /// Static variables in Rust can be annotated with the `#[used]` attribute to direct the `rustc`
- /// compiler to mark the variable as a "used global".
- ///
- /// ```no_run
- /// #[used]
- /// static FOO: u32 = 0;
- /// ```
+ /// Mark the given global value as "used", to prevent the compiler and linker from potentially
+ /// removing a static variable that may otherwise appear unused.
fn add_used_global(&self, global: Self::Value);
+
+ /// Same as add_used_global(), but only prevent the compiler from potentially removing an
+ /// otherwise unused symbol. The linker is still permitted to drop it.
+ ///
+ /// This corresponds to the semantics of the `#[used]` attribute.
+ fn add_compiler_used_global(&self, global: Self::Value);
}
pub trait StaticBuilderMethods: BackendTypes {
diff --git a/compiler/rustc_codegen_ssa/src/traits/type_.rs b/compiler/rustc_codegen_ssa/src/traits/type_.rs
index 634a20b..b94fb1e 100644
--- a/compiler/rustc_codegen_ssa/src/traits/type_.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/type_.rs
@@ -102,6 +102,7 @@
pub trait LayoutTypeMethods<'tcx>: Backend<'tcx> {
fn backend_type(&self, layout: TyAndLayout<'tcx>) -> Self::Type;
fn cast_backend_type(&self, ty: &CastTarget) -> Self::Type;
+ fn fn_decl_backend_type(&self, fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> Self::Type;
fn fn_ptr_backend_type(&self, fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> Self::Type;
fn reg_backend_type(&self, ty: &Reg) -> Self::Type;
fn immediate_backend_type(&self, layout: TyAndLayout<'tcx>) -> Self::Type;
diff --git a/compiler/rustc_data_structures/Cargo.toml b/compiler/rustc_data_structures/Cargo.toml
index 112b94f..bc13ca2 100644
--- a/compiler/rustc_data_structures/Cargo.toml
+++ b/compiler/rustc_data_structures/Cargo.toml
@@ -1,5 +1,4 @@
[package]
-authors = ["The Rust Project Developers"]
name = "rustc_data_structures"
version = "0.0.0"
edition = "2018"
@@ -26,7 +25,7 @@
bitflags = "1.2.1"
measureme = "9.1.0"
libc = "0.2"
-stacker = "0.1.12"
+stacker = "0.1.14"
tempfile = "3.2"
[dependencies.parking_lot]
diff --git a/compiler/rustc_data_structures/src/flock.rs b/compiler/rustc_data_structures/src/flock.rs
index 4f5d8d7..293ef4c 100644
--- a/compiler/rustc_data_structures/src/flock.rs
+++ b/compiler/rustc_data_structures/src/flock.rs
@@ -222,6 +222,10 @@
let msg = "file locks not supported on this platform";
Err(io::Error::new(io::ErrorKind::Other, msg))
}
+
+ pub fn error_unsupported(_err: &io::Error) -> bool {
+ true
+ }
}
}
}
diff --git a/compiler/rustc_data_structures/src/functor.rs b/compiler/rustc_data_structures/src/functor.rs
index fe7a256..5b83ae3 100644
--- a/compiler/rustc_data_structures/src/functor.rs
+++ b/compiler/rustc_data_structures/src/functor.rs
@@ -26,7 +26,7 @@
// inverse of `Box::assume_init()` and should be safe.
let mut raw: Box<mem::MaybeUninit<T>> = Box::from_raw(raw.cast());
// SAFETY: Write the mapped value back into the `Box`.
- ptr::write(raw.as_mut_ptr(), f(value));
+ raw.write(f(value));
// SAFETY: We just initialized `raw`.
raw.assume_init()
}
diff --git a/compiler/rustc_data_structures/src/graph/mod.rs b/compiler/rustc_data_structures/src/graph/mod.rs
index e0903e4..dff2285 100644
--- a/compiler/rustc_data_structures/src/graph/mod.rs
+++ b/compiler/rustc_data_structures/src/graph/mod.rs
@@ -60,18 +60,13 @@
}
pub trait ControlFlowGraph:
- DirectedGraph + WithStartNode + WithPredecessors + WithStartNode + WithSuccessors + WithNumNodes
+ DirectedGraph + WithStartNode + WithPredecessors + WithSuccessors + WithNumNodes
{
// convenient trait
}
impl<T> ControlFlowGraph for T where
- T: DirectedGraph
- + WithStartNode
- + WithPredecessors
- + WithStartNode
- + WithSuccessors
- + WithNumNodes
+ T: DirectedGraph + WithStartNode + WithPredecessors + WithSuccessors + WithNumNodes
{
}
diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs
index 041d52aa..18bc2f8 100644
--- a/compiler/rustc_data_structures/src/lib.rs
+++ b/compiler/rustc_data_structures/src/lib.rs
@@ -21,7 +21,8 @@
#![feature(iter_map_while)]
#![feature(maybe_uninit_uninit_array)]
#![feature(min_specialization)]
-#![feature(min_type_alias_impl_trait)]
+#![cfg_attr(bootstrap, feature(min_type_alias_impl_trait))]
+#![cfg_attr(not(bootstrap), feature(type_alias_impl_trait))]
#![feature(new_uninit)]
#![feature(nll)]
#![feature(once_cell)]
diff --git a/compiler/rustc_data_structures/src/owning_ref/mod.rs b/compiler/rustc_data_structures/src/owning_ref/mod.rs
index ad4b79d..e7397bf 100644
--- a/compiler/rustc_data_structures/src/owning_ref/mod.rs
+++ b/compiler/rustc_data_structures/src/owning_ref/mod.rs
@@ -5,7 +5,7 @@
This crate provides the _owning reference_ types `OwningRef` and `OwningRefMut`
that enables it to bundle a reference together with the owner of the data it points to.
-This allows moving and dropping of a `OwningRef` without needing to recreate the reference.
+This allows moving and dropping of an `OwningRef` without needing to recreate the reference.
This can sometimes be useful because Rust borrowing rules normally prevent
moving a type that has been moved from. For example, this kind of code gets rejected:
@@ -321,7 +321,7 @@
/////////////////////////////////////////////////////////////////////////////
impl<O, T: ?Sized> OwningRef<O, T> {
- /// Creates a new owning reference from a owner
+ /// Creates a new owning reference from an owner
/// initialized to the direct dereference of it.
///
/// # Example
@@ -368,7 +368,7 @@
/// fn main() {
/// let owning_ref = OwningRef::new(Box::new([1, 2, 3, 4]));
///
- /// // create a owning reference that points at the
+ /// // create an owning reference that points at the
/// // third element of the array.
/// let owning_ref = owning_ref.map(|array| &array[2]);
/// assert_eq!(*owning_ref, 3);
@@ -396,7 +396,7 @@
/// fn main() {
/// let owning_ref = OwningRef::new(Box::new([1, 2, 3, 4]));
///
- /// // create a owning reference that points at the
+ /// // create an owning reference that points at the
/// // third element of the array.
/// let owning_ref = owning_ref.try_map(|array| {
/// if array[2] == 3 { Ok(&array[2]) } else { Err(()) }
@@ -430,7 +430,7 @@
/// in an additional `Box<O>`.
///
/// This can be used to safely erase the owner of any `OwningRef<O, T>`
- /// to a `OwningRef<Box<Erased>, T>`.
+ /// to an `OwningRef<Box<Erased>, T>`.
pub fn map_owner_box(self) -> OwningRef<Box<O>, T> {
OwningRef { reference: self.reference, owner: Box::new(self.owner) }
}
@@ -511,7 +511,7 @@
}
impl<O, T: ?Sized> OwningRefMut<O, T> {
- /// Creates a new owning reference from a owner
+ /// Creates a new owning reference from an owner
/// initialized to the direct dereference of it.
///
/// # Example
@@ -558,7 +558,7 @@
/// fn main() {
/// let owning_ref_mut = OwningRefMut::new(Box::new([1, 2, 3, 4]));
///
- /// // create a owning reference that points at the
+ /// // create an owning reference that points at the
/// // third element of the array.
/// let owning_ref = owning_ref_mut.map(|array| &array[2]);
/// assert_eq!(*owning_ref, 3);
@@ -586,7 +586,7 @@
/// fn main() {
/// let owning_ref_mut = OwningRefMut::new(Box::new([1, 2, 3, 4]));
///
- /// // create a owning reference that points at the
+ /// // create an owning reference that points at the
/// // third element of the array.
/// let owning_ref_mut = owning_ref_mut.map_mut(|array| &mut array[2]);
/// assert_eq!(*owning_ref_mut, 3);
@@ -614,7 +614,7 @@
/// fn main() {
/// let owning_ref_mut = OwningRefMut::new(Box::new([1, 2, 3, 4]));
///
- /// // create a owning reference that points at the
+ /// // create an owning reference that points at the
/// // third element of the array.
/// let owning_ref = owning_ref_mut.try_map(|array| {
/// if array[2] == 3 { Ok(&array[2]) } else { Err(()) }
@@ -644,7 +644,7 @@
/// fn main() {
/// let owning_ref_mut = OwningRefMut::new(Box::new([1, 2, 3, 4]));
///
- /// // create a owning reference that points at the
+ /// // create an owning reference that points at the
/// // third element of the array.
/// let owning_ref_mut = owning_ref_mut.try_map_mut(|array| {
/// if array[2] == 3 { Ok(&mut array[2]) } else { Err(()) }
@@ -678,7 +678,7 @@
/// in an additional `Box<O>`.
///
/// This can be used to safely erase the owner of any `OwningRefMut<O, T>`
- /// to a `OwningRefMut<Box<Erased>, T>`.
+ /// to an `OwningRefMut<Box<Erased>, T>`.
pub fn map_owner_box(self) -> OwningRefMut<Box<O>, T> {
OwningRefMut { reference: self.reference, owner: Box::new(self.owner) }
}
@@ -970,7 +970,7 @@
}
}
-// ^ FIXME: Is a Into impl for calling into_inner() possible as well?
+// ^ FIXME: Is an Into impl for calling into_inner() possible as well?
impl<O, T: ?Sized> Debug for OwningRef<O, T>
where
@@ -1139,27 +1139,27 @@
// about which handle creation to use (i.e., read() vs try_read()) as well as
// what to do with error results.
-/// Typedef of a owning reference that uses a `Box` as the owner.
+/// Typedef of an owning reference that uses a `Box` as the owner.
pub type BoxRef<T, U = T> = OwningRef<Box<T>, U>;
-/// Typedef of a owning reference that uses a `Vec` as the owner.
+/// Typedef of an owning reference that uses a `Vec` as the owner.
pub type VecRef<T, U = T> = OwningRef<Vec<T>, U>;
-/// Typedef of a owning reference that uses a `String` as the owner.
+/// Typedef of an owning reference that uses a `String` as the owner.
pub type StringRef = OwningRef<String, str>;
-/// Typedef of a owning reference that uses a `Rc` as the owner.
+/// Typedef of an owning reference that uses an `Rc` as the owner.
pub type RcRef<T, U = T> = OwningRef<Rc<T>, U>;
-/// Typedef of a owning reference that uses a `Arc` as the owner.
+/// Typedef of an owning reference that uses an `Arc` as the owner.
pub type ArcRef<T, U = T> = OwningRef<Arc<T>, U>;
-/// Typedef of a owning reference that uses a `Ref` as the owner.
+/// Typedef of an owning reference that uses a `Ref` as the owner.
pub type RefRef<'a, T, U = T> = OwningRef<Ref<'a, T>, U>;
-/// Typedef of a owning reference that uses a `RefMut` as the owner.
+/// Typedef of an owning reference that uses a `RefMut` as the owner.
pub type RefMutRef<'a, T, U = T> = OwningRef<RefMut<'a, T>, U>;
-/// Typedef of a owning reference that uses a `MutexGuard` as the owner.
+/// Typedef of an owning reference that uses a `MutexGuard` as the owner.
pub type MutexGuardRef<'a, T, U = T> = OwningRef<MutexGuard<'a, T>, U>;
-/// Typedef of a owning reference that uses a `RwLockReadGuard` as the owner.
+/// Typedef of an owning reference that uses an `RwLockReadGuard` as the owner.
pub type RwLockReadGuardRef<'a, T, U = T> = OwningRef<RwLockReadGuard<'a, T>, U>;
-/// Typedef of a owning reference that uses a `RwLockWriteGuard` as the owner.
+/// Typedef of an owning reference that uses an `RwLockWriteGuard` as the owner.
pub type RwLockWriteGuardRef<'a, T, U = T> = OwningRef<RwLockWriteGuard<'a, T>, U>;
/// Typedef of a mutable owning reference that uses a `Box` as the owner.
@@ -1173,7 +1173,7 @@
pub type RefMutRefMut<'a, T, U = T> = OwningRefMut<RefMut<'a, T>, U>;
/// Typedef of a mutable owning reference that uses a `MutexGuard` as the owner.
pub type MutexGuardRefMut<'a, T, U = T> = OwningRefMut<MutexGuard<'a, T>, U>;
-/// Typedef of a mutable owning reference that uses a `RwLockWriteGuard` as the owner.
+/// Typedef of a mutable owning reference that uses an `RwLockWriteGuard` as the owner.
pub type RwLockWriteGuardRefMut<'a, T, U = T> = OwningRef<RwLockWriteGuard<'a, T>, U>;
unsafe impl<'a, T: 'a> IntoErased<'a> for Box<T> {
@@ -1219,11 +1219,11 @@
}
}
-/// Typedef of a owning reference that uses an erased `Box` as the owner.
+/// Typedef of an owning reference that uses an erased `Box` as the owner.
pub type ErasedBoxRef<U> = OwningRef<Box<dyn Erased>, U>;
-/// Typedef of a owning reference that uses an erased `Rc` as the owner.
+/// Typedef of an owning reference that uses an erased `Rc` as the owner.
pub type ErasedRcRef<U> = OwningRef<Rc<dyn Erased>, U>;
-/// Typedef of a owning reference that uses an erased `Arc` as the owner.
+/// Typedef of an owning reference that uses an erased `Arc` as the owner.
pub type ErasedArcRef<U> = OwningRef<Arc<dyn Erased>, U>;
/// Typedef of a mutable owning reference that uses an erased `Box` as the owner.
diff --git a/compiler/rustc_data_structures/src/profiling.rs b/compiler/rustc_data_structures/src/profiling.rs
index ef101c5..0bbd0ed 100644
--- a/compiler/rustc_data_structures/src/profiling.rs
+++ b/compiler/rustc_data_structures/src/profiling.rs
@@ -220,7 +220,7 @@
VerboseTimingGuard::start(message, self.generic_activity(event_label))
}
- /// Start profiling a extra verbose generic activity. Profiling continues until the
+ /// Start profiling an extra verbose generic activity. Profiling continues until the
/// VerboseTimingGuard returned from this call is dropped. In addition to recording
/// a measureme event, "extra verbose" generic activities also print a timing entry to
/// stdout if the compiler is invoked with -Ztime-passes.
diff --git a/compiler/rustc_data_structures/src/sync.rs b/compiler/rustc_data_structures/src/sync.rs
index 722ce6b..f99ca53 100644
--- a/compiler/rustc_data_structures/src/sync.rs
+++ b/compiler/rustc_data_structures/src/sync.rs
@@ -14,7 +14,7 @@
//!
//! `MTRef` is an immutable reference if cfg!(parallel_compiler), and a mutable reference otherwise.
//!
-//! `rustc_erase_owner!` erases a OwningRef owner into Erased or Erased + Send + Sync
+//! `rustc_erase_owner!` erases an OwningRef owner into Erased or Erased + Send + Sync
//! depending on the value of cfg!(parallel_compiler).
use crate::owning_ref::{Erased, OwningRef};
diff --git a/compiler/rustc_data_structures/src/tiny_list.rs b/compiler/rustc_data_structures/src/tiny_list.rs
index f88bcc2..9b07f86 100644
--- a/compiler/rustc_data_structures/src/tiny_list.rs
+++ b/compiler/rustc_data_structures/src/tiny_list.rs
@@ -5,7 +5,7 @@
//!
//! - If you have a list that rarely stores more than one element, then this
//! data-structure can store the element without allocating and only uses as
-//! much space as a `Option<(T, usize)>`. If T can double as the `Option`
+//! much space as an `Option<(T, usize)>`. If T can double as the `Option`
//! discriminant, it will even only be as large as `T, usize`.
//!
//! If you expect to store more than 1 element in the common case, steer clear
diff --git a/compiler/rustc_driver/Cargo.toml b/compiler/rustc_driver/Cargo.toml
index 93c6ec0..5715996 100644
--- a/compiler/rustc_driver/Cargo.toml
+++ b/compiler/rustc_driver/Cargo.toml
@@ -1,5 +1,4 @@
[package]
-authors = ["The Rust Project Developers"]
name = "rustc_driver"
version = "0.0.0"
edition = "2018"
@@ -34,6 +33,7 @@
rustc_serialize = { path = "../rustc_serialize" }
rustc_ast = { path = "../rustc_ast" }
rustc_span = { path = "../rustc_span" }
+rustc_typeck = { path = "../rustc_typeck" }
[target.'cfg(windows)'.dependencies]
winapi = { version = "0.3", features = ["consoleapi", "debugapi", "processenv"] }
diff --git a/compiler/rustc_driver/src/lib.rs b/compiler/rustc_driver/src/lib.rs
index 326fefa..5305332 100644
--- a/compiler/rustc_driver/src/lib.rs
+++ b/compiler/rustc_driver/src/lib.rs
@@ -423,10 +423,10 @@
sess.print_perf_stats();
}
- if sess.print_fuel_crate.is_some() {
+ if sess.opts.debugging_opts.print_fuel.is_some() {
eprintln!(
"Fuel used by {}: {}",
- sess.print_fuel_crate.as_ref().unwrap(),
+ sess.opts.debugging_opts.print_fuel.as_ref().unwrap(),
sess.print_fuel.load(SeqCst)
);
}
@@ -764,13 +764,7 @@
println!("release: {}", unw(util::release_str()));
let debug_flags = matches.opt_strs("Z");
- let backend_name = debug_flags.iter().find_map(|x| {
- if x.starts_with("codegen-backend=") {
- Some(&x["codegen-backends=".len()..])
- } else {
- None
- }
- });
+ let backend_name = debug_flags.iter().find_map(|x| x.strip_prefix("codegen-backend="));
get_codegen_backend(&None, backend_name).print_version();
}
}
@@ -1293,9 +1287,6 @@
.with_indent_lines(true)
.with_ansi(color_logs)
.with_targets(true)
- .with_wraparound(10)
- .with_verbose_exit(true)
- .with_verbose_entry(true)
.with_indent_amount(2);
#[cfg(parallel_compiler)]
let layer = layer.with_thread_ids(true).with_thread_names(true);
diff --git a/compiler/rustc_driver/src/pretty.rs b/compiler/rustc_driver/src/pretty.rs
index bf13191..579ba43 100644
--- a/compiler/rustc_driver/src/pretty.rs
+++ b/compiler/rustc_driver/src/pretty.rs
@@ -14,6 +14,7 @@
use rustc_span::FileName;
use std::cell::Cell;
+use std::fmt::Write;
use std::path::Path;
pub use self::PpMode::*;
@@ -471,7 +472,6 @@
ofile: Option<&Path>,
) -> Result<(), ErrorReported> {
tcx.analysis(())?;
-
let out = match ppm {
Mir => {
let mut out = Vec::new();
@@ -486,8 +486,18 @@
}
ThirTree => {
- // FIXME(rust-lang/project-thir-unsafeck#8)
- todo!()
+ let mut out = String::new();
+ abort_on_err(rustc_typeck::check_crate(tcx), tcx.sess);
+ debug!("pretty printing THIR tree");
+ for did in tcx.body_owners() {
+ let _ = writeln!(
+ out,
+ "{:?}:\n{}\n",
+ did,
+ tcx.thir_tree(ty::WithOptConstParam::unknown(did))
+ );
+ }
+ out
}
_ => unreachable!(),
diff --git a/compiler/rustc_error_codes/Cargo.toml b/compiler/rustc_error_codes/Cargo.toml
index b4c9cd9..270e530 100644
--- a/compiler/rustc_error_codes/Cargo.toml
+++ b/compiler/rustc_error_codes/Cargo.toml
@@ -1,5 +1,4 @@
[package]
-authors = ["The Rust Project Developers"]
name = "rustc_error_codes"
version = "0.0.0"
edition = "2018"
diff --git a/compiler/rustc_error_codes/src/error_codes.rs b/compiler/rustc_error_codes/src/error_codes.rs
index 1aa5f99..45d91c2 100644
--- a/compiler/rustc_error_codes/src/error_codes.rs
+++ b/compiler/rustc_error_codes/src/error_codes.rs
@@ -248,6 +248,7 @@
E0495: include_str!("./error_codes/E0495.md"),
E0496: include_str!("./error_codes/E0496.md"),
E0497: include_str!("./error_codes/E0497.md"),
+E0498: include_str!("./error_codes/E0498.md"),
E0499: include_str!("./error_codes/E0499.md"),
E0500: include_str!("./error_codes/E0500.md"),
E0501: include_str!("./error_codes/E0501.md"),
@@ -287,6 +288,7 @@
E0541: include_str!("./error_codes/E0541.md"),
E0542: include_str!("./error_codes/E0542.md"),
E0543: include_str!("./error_codes/E0543.md"),
+E0544: include_str!("./error_codes/E0544.md"),
E0545: include_str!("./error_codes/E0545.md"),
E0546: include_str!("./error_codes/E0546.md"),
E0547: include_str!("./error_codes/E0547.md"),
@@ -357,6 +359,7 @@
E0622: include_str!("./error_codes/E0622.md"),
E0623: include_str!("./error_codes/E0623.md"),
E0624: include_str!("./error_codes/E0624.md"),
+E0625: include_str!("./error_codes/E0625.md"),
E0626: include_str!("./error_codes/E0626.md"),
E0627: include_str!("./error_codes/E0627.md"),
E0628: include_str!("./error_codes/E0628.md"),
@@ -476,6 +479,8 @@
E0781: include_str!("./error_codes/E0781.md"),
E0782: include_str!("./error_codes/E0782.md"),
E0783: include_str!("./error_codes/E0783.md"),
+E0784: include_str!("./error_codes/E0784.md"),
+E0785: include_str!("./error_codes/E0785.md"),
;
// E0006, // merged with E0005
// E0008, // cannot bind by-move into a pattern guard
@@ -603,14 +608,12 @@
// E0488, // lifetime of variable does not enclose its declaration
// E0489, // type/lifetime parameter not in scope here
E0490, // a value of type `..` is borrowed for too long
- E0498, // malformed plugin attribute
E0514, // metadata version mismatch
E0519, // local crate and dependency have same (crate-name, disambiguator)
// two dependencies have same (crate-name, disambiguator) but different SVH
E0523,
// E0526, // shuffle indices are not constant
// E0540, // multiple rustc_deprecated attributes
- E0544, // multiple stability levels
// E0548, // replaced with a generic attribute input check
// E0553, // multiple rustc_const_unstable attributes
// E0555, // replaced with a generic attribute input check
@@ -622,7 +625,6 @@
// E0611, // merged into E0616
// E0612, // merged into E0609
// E0613, // Removed (merged with E0609)
- E0625, // thread-local statics cannot be accessed at compile-time
// E0629, // missing 'feature' (rustc_const_unstable)
// E0630, // rustc_const_unstable attribute must be paired with stable/unstable
// attribute
@@ -636,7 +638,7 @@
E0711, // a feature has been declared with conflicting stability attributes
E0717, // rustc_promotable without stability attribute
// E0721, // `await` keyword
-// E0723, unstable feature in `const` context
+// E0723, unstable feature in `const` context
E0726, // non-explicit (not `'_`) elided lifetime in unsupported position
// E0738, // Removed; errored on `#[track_caller] fn`s in `extern "Rust" { ... }`.
E0772, // `'static' obligation coming from `impl dyn Trait {}` or `impl Foo for dyn Bar {}`.
diff --git a/compiler/rustc_error_codes/src/error_codes/E0152.md b/compiler/rustc_error_codes/src/error_codes/E0152.md
index 120c96b..ef17b8b 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0152.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0152.md
@@ -6,7 +6,7 @@
#![feature(lang_items)]
#[lang = "owned_box"]
-struct Foo; // error: duplicate lang item found: `owned_box`
+struct Foo<T>(T); // error: duplicate lang item found: `owned_box`
```
Lang items are already implemented in the standard library. Unless you are
diff --git a/compiler/rustc_error_codes/src/error_codes/E0161.md b/compiler/rustc_error_codes/src/error_codes/E0161.md
index c2e2f02..ebd2c97 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0161.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0161.md
@@ -4,11 +4,18 @@
```compile_fail,E0161
#![feature(box_syntax)]
+trait Bar {
+ fn f(self);
+}
+
+impl Bar for i32 {
+ fn f(self) {}
+}
fn main() {
- let array: &[isize] = &[1, 2, 3];
- let _x: Box<[isize]> = box *array;
- // error: cannot move a value of type [isize]: the size of [isize] cannot
+ let b: Box<dyn Bar> = box (0 as i32);
+ b.f();
+ // error: cannot move a value of type dyn Bar: the size of dyn Bar cannot
// be statically determined
}
```
@@ -22,8 +29,17 @@
```
#![feature(box_syntax)]
+trait Bar {
+ fn f(&self);
+}
+
+impl Bar for i32 {
+ fn f(&self) {}
+}
+
fn main() {
- let array: &[isize] = &[1, 2, 3];
- let _x: Box<&[isize]> = box array; // ok!
+ let b: Box<dyn Bar> = box (0 as i32);
+ b.f();
+ // ok!
}
```
diff --git a/compiler/rustc_error_codes/src/error_codes/E0498.md b/compiler/rustc_error_codes/src/error_codes/E0498.md
new file mode 100644
index 0000000..c9ea4a7
--- /dev/null
+++ b/compiler/rustc_error_codes/src/error_codes/E0498.md
@@ -0,0 +1,22 @@
+The `plugin` attribute was malformed.
+
+Erroneous code example:
+
+```compile_fail,E0498
+#![feature(plugin)]
+#![plugin(foo(args))] // error: invalid argument
+#![plugin(bar="test")] // error: invalid argument
+```
+
+The `#[plugin]` attribute should take a single argument: the name of the plugin.
+
+For example, for the plugin `foo`:
+
+```ignore (requires external plugin crate)
+#![feature(plugin)]
+#![plugin(foo)] // ok!
+```
+
+See the [`plugin` feature] section of the Unstable book for more details.
+
+[`plugin` feature]: https://doc.rust-lang.org/nightly/unstable-book/language-features/plugin.html
diff --git a/compiler/rustc_error_codes/src/error_codes/E0530.md b/compiler/rustc_error_codes/src/error_codes/E0530.md
index 502f674..60fa711 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0530.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0530.md
@@ -1,32 +1,57 @@
A binding shadowed something it shouldn't.
-Erroneous code example:
+A match arm or a variable has a name that is already used by
+something else, e.g.
+
+* struct name
+* enum variant
+* static
+* associated constant
+
+This error may also happen when an enum variant *with fields* is used
+in a pattern, but without its fields.
+
+```compile_fail
+enum Enum {
+ WithField(i32)
+}
+
+use Enum::*;
+match WithField(1) {
+ WithField => {} // error: missing (_)
+}
+```
+
+Match bindings cannot shadow statics:
```compile_fail,E0530
static TEST: i32 = 0;
-let r: (i32, i32) = (0, 0);
+let r = 123;
match r {
- TEST => {} // error: match bindings cannot shadow statics
+ TEST => {} // error: name of a static
}
```
-To fix this error, just change the binding's name in order to avoid shadowing
-one of the following:
-
-* struct name
-* struct/enum variant
-* static
-* const
-* associated const
-
-Fixed example:
+Fixed examples:
```
static TEST: i32 = 0;
-let r: (i32, i32) = (0, 0);
+let r = 123;
match r {
- something => {} // ok!
+ some_value => {} // ok!
+}
+```
+
+or
+
+```
+const TEST: i32 = 0; // const, not static
+
+let r = 123;
+match r {
+ TEST => {} // const is ok!
+ other_values => {}
}
```
diff --git a/compiler/rustc_error_codes/src/error_codes/E0544.md b/compiler/rustc_error_codes/src/error_codes/E0544.md
new file mode 100644
index 0000000..2227e2a
--- /dev/null
+++ b/compiler/rustc_error_codes/src/error_codes/E0544.md
@@ -0,0 +1,29 @@
+Multiple stability attributes were declared on the same item.
+
+Erroneous code example:
+
+```compile_fail,E0544
+#![feature(staged_api)]
+#![stable(since = "1.0.0", feature = "rust1")]
+
+#[stable(feature = "rust1", since = "1.0.0")]
+#[stable(feature = "test", since = "2.0.0")] // invalid
+fn foo() {}
+```
+
+To fix this issue, ensure that each item has at most one stability attribute.
+
+```
+#![feature(staged_api)]
+#![stable(since = "1.0.0", feature = "rust1")]
+
+#[stable(feature = "test", since = "2.0.0")] // ok!
+fn foo() {}
+```
+
+See the [How Rust is Made and “Nightly Rust”][how-rust-made-nightly] appendix
+of the Book and the [Stability attributes][stability-attributes] section of the
+Rustc Dev Guide for more details.
+
+[how-rust-made-nightly]: https://doc.rust-lang.org/book/appendix-07-nightly-rust.html
+[stability-attributes]: https://rustc-dev-guide.rust-lang.org/stability.html
diff --git a/compiler/rustc_error_codes/src/error_codes/E0602.md b/compiler/rustc_error_codes/src/error_codes/E0602.md
index dcaf251..7980b70 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0602.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0602.md
@@ -1,4 +1,4 @@
-An unknown lint was used on the command line.
+An unknown or invalid lint was used on the command line.
Erroneous code example:
diff --git a/compiler/rustc_error_codes/src/error_codes/E0617.md b/compiler/rustc_error_codes/src/error_codes/E0617.md
index 1c5d1f8..eed384b 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0617.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0617.md
@@ -3,12 +3,13 @@
Erroneous code example:
```compile_fail,E0617
+# use std::os::raw::{c_char, c_int};
extern "C" {
- fn printf(c: *const i8, ...);
+ fn printf(format: *const c_char, ...) -> c_int;
}
unsafe {
- printf(::std::ptr::null(), 0f32);
+ printf("%f\n\0".as_ptr() as _, 0f32);
// error: cannot pass an `f32` to variadic function, cast to `c_double`
}
```
@@ -21,10 +22,12 @@
In this case, `c_double` has the same size as `f64` so we can use it directly:
```no_run
+# use std::os::raw::{c_char, c_int};
# extern "C" {
-# fn printf(c: *const i8, ...);
+# fn printf(format: *const c_char, ...) -> c_int;
# }
+
unsafe {
- printf(::std::ptr::null(), 0f64); // ok!
+ printf("%f\n\0".as_ptr() as _, 0f64); // ok!
}
```
diff --git a/compiler/rustc_error_codes/src/error_codes/E0625.md b/compiler/rustc_error_codes/src/error_codes/E0625.md
new file mode 100644
index 0000000..7db8577
--- /dev/null
+++ b/compiler/rustc_error_codes/src/error_codes/E0625.md
@@ -0,0 +1,28 @@
+A compile-time const variable is referring to a thread-local static variable.
+
+Erroneous code example:
+
+```compile_fail,E0625
+#![feature(thread_local)]
+
+#[thread_local]
+static X: usize = 12;
+
+const Y: usize = 2 * X;
+```
+
+Static and const variables can refer to other const variables but a const
+variable cannot refer to a thread-local static variable. In this example,
+`Y` cannot refer to `X`. To fix this, the value can be extracted as a const
+and then used:
+
+```
+#![feature(thread_local)]
+
+const C: usize = 12;
+
+#[thread_local]
+static X: usize = C;
+
+const Y: usize = 2 * C;
+```
diff --git a/compiler/rustc_error_codes/src/error_codes/E0633.md b/compiler/rustc_error_codes/src/error_codes/E0633.md
index 4d1f0c4..5b6c15c 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0633.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0633.md
@@ -1,8 +1,10 @@
+#### Note: this error code is no longer emitted by the compiler.
+
The `unwind` attribute was malformed.
Erroneous code example:
-```compile_fail,E0633
+```compile_fail
#![feature(unwind_attributes)]
#[unwind()] // error: expected one argument
diff --git a/compiler/rustc_error_codes/src/error_codes/E0665.md b/compiler/rustc_error_codes/src/error_codes/E0665.md
index a15f402..ae54d6d 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0665.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0665.md
@@ -1,8 +1,10 @@
+#### Note: this error code is no longer emitted by the compiler.
+
The `Default` trait was derived on an enum.
Erroneous code example:
-```compile_fail,E0665
+```compile_fail
#[derive(Default)]
enum Food {
Sweet,
diff --git a/compiler/rustc_error_codes/src/error_codes/E0671.md b/compiler/rustc_error_codes/src/error_codes/E0671.md
index a993ce8..d4dbfb7 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0671.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0671.md
@@ -4,8 +4,6 @@
The following is therefore invalid:
```compile_fail,E0770
-#![feature(const_generics)]
-
fn const_id<T, const N: T>() -> T { // error
N
}
diff --git a/compiler/rustc_error_codes/src/error_codes/E0741.md b/compiler/rustc_error_codes/src/error_codes/E0741.md
index 91379bf..70d963c 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0741.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0741.md
@@ -3,7 +3,7 @@
Erroneous code example:
```compile_fail,E0741
-#![feature(const_generics)]
+#![feature(adt_const_params)]
struct A;
@@ -16,7 +16,7 @@
To fix the previous code example, we derive `PartialEq` and `Eq`:
```
-#![feature(const_generics)]
+#![feature(adt_const_params)]
#[derive(PartialEq, Eq)] // We derive both traits here.
struct A;
diff --git a/compiler/rustc_error_codes/src/error_codes/E0744.md b/compiler/rustc_error_codes/src/error_codes/E0744.md
index 45804ab..9a8ef3b 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0744.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0744.md
@@ -2,25 +2,15 @@
Erroneous code example:
-```compile_fail,E0744
+```compile_fail,edition2018,E0744
const _: i32 = {
- let mut x = 0;
-
- for i in 0..4 { // error!
- x += i;
- }
+ async { 0 }.await
};
```
-At the moment, `for` loops, `.await`, and the `Try` operator (`?`) are forbidden
-inside a `const`, `static`, or `const fn`.
+At the moment, `.await` is forbidden inside a `const`, `static`, or `const fn`.
This may be allowed at some point in the future, but the implementation is not
-yet complete. See the tracking issues for [`async`] and [`?`] in `const fn`, and
-(to support `for` loops in `const fn`) the tracking issues for [`impl const
-Trait for Ty`] and [`&mut T`] in `const fn`.
+yet complete. See the tracking issue for [`async`] in `const fn`.
[`async`]: https://github.com/rust-lang/rust/issues/69431
-[`?`]: https://github.com/rust-lang/rust/issues/74935
-[`impl const Trait for Ty`]: https://github.com/rust-lang/rust/issues/67792
-[`&mut T`]: https://github.com/rust-lang/rust/issues/57349
diff --git a/compiler/rustc_error_codes/src/error_codes/E0770.md b/compiler/rustc_error_codes/src/error_codes/E0770.md
index b39163a..cd8fc48 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0770.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0770.md
@@ -3,7 +3,6 @@
Erroneous code example:
```compile_fail,E0770
-#![feature(const_generics)]
fn foo<T, const N: T>() {} // error!
```
diff --git a/compiler/rustc_error_codes/src/error_codes/E0771.md b/compiler/rustc_error_codes/src/error_codes/E0771.md
index 824a955..a2a1a20 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0771.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0771.md
@@ -4,7 +4,7 @@
Erroneous code example:
```compile_fail,E0771
-#![feature(const_generics)]
+#![feature(adt_const_params)]
fn function_with_str<'a, const STRING: &'a str>() {} // error!
```
@@ -13,7 +13,7 @@
`'static`:
```
-#![feature(const_generics)]
+#![feature(adt_const_params)]
fn function_with_str<const STRING: &'static str>() {} // ok!
```
diff --git a/compiler/rustc_error_codes/src/error_codes/E0784.md b/compiler/rustc_error_codes/src/error_codes/E0784.md
new file mode 100644
index 0000000..b20b703
--- /dev/null
+++ b/compiler/rustc_error_codes/src/error_codes/E0784.md
@@ -0,0 +1,32 @@
+A union expression does not have exactly one field.
+
+Erroneous code example:
+
+```compile_fail,E0784
+union Bird {
+ pigeon: u8,
+ turtledove: u16,
+}
+
+let bird = Bird {}; // error
+let bird = Bird { pigeon: 0, turtledove: 1 }; // error
+```
+
+The key property of unions is that all fields of a union share common storage.
+As a result, writes to one field of a union can overwrite its other fields, and
+size of a union is determined by the size of its largest field.
+
+You can find more information about the union types in the [Rust reference].
+
+Working example:
+
+```
+union Bird {
+ pigeon: u8,
+ turtledove: u16,
+}
+
+let bird = Bird { pigeon: 0 }; // OK
+```
+
+[Rust reference]: https://doc.rust-lang.org/reference/items/unions.html
diff --git a/compiler/rustc_error_codes/src/error_codes/E0785.md b/compiler/rustc_error_codes/src/error_codes/E0785.md
new file mode 100644
index 0000000..3733205
--- /dev/null
+++ b/compiler/rustc_error_codes/src/error_codes/E0785.md
@@ -0,0 +1,30 @@
+An inherent `impl` was written on a dyn auto trait.
+
+Erroneous code example:
+
+```compile_fail,E0785
+#![feature(auto_traits)]
+
+auto trait AutoTrait {}
+
+impl dyn AutoTrait {}
+```
+
+Dyn objects allow any number of auto traits, plus at most one non-auto trait.
+The non-auto trait becomes the "principal trait".
+
+When checking if an impl on a dyn trait is coherent, the principal trait is
+normally the only one considered. Since the erroneous code has no principal
+trait, it cannot be implemented at all.
+
+Working example:
+
+```
+#![feature(auto_traits)]
+
+trait PrincipalTrait {}
+
+auto trait AutoTrait {}
+
+impl dyn PrincipalTrait + AutoTrait + Send {}
+```
diff --git a/compiler/rustc_errors/Cargo.toml b/compiler/rustc_errors/Cargo.toml
index 5d8ff60..c74fd60 100644
--- a/compiler/rustc_errors/Cargo.toml
+++ b/compiler/rustc_errors/Cargo.toml
@@ -1,5 +1,4 @@
[package]
-authors = ["The Rust Project Developers"]
name = "rustc_errors"
version = "0.0.0"
edition = "2018"
diff --git a/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs b/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs
index 2253007..1eb4974 100644
--- a/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs
+++ b/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs
@@ -126,7 +126,7 @@
}
// owned: line source, line index, annotations
type Owned = (String, usize, Vec<crate::snippet::Annotation>);
- let filename = primary_lo.file.name.prefer_local();
+ let filename = source_map.filename_for_diagnostics(&primary_lo.file.name);
let origin = filename.to_string_lossy();
let annotated_files: Vec<Owned> = annotated_files
.into_iter()
diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs
index 45661ac..8199c44 100644
--- a/compiler/rustc_errors/src/diagnostic.rs
+++ b/compiler/rustc_errors/src/diagnostic.rs
@@ -444,6 +444,30 @@
self
}
+ /// Prints out a message with multiple suggested edits of the code.
+ /// See also [`Diagnostic::span_suggestion()`].
+ pub fn multipart_suggestions(
+ &mut self,
+ msg: &str,
+ suggestions: impl Iterator<Item = Vec<(Span, String)>>,
+ applicability: Applicability,
+ ) -> &mut Self {
+ self.suggestions.push(CodeSuggestion {
+ substitutions: suggestions
+ .map(|sugg| Substitution {
+ parts: sugg
+ .into_iter()
+ .map(|(span, snippet)| SubstitutionPart { snippet, span })
+ .collect(),
+ })
+ .collect(),
+ msg: msg.to_owned(),
+ style: SuggestionStyle::ShowCode,
+ applicability,
+ tool_metadata: Default::default(),
+ });
+ self
+ }
/// Prints out a message with a suggested edit of the code. If the suggestion is presented
/// inline, it will only show the message and not the suggestion.
///
diff --git a/compiler/rustc_errors/src/diagnostic_builder.rs b/compiler/rustc_errors/src/diagnostic_builder.rs
index 282877d..d35b292 100644
--- a/compiler/rustc_errors/src/diagnostic_builder.rs
+++ b/compiler/rustc_errors/src/diagnostic_builder.rs
@@ -301,6 +301,20 @@
self
}
+ /// See [`Diagnostic::multipart_suggestions()`].
+ pub fn multipart_suggestions(
+ &mut self,
+ msg: &str,
+ suggestions: impl Iterator<Item = Vec<(Span, String)>>,
+ applicability: Applicability,
+ ) -> &mut Self {
+ if !self.0.allow_suggestions {
+ return self;
+ }
+ self.0.diagnostic.multipart_suggestions(msg, suggestions, applicability);
+ self
+ }
+
/// See [`Diagnostic::span_suggestion_short()`].
pub fn span_suggestion_short(
&mut self,
diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs
index 87272b1..29f352a 100644
--- a/compiler/rustc_errors/src/emitter.rs
+++ b/compiler/rustc_errors/src/emitter.rs
@@ -14,7 +14,10 @@
use crate::snippet::{Annotation, AnnotationType, Line, MultilineAnnotation, Style, StyledString};
use crate::styled_buffer::StyledBuffer;
-use crate::{CodeSuggestion, Diagnostic, DiagnosticId, Level, SubDiagnostic, SuggestionStyle};
+use crate::{
+ CodeSuggestion, Diagnostic, DiagnosticId, Level, SubDiagnostic, SubstitutionHighlight,
+ SuggestionStyle,
+};
use rustc_lint_defs::pluralize;
@@ -954,7 +957,6 @@
// |
for pos in 0..=line_len {
draw_col_separator(buffer, line_offset + pos + 1, width_offset - 2);
- buffer.putc(line_offset + pos + 1, width_offset - 2, '|', Style::LineNumber);
}
// Write the horizontal lines for multiline annotations
@@ -1318,7 +1320,7 @@
buffer_msg_line_offset,
&format!(
"{}:{}:{}",
- loc.file.name.prefer_local(),
+ sm.filename_for_diagnostics(&loc.file.name),
sm.doctest_offset_line(&loc.file.name, loc.line),
loc.col.0 + 1,
),
@@ -1332,7 +1334,7 @@
0,
&format!(
"{}:{}:{}: ",
- loc.file.name.prefer_local(),
+ sm.filename_for_diagnostics(&loc.file.name),
sm.doctest_offset_line(&loc.file.name, loc.line),
loc.col.0 + 1,
),
@@ -1344,7 +1346,11 @@
let buffer_msg_line_offset = buffer.num_lines();
// Add spacing line
- draw_col_separator(&mut buffer, buffer_msg_line_offset, max_line_num_len + 1);
+ draw_col_separator_no_space(
+ &mut buffer,
+ buffer_msg_line_offset,
+ max_line_num_len + 1,
+ );
// Then, the secondary file indicator
buffer.prepend(buffer_msg_line_offset + 1, "::: ", Style::LineNumber);
@@ -1356,12 +1362,12 @@
};
format!(
"{}:{}{}",
- annotated_file.file.name.prefer_local(),
+ sm.filename_for_diagnostics(&annotated_file.file.name),
sm.doctest_offset_line(&annotated_file.file.name, first_line.line_index),
col
)
} else {
- format!("{}", annotated_file.file.name.prefer_local())
+ format!("{}", sm.filename_for_diagnostics(&annotated_file.file.name))
};
buffer.append(buffer_msg_line_offset + 1, &loc, Style::LineAndColumn);
for _ in 0..max_line_num_len {
@@ -1587,8 +1593,11 @@
);
let mut row_num = 2;
+ draw_col_separator_no_space(&mut buffer, 1, max_line_num_len + 1);
let mut notice_capitalization = false;
- for (complete, parts, only_capitalization) in suggestions.iter().take(MAX_SUGGESTIONS) {
+ for (complete, parts, highlights, only_capitalization) in
+ suggestions.iter().take(MAX_SUGGESTIONS)
+ {
notice_capitalization |= only_capitalization;
// Only show underline if the suggestion spans a single line and doesn't cover the
// entirety of the code output. If you have multiple replacements in the same line
@@ -1596,16 +1605,26 @@
let show_underline = !(parts.len() == 1 && parts[0].snippet.trim() == complete.trim())
&& complete.lines().count() == 1;
- let lines = sm
+ let has_deletion = parts.iter().any(|p| p.is_deletion());
+ let is_multiline = complete.lines().count() > 1;
+
+ let show_diff = has_deletion && !is_multiline;
+
+ if show_diff {
+ row_num += 1;
+ }
+
+ let file_lines = sm
.span_to_lines(parts[0].span)
.expect("span_to_lines failed when emitting suggestion");
- assert!(!lines.lines.is_empty() || parts[0].span.is_dummy());
+ assert!(!file_lines.lines.is_empty() || parts[0].span.is_dummy());
let line_start = sm.lookup_char_pos(parts[0].span.lo()).line;
draw_col_separator_no_space(&mut buffer, 1, max_line_num_len + 1);
let mut lines = complete.lines();
- for (line_pos, line) in lines.by_ref().take(MAX_SUGGESTION_HIGHLIGHT_LINES).enumerate()
+ for (line_pos, (line, highlight_parts)) in
+ lines.by_ref().zip(highlights).take(MAX_SUGGESTION_HIGHLIGHT_LINES).enumerate()
{
// Print the span column to avoid confusion
buffer.puts(
@@ -1614,9 +1633,68 @@
&self.maybe_anonymized(line_start + line_pos),
Style::LineNumber,
);
+ if show_diff {
+ // Add the line number for both addition and removal to drive the point home.
+ //
+ // N - fn foo<A: T>(bar: A) {
+ // N + fn foo(bar: impl T) {
+ buffer.puts(
+ row_num - 1,
+ 0,
+ &self.maybe_anonymized(line_start + line_pos),
+ Style::LineNumber,
+ );
+ buffer.puts(row_num - 1, max_line_num_len + 1, "- ", Style::Removal);
+ buffer.puts(
+ row_num - 1,
+ max_line_num_len + 3,
+ &replace_tabs(
+ &*file_lines
+ .file
+ .get_line(file_lines.lines[line_pos].line_index)
+ .unwrap(),
+ ),
+ Style::NoStyle,
+ );
+ buffer.puts(row_num, max_line_num_len + 1, "+ ", Style::Addition);
+ } else if is_multiline {
+ match &highlight_parts[..] {
+ [SubstitutionHighlight { start: 0, end }] if *end == line.len() => {
+ buffer.puts(row_num, max_line_num_len + 1, "+ ", Style::Addition);
+ }
+ [] => {
+ draw_col_separator(&mut buffer, row_num, max_line_num_len + 1);
+ }
+ _ => {
+ buffer.puts(row_num, max_line_num_len + 1, "~ ", Style::Addition);
+ }
+ }
+ } else {
+ draw_col_separator(&mut buffer, row_num, max_line_num_len + 1);
+ }
+
// print the suggestion
- draw_col_separator(&mut buffer, row_num, max_line_num_len + 1);
buffer.append(row_num, &replace_tabs(line), Style::NoStyle);
+
+ // Colorize addition/replacements with green.
+ for &SubstitutionHighlight { start, end } in highlight_parts {
+ // Account for tabs when highlighting (#87972).
+ let tabs: usize = line
+ .chars()
+ .take(start)
+ .map(|ch| match ch {
+ '\t' => 3,
+ _ => 0,
+ })
+ .sum();
+ buffer.set_style_range(
+ row_num,
+ max_line_num_len + 3 + start + tabs,
+ max_line_num_len + 3 + end + tabs,
+ Style::Addition,
+ true,
+ );
+ }
row_num += 1;
}
@@ -1651,25 +1729,29 @@
let underline_start = (span_start_pos + start) as isize + offset;
let underline_end = (span_start_pos + start + sub_len) as isize + offset;
assert!(underline_start >= 0 && underline_end >= 0);
+ let padding: usize = max_line_num_len + 3;
for p in underline_start..underline_end {
- buffer.putc(
- row_num,
- ((max_line_num_len + 3) as isize + p) as usize,
- '^',
- Style::UnderlinePrimary,
- );
- }
- // underline removals too
- if underline_start == underline_end {
- for p in underline_start - 1..underline_start + 1 {
+ if !show_diff {
+ // If this is a replacement, underline with `^`, if this is an addition
+ // underline with `+`.
buffer.putc(
row_num,
- ((max_line_num_len + 3) as isize + p) as usize,
- '-',
- Style::UnderlineSecondary,
+ (padding as isize + p) as usize,
+ if part.is_addition(&sm) { '+' } else { '~' },
+ Style::Addition,
);
}
}
+ if show_diff {
+ // Colorize removal with red in diff format.
+ buffer.set_style_range(
+ row_num - 2,
+ (padding as isize + span_start_pos as isize) as usize,
+ (padding as isize + span_end_pos as isize) as usize,
+ Style::Removal,
+ true,
+ );
+ }
// length of the code after substitution
let full_sub_len = part
@@ -2126,6 +2208,12 @@
fn apply_style(&mut self, lvl: Level, style: Style) -> io::Result<()> {
let mut spec = ColorSpec::new();
match style {
+ Style::Addition => {
+ spec.set_fg(Some(Color::Green)).set_intense(true);
+ }
+ Style::Removal => {
+ spec.set_fg(Some(Color::Red)).set_intense(true);
+ }
Style::LineAndColumn => {}
Style::LineNumber => {
spec.set_bold(true);
diff --git a/compiler/rustc_errors/src/json.rs b/compiler/rustc_errors/src/json.rs
index 1b6cd04..dde978c 100644
--- a/compiler/rustc_errors/src/json.rs
+++ b/compiler/rustc_errors/src/json.rs
@@ -464,7 +464,7 @@
});
DiagnosticSpan {
- file_name: start.file.name.prefer_local().to_string(),
+ file_name: je.sm.filename_for_diagnostics(&start.file.name).to_string(),
byte_start: start.file.original_relative_byte_pos(span.lo()).0,
byte_end: start.file.original_relative_byte_pos(span.hi()).0,
line_start: start.line,
diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs
index 993a7c2..02b6179 100644
--- a/compiler/rustc_errors/src/lib.rs
+++ b/compiler/rustc_errors/src/lib.rs
@@ -5,9 +5,11 @@
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
#![feature(crate_visibility_modifier)]
#![feature(backtrace)]
+#![feature(if_let_guard)]
#![feature(format_args_capture)]
#![feature(iter_zip)]
#![feature(nll)]
+#![cfg_attr(bootstrap, allow(incomplete_features))] // if_let_guard
#[macro_use]
extern crate rustc_macros;
@@ -160,32 +162,77 @@
pub snippet: String,
}
+/// Used to translate between `Span`s and byte positions within a single output line in highlighted
+/// code of structured suggestions.
+#[derive(Debug, Clone, Copy)]
+pub struct SubstitutionHighlight {
+ start: usize,
+ end: usize,
+}
+
+impl SubstitutionPart {
+ pub fn is_addition(&self, sm: &SourceMap) -> bool {
+ !self.snippet.is_empty()
+ && sm
+ .span_to_snippet(self.span)
+ .map_or(self.span.is_empty(), |snippet| snippet.trim().is_empty())
+ }
+
+ pub fn is_deletion(&self) -> bool {
+ self.snippet.trim().is_empty()
+ }
+
+ pub fn is_replacement(&self, sm: &SourceMap) -> bool {
+ !self.snippet.is_empty()
+ && sm
+ .span_to_snippet(self.span)
+ .map_or(!self.span.is_empty(), |snippet| !snippet.trim().is_empty())
+ }
+}
+
impl CodeSuggestion {
/// Returns the assembled code suggestions, whether they should be shown with an underline
/// and whether the substitution only differs in capitalization.
- pub fn splice_lines(&self, sm: &SourceMap) -> Vec<(String, Vec<SubstitutionPart>, bool)> {
+ pub fn splice_lines(
+ &self,
+ sm: &SourceMap,
+ ) -> Vec<(String, Vec<SubstitutionPart>, Vec<Vec<SubstitutionHighlight>>, bool)> {
+ // For the `Vec<Vec<SubstitutionHighlight>>` value, the first level of the vector
+ // corresponds to the output snippet's lines, while the second level corresponds to the
+ // substrings within that line that should be highlighted.
+
use rustc_span::{CharPos, Pos};
+ /// Append to a buffer the remainder of the line of existing source code, and return the
+ /// count of lines that have been added for accurate highlighting.
fn push_trailing(
buf: &mut String,
line_opt: Option<&Cow<'_, str>>,
lo: &Loc,
hi_opt: Option<&Loc>,
- ) {
+ ) -> usize {
+ let mut line_count = 0;
let (lo, hi_opt) = (lo.col.to_usize(), hi_opt.map(|hi| hi.col.to_usize()));
if let Some(line) = line_opt {
if let Some(lo) = line.char_indices().map(|(i, _)| i).nth(lo) {
let hi_opt = hi_opt.and_then(|hi| line.char_indices().map(|(i, _)| i).nth(hi));
match hi_opt {
- Some(hi) if hi > lo => buf.push_str(&line[lo..hi]),
+ Some(hi) if hi > lo => {
+ line_count = line[lo..hi].matches('\n').count();
+ buf.push_str(&line[lo..hi])
+ }
Some(_) => (),
- None => buf.push_str(&line[lo..]),
+ None => {
+ line_count = line[lo..].matches('\n').count();
+ buf.push_str(&line[lo..])
+ }
}
}
if hi_opt.is_none() {
buf.push('\n');
}
}
+ line_count
}
assert!(!self.substitutions.is_empty());
@@ -220,6 +267,7 @@
return None;
}
+ let mut highlights = vec![];
// To build up the result, we do this for each span:
// - push the line segment trailing the previous span
// (at the beginning a "phantom" span pointing at the start of the line)
@@ -236,17 +284,34 @@
lines.lines.get(0).and_then(|line0| sf.get_line(line0.line_index));
let mut buf = String::new();
+ let mut line_highlight = vec![];
+ // We need to keep track of the difference between the existing code and the added
+ // or deleted code in order to point at the correct column *after* substitution.
+ let mut acc = 0;
for part in &substitution.parts {
let cur_lo = sm.lookup_char_pos(part.span.lo());
if prev_hi.line == cur_lo.line {
- push_trailing(&mut buf, prev_line.as_ref(), &prev_hi, Some(&cur_lo));
+ let mut count =
+ push_trailing(&mut buf, prev_line.as_ref(), &prev_hi, Some(&cur_lo));
+ while count > 0 {
+ highlights.push(std::mem::take(&mut line_highlight));
+ acc = 0;
+ count -= 1;
+ }
} else {
- push_trailing(&mut buf, prev_line.as_ref(), &prev_hi, None);
+ acc = 0;
+ highlights.push(std::mem::take(&mut line_highlight));
+ let mut count = push_trailing(&mut buf, prev_line.as_ref(), &prev_hi, None);
+ while count > 0 {
+ highlights.push(std::mem::take(&mut line_highlight));
+ count -= 1;
+ }
// push lines between the previous and current span (if any)
for idx in prev_hi.line..(cur_lo.line - 1) {
if let Some(line) = sf.get_line(idx) {
buf.push_str(line.as_ref());
buf.push('\n');
+ highlights.push(std::mem::take(&mut line_highlight));
}
}
if let Some(cur_line) = sf.get_line(cur_lo.line - 1) {
@@ -257,10 +322,46 @@
buf.push_str(&cur_line[..end]);
}
}
+ // Add a whole line highlight per line in the snippet.
+ let len: isize = part
+ .snippet
+ .split('\n')
+ .next()
+ .unwrap_or(&part.snippet)
+ .chars()
+ .map(|c| match c {
+ '\t' => 4,
+ _ => 1,
+ })
+ .sum();
+ line_highlight.push(SubstitutionHighlight {
+ start: (cur_lo.col.0 as isize + acc) as usize,
+ end: (cur_lo.col.0 as isize + acc + len) as usize,
+ });
buf.push_str(&part.snippet);
- prev_hi = sm.lookup_char_pos(part.span.hi());
+ let cur_hi = sm.lookup_char_pos(part.span.hi());
+ if prev_hi.line == cur_lo.line {
+ // Account for the difference between the width of the current code and the
+ // snippet being suggested, so that the *later* suggestions are correctly
+ // aligned on the screen.
+ acc += len as isize - (cur_hi.col.0 - cur_lo.col.0) as isize;
+ }
+ prev_hi = cur_hi;
prev_line = sf.get_line(prev_hi.line - 1);
+ for line in part.snippet.split('\n').skip(1) {
+ acc = 0;
+ highlights.push(std::mem::take(&mut line_highlight));
+ let end: usize = line
+ .chars()
+ .map(|c| match c {
+ '\t' => 4,
+ _ => 1,
+ })
+ .sum();
+ line_highlight.push(SubstitutionHighlight { start: 0, end });
+ }
}
+ highlights.push(std::mem::take(&mut line_highlight));
let only_capitalization = is_case_difference(sm, &buf, bounding_span);
// if the replacement already ends with a newline, don't print the next line
if !buf.ends_with('\n') {
@@ -270,7 +371,7 @@
while buf.ends_with('\n') {
buf.pop();
}
- Some((buf, substitution.parts, only_capitalization))
+ Some((buf, substitution.parts, highlights, only_capitalization))
})
.collect()
}
@@ -342,6 +443,9 @@
deduplicated_warn_count: usize,
future_breakage_diagnostics: Vec<Diagnostic>,
+
+ /// If set to `true`, no warning or error will be emitted.
+ quiet: bool,
}
/// A key denoting where from a diagnostic was stashed.
@@ -456,10 +560,19 @@
emitted_diagnostics: Default::default(),
stashed_diagnostics: Default::default(),
future_breakage_diagnostics: Vec::new(),
+ quiet: false,
}),
}
}
+ pub fn with_disabled_diagnostic<T, F: FnOnce() -> T>(&self, f: F) -> T {
+ let prev = self.inner.borrow_mut().quiet;
+ self.inner.borrow_mut().quiet = true;
+ let ret = f();
+ self.inner.borrow_mut().quiet = prev;
+ ret
+ }
+
// This is here to not allow mutation of flags;
// as of this writing it's only used in tests in librustc_middle.
pub fn can_emit_warnings(&self) -> bool {
@@ -818,7 +931,7 @@
}
fn emit_diagnostic(&mut self, diagnostic: &Diagnostic) {
- if diagnostic.cancelled() {
+ if diagnostic.cancelled() || self.quiet {
return;
}
@@ -916,15 +1029,15 @@
let mut error_codes = self
.emitted_diagnostic_codes
.iter()
- .filter_map(|x| match &x {
- DiagnosticId::Error(s) => {
- if let Ok(Some(_explanation)) = registry.try_find_description(s) {
- Some(s.clone())
- } else {
- None
- }
+ .filter_map(|x| {
+ match &x {
+ DiagnosticId::Error(s)
+ if let Ok(Some(_explanation)) = registry.try_find_description(s) =>
+ {
+ Some(s.clone())
}
_ => None,
+ }
})
.collect::<Vec<_>>();
if !error_codes.is_empty() {
@@ -1035,6 +1148,9 @@
}
fn delay_as_bug(&mut self, diagnostic: Diagnostic) {
+ if self.quiet {
+ return;
+ }
if self.flags.report_delayed_bugs {
self.emit_diagnostic(&diagnostic);
}
diff --git a/compiler/rustc_errors/src/snippet.rs b/compiler/rustc_errors/src/snippet.rs
index 3fe02bd..6435346 100644
--- a/compiler/rustc_errors/src/snippet.rs
+++ b/compiler/rustc_errors/src/snippet.rs
@@ -177,4 +177,6 @@
NoStyle,
Level(Level),
Highlight,
+ Addition,
+ Removal,
}
diff --git a/compiler/rustc_expand/Cargo.toml b/compiler/rustc_expand/Cargo.toml
index 59c1604e..1be9321 100644
--- a/compiler/rustc_expand/Cargo.toml
+++ b/compiler/rustc_expand/Cargo.toml
@@ -1,5 +1,4 @@
[package]
-authors = ["The Rust Project Developers"]
name = "rustc_expand"
version = "0.0.0"
edition = "2018"
diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs
index 8c6aef8..35df8aa 100644
--- a/compiler/rustc_expand/src/base.rs
+++ b/compiler/rustc_expand/src/base.rs
@@ -1,6 +1,7 @@
use crate::expand::{self, AstFragment, Invocation};
use crate::module::DirOwnership;
+use rustc_ast::attr::MarkedAttrs;
use rustc_ast::ptr::P;
use rustc_ast::token::{self, Nonterminal};
use rustc_ast::tokenstream::{CanSynthesizeMissingTokens, TokenStream};
@@ -353,6 +354,7 @@
fn make_expr(self: Box<Self>) -> Option<P<ast::Expr>> {
None
}
+
/// Creates zero or more items.
fn make_items(self: Box<Self>) -> Option<SmallVec<[P<ast::Item>; 1]>> {
None
@@ -652,10 +654,7 @@
/// A trivial attribute "macro" that does nothing,
/// only keeps the attribute and marks it as inert,
/// thus making it ineligible for further expansion.
- NonMacroAttr {
- /// Suppresses the `unused_attributes` lint for this attribute.
- mark_used: bool,
- },
+ NonMacroAttr,
/// A token-based derive macro.
Derive(
@@ -704,7 +703,7 @@
SyntaxExtensionKind::Bang(..) | SyntaxExtensionKind::LegacyBang(..) => MacroKind::Bang,
SyntaxExtensionKind::Attr(..)
| SyntaxExtensionKind::LegacyAttr(..)
- | SyntaxExtensionKind::NonMacroAttr { .. } => MacroKind::Attr,
+ | SyntaxExtensionKind::NonMacroAttr => MacroKind::Attr,
SyntaxExtensionKind::Derive(..) | SyntaxExtensionKind::LegacyDerive(..) => {
MacroKind::Derive
}
@@ -810,8 +809,8 @@
SyntaxExtension::default(SyntaxExtensionKind::Derive(Box::new(expander)), edition)
}
- pub fn non_macro_attr(mark_used: bool, edition: Edition) -> SyntaxExtension {
- SyntaxExtension::default(SyntaxExtensionKind::NonMacroAttr { mark_used }, edition)
+ pub fn non_macro_attr(edition: Edition) -> SyntaxExtension {
+ SyntaxExtension::default(SyntaxExtensionKind::NonMacroAttr, edition)
}
pub fn expn_data(
@@ -895,6 +894,14 @@
/// Decodes the proc-macro quoted span in the specified crate, with the specified id.
/// No caching is performed.
fn get_proc_macro_quoted_span(&self, krate: CrateNum, id: usize) -> Span;
+
+ /// The order of items in the HIR is unrelated to the order of
+ /// items in the AST. However, we generate proc macro harnesses
+ /// based on the AST order, and later refer to these harnesses
+ /// from the HIR. This field keeps track of the order in which
+ /// we generated proc macros harnesses, so that we can map
+ /// HIR proc macros items back to their harness items.
+ fn declare_proc_macro(&mut self, id: NodeId);
}
#[derive(Clone, Default)]
@@ -928,6 +935,7 @@
pub prior_type_ascription: Option<(Span, bool)>,
/// Some parent node that is close to this macro call
pub lint_node_id: NodeId,
+ pub is_trailing_mac: bool,
}
type OnExternModLoaded<'a> =
@@ -951,6 +959,10 @@
///
/// `Ident` is the module name.
pub(super) extern_mod_loaded: OnExternModLoaded<'a>,
+ /// When we 'expand' an inert attribute, we leave it
+ /// in the AST, but insert it here so that we know
+ /// not to expand it again.
+ pub(super) expanded_inert_attrs: MarkedAttrs,
}
impl<'a> ExtCtxt<'a> {
@@ -974,9 +986,11 @@
dir_ownership: DirOwnership::Owned { relative: None },
prior_type_ascription: None,
lint_node_id: ast::CRATE_NODE_ID,
+ is_trailing_mac: false,
},
force_mode: false,
expansions: FxHashMap::default(),
+ expanded_inert_attrs: MarkedAttrs::new(),
}
}
@@ -1107,7 +1121,7 @@
span,
&format!(
"cannot resolve relative path in non-file source `{}`",
- other.prefer_local()
+ self.source_map().filename_for_diagnostics(&other)
),
));
}
diff --git a/compiler/rustc_expand/src/build.rs b/compiler/rustc_expand/src/build.rs
index 824df27..2cc15b3 100644
--- a/compiler/rustc_expand/src/build.rs
+++ b/compiler/rustc_expand/src/build.rs
@@ -2,7 +2,7 @@
use rustc_ast::attr;
use rustc_ast::ptr::P;
-use rustc_ast::{self as ast, AttrVec, BlockCheckMode, Expr, PatKind, UnOp};
+use rustc_ast::{self as ast, AttrVec, BlockCheckMode, Expr, LocalKind, PatKind, UnOp};
use rustc_span::source_map::Spanned;
use rustc_span::symbol::{kw, sym, Ident, Symbol};
@@ -153,8 +153,8 @@
let local = P(ast::Local {
pat,
ty: None,
- init: Some(ex),
id: ast::DUMMY_NODE_ID,
+ kind: LocalKind::Init(ex),
span: sp,
attrs: AttrVec::new(),
tokens: None,
@@ -167,8 +167,8 @@
let local = P(ast::Local {
pat: self.pat_wild(span),
ty: Some(ty),
- init: None,
id: ast::DUMMY_NODE_ID,
+ kind: LocalKind::Decl,
span,
attrs: AttrVec::new(),
tokens: None,
@@ -197,6 +197,7 @@
rules: BlockCheckMode::Default,
span,
tokens: None,
+ could_be_bare_literal: false,
})
}
diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs
index f914060..38c099f 100644
--- a/compiler/rustc_expand/src/config.rs
+++ b/compiler/rustc_expand/src/config.rs
@@ -5,7 +5,7 @@
use rustc_ast::tokenstream::{AttrAnnotatedTokenStream, AttrAnnotatedTokenTree};
use rustc_ast::tokenstream::{DelimSpan, Spacing};
use rustc_ast::tokenstream::{LazyTokenStream, TokenTree};
-use rustc_ast::{self as ast, AstLike, AttrItem, AttrStyle, Attribute, MetaItem};
+use rustc_ast::{self as ast, AstLike, AttrStyle, Attribute, MetaItem};
use rustc_attr as attr;
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::map_in_place::MapInPlace;
@@ -14,7 +14,7 @@
use rustc_feature::{
ACCEPTED_FEATURES, ACTIVE_FEATURES, REMOVED_FEATURES, STABLE_REMOVED_FEATURES,
};
-use rustc_parse::{parse_in, validate_attr};
+use rustc_parse::validate_attr;
use rustc_session::parse::feature_err;
use rustc_session::Session;
use rustc_span::edition::{Edition, ALL_EDITIONS};
@@ -75,7 +75,7 @@
// Process the edition umbrella feature-gates first, to ensure
// `edition_enabled_features` is completed before it's queried.
for attr in krate_attrs {
- if !sess.check_name(attr, sym::feature) {
+ if !attr.has_name(sym::feature) {
continue;
}
@@ -108,7 +108,7 @@
}
for attr in krate_attrs {
- if !sess.check_name(attr, sym::feature) {
+ if !attr.has_name(sym::feature) {
continue;
}
@@ -237,11 +237,6 @@
};
}
-const CFG_ATTR_GRAMMAR_HELP: &str = "#[cfg_attr(condition, attribute, other_attribute, ...)]";
-const CFG_ATTR_NOTE_REF: &str = "for more information, visit \
- <https://doc.rust-lang.org/reference/conditional-compilation.html\
- #the-cfg_attr-attribute>";
-
impl<'a> StripUnconfigured<'a> {
pub fn configure<T: AstLike>(&mut self, mut node: T) -> Option<T> {
self.process_cfg_attrs(&mut node);
@@ -310,15 +305,14 @@
Some((AttrAnnotatedTokenTree::Delimited(sp, delim, inner), *spacing))
.into_iter()
}
+ AttrAnnotatedTokenTree::Token(ref token) if let TokenKind::Interpolated(ref nt) = token.kind => {
+ panic!(
+ "Nonterminal should have been flattened at {:?}: {:?}",
+ token.span, nt
+ );
+ }
AttrAnnotatedTokenTree::Token(token) => {
- if let TokenKind::Interpolated(nt) = token.kind {
- panic!(
- "Nonterminal should have been flattened at {:?}: {:?}",
- token.span, nt
- );
- } else {
- Some((AttrAnnotatedTokenTree::Token(token), *spacing)).into_iter()
- }
+ Some((AttrAnnotatedTokenTree::Token(token), *spacing)).into_iter()
}
})
.collect();
@@ -349,19 +343,17 @@
return vec![attr];
}
- let (cfg_predicate, expanded_attrs) = match self.parse_cfg_attr(&attr) {
- None => return vec![],
- Some(r) => r,
- };
+ let (cfg_predicate, expanded_attrs) =
+ match rustc_parse::parse_cfg_attr(&attr, &self.sess.parse_sess) {
+ None => return vec![],
+ Some(r) => r,
+ };
// Lint on zero attributes in source.
if expanded_attrs.is_empty() {
return vec![attr];
}
- // At this point we know the attribute is considered used.
- self.sess.mark_attr_used(&attr);
-
if !attr::cfg_matches(&cfg_predicate, &self.sess.parse_sess, self.features) {
return vec![];
}
@@ -415,46 +407,10 @@
.collect()
}
- fn parse_cfg_attr(&self, attr: &Attribute) -> Option<(MetaItem, Vec<(AttrItem, Span)>)> {
- match attr.get_normal_item().args {
- ast::MacArgs::Delimited(dspan, delim, ref tts) if !tts.is_empty() => {
- let msg = "wrong `cfg_attr` delimiters";
- validate_attr::check_meta_bad_delim(&self.sess.parse_sess, dspan, delim, msg);
- match parse_in(&self.sess.parse_sess, tts.clone(), "`cfg_attr` input", |p| {
- p.parse_cfg_attr()
- }) {
- Ok(r) => return Some(r),
- Err(mut e) => {
- e.help(&format!("the valid syntax is `{}`", CFG_ATTR_GRAMMAR_HELP))
- .note(CFG_ATTR_NOTE_REF)
- .emit();
- }
- }
- }
- _ => self.error_malformed_cfg_attr_missing(attr.span),
- }
- None
- }
-
- fn error_malformed_cfg_attr_missing(&self, span: Span) {
- self.sess
- .parse_sess
- .span_diagnostic
- .struct_span_err(span, "malformed `cfg_attr` attribute input")
- .span_suggestion(
- span,
- "missing condition and attribute",
- CFG_ATTR_GRAMMAR_HELP.to_string(),
- Applicability::HasPlaceholders,
- )
- .note(CFG_ATTR_NOTE_REF)
- .emit();
- }
-
/// Determines if a node with the given attributes should be included in this configuration.
fn in_cfg(&self, attrs: &[Attribute]) -> bool {
attrs.iter().all(|attr| {
- if !is_cfg(self.sess, attr) {
+ if !is_cfg(attr) {
return true;
}
let meta_item = match validate_attr::parse_meta(&self.sess.parse_sess, attr) {
@@ -500,7 +456,7 @@
//
// N.B., this is intentionally not part of the visit_expr() function
// in order for filter_map_expr() to be able to avoid this check
- if let Some(attr) = expr.attrs().iter().find(|a| is_cfg(self.sess, a)) {
+ if let Some(attr) = expr.attrs().iter().find(|a| is_cfg(*a)) {
let msg = "removing an expression is not supported in this position";
self.sess.parse_sess.span_diagnostic.span_err(attr.span, msg);
}
@@ -536,6 +492,6 @@
}
}
-fn is_cfg(sess: &Session, attr: &Attribute) -> bool {
- sess.check_name(attr, sym::cfg)
+fn is_cfg(attr: &Attribute) -> bool {
+ attr.has_name(sym::cfg)
}
diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs
index dcd871c..48ad7be 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::{AstLike, Block, Inline, ItemKind, Local, MacArgs};
+use rustc_ast::{AstLike, Block, Inline, ItemKind, MacArgs, MacCall};
use rustc_ast::{MacCallStmt, MacStmtStyle, MetaItemKind, ModKind, NestedMetaItem};
use rustc_ast::{NodeId, PatKind, Path, StmtKind, Unsafe};
use rustc_ast_pretty::pprust;
@@ -26,7 +26,7 @@
AttemptLocalParseRecovery, ForceCollect, Parser, RecoverColon, RecoverComma,
};
use rustc_parse::validate_attr;
-use rustc_session::lint::builtin::UNUSED_DOC_COMMENTS;
+use rustc_session::lint::builtin::{UNUSED_ATTRIBUTES, UNUSED_DOC_COMMENTS};
use rustc_session::lint::BuiltinLintDiagnostics;
use rustc_session::parse::{feature_err, ParseSess};
use rustc_session::Limit;
@@ -559,7 +559,7 @@
self.cx.force_mode = orig_force_mode;
// Finally incorporate all the expanded macros into the input AST fragment.
- let mut placeholder_expander = PlaceholderExpander::new(self.cx, self.monotonic);
+ let mut placeholder_expander = PlaceholderExpander::default();
while let Some(expanded_fragments) = expanded_fragments.pop() {
for (expn_id, expanded_fragment) in expanded_fragments.into_iter().rev() {
placeholder_expander
@@ -753,11 +753,8 @@
}
}
}
- SyntaxExtensionKind::NonMacroAttr { mark_used } => {
- self.cx.sess.mark_attr_known(&attr);
- if *mark_used {
- self.cx.sess.mark_attr_used(&attr);
- }
+ SyntaxExtensionKind::NonMacroAttr => {
+ self.cx.expanded_inert_attrs.mark(&attr);
item.visit_attrs(|attrs| attrs.insert(pos, attr));
fragment_kind.expect_from_annotatables(iter::once(item))
}
@@ -1040,7 +1037,7 @@
item.visit_attrs(|attrs| {
attr = attrs
.iter()
- .position(|a| !self.cx.sess.is_attr_known(a) && !is_builtin_attr(a))
+ .position(|a| !self.cx.expanded_inert_attrs.is_marked(a) && !is_builtin_attr(a))
.map(|attr_pos| {
let attr = attrs.remove(attr_pos);
let following_derives = attrs[attr_pos..]
@@ -1064,13 +1061,51 @@
attr
}
+ fn take_stmt_bang(
+ &mut self,
+ stmt: ast::Stmt,
+ ) -> Result<(bool, MacCall, Vec<ast::Attribute>), ast::Stmt> {
+ match stmt.kind {
+ StmtKind::MacCall(mac) => {
+ let MacCallStmt { mac, style, attrs, .. } = mac.into_inner();
+ Ok((style == MacStmtStyle::Semicolon, mac, attrs.into()))
+ }
+ StmtKind::Item(ref item) if matches!(item.kind, ItemKind::MacCall(..)) => {
+ match stmt.kind {
+ StmtKind::Item(item) => match item.into_inner() {
+ ast::Item { kind: ItemKind::MacCall(mac), attrs, .. } => {
+ Ok((mac.args.need_semicolon(), mac, attrs))
+ }
+ _ => unreachable!(),
+ },
+ _ => unreachable!(),
+ }
+ }
+ StmtKind::Semi(ref expr) if matches!(expr.kind, ast::ExprKind::MacCall(..)) => {
+ match stmt.kind {
+ StmtKind::Semi(expr) => match expr.into_inner() {
+ ast::Expr { kind: ast::ExprKind::MacCall(mac), attrs, .. } => {
+ Ok((mac.args.need_semicolon(), mac, attrs.into()))
+ }
+ _ => unreachable!(),
+ },
+ _ => unreachable!(),
+ }
+ }
+ StmtKind::Local(..) | StmtKind::Empty | StmtKind::Item(..) | StmtKind::Semi(..) => {
+ Err(stmt)
+ }
+ StmtKind::Expr(..) => unreachable!(),
+ }
+ }
+
fn configure<T: AstLike>(&mut self, node: T) -> Option<T> {
self.cfg.configure(node)
}
// Detect use of feature-gated or invalid attributes on macro invocations
// since they will not be detected after macro expansion.
- fn check_attributes(&mut self, attrs: &[ast::Attribute]) {
+ fn check_attributes(&self, attrs: &[ast::Attribute], call: &MacCall) {
let features = self.cx.ecfg.features.unwrap();
let mut attrs = attrs.iter().peekable();
let mut span: Option<Span> = None;
@@ -1085,14 +1120,31 @@
continue;
}
- if attr.doc_str().is_some() {
+ if attr.is_doc_comment() {
self.cx.sess.parse_sess.buffer_lint_with_diagnostic(
&UNUSED_DOC_COMMENTS,
current_span,
- ast::CRATE_NODE_ID,
+ self.cx.current_expansion.lint_node_id,
"unused doc comment",
BuiltinLintDiagnostics::UnusedDocComment(attr.span),
);
+ } else if rustc_attr::is_builtin_attr(attr) {
+ let attr_name = attr.ident().unwrap().name;
+ // `#[cfg]` and `#[cfg_attr]` are special - they are
+ // eagerly evaluated.
+ if attr_name != sym::cfg && attr_name != sym::cfg_attr {
+ self.cx.sess.parse_sess.buffer_lint_with_diagnostic(
+ &UNUSED_ATTRIBUTES,
+ attr.span,
+ self.cx.current_expansion.lint_node_id,
+ &format!("unused attribute `{}`", attr_name),
+ BuiltinLintDiagnostics::UnusedBuiltinAttribute {
+ attr_name,
+ macro_name: pprust::path_to_string(&call.path),
+ invoc_span: call.path.span,
+ },
+ );
+ }
}
}
}
@@ -1152,7 +1204,7 @@
}
if let ast::ExprKind::MacCall(mac) = expr.kind {
- self.check_attributes(&expr.attrs);
+ self.check_attributes(&expr.attrs, &mac);
self.collect_bang(mac, expr.span, AstFragmentKind::Expr).make_expr().into_inner()
} else {
assign_id!(self, &mut expr.id, || {
@@ -1163,11 +1215,6 @@
});
}
- // This is needed in order to set `lint_node_id` for `let` statements
- fn visit_local(&mut self, local: &mut P<Local>) {
- assign_id!(self, &mut local.id, || noop_visit_local(local, self));
- }
-
fn flat_map_arm(&mut self, arm: ast::Arm) -> SmallVec<[ast::Arm; 1]> {
let mut arm = configure!(self, arm);
@@ -1253,7 +1300,7 @@
}
if let ast::ExprKind::MacCall(mac) = expr.kind {
- self.check_attributes(&expr.attrs);
+ self.check_attributes(&expr.attrs, &mac);
self.collect_bang(mac, expr.span, AstFragmentKind::OptExpr)
.make_opt_expr()
.map(|expr| expr.into_inner())
@@ -1285,40 +1332,60 @@
fn flat_map_stmt(&mut self, stmt: ast::Stmt) -> SmallVec<[ast::Stmt; 1]> {
let mut stmt = configure!(self, stmt);
- // we'll expand attributes on expressions separately
- if !stmt.is_expr() {
+ // We pull macro invocations (both attributes and fn-like macro calls) out of their
+ // `StmtKind`s and treat them as statement macro invocations, not as items or expressions.
+ // FIXME: invocations in semicolon-less expressions positions are expanded as expressions,
+ // changing that requires some compatibility measures.
+ let mut stmt = if !stmt.is_expr() {
if let Some(attr) = self.take_first_attr(&mut stmt) {
return self
.collect_attr(attr, Annotatable::Stmt(P(stmt)), AstFragmentKind::Stmts)
.make_stmts();
}
- }
- if let StmtKind::MacCall(mac) = stmt.kind {
- let MacCallStmt { mac, style, attrs, tokens: _ } = mac.into_inner();
- self.check_attributes(&attrs);
- let mut placeholder =
- self.collect_bang(mac, stmt.span, AstFragmentKind::Stmts).make_stmts();
+ let span = stmt.span;
+ match self.take_stmt_bang(stmt) {
+ Ok((add_semicolon, mac, attrs)) => {
+ self.check_attributes(&attrs, &mac);
+ let mut stmts =
+ self.collect_bang(mac, span, AstFragmentKind::Stmts).make_stmts();
- // If this is a macro invocation with a semicolon, then apply that
- // semicolon to the final statement produced by expansion.
- if style == MacStmtStyle::Semicolon {
- if let Some(stmt) = placeholder.pop() {
- placeholder.push(stmt.add_trailing_semicolon());
+ // If this is a macro invocation with a semicolon, then apply that
+ // semicolon to the final statement produced by expansion.
+ if add_semicolon {
+ if let Some(stmt) = stmts.pop() {
+ stmts.push(stmt.add_trailing_semicolon());
+ }
+ }
+
+ return stmts;
}
+ Err(stmt) => stmt,
}
+ } else {
+ stmt
+ };
- return placeholder;
- }
-
- // The placeholder expander gives ids to statements, so we avoid folding the id here.
- // We don't use `assign_id!` - it will be called when we visit statement's contents
- // (e.g. an expression, item, or local)
- let ast::Stmt { id, kind, span } = stmt;
- noop_flat_map_stmt_kind(kind, self)
- .into_iter()
- .map(|kind| ast::Stmt { id, kind, span })
- .collect()
+ // The only way that we can end up with a `MacCall` expression statement,
+ // (as opposed to a `StmtKind::MacCall`) is if we have a macro as the
+ // traiing expression in a block (e.g. `fn foo() { my_macro!() }`).
+ // Record this information, so that we can report a more specific
+ // `SEMICOLON_IN_EXPRESSIONS_FROM_MACROS` lint if needed.
+ // See #78991 for an investigation of treating macros in this position
+ // as statements, rather than expressions, during parsing.
+ let res = match &stmt.kind {
+ StmtKind::Expr(expr)
+ if matches!(**expr, ast::Expr { kind: ast::ExprKind::MacCall(..), .. }) =>
+ {
+ self.cx.current_expansion.is_trailing_mac = true;
+ // Don't use `assign_id` for this statement - it may get removed
+ // entirely due to a `#[cfg]` on the contained expression
+ noop_flat_map_stmt(stmt, self)
+ }
+ _ => assign_id!(self, &mut stmt.id, || noop_flat_map_stmt(stmt, self)),
+ };
+ self.cx.current_expansion.is_trailing_mac = false;
+ res
}
fn visit_block(&mut self, block: &mut P<Block>) {
@@ -1344,9 +1411,9 @@
let span = item.span;
match item.kind {
- ast::ItemKind::MacCall(..) => {
+ ast::ItemKind::MacCall(ref mac) => {
+ self.check_attributes(&attrs, &mac);
item.attrs = attrs;
- self.check_attributes(&item.attrs);
item.and_then(|item| match item.kind {
ItemKind::MacCall(mac) => {
self.collect_bang(mac, span, AstFragmentKind::Items).make_items()
@@ -1455,8 +1522,8 @@
}
match item.kind {
- ast::AssocItemKind::MacCall(..) => {
- self.check_attributes(&item.attrs);
+ ast::AssocItemKind::MacCall(ref mac) => {
+ self.check_attributes(&item.attrs, &mac);
item.and_then(|item| match item.kind {
ast::AssocItemKind::MacCall(mac) => self
.collect_bang(mac, item.span, AstFragmentKind::TraitItems)
@@ -1480,8 +1547,8 @@
}
match item.kind {
- ast::AssocItemKind::MacCall(..) => {
- self.check_attributes(&item.attrs);
+ ast::AssocItemKind::MacCall(ref mac) => {
+ self.check_attributes(&item.attrs, &mac);
item.and_then(|item| match item.kind {
ast::AssocItemKind::MacCall(mac) => self
.collect_bang(mac, item.span, AstFragmentKind::ImplItems)
@@ -1526,8 +1593,8 @@
}
match foreign_item.kind {
- ast::ForeignItemKind::MacCall(..) => {
- self.check_attributes(&foreign_item.attrs);
+ ast::ForeignItemKind::MacCall(ref mac) => {
+ self.check_attributes(&foreign_item.attrs, &mac);
foreign_item.and_then(|item| match item.kind {
ast::ForeignItemKind::MacCall(mac) => self
.collect_bang(mac, item.span, AstFragmentKind::ForeignItems)
diff --git a/compiler/rustc_expand/src/lib.rs b/compiler/rustc_expand/src/lib.rs
index efed41d..c6dc66e 100644
--- a/compiler/rustc_expand/src/lib.rs
+++ b/compiler/rustc_expand/src/lib.rs
@@ -1,12 +1,16 @@
+#![cfg_attr(bootstrap, feature(bindings_after_at))]
#![feature(crate_visibility_modifier)]
#![feature(decl_macro)]
#![feature(destructuring_assignment)]
#![feature(format_args_capture)]
+#![feature(if_let_guard)]
#![feature(iter_zip)]
#![feature(proc_macro_diagnostic)]
#![feature(proc_macro_internals)]
#![feature(proc_macro_span)]
#![feature(try_blocks)]
+#![cfg_attr(bootstrap, allow(incomplete_features))] // if_let_guard
+#![recursion_limit = "256"]
#[macro_use]
extern crate rustc_macros;
diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs
index 7f985af..f849165 100644
--- a/compiler/rustc_expand/src/mbe/macro_rules.rs
+++ b/compiler/rustc_expand/src/mbe/macro_rules.rs
@@ -43,7 +43,10 @@
/// The ident of the macro we're parsing
macro_ident: Ident,
lint_node_id: NodeId,
+ is_trailing_mac: bool,
arm_span: Span,
+ /// Whether or not this macro is defined in the current crate
+ is_local: bool,
}
crate fn annotate_err_with_kind(
@@ -116,8 +119,15 @@
impl<'a> ParserAnyMacro<'a> {
crate fn make(mut self: Box<ParserAnyMacro<'a>>, kind: AstFragmentKind) -> AstFragment {
- let ParserAnyMacro { site_span, macro_ident, ref mut parser, lint_node_id, arm_span } =
- *self;
+ let ParserAnyMacro {
+ site_span,
+ macro_ident,
+ ref mut parser,
+ lint_node_id,
+ arm_span,
+ is_trailing_mac,
+ is_local,
+ } = *self;
let snapshot = &mut parser.clone();
let fragment = match parse_ast_fragment(parser, kind) {
Ok(f) => f,
@@ -131,12 +141,15 @@
// `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",
- );
+ if is_local {
+ parser.sess.buffer_lint_with_diagnostic(
+ SEMICOLON_IN_EXPRESSIONS_FROM_MACROS,
+ parser.token.span,
+ lint_node_id,
+ "trailing semicolon in macro used in expression position",
+ BuiltinLintDiagnostics::TrailingMacro(is_trailing_mac, macro_ident),
+ );
+ }
parser.bump();
}
@@ -154,6 +167,7 @@
lhses: Vec<mbe::TokenTree>,
rhses: Vec<mbe::TokenTree>,
valid: bool,
+ is_local: bool,
}
impl TTMacroExpander for MacroRulesMacroExpander {
@@ -175,6 +189,7 @@
input,
&self.lhses,
&self.rhses,
+ self.is_local,
)
}
}
@@ -202,6 +217,7 @@
arg: TokenStream,
lhses: &[mbe::TokenTree],
rhses: &[mbe::TokenTree],
+ is_local: bool,
) -> Box<dyn MacResult + 'cx> {
let sess = &cx.sess.parse_sess;
@@ -301,7 +317,9 @@
site_span: sp,
macro_ident: name,
lint_node_id: cx.current_expansion.lint_node_id,
+ is_trailing_mac: cx.current_expansion.is_trailing_mac,
arm_span,
+ is_local,
});
}
Failure(token, msg) => match best_failure {
@@ -517,7 +535,7 @@
valid &= macro_check::check_meta_variables(&sess.parse_sess, def.id, def.span, &lhses, &rhses);
- let (transparency, transparency_error) = attr::find_transparency(sess, &def.attrs, macro_rules);
+ let (transparency, transparency_error) = attr::find_transparency(&def.attrs, macro_rules);
match transparency_error {
Some(TransparencyError::UnknownTransparency(value, span)) => {
diag.span_err(span, &format!("unknown macro transparency: `{}`", value))
@@ -535,6 +553,9 @@
lhses,
rhses,
valid,
+ // Macros defined in the current crate have a real node id,
+ // whereas macros from an external crate have a dummy id.
+ is_local: def.id != DUMMY_NODE_ID,
}))
}
@@ -1200,7 +1221,7 @@
fn quoted_tt_to_string(tt: &mbe::TokenTree) -> String {
match *tt {
- mbe::TokenTree::Token(ref token) => pprust::token_to_string(&token),
+ mbe::TokenTree::Token(ref token) => pprust::token_to_string(&token).into(),
mbe::TokenTree::MetaVar(_, name) => format!("${}", name),
mbe::TokenTree::MetaVarDecl(_, name, Some(kind)) => format!("${}:{}", name, kind),
mbe::TokenTree::MetaVarDecl(_, name, None) => format!("${}:", name),
diff --git a/compiler/rustc_expand/src/module.rs b/compiler/rustc_expand/src/module.rs
index 4d77704..60d653a 100644
--- a/compiler/rustc_expand/src/module.rs
+++ b/compiler/rustc_expand/src/module.rs
@@ -86,13 +86,12 @@
inline: Inline,
) -> (PathBuf, DirOwnership) {
match inline {
+ Inline::Yes if let Some(file_path) = mod_file_path_from_attr(sess, attrs, &module.dir_path) => {
+ // For inline modules file path from `#[path]` is actually the directory path
+ // for historical reasons, so we don't pop the last segment here.
+ (file_path, DirOwnership::Owned { relative: None })
+ }
Inline::Yes => {
- if let Some(file_path) = mod_file_path_from_attr(sess, attrs, &module.dir_path) {
- // For inline modules file path from `#[path]` is actually the directory path
- // for historical reasons, so we don't pop the last segment here.
- return (file_path, DirOwnership::Owned { relative: None });
- }
-
// We have to push on the current module name in the case of relative
// paths in order to ensure that any additional module paths from inline
// `mod x { ... }` come after the relative extension.
diff --git a/compiler/rustc_expand/src/placeholders.rs b/compiler/rustc_expand/src/placeholders.rs
index 6586ba1..8e78fcb 100644
--- a/compiler/rustc_expand/src/placeholders.rs
+++ b/compiler/rustc_expand/src/placeholders.rs
@@ -1,4 +1,3 @@
-use crate::base::ExtCtxt;
use crate::expand::{AstFragment, AstFragmentKind};
use rustc_ast as ast;
@@ -175,17 +174,12 @@
}
}
-pub struct PlaceholderExpander<'a, 'b> {
+#[derive(Default)]
+pub struct PlaceholderExpander {
expanded_fragments: FxHashMap<ast::NodeId, AstFragment>,
- cx: &'a mut ExtCtxt<'b>,
- monotonic: bool,
}
-impl<'a, 'b> PlaceholderExpander<'a, 'b> {
- pub fn new(cx: &'a mut ExtCtxt<'b>, monotonic: bool) -> Self {
- PlaceholderExpander { cx, expanded_fragments: FxHashMap::default(), monotonic }
- }
-
+impl PlaceholderExpander {
pub fn add(&mut self, id: ast::NodeId, mut fragment: AstFragment) {
fragment.mut_visit_with(self);
self.expanded_fragments.insert(id, fragment);
@@ -196,7 +190,7 @@
}
}
-impl<'a, 'b> MutVisitor for PlaceholderExpander<'a, 'b> {
+impl MutVisitor for PlaceholderExpander {
fn flat_map_arm(&mut self, arm: ast::Arm) -> SmallVec<[ast::Arm; 1]> {
if arm.is_placeholder {
self.remove(arm.id).make_arms()
@@ -360,15 +354,4 @@
_ => noop_visit_ty(ty, self),
}
}
-
- fn visit_block(&mut self, block: &mut P<ast::Block>) {
- noop_visit_block(block, self);
-
- for stmt in block.stmts.iter_mut() {
- if self.monotonic {
- assert_eq!(stmt.id, ast::DUMMY_NODE_ID);
- stmt.id = self.cx.resolver.next_node_id();
- }
- }
- }
}
diff --git a/compiler/rustc_expand/src/proc_macro_server.rs b/compiler/rustc_expand/src/proc_macro_server.rs
index ff135f6..55700f7 100644
--- a/compiler/rustc_expand/src/proc_macro_server.rs
+++ b/compiler/rustc_expand/src/proc_macro_server.rs
@@ -1,7 +1,7 @@
use crate::base::{ExtCtxt, ResolverExpand};
use rustc_ast as ast;
-use rustc_ast::token::{self, Nonterminal, NtIdent, TokenKind};
+use rustc_ast::token::{self, Nonterminal, NtIdent};
use rustc_ast::tokenstream::{self, CanSynthesizeMissingTokens};
use rustc_ast::tokenstream::{DelimSpan, Spacing::*, TokenStream, TreeAndSpacing};
use rustc_ast_pretty::pprust;
@@ -178,18 +178,19 @@
tt!(Punct::new('#', false))
}
+ Interpolated(nt)
+ if let Some((name, is_raw)) = ident_name_compatibility_hack(&nt, span, rustc) =>
+ {
+ TokenTree::Ident(Ident::new(rustc.sess, name.name, is_raw, name.span))
+ }
Interpolated(nt) => {
- if let Some((name, is_raw)) = ident_name_compatibility_hack(&nt, span, rustc) {
- TokenTree::Ident(Ident::new(rustc.sess, name.name, is_raw, name.span))
- } else {
- let stream = nt_to_tokenstream(&nt, rustc.sess, CanSynthesizeMissingTokens::No);
- TokenTree::Group(Group {
- delimiter: Delimiter::None,
- stream,
- span: DelimSpan::from_single(span),
- flatten: crate::base::pretty_printing_compatibility_hack(&nt, rustc.sess),
- })
- }
+ let stream = nt_to_tokenstream(&nt, rustc.sess, CanSynthesizeMissingTokens::No);
+ TokenTree::Group(Group {
+ delimiter: Delimiter::None,
+ stream,
+ span: DelimSpan::from_single(span),
+ flatten: crate::base::pretty_printing_compatibility_hack(&nt, rustc.sess),
+ })
}
OpenDelim(..) | CloseDelim(..) => unreachable!(),
@@ -537,32 +538,54 @@
impl server::Literal for Rustc<'_> {
fn from_str(&mut self, s: &str) -> Result<Self::Literal, ()> {
- let override_span = None;
- let stream = parse_stream_from_source_str(
- FileName::proc_macro_source_code(s),
- s.to_owned(),
- self.sess,
- override_span,
- );
- if stream.len() != 1 {
- return Err(());
- }
- let tree = stream.into_trees().next().unwrap();
- let token = match tree {
- tokenstream::TokenTree::Token(token) => token,
- tokenstream::TokenTree::Delimited { .. } => return Err(()),
- };
- let span_data = token.span.data();
- if (span_data.hi.0 - span_data.lo.0) as usize != s.len() {
- // There is a comment or whitespace adjacent to the literal.
- return Err(());
- }
- let lit = match token.kind {
- TokenKind::Literal(lit) => lit,
+ let name = FileName::proc_macro_source_code(s);
+ let mut parser = rustc_parse::new_parser_from_source_str(self.sess, name, s.to_owned());
+
+ let first_span = parser.token.span.data();
+ let minus_present = parser.eat(&token::BinOp(token::Minus));
+
+ let lit_span = parser.token.span.data();
+ let mut lit = match parser.token.kind {
+ token::Literal(lit) => lit,
_ => return Err(()),
};
+
+ // Check no comment or whitespace surrounding the (possibly negative)
+ // literal, or more tokens after it.
+ if (lit_span.hi.0 - first_span.lo.0) as usize != s.len() {
+ return Err(());
+ }
+
+ if minus_present {
+ // If minus is present, check no comment or whitespace in between it
+ // and the literal token.
+ if first_span.hi.0 != lit_span.lo.0 {
+ return Err(());
+ }
+
+ // Check literal is a kind we allow to be negated in a proc macro token.
+ match lit.kind {
+ token::LitKind::Bool
+ | token::LitKind::Byte
+ | token::LitKind::Char
+ | token::LitKind::Str
+ | token::LitKind::StrRaw(_)
+ | token::LitKind::ByteStr
+ | token::LitKind::ByteStrRaw(_)
+ | token::LitKind::Err => return Err(()),
+ token::LitKind::Integer | token::LitKind::Float => {}
+ }
+
+ // Synthesize a new symbol that includes the minus sign.
+ let symbol = Symbol::intern(&s[..1 + lit.symbol.len()]);
+ lit = token::Lit::new(lit.kind, symbol, lit.suffix);
+ }
+
Ok(Literal { lit, span: self.call_site })
}
+ fn to_string(&mut self, literal: &Self::Literal) -> String {
+ literal.lit.to_string()
+ }
fn debug_kind(&mut self, literal: &Self::Literal) -> String {
format!("{:?}", literal.lit.kind)
}
@@ -834,7 +857,7 @@
.flat_map(|c| c.as_os_str().to_str())
.find(|c| c.starts_with("js-sys"))
{
- let mut version = c.trim_start_matches("js-sys-").split(".");
+ let mut version = c.trim_start_matches("js-sys-").split('.');
if version.next() == Some("0")
&& version.next() == Some("3")
&& version
diff --git a/compiler/rustc_feature/Cargo.toml b/compiler/rustc_feature/Cargo.toml
index 7a06bce..ee381e3 100644
--- a/compiler/rustc_feature/Cargo.toml
+++ b/compiler/rustc_feature/Cargo.toml
@@ -1,5 +1,4 @@
[package]
-authors = ["The Rust Project Developers"]
name = "rustc_feature"
version = "0.0.0"
edition = "2018"
diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs
index 9550472..f557a4c 100644
--- a/compiler/rustc_feature/src/accepted.rs
+++ b/compiler/rustc_feature/src/accepted.rs
@@ -178,7 +178,7 @@
/// Allows annotating functions conforming to `fn(&PanicInfo) -> !` with `#[panic_handler]`.
/// This defines the behavior of panics.
(accepted, panic_handler, "1.30.0", Some(44489), None),
- /// Allows `#[used]` to preserve symbols (see llvm.used).
+ /// Allows `#[used]` to preserve symbols (see llvm.compiler.used).
(accepted, used, "1.30.0", Some(40289), None),
/// Allows `crate` in paths.
(accepted, crate_in_paths, "1.30.0", Some(45477), None),
@@ -273,7 +273,7 @@
/// 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.49.0", Some(68354), None),
- /// The smallest useful subset of `const_generics`.
+ /// The smallest useful subset of const generics.
(accepted, min_const_generics, "1.51.0", Some(74878), None),
/// The `unsafe_op_in_unsafe_fn` lint (allowed by default): no longer treat an unsafe function as an unsafe block.
(accepted, unsafe_block_in_unsafe_fn, "1.52.0", Some(71668), None),
@@ -287,6 +287,13 @@
(accepted, const_fn_unsize, "1.54.0", Some(64992), None),
/// Allows `impl Trait` with multiple unrelated lifetimes.
(accepted, member_constraints, "1.54.0", Some(61997), None),
+ /// Allows bindings in the subpattern of a binding pattern.
+ /// For example, you can write `x @ Some(y)`.
+ (accepted, bindings_after_at, "1.56.0", Some(65490), None),
+ /// Allows calling `transmute` in const fn
+ (accepted, const_fn_transmute, "1.56.0", Some(53605), None),
+ /// Allows accessing fields of unions inside `const` functions.
+ (accepted, const_fn_union, "1.56.0", Some(51909), None),
// -------------------------------------------------------------------------
// feature-group-end: accepted features
diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs
index a3e40da..743c40c 100644
--- a/compiler/rustc_feature/src/active.rs
+++ b/compiler/rustc_feature/src/active.rs
@@ -71,7 +71,7 @@
}
pub fn unordered_const_ty_params(&self) -> bool {
- self.const_generics || self.const_generics_defaults
+ self.const_generics_defaults || self.generic_const_exprs || self.adt_const_params
}
/// Some features are known to be incomplete and using them is likely to have
@@ -281,9 +281,6 @@
// feature-group-start: actual feature gates
// -------------------------------------------------------------------------
- /// Allows using `#[plugin_registrar]` on functions.
- (active, plugin_registrar, "1.0.0", Some(29597), None),
-
/// Allows using `#![plugin(myplugin)]`.
(active, plugin, "1.0.0", Some(29597), None),
@@ -311,11 +308,6 @@
/// Allows `extern "platform-intrinsic" { ... }`.
(active, platform_intrinsics, "1.4.0", Some(27731), None),
- /// Allows `#[unwind(..)]`.
- ///
- /// Permits specifying whether a function should permit unwinding or abort on unwind.
- (active, unwind_attributes, "1.4.0", Some(58760), None),
-
/// Allows attributes on expressions and non-item statements.
(active, stmt_expr_attributes, "1.6.0", Some(15701), None),
@@ -413,9 +405,6 @@
/// Allows inferring `'static` outlives requirements (RFC 2093).
(active, infer_static_outlives_requirements, "1.26.0", Some(54185), None),
- /// Allows accessing fields of unions inside `const` functions.
- (active, const_fn_union, "1.27.0", Some(51909), None),
-
/// Allows dereferencing raw pointers during const eval.
(active, const_raw_ptr_deref, "1.27.0", Some(51911), None),
@@ -464,9 +453,6 @@
/// Allows using `#[ffi_returns_twice]` on foreign functions.
(active, ffi_returns_twice, "1.34.0", Some(58314), None),
- /// Allows const generic types (e.g. `struct Foo<const N: usize>(...);`).
- (incomplete, const_generics, "1.34.0", Some(44580), None),
-
/// Allows using `#[optimize(X)]`.
(active, optimize_attribute, "1.34.0", Some(54882), None),
@@ -489,7 +475,7 @@
(active, async_closure, "1.37.0", Some(62290), None),
/// Allows `impl Trait` to be used inside type aliases (RFC 2515).
- (incomplete, type_alias_impl_trait, "1.38.0", Some(63063), None),
+ (active, type_alias_impl_trait, "1.38.0", Some(63063), None),
/// Allows the definition of `const extern fn` and `const unsafe extern fn`.
(active, const_extern_fn, "1.40.0", Some(64926), None),
@@ -526,16 +512,9 @@
/// Allows using `&mut` in constant functions.
(active, const_mut_refs, "1.41.0", Some(57349), None),
- /// Allows bindings in the subpattern of a binding pattern.
- /// For example, you can write `x @ Some(y)`.
- (active, bindings_after_at, "1.41.0", Some(65490), None),
-
/// Allows `impl const Trait for T` syntax.
(active, const_trait_impl, "1.42.0", Some(67792), None),
- /// Allows `T: ?const Trait` syntax in bounds.
- (incomplete, const_trait_bound_opt_out, "1.42.0", Some(67794), None),
-
/// Allows the use of `no_sanitize` attribute.
(active, no_sanitize, "1.42.0", Some(39699), None),
@@ -566,17 +545,8 @@
/// Allows capturing variables in scope using format_args!
(active, format_args_capture, "1.46.0", Some(67984), None),
- /// Lazily evaluate constants. This allows constants to depend on type parameters.
- (incomplete, lazy_normalization_consts, "1.46.0", Some(72219), None),
-
- /// Allows calling `transmute` in const fn
- (active, const_fn_transmute, "1.46.0", Some(53605), None),
-
/// Allows `if let` guard in match arms.
- (incomplete, if_let_guard, "1.47.0", Some(51114), None),
-
- /// Allows non-trivial generic constants which have to be manually propagated upwards.
- (incomplete, const_evaluatable_checked, "1.48.0", Some(76560), None),
+ (active, if_let_guard, "1.47.0", Some(51114), None),
/// Allows basic arithmetic on floating point types in a `const fn`.
(active, const_fn_floating_point_arithmetic, "1.48.0", Some(57241), None),
@@ -629,9 +599,6 @@
/// Allows macro attributes to observe output of `#[derive]`.
(active, macro_attributes_in_derive_output, "1.51.0", Some(81119), None),
- /// Allows the use of type alias impl trait in function return positions
- (active, min_type_alias_impl_trait, "1.52.0", Some(63063), None),
-
/// Allows associated types in inherent impls.
(incomplete, inherent_associated_types, "1.52.0", Some(8995), None),
@@ -675,15 +642,43 @@
/// Allows specifying the as-needed link modifier
(active, native_link_modifiers_as_needed, "1.53.0", Some(81490), None),
- /// Allows unnamed fields of struct and union type
- (incomplete, unnamed_fields, "1.53.0", Some(49804), None),
-
/// Allows qualified paths in struct expressions, struct patterns and tuple struct patterns.
(active, more_qualified_paths, "1.54.0", Some(86935), None),
/// Allows `cfg(target_abi = "...")`.
(active, cfg_target_abi, "1.55.0", Some(80970), None),
+ /// Infer generic args for both consts and types.
+ (active, generic_arg_infer, "1.55.0", Some(85077), None),
+
+ /// Allows `#[derive(Default)]` and `#[default]` on enums.
+ (active, derive_default_enum, "1.56.0", Some(86985), None),
+
+ /// Allows `for _ in _` loops in const contexts.
+ (active, const_for, "1.56.0", Some(87575), None),
+
+ /// Allows the `?` operator in const contexts.
+ (active, const_try, "1.56.0", Some(74935), None),
+
+ /// Allows upcasting trait objects via supertraits.
+ /// Trait upcasting is casting, e.g., `dyn Foo -> dyn Bar` where `Foo: Bar`.
+ (incomplete, trait_upcasting, "1.56.0", Some(65991), None),
+
+ /// Allows explicit generic arguments specification with `impl Trait` present.
+ (active, explicit_generic_args_with_impl_trait, "1.56.0", Some(83701), None),
+
+ /// Allows using doc(primitive) without a future-incompat warning
+ (active, doc_primitive, "1.56.0", Some(88070), None),
+
+ /// Allows non-trivial generic constants which have to have wfness manually propagated to callers
+ (incomplete, generic_const_exprs, "1.56.0", Some(76560), None),
+
+ /// Allows additional const parameter types, such as `&'static str` or user defined types
+ (incomplete, adt_const_params, "1.56.0", Some(44580), None),
+
+ /// Allows `let...else` statements.
+ (active, let_else, "1.56.0", Some(87335), None),
+
// -------------------------------------------------------------------------
// feature-group-end: actual feature gates
// -------------------------------------------------------------------------
diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs
index b1c725e..e2aa54a 100644
--- a/compiler/rustc_feature/src/builtin_attrs.rs
+++ b/compiler/rustc_feature/src/builtin_attrs.rs
@@ -52,11 +52,6 @@
/// by the compiler before the unused_attribute check
Normal,
- /// Builtin attribute that may not be consumed by the compiler
- /// before the unused_attribute check. These attributes
- /// will be ignored by the unused_attribute lint
- AssumedUsed,
-
/// Builtin attribute that is only allowed at the crate level
CrateLevel,
}
@@ -186,7 +181,7 @@
template!(Word, List: r#"expected = "reason"#, NameValueStr: "reason"),
),
// FIXME(Centril): This can be used on stable but shouldn't.
- ungated!(reexport_test_harness_main, Normal, template!(NameValueStr: "name")),
+ ungated!(reexport_test_harness_main, CrateLevel, template!(NameValueStr: "name")),
// Macros:
ungated!(automatically_derived, Normal, template!(Word)),
@@ -206,7 +201,7 @@
ungated!(allow, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#)),
ungated!(forbid, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#)),
ungated!(deny, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#)),
- ungated!(must_use, AssumedUsed, template!(Word, NameValueStr: "reason")),
+ ungated!(must_use, Normal, template!(Word, NameValueStr: "reason")),
// FIXME(#14407)
ungated!(
deprecated, Normal,
@@ -224,16 +219,16 @@
// ABI, linking, symbols, and FFI
ungated!(
- link, AssumedUsed,
+ link, Normal,
template!(List: r#"name = "...", /*opt*/ kind = "dylib|static|...", /*opt*/ wasm_import_module = "...""#),
),
- ungated!(link_name, AssumedUsed, template!(NameValueStr: "name")),
- ungated!(no_link, AssumedUsed, template!(Word)),
- ungated!(repr, AssumedUsed, template!(List: "C")),
- ungated!(export_name, AssumedUsed, template!(NameValueStr: "name")),
- ungated!(link_section, AssumedUsed, template!(NameValueStr: "name")),
- ungated!(no_mangle, AssumedUsed, template!(Word)),
- ungated!(used, AssumedUsed, template!(Word)),
+ ungated!(link_name, Normal, template!(NameValueStr: "name")),
+ ungated!(no_link, Normal, template!(Word)),
+ ungated!(repr, Normal, template!(List: "C")),
+ ungated!(export_name, Normal, template!(NameValueStr: "name")),
+ ungated!(link_section, Normal, template!(NameValueStr: "name")),
+ ungated!(no_mangle, Normal, template!(Word)),
+ ungated!(used, Normal, template!(Word)),
// Limits:
ungated!(recursion_limit, CrateLevel, template!(NameValueStr: "N")),
@@ -257,53 +252,41 @@
ungated!(path, Normal, template!(NameValueStr: "file")),
ungated!(no_std, CrateLevel, template!(Word)),
ungated!(no_implicit_prelude, Normal, template!(Word)),
- ungated!(non_exhaustive, AssumedUsed, template!(Word)),
+ ungated!(non_exhaustive, Normal, template!(Word)),
// Runtime
- ungated!(windows_subsystem, AssumedUsed, template!(NameValueStr: "windows|console")),
+ ungated!(windows_subsystem, Normal, template!(NameValueStr: "windows|console")),
ungated!(panic_handler, Normal, template!(Word)), // RFC 2070
// Code generation:
- ungated!(inline, AssumedUsed, template!(Word, List: "always|never")),
- ungated!(cold, AssumedUsed, template!(Word)),
- ungated!(no_builtins, AssumedUsed, template!(Word)),
- ungated!(target_feature, AssumedUsed, template!(List: r#"enable = "name""#)),
- ungated!(track_caller, AssumedUsed, template!(Word)),
+ ungated!(inline, Normal, template!(Word, List: "always|never")),
+ ungated!(cold, Normal, template!(Word)),
+ ungated!(no_builtins, Normal, template!(Word)),
+ ungated!(target_feature, Normal, template!(List: r#"enable = "name""#)),
+ ungated!(track_caller, Normal, template!(Word)),
gated!(
- no_sanitize, AssumedUsed,
+ no_sanitize, Normal,
template!(List: "address, memory, thread"),
experimental!(no_sanitize)
),
- gated!(no_coverage, AssumedUsed, template!(Word), experimental!(no_coverage)),
+ gated!(no_coverage, Normal, template!(Word), experimental!(no_coverage)),
// FIXME: #14408 assume docs are used since rustdoc looks at them.
- ungated!(doc, AssumedUsed, template!(List: "hidden|inline|...", NameValueStr: "string")),
+ ungated!(doc, Normal, template!(List: "hidden|inline|...", NameValueStr: "string")),
// ==========================================================================
// Unstable attributes:
// ==========================================================================
// Linking:
- gated!(naked, AssumedUsed, template!(Word), naked_functions, experimental!(naked)),
+ gated!(naked, Normal, template!(Word), naked_functions, experimental!(naked)),
gated!(
- link_ordinal, AssumedUsed, template!(List: "ordinal"), raw_dylib,
+ link_ordinal, Normal, template!(List: "ordinal"), raw_dylib,
experimental!(link_ordinal)
),
// Plugins:
(
- sym::plugin_registrar, Normal, template!(Word),
- Gated(
- Stability::Deprecated(
- "https://github.com/rust-lang/rust/pull/64675",
- Some("may be removed in a future compiler version"),
- ),
- sym::plugin_registrar,
- "compiler plugins are deprecated",
- cfg_fn!(plugin_registrar)
- )
- ),
- (
sym::plugin, CrateLevel, template!(List: "name"),
Gated(
Stability::Deprecated(
@@ -323,23 +306,23 @@
"custom test frameworks are an unstable feature",
),
// RFC #1268
- gated!(marker, AssumedUsed, template!(Word), marker_trait_attr, experimental!(marker)),
+ gated!(marker, Normal, template!(Word), marker_trait_attr, experimental!(marker)),
gated!(
- thread_local, AssumedUsed, template!(Word),
+ thread_local, Normal, template!(Word),
"`#[thread_local]` is an experimental feature, and does not currently handle destructors",
),
gated!(no_core, CrateLevel, template!(Word), experimental!(no_core)),
// RFC 2412
gated!(
- optimize, AssumedUsed, template!(List: "size|speed"), optimize_attribute,
+ optimize, Normal, template!(List: "size|speed"), optimize_attribute,
experimental!(optimize),
),
// RFC 2867
- gated!(instruction_set, AssumedUsed, template!(List: "set"), isa_attribute, experimental!(instruction_set)),
+ gated!(instruction_set, Normal, template!(List: "set"), isa_attribute, experimental!(instruction_set)),
- gated!(ffi_returns_twice, AssumedUsed, template!(Word), experimental!(ffi_returns_twice)),
- gated!(ffi_pure, AssumedUsed, template!(Word), experimental!(ffi_pure)),
- gated!(ffi_const, AssumedUsed, template!(Word), experimental!(ffi_const)),
+ gated!(ffi_returns_twice, Normal, template!(Word), experimental!(ffi_returns_twice)),
+ gated!(ffi_pure, Normal, template!(Word), experimental!(ffi_pure)),
+ gated!(ffi_const, Normal, template!(Word), experimental!(ffi_const)),
gated!(
register_attr, CrateLevel, template!(List: "attr1, attr2, ..."),
experimental!(register_attr),
@@ -349,10 +332,10 @@
experimental!(register_tool),
),
- gated!(cmse_nonsecure_entry, AssumedUsed, template!(Word), experimental!(cmse_nonsecure_entry)),
+ gated!(cmse_nonsecure_entry, Normal, template!(Word), experimental!(cmse_nonsecure_entry)),
// RFC 2632
gated!(
- default_method_body_is_const, AssumedUsed, template!(Word), const_trait_impl,
+ default_method_body_is_const, Normal, template!(Word), const_trait_impl,
"`default_method_body_is_const` is a temporary placeholder for declaring default bodies \
as `const`, which may be removed or renamed in the future."
),
@@ -365,26 +348,26 @@
// FIXME(#14407) -- only looked at on-demand so we can't
// guarantee they'll have already been checked.
ungated!(
- rustc_deprecated, AssumedUsed,
+ rustc_deprecated, Normal,
template!(List: r#"since = "version", reason = "...""#)
),
// FIXME(#14407)
- ungated!(stable, AssumedUsed, template!(List: r#"feature = "name", since = "version""#)),
+ ungated!(stable, Normal, template!(List: r#"feature = "name", since = "version""#)),
// FIXME(#14407)
ungated!(
- unstable, AssumedUsed,
+ unstable, Normal,
template!(List: r#"feature = "name", reason = "...", issue = "N""#),
),
// FIXME(#14407)
- ungated!(rustc_const_unstable, AssumedUsed, template!(List: r#"feature = "name""#)),
+ ungated!(rustc_const_unstable, Normal, template!(List: r#"feature = "name""#)),
// FIXME(#14407)
- ungated!(rustc_const_stable, AssumedUsed, template!(List: r#"feature = "name""#)),
+ ungated!(rustc_const_stable, Normal, template!(List: r#"feature = "name""#)),
gated!(
- allow_internal_unstable, AssumedUsed, template!(Word, List: "feat1, feat2, ..."),
+ allow_internal_unstable, Normal, template!(Word, List: "feat1, feat2, ..."),
"allow_internal_unstable side-steps feature gating and stability checks",
),
gated!(
- rustc_allow_const_fn_unstable, AssumedUsed, template!(Word, List: "feat1, feat2, ..."),
+ rustc_allow_const_fn_unstable, Normal, template!(Word, List: "feat1, feat2, ..."),
"rustc_allow_const_fn_unstable side-steps feature gating and stability checks"
),
gated!(
@@ -396,7 +379,7 @@
// Internal attributes: Type system related:
// ==========================================================================
- gated!(fundamental, AssumedUsed, template!(Word), experimental!(fundamental)),
+ gated!(fundamental, Normal, template!(Word), experimental!(fundamental)),
gated!(
may_dangle, Normal, template!(Word), dropck_eyepatch,
"`may_dangle` has unstable semantics and may be removed in the future",
@@ -406,30 +389,26 @@
// Internal attributes: Runtime related:
// ==========================================================================
- rustc_attr!(rustc_allocator, AssumedUsed, template!(Word), IMPL_DETAIL),
- rustc_attr!(rustc_allocator_nounwind, AssumedUsed, template!(Word), IMPL_DETAIL),
+ rustc_attr!(rustc_allocator, Normal, template!(Word), IMPL_DETAIL),
+ rustc_attr!(rustc_allocator_nounwind, Normal, template!(Word), IMPL_DETAIL),
gated!(alloc_error_handler, Normal, template!(Word), experimental!(alloc_error_handler)),
gated!(
- default_lib_allocator, AssumedUsed, template!(Word), allocator_internals,
+ default_lib_allocator, Normal, template!(Word), allocator_internals,
experimental!(default_lib_allocator),
),
gated!(
needs_allocator, Normal, template!(Word), allocator_internals,
experimental!(needs_allocator),
),
- gated!(panic_runtime, AssumedUsed, template!(Word), experimental!(panic_runtime)),
- gated!(needs_panic_runtime, AssumedUsed, template!(Word), experimental!(needs_panic_runtime)),
+ gated!(panic_runtime, Normal, template!(Word), experimental!(panic_runtime)),
+ gated!(needs_panic_runtime, Normal, template!(Word), experimental!(needs_panic_runtime)),
gated!(
- unwind, AssumedUsed, template!(List: "allowed|aborts"), unwind_attributes,
- experimental!(unwind),
- ),
- gated!(
- compiler_builtins, AssumedUsed, template!(Word),
+ compiler_builtins, Normal, template!(Word),
"the `#[compiler_builtins]` attribute is used to identify the `compiler_builtins` crate \
which contains compiler-rt intrinsics and will never be stable",
),
gated!(
- profiler_runtime, AssumedUsed, template!(Word),
+ profiler_runtime, Normal, template!(Word),
"the `#[profiler_runtime]` attribute is used to identify the `profiler_builtins` crate \
which contains the profiler runtime and will never be stable",
),
@@ -439,23 +418,23 @@
// ==========================================================================
gated!(
- linkage, AssumedUsed, template!(NameValueStr: "external|internal|..."),
+ linkage, Normal, template!(NameValueStr: "external|internal|..."),
"the `linkage` attribute is experimental and not portable across platforms",
),
- rustc_attr!(rustc_std_internal_symbol, AssumedUsed, template!(Word), INTERNAL_UNSTABLE),
+ rustc_attr!(rustc_std_internal_symbol, Normal, template!(Word), INTERNAL_UNSTABLE),
// ==========================================================================
// Internal attributes, Macro related:
// ==========================================================================
rustc_attr!(
- rustc_builtin_macro, AssumedUsed,
+ rustc_builtin_macro, Normal,
template!(Word, List: "name, /*opt*/ attributes(name1, name2, ...)"),
IMPL_DETAIL,
),
rustc_attr!(rustc_proc_macro_decls, Normal, template!(Word), INTERNAL_UNSTABLE),
rustc_attr!(
- rustc_macro_transparency, AssumedUsed,
+ rustc_macro_transparency, Normal,
template!(NameValueStr: "transparent|semitransparent|opaque"),
"used internally for testing macro hygiene",
),
@@ -465,7 +444,7 @@
// ==========================================================================
rustc_attr!(
- rustc_on_unimplemented, AssumedUsed,
+ rustc_on_unimplemented, Normal,
template!(
List: r#"/*opt*/ message = "...", /*opt*/ label = "...", /*opt*/ note = "...""#,
NameValueStr: "message"
@@ -473,31 +452,31 @@
INTERNAL_UNSTABLE
),
// Enumerates "identity-like" conversion methods to suggest on type mismatch.
- rustc_attr!(rustc_conversion_suggestion, AssumedUsed, template!(Word), INTERNAL_UNSTABLE),
+ rustc_attr!(rustc_conversion_suggestion, Normal, template!(Word), INTERNAL_UNSTABLE),
// ==========================================================================
// Internal attributes, Const related:
// ==========================================================================
- rustc_attr!(rustc_promotable, AssumedUsed, template!(Word), IMPL_DETAIL),
- rustc_attr!(rustc_legacy_const_generics, AssumedUsed, template!(List: "N"), INTERNAL_UNSTABLE),
+ rustc_attr!(rustc_promotable, Normal, template!(Word), IMPL_DETAIL),
+ rustc_attr!(rustc_legacy_const_generics, Normal, template!(List: "N"), INTERNAL_UNSTABLE),
// ==========================================================================
// Internal attributes, Layout related:
// ==========================================================================
rustc_attr!(
- rustc_layout_scalar_valid_range_start, AssumedUsed, template!(List: "value"),
+ rustc_layout_scalar_valid_range_start, Normal, template!(List: "value"),
"the `#[rustc_layout_scalar_valid_range_start]` attribute is just used to enable \
niche optimizations in libcore and will never be stable",
),
rustc_attr!(
- rustc_layout_scalar_valid_range_end, AssumedUsed, template!(List: "value"),
+ rustc_layout_scalar_valid_range_end, Normal, template!(List: "value"),
"the `#[rustc_layout_scalar_valid_range_end]` attribute is just used to enable \
niche optimizations in libcore and will never be stable",
),
rustc_attr!(
- rustc_nonnull_optimization_guaranteed, AssumedUsed, template!(Word),
+ rustc_nonnull_optimization_guaranteed, Normal, template!(Word),
"the `#[rustc_nonnull_optimization_guaranteed]` attribute is just used to enable \
niche optimizations in libcore and will never be stable",
),
@@ -522,7 +501,7 @@
),
gated!(
// Used in resolve:
- prelude_import, AssumedUsed, template!(Word),
+ prelude_import, Normal, template!(Word),
"`#[prelude_import]` is for use by rustc only",
),
gated!(
@@ -530,7 +509,7 @@
"unboxed_closures are still evolving",
),
rustc_attr!(
- rustc_inherit_overflow_checks, AssumedUsed, template!(Word),
+ rustc_inherit_overflow_checks, Normal, template!(Word),
"the `#[rustc_inherit_overflow_checks]` attribute is just used to control \
overflow checking behavior of several libcore functions that are inlined \
across crates and will never be stable",
@@ -572,40 +551,41 @@
rustc_attr!(TEST, rustc_layout, Normal, template!(List: "field1, field2, ...")),
rustc_attr!(TEST, rustc_regions, Normal, template!(Word)),
rustc_attr!(
- TEST, rustc_error, AssumedUsed,
+ TEST, rustc_error, Normal,
template!(Word, List: "delay_span_bug_from_inside_query")
),
- rustc_attr!(TEST, rustc_dump_user_substs, AssumedUsed, template!(Word)),
- rustc_attr!(TEST, rustc_evaluate_where_clauses, AssumedUsed, template!(Word)),
- rustc_attr!(TEST, rustc_if_this_changed, AssumedUsed, template!(Word, List: "DepNode")),
- rustc_attr!(TEST, rustc_then_this_would_need, AssumedUsed, template!(List: "DepNode")),
+ rustc_attr!(TEST, rustc_dump_user_substs, Normal, template!(Word)),
+ rustc_attr!(TEST, rustc_evaluate_where_clauses, Normal, template!(Word)),
+ rustc_attr!(TEST, rustc_if_this_changed, Normal, template!(Word, List: "DepNode")),
+ rustc_attr!(TEST, rustc_then_this_would_need, Normal, template!(List: "DepNode")),
rustc_attr!(
- TEST, rustc_clean, AssumedUsed,
+ TEST, rustc_clean, Normal,
template!(List: r#"cfg = "...", /*opt*/ label = "...", /*opt*/ except = "...""#),
),
rustc_attr!(
- TEST, rustc_partition_reused, AssumedUsed,
+ TEST, rustc_partition_reused, Normal,
template!(List: r#"cfg = "...", module = "...""#),
),
rustc_attr!(
- TEST, rustc_partition_codegened, AssumedUsed,
+ TEST, rustc_partition_codegened, Normal,
template!(List: r#"cfg = "...", module = "...""#),
),
rustc_attr!(
- TEST, rustc_expected_cgu_reuse, AssumedUsed,
+ TEST, rustc_expected_cgu_reuse, Normal,
template!(List: r#"cfg = "...", module = "...", kind = "...""#),
),
- rustc_attr!(TEST, rustc_synthetic, AssumedUsed, template!(Word)),
- rustc_attr!(TEST, rustc_symbol_name, AssumedUsed, template!(Word)),
- rustc_attr!(TEST, rustc_polymorphize_error, AssumedUsed, template!(Word)),
- rustc_attr!(TEST, rustc_def_path, AssumedUsed, template!(Word)),
- rustc_attr!(TEST, rustc_mir, AssumedUsed, template!(List: "arg1, arg2, ...")),
- rustc_attr!(TEST, rustc_dump_program_clauses, AssumedUsed, template!(Word)),
- rustc_attr!(TEST, rustc_dump_env_program_clauses, AssumedUsed, template!(Word)),
- rustc_attr!(TEST, rustc_object_lifetime_default, AssumedUsed, template!(Word)),
+ rustc_attr!(TEST, rustc_synthetic, Normal, template!(Word)),
+ rustc_attr!(TEST, rustc_symbol_name, Normal, template!(Word)),
+ rustc_attr!(TEST, rustc_polymorphize_error, Normal, template!(Word)),
+ rustc_attr!(TEST, rustc_def_path, Normal, template!(Word)),
+ rustc_attr!(TEST, rustc_mir, Normal, template!(List: "arg1, arg2, ...")),
+ rustc_attr!(TEST, rustc_dump_program_clauses, Normal, template!(Word)),
+ rustc_attr!(TEST, rustc_dump_env_program_clauses, Normal, template!(Word)),
+ rustc_attr!(TEST, rustc_object_lifetime_default, Normal, template!(Word)),
+ rustc_attr!(TEST, rustc_dump_vtable, Normal, template!(Word)),
rustc_attr!(TEST, rustc_dummy, Normal, template!(Word /* doesn't matter*/)),
gated!(
- omit_gdb_pretty_printer_section, AssumedUsed, template!(Word),
+ omit_gdb_pretty_printer_section, Normal, template!(Word),
"the `#[omit_gdb_pretty_printer_section]` attribute is just used for the Rust test suite",
),
];
diff --git a/compiler/rustc_feature/src/removed.rs b/compiler/rustc_feature/src/removed.rs
index 29f4423..8e498a5 100644
--- a/compiler/rustc_feature/src/removed.rs
+++ b/compiler/rustc_feature/src/removed.rs
@@ -102,6 +102,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 const generic types (e.g. `struct Foo<const N: usize>(...);`).
+ (removed, const_generics, "1.34.0", Some(44580), None,
+ Some("removed in favor of `#![feature(adt_const_params]` and `#![feature(generic_const_exprs)]`")),
/// 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")),
@@ -111,7 +114,7 @@
Some("subsumed by `.await` syntax")),
/// Allows defining `existential type`s.
(removed, existential_type, "1.38.0", Some(63063), None,
- Some("removed in favor of `#![feature(min_type_alias_impl_trait)]`")),
+ Some("removed in favor of `#![feature(type_alias_impl_trait)]`")),
/// Allows using the macros:
/// + `__diagnostic_used`
/// + `__register_diagnostic`
@@ -123,11 +126,18 @@
/// Allows overlapping impls of marker traits.
(removed, overlapping_marker_traits, "1.42.0", Some(29864), None,
Some("removed in favor of `#![feature(marker_trait_attr)]`")),
+ /// Allows `T: ?const Trait` syntax in bounds.
+ (removed, const_trait_bound_opt_out, "1.42.0", Some(67794), None,
+ Some("Removed in favor of `~const` bound in #![feature(const_trait_impl)]")),
/// Allows `#[no_debug]`.
(removed, no_debug, "1.43.0", Some(29721), None, Some("removed due to lack of demand")),
+ /// Lazily evaluate constants. This allows constants to depend on type parameters.
+ (removed, lazy_normalization_consts, "1.46.0", Some(72219), None, Some("superseded by `generic_const_exprs`")),
/// Allows comparing raw pointers during const eval.
(removed, const_compare_raw_pointers, "1.46.0", Some(53020), None,
Some("cannot be allowed in const eval in any meaningful way")),
+ /// Allows non-trivial generic constants which have to be manually propagated upwards.
+ (removed, const_evaluatable_checked, "1.48.0", Some(76560), None, Some("renamed to `generic_const_exprs`")),
/// Allows using the `#[link_args]` attribute.
(removed, link_args, "1.53.0", Some(29596), None,
Some("removed in favor of using `-C link-arg=ARG` on command line, \
@@ -136,9 +146,12 @@
(removed, main, "1.53.0", Some(29634), None, None),
(removed, pub_macro_rules, "1.53.0", Some(78855), None,
Some("removed due to being incomplete, in particular it does not work across crates")),
- /// Allows the definition of `const` functions with some advanced features.
+ /// Allows the definition of `const` functions with some advanced features.
(removed, const_fn, "1.54.0", Some(57563), None,
Some("split into finer-grained feature gates")),
+ /// Allows using `#[plugin_registrar]` on functions.
+ (removed, plugin_registrar, "1.54.0", Some(29597), None,
+ Some("a __rustc_plugin_registrar symbol must now be defined instead")),
/// Allows `#[doc(include = "some-file")]`.
(removed, external_doc, "1.54.0", Some(44732), None,
@@ -152,6 +165,15 @@
(removed, impl_trait_in_bindings, "1.55.0", Some(63065), None,
Some("the implementation was not maintainable, the feature may get reintroduced once the current refactorings are done")),
+ /// Allows the use of type alias impl trait in function return positions
+ (removed, min_type_alias_impl_trait, "1.56.0", Some(63063), None,
+ Some("removed in favor of full type_alias_impl_trait")),
+
+ /// Allows `#[unwind(..)]`.
+ ///
+ /// Permits specifying whether a function should permit unwinding or abort on unwind.
+ (removed, unwind_attributes, "1.56.0", Some(58760), None, Some("use the C-unwind ABI instead")),
+
// -------------------------------------------------------------------------
// feature-group-end: removed features
// -------------------------------------------------------------------------
diff --git a/compiler/rustc_fs_util/Cargo.toml b/compiler/rustc_fs_util/Cargo.toml
index e4414c7..c417e97 100644
--- a/compiler/rustc_fs_util/Cargo.toml
+++ b/compiler/rustc_fs_util/Cargo.toml
@@ -1,5 +1,4 @@
[package]
-authors = ["The Rust Project Developers"]
name = "rustc_fs_util"
version = "0.0.0"
edition = "2018"
diff --git a/compiler/rustc_graphviz/Cargo.toml b/compiler/rustc_graphviz/Cargo.toml
index d07b75a..87c41ae 100644
--- a/compiler/rustc_graphviz/Cargo.toml
+++ b/compiler/rustc_graphviz/Cargo.toml
@@ -1,5 +1,4 @@
[package]
-authors = ["The Rust Project Developers"]
name = "rustc_graphviz"
version = "0.0.0"
edition = "2018"
diff --git a/compiler/rustc_hir/Cargo.toml b/compiler/rustc_hir/Cargo.toml
index d41b81f..c92551c 100644
--- a/compiler/rustc_hir/Cargo.toml
+++ b/compiler/rustc_hir/Cargo.toml
@@ -1,5 +1,4 @@
[package]
-authors = ["The Rust Project Developers"]
name = "rustc_hir"
version = "0.0.0"
edition = "2018"
diff --git a/compiler/rustc_hir/src/arena.rs b/compiler/rustc_hir/src/arena.rs
index b05ca38..3e8b98e 100644
--- a/compiler/rustc_hir/src/arena.rs
+++ b/compiler/rustc_hir/src/arena.rs
@@ -9,8 +9,8 @@
/// where `T` is the type listed. These impls will appear in the implement_ty_decoder! macro.
#[macro_export]
macro_rules! arena_types {
- ($macro:path, $args:tt, $tcx:lifetime) => (
- $macro!($args, [
+ ($macro:path, $tcx:lifetime) => (
+ $macro!([
// HIR types
[few] hir_krate: rustc_hir::Crate<$tcx>,
[] arm: rustc_hir::Arm<$tcx>,
@@ -29,11 +29,13 @@
[] fn_decl: rustc_hir::FnDecl<$tcx>,
[] foreign_item: rustc_hir::ForeignItem<$tcx>,
[few] foreign_item_ref: rustc_hir::ForeignItemRef<$tcx>,
+ [] impl_item: rustc_hir::ImplItem<$tcx>,
[] impl_item_ref: rustc_hir::ImplItemRef<$tcx>,
+ [] item: rustc_hir::Item<$tcx>,
[few] inline_asm: rustc_hir::InlineAsm<$tcx>,
[few] llvm_inline_asm: rustc_hir::LlvmInlineAsm<$tcx>,
[] local: rustc_hir::Local<$tcx>,
- [few] macro_def: rustc_hir::MacroDef<$tcx>,
+ [few] mod_: rustc_hir::Mod<$tcx>,
[] param: rustc_hir::Param<$tcx>,
[] pat: rustc_hir::Pat<$tcx>,
[] path: rustc_hir::Path<$tcx>,
@@ -42,6 +44,7 @@
[] qpath: rustc_hir::QPath<$tcx>,
[] stmt: rustc_hir::Stmt<$tcx>,
[] field_def: rustc_hir::FieldDef<$tcx>,
+ [] trait_item: rustc_hir::TraitItem<$tcx>,
[] trait_item_ref: rustc_hir::TraitItemRef,
[] ty: rustc_hir::Ty<$tcx>,
[] type_binding: rustc_hir::TypeBinding<$tcx>,
diff --git a/compiler/rustc_hir/src/def.rs b/compiler/rustc_hir/src/def.rs
index de10d88..853415c 100644
--- a/compiler/rustc_hir/src/def.rs
+++ b/compiler/rustc_hir/src/def.rs
@@ -307,7 +307,7 @@
/// We do however allow `Self` in repeat expression even if it is generic to not break code
/// which already works on stable while causing the `const_evaluatable_unchecked` future compat lint.
///
- /// FIXME(lazy_normalization_consts): Remove this bodge once that feature is stable.
+ /// FIXME(generic_const_exprs): Remove this bodge once that feature is stable.
SelfTy(
/// Optionally, the trait associated with this `Self` type.
Option<DefId>,
@@ -476,7 +476,7 @@
/// Returns an iterator over the items which are `Some`.
pub fn present_items(self) -> impl Iterator<Item = T> {
- IntoIter::new([self.type_ns, self.value_ns, self.macro_ns]).filter_map(|it| it)
+ IntoIter::new([self.type_ns, self.value_ns, self.macro_ns]).flatten()
}
}
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index 6aff2fd..21fe894 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -1,6 +1,5 @@
-// ignore-tidy-filelength
use crate::def::{CtorKind, DefKind, Res};
-use crate::def_id::DefId;
+use crate::def_id::{DefId, CRATE_DEF_ID};
crate use crate::hir_id::{HirId, ItemLocalId};
use crate::{itemlikevisit, LangItem};
@@ -12,6 +11,7 @@
use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::sync::{par_for_each_in, Send, Sync};
+use rustc_index::vec::IndexVec;
use rustc_macros::HashStable_Generic;
use rustc_span::source_map::Spanned;
use rustc_span::symbol::{kw, sym, Ident, Symbol};
@@ -253,11 +253,38 @@
pub span: Span,
}
+#[derive(Copy, Clone, Encodable, Debug, HashStable_Generic)]
+pub enum InferKind {
+ Const,
+ Type,
+}
+
+impl InferKind {
+ #[inline]
+ pub fn is_type(self) -> bool {
+ matches!(self, InferKind::Type)
+ }
+}
+
+#[derive(Encodable, Debug, HashStable_Generic)]
+pub struct InferArg {
+ pub hir_id: HirId,
+ pub kind: InferKind,
+ pub span: Span,
+}
+
+impl InferArg {
+ pub fn to_ty(&self) -> Ty<'_> {
+ Ty { kind: TyKind::Infer, span: self.span, hir_id: self.hir_id }
+ }
+}
+
#[derive(Debug, HashStable_Generic)]
pub enum GenericArg<'hir> {
Lifetime(Lifetime),
Type(Ty<'hir>),
Const(ConstArg),
+ Infer(InferArg),
}
impl GenericArg<'_> {
@@ -266,6 +293,7 @@
GenericArg::Lifetime(l) => l.span,
GenericArg::Type(t) => t.span,
GenericArg::Const(c) => c.span,
+ GenericArg::Infer(i) => i.span,
}
}
@@ -274,6 +302,7 @@
GenericArg::Lifetime(l) => l.hir_id,
GenericArg::Type(t) => t.hir_id,
GenericArg::Const(c) => c.value.hir_id,
+ GenericArg::Infer(i) => i.hir_id,
}
}
@@ -290,6 +319,7 @@
GenericArg::Lifetime(_) => "lifetime",
GenericArg::Type(_) => "type",
GenericArg::Const(_) => "constant",
+ GenericArg::Infer(_) => "inferred",
}
}
@@ -300,6 +330,7 @@
GenericArg::Const(_) => {
ast::ParamKindOrd::Const { unordered: feats.unordered_const_ty_params() }
}
+ GenericArg::Infer(_) => ast::ParamKindOrd::Infer,
}
}
}
@@ -341,27 +372,36 @@
break;
}
GenericArg::Const(_) => {}
+ GenericArg::Infer(_) => {}
}
}
}
panic!("GenericArgs::inputs: not a `Fn(T) -> U`");
}
- pub fn own_counts(&self) -> GenericParamCount {
- // 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();
+ #[inline]
+ pub fn has_type_params(&self) -> bool {
+ self.args.iter().any(|arg| matches!(arg, GenericArg::Type(_)))
+ }
- for arg in self.args {
- match arg {
- GenericArg::Lifetime(_) => own_counts.lifetimes += 1,
- GenericArg::Type(_) => own_counts.types += 1,
- GenericArg::Const(_) => own_counts.consts += 1,
- };
- }
+ #[inline]
+ pub fn num_type_params(&self) -> usize {
+ self.args.iter().filter(|arg| matches!(arg, GenericArg::Type(_))).count()
+ }
- own_counts
+ #[inline]
+ pub fn num_lifetime_params(&self) -> usize {
+ self.args.iter().filter(|arg| matches!(arg, GenericArg::Lifetime(_))).count()
+ }
+
+ #[inline]
+ pub fn has_lifetime_params(&self) -> bool {
+ self.args.iter().any(|arg| matches!(arg, GenericArg::Lifetime(_)))
+ }
+
+ #[inline]
+ pub fn num_generic_params(&self) -> usize {
+ self.args.iter().filter(|arg| !matches!(arg, GenericArg::Lifetime(_))).count()
}
/// The span encompassing the text inside the surrounding brackets.
@@ -401,6 +441,7 @@
Trait(PolyTraitRef<'hir>, TraitBoundModifier),
// FIXME(davidtwco): Introduce `PolyTraitRef::LangItem`
LangItemTrait(LangItem, Span, HirId, &'hir GenericArgs<'hir>),
+ Unsized(Span),
Outlives(Lifetime),
}
@@ -417,6 +458,7 @@
GenericBound::Trait(t, ..) => t.span,
GenericBound::LangItemTrait(_, span, ..) => *span,
GenericBound::Outlives(l) => l.span,
+ GenericBound::Unsized(span) => *span,
}
}
}
@@ -484,6 +526,7 @@
pub lifetimes: usize,
pub types: usize,
pub consts: usize,
+ pub infer: usize,
}
/// Represents lifetimes and type parameters attached to a declaration
@@ -627,37 +670,12 @@
/// [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/hir.html
#[derive(Debug)]
pub struct Crate<'hir> {
- pub item: Mod<'hir>,
- pub exported_macros: &'hir [MacroDef<'hir>],
- // Attributes from non-exported macros, kept only for collecting the library feature list.
- pub non_exported_macro_attrs: &'hir [Attribute],
-
- // N.B., we use a `BTreeMap` here so that `visit_all_items` iterates
- // 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 UI tests yield
- // slightly different results.
- pub items: BTreeMap<ItemId, Item<'hir>>,
-
- pub trait_items: BTreeMap<TraitItemId, TraitItem<'hir>>,
- pub impl_items: BTreeMap<ImplItemId, ImplItem<'hir>>,
- pub foreign_items: BTreeMap<ForeignItemId, ForeignItem<'hir>>,
+ pub owners: IndexVec<LocalDefId, Option<OwnerNode<'hir>>>,
pub bodies: BTreeMap<BodyId, Body<'hir>>,
- pub trait_impls: BTreeMap<DefId, Vec<LocalDefId>>,
-
- /// A list of the body ids written out in the order in which they
- /// appear in the crate. If you're going to process all the bodies
- /// in the crate, you should iterate over this list rather than the keys
- /// of bodies.
- pub body_ids: Vec<BodyId>,
/// A list of modules written out in the order in which they
/// appear in the crate. This includes the main crate module.
pub modules: BTreeMap<LocalDefId, ModuleItems>,
- /// A list of proc macro HirIds, written out in the order in which
- /// they are declared in the static array generated by proc_macro_harness.
- pub proc_macros: Vec<HirId>,
/// Map indicating what traits are in scope for places where this
/// is relevant; generated by resolve.
@@ -668,20 +686,24 @@
}
impl Crate<'hir> {
- pub fn item(&self, id: ItemId) -> &Item<'hir> {
- &self.items[&id]
+ pub fn module(&self) -> &'hir Mod<'hir> {
+ if let Some(OwnerNode::Crate(m)) = self.owners[CRATE_DEF_ID] { m } else { panic!() }
}
- pub fn trait_item(&self, id: TraitItemId) -> &TraitItem<'hir> {
- &self.trait_items[&id]
+ pub fn item(&self, id: ItemId) -> &'hir Item<'hir> {
+ self.owners[id.def_id].as_ref().unwrap().expect_item()
}
- pub fn impl_item(&self, id: ImplItemId) -> &ImplItem<'hir> {
- &self.impl_items[&id]
+ pub fn trait_item(&self, id: TraitItemId) -> &'hir TraitItem<'hir> {
+ self.owners[id.def_id].as_ref().unwrap().expect_trait_item()
}
- pub fn foreign_item(&self, id: ForeignItemId) -> &ForeignItem<'hir> {
- &self.foreign_items[&id]
+ pub fn impl_item(&self, id: ImplItemId) -> &'hir ImplItem<'hir> {
+ self.owners[id.def_id].as_ref().unwrap().expect_impl_item()
+ }
+
+ pub fn foreign_item(&self, id: ForeignItemId) -> &'hir ForeignItem<'hir> {
+ self.owners[id.def_id].as_ref().unwrap().expect_foreign_item()
}
pub fn body(&self, id: BodyId) -> &Body<'hir> {
@@ -702,20 +724,14 @@
where
V: itemlikevisit::ItemLikeVisitor<'hir>,
{
- for item in self.items.values() {
- visitor.visit_item(item);
- }
-
- for trait_item in self.trait_items.values() {
- visitor.visit_trait_item(trait_item);
- }
-
- for impl_item in self.impl_items.values() {
- visitor.visit_impl_item(impl_item);
- }
-
- for foreign_item in self.foreign_items.values() {
- visitor.visit_foreign_item(foreign_item);
+ for owner in self.owners.iter().filter_map(Option::as_ref) {
+ match owner {
+ OwnerNode::Item(item) => visitor.visit_item(item),
+ OwnerNode::ForeignItem(item) => visitor.visit_foreign_item(item),
+ OwnerNode::ImplItem(item) => visitor.visit_impl_item(item),
+ OwnerNode::TraitItem(item) => visitor.visit_trait_item(item),
+ OwnerNode::Crate(_) => {}
+ }
}
}
@@ -724,47 +740,20 @@
where
V: itemlikevisit::ParItemLikeVisitor<'hir> + Sync + Send,
{
- parallel!(
- {
- par_for_each_in(&self.items, |(_, item)| {
- visitor.visit_item(item);
- });
- },
- {
- par_for_each_in(&self.trait_items, |(_, trait_item)| {
- visitor.visit_trait_item(trait_item);
- });
- },
- {
- par_for_each_in(&self.impl_items, |(_, impl_item)| {
- visitor.visit_impl_item(impl_item);
- });
- },
- {
- par_for_each_in(&self.foreign_items, |(_, foreign_item)| {
- visitor.visit_foreign_item(foreign_item);
- });
- }
- );
+ par_for_each_in(&self.owners.raw, |owner| match owner {
+ Some(OwnerNode::Item(item)) => visitor.visit_item(item),
+ Some(OwnerNode::ForeignItem(item)) => visitor.visit_foreign_item(item),
+ Some(OwnerNode::ImplItem(item)) => visitor.visit_impl_item(item),
+ Some(OwnerNode::TraitItem(item)) => visitor.visit_trait_item(item),
+ Some(OwnerNode::Crate(_)) | None => {}
+ })
}
-}
-/// A macro definition, in this crate or imported from another.
-///
-/// Not parsed directly, but created on macro import or `macro_rules!` expansion.
-#[derive(Debug)]
-pub struct MacroDef<'hir> {
- pub ident: Ident,
- pub vis: Visibility<'hir>,
- pub def_id: LocalDefId,
- pub span: Span,
- pub ast: ast::MacroDef,
-}
-
-impl MacroDef<'_> {
- #[inline]
- pub fn hir_id(&self) -> HirId {
- HirId::make_owner(self.def_id)
+ pub fn items<'hir>(&'hir self) -> impl Iterator<Item = &'hir Item<'hir>> + 'hir {
+ self.owners.iter().filter_map(|owner| match owner {
+ Some(OwnerNode::Item(item)) => Some(*item),
+ _ => None,
+ })
}
}
@@ -946,7 +935,7 @@
/// Invariant: `pats.len() >= 2`.
Or(&'hir [Pat<'hir>]),
- /// A path pattern for an unit struct/variant or a (maybe-associated) constant.
+ /// A path pattern for a unit struct/variant or a (maybe-associated) constant.
Path(QPath<'hir>),
/// A tuple pattern (e.g., `(a, b)`).
@@ -1188,6 +1177,7 @@
#[derive(Debug, HashStable_Generic)]
pub enum Guard<'hir> {
If(&'hir Expr<'hir>),
+ // FIXME use ExprKind::Let for this.
IfLet(&'hir Pat<'hir>, &'hir Expr<'hir>),
}
@@ -1422,6 +1412,9 @@
/// These are usually found nested inside types (e.g., array lengths)
/// or expressions (e.g., repeat counts), and also used to define
/// explicit discriminant values for enum variants.
+///
+/// You can check if this anon const is a default in a const param
+/// `const N: usize = { ... }` with `tcx.hir().opt_const_param_default_param_hir_id(..)`
#[derive(Copy, Clone, PartialEq, Eq, Encodable, Debug, HashStable_Generic)]
pub struct AnonConst {
pub hir_id: HirId,
@@ -1451,6 +1444,7 @@
ExprKind::Type(..) | ExprKind::Cast(..) => ExprPrecedence::Cast,
ExprKind::DropTemps(ref expr, ..) => expr.precedence(),
ExprKind::If(..) => ExprPrecedence::If,
+ ExprKind::Let(..) => ExprPrecedence::Let,
ExprKind::Loop(..) => ExprPrecedence::Loop,
ExprKind::Match(..) => ExprPrecedence::Match,
ExprKind::Closure(..) => ExprPrecedence::Closure,
@@ -1521,6 +1515,7 @@
| ExprKind::Break(..)
| ExprKind::Continue(..)
| ExprKind::Ret(..)
+ | ExprKind::Let(..)
| ExprKind::Loop(..)
| ExprKind::Assign(..)
| ExprKind::InlineAsm(..)
@@ -1603,6 +1598,7 @@
| ExprKind::Break(..)
| ExprKind::Continue(..)
| ExprKind::Ret(..)
+ | ExprKind::Let(..)
| ExprKind::Loop(..)
| ExprKind::Assign(..)
| ExprKind::InlineAsm(..)
@@ -1694,6 +1690,11 @@
/// 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>),
+ /// A `let $pat = $expr` expression.
+ ///
+ /// These are not `Local` and only occur as expressions.
+ /// The `let Some(x) = foo()` in `if let Some(x) = foo()` is an example of `Let(..)`.
+ Let(&'hir Pat<'hir>, &'hir Expr<'hir>, Span),
/// An `if` block, with an optional else block.
///
/// I.e., `if <expr> { <expr> } else { <expr> }`.
@@ -1853,15 +1854,6 @@
pub enum MatchSource {
/// A `match _ { .. }`.
Normal,
- /// An `if let _ = _ { .. }` (optionally with `else { .. }`).
- IfLetDesugar { contains_else_clause: bool },
- /// An `if let _ = _ => { .. }` match guard.
- IfLetGuardDesugar,
- /// A `while _ { .. }` (which was desugared to a `loop { match _ { .. } }`).
- WhileDesugar,
- /// A `while let _ = _ { .. }` (which was desugared to a
- /// `loop { match _ { .. } }`).
- WhileLetDesugar,
/// A desugared `for _ in _ { .. }` loop.
ForLoopDesugar,
/// A desugared `?` operator.
@@ -1871,12 +1863,11 @@
}
impl MatchSource {
- pub fn name(self) -> &'static str {
+ #[inline]
+ pub const fn name(self) -> &'static str {
use MatchSource::*;
match self {
Normal => "match",
- IfLetDesugar { .. } | IfLetGuardDesugar => "if",
- WhileDesugar | WhileLetDesugar => "while",
ForLoopDesugar => "for",
TryDesugar => "?",
AwaitDesugar => ".await",
@@ -1891,8 +1882,6 @@
Loop,
/// A `while _ { .. }` loop.
While,
- /// A `while let _ = _ { .. }` loop.
- WhileLet,
/// A `for _ in _ { .. }` loop.
ForLoop,
}
@@ -1901,7 +1890,7 @@
pub fn name(self) -> &'static str {
match self {
LoopSource::Loop => "loop",
- LoopSource::While | LoopSource::WhileLet => "while",
+ LoopSource::While => "while",
LoopSource::ForLoop => "for",
}
}
@@ -2296,7 +2285,7 @@
///
/// Type parameters may be stored in each `PathSegment`.
Path(QPath<'hir>),
- /// A opaque type definition itself. This is currently only used for the
+ /// An opaque type definition itself. This is currently only used for the
/// `opaque type Foo: Trait` item that `impl Trait` in desugars to.
///
/// The generic argument list contains the lifetimes (and in the future
@@ -2359,6 +2348,7 @@
#[derive(Debug, HashStable_Generic)]
pub struct InlineAsm<'hir> {
pub template: &'hir [InlineAsmTemplatePiece],
+ pub template_strs: &'hir [(Symbol, Option<Symbol>, Span)],
pub operands: &'hir [(InlineAsmOperand<'hir>, Span)],
pub options: InlineAsmOptions,
pub line_spans: &'hir [Span],
@@ -2574,7 +2564,7 @@
pub type Visibility<'hir> = Spanned<VisibilityKind<'hir>>;
-#[derive(Debug)]
+#[derive(Copy, Clone, Debug)]
pub enum VisibilityKind<'hir> {
Public,
Crate(CrateSugar),
@@ -2720,6 +2710,15 @@
NotConst,
}
+impl fmt::Display for Constness {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.write_str(match *self {
+ Self::Const => "const",
+ Self::NotConst => "non-const",
+ })
+ }
+}
+
#[derive(Copy, Clone, Encodable, Debug, HashStable_Generic)]
pub struct FnHeader {
pub unsafety: Unsafety,
@@ -2754,6 +2753,8 @@
Const(&'hir Ty<'hir>, BodyId),
/// A function declaration.
Fn(FnSig<'hir>, Generics<'hir>, BodyId),
+ /// A MBE macro definition (`macro_rules!` or `macro`).
+ Macro(ast::MacroDef),
/// A module.
Mod(Mod<'hir>),
/// An external module, e.g. `extern { .. }`.
@@ -2819,6 +2820,7 @@
ItemKind::Static(..) => "static item",
ItemKind::Const(..) => "constant item",
ItemKind::Fn(..) => "function",
+ ItemKind::Macro(..) => "macro",
ItemKind::Mod(..) => "module",
ItemKind::ForeignMod { .. } => "extern block",
ItemKind::GlobalAsm(..) => "global asm item",
@@ -2954,6 +2956,145 @@
}
#[derive(Copy, Clone, Debug, HashStable_Generic)]
+pub enum OwnerNode<'hir> {
+ Item(&'hir Item<'hir>),
+ ForeignItem(&'hir ForeignItem<'hir>),
+ TraitItem(&'hir TraitItem<'hir>),
+ ImplItem(&'hir ImplItem<'hir>),
+ Crate(&'hir Mod<'hir>),
+}
+
+impl<'hir> OwnerNode<'hir> {
+ pub fn ident(&self) -> Option<Ident> {
+ match self {
+ OwnerNode::Item(Item { ident, .. })
+ | OwnerNode::ForeignItem(ForeignItem { ident, .. })
+ | OwnerNode::ImplItem(ImplItem { ident, .. })
+ | OwnerNode::TraitItem(TraitItem { ident, .. }) => Some(*ident),
+ OwnerNode::Crate(..) => None,
+ }
+ }
+
+ pub fn span(&self) -> Span {
+ match self {
+ OwnerNode::Item(Item { span, .. })
+ | OwnerNode::ForeignItem(ForeignItem { span, .. })
+ | OwnerNode::ImplItem(ImplItem { span, .. })
+ | OwnerNode::TraitItem(TraitItem { span, .. })
+ | OwnerNode::Crate(Mod { inner: span, .. }) => *span,
+ }
+ }
+
+ pub fn fn_decl(&self) -> Option<&FnDecl<'hir>> {
+ match self {
+ OwnerNode::TraitItem(TraitItem { kind: TraitItemKind::Fn(fn_sig, _), .. })
+ | OwnerNode::ImplItem(ImplItem { kind: ImplItemKind::Fn(fn_sig, _), .. })
+ | OwnerNode::Item(Item { kind: ItemKind::Fn(fn_sig, _, _), .. }) => Some(fn_sig.decl),
+ OwnerNode::ForeignItem(ForeignItem {
+ kind: ForeignItemKind::Fn(fn_decl, _, _),
+ ..
+ }) => Some(fn_decl),
+ _ => None,
+ }
+ }
+
+ pub fn body_id(&self) -> Option<BodyId> {
+ match self {
+ OwnerNode::TraitItem(TraitItem {
+ kind: TraitItemKind::Fn(_, TraitFn::Provided(body_id)),
+ ..
+ })
+ | OwnerNode::ImplItem(ImplItem { kind: ImplItemKind::Fn(_, body_id), .. })
+ | OwnerNode::Item(Item { kind: ItemKind::Fn(.., body_id), .. }) => Some(*body_id),
+ _ => None,
+ }
+ }
+
+ pub fn generics(&self) -> Option<&'hir Generics<'hir>> {
+ match self {
+ OwnerNode::TraitItem(TraitItem { generics, .. })
+ | OwnerNode::ImplItem(ImplItem { generics, .. }) => Some(generics),
+ OwnerNode::Item(item) => item.kind.generics(),
+ _ => None,
+ }
+ }
+
+ pub fn def_id(self) -> LocalDefId {
+ match self {
+ OwnerNode::Item(Item { def_id, .. })
+ | OwnerNode::TraitItem(TraitItem { def_id, .. })
+ | OwnerNode::ImplItem(ImplItem { def_id, .. })
+ | OwnerNode::ForeignItem(ForeignItem { def_id, .. }) => *def_id,
+ OwnerNode::Crate(..) => crate::CRATE_HIR_ID.owner,
+ }
+ }
+
+ pub fn expect_item(self) -> &'hir Item<'hir> {
+ match self {
+ OwnerNode::Item(n) => n,
+ _ => panic!(),
+ }
+ }
+
+ pub fn expect_foreign_item(self) -> &'hir ForeignItem<'hir> {
+ match self {
+ OwnerNode::ForeignItem(n) => n,
+ _ => panic!(),
+ }
+ }
+
+ pub fn expect_impl_item(self) -> &'hir ImplItem<'hir> {
+ match self {
+ OwnerNode::ImplItem(n) => n,
+ _ => panic!(),
+ }
+ }
+
+ pub fn expect_trait_item(self) -> &'hir TraitItem<'hir> {
+ match self {
+ OwnerNode::TraitItem(n) => n,
+ _ => panic!(),
+ }
+ }
+}
+
+impl<'hir> Into<OwnerNode<'hir>> for &'hir Item<'hir> {
+ fn into(self) -> OwnerNode<'hir> {
+ OwnerNode::Item(self)
+ }
+}
+
+impl<'hir> Into<OwnerNode<'hir>> for &'hir ForeignItem<'hir> {
+ fn into(self) -> OwnerNode<'hir> {
+ OwnerNode::ForeignItem(self)
+ }
+}
+
+impl<'hir> Into<OwnerNode<'hir>> for &'hir ImplItem<'hir> {
+ fn into(self) -> OwnerNode<'hir> {
+ OwnerNode::ImplItem(self)
+ }
+}
+
+impl<'hir> Into<OwnerNode<'hir>> for &'hir TraitItem<'hir> {
+ fn into(self) -> OwnerNode<'hir> {
+ OwnerNode::TraitItem(self)
+ }
+}
+
+impl<'hir> Into<Node<'hir>> for OwnerNode<'hir> {
+ fn into(self) -> Node<'hir> {
+ match self {
+ OwnerNode::Item(n) => Node::Item(n),
+ OwnerNode::ForeignItem(n) => Node::ForeignItem(n),
+ OwnerNode::ImplItem(n) => Node::ImplItem(n),
+ OwnerNode::TraitItem(n) => Node::TraitItem(n),
+ OwnerNode::Crate(n) => Node::Crate(n),
+ }
+ }
+}
+
+#[derive(Copy, Clone, Debug, HashStable_Generic)]
pub enum Node<'hir> {
Param(&'hir Param<'hir>),
Item(&'hir Item<'hir>),
@@ -2973,7 +3114,6 @@
Arm(&'hir Arm<'hir>),
Block(&'hir Block<'hir>),
Local(&'hir Local<'hir>),
- MacroDef(&'hir MacroDef<'hir>),
/// `Ctor` refers to the constructor of an enum variant or struct. Only tuple or unit variants
/// with synthesized constructors.
@@ -2984,9 +3124,25 @@
Visibility(&'hir Visibility<'hir>),
Crate(&'hir Mod<'hir>),
+
+ Infer(&'hir InferArg),
}
impl<'hir> Node<'hir> {
+ /// Get the identifier of this `Node`, if applicable.
+ ///
+ /// # Edge cases
+ ///
+ /// Calling `.ident()` on a [`Node::Ctor`] will return `None`
+ /// because `Ctor`s do not have identifiers themselves.
+ /// Instead, call `.ident()` on the parent struct/variant, like so:
+ ///
+ /// ```ignore (illustrative)
+ /// ctor
+ /// .ctor_hir_id()
+ /// .and_then(|ctor_id| tcx.hir().find(tcx.hir().get_parent_node(ctor_id)))
+ /// .and_then(|parent| parent.ident())
+ /// ```
pub fn ident(&self) -> Option<Ident> {
match self {
Node::TraitItem(TraitItem { ident, .. })
@@ -2994,9 +3150,25 @@
| Node::ForeignItem(ForeignItem { ident, .. })
| Node::Field(FieldDef { ident, .. })
| Node::Variant(Variant { ident, .. })
- | Node::MacroDef(MacroDef { ident, .. })
- | Node::Item(Item { ident, .. }) => Some(*ident),
- _ => None,
+ | Node::Item(Item { ident, .. })
+ | Node::PathSegment(PathSegment { ident, .. }) => Some(*ident),
+ Node::Lifetime(lt) => Some(lt.name.ident()),
+ Node::GenericParam(p) => Some(p.name.ident()),
+ Node::Param(..)
+ | Node::AnonConst(..)
+ | Node::Expr(..)
+ | Node::Stmt(..)
+ | Node::Block(..)
+ | Node::Ctor(..)
+ | Node::Pat(..)
+ | Node::Binding(..)
+ | Node::Arm(..)
+ | Node::Local(..)
+ | Node::Visibility(..)
+ | Node::Crate(..)
+ | Node::Ty(..)
+ | Node::TraitRef(..)
+ | Node::Infer(..) => None,
}
}
@@ -3038,8 +3210,7 @@
Node::Item(Item { def_id, .. })
| Node::TraitItem(TraitItem { def_id, .. })
| Node::ImplItem(ImplItem { def_id, .. })
- | Node::ForeignItem(ForeignItem { def_id, .. })
- | Node::MacroDef(MacroDef { def_id, .. }) => Some(HirId::make_owner(*def_id)),
+ | Node::ForeignItem(ForeignItem { def_id, .. }) => Some(HirId::make_owner(*def_id)),
Node::Field(FieldDef { hir_id, .. })
| Node::AnonConst(AnonConst { hir_id, .. })
| Node::Expr(Expr { hir_id, .. })
@@ -3052,6 +3223,7 @@
| Node::Local(Local { hir_id, .. })
| Node::Lifetime(Lifetime { hir_id, .. })
| Node::Param(Param { hir_id, .. })
+ | Node::Infer(InferArg { hir_id, .. })
| Node::GenericParam(GenericParam { hir_id, .. }) => Some(*hir_id),
Node::TraitRef(TraitRef { hir_ref_id, .. }) => Some(*hir_ref_id),
Node::PathSegment(PathSegment { hir_id, .. }) => *hir_id,
@@ -3061,8 +3233,13 @@
}
}
- /// Returns `Constness::Const` when this node is a const fn/impl.
- pub fn constness(&self) -> Constness {
+ /// Returns `Constness::Const` when this node is a const fn/impl/item,
+ ///
+ /// HACK(fee1-dead): or an associated type in a trait. This works because
+ /// only typeck cares about const trait predicates, so although the predicates
+ /// query would return const predicates when it does not need to be const,
+ /// it wouldn't have any effect.
+ pub fn constness_for_typeck(&self) -> Constness {
match self {
Node::Item(Item {
kind: ItemKind::Fn(FnSig { header: FnHeader { constness, .. }, .. }, ..),
@@ -3078,9 +3255,25 @@
})
| Node::Item(Item { kind: ItemKind::Impl(Impl { constness, .. }), .. }) => *constness,
+ Node::Item(Item { kind: ItemKind::Const(..), .. })
+ | Node::TraitItem(TraitItem { kind: TraitItemKind::Const(..), .. })
+ | Node::TraitItem(TraitItem { kind: TraitItemKind::Type(..), .. })
+ | Node::ImplItem(ImplItem { kind: ImplItemKind::Const(..), .. }) => Constness::Const,
+
_ => Constness::NotConst,
}
}
+
+ pub fn as_owner(self) -> Option<OwnerNode<'hir>> {
+ match self {
+ Node::Item(i) => Some(OwnerNode::Item(i)),
+ Node::ForeignItem(i) => Some(OwnerNode::ForeignItem(i)),
+ Node::TraitItem(i) => Some(OwnerNode::TraitItem(i)),
+ Node::ImplItem(i) => Some(OwnerNode::ImplItem(i)),
+ Node::Crate(i) => Some(OwnerNode::Crate(i)),
+ _ => None,
+ }
+ }
}
// Some nodes are used a lot. Make sure they don't unintentionally get bigger.
diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs
index c08f1f5..f4fbfd2 100644
--- a/compiler/rustc_hir/src/intravisit.rs
+++ b/compiler/rustc_hir/src/intravisit.rs
@@ -313,7 +313,7 @@
}
/// When invoking `visit_all_item_likes()`, you need to supply an
- /// item-like visitor. This method converts a "intra-visit"
+ /// item-like visitor. This method converts an "intra-visit"
/// visitor into an item-like visitor that walks the entire tree.
/// If you use this, you probably don't want to process the
/// contents of nested item-like things, since the outer loop will
@@ -436,11 +436,15 @@
fn visit_label(&mut self, label: &'v Label) {
walk_label(self, label)
}
+ fn visit_infer(&mut self, inf: &'v InferArg) {
+ walk_inf(self, inf);
+ }
fn visit_generic_arg(&mut self, generic_arg: &'v GenericArg<'v>) {
match generic_arg {
GenericArg::Lifetime(lt) => self.visit_lifetime(lt),
GenericArg::Type(ty) => self.visit_ty(ty),
GenericArg::Const(ct) => self.visit_anon_const(&ct.value),
+ GenericArg::Infer(inf) => self.visit_infer(inf),
}
}
fn visit_lifetime(&mut self, lifetime: &'v Lifetime) {
@@ -462,9 +466,6 @@
walk_assoc_type_binding(self, type_binding)
}
fn visit_attribute(&mut self, _id: HirId, _attr: &'v Attribute) {}
- fn visit_macro_def(&mut self, macro_def: &'v MacroDef<'v>) {
- walk_macro_def(self, macro_def)
- }
fn visit_vis(&mut self, vis: &'v Visibility<'v>) {
walk_vis(self, vis)
}
@@ -478,8 +479,8 @@
/// Walks the contents of a crate. See also `Crate::visit_all_items`.
pub fn walk_crate<'v, V: Visitor<'v>>(visitor: &mut V, krate: &'v Crate<'v>) {
- visitor.visit_mod(&krate.item, krate.item.inner, CRATE_HIR_ID);
- walk_list!(visitor, visit_macro_def, krate.exported_macros);
+ let top_mod = krate.module();
+ visitor.visit_mod(top_mod, top_mod.inner, CRATE_HIR_ID);
for (&id, attrs) in krate.attrs.iter() {
for a in *attrs {
visitor.visit_attribute(id, a)
@@ -487,11 +488,6 @@
}
}
-pub fn walk_macro_def<'v, V: Visitor<'v>>(visitor: &mut V, macro_def: &'v MacroDef<'v>) {
- visitor.visit_id(macro_def.hir_id());
- visitor.visit_ident(macro_def.ident);
-}
-
pub fn walk_mod<'v, V: Visitor<'v>>(visitor: &mut V, module: &'v Mod<'v>, mod_hir_id: HirId) {
visitor.visit_id(mod_hir_id);
for &item_id in module.item_ids {
@@ -581,6 +577,9 @@
item.span,
item.hir_id(),
),
+ ItemKind::Macro(_) => {
+ visitor.visit_id(item.hir_id());
+ }
ItemKind::Mod(ref module) => {
// `visit_mod()` takes care of visiting the `Item`'s `HirId`.
visitor.visit_mod(module, item.span, item.hir_id())
@@ -746,6 +745,10 @@
}
}
+pub fn walk_inf<'v, V: Visitor<'v>>(visitor: &mut V, inf: &'v InferArg) {
+ visitor.visit_id(inf.hir_id);
+}
+
pub fn walk_qpath<'v, V: Visitor<'v>>(
visitor: &mut V,
qpath: &'v QPath<'v>,
@@ -880,6 +883,7 @@
visitor.visit_generic_args(span, args);
}
GenericBound::Outlives(ref lifetime) => visitor.visit_lifetime(lifetime),
+ GenericBound::Unsized(_) => {}
}
}
@@ -1153,6 +1157,10 @@
ExprKind::DropTemps(ref subexpression) => {
visitor.visit_expr(subexpression);
}
+ ExprKind::Let(ref pat, ref expr, _) => {
+ visitor.visit_expr(expr);
+ visitor.visit_pat(pat);
+ }
ExprKind::If(ref cond, ref then, ref else_opt) => {
visitor.visit_expr(cond);
visitor.visit_expr(then);
diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs
index 28ae080..b85ed0c 100644
--- a/compiler/rustc_hir/src/lang_items.rs
+++ b/compiler/rustc_hir/src/lang_items.rs
@@ -38,7 +38,7 @@
// So you probably just want to nip down to the end.
macro_rules! language_item_table {
(
- $( $(#[$attr:meta])* $variant:ident $($group:expr)?, $module:ident :: $name:ident, $method:ident, $target:expr; )*
+ $( $(#[$attr:meta])* $variant:ident $($group:expr)?, $module:ident :: $name:ident, $method:ident, $target:expr, $generics:expr; )*
) => {
enum_from_u32! {
@@ -72,6 +72,12 @@
$( LangItem::$variant => expand_group!($($group)*), )*
}
}
+
+ pub fn required_generics(&self) -> GenericRequirement {
+ match self {
+ $( LangItem::$variant => $generics, )*
+ }
+ }
}
/// All of the language items, defined or not.
@@ -165,108 +171,108 @@
}
language_item_table! {
-// 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;
- Array, sym::array, array_impl, Target::Impl;
- Slice, sym::slice, slice_impl, Target::Impl;
- SliceU8, sym::slice_u8, slice_u8_impl, Target::Impl;
- StrAlloc, sym::str_alloc, str_alloc_impl, Target::Impl;
- SliceAlloc, sym::slice_alloc, slice_alloc_impl, Target::Impl;
- SliceU8Alloc, sym::slice_u8_alloc, slice_u8_alloc_impl, Target::Impl;
- ConstPtr, sym::const_ptr, const_ptr_impl, Target::Impl;
- MutPtr, sym::mut_ptr, mut_ptr_impl, Target::Impl;
- ConstSlicePtr, sym::const_slice_ptr, const_slice_ptr_impl, Target::Impl;
- MutSlicePtr, sym::mut_slice_ptr, mut_slice_ptr_impl, Target::Impl;
- I8, sym::i8, i8_impl, Target::Impl;
- I16, sym::i16, i16_impl, Target::Impl;
- I32, sym::i32, i32_impl, Target::Impl;
- I64, sym::i64, i64_impl, Target::Impl;
- I128, sym::i128, i128_impl, Target::Impl;
- Isize, sym::isize, isize_impl, Target::Impl;
- U8, sym::u8, u8_impl, Target::Impl;
- U16, sym::u16, u16_impl, Target::Impl;
- U32, sym::u32, u32_impl, Target::Impl;
- U64, sym::u64, u64_impl, Target::Impl;
- U128, sym::u128, u128_impl, Target::Impl;
- Usize, sym::usize, usize_impl, Target::Impl;
- F32, sym::f32, f32_impl, Target::Impl;
- F64, sym::f64, f64_impl, Target::Impl;
- F32Runtime, sym::f32_runtime, f32_runtime_impl, Target::Impl;
- F64Runtime, sym::f64_runtime, f64_runtime_impl, Target::Impl;
+// Variant name, Name, Method name, Target Generic requirements;
+ Bool, sym::bool, bool_impl, Target::Impl, GenericRequirement::None;
+ Char, sym::char, char_impl, Target::Impl, GenericRequirement::None;
+ Str, sym::str, str_impl, Target::Impl, GenericRequirement::None;
+ Array, sym::array, array_impl, Target::Impl, GenericRequirement::None;
+ Slice, sym::slice, slice_impl, Target::Impl, GenericRequirement::None;
+ SliceU8, sym::slice_u8, slice_u8_impl, Target::Impl, GenericRequirement::None;
+ StrAlloc, sym::str_alloc, str_alloc_impl, Target::Impl, GenericRequirement::None;
+ SliceAlloc, sym::slice_alloc, slice_alloc_impl, Target::Impl, GenericRequirement::None;
+ SliceU8Alloc, sym::slice_u8_alloc, slice_u8_alloc_impl, Target::Impl, GenericRequirement::None;
+ ConstPtr, sym::const_ptr, const_ptr_impl, Target::Impl, GenericRequirement::None;
+ MutPtr, sym::mut_ptr, mut_ptr_impl, Target::Impl, GenericRequirement::None;
+ ConstSlicePtr, sym::const_slice_ptr, const_slice_ptr_impl, Target::Impl, GenericRequirement::None;
+ MutSlicePtr, sym::mut_slice_ptr, mut_slice_ptr_impl, Target::Impl, GenericRequirement::None;
+ I8, sym::i8, i8_impl, Target::Impl, GenericRequirement::None;
+ I16, sym::i16, i16_impl, Target::Impl, GenericRequirement::None;
+ I32, sym::i32, i32_impl, Target::Impl, GenericRequirement::None;
+ I64, sym::i64, i64_impl, Target::Impl, GenericRequirement::None;
+ I128, sym::i128, i128_impl, Target::Impl, GenericRequirement::None;
+ Isize, sym::isize, isize_impl, Target::Impl, GenericRequirement::None;
+ U8, sym::u8, u8_impl, Target::Impl, GenericRequirement::None;
+ U16, sym::u16, u16_impl, Target::Impl, GenericRequirement::None;
+ U32, sym::u32, u32_impl, Target::Impl, GenericRequirement::None;
+ U64, sym::u64, u64_impl, Target::Impl, GenericRequirement::None;
+ U128, sym::u128, u128_impl, Target::Impl, GenericRequirement::None;
+ Usize, sym::usize, usize_impl, Target::Impl, GenericRequirement::None;
+ F32, sym::f32, f32_impl, Target::Impl, GenericRequirement::None;
+ F64, sym::f64, f64_impl, Target::Impl, GenericRequirement::None;
+ F32Runtime, sym::f32_runtime, f32_runtime_impl, Target::Impl, GenericRequirement::None;
+ F64Runtime, sym::f64_runtime, f64_runtime_impl, Target::Impl, GenericRequirement::None;
- Sized, sym::sized, sized_trait, Target::Trait;
- Unsize, sym::unsize, unsize_trait, Target::Trait;
+ Sized, sym::sized, sized_trait, Target::Trait, GenericRequirement::Exact(0);
+ Unsize, sym::unsize, unsize_trait, Target::Trait, GenericRequirement::Minimum(1);
/// Trait injected by `#[derive(PartialEq)]`, (i.e. "Partial EQ").
- StructuralPeq, sym::structural_peq, structural_peq_trait, Target::Trait;
+ StructuralPeq, sym::structural_peq, structural_peq_trait, Target::Trait, GenericRequirement::None;
/// Trait injected by `#[derive(Eq)]`, (i.e. "Total EQ"; no, I will not apologize).
- StructuralTeq, sym::structural_teq, structural_teq_trait, Target::Trait;
- Copy, sym::copy, copy_trait, Target::Trait;
- Clone, sym::clone, clone_trait, Target::Trait;
- Sync, sym::sync, sync_trait, Target::Trait;
- DiscriminantKind, sym::discriminant_kind, discriminant_kind_trait, Target::Trait;
+ StructuralTeq, sym::structural_teq, structural_teq_trait, Target::Trait, GenericRequirement::None;
+ Copy, sym::copy, copy_trait, Target::Trait, GenericRequirement::Exact(0);
+ Clone, sym::clone, clone_trait, Target::Trait, GenericRequirement::None;
+ Sync, sym::sync, sync_trait, Target::Trait, GenericRequirement::Exact(0);
+ DiscriminantKind, sym::discriminant_kind, discriminant_kind_trait, Target::Trait, GenericRequirement::None;
/// The associated item of the [`DiscriminantKind`] trait.
- Discriminant, sym::discriminant_type, discriminant_type, Target::AssocTy;
+ Discriminant, sym::discriminant_type, discriminant_type, Target::AssocTy, GenericRequirement::None;
- PointeeTrait, sym::pointee_trait, pointee_trait, Target::Trait;
- Metadata, sym::metadata_type, metadata_type, Target::AssocTy;
- DynMetadata, sym::dyn_metadata, dyn_metadata, Target::Struct;
+ PointeeTrait, sym::pointee_trait, pointee_trait, Target::Trait, GenericRequirement::None;
+ Metadata, sym::metadata_type, metadata_type, Target::AssocTy, GenericRequirement::None;
+ DynMetadata, sym::dyn_metadata, dyn_metadata, Target::Struct, GenericRequirement::None;
- Freeze, sym::freeze, freeze_trait, Target::Trait;
+ Freeze, sym::freeze, freeze_trait, Target::Trait, GenericRequirement::Exact(0);
- Drop, sym::drop, drop_trait, Target::Trait;
+ Drop, sym::drop, drop_trait, Target::Trait, GenericRequirement::None;
- CoerceUnsized, sym::coerce_unsized, coerce_unsized_trait, Target::Trait;
- DispatchFromDyn, sym::dispatch_from_dyn, dispatch_from_dyn_trait, Target::Trait;
+ CoerceUnsized, sym::coerce_unsized, coerce_unsized_trait, Target::Trait, GenericRequirement::Minimum(1);
+ DispatchFromDyn, sym::dispatch_from_dyn, dispatch_from_dyn_trait, Target::Trait, GenericRequirement::Minimum(1);
- Add(Op), sym::add, add_trait, Target::Trait;
- Sub(Op), sym::sub, sub_trait, Target::Trait;
- Mul(Op), sym::mul, mul_trait, Target::Trait;
- Div(Op), sym::div, div_trait, Target::Trait;
- Rem(Op), sym::rem, rem_trait, Target::Trait;
- Neg(Op), sym::neg, neg_trait, Target::Trait;
- Not(Op), sym::not, not_trait, Target::Trait;
- BitXor(Op), sym::bitxor, bitxor_trait, Target::Trait;
- BitAnd(Op), sym::bitand, bitand_trait, Target::Trait;
- BitOr(Op), sym::bitor, bitor_trait, Target::Trait;
- Shl(Op), sym::shl, shl_trait, Target::Trait;
- Shr(Op), sym::shr, shr_trait, Target::Trait;
- AddAssign(Op), sym::add_assign, add_assign_trait, Target::Trait;
- SubAssign(Op), sym::sub_assign, sub_assign_trait, Target::Trait;
- MulAssign(Op), sym::mul_assign, mul_assign_trait, Target::Trait;
- DivAssign(Op), sym::div_assign, div_assign_trait, Target::Trait;
- RemAssign(Op), sym::rem_assign, rem_assign_trait, Target::Trait;
- BitXorAssign(Op), sym::bitxor_assign, bitxor_assign_trait, Target::Trait;
- BitAndAssign(Op), sym::bitand_assign, bitand_assign_trait, Target::Trait;
- BitOrAssign(Op), sym::bitor_assign, bitor_assign_trait, Target::Trait;
- ShlAssign(Op), sym::shl_assign, shl_assign_trait, Target::Trait;
- ShrAssign(Op), sym::shr_assign, shr_assign_trait, Target::Trait;
- Index(Op), sym::index, index_trait, Target::Trait;
- IndexMut(Op), sym::index_mut, index_mut_trait, Target::Trait;
+ Add(Op), sym::add, add_trait, Target::Trait, GenericRequirement::Exact(1);
+ Sub(Op), sym::sub, sub_trait, Target::Trait, GenericRequirement::Exact(1);
+ Mul(Op), sym::mul, mul_trait, Target::Trait, GenericRequirement::Exact(1);
+ Div(Op), sym::div, div_trait, Target::Trait, GenericRequirement::Exact(1);
+ Rem(Op), sym::rem, rem_trait, Target::Trait, GenericRequirement::Exact(1);
+ Neg(Op), sym::neg, neg_trait, Target::Trait, GenericRequirement::Exact(0);
+ Not(Op), sym::not, not_trait, Target::Trait, GenericRequirement::Exact(0);
+ BitXor(Op), sym::bitxor, bitxor_trait, Target::Trait, GenericRequirement::Exact(1);
+ BitAnd(Op), sym::bitand, bitand_trait, Target::Trait, GenericRequirement::Exact(1);
+ BitOr(Op), sym::bitor, bitor_trait, Target::Trait, GenericRequirement::Exact(1);
+ Shl(Op), sym::shl, shl_trait, Target::Trait, GenericRequirement::Exact(1);
+ Shr(Op), sym::shr, shr_trait, Target::Trait, GenericRequirement::Exact(1);
+ AddAssign(Op), sym::add_assign, add_assign_trait, Target::Trait, GenericRequirement::Exact(1);
+ SubAssign(Op), sym::sub_assign, sub_assign_trait, Target::Trait, GenericRequirement::Exact(1);
+ MulAssign(Op), sym::mul_assign, mul_assign_trait, Target::Trait, GenericRequirement::Exact(1);
+ DivAssign(Op), sym::div_assign, div_assign_trait, Target::Trait, GenericRequirement::Exact(1);
+ RemAssign(Op), sym::rem_assign, rem_assign_trait, Target::Trait, GenericRequirement::Exact(1);
+ BitXorAssign(Op), sym::bitxor_assign, bitxor_assign_trait, Target::Trait, GenericRequirement::Exact(1);
+ BitAndAssign(Op), sym::bitand_assign, bitand_assign_trait, Target::Trait, GenericRequirement::Exact(1);
+ BitOrAssign(Op), sym::bitor_assign, bitor_assign_trait, Target::Trait, GenericRequirement::Exact(1);
+ ShlAssign(Op), sym::shl_assign, shl_assign_trait, Target::Trait, GenericRequirement::Exact(1);
+ ShrAssign(Op), sym::shr_assign, shr_assign_trait, Target::Trait, GenericRequirement::Exact(1);
+ Index(Op), sym::index, index_trait, Target::Trait, GenericRequirement::Exact(1);
+ IndexMut(Op), sym::index_mut, index_mut_trait, Target::Trait, GenericRequirement::Exact(1);
- UnsafeCell, sym::unsafe_cell, unsafe_cell_type, Target::Struct;
- VaList, sym::va_list, va_list, Target::Struct;
+ UnsafeCell, sym::unsafe_cell, unsafe_cell_type, Target::Struct, GenericRequirement::None;
+ VaList, sym::va_list, va_list, Target::Struct, GenericRequirement::None;
- Deref, sym::deref, deref_trait, Target::Trait;
- DerefMut, sym::deref_mut, deref_mut_trait, Target::Trait;
- DerefTarget, sym::deref_target, deref_target, Target::AssocTy;
- Receiver, sym::receiver, receiver_trait, Target::Trait;
+ Deref, sym::deref, deref_trait, Target::Trait, GenericRequirement::Exact(0);
+ DerefMut, sym::deref_mut, deref_mut_trait, Target::Trait, GenericRequirement::Exact(0);
+ DerefTarget, sym::deref_target, deref_target, Target::AssocTy, GenericRequirement::None;
+ Receiver, sym::receiver, receiver_trait, Target::Trait, GenericRequirement::None;
- Fn, kw::Fn, fn_trait, Target::Trait;
- FnMut, sym::fn_mut, fn_mut_trait, Target::Trait;
- FnOnce, sym::fn_once, fn_once_trait, Target::Trait;
+ Fn, kw::Fn, fn_trait, Target::Trait, GenericRequirement::Exact(1);
+ FnMut, sym::fn_mut, fn_mut_trait, Target::Trait, GenericRequirement::Exact(1);
+ FnOnce, sym::fn_once, fn_once_trait, Target::Trait, GenericRequirement::Exact(1);
- FnOnceOutput, sym::fn_once_output, fn_once_output, Target::AssocTy;
+ FnOnceOutput, sym::fn_once_output, fn_once_output, Target::AssocTy, GenericRequirement::None;
- Future, sym::future_trait, future_trait, Target::Trait;
- GeneratorState, sym::generator_state, gen_state, Target::Enum;
- Generator, sym::generator, gen_trait, Target::Trait;
- Unpin, sym::unpin, unpin_trait, Target::Trait;
- Pin, sym::pin, pin_type, Target::Struct;
+ Future, sym::future_trait, future_trait, Target::Trait, GenericRequirement::Exact(0);
+ GeneratorState, sym::generator_state, gen_state, Target::Enum, GenericRequirement::None;
+ Generator, sym::generator, gen_trait, Target::Trait, GenericRequirement::Minimum(1);
+ Unpin, sym::unpin, unpin_trait, Target::Trait, GenericRequirement::None;
+ Pin, sym::pin, pin_type, Target::Struct, GenericRequirement::None;
- PartialEq, sym::eq, eq_trait, Target::Trait;
- PartialOrd, sym::partial_ord, partial_ord_trait, Target::Trait;
+ PartialEq, sym::eq, eq_trait, Target::Trait, GenericRequirement::Exact(1);
+ PartialOrd, sym::partial_ord, partial_ord_trait, Target::Trait, GenericRequirement::Exact(1);
// A number of panic-related lang items. The `panic` item corresponds to divide-by-zero and
// various panic cases with `match`. The `panic_bounds_check` item is for indexing arrays.
@@ -275,77 +281,86 @@
// in the sense that a crate is not required to have it defined to use it, but a final product
// is required to define it somewhere. Additionally, there are restrictions on crates that use
// a weak lang item, but do not have it defined.
- Panic, sym::panic, panic_fn, Target::Fn;
- PanicStr, sym::panic_str, panic_str, Target::Fn;
- PanicBoundsCheck, sym::panic_bounds_check, panic_bounds_check_fn, Target::Fn;
- PanicInfo, sym::panic_info, panic_info, Target::Struct;
- PanicLocation, sym::panic_location, panic_location, Target::Struct;
- PanicImpl, sym::panic_impl, panic_impl, Target::Fn;
+ Panic, sym::panic, panic_fn, Target::Fn, GenericRequirement::None;
+ PanicFmt, sym::panic_fmt, panic_fmt, Target::Fn, GenericRequirement::None;
+ PanicStr, sym::panic_str, panic_str, Target::Fn, GenericRequirement::None;
+ ConstPanicFmt, sym::const_panic_fmt, const_panic_fmt, Target::Fn, GenericRequirement::None;
+ PanicBoundsCheck, sym::panic_bounds_check, panic_bounds_check_fn, Target::Fn, GenericRequirement::None;
+ PanicInfo, sym::panic_info, panic_info, Target::Struct, GenericRequirement::None;
+ PanicLocation, sym::panic_location, panic_location, Target::Struct, GenericRequirement::None;
+ PanicImpl, sym::panic_impl, panic_impl, Target::Fn, GenericRequirement::None;
/// libstd panic entry point. Necessary for const eval to be able to catch it
- BeginPanic, sym::begin_panic, begin_panic_fn, Target::Fn;
+ BeginPanic, sym::begin_panic, begin_panic_fn, Target::Fn, GenericRequirement::None;
+ BeginPanicFmt, sym::begin_panic_fmt, begin_panic_fmt, Target::Fn, GenericRequirement::None;
- ExchangeMalloc, sym::exchange_malloc, exchange_malloc_fn, Target::Fn;
- BoxFree, sym::box_free, box_free_fn, Target::Fn;
- DropInPlace, sym::drop_in_place, drop_in_place_fn, Target::Fn;
- Oom, sym::oom, oom, Target::Fn;
- AllocLayout, sym::alloc_layout, alloc_layout, Target::Struct;
+ ExchangeMalloc, sym::exchange_malloc, exchange_malloc_fn, Target::Fn, GenericRequirement::None;
+ BoxFree, sym::box_free, box_free_fn, Target::Fn, GenericRequirement::Minimum(1);
+ DropInPlace, sym::drop_in_place, drop_in_place_fn, Target::Fn, GenericRequirement::Minimum(1);
+ Oom, sym::oom, oom, Target::Fn, GenericRequirement::None;
+ AllocLayout, sym::alloc_layout, alloc_layout, Target::Struct, GenericRequirement::None;
- Start, sym::start, start_fn, Target::Fn;
+ Start, sym::start, start_fn, Target::Fn, GenericRequirement::None;
- EhPersonality, sym::eh_personality, eh_personality, Target::Fn;
- EhCatchTypeinfo, sym::eh_catch_typeinfo, eh_catch_typeinfo, Target::Static;
+ EhPersonality, sym::eh_personality, eh_personality, Target::Fn, GenericRequirement::None;
+ EhCatchTypeinfo, sym::eh_catch_typeinfo, eh_catch_typeinfo, Target::Static, GenericRequirement::None;
- OwnedBox, sym::owned_box, owned_box, Target::Struct;
+ OwnedBox, sym::owned_box, owned_box, Target::Struct, GenericRequirement::Minimum(1);
- PhantomData, sym::phantom_data, phantom_data, Target::Struct;
+ PhantomData, sym::phantom_data, phantom_data, Target::Struct, GenericRequirement::Exact(1);
- ManuallyDrop, sym::manually_drop, manually_drop, Target::Struct;
+ ManuallyDrop, sym::manually_drop, manually_drop, Target::Struct, GenericRequirement::None;
- MaybeUninit, sym::maybe_uninit, maybe_uninit, Target::Union;
+ MaybeUninit, sym::maybe_uninit, maybe_uninit, Target::Union, GenericRequirement::None;
/// Align offset for stride != 1; must not panic.
- AlignOffset, sym::align_offset, align_offset_fn, Target::Fn;
+ AlignOffset, sym::align_offset, align_offset_fn, Target::Fn, GenericRequirement::None;
- Termination, sym::termination, termination, Target::Trait;
+ Termination, sym::termination, termination, Target::Trait, GenericRequirement::None;
- Try, sym::Try, try_trait, Target::Trait;
+ Try, sym::Try, try_trait, Target::Trait, GenericRequirement::None;
- SliceLen, sym::slice_len_fn, slice_len_fn, Target::Method(MethodKind::Inherent);
+ SliceLen, sym::slice_len_fn, slice_len_fn, Target::Method(MethodKind::Inherent), GenericRequirement::None;
// Language items from AST lowering
- TryTraitFromResidual, sym::from_residual, from_residual_fn, Target::Method(MethodKind::Trait { body: false });
- TryTraitFromOutput, sym::from_output, from_output_fn, Target::Method(MethodKind::Trait { body: false });
- TryTraitBranch, sym::branch, branch_fn, Target::Method(MethodKind::Trait { body: false });
+ TryTraitFromResidual, sym::from_residual, from_residual_fn, Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None;
+ TryTraitFromOutput, sym::from_output, from_output_fn, Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None;
+ TryTraitBranch, sym::branch, branch_fn, Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None;
- PollReady, sym::Ready, poll_ready_variant, Target::Variant;
- PollPending, sym::Pending, poll_pending_variant, Target::Variant;
+ PollReady, sym::Ready, poll_ready_variant, Target::Variant, GenericRequirement::None;
+ PollPending, sym::Pending, poll_pending_variant, Target::Variant, GenericRequirement::None;
- FromGenerator, sym::from_generator, from_generator_fn, Target::Fn;
- GetContext, sym::get_context, get_context_fn, Target::Fn;
+ FromGenerator, sym::from_generator, from_generator_fn, Target::Fn, GenericRequirement::None;
+ GetContext, sym::get_context, get_context_fn, Target::Fn, GenericRequirement::None;
- FuturePoll, sym::poll, future_poll_fn, Target::Method(MethodKind::Trait { body: false });
+ FuturePoll, sym::poll, future_poll_fn, Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None;
- FromFrom, sym::from, from_fn, Target::Method(MethodKind::Trait { body: false });
+ FromFrom, sym::from, from_fn, Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None;
- OptionSome, sym::Some, option_some_variant, Target::Variant;
- OptionNone, sym::None, option_none_variant, Target::Variant;
+ OptionSome, sym::Some, option_some_variant, Target::Variant, GenericRequirement::None;
+ OptionNone, sym::None, option_none_variant, Target::Variant, GenericRequirement::None;
- ResultOk, sym::Ok, result_ok_variant, Target::Variant;
- ResultErr, sym::Err, result_err_variant, Target::Variant;
+ ResultOk, sym::Ok, result_ok_variant, Target::Variant, GenericRequirement::None;
+ ResultErr, sym::Err, result_err_variant, Target::Variant, GenericRequirement::None;
- ControlFlowContinue, sym::Continue, cf_continue_variant, Target::Variant;
- ControlFlowBreak, sym::Break, cf_break_variant, Target::Variant;
+ ControlFlowContinue, sym::Continue, cf_continue_variant, Target::Variant, GenericRequirement::None;
+ ControlFlowBreak, sym::Break, cf_break_variant, Target::Variant, GenericRequirement::None;
- IntoIterIntoIter, sym::into_iter, into_iter_fn, Target::Method(MethodKind::Trait { body: false });
- IteratorNext, sym::next, next_fn, Target::Method(MethodKind::Trait { body: false});
+ IntoIterIntoIter, sym::into_iter, into_iter_fn, Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None;
+ IteratorNext, sym::next, next_fn, Target::Method(MethodKind::Trait { body: false}), GenericRequirement::None;
- PinNewUnchecked, sym::new_unchecked, new_unchecked_fn, Target::Method(MethodKind::Inherent);
+ PinNewUnchecked, sym::new_unchecked, new_unchecked_fn, Target::Method(MethodKind::Inherent), GenericRequirement::None;
- RangeFrom, sym::RangeFrom, range_from_struct, Target::Struct;
- RangeFull, sym::RangeFull, range_full_struct, Target::Struct;
- RangeInclusiveStruct, sym::RangeInclusive, range_inclusive_struct, Target::Struct;
- RangeInclusiveNew, sym::range_inclusive_new, range_inclusive_new_method, Target::Method(MethodKind::Inherent);
- Range, sym::Range, range_struct, Target::Struct;
- RangeToInclusive, sym::RangeToInclusive, range_to_inclusive_struct, Target::Struct;
- RangeTo, sym::RangeTo, range_to_struct, Target::Struct;
+ RangeFrom, sym::RangeFrom, range_from_struct, Target::Struct, GenericRequirement::None;
+ RangeFull, sym::RangeFull, range_full_struct, Target::Struct, GenericRequirement::None;
+ RangeInclusiveStruct, sym::RangeInclusive, range_inclusive_struct, Target::Struct, GenericRequirement::None;
+ RangeInclusiveNew, sym::range_inclusive_new, range_inclusive_new_method, Target::Method(MethodKind::Inherent), GenericRequirement::None;
+ Range, sym::Range, range_struct, Target::Struct, GenericRequirement::None;
+ RangeToInclusive, sym::RangeToInclusive, range_to_inclusive_struct, Target::Struct, GenericRequirement::None;
+ RangeTo, sym::RangeTo, range_to_struct, Target::Struct, GenericRequirement::None;
+}
+
+pub enum GenericRequirement {
+ None,
+ Minimum(usize),
+ Exact(usize),
}
diff --git a/compiler/rustc_hir/src/stable_hash_impls.rs b/compiler/rustc_hir/src/stable_hash_impls.rs
index 5606075..422a106 100644
--- a/compiler/rustc_hir/src/stable_hash_impls.rs
+++ b/compiler/rustc_hir/src/stable_hash_impls.rs
@@ -1,8 +1,8 @@
use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey};
use crate::hir::{
- BodyId, Expr, ForeignItem, ForeignItemId, ImplItem, ImplItemId, Item, ItemId, MacroDef, Mod,
- TraitItem, TraitItemId, Ty, VisibilityKind,
+ BodyId, Expr, ForeignItem, ForeignItemId, ImplItem, ImplItemId, Item, ItemId, Mod, TraitItem,
+ TraitItemId, Ty, VisibilityKind,
};
use crate::hir_id::{HirId, ItemLocalId};
use rustc_span::def_id::DefPathHash;
@@ -190,16 +190,3 @@
});
}
}
-
-impl<HirCtx: crate::HashStableContext> HashStable<HirCtx> for MacroDef<'_> {
- fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) {
- let MacroDef { ident, def_id: _, ref ast, ref vis, span } = *self;
-
- hcx.hash_hir_item_like(|hcx| {
- ident.name.hash_stable(hcx, hasher);
- ast.hash_stable(hcx, hasher);
- vis.hash_stable(hcx, hasher);
- span.hash_stable(hcx, hasher);
- });
- }
-}
diff --git a/compiler/rustc_hir/src/target.rs b/compiler/rustc_hir/src/target.rs
index 473477b..29c948f 100644
--- a/compiler/rustc_hir/src/target.rs
+++ b/compiler/rustc_hir/src/target.rs
@@ -111,6 +111,7 @@
ItemKind::Static(..) => Target::Static,
ItemKind::Const(..) => Target::Const,
ItemKind::Fn(..) => Target::Fn,
+ ItemKind::Macro(..) => Target::MacroDef,
ItemKind::Mod(..) => Target::Mod,
ItemKind::ForeignMod { .. } => Target::ForeignMod,
ItemKind::GlobalAsm(..) => Target::GlobalAsm,
diff --git a/compiler/rustc_hir_pretty/Cargo.toml b/compiler/rustc_hir_pretty/Cargo.toml
index 1f7643e..c7510b7 100644
--- a/compiler/rustc_hir_pretty/Cargo.toml
+++ b/compiler/rustc_hir_pretty/Cargo.toml
@@ -1,5 +1,4 @@
[package]
-authors = ["The Rust Project Developers"]
name = "rustc_hir_pretty"
version = "0.0.0"
edition = "2018"
diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs
index 5c1739b..42e51f4 100644
--- a/compiler/rustc_hir_pretty/src/lib.rs
+++ b/compiler/rustc_hir_pretty/src/lib.rs
@@ -103,6 +103,7 @@
Node::TraitRef(a) => self.print_trait_ref(&a),
Node::Binding(a) | Node::Pat(a) => self.print_pat(&a),
Node::Arm(a) => self.print_arm(&a),
+ Node::Infer(_) => self.s.word("_"),
Node::Block(a) => {
// Containing cbox, will be closed by print-block at `}`.
self.cbox(INDENT_UNIT);
@@ -119,7 +120,6 @@
// printing.
Node::Ctor(..) => panic!("cannot print isolated Ctor"),
Node::Local(a) => self.print_local_decl(&a),
- Node::MacroDef(_) => panic!("cannot print MacroDef"),
Node::Crate(..) => panic!("cannot print Crate"),
}
}
@@ -169,7 +169,7 @@
// When printing the AST, we sometimes need to inject `#[no_std]` here.
// Since you can't compile the HIR, it's not necessary.
- s.print_mod(&krate.item, s.attrs(hir::CRATE_HIR_ID));
+ s.print_mod(&krate.module(), s.attrs(hir::CRATE_HIR_ID));
s.print_remaining_comments();
s.s.eof()
}
@@ -437,14 +437,14 @@
self.print_anon_const(e);
self.s.word(")");
}
- hir::TyKind::Infer => {
- self.s.word("_");
- }
hir::TyKind::Err => {
self.popen();
self.s.word("/*ERROR*/");
self.pclose();
}
+ hir::TyKind::Infer => {
+ self.s.word("_");
+ }
}
self.end()
}
@@ -641,6 +641,11 @@
self.end(); // need to close a box
self.ann.nested(self, Nested::Body(body));
}
+ hir::ItemKind::Macro(ref macro_def) => {
+ self.print_mac_def(macro_def, &item.ident, &item.span, |state| {
+ state.print_visibility(&item.vis)
+ });
+ }
hir::ItemKind::Mod(ref _mod) => {
self.head(visibility_qualified(&item.vis, "mod"));
self.print_ident(item.ident);
@@ -1091,53 +1096,30 @@
}
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)
- }
- hir::ExprKind::Match(ref expr, arms, _) => {
- // else if let desugared to match
- assert!(arms.len() == 2, "if let desugars to match with two arms");
-
- self.s.word(" else ");
- self.s.word("{");
-
- self.cbox(INDENT_UNIT);
- self.ibox(INDENT_UNIT);
- self.word_nbsp("match");
- self.print_expr_as_cond(&expr);
- self.s.space();
- self.bopen();
- for arm in arms {
- self.print_arm(arm);
- }
- self.bclose(expr.span);
-
- self.s.word("}");
- }
- // BLEAH, constraints would be great here
- _ => {
- panic!("print_if saw if with weird alternative");
- }
+ if let Some(els_inner) = els {
+ match els_inner.kind {
+ // Another `else if` block.
+ 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` block.
+ hir::ExprKind::Block(ref b, _) => {
+ self.cbox(INDENT_UNIT - 1);
+ self.ibox(0);
+ self.s.word(" else ");
+ self.print_block(&b)
+ }
+ // Constraints would be great here!
+ _ => {
+ panic!("print_if saw if with weird alternative");
}
}
- _ => {}
}
}
@@ -1164,34 +1146,49 @@
self.pclose()
}
- pub fn print_expr_maybe_paren(&mut self, expr: &hir::Expr<'_>, prec: i8) {
- let needs_par = expr.precedence().order() < prec;
+ fn print_expr_maybe_paren(&mut self, expr: &hir::Expr<'_>, prec: i8) {
+ self.print_expr_cond_paren(expr, expr.precedence().order() < prec)
+ }
+
+ /// Prints an expr using syntax that's acceptable in a condition position, such as the `cond` in
+ /// `if cond { ... }`.
+ pub fn print_expr_as_cond(&mut self, expr: &hir::Expr<'_>) {
+ self.print_expr_cond_paren(expr, Self::cond_needs_par(expr))
+ }
+
+ /// Prints `expr` or `(expr)` when `needs_par` holds.
+ fn print_expr_cond_paren(&mut self, expr: &hir::Expr<'_>, needs_par: bool) {
if needs_par {
self.popen();
}
- self.print_expr(expr);
+ if let hir::ExprKind::DropTemps(ref actual_expr) = expr.kind {
+ self.print_expr(actual_expr);
+ } else {
+ self.print_expr(expr);
+ }
if needs_par {
self.pclose();
}
}
- /// Print an expr using syntax that's acceptable in a condition position, such as the `cond` in
- /// `if cond { ... }`.
- pub fn print_expr_as_cond(&mut self, expr: &hir::Expr<'_>) {
- let needs_par = match expr.kind {
- // These cases need parens due to the parse error observed in #26461: `if return {}`
- // parses as the erroneous construct `if (return {})`, not `if (return) {}`.
- hir::ExprKind::Closure(..) | hir::ExprKind::Ret(..) | hir::ExprKind::Break(..) => true,
+ /// Print a `let pat = expr` expression.
+ fn print_let(&mut self, pat: &hir::Pat<'_>, expr: &hir::Expr<'_>) {
+ self.s.word("let ");
+ self.print_pat(pat);
+ self.s.space();
+ self.word_space("=");
+ let npals = || parser::needs_par_as_let_scrutinee(expr.precedence().order());
+ self.print_expr_cond_paren(expr, Self::cond_needs_par(expr) || npals())
+ }
+ // Does `expr` need parenthesis when printed in a condition position?
+ //
+ // These cases need parens due to the parse error observed in #26461: `if return {}`
+ // parses as the erroneous construct `if (return {})`, not `if (return) {}`.
+ fn cond_needs_par(expr: &hir::Expr<'_>) -> bool {
+ match expr.kind {
+ hir::ExprKind::Break(..) | hir::ExprKind::Closure(..) | hir::ExprKind::Ret(..) => true,
_ => contains_exterior_struct_lit(expr),
- };
-
- if needs_par {
- self.popen();
- }
- self.print_expr(expr);
- if needs_par {
- self.pclose();
}
}
@@ -1313,6 +1310,9 @@
(&hir::ExprKind::Cast { .. }, hir::BinOpKind::Lt | hir::BinOpKind::Shl) => {
parser::PREC_FORCE_PAREN
}
+ (&hir::ExprKind::Let { .. }, _) if !parser::needs_par_as_let_scrutinee(prec) => {
+ parser::PREC_FORCE_PAREN
+ }
_ => left_prec,
};
@@ -1356,8 +1356,8 @@
Options(ast::InlineAsmOptions),
}
- let mut args = vec![];
- args.push(AsmArg::Template(ast::InlineAsmTemplatePiece::to_string(&asm.template)));
+ let mut args =
+ vec![AsmArg::Template(ast::InlineAsmTemplatePiece::to_string(&asm.template))];
args.extend(asm.operands.iter().map(|(o, _)| AsmArg::Operand(o)));
if !asm.options.is_empty() {
args.push(AsmArg::Options(asm.options));
@@ -1530,6 +1530,9 @@
// Print `}`:
self.bclose_maybe_open(expr.span, true);
}
+ hir::ExprKind::Let(ref pat, ref scrutinee, _) => {
+ self.print_let(pat, scrutinee);
+ }
hir::ExprKind::If(ref test, ref blk, ref elseopt) => {
self.print_if(&test, &blk, elseopt.as_ref().map(|e| &**e));
}
@@ -1851,6 +1854,7 @@
GenericArg::Lifetime(_) => {}
GenericArg::Type(ty) => s.print_type(ty),
GenericArg::Const(ct) => s.print_anon_const(&ct.value),
+ GenericArg::Infer(_inf) => s.word("_"),
},
);
}
@@ -2228,6 +2232,9 @@
GenericBound::Outlives(lt) => {
self.print_lifetime(lt);
}
+ GenericBound::Unsized(_) => {
+ self.s.word("?Sized");
+ }
}
}
}
diff --git a/compiler/rustc_incremental/Cargo.toml b/compiler/rustc_incremental/Cargo.toml
index 85bf4dc..9156243 100644
--- a/compiler/rustc_incremental/Cargo.toml
+++ b/compiler/rustc_incremental/Cargo.toml
@@ -1,5 +1,4 @@
[package]
-authors = ["The Rust Project Developers"]
name = "rustc_incremental"
version = "0.0.0"
edition = "2018"
diff --git a/compiler/rustc_incremental/src/assert_dep_graph.rs b/compiler/rustc_incremental/src/assert_dep_graph.rs
index b5680be..0a558eb 100644
--- a/compiler/rustc_incremental/src/assert_dep_graph.rs
+++ b/compiler/rustc_incremental/src/assert_dep_graph.rs
@@ -123,7 +123,7 @@
let def_path_hash = self.tcx.def_path_hash(def_id.to_def_id());
let attrs = self.tcx.hir().attrs(hir_id);
for attr in attrs {
- if self.tcx.sess.check_name(attr, sym::rustc_if_this_changed) {
+ if attr.has_name(sym::rustc_if_this_changed) {
let dep_node_interned = self.argument(attr);
let dep_node = match dep_node_interned {
None => DepNode::from_def_path_hash(def_path_hash, DepKind::hir_owner),
@@ -138,7 +138,7 @@
},
};
self.if_this_changed.push((attr.span, def_id.to_def_id(), dep_node));
- } else if self.tcx.sess.check_name(attr, sym::rustc_then_this_would_need) {
+ } else if attr.has_name(sym::rustc_then_this_would_need) {
let dep_node_interned = self.argument(attr);
let dep_node = match dep_node_interned {
Some(n) => match DepNode::from_label_string(&n.as_str(), def_path_hash) {
diff --git a/compiler/rustc_incremental/src/assert_module_sources.rs b/compiler/rustc_incremental/src/assert_module_sources.rs
index 8220eb6..a5f3e45 100644
--- a/compiler/rustc_incremental/src/assert_module_sources.rs
+++ b/compiler/rustc_incremental/src/assert_module_sources.rs
@@ -57,27 +57,26 @@
impl AssertModuleSource<'tcx> {
fn check_attr(&self, attr: &ast::Attribute) {
- let (expected_reuse, comp_kind) =
- if self.tcx.sess.check_name(attr, sym::rustc_partition_reused) {
- (CguReuse::PreLto, ComparisonKind::AtLeast)
- } else if self.tcx.sess.check_name(attr, sym::rustc_partition_codegened) {
- (CguReuse::No, ComparisonKind::Exact)
- } else if self.tcx.sess.check_name(attr, sym::rustc_expected_cgu_reuse) {
- match self.field(attr, sym::kind) {
- sym::no => (CguReuse::No, ComparisonKind::Exact),
- sym::pre_dash_lto => (CguReuse::PreLto, ComparisonKind::Exact),
- sym::post_dash_lto => (CguReuse::PostLto, ComparisonKind::Exact),
- sym::any => (CguReuse::PreLto, ComparisonKind::AtLeast),
- other => {
- self.tcx.sess.span_fatal(
- attr.span,
- &format!("unknown cgu-reuse-kind `{}` specified", other),
- );
- }
+ let (expected_reuse, comp_kind) = if attr.has_name(sym::rustc_partition_reused) {
+ (CguReuse::PreLto, ComparisonKind::AtLeast)
+ } else if attr.has_name(sym::rustc_partition_codegened) {
+ (CguReuse::No, ComparisonKind::Exact)
+ } else if attr.has_name(sym::rustc_expected_cgu_reuse) {
+ match self.field(attr, sym::kind) {
+ sym::no => (CguReuse::No, ComparisonKind::Exact),
+ sym::pre_dash_lto => (CguReuse::PreLto, ComparisonKind::Exact),
+ sym::post_dash_lto => (CguReuse::PostLto, ComparisonKind::Exact),
+ sym::any => (CguReuse::PreLto, ComparisonKind::AtLeast),
+ other => {
+ self.tcx.sess.span_fatal(
+ attr.span,
+ &format!("unknown cgu-reuse-kind `{}` specified", other),
+ );
}
- } else {
- return;
- };
+ }
+ } else {
+ return;
+ };
if !self.tcx.sess.opts.debugging_opts.query_dep_graph {
self.tcx.sess.span_fatal(
diff --git a/compiler/rustc_incremental/src/persist/dirty_clean.rs b/compiler/rustc_incremental/src/persist/dirty_clean.rs
index 9abd4ea..c4dc0fb 100644
--- a/compiler/rustc_incremental/src/persist/dirty_clean.rs
+++ b/compiler/rustc_incremental/src/persist/dirty_clean.rs
@@ -159,7 +159,7 @@
impl DirtyCleanVisitor<'tcx> {
/// Possibly "deserialize" the attribute into a clean/dirty assertion
fn assertion_maybe(&mut self, item_id: LocalDefId, attr: &Attribute) -> Option<Assertion> {
- if !self.tcx.sess.check_name(attr, sym::rustc_clean) {
+ if !attr.has_name(sym::rustc_clean) {
// skip: not rustc_clean/dirty
return None;
}
@@ -427,7 +427,7 @@
impl FindAllAttrs<'tcx> {
fn is_active_attr(&mut self, attr: &Attribute) -> bool {
- if self.tcx.sess.check_name(attr, sym::rustc_clean) && check_config(self.tcx, attr) {
+ if attr.has_name(sym::rustc_clean) && check_config(self.tcx, attr) {
return true;
}
diff --git a/compiler/rustc_index/Cargo.toml b/compiler/rustc_index/Cargo.toml
index 4b1f0b8..e1a2b61 100644
--- a/compiler/rustc_index/Cargo.toml
+++ b/compiler/rustc_index/Cargo.toml
@@ -1,5 +1,4 @@
[package]
-authors = ["The Rust Project Developers"]
name = "rustc_index"
version = "0.0.0"
edition = "2018"
diff --git a/compiler/rustc_index/src/bit_set.rs b/compiler/rustc_index/src/bit_set.rs
index df77750..aeb3f99 100644
--- a/compiler/rustc_index/src/bit_set.rs
+++ b/compiler/rustc_index/src/bit_set.rs
@@ -16,6 +16,43 @@
pub const WORD_BYTES: usize = mem::size_of::<Word>();
pub const WORD_BITS: usize = WORD_BYTES * 8;
+pub trait BitRelations<Rhs> {
+ fn union(&mut self, other: &Rhs) -> bool;
+ fn subtract(&mut self, other: &Rhs) -> bool;
+ fn intersect(&mut self, other: &Rhs) -> bool;
+}
+
+macro_rules! bit_relations_inherent_impls {
+ () => {
+ /// Sets `self = self | other` and returns `true` if `self` changed
+ /// (i.e., if new bits were added).
+ pub fn union<Rhs>(&mut self, other: &Rhs) -> bool
+ where
+ Self: BitRelations<Rhs>,
+ {
+ <Self as BitRelations<Rhs>>::union(self, other)
+ }
+
+ /// Sets `self = self - other` and returns `true` if `self` changed.
+ /// (i.e., if any bits were removed).
+ pub fn subtract<Rhs>(&mut self, other: &Rhs) -> bool
+ where
+ Self: BitRelations<Rhs>,
+ {
+ <Self as BitRelations<Rhs>>::subtract(self, other)
+ }
+
+ /// Sets `self = self & other` and return `true` if `self` changed.
+ /// (i.e., if any bits were removed).
+ pub fn intersect<Rhs>(&mut self, other: &Rhs) -> bool
+ where
+ Self: BitRelations<Rhs>,
+ {
+ <Self as BitRelations<Rhs>>::intersect(self, other)
+ }
+ };
+}
+
/// A fixed-size bitset type with a dense representation.
///
/// NOTE: Use [`GrowableBitSet`] if you need support for resizing after creation.
@@ -134,25 +171,6 @@
new_word != word
}
- /// Sets `self = self | other` and returns `true` if `self` changed
- /// (i.e., if new bits were added).
- pub fn union(&mut self, other: &impl UnionIntoBitSet<T>) -> bool {
- other.union_into(self)
- }
-
- /// Sets `self = self - other` and returns `true` if `self` changed.
- /// (i.e., if any bits were removed).
- pub fn subtract(&mut self, other: &impl SubtractFromBitSet<T>) -> bool {
- other.subtract_from(self)
- }
-
- /// Sets `self = self & other` and return `true` if `self` changed.
- /// (i.e., if any bits were removed).
- pub fn intersect(&mut self, other: &BitSet<T>) -> bool {
- assert_eq!(self.domain_size, other.domain_size);
- bitwise(&mut self.words, &other.words, |a, b| a & b)
- }
-
/// Gets a slice of the underlying words.
pub fn words(&self) -> &[Word] {
&self.words
@@ -208,33 +226,208 @@
not_already
}
+
+ bit_relations_inherent_impls! {}
}
-/// This is implemented by all the bitsets so that BitSet::union() can be
-/// passed any type of bitset.
-pub trait UnionIntoBitSet<T: Idx> {
- // Performs `other = other | self`.
- fn union_into(&self, other: &mut BitSet<T>) -> bool;
-}
-
-/// This is implemented by all the bitsets so that BitSet::subtract() can be
-/// passed any type of bitset.
-pub trait SubtractFromBitSet<T: Idx> {
- // Performs `other = other - self`.
- fn subtract_from(&self, other: &mut BitSet<T>) -> bool;
-}
-
-impl<T: Idx> UnionIntoBitSet<T> for BitSet<T> {
- fn union_into(&self, other: &mut BitSet<T>) -> bool {
+// dense REL dense
+impl<T: Idx> BitRelations<BitSet<T>> for BitSet<T> {
+ fn union(&mut self, other: &BitSet<T>) -> bool {
assert_eq!(self.domain_size, other.domain_size);
- bitwise(&mut other.words, &self.words, |a, b| a | b)
+ bitwise(&mut self.words, &other.words, |a, b| a | b)
+ }
+
+ fn subtract(&mut self, other: &BitSet<T>) -> bool {
+ assert_eq!(self.domain_size, other.domain_size);
+ bitwise(&mut self.words, &other.words, |a, b| a & !b)
+ }
+
+ fn intersect(&mut self, other: &BitSet<T>) -> bool {
+ assert_eq!(self.domain_size, other.domain_size);
+ bitwise(&mut self.words, &other.words, |a, b| a & b)
}
}
-impl<T: Idx> SubtractFromBitSet<T> for BitSet<T> {
- fn subtract_from(&self, other: &mut BitSet<T>) -> bool {
- assert_eq!(self.domain_size, other.domain_size);
- bitwise(&mut other.words, &self.words, |a, b| a & !b)
+// Applies a function to mutate a bitset, and returns true if any
+// of the applications return true
+fn sequential_update<T: Idx>(
+ mut self_update: impl FnMut(T) -> bool,
+ it: impl Iterator<Item = T>,
+) -> bool {
+ let mut changed = false;
+ for elem in it {
+ changed |= self_update(elem);
+ }
+ changed
+}
+
+// Optimization of intersection for SparseBitSet that's generic
+// over the RHS
+fn sparse_intersect<T: Idx>(
+ set: &mut SparseBitSet<T>,
+ other_contains: impl Fn(&T) -> bool,
+) -> bool {
+ let size = set.elems.len();
+ set.elems.retain(|elem| other_contains(elem));
+ set.elems.len() != size
+}
+
+// Optimization of dense/sparse intersection. The resulting set is
+// guaranteed to be at most the size of the sparse set, and hence can be
+// represented as a sparse set. Therefore the sparse set is copied and filtered,
+// then returned as the new set.
+fn dense_sparse_intersect<T: Idx>(
+ dense: &BitSet<T>,
+ sparse: &SparseBitSet<T>,
+) -> (SparseBitSet<T>, bool) {
+ let mut sparse_copy = sparse.clone();
+ sparse_intersect(&mut sparse_copy, |el| dense.contains(*el));
+ let n = sparse_copy.len();
+ (sparse_copy, n != dense.count())
+}
+
+// hybrid REL dense
+impl<T: Idx> BitRelations<BitSet<T>> for HybridBitSet<T> {
+ fn union(&mut self, other: &BitSet<T>) -> bool {
+ assert_eq!(self.domain_size(), other.domain_size);
+ match self {
+ HybridBitSet::Sparse(sparse) => {
+ // `self` is sparse and `other` is dense. To
+ // merge them, we have two available strategies:
+ // * Densify `self` then merge other
+ // * Clone other then integrate bits from `self`
+ // The second strategy requires dedicated method
+ // since the usual `union` returns the wrong
+ // result. In the dedicated case the computation
+ // is slightly faster if the bits of the sparse
+ // bitset map to only few words of the dense
+ // representation, i.e. indices are near each
+ // other.
+ //
+ // Benchmarking seems to suggest that the second
+ // option is worth it.
+ let mut new_dense = other.clone();
+ let changed = new_dense.reverse_union_sparse(sparse);
+ *self = HybridBitSet::Dense(new_dense);
+ changed
+ }
+
+ HybridBitSet::Dense(dense) => dense.union(other),
+ }
+ }
+
+ fn subtract(&mut self, other: &BitSet<T>) -> bool {
+ assert_eq!(self.domain_size(), other.domain_size);
+ match self {
+ HybridBitSet::Sparse(sparse) => {
+ sequential_update(|elem| sparse.remove(elem), other.iter())
+ }
+ HybridBitSet::Dense(dense) => dense.subtract(other),
+ }
+ }
+
+ fn intersect(&mut self, other: &BitSet<T>) -> bool {
+ assert_eq!(self.domain_size(), other.domain_size);
+ match self {
+ HybridBitSet::Sparse(sparse) => sparse_intersect(sparse, |elem| other.contains(*elem)),
+ HybridBitSet::Dense(dense) => dense.intersect(other),
+ }
+ }
+}
+
+// dense REL hybrid
+impl<T: Idx> BitRelations<HybridBitSet<T>> for BitSet<T> {
+ fn union(&mut self, other: &HybridBitSet<T>) -> bool {
+ assert_eq!(self.domain_size, other.domain_size());
+ match other {
+ HybridBitSet::Sparse(sparse) => {
+ sequential_update(|elem| self.insert(elem), sparse.iter().cloned())
+ }
+ HybridBitSet::Dense(dense) => self.union(dense),
+ }
+ }
+
+ fn subtract(&mut self, other: &HybridBitSet<T>) -> bool {
+ assert_eq!(self.domain_size, other.domain_size());
+ match other {
+ HybridBitSet::Sparse(sparse) => {
+ sequential_update(|elem| self.remove(elem), sparse.iter().cloned())
+ }
+ HybridBitSet::Dense(dense) => self.subtract(dense),
+ }
+ }
+
+ fn intersect(&mut self, other: &HybridBitSet<T>) -> bool {
+ assert_eq!(self.domain_size, other.domain_size());
+ match other {
+ HybridBitSet::Sparse(sparse) => {
+ let (updated, changed) = dense_sparse_intersect(self, sparse);
+
+ // We can't directly assign the SparseBitSet to the BitSet, and
+ // doing `*self = updated.to_dense()` would cause a drop / reallocation. Instead,
+ // the BitSet is cleared and `updated` is copied into `self`.
+ self.clear();
+ for elem in updated.iter() {
+ self.insert(*elem);
+ }
+ changed
+ }
+ HybridBitSet::Dense(dense) => self.intersect(dense),
+ }
+ }
+}
+
+// hybrid REL hybrid
+impl<T: Idx> BitRelations<HybridBitSet<T>> for HybridBitSet<T> {
+ fn union(&mut self, other: &HybridBitSet<T>) -> bool {
+ assert_eq!(self.domain_size(), other.domain_size());
+ match self {
+ HybridBitSet::Sparse(_) => {
+ match other {
+ HybridBitSet::Sparse(other_sparse) => {
+ // Both sets are sparse. Add the elements in
+ // `other_sparse` to `self` one at a time. This
+ // may or may not cause `self` to be densified.
+ let mut changed = false;
+ for elem in other_sparse.iter() {
+ changed |= self.insert(*elem);
+ }
+ changed
+ }
+
+ HybridBitSet::Dense(other_dense) => self.union(other_dense),
+ }
+ }
+
+ HybridBitSet::Dense(self_dense) => self_dense.union(other),
+ }
+ }
+
+ fn subtract(&mut self, other: &HybridBitSet<T>) -> bool {
+ assert_eq!(self.domain_size(), other.domain_size());
+ match self {
+ HybridBitSet::Sparse(self_sparse) => {
+ sequential_update(|elem| self_sparse.remove(elem), other.iter())
+ }
+ HybridBitSet::Dense(self_dense) => self_dense.subtract(other),
+ }
+ }
+
+ fn intersect(&mut self, other: &HybridBitSet<T>) -> bool {
+ assert_eq!(self.domain_size(), other.domain_size());
+ match self {
+ HybridBitSet::Sparse(self_sparse) => {
+ sparse_intersect(self_sparse, |elem| other.contains(*elem))
+ }
+ HybridBitSet::Dense(self_dense) => match other {
+ HybridBitSet::Sparse(other_sparse) => {
+ let (updated, changed) = dense_sparse_intersect(self_dense, other_sparse);
+ *self = HybridBitSet::Sparse(updated);
+ changed
+ }
+ HybridBitSet::Dense(other_dense) => self_dense.intersect(other_dense),
+ },
+ }
}
}
@@ -441,28 +634,8 @@
fn iter(&self) -> slice::Iter<'_, T> {
self.elems.iter()
}
-}
-impl<T: Idx> UnionIntoBitSet<T> for SparseBitSet<T> {
- fn union_into(&self, other: &mut BitSet<T>) -> bool {
- assert_eq!(self.domain_size, other.domain_size);
- let mut changed = false;
- for elem in self.iter() {
- changed |= other.insert(*elem);
- }
- changed
- }
-}
-
-impl<T: Idx> SubtractFromBitSet<T> for SparseBitSet<T> {
- fn subtract_from(&self, other: &mut BitSet<T>) -> bool {
- assert_eq!(self.domain_size, other.domain_size);
- let mut changed = false;
- for elem in self.iter() {
- changed |= other.remove(*elem);
- }
- changed
- }
+ bit_relations_inherent_impls! {}
}
/// A fixed-size bitset type with a hybrid representation: sparse when there
@@ -579,48 +752,6 @@
}
}
- pub fn union(&mut self, other: &HybridBitSet<T>) -> bool {
- match self {
- HybridBitSet::Sparse(self_sparse) => {
- match other {
- HybridBitSet::Sparse(other_sparse) => {
- // Both sets are sparse. Add the elements in
- // `other_sparse` to `self` one at a time. This
- // may or may not cause `self` to be densified.
- assert_eq!(self.domain_size(), other.domain_size());
- let mut changed = false;
- for elem in other_sparse.iter() {
- changed |= self.insert(*elem);
- }
- changed
- }
- HybridBitSet::Dense(other_dense) => {
- // `self` is sparse and `other` is dense. To
- // merge them, we have two available strategies:
- // * Densify `self` then merge other
- // * Clone other then integrate bits from `self`
- // The second strategy requires dedicated method
- // since the usual `union` returns the wrong
- // result. In the dedicated case the computation
- // is slightly faster if the bits of the sparse
- // bitset map to only few words of the dense
- // representation, i.e. indices are near each
- // other.
- //
- // Benchmarking seems to suggest that the second
- // option is worth it.
- let mut new_dense = other_dense.clone();
- let changed = new_dense.reverse_union_sparse(self_sparse);
- *self = HybridBitSet::Dense(new_dense);
- changed
- }
- }
- }
-
- HybridBitSet::Dense(self_dense) => self_dense.union(other),
- }
- }
-
/// Converts to a dense set, consuming itself in the process.
pub fn to_dense(self) -> BitSet<T> {
match self {
@@ -635,24 +766,8 @@
HybridBitSet::Dense(dense) => HybridIter::Dense(dense.iter()),
}
}
-}
-impl<T: Idx> UnionIntoBitSet<T> for HybridBitSet<T> {
- fn union_into(&self, other: &mut BitSet<T>) -> bool {
- match self {
- HybridBitSet::Sparse(sparse) => sparse.union_into(other),
- HybridBitSet::Dense(dense) => dense.union_into(other),
- }
- }
-}
-
-impl<T: Idx> SubtractFromBitSet<T> for HybridBitSet<T> {
- fn subtract_from(&self, other: &mut BitSet<T>) -> bool {
- match self {
- HybridBitSet::Sparse(sparse) => sparse.subtract_from(other),
- HybridBitSet::Dense(dense) => dense.subtract_from(other),
- }
- }
+ bit_relations_inherent_impls! {}
}
pub enum HybridIter<'a, T: Idx> {
@@ -974,6 +1089,26 @@
self.ensure_row(row).insert(column)
}
+ /// Sets the cell at `(row, column)` to false. Put another way, delete
+ /// `column` from the bitset for `row`. Has no effect if `row` does not
+ /// exist.
+ ///
+ /// Returns `true` if this changed the matrix.
+ pub fn remove(&mut self, row: R, column: C) -> bool {
+ match self.rows.get_mut(row) {
+ Some(Some(row)) => row.remove(column),
+ _ => false,
+ }
+ }
+
+ /// Sets all columns at `row` to false. Has no effect if `row` does
+ /// not exist.
+ pub fn clear(&mut self, row: R) {
+ if let Some(Some(row)) = self.rows.get_mut(row) {
+ row.clear();
+ }
+ }
+
/// Do the bits from `row` contain `column`? Put another way, is
/// the matrix cell at `(row, column)` true? Put yet another way,
/// if the matrix represents (transitive) reachability, can
@@ -1002,11 +1137,6 @@
}
}
- /// Union a row, `from`, into the `into` row.
- pub fn union_into_row(&mut self, into: R, from: &HybridBitSet<C>) -> bool {
- self.ensure_row(into).union(from)
- }
-
/// Insert all bits in the given row.
pub fn insert_all_into_row(&mut self, row: R) {
self.ensure_row(row).insert_all();
@@ -1025,6 +1155,45 @@
pub fn row(&self, row: R) -> Option<&HybridBitSet<C>> {
if let Some(Some(row)) = self.rows.get(row) { Some(row) } else { None }
}
+
+ /// Interescts `row` with `set`. `set` can be either `BitSet` or
+ /// `HybridBitSet`. Has no effect if `row` does not exist.
+ ///
+ /// Returns true if the row was changed.
+ pub fn intersect_row<Set>(&mut self, row: R, set: &Set) -> bool
+ where
+ HybridBitSet<C>: BitRelations<Set>,
+ {
+ match self.rows.get_mut(row) {
+ Some(Some(row)) => row.intersect(set),
+ _ => false,
+ }
+ }
+
+ /// Subtracts `set from `row`. `set` can be either `BitSet` or
+ /// `HybridBitSet`. Has no effect if `row` does not exist.
+ ///
+ /// Returns true if the row was changed.
+ pub fn subtract_row<Set>(&mut self, row: R, set: &Set) -> bool
+ where
+ HybridBitSet<C>: BitRelations<Set>,
+ {
+ match self.rows.get_mut(row) {
+ Some(Some(row)) => row.subtract(set),
+ _ => false,
+ }
+ }
+
+ /// Unions `row` with `set`. `set` can be either `BitSet` or
+ /// `HybridBitSet`.
+ ///
+ /// Returns true if the row was changed.
+ pub fn union_row<Set>(&mut self, row: R, set: &Set) -> bool
+ where
+ HybridBitSet<C>: BitRelations<Set>,
+ {
+ self.ensure_row(row).union(set)
+ }
}
#[inline]
diff --git a/compiler/rustc_index/src/bit_set/tests.rs b/compiler/rustc_index/src/bit_set/tests.rs
index c11b98e..aebc6d0 100644
--- a/compiler/rustc_index/src/bit_set/tests.rs
+++ b/compiler/rustc_index/src/bit_set/tests.rs
@@ -104,18 +104,40 @@
assert!(dense10.superset(&dense10)); // dense + dense (self)
assert!(dense256.superset(&dense10)); // dense + dense
- let mut hybrid = sparse038;
+ let mut hybrid = sparse038.clone();
assert!(!sparse01358.union(&hybrid)); // no change
assert!(hybrid.union(&sparse01358));
assert!(hybrid.superset(&sparse01358) && sparse01358.superset(&hybrid));
- assert!(!dense10.union(&sparse01358));
assert!(!dense256.union(&dense10));
- let mut dense = dense10;
+
+ // dense / sparse where dense superset sparse
+ assert!(!dense10.clone().union(&sparse01358));
+ assert!(sparse01358.clone().union(&dense10));
+ assert!(dense10.clone().intersect(&sparse01358));
+ assert!(!sparse01358.clone().intersect(&dense10));
+ assert!(dense10.clone().subtract(&sparse01358));
+ assert!(sparse01358.clone().subtract(&dense10));
+
+ // dense / sparse where sparse superset dense
+ let dense038 = sparse038.to_dense();
+ assert!(!sparse01358.clone().union(&dense038));
+ assert!(dense038.clone().union(&sparse01358));
+ assert!(sparse01358.clone().intersect(&dense038));
+ assert!(!dense038.clone().intersect(&sparse01358));
+ assert!(sparse01358.clone().subtract(&dense038));
+ assert!(dense038.clone().subtract(&sparse01358));
+
+ let mut dense = dense10.clone();
assert!(dense.union(&dense256));
assert!(dense.superset(&dense256) && dense256.superset(&dense));
assert!(hybrid.union(&dense256));
assert!(hybrid.superset(&dense256) && dense256.superset(&hybrid));
+ assert!(!dense10.clone().intersect(&dense256));
+ assert!(dense256.clone().intersect(&dense10));
+ assert!(dense10.clone().subtract(&dense256));
+ assert!(dense256.clone().subtract(&dense10));
+
assert_eq!(dense256.iter().count(), 256);
let mut dense0 = dense256;
for i in 0..256 {
@@ -282,6 +304,72 @@
assert!(iter.next().is_none());
}
+#[test]
+fn sparse_matrix_operations() {
+ let mut matrix: SparseBitMatrix<usize, usize> = SparseBitMatrix::new(100);
+ matrix.insert(3, 22);
+ matrix.insert(3, 75);
+ matrix.insert(2, 99);
+ matrix.insert(4, 0);
+
+ let mut disjoint: HybridBitSet<usize> = HybridBitSet::new_empty(100);
+ disjoint.insert(33);
+
+ let mut superset = HybridBitSet::new_empty(100);
+ superset.insert(22);
+ superset.insert(75);
+ superset.insert(33);
+
+ let mut subset = HybridBitSet::new_empty(100);
+ subset.insert(22);
+
+ // SparseBitMatrix::remove
+ {
+ let mut matrix = matrix.clone();
+ matrix.remove(3, 22);
+ assert!(!matrix.row(3).unwrap().contains(22));
+ matrix.remove(0, 0);
+ assert!(matrix.row(0).is_none());
+ }
+
+ // SparseBitMatrix::clear
+ {
+ let mut matrix = matrix.clone();
+ matrix.clear(3);
+ assert!(!matrix.row(3).unwrap().contains(75));
+ matrix.clear(0);
+ assert!(matrix.row(0).is_none());
+ }
+
+ // SparseBitMatrix::intersect_row
+ {
+ let mut matrix = matrix.clone();
+ assert!(!matrix.intersect_row(3, &superset));
+ assert!(matrix.intersect_row(3, &subset));
+ matrix.intersect_row(0, &disjoint);
+ assert!(matrix.row(0).is_none());
+ }
+
+ // SparseBitMatrix::subtract_row
+ {
+ let mut matrix = matrix.clone();
+ assert!(!matrix.subtract_row(3, &disjoint));
+ assert!(matrix.subtract_row(3, &subset));
+ assert!(matrix.subtract_row(3, &superset));
+ matrix.intersect_row(0, &disjoint);
+ assert!(matrix.row(0).is_none());
+ }
+
+ // SparseBitMatrix::union_row
+ {
+ let mut matrix = matrix.clone();
+ assert!(!matrix.union_row(3, &subset));
+ assert!(matrix.union_row(3, &disjoint));
+ matrix.union_row(0, &disjoint);
+ assert!(matrix.row(0).is_some());
+ }
+}
+
/// Merge dense hybrid set into empty sparse hybrid set.
#[bench]
fn union_hybrid_sparse_empty_to_dense(b: &mut Bencher) {
diff --git a/compiler/rustc_infer/Cargo.toml b/compiler/rustc_infer/Cargo.toml
index 9333731..15649bb 100644
--- a/compiler/rustc_infer/Cargo.toml
+++ b/compiler/rustc_infer/Cargo.toml
@@ -1,5 +1,4 @@
[package]
-authors = ["The Rust Project Developers"]
name = "rustc_infer"
version = "0.0.0"
edition = "2018"
diff --git a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
index 448dd66..934ada9 100644
--- a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
+++ b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
@@ -470,7 +470,7 @@
{
let needs_canonical_flags = if canonicalize_region_mode.any() {
TypeFlags::NEEDS_INFER |
- TypeFlags::HAS_FREE_REGIONS | // `HAS_RE_PLACEHOLDER` implies `HAS_FREE_REGIONS`
+ TypeFlags::HAS_POTENTIAL_FREE_REGIONS | // `HAS_RE_PLACEHOLDER` implies `HAS_POTENTIAL_FREE_REGIONS`
TypeFlags::HAS_TY_PLACEHOLDER |
TypeFlags::HAS_CT_PLACEHOLDER
} else {
diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs
index c3c28d7..6a97a6c 100644
--- a/compiler/rustc_infer/src/infer/canonical/query_response.rs
+++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs
@@ -678,7 +678,7 @@
fn const_equate(&mut self, _a: &'tcx Const<'tcx>, _b: &'tcx Const<'tcx>) {
span_bug!(
self.cause.span(self.infcx.tcx),
- "lazy_normalization_consts: unreachable `const_equate`"
+ "generic_const_exprs: unreachable `const_equate`"
);
}
diff --git a/compiler/rustc_infer/src/infer/combine.rs b/compiler/rustc_infer/src/infer/combine.rs
index 3a11b5a..a0ee212 100644
--- a/compiler/rustc_infer/src/infer/combine.rs
+++ b/compiler/rustc_infer/src/infer/combine.rs
@@ -22,7 +22,6 @@
// is also useful to track which value is the "expected" value in
// terms of error reporting.
-use super::equate::Equate;
use super::glb::Glb;
use super::lub::Lub;
use super::sub::Sub;
@@ -30,6 +29,7 @@
use super::unify_key::replace_if_possible;
use super::unify_key::{ConstVarValue, ConstVariableValue};
use super::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
+use super::{equate::Equate, type_variable::Diverging};
use super::{InferCtxt, MiscVariable, TypeTrace};
use crate::traits::{Obligation, PredicateObligations};
@@ -129,6 +129,8 @@
where
R: ConstEquateRelation<'tcx>,
{
+ let a = self.tcx.expose_default_const_substs(a);
+ let b = self.tcx.expose_default_const_substs(b);
debug!("{}.consts({:?}, {:?})", relation.tag(), a, b);
if a == b {
return Ok(a);
@@ -200,7 +202,7 @@
/// A good example of this is the following:
///
/// ```rust
- /// #![feature(const_generics)]
+ /// #![feature(generic_const_exprs)]
///
/// fn bind<const N: usize>(value: [u8; N]) -> [u8; 3 + 4] {
/// todo!()
@@ -643,8 +645,13 @@
.inner
.borrow_mut()
.type_variables()
- .new_var(self.for_universe, false, origin);
+ .new_var(self.for_universe, Diverging::NotDiverging, origin);
let u = self.tcx().mk_ty_var(new_var_id);
+
+ // Record that we replaced `vid` with `new_var_id` as part of a generalization
+ // operation. This is needed to detect cyclic types. To see why, see the
+ // docs in the `type_variables` module.
+ self.infcx.inner.borrow_mut().type_variables().sub(vid, new_var_id);
debug!("generalize: replacing original vid={:?} with new={:?}", vid, u);
Ok(u)
}
@@ -737,10 +744,9 @@
}
}
}
- ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted })
- if self.tcx().lazy_normalization() =>
- {
- assert_eq!(promoted, None);
+ ty::ConstKind::Unevaluated(uv) if self.tcx().lazy_normalization() => {
+ assert_eq!(uv.promoted, None);
+ let substs = uv.substs(self.tcx());
let substs = self.relate_with_variance(
ty::Variance::Invariant,
ty::VarianceDiagInfo::default(),
@@ -749,7 +755,7 @@
)?;
Ok(self.tcx().mk_const(ty::Const {
ty: c.ty,
- val: ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted }),
+ val: ty::ConstKind::Unevaluated(ty::Unevaluated::new(uv.def, substs)),
}))
}
_ => relate::super_relate_consts(self, c, c),
@@ -881,7 +887,7 @@
*self.infcx.inner.borrow_mut().type_variables().var_origin(vid);
let new_var_id = self.infcx.inner.borrow_mut().type_variables().new_var(
self.for_universe,
- false,
+ Diverging::NotDiverging,
origin,
);
let u = self.tcx().mk_ty_var(new_var_id);
@@ -971,10 +977,9 @@
}
}
}
- ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted })
- if self.tcx().lazy_normalization() =>
- {
- assert_eq!(promoted, None);
+ ty::ConstKind::Unevaluated(uv) if self.tcx().lazy_normalization() => {
+ assert_eq!(uv.promoted, None);
+ let substs = uv.substs(self.tcx());
let substs = self.relate_with_variance(
ty::Variance::Invariant,
ty::VarianceDiagInfo::default(),
@@ -983,7 +988,7 @@
)?;
Ok(self.tcx().mk_const(ty::Const {
ty: c.ty,
- val: ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted }),
+ val: ty::ConstKind::Unevaluated(ty::Unevaluated::new(uv.def, substs)),
}))
}
_ => relate::super_relate_consts(self, c, c),
diff --git a/compiler/rustc_infer/src/infer/equate.rs b/compiler/rustc_infer/src/infer/equate.rs
index 0c93271..cbc735c 100644
--- a/compiler/rustc_infer/src/infer/equate.rs
+++ b/compiler/rustc_infer/src/infer/equate.rs
@@ -105,7 +105,7 @@
b: ty::Region<'tcx>,
) -> RelateResult<'tcx, ty::Region<'tcx>> {
debug!("{}.regions({:?}, {:?})", self.tag(), a, b);
- let origin = Subtype(box self.fields.trace.clone());
+ let origin = Subtype(Box::new(self.fields.trace.clone()));
self.fields
.infcx
.inner
diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
index f885c0a..32150c7 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
@@ -71,7 +71,7 @@
subst::{GenericArgKind, Subst, SubstsRef},
Region, Ty, TyCtxt, TypeFoldable,
};
-use rustc_span::{sym, BytePos, DesugaringKind, Pos, Span};
+use rustc_span::{sym, BytePos, DesugaringKind, MultiSpan, Pos, Span};
use rustc_target::spec::abi;
use std::ops::ControlFlow;
use std::{cmp, fmt, iter};
@@ -89,16 +89,17 @@
prefix: &str,
region: ty::Region<'tcx>,
suffix: &str,
+ alt_span: Option<Span>,
) {
let (description, span) = match *region {
ty::ReEarlyBound(_) | ty::ReFree(_) | ty::ReStatic => {
- msg_span_from_free_region(tcx, region)
+ msg_span_from_free_region(tcx, region, alt_span)
}
- ty::ReEmpty(ty::UniverseIndex::ROOT) => ("the empty lifetime".to_owned(), None),
+ ty::ReEmpty(ty::UniverseIndex::ROOT) => ("the empty lifetime".to_owned(), alt_span),
// uh oh, hope no user ever sees THIS
- ty::ReEmpty(ui) => (format!("the empty lifetime in universe {:?}", ui), None),
+ ty::ReEmpty(ui) => (format!("the empty lifetime in universe {:?}", ui), alt_span),
ty::RePlaceholder(_) => return,
@@ -108,7 +109,7 @@
// We shouldn't really be having unification failures with ReVar
// and ReLateBound though.
ty::ReVar(_) | ty::ReLateBound(..) | ty::ReErased => {
- (format!("lifetime {:?}", region), None)
+ (format!("lifetime {:?}", region), alt_span)
}
};
@@ -122,7 +123,7 @@
region: ty::Region<'tcx>,
suffix: &str,
) {
- let (description, span) = msg_span_from_free_region(tcx, region);
+ let (description, span) = msg_span_from_free_region(tcx, region, None);
emit_msg_span(err, prefix, description, span, suffix);
}
@@ -130,14 +131,15 @@
fn msg_span_from_free_region(
tcx: TyCtxt<'tcx>,
region: ty::Region<'tcx>,
+ alt_span: Option<Span>,
) -> (String, Option<Span>) {
match *region {
ty::ReEarlyBound(_) | ty::ReFree(_) => {
msg_span_from_early_bound_and_free_regions(tcx, region)
}
- ty::ReStatic => ("the static lifetime".to_owned(), None),
- ty::ReEmpty(ty::UniverseIndex::ROOT) => ("an empty lifetime".to_owned(), None),
- ty::ReEmpty(ui) => (format!("an empty lifetime in universe {:?}", ui), None),
+ ty::ReStatic => ("the static lifetime".to_owned(), alt_span),
+ ty::ReEmpty(ty::UniverseIndex::ROOT) => ("an empty lifetime".to_owned(), alt_span),
+ ty::ReEmpty(ui) => (format!("an empty lifetime in universe {:?}", ui), alt_span),
_ => bug!("{:?}", region),
}
}
@@ -319,6 +321,7 @@
&format!("hidden type `{}` captures ", hidden_ty),
hidden_region,
"",
+ None,
);
}
}
@@ -641,17 +644,6 @@
scrut_span,
..
}) => match source {
- hir::MatchSource::IfLetDesugar { .. } => {
- let msg = "`if let` arms have incompatible types";
- err.span_label(cause.span, msg);
- if let Some(ret_sp) = opt_suggest_box_span {
- self.suggest_boxing_for_return_impl_trait(
- err,
- ret_sp,
- prior_arms.iter().chain(std::iter::once(&arm_span)).map(|s| *s),
- );
- }
- }
hir::MatchSource::TryDesugar => {
if let Some(ty::error::ExpectedFound { expected, .. }) = exp_found {
let scrut_expr = self.tcx.hir().expect_expr(scrut_hir_id);
@@ -789,6 +781,10 @@
);
}
}
+ ObligationCauseCode::LetElse => {
+ err.help("try adding a diverging expression, such as `return` or `panic!(..)`");
+ err.help("...or use `match` instead of `let...else`");
+ }
_ => (),
}
}
@@ -1188,16 +1184,26 @@
// | |
// | elided as they were the same
// not elided, they were different, but irrelevant
+ //
+ // For bound lifetimes, keep the names of the lifetimes,
+ // even if they are the same so that it's clear what's happening
+ // if we have something like
+ //
+ // for<'r, 's> fn(Inv<'r>, Inv<'s>)
+ // for<'r> fn(Inv<'r>, Inv<'r>)
let lifetimes = sub1.regions().zip(sub2.regions());
for (i, lifetimes) in lifetimes.enumerate() {
let l1 = lifetime_display(lifetimes.0);
let l2 = lifetime_display(lifetimes.1);
- if lifetimes.0 == lifetimes.1 {
- values.0.push_normal("'_");
- values.1.push_normal("'_");
- } else {
+ if lifetimes.0 != lifetimes.1 {
values.0.push_highlighted(l1);
values.1.push_highlighted(l2);
+ } else if lifetimes.0.is_late_bound() {
+ values.0.push_normal(l1);
+ values.1.push_normal(l2);
+ } else {
+ values.0.push_normal("'_");
+ values.1.push_normal("'_");
}
self.push_comma(&mut values.0, &mut values.1, len, i);
}
@@ -1485,31 +1491,49 @@
let count = values.len();
let kind = key.descr();
let mut returned_async_output_error = false;
- for sp in values {
- err.span_label(
- *sp,
- format!(
- "{}{}{} {}{}",
- if sp.is_desugaring(DesugaringKind::Async)
- && !returned_async_output_error
- {
- "checked the `Output` of this `async fn`, "
- } else if count == 1 {
- "the "
- } else {
- ""
- },
- if count > 1 { "one of the " } else { "" },
- target,
- kind,
- pluralize!(count),
- ),
- );
- if sp.is_desugaring(DesugaringKind::Async)
- && returned_async_output_error == false
- {
- err.note("while checking the return type of the `async fn`");
+ for &sp in values {
+ if sp.is_desugaring(DesugaringKind::Async) && !returned_async_output_error {
+ if &[sp] != err.span.primary_spans() {
+ let mut span: MultiSpan = sp.into();
+ span.push_span_label(
+ sp,
+ format!(
+ "checked the `Output` of this `async fn`, {}{} {}{}",
+ if count > 1 { "one of the " } else { "" },
+ target,
+ kind,
+ pluralize!(count),
+ ),
+ );
+ err.span_note(
+ span,
+ "while checking the return type of the `async fn`",
+ );
+ } else {
+ err.span_label(
+ sp,
+ format!(
+ "checked the `Output` of this `async fn`, {}{} {}{}",
+ if count > 1 { "one of the " } else { "" },
+ target,
+ kind,
+ pluralize!(count),
+ ),
+ );
+ err.note("while checking the return type of the `async fn`");
+ }
returned_async_output_error = true;
+ } else {
+ err.span_label(
+ sp,
+ format!(
+ "{}{} {}{}",
+ if count == 1 { "the " } else { "one of the " },
+ target,
+ kind,
+ pluralize!(count),
+ ),
+ );
}
}
}
@@ -1517,6 +1541,10 @@
}
impl<'tcx> ty::fold::TypeVisitor<'tcx> for OpaqueTypesVisitor<'tcx> {
+ fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
+ Some(self.tcx)
+ }
+
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
if let Some((kind, def_id)) = TyCategory::from_ty(self.tcx, t) {
let span = self.tcx.def_span(def_id);
@@ -1602,14 +1630,11 @@
(TypeError::Sorts(values), extra) => {
let sort_string = |ty: Ty<'tcx>| match (extra, ty.kind()) {
(true, ty::Opaque(def_id, _)) => {
- let pos = self
- .tcx
- .sess
- .source_map()
- .lookup_char_pos(self.tcx.def_span(*def_id).lo());
+ let sm = self.tcx.sess.source_map();
+ let pos = sm.lookup_char_pos(self.tcx.def_span(*def_id).lo());
format!(
" (opaque type at <{}:{}:{}>)",
- pos.file.name.prefer_local(),
+ sm.filename_for_diagnostics(&pos.file.name),
pos.line,
pos.col.to_usize() + 1,
)
@@ -1677,7 +1702,7 @@
}
// In some (most?) cases cause.body_id points to actual body, but in some cases
- // it's a actual definition. According to the comments (e.g. in
+ // it's an actual definition. According to the comments (e.g. in
// librustc_typeck/check/compare_method.rs:compare_predicate_entailment) the latter
// is relied upon by some other code. This might (or might not) need cleanup.
let body_owner_def_id =
@@ -2238,9 +2263,99 @@
}
};
- let mut err = match *sub {
- ty::ReEarlyBound(ty::EarlyBoundRegion { name, .. })
- | ty::ReFree(ty::FreeRegion { bound_region: ty::BrNamed(_, name), .. }) => {
+ #[derive(Debug)]
+ enum SubOrigin<'hir> {
+ GAT(&'hir hir::Generics<'hir>),
+ Impl(&'hir hir::Generics<'hir>),
+ Trait(&'hir hir::Generics<'hir>),
+ Fn(&'hir hir::Generics<'hir>),
+ Unknown,
+ }
+ let sub_origin = 'origin: {
+ match *sub {
+ ty::ReEarlyBound(ty::EarlyBoundRegion { def_id, .. }) => {
+ let node = self.tcx.hir().get_if_local(def_id).unwrap();
+ match node {
+ Node::GenericParam(param) => {
+ for h in self.tcx.hir().parent_iter(param.hir_id) {
+ break 'origin match h.1 {
+ Node::ImplItem(hir::ImplItem {
+ kind: hir::ImplItemKind::TyAlias(..),
+ generics,
+ ..
+ }) => SubOrigin::GAT(generics),
+ Node::ImplItem(hir::ImplItem {
+ kind: hir::ImplItemKind::Fn(..),
+ generics,
+ ..
+ }) => SubOrigin::Fn(generics),
+ Node::TraitItem(hir::TraitItem {
+ kind: hir::TraitItemKind::Type(..),
+ generics,
+ ..
+ }) => SubOrigin::GAT(generics),
+ Node::TraitItem(hir::TraitItem {
+ kind: hir::TraitItemKind::Fn(..),
+ generics,
+ ..
+ }) => SubOrigin::Fn(generics),
+ Node::Item(hir::Item {
+ kind: hir::ItemKind::Trait(_, _, generics, _, _),
+ ..
+ }) => SubOrigin::Trait(generics),
+ Node::Item(hir::Item {
+ kind: hir::ItemKind::Impl(hir::Impl { generics, .. }),
+ ..
+ }) => SubOrigin::Impl(generics),
+ Node::Item(hir::Item {
+ kind: hir::ItemKind::Fn(_, generics, _),
+ ..
+ }) => SubOrigin::Fn(generics),
+ _ => continue,
+ };
+ }
+ }
+ _ => {}
+ }
+ }
+ _ => {}
+ }
+ SubOrigin::Unknown
+ };
+ debug!(?sub_origin);
+
+ let mut err = match (*sub, sub_origin) {
+ // In the case of GATs, we have to be careful. If we a type parameter `T` on an impl,
+ // but a lifetime `'a` on an associated type, then we might need to suggest adding
+ // `where T: 'a`. Importantly, this is on the GAT span, not on the `T` declaration.
+ (ty::ReEarlyBound(ty::EarlyBoundRegion { name: _, .. }), SubOrigin::GAT(generics)) => {
+ // Does the required lifetime have a nice name we can print?
+ let mut err = struct_span_err!(
+ self.tcx.sess,
+ span,
+ E0309,
+ "{} may not live long enough",
+ labeled_user_string
+ );
+ let pred = format!("{}: {}", bound_kind, sub);
+ let suggestion = format!(
+ "{} {}",
+ if !generics.where_clause.predicates.is_empty() { "," } else { " where" },
+ pred,
+ );
+ err.span_suggestion(
+ generics.where_clause.tail_span_for_suggestion(),
+ "consider adding a where clause".into(),
+ suggestion,
+ Applicability::MaybeIncorrect,
+ );
+ err
+ }
+ (
+ ty::ReEarlyBound(ty::EarlyBoundRegion { name, .. })
+ | ty::ReFree(ty::FreeRegion { bound_region: ty::BrNamed(_, name), .. }),
+ _,
+ ) => {
// Does the required lifetime have a nice name we can print?
let mut err = struct_span_err!(
self.tcx.sess,
@@ -2257,7 +2372,7 @@
err
}
- ty::ReStatic => {
+ (ty::ReStatic, _) => {
// Does the required lifetime have a nice name we can print?
let mut err = struct_span_err!(
self.tcx.sess,
@@ -2285,8 +2400,9 @@
&format!("{} must be valid for ", labeled_user_string),
sub,
"...",
+ None,
);
- if let Some(infer::RelateParamBound(_, t)) = origin {
+ if let Some(infer::RelateParamBound(_, t, _)) = origin {
let return_impl_trait = self
.in_progress_typeck_results
.map(|typeck_results| typeck_results.borrow().hir_owner)
@@ -2332,6 +2448,7 @@
"first, the lifetime cannot outlive ",
sup_region,
"...",
+ None,
);
debug!("report_sub_sup_conflict: var_origin={:?}", var_origin);
@@ -2358,6 +2475,7 @@
"...but the lifetime must also be valid for ",
sub_region,
"...",
+ None,
);
err.span_note(
sup_trace.cause.span,
@@ -2379,6 +2497,7 @@
"but, the lifetime must be valid for ",
sub_region,
"...",
+ None,
);
self.note_region_origin(&mut err, &sub_origin);
@@ -2466,9 +2585,6 @@
CompareImplTypeObligation { .. } => Error0308("type not compatible with trait"),
MatchExpressionArm(box MatchExpressionArmCause { source, .. }) => {
Error0308(match source {
- hir::MatchSource::IfLetDesugar { .. } => {
- "`if let` arms have incompatible types"
- }
hir::MatchSource::TryDesugar => {
"try expression alternatives have incompatible types"
}
@@ -2477,6 +2593,7 @@
}
IfExpression { .. } => Error0308("`if` and `else` have incompatible types"),
IfExpressionWithNoElse => Error0317("`if` may be missing an `else` clause"),
+ LetElse => Error0308("`else` clause of `let...else` does not diverge"),
MainFunctionType => Error0580("`main` function has wrong type"),
StartFunctionType => Error0308("`#[start]` function has wrong type"),
IntrinsicType => Error0308("intrinsic has wrong type"),
@@ -2504,10 +2621,6 @@
CompareImplMethodObligation { .. } => "method type is compatible with trait",
CompareImplTypeObligation { .. } => "associated type is compatible with trait",
ExprAssignable => "expression is assignable",
- MatchExpressionArm(box MatchExpressionArmCause { source, .. }) => match source {
- hir::MatchSource::IfLetDesugar { .. } => "`if let` arms have compatible types",
- _ => "`match` arms have compatible types",
- },
IfExpression { .. } => "`if` and `else` have incompatible types",
IfExpressionWithNoElse => "`if` missing an `else` returns `()`",
MainFunctionType => "`main` function has the correct type",
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 9a71810..e00003f 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
@@ -51,7 +51,7 @@
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| {
+ ty.walk(self.infcx.tcx).any(|inner| {
inner == self.target
|| match (inner.unpack(), self.target.unpack()) {
(GenericArgKind::Type(inner_ty), GenericArgKind::Type(target_ty)) => {
@@ -753,23 +753,11 @@
if let (UnderspecifiedArgKind::Const { .. }, Some(parent_data)) =
(&arg_data.kind, &arg_data.parent)
{
- let has_impl_trait =
- self.tcx.generics_of(parent_data.def_id).params.iter().any(|param| {
- matches!(
- param.kind,
- ty::GenericParamDefKind::Type {
- synthetic: Some(
- hir::SyntheticTyParamKind::ImplTrait
- | hir::SyntheticTyParamKind::FromAttr,
- ),
- ..
- }
- )
- });
-
// (#83606): Do not emit a suggestion if the parent has an `impl Trait`
// as an argument otherwise it will cause the E0282 error.
- if !has_impl_trait {
+ if !self.tcx.generics_of(parent_data.def_id).has_impl_trait()
+ || self.tcx.features().explicit_generic_args_with_impl_trait
+ {
err.span_suggestion_verbose(
span,
"consider specifying the const argument",
@@ -814,7 +802,7 @@
let borrow = typeck_results.borrow();
if let Some((DefKind::AssocFn, did)) = borrow.type_dependent_def(e.hir_id) {
let generics = self.tcx.generics_of(did);
- if !generics.params.is_empty() {
+ if !generics.params.is_empty() && !generics.has_impl_trait() {
err.span_suggestion_verbose(
segment.ident.span.shrink_to_hi(),
&format!(
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs
index cca1954..c60a714 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs
@@ -43,7 +43,7 @@
multi_span
.push_span_label(binding_span, "introduces a `'static` lifetime requirement".into());
err.span_note(multi_span, "because this has an unmet lifetime requirement");
- note_and_explain_region(self.tcx(), &mut err, "", sup, "...");
+ note_and_explain_region(self.tcx(), &mut err, "", sup, "...", Some(binding_span));
if let Some(impl_node) = self.tcx().hir().get_if_local(*impl_def_id) {
// If an impl is local, then maybe this isn't what they want. Try to
// be as helpful as possible with implicit lifetimes.
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 fde4ec0..81059fb 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
@@ -9,7 +9,9 @@
use rustc_hir::def_id::DefId;
use rustc_hir::intravisit::{walk_ty, ErasedMap, NestedVisitorMap, Visitor};
use rustc_hir::{self as hir, GenericBound, Item, ItemKind, Lifetime, LifetimeName, Node, TyKind};
-use rustc_middle::ty::{self, AssocItemContainer, RegionKind, Ty, TypeFoldable, TypeVisitor};
+use rustc_middle::ty::{
+ self, AssocItemContainer, RegionKind, Ty, TyCtxt, TypeFoldable, TypeVisitor,
+};
use rustc_span::symbol::Ident;
use rustc_span::{MultiSpan, Span};
@@ -476,8 +478,14 @@
/// Collect all the trait objects in a type that could have received an implicit `'static` lifetime.
pub(super) struct TraitObjectVisitor(pub(super) FxHashSet<DefId>);
-impl TypeVisitor<'_> for TraitObjectVisitor {
- fn visit_ty(&mut self, t: Ty<'_>) -> ControlFlow<Self::BreakTy> {
+impl<'tcx> TypeVisitor<'tcx> for TraitObjectVisitor {
+ fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
+ // The default anon const substs cannot include
+ // trait objects, so we don't have to bother looking.
+ None
+ }
+
+ fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
match t.kind() {
ty::Dynamic(preds, RegionKind::ReStatic) => {
if let Some(def_id) = preds.principal_def_id() {
diff --git a/compiler/rustc_infer/src/infer/error_reporting/note.rs b/compiler/rustc_infer/src/infer/error_reporting/note.rs
index c88869a..4bc59a4 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/note.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/note.rs
@@ -74,14 +74,18 @@
),
);
}
- infer::RelateParamBound(span, t) => {
+ infer::RelateParamBound(span, t, opt_span) => {
label_or_note(
span,
&format!(
- "...so that the type `{}` will meet its required lifetime bounds",
- self.ty_to_string(t)
+ "...so that the type `{}` will meet its required lifetime bounds{}",
+ self.ty_to_string(t),
+ if opt_span.is_some() { "..." } else { "" },
),
);
+ if let Some(span) = opt_span {
+ err.span_note(span, "...that is required by this bound");
+ }
}
infer::RelateRegionParamBound(span) => {
label_or_note(
@@ -117,6 +121,7 @@
"",
sup,
" doesn't meet the lifetime requirements",
+ None,
);
}
(_, ty::RePlaceholder(_)) => {
@@ -126,16 +131,18 @@
"the required lifetime does not necessarily outlive ",
sub,
"",
+ None,
);
}
_ => {
- note_and_explain_region(self.tcx, &mut err, "", sup, "...");
+ note_and_explain_region(self.tcx, &mut err, "", sup, "...", None);
note_and_explain_region(
self.tcx,
&mut err,
"...does not necessarily outlive ",
sub,
"",
+ None,
);
}
}
@@ -154,6 +161,7 @@
"...the reference is valid for ",
sub,
"...",
+ None,
);
note_and_explain_region(
self.tcx,
@@ -161,6 +169,7 @@
"...but the borrowed content is only valid for ",
sup,
"",
+ None,
);
err
}
@@ -179,6 +188,7 @@
"...the borrowed pointer is valid for ",
sub,
"...",
+ None,
);
note_and_explain_region(
self.tcx,
@@ -186,6 +196,7 @@
&format!("...but `{}` is only valid for ", var_name),
sup,
"",
+ None,
);
err
}
@@ -197,17 +208,25 @@
"lifetime of the source pointer does not outlive lifetime bound of the \
object type"
);
- note_and_explain_region(self.tcx, &mut err, "object type is valid for ", sub, "");
+ note_and_explain_region(
+ self.tcx,
+ &mut err,
+ "object type is valid for ",
+ sub,
+ "",
+ None,
+ );
note_and_explain_region(
self.tcx,
&mut err,
"source pointer is only valid for ",
sup,
"",
+ None,
);
err
}
- infer::RelateParamBound(span, ty) => {
+ infer::RelateParamBound(span, ty, opt_span) => {
let mut err = struct_span_err!(
self.tcx.sess,
span,
@@ -216,10 +235,22 @@
self.ty_to_string(ty)
);
match *sub {
- ty::ReStatic => {
- note_and_explain_region(self.tcx, &mut err, "type must satisfy ", sub, "")
- }
- _ => note_and_explain_region(self.tcx, &mut err, "type must outlive ", sub, ""),
+ ty::ReStatic => note_and_explain_region(
+ self.tcx,
+ &mut err,
+ "type must satisfy ",
+ sub,
+ if opt_span.is_some() { " as required by this binding" } else { "" },
+ opt_span,
+ ),
+ _ => note_and_explain_region(
+ self.tcx,
+ &mut err,
+ "type must outlive ",
+ sub,
+ if opt_span.is_some() { " as required by this binding" } else { "" },
+ opt_span,
+ ),
}
err
}
@@ -232,6 +263,7 @@
"lifetime parameter instantiated with ",
sup,
"",
+ None,
);
note_and_explain_region(
self.tcx,
@@ -239,6 +271,7 @@
"but lifetime parameter must outlive ",
sub,
"",
+ None,
);
err
}
@@ -255,6 +288,7 @@
"the return value is only valid for ",
sup,
"",
+ None,
);
err
}
@@ -266,8 +300,22 @@
"a value of type `{}` is borrowed for too long",
self.ty_to_string(ty)
);
- note_and_explain_region(self.tcx, &mut err, "the type is valid for ", sub, "");
- note_and_explain_region(self.tcx, &mut err, "but the borrow lasts for ", sup, "");
+ note_and_explain_region(
+ self.tcx,
+ &mut err,
+ "the type is valid for ",
+ sub,
+ "",
+ None,
+ );
+ note_and_explain_region(
+ self.tcx,
+ &mut err,
+ "but the borrow lasts for ",
+ sup,
+ "",
+ None,
+ );
err
}
infer::ReferenceOutlivesReferent(ty, span) => {
@@ -278,13 +326,21 @@
"in type `{}`, reference has a longer lifetime than the data it references",
self.ty_to_string(ty)
);
- note_and_explain_region(self.tcx, &mut err, "the pointer is valid for ", sub, "");
+ note_and_explain_region(
+ self.tcx,
+ &mut err,
+ "the pointer is valid for ",
+ sub,
+ "",
+ None,
+ );
note_and_explain_region(
self.tcx,
&mut err,
"but the referenced data is only valid for ",
sup,
"",
+ None,
);
err
}
diff --git a/compiler/rustc_infer/src/infer/freshen.rs b/compiler/rustc_infer/src/infer/freshen.rs
index 4af1bdf..c40e409 100644
--- a/compiler/rustc_infer/src/infer/freshen.rs
+++ b/compiler/rustc_infer/src/infer/freshen.rs
@@ -146,7 +146,7 @@
}
fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
- if !t.needs_infer() && !t.has_erasable_regions() {
+ if !t.needs_infer() && !t.has_erasable_regions(self.tcx()) {
return t;
}
diff --git a/compiler/rustc_infer/src/infer/glb.rs b/compiler/rustc_infer/src/infer/glb.rs
index 60f02b8..d769667 100644
--- a/compiler/rustc_infer/src/infer/glb.rs
+++ b/compiler/rustc_infer/src/infer/glb.rs
@@ -67,7 +67,7 @@
) -> RelateResult<'tcx, ty::Region<'tcx>> {
debug!("{}.regions({:?}, {:?})", self.tag(), a, b);
- let origin = Subtype(box self.fields.trace.clone());
+ let origin = Subtype(Box::new(self.fields.trace.clone()));
Ok(self.fields.infcx.inner.borrow_mut().unwrap_region_constraints().glb_regions(
self.tcx(),
origin,
diff --git a/compiler/rustc_infer/src/infer/lub.rs b/compiler/rustc_infer/src/infer/lub.rs
index a083235..cbad663 100644
--- a/compiler/rustc_infer/src/infer/lub.rs
+++ b/compiler/rustc_infer/src/infer/lub.rs
@@ -67,7 +67,7 @@
) -> RelateResult<'tcx, ty::Region<'tcx>> {
debug!("{}.regions({:?}, {:?})", self.tag(), a, b);
- let origin = Subtype(box self.fields.trace.clone());
+ let origin = Subtype(Box::new(self.fields.trace.clone()));
Ok(self.fields.infcx.inner.borrow_mut().unwrap_region_constraints().lub_regions(
self.tcx(),
origin,
diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs
index d3bfb2b..bc98a3a 100644
--- a/compiler/rustc_infer/src/infer/mod.rs
+++ b/compiler/rustc_infer/src/infer/mod.rs
@@ -1,13 +1,16 @@
pub use self::freshen::TypeFreshener;
+pub use self::lexical_region_resolve::RegionResolutionError;
pub use self::LateBoundRegionConversionTime::*;
pub use self::RegionVariableOrigin::*;
pub use self::SubregionOrigin::*;
pub use self::ValuePairs::*;
+use self::opaque_types::OpaqueTypeMap;
pub(crate) use self::undo_log::{InferCtxtUndoLogs, Snapshot, UndoLog};
use crate::traits::{self, ObligationCause, PredicateObligations, TraitEngine};
+use hir::def_id::CRATE_DEF_ID;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::sync::Lrc;
use rustc_data_structures::undo_log::Rollback;
@@ -20,7 +23,7 @@
use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind, ToType};
use rustc_middle::mir::interpret::EvalToConstValueResult;
use rustc_middle::traits::select;
-use rustc_middle::ty::error::{ExpectedFound, TypeError, UnconstrainedNumeric};
+use rustc_middle::ty::error::{ExpectedFound, TypeError};
use rustc_middle::ty::fold::{TypeFoldable, TypeFolder};
use rustc_middle::ty::relate::RelateResult;
use rustc_middle::ty::subst::{GenericArg, GenericArgKind, InternalSubsts, SubstsRef};
@@ -43,7 +46,7 @@
use self::region_constraints::{
RegionConstraintCollector, RegionConstraintStorage, RegionSnapshot,
};
-use self::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
+use self::type_variable::{Diverging, TypeVariableOrigin, TypeVariableOriginKind};
pub mod at;
pub mod canonical;
@@ -59,6 +62,7 @@
mod lexical_region_resolve;
mod lub;
pub mod nll_relate;
+pub mod opaque_types;
pub mod outlives;
pub mod region_constraints;
pub mod resolve;
@@ -191,6 +195,19 @@
region_obligations: Vec<(hir::HirId, RegionObligation<'tcx>)>,
undo_log: InferCtxtUndoLogs<'tcx>,
+
+ // Opaque types found in explicit return types and their
+ // associated fresh inference variable. Writeback resolves these
+ // variables to get the concrete type, which can be used to
+ // 'de-opaque' OpaqueTypeDecl, after typeck is done with all functions.
+ pub opaque_types: OpaqueTypeMap<'tcx>,
+
+ /// A map from inference variables created from opaque
+ /// type instantiations (`ty::Infer`) to the actual opaque
+ /// type (`ty::Opaque`). Used during fallback to map unconstrained
+ /// opaque type inference variables to their corresponding
+ /// opaque type.
+ pub opaque_types_vars: FxHashMap<Ty<'tcx>, Ty<'tcx>>,
}
impl<'tcx> InferCtxtInner<'tcx> {
@@ -204,6 +221,8 @@
float_unification_storage: ut::UnificationTableStorage::new(),
region_constraint_storage: Some(RegionConstraintStorage::new()),
region_obligations: vec![],
+ opaque_types: Default::default(),
+ opaque_types_vars: Default::default(),
}
}
@@ -273,6 +292,10 @@
pub struct InferCtxt<'a, 'tcx> {
pub tcx: TyCtxt<'tcx>,
+ /// The `DefId` of the item in whose context we are performing inference or typeck.
+ /// It is used to check whether an opaque type use is a defining use.
+ pub defining_use_anchor: LocalDefId,
+
/// During type-checking/inference of a body, `in_progress_typeck_results`
/// contains a reference to the typeck results being built up, which are
/// used for reading closure kinds/signatures as they are inferred,
@@ -375,7 +398,7 @@
/// Some type parameter was instantiated with the given type,
/// and that type must outlive some region.
- RelateParamBound(Span, Ty<'tcx>),
+ RelateParamBound(Span, Ty<'tcx>, Option<Span>),
/// The given region parameter was instantiated with a region
/// that must outlive some other region.
@@ -531,6 +554,7 @@
pub struct InferCtxtBuilder<'tcx> {
tcx: TyCtxt<'tcx>,
fresh_typeck_results: Option<RefCell<ty::TypeckResults<'tcx>>>,
+ defining_use_anchor: LocalDefId,
}
pub trait TyCtxtInferExt<'tcx> {
@@ -539,15 +563,31 @@
impl TyCtxtInferExt<'tcx> for TyCtxt<'tcx> {
fn infer_ctxt(self) -> InferCtxtBuilder<'tcx> {
- InferCtxtBuilder { tcx: self, fresh_typeck_results: None }
+ InferCtxtBuilder {
+ tcx: self,
+ defining_use_anchor: CRATE_DEF_ID,
+ fresh_typeck_results: None,
+ }
}
}
impl<'tcx> InferCtxtBuilder<'tcx> {
/// Used only by `rustc_typeck` during body type-checking/inference,
/// will initialize `in_progress_typeck_results` with fresh `TypeckResults`.
+ /// Will also change the scope for opaque type defining use checks to the given owner.
pub fn with_fresh_in_progress_typeck_results(mut self, table_owner: LocalDefId) -> Self {
self.fresh_typeck_results = Some(RefCell::new(ty::TypeckResults::new(table_owner)));
+ self.with_opaque_type_inference(table_owner)
+ }
+
+ /// Whenever the `InferCtxt` should be able to handle defining uses of opaque types,
+ /// you need to call this function. Otherwise the opaque type will be treated opaquely.
+ ///
+ /// It is only meant to be called in two places, for typeck
+ /// (via `with_fresh_in_progress_typeck_results`) and for the inference context used
+ /// in mir borrowck.
+ pub fn with_opaque_type_inference(mut self, defining_use_anchor: LocalDefId) -> Self {
+ self.defining_use_anchor = defining_use_anchor;
self
}
@@ -575,10 +615,11 @@
}
pub fn enter<R>(&mut self, f: impl for<'a> FnOnce(InferCtxt<'a, 'tcx>) -> R) -> R {
- let InferCtxtBuilder { tcx, ref fresh_typeck_results } = *self;
+ let InferCtxtBuilder { tcx, defining_use_anchor, ref fresh_typeck_results } = *self;
let in_progress_typeck_results = fresh_typeck_results.as_ref();
f(InferCtxt {
tcx,
+ defining_use_anchor,
in_progress_typeck_results,
inner: RefCell::new(InferCtxtInner::new()),
lexical_region_resolutions: RefCell::new(None),
@@ -630,6 +671,19 @@
}
impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
+ /// calls `tcx.try_unify_abstract_consts` after
+ /// canonicalizing the consts.
+ pub fn try_unify_abstract_consts(
+ &self,
+ a: ty::Unevaluated<'tcx, ()>,
+ b: ty::Unevaluated<'tcx, ()>,
+ ) -> bool {
+ let canonical = self.canonicalize_query((a, b), &mut OriginalQueryValues::default());
+ debug!("canonical consts: {:?}", &canonical.value);
+
+ self.tcx.try_unify_abstract_consts(canonical.value)
+ }
+
pub fn is_in_snapshot(&self) -> bool {
self.in_snapshot.get()
}
@@ -638,10 +692,27 @@
t.fold_with(&mut self.freshener())
}
- pub fn type_var_diverges(&'a self, ty: Ty<'_>) -> bool {
+ /// Returns whether `ty` is a diverging type variable or not.
+ /// (If `ty` is not a type variable at all, returns not diverging.)
+ ///
+ /// No attempt is made to resolve `ty`.
+ pub fn type_var_diverges(&'a self, ty: Ty<'_>) -> Diverging {
match *ty.kind() {
ty::Infer(ty::TyVar(vid)) => self.inner.borrow_mut().type_variables().var_diverges(vid),
- _ => false,
+ _ => Diverging::NotDiverging,
+ }
+ }
+
+ /// Returns the origin of the type variable identified by `vid`, or `None`
+ /// if this is not a type variable.
+ ///
+ /// No attempt is made to resolve `ty`.
+ pub fn type_var_origin(&'a self, ty: Ty<'tcx>) -> Option<TypeVariableOrigin> {
+ match *ty.kind() {
+ ty::Infer(ty::TyVar(vid)) => {
+ Some(*self.inner.borrow_mut().type_variables().var_origin(vid))
+ }
+ _ => None,
}
}
@@ -654,28 +725,6 @@
freshen::TypeFreshener::new(self, true)
}
- pub fn type_is_unconstrained_numeric(&'a self, ty: Ty<'_>) -> UnconstrainedNumeric {
- use rustc_middle::ty::error::UnconstrainedNumeric::Neither;
- use rustc_middle::ty::error::UnconstrainedNumeric::{UnconstrainedFloat, UnconstrainedInt};
- match *ty.kind() {
- ty::Infer(ty::IntVar(vid)) => {
- if self.inner.borrow_mut().int_unification_table().probe_value(vid).is_some() {
- Neither
- } else {
- UnconstrainedInt
- }
- }
- ty::Infer(ty::FloatVar(vid)) => {
- if self.inner.borrow_mut().float_unification_table().probe_value(vid).is_some() {
- Neither
- } else {
- UnconstrainedFloat
- }
- }
- _ => Neither,
- }
- }
-
pub fn unsolved_variables(&self) -> Vec<Ty<'tcx>> {
let mut inner = self.inner.borrow_mut();
let mut vars: Vec<Ty<'_>> = inner
@@ -928,29 +977,62 @@
);
}
+ /// Processes a `Coerce` predicate from the fulfillment context.
+ /// This is NOT the preferred way to handle coercion, which is to
+ /// invoke `FnCtxt::coerce` or a similar method (see `coercion.rs`).
+ ///
+ /// This method here is actually a fallback that winds up being
+ /// invoked when `FnCtxt::coerce` encounters unresolved type variables
+ /// and records a coercion predicate. Presently, this method is equivalent
+ /// to `subtype_predicate` -- that is, "coercing" `a` to `b` winds up
+ /// actually requiring `a <: b`. This is of course a valid coercion,
+ /// but it's not as flexible as `FnCtxt::coerce` would be.
+ ///
+ /// (We may refactor this in the future, but there are a number of
+ /// practical obstacles. Among other things, `FnCtxt::coerce` presently
+ /// records adjustments that are required on the HIR in order to perform
+ /// the coercion, and we don't currently have a way to manage that.)
+ pub fn coerce_predicate(
+ &self,
+ cause: &ObligationCause<'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ predicate: ty::PolyCoercePredicate<'tcx>,
+ ) -> Option<InferResult<'tcx, ()>> {
+ let subtype_predicate = predicate.map_bound(|p| ty::SubtypePredicate {
+ a_is_expected: false, // when coercing from `a` to `b`, `b` is expected
+ a: p.a,
+ b: p.b,
+ });
+ self.subtype_predicate(cause, param_env, subtype_predicate)
+ }
+
pub fn subtype_predicate(
&self,
cause: &ObligationCause<'tcx>,
param_env: ty::ParamEnv<'tcx>,
predicate: ty::PolySubtypePredicate<'tcx>,
) -> Option<InferResult<'tcx, ()>> {
- // Subtle: it's ok to skip the binder here and resolve because
- // `shallow_resolve` just ignores anything that is not a type
- // variable, and because type variable's can't (at present, at
+ // Check for two unresolved inference variables, in which case we can
+ // make no progress. This is partly a micro-optimization, but it's
+ // also an opportunity to "sub-unify" the variables. This isn't
+ // *necessary* to prevent cycles, because they would eventually be sub-unified
+ // anyhow during generalization, but it helps with diagnostics (we can detect
+ // earlier that they are sub-unified).
+ //
+ // Note that we can just skip the binders here because
+ // type variables can't (at present, at
// least) capture any of the things bound by this binder.
//
- // NOTE(nmatsakis): really, there is no *particular* reason to do this
- // `shallow_resolve` here except as a micro-optimization.
- // Naturally I could not resist.
- let two_unbound_type_vars = {
- let a = self.shallow_resolve(predicate.skip_binder().a);
- let b = self.shallow_resolve(predicate.skip_binder().b);
- a.is_ty_var() && b.is_ty_var()
- };
-
- if two_unbound_type_vars {
- // Two unbound type variables? Can't make progress.
- return None;
+ // Note that this sub here is not just for diagnostics - it has semantic
+ // effects as well.
+ let r_a = self.shallow_resolve(predicate.skip_binder().a);
+ let r_b = self.shallow_resolve(predicate.skip_binder().b);
+ match (r_a.kind(), r_b.kind()) {
+ (&ty::Infer(ty::TyVar(a_vid)), &ty::Infer(ty::TyVar(b_vid))) => {
+ self.inner.borrow_mut().type_variables().sub(a_vid, b_vid);
+ return None;
+ }
+ _ => {}
}
Some(self.commit_if_ok(|_snapshot| {
@@ -979,12 +1061,12 @@
})
}
- pub fn next_ty_var_id(&self, diverging: bool, origin: TypeVariableOrigin) -> TyVid {
+ pub fn next_ty_var_id(&self, diverging: Diverging, origin: TypeVariableOrigin) -> TyVid {
self.inner.borrow_mut().type_variables().new_var(self.universe(), diverging, origin)
}
pub fn next_ty_var(&self, origin: TypeVariableOrigin) -> Ty<'tcx> {
- self.tcx.mk_ty_var(self.next_ty_var_id(false, origin))
+ self.tcx.mk_ty_var(self.next_ty_var_id(Diverging::NotDiverging, origin))
}
pub fn next_ty_var_in_universe(
@@ -992,12 +1074,16 @@
origin: TypeVariableOrigin,
universe: ty::UniverseIndex,
) -> Ty<'tcx> {
- let vid = self.inner.borrow_mut().type_variables().new_var(universe, false, origin);
+ let vid = self.inner.borrow_mut().type_variables().new_var(
+ universe,
+ Diverging::NotDiverging,
+ origin,
+ );
self.tcx.mk_ty_var(vid)
}
pub fn next_diverging_ty_var(&self, origin: TypeVariableOrigin) -> Ty<'tcx> {
- self.tcx.mk_ty_var(self.next_ty_var_id(true, origin))
+ self.tcx.mk_ty_var(self.next_ty_var_id(Diverging::Diverges, origin))
}
pub fn next_const_var(
@@ -1070,7 +1156,7 @@
/// etc) this is the root universe U0. For inference variables or
/// placeholders, however, it will return the universe which which
/// they are associated.
- fn universe_of_region(&self, r: ty::Region<'tcx>) -> ty::UniverseIndex {
+ pub fn universe_of_region(&self, r: ty::Region<'tcx>) -> ty::UniverseIndex {
self.inner.borrow_mut().unwrap_region_constraints().universe(r)
}
@@ -1111,7 +1197,7 @@
// as the substitutions for the default, `(T, U)`.
let ty_var_id = self.inner.borrow_mut().type_variables().new_var(
self.universe(),
- false,
+ Diverging::NotDiverging,
TypeVariableOrigin {
kind: TypeVariableOriginKind::TypeParameterDefinition(
param.name,
@@ -1248,6 +1334,17 @@
op(inner.unwrap_region_constraints().data())
}
+ pub fn region_var_origin(&self, vid: ty::RegionVid) -> RegionVariableOrigin {
+ let mut inner = self.inner.borrow_mut();
+ let inner = &mut *inner;
+ inner
+ .region_constraint_storage
+ .as_mut()
+ .expect("regions already resolved")
+ .with_log(&mut inner.undo_log)
+ .var_origin(vid)
+ }
+
/// Takes ownership of the list of variable regions. This implies
/// that all the region constraints have already been taken, and
/// hence that `resolve_regions_and_report_errors` can never be
@@ -1465,7 +1562,7 @@
self.inner.borrow_mut().projection_cache().clear();
}
- fn universe(&self) -> ty::UniverseIndex {
+ pub fn universe(&self) -> ty::UniverseIndex {
self.universe.get()
}
@@ -1492,16 +1589,16 @@
pub fn const_eval_resolve(
&self,
param_env: ty::ParamEnv<'tcx>,
- ty::Unevaluated { def, substs, promoted }: ty::Unevaluated<'tcx>,
+ unevaluated: ty::Unevaluated<'tcx>,
span: Option<Span>,
) -> EvalToConstValueResult<'tcx> {
let mut original_values = OriginalQueryValues::default();
- let canonical = self.canonicalize_query((param_env, substs), &mut original_values);
+ let canonical = self.canonicalize_query((param_env, unevaluated), &mut original_values);
- let (param_env, substs) = canonical.value;
+ let (param_env, unevaluated) = canonical.value;
// The return value is the evaluated value which doesn't contain any reference to inference
// variables, thus we don't need to substitute back the original values.
- self.tcx.const_eval_resolve(param_env, ty::Unevaluated { def, substs, promoted }, span)
+ self.tcx.const_eval_resolve(param_env, unevaluated, span)
}
/// If `typ` is a type variable of some kind, resolve it one level
@@ -1705,7 +1802,7 @@
match *self {
Subtype(ref a) => a.span(),
RelateObjectBound(a) => a,
- RelateParamBound(a, _) => a,
+ RelateParamBound(a, ..) => a,
RelateRegionParamBound(a) => a,
Reborrow(a) => a,
ReborrowUpvar(a, _) => a,
diff --git a/compiler/rustc_infer/src/infer/nll_relate/mod.rs b/compiler/rustc_infer/src/infer/nll_relate/mod.rs
index 20be06a..c211d8e 100644
--- a/compiler/rustc_infer/src/infer/nll_relate/mod.rs
+++ b/compiler/rustc_infer/src/infer/nll_relate/mod.rs
@@ -22,6 +22,7 @@
//! constituents)
use crate::infer::combine::ConstEquateRelation;
+use crate::infer::type_variable::Diverging;
use crate::infer::InferCtxt;
use crate::infer::{ConstVarValue, ConstVariableValue};
use rustc_data_structures::fx::FxHashMap;
@@ -201,6 +202,7 @@
};
value.skip_binder().visit_with(&mut ScopeInstantiator {
+ tcx: self.infcx.tcx,
next_region: &mut next_region,
target_index: ty::INNERMOST,
bound_region_scope: &mut scope,
@@ -306,7 +308,7 @@
/// relations between `'0` and `'a`).
///
/// The variable `pair` can be either a `(vid, ty)` or `(ty, vid)`
- /// -- in other words, it is always a (unresolved) inference
+ /// -- in other words, it is always an (unresolved) inference
/// variable `vid` and a type `ty` that are being related, but the
/// vid may appear either as the "a" type or the "b" type,
/// depending on where it appears in the tuple. The trait
@@ -388,7 +390,7 @@
}
}
-/// When we instantiate a inference variable with a value in
+/// When we instantiate an inference variable with a value in
/// `relate_ty_var`, we always have the pair of a `TyVid` and a `Ty`,
/// but the ordering may vary (depending on whether the inference
/// variable was found on the `a` or `b` sides). Therefore, this trait
@@ -756,6 +758,7 @@
/// `for<..`>. For each of those, it creates an entry in
/// `bound_region_scope`.
struct ScopeInstantiator<'me, 'tcx> {
+ tcx: TyCtxt<'tcx>,
next_region: &'me mut dyn FnMut(ty::BoundRegion) -> ty::Region<'tcx>,
// The debruijn index of the scope we are instantiating.
target_index: ty::DebruijnIndex,
@@ -763,6 +766,10 @@
}
impl<'me, 'tcx> TypeVisitor<'tcx> for ScopeInstantiator<'me, 'tcx> {
+ fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
+ Some(self.tcx)
+ }
+
fn visit_binder<T: TypeFoldable<'tcx>>(
&mut self,
t: &ty::Binder<'tcx, T>,
@@ -920,7 +927,8 @@
// Replacing with a new variable in the universe `self.universe`,
// it will be unified later with the original type variable in
// the universe `_universe`.
- let new_var_id = variables.new_var(self.universe, false, origin);
+ let new_var_id =
+ variables.new_var(self.universe, Diverging::NotDiverging, origin);
let u = self.tcx().mk_ty_var(new_var_id);
debug!("generalize: replacing original vid={:?} with new={:?}", vid, u);
diff --git a/compiler/rustc_infer/src/infer/opaque_types.rs b/compiler/rustc_infer/src/infer/opaque_types.rs
new file mode 100644
index 0000000..d0883f2
--- /dev/null
+++ b/compiler/rustc_infer/src/infer/opaque_types.rs
@@ -0,0 +1,47 @@
+use rustc_data_structures::vec_map::VecMap;
+use rustc_hir as hir;
+use rustc_middle::ty::{OpaqueTypeKey, Ty};
+use rustc_span::Span;
+
+pub type OpaqueTypeMap<'tcx> = VecMap<OpaqueTypeKey<'tcx>, OpaqueTypeDecl<'tcx>>;
+
+/// Information about the opaque types whose values we
+/// are inferring in this function (these are the `impl Trait` that
+/// appear in the return type).
+#[derive(Copy, Clone, Debug)]
+pub struct OpaqueTypeDecl<'tcx> {
+ /// The opaque type (`ty::Opaque`) for this declaration.
+ pub opaque_type: Ty<'tcx>,
+
+ /// The span of this particular definition of the opaque type. So
+ /// for example:
+ ///
+ /// ```ignore (incomplete snippet)
+ /// type Foo = impl Baz;
+ /// fn bar() -> Foo {
+ /// // ^^^ This is the span we are looking for!
+ /// }
+ /// ```
+ ///
+ /// In cases where the fn returns `(impl Trait, impl Trait)` or
+ /// other such combinations, the result is currently
+ /// over-approximated, but better than nothing.
+ pub definition_span: Span,
+
+ /// The type variable that represents the value of the opaque type
+ /// that we require. In other words, after we compile this function,
+ /// we will be created a constraint like:
+ ///
+ /// Foo<'a, T> = ?C
+ ///
+ /// where `?C` is the value of this type variable. =) It may
+ /// naturally refer to the type and lifetime parameters in scope
+ /// in this function, though ultimately it should only reference
+ /// those that are arguments to `Foo` in the constraint above. (In
+ /// other words, `?C` should not include `'b`, even though it's a
+ /// lifetime parameter on `foo`.)
+ pub concrete_ty: Ty<'tcx>,
+
+ /// The origin of the opaque type.
+ pub origin: hir::OpaqueTyOrigin,
+}
diff --git a/compiler/rustc_infer/src/infer/outlives/mod.rs b/compiler/rustc_infer/src/infer/outlives/mod.rs
index 07c75d5..4dd5e8b 100644
--- a/compiler/rustc_infer/src/infer/outlives/mod.rs
+++ b/compiler/rustc_infer/src/infer/outlives/mod.rs
@@ -19,6 +19,7 @@
.filter_map(move |kind| match kind {
ty::PredicateKind::Projection(..)
| ty::PredicateKind::Trait(..)
+ | ty::PredicateKind::Coerce(..)
| ty::PredicateKind::Subtype(..)
| ty::PredicateKind::WellFormed(..)
| ty::PredicateKind::ObjectSafe(..)
diff --git a/compiler/rustc_infer/src/infer/outlives/obligations.rs b/compiler/rustc_infer/src/infer/outlives/obligations.rs
index 3e2978f..437083c 100644
--- a/compiler/rustc_infer/src/infer/outlives/obligations.rs
+++ b/compiler/rustc_infer/src/infer/outlives/obligations.rs
@@ -64,7 +64,7 @@
use crate::infer::{
self, GenericKind, InferCtxt, RegionObligation, SubregionOrigin, UndoLog, VerifyBound,
};
-use crate::traits::ObligationCause;
+use crate::traits::{ObligationCause, ObligationCauseCode};
use rustc_middle::ty::outlives::Component;
use rustc_middle::ty::subst::GenericArgKind;
use rustc_middle::ty::{self, Region, Ty, TyCtxt, TypeFoldable};
@@ -99,7 +99,14 @@
cause: &ObligationCause<'tcx>,
) {
let origin = SubregionOrigin::from_obligation_cause(cause, || {
- infer::RelateParamBound(cause.span, sup_type)
+ infer::RelateParamBound(
+ cause.span,
+ sup_type,
+ match cause.code.peel_derives() {
+ ObligationCauseCode::BindingObligation(_, span) => Some(*span),
+ _ => None,
+ },
+ )
});
self.register_region_obligation(
diff --git a/compiler/rustc_infer/src/infer/outlives/verify.rs b/compiler/rustc_infer/src/infer/outlives/verify.rs
index f69212c..dba7325 100644
--- a/compiler/rustc_infer/src/infer/outlives/verify.rs
+++ b/compiler/rustc_infer/src/infer/outlives/verify.rs
@@ -189,7 +189,7 @@
visited: &mut SsoHashSet<GenericArg<'tcx>>,
) -> VerifyBound<'tcx> {
let mut bounds = parent
- .walk_shallow(visited)
+ .walk_shallow(self.tcx, visited)
.filter_map(|child| match child.unpack() {
GenericArgKind::Type(ty) => Some(self.type_bound(ty, visited)),
GenericArgKind::Lifetime(lt) => {
diff --git a/compiler/rustc_infer/src/infer/region_constraints/mod.rs b/compiler/rustc_infer/src/infer/region_constraints/mod.rs
index 7f4c33c..af31ab0 100644
--- a/compiler/rustc_infer/src/infer/region_constraints/mod.rs
+++ b/compiler/rustc_infer/src/infer/region_constraints/mod.rs
@@ -186,7 +186,7 @@
/// ('a: min) || ('b: min)
/// }
///
-/// This is described with a `AnyRegion('a, 'b)` node.
+/// This is described with an `AnyRegion('a, 'b)` node.
#[derive(Debug, Clone)]
pub enum VerifyBound<'tcx> {
/// Given a kind K and a bound B, expands to a function like the
@@ -445,6 +445,11 @@
self.var_infos[vid].universe
}
+ /// Returns the origin for the given variable.
+ pub fn var_origin(&self, vid: RegionVid) -> RegionVariableOrigin {
+ self.var_infos[vid].origin
+ }
+
fn add_constraint(&mut self, constraint: Constraint<'tcx>, origin: SubregionOrigin<'tcx>) {
// cannot add constraints once regions are resolved
debug!("RegionConstraintCollector: add_constraint({:?})", constraint);
diff --git a/compiler/rustc_infer/src/infer/resolve.rs b/compiler/rustc_infer/src/infer/resolve.rs
index 48b8ee1..4b08c2e 100644
--- a/compiler/rustc_infer/src/infer/resolve.rs
+++ b/compiler/rustc_infer/src/infer/resolve.rs
@@ -126,6 +126,11 @@
impl<'a, 'tcx> TypeVisitor<'tcx> for UnresolvedTypeFinder<'a, 'tcx> {
type BreakTy = (Ty<'tcx>, Option<Span>);
+
+ fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
+ Some(self.infcx.tcx)
+ }
+
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
let t = self.infcx.shallow_resolve(t);
if t.has_infer_types() {
diff --git a/compiler/rustc_infer/src/infer/sub.rs b/compiler/rustc_infer/src/infer/sub.rs
index b313193..1692d8e 100644
--- a/compiler/rustc_infer/src/infer/sub.rs
+++ b/compiler/rustc_infer/src/infer/sub.rs
@@ -85,7 +85,7 @@
let a = infcx.inner.borrow_mut().type_variables().replace_if_possible(a);
let b = infcx.inner.borrow_mut().type_variables().replace_if_possible(b);
match (a.kind(), b.kind()) {
- (&ty::Infer(TyVar(a_vid)), &ty::Infer(TyVar(b_vid))) => {
+ (&ty::Infer(TyVar(_)), &ty::Infer(TyVar(_))) => {
// Shouldn't have any LBR here, so we can safely put
// this under a binder below without fear of accidental
// capture.
@@ -93,11 +93,7 @@
assert!(!b.has_escaping_bound_vars());
// can't make progress on `A <: B` if both A and B are
- // type variables, so record an obligation. We also
- // have to record in the `type_variables` tracker that
- // the two variables are equal modulo subtyping, which
- // is important to the occurs check later on.
- infcx.inner.borrow_mut().type_variables().sub(a_vid, b_vid);
+ // type variables, so record an obligation.
self.fields.obligations.push(Obligation::new(
self.fields.trace.cause.clone(),
self.fields.param_env,
@@ -142,7 +138,7 @@
// FIXME -- we have more fine-grained information available
// from the "cause" field, we could perhaps give more tailored
// error messages.
- let origin = SubregionOrigin::Subtype(box self.fields.trace.clone());
+ let origin = SubregionOrigin::Subtype(Box::new(self.fields.trace.clone()));
self.fields
.infcx
.inner
diff --git a/compiler/rustc_infer/src/infer/type_variable.rs b/compiler/rustc_infer/src/infer/type_variable.rs
index 13b78b2..d2b0bda 100644
--- a/compiler/rustc_infer/src/infer/type_variable.rs
+++ b/compiler/rustc_infer/src/infer/type_variable.rs
@@ -75,14 +75,30 @@
/// ?1 <: ?3
/// Box<?3> <: ?1
///
- /// This works because `?1` and `?3` are unified in the
- /// `sub_relations` relation (not in `eq_relations`). Then when we
- /// process the `Box<?3> <: ?1` constraint, we do an occurs check
- /// on `Box<?3>` and find a potential cycle.
+ /// Without this second table, what would happen in a case like
+ /// this is that we would instantiate `?1` with a generalized
+ /// type like `Box<?6>`. We would then relate `Box<?3> <: Box<?6>`
+ /// and infer that `?3 <: ?6`. Next, since `?1` was instantiated,
+ /// we would process `?1 <: ?3`, generalize `?1 = Box<?6>` to `Box<?9>`,
+ /// and instantiate `?3` with `Box<?9>`. Finally, we would relate
+ /// `?6 <: ?9`. But now that we instantiated `?3`, we can process
+ /// `?3 <: ?6`, which gives us `Box<?9> <: ?6`... and the cycle
+ /// continues. (This is `occurs-check-2.rs`.)
+ ///
+ /// What prevents this cycle is that when we generalize
+ /// `Box<?3>` to `Box<?6>`, we also sub-unify `?3` and `?6`
+ /// (in the generalizer). When we then process `Box<?6> <: ?3`,
+ /// the occurs check then fails because `?6` and `?3` are sub-unified,
+ /// and hence generalization fails.
///
/// This is reasonable because, in Rust, subtypes have the same
/// "skeleton" and hence there is no possible type such that
/// (e.g.) `Box<?3> <: ?3` for any `?3`.
+ ///
+ /// In practice, we sometimes sub-unify variables in other spots, such
+ /// as when processing subtype predicates. This is not necessary but is
+ /// done to aid diagnostics, as it allows us to be more effective when
+ /// we guide the user towards where they should insert type hints.
sub_relations: ut::UnificationTableStorage<ty::TyVid>,
}
@@ -119,7 +135,13 @@
pub(crate) struct TypeVariableData {
origin: TypeVariableOrigin,
- diverging: bool,
+ diverging: Diverging,
+}
+
+#[derive(Copy, Clone, Debug)]
+pub enum Diverging {
+ NotDiverging,
+ Diverges,
}
#[derive(Copy, Clone, Debug)]
@@ -173,7 +195,7 @@
///
/// Note that this function does not return care whether
/// `vid` has been unified with something else or not.
- pub fn var_diverges(&self, vid: ty::TyVid) -> bool {
+ pub fn var_diverges(&self, vid: ty::TyVid) -> Diverging {
self.storage.values.get(vid.index as usize).diverging
}
@@ -238,7 +260,7 @@
pub fn new_var(
&mut self,
universe: ty::UniverseIndex,
- diverging: bool,
+ diverging: Diverging,
origin: TypeVariableOrigin,
) -> ty::TyVid {
let eq_key = self.eq_relations().new_key(TypeVariableValue::Unknown { universe });
diff --git a/compiler/rustc_infer/src/infer/undo_log.rs b/compiler/rustc_infer/src/infer/undo_log.rs
index 5ad2519..89db8f4 100644
--- a/compiler/rustc_infer/src/infer/undo_log.rs
+++ b/compiler/rustc_infer/src/infer/undo_log.rs
@@ -96,7 +96,7 @@
}
/// The UndoLogs trait defines how we undo a particular kind of action (of type T). We can undo any
-/// action that is convertable into a UndoLog (per the From impls above).
+/// action that is convertable into an UndoLog (per the From impls above).
impl<'tcx, T> UndoLogs<T> for InferCtxtUndoLogs<'tcx>
where
UndoLog<'tcx>: From<T>,
diff --git a/compiler/rustc_infer/src/lib.rs b/compiler/rustc_infer/src/lib.rs
index ee358c5..a4cfadd 100644
--- a/compiler/rustc_infer/src/lib.rs
+++ b/compiler/rustc_infer/src/lib.rs
@@ -15,13 +15,13 @@
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
#![feature(bool_to_option)]
#![feature(box_patterns)]
-#![feature(box_syntax)]
#![feature(extend_one)]
#![feature(iter_zip)]
#![feature(never_type)]
#![feature(in_band_lifetimes)]
#![feature(control_flow_enum)]
#![feature(min_specialization)]
+#![feature(label_break_value)]
#![recursion_limit = "512"] // For rustdoc
#[macro_use]
diff --git a/compiler/rustc_infer/src/traits/engine.rs b/compiler/rustc_infer/src/traits/engine.rs
index 2710deb..42333dc 100644
--- a/compiler/rustc_infer/src/traits/engine.rs
+++ b/compiler/rustc_infer/src/traits/engine.rs
@@ -1,5 +1,6 @@
use crate::infer::InferCtxt;
use crate::traits::Obligation;
+use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_middle::ty::{self, ToPredicate, Ty, WithConstness};
@@ -49,11 +50,28 @@
infcx: &InferCtxt<'_, 'tcx>,
) -> Result<(), Vec<FulfillmentError<'tcx>>>;
+ fn select_all_with_constness_or_error(
+ &mut self,
+ infcx: &InferCtxt<'_, 'tcx>,
+ _constness: hir::Constness,
+ ) -> Result<(), Vec<FulfillmentError<'tcx>>> {
+ self.select_all_or_error(infcx)
+ }
+
fn select_where_possible(
&mut self,
infcx: &InferCtxt<'_, 'tcx>,
) -> Result<(), Vec<FulfillmentError<'tcx>>>;
+ // FIXME(fee1-dead) this should not provide a default body for chalk as chalk should be updated
+ fn select_with_constness_where_possible(
+ &mut self,
+ infcx: &InferCtxt<'_, 'tcx>,
+ _constness: hir::Constness,
+ ) -> Result<(), Vec<FulfillmentError<'tcx>>> {
+ self.select_where_possible(infcx)
+ }
+
fn pending_obligations(&self) -> Vec<PredicateObligation<'tcx>>;
}
diff --git a/compiler/rustc_infer/src/traits/error_reporting/mod.rs b/compiler/rustc_infer/src/traits/error_reporting/mod.rs
index 0ac4b6b..d0bd508 100644
--- a/compiler/rustc_infer/src/traits/error_reporting/mod.rs
+++ b/compiler/rustc_infer/src/traits/error_reporting/mod.rs
@@ -104,11 +104,5 @@
to be resolvable dynamically; for more information visit \
<https://doc.rust-lang.org/reference/items/traits.html#object-safety>",
);
-
- if tcx.sess.trait_methods_not_found.borrow().iter().any(|full_span| full_span.contains(span)) {
- // Avoid emitting error caused by non-existing method (#58734)
- err.cancel();
- }
-
err
}
diff --git a/compiler/rustc_infer/src/traits/mod.rs b/compiler/rustc_infer/src/traits/mod.rs
index d5c17ed..b450c39 100644
--- a/compiler/rustc_infer/src/traits/mod.rs
+++ b/compiler/rustc_infer/src/traits/mod.rs
@@ -28,7 +28,7 @@
pub use rustc_middle::traits::*;
/// An `Obligation` represents some trait reference (e.g., `i32: Eq`) for
-/// which the "impl_source" must be found. The process of finding a "impl_source" is
+/// which the "impl_source" must be found. The process of finding an "impl_source" is
/// called "resolving" the `Obligation`. This process consists of
/// either identifying an `impl` (e.g., `impl Eq for i32`) that
/// satisfies the obligation, or else finding a bound that is in
diff --git a/compiler/rustc_infer/src/traits/util.rs b/compiler/rustc_infer/src/traits/util.rs
index 1cde480..3a25cb6 100644
--- a/compiler/rustc_infer/src/traits/util.rs
+++ b/compiler/rustc_infer/src/traits/util.rs
@@ -14,17 +14,17 @@
tcx.reuse_or_mk_predicate(pred, new)
}
-struct PredicateSet<'tcx> {
+pub struct PredicateSet<'tcx> {
tcx: TyCtxt<'tcx>,
set: FxHashSet<ty::Predicate<'tcx>>,
}
impl PredicateSet<'tcx> {
- fn new(tcx: TyCtxt<'tcx>) -> Self {
+ pub fn new(tcx: TyCtxt<'tcx>) -> Self {
Self { tcx, set: Default::default() }
}
- fn insert(&mut self, pred: ty::Predicate<'tcx>) -> bool {
+ pub fn insert(&mut self, pred: ty::Predicate<'tcx>) -> bool {
// We have to be careful here because we want
//
// for<'a> Foo<&'a i32>
@@ -124,7 +124,7 @@
let bound_predicate = obligation.predicate.kind();
match bound_predicate.skip_binder() {
- ty::PredicateKind::Trait(data, _) => {
+ ty::PredicateKind::Trait(data) => {
// Get predicates declared on the trait.
let predicates = tcx.super_predicates_of(data.def_id());
@@ -158,6 +158,10 @@
// Currently, we do not "elaborate" predicates like `X <: Y`,
// though conceivably we might.
}
+ ty::PredicateKind::Coerce(..) => {
+ // Currently, we do not "elaborate" predicates like `X -> Y`,
+ // though conceivably we might.
+ }
ty::PredicateKind::Projection(..) => {
// Nothing to elaborate in a projection predicate.
}
diff --git a/compiler/rustc_interface/Cargo.toml b/compiler/rustc_interface/Cargo.toml
index 8549397..dad5b25 100644
--- a/compiler/rustc_interface/Cargo.toml
+++ b/compiler/rustc_interface/Cargo.toml
@@ -1,5 +1,4 @@
[package]
-authors = ["The Rust Project Developers"]
name = "rustc_interface"
version = "0.0.0"
edition = "2018"
diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs
index 5db027f..7127ec5 100644
--- a/compiler/rustc_interface/src/passes.rs
+++ b/compiler/rustc_interface/src/passes.rs
@@ -324,7 +324,7 @@
};
let extern_mod_loaded = |ident: Ident, attrs, items, span| {
- let krate = ast::Crate { attrs, items, span, proc_macros: vec![] };
+ let krate = ast::Crate { attrs, items, span };
pre_expansion_lint(sess, lint_store, &krate, &ident.name.as_str());
(krate.attrs, krate.items)
};
@@ -741,7 +741,6 @@
let providers = &mut Providers::default();
providers.analysis = analysis;
proc_macro_decls::provide(providers);
- plugin::build::provide(providers);
rustc_middle::hir::provide(providers);
mir::provide(providers);
mir_build::provide(providers);
@@ -856,8 +855,6 @@
{
entry_point = sess.time("looking_for_entry_point", || tcx.entry_fn(()));
- sess.time("looking_for_plugin_registrar", || tcx.ensure().plugin_registrar_fn(()));
-
sess.time("looking_for_derive_registrar", || {
tcx.ensure().proc_macro_decls_static(())
});
diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs
index 8a0964e..2f54039 100644
--- a/compiler/rustc_interface/src/queries.rs
+++ b/compiler/rustc_interface/src/queries.rs
@@ -266,7 +266,7 @@
};
let attrs = &*tcx.get_attrs(def_id);
- let attrs = attrs.iter().filter(|attr| tcx.sess.check_name(attr, sym::rustc_error));
+ let attrs = attrs.iter().filter(|attr| attr.has_name(sym::rustc_error));
for attr in attrs {
match attr.meta_item_list() {
// Check if there is a `#[rustc_error(delay_span_bug_from_inside_query)]`.
diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs
index b1e4e3b..afab919 100644
--- a/compiler/rustc_interface/src/tests.rs
+++ b/compiler/rustc_interface/src/tests.rs
@@ -735,19 +735,22 @@
tracked!(merge_functions, Some(MergeFunctions::Disabled));
tracked!(mir_emit_retag, true);
tracked!(mir_opt_level, Some(4));
+ tracked!(move_size_limit, Some(4096));
tracked!(mutable_noalias, Some(true));
tracked!(new_llvm_pass_manager, Some(true));
tracked!(no_generate_arange_section, true);
tracked!(no_link, true);
+ tracked!(no_profiler_runtime, true);
tracked!(osx_rpath_install_name, true);
tracked!(panic_abort_tests, true);
+ tracked!(partially_uninit_const_threshold, Some(123));
tracked!(plt, Some(true));
tracked!(polonius, true);
tracked!(precise_enum_drop_elaboration, false);
tracked!(print_fuel, Some("abc".to_string()));
tracked!(profile, true);
tracked!(profile_emit, Some(PathBuf::from("abc")));
- tracked!(profiler_runtime, None);
+ tracked!(profiler_runtime, "abc".to_string());
tracked!(relax_elf_relocations, Some(true));
tracked!(relro_level, Some(RelroLevel::Full));
tracked!(simulate_remapped_rust_src_base, Some(PathBuf::from("/rustc/abc")));
diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs
index 8b41a0f..a5f0c01 100644
--- a/compiler/rustc_interface/src/util.rs
+++ b/compiler/rustc_interface/src/util.rs
@@ -488,13 +488,13 @@
}
pub(crate) fn check_attr_crate_type(
- sess: &Session,
+ _sess: &Session,
attrs: &[ast::Attribute],
lint_buffer: &mut LintBuffer,
) {
// Unconditionally collect crate types from attributes to make them used
for a in attrs.iter() {
- if sess.check_name(a, sym::crate_type) {
+ if a.has_name(sym::crate_type) {
if let Some(n) = a.value_str() {
if categorize_crate_type(n).is_some() {
return;
@@ -552,7 +552,7 @@
let attr_types: Vec<CrateType> = attrs
.iter()
.filter_map(|a| {
- if session.check_name(a, sym::crate_type) {
+ if a.has_name(sym::crate_type) {
match a.value_str() {
Some(s) => categorize_crate_type(s),
_ => None,
@@ -810,6 +810,7 @@
id: resolver.next_node_id(),
span: rustc_span::DUMMY_SP,
tokens: None,
+ could_be_bare_literal: false,
}
}
diff --git a/compiler/rustc_lexer/Cargo.toml b/compiler/rustc_lexer/Cargo.toml
index 1210177..7e05fe5 100644
--- a/compiler/rustc_lexer/Cargo.toml
+++ b/compiler/rustc_lexer/Cargo.toml
@@ -1,5 +1,4 @@
[package]
-authors = ["The Rust Project Developers"]
name = "rustc_lexer"
version = "0.1.0"
license = "MIT OR Apache-2.0"
diff --git a/compiler/rustc_lexer/src/lib.rs b/compiler/rustc_lexer/src/lib.rs
index 4cb2a6c..b64a891c 100644
--- a/compiler/rustc_lexer/src/lib.rs
+++ b/compiler/rustc_lexer/src/lib.rs
@@ -273,24 +273,14 @@
/// a formal definition of valid identifier name.
pub fn is_id_start(c: char) -> bool {
// This is XID_Start OR '_' (which formally is not a XID_Start).
- // We also add fast-path for ascii idents
- ('a'..='z').contains(&c)
- || ('A'..='Z').contains(&c)
- || c == '_'
- || (c > '\x7f' && unicode_xid::UnicodeXID::is_xid_start(c))
+ c == '_' || unicode_xid::UnicodeXID::is_xid_start(c)
}
/// True if `c` is valid as a non-first character of an identifier.
/// See [Rust language reference](https://doc.rust-lang.org/reference/identifiers.html) for
/// a formal definition of valid identifier name.
pub fn is_id_continue(c: char) -> bool {
- // This is exactly XID_Continue.
- // We also add fast-path for ascii idents
- ('a'..='z').contains(&c)
- || ('A'..='Z').contains(&c)
- || ('0'..='9').contains(&c)
- || c == '_'
- || (c > '\x7f' && unicode_xid::UnicodeXID::is_xid_continue(c))
+ unicode_xid::UnicodeXID::is_xid_continue(c)
}
/// The passed string is lexically an identifier.
@@ -499,7 +489,7 @@
// Start is already eaten, eat the rest of identifier.
self.eat_while(is_id_continue);
// Known prefixes must have been handled earlier. So if
- // we see a prefix here, it is definitely a unknown prefix.
+ // we see a prefix here, it is definitely an unknown prefix.
match self.first() {
'#' | '"' | '\'' => UnknownPrefix,
_ => Ident,
diff --git a/compiler/rustc_lexer/src/unescape.rs b/compiler/rustc_lexer/src/unescape.rs
index b4dd0fc..b970c9e 100644
--- a/compiler/rustc_lexer/src/unescape.rs
+++ b/compiler/rustc_lexer/src/unescape.rs
@@ -7,7 +7,7 @@
#[cfg(test)]
mod tests;
-/// Errors that can occur during string unescaping.
+/// Errors and warnings that can occur during string unescaping.
#[derive(Debug, PartialEq, Eq)]
pub enum EscapeError {
/// Expected 1 char, but 0 were found.
@@ -56,6 +56,24 @@
NonAsciiCharInByte,
/// Non-ascii character in byte string literal.
NonAsciiCharInByteString,
+
+ /// After a line ending with '\', the next line contains whitespace
+ /// characters that are not skipped.
+ UnskippedWhitespaceWarning,
+
+ /// After a line ending with '\', multiple lines are skipped.
+ MultipleSkippedLinesWarning,
+}
+
+impl EscapeError {
+ /// Returns true for actual errors, as opposed to warnings.
+ pub fn is_fatal(&self) -> bool {
+ match self {
+ EscapeError::UnskippedWhitespaceWarning => false,
+ EscapeError::MultipleSkippedLinesWarning => false,
+ _ => true,
+ }
+ }
}
/// Takes a contents of a literal (without quotes) and produces a
@@ -283,7 +301,7 @@
// if unescaped '\' character is followed by '\n'.
// For details see [Rust language reference]
// (https://doc.rust-lang.org/reference/tokens.html#string-literals).
- skip_ascii_whitespace(&mut chars);
+ skip_ascii_whitespace(&mut chars, start, callback);
continue;
}
_ => scan_escape(first_char, &mut chars, mode),
@@ -297,13 +315,30 @@
callback(start..end, unescaped_char);
}
- fn skip_ascii_whitespace(chars: &mut Chars<'_>) {
- let str = chars.as_str();
- let first_non_space = str
+ fn skip_ascii_whitespace<F>(chars: &mut Chars<'_>, start: usize, callback: &mut F)
+ where
+ F: FnMut(Range<usize>, Result<char, EscapeError>),
+ {
+ let tail = chars.as_str();
+ let first_non_space = tail
.bytes()
.position(|b| b != b' ' && b != b'\t' && b != b'\n' && b != b'\r')
- .unwrap_or(str.len());
- *chars = str[first_non_space..].chars()
+ .unwrap_or(tail.len());
+ if tail[1..first_non_space].contains('\n') {
+ // The +1 accounts for the escaping slash.
+ let end = start + first_non_space + 1;
+ callback(start..end, Err(EscapeError::MultipleSkippedLinesWarning));
+ }
+ let tail = &tail[first_non_space..];
+ if let Some(c) = tail.chars().nth(0) {
+ // For error reporting, we would like the span to contain the character that was not
+ // skipped. The +1 is necessary to account for the leading \ that started the escape.
+ let end = start + first_non_space + c.len_utf8() + 1;
+ if c.is_whitespace() {
+ callback(start..end, Err(EscapeError::UnskippedWhitespaceWarning));
+ }
+ }
+ *chars = tail.chars();
}
}
diff --git a/compiler/rustc_lexer/src/unescape/tests.rs b/compiler/rustc_lexer/src/unescape/tests.rs
index f2b751a..fa61554 100644
--- a/compiler/rustc_lexer/src/unescape/tests.rs
+++ b/compiler/rustc_lexer/src/unescape/tests.rs
@@ -99,6 +99,30 @@
}
#[test]
+fn test_unescape_str_warn() {
+ fn check(literal: &str, expected: &[(Range<usize>, Result<char, EscapeError>)]) {
+ let mut unescaped = Vec::with_capacity(literal.len());
+ unescape_literal(literal, Mode::Str, &mut |range, res| unescaped.push((range, res)));
+ assert_eq!(unescaped, expected);
+ }
+
+ // Check we can handle escaped newlines at the end of a file.
+ check("\\\n", &[]);
+ check("\\\n ", &[]);
+
+ check(
+ "\\\n \u{a0} x",
+ &[
+ (0..5, Err(EscapeError::UnskippedWhitespaceWarning)),
+ (3..5, Ok('\u{a0}')),
+ (5..6, Ok(' ')),
+ (6..7, Ok('x')),
+ ],
+ );
+ check("\\\n \n x", &[(0..7, Err(EscapeError::MultipleSkippedLinesWarning)), (7..8, Ok('x'))]);
+}
+
+#[test]
fn test_unescape_str_good() {
fn check(literal_text: &str, expected: &str) {
let mut buf = Ok(String::with_capacity(literal_text.len()));
diff --git a/compiler/rustc_lint/Cargo.toml b/compiler/rustc_lint/Cargo.toml
index 90badd3..8294d58 100644
--- a/compiler/rustc_lint/Cargo.toml
+++ b/compiler/rustc_lint/Cargo.toml
@@ -1,10 +1,10 @@
[package]
-authors = ["The Rust Project Developers"]
name = "rustc_lint"
version = "0.0.0"
edition = "2018"
[dependencies]
+if_chain = "1.0"
tracing = "0.1"
unicode-security = "0.0.5"
rustc_middle = { path = "../rustc_middle" }
@@ -22,3 +22,4 @@
rustc_serialize = { path = "../rustc_serialize" }
rustc_trait_selection = { path = "../rustc_trait_selection" }
rustc_parse_format = { path = "../rustc_parse_format" }
+rustc_infer = { path = "../rustc_infer" }
diff --git a/compiler/rustc_lint/src/array_into_iter.rs b/compiler/rustc_lint/src/array_into_iter.rs
index 77741c7..5ac42c5 100644
--- a/compiler/rustc_lint/src/array_into_iter.rs
+++ b/compiler/rustc_lint/src/array_into_iter.rs
@@ -32,7 +32,7 @@
Warn,
"detects calling `into_iter` on arrays in Rust 2015 and 2018",
@future_incompatible = FutureIncompatibleInfo {
- reference: "issue #66145 <https://github.com/rust-lang/rust/issues/66145>",
+ reference: "<https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html>",
reason: FutureIncompatibilityReason::EditionSemanticsChange(Edition::Edition2021),
};
}
@@ -74,39 +74,45 @@
_ => return,
};
- // As this is a method call expression, we have at least one
- // argument.
+ // As this is a method call expression, we have at least one argument.
let receiver_arg = &args[0];
+ let receiver_ty = cx.typeck_results().expr_ty(receiver_arg);
+ let adjustments = cx.typeck_results().expr_adjustments(receiver_arg);
- // Peel all `Box<_>` layers. We have to special case `Box` here as
- // `Box` is the only thing that values can be moved out of via
- // method call. `Box::new([1]).into_iter()` should trigger this
- // lint.
- let mut recv_ty = cx.typeck_results().expr_ty(receiver_arg);
- let mut num_box_derefs = 0;
- while recv_ty.is_box() {
- num_box_derefs += 1;
- recv_ty = recv_ty.boxed_ty();
+ let target = match adjustments.last() {
+ Some(Adjustment { kind: Adjust::Borrow(_), target }) => target,
+ _ => return,
+ };
+
+ let types =
+ std::iter::once(receiver_ty).chain(adjustments.iter().map(|adj| adj.target));
+
+ let mut found_array = false;
+
+ for ty in types {
+ match ty.kind() {
+ // If we run into a &[T; N] or &[T] first, there's nothing to warn about.
+ // It'll resolve to the reference version.
+ ty::Ref(_, inner_ty, _) if inner_ty.is_array() => return,
+ ty::Ref(_, inner_ty, _) if matches!(inner_ty.kind(), ty::Slice(..)) => return,
+ // Found an actual array type without matching a &[T; N] first.
+ // This is the problematic case.
+ ty::Array(..) => {
+ found_array = true;
+ break;
+ }
+ _ => {}
+ }
}
- // Make sure we found an array after peeling the boxes.
- if !matches!(recv_ty.kind(), ty::Array(..)) {
+ if !found_array {
return;
}
- // Make sure that there is an autoref coercion at the expected
- // position. The first `num_box_derefs` adjustments are the derefs
- // of the box.
- match cx.typeck_results().expr_adjustments(receiver_arg).get(num_box_derefs) {
- Some(Adjustment { kind: Adjust::Borrow(_), .. }) => {}
- _ => return,
- }
-
// Emit lint diagnostic.
- let target = match *cx.typeck_results().expr_ty_adjusted(receiver_arg).kind() {
+ let target = match *target.kind() {
ty::Ref(_, inner_ty, _) if inner_ty.is_array() => "[T; N]",
ty::Ref(_, inner_ty, _) if matches!(inner_ty.kind(), ty::Slice(..)) => "[T]",
-
// We know the original first argument type is an array type,
// we know that the first adjustment was an autoref coercion
// and we know that `IntoIterator` is the trait involved. The
@@ -135,7 +141,7 @@
String::new(),
Applicability::MaybeIncorrect,
);
- } else {
+ } else if receiver_ty.is_array() {
diag.multipart_suggestion(
"or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicitly iterate by value",
vec![
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index ccdbcca..88b9e92 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -1,5 +1,3 @@
-// ignore-tidy-filelength
-
//! Lints in the Rust compiler.
//!
//! This contains lints which can feasibly be implemented as their own
@@ -38,7 +36,7 @@
use rustc_feature::{GateIssue, Stability};
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
-use rustc_hir::def_id::{DefId, LocalDefId, LocalDefIdSet};
+use rustc_hir::def_id::{DefId, LocalDefId, LocalDefIdSet, CRATE_DEF_ID};
use rustc_hir::{ForeignItemKind, GenericParamKind, PatKind};
use rustc_hir::{HirId, Node};
use rustc_index::vec::Idx;
@@ -47,12 +45,11 @@
use rustc_middle::ty::subst::{GenericArgKind, Subst};
use rustc_middle::ty::Instance;
use rustc_middle::ty::{self, layout::LayoutError, Ty, TyCtxt};
-use rustc_session::lint::FutureIncompatibilityReason;
-use rustc_session::Session;
+use rustc_session::lint::{BuiltinLintDiagnostics, FutureIncompatibilityReason};
use rustc_span::edition::Edition;
use rustc_span::source_map::Spanned;
use rustc_span::symbol::{kw, sym, Ident, Symbol};
-use rustc_span::{BytePos, Span};
+use rustc_span::{BytePos, InnerSpan, MultiSpan, Span};
use rustc_target::abi::{LayoutOf, VariantIdx};
use rustc_trait_selection::traits::misc::can_type_implement_copy;
@@ -155,8 +152,8 @@
declare_lint_pass!(BoxPointers => [BOX_POINTERS]);
impl BoxPointers {
- fn check_heap_type(&self, cx: &LateContext<'_>, span: Span, ty: Ty<'_>) {
- for leaf in ty.walk() {
+ fn check_heap_type<'tcx>(&self, cx: &LateContext<'tcx>, span: Span, ty: Ty<'tcx>) {
+ for leaf in ty.walk(cx.tcx) {
if let GenericArgKind::Type(leaf_ty) = leaf.unpack() {
if leaf_ty.is_box() {
cx.struct_span_lint(BOX_POINTERS, span, |lint| {
@@ -346,7 +343,7 @@
impl EarlyLintPass for UnsafeCode {
fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &ast::Attribute) {
- if cx.sess().check_name(attr, sym::allow_internal_unsafe) {
+ if attr.has_name(sym::allow_internal_unsafe) {
self.report_unsafe(cx, attr.span, |lint| {
lint.build(
"`allow_internal_unsafe` allows defining \
@@ -419,6 +416,25 @@
}
}
+ fn check_impl_item(&mut self, cx: &EarlyContext<'_>, it: &ast::AssocItem) {
+ if let ast::AssocItemKind::Fn(..) = it.kind {
+ if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::no_mangle) {
+ self.report_overriden_symbol_name(
+ cx,
+ attr.span,
+ "declaration of a `no_mangle` method",
+ );
+ }
+ if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::export_name) {
+ self.report_overriden_symbol_name(
+ cx,
+ attr.span,
+ "declaration of a method with `export_name`",
+ );
+ }
+ }
+ }
+
fn check_fn(&mut self, cx: &EarlyContext<'_>, fk: FnKind<'_>, span: Span, _: ast::NodeId) {
if let FnKind::Fn(
ctxt,
@@ -475,12 +491,12 @@
impl_lint_pass!(MissingDoc => [MISSING_DOCS]);
-fn has_doc(sess: &Session, attr: &ast::Attribute) -> bool {
+fn has_doc(attr: &ast::Attribute) -> bool {
if attr.is_doc_comment() {
return true;
}
- if !sess.check_name(attr, sym::doc) {
+ if !attr.has_name(sym::doc) {
return false;
}
@@ -511,7 +527,7 @@
fn check_missing_docs_attrs(
&self,
cx: &LateContext<'_>,
- id: hir::HirId,
+ def_id: LocalDefId,
sp: Span,
article: &'static str,
desc: &'static str,
@@ -530,14 +546,14 @@
// Only check publicly-visible items, using the result from the privacy pass.
// It's an option so the crate root can also use this function (it doesn't
// have a `NodeId`).
- if id != hir::CRATE_HIR_ID {
- if !cx.access_levels.is_exported(id) {
+ if def_id != CRATE_DEF_ID {
+ if !cx.access_levels.is_exported(def_id) {
return;
}
}
- let attrs = cx.tcx.hir().attrs(id);
- let has_doc = attrs.iter().any(|a| has_doc(cx.sess(), a));
+ let attrs = cx.tcx.get_attrs(def_id.to_def_id());
+ let has_doc = attrs.iter().any(has_doc);
if !has_doc {
cx.struct_span_lint(
MISSING_DOCS,
@@ -551,10 +567,10 @@
}
impl<'tcx> LateLintPass<'tcx> for MissingDoc {
- fn enter_lint_attrs(&mut self, cx: &LateContext<'_>, attrs: &[ast::Attribute]) {
+ fn enter_lint_attrs(&mut self, _cx: &LateContext<'_>, attrs: &[ast::Attribute]) {
let doc_hidden = self.doc_hidden()
|| attrs.iter().any(|attr| {
- cx.sess().check_name(attr, sym::doc)
+ attr.has_name(sym::doc)
&& match attr.meta_item_list() {
None => false,
Some(l) => attr::list_contains_name(&l, sym::hidden),
@@ -568,25 +584,7 @@
}
fn check_crate(&mut self, cx: &LateContext<'_>, krate: &hir::Crate<'_>) {
- self.check_missing_docs_attrs(cx, hir::CRATE_HIR_ID, krate.item.inner, "the", "crate");
-
- for macro_def in krate.exported_macros {
- // Non exported macros should be skipped, since `missing_docs` only
- // applies to externally visible items.
- if !cx.access_levels.is_exported(macro_def.hir_id()) {
- continue;
- }
-
- let attrs = cx.tcx.hir().attrs(macro_def.hir_id());
- let has_doc = attrs.iter().any(|a| has_doc(cx.sess(), a));
- if !has_doc {
- cx.struct_span_lint(
- MISSING_DOCS,
- cx.tcx.sess.source_map().guess_head_span(macro_def.span),
- |lint| lint.build("missing documentation for macro").emit(),
- );
- }
- }
+ self.check_missing_docs_attrs(cx, CRATE_DEF_ID, krate.module().inner, "the", "crate");
}
fn check_item(&mut self, cx: &LateContext<'_>, it: &hir::Item<'_>) {
@@ -620,6 +618,7 @@
hir::ItemKind::TyAlias(..)
| hir::ItemKind::Fn(..)
+ | hir::ItemKind::Macro(..)
| hir::ItemKind::Mod(..)
| hir::ItemKind::Enum(..)
| hir::ItemKind::Struct(..)
@@ -632,7 +631,7 @@
let (article, desc) = cx.tcx.article_and_description(it.def_id.to_def_id());
- self.check_missing_docs_attrs(cx, it.hir_id(), it.span, article, desc);
+ self.check_missing_docs_attrs(cx, it.def_id, it.span, article, desc);
}
fn check_trait_item(&mut self, cx: &LateContext<'_>, trait_item: &hir::TraitItem<'_>) {
@@ -642,7 +641,7 @@
let (article, desc) = cx.tcx.article_and_description(trait_item.def_id.to_def_id());
- self.check_missing_docs_attrs(cx, trait_item.hir_id(), trait_item.span, article, desc);
+ self.check_missing_docs_attrs(cx, trait_item.def_id, trait_item.span, article, desc);
}
fn check_impl_item(&mut self, cx: &LateContext<'_>, impl_item: &hir::ImplItem<'_>) {
@@ -652,22 +651,23 @@
}
let (article, desc) = cx.tcx.article_and_description(impl_item.def_id.to_def_id());
- self.check_missing_docs_attrs(cx, impl_item.hir_id(), impl_item.span, article, desc);
+ self.check_missing_docs_attrs(cx, impl_item.def_id, impl_item.span, article, desc);
}
fn check_foreign_item(&mut self, cx: &LateContext<'_>, foreign_item: &hir::ForeignItem<'_>) {
let (article, desc) = cx.tcx.article_and_description(foreign_item.def_id.to_def_id());
- self.check_missing_docs_attrs(cx, foreign_item.hir_id(), foreign_item.span, article, desc);
+ self.check_missing_docs_attrs(cx, foreign_item.def_id, foreign_item.span, article, desc);
}
fn check_field_def(&mut self, cx: &LateContext<'_>, sf: &hir::FieldDef<'_>) {
if !sf.is_positional() {
- self.check_missing_docs_attrs(cx, sf.hir_id, sf.span, "a", "struct field")
+ let def_id = cx.tcx.hir().local_def_id(sf.hir_id);
+ self.check_missing_docs_attrs(cx, def_id, sf.span, "a", "struct field")
}
}
fn check_variant(&mut self, cx: &LateContext<'_>, v: &hir::Variant<'_>) {
- self.check_missing_docs_attrs(cx, v.id, v.span, "a", "variant");
+ self.check_missing_docs_attrs(cx, cx.tcx.hir().local_def_id(v.id), v.span, "a", "variant");
}
}
@@ -709,7 +709,7 @@
impl<'tcx> LateLintPass<'tcx> for MissingCopyImplementations {
fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) {
- if !cx.access_levels.is_reachable(item.hir_id()) {
+ if !cx.access_levels.is_reachable(item.def_id) {
return;
}
let (def, ty) = match item.kind {
@@ -796,7 +796,7 @@
impl<'tcx> LateLintPass<'tcx> for MissingDebugImplementations {
fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) {
- if !cx.access_levels.is_reachable(item.hir_id()) {
+ if !cx.access_levels.is_reachable(item.def_id) {
return;
}
@@ -981,7 +981,7 @@
return;
}
}
- if cx.sess().check_name(attr, sym::no_start) || cx.sess().check_name(attr, sym::crate_id) {
+ if attr.has_name(sym::no_start) || attr.has_name(sym::crate_id) {
let path_str = pprust::path_to_string(&attr.get_normal_item().path);
let msg = format!("use of deprecated attribute `{}`: no longer used.", path_str);
lint_deprecated_attr(cx, attr, &msg, None);
@@ -1010,7 +1010,7 @@
let span = sugared_span.take().unwrap_or(attr.span);
- if is_doc_comment || cx.sess().check_name(attr, sym::doc) {
+ if is_doc_comment || attr.has_name(sym::doc) {
cx.struct_span_lint(UNUSED_DOC_COMMENTS, span, |lint| {
let mut err = lint.build("unused doc comment");
err.span_label(
@@ -1116,31 +1116,37 @@
impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems {
fn check_item(&mut self, cx: &LateContext<'_>, it: &hir::Item<'_>) {
let attrs = cx.tcx.hir().attrs(it.hir_id());
+ let check_no_mangle_on_generic_fn = |no_mangle_attr: &ast::Attribute,
+ impl_generics: Option<&hir::Generics<'_>>,
+ generics: &hir::Generics<'_>,
+ span| {
+ for param in
+ generics.params.iter().chain(impl_generics.map(|g| g.params).into_iter().flatten())
+ {
+ match param.kind {
+ GenericParamKind::Lifetime { .. } => {}
+ GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => {
+ cx.struct_span_lint(NO_MANGLE_GENERIC_ITEMS, span, |lint| {
+ lint.build("functions generic over types or consts must be mangled")
+ .span_suggestion_short(
+ no_mangle_attr.span,
+ "remove this attribute",
+ String::new(),
+ // Use of `#[no_mangle]` suggests FFI intent; correct
+ // fix may be to monomorphize source by hand
+ Applicability::MaybeIncorrect,
+ )
+ .emit();
+ });
+ break;
+ }
+ }
+ }
+ };
match it.kind {
hir::ItemKind::Fn(.., ref generics, _) => {
if let Some(no_mangle_attr) = cx.sess().find_by_name(attrs, sym::no_mangle) {
- for param in generics.params {
- match param.kind {
- GenericParamKind::Lifetime { .. } => {}
- GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => {
- cx.struct_span_lint(NO_MANGLE_GENERIC_ITEMS, it.span, |lint| {
- lint.build(
- "functions generic over types or consts must be mangled",
- )
- .span_suggestion_short(
- no_mangle_attr.span,
- "remove this attribute",
- String::new(),
- // Use of `#[no_mangle]` suggests FFI intent; correct
- // fix may be to monomorphize source by hand
- Applicability::MaybeIncorrect,
- )
- .emit();
- });
- break;
- }
- }
- }
+ check_no_mangle_on_generic_fn(no_mangle_attr, None, generics, it.span);
}
}
hir::ItemKind::Const(..) => {
@@ -1171,6 +1177,23 @@
});
}
}
+ hir::ItemKind::Impl(hir::Impl { ref generics, items, .. }) => {
+ for it in items {
+ if let hir::AssocItemKind::Fn { .. } = it.kind {
+ if let Some(no_mangle_attr) = cx
+ .sess()
+ .find_by_name(cx.tcx.hir().attrs(it.id.hir_id()), sym::no_mangle)
+ {
+ check_no_mangle_on_generic_fn(
+ no_mangle_attr,
+ Some(generics),
+ cx.tcx.hir().get_generics(it.id.def_id.to_def_id()).unwrap(),
+ it.span,
+ );
+ }
+ }
+ }
+ }
_ => {}
}
}
@@ -1260,7 +1283,7 @@
impl<'tcx> LateLintPass<'tcx> for UnstableFeatures {
fn check_attribute(&mut self, cx: &LateContext<'_>, attr: &ast::Attribute) {
- if cx.sess().check_name(attr, sym::feature) {
+ if attr.has_name(sym::feature) {
if let Some(items) = attr.meta_item_list() {
for item in items {
cx.struct_span_lint(UNSTABLE_FEATURES, item.span(), |lint| {
@@ -1314,14 +1337,14 @@
&self,
cx: &LateContext<'_>,
what: &str,
- id: hir::HirId,
+ def_id: LocalDefId,
vis: &hir::Visibility<'_>,
span: Span,
exportable: bool,
) {
let mut applicability = Applicability::MachineApplicable;
match vis.node {
- hir::VisibilityKind::Public if !cx.access_levels.is_reachable(id) => {
+ hir::VisibilityKind::Public if !cx.access_levels.is_reachable(def_id) => {
if span.from_expansion() {
applicability = Applicability::MaybeIncorrect;
}
@@ -1354,14 +1377,14 @@
impl<'tcx> LateLintPass<'tcx> for UnreachablePub {
fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) {
- self.perform_lint(cx, "item", item.hir_id(), &item.vis, item.span, true);
+ self.perform_lint(cx, "item", item.def_id, &item.vis, item.span, true);
}
fn check_foreign_item(&mut self, cx: &LateContext<'_>, foreign_item: &hir::ForeignItem<'tcx>) {
self.perform_lint(
cx,
"item",
- foreign_item.hir_id(),
+ foreign_item.def_id,
&foreign_item.vis,
foreign_item.span,
true,
@@ -1369,11 +1392,12 @@
}
fn check_field_def(&mut self, cx: &LateContext<'_>, field: &hir::FieldDef<'_>) {
- self.perform_lint(cx, "field", field.hir_id, &field.vis, field.span, false);
+ let def_id = cx.tcx.hir().local_def_id(field.hir_id);
+ self.perform_lint(cx, "field", def_id, &field.vis, field.span, false);
}
fn check_impl_item(&mut self, cx: &LateContext<'_>, impl_item: &hir::ImplItem<'_>) {
- self.perform_lint(cx, "item", impl_item.hir_id(), &impl_item.vis, impl_item.span, false);
+ self.perform_lint(cx, "item", impl_item.def_id, &impl_item.vis, impl_item.span, false);
}
}
@@ -1610,11 +1634,12 @@
ObjectSafe(..) |
ClosureKind(..) |
Subtype(..) |
+ Coerce(..) |
ConstEvaluatable(..) |
ConstEquate(..) |
TypeWellFormedFromEnv(..) => continue,
};
- if predicate.is_global() {
+ if predicate.is_global(cx.tcx) {
cx.struct_span_lint(TRIVIAL_BOUNDS, span, |lint| {
lint.build(&format!(
"{} bound {} does not depend on any type \
@@ -1680,7 +1705,7 @@
Warn,
"`...` range patterns are deprecated",
@future_incompatible = FutureIncompatibleInfo {
- reference: "issue #80165 <https://github.com/rust-lang/rust/issues/80165>",
+ reference: "<https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>",
reason: FutureIncompatibilityReason::EditionError(Edition::Edition2021),
};
}
@@ -2315,7 +2340,7 @@
/// ### Example
///
/// ```rust
- /// #![feature(const_generics)]
+ /// #![feature(generic_const_exprs)]
/// ```
///
/// {{produces}}
@@ -2728,7 +2753,7 @@
overridden_link_name,
tcx.get_attrs(fi.def_id.to_def_id())
.iter()
- .find(|at| tcx.sess.check_name(at, sym::link_name))
+ .find(|at| at.has_name(sym::link_name))
.unwrap()
.span,
)
@@ -3098,3 +3123,123 @@
}
}
}
+
+declare_lint! {
+ /// The `named_asm_labels` lint detects the use of named labels in the
+ /// inline `asm!` macro.
+ ///
+ /// ### Example
+ ///
+ /// ```rust,compile_fail
+ /// #![feature(asm)]
+ /// fn main() {
+ /// unsafe {
+ /// asm!("foo: bar");
+ /// }
+ /// }
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// LLVM is allowed to duplicate inline assembly blocks for any
+ /// reason, for example when it is in a function that gets inlined. Because
+ /// of this, GNU assembler [local labels] *must* be used instead of labels
+ /// with a name. Using named labels might cause assembler or linker errors.
+ ///
+ /// See the [unstable book] for more details.
+ ///
+ /// [local labels]: https://sourceware.org/binutils/docs/as/Symbol-Names.html#Local-Labels
+ /// [unstable book]: https://doc.rust-lang.org/nightly/unstable-book/library-features/asm.html#labels
+ pub NAMED_ASM_LABELS,
+ Deny,
+ "named labels in inline assembly",
+}
+
+declare_lint_pass!(NamedAsmLabels => [NAMED_ASM_LABELS]);
+
+impl<'tcx> LateLintPass<'tcx> for NamedAsmLabels {
+ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) {
+ if let hir::Expr {
+ kind: hir::ExprKind::InlineAsm(hir::InlineAsm { template_strs, .. }),
+ ..
+ } = expr
+ {
+ for (template_sym, template_snippet, template_span) in template_strs.iter() {
+ let template_str = &template_sym.as_str();
+ let find_label_span = |needle: &str| -> Option<Span> {
+ if let Some(template_snippet) = template_snippet {
+ let snippet = template_snippet.as_str();
+ if let Some(pos) = snippet.find(needle) {
+ let end = pos
+ + &snippet[pos..]
+ .find(|c| c == ':')
+ .unwrap_or(snippet[pos..].len() - 1);
+ let inner = InnerSpan::new(pos, end);
+ return Some(template_span.from_inner(inner));
+ }
+ }
+
+ None
+ };
+
+ let mut found_labels = Vec::new();
+
+ // A semicolon might not actually be specified as a separator for all targets, but it seems like LLVM accepts it always
+ let statements = template_str.split(|c| matches!(c, '\n' | ';'));
+ for statement in statements {
+ // If there's a comment, trim it from the statement
+ let statement = statement.find("//").map_or(statement, |idx| &statement[..idx]);
+ let mut start_idx = 0;
+ for (idx, _) in statement.match_indices(':') {
+ let possible_label = statement[start_idx..idx].trim();
+ let mut chars = possible_label.chars();
+ if let Some(c) = chars.next() {
+ // A label starts with an alphabetic character or . or _ and continues with alphanumeric characters, _, or $
+ if (c.is_alphabetic() || matches!(c, '.' | '_'))
+ && chars.all(|c| c.is_alphanumeric() || matches!(c, '_' | '$'))
+ {
+ found_labels.push(possible_label);
+ } else {
+ // If we encounter a non-label, there cannot be any further labels, so stop checking
+ break;
+ }
+ } else {
+ // Empty string means a leading ':' in this section, which is not a label
+ break;
+ }
+
+ start_idx = idx + 1;
+ }
+ }
+
+ debug!("NamedAsmLabels::check_expr(): found_labels: {:#?}", &found_labels);
+
+ if found_labels.len() > 0 {
+ let spans = found_labels
+ .into_iter()
+ .filter_map(|label| find_label_span(label))
+ .collect::<Vec<Span>>();
+ // If there were labels but we couldn't find a span, combine the warnings and use the template span
+ let target_spans: MultiSpan =
+ if spans.len() > 0 { spans.into() } else { (*template_span).into() };
+
+ cx.lookup_with_diagnostics(
+ NAMED_ASM_LABELS,
+ Some(target_spans),
+ |diag| {
+ let mut err =
+ diag.build("avoid using named labels in inline assembly");
+ err.emit();
+ },
+ BuiltinLintDiagnostics::NamedAsmLabel(
+ "only local labels of the form `<number>:` should be used in inline asm"
+ .to_string(),
+ ),
+ );
+ }
+ }
+ }
+ }
+}
diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs
index f448acd..7dbc3d6 100644
--- a/compiler/rustc_lint/src/context.rs
+++ b/compiler/rustc_lint/src/context.rs
@@ -41,7 +41,7 @@
use rustc_session::SessionLintStore;
use rustc_span::lev_distance::find_best_match_for_name;
use rustc_span::{symbol::Symbol, MultiSpan, Span, DUMMY_SP};
-use rustc_target::abi::LayoutOf;
+use rustc_target::abi::{self, LayoutOf};
use tracing::debug;
use std::cell::Cell;
@@ -332,7 +332,16 @@
crate_attrs: &[ast::Attribute],
) {
let (tool_name, lint_name_only) = parse_lint_and_tool_name(lint_name);
-
+ if lint_name_only == crate::WARNINGS.name_lower() && level == Level::ForceWarn {
+ return struct_span_err!(
+ sess,
+ DUMMY_SP,
+ E0602,
+ "`{}` lint group is not supported with ´--force-warn´",
+ crate::WARNINGS.name_lower()
+ )
+ .emit();
+ }
let db = match self.check_lint_name(sess, lint_name_only, tool_name, crate_attrs) {
CheckLintNameResult::Ok(_) => None,
CheckLintNameResult::Warning(ref msg, _) => Some(sess.struct_warn(msg)),
@@ -734,6 +743,34 @@
Applicability::MachineApplicable,
);
}
+ BuiltinLintDiagnostics::UnusedBuiltinAttribute {
+ attr_name,
+ macro_name,
+ invoc_span
+ } => {
+ db.span_note(
+ invoc_span,
+ &format!("the built-in attribute `{attr_name}` will be ignored, since it's applied to the macro invocation `{macro_name}`")
+ );
+ }
+ BuiltinLintDiagnostics::TrailingMacro(is_trailing, name) => {
+ if is_trailing {
+ db.note("macro invocations at the end of a block are treated as expressions");
+ db.note(&format!("to ignore the value produced by the macro, add a semicolon after the invocation of `{name}`"));
+ }
+ }
+ BuiltinLintDiagnostics::BreakWithLabelAndLoop(span) => {
+ db.multipart_suggestion(
+ "wrap this expression in parentheses",
+ vec![(span.shrink_to_lo(), "(".to_string()),
+ (span.shrink_to_hi(), ")".to_string())],
+ Applicability::MachineApplicable
+ );
+ }
+ BuiltinLintDiagnostics::NamedAsmLabel(help) => {
+ db.help(&help);
+ db.note("see the asm section of the unstable book <https://doc.rust-lang.org/nightly/unstable-book/library-features/asm.html#labels> for more information");
+ }
}
// Rewrap `db`, and pass control to the user.
decorate(LintDiagnosticBuilder::new(db));
@@ -1022,7 +1059,28 @@
}
}
-impl<'tcx> LayoutOf for LateContext<'tcx> {
+impl<'tcx> abi::HasDataLayout for LateContext<'tcx> {
+ #[inline]
+ fn data_layout(&self) -> &abi::TargetDataLayout {
+ &self.tcx.data_layout
+ }
+}
+
+impl<'tcx> ty::layout::HasTyCtxt<'tcx> for LateContext<'tcx> {
+ #[inline]
+ fn tcx(&self) -> TyCtxt<'tcx> {
+ self.tcx
+ }
+}
+
+impl<'tcx> ty::layout::HasParamEnv<'tcx> for LateContext<'tcx> {
+ #[inline]
+ fn param_env(&self) -> ty::ParamEnv<'tcx> {
+ self.param_env
+ }
+}
+
+impl<'tcx> LayoutOf<'tcx> for LateContext<'tcx> {
type Ty = Ty<'tcx>;
type TyAndLayout = Result<TyAndLayout<'tcx>, LayoutError<'tcx>>;
diff --git a/compiler/rustc_lint/src/late.rs b/compiler/rustc_lint/src/late.rs
index e504662..30400da 100644
--- a/compiler/rustc_lint/src/late.rs
+++ b/compiler/rustc_lint/src/late.rs
@@ -244,6 +244,11 @@
hir_visit::walk_ty(self, t);
}
+ fn visit_infer(&mut self, inf: &'tcx hir::InferArg) {
+ lint_callback!(self, check_infer, inf);
+ hir_visit::walk_inf(self, inf);
+ }
+
fn visit_name(&mut self, sp: Span, name: Symbol) {
lint_callback!(self, check_name, sp, name);
}
@@ -448,10 +453,6 @@
lint_callback!(cx, check_crate, krate);
hir_visit::walk_crate(cx, krate);
- for attr in krate.non_exported_macro_attrs {
- // This HIR ID is a lie, since the macro ID isn't available.
- cx.visit_attribute(hir::CRATE_HIR_ID, attr);
- }
lint_callback!(cx, check_crate_post, krate);
})
diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs
index 069fa41..90bf34e 100644
--- a/compiler/rustc_lint/src/levels.rs
+++ b/compiler/rustc_lint/src/levels.rs
@@ -33,13 +33,10 @@
let mut builder = LintLevelMapBuilder { levels, tcx, store };
let krate = tcx.hir().krate();
- builder.levels.id_to_set.reserve(krate.exported_macros.len() + 1);
+ builder.levels.id_to_set.reserve(krate.owners.len() + 1);
let push = builder.levels.push(tcx.hir().attrs(hir::CRATE_HIR_ID), &store, true);
builder.levels.register_id(hir::CRATE_HIR_ID);
- for macro_def in krate.exported_macros {
- builder.levels.register_id(macro_def.hir_id());
- }
intravisit::walk_crate(&mut builder, krate);
builder.levels.pop(push);
@@ -236,8 +233,6 @@
Some(lvl) => lvl,
};
- self.sess.mark_attr_used(attr);
-
let mut metas = unwrap_or!(attr.meta_item_list(), continue);
if metas.is_empty() {
@@ -576,7 +571,7 @@
// NOTE: does no error handling; error handling is done by rustc_resolve.
sess.filter_by_name(attrs, sym::register_tool)
.filter_map(|attr| attr.meta_item_list())
- .flat_map(std::convert::identity)
+ .flatten()
.filter_map(|nested_meta| nested_meta.ident())
.map(|ident| ident.name)
.any(|name| name == m_item)
diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs
index c947801..ef4bda6 100644
--- a/compiler/rustc_lint/src/lib.rs
+++ b/compiler/rustc_lint/src/lib.rs
@@ -29,9 +29,9 @@
#![cfg_attr(test, feature(test))]
#![feature(array_windows)]
#![feature(bool_to_option)]
-#![feature(box_syntax)]
#![feature(box_patterns)]
#![feature(crate_visibility_modifier)]
+#![feature(format_args_capture)]
#![feature(iter_order_by)]
#![feature(iter_zip)]
#![feature(never_type)]
@@ -62,6 +62,8 @@
mod types;
mod unused;
+pub use array_into_iter::ARRAY_INTO_ITER;
+
use rustc_ast as ast;
use rustc_hir as hir;
use rustc_hir::def_id::LocalDefId;
@@ -151,8 +153,6 @@
// FIXME: Look into regression when this is used as a module lint
// May Depend on constants elsewhere
UnusedBrokenConst: UnusedBrokenConst,
- // Uses attr::is_used which is untracked, can't be an incremental module pass.
- UnusedAttributes: UnusedAttributes::new(),
// Needs to run after UnusedAttributes as it marks all `feature` attributes as used.
UnstableFeatures: UnstableFeatures,
// Tracks state across modules
@@ -169,6 +169,8 @@
TemporaryCStringAsPtr: TemporaryCStringAsPtr,
NonPanicFmt: NonPanicFmt,
NoopMethodCall: NoopMethodCall,
+ InvalidAtomicOrdering: InvalidAtomicOrdering,
+ NamedAsmLabels: NamedAsmLabels,
]
);
};
@@ -244,7 +246,7 @@
macro_rules! register_pass {
($method:ident, $ty:ident, $constructor:expr) => {
store.register_lints(&$ty::get_lints());
- store.$method(|| box $constructor);
+ store.$method(|| Box::new($constructor));
};
}
@@ -476,13 +478,13 @@
fn register_internals(store: &mut LintStore) {
store.register_lints(&LintPassImpl::get_lints());
- store.register_early_pass(|| box LintPassImpl);
+ store.register_early_pass(|| Box::new(LintPassImpl));
store.register_lints(&DefaultHashTypes::get_lints());
- store.register_late_pass(|| box DefaultHashTypes);
+ store.register_late_pass(|| Box::new(DefaultHashTypes));
store.register_lints(&ExistingDocKeyword::get_lints());
- store.register_late_pass(|| box ExistingDocKeyword);
+ store.register_late_pass(|| Box::new(ExistingDocKeyword));
store.register_lints(&TyTyKind::get_lints());
- store.register_late_pass(|| box TyTyKind);
+ store.register_late_pass(|| Box::new(TyTyKind));
store.register_group(
false,
"rustc::internal",
diff --git a/compiler/rustc_lint/src/non_fmt_panic.rs b/compiler/rustc_lint/src/non_fmt_panic.rs
index a32caf1..33a6eda 100644
--- a/compiler/rustc_lint/src/non_fmt_panic.rs
+++ b/compiler/rustc_lint/src/non_fmt_panic.rs
@@ -2,11 +2,15 @@
use rustc_ast as ast;
use rustc_errors::{pluralize, Applicability};
use rustc_hir as hir;
+use rustc_infer::infer::TyCtxtInferExt;
+use rustc_middle::lint::in_external_macro;
use rustc_middle::ty;
+use rustc_middle::ty::subst::InternalSubsts;
use rustc_parse_format::{ParseMode, Parser, Piece};
use rustc_session::lint::FutureIncompatibilityReason;
use rustc_span::edition::Edition;
use rustc_span::{hygiene, sym, symbol::kw, symbol::SymbolStr, InnerSpan, Span, Symbol};
+use rustc_trait_selection::infer::InferCtxtExt;
declare_lint! {
/// The `non_fmt_panics` lint detects `panic!(..)` invocations where the first
@@ -75,6 +79,11 @@
let (span, panic, symbol_str) = panic_call(cx, f);
+ if in_external_macro(cx.sess(), span) {
+ // Nothing that can be done about it in the current crate.
+ return;
+ }
+
// Find the span of the argument to `panic!()`, before expansion in the
// case of `panic!(some_macro!())`.
// We don't use source_callsite(), because this `panic!(..)` might itself
@@ -93,9 +102,9 @@
cx.struct_span_lint(NON_FMT_PANICS, arg_span, |lint| {
let mut l = lint.build("panic message is not a string literal");
- l.note("this usage of panic!() is deprecated; it will be a hard error in Rust 2021");
+ l.note(&format!("this usage of {}!() is deprecated; it will be a hard error in Rust 2021", symbol_str));
l.note("for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html>");
- if !span.contains(arg_span) {
+ if !is_arg_inside_call(arg_span, span) {
// No clue where this argument is coming from.
l.emit();
return;
@@ -114,16 +123,66 @@
);
}
} else {
- l.span_suggestion_verbose(
- arg_span.shrink_to_lo(),
- "add a \"{}\" format string to Display the message",
- "\"{}\", ".into(),
- Applicability::MaybeIncorrect,
+ let ty = cx.typeck_results().expr_ty(arg);
+ // If this is a &str or String, we can confidently give the `"{}", ` suggestion.
+ let is_str = matches!(
+ ty.kind(),
+ ty::Ref(_, r, _) if *r.kind() == ty::Str,
+ ) || matches!(
+ ty.ty_adt_def(),
+ Some(ty_def) if cx.tcx.is_diagnostic_item(sym::string_type, ty_def.did),
);
- if panic == sym::std_panic_macro {
+
+ let (suggest_display, suggest_debug) = cx.tcx.infer_ctxt().enter(|infcx| {
+ let display = is_str || cx.tcx.get_diagnostic_item(sym::display_trait).map(|t| {
+ infcx.type_implements_trait(t, ty, InternalSubsts::empty(), cx.param_env).may_apply()
+ }) == Some(true);
+ let debug = !display && cx.tcx.get_diagnostic_item(sym::debug_trait).map(|t| {
+ infcx.type_implements_trait(t, ty, InternalSubsts::empty(), cx.param_env).may_apply()
+ }) == Some(true);
+ (display, debug)
+ });
+
+ let suggest_panic_any = !is_str && panic == sym::std_panic_macro;
+
+ let fmt_applicability = if suggest_panic_any {
+ // If we can use panic_any, use that as the MachineApplicable suggestion.
+ Applicability::MaybeIncorrect
+ } else {
+ // If we don't suggest panic_any, using a format string is our best bet.
+ Applicability::MachineApplicable
+ };
+
+ if suggest_display {
+ l.span_suggestion_verbose(
+ arg_span.shrink_to_lo(),
+ "add a \"{}\" format string to Display the message",
+ "\"{}\", ".into(),
+ fmt_applicability,
+ );
+ } else if suggest_debug {
+ l.span_suggestion_verbose(
+ arg_span.shrink_to_lo(),
+ &format!(
+ "add a \"{{:?}}\" format string to use the Debug implementation of `{}`",
+ ty,
+ ),
+ "\"{:?}\", ".into(),
+ fmt_applicability,
+ );
+ }
+
+ if suggest_panic_any {
if let Some((open, close, del)) = find_delimiters(cx, span) {
l.multipart_suggestion(
- "or use std::panic::panic_any instead",
+ &format!(
+ "{}use std::panic::panic_any instead",
+ if suggest_display || suggest_debug {
+ "or "
+ } else {
+ ""
+ },
+ ),
if del == '(' {
vec![(span.until(open), "std::panic::panic_any".into())]
} else {
@@ -152,6 +211,13 @@
return;
}
+ let (span, _, _) = panic_call(cx, f);
+
+ if in_external_macro(cx.sess(), span) && in_external_macro(cx.sess(), arg.span) {
+ // Nothing that can be done about it in the current crate.
+ return;
+ }
+
let fmt_span = arg.span.source_callsite();
let (snippet, style) = match cx.sess().parse_sess.source_map().span_to_snippet(fmt_span) {
@@ -167,8 +233,6 @@
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],
@@ -180,7 +244,7 @@
_ => "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) {
+ if is_arg_inside_call(arg.span, span) {
l.span_suggestion(
arg.span.shrink_to_hi(),
&format!("add the missing argument{}", pluralize!(n_arguments)),
@@ -211,7 +275,7 @@
cx.struct_span_lint(NON_FMT_PANICS, brace_spans.unwrap_or_else(|| 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) {
+ if is_arg_inside_call(arg.span, span) {
l.span_suggestion(
arg.span.shrink_to_lo(),
"add a \"{}\" format string to use the message literally",
@@ -259,3 +323,11 @@
if let hygiene::ExpnKind::Macro(_, symbol) = expn.kind { symbol } else { sym::panic };
(expn.call_site, panic_macro, macro_symbol.as_str())
}
+
+fn is_arg_inside_call(arg: Span, call: Span) -> bool {
+ // We only add suggestions if the argument we're looking at appears inside the
+ // panic call in the source file, to avoid invalid suggestions when macros are involved.
+ // We specifically check for the spans to not be identical, as that happens sometimes when
+ // proc_macros lie about spans and apply the same span to all the tokens they produce.
+ call.contains(arg) && !call.source_equal(&arg)
+}
diff --git a/compiler/rustc_lint/src/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs
index 7146dd5..0334497 100644
--- a/compiler/rustc_lint/src/nonstandard_style.rs
+++ b/compiler/rustc_lint/src/nonstandard_style.rs
@@ -118,7 +118,7 @@
})
.fold((String::new(), None), |(acc, prev): (String, Option<String>), next| {
// separate two components with an underscore if their boundary cannot
- // be distinguished using a uppercase/lowercase case distinction
+ // be distinguished using an uppercase/lowercase case distinction
let join = if let Some(prev) = prev {
let l = prev.chars().last().unwrap();
let f = next.chars().next().unwrap();
@@ -391,9 +391,14 @@
_: Span,
id: hir::HirId,
) {
+ let attrs = cx.tcx.hir().attrs(id);
match &fk {
- FnKind::Method(ident, ..) => match method_context(cx, id) {
+ FnKind::Method(ident, sig, ..) => match method_context(cx, id) {
MethodLateContext::PlainImpl => {
+ if sig.header.abi != Abi::Rust && cx.sess().contains_name(attrs, sym::no_mangle)
+ {
+ return;
+ }
self.check_snake_case(cx, "method", ident);
}
MethodLateContext::TraitAutoImpl => {
@@ -402,7 +407,6 @@
_ => (),
},
FnKind::ItemFn(ident, _, header, _) => {
- let attrs = cx.tcx.hir().attrs(id);
// Skip foreign-ABI #[no_mangle] functions (Issue #31924)
if header.abi != Abi::Rust && cx.sess().contains_name(attrs, sym::no_mangle) {
return;
diff --git a/compiler/rustc_lint/src/noop_method_call.rs b/compiler/rustc_lint/src/noop_method_call.rs
index 479cc00..c14f16b 100644
--- a/compiler/rustc_lint/src/noop_method_call.rs
+++ b/compiler/rustc_lint/src/noop_method_call.rs
@@ -62,7 +62,7 @@
_ => return,
};
let substs = cx.typeck_results().node_substs(expr.hir_id);
- if substs.needs_subst() {
+ if substs.definitely_needs_subst(cx.tcx) {
// We can't resolve on types that require monomorphization, so we don't handle them if
// we need to perfom substitution.
return;
diff --git a/compiler/rustc_lint/src/passes.rs b/compiler/rustc_lint/src/passes.rs
index bbe17dc..2d047ac 100644
--- a/compiler/rustc_lint/src/passes.rs
+++ b/compiler/rustc_lint/src/passes.rs
@@ -33,6 +33,7 @@
fn check_expr(a: &$hir hir::Expr<$hir>);
fn check_expr_post(a: &$hir hir::Expr<$hir>);
fn check_ty(a: &$hir hir::Ty<$hir>);
+ fn check_infer(a: &$hir hir::InferArg);
fn check_generic_arg(a: &$hir hir::GenericArg<$hir>);
fn check_generic_param(a: &$hir hir::GenericParam<$hir>);
fn check_generics(a: &$hir hir::Generics<$hir>);
diff --git a/compiler/rustc_lint/src/traits.rs b/compiler/rustc_lint/src/traits.rs
index e713ce7..edb158d 100644
--- a/compiler/rustc_lint/src/traits.rs
+++ b/compiler/rustc_lint/src/traits.rs
@@ -18,23 +18,27 @@
///
/// ### Explanation
///
- /// `Drop` bounds do not really accomplish anything. A type may have
- /// compiler-generated drop glue without implementing the `Drop` trait
- /// itself. The `Drop` trait also only has one method, `Drop::drop`, and
- /// that function is by fiat not callable in user code. So there is really
- /// no use case for using `Drop` in trait bounds.
+ /// A generic trait bound of the form `T: Drop` is most likely misleading
+ /// and not what the programmer intended (they probably should have used
+ /// `std::mem::needs_drop` instead).
///
- /// The most likely use case of a drop bound is to distinguish between
- /// types that have destructors and types that don't. Combined with
- /// specialization, a naive coder would write an implementation that
- /// assumed a type could be trivially dropped, then write a specialization
- /// for `T: Drop` that actually calls the destructor. Except that doing so
- /// is not correct; String, for example, doesn't actually implement Drop,
- /// but because String contains a Vec, assuming it can be trivially dropped
- /// will leak memory.
+ /// `Drop` bounds do not actually indicate whether a type can be trivially
+ /// dropped or not, because a composite type containing `Drop` types does
+ /// not necessarily implement `Drop` itself. Naïvely, one might be tempted
+ /// to write an implementation that assumes that a type can be trivially
+ /// dropped while also supplying a specialization for `T: Drop` that
+ /// actually calls the destructor. However, this breaks down e.g. when `T`
+ /// is `String`, which does not implement `Drop` itself but contains a
+ /// `Vec`, which does implement `Drop`, so assuming `T` can be trivially
+ /// dropped would lead to a memory leak here.
+ ///
+ /// Furthermore, the `Drop` trait only contains one method, `Drop::drop`,
+ /// which may not be called explicitly in user code (`E0040`), so there is
+ /// really no use case for using `Drop` in trait bounds, save perhaps for
+ /// some obscure corner cases, which can use `#[allow(drop_bounds)]`.
pub DROP_BOUNDS,
Warn,
- "bounds of the form `T: Drop` are useless"
+ "bounds of the form `T: Drop` are most likely incorrect"
}
declare_lint! {
@@ -87,7 +91,7 @@
let predicates = cx.tcx.explicit_predicates_of(item.def_id);
for &(predicate, span) in predicates.predicates {
let trait_predicate = match predicate.kind().skip_binder() {
- Trait(trait_predicate, _constness) => trait_predicate,
+ Trait(trait_predicate) => trait_predicate,
_ => continue,
};
let def_id = trait_predicate.trait_ref.def_id;
@@ -102,8 +106,8 @@
None => return,
};
let msg = format!(
- "bounds on `{}` are useless, consider instead \
- using `{}` to detect if a type has a destructor",
+ "bounds on `{}` are most likely incorrect, consider instead \
+ using `{}` to detect whether a type can be trivially dropped",
predicate,
cx.tcx.def_path_str(needs_drop)
);
diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs
index a3a87a4..5d25578 100644
--- a/compiler/rustc_lint/src/types.rs
+++ b/compiler/rustc_lint/src/types.rs
@@ -4,17 +4,19 @@
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::Applicability;
use rustc_hir as hir;
-use rustc_hir::{is_range_literal, ExprKind, Node};
+use rustc_hir::def_id::DefId;
+use rustc_hir::{is_range_literal, Expr, ExprKind, Node};
use rustc_middle::ty::layout::{IntegerExt, SizeSkeleton};
use rustc_middle::ty::subst::SubstsRef;
-use rustc_middle::ty::{self, AdtKind, Ty, TyCtxt, TypeFoldable};
+use rustc_middle::ty::{self, AdtKind, DefIdTree, Ty, TyCtxt, TypeFoldable};
use rustc_span::source_map;
use rustc_span::symbol::sym;
-use rustc_span::{Span, DUMMY_SP};
+use rustc_span::{Span, Symbol, DUMMY_SP};
use rustc_target::abi::Abi;
use rustc_target::abi::{Integer, LayoutOf, TagEncoding, Variants};
use rustc_target::spec::abi::Abi as SpecAbi;
+use if_chain::if_chain;
use std::cmp;
use std::iter;
use std::ops::ControlFlow;
@@ -667,9 +669,7 @@
}
crate fn nonnull_optimization_guaranteed<'tcx>(tcx: TyCtxt<'tcx>, def: &ty::AdtDef) -> bool {
- tcx.get_attrs(def.did)
- .iter()
- .any(|a| tcx.sess.check_name(a, sym::rustc_nonnull_optimization_guaranteed))
+ tcx.get_attrs(def.did).iter().any(|a| a.has_name(sym::rustc_nonnull_optimization_guaranteed))
}
/// `repr(transparent)` structs can have a single non-ZST field, this function returns that
@@ -795,7 +795,7 @@
// Return the nullable type this Option-like enum can be safely represented with.
let field_ty_abi = &cx.layout_of(field_ty).unwrap().abi;
if let Abi::Scalar(field_ty_scalar) = field_ty_abi {
- match (field_ty_scalar.valid_range.start(), field_ty_scalar.valid_range.end()) {
+ match (field_ty_scalar.valid_range.start, field_ty_scalar.valid_range.end) {
(0, _) => unreachable!("Non-null optimisation extended to a non-zero value."),
(1, _) => {
return Some(get_nullable_type(cx, field_ty).unwrap());
@@ -906,7 +906,7 @@
} else {
return FfiUnsafe {
ty,
- reason: format!("box cannot be represented as a single pointer"),
+ reason: "box cannot be represented as a single pointer".to_string(),
help: None,
};
}
@@ -1160,6 +1160,9 @@
impl<'a, 'tcx> ty::fold::TypeVisitor<'tcx> for ProhibitOpaqueTypes<'a, 'tcx> {
type BreakTy = Ty<'tcx>;
+ fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
+ Some(self.cx.tcx)
+ }
fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
match ty.kind() {
@@ -1169,7 +1172,7 @@
ty::Projection(..) => {
let ty = self.cx.tcx.normalize_erasing_regions(self.cx.param_env, ty);
- // If `ty` is a opaque type directly then `super_visit_with` won't invoke
+ // If `ty` is an opaque type directly then `super_visit_with` won't invoke
// this function again.
if ty.has_opaque_types() {
self.visit_ty(ty)
@@ -1379,3 +1382,236 @@
}
}
}
+
+declare_lint! {
+ /// The `invalid_atomic_ordering` lint detects passing an `Ordering`
+ /// to an atomic operation that does not support that ordering.
+ ///
+ /// ### Example
+ ///
+ /// ```rust,compile_fail
+ /// # use core::sync::atomic::{AtomicU8, Ordering};
+ /// let atom = AtomicU8::new(0);
+ /// let value = atom.load(Ordering::Release);
+ /// # let _ = value;
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// Some atomic operations are only supported for a subset of the
+ /// `atomic::Ordering` variants. Passing an unsupported variant will cause
+ /// an unconditional panic at runtime, which is detected by this lint.
+ ///
+ /// This lint will trigger in the following cases: (where `AtomicType` is an
+ /// atomic type from `core::sync::atomic`, such as `AtomicBool`,
+ /// `AtomicPtr`, `AtomicUsize`, or any of the other integer atomics).
+ ///
+ /// - Passing `Ordering::Acquire` or `Ordering::AcqRel` to
+ /// `AtomicType::store`.
+ ///
+ /// - Passing `Ordering::Release` or `Ordering::AcqRel` to
+ /// `AtomicType::load`.
+ ///
+ /// - Passing `Ordering::Relaxed` to `core::sync::atomic::fence` or
+ /// `core::sync::atomic::compiler_fence`.
+ ///
+ /// - Passing `Ordering::Release` or `Ordering::AcqRel` as the failure
+ /// ordering for any of `AtomicType::compare_exchange`,
+ /// `AtomicType::compare_exchange_weak`, or `AtomicType::fetch_update`.
+ ///
+ /// - Passing in a pair of orderings to `AtomicType::compare_exchange`,
+ /// `AtomicType::compare_exchange_weak`, or `AtomicType::fetch_update`
+ /// where the failure ordering is stronger than the success ordering.
+ INVALID_ATOMIC_ORDERING,
+ Deny,
+ "usage of invalid atomic ordering in atomic operations and memory fences"
+}
+
+declare_lint_pass!(InvalidAtomicOrdering => [INVALID_ATOMIC_ORDERING]);
+
+impl InvalidAtomicOrdering {
+ fn inherent_atomic_method_call<'hir>(
+ cx: &LateContext<'_>,
+ expr: &Expr<'hir>,
+ recognized_names: &[Symbol], // used for fast path calculation
+ ) -> Option<(Symbol, &'hir [Expr<'hir>])> {
+ const ATOMIC_TYPES: &[Symbol] = &[
+ sym::AtomicBool,
+ sym::AtomicPtr,
+ sym::AtomicUsize,
+ sym::AtomicU8,
+ sym::AtomicU16,
+ sym::AtomicU32,
+ sym::AtomicU64,
+ sym::AtomicU128,
+ sym::AtomicIsize,
+ sym::AtomicI8,
+ sym::AtomicI16,
+ sym::AtomicI32,
+ sym::AtomicI64,
+ sym::AtomicI128,
+ ];
+ if_chain! {
+ if let ExprKind::MethodCall(ref method_path, _, args, _) = &expr.kind;
+ if recognized_names.contains(&method_path.ident.name);
+ if let Some(m_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
+ if let Some(impl_did) = cx.tcx.impl_of_method(m_def_id);
+ if let Some(adt) = cx.tcx.type_of(impl_did).ty_adt_def();
+ // skip extension traits, only lint functions from the standard library
+ if cx.tcx.trait_id_of_impl(impl_did).is_none();
+
+ if let Some(parent) = cx.tcx.parent(adt.did);
+ if cx.tcx.is_diagnostic_item(sym::atomic_mod, parent);
+ if ATOMIC_TYPES.contains(&cx.tcx.item_name(adt.did));
+ then {
+ return Some((method_path.ident.name, args));
+ }
+ }
+ None
+ }
+
+ fn matches_ordering(cx: &LateContext<'_>, did: DefId, orderings: &[Symbol]) -> bool {
+ let tcx = cx.tcx;
+ let atomic_ordering = tcx.get_diagnostic_item(sym::Ordering);
+ orderings.iter().any(|ordering| {
+ tcx.item_name(did) == *ordering && {
+ let parent = tcx.parent(did);
+ parent == atomic_ordering
+ // needed in case this is a ctor, not a variant
+ || parent.map_or(false, |parent| tcx.parent(parent) == atomic_ordering)
+ }
+ })
+ }
+
+ fn opt_ordering_defid(cx: &LateContext<'_>, ord_arg: &Expr<'_>) -> Option<DefId> {
+ if let ExprKind::Path(ref ord_qpath) = ord_arg.kind {
+ cx.qpath_res(ord_qpath, ord_arg.hir_id).opt_def_id()
+ } else {
+ None
+ }
+ }
+
+ fn check_atomic_load_store(cx: &LateContext<'_>, expr: &Expr<'_>) {
+ use rustc_hir::def::{DefKind, Res};
+ use rustc_hir::QPath;
+ if_chain! {
+ if let Some((method, args)) = Self::inherent_atomic_method_call(cx, expr, &[sym::load, sym::store]);
+ if let Some((ordering_arg, invalid_ordering)) = match method {
+ sym::load => Some((&args[1], sym::Release)),
+ sym::store => Some((&args[2], sym::Acquire)),
+ _ => None,
+ };
+
+ if let ExprKind::Path(QPath::Resolved(_, path)) = ordering_arg.kind;
+ if let Res::Def(DefKind::Ctor(..), ctor_id) = path.res;
+ if Self::matches_ordering(cx, ctor_id, &[invalid_ordering, sym::AcqRel]);
+ then {
+ cx.struct_span_lint(INVALID_ATOMIC_ORDERING, ordering_arg.span, |diag| {
+ if method == sym::load {
+ diag.build("atomic loads cannot have `Release` or `AcqRel` ordering")
+ .help("consider using ordering modes `Acquire`, `SeqCst` or `Relaxed`")
+ .emit()
+ } else {
+ debug_assert_eq!(method, sym::store);
+ diag.build("atomic stores cannot have `Acquire` or `AcqRel` ordering")
+ .help("consider using ordering modes `Release`, `SeqCst` or `Relaxed`")
+ .emit();
+ }
+ });
+ }
+ }
+ }
+
+ fn check_memory_fence(cx: &LateContext<'_>, expr: &Expr<'_>) {
+ if_chain! {
+ if let ExprKind::Call(ref func, ref args) = expr.kind;
+ if let ExprKind::Path(ref func_qpath) = func.kind;
+ if let Some(def_id) = cx.qpath_res(func_qpath, func.hir_id).opt_def_id();
+ if cx.tcx.is_diagnostic_item(sym::fence, def_id) ||
+ cx.tcx.is_diagnostic_item(sym::compiler_fence, def_id);
+ if let ExprKind::Path(ref ordering_qpath) = &args[0].kind;
+ if let Some(ordering_def_id) = cx.qpath_res(ordering_qpath, args[0].hir_id).opt_def_id();
+ if Self::matches_ordering(cx, ordering_def_id, &[sym::Relaxed]);
+ then {
+ cx.struct_span_lint(INVALID_ATOMIC_ORDERING, args[0].span, |diag| {
+ diag.build("memory fences cannot have `Relaxed` ordering")
+ .help("consider using ordering modes `Acquire`, `Release`, `AcqRel` or `SeqCst`")
+ .emit();
+ });
+ }
+ }
+ }
+
+ fn check_atomic_compare_exchange(cx: &LateContext<'_>, expr: &Expr<'_>) {
+ if_chain! {
+ if let Some((method, args)) = Self::inherent_atomic_method_call(cx, expr, &[sym::fetch_update, sym::compare_exchange, sym::compare_exchange_weak]);
+ if let Some((success_order_arg, failure_order_arg)) = match method {
+ sym::fetch_update => Some((&args[1], &args[2])),
+ sym::compare_exchange | sym::compare_exchange_weak => Some((&args[3], &args[4])),
+ _ => None,
+ };
+
+ if let Some(fail_ordering_def_id) = Self::opt_ordering_defid(cx, failure_order_arg);
+ then {
+ // Helper type holding on to some checking and error reporting data. Has
+ // - (success ordering,
+ // - list of failure orderings forbidden by the success order,
+ // - suggestion message)
+ type OrdLintInfo = (Symbol, &'static [Symbol], &'static str);
+ const RELAXED: OrdLintInfo = (sym::Relaxed, &[sym::SeqCst, sym::Acquire], "ordering mode `Relaxed`");
+ const ACQUIRE: OrdLintInfo = (sym::Acquire, &[sym::SeqCst], "ordering modes `Acquire` or `Relaxed`");
+ const SEQ_CST: OrdLintInfo = (sym::SeqCst, &[], "ordering modes `Acquire`, `SeqCst` or `Relaxed`");
+ const RELEASE: OrdLintInfo = (sym::Release, RELAXED.1, RELAXED.2);
+ const ACQREL: OrdLintInfo = (sym::AcqRel, ACQUIRE.1, ACQUIRE.2);
+ const SEARCH: [OrdLintInfo; 5] = [RELAXED, ACQUIRE, SEQ_CST, RELEASE, ACQREL];
+
+ let success_lint_info = Self::opt_ordering_defid(cx, success_order_arg)
+ .and_then(|success_ord_def_id| -> Option<OrdLintInfo> {
+ SEARCH
+ .iter()
+ .copied()
+ .find(|(ordering, ..)| {
+ Self::matches_ordering(cx, success_ord_def_id, &[*ordering])
+ })
+ });
+ if Self::matches_ordering(cx, fail_ordering_def_id, &[sym::Release, sym::AcqRel]) {
+ // If we don't know the success order is, use what we'd suggest
+ // if it were maximally permissive.
+ let suggested = success_lint_info.unwrap_or(SEQ_CST).2;
+ cx.struct_span_lint(INVALID_ATOMIC_ORDERING, failure_order_arg.span, |diag| {
+ let msg = format!(
+ "{}'s failure ordering may not be `Release` or `AcqRel`",
+ method,
+ );
+ diag.build(&msg)
+ .help(&format!("consider using {} instead", suggested))
+ .emit();
+ });
+ } else if let Some((success_ord, bad_ords_given_success, suggested)) = success_lint_info {
+ if Self::matches_ordering(cx, fail_ordering_def_id, bad_ords_given_success) {
+ cx.struct_span_lint(INVALID_ATOMIC_ORDERING, failure_order_arg.span, |diag| {
+ let msg = format!(
+ "{}'s failure ordering may not be stronger than the success ordering of `{}`",
+ method,
+ success_ord,
+ );
+ diag.build(&msg)
+ .help(&format!("consider using {} instead", suggested))
+ .emit();
+ });
+ }
+ }
+ }
+ }
+ }
+}
+
+impl<'tcx> LateLintPass<'tcx> for InvalidAtomicOrdering {
+ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
+ Self::check_atomic_load_store(cx, expr);
+ Self::check_memory_fence(cx, expr);
+ Self::check_atomic_compare_exchange(cx, expr);
+ }
+}
diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs
index c431c04..f04ac8d 100644
--- a/compiler/rustc_lint/src/unused.rs
+++ b/compiler/rustc_lint/src/unused.rs
@@ -1,24 +1,19 @@
use crate::Lint;
use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext};
use rustc_ast as ast;
-use rustc_ast::util::parser;
+use rustc_ast::util::{classify, parser};
use rustc_ast::{ExprKind, StmtKind};
use rustc_ast_pretty::pprust;
-use rustc_data_structures::fx::FxHashMap;
use rustc_errors::{pluralize, Applicability};
-use rustc_feature::{AttributeType, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP};
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::DefId;
use rustc_middle::ty::adjustment;
use rustc_middle::ty::{self, Ty};
-use rustc_session::lint::builtin::UNUSED_ATTRIBUTES;
use rustc_span::symbol::Symbol;
use rustc_span::symbol::{kw, sym};
use rustc_span::{BytePos, Span, DUMMY_SP};
-use tracing::debug;
-
declare_lint! {
/// The `unused_must_use` lint detects unused result of a type flagged as
/// `#[must_use]`.
@@ -161,7 +156,15 @@
if let Some(must_use_op) = must_use_op {
cx.struct_span_lint(UNUSED_MUST_USE, expr.span, |lint| {
- lint.build(&format!("unused {} that must be used", must_use_op)).emit()
+ let mut lint = lint.build(&format!("unused {} that must be used", must_use_op));
+ lint.span_label(expr.span, &format!("the {} produces a value", must_use_op));
+ lint.span_suggestion_verbose(
+ expr.span.shrink_to_lo(),
+ "use `let _ = ...` to ignore the resulting value",
+ "let _ = ".to_string(),
+ Applicability::MachineApplicable,
+ );
+ lint.emit();
});
op_warned = true;
}
@@ -203,7 +206,7 @@
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::PredicateKind::Trait(ref poly_trait_predicate, _) =
+ if let ty::PredicateKind::Trait(ref poly_trait_predicate) =
predicate.kind().skip_binder()
{
let def_id = poly_trait_predicate.trait_ref.def_id;
@@ -300,7 +303,7 @@
descr_post_path: &str,
) -> bool {
for attr in cx.tcx.get_attrs(def_id).iter() {
- if cx.sess().check_name(attr, sym::must_use) {
+ if attr.has_name(sym::must_use) {
cx.struct_span_lint(UNUSED_MUST_USE, span, |lint| {
let msg = format!(
"unused {}`{}`{} that must be used",
@@ -374,67 +377,12 @@
}
}
-#[derive(Copy, Clone)]
-pub struct UnusedAttributes {
- builtin_attributes: &'static FxHashMap<Symbol, &'static BuiltinAttribute>,
-}
-
-impl UnusedAttributes {
- pub fn new() -> Self {
- UnusedAttributes { builtin_attributes: &*BUILTIN_ATTRIBUTE_MAP }
- }
-}
-
-impl_lint_pass!(UnusedAttributes => [UNUSED_ATTRIBUTES]);
-
-impl<'tcx> LateLintPass<'tcx> for UnusedAttributes {
- fn check_attribute(&mut self, cx: &LateContext<'_>, attr: &ast::Attribute) {
- debug!("checking attribute: {:?}", attr);
-
- if attr.is_doc_comment() {
- return;
- }
-
- let attr_info = attr.ident().and_then(|ident| self.builtin_attributes.get(&ident.name));
-
- if let Some(&&(name, ty, ..)) = attr_info {
- if let AttributeType::AssumedUsed = ty {
- debug!("{:?} is AssumedUsed", name);
- return;
- }
- }
-
- if !cx.sess().is_attr_used(attr) {
- debug!("emitting warning for: {:?}", attr);
- cx.struct_span_lint(UNUSED_ATTRIBUTES, attr.span, |lint| {
- // Mark as used to avoid duplicate warnings.
- cx.sess().mark_attr_used(attr);
- lint.build("unused attribute").emit()
- });
- // Is it a builtin attribute that must be used at the crate level?
- if attr_info.map_or(false, |(_, ty, ..)| ty == &AttributeType::CrateLevel) {
- cx.struct_span_lint(UNUSED_ATTRIBUTES, attr.span, |lint| {
- let msg = match attr.style {
- ast::AttrStyle::Outer => {
- "crate-level attribute should be an inner attribute: add an exclamation \
- mark: `#![foo]`"
- }
- ast::AttrStyle::Inner => "crate-level attribute should be in the root module",
- };
- lint.build(msg).emit()
- });
- }
- } else {
- debug!("Attr was used: {:?}", attr);
- }
- }
-}
-
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
enum UnusedDelimsCtx {
FunctionArg,
MethodArg,
AssignedValue,
+ AssignedValueLetElse,
IfCond,
WhileCond,
ForIterExpr,
@@ -451,7 +399,9 @@
match ctx {
UnusedDelimsCtx::FunctionArg => "function argument",
UnusedDelimsCtx::MethodArg => "method argument",
- UnusedDelimsCtx::AssignedValue => "assigned value",
+ UnusedDelimsCtx::AssignedValue | UnusedDelimsCtx::AssignedValueLetElse => {
+ "assigned value"
+ }
UnusedDelimsCtx::IfCond => "`if` condition",
UnusedDelimsCtx::WhileCond => "`while` condition",
UnusedDelimsCtx::ForIterExpr => "`for` iterator expression",
@@ -494,14 +444,26 @@
right_pos: Option<BytePos>,
);
- fn is_expr_delims_necessary(inner: &ast::Expr, followed_by_block: bool) -> bool {
+ fn is_expr_delims_necessary(
+ inner: &ast::Expr,
+ followed_by_block: bool,
+ followed_by_else: bool,
+ ) -> bool {
+ if followed_by_else {
+ match inner.kind {
+ ast::ExprKind::Binary(op, ..) if op.node.lazy() => return true,
+ _ if classify::expr_trailing_brace(inner).is_some() => return true,
+ _ => {}
+ }
+ }
+
// Prevent false-positives in cases like `fn x() -> u8 { ({ 0 } + 1) }`
let lhs_needs_parens = {
let mut innermost = inner;
loop {
if let ExprKind::Binary(_, lhs, _rhs) = &innermost.kind {
innermost = lhs;
- if !rustc_ast::util::classify::expr_requires_semi_to_be_stmt(innermost) {
+ if !classify::expr_requires_semi_to_be_stmt(innermost) {
break true;
}
} else {
@@ -606,7 +568,8 @@
let (value, ctx, followed_by_block, left_pos, right_pos) = match e.kind {
// Do not lint `unused_braces` in `if let` expressions.
If(ref cond, ref block, _)
- if !matches!(cond.kind, Let(_, _)) || Self::LINT_EXPR_IN_PATTERN_MATCHING_CTX =>
+ if !matches!(cond.kind, Let(_, _, _))
+ || Self::LINT_EXPR_IN_PATTERN_MATCHING_CTX =>
{
let left = e.span.lo() + rustc_span::BytePos(2);
let right = block.span.lo();
@@ -615,7 +578,8 @@
// Do not lint `unused_braces` in `while let` expressions.
While(ref cond, ref block, ..)
- if !matches!(cond.kind, Let(_, _)) || Self::LINT_EXPR_IN_PATTERN_MATCHING_CTX =>
+ if !matches!(cond.kind, Let(_, _, _))
+ || Self::LINT_EXPR_IN_PATTERN_MATCHING_CTX =>
{
let left = e.span.lo() + rustc_span::BytePos(5);
let right = block.span.lo();
@@ -669,15 +633,12 @@
fn check_stmt(&mut self, cx: &EarlyContext<'_>, s: &ast::Stmt) {
match s.kind {
StmtKind::Local(ref local) if Self::LINT_EXPR_IN_PATTERN_MATCHING_CTX => {
- if let Some(ref value) = local.init {
- self.check_unused_delims_expr(
- cx,
- &value,
- UnusedDelimsCtx::AssignedValue,
- false,
- None,
- None,
- );
+ if let Some((init, els)) = local.kind.init_else_opt() {
+ let ctx = match els {
+ None => UnusedDelimsCtx::AssignedValue,
+ Some(_) => UnusedDelimsCtx::AssignedValueLetElse,
+ };
+ self.check_unused_delims_expr(cx, init, ctx, false, None, None);
}
}
StmtKind::Expr(ref expr) => {
@@ -753,7 +714,8 @@
) {
match value.kind {
ast::ExprKind::Paren(ref inner) => {
- if !Self::is_expr_delims_necessary(inner, followed_by_block)
+ let followed_by_else = ctx == UnusedDelimsCtx::AssignedValueLetElse;
+ if !Self::is_expr_delims_necessary(inner, followed_by_block, followed_by_else)
&& value.attrs.is_empty()
&& !value.span.from_expansion()
&& (ctx != UnusedDelimsCtx::LetScrutineeExpr
@@ -766,7 +728,7 @@
self.emit_unused_delims_expr(cx, value, ctx, left_pos, right_pos)
}
}
- ast::ExprKind::Let(_, ref expr) => {
+ ast::ExprKind::Let(_, ref expr, _) => {
self.check_unused_delims_expr(
cx,
expr,
@@ -820,7 +782,7 @@
impl EarlyLintPass for UnusedParens {
fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) {
match e.kind {
- ExprKind::Let(ref pat, _) | ExprKind::ForLoop(ref pat, ..) => {
+ ExprKind::Let(ref pat, _, _) | ExprKind::ForLoop(ref pat, ..) => {
self.check_unused_parens_pat(cx, pat, false, false);
}
// We ignore parens in cases like `if (((let Some(0) = Some(1))))` because we already
@@ -992,7 +954,7 @@
// FIXME(const_generics): handle paths when #67075 is fixed.
if let [stmt] = inner.stmts.as_slice() {
if let ast::StmtKind::Expr(ref expr) = stmt.kind {
- if !Self::is_expr_delims_necessary(expr, followed_by_block)
+ if !Self::is_expr_delims_necessary(expr, followed_by_block, false)
&& (ctx != UnusedDelimsCtx::AnonConst
|| matches!(expr.kind, ast::ExprKind::Lit(_)))
&& !cx.sess().source_map().is_multiline(value.span)
@@ -1004,7 +966,7 @@
}
}
}
- ast::ExprKind::Let(_, ref expr) => {
+ ast::ExprKind::Let(_, ref expr, _) => {
self.check_unused_delims_expr(
cx,
expr,
diff --git a/compiler/rustc_lint_defs/Cargo.toml b/compiler/rustc_lint_defs/Cargo.toml
index 2928338..f9ada5c 100644
--- a/compiler/rustc_lint_defs/Cargo.toml
+++ b/compiler/rustc_lint_defs/Cargo.toml
@@ -1,5 +1,4 @@
[package]
-authors = ["The Rust Project Developers"]
name = "rustc_lint_defs"
version = "0.0.0"
edition = "2018"
diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs
index 1b416f3..8fb678e 100644
--- a/compiler/rustc_lint_defs/src/builtin.rs
+++ b/compiler/rustc_lint_defs/src/builtin.rs
@@ -1,5 +1,3 @@
-// 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
@@ -1607,7 +1605,7 @@
Warn,
"suggest using `dyn Trait` for trait objects",
@future_incompatible = FutureIncompatibleInfo {
- reference: "issue #80165 <https://github.com/rust-lang/rust/issues/80165>",
+ reference: "<https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>",
reason: FutureIncompatibilityReason::EditionError(Edition::Edition2021),
};
}
@@ -2692,6 +2690,38 @@
}
declare_lint! {
+ /// The `undefined_naked_function_abi` lint detects naked function definitions that
+ /// either do not specify an ABI or specify the Rust ABI.
+ ///
+ /// ### Example
+ ///
+ /// ```rust
+ /// #![feature(naked_functions)]
+ /// #![feature(asm)]
+ ///
+ /// #[naked]
+ /// pub fn default_abi() -> u32 {
+ /// unsafe { asm!("", options(noreturn)); }
+ /// }
+ ///
+ /// #[naked]
+ /// pub extern "Rust" fn rust_abi() -> u32 {
+ /// unsafe { asm!("", options(noreturn)); }
+ /// }
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// The Rust ABI is currently undefined. Therefore, naked functions should
+ /// specify a non-Rust ABI.
+ pub UNDEFINED_NAKED_FUNCTION_ABI,
+ Warn,
+ "undefined naked function ABI"
+}
+
+declare_lint! {
/// The `unsupported_naked_functions` lint detects naked function
/// definitions that are unsupported but were previously accepted.
///
@@ -2701,7 +2731,7 @@
/// #![feature(naked_functions)]
///
/// #[naked]
- /// pub fn f() -> u32 {
+ /// pub extern "C" fn f() -> u32 {
/// 42
/// }
/// ```
@@ -2720,6 +2750,9 @@
/// The asm block must not contain any operands other than `const` and
/// `sym`. Additionally, naked function should specify a non-Rust ABI.
///
+ /// Naked functions cannot be inlined. All forms of the `inline` attribute
+ /// are prohibited.
+ ///
/// While other definitions of naked functions were previously accepted,
/// they are unsupported and might not work reliably. This is a
/// [future-incompatible] lint that will transition into hard error in
@@ -2799,7 +2832,7 @@
/// [issue #79813]: https://github.com/rust-lang/rust/issues/79813
/// [future-incompatible]: ../index.md#future-incompatible-lints
pub SEMICOLON_IN_EXPRESSIONS_FROM_MACROS,
- Allow,
+ Warn,
"trailing semicolon in macro body used as expression",
@future_incompatible = FutureIncompatibleInfo {
reference: "issue #79813 <https://github.com/rust-lang/rust/issues/79813>",
@@ -2975,6 +3008,8 @@
RUST_2021_PRELUDE_COLLISIONS,
RUST_2021_PREFIXES_INCOMPATIBLE_SYNTAX,
UNSUPPORTED_CALLING_CONVENTIONS,
+ BREAK_WITH_LABEL_AND_LOOP,
+ UNUSED_ATTRIBUTES,
]
}
@@ -3003,16 +3038,19 @@
declare_lint! {
/// The `rust_2021_incompatible_closure_captures` lint detects variables that aren't completely
- /// captured in Rust 2021 and affect the Drop order of at least one path starting at this variable.
- /// It can also detect when a variable implements a trait, but one of its field does not and
- /// the field is captured by a closure and used with the assumption that said field implements
+ /// captured in Rust 2021, such that the `Drop` order of their fields may differ between
+ /// Rust 2018 and 2021.
+ ///
+ /// It can also detect when a variable implements a trait like `Send`, but one of its fields does not,
+ /// and the field is captured by a closure and used with the assumption that said field implements
/// the same trait as the root variable.
///
/// ### Example of drop reorder
///
/// ```rust,compile_fail
- /// # #![deny(rust_2021_incompatible_closure_captures)]
+ /// #![deny(rust_2021_incompatible_closure_captures)]
/// # #![allow(unused)]
+ ///
/// struct FancyInteger(i32);
///
/// impl Drop for FancyInteger {
@@ -3066,8 +3104,8 @@
/// ### Explanation
///
/// In the above example, only `fptr.0` is captured in Rust 2021.
- /// The field is of type *mut i32 which doesn't implement Send, making the code invalid as the
- /// field cannot be sent between thread safely.
+ /// The field is of type `*mut i32`, which doesn't implement `Send`,
+ /// making the code invalid as the field cannot be sent between threads safely.
pub RUST_2021_INCOMPATIBLE_CLOSURE_CAPTURES,
Allow,
"detects closures affected by Rust 2021 changes",
@@ -3187,6 +3225,7 @@
///
/// ```rust,compile_fail
/// #![deny(rust_2021_incompatible_or_patterns)]
+ ///
/// macro_rules! match_any {
/// ( $expr:expr , $( $( $pat:pat )|+ => $expr_arm:expr ),+ ) => {
/// match $expr {
@@ -3208,12 +3247,12 @@
///
/// ### Explanation
///
- /// In Rust 2021, the pat matcher will match new patterns, which include the | character.
+ /// In Rust 2021, the `pat` matcher will match additional patterns, which include the `|` character.
pub RUST_2021_INCOMPATIBLE_OR_PATTERNS,
Allow,
"detects usage of old versions of or-patterns",
@future_incompatible = FutureIncompatibleInfo {
- reference: "issue #84869 <https://github.com/rust-lang/rust/issues/84869>",
+ reference: "<https://doc.rust-lang.org/nightly/edition-guide/rust-2021/or-patterns-macro-rules.html>",
reason: FutureIncompatibilityReason::EditionError(Edition::Edition2021),
};
}
@@ -3253,8 +3292,8 @@
/// In Rust 2021, one of the important introductions is the [prelude changes], which add
/// `TryFrom`, `TryInto`, and `FromIterator` into the standard library's prelude. Since this
/// results in an ambiguity as to which method/function to call when an existing `try_into`
- /// method is called via dot-call syntax or a `try_from`/`from_iter` associated function
- /// is called directly on a type.
+ /// method is called via dot-call syntax or a `try_from`/`from_iter` associated function
+ /// is called directly on a type.
///
/// [prelude changes]: https://blog.rust-lang.org/inside-rust/2021/03/04/planning-rust-2021.html#prelude-changes
pub RUST_2021_PRELUDE_COLLISIONS,
@@ -3262,7 +3301,7 @@
"detects the usage of trait methods which are ambiguous with traits added to the \
prelude in future editions",
@future_incompatible = FutureIncompatibleInfo {
- reference: "issue #85684 <https://github.com/rust-lang/rust/issues/85684>",
+ reference: "<https://doc.rust-lang.org/nightly/edition-guide/rust-2021/prelude.html>",
reason: FutureIncompatibilityReason::EditionError(Edition::Edition2021),
};
}
@@ -3297,14 +3336,14 @@
Allow,
"identifiers that will be parsed as a prefix in Rust 2021",
@future_incompatible = FutureIncompatibleInfo {
- reference: "issue #84978 <https://github.com/rust-lang/rust/issues/84978>",
+ reference: "<https://doc.rust-lang.org/nightly/edition-guide/rust-2021/reserving-syntax.html>",
reason: FutureIncompatibilityReason::EditionError(Edition::Edition2021),
};
crate_level_only
}
declare_lint! {
- /// The `unsupported_calling_conventions` lint is output whenever there is an use of the
+ /// The `unsupported_calling_conventions` lint is output whenever there is a use of the
/// `stdcall`, `fastcall`, `thiscall`, `vectorcall` calling conventions (or their unwind
/// variants) on targets that cannot meaningfully be supported for the requested target.
///
@@ -3348,3 +3387,32 @@
reference: "issue #87678 <https://github.com/rust-lang/rust/issues/87678>",
};
}
+
+declare_lint! {
+ /// The `break_with_label_and_loop` lint detects labeled `break` expressions with
+ /// an unlabeled loop as their value expression.
+ ///
+ /// ### Example
+ ///
+ /// ```rust
+ /// 'label: loop {
+ /// break 'label loop { break 42; };
+ /// };
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// In Rust, loops can have a label, and `break` expressions can refer to that label to
+ /// break out of specific loops (and not necessarily the innermost one). `break` expressions
+ /// can also carry a value expression, which can be another loop. A labeled `break` with an
+ /// unlabeled loop as its value expression is easy to confuse with an unlabeled break with
+ /// a labeled loop and is thus discouraged (but allowed for compatibility); use parentheses
+ /// around the loop expression to silence this warning. Unlabeled `break` expressions with
+ /// labeled loops yield a hard error, which can also be silenced by wrapping the expression
+ /// in parentheses.
+ pub BREAK_WITH_LABEL_AND_LOOP,
+ Warn,
+ "`break` expression with label and unlabeled loop as value expression"
+}
diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs
index 4190e76..f89d531 100644
--- a/compiler/rustc_lint_defs/src/lib.rs
+++ b/compiler/rustc_lint_defs/src/lib.rs
@@ -296,12 +296,16 @@
DeprecatedMacro(Option<Symbol>, Span),
MissingAbi(Span, Abi),
UnusedDocComment(Span),
+ UnusedBuiltinAttribute { attr_name: Symbol, macro_name: String, invoc_span: Span },
PatternsInFnsWithoutBody(Span, Ident),
LegacyDeriveHelpers(Span),
ExternDepSpec(String, ExternDepSpec),
ProcMacroBackCompat(String),
OrPatternsBackCompat(Span, String),
ReservedPrefix(Span),
+ TrailingMacro(bool, Ident),
+ BreakWithLabelAndLoop(Span),
+ NamedAsmLabel(String),
}
/// Lints that are buffered up early on in the `Session` before the
diff --git a/compiler/rustc_llvm/Cargo.toml b/compiler/rustc_llvm/Cargo.toml
index 1bfa489..2f0f3dd 100644
--- a/compiler/rustc_llvm/Cargo.toml
+++ b/compiler/rustc_llvm/Cargo.toml
@@ -1,5 +1,4 @@
[package]
-authors = ["The Rust Project Developers"]
name = "rustc_llvm"
version = "0.0.0"
edition = "2018"
diff --git a/compiler/rustc_llvm/build.rs b/compiler/rustc_llvm/build.rs
index 452d1b19a..964b7ca 100644
--- a/compiler/rustc_llvm/build.rs
+++ b/compiler/rustc_llvm/build.rs
@@ -182,7 +182,7 @@
} else if target.contains("windows-gnu") {
println!("cargo:rustc-link-lib=shell32");
println!("cargo:rustc-link-lib=uuid");
- } else if target.contains("netbsd") || target.contains("haiku") {
+ } else if target.contains("netbsd") || target.contains("haiku") || target.contains("darwin") {
println!("cargo:rustc-link-lib=z");
}
cmd.args(&components);
diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
index 3595e37..b3f86f3 100644
--- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
@@ -331,20 +331,24 @@
Oz,
};
-static PassBuilder::OptimizationLevel fromRust(LLVMRustPassBuilderOptLevel Level) {
+#if LLVM_VERSION_LT(14,0)
+using OptimizationLevel = PassBuilder::OptimizationLevel;
+#endif
+
+static OptimizationLevel fromRust(LLVMRustPassBuilderOptLevel Level) {
switch (Level) {
case LLVMRustPassBuilderOptLevel::O0:
- return PassBuilder::OptimizationLevel::O0;
+ return OptimizationLevel::O0;
case LLVMRustPassBuilderOptLevel::O1:
- return PassBuilder::OptimizationLevel::O1;
+ return OptimizationLevel::O1;
case LLVMRustPassBuilderOptLevel::O2:
- return PassBuilder::OptimizationLevel::O2;
+ return OptimizationLevel::O2;
case LLVMRustPassBuilderOptLevel::O3:
- return PassBuilder::OptimizationLevel::O3;
+ return OptimizationLevel::O3;
case LLVMRustPassBuilderOptLevel::Os:
- return PassBuilder::OptimizationLevel::Os;
+ return OptimizationLevel::Os;
case LLVMRustPassBuilderOptLevel::Oz:
- return PassBuilder::OptimizationLevel::Oz;
+ return OptimizationLevel::Oz;
default:
report_fatal_error("Bad PassBuilderOptLevel.");
}
@@ -754,7 +758,7 @@
const char *ExtraPasses, size_t ExtraPassesLen) {
Module *TheModule = unwrap(ModuleRef);
TargetMachine *TM = unwrap(TMRef);
- PassBuilder::OptimizationLevel OptLevel = fromRust(OptLevelRust);
+ OptimizationLevel OptLevel = fromRust(OptLevelRust);
PipelineTuningOptions PTO;
@@ -827,19 +831,19 @@
// We manually collect pipeline callbacks so we can apply them at O0, where the
// PassBuilder does not create a pipeline.
- std::vector<std::function<void(ModulePassManager &, PassBuilder::OptimizationLevel)>>
+ std::vector<std::function<void(ModulePassManager &, OptimizationLevel)>>
PipelineStartEPCallbacks;
#if LLVM_VERSION_GE(11, 0)
- std::vector<std::function<void(ModulePassManager &, PassBuilder::OptimizationLevel)>>
+ std::vector<std::function<void(ModulePassManager &, OptimizationLevel)>>
OptimizerLastEPCallbacks;
#else
- std::vector<std::function<void(FunctionPassManager &, PassBuilder::OptimizationLevel)>>
+ std::vector<std::function<void(FunctionPassManager &, OptimizationLevel)>>
OptimizerLastEPCallbacks;
#endif
if (VerifyIR) {
PipelineStartEPCallbacks.push_back(
- [VerifyIR](ModulePassManager &MPM, PassBuilder::OptimizationLevel Level) {
+ [VerifyIR](ModulePassManager &MPM, OptimizationLevel Level) {
MPM.addPass(VerifierPass());
}
);
@@ -847,7 +851,7 @@
if (InstrumentGCOV) {
PipelineStartEPCallbacks.push_back(
- [](ModulePassManager &MPM, PassBuilder::OptimizationLevel Level) {
+ [](ModulePassManager &MPM, OptimizationLevel Level) {
MPM.addPass(GCOVProfilerPass(GCOVOptions::getDefault()));
}
);
@@ -855,7 +859,7 @@
if (InstrumentCoverage) {
PipelineStartEPCallbacks.push_back(
- [](ModulePassManager &MPM, PassBuilder::OptimizationLevel Level) {
+ [](ModulePassManager &MPM, OptimizationLevel Level) {
InstrProfOptions Options;
MPM.addPass(InstrProfiling(Options, false));
}
@@ -870,19 +874,19 @@
/*CompileKernel=*/false);
#if LLVM_VERSION_GE(11, 0)
OptimizerLastEPCallbacks.push_back(
- [Options](ModulePassManager &MPM, PassBuilder::OptimizationLevel Level) {
+ [Options](ModulePassManager &MPM, OptimizationLevel Level) {
MPM.addPass(MemorySanitizerPass(Options));
MPM.addPass(createModuleToFunctionPassAdaptor(MemorySanitizerPass(Options)));
}
);
#else
PipelineStartEPCallbacks.push_back(
- [Options](ModulePassManager &MPM, PassBuilder::OptimizationLevel Level) {
+ [Options](ModulePassManager &MPM, OptimizationLevel Level) {
MPM.addPass(MemorySanitizerPass(Options));
}
);
OptimizerLastEPCallbacks.push_back(
- [Options](FunctionPassManager &FPM, PassBuilder::OptimizationLevel Level) {
+ [Options](FunctionPassManager &FPM, OptimizationLevel Level) {
FPM.addPass(MemorySanitizerPass(Options));
}
);
@@ -892,19 +896,19 @@
if (SanitizerOptions->SanitizeThread) {
#if LLVM_VERSION_GE(11, 0)
OptimizerLastEPCallbacks.push_back(
- [](ModulePassManager &MPM, PassBuilder::OptimizationLevel Level) {
+ [](ModulePassManager &MPM, OptimizationLevel Level) {
MPM.addPass(ThreadSanitizerPass());
MPM.addPass(createModuleToFunctionPassAdaptor(ThreadSanitizerPass()));
}
);
#else
PipelineStartEPCallbacks.push_back(
- [](ModulePassManager &MPM, PassBuilder::OptimizationLevel Level) {
+ [](ModulePassManager &MPM, OptimizationLevel Level) {
MPM.addPass(ThreadSanitizerPass());
}
);
OptimizerLastEPCallbacks.push_back(
- [](FunctionPassManager &FPM, PassBuilder::OptimizationLevel Level) {
+ [](FunctionPassManager &FPM, OptimizationLevel Level) {
FPM.addPass(ThreadSanitizerPass());
}
);
@@ -914,30 +918,38 @@
if (SanitizerOptions->SanitizeAddress) {
#if LLVM_VERSION_GE(11, 0)
OptimizerLastEPCallbacks.push_back(
- [SanitizerOptions](ModulePassManager &MPM, PassBuilder::OptimizationLevel Level) {
+ [SanitizerOptions](ModulePassManager &MPM, OptimizationLevel Level) {
MPM.addPass(RequireAnalysisPass<ASanGlobalsMetadataAnalysis, Module>());
MPM.addPass(ModuleAddressSanitizerPass(
/*CompileKernel=*/false, SanitizerOptions->SanitizeAddressRecover));
+#if LLVM_VERSION_GE(14, 0)
+ AddressSanitizerOptions opts(/*CompileKernel=*/false,
+ SanitizerOptions->SanitizeAddressRecover,
+ /*UseAfterScope=*/true,
+ AsanDetectStackUseAfterReturnMode::Runtime);
+ MPM.addPass(createModuleToFunctionPassAdaptor(AddressSanitizerPass(opts)));
+#else
MPM.addPass(createModuleToFunctionPassAdaptor(AddressSanitizerPass(
/*CompileKernel=*/false, SanitizerOptions->SanitizeAddressRecover,
/*UseAfterScope=*/true)));
+#endif
}
);
#else
PipelineStartEPCallbacks.push_back(
- [&](ModulePassManager &MPM, PassBuilder::OptimizationLevel Level) {
+ [&](ModulePassManager &MPM, OptimizationLevel Level) {
MPM.addPass(RequireAnalysisPass<ASanGlobalsMetadataAnalysis, Module>());
}
);
OptimizerLastEPCallbacks.push_back(
- [SanitizerOptions](FunctionPassManager &FPM, PassBuilder::OptimizationLevel Level) {
+ [SanitizerOptions](FunctionPassManager &FPM, OptimizationLevel Level) {
FPM.addPass(AddressSanitizerPass(
/*CompileKernel=*/false, SanitizerOptions->SanitizeAddressRecover,
/*UseAfterScope=*/true));
}
);
PipelineStartEPCallbacks.push_back(
- [SanitizerOptions](ModulePassManager &MPM, PassBuilder::OptimizationLevel Level) {
+ [SanitizerOptions](ModulePassManager &MPM, OptimizationLevel Level) {
MPM.addPass(ModuleAddressSanitizerPass(
/*CompileKernel=*/false, SanitizerOptions->SanitizeAddressRecover));
}
@@ -947,14 +959,21 @@
if (SanitizerOptions->SanitizeHWAddress) {
#if LLVM_VERSION_GE(11, 0)
OptimizerLastEPCallbacks.push_back(
- [SanitizerOptions](ModulePassManager &MPM, PassBuilder::OptimizationLevel Level) {
+ [SanitizerOptions](ModulePassManager &MPM, OptimizationLevel Level) {
+#if LLVM_VERSION_GE(14, 0)
+ HWAddressSanitizerOptions opts(
+ /*CompileKernel=*/false, SanitizerOptions->SanitizeHWAddressRecover,
+ /*DisableOptimization=*/false);
+ MPM.addPass(HWAddressSanitizerPass(opts));
+#else
MPM.addPass(HWAddressSanitizerPass(
/*CompileKernel=*/false, SanitizerOptions->SanitizeHWAddressRecover));
+#endif
}
);
#else
PipelineStartEPCallbacks.push_back(
- [SanitizerOptions](ModulePassManager &MPM, PassBuilder::OptimizationLevel Level) {
+ [SanitizerOptions](ModulePassManager &MPM, OptimizationLevel Level) {
MPM.addPass(HWAddressSanitizerPass(
/*CompileKernel=*/false, SanitizerOptions->SanitizeHWAddressRecover));
}
@@ -970,7 +989,7 @@
#endif
bool NeedThinLTOBufferPasses = UseThinLTOBuffers;
if (!NoPrepopulatePasses) {
- if (OptLevel == PassBuilder::OptimizationLevel::O0) {
+ if (OptLevel == OptimizationLevel::O0) {
#if LLVM_VERSION_GE(12, 0)
for (const auto &C : PipelineStartEPCallbacks)
PB.registerPipelineStartEPCallback(C);
diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
index 4cdc8a4..4f07a0c 100644
--- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
@@ -270,34 +270,30 @@
LLVMRustAttribute RustAttr) {
Function *A = unwrap<Function>(Fn);
Attribute Attr = Attribute::get(A->getContext(), fromRust(RustAttr));
- AttrBuilder B(Attr);
- A->addAttributes(Index, B);
+ A->addAttribute(Index, Attr);
}
extern "C" void LLVMRustAddAlignmentAttr(LLVMValueRef Fn,
unsigned Index,
uint32_t Bytes) {
Function *A = unwrap<Function>(Fn);
- AttrBuilder B;
- B.addAlignmentAttr(Bytes);
- A->addAttributes(Index, B);
+ A->addAttribute(Index, Attribute::getWithAlignment(
+ A->getContext(), llvm::Align(Bytes)));
}
extern "C" void LLVMRustAddDereferenceableAttr(LLVMValueRef Fn, unsigned Index,
uint64_t Bytes) {
Function *A = unwrap<Function>(Fn);
- AttrBuilder B;
- B.addDereferenceableAttr(Bytes);
- A->addAttributes(Index, B);
+ A->addAttribute(Index, Attribute::getWithDereferenceableBytes(A->getContext(),
+ Bytes));
}
extern "C" void LLVMRustAddDereferenceableOrNullAttr(LLVMValueRef Fn,
unsigned Index,
uint64_t Bytes) {
Function *A = unwrap<Function>(Fn);
- AttrBuilder B;
- B.addDereferenceableOrNullAttr(Bytes);
- A->addAttributes(Index, B);
+ A->addAttribute(Index, Attribute::getWithDereferenceableOrNullBytes(
+ A->getContext(), Bytes));
}
extern "C" void LLVMRustAddByValAttr(LLVMValueRef Fn, unsigned Index,
@@ -323,9 +319,8 @@
const char *Name,
const char *Value) {
Function *F = unwrap<Function>(Fn);
- AttrBuilder B;
- B.addAttribute(Name, Value);
- F->addAttributes(Index, B);
+ F->addAttribute(Index, Attribute::get(
+ F->getContext(), StringRef(Name), StringRef(Value)));
}
extern "C" void LLVMRustRemoveFunctionAttributes(LLVMValueRef Fn,
@@ -1114,15 +1109,13 @@
LLVMRustUnpackInlineAsmDiagnostic(LLVMDiagnosticInfoRef DI,
LLVMRustDiagnosticLevel *LevelOut,
unsigned *CookieOut,
- LLVMTwineRef *MessageOut,
- LLVMValueRef *InstructionOut) {
+ LLVMTwineRef *MessageOut) {
// Undefined to call this not on an inline assembly diagnostic!
llvm::DiagnosticInfoInlineAsm *IA =
static_cast<llvm::DiagnosticInfoInlineAsm *>(unwrap(DI));
*CookieOut = IA->getLocCookie();
*MessageOut = wrap(&IA->getMsgStr());
- *InstructionOut = wrap(IA->getInstruction());
switch (IA->getSeverity()) {
case DS_Error:
@@ -1165,6 +1158,7 @@
PGOProfile,
Linker,
Unsupported,
+ SrcMgr,
};
static LLVMRustDiagnosticKind toRust(DiagnosticKind Kind) {
@@ -1193,6 +1187,10 @@
return LLVMRustDiagnosticKind::Linker;
case DK_Unsupported:
return LLVMRustDiagnosticKind::Unsupported;
+#if LLVM_VERSION_GE(13, 0)
+ case DK_SrcMgr:
+ return LLVMRustDiagnosticKind::SrcMgr;
+#endif
default:
return (Kind >= DK_FirstRemark && Kind <= DK_LastRemark)
? LLVMRustDiagnosticKind::OptimizationRemarkOther
@@ -1280,6 +1278,17 @@
#endif
}
+extern "C" LLVMSMDiagnosticRef LLVMRustGetSMDiagnostic(
+ LLVMDiagnosticInfoRef DI, unsigned *Cookie) {
+#if LLVM_VERSION_GE(13, 0)
+ llvm::DiagnosticInfoSrcMgr *SM = static_cast<llvm::DiagnosticInfoSrcMgr *>(unwrap(DI));
+ *Cookie = SM->getLocCookie();
+ return wrap(&SM->getSMDiag());
+#else
+ report_fatal_error("Shouldn't get called on older versions");
+#endif
+}
+
extern "C" bool LLVMRustUnpackSMDiagnostic(LLVMSMDiagnosticRef DRef,
RustStringRef MessageOut,
RustStringRef BufferOut,
@@ -1392,11 +1401,11 @@
delete Bundle;
}
-extern "C" LLVMValueRef LLVMRustBuildCall(LLVMBuilderRef B, LLVMValueRef Fn,
+extern "C" LLVMValueRef LLVMRustBuildCall(LLVMBuilderRef B, LLVMTypeRef Ty, LLVMValueRef Fn,
LLVMValueRef *Args, unsigned NumArgs,
OperandBundleDef *Bundle) {
Value *Callee = unwrap(Fn);
- FunctionType *FTy = cast<FunctionType>(Callee->getType()->getPointerElementType());
+ FunctionType *FTy = unwrap<FunctionType>(Ty);
unsigned Len = Bundle ? 1 : 0;
ArrayRef<OperandBundleDef> Bundles = makeArrayRef(Bundle, Len);
return wrap(unwrap(B)->CreateCall(
@@ -1437,12 +1446,12 @@
}
extern "C" LLVMValueRef
-LLVMRustBuildInvoke(LLVMBuilderRef B, LLVMValueRef Fn, LLVMValueRef *Args,
- unsigned NumArgs, LLVMBasicBlockRef Then,
- LLVMBasicBlockRef Catch, OperandBundleDef *Bundle,
- const char *Name) {
+LLVMRustBuildInvoke(LLVMBuilderRef B, LLVMTypeRef Ty, LLVMValueRef Fn,
+ LLVMValueRef *Args, unsigned NumArgs,
+ LLVMBasicBlockRef Then, LLVMBasicBlockRef Catch,
+ OperandBundleDef *Bundle, const char *Name) {
Value *Callee = unwrap(Fn);
- FunctionType *FTy = cast<FunctionType>(Callee->getType()->getPointerElementType());
+ FunctionType *FTy = unwrap<FunctionType>(Ty);
unsigned Len = Bundle ? 1 : 0;
ArrayRef<OperandBundleDef> Bundles = makeArrayRef(Bundle, Len);
return wrap(unwrap(B)->CreateInvoke(FTy, Callee, unwrap(Then), unwrap(Catch),
@@ -1551,6 +1560,16 @@
LLVMSetLinkage(V, fromRust(RustLinkage));
}
+extern "C" LLVMValueRef LLVMRustConstInBoundsGEP2(LLVMTypeRef Ty,
+ LLVMValueRef ConstantVal,
+ LLVMValueRef *ConstantIndices,
+ unsigned NumIndices) {
+ ArrayRef<Constant *> IdxList(unwrap<Constant>(ConstantIndices, NumIndices),
+ NumIndices);
+ Constant *Val = unwrap<Constant>(ConstantVal);
+ return wrap(ConstantExpr::getInBoundsGetElementPtr(unwrap(Ty), Val, IdxList));
+}
+
// Returns true if both high and low were successfully set. Fails in case constant wasn’t any of
// the common sizes (1, 8, 16, 32, 64, 128 bits)
extern "C" bool LLVMRustConstInt128Get(LLVMValueRef CV, bool sext, uint64_t *high, uint64_t *low)
diff --git a/compiler/rustc_macros/Cargo.toml b/compiler/rustc_macros/Cargo.toml
index 73eb0dd..e4dddba 100644
--- a/compiler/rustc_macros/Cargo.toml
+++ b/compiler/rustc_macros/Cargo.toml
@@ -1,7 +1,6 @@
[package]
name = "rustc_macros"
version = "0.1.0"
-authors = ["The Rust Project Developers"]
edition = "2018"
[lib]
diff --git a/compiler/rustc_macros/src/query.rs b/compiler/rustc_macros/src/query.rs
index dcd36d6..7ad3697 100644
--- a/compiler/rustc_macros/src/query.rs
+++ b/compiler/rustc_macros/src/query.rs
@@ -1,6 +1,6 @@
use proc_macro::TokenStream;
use proc_macro2::{Delimiter, TokenTree};
-use quote::quote;
+use quote::{quote, quote_spanned};
use syn::parse::{Parse, ParseStream, Result};
use syn::punctuated::Punctuated;
use syn::spanned::Spanned;
@@ -42,19 +42,19 @@
LoadCached(Ident, Ident, Block),
/// A cycle error for this query aborting the compilation with a fatal error.
- FatalCycle,
+ FatalCycle(Ident),
/// A cycle error results in a delay_bug call
- CycleDelayBug,
+ CycleDelayBug(Ident),
/// Don't hash the result, instead just mark a query red if it runs
- NoHash,
+ NoHash(Ident),
/// Generate a dep node based on the dependencies of the query
- Anon,
+ Anon(Ident),
/// Always evaluate the query, ignoring its dependencies
- EvalAlways,
+ EvalAlways(Ident),
}
impl Parse for QueryModifier {
@@ -111,15 +111,15 @@
let ty = args.parse()?;
Ok(QueryModifier::Storage(ty))
} else if modifier == "fatal_cycle" {
- Ok(QueryModifier::FatalCycle)
+ Ok(QueryModifier::FatalCycle(modifier))
} else if modifier == "cycle_delay_bug" {
- Ok(QueryModifier::CycleDelayBug)
+ Ok(QueryModifier::CycleDelayBug(modifier))
} else if modifier == "no_hash" {
- Ok(QueryModifier::NoHash)
+ Ok(QueryModifier::NoHash(modifier))
} else if modifier == "anon" {
- Ok(QueryModifier::Anon)
+ Ok(QueryModifier::Anon(modifier))
} else if modifier == "eval_always" {
- Ok(QueryModifier::EvalAlways)
+ Ok(QueryModifier::EvalAlways(modifier))
} else {
Err(Error::new(modifier.span(), "unknown query modifier"))
}
@@ -203,19 +203,19 @@
load_cached: Option<(Ident, Ident, Block)>,
/// A cycle error for this query aborting the compilation with a fatal error.
- fatal_cycle: bool,
+ fatal_cycle: Option<Ident>,
/// A cycle error results in a delay_bug call
- cycle_delay_bug: bool,
+ cycle_delay_bug: Option<Ident>,
/// Don't hash the result, instead just mark a query red if it runs
- no_hash: bool,
+ no_hash: Option<Ident>,
/// Generate a dep node based on the dependencies of the query
- anon: bool,
+ anon: Option<Ident>,
// Always evaluate the query, ignoring its dependencies
- eval_always: bool,
+ eval_always: Option<Ident>,
}
/// Process query modifiers into a struct, erroring on duplicates
@@ -224,11 +224,11 @@
let mut storage = None;
let mut cache = None;
let mut desc = None;
- let mut fatal_cycle = false;
- let mut cycle_delay_bug = false;
- let mut no_hash = false;
- let mut anon = false;
- let mut eval_always = false;
+ let mut fatal_cycle = None;
+ let mut cycle_delay_bug = None;
+ let mut no_hash = None;
+ let mut anon = None;
+ let mut eval_always = None;
for modifier in query.modifiers.0.drain(..) {
match modifier {
QueryModifier::LoadCached(tcx, id, block) => {
@@ -289,35 +289,35 @@
}
desc = Some((tcx, list));
}
- QueryModifier::FatalCycle => {
- if fatal_cycle {
+ QueryModifier::FatalCycle(ident) => {
+ if fatal_cycle.is_some() {
panic!("duplicate modifier `fatal_cycle` for query `{}`", query.name);
}
- fatal_cycle = true;
+ fatal_cycle = Some(ident);
}
- QueryModifier::CycleDelayBug => {
- if cycle_delay_bug {
+ QueryModifier::CycleDelayBug(ident) => {
+ if cycle_delay_bug.is_some() {
panic!("duplicate modifier `cycle_delay_bug` for query `{}`", query.name);
}
- cycle_delay_bug = true;
+ cycle_delay_bug = Some(ident);
}
- QueryModifier::NoHash => {
- if no_hash {
+ QueryModifier::NoHash(ident) => {
+ if no_hash.is_some() {
panic!("duplicate modifier `no_hash` for query `{}`", query.name);
}
- no_hash = true;
+ no_hash = Some(ident);
}
- QueryModifier::Anon => {
- if anon {
+ QueryModifier::Anon(ident) => {
+ if anon.is_some() {
panic!("duplicate modifier `anon` for query `{}`", query.name);
}
- anon = true;
+ anon = Some(ident);
}
- QueryModifier::EvalAlways => {
- if eval_always {
+ QueryModifier::EvalAlways(ident) => {
+ if eval_always.is_some() {
panic!("duplicate modifier `eval_always` for query `{}`", query.name);
}
- eval_always = true;
+ eval_always = Some(ident);
}
}
}
@@ -454,31 +454,39 @@
let mut attributes = Vec::new();
// Pass on the fatal_cycle modifier
- if modifiers.fatal_cycle {
- attributes.push(quote! { fatal_cycle });
+ if let Some(fatal_cycle) = &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) });
+ let span = ty.span();
+ attributes.push(quote_spanned! {span=> storage(#ty) });
};
// Pass on the cycle_delay_bug modifier
- if modifiers.cycle_delay_bug {
- attributes.push(quote! { cycle_delay_bug });
+ if let Some(cycle_delay_bug) = &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 });
+ if let Some(no_hash) = &modifiers.no_hash {
+ attributes.push(quote! { #no_hash });
};
// Pass on the anon modifier
- if modifiers.anon {
- attributes.push(quote! { anon });
+ if let Some(anon) = &modifiers.anon {
+ attributes.push(quote! { #anon });
};
// Pass on the eval_always modifier
- if modifiers.eval_always {
- attributes.push(quote! { eval_always });
+ if let Some(eval_always) = &modifiers.eval_always {
+ attributes.push(quote! { #eval_always });
};
- let attribute_stream = quote! {#(#attributes),*};
+ // This uses the span of the query definition for the commas,
+ // which can be important if we later encounter any ambiguity
+ // errors with any of the numerous macro_rules! macros that
+ // we use. Using the call-site span would result in a span pointing
+ // at the entire `rustc_queries!` invocation, which wouldn't
+ // be very useful.
+ let span = name.span();
+ let attribute_stream = quote_spanned! {span=> #(#attributes),*};
let doc_comments = query.doc_comments.iter();
// Add the query to the group
query_stream.extend(quote! {
diff --git a/compiler/rustc_macros/src/symbols.rs b/compiler/rustc_macros/src/symbols.rs
index 2f063f7..85e990b 100644
--- a/compiler/rustc_macros/src/symbols.rs
+++ b/compiler/rustc_macros/src/symbols.rs
@@ -135,7 +135,7 @@
let mut check_dup = |span: Span, str: &str, errors: &mut Errors| {
if let Some(prev_span) = keys.get(str) {
errors.error(span, format!("Symbol `{}` is duplicated", str));
- errors.error(*prev_span, format!("location of previous definition"));
+ errors.error(*prev_span, "location of previous definition".to_string());
} else {
keys.insert(str.to_string(), span);
}
@@ -207,7 +207,6 @@
#keyword_stream
}
- #[cfg_attr(bootstrap, allow(rustc::default_hash_types))]
#[allow(non_upper_case_globals)]
#[doc(hidden)]
pub mod sym_generated {
diff --git a/compiler/rustc_metadata/Cargo.toml b/compiler/rustc_metadata/Cargo.toml
index 14b4ebf..7c79aa5 100644
--- a/compiler/rustc_metadata/Cargo.toml
+++ b/compiler/rustc_metadata/Cargo.toml
@@ -1,5 +1,4 @@
[package]
-authors = ["The Rust Project Developers"]
name = "rustc_metadata"
version = "0.0.0"
edition = "2018"
diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs
index 5373169b..394cb83 100644
--- a/compiler/rustc_metadata/src/creader.rs
+++ b/compiler/rustc_metadata/src/creader.rs
@@ -777,19 +777,17 @@
}
fn inject_profiler_runtime(&mut self, krate: &ast::Crate) {
- let profiler_runtime = &self.sess.opts.debugging_opts.profiler_runtime;
-
- if !(profiler_runtime.is_some()
- && (self.sess.instrument_coverage()
+ if self.sess.opts.debugging_opts.no_profiler_runtime
+ || !(self.sess.instrument_coverage()
|| self.sess.opts.debugging_opts.profile
- || self.sess.opts.cg.profile_generate.enabled()))
+ || self.sess.opts.cg.profile_generate.enabled())
{
return;
}
info!("loading profiler");
- let name = Symbol::intern(profiler_runtime.as_ref().unwrap());
+ let name = Symbol::intern(&self.sess.opts.debugging_opts.profiler_runtime);
if name == sym::profiler_builtins && self.sess.contains_name(&krate.attrs, sym::no_core) {
self.sess.err(
"`profiler_builtins` crate (required by compiler options) \
diff --git a/compiler/rustc_metadata/src/locator.rs b/compiler/rustc_metadata/src/locator.rs
index 028104f..8d1bf6f 100644
--- a/compiler/rustc_metadata/src/locator.rs
+++ b/compiler/rustc_metadata/src/locator.rs
@@ -226,7 +226,7 @@
use rustc_session::filesearch::{FileDoesntMatch, FileMatches, FileSearch};
use rustc_session::search_paths::PathKind;
use rustc_session::utils::CanonicalizedPath;
-use rustc_session::{Session, StableCrateId};
+use rustc_session::Session;
use rustc_span::symbol::{sym, Symbol};
use rustc_span::Span;
use rustc_target::spec::{Target, TargetTriple};
@@ -787,7 +787,7 @@
metadata_loader: &dyn MetadataLoader,
span: Span,
name: Symbol,
-) -> (PathBuf, StableCrateId) {
+) -> PathBuf {
match find_plugin_registrar_impl(sess, metadata_loader, name) {
Ok(res) => res,
// `core` is always available if we got as far as loading plugins.
@@ -799,7 +799,7 @@
sess: &'a Session,
metadata_loader: &dyn MetadataLoader,
name: Symbol,
-) -> Result<(PathBuf, StableCrateId), CrateError> {
+) -> Result<PathBuf, CrateError> {
info!("find plugin registrar `{}`", name);
let mut locator = CrateLocator::new(
sess,
@@ -816,7 +816,7 @@
match locator.maybe_load_library_crate()? {
Some(library) => match library.source.dylib {
- Some(dylib) => Ok((dylib.0, library.metadata.get_root().stable_crate_id())),
+ Some(dylib) => Ok(dylib.0),
None => Err(CrateError::NonDylibPlugin(name)),
},
None => Err(locator.into_error()),
@@ -1080,7 +1080,10 @@
locator.triple
));
}
- if missing_core && std::env::var("RUSTUP_HOME").is_ok() {
+ // NOTE: this suggests using rustup, even though the user may not have it installed.
+ // That's because they could choose to install it; or this may give them a hint which
+ // target they need to install from their distro.
+ if missing_core {
err.help(&format!(
"consider downloading the target with `rustup target add {}`",
locator.triple
@@ -1097,11 +1100,11 @@
current_crate
));
}
- if sess.is_nightly_build() && std::env::var("CARGO").is_ok() {
+ if sess.is_nightly_build() {
err.help("consider building the standard library from source with `cargo build -Zbuild-std`");
}
- } else if Some(crate_name)
- == sess.opts.debugging_opts.profiler_runtime.as_deref().map(Symbol::intern)
+ } else if crate_name
+ == Symbol::intern(&sess.opts.debugging_opts.profiler_runtime)
{
err.note(&"the compiler may have been built without the profiler runtime");
}
diff --git a/compiler/rustc_metadata/src/native_libs.rs b/compiler/rustc_metadata/src/native_libs.rs
index 16b4d26..5f0d8c4 100644
--- a/compiler/rustc_metadata/src/native_libs.rs
+++ b/compiler/rustc_metadata/src/native_libs.rs
@@ -44,8 +44,7 @@
// Process all of the #[link(..)]-style arguments
let sess = &self.tcx.sess;
- for m in self.tcx.hir().attrs(it.hir_id()).iter().filter(|a| sess.check_name(a, sym::link))
- {
+ for m in self.tcx.hir().attrs(it.hir_id()).iter().filter(|a| a.has_name(sym::link)) {
let items = match m.meta_item_list() {
Some(item) => item,
None => continue,
@@ -77,6 +76,15 @@
modifier `-bundle` with library kind `static`",
)
.emit();
+ if !self.tcx.features().static_nobundle {
+ feature_err(
+ &self.tcx.sess.parse_sess,
+ sym::static_nobundle,
+ item.span(),
+ "kind=\"static-nobundle\" is unstable",
+ )
+ .emit();
+ }
NativeLibKind::Static { bundle: Some(false), whole_archive: None }
}
"dylib" => NativeLibKind::Dylib { as_needed: None },
@@ -252,17 +260,6 @@
)
.emit();
}
- if matches!(lib.kind, NativeLibKind::Static { bundle: Some(false), .. })
- && !self.tcx.features().static_nobundle
- {
- feature_err(
- &self.tcx.sess.parse_sess,
- sym::static_nobundle,
- span.unwrap_or(rustc_span::DUMMY_SP),
- "kind=\"static-nobundle\" is unstable",
- )
- .emit();
- }
// this just unwraps lib.name; we already established that it isn't empty above.
if let (NativeLibKind::RawDylib, Some(lib_name)) = (lib.kind, lib.name) {
let span = match span {
diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs
index 8bdd431..dd44e0c 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder.rs
@@ -62,7 +62,7 @@
// --- Some data pre-decoded from the metadata blob, usually for performance ---
/// Properties of the whole crate.
/// NOTE(eddyb) we pass `'static` to a `'tcx` parameter because this
- /// lifetime is only used behind `Lazy`, and therefore acts like an
+ /// lifetime is only used behind `Lazy`, and therefore acts like a
/// universal (`for<'tcx>`), that is paired up with whichever `TyCtxt`
/// is being used to decode those values.
root: CrateRoot<'static>,
@@ -1100,7 +1100,13 @@
let vis = self.get_visibility(child_index);
let def_id = self.local_def_id(child_index);
let res = Res::Def(kind, def_id);
- callback(Export { res, ident, vis, span });
+
+ // FIXME: Macros are currently encoded twice, once as items and once as
+ // reexports. We ignore the items here and only use the reexports.
+ if !matches!(kind, DefKind::Macro(..)) {
+ callback(Export { res, ident, vis, span });
+ }
+
// For non-re-export structs and variants add their constructors to children.
// Re-export lists automatically contain constructors when necessary.
match kind {
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index a4913a3..d8b9a47 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -439,7 +439,7 @@
fn encode_info_for_items(&mut self) {
let krate = self.tcx.hir().krate();
- self.encode_info_for_mod(CRATE_DEF_ID, &krate.item);
+ self.encode_info_for_mod(CRATE_DEF_ID, krate.module());
// Proc-macro crates only export proc-macro items, which are looked
// up using `proc_macro_data`
@@ -448,16 +448,13 @@
}
krate.visit_all_item_likes(&mut self.as_deep_visitor());
- for macro_def in krate.exported_macros {
- self.visit_macro_def(macro_def);
- }
}
fn encode_def_path_table(&mut self) {
let table = self.tcx.resolutions(()).definitions.def_path_table();
if self.is_proc_macro {
for def_index in std::iter::once(CRATE_DEF_INDEX)
- .chain(self.tcx.hir().krate().proc_macros.iter().map(|p| p.owner.local_def_index))
+ .chain(self.tcx.resolutions(()).proc_macros.iter().map(|p| p.local_def_index))
{
let def_key = self.lazy(table.def_key(def_index));
let def_path_hash = self.lazy(table.def_path_hash(def_index));
@@ -503,14 +500,26 @@
// Prepend path of working directory onto potentially
// relative paths, because they could become relative
// to a wrong directory.
- let working_dir = &self.tcx.sess.working_dir;
+ // We include `working_dir` as part of the crate hash,
+ // so it's okay for us to use it as part of the encoded
+ // metadata.
+ let working_dir = &self.tcx.sess.opts.working_dir;
match working_dir {
RealFileName::LocalPath(absolute) => {
- // If working_dir has not been remapped, then we emit a
- // LocalPath variant as it's likely to be a valid path
- RealFileName::LocalPath(
- Path::new(absolute).join(path_to_file),
- )
+ // Although neither working_dir or the file name were subject
+ // to path remapping, the concatenation between the two may
+ // be. Hence we need to do a remapping here.
+ let joined = Path::new(absolute).join(path_to_file);
+ let (joined, remapped) =
+ source_map.path_mapping().map_prefix(joined);
+ if remapped {
+ RealFileName::Remapped {
+ local_path: None,
+ virtual_name: joined,
+ }
+ } else {
+ RealFileName::LocalPath(joined)
+ }
}
RealFileName::Remapped { local_path: _, virtual_name } => {
// If working_dir has been remapped, then we emit
@@ -918,12 +927,12 @@
| DefKind::AnonConst
| DefKind::OpaqueTy
| DefKind::Impl
+ | DefKind::Field
+ | DefKind::TyParam
| DefKind::Closure
| DefKind::Generator => true,
DefKind::Mod
- | DefKind::Field
| DefKind::ForeignMod
- | DefKind::TyParam
| DefKind::ConstParam
| DefKind::Macro(..)
| DefKind::Use
@@ -1373,6 +1382,9 @@
EntryKind::Fn(self.lazy(data))
}
+ hir::ItemKind::Macro(ref macro_def) => {
+ EntryKind::MacroDef(self.lazy(macro_def.clone()))
+ }
hir::ItemKind::Mod(ref m) => {
return self.encode_info_for_mod(item.def_id, m);
}
@@ -1527,13 +1539,6 @@
}
}
- /// Serialize the text of exported macros
- fn encode_info_for_macro_def(&mut self, macro_def: &hir::MacroDef<'_>) {
- let def_id = macro_def.def_id.to_def_id();
- record!(self.tables.kind[def_id] <- EntryKind::MacroDef(self.lazy(macro_def.ast.clone())));
- self.encode_ident_span(def_id, macro_def.ident);
- }
-
fn encode_info_for_generic_param(&mut self, def_id: DefId, kind: EntryKind, encode_type: bool) {
record!(self.tables.kind[def_id] <- kind);
if encode_type {
@@ -1625,7 +1630,8 @@
let proc_macro_decls_static = tcx.proc_macro_decls_static(()).unwrap().local_def_index;
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));
+ let macros =
+ self.lazy(tcx.resolutions(()).proc_macros.iter().map(|p| p.local_def_index));
let spans = self.tcx.sess.parse_sess.proc_macro_quoted_spans();
for (i, span) in spans.into_iter().enumerate() {
let span = self.lazy(span);
@@ -1644,13 +1650,14 @@
// 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
- for proc_macro in &hir.krate().proc_macros {
- let id = proc_macro.owner.local_def_index;
- let mut name = hir.name(*proc_macro);
- let span = hir.span(*proc_macro);
+ for &proc_macro in &tcx.resolutions(()).proc_macros {
+ let id = proc_macro;
+ let proc_macro = hir.local_def_id_to_hir_id(proc_macro);
+ let mut name = hir.name(proc_macro);
+ let span = hir.span(proc_macro);
// Proc-macros may have attributes like `#[allow_internal_unstable]`,
// so downstream crates need access to them.
- let attrs = hir.attrs(*proc_macro);
+ let attrs = hir.attrs(proc_macro);
let macro_kind = if tcx.sess.contains_name(attrs, sym::proc_macro) {
MacroKind::Bang
} else if tcx.sess.contains_name(attrs, sym::proc_macro_attribute) {
@@ -1668,10 +1675,10 @@
bug!("Unknown proc-macro type for item {:?}", id);
};
- let mut def_key = self.tcx.hir().def_key(proc_macro.owner);
+ let mut def_key = self.tcx.hir().def_key(id);
def_key.disambiguated_data.data = DefPathData::MacroNs(name);
- let def_id = DefId::local(id);
+ let def_id = id.to_def_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);
@@ -1903,9 +1910,6 @@
intravisit::walk_generics(self, generics);
self.encode_info_for_generics(generics);
}
- fn visit_macro_def(&mut self, macro_def: &'tcx hir::MacroDef<'tcx>) {
- self.encode_info_for_macro_def(macro_def);
- }
}
impl EncodeContext<'a, 'tcx> {
@@ -1960,6 +1964,7 @@
hir::ItemKind::Static(..)
| hir::ItemKind::Const(..)
| hir::ItemKind::Fn(..)
+ | hir::ItemKind::Macro(..)
| hir::ItemKind::Mod(..)
| hir::ItemKind::ForeignMod { .. }
| hir::ItemKind::GlobalAsm(..)
diff --git a/compiler/rustc_middle/Cargo.toml b/compiler/rustc_middle/Cargo.toml
index 90ad025..2403ce2 100644
--- a/compiler/rustc_middle/Cargo.toml
+++ b/compiler/rustc_middle/Cargo.toml
@@ -1,5 +1,4 @@
[package]
-authors = ["The Rust Project Developers"]
name = "rustc_middle"
version = "0.0.0"
edition = "2018"
@@ -12,7 +11,7 @@
bitflags = "1.2.1"
tracing = "0.1"
rustc-rayon-core = "0.3.1"
-polonius-engine = "0.12.0"
+polonius-engine = "0.13.0"
rustc_apfloat = { path = "../rustc_apfloat" }
rustc_attr = { path = "../rustc_attr" }
rustc_feature = { path = "../rustc_feature" }
diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs
index a89d00e..59db2c6 100644
--- a/compiler/rustc_middle/src/arena.rs
+++ b/compiler/rustc_middle/src/arena.rs
@@ -9,8 +9,8 @@
/// listed. These impls will appear in the implement_ty_decoder! macro.
#[macro_export]
macro_rules! arena_types {
- ($macro:path, $args:tt, $tcx:lifetime) => (
- $macro!($args, [
+ ($macro:path, $tcx:lifetime) => (
+ $macro!([
[] layouts: rustc_target::abi::Layout,
// AdtDef are interned and compared by address
[] adt_def: rustc_middle::ty::AdtDef,
@@ -109,4 +109,4 @@
)
}
-arena_types!(rustc_arena::declare_arena, [], 'tcx);
+arena_types!(rustc_arena::declare_arena, 'tcx);
diff --git a/compiler/rustc_middle/src/hir/map/blocks.rs b/compiler/rustc_middle/src/hir/map/blocks.rs
index 706c790..8efec8e 100644
--- a/compiler/rustc_middle/src/hir/map/blocks.rs
+++ b/compiler/rustc_middle/src/hir/map/blocks.rs
@@ -63,7 +63,7 @@
}
}
-/// Carries either an FnLikeNode or a Expr, as these are the two
+/// Carries either an FnLikeNode or an Expr, as these are the two
/// constructs that correspond to "code" (as in, something from which
/// we can construct a control-flow graph).
#[derive(Copy, Clone)]
diff --git a/compiler/rustc_middle/src/hir/map/collector.rs b/compiler/rustc_middle/src/hir/map/collector.rs
index 8ffd983..1351b49 100644
--- a/compiler/rustc_middle/src/hir/map/collector.rs
+++ b/compiler/rustc_middle/src/hir/map/collector.rs
@@ -7,7 +7,7 @@
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_hir as hir;
use rustc_hir::def_id::LocalDefId;
-use rustc_hir::def_id::CRATE_DEF_INDEX;
+use rustc_hir::def_id::CRATE_DEF_ID;
use rustc_hir::definitions;
use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
use rustc_hir::*;
@@ -75,46 +75,20 @@
arena: &'hir Arena<'hir>,
krate: &'hir Crate<'hir>,
definitions: &'a definitions::Definitions,
- mut hcx: StableHashingContext<'a>,
+ hcx: StableHashingContext<'a>,
) -> NodeCollector<'a, 'hir> {
- let hash = {
- let Crate {
- ref item,
- // These fields are handled separately:
- exported_macros: _,
- non_exported_macro_attrs: _,
- items: _,
- trait_items: _,
- impl_items: _,
- foreign_items: _,
- bodies: _,
- trait_impls: _,
- body_ids: _,
- modules: _,
- proc_macros: _,
- trait_map: _,
- attrs: _,
- } = *krate;
-
- hash_body(&mut hcx, item)
- };
-
let mut collector = NodeCollector {
arena,
krate,
source_map: sess.source_map(),
parent_node: hir::CRATE_HIR_ID,
- current_dep_node_owner: LocalDefId { local_def_index: CRATE_DEF_INDEX },
+ current_dep_node_owner: CRATE_DEF_ID,
definitions,
hcx,
map: IndexVec::from_fn_n(|_| None, definitions.def_index_count()),
parenting: FxHashMap::default(),
};
- collector.insert_entry(
- hir::CRATE_HIR_ID,
- Entry { parent: hir::CRATE_HIR_ID, node: Node::Crate(&krate.item) },
- hash,
- );
+ collector.insert_owner(CRATE_DEF_ID, OwnerNode::Crate(krate.module()));
collector
}
@@ -128,53 +102,20 @@
IndexedHir { map: self.map, parenting: self.parenting }
}
- fn insert_entry(&mut self, id: HirId, entry: Entry<'hir>, hash: Fingerprint) {
- let i = id.local_id.as_u32() as usize;
+ fn insert_owner(&mut self, owner: LocalDefId, node: OwnerNode<'hir>) {
+ let hash = hash_body(&mut self.hcx, node);
- let arena = self.arena;
+ let mut nodes = IndexVec::new();
+ nodes.push(Some(ParentedNode { parent: ItemLocalId::new(0), node: node.into() }));
- let data = &mut self.map[id.owner];
-
- if i == 0 {
- debug_assert!(data.is_none());
- *data = Some(arena.alloc(OwnerNodes {
- hash,
- nodes: IndexVec::new(),
- bodies: FxHashMap::default(),
- }));
-
- let dk_parent = self.definitions.def_key(id.owner).parent;
- if let Some(dk_parent) = dk_parent {
- let dk_parent = LocalDefId { local_def_index: dk_parent };
- let dk_parent = self.definitions.local_def_id_to_hir_id(dk_parent);
- if dk_parent.owner != entry.parent.owner {
- panic!(
- "Different parents for {:?} => dk_parent={:?} actual={:?}",
- id.owner, dk_parent, entry.parent,
- )
- }
-
- debug_assert_eq!(self.parenting.get(&id.owner), Some(&entry.parent));
- }
- } else {
- debug_assert_eq!(entry.parent.owner, id.owner);
- }
-
- let data = data.as_mut().unwrap();
-
- insert_vec_map(
- &mut data.nodes,
- id.local_id,
- ParentedNode { parent: entry.parent.local_id, node: entry.node },
- );
+ debug_assert!(self.map[owner].is_none());
+ self.map[owner] =
+ Some(self.arena.alloc(OwnerNodes { hash, nodes, bodies: FxHashMap::default() }));
}
fn insert(&mut self, span: Span, hir_id: HirId, node: Node<'hir>) {
- self.insert_with_hash(span, hir_id, node, Fingerprint::ZERO)
- }
-
- fn insert_with_hash(&mut self, span: Span, hir_id: HirId, node: Node<'hir>, hash: Fingerprint) {
- let entry = Entry { parent: self.parent_node, node };
+ debug_assert_eq!(self.current_dep_node_owner, hir_id.owner);
+ debug_assert_ne!(hir_id.local_id.as_u32(), 0);
// Make sure that the DepNode of some node coincides with the HirId
// owner of that node.
@@ -201,7 +142,14 @@
}
}
- self.insert_entry(hir_id, entry, hash);
+ let nodes = self.map[hir_id.owner].as_mut().unwrap();
+
+ debug_assert_eq!(self.parent_node.owner, self.current_dep_node_owner);
+ insert_vec_map(
+ &mut nodes.nodes,
+ hir_id.local_id,
+ ParentedNode { parent: self.parent_node.local_id, node: node },
+ );
}
fn with_parent<F: FnOnce(&mut Self)>(&mut self, parent_node_id: HirId, f: F) {
@@ -211,21 +159,15 @@
self.parent_node = parent_node;
}
- fn with_dep_node_owner<
- T: for<'b> HashStable<StableHashingContext<'b>>,
- F: FnOnce(&mut Self, Fingerprint),
- >(
- &mut self,
- dep_node_owner: LocalDefId,
- item_like: &T,
- f: F,
- ) {
+ fn with_dep_node_owner(&mut self, dep_node_owner: LocalDefId, f: impl FnOnce(&mut Self)) {
let prev_owner = self.current_dep_node_owner;
- let hash = hash_body(&mut self.hcx, item_like);
+ let prev_parent = self.parent_node;
self.current_dep_node_owner = dep_node_owner;
- f(self, hash);
+ self.parent_node = HirId::make_owner(dep_node_owner);
+ f(self);
self.current_dep_node_owner = prev_owner;
+ self.parent_node = prev_parent;
}
fn insert_nested(&mut self, item: LocalDefId) {
@@ -291,28 +233,22 @@
fn visit_item(&mut self, i: &'hir Item<'hir>) {
debug!("visit_item: {:?}", i);
- self.with_dep_node_owner(i.def_id, i, |this, hash| {
- let hir_id = i.hir_id();
- this.insert_with_hash(i.span, hir_id, Node::Item(i), hash);
- this.with_parent(hir_id, |this| {
- if let ItemKind::Struct(ref struct_def, _) = i.kind {
- // If this is a tuple or unit-like struct, register the constructor.
- if let Some(ctor_hir_id) = struct_def.ctor_hir_id() {
- this.insert(i.span, ctor_hir_id, Node::Ctor(struct_def));
- }
+ self.insert_owner(i.def_id, OwnerNode::Item(i));
+ self.with_dep_node_owner(i.def_id, |this| {
+ if let ItemKind::Struct(ref struct_def, _) = i.kind {
+ // If this is a tuple or unit-like struct, register the constructor.
+ if let Some(ctor_hir_id) = struct_def.ctor_hir_id() {
+ this.insert(i.span, ctor_hir_id, Node::Ctor(struct_def));
}
- intravisit::walk_item(this, i);
- });
+ }
+ intravisit::walk_item(this, i);
});
}
fn visit_foreign_item(&mut self, fi: &'hir ForeignItem<'hir>) {
- self.with_dep_node_owner(fi.def_id, fi, |this, hash| {
- this.insert_with_hash(fi.span, fi.hir_id(), Node::ForeignItem(fi), hash);
-
- this.with_parent(fi.hir_id(), |this| {
- intravisit::walk_foreign_item(this, fi);
- });
+ self.insert_owner(fi.def_id, OwnerNode::ForeignItem(fi));
+ self.with_dep_node_owner(fi.def_id, |this| {
+ intravisit::walk_foreign_item(this, fi);
});
}
@@ -322,26 +258,22 @@
}
fn visit_const_param_default(&mut self, param: HirId, ct: &'hir AnonConst) {
- self.with_parent(param, |this| intravisit::walk_const_param_default(this, ct))
+ self.with_parent(param, |this| {
+ intravisit::walk_const_param_default(this, ct);
+ })
}
fn visit_trait_item(&mut self, ti: &'hir TraitItem<'hir>) {
- self.with_dep_node_owner(ti.def_id, ti, |this, hash| {
- this.insert_with_hash(ti.span, ti.hir_id(), Node::TraitItem(ti), hash);
-
- this.with_parent(ti.hir_id(), |this| {
- intravisit::walk_trait_item(this, ti);
- });
+ self.insert_owner(ti.def_id, OwnerNode::TraitItem(ti));
+ self.with_dep_node_owner(ti.def_id, |this| {
+ intravisit::walk_trait_item(this, ti);
});
}
fn visit_impl_item(&mut self, ii: &'hir ImplItem<'hir>) {
- self.with_dep_node_owner(ii.def_id, ii, |this, hash| {
- this.insert_with_hash(ii.span, ii.hir_id(), Node::ImplItem(ii), hash);
-
- this.with_parent(ii.hir_id(), |this| {
- intravisit::walk_impl_item(this, ii);
- });
+ self.insert_owner(ii.def_id, OwnerNode::ImplItem(ii));
+ self.with_dep_node_owner(ii.def_id, |this| {
+ intravisit::walk_impl_item(this, ii);
});
}
@@ -404,6 +336,14 @@
});
}
+ fn visit_infer(&mut self, inf: &'hir InferArg) {
+ self.insert(inf.span, inf.hir_id, Node::Infer(inf));
+
+ self.with_parent(inf.hir_id, |this| {
+ intravisit::walk_inf(this, inf);
+ });
+ }
+
fn visit_trait_ref(&mut self, tr: &'hir TraitRef<'hir>) {
self.insert(tr.path.span, tr.hir_ref_id, Node::TraitRef(tr));
@@ -433,7 +373,9 @@
fn visit_local(&mut self, l: &'hir Local<'hir>) {
self.insert(l.span, l.hir_id, Node::Local(l));
- self.with_parent(l.hir_id, |this| intravisit::walk_local(this, l))
+ self.with_parent(l.hir_id, |this| {
+ intravisit::walk_local(this, l);
+ })
}
fn visit_lifetime(&mut self, lifetime: &'hir Lifetime) {
@@ -452,27 +394,6 @@
}
}
- fn visit_macro_def(&mut self, macro_def: &'hir MacroDef<'hir>) {
- // 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.def_id);
- 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.insert_nested(macro_def.def_id);
- this.with_dep_node_owner(macro_def.def_id, macro_def, |this, hash| {
- this.insert_with_hash(
- macro_def.span,
- macro_def.hir_id(),
- Node::MacroDef(macro_def),
- hash,
- );
- })
- });
- }
-
fn visit_variant(&mut self, v: &'hir Variant<'hir>, g: &'hir Generics<'hir>, item_id: HirId) {
self.insert(v.span, v.id, Node::Variant(v));
self.with_parent(v.id, |this| {
diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs
index 392372f..62d0374 100644
--- a/compiler/rustc_middle/src/hir/map/mod.rs
+++ b/compiler/rustc_middle/src/hir/map/mod.rs
@@ -1,6 +1,6 @@
use self::collector::NodeCollector;
-use crate::hir::{AttributeMap, IndexedHir};
+use crate::hir::{AttributeMap, IndexedHir, Owner};
use crate::ty::TyCtxt;
use rustc_ast as ast;
use rustc_data_structures::fingerprint::Fingerprint;
@@ -10,7 +10,6 @@
use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, CRATE_DEF_INDEX, LOCAL_CRATE};
use rustc_hir::definitions::{DefKey, DefPath, DefPathHash};
use rustc_hir::intravisit;
-use rustc_hir::intravisit::Visitor;
use rustc_hir::itemlikevisit::ItemLikeVisitor;
use rustc_hir::*;
use rustc_index::vec::Idx;
@@ -121,13 +120,13 @@
}
impl<'hir> Iterator for ParentOwnerIterator<'_, 'hir> {
- type Item = (HirId, Node<'hir>);
+ type Item = (HirId, OwnerNode<'hir>);
fn next(&mut self) -> Option<Self::Item> {
if self.current_id.local_id.index() != 0 {
self.current_id.local_id = ItemLocalId::new(0);
- if let Some(node) = self.map.find(self.current_id) {
- return Some((self.current_id, node));
+ if let Some(node) = self.map.tcx.hir_owner(self.current_id.owner) {
+ return Some((self.current_id, node.node));
}
}
if self.current_id == CRATE_HIR_ID {
@@ -144,8 +143,8 @@
self.current_id = HirId::make_owner(parent_id);
// If this `HirId` doesn't have an entry, skip it and look for its `parent_id`.
- if let Some(node) = self.map.find(self.current_id) {
- return Some((self.current_id, node));
+ if let Some(node) = self.map.tcx.hir_owner(self.current_id.owner) {
+ return Some((self.current_id, node.node));
}
}
}
@@ -218,6 +217,7 @@
ItemKind::Static(..) => DefKind::Static,
ItemKind::Const(..) => DefKind::Const,
ItemKind::Fn(..) => DefKind::Fn,
+ ItemKind::Macro(..) => DefKind::Macro(MacroKind::Bang),
ItemKind::Mod(..) => DefKind::Mod,
ItemKind::OpaqueTy(..) => DefKind::OpaqueTy,
ItemKind::TyAlias(..) => DefKind::TyAlias,
@@ -266,7 +266,6 @@
ExprKind::Closure(.., Some(_)) => DefKind::Generator,
_ => bug!("def_kind: unsupported node: {}", self.node_to_string(hir_id)),
},
- Node::MacroDef(_) => DefKind::Macro(MacroKind::Bang),
Node::GenericParam(param) => match param.kind {
GenericParamKind::Lifetime { .. } => DefKind::LifetimeParam,
GenericParamKind::Type { .. } => DefKind::TyParam,
@@ -276,6 +275,7 @@
Node::Stmt(_)
| Node::PathSegment(_)
| Node::Ty(_)
+ | Node::Infer(_)
| Node::TraitRef(_)
| Node::Pat(_)
| Node::Binding(_)
@@ -313,7 +313,7 @@
pub fn find(&self, id: HirId) -> Option<Node<'hir>> {
if id.local_id == ItemLocalId::from_u32(0) {
let owner = self.tcx.hir_owner(id.owner)?;
- Some(owner.node)
+ Some(owner.node.into())
} else {
let owner = self.tcx.hir_owner_nodes(id.owner)?;
let node = owner.nodes[id.local_id].as_ref()?;
@@ -331,10 +331,12 @@
}
pub fn get_generics(&self, id: DefId) -> Option<&'hir Generics<'hir>> {
- self.get_if_local(id).and_then(|node| match &node {
- Node::ImplItem(impl_item) => Some(&impl_item.generics),
- Node::TraitItem(trait_item) => Some(&trait_item.generics),
- Node::Item(Item {
+ let id = id.as_local()?;
+ let node = self.tcx.hir_owner(id)?;
+ match node.node {
+ OwnerNode::ImplItem(impl_item) => Some(&impl_item.generics),
+ OwnerNode::TraitItem(trait_item) => Some(&trait_item.generics),
+ OwnerNode::Item(Item {
kind:
ItemKind::Fn(_, generics, _)
| ItemKind::TyAlias(_, generics)
@@ -347,35 +349,23 @@
..
}) => Some(generics),
_ => None,
- })
+ }
}
pub fn item(&self, id: ItemId) -> &'hir Item<'hir> {
- match self.find(id.hir_id()).unwrap() {
- Node::Item(item) => item,
- _ => bug!(),
- }
+ self.tcx.hir_owner(id.def_id).unwrap().node.expect_item()
}
pub fn trait_item(&self, id: TraitItemId) -> &'hir TraitItem<'hir> {
- match self.find(id.hir_id()).unwrap() {
- Node::TraitItem(item) => item,
- _ => bug!(),
- }
+ self.tcx.hir_owner(id.def_id).unwrap().node.expect_trait_item()
}
pub fn impl_item(&self, id: ImplItemId) -> &'hir ImplItem<'hir> {
- match self.find(id.hir_id()).unwrap() {
- Node::ImplItem(item) => item,
- _ => bug!(),
- }
+ self.tcx.hir_owner(id.def_id).unwrap().node.expect_impl_item()
}
pub fn foreign_item(&self, id: ForeignItemId) -> &'hir ForeignItem<'hir> {
- match self.find(id.hir_id()).unwrap() {
- Node::ForeignItem(item) => item,
- _ => bug!(),
- }
+ self.tcx.hir_owner(id.def_id).unwrap().node.expect_foreign_item()
}
pub fn body(&self, id: BodyId) -> &'hir Body<'hir> {
@@ -519,10 +509,12 @@
}
pub fn get_module(&self, module: LocalDefId) -> (&'hir Mod<'hir>, Span, HirId) {
- let hir_id = self.local_def_id_to_hir_id(module);
- match self.get(hir_id) {
- Node::Item(&Item { span, kind: ItemKind::Mod(ref m), .. }) => (m, span, hir_id),
- Node::Crate(item) => (&item, item.inner, hir_id),
+ let hir_id = HirId::make_owner(module);
+ match self.tcx.hir_owner(module).map(|o| o.node) {
+ Some(OwnerNode::Item(&Item { span, kind: ItemKind::Mod(ref m), .. })) => {
+ (m, span, hir_id)
+ }
+ Some(OwnerNode::Crate(item)) => (item, item.inner, hir_id),
node => panic!("not a module: {:?}", node),
}
}
@@ -550,15 +542,6 @@
}
}
- 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()));
- }
- }
-
/// Returns an iterator for the nodes in the ancestor tree of the `current_id`
/// until the crate root is reached. Prefer this over your own loop using `get_parent_node`.
pub fn parent_iter(&self, current_id: HirId) -> ParentHirIterator<'_, 'hir> {
@@ -588,14 +571,6 @@
self.body_const_context(self.local_def_id(self.enclosing_body_owner(hir_id))).is_some()
}
- /// Whether `hir_id` corresponds to a `mod` or a crate.
- pub fn is_hir_id_module(&self, hir_id: HirId) -> bool {
- matches!(
- self.get(hir_id),
- Node::Item(Item { kind: ItemKind::Mod(_), .. }) | Node::Crate(..)
- )
- }
-
/// Retrieves the `HirId` for `id`'s enclosing method, unless there's a
/// `while` or `loop` before reaching it, as block tail returns are not
/// available in them.
@@ -659,24 +634,18 @@
/// in the HIR which is recorded by the map and is an item, either an item
/// in a module, trait, or impl.
pub fn get_parent_item(&self, hir_id: HirId) -> HirId {
- for (hir_id, node) in self.parent_owner_iter(hir_id) {
- if let Node::Crate(_)
- | Node::Item(_)
- | Node::ForeignItem(_)
- | Node::TraitItem(_)
- | Node::ImplItem(_) = node
- {
- return hir_id;
- }
+ if let Some((hir_id, _node)) = self.parent_owner_iter(hir_id).next() {
+ hir_id
+ } else {
+ CRATE_HIR_ID
}
- CRATE_HIR_ID
}
/// Returns the `HirId` of `id`'s nearest module parent, or `id` itself if no
/// module parent is in this map.
pub(super) fn get_module_parent_node(&self, hir_id: HirId) -> HirId {
for (hir_id, node) in self.parent_owner_iter(hir_id) {
- if let Node::Item(&Item { kind: ItemKind::Mod(_), .. }) = node {
+ if let OwnerNode::Item(&Item { kind: ItemKind::Mod(_), .. }) = node {
return hir_id;
}
}
@@ -749,8 +718,9 @@
pub fn get_foreign_abi(&self, hir_id: HirId) -> Abi {
let parent = self.get_parent_item(hir_id);
- if let Some(node) = self.find(parent) {
- if let Node::Item(Item { kind: ItemKind::ForeignMod { abi, .. }, .. }) = node {
+ if let Some(node) = self.tcx.hir_owner(self.local_def_id(parent)) {
+ if let OwnerNode::Item(Item { kind: ItemKind::ForeignMod { abi, .. }, .. }) = node.node
+ {
return *abi;
}
}
@@ -758,22 +728,22 @@
}
pub fn expect_item(&self, id: HirId) -> &'hir Item<'hir> {
- match self.find(id) {
- Some(Node::Item(item)) => item,
+ match self.tcx.hir_owner(id.expect_owner()) {
+ Some(Owner { node: OwnerNode::Item(item) }) => item,
_ => bug!("expected item, found {}", self.node_to_string(id)),
}
}
pub fn expect_impl_item(&self, id: HirId) -> &'hir ImplItem<'hir> {
- match self.find(id) {
- Some(Node::ImplItem(item)) => item,
+ match self.tcx.hir_owner(id.expect_owner()) {
+ Some(Owner { node: OwnerNode::ImplItem(item) }) => item,
_ => bug!("expected impl item, found {}", self.node_to_string(id)),
}
}
pub fn expect_trait_item(&self, id: HirId) -> &'hir TraitItem<'hir> {
- match self.find(id) {
- Some(Node::TraitItem(item)) => item,
+ match self.tcx.hir_owner(id.expect_owner()) {
+ Some(Owner { node: OwnerNode::TraitItem(item) }) => item,
_ => bug!("expected trait item, found {}", self.node_to_string(id)),
}
}
@@ -786,19 +756,12 @@
}
pub fn expect_foreign_item(&self, id: HirId) -> &'hir ForeignItem<'hir> {
- match self.find(id) {
- Some(Node::ForeignItem(item)) => item,
+ match self.tcx.hir_owner(id.expect_owner()) {
+ Some(Owner { node: OwnerNode::ForeignItem(item) }) => item,
_ => bug!("expected foreign item, found {}", self.node_to_string(id)),
}
}
- 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,
@@ -818,7 +781,6 @@
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,
})
}
@@ -882,9 +844,9 @@
node: VisibilityKind::Restricted { ref path, .. },
..
}) => path.span,
+ Node::Infer(i) => i.span,
Node::Visibility(v) => bug!("unexpected Visibility {:?}", v),
Node::Local(local) => local.span,
- Node::MacroDef(macro_def) => macro_def.span,
Node::Crate(item) => item.inner,
};
Some(span)
@@ -919,6 +881,19 @@
pub fn node_to_string(&self, id: HirId) -> String {
hir_id_to_string(self, id)
}
+
+ /// Returns the HirId of `N` in `struct Foo<const N: usize = { ... }>` when
+ /// called with the HirId for the `{ ... }` anon const
+ pub fn opt_const_param_default_param_hir_id(&self, anon_const: HirId) -> Option<HirId> {
+ match self.get(self.get_parent_node(anon_const)) {
+ Node::GenericParam(GenericParam {
+ hir_id: param_id,
+ kind: GenericParamKind::Const { .. },
+ ..
+ }) => Some(*param_id),
+ _ => None,
+ }
+ }
}
impl<'hir> intravisit::Map<'hir> for Map<'hir> {
@@ -1017,7 +992,6 @@
source_file_names.hash_stable(&mut hcx, &mut stable_hasher);
tcx.sess.opts.dep_tracking_hash(true).hash_stable(&mut hcx, &mut stable_hasher);
tcx.sess.local_stable_crate_id().hash_stable(&mut hcx, &mut stable_hasher);
- tcx.untracked_crate.non_exported_macro_attrs.hash_stable(&mut hcx, &mut stable_hasher);
let crate_hash: Fingerprint = stable_hasher.finish();
Svh::new(crate_hash.to_smaller_hash())
@@ -1066,6 +1040,7 @@
ItemKind::Static(..) => "static",
ItemKind::Const(..) => "const",
ItemKind::Fn(..) => "fn",
+ ItemKind::Macro(..) => "macro",
ItemKind::Mod(..) => "mod",
ItemKind::ForeignMod { .. } => "foreign mod",
ItemKind::GlobalAsm(..) => "global asm",
@@ -1116,12 +1091,12 @@
Some(Node::Param(_)) => node_str("param"),
Some(Node::Arm(_)) => node_str("arm"),
Some(Node::Block(_)) => node_str("block"),
+ Some(Node::Infer(_)) => node_str("infer"),
Some(Node::Local(_)) => node_str("local"),
Some(Node::Ctor(..)) => format!("ctor {}{}", path_str(), id_str),
Some(Node::Lifetime(_)) => node_str("lifetime"),
Some(Node::GenericParam(ref param)) => format!("generic_param {:?}{}", param, id_str),
Some(Node::Visibility(ref vis)) => format!("visibility {:?}{}", vis, id_str),
- Some(Node::MacroDef(_)) => format!("macro {}{}", path_str(), id_str),
Some(Node::Crate(..)) => String::from("root_crate"),
None => format!("unknown node{}", id_str),
}
diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs
index 3026bf8..34aee4f 100644
--- a/compiler/rustc_middle/src/hir/mod.rs
+++ b/compiler/rustc_middle/src/hir/mod.rs
@@ -33,9 +33,12 @@
/// Top-level HIR node for current owner. This only contains the node for which
/// `HirId::local_id == 0`, and excludes bodies.
+///
+/// This struct exists to encapsulate all access to the hir_owner query in this module, and to
+/// implement HashStable without hashing bodies.
#[derive(Copy, Clone, Debug)]
pub struct Owner<'tcx> {
- node: Node<'tcx>,
+ node: OwnerNode<'tcx>,
}
impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for Owner<'tcx> {
@@ -140,7 +143,8 @@
providers.hir_module_items = |tcx, id| &tcx.untracked_crate.modules[&id];
providers.hir_owner = |tcx, id| {
let owner = tcx.index_hir(()).map[id].as_ref()?;
- let node = owner.nodes[ItemLocalId::new(0)].as_ref()?.node;
+ let node = owner.nodes[ItemLocalId::new(0)].as_ref().unwrap().node;
+ let node = node.as_owner().unwrap(); // Indexing must ensure it is an OwnerNode.
Some(Owner { node })
};
providers.hir_owner_nodes = |tcx, id| tcx.index_hir(()).map[id].as_deref();
@@ -166,7 +170,7 @@
}
};
providers.opt_def_kind = |tcx, def_id| tcx.hir().opt_def_kind(def_id.expect_local());
- providers.all_local_trait_impls = |tcx, ()| &tcx.hir_crate(()).trait_impls;
+ providers.all_local_trait_impls = |tcx, ()| &tcx.resolutions(()).trait_impls;
providers.expn_that_defined = |tcx, id| {
let id = id.expect_local();
tcx.resolutions(()).definitions.expansion_that_defined(id)
diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs
index f2acc60..573fa91 100644
--- a/compiler/rustc_middle/src/lib.rs
+++ b/compiler/rustc_middle/src/lib.rs
@@ -23,16 +23,18 @@
//! This API is completely unstable and subject to change.
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
+#![feature(allocator_api)]
#![feature(array_windows)]
#![feature(assert_matches)]
#![feature(backtrace)]
#![feature(bool_to_option)]
#![feature(box_patterns)]
-#![feature(box_syntax)]
#![feature(core_intrinsics)]
#![feature(discriminant_kind)]
+#![feature(if_let_guard)]
#![feature(never_type)]
#![feature(extern_types)]
+#![feature(new_uninit)]
#![feature(nll)]
#![feature(once_cell)]
#![feature(min_specialization)]
@@ -49,7 +51,9 @@
#![feature(iter_zip)]
#![feature(thread_local_const_init)]
#![feature(try_reserve)]
+#![feature(try_reserve_kind)]
#![feature(nonzero_ops)]
+#![cfg_attr(bootstrap, allow(incomplete_features))] // if_let_guard
#![recursion_limit = "512"]
#[macro_use]
diff --git a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs
index 93e7aea..b2705c7 100644
--- a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs
+++ b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs
@@ -52,13 +52,9 @@
/// `#[rustc_allocator]`: a hint to LLVM that the pointer returned from this
/// function is never null.
const ALLOCATOR = 1 << 1;
- /// `#[unwind]`: an indicator that this function may unwind despite what
- /// its ABI signature may otherwise imply.
- const UNWIND = 1 << 2;
- /// `#[rust_allocator_nounwind]`, an indicator that an imported FFI
- /// function will never unwind. Probably obsolete by recent changes with
- /// #[unwind], but hasn't been removed/migrated yet
- const RUSTC_ALLOCATOR_NOUNWIND = 1 << 3;
+ /// An indicator that function will never unwind. Will become obsolete
+ /// once C-unwind is fully stabilized.
+ const NEVER_UNWIND = 1 << 3;
/// `#[naked]`: an indicator to LLVM that no function prologue/epilogue
/// should be generated.
const NAKED = 1 << 4;
diff --git a/compiler/rustc_middle/src/middle/limits.rs b/compiler/rustc_middle/src/middle/limits.rs
index c4bfd0e..20dcb67 100644
--- a/compiler/rustc_middle/src/middle/limits.rs
+++ b/compiler/rustc_middle/src/middle/limits.rs
@@ -21,7 +21,12 @@
pub fn provide(providers: &mut ty::query::Providers) {
providers.limits = |tcx, ()| Limits {
recursion_limit: get_recursion_limit(tcx.hir().krate_attrs(), tcx.sess),
- move_size_limit: get_limit(tcx.hir().krate_attrs(), tcx.sess, sym::move_size_limit, 0),
+ move_size_limit: get_limit(
+ tcx.hir().krate_attrs(),
+ tcx.sess,
+ sym::move_size_limit,
+ tcx.sess.opts.debugging_opts.move_size_limit.unwrap_or(0),
+ ),
type_length_limit: get_limit(
tcx.hir().krate_attrs(),
tcx.sess,
@@ -43,7 +48,7 @@
fn get_limit(krate_attrs: &[Attribute], sess: &Session, name: Symbol, default: usize) -> Limit {
for attr in krate_attrs {
- if !sess.check_name(attr, name) {
+ if !attr.has_name(name) {
continue;
}
diff --git a/compiler/rustc_middle/src/middle/privacy.rs b/compiler/rustc_middle/src/middle/privacy.rs
index 5418898..a11ca74 100644
--- a/compiler/rustc_middle/src/middle/privacy.rs
+++ b/compiler/rustc_middle/src/middle/privacy.rs
@@ -3,9 +3,8 @@
//! which are available for use externally when compiled as a library.
use rustc_data_structures::fx::FxHashMap;
-use rustc_hir::HirId;
use rustc_macros::HashStable;
-use std::fmt;
+use rustc_span::def_id::LocalDefId;
use std::hash::Hash;
/// Represents the levels of accessibility an item can have.
@@ -27,8 +26,8 @@
}
/// Holds a map of accessibility levels for reachable HIR nodes.
-#[derive(Clone)]
-pub struct AccessLevels<Id = HirId> {
+#[derive(Debug)]
+pub struct AccessLevels<Id = LocalDefId> {
pub map: FxHashMap<Id, AccessLevel>,
}
@@ -49,14 +48,8 @@
}
}
-impl<Id: Hash + Eq> Default for AccessLevels<Id> {
+impl<Id> Default for AccessLevels<Id> {
fn default() -> Self {
AccessLevels { map: Default::default() }
}
}
-
-impl<Id: Hash + Eq + fmt::Debug> fmt::Debug for AccessLevels<Id> {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- fmt::Debug::fmt(&self.map, f)
- }
-}
diff --git a/compiler/rustc_middle/src/middle/region.rs b/compiler/rustc_middle/src/middle/region.rs
index f44267a..bd4e83a 100644
--- a/compiler/rustc_middle/src/middle/region.rs
+++ b/compiler/rustc_middle/src/middle/region.rs
@@ -94,6 +94,7 @@
ScopeData::CallSite => write!(fmt, "CallSite({:?})", self.id),
ScopeData::Arguments => write!(fmt, "Arguments({:?})", self.id),
ScopeData::Destruction => write!(fmt, "Destruction({:?})", self.id),
+ ScopeData::IfThen => write!(fmt, "IfThen({:?})", self.id),
ScopeData::Remainder(fsi) => write!(
fmt,
"Remainder {{ block: {:?}, first_statement_index: {}}}",
@@ -120,6 +121,10 @@
/// Scope of destructors for temporaries of node-id.
Destruction,
+ /// Scope of the condition and then block of an if expression
+ /// Used for variables introduced in an if-let expression.
+ IfThen,
+
/// Scope following a `let id = expr;` binding in a block.
Remainder(FirstStatementIndex),
}
@@ -151,7 +156,7 @@
static_assert_size!(ScopeData, 4);
impl Scope {
- /// Returns a item-local ID associated with this scope.
+ /// Returns an item-local ID associated with this scope.
///
/// N.B., likely to be replaced as API is refined; e.g., pnkfelix
/// anticipates `fn entry_node_id` and `fn each_exit_node_id`.
@@ -189,7 +194,7 @@
// To avoid issues with macro-generated spans, the span
// of the statement must be nested in that of the block.
if span.lo() <= stmt_span.lo() && stmt_span.lo() <= span.hi() {
- return Span::new(stmt_span.lo(), span.hi(), span.ctxt());
+ return span.with_lo(stmt_span.lo());
}
}
}
diff --git a/compiler/rustc_middle/src/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs
index 2804fe5..f0b4b6b 100644
--- a/compiler/rustc_middle/src/middle/stability.rs
+++ b/compiler/rustc_middle/src/middle/stability.rs
@@ -11,7 +11,7 @@
use rustc_feature::GateIssue;
use rustc_hir as hir;
use rustc_hir::def::DefKind;
-use rustc_hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX};
+use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, CRATE_DEF_INDEX};
use rustc_hir::{self, HirId};
use rustc_middle::ty::print::with_no_trimmed_paths;
use rustc_session::lint::builtin::{DEPRECATED, DEPRECATED_IN_FUTURE, SOFT_UNSTABLE};
@@ -36,12 +36,12 @@
pub attr: Deprecation,
/// The `DefId` where the attr was originally attached. `None` for non-local
/// `DefId`'s.
- origin: Option<HirId>,
+ origin: Option<LocalDefId>,
}
impl DeprecationEntry {
- pub fn local(attr: Deprecation, id: HirId) -> DeprecationEntry {
- DeprecationEntry { attr, origin: Some(id) }
+ pub fn local(attr: Deprecation, def_id: LocalDefId) -> DeprecationEntry {
+ DeprecationEntry { attr, origin: Some(def_id) }
}
pub fn external(attr: Deprecation) -> DeprecationEntry {
@@ -61,9 +61,9 @@
pub struct Index<'tcx> {
/// This is mostly a cache, except the stabilities of local items
/// are filled by the annotator.
- pub stab_map: FxHashMap<HirId, &'tcx Stability>,
- pub const_stab_map: FxHashMap<HirId, &'tcx ConstStability>,
- pub depr_map: FxHashMap<HirId, DeprecationEntry>,
+ pub stab_map: FxHashMap<LocalDefId, &'tcx Stability>,
+ pub const_stab_map: FxHashMap<LocalDefId, &'tcx ConstStability>,
+ pub depr_map: FxHashMap<LocalDefId, DeprecationEntry>,
/// Maps for each crate whether it is part of the staged API.
pub staged_api: FxHashMap<CrateNum, bool>,
@@ -73,16 +73,16 @@
}
impl<'tcx> Index<'tcx> {
- pub fn local_stability(&self, id: HirId) -> Option<&'tcx Stability> {
- self.stab_map.get(&id).cloned()
+ pub fn local_stability(&self, def_id: LocalDefId) -> Option<&'tcx Stability> {
+ self.stab_map.get(&def_id).copied()
}
- pub fn local_const_stability(&self, id: HirId) -> Option<&'tcx ConstStability> {
- self.const_stab_map.get(&id).cloned()
+ pub fn local_const_stability(&self, def_id: LocalDefId) -> Option<&'tcx ConstStability> {
+ self.const_stab_map.get(&def_id).copied()
}
- pub fn local_deprecation_entry(&self, id: HirId) -> Option<DeprecationEntry> {
- self.depr_map.get(&id).cloned()
+ pub fn local_deprecation_entry(&self, def_id: LocalDefId) -> Option<DeprecationEntry> {
+ self.depr_map.get(&def_id).cloned()
}
}
diff --git a/compiler/rustc_middle/src/mir/interpret/allocation.rs b/compiler/rustc_middle/src/mir/interpret/allocation.rs
index bbf792e..b6358f9 100644
--- a/compiler/rustc_middle/src/mir/interpret/allocation.rs
+++ b/compiler/rustc_middle/src/mir/interpret/allocation.rs
@@ -1,7 +1,7 @@
//! The virtual memory representation of the MIR interpreter.
use std::borrow::Cow;
-use std::convert::TryFrom;
+use std::convert::{TryFrom, TryInto};
use std::iter;
use std::ops::{Deref, Range};
use std::ptr;
@@ -12,7 +12,7 @@
use rustc_target::abi::{Align, HasDataLayout, Size};
use super::{
- read_target_uint, write_target_uint, AllocId, InterpError, InterpResult, Pointer,
+ read_target_uint, write_target_uint, AllocId, InterpError, InterpResult, Pointer, Provenance,
ResourceExhaustionInfo, Scalar, ScalarMaybeUninit, UndefinedBehaviorInfo, UninitBytesAccess,
UnsupportedOpInfo,
};
@@ -28,7 +28,7 @@
pub struct Allocation<Tag = AllocId, Extra = ()> {
/// The actual bytes of the allocation.
/// Note that the bytes of a pointer represent the offset of the pointer.
- bytes: Vec<u8>,
+ bytes: Box<[u8]>,
/// Maps from byte addresses to extra data for each pointer.
/// Only the first byte of a pointer is inserted into the map; i.e.,
/// every entry in this map applies to `pointer_size` consecutive bytes starting
@@ -53,6 +53,8 @@
pub enum AllocError {
/// Encountered a pointer where we needed raw bytes.
ReadPointerAsBytes,
+ /// Partially overwriting a pointer.
+ PartialPointerOverwrite(Size),
/// Using uninitialized data where it is not allowed.
InvalidUninitBytes(Option<UninitBytesAccess>),
}
@@ -60,11 +62,13 @@
impl AllocError {
pub fn to_interp_error<'tcx>(self, alloc_id: AllocId) -> InterpError<'tcx> {
+ use AllocError::*;
match self {
- AllocError::ReadPointerAsBytes => {
- InterpError::Unsupported(UnsupportedOpInfo::ReadPointerAsBytes)
- }
- AllocError::InvalidUninitBytes(info) => InterpError::UndefinedBehavior(
+ ReadPointerAsBytes => InterpError::Unsupported(UnsupportedOpInfo::ReadPointerAsBytes),
+ PartialPointerOverwrite(offset) => InterpError::Unsupported(
+ UnsupportedOpInfo::PartialPointerOverwrite(Pointer::new(alloc_id, offset)),
+ ),
+ InvalidUninitBytes(info) => InterpError::UndefinedBehavior(
UndefinedBehaviorInfo::InvalidUninitBytes(info.map(|b| (alloc_id, b))),
),
}
@@ -108,7 +112,7 @@
align: Align,
mutability: Mutability,
) -> Self {
- let bytes = slice.into().into_owned();
+ let bytes = Box::<[u8]>::from(slice.into());
let size = Size::from_bytes(bytes.len());
Self {
bytes,
@@ -127,8 +131,7 @@
/// Try to create an Allocation of `size` bytes, failing if there is not enough memory
/// available to the compiler to do so.
pub fn uninit(size: Size, align: Align, panic_on_fail: bool) -> InterpResult<'static, Self> {
- let mut bytes = Vec::new();
- bytes.try_reserve(size.bytes_usize()).map_err(|_| {
+ let bytes = Box::<[u8]>::try_new_zeroed_slice(size.bytes_usize()).map_err(|_| {
// This results in an error that can happen non-deterministically, since the memory
// available to the compiler can change between runs. Normally queries are always
// deterministic. However, we can be non-determinstic here because all uses of const
@@ -142,7 +145,8 @@
});
InterpError::ResourceExhaustion(ResourceExhaustionInfo::MemoryExhausted)
})?;
- bytes.resize(size.bytes_usize(), 0);
+ // SAFETY: the box was zero-allocated, which is a valid initial value for Box<[u8]>
+ let bytes = unsafe { bytes.assume_init() };
Ok(Allocation {
bytes,
relocations: Relocations::new(),
@@ -218,7 +222,7 @@
}
/// Byte accessors.
-impl<Tag: Copy, Extra> Allocation<Tag, Extra> {
+impl<Tag: Provenance, Extra> Allocation<Tag, Extra> {
/// The last argument controls whether we error out when there are uninitialized
/// or pointer bytes. You should never call this, call `get_bytes` or
/// `get_bytes_with_uninit_and_ptr` instead,
@@ -275,30 +279,35 @@
/// It is the caller's responsibility to check bounds and alignment beforehand.
/// Most likely, you want to use the `PlaceTy` and `OperandTy`-based methods
/// on `InterpCx` instead.
- pub fn get_bytes_mut(&mut self, cx: &impl HasDataLayout, range: AllocRange) -> &mut [u8] {
+ pub fn get_bytes_mut(
+ &mut self,
+ cx: &impl HasDataLayout,
+ range: AllocRange,
+ ) -> AllocResult<&mut [u8]> {
self.mark_init(range, true);
- self.clear_relocations(cx, range);
+ self.clear_relocations(cx, range)?;
- &mut self.bytes[range.start.bytes_usize()..range.end().bytes_usize()]
+ Ok(&mut self.bytes[range.start.bytes_usize()..range.end().bytes_usize()])
}
/// A raw pointer variant of `get_bytes_mut` that avoids invalidating existing aliases into this memory.
- pub fn get_bytes_mut_ptr(&mut self, cx: &impl HasDataLayout, range: AllocRange) -> *mut [u8] {
+ pub fn get_bytes_mut_ptr(
+ &mut self,
+ cx: &impl HasDataLayout,
+ range: AllocRange,
+ ) -> AllocResult<*mut [u8]> {
self.mark_init(range, true);
- // This also clears relocations that just overlap with the written range. So writing to some
- // byte can de-initialize its neighbors! See
- // <https://github.com/rust-lang/rust/issues/87184> for details.
- self.clear_relocations(cx, range);
+ self.clear_relocations(cx, range)?;
assert!(range.end().bytes_usize() <= self.bytes.len()); // need to do our own bounds-check
let begin_ptr = self.bytes.as_mut_ptr().wrapping_add(range.start.bytes_usize());
let len = range.end().bytes_usize() - range.start.bytes_usize();
- ptr::slice_from_raw_parts_mut(begin_ptr, len)
+ Ok(ptr::slice_from_raw_parts_mut(begin_ptr, len))
}
}
/// Reading and writing.
-impl<Tag: Copy, Extra> Allocation<Tag, Extra> {
+impl<Tag: Provenance, Extra> Allocation<Tag, Extra> {
/// Validates that `ptr.offset` and `ptr.offset + size` do not point to the middle of a
/// relocation. If `allow_uninit_and_ptr` is `false`, also enforces that the memory in the
/// given range contains neither relocations nor uninitialized bytes.
@@ -395,7 +404,7 @@
};
let endian = cx.data_layout().endian;
- let dst = self.get_bytes_mut(cx, range);
+ let dst = self.get_bytes_mut(cx, range)?;
write_target_uint(endian, dst, bytes).unwrap();
// See if we have to also write a relocation.
@@ -433,13 +442,16 @@
/// uninitialized. This is a somewhat odd "spooky action at a distance",
/// but it allows strictly more code to run than if we would just error
/// immediately in that case.
- fn clear_relocations(&mut self, cx: &impl HasDataLayout, range: AllocRange) {
+ fn clear_relocations(&mut self, cx: &impl HasDataLayout, range: AllocRange) -> AllocResult
+ where
+ Tag: Provenance,
+ {
// Find the start and end of the given range and its outermost relocations.
let (first, last) = {
// Find all relocations overlapping the given range.
let relocations = self.get_relocations(cx, range);
if relocations.is_empty() {
- return;
+ return Ok(());
}
(
@@ -450,17 +462,27 @@
let start = range.start;
let end = range.end();
- // Mark parts of the outermost relocations as uninitialized if they partially fall outside the
- // given range.
+ // We need to handle clearing the relocations from parts of a pointer. See
+ // <https://github.com/rust-lang/rust/issues/87184> for details.
if first < start {
+ if Tag::ERR_ON_PARTIAL_PTR_OVERWRITE {
+ return Err(AllocError::PartialPointerOverwrite(first));
+ }
self.init_mask.set_range(first, start, false);
}
if last > end {
+ if Tag::ERR_ON_PARTIAL_PTR_OVERWRITE {
+ return Err(AllocError::PartialPointerOverwrite(
+ last - cx.data_layout().pointer_size,
+ ));
+ }
self.init_mask.set_range(end, last, false);
}
// Forget all the relocations.
self.relocations.0.remove_range(first..last);
+
+ Ok(())
}
/// Errors if there are relocations overlapping with the edges of the
@@ -473,129 +495,6 @@
}
}
-/// Uninitialized bytes.
-impl<Tag: Copy, Extra> Allocation<Tag, Extra> {
- /// Checks whether the given range is entirely initialized.
- ///
- /// Returns `Ok(())` if it's initialized. Otherwise returns the range of byte
- /// indexes of the first contiguous uninitialized access.
- fn is_init(&self, range: AllocRange) -> Result<(), Range<Size>> {
- self.init_mask.is_range_initialized(range.start, range.end()) // `Size` addition
- }
-
- /// Checks that a range of bytes is initialized. If not, returns the `InvalidUninitBytes`
- /// error which will report the first range of bytes which is uninitialized.
- fn check_init(&self, range: AllocRange) -> AllocResult {
- self.is_init(range).or_else(|idx_range| {
- Err(AllocError::InvalidUninitBytes(Some(UninitBytesAccess {
- access_offset: range.start,
- access_size: range.size,
- uninit_offset: idx_range.start,
- uninit_size: idx_range.end - idx_range.start, // `Size` subtraction
- })))
- })
- }
-
- pub fn mark_init(&mut self, range: AllocRange, is_init: bool) {
- if range.size.bytes() == 0 {
- return;
- }
- assert!(self.mutability == Mutability::Mut);
- self.init_mask.set_range(range.start, range.end(), is_init);
- }
-}
-
-/// Run-length encoding of the uninit mask.
-/// Used to copy parts of a mask multiple times to another allocation.
-pub struct InitMaskCompressed {
- /// Whether the first range is initialized.
- initial: bool,
- /// The lengths of ranges that are run-length encoded.
- /// The initialization state of the ranges alternate starting with `initial`.
- ranges: smallvec::SmallVec<[u64; 1]>,
-}
-
-impl InitMaskCompressed {
- pub fn no_bytes_init(&self) -> bool {
- // The `ranges` are run-length encoded and of alternating initialization state.
- // So if `ranges.len() > 1` then the second block is an initialized range.
- !self.initial && self.ranges.len() == 1
- }
-}
-
-/// Transferring the initialization mask to other allocations.
-impl<Tag, Extra> Allocation<Tag, Extra> {
- /// Creates a run-length encoding of the initialization mask.
- pub fn compress_uninit_range(&self, range: AllocRange) -> InitMaskCompressed {
- // Since we are copying `size` bytes from `src` to `dest + i * size` (`for i in 0..repeat`),
- // a naive initialization mask copying algorithm would repeatedly have to read the initialization mask from
- // the source and write it to the destination. Even if we optimized the memory accesses,
- // we'd be doing all of this `repeat` times.
- // Therefore we precompute a compressed version of the initialization mask of the source value and
- // then write it back `repeat` times without computing any more information from the source.
-
- // A precomputed cache for ranges of initialized / uninitialized bits
- // 0000010010001110 will become
- // `[5, 1, 2, 1, 3, 3, 1]`,
- // where each element toggles the state.
-
- let mut ranges = smallvec::SmallVec::<[u64; 1]>::new();
- let initial = self.init_mask.get(range.start);
- let mut cur_len = 1;
- let mut cur = initial;
-
- for i in 1..range.size.bytes() {
- // FIXME: optimize to bitshift the current uninitialized block's bits and read the top bit.
- if self.init_mask.get(range.start + Size::from_bytes(i)) == cur {
- cur_len += 1;
- } else {
- ranges.push(cur_len);
- cur_len = 1;
- cur = !cur;
- }
- }
-
- ranges.push(cur_len);
-
- InitMaskCompressed { ranges, initial }
- }
-
- /// Applies multiple instances of the run-length encoding to the initialization mask.
- pub fn mark_compressed_init_range(
- &mut self,
- defined: &InitMaskCompressed,
- range: AllocRange,
- repeat: u64,
- ) {
- // An optimization where we can just overwrite an entire range of initialization
- // bits if they are going to be uniformly `1` or `0`.
- if defined.ranges.len() <= 1 {
- self.init_mask.set_range_inbounds(
- range.start,
- range.start + range.size * repeat, // `Size` operations
- defined.initial,
- );
- return;
- }
-
- for mut j in 0..repeat {
- j *= range.size.bytes();
- j += range.start.bytes();
- let mut cur = defined.initial;
- for range in &defined.ranges {
- let old_j = j;
- j += range;
- self.init_mask.set_range_inbounds(
- Size::from_bytes(old_j),
- Size::from_bytes(j),
- cur,
- );
- cur = !cur;
- }
- }
- }
-}
-
/// "Relocations" stores the provenance information of pointers stored in memory.
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, TyEncodable, TyDecodable)]
pub struct Relocations<Tag = AllocId>(SortedMap<Size, Tag>);
@@ -682,37 +581,30 @@
impl InitMask {
pub const BLOCK_SIZE: u64 = 64;
+ #[inline]
+ fn bit_index(bits: Size) -> (usize, usize) {
+ // BLOCK_SIZE is the number of bits that can fit in a `Block`.
+ // Each bit in a `Block` represents the initialization state of one byte of an allocation,
+ // so we use `.bytes()` here.
+ let bits = bits.bytes();
+ let a = bits / InitMask::BLOCK_SIZE;
+ let b = bits % InitMask::BLOCK_SIZE;
+ (usize::try_from(a).unwrap(), usize::try_from(b).unwrap())
+ }
+
+ #[inline]
+ fn size_from_bit_index(block: impl TryInto<u64>, bit: impl TryInto<u64>) -> Size {
+ let block = block.try_into().ok().unwrap();
+ let bit = bit.try_into().ok().unwrap();
+ Size::from_bytes(block * InitMask::BLOCK_SIZE + bit)
+ }
+
pub fn new(size: Size, state: bool) -> Self {
let mut m = InitMask { blocks: vec![], len: Size::ZERO };
m.grow(size, state);
m
}
- /// Checks whether the range `start..end` (end-exclusive) is entirely initialized.
- ///
- /// Returns `Ok(())` if it's initialized. Otherwise returns a range of byte
- /// indexes for the first contiguous span of the uninitialized access.
- #[inline]
- pub fn is_range_initialized(&self, start: Size, end: Size) -> Result<(), Range<Size>> {
- if end > self.len {
- return Err(self.len..end);
- }
-
- // FIXME(oli-obk): optimize this for allocations larger than a block.
- let idx = (start.bytes()..end.bytes()).map(Size::from_bytes).find(|&i| !self.get(i));
-
- match idx {
- Some(idx) => {
- let uninit_end = (idx.bytes()..end.bytes())
- .map(Size::from_bytes)
- .find(|&i| self.get(i))
- .unwrap_or(end);
- Err(idx..uninit_end)
- }
- None => Ok(()),
- }
- }
-
pub fn set_range(&mut self, start: Size, end: Size, new_state: bool) {
let len = self.len;
if end > len {
@@ -722,8 +614,8 @@
}
pub fn set_range_inbounds(&mut self, start: Size, end: Size, new_state: bool) {
- let (blocka, bita) = bit_index(start);
- let (blockb, bitb) = bit_index(end);
+ let (blocka, bita) = Self::bit_index(start);
+ let (blockb, bitb) = Self::bit_index(end);
if blocka == blockb {
// First set all bits except the first `bita`,
// then unset the last `64 - bitb` bits.
@@ -767,13 +659,13 @@
#[inline]
pub fn get(&self, i: Size) -> bool {
- let (block, bit) = bit_index(i);
+ let (block, bit) = Self::bit_index(i);
(self.blocks[block] & (1 << bit)) != 0
}
#[inline]
pub fn set(&mut self, i: Size, new_state: bool) {
- let (block, bit) = bit_index(i);
+ let (block, bit) = Self::bit_index(i);
self.set_bit(block, bit, new_state);
}
@@ -803,12 +695,418 @@
self.len += amount;
self.set_range_inbounds(start, start + amount, new_state); // `Size` operation
}
+
+ /// Returns the index of the first bit in `start..end` (end-exclusive) that is equal to is_init.
+ fn find_bit(&self, start: Size, end: Size, is_init: bool) -> Option<Size> {
+ /// A fast implementation of `find_bit`,
+ /// which skips over an entire block at a time if it's all 0s (resp. 1s),
+ /// and finds the first 1 (resp. 0) bit inside a block using `trailing_zeros` instead of a loop.
+ ///
+ /// Note that all examples below are written with 8 (instead of 64) bit blocks for simplicity,
+ /// and with the least significant bit (and lowest block) first:
+ ///
+ /// 00000000|00000000
+ /// ^ ^ ^ ^
+ /// index: 0 7 8 15
+ ///
+ /// Also, if not stated, assume that `is_init = true`, that is, we are searching for the first 1 bit.
+ fn find_bit_fast(
+ init_mask: &InitMask,
+ start: Size,
+ end: Size,
+ is_init: bool,
+ ) -> Option<Size> {
+ /// Search one block, returning the index of the first bit equal to `is_init`.
+ fn search_block(
+ bits: Block,
+ block: usize,
+ start_bit: usize,
+ is_init: bool,
+ ) -> Option<Size> {
+ // For the following examples, assume this function was called with:
+ // bits = 0b00111011
+ // start_bit = 3
+ // is_init = false
+ // Note that, for the examples in this function, the most significant bit is written first,
+ // which is backwards compared to the comments in `find_bit`/`find_bit_fast`.
+
+ // Invert bits so we're always looking for the first set bit.
+ // ! 0b00111011
+ // bits = 0b11000100
+ let bits = if is_init { bits } else { !bits };
+ // Mask off unused start bits.
+ // 0b11000100
+ // & 0b11111000
+ // bits = 0b11000000
+ let bits = bits & (!0 << start_bit);
+ // Find set bit, if any.
+ // bit = trailing_zeros(0b11000000)
+ // bit = 6
+ if bits == 0 {
+ None
+ } else {
+ let bit = bits.trailing_zeros();
+ Some(InitMask::size_from_bit_index(block, bit))
+ }
+ }
+
+ if start >= end {
+ return None;
+ }
+
+ // Convert `start` and `end` to block indexes and bit indexes within each block.
+ // We must convert `end` to an inclusive bound to handle block boundaries correctly.
+ //
+ // For example:
+ //
+ // (a) 00000000|00000000 (b) 00000000|
+ // ^~~~~~~~~~~^ ^~~~~~~~~^
+ // start end start end
+ //
+ // In both cases, the block index of `end` is 1.
+ // But we do want to search block 1 in (a), and we don't in (b).
+ //
+ // We subtract 1 from both end positions to make them inclusive:
+ //
+ // (a) 00000000|00000000 (b) 00000000|
+ // ^~~~~~~~~~^ ^~~~~~~^
+ // start end_inclusive start end_inclusive
+ //
+ // For (a), the block index of `end_inclusive` is 1, and for (b), it's 0.
+ // This provides the desired behavior of searching blocks 0 and 1 for (a),
+ // and searching only block 0 for (b).
+ // There is no concern of overflows since we checked for `start >= end` above.
+ let (start_block, start_bit) = InitMask::bit_index(start);
+ let end_inclusive = Size::from_bytes(end.bytes() - 1);
+ let (end_block_inclusive, _) = InitMask::bit_index(end_inclusive);
+
+ // Handle first block: need to skip `start_bit` bits.
+ //
+ // We need to handle the first block separately,
+ // because there may be bits earlier in the block that should be ignored,
+ // such as the bit marked (1) in this example:
+ //
+ // (1)
+ // -|------
+ // (c) 01000000|00000000|00000001
+ // ^~~~~~~~~~~~~~~~~~^
+ // start end
+ if let Some(i) =
+ search_block(init_mask.blocks[start_block], start_block, start_bit, is_init)
+ {
+ // If the range is less than a block, we may find a matching bit after `end`.
+ //
+ // For example, we shouldn't successfully find bit (2), because it's after `end`:
+ //
+ // (2)
+ // -------|
+ // (d) 00000001|00000000|00000001
+ // ^~~~~^
+ // start end
+ //
+ // An alternative would be to mask off end bits in the same way as we do for start bits,
+ // but performing this check afterwards is faster and simpler to implement.
+ if i < end {
+ return Some(i);
+ } else {
+ return None;
+ }
+ }
+
+ // Handle remaining blocks.
+ //
+ // We can skip over an entire block at once if it's all 0s (resp. 1s).
+ // The block marked (3) in this example is the first block that will be handled by this loop,
+ // and it will be skipped for that reason:
+ //
+ // (3)
+ // --------
+ // (e) 01000000|00000000|00000001
+ // ^~~~~~~~~~~~~~~~~~^
+ // start end
+ if start_block < end_block_inclusive {
+ // This loop is written in a specific way for performance.
+ // Notably: `..end_block_inclusive + 1` is used for an inclusive range instead of `..=end_block_inclusive`,
+ // and `.zip(start_block + 1..)` is used to track the index instead of `.enumerate().skip().take()`,
+ // because both alternatives result in significantly worse codegen.
+ // `end_block_inclusive + 1` is guaranteed not to wrap, because `end_block_inclusive <= end / BLOCK_SIZE`,
+ // and `BLOCK_SIZE` (the number of bits per block) will always be at least 8 (1 byte).
+ for (&bits, block) in init_mask.blocks[start_block + 1..end_block_inclusive + 1]
+ .iter()
+ .zip(start_block + 1..)
+ {
+ if let Some(i) = search_block(bits, block, 0, is_init) {
+ // If this is the last block, we may find a matching bit after `end`.
+ //
+ // For example, we shouldn't successfully find bit (4), because it's after `end`:
+ //
+ // (4)
+ // -------|
+ // (f) 00000001|00000000|00000001
+ // ^~~~~~~~~~~~~~~~~~^
+ // start end
+ //
+ // As above with example (d), we could handle the end block separately and mask off end bits,
+ // but unconditionally searching an entire block at once and performing this check afterwards
+ // is faster and much simpler to implement.
+ if i < end {
+ return Some(i);
+ } else {
+ return None;
+ }
+ }
+ }
+ }
+
+ None
+ }
+
+ #[cfg_attr(not(debug_assertions), allow(dead_code))]
+ fn find_bit_slow(
+ init_mask: &InitMask,
+ start: Size,
+ end: Size,
+ is_init: bool,
+ ) -> Option<Size> {
+ (start..end).find(|&i| init_mask.get(i) == is_init)
+ }
+
+ let result = find_bit_fast(self, start, end, is_init);
+
+ debug_assert_eq!(
+ result,
+ find_bit_slow(self, start, end, is_init),
+ "optimized implementation of find_bit is wrong for start={:?} end={:?} is_init={} init_mask={:#?}",
+ start,
+ end,
+ is_init,
+ self
+ );
+
+ result
+ }
}
-#[inline]
-fn bit_index(bits: Size) -> (usize, usize) {
- let bits = bits.bytes();
- let a = bits / InitMask::BLOCK_SIZE;
- let b = bits % InitMask::BLOCK_SIZE;
- (usize::try_from(a).unwrap(), usize::try_from(b).unwrap())
+/// A contiguous chunk of initialized or uninitialized memory.
+pub enum InitChunk {
+ Init(Range<Size>),
+ Uninit(Range<Size>),
+}
+
+impl InitChunk {
+ #[inline]
+ pub fn is_init(&self) -> bool {
+ match self {
+ Self::Init(_) => true,
+ Self::Uninit(_) => false,
+ }
+ }
+
+ #[inline]
+ pub fn range(&self) -> Range<Size> {
+ match self {
+ Self::Init(r) => r.clone(),
+ Self::Uninit(r) => r.clone(),
+ }
+ }
+}
+
+impl InitMask {
+ /// Checks whether the range `start..end` (end-exclusive) is entirely initialized.
+ ///
+ /// Returns `Ok(())` if it's initialized. Otherwise returns a range of byte
+ /// indexes for the first contiguous span of the uninitialized access.
+ #[inline]
+ pub fn is_range_initialized(&self, start: Size, end: Size) -> Result<(), Range<Size>> {
+ if end > self.len {
+ return Err(self.len..end);
+ }
+
+ let uninit_start = self.find_bit(start, end, false);
+
+ match uninit_start {
+ Some(uninit_start) => {
+ let uninit_end = self.find_bit(uninit_start, end, true).unwrap_or(end);
+ Err(uninit_start..uninit_end)
+ }
+ None => Ok(()),
+ }
+ }
+
+ /// Returns an iterator, yielding a range of byte indexes for each contiguous region
+ /// of initialized or uninitialized bytes inside the range `start..end` (end-exclusive).
+ ///
+ /// The iterator guarantees the following:
+ /// - Chunks are nonempty.
+ /// - Chunks are adjacent (each range's start is equal to the previous range's end).
+ /// - Chunks span exactly `start..end` (the first starts at `start`, the last ends at `end`).
+ /// - Chunks alternate between [`InitChunk::Init`] and [`InitChunk::Uninit`].
+ #[inline]
+ pub fn range_as_init_chunks(&self, start: Size, end: Size) -> InitChunkIter<'_> {
+ assert!(end <= self.len);
+
+ let is_init = if start < end {
+ self.get(start)
+ } else {
+ // `start..end` is empty: there are no chunks, so use some arbitrary value
+ false
+ };
+
+ InitChunkIter { init_mask: self, is_init, start, end }
+ }
+}
+
+/// Yields [`InitChunk`]s. See [`InitMask::range_as_init_chunks`].
+pub struct InitChunkIter<'a> {
+ init_mask: &'a InitMask,
+ /// Whether the next chunk we will return is initialized.
+ /// If there are no more chunks, contains some arbitrary value.
+ is_init: bool,
+ /// The current byte index into `init_mask`.
+ start: Size,
+ /// The end byte index into `init_mask`.
+ end: Size,
+}
+
+impl<'a> Iterator for InitChunkIter<'a> {
+ type Item = InitChunk;
+
+ #[inline]
+ fn next(&mut self) -> Option<Self::Item> {
+ if self.start >= self.end {
+ return None;
+ }
+
+ let end_of_chunk =
+ self.init_mask.find_bit(self.start, self.end, !self.is_init).unwrap_or(self.end);
+ let range = self.start..end_of_chunk;
+
+ let ret =
+ Some(if self.is_init { InitChunk::Init(range) } else { InitChunk::Uninit(range) });
+
+ self.is_init = !self.is_init;
+ self.start = end_of_chunk;
+
+ ret
+ }
+}
+
+/// Uninitialized bytes.
+impl<Tag: Copy, Extra> Allocation<Tag, Extra> {
+ /// Checks whether the given range is entirely initialized.
+ ///
+ /// Returns `Ok(())` if it's initialized. Otherwise returns the range of byte
+ /// indexes of the first contiguous uninitialized access.
+ fn is_init(&self, range: AllocRange) -> Result<(), Range<Size>> {
+ self.init_mask.is_range_initialized(range.start, range.end()) // `Size` addition
+ }
+
+ /// Checks that a range of bytes is initialized. If not, returns the `InvalidUninitBytes`
+ /// error which will report the first range of bytes which is uninitialized.
+ fn check_init(&self, range: AllocRange) -> AllocResult {
+ self.is_init(range).or_else(|idx_range| {
+ Err(AllocError::InvalidUninitBytes(Some(UninitBytesAccess {
+ access_offset: range.start,
+ access_size: range.size,
+ uninit_offset: idx_range.start,
+ uninit_size: idx_range.end - idx_range.start, // `Size` subtraction
+ })))
+ })
+ }
+
+ pub fn mark_init(&mut self, range: AllocRange, is_init: bool) {
+ if range.size.bytes() == 0 {
+ return;
+ }
+ assert!(self.mutability == Mutability::Mut);
+ self.init_mask.set_range(range.start, range.end(), is_init);
+ }
+}
+
+/// Run-length encoding of the uninit mask.
+/// Used to copy parts of a mask multiple times to another allocation.
+pub struct InitMaskCompressed {
+ /// Whether the first range is initialized.
+ initial: bool,
+ /// The lengths of ranges that are run-length encoded.
+ /// The initialization state of the ranges alternate starting with `initial`.
+ ranges: smallvec::SmallVec<[u64; 1]>,
+}
+
+impl InitMaskCompressed {
+ pub fn no_bytes_init(&self) -> bool {
+ // The `ranges` are run-length encoded and of alternating initialization state.
+ // So if `ranges.len() > 1` then the second block is an initialized range.
+ !self.initial && self.ranges.len() == 1
+ }
+}
+
+/// Transferring the initialization mask to other allocations.
+impl<Tag, Extra> Allocation<Tag, Extra> {
+ /// Creates a run-length encoding of the initialization mask; panics if range is empty.
+ ///
+ /// This is essentially a more space-efficient version of
+ /// `InitMask::range_as_init_chunks(...).collect::<Vec<_>>()`.
+ pub fn compress_uninit_range(&self, range: AllocRange) -> InitMaskCompressed {
+ // Since we are copying `size` bytes from `src` to `dest + i * size` (`for i in 0..repeat`),
+ // a naive initialization mask copying algorithm would repeatedly have to read the initialization mask from
+ // the source and write it to the destination. Even if we optimized the memory accesses,
+ // we'd be doing all of this `repeat` times.
+ // Therefore we precompute a compressed version of the initialization mask of the source value and
+ // then write it back `repeat` times without computing any more information from the source.
+
+ // A precomputed cache for ranges of initialized / uninitialized bits
+ // 0000010010001110 will become
+ // `[5, 1, 2, 1, 3, 3, 1]`,
+ // where each element toggles the state.
+
+ let mut ranges = smallvec::SmallVec::<[u64; 1]>::new();
+
+ let mut chunks = self.init_mask.range_as_init_chunks(range.start, range.end()).peekable();
+
+ let initial = chunks.peek().expect("range should be nonempty").is_init();
+
+ // Here we rely on `range_as_init_chunks` to yield alternating init/uninit chunks.
+ for chunk in chunks {
+ let len = chunk.range().end.bytes() - chunk.range().start.bytes();
+ ranges.push(len);
+ }
+
+ InitMaskCompressed { ranges, initial }
+ }
+
+ /// Applies multiple instances of the run-length encoding to the initialization mask.
+ pub fn mark_compressed_init_range(
+ &mut self,
+ defined: &InitMaskCompressed,
+ range: AllocRange,
+ repeat: u64,
+ ) {
+ // An optimization where we can just overwrite an entire range of initialization
+ // bits if they are going to be uniformly `1` or `0`.
+ if defined.ranges.len() <= 1 {
+ self.init_mask.set_range_inbounds(
+ range.start,
+ range.start + range.size * repeat, // `Size` operations
+ defined.initial,
+ );
+ return;
+ }
+
+ for mut j in 0..repeat {
+ j *= range.size.bytes();
+ j += range.start.bytes();
+ let mut cur = defined.initial;
+ for range in &defined.ranges {
+ let old_j = j;
+ j += range;
+ self.init_mask.set_range_inbounds(
+ Size::from_bytes(old_j),
+ Size::from_bytes(j),
+ cur,
+ );
+ cur = !cur;
+ }
+ }
+ }
}
diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs
index 94ac303..5d17bb9 100644
--- a/compiler/rustc_middle/src/mir/interpret/error.rs
+++ b/compiler/rustc_middle/src/mir/interpret/error.rs
@@ -46,7 +46,7 @@
/// Packages the kind of error we got from the const code interpreter
/// up with a Rust-level backtrace of where the error occurred.
/// These should always be constructed by calling `.into()` on
-/// a `InterpError`. In `rustc_mir::interpret`, we have `throw_err_*`
+/// an `InterpError`. In `rustc_mir::interpret`, we have `throw_err_*`
/// macros for this.
#[derive(Debug)]
pub struct InterpErrorInfo<'tcx>(Box<InterpErrorInfoInner<'tcx>>);
@@ -402,10 +402,11 @@
pub enum UnsupportedOpInfo {
/// Free-form case. Only for errors that are never caught!
Unsupported(String),
- /// Could not find MIR for a function.
- NoMirFor(DefId),
/// Encountered a pointer where we needed raw bytes.
ReadPointerAsBytes,
+ /// Overwriting parts of a pointer; the resulting state cannot be represented in our
+ /// `Allocation` data structure.
+ PartialPointerOverwrite(Pointer<AllocId>),
//
// The variants below are only reachable from CTFE/const prop, miri will never emit them.
//
@@ -420,10 +421,12 @@
use UnsupportedOpInfo::*;
match self {
Unsupported(ref msg) => write!(f, "{}", msg),
- ReadExternStatic(did) => write!(f, "cannot read from extern static ({:?})", did),
- NoMirFor(did) => write!(f, "no MIR body is available for {:?}", did),
- ReadPointerAsBytes => write!(f, "unable to turn pointer into raw bytes",),
+ ReadPointerAsBytes => write!(f, "unable to turn pointer into raw bytes"),
+ PartialPointerOverwrite(ptr) => {
+ write!(f, "unable to overwrite parts of a pointer in memory at {:?}", ptr)
+ }
ThreadLocalStatic(did) => write!(f, "cannot access thread local static ({:?})", did),
+ ReadExternStatic(did) => write!(f, "cannot read from extern static ({:?})", did),
}
}
}
diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs
index dd9ac7f..4628c24 100644
--- a/compiler/rustc_middle/src/mir/interpret/mod.rs
+++ b/compiler/rustc_middle/src/mir/interpret/mod.rs
@@ -125,7 +125,9 @@
pub use self::value::{get_slice_bytes, ConstAlloc, ConstValue, Scalar, ScalarMaybeUninit};
-pub use self::allocation::{alloc_range, AllocRange, Allocation, InitMask, Relocations};
+pub use self::allocation::{
+ alloc_range, AllocRange, Allocation, InitChunk, InitChunkIter, InitMask, Relocations,
+};
pub use self::pointer::{Pointer, PointerArithmetic, Provenance};
diff --git a/compiler/rustc_middle/src/mir/interpret/pointer.rs b/compiler/rustc_middle/src/mir/interpret/pointer.rs
index 568b3f2..3eee45a 100644
--- a/compiler/rustc_middle/src/mir/interpret/pointer.rs
+++ b/compiler/rustc_middle/src/mir/interpret/pointer.rs
@@ -108,6 +108,10 @@
/// If `false`, ptr-to-int casts are not supported. The offset *must* be relative in that case.
const OFFSET_IS_ADDR: bool;
+ /// We also use this trait to control whether to abort execution when a pointer is being partially overwritten
+ /// (this avoids a separate trait in `allocation.rs` just for this purpose).
+ const ERR_ON_PARTIAL_PTR_OVERWRITE: bool;
+
/// Determines how a pointer should be printed.
fn fmt(ptr: &Pointer<Self>, f: &mut fmt::Formatter<'_>) -> fmt::Result
where
@@ -123,6 +127,9 @@
// so ptr-to-int casts are not possible (since we do not know the global physical offset).
const OFFSET_IS_ADDR: bool = false;
+ // For now, do not allow this, so that we keep our options open.
+ const ERR_ON_PARTIAL_PTR_OVERWRITE: bool = true;
+
fn fmt(ptr: &Pointer<Self>, f: &mut fmt::Formatter<'_>) -> fmt::Result {
// Forward `alternate` flag to `alloc_id` printing.
if f.alternate() {
diff --git a/compiler/rustc_middle/src/mir/interpret/queries.rs b/compiler/rustc_middle/src/mir/interpret/queries.rs
index fa7c067..c63613a 100644
--- a/compiler/rustc_middle/src/mir/interpret/queries.rs
+++ b/compiler/rustc_middle/src/mir/interpret/queries.rs
@@ -38,7 +38,7 @@
ct: ty::Unevaluated<'tcx>,
span: Option<Span>,
) -> EvalToConstValueResult<'tcx> {
- match ty::Instance::resolve_opt_const_arg(self, param_env, ct.def, ct.substs) {
+ match ty::Instance::resolve_opt_const_arg(self, param_env, ct.def, ct.substs(self)) {
Ok(Some(instance)) => {
let cid = GlobalId { instance, promoted: ct.promoted };
self.const_eval_global_id(param_env, cid, span)
diff --git a/compiler/rustc_middle/src/mir/interpret/value.rs b/compiler/rustc_middle/src/mir/interpret/value.rs
index 62b71b1..cc31d8c 100644
--- a/compiler/rustc_middle/src/mir/interpret/value.rs
+++ b/compiler/rustc_middle/src/mir/interpret/value.rs
@@ -17,7 +17,7 @@
/// Represents the result of const evaluation via the `eval_to_allocation` query.
#[derive(Copy, Clone, HashStable, TyEncodable, TyDecodable, Debug, Hash, Eq, PartialEq)]
pub struct ConstAlloc<'tcx> {
- // the value lives here, at offset 0, and that allocation definitely is a `AllocKind::Memory`
+ // the value lives here, at offset 0, and that allocation definitely is an `AllocKind::Memory`
// (so you can use `AllocMap::unwrap_memory`).
pub alloc_id: AllocId,
pub ty: Ty<'tcx>,
@@ -113,7 +113,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 16 bytes in
+/// `memory::Allocation`. It is in many ways like a small chunk of an `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`
///
@@ -376,27 +376,27 @@
self.to_bits(sz)
}
- /// Converts the scalar to produce an `u8`. Fails if the scalar is a pointer.
+ /// Converts the scalar to produce a `u8`. Fails if the scalar is a pointer.
pub fn to_u8(self) -> InterpResult<'static, u8> {
self.to_unsigned_with_bit_width(8).map(|v| u8::try_from(v).unwrap())
}
- /// Converts the scalar to produce an `u16`. Fails if the scalar is a pointer.
+ /// Converts the scalar to produce a `u16`. Fails if the scalar is a pointer.
pub fn to_u16(self) -> InterpResult<'static, u16> {
self.to_unsigned_with_bit_width(16).map(|v| u16::try_from(v).unwrap())
}
- /// Converts the scalar to produce an `u32`. Fails if the scalar is a pointer.
+ /// Converts the scalar to produce a `u32`. Fails if the scalar is a pointer.
pub fn to_u32(self) -> InterpResult<'static, u32> {
self.to_unsigned_with_bit_width(32).map(|v| u32::try_from(v).unwrap())
}
- /// Converts the scalar to produce an `u64`. Fails if the scalar is a pointer.
+ /// Converts the scalar to produce a `u64`. Fails if the scalar is a pointer.
pub fn to_u64(self) -> InterpResult<'static, u64> {
self.to_unsigned_with_bit_width(64).map(|v| u64::try_from(v).unwrap())
}
- /// Converts the scalar to produce an `u128`. Fails if the scalar is a pointer.
+ /// Converts the scalar to produce a `u128`. Fails if the scalar is a pointer.
pub fn to_u128(self) -> InterpResult<'static, u128> {
self.to_unsigned_with_bit_width(128)
}
diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs
index da0d257..83f6e79 100644
--- a/compiler/rustc_middle/src/mir/mod.rs
+++ b/compiler/rustc_middle/src/mir/mod.rs
@@ -242,6 +242,7 @@
impl<'tcx> Body<'tcx> {
pub fn new(
+ tcx: TyCtxt<'tcx>,
source: MirSource<'tcx>,
basic_blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>,
source_scopes: IndexVec<SourceScope, SourceScopeData<'tcx>>,
@@ -284,7 +285,7 @@
predecessor_cache: PredecessorCache::new(),
is_cyclic: GraphIsCyclicCache::new(),
};
- body.is_polymorphic = body.has_param_types_or_consts();
+ body.is_polymorphic = body.definitely_has_param_types_or_consts(tcx);
body
}
@@ -294,7 +295,7 @@
/// is only useful for testing but cannot be `#[cfg(test)]` because it is used in a different
/// crate.
pub fn new_cfg_only(basic_blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>) -> Self {
- let mut body = Body {
+ Body {
phase: MirPhase::Build,
source: MirSource::item(DefId::local(CRATE_DEF_INDEX)),
basic_blocks,
@@ -310,9 +311,7 @@
is_polymorphic: false,
predecessor_cache: PredecessorCache::new(),
is_cyclic: GraphIsCyclicCache::new(),
- };
- body.is_polymorphic = body.has_param_types_or_consts();
- body
+ }
}
#[inline]
@@ -412,8 +411,7 @@
/// Returns an iterator over all function arguments.
#[inline]
pub fn args_iter(&self) -> impl Iterator<Item = Local> + ExactSizeIterator {
- let arg_count = self.arg_count;
- (1..arg_count + 1).map(Local::new)
+ (1..self.arg_count + 1).map(Local::new)
}
/// Returns an iterator over all user-defined variables and compiler-generated temporaries (all
@@ -422,9 +420,12 @@
pub fn vars_and_temps_iter(
&self,
) -> impl DoubleEndedIterator<Item = Local> + ExactSizeIterator {
- let arg_count = self.arg_count;
- let local_count = self.local_decls.len();
- (arg_count + 1..local_count).map(Local::new)
+ (self.arg_count + 1..self.local_decls.len()).map(Local::new)
+ }
+
+ #[inline]
+ pub fn drain_vars_and_temps<'a>(&'a mut self) -> impl Iterator<Item = LocalDecl<'tcx>> + 'a {
+ self.local_decls.drain(self.arg_count + 1..)
}
/// Changes a statement to a nop. This is both faster than deleting instructions and avoids
@@ -1664,13 +1665,10 @@
AscribeUserType(box (ref place, ref c_ty), ref variance) => {
write!(fmt, "AscribeUserType({:?}, {:?}, {:?})", place, variance, c_ty)
}
- Coverage(box ref coverage) => {
- if let Some(rgn) = &coverage.code_region {
- write!(fmt, "Coverage::{:?} for {:?}", coverage.kind, rgn)
- } else {
- write!(fmt, "Coverage::{:?}", coverage.kind)
- }
+ Coverage(box self::Coverage { ref kind, code_region: Some(ref rgn) }) => {
+ write!(fmt, "Coverage::{:?} for {:?}", kind, rgn)
}
+ Coverage(box ref coverage) => write!(fmt, "Coverage::{:?}", coverage.kind),
CopyNonOverlapping(box crate::mir::CopyNonOverlapping {
ref src,
ref dst,
@@ -2061,11 +2059,11 @@
span: Span,
) -> Self {
let ty = tcx.type_of(def_id).subst(tcx, substs);
- Operand::Constant(box Constant {
+ Operand::Constant(Box::new(Constant {
span,
user_ty: None,
literal: ConstantKind::Ty(ty::Const::zero_sized(tcx, ty)),
- })
+ }))
}
pub fn is_move(&self) -> bool {
@@ -2092,11 +2090,11 @@
};
scalar_size == type_size
});
- Operand::Constant(box Constant {
+ Operand::Constant(Box::new(Constant {
span,
user_ty: None,
literal: ConstantKind::Val(ConstValue::Scalar(val), ty),
- })
+ }))
}
pub fn to_copy(&self) -> Self {
diff --git a/compiler/rustc_middle/src/mir/tcx.rs b/compiler/rustc_middle/src/mir/tcx.rs
index 6e81914..74d303c 100644
--- a/compiler/rustc_middle/src/mir/tcx.rs
+++ b/compiler/rustc_middle/src/mir/tcx.rs
@@ -265,7 +265,7 @@
BorrowKind::Shared => hir::Mutability::Not,
// We have no type corresponding to a unique imm borrow, so
- // use `&mut`. It gives all the capabilities of an `&uniq`
+ // use `&mut`. It gives all the capabilities of a `&uniq`
// and hence is a safe "over approximation".
BorrowKind::Unique => hir::Mutability::Mut,
diff --git a/compiler/rustc_middle/src/mir/terminator.rs b/compiler/rustc_middle/src/mir/terminator.rs
index c8db4ae..e78b6fd 100644
--- a/compiler/rustc_middle/src/mir/terminator.rs
+++ b/compiler/rustc_middle/src/mir/terminator.rs
@@ -237,7 +237,7 @@
/// consider it in borrowck. We don't want to accept programs which
/// pass borrowck only when `panic=abort` or some assertions are disabled
/// due to release vs. debug mode builds. This needs to be an `Option` because
- /// of the `remove_noop_landing_pads` and `no_landing_pads` passes.
+ /// of the `remove_noop_landing_pads` and `abort_unwinding_calls` passes.
unwind: Option<BasicBlock>,
},
diff --git a/compiler/rustc_middle/src/mir/type_foldable.rs b/compiler/rustc_middle/src/mir/type_foldable.rs
index f3124e5b..b2d4a22 100644
--- a/compiler/rustc_middle/src/mir/type_foldable.rs
+++ b/compiler/rustc_middle/src/mir/type_foldable.rs
@@ -182,10 +182,10 @@
Len(place) => Len(place.fold_with(folder)),
Cast(kind, op, ty) => Cast(kind, op.fold_with(folder), ty.fold_with(folder)),
BinaryOp(op, box (rhs, lhs)) => {
- BinaryOp(op, box (rhs.fold_with(folder), lhs.fold_with(folder)))
+ BinaryOp(op, Box::new((rhs.fold_with(folder), lhs.fold_with(folder))))
}
CheckedBinaryOp(op, box (rhs, lhs)) => {
- CheckedBinaryOp(op, box (rhs.fold_with(folder), lhs.fold_with(folder)))
+ CheckedBinaryOp(op, Box::new((rhs.fold_with(folder), lhs.fold_with(folder))))
}
UnaryOp(op, val) => UnaryOp(op, val.fold_with(folder)),
Discriminant(place) => Discriminant(place.fold_with(folder)),
diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs
index 5516a04..af7f779 100644
--- a/compiler/rustc_middle/src/mir/visit.rs
+++ b/compiler/rustc_middle/src/mir/visit.rs
@@ -587,14 +587,12 @@
InlineAsmOperand::In { value, .. } => {
self.visit_operand(value, location);
}
- InlineAsmOperand::Out { place, .. } => {
- if let Some(place) = place {
- self.visit_place(
- place,
- PlaceContext::MutatingUse(MutatingUseContext::Store),
- location,
- );
- }
+ InlineAsmOperand::Out { place: Some(place), .. } => {
+ self.visit_place(
+ place,
+ PlaceContext::MutatingUse(MutatingUseContext::Store),
+ location,
+ );
}
InlineAsmOperand::InOut { in_value, out_place, .. } => {
self.visit_operand(in_value, location);
@@ -610,7 +608,8 @@
| InlineAsmOperand::SymFn { value } => {
self.visit_constant(value, location);
}
- InlineAsmOperand::SymStatic { def_id: _ } => {}
+ InlineAsmOperand::Out { place: None, .. }
+ | InlineAsmOperand::SymStatic { def_id: _ } => {}
}
}
}
@@ -1202,7 +1201,7 @@
StorageDead,
/// User type annotation assertions for NLL.
AscribeUserTy,
- /// The data of an user variable, for debug info.
+ /// The data of a user variable, for debug info.
VarDebugInfo,
}
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index 0908b6a..ed32bb1 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -114,9 +114,24 @@
desc { |tcx| "compute const default for a given parameter `{}`", tcx.def_path_str(param) }
}
+ query default_anon_const_substs(key: DefId) -> SubstsRef<'tcx> {
+ desc { |tcx| "computing the default generic arguments for `{}`", tcx.def_path_str(key) }
+ }
+
/// Records the type of every item.
query type_of(key: DefId) -> Ty<'tcx> {
- desc { |tcx| "computing type of `{}`", tcx.def_path_str(key) }
+ desc { |tcx|
+ "{action} `{path}`",
+ action = {
+ use rustc_hir::def::DefKind;
+ match tcx.def_kind(key) {
+ DefKind::TyAlias => "expanding type alias",
+ DefKind::TraitAlias => "expanding trait alias",
+ _ => "computing type of",
+ }
+ },
+ path = tcx.def_path_str(key),
+ }
cache_on_disk_if { key.is_local() }
}
@@ -230,6 +245,12 @@
desc { |tcx| "building THIR for `{}`", tcx.def_path_str(key.did.to_def_id()) }
}
+ /// Create a THIR tree for debugging.
+ query thir_tree(key: ty::WithOptConstParam<LocalDefId>) -> String {
+ no_hash
+ desc { |tcx| "constructing THIR tree for `{}`", tcx.def_path_str(key.did.to_def_id()) }
+ }
+
/// 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.
@@ -293,12 +314,11 @@
}
query try_unify_abstract_consts(key: (
- (ty::WithOptConstParam<DefId>, SubstsRef<'tcx>),
- (ty::WithOptConstParam<DefId>, SubstsRef<'tcx>)
+ ty::Unevaluated<'tcx, ()>, ty::Unevaluated<'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)
+ tcx.def_path_str(key.0.def.did), tcx.def_path_str(key.1.def.did)
}
}
@@ -336,6 +356,16 @@
}
}
+ query symbols_for_closure_captures(
+ key: (LocalDefId, DefId)
+ ) -> Vec<rustc_span::Symbol> {
+ desc {
+ |tcx| "symbols for captures of closure `{}` in `{}`",
+ tcx.def_path_str(key.1),
+ tcx.def_path_str(key.0.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> {
@@ -632,7 +662,7 @@
}
}
- /// HACK: when evaluated, this reports a "unsafe derive on repr(packed)" error.
+ /// HACK: when evaluated, this reports an "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
@@ -971,6 +1001,18 @@
desc { |tcx| "finding all vtable entries for trait {}", tcx.def_path_str(key.def_id()) }
}
+ query vtable_trait_upcasting_coercion_new_vptr_slot(key: (ty::Ty<'tcx>, ty::Ty<'tcx>)) -> Option<usize> {
+ desc { |tcx| "finding the slot within vtable for trait object {} vtable ptr during trait upcasting coercion from {} vtable",
+ key.1, key.0 }
+ }
+
+ query vtable_allocation(key: (Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>)) -> mir::interpret::AllocId {
+ desc { |tcx| "vtable const allocation for <{} as {}>",
+ key.0,
+ key.1.map(|trait_ref| format!("{}", trait_ref)).unwrap_or("_".to_owned())
+ }
+ }
+
query codegen_fulfill_obligation(
key: (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>)
) -> Result<ImplSource<'tcx, ()>, ErrorReported> {
@@ -1079,10 +1121,12 @@
cache_on_disk_if { false }
}
- 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 }
+ /// Computes the layout of a type. Note that this implicitly
+ /// executes in "reveal all" mode, and will normalize the input type.
+ query layout_of(
+ key: ty::ParamEnvAnd<'tcx, Ty<'tcx>>
+ ) -> Result<ty::layout::TyAndLayout<'tcx>, ty::layout::LayoutError<'tcx>> {
+ desc { "computing layout of `{}`", key.value }
}
query dylib_dependency_formats(_: CrateNum)
@@ -1241,9 +1285,6 @@
query entry_fn(_: ()) -> Option<(DefId, EntryFnType)> {
desc { "looking up the entry function of a crate" }
}
- query plugin_registrar_fn(_: ()) -> Option<LocalDefId> {
- desc { "looking up the plugin registrar for a crate" }
- }
query proc_macro_decls_static(_: ()) -> Option<LocalDefId> {
desc { "looking up the derive registrar for a crate" }
}
@@ -1715,7 +1756,7 @@
}
/// Performs an HIR-based well-formed check on the item with the given `HirId`. If
- /// we get an `Umimplemented` error that matches the provided `Predicate`, return
+ /// we get an `Unimplemented` error that matches the provided `Predicate`, return
/// the cause of the newly created obligation.
///
/// This is only used by error-reporting code to get a better cause (in particular, a better
diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs
index cdefc9e..91a64e1 100644
--- a/compiler/rustc_middle/src/thir.rs
+++ b/compiler/rustc_middle/src/thir.rs
@@ -14,7 +14,7 @@
use rustc_hir::def_id::DefId;
use rustc_hir::RangeEnd;
use rustc_index::newtype_index;
-use rustc_index::vec::{Idx, IndexVec};
+use rustc_index::vec::IndexVec;
use rustc_middle::infer::canonical::Canonical;
use rustc_middle::middle::region;
use rustc_middle::mir::{
@@ -223,6 +223,7 @@
},
/// An `if` expression.
If {
+ if_then_scope: region::Scope,
cond: ExprId,
then: ExprId,
else_opt: Option<ExprId>,
@@ -292,6 +293,10 @@
Loop {
body: ExprId,
},
+ Let {
+ expr: ExprId,
+ pat: Pat<'tcx>,
+ },
/// A `match` expression.
Match {
scrutinee: ExprId,
@@ -712,17 +717,9 @@
PatKind::Variant { adt_def, variant_index, .. } => {
Some(&adt_def.variants[variant_index])
}
- _ => {
- if let ty::Adt(adt, _) = self.ty.kind() {
- if !adt.is_enum() {
- Some(&adt.variants[VariantIdx::new(0)])
- } else {
- None
- }
- } else {
- None
- }
- }
+ _ => self.ty.ty_adt_def().and_then(|adt| {
+ if !adt.is_enum() { Some(adt.non_enum_variant()) } else { None }
+ }),
};
if let Some(variant) = variant {
diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs
index a4a2e82..74edb17 100644
--- a/compiler/rustc_middle/src/traits/mod.rs
+++ b/compiler/rustc_middle/src/traits/mod.rs
@@ -17,7 +17,6 @@
use rustc_errors::{Applicability, DiagnosticBuilder};
use rustc_hir as hir;
use rustc_hir::def_id::{DefId, LocalDefId};
-use rustc_hir::Constness;
use rustc_span::symbol::Symbol;
use rustc_span::{Span, DUMMY_SP};
use smallvec::SmallVec;
@@ -225,6 +224,8 @@
SizedReturnType,
/// Yield type must be `Sized`.
SizedYieldType,
+ /// Box expression result type must be `Sized`.
+ SizedBoxType,
/// Inline asm operand type must be `Sized`.
InlineAsmSized,
/// `[T, ..n]` implies that `T` must be `Copy`.
@@ -304,6 +305,9 @@
/// Intrinsic has wrong type
IntrinsicType,
+ /// A let else block does not diverge
+ LetElse,
+
/// Method receiver
MethodReceiver,
@@ -495,7 +499,7 @@
/// for some type parameter. The `Vec<N>` represents the
/// obligations incurred from normalizing the where-clause (if
/// any).
- Param(Vec<N>, Constness),
+ Param(Vec<N>, ty::BoundConstness),
/// Virtual calls through an object.
Object(ImplSourceObjectData<'tcx, N>),
@@ -503,8 +507,11 @@
/// Successful resolution for a builtin trait.
Builtin(ImplSourceBuiltinData<N>),
+ /// ImplSource for trait upcasting coercion
+ TraitUpcasting(ImplSourceTraitUpcastingData<'tcx, N>),
+
/// ImplSource automatically generated for a closure. The `DefId` is the ID
- /// of the closure expression. This is a `ImplSource::UserDefined` in spirit, but the
+ /// of the closure expression. This is an `ImplSource::UserDefined` in spirit, but the
/// impl is generated by the compiler and does not appear in the source.
Closure(ImplSourceClosureData<'tcx, N>),
@@ -538,6 +545,7 @@
ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData)
| ImplSource::Pointee(ImplSourcePointeeData) => Vec::new(),
ImplSource::TraitAlias(d) => d.nested,
+ ImplSource::TraitUpcasting(d) => d.nested,
}
}
@@ -554,6 +562,7 @@
ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData)
| ImplSource::Pointee(ImplSourcePointeeData) => &[],
ImplSource::TraitAlias(d) => &d.nested[..],
+ ImplSource::TraitUpcasting(d) => &d.nested[..],
}
}
@@ -605,6 +614,13 @@
substs: d.substs,
nested: d.nested.into_iter().map(f).collect(),
}),
+ ImplSource::TraitUpcasting(d) => {
+ ImplSource::TraitUpcasting(ImplSourceTraitUpcastingData {
+ upcast_trait_ref: d.upcast_trait_ref,
+ vtable_vptr_slot: d.vtable_vptr_slot,
+ nested: d.nested.into_iter().map(f).collect(),
+ })
+ }
}
}
}
@@ -651,6 +667,20 @@
}
#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, TypeFoldable, Lift)]
+pub struct ImplSourceTraitUpcastingData<'tcx, N> {
+ /// `Foo` upcast to the obligation trait. This will be some supertrait of `Foo`.
+ pub upcast_trait_ref: ty::PolyTraitRef<'tcx>,
+
+ /// The vtable is formed by concatenating together the method lists of
+ /// the base object trait and all supertraits, pointers to supertrait vtable will
+ /// be provided when necessary; this is the position of `upcast_trait_ref`'s vtable
+ /// within that vtable.
+ pub vtable_vptr_slot: Option<usize>,
+
+ pub nested: Vec<N>,
+}
+
+#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, TypeFoldable, Lift)]
pub struct ImplSourceBuiltinData<N> {
pub nested: Vec<N>,
}
@@ -661,8 +691,9 @@
pub upcast_trait_ref: ty::PolyTraitRef<'tcx>,
/// The vtable is formed by concatenating together the method lists of
- /// the base object trait and all supertraits; this is the start of
- /// `upcast_trait_ref`'s methods in that vtable.
+ /// the base object trait and all supertraits, pointers to supertrait vtable will
+ /// be provided when necessary; this is the start of `upcast_trait_ref`'s methods
+ /// in that vtable.
pub vtable_base: usize,
pub nested: Vec<N>,
diff --git a/compiler/rustc_middle/src/traits/select.rs b/compiler/rustc_middle/src/traits/select.rs
index ab08517..62996bf 100644
--- a/compiler/rustc_middle/src/traits/select.rs
+++ b/compiler/rustc_middle/src/traits/select.rs
@@ -12,12 +12,12 @@
use rustc_query_system::cache::Cache;
pub type SelectionCache<'tcx> = Cache<
- ty::ParamEnvAnd<'tcx, ty::TraitRef<'tcx>>,
+ ty::ConstnessAnd<ty::ParamEnvAnd<'tcx, ty::TraitRef<'tcx>>>,
SelectionResult<'tcx, SelectionCandidate<'tcx>>,
>;
pub type EvaluationCache<'tcx> =
- Cache<ty::ParamEnvAnd<'tcx, ty::PolyTraitRef<'tcx>>, EvaluationResult>;
+ Cache<ty::ParamEnvAnd<'tcx, ty::ConstnessAnd<ty::PolyTraitRef<'tcx>>>, EvaluationResult>;
/// The selection process begins by considering all impls, where
/// clauses, and so forth that might resolve an obligation. Sometimes
@@ -111,7 +111,7 @@
ProjectionCandidate(usize),
/// Implementation of a `Fn`-family trait by one of the anonymous types
- /// generated for a `||` expression.
+ /// generated for an `||` expression.
ClosureCandidate,
/// Implementation of a `Generator` trait by one of the anonymous types
@@ -135,6 +135,11 @@
/// `rustc_infer::traits::util::supertraits`.
ObjectCandidate(usize),
+ /// Perform trait upcasting coercion of `dyn Trait` to a supertrait of `Trait`.
+ /// The index is the position in the iterator returned by
+ /// `rustc_infer::traits::util::supertraits`.
+ TraitUpcastingUnsizeCandidate(usize),
+
BuiltinObjectCandidate,
BuiltinUnsizeCandidate,
diff --git a/compiler/rustc_middle/src/traits/structural_impls.rs b/compiler/rustc_middle/src/traits/structural_impls.rs
index 4f978e6..aa16e14 100644
--- a/compiler/rustc_middle/src/traits/structural_impls.rs
+++ b/compiler/rustc_middle/src/traits/structural_impls.rs
@@ -30,6 +30,8 @@
super::ImplSource::Builtin(ref d) => write!(f, "{:?}", d),
super::ImplSource::TraitAlias(ref d) => write!(f, "{:?}", d),
+
+ super::ImplSource::TraitUpcasting(ref d) => write!(f, "{:?}", d),
}
}
}
@@ -70,6 +72,16 @@
}
}
+impl<N: fmt::Debug> fmt::Debug for traits::ImplSourceTraitUpcastingData<'tcx, N> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(
+ f,
+ "ImplSourceTraitUpcastingData(upcast={:?}, vtable_vptr_slot={:?}, nested={:?})",
+ self.upcast_trait_ref, self.vtable_vptr_slot, self.nested
+ )
+ }
+}
+
impl<N: fmt::Debug> fmt::Debug for traits::ImplSourceAutoImplData<N> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
diff --git a/compiler/rustc_middle/src/ty/adt.rs b/compiler/rustc_middle/src/ty/adt.rs
index 95159ea..27927bc 100644
--- a/compiler/rustc_middle/src/ty/adt.rs
+++ b/compiler/rustc_middle/src/ty/adt.rs
@@ -209,7 +209,7 @@
self.flags.contains(AdtFlags::IS_UNION)
}
- /// Returns `true` if this is a enum.
+ /// Returns `true` if this is an enum.
#[inline]
pub fn is_enum(&self) -> bool {
self.flags.contains(AdtFlags::IS_ENUM)
diff --git a/compiler/rustc_middle/src/ty/assoc.rs b/compiler/rustc_middle/src/ty/assoc.rs
index 2d17755..5cb2b90 100644
--- a/compiler/rustc_middle/src/ty/assoc.rs
+++ b/compiler/rustc_middle/src/ty/assoc.rs
@@ -16,6 +16,13 @@
}
impl AssocItemContainer {
+ pub fn impl_def_id(&self) -> Option<DefId> {
+ match *self {
+ ImplContainer(id) => Some(id),
+ _ => None,
+ }
+ }
+
/// Asserts that this is the `DefId` of an associated item declared
/// in a trait, and returns the trait `DefId`.
pub fn assert_trait(&self) -> DefId {
diff --git a/compiler/rustc_middle/src/ty/closure.rs b/compiler/rustc_middle/src/ty/closure.rs
index 6b51adc..4eacb3c 100644
--- a/compiler/rustc_middle/src/ty/closure.rs
+++ b/compiler/rustc_middle/src/ty/closure.rs
@@ -3,10 +3,12 @@
};
use crate::{mir, ty};
+use std::fmt::Write;
+
use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
use rustc_hir as hir;
use rustc_hir::def_id::{DefId, LocalDefId};
-use rustc_span::Span;
+use rustc_span::{Span, Symbol};
use super::{Ty, TyCtxt};
@@ -159,6 +161,43 @@
place_to_string_for_capture(tcx, &self.place)
}
+ /// Returns a symbol of the captured upvar, which looks like `name__field1__field2`.
+ fn to_symbol(&self, tcx: TyCtxt<'tcx>) -> Symbol {
+ let hir_id = match self.place.base {
+ HirPlaceBase::Upvar(upvar_id) => upvar_id.var_path.hir_id,
+ base => bug!("Expected an upvar, found {:?}", base),
+ };
+ let mut symbol = tcx.hir().name(hir_id).as_str().to_string();
+
+ let mut ty = self.place.base_ty;
+ for proj in self.place.projections.iter() {
+ match proj.kind {
+ HirProjectionKind::Field(idx, variant) => match ty.kind() {
+ ty::Tuple(_) => write!(&mut symbol, "__{}", idx).unwrap(),
+ ty::Adt(def, ..) => {
+ write!(
+ &mut symbol,
+ "__{}",
+ def.variants[variant].fields[idx as usize].ident.name.as_str(),
+ )
+ .unwrap();
+ }
+ ty => {
+ bug!("Unexpected type {:?} for `Field` projection", ty)
+ }
+ },
+
+ // Ignore derefs for now, as they are likely caused by
+ // autoderefs that don't appear in the original code.
+ HirProjectionKind::Deref => {}
+ proj => bug!("Unexpected projection {:?} in captured place", proj),
+ }
+ ty = proj.ty;
+ }
+
+ Symbol::intern(&symbol)
+ }
+
/// 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 {
@@ -209,6 +248,15 @@
}
}
+fn symbols_for_closure_captures<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ def_id: (LocalDefId, DefId),
+) -> Vec<Symbol> {
+ let typeck_results = tcx.typeck(def_id.0);
+ let captures = typeck_results.closure_min_captures_flattened(def_id.1);
+ captures.into_iter().map(|captured_place| captured_place.to_symbol(tcx)).collect()
+}
+
/// Return true if the `proj_possible_ancestor` represents an ancestor path
/// to `proj_capture` or `proj_possible_ancestor` is same as `proj_capture`,
/// assuming they both start off of the same root variable.
@@ -386,9 +434,13 @@
ImmBorrow => hir::Mutability::Not,
// We have no type corresponding to a unique imm borrow, so
- // use `&mut`. It gives all the capabilities of an `&uniq`
+ // use `&mut`. It gives all the capabilities of a `&uniq`
// and hence is a safe "over approximation".
UniqueImmBorrow => hir::Mutability::Mut,
}
}
}
+
+pub fn provide(providers: &mut ty::query::Providers) {
+ *providers = ty::query::Providers { symbols_for_closure_captures, ..*providers }
+}
diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs
index 5ec665e..4edb6a3 100644
--- a/compiler/rustc_middle/src/ty/codec.rs
+++ b/compiler/rustc_middle/src/ty/codec.rs
@@ -209,7 +209,7 @@
impl<'tcx, D: TyDecoder<'tcx>> Decodable<D> for Ty<'tcx> {
#[allow(rustc::usage_of_ty_tykind)]
fn decode(decoder: &mut D) -> Result<Ty<'tcx>, D::Error> {
- // Handle shorthands first, if we have an usize > 0x80.
+ // Handle shorthands first, if we have a usize > 0x80.
if decoder.positioned_at_shorthand() {
let pos = decoder.read_usize()?;
assert!(pos >= SHORTHAND_OFFSET);
@@ -228,7 +228,7 @@
impl<'tcx, D: TyDecoder<'tcx>> Decodable<D> for ty::Binder<'tcx, ty::PredicateKind<'tcx>> {
fn decode(decoder: &mut D) -> Result<ty::Binder<'tcx, ty::PredicateKind<'tcx>>, D::Error> {
let bound_vars = Decodable::decode(decoder)?;
- // Handle shorthands first, if we have an usize > 0x80.
+ // Handle shorthands first, if we have a usize > 0x80.
Ok(ty::Binder::bind_with_vars(
if decoder.positioned_at_shorthand() {
let pos = decoder.read_usize()?;
@@ -385,7 +385,7 @@
impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for ty::List<ty::BoundVariableKind> {
fn decode(decoder: &mut D) -> Result<&'tcx Self, D::Error> {
let len = decoder.read_usize()?;
- Ok(decoder.tcx().mk_bound_variable_kinds((0..len).map(|_| Decodable::decode(decoder)))?)
+ decoder.tcx().mk_bound_variable_kinds((0..len).map(|_| Decodable::decode(decoder)))
}
}
@@ -437,15 +437,15 @@
}
macro_rules! impl_arena_allocatable_decoders {
- ([], [$($a:tt $name:ident: $ty:ty,)*], $tcx:lifetime) => {
+ ([$($a:tt $name:ident: $ty:ty,)*], $tcx:lifetime) => {
$(
impl_arena_allocatable_decoder!($a [[$name: $ty], $tcx]);
)*
}
}
-rustc_hir::arena_types!(impl_arena_allocatable_decoders, [], 'tcx);
-arena_types!(impl_arena_allocatable_decoders, [], 'tcx);
+rustc_hir::arena_types!(impl_arena_allocatable_decoders, 'tcx);
+arena_types!(impl_arena_allocatable_decoders, 'tcx);
#[macro_export]
macro_rules! implement_ty_decoder {
diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs
index c781512..869b2ab 100644
--- a/compiler/rustc_middle/src/ty/consts.rs
+++ b/compiler/rustc_middle/src/ty/consts.rs
@@ -1,6 +1,5 @@
use crate::mir::interpret::ConstValue;
use crate::mir::interpret::{LitToConstInput, Scalar};
-use crate::ty::subst::InternalSubsts;
use crate::ty::{self, Ty, TyCtxt};
use crate::ty::{ParamEnv, ParamEnvAnd};
use rustc_errors::ErrorReported;
@@ -100,7 +99,7 @@
}
_ => ty::ConstKind::Unevaluated(ty::Unevaluated {
def: def.to_global(),
- substs: InternalSubsts::identity_for_item(tcx, def.did.to_def_id()),
+ substs_: None,
promoted: None,
}),
};
diff --git a/compiler/rustc_middle/src/ty/consts/kind.rs b/compiler/rustc_middle/src/ty/consts/kind.rs
index f2db95d1..7188eed 100644
--- a/compiler/rustc_middle/src/ty/consts/kind.rs
+++ b/compiler/rustc_middle/src/ty/consts/kind.rs
@@ -1,4 +1,5 @@
use std::convert::TryInto;
+use std::fmt;
use crate::mir::interpret::{AllocId, ConstValue, Scalar};
use crate::mir::Promoted;
@@ -12,12 +13,53 @@
use super::ScalarInt;
/// An unevaluated, potentially generic, constant.
-#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable)]
+///
+/// If `substs_` is `None` it means that this anon const
+/// still has its default substs.
+///
+/// We check for all possible substs in `fn default_anon_const_substs`,
+/// so refer to that check for more info.
+#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable, Lift)]
#[derive(Hash, HashStable)]
-pub struct Unevaluated<'tcx> {
+pub struct Unevaluated<'tcx, P = Option<Promoted>> {
pub def: ty::WithOptConstParam<DefId>,
- pub substs: SubstsRef<'tcx>,
- pub promoted: Option<Promoted>,
+ pub substs_: Option<SubstsRef<'tcx>>,
+ pub promoted: P,
+}
+
+impl<'tcx> Unevaluated<'tcx> {
+ #[inline]
+ pub fn shrink(self) -> Unevaluated<'tcx, ()> {
+ debug_assert_eq!(self.promoted, None);
+ Unevaluated { def: self.def, substs_: self.substs_, promoted: () }
+ }
+}
+
+impl<'tcx> Unevaluated<'tcx, ()> {
+ #[inline]
+ pub fn expand(self) -> Unevaluated<'tcx> {
+ Unevaluated { def: self.def, substs_: self.substs_, promoted: None }
+ }
+}
+
+impl<'tcx, P: Default> Unevaluated<'tcx, P> {
+ #[inline]
+ pub fn new(def: ty::WithOptConstParam<DefId>, substs: SubstsRef<'tcx>) -> Unevaluated<'tcx, P> {
+ Unevaluated { def, substs_: Some(substs), promoted: Default::default() }
+ }
+}
+
+impl<'tcx, P: Default + PartialEq + fmt::Debug> Unevaluated<'tcx, P> {
+ #[inline]
+ pub fn substs(self, tcx: TyCtxt<'tcx>) -> SubstsRef<'tcx> {
+ self.substs_.unwrap_or_else(|| {
+ // We must not use the parents default substs for promoted constants
+ // as that can result in incorrect substs and calls the `default_anon_const_substs`
+ // for something that might not actually be a constant.
+ debug_assert_eq!(self.promoted, Default::default());
+ tcx.default_anon_const_substs(self.def.did)
+ })
+ }
}
/// Represents a constant in Rust.
@@ -109,7 +151,7 @@
tcx: TyCtxt<'tcx>,
param_env: ParamEnv<'tcx>,
) -> Option<Result<ConstValue<'tcx>, ErrorReported>> {
- if let ConstKind::Unevaluated(Unevaluated { def, substs, promoted }) = self {
+ if let ConstKind::Unevaluated(unevaluated) = self {
use crate::mir::interpret::ErrorHandled;
// HACK(eddyb) this erases lifetimes even though `const_eval_resolve`
@@ -118,29 +160,32 @@
// Note that we erase regions *before* calling `with_reveal_all_normalized`,
// so that we don't try to invoke this query with
// any region variables.
- let param_env_and_substs = tcx
+ let param_env_and = tcx
.erase_regions(param_env)
.with_reveal_all_normalized(tcx)
- .and(tcx.erase_regions(substs));
+ .and(tcx.erase_regions(unevaluated));
// HACK(eddyb) when the query key would contain inference variables,
// attempt using identity substs and `ParamEnv` instead, that will succeed
// when the expression doesn't depend on any parameters.
// FIXME(eddyb, skinny121) pass `InferCtxt` into here when it's available, so that
// we can call `infcx.const_eval_resolve` which handles inference variables.
- let param_env_and_substs = if param_env_and_substs.needs_infer() {
- tcx.param_env(def.did).and(InternalSubsts::identity_for_item(tcx, def.did))
+ let param_env_and = if param_env_and.needs_infer() {
+ tcx.param_env(unevaluated.def.did).and(ty::Unevaluated {
+ def: unevaluated.def,
+ substs_: Some(InternalSubsts::identity_for_item(tcx, unevaluated.def.did)),
+ promoted: unevaluated.promoted,
+ })
} else {
- param_env_and_substs
+ param_env_and
};
// FIXME(eddyb) maybe the `const_eval_*` methods should take
- // `ty::ParamEnvAnd<SubstsRef>` instead of having them separate.
- let (param_env, substs) = param_env_and_substs.into_parts();
+ // `ty::ParamEnvAnd` instead of having them separate.
+ let (param_env, unevaluated) = param_env_and.into_parts();
// try to resolve e.g. associated constants to their definition on an impl, and then
// evaluate the const.
- match tcx.const_eval_resolve(param_env, ty::Unevaluated { def, substs, promoted }, None)
- {
+ match tcx.const_eval_resolve(param_env, unevaluated, None) {
// NOTE(eddyb) `val` contains no lifetimes/types/consts,
// and we use the original type, so nothing from `substs`
// (which may be identity substs, see above),
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index 4ce4903..4def27e 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -10,7 +10,7 @@
use crate::middle::cstore::EncodedMetadata;
use crate::middle::resolve_lifetime::{self, LifetimeScopeForPath, ObjectLifetimeDefault};
use crate::middle::stability;
-use crate::mir::interpret::{self, AllocId, Allocation, ConstValue, Scalar};
+use crate::mir::interpret::{self, Allocation, ConstValue, Scalar};
use crate::mir::{Body, Field, Local, Place, PlaceElem, ProjectionKind, Promoted};
use crate::thir::Thir;
use crate::traits;
@@ -32,7 +32,6 @@
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_data_structures::steal::Steal;
use rustc_data_structures::sync::{self, Lock, Lrc, WorkerLocal};
-use rustc_data_structures::vec_map::VecMap;
use rustc_errors::ErrorReported;
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
@@ -46,7 +45,6 @@
use rustc_index::vec::{Idx, IndexVec};
use rustc_macros::HashStable;
use rustc_middle::mir::FakeReadCause;
-use rustc_middle::ty::OpaqueTypeKey;
use rustc_serialize::opaque::{FileEncodeResult, FileEncoder};
use rustc_session::config::{BorrowckMode, CrateType, OutputFilenames};
use rustc_session::lint::{Level, Lint};
@@ -477,7 +475,7 @@
/// All the opaque types that are restricted to concrete types
/// by this function.
- pub concrete_opaque_types: VecMap<OpaqueTypeKey<'tcx>, Ty<'tcx>>,
+ pub concrete_opaque_types: FxHashSet<DefId>,
/// Tracks the minimum captures required for a closure;
/// see `MinCaptureInformationMap` for more details.
@@ -1064,9 +1062,6 @@
layout_interner: ShardedHashMap<&'tcx Layout, ()>,
output_filenames: Arc<OutputFilenames>,
-
- pub(super) vtables_cache:
- Lock<FxHashMap<(Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>), AllocId>>,
}
impl<'tcx> TyCtxt<'tcx> {
@@ -1138,7 +1133,7 @@
pub fn layout_scalar_valid_range(self, def_id: DefId) -> (Bound<u128>, Bound<u128>) {
let attrs = self.get_attrs(def_id);
let get = |name| {
- let attr = match attrs.iter().find(|a| self.sess.check_name(a, name)) {
+ let attr = match attrs.iter().find(|a| a.has_name(name)) {
Some(attr) => attr,
None => return Bound::Unbounded,
};
@@ -1214,7 +1209,6 @@
const_stability_interner: Default::default(),
alloc_map: Lock::new(interpret::AllocMap::new()),
output_filenames: Arc::new(output_filenames),
- vtables_cache: Default::default(),
}
}
@@ -1422,8 +1416,8 @@
#[inline]
pub fn lazy_normalization(self) -> bool {
let features = self.features();
- // Note: We do not enable lazy normalization for `min_const_generics`.
- features.const_generics || features.lazy_normalization_consts
+ // Note: We only use lazy normalization for generic const expressions.
+ features.generic_const_exprs
}
#[inline]
@@ -1794,7 +1788,7 @@
if context == 0 {
f(None)
} else {
- // We could get a `ImplicitCtxt` pointer from another thread.
+ // We could get an `ImplicitCtxt` pointer from another thread.
// Ensure that `ImplicitCtxt` is `Sync`.
sync::assert_sync::<ImplicitCtxt<'_, '_>>();
@@ -2171,7 +2165,7 @@
let generic_predicates = self.super_predicates_of(trait_did);
for (predicate, _) in generic_predicates.predicates {
- if let ty::PredicateKind::Trait(data, _) = predicate.kind().skip_binder() {
+ if let ty::PredicateKind::Trait(data) = predicate.kind().skip_binder() {
if set.insert(data.def_id()) {
stack.push(data.def_id());
}
@@ -2854,18 +2848,11 @@
tcx.arena.alloc(tcx.resolutions(()).glob_map.get(&id).cloned().unwrap_or_default())
};
- providers.lookup_stability = |tcx, id| {
- let id = tcx.hir().local_def_id_to_hir_id(id.expect_local());
- tcx.stability().local_stability(id)
- };
- providers.lookup_const_stability = |tcx, id| {
- let id = tcx.hir().local_def_id_to_hir_id(id.expect_local());
- tcx.stability().local_const_stability(id)
- };
- providers.lookup_deprecation_entry = |tcx, id| {
- let id = tcx.hir().local_def_id_to_hir_id(id.expect_local());
- tcx.stability().local_deprecation_entry(id)
- };
+ providers.lookup_stability = |tcx, id| tcx.stability().local_stability(id.expect_local());
+ providers.lookup_const_stability =
+ |tcx, id| tcx.stability().local_const_stability(id.expect_local());
+ providers.lookup_deprecation_entry =
+ |tcx, id| tcx.stability().local_deprecation_entry(id.expect_local());
providers.extern_mod_stmt_cnum =
|tcx, id| tcx.resolutions(()).extern_crate_map.get(&id).cloned();
providers.output_filenames = |tcx, ()| tcx.output_filenames.clone();
diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs
index bfb4c0c..4cfb104 100644
--- a/compiler/rustc_middle/src/ty/diagnostics.rs
+++ b/compiler/rustc_middle/src/ty/diagnostics.rs
@@ -2,6 +2,7 @@
use crate::ty::TyKind::*;
use crate::ty::{InferTy, TyCtxt, TyS};
+use rustc_data_structures::fx::FxHashSet;
use rustc_errors::{Applicability, DiagnosticBuilder};
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
@@ -105,6 +106,116 @@
true
}
+fn suggest_removing_unsized_bound(
+ generics: &hir::Generics<'_>,
+ err: &mut DiagnosticBuilder<'_>,
+ param_name: &str,
+ param: &hir::GenericParam<'_>,
+ def_id: Option<DefId>,
+) {
+ // See if there's a `?Sized` bound that can be removed to suggest that.
+ // First look at the `where` clause because we can have `where T: ?Sized`, but that
+ // `?Sized` bound is *also* included in the `GenericParam` as a bound, which breaks
+ // the spans. Hence the somewhat involved logic that follows.
+ let mut where_unsized_bounds = FxHashSet::default();
+ for (where_pos, predicate) in generics.where_clause.predicates.iter().enumerate() {
+ match predicate {
+ WherePredicate::BoundPredicate(WhereBoundPredicate {
+ bounded_ty:
+ hir::Ty {
+ kind:
+ hir::TyKind::Path(hir::QPath::Resolved(
+ None,
+ hir::Path {
+ segments: [segment],
+ res: hir::def::Res::Def(hir::def::DefKind::TyParam, _),
+ ..
+ },
+ )),
+ ..
+ },
+ bounds,
+ span,
+ ..
+ }) if segment.ident.as_str() == param_name => {
+ for (pos, bound) in bounds.iter().enumerate() {
+ match bound {
+ hir::GenericBound::Unsized(_) => {}
+ hir::GenericBound::Trait(poly, hir::TraitBoundModifier::Maybe)
+ if poly.trait_ref.trait_def_id() == def_id => {}
+ _ => continue,
+ }
+ let sp = match (
+ bounds.len(),
+ pos,
+ generics.where_clause.predicates.len(),
+ where_pos,
+ ) {
+ // where T: ?Sized
+ // ^^^^^^^^^^^^^^^
+ (1, _, 1, _) => generics.where_clause.span,
+ // where Foo: Bar, T: ?Sized,
+ // ^^^^^^^^^^^
+ (1, _, len, pos) if pos == len - 1 => generics.where_clause.predicates
+ [pos - 1]
+ .span()
+ .shrink_to_hi()
+ .to(*span),
+ // where T: ?Sized, Foo: Bar,
+ // ^^^^^^^^^^^
+ (1, _, _, pos) => {
+ span.until(generics.where_clause.predicates[pos + 1].span())
+ }
+ // where T: ?Sized + Bar, Foo: Bar,
+ // ^^^^^^^^^
+ (_, 0, _, _) => bound.span().to(bounds[1].span().shrink_to_lo()),
+ // where T: Bar + ?Sized, Foo: Bar,
+ // ^^^^^^^^^
+ (_, pos, _, _) => bounds[pos - 1].span().shrink_to_hi().to(bound.span()),
+ };
+ where_unsized_bounds.insert(bound.span());
+ err.span_suggestion_verbose(
+ sp,
+ "consider removing the `?Sized` bound to make the \
+ type parameter `Sized`",
+ String::new(),
+ Applicability::MaybeIncorrect,
+ );
+ }
+ }
+ _ => {}
+ }
+ }
+ for (pos, bound) in param.bounds.iter().enumerate() {
+ match bound {
+ hir::GenericBound::Trait(poly, hir::TraitBoundModifier::Maybe)
+ if poly.trait_ref.trait_def_id() == def_id
+ && !where_unsized_bounds.contains(&bound.span()) =>
+ {
+ let sp = match (param.bounds.len(), pos) {
+ // T: ?Sized,
+ // ^^^^^^^^
+ (1, _) => param.span.shrink_to_hi().to(bound.span()),
+ // T: ?Sized + Bar,
+ // ^^^^^^^^^
+ (_, 0) => bound.span().to(param.bounds[1].span().shrink_to_lo()),
+ // T: Bar + ?Sized,
+ // ^^^^^^^^^
+ (_, pos) => param.bounds[pos - 1].span().shrink_to_hi().to(bound.span()),
+ };
+ err.span_suggestion_verbose(
+ sp,
+ "consider removing the `?Sized` bound to make the type parameter \
+ `Sized`",
+ String::new(),
+ Applicability::MaybeIncorrect,
+ );
+ }
+ _ => {}
+ }
+ }
+}
+
/// Suggest restricting a type param with a new bound.
pub fn suggest_constraining_type_param(
tcx: TyCtxt<'_>,
@@ -130,6 +241,7 @@
if def_id == tcx.lang_items().sized_trait() {
// Type parameters are already `Sized` by default.
err.span_label(param.span, &format!("this type parameter needs to be `{}`", constraint));
+ suggest_removing_unsized_bound(generics, err, param_name, param, def_id);
return true;
}
let mut suggest_restrict = |span| {
diff --git a/compiler/rustc_middle/src/ty/erase_regions.rs b/compiler/rustc_middle/src/ty/erase_regions.rs
index 759d1a0..63eb55e 100644
--- a/compiler/rustc_middle/src/ty/erase_regions.rs
+++ b/compiler/rustc_middle/src/ty/erase_regions.rs
@@ -21,7 +21,9 @@
T: TypeFoldable<'tcx>,
{
// If there's nothing to erase avoid performing the query at all
- if !value.has_type_flags(TypeFlags::HAS_RE_LATE_BOUND | TypeFlags::HAS_FREE_REGIONS) {
+ if !value
+ .has_type_flags(TypeFlags::HAS_RE_LATE_BOUND | TypeFlags::HAS_POTENTIAL_FREE_REGIONS)
+ {
return value;
}
debug!("erase_regions({:?})", value);
diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs
index 96aae3b..796ca65 100644
--- a/compiler/rustc_middle/src/ty/error.rs
+++ b/compiler/rustc_middle/src/ty/error.rs
@@ -33,6 +33,7 @@
#[derive(Clone, Debug, TypeFoldable)]
pub enum TypeError<'tcx> {
Mismatch,
+ ConstnessMismatch(ExpectedFound<ty::BoundConstness>),
UnsafetyMismatch(ExpectedFound<hir::Unsafety>),
AbiMismatch(ExpectedFound<abi::Abi>),
Mutability,
@@ -70,12 +71,6 @@
TargetFeatureCast(DefId),
}
-pub enum UnconstrainedNumeric {
- UnconstrainedFloat,
- UnconstrainedInt,
- Neither,
-}
-
/// Explains the source of a type err in a short, human readable way. This is meant to be placed
/// in parentheses after some larger message. You should also invoke `note_and_explain_type_err()`
/// afterwards to present additional details, particularly when it comes to lifetime-related
@@ -106,6 +101,9 @@
CyclicTy(_) => write!(f, "cyclic type of infinite size"),
CyclicConst(_) => write!(f, "encountered a self-referencing constant"),
Mismatch => write!(f, "types differ"),
+ ConstnessMismatch(values) => {
+ write!(f, "expected {} bound, found {} bound", values.expected, values.found)
+ }
UnsafetyMismatch(values) => {
write!(f, "expected {} fn, found {} fn", values.expected, values.found)
}
@@ -213,9 +211,11 @@
pub fn must_include_note(&self) -> bool {
use self::TypeError::*;
match self {
- CyclicTy(_) | CyclicConst(_) | UnsafetyMismatch(_) | Mismatch | AbiMismatch(_)
- | FixedArraySize(_) | ArgumentSorts(..) | Sorts(_) | IntMismatch(_)
- | FloatMismatch(_) | VariadicMismatch(_) | TargetFeatureCast(_) => false,
+ CyclicTy(_) | CyclicConst(_) | UnsafetyMismatch(_) | ConstnessMismatch(_)
+ | Mismatch | AbiMismatch(_) | FixedArraySize(_) | ArgumentSorts(..) | Sorts(_)
+ | IntMismatch(_) | FloatMismatch(_) | VariadicMismatch(_) | TargetFeatureCast(_) => {
+ false
+ }
Mutability
| ArgumentMutability(_)
@@ -279,13 +279,10 @@
}
ty::FnDef(..) => "fn item".into(),
ty::FnPtr(_) => "fn pointer".into(),
- ty::Dynamic(ref inner, ..) => {
- if let Some(principal) = inner.principal() {
- format!("trait object `dyn {}`", tcx.def_path_str(principal.def_id())).into()
- } else {
- "trait object".into()
- }
+ ty::Dynamic(ref inner, ..) if let Some(principal) = inner.principal() => {
+ format!("trait object `dyn {}`", tcx.def_path_str(principal.def_id())).into()
}
+ ty::Dynamic(..) => "trait object".into(),
ty::Closure(..) => "closure".into(),
ty::Generator(def_id, ..) => tcx.generator_kind(def_id).unwrap().descr().into(),
ty::GeneratorWitness(..) => "generator witness".into(),
@@ -365,20 +362,19 @@
// Issue #63167
db.note("distinct uses of `impl Trait` result in different opaque types");
}
- (ty::Float(_), ty::Infer(ty::IntVar(_))) => {
+ (ty::Float(_), ty::Infer(ty::IntVar(_)))
if let Ok(
// Issue #53280
snippet,
- ) = self.sess.source_map().span_to_snippet(sp)
- {
- if snippet.chars().all(|c| c.is_digit(10) || c == '-' || c == '_') {
- db.span_suggestion(
- sp,
- "use a float literal",
- format!("{}.0", snippet),
- MachineApplicable,
- );
- }
+ ) = self.sess.source_map().span_to_snippet(sp) =>
+ {
+ if snippet.chars().all(|c| c.is_digit(10) || c == '-' || c == '_') {
+ db.span_suggestion(
+ sp,
+ "use a float literal",
+ format!("{}.0", snippet),
+ MachineApplicable,
+ );
}
}
(ty::Param(expected), ty::Param(found)) => {
@@ -628,6 +624,7 @@
assoc_substs,
ty,
msg,
+ false,
) {
return true;
}
@@ -646,6 +643,7 @@
assoc_substs,
ty,
msg,
+ false,
);
}
}
@@ -771,13 +769,24 @@
) -> bool {
let assoc = self.associated_item(proj_ty.item_def_id);
if let ty::Opaque(def_id, _) = *proj_ty.self_ty().kind() {
- self.constrain_associated_type_structured_suggestion(
+ let opaque_local_def_id = def_id.expect_local();
+ let opaque_hir_id = self.hir().local_def_id_to_hir_id(opaque_local_def_id);
+ let opaque_hir_ty = match &self.hir().expect_item(opaque_hir_id).kind {
+ hir::ItemKind::OpaqueTy(opaque_hir_ty) => opaque_hir_ty,
+ _ => bug!("The HirId comes from a `ty::Opaque`"),
+ };
+
+ let (trait_ref, assoc_substs) = proj_ty.trait_ref_and_own_substs(self);
+
+ self.constrain_generic_bound_associated_type_structured_suggestion(
db,
- self.def_span(def_id),
- &assoc,
- proj_ty.trait_ref_and_own_substs(self).1,
+ &trait_ref,
+ opaque_hir_ty.bounds,
+ assoc,
+ assoc_substs,
ty,
- &msg,
+ msg,
+ true,
)
} else {
false
@@ -899,6 +908,11 @@
/// Given a slice of `hir::GenericBound`s, if any of them corresponds to the `trait_ref`
/// requirement, provide a structured suggestion to constrain it to a given type `ty`.
+ ///
+ /// `is_bound_surely_present` indicates whether we know the bound we're looking for is
+ /// inside `bounds`. If that's the case then we can consider `bounds` containing only one
+ /// trait bound as the one we're looking for. This can help in cases where the associated
+ /// type is defined on a supertrait of the one present in the bounds.
fn constrain_generic_bound_associated_type_structured_suggestion(
self,
db: &mut DiagnosticBuilder<'_>,
@@ -908,23 +922,30 @@
assoc_substs: &[ty::GenericArg<'tcx>],
ty: Ty<'tcx>,
msg: &str,
+ is_bound_surely_present: bool,
) -> bool {
// FIXME: we would want to call `resolve_vars_if_possible` on `ty` before suggesting.
- bounds.iter().any(|bound| match bound {
- hir::GenericBound::Trait(ptr, hir::TraitBoundModifier::None) => {
- // Relate the type param against `T` in `<A as T>::Foo`.
- ptr.trait_ref.trait_def_id() == Some(trait_ref.def_id)
- && self.constrain_associated_type_structured_suggestion(
- db,
- ptr.span,
- assoc,
- assoc_substs,
- ty,
- msg,
- )
- }
- _ => false,
- })
+
+ let trait_bounds = bounds.iter().filter_map(|bound| match bound {
+ hir::GenericBound::Trait(ptr, hir::TraitBoundModifier::None) => Some(ptr),
+ _ => None,
+ });
+
+ let matching_trait_bounds = trait_bounds
+ .clone()
+ .filter(|ptr| ptr.trait_ref.trait_def_id() == Some(trait_ref.def_id))
+ .collect::<Vec<_>>();
+
+ let span = match &matching_trait_bounds[..] {
+ &[ptr] => ptr.span,
+ &[] if is_bound_surely_present => match &trait_bounds.collect::<Vec<_>>()[..] {
+ &[ptr] => ptr.span,
+ _ => return false,
+ },
+ _ => return false,
+ };
+
+ self.constrain_associated_type_structured_suggestion(db, span, assoc, assoc_substs, ty, msg)
}
/// Given a span corresponding to a bound, provide a structured suggestion to set an
diff --git a/compiler/rustc_middle/src/ty/flags.rs b/compiler/rustc_middle/src/ty/flags.rs
index 9faa172..a078b6f 100644
--- a/compiler/rustc_middle/src/ty/flags.rs
+++ b/compiler/rustc_middle/src/ty/flags.rs
@@ -34,6 +34,12 @@
result.flags
}
+ pub fn for_unevaluated_const(uv: ty::Unevaluated<'_>) -> TypeFlags {
+ let mut result = FlagComputation::new();
+ result.add_unevaluated_const(uv);
+ result.flags
+ }
+
fn add_flags(&mut self, flags: TypeFlags) {
self.flags = self.flags | flags;
}
@@ -91,7 +97,7 @@
&ty::Error(_) => self.add_flags(TypeFlags::HAS_ERROR),
&ty::Param(_) => {
- self.add_flags(TypeFlags::HAS_TY_PARAM);
+ self.add_flags(TypeFlags::HAS_KNOWN_TY_PARAM);
self.add_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE);
}
@@ -216,7 +222,7 @@
fn add_predicate_atom(&mut self, atom: ty::PredicateKind<'_>) {
match atom {
- ty::PredicateKind::Trait(trait_pred, _constness) => {
+ ty::PredicateKind::Trait(trait_pred) => {
self.add_substs(trait_pred.trait_ref.substs);
}
ty::PredicateKind::RegionOutlives(ty::OutlivesPredicate(a, b)) => {
@@ -231,6 +237,10 @@
self.add_ty(a);
self.add_ty(b);
}
+ ty::PredicateKind::Coerce(ty::CoercePredicate { a, b }) => {
+ self.add_ty(a);
+ self.add_ty(b);
+ }
ty::PredicateKind::Projection(ty::ProjectionPredicate { projection_ty, ty }) => {
self.add_projection_ty(projection_ty);
self.add_ty(ty);
@@ -242,8 +252,8 @@
ty::PredicateKind::ClosureKind(_def_id, substs, _kind) => {
self.add_substs(substs);
}
- ty::PredicateKind::ConstEvaluatable(_def_id, substs) => {
- self.add_substs(substs);
+ ty::PredicateKind::ConstEvaluatable(uv) => {
+ self.add_unevaluated_const(uv);
}
ty::PredicateKind::ConstEquate(expected, found) => {
self.add_const(expected);
@@ -288,7 +298,7 @@
self.add_bound_var(debruijn);
}
ty::ConstKind::Param(_) => {
- self.add_flags(TypeFlags::HAS_CT_PARAM);
+ self.add_flags(TypeFlags::HAS_KNOWN_CT_PARAM);
self.add_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE);
}
ty::ConstKind::Placeholder(_) => {
@@ -300,8 +310,24 @@
}
}
- fn add_unevaluated_const(&mut self, ct: ty::Unevaluated<'tcx>) {
- self.add_substs(ct.substs);
+ fn add_unevaluated_const<P>(&mut self, ct: ty::Unevaluated<'tcx, P>) {
+ // The generic arguments of unevaluated consts are a bit special,
+ // see the `rustc-dev-guide` for more information.
+ //
+ // FIXME(@lcnr): Actually add a link here.
+ if let Some(substs) = ct.substs_ {
+ // If they are available, we treat them as ordinary generic arguments.
+ self.add_substs(substs);
+ } else {
+ // Otherwise, we add `HAS_UNKNOWN_DEFAULT_CONST_SUBSTS` to signify
+ // that our const may potentially refer to generic parameters.
+ //
+ // Note that depending on which generic parameters are actually
+ // used in this constant, we may not actually refer to any generic
+ // parameters at all.
+ self.add_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE);
+ self.add_flags(TypeFlags::HAS_UNKNOWN_DEFAULT_CONST_SUBSTS);
+ }
self.add_flags(TypeFlags::HAS_CT_PROJECTION);
}
diff --git a/compiler/rustc_middle/src/ty/fold.rs b/compiler/rustc_middle/src/ty/fold.rs
index a40210d..a04b0a7 100644
--- a/compiler/rustc_middle/src/ty/fold.rs
+++ b/compiler/rustc_middle/src/ty/fold.rs
@@ -74,8 +74,14 @@
self.has_vars_bound_at_or_above(ty::INNERMOST)
}
+ fn definitely_has_type_flags(&self, tcx: TyCtxt<'tcx>, flags: TypeFlags) -> bool {
+ self.visit_with(&mut HasTypeFlagsVisitor { tcx: Some(tcx), flags }).break_value()
+ == Some(FoundFlags)
+ }
+
fn has_type_flags(&self, flags: TypeFlags) -> bool {
- self.visit_with(&mut HasTypeFlagsVisitor { flags }).break_value() == Some(FoundFlags)
+ self.visit_with(&mut HasTypeFlagsVisitor { tcx: None, flags }).break_value()
+ == Some(FoundFlags)
}
fn has_projections(&self) -> bool {
self.has_type_flags(TypeFlags::HAS_PROJECTION)
@@ -86,8 +92,18 @@
fn references_error(&self) -> bool {
self.has_type_flags(TypeFlags::HAS_ERROR)
}
- fn has_param_types_or_consts(&self) -> bool {
- self.has_type_flags(TypeFlags::HAS_TY_PARAM | TypeFlags::HAS_CT_PARAM)
+ fn potentially_has_param_types_or_consts(&self) -> bool {
+ self.has_type_flags(
+ TypeFlags::HAS_KNOWN_TY_PARAM
+ | TypeFlags::HAS_KNOWN_CT_PARAM
+ | TypeFlags::HAS_UNKNOWN_DEFAULT_CONST_SUBSTS,
+ )
+ }
+ fn definitely_has_param_types_or_consts(&self, tcx: TyCtxt<'tcx>) -> bool {
+ self.definitely_has_type_flags(
+ tcx,
+ TypeFlags::HAS_KNOWN_TY_PARAM | TypeFlags::HAS_KNOWN_CT_PARAM,
+ )
}
fn has_infer_regions(&self) -> bool {
self.has_type_flags(TypeFlags::HAS_RE_INFER)
@@ -108,13 +124,18 @@
| TypeFlags::HAS_CT_PLACEHOLDER,
)
}
- fn needs_subst(&self) -> bool {
- self.has_type_flags(TypeFlags::NEEDS_SUBST)
+ fn potentially_needs_subst(&self) -> bool {
+ self.has_type_flags(
+ TypeFlags::KNOWN_NEEDS_SUBST | TypeFlags::HAS_UNKNOWN_DEFAULT_CONST_SUBSTS,
+ )
+ }
+ fn definitely_needs_subst(&self, tcx: TyCtxt<'tcx>) -> bool {
+ self.definitely_has_type_flags(tcx, TypeFlags::KNOWN_NEEDS_SUBST)
}
/// "Free" regions in this context means that it has any region
/// that is not (a) erased or (b) late-bound.
- fn has_free_regions(&self) -> bool {
- self.has_type_flags(TypeFlags::HAS_FREE_REGIONS)
+ fn has_free_regions(&self, tcx: TyCtxt<'tcx>) -> bool {
+ self.definitely_has_type_flags(tcx, TypeFlags::HAS_KNOWN_FREE_REGIONS)
}
fn has_erased_regions(&self) -> bool {
@@ -122,15 +143,25 @@
}
/// True if there are any un-erased free regions.
- fn has_erasable_regions(&self) -> bool {
- self.has_type_flags(TypeFlags::HAS_FREE_REGIONS)
+ fn has_erasable_regions(&self, tcx: TyCtxt<'tcx>) -> bool {
+ self.definitely_has_type_flags(tcx, TypeFlags::HAS_KNOWN_FREE_REGIONS)
+ }
+
+ /// Indicates whether this value definitely references only 'global'
+ /// generic parameters that are the same regardless of what fn we are
+ /// in. This is used for caching.
+ ///
+ /// Note that this function is pessimistic and may incorrectly return
+ /// `false`.
+ fn is_known_global(&self) -> bool {
+ !self.has_type_flags(TypeFlags::HAS_POTENTIAL_FREE_LOCAL_NAMES)
}
/// Indicates whether this value references only 'global'
/// generic parameters that are the same regardless of what fn we are
/// in. This is used for caching.
- fn is_global(&self) -> bool {
- !self.has_type_flags(TypeFlags::HAS_FREE_LOCAL_NAMES)
+ fn is_global(&self, tcx: TyCtxt<'tcx>) -> bool {
+ !self.definitely_has_type_flags(tcx, TypeFlags::HAS_KNOWN_FREE_LOCAL_NAMES)
}
/// True if there are any late-bound regions
@@ -182,6 +213,10 @@
c.super_fold_with(self)
}
+ fn fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> {
+ p.super_fold_with(self)
+ }
+
fn fold_mir_const(&mut self, c: mir::ConstantKind<'tcx>) -> mir::ConstantKind<'tcx> {
bug!("most type folders should not be folding MIR datastructures: {:?}", c)
}
@@ -189,6 +224,17 @@
pub trait TypeVisitor<'tcx>: Sized {
type BreakTy = !;
+ /// Supplies the `tcx` for an unevaluated anonymous constant in case its default substs
+ /// are not yet supplied.
+ ///
+ /// Returning `None` for this method is only recommended if the `TypeVisitor`
+ /// does not care about default anon const substs, as it ignores generic parameters,
+ /// and fetching the default substs would cause a query cycle.
+ ///
+ /// For visitors which return `None` we completely skip the default substs in `ty::Unevaluated::super_visit_with`.
+ /// This means that incorrectly returning `None` can very quickly lead to ICE or other critical bugs, so be careful and
+ /// try to return an actual `tcx` if possible.
+ fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>>;
fn visit_binder<T: TypeFoldable<'tcx>>(
&mut self,
@@ -209,6 +255,10 @@
c.super_visit_with(self)
}
+ fn visit_unevaluated_const(&mut self, uv: ty::Unevaluated<'tcx>) -> ControlFlow<Self::BreakTy> {
+ uv.super_visit_with(self)
+ }
+
fn visit_predicate(&mut self, p: ty::Predicate<'tcx>) -> ControlFlow<Self::BreakTy> {
p.super_visit_with(self)
}
@@ -301,7 +351,8 @@
value: &impl TypeFoldable<'tcx>,
callback: impl FnMut(ty::Region<'tcx>) -> bool,
) -> bool {
- struct RegionVisitor<F> {
+ struct RegionVisitor<'tcx, F> {
+ tcx: TyCtxt<'tcx>,
/// The index of a binder *just outside* the things we have
/// traversed. If we encounter a bound region bound by this
/// binder or one outer to it, it appears free. Example:
@@ -323,12 +374,16 @@
callback: F,
}
- impl<'tcx, F> TypeVisitor<'tcx> for RegionVisitor<F>
+ impl<'tcx, F> TypeVisitor<'tcx> for RegionVisitor<'tcx, F>
where
F: FnMut(ty::Region<'tcx>) -> bool,
{
type BreakTy = ();
+ fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
+ Some(self.tcx)
+ }
+
fn visit_binder<T: TypeFoldable<'tcx>>(
&mut self,
t: &Binder<'tcx, T>,
@@ -356,7 +411,7 @@
fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
// We're only interested in types involving regions
- if ty.flags().intersects(TypeFlags::HAS_FREE_REGIONS) {
+ if ty.flags().intersects(TypeFlags::HAS_POTENTIAL_FREE_REGIONS) {
ty.super_visit_with(self)
} else {
ControlFlow::CONTINUE
@@ -364,7 +419,9 @@
}
}
- value.visit_with(&mut RegionVisitor { outer_index: ty::INNERMOST, callback }).is_break()
+ value
+ .visit_with(&mut RegionVisitor { tcx: self, outer_index: ty::INNERMOST, callback })
+ .is_break()
}
}
@@ -708,7 +765,7 @@
where
T: TypeFoldable<'tcx>,
{
- let mut collector = LateBoundRegionsCollector::new(just_constraint);
+ let mut collector = LateBoundRegionsCollector::new(self, just_constraint);
let result = value.as_ref().skip_binder().visit_with(&mut collector);
assert!(result.is_continue()); // should never have stopped early
collector.regions
@@ -775,6 +832,11 @@
impl<'tcx> TypeVisitor<'tcx> for ValidateBoundVars<'tcx> {
type BreakTy = ();
+ fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
+ // Anonymous constants do not contain bound vars in their substs by default.
+ None
+ }
+
fn visit_binder<T: TypeFoldable<'tcx>>(
&mut self,
t: &Binder<'tcx, T>,
@@ -989,6 +1051,11 @@
impl<'tcx> TypeVisitor<'tcx> for HasEscapingVarsVisitor {
type BreakTy = FoundEscapingVars;
+ fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
+ // Anonymous constants do not contain bound vars in their substs by default.
+ None
+ }
+
fn visit_binder<T: TypeFoldable<'tcx>>(
&mut self,
t: &Binder<'tcx, T>,
@@ -1053,25 +1120,28 @@
struct FoundFlags;
// FIXME: Optimize for checking for infer flags
-struct HasTypeFlagsVisitor {
+struct HasTypeFlagsVisitor<'tcx> {
+ tcx: Option<TyCtxt<'tcx>>,
flags: ty::TypeFlags,
}
-impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor {
+impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor<'tcx> {
type BreakTy = FoundFlags;
+ fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
+ bug!("we shouldn't call this method as we manually look at ct substs");
+ }
#[inline]
- fn visit_ty(&mut self, t: Ty<'_>) -> ControlFlow<Self::BreakTy> {
- debug!(
- "HasTypeFlagsVisitor: t={:?} t.flags={:?} self.flags={:?}",
- t,
- t.flags(),
- self.flags
- );
- if t.flags().intersects(self.flags) {
+ fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
+ let flags = t.flags();
+ debug!("HasTypeFlagsVisitor: t={:?} flags={:?} self.flags={:?}", t, flags, self.flags);
+ if flags.intersects(self.flags) {
ControlFlow::Break(FoundFlags)
} else {
- ControlFlow::CONTINUE
+ match flags.intersects(TypeFlags::HAS_UNKNOWN_DEFAULT_CONST_SUBSTS) {
+ true if self.tcx.is_some() => UnknownConstSubstsVisitor::search(&self, t),
+ _ => ControlFlow::CONTINUE,
+ }
}
}
@@ -1093,27 +1163,144 @@
if flags.intersects(self.flags) {
ControlFlow::Break(FoundFlags)
} else {
- ControlFlow::CONTINUE
+ match flags.intersects(TypeFlags::HAS_UNKNOWN_DEFAULT_CONST_SUBSTS) {
+ true if self.tcx.is_some() => UnknownConstSubstsVisitor::search(&self, c),
+ _ => ControlFlow::CONTINUE,
+ }
+ }
+ }
+
+ #[inline]
+ fn visit_unevaluated_const(&mut self, uv: ty::Unevaluated<'tcx>) -> ControlFlow<Self::BreakTy> {
+ let flags = FlagComputation::for_unevaluated_const(uv);
+ debug!("HasTypeFlagsVisitor: uv={:?} uv.flags={:?} self.flags={:?}", uv, flags, self.flags);
+ if flags.intersects(self.flags) {
+ ControlFlow::Break(FoundFlags)
+ } else {
+ match flags.intersects(TypeFlags::HAS_UNKNOWN_DEFAULT_CONST_SUBSTS) {
+ true if self.tcx.is_some() => UnknownConstSubstsVisitor::search(&self, uv),
+ _ => ControlFlow::CONTINUE,
+ }
}
}
#[inline]
fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ControlFlow<Self::BreakTy> {
+ let flags = predicate.inner.flags;
debug!(
- "HasTypeFlagsVisitor: predicate={:?} predicate.flags={:?} self.flags={:?}",
- predicate, predicate.inner.flags, self.flags
+ "HasTypeFlagsVisitor: predicate={:?} flags={:?} self.flags={:?}",
+ predicate, flags, self.flags
);
- if predicate.inner.flags.intersects(self.flags) {
+ if flags.intersects(self.flags) {
ControlFlow::Break(FoundFlags)
} else {
+ match flags.intersects(TypeFlags::HAS_UNKNOWN_DEFAULT_CONST_SUBSTS) {
+ true if self.tcx.is_some() => UnknownConstSubstsVisitor::search(&self, predicate),
+ _ => ControlFlow::CONTINUE,
+ }
+ }
+ }
+}
+
+struct UnknownConstSubstsVisitor<'tcx> {
+ tcx: TyCtxt<'tcx>,
+ flags: ty::TypeFlags,
+}
+
+impl<'tcx> UnknownConstSubstsVisitor<'tcx> {
+ /// This is fairly cold and we don't want to
+ /// bloat the size of the `HasTypeFlagsVisitor`.
+ #[inline(never)]
+ pub fn search<T: TypeFoldable<'tcx>>(
+ visitor: &HasTypeFlagsVisitor<'tcx>,
+ v: T,
+ ) -> ControlFlow<FoundFlags> {
+ if visitor.flags.intersects(TypeFlags::MAY_NEED_DEFAULT_CONST_SUBSTS) {
+ v.super_visit_with(&mut UnknownConstSubstsVisitor {
+ tcx: visitor.tcx.unwrap(),
+ flags: visitor.flags,
+ })
+ } else {
ControlFlow::CONTINUE
}
}
}
+impl<'tcx> TypeVisitor<'tcx> for UnknownConstSubstsVisitor<'tcx> {
+ type BreakTy = FoundFlags;
+ fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
+ bug!("we shouldn't call this method as we manually look at ct substs");
+ }
+
+ fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
+ if t.flags().intersects(TypeFlags::HAS_UNKNOWN_DEFAULT_CONST_SUBSTS) {
+ t.super_visit_with(self)
+ } else {
+ ControlFlow::CONTINUE
+ }
+ }
+
+ #[inline]
+ fn visit_unevaluated_const(&mut self, uv: ty::Unevaluated<'tcx>) -> ControlFlow<Self::BreakTy> {
+ if uv.substs_.is_none() {
+ self.tcx
+ .default_anon_const_substs(uv.def.did)
+ .visit_with(&mut HasTypeFlagsVisitor { tcx: Some(self.tcx), flags: self.flags })
+ } else {
+ ControlFlow::CONTINUE
+ }
+ }
+
+ #[inline]
+ fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ControlFlow<Self::BreakTy> {
+ if predicate.inner.flags.intersects(TypeFlags::HAS_UNKNOWN_DEFAULT_CONST_SUBSTS) {
+ predicate.super_visit_with(self)
+ } else {
+ ControlFlow::CONTINUE
+ }
+ }
+}
+
+impl<'tcx> TyCtxt<'tcx> {
+ /// This is a HACK(const_generics) and should probably not be needed.
+ /// Might however be perf relevant, so who knows.
+ ///
+ /// FIXME(@lcnr): explain this function a bit more
+ pub fn expose_default_const_substs<T: TypeFoldable<'tcx>>(self, v: T) -> T {
+ v.fold_with(&mut ExposeDefaultConstSubstsFolder { tcx: self })
+ }
+}
+
+struct ExposeDefaultConstSubstsFolder<'tcx> {
+ tcx: TyCtxt<'tcx>,
+}
+
+impl<'tcx> TypeFolder<'tcx> for ExposeDefaultConstSubstsFolder<'tcx> {
+ fn tcx(&self) -> TyCtxt<'tcx> {
+ self.tcx
+ }
+
+ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
+ if ty.flags().intersects(TypeFlags::HAS_UNKNOWN_DEFAULT_CONST_SUBSTS) {
+ ty.super_fold_with(self)
+ } else {
+ ty
+ }
+ }
+
+ fn fold_predicate(&mut self, pred: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> {
+ if pred.inner.flags.intersects(TypeFlags::HAS_UNKNOWN_DEFAULT_CONST_SUBSTS) {
+ pred.super_fold_with(self)
+ } else {
+ pred
+ }
+ }
+}
+
/// Collects all the late-bound regions at the innermost binding level
/// into a hash set.
-struct LateBoundRegionsCollector {
+struct LateBoundRegionsCollector<'tcx> {
+ tcx: TyCtxt<'tcx>,
current_index: ty::DebruijnIndex,
regions: FxHashSet<ty::BoundRegionKind>,
@@ -1127,9 +1314,10 @@
just_constrained: bool,
}
-impl LateBoundRegionsCollector {
- fn new(just_constrained: bool) -> Self {
+impl LateBoundRegionsCollector<'tcx> {
+ fn new(tcx: TyCtxt<'tcx>, just_constrained: bool) -> Self {
LateBoundRegionsCollector {
+ tcx,
current_index: ty::INNERMOST,
regions: Default::default(),
just_constrained,
@@ -1137,7 +1325,11 @@
}
}
-impl<'tcx> TypeVisitor<'tcx> for LateBoundRegionsCollector {
+impl<'tcx> TypeVisitor<'tcx> for LateBoundRegionsCollector<'tcx> {
+ fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
+ Some(self.tcx)
+ }
+
fn visit_binder<T: TypeFoldable<'tcx>>(
&mut self,
t: &Binder<'tcx, T>,
diff --git a/compiler/rustc_middle/src/ty/generics.rs b/compiler/rustc_middle/src/ty/generics.rs
index 4e3f475..0f89581 100644
--- a/compiler/rustc_middle/src/ty/generics.rs
+++ b/compiler/rustc_middle/src/ty/generics.rs
@@ -198,6 +198,21 @@
_ => bug!("expected const parameter, but found another generic parameter"),
}
}
+
+ /// Returns `true` if `params` has `impl Trait`.
+ pub fn has_impl_trait(&'tcx self) -> bool {
+ self.params.iter().any(|param| {
+ matches!(
+ param.kind,
+ ty::GenericParamDefKind::Type {
+ synthetic: Some(
+ hir::SyntheticTyParamKind::ImplTrait | hir::SyntheticTyParamKind::FromAttr,
+ ),
+ ..
+ }
+ )
+ })
+ }
}
/// Bounds on generics.
diff --git a/compiler/rustc_middle/src/ty/inhabitedness/mod.rs b/compiler/rustc_middle/src/ty/inhabitedness/mod.rs
index 119cb13..77d82ee 100644
--- a/compiler/rustc_middle/src/ty/inhabitedness/mod.rs
+++ b/compiler/rustc_middle/src/ty/inhabitedness/mod.rs
@@ -9,7 +9,7 @@
mod def_id_forest;
-// The methods in this module calculate `DefIdForest`s of modules in which a
+// The methods in this module calculate `DefIdForest`s of modules in which an
// `AdtDef`/`VariantDef`/`FieldDef` is visibly uninhabited.
//
// # Example
diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs
index 95ea38d..5e5902a 100644
--- a/compiler/rustc_middle/src/ty/layout.rs
+++ b/compiler/rustc_middle/src/ty/layout.rs
@@ -1,4 +1,3 @@
-// ignore-tidy-filelength
use crate::ich::StableHashingContext;
use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags;
use crate::mir::{GeneratorLayout, GeneratorSavedLocal};
@@ -43,6 +42,7 @@
}
impl IntegerExt for Integer {
+ #[inline]
fn to_ty<'tcx>(&self, tcx: TyCtxt<'tcx>, signed: bool) -> Ty<'tcx> {
match (*self, signed) {
(I8, false) => tcx.types.u8,
@@ -113,9 +113,6 @@
let unsigned_fit = Integer::fit_unsigned(cmp::max(min as u128, max as u128));
let signed_fit = cmp::max(Integer::fit_signed(min), Integer::fit_signed(max));
- let mut min_from_extern = None;
- let min_default = I8;
-
if let Some(ity) = repr.int {
let discr = Integer::from_attr(&tcx, ity);
let fit = if ity.is_signed() { signed_fit } else { unsigned_fit };
@@ -129,19 +126,14 @@
return (discr, ity.is_signed());
}
- if repr.c() {
- match &tcx.sess.target.arch[..] {
- "hexagon" => min_from_extern = Some(I8),
- // WARNING: the ARM EABI has two variants; the one corresponding
- // to `at_least == I32` appears to be used on Linux and NetBSD,
- // but some systems may use the variant corresponding to no
- // lower bound. However, we don't run on those yet...?
- "arm" => min_from_extern = Some(I32),
- _ => min_from_extern = Some(I32),
- }
- }
-
- let at_least = min_from_extern.unwrap_or(min_default);
+ let at_least = if repr.c() {
+ // This is usually I32, however it can be different on some platforms,
+ // notably hexagon and arm-none/thumb-none
+ tcx.data_layout().c_enum_min_size
+ } else {
+ // repr(Rust) enums try to be as small as possible
+ I8
+ };
// If there are no negative values, we can use the unsigned fit.
if min >= 0 {
@@ -158,6 +150,7 @@
}
impl PrimitiveExt for Primitive {
+ #[inline]
fn to_ty<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
match *self {
Int(i, signed) => i.to_ty(tcx, signed),
@@ -169,6 +162,7 @@
/// Return an *integer* type matching this primitive.
/// Useful in particular when dealing with enum discriminants.
+ #[inline]
fn to_int_ty(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
match *self {
Int(i, signed) => i.to_ty(tcx, signed),
@@ -214,10 +208,10 @@
}
}
-fn layout_raw<'tcx>(
+fn layout_of<'tcx>(
tcx: TyCtxt<'tcx>,
query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>,
-) -> Result<&'tcx Layout, LayoutError<'tcx>> {
+) -> Result<TyAndLayout<'tcx>, LayoutError<'tcx>> {
ty::tls::with_related_context(tcx, move |icx| {
let (param_env, ty) = query.into_parts();
@@ -229,21 +223,33 @@
let icx = ty::tls::ImplicitCtxt { layout_depth: icx.layout_depth + 1, ..icx.clone() };
ty::tls::enter_context(&icx, |_| {
- let cx = LayoutCx { tcx, param_env };
- let layout = cx.layout_raw_uncached(ty);
- // Type-level uninhabitedness should always imply ABI uninhabitedness.
- if let Ok(layout) = layout {
- if tcx.conservative_is_privately_uninhabited(param_env.and(ty)) {
- assert!(layout.abi.is_uninhabited());
- }
+ let param_env = param_env.with_reveal_all_normalized(tcx);
+ let unnormalized_ty = ty;
+ let ty = tcx.normalize_erasing_regions(param_env, ty);
+ if ty != unnormalized_ty {
+ // Ensure this layout is also cached for the normalized type.
+ return tcx.layout_of(param_env.and(ty));
}
- layout
+
+ let cx = LayoutCx { tcx, param_env };
+
+ let layout = cx.layout_of_uncached(ty)?;
+ let layout = TyAndLayout { ty, layout };
+
+ cx.record_layout_for_printing(layout);
+
+ // Type-level uninhabitedness should always imply ABI uninhabitedness.
+ if tcx.conservative_is_privately_uninhabited(param_env.and(ty)) {
+ assert!(layout.abi.is_uninhabited());
+ }
+
+ Ok(layout)
})
})
}
pub fn provide(providers: &mut ty::query::Providers) {
- *providers = ty::query::Providers { layout_raw, ..*providers };
+ *providers = ty::query::Providers { layout_of, ..*providers };
}
pub struct LayoutCx<'tcx, C> {
@@ -501,14 +507,14 @@
})
}
- fn layout_raw_uncached(&self, ty: Ty<'tcx>) -> Result<&'tcx Layout, LayoutError<'tcx>> {
+ fn layout_of_uncached(&self, ty: Ty<'tcx>) -> Result<&'tcx Layout, LayoutError<'tcx>> {
let tcx = self.tcx;
let param_env = self.param_env;
let dl = self.data_layout();
let scalar_unit = |value: Primitive| {
let bits = value.size(dl).bits();
assert!(bits <= 128);
- Scalar { value, valid_range: 0..=(!0 >> (128 - bits)) }
+ Scalar { value, valid_range: WrappingRange { start: 0, end: (!0 >> (128 - bits)) } }
};
let scalar = |value: Primitive| tcx.intern_layout(Layout::scalar(self, scalar_unit(value)));
@@ -521,11 +527,14 @@
// Basic scalars.
ty::Bool => tcx.intern_layout(Layout::scalar(
self,
- Scalar { value: Int(I8, false), valid_range: 0..=1 },
+ Scalar { value: Int(I8, false), valid_range: WrappingRange { start: 0, end: 1 } },
)),
ty::Char => tcx.intern_layout(Layout::scalar(
self,
- Scalar { value: Int(I32, false), valid_range: 0..=0x10FFFF },
+ Scalar {
+ value: Int(I32, false),
+ valid_range: WrappingRange { start: 0, end: 0x10FFFF },
+ },
)),
ty::Int(ity) => scalar(Int(Integer::from_int_ty(dl, ity), true)),
ty::Uint(ity) => scalar(Int(Integer::from_uint_ty(dl, ity), false)),
@@ -535,7 +544,7 @@
}),
ty::FnPtr(_) => {
let mut ptr = scalar_unit(Pointer);
- ptr.valid_range = 1..=*ptr.valid_range.end();
+ ptr.valid_range = ptr.valid_range.with_start(1);
tcx.intern_layout(Layout::scalar(self, ptr))
}
@@ -553,7 +562,7 @@
ty::Ref(_, pointee, _) | ty::RawPtr(ty::TypeAndMut { ty: pointee, .. }) => {
let mut data_ptr = scalar_unit(Pointer);
if !ty.is_unsafe_ptr() {
- data_ptr.valid_range = 1..=*data_ptr.valid_range.end();
+ data_ptr.valid_range = data_ptr.valid_range.with_start(1);
}
let pointee = tcx.normalize_erasing_regions(param_env, pointee);
@@ -569,7 +578,7 @@
ty::Slice(_) | ty::Str => scalar_unit(Int(dl.ptr_sized_integer(), false)),
ty::Dynamic(..) => {
let mut vtable = scalar_unit(Pointer);
- vtable.valid_range = 1..=*vtable.valid_range.end();
+ vtable.valid_range = vtable.valid_range.with_start(1);
vtable
}
_ => return Err(LayoutError::Unknown(unsized_part)),
@@ -895,7 +904,9 @@
let present_first = match present_first {
Some(present_first) => present_first,
// Uninhabited because it has no variants, or only absent ones.
- None if def.is_enum() => return tcx.layout_raw(param_env.and(tcx.types.never)),
+ None if def.is_enum() => {
+ return Ok(tcx.layout_of(param_env.and(tcx.types.never))?.layout);
+ }
// If it's a struct, still compute a layout so that we can still compute the
// field offsets.
None => VariantIdx::new(0),
@@ -942,14 +953,14 @@
if let Bound::Included(start) = start {
// FIXME(eddyb) this might be incorrect - it doesn't
// account for wrap-around (end < start) ranges.
- assert!(*scalar.valid_range.start() <= start);
- scalar.valid_range = start..=*scalar.valid_range.end();
+ assert!(scalar.valid_range.start <= start);
+ scalar.valid_range.start = start;
}
if let Bound::Included(end) = end {
// FIXME(eddyb) this might be incorrect - it doesn't
// account for wrap-around (end < start) ranges.
- assert!(*scalar.valid_range.end() >= end);
- scalar.valid_range = *scalar.valid_range.start()..=end;
+ assert!(scalar.valid_range.end >= end);
+ scalar.valid_range.end = end;
}
// Update `largest_niche` if we have introduced a larger niche.
@@ -1265,7 +1276,10 @@
let tag_mask = !0u128 >> (128 - ity.size().bits());
let tag = Scalar {
value: Int(ity, signed),
- valid_range: (min as u128 & tag_mask)..=(max as u128 & tag_mask),
+ valid_range: WrappingRange {
+ start: (min as u128 & tag_mask),
+ end: (max as u128 & tag_mask),
+ },
};
let mut abi = Abi::Aggregate { sized: true };
if tag.value.size(dl) == size {
@@ -1371,11 +1385,9 @@
// Types with no meaningful known layout.
ty::Projection(_) | ty::Opaque(..) => {
- let normalized = tcx.normalize_erasing_regions(param_env, ty);
- if ty == normalized {
- return Err(LayoutError::Unknown(ty));
- }
- tcx.layout_raw(param_env.and(normalized))?
+ // NOTE(eddyb) `layout_of` query should've normalized these away,
+ // if that was possible, so there's no reason to try again here.
+ return Err(LayoutError::Unknown(ty));
}
ty::Placeholder(..) | ty::GeneratorWitness(..) | ty::Infer(_) => {
@@ -1544,7 +1556,10 @@
let max_discr = (info.variant_fields.len() - 1) as u128;
let discr_int = Integer::fit_unsigned(max_discr);
let discr_int_ty = discr_int.to_ty(tcx, false);
- let tag = Scalar { value: Primitive::Int(discr_int, false), valid_range: 0..=max_discr };
+ let tag = Scalar {
+ value: Primitive::Int(discr_int, false),
+ valid_range: WrappingRange { start: 0, end: max_discr },
+ };
let tag_layout = self.tcx.intern_layout(Layout::scalar(self, tag.clone()));
let tag_layout = TyAndLayout { ty: discr_int_ty, layout: tag_layout };
@@ -1712,7 +1727,7 @@
Ok(layout)
}
- /// This is invoked by the `layout_raw` query to record the final
+ /// This is invoked by the `layout_of` query to record the final
/// layout of each type.
#[inline(always)]
fn record_layout_for_printing(&self, layout: TyAndLayout<'tcx>) {
@@ -1727,7 +1742,9 @@
// Ignore layouts that are done with non-empty environments or
// non-monomorphic layouts, as the user only wants to see the stuff
// resulting from the final codegen session.
- if layout.ty.has_param_types_or_consts() || !self.param_env.caller_bounds().is_empty() {
+ if layout.ty.definitely_has_param_types_or_consts(self.tcx)
+ || !self.param_env.caller_bounds().is_empty()
+ {
return;
}
@@ -1771,22 +1788,18 @@
let field_info: Vec<_> = flds
.iter()
.enumerate()
- .map(|(i, &name)| match layout.field(self, i) {
- Err(err) => {
- bug!("no layout found for field {}: `{:?}`", name, err);
+ .map(|(i, &name)| {
+ let field_layout = layout.field(self, i);
+ let offset = layout.fields.offset(i);
+ let field_end = offset + field_layout.size;
+ if min_size < field_end {
+ min_size = field_end;
}
- Ok(field_layout) => {
- let offset = layout.fields.offset(i);
- let field_end = offset + field_layout.size;
- if min_size < field_end {
- min_size = field_end;
- }
- FieldInfo {
- name: name.to_string(),
- offset: offset.bytes(),
- size: field_layout.size.bytes(),
- align: field_layout.align.abi.bytes(),
- }
+ FieldInfo {
+ name: name.to_string(),
+ offset: offset.bytes(),
+ size: field_layout.size.bytes(),
+ align: field_layout.align.abi.bytes(),
}
})
.collect();
@@ -1894,7 +1907,7 @@
let tail = tcx.struct_tail_erasing_lifetimes(pointee, param_env);
match tail.kind() {
ty::Param(_) | ty::Projection(_) => {
- debug_assert!(tail.has_param_types_or_consts());
+ debug_assert!(tail.definitely_has_param_types_or_consts(tcx));
Ok(SizeSkeleton::Pointer { non_zero, tail: tcx.erase_regions(tail) })
}
_ => bug!(
@@ -2004,17 +2017,33 @@
}
impl<'tcx> HasDataLayout for TyCtxt<'tcx> {
+ #[inline]
fn data_layout(&self) -> &TargetDataLayout {
&self.data_layout
}
}
impl<'tcx> HasTyCtxt<'tcx> for TyCtxt<'tcx> {
+ #[inline]
fn tcx(&self) -> TyCtxt<'tcx> {
*self
}
}
+impl<'tcx> HasDataLayout for ty::query::TyCtxtAt<'tcx> {
+ #[inline]
+ fn data_layout(&self) -> &TargetDataLayout {
+ &self.data_layout
+ }
+}
+
+impl<'tcx> HasTyCtxt<'tcx> for ty::query::TyCtxtAt<'tcx> {
+ #[inline]
+ fn tcx(&self) -> TyCtxt<'tcx> {
+ **self
+ }
+}
+
impl<'tcx, C> HasParamEnv<'tcx> for LayoutCx<'tcx, C> {
fn param_env(&self) -> ty::ParamEnv<'tcx> {
self.param_env
@@ -2035,89 +2064,35 @@
pub type TyAndLayout<'tcx> = rustc_target::abi::TyAndLayout<'tcx, Ty<'tcx>>;
-impl<'tcx> LayoutOf for LayoutCx<'tcx, TyCtxt<'tcx>> {
+impl LayoutOf<'tcx> for LayoutCx<'tcx, TyCtxt<'tcx>> {
type Ty = Ty<'tcx>;
type TyAndLayout = Result<TyAndLayout<'tcx>, LayoutError<'tcx>>;
/// Computes the layout of a type. Note that this implicitly
- /// executes in "reveal all" mode.
+ /// executes in "reveal all" mode, and will normalize the input type.
+ #[inline]
fn layout_of(&self, ty: Ty<'tcx>) -> Self::TyAndLayout {
- let param_env = self.param_env.with_reveal_all_normalized(self.tcx);
- let ty = self.tcx.normalize_erasing_regions(param_env, ty);
- let layout = self.tcx.layout_raw(param_env.and(ty))?;
- let layout = TyAndLayout { ty, layout };
-
- // N.B., this recording is normally disabled; when enabled, it
- // can however trigger recursive invocations of `layout_of`.
- // Therefore, we execute it *after* the main query has
- // completed, to avoid problems around recursive structures
- // and the like. (Admittedly, I wasn't able to reproduce a problem
- // here, but it seems like the right thing to do. -nmatsakis)
- self.record_layout_for_printing(layout);
-
- Ok(layout)
+ self.tcx.layout_of(self.param_env.and(ty))
}
}
-impl LayoutOf for LayoutCx<'tcx, ty::query::TyCtxtAt<'tcx>> {
+impl LayoutOf<'tcx> for LayoutCx<'tcx, ty::query::TyCtxtAt<'tcx>> {
type Ty = Ty<'tcx>;
type TyAndLayout = Result<TyAndLayout<'tcx>, LayoutError<'tcx>>;
/// Computes the layout of a type. Note that this implicitly
- /// executes in "reveal all" mode.
+ /// executes in "reveal all" mode, and will normalize the input type.
+ #[inline]
fn layout_of(&self, ty: Ty<'tcx>) -> Self::TyAndLayout {
- let param_env = self.param_env.with_reveal_all_normalized(*self.tcx);
- let ty = self.tcx.normalize_erasing_regions(param_env, ty);
- let layout = self.tcx.layout_raw(param_env.and(ty))?;
- let layout = TyAndLayout { ty, layout };
-
- // N.B., this recording is normally disabled; when enabled, it
- // can however trigger recursive invocations of `layout_of`.
- // Therefore, we execute it *after* the main query has
- // completed, to avoid problems around recursive structures
- // and the like. (Admittedly, I wasn't able to reproduce a problem
- // here, but it seems like the right thing to do. -nmatsakis)
- let cx = LayoutCx { tcx: *self.tcx, param_env: self.param_env };
- cx.record_layout_for_printing(layout);
-
- Ok(layout)
+ self.tcx.layout_of(self.param_env.and(ty))
}
}
-// Helper (inherent) `layout_of` methods to avoid pushing `LayoutCx` to users.
-impl TyCtxt<'tcx> {
- /// Computes the layout of a type. Note that this implicitly
- /// executes in "reveal all" mode.
- #[inline]
- pub fn layout_of(
- self,
- param_env_and_ty: ty::ParamEnvAnd<'tcx, Ty<'tcx>>,
- ) -> Result<TyAndLayout<'tcx>, LayoutError<'tcx>> {
- let cx = LayoutCx { tcx: self, param_env: param_env_and_ty.param_env };
- cx.layout_of(param_env_and_ty.value)
- }
-}
-
-impl ty::query::TyCtxtAt<'tcx> {
- /// Computes the layout of a type. Note that this implicitly
- /// executes in "reveal all" mode.
- #[inline]
- pub fn layout_of(
- self,
- param_env_and_ty: ty::ParamEnvAnd<'tcx, Ty<'tcx>>,
- ) -> Result<TyAndLayout<'tcx>, LayoutError<'tcx>> {
- let cx = LayoutCx { tcx: self.at(self.span), param_env: param_env_and_ty.param_env };
- cx.layout_of(param_env_and_ty.value)
- }
-}
-
-impl<'tcx, C> TyAndLayoutMethods<'tcx, C> for Ty<'tcx>
+impl<'tcx, C> TyAbiInterface<'tcx, C> for Ty<'tcx>
where
- C: LayoutOf<Ty = Ty<'tcx>, TyAndLayout: MaybeResult<TyAndLayout<'tcx>>>
- + HasTyCtxt<'tcx>
- + HasParamEnv<'tcx>,
+ C: HasTyCtxt<'tcx> + HasParamEnv<'tcx>,
{
- fn for_variant(
+ fn ty_and_layout_for_variant(
this: TyAndLayout<'tcx>,
cx: &C,
variant_index: VariantIdx,
@@ -2134,8 +2109,11 @@
}
Variants::Single { index } => {
+ let tcx = cx.tcx();
+ let param_env = cx.param_env();
+
// Deny calling for_variant more than once for non-Single enums.
- if let Ok(original_layout) = cx.layout_of(this.ty).to_result() {
+ if let Ok(original_layout) = tcx.layout_of(param_env.and(this.ty)) {
assert_eq!(original_layout.variants, Variants::Single { index });
}
@@ -2145,7 +2123,6 @@
ty::Adt(def, _) => def.variants[variant_index].fields.len(),
_ => bug!(),
};
- let tcx = cx.tcx();
tcx.intern_layout(Layout {
variants: Variants::Single { index: variant_index },
fields: match NonZeroUsize::new(fields) {
@@ -2167,32 +2144,24 @@
TyAndLayout { ty: this.ty, layout }
}
- fn field(this: TyAndLayout<'tcx>, cx: &C, i: usize) -> C::TyAndLayout {
- enum TyMaybeWithLayout<C: LayoutOf> {
- Ty(C::Ty),
- TyAndLayout(C::TyAndLayout),
+ fn ty_and_layout_field(this: TyAndLayout<'tcx>, cx: &C, i: usize) -> TyAndLayout<'tcx> {
+ enum TyMaybeWithLayout<'tcx> {
+ Ty(Ty<'tcx>),
+ TyAndLayout(TyAndLayout<'tcx>),
}
- fn ty_and_layout_kind<
- C: LayoutOf<Ty = Ty<'tcx>, TyAndLayout: MaybeResult<TyAndLayout<'tcx>>>
- + HasTyCtxt<'tcx>
- + HasParamEnv<'tcx>,
- >(
+ fn field_ty_or_layout(
this: TyAndLayout<'tcx>,
- cx: &C,
+ cx: &(impl HasTyCtxt<'tcx> + HasParamEnv<'tcx>),
i: usize,
- ty: C::Ty,
- ) -> TyMaybeWithLayout<C> {
+ ) -> TyMaybeWithLayout<'tcx> {
let tcx = cx.tcx();
- let tag_layout = |tag: &Scalar| -> C::TyAndLayout {
+ let tag_layout = |tag: &Scalar| -> TyAndLayout<'tcx> {
let layout = Layout::scalar(cx, tag.clone());
- MaybeResult::from(Ok(TyAndLayout {
- layout: tcx.intern_layout(layout),
- ty: tag.value.to_ty(tcx),
- }))
+ TyAndLayout { layout: tcx.intern_layout(layout), ty: tag.value.to_ty(tcx) }
};
- match *ty.kind() {
+ match *this.ty.kind() {
ty::Bool
| ty::Char
| ty::Int(_)
@@ -2203,7 +2172,7 @@
| ty::FnDef(..)
| ty::GeneratorWitness(..)
| ty::Foreign(..)
- | ty::Dynamic(..) => bug!("TyAndLayout::field_type({:?}): not applicable", this),
+ | ty::Dynamic(..) => bug!("TyAndLayout::field({:?}): not applicable", this),
// Potentially-fat pointers.
ty::Ref(_, pointee, _) | ty::RawPtr(ty::TypeAndMut { ty: pointee, .. }) => {
@@ -2215,17 +2184,19 @@
// as the `Abi` or `FieldsShape` is checked by users.
if i == 0 {
let nil = tcx.mk_unit();
- let ptr_ty = if ty.is_unsafe_ptr() {
+ let unit_ptr_ty = if this.ty.is_unsafe_ptr() {
tcx.mk_mut_ptr(nil)
} else {
tcx.mk_mut_ref(tcx.lifetimes.re_static, nil)
};
- return TyMaybeWithLayout::TyAndLayout(MaybeResult::from(
- cx.layout_of(ptr_ty).to_result().map(|mut ptr_layout| {
- ptr_layout.ty = ty;
- ptr_layout
- }),
- ));
+
+ // NOTE(eddyb) using an empty `ParamEnv`, and `unwrap`-ing
+ // the `Result` should always work because the type is
+ // always either `*mut ()` or `&'static mut ()`.
+ return TyMaybeWithLayout::TyAndLayout(TyAndLayout {
+ ty: this.ty,
+ ..tcx.layout_of(ty::ParamEnv::reveal_all().and(unit_ptr_ty)).unwrap()
+ });
}
match tcx.struct_tail_erasing_lifetimes(pointee, cx.param_env()).kind() {
@@ -2249,7 +2220,7 @@
])
*/
}
- _ => bug!("TyAndLayout::field_type({:?}): not applicable", this),
+ _ => bug!("TyAndLayout::field({:?}): not applicable", this),
}
}
@@ -2258,9 +2229,11 @@
ty::Str => TyMaybeWithLayout::Ty(tcx.types.u8),
// Tuples, generators and closures.
- ty::Closure(_, ref substs) => {
- ty_and_layout_kind(this, cx, i, substs.as_closure().tupled_upvars_ty())
- }
+ ty::Closure(_, ref substs) => field_ty_or_layout(
+ TyAndLayout { ty: substs.as_closure().tupled_upvars_ty(), ..this },
+ cx,
+ i,
+ ),
ty::Generator(def_id, ref substs, _) => match this.variants {
Variants::Single { index } => TyMaybeWithLayout::Ty(
@@ -2303,24 +2276,42 @@
| ty::Opaque(..)
| ty::Param(_)
| ty::Infer(_)
- | ty::Error(_) => bug!("TyAndLayout::field_type: unexpected type `{}`", this.ty),
+ | ty::Error(_) => bug!("TyAndLayout::field: unexpected type `{}`", this.ty),
}
}
- cx.layout_of(match ty_and_layout_kind(this, cx, i, this.ty) {
- TyMaybeWithLayout::Ty(result) => result,
- TyMaybeWithLayout::TyAndLayout(result) => return result,
- })
+ match field_ty_or_layout(this, cx, i) {
+ TyMaybeWithLayout::Ty(field_ty) => {
+ cx.tcx().layout_of(cx.param_env().and(field_ty)).unwrap_or_else(|e| {
+ bug!(
+ "failed to get layout for `{}`: {},\n\
+ despite it being a field (#{}) of an existing layout: {:#?}",
+ field_ty,
+ e,
+ i,
+ this
+ )
+ })
+ }
+ TyMaybeWithLayout::TyAndLayout(field_layout) => field_layout,
+ }
}
- fn pointee_info_at(this: TyAndLayout<'tcx>, cx: &C, offset: Size) -> Option<PointeeInfo> {
+ fn ty_and_layout_pointee_info_at(
+ this: TyAndLayout<'tcx>,
+ cx: &C,
+ offset: Size,
+ ) -> Option<PointeeInfo> {
+ let tcx = cx.tcx();
+ let param_env = cx.param_env();
+
let addr_space_of_ty = |ty: Ty<'tcx>| {
if ty.is_fn() { cx.data_layout().instruction_address_space } else { AddressSpace::DATA }
};
let pointee_info = match *this.ty.kind() {
ty::RawPtr(mt) if offset.bytes() == 0 => {
- cx.layout_of(mt.ty).to_result().ok().map(|layout| PointeeInfo {
+ tcx.layout_of(param_env.and(mt.ty)).ok().map(|layout| PointeeInfo {
size: layout.size,
align: layout.align.abi,
safe: None,
@@ -2328,18 +2319,15 @@
})
}
ty::FnPtr(fn_sig) if offset.bytes() == 0 => {
- cx.layout_of(cx.tcx().mk_fn_ptr(fn_sig)).to_result().ok().map(|layout| {
- PointeeInfo {
- size: layout.size,
- align: layout.align.abi,
- safe: None,
- address_space: cx.data_layout().instruction_address_space,
- }
+ tcx.layout_of(param_env.and(tcx.mk_fn_ptr(fn_sig))).ok().map(|layout| PointeeInfo {
+ size: layout.size,
+ align: layout.align.abi,
+ safe: None,
+ address_space: cx.data_layout().instruction_address_space,
})
}
ty::Ref(_, ty, mt) if offset.bytes() == 0 => {
let address_space = addr_space_of_ty(ty);
- let tcx = cx.tcx();
let kind = if tcx.sess.opts.optimize == OptLevel::No {
// Use conservative pointer kind if not optimizing. This saves us the
// Freeze/Unpin queries, and can save time in the codegen backend (noalias
@@ -2368,7 +2356,7 @@
}
};
- cx.layout_of(ty).to_result().ok().map(|layout| PointeeInfo {
+ tcx.layout_of(param_env.and(ty)).ok().map(|layout| PointeeInfo {
size: layout.size,
align: layout.align.abi,
safe: Some(kind),
@@ -2456,6 +2444,7 @@
}
impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for LayoutError<'tcx> {
+ #[inline]
fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
use crate::ty::layout::LayoutError::*;
mem::discriminant(self).hash_stable(hcx, hasher);
@@ -2483,10 +2472,9 @@
// `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) if tcx.sess.opts.debugging_opts.polymorphize => tcx
+ ty::FnDef(def_id, substs) => tcx
.normalize_erasing_regions(tcx.param_env(def_id), tcx.fn_sig(def_id))
.subst(tcx, substs),
- ty::FnDef(def_id, substs) => tcx.fn_sig(def_id).subst(tcx, substs),
_ => unreachable!(),
};
@@ -2571,7 +2559,7 @@
pub trait FnAbiExt<'tcx, C>
where
- C: LayoutOf<Ty = Ty<'tcx>, TyAndLayout = TyAndLayout<'tcx>>
+ C: LayoutOf<'tcx, Ty = Ty<'tcx>, TyAndLayout = TyAndLayout<'tcx>>
+ HasDataLayout
+ HasTargetSpec
+ HasTyCtxt<'tcx>
@@ -2580,14 +2568,14 @@
/// Compute a `FnAbi` suitable for indirect calls, i.e. to `fn` pointers.
///
/// NB: this doesn't handle virtual calls - those should use `FnAbi::of_instance`
- /// instead, where the instance is a `InstanceDef::Virtual`.
+ /// instead, where the instance is an `InstanceDef::Virtual`.
fn of_fn_ptr(cx: &C, sig: ty::PolyFnSig<'tcx>, extra_args: &[Ty<'tcx>]) -> Self;
/// Compute a `FnAbi` suitable for declaring/defining an `fn` instance, and for
/// direct calls to an `fn`.
///
/// NB: that includes virtual calls, which are represented by "direct calls"
- /// to a `InstanceDef::Virtual` instance (of `<dyn Trait as Trait>::fn`).
+ /// to an `InstanceDef::Virtual` instance (of `<dyn Trait as Trait>::fn`).
fn of_instance(cx: &C, instance: ty::Instance<'tcx>, extra_args: &[Ty<'tcx>]) -> Self;
fn new_internal(
@@ -2601,68 +2589,129 @@
fn adjust_for_abi(&mut self, cx: &C, abi: SpecAbi);
}
+/// Calculates whether a function's ABI can unwind or not.
+///
+/// This takes two primary parameters:
+///
+/// * `codegen_fn_attr_flags` - these are flags calculated as part of the
+/// codegen attrs for a defined function. For function pointers this set of
+/// flags is the empty set. This is only applicable for Rust-defined
+/// functions, and generally isn't needed except for small optimizations where
+/// we try to say a function which otherwise might look like it could unwind
+/// doesn't actually unwind (such as for intrinsics and such).
+///
+/// * `abi` - this is the ABI that the function is defined with. This is the
+/// primary factor for determining whether a function can unwind or not.
+///
+/// Note that in this case unwinding is not necessarily panicking in Rust. Rust
+/// panics are implemented with unwinds on most platform (when
+/// `-Cpanic=unwind`), but this also accounts for `-Cpanic=abort` build modes.
+/// Notably unwinding is disallowed for more non-Rust ABIs unless it's
+/// specifically in the name (e.g. `"C-unwind"`). Unwinding within each ABI is
+/// defined for each ABI individually, but it always corresponds to some form of
+/// stack-based unwinding (the exact mechanism of which varies
+/// platform-by-platform).
+///
+/// Rust functions are classfied whether or not they can unwind based on the
+/// active "panic strategy". In other words Rust functions are considered to
+/// unwind in `-Cpanic=unwind` mode and cannot unwind in `-Cpanic=abort` mode.
+/// Note that Rust supports intermingling panic=abort and panic=unwind code, but
+/// only if the final panic mode is panic=abort. In this scenario any code
+/// previously compiled assuming that a function can unwind is still correct, it
+/// just never happens to actually unwind at runtime.
+///
+/// This function's answer to whether or not a function can unwind is quite
+/// impactful throughout the compiler. This affects things like:
+///
+/// * Calling a function which can't unwind means codegen simply ignores any
+/// associated unwinding cleanup.
+/// * Calling a function which can unwind from a function which can't unwind
+/// causes the `abort_unwinding_calls` MIR pass to insert a landing pad that
+/// aborts the process.
+/// * This affects whether functions have the LLVM `nounwind` attribute, which
+/// affects various optimizations and codegen.
+///
+/// FIXME: this is actually buggy with respect to Rust functions. Rust functions
+/// compiled with `-Cpanic=unwind` and referenced from another crate compiled
+/// with `-Cpanic=abort` will look like they can't unwind when in fact they
+/// might (from a foreign exception or similar).
+#[inline]
pub fn fn_can_unwind(
- panic_strategy: PanicStrategy,
+ tcx: TyCtxt<'tcx>,
codegen_fn_attr_flags: CodegenFnAttrFlags,
- call_conv: Conv,
abi: SpecAbi,
) -> bool {
- if panic_strategy != PanicStrategy::Unwind {
- // In panic=abort mode we assume nothing can unwind anywhere, so
- // optimize based on this!
- false
- } else if codegen_fn_attr_flags.contains(CodegenFnAttrFlags::UNWIND) {
- // If a specific #[unwind] attribute is present, use that.
- true
- } else if codegen_fn_attr_flags.contains(CodegenFnAttrFlags::RUSTC_ALLOCATOR_NOUNWIND) {
- // Special attribute for allocator functions, which can't unwind.
- false
- } else {
- if call_conv == Conv::Rust {
- // Any Rust method (or `extern "Rust" fn` or `extern
- // "rust-call" fn`) is explicitly allowed to unwind
- // (unless it has no-unwind attribute, handled above).
- true
- } else {
- // Anything else is either:
- //
- // 1. A foreign item using a non-Rust ABI (like `extern "C" { fn foo(); }`), or
- //
- // 2. A Rust item using a non-Rust ABI (like `extern "C" fn foo() { ... }`).
- //
- // In both of these cases, we should refer to the ABI to determine whether or not we
- // should unwind. See Rust RFC 2945 for more information on this behavior, here:
- // https://github.com/rust-lang/rfcs/blob/master/text/2945-c-unwind-abi.md
- use SpecAbi::*;
- match abi {
- C { unwind } | Stdcall { unwind } | System { unwind } | Thiscall { unwind } => {
- unwind
- }
- Cdecl
- | Fastcall
- | Vectorcall
- | Aapcs
- | Win64
- | SysV64
- | PtxKernel
- | Msp430Interrupt
- | X86Interrupt
- | AmdGpuKernel
- | EfiApi
- | AvrInterrupt
- | AvrNonBlockingInterrupt
- | CCmseNonSecureCall
- | Wasm
- | RustIntrinsic
- | PlatformIntrinsic
- | Unadjusted => false,
- // In the `if` above, we checked for functions with the Rust calling convention.
- Rust | RustCall => unreachable!(),
- }
+ // Special attribute for functions which can't unwind.
+ if codegen_fn_attr_flags.contains(CodegenFnAttrFlags::NEVER_UNWIND) {
+ return false;
+ }
+
+ // Otherwise if this isn't special then unwinding is generally determined by
+ // the ABI of the itself. ABIs like `C` have variants which also
+ // specifically allow unwinding (`C-unwind`), but not all platform-specific
+ // ABIs have such an option. Otherwise the only other thing here is Rust
+ // itself, and those ABIs are determined by the panic strategy configured
+ // for this compilation.
+ //
+ // Unfortunately at this time there's also another caveat. Rust [RFC
+ // 2945][rfc] has been accepted and is in the process of being implemented
+ // and stabilized. In this interim state we need to deal with historical
+ // rustc behavior as well as plan for future rustc behavior.
+ //
+ // Historically functions declared with `extern "C"` were marked at the
+ // codegen layer as `nounwind`. This happened regardless of `panic=unwind`
+ // or not. This is UB for functions in `panic=unwind` mode that then
+ // actually panic and unwind. Note that this behavior is true for both
+ // externally declared functions as well as Rust-defined function.
+ //
+ // To fix this UB rustc would like to change in the future to catch unwinds
+ // from function calls that may unwind within a Rust-defined `extern "C"`
+ // function and forcibly abort the process, thereby respecting the
+ // `nounwind` attribut emitted for `extern "C"`. This behavior change isn't
+ // ready to roll out, so determining whether or not the `C` family of ABIs
+ // unwinds is conditional not only on their definition but also whether the
+ // `#![feature(c_unwind)]` feature gate is active.
+ //
+ // Note that this means that unlike historical compilers rustc now, by
+ // default, unconditionally thinks that the `C` ABI may unwind. This will
+ // prevent some optimization opportunities, however, so we try to scope this
+ // change and only assume that `C` unwinds with `panic=unwind` (as opposed
+ // to `panic=abort`).
+ //
+ // Eventually the check against `c_unwind` here will ideally get removed and
+ // this'll be a little cleaner as it'll be a straightforward check of the
+ // ABI.
+ //
+ // [rfc]: https://github.com/rust-lang/rfcs/blob/master/text/2945-c-unwind-abi.md
+ use SpecAbi::*;
+ match abi {
+ C { unwind } | Stdcall { unwind } | System { unwind } | Thiscall { unwind } => {
+ unwind
+ || (!tcx.features().c_unwind && tcx.sess.panic_strategy() == PanicStrategy::Unwind)
}
+ Cdecl
+ | Fastcall
+ | Vectorcall
+ | Aapcs
+ | Win64
+ | SysV64
+ | PtxKernel
+ | Msp430Interrupt
+ | X86Interrupt
+ | AmdGpuKernel
+ | EfiApi
+ | AvrInterrupt
+ | AvrNonBlockingInterrupt
+ | CCmseNonSecureCall
+ | Wasm
+ | RustIntrinsic
+ | PlatformIntrinsic
+ | Unadjusted => false,
+ Rust | RustCall => tcx.sess.panic_strategy() == PanicStrategy::Unwind,
}
}
+#[inline]
pub fn conv_from_spec_abi(tcx: TyCtxt<'_>, abi: SpecAbi) -> Conv {
use rustc_target::spec::abi::Abi::*;
match tcx.sess.target.adjust_abi(abi) {
@@ -2695,21 +2744,16 @@
}
}
-pub fn fn_ptr_codegen_fn_attr_flags() -> CodegenFnAttrFlags {
- // Assume that fn pointers may always unwind
- CodegenFnAttrFlags::UNWIND
-}
-
impl<'tcx, C> FnAbiExt<'tcx, C> for call::FnAbi<'tcx, Ty<'tcx>>
where
- C: LayoutOf<Ty = Ty<'tcx>, TyAndLayout = TyAndLayout<'tcx>>
+ C: LayoutOf<'tcx, Ty = Ty<'tcx>, TyAndLayout = TyAndLayout<'tcx>>
+ HasDataLayout
+ HasTargetSpec
+ HasTyCtxt<'tcx>
+ HasParamEnv<'tcx>,
{
fn of_fn_ptr(cx: &C, sig: ty::PolyFnSig<'tcx>, extra_args: &[Ty<'tcx>]) -> Self {
- call::FnAbi::new_internal(cx, sig, extra_args, None, fn_ptr_codegen_fn_attr_flags(), false)
+ call::FnAbi::new_internal(cx, sig, extra_args, None, CodegenFnAttrFlags::empty(), false)
}
fn of_instance(cx: &C, instance: ty::Instance<'tcx>, extra_args: &[Ty<'tcx>]) -> Self {
@@ -2801,10 +2845,8 @@
return;
}
- if scalar.valid_range.start() < scalar.valid_range.end() {
- if *scalar.valid_range.start() > 0 {
- attrs.set(ArgAttribute::NonNull);
- }
+ if !scalar.valid_range.contains_zero() {
+ attrs.set(ArgAttribute::NonNull);
}
if let Some(pointee) = layout.pointee_info_at(cx, offset) {
@@ -2901,12 +2943,7 @@
c_variadic: sig.c_variadic,
fixed_count: inputs.len(),
conv,
- can_unwind: fn_can_unwind(
- cx.tcx().sess.panic_strategy(),
- codegen_fn_attr_flags,
- conv,
- sig.abi,
- ),
+ can_unwind: fn_can_unwind(cx.tcx(), codegen_fn_attr_flags, sig.abi),
};
fn_abi.adjust_for_abi(cx, sig.abi);
debug!("FnAbi::new_internal = {:?}", fn_abi);
@@ -2988,16 +3025,15 @@
}
}
-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>,
-{
+fn make_thin_self_ptr<'tcx>(
+ cx: &(impl HasTyCtxt<'tcx> + HasParamEnv<'tcx>),
+ layout: TyAndLayout<'tcx>,
+) -> TyAndLayout<'tcx> {
+ let tcx = cx.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)
+ tcx.mk_mut_ptr(layout.ty)
} else {
match layout.abi {
Abi::ScalarPair(..) => (),
@@ -3031,8 +3067,13 @@
// 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
+ let unit_ptr_ty = tcx.mk_mut_ptr(tcx.mk_unit());
+
+ TyAndLayout {
+ ty: fat_pointer_ty,
+
+ // NOTE(eddyb) using an empty `ParamEnv`, and `unwrap`-ing the `Result`
+ // should always work because the type is always `*mut ()`.
+ ..tcx.layout_of(ty::ParamEnv::reveal_all().and(unit_ptr_ty)).unwrap()
+ }
}
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index a6aff42..1bb9a86 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -16,7 +16,6 @@
pub use self::Variance::*;
pub use adt::*;
pub use assoc::*;
-pub use closure::*;
pub use generics::*;
pub use vtable::*;
@@ -38,13 +37,14 @@
use rustc_hir as hir;
use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LocalDefIdMap, CRATE_DEF_INDEX};
-use rustc_hir::{Constness, Node};
+use rustc_hir::Node;
use rustc_macros::HashStable;
use rustc_span::symbol::{kw, Ident, Symbol};
use rustc_span::Span;
use rustc_target::abi::Align;
use std::cmp::Ordering;
+use std::collections::BTreeMap;
use std::hash::{Hash, Hasher};
use std::ops::ControlFlow;
use std::{fmt, ptr, str};
@@ -55,6 +55,12 @@
pub use self::binding::BindingMode;
pub use self::binding::BindingMode::*;
+pub use self::closure::{
+ is_ancestor_or_same_capture, place_to_string_for_capture, BorrowKind, CaptureInfo,
+ CapturedPlace, ClosureKind, MinCaptureInformationMap, MinCaptureList,
+ RootVariableMinCaptureList, UpvarBorrow, UpvarCapture, UpvarCaptureMap, UpvarId, UpvarListMap,
+ UpvarPath, CAPTURE_STRUCT_LOCAL,
+};
pub use self::consts::{Const, ConstInt, ConstKind, InferConst, ScalarInt, Unevaluated, ValTree};
pub use self::context::{
tls, CanonicalUserType, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations,
@@ -127,6 +133,10 @@
/// via `extern crate` item and not `--extern` option or compiler built-in.
pub extern_prelude: FxHashMap<Symbol, bool>,
pub main_def: Option<MainDefinition>,
+ pub trait_impls: BTreeMap<DefId, Vec<LocalDefId>>,
+ /// A list of proc macro LocalDefIds, written out in the order in which
+ /// they are declared in the static array generated by proc_macro_harness.
+ pub proc_macros: Vec<LocalDefId>,
}
#[derive(Clone, Copy, Debug)]
@@ -176,6 +186,25 @@
Invisible,
}
+#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, HashStable, TyEncodable, TyDecodable)]
+pub enum BoundConstness {
+ /// `T: Trait`
+ NotConst,
+ /// `T: ~const Trait`
+ ///
+ /// Requires resolving to const only when we are in a const context.
+ ConstIfConst,
+}
+
+impl fmt::Display for BoundConstness {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match self {
+ Self::NotConst => f.write_str("normal"),
+ Self::ConstIfConst => f.write_str("`~const`"),
+ }
+ }
+}
+
#[derive(
Clone,
Debug,
@@ -452,11 +481,7 @@
/// 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.
- ///
- /// A trait predicate will have `Constness::Const` if it originates
- /// from a bound on a `const fn` without the `?const` opt-out (e.g.,
- /// `const fn foobar<Foo: Bar>() {}`).
- Trait(TraitPredicate<'tcx>, Constness),
+ Trait(TraitPredicate<'tcx>),
/// `where 'a: 'b`
RegionOutlives(RegionOutlivesPredicate<'tcx>),
@@ -480,10 +505,24 @@
ClosureKind(DefId, SubstsRef<'tcx>, ClosureKind),
/// `T1 <: T2`
+ ///
+ /// This obligation is created most often when we have two
+ /// unresolved type variables and hence don't have enough
+ /// information to process the subtyping obligation yet.
Subtype(SubtypePredicate<'tcx>),
+ /// `T1` coerced to `T2`
+ ///
+ /// Like a subtyping obligation, this is created most often
+ /// when we have two unresolved type variables and hence
+ /// don't have enough information to process the coercion
+ /// obligation yet. At the moment, we actually process coercions
+ /// very much like subtyping and don't handle the full coercion
+ /// logic.
+ Coerce(CoercePredicate<'tcx>),
+
/// Constant initializer must evaluate successfully.
- ConstEvaluatable(ty::WithOptConstParam<DefId>, SubstsRef<'tcx>),
+ ConstEvaluatable(ty::Unevaluated<'tcx, ()>),
/// Constants must be equal. The first component is the const that is expected.
ConstEquate(&'tcx Const<'tcx>, &'tcx Const<'tcx>),
@@ -612,6 +651,8 @@
#[derive(HashStable, TypeFoldable)]
pub struct TraitPredicate<'tcx> {
pub trait_ref: TraitRef<'tcx>,
+
+ pub constness: BoundConstness,
}
pub type PolyTraitPredicate<'tcx> = ty::Binder<'tcx, TraitPredicate<'tcx>>;
@@ -645,6 +686,9 @@
pub type PolyRegionOutlivesPredicate<'tcx> = ty::Binder<'tcx, RegionOutlivesPredicate<'tcx>>;
pub type PolyTypeOutlivesPredicate<'tcx> = ty::Binder<'tcx, TypeOutlivesPredicate<'tcx>>;
+/// Encodes that `a` must be a subtype of `b`. The `a_is_expected` flag indicates
+/// whether the `a` type is the type that we should label as "expected" when
+/// presenting user diagnostics.
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, TyEncodable, TyDecodable)]
#[derive(HashStable, TypeFoldable)]
pub struct SubtypePredicate<'tcx> {
@@ -654,6 +698,15 @@
}
pub type PolySubtypePredicate<'tcx> = ty::Binder<'tcx, SubtypePredicate<'tcx>>;
+/// Encodes that we have to coerce *from* the `a` type to the `b` type.
+#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, TyEncodable, TyDecodable)]
+#[derive(HashStable, TypeFoldable)]
+pub struct CoercePredicate<'tcx> {
+ pub a: Ty<'tcx>,
+ pub b: Ty<'tcx>,
+}
+pub type PolyCoercePredicate<'tcx> = ty::Binder<'tcx, CoercePredicate<'tcx>>;
+
/// This kind of predicate has no *direct* correspondent in the
/// syntax, but it roughly corresponds to the syntactic forms:
///
@@ -745,8 +798,11 @@
impl<'tcx> ToPredicate<'tcx> for ConstnessAnd<TraitRef<'tcx>> {
fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
- PredicateKind::Trait(ty::TraitPredicate { trait_ref: self.value }, self.constness)
- .to_predicate(tcx)
+ PredicateKind::Trait(ty::TraitPredicate {
+ trait_ref: self.value,
+ constness: self.constness,
+ })
+ .to_predicate(tcx)
}
}
@@ -754,15 +810,15 @@
fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
self.value
.map_bound(|trait_ref| {
- PredicateKind::Trait(ty::TraitPredicate { trait_ref }, self.constness)
+ PredicateKind::Trait(ty::TraitPredicate { trait_ref, constness: self.constness })
})
.to_predicate(tcx)
}
}
-impl<'tcx> ToPredicate<'tcx> for ConstnessAnd<PolyTraitPredicate<'tcx>> {
+impl<'tcx> ToPredicate<'tcx> for PolyTraitPredicate<'tcx> {
fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
- self.value.map_bound(|value| PredicateKind::Trait(value, self.constness)).to_predicate(tcx)
+ self.map_bound(PredicateKind::Trait).to_predicate(tcx)
}
}
@@ -788,11 +844,12 @@
pub fn to_opt_poly_trait_ref(self) -> Option<ConstnessAnd<PolyTraitRef<'tcx>>> {
let predicate = self.kind();
match predicate.skip_binder() {
- PredicateKind::Trait(t, constness) => {
- Some(ConstnessAnd { constness, value: predicate.rebind(t.trait_ref) })
+ PredicateKind::Trait(t) => {
+ Some(ConstnessAnd { constness: t.constness, value: predicate.rebind(t.trait_ref) })
}
PredicateKind::Projection(..)
| PredicateKind::Subtype(..)
+ | PredicateKind::Coerce(..)
| PredicateKind::RegionOutlives(..)
| PredicateKind::WellFormed(..)
| PredicateKind::ObjectSafe(..)
@@ -811,6 +868,7 @@
PredicateKind::Trait(..)
| PredicateKind::Projection(..)
| PredicateKind::Subtype(..)
+ | PredicateKind::Coerce(..)
| PredicateKind::RegionOutlives(..)
| PredicateKind::WellFormed(..)
| PredicateKind::ObjectSafe(..)
@@ -824,7 +882,7 @@
/// Represents the bounds declared on a particular set of type
/// parameters. Should eventually be generalized into a flag list of
-/// where-clauses. You can obtain a `InstantiatedPredicates` list from a
+/// where-clauses. You can obtain an `InstantiatedPredicates` list from a
/// `GenericPredicates` by using the `instantiate` method. Note that this method
/// reflects an important semantic invariant of `InstantiatedPredicates`: while
/// the `GenericPredicates` are expressed in terms of the bound type
@@ -1251,7 +1309,7 @@
Reveal::UserFacing => ParamEnvAnd { param_env: self, value },
Reveal::All => {
- if value.is_global() {
+ if value.is_known_global() {
ParamEnvAnd { param_env: self.without_caller_bounds(), value }
} else {
ParamEnvAnd { param_env: self, value }
@@ -1263,7 +1321,7 @@
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TypeFoldable)]
pub struct ConstnessAnd<T> {
- pub constness: Constness,
+ pub constness: BoundConstness,
pub value: T,
}
@@ -1271,18 +1329,18 @@
// the constness of trait bounds is being propagated correctly.
pub trait WithConstness: Sized {
#[inline]
- fn with_constness(self, constness: Constness) -> ConstnessAnd<Self> {
+ fn with_constness(self, constness: BoundConstness) -> ConstnessAnd<Self> {
ConstnessAnd { constness, value: self }
}
#[inline]
- fn with_const(self) -> ConstnessAnd<Self> {
- self.with_constness(Constness::Const)
+ fn with_const_if_const(self) -> ConstnessAnd<Self> {
+ self.with_constness(BoundConstness::ConstIfConst)
}
#[inline]
fn without_const(self) -> ConstnessAnd<Self> {
- self.with_constness(Constness::NotConst)
+ self.with_constness(BoundConstness::NotConst)
}
}
@@ -1330,7 +1388,7 @@
}
}
-/// Definition of a variant -- a struct's fields or a enum variant.
+/// Definition of a variant -- a struct's fields or an enum variant.
#[derive(Debug, HashStable)]
pub struct VariantDef {
/// `DefId` that identifies the variant itself.
@@ -1624,16 +1682,12 @@
/// crate. If you would prefer to iterate over the bodies
/// themselves, you can do `self.hir().krate().body_ids.iter()`.
pub fn body_owners(self) -> impl Iterator<Item = LocalDefId> + Captures<'tcx> + 'tcx {
- self.hir()
- .krate()
- .body_ids
- .iter()
- .map(move |&body_id| self.hir().body_owner_def_id(body_id))
+ self.hir().krate().bodies.keys().map(move |&body_id| self.hir().body_owner_def_id(body_id))
}
pub fn par_body_owners<F: Fn(LocalDefId) + sync::Sync + sync::Send>(self, f: F) {
- par_iter(&self.hir().krate().body_ids)
- .for_each(|&body_id| f(self.hir().body_owner_def_id(body_id)));
+ par_iter(&self.hir().krate().bodies)
+ .for_each(|(&body_id, _)| f(self.hir().body_owner_def_id(body_id)));
}
pub fn provided_trait_methods(self, id: DefId) -> impl 'tcx + Iterator<Item = &'tcx AssocItem> {
@@ -1980,6 +2034,7 @@
}
pub fn provide(providers: &mut ty::query::Providers) {
+ closure::provide(providers);
context::provide(providers);
erase_regions::provide(providers);
layout::provide(providers);
@@ -1991,6 +2046,7 @@
trait_impls_of: trait_def::trait_impls_of_provider,
type_uninhabited_from: inhabitedness::type_uninhabited_from,
const_param_default: consts::const_param_default,
+ vtable_allocation: vtable::vtable_allocation_provider,
..*providers
};
}
diff --git a/compiler/rustc_middle/src/ty/outlives.rs b/compiler/rustc_middle/src/ty/outlives.rs
index 86750d5..ef4ad99 100644
--- a/compiler/rustc_middle/src/ty/outlives.rs
+++ b/compiler/rustc_middle/src/ty/outlives.rs
@@ -194,7 +194,7 @@
out: &mut SmallVec<[Component<'tcx>; 4]>,
visited: &mut SsoHashSet<GenericArg<'tcx>>,
) {
- for child in parent.walk_shallow(visited) {
+ for child in parent.walk_shallow(tcx, visited) {
match child.unpack() {
GenericArgKind::Type(ty) => {
compute_components(tcx, ty, out, visited);
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index b5733bd..18b52ba 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -630,7 +630,7 @@
for (predicate, _) in bounds {
let predicate = predicate.subst(self.tcx(), substs);
let bound_predicate = predicate.kind();
- if let ty::PredicateKind::Trait(pred, _) = bound_predicate.skip_binder() {
+ 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() {
@@ -927,20 +927,21 @@
}
match ct.val {
- ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted }) => {
- if let Some(promoted) = promoted {
- p!(print_value_path(def.did, substs));
+ ty::ConstKind::Unevaluated(uv) => {
+ if let Some(promoted) = uv.promoted {
+ let substs = uv.substs_.unwrap();
+ p!(print_value_path(uv.def.did, substs));
p!(write("::{:?}", promoted));
} else {
- match self.tcx().def_kind(def.did) {
+ let tcx = self.tcx();
+ match tcx.def_kind(uv.def.did) {
DefKind::Static | DefKind::Const | DefKind::AssocConst => {
- p!(print_value_path(def.did, substs))
+ p!(print_value_path(uv.def.did, uv.substs(tcx)))
}
_ => {
- if def.is_local() {
- let span = self.tcx().def_span(def.did);
- if let Ok(snip) = self.tcx().sess.source_map().span_to_snippet(span)
- {
+ if uv.def.is_local() {
+ let span = tcx.def_span(uv.def.did);
+ if let Ok(snip) = tcx.sess.source_map().span_to_snippet(span) {
p!(write("{}", snip))
} else {
print_underscore!()
@@ -1192,7 +1193,7 @@
// Aggregates, printed as array/tuple/struct/variant construction syntax.
//
- // NB: the `has_param_types_or_consts` check ensures that we can use
+ // NB: the `potentially_has_param_types_or_consts` check ensures that we can use
// the `destructure_const` query with an empty `ty::ParamEnv` without
// introducing ICEs (e.g. via `layout_of`) from missing bounds.
// E.g. `transmute([0usize; 2]): (u8, *mut T)` needs to know `T: Sized`
@@ -1200,7 +1201,9 @@
//
// FIXME(eddyb) for `--emit=mir`/`-Z dump-mir`, we should provide the
// correct `ty::ParamEnv` to allow printing *all* constant values.
- (_, ty::Array(..) | ty::Tuple(..) | ty::Adt(..)) if !ty.has_param_types_or_consts() => {
+ (_, ty::Array(..) | ty::Tuple(..) | ty::Adt(..))
+ if !ty.potentially_has_param_types_or_consts() =>
+ {
let contents = self.tcx().destructure_const(
ty::ParamEnv::reveal_all()
.and(self.tcx().mk_const(ty::Const { val: ty::ConstKind::Value(ct), ty })),
@@ -1218,13 +1221,20 @@
}
p!(")");
}
- ty::Adt(def, substs) if def.variants.is_empty() => {
- p!(print_value_path(def.did, substs));
+ ty::Adt(def, _) if def.variants.is_empty() => {
+ self = self.typed_value(
+ |mut this| {
+ write!(this, "unreachable()")?;
+ Ok(this)
+ },
+ |this| this.print_type(ty),
+ ": ",
+ )?;
}
ty::Adt(def, substs) => {
- let variant_id =
- contents.variant.expect("destructed const of adt without variant id");
- let variant_def = &def.variants[variant_id];
+ let variant_idx =
+ contents.variant.expect("destructed const of adt without variant idx");
+ let variant_def = &def.variants[variant_idx];
p!(print_value_path(variant_def.def_id, substs));
match variant_def.ctor_kind {
@@ -2015,6 +2025,7 @@
debug!("prepare_late_bound_region_info(value: {:?})", value);
struct LateBoundRegionNameCollector<'a, 'tcx> {
+ tcx: TyCtxt<'tcx>,
used_region_names: &'a mut FxHashSet<Symbol>,
type_collector: SsoHashSet<Ty<'tcx>>,
}
@@ -2022,6 +2033,10 @@
impl<'tcx> ty::fold::TypeVisitor<'tcx> for LateBoundRegionNameCollector<'_, 'tcx> {
type BreakTy = ();
+ fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
+ Some(self.tcx)
+ }
+
fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
debug!("LateBoundRegionNameCollector::visit_region(r: {:?}, address: {:p})", r, &r);
if let ty::ReLateBound(_, ty::BoundRegion { kind: ty::BrNamed(_, name), .. }) = *r {
@@ -2051,6 +2066,7 @@
self.used_region_names.clear();
let mut collector = LateBoundRegionNameCollector {
+ tcx: self.tcx,
used_region_names: &mut self.used_region_names,
type_collector: SsoHashSet::new(),
};
@@ -2161,6 +2177,7 @@
// because `for<'tcx>` isn't possible yet.
ty::Binder<'tcx, ty::ExistentialPredicate<'tcx>>,
ty::Binder<'tcx, ty::TraitRef<'tcx>>,
+ ty::Binder<'tcx, ty::ExistentialTraitRef<'tcx>>,
ty::Binder<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
ty::Binder<'tcx, ty::FnSig<'tcx>>,
ty::Binder<'tcx, ty::TraitPredicate<'tcx>>,
@@ -2236,6 +2253,10 @@
p!(print(self.a), " <: ", print(self.b))
}
+ ty::CoercePredicate<'tcx> {
+ p!(print(self.a), " -> ", print(self.b))
+ }
+
ty::TraitPredicate<'tcx> {
p!(print(self.trait_ref.self_ty()), ": ",
print(self.trait_ref.print_only_trait_path()))
@@ -2264,13 +2285,11 @@
ty::PredicateKind<'tcx> {
match *self {
- ty::PredicateKind::Trait(ref data, constness) => {
- if let hir::Constness::Const = constness {
- p!("const ");
- }
+ ty::PredicateKind::Trait(ref data) => {
p!(print(data))
}
ty::PredicateKind::Subtype(predicate) => p!(print(predicate)),
+ ty::PredicateKind::Coerce(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)),
@@ -2283,8 +2302,8 @@
print_value_path(closure_def_id, &[]),
write("` implements the trait `{}`", kind))
}
- ty::PredicateKind::ConstEvaluatable(def, substs) => {
- p!("the constant `", print_value_path(def.did, substs), "` can be evaluated")
+ ty::PredicateKind::ConstEvaluatable(uv) => {
+ p!("the constant `", print_value_path(uv.def.did, uv.substs_.map_or(&[], |x| x)), "` can be evaluated")
}
ty::PredicateKind::ConstEquate(c1, c2) => {
p!("the constant `", print(c1), "` equals `", print(c2), "`")
@@ -2307,7 +2326,7 @@
fn for_each_def(tcx: TyCtxt<'_>, mut collect_fn: impl for<'b> FnMut(&'b Ident, Namespace, DefId)) {
// Iterate all local crate items no matter where they are defined.
let hir = tcx.hir();
- for item in hir.krate().items.values() {
+ for item in hir.krate().items() {
if item.ident.name.as_str().is_empty() || matches!(item.kind, ItemKind::Use(_, _)) {
continue;
}
diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs
index a4c36be..9d1be21 100644
--- a/compiler/rustc_middle/src/ty/relate.rs
+++ b/compiler/rustc_middle/src/ty/relate.rs
@@ -200,6 +200,33 @@
}
}
+impl<'tcx> Relate<'tcx> for ty::BoundConstness {
+ fn relate<R: TypeRelation<'tcx>>(
+ relation: &mut R,
+ a: ty::BoundConstness,
+ b: ty::BoundConstness,
+ ) -> RelateResult<'tcx, ty::BoundConstness> {
+ if a != b {
+ Err(TypeError::ConstnessMismatch(expected_found(relation, a, b)))
+ } else {
+ Ok(a)
+ }
+ }
+}
+
+impl<'tcx, T: Relate<'tcx>> Relate<'tcx> for ty::ConstnessAnd<T> {
+ fn relate<R: TypeRelation<'tcx>>(
+ relation: &mut R,
+ a: ty::ConstnessAnd<T>,
+ b: ty::ConstnessAnd<T>,
+ ) -> RelateResult<'tcx, ty::ConstnessAnd<T>> {
+ Ok(ty::ConstnessAnd {
+ constness: relation.relate(a.constness, b.constness)?,
+ value: relation.relate(a.value, b.value)?,
+ })
+ }
+}
+
impl<'tcx> Relate<'tcx> for ast::Unsafety {
fn relate<R: TypeRelation<'tcx>>(
relation: &mut R,
@@ -550,13 +577,13 @@
}
(ty::ConstKind::Unevaluated(au), ty::ConstKind::Unevaluated(bu))
- if tcx.features().const_evaluatable_checked =>
+ if tcx.features().generic_const_exprs =>
{
- tcx.try_unify_abstract_consts(((au.def, au.substs), (bu.def, bu.substs)))
+ tcx.try_unify_abstract_consts((au.shrink(), bu.shrink()))
}
// While this is slightly incorrect, it shouldn't matter for `min_const_generics`
- // and is the better alternative to waiting until `const_evaluatable_checked` can
+ // and is the better alternative to waiting until `generic_const_exprs` can
// be stabilized.
(ty::ConstKind::Unevaluated(au), ty::ConstKind::Unevaluated(bu))
if au.def == bu.def && au.promoted == bu.promoted =>
@@ -564,13 +591,13 @@
let substs = relation.relate_with_variance(
ty::Variance::Invariant,
ty::VarianceDiagInfo::default(),
- au.substs,
- bu.substs,
+ au.substs(tcx),
+ bu.substs(tcx),
)?;
return Ok(tcx.mk_const(ty::Const {
val: ty::ConstKind::Unevaluated(ty::Unevaluated {
def: au.def,
- substs,
+ substs_: Some(substs),
promoted: au.promoted,
}),
ty: a.ty,
@@ -767,7 +794,10 @@
a: ty::TraitPredicate<'tcx>,
b: ty::TraitPredicate<'tcx>,
) -> RelateResult<'tcx, ty::TraitPredicate<'tcx>> {
- Ok(ty::TraitPredicate { trait_ref: relation.relate(a.trait_ref, b.trait_ref)? })
+ Ok(ty::TraitPredicate {
+ trait_ref: relation.relate(a.trait_ref, b.trait_ref)?,
+ constness: relation.relate(a.constness, b.constness)?,
+ })
}
}
diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs
index 7290c41..89ad99d 100644
--- a/compiler/rustc_middle/src/ty/structural_impls.rs
+++ b/compiler/rustc_middle/src/ty/structural_impls.rs
@@ -8,7 +8,6 @@
use crate::ty::print::{with_no_trimmed_paths, FmtPrinter, Printer};
use crate::ty::{self, InferConst, Lift, Ty, TyCtxt};
use rustc_data_structures::functor::IdFunctor;
-use rustc_hir as hir;
use rustc_hir::def::Namespace;
use rustc_hir::def_id::CRATE_DEF_INDEX;
use rustc_index::vec::{Idx, IndexVec};
@@ -155,6 +154,9 @@
impl fmt::Debug for ty::TraitPredicate<'tcx> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ if let ty::BoundConstness::ConstIfConst = self.constness {
+ write!(f, "~const ")?;
+ }
write!(f, "TraitPredicate({:?})", self.trait_ref)
}
}
@@ -174,13 +176,9 @@
impl fmt::Debug for ty::PredicateKind<'tcx> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
- ty::PredicateKind::Trait(ref a, constness) => {
- if let hir::Constness::Const = constness {
- write!(f, "const ")?;
- }
- a.fmt(f)
- }
+ ty::PredicateKind::Trait(ref a) => a.fmt(f),
ty::PredicateKind::Subtype(ref pair) => pair.fmt(f),
+ ty::PredicateKind::Coerce(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),
@@ -191,8 +189,8 @@
ty::PredicateKind::ClosureKind(closure_def_id, closure_substs, kind) => {
write!(f, "ClosureKind({:?}, {:?}, {:?})", closure_def_id, closure_substs, kind)
}
- ty::PredicateKind::ConstEvaluatable(def_id, substs) => {
- write!(f, "ConstEvaluatable({:?}, {:?})", def_id, substs)
+ ty::PredicateKind::ConstEvaluatable(uv) => {
+ write!(f, "ConstEvaluatable({:?}, {:?})", uv.def, uv.substs_)
}
ty::PredicateKind::ConstEquate(c1, c2) => write!(f, "ConstEquate({:?}, {:?})", c1, c2),
ty::PredicateKind::TypeWellFormedFromEnv(ty) => {
@@ -242,6 +240,7 @@
crate::traits::Reveal,
crate::ty::adjustment::AutoBorrowMutability,
crate::ty::AdtKind,
+ crate::ty::BoundConstness,
// Including `BoundRegionKind` is a *bit* dubious, but direct
// references to bound region appear in `ty::Error`, and aren't
// really meant to be folded. In general, we can only fold a fully
@@ -366,7 +365,8 @@
impl<'a, 'tcx> Lift<'tcx> for ty::TraitPredicate<'a> {
type Lifted = ty::TraitPredicate<'tcx>;
fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<ty::TraitPredicate<'tcx>> {
- tcx.lift(self.trait_ref).map(|trait_ref| ty::TraitPredicate { trait_ref })
+ tcx.lift(self.trait_ref)
+ .map(|trait_ref| ty::TraitPredicate { trait_ref, constness: self.constness })
}
}
@@ -381,6 +381,13 @@
}
}
+impl<'a, 'tcx> Lift<'tcx> for ty::CoercePredicate<'a> {
+ type Lifted = ty::CoercePredicate<'tcx>;
+ fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<ty::CoercePredicate<'tcx>> {
+ tcx.lift((self.a, self.b)).map(|(a, b)| ty::CoercePredicate { a, b })
+ }
+}
+
impl<'tcx, A: Copy + Lift<'tcx>, B: Copy + Lift<'tcx>> Lift<'tcx> for ty::OutlivesPredicate<A, B> {
type Lifted = ty::OutlivesPredicate<A::Lifted, B::Lifted>;
fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
@@ -419,10 +426,9 @@
type Lifted = ty::PredicateKind<'tcx>;
fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
match self {
- ty::PredicateKind::Trait(data, constness) => {
- tcx.lift(data).map(|data| ty::PredicateKind::Trait(data, constness))
- }
+ ty::PredicateKind::Trait(data) => tcx.lift(data).map(ty::PredicateKind::Trait),
ty::PredicateKind::Subtype(data) => tcx.lift(data).map(ty::PredicateKind::Subtype),
+ ty::PredicateKind::Coerce(data) => tcx.lift(data).map(ty::PredicateKind::Coerce),
ty::PredicateKind::RegionOutlives(data) => {
tcx.lift(data).map(ty::PredicateKind::RegionOutlives)
}
@@ -441,8 +447,8 @@
ty::PredicateKind::ObjectSafe(trait_def_id) => {
Some(ty::PredicateKind::ObjectSafe(trait_def_id))
}
- ty::PredicateKind::ConstEvaluatable(def_id, substs) => {
- tcx.lift(substs).map(|substs| ty::PredicateKind::ConstEvaluatable(def_id, substs))
+ ty::PredicateKind::ConstEvaluatable(uv) => {
+ tcx.lift(uv).map(|uv| ty::PredicateKind::ConstEvaluatable(uv))
}
ty::PredicateKind::ConstEquate(c1, c2) => {
tcx.lift((c1, c2)).map(|(c1, c2)| ty::PredicateKind::ConstEquate(c1, c2))
@@ -584,6 +590,7 @@
Some(match self {
Mismatch => Mismatch,
+ ConstnessMismatch(x) => ConstnessMismatch(x),
UnsafetyMismatch(x) => UnsafetyMismatch(x),
AbiMismatch(x) => AbiMismatch(x),
Mutability => Mutability,
@@ -967,6 +974,10 @@
}
impl<'tcx> TypeFoldable<'tcx> for ty::Predicate<'tcx> {
+ fn fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
+ folder.fold_predicate(self)
+ }
+
fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
let new = self.inner.kind.fold_with(folder);
folder.tcx().reuse_or_mk_predicate(self, new)
@@ -1039,13 +1050,7 @@
match self {
ty::ConstKind::Infer(ic) => ty::ConstKind::Infer(ic.fold_with(folder)),
ty::ConstKind::Param(p) => ty::ConstKind::Param(p.fold_with(folder)),
- ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted }) => {
- ty::ConstKind::Unevaluated(ty::Unevaluated {
- def,
- substs: substs.fold_with(folder),
- promoted,
- })
- }
+ ty::ConstKind::Unevaluated(uv) => ty::ConstKind::Unevaluated(uv.fold_with(folder)),
ty::ConstKind::Value(_)
| ty::ConstKind::Bound(..)
| ty::ConstKind::Placeholder(..)
@@ -1057,7 +1062,7 @@
match *self {
ty::ConstKind::Infer(ic) => ic.visit_with(visitor),
ty::ConstKind::Param(p) => p.visit_with(visitor),
- ty::ConstKind::Unevaluated(ct) => ct.substs.visit_with(visitor),
+ ty::ConstKind::Unevaluated(uv) => uv.visit_with(visitor),
ty::ConstKind::Value(_)
| ty::ConstKind::Bound(..)
| ty::ConstKind::Placeholder(_)
@@ -1075,3 +1080,53 @@
ControlFlow::CONTINUE
}
}
+
+impl<'tcx> TypeFoldable<'tcx> for ty::Unevaluated<'tcx> {
+ fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
+ ty::Unevaluated {
+ def: self.def,
+ substs_: Some(self.substs(folder.tcx()).fold_with(folder)),
+ promoted: self.promoted,
+ }
+ }
+
+ fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
+ visitor.visit_unevaluated_const(*self)
+ }
+
+ fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
+ if let Some(tcx) = visitor.tcx_for_anon_const_substs() {
+ self.substs(tcx).visit_with(visitor)
+ } else if let Some(substs) = self.substs_ {
+ substs.visit_with(visitor)
+ } else {
+ debug!("ignoring default substs of `{:?}`", self.def);
+ ControlFlow::CONTINUE
+ }
+ }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for ty::Unevaluated<'tcx, ()> {
+ fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
+ ty::Unevaluated {
+ def: self.def,
+ substs_: Some(self.substs(folder.tcx()).fold_with(folder)),
+ promoted: self.promoted,
+ }
+ }
+
+ fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
+ visitor.visit_unevaluated_const(self.expand())
+ }
+
+ fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
+ if let Some(tcx) = visitor.tcx_for_anon_const_substs() {
+ self.substs(tcx).visit_with(visitor)
+ } else if let Some(substs) = self.substs_ {
+ substs.visit_with(visitor)
+ } else {
+ debug!("ignoring default substs of `{:?}`", self.def);
+ ControlFlow::CONTINUE
+ }
+ }
+}
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index 6a7e349..65dd61b 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -239,7 +239,7 @@
/// implements `CK<(u32, u32), Output = u32>`, where `CK` is the trait
/// specified above.
/// - U is a type parameter representing the types of its upvars, tupled up
-/// (borrowed, if appropriate; that is, if an U field represents a by-ref upvar,
+/// (borrowed, if appropriate; that is, if a U field represents a by-ref upvar,
/// and the up-var has the type `Foo`, then that field of U will be `&Foo`).
///
/// So, for example, given this function:
@@ -876,7 +876,10 @@
}
pub fn to_poly_trait_predicate(&self) -> ty::PolyTraitPredicate<'tcx> {
- self.map_bound(|trait_ref| ty::TraitPredicate { trait_ref })
+ self.map_bound(|trait_ref| ty::TraitPredicate {
+ trait_ref,
+ constness: ty::BoundConstness::NotConst,
+ })
}
}
@@ -1320,7 +1323,7 @@
/// These are regions that are stored behind a binder and must be substituted
/// with some concrete region before being used. There are two kind of
/// bound regions: early-bound, which are bound in an item's `Generics`,
-/// and are substituted by a `InternalSubsts`, and late-bound, which are part of
+/// and are substituted by an `InternalSubsts`, and late-bound, which are part of
/// higher-ranked types (e.g., `for<'a> fn(&'a ())`), and are substituted by
/// the likes of `liberate_late_bound_regions`. The distinction exists
/// because higher-ranked lifetimes aren't supported in all places. See [1][2].
@@ -1468,7 +1471,7 @@
impl<'tcx> ExistentialProjection<'tcx> {
/// Extracts the underlying existential trait reference from this projection.
/// For example, if this is a projection of `exists T. <T as Iterator>::Item == X`,
- /// then this function would return a `exists T. T: Iterator` existential trait
+ /// then this function would return an `exists T. T: Iterator` existential trait
/// reference.
pub fn trait_ref(&self, tcx: TyCtxt<'tcx>) -> ty::ExistentialTraitRef<'tcx> {
let def_id = tcx.associated_item(self.item_def_id).container.id();
@@ -1562,26 +1565,26 @@
match *self {
ty::ReVar(..) => {
- flags = flags | TypeFlags::HAS_FREE_REGIONS;
- flags = flags | TypeFlags::HAS_FREE_LOCAL_REGIONS;
+ flags = flags | TypeFlags::HAS_KNOWN_FREE_REGIONS;
+ flags = flags | TypeFlags::HAS_KNOWN_FREE_LOCAL_REGIONS;
flags = flags | TypeFlags::HAS_RE_INFER;
}
ty::RePlaceholder(..) => {
- flags = flags | TypeFlags::HAS_FREE_REGIONS;
- flags = flags | TypeFlags::HAS_FREE_LOCAL_REGIONS;
+ flags = flags | TypeFlags::HAS_KNOWN_FREE_REGIONS;
+ flags = flags | TypeFlags::HAS_KNOWN_FREE_LOCAL_REGIONS;
flags = flags | TypeFlags::HAS_RE_PLACEHOLDER;
}
ty::ReEarlyBound(..) => {
- flags = flags | TypeFlags::HAS_FREE_REGIONS;
- flags = flags | TypeFlags::HAS_FREE_LOCAL_REGIONS;
- flags = flags | TypeFlags::HAS_RE_PARAM;
+ flags = flags | TypeFlags::HAS_KNOWN_FREE_REGIONS;
+ flags = flags | TypeFlags::HAS_KNOWN_FREE_LOCAL_REGIONS;
+ flags = flags | TypeFlags::HAS_KNOWN_RE_PARAM;
}
ty::ReFree { .. } => {
- flags = flags | TypeFlags::HAS_FREE_REGIONS;
- flags = flags | TypeFlags::HAS_FREE_LOCAL_REGIONS;
+ flags = flags | TypeFlags::HAS_KNOWN_FREE_REGIONS;
+ flags = flags | TypeFlags::HAS_KNOWN_FREE_LOCAL_REGIONS;
}
ty::ReEmpty(_) | ty::ReStatic => {
- flags = flags | TypeFlags::HAS_FREE_REGIONS;
+ flags = flags | TypeFlags::HAS_KNOWN_FREE_REGIONS;
}
ty::ReLateBound(..) => {
flags = flags | TypeFlags::HAS_RE_LATE_BOUND;
diff --git a/compiler/rustc_middle/src/ty/subst.rs b/compiler/rustc_middle/src/ty/subst.rs
index 9b8d22d..2438d1a 100644
--- a/compiler/rustc_middle/src/ty/subst.rs
+++ b/compiler/rustc_middle/src/ty/subst.rs
@@ -22,7 +22,7 @@
/// An entity in the Rust type system, which can be one of
/// several kinds (types, lifetimes, and consts).
-/// To reduce memory usage, a `GenericArg` is a interned pointer,
+/// To reduce memory usage, a `GenericArg` is an interned pointer,
/// with the lowest 2 bits being reserved for a tag to
/// indicate the type (`Ty`, `Region`, or `Const`) it points to.
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
@@ -204,12 +204,12 @@
GeneratorSubsts { substs: self }
}
- /// Creates a `InternalSubsts` that maps each generic parameter to itself.
+ /// Creates an `InternalSubsts` that maps each generic parameter to itself.
pub fn identity_for_item(tcx: TyCtxt<'tcx>, def_id: DefId) -> SubstsRef<'tcx> {
Self::for_item(tcx, def_id, |param, _| tcx.mk_param_from_def(param))
}
- /// Creates a `InternalSubsts` for generic parameter definitions,
+ /// Creates an `InternalSubsts` for generic parameter definitions,
/// by calling closures to obtain each kind.
/// The closures get to observe the `InternalSubsts` as they're
/// being built, which can be used to correctly
@@ -234,7 +234,7 @@
})
}
- fn fill_item<F>(
+ pub fn fill_item<F>(
substs: &mut SmallVec<[GenericArg<'tcx>; 8]>,
tcx: TyCtxt<'tcx>,
defs: &ty::Generics,
@@ -249,7 +249,7 @@
Self::fill_single(substs, defs, mk_kind)
}
- fn fill_single<F>(
+ pub fn fill_single<F>(
substs: &mut SmallVec<[GenericArg<'tcx>; 8]>,
defs: &ty::Generics,
mk_kind: &mut F,
@@ -486,7 +486,7 @@
}
fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
- if !t.needs_subst() {
+ if !t.potentially_needs_subst() {
return t;
}
@@ -497,10 +497,6 @@
}
fn fold_const(&mut self, c: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
- if !c.needs_subst() {
- return c;
- }
-
if let ty::ConstKind::Param(p) = c.val {
self.const_for_param(p, c)
} else {
diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs
index 485be4c..1b8e942 100644
--- a/compiler/rustc_middle/src/ty/util.rs
+++ b/compiler/rustc_middle/src/ty/util.rs
@@ -225,14 +225,12 @@
}
}
- ty::Tuple(tys) => {
- if let Some((&last_ty, _)) = tys.split_last() {
- ty = last_ty.expect_ty();
- } else {
- break;
- }
+ ty::Tuple(tys) if let Some((&last_ty, _)) = tys.split_last() => {
+ ty = last_ty.expect_ty();
}
+ ty::Tuple(_) => break,
+
ty::Projection(_) | ty::Opaque(..) => {
let normalized = normalize(ty);
if ty == normalized {
@@ -540,6 +538,7 @@
expanded_cache: FxHashMap::default(),
primary_def_id: Some(def_id),
found_recursion: false,
+ found_any_recursion: false,
check_recursion: true,
tcx: self,
};
@@ -560,6 +559,7 @@
expanded_cache: FxHashMap<(DefId, SubstsRef<'tcx>), Ty<'tcx>>,
primary_def_id: Option<DefId>,
found_recursion: bool,
+ found_any_recursion: bool,
/// Whether or not to check for recursive opaque types.
/// This is `true` when we're explicitly checking for opaque type
/// recursion, and 'false' otherwise to avoid unnecessary work.
@@ -569,7 +569,7 @@
impl<'tcx> OpaqueTypeExpander<'tcx> {
fn expand_opaque_ty(&mut self, def_id: DefId, substs: SubstsRef<'tcx>) -> Option<Ty<'tcx>> {
- if self.found_recursion {
+ if self.found_any_recursion {
return None;
}
let substs = substs.fold_with(self);
@@ -591,6 +591,7 @@
} else {
// If another opaque type that we contain is recursive, then it
// will report the error, so we don't have to.
+ self.found_any_recursion = true;
self.found_recursion = def_id == *self.primary_def_id.as_ref().unwrap();
None
}
@@ -678,7 +679,7 @@
}
/// Checks whether values of this type `T` implement the `Freeze`
- /// trait -- frozen types are those that do not contain a
+ /// trait -- frozen types are those that do not contain an
/// `UnsafeCell` anywhere. This is a language concept used to
/// distinguish "true immutability", which is relevant to
/// optimization as well as the rules around static values. Note
@@ -1078,6 +1079,7 @@
expanded_cache: FxHashMap::default(),
primary_def_id: None,
found_recursion: false,
+ found_any_recursion: false,
check_recursion: false,
tcx,
};
diff --git a/compiler/rustc_middle/src/ty/vtable.rs b/compiler/rustc_middle/src/ty/vtable.rs
index 78109fc..f766cad 100644
--- a/compiler/rustc_middle/src/ty/vtable.rs
+++ b/compiler/rustc_middle/src/ty/vtable.rs
@@ -1,17 +1,39 @@
use std::convert::TryFrom;
+use std::fmt;
use crate::mir::interpret::{alloc_range, AllocId, Allocation, Pointer, Scalar, ScalarMaybeUninit};
-use crate::ty::fold::TypeFoldable;
-use crate::ty::{self, DefId, SubstsRef, Ty, TyCtxt};
+use crate::ty::{self, Instance, PolyTraitRef, Ty, TyCtxt};
use rustc_ast::Mutability;
-#[derive(Clone, Copy, Debug, PartialEq, HashStable)]
+#[derive(Clone, Copy, PartialEq, HashStable)]
pub enum VtblEntry<'tcx> {
+ /// destructor of this type (used in vtable header)
MetadataDropInPlace,
+ /// layout size of this type (used in vtable header)
MetadataSize,
+ /// layout align of this type (used in vtable header)
MetadataAlign,
+ /// non-dispatchable associated function that is excluded from trait object
Vacant,
- Method(DefId, SubstsRef<'tcx>),
+ /// dispatchable associated function
+ Method(Instance<'tcx>),
+ /// pointer to a separate supertrait vtable, can be used by trait upcasting coercion
+ TraitVPtr(PolyTraitRef<'tcx>),
+}
+
+impl<'tcx> fmt::Debug for VtblEntry<'tcx> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ // We want to call `Display` on `Instance` and `PolyTraitRef`,
+ // so we implement this manually.
+ match self {
+ VtblEntry::MetadataDropInPlace => write!(f, "MetadataDropInPlace"),
+ VtblEntry::MetadataSize => write!(f, "MetadataSize"),
+ VtblEntry::MetadataAlign => write!(f, "MetadataAlign"),
+ VtblEntry::Vacant => write!(f, "Vacant"),
+ VtblEntry::Method(instance) => write!(f, "Method({})", instance),
+ VtblEntry::TraitVPtr(trait_ref) => write!(f, "TraitVPtr({})", trait_ref),
+ }
+ }
}
pub const COMMON_VTABLE_ENTRIES: &[VtblEntry<'_>] =
@@ -21,87 +43,72 @@
pub const COMMON_VTABLE_ENTRIES_SIZE: usize = 1;
pub const COMMON_VTABLE_ENTRIES_ALIGN: usize = 2;
-impl<'tcx> TyCtxt<'tcx> {
- /// Retrieves an allocation that represents the contents of a vtable.
- /// There's a cache within `TyCtxt` so it will be deduplicated.
- pub fn vtable_allocation(
- self,
- ty: Ty<'tcx>,
- poly_trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>,
- ) -> AllocId {
- let tcx = self;
- let vtables_cache = tcx.vtables_cache.lock();
- if let Some(alloc_id) = vtables_cache.get(&(ty, poly_trait_ref)).cloned() {
- return alloc_id;
- }
- drop(vtables_cache);
+/// Retrieves an allocation that represents the contents of a vtable.
+/// Since this is a query, allocations are cached and not duplicated.
+pub(super) fn vtable_allocation_provider<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ key: (Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>),
+) -> AllocId {
+ let (ty, poly_trait_ref) = key;
- // See https://github.com/rust-lang/rust/pull/86475#discussion_r655162674
- assert!(
- !ty.needs_subst() && !poly_trait_ref.map_or(false, |trait_ref| trait_ref.needs_subst())
- );
- let param_env = ty::ParamEnv::reveal_all();
- let vtable_entries = if let Some(poly_trait_ref) = poly_trait_ref {
- let trait_ref = poly_trait_ref.with_self_ty(tcx, ty);
- let trait_ref = tcx.erase_regions(trait_ref);
+ let vtable_entries = if let Some(poly_trait_ref) = poly_trait_ref {
+ let trait_ref = poly_trait_ref.with_self_ty(tcx, ty);
+ let trait_ref = tcx.erase_regions(trait_ref);
- tcx.vtable_entries(trait_ref)
- } else {
- COMMON_VTABLE_ENTRIES
+ tcx.vtable_entries(trait_ref)
+ } else {
+ COMMON_VTABLE_ENTRIES
+ };
+
+ let layout = tcx
+ .layout_of(ty::ParamEnv::reveal_all().and(ty))
+ .expect("failed to build vtable representation");
+ assert!(!layout.is_unsized(), "can't create a vtable for an unsized type");
+ let size = layout.size.bytes();
+ let align = layout.align.abi.bytes();
+
+ let ptr_size = tcx.data_layout.pointer_size;
+ let ptr_align = tcx.data_layout.pointer_align.abi;
+
+ let vtable_size = ptr_size * u64::try_from(vtable_entries.len()).unwrap();
+ let mut vtable = Allocation::uninit(vtable_size, ptr_align, /* panic_on_fail */ true).unwrap();
+
+ // No need to do any alignment checks on the memory accesses below, because we know the
+ // allocation is correctly aligned as we created it above. Also we're only offsetting by
+ // multiples of `ptr_align`, which means that it will stay aligned to `ptr_align`.
+
+ for (idx, entry) in vtable_entries.iter().enumerate() {
+ let idx: u64 = u64::try_from(idx).unwrap();
+ let scalar = match entry {
+ VtblEntry::MetadataDropInPlace => {
+ let instance = ty::Instance::resolve_drop_in_place(tcx, ty);
+ let fn_alloc_id = tcx.create_fn_alloc(instance);
+ let fn_ptr = Pointer::from(fn_alloc_id);
+ ScalarMaybeUninit::from_pointer(fn_ptr, &tcx)
+ }
+ VtblEntry::MetadataSize => Scalar::from_uint(size, ptr_size).into(),
+ VtblEntry::MetadataAlign => Scalar::from_uint(align, ptr_size).into(),
+ VtblEntry::Vacant => continue,
+ VtblEntry::Method(instance) => {
+ // Prepare the fn ptr we write into the vtable.
+ let instance = instance.polymorphize(tcx);
+ let fn_alloc_id = tcx.create_fn_alloc(instance);
+ let fn_ptr = Pointer::from(fn_alloc_id);
+ ScalarMaybeUninit::from_pointer(fn_ptr, &tcx)
+ }
+ VtblEntry::TraitVPtr(trait_ref) => {
+ let super_trait_ref = trait_ref
+ .map_bound(|trait_ref| ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref));
+ let supertrait_alloc_id = tcx.vtable_allocation((ty, Some(super_trait_ref)));
+ let vptr = Pointer::from(supertrait_alloc_id);
+ ScalarMaybeUninit::from_pointer(vptr, &tcx)
+ }
};
-
- let layout =
- tcx.layout_of(param_env.and(ty)).expect("failed to build vtable representation");
- assert!(!layout.is_unsized(), "can't create a vtable for an unsized type");
- let size = layout.size.bytes();
- let align = layout.align.abi.bytes();
-
- let ptr_size = tcx.data_layout.pointer_size;
- let ptr_align = tcx.data_layout.pointer_align.abi;
-
- let vtable_size = ptr_size * u64::try_from(vtable_entries.len()).unwrap();
- let mut vtable =
- Allocation::uninit(vtable_size, ptr_align, /* panic_on_fail */ true).unwrap();
-
- // No need to do any alignment checks on the memory accesses below, because we know the
- // allocation is correctly aligned as we created it above. Also we're only offsetting by
- // multiples of `ptr_align`, which means that it will stay aligned to `ptr_align`.
-
- for (idx, entry) in vtable_entries.iter().enumerate() {
- let idx: u64 = u64::try_from(idx).unwrap();
- let scalar = match entry {
- VtblEntry::MetadataDropInPlace => {
- let instance = ty::Instance::resolve_drop_in_place(tcx, ty);
- let fn_alloc_id = tcx.create_fn_alloc(instance);
- let fn_ptr = Pointer::from(fn_alloc_id);
- ScalarMaybeUninit::from_pointer(fn_ptr, &tcx)
- }
- VtblEntry::MetadataSize => Scalar::from_uint(size, ptr_size).into(),
- VtblEntry::MetadataAlign => Scalar::from_uint(align, ptr_size).into(),
- VtblEntry::Vacant => continue,
- VtblEntry::Method(def_id, substs) => {
- // See https://github.com/rust-lang/rust/pull/86475#discussion_r655162674
- assert!(!substs.needs_subst());
-
- // Prepare the fn ptr we write into the vtable.
- let instance =
- ty::Instance::resolve_for_vtable(tcx, param_env, *def_id, substs)
- .expect("resolution failed during building vtable representation")
- .polymorphize(tcx);
- let fn_alloc_id = tcx.create_fn_alloc(instance);
- let fn_ptr = Pointer::from(fn_alloc_id);
- ScalarMaybeUninit::from_pointer(fn_ptr, &tcx)
- }
- };
- vtable
- .write_scalar(&tcx, alloc_range(ptr_size * idx, ptr_size), scalar)
- .expect("failed to build vtable representation");
- }
-
- vtable.mutability = Mutability::Not;
- let alloc_id = tcx.create_memory_alloc(tcx.intern_const_alloc(vtable));
- let mut vtables_cache = self.vtables_cache.lock();
- vtables_cache.insert((ty, poly_trait_ref), alloc_id);
- alloc_id
+ vtable
+ .write_scalar(&tcx, alloc_range(ptr_size * idx, ptr_size), scalar)
+ .expect("failed to build vtable representation");
}
+
+ vtable.mutability = Mutability::Not;
+ tcx.create_memory_alloc(tcx.intern_const_alloc(vtable))
}
diff --git a/compiler/rustc_middle/src/ty/walk.rs b/compiler/rustc_middle/src/ty/walk.rs
index c2fe5f1..73985cf 100644
--- a/compiler/rustc_middle/src/ty/walk.rs
+++ b/compiler/rustc_middle/src/ty/walk.rs
@@ -1,8 +1,8 @@
//! An iterator over the type substructure.
//! WARNING: this does not keep track of the region depth.
-use crate::ty;
use crate::ty::subst::{GenericArg, GenericArgKind};
+use crate::ty::{self, TyCtxt};
use rustc_data_structures::sso::SsoHashSet;
use smallvec::{self, SmallVec};
@@ -11,6 +11,7 @@
type TypeWalkerStack<'tcx> = SmallVec<[GenericArg<'tcx>; 8]>;
pub struct TypeWalker<'tcx> {
+ expose_default_const_substs: Option<TyCtxt<'tcx>>,
stack: TypeWalkerStack<'tcx>,
last_subtree: usize,
pub visited: SsoHashSet<GenericArg<'tcx>>,
@@ -25,8 +26,13 @@
/// It maintains a set of visited types and
/// skips any types that are already there.
impl<'tcx> TypeWalker<'tcx> {
- pub fn new(root: GenericArg<'tcx>) -> Self {
- Self { stack: smallvec![root], last_subtree: 1, visited: SsoHashSet::new() }
+ fn new(expose_default_const_substs: Option<TyCtxt<'tcx>>, root: GenericArg<'tcx>) -> Self {
+ Self {
+ expose_default_const_substs,
+ stack: smallvec![root],
+ last_subtree: 1,
+ visited: SsoHashSet::new(),
+ }
}
/// Skips the subtree corresponding to the last type
@@ -55,7 +61,7 @@
let next = self.stack.pop()?;
self.last_subtree = self.stack.len();
if self.visited.insert(next) {
- push_inner(&mut self.stack, next);
+ push_inner(self.expose_default_const_substs, &mut self.stack, next);
debug!("next: stack={:?}", self.stack);
return Some(next);
}
@@ -74,8 +80,8 @@
/// Foo<Bar<isize>> => { Foo<Bar<isize>>, Bar<isize>, isize }
/// [isize] => { [isize], isize }
/// ```
- pub fn walk(self) -> TypeWalker<'tcx> {
- TypeWalker::new(self)
+ pub fn walk(self, tcx: TyCtxt<'tcx>) -> TypeWalker<'tcx> {
+ TypeWalker::new(Some(tcx), self)
}
/// Iterator that walks the immediate children of `self`. Hence
@@ -87,16 +93,21 @@
/// and skips any types that are already there.
pub fn walk_shallow(
self,
+ tcx: TyCtxt<'tcx>,
visited: &mut SsoHashSet<GenericArg<'tcx>>,
) -> impl Iterator<Item = GenericArg<'tcx>> {
let mut stack = SmallVec::new();
- push_inner(&mut stack, self);
+ push_inner(Some(tcx), &mut stack, self);
stack.retain(|a| visited.insert(*a));
stack.into_iter()
}
}
impl<'tcx> super::TyS<'tcx> {
+ pub fn walk_ignoring_default_const_substs(&'tcx self) -> TypeWalker<'tcx> {
+ TypeWalker::new(None, self.into())
+ }
+
/// Iterator that walks `self` and any types reachable from
/// `self`, in depth-first order. Note that just walks the types
/// that appear in `self`, it does not descend into the fields of
@@ -107,18 +118,22 @@
/// Foo<Bar<isize>> => { Foo<Bar<isize>>, Bar<isize>, isize }
/// [isize] => { [isize], isize }
/// ```
- pub fn walk(&'tcx self) -> TypeWalker<'tcx> {
- TypeWalker::new(self.into())
+ pub fn walk(&'tcx self, tcx: TyCtxt<'tcx>) -> TypeWalker<'tcx> {
+ TypeWalker::new(Some(tcx), self.into())
}
}
-// We push `GenericArg`s on the stack in reverse order so as to
-// maintain a pre-order traversal. As of the time of this
-// writing, the fact that the traversal is pre-order is not
-// known to be significant to any code, but it seems like the
-// natural order one would expect (basically, the order of the
-// types as they are written).
-fn push_inner<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent: GenericArg<'tcx>) {
+/// We push `GenericArg`s on the stack in reverse order so as to
+/// maintain a pre-order traversal. As of the time of this
+/// writing, the fact that the traversal is pre-order is not
+/// known to be significant to any code, but it seems like the
+/// natural order one would expect (basically, the order of the
+/// types as they are written).
+fn push_inner<'tcx>(
+ expose_default_const_substs: Option<TyCtxt<'tcx>>,
+ stack: &mut TypeWalkerStack<'tcx>,
+ parent: GenericArg<'tcx>,
+) {
match parent.unpack() {
GenericArgKind::Type(parent_ty) => match *parent_ty.kind() {
ty::Bool
@@ -196,7 +211,11 @@
| ty::ConstKind::Error(_) => {}
ty::ConstKind::Unevaluated(ct) => {
- stack.extend(ct.substs.iter().rev());
+ if let Some(tcx) = expose_default_const_substs {
+ stack.extend(ct.substs(tcx).iter().rev());
+ } else if let Some(substs) = ct.substs_ {
+ stack.extend(substs.iter().rev());
+ }
}
}
}
diff --git a/compiler/rustc_mir/Cargo.toml b/compiler/rustc_mir/Cargo.toml
index 59a0c9a..3049fb3 100644
--- a/compiler/rustc_mir/Cargo.toml
+++ b/compiler/rustc_mir/Cargo.toml
@@ -1,5 +1,4 @@
[package]
-authors = ["The Rust Project Developers"]
name = "rustc_mir"
version = "0.0.0"
edition = "2018"
@@ -13,7 +12,7 @@
gsgdt = "0.1.2"
itertools = "0.9"
tracing = "0.1"
-polonius-engine = "0.12.0"
+polonius-engine = "0.13.0"
regex = "1"
rustc_middle = { path = "../rustc_middle" }
rustc_attr = { path = "../rustc_attr" }
@@ -28,6 +27,7 @@
rustc_session = { path = "../rustc_session" }
rustc_target = { path = "../rustc_target" }
rustc_trait_selection = { path = "../rustc_trait_selection" }
+rustc_traits = { path = "../rustc_traits" }
rustc_ast = { path = "../rustc_ast" }
rustc_span = { path = "../rustc_span" }
rustc_apfloat = { path = "../rustc_apfloat" }
diff --git a/compiler/rustc_mir/src/borrow_check/constraint_generation.rs b/compiler/rustc_mir/src/borrow_check/constraint_generation.rs
index 33b09dc..c849285 100644
--- a/compiler/rustc_mir/src/borrow_check/constraint_generation.rs
+++ b/compiler/rustc_mir/src/borrow_check/constraint_generation.rs
@@ -224,7 +224,7 @@
if places_conflict {
let location_index = self.location_table.mid_index(location);
- all_facts.killed.push((borrow_index, location_index));
+ all_facts.loan_killed_at.push((borrow_index, location_index));
}
}
}
@@ -243,10 +243,10 @@
location: Location,
) {
if let Some(borrow_indices) = borrow_set.local_map.get(&local) {
- all_facts.killed.reserve(borrow_indices.len());
+ all_facts.loan_killed_at.reserve(borrow_indices.len());
for &borrow_index in borrow_indices {
let location_index = location_table.mid_index(location);
- all_facts.killed.push((borrow_index, location_index));
+ all_facts.loan_killed_at.push((borrow_index, location_index));
}
}
}
diff --git a/compiler/rustc_mir/src/borrow_check/consumers.rs b/compiler/rustc_mir/src/borrow_check/consumers.rs
new file mode 100644
index 0000000..f6e4e38
--- /dev/null
+++ b/compiler/rustc_mir/src/borrow_check/consumers.rs
@@ -0,0 +1,39 @@
+//! This file provides API for compiler consumers.
+
+use rustc_hir::def_id::LocalDefId;
+use rustc_index::vec::IndexVec;
+use rustc_infer::infer::TyCtxtInferExt;
+use rustc_middle::mir::Body;
+use rustc_middle::ty::{self, TyCtxt};
+
+pub use super::{
+ facts::{AllFacts as PoloniusInput, RustcFacts},
+ location::{LocationTable, RichLocation},
+ nll::PoloniusOutput,
+ BodyWithBorrowckFacts,
+};
+
+/// This function computes Polonius facts for the given body. It makes a copy of
+/// the body because it needs to regenerate the region identifiers.
+///
+/// Note:
+/// * This function will panic if the required body was already stolen. This
+/// can, for example, happen when requesting a body of a `const` function
+/// because they are evaluated during typechecking. The panic can be avoided
+/// by overriding the `mir_borrowck` query. You can find a complete example
+/// that shows how to do this at `src/test/run-make/obtain-borrowck/`.
+/// * This function will also panic if computation of Polonius facts
+/// (`-Zpolonius` flag) is not enabled.
+///
+/// * Polonius is highly unstable, so expect regular changes in its signature or other details.
+pub fn get_body_with_borrowck_facts<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ def: ty::WithOptConstParam<LocalDefId>,
+) -> BodyWithBorrowckFacts<'tcx> {
+ let (input_body, promoted) = tcx.mir_promoted(def);
+ tcx.infer_ctxt().enter(|infcx| {
+ let input_body: &Body<'_> = &input_body.borrow();
+ let promoted: &IndexVec<_, _> = &promoted.borrow();
+ *super::do_mir_borrowck(&infcx, input_body, promoted, true).1.unwrap()
+ })
+}
diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/bound_region_errors.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/bound_region_errors.rs
new file mode 100644
index 0000000..ac30093
--- /dev/null
+++ b/compiler/rustc_mir/src/borrow_check/diagnostics/bound_region_errors.rs
@@ -0,0 +1,373 @@
+use rustc_errors::DiagnosticBuilder;
+use rustc_infer::infer::canonical::Canonical;
+use rustc_infer::infer::error_reporting::nice_region_error::NiceRegionError;
+use rustc_infer::infer::region_constraints::Constraint;
+use rustc_infer::infer::{InferCtxt, RegionResolutionError, SubregionOrigin, TyCtxtInferExt as _};
+use rustc_infer::traits::{Normalized, ObligationCause, TraitEngine, TraitEngineExt};
+use rustc_middle::ty::error::TypeError;
+use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable};
+use rustc_span::Span;
+use rustc_trait_selection::traits::query::type_op;
+use rustc_trait_selection::traits::{SelectionContext, TraitEngineExt as _};
+use rustc_traits::{type_op_ascribe_user_type_with_span, type_op_prove_predicate_with_span};
+
+use std::fmt;
+use std::rc::Rc;
+
+use crate::borrow_check::region_infer::values::RegionElement;
+use crate::borrow_check::MirBorrowckCtxt;
+
+#[derive(Clone)]
+crate struct UniverseInfo<'tcx>(UniverseInfoInner<'tcx>);
+
+/// What operation a universe was created for.
+#[derive(Clone)]
+enum UniverseInfoInner<'tcx> {
+ /// Relating two types which have binders.
+ RelateTys { expected: Ty<'tcx>, found: Ty<'tcx> },
+ /// Created from performing a `TypeOp`.
+ TypeOp(Rc<dyn TypeOpInfo<'tcx> + 'tcx>),
+ /// Any other reason.
+ Other,
+}
+
+impl UniverseInfo<'tcx> {
+ crate fn other() -> UniverseInfo<'tcx> {
+ UniverseInfo(UniverseInfoInner::Other)
+ }
+
+ crate fn relate(expected: Ty<'tcx>, found: Ty<'tcx>) -> UniverseInfo<'tcx> {
+ UniverseInfo(UniverseInfoInner::RelateTys { expected, found })
+ }
+
+ crate fn report_error(
+ &self,
+ mbcx: &mut MirBorrowckCtxt<'_, 'tcx>,
+ placeholder: ty::PlaceholderRegion,
+ error_element: RegionElement,
+ span: Span,
+ ) {
+ match self.0 {
+ UniverseInfoInner::RelateTys { expected, found } => {
+ let body_id = mbcx.infcx.tcx.hir().local_def_id_to_hir_id(mbcx.mir_def_id());
+ let err = mbcx.infcx.report_mismatched_types(
+ &ObligationCause::misc(span, body_id),
+ expected,
+ found,
+ TypeError::RegionsPlaceholderMismatch,
+ );
+ err.buffer(&mut mbcx.errors_buffer);
+ }
+ UniverseInfoInner::TypeOp(ref type_op_info) => {
+ type_op_info.report_error(mbcx, placeholder, error_element, span);
+ }
+ UniverseInfoInner::Other => {
+ // FIXME: This error message isn't great, but it doesn't show
+ // up in the existing UI tests. Consider investigating this
+ // some more.
+ mbcx.infcx
+ .tcx
+ .sess
+ .struct_span_err(span, "higher-ranked subtype error")
+ .buffer(&mut mbcx.errors_buffer);
+ }
+ }
+ }
+}
+
+crate trait ToUniverseInfo<'tcx> {
+ fn to_universe_info(self, base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx>;
+}
+
+impl<'tcx> ToUniverseInfo<'tcx>
+ for Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::prove_predicate::ProvePredicate<'tcx>>>
+{
+ fn to_universe_info(self, base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx> {
+ UniverseInfo(UniverseInfoInner::TypeOp(Rc::new(PredicateQuery {
+ canonical_query: self,
+ base_universe,
+ })))
+ }
+}
+
+impl<'tcx, T: Copy + fmt::Display + TypeFoldable<'tcx> + 'tcx> ToUniverseInfo<'tcx>
+ for Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::Normalize<T>>>
+{
+ fn to_universe_info(self, base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx> {
+ UniverseInfo(UniverseInfoInner::TypeOp(Rc::new(NormalizeQuery {
+ canonical_query: self,
+ base_universe,
+ })))
+ }
+}
+
+impl<'tcx> ToUniverseInfo<'tcx>
+ for Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::AscribeUserType<'tcx>>>
+{
+ fn to_universe_info(self, base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx> {
+ UniverseInfo(UniverseInfoInner::TypeOp(Rc::new(AscribeUserTypeQuery {
+ canonical_query: self,
+ base_universe,
+ })))
+ }
+}
+
+impl<'tcx, F, G> ToUniverseInfo<'tcx> for Canonical<'tcx, type_op::custom::CustomTypeOp<F, G>> {
+ fn to_universe_info(self, _base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx> {
+ // We can't rerun custom type ops.
+ UniverseInfo::other()
+ }
+}
+
+#[allow(unused_lifetimes)]
+trait TypeOpInfo<'tcx> {
+ /// Returns an error to be reported if rerunning the type op fails to
+ /// recover the error's cause.
+ fn fallback_error(&self, tcx: TyCtxt<'tcx>, span: Span) -> DiagnosticBuilder<'tcx>;
+
+ fn base_universe(&self) -> ty::UniverseIndex;
+
+ fn nice_error(
+ &self,
+ tcx: TyCtxt<'tcx>,
+ span: Span,
+ placeholder_region: ty::Region<'tcx>,
+ error_region: Option<ty::Region<'tcx>>,
+ ) -> Option<DiagnosticBuilder<'tcx>>;
+
+ fn report_error(
+ &self,
+ mbcx: &mut MirBorrowckCtxt<'_, 'tcx>,
+ placeholder: ty::PlaceholderRegion,
+ error_element: RegionElement,
+ span: Span,
+ ) {
+ let tcx = mbcx.infcx.tcx;
+ let base_universe = self.base_universe();
+
+ let adjusted_universe = if let Some(adjusted) =
+ placeholder.universe.as_u32().checked_sub(base_universe.as_u32())
+ {
+ adjusted
+ } else {
+ self.fallback_error(tcx, span).buffer(&mut mbcx.errors_buffer);
+ return;
+ };
+
+ let placeholder_region = tcx.mk_region(ty::RePlaceholder(ty::Placeholder {
+ name: placeholder.name,
+ universe: adjusted_universe.into(),
+ }));
+
+ let error_region =
+ if let RegionElement::PlaceholderRegion(error_placeholder) = error_element {
+ let adjusted_universe =
+ error_placeholder.universe.as_u32().checked_sub(base_universe.as_u32());
+ adjusted_universe.map(|adjusted| {
+ tcx.mk_region(ty::RePlaceholder(ty::Placeholder {
+ name: error_placeholder.name,
+ universe: adjusted.into(),
+ }))
+ })
+ } else {
+ None
+ };
+
+ debug!(?placeholder_region);
+
+ let nice_error = self.nice_error(tcx, span, placeholder_region, error_region);
+
+ if let Some(nice_error) = nice_error {
+ nice_error.buffer(&mut mbcx.errors_buffer);
+ } else {
+ self.fallback_error(tcx, span).buffer(&mut mbcx.errors_buffer);
+ }
+ }
+}
+
+struct PredicateQuery<'tcx> {
+ canonical_query:
+ Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::prove_predicate::ProvePredicate<'tcx>>>,
+ base_universe: ty::UniverseIndex,
+}
+
+impl TypeOpInfo<'tcx> for PredicateQuery<'tcx> {
+ fn fallback_error(&self, tcx: TyCtxt<'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
+ let mut err = tcx.sess.struct_span_err(span, "higher-ranked lifetime error");
+ err.note(&format!("could not prove {}", self.canonical_query.value.value.predicate));
+ err
+ }
+
+ fn base_universe(&self) -> ty::UniverseIndex {
+ self.base_universe
+ }
+
+ fn nice_error(
+ &self,
+ tcx: TyCtxt<'tcx>,
+ span: Span,
+ placeholder_region: ty::Region<'tcx>,
+ error_region: Option<ty::Region<'tcx>>,
+ ) -> Option<DiagnosticBuilder<'tcx>> {
+ tcx.infer_ctxt().enter_with_canonical(span, &self.canonical_query, |ref infcx, key, _| {
+ let mut fulfill_cx = <dyn TraitEngine<'_>>::new(tcx);
+ type_op_prove_predicate_with_span(infcx, &mut *fulfill_cx, key, Some(span));
+ try_extract_error_from_fulfill_cx(fulfill_cx, infcx, placeholder_region, error_region)
+ })
+ }
+}
+
+struct NormalizeQuery<'tcx, T> {
+ canonical_query: Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::Normalize<T>>>,
+ base_universe: ty::UniverseIndex,
+}
+
+impl<T> TypeOpInfo<'tcx> for NormalizeQuery<'tcx, T>
+where
+ T: Copy + fmt::Display + TypeFoldable<'tcx> + 'tcx,
+{
+ fn fallback_error(&self, tcx: TyCtxt<'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
+ let mut err = tcx.sess.struct_span_err(span, "higher-ranked lifetime error");
+ err.note(&format!("could not normalize `{}`", self.canonical_query.value.value.value));
+ err
+ }
+
+ fn base_universe(&self) -> ty::UniverseIndex {
+ self.base_universe
+ }
+
+ fn nice_error(
+ &self,
+ tcx: TyCtxt<'tcx>,
+ span: Span,
+ placeholder_region: ty::Region<'tcx>,
+ error_region: Option<ty::Region<'tcx>>,
+ ) -> Option<DiagnosticBuilder<'tcx>> {
+ tcx.infer_ctxt().enter_with_canonical(span, &self.canonical_query, |ref infcx, key, _| {
+ let mut fulfill_cx = <dyn TraitEngine<'_>>::new(tcx);
+
+ let mut selcx = SelectionContext::new(infcx);
+
+ // FIXME(lqd): Unify and de-duplicate the following with the actual
+ // `rustc_traits::type_op::type_op_normalize` query to allow the span we need in the
+ // `ObligationCause`. The normalization results are currently different between
+ // `AtExt::normalize` used in the query and `normalize` called below: the former fails
+ // to normalize the `nll/relate_tys/impl-fn-ignore-binder-via-bottom.rs` test. Check
+ // after #85499 lands to see if its fixes have erased this difference.
+ let (param_env, value) = key.into_parts();
+ let Normalized { value: _, obligations } = rustc_trait_selection::traits::normalize(
+ &mut selcx,
+ param_env,
+ ObligationCause::dummy_with_span(span),
+ value.value,
+ );
+ fulfill_cx.register_predicate_obligations(infcx, obligations);
+
+ try_extract_error_from_fulfill_cx(fulfill_cx, infcx, placeholder_region, error_region)
+ })
+ }
+}
+
+struct AscribeUserTypeQuery<'tcx> {
+ canonical_query: Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::AscribeUserType<'tcx>>>,
+ base_universe: ty::UniverseIndex,
+}
+
+impl TypeOpInfo<'tcx> for AscribeUserTypeQuery<'tcx> {
+ fn fallback_error(&self, tcx: TyCtxt<'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
+ // FIXME: This error message isn't great, but it doesn't show up in the existing UI tests,
+ // and is only the fallback when the nice error fails. Consider improving this some more.
+ tcx.sess.struct_span_err(span, "higher-ranked lifetime error")
+ }
+
+ fn base_universe(&self) -> ty::UniverseIndex {
+ self.base_universe
+ }
+
+ fn nice_error(
+ &self,
+ tcx: TyCtxt<'tcx>,
+ span: Span,
+ placeholder_region: ty::Region<'tcx>,
+ error_region: Option<ty::Region<'tcx>>,
+ ) -> Option<DiagnosticBuilder<'tcx>> {
+ tcx.infer_ctxt().enter_with_canonical(span, &self.canonical_query, |ref infcx, key, _| {
+ let mut fulfill_cx = <dyn TraitEngine<'_>>::new(tcx);
+ type_op_ascribe_user_type_with_span(infcx, &mut *fulfill_cx, key, Some(span)).ok()?;
+ try_extract_error_from_fulfill_cx(fulfill_cx, infcx, placeholder_region, error_region)
+ })
+ }
+}
+
+fn try_extract_error_from_fulfill_cx<'tcx>(
+ mut fulfill_cx: Box<dyn TraitEngine<'tcx> + 'tcx>,
+ infcx: &InferCtxt<'_, 'tcx>,
+ placeholder_region: ty::Region<'tcx>,
+ error_region: Option<ty::Region<'tcx>>,
+) -> Option<DiagnosticBuilder<'tcx>> {
+ let tcx = infcx.tcx;
+
+ // We generally shouldn't have errors here because the query was
+ // already run, but there's no point using `delay_span_bug`
+ // when we're going to emit an error here anyway.
+ let _errors = fulfill_cx.select_all_or_error(infcx).err().unwrap_or_else(Vec::new);
+
+ let (sub_region, cause) = infcx.with_region_constraints(|region_constraints| {
+ debug!(?region_constraints);
+ region_constraints.constraints.iter().find_map(|(constraint, cause)| {
+ match *constraint {
+ Constraint::RegSubReg(sub, sup) if sup == placeholder_region && sup != sub => {
+ Some((sub, cause.clone()))
+ }
+ // FIXME: Should this check the universe of the var?
+ Constraint::VarSubReg(vid, sup) if sup == placeholder_region => {
+ Some((tcx.mk_region(ty::ReVar(vid)), cause.clone()))
+ }
+ _ => None,
+ }
+ })
+ })?;
+
+ debug!(?sub_region, ?cause);
+ let nice_error = match (error_region, sub_region) {
+ (Some(error_region), &ty::ReVar(vid)) => NiceRegionError::new(
+ infcx,
+ RegionResolutionError::SubSupConflict(
+ vid,
+ infcx.region_var_origin(vid),
+ cause.clone(),
+ error_region,
+ cause.clone(),
+ placeholder_region,
+ ),
+ ),
+ (Some(error_region), _) => NiceRegionError::new(
+ infcx,
+ RegionResolutionError::ConcreteFailure(cause.clone(), error_region, placeholder_region),
+ ),
+ // Note universe here is wrong...
+ (None, &ty::ReVar(vid)) => NiceRegionError::new(
+ infcx,
+ RegionResolutionError::UpperBoundUniverseConflict(
+ vid,
+ infcx.region_var_origin(vid),
+ infcx.universe_of_region(sub_region),
+ cause.clone(),
+ placeholder_region,
+ ),
+ ),
+ (None, _) => NiceRegionError::new(
+ infcx,
+ RegionResolutionError::ConcreteFailure(cause.clone(), sub_region, placeholder_region),
+ ),
+ };
+ nice_error.try_report_from_nll().or_else(|| {
+ if let SubregionOrigin::Subtype(trace) = cause {
+ Some(
+ infcx.report_and_explain_type_error(*trace, &TypeError::RegionsPlaceholderMismatch),
+ )
+ } else {
+ None
+ }
+ })
+}
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 2e854ea..6561fe3 100644
--- a/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs
+++ b/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs
@@ -12,7 +12,7 @@
use rustc_middle::ty::{self, suggest_constraining_type_param, Ty};
use rustc_span::source_map::DesugaringKind;
use rustc_span::symbol::sym;
-use rustc_span::{MultiSpan, Span, DUMMY_SP};
+use rustc_span::{BytePos, MultiSpan, Span, DUMMY_SP};
use rustc_trait_selection::infer::InferCtxtExt;
use crate::dataflow::drop_flag_effects;
@@ -320,7 +320,7 @@
.map(|n| format!("`{}`", n))
.unwrap_or_else(|| "the mutable reference".to_string()),
),
- format!("&mut *"),
+ "&mut *".to_string(),
Applicability::MachineApplicable,
);
}
@@ -825,7 +825,7 @@
// We're going to want to traverse the first borrowed place to see if we can find
// 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.
+ // second borrowed place for the same union and an access to a different field.
for (place_base, elem) in first_borrowed_place.iter_projections().rev() {
match elem {
ProjectionElem::Field(field, _) if union_ty(place_base).is_some() => {
@@ -838,7 +838,7 @@
})
.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.
+ // borrowed place and look for an access to a different field of the same union.
for (place_base, elem) in second_borrowed_place.iter_projections().rev() {
if let ProjectionElem::Field(field, _) = elem {
if let Some(union_ty) = union_ty(place_base) {
@@ -1393,18 +1393,19 @@
let tcx = self.infcx.tcx;
let args_span = use_span.args_or_use();
- let suggestion = match tcx.sess.source_map().span_to_snippet(args_span) {
- Ok(mut string) => {
+ let (sugg_span, suggestion) = match tcx.sess.source_map().span_to_snippet(args_span) {
+ Ok(string) => {
if string.starts_with("async ") {
- string.insert_str(6, "move ");
+ let pos = args_span.lo() + BytePos(6);
+ (args_span.with_lo(pos).with_hi(pos), "move ".to_string())
} else if string.starts_with("async|") {
- string.insert_str(5, " move");
+ let pos = args_span.lo() + BytePos(5);
+ (args_span.with_lo(pos).with_hi(pos), " move".to_string())
} else {
- string.insert_str(0, "move ");
- };
- string
+ (args_span.shrink_to_lo(), "move ".to_string())
+ }
}
- Err(_) => "move |<args>| <body>".to_string(),
+ Err(_) => (args_span, "move |<args>| <body>".to_string()),
};
let kind = match use_span.generator_kind() {
Some(generator_kind) => match generator_kind {
@@ -1420,8 +1421,8 @@
let mut err =
self.cannot_capture_in_long_lived_closure(args_span, kind, captured_var, var_span);
- err.span_suggestion(
- args_span,
+ err.span_suggestion_verbose(
+ sugg_span,
&format!(
"to force the {} to take ownership of {} (and any \
other referenced variables), use the `move` keyword",
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 76de010..f40a2db 100644
--- a/compiler/rustc_mir/src/borrow_check/diagnostics/explain_borrow.rs
+++ b/compiler/rustc_mir/src/borrow_check/diagnostics/explain_borrow.rs
@@ -606,7 +606,7 @@
/// Checks if a borrowed value was captured by a trait object. We do this by
/// looking forward in the MIR from the reserve location and checking if we see
- /// a unsized cast to a trait object on our data.
+ /// an unsized cast to a trait object on our data.
fn was_captured_by_trait_object(&self, borrow: &BorrowData<'tcx>) -> bool {
// Start at the reserve location, find the place that we want to see cast to a trait object.
let location = borrow.reserve_location;
@@ -666,7 +666,7 @@
}
_ => {}
},
- // If we see a unsized cast, then if it is our data we should check
+ // If we see an unsized cast, then if it is our data we should check
// whether it is being cast to a trait object.
Rvalue::Cast(CastKind::Pointer(PointerCast::Unsize), operand, ty) => {
match operand {
diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs
index 1bb8c7e..55c6410 100644
--- a/compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs
+++ b/compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs
@@ -28,12 +28,14 @@
mod region_name;
mod var_name;
+mod bound_region_errors;
mod conflict_errors;
mod explain_borrow;
mod move_errors;
mod mutability_errors;
mod region_errors;
+crate use bound_region_errors::{ToUniverseInfo, UniverseInfo};
crate use mutability_errors::AccessKind;
crate use outlives_suggestion::OutlivesSuggestionBuilder;
crate use region_errors::{ErrorConstraintInfo, RegionErrorKind, RegionErrors};
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 3f87d9c..66e0632 100644
--- a/compiler/rustc_mir/src/borrow_check/diagnostics/move_errors.rs
+++ b/compiler/rustc_mir/src/borrow_check/diagnostics/move_errors.rs
@@ -1,8 +1,10 @@
use rustc_errors::{Applicability, DiagnosticBuilder};
+use rustc_infer::infer::TyCtxtInferExt;
use rustc_middle::mir::*;
use rustc_middle::ty;
use rustc_span::source_map::DesugaringKind;
-use rustc_span::{sym, Span};
+use rustc_span::{sym, Span, DUMMY_SP};
+use rustc_trait_selection::traits::type_known_to_meet_bound_modulo_regions;
use crate::borrow_check::diagnostics::UseSpans;
use crate::borrow_check::prefixes::PrefixSet;
@@ -384,36 +386,48 @@
}
}
};
- if let Ok(snippet) = self.infcx.tcx.sess.source_map().span_to_snippet(span) {
- let def_id = match *move_place.ty(self.body, self.infcx.tcx).ty.kind() {
- ty::Adt(self_def, _) => self_def.did,
- ty::Foreign(def_id)
- | ty::FnDef(def_id, _)
- | ty::Closure(def_id, _)
- | ty::Generator(def_id, ..)
- | ty::Opaque(def_id, _) => def_id,
- _ => return err,
+ let ty = move_place.ty(self.body, self.infcx.tcx).ty;
+ let def_id = match *ty.kind() {
+ ty::Adt(self_def, _) => self_def.did,
+ ty::Foreign(def_id)
+ | ty::FnDef(def_id, _)
+ | ty::Closure(def_id, _)
+ | ty::Generator(def_id, ..)
+ | ty::Opaque(def_id, _) => def_id,
+ _ => return err,
+ };
+ let is_option = self.infcx.tcx.is_diagnostic_item(sym::option_type, def_id);
+ let is_result = self.infcx.tcx.is_diagnostic_item(sym::result_type, def_id);
+ if (is_option || is_result) && use_spans.map_or(true, |v| !v.for_closure()) {
+ err.span_suggestion_verbose(
+ span.shrink_to_hi(),
+ &format!(
+ "consider borrowing the `{}`'s content",
+ if is_option { "Option" } else { "Result" }
+ ),
+ ".as_ref()".to_string(),
+ Applicability::MaybeIncorrect,
+ );
+ } else if matches!(span.desugaring_kind(), Some(DesugaringKind::ForLoop(_))) {
+ let suggest = match self.infcx.tcx.get_diagnostic_item(sym::IntoIterator) {
+ Some(def_id) => self.infcx.tcx.infer_ctxt().enter(|infcx| {
+ type_known_to_meet_bound_modulo_regions(
+ &infcx,
+ self.param_env,
+ infcx
+ .tcx
+ .mk_imm_ref(infcx.tcx.lifetimes.re_erased, infcx.tcx.erase_regions(ty)),
+ def_id,
+ DUMMY_SP,
+ )
+ }),
+ _ => false,
};
- let is_option = self.infcx.tcx.is_diagnostic_item(sym::option_type, def_id);
- let is_result = self.infcx.tcx.is_diagnostic_item(sym::result_type, def_id);
- if (is_option || is_result) && use_spans.map_or(true, |v| !v.for_closure()) {
- err.span_suggestion(
- span,
- &format!(
- "consider borrowing the `{}`'s content",
- if is_option { "Option" } else { "Result" }
- ),
- format!("{}.as_ref()", snippet),
- Applicability::MaybeIncorrect,
- );
- } else if matches!(span.desugaring_kind(), Some(DesugaringKind::ForLoop(_)))
- && self.infcx.tcx.is_diagnostic_item(sym::vec_type, def_id)
- {
- // FIXME: suggest for anything that implements `IntoIterator`.
- err.span_suggestion(
- span,
- "consider iterating over a slice of the `Vec<_>`'s content",
- format!("&{}", snippet),
+ if suggest {
+ err.span_suggestion_verbose(
+ span.shrink_to_lo(),
+ &format!("consider iterating over a slice of the `{}`'s content", ty),
+ "&".to_string(),
Applicability::MaybeIncorrect,
);
}
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 671d947..4e079ed 100644
--- a/compiler/rustc_mir/src/borrow_check/diagnostics/mutability_errors.rs
+++ b/compiler/rustc_mir/src/borrow_check/diagnostics/mutability_errors.rs
@@ -5,11 +5,14 @@
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_middle::{
hir::place::PlaceBase,
- mir::{self, ClearCrossCrate, Local, LocalDecl, LocalInfo, LocalKind, Location},
+ mir::{
+ self, BindingForm, ClearCrossCrate, ImplicitSelfKind, Local, LocalDecl, LocalInfo,
+ LocalKind, Location,
+ },
};
use rustc_span::source_map::DesugaringKind;
use rustc_span::symbol::{kw, Symbol};
-use rustc_span::Span;
+use rustc_span::{BytePos, Span};
use crate::borrow_check::diagnostics::BorrowedContentSource;
use crate::borrow_check::MirBorrowckCtxt;
@@ -72,7 +75,7 @@
// If the place is immutable then:
//
- // - Either we deref a immutable ref to get to our final place.
+ // - Either we deref an 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.
@@ -241,8 +244,74 @@
.map(|l| mut_borrow_of_mutable_ref(l, self.local_names[local]))
.unwrap_or(false) =>
{
+ let decl = &self.body.local_decls[local];
err.span_label(span, format!("cannot {ACT}", ACT = act));
- err.span_label(span, "try removing `&mut` here");
+ if let Some(mir::Statement {
+ source_info,
+ kind:
+ mir::StatementKind::Assign(box (
+ _,
+ mir::Rvalue::Ref(
+ _,
+ mir::BorrowKind::Mut { allow_two_phase_borrow: false },
+ _,
+ ),
+ )),
+ ..
+ }) = &self.body[location.block].statements.get(location.statement_index)
+ {
+ match decl.local_info {
+ Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var(
+ mir::VarBindingForm {
+ binding_mode: ty::BindingMode::BindByValue(Mutability::Not),
+ opt_ty_info: Some(sp),
+ opt_match_place: _,
+ pat_span: _,
+ },
+ )))) => {
+ err.span_note(sp, "the binding is already a mutable borrow");
+ }
+ _ => {
+ err.span_note(
+ decl.source_info.span,
+ "the binding is already a mutable borrow",
+ );
+ }
+ }
+ if let Ok(snippet) =
+ self.infcx.tcx.sess.source_map().span_to_snippet(source_info.span)
+ {
+ if snippet.starts_with("&mut ") {
+ // We don't have access to the HIR to get accurate spans, but we can
+ // give a best effort structured suggestion.
+ err.span_suggestion_verbose(
+ source_info.span.with_hi(source_info.span.lo() + BytePos(5)),
+ "try removing `&mut` here",
+ String::new(),
+ Applicability::MachineApplicable,
+ );
+ } else {
+ // This can occur with things like `(&mut self).foo()`.
+ err.span_help(source_info.span, "try removing `&mut` here");
+ }
+ } else {
+ err.span_help(source_info.span, "try removing `&mut` here");
+ }
+ } else if decl.mutability == Mutability::Not
+ && !matches!(
+ decl.local_info,
+ Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::ImplicitSelf(
+ ImplicitSelfKind::MutRef
+ ))))
+ )
+ {
+ err.span_suggestion_verbose(
+ decl.source_info.span.shrink_to_lo(),
+ "consider making the binding mutable",
+ "mut ".to_string(),
+ Applicability::MachineApplicable,
+ );
+ }
}
// We want to suggest users use `let mut` for local (user
@@ -324,7 +393,12 @@
} =>
{
err.span_label(span, format!("cannot {ACT}", ACT = act));
- err.span_label(span, "try removing `&mut` here");
+ err.span_suggestion(
+ span,
+ "try removing `&mut` here",
+ String::new(),
+ Applicability::MaybeIncorrect,
+ );
}
PlaceRef { local, projection: [ProjectionElem::Deref] }
@@ -591,7 +665,7 @@
let reason = if let PlaceBase::Upvar(upvar_id) = closure_kind_origin.base {
let upvar = ty::place_to_string_for_capture(tcx, closure_kind_origin);
let root_hir_id = upvar_id.var_path.hir_id;
- // we have a origin for this closure kind starting at this root variable so it's safe to unwrap here
+ // we have an origin for this closure kind starting at this root variable so it's safe to unwrap here
let captured_places = tables.closure_min_captures[id].get(&root_hir_id).unwrap();
let origin_projection = closure_kind_origin
@@ -721,7 +795,7 @@
if suggestions.peek().is_some() {
err.span_suggestions(
path_segment.ident.span,
- &format!("use mutable method"),
+ "use mutable method",
suggestions,
Applicability::MaybeIncorrect,
);
@@ -905,6 +979,8 @@
Some(c) if c.is_whitespace() => true,
// e.g. `&mut(x)`
Some('(') => true,
+ // e.g. `&mut{x}`
+ Some('{') => true,
// e.g. `&mutablevar`
_ => false,
}
@@ -912,9 +988,7 @@
false
}
};
- if let (true, Some(ws_pos)) =
- (src.starts_with("&'"), src.find(|c: char| -> bool { c.is_whitespace() }))
- {
+ if let (true, Some(ws_pos)) = (src.starts_with("&'"), src.find(char::is_whitespace)) {
let lt_name = &src[1..ws_pos];
let ty = src[ws_pos..].trim_start();
if !is_mutbl(ty) {
@@ -940,9 +1014,7 @@
};
if let Ok(src) = tcx.sess.source_map().span_to_snippet(highlight_span) {
- if let (true, Some(ws_pos)) =
- (src.starts_with("&'"), src.find(|c: char| -> bool { c.is_whitespace() }))
- {
+ if let (true, Some(ws_pos)) = (src.starts_with("&'"), src.find(char::is_whitespace)) {
let lt_name = &src[1..ws_pos];
let ty = &src[ws_pos..];
return (highlight_span, format!("&{} mut{}", lt_name, ty));
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 1460c23..cbb8f06 100644
--- a/compiler/rustc_mir/src/borrow_check/diagnostics/region_errors.rs
+++ b/compiler/rustc_mir/src/borrow_check/diagnostics/region_errors.rs
@@ -75,8 +75,8 @@
longer_fr: RegionVid,
/// The region element that erroneously must be outlived by `longer_fr`.
error_element: RegionElement,
- /// The origin of the placeholder region.
- fr_origin: NllRegionVariableOrigin,
+ /// The placeholder region.
+ placeholder: ty::PlaceholderRegion,
},
/// Any other lifetime error.
@@ -210,25 +210,23 @@
RegionErrorKind::BoundUniversalRegionError {
longer_fr,
- fr_origin,
+ placeholder,
error_element,
} => {
- let error_region = self.regioncx.region_from_element(longer_fr, error_element);
+ let error_vid = self.regioncx.region_from_element(longer_fr, &error_element);
// Find the code to blame for the fact that `longer_fr` outlives `error_fr`.
let (_, span) = self.regioncx.find_outlives_blame_span(
&self.body,
longer_fr,
- fr_origin,
- error_region,
+ NllRegionVariableOrigin::Placeholder(placeholder),
+ error_vid,
);
- // FIXME: improve this error message
- self.infcx
- .tcx
- .sess
- .struct_span_err(span, "higher-ranked subtype error")
- .buffer(&mut self.errors_buffer);
+ let universe = placeholder.universe;
+ let universe_info = self.regioncx.universe_info(universe);
+
+ universe_info.report_error(self, placeholder, error_element, span);
}
RegionErrorKind::RegionError { fr_origin, longer_fr, shorter_fr, is_reported } => {
@@ -425,7 +423,7 @@
diag
}
- /// Reports a error specifically for when data is escaping a closure.
+ /// Reports an error specifically for when data is escaping a closure.
///
/// ```text
/// error: borrowed data escapes outside of function
@@ -568,7 +566,7 @@
diag
}
- /// Adds a suggestion to errors where a `impl Trait` is returned.
+ /// Adds a suggestion to errors where an `impl Trait` is returned.
///
/// ```text
/// help: to allow this `impl Trait` to capture borrowed data with lifetime `'1`, add `'_` as
diff --git a/compiler/rustc_mir/src/borrow_check/facts.rs b/compiler/rustc_mir/src/borrow_check/facts.rs
index 6d6b94e..215dead 100644
--- a/compiler/rustc_mir/src/borrow_check/facts.rs
+++ b/compiler/rustc_mir/src/borrow_check/facts.rs
@@ -12,7 +12,7 @@
use std::path::Path;
#[derive(Copy, Clone, Debug)]
-crate struct RustcFacts;
+pub struct RustcFacts;
impl polonius_engine::FactTypes for RustcFacts {
type Origin = RegionVid;
@@ -22,7 +22,7 @@
type Path = MovePathIndex;
}
-crate type AllFacts = PoloniusFacts<RustcFacts>;
+pub type AllFacts = PoloniusFacts<RustcFacts>;
crate trait AllFactsExt {
/// Returns `true` if there is a need to gather `AllFacts` given the
@@ -64,13 +64,12 @@
}
write_facts_to_path! {
wr.write_facts_to_path(self.[
- borrow_region,
+ loan_issued_at,
universal_region,
- placeholder,
cfg_edge,
- killed,
- outlives,
- invalidates,
+ loan_killed_at,
+ subset_base,
+ loan_invalidated_at,
var_used_at,
var_defined_at,
var_dropped_at,
@@ -81,7 +80,8 @@
path_assigned_at_base,
path_moved_at_base,
path_accessed_at_base,
- known_subset,
+ known_placeholder_subset,
+ placeholder,
])
}
Ok(())
diff --git a/compiler/rustc_mir/src/borrow_check/invalidation.rs b/compiler/rustc_mir/src/borrow_check/invalidation.rs
index e621baf..b83a427 100644
--- a/compiler/rustc_mir/src/borrow_check/invalidation.rs
+++ b/compiler/rustc_mir/src/borrow_check/invalidation.rs
@@ -179,7 +179,7 @@
let resume = self.location_table.start_index(resume.start_location());
for (i, data) in borrow_set.iter_enumerated() {
if borrow_of_local_data(data.borrowed_place) {
- self.all_facts.invalidates.push((resume, i));
+ self.all_facts.loan_invalidated_at.push((resume, i));
}
}
@@ -191,7 +191,7 @@
let start = self.location_table.start_index(location);
for (i, data) in borrow_set.iter_enumerated() {
if borrow_of_local_data(data.borrowed_place) {
- self.all_facts.invalidates.push((start, i));
+ self.all_facts.loan_invalidated_at.push((start, i));
}
}
}
@@ -420,7 +420,7 @@
// Unique and mutable borrows are invalidated by reads from any
// involved path
- this.generate_invalidates(borrow_index, location);
+ this.emit_loan_invalidated_at(borrow_index, location);
}
(Reservation(_) | Activation(_, _) | Write(_), _) => {
@@ -428,7 +428,7 @@
// Reservations count as writes since we need to check
// that activating the borrow will be OK
// FIXME(bob_twinkles) is this actually the right thing to do?
- this.generate_invalidates(borrow_index, location);
+ this.emit_loan_invalidated_at(borrow_index, location);
}
}
Control::Continue
@@ -436,10 +436,10 @@
);
}
- /// Generates a new `invalidates(L, B)` fact.
- fn generate_invalidates(&mut self, b: BorrowIndex, l: Location) {
+ /// Generates a new `loan_invalidated_at(L, B)` fact.
+ fn emit_loan_invalidated_at(&mut self, b: BorrowIndex, l: Location) {
let lidx = self.location_table.start_index(l);
- self.all_facts.invalidates.push((lidx, b));
+ self.all_facts.loan_invalidated_at.push((lidx, b));
}
fn check_activations(&mut self, location: Location) {
diff --git a/compiler/rustc_mir/src/borrow_check/location.rs b/compiler/rustc_mir/src/borrow_check/location.rs
index 375ff72..d378a2c 100644
--- a/compiler/rustc_mir/src/borrow_check/location.rs
+++ b/compiler/rustc_mir/src/borrow_check/location.rs
@@ -12,7 +12,7 @@
/// granularity through outlives relations; however, the rich location
/// table serves another purpose: it compresses locations from
/// multiple words into a single u32.
-crate struct LocationTable {
+pub struct LocationTable {
num_points: usize,
statements_before_block: IndexVec<BasicBlock, usize>,
}
@@ -24,7 +24,7 @@
}
#[derive(Copy, Clone, Debug)]
-crate enum RichLocation {
+pub enum RichLocation {
Start(Location),
Mid(Location),
}
@@ -48,23 +48,23 @@
Self { num_points, statements_before_block }
}
- crate fn all_points(&self) -> impl Iterator<Item = LocationIndex> {
+ pub fn all_points(&self) -> impl Iterator<Item = LocationIndex> {
(0..self.num_points).map(LocationIndex::new)
}
- crate fn start_index(&self, location: Location) -> LocationIndex {
+ pub fn start_index(&self, location: Location) -> LocationIndex {
let Location { block, statement_index } = location;
let start_index = self.statements_before_block[block];
LocationIndex::new(start_index + statement_index * 2)
}
- crate fn mid_index(&self, location: Location) -> LocationIndex {
+ pub fn mid_index(&self, location: Location) -> LocationIndex {
let Location { block, statement_index } = location;
let start_index = self.statements_before_block[block];
LocationIndex::new(start_index + statement_index * 2 + 1)
}
- crate fn to_location(&self, index: LocationIndex) -> RichLocation {
+ pub fn to_location(&self, index: LocationIndex) -> RichLocation {
let point_index = index.index();
// Find the basic block. We have a vector with the
diff --git a/compiler/rustc_mir/src/borrow_check/mod.rs b/compiler/rustc_mir/src/borrow_check/mod.rs
index 36eb8a4..1dcb067 100644
--- a/compiler/rustc_mir/src/borrow_check/mod.rs
+++ b/compiler/rustc_mir/src/borrow_check/mod.rs
@@ -42,12 +42,14 @@
use self::location::LocationTable;
use self::prefixes::PrefixSet;
use self::MutateMode::{JustWrite, WriteAndRead};
+use facts::AllFacts;
use self::path_utils::*;
mod borrow_set;
mod constraint_generation;
mod constraints;
+pub mod consumers;
mod def_use;
mod diagnostics;
mod facts;
@@ -105,25 +107,36 @@
let (input_body, promoted) = tcx.mir_promoted(def);
debug!("run query mir_borrowck: {}", tcx.def_path_str(def.did.to_def_id()));
- let opt_closure_req = tcx.infer_ctxt().enter(|infcx| {
+ let opt_closure_req = tcx.infer_ctxt().with_opaque_type_inference(def.did).enter(|infcx| {
let input_body: &Body<'_> = &input_body.borrow();
let promoted: &IndexVec<_, _> = &promoted.borrow();
- do_mir_borrowck(&infcx, input_body, promoted)
+ do_mir_borrowck(&infcx, input_body, promoted, false).0
});
debug!("mir_borrowck done");
tcx.arena.alloc(opt_closure_req)
}
+/// Perform the actual borrow checking.
+///
+/// If `return_body_with_facts` is true, then return the body with non-erased
+/// region ids on which the borrow checking was performed together with Polonius
+/// facts.
fn do_mir_borrowck<'a, 'tcx>(
infcx: &InferCtxt<'a, 'tcx>,
input_body: &Body<'tcx>,
input_promoted: &IndexVec<Promoted, Body<'tcx>>,
-) -> BorrowCheckResult<'tcx> {
+ return_body_with_facts: bool,
+) -> (BorrowCheckResult<'tcx>, Option<Box<BodyWithBorrowckFacts<'tcx>>>) {
let def = input_body.source.with_opt_param().as_local().unwrap();
debug!("do_mir_borrowck(def = {:?})", def);
+ assert!(
+ !return_body_with_facts || infcx.tcx.sess.opts.debugging_opts.polonius,
+ "borrowck facts can be requested only when Polonius is enabled"
+ );
+
let tcx = infcx.tcx;
let param_env = tcx.param_env(def.did);
let id = tcx.hir().local_def_id_to_hir_id(def.did);
@@ -169,12 +182,14 @@
// requires first making our own copy of the MIR. This copy will
// be modified (in place) to contain non-lexical lifetimes. It
// will have a lifetime tied to the inference context.
- let mut body = input_body.clone();
+ let mut body_owned = input_body.clone();
let mut promoted = input_promoted.clone();
- let free_regions = nll::replace_regions_in_mir(infcx, param_env, &mut body, &mut promoted);
- let body = &body; // no further changes
+ let free_regions =
+ nll::replace_regions_in_mir(infcx, param_env, &mut body_owned, &mut promoted);
+ let body = &body_owned; // no further changes
- let location_table = &LocationTable::new(&body);
+ let location_table_owned = LocationTable::new(body);
+ let location_table = &location_table_owned;
let mut errors_buffer = Vec::new();
let (move_data, move_errors): (MoveData<'tcx>, Vec<(Place<'tcx>, MoveError<'tcx>)>) =
@@ -202,6 +217,7 @@
let nll::NllOutput {
regioncx,
opaque_type_values,
+ polonius_input,
polonius_output,
opt_closure_req,
nll_errors,
@@ -446,9 +462,37 @@
used_mut_upvars: mbcx.used_mut_upvars,
};
+ let body_with_facts = if return_body_with_facts {
+ let output_facts = mbcx.polonius_output.expect("Polonius output was not computed");
+ Some(Box::new(BodyWithBorrowckFacts {
+ body: body_owned,
+ input_facts: *polonius_input.expect("Polonius input facts were not generated"),
+ output_facts,
+ location_table: location_table_owned,
+ }))
+ } else {
+ None
+ };
+
debug!("do_mir_borrowck: result = {:#?}", result);
- result
+ (result, body_with_facts)
+}
+
+/// A `Body` with information computed by the borrow checker. This struct is
+/// intended to be consumed by compiler consumers.
+///
+/// We need to include the MIR body here because the region identifiers must
+/// match the ones in the Polonius facts.
+pub struct BodyWithBorrowckFacts<'tcx> {
+ /// A mir body that contains region identifiers.
+ pub body: Body<'tcx>,
+ /// Polonius input facts.
+ pub input_facts: AllFacts,
+ /// Polonius output facts.
+ pub output_facts: Rc<self::nll::PoloniusOutput>,
+ /// The table that maps Polonius points to locations in the table.
+ pub location_table: LocationTable,
}
crate struct MirBorrowckCtxt<'cx, 'tcx> {
@@ -1197,7 +1241,7 @@
}
}
- // Special case: you can assign a immutable local variable
+ // Special case: you can assign an immutable local variable
// (e.g., `x = ...`) so long as it has never been initialized
// before (at this point in the flow).
if let Some(local) = place_span.0.as_local() {
@@ -1658,7 +1702,7 @@
// initialization state of `a.b` is all we need to inspect to
// know if `a.b.c` is valid (and from that we infer that the
// dereference and `.d` access is also valid, since we assume
- // `a.b.c` is assigned a reference to a initialized and
+ // `a.b.c` is assigned a reference to an initialized and
// well-formed record structure.)
// Therefore, if we seek out the *closest* prefix for which we
@@ -1845,7 +1889,7 @@
ProjectionElem::Downcast(_/*adt_def*/, _/*variant_idx*/) =>
// assigning to (P->variant) is okay if assigning to `P` is okay
//
- // FIXME: is this true even if P is a adt with a dtor?
+ // FIXME: is this true even if P is an adt with a dtor?
{ }
// assigning to (*P) requires P to be initialized
@@ -1959,8 +2003,8 @@
}
if let Some((prefix, mpi)) = shortest_uninit_seen {
- // Check for a reassignment into a uninitialized field of a union (for example,
- // after a move out). In this case, do not report a error here. There is an
+ // Check for a reassignment into an uninitialized field of a union (for example,
+ // after a move out). In this case, do not report an error here. There is an
// exception, if this is the first assignment into the union (that is, there is
// no move out from an earlier location) then this is an attempt at initialization
// of the union - we should error in that case.
diff --git a/compiler/rustc_mir/src/borrow_check/nll.rs b/compiler/rustc_mir/src/borrow_check/nll.rs
index bfeafa3..66ca94d3 100644
--- a/compiler/rustc_mir/src/borrow_check/nll.rs
+++ b/compiler/rustc_mir/src/borrow_check/nll.rs
@@ -40,13 +40,14 @@
Upvar,
};
-crate type PoloniusOutput = Output<RustcFacts>;
+pub type PoloniusOutput = Output<RustcFacts>;
/// The output of `nll::compute_regions`. This includes the computed `RegionInferenceContext`, any
/// closure requirements to propagate, and any generated errors.
crate struct NllOutput<'tcx> {
pub regioncx: RegionInferenceContext<'tcx>,
pub opaque_type_values: VecMap<OpaqueTypeKey<'tcx>, Ty<'tcx>>,
+ pub polonius_input: Option<Box<AllFacts>>,
pub polonius_output: Option<Rc<PoloniusOutput>>,
pub opt_closure_req: Option<ClosureRegionRequirements<'tcx>>,
pub nll_errors: RegionErrors<'tcx>,
@@ -216,14 +217,15 @@
}
// 2: the universal region relations `outlives` constraints are emitted as
- // `known_subset` facts.
+ // `known_placeholder_subset` facts.
for (fr1, fr2) in universal_region_relations.known_outlives() {
if fr1 != fr2 {
debug!(
- "compute_regions: emitting polonius `known_subset` fr1={:?}, fr2={:?}",
+ "compute_regions: emitting polonius `known_placeholder_subset` \
+ fr1={:?}, fr2={:?}",
fr1, fr2
);
- all_facts.known_subset.push((*fr1, *fr2));
+ all_facts.known_placeholder_subset.push((*fr1, *fr2));
}
}
}
@@ -239,6 +241,7 @@
outlives_constraints,
member_constraints,
closure_bounds_mapping,
+ universe_causes,
type_tests,
} = constraints;
let placeholder_indices = Rc::new(placeholder_indices);
@@ -260,6 +263,7 @@
outlives_constraints,
member_constraints,
closure_bounds_mapping,
+ universe_causes,
type_tests,
liveness_constraints,
elements,
@@ -271,7 +275,7 @@
let def_id = body.source.def_id();
// Dump facts if requested.
- let polonius_output = all_facts.and_then(|all_facts| {
+ let polonius_output = all_facts.as_ref().and_then(|all_facts| {
if infcx.tcx.sess.opts.debugging_opts.nll_facts {
let def_path = infcx.tcx.def_path(def_id);
let dir_path = PathBuf::from(&infcx.tcx.sess.opts.debugging_opts.nll_facts_dir)
@@ -281,7 +285,7 @@
if infcx.tcx.sess.opts.debugging_opts.polonius {
let algorithm =
- env::var("POLONIUS_ALGORITHM").unwrap_or_else(|_| String::from("Naive"));
+ env::var("POLONIUS_ALGORITHM").unwrap_or_else(|_| String::from("Hybrid"));
let algorithm = Algorithm::from_str(&algorithm).unwrap();
debug!("compute_regions: using polonius algorithm {:?}", algorithm);
let _prof_timer = infcx.tcx.prof.generic_activity("polonius_analysis");
@@ -305,6 +309,7 @@
NllOutput {
regioncx,
opaque_type_values: remapped_opaque_tys,
+ polonius_input: all_facts.map(Box::new),
polonius_output,
opt_closure_req: closure_region_requirements,
nll_errors,
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 c40e6bf..a96cdbc 100644
--- a/compiler/rustc_mir/src/borrow_check/region_infer/mod.rs
+++ b/compiler/rustc_mir/src/borrow_check/region_infer/mod.rs
@@ -21,7 +21,7 @@
constraints::{
graph::NormalConstraintGraph, ConstraintSccIndex, OutlivesConstraint, OutlivesConstraintSet,
},
- diagnostics::{RegionErrorKind, RegionErrors},
+ diagnostics::{RegionErrorKind, RegionErrors, UniverseInfo},
member_constraints::{MemberConstraintSet, NllMemberConstraintIndex},
nll::{PoloniusOutput, ToRegionVid},
region_infer::reverse_sccs::ReverseSccGraph,
@@ -84,6 +84,9 @@
closure_bounds_mapping:
FxHashMap<Location, FxHashMap<(RegionVid, RegionVid), (ConstraintCategory, Span)>>,
+ /// Map universe indexes to information on why we created it.
+ universe_causes: IndexVec<ty::UniverseIndex, UniverseInfo<'tcx>>,
+
/// Contains the minimum universe of any variable within the same
/// SCC. We will ensure that no SCC contains values that are not
/// visible from this index.
@@ -253,6 +256,7 @@
Location,
FxHashMap<(RegionVid, RegionVid), (ConstraintCategory, Span)>,
>,
+ universe_causes: IndexVec<ty::UniverseIndex, UniverseInfo<'tcx>>,
type_tests: Vec<TypeTest<'tcx>>,
liveness_constraints: LivenessValues<RegionVid>,
elements: &Rc<RegionValueElements>,
@@ -293,6 +297,7 @@
member_constraints,
member_constraints_applied: Vec::new(),
closure_bounds_mapping,
+ universe_causes,
scc_universes,
scc_representatives,
scc_values,
@@ -1632,7 +1637,7 @@
errors_buffer.push(RegionErrorKind::BoundUniversalRegionError {
longer_fr,
error_element,
- fr_origin: NllRegionVariableOrigin::Placeholder(placeholder),
+ placeholder,
});
}
@@ -1918,8 +1923,12 @@
}
/// Get the region outlived by `longer_fr` and live at `element`.
- crate fn region_from_element(&self, longer_fr: RegionVid, element: RegionElement) -> RegionVid {
- match element {
+ crate fn region_from_element(
+ &self,
+ longer_fr: RegionVid,
+ element: &RegionElement,
+ ) -> RegionVid {
+ match *element {
RegionElement::Location(l) => self.find_sub_region_live_at(longer_fr, l),
RegionElement::RootUniversalRegion(r) => r,
RegionElement::PlaceholderRegion(error_placeholder) => self
@@ -2138,6 +2147,10 @@
categorized_path.remove(0)
}
+
+ crate fn universe_info(&self, universe: ty::UniverseIndex) -> UniverseInfo<'tcx> {
+ self.universe_causes[universe].clone()
+ }
}
impl<'tcx> RegionDefinition<'tcx> {
diff --git a/compiler/rustc_mir/src/borrow_check/region_infer/values.rs b/compiler/rustc_mir/src/borrow_check/region_infer/values.rs
index f247d07..2864abde 100644
--- a/compiler/rustc_mir/src/borrow_check/region_infer/values.rs
+++ b/compiler/rustc_mir/src/borrow_check/region_infer/values.rs
@@ -160,7 +160,7 @@
/// region. Returns whether any of them are newly added.
crate fn add_elements(&mut self, row: N, locations: &HybridBitSet<PointIndex>) -> bool {
debug!("LivenessValues::add_elements(row={:?}, locations={:?})", row, locations);
- self.points.union_into_row(row, locations)
+ self.points.union_row(row, locations)
}
/// Adds all the control-flow points to the values for `r`.
@@ -294,7 +294,7 @@
/// the region `to` in `self`.
crate fn merge_liveness<M: Idx>(&mut self, to: N, from: M, values: &LivenessValues<M>) {
if let Some(set) = values.points.row(from) {
- self.points.union_into_row(to, set);
+ self.points.union_row(to, set);
}
}
diff --git a/compiler/rustc_mir/src/borrow_check/type_check/canonical.rs b/compiler/rustc_mir/src/borrow_check/type_check/canonical.rs
new file mode 100644
index 0000000..b501716
--- /dev/null
+++ b/compiler/rustc_mir/src/borrow_check/type_check/canonical.rs
@@ -0,0 +1,157 @@
+use std::fmt;
+
+use rustc_infer::infer::canonical::Canonical;
+use rustc_infer::traits::query::NoSolution;
+use rustc_middle::mir::ConstraintCategory;
+use rustc_middle::ty::{self, ToPredicate, TypeFoldable};
+use rustc_span::Span;
+use rustc_trait_selection::traits::query::type_op::{self, TypeOpOutput};
+use rustc_trait_selection::traits::query::Fallible;
+
+use crate::borrow_check::diagnostics::{ToUniverseInfo, UniverseInfo};
+
+use super::{Locations, NormalizeLocation, TypeChecker};
+
+impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
+ /// Given some operation `op` that manipulates types, proves
+ /// predicates, or otherwise uses the inference context, executes
+ /// `op` and then executes all the further obligations that `op`
+ /// returns. This will yield a set of outlives constraints amongst
+ /// regions which are extracted and stored as having occurred at
+ /// `locations`.
+ ///
+ /// **Any `rustc_infer::infer` operations that might generate region
+ /// constraints should occur within this method so that those
+ /// constraints can be properly localized!**
+ pub(super) fn fully_perform_op<R, Op>(
+ &mut self,
+ locations: Locations,
+ category: ConstraintCategory,
+ op: Op,
+ ) -> Fallible<R>
+ where
+ Op: type_op::TypeOp<'tcx, Output = R>,
+ Canonical<'tcx, Op>: ToUniverseInfo<'tcx>,
+ {
+ let old_universe = self.infcx.universe();
+
+ let TypeOpOutput { output, constraints, canonicalized_query } =
+ op.fully_perform(self.infcx)?;
+
+ if let Some(data) = &constraints {
+ self.push_region_constraints(locations, category, data);
+ }
+
+ let universe = self.infcx.universe();
+
+ if old_universe != universe {
+ let universe_info = match canonicalized_query {
+ Some(canonicalized_query) => canonicalized_query.to_universe_info(old_universe),
+ None => UniverseInfo::other(),
+ };
+ for u in old_universe..universe {
+ let info_universe =
+ self.borrowck_context.constraints.universe_causes.push(universe_info.clone());
+ assert_eq!(u.as_u32() + 1, info_universe.as_u32());
+ }
+ }
+
+ Ok(output)
+ }
+
+ pub(super) fn instantiate_canonical_with_fresh_inference_vars<T>(
+ &mut self,
+ span: Span,
+ canonical: &Canonical<'tcx, T>,
+ ) -> T
+ where
+ T: TypeFoldable<'tcx>,
+ {
+ let (instantiated, _) =
+ self.infcx.instantiate_canonical_with_fresh_inference_vars(span, canonical);
+
+ for _ in 0..canonical.max_universe.as_u32() {
+ let info = UniverseInfo::other();
+ self.borrowck_context.constraints.universe_causes.push(info);
+ }
+
+ instantiated
+ }
+
+ pub(super) fn prove_trait_ref(
+ &mut self,
+ trait_ref: ty::TraitRef<'tcx>,
+ locations: Locations,
+ category: ConstraintCategory,
+ ) {
+ self.prove_predicates(
+ Some(ty::PredicateKind::Trait(ty::TraitPredicate {
+ trait_ref,
+ constness: ty::BoundConstness::NotConst,
+ })),
+ locations,
+ category,
+ );
+ }
+
+ pub(super) fn normalize_and_prove_instantiated_predicates(
+ &mut self,
+ instantiated_predicates: ty::InstantiatedPredicates<'tcx>,
+ locations: Locations,
+ ) {
+ for predicate in instantiated_predicates.predicates {
+ let predicate = self.normalize(predicate, locations);
+ self.prove_predicate(predicate, locations, ConstraintCategory::Boring);
+ }
+ }
+
+ pub(super) fn prove_predicates(
+ &mut self,
+ predicates: impl IntoIterator<Item = impl ToPredicate<'tcx>>,
+ locations: Locations,
+ category: ConstraintCategory,
+ ) {
+ for predicate in predicates {
+ let predicate = predicate.to_predicate(self.tcx());
+ debug!("prove_predicates(predicate={:?}, locations={:?})", predicate, locations,);
+
+ self.prove_predicate(predicate, locations, category);
+ }
+ }
+
+ pub(super) fn prove_predicate(
+ &mut self,
+ predicate: ty::Predicate<'tcx>,
+ locations: Locations,
+ category: ConstraintCategory,
+ ) {
+ debug!("prove_predicate(predicate={:?}, location={:?})", predicate, locations,);
+
+ let param_env = self.param_env;
+ self.fully_perform_op(
+ locations,
+ category,
+ param_env.and(type_op::prove_predicate::ProvePredicate::new(predicate)),
+ )
+ .unwrap_or_else(|NoSolution| {
+ span_mirbug!(self, NoSolution, "could not prove {:?}", predicate);
+ })
+ }
+
+ pub(super) fn normalize<T>(&mut self, value: T, location: impl NormalizeLocation) -> T
+ where
+ T: type_op::normalize::Normalizable<'tcx> + fmt::Display + Copy + 'tcx,
+ {
+ debug!("normalize(value={:?}, location={:?})", value, location);
+ let param_env = self.param_env;
+ self.fully_perform_op(
+ location.to_locations(),
+ ConstraintCategory::Boring,
+ param_env.and(type_op::normalize::Normalize::new(value)),
+ )
+ .unwrap_or_else(|NoSolution| {
+ span_mirbug!(self, NoSolution, "failed to normalize `{:?}`", value);
+ value
+ })
+ }
+}
diff --git a/compiler/rustc_mir/src/borrow_check/type_check/constraint_conversion.rs b/compiler/rustc_mir/src/borrow_check/type_check/constraint_conversion.rs
index eb11b93..446a0f8 100644
--- a/compiler/rustc_mir/src/borrow_check/type_check/constraint_conversion.rs
+++ b/compiler/rustc_mir/src/borrow_check/type_check/constraint_conversion.rs
@@ -99,7 +99,7 @@
GenericArgKind::Type(t1) => {
// we don't actually use this for anything, but
// the `TypeOutlives` code needs an origin.
- let origin = infer::RelateParamBound(DUMMY_SP, t1);
+ let origin = infer::RelateParamBound(DUMMY_SP, t1, None);
TypeOutlives::new(
&mut *self,
diff --git a/compiler/rustc_mir/src/borrow_check/type_check/free_region_relations.rs b/compiler/rustc_mir/src/borrow_check/type_check/free_region_relations.rs
index beee318..6426098 100644
--- a/compiler/rustc_mir/src/borrow_check/type_check/free_region_relations.rs
+++ b/compiler/rustc_mir/src/borrow_check/type_check/free_region_relations.rs
@@ -11,6 +11,7 @@
use rustc_span::DUMMY_SP;
use rustc_trait_selection::traits::query::type_op::{self, TypeOp};
use std::rc::Rc;
+use type_op::TypeOpOutput;
use crate::borrow_check::{
nll::ToRegionVid,
@@ -255,7 +256,10 @@
let constraint_sets: Vec<_> = unnormalized_input_output_tys
.flat_map(|ty| {
debug!("build: input_or_output={:?}", ty);
- let (ty, constraints1) = self
+ // We add implied bounds from both the unnormalized and normalized ty
+ // See issue #87748
+ let constraints_implied_1 = self.add_implied_bounds(ty);
+ let TypeOpOutput { output: ty, constraints: constraints1, .. } = self
.param_env
.and(type_op::normalize::Normalize::new(ty))
.fully_perform(self.infcx)
@@ -264,11 +268,27 @@
.tcx
.sess
.delay_span_bug(DUMMY_SP, &format!("failed to normalize {:?}", ty));
- (self.infcx.tcx.ty_error(), None)
+ TypeOpOutput {
+ output: self.infcx.tcx.ty_error(),
+ constraints: None,
+ canonicalized_query: None,
+ }
});
- let constraints2 = self.add_implied_bounds(ty);
+ // Note: we need this in examples like
+ // ```
+ // trait Foo {
+ // type Bar;
+ // fn foo(&self) -> &Self::Bar;
+ // }
+ // impl Foo for () {
+ // type Bar = ();
+ // fn foo(&self) ->&() {}
+ // }
+ // ```
+ // Both &Self::Bar and &() are WF
+ let constraints_implied_2 = self.add_implied_bounds(ty);
normalized_inputs_and_output.push(ty);
- constraints1.into_iter().chain(constraints2)
+ constraints1.into_iter().chain(constraints_implied_1).chain(constraints_implied_2)
})
.collect();
@@ -317,7 +337,7 @@
/// from this local.
fn add_implied_bounds(&mut self, ty: Ty<'tcx>) -> Option<Rc<QueryRegionConstraints<'tcx>>> {
debug!("add_implied_bounds(ty={:?})", ty);
- let (bounds, constraints) = self
+ let TypeOpOutput { output: bounds, constraints, .. } = self
.param_env
.and(type_op::implied_outlives_bounds::ImpliedOutlivesBounds { ty })
.fully_perform(self.infcx)
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 37e0643..ba9b692 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
@@ -9,7 +9,9 @@
use rustc_infer::infer::LateBoundRegionConversionTime;
use rustc_middle::mir::*;
-use rustc_middle::ty::Ty;
+use rustc_middle::traits::ObligationCause;
+use rustc_middle::ty::{self, Ty};
+use rustc_trait_selection::traits::query::normalize::AtExt;
use rustc_index::vec::Idx;
use rustc_span::Span;
@@ -44,7 +46,7 @@
// Instantiate the canonicalized variables from
// user-provided signature (e.g., the `_` in the code
// above) with fresh variables.
- let (poly_sig, _) = self.infcx.instantiate_canonical_with_fresh_inference_vars(
+ let poly_sig = self.instantiate_canonical_with_fresh_inference_vars(
body.span,
&user_provided_poly_sig,
);
@@ -162,17 +164,49 @@
fn equate_normalized_input_or_output(&mut self, a: Ty<'tcx>, b: Ty<'tcx>, span: Span) {
debug!("equate_normalized_input_or_output(a={:?}, b={:?})", a, b);
- if let Err(terr) =
+ if let Err(_) =
self.eq_types(a, b, Locations::All(span), ConstraintCategory::BoringNoLocation)
{
- span_mirbug!(
- self,
- Location::START,
- "equate_normalized_input_or_output: `{:?}=={:?}` failed with `{:?}`",
- a,
- b,
- terr
- );
+ // FIXME(jackh726): This is a hack. It's somewhat like
+ // `rustc_traits::normalize_after_erasing_regions`. Ideally, we'd
+ // like to normalize *before* inserting into `local_decls`, but
+ // doing so ends up causing some other trouble.
+ let b = match self
+ .infcx
+ .at(&ObligationCause::dummy(), ty::ParamEnv::empty())
+ .normalize(b)
+ {
+ Ok(n) => {
+ debug!("equate_inputs_and_outputs: {:?}", n);
+ if n.obligations.iter().all(|o| {
+ matches!(
+ o.predicate.kind().skip_binder(),
+ ty::PredicateKind::RegionOutlives(_)
+ | ty::PredicateKind::TypeOutlives(_)
+ )
+ }) {
+ n.value
+ } else {
+ b
+ }
+ }
+ Err(_) => {
+ debug!("equate_inputs_and_outputs: NoSolution");
+ b
+ }
+ };
+ if let Err(terr) =
+ self.eq_types(a, b, Locations::All(span), ConstraintCategory::BoringNoLocation)
+ {
+ span_mirbug!(
+ self,
+ Location::START,
+ "equate_normalized_input_or_output: `{:?}=={:?}` failed with `{:?}`",
+ a,
+ b,
+ terr
+ );
+ }
}
}
}
diff --git a/compiler/rustc_mir/src/borrow_check/type_check/liveness/trace.rs b/compiler/rustc_mir/src/borrow_check/type_check/liveness/trace.rs
index f04736e..566c118 100644
--- a/compiler/rustc_mir/src/borrow_check/type_check/liveness/trace.rs
+++ b/compiler/rustc_mir/src/borrow_check/type_check/liveness/trace.rs
@@ -5,7 +5,7 @@
use rustc_middle::ty::{Ty, TypeFoldable};
use rustc_trait_selection::traits::query::dropck_outlives::DropckOutlivesResult;
use rustc_trait_selection::traits::query::type_op::outlives::DropckOutlives;
-use rustc_trait_selection::traits::query::type_op::TypeOp;
+use rustc_trait_selection::traits::query::type_op::{TypeOp, TypeOpOutput};
use std::rc::Rc;
use crate::dataflow::impls::MaybeInitializedPlaces;
@@ -171,7 +171,7 @@
for (local, location) in drop_used {
if !live_locals.contains(&local) {
let local_ty = self.cx.body.local_decls[local].ty;
- if local_ty.has_free_regions() {
+ if local_ty.has_free_regions(self.cx.typeck.tcx()) {
self.cx.add_drop_live_facts_for(local, local_ty, &[location], &locations);
}
}
@@ -519,9 +519,9 @@
debug!("compute_drop_data(dropped_ty={:?})", dropped_ty,);
let param_env = typeck.param_env;
- let (dropck_result, region_constraint_data) =
+ let TypeOpOutput { output, constraints, .. } =
param_env.and(DropckOutlives::new(dropped_ty)).fully_perform(typeck.infcx).unwrap();
- DropData { dropck_result, region_constraint_data }
+ DropData { dropck_result: output, region_constraint_data: constraints }
}
}
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 3fb06cd..639bcb8 100644
--- a/compiler/rustc_mir/src/borrow_check/type_check/mod.rs
+++ b/compiler/rustc_mir/src/borrow_check/type_check/mod.rs
@@ -38,7 +38,7 @@
use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
use rustc_trait_selection::traits::query::type_op;
use rustc_trait_selection::traits::query::type_op::custom::CustomTypeOp;
-use rustc_trait_selection::traits::query::{Fallible, NoSolution};
+use rustc_trait_selection::traits::query::Fallible;
use rustc_trait_selection::traits::{self, ObligationCause, PredicateObligations};
use crate::dataflow::impls::MaybeInitializedPlaces;
@@ -51,6 +51,7 @@
use crate::borrow_check::{
borrow_set::BorrowSet,
constraints::{OutlivesConstraint, OutlivesConstraintSet},
+ diagnostics::UniverseInfo,
facts::AllFacts,
location::LocationTable,
member_constraints::MemberConstraintSet,
@@ -89,6 +90,7 @@
})
}
+mod canonical;
mod constraint_conversion;
pub mod free_region_relations;
mod input_output;
@@ -142,6 +144,7 @@
member_constraints: MemberConstraintSet::default(),
closure_bounds_mapping: Default::default(),
type_tests: Vec::default(),
+ universe_causes: IndexVec::from_elem_n(UniverseInfo::other(), 1),
};
let CreateResult {
@@ -156,6 +159,11 @@
&mut constraints,
);
+ for _ in ty::UniverseIndex::ROOT..infcx.universe() {
+ let info = UniverseInfo::other();
+ constraints.universe_causes.push(info);
+ }
+
let mut borrowck_context = BorrowCheckContext {
universal_regions,
location_table,
@@ -179,54 +187,55 @@
liveness::generate(&mut cx, body, elements, flow_inits, move_data, location_table);
translate_outlives_facts(&mut cx);
- let mut opaque_type_values = cx.opaque_type_values;
+ let opaque_type_values = mem::take(&mut infcx.inner.borrow_mut().opaque_types);
- for (_, revealed_ty) in &mut opaque_type_values {
- *revealed_ty = infcx.resolve_vars_if_possible(*revealed_ty);
- if revealed_ty.has_infer_types_or_consts() {
- infcx.tcx.sess.delay_span_bug(
- body.span,
- &format!("could not resolve {:#?}", revealed_ty.kind()),
- );
- *revealed_ty = infcx.tcx.ty_error();
- }
- }
-
- opaque_type_values.retain(|(opaque_type_key, resolved_ty)| {
- let concrete_is_opaque = if let ty::Opaque(def_id, _) = resolved_ty.kind() {
- *def_id == opaque_type_key.def_id
- } else {
- false
- };
-
- if concrete_is_opaque {
- // We're using an opaque `impl Trait` type without
- // 'revealing' it. For example, code like this:
- //
- // type Foo = impl Debug;
- // fn foo1() -> Foo { ... }
- // fn foo2() -> Foo { foo1() }
- //
- // In `foo2`, we're not revealing the type of `Foo` - we're
- // just treating it as the opaque type.
- //
- // When this occurs, we do *not* want to try to equate
- // the concrete type with the underlying defining type
- // of the opaque type - this will always fail, since
- // the defining type of an opaque type is always
- // some other type (e.g. not itself)
- // Essentially, none of the normal obligations apply here -
- // we're just passing around some unknown opaque type,
- // without actually looking at the underlying type it
- // gets 'revealed' into
- debug!(
- "eq_opaque_type_and_type: non-defining use of {:?}",
- opaque_type_key.def_id,
- );
- }
- !concrete_is_opaque
- });
opaque_type_values
+ .into_iter()
+ .filter_map(|(opaque_type_key, decl)| {
+ let mut revealed_ty = infcx.resolve_vars_if_possible(decl.concrete_ty);
+ if revealed_ty.has_infer_types_or_consts() {
+ infcx.tcx.sess.delay_span_bug(
+ body.span,
+ &format!("could not resolve {:#?}", revealed_ty.kind()),
+ );
+ revealed_ty = infcx.tcx.ty_error();
+ }
+ let concrete_is_opaque = if let ty::Opaque(def_id, _) = revealed_ty.kind() {
+ *def_id == opaque_type_key.def_id
+ } else {
+ false
+ };
+
+ if concrete_is_opaque {
+ // We're using an opaque `impl Trait` type without
+ // 'revealing' it. For example, code like this:
+ //
+ // type Foo = impl Debug;
+ // fn foo1() -> Foo { ... }
+ // fn foo2() -> Foo { foo1() }
+ //
+ // In `foo2`, we're not revealing the type of `Foo` - we're
+ // just treating it as the opaque type.
+ //
+ // When this occurs, we do *not* want to try to equate
+ // the concrete type with the underlying defining type
+ // of the opaque type - this will always fail, since
+ // the defining type of an opaque type is always
+ // some other type (e.g. not itself)
+ // Essentially, none of the normal obligations apply here -
+ // we're just passing around some unknown opaque type,
+ // without actually looking at the underlying type it
+ // gets 'revealed' into
+ debug!(
+ "eq_opaque_type_and_type: non-defining use of {:?}",
+ opaque_type_key.def_id,
+ );
+ None
+ } else {
+ Some((opaque_type_key, revealed_ty))
+ }
+ })
+ .collect()
},
);
@@ -272,7 +281,7 @@
if let Some(facts) = cx.all_facts {
let _prof_timer = typeck.infcx.tcx.prof.generic_activity("polonius_fact_generation");
let location_table = cx.location_table;
- facts.outlives.extend(cx.constraints.outlives_constraints.outlives().iter().flat_map(
+ facts.subset_base.extend(cx.constraints.outlives_constraints.outlives().iter().flat_map(
|constraint: &OutlivesConstraint<'_>| {
if let Some(from_location) = constraint.locations.from_location() {
Either::Left(iter::once((
@@ -368,15 +377,15 @@
},
_ => None,
};
- if let Some(ty::Unevaluated { def, substs, promoted }) = maybe_uneval {
- if let Some(promoted) = promoted {
+ if let Some(uv) = maybe_uneval {
+ if let Some(promoted) = uv.promoted {
let check_err = |verifier: &mut TypeVerifier<'a, 'b, 'tcx>,
promoted: &Body<'tcx>,
ty,
san_ty| {
if let Err(terr) = verifier.cx.eq_types(
- san_ty,
ty,
+ san_ty,
location.to_locations(),
ConstraintCategory::Boring,
) {
@@ -404,8 +413,8 @@
ConstraintCategory::Boring,
self.cx.param_env.and(type_op::ascribe_user_type::AscribeUserType::new(
constant.literal.ty(),
- def.did,
- UserSubsts { substs, user_self_ty: None },
+ uv.def.did,
+ UserSubsts { substs: uv.substs(self.tcx()), user_self_ty: None },
)),
) {
span_mirbug!(
@@ -424,8 +433,8 @@
let literal_ty = constant.literal.ty().builtin_deref(true).unwrap().ty;
if let Err(terr) = self.cx.eq_types(
- normalized_ty,
literal_ty,
+ normalized_ty,
locations,
ConstraintCategory::Boring,
) {
@@ -541,7 +550,7 @@
return PlaceTy::from_ty(self.tcx().ty_error());
}
}
- place_ty = self.sanitize_projection(place_ty, elem, place, location)
+ place_ty = self.sanitize_projection(place_ty, elem, place, location);
}
if let PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy) = context {
@@ -865,7 +874,6 @@
reported_errors: FxHashSet<(Ty<'tcx>, Span)>,
borrowck_context: &'a mut BorrowCheckContext<'a, 'tcx>,
universal_region_relations: &'a UniversalRegionRelations<'tcx>,
- opaque_type_values: VecMap<OpaqueTypeKey<'tcx>, Ty<'tcx>>,
}
struct BorrowCheckContext<'a, 'tcx> {
@@ -916,6 +924,8 @@
crate closure_bounds_mapping:
FxHashMap<Location, FxHashMap<(RegionVid, RegionVid), (ConstraintCategory, Span)>>,
+ crate universe_causes: IndexVec<ty::UniverseIndex, UniverseInfo<'tcx>>,
+
crate type_tests: Vec<TypeTest<'tcx>>,
}
@@ -1025,7 +1035,6 @@
borrowck_context,
reported_errors: Default::default(),
universal_region_relations,
- opaque_type_values: VecMap::default(),
};
checker.check_user_type_annotations();
checker
@@ -1044,8 +1053,8 @@
);
for user_annotation in self.user_type_annotations {
let CanonicalUserTypeAnnotation { span, ref user_ty, inferred_ty } = *user_annotation;
- let (annotation, _) =
- self.infcx.instantiate_canonical_with_fresh_inference_vars(span, user_ty);
+ let inferred_ty = self.normalize(inferred_ty, Locations::All(span));
+ let annotation = self.instantiate_canonical_with_fresh_inference_vars(span, user_ty);
match annotation {
UserType::Ty(mut ty) => {
ty = self.normalize(ty, Locations::All(span));
@@ -1085,11 +1094,12 @@
span_mirbug!(
self,
user_annotation,
- "bad user type AscribeUserType({:?}, {:?} {:?}): {:?}",
+ "bad user type AscribeUserType({:?}, {:?} {:?}, type_of={:?}): {:?}",
inferred_ty,
def_id,
user_substs,
- terr
+ self.tcx().type_of(def_id),
+ terr,
);
}
}
@@ -1097,31 +1107,6 @@
}
}
- /// Given some operation `op` that manipulates types, proves
- /// predicates, or otherwise uses the inference context, executes
- /// `op` and then executes all the further obligations that `op`
- /// returns. This will yield a set of outlives constraints amongst
- /// regions which are extracted and stored as having occurred at
- /// `locations`.
- ///
- /// **Any `rustc_infer::infer` operations that might generate region
- /// constraints should occur within this method so that those
- /// constraints can be properly localized!**
- fn fully_perform_op<R>(
- &mut self,
- locations: Locations,
- category: ConstraintCategory,
- op: impl type_op::TypeOp<'tcx, Output = R>,
- ) -> Fallible<R> {
- let (r, opt_data) = op.fully_perform(self.infcx)?;
-
- if let Some(data) = &opt_data {
- self.push_region_constraints(locations, category, data);
- }
-
- Ok(r)
- }
-
fn push_region_constraints(
&mut self,
locations: Locations,
@@ -1161,7 +1146,7 @@
b,
locations,
category,
- Some(self.borrowck_context),
+ self.borrowck_context,
)
}
@@ -1173,17 +1158,19 @@
locations: Locations,
category: ConstraintCategory,
) -> Fallible<()> {
- self.relate_types(sub, ty::Variance::Covariant, sup, locations, category)
+ // Use this order of parameters because the sup type is usually the
+ // "expected" type in diagnostics.
+ self.relate_types(sup, ty::Variance::Contravariant, sub, locations, category)
}
fn eq_types(
&mut self,
- a: Ty<'tcx>,
- b: Ty<'tcx>,
+ expected: Ty<'tcx>,
+ found: Ty<'tcx>,
locations: Locations,
category: ConstraintCategory,
) -> Fallible<()> {
- self.relate_types(a, ty::Variance::Invariant, b, locations, category)
+ self.relate_types(expected, ty::Variance::Invariant, found, locations, category)
}
fn relate_type_and_user_type(
@@ -1222,7 +1209,7 @@
);
let ty = curr_projected_ty.ty;
- self.relate_types(a, v, ty, locations, category)?;
+ self.relate_types(ty, v.xform(ty::Variance::Contravariant), a, locations, category)?;
Ok(())
}
@@ -1289,10 +1276,8 @@
let body = self.body;
let mir_def_id = body.source.def_id().expect_local();
- let mut opaque_type_values = VecMap::new();
-
debug!("eq_opaque_type_and_type: mir_def_id={:?}", mir_def_id);
- let opaque_type_map = self.fully_perform_op(
+ self.fully_perform_op(
locations,
category,
CustomTypeOp::new(
@@ -1307,20 +1292,17 @@
// to `Box<?T>`, returning an `opaque_type_map` mapping `{Foo<T> -> ?T}`.
// (Note that the key of the map is both the def-id of `Foo` along with
// any generic parameters.)
- let (output_ty, opaque_type_map) =
- obligations.add(infcx.instantiate_opaque_types(
- mir_def_id,
- dummy_body_id,
- param_env,
- anon_ty,
- locations.span(body),
- ));
+ let output_ty = obligations.add(infcx.instantiate_opaque_types(
+ dummy_body_id,
+ param_env,
+ anon_ty,
+ locations.span(body),
+ ));
debug!(
"eq_opaque_type_and_type: \
instantiated output_ty={:?} \
- opaque_type_map={:#?} \
revealed_ty={:?}",
- output_ty, opaque_type_map, revealed_ty
+ output_ty, revealed_ty
);
// Make sure that the inferred types are well-formed. I'm
@@ -1338,48 +1320,38 @@
.eq(output_ty, revealed_ty)?,
);
- for &(opaque_type_key, opaque_decl) in &opaque_type_map {
- opaque_type_values.insert(opaque_type_key, opaque_decl.concrete_ty);
- }
-
debug!("eq_opaque_type_and_type: equated");
- Ok(InferOk {
- value: Some(opaque_type_map),
- obligations: obligations.into_vec(),
- })
+ Ok(InferOk { value: (), obligations: obligations.into_vec() })
},
|| "input_output".to_string(),
),
)?;
- self.opaque_type_values.extend(opaque_type_values);
-
let universal_region_relations = self.universal_region_relations;
// Finally, if we instantiated the anon types successfully, we
// have to solve any bounds (e.g., `-> impl Iterator` needs to
// prove that `T: Iterator` where `T` is the type we
// instantiated it with).
- if let Some(opaque_type_map) = opaque_type_map {
- for (opaque_type_key, opaque_decl) in opaque_type_map {
- self.fully_perform_op(
- locations,
- ConstraintCategory::OpaqueType,
- CustomTypeOp::new(
- |infcx| {
- infcx.constrain_opaque_type(
- opaque_type_key,
- &opaque_decl,
- GenerateMemberConstraints::IfNoStaticBound,
- universal_region_relations,
- );
- Ok(InferOk { value: (), obligations: vec![] })
- },
- || "opaque_type_map".to_string(),
- ),
- )?;
- }
+ let opaque_type_map = self.infcx.inner.borrow().opaque_types.clone();
+ for (opaque_type_key, opaque_decl) in opaque_type_map {
+ self.fully_perform_op(
+ locations,
+ ConstraintCategory::OpaqueType,
+ CustomTypeOp::new(
+ |infcx| {
+ infcx.constrain_opaque_type(
+ opaque_type_key,
+ &opaque_decl,
+ GenerateMemberConstraints::IfNoStaticBound,
+ universal_region_relations,
+ );
+ Ok(InferOk { value: (), obligations: vec![] })
+ },
+ || "opaque_type_map".to_string(),
+ ),
+ )?;
}
Ok(())
}
@@ -1922,9 +1894,7 @@
// While this is located in `nll::typeck` this error is not
// an NLL error, it's a required check to prevent creation
- // of unsized rvalues in certain cases:
- // * operand of a box expression
- // * callee in a call expression
+ // of unsized rvalues in a call expression.
diag.emit();
}
}
@@ -2068,8 +2038,8 @@
let ty_fn_ptr_from = tcx.mk_fn_ptr(fn_sig);
if let Err(terr) = self.eq_types(
- ty_fn_ptr_from,
ty,
+ ty_fn_ptr_from,
location.to_locations(),
ConstraintCategory::Cast,
) {
@@ -2092,8 +2062,8 @@
let ty_fn_ptr_from = tcx.mk_fn_ptr(tcx.signature_unclosure(sig, *unsafety));
if let Err(terr) = self.eq_types(
- ty_fn_ptr_from,
ty,
+ ty_fn_ptr_from,
location.to_locations(),
ConstraintCategory::Cast,
) {
@@ -2121,8 +2091,8 @@
let ty_fn_ptr_from = tcx.safe_to_unsafe_fn_ty(fn_sig);
if let Err(terr) = self.eq_types(
- ty_fn_ptr_from,
ty,
+ ty_fn_ptr_from,
location.to_locations(),
ConstraintCategory::Cast,
) {
@@ -2309,20 +2279,18 @@
kind: TypeVariableOriginKind::MiscVariable,
span: body.source_info(location).span,
});
- self.relate_types(
- common_ty,
- ty::Variance::Contravariant,
+ self.sub_types(
ty_left,
+ common_ty,
location.to_locations(),
ConstraintCategory::Boring,
)
.unwrap_or_else(|err| {
bug!("Could not equate type variable with {:?}: {:?}", ty_left, err)
});
- if let Err(terr) = self.relate_types(
- common_ty,
- ty::Variance::Contravariant,
+ if let Err(terr) = self.sub_types(
ty_right,
+ common_ty,
location.to_locations(),
ConstraintCategory::Boring,
) {
@@ -2461,7 +2429,7 @@
let BorrowCheckContext { borrow_set, location_table, all_facts, constraints, .. } =
self.borrowck_context;
- // In Polonius mode, we also push a `borrow_region` fact
+ // In Polonius mode, we also push a `loan_issued_at` fact
// linking the loan to the region (in some cases, though,
// there is no loan associated with this borrow expression --
// that occurs when we are borrowing an unsafe place, for
@@ -2470,7 +2438,7 @@
let _prof_timer = self.infcx.tcx.prof.generic_activity("polonius_fact_generation");
if let Some(borrow_index) = borrow_set.get_index_of(&location) {
let region_vid = borrow_region.to_region_vid();
- all_facts.borrow_region.push((
+ all_facts.loan_issued_at.push((
region_vid,
borrow_index,
location_table.mid_index(location),
@@ -2697,66 +2665,6 @@
tcx.predicates_of(def_id).instantiate(tcx, substs)
}
- fn prove_trait_ref(
- &mut self,
- trait_ref: ty::TraitRef<'tcx>,
- locations: Locations,
- category: ConstraintCategory,
- ) {
- self.prove_predicates(
- Some(ty::PredicateKind::Trait(
- ty::TraitPredicate { trait_ref },
- hir::Constness::NotConst,
- )),
- locations,
- category,
- );
- }
-
- fn normalize_and_prove_instantiated_predicates(
- &mut self,
- instantiated_predicates: ty::InstantiatedPredicates<'tcx>,
- locations: Locations,
- ) {
- for predicate in instantiated_predicates.predicates {
- let predicate = self.normalize(predicate, locations);
- self.prove_predicate(predicate, locations, ConstraintCategory::Boring);
- }
- }
-
- fn prove_predicates(
- &mut self,
- predicates: impl IntoIterator<Item = impl ToPredicate<'tcx>>,
- locations: Locations,
- category: ConstraintCategory,
- ) {
- for predicate in predicates {
- let predicate = predicate.to_predicate(self.tcx());
- debug!("prove_predicates(predicate={:?}, locations={:?})", predicate, locations,);
-
- self.prove_predicate(predicate, locations, category);
- }
- }
-
- fn prove_predicate(
- &mut self,
- predicate: ty::Predicate<'tcx>,
- locations: Locations,
- category: ConstraintCategory,
- ) {
- debug!("prove_predicate(predicate={:?}, location={:?})", predicate, locations,);
-
- let param_env = self.param_env;
- self.fully_perform_op(
- locations,
- category,
- param_env.and(type_op::prove_predicate::ProvePredicate::new(predicate)),
- )
- .unwrap_or_else(|NoSolution| {
- span_mirbug!(self, NoSolution, "could not prove {:?}", predicate);
- })
- }
-
fn typeck_mir(&mut self, body: &Body<'tcx>) {
self.last_span = body.span;
debug!("run_on_mir: {:?}", body.span);
@@ -2779,23 +2687,6 @@
self.check_iscleanup(&body, block_data);
}
}
-
- fn normalize<T>(&mut self, value: T, location: impl NormalizeLocation) -> T
- where
- T: type_op::normalize::Normalizable<'tcx> + Copy + 'tcx,
- {
- debug!("normalize(value={:?}, location={:?})", value, location);
- let param_env = self.param_env;
- self.fully_perform_op(
- location.to_locations(),
- ConstraintCategory::Boring,
- param_env.and(type_op::normalize::Normalize::new(value)),
- )
- .unwrap_or_else(|NoSolution| {
- span_mirbug!(self, NoSolution, "failed to normalize `{:?}`", value);
- value
- })
- }
}
trait NormalizeLocation: fmt::Debug + Copy {
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 f97252a..971c4da 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
@@ -6,6 +6,7 @@
use rustc_trait_selection::traits::query::Fallible;
use crate::borrow_check::constraints::OutlivesConstraint;
+use crate::borrow_check::diagnostics::UniverseInfo;
use crate::borrow_check::type_check::{BorrowCheckContext, Locations};
/// Adds sufficient constraints to ensure that `a R b` where `R` depends on `v`:
@@ -24,12 +25,19 @@
b: Ty<'tcx>,
locations: Locations,
category: ConstraintCategory,
- borrowck_context: Option<&mut BorrowCheckContext<'_, 'tcx>>,
+ borrowck_context: &mut BorrowCheckContext<'_, 'tcx>,
) -> Fallible<()> {
debug!("relate_types(a={:?}, v={:?}, b={:?}, locations={:?})", a, v, b, locations);
TypeRelating::new(
infcx,
- NllTypeRelatingDelegate::new(infcx, borrowck_context, param_env, locations, category),
+ NllTypeRelatingDelegate::new(
+ infcx,
+ borrowck_context,
+ param_env,
+ locations,
+ category,
+ UniverseInfo::relate(a, b),
+ ),
v,
)
.relate(a, b)?;
@@ -38,7 +46,7 @@
struct NllTypeRelatingDelegate<'me, 'bccx, 'tcx> {
infcx: &'me InferCtxt<'me, 'tcx>,
- borrowck_context: Option<&'me mut BorrowCheckContext<'bccx, 'tcx>>,
+ borrowck_context: &'me mut BorrowCheckContext<'bccx, 'tcx>,
param_env: ty::ParamEnv<'tcx>,
@@ -47,17 +55,22 @@
/// What category do we assign the resulting `'a: 'b` relationships?
category: ConstraintCategory,
+
+ /// Information so that error reporting knows what types we are relating
+ /// when reporting a bound region error.
+ universe_info: UniverseInfo<'tcx>,
}
impl NllTypeRelatingDelegate<'me, 'bccx, 'tcx> {
fn new(
infcx: &'me InferCtxt<'me, 'tcx>,
- borrowck_context: Option<&'me mut BorrowCheckContext<'bccx, 'tcx>>,
+ borrowck_context: &'me mut BorrowCheckContext<'bccx, 'tcx>,
param_env: ty::ParamEnv<'tcx>,
locations: Locations,
category: ConstraintCategory,
+ universe_info: UniverseInfo<'tcx>,
) -> Self {
- Self { infcx, borrowck_context, param_env, locations, category }
+ Self { infcx, borrowck_context, param_env, locations, category, universe_info }
}
}
@@ -67,24 +80,20 @@
}
fn create_next_universe(&mut self) -> ty::UniverseIndex {
- self.infcx.create_next_universe()
+ let info_universe =
+ self.borrowck_context.constraints.universe_causes.push(self.universe_info.clone());
+ let universe = self.infcx.create_next_universe();
+ assert_eq!(info_universe, universe);
+ universe
}
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 };
- self.infcx.next_nll_region_var(origin)
- } else {
- self.infcx.tcx.lifetimes.re_erased
- }
+ let origin = NllRegionVariableOrigin::Existential { from_forall };
+ self.infcx.next_nll_region_var(origin)
}
fn next_placeholder_region(&mut self, placeholder: ty::PlaceholderRegion) -> ty::Region<'tcx> {
- if let Some(borrowck_context) = &mut self.borrowck_context {
- borrowck_context.constraints.placeholder_region(self.infcx, placeholder)
- } else {
- self.infcx.tcx.lifetimes.re_erased
- }
+ self.borrowck_context.constraints.placeholder_region(self.infcx, placeholder)
}
fn generalize_existential(&mut self, universe: ty::UniverseIndex) -> ty::Region<'tcx> {
@@ -100,17 +109,15 @@
sub: ty::Region<'tcx>,
info: ty::VarianceDiagInfo<'tcx>,
) {
- if let Some(borrowck_context) = &mut self.borrowck_context {
- let sub = borrowck_context.universal_regions.to_region_vid(sub);
- let sup = borrowck_context.universal_regions.to_region_vid(sup);
- borrowck_context.constraints.outlives_constraints.push(OutlivesConstraint {
- sup,
- sub,
- locations: self.locations,
- category: self.category,
- variance_info: info,
- });
- }
+ let sub = self.borrowck_context.universal_regions.to_region_vid(sub);
+ let sup = self.borrowck_context.universal_regions.to_region_vid(sup);
+ self.borrowck_context.constraints.outlives_constraints.push(OutlivesConstraint {
+ sup,
+ sub,
+ locations: self.locations,
+ category: self.category,
+ variance_info: info,
+ });
}
// We don't have to worry about the equality of consts during borrow checking
diff --git a/compiler/rustc_mir/src/borrow_check/universal_regions.rs b/compiler/rustc_mir/src/borrow_check/universal_regions.rs
index c2ac1e2..3c9b427 100644
--- a/compiler/rustc_mir/src/borrow_check/universal_regions.rs
+++ b/compiler/rustc_mir/src/borrow_check/universal_regions.rs
@@ -169,7 +169,7 @@
/// used because trait matching and type-checking will feed us
/// region constraints that reference those regions and we need to
/// be able to map them our internal `RegionVid`. This is
- /// basically equivalent to a `InternalSubsts`, except that it also
+ /// basically equivalent to an `InternalSubsts`, except that it also
/// contains an entry for `ReStatic` -- it might be nice to just
/// use a substs, and then handle `ReStatic` another way.
indices: FxHashMap<ty::Region<'tcx>, RegionVid>,
diff --git a/compiler/rustc_mir/src/const_eval/machine.rs b/compiler/rustc_mir/src/const_eval/machine.rs
index c809f4f..8a90686 100644
--- a/compiler/rustc_mir/src/const_eval/machine.rs
+++ b/compiler/rustc_mir/src/const_eval/machine.rs
@@ -30,7 +30,9 @@
&mut self,
instance: ty::Instance<'tcx>,
args: &[OpTy<'tcx>],
- ) -> InterpResult<'tcx> {
+ ) -> InterpResult<'tcx, Option<ty::Instance<'tcx>>> {
+ // The list of functions we handle here must be in sync with
+ // `is_lang_panic_fn` in `transform/check_consts/mod.rs`.
let def_id = instance.def_id();
if Some(def_id) == self.tcx.lang_items().panic_fn()
|| Some(def_id) == self.tcx.lang_items().panic_str()
@@ -43,10 +45,25 @@
let msg = Symbol::intern(self.read_str(&msg_place)?);
let span = self.find_closest_untracked_caller_location();
let (file, line, col) = self.location_triple_for_span(span);
- Err(ConstEvalErrKind::Panic { msg, file, line, col }.into())
- } else {
- Ok(())
+ return Err(ConstEvalErrKind::Panic { msg, file, line, col }.into());
+ } else if Some(def_id) == self.tcx.lang_items().panic_fmt()
+ || Some(def_id) == self.tcx.lang_items().begin_panic_fmt()
+ {
+ // For panic_fmt, call const_panic_fmt instead.
+ if let Some(const_panic_fmt) = self.tcx.lang_items().const_panic_fmt() {
+ return Ok(Some(
+ ty::Instance::resolve(
+ *self.tcx,
+ ty::ParamEnv::reveal_all(),
+ const_panic_fmt,
+ self.tcx.intern_substs(&[]),
+ )
+ .unwrap()
+ .unwrap(),
+ ));
+ }
}
+ Ok(None)
}
}
@@ -212,7 +229,9 @@
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))
+ let path = ecx.tcx.def_path_str(def.did);
+ Err(ConstEvalErrKind::NeedsRfc(format!("calling extern function `{}`", path))
+ .into())
}
}
_ => Ok(ecx.tcx.instance_mir(instance)),
@@ -239,28 +258,26 @@
if !ecx.tcx.has_attr(def.did, sym::default_method_body_is_const) {
// Some functions we support even if they are non-const -- but avoid testing
// that for const fn!
- ecx.hook_panic_fn(instance, args)?;
- // We certainly do *not* want to actually call the fn
- // though, so be sure we return here.
- throw_unsup_format!("calling non-const function `{}`", instance)
+ if let Some(new_instance) = ecx.hook_panic_fn(instance, args)? {
+ // We call another const fn instead.
+ return Self::find_mir_or_eval_fn(
+ ecx,
+ new_instance,
+ _abi,
+ args,
+ _ret,
+ _unwind,
+ );
+ } else {
+ // We certainly do *not* want to actually call the fn
+ // though, so be sure we return here.
+ throw_unsup_format!("calling non-const function `{}`", instance)
+ }
}
}
}
// This is a const fn. Call it.
- Ok(Some(match ecx.load_mir(instance.def, None) {
- Ok(body) => body,
- Err(err) => {
- if let err_unsup!(NoMirFor(did)) = err.kind() {
- let path = ecx.tcx.def_path_str(*did);
- return Err(ConstEvalErrKind::NeedsRfc(format!(
- "calling extern function `{}`",
- path
- ))
- .into());
- }
- return Err(err);
- }
- }))
+ Ok(Some(ecx.load_mir(instance.def, None)?))
}
fn call_intrinsic(
diff --git a/compiler/rustc_mir/src/dataflow/framework/engine.rs b/compiler/rustc_mir/src/dataflow/framework/engine.rs
index 3f9f558..7ff7c86 100644
--- a/compiler/rustc_mir/src/dataflow/framework/engine.rs
+++ b/compiler/rustc_mir/src/dataflow/framework/engine.rs
@@ -338,7 +338,7 @@
let rustc_mir_attrs = attrs
.iter()
- .filter(|attr| tcx.sess.check_name(attr, sym::rustc_mir))
+ .filter(|attr| attr.has_name(sym::rustc_mir))
.flat_map(|attr| attr.meta_item_list().into_iter().flat_map(|v| v.into_iter()));
for attr in rustc_mir_attrs {
diff --git a/compiler/rustc_mir/src/dataflow/framework/fmt.rs b/compiler/rustc_mir/src/dataflow/framework/fmt.rs
index 0140a75..35115ca 100644
--- a/compiler/rustc_mir/src/dataflow/framework/fmt.rs
+++ b/compiler/rustc_mir/src/dataflow/framework/fmt.rs
@@ -33,7 +33,7 @@
}
write!(f, "\u{001f}-")?;
- self.fmt_with(ctxt, f)
+ old.fmt_with(ctxt, f)
}
}
diff --git a/compiler/rustc_mir/src/dataflow/framework/mod.rs b/compiler/rustc_mir/src/dataflow/framework/mod.rs
index 344d7b9..a5badc0 100644
--- a/compiler/rustc_mir/src/dataflow/framework/mod.rs
+++ b/compiler/rustc_mir/src/dataflow/framework/mod.rs
@@ -42,7 +42,7 @@
mod direction;
mod engine;
pub mod fmt;
-mod graphviz;
+pub mod graphviz;
pub mod lattice;
mod visitor;
diff --git a/compiler/rustc_mir/src/dataflow/mod.rs b/compiler/rustc_mir/src/dataflow/mod.rs
index 03531a6..8a426cc 100644
--- a/compiler/rustc_mir/src/dataflow/mod.rs
+++ b/compiler/rustc_mir/src/dataflow/mod.rs
@@ -5,7 +5,7 @@
pub(crate) use self::drop_flag_effects::*;
pub use self::framework::{
- fmt, lattice, visit_results, Analysis, AnalysisDomain, Backward, BorrowckFlowState,
+ fmt, graphviz, lattice, visit_results, Analysis, AnalysisDomain, Backward, BorrowckFlowState,
BorrowckResults, Engine, Forward, GenKill, GenKillAnalysis, JoinSemiLattice, Results,
ResultsCursor, ResultsRefCursor, ResultsVisitor, SwitchIntEdgeEffects,
};
@@ -30,12 +30,12 @@
}
pub(crate) fn has_rustc_mir_with(
- sess: &Session,
+ _sess: &Session,
attrs: &[ast::Attribute],
name: Symbol,
) -> Option<MetaItem> {
for attr in attrs {
- if sess.check_name(attr, sym::rustc_mir) {
+ if attr.has_name(sym::rustc_mir) {
let items = attr.meta_item_list();
for item in items.iter().flat_map(|l| l.iter()) {
match item.meta_item() {
diff --git a/compiler/rustc_mir/src/interpret/cast.rs b/compiler/rustc_mir/src/interpret/cast.rs
index 514c1aa..6f18009 100644
--- a/compiler/rustc_mir/src/interpret/cast.rs
+++ b/compiler/rustc_mir/src/interpret/cast.rs
@@ -269,12 +269,27 @@
Immediate::new_slice(ptr, length.eval_usize(*self.tcx, self.param_env), self);
self.write_immediate(val, dest)
}
- (&ty::Dynamic(..), &ty::Dynamic(..)) => {
- // For now, upcasts are limited to changes in marker
- // traits, and hence never actually require an actual
- // change to the vtable.
+ (&ty::Dynamic(ref data_a, ..), &ty::Dynamic(ref data_b, ..)) => {
let val = self.read_immediate(src)?;
- self.write_immediate(*val, dest)
+ if data_a.principal_def_id() == data_b.principal_def_id() {
+ return self.write_immediate(*val, dest);
+ }
+ // trait upcasting coercion
+ let vptr_entry_idx = self.tcx.vtable_trait_upcasting_coercion_new_vptr_slot((
+ src_pointee_ty,
+ dest_pointee_ty,
+ ));
+
+ if let Some(entry_idx) = vptr_entry_idx {
+ let entry_idx = u64::try_from(entry_idx).unwrap();
+ let (old_data, old_vptr) = val.to_scalar_pair()?;
+ let old_vptr = self.scalar_to_ptr(old_vptr);
+ let new_vptr = self
+ .read_new_vtable_after_trait_upcasting_from_vtable(old_vptr, entry_idx)?;
+ self.write_immediate(Immediate::new_dyn_trait(old_data, new_vptr, self), dest)
+ } else {
+ self.write_immediate(*val, dest)
+ }
}
(_, &ty::Dynamic(ref data, _)) => {
// Initial cast from sized to dyn trait
@@ -325,7 +340,7 @@
// Example: `Arc<T>` -> `Arc<Trait>`
// here we need to increase the size of every &T thin ptr field to a fat ptr
for i in 0..src.layout.fields.count() {
- let cast_ty_field = cast_ty.field(self, i)?;
+ let cast_ty_field = cast_ty.field(self, i);
if cast_ty_field.is_zst() {
continue;
}
diff --git a/compiler/rustc_mir/src/interpret/eval_context.rs b/compiler/rustc_mir/src/interpret/eval_context.rs
index 516ef4f4..c6003d8 100644
--- a/compiler/rustc_mir/src/interpret/eval_context.rs
+++ b/compiler/rustc_mir/src/interpret/eval_context.rs
@@ -272,11 +272,12 @@
write!(f, "inside `{}`", self.instance)?;
}
if !self.span.is_dummy() {
- let lo = tcx.sess.source_map().lookup_char_pos(self.span.lo());
+ let sm = tcx.sess.source_map();
+ let lo = sm.lookup_char_pos(self.span.lo());
write!(
f,
" at {}:{}:{}",
- lo.file.name.prefer_local(),
+ sm.filename_for_diagnostics(&lo.file.name),
lo.line,
lo.col.to_usize() + 1
)?;
@@ -312,7 +313,7 @@
}
}
-impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> LayoutOf for InterpCx<'mir, 'tcx, M> {
+impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> LayoutOf<'tcx> for InterpCx<'mir, 'tcx, M> {
type Ty = Ty<'tcx>;
type TyAndLayout = InterpResult<'tcx, TyAndLayout<'tcx>>;
@@ -592,7 +593,7 @@
// Recurse to get the size of the dynamically sized field (must be
// the last field). Can't have foreign types here, how would we
// adjust alignment and size for them?
- let field = layout.field(self, layout.fields.count() - 1)?;
+ let field = layout.field(self, layout.fields.count() - 1);
let (unsized_size, unsized_align) =
match self.size_and_align_of(metadata, &field)? {
Some(size_and_align) => size_and_align,
@@ -645,7 +646,7 @@
ty::Slice(_) | ty::Str => {
let len = metadata.unwrap_meta().to_machine_usize(self)?;
- let elem = layout.field(self, 0)?;
+ let elem = layout.field(self, 0);
// Make sure the slice is not too big.
let size = elem.size.checked_mul(len, self).ok_or_else(|| {
diff --git a/compiler/rustc_mir/src/interpret/intrinsics.rs b/compiler/rustc_mir/src/interpret/intrinsics.rs
index dc1f905..bfab886 100644
--- a/compiler/rustc_mir/src/interpret/intrinsics.rs
+++ b/compiler/rustc_mir/src/interpret/intrinsics.rs
@@ -465,7 +465,7 @@
);
self.copy_op(&self.operand_index(&args[0], index)?, dest)?;
}
- sym::likely | sym::unlikely => {
+ sym::likely | sym::unlikely | sym::black_box => {
// These just return their argument
self.copy_op(&args[0], dest)?;
}
diff --git a/compiler/rustc_mir/src/interpret/memory.rs b/compiler/rustc_mir/src/interpret/memory.rs
index 6dcd944..4d13274 100644
--- a/compiler/rustc_mir/src/interpret/memory.rs
+++ b/compiler/rustc_mir/src/interpret/memory.rs
@@ -907,7 +907,7 @@
}
/// Reading and writing.
-impl<'tcx, 'a, Tag: Copy, Extra> AllocRefMut<'a, 'tcx, Tag, Extra> {
+impl<'tcx, 'a, Tag: Provenance, Extra> AllocRefMut<'a, 'tcx, Tag, Extra> {
pub fn write_scalar(
&mut self,
range: AllocRange,
@@ -928,7 +928,7 @@
}
}
-impl<'tcx, 'a, Tag: Copy, Extra> AllocRef<'a, 'tcx, Tag, Extra> {
+impl<'tcx, 'a, Tag: Provenance, Extra> AllocRef<'a, 'tcx, Tag, Extra> {
pub fn read_scalar(&self, range: AllocRange) -> InterpResult<'tcx, ScalarMaybeUninit<Tag>> {
Ok(self
.alloc
@@ -998,7 +998,11 @@
// Side-step AllocRef and directly access the underlying bytes more efficiently.
// (We are staying inside the bounds here so all is good.)
- let bytes = alloc_ref.alloc.get_bytes_mut(&alloc_ref.tcx, alloc_ref.range);
+ let alloc_id = alloc_ref.alloc_id;
+ let bytes = alloc_ref
+ .alloc
+ .get_bytes_mut(&alloc_ref.tcx, alloc_ref.range)
+ .map_err(move |e| e.to_interp_error(alloc_id))?;
// `zip` would stop when the first iterator ends; we want to definitely
// cover all of `bytes`.
for dest in bytes {
@@ -1072,7 +1076,10 @@
let (dest_alloc, extra) = self.get_raw_mut(dest_alloc_id)?;
let dest_range = alloc_range(dest_offset, size * num_copies);
M::memory_written(extra, &mut dest_alloc.extra, dest.provenance, dest_range)?;
- let dest_bytes = dest_alloc.get_bytes_mut_ptr(&tcx, dest_range).as_mut_ptr();
+ let dest_bytes = dest_alloc
+ .get_bytes_mut_ptr(&tcx, dest_range)
+ .map_err(|e| e.to_interp_error(dest_alloc_id))?
+ .as_mut_ptr();
if compressed.no_bytes_init() {
// Fast path: If all bytes are `uninit` then there is nothing to copy. The target range
@@ -1142,7 +1149,11 @@
Err(ptr) => ptr.into(),
Ok(bits) => {
let addr = u64::try_from(bits).unwrap();
- M::ptr_from_addr(&self, addr)
+ let ptr = M::ptr_from_addr(&self, addr);
+ if addr == 0 {
+ assert!(ptr.provenance.is_none(), "null pointer can never have an AllocId");
+ }
+ ptr
}
}
}
diff --git a/compiler/rustc_mir/src/interpret/operand.rs b/compiler/rustc_mir/src/interpret/operand.rs
index aba7db7..4afce2b 100644
--- a/compiler/rustc_mir/src/interpret/operand.rs
+++ b/compiler/rustc_mir/src/interpret/operand.rs
@@ -63,15 +63,19 @@
Immediate::ScalarPair(val.into(), Scalar::from_machine_usize(len, cx).into())
}
- pub fn new_dyn_trait(val: Scalar<Tag>, vtable: Pointer<Tag>, cx: &impl HasDataLayout) -> Self {
- Immediate::ScalarPair(val.into(), ScalarMaybeUninit::from_pointer(vtable, cx))
+ pub fn new_dyn_trait(
+ val: Scalar<Tag>,
+ vtable: Pointer<Option<Tag>>,
+ cx: &impl HasDataLayout,
+ ) -> Self {
+ Immediate::ScalarPair(val.into(), ScalarMaybeUninit::from_maybe_pointer(vtable, cx))
}
#[inline]
pub fn to_scalar_or_uninit(self) -> ScalarMaybeUninit<Tag> {
match self {
Immediate::Scalar(val) => val,
- Immediate::ScalarPair(..) => bug!("Got a wide pointer where a scalar was expected"),
+ Immediate::ScalarPair(..) => bug!("Got a scalar pair where a scalar was expected"),
}
}
@@ -79,6 +83,16 @@
pub fn to_scalar(self) -> InterpResult<'tcx, Scalar<Tag>> {
self.to_scalar_or_uninit().check_init()
}
+
+ #[inline]
+ pub fn to_scalar_pair(self) -> InterpResult<'tcx, (Scalar<Tag>, Scalar<Tag>)> {
+ match self {
+ Immediate::ScalarPair(val1, val2) => Ok((val1.check_init()?, val2.check_init()?)),
+ Immediate::Scalar(..) => {
+ bug!("Got a scalar where a scalar pair was expected")
+ }
+ }
+ }
}
// ScalarPair needs a type to interpret, so we often have an immediate and a type together
@@ -281,7 +295,7 @@
/// we can find the data.
/// Note that for a given layout, this operation will either always fail or always
/// succeed! Whether it succeeds depends on whether the layout can be represented
- /// in a `Immediate`, not on which data is stored there currently.
+ /// in an `Immediate`, not on which data is stored there currently.
pub(crate) fn try_read_immediate(
&self,
src: &OpTy<'tcx, M::PointerTag>,
@@ -350,7 +364,7 @@
Err(value) => value,
};
- let field_layout = op.layout.field(self, field)?;
+ let field_layout = op.layout.field(self, field);
if field_layout.is_zst() {
let immediate = Scalar::ZST.into();
return Ok(OpTy { op: Operand::Immediate(immediate), layout: field_layout });
@@ -541,9 +555,9 @@
match val.val {
ty::ConstKind::Param(_) | ty::ConstKind::Bound(..) => throw_inval!(TooGeneric),
ty::ConstKind::Error(_) => throw_inval!(AlreadyReported(ErrorReported)),
- ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted }) => {
- let instance = self.resolve(def, substs)?;
- Ok(self.eval_to_allocation(GlobalId { instance, promoted })?.into())
+ ty::ConstKind::Unevaluated(uv) => {
+ let instance = self.resolve(uv.def, uv.substs(*self.tcx))?;
+ Ok(self.eval_to_allocation(GlobalId { instance, promoted: uv.promoted })?.into())
}
ty::ConstKind::Infer(..) | ty::ConstKind::Placeholder(..) => {
span_bug!(self.cur_span(), "const_to_op: Unexpected ConstKind {:?}", val)
@@ -585,7 +599,7 @@
let ptr = self.global_base_pointer(Pointer::new(id, offset))?;
Operand::Indirect(MemPlace::from_ptr(ptr.into(), layout.align.abi))
}
- ConstValue::Scalar(x) => Operand::Immediate(tag_scalar(x.into())?.into()),
+ ConstValue::Scalar(x) => Operand::Immediate(tag_scalar(x)?.into()),
ConstValue::Slice { data, start, end } => {
// We rely on mutability being set correctly in `data` to prevent writes
// where none should happen.
diff --git a/compiler/rustc_mir/src/interpret/place.rs b/compiler/rustc_mir/src/interpret/place.rs
index 91fcc34..afad971 100644
--- a/compiler/rustc_mir/src/interpret/place.rs
+++ b/compiler/rustc_mir/src/interpret/place.rs
@@ -355,7 +355,7 @@
field: usize,
) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
let offset = base.layout.fields.offset(field);
- let field_layout = base.layout.field(self, field)?;
+ let field_layout = base.layout.field(self, field);
// Offset may need adjustment for unsized fields.
let (meta, offset) = if field_layout.is_unsized() {
@@ -405,7 +405,7 @@
}
let offset = stride * index; // `Size` multiplication
// All fields have the same layout.
- let field_layout = base.layout.field(self, 0)?;
+ let field_layout = base.layout.field(self, 0);
assert!(!field_layout.is_unsized());
base.offset(offset, MemPlaceMeta::None, field_layout, self)
@@ -430,7 +430,7 @@
FieldsShape::Array { stride, .. } => stride,
_ => span_bug!(self.cur_span(), "mplace_array_fields: expected an array layout"),
};
- let layout = base.layout.field(self, 0)?;
+ let layout = base.layout.field(self, 0);
let dl = &self.tcx.data_layout;
// `Size` multiplication
Ok((0..len).map(move |i| base.offset(stride * i, MemPlaceMeta::None, layout, dl)))
diff --git a/compiler/rustc_mir/src/interpret/terminator.rs b/compiler/rustc_mir/src/interpret/terminator.rs
index f369480..6349604 100644
--- a/compiler/rustc_mir/src/interpret/terminator.rs
+++ b/compiler/rustc_mir/src/interpret/terminator.rs
@@ -18,12 +18,7 @@
impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
fn fn_can_unwind(&self, attrs: CodegenFnAttrFlags, abi: Abi) -> bool {
- layout::fn_can_unwind(
- self.tcx.sess.panic_strategy(),
- attrs,
- layout::conv_from_spec_abi(*self.tcx, abi),
- abi,
- )
+ layout::fn_can_unwind(*self.tcx, attrs, abi)
}
pub(super) fn eval_terminator(
@@ -73,11 +68,11 @@
ty::FnPtr(sig) => {
let caller_abi = sig.abi();
let fn_ptr = self.read_pointer(&func)?;
- let fn_val = self.memory.get_fn(fn_ptr.into())?;
+ let fn_val = self.memory.get_fn(fn_ptr)?;
(
fn_val,
caller_abi,
- self.fn_can_unwind(layout::fn_ptr_codegen_fn_attr_flags(), caller_abi),
+ self.fn_can_unwind(CodegenFnAttrFlags::empty(), caller_abi),
)
}
ty::FnDef(def_id, substs) => {
@@ -466,7 +461,7 @@
// a thin pointer.
assert!(receiver_place.layout.is_unsized());
let receiver_ptr_ty = self.tcx.mk_mut_ptr(receiver_place.layout.ty);
- let this_receiver_ptr = self.layout_of(receiver_ptr_ty)?.field(self, 0)?;
+ let this_receiver_ptr = self.layout_of(receiver_ptr_ty)?.field(self, 0);
// Adjust receiver argument.
args[0] = OpTy::from(ImmTy::from_immediate(
Scalar::from_maybe_pointer(receiver_place.ptr, self).into(),
diff --git a/compiler/rustc_mir/src/interpret/traits.rs b/compiler/rustc_mir/src/interpret/traits.rs
index 7a93fce..131674d 100644
--- a/compiler/rustc_mir/src/interpret/traits.rs
+++ b/compiler/rustc_mir/src/interpret/traits.rs
@@ -21,7 +21,7 @@
&mut self,
ty: Ty<'tcx>,
poly_trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>,
- ) -> InterpResult<'tcx, Pointer<M::PointerTag>> {
+ ) -> InterpResult<'tcx, Pointer<Option<M::PointerTag>>> {
trace!("get_vtable(trait_ref={:?})", poly_trait_ref);
let (ty, poly_trait_ref) = self.tcx.erase_regions((ty, poly_trait_ref));
@@ -30,11 +30,11 @@
ensure_monomorphic_enough(*self.tcx, ty)?;
ensure_monomorphic_enough(*self.tcx, poly_trait_ref)?;
- let vtable_allocation = self.tcx.vtable_allocation(ty, poly_trait_ref);
+ let vtable_allocation = self.tcx.vtable_allocation((ty, poly_trait_ref));
let vtable_ptr = self.memory.global_base_pointer(Pointer::from(vtable_allocation))?;
- Ok(vtable_ptr)
+ Ok(vtable_ptr.into())
}
/// Resolves the function at the specified slot in the provided
@@ -121,4 +121,22 @@
}
Ok((Size::from_bytes(size), align))
}
+
+ pub fn read_new_vtable_after_trait_upcasting_from_vtable(
+ &self,
+ vtable: Pointer<Option<M::PointerTag>>,
+ idx: u64,
+ ) -> InterpResult<'tcx, Pointer<Option<M::PointerTag>>> {
+ let pointer_size = self.pointer_size();
+
+ let vtable_slot = vtable.offset(pointer_size * idx, self)?;
+ let new_vtable = self
+ .memory
+ .get(vtable_slot, pointer_size, self.tcx.data_layout.pointer_align.abi)?
+ .expect("cannot be a ZST");
+
+ let new_vtable = self.scalar_to_ptr(new_vtable.read_ptr_sized(Size::ZERO)?.check_init()?);
+
+ Ok(new_vtable)
+ }
}
diff --git a/compiler/rustc_mir/src/interpret/util.rs b/compiler/rustc_mir/src/interpret/util.rs
index 89f34cd..eb0fdeb 100644
--- a/compiler/rustc_mir/src/interpret/util.rs
+++ b/compiler/rustc_mir/src/interpret/util.rs
@@ -9,7 +9,7 @@
T: TypeFoldable<'tcx>,
{
debug!("ensure_monomorphic_enough: ty={:?}", ty);
- if !ty.needs_subst() {
+ if !ty.potentially_needs_subst() {
return Ok(());
}
@@ -21,19 +21,12 @@
impl<'tcx> TypeVisitor<'tcx> for UsedParamsNeedSubstVisitor<'tcx> {
type BreakTy = FoundParam;
- fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
- if !c.needs_subst() {
- return ControlFlow::CONTINUE;
- }
-
- match c.val {
- ty::ConstKind::Param(..) => ControlFlow::Break(FoundParam),
- _ => c.super_visit_with(self),
- }
+ fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
+ Some(self.tcx)
}
fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
- if !ty.needs_subst() {
+ if !ty.potentially_needs_subst() {
return ControlFlow::CONTINUE;
}
@@ -50,7 +43,7 @@
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()) {
+ match (is_used, subst.definitely_needs_subst(self.tcx)) {
// Just in case there are closures or generators within this subst,
// recurse.
(true, true) => return subst.super_visit_with(self),
@@ -73,6 +66,13 @@
_ => ty.super_visit_with(self),
}
}
+
+ fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
+ match c.val {
+ ty::ConstKind::Param(..) => ControlFlow::Break(FoundParam),
+ _ => c.super_visit_with(self),
+ }
+ }
}
let mut vis = UsedParamsNeedSubstVisitor { tcx };
diff --git a/compiler/rustc_mir/src/interpret/validity.rs b/compiler/rustc_mir/src/interpret/validity.rs
index 0c7f89c..2bb2f88 100644
--- a/compiler/rustc_mir/src/interpret/validity.rs
+++ b/compiler/rustc_mir/src/interpret/validity.rs
@@ -7,7 +7,6 @@
use std::convert::TryFrom;
use std::fmt::Write;
use std::num::NonZeroUsize;
-use std::ops::RangeInclusive;
use rustc_data_structures::fx::FxHashSet;
use rustc_hir as hir;
@@ -15,7 +14,9 @@
use rustc_middle::ty;
use rustc_middle::ty::layout::TyAndLayout;
use rustc_span::symbol::{sym, Symbol};
-use rustc_target::abi::{Abi, LayoutOf, Scalar as ScalarAbi, Size, VariantIdx, Variants};
+use rustc_target::abi::{
+ Abi, LayoutOf, Scalar as ScalarAbi, Size, VariantIdx, Variants, WrappingRange,
+};
use std::hash::Hash;
@@ -181,22 +182,10 @@
}
}
-// Test if a range that wraps at overflow contains `test`
-fn wrapping_range_contains(r: &RangeInclusive<u128>, test: u128) -> bool {
- let (lo, hi) = r.clone().into_inner();
- if lo > hi {
- // Wrapped
- (..=hi).contains(&test) || (lo..).contains(&test)
- } else {
- // Normal
- r.contains(&test)
- }
-}
-
// Formats such that a sentence like "expected something {}" to mean
// "expected something <in the given range>" makes sense.
-fn wrapping_range_format(r: &RangeInclusive<u128>, max_hi: u128) -> String {
- let (lo, hi) = r.clone().into_inner();
+fn wrapping_range_format(r: WrappingRange, max_hi: u128) -> String {
+ let WrappingRange { start: lo, end: hi } = r;
assert!(hi <= max_hi);
if lo > hi {
format!("less or equal to {}, or greater or equal to {}", hi, lo)
@@ -634,8 +623,8 @@
scalar_layout: &ScalarAbi,
) -> InterpResult<'tcx> {
let value = self.read_scalar(op)?;
- let valid_range = &scalar_layout.valid_range;
- let (lo, hi) = valid_range.clone().into_inner();
+ let valid_range = scalar_layout.valid_range.clone();
+ let WrappingRange { start: lo, end: hi } = valid_range;
// Determine the allowed range
// `max_hi` is as big as the size fits
let max_hi = u128::MAX >> (128 - op.layout.size.bits());
@@ -684,7 +673,7 @@
Ok(int) => int.assert_bits(op.layout.size),
};
// Now compare. This is slightly subtle because this is a special "wrap-around" range.
- if wrapping_range_contains(&valid_range, bits) {
+ if valid_range.contains(bits) {
Ok(())
} else {
throw_validation_failure!(self.path,
@@ -857,7 +846,7 @@
// types above, in `visit_primitive`.
// In run-time mode, we accept pointers in here. This is actually more
// permissive than a per-element check would be, e.g., we accept
- // an &[u8] that contains a pointer even though bytewise checking would
+ // a &[u8] that contains a pointer even though bytewise checking would
// reject it. However, that's good: We don't inherently want
// to reject those pointers, we just do not have the machinery to
// talk about parts of a pointer.
diff --git a/compiler/rustc_mir/src/lib.rs b/compiler/rustc_mir/src/lib.rs
index a58ded9..e439a24 100644
--- a/compiler/rustc_mir/src/lib.rs
+++ b/compiler/rustc_mir/src/lib.rs
@@ -8,10 +8,9 @@
#![feature(in_band_lifetimes)]
#![feature(array_windows)]
#![feature(assert_matches)]
-#![feature(bindings_after_at)]
+#![cfg_attr(bootstrap, feature(bindings_after_at))]
#![feature(bool_to_option)]
#![feature(box_patterns)]
-#![feature(box_syntax)]
#![feature(crate_visibility_modifier)]
#![feature(decl_macro)]
#![feature(exact_size_is_empty)]
@@ -30,6 +29,7 @@
#![feature(once_cell)]
#![feature(control_flow_enum)]
#![feature(try_reserve)]
+#![feature(try_reserve_kind)]
#![recursion_limit = "256"]
#[macro_use]
@@ -46,6 +46,9 @@
pub mod transform;
pub mod util;
+// A public API provided for the Rust compiler consumers.
+pub use self::borrow_check::consumers;
+
use rustc_middle::ty::query::Providers;
pub fn provide(providers: &mut Providers) {
diff --git a/compiler/rustc_mir/src/monomorphize/collector.rs b/compiler/rustc_mir/src/monomorphize/collector.rs
index 2ce7cf7..4cb3622 100644
--- a/compiler/rustc_mir/src/monomorphize/collector.rs
+++ b/compiler/rustc_mir/src/monomorphize/collector.rs
@@ -573,7 +573,7 @@
let type_length = instance
.substs
.iter()
- .flat_map(|arg| arg.walk())
+ .flat_map(|arg| arg.walk(tcx))
.filter(|arg| match arg.unpack() {
GenericArgKind::Type(_) | GenericArgKind::Const(_) => true,
GenericArgKind::Lifetime(_) => false,
@@ -1116,13 +1116,13 @@
| VtblEntry::MetadataSize
| VtblEntry::MetadataAlign
| VtblEntry::Vacant => None,
- VtblEntry::Method(def_id, substs) => ty::Instance::resolve_for_vtable(
- tcx,
- ty::ParamEnv::reveal_all(),
- *def_id,
- substs,
- )
- .filter(|instance| should_codegen_locally(tcx, instance)),
+ VtblEntry::TraitVPtr(_) => {
+ // all super trait items already covered, so skip them.
+ None
+ }
+ VtblEntry::Method(instance) => {
+ Some(*instance).filter(|instance| should_codegen_locally(tcx, instance))
+ }
})
.map(|item| create_fn_mono_item(tcx, item, source));
output.extend(methods);
@@ -1149,6 +1149,7 @@
match item.kind {
hir::ItemKind::ExternCrate(..)
| hir::ItemKind::Use(..)
+ | hir::ItemKind::Macro(..)
| hir::ItemKind::ForeignMod { .. }
| hir::ItemKind::TyAlias(..)
| hir::ItemKind::Trait(..)
diff --git a/compiler/rustc_mir/src/monomorphize/partitioning/default.rs b/compiler/rustc_mir/src/monomorphize/partitioning/default.rs
index 541c825..a559a6c 100644
--- a/compiler/rustc_mir/src/monomorphize/partitioning/default.rs
+++ b/compiler/rustc_mir/src/monomorphize/partitioning/default.rs
@@ -455,7 +455,7 @@
def_id
} else {
return if export_generics && is_generic {
- // If it is a upstream monomorphization and we export generics, we must make
+ // If it is an upstream monomorphization and we export generics, we must make
// it available to downstream crates.
*can_be_internalized = false;
default_visibility(tcx, def_id, true)
diff --git a/compiler/rustc_mir/src/monomorphize/partitioning/merging.rs b/compiler/rustc_mir/src/monomorphize/partitioning/merging.rs
index 5107e69..cbe3666 100644
--- a/compiler/rustc_mir/src/monomorphize/partitioning/merging.rs
+++ b/compiler/rustc_mir/src/monomorphize/partitioning/merging.rs
@@ -46,7 +46,7 @@
// Record that `second_smallest` now contains all the stuff that was in
// `smallest` before.
let mut consumed_cgu_names = cgu_contents.remove(&smallest.name()).unwrap();
- cgu_contents.get_mut(&second_smallest.name()).unwrap().extend(consumed_cgu_names.drain(..));
+ cgu_contents.get_mut(&second_smallest.name()).unwrap().append(&mut consumed_cgu_names);
debug!(
"CodegenUnit {} merged into CodegenUnit {}",
diff --git a/compiler/rustc_mir/src/monomorphize/polymorphize.rs b/compiler/rustc_mir/src/monomorphize/polymorphize.rs
index 30e758c7..3c55a4b 100644
--- a/compiler/rustc_mir/src/monomorphize/polymorphize.rs
+++ b/compiler/rustc_mir/src/monomorphize/polymorphize.rs
@@ -178,7 +178,7 @@
// Consider all generic params in a predicate as used if any other parameter in the
// predicate is used.
let any_param_used = {
- let mut vis = HasUsedGenericParams { unused_parameters };
+ let mut vis = HasUsedGenericParams { tcx, unused_parameters };
predicate.visit_with(&mut vis).is_break()
};
@@ -204,11 +204,7 @@
unused_parameters: &FiniteBitSet<u32>,
) {
let base_def_id = tcx.closure_base_def_id(def_id);
- if !tcx
- .get_attrs(base_def_id)
- .iter()
- .any(|a| tcx.sess.check_name(a, sym::rustc_polymorphize_error))
- {
+ if !tcx.get_attrs(base_def_id).iter().any(|a| a.has_name(sym::rustc_polymorphize_error)) {
return;
}
@@ -287,9 +283,12 @@
}
impl<'a, 'tcx> TypeVisitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> {
+ fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
+ Some(self.tcx)
+ }
#[instrument(skip(self))]
fn visit_const(&mut self, c: &'tcx Const<'tcx>) -> ControlFlow<Self::BreakTy> {
- if !c.has_param_types_or_consts() {
+ if !c.potentially_has_param_types_or_consts() {
return ControlFlow::CONTINUE;
}
@@ -299,7 +298,7 @@
self.unused_parameters.clear(param.index);
ControlFlow::CONTINUE
}
- ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs: _, promoted: Some(p)})
+ ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs_: _, promoted: Some(p)})
// Avoid considering `T` unused when constants are of the form:
// `<Self as Foo<T>>::foo::promoted[p]`
if self.def_id == def.did && !self.tcx.generics_of(def.did).has_self =>
@@ -310,10 +309,10 @@
self.visit_body(&promoted[p]);
ControlFlow::CONTINUE
}
- ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted: None })
- if self.tcx.def_kind(def.did) == DefKind::AnonConst =>
+ ty::ConstKind::Unevaluated(uv)
+ if self.tcx.def_kind(uv.def.did) == DefKind::AnonConst =>
{
- self.visit_child_body(def.did, substs);
+ self.visit_child_body(uv.def.did, uv.substs(self.tcx));
ControlFlow::CONTINUE
}
_ => c.super_visit_with(self),
@@ -322,7 +321,7 @@
#[instrument(skip(self))]
fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
- if !ty.has_param_types_or_consts() {
+ if !ty.potentially_has_param_types_or_consts() {
return ControlFlow::CONTINUE;
}
@@ -350,16 +349,21 @@
}
/// Visitor used to check if a generic parameter is used.
-struct HasUsedGenericParams<'a> {
+struct HasUsedGenericParams<'a, 'tcx> {
+ tcx: TyCtxt<'tcx>,
unused_parameters: &'a FiniteBitSet<u32>,
}
-impl<'a, 'tcx> TypeVisitor<'tcx> for HasUsedGenericParams<'a> {
+impl<'a, 'tcx> TypeVisitor<'tcx> for HasUsedGenericParams<'a, 'tcx> {
type BreakTy = ();
+ fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
+ Some(self.tcx)
+ }
+
#[instrument(skip(self))]
fn visit_const(&mut self, c: &'tcx Const<'tcx>) -> ControlFlow<Self::BreakTy> {
- if !c.has_param_types_or_consts() {
+ if !c.potentially_has_param_types_or_consts() {
return ControlFlow::CONTINUE;
}
@@ -377,7 +381,7 @@
#[instrument(skip(self))]
fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
- if !ty.has_param_types_or_consts() {
+ if !ty.potentially_has_param_types_or_consts() {
return ControlFlow::CONTINUE;
}
diff --git a/compiler/rustc_mir/src/shim.rs b/compiler/rustc_mir/src/shim.rs
index 796d024..8083ec9 100644
--- a/compiler/rustc_mir/src/shim.rs
+++ b/compiler/rustc_mir/src/shim.rs
@@ -16,7 +16,7 @@
use std::iter;
use crate::transform::{
- add_call_guards, add_moves_for_packed_drops, no_landing_pads, remove_noop_landing_pads,
+ abort_unwinding_calls, add_call_guards, add_moves_for_packed_drops, remove_noop_landing_pads,
run_passes, simplify,
};
use crate::util::elaborate_drops::{self, DropElaborator, DropFlagMode, DropStyle};
@@ -81,10 +81,10 @@
MirPhase::Const,
&[&[
&add_moves_for_packed_drops::AddMovesForPackedDrops,
- &no_landing_pads::NoLandingPads,
&remove_noop_landing_pads::RemoveNoopLandingPads,
&simplify::SimplifyCfg::new("make_shim"),
&add_call_guards::CriticalCallEdges,
+ &abort_unwinding_calls::AbortUnwindingCalls,
]],
);
@@ -163,7 +163,7 @@
let source = MirSource::from_instance(ty::InstanceDef::DropGlue(def_id, ty));
let mut body =
- new_body(source, blocks, local_decls_for_sig(&sig, span), sig.inputs().len(), span);
+ new_body(tcx, source, blocks, local_decls_for_sig(&sig, span), sig.inputs().len(), span);
if ty.is_some() {
// The first argument (index 0), but add 1 for the return value.
@@ -174,7 +174,7 @@
0,
Statement {
source_info,
- kind: StatementKind::Retag(RetagKind::Raw, box (dropee_ptr)),
+ kind: StatementKind::Retag(RetagKind::Raw, Box::new(dropee_ptr)),
},
);
}
@@ -202,6 +202,7 @@
}
fn new_body<'tcx>(
+ tcx: TyCtxt<'tcx>,
source: MirSource<'tcx>,
basic_blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>,
local_decls: IndexVec<Local, LocalDecl<'tcx>>,
@@ -209,6 +210,7 @@
span: Span,
) -> Body<'tcx> {
Body::new(
+ tcx,
source,
basic_blocks,
IndexVec::from_elem_n(
@@ -353,7 +355,14 @@
self.def_id,
self.sig.inputs_and_output[0],
));
- new_body(source, self.blocks, self.local_decls, self.sig.inputs().len(), self.span)
+ new_body(
+ self.tcx,
+ source,
+ self.blocks,
+ self.local_decls,
+ self.sig.inputs().len(),
+ self.span,
+ )
}
fn source_info(&self) -> SourceInfo {
@@ -388,10 +397,10 @@
fn copy_shim(&mut self) {
let rcvr = self.tcx.mk_place_deref(Place::from(Local::new(1 + 0)));
- let ret_statement = self.make_statement(StatementKind::Assign(box (
+ let ret_statement = self.make_statement(StatementKind::Assign(Box::new((
Place::return_place(),
Rvalue::Use(Operand::Copy(rcvr)),
- )));
+ ))));
self.block(vec![ret_statement], TerminatorKind::Return, false);
}
@@ -418,11 +427,11 @@
// `func == Clone::clone(&ty) -> ty`
let func_ty = tcx.mk_fn_def(self.def_id, substs);
- let func = Operand::Constant(box Constant {
+ let func = Operand::Constant(Box::new(Constant {
span: self.span,
user_ty: None,
literal: ty::Const::zero_sized(tcx, func_ty).into(),
- });
+ }));
let ref_loc = self.make_place(
Mutability::Not,
@@ -430,10 +439,10 @@
);
// `let ref_loc: &ty = &src;`
- let statement = self.make_statement(StatementKind::Assign(box (
+ let statement = self.make_statement(StatementKind::Assign(Box::new((
ref_loc,
Rvalue::Ref(tcx.lifetimes.re_erased, BorrowKind::Shared, src),
- )));
+ ))));
// `let loc = Clone::clone(ref_loc);`
self.block(
@@ -461,10 +470,10 @@
let tcx = self.tcx;
let cond = self.make_place(Mutability::Mut, tcx.types.bool);
- let compute_cond = self.make_statement(StatementKind::Assign(box (
+ let compute_cond = self.make_statement(StatementKind::Assign(Box::new((
cond,
- Rvalue::BinaryOp(BinOp::Ne, box (Operand::Copy(end), Operand::Copy(beg))),
- )));
+ Rvalue::BinaryOp(BinOp::Ne, Box::new((Operand::Copy(end), Operand::Copy(beg)))),
+ ))));
// `if end != beg { goto loop_body; } else { goto loop_end; }`
self.block(
@@ -475,11 +484,11 @@
}
fn make_usize(&self, value: u64) -> Box<Constant<'tcx>> {
- box Constant {
+ Box::new(Constant {
span: self.span,
user_ty: None,
literal: ty::Const::from_usize(self.tcx, value).into(),
- }
+ })
}
fn array_shim(
@@ -500,18 +509,18 @@
// `let end = len;`
// `goto #1;`
let inits = vec![
- self.make_statement(StatementKind::Assign(box (
+ self.make_statement(StatementKind::Assign(Box::new((
Place::from(beg),
Rvalue::Use(Operand::Constant(self.make_usize(0))),
- ))),
- self.make_statement(StatementKind::Assign(box (
+ )))),
+ self.make_statement(StatementKind::Assign(Box::new((
end,
- Rvalue::Use(Operand::Constant(box Constant {
+ Rvalue::Use(Operand::Constant(Box::new(Constant {
span: self.span,
user_ty: None,
literal: len.into(),
- })),
- ))),
+ }))),
+ )))),
];
self.block(inits, TerminatorKind::Goto { target: BasicBlock::new(1) }, false);
@@ -532,13 +541,13 @@
// BB #3
// `beg = beg + 1;`
// `goto #1`;
- let statements = vec![self.make_statement(StatementKind::Assign(box (
+ let statements = vec![self.make_statement(StatementKind::Assign(Box::new((
Place::from(beg),
Rvalue::BinaryOp(
BinOp::Add,
- box (Operand::Copy(Place::from(beg)), Operand::Constant(self.make_usize(1))),
+ Box::new((Operand::Copy(Place::from(beg)), Operand::Constant(self.make_usize(1)))),
),
- )))];
+ ))))];
self.block(statements, TerminatorKind::Goto { target: BasicBlock::new(1) }, false);
// BB #4
@@ -551,10 +560,10 @@
// goto #6;
let end = beg;
let beg = self.local_decls.push(LocalDecl::new(tcx.types.usize, span));
- let init = self.make_statement(StatementKind::Assign(box (
+ let init = self.make_statement(StatementKind::Assign(Box::new((
Place::from(beg),
Rvalue::Use(Operand::Constant(self.make_usize(0))),
- )));
+ ))));
self.block(vec![init], TerminatorKind::Goto { target: BasicBlock::new(6) }, true);
// BB #6 (cleanup): loop {
@@ -585,13 +594,13 @@
// BB #8 (cleanup)
// `beg = beg + 1;`
// `goto #6;`
- let statement = self.make_statement(StatementKind::Assign(box (
+ let statement = self.make_statement(StatementKind::Assign(Box::new((
Place::from(beg),
Rvalue::BinaryOp(
BinOp::Add,
- box (Operand::Copy(Place::from(beg)), Operand::Constant(self.make_usize(1))),
+ Box::new((Operand::Copy(Place::from(beg)), Operand::Constant(self.make_usize(1)))),
),
- )));
+ ))));
self.block(vec![statement], TerminatorKind::Goto { target: BasicBlock::new(6) }, true);
// BB #9 (resume)
@@ -748,10 +757,10 @@
let borrow_kind = BorrowKind::Mut { allow_two_phase_borrow: false };
statements.push(Statement {
source_info,
- kind: StatementKind::Assign(box (
+ kind: StatementKind::Assign(Box::new((
Place::from(ref_rcvr),
Rvalue::Ref(tcx.lifetimes.re_erased, borrow_kind, rcvr_place()),
- )),
+ ))),
});
Operand::Move(Place::from(ref_rcvr))
}
@@ -765,11 +774,11 @@
CallKind::Direct(def_id) => {
let ty = tcx.type_of(def_id);
(
- Operand::Constant(box Constant {
+ Operand::Constant(Box::new(Constant {
span,
user_ty: None,
literal: ty::Const::zero_sized(tcx, ty).into(),
- }),
+ })),
rcvr.into_iter().collect::<Vec<_>>(),
)
}
@@ -851,8 +860,14 @@
block(&mut blocks, vec![], TerminatorKind::Resume, true);
}
- let mut body =
- new_body(MirSource::from_instance(instance), blocks, local_decls, sig.inputs().len(), span);
+ let mut body = new_body(
+ tcx,
+ MirSource::from_instance(instance),
+ blocks,
+ local_decls,
+ sig.inputs().len(),
+ span,
+ );
if let Abi::RustCall = sig.abi {
body.spread_arg = Some(Local::new(sig.inputs().len()));
@@ -917,6 +932,7 @@
let source = MirSource::item(ctor_id);
let body = new_body(
+ tcx,
source,
IndexVec::from_elem_n(start_block, 1),
local_decls,
diff --git a/compiler/rustc_mir/src/transform/abort_unwinding_calls.rs b/compiler/rustc_mir/src/transform/abort_unwinding_calls.rs
new file mode 100644
index 0000000..aecb237
--- /dev/null
+++ b/compiler/rustc_mir/src/transform/abort_unwinding_calls.rs
@@ -0,0 +1,141 @@
+use crate::transform::MirPass;
+use rustc_hir::def::DefKind;
+use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
+use rustc_middle::mir::*;
+use rustc_middle::ty::layout;
+use rustc_middle::ty::{self, TyCtxt};
+use rustc_target::spec::abi::Abi;
+
+/// A pass that runs which is targeted at ensuring that codegen guarantees about
+/// unwinding are upheld for compilations of panic=abort programs.
+///
+/// When compiling with panic=abort codegen backends generally want to assume
+/// that all Rust-defined functions do not unwind, and it's UB if they actually
+/// do unwind. Foreign functions, however, can be declared as "may unwind" via
+/// their ABI (e.g. `extern "C-unwind"`). To uphold the guarantees that
+/// Rust-defined functions never unwind a well-behaved Rust program needs to
+/// catch unwinding from foreign functions and force them to abort.
+///
+/// This pass walks over all functions calls which may possibly unwind,
+/// and if any are found sets their cleanup to a block that aborts the process.
+/// This forces all unwinds, in panic=abort mode happening in foreign code, to
+/// trigger a process abort.
+#[derive(PartialEq)]
+pub struct AbortUnwindingCalls;
+
+impl<'tcx> MirPass<'tcx> for AbortUnwindingCalls {
+ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
+ let def_id = body.source.def_id();
+ let kind = tcx.def_kind(def_id);
+
+ // We don't simplify the MIR of constants at this time because that
+ // namely results in a cyclic query when we call `tcx.type_of` below.
+ let is_function = match kind {
+ DefKind::Fn | DefKind::AssocFn | DefKind::Ctor(..) => true,
+ _ => tcx.is_closure(def_id),
+ };
+ if !is_function {
+ return;
+ }
+
+ // This pass only runs on functions which themselves cannot unwind,
+ // forcibly changing the body of the function to structurally provide
+ // this guarantee by aborting on an unwind. If this function can unwind,
+ // then there's nothing to do because it already should work correctly.
+ //
+ // Here we test for this function itself whether its ABI allows
+ // unwinding or not.
+ let body_flags = tcx.codegen_fn_attrs(def_id).flags;
+ let body_ty = tcx.type_of(def_id);
+ let body_abi = match body_ty.kind() {
+ ty::FnDef(..) => body_ty.fn_sig(tcx).abi(),
+ ty::Closure(..) => Abi::RustCall,
+ ty::Generator(..) => Abi::Rust,
+ _ => span_bug!(body.span, "unexpected body ty: {:?}", body_ty),
+ };
+ let body_can_unwind = layout::fn_can_unwind(tcx, body_flags, body_abi);
+
+ // Look in this function body for any basic blocks which are terminated
+ // with a function call, and whose function we're calling may unwind.
+ // This will filter to functions with `extern "C-unwind"` ABIs, for
+ // example.
+ let mut calls_to_terminate = Vec::new();
+ let mut cleanups_to_remove = Vec::new();
+ for (id, block) in body.basic_blocks().iter_enumerated() {
+ if block.is_cleanup {
+ continue;
+ }
+ let terminator = match &block.terminator {
+ Some(terminator) => terminator,
+ None => continue,
+ };
+ let span = terminator.source_info.span;
+
+ let call_can_unwind = match &terminator.kind {
+ TerminatorKind::Call { func, .. } => {
+ let ty = func.ty(body, tcx);
+ let sig = ty.fn_sig(tcx);
+ let flags = match ty.kind() {
+ ty::FnPtr(_) => CodegenFnAttrFlags::empty(),
+ ty::FnDef(def_id, _) => tcx.codegen_fn_attrs(*def_id).flags,
+ _ => span_bug!(span, "invalid callee of type {:?}", ty),
+ };
+ layout::fn_can_unwind(tcx, flags, sig.abi())
+ }
+ TerminatorKind::Drop { .. }
+ | TerminatorKind::DropAndReplace { .. }
+ | TerminatorKind::Assert { .. }
+ | TerminatorKind::FalseUnwind { .. } => {
+ layout::fn_can_unwind(tcx, CodegenFnAttrFlags::empty(), Abi::Rust)
+ }
+ _ => continue,
+ };
+
+ // If this function call can't unwind, then there's no need for it
+ // to have a landing pad. This means that we can remove any cleanup
+ // registered for it.
+ if !call_can_unwind {
+ cleanups_to_remove.push(id);
+ continue;
+ }
+
+ // Otherwise if this function can unwind, then if the outer function
+ // can also unwind there's nothing to do. If the outer function
+ // can't unwind, however, we need to change the landing pad for this
+ // function call to one that aborts.
+ if !body_can_unwind {
+ calls_to_terminate.push(id);
+ }
+ }
+
+ // For call instructions which need to be terminated, we insert a
+ // singular basic block which simply terminates, and then configure the
+ // `cleanup` attribute for all calls we found to this basic block we
+ // insert which means that any unwinding that happens in the functions
+ // will force an abort of the process.
+ if !calls_to_terminate.is_empty() {
+ let bb = BasicBlockData {
+ statements: Vec::new(),
+ is_cleanup: true,
+ terminator: Some(Terminator {
+ source_info: SourceInfo::outermost(body.span),
+ kind: TerminatorKind::Abort,
+ }),
+ };
+ let abort_bb = body.basic_blocks_mut().push(bb);
+
+ for bb in calls_to_terminate {
+ let cleanup = body.basic_blocks_mut()[bb].terminator_mut().unwind_mut().unwrap();
+ *cleanup = Some(abort_bb);
+ }
+ }
+
+ for id in cleanups_to_remove {
+ let cleanup = body.basic_blocks_mut()[id].terminator_mut().unwind_mut().unwrap();
+ *cleanup = None;
+ }
+
+ // We may have invalidated some `cleanup` blocks so clean those up now.
+ super::simplify::remove_dead_blocks(tcx, body);
+ }
+}
diff --git a/compiler/rustc_mir/src/transform/add_retag.rs b/compiler/rustc_mir/src/transform/add_retag.rs
index 6fe9f64..cb60881 100644
--- a/compiler/rustc_mir/src/transform/add_retag.rs
+++ b/compiler/rustc_mir/src/transform/add_retag.rs
@@ -105,7 +105,7 @@
0..0,
places.map(|place| Statement {
source_info,
- kind: StatementKind::Retag(RetagKind::FnEntry, box (place)),
+ kind: StatementKind::Retag(RetagKind::FnEntry, Box::new(place)),
}),
);
}
@@ -137,7 +137,7 @@
0,
Statement {
source_info,
- kind: StatementKind::Retag(RetagKind::Default, box (dest_place)),
+ kind: StatementKind::Retag(RetagKind::Default, Box::new(dest_place)),
},
);
}
@@ -175,7 +175,10 @@
let source_info = block_data.statements[i].source_info;
block_data.statements.insert(
i + 1,
- Statement { source_info, kind: StatementKind::Retag(retag_kind, box (place)) },
+ Statement {
+ source_info,
+ kind: StatementKind::Retag(retag_kind, Box::new(place)),
+ },
);
}
}
diff --git a/compiler/rustc_mir/src/transform/check_consts/validation.rs b/compiler/rustc_mir/src/transform/check_consts/check.rs
similarity index 92%
rename from compiler/rustc_mir/src/transform/check_consts/validation.rs
rename to compiler/rustc_mir/src/transform/check_consts/check.rs
index cfc538e..0c38127 100644
--- a/compiler/rustc_mir/src/transform/check_consts/validation.rs
+++ b/compiler/rustc_mir/src/transform/check_consts/check.rs
@@ -9,7 +9,7 @@
use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor};
use rustc_middle::mir::*;
use rustc_middle::ty::cast::CastTy;
-use rustc_middle::ty::subst::GenericArgKind;
+use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts};
use rustc_middle::ty::{self, adjustment::PointerCast, Instance, InstanceDef, Ty, TyCtxt};
use rustc_middle::ty::{Binder, TraitPredicate, TraitRef};
use rustc_span::{sym, Span, Symbol};
@@ -180,7 +180,7 @@
}
}
-pub struct Validator<'mir, 'tcx> {
+pub struct Checker<'mir, 'tcx> {
ccx: &'mir ConstCx<'mir, 'tcx>,
qualifs: Qualifs<'mir, 'tcx>,
@@ -194,7 +194,7 @@
secondary_errors: Vec<Diagnostic>,
}
-impl Deref for Validator<'mir, 'tcx> {
+impl Deref for Checker<'mir, 'tcx> {
type Target = ConstCx<'mir, 'tcx>;
fn deref(&self) -> &Self::Target {
@@ -202,9 +202,9 @@
}
}
-impl Validator<'mir, 'tcx> {
+impl Checker<'mir, 'tcx> {
pub fn new(ccx: &'mir ConstCx<'mir, 'tcx>) -> Self {
- Validator {
+ Checker {
span: ccx.body.span,
ccx,
qualifs: Default::default(),
@@ -365,7 +365,7 @@
fn check_local_or_return_ty(&mut self, ty: Ty<'tcx>, local: Local) {
let kind = self.body.local_kind(local);
- for ty in ty.walk() {
+ for ty in ty.walk(self.tcx) {
let ty = match ty.unpack() {
GenericArgKind::Type(ty) => ty,
@@ -420,10 +420,10 @@
ty::PredicateKind::ClosureKind(..) => {
bug!("closure kind predicate on function: {:#?}", predicate)
}
- ty::PredicateKind::Subtype(_) => {
- bug!("subtype predicate on function: {:#?}", predicate)
+ ty::PredicateKind::Subtype(_) | ty::PredicateKind::Coerce(_) => {
+ bug!("subtype/coerce predicate on function: {:#?}", predicate)
}
- ty::PredicateKind::Trait(pred, _constness) => {
+ ty::PredicateKind::Trait(pred) => {
if Some(pred.def_id()) == tcx.lang_items().sized_trait() {
continue;
}
@@ -477,7 +477,7 @@
}
}
-impl Visitor<'tcx> for Validator<'mir, 'tcx> {
+impl Visitor<'tcx> for Checker<'mir, 'tcx> {
fn visit_basic_block_data(&mut self, bb: BasicBlock, block: &BasicBlockData<'tcx>) {
trace!("visit_basic_block_data: bb={:?} is_cleanup={:?}", bb, block.is_cleanup);
@@ -748,12 +748,7 @@
| ProjectionElem::Downcast(..)
| ProjectionElem::Subslice { .. }
| ProjectionElem::Field(..)
- | ProjectionElem::Index(_) => {
- let base_ty = Place::ty_from(place_local, proj_base, self.body, self.tcx).ty;
- if base_ty.is_union() {
- self.check_op(ops::UnionAccess);
- }
- }
+ | ProjectionElem::Index(_) => {}
}
}
@@ -798,7 +793,7 @@
let fn_ty = func.ty(body, tcx);
- let (mut callee, substs) = match *fn_ty.kind() {
+ let (mut callee, mut substs) = match *fn_ty.kind() {
ty::FnDef(def_id, substs) => (def_id, substs),
ty::FnPtr(_) => {
@@ -810,6 +805,8 @@
}
};
+ let mut nonconst_call_permission = false;
+
// Attempting to call a trait method?
if let Some(trait_id) = tcx.trait_of_item(callee) {
trace!("attempting to call a trait method");
@@ -822,22 +819,58 @@
let obligation = Obligation::new(
ObligationCause::dummy(),
param_env,
- Binder::dummy(TraitPredicate { trait_ref }),
+ Binder::dummy(TraitPredicate {
+ trait_ref,
+ constness: ty::BoundConstness::ConstIfConst,
+ }),
);
let implsrc = tcx.infer_ctxt().enter(|infcx| {
- let mut selcx = SelectionContext::new(&infcx);
- selcx.select(&obligation).unwrap()
+ let mut selcx =
+ SelectionContext::with_constness(&infcx, hir::Constness::Const);
+ selcx.select(&obligation)
});
- // If the method is provided via a where-clause that does not use the `?const`
- // opt-out, the call is allowed.
- if let Some(ImplSource::Param(_, hir::Constness::Const)) = implsrc {
- debug!(
- "const_trait_impl: provided {:?} via where-clause in {:?}",
- trait_ref, param_env
- );
- return;
+ match implsrc {
+ Ok(Some(ImplSource::Param(_, ty::BoundConstness::ConstIfConst))) => {
+ debug!(
+ "const_trait_impl: provided {:?} via where-clause in {:?}",
+ trait_ref, param_env
+ );
+ return;
+ }
+ Ok(Some(ImplSource::UserDefined(data))) => {
+ let callee_name = tcx.item_name(callee);
+ if let Some(&did) = tcx
+ .associated_item_def_ids(data.impl_def_id)
+ .iter()
+ .find(|did| tcx.item_name(**did) == callee_name)
+ {
+ // using internal substs is ok here, since this is only
+ // used for the `resolve` call below
+ substs = InternalSubsts::identity_for_item(tcx, did);
+ callee = did;
+ }
+ }
+ _ if !tcx.is_const_fn_raw(callee) => {
+ // At this point, it is only legal when the caller is marked with
+ // #[default_method_body_is_const], and the callee is in the same
+ // trait.
+ let callee_trait = tcx.trait_of_item(callee);
+ if callee_trait.is_some() {
+ if tcx.has_attr(caller, sym::default_method_body_is_const) {
+ if tcx.trait_of_item(caller) == callee_trait {
+ nonconst_call_permission = true;
+ }
+ }
+ }
+
+ if !nonconst_call_permission {
+ self.check_op(ops::FnCallNonConst);
+ return;
+ }
+ }
+ _ => {}
}
// Resolve a trait method call to its concrete implementation, which may be in a
@@ -876,44 +909,17 @@
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 is_intrinsic && tcx.item_name(callee) == sym::transmute {
- self.check_op(ops::Transmute);
- return;
- }
-
if !tcx.is_const_fn_raw(callee) {
- let mut permitted = false;
-
- let callee_trait = tcx.trait_of_item(callee);
- if let Some(trait_id) = callee_trait {
- if tcx.has_attr(caller, sym::default_method_body_is_const) {
- // permit call to non-const fn when caller has default_method_body_is_const..
- if tcx.trait_of_item(caller) == callee_trait {
- // ..and caller and callee are in the same trait.
- permitted = true;
- }
- }
- if !permitted {
- // if trait's impls are all const, permit the call.
- let mut const_impls = true;
- tcx.for_each_relevant_impl(trait_id, substs.type_at(0), |imp| {
- if const_impls {
- if let hir::Constness::NotConst = tcx.impl_constness(imp) {
- const_impls = false;
- }
- }
- });
- if const_impls {
- permitted = true;
- }
+ if tcx.trait_of_item(callee).is_some() {
+ if tcx.has_attr(callee, sym::default_method_body_is_const) {
+ // To get to here we must have already found a const impl for the
+ // trait, but for it to still be non-const can be that the impl is
+ // using default method bodies.
+ nonconst_call_permission = true;
}
}
- if !permitted {
+ if !nonconst_call_permission {
self.check_op(ops::FnCallNonConst);
return;
}
diff --git a/compiler/rustc_mir/src/transform/check_consts/mod.rs b/compiler/rustc_mir/src/transform/check_consts/mod.rs
index 19aee03..a5cb0f4 100644
--- a/compiler/rustc_mir/src/transform/check_consts/mod.rs
+++ b/compiler/rustc_mir/src/transform/check_consts/mod.rs
@@ -9,15 +9,15 @@
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_middle::mir;
use rustc_middle::ty::{self, TyCtxt};
-use rustc_span::Symbol;
+use rustc_span::{sym, Symbol};
pub use self::qualifs::Qualif;
+pub mod check;
mod ops;
pub mod post_drop_elaboration;
pub mod qualifs;
mod resolver;
-pub mod validation;
/// Information about the item currently being const-checked, as well as a reference to the global
/// context.
@@ -74,9 +74,14 @@
/// Returns `true` if this `DefId` points to one of the official `panic` lang items.
pub fn is_lang_panic_fn(tcx: TyCtxt<'tcx>, def_id: DefId) -> bool {
+ // We can allow calls to these functions because `hook_panic_fn` in
+ // `const_eval/machine.rs` ensures the calls are handled specially.
+ // Keep in sync with what that function handles!
Some(def_id) == tcx.lang_items().panic_fn()
|| Some(def_id) == tcx.lang_items().panic_str()
|| Some(def_id) == tcx.lang_items().begin_panic_fn()
+ || Some(def_id) == tcx.lang_items().panic_fmt()
+ || Some(def_id) == tcx.lang_items().begin_panic_fmt()
}
pub fn rustc_allow_const_fn_unstable(
@@ -99,6 +104,13 @@
pub fn is_const_stable_const_fn(tcx: TyCtxt<'tcx>, def_id: DefId) -> bool {
use attr::{ConstStability, Stability, StabilityLevel};
+ // A default body marked const is not const-stable because const
+ // trait fns currently cannot be const-stable. We shouldn't
+ // restrict default bodies to only call const-stable functions.
+ if tcx.has_attr(def_id, sym::default_method_body_is_const) {
+ return false;
+ }
+
// Const-stability is only relevant for `const fn`.
assert!(tcx.is_const_fn_raw(def_id));
diff --git a/compiler/rustc_mir/src/transform/check_consts/ops.rs b/compiler/rustc_mir/src/transform/check_consts/ops.rs
index fd72ec4..8923d98 100644
--- a/compiler/rustc_mir/src/transform/check_consts/ops.rs
+++ b/compiler/rustc_mir/src/transform/check_consts/ops.rs
@@ -86,7 +86,7 @@
}
}
-/// A call to a `#[unstable]` const fn or `#[rustc_const_unstable]` function.
+/// A call to an `#[unstable]` const fn or `#[rustc_const_unstable]` function.
///
/// Contains the name of the feature that would allow the use of this function.
#[derive(Debug)]
@@ -255,7 +255,7 @@
);
err.span_label(
span,
- format!("this borrow of an interior mutable value may end up in the final value"),
+ "this borrow of an interior mutable value may end up in the final value",
);
if let hir::ConstContext::Static(_) = ccx.const_kind() {
err.help(
@@ -501,51 +501,6 @@
}
}
-#[derive(Debug)]
-pub struct Transmute;
-impl NonConstOp for Transmute {
- fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status {
- if ccx.const_kind() != hir::ConstContext::ConstFn {
- Status::Allowed
- } else {
- Status::Unstable(sym::const_fn_transmute)
- }
- }
-
- fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
- let mut err = feature_err(
- &ccx.tcx.sess.parse_sess,
- sym::const_fn_transmute,
- span,
- &format!("`transmute` is not allowed in {}s", ccx.const_kind()),
- );
- err.note("`transmute` is only allowed in constants and statics for now");
- err
- }
-}
-
-#[derive(Debug)]
-pub struct UnionAccess;
-impl NonConstOp for UnionAccess {
- fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status {
- // Union accesses are stable in all contexts except `const fn`.
- if ccx.const_kind() != hir::ConstContext::ConstFn {
- Status::Allowed
- } else {
- Status::Unstable(sym::const_fn_union)
- }
- }
-
- fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
- feature_err(
- &ccx.tcx.sess.parse_sess,
- sym::const_fn_union,
- span,
- "unions in const fn are unstable",
- )
- }
-}
-
// Types that cannot appear in the signature or locals of a `const fn`.
pub mod ty {
use super::*;
diff --git a/compiler/rustc_mir/src/transform/check_consts/post_drop_elaboration.rs b/compiler/rustc_mir/src/transform/check_consts/post_drop_elaboration.rs
index 057092b..b08ce21 100644
--- a/compiler/rustc_mir/src/transform/check_consts/post_drop_elaboration.rs
+++ b/compiler/rustc_mir/src/transform/check_consts/post_drop_elaboration.rs
@@ -3,9 +3,9 @@
use rustc_middle::ty::TyCtxt;
use rustc_span::Span;
+use super::check::Qualifs;
use super::ops::{self, NonConstOp};
use super::qualifs::{NeedsDrop, Qualif};
-use super::validation::Qualifs;
use super::ConstCx;
/// Returns `true` if we should use the more precise live drop checker that runs after drop
diff --git a/compiler/rustc_mir/src/transform/check_consts/qualifs.rs b/compiler/rustc_mir/src/transform/check_consts/qualifs.rs
index ac8c748..413a963 100644
--- a/compiler/rustc_mir/src/transform/check_consts/qualifs.rs
+++ b/compiler/rustc_mir/src/transform/check_consts/qualifs.rs
@@ -247,7 +247,7 @@
// Check the qualifs of the value of `const` items.
if let Some(ct) = constant.literal.const_for_ty() {
- if let ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs: _, promoted }) = ct.val {
+ if let ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs_: _, promoted }) = ct.val {
assert!(promoted.is_none());
// Don't peek inside trait associated constants.
if cx.tcx.trait_of_item(def.did).is_none() {
diff --git a/compiler/rustc_mir/src/transform/const_prop.rs b/compiler/rustc_mir/src/transform/const_prop.rs
index e02e41d..5c51aa4 100644
--- a/compiler/rustc_mir/src/transform/const_prop.rs
+++ b/compiler/rustc_mir/src/transform/const_prop.rs
@@ -17,7 +17,7 @@
Location, Operand, Place, Rvalue, SourceInfo, SourceScope, SourceScopeData, Statement,
StatementKind, Terminator, TerminatorKind, UnOp, RETURN_PLACE,
};
-use rustc_middle::ty::layout::{HasTyCtxt, LayoutError, TyAndLayout};
+use rustc_middle::ty::layout::{LayoutError, TyAndLayout};
use rustc_middle::ty::subst::{InternalSubsts, Subst};
use rustc_middle::ty::{
self, ConstInt, ConstKind, Instance, ParamEnv, ScalarInt, Ty, TyCtxt, TypeFoldable,
@@ -120,7 +120,7 @@
.predicates_of(def_id.to_def_id())
.predicates
.iter()
- .filter_map(|(p, _)| if p.is_global() { Some(*p) } else { None });
+ .filter_map(|(p, _)| if p.is_global(tcx) { Some(*p) } else { None });
if traits::impossible_predicates(
tcx,
traits::elaborate_predicates(tcx, predicates).map(|o| o.predicate).collect(),
@@ -132,6 +132,7 @@
trace!("ConstProp starting for {:?}", def_id);
let dummy_body = &Body::new(
+ tcx,
body.source,
body.basic_blocks().clone(),
body.source_scopes.clone(),
@@ -145,7 +146,7 @@
// FIXME(oli-obk, eddyb) Optimize locals (or even local paths) to hold
// constants, instead of just checking for const-folding succeeding.
- // That would require an uniform one-def no-mutation analysis
+ // That would require a uniform one-def no-mutation analysis
// and RPO (or recursing when needing the value of a local).
let mut optimization_finder = ConstPropagator::new(body, dummy_body, tcx);
optimization_finder.visit_body(body);
@@ -329,7 +330,7 @@
source_info: Option<SourceInfo>,
}
-impl<'mir, 'tcx> LayoutOf for ConstPropagator<'mir, 'tcx> {
+impl<'mir, 'tcx> LayoutOf<'tcx> for ConstPropagator<'mir, 'tcx> {
type Ty = Ty<'tcx>;
type TyAndLayout = Result<TyAndLayout<'tcx>, LayoutError<'tcx>>;
@@ -345,13 +346,20 @@
}
}
-impl<'mir, 'tcx> HasTyCtxt<'tcx> for ConstPropagator<'mir, 'tcx> {
+impl<'mir, 'tcx> ty::layout::HasTyCtxt<'tcx> for ConstPropagator<'mir, 'tcx> {
#[inline]
fn tcx(&self) -> TyCtxt<'tcx> {
self.tcx
}
}
+impl<'mir, 'tcx> ty::layout::HasParamEnv<'tcx> for ConstPropagator<'mir, 'tcx> {
+ #[inline]
+ fn param_env(&self) -> ty::ParamEnv<'tcx> {
+ self.param_env
+ }
+}
+
impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
fn new(
body: &Body<'tcx>,
@@ -468,7 +476,7 @@
/// Returns the value, if any, of evaluating `c`.
fn eval_constant(&mut self, c: &Constant<'tcx>, source_info: SourceInfo) -> Option<OpTy<'tcx>> {
// FIXME we need to revisit this for #67176
- if c.needs_subst() {
+ if c.definitely_needs_subst(self.tcx) {
return None;
}
@@ -483,14 +491,14 @@
// Promoteds must lint and not error as the user didn't ask for them
ConstKind::Unevaluated(ty::Unevaluated {
def: _,
- substs: _,
+ substs_: _,
promoted: Some(_),
}) => true,
// Out of backwards compatibility we cannot report hard errors in unused
// generic functions using associated constants of the generic parameters.
- _ => c.literal.needs_subst(),
+ _ => c.literal.definitely_needs_subst(*tcx),
},
- ConstantKind::Val(_, ty) => ty.needs_subst(),
+ ConstantKind::Val(_, ty) => ty.definitely_needs_subst(*tcx),
};
if lint_only {
// Out of backwards compatibility we cannot report hard errors in unused
@@ -720,7 +728,7 @@
}
// FIXME we need to revisit this for #67176
- if rvalue.needs_subst() {
+ if rvalue.definitely_needs_subst(self.tcx) {
return None;
}
diff --git a/compiler/rustc_mir/src/transform/coverage/counters.rs b/compiler/rustc_mir/src/transform/coverage/counters.rs
index 272a7bf..6726b66 100644
--- a/compiler/rustc_mir/src/transform/coverage/counters.rs
+++ b/compiler/rustc_mir/src/transform/coverage/counters.rs
@@ -100,7 +100,7 @@
CounterValueReference::from(next)
}
- /// Expression IDs start from u32::MAX and go down because a Expression can reference
+ /// Expression IDs start from u32::MAX and go down because an Expression can reference
/// (add or subtract counts) of both Counter regions and Expression regions. The counter
/// expression operand IDs must be unique across both types.
fn next_expression(&mut self) -> InjectedExpressionId {
diff --git a/compiler/rustc_mir/src/transform/coverage/debug.rs b/compiler/rustc_mir/src/transform/coverage/debug.rs
index f667233..4640796 100644
--- a/compiler/rustc_mir/src/transform/coverage/debug.rs
+++ b/compiler/rustc_mir/src/transform/coverage/debug.rs
@@ -344,7 +344,7 @@
return if counter_format.id {
format!("{}#{}", block_label, id.index())
} else {
- format!("{}", block_label)
+ block_label.to_string()
};
}
}
@@ -369,10 +369,10 @@
}
return format!("({})", self.format_counter_kind(counter_kind));
}
- return format!("{}", self.format_counter_kind(counter_kind));
+ return self.format_counter_kind(counter_kind);
}
}
- format!("#{}", operand.index().to_string())
+ format!("#{}", operand.index())
}
}
diff --git a/compiler/rustc_mir/src/transform/coverage/graph.rs b/compiler/rustc_mir/src/transform/coverage/graph.rs
index 0521f50..d78ad6c 100644
--- a/compiler/rustc_mir/src/transform/coverage/graph.rs
+++ b/compiler/rustc_mir/src/transform/coverage/graph.rs
@@ -491,15 +491,19 @@
term_kind: &'tcx TerminatorKind<'tcx>,
) -> Box<dyn Iterator<Item = &'a BasicBlock> + 'a> {
let mut successors = term_kind.successors();
- box match &term_kind {
- // SwitchInt successors are never unwind, and all of them should be traversed.
- TerminatorKind::SwitchInt { .. } => successors,
- // For all other kinds, return only the first successor, if any, and ignore unwinds.
- // NOTE: `chain(&[])` is required to coerce the `option::iter` (from
- // `next().into_iter()`) into the `mir::Successors` aliased type.
- _ => successors.next().into_iter().chain(&[]),
- }
- .filter(move |&&successor| body[successor].terminator().kind != TerminatorKind::Unreachable)
+ Box::new(
+ match &term_kind {
+ // SwitchInt successors are never unwind, and all of them should be traversed.
+ TerminatorKind::SwitchInt { .. } => successors,
+ // For all other kinds, return only the first successor, if any, and ignore unwinds.
+ // NOTE: `chain(&[])` is required to coerce the `option::iter` (from
+ // `next().into_iter()`) into the `mir::Successors` aliased type.
+ _ => successors.next().into_iter().chain(&[]),
+ }
+ .filter(move |&&successor| {
+ body[successor].terminator().kind != TerminatorKind::Unreachable
+ }),
+ )
}
/// Maintains separate worklists for each loop in the BasicCoverageBlock CFG, plus one for the
@@ -526,8 +530,8 @@
pub fn new(basic_coverage_blocks: &CoverageGraph) -> Self {
let start_bcb = basic_coverage_blocks.start_node();
let backedges = find_loop_backedges(basic_coverage_blocks);
- let mut context_stack = Vec::new();
- context_stack.push(TraversalContext { loop_backedges: None, worklist: vec![start_bcb] });
+ let context_stack =
+ vec![TraversalContext { loop_backedges: None, worklist: vec![start_bcb] }];
// `context_stack` starts with a `TraversalContext` for the main function context (beginning
// with the `start` BasicCoverageBlock of the function). New worklists are pushed to the top
// of the stack as loops are entered, and popped off of the stack when a loop's worklist is
diff --git a/compiler/rustc_mir/src/transform/coverage/mod.rs b/compiler/rustc_mir/src/transform/coverage/mod.rs
index 71c244f..f7fbea6 100644
--- a/compiler/rustc_mir/src/transform/coverage/mod.rs
+++ b/compiler/rustc_mir/src/transform/coverage/mod.rs
@@ -334,7 +334,7 @@
/// process (via `take_counter()`).
///
/// Any other counter associated with a `BasicCoverageBlock`, or its incoming edge, but not
- /// associated with a `CoverageSpan`, should only exist if the counter is a `Expression`
+ /// associated with a `CoverageSpan`, should only exist if the counter is an `Expression`
/// dependency (one of the expression operands). Collect them, and inject the additional
/// counters into the MIR, without a reportable coverage span.
fn inject_indirect_counters(
@@ -478,10 +478,10 @@
let source_info = data.terminator().source_info;
let statement = Statement {
source_info,
- kind: StatementKind::Coverage(box Coverage {
+ kind: StatementKind::Coverage(Box::new(Coverage {
kind: counter_kind,
code_region: some_code_region,
- }),
+ })),
};
data.statements.insert(0, statement);
}
@@ -495,7 +495,7 @@
let source_info = data.terminator().source_info;
let statement = Statement {
source_info,
- kind: StatementKind::Coverage(box Coverage { kind: expression, code_region: None }),
+ kind: StatementKind::Coverage(Box::new(Coverage { kind: expression, code_region: None })),
};
data.statements.push(statement);
}
diff --git a/compiler/rustc_mir/src/transform/coverage/test_macros/Cargo.toml b/compiler/rustc_mir/src/transform/coverage/test_macros/Cargo.toml
index eda1ced..cc93fd4 100644
--- a/compiler/rustc_mir/src/transform/coverage/test_macros/Cargo.toml
+++ b/compiler/rustc_mir/src/transform/coverage/test_macros/Cargo.toml
@@ -1,5 +1,4 @@
[package]
-authors = ["The Rust Project Developers"]
name = "coverage_test_macros"
version = "0.0.0"
edition = "2018"
diff --git a/compiler/rustc_mir/src/transform/coverage/tests.rs b/compiler/rustc_mir/src/transform/coverage/tests.rs
index e5b3059..14dd0a8 100644
--- a/compiler/rustc_mir/src/transform/coverage/tests.rs
+++ b/compiler/rustc_mir/src/transform/coverage/tests.rs
@@ -44,11 +44,11 @@
fn dummy_ty() -> &'static TyS<'static> {
thread_local! {
- static DUMMY_TYS: &'static TyS<'static> = Box::leak(box TyS::make_for_test(
+ static DUMMY_TYS: &'static TyS<'static> = Box::leak(Box::new(TyS::make_for_test(
ty::Bool,
TypeFlags::empty(),
DebruijnIndex::from_usize(0),
- ));
+ )));
}
&DUMMY_TYS.with(|tys| *tys)
diff --git a/compiler/rustc_mir/src/transform/early_otherwise_branch.rs b/compiler/rustc_mir/src/transform/early_otherwise_branch.rs
index 0712704..e507bcb 100644
--- a/compiler/rustc_mir/src/transform/early_otherwise_branch.rs
+++ b/compiler/rustc_mir/src/transform/early_otherwise_branch.rs
@@ -96,14 +96,14 @@
opt_to_apply.infos[0].first_switch_info.discr_used_in_switch;
let not_equal_rvalue = Rvalue::BinaryOp(
not_equal,
- box (
+ Box::new((
Operand::Copy(Place::from(second_discriminant_temp)),
Operand::Copy(first_descriminant_place),
- ),
+ )),
);
patch.add_statement(
end_of_block_location,
- StatementKind::Assign(box (Place::from(not_equal_temp), not_equal_rvalue)),
+ StatementKind::Assign(Box::new((Place::from(not_equal_temp), not_equal_rvalue))),
);
let new_targets = opt_to_apply
diff --git a/compiler/rustc_mir/src/transform/elaborate_drops.rs b/compiler/rustc_mir/src/transform/elaborate_drops.rs
index c0fcfb6..9b44af0 100644
--- a/compiler/rustc_mir/src/transform/elaborate_drops.rs
+++ b/compiler/rustc_mir/src/transform/elaborate_drops.rs
@@ -409,7 +409,7 @@
assert!(!data.is_cleanup, "DropAndReplace in unwind path not supported");
let assign = Statement {
- kind: StatementKind::Assign(box (place, Rvalue::Use(value.clone()))),
+ kind: StatementKind::Assign(Box::new((place, Rvalue::Use(value.clone())))),
source_info: terminator.source_info,
};
diff --git a/compiler/rustc_mir/src/transform/function_item_references.rs b/compiler/rustc_mir/src/transform/function_item_references.rs
index 8d02ac6..ba2c91a 100644
--- a/compiler/rustc_mir/src/transform/function_item_references.rs
+++ b/compiler/rustc_mir/src/transform/function_item_references.rs
@@ -49,7 +49,7 @@
// Handle calls to `transmute`
if self.tcx.is_diagnostic_item(sym::transmute, def_id) {
let arg_ty = args[0].ty(self.body, self.tcx);
- for generic_inner_ty in arg_ty.walk() {
+ for generic_inner_ty in arg_ty.walk(self.tcx) {
if let GenericArgKind::Type(inner_ty) = generic_inner_ty.unpack() {
if let Some((fn_id, fn_substs)) =
FunctionItemRefChecker::is_fn_ref(inner_ty)
@@ -110,7 +110,7 @@
let arg_defs = self.tcx.fn_sig(def_id).skip_binder().inputs();
for (arg_num, arg_def) in arg_defs.iter().enumerate() {
// For all types reachable from the argument type in the fn sig
- for generic_inner_ty in arg_def.walk() {
+ for generic_inner_ty in arg_def.walk(self.tcx) {
if let GenericArgKind::Type(inner_ty) = generic_inner_ty.unpack() {
// If the inner type matches the type bound by `Pointer`
if TyS::same_type(inner_ty, bound_ty) {
@@ -132,7 +132,7 @@
/// If the given predicate is the trait `fmt::Pointer`, returns the bound parameter type.
fn is_pointer_trait(&self, bound: &PredicateKind<'tcx>) -> Option<Ty<'tcx>> {
- if let ty::PredicateKind::Trait(predicate, _) = bound {
+ 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 {
diff --git a/compiler/rustc_mir/src/transform/generator.rs b/compiler/rustc_mir/src/transform/generator.rs
index 3560b4b..acdaa5b 100644
--- a/compiler/rustc_mir/src/transform/generator.rs
+++ b/compiler/rustc_mir/src/transform/generator.rs
@@ -53,7 +53,6 @@
MaybeBorrowedLocals, MaybeLiveLocals, MaybeRequiresStorage, MaybeStorageLive,
};
use crate::dataflow::{self, Analysis};
-use crate::transform::no_landing_pads::no_landing_pads;
use crate::transform::simplify;
use crate::transform::MirPass;
use crate::util::dump_mir;
@@ -275,7 +274,7 @@
Statement {
source_info,
kind: StatementKind::SetDiscriminant {
- place: box self_place,
+ place: Box::new(self_place),
variant_index: state_disc,
},
}
@@ -290,7 +289,7 @@
let self_place = Place::from(SELF_ARG);
let assign = Statement {
source_info: SourceInfo::outermost(body.span),
- kind: StatementKind::Assign(box (temp, Rvalue::Discriminant(self_place))),
+ kind: StatementKind::Assign(Box::new((temp, Rvalue::Discriminant(self_place)))),
};
(assign, temp)
}
@@ -627,7 +626,7 @@
// Locals that are always live or ones that need to be stored across
// suspension points are not eligible for overlap.
let mut ineligible_locals = always_live_locals.into_inner();
- ineligible_locals.intersect(saved_locals);
+ ineligible_locals.intersect(&**saved_locals);
// Compute the storage conflicts for all eligible locals.
let mut visitor = StorageConflictVisitor {
@@ -702,7 +701,7 @@
}
let mut eligible_storage_live = flow_state.clone();
- eligible_storage_live.intersect(&self.saved_locals);
+ eligible_storage_live.intersect(&**self.saved_locals);
for local in eligible_storage_live.iter() {
self.local_conflicts.union_row_with(&eligible_storage_live, local);
@@ -955,13 +954,11 @@
0,
Statement {
source_info,
- kind: StatementKind::Retag(RetagKind::Raw, box Place::from(SELF_ARG)),
+ kind: StatementKind::Retag(RetagKind::Raw, Box::new(Place::from(SELF_ARG))),
},
)
}
- no_landing_pads(tcx, &mut body);
-
// Make sure we remove dead blocks to remove
// unrelated code from the resume part of the function
simplify::remove_dead_blocks(tcx, &mut body);
@@ -987,11 +984,11 @@
) -> BasicBlock {
let assert_block = BasicBlock::new(body.basic_blocks().len());
let term = TerminatorKind::Assert {
- cond: Operand::Constant(box Constant {
+ cond: Operand::Constant(Box::new(Constant {
span: body.span,
user_ty: None,
literal: ty::Const::from_bool(tcx, false).into(),
- }),
+ })),
expected: true,
msg: message,
target: assert_block,
@@ -1133,8 +1130,6 @@
make_generator_state_argument_indirect(tcx, body);
make_generator_state_argument_pinned(tcx, body);
- no_landing_pads(tcx, body);
-
// Make sure we remove dead blocks to remove
// unrelated code from the drop part of the function
simplify::remove_dead_blocks(tcx, body);
@@ -1212,10 +1207,10 @@
let resume_arg = Local::new(2); // 0 = return, 1 = self
statements.push(Statement {
source_info,
- kind: StatementKind::Assign(box (
+ kind: StatementKind::Assign(Box::new((
point.resume_arg,
Rvalue::Use(Operand::Move(resume_arg.into())),
- )),
+ ))),
});
}
@@ -1292,10 +1287,10 @@
0,
Statement {
source_info,
- kind: StatementKind::Assign(box (
+ kind: StatementKind::Assign(Box::new((
new_resume_local.into(),
Rvalue::Use(Operand::Move(resume_local.into())),
- )),
+ ))),
},
);
diff --git a/compiler/rustc_mir/src/transform/inline.rs b/compiler/rustc_mir/src/transform/inline.rs
index 7d765ce..8e9da31 100644
--- a/compiler/rustc_mir/src/transform/inline.rs
+++ b/compiler/rustc_mir/src/transform/inline.rs
@@ -520,7 +520,7 @@
let temp = Place::from(self.new_call_temp(caller_body, &callsite, dest_ty));
caller_body[callsite.block].statements.push(Statement {
source_info: callsite.source_info,
- kind: StatementKind::Assign(box (temp, dest)),
+ kind: StatementKind::Assign(Box::new((temp, dest))),
});
self.tcx.mk_place_deref(temp)
} else {
@@ -607,15 +607,9 @@
}
// Insert all of the (mapped) parts of the callee body into the caller.
- caller_body.local_decls.extend(
- // FIXME(eddyb) make `Range<Local>` iterable so that we can use
- // `callee_body.local_decls.drain(callee_body.vars_and_temps())`
- callee_body
- .vars_and_temps_iter()
- .map(|local| callee_body.local_decls[local].clone()),
- );
- caller_body.source_scopes.extend(callee_body.source_scopes.drain(..));
- caller_body.var_debug_info.extend(callee_body.var_debug_info.drain(..));
+ caller_body.local_decls.extend(callee_body.drain_vars_and_temps());
+ caller_body.source_scopes.extend(&mut callee_body.source_scopes.drain(..));
+ caller_body.var_debug_info.append(&mut callee_body.var_debug_info);
caller_body.basic_blocks_mut().extend(callee_body.basic_blocks_mut().drain(..));
caller_body[callsite.block].terminator = Some(Terminator {
@@ -729,7 +723,7 @@
let local = self.new_call_temp(caller_body, callsite, arg_ty);
caller_body[callsite.block].statements.push(Statement {
source_info: callsite.source_info,
- kind: StatementKind::Assign(box (Place::from(local), Rvalue::Use(arg))),
+ kind: StatementKind::Assign(Box::new((Place::from(local), Rvalue::Use(arg)))),
});
local
}
diff --git a/compiler/rustc_mir/src/transform/inline/cycle.rs b/compiler/rustc_mir/src/transform/inline/cycle.rs
index c9eafaf..385394b 100644
--- a/compiler/rustc_mir/src/transform/inline/cycle.rs
+++ b/compiler/rustc_mir/src/transform/inline/cycle.rs
@@ -89,7 +89,7 @@
// 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() {
+ if callee.definitely_needs_subst(tcx) {
continue;
}
}
diff --git a/compiler/rustc_mir/src/transform/instcombine.rs b/compiler/rustc_mir/src/transform/instcombine.rs
index b64189a..805f546 100644
--- a/compiler/rustc_mir/src/transform/instcombine.rs
+++ b/compiler/rustc_mir/src/transform/instcombine.rs
@@ -124,7 +124,7 @@
let constant =
Constant { span: source_info.span, literal: len.into(), user_ty: None };
- *rvalue = Rvalue::Use(Operand::Constant(box constant));
+ *rvalue = Rvalue::Use(Operand::Constant(Box::new(constant)));
}
}
}
diff --git a/compiler/rustc_mir/src/transform/lower_intrinsics.rs b/compiler/rustc_mir/src/transform/lower_intrinsics.rs
index 6d7e4cd..e9f1d4f 100644
--- a/compiler/rustc_mir/src/transform/lower_intrinsics.rs
+++ b/compiler/rustc_mir/src/transform/lower_intrinsics.rs
@@ -29,14 +29,14 @@
if let Some((destination, target)) = *destination {
block.statements.push(Statement {
source_info: terminator.source_info,
- kind: StatementKind::Assign(box (
+ kind: StatementKind::Assign(Box::new((
destination,
- Rvalue::Use(Operand::Constant(box Constant {
+ Rvalue::Use(Operand::Constant(Box::new(Constant {
span: terminator.source_info.span,
user_ty: None,
literal: ty::Const::zero_sized(tcx, tcx.types.unit).into(),
- })),
- )),
+ }))),
+ ))),
});
terminator.kind = TerminatorKind::Goto { target };
}
@@ -46,13 +46,13 @@
let mut args = args.drain(..);
block.statements.push(Statement {
source_info: terminator.source_info,
- kind: StatementKind::CopyNonOverlapping(
- box rustc_middle::mir::CopyNonOverlapping {
+ kind: StatementKind::CopyNonOverlapping(Box::new(
+ rustc_middle::mir::CopyNonOverlapping {
src: args.next().unwrap(),
dst: args.next().unwrap(),
count: args.next().unwrap(),
},
- ),
+ )),
});
assert_eq!(
args.next(),
@@ -79,10 +79,10 @@
};
block.statements.push(Statement {
source_info: terminator.source_info,
- kind: StatementKind::Assign(box (
+ kind: StatementKind::Assign(Box::new((
destination,
- Rvalue::BinaryOp(bin_op, box (lhs, rhs)),
- )),
+ Rvalue::BinaryOp(bin_op, Box::new((lhs, rhs))),
+ ))),
});
terminator.kind = TerminatorKind::Goto { target };
}
@@ -97,10 +97,10 @@
let tp_ty = substs.type_at(0);
block.statements.push(Statement {
source_info: terminator.source_info,
- kind: StatementKind::Assign(box (
+ kind: StatementKind::Assign(Box::new((
destination,
Rvalue::NullaryOp(NullOp::SizeOf, tp_ty),
- )),
+ ))),
});
terminator.kind = TerminatorKind::Goto { target };
}
@@ -112,10 +112,10 @@
let arg = tcx.mk_place_deref(arg);
block.statements.push(Statement {
source_info: terminator.source_info,
- kind: StatementKind::Assign(box (
+ kind: StatementKind::Assign(Box::new((
destination,
Rvalue::Discriminant(arg),
- )),
+ ))),
});
terminator.kind = TerminatorKind::Goto { target };
}
@@ -147,8 +147,8 @@
match &args[2] {
Operand::Constant(_) => {} // all good
_ => {
- let msg = format!("last argument of `simd_shuffle` is required to be a `const` item");
- tcx.sess.span_err(span, &msg);
+ let msg = "last argument of `simd_shuffle` is required to be a `const` item";
+ tcx.sess.span_err(span, msg);
}
}
}
diff --git a/compiler/rustc_mir/src/transform/match_branches.rs b/compiler/rustc_mir/src/transform/match_branches.rs
index 21b208a..37a3fa5 100644
--- a/compiler/rustc_mir/src/transform/match_branches.rs
+++ b/compiler/rustc_mir/src/transform/match_branches.rs
@@ -140,11 +140,11 @@
let op = if f_b { BinOp::Eq } else { BinOp::Ne };
let rhs = Rvalue::BinaryOp(
op,
- box (Operand::Copy(Place::from(discr_local)), const_cmp),
+ Box::new((Operand::Copy(Place::from(discr_local)), const_cmp)),
);
Statement {
source_info: f.source_info,
- kind: StatementKind::Assign(box (*lhs, rhs)),
+ kind: StatementKind::Assign(Box::new((*lhs, rhs))),
}
}
}
@@ -157,7 +157,10 @@
.push(Statement { source_info, kind: StatementKind::StorageLive(discr_local) });
from.statements.push(Statement {
source_info,
- kind: StatementKind::Assign(box (Place::from(discr_local), Rvalue::Use(discr))),
+ kind: StatementKind::Assign(Box::new((
+ Place::from(discr_local),
+ Rvalue::Use(discr),
+ ))),
});
from.statements.extend(new_stmts);
from.statements
diff --git a/compiler/rustc_mir/src/transform/mod.rs b/compiler/rustc_mir/src/transform/mod.rs
index 5c20159..d4c2456 100644
--- a/compiler/rustc_mir/src/transform/mod.rs
+++ b/compiler/rustc_mir/src/transform/mod.rs
@@ -13,6 +13,7 @@
use rustc_span::{Span, Symbol};
use std::borrow::Cow;
+pub mod abort_unwinding_calls;
pub mod add_call_guards;
pub mod add_moves_for_packed_drops;
pub mod add_retag;
@@ -39,7 +40,6 @@
pub mod lower_slice_len;
pub mod match_branches;
pub mod multiple_return_terminators;
-pub mod no_landing_pads;
pub mod nrvo;
pub mod promote_consts;
pub mod remove_noop_landing_pads;
@@ -48,6 +48,7 @@
pub mod remove_zsts;
pub mod required_consts;
pub mod rustc_peek;
+pub mod separate_const_switch;
pub mod simplify;
pub mod simplify_branches;
pub mod simplify_comparison_integral;
@@ -240,7 +241,7 @@
let ccx = check_consts::ConstCx { body, tcx, const_kind, param_env: tcx.param_env(def.did) };
- let mut validator = check_consts::validation::Validator::new(&ccx);
+ let mut validator = check_consts::check::Checker::new(&ccx);
validator.check_body();
// We return the qualifs in the return place for every MIR body, even though it is only used
@@ -258,10 +259,12 @@
}
// Unsafety check uses the raw mir, so make sure it is run.
- if let Some(param_did) = def.const_param_did {
- tcx.ensure().unsafety_check_result_for_const_arg((def.did, param_did));
- } else {
- tcx.ensure().unsafety_check_result(def.did);
+ if !tcx.sess.opts.debugging_opts.thir_unsafeck {
+ if let Some(param_did) = def.const_param_did {
+ tcx.ensure().unsafety_check_result_for_const_arg((def.did, param_did));
+ } else {
+ tcx.ensure().unsafety_check_result(def.did);
+ }
}
let mut body = tcx.mir_built(def).steal();
@@ -397,7 +400,7 @@
}
}
- debug_assert!(!body.has_free_regions(), "Free regions in MIR for CTFE");
+ debug_assert!(!body.has_free_regions(tcx), "Free regions in MIR for CTFE");
body
}
@@ -448,7 +451,6 @@
let post_borrowck_cleanup: &[&dyn MirPass<'tcx>] = &[
// Remove all things only needed by analysis
- &no_landing_pads::NoLandingPads,
&simplify_branches::SimplifyBranches::new("initial"),
&remove_noop_landing_pads::RemoveNoopLandingPads,
&cleanup_post_borrowck::CleanupNonCodegenStatements,
@@ -456,7 +458,10 @@
// These next passes must be executed together
&add_call_guards::CriticalCallEdges,
&elaborate_drops::ElaborateDrops,
- &no_landing_pads::NoLandingPads,
+ // This will remove extraneous landing pads which are no longer
+ // necessary as well as well as forcing any call in a non-unwinding
+ // function calling a possibly-unwinding function to abort the process.
+ &abort_unwinding_calls::AbortUnwindingCalls,
// AddMovesForPackedDrops needs to run after drop
// elaboration.
&add_moves_for_packed_drops::AddMovesForPackedDrops,
@@ -501,6 +506,7 @@
// inst combine is after MatchBranchSimplification to clean up Ne(_1, false)
&multiple_return_terminators::MultipleReturnTerminators,
&instcombine::InstCombine,
+ &separate_const_switch::SeparateConstSwitch,
&const_prop::ConstProp,
&simplify_branches::SimplifyBranches::new("after-const-prop"),
&early_otherwise_branch::EarlyOtherwiseBranch,
@@ -588,7 +594,7 @@
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");
+ debug_assert!(!body.has_free_regions(tcx), "Free regions in optimized MIR");
body
}
@@ -615,7 +621,7 @@
run_post_borrowck_cleanup_passes(tcx, body);
}
- debug_assert!(!promoted.has_free_regions(), "Free regions in promoted MIR");
+ debug_assert!(!promoted.has_free_regions(tcx), "Free regions in promoted MIR");
tcx.arena.alloc(promoted)
}
diff --git a/compiler/rustc_mir/src/transform/no_landing_pads.rs b/compiler/rustc_mir/src/transform/no_landing_pads.rs
deleted file mode 100644
index 5479f0c..0000000
--- a/compiler/rustc_mir/src/transform/no_landing_pads.rs
+++ /dev/null
@@ -1,28 +0,0 @@
-//! This pass removes the unwind branch of all the terminators when the no-landing-pads option is
-//! specified.
-
-use crate::transform::MirPass;
-use rustc_middle::mir::*;
-use rustc_middle::ty::TyCtxt;
-use rustc_target::spec::PanicStrategy;
-
-pub struct NoLandingPads;
-
-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 {
- return;
- }
-
- for block in body.basic_blocks_mut() {
- let terminator = block.terminator_mut();
- if let Some(unwind) = terminator.kind.unwind_mut() {
- unwind.take();
- }
- }
-}
diff --git a/compiler/rustc_mir/src/transform/promote_consts.rs b/compiler/rustc_mir/src/transform/promote_consts.rs
index 78e8441..1b43670 100644
--- a/compiler/rustc_mir/src/transform/promote_consts.rs
+++ b/compiler/rustc_mir/src/transform/promote_consts.rs
@@ -719,7 +719,7 @@
let data = &mut self.promoted[last];
data.statements.push(Statement {
source_info: SourceInfo::outermost(span),
- kind: StatementKind::Assign(box (Place::from(dest), rvalue)),
+ kind: StatementKind::Assign(Box::new((Place::from(dest), rvalue))),
});
}
@@ -774,11 +774,11 @@
if self.keep_original {
rhs.clone()
} else {
- let unit = Rvalue::Use(Operand::Constant(box Constant {
+ let unit = Rvalue::Use(Operand::Constant(Box::new(Constant {
span: statement.source_info.span,
user_ty: None,
literal: ty::Const::zero_sized(self.tcx, self.tcx.types.unit).into(),
- }));
+ })));
mem::replace(rhs, unit)
},
statement.source_info,
@@ -859,13 +859,17 @@
ty,
val: ty::ConstKind::Unevaluated(ty::Unevaluated {
def,
- substs: InternalSubsts::for_item(tcx, def.did, |param, _| {
- if let ty::GenericParamDefKind::Lifetime = param.kind {
- tcx.lifetimes.re_erased.into()
- } else {
- tcx.mk_param_from_def(param)
- }
- }),
+ substs_: Some(InternalSubsts::for_item(
+ tcx,
+ def.did,
+ |param, _| {
+ if let ty::GenericParamDefKind::Lifetime = param.kind {
+ tcx.lifetimes.re_erased.into()
+ } else {
+ tcx.mk_param_from_def(param)
+ }
+ },
+ )),
promoted: Some(promoted_id),
}),
})
@@ -988,6 +992,7 @@
scope.parent_scope = None;
let promoted = Body::new(
+ tcx,
body.source, // `promoted` gets filled in below
IndexVec::new(),
IndexVec::from_elem_n(scope, 1),
diff --git a/compiler/rustc_mir/src/transform/remove_zsts.rs b/compiler/rustc_mir/src/transform/remove_zsts.rs
index 40b1a8a..5876ac2 100644
--- a/compiler/rustc_mir/src/transform/remove_zsts.rs
+++ b/compiler/rustc_mir/src/transform/remove_zsts.rs
@@ -9,7 +9,8 @@
impl<'tcx> MirPass<'tcx> for RemoveZsts {
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
- if tcx.sess.mir_opt_level() < 3 {
+ // Avoid query cycles (generators require optimized MIR for layout).
+ if tcx.type_of(body.source.def_id()).is_generator() {
return;
}
let param_env = tcx.param_env(body.source.def_id());
diff --git a/compiler/rustc_mir/src/transform/rustc_peek.rs b/compiler/rustc_mir/src/transform/rustc_peek.rs
index a6b8f20..f4a1b0d 100644
--- a/compiler/rustc_mir/src/transform/rustc_peek.rs
+++ b/compiler/rustc_mir/src/transform/rustc_peek.rs
@@ -88,11 +88,11 @@
/// For each such call, determines what the dataflow bit-state is for
/// the L-value corresponding to `expr`; if the bit-state is a 1, then
/// that call to `rustc_peek` is ignored by the sanity check. If the
-/// bit-state is a 0, then this pass emits a error message saying
+/// bit-state is a 0, then this pass emits an error message saying
/// "rustc_peek: bit not set".
///
/// The intention is that one can write unit tests for dataflow by
-/// putting code into an UI test and using `rustc_peek` to
+/// putting code into a 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/separate_const_switch.rs b/compiler/rustc_mir/src/transform/separate_const_switch.rs
new file mode 100644
index 0000000..87cd279
--- /dev/null
+++ b/compiler/rustc_mir/src/transform/separate_const_switch.rs
@@ -0,0 +1,343 @@
+//! A pass that duplicates switch-terminated blocks
+//! into a new copy for each predecessor, provided
+//! the predecessor sets the value being switched
+//! over to a constant.
+//!
+//! The purpose of this pass is to help constant
+//! propagation passes to simplify the switch terminator
+//! of the copied blocks into gotos when some predecessors
+//! statically determine the output of switches.
+//!
+//! ```text
+//! x = 12 --- ---> something
+//! \ / 12
+//! --> switch x
+//! / \ otherwise
+//! x = y --- ---> something else
+//! ```
+//! becomes
+//! ```text
+//! x = 12 ---> switch x ------> something
+//! \ / 12
+//! X
+//! / \ otherwise
+//! x = y ---> switch x ------> something else
+//! ```
+//! so it can hopefully later be turned by another pass into
+//! ```text
+//! x = 12 --------------------> something
+//! / 12
+//! /
+//! / otherwise
+//! x = y ---- switch x ------> something else
+//! ```
+//!
+//! This optimization is meant to cover simple cases
+//! like `?` desugaring. For now, it thus focuses on
+//! simplicity rather than completeness (it notably
+//! sometimes duplicates abusively).
+
+use crate::transform::MirPass;
+use rustc_middle::mir::*;
+use rustc_middle::ty::TyCtxt;
+use smallvec::SmallVec;
+
+pub struct SeparateConstSwitch;
+
+impl<'tcx> MirPass<'tcx> for SeparateConstSwitch {
+ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
+ if tcx.sess.mir_opt_level() < 4 {
+ return;
+ }
+
+ // If execution did something, applying a simplification layer
+ // helps later passes optimize the copy away.
+ if separate_const_switch(body) > 0 {
+ super::simplify::simplify_cfg(tcx, body);
+ }
+ }
+}
+
+/// Returns the amount of blocks that were duplicated
+pub fn separate_const_switch<'tcx>(body: &mut Body<'tcx>) -> usize {
+ let mut new_blocks: SmallVec<[(BasicBlock, BasicBlock); 6]> = SmallVec::new();
+ let predecessors = body.predecessors();
+ 'block_iter: for (block_id, block) in body.basic_blocks().iter_enumerated() {
+ if let TerminatorKind::SwitchInt {
+ discr: Operand::Copy(switch_place) | Operand::Move(switch_place),
+ ..
+ } = block.terminator().kind
+ {
+ // If the block is on an unwind path, do not
+ // apply the optimization as unwind paths
+ // rely on a unique parent invariant
+ if block.is_cleanup {
+ continue 'block_iter;
+ }
+
+ // If the block has fewer than 2 predecessors, ignore it
+ // we could maybe chain blocks that have exactly one
+ // predecessor, but for now we ignore that
+ if predecessors[block_id].len() < 2 {
+ continue 'block_iter;
+ }
+
+ // First, let's find a non-const place
+ // that determines the result of the switch
+ if let Some(switch_place) = find_determining_place(switch_place, block) {
+ // We now have an input place for which it would
+ // be interesting if predecessors assigned it from a const
+
+ let mut predecessors_left = predecessors[block_id].len();
+ 'predec_iter: for predecessor_id in predecessors[block_id].iter().copied() {
+ let predecessor = &body.basic_blocks()[predecessor_id];
+
+ // First we make sure the predecessor jumps
+ // in a reasonable way
+ match &predecessor.terminator().kind {
+ // The following terminators are
+ // unconditionally valid
+ TerminatorKind::Goto { .. } | TerminatorKind::SwitchInt { .. } => {}
+
+ TerminatorKind::FalseEdge { real_target, .. } => {
+ if *real_target != block_id {
+ continue 'predec_iter;
+ }
+ }
+
+ // The following terminators are not allowed
+ TerminatorKind::Resume
+ | TerminatorKind::Drop { .. }
+ | TerminatorKind::DropAndReplace { .. }
+ | TerminatorKind::Call { .. }
+ | TerminatorKind::Assert { .. }
+ | TerminatorKind::FalseUnwind { .. }
+ | TerminatorKind::Yield { .. }
+ | TerminatorKind::Abort
+ | TerminatorKind::Return
+ | TerminatorKind::Unreachable
+ | TerminatorKind::InlineAsm { .. }
+ | TerminatorKind::GeneratorDrop => {
+ continue 'predec_iter;
+ }
+ }
+
+ if is_likely_const(switch_place, predecessor) {
+ new_blocks.push((predecessor_id, block_id));
+ predecessors_left -= 1;
+ if predecessors_left < 2 {
+ // If the original block only has one predecessor left,
+ // we have nothing left to do
+ break 'predec_iter;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // Once the analysis is done, perform the duplication
+ let body_span = body.span;
+ let copied_blocks = new_blocks.len();
+ let blocks = body.basic_blocks_mut();
+ for (pred_id, target_id) in new_blocks {
+ let new_block = blocks[target_id].clone();
+ let new_block_id = blocks.push(new_block);
+ let terminator = blocks[pred_id].terminator_mut();
+
+ match terminator.kind {
+ TerminatorKind::Goto { ref mut target } => {
+ *target = new_block_id;
+ }
+
+ TerminatorKind::FalseEdge { ref mut real_target, .. } => {
+ if *real_target == target_id {
+ *real_target = new_block_id;
+ }
+ }
+
+ TerminatorKind::SwitchInt { ref mut targets, .. } => {
+ targets.all_targets_mut().iter_mut().for_each(|x| {
+ if *x == target_id {
+ *x = new_block_id;
+ }
+ });
+ }
+
+ TerminatorKind::Resume
+ | TerminatorKind::Abort
+ | TerminatorKind::Return
+ | TerminatorKind::Unreachable
+ | TerminatorKind::GeneratorDrop
+ | TerminatorKind::Assert { .. }
+ | TerminatorKind::DropAndReplace { .. }
+ | TerminatorKind::FalseUnwind { .. }
+ | TerminatorKind::Drop { .. }
+ | TerminatorKind::Call { .. }
+ | TerminatorKind::InlineAsm { .. }
+ | TerminatorKind::Yield { .. } => {
+ span_bug!(
+ body_span,
+ "basic block terminator had unexpected kind {:?}",
+ &terminator.kind
+ )
+ }
+ }
+ }
+
+ copied_blocks
+}
+
+/// This function describes a rough heuristic guessing
+/// whether a place is last set with a const within the block.
+/// Notably, it will be overly pessimistic in cases that are already
+/// not handled by `separate_const_switch`.
+fn is_likely_const<'tcx>(mut tracked_place: Place<'tcx>, block: &BasicBlockData<'tcx>) -> bool {
+ for statement in block.statements.iter().rev() {
+ match &statement.kind {
+ StatementKind::Assign(assign) => {
+ if assign.0 == tracked_place {
+ match assign.1 {
+ // These rvalues are definitely constant
+ Rvalue::Use(Operand::Constant(_))
+ | Rvalue::Ref(_, _, _)
+ | Rvalue::AddressOf(_, _)
+ | Rvalue::Cast(_, Operand::Constant(_), _)
+ | Rvalue::NullaryOp(_, _)
+ | Rvalue::UnaryOp(_, Operand::Constant(_)) => return true,
+
+ // These rvalues make things ambiguous
+ Rvalue::Repeat(_, _)
+ | Rvalue::ThreadLocalRef(_)
+ | Rvalue::Len(_)
+ | Rvalue::BinaryOp(_, _)
+ | Rvalue::CheckedBinaryOp(_, _)
+ | Rvalue::Aggregate(_, _) => return false,
+
+ // These rvalues move the place to track
+ Rvalue::Cast(_, Operand::Copy(place) | Operand::Move(place), _)
+ | Rvalue::Use(Operand::Copy(place) | Operand::Move(place))
+ | Rvalue::UnaryOp(_, Operand::Copy(place) | Operand::Move(place))
+ | Rvalue::Discriminant(place) => tracked_place = place,
+ }
+ }
+ }
+
+ // If the discriminant is set, it is always set
+ // as a constant, so the job is done.
+ // As we are **ignoring projections**, if the place
+ // we are tracking sees its discriminant be set,
+ // that means we had to be tracking the discriminant
+ // specifically (as it is impossible to switch over
+ // an enum directly, and if we were switching over
+ // its content, we would have had to at least cast it to
+ // some variant first)
+ StatementKind::SetDiscriminant { place, .. } => {
+ if **place == tracked_place {
+ return true;
+ }
+ }
+
+ // If inline assembly is found, we probably should
+ // not try to analyze the code
+ StatementKind::LlvmInlineAsm(_) => return false,
+
+ // These statements have no influence on the place
+ // we are interested in
+ StatementKind::FakeRead(_)
+ | StatementKind::StorageLive(_)
+ | StatementKind::Retag(_, _)
+ | StatementKind::AscribeUserType(_, _)
+ | StatementKind::Coverage(_)
+ | StatementKind::StorageDead(_)
+ | StatementKind::CopyNonOverlapping(_)
+ | StatementKind::Nop => {}
+ }
+ }
+
+ // If no good reason for the place to be const is found,
+ // give up. We could maybe go up predecessors, but in
+ // most cases giving up now should be sufficient.
+ false
+}
+
+/// Finds a unique place that entirely determines the value
+/// of `switch_place`, if it exists. This is only a heuristic.
+/// Ideally we would like to track multiple determining places
+/// for some edge cases, but one is enough for a lot of situations.
+fn find_determining_place<'tcx>(
+ mut switch_place: Place<'tcx>,
+ block: &BasicBlockData<'tcx>,
+) -> Option<Place<'tcx>> {
+ for statement in block.statements.iter().rev() {
+ match &statement.kind {
+ StatementKind::Assign(op) => {
+ if op.0 != switch_place {
+ continue;
+ }
+
+ match op.1 {
+ // The following rvalues move the place
+ // that may be const in the predecessor
+ Rvalue::Use(Operand::Move(new) | Operand::Copy(new))
+ | Rvalue::UnaryOp(_, Operand::Copy(new) | Operand::Move(new))
+ | Rvalue::Cast(_, Operand::Move(new) | Operand::Copy(new), _)
+ | Rvalue::Repeat(Operand::Move(new) | Operand::Copy(new), _)
+ | Rvalue::Discriminant(new)
+ => switch_place = new,
+
+ // The following rvalues might still make the block
+ // be valid but for now we reject them
+ Rvalue::Len(_)
+ | Rvalue::Ref(_, _, _)
+ | Rvalue::BinaryOp(_, _)
+ | Rvalue::CheckedBinaryOp(_, _)
+ | Rvalue::Aggregate(_, _)
+
+ // The following rvalues definitely mean we cannot
+ // or should not apply this optimization
+ | Rvalue::Use(Operand::Constant(_))
+ | Rvalue::Repeat(Operand::Constant(_), _)
+ | Rvalue::ThreadLocalRef(_)
+ | Rvalue::AddressOf(_, _)
+ | Rvalue::NullaryOp(_, _)
+ | Rvalue::UnaryOp(_, Operand::Constant(_))
+ | Rvalue::Cast(_, Operand::Constant(_), _)
+ => return None,
+ }
+ }
+
+ // These statements have no influence on the place
+ // we are interested in
+ StatementKind::FakeRead(_)
+ | StatementKind::StorageLive(_)
+ | StatementKind::StorageDead(_)
+ | StatementKind::Retag(_, _)
+ | StatementKind::AscribeUserType(_, _)
+ | StatementKind::Coverage(_)
+ | StatementKind::CopyNonOverlapping(_)
+ | StatementKind::Nop => {}
+
+ // If inline assembly is found, we probably should
+ // not try to analyze the code
+ StatementKind::LlvmInlineAsm(_) => return None,
+
+ // If the discriminant is set, it is always set
+ // as a constant, so the job is already done.
+ // As we are **ignoring projections**, if the place
+ // we are tracking sees its discriminant be set,
+ // that means we had to be tracking the discriminant
+ // specifically (as it is impossible to switch over
+ // an enum directly, and if we were switching over
+ // its content, we would have had to at least cast it to
+ // some variant first)
+ StatementKind::SetDiscriminant { place, .. } => {
+ if **place == switch_place {
+ return None;
+ }
+ }
+ }
+ }
+
+ Some(switch_place)
+}
diff --git a/compiler/rustc_mir/src/transform/simplify.rs b/compiler/rustc_mir/src/transform/simplify.rs
index 7aebca7..3ecb513 100644
--- a/compiler/rustc_mir/src/transform/simplify.rs
+++ b/compiler/rustc_mir/src/transform/simplify.rs
@@ -382,10 +382,10 @@
for (source_info, code_region) in dropped_coverage {
start_block.statements.push(Statement {
source_info,
- kind: StatementKind::Coverage(box Coverage {
+ kind: StatementKind::Coverage(Box::new(Coverage {
kind: CoverageKind::Unreachable,
code_region: Some(code_region),
- }),
+ })),
})
}
}
diff --git a/compiler/rustc_mir/src/transform/simplify_comparison_integral.rs b/compiler/rustc_mir/src/transform/simplify_comparison_integral.rs
index 1ddf7c9..948fcd9 100644
--- a/compiler/rustc_mir/src/transform/simplify_comparison_integral.rs
+++ b/compiler/rustc_mir/src/transform/simplify_comparison_integral.rs
@@ -211,7 +211,7 @@
return None;
};
let branch_value_scalar = branch_value.literal.try_to_scalar()?;
- Some((branch_value_scalar.into(), branch_value_ty, *to_switch_on))
+ Some((branch_value_scalar, branch_value_ty, *to_switch_on))
}
_ => None,
}
diff --git a/compiler/rustc_mir/src/transform/simplify_try.rs b/compiler/rustc_mir/src/transform/simplify_try.rs
index dd2ec39..9c3055c 100644
--- a/compiler/rustc_mir/src/transform/simplify_try.rs
+++ b/compiler/rustc_mir/src/transform/simplify_try.rs
@@ -420,10 +420,10 @@
let stmt = &mut bb.statements[opt_info.stmt_to_overwrite];
stmt.source_info = opt_info.source_info;
- stmt.kind = StatementKind::Assign(box (
+ stmt.kind = StatementKind::Assign(Box::new((
opt_info.local_0.into(),
Rvalue::Use(Operand::Move(opt_info.local_1.into())),
- ));
+ )));
bb.statements.retain(|stmt| stmt.kind != StatementKind::Nop);
@@ -544,6 +544,12 @@
impl<'tcx> MirPass<'tcx> for SimplifyBranchSame {
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
+ // This optimization is disabled by default for now due to
+ // soundness concerns; see issue #89485 and PR #89489.
+ if !tcx.sess.opts.debugging_opts.unsound_mir_opts {
+ return;
+ }
+
trace!("Running SimplifyBranchSame on {:?}", body.source);
let finder = SimplifyBranchSameOptimizationFinder { body, tcx };
let opts = finder.find();
@@ -706,12 +712,24 @@
let helper = |rhs: &Rvalue<'tcx>,
place: &Place<'tcx>,
variant_index: &VariantIdx,
+ switch_value: u128,
side_to_choose| {
let place_type = place.ty(self.body, self.tcx).ty;
let adt = match *place_type.kind() {
ty::Adt(adt, _) if adt.is_enum() => adt,
_ => return StatementEquality::NotEqual,
};
+ // We need to make sure that the switch value that targets the bb with
+ // SetDiscriminant is the same as the variant discriminant.
+ let variant_discr = adt.discriminant_for_variant(self.tcx, *variant_index).val;
+ if variant_discr != switch_value {
+ trace!(
+ "NO: variant discriminant {} does not equal switch value {}",
+ variant_discr,
+ switch_value
+ );
+ return StatementEquality::NotEqual;
+ }
let variant_is_fieldless = adt.variants[*variant_index].fields.is_empty();
if !variant_is_fieldless {
trace!("NO: variant {:?} was not fieldless", variant_index);
@@ -740,20 +758,28 @@
(
StatementKind::Assign(box (_, rhs)),
StatementKind::SetDiscriminant { place, variant_index },
- )
- // we need to make sure that the switch value that targets the bb with SetDiscriminant (y), is the same as the variant index
- if Some(variant_index.index() as u128) == y_target_and_value.value => {
+ ) if y_target_and_value.value.is_some() => {
// choose basic block of x, as that has the assign
- helper(rhs, place, variant_index, x_target_and_value.target)
+ helper(
+ rhs,
+ place,
+ variant_index,
+ y_target_and_value.value.unwrap(),
+ x_target_and_value.target,
+ )
}
(
StatementKind::SetDiscriminant { place, variant_index },
StatementKind::Assign(box (_, rhs)),
- )
- // we need to make sure that the switch value that targets the bb with SetDiscriminant (x), is the same as the variant index
- if Some(variant_index.index() as u128) == x_target_and_value.value => {
+ ) if x_target_and_value.value.is_some() => {
// choose basic block of y, as that has the assign
- helper(rhs, place, variant_index, y_target_and_value.target)
+ helper(
+ rhs,
+ place,
+ variant_index,
+ x_target_and_value.value.unwrap(),
+ y_target_and_value.target,
+ )
}
_ => {
trace!("NO: statements `{:?}` and `{:?}` not considered equal", x, y);
diff --git a/compiler/rustc_mir/src/util/aggregate.rs b/compiler/rustc_mir/src/util/aggregate.rs
index 130409b..4bc0357 100644
--- a/compiler/rustc_mir/src/util/aggregate.rs
+++ b/compiler/rustc_mir/src/util/aggregate.rs
@@ -25,7 +25,7 @@
AggregateKind::Adt(adt_def, variant_index, _, _, active_field_index) => {
if adt_def.is_enum() {
set_discriminant = Some(Statement {
- kind: StatementKind::SetDiscriminant { place: box (lhs), variant_index },
+ kind: StatementKind::SetDiscriminant { place: Box::new(lhs), variant_index },
source_info,
});
lhs = tcx.mk_place_downcast(lhs, adt_def, variant_index);
@@ -37,7 +37,7 @@
// variant 0 (Unresumed).
let variant_index = VariantIdx::new(0);
set_discriminant = Some(Statement {
- kind: StatementKind::SetDiscriminant { place: box (lhs), variant_index },
+ kind: StatementKind::SetDiscriminant { place: Box::new(lhs), variant_index },
source_info,
});
@@ -66,7 +66,10 @@
let field = Field::new(active_field_index.unwrap_or(i));
tcx.mk_place_field(lhs, field, ty)
};
- Statement { source_info, kind: StatementKind::Assign(box (lhs_field, Rvalue::Use(op))) }
+ Statement {
+ source_info,
+ kind: StatementKind::Assign(Box::new((lhs_field, Rvalue::Use(op)))),
+ }
})
.chain(set_discriminant)
}
diff --git a/compiler/rustc_mir/src/util/alignment.rs b/compiler/rustc_mir/src/util/alignment.rs
index 5d4ca87..73adc60 100644
--- a/compiler/rustc_mir/src/util/alignment.rs
+++ b/compiler/rustc_mir/src/util/alignment.rs
@@ -24,7 +24,7 @@
};
let ty = place.ty(local_decls, tcx).ty;
- match tcx.layout_raw(param_env.and(ty)) {
+ match tcx.layout_of(param_env.and(ty)) {
Ok(layout) if layout.align.abi <= pack => {
// If the packed alignment is greater or equal to the field alignment, the type won't be
// further disaligned.
diff --git a/compiler/rustc_mir/src/util/elaborate_drops.rs b/compiler/rustc_mir/src/util/elaborate_drops.rs
index e9190d7..50756fc 100644
--- a/compiler/rustc_mir/src/util/elaborate_drops.rs
+++ b/compiler/rustc_mir/src/util/elaborate_drops.rs
@@ -680,12 +680,12 @@
let (ptr_next, cur_next) = if ptr_based {
(
Rvalue::Use(copy(cur.into())),
- Rvalue::BinaryOp(BinOp::Offset, box (move_(cur.into()), one)),
+ Rvalue::BinaryOp(BinOp::Offset, Box::new((move_(cur.into()), one))),
)
} else {
(
Rvalue::AddressOf(Mutability::Mut, tcx.mk_place_index(self.place, cur)),
- Rvalue::BinaryOp(BinOp::Add, box (move_(cur.into()), one)),
+ Rvalue::BinaryOp(BinOp::Add, Box::new((move_(cur.into()), one))),
)
};
@@ -703,7 +703,10 @@
let loop_block = BasicBlockData {
statements: vec![self.assign(
can_go,
- Rvalue::BinaryOp(BinOp::Eq, box (copy(Place::from(cur)), copy(length_or_end))),
+ Rvalue::BinaryOp(
+ BinOp::Eq,
+ Box::new((copy(Place::from(cur)), copy(length_or_end))),
+ ),
)],
is_cleanup: unwind.is_cleanup(),
terminator: Some(Terminator {
@@ -821,7 +824,7 @@
length_or_end,
Rvalue::BinaryOp(
BinOp::Offset,
- box (Operand::Copy(cur), Operand::Move(length)),
+ Box::new((Operand::Copy(cur), Operand::Move(length))),
),
),
]
@@ -1032,14 +1035,17 @@
}
fn constant_usize(&self, val: u16) -> Operand<'tcx> {
- Operand::Constant(box Constant {
+ Operand::Constant(Box::new(Constant {
span: self.source_info.span,
user_ty: None,
literal: ty::Const::from_usize(self.tcx(), val.into()).into(),
- })
+ }))
}
fn assign(&self, lhs: Place<'tcx>, rhs: Rvalue<'tcx>) -> Statement<'tcx> {
- Statement { source_info: self.source_info, kind: StatementKind::Assign(box (lhs, rhs)) }
+ Statement {
+ source_info: self.source_info,
+ kind: StatementKind::Assign(Box::new((lhs, rhs))),
+ }
}
}
diff --git a/compiler/rustc_mir/src/util/mod.rs b/compiler/rustc_mir/src/util/mod.rs
index b7b7024..3e466b5 100644
--- a/compiler/rustc_mir/src/util/mod.rs
+++ b/compiler/rustc_mir/src/util/mod.rs
@@ -18,4 +18,4 @@
pub use self::find_self_call::find_self_call;
pub use self::generic_graph::graphviz_safe_def_name;
pub use self::graphviz::write_mir_graphviz;
-pub use self::pretty::{dump_enabled, dump_mir, write_mir_pretty, PassWhere};
+pub use self::pretty::{dump_enabled, dump_mir, write_mir_fn, write_mir_pretty, PassWhere};
diff --git a/compiler/rustc_mir/src/util/patch.rs b/compiler/rustc_mir/src/util/patch.rs
index d09195f..1f571a3 100644
--- a/compiler/rustc_mir/src/util/patch.rs
+++ b/compiler/rustc_mir/src/util/patch.rs
@@ -112,7 +112,7 @@
}
pub fn add_assign(&mut self, loc: Location, place: Place<'tcx>, rv: Rvalue<'tcx>) {
- self.add_statement(loc, StatementKind::Assign(box (place, rv)));
+ self.add_statement(loc, StatementKind::Assign(Box::new((place, rv))));
}
pub fn apply(self, body: &mut Body<'tcx>) {
diff --git a/compiler/rustc_mir/src/util/pretty.rs b/compiler/rustc_mir/src/util/pretty.rs
index d0b1bc4..92591db 100644
--- a/compiler/rustc_mir/src/util/pretty.rs
+++ b/compiler/rustc_mir/src/util/pretty.rs
@@ -475,11 +475,11 @@
ty::ConstKind::Unevaluated(uv) => format!(
"Unevaluated({}, {:?}, {:?})",
self.tcx.def_path_str(uv.def.did),
- uv.substs,
+ uv.substs(self.tcx),
uv.promoted
),
ty::ConstKind::Value(val) => format!("Value({:?})", val),
- ty::ConstKind::Error(_) => format!("Error"),
+ ty::ConstKind::Error(_) => "Error".to_string(),
};
self.push(&format!("+ val: {}", val));
}
@@ -682,6 +682,12 @@
}
struct CollectAllocIds(BTreeSet<AllocId>);
impl<'tcx> TypeVisitor<'tcx> for CollectAllocIds {
+ fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
+ // `AllocId`s are only inside of `ConstKind::Value` which
+ // can't be part of the anon const default substs.
+ None
+ }
+
fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
if let ty::ConstKind::Value(val) = c.val {
self.0.extend(alloc_ids_from_const(val));
diff --git a/compiler/rustc_mir_build/Cargo.toml b/compiler/rustc_mir_build/Cargo.toml
index b75221b..e9fbc1b 100644
--- a/compiler/rustc_mir_build/Cargo.toml
+++ b/compiler/rustc_mir_build/Cargo.toml
@@ -1,5 +1,4 @@
[package]
-authors = ["The Rust Project Developers"]
name = "rustc_mir_build"
version = "0.0.0"
edition = "2018"
diff --git a/compiler/rustc_mir_build/src/build/cfg.rs b/compiler/rustc_mir_build/src/build/cfg.rs
index fd4a783..f08c640 100644
--- a/compiler/rustc_mir_build/src/build/cfg.rs
+++ b/compiler/rustc_mir_build/src/build/cfg.rs
@@ -40,7 +40,7 @@
) {
self.push(
block,
- Statement { source_info, kind: StatementKind::Assign(box (place, rvalue)) },
+ Statement { source_info, kind: StatementKind::Assign(Box::new((place, rvalue))) },
);
}
@@ -51,7 +51,12 @@
temp: Place<'tcx>,
constant: Constant<'tcx>,
) {
- self.push_assign(block, source_info, temp, Rvalue::Use(Operand::Constant(box constant)));
+ self.push_assign(
+ block,
+ source_info,
+ temp,
+ Rvalue::Use(Operand::Constant(Box::new(constant))),
+ );
}
crate fn push_assign_unit(
@@ -65,11 +70,11 @@
block,
source_info,
place,
- Rvalue::Use(Operand::Constant(box Constant {
+ Rvalue::Use(Operand::Constant(Box::new(Constant {
span: source_info.span,
user_ty: None,
literal: ty::Const::zero_sized(tcx, tcx.types.unit).into(),
- })),
+ }))),
);
}
@@ -80,7 +85,7 @@
cause: FakeReadCause,
place: Place<'tcx>,
) {
- let kind = StatementKind::FakeRead(box (cause, place));
+ let kind = StatementKind::FakeRead(Box::new((cause, place)));
let stmt = Statement { source_info, kind };
self.push(block, stmt);
}
diff --git a/compiler/rustc_mir_build/src/build/expr/as_operand.rs b/compiler/rustc_mir_build/src/build/expr/as_operand.rs
index b2a1dbf..bbb2f89 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_operand.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_operand.rs
@@ -111,7 +111,7 @@
match category {
Category::Constant => {
let constant = this.as_constant(expr);
- block.and(Operand::Constant(box constant))
+ block.and(Operand::Constant(Box::new(constant)))
}
Category::Place | Category::Rvalue(..) => {
let operand = unpack!(block = this.as_temp(block, scope, expr, Mutability::Mut));
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 bedb8b1..05995dd 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_place.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_place.rs
@@ -507,10 +507,10 @@
Statement {
source_info,
kind: StatementKind::AscribeUserType(
- box (
+ Box::new((
place,
UserTypeProjection { base: annotation_index, projs: vec![] },
- ),
+ )),
Variance::Invariant,
),
},
@@ -534,10 +534,10 @@
Statement {
source_info,
kind: StatementKind::AscribeUserType(
- box (
+ Box::new((
Place::from(temp),
UserTypeProjection { base: annotation_index, projs: vec![] },
- ),
+ )),
Variance::Invariant,
),
},
@@ -565,6 +565,7 @@
| ExprKind::If { .. }
| ExprKind::Loop { .. }
| ExprKind::Block { .. }
+ | ExprKind::Let { .. }
| ExprKind::Assign { .. }
| ExprKind::AssignOp { .. }
| ExprKind::Break { .. }
@@ -690,7 +691,7 @@
lt,
Rvalue::BinaryOp(
BinOp::Lt,
- box (Operand::Copy(Place::from(index)), Operand::Copy(len)),
+ Box::new((Operand::Copy(Place::from(index)), Operand::Copy(len))),
),
);
let msg = BoundsCheck { len: Operand::Move(len), index: Operand::Copy(Place::from(index)) };
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 69786c1..68de1af 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
@@ -73,7 +73,7 @@
block,
source_info,
is_min,
- Rvalue::BinaryOp(BinOp::Eq, box (arg.to_copy(), minval)),
+ Rvalue::BinaryOp(BinOp::Eq, Box::new((arg.to_copy(), minval))),
);
block = this.assert(
@@ -158,7 +158,7 @@
.map(|f| unpack!(block = this.as_operand(block, scope, &this.thir[f])))
.collect();
- block.and(Rvalue::Aggregate(box AggregateKind::Array(el_ty), fields))
+ block.and(Rvalue::Aggregate(Box::new(AggregateKind::Array(el_ty)), fields))
}
ExprKind::Tuple { ref fields } => {
// see (*) above
@@ -169,7 +169,7 @@
.map(|f| unpack!(block = this.as_operand(block, scope, &this.thir[f])))
.collect();
- block.and(Rvalue::Aggregate(box AggregateKind::Tuple, fields))
+ block.and(Rvalue::Aggregate(Box::new(AggregateKind::Tuple), fields))
}
ExprKind::Closure { closure_id, substs, ref upvars, movability, ref fake_reads } => {
// Convert the closure fake reads, if any, from `ExprRef` to mir `Place`
@@ -254,19 +254,21 @@
// We implicitly set the discriminant to 0. See
// librustc_mir/transform/deaggregator.rs for details.
let movability = movability.unwrap();
- box AggregateKind::Generator(closure_id, substs, movability)
+ Box::new(AggregateKind::Generator(closure_id, substs, movability))
}
- UpvarSubsts::Closure(substs) => box AggregateKind::Closure(closure_id, substs),
+ UpvarSubsts::Closure(substs) => {
+ Box::new(AggregateKind::Closure(closure_id, substs))
+ }
};
block.and(Rvalue::Aggregate(result, operands))
}
ExprKind::Assign { .. } | ExprKind::AssignOp { .. } => {
block = unpack!(this.stmt_expr(block, expr, None));
- block.and(Rvalue::Use(Operand::Constant(box Constant {
+ block.and(Rvalue::Use(Operand::Constant(Box::new(Constant {
span: expr_span,
user_ty: None,
literal: ty::Const::zero_sized(this.tcx, this.tcx.types.unit).into(),
- })))
+ }))))
}
ExprKind::Yield { .. }
| ExprKind::Literal { .. }
@@ -284,6 +286,7 @@
| ExprKind::LogicalOp { .. }
| ExprKind::Call { .. }
| ExprKind::Field { .. }
+ | ExprKind::Let { .. }
| ExprKind::Deref { .. }
| ExprKind::Index { .. }
| ExprKind::VarRef { .. }
@@ -326,7 +329,7 @@
block,
source_info,
result_value,
- Rvalue::CheckedBinaryOp(op, box (lhs.to_copy(), rhs.to_copy())),
+ Rvalue::CheckedBinaryOp(op, Box::new((lhs.to_copy(), rhs.to_copy()))),
);
let val_fld = Field::new(0);
let of_fld = Field::new(1);
@@ -359,7 +362,7 @@
block,
source_info,
is_zero,
- Rvalue::BinaryOp(BinOp::Eq, box (rhs.to_copy(), zero)),
+ Rvalue::BinaryOp(BinOp::Eq, Box::new((rhs.to_copy(), zero))),
);
block = self.assert(block, Operand::Move(is_zero), false, zero_err, span);
@@ -380,13 +383,13 @@
block,
source_info,
is_neg_1,
- Rvalue::BinaryOp(BinOp::Eq, box (rhs.to_copy(), neg_1)),
+ Rvalue::BinaryOp(BinOp::Eq, Box::new((rhs.to_copy(), neg_1))),
);
self.cfg.push_assign(
block,
source_info,
is_min,
- Rvalue::BinaryOp(BinOp::Eq, box (lhs.to_copy(), min)),
+ Rvalue::BinaryOp(BinOp::Eq, Box::new((lhs.to_copy(), min))),
);
let is_neg_1 = Operand::Move(is_neg_1);
@@ -395,14 +398,14 @@
block,
source_info,
of,
- Rvalue::BinaryOp(BinOp::BitAnd, box (is_neg_1, is_min)),
+ Rvalue::BinaryOp(BinOp::BitAnd, Box::new((is_neg_1, is_min))),
);
block = self.assert(block, Operand::Move(of), false, overflow_err, span);
}
}
- block.and(Rvalue::BinaryOp(op, box (lhs, rhs)))
+ block.and(Rvalue::BinaryOp(op, Box::new((lhs, rhs))))
}
}
diff --git a/compiler/rustc_mir_build/src/build/expr/as_temp.rs b/compiler/rustc_mir_build/src/build/expr/as_temp.rs
index 45e0243..32373f1 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_temp.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_temp.rs
@@ -62,16 +62,16 @@
assert!(!this.tcx.is_thread_local_static(def_id));
local_decl.internal = true;
local_decl.local_info =
- Some(box LocalInfo::StaticRef { def_id, is_thread_local: false });
+ Some(Box::new(LocalInfo::StaticRef { def_id, is_thread_local: false }));
}
ExprKind::ThreadLocalRef(def_id) => {
assert!(this.tcx.is_thread_local_static(def_id));
local_decl.internal = true;
local_decl.local_info =
- Some(box LocalInfo::StaticRef { def_id, is_thread_local: true });
+ Some(Box::new(LocalInfo::StaticRef { def_id, is_thread_local: true }));
}
ExprKind::Literal { const_id: Some(def_id), .. } => {
- local_decl.local_info = Some(box LocalInfo::ConstRef { def_id });
+ local_decl.local_info = Some(Box::new(LocalInfo::ConstRef { def_id }));
}
_ => {}
}
diff --git a/compiler/rustc_mir_build/src/build/expr/category.rs b/compiler/rustc_mir_build/src/build/expr/category.rs
index c834ce6..fcda52e 100644
--- a/compiler/rustc_mir_build/src/build/expr/category.rs
+++ b/compiler/rustc_mir_build/src/build/expr/category.rs
@@ -46,6 +46,7 @@
ExprKind::LogicalOp { .. }
| ExprKind::Match { .. }
| ExprKind::If { .. }
+ | ExprKind::Let { .. }
| 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 d7b3a85..e30e758 100644
--- a/compiler/rustc_mir_build/src/build/expr/into.rs
+++ b/compiler/rustc_mir_build/src/build/expr/into.rs
@@ -52,49 +52,91 @@
ExprKind::Match { scrutinee, ref arms } => {
this.match_expr(destination, expr_span, block, &this.thir[scrutinee], arms)
}
- ExprKind::If { cond, then, else_opt } => {
- let place = unpack!(
- block = this.as_temp(
- block,
- Some(this.local_scope()),
- &this.thir[cond],
- Mutability::Mut
+ ExprKind::If { cond, then, else_opt, if_then_scope } => {
+ let then_blk;
+ let then_expr = &this.thir[then];
+ let then_source_info = this.source_info(then_expr.span);
+ let condition_scope = this.local_scope();
+
+ let mut else_blk = unpack!(
+ then_blk = this.in_scope(
+ (if_then_scope, then_source_info),
+ LintLevel::Inherited,
+ |this| {
+ let (then_block, else_block) =
+ this.in_if_then_scope(condition_scope, |this| {
+ let then_blk = unpack!(this.then_else_break(
+ block,
+ &this.thir[cond],
+ Some(condition_scope),
+ condition_scope,
+ then_expr.span,
+ ));
+ this.expr_into_dest(destination, then_blk, then_expr)
+ });
+ then_block.and(else_block)
+ },
)
);
- 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.tcx, operand, then_block, else_block);
- this.cfg.terminate(block, source_info, term);
-
- unpack!(
- then_block = this.expr_into_dest(destination, then_block, &this.thir[then])
- );
- else_block = if let Some(else_opt) = else_opt {
- unpack!(this.expr_into_dest(destination, else_block, &this.thir[else_opt]))
+ else_blk = if let Some(else_opt) = else_opt {
+ unpack!(this.expr_into_dest(destination, else_blk, &this.thir[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.
+ // we implicitly generate an `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.tcx);
- else_block
+ this.cfg.push_assign_unit(else_blk, correct_si, destination, this.tcx);
+ else_blk
};
let join_block = this.cfg.start_new_block();
this.cfg.terminate(
- then_block,
+ then_blk,
source_info,
TerminatorKind::Goto { target: join_block },
);
this.cfg.terminate(
- else_block,
+ else_blk,
source_info,
TerminatorKind::Goto { target: join_block },
);
join_block.unit()
}
+ ExprKind::Let { expr, ref pat } => {
+ let scope = this.local_scope();
+ let (true_block, false_block) = this.in_if_then_scope(scope, |this| {
+ this.lower_let_expr(block, &this.thir[expr], pat, scope, expr_span)
+ });
+
+ let join_block = this.cfg.start_new_block();
+
+ this.cfg.push_assign_constant(
+ true_block,
+ source_info,
+ destination,
+ Constant {
+ span: expr_span,
+ user_ty: None,
+ literal: ty::Const::from_bool(this.tcx, true).into(),
+ },
+ );
+
+ this.cfg.push_assign_constant(
+ false_block,
+ source_info,
+ destination,
+ Constant {
+ span: expr_span,
+ user_ty: None,
+ literal: ty::Const::from_bool(this.tcx, false).into(),
+ },
+ );
+
+ this.cfg.goto(true_block, source_info, join_block);
+ this.cfg.goto(false_block, source_info, join_block);
+ join_block.unit()
+ }
ExprKind::NeverToAny { source } => {
let source = &this.thir[source];
let is_call =
@@ -190,7 +232,7 @@
);
this.diverge_from(loop_block);
- // The “return” value of the loop body must always be an unit. We therefore
+ // The “return” value of the loop body must always be a unit. We therefore
// introduce a unit temporary as the destination for the loop body.
let tmp = this.get_unit_temp();
// Execute the body, branching back to the test.
@@ -328,13 +370,13 @@
inferred_ty,
})
});
- let adt = box AggregateKind::Adt(
+ let adt = Box::new(AggregateKind::Adt(
adt_def,
variant_index,
substs,
user_ty,
active_field_index,
- );
+ ));
this.cfg.push_assign(
block,
source_info,
@@ -385,11 +427,15 @@
}
thir::InlineAsmOperand::Const { value, span } => {
mir::InlineAsmOperand::Const {
- value: box Constant { span, user_ty: None, literal: value.into() },
+ value: Box::new(Constant {
+ span,
+ user_ty: None,
+ literal: value.into(),
+ }),
}
}
thir::InlineAsmOperand::SymFn { expr } => mir::InlineAsmOperand::SymFn {
- value: box this.as_constant(&this.thir[expr]),
+ value: Box::new(this.as_constant(&this.thir[expr])),
},
thir::InlineAsmOperand::SymStatic { def_id } => {
mir::InlineAsmOperand::SymStatic { def_id }
diff --git a/compiler/rustc_mir_build/src/build/expr/stmt.rs b/compiler/rustc_mir_build/src/build/expr/stmt.rs
index b03a6bb..4245535 100644
--- a/compiler/rustc_mir_build/src/build/expr/stmt.rs
+++ b/compiler/rustc_mir_build/src/build/expr/stmt.rs
@@ -123,11 +123,11 @@
block,
Statement {
source_info,
- kind: StatementKind::LlvmInlineAsm(box LlvmInlineAsm {
+ kind: StatementKind::LlvmInlineAsm(Box::new(LlvmInlineAsm {
asm: asm.clone(),
outputs,
inputs,
- }),
+ })),
},
);
this.block_context.pop();
diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs
index 8164529..ba94e15 100644
--- a/compiler/rustc_mir_build/src/build/matches/mod.rs
+++ b/compiler/rustc_mir_build/src/build/matches/mod.rs
@@ -21,7 +21,7 @@
use rustc_middle::thir::{self, *};
use rustc_middle::ty::{self, CanonicalUserTypeAnnotation, Ty};
use rustc_span::symbol::Symbol;
-use rustc_span::Span;
+use rustc_span::{BytePos, Pos, Span};
use rustc_target::abi::VariantIdx;
use smallvec::{smallvec, SmallVec};
@@ -35,6 +35,53 @@
use std::mem;
impl<'a, 'tcx> Builder<'a, 'tcx> {
+ pub(crate) fn then_else_break(
+ &mut self,
+ mut block: BasicBlock,
+ expr: &Expr<'tcx>,
+ temp_scope_override: Option<region::Scope>,
+ break_scope: region::Scope,
+ variable_scope_span: Span,
+ ) -> BlockAnd<()> {
+ let this = self;
+ let expr_span = expr.span;
+
+ match expr.kind {
+ ExprKind::Scope { region_scope, lint_level, value } => {
+ let region_scope = (region_scope, this.source_info(expr_span));
+ this.in_scope(region_scope, lint_level, |this| {
+ this.then_else_break(
+ block,
+ &this.thir[value],
+ temp_scope_override,
+ break_scope,
+ variable_scope_span,
+ )
+ })
+ }
+ ExprKind::Let { expr, ref pat } => {
+ this.lower_let_expr(block, &this.thir[expr], pat, break_scope, variable_scope_span)
+ }
+ _ => {
+ let temp_scope = temp_scope_override.unwrap_or_else(|| this.local_scope());
+ let mutability = Mutability::Mut;
+ let place =
+ unpack!(block = this.as_temp(block, Some(temp_scope), expr, mutability));
+ let operand = Operand::Move(Place::from(place));
+
+ let then_block = this.cfg.start_new_block();
+ let else_block = this.cfg.start_new_block();
+ let term = TerminatorKind::if_(this.tcx, operand, then_block, else_block);
+
+ let source_info = this.source_info(expr_span);
+ this.cfg.terminate(block, source_info, term);
+ this.break_for_else(else_block, break_scope, source_info);
+
+ then_block.unit()
+ }
+ }
+ }
+
/// Generates MIR for a `match` expression.
///
/// The MIR that we generate for a match looks like this.
@@ -103,8 +150,15 @@
let mut candidates =
arm_candidates.iter_mut().map(|(_, candidate)| candidate).collect::<Vec<_>>();
- let fake_borrow_temps =
- self.lower_match_tree(block, scrutinee_span, match_has_guard, &mut candidates);
+ let match_start_span = span.shrink_to_lo().to(scrutinee.span);
+
+ let fake_borrow_temps = self.lower_match_tree(
+ block,
+ scrutinee_span,
+ match_start_span,
+ match_has_guard,
+ &mut candidates,
+ );
self.lower_match_arms(
destination,
@@ -184,6 +238,7 @@
&mut self,
block: BasicBlock,
scrutinee_span: Span,
+ match_start_span: Span,
match_has_guard: bool,
candidates: &mut [&mut Candidate<'pat, 'tcx>],
) -> Vec<(Place<'tcx>, Local)> {
@@ -196,7 +251,14 @@
// This will generate code to test scrutinee_place and
// branch to the appropriate arm block
- self.match_candidates(scrutinee_span, block, &mut otherwise, candidates, &mut fake_borrows);
+ self.match_candidates(
+ match_start_span,
+ scrutinee_span,
+ block,
+ &mut otherwise,
+ candidates,
+ &mut fake_borrows,
+ );
if let Some(otherwise_block) = otherwise {
// See the doc comment on `match_candidates` for why we may have an
@@ -247,6 +309,7 @@
let arm_source_info = self.source_info(arm.span);
let arm_scope = (arm.scope, arm_source_info);
+ let match_scope = self.local_scope();
self.in_scope(arm_scope, arm.lint_level, |this| {
// `try_upvars_resolved` may fail if it is unable to resolve the given
// `PlaceBuilder` inside a closure. In this case, we don't want to include
@@ -285,6 +348,7 @@
scrutinee_span,
Some(arm.span),
Some(arm.scope),
+ Some(match_scope),
);
if let Some(source_scope) = scope {
@@ -299,8 +363,14 @@
// all the arm blocks will rejoin here
let end_block = self.cfg.start_new_block();
+ let end_brace = self.source_info(
+ outer_source_info.span.with_lo(outer_source_info.span.hi() - BytePos::from_usize(1)),
+ );
for arm_block in arm_end_blocks {
- self.cfg.goto(unpack!(arm_block), outer_source_info, end_block);
+ let block = &self.cfg.basic_blocks[arm_block.0];
+ let last_location = block.statements.last().map(|s| s.source_info);
+
+ self.cfg.goto(unpack!(arm_block), last_location.unwrap_or(end_brace), end_block);
}
self.source_scope = outer_source_info.scope;
@@ -323,6 +393,7 @@
scrutinee_span: Span,
arm_span: Option<Span>,
arm_scope: Option<region::Scope>,
+ match_scope: Option<region::Scope>,
) -> BasicBlock {
if candidate.subcandidates.is_empty() {
// Avoid generating another `BasicBlock` when we only have one
@@ -334,6 +405,7 @@
fake_borrow_temps,
scrutinee_span,
arm_span,
+ match_scope,
true,
)
} else {
@@ -370,6 +442,7 @@
&fake_borrow_temps,
scrutinee_span,
arm_span,
+ match_scope,
schedule_drops,
);
if arm_scope.is_none() {
@@ -454,7 +527,7 @@
Statement {
source_info: ty_source_info,
kind: StatementKind::AscribeUserType(
- box (place, user_ty),
+ Box::new((place, user_ty)),
// We always use invariant as the variance here. This is because the
// variance field from the ascription refers to the variance to use
// when applying the type to the value being matched, but this
@@ -493,8 +566,13 @@
set_match_place: bool,
) -> BlockAnd<()> {
let mut candidate = Candidate::new(initializer.clone(), &irrefutable_pat, false);
- let fake_borrow_temps =
- self.lower_match_tree(block, irrefutable_pat.span, false, &mut [&mut candidate]);
+ let fake_borrow_temps = self.lower_match_tree(
+ block,
+ irrefutable_pat.span,
+ irrefutable_pat.span,
+ false,
+ &mut [&mut candidate],
+ );
// For matches and function arguments, the place that is being matched
// can be set when creating the variables. But the place for
// let PATTERN = ... might not even exist until we do the assignment.
@@ -550,6 +628,7 @@
irrefutable_pat.span,
None,
None,
+ None,
)
.unit()
}
@@ -953,6 +1032,7 @@
fn match_candidates<'pat>(
&mut self,
span: Span,
+ scrutinee_span: Span,
start_block: BasicBlock,
otherwise_block: &mut Option<BasicBlock>,
candidates: &mut [&mut Candidate<'pat, 'tcx>],
@@ -982,6 +1062,7 @@
}
self.match_simplified_candidates(
span,
+ scrutinee_span,
start_block,
otherwise_block,
&mut *new_candidates,
@@ -990,6 +1071,7 @@
} else {
self.match_simplified_candidates(
span,
+ scrutinee_span,
start_block,
otherwise_block,
candidates,
@@ -1002,6 +1084,7 @@
fn match_simplified_candidates(
&mut self,
span: Span,
+ scrutinee_span: Span,
start_block: BasicBlock,
otherwise_block: &mut Option<BasicBlock>,
candidates: &mut [&mut Candidate<'_, 'tcx>],
@@ -1047,6 +1130,7 @@
// Test for the remaining candidates.
self.test_candidates_with_or(
span,
+ scrutinee_span,
unmatched_candidates,
block,
otherwise_block,
@@ -1217,6 +1301,7 @@
fn test_candidates_with_or(
&mut self,
span: Span,
+ scrutinee_span: Span,
candidates: &mut [&mut Candidate<'_, 'tcx>],
block: BasicBlock,
otherwise_block: &mut Option<BasicBlock>,
@@ -1229,7 +1314,14 @@
match *first_candidate.match_pairs[0].pattern.kind {
PatKind::Or { .. } => (),
_ => {
- self.test_candidates(span, candidates, block, otherwise_block, fake_borrows);
+ self.test_candidates(
+ span,
+ scrutinee_span,
+ candidates,
+ block,
+ otherwise_block,
+ fake_borrows,
+ );
return;
}
}
@@ -1262,6 +1354,7 @@
self.match_candidates(
span,
+ scrutinee_span,
remainder_start,
otherwise_block,
remaining_candidates,
@@ -1291,6 +1384,7 @@
};
self.match_candidates(
or_span,
+ or_span,
candidate.pre_binding_block.unwrap(),
otherwise,
&mut or_candidate_refs,
@@ -1457,6 +1551,7 @@
fn test_candidates<'pat, 'b, 'c>(
&mut self,
span: Span,
+ scrutinee_span: Span,
mut candidates: &'b mut [&'c mut Candidate<'pat, 'tcx>],
block: BasicBlock,
otherwise_block: &mut Option<BasicBlock>,
@@ -1551,6 +1646,7 @@
let candidate_start = this.cfg.start_new_block();
this.match_candidates(
span,
+ scrutinee_span,
candidate_start,
remainder_start,
&mut *candidates,
@@ -1567,6 +1663,7 @@
let remainder_start = remainder_start.unwrap_or_else(|| this.cfg.start_new_block());
this.match_candidates(
span,
+ scrutinee_span,
remainder_start,
otherwise_block,
candidates,
@@ -1577,7 +1674,7 @@
target_blocks
};
- self.perform_test(block, match_place, &test, make_target_blocks);
+ self.perform_test(span, scrutinee_span, block, match_place, &test, make_target_blocks);
}
/// Determine the fake borrows that are needed from a set of places that
@@ -1658,6 +1755,52 @@
// Pat binding - used for `let` and function parameters as well.
impl<'a, 'tcx> Builder<'a, 'tcx> {
+ crate fn lower_let_expr(
+ &mut self,
+ mut block: BasicBlock,
+ expr: &Expr<'tcx>,
+ pat: &Pat<'tcx>,
+ else_target: region::Scope,
+ span: Span,
+ ) -> BlockAnd<()> {
+ let expr_span = expr.span;
+ let expr_place_builder = unpack!(block = self.lower_scrutinee(block, expr, expr_span));
+ let mut guard_candidate = Candidate::new(expr_place_builder.clone(), &pat, false);
+ let wildcard = Pat::wildcard_from_ty(pat.ty);
+ let mut otherwise_candidate = Candidate::new(expr_place_builder.clone(), &wildcard, false);
+ let fake_borrow_temps = self.lower_match_tree(
+ block,
+ pat.span,
+ pat.span,
+ false,
+ &mut [&mut guard_candidate, &mut otherwise_candidate],
+ );
+ let mut opt_expr_place: Option<(Option<&Place<'tcx>>, Span)> = None;
+ let expr_place: Place<'tcx>;
+ if let Ok(expr_builder) =
+ expr_place_builder.try_upvars_resolved(self.tcx, self.typeck_results)
+ {
+ expr_place = expr_builder.into_place(self.tcx, self.typeck_results);
+ opt_expr_place = Some((Some(&expr_place), expr_span));
+ }
+ let otherwise_post_guard_block = otherwise_candidate.pre_binding_block.unwrap();
+ self.break_for_else(otherwise_post_guard_block, else_target, self.source_info(expr_span));
+
+ self.declare_bindings(None, pat.span.to(span), pat, ArmHasGuard(false), opt_expr_place);
+ let post_guard_block = self.bind_pattern(
+ self.source_info(pat.span),
+ guard_candidate,
+ None,
+ &fake_borrow_temps,
+ expr.span,
+ None,
+ None,
+ None,
+ );
+
+ post_guard_block.unit()
+ }
+
/// Initializes each of the bindings from the candidate by
/// moving/copying/ref'ing the source as appropriate. Tests the guard, if
/// any, and then branches to the arm. Returns the block for the case where
@@ -1674,6 +1817,7 @@
fake_borrows: &Vec<(Place<'tcx>, Local)>,
scrutinee_span: Span,
arm_span: Option<Span>,
+ match_scope: Option<region::Scope>,
schedule_drops: bool,
) -> BasicBlock {
debug!("bind_and_guard_matched_candidate(candidate={:?})", candidate);
@@ -1804,57 +1948,24 @@
self.cfg.push_assign(block, scrutinee_source_info, Place::from(temp), borrow);
}
- let (guard_span, (post_guard_block, otherwise_post_guard_block)) = match *guard {
- Guard::If(e) => {
- let e = &self.thir[e];
- let source_info = self.source_info(e.span);
- (e.span, self.test_bool(block, e, source_info))
- }
- Guard::IfLet(ref pat, scrutinee) => {
- let scrutinee = &self.thir[scrutinee];
- let scrutinee_span = scrutinee.span;
- let scrutinee_place_builder =
- unpack!(block = self.lower_scrutinee(block, scrutinee, scrutinee_span));
- let mut guard_candidate =
- Candidate::new(scrutinee_place_builder.clone(), &pat, false);
- let wildcard = Pat::wildcard_from_ty(pat.ty);
- let mut otherwise_candidate =
- Candidate::new(scrutinee_place_builder.clone(), &wildcard, false);
- let fake_borrow_temps = self.lower_match_tree(
- block,
- pat.span,
- false,
- &mut [&mut guard_candidate, &mut otherwise_candidate],
- );
- let mut opt_scrutinee_place: Option<(Option<&Place<'tcx>>, Span)> = None;
- let scrutinee_place: Place<'tcx>;
- if let Ok(scrutinee_builder) =
- scrutinee_place_builder.try_upvars_resolved(self.tcx, self.typeck_results)
- {
- scrutinee_place =
- scrutinee_builder.into_place(self.tcx, self.typeck_results);
- opt_scrutinee_place = Some((Some(&scrutinee_place), scrutinee_span));
+ let arm_span = arm_span.unwrap();
+ let match_scope = match_scope.unwrap();
+ let mut guard_span = rustc_span::DUMMY_SP;
+
+ let (post_guard_block, otherwise_post_guard_block) =
+ self.in_if_then_scope(match_scope, |this| match *guard {
+ Guard::If(e) => {
+ let e = &this.thir[e];
+ guard_span = e.span;
+ this.then_else_break(block, e, None, match_scope, arm_span)
}
- self.declare_bindings(
- None,
- pat.span.to(arm_span.unwrap()),
- pat,
- ArmHasGuard(false),
- opt_scrutinee_place,
- );
- let post_guard_block = self.bind_pattern(
- self.source_info(pat.span),
- guard_candidate,
- None,
- &fake_borrow_temps,
- scrutinee_span,
- None,
- None,
- );
- let otherwise_post_guard_block = otherwise_candidate.pre_binding_block.unwrap();
- (scrutinee_span, (post_guard_block, otherwise_post_guard_block))
- }
- };
+ Guard::IfLet(ref pat, scrutinee) => {
+ let s = &this.thir[scrutinee];
+ guard_span = s.span;
+ this.lower_let_expr(block, s, pat, match_scope, arm_span)
+ }
+ });
+
let source_info = self.source_info(guard_span);
let guard_end = self.source_info(tcx.sess.source_map().end_point(guard_span));
let guard_frame = self.guard_context.pop().unwrap();
@@ -1870,10 +1981,8 @@
self.cfg.terminate(unreachable, source_info, TerminatorKind::Unreachable);
unreachable
});
- let outside_scope = self.cfg.start_new_block();
- self.exit_top_scope(otherwise_post_guard_block, outside_scope, source_info);
self.false_edges(
- outside_scope,
+ otherwise_post_guard_block,
otherwise_block,
candidate.next_candidate_pre_binding_block,
source_info,
@@ -1896,7 +2005,7 @@
// }
// ```
//
- // would yield a `arm_block` something like:
+ // would yield an `arm_block` something like:
//
// ```
// StorageLive(_4); // _4 is `x`
@@ -1964,7 +2073,7 @@
Statement {
source_info,
kind: StatementKind::AscribeUserType(
- box (ascription.source, user_ty),
+ Box::new((ascription.source, user_ty)),
ascription.variance,
),
},
@@ -2093,11 +2202,11 @@
let local = LocalDecl::<'tcx> {
mutability,
ty: var_ty,
- user_ty: if user_ty.is_empty() { None } else { Some(box user_ty) },
+ user_ty: if user_ty.is_empty() { None } else { Some(Box::new(user_ty)) },
source_info,
internal: false,
is_block_tail: None,
- local_info: Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var(
+ local_info: Some(Box::new(LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var(
VarBindingForm {
binding_mode,
// hypothetically, `visit_primary_bindings` could try to unzip
@@ -2108,7 +2217,7 @@
opt_match_place,
pat_span,
},
- )))),
+ ))))),
};
let for_arm_body = self.local_decls.push(local);
self.var_debug_info.push(VarDebugInfo {
@@ -2126,9 +2235,9 @@
source_info,
internal: false,
is_block_tail: None,
- local_info: Some(box LocalInfo::User(ClearCrossCrate::Set(
+ local_info: Some(Box::new(LocalInfo::User(ClearCrossCrate::Set(
BindingForm::RefForGuard,
- ))),
+ )))),
});
self.var_debug_info.push(VarDebugInfo {
name,
diff --git a/compiler/rustc_mir_build/src/build/matches/simplify.rs b/compiler/rustc_mir_build/src/build/matches/simplify.rs
index 13cfc36..1feb8b0 100644
--- a/compiler/rustc_mir_build/src/build/matches/simplify.rs
+++ b/compiler/rustc_mir_build/src/build/matches/simplify.rs
@@ -155,12 +155,16 @@
ascription: thir::Ascription { variance, user_ty, user_ty_span },
} => {
// Apply the type ascription to the value at `match_pair.place`, which is the
- candidate.ascriptions.push(Ascription {
- span: user_ty_span,
- user_ty,
- source: match_pair.place.clone().into_place(self.tcx, self.typeck_results),
- variance,
- });
+ if let Ok(place_resolved) =
+ match_pair.place.clone().try_upvars_resolved(self.tcx, self.typeck_results)
+ {
+ candidate.ascriptions.push(Ascription {
+ span: user_ty_span,
+ user_ty,
+ source: place_resolved.into_place(self.tcx, self.typeck_results),
+ variance,
+ });
+ }
candidate.match_pairs.push(MatchPair::new(match_pair.place, subpattern));
@@ -173,15 +177,19 @@
}
PatKind::Binding { name, mutability, mode, var, ty, ref subpattern, is_primary: _ } => {
- candidate.bindings.push(Binding {
- name,
- mutability,
- span: match_pair.pattern.span,
- source: match_pair.place.clone().into_place(self.tcx, self.typeck_results),
- var_id: var,
- var_ty: ty,
- binding_mode: mode,
- });
+ if let Ok(place_resolved) =
+ match_pair.place.clone().try_upvars_resolved(self.tcx, self.typeck_results)
+ {
+ candidate.bindings.push(Binding {
+ name,
+ mutability,
+ span: match_pair.pattern.span,
+ source: place_resolved.into_place(self.tcx, self.typeck_results),
+ var_id: var,
+ var_ty: ty,
+ binding_mode: mode,
+ });
+ }
if let Some(subpattern) = subpattern.as_ref() {
// this is the `x @ P` case; have to keep matching against `P` now
diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs
index c87f427..a01df23 100644
--- a/compiler/rustc_mir_build/src/build/matches/test.rs
+++ b/compiler/rustc_mir_build/src/build/matches/test.rs
@@ -19,6 +19,7 @@
use rustc_middle::ty::{self, adjustment::PointerCast, Ty, TyCtxt};
use rustc_span::def_id::DefId;
use rustc_span::symbol::{sym, Symbol};
+use rustc_span::Span;
use rustc_target::abi::VariantIdx;
use std::cmp::Ordering;
@@ -151,6 +152,8 @@
pub(super) fn perform_test(
&mut self,
+ match_start_span: Span,
+ scrutinee_span: Span,
block: BasicBlock,
place_builder: PlaceBuilder<'tcx>,
test: &Test<'tcx>,
@@ -206,10 +209,15 @@
debug!("num_enum_variants: {}, variants: {:?}", num_enum_variants, variants);
let discr_ty = adt_def.repr.discr_type().to_ty(tcx);
let discr = self.temp(discr_ty, test.span);
- self.cfg.push_assign(block, source_info, discr, Rvalue::Discriminant(place));
+ self.cfg.push_assign(
+ block,
+ self.source_info(scrutinee_span),
+ discr,
+ Rvalue::Discriminant(place),
+ );
self.cfg.terminate(
block,
- source_info,
+ self.source_info(match_start_span),
TerminatorKind::SwitchInt {
discr: Operand::Move(discr),
switch_ty: discr_ty,
@@ -246,7 +254,7 @@
targets: switch_targets,
}
};
- self.cfg.terminate(block, source_info, terminator);
+ self.cfg.terminate(block, self.source_info(match_start_span), terminator);
}
TestKind::Eq { value, ty } => {
@@ -346,7 +354,12 @@
let result = self.temp(bool_ty, source_info.span);
// result = op(left, right)
- self.cfg.push_assign(block, source_info, result, Rvalue::BinaryOp(op, box (left, right)));
+ self.cfg.push_assign(
+ block,
+ source_info,
+ result,
+ Rvalue::BinaryOp(op, Box::new((left, right))),
+ );
// branch based on result
self.cfg.terminate(
@@ -429,7 +442,7 @@
block,
source_info,
TerminatorKind::Call {
- func: Operand::Constant(box Constant {
+ func: Operand::Constant(Box::new(Constant {
span: source_info.span,
// FIXME(#54571): This constant comes from user input (a
@@ -439,7 +452,7 @@
user_ty: None,
literal: method.into(),
- }),
+ })),
args: vec![val, expect],
destination: Some((eq_result, eq_block)),
cleanup: None,
diff --git a/compiler/rustc_mir_build/src/build/matches/util.rs b/compiler/rustc_mir_build/src/build/matches/util.rs
index 3cf8ae6..88dd76e 100644
--- a/compiler/rustc_mir_build/src/build/matches/util.rs
+++ b/compiler/rustc_mir_build/src/build/matches/util.rs
@@ -31,15 +31,20 @@
suffix: &'pat [Pat<'tcx>],
) {
let tcx = self.tcx;
- let (min_length, exact_size) = match place
- .clone()
- .into_place(tcx, self.typeck_results)
- .ty(&self.local_decls, tcx)
- .ty
- .kind()
+ let (min_length, exact_size) = if let Ok(place_resolved) =
+ place.clone().try_upvars_resolved(tcx, self.typeck_results)
{
- ty::Array(_, length) => (length.eval_usize(tcx, self.param_env), true),
- _ => ((prefix.len() + suffix.len()).try_into().unwrap(), false),
+ match place_resolved
+ .into_place(tcx, self.typeck_results)
+ .ty(&self.local_decls, tcx)
+ .ty
+ .kind()
+ {
+ ty::Array(_, length) => (length.eval_usize(tcx, self.param_env), true),
+ _ => ((prefix.len() + suffix.len()).try_into().unwrap(), false),
+ }
+ } else {
+ ((prefix.len() + suffix.len()).try_into().unwrap(), false)
};
match_pairs.extend(prefix.iter().enumerate().map(|(idx, subpattern)| {
diff --git a/compiler/rustc_mir_build/src/build/misc.rs b/compiler/rustc_mir_build/src/build/misc.rs
index a1126d1..78047da 100644
--- a/compiler/rustc_mir_build/src/build/misc.rs
+++ b/compiler/rustc_mir_build/src/build/misc.rs
@@ -31,7 +31,7 @@
literal: &'tcx ty::Const<'tcx>,
) -> Operand<'tcx> {
let literal = literal.into();
- let constant = box Constant { span, user_ty: None, literal };
+ let constant = Box::new(Constant { span, user_ty: None, literal });
Operand::Constant(constant)
}
diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs
index 60cfd73..0a760a7 100644
--- a/compiler/rustc_mir_build/src/build/mod.rs
+++ b/compiler/rustc_mir_build/src/build/mod.rs
@@ -2,7 +2,6 @@
use crate::build::expr::as_place::PlaceBuilder;
use crate::build::scope::DropKind;
use crate::thir::pattern::pat_from_hir;
-use rustc_attr::{self as attr, UnwindAttr};
use rustc_errors::ErrorReported;
use rustc_hir as hir;
use rustc_hir::def_id::{DefId, LocalDefId};
@@ -16,10 +15,9 @@
use rustc_middle::thir::{BindingMode, Expr, ExprId, LintLevel, PatKind, Thir};
use rustc_middle::ty::subst::Subst;
use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeckResults};
-use rustc_span::symbol::{kw, sym};
+use rustc_span::symbol::sym;
use rustc_span::Span;
use rustc_target::spec::abi::Abi;
-use rustc_target::spec::PanicStrategy;
use super::lints;
@@ -241,10 +239,10 @@
// The exception is `body.user_type_annotations`, which is used unmodified
// by borrow checking.
debug_assert!(
- !(body.local_decls.has_free_regions()
- || body.basic_blocks().has_free_regions()
- || body.var_debug_info.has_free_regions()
- || body.yield_ty().has_free_regions()),
+ !(body.local_decls.has_free_regions(tcx)
+ || body.basic_blocks().has_free_regions(tcx)
+ || body.var_debug_info.has_free_regions(tcx)
+ || body.yield_ty().has_free_regions(tcx)),
"Unexpected free regions in MIR: {:?}",
body,
);
@@ -581,60 +579,6 @@
}};
}
-fn should_abort_on_panic(tcx: TyCtxt<'_>, fn_def_id: LocalDefId, abi: Abi) -> bool {
- // Validate `#[unwind]` syntax regardless of platform-specific panic strategy.
- let attrs = &tcx.get_attrs(fn_def_id.to_def_id());
- let unwind_attr = attr::find_unwind_attr(&tcx.sess, attrs);
-
- // We never unwind, so it's not relevant to stop an unwind.
- if tcx.sess.panic_strategy() != PanicStrategy::Unwind {
- return false;
- }
-
- match unwind_attr {
- // If an `#[unwind]` attribute was found, we should adhere to it.
- Some(UnwindAttr::Allowed) => false,
- Some(UnwindAttr::Aborts) => true,
- // If no attribute was found and the panic strategy is `unwind`, then we should examine
- // the function's ABI string to determine whether it should abort upon panic.
- None if tcx.features().c_unwind => {
- use Abi::*;
- match abi {
- // In the case of ABI's that have an `-unwind` equivalent, check whether the ABI
- // permits unwinding. If so, we should not abort. Otherwise, we should.
- C { unwind } | Stdcall { unwind } | System { unwind } | Thiscall { unwind } => {
- !unwind
- }
- // Rust and `rust-call` functions are allowed to unwind, and should not abort.
- Rust | RustCall => false,
- // Other ABI's should abort.
- Cdecl
- | Fastcall
- | Vectorcall
- | Aapcs
- | Win64
- | SysV64
- | PtxKernel
- | Msp430Interrupt
- | X86Interrupt
- | AmdGpuKernel
- | EfiApi
- | AvrInterrupt
- | AvrNonBlockingInterrupt
- | CCmseNonSecureCall
- | Wasm
- | RustIntrinsic
- | PlatformIntrinsic
- | Unadjusted => true,
- }
- }
- // If the `c_unwind` feature gate is not active, follow the behavior that was in place
- // prior to #76570. This is a special case: some functions have a C ABI but are meant to
- // unwind anyway. Don't stop them.
- None => false, // FIXME(#58794); should be `!(abi == Abi::Rust || abi == Abi::RustCall)`
- }
-}
-
///////////////////////////////////////////////////////////////////////////
/// the main entry point for building MIR for a function
@@ -704,8 +648,7 @@
}));
let source_info = builder.source_info(fn_end);
builder.cfg.terminate(return_block, source_info, TerminatorKind::Return);
- let should_abort = should_abort_on_panic(tcx, fn_def.did, abi);
- builder.build_drop_trees(should_abort);
+ builder.build_drop_trees();
return_block.unit()
}));
@@ -752,12 +695,12 @@
let source_info = builder.source_info(span);
builder.cfg.terminate(block, source_info, TerminatorKind::Return);
- builder.build_drop_trees(false);
+ builder.build_drop_trees();
builder.finish()
}
-/// Construct MIR for a item that has had errors in type checking.
+/// Construct MIR for an item that has had errors in type checking.
///
/// This is required because we may still want to run MIR passes on an item
/// with type errors, but normal MIR construction can't handle that in general.
@@ -812,6 +755,7 @@
cfg.terminate(START_BLOCK, source_info, TerminatorKind::Unreachable);
let mut body = Body::new(
+ tcx,
MirSource::item(def.did.to_def_id()),
cfg.basic_blocks,
source_scopes,
@@ -900,6 +844,7 @@
}
Body::new(
+ self.tcx,
MirSource::item(self.def_id),
self.cfg.basic_blocks,
self.source_scopes,
@@ -942,7 +887,7 @@
let tcx_hir = tcx.hir();
let hir_typeck_results = self.typeck_results;
- // In analyze_closure() in upvar.rs we gathered a list of upvars used by a
+ // In analyze_closure() in upvar.rs we gathered a list of upvars used by an
// indexed closure and we stored in a map called closure_min_captures in TypeckResults
// with the closure's DefId. Here, we run through that vec of UpvarIds for
// the given closure and use the necessary information to create upvar
@@ -959,13 +904,16 @@
ty::Generator(_, substs, _) => ty::UpvarSubsts::Generator(substs),
_ => span_bug!(self.fn_span, "upvars with non-closure env ty {:?}", closure_ty),
};
+ let def_id = self.def_id.as_local().unwrap();
+ let capture_syms = tcx.symbols_for_closure_captures((def_id, fn_def_id));
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.zip(capture_syms));
self.upvar_mutbls = captures_with_tys
.enumerate()
- .map(|(i, (captured_place, ty))| {
+ .map(|(i, (captured_place, (ty, sym)))| {
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,
@@ -974,14 +922,6 @@
let mutability = captured_place.mutability;
- // FIXME(project-rfc-2229#8): Store more precise information
- 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;
- }
- }
-
let mut projs = closure_env_projs.clone();
projs.push(ProjectionElem::Field(Field::new(i), ty));
match capture {
@@ -992,7 +932,7 @@
};
self.var_debug_info.push(VarDebugInfo {
- name,
+ name: sym,
source_info: SourceInfo::outermost(tcx_hir.span(var_id)),
value: VarDebugInfoContents::Place(Place {
local: ty::CAPTURE_STRUCT_LOCAL,
@@ -1042,19 +982,19 @@
self.local_decls[local].mutability = mutability;
self.local_decls[local].source_info.scope = self.source_scope;
self.local_decls[local].local_info = if let Some(kind) = self_binding {
- Some(box LocalInfo::User(ClearCrossCrate::Set(
+ Some(Box::new(LocalInfo::User(ClearCrossCrate::Set(
BindingForm::ImplicitSelf(*kind),
- )))
+ ))))
} else {
let binding_mode = ty::BindingMode::BindByValue(mutability);
- Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var(
+ Some(Box::new(LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var(
VarBindingForm {
binding_mode,
opt_ty_info,
opt_match_place: Some((Some(place), span)),
pat_span: span,
},
- ))))
+ )))))
};
self.var_indices.insert(var, LocalsForNode::One(local));
}
diff --git a/compiler/rustc_mir_build/src/build/scope.rs b/compiler/rustc_mir_build/src/build/scope.rs
index 3de894b..bd8d14f 100644
--- a/compiler/rustc_mir_build/src/build/scope.rs
+++ b/compiler/rustc_mir_build/src/build/scope.rs
@@ -81,6 +81,8 @@
*/
+use std::mem;
+
use crate::build::{BlockAnd, BlockAndExtension, BlockFrame, Builder, CFG};
use rustc_data_structures::fx::FxHashMap;
use rustc_index::vec::IndexVec;
@@ -93,9 +95,13 @@
#[derive(Debug)]
pub struct Scopes<'tcx> {
scopes: Vec<Scope>,
+
/// The current set of breakable scopes. See module comment for more details.
breakable_scopes: Vec<BreakableScope<'tcx>>,
+ /// The scope of the innermost if-then currently being lowered.
+ if_then_scope: Option<IfThenScope>,
+
/// Drops that need to be done on unwind paths. See the comment on
/// [DropTree] for more details.
unwind_drops: DropTree,
@@ -164,6 +170,14 @@
continue_drops: Option<DropTree>,
}
+#[derive(Debug)]
+struct IfThenScope {
+ /// The if-then scope or arm scope
+ region_scope: region::Scope,
+ /// Drops that happen on the `else` path.
+ else_drops: DropTree,
+}
+
/// The target of an expression that breaks out of a scope
#[derive(Clone, Copy, Debug)]
crate enum BreakableTarget {
@@ -183,6 +197,7 @@
/// * Drops on unwind paths
/// * Drops on generator drop paths (when a suspended generator is dropped)
/// * Drops on return and loop exit paths
+/// * Drops on the else path in an `if let` chain
///
/// Once no more nodes could be added to the tree, we lower it to MIR in one go
/// in `build_mir`.
@@ -394,6 +409,7 @@
Self {
scopes: Vec::new(),
breakable_scopes: Vec::new(),
+ if_then_scope: None,
unwind_drops: DropTree::new(),
generator_drops: DropTree::new(),
}
@@ -483,6 +499,45 @@
}
}
+ /// Start an if-then scope which tracks drop for `if` expressions and `if`
+ /// guards.
+ ///
+ /// For an if-let chain:
+ ///
+ /// if let Some(x) = a && let Some(y) = b && let Some(z) = c { ... }
+ ///
+ /// there are three possible ways the condition can be false and we may have
+ /// to drop `x`, `x` and `y`, or neither depending on which binding fails.
+ /// To handle this correctly we use a `DropTree` in a similar way to a
+ /// `loop` expression and 'break' out on all of the 'else' paths.
+ ///
+ /// Notes:
+ /// - We don't need to keep a stack of scopes in the `Builder` because the
+ /// 'else' paths will only leave the innermost scope.
+ /// - This is also used for match guards.
+ crate fn in_if_then_scope<F>(
+ &mut self,
+ region_scope: region::Scope,
+ f: F,
+ ) -> (BasicBlock, BasicBlock)
+ where
+ F: FnOnce(&mut Builder<'a, 'tcx>) -> BlockAnd<()>,
+ {
+ let scope = IfThenScope { region_scope, else_drops: DropTree::new() };
+ let previous_scope = mem::replace(&mut self.scopes.if_then_scope, Some(scope));
+
+ let then_block = unpack!(f(self));
+
+ let if_then_scope = mem::replace(&mut self.scopes.if_then_scope, previous_scope).unwrap();
+ assert!(if_then_scope.region_scope == region_scope);
+
+ let else_block = self
+ .build_exit_tree(if_then_scope.else_drops, None)
+ .map_or_else(|| self.cfg.start_new_block(), |else_block_and| unpack!(else_block_and));
+
+ (then_block, else_block)
+ }
+
crate fn in_opt_scope<F, R>(
&mut self,
opt_scope: Option<(region::Scope, SourceInfo)>,
@@ -651,6 +706,36 @@
self.cfg.start_new_block().unit()
}
+ crate fn break_for_else(
+ &mut self,
+ block: BasicBlock,
+ target: region::Scope,
+ source_info: SourceInfo,
+ ) {
+ let scope_index = self.scopes.scope_index(target, source_info.span);
+ let if_then_scope = self
+ .scopes
+ .if_then_scope
+ .as_mut()
+ .unwrap_or_else(|| span_bug!(source_info.span, "no if-then scope found"));
+
+ assert_eq!(if_then_scope.region_scope, target, "breaking to incorrect scope");
+
+ let mut drop_idx = ROOT_NODE;
+ let drops = &mut if_then_scope.else_drops;
+ for scope in &self.scopes.scopes[scope_index + 1..] {
+ for drop in &scope.drops {
+ drop_idx = drops.add_drop(*drop, drop_idx);
+ }
+ }
+ drops.add_entry(block, drop_idx);
+
+ // `build_drop_tree` doesn't have access to our source_info, so we
+ // create a dummy terminator now. `TerminatorKind::Resume` is used
+ // because MIR type checking will panic if it hasn't been overwritten.
+ self.cfg.terminate(block, source_info, TerminatorKind::Resume);
+ }
+
// Add a dummy `Assign` statement to the CFG, with the span for the source code's `continue`
// statement.
fn add_dummy_assignment(&mut self, span: &Span, block: BasicBlock, source_info: SourceInfo) {
@@ -659,16 +744,6 @@
self.cfg.push_assign_unit(block, source_info, temp_place, self.tcx);
}
- crate fn exit_top_scope(
- &mut self,
- mut block: BasicBlock,
- target: BasicBlock,
- source_info: SourceInfo,
- ) {
- block = self.leave_top_scope(block);
- self.cfg.terminate(block, source_info, TerminatorKind::Goto { target });
- }
-
fn leave_top_scope(&mut self, block: BasicBlock) -> BasicBlock {
// If we are emitting a `drop` statement, we need to have the cached
// diverge cleanup pads ready in case that drop panics.
@@ -927,61 +1002,6 @@
// Other
// =====
- /// Branch based on a boolean condition.
- ///
- /// This is a special case because the temporary for the condition needs to
- /// be dropped on both the true and the false arm.
- crate fn test_bool(
- &mut self,
- mut block: BasicBlock,
- condition: &Expr<'tcx>,
- source_info: SourceInfo,
- ) -> (BasicBlock, BasicBlock) {
- let cond = unpack!(block = self.as_local_operand(block, condition));
- let true_block = self.cfg.start_new_block();
- let false_block = self.cfg.start_new_block();
- let term = TerminatorKind::if_(self.tcx, cond.clone(), true_block, false_block);
- self.cfg.terminate(block, source_info, term);
-
- match cond {
- // Don't try to drop a constant
- Operand::Constant(_) => (),
- Operand::Copy(place) | Operand::Move(place) => {
- if let Some(cond_temp) = place.as_local() {
- // Manually drop the condition on both branches.
- let top_scope = self.scopes.scopes.last_mut().unwrap();
- let top_drop_data = top_scope.drops.pop().unwrap();
- if self.generator_kind.is_some() {
- top_scope.invalidate_cache();
- }
-
- match top_drop_data.kind {
- DropKind::Value { .. } => {
- bug!("Drop scheduled on top of condition variable")
- }
- DropKind::Storage => {
- let source_info = top_drop_data.source_info;
- let local = top_drop_data.local;
- assert_eq!(local, cond_temp, "Drop scheduled on top of condition");
- self.cfg.push(
- true_block,
- Statement { source_info, kind: StatementKind::StorageDead(local) },
- );
- self.cfg.push(
- false_block,
- Statement { source_info, kind: StatementKind::StorageDead(local) },
- );
- }
- }
- } else {
- bug!("Expected as_local_operand to produce a temporary");
- }
- }
- }
-
- (true_block, false_block)
- }
-
/// Returns the [DropIdx] for the innermost drop if the function unwound at
/// this point. The `DropIdx` will be created if it doesn't already exist.
fn diverge_cleanup(&mut self) -> DropIdx {
@@ -1249,21 +1269,20 @@
}
/// Build the unwind and generator drop trees.
- crate fn build_drop_trees(&mut self, should_abort: bool) {
+ crate fn build_drop_trees(&mut self) {
if self.generator_kind.is_some() {
- self.build_generator_drop_trees(should_abort);
+ self.build_generator_drop_trees();
} else {
Self::build_unwind_tree(
&mut self.cfg,
&mut self.scopes.unwind_drops,
self.fn_span,
- should_abort,
&mut None,
);
}
}
- fn build_generator_drop_trees(&mut self, should_abort: bool) {
+ fn build_generator_drop_trees(&mut self) {
// Build the drop tree for dropping the generator while it's suspended.
let drops = &mut self.scopes.generator_drops;
let cfg = &mut self.cfg;
@@ -1281,7 +1300,7 @@
// Build the drop tree for unwinding in the normal control flow paths.
let resume_block = &mut None;
let unwind_drops = &mut self.scopes.unwind_drops;
- Self::build_unwind_tree(cfg, unwind_drops, fn_span, should_abort, resume_block);
+ Self::build_unwind_tree(cfg, unwind_drops, fn_span, resume_block);
// Build the drop tree for unwinding when dropping a suspended
// generator.
@@ -1296,26 +1315,20 @@
drops.entry_points.push((drop_data.1, blocks[drop_idx].unwrap()));
}
}
- Self::build_unwind_tree(cfg, drops, fn_span, should_abort, resume_block);
+ Self::build_unwind_tree(cfg, drops, fn_span, resume_block);
}
fn build_unwind_tree(
cfg: &mut CFG<'tcx>,
drops: &mut DropTree,
fn_span: Span,
- should_abort: bool,
resume_block: &mut Option<BasicBlock>,
) {
let mut blocks = IndexVec::from_elem(None, &drops.drops);
blocks[ROOT_NODE] = *resume_block;
drops.build_mir::<Unwind>(cfg, &mut blocks);
if let (None, Some(resume)) = (*resume_block, blocks[ROOT_NODE]) {
- // `TerminatorKind::Abort` is used for `#[unwind(aborts)]`
- // functions.
- let terminator =
- if should_abort { TerminatorKind::Abort } else { TerminatorKind::Resume };
-
- cfg.terminate(resume, SourceInfo::outermost(fn_span), terminator);
+ cfg.terminate(resume, SourceInfo::outermost(fn_span), TerminatorKind::Resume);
*resume_block = blocks[ROOT_NODE];
}
diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs
index 82e19c0..05a5fce 100644
--- a/compiler/rustc_mir_build/src/check_unsafety.rs
+++ b/compiler/rustc_mir_build/src/check_unsafety.rs
@@ -5,7 +5,7 @@
use rustc_hir as hir;
use rustc_middle::mir::BorrowKind;
use rustc_middle::thir::*;
-use rustc_middle::ty::{self, ParamEnv, TyCtxt};
+use rustc_middle::ty::{self, ParamEnv, Ty, TyCtxt};
use rustc_session::lint::builtin::{UNSAFE_OP_IN_UNSAFE_FN, UNUSED_UNSAFE};
use rustc_session::lint::Level;
use rustc_span::def_id::{DefId, LocalDefId};
@@ -27,7 +27,9 @@
/// The `#[target_feature]` attributes of the body. Used for checking
/// calls to functions with `#[target_feature]` (RFC 2396).
body_target_features: &'tcx Vec<Symbol>,
- in_possible_lhs_union_assign: bool,
+ /// When inside the LHS of an assignment to a field, this is the type
+ /// of the LHS and the span of the assignment expression.
+ assignment_info: Option<(Ty<'tcx>, Span)>,
in_union_destructure: bool,
param_env: ParamEnv<'tcx>,
inside_adt: bool,
@@ -287,7 +289,7 @@
}
fn visit_expr(&mut self, expr: &Expr<'tcx>) {
- // could we be in a the LHS of an assignment of a union?
+ // could we be in the LHS of an assignment to a field?
match expr.kind {
ExprKind::Field { .. }
| ExprKind::VarRef { .. }
@@ -323,13 +325,19 @@
| ExprKind::Return { .. }
| ExprKind::Yield { .. }
| ExprKind::Loop { .. }
+ | ExprKind::Let { .. }
| ExprKind::Match { .. }
| ExprKind::Box { .. }
| ExprKind::If { .. }
| ExprKind::InlineAsm { .. }
| ExprKind::LlvmInlineAsm { .. }
| ExprKind::LogicalOp { .. }
- | ExprKind::Use { .. } => self.in_possible_lhs_union_assign = false,
+ | ExprKind::Use { .. } => {
+ // We don't need to save the old value and restore it
+ // because all the place expressions can't have more
+ // than one child.
+ self.assignment_info = None;
+ }
};
match expr.kind {
ExprKind::Scope { value, lint_level: LintLevel::Explicit(hir_id), region_scope: _ } => {
@@ -409,11 +417,21 @@
self.safety_context = closure_visitor.safety_context;
}
ExprKind::Field { lhs, .. } => {
- // assigning to union field is okay for AccessToUnionField
- if let ty::Adt(adt_def, _) = &self.thir[lhs].ty.kind() {
+ let lhs = &self.thir[lhs];
+ if let ty::Adt(adt_def, _) = lhs.ty.kind() {
if adt_def.is_union() {
- if self.in_possible_lhs_union_assign {
- // FIXME: trigger AssignToDroppingUnionField unsafety if needed
+ if let Some((assigned_ty, assignment_span)) = self.assignment_info {
+ // To avoid semver hazard, we only consider `Copy` and `ManuallyDrop` non-dropping.
+ if !(assigned_ty
+ .ty_adt_def()
+ .map_or(false, |adt| adt.is_manually_drop())
+ || assigned_ty
+ .is_copy_modulo_regions(self.tcx.at(expr.span), self.param_env))
+ {
+ self.requires_unsafe(assignment_span, AssignToDroppingUnionField);
+ } else {
+ // write to non-drop union field, safe
+ }
} else {
self.requires_unsafe(expr.span, AccessToUnionField);
}
@@ -421,9 +439,10 @@
}
}
ExprKind::Assign { lhs, rhs } | ExprKind::AssignOp { lhs, rhs, .. } => {
+ let lhs = &self.thir[lhs];
// First, check whether we are mutating a layout constrained field
let mut visitor = LayoutConstrainedPlaceVisitor::new(self.thir, self.tcx);
- visit::walk_expr(&mut visitor, &self.thir[lhs]);
+ visit::walk_expr(&mut visitor, lhs);
if visitor.found {
self.requires_unsafe(expr.span, MutationOfLayoutConstrainedField);
}
@@ -431,35 +450,40 @@
// Second, check for accesses to union fields
// don't have any special handling for AssignOp since it causes a read *and* write to lhs
if matches!(expr.kind, ExprKind::Assign { .. }) {
- // assigning to a union is safe, check here so it doesn't get treated as a read later
- self.in_possible_lhs_union_assign = true;
- visit::walk_expr(self, &self.thir()[lhs]);
- self.in_possible_lhs_union_assign = false;
+ self.assignment_info = Some((lhs.ty, expr.span));
+ visit::walk_expr(self, lhs);
+ self.assignment_info = None;
visit::walk_expr(self, &self.thir()[rhs]);
return; // we have already visited everything by now
}
}
- ExprKind::Borrow { borrow_kind, arg } => match borrow_kind {
- BorrowKind::Shallow | BorrowKind::Shared | BorrowKind::Unique => {
- if !self.thir[arg]
- .ty
- .is_freeze(self.tcx.at(self.thir[arg].span), self.param_env)
- {
- let mut visitor = LayoutConstrainedPlaceVisitor::new(self.thir, self.tcx);
- visit::walk_expr(&mut visitor, expr);
- if visitor.found {
- self.requires_unsafe(expr.span, BorrowOfLayoutConstrainedField);
+ ExprKind::Borrow { borrow_kind, arg } => {
+ let mut visitor = LayoutConstrainedPlaceVisitor::new(self.thir, self.tcx);
+ visit::walk_expr(&mut visitor, expr);
+ if visitor.found {
+ match borrow_kind {
+ BorrowKind::Shallow | BorrowKind::Shared | BorrowKind::Unique
+ if !self.thir[arg]
+ .ty
+ .is_freeze(self.tcx.at(self.thir[arg].span), self.param_env) =>
+ {
+ self.requires_unsafe(expr.span, BorrowOfLayoutConstrainedField)
}
+ BorrowKind::Mut { .. } => {
+ self.requires_unsafe(expr.span, MutationOfLayoutConstrainedField)
+ }
+ BorrowKind::Shallow | BorrowKind::Shared | BorrowKind::Unique => {}
}
}
- BorrowKind::Mut { .. } => {
- let mut visitor = LayoutConstrainedPlaceVisitor::new(self.thir, self.tcx);
- visit::walk_expr(&mut visitor, expr);
- if visitor.found {
- self.requires_unsafe(expr.span, MutationOfLayoutConstrainedField);
+ }
+ ExprKind::Let { expr: expr_id, .. } => {
+ let let_expr = &self.thir[expr_id];
+ if let ty::Adt(adt_def, _) = let_expr.ty.kind() {
+ if adt_def.is_union() {
+ self.requires_unsafe(expr.span, AccessToUnionField);
}
}
- },
+ }
_ => {}
}
visit::walk_expr(self, expr);
@@ -506,12 +530,9 @@
UseOfMutableStatic,
UseOfExternStatic,
DerefOfRawPointer,
- #[allow(dead_code)] // FIXME
AssignToDroppingUnionField,
AccessToUnionField,
- #[allow(dead_code)] // FIXME
MutationOfLayoutConstrainedField,
- #[allow(dead_code)] // FIXME
BorrowOfLayoutConstrainedField,
CallToFunctionWith,
}
@@ -585,13 +606,10 @@
// Closures are handled by their owner, if it has a body
if tcx.is_closure(def.did.to_def_id()) {
- let owner = tcx.hir().local_def_id_to_hir_id(def.did).owner;
- let owner_hir_id = tcx.hir().local_def_id_to_hir_id(owner);
-
- if tcx.hir().maybe_body_owned_by(owner_hir_id).is_some() {
- tcx.ensure().thir_check_unsafety(owner);
- return;
- }
+ let hir = tcx.hir();
+ let owner = hir.enclosing_body_owner(hir.local_def_id_to_hir_id(def.did));
+ tcx.ensure().thir_check_unsafety(hir.local_def_id(owner));
+ return;
}
let (thir, expr) = tcx.thir_body(def);
@@ -619,7 +637,7 @@
hir_context: hir_id,
body_unsafety,
body_target_features,
- in_possible_lhs_union_assign: false,
+ assignment_info: None,
in_union_destructure: false,
param_env: tcx.param_env(def.did),
inside_adt: false,
diff --git a/compiler/rustc_mir_build/src/lib.rs b/compiler/rustc_mir_build/src/lib.rs
index d2992f0..02023c4 100644
--- a/compiler/rustc_mir_build/src/lib.rs
+++ b/compiler/rustc_mir_build/src/lib.rs
@@ -2,7 +2,6 @@
//!
//! This crate also contains the match exhaustiveness and usefulness checking.
#![feature(box_patterns)]
-#![feature(box_syntax)]
#![feature(control_flow_enum)]
#![feature(crate_visibility_modifier)]
#![feature(bool_to_option)]
@@ -30,4 +29,5 @@
providers.thir_check_unsafety = check_unsafety::thir_check_unsafety;
providers.thir_check_unsafety_for_const_arg = check_unsafety::thir_check_unsafety_for_const_arg;
providers.thir_body = thir::cx::thir_body;
+ providers.thir_tree = thir::cx::thir_tree;
}
diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs
index c3908dd..66005be 100644
--- a/compiler/rustc_mir_build/src/thir/cx/expr.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs
@@ -132,7 +132,7 @@
},
};
- let expr = box [self.thir.exprs.push(expr)];
+ let expr = Box::new([self.thir.exprs.push(expr)]);
self.overloaded_place(hir_expr, adjustment.target, Some(call), expr, deref.span)
}
@@ -190,7 +190,7 @@
ExprKind::Call {
ty: method.ty,
fun: self.thir.exprs.push(method),
- args: box [self.mirror_expr(fun), tupled_args],
+ args: Box::new([self.mirror_expr(fun), tupled_args]),
from_hir_call: true,
fn_span: expr.span,
}
@@ -266,7 +266,7 @@
if self.typeck_results().is_method_call(expr) {
let lhs = self.mirror_expr(lhs);
let rhs = self.mirror_expr(rhs);
- self.overloaded_operator(expr, box [lhs, rhs])
+ self.overloaded_operator(expr, Box::new([lhs, rhs]))
} else {
ExprKind::AssignOp {
op: bin_op(op.node),
@@ -286,7 +286,7 @@
if self.typeck_results().is_method_call(expr) {
let lhs = self.mirror_expr(lhs);
let rhs = self.mirror_expr(rhs);
- self.overloaded_operator(expr, box [lhs, rhs])
+ self.overloaded_operator(expr, Box::new([lhs, rhs]))
} else {
// FIXME overflow
match op.node {
@@ -317,7 +317,7 @@
if self.typeck_results().is_method_call(expr) {
let lhs = self.mirror_expr(lhs);
let index = self.mirror_expr(index);
- self.overloaded_place(expr, expr_ty, None, box [lhs, index], expr.span)
+ self.overloaded_place(expr, expr_ty, None, Box::new([lhs, index]), expr.span)
} else {
ExprKind::Index { lhs: self.mirror_expr(lhs), index: self.mirror_expr(index) }
}
@@ -326,7 +326,7 @@
hir::ExprKind::Unary(hir::UnOp::Deref, ref arg) => {
if self.typeck_results().is_method_call(expr) {
let arg = self.mirror_expr(arg);
- self.overloaded_place(expr, expr_ty, None, box [arg], expr.span)
+ self.overloaded_place(expr, expr_ty, None, Box::new([arg]), expr.span)
} else {
ExprKind::Deref { arg: self.mirror_expr(arg) }
}
@@ -335,7 +335,7 @@
hir::ExprKind::Unary(hir::UnOp::Not, ref arg) => {
if self.typeck_results().is_method_call(expr) {
let arg = self.mirror_expr(arg);
- self.overloaded_operator(expr, box [arg])
+ self.overloaded_operator(expr, Box::new([arg]))
} else {
ExprKind::Unary { op: UnOp::Not, arg: self.mirror_expr(arg) }
}
@@ -344,7 +344,7 @@
hir::ExprKind::Unary(hir::UnOp::Neg, ref arg) => {
if self.typeck_results().is_method_call(expr) {
let arg = self.mirror_expr(arg);
- self.overloaded_operator(expr, box [arg])
+ self.overloaded_operator(expr, Box::new([arg]))
} else if let hir::ExprKind::Lit(ref lit) = arg.kind {
ExprKind::Literal {
literal: self.const_eval_literal(&lit.node, expr_ty, lit.span, true),
@@ -590,7 +590,14 @@
},
Err(err) => bug!("invalid loop id for continue: {}", err),
},
+ hir::ExprKind::Let(ref pat, ref expr, _) => {
+ ExprKind::Let { expr: self.mirror_expr(expr), pat: self.pattern_from_hir(pat) }
+ }
hir::ExprKind::If(cond, then, else_opt) => ExprKind::If {
+ if_then_scope: region::Scope {
+ id: then.hir_id.local_id,
+ data: region::ScopeData::IfThen,
+ },
cond: self.mirror_expr(cond),
then: self.mirror_expr(then),
else_opt: else_opt.map(|el| self.mirror_expr(el)),
@@ -690,11 +697,10 @@
// and not the beginning of discriminants (which is always `0`)
let substs = InternalSubsts::identity_for_item(self.tcx(), did);
let lhs = ty::Const {
- val: ty::ConstKind::Unevaluated(ty::Unevaluated {
- def: ty::WithOptConstParam::unknown(did),
+ val: ty::ConstKind::Unevaluated(ty::Unevaluated::new(
+ ty::WithOptConstParam::unknown(did),
substs,
- promoted: None,
- }),
+ )),
ty: var_ty,
};
let lhs = self.thir.exprs.push(mk_const(self.tcx().mk_const(lhs)));
@@ -785,7 +791,7 @@
self.user_substs_applied_to_ty_of_hir_id(hir_id)
}
- // `Self` is used in expression as a tuple struct constructor or an unit struct constructor
+ // `Self` is used in expression as a tuple struct constructor or a unit struct constructor
Res::SelfCtor(_) => self.user_substs_applied_to_ty_of_hir_id(hir_id),
_ => bug!("user_substs_applied_to_res: unexpected res {:?} at {:?}", res, hir_id),
@@ -886,11 +892,10 @@
debug!("convert_path_expr: (const) user_ty={:?}", user_ty);
ExprKind::Literal {
literal: self.tcx.mk_const(ty::Const {
- val: ty::ConstKind::Unevaluated(ty::Unevaluated {
- def: ty::WithOptConstParam::unknown(def_id),
+ val: ty::ConstKind::Unevaluated(ty::Unevaluated::new(
+ ty::WithOptConstParam::unknown(def_id),
substs,
- promoted: None,
- }),
+ )),
ty: self.typeck_results().node_type(expr.hir_id),
}),
user_ty,
@@ -911,7 +916,7 @@
variant_index: adt_def.variant_index_with_ctor_id(def_id),
substs,
user_ty: user_provided_type,
- fields: box [],
+ fields: Box::new([]),
base: None,
})),
_ => bug!("unexpected ty: {:?}", ty),
diff --git a/compiler/rustc_mir_build/src/thir/cx/mod.rs b/compiler/rustc_mir_build/src/thir/cx/mod.rs
index 604e544..5059dd9 100644
--- a/compiler/rustc_mir_build/src/thir/cx/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/mod.rs
@@ -30,6 +30,13 @@
(tcx.alloc_steal_thir(cx.thir), expr)
}
+crate fn thir_tree<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ owner_def: ty::WithOptConstParam<LocalDefId>,
+) -> String {
+ format!("{:#?}", thir_body(tcx, owner_def).0.steal())
+}
+
struct Cx<'tcx> {
tcx: TyCtxt<'tcx>,
thir: Thir<'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 22c07fb..b34c1e0 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
@@ -16,9 +16,8 @@
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_session::lint::builtin::BINDINGS_WITH_VARIANT_NAME;
use rustc_session::lint::builtin::{IRREFUTABLE_LET_PATTERNS, UNREACHABLE_PATTERNS};
-use rustc_session::parse::feature_err;
use rustc_session::Session;
-use rustc_span::{sym, Span};
+use rustc_span::{DesugaringKind, ExpnKind, Span};
use std::slice;
crate fn check_match(tcx: TyCtxt<'_>, def_id: DefId) {
@@ -56,9 +55,10 @@
fn visit_expr(&mut self, ex: &'tcx hir::Expr<'tcx>) {
intravisit::walk_expr(self, ex);
-
- if let hir::ExprKind::Match(ref scrut, ref arms, source) = ex.kind {
- self.check_match(scrut, arms, source);
+ match &ex.kind {
+ hir::ExprKind::Match(scrut, arms, source) => self.check_match(scrut, arms, *source),
+ hir::ExprKind::Let(pat, scrut, span) => self.check_let(pat, scrut, *span),
+ _ => {}
}
}
@@ -113,11 +113,8 @@
}
impl<'tcx> MatchVisitor<'_, 'tcx> {
- fn check_patterns(&mut self, pat: &Pat<'_>) {
+ fn check_patterns(&self, pat: &Pat<'_>) {
pat.walk_always(|pat| check_borrow_conflicts_in_at_patterns(self, pat));
- if !self.tcx.features().bindings_after_at {
- check_legality_of_bindings_in_at_patterns(self, pat);
- }
check_for_bindings_named_same_as_variants(self, pat);
}
@@ -148,26 +145,28 @@
}
}
+ fn check_let(&mut self, pat: &'tcx hir::Pat<'tcx>, expr: &hir::Expr<'_>, span: Span) {
+ self.check_patterns(pat);
+ let mut cx = self.new_cx(expr.hir_id);
+ let tpat = self.lower_pattern(&mut cx, pat, &mut false).0;
+ check_let_reachability(&mut cx, pat.hir_id, &tpat, span);
+ }
+
fn check_match(
&mut self,
scrut: &hir::Expr<'_>,
arms: &'tcx [hir::Arm<'tcx>],
source: hir::MatchSource,
) {
+ let mut cx = self.new_cx(scrut.hir_id);
+
for arm in arms {
// Check the arm for some things unrelated to exhaustiveness.
self.check_patterns(&arm.pat);
if let Some(hir::Guard::IfLet(ref pat, _)) = arm.guard {
self.check_patterns(pat);
- }
- }
-
- let mut cx = self.new_cx(scrut.hir_id);
-
- for arm in arms {
- if let Some(hir::Guard::IfLet(ref pat, _)) = arm.guard {
let tpat = self.lower_pattern(&mut cx, pat, &mut false).0;
- check_if_let_guard(&mut cx, &tpat, pat.hir_id);
+ check_let_reachability(&mut cx, pat.hir_id, &tpat, tpat.span);
}
}
@@ -190,8 +189,16 @@
let scrut_ty = self.typeck_results.expr_ty_adjusted(scrut);
let report = compute_match_usefulness(&cx, &arms, scrut.hir_id, scrut_ty);
- // Report unreachable arms.
- report_arm_reachability(&cx, &report, source);
+ report_arm_reachability(&cx, &report, |_, arm_span, arm_hir_id, catchall| {
+ match source {
+ hir::MatchSource::ForLoopDesugar | hir::MatchSource::Normal => {
+ unreachable_pattern(cx.tcx, arm_span, arm_hir_id, catchall);
+ }
+ // Unreachable patterns in try and await expressions occur when one of
+ // the arms are an uninhabited type. Which is OK.
+ hir::MatchSource::AwaitDesugar | hir::MatchSource::TryDesugar => {}
+ }
+ });
// Check if the match is exhaustive.
// Note: An empty match isn't the same as an empty matrix for diagnostics purposes,
@@ -358,89 +365,111 @@
});
}
-fn irrefutable_let_pattern(tcx: TyCtxt<'_>, span: Span, id: HirId, source: hir::MatchSource) {
+fn irrefutable_let_pattern(tcx: TyCtxt<'_>, id: HirId, span: Span) {
+ macro_rules! emit_diag {
+ (
+ $lint:expr,
+ $source_name:expr,
+ $note_sufix:expr,
+ $help_sufix:expr
+ ) => {{
+ let mut diag = $lint.build(concat!("irrefutable ", $source_name, " pattern"));
+ diag.note(concat!("this pattern will always match, so the ", $note_sufix));
+ diag.help(concat!("consider ", $help_sufix));
+ diag.emit()
+ }};
+ }
+
+ let source = let_source(tcx, id);
+ let span = match source {
+ LetSource::LetElse(span) => span,
+ _ => span,
+ };
tcx.struct_span_lint_hir(IRREFUTABLE_LET_PATTERNS, id, span, |lint| match source {
- hir::MatchSource::IfLetDesugar { .. } => {
- let mut diag = lint.build("irrefutable `if let` pattern");
- diag.note("this pattern will always match, so the `if let` is useless");
- diag.help("consider replacing the `if let` with a `let`");
- diag.emit()
+ LetSource::GenericLet => {
+ emit_diag!(lint, "`let`", "`let` is useless", "removing `let`");
}
- hir::MatchSource::WhileLetDesugar => {
- let mut diag = lint.build("irrefutable `while let` pattern");
- diag.note("this pattern will always match, so the loop will never exit");
- diag.help("consider instead using a `loop { ... }` with a `let` inside it");
- diag.emit()
+ LetSource::IfLet => {
+ emit_diag!(
+ lint,
+ "`if let`",
+ "`if let` is useless",
+ "replacing the `if let` with a `let`"
+ );
}
- hir::MatchSource::IfLetGuardDesugar => {
- let mut diag = lint.build("irrefutable `if let` guard pattern");
- diag.note("this pattern will always match, so the guard is useless");
- diag.help("consider removing the guard and adding a `let` inside the match arm");
- diag.emit()
+ LetSource::IfLetGuard => {
+ emit_diag!(
+ lint,
+ "`if let` guard",
+ "guard is useless",
+ "removing the guard and adding a `let` inside the match arm"
+ );
}
- _ => {
- bug!(
- "expected `if let`, `while let`, or `if let` guard HIR match source, found {:?}",
- source,
- )
+ LetSource::LetElse(..) => {
+ emit_diag!(
+ lint,
+ "`let...else`",
+ "`else` clause is useless",
+ "removing the `else` clause"
+ );
+ }
+ LetSource::WhileLet => {
+ emit_diag!(
+ lint,
+ "`while let`",
+ "loop will never exit",
+ "instead using a `loop { ... }` with a `let` inside it"
+ );
}
});
}
-fn check_if_let_guard<'p, 'tcx>(
+fn check_let_reachability<'p, 'tcx>(
cx: &mut MatchCheckCtxt<'p, 'tcx>,
- pat: &'p super::Pat<'tcx>,
pat_id: HirId,
+ pat: &'p super::Pat<'tcx>,
+ span: Span,
) {
let arms = [MatchArm { pat, hir_id: pat_id, has_guard: false }];
let report = compute_match_usefulness(&cx, &arms, pat_id, pat.ty);
- report_arm_reachability(&cx, &report, hir::MatchSource::IfLetGuardDesugar);
+
+ report_arm_reachability(&cx, &report, |arm_index, arm_span, arm_hir_id, _| {
+ match let_source(cx.tcx, pat_id) {
+ LetSource::IfLet | LetSource::WhileLet => {
+ match arm_index {
+ // The arm with the user-specified pattern.
+ 0 => unreachable_pattern(cx.tcx, arm_span, arm_hir_id, None),
+ // The arm with the wildcard pattern.
+ 1 => irrefutable_let_pattern(cx.tcx, pat_id, arm_span),
+ _ => bug!(),
+ }
+ }
+ LetSource::IfLetGuard if arm_index == 0 => {
+ unreachable_pattern(cx.tcx, arm_span, arm_hir_id, None);
+ }
+ _ => {}
+ }
+ });
if report.non_exhaustiveness_witnesses.is_empty() {
// The match is exhaustive, i.e. the `if let` pattern is irrefutable.
- irrefutable_let_pattern(cx.tcx, pat.span, pat_id, hir::MatchSource::IfLetGuardDesugar)
+ irrefutable_let_pattern(cx.tcx, pat_id, span);
}
}
/// Report unreachable arms, if any.
-fn report_arm_reachability<'p, 'tcx>(
+fn report_arm_reachability<'p, 'tcx, F>(
cx: &MatchCheckCtxt<'p, 'tcx>,
report: &UsefulnessReport<'p, 'tcx>,
- source: hir::MatchSource,
-) {
+ unreachable: F,
+) where
+ F: Fn(usize, Span, HirId, Option<Span>),
+{
use Reachability::*;
let mut catchall = None;
for (arm_index, (arm, is_useful)) in report.arm_usefulness.iter().enumerate() {
match is_useful {
- Unreachable => {
- match source {
- hir::MatchSource::WhileDesugar => bug!(),
-
- hir::MatchSource::IfLetDesugar { .. } | hir::MatchSource::WhileLetDesugar => {
- // Check which arm we're on.
- match arm_index {
- // The arm with the user-specified pattern.
- 0 => unreachable_pattern(cx.tcx, arm.pat.span, arm.hir_id, None),
- // The arm with the wildcard pattern.
- 1 => irrefutable_let_pattern(cx.tcx, arm.pat.span, arm.hir_id, source),
- _ => bug!(),
- }
- }
-
- hir::MatchSource::IfLetGuardDesugar => {
- assert_eq!(arm_index, 0);
- unreachable_pattern(cx.tcx, arm.pat.span, arm.hir_id, None);
- }
-
- hir::MatchSource::ForLoopDesugar | hir::MatchSource::Normal => {
- unreachable_pattern(cx.tcx, arm.pat.span, arm.hir_id, catchall);
- }
-
- // Unreachable patterns in try and await expressions occur when one of
- // the arms are an uninhabited type. Which is OK.
- hir::MatchSource::AwaitDesugar | hir::MatchSource::TryDesugar => {}
- }
- }
+ Unreachable => unreachable(arm_index, arm.pat.span, arm.hir_id, catchall),
Reachable(unreachables) if unreachables.is_empty() => {}
// The arm is reachable, but contains unreachable subpatterns (from or-patterns).
Reachable(unreachables) => {
@@ -733,45 +762,51 @@
}
}
-/// Forbids bindings in `@` patterns. This used to be is necessary for memory safety,
-/// because of the way rvalues were handled in the borrow check. (See issue #14587.)
-fn check_legality_of_bindings_in_at_patterns(cx: &MatchVisitor<'_, '_>, pat: &Pat<'_>) {
- AtBindingPatternVisitor { cx, bindings_allowed: true }.visit_pat(pat);
+#[derive(Clone, Copy, Debug)]
+pub enum LetSource {
+ GenericLet,
+ IfLet,
+ IfLetGuard,
+ LetElse(Span),
+ WhileLet,
+}
- struct AtBindingPatternVisitor<'a, 'b, 'tcx> {
- cx: &'a MatchVisitor<'b, 'tcx>,
- bindings_allowed: bool,
- }
-
- impl<'v> Visitor<'v> for AtBindingPatternVisitor<'_, '_, '_> {
- type Map = intravisit::ErasedMap<'v>;
-
- fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
- NestedVisitorMap::None
+fn let_source(tcx: TyCtxt<'_>, pat_id: HirId) -> LetSource {
+ let hir = tcx.hir();
+ let parent = hir.get_parent_node(pat_id);
+ match hir.get(parent) {
+ hir::Node::Arm(hir::Arm {
+ guard: Some(hir::Guard::IfLet(&hir::Pat { hir_id, .. }, _)),
+ ..
+ }) if hir_id == pat_id => {
+ return LetSource::IfLetGuard;
}
-
- fn visit_pat(&mut self, pat: &Pat<'_>) {
- match pat.kind {
- hir::PatKind::Binding(.., ref subpat) => {
- if !self.bindings_allowed {
- feature_err(
- &self.cx.tcx.sess.parse_sess,
- sym::bindings_after_at,
- pat.span,
- "pattern bindings after an `@` are unstable",
- )
- .emit();
- }
-
- if subpat.is_some() {
- let bindings_were_allowed = self.bindings_allowed;
- self.bindings_allowed = false;
- intravisit::walk_pat(self, pat);
- self.bindings_allowed = bindings_were_allowed;
- }
- }
- _ => intravisit::walk_pat(self, pat),
+ hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Let(..), span, .. }) => {
+ let expn_data = span.ctxt().outer_expn_data();
+ if let ExpnKind::Desugaring(DesugaringKind::LetElse) = expn_data.kind {
+ return LetSource::LetElse(expn_data.call_site);
}
}
+ _ => {}
+ }
+ let parent_parent = hir.get_parent_node(parent);
+ let parent_parent_node = hir.get(parent_parent);
+
+ let parent_parent_parent = hir.get_parent_node(parent_parent);
+ let parent_parent_parent_parent = hir.get_parent_node(parent_parent_parent);
+ let parent_parent_parent_parent_node = hir.get(parent_parent_parent_parent);
+
+ if let hir::Node::Expr(hir::Expr {
+ kind: hir::ExprKind::Loop(_, _, hir::LoopSource::While, _),
+ ..
+ }) = parent_parent_parent_parent_node
+ {
+ LetSource::WhileLet
+ } else if let hir::Node::Expr(hir::Expr { kind: hir::ExprKind::If { .. }, .. }) =
+ parent_parent_node
+ {
+ LetSource::IfLet
+ } else {
+ LetSource::GenericLet
}
}
diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
index 926bd83..bbb5de3 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
@@ -237,7 +237,7 @@
// code at the moment, because types like `for <'a> fn(&'a ())` do
// not *yet* implement `PartialEq`. So for now we leave this here.
has_impl
- || ty.walk().any(|t| match t.unpack() {
+ || ty.walk(self.tcx()).any(|t| match t.unpack() {
ty::subst::GenericArgKind::Lifetime(_) => false,
ty::subst::GenericArgKind::Type(t) => t.is_fn_ptr(),
ty::subst::GenericArgKind::Const(_) => false,
diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
index dd265d8..cb74ae4 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
@@ -21,7 +21,7 @@
use rustc_middle::mir::{BorrowKind, Field, Mutability};
use rustc_middle::thir::{Ascription, BindingMode, FieldPat, Pat, PatKind, PatRange, PatTyProj};
use rustc_middle::ty::subst::{GenericArg, SubstsRef};
-use rustc_middle::ty::{self, AdtDef, DefIdTree, Region, Ty, TyCtxt, UserType};
+use rustc_middle::ty::{self, AdtDef, ConstKind, DefIdTree, Region, Ty, TyCtxt, UserType};
use rustc_span::{Span, Symbol};
use std::cmp::Ordering;
@@ -545,6 +545,11 @@
hir::ExprKind::ConstBlock(ref anon_const) => {
let anon_const_def_id = self.tcx.hir().local_def_id(anon_const.hir_id);
let value = ty::Const::from_anon_const(self.tcx, anon_const_def_id);
+ if matches!(value.val, ConstKind::Param(_)) {
+ let span = self.tcx.hir().span(anon_const.hir_id);
+ self.errors.push(PatternError::ConstParamInPattern(span));
+ return PatKind::Wild;
+ }
return *self.const_to_pat(value, expr.hir_id, expr.span, false).kind;
}
hir::ExprKind::Lit(ref lit) => (lit, false),
@@ -600,7 +605,7 @@
impl<'tcx, T: PatternFoldable<'tcx>> PatternFoldable<'tcx> for Box<T> {
fn super_fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self {
let content: T = (**self).fold_with(folder);
- box content
+ Box::new(content)
}
}
diff --git a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs
index 5d4eb75..344006e 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs
@@ -762,7 +762,7 @@
for i in 0..*alt_count {
let sub_set = subpats.get(&i).unwrap_or(&SubPatSet::Empty);
if sub_set.is_empty() {
- // Found a unreachable subpattern.
+ // Found an unreachable subpattern.
spans.push(expanded[i].span);
} else {
fill_spans(sub_set, spans);
diff --git a/compiler/rustc_mir_build/src/thir/visit.rs b/compiler/rustc_mir_build/src/thir/visit.rs
index ce5d436..51c371b 100644
--- a/compiler/rustc_mir_build/src/thir/visit.rs
+++ b/compiler/rustc_mir_build/src/thir/visit.rs
@@ -34,7 +34,7 @@
visitor.visit_expr(&visitor.thir()[value])
}
Box { value } => visitor.visit_expr(&visitor.thir()[value]),
- If { cond, then, else_opt } => {
+ If { cond, then, else_opt, if_then_scope: _ } => {
visitor.visit_expr(&visitor.thir()[cond]);
visitor.visit_expr(&visitor.thir()[then]);
if let Some(else_expr) = else_opt {
@@ -57,6 +57,9 @@
Use { source } => visitor.visit_expr(&visitor.thir()[source]),
NeverToAny { source } => visitor.visit_expr(&visitor.thir()[source]),
Pointer { source, cast: _ } => visitor.visit_expr(&visitor.thir()[source]),
+ Let { expr, .. } => {
+ visitor.visit_expr(&visitor.thir()[expr]);
+ }
Loop { body } => visitor.visit_expr(&visitor.thir()[body]),
Match { scrutinee, ref arms } => {
visitor.visit_expr(&visitor.thir()[scrutinee]);
diff --git a/compiler/rustc_parse/Cargo.toml b/compiler/rustc_parse/Cargo.toml
index 60c2175..1ca1a92 100644
--- a/compiler/rustc_parse/Cargo.toml
+++ b/compiler/rustc_parse/Cargo.toml
@@ -1,5 +1,4 @@
[package]
-authors = ["The Rust Project Developers"]
name = "rustc_parse"
version = "0.0.0"
edition = "2018"
diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs
index 98befe4..1e65cc2 100644
--- a/compiler/rustc_parse/src/lexer/mod.rs
+++ b/compiler/rustc_parse/src/lexer/mod.rs
@@ -505,7 +505,8 @@
// identifier tokens.
fn report_unknown_prefix(&self, start: BytePos) {
let prefix_span = self.mk_sp(start, self.pos);
- let msg = format!("prefix `{}` is unknown", self.str_from_to(start, self.pos));
+ let prefix_str = self.str_from_to(start, self.pos);
+ let msg = format!("prefix `{}` is unknown", prefix_str);
let expn_data = prefix_span.ctxt().outer_expn_data();
@@ -513,12 +514,19 @@
// In Rust 2021, this is a hard error.
let mut err = self.sess.span_diagnostic.struct_span_err(prefix_span, &msg);
err.span_label(prefix_span, "unknown prefix");
- if expn_data.is_root() {
+ if prefix_str == "rb" {
+ err.span_suggestion_verbose(
+ prefix_span,
+ "use `br` for a raw byte string",
+ "br".to_string(),
+ Applicability::MaybeIncorrect,
+ );
+ } else if expn_data.is_root() {
err.span_suggestion_verbose(
prefix_span.shrink_to_hi(),
"consider inserting whitespace here",
" ".into(),
- Applicability::MachineApplicable,
+ Applicability::MaybeIncorrect,
);
}
err.note("prefixed identifiers and literals are reserved since Rust 2021");
diff --git a/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs b/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs
index a580f0c..aa6b424 100644
--- a/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs
+++ b/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs
@@ -153,16 +153,37 @@
EscapeError::NonAsciiCharInByte => {
assert!(mode.is_bytes());
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(
+ let mut err = handler.struct_span_err(span, "non-ASCII character in byte constant");
+ err.span_label(span, "byte constant must be ASCII");
+ if (c as u32) <= 0xFF {
+ err.span_suggestion(
span,
- "use a \\xHH escape for a non-ASCII byte",
+ &format!(
+ "if you meant to use the unicode code point for '{}', use a \\xHH escape",
+ c
+ ),
format!("\\x{:X}", c as u32),
- Applicability::MachineApplicable,
- )
- .emit();
+ Applicability::MaybeIncorrect,
+ );
+ } else if matches!(mode, Mode::Byte) {
+ err.span_label(span, "this multibyte character does not fit into a single byte");
+ } else if matches!(mode, Mode::ByteStr) {
+ let mut utf8 = String::new();
+ utf8.push(c);
+ err.span_suggestion(
+ span,
+ &format!(
+ "if you meant to use the UTF-8 encoding of '{}', use \\xHH escapes",
+ c
+ ),
+ utf8.as_bytes()
+ .iter()
+ .map(|b: &u8| format!("\\x{:X}", *b))
+ .fold("".to_string(), |a, c| a + &c),
+ Applicability::MaybeIncorrect,
+ );
+ }
+ err.emit();
}
EscapeError::NonAsciiCharInByteString => {
assert!(mode.is_bytes());
@@ -253,6 +274,17 @@
let msg = "invalid trailing slash in literal";
handler.struct_span_err(span, msg).span_label(span, msg).emit();
}
+ EscapeError::UnskippedWhitespaceWarning => {
+ let (c, char_span) = last_char();
+ let msg =
+ format!("non-ASCII whitespace symbol '{}' is not skipped", c.escape_unicode());
+ handler.struct_span_warn(span, &msg).span_label(char_span, &msg).emit();
+ }
+ EscapeError::MultipleSkippedLinesWarning => {
+ let msg = "multiple lines skipped by escaped newline";
+ let bottom_msg = "skipping everything up to and including this point";
+ handler.struct_span_warn(span, msg).span_label(span, bottom_msg).emit();
+ }
}
}
diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs
index 51df06b..bf76ded 100644
--- a/compiler/rustc_parse/src/lib.rs
+++ b/compiler/rustc_parse/src/lib.rs
@@ -2,9 +2,10 @@
#![feature(array_windows)]
#![feature(crate_visibility_modifier)]
-#![feature(bindings_after_at)]
-#![feature(box_syntax)]
+#![feature(if_let_guard)]
+#![cfg_attr(bootstrap, feature(bindings_after_at))]
#![feature(box_patterns)]
+#![cfg_attr(bootstrap, allow(incomplete_features))] // if_let_guard
#![recursion_limit = "256"]
use rustc_ast as ast;
@@ -14,9 +15,10 @@
use rustc_ast::tokenstream::{Spacing, TokenStream};
use rustc_ast::AstLike;
use rustc_ast::Attribute;
+use rustc_ast::{AttrItem, MetaItem};
use rustc_ast_pretty::pprust;
use rustc_data_structures::sync::Lrc;
-use rustc_errors::{Diagnostic, FatalError, Level, PResult};
+use rustc_errors::{Applicability, Diagnostic, FatalError, Level, PResult};
use rustc_session::parse::ParseSess;
use rustc_span::{FileName, SourceFile, Span};
@@ -188,7 +190,7 @@
let src = source_file.src.as_ref().unwrap_or_else(|| {
sess.span_diagnostic.bug(&format!(
"cannot lex `source_file` without source: {}",
- source_file.name.prefer_local()
+ sess.source_map().filename_for_diagnostics(&source_file.name)
));
});
@@ -262,20 +264,17 @@
let tokens = match *nt {
Nonterminal::NtItem(ref item) => prepend_attrs(&item.attrs, item.tokens.as_ref()),
Nonterminal::NtBlock(ref block) => convert_tokens(block.tokens.as_ref()),
- Nonterminal::NtStmt(ref stmt) => {
- if let ast::StmtKind::Empty = stmt.kind {
- let tokens = AttrAnnotatedTokenStream::new(vec![(
- tokenstream::AttrAnnotatedTokenTree::Token(Token::new(
- TokenKind::Semi,
- stmt.span,
- )),
- Spacing::Alone,
- )]);
- prepend_attrs(&stmt.attrs(), Some(&LazyTokenStream::new(tokens)))
- } else {
- prepend_attrs(&stmt.attrs(), stmt.tokens())
- }
+ Nonterminal::NtStmt(ref stmt) if let ast::StmtKind::Empty = stmt.kind => {
+ let tokens = AttrAnnotatedTokenStream::new(vec![(
+ tokenstream::AttrAnnotatedTokenTree::Token(Token::new(
+ TokenKind::Semi,
+ stmt.span,
+ )),
+ Spacing::Alone,
+ )]);
+ prepend_attrs(&stmt.attrs(), Some(&LazyTokenStream::new(tokens)))
}
+ Nonterminal::NtStmt(ref stmt) => prepend_attrs(&stmt.attrs(), 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) => {
@@ -325,3 +324,44 @@
let filename = FileName::macro_expansion_source_code(&source);
parse_stream_from_source_str(filename, source, sess, Some(nt.span()))
}
+
+pub fn parse_cfg_attr(
+ attr: &Attribute,
+ parse_sess: &ParseSess,
+) -> Option<(MetaItem, Vec<(AttrItem, Span)>)> {
+ match attr.get_normal_item().args {
+ ast::MacArgs::Delimited(dspan, delim, ref tts) if !tts.is_empty() => {
+ let msg = "wrong `cfg_attr` delimiters";
+ crate::validate_attr::check_meta_bad_delim(parse_sess, dspan, delim, msg);
+ match parse_in(parse_sess, tts.clone(), "`cfg_attr` input", |p| p.parse_cfg_attr()) {
+ Ok(r) => return Some(r),
+ Err(mut e) => {
+ e.help(&format!("the valid syntax is `{}`", CFG_ATTR_GRAMMAR_HELP))
+ .note(CFG_ATTR_NOTE_REF)
+ .emit();
+ }
+ }
+ }
+ _ => error_malformed_cfg_attr_missing(attr.span, parse_sess),
+ }
+ None
+}
+
+const CFG_ATTR_GRAMMAR_HELP: &str = "#[cfg_attr(condition, attribute, other_attribute, ...)]";
+const CFG_ATTR_NOTE_REF: &str = "for more information, visit \
+ <https://doc.rust-lang.org/reference/conditional-compilation.html\
+ #the-cfg_attr-attribute>";
+
+fn error_malformed_cfg_attr_missing(span: Span, parse_sess: &ParseSess) {
+ parse_sess
+ .span_diagnostic
+ .struct_span_err(span, "malformed `cfg_attr` attribute input")
+ .span_suggestion(
+ span,
+ "missing condition and attribute",
+ CFG_ATTR_GRAMMAR_HELP.to_string(),
+ Applicability::HasPlaceholders,
+ )
+ .note(CFG_ATTR_NOTE_REF)
+ .emit();
+}
diff --git a/compiler/rustc_parse/src/parser/attr_wrapper.rs b/compiler/rustc_parse/src/parser/attr_wrapper.rs
index e1d0b84..9f06bdc 100644
--- a/compiler/rustc_parse/src/parser/attr_wrapper.rs
+++ b/compiler/rustc_parse/src/parser/attr_wrapper.rs
@@ -301,7 +301,7 @@
// If we 'broke' the last token (e.g. breaking a '>>' token to two '>' tokens),
// then extend the range of captured tokens to include it, since the parser
// was not actually bumped past it. When the `LazyTokenStream` gets converted
- // into a `AttrAnnotatedTokenStream`, we will create the proper token.
+ // into an `AttrAnnotatedTokenStream`, we will create the proper token.
if self.token_cursor.break_last_token {
assert_eq!(
trailing,
@@ -320,7 +320,7 @@
} else {
// Grab any replace ranges that occur *inside* the current AST node.
// We will perform the actual replacement when we convert the `LazyTokenStream`
- // to a `AttrAnnotatedTokenStream`
+ // to an `AttrAnnotatedTokenStream`
let start_calls: u32 = cursor_snapshot_next_calls.try_into().unwrap();
self.capture_state.replace_ranges[replace_ranges_start..replace_ranges_end]
.iter()
@@ -486,7 +486,7 @@
if let AttrAnnotatedTokenTree::Token(last_token) = last_token {
let unglued_first = last_token.kind.break_two_token_op().unwrap().0;
- // A 'unglued' token is always two ASCII characters
+ // An 'unglued' token is always two ASCII characters
let mut first_span = last_token.span.shrink_to_lo();
first_span = first_span.with_hi(first_span.lo() + rustc_span::BytePos(1));
diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs
index b37caae..94ca70d 100644
--- a/compiler/rustc_parse/src/parser/diagnostics.rs
+++ b/compiler/rustc_parse/src/parser/diagnostics.rs
@@ -242,6 +242,63 @@
expected.sort_by_cached_key(|x| x.to_string());
expected.dedup();
+ let sm = self.sess.source_map();
+ let msg = format!("expected `;`, found {}", super::token_descr(&self.token));
+ let appl = Applicability::MachineApplicable;
+ if expected.contains(&TokenType::Token(token::Semi)) {
+ if self.token.span == DUMMY_SP || self.prev_token.span == DUMMY_SP {
+ // Likely inside a macro, can't provide meaningful suggestions.
+ } else if !sm.is_multiline(self.prev_token.span.until(self.token.span)) {
+ // The current token is in the same line as the prior token, not recoverable.
+ } else if [token::Comma, token::Colon].contains(&self.token.kind)
+ && self.prev_token.kind == token::CloseDelim(token::Paren)
+ {
+ // Likely typo: The current token is on a new line and is expected to be
+ // `.`, `;`, `?`, or an operator after a close delimiter token.
+ //
+ // let a = std::process::Command::new("echo")
+ // .arg("1")
+ // ,arg("2")
+ // ^
+ // https://github.com/rust-lang/rust/issues/72253
+ } else if self.look_ahead(1, |t| {
+ t == &token::CloseDelim(token::Brace)
+ || t.can_begin_expr() && t.kind != token::Colon
+ }) && [token::Comma, token::Colon].contains(&self.token.kind)
+ {
+ // Likely typo: `,` → `;` or `:` → `;`. This is triggered if the current token is
+ // either `,` or `:`, and the next token could either start a new statement or is a
+ // block close. For example:
+ //
+ // let x = 32:
+ // let y = 42;
+ self.bump();
+ let sp = self.prev_token.span;
+ self.struct_span_err(sp, &msg)
+ .span_suggestion_short(sp, "change this to `;`", ";".to_string(), appl)
+ .emit();
+ return Ok(false);
+ } else if self.look_ahead(0, |t| {
+ t == &token::CloseDelim(token::Brace)
+ || (
+ t.can_begin_expr() && t != &token::Semi && t != &token::Pound
+ // Avoid triggering with too many trailing `#` in raw string.
+ )
+ }) {
+ // Missing semicolon typo. This is triggered if the next token could either start a
+ // new statement or is a block close. For example:
+ //
+ // let x = 32
+ // let y = 42;
+ let sp = self.prev_token.span.shrink_to_hi();
+ self.struct_span_err(sp, &msg)
+ .span_label(self.token.span, "unexpected token")
+ .span_suggestion_short(sp, "add `;` here", ";".to_string(), appl)
+ .emit();
+ return Ok(false);
+ }
+ }
+
let expect = tokens_to_string(&expected[..]);
let actual = super::token_descr(&self.token);
let (msg_exp, (label_sp, label_exp)) = if expected.len() > 1 {
@@ -303,7 +360,6 @@
return Err(err);
}
- let sm = self.sess.source_map();
if self.prev_token.span == DUMMY_SP {
// Account for macro context where the previous span might not be
// available to avoid incorrect output (#54841).
@@ -390,11 +446,13 @@
)
.emit();
*self = snapshot;
- Ok(self.mk_block(
+ let mut tail = self.mk_block(
vec![self.mk_stmt_err(expr.span)],
s,
lo.to(self.prev_token.span),
- ))
+ );
+ tail.could_be_bare_literal = true;
+ Ok(tail)
}
(Err(mut err), Ok(tail)) => {
// We have a block tail that contains a somehow valid type ascription expr.
@@ -407,7 +465,10 @@
self.consume_block(token::Brace, ConsumeClosingDelim::Yes);
Err(err)
}
- (Ok(_), Ok(tail)) => Ok(tail),
+ (Ok(_), Ok(mut tail)) => {
+ tail.could_be_bare_literal = true;
+ Ok(tail)
+ }
});
}
None
@@ -1144,62 +1205,6 @@
if self.eat(&token::Semi) {
return Ok(());
}
- let sm = self.sess.source_map();
- let msg = format!("expected `;`, found {}", super::token_descr(&self.token));
- let appl = Applicability::MachineApplicable;
- if self.token.span == DUMMY_SP || self.prev_token.span == DUMMY_SP {
- // Likely inside a macro, can't provide meaningful suggestions.
- return self.expect(&token::Semi).map(drop);
- } else if !sm.is_multiline(self.prev_token.span.until(self.token.span)) {
- // The current token is in the same line as the prior token, not recoverable.
- } else if [token::Comma, token::Colon].contains(&self.token.kind)
- && self.prev_token.kind == token::CloseDelim(token::Paren)
- {
- // Likely typo: The current token is on a new line and is expected to be
- // `.`, `;`, `?`, or an operator after a close delimiter token.
- //
- // let a = std::process::Command::new("echo")
- // .arg("1")
- // ,arg("2")
- // ^
- // https://github.com/rust-lang/rust/issues/72253
- self.expect(&token::Semi)?;
- return Ok(());
- } else if self.look_ahead(1, |t| {
- t == &token::CloseDelim(token::Brace) || t.can_begin_expr() && t.kind != token::Colon
- }) && [token::Comma, token::Colon].contains(&self.token.kind)
- {
- // Likely typo: `,` → `;` or `:` → `;`. This is triggered if the current token is
- // either `,` or `:`, and the next token could either start a new statement or is a
- // block close. For example:
- //
- // let x = 32:
- // let y = 42;
- self.bump();
- let sp = self.prev_token.span;
- self.struct_span_err(sp, &msg)
- .span_suggestion_short(sp, "change this to `;`", ";".to_string(), appl)
- .emit();
- return Ok(());
- } else if self.look_ahead(0, |t| {
- t == &token::CloseDelim(token::Brace)
- || (
- t.can_begin_expr() && t != &token::Semi && t != &token::Pound
- // Avoid triggering with too many trailing `#` in raw string.
- )
- }) {
- // Missing semicolon typo. This is triggered if the next token could either start a
- // new statement or is a block close. For example:
- //
- // let x = 32
- // let y = 42;
- let sp = self.prev_token.span.shrink_to_hi();
- self.struct_span_err(sp, &msg)
- .span_label(self.token.span, "unexpected token")
- .span_suggestion_short(sp, "add `;` here", ";".to_string(), appl)
- .emit();
- return Ok(());
- }
self.expect(&token::Semi).map(drop) // Error unconditionally
}
@@ -1432,12 +1437,22 @@
// the most sense, which is immediately after the last token:
//
// {foo(bar {}}
- // - ^
+ // ^ ^
// | |
// | help: `)` may belong here
// |
// unclosed delimiter
if let Some(sp) = unmatched.unclosed_span {
+ let mut primary_span: Vec<Span> =
+ err.span.primary_spans().iter().cloned().collect();
+ primary_span.push(sp);
+ let mut primary_span: MultiSpan = primary_span.into();
+ for span_label in err.span.span_labels() {
+ if let Some(label) = span_label.label {
+ primary_span.push_span_label(span_label.span, label);
+ }
+ }
+ err.set_span(primary_span);
err.span_label(sp, "unclosed delimiter");
}
// Backticks should be removed to apply suggestions.
@@ -1770,7 +1785,7 @@
let mut err = self.struct_span_err(span, &msg);
let sp = self.sess.source_map().start_point(self.token.span);
if let Some(sp) = self.sess.ambiguous_block_expr_parse.borrow().get(&sp) {
- self.sess.expr_parentheses_needed(&mut err, *sp, None);
+ self.sess.expr_parentheses_needed(&mut err, *sp);
}
err.span_label(span, "expected expression");
err
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index ef05f64..a1d3e9a 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -15,6 +15,8 @@
use rustc_ast::{Arm, Async, BlockCheckMode, Expr, ExprKind, Label, Movability, RangeLimits};
use rustc_ast_pretty::pprust;
use rustc_errors::{Applicability, DiagnosticBuilder, PResult};
+use rustc_session::lint::builtin::BREAK_WITH_LABEL_AND_LOOP;
+use rustc_session::lint::BuiltinLintDiagnostics;
use rustc_span::edition::LATEST_STABLE_EDITION;
use rustc_span::source_map::{self, Span, Spanned};
use rustc_span::symbol::{kw, sym, Ident, Symbol};
@@ -39,7 +41,7 @@
let path = path.clone();
$p.bump();
return Ok($p.mk_expr(
- $p.token.span,
+ $p.prev_token.span,
ExprKind::Path(None, path),
AttrVec::new(),
));
@@ -48,7 +50,7 @@
let block = block.clone();
$p.bump();
return Ok($p.mk_expr(
- $p.token.span,
+ $p.prev_token.span,
ExprKind::Block(block, None),
AttrVec::new(),
));
@@ -358,7 +360,7 @@
&format!("expected expression, found `{}`", pprust::token_to_string(&self.token),),
);
err.span_label(self.token.span, "expected expression");
- self.sess.expr_parentheses_needed(&mut err, lhs.span, Some(pprust::expr_to_string(&lhs)));
+ self.sess.expr_parentheses_needed(&mut err, lhs.span);
err.emit();
}
@@ -696,20 +698,18 @@
let expr =
mk_expr(self, lhs, self.mk_ty(path.span, TyKind::Path(None, path)));
- let expr_str = self
- .span_to_snippet(expr.span)
- .unwrap_or_else(|_| pprust::expr_to_string(&expr));
-
self.struct_span_err(self.token.span, &msg)
.span_label(
self.look_ahead(1, |t| t.span).to(span_after_type),
"interpreted as generic arguments",
)
.span_label(self.token.span, format!("not interpreted as {}", op_noun))
- .span_suggestion(
- expr.span,
+ .multipart_suggestion(
&format!("try {} the cast value", op_verb),
- format!("({})", expr_str),
+ vec![
+ (expr.span.shrink_to_lo(), "(".to_string()),
+ (expr.span.shrink_to_hi(), ")".to_string()),
+ ],
Applicability::MachineApplicable,
)
.emit();
@@ -1092,7 +1092,7 @@
// added to the return value after the fact.
//
// Therefore, prevent sub-parser from parsing
- // attributes by giving them a empty "already-parsed" list.
+ // attributes by giving them an empty "already-parsed" list.
let attrs = AttrVec::new();
// Note: when adding new syntax here, don't forget to adjust `TokenKind::can_begin_expr()`.
@@ -1377,14 +1377,59 @@
self.maybe_recover_from_bad_qpath(expr, true)
}
- /// Parse `"('label ":")? break expr?`.
+ /// Parse `"break" (('label (:? expr)?) | expr?)` with `"break"` token already eaten.
+ /// If the label is followed immediately by a `:` token, the label and `:` are
+ /// parsed as part of the expression (i.e. a labeled loop). The language team has
+ /// decided in #87026 to require parentheses as a visual aid to avoid confusion if
+ /// the break expression of an unlabeled break is a labeled loop (as in
+ /// `break 'lbl: loop {}`); a labeled break with an unlabeled loop as its value
+ /// expression only gets a warning for compatibility reasons; and a labeled break
+ /// with a labeled loop does not even get a warning because there is no ambiguity.
fn parse_break_expr(&mut self, attrs: AttrVec) -> PResult<'a, P<Expr>> {
let lo = self.prev_token.span;
- let label = self.eat_label();
- let kind = if self.token != token::OpenDelim(token::Brace)
+ let mut label = self.eat_label();
+ let kind = if label.is_some() && self.token == token::Colon {
+ // The value expression can be a labeled loop, see issue #86948, e.g.:
+ // `loop { break 'label: loop { break 'label 42; }; }`
+ let lexpr = self.parse_labeled_expr(label.take().unwrap(), AttrVec::new(), true)?;
+ self.struct_span_err(
+ lexpr.span,
+ "parentheses are required around this expression to avoid confusion with a labeled break expression",
+ )
+ .multipart_suggestion(
+ "wrap the expression in parentheses",
+ vec![
+ (lexpr.span.shrink_to_lo(), "(".to_string()),
+ (lexpr.span.shrink_to_hi(), ")".to_string()),
+ ],
+ Applicability::MachineApplicable,
+ )
+ .emit();
+ Some(lexpr)
+ } else if self.token != token::OpenDelim(token::Brace)
|| !self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL)
{
- self.parse_expr_opt()?
+ let expr = self.parse_expr_opt()?;
+ if let Some(ref expr) = expr {
+ if label.is_some()
+ && matches!(
+ expr.kind,
+ ExprKind::While(_, _, None)
+ | ExprKind::ForLoop(_, _, _, None)
+ | ExprKind::Loop(_, None)
+ | ExprKind::Block(_, None)
+ )
+ {
+ self.sess.buffer_lint_with_diagnostic(
+ BREAK_WITH_LABEL_AND_LOOP,
+ lo.to(expr.span),
+ ast::CRATE_NODE_ID,
+ "this labeled break expression is easy to confuse with an unlabeled break with a labeled value expression",
+ BuiltinLintDiagnostics::BreakWithLabelAndLoop(expr.span),
+ );
+ }
+ }
+ expr
} else {
None
};
@@ -1483,7 +1528,7 @@
.span_suggestion(
token.span,
"must have an integer part",
- pprust::token_to_string(token),
+ pprust::token_to_string(token).into(),
Applicability::MachineApplicable,
)
.emit();
@@ -1822,7 +1867,7 @@
})?;
let span = lo.to(expr.span);
self.sess.gated_spans.gate(sym::let_chains, span);
- Ok(self.mk_expr(span, ExprKind::Let(pat, expr), attrs))
+ Ok(self.mk_expr(span, ExprKind::Let(pat, expr, span), attrs))
}
/// Parses an `else { ... }` expression (`else` token already eaten).
diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs
index 2ce63d0..c5b961f 100644
--- a/compiler/rustc_parse/src/parser/item.rs
+++ b/compiler/rustc_parse/src/parser/item.rs
@@ -26,8 +26,7 @@
/// Parses a source module as a crate. This is the main entry point for the parser.
pub fn parse_crate_mod(&mut self) -> PResult<'a, ast::Crate> {
let (attrs, items, span) = self.parse_mod(&token::Eof)?;
- let proc_macros = Vec::new(); // Filled in by `proc_macro_harness::inject()`.
- Ok(ast::Crate { attrs, items, span, proc_macros })
+ Ok(ast::Crate { attrs, items, span })
}
/// Parses a `mod <foo> { ... }` or `mod <foo>;` item.
@@ -221,7 +220,7 @@
} else if self.check_fn_front_matter(def_final) {
// FUNCTION ITEM
let (ident, sig, generics, body) = self.parse_fn(attrs, req_name, lo)?;
- (ident, ItemKind::Fn(box FnKind(def(), sig, generics, body)))
+ (ident, ItemKind::Fn(Box::new(FnKind(def(), sig, generics, body))))
} else if self.eat_keyword(kw::Extern) {
if self.eat_keyword(kw::Crate) {
// EXTERN CRATE
@@ -548,7 +547,7 @@
};
let trait_ref = TraitRef { path, ref_id: ty_first.id };
- ItemKind::Impl(box ImplKind {
+ ItemKind::Impl(Box::new(ImplKind {
unsafety,
polarity,
defaultness,
@@ -557,11 +556,11 @@
of_trait: Some(trait_ref),
self_ty: ty_second,
items: impl_items,
- })
+ }))
}
None => {
// impl Type
- ItemKind::Impl(box ImplKind {
+ ItemKind::Impl(Box::new(ImplKind {
unsafety,
polarity,
defaultness,
@@ -570,7 +569,7 @@
of_trait: None,
self_ty: ty_first,
items: impl_items,
- })
+ }))
}
};
@@ -710,7 +709,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(ForceCollect::No))?;
- Ok((ident, ItemKind::Trait(box TraitKind(is_auto, unsafety, tps, bounds, items))))
+ Ok((ident, ItemKind::Trait(Box::new(TraitKind(is_auto, unsafety, tps, bounds, items)))))
}
}
@@ -769,7 +768,7 @@
let default = if self.eat(&token::Eq) { Some(self.parse_ty()?) } else { None };
self.expect_semi()?;
- Ok((ident, ItemKind::TyAlias(box TyAliasKind(def, generics, bounds, default))))
+ Ok((ident, ItemKind::TyAlias(Box::new(TyAliasKind(def, generics, bounds, default)))))
}
/// Parses a `UseTree`.
@@ -1107,8 +1106,7 @@
e
})?;
- let enum_definition =
- EnumDef { variants: variants.into_iter().filter_map(|v| v).collect() };
+ let enum_definition = EnumDef { variants: variants.into_iter().flatten().collect() };
Ok((id, ItemKind::Enum(enum_definition, generics)))
}
@@ -1236,7 +1234,7 @@
Ok((class_name, ItemKind::Union(vdata, generics)))
}
- pub(super) fn parse_record_struct_body(
+ fn parse_record_struct_body(
&mut self,
adt_ty: &str,
) -> PResult<'a, (Vec<FieldDef>, /* recovered */ bool)> {
@@ -1470,28 +1468,22 @@
fn parse_field_ident(&mut self, adt_ty: &str, lo: Span) -> PResult<'a, Ident> {
let (ident, is_raw) = self.ident_or_err()?;
if !is_raw && ident.is_reserved() {
- if ident.name == kw::Underscore {
- self.sess.gated_spans.gate(sym::unnamed_fields, lo);
+ let err = if self.check_fn_front_matter(false) {
+ // We use `parse_fn` to get a span for the function
+ if let Err(mut db) = self.parse_fn(&mut Vec::new(), |_| true, lo) {
+ db.delay_as_bug();
+ }
+ let mut err = self.struct_span_err(
+ lo.to(self.prev_token.span),
+ &format!("functions are not allowed in {} definitions", adt_ty),
+ );
+ err.help("unlike in C++, Java, and C#, functions are declared in `impl` blocks");
+ err.help("see https://doc.rust-lang.org/book/ch05-03-method-syntax.html for more information");
+ err
} else {
- let err = if self.check_fn_front_matter(false) {
- // We use `parse_fn` to get a span for the function
- if let Err(mut db) = self.parse_fn(&mut Vec::new(), |_| true, lo) {
- db.delay_as_bug();
- }
- let mut err = self.struct_span_err(
- lo.to(self.prev_token.span),
- &format!("functions are not allowed in {} definitions", adt_ty),
- );
- err.help(
- "unlike in C++, Java, and C#, functions are declared in `impl` blocks",
- );
- err.help("see https://doc.rust-lang.org/book/ch05-03-method-syntax.html for more information");
- err
- } else {
- self.expected_ident_found()
- };
- return Err(err);
- }
+ self.expected_ident_found()
+ };
+ return Err(err);
}
self.bump();
Ok(ident)
@@ -1715,13 +1707,11 @@
// the AST for typechecking.
err.span_label(ident.span, "while parsing this `fn`");
err.emit();
- (Vec::new(), None)
} else {
return Err(err);
}
- } else {
- unreachable!()
}
+ (Vec::new(), None)
};
attrs.extend(inner_attrs);
Ok(body)
@@ -1771,8 +1761,14 @@
pub(super) fn parse_fn_front_matter(&mut self) -> PResult<'a, FnHeader> {
let sp_start = self.token.span;
let constness = self.parse_constness();
+
+ let async_start_sp = self.token.span;
let asyncness = self.parse_asyncness();
+
+ let unsafe_start_sp = self.token.span;
let unsafety = self.parse_unsafety();
+
+ let ext_start_sp = self.token.span;
let ext = self.parse_extern();
if let Async::Yes { span, .. } = asyncness {
@@ -1787,8 +1783,35 @@
Ok(true) => {}
Ok(false) => unreachable!(),
Err(mut err) => {
+ // Qualifier keywords ordering check
+
+ // This will allow the machine fix to directly place the keyword in the correct place
+ let current_qual_sp = if self.check_keyword(kw::Const) {
+ Some(async_start_sp)
+ } else if self.check_keyword(kw::Async) {
+ Some(unsafe_start_sp)
+ } else if self.check_keyword(kw::Unsafe) {
+ Some(ext_start_sp)
+ } else {
+ None
+ };
+
+ if let Some(current_qual_sp) = current_qual_sp {
+ let current_qual_sp = current_qual_sp.to(self.prev_token.span);
+ if let Ok(current_qual) = self.span_to_snippet(current_qual_sp) {
+ let invalid_qual_sp = self.token.uninterpolated_span();
+ let invalid_qual = self.span_to_snippet(invalid_qual_sp).unwrap();
+
+ err.span_suggestion(
+ current_qual_sp.to(invalid_qual_sp),
+ &format!("`{}` must come before `{}`", invalid_qual, current_qual),
+ format!("{} {}", invalid_qual, current_qual),
+ Applicability::MachineApplicable,
+ ).note("keyword order for functions declaration is `default`, `pub`, `const`, `async`, `unsafe`, `extern`");
+ }
+ }
// Recover incorrect visibility order such as `async pub`.
- if self.check_keyword(kw::Pub) {
+ else if self.check_keyword(kw::Pub) {
let sp = sp_start.to(self.prev_token.span);
if let Ok(snippet) = self.span_to_snippet(sp) {
let vis = match self.parse_visibility(FollowedByType::No) {
diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs
index 51d4e00..c4419e9 100644
--- a/compiler/rustc_parse/src/parser/mod.rs
+++ b/compiler/rustc_parse/src/parser/mod.rs
@@ -33,7 +33,7 @@
use rustc_errors::PResult;
use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, FatalError};
use rustc_session::parse::ParseSess;
-use rustc_span::source_map::{Span, DUMMY_SP};
+use rustc_span::source_map::{MultiSpan, Span, DUMMY_SP};
use rustc_span::symbol::{kw, sym, Ident, Symbol};
use tracing::debug;
@@ -152,7 +152,7 @@
/// attribute, we parse a nested AST node that has `#[cfg]` or `#[cfg_attr]`
/// In this case, we use a `ReplaceRange` to replace the entire inner AST node
/// with `FlatToken::AttrTarget`, allowing us to perform eager cfg-expansion
-/// on a `AttrAnnotatedTokenStream`
+/// on an `AttrAnnotatedTokenStream`
///
/// 2. When we parse an inner attribute while collecting tokens. We
/// remove inner attributes from the token stream entirely, and
@@ -165,7 +165,7 @@
/// Controls how we capture tokens. Capturing can be expensive,
/// so we try to avoid performing capturing in cases where
-/// we will never need a `AttrAnnotatedTokenStream`
+/// we will never need an `AttrAnnotatedTokenStream`
#[derive(Copy, Clone)]
pub enum Capturing {
/// We aren't performing any capturing - this is the default mode.
@@ -806,7 +806,7 @@
.span_suggestion_short(
sp,
&format!("missing `{}`", token_str),
- token_str,
+ token_str.into(),
Applicability::MaybeIncorrect,
)
.emit();
@@ -1335,8 +1335,13 @@
// `None` here means an `Eof` was found. We already emit those errors elsewhere, we add them to
// `unmatched_braces` only for error recovery in the `Parser`.
let found_delim = unmatched.found_delim?;
+ let span: MultiSpan = if let Some(sp) = unmatched.unclosed_span {
+ vec![unmatched.found_span, sp].into()
+ } else {
+ unmatched.found_span.into()
+ };
let mut err = sess.span_diagnostic.struct_span_err(
- unmatched.found_span,
+ span,
&format!(
"mismatched closing delimiter: `{}`",
pprust::token_kind_to_string(&token::CloseDelim(found_delim)),
@@ -1362,10 +1367,10 @@
}
}
-/// A helper struct used when building a `AttrAnnotatedTokenStream` from
+/// A helper struct used when building an `AttrAnnotatedTokenStream` from
/// a `LazyTokenStream`. Both delimiter and non-delimited tokens
/// are stored as `FlatToken::Token`. A vector of `FlatToken`s
-/// is then 'parsed' to build up a `AttrAnnotatedTokenStream` with nested
+/// is then 'parsed' to build up an `AttrAnnotatedTokenStream` with nested
/// `AttrAnnotatedTokenTree::Delimited` tokens
#[derive(Debug, Clone)]
pub enum FlatToken {
@@ -1375,10 +1380,10 @@
/// Holds the `AttributesData` for an AST node. The
/// `AttributesData` is inserted directly into the
/// constructed `AttrAnnotatedTokenStream` as
- /// a `AttrAnnotatedTokenTree::Attributes`
+ /// an `AttrAnnotatedTokenTree::Attributes`
AttrTarget(AttributesData),
/// A special 'empty' token that is ignored during the conversion
- /// to a `AttrAnnotatedTokenStream`. This is used to simplify the
+ /// to an `AttrAnnotatedTokenStream`. This is used to simplify the
/// handling of replace ranges.
Empty,
}
diff --git a/compiler/rustc_parse/src/parser/nonterminal.rs b/compiler/rustc_parse/src/parser/nonterminal.rs
index 313d9db..72e6f8a 100644
--- a/compiler/rustc_parse/src/parser/nonterminal.rs
+++ b/compiler/rustc_parse/src/parser/nonterminal.rs
@@ -143,15 +143,16 @@
token::NtTy(self.collect_tokens_no_attrs(|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) =>
+ {
+ self.bump();
+ token::NtIdent(ident, is_raw)
+ }
NonterminalKind::Ident => {
- if let Some((ident, is_raw)) = get_macro_ident(&self.token) {
- self.bump();
- token::NtIdent(ident, is_raw)
- } else {
- let token_str = pprust::token_to_string(&self.token);
- let msg = &format!("expected ident, found {}", &token_str);
- return Err(self.struct_span_err(self.token.span, msg));
- }
+ let token_str = pprust::token_to_string(&self.token);
+ let msg = &format!("expected ident, found {}", &token_str);
+ return Err(self.struct_span_err(self.token.span, msg));
}
NonterminalKind::Path => token::NtPath(
self.collect_tokens_no_attrs(|this| this.parse_path(PathStyle::Type))?,
diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs
index 7219e39..b03b545 100644
--- a/compiler/rustc_parse/src/parser/pat.rs
+++ b/compiler/rustc_parse/src/parser/pat.rs
@@ -763,7 +763,7 @@
let sp = self.sess.source_map().start_point(self.token.span);
if let Some(sp) = self.sess.ambiguous_block_expr_parse.borrow().get(&sp) {
- self.sess.expr_parentheses_needed(&mut err, *sp, None);
+ self.sess.expr_parentheses_needed(&mut err, *sp);
}
Err(err)
diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs
index 9ef3f61..25dcb4a 100644
--- a/compiler/rustc_parse/src/parser/stmt.rs
+++ b/compiler/rustc_parse/src/parser/stmt.rs
@@ -11,8 +11,9 @@
use rustc_ast::ptr::P;
use rustc_ast::token::{self, TokenKind};
use rustc_ast::util::classify;
-use rustc_ast::AstLike;
-use rustc_ast::{AttrStyle, AttrVec, Attribute, MacCall, MacCallStmt, MacStmtStyle};
+use rustc_ast::{
+ AstLike, AttrStyle, AttrVec, Attribute, LocalKind, MacCall, MacCallStmt, MacStmtStyle,
+};
use rustc_ast::{Block, BlockCheckMode, Expr, ExprKind, Local, Stmt};
use rustc_ast::{StmtKind, DUMMY_NODE_ID};
use rustc_errors::{Applicability, PResult};
@@ -292,8 +293,65 @@
return Err(err);
}
};
+ let kind = match init {
+ None => LocalKind::Decl,
+ Some(init) => {
+ if self.eat_keyword(kw::Else) {
+ let els = self.parse_block()?;
+ self.check_let_else_init_bool_expr(&init);
+ self.check_let_else_init_trailing_brace(&init);
+ LocalKind::InitElse(init, els)
+ } else {
+ LocalKind::Init(init)
+ }
+ }
+ };
let hi = if self.token == token::Semi { self.token.span } else { self.prev_token.span };
- Ok(P(ast::Local { ty, pat, init, id: DUMMY_NODE_ID, span: lo.to(hi), attrs, tokens: None }))
+ Ok(P(ast::Local { ty, pat, kind, id: DUMMY_NODE_ID, span: lo.to(hi), attrs, tokens: None }))
+ }
+
+ fn check_let_else_init_bool_expr(&self, init: &ast::Expr) {
+ if let ast::ExprKind::Binary(op, ..) = init.kind {
+ if op.node.lazy() {
+ let suggs = vec![
+ (init.span.shrink_to_lo(), "(".to_string()),
+ (init.span.shrink_to_hi(), ")".to_string()),
+ ];
+ self.struct_span_err(
+ init.span,
+ &format!(
+ "a `{}` expression cannot be directly assigned in `let...else`",
+ op.node.to_string()
+ ),
+ )
+ .multipart_suggestion(
+ "wrap the expression in parenthesis",
+ suggs,
+ Applicability::MachineApplicable,
+ )
+ .emit();
+ }
+ }
+ }
+
+ fn check_let_else_init_trailing_brace(&self, init: &ast::Expr) {
+ if let Some(trailing) = classify::expr_trailing_brace(init) {
+ let err_span = trailing.span.with_lo(trailing.span.hi() - BytePos(1));
+ let suggs = vec![
+ (trailing.span.shrink_to_lo(), "(".to_string()),
+ (trailing.span.shrink_to_hi(), ")".to_string()),
+ ];
+ self.struct_span_err(
+ err_span,
+ "right curly brace `}` before `else` in a `let...else` statement not allowed",
+ )
+ .multipart_suggestion(
+ "try wrapping the expression in parenthesis",
+ suggs,
+ Applicability::MachineApplicable,
+ )
+ .emit();
+ }
}
/// Parses the RHS of a local variable declaration (e.g., `= 14;`).
@@ -493,21 +551,19 @@
}
}
StmtKind::Expr(_) | StmtKind::MacCall(_) => {}
- StmtKind::Local(ref mut local) => {
- if let Err(e) = self.expect_semi() {
- // We might be at the `,` in `let x = foo<bar, baz>;`. Try to recover.
- match &mut local.init {
- Some(ref mut expr) => {
+ StmtKind::Local(ref mut local) if let Err(e) = self.expect_semi() => {
+ // We might be at the `,` in `let x = foo<bar, baz>;`. Try to recover.
+ match &mut local.kind {
+ LocalKind::Init(expr) | LocalKind::InitElse(expr, _) => {
self.check_mistyped_turbofish_with_multiple_type_params(e, expr)?;
// We found `foo<bar, baz>`, have we fully recovered?
self.expect_semi()?;
}
- None => return Err(e),
- }
+ LocalKind::Decl => return Err(e),
}
eat_semi = false;
}
- StmtKind::Empty | StmtKind::Item(_) | StmtKind::Semi(_) => eat_semi = false,
+ StmtKind::Empty | StmtKind::Item(_) | StmtKind::Local(_) | StmtKind::Semi(_) => eat_semi = false,
}
if eat_semi && self.eat(&token::Semi) {
@@ -518,7 +574,14 @@
}
pub(super) fn mk_block(&self, stmts: Vec<Stmt>, rules: BlockCheckMode, span: Span) -> P<Block> {
- P(Block { stmts, id: DUMMY_NODE_ID, rules, span, tokens: None })
+ P(Block {
+ stmts,
+ id: DUMMY_NODE_ID,
+ rules,
+ span,
+ tokens: None,
+ could_be_bare_literal: false,
+ })
}
pub(super) fn mk_stmt(&self, span: Span, kind: StmtKind) -> Stmt {
diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs
index 1fbf01b..9840037 100644
--- a/compiler/rustc_parse/src/parser/ty.rs
+++ b/compiler/rustc_parse/src/parser/ty.rs
@@ -11,12 +11,12 @@
use rustc_span::source_map::Span;
use rustc_span::symbol::{kw, sym};
-/// Any `?` or `?const` modifiers that appear at the start of a bound.
+/// Any `?` or `~const` modifiers that appear at the start of a bound.
struct BoundModifiers {
/// `?Trait`.
maybe: Option<Span>,
- /// `?const Trait`.
+ /// `~const Trait`.
maybe_const: Option<Span>,
}
@@ -226,19 +226,6 @@
}
} else if self.eat_keyword(kw::Impl) {
self.parse_impl_ty(&mut impl_dyn_multi)?
- } else if self.token.is_keyword(kw::Union)
- && self.look_ahead(1, |t| t == &token::OpenDelim(token::Brace))
- {
- self.bump();
- let (fields, recovered) = self.parse_record_struct_body("union")?;
- let span = lo.to(self.prev_token.span);
- self.sess.gated_spans.gate(sym::unnamed_fields, span);
- TyKind::AnonymousUnion(fields, recovered)
- } else if self.eat_keyword(kw::Struct) {
- let (fields, recovered) = self.parse_record_struct_body("struct")?;
- let span = lo.to(self.prev_token.span);
- self.sess.gated_spans.gate(sym::unnamed_fields, span);
- TyKind::AnonymousStruct(fields, recovered)
} else if self.is_explicit_dyn_type() {
self.parse_dyn_ty(&mut impl_dyn_multi)?
} else if self.eat_lt() {
@@ -609,6 +596,7 @@
|| self.check_lifetime()
|| self.check(&token::Not) // Used for error reporting only.
|| self.check(&token::Question)
+ || self.check(&token::Tilde)
|| self.check_keyword(kw::For)
|| self.check(&token::OpenDelim(token::Paren))
}
@@ -655,7 +643,7 @@
let inner_lo = self.token.span;
let is_negative = self.eat(&token::Not);
- let modifiers = self.parse_ty_bound_modifiers();
+ let modifiers = self.parse_ty_bound_modifiers()?;
let bound = if self.token.is_lifetime() {
self.error_lt_bound_with_modifiers(modifiers);
self.parse_generic_lt_bound(lo, inner_lo, has_parens)?
@@ -690,7 +678,7 @@
if let Some(span) = modifiers.maybe_const {
self.struct_span_err(
span,
- "`?const` may only modify trait bounds, not lifetime bounds",
+ "`~const` may only modify trait bounds, not lifetime bounds",
)
.emit();
}
@@ -721,34 +709,27 @@
Ok(())
}
- /// Parses the modifiers that may precede a trait in a bound, e.g. `?Trait` or `?const Trait`.
+ /// Parses the modifiers that may precede a trait in a bound, e.g. `?Trait` or `~const Trait`.
///
/// If no modifiers are present, this does not consume any tokens.
///
/// ```
- /// TY_BOUND_MODIFIERS = "?" ["const" ["?"]]
+ /// TY_BOUND_MODIFIERS = ["~const"] ["?"]
/// ```
- fn parse_ty_bound_modifiers(&mut self) -> BoundModifiers {
- if !self.eat(&token::Question) {
- return BoundModifiers { maybe: None, maybe_const: None };
- }
+ fn parse_ty_bound_modifiers(&mut self) -> PResult<'a, BoundModifiers> {
+ let maybe_const = if self.eat(&token::Tilde) {
+ let tilde = self.prev_token.span;
+ self.expect_keyword(kw::Const)?;
+ let span = tilde.to(self.prev_token.span);
+ self.sess.gated_spans.gate(sym::const_trait_impl, span);
+ Some(span)
+ } else {
+ None
+ };
- // `? ...`
- let first_question = self.prev_token.span;
- if !self.eat_keyword(kw::Const) {
- return BoundModifiers { maybe: Some(first_question), maybe_const: None };
- }
+ let maybe = if self.eat(&token::Question) { Some(self.prev_token.span) } else { None };
- // `?const ...`
- let maybe_const = first_question.to(self.prev_token.span);
- self.sess.gated_spans.gate(sym::const_trait_bound_opt_out, maybe_const);
- if !self.eat(&token::Question) {
- return BoundModifiers { maybe: None, maybe_const: Some(maybe_const) };
- }
-
- // `?const ? ...`
- let second_question = self.prev_token.span;
- BoundModifiers { maybe: Some(second_question), maybe_const: Some(maybe_const) }
+ Ok(BoundModifiers { maybe, maybe_const })
}
/// Parses a type bound according to:
@@ -757,7 +738,7 @@
/// TY_BOUND_NOPAREN = [TY_BOUND_MODIFIERS] [for<LT_PARAM_DEFS>] SIMPLE_PATH
/// ```
///
- /// For example, this grammar accepts `?const ?for<'a: 'b> m::Trait<'a>`.
+ /// For example, this grammar accepts `~const ?for<'a: 'b> m::Trait<'a>`.
fn parse_generic_ty_bound(
&mut self,
lo: Span,
diff --git a/compiler/rustc_parse/src/validate_attr.rs b/compiler/rustc_parse/src/validate_attr.rs
index 2137272..67695dc 100644
--- a/compiler/rustc_parse/src/validate_attr.rs
+++ b/compiler/rustc_parse/src/validate_attr.rs
@@ -24,16 +24,15 @@
Some((name, _, template, _)) if name != sym::rustc_dummy => {
check_builtin_attribute(sess, attr, name, template)
}
- _ => {
- if let MacArgs::Eq(..) = attr.get_normal_item().args {
- // All key-value attributes are restricted to meta-item syntax.
- parse_meta(sess, attr)
- .map_err(|mut err| {
- err.emit();
- })
- .ok();
- }
+ _ if let MacArgs::Eq(..) = attr.get_normal_item().args => {
+ // All key-value attributes are restricted to meta-item syntax.
+ parse_meta(sess, attr)
+ .map_err(|mut err| {
+ err.emit();
+ })
+ .ok();
}
+ _ => {}
}
}
diff --git a/compiler/rustc_parse_format/Cargo.toml b/compiler/rustc_parse_format/Cargo.toml
index c2317d9..7b77560 100644
--- a/compiler/rustc_parse_format/Cargo.toml
+++ b/compiler/rustc_parse_format/Cargo.toml
@@ -1,5 +1,4 @@
[package]
-authors = ["The Rust Project Developers"]
name = "rustc_parse_format"
version = "0.0.0"
edition = "2018"
diff --git a/compiler/rustc_passes/Cargo.toml b/compiler/rustc_passes/Cargo.toml
index c69d488..bf1e52c 100644
--- a/compiler/rustc_passes/Cargo.toml
+++ b/compiler/rustc_passes/Cargo.toml
@@ -1,5 +1,4 @@
[package]
-authors = ["The Rust Project Developers"]
name = "rustc_passes"
version = "0.0.0"
edition = "2018"
@@ -12,6 +11,7 @@
rustc_errors = { path = "../rustc_errors" }
rustc_hir = { path = "../rustc_hir" }
rustc_index = { path = "../rustc_index" }
+rustc_parse = { path = "../rustc_parse" }
rustc_session = { path = "../rustc_session" }
rustc_target = { path = "../rustc_target" }
rustc_ast = { path = "../rustc_ast" }
@@ -19,3 +19,4 @@
rustc_span = { path = "../rustc_span" }
rustc_lexer = { path = "../rustc_lexer" }
rustc_ast_pretty = { path = "../rustc_ast_pretty" }
+rustc_feature = { path = "../rustc_feature" }
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index 7123183..fd438bd 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -8,8 +8,10 @@
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::TyCtxt;
-use rustc_ast::{AttrStyle, Attribute, Lit, LitKind, NestedMetaItem};
+use rustc_ast::{ast, AttrStyle, Attribute, Lit, LitKind, NestedMetaItem};
+use rustc_data_structures::stable_set::FxHashSet;
use rustc_errors::{pluralize, struct_span_err, Applicability};
+use rustc_feature::{AttributeType, BUILTIN_ATTRIBUTE_MAP};
use rustc_hir as hir;
use rustc_hir::def_id::LocalDefId;
use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
@@ -66,9 +68,10 @@
) {
let mut is_valid = true;
let mut specified_inline = None;
+ let mut seen = FxHashSet::default();
let attrs = self.tcx.hir().attrs(hir_id);
for attr in attrs {
- is_valid &= match attr.name_or_empty() {
+ let attr_is_valid = match attr.name_or_empty() {
sym::inline => self.check_inline(hir_id, attr, span, target),
sym::non_exhaustive => self.check_non_exhaustive(hir_id, attr, span, target),
sym::marker => self.check_marker(hir_id, attr, span, target),
@@ -101,14 +104,72 @@
sym::default_method_body_is_const => {
self.check_default_method_body_is_const(attr, span, target)
}
+ sym::rustc_const_unstable
+ | sym::rustc_const_stable
+ | sym::unstable
+ | sym::stable
+ | sym::rustc_promotable => self.check_stability_promotable(&attr, span, target),
_ => true,
};
+ is_valid &= attr_is_valid;
+
// lint-only checks
match attr.name_or_empty() {
sym::cold => self.check_cold(hir_id, attr, span, target),
sym::link_name => self.check_link_name(hir_id, attr, span, target),
sym::link_section => self.check_link_section(hir_id, attr, span, target),
sym::no_mangle => self.check_no_mangle(hir_id, attr, span, target),
+ sym::deprecated | sym::rustc_deprecated => {
+ self.check_deprecated(hir_id, attr, span, target)
+ }
+ sym::macro_use | sym::macro_escape => self.check_macro_use(hir_id, attr, target),
+ sym::path => self.check_generic_attr(hir_id, attr, target, &[Target::Mod]),
+ sym::cfg_attr => self.check_cfg_attr(hir_id, attr),
+ sym::plugin_registrar => self.check_plugin_registrar(hir_id, attr, target),
+ sym::macro_export => self.check_macro_export(hir_id, attr, target),
+ sym::ignore | sym::should_panic | sym::proc_macro_derive => {
+ self.check_generic_attr(hir_id, attr, target, &[Target::Fn])
+ }
+ sym::automatically_derived => {
+ self.check_generic_attr(hir_id, attr, target, &[Target::Impl])
+ }
+ sym::no_implicit_prelude => {
+ self.check_generic_attr(hir_id, attr, target, &[Target::Mod])
+ }
+ _ => {}
+ }
+
+ if hir_id != CRATE_HIR_ID {
+ if let Some((_, AttributeType::CrateLevel, ..)) =
+ attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name))
+ {
+ self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| {
+ let msg = match attr.style {
+ ast::AttrStyle::Outer => {
+ "crate-level attribute should be an inner attribute: add an exclamation \
+ mark: `#![foo]`"
+ }
+ ast::AttrStyle::Inner => "crate-level attribute should be in the root module",
+ };
+ lint.build(msg).emit()
+ });
+ }
+ }
+
+ // Duplicate attributes
+ match attr.name_or_empty() {
+ name @ sym::macro_use => {
+ let args = attr.meta_item_list().unwrap_or_else(Vec::new);
+ let args: Vec<_> = args.iter().map(|arg| arg.name_or_empty()).collect();
+ if !seen.insert((name, args)) {
+ self.tcx.struct_span_lint_hir(
+ UNUSED_ATTRIBUTES,
+ hir_id,
+ attr.span,
+ |lint| lint.build("unused attribute").emit(),
+ );
+ }
+ }
_ => {}
}
}
@@ -211,6 +272,37 @@
}
}
+ fn check_generic_attr(
+ &self,
+ hir_id: HirId,
+ attr: &Attribute,
+ target: Target,
+ allowed_targets: &[Target],
+ ) {
+ if !allowed_targets.iter().any(|t| t == &target) {
+ let name = attr.name_or_empty();
+ let mut i = allowed_targets.iter();
+ // Pluralize
+ let b = i.next().map_or_else(String::new, |t| t.to_string() + "s");
+ let supported_names = i.enumerate().fold(b, |mut b, (i, allowed_target)| {
+ if allowed_targets.len() > 2 && i == allowed_targets.len() - 2 {
+ b.push_str(", and ");
+ } else if allowed_targets.len() == 2 && i == allowed_targets.len() - 2 {
+ b.push_str(" and ");
+ } else {
+ b.push_str(", ");
+ }
+ // Pluralize
+ b.push_str(&(allowed_target.to_string() + "s"));
+ b
+ });
+ self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| {
+ lint.build(&format!("`#[{name}]` only has an effect on {}", supported_names))
+ .emit();
+ });
+ }
+ }
+
/// Checks if `#[naked]` is applied to a function definition.
fn check_naked(&self, hir_id: HirId, attr: &Attribute, span: &Span, target: Target) -> bool {
match target {
@@ -717,6 +809,42 @@
true
}
+ /// Checks that `doc(test(...))` attribute contains only valid attributes. Returns `true` if
+ /// valid.
+ fn check_test_attr(&self, meta: &NestedMetaItem, hir_id: HirId) -> bool {
+ let mut is_valid = true;
+ if let Some(metas) = meta.meta_item_list() {
+ for i_meta in metas {
+ match i_meta.name_or_empty() {
+ sym::attr | sym::no_crate_inject => {}
+ _ => {
+ self.tcx.struct_span_lint_hir(
+ INVALID_DOC_ATTRIBUTES,
+ hir_id,
+ i_meta.span(),
+ |lint| {
+ lint.build(&format!(
+ "unknown `doc(test)` attribute `{}`",
+ rustc_ast_pretty::pprust::path_to_string(
+ &i_meta.meta_item().unwrap().path
+ ),
+ ))
+ .emit();
+ },
+ );
+ is_valid = false;
+ }
+ }
+ }
+ } else {
+ self.tcx.struct_span_lint_hir(INVALID_DOC_ATTRIBUTES, hir_id, meta.span(), |lint| {
+ lint.build("`#[doc(test(...)]` takes a list of attributes").emit();
+ });
+ is_valid = false;
+ }
+ is_valid
+ }
+
/// Runs various checks on `#[doc]` attributes. Returns `true` if valid.
///
/// `specified_inline` should be initialized to `None` and kept for the scope
@@ -793,9 +921,29 @@
| sym::no_inline
| sym::notable_trait
| sym::passes
- | sym::plugins
- | sym::primitive
- | sym::test => {}
+ | sym::plugins => {}
+
+ sym::test => {
+ if !self.check_test_attr(&meta, hir_id) {
+ is_valid = false;
+ }
+ }
+
+ sym::primitive => {
+ if !self.tcx.features().doc_primitive {
+ self.tcx.struct_span_lint_hir(
+ INVALID_DOC_ATTRIBUTES,
+ hir_id,
+ i_meta.span,
+ |lint| {
+ let mut diag = lint.build(
+ "`doc(primitive)` should never have been stable",
+ );
+ diag.emit();
+ },
+ );
+ }
+ }
_ => {
self.tcx.struct_span_lint_hir(
@@ -855,7 +1003,7 @@
hir_id,
meta.span(),
|lint| {
- lint.build(&format!("invalid `doc` attribute")).emit();
+ lint.build(&"invalid `doc` attribute").emit();
},
);
is_valid = false;
@@ -962,6 +1110,10 @@
}
}
+ fn is_impl_item(&self, hir_id: HirId) -> bool {
+ matches!(self.tcx.hir().get(hir_id), hir::Node::ImplItem(..))
+ }
+
/// Checks if `#[export_name]` is applied to a function or static. Returns `true` if valid.
fn check_export_name(
&self,
@@ -971,7 +1123,8 @@
target: Target,
) -> bool {
match target {
- Target::Static | Target::Fn | Target::Method(..) => true,
+ Target::Static | Target::Fn => true,
+ Target::Method(..) if self.is_impl_item(hir_id) => 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
@@ -985,9 +1138,9 @@
.sess
.struct_span_err(
attr.span,
- "attribute should be applied to a function or static",
+ "attribute should be applied to a free function, impl method or static",
)
- .span_label(*span, "not a function or static")
+ .span_label(*span, "not a free function, impl method or static")
.emit();
false
}
@@ -1169,7 +1322,8 @@
/// Checks if `#[no_mangle]` is applied to a function or static.
fn check_no_mangle(&self, hir_id: HirId, attr: &Attribute, span: &Span, target: Target) {
match target {
- Target::Static | Target::Fn | Target::Method(..) => {}
+ Target::Static | Target::Fn => {}
+ Target::Method(..) if self.is_impl_item(hir_id) => {}
// 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
@@ -1177,18 +1331,50 @@
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, this should be an error
+ // The error should specify that the item that is wrong is specifically a *foreign* fn/static
+ // otherwise the error seems odd
+ Target::ForeignFn | Target::ForeignStatic => {
+ let foreign_item_kind = match target {
+ Target::ForeignFn => "function",
+ Target::ForeignStatic => "static",
+ _ => unreachable!(),
+ };
+ self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| {
+ lint.build(&format!(
+ "`#[no_mangle]` has no effect on a foreign {}",
+ foreign_item_kind
+ ))
+ .warn(
+ "this was previously accepted by the compiler but is \
+ being phased out; it will become a hard error in \
+ a future release!",
+ )
+ .span_label(*span, format!("foreign {}", foreign_item_kind))
+ .note("symbol names in extern blocks are not mangled")
+ .span_suggestion(
+ attr.span,
+ "remove this attribute",
+ String::new(),
+ Applicability::MachineApplicable,
+ )
+ .emit();
+ });
+ }
_ => {
// FIXME: #[no_mangle] was previously allowed on non-functions/statics and some
// crates used this, so only emit a warning.
self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| {
- lint.build("attribute should be applied to a function or static")
- .warn(
- "this was previously accepted by the compiler but is \
- being phased out; it will become a hard error in \
- a future release!",
- )
- .span_label(*span, "not a function or static")
- .emit();
+ lint.build(
+ "attribute should be applied to a free function, impl method or static",
+ )
+ .warn(
+ "this was previously accepted by the compiler but is \
+ being phased out; it will become a hard error in \
+ a future release!",
+ )
+ .span_label(*span, "not a free function, impl method or static")
+ .emit();
});
}
}
@@ -1491,6 +1677,72 @@
}
}
}
+
+ fn check_stability_promotable(&self, attr: &Attribute, _span: &Span, target: Target) -> bool {
+ match target {
+ Target::Expression => {
+ self.tcx
+ .sess
+ .struct_span_err(attr.span, "attribute cannot be applied to an expression")
+ .emit();
+ false
+ }
+ _ => true,
+ }
+ }
+
+ fn check_deprecated(&self, hir_id: HirId, attr: &Attribute, _span: &Span, target: Target) {
+ match target {
+ Target::Closure | Target::Expression | Target::Statement | Target::Arm => {
+ self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| {
+ lint.build("attribute is ignored here").emit();
+ });
+ }
+ _ => {}
+ }
+ }
+
+ fn check_macro_use(&self, hir_id: HirId, attr: &Attribute, target: Target) {
+ let name = attr.name_or_empty();
+ match target {
+ Target::ExternCrate | Target::Mod => {}
+ _ => {
+ self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| {
+ lint.build(&format!(
+ "`#[{name}]` only has an effect on `extern crate` and modules"
+ ))
+ .emit();
+ });
+ }
+ }
+ }
+
+ fn check_macro_export(&self, hir_id: HirId, attr: &Attribute, target: Target) {
+ if target != Target::MacroDef {
+ self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| {
+ lint.build(&format!("`#[macro_export]` only has an effect on macro definitions"))
+ .emit();
+ });
+ }
+ }
+
+ fn check_cfg_attr(&self, hir_id: HirId, attr: &Attribute) {
+ if let Some((_, attrs)) = rustc_parse::parse_cfg_attr(&attr, &self.tcx.sess.parse_sess) {
+ if attrs.is_empty() {
+ self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| {
+ lint.build("`#[cfg_attr]` does not expand to any attributes").emit();
+ });
+ }
+ }
+ }
+
+ fn check_plugin_registrar(&self, hir_id: HirId, attr: &Attribute, target: Target) {
+ if target != Target::Fn {
+ self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| {
+ lint.build("`#[plugin_registrar]` only has an effect on functions").emit();
+ });
+ }
+ }
}
impl Visitor<'tcx> for CheckAttrVisitor<'tcx> {
@@ -1501,6 +1753,16 @@
}
fn visit_item(&mut self, item: &'tcx Item<'tcx>) {
+ // Historically we've run more checks on non-exported than exported macros,
+ // so this lets us continue to run them while maintaining backwards compatibility.
+ // In the long run, the checks should be harmonized.
+ if let ItemKind::Macro(ref macro_def) = item.kind {
+ let def_id = item.def_id.to_def_id();
+ if macro_def.macro_rules && !self.tcx.has_attr(def_id, sym::macro_export) {
+ check_non_exported_macro_for_invalid_attrs(self.tcx, item);
+ }
+ }
+
let target = Target::from_item(item);
self.check_attributes(item.hir_id(), &item.span, target, Some(ItemLike::Item(item)));
intravisit::walk_item(self, item)
@@ -1573,11 +1835,6 @@
intravisit::walk_variant(self, variant, generics, item_id)
}
- fn visit_macro_def(&mut self, macro_def: &'tcx hir::MacroDef<'tcx>) {
- self.check_attributes(macro_def.hir_id(), ¯o_def.span, Target::MacroDef, None);
- intravisit::walk_macro_def(self, macro_def);
- }
-
fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) {
self.check_attributes(param.hir_id, ¶m.span, Target::Param, None);
@@ -1611,7 +1868,7 @@
for attr in attrs {
for attr_to_check in ATTRS_TO_CHECK {
- if tcx.sess.check_name(attr, *attr_to_check) {
+ if attr.has_name(*attr_to_check) {
tcx.sess
.struct_span_err(
attr.span,
@@ -1626,9 +1883,11 @@
}
}
-fn check_invalid_macro_level_attr(tcx: TyCtxt<'_>, attrs: &[Attribute]) {
+fn check_non_exported_macro_for_invalid_attrs(tcx: TyCtxt<'_>, item: &Item<'_>) {
+ let attrs = tcx.hir().attrs(item.hir_id());
+
for attr in attrs {
- if tcx.sess.check_name(attr, sym::inline) {
+ if attr.has_name(sym::inline) {
struct_span_err!(
tcx.sess,
attr.span,
@@ -1644,8 +1903,6 @@
fn check_mod_attrs(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
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() {
check_attr_visitor.check_attributes(CRATE_HIR_ID, &DUMMY_SP, Target::Mod, None);
check_invalid_crate_level_attr(tcx, tcx.hir().krate_attrs());
diff --git a/compiler/rustc_passes/src/check_const.rs b/compiler/rustc_passes/src/check_const.rs
index 6ee54cf..4a82252a 100644
--- a/compiler/rustc_passes/src/check_const.rs
+++ b/compiler/rustc_passes/src/check_const.rs
@@ -40,18 +40,16 @@
use hir::MatchSource::*;
let gates: &[_] = match self {
- // A `for` loop's desugaring contains a call to `IntoIterator::into_iter`,
- // so they are not yet allowed.
- // Likewise, `?` desugars to a call to `Try::into_result`.
- Self::Loop(ForLoop) | Self::Match(ForLoopDesugar | TryDesugar | AwaitDesugar) => {
+ Self::Match(AwaitDesugar) => {
return None;
}
- Self::Match(IfLetGuardDesugar) => bug!("`if let` guard outside a `match` expression"),
+ Self::Loop(ForLoop) | Self::Match(ForLoopDesugar) => &[sym::const_for],
+
+ Self::Match(TryDesugar) => &[sym::const_try],
// All other expressions are allowed.
- Self::Loop(Loop | While | WhileLet)
- | Self::Match(WhileDesugar | WhileLetDesugar | Normal | IfLetDesugar { .. }) => &[],
+ Self::Loop(Loop | While) | Self::Match(Normal) => &[],
};
Some(gates)
@@ -276,9 +274,7 @@
hir::ExprKind::Match(_, _, source) => {
let non_const_expr = match source {
// These are handled by `ExprKind::Loop` above.
- hir::MatchSource::WhileDesugar
- | hir::MatchSource::WhileLetDesugar
- | hir::MatchSource::ForLoopDesugar => None,
+ hir::MatchSource::ForLoopDesugar => None,
_ => Some(NonConstExpr::Match(*source)),
};
diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs
index b71ec70..ae65222 100644
--- a/compiler/rustc_passes/src/dead.rs
+++ b/compiler/rustc_passes/src/dead.rs
@@ -5,7 +5,7 @@
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_hir as hir;
use rustc_hir::def::{CtorOf, DefKind, Res};
-use rustc_hir::def_id::DefId;
+use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
use rustc_hir::itemlikevisit::ItemLikeVisitor;
use rustc_hir::{Node, PatKind, TyKind};
@@ -14,16 +14,16 @@
use rustc_middle::middle::privacy;
use rustc_middle::ty::{self, DefIdTree, TyCtxt};
use rustc_session::lint;
-
use rustc_span::symbol::{sym, Symbol};
+use std::mem;
// Any local node that may call something in its body block should be
// explored. For example, if it's a live Node::Item that is a
// 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 {
+fn should_explore(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
matches!(
- tcx.hir().find(hir_id),
+ tcx.hir().find(tcx.hir().local_def_id_to_hir_id(def_id)),
Some(
Node::Item(..)
| Node::ImplItem(..)
@@ -31,23 +31,22 @@
| Node::TraitItem(..)
| Node::Variant(..)
| Node::AnonConst(..)
- | Node::Pat(..),
)
)
}
struct MarkSymbolVisitor<'tcx> {
- worklist: Vec<hir::HirId>,
+ worklist: Vec<LocalDefId>,
tcx: TyCtxt<'tcx>,
maybe_typeck_results: Option<&'tcx ty::TypeckResults<'tcx>>,
- live_symbols: FxHashSet<hir::HirId>,
+ live_symbols: FxHashSet<LocalDefId>,
repr_has_repr_c: bool,
in_pat: bool,
inherited_pub_visibility: bool,
pub_visibility: bool,
ignore_variant_stack: Vec<DefId>,
// maps from tuple struct constructors to tuple struct items
- struct_constructors: FxHashMap<hir::HirId, hir::HirId>,
+ struct_constructors: FxHashMap<LocalDefId, LocalDefId>,
}
impl<'tcx> MarkSymbolVisitor<'tcx> {
@@ -62,19 +61,17 @@
fn check_def_id(&mut self, def_id: DefId) {
if let Some(def_id) = def_id.as_local() {
- let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id);
- if should_explore(self.tcx, hir_id) || self.struct_constructors.contains_key(&hir_id) {
- self.worklist.push(hir_id);
+ if should_explore(self.tcx, def_id) || self.struct_constructors.contains_key(&def_id) {
+ self.worklist.push(def_id);
}
- self.live_symbols.insert(hir_id);
+ self.live_symbols.insert(def_id);
}
}
fn insert_def_id(&mut self, def_id: DefId) {
if let Some(def_id) = def_id.as_local() {
- let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id);
- debug_assert!(!should_explore(self.tcx, hir_id));
- self.live_symbols.insert(hir_id);
+ debug_assert!(!should_explore(self.tcx, def_id));
+ self.live_symbols.insert(def_id);
}
}
@@ -233,9 +230,9 @@
// in the case of tuple struct constructors we want to check the item, not the generated
// tuple struct constructor function
- let id = self.struct_constructors.get(&id).cloned().unwrap_or(id);
+ let id = self.struct_constructors.get(&id).copied().unwrap_or(id);
- if let Some(node) = self.tcx.hir().find(id) {
+ if let Some(node) = self.tcx.hir().find(self.tcx.hir().local_def_id_to_hir_id(id)) {
self.live_symbols.insert(id);
self.visit_node(node);
}
@@ -326,7 +323,8 @@
let live_fields = def.fields().iter().filter(|f| {
has_repr_c || (pub_visibility && (inherited_pub_visibility || f.vis.node.is_pub()))
});
- self.live_symbols.extend(live_fields.map(|f| f.hir_id));
+ let hir = self.tcx.hir();
+ self.live_symbols.extend(live_fields.map(|f| hir.local_def_id(f.hir_id)));
intravisit::walk_struct_def(self, def);
}
@@ -398,8 +396,14 @@
}
fn visit_anon_const(&mut self, c: &'tcx hir::AnonConst) {
- self.live_symbols.insert(c.hir_id);
+ // When inline const blocks are used in pattern position, paths
+ // referenced by it should be considered as used.
+ let in_pat = mem::replace(&mut self.in_pat, false);
+
+ self.live_symbols.insert(self.tcx.hir().local_def_id(c.hir_id));
intravisit::walk_anon_const(self, c);
+
+ self.in_pat = in_pat;
}
}
@@ -445,47 +449,52 @@
// 2) We are not sure to be live or not
// * Implementations of traits and trait methods
struct LifeSeeder<'k, 'tcx> {
- worklist: Vec<hir::HirId>,
+ worklist: Vec<LocalDefId>,
krate: &'k hir::Crate<'k>,
tcx: TyCtxt<'tcx>,
// see `MarkSymbolVisitor::struct_constructors`
- struct_constructors: FxHashMap<hir::HirId, hir::HirId>,
+ struct_constructors: FxHashMap<LocalDefId, LocalDefId>,
}
impl<'v, 'k, 'tcx> ItemLikeVisitor<'v> for LifeSeeder<'k, 'tcx> {
fn visit_item(&mut self, item: &hir::Item<'_>) {
let allow_dead_code = has_allow_dead_code_or_lang_attr(self.tcx, item.hir_id());
if allow_dead_code {
- self.worklist.push(item.hir_id());
+ self.worklist.push(item.def_id);
}
match item.kind {
hir::ItemKind::Enum(ref enum_def, _) => {
+ let hir = self.tcx.hir();
if allow_dead_code {
- self.worklist.extend(enum_def.variants.iter().map(|variant| variant.id));
+ self.worklist.extend(
+ enum_def.variants.iter().map(|variant| hir.local_def_id(variant.id)),
+ );
}
for variant in enum_def.variants {
if let Some(ctor_hir_id) = variant.data.ctor_hir_id() {
- self.struct_constructors.insert(ctor_hir_id, variant.id);
+ self.struct_constructors
+ .insert(hir.local_def_id(ctor_hir_id), hir.local_def_id(variant.id));
}
}
}
hir::ItemKind::Impl(hir::Impl { ref of_trait, items, .. }) => {
if of_trait.is_some() {
- self.worklist.push(item.hir_id());
+ self.worklist.push(item.def_id);
}
for impl_item_ref in items {
let impl_item = self.krate.impl_item(impl_item_ref.id);
if of_trait.is_some()
|| has_allow_dead_code_or_lang_attr(self.tcx, impl_item.hir_id())
{
- self.worklist.push(impl_item_ref.id.hir_id());
+ self.worklist.push(impl_item_ref.id.def_id);
}
}
}
hir::ItemKind::Struct(ref variant_data, _) => {
if let Some(ctor_hir_id) = variant_data.ctor_hir_id() {
- self.struct_constructors.insert(ctor_hir_id, item.hir_id());
+ self.struct_constructors
+ .insert(self.tcx.hir().local_def_id(ctor_hir_id), item.def_id);
}
}
_ => (),
@@ -497,7 +506,7 @@
if matches!(trait_item.kind, Const(_, Some(_)) | Fn(_, hir::TraitFn::Provided(_)))
&& has_allow_dead_code_or_lang_attr(self.tcx, trait_item.hir_id())
{
- self.worklist.push(trait_item.hir_id());
+ self.worklist.push(trait_item.def_id);
}
}
@@ -510,7 +519,7 @@
if matches!(foreign_item.kind, Static(..) | Fn(..))
&& has_allow_dead_code_or_lang_attr(self.tcx, foreign_item.hir_id())
{
- self.worklist.push(foreign_item.hir_id());
+ self.worklist.push(foreign_item.def_id);
}
}
}
@@ -519,7 +528,7 @@
tcx: TyCtxt<'tcx>,
access_levels: &privacy::AccessLevels,
krate: &hir::Crate<'_>,
-) -> (Vec<hir::HirId>, FxHashMap<hir::HirId, hir::HirId>) {
+) -> (Vec<LocalDefId>, FxHashMap<LocalDefId, LocalDefId>) {
let worklist = access_levels
.map
.iter()
@@ -528,12 +537,8 @@
if level >= privacy::AccessLevel::Reachable { Some(id) } else { None }
},
)
- .chain(
- // Seed entry point
- tcx.entry_fn(()).and_then(|(def_id, _)| {
- def_id.as_local().map(|def_id| tcx.hir().local_def_id_to_hir_id(def_id))
- }),
- )
+ // Seed entry point
+ .chain(tcx.entry_fn(()).and_then(|(def_id, _)| def_id.as_local()))
.collect::<Vec<_>>();
// Seed implemented trait items
@@ -548,7 +553,7 @@
tcx: TyCtxt<'tcx>,
access_levels: &privacy::AccessLevels,
krate: &hir::Crate<'_>,
-) -> FxHashSet<hir::HirId> {
+) -> FxHashSet<LocalDefId> {
let (worklist, struct_constructors) = create_and_seed_worklist(tcx, access_levels, krate);
let mut symbol_visitor = MarkSymbolVisitor {
worklist,
@@ -568,7 +573,7 @@
struct DeadVisitor<'tcx> {
tcx: TyCtxt<'tcx>,
- live_symbols: FxHashSet<hir::HirId>,
+ live_symbols: FxHashSet<LocalDefId>,
}
impl DeadVisitor<'tcx> {
@@ -583,42 +588,41 @@
| hir::ItemKind::Struct(..)
| hir::ItemKind::Union(..)
);
- should_warn && !self.symbol_is_live(item.hir_id())
+ should_warn && !self.symbol_is_live(item.def_id)
}
fn should_warn_about_field(&mut self, field: &hir::FieldDef<'_>) -> bool {
- let field_type = self.tcx.type_of(self.tcx.hir().local_def_id(field.hir_id));
+ let def_id = self.tcx.hir().local_def_id(field.hir_id);
+ let field_type = self.tcx.type_of(def_id);
!field.is_positional()
- && !self.symbol_is_live(field.hir_id)
+ && !self.symbol_is_live(def_id)
&& !field_type.is_phantom_data()
&& !has_allow_dead_code_or_lang_attr(self.tcx, field.hir_id)
}
fn should_warn_about_variant(&mut self, variant: &hir::Variant<'_>) -> bool {
- !self.symbol_is_live(variant.id) && !has_allow_dead_code_or_lang_attr(self.tcx, variant.id)
+ let def_id = self.tcx.hir().local_def_id(variant.id);
+ !self.symbol_is_live(def_id) && !has_allow_dead_code_or_lang_attr(self.tcx, variant.id)
}
fn should_warn_about_foreign_item(&mut self, fi: &hir::ForeignItem<'_>) -> bool {
- !self.symbol_is_live(fi.hir_id())
- && !has_allow_dead_code_or_lang_attr(self.tcx, fi.hir_id())
+ !self.symbol_is_live(fi.def_id) && !has_allow_dead_code_or_lang_attr(self.tcx, fi.hir_id())
}
// id := HIR id of an item's definition.
- fn symbol_is_live(&mut self, id: hir::HirId) -> bool {
- if self.live_symbols.contains(&id) {
+ fn symbol_is_live(&mut self, def_id: LocalDefId) -> bool {
+ if self.live_symbols.contains(&def_id) {
return true;
}
// If it's a type whose items are live, then it's live, too.
// This is done to handle the case where, for example, the static
// method of a private type is used, but the type itself is never
// called directly.
- let def_id = self.tcx.hir().local_def_id(id);
let inherent_impls = self.tcx.inherent_impls(def_id);
for &impl_did in inherent_impls.iter() {
for item_did in self.tcx.associated_item_def_ids(impl_did) {
- if let Some(did) = item_did.as_local() {
- let item_hir_id = self.tcx.hir().local_def_id_to_hir_id(did);
- if self.live_symbols.contains(&item_hir_id) {
+ if let Some(def_id) = item_did.as_local() {
+ if self.live_symbols.contains(&def_id) {
return true;
}
}
@@ -721,7 +725,7 @@
fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) {
match impl_item.kind {
hir::ImplItemKind::Const(_, body_id) => {
- if !self.symbol_is_live(impl_item.hir_id()) {
+ if !self.symbol_is_live(impl_item.def_id) {
self.warn_dead_code(
impl_item.hir_id(),
impl_item.span,
@@ -732,7 +736,7 @@
self.visit_nested_body(body_id)
}
hir::ImplItemKind::Fn(_, body_id) => {
- if !self.symbol_is_live(impl_item.hir_id()) {
+ if !self.symbol_is_live(impl_item.def_id) {
// FIXME(66095): Because impl_item.span is annotated with things
// like expansion data, and ident.span isn't, we use the
// def_span method if it's part of a macro invocation
diff --git a/compiler/rustc_passes/src/diagnostic_items.rs b/compiler/rustc_passes/src/diagnostic_items.rs
index ddcc6fc..3f12a74 100644
--- a/compiler/rustc_passes/src/diagnostic_items.rs
+++ b/compiler/rustc_passes/src/diagnostic_items.rs
@@ -15,7 +15,6 @@
use rustc_hir::itemlikevisit::ItemLikeVisitor;
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::TyCtxt;
-use rustc_session::Session;
use rustc_span::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE};
use rustc_span::symbol::{sym, Symbol};
@@ -51,7 +50,7 @@
fn observe_item(&mut self, def_id: LocalDefId) {
let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id);
let attrs = self.tcx.hir().attrs(hir_id);
- if let Some(name) = extract(&self.tcx.sess, attrs) {
+ if let Some(name) = extract(attrs) {
// insert into our table
collect_item(self.tcx, &mut self.items, name, def_id.to_def_id());
}
@@ -91,10 +90,10 @@
}
}
-/// Extract the first `rustc_diagnostic_item = "$name"` out of a list of attributes.
-fn extract(sess: &Session, attrs: &[ast::Attribute]) -> Option<Symbol> {
+/// Extract the first `rustc_diagnostic_item = "$name"` out of a list of attributes.p
+fn extract(attrs: &[ast::Attribute]) -> Option<Symbol> {
attrs.iter().find_map(|attr| {
- if sess.check_name(attr, sym::rustc_diagnostic_item) { attr.value_str() } else { None }
+ if attr.has_name(sym::rustc_diagnostic_item) { attr.value_str() } else { None }
})
}
@@ -108,10 +107,6 @@
// Collect diagnostic items in this crate.
tcx.hir().krate().visit_all_item_likes(&mut collector);
- for m in tcx.hir().krate().exported_macros {
- collector.observe_item(m.def_id);
- }
-
collector.items
}
diff --git a/compiler/rustc_passes/src/entry.rs b/compiler/rustc_passes/src/entry.rs
index 550f4f1..e881a85 100644
--- a/compiler/rustc_passes/src/entry.rs
+++ b/compiler/rustc_passes/src/entry.rs
@@ -183,7 +183,7 @@
}
fn no_main_err(tcx: TyCtxt<'_>, visitor: &EntryContext<'_, '_>) {
- let sp = tcx.hir().krate().item.inner;
+ let sp = tcx.hir().krate().module().inner;
if *tcx.sess.parse_sess.reached_eof.borrow() {
// There's an unclosed brace that made the parser reach `Eof`, we shouldn't complain about
// the missing `fn main()` then as it might have been hidden inside an unclosed block.
@@ -229,7 +229,7 @@
if let Some(main_def) = tcx.resolutions(()).main_def {
if main_def.opt_fn_def_id().is_none() {
// There is something at `crate::main`, but it is not a function definition.
- err.span_label(main_def.span, &format!("non-function item at `crate::main` is found"));
+ err.span_label(main_def.span, "non-function item at `crate::main` is found");
}
}
diff --git a/compiler/rustc_passes/src/hir_stats.rs b/compiler/rustc_passes/src/hir_stats.rs
index 2bed8ca..b8ce973 100644
--- a/compiler/rustc_passes/src/hir_stats.rs
+++ b/compiler/rustc_passes/src/hir_stats.rs
@@ -244,11 +244,6 @@
fn visit_attribute(&mut self, _: hir::HirId, attr: &'v ast::Attribute) {
self.record("Attribute", Id::Attr(attr.id), attr);
}
-
- fn visit_macro_def(&mut self, macro_def: &'v hir::MacroDef<'v>) {
- self.record("MacroDef", Id::Node(macro_def.hir_id()), macro_def);
- hir_visit::walk_macro_def(self, macro_def)
- }
}
impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> {
diff --git a/compiler/rustc_passes/src/intrinsicck.rs b/compiler/rustc_passes/src/intrinsicck.rs
index 012d97e..96e9a40 100644
--- a/compiler/rustc_passes/src/intrinsicck.rs
+++ b/compiler/rustc_passes/src/intrinsicck.rs
@@ -139,6 +139,7 @@
reg: InlineAsmRegOrRegClass,
expr: &hir::Expr<'tcx>,
template: &[InlineAsmTemplatePiece],
+ is_input: bool,
tied_input: Option<(&hir::Expr<'tcx>, Option<InlineAsmType>)>,
) -> Option<InlineAsmType> {
// Check the type against the allowed types for inline asm.
@@ -150,7 +151,9 @@
_ => unreachable!(),
};
let asm_ty = match *ty.kind() {
- ty::Never | ty::Error(_) => return None,
+ // `!` is allowed for input but not for output (issue #87802)
+ ty::Never if is_input => return None,
+ ty::Error(_) => return None,
ty::Int(IntTy::I8) | ty::Uint(UintTy::U8) => Some(InlineAsmType::I8),
ty::Int(IntTy::I16) | ty::Uint(UintTy::U16) => Some(InlineAsmType::I16),
ty::Int(IntTy::I32) | ty::Uint(UintTy::U32) => Some(InlineAsmType::I32),
@@ -350,24 +353,26 @@
for (idx, (op, _)) in asm.operands.iter().enumerate() {
match *op {
hir::InlineAsmOperand::In { reg, ref expr } => {
- self.check_asm_operand_type(idx, reg, expr, asm.template, None);
+ self.check_asm_operand_type(idx, reg, expr, asm.template, true, None);
}
hir::InlineAsmOperand::Out { reg, late: _, ref expr } => {
if let Some(expr) = expr {
- self.check_asm_operand_type(idx, reg, expr, asm.template, None);
+ self.check_asm_operand_type(idx, reg, expr, asm.template, false, None);
}
}
hir::InlineAsmOperand::InOut { reg, late: _, ref expr } => {
- self.check_asm_operand_type(idx, reg, expr, asm.template, None);
+ self.check_asm_operand_type(idx, reg, expr, asm.template, false, None);
}
hir::InlineAsmOperand::SplitInOut { reg, late: _, ref in_expr, ref out_expr } => {
- let in_ty = self.check_asm_operand_type(idx, reg, in_expr, asm.template, None);
+ let in_ty =
+ self.check_asm_operand_type(idx, reg, in_expr, asm.template, true, None);
if let Some(out_expr) = out_expr {
self.check_asm_operand_type(
idx,
reg,
out_expr,
asm.template,
+ false,
Some((in_expr, in_ty)),
);
}
diff --git a/compiler/rustc_passes/src/lang_items.rs b/compiler/rustc_passes/src/lang_items.rs
index 3a88d19..77ff8dc 100644
--- a/compiler/rustc_passes/src/lang_items.rs
+++ b/compiler/rustc_passes/src/lang_items.rs
@@ -13,11 +13,12 @@
use rustc_middle::middle::cstore::ExternCrate;
use rustc_middle::ty::TyCtxt;
+use rustc_ast::Attribute;
use rustc_errors::{pluralize, struct_span_err};
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_hir::itemlikevisit::ItemLikeVisitor;
-use rustc_hir::lang_items::{extract, ITEM_REFS};
+use rustc_hir::lang_items::{extract, GenericRequirement, ITEM_REFS};
use rustc_hir::{HirId, LangItem, LanguageItems, Target};
use rustc_span::Span;
@@ -57,7 +58,7 @@
fn check_for_lang(&mut self, actual_target: Target, hir_id: HirId) {
let attrs = self.tcx.hir().attrs(hir_id);
- let check_name = |attr, sym| self.tcx.sess.check_name(attr, sym);
+ let check_name = |attr: &Attribute, sym| attr.has_name(sym);
if let Some((value, span)) = extract(check_name, &attrs) {
match ITEM_REFS.get(&value).cloned() {
// Known lang item with attribute on correct target.
@@ -182,97 +183,39 @@
}
// Like collect_item() above, but also checks whether the lang item is declared
- // with the right number of generic arguments if it is a trait.
+ // with the right number of generic arguments.
fn collect_item_extended(&mut self, item_index: usize, hir_id: HirId, span: Span) {
let item_def_id = self.tcx.hir().local_def_id(hir_id).to_def_id();
let lang_item = LangItem::from_u32(item_index as u32).unwrap();
let name = lang_item.name();
- self.collect_item(item_index, item_def_id);
-
// Now check whether the lang_item has the expected number of generic
- // arguments if it is a trait. Generally speaking, binary and indexing
- // operations have one (for the RHS/index), unary operations have none,
- // and the rest also have none except for the closure traits (one for
- // the argument list), generators (one for the resume argument),
- // ordering/equality relations (one for the RHS), and various conversion
- // traits.
+ // arguments. Generally speaking, binary and indexing operations have
+ // one (for the RHS/index), unary operations have none, the closure
+ // traits have one for the argument list, generators have one for the
+ // resume argument, and ordering/equality relations have one for the RHS
+ // Some other types like Box and various functions like drop_in_place
+ // have minimum requirements.
- let expected_num = match lang_item {
- // Binary operations
- LangItem::Add
- | LangItem::Sub
- | LangItem::Mul
- | LangItem::Div
- | LangItem::Rem
- | LangItem::BitXor
- | LangItem::BitAnd
- | LangItem::BitOr
- | LangItem::Shl
- | LangItem::Shr
- | LangItem::AddAssign
- | LangItem::SubAssign
- | LangItem::MulAssign
- | LangItem::DivAssign
- | LangItem::RemAssign
- | LangItem::BitXorAssign
- | LangItem::BitAndAssign
- | LangItem::BitOrAssign
- | LangItem::ShlAssign
- | LangItem::ShrAssign
- | LangItem::Index
- | LangItem::IndexMut
-
- // Miscellaneous
- | LangItem::Unsize
- | LangItem::CoerceUnsized
- | LangItem::DispatchFromDyn
- | LangItem::Fn
- | LangItem::FnMut
- | LangItem::FnOnce
- | LangItem::Generator
- | LangItem::PartialEq
- | LangItem::PartialOrd
- => Some(1),
-
- // Unary operations
- LangItem::Neg
- | LangItem::Not
-
- // Miscellaneous
- | LangItem::Deref
- | LangItem::DerefMut
- | LangItem::Sized
- | LangItem::StructuralPeq
- | LangItem::StructuralTeq
- | LangItem::Copy
- | LangItem::Clone
- | LangItem::Sync
- | LangItem::DiscriminantKind
- | LangItem::PointeeTrait
- | LangItem::Freeze
- | LangItem::Drop
- | LangItem::Receiver
- | LangItem::Future
- | LangItem::Unpin
- | LangItem::Termination
- | LangItem::Try
- => Some(0),
-
- // Not a trait
- _ => None,
- };
-
- if let Some(expected_num) = expected_num {
- let (actual_num, generics_span) = match self.tcx.hir().get(hir_id) {
- hir::Node::Item(hir::Item {
- kind: hir::ItemKind::Trait(_, _, generics, ..),
- ..
- }) => (generics.params.len(), generics.span),
- _ => bug!("op/index/deref lang item target is not a trait: {:?}", lang_item),
+ if let hir::Node::Item(hir::Item { kind, span: item_span, .. }) = self.tcx.hir().get(hir_id)
+ {
+ let (actual_num, generics_span) = match kind.generics() {
+ Some(generics) => (generics.params.len(), generics.span),
+ None => (0, *item_span),
};
- if expected_num != actual_num {
+ let required = match lang_item.required_generics() {
+ GenericRequirement::Exact(num) if num != actual_num => {
+ Some((format!("{}", num), pluralize!(num)))
+ }
+ GenericRequirement::Minimum(num) if actual_num < num => {
+ Some((format!("at least {}", num), pluralize!(num)))
+ }
+ // If the number matches, or there is no requirement, handle it normally
+ _ => None,
+ };
+
+ if let Some((range_str, pluralized)) = required {
// We are issuing E0718 "incorrect target" here, because while the
// item kind of the target is correct, the target is still wrong
// because of the wrong number of generic arguments.
@@ -280,23 +223,29 @@
self.tcx.sess,
span,
E0718,
- "`{}` language item must be applied to a trait with {} generic argument{}",
+ "`{}` language item must be applied to a {} with {} generic argument{}",
name,
- expected_num,
- pluralize!(expected_num)
+ kind.descr(),
+ range_str,
+ pluralized,
)
.span_label(
generics_span,
format!(
- "this trait has {} generic argument{}, not {}",
+ "this {} has {} generic argument{}",
+ kind.descr(),
actual_num,
pluralize!(actual_num),
- expected_num
),
)
.emit();
+
+ // return early to not collect the lang item
+ return;
}
}
+
+ self.collect_item(item_index, item_def_id);
}
}
diff --git a/compiler/rustc_passes/src/layout_test.rs b/compiler/rustc_passes/src/layout_test.rs
index 18c1d64..64ea4ee 100644
--- a/compiler/rustc_passes/src/layout_test.rs
+++ b/compiler/rustc_passes/src/layout_test.rs
@@ -27,7 +27,7 @@
| ItemKind::Struct(..)
| ItemKind::Union(..) => {
for attr in self.tcx.get_attrs(item.def_id.to_def_id()).iter() {
- if self.tcx.sess.check_name(attr, sym::rustc_layout) {
+ if attr.has_name(sym::rustc_layout) {
self.dump_layout_of(item.def_id, item, attr);
}
}
@@ -113,7 +113,7 @@
param_env: ParamEnv<'tcx>,
}
-impl LayoutOf for UnwrapLayoutCx<'tcx> {
+impl LayoutOf<'tcx> for UnwrapLayoutCx<'tcx> {
type Ty = Ty<'tcx>;
type TyAndLayout = TyAndLayout<'tcx>;
diff --git a/compiler/rustc_passes/src/lib.rs b/compiler/rustc_passes/src/lib.rs
index cadb8d2..f583a5d 100644
--- a/compiler/rustc_passes/src/lib.rs
+++ b/compiler/rustc_passes/src/lib.rs
@@ -7,6 +7,7 @@
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
#![feature(crate_visibility_modifier)]
#![feature(in_band_lifetimes)]
+#![feature(format_args_capture)]
#![feature(iter_zip)]
#![feature(nll)]
#![feature(min_specialization)]
diff --git a/compiler/rustc_passes/src/lib_features.rs b/compiler/rustc_passes/src/lib_features.rs
index 363a6417..7d15ca1 100644
--- a/compiler/rustc_passes/src/lib_features.rs
+++ b/compiler/rustc_passes/src/lib_features.rs
@@ -33,9 +33,7 @@
// Find a stability attribute (i.e., `#[stable (..)]`, `#[unstable (..)]`,
// `#[rustc_const_unstable (..)]`).
- if let Some(stab_attr) =
- stab_attrs.iter().find(|stab_attr| self.tcx.sess.check_name(attr, **stab_attr))
- {
+ if let Some(stab_attr) = stab_attrs.iter().find(|stab_attr| attr.has_name(**stab_attr)) {
let meta_item = attr.meta();
if let Some(MetaItem { kind: MetaItemKind::List(ref metas), .. }) = meta_item {
let mut feature = None;
@@ -129,9 +127,7 @@
fn get_lib_features(tcx: TyCtxt<'_>, (): ()) -> LibFeatures {
let mut collector = LibFeatureCollector::new(tcx);
let krate = tcx.hir().krate();
- for attr in krate.non_exported_macro_attrs {
- collector.visit_attribute(rustc_hir::CRATE_HIR_ID, attr);
- }
+
intravisit::walk_crate(&mut collector, krate);
collector.lib_features
}
diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs
index 4ceefa1..ab9bfea 100644
--- a/compiler/rustc_passes/src/liveness.rs
+++ b/compiler/rustc_passes/src/liveness.rs
@@ -95,7 +95,7 @@
use rustc_index::vec::IndexVec;
use rustc_middle::hir::map::Map;
use rustc_middle::ty::query::Providers;
-use rustc_middle::ty::{self, DefIdTree, RootVariableMinCaptureList, TyCtxt};
+use rustc_middle::ty::{self, DefIdTree, RootVariableMinCaptureList, Ty, TyCtxt};
use rustc_session::lint;
use rustc_span::symbol::{kw, sym, Symbol};
use rustc_span::Span;
@@ -123,8 +123,8 @@
#[derive(Copy, Clone, PartialEq, Debug)]
enum LiveNodeKind {
UpvarNode(Span),
- ExprNode(Span),
- VarDefNode(Span),
+ ExprNode(Span, HirId),
+ VarDefNode(Span, HirId),
ClosureNode,
ExitNode,
}
@@ -133,8 +133,8 @@
let sm = tcx.sess.source_map();
match lnk {
UpvarNode(s) => format!("Upvar node [{}]", sm.span_to_diagnostic_string(s)),
- ExprNode(s) => format!("Expr node [{}]", sm.span_to_diagnostic_string(s)),
- VarDefNode(s) => format!("Var def node [{}]", sm.span_to_diagnostic_string(s)),
+ ExprNode(s, _) => format!("Expr node [{}]", sm.span_to_diagnostic_string(s)),
+ VarDefNode(s, _) => format!("Var def node [{}]", sm.span_to_diagnostic_string(s)),
ClosureNode => "Closure node".to_owned(),
ExitNode => "Exit node".to_owned(),
}
@@ -297,7 +297,7 @@
}
pat.each_binding(|_, hir_id, _, ident| {
- self.add_live_node_for_node(hir_id, VarDefNode(ident.span));
+ self.add_live_node_for_node(hir_id, VarDefNode(ident.span, hir_id));
self.add_variable(Local(LocalInfo {
id: hir_id,
name: ident.name,
@@ -332,8 +332,13 @@
}
}
- if let Some(captures) = maps.tcx.typeck(local_def_id).closure_min_captures.get(&def_id) {
- for &var_hir_id in captures.keys() {
+ // Don't run unused pass for #[naked]
+ if self.tcx.has_attr(def_id, sym::naked) {
+ return;
+ }
+
+ if let Some(upvars) = maps.tcx.upvars_mentioned(def_id) {
+ for &var_hir_id in upvars.keys() {
let var_name = maps.tcx.hir().name(var_hir_id);
maps.add_variable(Upvar(var_hir_id, var_name));
}
@@ -391,30 +396,23 @@
hir::ExprKind::Path(hir::QPath::Resolved(_, ref path)) => {
debug!("expr {}: path that leads to {:?}", expr.hir_id, path.res);
if let Res::Local(_var_hir_id) = path.res {
- self.add_live_node_for_node(expr.hir_id, ExprNode(expr.span));
+ self.add_live_node_for_node(expr.hir_id, ExprNode(expr.span, expr.hir_id));
}
intravisit::walk_expr(self, expr);
}
hir::ExprKind::Closure(..) => {
// Interesting control flow (for loops can contain labeled
// breaks or continues)
- self.add_live_node_for_node(expr.hir_id, ExprNode(expr.span));
+ self.add_live_node_for_node(expr.hir_id, ExprNode(expr.span, expr.hir_id));
- // Make a live_node for each captured variable, with the span
+ // Make a live_node for each mentioned variable, with the span
// being the location that the variable is used. This results
// in better error messages than just pointing at the closure
// construction site.
let mut call_caps = Vec::new();
let closure_def_id = self.tcx.hir().local_def_id(expr.hir_id);
- if let Some(captures) = self
- .tcx
- .typeck(closure_def_id)
- .closure_min_captures
- .get(&closure_def_id.to_def_id())
- {
- // If closure_min_captures is Some, upvars_mentioned must also be Some
- let upvars = self.tcx.upvars_mentioned(closure_def_id).unwrap();
- call_caps.extend(captures.keys().map(|var_id| {
+ if let Some(upvars) = self.tcx.upvars_mentioned(closure_def_id) {
+ call_caps.extend(upvars.keys().map(|var_id| {
let upvar = upvars[var_id];
let upvar_ln = self.add_live_node(UpvarNode(upvar.span));
CaptureInfo { ln: upvar_ln, var_hid: *var_id }
@@ -424,13 +422,21 @@
intravisit::walk_expr(self, expr);
}
+ hir::ExprKind::Let(ref pat, ..) => {
+ self.add_from_pat(pat);
+ intravisit::walk_expr(self, expr);
+ }
+
// live nodes required for interesting control flow:
- hir::ExprKind::If(..) | hir::ExprKind::Match(..) | hir::ExprKind::Loop(..) => {
- self.add_live_node_for_node(expr.hir_id, ExprNode(expr.span));
+ hir::ExprKind::If(..)
+ | hir::ExprKind::Match(..)
+ | hir::ExprKind::Loop(..)
+ | hir::ExprKind::Yield(..) => {
+ self.add_live_node_for_node(expr.hir_id, ExprNode(expr.span, expr.hir_id));
intravisit::walk_expr(self, expr);
}
hir::ExprKind::Binary(op, ..) if op.node.is_lazy() => {
- self.add_live_node_for_node(expr.hir_id, ExprNode(expr.span));
+ self.add_live_node_for_node(expr.hir_id, ExprNode(expr.span, expr.hir_id));
intravisit::walk_expr(self, expr);
}
@@ -459,7 +465,6 @@
| hir::ExprKind::InlineAsm(..)
| hir::ExprKind::LlvmInlineAsm(..)
| hir::ExprKind::Box(..)
- | hir::ExprKind::Yield(..)
| hir::ExprKind::Type(..)
| hir::ExprKind::Err
| hir::ExprKind::Path(hir::QPath::TypeRelative(..))
@@ -484,7 +489,6 @@
ir: &'a mut IrMaps<'tcx>,
typeck_results: &'a ty::TypeckResults<'tcx>,
param_env: ty::ParamEnv<'tcx>,
- upvars: Option<&'tcx FxIndexMap<hir::HirId, hir::Upvar>>,
closure_min_captures: Option<&'tcx RootVariableMinCaptureList<'tcx>>,
successors: IndexVec<LiveNode, Option<LiveNode>>,
rwu_table: rwu_table::RWUTable,
@@ -508,7 +512,6 @@
fn new(ir: &'a mut IrMaps<'tcx>, body_owner: LocalDefId) -> Liveness<'a, 'tcx> {
let typeck_results = ir.tcx.typeck(body_owner);
let param_env = ir.tcx.param_env(body_owner);
- let upvars = ir.tcx.upvars_mentioned(body_owner);
let closure_min_captures = typeck_results.closure_min_captures.get(&body_owner.to_def_id());
let closure_ln = ir.add_live_node(ClosureNode);
let exit_ln = ir.add_live_node(ExitNode);
@@ -520,7 +523,6 @@
ir,
typeck_results,
param_env,
- upvars,
closure_min_captures,
successors: IndexVec::from_elem_n(None, num_live_nodes),
rwu_table: rwu_table::RWUTable::new(num_live_nodes, num_vars),
@@ -847,10 +849,22 @@
})
}
+ hir::ExprKind::Let(ref pat, ref scrutinee, _) => {
+ let succ = self.propagate_through_expr(scrutinee, succ);
+ self.define_bindings_in_pat(pat, succ)
+ }
+
// 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::Yield(ref e, ..) => {
+ let yield_ln = self.live_node(expr.hir_id, expr.span);
+ self.init_from_succ(yield_ln, succ);
+ self.merge_from_succ(yield_ln, self.exit_ln);
+ self.propagate_through_expr(e, yield_ln)
+ }
+
hir::ExprKind::If(ref cond, ref then, ref else_opt) => {
//
// (cond)
@@ -977,32 +991,13 @@
}
hir::ExprKind::Call(ref f, ref args) => {
- let m = self.ir.tcx.parent_module(expr.hir_id).to_def_id();
- let succ = if self.ir.tcx.is_ty_uninhabited_from(
- m,
- self.typeck_results.expr_ty(expr),
- self.param_env,
- ) {
- self.exit_ln
- } else {
- succ
- };
+ let succ = self.check_is_ty_uninhabited(expr, succ);
let succ = self.propagate_through_exprs(args, succ);
self.propagate_through_expr(&f, succ)
}
hir::ExprKind::MethodCall(.., ref args, _) => {
- let m = self.ir.tcx.parent_module(expr.hir_id).to_def_id();
- let succ = if self.ir.tcx.is_ty_uninhabited_from(
- m,
- self.typeck_results.expr_ty(expr),
- self.param_env,
- ) {
- self.exit_ln
- } else {
- succ
- };
-
+ let succ = self.check_is_ty_uninhabited(expr, succ);
self.propagate_through_exprs(args, succ)
}
@@ -1029,7 +1024,6 @@
| hir::ExprKind::Type(ref e, _)
| hir::ExprKind::DropTemps(ref e)
| hir::ExprKind::Unary(_, ref e)
- | hir::ExprKind::Yield(ref e, _)
| hir::ExprKind::Repeat(ref e, _) => self.propagate_through_expr(&e, succ),
hir::ExprKind::InlineAsm(ref asm) => {
@@ -1219,21 +1213,7 @@
acc: u32,
) -> LiveNode {
match path.res {
- Res::Local(hid) => {
- let in_upvars = self.upvars.map_or(false, |u| u.contains_key(&hid));
- let in_captures = self.closure_min_captures.map_or(false, |c| c.contains_key(&hid));
-
- match (in_upvars, in_captures) {
- (false, _) | (true, true) => self.access_var(hir_id, hid, succ, acc, path.span),
- (true, false) => {
- // This case is possible when with RFC-2229, a wild pattern
- // is used within a closure.
- // eg: `let _ = x`. The closure doesn't capture x here,
- // even though it's mentioned in the closure.
- succ
- }
- }
- }
+ Res::Local(hid) => self.access_var(hir_id, hid, succ, acc, path.span),
_ => succ,
}
}
@@ -1274,6 +1254,66 @@
ln
}
+
+ fn check_is_ty_uninhabited(&mut self, expr: &Expr<'_>, succ: LiveNode) -> LiveNode {
+ let ty = self.typeck_results.expr_ty(expr);
+ let m = self.ir.tcx.parent_module(expr.hir_id).to_def_id();
+ if self.ir.tcx.is_ty_uninhabited_from(m, ty, self.param_env) {
+ match self.ir.lnks[succ] {
+ LiveNodeKind::ExprNode(succ_span, succ_id) => {
+ self.warn_about_unreachable(expr.span, ty, succ_span, succ_id, "expression");
+ }
+ LiveNodeKind::VarDefNode(succ_span, succ_id) => {
+ self.warn_about_unreachable(expr.span, ty, succ_span, succ_id, "definition");
+ }
+ _ => {}
+ };
+ self.exit_ln
+ } else {
+ succ
+ }
+ }
+
+ fn warn_about_unreachable(
+ &mut self,
+ orig_span: Span,
+ orig_ty: Ty<'tcx>,
+ expr_span: Span,
+ expr_id: HirId,
+ descr: &str,
+ ) {
+ if !orig_ty.is_never() {
+ // Unreachable code warnings are already emitted during type checking.
+ // However, during type checking, full type information is being
+ // calculated but not yet available, so the check for diverging
+ // expressions due to uninhabited result types is pretty crude and
+ // only checks whether ty.is_never(). Here, we have full type
+ // information available and can issue warnings for less obviously
+ // uninhabited types (e.g. empty enums). The check above is used so
+ // that we do not emit the same warning twice if the uninhabited type
+ // is indeed `!`.
+
+ self.ir.tcx.struct_span_lint_hir(
+ lint::builtin::UNREACHABLE_CODE,
+ expr_id,
+ expr_span,
+ |lint| {
+ let msg = format!("unreachable {}", descr);
+ lint.build(&msg)
+ .span_label(expr_span, &msg)
+ .span_label(orig_span, "any code following this expression is unreachable")
+ .span_note(
+ orig_span,
+ &format!(
+ "this expression has type `{}`, which is uninhabited",
+ orig_ty
+ ),
+ )
+ .emit();
+ },
+ );
+ }
+ }
}
// _______________________________________________________________________
@@ -1298,6 +1338,7 @@
fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) {
check_expr(self, ex);
+ intravisit::walk_expr(self, ex);
}
fn visit_arm(&mut self, arm: &'tcx hir::Arm<'tcx>) {
@@ -1353,6 +1394,10 @@
}
}
+ hir::ExprKind::Let(ref pat, ..) => {
+ this.check_unused_vars_in_pat(pat, None, |_, _, _, _| {});
+ }
+
// no correctness conditions related to liveness
hir::ExprKind::Call(..)
| hir::ExprKind::MethodCall(..)
@@ -1383,8 +1428,6 @@
| hir::ExprKind::Type(..)
| hir::ExprKind::Err => {}
}
-
- intravisit::walk_expr(this, expr);
}
impl<'tcx> Liveness<'_, 'tcx> {
diff --git a/compiler/rustc_passes/src/naked_functions.rs b/compiler/rustc_passes/src/naked_functions.rs
index 89bc2e1..d3ecd18 100644
--- a/compiler/rustc_passes/src/naked_functions.rs
+++ b/compiler/rustc_passes/src/naked_functions.rs
@@ -1,12 +1,13 @@
//! Checks validity of naked functions.
-use rustc_ast::InlineAsmOptions;
+use rustc_ast::{Attribute, InlineAsmOptions};
use rustc_hir as hir;
use rustc_hir::def_id::LocalDefId;
use rustc_hir::intravisit::{ErasedMap, FnKind, NestedVisitorMap, Visitor};
use rustc_hir::{ExprKind, HirId, InlineAsmOperand, StmtKind};
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::TyCtxt;
+use rustc_session::lint::builtin::UNDEFINED_NAKED_FUNCTION_ABI;
use rustc_session::lint::builtin::UNSUPPORTED_NAKED_FUNCTIONS;
use rustc_span::symbol::sym;
use rustc_span::Span;
@@ -70,14 +71,24 @@
check_no_patterns(self.tcx, body.params);
check_no_parameters_use(self.tcx, body);
check_asm(self.tcx, hir_id, body, span);
+ check_inline(self.tcx, hir_id, attrs);
}
}
}
+/// Check that the function isn't inlined.
+fn check_inline(tcx: TyCtxt<'_>, hir_id: HirId, attrs: &[Attribute]) {
+ for attr in attrs.iter().filter(|attr| attr.has_name(sym::inline)) {
+ tcx.struct_span_lint_hir(UNSUPPORTED_NAKED_FUNCTIONS, hir_id, attr.span, |lint| {
+ lint.build("naked functions cannot be inlined").emit();
+ });
+ }
+}
+
/// Checks that function uses non-Rust ABI.
fn check_abi(tcx: TyCtxt<'_>, hir_id: HirId, abi: Abi, fn_ident_span: Span) {
if abi == Abi::Rust {
- tcx.struct_span_lint_hir(UNSUPPORTED_NAKED_FUNCTIONS, hir_id, fn_ident_span, |lint| {
+ tcx.struct_span_lint_hir(UNDEFINED_NAKED_FUNCTION_ABI, hir_id, fn_ident_span, |lint| {
lint.build("Rust ABI is unsupported in naked functions").emit();
});
}
@@ -210,6 +221,7 @@
| ExprKind::Index(..)
| ExprKind::Path(..)
| ExprKind::AddrOf(..)
+ | ExprKind::Let(..)
| ExprKind::Break(..)
| ExprKind::Continue(..)
| ExprKind::Ret(..)
diff --git a/compiler/rustc_passes/src/reachable.rs b/compiler/rustc_passes/src/reachable.rs
index 0b3227a..23f4323 100644
--- a/compiler/rustc_passes/src/reachable.rs
+++ b/compiler/rustc_passes/src/reachable.rs
@@ -211,19 +211,22 @@
if !self.any_library {
// If we are building an executable, only explicitly extern
// types need to be exported.
- if let Node::Item(item) = *node {
- let reachable = if let hir::ItemKind::Fn(ref sig, ..) = item.kind {
+ let reachable =
+ if let Node::Item(hir::Item { kind: hir::ItemKind::Fn(sig, ..), .. })
+ | Node::ImplItem(hir::ImplItem {
+ kind: hir::ImplItemKind::Fn(sig, ..), ..
+ }) = *node
+ {
sig.header.abi != Abi::Rust
} else {
false
};
- let codegen_attrs = self.tcx.codegen_fn_attrs(item.def_id);
- let is_extern = codegen_attrs.contains_extern_indicator();
- let std_internal =
- codegen_attrs.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL);
- if reachable || is_extern || std_internal {
- self.reachable_symbols.insert(search_item);
- }
+ let codegen_attrs = self.tcx.codegen_fn_attrs(search_item);
+ let is_extern = codegen_attrs.contains_extern_indicator();
+ let std_internal =
+ codegen_attrs.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL);
+ if reachable || is_extern || std_internal {
+ self.reachable_symbols.insert(search_item);
}
} else {
// If we are building a library, then reachable symbols will
@@ -260,6 +263,7 @@
| hir::ItemKind::Use(..)
| hir::ItemKind::OpaqueTy(..)
| hir::ItemKind::TyAlias(..)
+ | hir::ItemKind::Macro(..)
| hir::ItemKind::Mod(..)
| hir::ItemKind::ForeignMod { .. }
| hir::ItemKind::Impl { .. }
@@ -306,8 +310,7 @@
| Node::Ctor(..)
| Node::Field(_)
| Node::Ty(_)
- | Node::Crate(_)
- | Node::MacroDef(_) => {}
+ | Node::Crate(_) => {}
_ => {
bug!(
"found unexpected node kind in worklist: {} ({:?})",
@@ -335,23 +338,29 @@
worklist: &'a mut Vec<LocalDefId>,
}
-impl<'a, 'tcx> ItemLikeVisitor<'tcx> for CollectPrivateImplItemsVisitor<'a, 'tcx> {
- fn visit_item(&mut self, item: &hir::Item<'_>) {
+impl CollectPrivateImplItemsVisitor<'_, '_> {
+ fn push_to_worklist_if_has_custom_linkage(&mut self, def_id: LocalDefId) {
// Anything which has custom linkage gets thrown on the worklist no
// matter where it is in the crate, along with "special std symbols"
// which are currently akin to allocator symbols.
- let codegen_attrs = self.tcx.codegen_fn_attrs(item.def_id);
+ let codegen_attrs = self.tcx.codegen_fn_attrs(def_id);
if codegen_attrs.contains_extern_indicator()
|| codegen_attrs.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL)
{
- self.worklist.push(item.def_id);
+ self.worklist.push(def_id);
}
+ }
+}
+
+impl<'a, 'tcx> ItemLikeVisitor<'tcx> for CollectPrivateImplItemsVisitor<'a, 'tcx> {
+ fn visit_item(&mut self, item: &hir::Item<'_>) {
+ self.push_to_worklist_if_has_custom_linkage(item.def_id);
// We need only trait impls here, not inherent impls, and only non-exported ones
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()) {
+ if !self.access_levels.is_reachable(item.def_id) {
// FIXME(#53488) remove `let`
let tcx = self.tcx;
self.worklist.extend(items.iter().map(|ii_ref| ii_ref.id.def_id));
@@ -375,8 +384,8 @@
fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem<'_>) {}
- fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem<'_>) {
- // processed in visit_item above
+ fn visit_impl_item(&mut self, impl_item: &hir::ImplItem<'_>) {
+ self.push_to_worklist_if_has_custom_linkage(impl_item.def_id);
}
fn visit_foreign_item(&mut self, _foreign_item: &hir::ForeignItem<'_>) {
@@ -404,9 +413,7 @@
// If other crates link to us, they're going to expect to be able to
// use the lang items, so we need to be sure to mark them as
// exported.
- reachable_context
- .worklist
- .extend(access_levels.map.iter().map(|(id, _)| tcx.hir().local_def_id(*id)));
+ reachable_context.worklist.extend(access_levels.map.keys());
for item in tcx.lang_items().items().iter() {
if let Some(def_id) = *item {
if let Some(def_id) = def_id.as_local() {
diff --git a/compiler/rustc_passes/src/region.rs b/compiler/rustc_passes/src/region.rs
index c133f1a..08702ca 100644
--- a/compiler/rustc_passes/src/region.rs
+++ b/compiler/rustc_passes/src/region.rs
@@ -233,14 +233,12 @@
terminating(r.hir_id.local_id);
}
- hir::ExprKind::If(ref expr, ref then, Some(ref otherwise)) => {
- terminating(expr.hir_id.local_id);
+ hir::ExprKind::If(_, ref then, Some(ref otherwise)) => {
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);
+ hir::ExprKind::If(_, ref then, None) => {
terminating(then.hir_id.local_id);
}
@@ -392,6 +390,25 @@
}
}
+ hir::ExprKind::If(ref cond, ref then, Some(ref otherwise)) => {
+ let expr_cx = visitor.cx;
+ visitor.enter_scope(Scope { id: then.hir_id.local_id, data: ScopeData::IfThen });
+ visitor.cx.var_parent = visitor.cx.parent;
+ visitor.visit_expr(cond);
+ visitor.visit_expr(then);
+ visitor.cx = expr_cx;
+ visitor.visit_expr(otherwise);
+ }
+
+ hir::ExprKind::If(ref cond, ref then, None) => {
+ let expr_cx = visitor.cx;
+ visitor.enter_scope(Scope { id: then.hir_id.local_id, data: ScopeData::IfThen });
+ visitor.cx.var_parent = visitor.cx.parent;
+ visitor.visit_expr(cond);
+ visitor.visit_expr(then);
+ visitor.cx = expr_cx;
+ }
+
_ => intravisit::walk_expr(visitor, expr),
}
diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs
index 42a4753..a88393c 100644
--- a/compiler/rustc_passes/src/stability.rs
+++ b/compiler/rustc_passes/src/stability.rs
@@ -7,7 +7,7 @@
use rustc_errors::struct_span_err;
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
-use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_INDEX, LOCAL_CRATE};
+use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID, CRATE_DEF_INDEX, LOCAL_CRATE};
use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
use rustc_hir::{FieldDef, Generics, HirId, Item, TraitRef, Ty, TyKind, Variant};
use rustc_middle::hir::map::Map;
@@ -99,7 +99,7 @@
// If the node is a function, `fn_sig` is its signature
fn annotate<F>(
&mut self,
- hir_id: HirId,
+ def_id: LocalDefId,
item_sp: Span,
fn_sig: Option<&'tcx hir::FnSig<'tcx>>,
kind: AnnotationKind,
@@ -110,11 +110,11 @@
) where
F: FnOnce(&mut Self),
{
- let attrs = self.tcx.hir().attrs(hir_id);
- debug!("annotate(id = {:?}, attrs = {:?})", hir_id, attrs);
+ let attrs = self.tcx.get_attrs(def_id.to_def_id());
+ debug!("annotate(id = {:?}, attrs = {:?})", def_id, attrs);
let mut did_error = false;
if !self.tcx.features().staged_api {
- did_error = self.forbid_staged_api_attrs(hir_id, attrs, inherit_deprecation.clone());
+ did_error = self.forbid_staged_api_attrs(def_id, attrs, inherit_deprecation.clone());
}
let depr = if did_error { None } else { attr::find_deprecation(&self.tcx.sess, attrs) };
@@ -123,6 +123,7 @@
is_deprecated = true;
if kind == AnnotationKind::Prohibited || kind == AnnotationKind::DeprecationProhibited {
+ let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id);
self.tcx.struct_span_lint_hir(USELESS_DEPRECATED, hir_id, *span, |lint| {
lint.build("this `#[deprecated]` annotation has no effect")
.span_suggestion_short(
@@ -136,18 +137,18 @@
}
// `Deprecation` is just two pointers, no need to intern it
- let depr_entry = DeprecationEntry::local(depr.clone(), hir_id);
- self.index.depr_map.insert(hir_id, depr_entry);
+ let depr_entry = DeprecationEntry::local(depr.clone(), def_id);
+ self.index.depr_map.insert(def_id, depr_entry);
} else if let Some(parent_depr) = self.parent_depr.clone() {
if inherit_deprecation.yes() {
is_deprecated = true;
- info!("tagging child {:?} as deprecated from parent", hir_id);
- self.index.depr_map.insert(hir_id, parent_depr);
+ info!("tagging child {:?} as deprecated from parent", def_id);
+ self.index.depr_map.insert(def_id, parent_depr);
}
}
if self.tcx.features().staged_api {
- if let Some(a) = attrs.iter().find(|a| self.tcx.sess.check_name(a, sym::deprecated)) {
+ if let Some(a) = attrs.iter().find(|a| a.has_name(sym::deprecated)) {
self.tcx
.sess
.struct_span_err(a.span, "`#[deprecated]` cannot be used in staged API")
@@ -157,7 +158,7 @@
}
} else {
self.recurse_with_stability_attrs(
- depr.map(|(d, _)| DeprecationEntry::local(d, hir_id)),
+ depr.map(|(d, _)| DeprecationEntry::local(d, def_id)),
None,
None,
visit_children,
@@ -170,7 +171,7 @@
let const_stab = const_stab.map(|(const_stab, const_span_node)| {
let const_stab = self.tcx.intern_const_stability(const_stab);
- self.index.const_stab_map.insert(hir_id, const_stab);
+ self.index.const_stab_map.insert(def_id, const_stab);
const_span = Some(const_span_node);
const_stab
});
@@ -183,7 +184,7 @@
&& !fn_sig.header.is_const()
{
if !self.in_trait_impl
- || (self.in_trait_impl && !self.tcx.is_const_fn_raw(hir_id.owner.to_def_id()))
+ || (self.in_trait_impl && !self.tcx.is_const_fn_raw(def_id.to_def_id()))
{
missing_const_err(&self.tcx.sess, fn_sig.span, const_span);
}
@@ -196,7 +197,7 @@
debug!("annotate: const_stab not found, parent = {:?}", self.parent_const_stab);
if let Some(parent) = self.parent_const_stab {
if parent.level.is_unstable() {
- self.index.const_stab_map.insert(hir_id, parent);
+ self.index.const_stab_map.insert(def_id, parent);
}
}
}
@@ -271,7 +272,7 @@
}
}
- self.index.stab_map.insert(hir_id, stab);
+ self.index.stab_map.insert(def_id, stab);
stab
});
@@ -281,13 +282,13 @@
if inherit_deprecation.yes() && stab.level.is_unstable()
|| inherit_from_parent.yes()
{
- self.index.stab_map.insert(hir_id, stab);
+ self.index.stab_map.insert(def_id, stab);
}
}
}
self.recurse_with_stability_attrs(
- depr.map(|(d, _)| DeprecationEntry::local(d, hir_id)),
+ depr.map(|(d, _)| DeprecationEntry::local(d, def_id)),
stab,
if inherit_const_stability.yes() { const_stab } else { None },
visit_children,
@@ -333,7 +334,7 @@
// returns true if an error occurred, used to suppress some spurious errors
fn forbid_staged_api_attrs(
&mut self,
- hir_id: HirId,
+ def_id: LocalDefId,
attrs: &[Attribute],
inherit_deprecation: InheritDeprecation,
) -> bool {
@@ -349,7 +350,6 @@
for attr in attrs {
let name = attr.name_or_empty();
if unstable_attrs.contains(&name) {
- self.tcx.sess.mark_attr_used(attr);
struct_span_err!(
self.tcx.sess,
attr.span,
@@ -365,7 +365,7 @@
// -Zforce-unstable-if-unmarked is set.
if let Some(stab) = self.parent_stab {
if inherit_deprecation.yes() && stab.level.is_unstable() {
- self.index.stab_map.insert(hir_id, stab);
+ self.index.stab_map.insert(def_id, stab);
}
}
@@ -407,7 +407,7 @@
hir::ItemKind::Struct(ref sd, _) => {
if let Some(ctor_hir_id) = sd.ctor_hir_id() {
self.annotate(
- ctor_hir_id,
+ self.tcx.hir().local_def_id(ctor_hir_id),
i.span,
None,
AnnotationKind::Required,
@@ -425,7 +425,7 @@
}
self.annotate(
- i.hir_id(),
+ i.def_id,
i.span,
fn_sig,
kind,
@@ -444,7 +444,7 @@
};
self.annotate(
- ti.hir_id(),
+ ti.def_id,
ti.span,
fn_sig,
AnnotationKind::Required,
@@ -467,7 +467,7 @@
};
self.annotate(
- ii.hir_id(),
+ ii.def_id,
ii.span,
fn_sig,
kind,
@@ -482,7 +482,7 @@
fn visit_variant(&mut self, var: &'tcx Variant<'tcx>, g: &'tcx Generics<'tcx>, item_id: HirId) {
self.annotate(
- var.id,
+ self.tcx.hir().local_def_id(var.id),
var.span,
None,
AnnotationKind::Required,
@@ -492,7 +492,7 @@
|v| {
if let Some(ctor_hir_id) = var.data.ctor_hir_id() {
v.annotate(
- ctor_hir_id,
+ v.tcx.hir().local_def_id(ctor_hir_id),
var.span,
None,
AnnotationKind::Required,
@@ -510,7 +510,7 @@
fn visit_field_def(&mut self, s: &'tcx FieldDef<'tcx>) {
self.annotate(
- s.hir_id,
+ self.tcx.hir().local_def_id(s.hir_id),
s.span,
None,
AnnotationKind::Required,
@@ -525,7 +525,7 @@
fn visit_foreign_item(&mut self, i: &'tcx hir::ForeignItem<'tcx>) {
self.annotate(
- i.hir_id(),
+ i.def_id,
i.span,
None,
AnnotationKind::Required,
@@ -538,19 +538,6 @@
);
}
- fn visit_macro_def(&mut self, md: &'tcx hir::MacroDef<'tcx>) {
- self.annotate(
- md.hir_id(),
- md.span,
- None,
- AnnotationKind::Required,
- InheritDeprecation::Yes,
- InheritConstStability::No,
- InheritStability::No,
- |_| {},
- );
- }
-
fn visit_generic_param(&mut self, p: &'tcx hir::GenericParam<'tcx>) {
let kind = match &p.kind {
// Allow stability attributes on default generic arguments.
@@ -560,7 +547,7 @@
};
self.annotate(
- p.hir_id,
+ self.tcx.hir().local_def_id(p.hir_id),
p.span,
None,
kind,
@@ -580,22 +567,19 @@
}
impl<'tcx> MissingStabilityAnnotations<'tcx> {
- fn check_missing_stability(&self, hir_id: HirId, span: Span) {
- let stab = self.tcx.stability().local_stability(hir_id);
- let is_error =
- !self.tcx.sess.opts.test && stab.is_none() && self.access_levels.is_reachable(hir_id);
- if is_error {
- let def_id = self.tcx.hir().local_def_id(hir_id);
+ fn check_missing_stability(&self, def_id: LocalDefId, span: Span) {
+ let stab = self.tcx.stability().local_stability(def_id);
+ if !self.tcx.sess.opts.test && stab.is_none() && self.access_levels.is_reachable(def_id) {
let descr = self.tcx.def_kind(def_id).descr(def_id.to_def_id());
self.tcx.sess.span_err(span, &format!("{} has missing stability attribute", descr));
}
}
- fn check_missing_const_stability(&self, hir_id: HirId, span: Span) {
+ fn check_missing_const_stability(&self, def_id: LocalDefId, span: Span) {
let stab_map = self.tcx.stability();
- let stab = stab_map.local_stability(hir_id);
+ let stab = stab_map.local_stability(def_id);
if stab.map_or(false, |stab| stab.level.is_stable()) {
- let const_stab = stab_map.local_const_stability(hir_id);
+ let const_stab = stab_map.local_const_stability(def_id);
if const_stab.is_none() {
self.tcx.sess.span_err(
span,
@@ -624,7 +608,7 @@
hir::ItemKind::Impl(hir::Impl { of_trait: None, .. })
| hir::ItemKind::ForeignMod { .. }
) {
- self.check_missing_stability(i.hir_id(), i.span);
+ self.check_missing_stability(i.def_id, i.span);
}
// Ensure `const fn` that are `stable` have one of `rustc_const_unstable` or
@@ -632,44 +616,39 @@
if self.tcx.features().staged_api
&& matches!(&i.kind, hir::ItemKind::Fn(sig, ..) if sig.header.is_const())
{
- self.check_missing_const_stability(i.hir_id(), i.span);
+ self.check_missing_const_stability(i.def_id, i.span);
}
intravisit::walk_item(self, i)
}
fn visit_trait_item(&mut self, ti: &'tcx hir::TraitItem<'tcx>) {
- self.check_missing_stability(ti.hir_id(), ti.span);
+ self.check_missing_stability(ti.def_id, ti.span);
intravisit::walk_trait_item(self, ti);
}
fn visit_impl_item(&mut self, ii: &'tcx hir::ImplItem<'tcx>) {
let impl_def_id = self.tcx.hir().local_def_id(self.tcx.hir().get_parent_item(ii.hir_id()));
if self.tcx.impl_trait_ref(impl_def_id).is_none() {
- self.check_missing_stability(ii.hir_id(), ii.span);
+ self.check_missing_stability(ii.def_id, ii.span);
}
intravisit::walk_impl_item(self, ii);
}
fn visit_variant(&mut self, var: &'tcx Variant<'tcx>, g: &'tcx Generics<'tcx>, item_id: HirId) {
- self.check_missing_stability(var.id, var.span);
+ self.check_missing_stability(self.tcx.hir().local_def_id(var.id), var.span);
intravisit::walk_variant(self, var, g, item_id);
}
fn visit_field_def(&mut self, s: &'tcx FieldDef<'tcx>) {
- self.check_missing_stability(s.hir_id, s.span);
+ self.check_missing_stability(self.tcx.hir().local_def_id(s.hir_id), s.span);
intravisit::walk_field_def(self, s);
}
fn visit_foreign_item(&mut self, i: &'tcx hir::ForeignItem<'tcx>) {
- self.check_missing_stability(i.hir_id(), i.span);
+ self.check_missing_stability(i.def_id, i.span);
intravisit::walk_foreign_item(self, i);
}
-
- fn visit_macro_def(&mut self, md: &'tcx hir::MacroDef<'tcx>) {
- self.check_missing_stability(md.hir_id(), md.span);
- }
-
// Note that we don't need to `check_missing_stability` for default generic parameters,
// as we assume that any default generic parameters without attributes are automatically
// stable (assuming they have not inherited instability from their parent).
@@ -731,8 +710,8 @@
}
annotator.annotate(
- hir::CRATE_HIR_ID,
- krate.item.inner,
+ CRATE_DEF_ID,
+ krate.module().inner,
None,
AnnotationKind::Required,
InheritDeprecation::Yes,
@@ -929,7 +908,7 @@
if tcx.stability().staged_api[&LOCAL_CRATE] {
let krate = tcx.hir().krate();
let mut missing = MissingStabilityAnnotations { tcx, access_levels };
- missing.check_missing_stability(hir::CRATE_HIR_ID, krate.item.inner);
+ missing.check_missing_stability(CRATE_DEF_ID, krate.module().inner);
intravisit::walk_crate(&mut missing, krate);
krate.visit_all_item_likes(&mut missing.as_deep_visitor());
}
diff --git a/compiler/rustc_passes/src/weak_lang_items.rs b/compiler/rustc_passes/src/weak_lang_items.rs
index 629513c..3a662a9 100644
--- a/compiler/rustc_passes/src/weak_lang_items.rs
+++ b/compiler/rustc_passes/src/weak_lang_items.rs
@@ -1,5 +1,6 @@
//! Validity checking for weak lang items
+use rustc_ast::Attribute;
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::struct_span_err;
use rustc_hir as hir;
@@ -96,7 +97,7 @@
}
fn visit_foreign_item(&mut self, i: &hir::ForeignItem<'_>) {
- let check_name = |attr, sym| self.tcx.sess.check_name(attr, sym);
+ let check_name = |attr: &Attribute, sym| attr.has_name(sym);
let attrs = self.tcx.hir().attrs(i.hir_id());
if let Some((lang_item, _)) = lang_items::extract(check_name, attrs) {
self.register(lang_item, i.span);
diff --git a/compiler/rustc_plugin_impl/Cargo.toml b/compiler/rustc_plugin_impl/Cargo.toml
index 500d13a..c8eaca0 100644
--- a/compiler/rustc_plugin_impl/Cargo.toml
+++ b/compiler/rustc_plugin_impl/Cargo.toml
@@ -1,5 +1,4 @@
[package]
-authors = ["The Rust Project Developers"]
name = "rustc_plugin_impl"
version = "0.0.0"
build = false
diff --git a/compiler/rustc_plugin_impl/src/build.rs b/compiler/rustc_plugin_impl/src/build.rs
deleted file mode 100644
index b95c4a7..0000000
--- a/compiler/rustc_plugin_impl/src/build.rs
+++ /dev/null
@@ -1,57 +0,0 @@
-//! Used by `rustc` when compiling a plugin crate.
-
-use rustc_hir as hir;
-use rustc_hir::def_id::LocalDefId;
-use rustc_hir::itemlikevisit::ItemLikeVisitor;
-use rustc_middle::ty::query::Providers;
-use rustc_middle::ty::TyCtxt;
-use rustc_span::symbol::sym;
-use rustc_span::Span;
-
-struct RegistrarFinder<'tcx> {
- tcx: TyCtxt<'tcx>,
- registrars: Vec<(LocalDefId, Span)>,
-}
-
-impl<'v, 'tcx> ItemLikeVisitor<'v> for RegistrarFinder<'tcx> {
- fn visit_item(&mut self, item: &hir::Item<'_>) {
- if let hir::ItemKind::Fn(..) = item.kind {
- let attrs = self.tcx.hir().attrs(item.hir_id());
- if self.tcx.sess.contains_name(attrs, sym::plugin_registrar) {
- self.registrars.push((item.def_id, item.span));
- }
- }
- }
-
- fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem<'_>) {}
-
- fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem<'_>) {}
-
- fn visit_foreign_item(&mut self, _foreign_item: &hir::ForeignItem<'_>) {}
-}
-
-/// Finds the function marked with `#[plugin_registrar]`, if any.
-fn plugin_registrar_fn(tcx: TyCtxt<'_>, (): ()) -> Option<LocalDefId> {
- let mut finder = RegistrarFinder { tcx, registrars: Vec::new() };
- tcx.hir().krate().visit_all_item_likes(&mut finder);
-
- let (def_id, span) = finder.registrars.pop()?;
-
- if !finder.registrars.is_empty() {
- let diagnostic = tcx.sess.diagnostic();
- let mut e = diagnostic.struct_err("multiple plugin registration functions found");
- e.span_note(span, "one is here");
- for &(_, span) in &finder.registrars {
- e.span_note(span, "one is here");
- }
- e.emit();
- diagnostic.abort_if_errors();
- unreachable!();
- }
-
- Some(def_id)
-}
-
-pub fn provide(providers: &mut Providers) {
- *providers = Providers { plugin_registrar_fn, ..*providers };
-}
diff --git a/compiler/rustc_plugin_impl/src/lib.rs b/compiler/rustc_plugin_impl/src/lib.rs
index 5bf4d30..a1e13a1 100644
--- a/compiler/rustc_plugin_impl/src/lib.rs
+++ b/compiler/rustc_plugin_impl/src/lib.rs
@@ -12,7 +12,6 @@
use rustc_lint::LintStore;
-pub mod build;
pub mod load;
/// Structure used to register plugins.
diff --git a/compiler/rustc_plugin_impl/src/load.rs b/compiler/rustc_plugin_impl/src/load.rs
index 687f7db..51cf85f 100644
--- a/compiler/rustc_plugin_impl/src/load.rs
+++ b/compiler/rustc_plugin_impl/src/load.rs
@@ -32,7 +32,7 @@
let mut plugins = Vec::new();
for attr in &krate.attrs {
- if !sess.check_name(attr, sym::plugin) {
+ if !attr.has_name(sym::plugin) {
continue;
}
@@ -55,20 +55,13 @@
metadata_loader: &dyn MetadataLoader,
ident: Ident,
) {
- let (lib, disambiguator) =
- locator::find_plugin_registrar(sess, metadata_loader, ident.span, ident.name);
- let symbol = sess.generate_plugin_registrar_symbol(disambiguator);
- let fun = dylink_registrar(sess, ident.span, lib, symbol);
+ let lib = locator::find_plugin_registrar(sess, metadata_loader, ident.span, ident.name);
+ let fun = dylink_registrar(sess, ident.span, lib);
plugins.push(fun);
}
// Dynamically link a registrar function into the compiler process.
-fn dylink_registrar(
- sess: &Session,
- span: Span,
- path: PathBuf,
- symbol: String,
-) -> PluginRegistrarFn {
+fn dylink_registrar(sess: &Session, span: Span, path: PathBuf) -> PluginRegistrarFn {
use rustc_metadata::dynamic_lib::DynamicLibrary;
// Make sure the path contains a / or the linker will search for it.
@@ -83,7 +76,7 @@
};
unsafe {
- let registrar = match lib.symbol(&symbol) {
+ let registrar = match lib.symbol("__rustc_plugin_registrar") {
Ok(registrar) => mem::transmute::<*mut u8, PluginRegistrarFn>(registrar),
// again fatal if we can't register macros
Err(err) => sess.span_fatal(span, &err),
@@ -91,7 +84,7 @@
// Intentionally leak the dynamic library. We can't ever unload it
// since the library can make things that will live arbitrarily long
- // (e.g., an @-box cycle or a thread).
+ // (e.g., an Rc cycle or a thread).
mem::forget(lib);
registrar
diff --git a/compiler/rustc_privacy/Cargo.toml b/compiler/rustc_privacy/Cargo.toml
index 85e584d..6ac2915 100644
--- a/compiler/rustc_privacy/Cargo.toml
+++ b/compiler/rustc_privacy/Cargo.toml
@@ -1,11 +1,11 @@
[package]
-authors = ["The Rust Project Developers"]
name = "rustc_privacy"
version = "0.0.0"
edition = "2018"
[dependencies]
rustc_middle = { path = "../rustc_middle" }
+rustc_ast = { path = "../rustc_ast" }
rustc_attr = { path = "../rustc_attr" }
rustc_errors = { path = "../rustc_errors" }
rustc_hir = { path = "../rustc_hir" }
diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs
index d969f50..9c376c6 100644
--- a/compiler/rustc_privacy/src/lib.rs
+++ b/compiler/rustc_privacy/src/lib.rs
@@ -6,12 +6,14 @@
#![feature(associated_type_defaults)]
#![recursion_limit = "256"]
+use rustc_ast::MacroDef;
use rustc_attr as attr;
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::struct_span_err;
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
-use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_INDEX, LOCAL_CRATE};
+use rustc_hir::def_id::{DefId, LocalDefId, LocalDefIdSet};
+use rustc_hir::def_id::{CRATE_DEF_ID, CRATE_DEF_INDEX, LOCAL_CRATE};
use rustc_hir::intravisit::{self, DeepVisitor, NestedVisitorMap, Visitor};
use rustc_hir::{AssocItemKind, HirIdSet, Node, PatKind};
use rustc_middle::bug;
@@ -25,7 +27,7 @@
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::symbol::{kw, sym, Ident};
use rustc_span::Span;
use rustc_trait_selection::traits::const_evaluatable::{self, AbstractConst};
@@ -122,7 +124,7 @@
fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ControlFlow<V::BreakTy> {
match predicate.kind().skip_binder() {
- ty::PredicateKind::Trait(ty::TraitPredicate { trait_ref }, _) => {
+ ty::PredicateKind::Trait(ty::TraitPredicate { trait_ref, constness: _ }) => {
self.visit_trait(trait_ref)
}
ty::PredicateKind::Projection(ty::ProjectionPredicate { projection_ty, ty }) => {
@@ -133,11 +135,11 @@
ty.visit_with(self)
}
ty::PredicateKind::RegionOutlives(..) => ControlFlow::CONTINUE,
- ty::PredicateKind::ConstEvaluatable(defs, substs)
- if self.def_id_visitor.tcx().features().const_evaluatable_checked =>
+ ty::PredicateKind::ConstEvaluatable(uv)
+ if self.def_id_visitor.tcx().features().generic_const_exprs =>
{
let tcx = self.def_id_visitor.tcx();
- if let Ok(Some(ct)) = AbstractConst::new(tcx, defs, substs) {
+ if let Ok(Some(ct)) = AbstractConst::new(tcx, uv) {
self.visit_abstract_const_expr(tcx, ct)?;
}
ControlFlow::CONTINUE
@@ -178,6 +180,10 @@
{
type BreakTy = V::BreakTy;
+ fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
+ Some(self.def_id_visitor.tcx())
+ }
+
fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<V::BreakTy> {
let tcx = self.def_id_visitor.tcx();
// InternalSubsts are not visited here because they are visited below in `super_visit_with`.
@@ -354,9 +360,8 @@
// Returns an over-approximation (`skip_assoc_tys` = true) of visibility due to
// associated types for which we can't determine visibility precisely.
- fn of_impl(hir_id: hir::HirId, tcx: TyCtxt<'_>, access_levels: &AccessLevels) -> Self {
+ fn of_impl(def_id: LocalDefId, tcx: TyCtxt<'_>, access_levels: &AccessLevels) -> Self {
let mut find = FindMin { tcx, access_levels, min: Self::MAX };
- let def_id = tcx.hir().local_def_id(hir_id);
find.visit(tcx.type_of(def_id));
if let Some(trait_ref) = tcx.impl_trait_ref(def_id) {
find.visit_trait(trait_ref);
@@ -385,8 +390,7 @@
fn new_min(find: &FindMin<'_, '_, Self>, def_id: DefId) -> Self {
cmp::min(
if let Some(def_id) = def_id.as_local() {
- let hir_id = find.tcx.hir().local_def_id_to_hir_id(def_id);
- find.access_levels.map.get(&hir_id).cloned()
+ find.access_levels.map.get(&def_id).copied()
} else {
Self::MAX
},
@@ -416,7 +420,7 @@
/// pub macro m() {
/// n::p::f()
/// }
- macro_reachable: FxHashSet<(hir::HirId, DefId)>,
+ macro_reachable: FxHashSet<(LocalDefId, LocalDefId)>,
/// Previous accessibility level; `None` means unreachable.
prev_level: Option<AccessLevel>,
/// Has something changed in the level map?
@@ -425,21 +429,21 @@
struct ReachEverythingInTheInterfaceVisitor<'a, 'tcx> {
access_level: Option<AccessLevel>,
- item_def_id: DefId,
+ item_def_id: LocalDefId,
ev: &'a mut EmbargoVisitor<'tcx>,
}
impl EmbargoVisitor<'tcx> {
- fn get(&self, id: hir::HirId) -> Option<AccessLevel> {
- self.access_levels.map.get(&id).cloned()
+ fn get(&self, def_id: LocalDefId) -> Option<AccessLevel> {
+ self.access_levels.map.get(&def_id).copied()
}
/// Updates node level and returns the updated level.
- fn update(&mut self, id: hir::HirId, level: Option<AccessLevel>) -> Option<AccessLevel> {
- let old_level = self.get(id);
+ fn update(&mut self, def_id: LocalDefId, level: Option<AccessLevel>) -> Option<AccessLevel> {
+ let old_level = self.get(def_id);
// Accessibility levels can only grow.
if level > old_level {
- self.access_levels.map.insert(id, level.unwrap());
+ self.access_levels.map.insert(def_id, level.unwrap());
self.changed = true;
level
} else {
@@ -449,43 +453,82 @@
fn reach(
&mut self,
- item_id: hir::HirId,
+ def_id: LocalDefId,
access_level: Option<AccessLevel>,
) -> ReachEverythingInTheInterfaceVisitor<'_, 'tcx> {
ReachEverythingInTheInterfaceVisitor {
access_level: cmp::min(access_level, Some(AccessLevel::Reachable)),
- item_def_id: self.tcx.hir().local_def_id(item_id).to_def_id(),
+ item_def_id: def_id,
ev: self,
}
}
+ // We have to make sure that the items that macros might reference
+ // are reachable, since they might be exported transitively.
+ fn update_reachability_from_macro(&mut self, local_def_id: LocalDefId, md: &MacroDef) {
+ // Non-opaque macros cannot make other items more accessible than they already are.
+
+ let hir_id = self.tcx.hir().local_def_id_to_hir_id(local_def_id);
+ let attrs = self.tcx.hir().attrs(hir_id);
+ if attr::find_transparency(&attrs, md.macro_rules).0 != Transparency::Opaque {
+ return;
+ }
+
+ let item_def_id = local_def_id.to_def_id();
+ let macro_module_def_id =
+ ty::DefIdTree::parent(self.tcx, item_def_id).unwrap().expect_local();
+ if self.tcx.hir().opt_def_kind(macro_module_def_id) != Some(DefKind::Mod) {
+ // The macro's parent doesn't correspond to a `mod`, return early (#63164, #65252).
+ return;
+ }
+
+ if self.get(local_def_id).is_none() {
+ return;
+ }
+
+ // Since we are starting from an externally visible module,
+ // all the parents in the loop below are also guaranteed to be modules.
+ let mut module_def_id = macro_module_def_id;
+ loop {
+ let changed_reachability =
+ self.update_macro_reachable(module_def_id, macro_module_def_id);
+ if changed_reachability || module_def_id == CRATE_DEF_ID {
+ break;
+ }
+ module_def_id =
+ ty::DefIdTree::parent(self.tcx, module_def_id.to_def_id()).unwrap().expect_local();
+ }
+ }
+
/// Updates the item as being reachable through a macro defined in the given
/// module. Returns `true` if the level has changed.
- fn update_macro_reachable(&mut self, reachable_mod: hir::HirId, defining_mod: DefId) -> bool {
- if self.macro_reachable.insert((reachable_mod, defining_mod)) {
- self.update_macro_reachable_mod(reachable_mod, defining_mod);
+ fn update_macro_reachable(
+ &mut self,
+ module_def_id: LocalDefId,
+ defining_mod: LocalDefId,
+ ) -> bool {
+ if self.macro_reachable.insert((module_def_id, defining_mod)) {
+ self.update_macro_reachable_mod(module_def_id, defining_mod);
true
} else {
false
}
}
- fn update_macro_reachable_mod(&mut self, reachable_mod: hir::HirId, defining_mod: DefId) {
- let module_def_id = self.tcx.hir().local_def_id(reachable_mod);
+ fn update_macro_reachable_mod(&mut self, module_def_id: LocalDefId, defining_mod: LocalDefId) {
let module = self.tcx.hir().get_module(module_def_id).0;
for item_id in module.item_ids {
let def_kind = self.tcx.def_kind(item_id.def_id);
let vis = self.tcx.visibility(item_id.def_id);
- self.update_macro_reachable_def(item_id.hir_id(), def_kind, vis, defining_mod);
+ self.update_macro_reachable_def(item_id.def_id, def_kind, vis, defining_mod);
}
if let Some(exports) = self.tcx.module_exports(module_def_id) {
for export in exports {
- if export.vis.is_accessible_from(defining_mod, self.tcx) {
+ if export.vis.is_accessible_from(defining_mod.to_def_id(), self.tcx) {
if let Res::Def(def_kind, def_id) = export.res {
if let Some(def_id) = def_id.as_local() {
- let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id);
let vis = self.tcx.visibility(def_id.to_def_id());
- self.update_macro_reachable_def(hir_id, def_kind, vis, defining_mod);
+ self.update_macro_reachable_def(def_id, def_kind, vis, defining_mod);
}
}
}
@@ -495,24 +538,34 @@
fn update_macro_reachable_def(
&mut self,
- hir_id: hir::HirId,
+ def_id: LocalDefId,
def_kind: DefKind,
vis: ty::Visibility,
- module: DefId,
+ module: LocalDefId,
) {
let level = Some(AccessLevel::Reachable);
if let ty::Visibility::Public = vis {
- self.update(hir_id, level);
+ self.update(def_id, level);
}
match def_kind {
// No type privacy, so can be directly marked as reachable.
- DefKind::Const
- | DefKind::Macro(_)
- | DefKind::Static
- | DefKind::TraitAlias
- | DefKind::TyAlias => {
- if vis.is_accessible_from(module, self.tcx) {
- self.update(hir_id, level);
+ DefKind::Const | DefKind::Static | DefKind::TraitAlias | DefKind::TyAlias => {
+ if vis.is_accessible_from(module.to_def_id(), self.tcx) {
+ self.update(def_id, level);
+ }
+ }
+
+ // Hygine isn't really implemented for `macro_rules!` macros at the
+ // moment. Accordingly, marking them as reachable is unwise. `macro` macros
+ // have normal hygine, so we can treat them like other items without type
+ // privacy and mark them reachable.
+ DefKind::Macro(_) => {
+ let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id);
+ let item = self.tcx.hir().expect_item(hir_id);
+ if let hir::ItemKind::Macro(MacroDef { macro_rules: false, .. }) = item.kind {
+ if vis.is_accessible_from(module.to_def_id(), self.tcx) {
+ self.update(def_id, level);
+ }
}
}
@@ -521,24 +574,24 @@
// hygiene these don't need to be marked reachable. The contents of
// the module, however may be reachable.
DefKind::Mod => {
- if vis.is_accessible_from(module, self.tcx) {
- self.update_macro_reachable(hir_id, module);
+ if vis.is_accessible_from(module.to_def_id(), self.tcx) {
+ self.update_macro_reachable(def_id, module);
}
}
DefKind::Struct | DefKind::Union => {
- // While structs and unions have type privacy, their fields do
- // not.
+ // While structs and unions have type privacy, their fields do not.
if let ty::Visibility::Public = vis {
- let item = self.tcx.hir().expect_item(hir_id);
+ let item =
+ self.tcx.hir().expect_item(self.tcx.hir().local_def_id_to_hir_id(def_id));
if let hir::ItemKind::Struct(ref struct_def, _)
| hir::ItemKind::Union(ref struct_def, _) = item.kind
{
for field in struct_def.fields() {
- let field_vis =
- self.tcx.visibility(self.tcx.hir().local_def_id(field.hir_id));
- if field_vis.is_accessible_from(module, self.tcx) {
- self.reach(field.hir_id, level).ty();
+ let def_id = self.tcx.hir().local_def_id(field.hir_id);
+ let field_vis = self.tcx.visibility(def_id);
+ if field_vis.is_accessible_from(module.to_def_id(), self.tcx) {
+ self.reach(def_id, level).ty();
}
}
} else {
@@ -574,7 +627,7 @@
}
}
- /// Given the path segments of a `ItemKind::Use`, then we need
+ /// Given the path segments of an `ItemKind::Use`, then we need
/// to update the visibility of the intermediate use so that it isn't linted
/// by `unreachable_pub`.
///
@@ -616,7 +669,7 @@
continue;
}
if let hir::ItemKind::Use(..) = item.kind {
- self.update(item.hir_id(), Some(AccessLevel::Exported));
+ self.update(item.def_id, Some(AccessLevel::Exported));
}
}
}
@@ -637,7 +690,13 @@
fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
let inherited_item_level = match item.kind {
hir::ItemKind::Impl { .. } => {
- Option::<AccessLevel>::of_impl(item.hir_id(), self.tcx, &self.access_levels)
+ Option::<AccessLevel>::of_impl(item.def_id, self.tcx, &self.access_levels)
+ }
+ // Only exported `macro_rules!` items are public, but they always are.
+ hir::ItemKind::Macro(MacroDef { macro_rules: true, .. }) => {
+ let def_id = item.def_id.to_def_id();
+ let is_macro_export = self.tcx.has_attr(def_id, sym::macro_export);
+ if is_macro_export { Some(AccessLevel::Public) } else { None }
}
// Foreign modules inherit level from parents.
hir::ItemKind::ForeignMod { .. } => self.prev_level,
@@ -647,6 +706,7 @@
| hir::ItemKind::ExternCrate(..)
| hir::ItemKind::GlobalAsm(..)
| hir::ItemKind::Fn(..)
+ | hir::ItemKind::Macro(..)
| hir::ItemKind::Mod(..)
| hir::ItemKind::Static(..)
| hir::ItemKind::Struct(..)
@@ -665,50 +725,55 @@
};
// Update level of the item itself.
- let item_level = self.update(item.hir_id(), inherited_item_level);
+ let item_level = self.update(item.def_id, inherited_item_level);
// Update levels of nested things.
match item.kind {
hir::ItemKind::Enum(ref def, _) => {
for variant in def.variants {
- let variant_level = self.update(variant.id, item_level);
+ let variant_level =
+ self.update(self.tcx.hir().local_def_id(variant.id), item_level);
if let Some(ctor_hir_id) = variant.data.ctor_hir_id() {
- self.update(ctor_hir_id, item_level);
+ self.update(self.tcx.hir().local_def_id(ctor_hir_id), item_level);
}
for field in variant.data.fields() {
- self.update(field.hir_id, variant_level);
+ self.update(self.tcx.hir().local_def_id(field.hir_id), variant_level);
}
}
}
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);
+ self.update(impl_item_ref.id.def_id, item_level);
}
}
}
hir::ItemKind::Trait(.., trait_item_refs) => {
for trait_item_ref in trait_item_refs {
- self.update(trait_item_ref.id.hir_id(), item_level);
+ self.update(trait_item_ref.id.def_id, item_level);
}
}
hir::ItemKind::Struct(ref def, _) | hir::ItemKind::Union(ref def, _) => {
if let Some(ctor_hir_id) = def.ctor_hir_id() {
- self.update(ctor_hir_id, item_level);
+ self.update(self.tcx.hir().local_def_id(ctor_hir_id), item_level);
}
for field in def.fields() {
if field.vis.node.is_pub() {
- self.update(field.hir_id, item_level);
+ self.update(self.tcx.hir().local_def_id(field.hir_id), item_level);
}
}
}
+ hir::ItemKind::Macro(ref macro_def) => {
+ self.update_reachability_from_macro(item.def_id, macro_def);
+ }
hir::ItemKind::ForeignMod { items, .. } => {
for foreign_item in items {
if foreign_item.vis.node.is_pub() {
- self.update(foreign_item.id.hir_id(), item_level);
+ self.update(foreign_item.id.def_id, item_level);
}
}
}
+
hir::ItemKind::OpaqueTy(..)
| hir::ItemKind::Use(..)
| hir::ItemKind::Static(..)
@@ -724,7 +789,7 @@
// Mark all items in interfaces of reachable items as reachable.
match item.kind {
// The interface is empty.
- hir::ItemKind::ExternCrate(..) => {}
+ hir::ItemKind::Macro(..) | hir::ItemKind::ExternCrate(..) => {}
// All nested items are checked by `visit_item`.
hir::ItemKind::Mod(..) => {}
// Re-exports are handled in `visit_mod`. However, in order to avoid looping over
@@ -748,7 +813,7 @@
// reachable if they are returned via `impl Trait`, even from private functions.
let exist_level =
cmp::max(item_level, Some(AccessLevel::ReachableFromImplTrait));
- self.reach(item.hir_id(), exist_level).generics().predicates().ty();
+ self.reach(item.def_id, exist_level).generics().predicates().ty();
}
}
// Visit everything.
@@ -757,15 +822,15 @@
| hir::ItemKind::Fn(..)
| hir::ItemKind::TyAlias(..) => {
if item_level.is_some() {
- self.reach(item.hir_id(), item_level).generics().predicates().ty();
+ self.reach(item.def_id, item_level).generics().predicates().ty();
}
}
hir::ItemKind::Trait(.., trait_item_refs) => {
if item_level.is_some() {
- self.reach(item.hir_id(), item_level).generics().predicates();
+ self.reach(item.def_id, item_level).generics().predicates();
for trait_item_ref in trait_item_refs {
- let mut reach = self.reach(trait_item_ref.id.hir_id(), item_level);
+ let mut reach = self.reach(trait_item_ref.id.def_id, item_level);
reach.generics().predicates();
if trait_item_ref.kind == AssocItemKind::Type
@@ -780,18 +845,18 @@
}
hir::ItemKind::TraitAlias(..) => {
if item_level.is_some() {
- self.reach(item.hir_id(), item_level).generics().predicates();
+ self.reach(item.def_id, item_level).generics().predicates();
}
}
// Visit everything except for private impl items.
hir::ItemKind::Impl(ref impl_) => {
if item_level.is_some() {
- self.reach(item.hir_id(), item_level).generics().predicates().ty().trait_ref();
+ self.reach(item.def_id, item_level).generics().predicates().ty().trait_ref();
for impl_item_ref in impl_.items {
- let impl_item_level = self.get(impl_item_ref.id.hir_id());
+ let impl_item_level = self.get(impl_item_ref.id.def_id);
if impl_item_level.is_some() {
- self.reach(impl_item_ref.id.hir_id(), impl_item_level)
+ self.reach(impl_item_ref.id.def_id, impl_item_level)
.generics()
.predicates()
.ty();
@@ -803,26 +868,27 @@
// Visit everything, but enum variants have their own levels.
hir::ItemKind::Enum(ref def, _) => {
if item_level.is_some() {
- self.reach(item.hir_id(), item_level).generics().predicates();
+ self.reach(item.def_id, item_level).generics().predicates();
}
for variant in def.variants {
- let variant_level = self.get(variant.id);
+ let variant_level = self.get(self.tcx.hir().local_def_id(variant.id));
if variant_level.is_some() {
for field in variant.data.fields() {
- self.reach(field.hir_id, variant_level).ty();
+ self.reach(self.tcx.hir().local_def_id(field.hir_id), variant_level)
+ .ty();
}
// Corner case: if the variant is reachable, but its
// enum is not, make the enum reachable as well.
- self.update(item.hir_id(), variant_level);
+ self.update(item.def_id, variant_level);
}
}
}
// Visit everything, but foreign items have their own levels.
hir::ItemKind::ForeignMod { items, .. } => {
for foreign_item in items {
- let foreign_item_level = self.get(foreign_item.id.hir_id());
+ let foreign_item_level = self.get(foreign_item.id.def_id);
if foreign_item_level.is_some() {
- self.reach(foreign_item.id.hir_id(), foreign_item_level)
+ self.reach(foreign_item.id.def_id, foreign_item_level)
.generics()
.predicates()
.ty();
@@ -832,11 +898,12 @@
// Visit everything except for private fields.
hir::ItemKind::Struct(ref struct_def, _) | hir::ItemKind::Union(ref struct_def, _) => {
if item_level.is_some() {
- self.reach(item.hir_id(), item_level).generics().predicates();
+ self.reach(item.def_id, item_level).generics().predicates();
for field in struct_def.fields() {
- let field_level = self.get(field.hir_id);
+ let def_id = self.tcx.hir().local_def_id(field.hir_id);
+ let field_level = self.get(def_id);
if field_level.is_some() {
- self.reach(field.hir_id, field_level).ty();
+ self.reach(def_id, field_level).ty();
}
}
}
@@ -867,8 +934,7 @@
if export.vis == ty::Visibility::Public {
if let Some(def_id) = export.res.opt_def_id() {
if let Some(def_id) = def_id.as_local() {
- let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id);
- self.update(hir_id, Some(AccessLevel::Exported));
+ self.update(def_id, Some(AccessLevel::Exported));
}
}
}
@@ -878,44 +944,6 @@
intravisit::walk_mod(self, m, id);
}
-
- fn visit_macro_def(&mut self, md: &'tcx hir::MacroDef<'tcx>) {
- // Non-opaque macros cannot make other items more accessible than they already are.
- let attrs = self.tcx.hir().attrs(md.hir_id());
- if attr::find_transparency(&self.tcx.sess, &attrs, md.ast.macro_rules).0
- != Transparency::Opaque
- {
- // `#[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, md.def_id.to_def_id()).unwrap();
- let hir_id = macro_module_def_id
- .as_local()
- .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).
- _ => return,
- };
- let level = if md.vis.node.is_pub() { self.get(module_id) } else { None };
- let new_level = self.update(md.hir_id(), level);
- if new_level.is_none() {
- return;
- }
-
- loop {
- let changed_reachability = self.update_macro_reachable(module_id, macro_module_def_id);
- if changed_reachability || module_id == hir::CRATE_HIR_ID {
- break;
- }
- module_id = self.tcx.hir().get_parent_node(module_id);
- }
- }
}
impl ReachEverythingInTheInterfaceVisitor<'_, 'tcx> {
@@ -971,8 +999,7 @@
if let (ty::Visibility::Public, _) | (_, Some(AccessLevel::ReachableFromImplTrait)) =
(self.tcx().visibility(def_id.to_def_id()), self.access_level)
{
- let hir_id = self.ev.tcx.hir().local_def_id_to_hir_id(def_id);
- self.ev.update(hir_id, self.access_level);
+ self.ev.update(def_id, self.access_level);
}
}
ControlFlow::CONTINUE
@@ -989,7 +1016,7 @@
struct NamePrivacyVisitor<'tcx> {
tcx: TyCtxt<'tcx>,
maybe_typeck_results: Option<&'tcx ty::TypeckResults<'tcx>>,
- current_item: Option<hir::HirId>,
+ current_item: LocalDefId,
}
impl<'tcx> NamePrivacyVisitor<'tcx> {
@@ -1011,11 +1038,15 @@
field: &'tcx ty::FieldDef,
in_update_syntax: bool,
) {
+ if def.is_enum() {
+ return;
+ }
+
// definition of the field
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) {
+ let hir_id = self.tcx.hir().local_def_id_to_hir_id(self.current_item);
+ let def_id = self.tcx.adjust_ident_and_get_scope(ident, def.did, hir_id).1;
+ if !field.vis.is_accessible_from(def_id, self.tcx) {
let label = if in_update_syntax {
format!("field `{}` is private", field.ident)
} else {
@@ -1060,7 +1091,7 @@
}
fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
- let orig_current_item = self.current_item.replace(item.hir_id());
+ let orig_current_item = mem::replace(&mut self.current_item, item.def_id);
intravisit::walk_item(self, item);
self.current_item = orig_current_item;
}
@@ -1188,6 +1219,14 @@
self.maybe_typeck_results = old_maybe_typeck_results;
}
+ fn visit_generic_arg(&mut self, generic_arg: &'tcx hir::GenericArg<'tcx>) {
+ match generic_arg {
+ hir::GenericArg::Type(t) => self.visit_ty(t),
+ hir::GenericArg::Infer(inf) => self.visit_infer(inf),
+ hir::GenericArg::Lifetime(_) | hir::GenericArg::Const(_) => {}
+ }
+ }
+
fn visit_ty(&mut self, hir_ty: &'tcx hir::Ty<'tcx>) {
self.span = hir_ty.span;
if let Some(typeck_results) = self.maybe_typeck_results {
@@ -1207,6 +1246,30 @@
intravisit::walk_ty(self, hir_ty);
}
+ fn visit_infer(&mut self, inf: &'tcx hir::InferArg) {
+ self.span = inf.span;
+ if let Some(typeck_results) = self.maybe_typeck_results {
+ if let Some(ty) = typeck_results.node_type_opt(inf.hir_id) {
+ if self.visit(ty).is_break() {
+ return;
+ }
+ }
+ } else {
+ let local_id = self.tcx.hir().local_def_id(inf.hir_id);
+ if let Some(did) = self.tcx.opt_const_param_of(local_id) {
+ if self.visit_def_id(did, "inferred", &"").is_break() {
+ return;
+ }
+ }
+
+ // FIXME see above note for same issue.
+ if self.visit(rustc_typeck::hir_ty_to_ty(self.tcx, &inf.to_ty())).is_break() {
+ return;
+ }
+ }
+ intravisit::walk_inf(self, inf);
+ }
+
fn visit_trait_ref(&mut self, trait_ref: &'tcx hir::TraitRef<'tcx>) {
self.span = trait_ref.path.span;
if self.maybe_typeck_results.is_none() {
@@ -1417,7 +1480,7 @@
}
}
- fn trait_is_public(&self, trait_id: hir::HirId) -> bool {
+ fn trait_is_public(&self, trait_id: LocalDefId) -> bool {
// FIXME: this would preferably be using `exported_items`, but all
// traits are exported currently (see `EmbargoVisitor.exported_trait`).
self.access_levels.is_public(trait_id)
@@ -1431,8 +1494,8 @@
}
}
- fn item_is_public(&self, id: &hir::HirId, vis: &hir::Visibility<'_>) -> bool {
- self.access_levels.is_reachable(*id) || vis.node.is_pub()
+ fn item_is_public(&self, def_id: LocalDefId, vis: &hir::Visibility<'_>) -> bool {
+ self.access_levels.is_reachable(def_id) || vis.node.is_pub()
}
}
@@ -1443,6 +1506,14 @@
NestedVisitorMap::None
}
+ fn visit_generic_arg(&mut self, generic_arg: &'v hir::GenericArg<'v>) {
+ match generic_arg {
+ hir::GenericArg::Type(t) => self.visit_ty(t),
+ hir::GenericArg::Infer(inf) => self.visit_ty(&inf.to_ty()),
+ hir::GenericArg::Lifetime(_) | hir::GenericArg::Const(_) => {}
+ }
+ }
+
fn visit_ty(&mut self, ty: &hir::Ty<'_>) {
if let hir::TyKind::Path(hir::QPath::Resolved(_, ref path)) = ty.kind {
if self.inner.path_is_private_type(path) {
@@ -1484,7 +1555,7 @@
hir::ItemKind::ForeignMod { .. } => {}
hir::ItemKind::Trait(.., ref bounds, _) => {
- if !self.trait_is_public(item.hir_id()) {
+ if !self.trait_is_public(item.def_id) {
return;
}
@@ -1524,10 +1595,8 @@
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();
-
- if let Some(did) = did.as_local() {
- self.trait_is_public(self.tcx.hir().local_def_id_to_hir_id(did))
+ if let Some(def_id) = tr.path.res.def_id().as_local() {
+ self.trait_is_public(def_id)
} else {
true // external traits must be public
}
@@ -1547,7 +1616,7 @@
let impl_item = self.tcx.hir().impl_item(impl_item_ref.id);
match impl_item.kind {
hir::ImplItemKind::Const(..) | hir::ImplItemKind::Fn(..) => {
- self.access_levels.is_reachable(impl_item_ref.id.hir_id())
+ self.access_levels.is_reachable(impl_item_ref.id.def_id)
}
hir::ImplItemKind::TyAlias(_) => false,
}
@@ -1567,10 +1636,8 @@
let impl_item = self.tcx.hir().impl_item(impl_item_ref.id);
match impl_item.kind {
hir::ImplItemKind::Const(..) | hir::ImplItemKind::Fn(..)
- if self.item_is_public(
- &impl_item.hir_id(),
- &impl_item.vis,
- ) =>
+ if self
+ .item_is_public(impl_item.def_id, &impl_item.vis) =>
{
intravisit::walk_impl_item(self, impl_item)
}
@@ -1611,7 +1678,7 @@
// methods will be visible as `Public::foo`.
let mut found_pub_static = false;
for impl_item_ref in impl_.items {
- if self.item_is_public(&impl_item_ref.id.hir_id(), &impl_item_ref.vis) {
+ if self.item_is_public(impl_item_ref.id.def_id, &impl_item_ref.vis) {
let impl_item = self.tcx.hir().impl_item(impl_item_ref.id);
match impl_item_ref.kind {
AssocItemKind::Const => {
@@ -1638,7 +1705,7 @@
hir::ItemKind::TyAlias(..) => return,
// Not at all public, so we don't care.
- _ if !self.item_is_public(&item.hir_id(), &item.vis) => {
+ _ if !self.item_is_public(item.def_id, &item.vis) => {
return;
}
@@ -1674,7 +1741,7 @@
}
fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem<'tcx>) {
- if self.access_levels.is_reachable(item.hir_id()) {
+ if self.access_levels.is_reachable(item.def_id) {
intravisit::walk_foreign_item(self, item)
}
}
@@ -1694,7 +1761,7 @@
g: &'tcx hir::Generics<'tcx>,
item_id: hir::HirId,
) {
- if self.access_levels.is_reachable(v.id) {
+ if self.access_levels.is_reachable(self.tcx.hir().local_def_id(v.id)) {
self.in_variant = true;
intravisit::walk_variant(self, v, g, item_id);
self.in_variant = false;
@@ -1724,9 +1791,7 @@
struct SearchInterfaceForPrivateItemsVisitor<'tcx> {
tcx: TyCtxt<'tcx>,
- item_id: hir::HirId,
- item_def_id: DefId,
- span: Span,
+ item_def_id: LocalDefId,
/// The visitor checks that each component type is at least this visible.
required_visibility: ty::Visibility,
has_pub_restricted: bool,
@@ -1744,7 +1809,7 @@
self.visit(self.tcx.type_of(param.def_id));
}
}
- // FIXME(const_evaluatable_checked): May want to look inside const here
+ // FIXME(generic_const_exprs): May want to look inside const here
GenericParamDefKind::Const { .. } => {
self.visit(self.tcx.type_of(param.def_id));
}
@@ -1781,8 +1846,8 @@
if self.leaks_private_dep(def_id) {
self.tcx.struct_span_lint_hir(
lint::builtin::EXPORTED_PRIVATE_DEPENDENCIES,
- self.item_id,
- self.span,
+ self.tcx.hir().local_def_id_to_hir_id(self.item_def_id),
+ self.tcx.def_span(self.item_def_id.to_def_id()),
|lint| {
lint.build(&format!(
"{} `{}` from private dependency '{}' in public \
@@ -1817,15 +1882,16 @@
}
};
let make_msg = || format!("{} {} `{}` in public interface", vis_descr, kind, descr);
+ let span = self.tcx.def_span(self.item_def_id.to_def_id());
if self.has_pub_restricted || self.has_old_errors || self.in_assoc_ty {
let mut err = if kind == "trait" {
- struct_span_err!(self.tcx.sess, self.span, E0445, "{}", make_msg())
+ struct_span_err!(self.tcx.sess, span, E0445, "{}", make_msg())
} else {
- struct_span_err!(self.tcx.sess, self.span, E0446, "{}", make_msg())
+ struct_span_err!(self.tcx.sess, span, E0446, "{}", make_msg())
};
let vis_span =
self.tcx.sess.source_map().guess_head_span(self.tcx.def_span(def_id));
- err.span_label(self.span, format!("can't leak {} {}", vis_descr, kind));
+ err.span_label(span, format!("can't leak {} {}", vis_descr, kind));
err.span_label(vis_span, format!("`{}` declared as {}", descr, vis_descr));
err.emit();
} else {
@@ -1833,7 +1899,7 @@
self.tcx.struct_span_lint_hir(
lint::builtin::PRIVATE_IN_PUBLIC,
hir_id,
- self.span,
+ span,
|lint| lint.build(&format!("{} (error {})", make_msg(), err_code)).emit(),
);
}
@@ -1876,35 +1942,33 @@
struct PrivateItemsInPublicInterfacesVisitor<'tcx> {
tcx: TyCtxt<'tcx>,
has_pub_restricted: bool,
- old_error_set_ancestry: HirIdSet,
+ old_error_set_ancestry: LocalDefIdSet,
}
impl<'tcx> PrivateItemsInPublicInterfacesVisitor<'tcx> {
fn check(
&self,
- item_id: hir::HirId,
+ def_id: LocalDefId,
required_visibility: ty::Visibility,
) -> SearchInterfaceForPrivateItemsVisitor<'tcx> {
SearchInterfaceForPrivateItemsVisitor {
tcx: self.tcx,
- item_id,
- item_def_id: self.tcx.hir().local_def_id(item_id).to_def_id(),
- span: self.tcx.hir().span(item_id),
+ item_def_id: def_id,
required_visibility,
has_pub_restricted: self.has_pub_restricted,
- has_old_errors: self.old_error_set_ancestry.contains(&item_id),
+ has_old_errors: self.old_error_set_ancestry.contains(&def_id),
in_assoc_ty: false,
}
}
fn check_assoc_item(
&self,
- hir_id: hir::HirId,
+ def_id: LocalDefId,
assoc_item_kind: AssocItemKind,
defaultness: hir::Defaultness,
vis: ty::Visibility,
) {
- let mut check = self.check(hir_id, vis);
+ let mut check = self.check(def_id, vis);
let (check_ty, is_assoc_ty) = match assoc_item_kind {
AssocItemKind::Const | AssocItemKind::Fn { .. } => (true, false),
@@ -1937,44 +2001,44 @@
// Checked in resolve.
hir::ItemKind::Use(..) => {}
// No subitems.
- hir::ItemKind::GlobalAsm(..) => {}
+ hir::ItemKind::Macro(..) | hir::ItemKind::GlobalAsm(..) => {}
// Subitems of these items have inherited publicity.
hir::ItemKind::Const(..)
| hir::ItemKind::Static(..)
| hir::ItemKind::Fn(..)
| hir::ItemKind::TyAlias(..) => {
- self.check(item.hir_id(), item_visibility).generics().predicates().ty();
+ self.check(item.def_id, item_visibility).generics().predicates().ty();
}
hir::ItemKind::OpaqueTy(..) => {
// `ty()` for opaque types is the underlying type,
// it's not a part of interface, so we skip it.
- self.check(item.hir_id(), item_visibility).generics().bounds();
+ self.check(item.def_id, item_visibility).generics().bounds();
}
hir::ItemKind::Trait(.., trait_item_refs) => {
- self.check(item.hir_id(), item_visibility).generics().predicates();
+ self.check(item.def_id, item_visibility).generics().predicates();
for trait_item_ref in trait_item_refs {
self.check_assoc_item(
- trait_item_ref.id.hir_id(),
+ trait_item_ref.id.def_id,
trait_item_ref.kind,
trait_item_ref.defaultness,
item_visibility,
);
if let AssocItemKind::Type = trait_item_ref.kind {
- self.check(trait_item_ref.id.hir_id(), item_visibility).bounds();
+ self.check(trait_item_ref.id.def_id, item_visibility).bounds();
}
}
}
hir::ItemKind::TraitAlias(..) => {
- self.check(item.hir_id(), item_visibility).generics().predicates();
+ self.check(item.def_id, item_visibility).generics().predicates();
}
hir::ItemKind::Enum(ref def, _) => {
- self.check(item.hir_id(), item_visibility).generics().predicates();
+ self.check(item.def_id, item_visibility).generics().predicates();
for variant in def.variants {
for field in variant.data.fields() {
- self.check(field.hir_id, item_visibility).ty();
+ self.check(self.tcx.hir().local_def_id(field.hir_id), item_visibility).ty();
}
}
}
@@ -1982,16 +2046,17 @@
hir::ItemKind::ForeignMod { items, .. } => {
for foreign_item in items {
let vis = tcx.visibility(foreign_item.id.def_id);
- self.check(foreign_item.id.hir_id(), vis).generics().predicates().ty();
+ self.check(foreign_item.id.def_id, vis).generics().predicates().ty();
}
}
// Subitems of structs and unions have their own publicity.
hir::ItemKind::Struct(ref struct_def, _) | hir::ItemKind::Union(ref struct_def, _) => {
- self.check(item.hir_id(), item_visibility).generics().predicates();
+ self.check(item.def_id, item_visibility).generics().predicates();
for field in struct_def.fields() {
- let field_visibility = tcx.visibility(tcx.hir().local_def_id(field.hir_id));
- self.check(field.hir_id, min(item_visibility, field_visibility, tcx)).ty();
+ let def_id = tcx.hir().local_def_id(field.hir_id);
+ let field_visibility = tcx.visibility(def_id);
+ self.check(def_id, min(item_visibility, field_visibility, tcx)).ty();
}
}
// An inherent impl is public when its type is public
@@ -1999,8 +2064,8 @@
// 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 impl_) => {
- let impl_vis = ty::Visibility::of_impl(item.hir_id(), tcx, &Default::default());
- self.check(item.hir_id(), impl_vis).generics().predicates();
+ let impl_vis = ty::Visibility::of_impl(item.def_id, tcx, &Default::default());
+ self.check(item.def_id, impl_vis).generics().predicates();
for impl_item_ref in impl_.items {
let impl_item_vis = if impl_.of_trait.is_none() {
min(tcx.visibility(impl_item_ref.id.def_id), impl_vis, tcx)
@@ -2008,7 +2073,7 @@
impl_vis
};
self.check_assoc_item(
- impl_item_ref.id.hir_id(),
+ impl_item_ref.id.def_id,
impl_item_ref.kind,
impl_item_ref.defaultness,
impl_item_vis,
@@ -2080,7 +2145,8 @@
fn check_mod_privacy(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
// Check privacy of names not checked in previous compilation stages.
- let mut visitor = NamePrivacyVisitor { tcx, maybe_typeck_results: None, current_item: None };
+ let mut visitor =
+ NamePrivacyVisitor { tcx, maybe_typeck_results: None, current_item: module_def_id };
let (module, span, hir_id) = tcx.hir().get_module(module_def_id);
intravisit::walk_mod(&mut visitor, module, hir_id);
@@ -2110,7 +2176,7 @@
break;
}
}
- visitor.update(hir::CRATE_HIR_ID, Some(AccessLevel::Public));
+ visitor.update(CRATE_DEF_ID, Some(AccessLevel::Public));
tcx.arena.alloc(visitor.access_levels)
}
@@ -2149,7 +2215,15 @@
}
// Check for private types and traits in public interfaces.
- let mut visitor =
- PrivateItemsInPublicInterfacesVisitor { tcx, has_pub_restricted, old_error_set_ancestry };
+ let mut visitor = PrivateItemsInPublicInterfacesVisitor {
+ tcx,
+ has_pub_restricted,
+ // Only definition IDs are ever searched in `old_error_set_ancestry`,
+ // so we can filter away all non-definition IDs at this point.
+ old_error_set_ancestry: old_error_set_ancestry
+ .into_iter()
+ .filter_map(|hir_id| tcx.hir().opt_local_def_id(hir_id))
+ .collect(),
+ };
krate.visit_all_item_likes(&mut DeepVisitor::new(&mut visitor));
}
diff --git a/compiler/rustc_query_impl/Cargo.toml b/compiler/rustc_query_impl/Cargo.toml
index 6a1768b..7c8dbe3 100644
--- a/compiler/rustc_query_impl/Cargo.toml
+++ b/compiler/rustc_query_impl/Cargo.toml
@@ -1,5 +1,4 @@
[package]
-authors = ["The Rust Project Developers"]
name = "rustc_query_impl"
version = "0.0.0"
edition = "2018"
diff --git a/compiler/rustc_query_impl/src/keys.rs b/compiler/rustc_query_impl/src/keys.rs
index 0ad360c..ad621d6 100644
--- a/compiler/rustc_query_impl/src/keys.rs
+++ b/compiler/rustc_query_impl/src/keys.rs
@@ -20,6 +20,12 @@
/// In the event that a cycle occurs, if no explicit span has been
/// given for a query with key `self`, what span should we use?
fn default_span(&self, tcx: TyCtxt<'_>) -> Span;
+
+ /// If the key is a [`DefId`] or `DefId`--equivalent, return that `DefId`.
+ /// Otherwise, return `None`.
+ fn key_as_def_id(&self) -> Option<DefId> {
+ None
+ }
}
impl Key for () {
@@ -66,6 +72,17 @@
}
}
+impl<'tcx> Key for (Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>) {
+ #[inline(always)]
+ fn query_crate_is_local(&self) -> bool {
+ true
+ }
+
+ fn default_span(&self, _: TyCtxt<'_>) -> Span {
+ DUMMY_SP
+ }
+}
+
impl<'tcx> Key for mir::interpret::LitToConstInput<'tcx> {
#[inline(always)]
fn query_crate_is_local(&self) -> bool {
@@ -95,6 +112,9 @@
fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
self.to_def_id().default_span(tcx)
}
+ fn key_as_def_id(&self) -> Option<DefId> {
+ Some(self.to_def_id())
+ }
}
impl Key for DefId {
@@ -105,6 +125,10 @@
fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
tcx.def_span(*self)
}
+ #[inline(always)]
+ fn key_as_def_id(&self) -> Option<DefId> {
+ Some(*self)
+ }
}
impl Key for ty::WithOptConstParam<LocalDefId> {
@@ -165,6 +189,10 @@
fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
tcx.def_span(self.0)
}
+ #[inline(always)]
+ fn key_as_def_id(&self) -> Option<DefId> {
+ Some(self.0)
+ }
}
impl Key for (DefId, LocalDefId, Ident) {
@@ -217,18 +245,13 @@
}
}
-impl<'tcx> Key
- for (
- (ty::WithOptConstParam<DefId>, SubstsRef<'tcx>),
- (ty::WithOptConstParam<DefId>, SubstsRef<'tcx>),
- )
-{
+impl<'tcx> Key for (ty::Unevaluated<'tcx, ()>, ty::Unevaluated<'tcx, ()>) {
#[inline(always)]
fn query_crate_is_local(&self) -> bool {
- (self.0).0.did.krate == LOCAL_CRATE
+ (self.0).def.did.krate == LOCAL_CRATE
}
fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
- (self.0).0.did.default_span(tcx)
+ (self.0).def.did.default_span(tcx)
}
}
@@ -282,6 +305,16 @@
}
}
+impl<'tcx> Key for (ty::PolyTraitRef<'tcx>, ty::PolyTraitRef<'tcx>) {
+ #[inline(always)]
+ fn query_crate_is_local(&self) -> bool {
+ self.0.def_id().krate == LOCAL_CRATE
+ }
+ fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
+ tcx.def_span(self.0.def_id())
+ }
+}
+
impl<'tcx> Key for GenericArg<'tcx> {
#[inline(always)]
fn query_crate_is_local(&self) -> bool {
@@ -322,6 +355,16 @@
}
}
+impl<'tcx> Key for (Ty<'tcx>, Ty<'tcx>) {
+ #[inline(always)]
+ fn query_crate_is_local(&self) -> bool {
+ true
+ }
+ fn default_span(&self, _: TyCtxt<'_>) -> Span {
+ DUMMY_SP
+ }
+}
+
impl<'tcx> Key for &'tcx ty::List<ty::Predicate<'tcx>> {
#[inline(always)]
fn query_crate_is_local(&self) -> bool {
diff --git a/compiler/rustc_query_impl/src/lib.rs b/compiler/rustc_query_impl/src/lib.rs
index 5022bf2..bb0e651 100644
--- a/compiler/rustc_query_impl/src/lib.rs
+++ b/compiler/rustc_query_impl/src/lib.rs
@@ -51,6 +51,8 @@
mod profiling_support;
pub use self::profiling_support::alloc_self_profile_query_strings;
+mod util;
+
rustc_query_append! { [define_queries!][<'tcx>] }
impl<'tcx> Queries<'tcx> {
diff --git a/compiler/rustc_query_impl/src/on_disk_cache.rs b/compiler/rustc_query_impl/src/on_disk_cache.rs
index b024668..ee64f22 100644
--- a/compiler/rustc_query_impl/src/on_disk_cache.rs
+++ b/compiler/rustc_query_impl/src/on_disk_cache.rs
@@ -1,9 +1,7 @@
use crate::QueryCtxt;
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, StableCrateId, LOCAL_CRATE};
use rustc_hir::definitions::DefPathHash;
use rustc_index::vec::{Idx, IndexVec};
@@ -13,7 +11,7 @@
use rustc_middle::ty::codec::{RefDecodable, TyDecoder, TyEncoder};
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_query_system::dep_graph::DepContext;
-use rustc_query_system::query::QueryContext;
+use rustc_query_system::query::{QueryContext, QuerySideEffects};
use rustc_serialize::{
opaque::{self, FileEncodeResult, FileEncoder, IntEncodedWithFixedSize},
Decodable, Decoder, Encodable, Encoder,
@@ -41,14 +39,14 @@
/// Provides an interface to incremental compilation data cached from the
/// previous compilation session. This data will eventually include the results
/// of a few selected queries (like `typeck` and `mir_optimized`) and
-/// any diagnostics that have been emitted during a query.
+/// any side effects that have been emitted during a query.
pub struct OnDiskCache<'sess> {
// The complete cache data in serialized form.
serialized_data: Vec<u8>,
- // Collects all `Diagnostic`s emitted during the current compilation
+ // Collects all `QuerySideEffects` created during the current compilation
// session.
- current_diagnostics: Lock<FxHashMap<DepNodeIndex, Vec<Diagnostic>>>,
+ current_side_effects: Lock<FxHashMap<DepNodeIndex, QuerySideEffects>>,
cnum_map: OnceCell<UnhashMap<StableCrateId, CrateNum>>,
@@ -62,9 +60,9 @@
// `serialized_data`.
query_result_index: FxHashMap<SerializedDepNodeIndex, AbsoluteBytePos>,
- // A map from dep-node to the position of any associated diagnostics in
+ // A map from dep-node to the position of any associated `QuerySideEffects` in
// `serialized_data`.
- prev_diagnostics_index: FxHashMap<SerializedDepNodeIndex, AbsoluteBytePos>,
+ prev_side_effects_index: FxHashMap<SerializedDepNodeIndex, AbsoluteBytePos>,
alloc_decoding_state: AllocDecodingState,
@@ -113,8 +111,8 @@
#[derive(Encodable, Decodable)]
struct Footer {
file_index_to_stable_id: FxHashMap<SourceFileIndex, EncodedSourceFileId>,
- query_result_index: EncodedQueryResultIndex,
- diagnostics_index: EncodedQueryResultIndex,
+ query_result_index: EncodedDepNodeIndex,
+ side_effects_index: EncodedDepNodeIndex,
// The location of all allocations.
interpret_alloc_index: Vec<u32>,
// See `OnDiskCache.syntax_contexts`
@@ -125,9 +123,7 @@
foreign_expn_data: UnhashMap<ExpnHash, u32>,
}
-pub type EncodedQueryResultIndex = Vec<(SerializedDepNodeIndex, AbsoluteBytePos)>;
-type EncodedDiagnosticsIndex = Vec<(SerializedDepNodeIndex, AbsoluteBytePos)>;
-type EncodedDiagnostics = Vec<Diagnostic>;
+pub type EncodedDepNodeIndex = Vec<(SerializedDepNodeIndex, AbsoluteBytePos)>;
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Encodable, Decodable)]
struct SourceFileIndex(u32);
@@ -213,9 +209,9 @@
file_index_to_file: Default::default(),
cnum_map: OnceCell::new(),
source_map: sess.source_map(),
- current_diagnostics: Default::default(),
+ current_side_effects: Default::default(),
query_result_index: footer.query_result_index.into_iter().collect(),
- prev_diagnostics_index: footer.diagnostics_index.into_iter().collect(),
+ prev_side_effects_index: footer.side_effects_index.into_iter().collect(),
alloc_decoding_state: AllocDecodingState::new(footer.interpret_alloc_index),
syntax_contexts: footer.syntax_contexts,
expn_data: footer.expn_data,
@@ -234,9 +230,9 @@
file_index_to_file: Default::default(),
cnum_map: OnceCell::new(),
source_map,
- current_diagnostics: Default::default(),
+ current_side_effects: Default::default(),
query_result_index: Default::default(),
- prev_diagnostics_index: Default::default(),
+ prev_side_effects_index: Default::default(),
alloc_decoding_state: AllocDecodingState::new(Vec::new()),
syntax_contexts: FxHashMap::default(),
expn_data: UnhashMap::default(),
@@ -301,7 +297,7 @@
};
// Encode query results.
- let mut query_result_index = EncodedQueryResultIndex::new();
+ let mut query_result_index = EncodedDepNodeIndex::new();
tcx.sess.time("encode_query_results", || -> FileEncodeResult {
let enc = &mut encoder;
@@ -309,18 +305,16 @@
QueryCtxt::from_tcx(tcx).encode_query_results(enc, qri)
})?;
- // Encode diagnostics.
- let diagnostics_index: EncodedDiagnosticsIndex = self
- .current_diagnostics
+ // Encode side effects.
+ let side_effects_index: EncodedDepNodeIndex = self
+ .current_side_effects
.borrow()
.iter()
.map(
- |(dep_node_index, diagnostics)| -> Result<_, <FileEncoder as Encoder>::Error> {
+ |(dep_node_index, side_effects)| -> 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)?;
+ encoder.encode_tagged(dep_node_index, side_effects)?;
Ok((dep_node_index, pos))
},
@@ -386,7 +380,7 @@
&Footer {
file_index_to_stable_id,
query_result_index,
- diagnostics_index,
+ side_effects_index,
interpret_alloc_index,
syntax_contexts,
expn_data,
@@ -488,30 +482,26 @@
self as _
}
- /// Loads a diagnostic emitted during the previous compilation session.
- pub fn load_diagnostics(
+ /// Loads a `QuerySideEffects` created during the previous compilation session.
+ pub fn load_side_effects(
&self,
tcx: TyCtxt<'_>,
dep_node_index: SerializedDepNodeIndex,
- ) -> Vec<Diagnostic> {
- let diagnostics: Option<EncodedDiagnostics> =
- self.load_indexed(tcx, dep_node_index, &self.prev_diagnostics_index, "diagnostics");
+ ) -> QuerySideEffects {
+ let side_effects: Option<QuerySideEffects> =
+ self.load_indexed(tcx, dep_node_index, &self.prev_side_effects_index, "side_effects");
- diagnostics.unwrap_or_default()
+ side_effects.unwrap_or_default()
}
- /// Stores a diagnostic emitted during the current compilation session.
- /// Anything stored like this will be available via `load_diagnostics` in
+ /// Stores a `QuerySideEffects` emitted during the current compilation session.
+ /// Anything stored like this will be available via `load_side_effects` in
/// the next compilation session.
#[inline(never)]
#[cold]
- pub fn store_diagnostics(
- &self,
- dep_node_index: DepNodeIndex,
- diagnostics: ThinVec<Diagnostic>,
- ) {
- let mut current_diagnostics = self.current_diagnostics.borrow_mut();
- let prev = current_diagnostics.insert(dep_node_index, diagnostics.into());
+ pub fn store_side_effects(&self, dep_node_index: DepNodeIndex, side_effects: QuerySideEffects) {
+ let mut current_side_effects = self.current_side_effects.borrow_mut();
+ let prev = current_side_effects.insert(dep_node_index, side_effects);
debug_assert!(prev.is_none());
}
@@ -539,22 +529,21 @@
self.load_indexed(tcx, dep_node_index, &self.query_result_index, "query result")
}
- /// Stores a diagnostic emitted during computation of an anonymous query.
+ /// Stores side effect emitted during computation of an anonymous query.
/// Since many anonymous queries can share the same `DepNode`, we aggregate
/// them -- as opposed to regular queries where we assume that there is a
/// 1:1 relationship between query-key and `DepNode`.
#[inline(never)]
#[cold]
- pub fn store_diagnostics_for_anon_node(
+ pub fn store_side_effects_for_anon_node(
&self,
dep_node_index: DepNodeIndex,
- diagnostics: ThinVec<Diagnostic>,
+ side_effects: QuerySideEffects,
) {
- let mut current_diagnostics = self.current_diagnostics.borrow_mut();
+ let mut current_side_effects = self.current_side_effects.borrow_mut();
- let x = current_diagnostics.entry(dep_node_index).or_default();
-
- x.extend(Into::<Vec<_>>::into(diagnostics));
+ let x = current_side_effects.entry(dep_node_index).or_default();
+ x.append(side_effects);
}
fn load_indexed<'tcx, T>(
@@ -1155,7 +1144,7 @@
pub fn encode_query_results<'a, 'tcx, CTX, Q>(
tcx: CTX,
encoder: &mut CacheEncoder<'a, 'tcx, FileEncoder>,
- query_result_index: &mut EncodedQueryResultIndex,
+ query_result_index: &mut EncodedDepNodeIndex,
) -> FileEncodeResult
where
CTX: QueryContext + 'tcx,
diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs
index 58c1b57..90a6ba4 100644
--- a/compiler/rustc_query_impl/src/plumbing.rs
+++ b/compiler/rustc_query_impl/src/plumbing.rs
@@ -7,7 +7,9 @@
use rustc_middle::ty::tls::{self, ImplicitCtxt};
use rustc_middle::ty::{self, TyCtxt};
use rustc_query_system::dep_graph::HasDepContext;
-use rustc_query_system::query::{QueryContext, QueryDescription, QueryJobId, QueryMap};
+use rustc_query_system::query::{
+ QueryContext, QueryDescription, QueryJobId, QueryMap, QuerySideEffects,
+};
use rustc_data_structures::sync::Lock;
use rustc_data_structures::thin_vec::ThinVec;
@@ -83,27 +85,27 @@
}
// Interactions with on_disk_cache
- fn load_diagnostics(&self, prev_dep_node_index: SerializedDepNodeIndex) -> Vec<Diagnostic> {
+ fn load_side_effects(&self, prev_dep_node_index: SerializedDepNodeIndex) -> QuerySideEffects {
self.queries
.on_disk_cache
.as_ref()
- .map(|c| c.load_diagnostics(**self, prev_dep_node_index))
+ .map(|c| c.load_side_effects(**self, prev_dep_node_index))
.unwrap_or_default()
}
- fn store_diagnostics(&self, dep_node_index: DepNodeIndex, diagnostics: ThinVec<Diagnostic>) {
+ fn store_side_effects(&self, dep_node_index: DepNodeIndex, side_effects: QuerySideEffects) {
if let Some(c) = self.queries.on_disk_cache.as_ref() {
- c.store_diagnostics(dep_node_index, diagnostics)
+ c.store_side_effects(dep_node_index, side_effects)
}
}
- fn store_diagnostics_for_anon_node(
+ fn store_side_effects_for_anon_node(
&self,
dep_node_index: DepNodeIndex,
- diagnostics: ThinVec<Diagnostic>,
+ side_effects: QuerySideEffects,
) {
if let Some(c) = self.queries.on_disk_cache.as_ref() {
- c.store_diagnostics_for_anon_node(dep_node_index, diagnostics)
+ c.store_side_effects_for_anon_node(dep_node_index, side_effects)
}
}
@@ -163,7 +165,7 @@
pub(super) fn encode_query_results(
self,
encoder: &mut on_disk_cache::CacheEncoder<'a, 'tcx, opaque::FileEncoder>,
- query_result_index: &mut on_disk_cache::EncodedQueryResultIndex,
+ query_result_index: &mut on_disk_cache::EncodedDepNodeIndex,
) -> opaque::FileEncodeResult {
macro_rules! encode_queries {
($($query:ident,)*) => {
@@ -335,6 +337,13 @@
} else {
Some(key.default_span(*tcx))
};
+ let def_id = key.key_as_def_id();
+ let def_kind = def_id
+ .and_then(|def_id| def_id.as_local())
+ // Use `tcx.hir().opt_def_kind()` to reduce the chance of
+ // accidentally triggering an infinite query loop.
+ .and_then(|def_id| tcx.hir().opt_def_kind(def_id))
+ .map(|def_kind| $crate::util::def_kind_to_simple_def_kind(def_kind));
let hash = || {
let mut hcx = tcx.create_stable_hashing_context();
let mut hasher = StableHasher::new();
@@ -343,7 +352,7 @@
hasher.finish::<u64>()
};
- QueryStackFrame::new(name, description, span, hash)
+ QueryStackFrame::new(name, description, span, def_kind, hash)
})*
}
diff --git a/compiler/rustc_query_impl/src/util.rs b/compiler/rustc_query_impl/src/util.rs
new file mode 100644
index 0000000..517c107
--- /dev/null
+++ b/compiler/rustc_query_impl/src/util.rs
@@ -0,0 +1,18 @@
+use rustc_hir::def::DefKind;
+use rustc_query_system::query::SimpleDefKind;
+
+/// Convert a [`DefKind`] to a [`SimpleDefKind`].
+///
+/// *See [`SimpleDefKind`]'s docs for more information.*
+pub(crate) fn def_kind_to_simple_def_kind(def_kind: DefKind) -> SimpleDefKind {
+ match def_kind {
+ DefKind::Struct => SimpleDefKind::Struct,
+ DefKind::Enum => SimpleDefKind::Enum,
+ DefKind::Union => SimpleDefKind::Union,
+ DefKind::Trait => SimpleDefKind::Trait,
+ DefKind::TyAlias => SimpleDefKind::TyAlias,
+ DefKind::TraitAlias => SimpleDefKind::TraitAlias,
+
+ _ => SimpleDefKind::Other,
+ }
+}
diff --git a/compiler/rustc_query_system/Cargo.toml b/compiler/rustc_query_system/Cargo.toml
index 19512dc..47fb78b 100644
--- a/compiler/rustc_query_system/Cargo.toml
+++ b/compiler/rustc_query_system/Cargo.toml
@@ -1,5 +1,4 @@
[package]
-authors = ["The Rust Project Developers"]
name = "rustc_query_system"
version = "0.0.0"
edition = "2018"
diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs
index c8a46e9..9c3dad8 100644
--- a/compiler/rustc_query_system/src/dep_graph/graph.rs
+++ b/compiler/rustc_query_system/src/dep_graph/graph.rs
@@ -5,23 +5,20 @@
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_data_structures::steal::Steal;
use rustc_data_structures::sync::{AtomicU32, AtomicU64, Lock, Lrc, Ordering};
-use rustc_data_structures::unlikely;
-use rustc_errors::Diagnostic;
use rustc_index::vec::IndexVec;
use rustc_serialize::opaque::{FileEncodeResult, FileEncoder};
-use parking_lot::{Condvar, Mutex};
+use parking_lot::Mutex;
use smallvec::{smallvec, SmallVec};
use std::collections::hash_map::Entry;
use std::hash::Hash;
use std::marker::PhantomData;
-use std::mem;
use std::sync::atomic::Ordering::Relaxed;
use super::query::DepGraphQuery;
use super::serialized::{GraphEncoder, SerializedDepGraph, SerializedDepNodeIndex};
use super::{DepContext, DepKind, DepNode, HasDepContext, WorkProductId};
-use crate::query::QueryContext;
+use crate::query::{QueryContext, QuerySideEffects};
#[cfg(debug_assertions)]
use {super::debug::EdgeFilter, std::env};
@@ -87,11 +84,7 @@
colors: DepNodeColorMap,
- /// A set of loaded diagnostics that is in the progress of being emitted.
- emitting_diagnostics: Mutex<FxHashSet<DepNodeIndex>>,
-
- /// Used to wait for diagnostics to be emitted.
- emitting_diagnostics_cond_var: Condvar,
+ processed_side_effects: Mutex<FxHashSet<DepNodeIndex>>,
/// When we load, there may be `.o` files, cached MIR, or other such
/// things available to us. If we find that they are not dirty, we
@@ -144,8 +137,7 @@
previous_work_products: prev_work_products,
dep_node_debug: Default::default(),
current,
- emitting_diagnostics: Default::default(),
- emitting_diagnostics_cond_var: Condvar::new(),
+ processed_side_effects: Default::default(),
previous: prev_graph,
colors: DepNodeColorMap::new(prev_graph_node_count),
})),
@@ -691,7 +683,7 @@
// FIXME: Store the fact that a node has diagnostics in a bit in the dep graph somewhere
// Maybe store a list on disk and encode this fact in the DepNodeState
- let diagnostics = tcx.load_diagnostics(prev_dep_node_index);
+ let side_effects = tcx.load_side_effects(prev_dep_node_index);
#[cfg(not(parallel_compiler))]
debug_assert!(
@@ -701,8 +693,8 @@
dep_node
);
- if unlikely!(!diagnostics.is_empty()) {
- self.emit_diagnostics(tcx, data, dep_node_index, prev_dep_node_index, diagnostics);
+ if unlikely!(!side_effects.is_empty()) {
+ self.emit_side_effects(tcx, data, dep_node_index, side_effects);
}
// ... and finally storing a "Green" entry in the color map.
@@ -717,54 +709,27 @@
/// This may be called concurrently on multiple threads for the same dep node.
#[cold]
#[inline(never)]
- fn emit_diagnostics<Ctxt: QueryContext<DepKind = K>>(
+ fn emit_side_effects<Ctxt: QueryContext<DepKind = K>>(
&self,
tcx: Ctxt,
data: &DepGraphData<K>,
dep_node_index: DepNodeIndex,
- prev_dep_node_index: SerializedDepNodeIndex,
- diagnostics: Vec<Diagnostic>,
+ side_effects: QuerySideEffects,
) {
- let mut emitting = data.emitting_diagnostics.lock();
+ let mut processed = data.processed_side_effects.lock();
- if data.colors.get(prev_dep_node_index) == Some(DepNodeColor::Green(dep_node_index)) {
- // The node is already green so diagnostics must have been emitted already
- return;
- }
-
- if emitting.insert(dep_node_index) {
+ if processed.insert(dep_node_index) {
// We were the first to insert the node in the set so this thread
- // must emit the diagnostics and signal other potentially waiting
- // threads after.
- mem::drop(emitting);
+ // must process side effects
// Promote the previous diagnostics to the current session.
- tcx.store_diagnostics(dep_node_index, diagnostics.clone().into());
+ tcx.store_side_effects(dep_node_index, side_effects.clone());
let handle = tcx.dep_context().sess().diagnostic();
- for diagnostic in diagnostics {
+ for diagnostic in side_effects.diagnostics {
handle.emit_diagnostic(&diagnostic);
}
-
- // Mark the node as green now that diagnostics are emitted
- data.colors.insert(prev_dep_node_index, DepNodeColor::Green(dep_node_index));
-
- // Remove the node from the set
- data.emitting_diagnostics.lock().remove(&dep_node_index);
-
- // Wake up waiters
- data.emitting_diagnostics_cond_var.notify_all();
- } else {
- // We must wait for the other thread to finish emitting the diagnostic
-
- loop {
- data.emitting_diagnostics_cond_var.wait(&mut emitting);
- if data.colors.get(prev_dep_node_index) == Some(DepNodeColor::Green(dep_node_index))
- {
- break;
- }
- }
}
}
diff --git a/compiler/rustc_query_system/src/lib.rs b/compiler/rustc_query_system/src/lib.rs
index 0d4fb34..c205f0f 100644
--- a/compiler/rustc_query_system/src/lib.rs
+++ b/compiler/rustc_query_system/src/lib.rs
@@ -3,6 +3,7 @@
#![feature(hash_raw_entry)]
#![feature(iter_zip)]
#![feature(min_specialization)]
+#![feature(thread_local_const_init)]
#[macro_use]
extern crate tracing;
diff --git a/compiler/rustc_query_system/src/query/job.rs b/compiler/rustc_query_system/src/query/job.rs
index a967670..c3fdf4f 100644
--- a/compiler/rustc_query_system/src/query/job.rs
+++ b/compiler/rustc_query_system/src/query/job.rs
@@ -1,6 +1,6 @@
use crate::dep_graph::DepContext;
use crate::query::plumbing::CycleError;
-use crate::query::{QueryContext, QueryStackFrame};
+use crate::query::{QueryContext, QueryStackFrame, SimpleDefKind};
use rustc_data_structures::fx::FxHashMap;
use rustc_errors::{struct_span_err, Diagnostic, DiagnosticBuilder, Handler, Level};
@@ -61,7 +61,7 @@
}
fn query(self, map: &QueryMap<D>) -> QueryStackFrame {
- map.get(&self).unwrap().info.query.clone()
+ map.get(&self).unwrap().query.clone()
}
#[cfg(parallel_compiler)]
@@ -81,7 +81,7 @@
}
pub struct QueryJobInfo<D> {
- pub info: QueryInfo,
+ pub query: QueryStackFrame,
pub job: QueryJob<D>,
}
@@ -155,7 +155,7 @@
while let Some(job) = current_job {
let info = query_map.get(&job).unwrap();
- cycle.push(info.info.clone());
+ cycle.push(QueryInfo { span: info.job.span, query: info.query.clone() });
if job == *self {
cycle.reverse();
@@ -170,7 +170,7 @@
.job
.parent
.as_ref()
- .map(|parent| (info.info.span, parent.query(&query_map)));
+ .map(|parent| (info.job.span, parent.query(&query_map)));
return CycleError { usage, cycle };
}
@@ -591,10 +591,33 @@
err.span_note(span, &format!("...which requires {}...", query.description));
}
- err.note(&format!(
- "...which again requires {}, completing the cycle",
- stack[0].query.description
- ));
+ if stack.len() == 1 {
+ err.note(&format!("...which immediately requires {} again", stack[0].query.description));
+ } else {
+ err.note(&format!(
+ "...which again requires {}, completing the cycle",
+ stack[0].query.description
+ ));
+ }
+
+ if stack.iter().all(|entry| {
+ entry.query.def_kind.map_or(false, |def_kind| {
+ matches!(def_kind, SimpleDefKind::TyAlias | SimpleDefKind::TraitAlias)
+ })
+ }) {
+ if stack.iter().all(|entry| {
+ entry
+ .query
+ .def_kind
+ .map_or(false, |def_kind| matches!(def_kind, SimpleDefKind::TyAlias))
+ }) {
+ err.note("type aliases cannot be recursive");
+ err.help("consider using a struct, enum, or union instead to break the cycle");
+ err.help("see <https://doc.rust-lang.org/reference/types.html#recursive-types> for more information");
+ } else {
+ err.note("trait aliases cannot be recursive");
+ }
+ }
if let Some((span, query)) = usage {
err.span_note(fix_span(span, &query), &format!("cycle used when {}", query.description));
@@ -626,13 +649,10 @@
};
let mut diag = Diagnostic::new(
Level::FailureNote,
- &format!(
- "#{} [{}] {}",
- i, query_info.info.query.name, query_info.info.query.description
- ),
+ &format!("#{} [{}] {}", i, query_info.query.name, query_info.query.description),
);
diag.span =
- tcx.dep_context().sess().source_map().guess_head_span(query_info.info.span).into();
+ tcx.dep_context().sess().source_map().guess_head_span(query_info.job.span).into();
handler.force_print_diagnostic(diag);
current_query = query_info.job.parent;
diff --git a/compiler/rustc_query_system/src/query/mod.rs b/compiler/rustc_query_system/src/query/mod.rs
index 927e811..dffe7f3 100644
--- a/compiler/rustc_query_system/src/query/mod.rs
+++ b/compiler/rustc_query_system/src/query/mod.rs
@@ -29,24 +29,53 @@
pub name: &'static str,
pub description: String,
span: Option<Span>,
+ /// The `DefKind` this query frame is associated with, if applicable.
+ ///
+ /// We can't use `rustc_hir::def::DefKind` because `rustc_hir` is not
+ /// available in `rustc_query_system`. Instead, we have a simplified
+ /// custom version of it, called [`SimpleDefKind`].
+ def_kind: Option<SimpleDefKind>,
/// This hash is used to deterministically pick
/// a query to remove cycles in the parallel compiler.
#[cfg(parallel_compiler)]
hash: u64,
}
+/// A simplified version of `rustc_hir::def::DefKind`.
+///
+/// It was added to help improve cycle errors caused by recursive type aliases.
+/// As of August 2021, `rustc_query_system` cannot depend on `rustc_hir`
+/// because it would create a dependency cycle. So, instead, a simplified
+/// version of `DefKind` was added to `rustc_query_system`.
+///
+/// `DefKind`s are converted to `SimpleDefKind`s in `rustc_query_impl`.
+#[derive(Debug, Copy, Clone)]
+pub enum SimpleDefKind {
+ Struct,
+ Enum,
+ Union,
+ Trait,
+ TyAlias,
+ TraitAlias,
+
+ // FIXME: add more from `rustc_hir::def::DefKind` and then remove `Other`
+ Other,
+}
+
impl QueryStackFrame {
#[inline]
pub fn new(
name: &'static str,
description: String,
span: Option<Span>,
+ def_kind: Option<SimpleDefKind>,
_hash: impl FnOnce() -> u64,
) -> Self {
Self {
name,
description,
span,
+ def_kind,
#[cfg(parallel_compiler)]
hash: _hash(),
}
@@ -62,6 +91,31 @@
}
}
+/// Tracks 'side effects' for a particular query.
+/// This struct is saved to disk along with the query result,
+/// and loaded from disk if we mark the query as green.
+/// This allows us to 'replay' changes to global state
+/// that would otherwise only occur if we actually
+/// executed the query method.
+#[derive(Debug, Clone, Default, Encodable, Decodable)]
+pub struct QuerySideEffects {
+ /// Stores any diagnostics emitted during query execution.
+ /// These diagnostics will be re-emitted if we mark
+ /// the query as green.
+ pub(super) diagnostics: ThinVec<Diagnostic>,
+}
+
+impl QuerySideEffects {
+ pub fn is_empty(&self) -> bool {
+ let QuerySideEffects { diagnostics } = self;
+ diagnostics.is_empty()
+ }
+ pub fn append(&mut self, other: QuerySideEffects) {
+ let QuerySideEffects { diagnostics } = self;
+ diagnostics.extend(other.diagnostics);
+ }
+}
+
pub trait QueryContext: HasDepContext {
/// Get the query information from the TLS context.
fn current_query_job(&self) -> Option<QueryJobId<Self::DepKind>>;
@@ -74,17 +128,17 @@
/// Try to force a dep node to execute and see if it's green.
fn try_force_from_dep_node(&self, dep_node: &DepNode<Self::DepKind>) -> bool;
- /// Load diagnostics associated to the node in the previous session.
- fn load_diagnostics(&self, prev_dep_node_index: SerializedDepNodeIndex) -> Vec<Diagnostic>;
+ /// Load side effects associated to the node in the previous session.
+ fn load_side_effects(&self, prev_dep_node_index: SerializedDepNodeIndex) -> QuerySideEffects;
/// Register diagnostics for the given node, for use in next session.
- fn store_diagnostics(&self, dep_node_index: DepNodeIndex, diagnostics: ThinVec<Diagnostic>);
+ fn store_side_effects(&self, dep_node_index: DepNodeIndex, side_effects: QuerySideEffects);
/// Register diagnostics for the given node, for use in next session.
- fn store_diagnostics_for_anon_node(
+ fn store_side_effects_for_anon_node(
&self,
dep_node_index: DepNodeIndex,
- diagnostics: ThinVec<Diagnostic>,
+ side_effects: QuerySideEffects,
);
/// Executes a job by changing the `ImplicitCtxt` to point to the
diff --git a/compiler/rustc_query_system/src/query/plumbing.rs b/compiler/rustc_query_system/src/query/plumbing.rs
index c227c2a..3f22de6 100644
--- a/compiler/rustc_query_system/src/query/plumbing.rs
+++ b/compiler/rustc_query_system/src/query/plumbing.rs
@@ -9,7 +9,7 @@
use crate::query::job::{
report_cycle, QueryInfo, QueryJob, QueryJobId, QueryJobInfo, QueryShardJobId,
};
-use crate::query::{QueryContext, QueryMap, QueryStackFrame};
+use crate::query::{QueryContext, QueryMap, QuerySideEffects, QueryStackFrame};
use rustc_data_structures::fingerprint::Fingerprint;
use rustc_data_structures::fx::{FxHashMap, FxHasher};
@@ -20,6 +20,7 @@
use rustc_errors::DiagnosticBuilder;
use rustc_errors::{Diagnostic, FatalError};
use rustc_span::{Span, DUMMY_SP};
+use std::cell::Cell;
use std::collections::hash_map::Entry;
use std::fmt::Debug;
use std::hash::{Hash, Hasher};
@@ -129,8 +130,8 @@
for (k, v) in shard.active.iter() {
if let QueryResult::Started(ref job) = *v {
let id = QueryJobId::new(job.id, shard_id, kind);
- let info = QueryInfo { span: job.span, query: make_query(tcx, k.clone()) };
- jobs.insert(id, QueryJobInfo { info, job: job.clone() });
+ let query = make_query(tcx, k.clone());
+ jobs.insert(id, QueryJobInfo { query, job: job.clone() });
}
}
}
@@ -479,8 +480,10 @@
dep_graph.read_index(dep_node_index);
- if unlikely!(!diagnostics.is_empty()) {
- tcx.store_diagnostics_for_anon_node(dep_node_index, diagnostics);
+ let side_effects = QuerySideEffects { diagnostics };
+
+ if unlikely!(!side_effects.is_empty()) {
+ tcx.store_side_effects_for_anon_node(dep_node_index, side_effects);
}
return job.complete(result, dep_node_index);
@@ -616,12 +619,32 @@
} else {
"`cargo clean`".to_string()
};
- tcx.sess().struct_err(&format!("internal compiler error: encountered incremental compilation error with {:?}", dep_node))
- .help(&format!("This is a known issue with the compiler. Run {} to allow your project to compile", run_cmd))
- .note(&format!("Please follow the instructions below to create a bug report with the provided information"))
- .note(&format!("See <https://github.com/rust-lang/rust/issues/84970> for more information"))
- .emit();
- panic!("Found unstable fingerprints for {:?}: {:?}", dep_node, result);
+
+ // When we emit an error message and panic, we try to debug-print the `DepNode`
+ // and query result. Unforunately, this can cause us to run additional queries,
+ // which may result in another fingerprint mismatch while we're in the middle
+ // of processing this one. To avoid a double-panic (which kills the process
+ // before we can print out the query static), we print out a terse
+ // but 'safe' message if we detect a re-entrant call to this method.
+ thread_local! {
+ static INSIDE_VERIFY_PANIC: Cell<bool> = const { Cell::new(false) };
+ };
+
+ let old_in_panic = INSIDE_VERIFY_PANIC.with(|in_panic| in_panic.replace(true));
+
+ if old_in_panic {
+ tcx.sess().struct_err("internal compiler error: re-entrant incremental verify failure, suppressing message")
+ .emit();
+ } else {
+ tcx.sess().struct_err(&format!("internal compiler error: encountered incremental compilation error with {:?}", dep_node))
+ .help(&format!("This is a known issue with the compiler. Run {} to allow your project to compile", run_cmd))
+ .note(&"Please follow the instructions below to create a bug report with the provided information")
+ .note(&"See <https://github.com/rust-lang/rust/issues/84970> for more information")
+ .emit();
+ panic!("Found unstable fingerprints for {:?}: {:?}", dep_node, result);
+ }
+
+ INSIDE_VERIFY_PANIC.with(|in_panic| in_panic.set(old_in_panic));
}
}
@@ -677,8 +700,10 @@
prof_timer.finish_with_query_invocation_id(dep_node_index.into());
- if unlikely!(!diagnostics.is_empty()) && dep_node.kind != DepKind::NULL {
- tcx.store_diagnostics(dep_node_index, diagnostics);
+ let side_effects = QuerySideEffects { diagnostics };
+
+ if unlikely!(!side_effects.is_empty()) && dep_node.kind != DepKind::NULL {
+ tcx.store_side_effects(dep_node_index, side_effects);
}
let result = job.complete(result, dep_node_index);
diff --git a/compiler/rustc_resolve/Cargo.toml b/compiler/rustc_resolve/Cargo.toml
index 7441f4a..1581b05 100644
--- a/compiler/rustc_resolve/Cargo.toml
+++ b/compiler/rustc_resolve/Cargo.toml
@@ -1,5 +1,4 @@
[package]
-authors = ["The Rust Project Developers"]
name = "rustc_resolve"
version = "0.0.0"
edition = "2018"
diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs
index 178d727..2ee483d 100644
--- a/compiler/rustc_resolve/src/build_reduced_graph.rs
+++ b/compiler/rustc_resolve/src/build_reduced_graph.rs
@@ -195,7 +195,7 @@
crate fn get_macro(&mut self, res: Res) -> Option<Lrc<SyntaxExtension>> {
match res {
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())),
+ Res::NonMacroAttr(_) => Some(self.non_macro_attr.clone()),
_ => None,
}
}
@@ -1059,7 +1059,7 @@
let mut import_all = None;
let mut single_imports = Vec::new();
for attr in &item.attrs {
- if self.r.session.check_name(attr, sym::macro_use) {
+ if attr.has_name(sym::macro_use) {
if self.parent_scope.module.parent.is_some() {
struct_span_err!(
self.r.session,
@@ -1165,7 +1165,7 @@
/// Returns `true` if this attribute list contains `macro_use`.
fn contains_macro_use(&mut self, attrs: &[ast::Attribute]) -> bool {
for attr in attrs {
- if self.r.session.check_name(attr, sym::macro_escape) {
+ if attr.has_name(sym::macro_escape) {
let msg = "`#[macro_escape]` is a deprecated synonym for `#[macro_use]`";
let mut err = self.r.session.struct_span_warn(attr.span, msg);
if let ast::AttrStyle::Inner = attr.style {
@@ -1173,7 +1173,7 @@
} else {
err.emit();
}
- } else if !self.r.session.check_name(attr, sym::macro_use) {
+ } else if !attr.has_name(sym::macro_use) {
continue;
}
diff --git a/compiler/rustc_resolve/src/check_unused.rs b/compiler/rustc_resolve/src/check_unused.rs
index 89ce89b..760b746 100644
--- a/compiler/rustc_resolve/src/check_unused.rs
+++ b/compiler/rustc_resolve/src/check_unused.rs
@@ -63,8 +63,7 @@
// We have information about whether `use` (import) items are actually
// used now. If an import is not used at all, we signal a lint error.
fn check_import(&mut self, id: ast::NodeId) {
- let mut used = false;
- self.r.per_ns(|this, ns| used |= this.used_imports.contains(&(id, ns)));
+ let used = self.r.used_imports.contains(&id);
let def_id = self.r.local_def_id(id);
if !used {
if self.r.maybe_unused_trait_imports.contains(&def_id) {
@@ -98,7 +97,7 @@
impl<'a, 'b> Visitor<'a> for UnusedImportCheckVisitor<'a, 'b> {
fn visit_item(&mut self, item: &'a ast::Item) {
- self.item_span = item.span;
+ self.item_span = item.span_with_attributes();
// Ignore is_public import statements because there's no way to be sure
// whether they're used or not. Also ignore imports with a dummy span
diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs
index 7439cd9..0b1687d 100644
--- a/compiler/rustc_resolve/src/diagnostics.rs
+++ b/compiler/rustc_resolve/src/diagnostics.rs
@@ -38,14 +38,25 @@
/// similarly named label and whether or not it is reachable.
crate type LabelSuggestion = (Ident, bool);
+crate enum SuggestionTarget {
+ /// The target has a similar name as the name used by the programmer (probably a typo)
+ SimilarlyNamed,
+ /// The target is the only valid item that can be used in the corresponding context
+ SingleItem,
+}
+
crate struct TypoSuggestion {
pub candidate: Symbol,
pub res: Res,
+ pub target: SuggestionTarget,
}
impl TypoSuggestion {
- crate fn from_res(candidate: Symbol, res: Res) -> TypoSuggestion {
- TypoSuggestion { candidate, res }
+ crate fn typo_from_res(candidate: Symbol, res: Res) -> TypoSuggestion {
+ Self { candidate, res, target: SuggestionTarget::SimilarlyNamed }
+ }
+ crate fn single_item_from_res(candidate: Symbol, res: Res) -> TypoSuggestion {
+ Self { candidate, res, target: SuggestionTarget::SingleItem }
}
}
@@ -80,7 +91,7 @@
if let Some(binding) = resolution.borrow().binding {
let res = binding.res();
if filter_fn(res) {
- names.push(TypoSuggestion::from_res(key.ident.name, res));
+ names.push(TypoSuggestion::typo_from_res(key.ident.name, res));
}
}
}
@@ -495,8 +506,7 @@
if self.session.is_nightly_build() {
err.help(
- "use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` \
- to allow generic const expressions"
+ "use `#![feature(generic_const_exprs)]` to allow generic const expressions",
);
}
@@ -623,7 +633,7 @@
.get(&expn_id)
.into_iter()
.flatten()
- .map(|ident| TypoSuggestion::from_res(ident.name, res)),
+ .map(|ident| TypoSuggestion::typo_from_res(ident.name, res)),
);
}
}
@@ -642,7 +652,7 @@
suggestions.extend(
ext.helper_attrs
.iter()
- .map(|name| TypoSuggestion::from_res(*name, res)),
+ .map(|name| TypoSuggestion::typo_from_res(*name, res)),
);
}
}
@@ -652,8 +662,10 @@
if let MacroRulesScope::Binding(macro_rules_binding) = macro_rules_scope.get() {
let res = macro_rules_binding.binding.res();
if filter_fn(res) {
- suggestions
- .push(TypoSuggestion::from_res(macro_rules_binding.ident.name, res))
+ suggestions.push(TypoSuggestion::typo_from_res(
+ macro_rules_binding.ident.name,
+ res,
+ ))
}
}
}
@@ -671,7 +683,7 @@
suggestions.extend(
this.registered_attrs
.iter()
- .map(|ident| TypoSuggestion::from_res(ident.name, res)),
+ .map(|ident| TypoSuggestion::typo_from_res(ident.name, res)),
);
}
}
@@ -679,7 +691,7 @@
suggestions.extend(this.macro_use_prelude.iter().filter_map(
|(name, binding)| {
let res = binding.res();
- filter_fn(res).then_some(TypoSuggestion::from_res(*name, res))
+ filter_fn(res).then_some(TypoSuggestion::typo_from_res(*name, res))
},
));
}
@@ -689,14 +701,14 @@
suggestions.extend(
BUILTIN_ATTRIBUTES
.iter()
- .map(|(name, ..)| TypoSuggestion::from_res(*name, res)),
+ .map(|(name, ..)| TypoSuggestion::typo_from_res(*name, res)),
);
}
}
Scope::ExternPrelude => {
suggestions.extend(this.extern_prelude.iter().filter_map(|(ident, _)| {
let res = Res::Def(DefKind::Mod, DefId::local(CRATE_DEF_INDEX));
- filter_fn(res).then_some(TypoSuggestion::from_res(ident.name, res))
+ filter_fn(res).then_some(TypoSuggestion::typo_from_res(ident.name, res))
}));
}
Scope::ToolPrelude => {
@@ -704,7 +716,7 @@
suggestions.extend(
this.registered_tools
.iter()
- .map(|ident| TypoSuggestion::from_res(ident.name, res)),
+ .map(|ident| TypoSuggestion::typo_from_res(ident.name, res)),
);
}
Scope::StdLibPrelude => {
@@ -721,7 +733,7 @@
Scope::BuiltinTypes => {
suggestions.extend(PrimTy::ALL.iter().filter_map(|prim_ty| {
let res = Res::PrimTy(*prim_ty);
- filter_fn(res).then_some(TypoSuggestion::from_res(prim_ty.name(), res))
+ filter_fn(res).then_some(TypoSuggestion::typo_from_res(prim_ty.name(), res))
}))
}
}
@@ -937,17 +949,67 @@
self.add_typo_suggestion(err, suggestion, ident.span);
let import_suggestions =
- self.lookup_import_candidates(ident, Namespace::MacroNS, parent_scope, |res| {
- matches!(res, Res::Def(DefKind::Macro(MacroKind::Bang), _))
- });
+ self.lookup_import_candidates(ident, Namespace::MacroNS, parent_scope, is_expected);
show_candidates(err, None, &import_suggestions, false, true);
if macro_kind == MacroKind::Derive && (ident.name == sym::Send || ident.name == sym::Sync) {
let msg = format!("unsafe traits like `{}` should be implemented explicitly", ident);
err.span_note(ident.span, &msg);
+ return;
}
if self.macro_names.contains(&ident.normalize_to_macros_2_0()) {
err.help("have you added the `#[macro_use]` on the module/import?");
+ return;
+ }
+ for ns in [Namespace::MacroNS, Namespace::TypeNS, Namespace::ValueNS] {
+ if let Ok(binding) = self.early_resolve_ident_in_lexical_scope(
+ ident,
+ ScopeSet::All(ns, false),
+ &parent_scope,
+ false,
+ false,
+ ident.span,
+ ) {
+ let desc = match binding.res() {
+ Res::Def(DefKind::Macro(MacroKind::Bang), _) => {
+ "a function-like macro".to_string()
+ }
+ Res::Def(DefKind::Macro(MacroKind::Attr), _) | Res::NonMacroAttr(..) => {
+ format!("an attribute: `#[{}]`", ident)
+ }
+ Res::Def(DefKind::Macro(MacroKind::Derive), _) => {
+ format!("a derive macro: `#[derive({})]`", ident)
+ }
+ Res::ToolMod => {
+ // Don't confuse the user with tool modules.
+ continue;
+ }
+ Res::Def(DefKind::Trait, _) if macro_kind == MacroKind::Derive => {
+ "only a trait, without a derive macro".to_string()
+ }
+ res => format!(
+ "{} {}, not {} {}",
+ res.article(),
+ res.descr(),
+ macro_kind.article(),
+ macro_kind.descr_expected(),
+ ),
+ };
+ if let crate::NameBindingKind::Import { import, .. } = binding.kind {
+ if !import.span.is_dummy() {
+ err.span_note(
+ import.span,
+ &format!("`{}` is imported here, but it is {}", ident, desc),
+ );
+ // Silence the 'unused import' warning we might get,
+ // since this diagnostic already covers that import.
+ self.record_use(ident, binding, false);
+ return;
+ }
+ }
+ err.note(&format!("`{}` is in scope, but it is {}", ident, desc));
+ return;
+ }
}
}
@@ -993,20 +1055,31 @@
// | ^
return false;
}
+ let prefix = match suggestion.target {
+ SuggestionTarget::SimilarlyNamed => "similarly named ",
+ SuggestionTarget::SingleItem => "",
+ };
+
err.span_label(
self.session.source_map().guess_head_span(def_span),
&format!(
- "similarly named {} `{}` defined here",
+ "{}{} `{}` defined here",
+ prefix,
suggestion.res.descr(),
suggestion.candidate.as_str(),
),
);
}
- let msg = format!(
- "{} {} with a similar name exists",
- suggestion.res.article(),
- suggestion.res.descr()
- );
+ let msg = match suggestion.target {
+ SuggestionTarget::SimilarlyNamed => format!(
+ "{} {} with a similar name exists",
+ suggestion.res.article(),
+ suggestion.res.descr()
+ ),
+ SuggestionTarget::SingleItem => {
+ format!("maybe you meant this {}", suggestion.res.descr())
+ }
+ };
err.span_suggestion(
span,
&msg,
diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs
index acfa389..dfb6d89 100644
--- a/compiler/rustc_resolve/src/imports.rs
+++ b/compiler/rustc_resolve/src/imports.rs
@@ -303,7 +303,7 @@
if self.last_import_segment && check_usable(self, binding).is_err() {
Err((Determined, Weak::No))
} else {
- self.record_use(ident, ns, binding, restricted_shadowing);
+ self.record_use(ident, binding, restricted_shadowing);
if let Some(shadowed_glob) = resolution.shadowed_glob {
// Forbid expanded shadowing to avoid time travel.
@@ -609,9 +609,9 @@
self.per_ns(|this, ns| {
let key = this.new_key(target, ns);
let _ = this.try_define(import.parent_scope.module, key, dummy_binding);
- // Consider erroneous imports used to avoid duplicate diagnostics.
- this.record_use(target, ns, dummy_binding, false);
});
+ // Consider erroneous imports used to avoid duplicate diagnostics.
+ self.record_use(target, dummy_binding, false);
}
}
}
@@ -709,7 +709,7 @@
}
} else if is_indeterminate {
// Consider erroneous imports used to avoid duplicate diagnostics.
- self.r.used_imports.insert((import.id, TypeNS));
+ self.r.used_imports.insert(import.id);
let path = import_path_to_string(
&import.module_path.iter().map(|seg| seg.ident).collect::<Vec<_>>(),
&import.kind,
@@ -902,7 +902,7 @@
import.vis.set(orig_vis);
if let PathResult::Failed { .. } | PathResult::NonModule(..) = path_res {
// Consider erroneous imports used to avoid duplicate diagnostics.
- self.r.used_imports.insert((import.id, TypeNS));
+ self.r.used_imports.insert(import.id);
}
let module = match path_res {
PathResult::Module(module) => {
@@ -1043,7 +1043,6 @@
{
this.record_use(
ident,
- ns,
target_binding,
import.module_path.is_empty(),
);
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index a21d819..6057396 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -383,6 +383,11 @@
/// Only used for better errors on `fn(): fn()`.
current_type_ascription: Vec<Span>,
+ /// Only used for better errors on `let x = { foo: bar };`.
+ /// In the case of a parse error with `let x = { foo: bar, };`, this isn't needed, it's only
+ /// needed for cases where this parses as a correct type ascription.
+ current_block_could_be_bare_struct_literal: Option<Span>,
+
/// Only used for better errors on `let <pat>: <expr, not type>;`.
current_let_binding: Option<(Span, Option<Span>, Option<Span>)>,
@@ -454,7 +459,7 @@
_ => Some((
local.pat.span,
local.ty.as_ref().map(|ty| ty.span),
- local.init.as_ref().map(|init| init.span),
+ local.kind.init().map(|init| init.span),
)),
};
let original = replace(&mut self.diagnostic_metadata.current_let_binding, local_spans);
@@ -952,6 +957,7 @@
match item.kind {
ItemKind::TyAlias(box TyAliasKind(_, ref generics, _, _))
| ItemKind::Fn(box FnKind(_, _, ref generics, _)) => {
+ self.compute_num_lifetime_params(item.id, generics);
self.with_generic_param_rib(generics, ItemRibKind(HasGenericParams::Yes), |this| {
visit::walk_item(this, item)
});
@@ -960,6 +966,7 @@
ItemKind::Enum(_, ref generics)
| ItemKind::Struct(_, ref generics)
| ItemKind::Union(_, ref generics) => {
+ self.compute_num_lifetime_params(item.id, generics);
self.resolve_adt(item, generics);
}
@@ -970,10 +977,12 @@
items: ref impl_items,
..
}) => {
+ self.compute_num_lifetime_params(item.id, generics);
self.resolve_implementation(generics, of_trait, &self_ty, item.id, impl_items);
}
ItemKind::Trait(box TraitKind(.., ref generics, ref bounds, ref trait_items)) => {
+ self.compute_num_lifetime_params(item.id, generics);
// 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();
@@ -1025,6 +1034,7 @@
}
ItemKind::TraitAlias(ref generics, ref bounds) => {
+ self.compute_num_lifetime_params(item.id, generics);
// 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();
@@ -1276,7 +1286,14 @@
this.with_self_rib(Res::SelfTy(None, None), |this| {
// Resolve the trait reference, if necessary.
this.with_optional_trait_ref(opt_trait_reference.as_ref(), |this, trait_id| {
- let item_def_id = this.r.local_def_id(item_id).to_def_id();
+ let item_def_id = this.r.local_def_id(item_id);
+
+ // Register the trait definitions from here.
+ if let Some(trait_id) = trait_id {
+ this.r.trait_impls.entry(trait_id).or_default().push(item_def_id);
+ }
+
+ let item_def_id = item_def_id.to_def_id();
this.with_self_rib(Res::SelfTy(trait_id, Some((item_def_id, false))), |this| {
if let Some(trait_ref) = opt_trait_reference.as_ref() {
// Resolve type arguments in the trait path.
@@ -1426,7 +1443,14 @@
walk_list!(self, visit_ty, &local.ty);
// Resolve the initializer.
- walk_list!(self, visit_expr, &local.init);
+ if let Some((init, els)) = local.kind.init_else_opt() {
+ self.visit_expr(init);
+
+ // Resolve the `else` block
+ if let Some(els) = els {
+ self.visit_block(els);
+ }
+ }
// Resolve the pattern.
self.resolve_pattern_top(&local.pat, PatternSource::Let);
@@ -1738,7 +1762,7 @@
// whether they can be shadowed by fresh bindings or not, so force an error.
// issues/33118#issuecomment-233962221 (see below) still applies here,
// but we have to ignore it for backward compatibility.
- self.r.record_use(ident, ValueNS, binding, false);
+ self.r.record_use(ident, binding, false);
return None;
}
LexicalScopeBinding::Item(binding) => (binding.res(), Some(binding)),
@@ -1753,7 +1777,7 @@
) if is_syntactic_ambiguity => {
// Disambiguate in favor of a unit struct/variant or constant pattern.
if let Some(binding) = binding {
- self.r.record_use(ident, ValueNS, binding, false);
+ self.r.record_use(ident, binding, false);
}
Some(res)
}
@@ -1852,6 +1876,7 @@
let instead = res.is_some();
let suggestion =
if res.is_none() { this.report_missing_type_error(path) } else { None };
+ // get_from_node_id
this.r.use_injections.push(UseError {
err,
@@ -2235,6 +2260,15 @@
self.ribs[ValueNS].push(Rib::new(NormalRibKind));
}
+ let prev = self.diagnostic_metadata.current_block_could_be_bare_struct_literal.take();
+ if let (true, [Stmt { kind: StmtKind::Expr(expr), .. }]) =
+ (block.could_be_bare_literal, &block.stmts[..])
+ {
+ if let ExprKind::Type(..) = expr.kind {
+ self.diagnostic_metadata.current_block_could_be_bare_struct_literal =
+ Some(block.span);
+ }
+ }
// Descend into the block.
for stmt in &block.stmts {
if let StmtKind::Item(ref item) = stmt.kind {
@@ -2248,6 +2282,7 @@
self.visit_stmt(stmt);
}
+ self.diagnostic_metadata.current_block_could_be_bare_struct_literal = prev;
// Move back up.
self.parent_scope.module = orig_module;
@@ -2309,7 +2344,7 @@
self.resolve_expr(e, Some(&expr));
}
- ExprKind::Let(ref pat, ref scrutinee) => {
+ ExprKind::Let(ref pat, ref scrutinee, _) => {
self.visit_expr(scrutinee);
self.resolve_pattern_top(pat, PatternSource::Let);
}
@@ -2456,6 +2491,16 @@
Some((ident.name, ns)),
)
}
+
+ fn compute_num_lifetime_params(&mut self, id: NodeId, generics: &Generics) {
+ let def_id = self.r.local_def_id(id);
+ let count = generics
+ .params
+ .iter()
+ .filter(|param| matches!(param.kind, ast::GenericParamKind::Lifetime { .. }))
+ .count();
+ self.r.item_generics_num_lifetimes.insert(def_id, count);
+ }
}
impl<'a> Resolver<'a> {
diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs
index 76979ab..b2c0c78 100644
--- a/compiler/rustc_resolve/src/late/diagnostics.rs
+++ b/compiler/rustc_resolve/src/late/diagnostics.rs
@@ -207,6 +207,16 @@
let code = source.error_code(res.is_some());
let mut err = self.r.session.struct_span_err_with_code(base_span, &base_msg, code);
+ if let Some(span) = self.diagnostic_metadata.current_block_could_be_bare_struct_literal {
+ err.multipart_suggestion(
+ "you might have meant to write a `struct` literal",
+ vec![
+ (span.shrink_to_lo(), "{ SomeStruct ".to_string()),
+ (span.shrink_to_hi(), "}".to_string()),
+ ],
+ Applicability::HasPlaceholders,
+ );
+ }
match (source, self.diagnostic_metadata.in_if_condition) {
(PathSource::Expr(_), Some(Expr { span, kind: ExprKind::Assign(..), .. })) => {
err.span_suggestion_verbose(
@@ -215,7 +225,6 @@
"let ".to_string(),
Applicability::MaybeIncorrect,
);
- self.r.session.if_let_suggestions.borrow_mut().insert(*span);
}
_ => {}
}
@@ -541,6 +550,10 @@
}
_ => {}
}
+
+ // If the trait has a single item (which wasn't matched by Levenshtein), suggest it
+ let suggestion = self.get_single_associated_item(&path, span, &source, is_expected);
+ self.r.add_typo_suggestion(&mut err, suggestion, ident_span);
}
if fallback {
// Fallback label.
@@ -585,6 +598,40 @@
(err, candidates)
}
+ fn get_single_associated_item(
+ &mut self,
+ path: &[Segment],
+ span: Span,
+ source: &PathSource<'_>,
+ filter_fn: &impl Fn(Res) -> bool,
+ ) -> Option<TypoSuggestion> {
+ if let crate::PathSource::TraitItem(_) = source {
+ let mod_path = &path[..path.len() - 1];
+ if let PathResult::Module(ModuleOrUniformRoot::Module(module)) =
+ self.resolve_path(mod_path, None, false, span, CrateLint::No)
+ {
+ let resolutions = self.r.resolutions(module).borrow();
+ let targets: Vec<_> =
+ resolutions
+ .iter()
+ .filter_map(|(key, resolution)| {
+ resolution.borrow().binding.map(|binding| binding.res()).and_then(
+ |res| if filter_fn(res) { Some((key, res)) } else { None },
+ )
+ })
+ .collect();
+ if targets.len() == 1 {
+ let target = targets[0];
+ return Some(TypoSuggestion::single_item_from_res(
+ target.0.ident.name,
+ target.1,
+ ));
+ }
+ }
+ }
+ None
+ }
+
/// Given `where <T as Bar>::Baz: String`, suggest `where T: Bar<Baz = String>`.
fn restrict_assoc_type_in_where_clause(
&mut self,
@@ -1061,7 +1108,7 @@
}
err.span_suggestion(
span,
- &format!("use this syntax instead"),
+ &"use this syntax instead",
format!("{path_str}"),
Applicability::MaybeIncorrect,
);
@@ -1208,7 +1255,7 @@
// Locals and type parameters
for (ident, &res) in &rib.bindings {
if filter_fn(res) {
- names.push(TypoSuggestion::from_res(ident.name, res));
+ names.push(TypoSuggestion::typo_from_res(ident.name, res));
}
}
// Items in scope
@@ -1231,7 +1278,9 @@
);
if filter_fn(crate_mod) {
- Some(TypoSuggestion::from_res(ident.name, crate_mod))
+ Some(TypoSuggestion::typo_from_res(
+ ident.name, crate_mod,
+ ))
} else {
None
}
@@ -1249,11 +1298,9 @@
}
// Add primitive types to the mix
if filter_fn(Res::PrimTy(PrimTy::Bool)) {
- names.extend(
- PrimTy::ALL.iter().map(|prim_ty| {
- TypoSuggestion::from_res(prim_ty.name(), Res::PrimTy(*prim_ty))
- }),
- )
+ names.extend(PrimTy::ALL.iter().map(|prim_ty| {
+ TypoSuggestion::typo_from_res(prim_ty.name(), Res::PrimTy(*prim_ty))
+ }))
}
} else {
// Search in module.
@@ -1788,7 +1835,7 @@
err.emit();
}
- // FIXME(const_generics): This patches over a ICE caused by non-'static lifetimes in const
+ // FIXME(const_generics): This patches over an ICE caused by non-'static lifetimes in const
// generics. We are disallowing this until we can decide on how we want to handle non-'static
// lifetimes in const generics. See issue #74052 for discussion.
crate fn emit_non_static_lt_in_const_generic_error(&self, lifetime_ref: &hir::Lifetime) {
@@ -2035,20 +2082,85 @@
continue;
}
});
+
+ struct Lifetime(Span, String);
+ impl Lifetime {
+ fn is_unnamed(&self) -> bool {
+ self.1.starts_with('&') && !self.1.starts_with("&'")
+ }
+ fn is_underscore(&self) -> bool {
+ self.1.starts_with("&'_ ")
+ }
+ fn is_named(&self) -> bool {
+ self.1.starts_with("&'")
+ }
+ fn suggestion(&self, sugg: String) -> Option<(Span, String)> {
+ Some(
+ match (
+ self.is_unnamed(),
+ self.is_underscore(),
+ self.is_named(),
+ sugg.starts_with('&'),
+ ) {
+ (true, _, _, false) => (self.span_unnamed_borrow(), sugg),
+ (true, _, _, true) => {
+ (self.span_unnamed_borrow(), sugg[1..].to_string())
+ }
+ (_, true, _, false) => {
+ (self.span_underscore_borrow(), sugg.trim().to_string())
+ }
+ (_, true, _, true) => {
+ (self.span_underscore_borrow(), sugg[1..].trim().to_string())
+ }
+ (_, _, true, false) => {
+ (self.span_named_borrow(), sugg.trim().to_string())
+ }
+ (_, _, true, true) => {
+ (self.span_named_borrow(), sugg[1..].trim().to_string())
+ }
+ _ => return None,
+ },
+ )
+ }
+ fn span_unnamed_borrow(&self) -> Span {
+ let lo = self.0.lo() + BytePos(1);
+ self.0.with_lo(lo).with_hi(lo)
+ }
+ fn span_named_borrow(&self) -> Span {
+ let lo = self.0.lo() + BytePos(1);
+ self.0.with_lo(lo)
+ }
+ fn span_underscore_borrow(&self) -> Span {
+ let lo = self.0.lo() + BytePos(1);
+ let hi = lo + BytePos(2);
+ self.0.with_lo(lo).with_hi(hi)
+ }
+ }
+
for param in params {
if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(param.span) {
- if snippet.starts_with('&') && !snippet.starts_with("&'") {
- introduce_suggestion
- .push((param.span, format!("&'a {}", &snippet[1..])));
- } else if let Some(stripped) = snippet.strip_prefix("&'_ ") {
- introduce_suggestion.push((param.span, format!("&'a {}", &stripped)));
+ if let Some((span, sugg)) =
+ Lifetime(param.span, snippet).suggestion("'a ".to_string())
+ {
+ introduce_suggestion.push((span, sugg));
}
}
}
- for ((span, _), sugg) in spans_with_counts.iter().copied().zip(suggs.iter()) {
- if let Some(sugg) = sugg {
- introduce_suggestion.push((span, sugg.to_string()));
- }
+ for (span, sugg) in spans_with_counts.iter().copied().zip(suggs.iter()).filter_map(
+ |((span, _), sugg)| match &sugg {
+ Some(sugg) => Some((span, sugg.to_string())),
+ _ => None,
+ },
+ ) {
+ let (span, sugg) = self
+ .tcx
+ .sess
+ .source_map()
+ .span_to_snippet(span)
+ .ok()
+ .and_then(|snippet| Lifetime(span, snippet).suggestion(sugg.clone()))
+ .unwrap_or((span, sugg));
+ introduce_suggestion.push((span, sugg.to_string()));
}
err.multipart_suggestion_with_style(
&msg,
@@ -2121,7 +2233,8 @@
for ((span, _), snippet) in spans_with_counts.iter().copied().zip(snippets.iter()) {
match snippet.as_deref() {
Some("") => spans_suggs.push((span, "'lifetime, ".to_string())),
- Some("&") => spans_suggs.push((span, "&'lifetime ".to_string())),
+ Some("&") => spans_suggs
+ .push((span.with_lo(span.lo() + BytePos(1)), "'lifetime ".to_string())),
_ => {}
}
}
@@ -2142,7 +2255,7 @@
}
/// 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
+ /// This function will emit an error if `generic_const_exprs` 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,
@@ -2161,7 +2274,7 @@
if !self.tcx.lazy_normalization() && is_anon_const && !is_allowed_lifetime {
feature_err(
&self.tcx.sess.parse_sess,
- sym::const_generics,
+ sym::generic_const_exprs,
lifetime_ref.span,
"a non-static lifetime is not allowed in a `const`",
)
diff --git a/compiler/rustc_resolve/src/late/lifetimes.rs b/compiler/rustc_resolve/src/late/lifetimes.rs
index ca7cdc4..4c1d537 100644
--- a/compiler/rustc_resolve/src/late/lifetimes.rs
+++ b/compiler/rustc_resolve/src/late/lifetimes.rs
@@ -740,6 +740,7 @@
hir::ItemKind::ExternCrate(_)
| hir::ItemKind::Use(..)
+ | hir::ItemKind::Macro(..)
| hir::ItemKind::Mod(..)
| hir::ItemKind::ForeignMod { .. }
| hir::ItemKind::GlobalAsm(..) => {
@@ -1015,24 +1016,17 @@
let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id);
// Ensure that the parent of the def is an item, not HRTB
let parent_id = self.tcx.hir().get_parent_node(hir_id);
- let parent_is_item = if let Some(parent_def_id) =
- parent_id.as_owner()
- {
- let parent_item_id = hir::ItemId { def_id: parent_def_id };
- let parent_impl_id = hir::ImplItemId { def_id: parent_def_id };
- let parent_trait_id =
- hir::TraitItemId { def_id: parent_def_id };
- let parent_foreign_id =
- hir::ForeignItemId { def_id: parent_def_id };
- let krate = self.tcx.hir().krate();
-
- krate.items.contains_key(&parent_item_id)
- || krate.impl_items.contains_key(&parent_impl_id)
- || krate.trait_items.contains_key(&parent_trait_id)
- || krate.foreign_items.contains_key(&parent_foreign_id)
- } else {
- false
- };
+ // FIXME(cjgillot) Can this check be replaced by
+ // `let parent_is_item = parent_id.is_owner();`?
+ let parent_is_item =
+ if let Some(parent_def_id) = parent_id.as_owner() {
+ matches!(
+ self.tcx.hir().krate().owners.get(parent_def_id),
+ Some(Some(_)),
+ )
+ } else {
+ false
+ };
if !parent_is_item {
if !self.trait_definition_only {
@@ -2064,9 +2058,13 @@
if let Some(def_id) = parent_def_id.as_local() {
let parent_hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id);
// lifetimes in `derive` expansions don't count (Issue #53738)
- if self.tcx.hir().attrs(parent_hir_id).iter().any(|attr| {
- self.tcx.sess.check_name(attr, sym::automatically_derived)
- }) {
+ if self
+ .tcx
+ .hir()
+ .attrs(parent_hir_id)
+ .iter()
+ .any(|attr| attr.has_name(sym::automatically_derived))
+ {
continue;
}
}
@@ -2303,7 +2301,7 @@
match *scope {
Scope::Body { id, s } => {
// Non-static lifetimes are prohibited in anonymous constants without
- // `const_generics`.
+ // `generic_const_exprs`.
self.maybe_emit_forbidden_non_static_lifetime_error(id, lifetime_ref);
outermost_body = Some(id);
@@ -2557,6 +2555,12 @@
GenericArg::Const(ct) => {
self.visit_anon_const(&ct.value);
}
+ GenericArg::Infer(inf) => {
+ self.visit_id(inf.hir_id);
+ if inf.kind.is_type() {
+ i += 1;
+ }
+ }
}
}
@@ -2601,8 +2605,10 @@
binding.ident,
);
self.with(scope, |_, this| {
- let scope =
- Scope::Supertrait { lifetimes: lifetimes.unwrap_or(vec![]), s: this.scope };
+ let scope = Scope::Supertrait {
+ lifetimes: lifetimes.unwrap_or_default(),
+ s: this.scope,
+ };
this.with(scope, |_, this| this.visit_assoc_type_binding(binding));
});
} else {
@@ -2658,7 +2664,7 @@
let obligations = predicates.predicates.iter().filter_map(|&(pred, _)| {
let bound_predicate = pred.kind();
match bound_predicate.skip_binder() {
- ty::PredicateKind::Trait(data, _) => {
+ ty::PredicateKind::Trait(data) => {
// The order here needs to match what we would get from `subst_supertrait`
let pred_bound_vars = bound_predicate.bound_vars();
let mut all_bound_vars = bound_vars.clone();
@@ -2688,15 +2694,14 @@
Scope::Binder { hir_id, .. } => {
break *hir_id;
}
- Scope::Body { id, .. } => break id.hir_id,
Scope::ObjectLifetimeDefault { ref s, .. }
| Scope::Elision { ref s, .. }
| Scope::Supertrait { ref s, .. }
| Scope::TraitRefBoundary { ref s, .. } => {
scope = *s;
}
- Scope::Root => {
- // See issue #83907. Just bail out from looking inside.
+ Scope::Root | Scope::Body { .. } => {
+ // See issues #83907 and #83693. Just bail out from looking inside.
self.tcx.sess.delay_span_bug(
rustc_span::DUMMY_SP,
"In fn_like_elision without appropriate scope above",
diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs
index 7114fd3..152d34f 100644
--- a/compiler/rustc_resolve/src/lib.rs
+++ b/compiler/rustc_resolve/src/lib.rs
@@ -60,7 +60,7 @@
use smallvec::{smallvec, SmallVec};
use std::cell::{Cell, RefCell};
-use std::collections::BTreeSet;
+use std::collections::{BTreeMap, BTreeSet};
use std::ops::ControlFlow;
use std::{cmp, fmt, iter, ptr};
use tracing::debug;
@@ -668,7 +668,7 @@
}
impl<'a> NameBindingKind<'a> {
- /// Is this a name binding of a import?
+ /// Is this a name binding of an import?
fn is_import(&self) -> bool {
matches!(*self, NameBindingKind::Import { .. })
}
@@ -942,7 +942,7 @@
glob_map: FxHashMap<LocalDefId, FxHashSet<Symbol>>,
/// Visibilities in "lowered" form, for all entities that have them.
visibilities: FxHashMap<LocalDefId, ty::Visibility>,
- used_imports: FxHashSet<(NodeId, Namespace)>,
+ used_imports: FxHashSet<NodeId>,
maybe_unused_trait_imports: FxHashSet<LocalDefId>,
maybe_unused_extern_crates: Vec<(LocalDefId, Span)>,
@@ -968,7 +968,7 @@
macro_map: FxHashMap<DefId, Lrc<SyntaxExtension>>,
dummy_ext_bang: Lrc<SyntaxExtension>,
dummy_ext_derive: Lrc<SyntaxExtension>,
- non_macro_attrs: [Lrc<SyntaxExtension>; 2],
+ non_macro_attr: Lrc<SyntaxExtension>,
local_macro_def_scopes: FxHashMap<LocalDefId, Module<'a>>,
ast_transform_scopes: FxHashMap<LocalExpnId, Module<'a>>,
unused_macros: FxHashMap<LocalDefId, (NodeId, Span)>,
@@ -1030,8 +1030,14 @@
trait_impl_items: FxHashSet<LocalDefId>,
legacy_const_generic_args: FxHashMap<DefId, Option<Vec<usize>>>,
+ /// Amount of lifetime parameters for each item in the crate.
+ item_generics_num_lifetimes: FxHashMap<LocalDefId, usize>,
main_def: Option<MainDefinition>,
+ trait_impls: BTreeMap<DefId, Vec<LocalDefId>>,
+ /// A list of proc macro LocalDefIds, written out in the order in which
+ /// they are declared in the static array generated by proc_macro_harness.
+ proc_macros: Vec<NodeId>,
}
/// Nothing really interesting here; it just provides memory for the rest of the crate.
@@ -1109,8 +1115,12 @@
}
}
- fn item_generics_num_lifetimes(&self, def_id: DefId, sess: &Session) -> usize {
- self.cstore().item_generics_num_lifetimes(def_id, sess)
+ fn item_generics_num_lifetimes(&self, def_id: DefId) -> usize {
+ if let Some(def_id) = def_id.as_local() {
+ self.item_generics_num_lifetimes[&def_id]
+ } else {
+ self.cstore().item_generics_num_lifetimes(def_id, self.session)
+ }
}
fn legacy_const_generic_args(&mut self, expr: &Expr) -> Option<Vec<usize>> {
@@ -1293,8 +1303,6 @@
macros::registered_attrs_and_tools(session, &krate.attrs);
let features = session.features_untracked();
- let non_macro_attr =
- |mark_used| Lrc::new(SyntaxExtension::non_macro_attr(mark_used, session.edition()));
let mut resolver = Resolver {
session,
@@ -1361,7 +1369,7 @@
macro_map: FxHashMap::default(),
dummy_ext_bang: Lrc::new(SyntaxExtension::dummy_bang(session.edition())),
dummy_ext_derive: Lrc::new(SyntaxExtension::dummy_derive(session.edition())),
- non_macro_attrs: [non_macro_attr(false), non_macro_attr(true)],
+ non_macro_attr: Lrc::new(SyntaxExtension::non_macro_attr(session.edition())),
invocation_parent_scopes: Default::default(),
output_macro_rules_scopes: Default::default(),
helper_attrs: Default::default(),
@@ -1392,7 +1400,10 @@
next_disambiguator: Default::default(),
trait_impl_items: Default::default(),
legacy_const_generic_args: Default::default(),
+ item_generics_num_lifetimes: Default::default(),
main_def: Default::default(),
+ trait_impls: Default::default(),
+ proc_macros: Default::default(),
};
let root_parent_scope = ParentScope::module(graph_root, &resolver);
@@ -1427,6 +1438,7 @@
}
pub fn into_outputs(self) -> ResolverOutputs {
+ let proc_macros = self.proc_macros.iter().map(|id| self.local_def_id(*id)).collect();
let definitions = self.definitions;
let visibilities = self.visibilities;
let extern_crate_map = self.extern_crate_map;
@@ -1450,10 +1462,13 @@
.map(|(ident, entry)| (ident.name, entry.introduced_by_item))
.collect(),
main_def,
+ trait_impls: self.trait_impls,
+ proc_macros,
}
}
pub fn clone_outputs(&self) -> ResolverOutputs {
+ let proc_macros = self.proc_macros.iter().map(|id| self.local_def_id(*id)).collect();
ResolverOutputs {
definitions: self.definitions.clone(),
cstore: Box::new(self.cstore().clone()),
@@ -1469,6 +1484,8 @@
.map(|(ident, entry)| (ident.name, entry.introduced_by_item))
.collect(),
main_def: self.main_def.clone(),
+ trait_impls: self.trait_impls.clone(),
+ proc_macros,
}
}
@@ -1476,15 +1493,11 @@
self.crate_loader.cstore()
}
- fn non_macro_attr(&self, mark_used: bool) -> Lrc<SyntaxExtension> {
- self.non_macro_attrs[mark_used as usize].clone()
- }
-
fn dummy_ext(&self, macro_kind: MacroKind) -> Lrc<SyntaxExtension> {
match macro_kind {
MacroKind::Bang => self.dummy_ext_bang.clone(),
MacroKind::Derive => self.dummy_ext_derive.clone(),
- MacroKind::Attr => self.non_macro_attr(true),
+ MacroKind::Attr => self.non_macro_attr.clone(),
}
}
@@ -1656,7 +1669,6 @@
fn record_use(
&mut self,
ident: Ident,
- ns: Namespace,
used_binding: &'a NameBinding<'a>,
is_lexical_scope: bool,
) {
@@ -1684,9 +1696,9 @@
}
used.set(true);
import.used.set(true);
- self.used_imports.insert((import.id, ns));
+ self.used_imports.insert(import.id);
self.add_to_glob_map(&import, ident);
- self.record_use(ident, ns, binding, false);
+ self.record_use(ident, binding, false);
}
}
@@ -2741,10 +2753,7 @@
ConstantItemRibKind(trivial, _) => {
let features = self.session.features_untracked();
// HACK(min_const_generics): We currently only allow `N` or `{ N }`.
- if !(trivial
- || features.const_generics
- || features.lazy_normalization_consts)
- {
+ if !(trivial || features.generic_const_exprs) {
// 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.
@@ -2816,10 +2825,7 @@
ConstantItemRibKind(trivial, _) => {
let features = self.session.features_untracked();
// HACK(min_const_generics): We currently only allow `N` or `{ N }`.
- if !(trivial
- || features.const_generics
- || features.lazy_normalization_consts)
- {
+ if !(trivial || features.generic_const_exprs) {
if record_used {
self.report_error(
span,
@@ -3066,7 +3072,7 @@
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.
+ // been introduced by an item.
let should_remove_import = duplicate
&& !has_dummy_span
&& ((new_binding.is_extern_crate() || old_binding.is_extern_crate()) || from_item);
@@ -3161,7 +3167,7 @@
}
}
- /// This function adds a suggestion to remove a unnecessary binding from an import that is
+ /// This function adds a suggestion to remove an unnecessary binding from an import that is
/// nested. In the following example, this function will be invoked to remove the `a` binding
/// in the second use statement:
///
@@ -3213,7 +3219,7 @@
Applicability::MaybeIncorrect,
);
} else {
- // Remove the entire line if we cannot extend the span back, this indicates a
+ // Remove the entire line if we cannot extend the span back, this indicates an
// `issue_52891::{self}` case.
err.span_suggestion(
import.use_span_with_attributes,
@@ -3241,7 +3247,7 @@
self.extern_prelude.get(&ident.normalize_to_macros_2_0()).cloned().and_then(|entry| {
if let Some(binding) = entry.extern_crate_item {
if !speculative && entry.introduced_by_item {
- self.record_use(ident, TypeNS, binding, false);
+ self.record_use(ident, binding, false);
}
Some(binding)
} else {
@@ -3382,9 +3388,8 @@
let parse_attrs = || {
let attrs = self.cstore().item_attrs(def_id, self.session);
- let attr = attrs
- .iter()
- .find(|a| self.session.check_name(a, sym::rustc_legacy_const_generics))?;
+ let attr =
+ attrs.iter().find(|a| a.has_name(sym::rustc_legacy_const_generics))?;
let mut ret = vec![];
for meta in attr.meta_item_list()? {
match meta.literal()?.kind {
@@ -3428,7 +3433,7 @@
let is_import = name_binding.is_import();
let span = name_binding.span;
if let Res::Def(DefKind::Fn, _) = res {
- self.record_use(ident, ValueNS, name_binding, false);
+ self.record_use(ident, name_binding, false);
}
self.main_def = Some(MainDefinition { res, is_import, span });
}
diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs
index b2a8aa0..6dc3aa0 100644
--- a/compiler/rustc_resolve/src/macros.rs
+++ b/compiler/rustc_resolve/src/macros.rs
@@ -466,6 +466,10 @@
fn get_proc_macro_quoted_span(&self, krate: CrateNum, id: usize) -> Span {
self.crate_loader.cstore().get_proc_macro_quoted_span_untracked(krate, id, self.session)
}
+
+ fn declare_proc_macro(&mut self, id: NodeId) {
+ self.proc_macros.push(id)
+ }
}
impl<'a> Resolver<'a> {
@@ -1090,7 +1094,7 @@
) {
Ok(binding) => {
let initial_res = initial_binding.map(|initial_binding| {
- self.record_use(ident, MacroNS, initial_binding, false);
+ self.record_use(ident, initial_binding, false);
initial_binding.res()
});
let res = binding.res();
diff --git a/compiler/rustc_save_analysis/Cargo.toml b/compiler/rustc_save_analysis/Cargo.toml
index da1bed3..535a48b 100644
--- a/compiler/rustc_save_analysis/Cargo.toml
+++ b/compiler/rustc_save_analysis/Cargo.toml
@@ -1,5 +1,4 @@
[package]
-authors = ["The Rust Project Developers"]
name = "rustc_save_analysis"
version = "0.0.0"
edition = "2018"
diff --git a/compiler/rustc_save_analysis/src/dump_visitor.rs b/compiler/rustc_save_analysis/src/dump_visitor.rs
index 842f7f9..2906876 100644
--- a/compiler/rustc_save_analysis/src/dump_visitor.rs
+++ b/compiler/rustc_save_analysis/src/dump_visitor.rs
@@ -146,7 +146,7 @@
},
crate_root: crate_root.unwrap_or_else(|| "<no source>".to_owned()),
external_crates: self.save_ctxt.get_external_crates(),
- span: self.span_from_span(krate.item.inner),
+ span: self.span_from_span(krate.module().inner),
};
self.dumper.crate_prelude(data);
@@ -185,7 +185,7 @@
};
let data = CompilationOptions {
- directory: self.tcx.sess.working_dir.remapped_path_if_available().into(),
+ directory: self.tcx.sess.opts.working_dir.remapped_path_if_available().into(),
program,
arguments,
output: self.save_ctxt.compilation_output(crate_name),
@@ -255,16 +255,17 @@
&mut self,
sig: &'tcx hir::FnSig<'tcx>,
body: Option<hir::BodyId>,
- hir_id: hir::HirId,
+ def_id: LocalDefId,
ident: Ident,
generics: &'tcx hir::Generics<'tcx>,
vis: &hir::Visibility<'tcx>,
span: Span,
) {
- debug!("process_method: {}:{}", hir_id, ident);
+ debug!("process_method: {:?}:{}", def_id, ident);
let map = &self.tcx.hir();
- self.nest_typeck_results(map.local_def_id(hir_id), |v| {
+ let hir_id = map.local_def_id_to_hir_id(def_id);
+ self.nest_typeck_results(def_id, |v| {
if let Some(mut method_data) = v.save_ctxt.get_method_data(hir_id, ident, span) {
if let Some(body) = body {
v.process_formals(map.body(body).params, &method_data.qualname);
@@ -275,7 +276,7 @@
fn_to_string(sig.decl, sig.header, Some(ident.name), generics, vis, &[], None);
method_data.sig = sig::method_signature(hir_id, ident, generics, sig, &v.save_ctxt);
- v.dumper.dump_def(&access_from_vis!(v.save_ctxt, vis, hir_id), method_data);
+ v.dumper.dump_def(&access_from_vis!(v.save_ctxt, vis, def_id), method_data);
}
// walk arg and return types
@@ -301,7 +302,10 @@
) {
let field_data = self.save_ctxt.get_field_data(field, parent_id);
if let Some(field_data) = field_data {
- self.dumper.dump_def(&access_from!(self.save_ctxt, field, field.hir_id), field_data);
+ self.dumper.dump_def(
+ &access_from!(self.save_ctxt, field, self.tcx.hir().local_def_id(field.hir_id)),
+ field_data,
+ );
}
}
@@ -366,7 +370,7 @@
v.process_formals(body.params, &fn_data.qualname);
v.process_generic_params(ty_params, &fn_data.qualname, item.hir_id());
- v.dumper.dump_def(&access_from!(v.save_ctxt, item, item.hir_id()), fn_data);
+ v.dumper.dump_def(&access_from!(v.save_ctxt, item, item.def_id), fn_data);
}
for arg in decl.inputs {
@@ -390,7 +394,7 @@
self.nest_typeck_results(item.def_id, |v| {
if let Some(var_data) = v.save_ctxt.get_item_data(item) {
down_cast_data!(var_data, DefData, item.span);
- v.dumper.dump_def(&access_from!(v.save_ctxt, item, item.hir_id()), var_data);
+ v.dumper.dump_def(&access_from!(v.save_ctxt, item, item.def_id), var_data);
}
v.visit_ty(&typ);
v.visit_expr(expr);
@@ -399,7 +403,7 @@
fn process_assoc_const(
&mut self,
- hir_id: hir::HirId,
+ def_id: LocalDefId,
ident: Ident,
typ: &'tcx hir::Ty<'tcx>,
expr: Option<&'tcx hir::Expr<'tcx>>,
@@ -407,15 +411,15 @@
vis: &hir::Visibility<'tcx>,
attrs: &'tcx [ast::Attribute],
) {
- let qualname =
- format!("::{}", self.tcx.def_path_str(self.tcx.hir().local_def_id(hir_id).to_def_id()));
+ let qualname = format!("::{}", self.tcx.def_path_str(def_id.to_def_id()));
if !self.span.filter_generated(ident.span) {
+ let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id);
let sig = sig::assoc_const_signature(hir_id, ident.name, typ, expr, &self.save_ctxt);
let span = self.span_from_span(ident.span);
self.dumper.dump_def(
- &access_from_vis!(self.save_ctxt, vis, hir_id),
+ &access_from_vis!(self.save_ctxt, vis, def_id),
Def {
kind: DefKind::Const,
id: id_from_hir_id(hir_id, &self.save_ctxt),
@@ -434,7 +438,7 @@
}
// walk type and init value
- self.nest_typeck_results(self.tcx.hir().local_def_id(hir_id), |v| {
+ self.nest_typeck_results(def_id, |v| {
v.visit_ty(typ);
if let Some(expr) = expr {
v.visit_expr(expr);
@@ -484,7 +488,7 @@
let span = self.span_from_span(item.ident.span);
let attrs = self.tcx.hir().attrs(item.hir_id());
self.dumper.dump_def(
- &access_from!(self.save_ctxt, item, item.hir_id()),
+ &access_from!(self.save_ctxt, item, item.def_id),
Def {
kind,
id: id_from_def_id(item.def_id.to_def_id()),
@@ -525,7 +529,7 @@
};
down_cast_data!(enum_data, DefData, item.span);
- let access = access_from!(self.save_ctxt, item, item.hir_id());
+ let access = access_from!(self.save_ctxt, item, item.def_id);
for variant in enum_definition.variants {
let name = variant.ident.name.to_string();
@@ -660,7 +664,7 @@
methods.iter().map(|i| id_from_def_id(i.id.def_id.to_def_id())).collect();
let attrs = self.tcx.hir().attrs(item.hir_id());
self.dumper.dump_def(
- &access_from!(self.save_ctxt, item, item.hir_id()),
+ &access_from!(self.save_ctxt, item, item.def_id),
Def {
kind: DefKind::Trait,
id,
@@ -689,6 +693,7 @@
(Some(self.tcx.require_lang_item(lang_item, Some(span))), span)
}
hir::GenericBound::Outlives(..) => continue,
+ hir::GenericBound::Unsized(_) => continue,
};
if let Some(id) = def_id {
@@ -722,7 +727,7 @@
fn process_mod(&mut self, item: &'tcx hir::Item<'tcx>) {
if let Some(mod_data) = self.save_ctxt.get_item_data(item) {
down_cast_data!(mod_data, DefData, item.span);
- self.dumper.dump_def(&access_from!(self.save_ctxt, item, item.hir_id()), mod_data);
+ self.dumper.dump_def(&access_from!(self.save_ctxt, item, item.def_id), mod_data);
}
}
@@ -984,7 +989,7 @@
let respan = respan(vis_span, hir::VisibilityKind::Public);
let attrs = self.tcx.hir().attrs(trait_item.hir_id());
self.process_assoc_const(
- trait_item.hir_id(),
+ trait_item.def_id,
trait_item.ident,
&ty,
body,
@@ -1000,7 +1005,7 @@
self.process_method(
sig,
body,
- trait_item.hir_id(),
+ trait_item.def_id,
trait_item.ident,
&trait_item.generics,
&respan,
@@ -1057,7 +1062,7 @@
let body = self.tcx.hir().body(body);
let attrs = self.tcx.hir().attrs(impl_item.hir_id());
self.process_assoc_const(
- impl_item.hir_id(),
+ impl_item.def_id,
impl_item.ident,
&ty,
Some(&body.value),
@@ -1070,7 +1075,7 @@
self.process_method(
sig,
Some(body),
- impl_item.hir_id(),
+ impl_item.def_id,
impl_item.ident,
&impl_item.generics,
&impl_item.vis,
@@ -1092,11 +1097,12 @@
format!("::{}", self.tcx.def_path_str(self.tcx.hir().local_def_id(id).to_def_id()));
let sm = self.tcx.sess.source_map();
- let filename = sm.span_to_filename(krate.item.inner);
+ let krate_mod = krate.module();
+ let filename = sm.span_to_filename(krate_mod.inner);
let data_id = id_from_hir_id(id, &self.save_ctxt);
let children =
- krate.item.item_ids.iter().map(|i| id_from_def_id(i.def_id.to_def_id())).collect();
- let span = self.span_from_span(krate.item.inner);
+ krate_mod.item_ids.iter().map(|i| id_from_def_id(i.def_id.to_def_id())).collect();
+ let span = self.span_from_span(krate_mod.inner);
let attrs = self.tcx.hir().attrs(id);
self.dumper.dump_def(
@@ -1144,7 +1150,7 @@
hir::ItemKind::Use(path, hir::UseKind::Single) => {
let sub_span = path.segments.last().unwrap().ident.span;
if !self.span.filter_generated(sub_span) {
- let access = access_from!(self.save_ctxt, item, item.hir_id());
+ let access = access_from!(self.save_ctxt, item, item.def_id);
let ref_id = self.lookup_def_id(item.hir_id()).map(id_from_def_id);
let span = self.span_from_span(sub_span);
let parent =
@@ -1173,7 +1179,7 @@
// we don't want to track anyway, since it's probably macro-internal `use`
if let Some(sub_span) = self.span.sub_span_of_star(item.span) {
if !self.span.filter_generated(item.span) {
- let access = access_from!(self.save_ctxt, item, item.hir_id());
+ let access = access_from!(self.save_ctxt, item, item.def_id);
let span = self.span_from_span(sub_span);
let parent =
self.save_ctxt.tcx.parent(item.def_id.to_def_id()).map(id_from_def_id);
@@ -1246,7 +1252,7 @@
let attrs = self.tcx.hir().attrs(item.hir_id());
self.dumper.dump_def(
- &access_from!(self.save_ctxt, item, item.hir_id()),
+ &access_from!(self.save_ctxt, item, item.def_id),
Def {
kind: DefKind::Type,
id,
@@ -1430,7 +1436,7 @@
}
fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem<'tcx>) {
- let access = access_from!(self.save_ctxt, item, item.hir_id());
+ let access = access_from!(self.save_ctxt, item, item.def_id);
match item.kind {
hir::ForeignItemKind::Fn(decl, _, ref generics) => {
diff --git a/compiler/rustc_save_analysis/src/lib.rs b/compiler/rustc_save_analysis/src/lib.rs
index 0a8a881..41d174c 100644
--- a/compiler/rustc_save_analysis/src/lib.rs
+++ b/compiler/rustc_save_analysis/src/lib.rs
@@ -1,5 +1,7 @@
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
+#![feature(if_let_guard)]
#![feature(nll)]
+#![cfg_attr(bootstrap, allow(incomplete_features))] // if_let_guard
#![recursion_limit = "256"]
mod dump_visitor;
@@ -326,54 +328,53 @@
attributes: lower_attributes(attrs.to_vec(), self),
}))
}
- 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) {
- return None;
- }
- let sub_span = path.segments.last().unwrap().ident.span;
- filter!(self.span_utils, sub_span);
-
- let impl_id = self.next_impl_id();
- let span = self.span_from_span(sub_span);
-
- let type_data = self.lookup_def_id(self_ty.hir_id);
- type_data.map(|type_data| {
- Data::RelationData(
- Relation {
- kind: RelationKind::Impl { id: impl_id },
- span: span.clone(),
- from: id_from_def_id(type_data),
- to: of_trait
- .as_ref()
- .and_then(|t| self.lookup_def_id(t.hir_ref_id))
- .map(id_from_def_id)
- .unwrap_or_else(null_id),
- },
- Impl {
- id: impl_id,
- kind: match *of_trait {
- Some(_) => ImplKind::Direct,
- None => ImplKind::Inherent,
- },
- span,
- value: String::new(),
- parent: None,
- children: items
- .iter()
- .map(|i| id_from_def_id(i.id.def_id.to_def_id()))
- .collect(),
- docs: String::new(),
- sig: None,
- attributes: vec![],
- },
- )
- })
- } else {
- None
+ 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) {
+ return None;
}
+ let sub_span = path.segments.last().unwrap().ident.span;
+ filter!(self.span_utils, sub_span);
+
+ let impl_id = self.next_impl_id();
+ let span = self.span_from_span(sub_span);
+
+ let type_data = self.lookup_def_id(self_ty.hir_id);
+ type_data.map(|type_data| {
+ Data::RelationData(
+ Relation {
+ kind: RelationKind::Impl { id: impl_id },
+ span: span.clone(),
+ from: id_from_def_id(type_data),
+ to: of_trait
+ .as_ref()
+ .and_then(|t| self.lookup_def_id(t.hir_ref_id))
+ .map(id_from_def_id)
+ .unwrap_or_else(null_id),
+ },
+ Impl {
+ id: impl_id,
+ kind: match *of_trait {
+ Some(_) => ImplKind::Direct,
+ None => ImplKind::Inherent,
+ },
+ span,
+ value: String::new(),
+ parent: None,
+ children: items
+ .iter()
+ .map(|i| id_from_def_id(i.id.def_id.to_def_id()))
+ .collect(),
+ docs: String::new(),
+ sig: None,
+ attributes: vec![],
+ },
+ )
+ })
}
+ hir::ItemKind::Impl(_) => None,
_ => {
// FIXME
bug!();
diff --git a/compiler/rustc_save_analysis/src/sig.rs b/compiler/rustc_save_analysis/src/sig.rs
index c3bc1c1..7864b47 100644
--- a/compiler/rustc_save_analysis/src/sig.rs
+++ b/compiler/rustc_save_analysis/src/sig.rs
@@ -416,6 +416,14 @@
Ok(sig)
}
+ hir::ItemKind::Macro(_) => {
+ let mut text = "macro".to_owned();
+ let name = self.ident.to_string();
+ text.push_str(&name);
+ text.push_str(&"! {}");
+
+ Ok(text_sig(text))
+ }
hir::ItemKind::Mod(ref _mod) => {
let mut text = "mod ".to_owned();
let name = self.ident.to_string();
diff --git a/compiler/rustc_save_analysis/src/span_utils.rs b/compiler/rustc_save_analysis/src/span_utils.rs
index 1947b04..8d6758f 100644
--- a/compiler/rustc_save_analysis/src/span_utils.rs
+++ b/compiler/rustc_save_analysis/src/span_utils.rs
@@ -27,6 +27,7 @@
.to_string()
} else {
self.sess
+ .opts
.working_dir
.remapped_path_if_available()
.join(&path)
diff --git a/compiler/rustc_serialize/Cargo.toml b/compiler/rustc_serialize/Cargo.toml
index 05fc6a4..593a756 100644
--- a/compiler/rustc_serialize/Cargo.toml
+++ b/compiler/rustc_serialize/Cargo.toml
@@ -1,5 +1,4 @@
[package]
-authors = ["The Rust Project Developers"]
name = "rustc_serialize"
version = "0.0.0"
edition = "2018"
diff --git a/compiler/rustc_serialize/src/json.rs b/compiler/rustc_serialize/src/json.rs
index 4d21320..e5369b4 100644
--- a/compiler/rustc_serialize/src/json.rs
+++ b/compiler/rustc_serialize/src/json.rs
@@ -1202,7 +1202,7 @@
matches!(*self, Json::I64(_) | Json::U64(_) | Json::F64(_))
}
- /// Returns `true` if the Json value is a `i64`.
+ /// Returns `true` if the Json value is an `i64`.
pub fn is_i64(&self) -> bool {
matches!(*self, Json::I64(_))
}
@@ -1217,7 +1217,7 @@
matches!(*self, Json::F64(_))
}
- /// If the Json value is a number, returns or cast it to a `i64`;
+ /// If the Json value is a number, returns or cast it to an `i64`;
/// returns `None` otherwise.
pub fn as_i64(&self) -> Option<i64> {
match *self {
diff --git a/compiler/rustc_serialize/src/lib.rs b/compiler/rustc_serialize/src/lib.rs
index c79786a..b31fbab 100644
--- a/compiler/rustc_serialize/src/lib.rs
+++ b/compiler/rustc_serialize/src/lib.rs
@@ -9,7 +9,6 @@
html_playground_url = "https://play.rust-lang.org/",
test(attr(allow(unused_variables), deny(warnings)))
)]
-#![feature(box_syntax)]
#![feature(never_type)]
#![feature(nll)]
#![feature(associated_type_bounds)]
diff --git a/compiler/rustc_serialize/src/serialize.rs b/compiler/rustc_serialize/src/serialize.rs
index bb3c537..ecc8dae 100644
--- a/compiler/rustc_serialize/src/serialize.rs
+++ b/compiler/rustc_serialize/src/serialize.rs
@@ -644,7 +644,7 @@
}
// FIXME: #15036
-// Should use `try_borrow`, returning a
+// Should use `try_borrow`, returning an
// `encoder.error("attempting to Encode borrowed RefCell")`
// from `encode` when `try_borrow` returns `None`.
@@ -679,6 +679,6 @@
}
impl<D: Decoder, T: Decodable<D>> Decodable<D> for Box<T> {
fn decode(d: &mut D) -> Result<Box<T>, D::Error> {
- Ok(box Decodable::decode(d)?)
+ Ok(Box::new(Decodable::decode(d)?))
}
}
diff --git a/compiler/rustc_session/Cargo.toml b/compiler/rustc_session/Cargo.toml
index 571fd58..5b617a2 100644
--- a/compiler/rustc_session/Cargo.toml
+++ b/compiler/rustc_session/Cargo.toml
@@ -1,5 +1,4 @@
[package]
-authors = ["The Rust Project Developers"]
name = "rustc_session"
version = "0.0.0"
edition = "2018"
diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs
index 2d7f5f9..fdedb7e 100644
--- a/compiler/rustc_session/src/config.rs
+++ b/compiler/rustc_session/src/config.rs
@@ -21,6 +21,7 @@
use rustc_span::edition::{Edition, DEFAULT_EDITION, EDITION_NAME_LIST, LATEST_STABLE_EDITION};
use rustc_span::source_map::{FileName, FilePathMapping};
use rustc_span::symbol::{sym, Symbol};
+use rustc_span::RealFileName;
use rustc_span::SourceFileHashAlgorithm;
use rustc_errors::emitter::HumanReadableErrorType;
@@ -707,6 +708,7 @@
json_artifact_notifications: false,
json_unused_externs: false,
pretty: None,
+ working_dir: RealFileName::LocalPath(std::env::current_dir().unwrap()),
}
}
}
@@ -1087,10 +1089,11 @@
),
opt::flag_s("", "test", "Build a test harness"),
opt::opt_s("", "target", "Target triple for which the code is compiled", "TARGET"),
- opt::multi_s("W", "warn", "Set lint warnings", "OPT"),
- opt::multi_s("A", "allow", "Set lint allowed", "OPT"),
- opt::multi_s("D", "deny", "Set lint denied", "OPT"),
- opt::multi_s("F", "forbid", "Set lint forbidden", "OPT"),
+ opt::multi_s("A", "allow", "Set lint allowed", "LINT"),
+ opt::multi_s("W", "warn", "Set lint warnings", "LINT"),
+ opt::multi_s("", "force-warn", "Set lint force-warn", "LINT"),
+ opt::multi_s("D", "deny", "Set lint denied", "LINT"),
+ opt::multi_s("F", "forbid", "Set lint forbidden", "LINT"),
opt::multi_s(
"",
"cap-lints",
@@ -1099,13 +1102,6 @@
level",
"LEVEL",
),
- opt::multi_s(
- "",
- "force-warn",
- "Specifiy lints that should warn even if \
- they are allowed somewhere else",
- "LINT",
- ),
opt::multi_s("C", "codegen", "Set a codegen option", "OPT[=VALUE]"),
opt::flag_s("V", "version", "Print version info and exit"),
opt::flag_s("v", "verbose", "Use verbose output"),
@@ -1148,15 +1144,6 @@
never = never colorize output",
"auto|always|never",
),
- opt::opt(
- "",
- "pretty",
- "Pretty-print the input instead of compiling;
- valid types are: `normal` (un-annotated source),
- `expanded` (crates expanded), or
- `expanded,identified` (fully parenthesized, AST nodes with IDs).",
- "TYPE",
- ),
opt::multi_s(
"",
"remap-path-prefix",
@@ -1170,19 +1157,10 @@
pub fn get_cmd_lint_options(
matches: &getopts::Matches,
error_format: ErrorOutputType,
- debugging_opts: &DebuggingOptions,
) -> (Vec<(String, lint::Level)>, bool, Option<lint::Level>) {
let mut lint_opts_with_position = vec![];
let mut describe_lints = false;
- if !debugging_opts.unstable_options && matches.opt_present("force-warn") {
- early_error(
- error_format,
- "the `-Z unstable-options` flag must also be passed to enable \
- the flag `--force-warn=lints`",
- );
- }
-
for level in [lint::Allow, lint::Warn, lint::ForceWarn, lint::Deny, lint::Forbid] {
for (arg_pos, lint_name) in matches.opt_strs_pos(level.as_str()) {
if lint_name == "help" {
@@ -1618,8 +1596,20 @@
}
}
-fn parse_native_lib_kind(kind: &str, error_format: ErrorOutputType) -> NativeLibKind {
- match kind {
+fn parse_native_lib_kind(
+ matches: &getopts::Matches,
+ kind: &str,
+ error_format: ErrorOutputType,
+) -> (NativeLibKind, Option<bool>) {
+ let is_nightly = nightly_options::match_is_nightly_build(matches);
+ let enable_unstable = nightly_options::is_unstable_enabled(matches);
+
+ let (kind, modifiers) = match kind.split_once(':') {
+ None => (kind, None),
+ Some((kind, modifiers)) => (kind, Some(modifiers)),
+ };
+
+ let kind = match kind {
"dylib" => NativeLibKind::Dylib { as_needed: None },
"framework" => NativeLibKind::Framework { as_needed: None },
"static" => NativeLibKind::Static { bundle: None, whole_archive: None },
@@ -1629,17 +1619,49 @@
"library kind `static-nobundle` has been superseded by specifying \
`-bundle` on library kind `static`. Try `static:-bundle`",
);
+ if modifiers.is_some() {
+ early_error(
+ error_format,
+ "linking modifier can't be used with library kind `static-nobundle`",
+ )
+ }
+ if !is_nightly {
+ early_error(
+ error_format,
+ "library kind `static-nobundle` are currently unstable and only accepted on \
+ the nightly compiler",
+ );
+ }
NativeLibKind::Static { bundle: Some(false), whole_archive: None }
}
s => early_error(
error_format,
&format!("unknown library kind `{}`, expected one of dylib, framework, or static", s),
),
+ };
+ match modifiers {
+ None => (kind, None),
+ Some(modifiers) => {
+ if !is_nightly {
+ early_error(
+ error_format,
+ "linking modifiers are currently unstable and only accepted on \
+ the nightly compiler",
+ );
+ }
+ if !enable_unstable {
+ early_error(
+ error_format,
+ "linking modifiers are currently unstable, \
+ the `-Z unstable-options` flag must also be passed to use it",
+ )
+ }
+ parse_native_lib_modifiers(kind, modifiers, error_format)
+ }
}
}
fn parse_native_lib_modifiers(
- is_nightly: bool,
mut kind: NativeLibKind,
modifiers: &str,
error_format: ErrorOutputType,
@@ -1655,14 +1677,6 @@
),
};
- if !is_nightly {
- early_error(
- error_format,
- "linking modifiers are currently unstable and only accepted on \
- the nightly compiler",
- );
- }
-
match (modifier, &mut kind) {
("bundle", NativeLibKind::Static { bundle, .. }) => {
*bundle = Some(value);
@@ -1709,7 +1723,6 @@
}
fn parse_libs(matches: &getopts::Matches, error_format: ErrorOutputType) -> Vec<NativeLib> {
- let is_nightly = nightly_options::match_is_nightly_build(matches);
matches
.opt_strs("l")
.into_iter()
@@ -1723,13 +1736,7 @@
let (name, kind, verbatim) = match s.split_once('=') {
None => (s, NativeLibKind::Unspecified, None),
Some((kind, name)) => {
- let (kind, verbatim) = match kind.split_once(':') {
- None => (parse_native_lib_kind(kind, error_format), None),
- Some((kind, modifiers)) => {
- let kind = parse_native_lib_kind(kind, error_format);
- parse_native_lib_modifiers(is_nightly, kind, modifiers, error_format)
- }
- };
+ let (kind, verbatim) = parse_native_lib_kind(matches, kind, error_format);
(name.to_string(), kind, verbatim)
}
};
@@ -1876,7 +1883,7 @@
)
});
- let locparts: Vec<_> = loc.split(":").collect();
+ let locparts: Vec<_> = loc.split(':').collect();
let spec = match &locparts[..] {
["raw", ..] => {
// Don't want `:` split string
@@ -1943,8 +1950,7 @@
.unwrap_or_else(|e| early_error(error_format, &e[..]));
let mut debugging_opts = DebuggingOptions::build(matches, error_format);
- let (lint_opts, describe_lints, lint_cap) =
- get_cmd_lint_options(matches, error_format, &debugging_opts);
+ let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(matches, error_format);
check_debug_option_stability(&debugging_opts, error_format, json_rendered);
@@ -2073,7 +2079,7 @@
let remap_path_prefix = parse_remap_path_prefix(matches, error_format);
- let pretty = parse_pretty(matches, &debugging_opts, error_format);
+ let pretty = parse_pretty(&debugging_opts, error_format);
if !debugging_opts.unstable_options
&& !target_triple.triple().contains("apple")
@@ -2112,6 +2118,18 @@
if candidate.join("library/std/src/lib.rs").is_file() { Some(candidate) } else { None }
};
+ let working_dir = std::env::current_dir().unwrap_or_else(|e| {
+ early_error(error_format, &format!("Current directory is invalid: {}", e));
+ });
+
+ let (path, remapped) =
+ FilePathMapping::new(remap_path_prefix.clone()).map_prefix(working_dir.clone());
+ let working_dir = if remapped {
+ RealFileName::Remapped { local_path: Some(working_dir), virtual_name: path }
+ } else {
+ RealFileName::LocalPath(path)
+ };
+
Options {
crate_types,
optimize: opt_level,
@@ -2147,72 +2165,43 @@
json_artifact_notifications,
json_unused_externs,
pretty,
+ working_dir,
}
}
-fn parse_pretty(
- matches: &getopts::Matches,
- debugging_opts: &DebuggingOptions,
- efmt: ErrorOutputType,
-) -> Option<PpMode> {
- fn parse_pretty_inner(efmt: ErrorOutputType, name: &str, extended: bool) -> PpMode {
- use PpMode::*;
- let first = match (name, extended) {
- ("normal", _) => Source(PpSourceMode::Normal),
- ("identified", _) => Source(PpSourceMode::Identified),
- ("everybody_loops", true) => Source(PpSourceMode::EveryBodyLoops),
- ("expanded", _) => Source(PpSourceMode::Expanded),
- ("expanded,identified", _) => Source(PpSourceMode::ExpandedIdentified),
- ("expanded,hygiene", _) => Source(PpSourceMode::ExpandedHygiene),
- ("ast-tree", true) => AstTree(PpAstTreeMode::Normal),
- ("ast-tree,expanded", true) => AstTree(PpAstTreeMode::Expanded),
- ("hir", true) => Hir(PpHirMode::Normal),
- ("hir,identified", true) => Hir(PpHirMode::Identified),
- ("hir,typed", true) => Hir(PpHirMode::Typed),
- ("hir-tree", true) => HirTree,
- ("thir-tree", true) => ThirTree,
- ("mir", true) => Mir,
- ("mir-cfg", true) => MirCFG,
- _ => {
- if extended {
- early_error(
- efmt,
- &format!(
- "argument to `unpretty` must be one of `normal`, \
- `expanded`, `identified`, `expanded,identified`, \
- `expanded,hygiene`, `everybody_loops`, \
- `ast-tree`, `ast-tree,expanded`, `hir`, `hir,identified`, \
- `hir,typed`, `hir-tree`, `mir` or `mir-cfg`; got {}",
- name
- ),
- );
- } else {
- early_error(
- efmt,
- &format!(
- "argument to `pretty` must be one of `normal`, \
- `expanded`, `identified`, or `expanded,identified`; got {}",
- name
- ),
- );
- }
- }
- };
- tracing::debug!("got unpretty option: {:?}", first);
- first
- }
+fn parse_pretty(debugging_opts: &DebuggingOptions, efmt: ErrorOutputType) -> Option<PpMode> {
+ use PpMode::*;
- if debugging_opts.unstable_options {
- if let Some(a) = matches.opt_default("pretty", "normal") {
- // stable pretty-print variants only
- return Some(parse_pretty_inner(efmt, &a, false));
- }
- }
-
- debugging_opts.unpretty.as_ref().map(|a| {
- // extended with unstable pretty-print variants
- parse_pretty_inner(efmt, &a, true)
- })
+ let first = match debugging_opts.unpretty.as_deref()? {
+ "normal" => Source(PpSourceMode::Normal),
+ "identified" => Source(PpSourceMode::Identified),
+ "everybody_loops" => Source(PpSourceMode::EveryBodyLoops),
+ "expanded" => Source(PpSourceMode::Expanded),
+ "expanded,identified" => Source(PpSourceMode::ExpandedIdentified),
+ "expanded,hygiene" => Source(PpSourceMode::ExpandedHygiene),
+ "ast-tree" => AstTree(PpAstTreeMode::Normal),
+ "ast-tree,expanded" => AstTree(PpAstTreeMode::Expanded),
+ "hir" => Hir(PpHirMode::Normal),
+ "hir,identified" => Hir(PpHirMode::Identified),
+ "hir,typed" => Hir(PpHirMode::Typed),
+ "hir-tree" => HirTree,
+ "thir-tree" => ThirTree,
+ "mir" => Mir,
+ "mir-cfg" => MirCFG,
+ name => early_error(
+ efmt,
+ &format!(
+ "argument to `unpretty` must be one of `normal`, \
+ `expanded`, `identified`, `expanded,identified`, \
+ `expanded,hygiene`, `everybody_loops`, \
+ `ast-tree`, `ast-tree,expanded`, `hir`, `hir,identified`, \
+ `hir,typed`, `hir-tree`, `mir` or `mir-cfg`; got {}",
+ name
+ ),
+ ),
+ };
+ tracing::debug!("got unpretty option: {:?}", first);
+ Some(first)
}
pub fn make_crate_type_option() -> RustcOptGroup {
@@ -2320,17 +2309,17 @@
#[derive(Copy, Clone, PartialEq, Debug)]
pub enum PpSourceMode {
- /// `--pretty=normal`
+ /// `-Zunpretty=normal`
Normal,
/// `-Zunpretty=everybody_loops`
EveryBodyLoops,
- /// `--pretty=expanded`
+ /// `-Zunpretty=expanded`
Expanded,
- /// `--pretty=identified`
+ /// `-Zunpretty=identified`
Identified,
- /// `--pretty=expanded,identified`
+ /// `-Zunpretty=expanded,identified`
ExpandedIdentified,
- /// `--pretty=expanded,hygiene`
+ /// `-Zunpretty=expanded,hygiene`
ExpandedHygiene,
}
@@ -2355,7 +2344,7 @@
#[derive(Copy, Clone, PartialEq, Debug)]
pub enum PpMode {
/// Options that print the source code, i.e.
- /// `--pretty` and `-Zunpretty=everybody_loops`
+ /// `-Zunpretty=normal` and `-Zunpretty=everybody_loops`
Source(PpSourceMode),
AstTree(PpAstTreeMode),
/// Options that print the HIR, i.e. `-Zunpretty=hir`
@@ -2423,6 +2412,7 @@
use crate::utils::{NativeLib, NativeLibKind};
use rustc_feature::UnstableFeatures;
use rustc_span::edition::Edition;
+ use rustc_span::RealFileName;
use rustc_target::spec::{CodeModel, MergeFunctions, PanicStrategy, RelocModel};
use rustc_target::spec::{RelroLevel, SanitizerSet, SplitDebuginfo, TargetTriple, TlsModel};
use std::collections::hash_map::DefaultHasher;
@@ -2504,6 +2494,7 @@
TrimmedDefPaths,
Option<LdImpl>,
OutputType,
+ RealFileName,
);
impl<T1, T2> DepTrackingHash for (T1, T2)
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index 172337a..9a1be40 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -10,6 +10,7 @@
use rustc_feature::UnstableFeatures;
use rustc_span::edition::Edition;
+use rustc_span::RealFileName;
use rustc_span::SourceFileHashAlgorithm;
use std::collections::BTreeMap;
@@ -203,6 +204,9 @@
json_unused_externs: bool [UNTRACKED],
pretty: Option<PpMode> [UNTRACKED],
+
+ /// The (potentially remapped) working directory
+ working_dir: RealFileName [TRACKED],
}
);
@@ -684,7 +688,7 @@
Some(v) => v,
};
- *slot = Some(match v.trim_end_matches("s") {
+ *slot = Some(match v.trim_end_matches('s') {
"statement" | "stmt" => MirSpanview::Statement,
"terminator" | "term" => MirSpanview::Terminator,
"block" | "basicblock" => MirSpanview::Block,
@@ -1148,6 +1152,8 @@
(default: no)"),
mir_opt_level: Option<usize> = (None, parse_opt_number, [TRACKED],
"MIR optimization level (0-4; default: 1 in non optimized builds and 2 in optimized builds)"),
+ move_size_limit: Option<usize> = (None, parse_opt_number, [TRACKED],
+ "the size at which the `large_assignments` lint starts to be emitted"),
mutable_noalias: Option<bool> = (None, parse_opt_bool, [TRACKED],
"emit noalias metadata for mutable references (default: yes for LLVM >= 12, otherwise no)"),
new_llvm_pass_manager: Option<bool> = (None, parse_opt_bool, [TRACKED],
@@ -1170,6 +1176,8 @@
"compile without linking"),
no_parallel_llvm: bool = (false, parse_no_flag, [UNTRACKED],
"run LLVM in non-parallel mode (while keeping codegen-units and ThinLTO)"),
+ no_profiler_runtime: bool = (false, parse_no_flag, [TRACKED],
+ "prevent automatic injection of the profiler_builtins crate"),
normalize_docs: bool = (false, parse_bool, [TRACKED],
"normalize associated items in rustdoc when generating documentation"),
osx_rpath_install_name: bool = (false, parse_bool, [TRACKED],
@@ -1178,6 +1186,9 @@
"support compiling tests with panic=abort (default: no)"),
parse_only: bool = (false, parse_bool, [UNTRACKED],
"parse only; do not compile, assemble, or link (default: no)"),
+ partially_uninit_const_threshold: Option<usize> = (None, parse_opt_number, [TRACKED],
+ "allow generating const initializers with mixed init/uninit bytes, \
+ and set the maximum total size of a const allocation for which this is allowed (default: never)"),
perf_stats: bool = (false, parse_bool, [UNTRACKED],
"print some performance-related statistics (default: no)"),
plt: Option<bool> = (None, parse_opt_bool, [TRACKED],
@@ -1215,8 +1226,8 @@
profile_emit: Option<PathBuf> = (None, parse_opt_pathbuf, [TRACKED],
"file path to emit profiling data at runtime when using 'profile' \
(default based on relative source path)"),
- profiler_runtime: Option<String> = (Some(String::from("profiler_builtins")), parse_opt_string, [TRACKED],
- "name of the profiler runtime crate to automatically inject, or None to disable"),
+ profiler_runtime: String = (String::from("profiler_builtins"), parse_string, [TRACKED],
+ "name of the profiler runtime crate to automatically inject (default: `profiler_builtins`)"),
query_dep_graph: bool = (false, parse_bool, [UNTRACKED],
"enable queries of the dependency graph for regression testing (default: no)"),
query_stats: bool = (false, parse_bool, [UNTRACKED],
@@ -1279,7 +1290,7 @@
thinlto: Option<bool> = (None, parse_opt_bool, [TRACKED],
"enable ThinLTO when possible"),
thir_unsafeck: bool = (false, parse_bool, [TRACKED],
- "use the work-in-progress THIR unsafety checker. NOTE: this is unsound (default: no)"),
+ "use the THIR unsafety checker (default: no)"),
/// We default to 1 here since we want to behave like
/// a sequential compiler for now. This'll likely be adjusted
/// in the future. Note that -Zthreads=0 is the way to get
@@ -1308,7 +1319,7 @@
"take the brakes off const evaluation. NOTE: this is unsound (default: no)"),
unpretty: Option<String> = (None, parse_unpretty, [UNTRACKED],
"present the input source, unstable (and less-pretty) variants;
- valid types are any of the types for `--pretty`, as well as:
+ `normal`, `identified`,
`expanded`, `expanded,identified`,
`expanded,hygiene` (with internal representations),
`everybody_loops` (all function bodies replaced with `loop {}`),
diff --git a/compiler/rustc_session/src/parse.rs b/compiler/rustc_session/src/parse.rs
index 226fde2..a007b53 100644
--- a/compiler/rustc_session/src/parse.rs
+++ b/compiler/rustc_session/src/parse.rs
@@ -228,20 +228,12 @@
/// Extend an error with a suggestion to wrap an expression with parentheses to allow the
/// parser to continue parsing the following operation as part of the same expression.
- pub fn expr_parentheses_needed(
- &self,
- err: &mut DiagnosticBuilder<'_>,
- span: Span,
- alt_snippet: Option<String>,
- ) {
- if let Some(snippet) = self.source_map().span_to_snippet(span).ok().or(alt_snippet) {
- err.span_suggestion(
- span,
- "parentheses are required to parse this as an expression",
- format!("({})", snippet),
- Applicability::MachineApplicable,
- );
- }
+ pub fn expr_parentheses_needed(&self, err: &mut DiagnosticBuilder<'_>, span: Span) {
+ err.multipart_suggestion(
+ "parentheses are required to parse this as an expression",
+ vec![(span.shrink_to_lo(), "(".to_string()), (span.shrink_to_hi(), ")".to_string())],
+ Applicability::MachineApplicable,
+ );
}
pub fn save_proc_macro_span(&self, span: Span) -> usize {
diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs
index 86d495c..0f7db69 100644
--- a/compiler/rustc_session/src/session.rs
+++ b/compiler/rustc_session/src/session.rs
@@ -23,8 +23,8 @@
use rustc_errors::{DiagnosticBuilder, DiagnosticId, ErrorReported};
use rustc_macros::HashStable_Generic;
pub use rustc_span::def_id::StableCrateId;
+use rustc_span::edition::Edition;
use rustc_span::source_map::{FileLoader, MultiSpan, RealFileLoader, SourceMap, Span};
-use rustc_span::{edition::Edition, RealFileName};
use rustc_span::{sym, SourceFileHashAlgorithm, Symbol};
use rustc_target::asm::InlineAsmArch;
use rustc_target::spec::{CodeModel, PanicStrategy, RelocModel, RelroLevel};
@@ -139,8 +139,6 @@
/// The name of the root source file of the crate, in the local file system.
/// `None` means that there is no source file.
pub local_crate_source_file: Option<PathBuf>,
- /// The directory the compiler has been executed in
- pub working_dir: RealFileName,
/// Set of `(DiagnosticId, Option<Span>, message)` tuples tracking
/// (sub)diagnostics that have been set once, but should not be set again,
@@ -172,15 +170,9 @@
/// Data about code being compiled, gathered during compilation.
pub code_stats: CodeStats,
- /// If `-zfuel=crate=n` is specified, `Some(crate)`.
- optimization_fuel_crate: Option<String>,
-
/// Tracks fuel info if `-zfuel=crate=n` is specified.
optimization_fuel: Lock<OptimizationFuel>,
- // The next two are public because the driver needs to read them.
- /// If `-zprint-fuel=crate`, `Some(crate)`.
- pub print_fuel_crate: Option<String>,
/// Always set to zero and incremented so that we can print fuel expended by a crate.
pub print_fuel: AtomicU64,
@@ -191,20 +183,16 @@
/// Cap lint level specified by a driver specifically.
pub driver_lint_caps: FxHashMap<lint::LintId, lint::Level>,
- /// `Span`s of trait methods that weren't found to avoid emitting object safety errors
- pub trait_methods_not_found: Lock<FxHashSet<Span>>,
-
/// Mapping from ident span to path span for paths that don't exist as written, but that
/// exist under `std`. For example, wrote `str::from_utf8` instead of `std::str::from_utf8`.
pub confused_type_with_std_module: Lock<FxHashMap<Span, Span>>,
- /// Path for libraries that will take preference over libraries shipped by Rust.
- /// Used by windows-gnu targets to priortize system mingw-w64 libraries.
- pub system_library_path: OneThread<RefCell<Option<Option<PathBuf>>>>,
-
/// Tracks the current behavior of the CTFE engine when an error occurs.
/// Options range from returning the error without a backtrace to returning an error
/// and immediately printing the backtrace to stderr.
+ /// The `Lock` is only used by miri to allow setting `ctfe_backtrace` after analysis when
+ /// `MIRI_BACKTRACE` is set. This makes it only apply to miri's errors and not to all CTFE
+ /// errors.
pub ctfe_backtrace: Lock<CtfeBacktrace>,
/// This tracks where `-Zunleash-the-miri-inside-of-you` was used to get around a
@@ -218,12 +206,6 @@
/// Set of enabled features for the current target.
pub target_features: FxHashSet<Symbol>,
-
- known_attrs: Lock<MarkedAttrs>,
- used_attrs: Lock<MarkedAttrs>,
-
- /// `Span`s for `if` conditions that we have suggested turning into `if let`.
- pub if_let_suggestions: Lock<FxHashSet<Span>>,
}
pub struct PerfStats {
@@ -455,8 +437,7 @@
{
let old_count = self.err_count();
let result = f();
- let errors = self.err_count() - old_count;
- if errors == 0 { Ok(result) } else { Err(ErrorReported) }
+ if self.err_count() == old_count { Ok(result) } else { Err(ErrorReported) }
}
pub fn span_warn<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
self.diagnostic().span_warn(sp, msg)
@@ -505,6 +486,10 @@
&self.parse_sess.span_diagnostic
}
+ pub fn with_disabled_diagnostic<T, F: FnOnce() -> T>(&self, f: F) -> T {
+ self.parse_sess.span_diagnostic.with_disabled_diagnostic(f)
+ }
+
/// Analogous to calling methods on the given `DiagnosticBuilder`, but
/// deduplicates on lint ID, span (if any), and message for this `Session`
fn diag_once<'a, 'b>(
@@ -794,12 +779,6 @@
)
}
- /// Returns the symbol name for the registrar function,
- /// given the crate `Svh` and the function `DefIndex`.
- pub fn generate_plugin_registrar_symbol(&self, stable_crate_id: StableCrateId) -> String {
- format!("__rustc_plugin_registrar_{:08x}__", stable_crate_id.to_u64())
- }
-
pub fn generate_proc_macro_decls_symbol(&self, stable_crate_id: StableCrateId) -> String {
format!("__rustc_proc_macro_decls_{:08x}__", stable_crate_id.to_u64())
}
@@ -908,7 +887,7 @@
/// This expends fuel if applicable, and records fuel if applicable.
pub fn consider_optimizing<T: Fn() -> String>(&self, crate_name: &str, msg: T) -> bool {
let mut ret = true;
- if let Some(ref c) = self.optimization_fuel_crate {
+ if let Some(c) = self.opts.debugging_opts.fuel.as_ref().map(|i| &i.0) {
if c == crate_name {
assert_eq!(self.threads(), 1);
let mut fuel = self.optimization_fuel.lock();
@@ -921,7 +900,7 @@
}
}
}
- if let Some(ref c) = self.print_fuel_crate {
+ if let Some(ref c) = self.opts.debugging_opts.print_fuel {
if c == crate_name {
assert_eq!(self.threads(), 1);
self.print_fuel.fetch_add(1, SeqCst);
@@ -1076,47 +1055,14 @@
== config::InstrumentCoverage::ExceptUnusedFunctions
}
- pub fn mark_attr_known(&self, attr: &Attribute) {
- self.known_attrs.lock().mark(attr)
- }
-
- pub fn is_attr_known(&self, attr: &Attribute) -> bool {
- self.known_attrs.lock().is_marked(attr)
- }
-
- pub fn mark_attr_used(&self, attr: &Attribute) {
- self.used_attrs.lock().mark(attr)
- }
-
- pub fn is_attr_used(&self, attr: &Attribute) -> bool {
- self.used_attrs.lock().is_marked(attr)
- }
-
- /// Returns `true` if the attribute's path matches the argument. If it
- /// matches, then the attribute is marked as used.
- ///
- /// This method should only be used by rustc, other tools can use
- /// `Attribute::has_name` instead, because only rustc is supposed to report
- /// the `unused_attributes` lint. (`MetaItem` and `NestedMetaItem` are
- /// produced by lowering an `Attribute` and don't have identity, so they
- /// only have the `has_name` method, and you need to mark the original
- /// `Attribute` as used when necessary.)
- pub fn check_name(&self, attr: &Attribute, name: Symbol) -> bool {
- let matches = attr.has_name(name);
- if matches {
- self.mark_attr_used(attr);
- }
- matches
- }
-
pub fn is_proc_macro_attr(&self, attr: &Attribute) -> bool {
[sym::proc_macro, sym::proc_macro_attribute, sym::proc_macro_derive]
.iter()
- .any(|kind| self.check_name(attr, *kind))
+ .any(|kind| attr.has_name(*kind))
}
pub fn contains_name(&self, attrs: &[Attribute], name: Symbol) -> bool {
- attrs.iter().any(|item| self.check_name(item, name))
+ attrs.iter().any(|item| item.has_name(name))
}
pub fn find_by_name<'a>(
@@ -1124,7 +1070,7 @@
attrs: &'a [Attribute],
name: Symbol,
) -> Option<&'a Attribute> {
- attrs.iter().find(|attr| self.check_name(attr, name))
+ attrs.iter().find(|attr| attr.has_name(name))
}
pub fn filter_by_name<'a>(
@@ -1132,7 +1078,7 @@
attrs: &'a [Attribute],
name: Symbol,
) -> impl Iterator<Item = &'a Attribute> {
- attrs.iter().filter(move |attr| self.check_name(attr, name))
+ attrs.iter().filter(move |attr| attr.has_name(name))
}
pub fn first_attr_value_str_by_name(
@@ -1140,7 +1086,7 @@
attrs: &[Attribute],
name: Symbol,
) -> Option<Symbol> {
- attrs.iter().find(|at| self.check_name(at, name)).and_then(|at| at.value_str())
+ attrs.iter().find(|at| at.has_name(name)).and_then(|at| at.value_str())
}
}
@@ -1312,24 +1258,12 @@
let local_crate_source_file =
local_crate_source_file.map(|path| file_path_mapping.map_prefix(path).0);
- 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_or(0, |i| i.1),
out_of_fuel: false,
});
- let print_fuel_crate = sopts.debugging_opts.print_fuel.clone();
let print_fuel = AtomicU64::new(0);
- let working_dir = env::current_dir().unwrap_or_else(|e| {
- parse_sess.span_diagnostic.fatal(&format!("Current directory is invalid: {}", e)).raise()
- });
- let (path, remapped) = file_path_mapping.map_prefix(working_dir.clone());
- let working_dir = if remapped {
- RealFileName::Remapped { local_path: Some(working_dir), virtual_name: path }
- } else {
- RealFileName::LocalPath(path)
- };
-
let cgu_reuse_tracker = if sopts.debugging_opts.query_dep_graph {
CguReuseTracker::new()
} else {
@@ -1360,7 +1294,6 @@
parse_sess,
sysroot,
local_crate_source_file,
- working_dir,
one_time_diagnostics: Default::default(),
crate_types: OnceCell::new(),
stable_crate_id: OnceCell::new(),
@@ -1376,22 +1309,15 @@
normalize_projection_ty: AtomicUsize::new(0),
},
code_stats: Default::default(),
- optimization_fuel_crate,
optimization_fuel,
- print_fuel_crate,
print_fuel,
jobserver: jobserver::client(),
driver_lint_caps,
- trait_methods_not_found: Lock::new(Default::default()),
confused_type_with_std_module: Lock::new(Default::default()),
- system_library_path: OneThread::new(RefCell::new(Default::default())),
ctfe_backtrace,
miri_unleashed_features: Lock::new(Default::default()),
asm_arch,
target_features: FxHashSet::default(),
- known_attrs: Lock::new(MarkedAttrs::new()),
- used_attrs: Lock::new(MarkedAttrs::new()),
- if_let_suggestions: Default::default(),
};
validate_commandline_args_with_session_available(&sess);
diff --git a/compiler/rustc_span/Cargo.toml b/compiler/rustc_span/Cargo.toml
index 4552f14..e475e89 100644
--- a/compiler/rustc_span/Cargo.toml
+++ b/compiler/rustc_span/Cargo.toml
@@ -1,5 +1,4 @@
[package]
-authors = ["The Rust Project Developers"]
name = "rustc_span"
version = "0.0.0"
edition = "2018"
diff --git a/compiler/rustc_span/src/edition.rs b/compiler/rustc_span/src/edition.rs
index 8544acd..511c2e8 100644
--- a/compiler/rustc_span/src/edition.rs
+++ b/compiler/rustc_span/src/edition.rs
@@ -32,7 +32,7 @@
pub const DEFAULT_EDITION: Edition = Edition::Edition2015;
-pub const LATEST_STABLE_EDITION: Edition = Edition::Edition2018;
+pub const LATEST_STABLE_EDITION: Edition = Edition::Edition2021;
impl fmt::Display for Edition {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
@@ -66,7 +66,7 @@
match *self {
Edition::Edition2015 => true,
Edition::Edition2018 => true,
- Edition::Edition2021 => false,
+ Edition::Edition2021 => true,
}
}
}
diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs
index e44a2e9..c22093c 100644
--- a/compiler/rustc_span/src/hygiene.rs
+++ b/compiler/rustc_span/src/hygiene.rs
@@ -1097,6 +1097,7 @@
Async,
Await,
ForLoop(ForLoopLoc),
+ LetElse,
}
/// A location in the desugaring of a `for` loop
@@ -1117,6 +1118,7 @@
DesugaringKind::TryBlock => "`try` block",
DesugaringKind::OpaqueTy => "`impl Trait`",
DesugaringKind::ForLoop(_) => "`for` loop",
+ DesugaringKind::LetElse => "`let...else`",
}
}
}
diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs
index 1c95cc9..b4cc8b2 100644
--- a/compiler/rustc_span/src/lib.rs
+++ b/compiler/rustc_span/src/lib.rs
@@ -16,10 +16,12 @@
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
#![feature(array_windows)]
#![feature(crate_visibility_modifier)]
+#![feature(if_let_guard)]
#![feature(negative_impls)]
#![feature(nll)]
#![feature(min_specialization)]
#![feature(thread_local_const_init)]
+#![cfg_attr(bootstrap, allow(incomplete_features))] // if_let_guard
#[macro_use]
extern crate rustc_macros;
@@ -157,7 +159,7 @@
// FIXME: We should use this enum or something like it to get rid of the
// use of magic `/rust/1.x/...` paths across the board.
#[derive(Debug, Eq, PartialEq, Clone, Ord, PartialOrd)]
-#[derive(HashStable_Generic, Decodable)]
+#[derive(Decodable)]
pub enum RealFileName {
LocalPath(PathBuf),
/// For remapped paths (namely paths into libstd that have been mapped
@@ -258,18 +260,19 @@
}
}
- pub fn to_string_lossy(&self, prefer_local: bool) -> Cow<'_, str> {
- if prefer_local {
- self.local_path_if_available().to_string_lossy()
- } else {
- self.remapped_path_if_available().to_string_lossy()
+ pub fn to_string_lossy(&self, display_pref: FileNameDisplayPreference) -> Cow<'_, str> {
+ match display_pref {
+ FileNameDisplayPreference::Local => self.local_path_if_available().to_string_lossy(),
+ FileNameDisplayPreference::Remapped => {
+ self.remapped_path_if_available().to_string_lossy()
+ }
}
}
}
/// Differentiates between real files and common virtual files.
#[derive(Debug, Eq, PartialEq, Clone, Ord, PartialOrd, Hash)]
-#[derive(HashStable_Generic, Decodable, Encodable)]
+#[derive(Decodable, Encodable)]
pub enum FileName {
Real(RealFileName),
/// Call to `quote!`.
@@ -298,9 +301,15 @@
}
}
+#[derive(Clone, Copy, Eq, PartialEq, Hash, Debug)]
+pub enum FileNameDisplayPreference {
+ Remapped,
+ Local,
+}
+
pub struct FileNameDisplay<'a> {
inner: &'a FileName,
- prefer_local: bool,
+ display_pref: FileNameDisplayPreference,
}
impl fmt::Display for FileNameDisplay<'_> {
@@ -308,7 +317,7 @@
use FileName::*;
match *self.inner {
Real(ref name) => {
- write!(fmt, "{}", name.to_string_lossy(self.prefer_local))
+ write!(fmt, "{}", name.to_string_lossy(self.display_pref))
}
QuoteExpansion(_) => write!(fmt, "<quote expansion>"),
MacroExpansion(_) => write!(fmt, "<macro expansion>"),
@@ -326,7 +335,7 @@
impl FileNameDisplay<'_> {
pub fn to_string_lossy(&self) -> Cow<'_, str> {
match self.inner {
- FileName::Real(ref inner) => inner.to_string_lossy(self.prefer_local),
+ FileName::Real(ref inner) => inner.to_string_lossy(self.display_pref),
_ => Cow::from(format!("{}", self)),
}
}
@@ -350,13 +359,17 @@
}
pub fn prefer_remapped(&self) -> FileNameDisplay<'_> {
- FileNameDisplay { inner: self, prefer_local: false }
+ FileNameDisplay { inner: self, display_pref: FileNameDisplayPreference::Remapped }
}
// This may include transient local filesystem information.
// Must not be embedded in build outputs.
pub fn prefer_local(&self) -> FileNameDisplay<'_> {
- FileNameDisplay { inner: self, prefer_local: true }
+ FileNameDisplay { inner: self, display_pref: FileNameDisplayPreference::Local }
+ }
+
+ pub fn display(&self, display_pref: FileNameDisplayPreference) -> FileNameDisplay<'_> {
+ FileNameDisplay { inner: self, display_pref }
}
pub fn macro_expansion_source_code(src: &str) -> FileName {
@@ -595,6 +608,14 @@
if !expn_data.is_root() { Some(expn_data.call_site) } else { None }
}
+ /// Walk down the expansion ancestors to find a span that's contained within `outer`.
+ pub fn find_ancestor_inside(mut self, outer: Span) -> Option<Span> {
+ while !outer.contains(self) {
+ self = self.parent()?;
+ }
+ Some(self)
+ }
+
/// Edition of the crate from which this span came.
pub fn edition(self) -> edition::Edition {
self.ctxt().edition()
diff --git a/compiler/rustc_span/src/source_map.rs b/compiler/rustc_span/src/source_map.rs
index 77a3ad9..9b8c859 100644
--- a/compiler/rustc_span/src/source_map.rs
+++ b/compiler/rustc_span/src/source_map.rs
@@ -100,7 +100,7 @@
/// Query the existence of a file.
fn file_exists(&self, path: &Path) -> bool;
- /// Read the contents of an UTF-8 file into memory.
+ /// Read the contents of a UTF-8 file into memory.
fn read_file(&self, path: &Path) -> io::Result<String>;
}
@@ -427,7 +427,7 @@
}
}
- fn span_to_string(&self, sp: Span, prefer_local: bool) -> String {
+ fn span_to_string(&self, sp: Span, filename_display_pref: FileNameDisplayPreference) -> String {
if self.files.borrow().source_files.is_empty() || sp.is_dummy() {
return "no-location".to_string();
}
@@ -436,7 +436,7 @@
let hi = self.lookup_char_pos(sp.hi());
format!(
"{}:{}:{}: {}:{}",
- if prefer_local { lo.file.name.prefer_local() } else { lo.file.name.prefer_remapped() },
+ lo.file.name.display(filename_display_pref),
lo.line,
lo.col.to_usize() + 1,
hi.line,
@@ -446,20 +446,24 @@
/// Format the span location suitable for embedding in build artifacts
pub fn span_to_embeddable_string(&self, sp: Span) -> String {
- self.span_to_string(sp, false)
+ self.span_to_string(sp, FileNameDisplayPreference::Remapped)
}
/// Format the span location to be printed in diagnostics. Must not be emitted
/// to build artifacts as this may leak local file paths. Use span_to_embeddable_string
/// for string suitable for embedding.
pub fn span_to_diagnostic_string(&self, sp: Span) -> String {
- self.span_to_string(sp, true)
+ self.span_to_string(sp, self.path_mapping.filename_display_for_diagnostics)
}
pub fn span_to_filename(&self, sp: Span) -> FileName {
self.lookup_char_pos(sp.lo()).file.name.clone()
}
+ pub fn filename_for_diagnostics<'a>(&self, filename: &'a FileName) -> FileNameDisplay<'a> {
+ filename.display(self.path_mapping.filename_display_for_diagnostics)
+ }
+
pub fn is_multiline(&self, sp: Span) -> bool {
let lo = self.lookup_source_file_idx(sp.lo());
let hi = self.lookup_source_file_idx(sp.hi());
@@ -567,6 +571,17 @@
}
}
+ /// Returns whether or not this span points into a file
+ /// in the current crate. This may be `false` for spans
+ /// produced by a macro expansion, or for spans associated
+ /// with the definition of an item in a foreign crate
+ pub fn is_local_span(&self, sp: Span) -> bool {
+ let local_begin = self.lookup_byte_offset(sp.lo());
+ let local_end = self.lookup_byte_offset(sp.hi());
+ // This might be a weird span that covers multiple files
+ local_begin.sf.src.is_some() && local_end.sf.src.is_some()
+ }
+
/// Returns the source snippet as `String` corresponding to the given `Span`.
pub fn span_to_snippet(&self, sp: Span) -> Result<String, SpanSnippetError> {
self.span_to_source(sp, |src, start_index, end_index| {
@@ -982,15 +997,13 @@
None
}
pub fn ensure_source_file_source_present(&self, source_file: Lrc<SourceFile>) -> bool {
- source_file.add_external_src(|| match source_file.name {
- FileName::Real(ref name) => {
- if let Some(local_path) = name.local_path() {
+ source_file.add_external_src(|| {
+ match source_file.name {
+ FileName::Real(ref name) if let Some(local_path) = name.local_path() => {
self.file_loader.read_file(local_path).ok()
- } else {
- None
}
+ _ => None,
}
- _ => None,
})
}
@@ -1004,15 +1017,22 @@
#[derive(Clone)]
pub struct FilePathMapping {
mapping: Vec<(PathBuf, PathBuf)>,
+ filename_display_for_diagnostics: FileNameDisplayPreference,
}
impl FilePathMapping {
pub fn empty() -> FilePathMapping {
- FilePathMapping { mapping: vec![] }
+ FilePathMapping::new(Vec::new())
}
pub fn new(mapping: Vec<(PathBuf, PathBuf)>) -> FilePathMapping {
- FilePathMapping { mapping }
+ let filename_display_for_diagnostics = if mapping.is_empty() {
+ FileNameDisplayPreference::Local
+ } else {
+ FileNameDisplayPreference::Remapped
+ };
+
+ FilePathMapping { mapping, filename_display_for_diagnostics }
}
/// Applies any path prefix substitution as defined by the mapping.
@@ -1033,22 +1053,19 @@
fn map_filename_prefix(&self, file: &FileName) -> (FileName, bool) {
match file {
- FileName::Real(realfile) => {
- if let RealFileName::LocalPath(local_path) = realfile {
- let (mapped_path, mapped) = self.map_prefix(local_path.to_path_buf());
- let realfile = if mapped {
- RealFileName::Remapped {
- local_path: Some(local_path.clone()),
- virtual_name: mapped_path,
- }
- } else {
- realfile.clone()
- };
- (FileName::Real(realfile), mapped)
+ FileName::Real(realfile) if let RealFileName::LocalPath(local_path) = realfile => {
+ let (mapped_path, mapped) = self.map_prefix(local_path.to_path_buf());
+ let realfile = if mapped {
+ RealFileName::Remapped {
+ local_path: Some(local_path.clone()),
+ virtual_name: mapped_path,
+ }
} else {
- unreachable!("attempted to remap an already remapped filename");
- }
+ realfile.clone()
+ };
+ (FileName::Real(realfile), mapped)
}
+ FileName::Real(_) => unreachable!("attempted to remap an already remapped filename"),
other => (other.clone(), false),
}
}
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index a8f9697..5150900 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -121,6 +121,8 @@
// There is currently no checking that all symbols are used; that would be
// nice to have.
Symbols {
+ AcqRel,
+ Acquire,
Alignment,
Any,
Arc,
@@ -129,6 +131,20 @@
Arguments,
AsMut,
AsRef,
+ AtomicBool,
+ AtomicI128,
+ AtomicI16,
+ AtomicI32,
+ AtomicI64,
+ AtomicI8,
+ AtomicIsize,
+ AtomicPtr,
+ AtomicU128,
+ AtomicU16,
+ AtomicU32,
+ AtomicU64,
+ AtomicU8,
+ AtomicUsize,
BTreeEntry,
BTreeMap,
BTreeSet,
@@ -215,12 +231,15 @@
Rc,
Ready,
Receiver,
+ Relaxed,
+ Release,
Result,
Return,
Right,
RustcDecodable,
RustcEncodable,
Send,
+ SeqCst,
Some,
StructuralEq,
StructuralPartialEq,
@@ -265,6 +284,7 @@
add_assign,
add_with_overflow,
address,
+ adt_const_params,
advanced_slice_patterns,
adx_target_feature,
alias,
@@ -311,6 +331,8 @@
assume_init,
async_await,
async_closure,
+ atomic,
+ atomic_mod,
atomics,
att_syntax,
attr,
@@ -323,6 +345,7 @@
await_macro,
bang,
begin_panic,
+ begin_panic_fmt,
bench,
bin,
bind_by_move_pattern_guards,
@@ -334,6 +357,7 @@
bitreverse,
bitxor,
bitxor_assign,
+ black_box,
block,
bool,
borrowck_graphviz_format,
@@ -376,6 +400,7 @@
char,
client,
clippy,
+ clobber_abi,
clone,
clone_closures,
clone_from,
@@ -389,8 +414,12 @@
coerce_unsized,
cold,
column,
+ compare_and_swap,
+ compare_exchange,
+ compare_exchange_weak,
compile_error,
compiler_builtins,
+ compiler_fence,
concat,
concat_idents,
conservative_impl_trait,
@@ -409,6 +438,8 @@
const_fn_transmute,
const_fn_union,
const_fn_unsize,
+ const_for,
+ const_format_args,
const_generic_defaults,
const_generics,
const_generics_defaults,
@@ -420,6 +451,7 @@
const_loop,
const_mut_refs,
const_panic,
+ const_panic_fmt,
const_precise_live_drops,
const_ptr,
const_raw_ptr_deref,
@@ -429,6 +461,7 @@
const_trait_bound_opt_out,
const_trait_impl,
const_transmute,
+ const_try,
constant,
constructor,
contents,
@@ -446,6 +479,7 @@
core_panic_macro,
cosf32,
cosf64,
+ cr,
crate_id,
crate_in_paths,
crate_local,
@@ -489,6 +523,7 @@
deref_mut,
deref_target,
derive,
+ derive_default_enum,
destructuring_assignment,
diagnostic,
direct,
@@ -505,6 +540,7 @@
doc_keyword,
doc_masked,
doc_notable_trait,
+ doc_primitive,
doc_spotlight,
doctest,
document_private_items,
@@ -522,6 +558,7 @@
dyn_metadata,
dyn_trait,
edition_macro_pats,
+ edition_panic,
eh_catch_typeinfo,
eh_personality,
emit_enum,
@@ -548,6 +585,7 @@
expected,
expf32,
expf64,
+ explicit_generic_args_with_impl_trait,
export_name,
expr,
extended_key_value_attributes,
@@ -569,6 +607,8 @@
fadd_fast,
fdiv_fast,
feature,
+ fence,
+ fetch_update,
ffi,
ffi_const,
ffi_pure,
@@ -585,6 +625,7 @@
fmaf32,
fmaf64,
fmt,
+ fmt_as_str,
fmt_internals,
fmul_fast,
fn_align,
@@ -622,7 +663,9 @@
generator,
generator_state,
generators,
+ generic_arg_infer,
generic_associated_types,
+ generic_const_exprs,
generic_param_attrs,
get_context,
global_allocator,
@@ -703,6 +746,7 @@
le,
len,
let_chains,
+ let_else,
lhs,
lib,
libc,
@@ -720,6 +764,7 @@
lint_reasons,
literal,
llvm_asm,
+ load,
local,
local_inner_macros,
log10f32,
@@ -879,6 +924,7 @@
panic_2021,
panic_abort,
panic_bounds_check,
+ panic_fmt,
panic_handler,
panic_impl,
panic_implementation,
@@ -1047,6 +1093,7 @@
rustc_dump_env_program_clauses,
rustc_dump_program_clauses,
rustc_dump_user_substs,
+ rustc_dump_vtable,
rustc_error,
rustc_evaluate_where_clauses,
rustc_expected_cgu_reuse,
@@ -1207,6 +1254,7 @@
stmt,
stmt_expr_attributes,
stop_after_dataflow,
+ store,
str,
str_alloc,
string_type,
@@ -1260,6 +1308,7 @@
trace_macros,
track_caller,
trait_alias,
+ trait_upcasting,
transmute,
transparent,
transparent_enums,
@@ -1310,7 +1359,6 @@
unix,
unlikely,
unmarked_api,
- unnamed_fields,
unpin,
unreachable,
unreachable_code,
@@ -1371,6 +1419,7 @@
wreg,
write_bytes,
x87_reg,
+ xer,
xmm_reg,
ymm_reg,
zmm_reg,
@@ -1588,6 +1637,10 @@
self.0.as_u32()
}
+ pub fn len(self) -> usize {
+ with_interner(|interner| interner.get(self).len())
+ }
+
pub fn is_empty(self) -> bool {
self == kw::Empty
}
diff --git a/compiler/rustc_symbol_mangling/Cargo.toml b/compiler/rustc_symbol_mangling/Cargo.toml
index 53d4dc2..aebf77a 100644
--- a/compiler/rustc_symbol_mangling/Cargo.toml
+++ b/compiler/rustc_symbol_mangling/Cargo.toml
@@ -1,5 +1,4 @@
[package]
-authors = ["The Rust Project Developers"]
name = "rustc_symbol_mangling"
version = "0.0.0"
edition = "2018"
@@ -10,7 +9,7 @@
[dependencies]
tracing = "0.1"
punycode = "0.4.0"
-rustc-demangle = "0.1.18"
+rustc-demangle = "0.1.21"
rustc_span = { path = "../rustc_span" }
rustc_middle = { path = "../rustc_middle" }
diff --git a/compiler/rustc_symbol_mangling/src/legacy.rs b/compiler/rustc_symbol_mangling/src/legacy.rs
index 0c64fe6..e236ef9 100644
--- a/compiler/rustc_symbol_mangling/src/legacy.rs
+++ b/compiler/rustc_symbol_mangling/src/legacy.rs
@@ -55,7 +55,8 @@
let hash = get_symbol_hash(tcx, instance, instance_ty, instantiating_crate);
- let mut printer = SymbolPrinter { tcx, path: SymbolPath::new(), keep_within_component: false }
+ let mut printer = SymbolPrinter { tcx, path: SymbolPath::new(), keep_within_component: false };
+ printer
.print_def_path(
def_id,
if let ty::InstanceDef::DropGlue(_, _) = instance.def {
@@ -106,9 +107,9 @@
tcx.def_path_hash(def_id).hash_stable(&mut hcx, &mut hasher);
// Include the main item-type. Note that, in this case, the
- // assertions about `needs_subst` may not hold, but this item-type
+ // assertions about `definitely_needs_subst` may not hold, but this item-type
// ought to be the same for every reference anyway.
- assert!(!item_type.has_erasable_regions());
+ assert!(!item_type.has_erasable_regions(tcx));
hcx.while_hashing_spans(false, |hcx| {
hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| {
item_type.hash_stable(hcx, &mut hasher);
@@ -198,7 +199,7 @@
// `PrettyPrinter` aka pretty printing of e.g. types in paths,
// symbol names should have their own printing machinery.
-impl Printer<'tcx> for SymbolPrinter<'tcx> {
+impl Printer<'tcx> for &mut SymbolPrinter<'tcx> {
type Error = fmt::Error;
type Path = Self;
@@ -242,7 +243,7 @@
Ok(self)
}
- fn print_const(mut self, ct: &'tcx ty::Const<'tcx>) -> Result<Self::Const, Self::Error> {
+ fn print_const(self, ct: &'tcx ty::Const<'tcx>) -> Result<Self::Const, Self::Error> {
// only print integers
if let ty::ConstKind::Value(ConstValue::Scalar(Scalar::Int { .. })) = ct.val {
if ct.ty.is_integral() {
@@ -253,7 +254,7 @@
Ok(self)
}
- fn path_crate(mut self, cnum: CrateNum) -> Result<Self::Path, Self::Error> {
+ fn path_crate(self, cnum: CrateNum) -> Result<Self::Path, Self::Error> {
self.write_str(&self.tcx.crate_name(cnum).as_str())?;
Ok(self)
}
@@ -344,7 +345,7 @@
}
}
-impl PrettyPrinter<'tcx> for SymbolPrinter<'tcx> {
+impl PrettyPrinter<'tcx> for &mut SymbolPrinter<'tcx> {
fn region_should_not_be_omitted(&self, _region: ty::Region<'_>) -> bool {
false
}
diff --git a/compiler/rustc_symbol_mangling/src/lib.rs b/compiler/rustc_symbol_mangling/src/lib.rs
index ba59ff9..220c9f7 100644
--- a/compiler/rustc_symbol_mangling/src/lib.rs
+++ b/compiler/rustc_symbol_mangling/src/lib.rs
@@ -91,6 +91,7 @@
#![feature(never_type)]
#![feature(nll)]
#![feature(in_band_lifetimes)]
+#![feature(iter_zip)]
#![recursion_limit = "256"]
#[macro_use]
@@ -164,10 +165,6 @@
// FIXME(eddyb) Precompute a custom symbol name based on attributes.
let is_foreign = if let Some(def_id) = def_id.as_local() {
- if tcx.plugin_registrar_fn(()) == Some(def_id) {
- let stable_crate_id = tcx.sess.local_stable_crate_id();
- return tcx.sess.generate_plugin_registrar_symbol(stable_crate_id);
- }
if tcx.proc_macro_decls_static(()) == Some(def_id) {
let stable_crate_id = tcx.sess.local_stable_crate_id();
return tcx.sess.generate_proc_macro_decls_symbol(stable_crate_id);
@@ -249,10 +246,18 @@
tcx.symbol_mangling_version(mangling_version_crate)
};
- match mangling_version {
+ let symbol = match mangling_version {
SymbolManglingVersion::Legacy => legacy::mangle(tcx, instance, instantiating_crate),
SymbolManglingVersion::V0 => v0::mangle(tcx, instance, instantiating_crate),
- }
+ };
+
+ debug_assert!(
+ rustc_demangle::try_demangle(&symbol).is_ok(),
+ "compute_symbol_name: `{}` cannot be demangled",
+ symbol
+ );
+
+ symbol
}
fn is_generic(substs: SubstsRef<'_>) -> bool {
diff --git a/compiler/rustc_symbol_mangling/src/test.rs b/compiler/rustc_symbol_mangling/src/test.rs
index bfe9c4d..183df96 100644
--- a/compiler/rustc_symbol_mangling/src/test.rs
+++ b/compiler/rustc_symbol_mangling/src/test.rs
@@ -35,7 +35,7 @@
fn process_attrs(&mut self, def_id: LocalDefId) {
let tcx = self.tcx;
for attr in tcx.get_attrs(def_id.to_def_id()).iter() {
- if tcx.sess.check_name(attr, SYMBOL_NAME) {
+ if attr.has_name(SYMBOL_NAME) {
let def_id = def_id.to_def_id();
let instance = Instance::new(
def_id,
@@ -47,7 +47,7 @@
tcx.sess.span_err(attr.span, &format!("demangling({})", demangling));
tcx.sess.span_err(attr.span, &format!("demangling-alt({:#})", demangling));
}
- } else if tcx.sess.check_name(attr, DEF_PATH) {
+ } else if attr.has_name(DEF_PATH) {
let path = with_no_trimmed_paths(|| tcx.def_path_str(def_id.to_def_id()));
tcx.sess.span_err(attr.span, &format!("def-path({})", path));
}
diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs
index 1444280..521730d 100644
--- a/compiler/rustc_symbol_mangling/src/v0.rs
+++ b/compiler/rustc_symbol_mangling/src/v0.rs
@@ -1,8 +1,10 @@
use rustc_data_structures::base_n;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_hir as hir;
+use rustc_hir::def::CtorKind;
use rustc_hir::def_id::{CrateNum, DefId};
use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData};
+use rustc_middle::mir::interpret::ConstValue;
use rustc_middle::ty::layout::IntegerExt;
use rustc_middle::ty::print::{Print, Printer};
use rustc_middle::ty::subst::{GenericArg, GenericArgKind, Subst};
@@ -11,6 +13,7 @@
use rustc_target::spec::abi::Abi;
use std::fmt::Write;
+use std::iter;
use std::ops::Range;
pub(super) fn mangle(
@@ -23,15 +26,12 @@
let substs = tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), instance.substs);
let prefix = "_R";
- let mut cx = SymbolMangler {
+ let mut cx = &mut SymbolMangler {
tcx,
- compress: Some(Box::new(CompressionCaches {
- start_offset: prefix.len(),
-
- paths: FxHashMap::default(),
- types: FxHashMap::default(),
- consts: FxHashMap::default(),
- })),
+ start_offset: prefix.len(),
+ paths: FxHashMap::default(),
+ types: FxHashMap::default(),
+ consts: FxHashMap::default(),
binders: vec![],
out: String::from(prefix),
};
@@ -52,17 +52,7 @@
if let Some(instantiating_crate) = instantiating_crate {
cx = cx.print_def_path(instantiating_crate.as_def_id(), &[]).unwrap();
}
- cx.out
-}
-
-struct CompressionCaches<'tcx> {
- // The length of the prefix in `out` (e.g. 2 for `_R`).
- start_offset: usize,
-
- // The values are start positions in `out`, in bytes.
- paths: FxHashMap<(DefId, &'tcx [GenericArg<'tcx>]), usize>,
- types: FxHashMap<Ty<'tcx>, usize>,
- consts: FxHashMap<&'tcx ty::Const<'tcx>, usize>,
+ std::mem::take(&mut cx.out)
}
struct BinderLevel {
@@ -81,9 +71,15 @@
struct SymbolMangler<'tcx> {
tcx: TyCtxt<'tcx>,
- compress: Option<Box<CompressionCaches<'tcx>>>,
binders: Vec<BinderLevel>,
out: String,
+
+ /// The length of the prefix in `out` (e.g. 2 for `_R`).
+ start_offset: usize,
+ /// The values are start positions in `out`, in bytes.
+ paths: FxHashMap<(DefId, &'tcx [GenericArg<'tcx>]), usize>,
+ types: FxHashMap<Ty<'tcx>, usize>,
+ consts: FxHashMap<&'tcx ty::Const<'tcx>, usize>,
}
impl SymbolMangler<'tcx> {
@@ -160,13 +156,13 @@
self.push(ident);
}
- fn path_append_ns(
- mut self,
- print_prefix: impl FnOnce(Self) -> Result<Self, !>,
+ fn path_append_ns<'a>(
+ mut self: &'a mut Self,
+ print_prefix: impl FnOnce(&'a mut Self) -> Result<&'a mut Self, !>,
ns: char,
disambiguator: u64,
name: &str,
- ) -> Result<Self, !> {
+ ) -> Result<&'a mut Self, !> {
self.push("N");
self.out.push(ns);
self = print_prefix(self)?;
@@ -175,17 +171,17 @@
Ok(self)
}
- fn print_backref(mut self, i: usize) -> Result<Self, !> {
+ fn print_backref(&mut self, i: usize) -> Result<&mut Self, !> {
self.push("B");
- self.push_integer_62((i - self.compress.as_ref().unwrap().start_offset) as u64);
+ self.push_integer_62((i - self.start_offset) as u64);
Ok(self)
}
- fn in_binder<T>(
- mut self,
+ fn in_binder<'a, T>(
+ mut self: &'a mut Self,
value: &ty::Binder<'tcx, T>,
- print_value: impl FnOnce(Self, &T) -> Result<Self, !>,
- ) -> Result<Self, !>
+ print_value: impl FnOnce(&'a mut Self, &T) -> Result<&'a mut Self, !>,
+ ) -> Result<&'a mut Self, !>
where
T: TypeFoldable<'tcx>,
{
@@ -218,7 +214,7 @@
}
}
-impl Printer<'tcx> for SymbolMangler<'tcx> {
+impl Printer<'tcx> for &mut SymbolMangler<'tcx> {
type Error = !;
type Path = Self;
@@ -236,7 +232,7 @@
def_id: DefId,
substs: &'tcx [GenericArg<'tcx>],
) -> Result<Self::Path, Self::Error> {
- if let Some(&i) = self.compress.as_ref().and_then(|c| c.paths.get(&(def_id, substs))) {
+ if let Some(&i) = self.paths.get(&(def_id, substs)) {
return self.print_backref(i);
}
let start = self.out.len();
@@ -246,9 +242,7 @@
// Only cache paths that do not refer to an enclosing
// binder (which would change depending on context).
if !substs.iter().any(|k| k.has_escaping_bound_vars()) {
- if let Some(c) = &mut self.compress {
- c.paths.insert((def_id, substs), start);
- }
+ self.paths.insert((def_id, substs), start);
}
Ok(self)
}
@@ -286,7 +280,9 @@
// Encode impl generic params if the substitutions contain parameters (implying
// polymorphization is enabled) and this isn't an inherent impl.
- if impl_trait_ref.is_some() && substs.iter().any(|a| a.has_param_types_or_consts()) {
+ if impl_trait_ref.is_some()
+ && substs.iter().any(|a| a.definitely_has_param_types_or_consts(self.tcx))
+ {
self = self.path_generic_args(
|this| {
this.path_append_ns(
@@ -312,7 +308,7 @@
Ok(self)
}
- fn print_region(mut self, region: ty::Region<'_>) -> Result<Self::Region, Self::Error> {
+ fn print_region(self, region: ty::Region<'_>) -> Result<Self::Region, Self::Error> {
let i = match *region {
// Erased lifetimes use the index 0, for a
// shorter mangling of `L_`.
@@ -367,7 +363,7 @@
return Ok(self);
}
- if let Some(&i) = self.compress.as_ref().and_then(|c| c.types.get(&ty)) {
+ if let Some(&i) = self.types.get(&ty) {
return self.print_backref(i);
}
let start = self.out.len();
@@ -476,9 +472,7 @@
// Only cache types that do not refer to an enclosing
// binder (which would change depending on context).
if !ty.has_escaping_bound_vars() {
- if let Some(c) = &mut self.compress {
- c.types.insert(ty, start);
- }
+ self.types.insert(ty, start);
}
Ok(self)
}
@@ -545,52 +539,164 @@
}
fn print_const(mut self, ct: &'tcx ty::Const<'tcx>) -> Result<Self::Const, Self::Error> {
- if let Some(&i) = self.compress.as_ref().and_then(|c| c.consts.get(&ct)) {
+ // We only mangle a typed value if the const can be evaluated.
+ let ct = ct.eval(self.tcx, ty::ParamEnv::reveal_all());
+ match ct.val {
+ ty::ConstKind::Value(_) => {}
+
+ // Placeholders (should be demangled as `_`).
+ // NOTE(eddyb) despite `Unevaluated` having a `DefId` (and therefore
+ // a path), even for it we still need to encode a placeholder, as
+ // the path could refer back to e.g. an `impl` using the constant.
+ ty::ConstKind::Unevaluated(_)
+ | ty::ConstKind::Param(_)
+ | ty::ConstKind::Infer(_)
+ | ty::ConstKind::Bound(..)
+ | ty::ConstKind::Placeholder(_)
+ | ty::ConstKind::Error(_) => {
+ // Never cached (single-character).
+ self.push("p");
+ return Ok(self);
+ }
+ }
+
+ if let Some(&i) = self.consts.get(&ct) {
return self.print_backref(i);
}
let start = self.out.len();
- let mut neg = false;
- let val = match ct.ty.kind() {
- ty::Uint(_) | ty::Bool | ty::Char => {
- ct.try_eval_bits(self.tcx, ty::ParamEnv::reveal_all(), ct.ty)
- }
- ty::Int(ity) => {
- ct.try_eval_bits(self.tcx, ty::ParamEnv::reveal_all(), ct.ty).and_then(|b| {
- let val = Integer::from_int_ty(&self.tcx, *ity).size().sign_extend(b) as i128;
+ match ct.ty.kind() {
+ ty::Uint(_) | ty::Int(_) | ty::Bool | ty::Char => {
+ self = ct.ty.print(self)?;
+
+ let mut bits = ct.eval_bits(self.tcx, ty::ParamEnv::reveal_all(), ct.ty);
+
+ // Negative integer values are mangled using `n` as a "sign prefix".
+ if let ty::Int(ity) = ct.ty.kind() {
+ let val =
+ Integer::from_int_ty(&self.tcx, *ity).size().sign_extend(bits) as i128;
if val < 0 {
- neg = true;
+ self.push("n");
}
- Some(val.unsigned_abs())
- })
+ bits = val.unsigned_abs();
+ }
+
+ let _ = write!(self.out, "{:x}_", bits);
}
+
+ // HACK(eddyb) because `ty::Const` only supports sized values (for now),
+ // we can't use `deref_const` + supporting `str`, we have to specially
+ // handle `&str` and include both `&` ("R") and `str` ("e") prefixes.
+ ty::Ref(_, ty, hir::Mutability::Not) if *ty == self.tcx.types.str_ => {
+ self.push("R");
+ match ct.val {
+ ty::ConstKind::Value(ConstValue::Slice { data, start, end }) => {
+ // NOTE(eddyb) the following comment was kept from `ty::print::pretty`:
+ // The `inspect` here is okay since we checked the bounds, and there are no
+ // relocations (we have an active `str` reference here). We don't use this
+ // result to affect interpreter execution.
+ let slice =
+ data.inspect_with_uninit_and_ptr_outside_interpreter(start..end);
+ let s = std::str::from_utf8(slice).expect("non utf8 str from miri");
+
+ self.push("e");
+ // FIXME(eddyb) use a specialized hex-encoding loop.
+ for byte in s.bytes() {
+ let _ = write!(self.out, "{:02x}", byte);
+ }
+ self.push("_");
+ }
+
+ _ => {
+ bug!("symbol_names: unsupported `&str` constant: {:?}", ct);
+ }
+ }
+ }
+
+ ty::Ref(_, _, mutbl) => {
+ self.push(match mutbl {
+ hir::Mutability::Not => "R",
+ hir::Mutability::Mut => "Q",
+ });
+ self = self.tcx.deref_const(ty::ParamEnv::reveal_all().and(ct)).print(self)?;
+ }
+
+ ty::Array(..) | ty::Tuple(..) | ty::Adt(..) => {
+ let contents = self.tcx.destructure_const(ty::ParamEnv::reveal_all().and(ct));
+ let fields = contents.fields.iter().copied();
+
+ let print_field_list = |mut this: Self| {
+ for field in fields.clone() {
+ this = field.print(this)?;
+ }
+ this.push("E");
+ Ok(this)
+ };
+
+ match *ct.ty.kind() {
+ ty::Array(..) => {
+ self.push("A");
+ self = print_field_list(self)?;
+ }
+ ty::Tuple(..) => {
+ self.push("T");
+ self = print_field_list(self)?;
+ }
+ ty::Adt(def, substs) => {
+ let variant_idx =
+ contents.variant.expect("destructed const of adt without variant idx");
+ let variant_def = &def.variants[variant_idx];
+
+ self.push("V");
+ self = self.print_def_path(variant_def.def_id, substs)?;
+
+ match variant_def.ctor_kind {
+ CtorKind::Const => {
+ self.push("U");
+ }
+ CtorKind::Fn => {
+ self.push("T");
+ self = print_field_list(self)?;
+ }
+ CtorKind::Fictive => {
+ self.push("S");
+ for (field_def, field) in iter::zip(&variant_def.fields, fields) {
+ // HACK(eddyb) this mimics `path_append`,
+ // instead of simply using `field_def.ident`,
+ // just to be able to handle disambiguators.
+ let disambiguated_field =
+ self.tcx.def_key(field_def.did).disambiguated_data;
+ let field_name =
+ disambiguated_field.data.get_opt_name().map(|s| s.as_str());
+ self.push_disambiguator(
+ disambiguated_field.disambiguator as u64,
+ );
+ self.push_ident(&field_name.as_ref().map_or("", |s| &s[..]));
+
+ self = field.print(self)?;
+ }
+ self.push("E");
+ }
+ }
+ }
+ _ => unreachable!(),
+ }
+ }
+
_ => {
bug!("symbol_names: unsupported constant of type `{}` ({:?})", ct.ty, ct);
}
- };
-
- if let Some(bits) = val {
- // We only print the type if the const can be evaluated.
- self = ct.ty.print(self)?;
- let _ = write!(self.out, "{}{:x}_", if neg { "n" } else { "" }, bits);
- } else {
- // NOTE(eddyb) despite having the path, we need to
- // encode a placeholder, as the path could refer
- // back to e.g. an `impl` using the constant.
- self.push("p");
}
// Only cache consts that do not refer to an enclosing
// binder (which would change depending on context).
if !ct.has_escaping_bound_vars() {
- if let Some(c) = &mut self.compress {
- c.consts.insert(ct, start);
- }
+ self.consts.insert(ct, start);
}
Ok(self)
}
- fn path_crate(mut self, cnum: CrateNum) -> Result<Self::Path, Self::Error> {
+ fn path_crate(self, cnum: CrateNum) -> Result<Self::Path, Self::Error> {
self.push("C");
let stable_crate_id = self.tcx.def_path_hash(cnum.as_def_id()).stable_crate_id();
self.push_disambiguator(stable_crate_id.to_u64());
diff --git a/compiler/rustc_target/Cargo.toml b/compiler/rustc_target/Cargo.toml
index 2d7d9f1..e47a84d 100644
--- a/compiler/rustc_target/Cargo.toml
+++ b/compiler/rustc_target/Cargo.toml
@@ -1,5 +1,4 @@
[package]
-authors = ["The Rust Project Developers"]
name = "rustc_target"
version = "0.0.0"
edition = "2018"
diff --git a/compiler/rustc_target/src/abi/call/aarch64.rs b/compiler/rustc_target/src/abi/call/aarch64.rs
index a5e985d..4613a45 100644
--- a/compiler/rustc_target/src/abi/call/aarch64.rs
+++ b/compiler/rustc_target/src/abi/call/aarch64.rs
@@ -1,10 +1,10 @@
use crate::abi::call::{ArgAbi, FnAbi, Reg, RegKind, Uniform};
-use crate::abi::{HasDataLayout, LayoutOf, TyAndLayout, TyAndLayoutMethods};
+use crate::abi::{HasDataLayout, TyAbiInterface};
fn is_homogeneous_aggregate<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>) -> Option<Uniform>
where
- Ty: TyAndLayoutMethods<'a, C> + Copy,
- C: LayoutOf<Ty = Ty, TyAndLayout = TyAndLayout<'a, Ty>> + HasDataLayout,
+ Ty: TyAbiInterface<'a, C> + Copy,
+ C: HasDataLayout,
{
arg.layout.homogeneous_aggregate(cx).ok().and_then(|ha| ha.unit()).and_then(|unit| {
let size = arg.layout.size;
@@ -26,8 +26,8 @@
fn classify_ret<'a, Ty, C>(cx: &C, ret: &mut ArgAbi<'a, Ty>)
where
- Ty: TyAndLayoutMethods<'a, C> + Copy,
- C: LayoutOf<Ty = Ty, TyAndLayout = TyAndLayout<'a, Ty>> + HasDataLayout,
+ Ty: TyAbiInterface<'a, C> + Copy,
+ C: HasDataLayout,
{
if !ret.layout.is_aggregate() {
ret.extend_integer_width_to(32);
@@ -48,8 +48,8 @@
fn classify_arg<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>)
where
- Ty: TyAndLayoutMethods<'a, C> + Copy,
- C: LayoutOf<Ty = Ty, TyAndLayout = TyAndLayout<'a, Ty>> + HasDataLayout,
+ Ty: TyAbiInterface<'a, C> + Copy,
+ C: HasDataLayout,
{
if !arg.layout.is_aggregate() {
arg.extend_integer_width_to(32);
@@ -70,8 +70,8 @@
pub fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>)
where
- Ty: TyAndLayoutMethods<'a, C> + Copy,
- C: LayoutOf<Ty = Ty, TyAndLayout = TyAndLayout<'a, Ty>> + HasDataLayout,
+ Ty: TyAbiInterface<'a, C> + Copy,
+ C: HasDataLayout,
{
if !fn_abi.ret.is_ignore() {
classify_ret(cx, &mut fn_abi.ret);
diff --git a/compiler/rustc_target/src/abi/call/amdgpu.rs b/compiler/rustc_target/src/abi/call/amdgpu.rs
index 0b4f279..9be9747 100644
--- a/compiler/rustc_target/src/abi/call/amdgpu.rs
+++ b/compiler/rustc_target/src/abi/call/amdgpu.rs
@@ -1,26 +1,26 @@
use crate::abi::call::{ArgAbi, FnAbi};
-use crate::abi::{HasDataLayout, LayoutOf, TyAndLayout, TyAndLayoutMethods};
+use crate::abi::{HasDataLayout, TyAbiInterface};
fn classify_ret<'a, Ty, C>(_cx: &C, ret: &mut ArgAbi<'a, Ty>)
where
- Ty: TyAndLayoutMethods<'a, C> + Copy,
- C: LayoutOf<Ty = Ty, TyAndLayout = TyAndLayout<'a, Ty>> + HasDataLayout,
+ Ty: TyAbiInterface<'a, C> + Copy,
+ C: HasDataLayout,
{
ret.extend_integer_width_to(32);
}
fn classify_arg<'a, Ty, C>(_cx: &C, arg: &mut ArgAbi<'a, Ty>)
where
- Ty: TyAndLayoutMethods<'a, C> + Copy,
- C: LayoutOf<Ty = Ty, TyAndLayout = TyAndLayout<'a, Ty>> + HasDataLayout,
+ Ty: TyAbiInterface<'a, C> + Copy,
+ C: HasDataLayout,
{
arg.extend_integer_width_to(32);
}
pub fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>)
where
- Ty: TyAndLayoutMethods<'a, C> + Copy,
- C: LayoutOf<Ty = Ty, TyAndLayout = TyAndLayout<'a, Ty>> + HasDataLayout,
+ Ty: TyAbiInterface<'a, C> + Copy,
+ C: HasDataLayout,
{
if !fn_abi.ret.is_ignore() {
classify_ret(cx, &mut fn_abi.ret);
diff --git a/compiler/rustc_target/src/abi/call/arm.rs b/compiler/rustc_target/src/abi/call/arm.rs
index b560e11..e66c213 100644
--- a/compiler/rustc_target/src/abi/call/arm.rs
+++ b/compiler/rustc_target/src/abi/call/arm.rs
@@ -1,11 +1,11 @@
use crate::abi::call::{ArgAbi, Conv, FnAbi, Reg, RegKind, Uniform};
-use crate::abi::{HasDataLayout, LayoutOf, TyAndLayout, TyAndLayoutMethods};
+use crate::abi::{HasDataLayout, TyAbiInterface};
use crate::spec::HasTargetSpec;
fn is_homogeneous_aggregate<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>) -> Option<Uniform>
where
- Ty: TyAndLayoutMethods<'a, C> + Copy,
- C: LayoutOf<Ty = Ty, TyAndLayout = TyAndLayout<'a, Ty>> + HasDataLayout,
+ Ty: TyAbiInterface<'a, C> + Copy,
+ C: HasDataLayout,
{
arg.layout.homogeneous_aggregate(cx).ok().and_then(|ha| ha.unit()).and_then(|unit| {
let size = arg.layout.size;
@@ -27,8 +27,8 @@
fn classify_ret<'a, Ty, C>(cx: &C, ret: &mut ArgAbi<'a, Ty>, vfp: bool)
where
- Ty: TyAndLayoutMethods<'a, C> + Copy,
- C: LayoutOf<Ty = Ty, TyAndLayout = TyAndLayout<'a, Ty>> + HasDataLayout,
+ Ty: TyAbiInterface<'a, C> + Copy,
+ C: HasDataLayout,
{
if !ret.layout.is_aggregate() {
ret.extend_integer_width_to(32);
@@ -53,8 +53,8 @@
fn classify_arg<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>, vfp: bool)
where
- Ty: TyAndLayoutMethods<'a, C> + Copy,
- C: LayoutOf<Ty = Ty, TyAndLayout = TyAndLayout<'a, Ty>> + HasDataLayout,
+ Ty: TyAbiInterface<'a, C> + Copy,
+ C: HasDataLayout,
{
if !arg.layout.is_aggregate() {
arg.extend_integer_width_to(32);
@@ -75,8 +75,8 @@
pub fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>)
where
- Ty: TyAndLayoutMethods<'a, C> + Copy,
- C: LayoutOf<Ty = Ty, TyAndLayout = TyAndLayout<'a, Ty>> + HasDataLayout + HasTargetSpec,
+ Ty: TyAbiInterface<'a, C> + Copy,
+ C: HasDataLayout + HasTargetSpec,
{
// If this is a target with a hard-float ABI, and the function is not explicitly
// `extern "aapcs"`, then we must use the VFP registers for homogeneous aggregates.
diff --git a/compiler/rustc_target/src/abi/call/mips.rs b/compiler/rustc_target/src/abi/call/mips.rs
index 733a732..cc44319 100644
--- a/compiler/rustc_target/src/abi/call/mips.rs
+++ b/compiler/rustc_target/src/abi/call/mips.rs
@@ -1,10 +1,9 @@
use crate::abi::call::{ArgAbi, FnAbi, Reg, Uniform};
-use crate::abi::{HasDataLayout, LayoutOf, Size, TyAndLayoutMethods};
+use crate::abi::{HasDataLayout, Size};
-fn classify_ret<'a, Ty, C>(cx: &C, ret: &mut ArgAbi<'_, Ty>, offset: &mut Size)
+fn classify_ret<Ty, C>(cx: &C, ret: &mut ArgAbi<'_, Ty>, offset: &mut Size)
where
- Ty: TyAndLayoutMethods<'a, C>,
- C: LayoutOf<Ty = Ty> + HasDataLayout,
+ C: HasDataLayout,
{
if !ret.layout.is_aggregate() {
ret.extend_integer_width_to(32);
@@ -14,10 +13,9 @@
}
}
-fn classify_arg<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'_, Ty>, offset: &mut Size)
+fn classify_arg<Ty, C>(cx: &C, arg: &mut ArgAbi<'_, Ty>, offset: &mut Size)
where
- Ty: TyAndLayoutMethods<'a, C>,
- C: LayoutOf<Ty = Ty> + HasDataLayout,
+ C: HasDataLayout,
{
let dl = cx.data_layout();
let size = arg.layout.size;
@@ -35,10 +33,9 @@
*offset = offset.align_to(align) + size.align_to(align);
}
-pub fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'_, Ty>)
+pub fn compute_abi_info<Ty, C>(cx: &C, fn_abi: &mut FnAbi<'_, Ty>)
where
- Ty: TyAndLayoutMethods<'a, C>,
- C: LayoutOf<Ty = Ty> + HasDataLayout,
+ C: HasDataLayout,
{
let mut offset = Size::ZERO;
if !fn_abi.ret.is_ignore() {
diff --git a/compiler/rustc_target/src/abi/call/mips64.rs b/compiler/rustc_target/src/abi/call/mips64.rs
index a630c84..28ca93c 100644
--- a/compiler/rustc_target/src/abi/call/mips64.rs
+++ b/compiler/rustc_target/src/abi/call/mips64.rs
@@ -1,5 +1,5 @@
use crate::abi::call::{ArgAbi, ArgExtension, CastTarget, FnAbi, PassMode, Reg, RegKind, Uniform};
-use crate::abi::{self, HasDataLayout, LayoutOf, Size, TyAndLayout, TyAndLayoutMethods};
+use crate::abi::{self, HasDataLayout, Size, TyAbiInterface};
fn extend_integer_width_mips<Ty>(arg: &mut ArgAbi<'_, Ty>, bits: u64) {
// Always sign extend u32 values on 64-bit mips
@@ -19,8 +19,8 @@
fn float_reg<'a, Ty, C>(cx: &C, ret: &ArgAbi<'a, Ty>, i: usize) -> Option<Reg>
where
- Ty: TyAndLayoutMethods<'a, C> + Copy,
- C: LayoutOf<Ty = Ty, TyAndLayout = TyAndLayout<'a, Ty>> + HasDataLayout,
+ Ty: TyAbiInterface<'a, C> + Copy,
+ C: HasDataLayout,
{
match ret.layout.field(cx, i).abi {
abi::Abi::Scalar(ref scalar) => match scalar.value {
@@ -34,8 +34,8 @@
fn classify_ret<'a, Ty, C>(cx: &C, ret: &mut ArgAbi<'a, Ty>)
where
- Ty: TyAndLayoutMethods<'a, C> + Copy,
- C: LayoutOf<Ty = Ty, TyAndLayout = TyAndLayout<'a, Ty>> + HasDataLayout,
+ Ty: TyAbiInterface<'a, C> + Copy,
+ C: HasDataLayout,
{
if !ret.layout.is_aggregate() {
extend_integer_width_mips(ret, 64);
@@ -74,8 +74,8 @@
fn classify_arg<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>)
where
- Ty: TyAndLayoutMethods<'a, C> + Copy,
- C: LayoutOf<Ty = Ty, TyAndLayout = TyAndLayout<'a, Ty>> + HasDataLayout,
+ Ty: TyAbiInterface<'a, C> + Copy,
+ C: HasDataLayout,
{
if !arg.layout.is_aggregate() {
extend_integer_width_mips(arg, 64);
@@ -144,8 +144,8 @@
pub fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>)
where
- Ty: TyAndLayoutMethods<'a, C> + Copy,
- C: LayoutOf<Ty = Ty, TyAndLayout = TyAndLayout<'a, Ty>> + HasDataLayout,
+ Ty: TyAbiInterface<'a, C> + Copy,
+ C: HasDataLayout,
{
if !fn_abi.ret.is_ignore() {
classify_ret(cx, &mut fn_abi.ret);
diff --git a/compiler/rustc_target/src/abi/call/mod.rs b/compiler/rustc_target/src/abi/call/mod.rs
index 6e0e140..6d3c731 100644
--- a/compiler/rustc_target/src/abi/call/mod.rs
+++ b/compiler/rustc_target/src/abi/call/mod.rs
@@ -1,5 +1,5 @@
use crate::abi::{self, Abi, Align, FieldsShape, Size};
-use crate::abi::{HasDataLayout, LayoutOf, TyAndLayout, TyAndLayoutMethods};
+use crate::abi::{HasDataLayout, TyAbiInterface, TyAndLayout};
use crate::spec::{self, HasTargetSpec};
mod aarch64;
@@ -316,8 +316,7 @@
/// specific targets.
pub fn homogeneous_aggregate<C>(&self, cx: &C) -> Result<HomogeneousAggregate, Heterogeneous>
where
- Ty: TyAndLayoutMethods<'a, C> + Copy,
- C: LayoutOf<Ty = Ty, TyAndLayout = Self>,
+ Ty: TyAbiInterface<'a, C> + Copy,
{
match self.abi {
Abi::Uninhabited => Err(Heterogeneous),
@@ -603,8 +602,8 @@
impl<'a, Ty> FnAbi<'a, Ty> {
pub fn adjust_for_cabi<C>(&mut self, cx: &C, abi: spec::abi::Abi) -> Result<(), String>
where
- Ty: TyAndLayoutMethods<'a, C> + Copy,
- C: LayoutOf<Ty = Ty, TyAndLayout = TyAndLayout<'a, Ty>> + HasDataLayout + HasTargetSpec,
+ Ty: TyAbiInterface<'a, C> + Copy,
+ C: HasDataLayout + HasTargetSpec,
{
if abi == spec::abi::Abi::X86Interrupt {
if let Some(arg) = self.args.first_mut() {
diff --git a/compiler/rustc_target/src/abi/call/powerpc64.rs b/compiler/rustc_target/src/abi/call/powerpc64.rs
index 8c2a9d0..c22ef9c 100644
--- a/compiler/rustc_target/src/abi/call/powerpc64.rs
+++ b/compiler/rustc_target/src/abi/call/powerpc64.rs
@@ -3,7 +3,7 @@
// need to be fixed when PowerPC vector support is added.
use crate::abi::call::{ArgAbi, FnAbi, Reg, RegKind, Uniform};
-use crate::abi::{Endian, HasDataLayout, LayoutOf, TyAndLayout, TyAndLayoutMethods};
+use crate::abi::{Endian, HasDataLayout, TyAbiInterface};
use crate::spec::HasTargetSpec;
#[derive(Debug, Clone, Copy, PartialEq)]
@@ -19,8 +19,8 @@
abi: ABI,
) -> Option<Uniform>
where
- Ty: TyAndLayoutMethods<'a, C> + Copy,
- C: LayoutOf<Ty = Ty, TyAndLayout = TyAndLayout<'a, Ty>> + HasDataLayout,
+ Ty: TyAbiInterface<'a, C> + Copy,
+ C: HasDataLayout,
{
arg.layout.homogeneous_aggregate(cx).ok().and_then(|ha| ha.unit()).and_then(|unit| {
// ELFv1 only passes one-member aggregates transparently.
@@ -43,8 +43,8 @@
fn classify_ret<'a, Ty, C>(cx: &C, ret: &mut ArgAbi<'a, Ty>, abi: ABI)
where
- Ty: TyAndLayoutMethods<'a, C> + Copy,
- C: LayoutOf<Ty = Ty, TyAndLayout = TyAndLayout<'a, Ty>> + HasDataLayout,
+ Ty: TyAbiInterface<'a, C> + Copy,
+ C: HasDataLayout,
{
if !ret.layout.is_aggregate() {
ret.extend_integer_width_to(64);
@@ -86,8 +86,8 @@
fn classify_arg<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>, abi: ABI)
where
- Ty: TyAndLayoutMethods<'a, C> + Copy,
- C: LayoutOf<Ty = Ty, TyAndLayout = TyAndLayout<'a, Ty>> + HasDataLayout,
+ Ty: TyAbiInterface<'a, C> + Copy,
+ C: HasDataLayout,
{
if !arg.layout.is_aggregate() {
arg.extend_integer_width_to(64);
@@ -116,8 +116,8 @@
pub fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>)
where
- Ty: TyAndLayoutMethods<'a, C> + Copy,
- C: LayoutOf<Ty = Ty, TyAndLayout = TyAndLayout<'a, Ty>> + HasDataLayout + HasTargetSpec,
+ Ty: TyAbiInterface<'a, C> + Copy,
+ C: HasDataLayout + HasTargetSpec,
{
let abi = if cx.target_spec().env == "musl" {
ELFv2
diff --git a/compiler/rustc_target/src/abi/call/riscv.rs b/compiler/rustc_target/src/abi/call/riscv.rs
index 1ab881d..8c2ef8c 100644
--- a/compiler/rustc_target/src/abi/call/riscv.rs
+++ b/compiler/rustc_target/src/abi/call/riscv.rs
@@ -5,9 +5,7 @@
// https://github.com/llvm/llvm-project/blob/8e780252a7284be45cf1ba224cabd884847e8e92/clang/lib/CodeGen/TargetInfo.cpp#L9311-L9773
use crate::abi::call::{ArgAbi, ArgExtension, CastTarget, FnAbi, PassMode, Reg, RegKind, Uniform};
-use crate::abi::{
- self, Abi, FieldsShape, HasDataLayout, LayoutOf, Size, TyAndLayout, TyAndLayoutMethods,
-};
+use crate::abi::{self, Abi, FieldsShape, HasDataLayout, Size, TyAbiInterface, TyAndLayout};
use crate::spec::HasTargetSpec;
#[derive(Copy, Clone)]
@@ -43,8 +41,7 @@
field2_kind: &mut RegPassKind,
) -> Result<(), CannotUseFpConv>
where
- Ty: TyAndLayoutMethods<'a, C> + Copy,
- C: LayoutOf<Ty = Ty, TyAndLayout = TyAndLayout<'a, Ty>>,
+ Ty: TyAbiInterface<'a, C> + Copy,
{
match arg_layout.abi {
Abi::Scalar(ref scalar) => match scalar.value {
@@ -130,8 +127,7 @@
flen: u64,
) -> Option<FloatConv>
where
- Ty: TyAndLayoutMethods<'a, C> + Copy,
- C: LayoutOf<Ty = Ty, TyAndLayout = TyAndLayout<'a, Ty>>,
+ Ty: TyAbiInterface<'a, C> + Copy,
{
let mut field1_kind = RegPassKind::Unknown;
let mut field2_kind = RegPassKind::Unknown;
@@ -149,8 +145,7 @@
fn classify_ret<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>, xlen: u64, flen: u64) -> bool
where
- Ty: TyAndLayoutMethods<'a, C> + Copy,
- C: LayoutOf<Ty = Ty, TyAndLayout = TyAndLayout<'a, Ty>>,
+ Ty: TyAbiInterface<'a, C> + Copy,
{
if let Some(conv) = should_use_fp_conv(cx, &arg.layout, xlen, flen) {
match conv {
@@ -212,8 +207,7 @@
avail_gprs: &mut u64,
avail_fprs: &mut u64,
) where
- Ty: TyAndLayoutMethods<'a, C> + Copy,
- C: LayoutOf<Ty = Ty, TyAndLayout = TyAndLayout<'a, Ty>>,
+ Ty: TyAbiInterface<'a, C> + Copy,
{
if !is_vararg {
match should_use_fp_conv(cx, &arg.layout, xlen, flen) {
@@ -320,8 +314,8 @@
pub fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>)
where
- Ty: TyAndLayoutMethods<'a, C> + Copy,
- C: LayoutOf<Ty = Ty, TyAndLayout = TyAndLayout<'a, Ty>> + HasDataLayout + HasTargetSpec,
+ Ty: TyAbiInterface<'a, C> + Copy,
+ C: HasDataLayout + HasTargetSpec,
{
let flen = match &cx.target_spec().llvm_abiname[..] {
"ilp32f" | "lp64f" => 32,
diff --git a/compiler/rustc_target/src/abi/call/s390x.rs b/compiler/rustc_target/src/abi/call/s390x.rs
index 005dcc6..5941089 100644
--- a/compiler/rustc_target/src/abi/call/s390x.rs
+++ b/compiler/rustc_target/src/abi/call/s390x.rs
@@ -2,13 +2,9 @@
// for a pre-z13 machine or using -mno-vx.
use crate::abi::call::{ArgAbi, FnAbi, Reg};
-use crate::abi::{self, HasDataLayout, LayoutOf, TyAndLayout, TyAndLayoutMethods};
+use crate::abi::{self, HasDataLayout, TyAbiInterface, TyAndLayout};
-fn classify_ret<'a, Ty, C>(ret: &mut ArgAbi<'_, Ty>)
-where
- Ty: TyAndLayoutMethods<'a, C>,
- C: LayoutOf<Ty = Ty> + HasDataLayout,
-{
+fn classify_ret<Ty>(ret: &mut ArgAbi<'_, Ty>) {
if !ret.layout.is_aggregate() && ret.layout.size.bits() <= 64 {
ret.extend_integer_width_to(64);
} else {
@@ -18,8 +14,8 @@
fn is_single_fp_element<'a, Ty, C>(cx: &C, layout: TyAndLayout<'a, Ty>) -> bool
where
- Ty: TyAndLayoutMethods<'a, C>,
- C: LayoutOf<Ty = Ty, TyAndLayout = TyAndLayout<'a, Ty>> + HasDataLayout,
+ Ty: TyAbiInterface<'a, C>,
+ C: HasDataLayout,
{
match layout.abi {
abi::Abi::Scalar(ref scalar) => scalar.value.is_float(),
@@ -36,8 +32,8 @@
fn classify_arg<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>)
where
- Ty: TyAndLayoutMethods<'a, C> + Copy,
- C: LayoutOf<Ty = Ty, TyAndLayout = TyAndLayout<'a, Ty>> + HasDataLayout,
+ Ty: TyAbiInterface<'a, C> + Copy,
+ C: HasDataLayout,
{
if !arg.layout.is_aggregate() && arg.layout.size.bits() <= 64 {
arg.extend_integer_width_to(64);
@@ -63,8 +59,8 @@
pub fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>)
where
- Ty: TyAndLayoutMethods<'a, C> + Copy,
- C: LayoutOf<Ty = Ty, TyAndLayout = TyAndLayout<'a, Ty>> + HasDataLayout,
+ Ty: TyAbiInterface<'a, C> + Copy,
+ C: HasDataLayout,
{
if !fn_abi.ret.is_ignore() {
classify_ret(&mut fn_abi.ret);
diff --git a/compiler/rustc_target/src/abi/call/sparc.rs b/compiler/rustc_target/src/abi/call/sparc.rs
index 733a732..cc44319 100644
--- a/compiler/rustc_target/src/abi/call/sparc.rs
+++ b/compiler/rustc_target/src/abi/call/sparc.rs
@@ -1,10 +1,9 @@
use crate::abi::call::{ArgAbi, FnAbi, Reg, Uniform};
-use crate::abi::{HasDataLayout, LayoutOf, Size, TyAndLayoutMethods};
+use crate::abi::{HasDataLayout, Size};
-fn classify_ret<'a, Ty, C>(cx: &C, ret: &mut ArgAbi<'_, Ty>, offset: &mut Size)
+fn classify_ret<Ty, C>(cx: &C, ret: &mut ArgAbi<'_, Ty>, offset: &mut Size)
where
- Ty: TyAndLayoutMethods<'a, C>,
- C: LayoutOf<Ty = Ty> + HasDataLayout,
+ C: HasDataLayout,
{
if !ret.layout.is_aggregate() {
ret.extend_integer_width_to(32);
@@ -14,10 +13,9 @@
}
}
-fn classify_arg<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'_, Ty>, offset: &mut Size)
+fn classify_arg<Ty, C>(cx: &C, arg: &mut ArgAbi<'_, Ty>, offset: &mut Size)
where
- Ty: TyAndLayoutMethods<'a, C>,
- C: LayoutOf<Ty = Ty> + HasDataLayout,
+ C: HasDataLayout,
{
let dl = cx.data_layout();
let size = arg.layout.size;
@@ -35,10 +33,9 @@
*offset = offset.align_to(align) + size.align_to(align);
}
-pub fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'_, Ty>)
+pub fn compute_abi_info<Ty, C>(cx: &C, fn_abi: &mut FnAbi<'_, Ty>)
where
- Ty: TyAndLayoutMethods<'a, C>,
- C: LayoutOf<Ty = Ty> + HasDataLayout,
+ C: HasDataLayout,
{
let mut offset = Size::ZERO;
if !fn_abi.ret.is_ignore() {
diff --git a/compiler/rustc_target/src/abi/call/sparc64.rs b/compiler/rustc_target/src/abi/call/sparc64.rs
index a647675..5d74c94 100644
--- a/compiler/rustc_target/src/abi/call/sparc64.rs
+++ b/compiler/rustc_target/src/abi/call/sparc64.rs
@@ -1,12 +1,12 @@
// FIXME: This needs an audit for correctness and completeness.
use crate::abi::call::{ArgAbi, FnAbi, Reg, RegKind, Uniform};
-use crate::abi::{HasDataLayout, LayoutOf, TyAndLayout, TyAndLayoutMethods};
+use crate::abi::{HasDataLayout, TyAbiInterface};
fn is_homogeneous_aggregate<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>) -> Option<Uniform>
where
- Ty: TyAndLayoutMethods<'a, C> + Copy,
- C: LayoutOf<Ty = Ty, TyAndLayout = TyAndLayout<'a, Ty>> + HasDataLayout,
+ Ty: TyAbiInterface<'a, C> + Copy,
+ C: HasDataLayout,
{
arg.layout.homogeneous_aggregate(cx).ok().and_then(|ha| ha.unit()).and_then(|unit| {
// Ensure we have at most eight uniquely addressable members.
@@ -26,8 +26,8 @@
fn classify_ret<'a, Ty, C>(cx: &C, ret: &mut ArgAbi<'a, Ty>)
where
- Ty: TyAndLayoutMethods<'a, C> + Copy,
- C: LayoutOf<Ty = Ty, TyAndLayout = TyAndLayout<'a, Ty>> + HasDataLayout,
+ Ty: TyAbiInterface<'a, C> + Copy,
+ C: HasDataLayout,
{
if !ret.layout.is_aggregate() {
ret.extend_integer_width_to(64);
@@ -52,8 +52,8 @@
fn classify_arg<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>)
where
- Ty: TyAndLayoutMethods<'a, C> + Copy,
- C: LayoutOf<Ty = Ty, TyAndLayout = TyAndLayout<'a, Ty>> + HasDataLayout,
+ Ty: TyAbiInterface<'a, C> + Copy,
+ C: HasDataLayout,
{
if !arg.layout.is_aggregate() {
arg.extend_integer_width_to(64);
@@ -76,8 +76,8 @@
pub fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>)
where
- Ty: TyAndLayoutMethods<'a, C> + Copy,
- C: LayoutOf<Ty = Ty, TyAndLayout = TyAndLayout<'a, Ty>> + HasDataLayout,
+ Ty: TyAbiInterface<'a, C> + Copy,
+ C: HasDataLayout,
{
if !fn_abi.ret.is_ignore() {
classify_ret(cx, &mut fn_abi.ret);
diff --git a/compiler/rustc_target/src/abi/call/wasm.rs b/compiler/rustc_target/src/abi/call/wasm.rs
index bf2c08b..3237cde 100644
--- a/compiler/rustc_target/src/abi/call/wasm.rs
+++ b/compiler/rustc_target/src/abi/call/wasm.rs
@@ -1,10 +1,10 @@
use crate::abi::call::{ArgAbi, FnAbi, Uniform};
-use crate::abi::{HasDataLayout, LayoutOf, TyAndLayout, TyAndLayoutMethods};
+use crate::abi::{HasDataLayout, TyAbiInterface};
fn unwrap_trivial_aggregate<'a, Ty, C>(cx: &C, val: &mut ArgAbi<'a, Ty>) -> bool
where
- Ty: TyAndLayoutMethods<'a, C> + Copy,
- C: LayoutOf<Ty = Ty, TyAndLayout = TyAndLayout<'a, Ty>> + HasDataLayout,
+ Ty: TyAbiInterface<'a, C> + Copy,
+ C: HasDataLayout,
{
if val.layout.is_aggregate() {
if let Some(unit) = val.layout.homogeneous_aggregate(cx).ok().and_then(|ha| ha.unit()) {
@@ -20,8 +20,8 @@
fn classify_ret<'a, Ty, C>(cx: &C, ret: &mut ArgAbi<'a, Ty>)
where
- Ty: TyAndLayoutMethods<'a, C> + Copy,
- C: LayoutOf<Ty = Ty, TyAndLayout = TyAndLayout<'a, Ty>> + HasDataLayout,
+ Ty: TyAbiInterface<'a, C> + Copy,
+ C: HasDataLayout,
{
ret.extend_integer_width_to(32);
if ret.layout.is_aggregate() && !unwrap_trivial_aggregate(cx, ret) {
@@ -31,8 +31,8 @@
fn classify_arg<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>)
where
- Ty: TyAndLayoutMethods<'a, C> + Copy,
- C: LayoutOf<Ty = Ty, TyAndLayout = TyAndLayout<'a, Ty>> + HasDataLayout,
+ Ty: TyAbiInterface<'a, C> + Copy,
+ C: HasDataLayout,
{
arg.extend_integer_width_to(32);
if arg.layout.is_aggregate() && !unwrap_trivial_aggregate(cx, arg) {
@@ -43,8 +43,8 @@
/// The purpose of this ABI is to match the C ABI (aka clang) exactly.
pub fn compute_c_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>)
where
- Ty: TyAndLayoutMethods<'a, C> + Copy,
- C: LayoutOf<Ty = Ty, TyAndLayout = TyAndLayout<'a, Ty>> + HasDataLayout,
+ Ty: TyAbiInterface<'a, C> + Copy,
+ C: HasDataLayout,
{
if !fn_abi.ret.is_ignore() {
classify_ret(cx, &mut fn_abi.ret);
diff --git a/compiler/rustc_target/src/abi/call/x86.rs b/compiler/rustc_target/src/abi/call/x86.rs
index ff8849e..3fc197b 100644
--- a/compiler/rustc_target/src/abi/call/x86.rs
+++ b/compiler/rustc_target/src/abi/call/x86.rs
@@ -1,5 +1,5 @@
use crate::abi::call::{ArgAttribute, FnAbi, PassMode, Reg, RegKind};
-use crate::abi::{self, HasDataLayout, LayoutOf, TyAndLayout, TyAndLayoutMethods};
+use crate::abi::{self, HasDataLayout, TyAbiInterface, TyAndLayout};
use crate::spec::HasTargetSpec;
#[derive(PartialEq)]
@@ -10,8 +10,8 @@
fn is_single_fp_element<'a, Ty, C>(cx: &C, layout: TyAndLayout<'a, Ty>) -> bool
where
- Ty: TyAndLayoutMethods<'a, C> + Copy,
- C: LayoutOf<Ty = Ty, TyAndLayout = TyAndLayout<'a, Ty>> + HasDataLayout,
+ Ty: TyAbiInterface<'a, C> + Copy,
+ C: HasDataLayout,
{
match layout.abi {
abi::Abi::Scalar(ref scalar) => scalar.value.is_float(),
@@ -28,8 +28,8 @@
pub fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>, flavor: Flavor)
where
- Ty: TyAndLayoutMethods<'a, C> + Copy,
- C: LayoutOf<Ty = Ty, TyAndLayout = TyAndLayout<'a, Ty>> + HasDataLayout + HasTargetSpec,
+ Ty: TyAbiInterface<'a, C> + Copy,
+ C: HasDataLayout + HasTargetSpec,
{
if !fn_abi.ret.is_ignore() {
if fn_abi.ret.layout.is_aggregate() {
diff --git a/compiler/rustc_target/src/abi/call/x86_64.rs b/compiler/rustc_target/src/abi/call/x86_64.rs
index a55658b..08f0aab 100644
--- a/compiler/rustc_target/src/abi/call/x86_64.rs
+++ b/compiler/rustc_target/src/abi/call/x86_64.rs
@@ -2,7 +2,7 @@
// https://github.com/jckarter/clay/blob/master/compiler/src/externals.cpp
use crate::abi::call::{ArgAbi, CastTarget, FnAbi, Reg, RegKind};
-use crate::abi::{self, Abi, HasDataLayout, LayoutOf, Size, TyAndLayout, TyAndLayoutMethods};
+use crate::abi::{self, Abi, HasDataLayout, Size, TyAbiInterface, TyAndLayout};
/// Classification of "eightbyte" components.
// N.B., the order of the variants is from general to specific,
@@ -26,8 +26,8 @@
arg: &ArgAbi<'a, Ty>,
) -> Result<[Option<Class>; MAX_EIGHTBYTES], Memory>
where
- Ty: TyAndLayoutMethods<'a, C> + Copy,
- C: LayoutOf<Ty = Ty, TyAndLayout = TyAndLayout<'a, Ty>> + HasDataLayout,
+ Ty: TyAbiInterface<'a, C> + Copy,
+ C: HasDataLayout,
{
fn classify<'a, Ty, C>(
cx: &C,
@@ -36,8 +36,8 @@
off: Size,
) -> Result<(), Memory>
where
- Ty: TyAndLayoutMethods<'a, C> + Copy,
- C: LayoutOf<Ty = Ty, TyAndLayout = TyAndLayout<'a, Ty>> + HasDataLayout,
+ Ty: TyAbiInterface<'a, C> + Copy,
+ C: HasDataLayout,
{
if !off.is_aligned(layout.align.abi) {
if !layout.is_zst() {
@@ -172,8 +172,8 @@
pub fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>)
where
- Ty: TyAndLayoutMethods<'a, C> + Copy,
- C: LayoutOf<Ty = Ty, TyAndLayout = TyAndLayout<'a, Ty>> + HasDataLayout,
+ Ty: TyAbiInterface<'a, C> + Copy,
+ C: HasDataLayout,
{
let mut int_regs = MAX_INT_REGS;
let mut sse_regs = MAX_SSE_REGS;
diff --git a/compiler/rustc_target/src/abi/mod.rs b/compiler/rustc_target/src/abi/mod.rs
index 9a24edf..8203999 100644
--- a/compiler/rustc_target/src/abi/mod.rs
+++ b/compiler/rustc_target/src/abi/mod.rs
@@ -5,6 +5,7 @@
use std::convert::{TryFrom, TryInto};
use std::fmt;
+use std::iter::Step;
use std::num::NonZeroUsize;
use std::ops::{Add, AddAssign, Deref, Mul, Range, RangeInclusive, Sub};
use std::str::FromStr;
@@ -36,6 +37,9 @@
pub vector_align: Vec<(Size, AbiAndPrefAlign)>,
pub instruction_address_space: AddressSpace,
+
+ /// Minimum size of #[repr(C)] enums (default I32 bits)
+ pub c_enum_min_size: Integer,
}
impl Default for TargetDataLayout {
@@ -60,6 +64,7 @@
(Size::from_bits(128), AbiAndPrefAlign::new(align(128))),
],
instruction_address_space: AddressSpace::DATA,
+ c_enum_min_size: Integer::I32,
}
}
}
@@ -173,6 +178,8 @@
));
}
+ dl.c_enum_min_size = Integer::from_size(Size::from_bits(target.c_enum_min_bits))?;
+
Ok(dl)
}
@@ -187,6 +194,7 @@
/// to represent object size in bits. It would need to be 1 << 61 to account for this, but is
/// currently conservatively bounded to 1 << 47 as that is enough to cover the current usable
/// address space on 64-bit ARMv8 and x86_64.
+ #[inline]
pub fn obj_size_bound(&self) -> u64 {
match self.pointer_size.bits() {
16 => 1 << 15,
@@ -196,6 +204,7 @@
}
}
+ #[inline]
pub fn ptr_sized_integer(&self) -> Integer {
match self.pointer_size.bits() {
16 => I16,
@@ -205,6 +214,7 @@
}
}
+ #[inline]
pub fn vector_align(&self, vec_size: Size) -> AbiAndPrefAlign {
for &(size, align) in &self.vector_align {
if size == vec_size {
@@ -434,6 +444,43 @@
}
}
+impl Step for Size {
+ #[inline]
+ fn steps_between(start: &Self, end: &Self) -> Option<usize> {
+ u64::steps_between(&start.bytes(), &end.bytes())
+ }
+
+ #[inline]
+ fn forward_checked(start: Self, count: usize) -> Option<Self> {
+ u64::forward_checked(start.bytes(), count).map(Self::from_bytes)
+ }
+
+ #[inline]
+ fn forward(start: Self, count: usize) -> Self {
+ Self::from_bytes(u64::forward(start.bytes(), count))
+ }
+
+ #[inline]
+ unsafe fn forward_unchecked(start: Self, count: usize) -> Self {
+ Self::from_bytes(u64::forward_unchecked(start.bytes(), count))
+ }
+
+ #[inline]
+ fn backward_checked(start: Self, count: usize) -> Option<Self> {
+ u64::backward_checked(start.bytes(), count).map(Self::from_bytes)
+ }
+
+ #[inline]
+ fn backward(start: Self, count: usize) -> Self {
+ Self::from_bytes(u64::backward(start.bytes(), count))
+ }
+
+ #[inline]
+ unsafe fn backward_unchecked(start: Self, count: usize) -> Self {
+ Self::from_bytes(u64::backward_unchecked(start.bytes(), count))
+ }
+}
+
/// Alignment of a type in bytes (always a power of two).
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Encodable, Decodable)]
#[derive(HashStable_Generic)]
@@ -518,14 +565,17 @@
}
impl AbiAndPrefAlign {
+ #[inline]
pub fn new(align: Align) -> AbiAndPrefAlign {
AbiAndPrefAlign { abi: align, pref: align }
}
+ #[inline]
pub fn min(self, other: AbiAndPrefAlign) -> AbiAndPrefAlign {
AbiAndPrefAlign { abi: self.abi.min(other.abi), pref: self.pref.min(other.pref) }
}
+ #[inline]
pub fn max(self, other: AbiAndPrefAlign) -> AbiAndPrefAlign {
AbiAndPrefAlign { abi: self.abi.max(other.abi), pref: self.pref.max(other.pref) }
}
@@ -542,6 +592,7 @@
}
impl Integer {
+ #[inline]
pub fn size(self) -> Size {
match self {
I8 => Size::from_bytes(1),
@@ -565,6 +616,7 @@
}
/// Finds the smallest Integer type which can represent the signed value.
+ #[inline]
pub fn fit_signed(x: i128) -> Integer {
match x {
-0x0000_0000_0000_0080..=0x0000_0000_0000_007f => I8,
@@ -576,6 +628,7 @@
}
/// Finds the smallest Integer type which can represent the unsigned value.
+ #[inline]
pub fn fit_unsigned(x: u128) -> Integer {
match x {
0..=0x0000_0000_0000_00ff => I8,
@@ -610,6 +663,20 @@
}
I8
}
+
+ // FIXME(eddyb) consolidate this and other methods that find the appropriate
+ // `Integer` given some requirements.
+ #[inline]
+ fn from_size(size: Size) -> Result<Self, String> {
+ match size.bits() {
+ 8 => Ok(Integer::I8),
+ 16 => Ok(Integer::I16),
+ 32 => Ok(Integer::I32),
+ 64 => Ok(Integer::I64),
+ 128 => Ok(Integer::I128),
+ _ => Err(format!("rust does not support integers with {} bits", size.bits())),
+ }
+ }
}
/// Fundamental unit of memory access and layout.
@@ -651,41 +718,94 @@
}
}
+ // FIXME(eddyb) remove, it's trivial thanks to `matches!`.
+ #[inline]
pub fn is_float(self) -> bool {
matches!(self, F32 | F64)
}
+ // FIXME(eddyb) remove, it's completely unused.
+ #[inline]
pub fn is_int(self) -> bool {
matches!(self, Int(..))
}
}
+/// Inclusive wrap-around range of valid values, that is, if
+/// start > end, it represents `start..=MAX`,
+/// followed by `0..=end`.
+///
+/// That is, for an i8 primitive, a range of `254..=2` means following
+/// sequence:
+///
+/// 254 (-2), 255 (-1), 0, 1, 2
+///
+/// This is intended specifically to mirror LLVM’s `!range` metadata,
+/// semantics.
+#[derive(Clone, PartialEq, Eq, Hash)]
+#[derive(HashStable_Generic)]
+pub struct WrappingRange {
+ pub start: u128,
+ pub end: u128,
+}
+
+impl WrappingRange {
+ /// Returns `true` if `v` is contained in the range.
+ #[inline(always)]
+ pub fn contains(&self, v: u128) -> bool {
+ if self.start <= self.end {
+ self.start <= v && v <= self.end
+ } else {
+ self.start <= v || v <= self.end
+ }
+ }
+
+ /// Returns `true` if zero is contained in the range.
+ /// Equal to `range.contains(0)` but should be faster.
+ #[inline(always)]
+ pub fn contains_zero(&self) -> bool {
+ self.start > self.end || self.start == 0
+ }
+
+ /// Returns `self` with replaced `start`
+ #[inline(always)]
+ pub fn with_start(mut self, start: u128) -> Self {
+ self.start = start;
+ self
+ }
+
+ /// Returns `self` with replaced `end`
+ #[inline(always)]
+ pub fn with_end(mut self, end: u128) -> Self {
+ self.end = end;
+ self
+ }
+}
+
+impl fmt::Debug for WrappingRange {
+ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(fmt, "{}..={}", self.start, self.end)?;
+ Ok(())
+ }
+}
+
/// Information about one scalar component of a Rust type.
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
#[derive(HashStable_Generic)]
pub struct Scalar {
pub value: Primitive,
- /// Inclusive wrap-around range of valid values, that is, if
- /// start > end, it represents `start..=MAX`,
- /// followed by `0..=end`.
- ///
- /// That is, for an i8 primitive, a range of `254..=2` means following
- /// sequence:
- ///
- /// 254 (-2), 255 (-1), 0, 1, 2
- ///
- /// This is intended specifically to mirror LLVM’s `!range` metadata,
- /// semantics.
// FIXME(eddyb) always use the shortest range, e.g., by finding
// the largest space between two consecutive valid values and
// taking everything else as the (shortest) valid range.
- pub valid_range: RangeInclusive<u128>,
+ pub valid_range: WrappingRange,
}
impl Scalar {
+ #[inline]
pub fn is_bool(&self) -> bool {
- matches!(self.value, Int(I8, false)) && self.valid_range == (0..=1)
+ matches!(self.value, Int(I8, false))
+ && matches!(self.valid_range, WrappingRange { start: 0, end: 1 })
}
/// Returns the valid range as a `x..y` range.
@@ -698,8 +818,8 @@
let bits = self.value.size(cx).bits();
assert!(bits <= 128);
let mask = !0u128 >> (128 - bits);
- let start = *self.valid_range.start();
- let end = *self.valid_range.end();
+ let start = self.valid_range.start;
+ let end = self.valid_range.end;
assert_eq!(start, start & mask);
assert_eq!(end, end & mask);
start..(end.wrapping_add(1) & mask)
@@ -749,6 +869,7 @@
}
impl FieldsShape {
+ #[inline]
pub fn count(&self) -> usize {
match *self {
FieldsShape::Primitive => 0,
@@ -758,6 +879,7 @@
}
}
+ #[inline]
pub fn offset(&self, i: usize) -> Size {
match *self {
FieldsShape::Primitive => {
@@ -781,6 +903,7 @@
}
}
+ #[inline]
pub fn memory_index(&self, i: usize) -> usize {
match *self {
FieldsShape::Primitive => {
@@ -864,6 +987,7 @@
}
/// Returns `true` if this is a single signed integer scalar
+ #[inline]
pub fn is_signed(&self) -> bool {
match *self {
Abi::Scalar(ref scal) => match scal.value {
@@ -954,14 +1078,14 @@
let max_value = !0u128 >> (128 - bits);
// Find out how many values are outside the valid range.
- let niche = v.end().wrapping_add(1)..*v.start();
+ let niche = v.end.wrapping_add(1)..v.start;
niche.end.wrapping_sub(niche.start) & max_value
}
pub fn reserve<C: HasDataLayout>(&self, cx: &C, count: u128) -> Option<(u128, Scalar)> {
assert!(count > 0);
- let Scalar { value, valid_range: ref v } = self.scalar;
+ let Scalar { value, valid_range: v } = self.scalar.clone();
let bits = value.size(cx).bits();
assert!(bits <= 128);
let max_value = !0u128 >> (128 - bits);
@@ -971,24 +1095,14 @@
}
// Compute the range of invalid values being reserved.
- let start = v.end().wrapping_add(1) & max_value;
- let end = v.end().wrapping_add(count) & max_value;
+ let start = v.end.wrapping_add(1) & max_value;
+ let end = v.end.wrapping_add(count) & max_value;
- // If the `end` of our range is inside the valid range,
- // then we ran out of invalid values.
- // FIXME(eddyb) abstract this with a wraparound range type.
- let valid_range_contains = |x| {
- if v.start() <= v.end() {
- *v.start() <= x && x <= *v.end()
- } else {
- *v.start() <= x || x <= *v.end()
- }
- };
- if valid_range_contains(end) {
+ if v.contains(end) {
return None;
}
- Some((start, Scalar { value, valid_range: *v.start()..=end }))
+ Some((start, Scalar { value, valid_range: v.with_end(end) }))
}
}
@@ -1046,7 +1160,7 @@
/// to that obtained from `layout_of(ty)`, as we need to produce
/// layouts for which Rust types do not exist, such as enum variants
/// or synthetic fields of enums (i.e., discriminants) and fat pointers.
-#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
+#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, HashStable_Generic)]
pub struct TyAndLayout<'a, Ty> {
pub ty: Ty,
pub layout: &'a Layout,
@@ -1060,9 +1174,9 @@
}
/// Trait for context types that can compute layouts of things.
-pub trait LayoutOf {
- type Ty;
- type TyAndLayout;
+pub trait LayoutOf<'a>: Sized {
+ type Ty: TyAbiInterface<'a, Self>;
+ type TyAndLayout: MaybeResult<TyAndLayout<'a, Self::Ty>>;
fn layout_of(&self, ty: Self::Ty) -> Self::TyAndLayout;
fn spanned_layout_of(&self, ty: Self::Ty, _span: Span) -> Self::TyAndLayout {
@@ -1070,9 +1184,6 @@
}
}
-/// The `TyAndLayout` above will always be a `MaybeResult<TyAndLayout<'_, Self>>`.
-/// We can't add the bound due to the lifetime, but this trait is still useful when
-/// writing code that's generic over the `LayoutOf` impl.
pub trait MaybeResult<T> {
type Error;
@@ -1125,41 +1236,42 @@
pub address_space: AddressSpace,
}
-pub trait TyAndLayoutMethods<'a, C: LayoutOf<Ty = Self>>: Sized {
- fn for_variant(
+/// Trait that needs to be implemented by the higher-level type representation
+/// (e.g. `rustc_middle::ty::Ty`), to provide `rustc_target::abi` functionality.
+pub trait TyAbiInterface<'a, C>: Sized {
+ fn ty_and_layout_for_variant(
this: TyAndLayout<'a, Self>,
cx: &C,
variant_index: VariantIdx,
) -> TyAndLayout<'a, Self>;
- fn field(this: TyAndLayout<'a, Self>, cx: &C, i: usize) -> C::TyAndLayout;
- fn pointee_info_at(this: TyAndLayout<'a, Self>, cx: &C, offset: Size) -> Option<PointeeInfo>;
+ fn ty_and_layout_field(this: TyAndLayout<'a, Self>, cx: &C, i: usize) -> TyAndLayout<'a, Self>;
+ fn ty_and_layout_pointee_info_at(
+ this: TyAndLayout<'a, Self>,
+ cx: &C,
+ offset: Size,
+ ) -> Option<PointeeInfo>;
}
impl<'a, Ty> TyAndLayout<'a, Ty> {
pub fn for_variant<C>(self, cx: &C, variant_index: VariantIdx) -> Self
where
- Ty: TyAndLayoutMethods<'a, C>,
- C: LayoutOf<Ty = Ty>,
+ Ty: TyAbiInterface<'a, C>,
{
- Ty::for_variant(self, cx, variant_index)
+ Ty::ty_and_layout_for_variant(self, cx, variant_index)
}
- /// Callers might want to use `C: LayoutOf<Ty=Ty, TyAndLayout: MaybeResult<Self>>`
- /// to allow recursion (see `might_permit_zero_init` below for an example).
- pub fn field<C>(self, cx: &C, i: usize) -> C::TyAndLayout
+ pub fn field<C>(self, cx: &C, i: usize) -> Self
where
- Ty: TyAndLayoutMethods<'a, C>,
- C: LayoutOf<Ty = Ty>,
+ Ty: TyAbiInterface<'a, C>,
{
- Ty::field(self, cx, i)
+ Ty::ty_and_layout_field(self, cx, i)
}
pub fn pointee_info_at<C>(self, cx: &C, offset: Size) -> Option<PointeeInfo>
where
- Ty: TyAndLayoutMethods<'a, C>,
- C: LayoutOf<Ty = Ty>,
+ Ty: TyAbiInterface<'a, C>,
{
- Ty::pointee_info_at(self, cx, offset)
+ Ty::ty_and_layout_pointee_info_at(self, cx, offset)
}
}
@@ -1187,17 +1299,16 @@
/// FIXME: Once we removed all the conservatism, we could alternatively
/// create an all-0/all-undef constant and run the const value validator to see if
/// this is a valid value for the given type.
- pub fn might_permit_raw_init<C, E>(self, cx: &C, zero: bool) -> Result<bool, E>
+ pub fn might_permit_raw_init<C>(self, cx: &C, zero: bool) -> bool
where
Self: Copy,
- Ty: TyAndLayoutMethods<'a, C>,
- C: LayoutOf<Ty = Ty, TyAndLayout: MaybeResult<Self, Error = E>> + HasDataLayout,
+ Ty: TyAbiInterface<'a, C>,
+ C: HasDataLayout,
{
let scalar_allows_raw_init = move |s: &Scalar| -> bool {
if zero {
- let range = &s.valid_range;
// The range must contain 0.
- range.contains(&0) || (*range.start() > *range.end()) // wrap-around allows 0
+ s.valid_range.contains_zero()
} else {
// The range must include all values. `valid_range_exclusive` handles
// the wrap-around using target arithmetic; with wrap-around then the full
@@ -1217,7 +1328,7 @@
};
if !valid {
// This is definitely not okay.
- return Ok(false);
+ return false;
}
// If we have not found an error yet, we need to recursively descend into fields.
@@ -1228,16 +1339,15 @@
}
FieldsShape::Arbitrary { offsets, .. } => {
for idx in 0..offsets.len() {
- let field = self.field(cx, idx).to_result()?;
- if !field.might_permit_raw_init(cx, zero)? {
+ if !self.field(cx, idx).might_permit_raw_init(cx, zero) {
// We found a field that is unhappy with this kind of initialization.
- return Ok(false);
+ return false;
}
}
}
}
// FIXME(#66151): For now, we are conservative and do not check `self.variants`.
- Ok(true)
+ true
}
}
diff --git a/compiler/rustc_target/src/asm/mod.rs b/compiler/rustc_target/src/asm/mod.rs
index b52fa5b..99699c5 100644
--- a/compiler/rustc_target/src/asm/mod.rs
+++ b/compiler/rustc_target/src/asm/mod.rs
@@ -154,6 +154,7 @@
mod nvptx;
mod powerpc;
mod riscv;
+mod s390x;
mod spirv;
mod wasm;
mod x86;
@@ -166,6 +167,7 @@
pub use nvptx::{NvptxInlineAsmReg, NvptxInlineAsmRegClass};
pub use powerpc::{PowerPCInlineAsmReg, PowerPCInlineAsmRegClass};
pub use riscv::{RiscVInlineAsmReg, RiscVInlineAsmRegClass};
+pub use s390x::{S390xInlineAsmReg, S390xInlineAsmRegClass};
pub use spirv::{SpirVInlineAsmReg, SpirVInlineAsmRegClass};
pub use wasm::{WasmInlineAsmReg, WasmInlineAsmRegClass};
pub use x86::{X86InlineAsmReg, X86InlineAsmRegClass};
@@ -184,6 +186,7 @@
Mips64,
PowerPC,
PowerPC64,
+ S390x,
SpirV,
Wasm32,
Bpf,
@@ -206,6 +209,7 @@
"hexagon" => Ok(Self::Hexagon),
"mips" => Ok(Self::Mips),
"mips64" => Ok(Self::Mips64),
+ "s390x" => Ok(Self::S390x),
"spirv" => Ok(Self::SpirV),
"wasm32" => Ok(Self::Wasm32),
"bpf" => Ok(Self::Bpf),
@@ -235,6 +239,7 @@
PowerPC(PowerPCInlineAsmReg),
Hexagon(HexagonInlineAsmReg),
Mips(MipsInlineAsmReg),
+ S390x(S390xInlineAsmReg),
SpirV(SpirVInlineAsmReg),
Wasm(WasmInlineAsmReg),
Bpf(BpfInlineAsmReg),
@@ -252,6 +257,7 @@
Self::PowerPC(r) => r.name(),
Self::Hexagon(r) => r.name(),
Self::Mips(r) => r.name(),
+ Self::S390x(r) => r.name(),
Self::Bpf(r) => r.name(),
Self::Err => "<reg>",
}
@@ -266,6 +272,7 @@
Self::PowerPC(r) => InlineAsmRegClass::PowerPC(r.reg_class()),
Self::Hexagon(r) => InlineAsmRegClass::Hexagon(r.reg_class()),
Self::Mips(r) => InlineAsmRegClass::Mips(r.reg_class()),
+ Self::S390x(r) => InlineAsmRegClass::S390x(r.reg_class()),
Self::Bpf(r) => InlineAsmRegClass::Bpf(r.reg_class()),
Self::Err => InlineAsmRegClass::Err,
}
@@ -305,6 +312,9 @@
InlineAsmArch::Mips | InlineAsmArch::Mips64 => {
Self::Mips(MipsInlineAsmReg::parse(arch, has_feature, target, &name)?)
}
+ InlineAsmArch::S390x => {
+ Self::S390x(S390xInlineAsmReg::parse(arch, has_feature, target, &name)?)
+ }
InlineAsmArch::SpirV => {
Self::SpirV(SpirVInlineAsmReg::parse(arch, has_feature, target, &name)?)
}
@@ -333,6 +343,7 @@
Self::PowerPC(r) => r.emit(out, arch, modifier),
Self::Hexagon(r) => r.emit(out, arch, modifier),
Self::Mips(r) => r.emit(out, arch, modifier),
+ Self::S390x(r) => r.emit(out, arch, modifier),
Self::Bpf(r) => r.emit(out, arch, modifier),
Self::Err => unreachable!("Use of InlineAsmReg::Err"),
}
@@ -344,9 +355,10 @@
Self::Arm(r) => r.overlapping_regs(|r| cb(Self::Arm(r))),
Self::AArch64(_) => cb(self),
Self::RiscV(_) => cb(self),
- Self::PowerPC(_) => cb(self),
+ Self::PowerPC(r) => r.overlapping_regs(|r| cb(Self::PowerPC(r))),
Self::Hexagon(r) => r.overlapping_regs(|r| cb(Self::Hexagon(r))),
Self::Mips(_) => cb(self),
+ Self::S390x(_) => cb(self),
Self::Bpf(r) => r.overlapping_regs(|r| cb(Self::Bpf(r))),
Self::Err => unreachable!("Use of InlineAsmReg::Err"),
}
@@ -374,6 +386,7 @@
PowerPC(PowerPCInlineAsmRegClass),
Hexagon(HexagonInlineAsmRegClass),
Mips(MipsInlineAsmRegClass),
+ S390x(S390xInlineAsmRegClass),
SpirV(SpirVInlineAsmRegClass),
Wasm(WasmInlineAsmRegClass),
Bpf(BpfInlineAsmRegClass),
@@ -392,6 +405,7 @@
Self::PowerPC(r) => r.name(),
Self::Hexagon(r) => r.name(),
Self::Mips(r) => r.name(),
+ Self::S390x(r) => r.name(),
Self::SpirV(r) => r.name(),
Self::Wasm(r) => r.name(),
Self::Bpf(r) => r.name(),
@@ -412,6 +426,7 @@
Self::PowerPC(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::PowerPC),
Self::Hexagon(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Hexagon),
Self::Mips(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Mips),
+ Self::S390x(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::S390x),
Self::SpirV(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::SpirV),
Self::Wasm(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Wasm),
Self::Bpf(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Bpf),
@@ -439,6 +454,7 @@
Self::PowerPC(r) => r.suggest_modifier(arch, ty),
Self::Hexagon(r) => r.suggest_modifier(arch, ty),
Self::Mips(r) => r.suggest_modifier(arch, ty),
+ Self::S390x(r) => r.suggest_modifier(arch, ty),
Self::SpirV(r) => r.suggest_modifier(arch, ty),
Self::Wasm(r) => r.suggest_modifier(arch, ty),
Self::Bpf(r) => r.suggest_modifier(arch, ty),
@@ -462,6 +478,7 @@
Self::PowerPC(r) => r.default_modifier(arch),
Self::Hexagon(r) => r.default_modifier(arch),
Self::Mips(r) => r.default_modifier(arch),
+ Self::S390x(r) => r.default_modifier(arch),
Self::SpirV(r) => r.default_modifier(arch),
Self::Wasm(r) => r.default_modifier(arch),
Self::Bpf(r) => r.default_modifier(arch),
@@ -469,7 +486,7 @@
}
}
- /// Returns a list of supported types for this register class, each with a
+ /// Returns a list of supported types for this register class, each with an
/// options target feature required to use this type.
pub fn supported_types(
self,
@@ -484,6 +501,7 @@
Self::PowerPC(r) => r.supported_types(arch),
Self::Hexagon(r) => r.supported_types(arch),
Self::Mips(r) => r.supported_types(arch),
+ Self::S390x(r) => r.supported_types(arch),
Self::SpirV(r) => r.supported_types(arch),
Self::Wasm(r) => r.supported_types(arch),
Self::Bpf(r) => r.supported_types(arch),
@@ -509,6 +527,7 @@
InlineAsmArch::Mips | InlineAsmArch::Mips64 => {
Self::Mips(MipsInlineAsmRegClass::parse(arch, name)?)
}
+ InlineAsmArch::S390x => Self::S390x(S390xInlineAsmRegClass::parse(arch, name)?),
InlineAsmArch::SpirV => Self::SpirV(SpirVInlineAsmRegClass::parse(arch, name)?),
InlineAsmArch::Wasm32 => Self::Wasm(WasmInlineAsmRegClass::parse(arch, name)?),
InlineAsmArch::Bpf => Self::Bpf(BpfInlineAsmRegClass::parse(arch, name)?),
@@ -527,6 +546,7 @@
Self::PowerPC(r) => r.valid_modifiers(arch),
Self::Hexagon(r) => r.valid_modifiers(arch),
Self::Mips(r) => r.valid_modifiers(arch),
+ Self::S390x(r) => r.valid_modifiers(arch),
Self::SpirV(r) => r.valid_modifiers(arch),
Self::Wasm(r) => r.valid_modifiers(arch),
Self::Bpf(r) => r.valid_modifiers(arch),
@@ -695,6 +715,11 @@
mips::fill_reg_map(arch, has_feature, target, &mut map);
map
}
+ InlineAsmArch::S390x => {
+ let mut map = s390x::regclass_map();
+ s390x::fill_reg_map(arch, has_feature, target, &mut map);
+ map
+ }
InlineAsmArch::SpirV => {
let mut map = spirv::regclass_map();
spirv::fill_reg_map(arch, has_feature, target, &mut map);
@@ -712,3 +737,185 @@
}
}
}
+
+#[derive(
+ Copy,
+ Clone,
+ Encodable,
+ Decodable,
+ Debug,
+ Eq,
+ PartialEq,
+ PartialOrd,
+ Hash,
+ HashStable_Generic
+)]
+pub enum InlineAsmClobberAbi {
+ X86,
+ X86_64Win,
+ X86_64SysV,
+ Arm,
+ AArch64,
+ RiscV,
+}
+
+impl InlineAsmClobberAbi {
+ /// Parses a clobber ABI for the given target, or returns a list of supported
+ /// clobber ABIs for the target.
+ pub fn parse(
+ arch: InlineAsmArch,
+ target: &Target,
+ name: Symbol,
+ ) -> Result<Self, &'static [&'static str]> {
+ let name = &*name.as_str();
+ match arch {
+ InlineAsmArch::X86 => match name {
+ "C" | "system" | "efiapi" | "cdecl" | "stdcall" | "fastcall" => {
+ Ok(InlineAsmClobberAbi::X86)
+ }
+ _ => Err(&["C", "system", "efiapi", "cdecl", "stdcall", "fastcall"]),
+ },
+ InlineAsmArch::X86_64 => match name {
+ "C" | "system" if !target.is_like_windows => Ok(InlineAsmClobberAbi::X86_64SysV),
+ "C" | "system" if target.is_like_windows => Ok(InlineAsmClobberAbi::X86_64Win),
+ "win64" | "efiapi" => Ok(InlineAsmClobberAbi::X86_64Win),
+ "sysv64" => Ok(InlineAsmClobberAbi::X86_64SysV),
+ _ => Err(&["C", "system", "efiapi", "win64", "sysv64"]),
+ },
+ InlineAsmArch::Arm => match name {
+ "C" | "system" | "efiapi" | "aapcs" => Ok(InlineAsmClobberAbi::Arm),
+ _ => Err(&["C", "system", "efiapi", "aapcs"]),
+ },
+ InlineAsmArch::AArch64 => match name {
+ "C" | "system" | "efiapi" => Ok(InlineAsmClobberAbi::AArch64),
+ _ => Err(&["C", "system", "efiapi"]),
+ },
+ InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => match name {
+ "C" | "system" | "efiapi" => Ok(InlineAsmClobberAbi::RiscV),
+ _ => Err(&["C", "system", "efiapi"]),
+ },
+ _ => Err(&[]),
+ }
+ }
+
+ /// Returns the set of registers which are clobbered by this ABI.
+ pub fn clobbered_regs(self) -> &'static [InlineAsmReg] {
+ macro_rules! clobbered_regs {
+ ($arch:ident $arch_reg:ident {
+ $(
+ $reg:ident,
+ )*
+ }) => {
+ &[
+ $(InlineAsmReg::$arch($arch_reg::$reg),)*
+ ]
+ };
+ }
+ match self {
+ InlineAsmClobberAbi::X86 => clobbered_regs! {
+ X86 X86InlineAsmReg {
+ ax, cx, dx,
+
+ xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7,
+
+ k1, k2, k3, k4, k5, k6, k7,
+
+ mm0, mm1, mm2, mm3, mm4, mm5, mm6, mm7,
+ st0, st1, st2, st3, st4, st5, st6, st7,
+ }
+ },
+ InlineAsmClobberAbi::X86_64SysV => clobbered_regs! {
+ X86 X86InlineAsmReg {
+ ax, cx, dx, si, di, r8, r9, r10, r11,
+
+ xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7,
+ xmm8, xmm9, xmm10, xmm11, xmm12, xmm13, xmm14, xmm15,
+ zmm16, zmm17, zmm18, zmm19, zmm20, zmm21, zmm22, zmm23,
+ zmm24, zmm25, zmm26, zmm27, zmm28, zmm29, zmm30, zmm31,
+
+ k1, k2, k3, k4, k5, k6, k7,
+
+ mm0, mm1, mm2, mm3, mm4, mm5, mm6, mm7,
+ st0, st1, st2, st3, st4, st5, st6, st7,
+ }
+ },
+ InlineAsmClobberAbi::X86_64Win => clobbered_regs! {
+ X86 X86InlineAsmReg {
+ // rdi and rsi are callee-saved on windows
+ ax, cx, dx, r8, r9, r10, r11,
+
+ // xmm6-xmm15 are callee-saved on windows, but we need to
+ // mark them as clobbered anyways because the upper portions
+ // of ymm6-ymm15 are volatile.
+ xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7,
+ xmm8, xmm9, xmm10, xmm11, xmm12, xmm13, xmm14, xmm15,
+ zmm16, zmm17, zmm18, zmm19, zmm20, zmm21, zmm22, zmm23,
+ zmm24, zmm25, zmm26, zmm27, zmm28, zmm29, zmm30, zmm31,
+
+ k1, k2, k3, k4, k5, k6, k7,
+
+ mm0, mm1, mm2, mm3, mm4, mm5, mm6, mm7,
+ st0, st1, st2, st3, st4, st5, st6, st7,
+ }
+ },
+ InlineAsmClobberAbi::AArch64 => clobbered_regs! {
+ AArch64 AArch64InlineAsmReg {
+ x0, x1, x2, x3, x4, x5, x6, x7,
+ x8, x9, x10, x11, x12, x13, x14, x15,
+ // x18 is platform-reserved or temporary, but we exclude it
+ // here since it is a reserved register.
+ x16, x17, x30,
+
+ // Technically the low 64 bits of v8-v15 are preserved, but
+ // we have no way of expressing this using clobbers.
+ v0, v1, v2, v3, v4, v5, v6, v7,
+ v8, v9, v10, v11, v12, v13, v14, v15,
+ v16, v17, v18, v19, v20, v21, v22, v23,
+ v24, v25, v26, v27, v28, v29, v30, v31,
+
+ p0, p1, p2, p3, p4, p5, p6, p7,
+ p8, p9, p10, p11, p12, p13, p14, p15,
+ ffr,
+
+ }
+ },
+ InlineAsmClobberAbi::Arm => clobbered_regs! {
+ Arm ArmInlineAsmReg {
+ // r9 is platform-reserved and is treated as callee-saved.
+ r0, r1, r2, r3, r12, r14,
+
+ // The finest-grained register variant is used here so that
+ // partial uses of larger registers are properly handled.
+ s0, s1, s2, s3, s4, s5, s6, s7,
+ s8, s9, s10, s11, s12, s13, s14, s15,
+ // s16-s31 are callee-saved
+ d16, d17, d18, d19, d20, d21, d22, d23,
+ d24, d25, d26, d27, d28, d29, d30, d31,
+ }
+ },
+ InlineAsmClobberAbi::RiscV => clobbered_regs! {
+ RiscV RiscVInlineAsmReg {
+ // ra
+ x1,
+ // t0-t2
+ x5, x6, x7,
+ // a0-a7
+ x10, x11, x12, x13, x14, x15, x16, x17,
+ // t3-t6
+ x28, x29, x30, x31,
+ // ft0-ft7
+ f0, f1, f2, f3, f4, f5, f6, f7,
+ // fa0-fa7
+ f10, f11, f12, f13, f14, f15, f16, f17,
+ // ft8-ft11
+ f28, f29, f30, f31,
+
+ v0, v1, v2, v3, v4, v5, v6, v7,
+ v8, v9, v10, v11, v12, v13, v14, v15,
+ v16, v17, v18, v19, v20, v21, v22, v23,
+ v24, v25, v26, v27, v28, v29, v30, v31,
+ }
+ },
+ }
+ }
+}
diff --git a/compiler/rustc_target/src/asm/powerpc.rs b/compiler/rustc_target/src/asm/powerpc.rs
index 42fc25c..51a4303 100644
--- a/compiler/rustc_target/src/asm/powerpc.rs
+++ b/compiler/rustc_target/src/asm/powerpc.rs
@@ -7,6 +7,8 @@
reg,
reg_nonzero,
freg,
+ cr,
+ xer,
}
}
@@ -44,6 +46,7 @@
}
}
Self::freg => types! { _: F32, F64; },
+ Self::cr | Self::xer => &[],
}
}
}
@@ -108,6 +111,16 @@
f29: freg = ["f29", "fr29"],
f30: freg = ["f30", "fr30"],
f31: freg = ["f31", "fr31"],
+ cr: cr = ["cr"],
+ cr0: cr = ["cr0"],
+ cr1: cr = ["cr1"],
+ cr2: cr = ["cr2"],
+ cr3: cr = ["cr3"],
+ cr4: cr = ["cr4"],
+ cr5: cr = ["cr5"],
+ cr6: cr = ["cr6"],
+ cr7: cr = ["cr7"],
+ xer: xer = ["xer"],
#error = ["r1", "1", "sp"] =>
"the stack pointer cannot be used as an operand for inline asm",
#error = ["r2", "2"] =>
@@ -136,17 +149,55 @@
_arch: InlineAsmArch,
_modifier: Option<char>,
) -> fmt::Result {
+ macro_rules! do_emit {
+ (
+ $($(($reg:ident, $value:literal)),*;)*
+ ) => {
+ out.write_str(match self {
+ $($(Self::$reg => $value,)*)*
+ })
+ };
+ }
// Strip off the leading prefix.
- if self as u32 <= Self::r28 as u32 {
- let index = self as u32 - Self::r28 as u32;
- write!(out, "{}", index)
- } else if self as u32 >= Self::f0 as u32 && self as u32 <= Self::f31 as u32 {
- let index = self as u32 - Self::f31 as u32;
- write!(out, "{}", index)
- } else {
- unreachable!()
+ do_emit! {
+ (r0, "0"), (r3, "3"), (r4, "4"), (r5, "5"), (r6, "6"), (r7, "7");
+ (r8, "8"), (r9, "9"), (r10, "10"), (r11, "11"), (r12, "12"), (r14, "14"), (r15, "15");
+ (r16, "16"), (r17, "17"), (r18, "18"), (r19, "19"), (r20, "20"), (r21, "21"), (r22, "22"), (r23, "23");
+ (r24, "24"), (r25, "25"), (r26, "26"), (r27, "27"), (r28, "28");
+ (f0, "0"), (f1, "1"), (f2, "2"), (f3, "3"), (f4, "4"), (f5, "5"), (f6, "6"), (f7, "7");
+ (f8, "8"), (f9, "9"), (f10, "10"), (f11, "11"), (f12, "12"), (f13, "13"), (f14, "14"), (f15, "15");
+ (f16, "16"), (f17, "17"), (f18, "18"), (f19, "19"), (f20, "20"), (f21, "21"), (f22, "22"), (f23, "23");
+ (f24, "24"), (f25, "25"), (f26, "26"), (f27, "27"), (f28, "28"), (f29, "29"), (f30, "30"), (f31, "31");
+ (cr, "cr");
+ (cr0, "0"), (cr1, "1"), (cr2, "2"), (cr3, "3"), (cr4, "4"), (cr5, "5"), (cr6, "6"), (cr7, "7");
+ (xer, "xer");
}
}
- pub fn overlapping_regs(self, mut _cb: impl FnMut(PowerPCInlineAsmReg)) {}
+ pub fn overlapping_regs(self, mut cb: impl FnMut(PowerPCInlineAsmReg)) {
+ macro_rules! reg_conflicts {
+ (
+ $(
+ $full:ident : $($field:ident)*
+ ),*;
+ ) => {
+ match self {
+ $(
+ Self::$full => {
+ cb(Self::$full);
+ $(cb(Self::$field);)*
+ }
+ $(Self::$field)|* => {
+ cb(Self::$full);
+ cb(self);
+ }
+ )*
+ r => cb(r),
+ }
+ };
+ }
+ reg_conflicts! {
+ cr : cr0 cr1 cr2 cr3 cr4 cr5 cr6 cr7;
+ }
+ }
}
diff --git a/compiler/rustc_target/src/asm/s390x.rs b/compiler/rustc_target/src/asm/s390x.rs
new file mode 100644
index 0000000..a74873f
--- /dev/null
+++ b/compiler/rustc_target/src/asm/s390x.rs
@@ -0,0 +1,106 @@
+use super::{InlineAsmArch, InlineAsmType};
+use rustc_macros::HashStable_Generic;
+use std::fmt;
+
+def_reg_class! {
+ S390x S390xInlineAsmRegClass {
+ reg,
+ freg,
+ }
+}
+
+impl S390xInlineAsmRegClass {
+ pub fn valid_modifiers(self, _arch: super::InlineAsmArch) -> &'static [char] {
+ &[]
+ }
+
+ pub fn suggest_class(self, _arch: InlineAsmArch, _ty: InlineAsmType) -> Option<Self> {
+ None
+ }
+
+ pub fn suggest_modifier(
+ self,
+ _arch: InlineAsmArch,
+ _ty: InlineAsmType,
+ ) -> Option<(char, &'static str)> {
+ None
+ }
+
+ pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<(char, &'static str)> {
+ None
+ }
+
+ pub fn supported_types(
+ self,
+ arch: InlineAsmArch,
+ ) -> &'static [(InlineAsmType, Option<&'static str>)] {
+ match (self, arch) {
+ (Self::reg, _) => types! { _: I8, I16, I32, I64; },
+ (Self::freg, _) => types! { _: F32, F64; },
+ }
+ }
+}
+
+def_regs! {
+ S390x S390xInlineAsmReg S390xInlineAsmRegClass {
+ r0: reg = ["r0"],
+ r1: reg = ["r1"],
+ r2: reg = ["r2"],
+ r3: reg = ["r3"],
+ r4: reg = ["r4"],
+ r5: reg = ["r5"],
+ r6: reg = ["r6"],
+ r7: reg = ["r7"],
+ r8: reg = ["r8"],
+ r9: reg = ["r9"],
+ r10: reg = ["r10"],
+ r12: reg = ["r12"],
+ r13: reg = ["r13"],
+ r14: reg = ["r14"],
+ f0: freg = ["f0"],
+ f1: freg = ["f1"],
+ f2: freg = ["f2"],
+ f3: freg = ["f3"],
+ f4: freg = ["f4"],
+ f5: freg = ["f5"],
+ f6: freg = ["f6"],
+ f7: freg = ["f7"],
+ f8: freg = ["f8"],
+ f9: freg = ["f9"],
+ f10: freg = ["f10"],
+ f11: freg = ["f11"],
+ f12: freg = ["f12"],
+ f13: freg = ["f13"],
+ f14: freg = ["f14"],
+ f15: freg = ["f15"],
+ #error = ["r11"] =>
+ "The frame pointer cannot be used as an operand for inline asm",
+ #error = ["r15"] =>
+ "The stack pointer cannot be used as an operand for inline asm",
+ #error = [
+ "c0", "c1", "c2", "c3",
+ "c4", "c5", "c6", "c7",
+ "c8", "c9", "c10", "c11",
+ "c12", "c13", "c14", "c15"
+ ] =>
+ "control registers are reserved by the kernel and cannot be used as operands for inline asm",
+ #error = [
+ "a0", "a1", "a2", "a3",
+ "a4", "a5", "a6", "a7",
+ "a8", "a9", "a10", "a11",
+ "a12", "a13", "a14", "a15"
+ ] =>
+ "access registers are not supported and cannot be used as operands for inline asm",
+ }
+}
+
+impl S390xInlineAsmReg {
+ pub fn emit(
+ self,
+ out: &mut dyn fmt::Write,
+ _arch: InlineAsmArch,
+ _modifier: Option<char>,
+ ) -> fmt::Result {
+ write!(out, "%{}", self.name())
+ }
+}
diff --git a/compiler/rustc_target/src/lib.rs b/compiler/rustc_target/src/lib.rs
index d39e5a5..e75c525 100644
--- a/compiler/rustc_target/src/lib.rs
+++ b/compiler/rustc_target/src/lib.rs
@@ -14,6 +14,8 @@
#![feature(associated_type_bounds)]
#![feature(exhaustive_patterns)]
#![feature(min_specialization)]
+#![feature(step_trait)]
+#![feature(unchecked_math)]
use std::path::{Path, PathBuf};
diff --git a/compiler/rustc_target/src/spec/aarch64_apple_ios.rs b/compiler/rustc_target/src/spec/aarch64_apple_ios.rs
index e5805d9..6468419 100644
--- a/compiler/rustc_target/src/spec/aarch64_apple_ios.rs
+++ b/compiler/rustc_target/src/spec/aarch64_apple_ios.rs
@@ -2,8 +2,15 @@
use crate::spec::{FramePointer, Target, TargetOptions};
pub fn target() -> Target {
+ // Clang automatically chooses a more specific target based on
+ // IPHONEOS_DEPLOYMENT_TARGET.
+ // This is required for the target to pick the right
+ // MACH-O commands, so we do too.
+ let arch = "arm64";
+ let llvm_target = super::apple_base::ios_llvm_target(arch);
+
Target {
- llvm_target: "arm64-apple-ios".to_string(),
+ llvm_target,
pointer_width: 64,
data_layout: "e-m:o-i64:64-i128:128-n32:64-S128".to_string(),
arch: "aarch64".to_string(),
diff --git a/compiler/rustc_target/src/spec/aarch64_unknown_freebsd.rs b/compiler/rustc_target/src/spec/aarch64_unknown_freebsd.rs
index 09ea7d3..0caecd2 100644
--- a/compiler/rustc_target/src/spec/aarch64_unknown_freebsd.rs
+++ b/compiler/rustc_target/src/spec/aarch64_unknown_freebsd.rs
@@ -1,4 +1,4 @@
-use crate::spec::{Target, TargetOptions};
+use crate::spec::{SanitizerSet, Target, TargetOptions};
pub fn target() -> Target {
Target {
@@ -6,6 +6,12 @@
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 { max_atomic_width: Some(128), ..super::freebsd_base::opts() },
+ options: TargetOptions {
+ max_atomic_width: Some(128),
+ supported_sanitizers: SanitizerSet::ADDRESS
+ | SanitizerSet::MEMORY
+ | SanitizerSet::THREAD,
+ ..super::freebsd_base::opts()
+ },
}
}
diff --git a/compiler/rustc_target/src/spec/aarch64_unknown_uefi.rs b/compiler/rustc_target/src/spec/aarch64_unknown_uefi.rs
new file mode 100644
index 0000000..20c528d
--- /dev/null
+++ b/compiler/rustc_target/src/spec/aarch64_unknown_uefi.rs
@@ -0,0 +1,27 @@
+// This defines the aarch64 target for UEFI systems as described in the UEFI specification. See the
+// uefi-base module for generic UEFI options.
+
+use super::uefi_msvc_base;
+use crate::spec::{LinkerFlavor, LldFlavor, Target};
+
+pub fn target() -> Target {
+ let mut base = uefi_msvc_base::opts();
+
+ base.max_atomic_width = Some(64);
+
+ let pre_link_args_msvc = vec!["/machine:arm64".to_string()];
+
+ base.pre_link_args.get_mut(&LinkerFlavor::Msvc).unwrap().extend(pre_link_args_msvc.clone());
+ base.pre_link_args
+ .get_mut(&LinkerFlavor::Lld(LldFlavor::Link))
+ .unwrap()
+ .extend(pre_link_args_msvc);
+
+ Target {
+ llvm_target: "aarch64-unknown-windows".to_string(),
+ pointer_width: 64,
+ data_layout: "e-m:w-p:64:64-i32:32-i64:64-i128:128-n32:64-S128".to_string(),
+ arch: "aarch64".to_string(),
+ options: base,
+ }
+}
diff --git a/compiler/rustc_target/src/spec/abi.rs b/compiler/rustc_target/src/spec/abi.rs
index ee36090..e3a2226 100644
--- a/compiler/rustc_target/src/spec/abi.rs
+++ b/compiler/rustc_target/src/spec/abi.rs
@@ -87,6 +87,9 @@
}
impl Abi {
+ /// Default ABI chosen for `extern fn` declarations without an explicit ABI.
+ pub const FALLBACK: Abi = Abi::C { unwind: false };
+
#[inline]
pub fn index(self) -> usize {
// N.B., this ordering MUST match the AbiDatas array above.
diff --git a/compiler/rustc_target/src/spec/apple_base.rs b/compiler/rustc_target/src/spec/apple_base.rs
index 0c8a892..a21b784 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::{FramePointer, SplitDebuginfo, TargetOptions};
+use crate::spec::{FramePointer, LldFlavor, 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
@@ -35,6 +35,7 @@
abi_return_struct_as_int: true,
emit_debug_gdb_scripts: false,
eh_frame_header: false,
+ lld_flavor: LldFlavor::Ld64,
// The historical default for macOS targets is to run `dsymutil` which
// generates a packed version of debuginfo split from the main file.
@@ -91,6 +92,17 @@
deployment_target("IPHONEOS_DEPLOYMENT_TARGET").unwrap_or((7, 0))
}
+pub fn ios_llvm_target(arch: &str) -> String {
+ // Modern iOS tooling extracts information about deployment target
+ // from LC_BUILD_VERSION. This load command will only be emitted when
+ // we build with a version specific `llvm_target`, with the version
+ // set high enough. Luckily one LC_BUILD_VERSION is enough, for Xcode
+ // to pick it up (since std and core are still built with the fallback
+ // of version 7.0 and hence emit the old LC_IPHONE_MIN_VERSION).
+ let (major, minor) = ios_deployment_target();
+ format!("{}-apple-ios{}.{}.0", arch, major, minor)
+}
+
pub fn ios_sim_llvm_target(arch: &str) -> String {
let (major, minor) = ios_deployment_target();
format!("{}-apple-ios{}.{}.0-simulator", arch, major, minor)
diff --git a/compiler/rustc_target/src/spec/armebv7r_none_eabi.rs b/compiler/rustc_target/src/spec/armebv7r_none_eabi.rs
index c98a12c..ed4779c 100644
--- a/compiler/rustc_target/src/spec/armebv7r_none_eabi.rs
+++ b/compiler/rustc_target/src/spec/armebv7r_none_eabi.rs
@@ -20,6 +20,8 @@
panic_strategy: PanicStrategy::Abort,
max_atomic_width: Some(32),
emit_debug_gdb_scripts: false,
+ // GCC and Clang default to 8 for arm-none here
+ c_enum_min_bits: 8,
..Default::default()
},
}
diff --git a/compiler/rustc_target/src/spec/armebv7r_none_eabihf.rs b/compiler/rustc_target/src/spec/armebv7r_none_eabihf.rs
index 2926354..b60e289 100644
--- a/compiler/rustc_target/src/spec/armebv7r_none_eabihf.rs
+++ b/compiler/rustc_target/src/spec/armebv7r_none_eabihf.rs
@@ -21,6 +21,8 @@
features: "+vfp3,-d32,-fp16".to_string(),
max_atomic_width: Some(32),
emit_debug_gdb_scripts: false,
+ // GCC and Clang default to 8 for arm-none here
+ c_enum_min_bits: 8,
..Default::default()
},
}
diff --git a/compiler/rustc_target/src/spec/armv7_apple_ios.rs b/compiler/rustc_target/src/spec/armv7_apple_ios.rs
index 2f22868..1f90c78 100644
--- a/compiler/rustc_target/src/spec/armv7_apple_ios.rs
+++ b/compiler/rustc_target/src/spec/armv7_apple_ios.rs
@@ -3,7 +3,7 @@
pub fn target() -> Target {
Target {
- llvm_target: "armv7-apple-ios".to_string(),
+ llvm_target: super::apple_base::ios_llvm_target("armv7"),
pointer_width: 32,
data_layout: "e-m:o-p:32:32-Fi8-f64:32:64-v64:32:64-v128:32:128-a:0:32-n32-S32".to_string(),
arch: "arm".to_string(),
diff --git a/compiler/rustc_target/src/spec/armv7a_none_eabi.rs b/compiler/rustc_target/src/spec/armv7a_none_eabi.rs
index 8bff60e..88040f4 100644
--- a/compiler/rustc_target/src/spec/armv7a_none_eabi.rs
+++ b/compiler/rustc_target/src/spec/armv7a_none_eabi.rs
@@ -28,6 +28,7 @@
max_atomic_width: Some(64),
panic_strategy: PanicStrategy::Abort,
emit_debug_gdb_scripts: false,
+ c_enum_min_bits: 8,
..Default::default()
};
Target {
diff --git a/compiler/rustc_target/src/spec/armv7a_none_eabihf.rs b/compiler/rustc_target/src/spec/armv7a_none_eabihf.rs
index ea2751e..af32484 100644
--- a/compiler/rustc_target/src/spec/armv7a_none_eabihf.rs
+++ b/compiler/rustc_target/src/spec/armv7a_none_eabihf.rs
@@ -19,6 +19,8 @@
max_atomic_width: Some(64),
panic_strategy: PanicStrategy::Abort,
emit_debug_gdb_scripts: false,
+ // GCC and Clang default to 8 for arm-none here
+ c_enum_min_bits: 8,
..Default::default()
};
Target {
diff --git a/compiler/rustc_target/src/spec/armv7r_none_eabi.rs b/compiler/rustc_target/src/spec/armv7r_none_eabi.rs
index c695542..c0e9709 100644
--- a/compiler/rustc_target/src/spec/armv7r_none_eabi.rs
+++ b/compiler/rustc_target/src/spec/armv7r_none_eabi.rs
@@ -19,6 +19,8 @@
panic_strategy: PanicStrategy::Abort,
max_atomic_width: Some(32),
emit_debug_gdb_scripts: false,
+ // GCC and Clang default to 8 for arm-none here
+ c_enum_min_bits: 8,
..Default::default()
},
}
diff --git a/compiler/rustc_target/src/spec/armv7r_none_eabihf.rs b/compiler/rustc_target/src/spec/armv7r_none_eabihf.rs
index 50c3702..b126887 100644
--- a/compiler/rustc_target/src/spec/armv7r_none_eabihf.rs
+++ b/compiler/rustc_target/src/spec/armv7r_none_eabihf.rs
@@ -20,6 +20,8 @@
features: "+vfp3,-d32,-fp16".to_string(),
max_atomic_width: Some(32),
emit_debug_gdb_scripts: false,
+ // GCC and Clang default to 8 for arm-none here
+ c_enum_min_bits: 8,
..Default::default()
},
}
diff --git a/compiler/rustc_target/src/spec/freebsd_base.rs b/compiler/rustc_target/src/spec/freebsd_base.rs
index 998d6ff..f2ec6aa 100644
--- a/compiler/rustc_target/src/spec/freebsd_base.rs
+++ b/compiler/rustc_target/src/spec/freebsd_base.rs
@@ -1,4 +1,4 @@
-use crate::spec::{FramePointer, RelroLevel, TargetOptions};
+use crate::spec::{RelroLevel, TargetOptions};
pub fn opts() -> TargetOptions {
TargetOptions {
@@ -8,7 +8,6 @@
families: vec!["unix".to_string()],
has_rpath: true,
position_independent_executables: true,
- frame_pointer: FramePointer::Always, // FIXME 43575: should be MayOmit...
relro_level: RelroLevel::Full,
abi_return_struct_as_int: true,
dwarf_version: Some(2),
diff --git a/compiler/rustc_target/src/spec/hexagon_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/hexagon_unknown_linux_musl.rs
index e0097ee..27d306c 100644
--- a/compiler/rustc_target/src/spec/hexagon_unknown_linux_musl.rs
+++ b/compiler/rustc_target/src/spec/hexagon_unknown_linux_musl.rs
@@ -13,6 +13,8 @@
base.dynamic_linking = true;
base.executables = true;
+ base.c_enum_min_bits = 8;
+
Target {
llvm_target: "hexagon-unknown-linux-musl".to_string(),
pointer_width: 32,
diff --git a/compiler/rustc_target/src/spec/i386_apple_ios.rs b/compiler/rustc_target/src/spec/i386_apple_ios.rs
index f5d7be4..4419dfe 100644
--- a/compiler/rustc_target/src/spec/i386_apple_ios.rs
+++ b/compiler/rustc_target/src/spec/i386_apple_ios.rs
@@ -4,7 +4,7 @@
pub fn target() -> Target {
let base = opts("ios", Arch::I386);
Target {
- llvm_target: "i386-apple-ios".to_string(),
+ llvm_target: super::apple_base::ios_sim_llvm_target("i386"),
pointer_width: 32,
data_layout: "e-m:o-p:32:32-p270:32:32-p271:32:32-p272:64:64-\
f64:32:64-f80:128-n8:16:32-S128"
diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs
index 0185132..27322136 100644
--- a/compiler/rustc_target/src/spec/mod.rs
+++ b/compiler/rustc_target/src/spec/mod.rs
@@ -664,7 +664,7 @@
self.into_iter()
.map(|v| Some(v.as_str()?.to_json()))
.collect::<Option<Vec<_>>>()
- .unwrap_or(Vec::new())
+ .unwrap_or_default()
.to_json()
}
}
@@ -802,6 +802,7 @@
("armv6-unknown-freebsd", armv6_unknown_freebsd),
("armv7-unknown-freebsd", armv7_unknown_freebsd),
("i686-unknown-freebsd", i686_unknown_freebsd),
+ ("powerpc-unknown-freebsd", powerpc_unknown_freebsd),
("powerpc64-unknown-freebsd", powerpc64_unknown_freebsd),
("powerpc64le-unknown-freebsd", powerpc64le_unknown_freebsd),
("x86_64-unknown-freebsd", x86_64_unknown_freebsd),
@@ -902,6 +903,7 @@
("riscv32i-unknown-none-elf", riscv32i_unknown_none_elf),
("riscv32imc-unknown-none-elf", riscv32imc_unknown_none_elf),
+ ("riscv32imc-esp-espidf", riscv32imc_esp_espidf),
("riscv32imac-unknown-none-elf", riscv32imac_unknown_none_elf),
("riscv32gc-unknown-linux-gnu", riscv32gc_unknown_linux_gnu),
("riscv32gc-unknown-linux-musl", riscv32gc_unknown_linux_musl),
@@ -917,6 +919,7 @@
("x86_64-unknown-uefi", x86_64_unknown_uefi),
("i686-unknown-uefi", i686_unknown_uefi),
+ ("aarch64-unknown-uefi", aarch64_unknown_uefi),
("nvptx64-nvidia-cuda", nvptx64_nvidia_cuda),
@@ -1333,6 +1336,9 @@
/// If present it's a default value to use for adjusting the C ABI.
pub default_adjusted_cabi: Option<Abi>,
+
+ /// Minimum number of bits in #[repr(C)] enum. Defaults to 32.
+ pub c_enum_min_bits: u64,
}
impl Default for TargetOptions {
@@ -1437,6 +1443,7 @@
split_debuginfo: SplitDebuginfo::Off,
supported_sanitizers: SanitizerSet::empty(),
default_adjusted_cabi: None,
+ c_enum_min_bits: 32,
}
}
}
@@ -1494,7 +1501,8 @@
| Cdecl
| EfiApi => true,
X86Interrupt => ["x86", "x86_64"].contains(&&self.arch[..]),
- Aapcs | CCmseNonSecureCall => ["arm", "aarch64"].contains(&&self.arch[..]),
+ Aapcs => "arm" == self.arch,
+ CCmseNonSecureCall => ["arm", "aarch64"].contains(&&self.arch[..]),
Win64 | SysV64 => self.arch == "x86_64",
PtxKernel => self.arch == "nvptx64",
Msp430Interrupt => self.arch == "msp430",
@@ -1601,6 +1609,12 @@
base.$key_name = s;
}
} );
+ ($key_name:ident, u64) => ( {
+ let name = (stringify!($key_name)).replace("_", "-");
+ if let Some(s) = obj.remove_key(&name).and_then(|j| Json::as_u64(&j)) {
+ base.$key_name = s;
+ }
+ } );
($key_name:ident, Option<u32>) => ( {
let name = (stringify!($key_name)).replace("_", "-");
if let Some(s) = obj.remove_key(&name).and_then(|j| Json::as_u64(&j)) {
@@ -2014,10 +2028,11 @@
key!(split_debuginfo, SplitDebuginfo)?;
key!(supported_sanitizers, SanitizerSet)?;
key!(default_adjusted_cabi, Option<Abi>)?;
+ key!(c_enum_min_bits, u64);
if base.is_builtin {
// This can cause unfortunate ICEs later down the line.
- return Err(format!("may not set is_builtin for targets not built-in"));
+ return Err("may not set is_builtin for targets not built-in".to_string());
}
// Each field should have been read using `Json::remove_key` so any keys remaining are unused.
let remaining_keys = obj.as_object().ok_or("Expected JSON object for target")?.keys();
@@ -2252,6 +2267,7 @@
target_option_val!(has_thumb_interworking);
target_option_val!(split_debuginfo);
target_option_val!(supported_sanitizers);
+ target_option_val!(c_enum_min_bits);
if let Some(abi) = self.default_adjusted_cabi {
d.insert("default-adjusted-cabi".to_string(), Abi::name(abi).to_json());
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 559a1a4..f10d4d4 100644
--- a/compiler/rustc_target/src/spec/powerpc64_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/powerpc64_unknown_linux_gnu.rs
@@ -14,7 +14,7 @@
Target {
llvm_target: "powerpc64-unknown-linux-gnu".to_string(),
pointer_width: 64,
- data_layout: "E-m:e-i64:64-n32:64-v256:256:256-v512:512:512".to_string(),
+ data_layout: "E-m:e-i64:64-n32:64-S128-v256:256:256-v512:512:512".to_string(),
arch: "powerpc64".to_string(),
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 f1190b1..6116217 100644
--- a/compiler/rustc_target/src/spec/powerpc64_unknown_linux_musl.rs
+++ b/compiler/rustc_target/src/spec/powerpc64_unknown_linux_musl.rs
@@ -10,7 +10,7 @@
Target {
llvm_target: "powerpc64-unknown-linux-musl".to_string(),
pointer_width: 64,
- data_layout: "E-m:e-i64:64-n32:64-v256:256:256-v512:512:512".to_string(),
+ data_layout: "E-m:e-i64:64-n32:64-S128-v256:256:256-v512:512:512".to_string(),
arch: "powerpc64".to_string(),
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 3ebc546..9c63997 100644
--- a/compiler/rustc_target/src/spec/powerpc64_wrs_vxworks.rs
+++ b/compiler/rustc_target/src/spec/powerpc64_wrs_vxworks.rs
@@ -10,7 +10,7 @@
Target {
llvm_target: "powerpc64-unknown-linux-gnu".to_string(),
pointer_width: 64,
- data_layout: "E-m:e-i64:64-n32:64-v256:256:256-v512:512:512".to_string(),
+ data_layout: "E-m:e-i64:64-n32:64-S128-v256:256:256-v512:512:512".to_string(),
arch: "powerpc64".to_string(),
options: TargetOptions { endian: Endian::Big, ..base },
}
diff --git a/compiler/rustc_target/src/spec/powerpc64le_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/powerpc64le_unknown_linux_gnu.rs
index 76f70e4..f645ece 100644
--- a/compiler/rustc_target/src/spec/powerpc64le_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/powerpc64le_unknown_linux_gnu.rs
@@ -9,7 +9,7 @@
Target {
llvm_target: "powerpc64le-unknown-linux-gnu".to_string(),
pointer_width: 64,
- data_layout: "e-m:e-i64:64-n32:64-v256:256:256-v512:512:512".to_string(),
+ data_layout: "e-m:e-i64:64-n32:64-S128-v256:256:256-v512:512:512".to_string(),
arch: "powerpc64".to_string(),
options: TargetOptions { mcount: "_mcount".to_string(), ..base },
}
diff --git a/compiler/rustc_target/src/spec/powerpc64le_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/powerpc64le_unknown_linux_musl.rs
index 42c4910..934371f 100644
--- a/compiler/rustc_target/src/spec/powerpc64le_unknown_linux_musl.rs
+++ b/compiler/rustc_target/src/spec/powerpc64le_unknown_linux_musl.rs
@@ -9,7 +9,7 @@
Target {
llvm_target: "powerpc64le-unknown-linux-musl".to_string(),
pointer_width: 64,
- data_layout: "e-m:e-i64:64-n32:64-v256:256:256-v512:512:512".to_string(),
+ data_layout: "e-m:e-i64:64-n32:64-S128-v256:256:256-v512:512:512".to_string(),
arch: "powerpc64".to_string(),
options: TargetOptions { mcount: "_mcount".to_string(), ..base },
}
diff --git a/compiler/rustc_target/src/spec/powerpc_unknown_freebsd.rs b/compiler/rustc_target/src/spec/powerpc_unknown_freebsd.rs
new file mode 100644
index 0000000..e113180
--- /dev/null
+++ b/compiler/rustc_target/src/spec/powerpc_unknown_freebsd.rs
@@ -0,0 +1,27 @@
+use crate::abi::Endian;
+use crate::spec::{LinkerFlavor, RelocModel, Target, TargetOptions};
+
+pub fn target() -> Target {
+ let mut base = super::freebsd_base::opts();
+ base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m32".to_string());
+ // Extra hint to linker that we are generating secure-PLT code.
+ base.pre_link_args
+ .entry(LinkerFlavor::Gcc)
+ .or_default()
+ .push("--target=powerpc-unknown-freebsd13.0".to_string());
+ base.max_atomic_width = Some(32);
+
+ Target {
+ llvm_target: "powerpc-unknown-freebsd13.0".to_string(),
+ pointer_width: 32,
+ data_layout: "E-m:e-p:32:32-i64:64-n32".to_string(),
+ arch: "powerpc".to_string(),
+ options: TargetOptions {
+ endian: Endian::Big,
+ features: "+secure-plt".to_string(),
+ relocation_model: RelocModel::Pic,
+ mcount: "_mcount".to_string(),
+ ..base
+ },
+ }
+}
diff --git a/compiler/rustc_target/src/spec/riscv32imc_esp_espidf.rs b/compiler/rustc_target/src/spec/riscv32imc_esp_espidf.rs
new file mode 100644
index 0000000..fb084af
--- /dev/null
+++ b/compiler/rustc_target/src/spec/riscv32imc_esp_espidf.rs
@@ -0,0 +1,37 @@
+use crate::spec::{LinkerFlavor, PanicStrategy, RelocModel};
+use crate::spec::{Target, TargetOptions};
+
+pub fn target() -> Target {
+ Target {
+ data_layout: "e-m:e-p:32:32-i64:64-n32-S128".to_string(),
+ llvm_target: "riscv32".to_string(),
+ pointer_width: 32,
+ arch: "riscv32".to_string(),
+
+ options: TargetOptions {
+ families: vec!["unix".to_string()],
+ os: "espidf".to_string(),
+ env: "newlib".to_string(),
+ vendor: "espressif".to_string(),
+ linker_flavor: LinkerFlavor::Gcc,
+ linker: Some("riscv32-esp-elf-gcc".to_string()),
+ cpu: "generic-rv32".to_string(),
+
+ // While the RiscV32IMC architecture does not natively support atomics, ESP-IDF does support
+ // the __atomic* and __sync* GCC builtins, so setting `max_atomic_width` to `Some(32)`
+ // and `atomic_cas` to `true` will cause the compiler to emit libcalls to these builtins.
+ //
+ // Support for atomics is necessary for the Rust STD library, which is supported by the ESP-IDF framework.
+ max_atomic_width: Some(32),
+ atomic_cas: true,
+
+ features: "+m,+c".to_string(),
+ executables: true,
+ panic_strategy: PanicStrategy::Abort,
+ relocation_model: RelocModel::Static,
+ emit_debug_gdb_scripts: false,
+ eh_frame_header: false,
+ ..Default::default()
+ },
+ }
+}
diff --git a/compiler/rustc_target/src/spec/thumb_base.rs b/compiler/rustc_target/src/spec/thumb_base.rs
index bac1203..e2e5285 100644
--- a/compiler/rustc_target/src/spec/thumb_base.rs
+++ b/compiler/rustc_target/src/spec/thumb_base.rs
@@ -53,6 +53,9 @@
// LLVM is eager to trash the link register when calling `noreturn` functions, which
// breaks debugging. Preserve LR by default to prevent that from happening.
frame_pointer: FramePointer::Always,
+ // ARM supports multiple ABIs for enums, the linux one matches the default of 32 here
+ // but any arm-none or thumb-none target will be defaulted to 8 on GCC and clang
+ c_enum_min_bits: 8,
..Default::default()
}
}
diff --git a/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs b/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs
index 3021393..86b1a75 100644
--- a/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs
+++ b/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs
@@ -43,7 +43,7 @@
Target {
llvm_target: "wasm32-unknown-emscripten".to_string(),
pointer_width: 32,
- data_layout: "e-m:e-p:32:32-i64:64-n32:64-S128".to_string(),
+ data_layout: "e-m:e-p:32:32-i64:64-f128:64-n32:64-S128-ni:1:10:20".to_string(),
arch: "wasm32".to_string(),
options: opts,
}
diff --git a/compiler/rustc_target/src/spec/wasm32_unknown_unknown.rs b/compiler/rustc_target/src/spec/wasm32_unknown_unknown.rs
index 834c4db..134c680 100644
--- a/compiler/rustc_target/src/spec/wasm32_unknown_unknown.rs
+++ b/compiler/rustc_target/src/spec/wasm32_unknown_unknown.rs
@@ -54,7 +54,7 @@
Target {
llvm_target: "wasm32-unknown-unknown".to_string(),
pointer_width: 32,
- data_layout: "e-m:e-p:32:32-i64:64-n32:64-S128".to_string(),
+ data_layout: "e-m:e-p:32:32-i64:64-n32:64-S128-ni:1:10:20".to_string(),
arch: "wasm32".to_string(),
options,
}
diff --git a/compiler/rustc_target/src/spec/wasm32_wasi.rs b/compiler/rustc_target/src/spec/wasm32_wasi.rs
index a6b12d2..2dab206 100644
--- a/compiler/rustc_target/src/spec/wasm32_wasi.rs
+++ b/compiler/rustc_target/src/spec/wasm32_wasi.rs
@@ -109,7 +109,7 @@
Target {
llvm_target: "wasm32-wasi".to_string(),
pointer_width: 32,
- data_layout: "e-m:e-p:32:32-i64:64-n32:64-S128".to_string(),
+ data_layout: "e-m:e-p:32:32-i64:64-n32:64-S128-ni:1:10:20".to_string(),
arch: "wasm32".to_string(),
options,
}
diff --git a/compiler/rustc_target/src/spec/wasm64_unknown_unknown.rs b/compiler/rustc_target/src/spec/wasm64_unknown_unknown.rs
index 8bfb229..fb6526c 100644
--- a/compiler/rustc_target/src/spec/wasm64_unknown_unknown.rs
+++ b/compiler/rustc_target/src/spec/wasm64_unknown_unknown.rs
@@ -32,7 +32,7 @@
Target {
llvm_target: "wasm64-unknown-unknown".to_string(),
pointer_width: 64,
- data_layout: "e-m:e-p:64:64-i64:64-n32:64-S128".to_string(),
+ data_layout: "e-m:e-p:64:64-i64:64-n32:64-S128-ni:1:10:20".to_string(),
arch: "wasm64".to_string(),
options,
}
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 adb8771..6e20bd2 100644
--- a/compiler/rustc_target/src/spec/x86_64_apple_ios.rs
+++ b/compiler/rustc_target/src/spec/x86_64_apple_ios.rs
@@ -4,7 +4,7 @@
pub fn target() -> Target {
let base = opts("ios", Arch::X86_64);
Target {
- llvm_target: "x86_64-apple-ios".to_string(),
+ llvm_target: super::apple_base::ios_sim_llvm_target("x86_64"),
pointer_width: 64,
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(),
diff --git a/compiler/rustc_target/src/spec/x86_64_pc_solaris.rs b/compiler/rustc_target/src/spec/x86_64_pc_solaris.rs
index b78e43d..34b6d29 100644
--- a/compiler/rustc_target/src/spec/x86_64_pc_solaris.rs
+++ b/compiler/rustc_target/src/spec/x86_64_pc_solaris.rs
@@ -1,4 +1,4 @@
-use crate::spec::{LinkerFlavor, StackProbeType, Target};
+use crate::spec::{LinkerFlavor, SanitizerSet, StackProbeType, Target};
pub fn target() -> Target {
let mut base = super::solaris_base::opts();
@@ -8,6 +8,7 @@
base.max_atomic_width = Some(64);
// don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
base.stack_probes = StackProbeType::Call;
+ base.supported_sanitizers = SanitizerSet::ADDRESS;
Target {
llvm_target: "x86_64-pc-solaris".to_string(),
diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_illumos.rs b/compiler/rustc_target/src/spec/x86_64_unknown_illumos.rs
index d3f9349..ec196a7 100644
--- a/compiler/rustc_target/src/spec/x86_64_unknown_illumos.rs
+++ b/compiler/rustc_target/src/spec/x86_64_unknown_illumos.rs
@@ -1,10 +1,11 @@
-use crate::spec::{LinkerFlavor, Target};
+use crate::spec::{LinkerFlavor, SanitizerSet, Target};
pub fn target() -> Target {
let mut base = super::illumos_base::opts();
base.pre_link_args.insert(LinkerFlavor::Gcc, vec!["-m64".to_string(), "-std=c99".to_string()]);
base.cpu = "x86-64".to_string();
base.max_atomic_width = Some(64);
+ base.supported_sanitizers = SanitizerSet::ADDRESS;
Target {
// LLVM does not currently have a separate illumos 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 0269c7a..9ba8628 100644
--- a/compiler/rustc_target/src/spec/x86_64_unknown_netbsd.rs
+++ b/compiler/rustc_target/src/spec/x86_64_unknown_netbsd.rs
@@ -1,4 +1,4 @@
-use crate::spec::{LinkerFlavor, StackProbeType, Target, TargetOptions};
+use crate::spec::{LinkerFlavor, SanitizerSet, StackProbeType, Target, TargetOptions};
pub fn target() -> Target {
let mut base = super::netbsd_base::opts();
@@ -7,6 +7,8 @@
base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m64".to_string());
// don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
base.stack_probes = StackProbeType::Call;
+ base.supported_sanitizers =
+ SanitizerSet::ADDRESS | SanitizerSet::LEAK | SanitizerSet::MEMORY | SanitizerSet::THREAD;
Target {
llvm_target: "x86_64-unknown-netbsd".to_string(),
diff --git a/compiler/rustc_trait_selection/Cargo.toml b/compiler/rustc_trait_selection/Cargo.toml
index c5d4c24..e2c626d 100644
--- a/compiler/rustc_trait_selection/Cargo.toml
+++ b/compiler/rustc_trait_selection/Cargo.toml
@@ -1,5 +1,4 @@
[package]
-authors = ["The Rust Project Developers"]
name = "rustc_trait_selection"
version = "0.0.0"
edition = "2018"
diff --git a/compiler/rustc_trait_selection/src/infer.rs b/compiler/rustc_trait_selection/src/infer.rs
index ea07419..c906493 100644
--- a/compiler/rustc_trait_selection/src/infer.rs
+++ b/compiler/rustc_trait_selection/src/infer.rs
@@ -44,6 +44,10 @@
/// - the self type
/// - the *other* type parameters of the trait, excluding the self-type
/// - the parameter environment
+ ///
+ /// Invokes `evaluate_obligation`, so in the event that evaluating
+ /// `Ty: Trait` causes overflow, EvaluatedToRecur (or EvaluatedToUnknown)
+ /// will be returned.
fn type_implements_trait(
&self,
trait_def_id: DefId,
@@ -117,7 +121,7 @@
recursion_depth: 0,
predicate: trait_ref.without_const().to_predicate(self.tcx),
};
- self.evaluate_obligation_no_overflow(&obligation)
+ self.evaluate_obligation(&obligation).unwrap_or(traits::EvaluationResult::EvaluatedToErr)
}
}
diff --git a/compiler/rustc_trait_selection/src/lib.rs b/compiler/rustc_trait_selection/src/lib.rs
index e932b1b..017a7c4 100644
--- a/compiler/rustc_trait_selection/src/lib.rs
+++ b/compiler/rustc_trait_selection/src/lib.rs
@@ -31,6 +31,8 @@
extern crate tracing;
#[macro_use]
extern crate rustc_middle;
+#[macro_use]
+extern crate smallvec;
pub mod autoderef;
pub mod infer;
diff --git a/compiler/rustc_trait_selection/src/opaque_types.rs b/compiler/rustc_trait_selection/src/opaque_types.rs
index 95c81c5..b743c80 100644
--- a/compiler/rustc_trait_selection/src/opaque_types.rs
+++ b/compiler/rustc_trait_selection/src/opaque_types.rs
@@ -2,11 +2,11 @@
use crate::traits::{self, ObligationCause, PredicateObligation};
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::sync::Lrc;
-use rustc_data_structures::vec_map::VecMap;
use rustc_hir as hir;
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_infer::infer::error_reporting::unexpected_hidden_region_diagnostic;
use rustc_infer::infer::free_regions::FreeRegionRelations;
+use rustc_infer::infer::opaque_types::OpaqueTypeDecl;
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_infer::infer::{self, InferCtxt, InferOk};
use rustc_middle::ty::fold::{BottomUpFolder, TypeFoldable, TypeFolder, TypeVisitor};
@@ -16,72 +16,6 @@
use std::ops::ControlFlow;
-pub type OpaqueTypeMap<'tcx> = VecMap<OpaqueTypeKey<'tcx>, OpaqueTypeDecl<'tcx>>;
-
-/// Information about the opaque types whose values we
-/// are inferring in this function (these are the `impl Trait` that
-/// appear in the return type).
-#[derive(Copy, Clone, Debug)]
-pub struct OpaqueTypeDecl<'tcx> {
- /// The opaque type (`ty::Opaque`) for this declaration.
- pub opaque_type: Ty<'tcx>,
-
- /// The span of this particular definition of the opaque type. So
- /// for example:
- ///
- /// ```ignore (incomplete snippet)
- /// type Foo = impl Baz;
- /// fn bar() -> Foo {
- /// // ^^^ This is the span we are looking for!
- /// }
- /// ```
- ///
- /// In cases where the fn returns `(impl Trait, impl Trait)` or
- /// other such combinations, the result is currently
- /// over-approximated, but better than nothing.
- pub definition_span: Span,
-
- /// The type variable that represents the value of the opaque type
- /// that we require. In other words, after we compile this function,
- /// we will be created a constraint like:
- ///
- /// Foo<'a, T> = ?C
- ///
- /// where `?C` is the value of this type variable. =) It may
- /// naturally refer to the type and lifetime parameters in scope
- /// in this function, though ultimately it should only reference
- /// those that are arguments to `Foo` in the constraint above. (In
- /// other words, `?C` should not include `'b`, even though it's a
- /// lifetime parameter on `foo`.)
- pub concrete_ty: Ty<'tcx>,
-
- /// Returns `true` if the `impl Trait` bounds include region bounds.
- /// For example, this would be true for:
- ///
- /// fn foo<'a, 'b, 'c>() -> impl Trait<'c> + 'a + 'b
- ///
- /// but false for:
- ///
- /// fn foo<'c>() -> impl Trait<'c>
- ///
- /// unless `Trait` was declared like:
- ///
- /// trait Trait<'c>: 'c
- ///
- /// in which case it would be true.
- ///
- /// This is used during regionck to decide whether we need to
- /// impose any additional constraints to ensure that region
- /// variables in `concrete_ty` wind up being constrained to
- /// something from `substs` (or, at minimum, things that outlive
- /// the fn body). (Ultimately, writeback is responsible for this
- /// check.)
- pub has_required_region_bounds: bool,
-
- /// The origin of the opaque type.
- pub origin: hir::OpaqueTyOrigin,
-}
-
/// Whether member constraints should be generated for all opaque types
#[derive(Debug)]
pub enum GenerateMemberConstraints {
@@ -98,18 +32,13 @@
pub trait InferCtxtExt<'tcx> {
fn instantiate_opaque_types<T: TypeFoldable<'tcx>>(
&self,
- parent_def_id: LocalDefId,
body_id: hir::HirId,
param_env: ty::ParamEnv<'tcx>,
value: T,
value_span: Span,
- ) -> InferOk<'tcx, (T, OpaqueTypeMap<'tcx>)>;
+ ) -> InferOk<'tcx, T>;
- fn constrain_opaque_types<FRR: FreeRegionRelations<'tcx>>(
- &self,
- opaque_types: &OpaqueTypeMap<'tcx>,
- free_region_relations: &FRR,
- );
+ fn constrain_opaque_types<FRR: FreeRegionRelations<'tcx>>(&self, free_region_relations: &FRR);
fn constrain_opaque_type<FRR: FreeRegionRelations<'tcx>>(
&self,
@@ -148,7 +77,7 @@
/// ?0: Iterator<Item = ?1>
/// ?1: Debug
///
- /// Moreover, it returns a `OpaqueTypeMap` that would map `?0` to
+ /// Moreover, it returns an `OpaqueTypeMap` that would map `?0` to
/// info about the `impl Iterator<..>` type and `?1` to info about
/// the `impl Debug` type.
///
@@ -164,28 +93,20 @@
/// - `value_span` -- the span where the value came from, used in error reporting
fn instantiate_opaque_types<T: TypeFoldable<'tcx>>(
&self,
- parent_def_id: LocalDefId,
body_id: hir::HirId,
param_env: ty::ParamEnv<'tcx>,
value: T,
value_span: Span,
- ) -> InferOk<'tcx, (T, OpaqueTypeMap<'tcx>)> {
+ ) -> InferOk<'tcx, T> {
debug!(
- "instantiate_opaque_types(value={:?}, parent_def_id={:?}, body_id={:?}, \
+ "instantiate_opaque_types(value={:?}, body_id={:?}, \
param_env={:?}, value_span={:?})",
- value, parent_def_id, body_id, param_env, value_span,
+ value, body_id, param_env, value_span,
);
- let mut instantiator = Instantiator {
- infcx: self,
- parent_def_id,
- body_id,
- param_env,
- value_span,
- opaque_types: Default::default(),
- obligations: vec![],
- };
+ let mut instantiator =
+ Instantiator { infcx: self, body_id, param_env, value_span, obligations: vec![] };
let value = instantiator.instantiate_opaque_types_in_map(value);
- InferOk { value: (value, instantiator.opaque_types), obligations: instantiator.obligations }
+ InferOk { value, obligations: instantiator.obligations }
}
/// Given the map `opaque_types` containing the opaque
@@ -350,12 +271,9 @@
/// - `opaque_types` -- the map produced by `instantiate_opaque_types`
/// - `free_region_relations` -- something that can be used to relate
/// the free regions (`'a`) that appear in the impl trait.
- fn constrain_opaque_types<FRR: FreeRegionRelations<'tcx>>(
- &self,
- opaque_types: &OpaqueTypeMap<'tcx>,
- free_region_relations: &FRR,
- ) {
- for &(opaque_type_key, opaque_defn) in opaque_types {
+ fn constrain_opaque_types<FRR: FreeRegionRelations<'tcx>>(&self, free_region_relations: &FRR) {
+ let opaque_types = self.inner.borrow().opaque_types.clone();
+ for (opaque_type_key, opaque_defn) in opaque_types {
self.constrain_opaque_type(
opaque_type_key,
&opaque_defn,
@@ -403,21 +321,38 @@
let span = tcx.def_span(def_id);
- // If there are required region bounds, we can use them.
- if opaque_defn.has_required_region_bounds {
- let bounds = tcx.explicit_item_bounds(def_id);
- debug!("{:#?}", bounds);
- let bounds: Vec<_> =
- bounds.iter().map(|(bound, _)| bound.subst(tcx, opaque_type_key.substs)).collect();
- debug!("{:#?}", bounds);
- let opaque_type = tcx.mk_opaque(def_id, opaque_type_key.substs);
+ // Check if the `impl Trait` bounds include region bounds.
+ // For example, this would be true for:
+ //
+ // fn foo<'a, 'b, 'c>() -> impl Trait<'c> + 'a + 'b
+ //
+ // but false for:
+ //
+ // fn foo<'c>() -> impl Trait<'c>
+ //
+ // unless `Trait` was declared like:
+ //
+ // trait Trait<'c>: 'c
+ //
+ // in which case it would be true.
+ //
+ // This is used during regionck to decide whether we need to
+ // impose any additional constraints to ensure that region
+ // variables in `concrete_ty` wind up being constrained to
+ // something from `substs` (or, at minimum, things that outlive
+ // the fn body). (Ultimately, writeback is responsible for this
+ // check.)
+ let bounds = tcx.explicit_item_bounds(def_id);
+ debug!("{:#?}", bounds);
+ let bounds = bounds.iter().map(|(bound, _)| bound.subst(tcx, opaque_type_key.substs));
+ debug!("{:#?}", bounds);
+ let opaque_type = tcx.mk_opaque(def_id, opaque_type_key.substs);
- let required_region_bounds =
- required_region_bounds(tcx, opaque_type, bounds.into_iter());
- debug_assert!(!required_region_bounds.is_empty());
-
+ let required_region_bounds = required_region_bounds(tcx, opaque_type, bounds);
+ if !required_region_bounds.is_empty() {
for required_region in required_region_bounds {
concrete_ty.visit_with(&mut ConstrainOpaqueTypeRegionVisitor {
+ tcx,
op: |r| self.sub_regions(infer::CallReturn(span), required_region, r),
});
}
@@ -493,6 +428,7 @@
}
}
concrete_ty.visit_with(&mut ConstrainOpaqueTypeRegionVisitor {
+ tcx,
op: |r| self.sub_regions(infer::CallReturn(span), least_region, r),
});
}
@@ -527,6 +463,7 @@
);
concrete_ty.visit_with(&mut ConstrainOpaqueTypeRegionVisitor {
+ tcx: self.tcx,
op: |r| {
self.member_constraint(
opaque_type_key.def_id,
@@ -612,14 +549,19 @@
//
// We ignore any type parameters because impl trait values are assumed to
// capture all the in-scope type parameters.
-struct ConstrainOpaqueTypeRegionVisitor<OP> {
+struct ConstrainOpaqueTypeRegionVisitor<'tcx, OP> {
+ tcx: TyCtxt<'tcx>,
op: OP,
}
-impl<'tcx, OP> TypeVisitor<'tcx> for ConstrainOpaqueTypeRegionVisitor<OP>
+impl<'tcx, OP> TypeVisitor<'tcx> for ConstrainOpaqueTypeRegionVisitor<'tcx, OP>
where
OP: FnMut(ty::Region<'tcx>),
{
+ fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
+ Some(self.tcx)
+ }
+
fn visit_binder<T: TypeFoldable<'tcx>>(
&mut self,
t: &ty::Binder<'tcx, T>,
@@ -641,7 +583,7 @@
fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
// We're only interested in types involving regions
- if !ty.flags().intersects(ty::TypeFlags::HAS_FREE_REGIONS) {
+ if !ty.flags().intersects(ty::TypeFlags::HAS_POTENTIAL_FREE_REGIONS) {
return ControlFlow::CONTINUE;
}
@@ -914,11 +856,9 @@
struct Instantiator<'a, 'tcx> {
infcx: &'a InferCtxt<'a, 'tcx>,
- parent_def_id: LocalDefId,
body_id: hir::HirId,
param_env: ty::ParamEnv<'tcx>,
value_span: Span,
- opaque_types: OpaqueTypeMap<'tcx>,
obligations: Vec<PredicateObligation<'tcx>>,
}
@@ -954,7 +894,7 @@
// }
// ```
//
- // Here, the return type of `foo` references a
+ // Here, the return type of `foo` references an
// `Opaque` indeed, but not one whose value is
// presently being inferred. You can get into a
// similar situation with closure return types
@@ -968,7 +908,7 @@
// ```
if let Some(def_id) = def_id.as_local() {
let opaque_hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
- let parent_def_id = self.parent_def_id;
+ let parent_def_id = self.infcx.defining_use_anchor;
let def_scope_default = || {
let opaque_parent_hir_id = tcx.hir().get_parent_item(opaque_hir_id);
parent_def_id == tcx.hir().local_def_id(opaque_parent_hir_id)
@@ -980,14 +920,14 @@
impl_trait_fn: Some(parent),
origin,
..
- }) => (parent == self.parent_def_id.to_def_id(), origin),
+ }) => (parent == parent_def_id.to_def_id(), origin),
// Named `type Foo = impl Bar;`
hir::ItemKind::OpaqueTy(hir::OpaqueTy {
impl_trait_fn: None,
origin,
..
}) => (
- may_define_opaque_type(tcx, self.parent_def_id, opaque_hir_id),
+ may_define_opaque_type(tcx, parent_def_id, opaque_hir_id),
origin,
),
_ => (def_scope_default(), hir::OpaqueTyOrigin::TyAlias),
@@ -1028,32 +968,14 @@
// Use the same type variable if the exact same opaque type appears more
// than once in the return type (e.g., if it's passed to a type alias).
- if let Some(opaque_defn) = self.opaque_types.get(&opaque_type_key) {
+ if let Some(opaque_defn) = infcx.inner.borrow().opaque_types.get(&opaque_type_key) {
debug!("instantiate_opaque_types: returning concrete ty {:?}", opaque_defn.concrete_ty);
return opaque_defn.concrete_ty;
}
- let span = tcx.def_span(def_id);
- debug!("fold_opaque_ty {:?} {:?}", self.value_span, span);
- let ty_var = infcx
- .next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::TypeInference, span });
-
- let item_bounds = tcx.explicit_item_bounds(def_id);
- debug!("instantiate_opaque_types: bounds={:#?}", item_bounds);
- let bounds: Vec<_> =
- item_bounds.iter().map(|(bound, _)| bound.subst(tcx, substs)).collect();
-
- let param_env = tcx.param_env(def_id);
- let InferOk { value: bounds, obligations } = infcx.partially_normalize_associated_types_in(
- ObligationCause::misc(span, self.body_id),
- param_env,
- bounds,
- );
- self.obligations.extend(obligations);
-
- debug!("instantiate_opaque_types: bounds={:?}", bounds);
-
- let required_region_bounds = required_region_bounds(tcx, ty, bounds.iter().copied());
- debug!("instantiate_opaque_types: required_region_bounds={:?}", required_region_bounds);
+ let ty_var = infcx.next_ty_var(TypeVariableOrigin {
+ kind: TypeVariableOriginKind::TypeInference,
+ span: self.value_span,
+ });
// Make sure that we are in fact defining the *entire* type
// (e.g., `type Foo<T: Bound> = impl Bar;` needs to be
@@ -1068,23 +990,46 @@
// Foo, impl Bar)`.
let definition_span = self.value_span;
- self.opaque_types.insert(
- OpaqueTypeKey { def_id, substs },
- OpaqueTypeDecl {
- opaque_type: ty,
- definition_span,
- concrete_ty: ty_var,
- has_required_region_bounds: !required_region_bounds.is_empty(),
- origin,
- },
- );
+ {
+ let mut infcx = self.infcx.inner.borrow_mut();
+ infcx.opaque_types.insert(
+ OpaqueTypeKey { def_id, substs },
+ OpaqueTypeDecl { opaque_type: ty, definition_span, concrete_ty: ty_var, origin },
+ );
+ infcx.opaque_types_vars.insert(ty_var, ty);
+ }
+
debug!("instantiate_opaque_types: ty_var={:?}", ty_var);
+ self.compute_opaque_type_obligations(opaque_type_key);
+
+ ty_var
+ }
+
+ fn compute_opaque_type_obligations(&mut self, opaque_type_key: OpaqueTypeKey<'tcx>) {
+ let infcx = self.infcx;
+ let tcx = infcx.tcx;
+ let OpaqueTypeKey { def_id, substs } = opaque_type_key;
+
+ let item_bounds = tcx.explicit_item_bounds(def_id);
+ debug!("instantiate_opaque_types: bounds={:#?}", item_bounds);
+ let bounds: Vec<_> =
+ item_bounds.iter().map(|(bound, _)| bound.subst(tcx, substs)).collect();
+
+ let param_env = tcx.param_env(def_id);
+ let InferOk { value: bounds, obligations } = infcx.partially_normalize_associated_types_in(
+ ObligationCause::misc(self.value_span, self.body_id),
+ param_env,
+ bounds,
+ );
+ self.obligations.extend(obligations);
+
+ debug!("instantiate_opaque_types: bounds={:?}", bounds);
for predicate in &bounds {
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;
+ return;
}
}
}
@@ -1096,14 +1041,13 @@
// This also instantiates nested instances of `impl Trait`.
let predicate = self.instantiate_opaque_types_in_map(predicate);
- let cause = traits::ObligationCause::new(span, self.body_id, traits::OpaqueType);
+ let cause =
+ traits::ObligationCause::new(self.value_span, self.body_id, traits::OpaqueType);
// Require that the predicate holds for the concrete type.
debug!("instantiate_opaque_types: predicate={:?}", predicate);
self.obligations.push(traits::Obligation::new(cause, self.param_env, predicate));
}
-
- ty_var
}
}
@@ -1183,6 +1127,7 @@
ty::PredicateKind::Projection(..)
| ty::PredicateKind::Trait(..)
| ty::PredicateKind::Subtype(..)
+ | ty::PredicateKind::Coerce(..)
| ty::PredicateKind::WellFormed(..)
| ty::PredicateKind::ObjectSafe(..)
| ty::PredicateKind::ClosureKind(..)
diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
index f54eb09..622c9ed 100644
--- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs
+++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
@@ -285,6 +285,7 @@
def_id: trait_did,
substs: infcx.tcx.mk_substs_trait(ty, &[]),
},
+ constness: ty::BoundConstness::NotConst,
}));
let computed_preds = param_env.caller_bounds().iter();
@@ -344,10 +345,7 @@
Err(SelectionError::Unimplemented) => {
if self.is_param_no_infer(pred.skip_binder().trait_ref.substs) {
already_visited.remove(&pred);
- self.add_user_pred(
- &mut user_computed_preds,
- pred.without_const().to_predicate(self.tcx),
- );
+ self.add_user_pred(&mut user_computed_preds, pred.to_predicate(self.tcx));
predicates.push_back(pred);
} else {
debug!(
@@ -414,10 +412,8 @@
) {
let mut should_add_new = true;
user_computed_preds.retain(|&old_pred| {
- if let (
- ty::PredicateKind::Trait(new_trait, _),
- ty::PredicateKind::Trait(old_trait, _),
- ) = (new_pred.kind().skip_binder(), old_pred.kind().skip_binder())
+ if let (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;
@@ -638,7 +634,7 @@
let bound_predicate = predicate.kind();
match bound_predicate.skip_binder() {
- ty::PredicateKind::Trait(p, _) => {
+ 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`
diff --git a/compiler/rustc_trait_selection/src/traits/codegen.rs b/compiler/rustc_trait_selection/src/traits/codegen.rs
index 45853a6..f06f0e3 100644
--- a/compiler/rustc_trait_selection/src/traits/codegen.rs
+++ b/compiler/rustc_trait_selection/src/traits/codegen.rs
@@ -12,7 +12,7 @@
use rustc_middle::ty::fold::TypeFoldable;
use rustc_middle::ty::{self, TyCtxt};
-/// Attempts to resolve an obligation to a `ImplSource`. The result is
+/// Attempts to resolve an obligation to an `ImplSource`. The result is
/// a shallow `ImplSource` resolution, meaning that we do not
/// (necessarily) resolve all nested obligations on the impl. Note
/// that type check should guarantee to us that all nested
diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs
index 9bb4af1..668a74b 100644
--- a/compiler/rustc_trait_selection/src/traits/coherence.rs
+++ b/compiler/rustc_trait_selection/src/traits/coherence.rs
@@ -391,7 +391,7 @@
) -> Result<(), OrphanCheckErr<'tcx>> {
debug!("orphan_check_trait_ref(trait_ref={:?}, in_crate={:?})", trait_ref, in_crate);
- if trait_ref.needs_infer() && trait_ref.needs_subst() {
+ if trait_ref.needs_infer() && trait_ref.definitely_needs_subst(tcx) {
bug!(
"can't orphan check a trait ref with both params and inference variables {:?}",
trait_ref
diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
index b1a9388..ddabe59 100644
--- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
+++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
@@ -19,7 +19,7 @@
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};
+use rustc_span::def_id::LocalDefId;
use rustc_span::Span;
use std::cmp;
@@ -29,26 +29,20 @@
/// Check if a given constant can be evaluated.
pub fn is_const_evaluatable<'cx, 'tcx>(
infcx: &InferCtxt<'cx, 'tcx>,
- def: ty::WithOptConstParam<DefId>,
- substs: SubstsRef<'tcx>,
+ uv: ty::Unevaluated<'tcx, ()>,
param_env: ty::ParamEnv<'tcx>,
span: Span,
) -> Result<(), NotConstEvaluatable> {
- debug!("is_const_evaluatable({:?}, {:?})", def, substs);
- if infcx.tcx.features().const_evaluatable_checked {
+ debug!("is_const_evaluatable({:?})", uv);
+ if infcx.tcx.features().generic_const_exprs {
let tcx = infcx.tcx;
- match AbstractConst::new(tcx, def, substs)? {
+ match AbstractConst::new(tcx, uv)? {
// We are looking at a generic abstract constant.
Some(ct) => {
for pred in param_env.caller_bounds() {
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(());
- }
-
- if let Some(b_ct) = AbstractConst::new(tcx, b_def, b_substs)? {
+ ty::PredicateKind::ConstEvaluatable(uv) => {
+ if let Some(b_ct) = AbstractConst::new(tcx, uv)? {
// 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`
@@ -91,7 +85,7 @@
let leaf = leaf.subst(tcx, ct.substs);
if leaf.has_infer_types_or_consts() {
failure_kind = FailureKind::MentionsInfer;
- } else if leaf.has_param_types_or_consts() {
+ } else if leaf.definitely_has_param_types_or_consts(tcx) {
failure_kind = cmp::min(failure_kind, FailureKind::MentionsParam);
}
@@ -101,7 +95,7 @@
let ty = ty.subst(tcx, ct.substs);
if ty.has_infer_types_or_consts() {
failure_kind = FailureKind::MentionsInfer;
- } else if ty.has_param_types_or_consts() {
+ } else if ty.definitely_has_param_types_or_consts(tcx) {
failure_kind = cmp::min(failure_kind, FailureKind::MentionsParam);
}
@@ -134,7 +128,7 @@
}
let future_compat_lint = || {
- if let Some(local_def_id) = def.did.as_local() {
+ if let Some(local_def_id) = uv.def.did.as_local() {
infcx.tcx.struct_span_lint_hir(
lint::builtin::CONST_EVALUATABLE_UNCHECKED,
infcx.tcx.hir().local_def_id_to_hir_id(local_def_id),
@@ -155,16 +149,12 @@
// and hopefully soon change this to an error.
//
// See #74595 for more details about this.
- let concrete = infcx.const_eval_resolve(
- param_env,
- ty::Unevaluated { def, substs, promoted: None },
- Some(span),
- );
+ let concrete = infcx.const_eval_resolve(param_env, uv.expand(), Some(span));
- if concrete.is_ok() && substs.has_param_types_or_consts() {
- match infcx.tcx.def_kind(def.did) {
+ if concrete.is_ok() && uv.substs(infcx.tcx).definitely_has_param_types_or_consts(infcx.tcx) {
+ match infcx.tcx.def_kind(uv.def.did) {
DefKind::AnonConst => {
- let mir_body = infcx.tcx.mir_for_ctfe_opt_const_arg(def);
+ let mir_body = infcx.tcx.mir_for_ctfe_opt_const_arg(uv.def);
if mir_body.is_polymorphic {
future_compat_lint();
@@ -176,7 +166,7 @@
debug!(?concrete, "is_const_evaluatable");
match concrete {
- Err(ErrorHandled::TooGeneric) => Err(match substs.has_infer_types_or_consts() {
+ Err(ErrorHandled::TooGeneric) => Err(match uv.has_infer_types_or_consts() {
true => NotConstEvaluatable::MentionsInfer,
false => NotConstEvaluatable::MentionsParam,
}),
@@ -201,15 +191,14 @@
pub substs: SubstsRef<'tcx>,
}
-impl AbstractConst<'tcx> {
+impl<'tcx> AbstractConst<'tcx> {
pub fn new(
tcx: TyCtxt<'tcx>,
- def: ty::WithOptConstParam<DefId>,
- substs: SubstsRef<'tcx>,
+ uv: ty::Unevaluated<'tcx, ()>,
) -> Result<Option<AbstractConst<'tcx>>, ErrorReported> {
- let inner = tcx.mir_abstract_const_opt_const_arg(def)?;
- debug!("AbstractConst::new({:?}) = {:?}", def, inner);
- Ok(inner.map(|inner| AbstractConst { inner, substs }))
+ let inner = tcx.mir_abstract_const_opt_const_arg(uv.def)?;
+ debug!("AbstractConst::new({:?}) = {:?}", uv, inner);
+ Ok(inner.map(|inner| AbstractConst { inner, substs: uv.substs(tcx) }))
}
pub fn from_const(
@@ -217,9 +206,7 @@
ct: &ty::Const<'tcx>,
) -> Result<Option<AbstractConst<'tcx>>, ErrorReported> {
match ct.val {
- ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted: _ }) => {
- AbstractConst::new(tcx, def, substs)
- }
+ ty::ConstKind::Unevaluated(uv) => AbstractConst::new(tcx, uv.shrink()),
ty::ConstKind::Error(_) => Err(ErrorReported),
_ => Ok(None),
}
@@ -550,9 +537,9 @@
tcx: TyCtxt<'tcx>,
def: ty::WithOptConstParam<LocalDefId>,
) -> Result<Option<&'tcx [mir::abstract_const::Node<'tcx>]>, ErrorReported> {
- if tcx.features().const_evaluatable_checked {
+ if tcx.features().generic_const_exprs {
match tcx.def_kind(def.did) {
- // FIXME(const_evaluatable_checked): We currently only do this for anonymous constants,
+ // FIXME(generic_const_exprs): We currently only do this for anonymous constants,
// meaning that we do not look into associated constants. I(@lcnr) am not yet sure whether
// we want to look into them or treat them as opaque projections.
//
@@ -569,14 +556,11 @@
pub(super) fn try_unify_abstract_consts<'tcx>(
tcx: TyCtxt<'tcx>,
- ((a, a_substs), (b, b_substs)): (
- (ty::WithOptConstParam<DefId>, SubstsRef<'tcx>),
- (ty::WithOptConstParam<DefId>, SubstsRef<'tcx>),
- ),
+ (a, b): (ty::Unevaluated<'tcx, ()>, ty::Unevaluated<'tcx, ()>),
) -> bool {
(|| {
- if let Some(a) = AbstractConst::new(tcx, a, a_substs)? {
- if let Some(b) = AbstractConst::new(tcx, b, b_substs)? {
+ if let Some(a) = AbstractConst::new(tcx, a)? {
+ if let Some(b) = AbstractConst::new(tcx, b)? {
return Ok(try_unify(tcx, a, b));
}
}
@@ -584,7 +568,7 @@
Ok(false)
})()
.unwrap_or_else(|ErrorReported| true)
- // FIXME(const_evaluatable_checked): We should instead have this
+ // FIXME(generic_const_exprs): We should instead have this
// method return the resulting `ty::Const` and return `ConstKind::Error`
// on `ErrorReported`.
}
@@ -672,13 +656,13 @@
// branch should only be taking when dealing with associated constants, at
// which point directly comparing them seems like the desired behavior.
//
- // FIXME(const_evaluatable_checked): This isn't actually the case.
+ // FIXME(generic_const_exprs): This isn't actually the case.
// We also take this branch for concrete anonymous constants and
// expand generic anonymous constants with concrete substs.
(ty::ConstKind::Unevaluated(a_uv), ty::ConstKind::Unevaluated(b_uv)) => {
a_uv == b_uv
}
- // FIXME(const_evaluatable_checked): We may want to either actually try
+ // FIXME(generic_const_exprs): We may want to either actually try
// to evaluate `a_ct` and `b_ct` if they are are fully concrete or something like
// this, for now we just return false here.
_ => false,
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 713e06f..9ce6c58 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
@@ -16,6 +16,8 @@
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_hir::intravisit::Visitor;
+use rustc_hir::GenericParam;
+use rustc_hir::Item;
use rustc_hir::Node;
use rustc_middle::mir::abstract_const::NotConstEvaluatable;
use rustc_middle::ty::error::ExpectedFound;
@@ -224,7 +226,9 @@
debug!("report_overflow_error_cycle: cycle={:?}", cycle);
- self.report_overflow_error(&cycle[0], false);
+ // The 'deepest' obligation is most likely to have a useful
+ // cause 'backtrace'
+ self.report_overflow_error(cycle.iter().max_by_key(|p| p.recursion_depth).unwrap(), false);
}
fn report_selection_error(
@@ -240,8 +244,8 @@
let mut err = match *error {
SelectionError::Unimplemented => {
- // If this obligation was generated as a result of well-formed checking, see if we
- // can get a better error message by performing HIR-based well formed checking.
+ // If this obligation was generated as a result of well-formedness checking, see if we
+ // can get a better error message by performing HIR-based well-formedness checking.
if let ObligationCauseCode::WellFormed(Some(wf_loc)) =
root_obligation.cause.code.peel_derives()
{
@@ -277,7 +281,7 @@
let bound_predicate = obligation.predicate.kind();
match bound_predicate.skip_binder() {
- ty::PredicateKind::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);
@@ -518,8 +522,7 @@
);
trait_pred
});
- let unit_obligation =
- obligation.with(predicate.without_const().to_predicate(tcx));
+ let unit_obligation = obligation.with(predicate.to_predicate(tcx));
if self.predicate_may_hold(&unit_obligation) {
err.note("this trait is implemented for `()`.");
err.note(
@@ -566,6 +569,13 @@
span_bug!(span, "subtype requirement gave wrong error: `{:?}`", predicate)
}
+ ty::PredicateKind::Coerce(predicate) => {
+ // Errors for Coerce predicates show up as
+ // `FulfillmentErrorCode::CodeSubtypeError`,
+ // not selection error.
+ span_bug!(span, "coerce requirement gave wrong error: `{:?}`", predicate)
+ }
+
ty::PredicateKind::RegionOutlives(predicate) => {
let predicate = bound_predicate.rebind(predicate);
let predicate = self.resolve_vars_if_possible(predicate);
@@ -788,7 +798,7 @@
)
}
SelectionError::NotConstEvaluatable(NotConstEvaluatable::MentionsParam) => {
- if !self.tcx.features().const_evaluatable_checked {
+ if !self.tcx.features().generic_const_exprs {
let mut err = self.tcx.sess.struct_span_err(
span,
"constant expression depends on a generic parameter",
@@ -797,7 +807,7 @@
// issue. However, this is currently not actually possible
// (see https://github.com/rust-lang/rust/issues/66962#issuecomment-575907083).
//
- // Note that with `feature(const_evaluatable_checked)` this case should not
+ // Note that with `feature(generic_const_exprs)` this case should not
// be reachable.
err.note("this may fail depending on what value the parameter takes");
err.emit();
@@ -805,10 +815,10 @@
}
match obligation.predicate.kind().skip_binder() {
- ty::PredicateKind::ConstEvaluatable(def, _) => {
+ ty::PredicateKind::ConstEvaluatable(uv) => {
let mut err =
self.tcx.sess.struct_span_err(span, "unconstrained generic constant");
- let const_span = self.tcx.def_span(def.did);
+ let const_span = self.tcx.def_span(uv.def.did);
match self.tcx.sess.source_map().span_to_snippet(const_span) {
Ok(snippet) => err.help(&format!(
"try adding a `where` bound using this expression: `where [(); {}]:`",
@@ -1130,6 +1140,20 @@
obligation: &PredicateObligation<'tcx>,
);
+ fn maybe_suggest_unsized_generics(
+ &self,
+ err: &mut DiagnosticBuilder<'tcx>,
+ span: Span,
+ node: Node<'hir>,
+ );
+
+ fn maybe_indirection_for_unsized(
+ &self,
+ err: &mut DiagnosticBuilder<'tcx>,
+ item: &'hir Item<'hir>,
+ param: &'hir GenericParam<'hir>,
+ ) -> bool;
+
fn is_recursive_obligation(
&self,
obligated_types: &mut Vec<&ty::TyS<'tcx>>,
@@ -1148,7 +1172,7 @@
// FIXME: It should be possible to deal with `ForAll` in a cleaner way.
let bound_error = error.kind();
let (cond, error) = match (cond.kind().skip_binder(), bound_error.skip_binder()) {
- (ty::PredicateKind::Trait(..), ty::PredicateKind::Trait(error, _)) => {
+ (ty::PredicateKind::Trait(..), ty::PredicateKind::Trait(error)) => {
(cond, bound_error.rebind(error))
}
_ => {
@@ -1159,7 +1183,7 @@
for obligation in super::elaborate_predicates(self.tcx, std::iter::once(cond)) {
let bound_predicate = obligation.predicate.kind();
- if let ty::PredicateKind::Trait(implication, _) = bound_predicate.skip_binder() {
+ 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.
@@ -1536,7 +1560,7 @@
let bound_predicate = predicate.kind();
let mut err = match bound_predicate.skip_binder() {
- ty::PredicateKind::Trait(data, _) => {
+ ty::PredicateKind::Trait(data) => {
let trait_ref = bound_predicate.rebind(data.trait_ref);
debug!("trait_ref {:?}", trait_ref);
@@ -1604,6 +1628,8 @@
let generics = self.tcx.generics_of(*def_id);
if generics.params.iter().any(|p| p.name != kw::SelfUpper)
&& !snippet.ends_with('>')
+ && !generics.has_impl_trait()
+ && !self.tcx.fn_trait_kind_from_lang_item(*def_id).is_some()
{
// FIXME: To avoid spurious suggestions in functions where type arguments
// where already supplied, we check the snippet to make sure it doesn't
@@ -1801,12 +1827,15 @@
match (obligation.predicate.kind().skip_binder(), obligation.cause.code.peel_derives())
{
(
- ty::PredicateKind::Trait(pred, _),
+ ty::PredicateKind::Trait(pred),
&ObligationCauseCode::BindingObligation(item_def_id, span),
) => (pred, item_def_id, span),
_ => return,
};
-
+ debug!(
+ "suggest_unsized_bound_if_applicable: pred={:?} item_def_id={:?} span={:?}",
+ pred, item_def_id, span
+ );
let node = match (
self.tcx.hir().get_if_local(item_def_id),
Some(pred.def_id()) == self.tcx.lang_items().sized_trait(),
@@ -1814,80 +1843,105 @@
(Some(node), true) => node,
_ => return,
};
+ self.maybe_suggest_unsized_generics(err, span, node);
+ }
+
+ fn maybe_suggest_unsized_generics(
+ &self,
+ err: &mut DiagnosticBuilder<'tcx>,
+ span: Span,
+ node: Node<'hir>,
+ ) {
let generics = match node.generics() {
Some(generics) => generics,
None => return,
};
- for param in generics.params {
- if param.span != span
- || param.bounds.iter().any(|bound| {
- bound.trait_ref().and_then(|trait_ref| trait_ref.trait_def_id())
- == self.tcx.lang_items().sized_trait()
- })
- {
- continue;
- }
- match node {
- hir::Node::Item(
- item
- @
- hir::Item {
- kind:
- hir::ItemKind::Enum(..)
- | hir::ItemKind::Struct(..)
- | hir::ItemKind::Union(..),
- ..
- },
- ) => {
- // Suggesting `T: ?Sized` is only valid in an ADT if `T` is only used in a
- // borrow. `struct S<'a, T: ?Sized>(&'a T);` is valid, `struct S<T: ?Sized>(T);`
- // is not.
- let mut visitor = FindTypeParam {
- param: param.name.ident().name,
- invalid_spans: vec![],
- nested: false,
- };
- visitor.visit_item(item);
- if !visitor.invalid_spans.is_empty() {
- let mut multispan: MultiSpan = param.span.into();
- multispan.push_span_label(
- param.span,
- format!("this could be changed to `{}: ?Sized`...", param.name.ident()),
- );
- for sp in visitor.invalid_spans {
- multispan.push_span_label(
- sp,
- format!(
- "...if indirection were used here: `Box<{}>`",
- param.name.ident(),
- ),
- );
- }
- err.span_help(
- multispan,
- &format!(
- "you could relax the implicit `Sized` bound on `{T}` if it were \
- used through indirection like `&{T}` or `Box<{T}>`",
- T = param.name.ident(),
- ),
- );
- return;
- }
+ let sized_trait = self.tcx.lang_items().sized_trait();
+ debug!("maybe_suggest_unsized_generics: generics.params={:?}", generics.params);
+ debug!("maybe_suggest_unsized_generics: generics.where_clause={:?}", generics.where_clause);
+ let param = generics
+ .params
+ .iter()
+ .filter(|param| param.span == span)
+ .filter(|param| {
+ // Check that none of the explicit trait bounds is `Sized`. Assume that an explicit
+ // `Sized` bound is there intentionally and we don't need to suggest relaxing it.
+ param
+ .bounds
+ .iter()
+ .all(|bound| bound.trait_ref().and_then(|tr| tr.trait_def_id()) != sized_trait)
+ })
+ .next();
+ let param = match param {
+ Some(param) => param,
+ _ => return,
+ };
+ debug!("maybe_suggest_unsized_generics: param={:?}", param);
+ match node {
+ hir::Node::Item(
+ item
+ @
+ hir::Item {
+ // Only suggest indirection for uses of type parameters in ADTs.
+ kind:
+ hir::ItemKind::Enum(..) | hir::ItemKind::Struct(..) | hir::ItemKind::Union(..),
+ ..
+ },
+ ) => {
+ if self.maybe_indirection_for_unsized(err, item, param) {
+ return;
}
- _ => {}
}
- let (span, separator) = match param.bounds {
- [] => (span.shrink_to_hi(), ":"),
- [.., bound] => (bound.span().shrink_to_hi(), " +"),
- };
- err.span_suggestion_verbose(
- span,
- "consider relaxing the implicit `Sized` restriction",
- format!("{} ?Sized", separator),
- Applicability::MachineApplicable,
- );
- return;
+ _ => {}
+ };
+ // Didn't add an indirection suggestion, so add a general suggestion to relax `Sized`.
+ let (span, separator) = match param.bounds {
+ [] => (span.shrink_to_hi(), ":"),
+ [.., bound] => (bound.span().shrink_to_hi(), " +"),
+ };
+ err.span_suggestion_verbose(
+ span,
+ "consider relaxing the implicit `Sized` restriction",
+ format!("{} ?Sized", separator),
+ Applicability::MachineApplicable,
+ );
+ }
+
+ fn maybe_indirection_for_unsized(
+ &self,
+ err: &mut DiagnosticBuilder<'tcx>,
+ item: &'hir Item<'hir>,
+ param: &'hir GenericParam<'hir>,
+ ) -> bool {
+ // Suggesting `T: ?Sized` is only valid in an ADT if `T` is only used in a
+ // borrow. `struct S<'a, T: ?Sized>(&'a T);` is valid, `struct S<T: ?Sized>(T);`
+ // is not. Look for invalid "bare" parameter uses, and suggest using indirection.
+ let mut visitor =
+ FindTypeParam { param: param.name.ident().name, invalid_spans: vec![], nested: false };
+ visitor.visit_item(item);
+ if visitor.invalid_spans.is_empty() {
+ return false;
}
+ let mut multispan: MultiSpan = param.span.into();
+ multispan.push_span_label(
+ param.span,
+ format!("this could be changed to `{}: ?Sized`...", param.name.ident()),
+ );
+ for sp in visitor.invalid_spans {
+ multispan.push_span_label(
+ sp,
+ format!("...if indirection were used here: `Box<{}>`", param.name.ident()),
+ );
+ }
+ err.span_help(
+ multispan,
+ &format!(
+ "you could relax the implicit `Sized` bound on `{T}` if it were \
+ used through indirection like `&{T}` or `Box<{T}>`",
+ T = param.name.ident(),
+ ),
+ );
+ true
}
fn is_recursive_obligation(
@@ -1938,6 +1992,7 @@
if path.segments.len() == 1 && path.segments[0].ident.name == self.param =>
{
if !self.nested {
+ debug!("FindTypeParam::visit_ty: ty={:?}", ty);
self.invalid_spans.push(ty.span);
}
}
@@ -2001,7 +2056,7 @@
Arg(String, String),
/// An argument of tuple type. For a "found" argument, the span is
- /// the location in the source of the pattern. For a "expected"
+ /// the location in the source of the pattern. For an "expected"
/// argument, it will be None. The vector is a list of (name, ty)
/// strings for the components of the tuple.
Tuple(Option<Span>, Vec<(String, String)>),
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs
index 0ca0245..3a32f1c 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs
@@ -124,11 +124,10 @@
self.impl_similar_to(trait_ref, obligation).unwrap_or_else(|| trait_ref.def_id());
let trait_ref = trait_ref.skip_binder();
- let mut flags = vec![];
- flags.push((
+ let mut flags = vec![(
sym::ItemContext,
self.describe_enclosure(obligation.cause.body_id).map(|s| s.to_owned()),
- ));
+ )];
match obligation.cause.code {
ObligationCauseCode::BuiltinDerivedObligation(..)
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 9a33875..db3432b 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -290,13 +290,9 @@
} else {
// Trivial case: `T` needs an extra bound: `T: Bound`.
let (sp, suggestion) = match (
- generics
- .params
- .iter()
- .filter(|p| {
- !matches!(p.kind, hir::GenericParamKind::Type { synthetic: Some(_), .. })
- })
- .next(),
+ generics.params.iter().find(|p| {
+ !matches!(p.kind, hir::GenericParamKind::Type { synthetic: Some(_), .. })
+ }),
super_traits,
) {
(_, None) => predicate_constraint(
@@ -1163,15 +1159,18 @@
if is_object_safe {
// Suggest `-> Box<dyn Trait>` and `Box::new(returned_value)`.
// Get all the return values and collect their span and suggestion.
- if let Some(mut suggestions) = visitor
+ let mut suggestions: Vec<_> = visitor
.returns
.iter()
- .map(|expr| {
- let snip = sm.span_to_snippet(expr.span).ok()?;
- Some((expr.span, format!("Box::new({})", snip)))
+ .flat_map(|expr| {
+ vec![
+ (expr.span.shrink_to_lo(), "Box::new(".to_string()),
+ (expr.span.shrink_to_hi(), ")".to_string()),
+ ]
+ .into_iter()
})
- .collect::<Option<Vec<_>>>()
- {
+ .collect();
+ if !suggestions.is_empty() {
// Add the suggestion for the return type.
suggestions.push((ret_ty.span, format!("Box<dyn {}>", trait_obj)));
err.multipart_suggestion(
@@ -1366,7 +1365,7 @@
// When a future does not implement a trait because of a captured type in one of the
// generators somewhere in the call stack, then the result is a chain of obligations.
//
- // Given a `async fn` A that calls a `async fn` B which captures a non-send type and that
+ // Given an `async fn` A that calls an `async fn` B which captures a non-send type and that
// future is passed as an argument to a function C which requires a `Send` type, then the
// chain looks something like this:
//
@@ -1387,7 +1386,7 @@
// 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.kind().skip_binder() {
- ty::PredicateKind::Trait(p, _) => (Some(p.trait_ref), Some(p.self_ty())),
+ ty::PredicateKind::Trait(p) => (Some(p.trait_ref), Some(p.self_ty())),
_ => (None, None),
};
let mut generator = None;
@@ -1929,7 +1928,11 @@
| ObligationCauseCode::OpaqueType
| ObligationCauseCode::MiscObligation
| ObligationCauseCode::WellFormed(..)
- | ObligationCauseCode::MatchImpl(..) => {}
+ | ObligationCauseCode::MatchImpl(..)
+ | ObligationCauseCode::ReturnType
+ | ObligationCauseCode::ReturnValue(_)
+ | ObligationCauseCode::BlockTailExpression(_)
+ | ObligationCauseCode::LetElse => {}
ObligationCauseCode::SliceOrArrayElem => {
err.note("slice and array elements must have `Sized` type");
}
@@ -1963,7 +1966,7 @@
}
ObligationCauseCode::BindingObligation(item_def_id, span) => {
let item_name = tcx.def_path_str(item_def_id);
- let msg = format!("required by this bound in `{}`", item_name);
+ let mut multispan = MultiSpan::from(span);
if let Some(ident) = tcx.opt_item_name(item_def_id) {
let sm = tcx.sess.source_map();
let same_line =
@@ -1972,16 +1975,17 @@
_ => true,
};
if !ident.span.overlaps(span) && !same_line {
- err.span_label(ident.span, "required by a bound in this");
+ multispan
+ .push_span_label(ident.span, "required by a bound in this".to_string());
}
}
+ let descr = format!("required by a bound in `{}`", item_name);
if span != DUMMY_SP {
- err.span_label(span, &msg);
+ let msg = format!("required by this bound in `{}`", item_name);
+ multispan.push_span_label(span, msg);
+ err.span_note(multispan, &descr);
} else {
- err.span_note(
- tcx.def_span(item_def_id),
- &format!("required by a bound in `{}`", item_name),
- );
+ err.span_note(tcx.def_span(item_def_id), &descr);
}
}
ObligationCauseCode::ObjectCastObligation(object_ty) => {
@@ -2072,6 +2076,9 @@
ObligationCauseCode::SizedYieldType => {
err.note("the yield type of a generator must have a statically known size");
}
+ ObligationCauseCode::SizedBoxType => {
+ err.note("the type of a box expression must have a statically known size");
+ }
ObligationCauseCode::AssignmentLhsSized => {
err.note("the left-hand-side of an assignment must have a statically known size");
}
@@ -2335,9 +2342,6 @@
predicate
));
}
- ObligationCauseCode::ReturnType
- | ObligationCauseCode::ReturnValue(_)
- | ObligationCauseCode::BlockTailExpression(_) => (),
ObligationCauseCode::TrivialBound => {
err.help("see issue #48214");
if tcx.sess.opts.unstable_features.is_nightly_build() {
diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs
index 9ec1dd5..18abcc7 100644
--- a/compiler/rustc_trait_selection/src/traits/fulfill.rs
+++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs
@@ -3,6 +3,7 @@
use rustc_data_structures::obligation_forest::{Error, ForestObligation, Outcome};
use rustc_data_structures::obligation_forest::{ObligationForest, ObligationProcessor};
use rustc_errors::ErrorReported;
+use rustc_hir as hir;
use rustc_infer::traits::{SelectionError, TraitEngine, TraitEngineExt as _, TraitObligation};
use rustc_middle::mir::abstract_const::NotConstEvaluatable;
use rustc_middle::mir::interpret::ErrorHandled;
@@ -228,6 +229,22 @@
if errors.is_empty() { Ok(()) } else { Err(errors) }
}
+ fn select_all_with_constness_or_error(
+ &mut self,
+ infcx: &InferCtxt<'_, 'tcx>,
+ constness: rustc_hir::Constness,
+ ) -> Result<(), Vec<FulfillmentError<'tcx>>> {
+ self.select_with_constness_where_possible(infcx, constness)?;
+
+ let errors: Vec<_> = self
+ .predicates
+ .to_errors(CodeAmbiguity)
+ .into_iter()
+ .map(to_fulfillment_error)
+ .collect();
+ if errors.is_empty() { Ok(()) } else { Err(errors) }
+ }
+
fn select_where_possible(
&mut self,
infcx: &InferCtxt<'_, 'tcx>,
@@ -236,6 +253,15 @@
self.select(&mut selcx)
}
+ fn select_with_constness_where_possible(
+ &mut self,
+ infcx: &InferCtxt<'_, 'tcx>,
+ constness: hir::Constness,
+ ) -> Result<(), Vec<FulfillmentError<'tcx>>> {
+ let mut selcx = SelectionContext::with_constness(infcx, constness);
+ self.select(&mut selcx)
+ }
+
fn pending_obligations(&self) -> Vec<PredicateObligation<'tcx>> {
self.predicates.map_pending_obligations(|o| o.obligation.clone())
}
@@ -352,7 +378,7 @@
// Evaluation will discard candidates using the leak check.
// This means we need to pass it the bound version of our
// predicate.
- ty::PredicateKind::Trait(trait_ref, _constness) => {
+ ty::PredicateKind::Trait(trait_ref) => {
let trait_obligation = obligation.with(binder.rebind(trait_ref));
self.process_trait_obligation(
@@ -376,6 +402,7 @@
| ty::PredicateKind::ObjectSafe(_)
| ty::PredicateKind::ClosureKind(..)
| ty::PredicateKind::Subtype(_)
+ | ty::PredicateKind::Coerce(_)
| ty::PredicateKind::ConstEvaluatable(..)
| ty::PredicateKind::ConstEquate(..) => {
let pred = infcx.replace_bound_vars_with_placeholders(binder);
@@ -388,7 +415,7 @@
}
},
Some(pred) => match pred {
- ty::PredicateKind::Trait(data, _) => {
+ ty::PredicateKind::Trait(data) => {
let trait_obligation = obligation.with(Binder::dummy(data));
self.process_trait_obligation(
@@ -491,11 +518,35 @@
}
}
- ty::PredicateKind::ConstEvaluatable(def_id, substs) => {
+ ty::PredicateKind::Coerce(coerce) => {
+ match self.selcx.infcx().coerce_predicate(
+ &obligation.cause,
+ obligation.param_env,
+ Binder::dummy(coerce),
+ ) {
+ None => {
+ // None means that both are unresolved.
+ pending_obligation.stalled_on = vec![
+ TyOrConstInferVar::maybe_from_ty(coerce.a).unwrap(),
+ TyOrConstInferVar::maybe_from_ty(coerce.b).unwrap(),
+ ];
+ ProcessResult::Unchanged
+ }
+ Some(Ok(ok)) => ProcessResult::Changed(mk_pending(ok.obligations)),
+ Some(Err(err)) => {
+ let expected_found = ExpectedFound::new(false, coerce.a, coerce.b);
+ ProcessResult::Error(FulfillmentErrorCode::CodeSubtypeError(
+ expected_found,
+ err,
+ ))
+ }
+ }
+ }
+
+ ty::PredicateKind::ConstEvaluatable(uv) => {
match const_evaluatable::is_const_evaluatable(
self.selcx.infcx(),
- def_id,
- substs,
+ uv,
obligation.param_env,
obligation.cause.span,
) {
@@ -503,7 +554,9 @@
Err(NotConstEvaluatable::MentionsInfer) => {
pending_obligation.stalled_on.clear();
pending_obligation.stalled_on.extend(
- substs.iter().filter_map(TyOrConstInferVar::maybe_from_generic_arg),
+ uv.substs(infcx.tcx)
+ .iter()
+ .filter_map(TyOrConstInferVar::maybe_from_generic_arg),
);
ProcessResult::Unchanged
}
@@ -518,7 +571,8 @@
ty::PredicateKind::ConstEquate(c1, c2) => {
debug!(?c1, ?c2, "equating consts");
- if self.selcx.tcx().features().const_evaluatable_checked {
+ let tcx = self.selcx.tcx();
+ if tcx.features().generic_const_exprs {
// FIXME: we probably should only try to unify abstract constants
// if the constants depend on generic parameters.
//
@@ -526,11 +580,7 @@
if let (ty::ConstKind::Unevaluated(a), ty::ConstKind::Unevaluated(b)) =
(c1.val, c2.val)
{
- if self
- .selcx
- .tcx()
- .try_unify_abstract_consts(((a.def, a.substs), (b.def, b.substs)))
- {
+ if infcx.try_unify_abstract_consts(a.shrink(), b.shrink()) {
return ProcessResult::Changed(vec![]);
}
}
@@ -549,7 +599,7 @@
Err(ErrorHandled::TooGeneric) => {
stalled_on.extend(
unevaluated
- .substs
+ .substs(tcx)
.iter()
.filter_map(TyOrConstInferVar::maybe_from_generic_arg),
);
@@ -620,10 +670,15 @@
stalled_on: &mut Vec<TyOrConstInferVar<'tcx>>,
) -> ProcessResult<PendingPredicateObligation<'tcx>, FulfillmentErrorCode<'tcx>> {
let infcx = self.selcx.infcx();
- if obligation.predicate.is_global() {
+ if obligation.predicate.is_known_global() {
// no type variables present, can use evaluation for better caching.
// FIXME: consider caching errors too.
- if infcx.predicate_must_hold_considering_regions(obligation) {
+ //
+ // If the predicate is considered const, then we cannot use this because
+ // it will cause false negatives in the ui tests.
+ if !self.selcx.is_predicate_const(obligation.predicate)
+ && infcx.predicate_must_hold_considering_regions(obligation)
+ {
debug!(
"selecting trait at depth {} evaluated to holds",
obligation.recursion_depth
@@ -674,10 +729,15 @@
) -> ProcessResult<PendingPredicateObligation<'tcx>, FulfillmentErrorCode<'tcx>> {
let tcx = self.selcx.tcx();
- if obligation.predicate.is_global() {
+ if obligation.predicate.is_global(tcx) {
// no type variables present, can use evaluation for better caching.
// FIXME: consider caching errors too.
- if self.selcx.infcx().predicate_must_hold_considering_regions(obligation) {
+ //
+ // If the predicate is considered const, then we cannot use this because
+ // it will cause false negatives in the ui tests.
+ if !self.selcx.is_predicate_const(obligation.predicate)
+ && self.selcx.infcx().predicate_must_hold_considering_regions(obligation)
+ {
return ProcessResult::Changed(vec![]);
} else {
tracing::debug!("Does NOT hold: {:?}", obligation);
@@ -708,14 +768,15 @@
selcx: &mut SelectionContext<'a, 'tcx>,
substs: ty::Binder<'tcx, SubstsRef<'tcx>>,
) -> impl Iterator<Item = TyOrConstInferVar<'tcx>> {
+ let tcx = selcx.tcx();
selcx
.infcx()
.resolve_vars_if_possible(substs)
.skip_binder() // ok because this check doesn't care about regions
.iter()
.filter(|arg| arg.has_infer_types_or_consts())
- .flat_map(|arg| {
- let mut walker = arg.walk();
+ .flat_map(move |arg| {
+ let mut walker = arg.walk(tcx);
while let Some(c) = walker.next() {
if !c.has_infer_types_or_consts() {
walker.visited.remove(&c);
diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs
index 3a80e72..17a4184 100644
--- a/compiler/rustc_trait_selection/src/traits/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/mod.rs
@@ -28,15 +28,18 @@
use rustc_errors::ErrorReported;
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
+use rustc_hir::lang_items::LangItem;
use rustc_middle::ty::fold::TypeFoldable;
use rustc_middle::ty::subst::{InternalSubsts, SubstsRef};
use rustc_middle::ty::{
self, GenericParamDefKind, ToPredicate, Ty, TyCtxt, VtblEntry, WithConstness,
COMMON_VTABLE_ENTRIES,
};
-use rustc_span::Span;
+use rustc_span::{sym, Span};
+use smallvec::SmallVec;
use std::fmt::Debug;
+use std::ops::ControlFlow;
pub use self::FulfillmentErrorCode::*;
pub use self::ImplSource::*;
@@ -447,13 +450,181 @@
debug!("subst_and_check_impossible_predicates(key={:?})", key);
let mut predicates = tcx.predicates_of(key.0).instantiate(tcx, key.1).predicates;
- predicates.retain(|predicate| !predicate.needs_subst());
+ predicates.retain(|predicate| !predicate.definitely_needs_subst(tcx));
let result = impossible_predicates(tcx, predicates);
debug!("subst_and_check_impossible_predicates(key={:?}) = {:?}", key, result);
result
}
+#[derive(Clone, Debug)]
+enum VtblSegment<'tcx> {
+ MetadataDSA,
+ TraitOwnEntries { trait_ref: ty::PolyTraitRef<'tcx>, emit_vptr: bool },
+}
+
+/// Prepare the segments for a vtable
+fn prepare_vtable_segments<'tcx, T>(
+ tcx: TyCtxt<'tcx>,
+ trait_ref: ty::PolyTraitRef<'tcx>,
+ mut segment_visitor: impl FnMut(VtblSegment<'tcx>) -> ControlFlow<T>,
+) -> Option<T> {
+ // The following constraints holds for the final arrangement.
+ // 1. The whole virtual table of the first direct super trait is included as the
+ // the prefix. If this trait doesn't have any super traits, then this step
+ // consists of the dsa metadata.
+ // 2. Then comes the proper pointer metadata(vptr) and all own methods for all
+ // other super traits except those already included as part of the first
+ // direct super trait virtual table.
+ // 3. finally, the own methods of this trait.
+
+ // This has the advantage that trait upcasting to the first direct super trait on each level
+ // is zero cost, and to another trait includes only replacing the pointer with one level indirection,
+ // while not using too much extra memory.
+
+ // For a single inheritance relationship like this,
+ // D --> C --> B --> A
+ // The resulting vtable will consists of these segments:
+ // DSA, A, B, C, D
+
+ // For a multiple inheritance relationship like this,
+ // D --> C --> A
+ // \-> B
+ // The resulting vtable will consists of these segments:
+ // DSA, A, B, B-vptr, C, D
+
+ // For a diamond inheritance relationship like this,
+ // D --> B --> A
+ // \-> C -/
+ // The resulting vtable will consists of these segments:
+ // DSA, A, B, C, C-vptr, D
+
+ // For a more complex inheritance relationship like this:
+ // O --> G --> C --> A
+ // \ \ \-> B
+ // | |-> F --> D
+ // | \-> E
+ // |-> N --> J --> H
+ // \ \-> I
+ // |-> M --> K
+ // \-> L
+ // The resulting vtable will consists of these segments:
+ // DSA, A, B, B-vptr, C, D, D-vptr, E, E-vptr, F, F-vptr, G,
+ // H, H-vptr, I, I-vptr, J, J-vptr, K, K-vptr, L, L-vptr, M, M-vptr,
+ // N, N-vptr, O
+
+ // emit dsa segment first.
+ if let ControlFlow::Break(v) = (segment_visitor)(VtblSegment::MetadataDSA) {
+ return Some(v);
+ }
+
+ let mut emit_vptr_on_new_entry = false;
+ let mut visited = util::PredicateSet::new(tcx);
+ let predicate = trait_ref.without_const().to_predicate(tcx);
+ let mut stack: SmallVec<[(ty::PolyTraitRef<'tcx>, _, _); 5]> =
+ smallvec![(trait_ref, emit_vptr_on_new_entry, None)];
+ visited.insert(predicate);
+
+ // the main traversal loop:
+ // basically we want to cut the inheritance directed graph into a few non-overlapping slices of nodes
+ // that each node is emited after all its descendents have been emitted.
+ // so we convert the directed graph into a tree by skipping all previously visted nodes using a visited set.
+ // this is done on the fly.
+ // Each loop run emits a slice - it starts by find a "childless" unvisited node, backtracking upwards, and it
+ // stops after it finds a node that has a next-sibling node.
+ // This next-sibling node will used as the starting point of next slice.
+
+ // Example:
+ // For a diamond inheritance relationship like this,
+ // D#1 --> B#0 --> A#0
+ // \-> C#1 -/
+
+ // Starting point 0 stack [D]
+ // Loop run #0: Stack after diving in is [D B A], A is "childless"
+ // after this point, all newly visited nodes won't have a vtable that equals to a prefix of this one.
+ // Loop run #0: Emiting the slice [B A] (in reverse order), B has a next-sibling node, so this slice stops here.
+ // Loop run #0: Stack after exiting out is [D C], C is the next starting point.
+ // Loop run #1: Stack after diving in is [D C], C is "childless", since its child A is skipped(already emitted).
+ // Loop run #1: Emiting the slice [D C] (in reverse order). No one has a next-sibling node.
+ // Loop run #1: Stack after exiting out is []. Now the function exits.
+
+ loop {
+ // dive deeper into the stack, recording the path
+ 'diving_in: loop {
+ if let Some((inner_most_trait_ref, _, _)) = stack.last() {
+ let inner_most_trait_ref = *inner_most_trait_ref;
+ let mut direct_super_traits_iter = tcx
+ .super_predicates_of(inner_most_trait_ref.def_id())
+ .predicates
+ .into_iter()
+ .filter_map(move |(pred, _)| {
+ pred.subst_supertrait(tcx, &inner_most_trait_ref).to_opt_poly_trait_ref()
+ });
+
+ 'diving_in_skip_visited_traits: loop {
+ if let Some(next_super_trait) = direct_super_traits_iter.next() {
+ if visited.insert(next_super_trait.to_predicate(tcx)) {
+ stack.push((
+ next_super_trait.value,
+ emit_vptr_on_new_entry,
+ Some(direct_super_traits_iter),
+ ));
+ break 'diving_in_skip_visited_traits;
+ } else {
+ continue 'diving_in_skip_visited_traits;
+ }
+ } else {
+ break 'diving_in;
+ }
+ }
+ }
+ }
+
+ // Other than the left-most path, vptr should be emitted for each trait.
+ emit_vptr_on_new_entry = true;
+
+ // emit innermost item, move to next sibling and stop there if possible, otherwise jump to outer level.
+ 'exiting_out: loop {
+ if let Some((inner_most_trait_ref, emit_vptr, siblings_opt)) = stack.last_mut() {
+ if let ControlFlow::Break(v) = (segment_visitor)(VtblSegment::TraitOwnEntries {
+ trait_ref: *inner_most_trait_ref,
+ emit_vptr: *emit_vptr,
+ }) {
+ return Some(v);
+ }
+
+ 'exiting_out_skip_visited_traits: loop {
+ if let Some(siblings) = siblings_opt {
+ if let Some(next_inner_most_trait_ref) = siblings.next() {
+ if visited.insert(next_inner_most_trait_ref.to_predicate(tcx)) {
+ *inner_most_trait_ref = next_inner_most_trait_ref.value;
+ *emit_vptr = emit_vptr_on_new_entry;
+ break 'exiting_out;
+ } else {
+ continue 'exiting_out_skip_visited_traits;
+ }
+ }
+ }
+ stack.pop();
+ continue 'exiting_out;
+ }
+ }
+ // all done
+ return None;
+ }
+ }
+}
+
+fn dump_vtable_entries<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ sp: Span,
+ trait_ref: ty::PolyTraitRef<'tcx>,
+ entries: &[VtblEntry<'tcx>],
+) {
+ let msg = format!("Vtable entries for `{}`: {:#?}", trait_ref, entries);
+ tcx.sess.struct_span_err(sp, &msg).emit();
+}
+
/// Given a trait `trait_ref`, iterates the vtable entries
/// that come from `trait_ref`, including its supertraits.
fn vtable_entries<'tcx>(
@@ -462,57 +633,86 @@
) -> &'tcx [VtblEntry<'tcx>] {
debug!("vtable_entries({:?})", trait_ref);
- let entries = COMMON_VTABLE_ENTRIES.iter().cloned().chain(
- supertraits(tcx, trait_ref).flat_map(move |trait_ref| {
- let trait_methods = tcx
- .associated_items(trait_ref.def_id())
- .in_definition_order()
- .filter(|item| item.kind == ty::AssocKind::Fn);
+ let mut entries = vec![];
- // Now list each method's DefId and InternalSubsts (for within its trait).
- // If the method can never be called from this object, produce `Vacant`.
- trait_methods.map(move |trait_method| {
- debug!("vtable_entries: trait_method={:?}", trait_method);
- let def_id = trait_method.def_id;
+ let vtable_segment_callback = |segment| -> ControlFlow<()> {
+ match segment {
+ VtblSegment::MetadataDSA => {
+ entries.extend(COMMON_VTABLE_ENTRIES);
+ }
+ VtblSegment::TraitOwnEntries { trait_ref, emit_vptr } => {
+ let trait_methods = tcx
+ .associated_items(trait_ref.def_id())
+ .in_definition_order()
+ .filter(|item| item.kind == ty::AssocKind::Fn);
+ // Now list each method's DefId and InternalSubsts (for within its trait).
+ // If the method can never be called from this object, produce `Vacant`.
+ let own_entries = trait_methods.map(move |trait_method| {
+ debug!("vtable_entries: trait_method={:?}", trait_method);
+ let def_id = trait_method.def_id;
- // Some methods cannot be called on an object; skip those.
- if !is_vtable_safe_method(tcx, trait_ref.def_id(), &trait_method) {
- debug!("vtable_entries: not vtable safe");
- return VtblEntry::Vacant;
- }
+ // Some methods cannot be called on an object; skip those.
+ if !is_vtable_safe_method(tcx, trait_ref.def_id(), &trait_method) {
+ debug!("vtable_entries: not vtable safe");
+ return VtblEntry::Vacant;
+ }
- // The method may have some early-bound lifetimes; add regions for those.
- let substs = trait_ref.map_bound(|trait_ref| {
- InternalSubsts::for_item(tcx, def_id, |param, _| match param.kind {
- GenericParamDefKind::Lifetime => tcx.lifetimes.re_erased.into(),
- GenericParamDefKind::Type { .. } | GenericParamDefKind::Const { .. } => {
- trait_ref.substs[param.index as usize]
- }
- })
+ // The method may have some early-bound lifetimes; add regions for those.
+ let substs = trait_ref.map_bound(|trait_ref| {
+ InternalSubsts::for_item(tcx, def_id, |param, _| match param.kind {
+ GenericParamDefKind::Lifetime => tcx.lifetimes.re_erased.into(),
+ GenericParamDefKind::Type { .. }
+ | GenericParamDefKind::Const { .. } => {
+ trait_ref.substs[param.index as usize]
+ }
+ })
+ });
+
+ // The trait type may have higher-ranked lifetimes in it;
+ // erase them if they appear, so that we get the type
+ // at some particular call site.
+ let substs = tcx
+ .normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), substs);
+
+ // It's possible that the method relies on where-clauses that
+ // do not hold for this particular set of type parameters.
+ // Note that this method could then never be called, so we
+ // do not want to try and codegen it, in that case (see #23435).
+ let predicates = tcx.predicates_of(def_id).instantiate_own(tcx, substs);
+ if impossible_predicates(tcx, predicates.predicates) {
+ debug!("vtable_entries: predicates do not hold");
+ return VtblEntry::Vacant;
+ }
+
+ let instance = ty::Instance::resolve_for_vtable(
+ tcx,
+ ty::ParamEnv::reveal_all(),
+ def_id,
+ substs,
+ )
+ .expect("resolution failed during building vtable representation");
+ VtblEntry::Method(instance)
});
- // The trait type may have higher-ranked lifetimes in it;
- // erase them if they appear, so that we get the type
- // at some particular call site.
- let substs =
- tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), substs);
+ entries.extend(own_entries);
- // It's possible that the method relies on where-clauses that
- // do not hold for this particular set of type parameters.
- // Note that this method could then never be called, so we
- // do not want to try and codegen it, in that case (see #23435).
- let predicates = tcx.predicates_of(def_id).instantiate_own(tcx, substs);
- if impossible_predicates(tcx, predicates.predicates) {
- debug!("vtable_entries: predicates do not hold");
- return VtblEntry::Vacant;
+ if emit_vptr {
+ entries.push(VtblEntry::TraitVPtr(trait_ref));
}
+ }
+ }
- VtblEntry::Method(def_id, substs)
- })
- }),
- );
+ ControlFlow::Continue(())
+ };
- tcx.arena.alloc_from_iter(entries)
+ let _ = prepare_vtable_segments(tcx, trait_ref, vtable_segment_callback);
+
+ if tcx.has_attr(trait_ref.def_id(), sym::rustc_dump_vtable) {
+ let sp = tcx.def_span(trait_ref.def_id());
+ dump_vtable_entries(tcx, sp, trait_ref, &entries);
+ }
+
+ tcx.arena.alloc_from_iter(entries.into_iter())
}
/// Find slot base for trait methods within vtable entries of another trait
@@ -525,20 +725,76 @@
) -> usize {
let (trait_to_be_found, trait_owning_vtable) = key;
- let mut supertraits = util::supertraits(tcx, trait_owning_vtable);
+ let vtable_segment_callback = {
+ let mut vtable_base = 0;
- // For each of the non-matching predicates that
- // we pass over, we sum up the set of number of vtable
- // entries, so that we can compute the offset for the selected
- // trait.
- let vtable_base = ty::COMMON_VTABLE_ENTRIES.len()
- + supertraits
- .by_ref()
- .take_while(|t| *t != trait_to_be_found)
- .map(|t| util::count_own_vtable_entries(tcx, t))
- .sum::<usize>();
+ move |segment| {
+ match segment {
+ VtblSegment::MetadataDSA => {
+ vtable_base += COMMON_VTABLE_ENTRIES.len();
+ }
+ VtblSegment::TraitOwnEntries { trait_ref, emit_vptr } => {
+ if trait_ref == trait_to_be_found {
+ return ControlFlow::Break(vtable_base);
+ }
+ vtable_base += util::count_own_vtable_entries(tcx, trait_ref);
+ if emit_vptr {
+ vtable_base += 1;
+ }
+ }
+ }
+ ControlFlow::Continue(())
+ }
+ };
- vtable_base
+ if let Some(vtable_base) =
+ prepare_vtable_segments(tcx, trait_owning_vtable, vtable_segment_callback)
+ {
+ vtable_base
+ } else {
+ bug!("Failed to find info for expected trait in vtable");
+ }
+}
+
+/// Find slot offset for trait vptr within vtable entries of another trait
+pub fn vtable_trait_upcasting_coercion_new_vptr_slot(
+ tcx: TyCtxt<'tcx>,
+ key: (
+ Ty<'tcx>, // trait object type whose trait owning vtable
+ Ty<'tcx>, // trait object for supertrait
+ ),
+) -> Option<usize> {
+ let (source, target) = key;
+ assert!(matches!(&source.kind(), &ty::Dynamic(..)) && !source.needs_infer());
+ assert!(matches!(&target.kind(), &ty::Dynamic(..)) && !target.needs_infer());
+
+ // this has been typecked-before, so diagnostics is not really needed.
+ let unsize_trait_did = tcx.require_lang_item(LangItem::Unsize, None);
+
+ let trait_ref = ty::TraitRef {
+ def_id: unsize_trait_did,
+ substs: tcx.mk_substs_trait(source, &[target.into()]),
+ };
+ let obligation = Obligation::new(
+ ObligationCause::dummy(),
+ ty::ParamEnv::reveal_all(),
+ ty::Binder::dummy(ty::TraitPredicate {
+ trait_ref,
+ constness: ty::BoundConstness::NotConst,
+ }),
+ );
+
+ let implsrc = tcx.infer_ctxt().enter(|infcx| {
+ let mut selcx = SelectionContext::new(&infcx);
+ selcx.select(&obligation).unwrap()
+ });
+
+ let implsrc_traitcasting = match implsrc {
+ Some(ImplSource::TraitUpcasting(data)) => data,
+ _ => bug!(),
+ };
+
+ implsrc_traitcasting.vtable_vptr_slot
}
pub fn provide(providers: &mut ty::query::Providers) {
@@ -549,6 +805,7 @@
specializes: specialize::specializes,
codegen_fulfill_obligation: codegen::codegen_fulfill_obligation,
vtable_entries,
+ vtable_trait_upcasting_coercion_new_vptr_slot,
subst_and_check_impossible_predicates,
mir_abstract_const: |tcx, def_id| {
let def_id = def_id.expect_local();
diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs
index 7ebef7f..57b8a84 100644
--- a/compiler/rustc_trait_selection/src/traits/object_safety.rs
+++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs
@@ -278,9 +278,9 @@
(predicate, sp): (ty::Predicate<'tcx>, Span),
) -> Option<Span> {
let self_ty = tcx.types.self_param;
- let has_self_ty = |arg: &GenericArg<'_>| arg.walk().any(|arg| arg == self_ty.into());
+ let has_self_ty = |arg: &GenericArg<'tcx>| arg.walk(tcx).any(|arg| arg == self_ty.into());
match predicate.kind().skip_binder() {
- ty::PredicateKind::Trait(ref data, _) => {
+ 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 }
}
@@ -308,6 +308,7 @@
| ty::PredicateKind::RegionOutlives(..)
| ty::PredicateKind::ClosureKind(..)
| ty::PredicateKind::Subtype(..)
+ | ty::PredicateKind::Coerce(..)
| ty::PredicateKind::ConstEvaluatable(..)
| ty::PredicateKind::ConstEquate(..)
| ty::PredicateKind::TypeWellFormedFromEnv(..) => None,
@@ -331,11 +332,12 @@
let predicates = predicates.instantiate_identity(tcx).predicates;
elaborate_predicates(tcx, predicates.into_iter()).any(|obligation| {
match obligation.predicate.kind().skip_binder() {
- ty::PredicateKind::Trait(ref trait_pred, _) => {
+ ty::PredicateKind::Trait(ref trait_pred) => {
trait_pred.def_id() == sized_def_id && trait_pred.self_ty().is_param(0)
}
ty::PredicateKind::Projection(..)
| ty::PredicateKind::Subtype(..)
+ | ty::PredicateKind::Coerce(..)
| ty::PredicateKind::RegionOutlives(..)
| ty::PredicateKind::WellFormed(..)
| ty::PredicateKind::ObjectSafe(..)
@@ -769,6 +771,9 @@
impl<'tcx> TypeVisitor<'tcx> for IllegalSelfTypeVisitor<'tcx> {
type BreakTy = ();
+ fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
+ Some(self.tcx)
+ }
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
match t.kind() {
@@ -815,10 +820,10 @@
}
}
- fn visit_const(&mut self, ct: &ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
- // First check if the type of this constant references `Self`.
- self.visit_ty(ct.ty)?;
-
+ fn visit_unevaluated_const(
+ &mut self,
+ uv: ty::Unevaluated<'tcx>,
+ ) -> ControlFlow<Self::BreakTy> {
// Constants can only influence object safety if they reference `Self`.
// This is only possible for unevaluated constants, so we walk these here.
//
@@ -832,7 +837,7 @@
// This shouldn't really matter though as we can't really use any
// 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) {
+ if let Ok(Some(ct)) = AbstractConst::new(self.tcx, uv.shrink()) {
const_evaluatable::walk_abstract_const(self.tcx, ct, |node| match node.root() {
Node::Leaf(leaf) => {
let leaf = leaf.subst(self.tcx, ct.substs);
@@ -847,31 +852,6 @@
ControlFlow::CONTINUE
}
}
-
- fn visit_predicate(&mut self, pred: ty::Predicate<'tcx>) -> ControlFlow<Self::BreakTy> {
- 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.root() {
- Node::Leaf(leaf) => {
- let leaf = leaf.subst(self.tcx, ct.substs);
- self.visit_const(leaf)
- }
- Node::Cast(_, _, ty) => self.visit_ty(ty),
- Node::Binop(..) | Node::UnaryOp(..) | Node::FunctionCall(_, _) => {
- ControlFlow::CONTINUE
- }
- })
- } else {
- ControlFlow::CONTINUE
- }
- } else {
- pred.super_visit_with(self)
- }
- }
}
value
diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs
index d1ab9fa..42c5afb 100644
--- a/compiler/rustc_trait_selection/src/traits/project.rs
+++ b/compiler/rustc_trait_selection/src/traits/project.rs
@@ -10,6 +10,7 @@
use super::Selection;
use super::SelectionContext;
use super::SelectionError;
+use super::TraitQueryMode;
use super::{
ImplSourceClosureData, ImplSourceDiscriminantKindData, ImplSourceFnPointerData,
ImplSourceGeneratorData, ImplSourcePointeeData, ImplSourceUserDefinedData,
@@ -18,7 +19,7 @@
use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use crate::infer::{InferCtxt, InferOk, LateBoundRegionConversionTime};
-use crate::traits::error_reporting::InferCtxtExt;
+use crate::traits::error_reporting::InferCtxtExt as _;
use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_errors::ErrorReported;
use rustc_hir::def_id::DefId;
@@ -62,7 +63,7 @@
/// Bounds specified on an object type
Object(ty::PolyProjectionPredicate<'tcx>),
- /// From a "impl" (or a "pseudo-impl" returned by select)
+ /// From an "impl" (or a "pseudo-impl" returned by select)
Select(Selection<'tcx>),
}
@@ -362,23 +363,38 @@
if !needs_normalization(&ty, self.param_env.reveal()) {
return ty;
}
- // We don't want to normalize associated types that occur inside of region
- // binders, because they may contain bound regions, and we can't cope with that.
- //
- // Example:
- //
- // for<'a> fn(<T as Foo<&'a>>::A)
- //
- // Instead of normalizing `<T as Foo<&'a>>::A` here, we'll
- // normalize it when we instantiate those bound regions (which
- // should occur eventually).
- let ty = ty.super_fold_with(self);
+ // We try to be a little clever here as a performance optimization in
+ // cases where there are nested projections under binders.
+ // For example:
+ // ```
+ // for<'a> fn(<T as Foo>::One<'a, Box<dyn Bar<'a, Item=<T as Foo>::Two<'a>>>>)
+ // ```
+ // We normalize the substs on the projection before the projecting, but
+ // if we're naive, we'll
+ // replace bound vars on inner, project inner, replace placeholders on inner,
+ // replace bound vars on outer, project outer, replace placeholders on outer
+ //
+ // However, if we're a bit more clever, we can replace the bound vars
+ // on the entire type before normalizing nested projections, meaning we
+ // replace bound vars on outer, project inner,
+ // project outer, replace placeholders on outer
+ //
+ // This is possible because the inner `'a` will already be a placeholder
+ // when we need to normalize the inner projection
+ //
+ // On the other hand, this does add a bit of complexity, since we only
+ // replace bound vars if the current type is a `Projection` and we need
+ // to make sure we don't forget to fold the substs regardless.
+
match *ty.kind() {
+ // This is really important. While we *can* handle this, this has
+ // severe performance implications for large opaque types with
+ // late-bound regions. See `issue-88862` benchmark.
ty::Opaque(def_id, substs) if !substs.has_escaping_bound_vars() => {
// Only normalize `impl Trait` after type-checking, usually in codegen.
match self.param_env.reveal() {
- Reveal::UserFacing => ty,
+ Reveal::UserFacing => ty.super_fold_with(self),
Reveal::All => {
let recursion_limit = self.tcx().recursion_limit();
@@ -392,6 +408,7 @@
self.selcx.infcx().report_overflow_error(&obligation, true);
}
+ let substs = substs.super_fold_with(self);
let generic_ty = self.tcx().type_of(def_id);
let concrete_ty = generic_ty.subst(self.tcx(), substs);
self.depth += 1;
@@ -403,18 +420,13 @@
}
ty::Projection(data) if !data.has_escaping_bound_vars() => {
- // This is kind of hacky -- we need to be able to
- // handle normalization within binders because
- // otherwise we wind up a need to normalize when doing
- // trait matching (since you can have a trait
- // obligation like `for<'a> T::B: Fn(&'a i32)`), but
- // we can't normalize with bound regions in scope. So
- // far now we just ignore binders but only normalize
- // if all bound regions are gone (and then we still
- // have to renormalize whenever we instantiate a
- // binder). It would be better to normalize in a
- // binding-aware fashion.
+ // This branch is *mostly* just an optimization: when we don't
+ // have escaping bound vars, we don't need to replace them with
+ // placeholders (see branch below). *Also*, we know that we can
+ // register an obligation to *later* project, since we know
+ // there won't be bound vars there.
+ let data = data.super_fold_with(self);
let normalized_ty = normalize_projection_type(
self.selcx,
self.param_env,
@@ -433,22 +445,23 @@
normalized_ty
}
- ty::Projection(data) if !data.trait_ref(self.tcx()).has_escaping_bound_vars() => {
- // Okay, so you thought the previous branch was hacky. Well, to
- // extend upon this, when the *trait ref* doesn't have escaping
- // bound vars, but the associated item *does* (can only occur
- // with GATs), then we might still be able to project the type.
- // For this, we temporarily replace the bound vars with
- // placeholders. Note though, that in the case that we still
- // can't project for whatever reason (e.g. self type isn't
- // known enough), we *can't* register an obligation and return
- // an inference variable (since then that obligation would have
- // bound vars and that's a can of worms). Instead, we just
- // give up and fall back to pretending like we never tried!
+ ty::Projection(data) => {
+ // If there are escaping bound vars, we temporarily replace the
+ // bound vars with placeholders. Note though, that in the case
+ // that we still can't project for whatever reason (e.g. self
+ // type isn't known enough), we *can't* register an obligation
+ // and return an inference variable (since then that obligation
+ // would have bound vars and that's a can of worms). Instead,
+ // we just give up and fall back to pretending like we never tried!
+ //
+ // Note: this isn't necessarily the final approach here; we may
+ // want to figure out how to register obligations with escaping vars
+ // or handle this some other way.
let infcx = self.selcx.infcx();
let (data, mapped_regions, mapped_types, mapped_consts) =
BoundVarReplacer::replace_bound_vars(infcx, &mut self.universes, data);
+ let data = data.super_fold_with(self);
let normalized_ty = opt_normalize_projection_type(
self.selcx,
self.param_env,
@@ -459,16 +472,18 @@
)
.ok()
.flatten()
- .unwrap_or_else(|| ty);
+ .map(|normalized_ty| {
+ PlaceholderReplacer::replace_placeholders(
+ infcx,
+ mapped_regions,
+ mapped_types,
+ mapped_consts,
+ &self.universes,
+ normalized_ty,
+ )
+ })
+ .unwrap_or_else(|| ty.super_fold_with(self));
- let normalized_ty = PlaceholderReplacer::replace_placeholders(
- infcx,
- mapped_regions,
- mapped_types,
- mapped_consts,
- &self.universes,
- normalized_ty,
- );
debug!(
?self.depth,
?ty,
@@ -479,7 +494,7 @@
normalized_ty
}
- _ => ty,
+ _ => ty.super_fold_with(self),
}
}
@@ -829,6 +844,10 @@
obligations: &mut Vec<PredicateObligation<'tcx>>,
) -> Result<Option<Ty<'tcx>>, InProgress> {
let infcx = selcx.infcx();
+ // Don't use the projection cache in intercrate mode -
+ // the `infcx` may be re-used between intercrate in non-intercrate
+ // mode, which could lead to using incorrect cache results.
+ let use_cache = !selcx.is_intercrate();
let projection_ty = infcx.resolve_vars_if_possible(projection_ty);
let cache_key = ProjectionCacheKey::new(projection_ty);
@@ -841,7 +860,11 @@
// bounds. It might be the case that we want two distinct caches,
// or else another kind of cache entry.
- let cache_result = infcx.inner.borrow_mut().projection_cache().try_start(cache_key);
+ let cache_result = if use_cache {
+ infcx.inner.borrow_mut().projection_cache().try_start(cache_key)
+ } else {
+ Ok(())
+ };
match cache_result {
Ok(()) => debug!("no cache"),
Err(ProjectionCacheEntry::Ambiguous) => {
@@ -866,7 +889,9 @@
// should ensure that, unless this happens within a snapshot that's
// rolled back, fulfillment or evaluation will notice the cycle.
- infcx.inner.borrow_mut().projection_cache().recur(cache_key);
+ if use_cache {
+ infcx.inner.borrow_mut().projection_cache().recur(cache_key);
+ }
return Err(InProgress);
}
Err(ProjectionCacheEntry::Recur) => {
@@ -898,6 +923,7 @@
}
let obligation = Obligation::with_depth(cause.clone(), depth, param_env, projection_ty);
+
match project_type(selcx, &obligation) {
Ok(ProjectedTy::Progress(Progress {
ty: projected_ty,
@@ -908,9 +934,10 @@
// an impl, where-clause etc) and hence we must
// re-normalize it
+ let projected_ty = selcx.infcx().resolve_vars_if_possible(projected_ty);
debug!(?projected_ty, ?depth, ?projected_obligations);
- let result = if projected_ty.has_projections() {
+ let mut result = if projected_ty.has_projections() {
let mut normalizer = AssocTypeNormalizer::new(
selcx,
param_env,
@@ -927,21 +954,45 @@
Normalized { value: projected_ty, obligations: projected_obligations }
};
- let cache_value = prune_cache_value_obligations(infcx, &result);
- infcx.inner.borrow_mut().projection_cache().insert_ty(cache_key, cache_value);
+ let mut canonical =
+ SelectionContext::with_query_mode(selcx.infcx(), TraitQueryMode::Canonical);
+ result.obligations.drain_filter(|projected_obligation| {
+ // If any global obligations always apply, considering regions, then we don't
+ // need to include them. The `is_global` check rules out inference variables,
+ // so there's no need for the caller of `opt_normalize_projection_type`
+ // to evaluate them.
+ // Note that we do *not* discard obligations that evaluate to
+ // `EvaluatedtoOkModuloRegions`. Evaluating these obligations
+ // inside of a query (e.g. `evaluate_obligation`) can change
+ // the result to `EvaluatedToOkModuloRegions`, while an
+ // `EvaluatedToOk` obligation will never change the result.
+ // See #85360 for more details
+ projected_obligation.is_global(canonical.tcx())
+ && canonical
+ .evaluate_root_obligation(projected_obligation)
+ .map_or(false, |res| res.must_apply_considering_regions())
+ });
+
+ if use_cache {
+ infcx.inner.borrow_mut().projection_cache().insert_ty(cache_key, result.clone());
+ }
obligations.extend(result.obligations);
Ok(Some(result.value))
}
Ok(ProjectedTy::NoProgress(projected_ty)) => {
debug!(?projected_ty, "opt_normalize_projection_type: no progress");
let result = Normalized { value: projected_ty, obligations: vec![] };
- infcx.inner.borrow_mut().projection_cache().insert_ty(cache_key, result.clone());
+ if use_cache {
+ infcx.inner.borrow_mut().projection_cache().insert_ty(cache_key, result.clone());
+ }
// No need to extend `obligations`.
Ok(Some(result.value))
}
Err(ProjectionTyError::TooManyCandidates) => {
debug!("opt_normalize_projection_type: too many candidates");
- infcx.inner.borrow_mut().projection_cache().ambiguous(cache_key);
+ if use_cache {
+ infcx.inner.borrow_mut().projection_cache().ambiguous(cache_key);
+ }
Ok(None)
}
Err(ProjectionTyError::TraitSelectionError(_)) => {
@@ -951,7 +1002,9 @@
// Trait`, which when processed will cause the error to be
// reported later
- infcx.inner.borrow_mut().projection_cache().error(cache_key);
+ if use_cache {
+ infcx.inner.borrow_mut().projection_cache().error(cache_key);
+ }
let result = normalize_to_error(selcx, param_env, projection_ty, cause, depth);
obligations.extend(result.obligations);
Ok(Some(result.value))
@@ -959,49 +1012,6 @@
}
}
-/// If there are unresolved type variables, then we need to include
-/// any subobligations that bind them, at least until those type
-/// variables are fully resolved.
-fn prune_cache_value_obligations<'a, 'tcx>(
- infcx: &'a InferCtxt<'a, 'tcx>,
- result: &NormalizedTy<'tcx>,
-) -> NormalizedTy<'tcx> {
- if infcx.unresolved_type_vars(&result.value).is_none() {
- return NormalizedTy { value: result.value, obligations: vec![] };
- }
-
- let mut obligations: Vec<_> = result
- .obligations
- .iter()
- .filter(|obligation| {
- 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
- // variables. In principle, we only care if this
- // projection can help resolve any of the type
- // variables found in `result.value` -- but we just
- // check for any type variables here, for fear of
- // indirect obligations (e.g., we project to `?0`,
- // but we have `T: Foo<X = ?1>` and `?1: Bar<X =
- // ?0>`).
- ty::PredicateKind::Projection(data) => {
- infcx.unresolved_type_vars(&bound_predicate.rebind(data.ty)).is_some()
- }
-
- // We are only interested in `T: Foo<X = U>` predicates, whre
- // `U` references one of `unresolved_type_vars`. =)
- _ => false,
- }
- })
- .cloned()
- .collect();
-
- obligations.shrink_to_fit();
-
- NormalizedTy { value: result.value, obligations }
-}
-
/// If we are projecting `<T as Trait>::Item`, but `T: Trait` does not
/// hold. In various error cases, we cannot generate a valid
/// normalized projection. Therefore, we create an inference variable
@@ -1011,7 +1021,7 @@
/// Note that we used to return `Error` here, but that was quite
/// dubious -- the premise was that an error would *eventually* be
/// reported, when the obligation was processed. But in general once
-/// you see a `Error` you are supposed to be able to assume that an
+/// you see an `Error` you are supposed to be able to assume that an
/// error *has been* reported, so that you can take whatever heuristic
/// paths you want to take. To make things worse, it was possible for
/// cycles to arise, where you basically had a setup like `<MyType<$0>
@@ -1483,7 +1493,9 @@
// why we special case object types.
false
}
- super::ImplSource::AutoImpl(..) | super::ImplSource::Builtin(..) => {
+ super::ImplSource::AutoImpl(..)
+ | super::ImplSource::Builtin(..)
+ | super::ImplSource::TraitUpcasting(_) => {
// These traits have no associated types.
selcx.tcx().sess.delay_span_bug(
obligation.cause.span,
@@ -1554,6 +1566,7 @@
| super::ImplSource::AutoImpl(..)
| super::ImplSource::Param(..)
| super::ImplSource::Builtin(..)
+ | super::ImplSource::TraitUpcasting(_)
| super::ImplSource::TraitAlias(..) => {
// we don't create Select candidates with this kind of resolution
span_bug!(
diff --git a/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs b/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs
index 2dc48e4..032d402 100644
--- a/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs
@@ -71,7 +71,7 @@
// Run canonical query. If overflow occurs, rerun from scratch but this time
// in standard trait query mode so that overflow is handled appropriately
// within `SelectionContext`.
- self.tcx.evaluate_obligation(c_pred)
+ self.tcx.at(obligation.cause.span(self.tcx)).evaluate_obligation(c_pred)
}
// Helper function that canonicalizes and runs the query. If an
diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs
index 3f6efa0..1364cf1 100644
--- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs
@@ -14,7 +14,9 @@
use rustc_middle::mir;
use rustc_middle::ty::fold::{TypeFoldable, TypeFolder};
use rustc_middle::ty::subst::Subst;
-use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitor};
+
+use std::ops::ControlFlow;
use super::NoSolution;
@@ -65,6 +67,27 @@
universes: vec![],
};
+ // This is actually a consequence by the way `normalize_erasing_regions` works currently.
+ // Because it needs to call the `normalize_generic_arg_after_erasing_regions`, it folds
+ // through tys and consts in a `TypeFoldable`. Importantly, it skips binders, leaving us
+ // with trying to normalize with escaping bound vars.
+ //
+ // Here, we just add the universes that we *would* have created had we passed through the binders.
+ //
+ // We *could* replace escaping bound vars eagerly here, but it doesn't seem really necessary.
+ // The rest of the code is already set up to be lazy about replacing bound vars,
+ // and only when we actually have to normalize.
+ if value.has_escaping_bound_vars() {
+ let mut max_visitor = MaxEscapingBoundVarVisitor {
+ tcx: self.infcx.tcx,
+ outer_index: ty::INNERMOST,
+ escaping: 0,
+ };
+ value.visit_with(&mut max_visitor);
+ if max_visitor.escaping > 0 {
+ normalizer.universes.extend((0..max_visitor.escaping).map(|_| None));
+ }
+ }
let result = value.fold_with(&mut normalizer);
info!(
"normalize::<{}>: result={:?} with {} obligations",
@@ -85,6 +108,63 @@
}
}
+/// Visitor to find the maximum escaping bound var
+struct MaxEscapingBoundVarVisitor<'tcx> {
+ tcx: TyCtxt<'tcx>,
+ // The index which would count as escaping
+ outer_index: ty::DebruijnIndex,
+ escaping: usize,
+}
+
+impl<'tcx> TypeVisitor<'tcx> for MaxEscapingBoundVarVisitor<'tcx> {
+ fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
+ Some(self.tcx)
+ }
+
+ fn visit_binder<T: TypeFoldable<'tcx>>(
+ &mut self,
+ t: &ty::Binder<'tcx, T>,
+ ) -> ControlFlow<Self::BreakTy> {
+ self.outer_index.shift_in(1);
+ let result = t.super_visit_with(self);
+ self.outer_index.shift_out(1);
+ result
+ }
+
+ #[inline]
+ fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
+ if t.outer_exclusive_binder() > self.outer_index {
+ self.escaping = self
+ .escaping
+ .max(t.outer_exclusive_binder().as_usize() - self.outer_index.as_usize());
+ }
+ ControlFlow::CONTINUE
+ }
+
+ #[inline]
+ fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
+ match *r {
+ ty::ReLateBound(debruijn, _) if debruijn > self.outer_index => {
+ self.escaping =
+ self.escaping.max(debruijn.as_usize() - self.outer_index.as_usize());
+ }
+ _ => {}
+ }
+ ControlFlow::CONTINUE
+ }
+
+ fn visit_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
+ match ct.val {
+ ty::ConstKind::Bound(debruijn, _) if debruijn >= self.outer_index => {
+ self.escaping =
+ self.escaping.max(debruijn.as_usize() - self.outer_index.as_usize());
+ ControlFlow::CONTINUE
+ }
+ _ => ct.super_visit_with(self),
+ }
+ }
+}
+
struct QueryNormalizer<'cx, 'tcx> {
infcx: &'cx InferCtxt<'cx, 'tcx>,
cause: &'cx ObligationCause<'tcx>,
@@ -121,14 +201,21 @@
return ty;
}
- let ty = ty.super_fold_with(self);
+ // See note in `rustc_trait_selection::traits::project` about why we
+ // wait to fold the substs.
+
+ // Wrap this in a closure so we don't accidentally return from the outer function
let res = (|| match *ty.kind() {
+ // This is really important. While we *can* handle this, this has
+ // severe performance implications for large opaque types with
+ // late-bound regions. See `issue-88862` benchmark.
ty::Opaque(def_id, substs) if !substs.has_escaping_bound_vars() => {
// Only normalize `impl Trait` after type-checking, usually in codegen.
match self.param_env.reveal() {
- Reveal::UserFacing => ty,
+ Reveal::UserFacing => ty.super_fold_with(self),
Reveal::All => {
+ let substs = substs.super_fold_with(self);
let recursion_limit = self.tcx().recursion_limit();
if !recursion_limit.value_within_limit(self.anon_depth) {
let obligation = Obligation::with_depth(
@@ -161,19 +248,11 @@
}
ty::Projection(data) if !data.has_escaping_bound_vars() => {
- // This is kind of hacky -- we need to be able to
- // handle normalization within binders because
- // otherwise we wind up a need to normalize when doing
- // trait matching (since you can have a trait
- // obligation like `for<'a> T::B: Fn(&'a i32)`), but
- // we can't normalize with bound regions in scope. So
- // far now we just ignore binders but only normalize
- // if all bound regions are gone (and then we still
- // have to renormalize whenever we instantiate a
- // binder). It would be better to normalize in a
- // binding-aware fashion.
+ // This branch is just an optimization: when we don't have escaping bound vars,
+ // we don't need to replace them with placeholders (see branch below).
let tcx = self.infcx.tcx;
+ let data = data.super_fold_with(self);
let mut orig_values = OriginalQueryValues::default();
// HACK(matthewjasper) `'static` is special-cased in selection,
@@ -188,7 +267,7 @@
// We don't expect ambiguity.
if result.is_ambiguous() {
self.error = true;
- return ty;
+ return ty.super_fold_with(self);
}
match self.infcx.instantiate_query_response_and_region_obligations(
@@ -206,34 +285,21 @@
Err(_) => {
self.error = true;
- ty
+ ty.super_fold_with(self)
}
}
}
Err(NoSolution) => {
self.error = true;
- ty
+ ty.super_fold_with(self)
}
}
}
- ty::Projection(data) if !data.trait_ref(self.infcx.tcx).has_escaping_bound_vars() => {
+
+ ty::Projection(data) => {
// See note in `rustc_trait_selection::traits::project`
- // One other point mentioning: In `traits::project`, if a
- // projection can't be normalized, we return an inference variable
- // and register an obligation to later resolve that. Here, the query
- // will just return ambiguity. In both cases, the effect is the same: we only want
- // to return `ty` because there are bound vars that we aren't yet handling in a more
- // complete way.
-
- // `BoundVarReplacer` can't handle escaping bound vars. Ideally, we want this before even calling
- // `QueryNormalizer`, but some const-generics tests pass escaping bound vars.
- // Also, use `ty` so we get that sweet `outer_exclusive_binder` optimization
- assert!(!ty.has_vars_bound_at_or_above(ty::DebruijnIndex::from_usize(
- self.universes.len()
- )));
-
let tcx = self.infcx.tcx;
let infcx = self.infcx;
let (data, mapped_regions, mapped_types, mapped_consts) =
@@ -252,12 +318,12 @@
.canonicalize_query_keep_static(self.param_env.and(data), &mut orig_values);
debug!("QueryNormalizer: c_data = {:#?}", c_data);
debug!("QueryNormalizer: orig_values = {:#?}", orig_values);
- let normalized_ty = match tcx.normalize_projection_ty(c_data) {
+ match tcx.normalize_projection_ty(c_data) {
Ok(result) => {
// We don't expect ambiguity.
if result.is_ambiguous() {
self.error = true;
- return ty;
+ return ty.super_fold_with(self);
}
match self.infcx.instantiate_query_response_and_region_obligations(
self.cause,
@@ -269,30 +335,29 @@
debug!("QueryNormalizer: result = {:#?}", result);
debug!("QueryNormalizer: obligations = {:#?}", obligations);
self.obligations.extend(obligations);
- result.normalized_ty
+ crate::traits::project::PlaceholderReplacer::replace_placeholders(
+ infcx,
+ mapped_regions,
+ mapped_types,
+ mapped_consts,
+ &self.universes,
+ result.normalized_ty,
+ )
}
Err(_) => {
self.error = true;
- ty
+ ty.super_fold_with(self)
}
}
}
Err(NoSolution) => {
self.error = true;
- ty
+ ty.super_fold_with(self)
}
- };
- crate::traits::project::PlaceholderReplacer::replace_placeholders(
- infcx,
- mapped_regions,
- mapped_types,
- mapped_consts,
- &self.universes,
- normalized_ty,
- )
+ }
}
- _ => ty,
+ _ => ty.super_fold_with(self),
})();
self.cache.insert(ty, res);
res
diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs
index 4f5476c..b5398f8 100644
--- a/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs
@@ -1,13 +1,13 @@
-use crate::infer::{InferCtxt, InferOk};
-use crate::traits::query::Fallible;
-use std::fmt;
-
use crate::infer::canonical::query_response;
-use crate::infer::canonical::QueryRegionConstraints;
+use crate::infer::{InferCtxt, InferOk};
use crate::traits::engine::TraitEngineExt as _;
+use crate::traits::query::type_op::TypeOpOutput;
+use crate::traits::query::Fallible;
use crate::traits::{ObligationCause, TraitEngine};
use rustc_infer::traits::TraitEngineExt as _;
use rustc_span::source_map::DUMMY_SP;
+
+use std::fmt;
use std::rc::Rc;
pub struct CustomTypeOp<F, G> {
@@ -35,10 +35,7 @@
/// Processes the operation and all resulting obligations,
/// returning the final result along with any region constraints
/// (they will be given over to the NLL region solver).
- fn fully_perform(
- self,
- infcx: &InferCtxt<'_, 'tcx>,
- ) -> Fallible<(Self::Output, Option<Rc<QueryRegionConstraints<'tcx>>>)> {
+ fn fully_perform(self, infcx: &InferCtxt<'_, 'tcx>) -> Fallible<TypeOpOutput<'tcx, Self>> {
if cfg!(debug_assertions) {
info!("fully_perform({:?})", self);
}
@@ -58,10 +55,10 @@
/// Executes `op` and then scrapes out all the "old style" region
/// constraints that result, creating query-region-constraints.
-fn scrape_region_constraints<'tcx, R>(
+fn scrape_region_constraints<'tcx, Op: super::TypeOp<'tcx, Output = R>, R>(
infcx: &InferCtxt<'_, 'tcx>,
op: impl FnOnce() -> Fallible<InferOk<'tcx, R>>,
-) -> Fallible<(R, Option<Rc<QueryRegionConstraints<'tcx>>>)> {
+) -> Fallible<TypeOpOutput<'tcx, Op>> {
let mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx);
let dummy_body_id = ObligationCause::dummy().body_id;
@@ -101,8 +98,12 @@
);
if region_constraints.is_empty() {
- Ok((value, None))
+ Ok(TypeOpOutput { output: value, constraints: None, canonicalized_query: None })
} else {
- Ok((value, Some(Rc::new(region_constraints))))
+ Ok(TypeOpOutput {
+ output: value,
+ constraints: Some(Rc::new(region_constraints)),
+ canonicalized_query: None,
+ })
}
}
diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs
index b351af4..03087e3 100644
--- a/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs
@@ -3,7 +3,7 @@
use crate::traits::query::Fallible;
use rustc_middle::ty::{ParamEnvAnd, Ty, TyCtxt};
-#[derive(Clone, Debug, HashStable, TypeFoldable, Lift)]
+#[derive(Copy, Clone, Debug, HashStable, TypeFoldable, Lift)]
pub struct ImpliedOutlivesBounds<'tcx> {
pub ty: Ty<'tcx>,
}
@@ -24,7 +24,7 @@
) -> Fallible<CanonicalizedQueryResponse<'tcx, Self::QueryResponse>> {
// FIXME this `unchecked_map` is only necessary because the
// query is defined as taking a `ParamEnvAnd<Ty>`; it should
- // take a `ImpliedOutlivesBounds` instead
+ // take an `ImpliedOutlivesBounds` instead
let canonicalized = canonicalized.unchecked_map(|ParamEnvAnd { param_env, value }| {
let ImpliedOutlivesBounds { ty } = value;
param_env.and(ty)
diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs
index fbff866..12ca3fa 100644
--- a/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs
@@ -4,6 +4,7 @@
use crate::infer::{InferCtxt, InferOk};
use crate::traits::query::Fallible;
use crate::traits::ObligationCause;
+use rustc_infer::infer::canonical::Canonical;
use rustc_middle::ty::fold::TypeFoldable;
use rustc_middle::ty::{ParamEnvAnd, TyCtxt};
use std::fmt;
@@ -30,10 +31,18 @@
/// Processes the operation and all resulting obligations,
/// returning the final result along with any region constraints
/// (they will be given over to the NLL region solver).
- fn fully_perform(
- self,
- infcx: &InferCtxt<'_, 'tcx>,
- ) -> Fallible<(Self::Output, Option<Rc<QueryRegionConstraints<'tcx>>>)>;
+ fn fully_perform(self, infcx: &InferCtxt<'_, 'tcx>) -> Fallible<TypeOpOutput<'tcx, Self>>;
+}
+
+/// The output from performing a type op
+pub struct TypeOpOutput<'tcx, Op: TypeOp<'tcx>> {
+ /// The output from the type op.
+ pub output: Op::Output,
+ /// Any region constraints from performing the type op.
+ pub constraints: Option<Rc<QueryRegionConstraints<'tcx>>>,
+ /// The canonicalized form of the query.
+ /// This for error reporting to be able to rerun the query.
+ pub canonicalized_query: Option<Canonical<'tcx, Op>>,
}
/// "Query type ops" are type ops that are implemented using a
@@ -45,7 +54,7 @@
/// which produces the resulting query region constraints.
///
/// [c]: https://rust-lang.github.io/chalk/book/canonical_queries/canonicalization.html
-pub trait QueryTypeOp<'tcx>: fmt::Debug + Sized + TypeFoldable<'tcx> + 'tcx {
+pub trait QueryTypeOp<'tcx>: fmt::Debug + Copy + TypeFoldable<'tcx> + 'tcx {
type QueryResponse: TypeFoldable<'tcx>;
/// Give query the option for a simple fast path that never
@@ -71,9 +80,9 @@
query_key: ParamEnvAnd<'tcx, Self>,
infcx: &InferCtxt<'_, 'tcx>,
output_query_region_constraints: &mut QueryRegionConstraints<'tcx>,
- ) -> Fallible<Self::QueryResponse> {
+ ) -> Fallible<(Self::QueryResponse, Option<Canonical<'tcx, ParamEnvAnd<'tcx, Self>>>)> {
if let Some(result) = QueryTypeOp::try_fast_path(infcx.tcx, &query_key) {
- return Ok(result);
+ return Ok((result, None));
}
// FIXME(#33684) -- We need to use
@@ -101,14 +110,14 @@
// create obligations. In that case, we have to go
// fulfill them. We do this via a (recursive) query.
for obligation in obligations {
- let () = ProvePredicate::fully_perform_into(
+ let ((), _) = ProvePredicate::fully_perform_into(
obligation.param_env.and(ProvePredicate::new(obligation.predicate)),
infcx,
output_query_region_constraints,
)?;
}
- Ok(value)
+ Ok((value, Some(canonical_self)))
}
}
@@ -118,18 +127,16 @@
{
type Output = Q::QueryResponse;
- fn fully_perform(
- self,
- infcx: &InferCtxt<'_, 'tcx>,
- ) -> Fallible<(Self::Output, Option<Rc<QueryRegionConstraints<'tcx>>>)> {
+ fn fully_perform(self, infcx: &InferCtxt<'_, 'tcx>) -> Fallible<TypeOpOutput<'tcx, Self>> {
let mut region_constraints = QueryRegionConstraints::default();
- let r = Q::fully_perform_into(self, infcx, &mut region_constraints)?;
+ let (output, canonicalized_query) =
+ Q::fully_perform_into(self, infcx, &mut region_constraints)?;
// Promote the final query-region-constraints into a
// (optional) ref-counted vector:
- let opt_qrc =
+ let region_constraints =
if region_constraints.is_empty() { None } else { Some(Rc::new(region_constraints)) };
- Ok((r, opt_qrc))
+ Ok(TypeOpOutput { output, constraints: region_constraints, canonicalized_query })
}
}
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 de538c6..02e9b4d 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::PredicateKind::Trait(trait_ref, _) = key.value.predicate.kind().skip_binder() {
+ 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 752f6a8..e18828f 100644
--- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
@@ -144,7 +144,7 @@
// Instead, we select the right impl now but report "`Bar` does
// not implement `Clone`".
if candidates.len() == 1 {
- return self.filter_negative_and_reservation_impls(candidates.pop().unwrap());
+ return self.filter_impls(candidates.pop().unwrap(), stack.obligation);
}
// Winnow, but record the exact outcome of evaluation, which
@@ -217,7 +217,7 @@
}
// Just one candidate left.
- self.filter_negative_and_reservation_impls(candidates.pop().unwrap().candidate)
+ self.filter_impls(candidates.pop().unwrap().candidate, stack.obligation)
}
pub(super) fn assemble_candidates<'o>(
@@ -690,29 +690,50 @@
debug!(?source, ?target, "assemble_candidates_for_unsizing");
- let may_apply = match (source.kind(), target.kind()) {
+ match (source.kind(), target.kind()) {
// Trait+Kx+'a -> Trait+Ky+'b (upcasts).
(&ty::Dynamic(ref data_a, ..), &ty::Dynamic(ref data_b, ..)) => {
- // Upcasts permit two things:
+ // Upcast coercions permit several things:
//
// 1. Dropping auto traits, e.g., `Foo + Send` to `Foo`
// 2. Tightening the region bound, e.g., `Foo + 'a` to `Foo + 'b` if `'a: 'b`
+ // 3. Tightening trait to its super traits, eg. `Foo` to `Bar` if `Foo: Bar`
//
- // Note that neither of these changes requires any
- // change at runtime. Eventually this will be
- // generalized.
+ // Note that neither of the first two of these changes requires any
+ // change at runtime. The third needs to change pointer metadata at runtime.
//
- // We always upcast when we can because of reason
+ // We always perform upcasting coercions when we can because of reason
// #2 (region bounds).
- data_a.principal_def_id() == data_b.principal_def_id()
- && data_b
- .auto_traits()
- // All of a's auto traits need to be in b's auto traits.
- .all(|b| data_a.auto_traits().any(|a| a == b))
+ let auto_traits_compatible = data_b
+ .auto_traits()
+ // All of a's auto traits need to be in b's auto traits.
+ .all(|b| data_a.auto_traits().any(|a| a == b));
+ if auto_traits_compatible {
+ let principal_def_id_a = data_a.principal_def_id();
+ let principal_def_id_b = data_b.principal_def_id();
+ if principal_def_id_a == principal_def_id_b {
+ // no cyclic
+ candidates.vec.push(BuiltinUnsizeCandidate);
+ } else if principal_def_id_a.is_some() && principal_def_id_b.is_some() {
+ // not casual unsizing, now check whether this is trait upcasting coercion.
+ let principal_a = data_a.principal().unwrap();
+ let target_trait_did = principal_def_id_b.unwrap();
+ let source_trait_ref = principal_a.with_self_ty(self.tcx(), source);
+ for (idx, upcast_trait_ref) in
+ util::supertraits(self.tcx(), source_trait_ref).enumerate()
+ {
+ if upcast_trait_ref.def_id() == target_trait_did {
+ candidates.vec.push(TraitUpcastingUnsizeCandidate(idx));
+ }
+ }
+ }
+ }
}
// `T` -> `Trait`
- (_, &ty::Dynamic(..)) => true,
+ (_, &ty::Dynamic(..)) => {
+ candidates.vec.push(BuiltinUnsizeCandidate);
+ }
// Ambiguous handling is below `T` -> `Trait`, because inference
// variables can still implement `Unsize<Trait>` and nested
@@ -720,26 +741,29 @@
(&ty::Infer(ty::TyVar(_)), _) | (_, &ty::Infer(ty::TyVar(_))) => {
debug!("assemble_candidates_for_unsizing: ambiguous");
candidates.ambiguous = true;
- false
}
// `[T; n]` -> `[T]`
- (&ty::Array(..), &ty::Slice(_)) => true,
+ (&ty::Array(..), &ty::Slice(_)) => {
+ candidates.vec.push(BuiltinUnsizeCandidate);
+ }
// `Struct<T>` -> `Struct<U>`
(&ty::Adt(def_id_a, _), &ty::Adt(def_id_b, _)) if def_id_a.is_struct() => {
- def_id_a == def_id_b
+ if def_id_a == def_id_b {
+ candidates.vec.push(BuiltinUnsizeCandidate);
+ }
}
// `(.., T)` -> `(.., U)`
- (&ty::Tuple(tys_a), &ty::Tuple(tys_b)) => tys_a.len() == tys_b.len(),
+ (&ty::Tuple(tys_a), &ty::Tuple(tys_b)) => {
+ if tys_a.len() == tys_b.len() {
+ candidates.vec.push(BuiltinUnsizeCandidate);
+ }
+ }
- _ => false,
+ _ => {}
};
-
- if may_apply {
- candidates.vec.push(BuiltinUnsizeCandidate);
- }
}
fn assemble_candidates_for_trait_alias(
diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
index f8297ee..6fae817 100644
--- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
@@ -8,7 +8,6 @@
//! https://rustc-dev-guide.rust-lang.org/traits/resolution.html#confirmation
use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_hir::lang_items::LangItem;
-use rustc_hir::Constness;
use rustc_index::bit_set::GrowableBitSet;
use rustc_infer::infer::InferOk;
use rustc_infer::infer::LateBoundRegionConversionTime::HigherRankedType;
@@ -26,12 +25,13 @@
use crate::traits::OutputTypeParameterMismatch;
use crate::traits::Selection;
use crate::traits::TraitNotObjectSafe;
+use crate::traits::VtblSegment;
use crate::traits::{BuiltinDerivedObligation, ImplDerivedObligation};
use crate::traits::{
ImplSourceAutoImplData, ImplSourceBuiltinData, ImplSourceClosureData,
ImplSourceDiscriminantKindData, ImplSourceFnPointerData, ImplSourceGeneratorData,
ImplSourceObjectData, ImplSourcePointeeData, ImplSourceTraitAliasData,
- ImplSourceUserDefinedData,
+ ImplSourceTraitUpcastingData, ImplSourceUserDefinedData,
};
use crate::traits::{ObjectCastObligation, PredicateObligation, TraitObligation};
use crate::traits::{Obligation, ObligationCause};
@@ -42,6 +42,7 @@
use super::SelectionContext;
use std::iter;
+use std::ops::ControlFlow;
impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
#[instrument(level = "debug", skip(self))]
@@ -73,7 +74,7 @@
ProjectionCandidate(idx) => {
let obligations = self.confirm_projection_candidate(obligation, idx)?;
// FIXME(jschievink): constness
- Ok(ImplSource::Param(obligations, Constness::NotConst))
+ Ok(ImplSource::Param(obligations, ty::BoundConstness::NotConst))
}
ObjectCandidate(idx) => {
@@ -111,13 +112,18 @@
// This indicates something like `Trait + Send: Send`. In this case, we know that
// this holds because that's what the object type is telling us, and there's really
// no additional obligations to prove and no types in particular to unify, etc.
- Ok(ImplSource::Param(Vec::new(), Constness::NotConst))
+ Ok(ImplSource::Param(Vec::new(), ty::BoundConstness::NotConst))
}
BuiltinUnsizeCandidate => {
let data = self.confirm_builtin_unsize_candidate(obligation)?;
Ok(ImplSource::Builtin(data))
}
+
+ TraitUpcastingUnsizeCandidate(idx) => {
+ let data = self.confirm_trait_upcasting_unsize_candidate(obligation, idx)?;
+ Ok(ImplSource::TraitUpcasting(data))
+ }
}
}
@@ -250,7 +256,7 @@
ImplSourceBuiltinData { nested: obligations }
}
- /// This handles the case where a `auto trait Foo` impl is being used.
+ /// This handles the case where an `auto trait Foo` impl is being used.
/// The idea is that the impl applies to `X : Foo` if the following conditions are met:
///
/// 1. For each constituent type `Y` in `X`, `Y : Foo` holds
@@ -685,6 +691,114 @@
.map_err(|e| OutputTypeParameterMismatch(expected_trait_ref, obligation_trait_ref, e))
}
+ fn confirm_trait_upcasting_unsize_candidate(
+ &mut self,
+ obligation: &TraitObligation<'tcx>,
+ idx: usize,
+ ) -> Result<ImplSourceTraitUpcastingData<'tcx, PredicateObligation<'tcx>>, SelectionError<'tcx>>
+ {
+ let tcx = self.tcx();
+
+ // `assemble_candidates_for_unsizing` should ensure there are no late-bound
+ // regions here. See the comment there for more details.
+ let source = self.infcx.shallow_resolve(obligation.self_ty().no_bound_vars().unwrap());
+ let target = obligation.predicate.skip_binder().trait_ref.substs.type_at(1);
+ let target = self.infcx.shallow_resolve(target);
+
+ debug!(?source, ?target, "confirm_trait_upcasting_unsize_candidate");
+
+ let mut nested = vec![];
+ let source_trait_ref;
+ let upcast_trait_ref;
+ match (source.kind(), target.kind()) {
+ // TraitA+Kx+'a -> TraitB+Ky+'b (trait upcasting coercion).
+ (&ty::Dynamic(ref data_a, r_a), &ty::Dynamic(ref data_b, r_b)) => {
+ // See `assemble_candidates_for_unsizing` for more info.
+ // We already checked the compatiblity of auto traits within `assemble_candidates_for_unsizing`.
+ let principal_a = data_a.principal().unwrap();
+ source_trait_ref = principal_a.with_self_ty(tcx, source);
+ upcast_trait_ref = util::supertraits(tcx, source_trait_ref).nth(idx).unwrap();
+ assert_eq!(data_b.principal_def_id(), Some(upcast_trait_ref.def_id()));
+ let existential_predicate = upcast_trait_ref.map_bound(|trait_ref| {
+ ty::ExistentialPredicate::Trait(ty::ExistentialTraitRef::erase_self_ty(
+ tcx, trait_ref,
+ ))
+ });
+ let iter = Some(existential_predicate)
+ .into_iter()
+ .chain(
+ data_a
+ .projection_bounds()
+ .map(|b| b.map_bound(ty::ExistentialPredicate::Projection)),
+ )
+ .chain(
+ data_b
+ .auto_traits()
+ .map(ty::ExistentialPredicate::AutoTrait)
+ .map(ty::Binder::dummy),
+ );
+ let existential_predicates = tcx.mk_poly_existential_predicates(iter);
+ let source_trait = tcx.mk_dynamic(existential_predicates, r_b);
+
+ // Require that the traits involved in this upcast are **equal**;
+ // only the **lifetime bound** is changed.
+ let InferOk { obligations, .. } = self
+ .infcx
+ .at(&obligation.cause, obligation.param_env)
+ .sup(target, source_trait)
+ .map_err(|_| Unimplemented)?;
+ nested.extend(obligations);
+
+ // Register one obligation for 'a: 'b.
+ let cause = ObligationCause::new(
+ obligation.cause.span,
+ obligation.cause.body_id,
+ ObjectCastObligation(target),
+ );
+ let outlives = ty::OutlivesPredicate(r_a, r_b);
+ nested.push(Obligation::with_depth(
+ cause,
+ obligation.recursion_depth + 1,
+ obligation.param_env,
+ obligation.predicate.rebind(outlives).to_predicate(tcx),
+ ));
+ }
+ _ => bug!(),
+ };
+
+ let vtable_segment_callback = {
+ let mut vptr_offset = 0;
+ move |segment| {
+ match segment {
+ VtblSegment::MetadataDSA => {
+ vptr_offset += ty::COMMON_VTABLE_ENTRIES.len();
+ }
+ VtblSegment::TraitOwnEntries { trait_ref, emit_vptr } => {
+ vptr_offset += util::count_own_vtable_entries(tcx, trait_ref);
+ if trait_ref == upcast_trait_ref {
+ if emit_vptr {
+ return ControlFlow::Break(Some(vptr_offset));
+ } else {
+ return ControlFlow::Break(None);
+ }
+ }
+
+ if emit_vptr {
+ vptr_offset += 1;
+ }
+ }
+ }
+ ControlFlow::Continue(())
+ }
+ };
+
+ let vtable_vptr_slot =
+ super::super::prepare_vtable_segments(tcx, source_trait_ref, vtable_segment_callback)
+ .unwrap();
+
+ Ok(ImplSourceTraitUpcastingData { upcast_trait_ref, vtable_vptr_slot, nested })
+ }
+
fn confirm_builtin_unsize_candidate(
&mut self,
obligation: &TraitObligation<'tcx>,
@@ -701,9 +815,10 @@
let mut nested = vec![];
match (source.kind(), target.kind()) {
- // Trait+Kx+'a -> Trait+Ky+'b (upcasts).
+ // Trait+Kx+'a -> Trait+Ky+'b (auto traits and lifetime subtyping).
(&ty::Dynamic(ref data_a, r_a), &ty::Dynamic(ref data_b, r_b)) => {
// See `assemble_candidates_for_unsizing` for more info.
+ // We already checked the compatiblity of auto traits within `assemble_candidates_for_unsizing`.
let iter = data_a
.principal()
.map(|b| b.map_bound(ty::ExistentialPredicate::Trait))
@@ -831,7 +946,7 @@
let mut unsizing_params = GrowableBitSet::new_empty();
if tcx.features().relaxed_struct_unsize {
- for arg in tail_field_ty.walk() {
+ for arg in tail_field_ty.walk(tcx) {
if let Some(i) = maybe_unsizing_param_idx(arg) {
unsizing_params.insert(i);
}
@@ -840,7 +955,7 @@
// 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() {
+ for arg in tcx.type_of(field.did).walk(tcx) {
if let Some(i) = maybe_unsizing_param_idx(arg) {
unsizing_params.remove(i);
}
@@ -852,7 +967,7 @@
}
} else {
let mut found = false;
- for arg in tail_field_ty.walk() {
+ for arg in tail_field_ty.walk(tcx) {
if let Some(i) = maybe_unsizing_param_idx(arg) {
unsizing_params.insert(i);
found = true;
@@ -868,7 +983,7 @@
// 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() {
+ for arg in tcx.type_of(field.did).walk(tcx) {
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 95611eb..cf6f76a 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -32,7 +32,6 @@
use rustc_errors::ErrorReported;
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
-use rustc_hir::Constness;
use rustc_infer::infer::LateBoundRegionConversionTime;
use rustc_middle::dep_graph::{DepKind, DepNodeIndex};
use rustc_middle::mir::abstract_const::NotConstEvaluatable;
@@ -41,8 +40,9 @@
use rustc_middle::ty::print::with_no_trimmed_paths;
use rustc_middle::ty::relate::TypeRelation;
use rustc_middle::ty::subst::{GenericArgKind, Subst, SubstsRef};
+use rustc_middle::ty::WithConstness;
use rustc_middle::ty::{self, PolyProjectionPredicate, ToPolyTraitRef, ToPredicate};
-use rustc_middle::ty::{Ty, TyCtxt, TypeFoldable, WithConstness};
+use rustc_middle::ty::{Ty, TyCtxt, TypeFoldable};
use rustc_span::symbol::sym;
use std::cell::{Cell, RefCell};
@@ -129,6 +129,9 @@
/// and a negative impl
allow_negative_impls: bool,
+ /// Are we in a const context that needs `~const` bounds to be const?
+ is_in_const_context: bool,
+
/// The mode that trait queries run in, which informs our error handling
/// policy. In essence, canonicalized queries need their errors propagated
/// rather than immediately reported because we do not have accurate spans.
@@ -141,7 +144,7 @@
/// The trait ref from `obligation` but "freshened" with the
/// selection-context's freshener. Used to check for recursion.
- fresh_trait_ref: ty::PolyTraitRef<'tcx>,
+ fresh_trait_ref: ty::ConstnessAnd<ty::PolyTraitRef<'tcx>>,
/// Starts out equal to `depth` -- if, during evaluation, we
/// encounter a cycle, then we will set this flag to the minimum
@@ -220,6 +223,7 @@
intercrate: false,
intercrate_ambiguity_causes: None,
allow_negative_impls: false,
+ is_in_const_context: false,
query_mode: TraitQueryMode::Standard,
}
}
@@ -231,6 +235,7 @@
intercrate: true,
intercrate_ambiguity_causes: None,
allow_negative_impls: false,
+ is_in_const_context: false,
query_mode: TraitQueryMode::Standard,
}
}
@@ -246,6 +251,7 @@
intercrate: false,
intercrate_ambiguity_causes: None,
allow_negative_impls,
+ is_in_const_context: false,
query_mode: TraitQueryMode::Standard,
}
}
@@ -261,10 +267,26 @@
intercrate: false,
intercrate_ambiguity_causes: None,
allow_negative_impls: false,
+ is_in_const_context: false,
query_mode,
}
}
+ pub fn with_constness(
+ infcx: &'cx InferCtxt<'cx, 'tcx>,
+ constness: hir::Constness,
+ ) -> SelectionContext<'cx, 'tcx> {
+ SelectionContext {
+ infcx,
+ freshener: infcx.freshener_keep_static(),
+ intercrate: false,
+ intercrate_ambiguity_causes: None,
+ allow_negative_impls: false,
+ is_in_const_context: matches!(constness, hir::Constness::Const),
+ query_mode: TraitQueryMode::Standard,
+ }
+ }
+
/// Enables tracking of intercrate ambiguity causes. These are
/// used in coherence to give improved diagnostics. We don't do
/// this until we detect a coherence error because it can lead to
@@ -293,6 +315,27 @@
self.infcx.tcx
}
+ pub fn is_intercrate(&self) -> bool {
+ self.intercrate
+ }
+
+ /// Returns `true` if the trait predicate is considerd `const` to this selection context.
+ pub fn is_trait_predicate_const(&self, pred: ty::TraitPredicate<'_>) -> bool {
+ match pred.constness {
+ ty::BoundConstness::ConstIfConst if self.is_in_const_context => true,
+ _ => false,
+ }
+ }
+
+ /// Returns `true` if the predicate is considered `const` to
+ /// this selection context.
+ pub fn is_predicate_const(&self, pred: ty::Predicate<'_>) -> bool {
+ match pred.kind().skip_binder() {
+ ty::PredicateKind::Trait(pred) => self.is_trait_predicate_const(pred),
+ _ => false,
+ }
+ }
+
///////////////////////////////////////////////////////////////////////////
// Selection
//
@@ -454,7 +497,7 @@
let result = ensure_sufficient_stack(|| {
let bound_predicate = obligation.predicate.kind();
match bound_predicate.skip_binder() {
- ty::PredicateKind::Trait(t, _) => {
+ ty::PredicateKind::Trait(t) => {
let t = bound_predicate.rebind(t);
debug_assert!(!t.has_escaping_bound_vars());
let obligation = obligation.with(t);
@@ -477,6 +520,22 @@
}
}
+ ty::PredicateKind::Coerce(p) => {
+ let p = bound_predicate.rebind(p);
+ // Does this code ever run?
+ match self.infcx.coerce_predicate(&obligation.cause, obligation.param_env, p) {
+ Some(Ok(InferOk { mut obligations, .. })) => {
+ self.add_depth(obligations.iter_mut(), obligation.recursion_depth);
+ self.evaluate_predicates_recursively(
+ previous_stack,
+ obligations.into_iter(),
+ )
+ }
+ Some(Err(_)) => Ok(EvaluatedToErr),
+ None => Ok(EvaluatedToAmbig),
+ }
+ }
+
ty::PredicateKind::WellFormed(arg) => match wf::obligations(
self.infcx,
obligation.param_env,
@@ -493,7 +552,7 @@
},
ty::PredicateKind::TypeOutlives(pred) => {
- if pred.0.is_global() {
+ if pred.0.is_known_global() {
Ok(EvaluatedToOk)
} else {
Ok(EvaluatedToOkModuloRegions)
@@ -547,11 +606,10 @@
}
}
- ty::PredicateKind::ConstEvaluatable(def_id, substs) => {
+ ty::PredicateKind::ConstEvaluatable(uv) => {
match const_evaluatable::is_const_evaluatable(
self.infcx,
- def_id,
- substs,
+ uv,
obligation.param_env,
obligation.cause.span,
) {
@@ -565,7 +623,7 @@
ty::PredicateKind::ConstEquate(c1, c2) => {
debug!(?c1, ?c2, "evaluate_predicate_recursively: equating consts");
- if self.tcx().features().const_evaluatable_checked {
+ if self.tcx().features().generic_const_exprs {
// FIXME: we probably should only try to unify abstract constants
// if the constants depend on generic parameters.
//
@@ -573,10 +631,7 @@
if let (ty::ConstKind::Unevaluated(a), ty::ConstKind::Unevaluated(b)) =
(c1.val, c2.val)
{
- if self
- .tcx()
- .try_unify_abstract_consts(((a.def, a.substs), (b.def, b.substs)))
- {
+ if self.infcx.try_unify_abstract_consts(a.shrink(), b.shrink()) {
return Ok(EvaluatedToOk);
}
}
@@ -631,7 +686,7 @@
}
});
- debug!(?result);
+ debug!("finished: {:?} from {:?}", result, obligation);
result
}
@@ -644,8 +699,12 @@
debug!(?obligation, "evaluate_trait_predicate_recursively");
if !self.intercrate
- && obligation.is_global()
- && obligation.param_env.caller_bounds().iter().all(|bound| bound.needs_subst())
+ && obligation.is_global(self.tcx())
+ && obligation
+ .param_env
+ .caller_bounds()
+ .iter()
+ .all(|bound| bound.definitely_needs_subst(self.tcx()))
{
// If a param env has no global bounds, global obligations do not
// depend on its particular value in order to work, so we can clear
@@ -762,8 +821,7 @@
// if the regions match exactly.
let cycle = stack.iter().skip(1).take_while(|s| s.depth >= cycle_depth);
let tcx = self.tcx();
- let cycle =
- cycle.map(|stack| stack.obligation.predicate.without_const().to_predicate(tcx));
+ let cycle = cycle.map(|stack| stack.obligation.predicate.to_predicate(tcx));
if self.coinductive_match(cycle) {
debug!("evaluate_stack --> recursive, coinductive");
Some(EvaluatedToOk)
@@ -805,7 +863,7 @@
// terms of `Fn` etc, but we could probably make this more
// precise still.
let unbound_input_types =
- stack.fresh_trait_ref.skip_binder().substs.types().any(|ty| ty.is_fresh());
+ stack.fresh_trait_ref.value.skip_binder().substs.types().any(|ty| ty.is_fresh());
// This check was an imperfect workaround for a bug in the old
// intercrate mode; it should be removed when that goes away.
if unbound_input_types && self.intercrate {
@@ -873,7 +931,7 @@
fn coinductive_predicate(&self, predicate: ty::Predicate<'tcx>) -> bool {
let result = match predicate.kind().skip_binder() {
- ty::PredicateKind::Trait(ref data, _) => self.tcx().trait_is_auto(data.def_id()),
+ ty::PredicateKind::Trait(ref data) => self.tcx().trait_is_auto(data.def_id()),
_ => false,
};
debug!(?predicate, ?result, "coinductive_predicate");
@@ -926,8 +984,16 @@
fn check_evaluation_cache(
&self,
param_env: ty::ParamEnv<'tcx>,
- trait_ref: ty::PolyTraitRef<'tcx>,
+ trait_ref: ty::ConstnessAnd<ty::PolyTraitRef<'tcx>>,
) -> Option<EvaluationResult> {
+ // Neither the global nor local cache is aware of intercrate
+ // mode, so don't do any caching. In particular, we might
+ // re-use the same `InferCtxt` with both an intercrate
+ // and non-intercrate `SelectionContext`
+ if self.intercrate {
+ return None;
+ }
+
let tcx = self.tcx();
if self.can_use_global_caches(param_env) {
if let Some(res) = tcx.evaluation_cache.get(¶m_env.and(trait_ref), tcx) {
@@ -940,7 +1006,7 @@
fn insert_evaluation_cache(
&mut self,
param_env: ty::ParamEnv<'tcx>,
- trait_ref: ty::PolyTraitRef<'tcx>,
+ trait_ref: ty::ConstnessAnd<ty::PolyTraitRef<'tcx>>,
dep_node: DepNodeIndex,
result: EvaluationResult,
) {
@@ -950,6 +1016,14 @@
return;
}
+ // Neither the global nor local cache is aware of intercrate
+ // mode, so don't do any caching. In particular, we might
+ // re-use the same `InferCtxt` with both an intercrate
+ // and non-intercrate `SelectionContext`
+ if self.intercrate {
+ return;
+ }
+
if self.can_use_global_caches(param_env) {
if !trait_ref.needs_infer() {
debug!(?trait_ref, ?result, "insert_evaluation_cache global");
@@ -1016,13 +1090,42 @@
(result, dep_node)
}
- // Treat negative impls as unimplemented, and reservation impls as ambiguity.
- fn filter_negative_and_reservation_impls(
+ #[instrument(level = "debug", skip(self))]
+ fn filter_impls(
&mut self,
candidate: SelectionCandidate<'tcx>,
+ obligation: &TraitObligation<'tcx>,
) -> SelectionResult<'tcx, SelectionCandidate<'tcx>> {
+ let tcx = self.tcx();
+ // Respect const trait obligations
+ if self.is_trait_predicate_const(obligation.predicate.skip_binder()) {
+ if Some(obligation.predicate.skip_binder().trait_ref.def_id)
+ != tcx.lang_items().sized_trait()
+ // const Sized bounds are skipped
+ {
+ match candidate {
+ // const impl
+ ImplCandidate(def_id)
+ if tcx.impl_constness(def_id) == hir::Constness::Const => {}
+ // const param
+ ParamCandidate(ty::ConstnessAnd {
+ constness: ty::BoundConstness::ConstIfConst,
+ ..
+ }) => {}
+ // auto trait impl
+ AutoImplCandidate(..) => {}
+ // generator, this will raise error in other places
+ // or ignore error with const_async_blocks feature
+ GeneratorCandidate => {}
+ _ => {
+ // reject all other types of candidates
+ return Err(Unimplemented);
+ }
+ }
+ }
+ }
+ // Treat negative impls as unimplemented, and reservation impls as ambiguity.
if let ImplCandidate(def_id) = candidate {
- let tcx = self.tcx();
match tcx.impl_polarity(def_id) {
ty::ImplPolarity::Negative if !self.allow_negative_impls => {
return Err(Unimplemented);
@@ -1036,7 +1139,7 @@
let value = attr.and_then(|a| a.value_str());
if let Some(value) = value {
debug!(
- "filter_negative_and_reservation_impls: \
+ "filter_impls: \
reservation impl ambiguity on {:?}",
def_id
);
@@ -1102,14 +1205,27 @@
param_env: ty::ParamEnv<'tcx>,
cache_fresh_trait_pred: ty::PolyTraitPredicate<'tcx>,
) -> Option<SelectionResult<'tcx, SelectionCandidate<'tcx>>> {
+ // Neither the global nor local cache is aware of intercrate
+ // mode, so don't do any caching. In particular, we might
+ // re-use the same `InferCtxt` with both an intercrate
+ // and non-intercrate `SelectionContext`
+ if self.intercrate {
+ return None;
+ }
let tcx = self.tcx();
- let trait_ref = &cache_fresh_trait_pred.skip_binder().trait_ref;
+ let pred = &cache_fresh_trait_pred.skip_binder();
+ let trait_ref = pred.trait_ref;
if self.can_use_global_caches(param_env) {
- if let Some(res) = tcx.selection_cache.get(¶m_env.and(*trait_ref), tcx) {
+ if let Some(res) = tcx
+ .selection_cache
+ .get(¶m_env.and(trait_ref).with_constness(pred.constness), tcx)
+ {
return Some(res);
}
}
- self.infcx.selection_cache.get(¶m_env.and(*trait_ref), tcx)
+ self.infcx
+ .selection_cache
+ .get(¶m_env.and(trait_ref).with_constness(pred.constness), tcx)
}
/// Determines whether can we safely cache the result
@@ -1132,6 +1248,13 @@
&self,
result: &SelectionResult<'tcx, SelectionCandidate<'tcx>>,
) -> bool {
+ // Neither the global nor local cache is aware of intercrate
+ // mode, so don't do any caching. In particular, we might
+ // re-use the same `InferCtxt` with both an intercrate
+ // and non-intercrate `SelectionContext`
+ if self.intercrate {
+ return false;
+ }
match result {
Ok(Some(SelectionCandidate::ParamCandidate(trait_ref))) => !trait_ref.needs_infer(),
_ => true,
@@ -1146,7 +1269,8 @@
candidate: SelectionResult<'tcx, SelectionCandidate<'tcx>>,
) {
let tcx = self.tcx();
- let trait_ref = cache_fresh_trait_pred.skip_binder().trait_ref;
+ let pred = cache_fresh_trait_pred.skip_binder();
+ let trait_ref = pred.trait_ref;
if !self.can_cache_candidate(&candidate) {
debug!(?trait_ref, ?candidate, "insert_candidate_cache - candidate is not cacheable");
@@ -1160,14 +1284,22 @@
if !candidate.needs_infer() {
debug!(?trait_ref, ?candidate, "insert_candidate_cache global");
// This may overwrite the cache with the same value.
- tcx.selection_cache.insert(param_env.and(trait_ref), dep_node, candidate);
+ tcx.selection_cache.insert(
+ param_env.and(trait_ref).with_constness(pred.constness),
+ dep_node,
+ candidate,
+ );
return;
}
}
}
debug!(?trait_ref, ?candidate, "insert_candidate_cache local");
- self.infcx.selection_cache.insert(param_env.and(trait_ref), dep_node, candidate);
+ self.infcx.selection_cache.insert(
+ param_env.and(trait_ref).with_constness(pred.constness),
+ dep_node,
+ candidate,
+ );
}
/// Matches a predicate against the bounds of its self type.
@@ -1213,7 +1345,7 @@
.enumerate()
.filter_map(|(idx, bound)| {
let bound_predicate = bound.kind();
- if let ty::PredicateKind::Trait(pred, _) = bound_predicate.skip_binder() {
+ 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(
@@ -1359,7 +1491,7 @@
// the param_env so that it can be given the lowest priority. See
// #50825 for the motivation for this.
let is_global =
- |cand: &ty::PolyTraitRef<'_>| cand.is_global() && !cand.has_late_bound_regions();
+ |cand: &ty::PolyTraitRef<'_>| cand.is_known_global() && !cand.has_late_bound_regions();
// (*) Prefer `BuiltinCandidate { has_nested: false }`, `PointeeCandidate`,
// and `DiscriminantKindCandidate` to anything else.
@@ -1399,7 +1531,9 @@
// probably best characterized as a "hack", since we might prefer to just do our
// best to *not* create essentially duplicate candidates in the first place.
other.value.bound_vars().len() <= victim.value.bound_vars().len()
- } else if other.value == victim.value && victim.constness == Constness::NotConst {
+ } else if other.value == victim.value
+ && victim.constness == ty::BoundConstness::NotConst
+ {
// Drop otherwise equivalent non-const candidates in favor of const candidates.
true
} else {
@@ -1420,6 +1554,7 @@
| FnPointerCandidate
| BuiltinObjectCandidate
| BuiltinUnsizeCandidate
+ | TraitUpcastingUnsizeCandidate(_)
| BuiltinCandidate { .. }
| TraitAliasCandidate(..)
| ObjectCandidate(_)
@@ -1437,6 +1572,7 @@
| FnPointerCandidate
| BuiltinObjectCandidate
| BuiltinUnsizeCandidate
+ | TraitUpcastingUnsizeCandidate(_)
| BuiltinCandidate { has_nested: true }
| TraitAliasCandidate(..),
ParamCandidate(ref cand),
@@ -1466,6 +1602,7 @@
| FnPointerCandidate
| BuiltinObjectCandidate
| BuiltinUnsizeCandidate
+ | TraitUpcastingUnsizeCandidate(_)
| BuiltinCandidate { .. }
| TraitAliasCandidate(..),
) => true,
@@ -1477,6 +1614,7 @@
| FnPointerCandidate
| BuiltinObjectCandidate
| BuiltinUnsizeCandidate
+ | TraitUpcastingUnsizeCandidate(_)
| BuiltinCandidate { .. }
| TraitAliasCandidate(..),
ObjectCandidate(_) | ProjectionCandidate(_),
@@ -1486,12 +1624,19 @@
// See if we can toss out `victim` based on specialization.
// This requires us to know *for sure* that the `other` impl applies
// i.e., `EvaluatedToOk`.
+ //
+ // FIXME(@lcnr): Using `modulo_regions` here seems kind of scary
+ // to me but is required for `std` to compile, so I didn't change it
+ // for now.
+ let tcx = self.tcx();
if other.evaluation.must_apply_modulo_regions() {
- let tcx = self.tcx();
if tcx.specializes((other_def, victim_def)) {
return true;
}
- return match tcx.impls_are_allowed_to_overlap(other_def, victim_def) {
+ }
+
+ if other.evaluation.must_apply_considering_regions() {
+ match tcx.impls_are_allowed_to_overlap(other_def, victim_def) {
Some(ty::ImplOverlapKind::Permitted { marker: true }) => {
// Subtle: If the predicate we are evaluating has inference
// variables, do *not* allow discarding candidates due to
@@ -1536,7 +1681,7 @@
}
Some(_) => true,
None => false,
- };
+ }
} else {
false
}
@@ -1550,6 +1695,7 @@
| FnPointerCandidate
| BuiltinObjectCandidate
| BuiltinUnsizeCandidate
+ | TraitUpcastingUnsizeCandidate(_)
| BuiltinCandidate { has_nested: true }
| TraitAliasCandidate(..),
ImplCandidate(_)
@@ -1558,6 +1704,7 @@
| FnPointerCandidate
| BuiltinObjectCandidate
| BuiltinUnsizeCandidate
+ | TraitUpcastingUnsizeCandidate(_)
| BuiltinCandidate { has_nested: true }
| TraitAliasCandidate(..),
) => false,
@@ -1997,8 +2144,8 @@
fn match_fresh_trait_refs(
&self,
- previous: ty::PolyTraitRef<'tcx>,
- current: ty::PolyTraitRef<'tcx>,
+ previous: ty::ConstnessAnd<ty::PolyTraitRef<'tcx>>,
+ current: ty::ConstnessAnd<ty::PolyTraitRef<'tcx>>,
param_env: ty::ParamEnv<'tcx>,
) -> bool {
let mut matcher = ty::_match::Match::new(self.tcx(), param_env);
@@ -2010,8 +2157,11 @@
previous_stack: TraitObligationStackList<'o, 'tcx>,
obligation: &'o TraitObligation<'tcx>,
) -> TraitObligationStack<'o, 'tcx> {
- let fresh_trait_ref =
- obligation.predicate.to_poly_trait_ref().fold_with(&mut self.freshener);
+ let fresh_trait_ref = obligation
+ .predicate
+ .to_poly_trait_ref()
+ .fold_with(&mut self.freshener)
+ .with_constness(obligation.predicate.skip_binder().constness);
let dfn = previous_stack.cache.next_dfn();
let depth = previous_stack.depth() + 1;
@@ -2290,7 +2440,7 @@
/// - then we determine that `E` is in error -- we will then clear
/// all cache values whose DFN is >= 4 -- in this case, that
/// means the cached value for `F`.
- map: RefCell<FxHashMap<ty::PolyTraitRef<'tcx>, ProvisionalEvaluation>>,
+ map: RefCell<FxHashMap<ty::ConstnessAnd<ty::PolyTraitRef<'tcx>>, ProvisionalEvaluation>>,
}
/// A cache value for the provisional cache: contains the depth-first
@@ -2322,7 +2472,7 @@
/// `reached_depth` (from the returned value).
fn get_provisional(
&self,
- fresh_trait_ref: ty::PolyTraitRef<'tcx>,
+ fresh_trait_ref: ty::ConstnessAnd<ty::PolyTraitRef<'tcx>>,
) -> Option<ProvisionalEvaluation> {
debug!(
?fresh_trait_ref,
@@ -2340,7 +2490,7 @@
&self,
from_dfn: usize,
reached_depth: usize,
- fresh_trait_ref: ty::PolyTraitRef<'tcx>,
+ fresh_trait_ref: ty::ConstnessAnd<ty::PolyTraitRef<'tcx>>,
result: EvaluationResult,
) {
debug!(?from_dfn, ?fresh_trait_ref, ?result, "insert_provisional");
@@ -2418,7 +2568,7 @@
fn on_completion(
&self,
dfn: usize,
- mut op: impl FnMut(ty::PolyTraitRef<'tcx>, EvaluationResult),
+ mut op: impl FnMut(ty::ConstnessAnd<ty::PolyTraitRef<'tcx>>, EvaluationResult),
) {
debug!(?dfn, "on_completion");
diff --git a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
index 4b563a8..88aca79 100644
--- a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
@@ -149,7 +149,7 @@
let penv = tcx.param_env(impl1_def_id);
let impl1_trait_ref = tcx.impl_trait_ref(impl1_def_id).unwrap();
- // Create a infcx, taking the predicates of impl1 as assumptions:
+ // Create an infcx, taking the predicates of impl1 as assumptions:
tcx.infer_ctxt().enter(|infcx| {
// Normalize the trait reference. The WF rules ought to ensure
// that this always succeeds.
diff --git a/compiler/rustc_trait_selection/src/traits/structural_match.rs b/compiler/rustc_trait_selection/src/traits/structural_match.rs
index a6323a6..ac8bab0 100644
--- a/compiler/rustc_trait_selection/src/traits/structural_match.rs
+++ b/compiler/rustc_trait_selection/src/traits/structural_match.rs
@@ -130,6 +130,9 @@
impl<'a, 'tcx> TypeVisitor<'tcx> for Search<'a, 'tcx> {
type BreakTy = NonStructuralMatchTy<'tcx>;
+ fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
+ Some(self.tcx())
+ }
fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
debug!("Search visiting ty: {:?}", ty);
diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs
index 27c8e00c..75307f1 100644
--- a/compiler/rustc_trait_selection/src/traits/wf.rs
+++ b/compiler/rustc_trait_selection/src/traits/wf.rs
@@ -108,7 +108,7 @@
// It's ok to skip the binder here because wf code is prepared for it
match predicate.kind().skip_binder() {
- ty::PredicateKind::Trait(t, _) => {
+ ty::PredicateKind::Trait(t) => {
wf.compute_trait_ref(&t.trait_ref, Elaborate::None);
}
ty::PredicateKind::RegionOutlives(..) => {}
@@ -128,8 +128,13 @@
wf.compute(a.into());
wf.compute(b.into());
}
- ty::PredicateKind::ConstEvaluatable(def, substs) => {
- let obligations = wf.nominal_obligations(def.did, substs);
+ ty::PredicateKind::Coerce(ty::CoercePredicate { a, b }) => {
+ wf.compute(a.into());
+ wf.compute(b.into());
+ }
+ ty::PredicateKind::ConstEvaluatable(uv) => {
+ let substs = uv.substs(wf.tcx());
+ let obligations = wf.nominal_obligations(uv.def.did, substs);
wf.out.extend(obligations);
for arg in substs.iter() {
@@ -226,7 +231,7 @@
}
}
}
- ty::PredicateKind::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);
@@ -418,7 +423,7 @@
/// Pushes all the predicates needed to validate that `ty` is WF into `out`.
fn compute(&mut self, arg: GenericArg<'tcx>) {
- let mut walker = arg.walk();
+ let mut walker = arg.walk(self.tcx());
let param_env = self.param_env;
let depth = self.recursion_depth;
while let Some(arg) = walker.next() {
@@ -431,14 +436,17 @@
GenericArgKind::Const(constant) => {
match constant.val {
- ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted }) => {
- assert!(promoted.is_none());
+ ty::ConstKind::Unevaluated(uv) => {
+ assert!(uv.promoted.is_none());
+ let substs = uv.substs(self.tcx());
- let obligations = self.nominal_obligations(def.did, substs);
+ let obligations = self.nominal_obligations(uv.def.did, substs);
self.out.extend(obligations);
- let predicate = ty::PredicateKind::ConstEvaluatable(def, substs)
- .to_predicate(self.tcx());
+ let predicate = ty::PredicateKind::ConstEvaluatable(
+ ty::Unevaluated::new(uv.def, substs),
+ )
+ .to_predicate(self.tcx());
let cause = self.cause(traits::MiscObligation);
self.out.push(traits::Obligation::with_depth(
cause,
diff --git a/compiler/rustc_traits/Cargo.toml b/compiler/rustc_traits/Cargo.toml
index a7ce14a..219165f 100644
--- a/compiler/rustc_traits/Cargo.toml
+++ b/compiler/rustc_traits/Cargo.toml
@@ -1,5 +1,4 @@
[package]
-authors = ["The Rust Project Developers"]
name = "rustc_traits"
version = "0.0.0"
edition = "2018"
diff --git a/compiler/rustc_traits/src/chalk/db.rs b/compiler/rustc_traits/src/chalk/db.rs
index 8c97e60..1d457d6 100644
--- a/compiler/rustc_traits/src/chalk/db.rs
+++ b/compiler/rustc_traits/src/chalk/db.rs
@@ -718,7 +718,7 @@
}
}
-/// Creates a `InternalSubsts` that maps each generic parameter to a higher-ranked
+/// Creates an `InternalSubsts` that maps each generic parameter to a higher-ranked
/// var bound at index `0`. For types, we use a `BoundVar` index equal to
/// the type parameter index. For regions, we use the `BoundRegionKind::BrNamed`
/// variant (which has a `DefId`).
diff --git a/compiler/rustc_traits/src/chalk/lowering.rs b/compiler/rustc_traits/src/chalk/lowering.rs
index a838172..1d4196e 100644
--- a/compiler/rustc_traits/src/chalk/lowering.rs
+++ b/compiler/rustc_traits/src/chalk/lowering.rs
@@ -87,7 +87,7 @@
ty::PredicateKind::TypeWellFormedFromEnv(ty) => {
chalk_ir::DomainGoal::FromEnv(chalk_ir::FromEnv::Ty(ty.lower_into(interner)))
}
- ty::PredicateKind::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::PredicateKind::RegionOutlives(predicate) => chalk_ir::DomainGoal::Holds(
@@ -109,6 +109,7 @@
| ty::PredicateKind::ObjectSafe(..)
| ty::PredicateKind::ClosureKind(..)
| ty::PredicateKind::Subtype(..)
+ | ty::PredicateKind::Coerce(..)
| ty::PredicateKind::ConstEvaluatable(..)
| ty::PredicateKind::ConstEquate(..) => bug!("unexpected predicate {}", predicate),
};
@@ -137,7 +138,7 @@
collect_bound_vars(interner, interner.tcx, self.kind());
let value = match predicate {
- ty::PredicateKind::Trait(predicate, _) => {
+ ty::PredicateKind::Trait(predicate) => {
chalk_ir::GoalData::DomainGoal(chalk_ir::DomainGoal::Holds(
chalk_ir::WhereClause::Implemented(predicate.trait_ref.lower_into(interner)),
))
@@ -193,6 +194,7 @@
// some of these in terms of chalk operations.
ty::PredicateKind::ClosureKind(..)
| ty::PredicateKind::Subtype(..)
+ | ty::PredicateKind::Coerce(..)
| ty::PredicateKind::ConstEvaluatable(..)
| ty::PredicateKind::ConstEquate(..) => {
chalk_ir::GoalData::All(chalk_ir::Goals::empty(interner))
@@ -569,7 +571,7 @@
let (predicate, binders, _named_regions) =
collect_bound_vars(interner, interner.tcx, self.kind());
let value = match predicate {
- ty::PredicateKind::Trait(predicate, _) => {
+ ty::PredicateKind::Trait(predicate) => {
Some(chalk_ir::WhereClause::Implemented(predicate.trait_ref.lower_into(interner)))
}
ty::PredicateKind::RegionOutlives(predicate) => {
@@ -592,6 +594,7 @@
ty::PredicateKind::ObjectSafe(..)
| ty::PredicateKind::ClosureKind(..)
| ty::PredicateKind::Subtype(..)
+ | ty::PredicateKind::Coerce(..)
| ty::PredicateKind::ConstEvaluatable(..)
| ty::PredicateKind::ConstEquate(..)
| ty::PredicateKind::TypeWellFormedFromEnv(..) => {
@@ -702,7 +705,7 @@
let (predicate, binders, _named_regions) =
collect_bound_vars(interner, interner.tcx, self.kind());
match predicate {
- ty::PredicateKind::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),
@@ -719,6 +722,7 @@
| ty::PredicateKind::ObjectSafe(..)
| ty::PredicateKind::ClosureKind(..)
| ty::PredicateKind::Subtype(..)
+ | ty::PredicateKind::Coerce(..)
| ty::PredicateKind::ConstEvaluatable(..)
| ty::PredicateKind::ConstEquate(..)
| ty::PredicateKind::TypeWellFormedFromEnv(..) => {
@@ -802,7 +806,7 @@
tcx: TyCtxt<'tcx>,
ty: Binder<'tcx, T>,
) -> (T, chalk_ir::VariableKinds<RustInterner<'tcx>>, BTreeMap<DefId, u32>) {
- let mut bound_vars_collector = BoundVarsCollector::new();
+ let mut bound_vars_collector = BoundVarsCollector::new(tcx);
ty.as_ref().skip_binder().visit_with(&mut bound_vars_collector);
let mut parameters = bound_vars_collector.parameters;
let named_parameters: BTreeMap<DefId, u32> = bound_vars_collector
@@ -832,14 +836,16 @@
}
crate struct BoundVarsCollector<'tcx> {
+ tcx: TyCtxt<'tcx>,
binder_index: ty::DebruijnIndex,
crate parameters: BTreeMap<u32, chalk_ir::VariableKind<RustInterner<'tcx>>>,
crate named_parameters: Vec<DefId>,
}
impl<'tcx> BoundVarsCollector<'tcx> {
- crate fn new() -> Self {
+ crate fn new(tcx: TyCtxt<'tcx>) -> Self {
BoundVarsCollector {
+ tcx,
binder_index: ty::INNERMOST,
parameters: BTreeMap::new(),
named_parameters: vec![],
@@ -848,6 +854,10 @@
}
impl<'tcx> TypeVisitor<'tcx> for BoundVarsCollector<'tcx> {
+ fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
+ Some(self.tcx)
+ }
+
fn visit_binder<T: TypeFoldable<'tcx>>(
&mut self,
t: &Binder<'tcx, T>,
@@ -1066,6 +1076,11 @@
}
impl<'tcx> TypeVisitor<'tcx> for PlaceholdersCollector {
+ fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
+ // Anon const substs do not contain placeholders by default.
+ None
+ }
+
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
match t.kind() {
ty::Placeholder(p) if p.universe == self.universe_index => {
diff --git a/compiler/rustc_traits/src/dropck_outlives.rs b/compiler/rustc_traits/src/dropck_outlives.rs
index 4a41dfe..672e149 100644
--- a/compiler/rustc_traits/src/dropck_outlives.rs
+++ b/compiler/rustc_traits/src/dropck_outlives.rs
@@ -90,8 +90,8 @@
// "outlives" represent types/regions that may be touched
// by a destructor.
- result.kinds.extend(constraints.outlives.drain(..));
- result.overflows.extend(constraints.overflows.drain(..));
+ result.kinds.append(&mut constraints.outlives);
+ result.overflows.append(&mut constraints.overflows);
// If we have even one overflow, we should stop trying to evaluate further --
// chances are, the subsequent overflows for this evaluation won't provide useful
diff --git a/compiler/rustc_traits/src/implied_outlives_bounds.rs b/compiler/rustc_traits/src/implied_outlives_bounds.rs
index 90ba902..1d10d06 100644
--- a/compiler/rustc_traits/src/implied_outlives_bounds.rs
+++ b/compiler/rustc_traits/src/implied_outlives_bounds.rs
@@ -99,6 +99,7 @@
Some(pred) => match pred {
ty::PredicateKind::Trait(..)
| ty::PredicateKind::Subtype(..)
+ | ty::PredicateKind::Coerce(..)
| ty::PredicateKind::Projection(..)
| ty::PredicateKind::ClosureKind(..)
| ty::PredicateKind::ObjectSafe(..)
diff --git a/compiler/rustc_traits/src/lib.rs b/compiler/rustc_traits/src/lib.rs
index d0b05be..48c46c3 100644
--- a/compiler/rustc_traits/src/lib.rs
+++ b/compiler/rustc_traits/src/lib.rs
@@ -19,6 +19,8 @@
mod normalize_projection_ty;
mod type_op;
+pub use type_op::{type_op_ascribe_user_type_with_span, type_op_prove_predicate_with_span};
+
use rustc_middle::ty::query::Providers;
pub fn provide(p: &mut Providers) {
diff --git a/compiler/rustc_traits/src/normalize_erasing_regions.rs b/compiler/rustc_traits/src/normalize_erasing_regions.rs
index 5ad0684..61ab5e2 100644
--- a/compiler/rustc_traits/src/normalize_erasing_regions.rs
+++ b/compiler/rustc_traits/src/normalize_erasing_regions.rs
@@ -65,6 +65,7 @@
| ty::PredicateKind::ObjectSafe(..)
| ty::PredicateKind::ClosureKind(..)
| ty::PredicateKind::Subtype(..)
+ | ty::PredicateKind::Coerce(..)
| 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 2c55ea7..a76fb84 100644
--- a/compiler/rustc_traits/src/type_op.rs
+++ b/compiler/rustc_traits/src/type_op.rs
@@ -8,7 +8,7 @@
use rustc_middle::ty::subst::{GenericArg, Subst, UserSelfTy, UserSubsts};
use rustc_middle::ty::{self, FnSig, Lift, PolyFnSig, Ty, TyCtxt, TypeFoldable, Variance};
use rustc_middle::ty::{ParamEnv, ParamEnvAnd, Predicate, ToPredicate};
-use rustc_span::DUMMY_SP;
+use rustc_span::{Span, DUMMY_SP};
use rustc_trait_selection::infer::InferCtxtBuilderExt;
use rustc_trait_selection::infer::InferCtxtExt;
use rustc_trait_selection::traits::query::normalize::AtExt;
@@ -40,20 +40,30 @@
canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, AscribeUserType<'tcx>>>,
) -> Result<&'tcx Canonical<'tcx, QueryResponse<'tcx, ()>>, NoSolution> {
tcx.infer_ctxt().enter_canonical_trait_query(&canonicalized, |infcx, fulfill_cx, key| {
- let (param_env, AscribeUserType { mir_ty, def_id, user_substs }) = key.into_parts();
-
- debug!(
- "type_op_ascribe_user_type: mir_ty={:?} def_id={:?} user_substs={:?}",
- mir_ty, def_id, user_substs
- );
-
- let mut cx = AscribeUserTypeCx { infcx, param_env, fulfill_cx };
- cx.relate_mir_and_user_ty(mir_ty, def_id, user_substs)?;
-
- Ok(())
+ type_op_ascribe_user_type_with_span(infcx, fulfill_cx, key, None)
})
}
+/// The core of the `type_op_ascribe_user_type` query: for diagnostics purposes in NLL HRTB errors,
+/// this query can be re-run to better track the span of the obligation cause, and improve the error
+/// message. Do not call directly unless you're in that very specific context.
+pub fn type_op_ascribe_user_type_with_span<'a, 'tcx: 'a>(
+ infcx: &'a InferCtxt<'a, 'tcx>,
+ fulfill_cx: &'a mut dyn TraitEngine<'tcx>,
+ key: ParamEnvAnd<'tcx, AscribeUserType<'tcx>>,
+ span: Option<Span>,
+) -> Result<(), NoSolution> {
+ let (param_env, AscribeUserType { mir_ty, def_id, user_substs }) = key.into_parts();
+ debug!(
+ "type_op_ascribe_user_type: mir_ty={:?} def_id={:?} user_substs={:?}",
+ mir_ty, def_id, user_substs
+ );
+
+ let mut cx = AscribeUserTypeCx { infcx, param_env, fulfill_cx };
+ cx.relate_mir_and_user_ty(mir_ty, def_id, user_substs, span)?;
+ Ok(())
+}
+
struct AscribeUserTypeCx<'me, 'tcx> {
infcx: &'me InferCtxt<'me, 'tcx>,
param_env: ParamEnv<'tcx>,
@@ -85,10 +95,15 @@
Ok(())
}
- fn prove_predicate(&mut self, predicate: Predicate<'tcx>) {
+ fn prove_predicate(&mut self, predicate: Predicate<'tcx>, span: Option<Span>) {
+ let cause = if let Some(span) = span {
+ ObligationCause::dummy_with_span(span)
+ } else {
+ ObligationCause::dummy()
+ };
self.fulfill_cx.register_predicate_obligation(
self.infcx,
- Obligation::new(ObligationCause::dummy(), self.param_env, predicate),
+ Obligation::new(cause, self.param_env, predicate),
);
}
@@ -108,6 +123,7 @@
mir_ty: Ty<'tcx>,
def_id: DefId,
user_substs: UserSubsts<'tcx>,
+ span: Option<Span>,
) -> Result<(), NoSolution> {
let UserSubsts { user_self_ty, substs } = user_substs;
let tcx = self.tcx();
@@ -126,9 +142,10 @@
// outlives" error messages.
let instantiated_predicates =
self.tcx().predicates_of(def_id).instantiate(self.tcx(), substs);
+ debug!(?instantiated_predicates.predicates);
for instantiated_predicate in instantiated_predicates.predicates {
let instantiated_predicate = self.normalize(instantiated_predicate);
- self.prove_predicate(instantiated_predicate);
+ self.prove_predicate(instantiated_predicate, span);
}
if let Some(UserSelfTy { impl_def_id, self_ty }) = user_self_ty {
@@ -140,6 +157,7 @@
self.prove_predicate(
ty::PredicateKind::WellFormed(impl_self_ty.into()).to_predicate(self.tcx()),
+ span,
);
}
@@ -154,7 +172,10 @@
// 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::PredicateKind::WellFormed(ty.into()).to_predicate(self.tcx()));
+ self.prove_predicate(
+ ty::PredicateKind::WellFormed(ty.into()).to_predicate(self.tcx()),
+ span,
+ );
Ok(())
}
}
@@ -235,11 +256,25 @@
canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, ProvePredicate<'tcx>>>,
) -> Result<&'tcx Canonical<'tcx, QueryResponse<'tcx, ()>>, NoSolution> {
tcx.infer_ctxt().enter_canonical_trait_query(&canonicalized, |infcx, fulfill_cx, key| {
- let (param_env, ProvePredicate { predicate }) = key.into_parts();
- fulfill_cx.register_predicate_obligation(
- infcx,
- Obligation::new(ObligationCause::dummy(), param_env, predicate),
- );
+ type_op_prove_predicate_with_span(infcx, fulfill_cx, key, None);
Ok(())
})
}
+
+/// The core of the `type_op_prove_predicate` query: for diagnostics purposes in NLL HRTB errors,
+/// this query can be re-run to better track the span of the obligation cause, and improve the error
+/// message. Do not call directly unless you're in that very specific context.
+pub fn type_op_prove_predicate_with_span<'a, 'tcx: 'a>(
+ infcx: &'a InferCtxt<'a, 'tcx>,
+ fulfill_cx: &'a mut dyn TraitEngine<'tcx>,
+ key: ParamEnvAnd<'tcx, ProvePredicate<'tcx>>,
+ span: Option<Span>,
+) {
+ let cause = if let Some(span) = span {
+ ObligationCause::dummy_with_span(span)
+ } else {
+ ObligationCause::dummy()
+ };
+ let (param_env, ProvePredicate { predicate }) = key.into_parts();
+ fulfill_cx.register_predicate_obligation(infcx, Obligation::new(cause, param_env, predicate));
+}
diff --git a/compiler/rustc_ty_utils/Cargo.toml b/compiler/rustc_ty_utils/Cargo.toml
index 5020437..2eb27fb 100644
--- a/compiler/rustc_ty_utils/Cargo.toml
+++ b/compiler/rustc_ty_utils/Cargo.toml
@@ -1,5 +1,4 @@
[package]
-authors = ["The Rust Project Developers"]
name = "rustc_ty_utils"
version = "0.0.0"
edition = "2018"
diff --git a/compiler/rustc_ty_utils/src/instance.rs b/compiler/rustc_ty_utils/src/instance.rs
index 469ac04..b00d2ab 100644
--- a/compiler/rustc_ty_utils/src/instance.rs
+++ b/compiler/rustc_ty_utils/src/instance.rs
@@ -54,6 +54,10 @@
impl<'tcx> TypeVisitor<'tcx> for BoundVarsCollector<'tcx> {
type BreakTy = ();
+ fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
+ // Anon const substs do not contain bound vars by default.
+ None
+ }
fn visit_binder<T: TypeFoldable<'tcx>>(
&mut self,
t: &Binder<'tcx, T>,
@@ -381,7 +385,8 @@
| traits::ImplSource::Param(..)
| traits::ImplSource::TraitAlias(..)
| traits::ImplSource::DiscriminantKind(..)
- | traits::ImplSource::Pointee(..) => None,
+ | traits::ImplSource::Pointee(..)
+ | traits::ImplSource::TraitUpcasting(_) => None,
})
}
diff --git a/compiler/rustc_ty_utils/src/needs_drop.rs b/compiler/rustc_ty_utils/src/needs_drop.rs
index d837af8..bf155ec 100644
--- a/compiler/rustc_ty_utils/src/needs_drop.rs
+++ b/compiler/rustc_ty_utils/src/needs_drop.rs
@@ -3,6 +3,7 @@
use rustc_data_structures::fx::FxHashSet;
use rustc_hir::def_id::DefId;
use rustc_middle::ty::subst::Subst;
+use rustc_middle::ty::subst::SubstsRef;
use rustc_middle::ty::util::{needs_drop_components, AlwaysRequiresDrop};
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_session::Limit;
@@ -12,7 +13,8 @@
fn needs_drop_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
let adt_fields =
- move |adt_def: &ty::AdtDef| tcx.adt_drop_tys(adt_def.did).map(|tys| tys.iter());
+ move |adt_def: &ty::AdtDef, _| tcx.adt_drop_tys(adt_def.did).map(|tys| tys.iter());
+
// If we don't know a type doesn't need drop, for example if it's a type
// parameter without a `Copy` bound, then we conservatively return that it
// needs drop.
@@ -25,8 +27,9 @@
tcx: TyCtxt<'tcx>,
query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>,
) -> bool {
- let significant_drop_fields =
- move |adt_def: &ty::AdtDef| tcx.adt_significant_drop_tys(adt_def.did).map(|tys| tys.iter());
+ let significant_drop_fields = move |adt_def: &ty::AdtDef, _| {
+ tcx.adt_significant_drop_tys(adt_def.did).map(|tys| tys.iter())
+ };
let res = NeedsDropTypes::new(tcx, query.param_env, query.value, significant_drop_fields)
.next()
.is_some();
@@ -71,7 +74,7 @@
impl<'tcx, F, I> Iterator for NeedsDropTypes<'tcx, F>
where
- F: Fn(&ty::AdtDef) -> NeedsDropResult<I>,
+ F: Fn(&ty::AdtDef, SubstsRef<'tcx>) -> NeedsDropResult<I>,
I: Iterator<Item = Ty<'tcx>>,
{
type Item = NeedsDropResult<Ty<'tcx>>;
@@ -135,7 +138,7 @@
// `ManuallyDrop`. If it's a struct or enum without a `Drop`
// impl then check whether the field types need `Drop`.
ty::Adt(adt_def, substs) => {
- let tys = match (self.adt_components)(adt_def) {
+ let tys = match (self.adt_components)(adt_def, substs) {
Err(e) => return Some(Err(e)),
Ok(tys) => tys,
};
@@ -168,22 +171,44 @@
}
}
+enum DtorType {
+ /// Type has a `Drop` but it is considered insignificant.
+ /// Check the query `adt_significant_drop_tys` for understanding
+ /// "significant" / "insignificant".
+ Insignificant,
+
+ /// Type has a `Drop` implentation.
+ Significant,
+}
+
// This is a helper function for `adt_drop_tys` and `adt_significant_drop_tys`.
// Depending on the implentation of `adt_has_dtor`, it is used to check if the
// ADT has a destructor or if the ADT only has a significant destructor. For
// understanding significant destructor look at `adt_significant_drop_tys`.
-fn adt_drop_tys_helper(
- tcx: TyCtxt<'_>,
+fn adt_drop_tys_helper<'tcx>(
+ tcx: TyCtxt<'tcx>,
def_id: DefId,
- adt_has_dtor: impl Fn(&ty::AdtDef) -> bool,
-) -> Result<&ty::List<Ty<'_>>, AlwaysRequiresDrop> {
- let adt_components = move |adt_def: &ty::AdtDef| {
+ adt_has_dtor: impl Fn(&ty::AdtDef) -> Option<DtorType>,
+) -> Result<&ty::List<Ty<'tcx>>, AlwaysRequiresDrop> {
+ let adt_components = move |adt_def: &ty::AdtDef, substs: SubstsRef<'tcx>| {
if adt_def.is_manually_drop() {
debug!("adt_drop_tys: `{:?}` is manually drop", adt_def);
return Ok(Vec::new().into_iter());
- } else if adt_has_dtor(adt_def) {
- debug!("adt_drop_tys: `{:?}` implements `Drop`", adt_def);
- return Err(AlwaysRequiresDrop);
+ } else if let Some(dtor_info) = adt_has_dtor(adt_def) {
+ match dtor_info {
+ DtorType::Significant => {
+ debug!("adt_drop_tys: `{:?}` implements `Drop`", adt_def);
+ return Err(AlwaysRequiresDrop);
+ }
+ DtorType::Insignificant => {
+ debug!("adt_drop_tys: `{:?}` drop is insignificant", adt_def);
+
+ // Since the destructor is insignificant, we just want to make sure all of
+ // the passed in type parameters are also insignificant.
+ // Eg: Vec<T> dtor is insignificant when T=i32 but significant when T=Mutex.
+ return Ok(substs.types().collect::<Vec<Ty<'_>>>().into_iter());
+ }
+ }
} else if adt_def.is_union() {
debug!("adt_drop_tys: `{:?}` is a union", adt_def);
return Ok(Vec::new().into_iter());
@@ -201,7 +226,10 @@
}
fn adt_drop_tys(tcx: TyCtxt<'_>, def_id: DefId) -> Result<&ty::List<Ty<'_>>, AlwaysRequiresDrop> {
- let adt_has_dtor = |adt_def: &ty::AdtDef| adt_def.destructor(tcx).is_some();
+ // This is for the "needs_drop" query, that considers all `Drop` impls, therefore all dtors are
+ // significant.
+ let adt_has_dtor =
+ |adt_def: &ty::AdtDef| adt_def.destructor(tcx).map(|_| DtorType::Significant);
adt_drop_tys_helper(tcx, def_id, adt_has_dtor)
}
@@ -210,10 +238,22 @@
def_id: DefId,
) -> Result<&ty::List<Ty<'_>>, AlwaysRequiresDrop> {
let adt_has_dtor = |adt_def: &ty::AdtDef| {
- adt_def
- .destructor(tcx)
- .map(|dtor| !tcx.has_attr(dtor.did, sym::rustc_insignificant_dtor))
- .unwrap_or(false)
+ let is_marked_insig = tcx.has_attr(adt_def.did, sym::rustc_insignificant_dtor);
+ if is_marked_insig {
+ // In some cases like `std::collections::HashMap` where the struct is a wrapper around
+ // a type that is a Drop type, and the wrapped type (eg: `hashbrown::HashMap`) lies
+ // outside stdlib, we might choose to still annotate the the wrapper (std HashMap) with
+ // `rustc_insignificant_dtor`, even if the type itself doesn't have a `Drop` impl.
+ Some(DtorType::Insignificant)
+ } else if adt_def.destructor(tcx).is_some() {
+ // There is a Drop impl and the type isn't marked insignificant, therefore Drop must be
+ // significant.
+ Some(DtorType::Significant)
+ } else {
+ // No destructor found nor the type is annotated with `rustc_insignificant_dtor`, we
+ // treat this as the simple case of Drop impl for type.
+ None
+ }
};
adt_drop_tys_helper(tcx, def_id, adt_has_dtor)
}
diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs
index b0d644a..27ad7bf 100644
--- a/compiler/rustc_ty_utils/src/ty.rs
+++ b/compiler/rustc_ty_utils/src/ty.rs
@@ -185,7 +185,7 @@
/// - a type parameter or projection whose Sizedness can't be known
/// - a tuple of type parameters or projections, if there are multiple
/// such.
-/// - a Error, if a type contained itself. The representability
+/// - an Error, if a type contained itself. The representability
/// check should catch this case.
fn adt_sized_constraint(tcx: TyCtxt<'_>, def_id: DefId) -> ty::AdtSizedConstraint<'_> {
let def = tcx.adt_def(def_id);
@@ -223,7 +223,18 @@
}
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)
+ tcx.hir()
+ .get_if_local(def_id)
+ .and_then(|node| match node {
+ // A `Ctor` doesn't have an identifier itself, but its parent
+ // struct/variant does. Compare with `hir::Map::opt_span`.
+ hir::Node::Ctor(ctor) => ctor
+ .ctor_hir_id()
+ .and_then(|ctor_id| tcx.hir().find(tcx.hir().get_parent_node(ctor_id)))
+ .and_then(|parent| parent.ident()),
+ _ => node.ident(),
+ })
+ .map(|ident| ident.span)
}
/// If the given `DefId` describes an item belonging to a trait,
@@ -253,7 +264,7 @@
// `<i32 as Foo>::Bar` where `i32` does not implement `Foo`. We
// report these errors right here; this doesn't actually feel
// right to me, because constructing the environment feels like a
- // kind of a "idempotent" action, but I'm not sure where would be
+ // kind of an "idempotent" action, but I'm not sure where would be
// a better place. In practice, we construct environments for
// every fn once during type checking, and we'll abort if there
// are any errors at that point, so after type checking you can be
@@ -361,7 +372,7 @@
// constituents are well-formed.
NodeKind::InherentImpl => {
let self_ty = tcx.type_of(def_id);
- inputs.extend(self_ty.walk());
+ inputs.extend(self_ty.walk(tcx));
}
// In an fn, we assume that the arguments and all their constituents are
@@ -370,7 +381,7 @@
let fn_sig = tcx.fn_sig(def_id);
let fn_sig = tcx.liberate_late_bound_regions(def_id, fn_sig);
- inputs.extend(fn_sig.inputs().iter().flat_map(|ty| ty.walk()));
+ inputs.extend(fn_sig.inputs().iter().flat_map(|ty| ty.walk(tcx)));
}
NodeKind::Other => (),
diff --git a/compiler/rustc_type_ir/Cargo.toml b/compiler/rustc_type_ir/Cargo.toml
index 3f64bd8..1f6acbe 100644
--- a/compiler/rustc_type_ir/Cargo.toml
+++ b/compiler/rustc_type_ir/Cargo.toml
@@ -1,7 +1,6 @@
[package]
name = "rustc_type_ir"
version = "0.0.0"
-authors = ["The Rust Project Developers"]
edition = "2018"
[lib]
diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs
index 2d10212..c405bbe 100644
--- a/compiler/rustc_type_ir/src/lib.rs
+++ b/compiler/rustc_type_ir/src/lib.rs
@@ -19,94 +19,116 @@
// Does this have parameters? Used to determine whether substitution is
// required.
/// Does this have `Param`?
- const HAS_TY_PARAM = 1 << 0;
+ const HAS_KNOWN_TY_PARAM = 1 << 0;
/// Does this have `ReEarlyBound`?
- const HAS_RE_PARAM = 1 << 1;
+ const HAS_KNOWN_RE_PARAM = 1 << 1;
/// Does this have `ConstKind::Param`?
- const HAS_CT_PARAM = 1 << 2;
+ const HAS_KNOWN_CT_PARAM = 1 << 2;
- const NEEDS_SUBST = TypeFlags::HAS_TY_PARAM.bits
- | TypeFlags::HAS_RE_PARAM.bits
- | TypeFlags::HAS_CT_PARAM.bits;
+ const KNOWN_NEEDS_SUBST = TypeFlags::HAS_KNOWN_TY_PARAM.bits
+ | TypeFlags::HAS_KNOWN_RE_PARAM.bits
+ | TypeFlags::HAS_KNOWN_CT_PARAM.bits;
/// Does this have `Infer`?
- const HAS_TY_INFER = 1 << 3;
+ const HAS_TY_INFER = 1 << 3;
/// Does this have `ReVar`?
- const HAS_RE_INFER = 1 << 4;
+ const HAS_RE_INFER = 1 << 4;
/// Does this have `ConstKind::Infer`?
- const HAS_CT_INFER = 1 << 5;
+ const HAS_CT_INFER = 1 << 5;
/// Does this have inference variables? Used to determine whether
/// inference is required.
- const NEEDS_INFER = TypeFlags::HAS_TY_INFER.bits
- | TypeFlags::HAS_RE_INFER.bits
- | TypeFlags::HAS_CT_INFER.bits;
+ const NEEDS_INFER = TypeFlags::HAS_TY_INFER.bits
+ | TypeFlags::HAS_RE_INFER.bits
+ | TypeFlags::HAS_CT_INFER.bits;
/// Does this have `Placeholder`?
- const HAS_TY_PLACEHOLDER = 1 << 6;
+ const HAS_TY_PLACEHOLDER = 1 << 6;
/// Does this have `RePlaceholder`?
- const HAS_RE_PLACEHOLDER = 1 << 7;
+ const HAS_RE_PLACEHOLDER = 1 << 7;
/// Does this have `ConstKind::Placeholder`?
- const HAS_CT_PLACEHOLDER = 1 << 8;
+ const HAS_CT_PLACEHOLDER = 1 << 8;
/// `true` if there are "names" of regions and so forth
/// that are local to a particular fn/inferctxt
- const HAS_FREE_LOCAL_REGIONS = 1 << 9;
+ const HAS_KNOWN_FREE_LOCAL_REGIONS = 1 << 9;
/// `true` if there are "names" of types and regions and so forth
/// that are local to a particular fn
- const HAS_FREE_LOCAL_NAMES = TypeFlags::HAS_TY_PARAM.bits
- | TypeFlags::HAS_CT_PARAM.bits
- | TypeFlags::HAS_TY_INFER.bits
- | TypeFlags::HAS_CT_INFER.bits
- | TypeFlags::HAS_TY_PLACEHOLDER.bits
- | TypeFlags::HAS_CT_PLACEHOLDER.bits
- // We consider 'freshened' types and constants
- // to depend on a particular fn.
- // The freshening process throws away information,
- // which can make things unsuitable for use in a global
- // cache. Note that there is no 'fresh lifetime' flag -
- // freshening replaces all lifetimes with `ReErased`,
- // which is different from how types/const are freshened.
- | TypeFlags::HAS_TY_FRESH.bits
- | TypeFlags::HAS_CT_FRESH.bits
- | TypeFlags::HAS_FREE_LOCAL_REGIONS.bits;
+ const HAS_KNOWN_FREE_LOCAL_NAMES = TypeFlags::HAS_KNOWN_TY_PARAM.bits
+ | TypeFlags::HAS_KNOWN_CT_PARAM.bits
+ | TypeFlags::HAS_TY_INFER.bits
+ | TypeFlags::HAS_CT_INFER.bits
+ | TypeFlags::HAS_TY_PLACEHOLDER.bits
+ | TypeFlags::HAS_CT_PLACEHOLDER.bits
+ // We consider 'freshened' types and constants
+ // to depend on a particular fn.
+ // The freshening process throws away information,
+ // which can make things unsuitable for use in a global
+ // cache. Note that there is no 'fresh lifetime' flag -
+ // freshening replaces all lifetimes with `ReErased`,
+ // which is different from how types/const are freshened.
+ | TypeFlags::HAS_TY_FRESH.bits
+ | TypeFlags::HAS_CT_FRESH.bits
+ | TypeFlags::HAS_KNOWN_FREE_LOCAL_REGIONS.bits;
+
+ const HAS_POTENTIAL_FREE_LOCAL_NAMES = TypeFlags::HAS_KNOWN_FREE_LOCAL_NAMES.bits
+ | TypeFlags::HAS_UNKNOWN_DEFAULT_CONST_SUBSTS.bits;
/// Does this have `Projection`?
- const HAS_TY_PROJECTION = 1 << 10;
+ const HAS_TY_PROJECTION = 1 << 10;
/// Does this have `Opaque`?
- const HAS_TY_OPAQUE = 1 << 11;
+ const HAS_TY_OPAQUE = 1 << 11;
/// Does this have `ConstKind::Unevaluated`?
- const HAS_CT_PROJECTION = 1 << 12;
+ const HAS_CT_PROJECTION = 1 << 12;
/// Could this type be normalized further?
- const HAS_PROJECTION = TypeFlags::HAS_TY_PROJECTION.bits
- | TypeFlags::HAS_TY_OPAQUE.bits
- | TypeFlags::HAS_CT_PROJECTION.bits;
+ const HAS_PROJECTION = TypeFlags::HAS_TY_PROJECTION.bits
+ | TypeFlags::HAS_TY_OPAQUE.bits
+ | TypeFlags::HAS_CT_PROJECTION.bits;
/// Is an error type/const reachable?
- const HAS_ERROR = 1 << 13;
+ const HAS_ERROR = 1 << 13;
/// Does this have any region that "appears free" in the type?
/// Basically anything but `ReLateBound` and `ReErased`.
- const HAS_FREE_REGIONS = 1 << 14;
+ const HAS_KNOWN_FREE_REGIONS = 1 << 14;
+
+ const HAS_POTENTIAL_FREE_REGIONS = TypeFlags::HAS_KNOWN_FREE_REGIONS.bits
+ | TypeFlags::HAS_UNKNOWN_DEFAULT_CONST_SUBSTS.bits;
/// Does this have any `ReLateBound` regions? Used to check
/// if a global bound is safe to evaluate.
- const HAS_RE_LATE_BOUND = 1 << 15;
+ const HAS_RE_LATE_BOUND = 1 << 15;
/// Does this have any `ReErased` regions?
- const HAS_RE_ERASED = 1 << 16;
+ const HAS_RE_ERASED = 1 << 16;
/// Does this value have parameters/placeholders/inference variables which could be
/// replaced later, in a way that would change the results of `impl` specialization?
- const STILL_FURTHER_SPECIALIZABLE = 1 << 17;
+ ///
+ /// Note that this flag being set is not a guarantee, as it is also
+ /// set if there are any anon consts with unknown default substs.
+ const STILL_FURTHER_SPECIALIZABLE = 1 << 17;
/// Does this value have `InferTy::FreshTy/FreshIntTy/FreshFloatTy`?
- const HAS_TY_FRESH = 1 << 18;
+ const HAS_TY_FRESH = 1 << 18;
/// Does this value have `InferConst::Fresh`?
- const HAS_CT_FRESH = 1 << 19;
+ const HAS_CT_FRESH = 1 << 19;
+
+ /// Does this value have unknown default anon const substs.
+ ///
+ /// For more details refer to...
+ /// FIXME(@lcnr): ask me for now, still have to write all of this.
+ const HAS_UNKNOWN_DEFAULT_CONST_SUBSTS = 1 << 20;
+ /// Flags which can be influenced by default anon const substs.
+ const MAY_NEED_DEFAULT_CONST_SUBSTS = TypeFlags::HAS_KNOWN_RE_PARAM.bits
+ | TypeFlags::HAS_KNOWN_TY_PARAM.bits
+ | TypeFlags::HAS_KNOWN_CT_PARAM.bits
+ | TypeFlags::HAS_KNOWN_FREE_LOCAL_REGIONS.bits
+ | TypeFlags::HAS_KNOWN_FREE_REGIONS.bits;
+
}
}
diff --git a/compiler/rustc_typeck/Cargo.toml b/compiler/rustc_typeck/Cargo.toml
index eb55a8a..dd76a5e 100644
--- a/compiler/rustc_typeck/Cargo.toml
+++ b/compiler/rustc_typeck/Cargo.toml
@@ -1,5 +1,4 @@
[package]
-authors = ["The Rust Project Developers"]
name = "rustc_typeck"
version = "0.0.0"
edition = "2018"
@@ -27,3 +26,4 @@
rustc_infer = { path = "../rustc_infer" }
rustc_trait_selection = { path = "../rustc_trait_selection" }
rustc_ty_utils = { path = "../rustc_ty_utils" }
+rustc_lint = { path = "../rustc_lint" }
diff --git a/compiler/rustc_typeck/src/astconv/generics.rs b/compiler/rustc_typeck/src/astconv/generics.rs
index 456f2a9..fd0544a 100644
--- a/compiler/rustc_typeck/src/astconv/generics.rs
+++ b/compiler/rustc_typeck/src/astconv/generics.rs
@@ -39,8 +39,13 @@
);
if let GenericParamDefKind::Const { .. } = param.kind {
- if let GenericArg::Type(hir::Ty { kind: hir::TyKind::Infer, .. }) = arg {
+ if matches!(arg, GenericArg::Type(hir::Ty { kind: hir::TyKind::Infer, .. })) {
err.help("const arguments cannot yet be inferred with `_`");
+ if sess.is_nightly_build() {
+ err.help(
+ "add `#![feature(generic_arg_infer)]` to the crate attributes to enable",
+ );
+ }
}
}
@@ -249,14 +254,22 @@
(Some(&arg), Some(¶m)) => {
match (arg, ¶m.kind, arg_count.explicit_late_bound) {
(GenericArg::Lifetime(_), GenericParamDefKind::Lifetime, _)
- | (GenericArg::Type(_), GenericParamDefKind::Type { .. }, _)
- | (GenericArg::Const(_), GenericParamDefKind::Const { .. }, _) => {
+ | (
+ GenericArg::Type(_) | GenericArg::Infer(_),
+ GenericParamDefKind::Type { .. },
+ _,
+ )
+ | (
+ GenericArg::Const(_) | GenericArg::Infer(_),
+ GenericParamDefKind::Const { .. },
+ _,
+ ) => {
substs.push(ctx.provided_kind(param, arg));
args.next();
params.next();
}
(
- GenericArg::Type(_) | GenericArg::Const(_),
+ GenericArg::Infer(_) | GenericArg::Type(_) | GenericArg::Const(_),
GenericParamDefKind::Lifetime,
_,
) => {
@@ -325,6 +338,7 @@
.features()
.unordered_const_ty_params(),
},
+ GenericArg::Infer(_) => ParamKindOrd::Infer,
}),
Some(&format!(
"reorder the arguments: {}: `<{}>`",
@@ -445,9 +459,34 @@
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 = gen_args.own_counts();
- let infer_lifetimes = gen_pos != GenericArgPosition::Type && arg_counts.lifetimes == 0;
+
+ // Subtracting from param count to ensure type params synthesized from `impl Trait`
+ // cannot be explictly specified even with `explicit_generic_args_with_impl_trait`
+ // feature enabled.
+ let synth_type_param_count = if tcx.features().explicit_generic_args_with_impl_trait {
+ gen_params
+ .params
+ .iter()
+ .filter(|param| {
+ matches!(
+ param.kind,
+ ty::GenericParamDefKind::Type {
+ synthetic: Some(
+ hir::SyntheticTyParamKind::ImplTrait
+ | hir::SyntheticTyParamKind::FromAttr
+ ),
+ ..
+ }
+ )
+ })
+ .count()
+ } else {
+ 0
+ };
+ let named_type_param_count =
+ param_counts.types - has_self as usize - synth_type_param_count;
+ let infer_lifetimes =
+ gen_pos != GenericArgPosition::Type && !gen_args.has_lifetime_params();
if gen_pos != GenericArgPosition::Type && !gen_args.bindings.is_empty() {
Self::prohibit_assoc_ty_binding(tcx, gen_args.bindings[0].span);
@@ -505,7 +544,7 @@
let min_expected_lifetime_args = if infer_lifetimes { 0 } else { param_counts.lifetimes };
let max_expected_lifetime_args = param_counts.lifetimes;
- let num_provided_lifetime_args = arg_counts.lifetimes;
+ let num_provided_lifetime_args = gen_args.num_lifetime_params();
let lifetimes_correct = check_lifetime_args(
min_expected_lifetime_args,
@@ -576,14 +615,14 @@
- default_counts.consts
};
debug!("expected_min: {:?}", expected_min);
- debug!("arg_counts.lifetimes: {:?}", arg_counts.lifetimes);
+ debug!("arg_counts.lifetimes: {:?}", gen_args.num_lifetime_params());
check_types_and_consts(
expected_min,
param_counts.consts + named_type_param_count,
- arg_counts.consts + arg_counts.types,
+ gen_args.num_generic_params(),
param_counts.lifetimes + has_self as usize,
- arg_counts.lifetimes,
+ gen_args.num_lifetime_params(),
)
};
@@ -603,26 +642,21 @@
seg: &hir::PathSegment<'_>,
generics: &ty::Generics,
) -> bool {
- let explicit = !seg.infer_args;
- let impl_trait = generics.params.iter().any(|param| {
- matches!(
- param.kind,
- ty::GenericParamDefKind::Type {
- synthetic: Some(
- hir::SyntheticTyParamKind::ImplTrait | hir::SyntheticTyParamKind::FromAttr,
- ),
- ..
- }
- )
- });
+ if seg.infer_args || tcx.features().explicit_generic_args_with_impl_trait {
+ return false;
+ }
- if explicit && impl_trait {
+ let impl_trait = generics.has_impl_trait();
+
+ if impl_trait {
let spans = seg
.args()
.args
.iter()
.filter_map(|arg| match arg {
- GenericArg::Type(_) | GenericArg::Const(_) => Some(arg.span()),
+ GenericArg::Infer(_) | GenericArg::Type(_) | GenericArg::Const(_) => {
+ Some(arg.span())
+ }
_ => None,
})
.collect::<Vec<_>>();
@@ -659,8 +693,7 @@
position: GenericArgPosition,
) -> ExplicitLateBound {
let param_counts = def.own_counts();
- let arg_counts = args.own_counts();
- let infer_lifetimes = position != GenericArgPosition::Type && arg_counts.lifetimes == 0;
+ let infer_lifetimes = position != GenericArgPosition::Type && !args.has_lifetime_params();
if infer_lifetimes {
return ExplicitLateBound::No;
@@ -673,7 +706,7 @@
let span = args.args[0].span();
if position == GenericArgPosition::Value
- && arg_counts.lifetimes != param_counts.lifetimes
+ && args.num_lifetime_params() != param_counts.lifetimes
{
let mut err = tcx.sess.struct_span_err(span, msg);
err.span_note(span_late, note);
diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs
index f55e274..059e0ca 100644
--- a/compiler/rustc_typeck/src/astconv/mod.rs
+++ b/compiler/rustc_typeck/src/astconv/mod.rs
@@ -20,8 +20,8 @@
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::intravisit::{walk_generics, Visitor as _};
use rustc_hir::lang_items::LangItem;
-use rustc_hir::{Constness, GenericArg, GenericArgs};
-use rustc_middle::ty::subst::{self, InternalSubsts, Subst, SubstsRef};
+use rustc_hir::{GenericArg, GenericArgs};
+use rustc_middle::ty::subst::{self, GenericArgKind, InternalSubsts, Subst, SubstsRef};
use rustc_middle::ty::GenericParamDefKind;
use rustc_middle::ty::{self, Const, DefIdTree, Ty, TyCtxt, TypeFoldable};
use rustc_session::lint::builtin::AMBIGUOUS_ASSOCIATED_ITEMS;
@@ -47,8 +47,6 @@
fn item_def_id(&self) -> Option<DefId>;
- fn default_constness_for_trait_bounds(&self) -> Constness;
-
/// Returns predicates in scope of the form `X: Foo<T>`, where `X`
/// is a type parameter `X` with the given id `def_id` and T
/// matches `assoc_name`. This is a subset of the full set of
@@ -394,7 +392,7 @@
if self.is_object && has_default {
let default_ty = tcx.at(self.span).type_of(param.def_id);
let self_param = tcx.types.self_param;
- if default_ty.walk().any(|arg| arg == self_param.into()) {
+ if default_ty.walk(tcx).any(|arg| arg == self_param.into()) {
// There is no suitable inference default for a type parameter
// that references self, in an object type.
return true;
@@ -461,6 +459,43 @@
)
.into()
}
+ (&GenericParamDefKind::Const { has_default }, hir::GenericArg::Infer(inf)) => {
+ if has_default {
+ tcx.const_param_default(param.def_id).into()
+ } else if self.astconv.allow_ty_infer() {
+ // FIXME(const_generics): Actually infer parameter here?
+ todo!()
+ } else {
+ self.inferred_params.push(inf.span);
+ tcx.ty_error().into()
+ }
+ }
+ (
+ &GenericParamDefKind::Type { has_default, .. },
+ hir::GenericArg::Infer(inf),
+ ) => {
+ if has_default {
+ tcx.check_optional_stability(
+ param.def_id,
+ Some(arg.id()),
+ arg.span(),
+ None,
+ |_, _| {
+ // Default generic parameters may not be marked
+ // with stability attributes, i.e. when the
+ // default parameter was defined at the same time
+ // as the rest of the type. As such, we ignore missing
+ // stability attributes.
+ },
+ );
+ }
+ if self.astconv.allow_ty_infer() {
+ self.astconv.ast_ty_to_ty(&inf.to_ty()).into()
+ } else {
+ self.inferred_params.push(inf.span);
+ tcx.ty_error().into()
+ }
+ }
_ => unreachable!(),
}
}
@@ -488,12 +523,20 @@
tcx.ty_error().into()
} else {
// This is a default type parameter.
+ let substs = substs.unwrap();
+ if substs.iter().any(|arg| match arg.unpack() {
+ GenericArgKind::Type(ty) => ty.references_error(),
+ _ => false,
+ }) {
+ // Avoid ICE #86756 when type error recovery goes awry.
+ return tcx.ty_error().into();
+ }
self.astconv
.normalize_ty(
self.span,
tcx.at(self.span).type_of(param.def_id).subst_spanned(
tcx,
- substs.unwrap(),
+ substs,
Some(self.span),
),
)
@@ -679,7 +722,7 @@
&self,
trait_ref: &hir::TraitRef<'_>,
span: Span,
- constness: Constness,
+ constness: ty::BoundConstness,
self_ty: Ty<'tcx>,
bounds: &mut Bounds<'tcx>,
speculative: bool,
@@ -750,7 +793,7 @@
let bound_vars = tcx.late_bound_vars(hir_id);
let poly_trait_ref =
ty::Binder::bind_with_vars(ty::TraitRef::new(trait_def_id, substs), bound_vars);
- bounds.trait_bounds.push((poly_trait_ref, span, Constness::NotConst));
+ bounds.trait_bounds.push((poly_trait_ref, span, ty::BoundConstness::NotConst));
let mut dup_bindings = FxHashMap::default();
for binding in assoc_bindings {
@@ -875,14 +918,13 @@
bounds: &mut Bounds<'tcx>,
bound_vars: &'tcx ty::List<ty::BoundVariableKind>,
) {
- let constness = self.default_constness_for_trait_bounds();
for ast_bound in ast_bounds {
match *ast_bound {
hir::GenericBound::Trait(ref b, hir::TraitBoundModifier::None) => {
self.instantiate_poly_trait_ref(
&b.trait_ref,
b.span,
- constness,
+ ty::BoundConstness::NotConst,
param_ty,
bounds,
false,
@@ -892,13 +934,14 @@
self.instantiate_poly_trait_ref(
&b.trait_ref,
b.span,
- Constness::NotConst,
+ ty::BoundConstness::ConstIfConst,
param_ty,
bounds,
false,
);
}
- hir::GenericBound::Trait(_, hir::TraitBoundModifier::Maybe) => {}
+ hir::GenericBound::Trait(_, hir::TraitBoundModifier::Maybe)
+ | hir::GenericBound::Unsized(_) => {}
hir::GenericBound::LangItemTrait(lang_item, span, hir_id, args) => self
.instantiate_lang_item_trait_ref(
lang_item, span, hir_id, args, param_ty, bounds,
@@ -1205,7 +1248,7 @@
} = self.instantiate_poly_trait_ref(
&trait_bound.trait_ref,
trait_bound.span,
- Constness::NotConst,
+ ty::BoundConstness::NotConst,
dummy_self,
&mut bounds,
false,
@@ -1284,7 +1327,7 @@
.filter(|(trait_ref, _, _)| !tcx.trait_is_auto(trait_ref.def_id()));
for (base_trait_ref, span, constness) in regular_traits_refs_spans {
- assert_eq!(constness, Constness::NotConst);
+ assert_eq!(constness, ty::BoundConstness::NotConst);
for obligation in traits::elaborate_trait_ref(tcx, base_trait_ref) {
debug!(
@@ -1294,7 +1337,7 @@
let bound_predicate = obligation.predicate.kind();
match bound_predicate.skip_binder() {
- ty::PredicateKind::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())
@@ -1308,7 +1351,7 @@
// A `Self` within the original bound will be substituted with a
// `trait_object_dummy_self`, so check for that.
let references_self =
- pred.skip_binder().ty.walk().any(|arg| arg == dummy_self.into());
+ pred.skip_binder().ty.walk(tcx).any(|arg| arg == dummy_self.into());
// If the projection output contains `Self`, force the user to
// elaborate it explicitly to avoid a lot of complexity.
@@ -1922,6 +1965,14 @@
has_err = true;
(ct.span, "const")
}
+ hir::GenericArg::Infer(inf) => {
+ if err_for_ty {
+ continue;
+ }
+ has_err = true;
+ err_for_ty = true;
+ (inf.span, "generic")
+ }
};
let mut err = struct_span_err!(
self.tcx().sess,
@@ -2150,7 +2201,7 @@
self.prohibit_generics(path.segments);
// Try to evaluate any array length constants.
let normalized_ty = self.normalize_ty(span, tcx.at(span).type_of(def_id));
- if forbid_generic && normalized_ty.needs_subst() {
+ if forbid_generic && normalized_ty.definitely_needs_subst(tcx) {
let mut err = tcx.sess.struct_span_err(
path.span,
"generic `Self` types are currently not permitted in anonymous constants",
@@ -2296,7 +2347,7 @@
}
hir::TyKind::Infer => {
// Infer also appears as the type of arguments or return
- // values in a ExprKind::Closure, or as
+ // values in an ExprKind::Closure, or as
// the type of local variables. Both of these cases are
// handled specially and will not descend into this routine.
self.ty_infer(None, ast_ty.span)
@@ -2326,12 +2377,10 @@
if let Some(i) = (param.index as usize).checked_sub(generics.parent_count) {
// Our own parameters are the resolved lifetimes.
match param.kind {
- GenericParamDefKind::Lifetime => {
- if let hir::GenericArg::Lifetime(lifetime) = &lifetimes[i] {
- self.ast_region_to_region(lifetime, None).into()
- } else {
- bug!()
- }
+ GenericParamDefKind::Lifetime
+ if let hir::GenericArg::Lifetime(lifetime) = &lifetimes[i] =>
+ {
+ self.ast_region_to_region(lifetime, None).into()
}
_ => bug!(),
}
diff --git a/compiler/rustc_typeck/src/bounds.rs b/compiler/rustc_typeck/src/bounds.rs
index 5d20064..24474e1 100644
--- a/compiler/rustc_typeck/src/bounds.rs
+++ b/compiler/rustc_typeck/src/bounds.rs
@@ -1,7 +1,6 @@
//! Bounds are restrictions applied to some types after they've been converted into the
//! `ty` form from the HIR.
-use rustc_hir::Constness;
use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, WithConstness};
use rustc_span::Span;
@@ -30,7 +29,7 @@
/// A list of trait bounds. So if you had `T: Debug` this would be
/// `T: Debug`. Note that the self-type is explicit here.
- pub trait_bounds: Vec<(ty::PolyTraitRef<'tcx>, Span, Constness)>,
+ pub trait_bounds: Vec<(ty::PolyTraitRef<'tcx>, Span, ty::BoundConstness)>,
/// A list of projection equality bounds. So if you had `T:
/// Iterator<Item = u32>` this would include `<T as
diff --git a/compiler/rustc_typeck/src/check/_match.rs b/compiler/rustc_typeck/src/check/_match.rs
index d056f2c..01227ca 100644
--- a/compiler/rustc_typeck/src/check/_match.rs
+++ b/compiler/rustc_typeck/src/check/_match.rs
@@ -13,42 +13,8 @@
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> {
+ #[instrument(skip(self), level = "debug")]
pub fn check_match(
&self,
expr: &'tcx hir::Expr<'tcx>,
@@ -59,27 +25,9 @@
) -> Ty<'tcx> {
let tcx = self.tcx;
- use hir::MatchSource::*;
- let (source_if, if_no_else, force_scrutinee_bool) = match match_src {
- IfLetDesugar { contains_else_clause, .. } => (true, !contains_else_clause, false),
- WhileDesugar => (false, false, true),
- _ => (false, false, false),
- };
-
- // Type check the discriminant and get its type.
- let scrutinee_ty = if force_scrutinee_bool {
- // Here we want to ensure:
- //
- // 1. That default match bindings are *not* accepted in the condition of an
- // `if` expression. E.g. given `fn foo() -> &bool;` we reject `if foo() { .. }`.
- //
- // 2. By expecting `bool` for `expr` we get nice diagnostics for e.g. `if x = y { .. }`.
- //
- // FIXME(60707): Consider removing hack with principled solution.
- self.check_expr_has_type_or_error(scrut, self.tcx.types.bool, |_| {})
- } else {
- self.demand_scrutinee_type(scrut, arms_contain_ref_bindings(arms), arms.is_empty())
- };
+ let acrb = arms_contain_ref_bindings(arms);
+ let scrutinee_ty = self.demand_scrutinee_type(scrut, acrb, arms.is_empty());
+ debug!(?scrutinee_ty);
// If there are no arms, that is a diverging match; a special case.
if arms.is_empty() {
@@ -87,7 +35,7 @@
return tcx.types.never;
}
- self.warn_arms_when_scrutinee_diverges(arms, match_src);
+ self.warn_arms_when_scrutinee_diverges(arms);
// Otherwise, we have to union together the types that the arms produce and so forth.
let scrut_diverges = self.diverges.replace(Diverges::Maybe);
@@ -147,128 +95,95 @@
}
self.diverges.set(Diverges::Maybe);
- let arm_ty = if source_if
- && if_no_else
- && i != 0
- && 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`
- // clause to avoid duplicated type errors. (#60254)
- self.check_expr_with_expectation(&arm.body, expected)
- };
+
+ let arm_ty = self.check_expr_with_expectation(&arm.body, expected);
all_arms_diverge &= self.diverges.get();
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;
- match (i, if_no_else) {
- (0, _) => coercion.coerce(self, &self.misc(expr.span), &arm.body, arm_ty),
- (_, true) => {} // Handled above to avoid duplicated type errors (#60254).
- (_, _) => {
- let then_ty = prior_arm_ty.unwrap();
- let cause = self.if_cause(
- expr.span,
- then_expr,
- &arm.body,
- then_ty,
- arm_ty,
- opt_suggest_box_span,
- );
- coercion.coerce(self, &cause, &arm.body, arm_ty);
- }
- }
- } else {
- let (arm_span, semi_span) =
- self.get_appropriate_arm_semicolon_removal_span(&arms, i, prior_arm_ty, arm_ty);
- let (span, code) = match i {
- // The reason for the first arm to fail is not that the match arms diverge,
- // but rather that there's a prior obligation that doesn't hold.
- 0 => (arm_span, ObligationCauseCode::BlockTailExpression(arm.body.hir_id)),
- _ => (
- expr.span,
- ObligationCauseCode::MatchExpressionArm(box MatchExpressionArmCause {
- arm_span,
- scrut_span: scrut.span,
- semi_span,
- source: match_src,
- prior_arms: other_arms.clone(),
- last_ty: prior_arm_ty.unwrap(),
- scrut_hir_id: scrut.hir_id,
- opt_suggest_box_span,
- }),
- ),
- };
- let cause = self.cause(span, code);
+ let (arm_span, semi_span) =
+ self.get_appropriate_arm_semicolon_removal_span(&arms, i, prior_arm_ty, arm_ty);
+ let (span, code) = match i {
+ // The reason for the first arm to fail is not that the match arms diverge,
+ // but rather that there's a prior obligation that doesn't hold.
+ 0 => (arm_span, ObligationCauseCode::BlockTailExpression(arm.body.hir_id)),
+ _ => (
+ expr.span,
+ ObligationCauseCode::MatchExpressionArm(Box::new(MatchExpressionArmCause {
+ arm_span,
+ scrut_span: scrut.span,
+ semi_span,
+ source: match_src,
+ prior_arms: other_arms.clone(),
+ last_ty: prior_arm_ty.unwrap(),
+ scrut_hir_id: scrut.hir_id,
+ opt_suggest_box_span,
+ })),
+ ),
+ };
+ let cause = self.cause(span, code);
- // This is the moral equivalent of `coercion.coerce(self, cause, arm.body, arm_ty)`.
- // We use it this way to be able to expand on the potential error and detect when a
- // `match` tail statement could be a tail expression instead. If so, we suggest
- // removing the stray semicolon.
- coercion.coerce_inner(
- self,
- &cause,
- Some(&arm.body),
- arm_ty,
- Some(&mut |err: &mut DiagnosticBuilder<'_>| {
- let can_coerce_to_return_ty = match self.ret_coercion.as_ref() {
- Some(ret_coercion) if self.in_tail_expr => {
- let ret_ty = ret_coercion.borrow().expected_ty();
- let ret_ty = self.inh.infcx.shallow_resolve(ret_ty);
- self.can_coerce(arm_ty, ret_ty)
- && prior_arm_ty.map_or(true, |t| self.can_coerce(t, ret_ty))
- // The match arms need to unify for the case of `impl Trait`.
- && !matches!(ret_ty.kind(), ty::Opaque(..))
- }
- _ => false,
- };
- if let (Expectation::IsLast(stmt), Some(ret), true) =
- (orig_expected, self.ret_type_span, can_coerce_to_return_ty)
- {
- let semi_span = expr.span.shrink_to_hi().with_hi(stmt.hi());
- let mut ret_span: MultiSpan = semi_span.into();
- ret_span.push_span_label(
- expr.span,
- "this could be implicitly returned but it is a statement, not a \
- tail expression"
- .to_owned(),
- );
- ret_span.push_span_label(
- ret,
- "the `match` arms can conform to this return type".to_owned(),
- );
- ret_span.push_span_label(
- semi_span,
- "the `match` is a statement because of this semicolon, consider \
- removing it"
- .to_owned(),
- );
- err.span_note(
- ret_span,
- "you might have meant to return the `match` expression",
- );
- err.tool_only_span_suggestion(
- semi_span,
- "remove this semicolon",
- String::new(),
- Applicability::MaybeIncorrect,
- );
+ // This is the moral equivalent of `coercion.coerce(self, cause, arm.body, arm_ty)`.
+ // We use it this way to be able to expand on the potential error and detect when a
+ // `match` tail statement could be a tail expression instead. If so, we suggest
+ // removing the stray semicolon.
+ coercion.coerce_inner(
+ self,
+ &cause,
+ Some(&arm.body),
+ arm_ty,
+ Some(&mut |err: &mut DiagnosticBuilder<'_>| {
+ let can_coerce_to_return_ty = match self.ret_coercion.as_ref() {
+ Some(ret_coercion) if self.in_tail_expr => {
+ let ret_ty = ret_coercion.borrow().expected_ty();
+ let ret_ty = self.inh.infcx.shallow_resolve(ret_ty);
+ self.can_coerce(arm_ty, ret_ty)
+ && prior_arm_ty.map_or(true, |t| self.can_coerce(t, ret_ty))
+ // The match arms need to unify for the case of `impl Trait`.
+ && !matches!(ret_ty.kind(), ty::Opaque(..))
}
- }),
- false,
- );
+ _ => false,
+ };
+ if let (Expectation::IsLast(stmt), Some(ret), true) =
+ (orig_expected, self.ret_type_span, can_coerce_to_return_ty)
+ {
+ let semi_span = expr.span.shrink_to_hi().with_hi(stmt.hi());
+ let mut ret_span: MultiSpan = semi_span.into();
+ ret_span.push_span_label(
+ expr.span,
+ "this could be implicitly returned but it is a statement, not a \
+ tail expression"
+ .to_owned(),
+ );
+ ret_span.push_span_label(
+ ret,
+ "the `match` arms can conform to this return type".to_owned(),
+ );
+ ret_span.push_span_label(
+ semi_span,
+ "the `match` is a statement because of this semicolon, consider \
+ removing it"
+ .to_owned(),
+ );
+ err.span_note(
+ ret_span,
+ "you might have meant to return the `match` expression",
+ );
+ err.tool_only_span_suggestion(
+ semi_span,
+ "remove this semicolon",
+ String::new(),
+ Applicability::MaybeIncorrect,
+ );
+ }
+ }),
+ false,
+ );
- other_arms.push(arm_span);
- if other_arms.len() > 5 {
- other_arms.remove(0);
- }
+ other_arms.push(arm_span);
+ if other_arms.len() > 5 {
+ other_arms.remove(0);
}
prior_arm_ty = Some(arm_ty);
}
@@ -318,39 +233,27 @@
/// When the previously checked expression (the scrutinee) diverges,
/// warn the user about the match arms being unreachable.
- fn warn_arms_when_scrutinee_diverges(
- &self,
- arms: &'tcx [hir::Arm<'tcx>],
- source: hir::MatchSource,
- ) {
- use hir::MatchSource::*;
- let msg = match source {
- IfLetDesugar { .. } => "block in `if` expression",
- WhileDesugar { .. } | WhileLetDesugar { .. } => "block in `while` expression",
- _ => "arm",
- };
+ fn warn_arms_when_scrutinee_diverges(&self, arms: &'tcx [hir::Arm<'tcx>]) {
for arm in arms {
- self.warn_if_unreachable(arm.body.hir_id, arm.body.span, msg);
+ self.warn_if_unreachable(arm.body.hir_id, arm.body.span, "arm");
}
}
/// 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.
- pub(crate) fn if_fallback_coercion<F, T>(
+ pub(super) fn if_fallback_coercion<T>(
&self,
span: Span,
then_expr: &'tcx hir::Expr<'tcx>,
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 = ret_reason(then_expr.hir_id, span);
+ let ret_reason = self.maybe_get_coercion_reason(then_expr.hir_id, span);
let cause = self.cause(span, ObligationCauseCode::IfExpressionWithNoElse);
let mut error = false;
coercion.coerce_forced_unit(
@@ -373,23 +276,35 @@
error
}
- 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)
+ fn maybe_get_coercion_reason(&self, hir_id: hir::HirId, sp: Span) -> Option<(Span, String)> {
+ let node = {
+ let rslt = self.tcx.hir().get_parent_node(self.tcx.hir().get_parent_node(hir_id));
+ self.tcx.hir().get(rslt)
+ };
+ 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)))
+ });
+ }
+ }
}
- );
-
- 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)
+ if let hir::Node::Local(hir::Local { ty: Some(_), pat, .. }) = node {
+ return Some((pat.span, "expected because of this assignment".to_string()));
}
- );
+ None
+ }
pub(crate) fn if_cause(
&self,
@@ -484,17 +399,17 @@
// Finally construct the cause:
self.cause(
error_sp,
- ObligationCauseCode::IfExpression(box IfExpressionCause {
+ ObligationCauseCode::IfExpression(Box::new(IfExpressionCause {
then: then_sp,
else_sp: error_sp,
outer: outer_sp,
semicolon: remove_semicolon,
opt_suggest_box_span,
- }),
+ })),
)
}
- fn demand_scrutinee_type(
+ pub(super) fn demand_scrutinee_type(
&self,
scrut: &'tcx hir::Expr<'tcx>,
contains_ref_bindings: Option<hir::Mutability>,
@@ -595,24 +510,27 @@
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)))
+ (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 {
+ self.infcx.instantiate_opaque_types(self.body_id, self.param_env, ty, span);
+ assert!(
+ impl_trait_ret_ty.obligations.is_empty(),
+ "we should never get new obligations here"
+ );
+ let obligations = self.fulfillment_cx.borrow().pending_obligations();
+ let mut suggest_box = !obligations.is_empty();
+ for o in 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, &[]),
- },
+ ty::PredicateKind::Trait(t) => {
+ 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,
- );
+ constness: t.constness,
+ });
let obl = Obligation::new(
o.cause.clone(),
self.param_env,
diff --git a/compiler/rustc_typeck/src/check/cast.rs b/compiler/rustc_typeck/src/check/cast.rs
index b3808ea..1455069 100644
--- a/compiler/rustc_typeck/src/check/cast.rs
+++ b/compiler/rustc_typeck/src/check/cast.rs
@@ -51,6 +51,7 @@
/// Reifies a cast check to be checked once we have full type information for
/// a function context.
+#[derive(Debug)]
pub struct CastCheck<'tcx> {
expr: &'tcx hir::Expr<'tcx>,
expr_ty: Ty<'tcx>,
@@ -603,11 +604,10 @@
});
}
+ #[instrument(skip(fcx), level = "debug")]
pub fn check(mut self, fcx: &FnCtxt<'a, 'tcx>) {
- self.expr_ty = fcx.structurally_resolved_type(self.span, self.expr_ty);
- self.cast_ty = fcx.structurally_resolved_type(self.span, self.cast_ty);
-
- debug!("check_cast({}, {:?} as {:?})", self.expr.hir_id, self.expr_ty, self.cast_ty);
+ self.expr_ty = fcx.structurally_resolved_type(self.expr.span, self.expr_ty);
+ self.cast_ty = fcx.structurally_resolved_type(self.cast_span, self.cast_ty);
if !fcx.type_is_known_to_be_sized_modulo_regions(self.cast_ty, self.span) {
self.report_cast_to_unsized_type(fcx);
diff --git a/compiler/rustc_typeck/src/check/check.rs b/compiler/rustc_typeck/src/check/check.rs
index b5db333..8a91738 100644
--- a/compiler/rustc_typeck/src/check/check.rs
+++ b/compiler/rustc_typeck/src/check/check.rs
@@ -78,6 +78,7 @@
fn_id: hir::HirId,
body: &'tcx hir::Body<'tcx>,
can_be_generator: Option<hir::Movability>,
+ return_type_pre_known: bool,
) -> (FnCtxt<'a, 'tcx>, Option<GeneratorTypes<'tcx>>) {
let mut fn_sig = fn_sig;
@@ -87,6 +88,7 @@
// in the case of closures, based on the outer context.
let mut fcx = FnCtxt::new(inherited, param_env, body.value.hir_id);
fcx.ps.set(UnsafetyState::function(fn_sig.unsafety, fn_id));
+ fcx.return_type_pre_known = return_type_pre_known;
let tcx = fcx.tcx;
let sess = tcx.sess;
@@ -94,69 +96,8 @@
let declared_ret_ty = fn_sig.output();
- let feature = match tcx.hir().get(fn_id) {
- // TAIT usage in function return position.
- // Example:
- //
- // ```rust
- // type Foo = impl Debug;
- // fn bar() -> Foo { 42 }
- // ```
- Node::Item(hir::Item { kind: ItemKind::Fn(..), .. }) |
- // TAIT usage in associated function return position.
- //
- // Example with a free type alias:
- //
- // ```rust
- // type Foo = impl Debug;
- // impl SomeTrait for SomeType {
- // fn bar() -> Foo { 42 }
- // }
- // ```
- //
- // Example with an associated TAIT:
- //
- // ```rust
- // impl SomeTrait for SomeType {
- // type Foo = impl Debug;
- // fn bar() -> Self::Foo { 42 }
- // }
- // ```
- Node::ImplItem(hir::ImplItem {
- kind: hir::ImplItemKind::Fn(..), ..
- }) => None,
- // Forbid TAIT in trait declarations for now.
- // Examples:
- //
- // ```rust
- // type Foo = impl Debug;
- // trait Bar {
- // fn bar() -> Foo;
- // }
- // trait Bop {
- // type Bop: PartialEq<Foo>;
- // }
- // ```
- Node::TraitItem(hir::TraitItem {
- kind: hir::TraitItemKind::Fn(..),
- ..
- }) |
- // Forbid TAIT in closure return position for now.
- // Example:
- //
- // ```rust
- // type Foo = impl Debug;
- // let x = |y| -> Foo { 42 + y };
- // ```
- Node::Expr(hir::Expr { kind: hir::ExprKind::Closure(..), .. }) => Some(sym::type_alias_impl_trait),
- node => bug!("Item being checked wasn't a function/closure: {:?}", node),
- };
- let revealed_ret_ty = fcx.instantiate_opaque_types_from_value(
- fn_id,
- declared_ret_ty,
- decl.output.span(),
- feature,
- );
+ let revealed_ret_ty =
+ fcx.instantiate_opaque_types_from_value(declared_ret_ty, decl.output.span());
debug!("check_fn: declared_ret_ty: {}, revealed_ret_ty: {}", declared_ret_ty, revealed_ret_ty);
fcx.ret_coercion = Some(RefCell::new(CoerceMany::new(revealed_ret_ty)));
fcx.ret_type_span = Some(decl.output.span());
@@ -529,14 +470,17 @@
debug!(?item, ?span);
struct FoundParentLifetime;
- struct FindParentLifetimeVisitor<'tcx>(&'tcx ty::Generics);
+ struct FindParentLifetimeVisitor<'tcx>(TyCtxt<'tcx>, &'tcx ty::Generics);
impl<'tcx> ty::fold::TypeVisitor<'tcx> for FindParentLifetimeVisitor<'tcx> {
type BreakTy = FoundParentLifetime;
+ fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
+ Some(self.0)
+ }
fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
debug!("FindParentLifetimeVisitor: r={:?}", r);
if let RegionKind::ReEarlyBound(ty::EarlyBoundRegion { index, .. }) = r {
- if *index < self.0.parent_count as u32 {
+ if *index < self.1.parent_count as u32 {
return ControlFlow::Break(FoundParentLifetime);
} else {
return ControlFlow::CONTINUE;
@@ -558,21 +502,24 @@
}
struct ProhibitOpaqueVisitor<'tcx> {
+ tcx: TyCtxt<'tcx>,
opaque_identity_ty: Ty<'tcx>,
generics: &'tcx ty::Generics,
- tcx: TyCtxt<'tcx>,
selftys: Vec<(Span, Option<String>)>,
}
impl<'tcx> ty::fold::TypeVisitor<'tcx> for ProhibitOpaqueVisitor<'tcx> {
type BreakTy = Ty<'tcx>;
+ fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
+ Some(self.tcx)
+ }
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
debug!("check_opaque_for_inheriting_lifetimes: (visit_ty) t={:?}", t);
if t == self.opaque_identity_ty {
ControlFlow::CONTINUE
} else {
- t.super_visit_with(&mut FindParentLifetimeVisitor(self.generics))
+ t.super_visit_with(&mut FindParentLifetimeVisitor(self.tcx, self.generics))
.map_break(|FoundParentLifetime| t)
}
}
@@ -711,10 +658,11 @@
let misc_cause = traits::ObligationCause::misc(span, hir_id);
- let (_, opaque_type_map) = inh.register_infer_ok_obligations(
- infcx.instantiate_opaque_types(def_id, hir_id, param_env, opaque_ty, span),
+ let _ = inh.register_infer_ok_obligations(
+ infcx.instantiate_opaque_types(hir_id, param_env, opaque_ty, span),
);
+ let opaque_type_map = infcx.inner.borrow().opaque_types.clone();
for (OpaqueTypeKey { def_id, substs }, opaque_defn) in opaque_type_map {
match infcx
.at(&misc_cause, param_env)
@@ -1220,6 +1168,7 @@
match e.kind() {
ty::Param(_) => (), // pass struct<T>(T, T, T, T) through, let monomorphization catch errors
ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::RawPtr(_) => (), // struct(u8, u8, u8, u8) is ok
+ ty::Array(t, _) if matches!(t.kind(), ty::Param(_)) => (), // pass struct<T>([T; N]) through, let monomorphization catch errors
ty::Array(t, _clen)
if matches!(
t.kind(),
@@ -1472,15 +1421,17 @@
Some(ref expr) => tcx.hir().span(expr.hir_id),
None => v.span,
};
+ let display_discr = display_discriminant_value(tcx, v, discr.val);
+ let display_discr_i = display_discriminant_value(tcx, variant_i, disr_vals[i].val);
struct_span_err!(
tcx.sess,
span,
E0081,
"discriminant value `{}` already exists",
- disr_vals[i]
+ discr.val,
)
- .span_label(i_span, format!("first use of `{}`", disr_vals[i]))
- .span_label(span, format!("enum already has `{}`", disr_vals[i]))
+ .span_label(i_span, format!("first use of {}", display_discr_i))
+ .span_label(span, format!("enum already has {}", display_discr))
.emit();
}
disr_vals.push(discr);
@@ -1490,6 +1441,25 @@
check_transparent(tcx, sp, def);
}
+/// Format an enum discriminant value for use in a diagnostic message.
+fn display_discriminant_value<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ variant: &hir::Variant<'_>,
+ evaluated: u128,
+) -> String {
+ if let Some(expr) = &variant.disr_expr {
+ let body = &tcx.hir().body(expr.body).value;
+ if let hir::ExprKind::Lit(lit) = &body.kind {
+ if let rustc_ast::LitKind::Int(lit_value, _int_kind) = &lit.node {
+ if evaluated != *lit_value {
+ return format!("`{}` (overflowed from `{}`)", evaluated, lit_value);
+ }
+ }
+ }
+ }
+ format!("`{}`", evaluated)
+}
+
pub(super) fn check_type_params_are_used<'tcx>(
tcx: TyCtxt<'tcx>,
generics: &ty::Generics,
@@ -1512,7 +1482,7 @@
return;
}
- for leaf in ty.walk() {
+ for leaf in ty.walk(tcx) {
if let GenericArgKind::Type(leaf_ty) = leaf.unpack() {
if let ty::Param(param) = leaf_ty.kind() {
debug!("found use of ty param {:?}", param);
@@ -1614,8 +1584,12 @@
.filter_map(|e| typeck_results.node_type_opt(e.hir_id).map(|t| (e.span, t)))
.filter(|(_, ty)| !matches!(ty.kind(), ty::Never))
{
- struct VisitTypes(Vec<DefId>);
- impl<'tcx> ty::fold::TypeVisitor<'tcx> for VisitTypes {
+ struct OpaqueTypeCollector(Vec<DefId>);
+ impl<'tcx> ty::fold::TypeVisitor<'tcx> for OpaqueTypeCollector {
+ fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
+ // Default anon const substs cannot contain opaque types.
+ None
+ }
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
match *t.kind() {
ty::Opaque(def, _) => {
@@ -1626,7 +1600,7 @@
}
}
}
- let mut visitor = VisitTypes(vec![]);
+ let mut visitor = OpaqueTypeCollector(vec![]);
ty.visit_with(&mut visitor);
for def_id in visitor.0 {
let ty_span = tcx.def_span(def_id);
diff --git a/compiler/rustc_typeck/src/check/closure.rs b/compiler/rustc_typeck/src/check/closure.rs
index 22d3dc6..65ba1c0 100644
--- a/compiler/rustc_typeck/src/check/closure.rs
+++ b/compiler/rustc_typeck/src/check/closure.rs
@@ -73,8 +73,19 @@
debug!("check_closure: ty_of_closure returns {:?}", liberated_sig);
- let generator_types =
- check_fn(self, self.param_env, liberated_sig, decl, expr.hir_id, body, gen).1;
+ let return_type_pre_known = !liberated_sig.output().is_ty_infer();
+
+ let generator_types = check_fn(
+ self,
+ self.param_env,
+ liberated_sig,
+ decl,
+ expr.hir_id,
+ body,
+ gen,
+ return_type_pre_known,
+ )
+ .1;
let parent_substs = InternalSubsts::identity_for_item(
self.tcx,
@@ -606,7 +617,7 @@
/// Invoked when we are translating the generator that results
/// from desugaring an `async fn`. Returns the "sugared" return
/// type of the `async fn` -- that is, the return type that the
- /// user specified. The "desugared" return type is a `impl
+ /// user specified. The "desugared" return type is an `impl
/// Future<Output = T>`, so we do this by searching through the
/// obligations to extract the `T`.
fn deduce_future_output_from_obligations(&self, expr_def_id: DefId) -> Option<Ty<'tcx>> {
diff --git a/compiler/rustc_typeck/src/check/coercion.rs b/compiler/rustc_typeck/src/check/coercion.rs
index ba76b9c..3bfab9d 100644
--- a/compiler/rustc_typeck/src/check/coercion.rs
+++ b/compiler/rustc_typeck/src/check/coercion.rs
@@ -42,6 +42,7 @@
use rustc_hir::def_id::DefId;
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_infer::infer::{Coercion, InferOk, InferResult};
+use rustc_infer::traits::Obligation;
use rustc_middle::lint::in_external_macro;
use rustc_middle::ty::adjustment::{
Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability, PointerCast,
@@ -50,7 +51,7 @@
use rustc_middle::ty::fold::TypeFoldable;
use rustc_middle::ty::relate::RelateResult;
use rustc_middle::ty::subst::SubstsRef;
-use rustc_middle::ty::{self, Ty, TypeAndMut};
+use rustc_middle::ty::{self, ToPredicate, Ty, TypeAndMut};
use rustc_session::parse::feature_err;
use rustc_span::symbol::sym;
use rustc_span::{self, BytePos, Span};
@@ -146,7 +147,9 @@
}
fn coerce(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> {
+ // First, remove any resolved type variables (at the top level, at least):
let a = self.shallow_resolve(a);
+ let b = self.shallow_resolve(b);
debug!("Coerce.tys({:?} => {:?})", a, b);
// Just ignore error types.
@@ -154,6 +157,7 @@
return success(vec![], self.fcx.tcx.ty_error(), vec![]);
}
+ // Coercing from `!` to any type is allowed:
if a.is_never() {
// Subtle: If we are coercing from `!` to `?T`, where `?T` is an unbound
// type variable, we want `?T` to fallback to `!` if not
@@ -162,20 +166,26 @@
// let _: Option<?T> = Some({ return; });
//
// here, we would coerce from `!` to `?T`.
- let b = self.shallow_resolve(b);
- return if self.shallow_resolve(b).is_ty_var() {
+ return if b.is_ty_var() {
// Micro-optimization: no need for this if `b` is
// already resolved in some way.
let diverging_ty = self.next_diverging_ty_var(TypeVariableOrigin {
kind: TypeVariableOriginKind::AdjustmentType,
span: self.cause.span,
});
- self.unify_and(&b, &diverging_ty, simple(Adjust::NeverToAny))
+ self.coerce_from_inference_variable(diverging_ty, b, simple(Adjust::NeverToAny))
} else {
success(simple(Adjust::NeverToAny)(b), b, vec![])
};
}
+ // Coercing *from* an unresolved inference variable means that
+ // we have no information about the source type. This will always
+ // ultimately fall back to some form of subtyping.
+ if a.is_ty_var() {
+ return self.coerce_from_inference_variable(a, b, identity);
+ }
+
// Consider coercing the subtype to a DST
//
// NOTE: this is wrapped in a `commit_if_ok` because it creates
@@ -196,9 +206,6 @@
debug!("coerce: unsize failed");
// Examine the supertype and consider auto-borrowing.
- //
- // Note: does not attempt to resolve type variables we encounter.
- // See above for details.
match *b.kind() {
ty::RawPtr(mt_b) => {
return self.coerce_unsafe_ptr(a, b, mt_b.mutbl);
@@ -236,6 +243,58 @@
}
}
+ /// Coercing *from* an inference variable. In this case, we have no information
+ /// about the source type, so we can't really do a true coercion and we always
+ /// fall back to subtyping (`unify_and`).
+ fn coerce_from_inference_variable(
+ &self,
+ a: Ty<'tcx>,
+ b: Ty<'tcx>,
+ make_adjustments: impl FnOnce(Ty<'tcx>) -> Vec<Adjustment<'tcx>>,
+ ) -> CoerceResult<'tcx> {
+ debug!("coerce_from_inference_variable(a={:?}, b={:?})", a, b);
+ assert!(a.is_ty_var() && self.infcx.shallow_resolve(a) == a);
+ assert!(self.infcx.shallow_resolve(b) == b);
+
+ if b.is_ty_var() {
+ // Two unresolved type variables: create a `Coerce` predicate.
+ let target_ty = if self.use_lub {
+ self.infcx.next_ty_var(TypeVariableOrigin {
+ kind: TypeVariableOriginKind::LatticeVariable,
+ span: self.cause.span,
+ })
+ } else {
+ b
+ };
+
+ let mut obligations = Vec::with_capacity(2);
+ for &source_ty in &[a, b] {
+ if source_ty != target_ty {
+ obligations.push(Obligation::new(
+ self.cause.clone(),
+ self.param_env,
+ ty::PredicateKind::Coerce(ty::CoercePredicate {
+ a: source_ty,
+ b: target_ty,
+ })
+ .to_predicate(self.tcx()),
+ ));
+ }
+ }
+
+ debug!(
+ "coerce_from_inference_variable: two inference variables, target_ty={:?}, obligations={:?}",
+ target_ty, obligations
+ );
+ let adjustments = make_adjustments(target_ty);
+ InferResult::Ok(InferOk { value: (adjustments, target_ty), obligations })
+ } else {
+ // One unresolved type variable: just apply subtyping, we may be able
+ // to do something useful.
+ self.unify_and(a, b, make_adjustments)
+ }
+ }
+
/// Reborrows `&mut A` to `&mut B` and `&(mut) A` to `&B`.
/// To match `A` with `B`, autoderef will be performed,
/// calling `deref`/`deref_mut` where necessary.
@@ -576,6 +635,7 @@
)];
let mut has_unsized_tuple_coercion = false;
+ let mut has_trait_upcasting_coercion = false;
// Keep resolving `CoerceUnsized` and `Unsize` predicates to avoid
// emitting a coercion in cases like `Foo<$1>` -> `Foo<$2>`, where
@@ -586,11 +646,18 @@
debug!("coerce_unsized resolve step: {:?}", obligation);
let bound_predicate = obligation.predicate.kind();
let trait_pred = match bound_predicate.skip_binder() {
- ty::PredicateKind::Trait(trait_pred, _)
- if traits.contains(&trait_pred.def_id()) =>
- {
+ ty::PredicateKind::Trait(trait_pred) if traits.contains(&trait_pred.def_id()) => {
if unsize_did == trait_pred.def_id() {
+ let self_ty = trait_pred.self_ty();
let unsize_ty = trait_pred.trait_ref.substs[1].expect_ty();
+ if let (ty::Dynamic(ref data_a, ..), ty::Dynamic(ref data_b, ..)) =
+ (self_ty.kind(), unsize_ty.kind())
+ {
+ if data_a.principal_def_id() != data_b.principal_def_id() {
+ debug!("coerce_unsized: found trait upcasting coercion");
+ has_trait_upcasting_coercion = true;
+ }
+ }
if let ty::Tuple(..) = unsize_ty.kind() {
debug!("coerce_unsized: found unsized tuple coercion");
has_unsized_tuple_coercion = true;
@@ -666,6 +733,16 @@
.emit();
}
+ if has_trait_upcasting_coercion && !self.tcx().features().trait_upcasting {
+ feature_err(
+ &self.tcx.sess.parse_sess,
+ sym::trait_upcasting,
+ self.cause.span,
+ "trait upcasting coercion is experimental",
+ )
+ .emit();
+ }
+
Ok(coercion)
}
@@ -719,6 +796,8 @@
//! into a closure or a `proc`.
let b = self.shallow_resolve(b);
+ let InferOk { value: b, mut obligations } =
+ self.normalize_associated_types_in_as_infer_ok(self.cause.span, b);
debug!("coerce_from_fn_item(a={:?}, b={:?})", a, b);
match b.kind() {
@@ -738,8 +817,9 @@
}
}
- let InferOk { value: a_sig, mut obligations } =
+ let InferOk { value: a_sig, obligations: o1 } =
self.normalize_associated_types_in_as_infer_ok(self.cause.span, a_sig);
+ obligations.extend(o1);
let a_fn_pointer = self.tcx.mk_fn_ptr(a_sig);
let InferOk { value, obligations: o2 } = self.coerce_from_safe_fn(
@@ -1251,6 +1331,7 @@
/// The inner coercion "engine". If `expression` is `None`, this
/// is a forced-unit case, and hence `expression_ty` must be
/// `Nil`.
+ #[instrument(skip(self, fcx, augment_error, label_expression_as_expected), level = "debug")]
crate fn coerce_inner<'a>(
&mut self,
fcx: &FnCtxt<'a, 'tcx>,
diff --git a/compiler/rustc_typeck/src/check/compare_method.rs b/compiler/rustc_typeck/src/check/compare_method.rs
index d358688..d59291b 100644
--- a/compiler/rustc_typeck/src/check/compare_method.rs
+++ b/compiler/rustc_typeck/src/check/compare_method.rs
@@ -250,6 +250,8 @@
// Compute placeholder form of impl and trait method tys.
let tcx = infcx.tcx;
+ let mut wf_tys = vec![];
+
let (impl_sig, _) = infcx.replace_bound_vars_with_fresh_vars(
impl_m_span,
infer::HigherRankedType,
@@ -260,10 +262,18 @@
let impl_fty = tcx.mk_fn_ptr(ty::Binder::dummy(impl_sig));
debug!("compare_impl_method: impl_fty={:?}", impl_fty);
+ // First liberate late bound regions and subst placeholders
let trait_sig = tcx.liberate_late_bound_regions(impl_m.def_id, tcx.fn_sig(trait_m.def_id));
let trait_sig = trait_sig.subst(tcx, trait_to_placeholder_substs);
+ // Next, add all inputs and output as well-formed tys. Importantly,
+ // we have to do this before normalization, since the normalized ty may
+ // not contain the input parameters. See issue #87748.
+ wf_tys.extend(trait_sig.inputs_and_output.iter());
let trait_sig =
inh.normalize_associated_types_in(impl_m_span, impl_m_hir_id, param_env, trait_sig);
+ // Also add the resulting inputs and output as well-formed.
+ // This probably isn't strictly necessary.
+ wf_tys.extend(trait_sig.inputs_and_output.iter());
let trait_fty = tcx.mk_fn_ptr(ty::Binder::dummy(trait_sig));
debug!("compare_impl_method: trait_fty={:?}", trait_fty);
@@ -388,7 +398,7 @@
// Finally, resolve all regions. This catches wily misuses of
// lifetime parameters.
let fcx = FnCtxt::new(&inh, param_env, impl_m_hir_id);
- fcx.regionck_item(impl_m_hir_id, impl_m_span, trait_sig.inputs_and_output);
+ fcx.regionck_item(impl_m_hir_id, impl_m_span, &wf_tys);
Ok(())
})
@@ -708,11 +718,7 @@
Some(if pos == 0 {
arg.span
} else {
- Span::new(
- trait_m_sig.decl.inputs[0].span.lo(),
- arg.span.hi(),
- arg.span.ctxt(),
- )
+ arg.span.with_lo(trait_m_sig.decl.inputs[0].span.lo())
})
} else {
trait_item_span
@@ -731,11 +737,7 @@
if pos == 0 {
arg.span
} else {
- Span::new(
- impl_m_sig.decl.inputs[0].span.lo(),
- arg.span.hi(),
- arg.span.ctxt(),
- )
+ arg.span.with_lo(impl_m_sig.decl.inputs[0].span.lo())
}
} else {
impl_m_span
@@ -1233,6 +1235,7 @@
/// For default associated types the normalization is not possible (the value
/// from the impl could be overridden). We also can't normalize generic
/// associated types (yet) because they contain bound parameters.
+#[tracing::instrument(level = "debug", skip(tcx))]
pub fn check_type_bounds<'tcx>(
tcx: TyCtxt<'tcx>,
trait_ty: &ty::AssocItem,
@@ -1246,10 +1249,83 @@
// type Bar<C> =...
// }
//
- // - `impl_substs` would be `[A, B, C]`
- // - `rebased_substs` would be `[(A, B), u32, C]`, combining the substs from
- // the *trait* with the generic associated type parameters.
- let impl_ty_substs = InternalSubsts::identity_for_item(tcx, impl_ty.def_id);
+ // - `impl_trait_ref` would be `<(A, B) as Foo<u32>>
+ // - `impl_ty_substs` would be `[A, B, ^0.0]` (`^0.0` here is the bound var with db 0 and index 0)
+ // - `rebased_substs` would be `[(A, B), u32, ^0.0]`, combining the substs from
+ // the *trait* with the generic associated type parameters (as bound vars).
+ //
+ // A note regarding the use of bound vars here:
+ // Imagine as an example
+ // ```
+ // trait Family {
+ // type Member<C: Eq>;
+ // }
+ //
+ // impl Family for VecFamily {
+ // type Member<C: Eq> = i32;
+ // }
+ // ```
+ // Here, we would generate
+ // ```notrust
+ // forall<C> { Normalize(<VecFamily as Family>::Member<C> => i32) }
+ // ```
+ // when we really would like to generate
+ // ```notrust
+ // forall<C> { Normalize(<VecFamily as Family>::Member<C> => i32) :- Implemented(C: Eq) }
+ // ```
+ // But, this is probably fine, because although the first clause can be used with types C that
+ // do not implement Eq, for it to cause some kind of problem, there would have to be a
+ // VecFamily::Member<X> for some type X where !(X: Eq), that appears in the value of type
+ // Member<C: Eq> = .... That type would fail a well-formedness check that we ought to be doing
+ // elsewhere, which would check that any <T as Family>::Member<X> meets the bounds declared in
+ // the trait (notably, that X: Eq and T: Family).
+ let defs: &ty::Generics = tcx.generics_of(impl_ty.def_id);
+ let mut substs = smallvec::SmallVec::with_capacity(defs.count());
+ if let Some(def_id) = defs.parent {
+ let parent_defs = tcx.generics_of(def_id);
+ InternalSubsts::fill_item(&mut substs, tcx, parent_defs, &mut |param, _| {
+ tcx.mk_param_from_def(param)
+ });
+ }
+ let mut bound_vars: smallvec::SmallVec<[ty::BoundVariableKind; 8]> =
+ smallvec::SmallVec::with_capacity(defs.count());
+ InternalSubsts::fill_single(&mut substs, defs, &mut |param, _| match param.kind {
+ GenericParamDefKind::Type { .. } => {
+ let kind = ty::BoundTyKind::Param(param.name);
+ let bound_var = ty::BoundVariableKind::Ty(kind);
+ bound_vars.push(bound_var);
+ tcx.mk_ty(ty::Bound(
+ ty::INNERMOST,
+ ty::BoundTy { var: ty::BoundVar::from_usize(bound_vars.len() - 1), kind },
+ ))
+ .into()
+ }
+ GenericParamDefKind::Lifetime => {
+ let kind = ty::BoundRegionKind::BrNamed(param.def_id, param.name);
+ let bound_var = ty::BoundVariableKind::Region(kind);
+ bound_vars.push(bound_var);
+ tcx.mk_region(ty::ReLateBound(
+ ty::INNERMOST,
+ ty::BoundRegion { var: ty::BoundVar::from_usize(bound_vars.len() - 1), kind },
+ ))
+ .into()
+ }
+ GenericParamDefKind::Const { .. } => {
+ let bound_var = ty::BoundVariableKind::Const;
+ bound_vars.push(bound_var);
+ tcx.mk_const(ty::Const {
+ ty: tcx.type_of(param.def_id),
+ val: ty::ConstKind::Bound(
+ ty::INNERMOST,
+ ty::BoundVar::from_usize(bound_vars.len() - 1),
+ ),
+ })
+ .into()
+ }
+ });
+ let bound_vars = tcx.mk_bound_variable_kinds(bound_vars.into_iter());
+ let impl_ty_substs = tcx.intern_substs(&substs);
+
let rebased_substs =
impl_ty_substs.rebase_onto(tcx, impl_ty.container.id(), impl_trait_ref.substs);
let impl_ty_value = tcx.type_of(impl_ty.def_id);
@@ -1278,21 +1354,35 @@
// impl<T> X for T where T: X { type Y = <T as X>::Y; }
}
_ => predicates.push(
- ty::Binder::dummy(ty::ProjectionPredicate {
- projection_ty: ty::ProjectionTy {
- item_def_id: trait_ty.def_id,
- substs: rebased_substs,
+ ty::Binder::bind_with_vars(
+ ty::ProjectionPredicate {
+ projection_ty: ty::ProjectionTy {
+ item_def_id: trait_ty.def_id,
+ substs: rebased_substs,
+ },
+ ty: impl_ty_value,
},
- ty: impl_ty_value,
- })
+ bound_vars,
+ )
.to_predicate(tcx),
),
};
ty::ParamEnv::new(tcx.intern_predicates(&predicates), Reveal::UserFacing)
};
+ debug!(?normalize_param_env);
+
+ let impl_ty_substs = InternalSubsts::identity_for_item(tcx, impl_ty.def_id);
+ let rebased_substs =
+ impl_ty_substs.rebase_onto(tcx, impl_ty.container.id(), impl_trait_ref.substs);
tcx.infer_ctxt().enter(move |infcx| {
- let inh = Inherited::new(infcx, impl_ty.def_id.expect_local());
+ let constness = impl_ty
+ .container
+ .impl_def_id()
+ .map(|did| tcx.impl_constness(did))
+ .unwrap_or(hir::Constness::NotConst);
+
+ let inh = Inherited::with_constness(infcx, impl_ty.def_id.expect_local(), constness);
let infcx = &inh.infcx;
let mut selcx = traits::SelectionContext::new(&infcx);
@@ -1310,6 +1400,7 @@
.explicit_item_bounds(trait_ty.def_id)
.iter()
.map(|&(bound, span)| {
+ debug!(?bound);
let concrete_ty_bound = bound.subst(tcx, rebased_substs);
debug!("check_type_bounds: concrete_ty_bound = {:?}", concrete_ty_bound);
@@ -1334,7 +1425,9 @@
// Check that all obligations are satisfied by the implementation's
// version.
- if let Err(ref errors) = inh.fulfillment_cx.borrow_mut().select_all_or_error(&infcx) {
+ if let Err(ref errors) =
+ inh.fulfillment_cx.borrow_mut().select_all_with_constness_or_error(&infcx, constness)
+ {
infcx.report_fulfillment_errors(errors, None, false);
return Err(ErrorReported);
}
diff --git a/compiler/rustc_typeck/src/check/demand.rs b/compiler/rustc_typeck/src/check/demand.rs
index 3ea5990..808685d 100644
--- a/compiler/rustc_typeck/src/check/demand.rs
+++ b/compiler/rustc_typeck/src/check/demand.rs
@@ -13,7 +13,7 @@
use rustc_middle::ty::print::with_no_trimmed_paths;
use rustc_middle::ty::{self, AssocItem, Ty, TypeAndMut};
use rustc_span::symbol::sym;
-use rustc_span::Span;
+use rustc_span::{BytePos, Span};
use super::method::probe;
@@ -40,7 +40,7 @@
self.suggest_missing_parentheses(err, expr);
self.note_need_for_fn_pointer(err, expected, expr_ty);
self.note_internal_mutation_in_method(err, expr, expected, expr_ty);
- self.report_closure_infered_return_type(err, expected)
+ self.report_closure_inferred_return_type(err, expected);
}
// Requires that the two types unify, and prints an error message if
@@ -257,7 +257,7 @@
//
// FIXME? Other potential candidate methods: `as_ref` and
// `as_mut`?
- .any(|a| self.sess().check_name(a, sym::rustc_conversion_suggestion))
+ .any(|a| a.has_name(sym::rustc_conversion_suggestion))
});
methods
@@ -415,7 +415,7 @@
expr: &hir::Expr<'_>,
checked_ty: Ty<'tcx>,
expected: Ty<'tcx>,
- ) -> Option<(Span, &'static str, String, Applicability)> {
+ ) -> Option<(Span, &'static str, String, Applicability, bool /* verbose */)> {
let sess = self.sess();
let sp = expr.span;
@@ -441,12 +441,14 @@
(&ty::Str, &ty::Array(arr, _) | &ty::Slice(arr)) if arr == self.tcx.types.u8 => {
if let hir::ExprKind::Lit(_) = expr.kind {
if let Ok(src) = sm.span_to_snippet(sp) {
- if let Some(src) = replace_prefix(&src, "b\"", "\"") {
+ if let Some(_) = replace_prefix(&src, "b\"", "\"") {
+ let pos = sp.lo() + BytePos(1);
return Some((
- sp,
+ sp.with_hi(pos),
"consider removing the leading `b`",
- src,
+ String::new(),
Applicability::MachineApplicable,
+ true,
));
}
}
@@ -455,12 +457,13 @@
(&ty::Array(arr, _) | &ty::Slice(arr), &ty::Str) if arr == self.tcx.types.u8 => {
if let hir::ExprKind::Lit(_) = expr.kind {
if let Ok(src) = sm.span_to_snippet(sp) {
- if let Some(src) = replace_prefix(&src, "\"", "b\"") {
+ if let Some(_) = replace_prefix(&src, "\"", "b\"") {
return Some((
- sp,
+ sp.shrink_to_lo(),
"consider adding a leading `b`",
- src,
+ "b".to_string(),
Applicability::MachineApplicable,
+ true,
));
}
}
@@ -520,6 +523,7 @@
sugg.1,
sugg.2,
Applicability::MachineApplicable,
+ false,
));
}
let field_name = if is_struct_pat_shorthand_field {
@@ -539,13 +543,14 @@
// | |
// consider dereferencing here: `*opt` |
// expected mutable reference, found enum `Option`
- if let Ok(src) = sm.span_to_snippet(left_expr.span) {
+ if sm.span_to_snippet(left_expr.span).is_ok() {
return Some((
- left_expr.span,
+ left_expr.span.shrink_to_lo(),
"consider dereferencing here to assign to the mutable \
borrowed piece of memory",
- format!("*{}", src),
+ "*".to_string(),
Applicability::MachineApplicable,
+ true,
));
}
}
@@ -557,12 +562,14 @@
"consider mutably borrowing here",
format!("{}&mut {}", field_name, sugg_expr),
Applicability::MachineApplicable,
+ false,
),
hir::Mutability::Not => (
sp,
"consider borrowing here",
format!("{}&{}", field_name, sugg_expr),
Applicability::MachineApplicable,
+ false,
),
});
}
@@ -584,24 +591,26 @@
if let Some(call_span) =
iter::successors(Some(expr.span), |s| s.parent()).find(|&s| sp.contains(s))
{
- if let Ok(code) = sm.span_to_snippet(call_span) {
+ if sm.span_to_snippet(call_span).is_ok() {
return Some((
- sp,
+ sp.with_hi(call_span.lo()),
"consider removing the borrow",
- code,
+ String::new(),
Applicability::MachineApplicable,
+ true,
));
}
}
return None;
}
if sp.contains(expr.span) {
- if let Ok(code) = sm.span_to_snippet(expr.span) {
+ if sm.span_to_snippet(expr.span).is_ok() {
return Some((
- sp,
+ sp.with_hi(expr.span.lo()),
"consider removing the borrow",
- code,
+ String::new(),
Applicability::MachineApplicable,
+ true,
));
}
}
@@ -616,36 +625,59 @@
if steps > 0 {
// The pointer type implements `Copy` trait so the suggestion is always valid.
if let Ok(src) = sm.span_to_snippet(sp) {
- let derefs = &"*".repeat(steps);
- if let Some((src, applicability)) = match mutbl_b {
+ let derefs = "*".repeat(steps);
+ if let Some((span, src, applicability)) = match mutbl_b {
hir::Mutability::Mut => {
- let new_prefix = "&mut ".to_owned() + derefs;
+ let new_prefix = "&mut ".to_owned() + &derefs;
match mutbl_a {
hir::Mutability::Mut => {
- replace_prefix(&src, "&mut ", &new_prefix)
- .map(|s| (s, Applicability::MachineApplicable))
+ replace_prefix(&src, "&mut ", &new_prefix).map(|_| {
+ let pos = sp.lo() + BytePos(5);
+ let sp = sp.with_lo(pos).with_hi(pos);
+ (sp, derefs, Applicability::MachineApplicable)
+ })
}
hir::Mutability::Not => {
- replace_prefix(&src, "&", &new_prefix)
- .map(|s| (s, Applicability::Unspecified))
+ replace_prefix(&src, "&", &new_prefix).map(|_| {
+ let pos = sp.lo() + BytePos(1);
+ let sp = sp.with_lo(pos).with_hi(pos);
+ (
+ sp,
+ format!("mut {}", derefs),
+ Applicability::Unspecified,
+ )
+ })
}
}
}
hir::Mutability::Not => {
- let new_prefix = "&".to_owned() + derefs;
+ let new_prefix = "&".to_owned() + &derefs;
match mutbl_a {
hir::Mutability::Mut => {
- replace_prefix(&src, "&mut ", &new_prefix)
- .map(|s| (s, Applicability::MachineApplicable))
+ replace_prefix(&src, "&mut ", &new_prefix).map(|_| {
+ let lo = sp.lo() + BytePos(1);
+ let hi = sp.lo() + BytePos(5);
+ let sp = sp.with_lo(lo).with_hi(hi);
+ (sp, derefs, Applicability::MachineApplicable)
+ })
}
hir::Mutability::Not => {
- replace_prefix(&src, "&", &new_prefix)
- .map(|s| (s, Applicability::MachineApplicable))
+ replace_prefix(&src, "&", &new_prefix).map(|_| {
+ let pos = sp.lo() + BytePos(1);
+ let sp = sp.with_lo(pos).with_hi(pos);
+ (sp, derefs, Applicability::MachineApplicable)
+ })
}
}
}
} {
- return Some((sp, "consider dereferencing", src, applicability));
+ return Some((
+ span,
+ "consider dereferencing",
+ src,
+ applicability,
+ true,
+ ));
}
}
}
@@ -669,6 +701,7 @@
message,
suggestion,
Applicability::MachineApplicable,
+ false,
));
} else if self.infcx.type_is_copy_modulo_regions(
self.param_env,
@@ -682,21 +715,22 @@
} else {
"consider dereferencing the type"
};
- let suggestion = if is_struct_pat_shorthand_field {
- format!("{}: *{}", code, code)
+ let (span, suggestion) = if is_struct_pat_shorthand_field {
+ (expr.span, format!("{}: *{}", code, code))
} else if self.is_else_if_block(expr) {
// Don't suggest nonsense like `else *if`
return None;
} else if let Some(expr) = self.maybe_get_block_expr(expr.hir_id) {
- format!("*{}", sm.span_to_snippet(expr.span).unwrap_or(code))
+ (expr.span.shrink_to_lo(), "*".to_string())
} else {
- format!("*{}", code)
+ (expr.span.shrink_to_lo(), "*".to_string())
};
return Some((
- expr.span,
+ span,
message,
suggestion,
Applicability::MachineApplicable,
+ true,
));
}
}
@@ -1072,29 +1106,26 @@
}
// Report the type inferred by the return statement.
- fn report_closure_infered_return_type(
+ fn report_closure_inferred_return_type(
&self,
err: &mut DiagnosticBuilder<'_>,
expected: Ty<'tcx>,
) {
if let Some(sp) = self.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) {
- let hir = self.tcx.hir();
- let body_owner = hir.body_owned_by(hir.enclosing_body_owner(self.body_id));
- if self.tcx.is_closure(hir.body_owner_def_id(body_owner).to_def_id()) {
- err.span_note(
- sp,
- &format!(
- "return type inferred to be `{}` here",
- self.resolve_vars_if_possible(expected)
- ),
- );
- }
+ // If the closure has an explicit return type annotation, or if
+ // the closure's return type has been inferred from outside
+ // requirements (such as an Fn* trait bound), 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 !self.return_type_pre_known {
+ err.span_note(
+ sp,
+ &format!(
+ "return type inferred to be `{}` here",
+ self.resolve_vars_if_possible(expected)
+ ),
+ );
}
}
}
diff --git a/compiler/rustc_typeck/src/check/dropck.rs b/compiler/rustc_typeck/src/check/dropck.rs
index 0127649..fd15097 100644
--- a/compiler/rustc_typeck/src/check/dropck.rs
+++ b/compiler/rustc_typeck/src/check/dropck.rs
@@ -218,9 +218,9 @@
// This closure is a more robust way to check `Predicate` equality
// than simple `==` checks (which were the previous implementation).
- // It relies on `ty::relate` for `TraitPredicate` and `ProjectionPredicate`
- // (which implement the Relate trait), while delegating on simple equality
- // for the other `Predicate`.
+ // It relies on `ty::relate` for `TraitPredicate`, `ProjectionPredicate`,
+ // `ConstEvaluatable` and `TypeOutlives` (which implement the Relate trait),
+ // while delegating on simple equality for the other `Predicate`.
// This implementation solves (Issue #59497) and (Issue #58311).
// It is unclear to me at the moment whether the approach based on `relate`
// could be extended easily also to the other `Predicate`.
@@ -229,12 +229,19 @@
let predicate = predicate.kind();
let p = p.kind();
match (predicate.skip_binder(), p.skip_binder()) {
- (ty::PredicateKind::Trait(a, _), ty::PredicateKind::Trait(b, _)) => {
+ (ty::PredicateKind::Trait(a), ty::PredicateKind::Trait(b)) => {
relator.relate(predicate.rebind(a), p.rebind(b)).is_ok()
}
(ty::PredicateKind::Projection(a), ty::PredicateKind::Projection(b)) => {
relator.relate(predicate.rebind(a), p.rebind(b)).is_ok()
}
+ (
+ ty::PredicateKind::ConstEvaluatable(a),
+ ty::PredicateKind::ConstEvaluatable(b),
+ ) => tcx.try_unify_abstract_consts((a, b)),
+ (ty::PredicateKind::TypeOutlives(a), ty::PredicateKind::TypeOutlives(b)) => {
+ relator.relate(predicate.rebind(a.0), p.rebind(b.0)).is_ok()
+ }
_ => predicate == p,
}
};
diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs
index cfe1d1c..64594a8 100644
--- a/compiler/rustc_typeck/src/check/expr.rs
+++ b/compiler/rustc_typeck/src/check/expr.rs
@@ -156,12 +156,27 @@
/// Note that inspecting a type's structure *directly* may expose the fact
/// that there are actually multiple representations for `Error`, so avoid
/// that when err needs to be handled differently.
+ #[instrument(skip(self), level = "debug")]
pub(super) fn check_expr_with_expectation(
&self,
expr: &'tcx hir::Expr<'tcx>,
expected: Expectation<'tcx>,
) -> Ty<'tcx> {
- debug!(">> type-checking: expected={:?}, expr={:?} ", expected, expr);
+ if self.tcx().sess.verbose() {
+ // make this code only run with -Zverbose because it is probably slow
+ if let Ok(lint_str) = self.tcx.sess.source_map().span_to_snippet(expr.span) {
+ if !lint_str.contains('\n') {
+ debug!("expr text: {}", lint_str);
+ } else {
+ let mut lines = lint_str.lines();
+ if let Some(line0) = lines.next() {
+ let remaining_lines = lines.count();
+ debug!("expr text: {}", line0);
+ debug!("expr text: ...(and {} more lines)", remaining_lines);
+ }
+ }
+ }
+ }
// True if `expr` is a `Try::from_ok(())` that is a result of desugaring a try block
// without the final expr (e.g. `try { return; }`). We don't want to generate an
@@ -187,7 +202,11 @@
// Warn for non-block expressions with diverging children.
match expr.kind {
- ExprKind::Block(..) | ExprKind::If(..) | ExprKind::Loop(..) | ExprKind::Match(..) => {}
+ ExprKind::Block(..)
+ | ExprKind::If(..)
+ | ExprKind::Let(..)
+ | 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.
@@ -262,6 +281,7 @@
}
}
ExprKind::Ret(ref expr_opt) => self.check_expr_return(expr_opt.as_deref(), expr),
+ ExprKind::Let(pat, let_expr, _) => self.check_expr_let(let_expr, pat),
ExprKind::Loop(body, _, source, _) => {
self.check_expr_loop(body, source, expected, expr)
}
@@ -308,6 +328,7 @@
_ => NoExpectation,
});
let referent_ty = self.check_expr_with_expectation(expr, expected_inner);
+ self.require_type_is_sized(referent_ty, expr.span, traits::SizedBoxType);
self.tcx.mk_box(referent_ty)
}
@@ -344,7 +365,7 @@
if let Some(sp) =
tcx.sess.parse_sess.ambiguous_block_expr_parse.borrow().get(&sp)
{
- tcx.sess.parse_sess.expr_parentheses_needed(&mut err, *sp, None);
+ tcx.sess.parse_sess.expr_parentheses_needed(&mut err, *sp);
}
err.emit();
oprnd_t = tcx.ty_error();
@@ -802,7 +823,11 @@
) -> 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");
+ self.warn_if_unreachable(
+ cond_expr.hir_id,
+ then_expr.span,
+ "block in `if` or `while` expression",
+ );
let cond_diverges = self.diverges.get();
self.diverges.set(Diverges::Maybe);
@@ -824,7 +849,26 @@
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_ty = if sp.desugaring_kind() == Some(DesugaringKind::LetElse) {
+ // todo introduce `check_expr_with_expectation(.., Expectation::LetElse)`
+ // for errors that point to the offending expression rather than the entire block.
+ // We could use `check_expr_eq_type(.., tcx.types.never)`, but then there is no
+ // way to detect that the expected type originated from let-else and provide
+ // a customized error.
+ let else_ty = self.check_expr(else_expr);
+ let cause = self.cause(else_expr.span, ObligationCauseCode::LetElse);
+
+ if let Some(mut err) =
+ self.demand_eqtype_with_origin(&cause, self.tcx.types.never, else_ty)
+ {
+ err.emit();
+ self.tcx.ty_error()
+ } else {
+ else_ty
+ }
+ } else {
+ self.check_expr_with_expectation(else_expr, expected)
+ };
let else_diverges = self.diverges.get();
let opt_suggest_box_span =
@@ -837,9 +881,7 @@
// 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)
- });
+ self.if_fallback_coercion(sp, then_expr, &mut coerce);
// If the condition is false we can't diverge.
self.diverges.set(cond_diverges);
@@ -875,26 +917,16 @@
};
if !lhs.is_syntactic_place_expr() {
// Do not suggest `if let x = y` as `==` is way more likely to be the intention.
- let mut span_err = || {
- // Likely `if let` intended.
+ let hir = self.tcx.hir();
+ if let hir::Node::Expr(hir::Expr { kind: ExprKind::If { .. }, .. }) =
+ hir.get(hir.get_parent_node(hir.get_parent_node(expr.hir_id)))
+ {
err.span_suggestion_verbose(
expr.span.shrink_to_lo(),
"you might have meant to use pattern matching",
"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 {
@@ -906,9 +938,10 @@
);
}
- if self.sess().if_let_suggestions.borrow().get(&expr.span).is_some() {
- // We already emitted an `if let` suggestion due to an identifier not found.
- err.delay_as_bug();
+ // If the assignment expression itself is ill-formed, don't
+ // bother emitting another error
+ if lhs_ty.references_error() || rhs_ty.references_error() {
+ err.delay_as_bug()
} else {
err.emit();
}
@@ -929,6 +962,13 @@
}
}
+ fn check_expr_let(&self, expr: &'tcx hir::Expr<'tcx>, pat: &'tcx hir::Pat<'tcx>) -> Ty<'tcx> {
+ self.warn_if_unreachable(expr.hir_id, expr.span, "block in `let` expression");
+ let expr_ty = self.demand_scrutinee_type(expr, pat.contains_explicit_ref_binding(), false);
+ self.check_pat_top(pat, expr_ty, Some(expr.span), true);
+ self.tcx.types.bool
+ }
+
fn check_expr_loop(
&self,
body: &'tcx hir::Block<'tcx>,
@@ -943,7 +983,7 @@
Some(CoerceMany::new(coerce_to))
}
- hir::LoopSource::While | hir::LoopSource::WhileLet | hir::LoopSource::ForLoop => None,
+ hir::LoopSource::While | hir::LoopSource::ForLoop => None,
};
let ctxt = BreakableCtxt {
@@ -1034,7 +1074,7 @@
let t_cast = self.to_ty_saving_user_provided_ty(t);
let t_cast = self.resolve_vars_if_possible(t_cast);
let t_expr = self.check_expr_with_expectation(e, ExpectCastableToType(t_cast));
- let t_cast = self.resolve_vars_if_possible(t_cast);
+ let t_expr = self.resolve_vars_if_possible(t_expr);
// Eagerly check for some obvious errors.
if t_expr.references_error() || t_cast.references_error() {
@@ -1044,6 +1084,10 @@
let mut deferred_cast_checks = self.deferred_cast_checks.borrow_mut();
match cast::CastCheck::new(self, e, t_expr, t_cast, t.span, expr.span) {
Ok(cast_check) => {
+ debug!(
+ "check_expr_cast: deferring cast from {:?} to {:?}: {:?}",
+ t_cast, t_expr, cast_check,
+ );
deferred_cast_checks.push(cast_check);
t_cast
}
@@ -1304,18 +1348,21 @@
// Make sure the programmer specified correct number of fields.
if kind_name == "union" {
if ast_fields.len() != 1 {
- tcx.sess.span_err(span, "union expressions should have exactly one field");
+ struct_span_err!(
+ tcx.sess,
+ span,
+ E0784,
+ "union expressions should have exactly one field",
+ )
+ .emit();
}
} else if check_completeness && !error_happened && !remaining_fields.is_empty() {
- let no_accessible_remaining_fields = remaining_fields
- .iter()
- .find(|(_, (_, field))| {
- field.vis.is_accessible_from(tcx.parent_module(expr_id).to_def_id(), tcx)
- })
- .is_none();
+ let inaccessible_remaining_fields = remaining_fields.iter().any(|(_, (_, field))| {
+ !field.vis.is_accessible_from(tcx.parent_module(expr_id).to_def_id(), tcx)
+ });
- if no_accessible_remaining_fields {
- self.report_no_accessible_fields(adt_ty, span);
+ if inaccessible_remaining_fields {
+ self.report_inaccessible_fields(adt_ty, span);
} else {
self.report_missing_fields(adt_ty, span, remaining_fields);
}
@@ -1392,7 +1439,7 @@
.emit();
}
- /// Report an error for a struct field expression when there are no visible fields.
+ /// Report an error for a struct field expression when there are invisible fields.
///
/// ```text
/// error: cannot construct `Foo` with struct literal syntax due to inaccessible fields
@@ -1403,7 +1450,7 @@
///
/// error: aborting due to previous error
/// ```
- fn report_no_accessible_fields(&self, adt_ty: Ty<'tcx>, span: Span) {
+ fn report_inaccessible_fields(&self, adt_ty: Ty<'tcx>, span: Span) {
self.tcx.sess.span_err(
span,
&format!(
@@ -2137,14 +2184,11 @@
hir::InlineAsmOperand::In { expr, .. } => {
self.check_expr_asm_operand(expr, true);
}
- hir::InlineAsmOperand::Out { expr, .. } => {
- if let Some(expr) = expr {
- self.check_expr_asm_operand(expr, false);
- }
- }
- hir::InlineAsmOperand::InOut { expr, .. } => {
+ hir::InlineAsmOperand::Out { expr: Some(expr), .. }
+ | hir::InlineAsmOperand::InOut { expr, .. } => {
self.check_expr_asm_operand(expr, false);
}
+ hir::InlineAsmOperand::Out { expr: None, .. } => {}
hir::InlineAsmOperand::SplitInOut { in_expr, out_expr, .. } => {
self.check_expr_asm_operand(in_expr, true);
if let Some(out_expr) = out_expr {
diff --git a/compiler/rustc_typeck/src/check/fallback.rs b/compiler/rustc_typeck/src/check/fallback.rs
new file mode 100644
index 0000000..8f6cdc7
--- /dev/null
+++ b/compiler/rustc_typeck/src/check/fallback.rs
@@ -0,0 +1,161 @@
+use crate::check::FnCtxt;
+use rustc_infer::infer::type_variable::Diverging;
+use rustc_middle::ty::{self, Ty};
+
+impl<'tcx> FnCtxt<'_, 'tcx> {
+ /// Performs type inference fallback, returning true if any fallback
+ /// occurs.
+ pub(super) fn type_inference_fallback(&self) -> bool {
+ // All type checking constraints were added, try to fallback unsolved variables.
+ self.select_obligations_where_possible(false, |_| {});
+ let mut fallback_has_occurred = false;
+
+ // We do fallback in two passes, to try to generate
+ // better error messages.
+ // The first time, we do *not* replace opaque types.
+ for ty in &self.unsolved_variables() {
+ debug!("unsolved_variable = {:?}", ty);
+ fallback_has_occurred |= self.fallback_if_possible(ty);
+ }
+
+ // We now see if we can make progress. This might
+ // cause us to unify inference variables for opaque types,
+ // since we may have unified some other type variables
+ // during the first phase of fallback.
+ // This means that we only replace inference variables with their underlying
+ // opaque types as a last resort.
+ //
+ // In code like this:
+ //
+ // ```rust
+ // type MyType = impl Copy;
+ // fn produce() -> MyType { true }
+ // fn bad_produce() -> MyType { panic!() }
+ // ```
+ //
+ // we want to unify the opaque inference variable in `bad_produce`
+ // with the diverging fallback for `panic!` (e.g. `()` or `!`).
+ // This will produce a nice error message about conflicting concrete
+ // types for `MyType`.
+ //
+ // If we had tried to fallback the opaque inference variable to `MyType`,
+ // we will generate a confusing type-check error that does not explicitly
+ // refer to opaque types.
+ self.select_obligations_where_possible(fallback_has_occurred, |_| {});
+
+ // We now run fallback again, but this time we allow it to replace
+ // unconstrained opaque type variables, in addition to performing
+ // other kinds of fallback.
+ for ty in &self.unsolved_variables() {
+ fallback_has_occurred |= self.fallback_opaque_type_vars(ty);
+ }
+
+ // See if we can make any more progress.
+ self.select_obligations_where_possible(fallback_has_occurred, |_| {});
+
+ fallback_has_occurred
+ }
+
+ // Tries to apply a fallback to `ty` if it is an unsolved variable.
+ //
+ // - Unconstrained ints are replaced with `i32`.
+ //
+ // - Unconstrained floats are replaced with with `f64`.
+ //
+ // - Non-numerics get replaced with `!` when `#![feature(never_type_fallback)]`
+ // is enabled. Otherwise, they are replaced with `()`.
+ //
+ // Fallback becomes very dubious if we have encountered type-checking errors.
+ // In that case, fallback to Error.
+ // The return value indicates whether fallback has occurred.
+ fn fallback_if_possible(&self, ty: Ty<'tcx>) -> bool {
+ // Careful: we do NOT shallow-resolve `ty`. We know that `ty`
+ // is an unsolved variable, and we determine its fallback based
+ // solely on how it was created, not what other type variables
+ // it may have been unified with since then.
+ //
+ // The reason this matters is that other attempts at fallback may
+ // (in principle) conflict with this fallback, and we wish to generate
+ // a type error in that case. (However, this actually isn't true right now,
+ // because we're only using the builtin fallback rules. This would be
+ // true if we were using user-supplied fallbacks. But it's still useful
+ // to write the code to detect bugs.)
+ //
+ // (Note though that if we have a general type variable `?T` that is then unified
+ // with an integer type variable `?I` that ultimately never gets
+ // resolved to a special integral type, `?T` is not considered unsolved,
+ // but `?I` is. The same is true for float variables.)
+ let fallback = match ty.kind() {
+ _ if self.is_tainted_by_errors() => self.tcx.ty_error(),
+ ty::Infer(ty::IntVar(_)) => self.tcx.types.i32,
+ ty::Infer(ty::FloatVar(_)) => self.tcx.types.f64,
+ _ => match self.type_var_diverges(ty) {
+ Diverging::Diverges => self.tcx.mk_diverging_default(),
+ Diverging::NotDiverging => return false,
+ },
+ };
+ debug!("fallback_if_possible(ty={:?}): defaulting to `{:?}`", ty, fallback);
+
+ let span = self
+ .infcx
+ .type_var_origin(ty)
+ .map(|origin| origin.span)
+ .unwrap_or(rustc_span::DUMMY_SP);
+ self.demand_eqtype(span, ty, fallback);
+ true
+ }
+
+ /// Second round of fallback: Unconstrained type variables
+ /// created from the instantiation of an opaque
+ /// type fall back to the opaque type itself. This is a
+ /// somewhat incomplete attempt to manage "identity passthrough"
+ /// for `impl Trait` types.
+ ///
+ /// For example, in this code:
+ ///
+ ///```
+ /// type MyType = impl Copy;
+ /// fn defining_use() -> MyType { true }
+ /// fn other_use() -> MyType { defining_use() }
+ /// ```
+ ///
+ /// `defining_use` will constrain the instantiated inference
+ /// variable to `bool`, while `other_use` will constrain
+ /// the instantiated inference variable to `MyType`.
+ ///
+ /// When we process opaque types during writeback, we
+ /// will handle cases like `other_use`, and not count
+ /// them as defining usages
+ ///
+ /// However, we also need to handle cases like this:
+ ///
+ /// ```rust
+ /// pub type Foo = impl Copy;
+ /// fn produce() -> Option<Foo> {
+ /// None
+ /// }
+ /// ```
+ ///
+ /// In the above snippet, the inference variable created by
+ /// instantiating `Option<Foo>` will be completely unconstrained.
+ /// We treat this as a non-defining use by making the inference
+ /// variable fall back to the opaque type itself.
+ fn fallback_opaque_type_vars(&self, ty: Ty<'tcx>) -> bool {
+ let span = self
+ .infcx
+ .type_var_origin(ty)
+ .map(|origin| origin.span)
+ .unwrap_or(rustc_span::DUMMY_SP);
+ let oty = self.inner.borrow().opaque_types_vars.get(ty).map(|v| *v);
+ if let Some(opaque_ty) = oty {
+ debug!(
+ "fallback_opaque_type_vars(ty={:?}): falling back to opaque type {:?}",
+ ty, opaque_ty
+ );
+ self.demand_eqtype(span, ty, opaque_ty);
+ true
+ } else {
+ return false;
+ }
+ }
+}
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
index 865e4ccc0..9748c08 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
@@ -4,7 +4,7 @@
};
use crate::check::callee::{self, DeferredCallResolution};
use crate::check::method::{self, MethodCallee, SelfSource};
-use crate::check::{BreakableCtxt, Diverges, Expectation, FallbackMode, FnCtxt, LocalTy};
+use crate::check::{BreakableCtxt, Diverges, Expectation, FnCtxt, LocalTy};
use rustc_ast::TraitObjectSyntax;
use rustc_data_structures::captures::Captures;
@@ -29,12 +29,11 @@
};
use rustc_session::lint;
use rustc_session::lint::builtin::BARE_TRAIT_OBJECTS;
-use rustc_session::parse::feature_err;
use rustc_span::edition::Edition;
+use rustc_span::hygiene::DesugaringKind;
use rustc_span::source_map::{original_sp, DUMMY_SP};
use rustc_span::symbol::{kw, sym, Ident};
use rustc_span::{self, BytePos, MultiSpan, Span};
-use rustc_span::{hygiene::DesugaringKind, Symbol};
use rustc_trait_selection::infer::InferCtxtExt as _;
use rustc_trait_selection::opaque_types::InferCtxtExt as _;
use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
@@ -240,7 +239,7 @@
self.tag(),
);
- if Self::can_contain_user_lifetime_bounds((substs, user_self_ty)) {
+ if self.can_contain_user_lifetime_bounds((substs, user_self_ty)) {
let canonicalized = self.infcx.canonicalize_user_type_annotation(UserType::TypeOf(
def_id,
UserSubsts { substs, user_self_ty },
@@ -363,50 +362,18 @@
/// Replaces the opaque types from the given value with type variables,
/// and records the `OpaqueTypeMap` for later use during writeback. See
/// `InferCtxt::instantiate_opaque_types` for more details.
+ #[instrument(skip(self, value_span), level = "debug")]
pub(in super::super) fn instantiate_opaque_types_from_value<T: TypeFoldable<'tcx>>(
&self,
- parent_id: hir::HirId,
value: T,
value_span: Span,
- feature: Option<Symbol>,
) -> T {
- let parent_def_id = self.tcx.hir().local_def_id(parent_id);
- debug!(
- "instantiate_opaque_types_from_value(parent_def_id={:?}, value={:?})",
- parent_def_id, value
- );
-
- let (value, opaque_type_map) =
- self.register_infer_ok_obligations(self.instantiate_opaque_types(
- parent_def_id,
- self.body_id,
- self.param_env,
- value,
- value_span,
- ));
-
- let mut opaque_types = self.opaque_types.borrow_mut();
- let mut opaque_types_vars = self.opaque_types_vars.borrow_mut();
-
- for (ty, decl) in opaque_type_map {
- if let Some(feature) = feature {
- if let hir::OpaqueTyOrigin::TyAlias = decl.origin {
- if !self.tcx.features().enabled(feature) {
- feature_err(
- &self.tcx.sess.parse_sess,
- feature,
- value_span,
- "type alias impl trait is not permitted here",
- )
- .emit();
- }
- }
- }
- let _ = opaque_types.insert(ty, decl);
- let _ = opaque_types_vars.insert(decl.concrete_ty, decl.opaque_type);
- }
-
- value
+ self.register_infer_ok_obligations(self.instantiate_opaque_types(
+ self.body_id,
+ self.param_env,
+ value,
+ value_span,
+ ))
}
/// Convenience method which tracks extra diagnostic information for normalization
@@ -514,7 +481,7 @@
let ty = self.to_ty(ast_ty);
debug!("to_ty_saving_user_provided_ty: ty={:?}", ty);
- if Self::can_contain_user_lifetime_bounds(ty) {
+ if self.can_contain_user_lifetime_bounds(ty) {
let c_ty = self.infcx.canonicalize_response(UserType::Ty(ty));
debug!("to_ty_saving_user_provided_ty: c_ty={:?}", c_ty);
self.typeck_results.borrow_mut().user_provided_types_mut().insert(ast_ty.hir_id, c_ty);
@@ -559,11 +526,11 @@
// reader, although I have my doubts). Also pass in types with inference
// types, because they may be repeated. Other sorts of things are already
// sufficiently enforced with erased regions. =)
- fn can_contain_user_lifetime_bounds<T>(t: T) -> bool
+ fn can_contain_user_lifetime_bounds<T>(&self, t: T) -> bool
where
T: TypeFoldable<'tcx>,
{
- t.has_free_regions() || t.has_projections() || t.has_infer_types()
+ t.has_free_regions(self.tcx) || t.has_projections() || t.has_infer_types()
}
pub fn node_ty(&self, id: hir::HirId) -> Ty<'tcx> {
@@ -581,6 +548,14 @@
}
}
+ pub fn node_ty_opt(&self, id: hir::HirId) -> Option<Ty<'tcx>> {
+ match self.typeck_results.borrow().node_types().get(id) {
+ Some(&t) => Some(t),
+ None if self.is_tainted_by_errors() => Some(self.tcx.ty_error()),
+ None => None,
+ }
+ }
+
/// Registers an obligation for checking later, during regionck, that `arg` is well-formed.
pub fn register_wf_obligation(
&self,
@@ -660,86 +635,13 @@
}
}
- // Tries to apply a fallback to `ty` if it is an unsolved variable.
- //
- // - Unconstrained ints are replaced with `i32`.
- //
- // - Unconstrained floats are replaced with with `f64`.
- //
- // - Non-numerics get replaced with `!` when `#![feature(never_type_fallback)]`
- // is enabled. Otherwise, they are replaced with `()`.
- //
- // Fallback becomes very dubious if we have encountered type-checking errors.
- // In that case, fallback to Error.
- // The return value indicates whether fallback has occurred.
- pub(in super::super) fn fallback_if_possible(&self, ty: Ty<'tcx>, mode: FallbackMode) -> bool {
- use rustc_middle::ty::error::UnconstrainedNumeric::Neither;
- use rustc_middle::ty::error::UnconstrainedNumeric::{UnconstrainedFloat, UnconstrainedInt};
-
- assert!(ty.is_ty_infer());
- let fallback = match self.type_is_unconstrained_numeric(ty) {
- _ if self.is_tainted_by_errors() => self.tcx().ty_error(),
- UnconstrainedInt => self.tcx.types.i32,
- UnconstrainedFloat => self.tcx.types.f64,
- Neither if self.type_var_diverges(ty) => self.tcx.mk_diverging_default(),
- Neither => {
- // This type variable was created from the instantiation of an opaque
- // type. The fact that we're attempting to perform fallback for it
- // means that the function neither constrained it to a concrete
- // type, nor to the opaque type itself.
- //
- // For example, in this code:
- //
- //```
- // type MyType = impl Copy;
- // fn defining_use() -> MyType { true }
- // fn other_use() -> MyType { defining_use() }
- // ```
- //
- // `defining_use` will constrain the instantiated inference
- // variable to `bool`, while `other_use` will constrain
- // the instantiated inference variable to `MyType`.
- //
- // When we process opaque types during writeback, we
- // will handle cases like `other_use`, and not count
- // them as defining usages
- //
- // However, we also need to handle cases like this:
- //
- // ```rust
- // pub type Foo = impl Copy;
- // fn produce() -> Option<Foo> {
- // None
- // }
- // ```
- //
- // In the above snippet, the inference variable created by
- // instantiating `Option<Foo>` will be completely unconstrained.
- // We treat this as a non-defining use by making the inference
- // variable fall back to the opaque type itself.
- if let FallbackMode::All = mode {
- if let Some(opaque_ty) = self.opaque_types_vars.borrow().get(ty) {
- debug!(
- "fallback_if_possible: falling back opaque type var {:?} to {:?}",
- ty, opaque_ty
- );
- *opaque_ty
- } else {
- return false;
- }
- } else {
- return false;
- }
- }
- };
- debug!("fallback_if_possible: defaulting `{:?}` to `{:?}`", ty, fallback);
- self.demand_eqtype(rustc_span::DUMMY_SP, ty, fallback);
- true
- }
-
pub(in super::super) fn select_all_obligations_or_error(&self) {
debug!("select_all_obligations_or_error");
- if let Err(errors) = self.fulfillment_cx.borrow_mut().select_all_or_error(&self) {
+ if let Err(errors) = self
+ .fulfillment_cx
+ .borrow_mut()
+ .select_all_with_constness_or_error(&self, self.inh.constness)
+ {
self.report_fulfillment_errors(&errors, self.inh.body_id, false);
}
}
@@ -750,7 +652,10 @@
fallback_has_occurred: bool,
mutate_fulfillment_errors: impl Fn(&mut Vec<traits::FulfillmentError<'tcx>>),
) {
- let result = self.fulfillment_cx.borrow_mut().select_where_possible(self);
+ let result = self
+ .fulfillment_cx
+ .borrow_mut()
+ .select_with_constness_where_possible(self, self.inh.constness);
if let Err(mut errors) = result {
mutate_fulfillment_errors(&mut errors);
self.report_fulfillment_errors(&errors, self.inh.body_id, fallback_has_occurred);
@@ -821,10 +726,11 @@
bound_predicate.rebind(data).required_poly_trait_ref(self.tcx),
obligation,
)),
- ty::PredicateKind::Trait(data, _) => {
+ ty::PredicateKind::Trait(data) => {
Some((bound_predicate.rebind(data).to_poly_trait_ref(), obligation))
}
ty::PredicateKind::Subtype(..) => None,
+ ty::PredicateKind::Coerce(..) => None,
ty::PredicateKind::RegionOutlives(..) => None,
ty::PredicateKind::TypeOutlives(..) => None,
ty::PredicateKind::WellFormed(..) => None,
@@ -837,7 +743,7 @@
// possibly be referring to the current closure,
// because we haven't produced the `Closure` for
// this closure yet; this is exactly why the other
- // code is looking for a self type of a unresolved
+ // code is looking for a self type of an unresolved
// inference variable.
ty::PredicateKind::ClosureKind(..) => None,
ty::PredicateKind::TypeWellFormedFromEnv(..) => None,
@@ -952,13 +858,25 @@
path.segments,
);
}
- QPath::TypeRelative(ref qself, ref segment) => (self.to_ty(qself), qself, segment),
+ QPath::TypeRelative(ref qself, ref segment) => {
+ // Don't use `self.to_ty`, since this will register a WF obligation.
+ // If we're trying to call a non-existent method on a trait
+ // (e.g. `MyTrait::missing_method`), then resolution will
+ // give us a `QPath::TypeRelative` with a trait object as
+ // `qself`. In that case, we want to avoid registering a WF obligation
+ // for `dyn MyTrait`, since we don't actually need the trait
+ // to be object-safe.
+ // We manually call `register_wf_obligation` in the success path
+ // below.
+ (<dyn AstConv<'_>>::ast_ty_to_ty(self, qself), qself, segment)
+ }
QPath::LangItem(..) => {
bug!("`resolve_ty_and_res_fully_qualified_call` called on `LangItem`")
}
};
if let Some(&cached_result) = self.typeck_results.borrow().type_dependent_defs().get(hir_id)
{
+ self.register_wf_obligation(ty.into(), qself.span, traits::WellFormed(None));
// 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_or(Res::Err, |(kind, def_id)| Res::Def(kind, def_id));
@@ -972,6 +890,14 @@
method::MethodError::PrivateMatch(kind, def_id, _) => Ok((kind, def_id)),
_ => Err(ErrorReported),
};
+
+ // If we have a path like `MyTrait::missing_method`, then don't register
+ // a WF obligation for `dyn MyTrait` when method lookup fails. Otherwise,
+ // register a WF obligation so that we can detect any additional
+ // errors in the self type.
+ if !(matches!(error, method::MethodError::NoMatch(_)) && ty.is_trait()) {
+ self.register_wf_obligation(ty.into(), qself.span, traits::WellFormed(None));
+ }
if item_name.name != kw::Empty {
if let Some(mut e) = self.report_method_error(
span,
@@ -988,7 +914,8 @@
});
if result.is_ok() {
- self.maybe_lint_bare_trait(qpath, hir_id);
+ self.maybe_lint_bare_trait(qpath, hir_id, span);
+ self.register_wf_obligation(ty.into(), qself.span, traits::WellFormed(None));
}
// Write back the new resolution.
@@ -1000,7 +927,7 @@
)
}
- fn maybe_lint_bare_trait(&self, qpath: &QPath<'_>, hir_id: hir::HirId) {
+ fn maybe_lint_bare_trait(&self, qpath: &QPath<'_>, hir_id: hir::HirId, span: Span) {
if let QPath::TypeRelative(self_ty, _) = qpath {
if let TyKind::TraitObject([poly_trait_ref, ..], _, TraitObjectSyntax::None) =
self_ty.kind
@@ -1008,12 +935,17 @@
let msg = "trait objects without an explicit `dyn` are deprecated";
let (sugg, app) = match self.tcx.sess.source_map().span_to_snippet(self_ty.span) {
Ok(s) if poly_trait_ref.trait_ref.path.is_global() => {
- (format!("<dyn ({})>", s), Applicability::MachineApplicable)
+ (format!("dyn ({})", s), Applicability::MachineApplicable)
}
- Ok(s) => (format!("<dyn {}>", s), Applicability::MachineApplicable),
- Err(_) => ("<dyn <type>>".to_string(), Applicability::HasPlaceholders),
+ Ok(s) => (format!("dyn {}", s), Applicability::MachineApplicable),
+ Err(_) => ("dyn <type>".to_string(), Applicability::HasPlaceholders),
};
- let replace = String::from("use `dyn`");
+ // Wrap in `<..>` if it isn't already.
+ let sugg = match self.tcx.sess.source_map().span_to_snippet(span) {
+ Ok(s) if s.starts_with('<') => sugg,
+ _ => format!("<{}>", sugg),
+ };
+ let sugg_label = "use `dyn`";
if self.sess().edition() >= Edition::Edition2021 {
let mut err = rustc_errors::struct_span_err!(
self.sess(),
@@ -1024,8 +956,8 @@
);
err.span_suggestion(
self_ty.span,
- &sugg,
- replace,
+ sugg_label,
+ sugg,
Applicability::MachineApplicable,
)
.emit();
@@ -1036,7 +968,7 @@
self_ty.span,
|lint| {
let mut db = lint.build(msg);
- db.span_suggestion(self_ty.span, &replace, sugg, app);
+ db.span_suggestion(self_ty.span, sugg_label, sugg, app);
db.emit()
},
);
@@ -1272,12 +1204,12 @@
let mut user_self_ty = None;
let mut is_alias_variant_ctor = false;
match res {
- Res::Def(DefKind::Ctor(CtorOf::Variant, _), _) => {
- if let Some(self_ty) = self_ty {
- let adt_def = self_ty.ty_adt_def().unwrap();
- user_self_ty = Some(UserSelfTy { impl_def_id: adt_def.did, self_ty });
- is_alias_variant_ctor = true;
- }
+ Res::Def(DefKind::Ctor(CtorOf::Variant, _), _)
+ if let Some(self_ty) = self_ty =>
+ {
+ let adt_def = self_ty.ty_adt_def().unwrap();
+ user_self_ty = Some(UserSelfTy { impl_def_id: adt_def.did, self_ty });
+ is_alias_variant_ctor = true;
}
Res::Def(DefKind::AssocFn | DefKind::AssocConst, def_id) => {
let container = tcx.associated_item(def_id).container;
@@ -1471,6 +1403,13 @@
(GenericParamDefKind::Const { .. }, GenericArg::Const(ct)) => {
self.fcx.const_arg_to_const(&ct.value, param.def_id).into()
}
+ (GenericParamDefKind::Type { .. }, GenericArg::Infer(inf)) => {
+ self.fcx.ty_infer(Some(param), inf.span).into()
+ }
+ (GenericParamDefKind::Const { .. }, GenericArg::Infer(inf)) => {
+ let tcx = self.fcx.tcx();
+ self.fcx.ct_infer(tcx.type_of(param.def_id), Some(param), inf.span).into()
+ }
_ => unreachable!(),
}
}
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
index f65cc42..9efb52a 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
@@ -29,6 +29,7 @@
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
pub(in super::super) fn check_casts(&self) {
let mut deferred_cast_checks = self.deferred_cast_checks.borrow_mut();
+ debug!("FnCtxt::check_casts: {} deferred checks", deferred_cast_checks.len());
for cast in deferred_cast_checks.drain(..) {
cast.check(self);
}
@@ -923,7 +924,7 @@
continue;
}
- if let ty::PredicateKind::Trait(predicate, _) =
+ if let ty::PredicateKind::Trait(predicate) =
error.obligation.predicate.kind().skip_binder()
{
// Collect the argument position for all arguments that could have caused this
@@ -936,7 +937,7 @@
let ty = self.resolve_vars_if_possible(ty);
// We walk the argument type because the argument's type could have
// been `Option<T>`, but the `FulfillmentError` references `T`.
- if ty.walk().any(|arg| arg == predicate.self_ty().into()) {
+ if ty.walk(self.tcx).any(|arg| arg == predicate.self_ty().into()) {
Some(i)
} else {
None
@@ -974,7 +975,7 @@
if let hir::ExprKind::Path(qpath) = &path.kind {
if let hir::QPath::Resolved(_, path) = &qpath {
for error in errors {
- if let ty::PredicateKind::Trait(predicate, _) =
+ if let ty::PredicateKind::Trait(predicate) =
error.obligation.predicate.kind().skip_binder()
{
// If any of the type arguments in this path segment caused the
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs b/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs
index 13686cf..9c70d2c 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs
@@ -96,7 +96,7 @@
/// `foo(return)`; we warn on the `foo()` expression. (We then
/// update the flag to `WarnedAlways` to suppress duplicate
/// reports.) Similarly, if we traverse to a fresh statement (or
- /// tail expression) from a `Always` setting, we will issue a
+ /// tail expression) from an `Always` setting, we will issue a
/// warning. This corresponds to something like `{return;
/// foo();}` or `{return; 22}`, where we would warn on the
/// `foo()` or `22`.
@@ -111,6 +111,12 @@
pub(super) enclosing_breakables: RefCell<EnclosingBreakables<'tcx>>,
pub(super) inh: &'a Inherited<'a, 'tcx>,
+
+ /// True if the function or closure's return type is known before
+ /// entering the function/closure, i.e. if the return type is
+ /// either given explicitly or inferred from, say, an `Fn*` trait
+ /// bound. Used for diagnostic purposes only.
+ pub(super) return_type_pre_known: bool,
}
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
@@ -137,6 +143,7 @@
by_id: Default::default(),
}),
inh,
+ return_type_pre_known: true,
}
}
@@ -173,10 +180,6 @@
None
}
- fn default_constness_for_trait_bounds(&self) -> hir::Constness {
- self.tcx.hir().get(self.body_id).constness()
- }
-
fn get_type_parameter_bounds(
&self,
_: Span,
@@ -194,7 +197,7 @@
predicates: tcx.arena.alloc_from_iter(
self.param_env.caller_bounds().iter().filter_map(|predicate| {
match predicate.kind().skip_binder() {
- ty::PredicateKind::Trait(data, _) if data.self_ty().is_param(index) => {
+ 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 54aab27..0acf1d2 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs
@@ -213,8 +213,14 @@
expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>,
) {
let expr = expr.peel_blocks();
- if let Some((sp, msg, suggestion, applicability)) = self.check_ref(expr, found, expected) {
- err.span_suggestion(sp, msg, suggestion, applicability);
+ if let Some((sp, msg, suggestion, applicability, verbose)) =
+ self.check_ref(expr, found, expected)
+ {
+ if verbose {
+ err.span_suggestion_verbose(sp, msg, suggestion, applicability);
+ } else {
+ err.span_suggestion(sp, msg, suggestion, applicability);
+ }
} else if let (ty::FnDef(def_id, ..), true) =
(&found.kind(), self.suggest_fn_call(err, expr, expected, found))
{
@@ -234,29 +240,36 @@
None // do not suggest code that is already there (#53348)
} else {
let method_call_list = [".to_vec()", ".to_string()"];
- let sugg = if receiver.ends_with(".clone()")
+ let mut sugg = if receiver.ends_with(".clone()")
&& method_call_list.contains(&method_call.as_str())
{
let max_len = receiver.rfind('.').unwrap();
- format!("{}{}", &receiver[..max_len], method_call)
+ vec![(
+ expr.span,
+ format!("{}{}", &receiver[..max_len], method_call),
+ )]
} else {
if expr.precedence().order() < ExprPrecedence::MethodCall.order() {
- format!("({}){}", receiver, method_call)
+ vec![
+ (expr.span.shrink_to_lo(), "(".to_string()),
+ (expr.span.shrink_to_hi(), format!("){}", method_call)),
+ ]
} else {
- format!("{}{}", receiver, method_call)
+ vec![(expr.span.shrink_to_hi(), method_call)]
}
};
- Some(if is_struct_pat_shorthand_field {
- format!("{}: {}", receiver, sugg)
- } else {
- sugg
- })
+ if is_struct_pat_shorthand_field {
+ sugg.insert(
+ 0,
+ (expr.span.shrink_to_lo(), format!("{}: ", receiver)),
+ );
+ }
+ Some(sugg)
}
})
.peekable();
if suggestions.peek().is_some() {
- err.span_suggestions(
- expr.span,
+ err.multipart_suggestions(
"try using a conversion method",
suggestions,
Applicability::MaybeIncorrect,
@@ -283,14 +296,13 @@
return;
}
let boxed_found = self.tcx.mk_box(found);
- if let (true, Ok(snippet)) = (
- self.can_coerce(boxed_found, expected),
- self.sess().source_map().span_to_snippet(expr.span),
- ) {
- err.span_suggestion(
- expr.span,
+ if self.can_coerce(boxed_found, expected) {
+ err.multipart_suggestion(
"store this in the heap by calling `Box::new`",
- format!("Box::new({})", snippet),
+ vec![
+ (expr.span.shrink_to_lo(), "Box::new(".to_string()),
+ (expr.span.shrink_to_hi(), ")".to_string()),
+ ],
Applicability::MachineApplicable,
);
err.note(
@@ -357,19 +369,18 @@
}
let boxed_found = self.tcx.mk_box(found);
let new_found = self.tcx.mk_lang_item(boxed_found, LangItem::Pin).unwrap();
- if let (true, Ok(snippet)) = (
- self.can_coerce(new_found, expected),
- self.sess().source_map().span_to_snippet(expr.span),
- ) {
+ if self.can_coerce(new_found, expected) {
match found.kind() {
ty::Adt(def, _) if def.is_box() => {
err.help("use `Box::pin`");
}
_ => {
- err.span_suggestion(
- expr.span,
+ err.multipart_suggestion(
"you need to pin and box this expression",
- format!("Box::pin({})", snippet),
+ vec![
+ (expr.span.shrink_to_lo(), "Box::pin(".to_string()),
+ (expr.span.shrink_to_hi(), ")".to_string()),
+ ],
Applicability::MachineApplicable,
);
}
@@ -547,7 +558,7 @@
let sp = self.tcx.sess.source_map().start_point(expr.span);
if let Some(sp) = self.tcx.sess.parse_sess.ambiguous_block_expr_parse.borrow().get(&sp) {
// `{ 42 } &&x` (#61475) or `{ 42 } && if x { 1 } else { 0 }`
- self.tcx.sess.parse_sess.expr_parentheses_needed(err, *sp, None);
+ self.tcx.sess.parse_sess.expr_parentheses_needed(err, *sp);
}
}
diff --git a/compiler/rustc_typeck/src/check/inherited.rs b/compiler/rustc_typeck/src/check/inherited.rs
index 7e43e36..6006c8f 100644
--- a/compiler/rustc_typeck/src/check/inherited.rs
+++ b/compiler/rustc_typeck/src/check/inherited.rs
@@ -1,18 +1,15 @@
use super::callee::DeferredCallResolution;
use super::MaybeInProgressTables;
-use rustc_data_structures::fx::FxHashMap;
-use rustc_data_structures::vec_map::VecMap;
use rustc_hir as hir;
use rustc_hir::def_id::{DefIdMap, LocalDefId};
use rustc_hir::HirIdMap;
use rustc_infer::infer;
use rustc_infer::infer::{InferCtxt, InferOk, TyCtxtInferExt};
use rustc_middle::ty::fold::TypeFoldable;
-use rustc_middle::ty::{self, OpaqueTypeKey, Ty, TyCtxt};
+use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_span::{self, Span};
use rustc_trait_selection::infer::InferCtxtExt as _;
-use rustc_trait_selection::opaque_types::OpaqueTypeDecl;
use rustc_trait_selection::traits::{self, ObligationCause, TraitEngine, TraitEngineExt};
use std::cell::RefCell;
@@ -55,18 +52,8 @@
pub(super) deferred_generator_interiors:
RefCell<Vec<(hir::BodyId, Ty<'tcx>, hir::GeneratorKind)>>,
- // Opaque types found in explicit return types and their
- // associated fresh inference variable. Writeback resolves these
- // variables to get the concrete type, which can be used to
- // 'de-opaque' OpaqueTypeDecl, after typeck is done with all functions.
- pub(super) opaque_types: RefCell<VecMap<OpaqueTypeKey<'tcx>, OpaqueTypeDecl<'tcx>>>,
-
- /// A map from inference variables created from opaque
- /// type instantiations (`ty::Infer`) to the actual opaque
- /// type (`ty::Opaque`). Used during fallback to map unconstrained
- /// opaque type inference variables to their corresponding
- /// opaque type.
- pub(super) opaque_types_vars: RefCell<FxHashMap<Ty<'tcx>, Ty<'tcx>>>,
+ /// Reports whether this is in a const context.
+ pub(super) constness: hir::Constness,
pub(super) body_id: Option<hir::BodyId>,
}
@@ -111,6 +98,16 @@
pub(super) fn new(infcx: InferCtxt<'a, 'tcx>, def_id: LocalDefId) -> Self {
let tcx = infcx.tcx;
let item_id = tcx.hir().local_def_id_to_hir_id(def_id);
+ Self::with_constness(infcx, def_id, tcx.hir().get(item_id).constness_for_typeck())
+ }
+
+ pub(super) fn with_constness(
+ infcx: InferCtxt<'a, 'tcx>,
+ def_id: LocalDefId,
+ constness: hir::Constness,
+ ) -> Self {
+ let tcx = infcx.tcx;
+ let item_id = tcx.hir().local_def_id_to_hir_id(def_id);
let body_id = tcx.hir().maybe_body_owned_by(item_id);
Inherited {
@@ -124,8 +121,7 @@
deferred_call_resolutions: RefCell::new(Default::default()),
deferred_cast_checks: RefCell::new(Vec::new()),
deferred_generator_interiors: RefCell::new(Vec::new()),
- opaque_types: RefCell::new(Default::default()),
- opaque_types_vars: RefCell::new(Default::default()),
+ constness,
body_id,
}
}
diff --git a/compiler/rustc_typeck/src/check/intrinsic.rs b/compiler/rustc_typeck/src/check/intrinsic.rs
index 6661df21..664954b 100644
--- a/compiler/rustc_typeck/src/check/intrinsic.rs
+++ b/compiler/rustc_typeck/src/check/intrinsic.rs
@@ -102,6 +102,7 @@
| sym::maxnumf64
| sym::type_name
| sym::forget
+ | sym::black_box
| sym::variant_count => hir::Unsafety::Normal,
_ => hir::Unsafety::Unsafe,
}
@@ -387,6 +388,8 @@
(1, vec![param_ty; 2], tcx.types.bool)
}
+ sym::black_box => (1, vec![param(0)], param(0)),
+
other => {
tcx.sess.emit_err(UnrecognizedIntrinsicFunction { span: it.span, name: other });
return;
diff --git a/compiler/rustc_typeck/src/check/method/confirm.rs b/compiler/rustc_typeck/src/check/method/confirm.rs
index 75299ba..88be49e 100644
--- a/compiler/rustc_typeck/src/check/method/confirm.rs
+++ b/compiler/rustc_typeck/src/check/method/confirm.rs
@@ -366,6 +366,13 @@
(GenericParamDefKind::Const { .. }, GenericArg::Const(ct)) => {
self.cfcx.const_arg_to_const(&ct.value, param.def_id).into()
}
+ (GenericParamDefKind::Type { .. }, GenericArg::Infer(inf)) => {
+ self.cfcx.ty_infer(Some(param), inf.span).into()
+ }
+ (GenericParamDefKind::Const { .. }, GenericArg::Infer(inf)) => {
+ let tcx = self.cfcx.tcx();
+ self.cfcx.ct_infer(tcx.type_of(param.def_id), Some(param), inf.span).into()
+ }
_ => unreachable!(),
}
}
@@ -500,7 +507,7 @@
traits::elaborate_predicates(self.tcx, predicates.predicates.iter().copied())
// We don't care about regions here.
.filter_map(|obligation| match obligation.predicate.kind().skip_binder() {
- ty::PredicateKind::Trait(trait_pred, _) if trait_pred.def_id() == sized_def_id => {
+ ty::PredicateKind::Trait(trait_pred) if trait_pred.def_id() == sized_def_id => {
let span = iter::zip(&predicates.predicates, &predicates.spans)
.find_map(
|(p, span)| {
diff --git a/compiler/rustc_typeck/src/check/method/prelude2021.rs b/compiler/rustc_typeck/src/check/method/prelude2021.rs
index f13e239..5c8056b 100644
--- a/compiler/rustc_typeck/src/check/method/prelude2021.rs
+++ b/compiler/rustc_typeck/src/check/method/prelude2021.rs
@@ -5,9 +5,9 @@
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_middle::ty::subst::InternalSubsts;
-use rustc_middle::ty::{Ref, Ty};
+use rustc_middle::ty::{Adt, Array, Ref, Ty};
use rustc_session::lint::builtin::RUST_2021_PRELUDE_COLLISIONS;
-use rustc_span::symbol::kw::Underscore;
+use rustc_span::symbol::kw::{Empty, Underscore};
use rustc_span::symbol::{sym, Ident};
use rustc_span::Span;
use rustc_trait_selection::infer::InferCtxtExt;
@@ -38,10 +38,20 @@
return;
}
- // These are the method names that were added to prelude in Rust 2021
- if !matches!(segment.ident.name, sym::try_into) {
- return;
- }
+ let prelude_or_array_lint = match segment.ident.name {
+ // `try_into` was added to the prelude in Rust 2021.
+ sym::try_into => RUST_2021_PRELUDE_COLLISIONS,
+ // `into_iter` wasn't added to the prelude,
+ // but `[T; N].into_iter()` doesn't resolve to IntoIterator::into_iter
+ // before Rust 2021, which results in the same problem.
+ // It is only a problem for arrays.
+ sym::into_iter if let Array(..) = self_ty.kind() => {
+ // In this case, it wasn't really a prelude addition that was the problem.
+ // Instead, the problem is that the array-into_iter hack will no longer apply in Rust 2021.
+ rustc_lint::ARRAY_INTO_ITER
+ }
+ _ => return,
+ };
// No need to lint if method came from std/core, as that will now be in the prelude
if matches!(self.tcx.crate_name(pick.item.def_id.krate), sym::std | sym::core) {
@@ -69,7 +79,7 @@
// Inherent impls only require not relying on autoref and autoderef in order to
// ensure that the trait implementation won't be used
self.tcx.struct_span_lint_hir(
- RUST_2021_PRELUDE_COLLISIONS,
+ prelude_or_array_lint,
self_expr.hir_id,
self_expr.span,
|lint| {
@@ -130,7 +140,7 @@
// trait implementations require full disambiguation to not clash with the new prelude
// additions (i.e. convert from dot-call to fully-qualified call)
self.tcx.struct_span_lint_hir(
- RUST_2021_PRELUDE_COLLISIONS,
+ prelude_or_array_lint,
call_expr.hir_id,
call_expr.span,
|lint| {
@@ -146,15 +156,16 @@
segment.ident.name
));
- let (self_adjusted, precise) = self.adjust_expr(pick, self_expr);
+ let (self_adjusted, precise) = self.adjust_expr(pick, self_expr, sp);
if precise {
let args = args
.iter()
.skip(1)
.map(|arg| {
+ let span = arg.span.find_ancestor_inside(sp).unwrap_or_default();
format!(
", {}",
- self.sess().source_map().span_to_snippet(arg.span).unwrap()
+ self.sess().source_map().span_to_snippet(span).unwrap()
)
})
.collect::<String>();
@@ -163,8 +174,22 @@
sp,
"disambiguate the associated function",
format!(
- "{}::{}({}{})",
- trait_name, segment.ident.name, self_adjusted, args
+ "{}::{}{}({}{})",
+ trait_name,
+ segment.ident.name,
+ if let Some(args) = segment.args.as_ref().and_then(|args| self
+ .sess()
+ .source_map()
+ .span_to_snippet(args.span_ext)
+ .ok())
+ {
+ // Keep turbofish.
+ format!("::{}", args)
+ } else {
+ String::new()
+ },
+ self_adjusted,
+ args,
),
Applicability::MachineApplicable,
);
@@ -239,32 +264,57 @@
let trait_path = self.trait_path_or_bare_name(span, expr_id, pick.item.container.id());
let trait_generics = self.tcx.generics_of(pick.item.container.id());
- let parameter_count = trait_generics.count() - (trait_generics.has_self as usize);
- let trait_name = if parameter_count == 0 {
- trait_path
- } else {
- format!(
- "{}<{}>",
- trait_path,
- std::iter::repeat("_").take(parameter_count).collect::<Vec<_>>().join(", ")
- )
- };
+ let trait_name =
+ if trait_generics.params.len() <= trait_generics.has_self as usize {
+ trait_path
+ } else {
+ let counts = trait_generics.own_counts();
+ format!(
+ "{}<{}>",
+ trait_path,
+ std::iter::repeat("'_")
+ .take(counts.lifetimes)
+ .chain(std::iter::repeat("_").take(
+ counts.types + counts.consts - trait_generics.has_self as usize
+ ))
+ .collect::<Vec<_>>()
+ .join(", ")
+ )
+ };
let mut lint = lint.build(&format!(
"trait-associated function `{}` will become ambiguous in Rust 2021",
method_name.name
));
- let self_ty = self
- .sess()
- .source_map()
- .span_to_snippet(self_ty_span)
- .unwrap_or_else(|_| self_ty.to_string());
+ let mut self_ty_name = self_ty_span
+ .find_ancestor_inside(span)
+ .and_then(|span| self.sess().source_map().span_to_snippet(span).ok())
+ .unwrap_or_else(|| self_ty.to_string());
+ // Get the number of generics the self type has (if an Adt) unless we can determine that
+ // the user has written the self type with generics already which we (naively) do by looking
+ // for a "<" in `self_ty_name`.
+ if !self_ty_name.contains('<') {
+ if let Adt(def, _) = self_ty.kind() {
+ let generics = self.tcx.generics_of(def.did);
+ if !generics.params.is_empty() {
+ let counts = generics.own_counts();
+ self_ty_name += &format!(
+ "<{}>",
+ std::iter::repeat("'_")
+ .take(counts.lifetimes)
+ .chain(std::iter::repeat("_").take(counts.types + counts.consts))
+ .collect::<Vec<_>>()
+ .join(", ")
+ );
+ }
+ }
+ }
lint.span_suggestion(
span,
"disambiguate the associated function",
- format!("<{} as {}>::{}", self_ty, trait_name, method_name.name,),
+ format!("<{} as {}>::{}", self_ty_name, trait_name, method_name.name,),
Applicability::MachineApplicable,
);
@@ -307,7 +357,12 @@
.filter_map(|item| if item.ident.name != Underscore { Some(item.ident) } else { None })
.next();
if let Some(any_id) = any_id {
- return Some(format!("{}", any_id));
+ if any_id.name == Empty {
+ // Glob import, so just use its name.
+ return None;
+ } else {
+ return Some(format!("{}", any_id));
+ }
}
// All that is left is `_`! We need to use the full path. It doesn't matter which one we pick,
@@ -329,7 +384,12 @@
/// Creates a string version of the `expr` that includes explicit adjustments.
/// Returns the string and also a bool indicating whther this is a *precise*
/// suggestion.
- fn adjust_expr(&self, pick: &Pick<'tcx>, expr: &hir::Expr<'tcx>) -> (String, bool) {
+ fn adjust_expr(
+ &self,
+ pick: &Pick<'tcx>,
+ expr: &hir::Expr<'tcx>,
+ outer: Span,
+ ) -> (String, bool) {
let derefs = "*".repeat(pick.autoderefs);
let autoref = match pick.autoref_or_ptr_adjustment {
@@ -338,12 +398,15 @@
Some(probe::AutorefOrPtrAdjustment::ToConstPtr) | None => "",
};
- let (expr_text, precise) =
- if let Ok(expr_text) = self.sess().source_map().span_to_snippet(expr.span) {
- (expr_text, true)
- } else {
- (format!("(..)"), false)
- };
+ let (expr_text, precise) = if let Some(expr_text) = expr
+ .span
+ .find_ancestor_inside(outer)
+ .and_then(|span| self.sess().source_map().span_to_snippet(span).ok())
+ {
+ (expr_text, true)
+ } else {
+ ("(..)".to_string(), false)
+ };
let adjusted_text = if let Some(probe::AutorefOrPtrAdjustment::ToConstPtr) =
pick.autoref_or_ptr_adjustment
diff --git a/compiler/rustc_typeck/src/check/method/probe.rs b/compiler/rustc_typeck/src/check/method/probe.rs
index 9037ffe..1c7d68a 100644
--- a/compiler/rustc_typeck/src/check/method/probe.rs
+++ b/compiler/rustc_typeck/src/check/method/probe.rs
@@ -616,32 +616,30 @@
let lang_items = self.tcx.lang_items();
match *self_ty.value.value.kind() {
- ty::Dynamic(ref data, ..) => {
- if let Some(p) = data.principal() {
- // Subtle: we can't use `instantiate_query_response` here: using it will
- // commit to all of the type equalities assumed by inference going through
- // autoderef (see the `method-probe-no-guessing` test).
- //
- // However, in this code, it is OK if we end up with an object type that is
- // "more general" than the object type that we are evaluating. For *every*
- // object type `MY_OBJECT`, a function call that goes through a trait-ref
- // of the form `<MY_OBJECT as SuperTraitOf(MY_OBJECT)>::func` is a valid
- // `ObjectCandidate`, and it should be discoverable "exactly" through one
- // of the iterations in the autoderef loop, so there is no problem with it
- // being discoverable in another one of these iterations.
- //
- // Using `instantiate_canonical_with_fresh_inference_vars` on our
- // `Canonical<QueryResponse<Ty<'tcx>>>` and then *throwing away* the
- // `CanonicalVarValues` will exactly give us such a generalization - it
- // will still match the original object type, but it won't pollute our
- // type variables in any form, so just do that!
- let (QueryResponse { value: generalized_self_ty, .. }, _ignored_var_values) =
- self.fcx
- .instantiate_canonical_with_fresh_inference_vars(self.span, &self_ty);
+ ty::Dynamic(ref data, ..) if let Some(p) = data.principal() => {
+ // Subtle: we can't use `instantiate_query_response` here: using it will
+ // commit to all of the type equalities assumed by inference going through
+ // autoderef (see the `method-probe-no-guessing` test).
+ //
+ // However, in this code, it is OK if we end up with an object type that is
+ // "more general" than the object type that we are evaluating. For *every*
+ // object type `MY_OBJECT`, a function call that goes through a trait-ref
+ // of the form `<MY_OBJECT as SuperTraitOf(MY_OBJECT)>::func` is a valid
+ // `ObjectCandidate`, and it should be discoverable "exactly" through one
+ // of the iterations in the autoderef loop, so there is no problem with it
+ // being discoverable in another one of these iterations.
+ //
+ // Using `instantiate_canonical_with_fresh_inference_vars` on our
+ // `Canonical<QueryResponse<Ty<'tcx>>>` and then *throwing away* the
+ // `CanonicalVarValues` will exactly give us such a generalization - it
+ // will still match the original object type, but it won't pollute our
+ // type variables in any form, so just do that!
+ let (QueryResponse { value: generalized_self_ty, .. }, _ignored_var_values) =
+ self.fcx
+ .instantiate_canonical_with_fresh_inference_vars(self.span, &self_ty);
- self.assemble_inherent_candidates_from_object(generalized_self_ty);
- self.assemble_inherent_impl_candidates_for_type(p.def_id());
- }
+ self.assemble_inherent_candidates_from_object(generalized_self_ty);
+ self.assemble_inherent_impl_candidates_for_type(p.def_id());
}
ty::Adt(def, _) => {
self.assemble_inherent_impl_candidates_for_type(def.did);
@@ -832,7 +830,7 @@
let bounds = self.param_env.caller_bounds().iter().filter_map(|predicate| {
let bound_predicate = predicate.kind();
match bound_predicate.skip_binder() {
- ty::PredicateKind::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))
@@ -841,6 +839,7 @@
}
}
ty::PredicateKind::Subtype(..)
+ | ty::PredicateKind::Coerce(..)
| ty::PredicateKind::Projection(..)
| ty::PredicateKind::RegionOutlives(..)
| ty::PredicateKind::WellFormed(..)
diff --git a/compiler/rustc_typeck/src/check/method/suggest.rs b/compiler/rustc_typeck/src/check/method/suggest.rs
index 77586ce..afe274a 100644
--- a/compiler/rustc_typeck/src/check/method/suggest.rs
+++ b/compiler/rustc_typeck/src/check/method/suggest.rs
@@ -70,15 +70,13 @@
pub fn report_method_error(
&self,
- span: Span,
+ mut span: Span,
rcvr_ty: Ty<'tcx>,
item_name: Ident,
source: SelfSource<'tcx>,
error: MethodError<'tcx>,
args: Option<&'tcx [hir::Expr<'tcx>]>,
) -> Option<DiagnosticBuilder<'_>> {
- let orig_span = span;
- let mut span = span;
// Avoid suggestions when we don't know what's going on.
if rcvr_ty.references_error() {
return None;
@@ -545,7 +543,6 @@
} 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,
@@ -683,7 +680,7 @@
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::PredicateKind::Trait(p, _)) =
+ 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() {
@@ -763,7 +760,7 @@
bound_span_label(projection_ty.self_ty(), &obligation, &quiet);
Some((obligation, projection_ty.self_ty()))
}
- ty::PredicateKind::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();
@@ -1200,7 +1197,7 @@
match p.kind().skip_binder() {
// Hide traits if they are present in predicates as they can be fixed without
// having to implement them.
- ty::PredicateKind::Trait(t, _) => t.def_id() == info.def_id,
+ ty::PredicateKind::Trait(t) => t.def_id() == info.def_id,
ty::PredicateKind::Projection(p) => {
p.projection_ty.item_def_id == info.def_id
}
@@ -1695,8 +1692,8 @@
source_map: &source_map::SourceMap,
) {
let mut applicability = Applicability::MachineApplicable;
- let sugg_args = if let (ty::AssocKind::Fn, Some(args)) = (kind, args) {
- format!(
+ let (span, sugg) = if let (ty::AssocKind::Fn, Some(args)) = (kind, args) {
+ let args = format!(
"({}{})",
if rcvr_ty.is_region_ptr() {
if rcvr_ty.is_mutable_ptr() { "&mut " } else { "&" }
@@ -1710,12 +1707,12 @@
}))
.collect::<Vec<_>>()
.join(", "),
- )
+ );
+ (span, format!("{}::{}{}", trait_name, item_name, args))
} else {
- String::new()
+ (span.with_hi(item_name.span.lo()), format!("{}::", trait_name))
};
- let sugg = format!("{}::{}{}", trait_name, item_name, sugg_args);
- err.span_suggestion(
+ err.span_suggestion_verbose(
span,
&format!(
"disambiguate the {} for {}",
diff --git a/compiler/rustc_typeck/src/check/mod.rs b/compiler/rustc_typeck/src/check/mod.rs
index d30b057..803c440 100644
--- a/compiler/rustc_typeck/src/check/mod.rs
+++ b/compiler/rustc_typeck/src/check/mod.rs
@@ -75,6 +75,7 @@
pub mod dropck;
mod expectation;
mod expr;
+mod fallback;
mod fn_ctxt;
mod gather_locals;
mod generator_interior;
@@ -257,9 +258,7 @@
}
/// If this `DefId` is a "primary tables entry", returns
-/// `Some((body_id, header, decl))` with information about
-/// its body-id, fn-header and fn-decl (if any). Otherwise,
-/// returns `None`.
+/// `Some((body_id, body_ty, fn_sig))`. Otherwise, returns `None`.
///
/// If this function returns `Some`, then `typeck_results(def_id)` will
/// succeed; if it returns `None`, then `typeck_results(def_id)` may or
@@ -269,32 +268,28 @@
fn primary_body_of(
tcx: TyCtxt<'_>,
id: hir::HirId,
-) -> Option<(hir::BodyId, Option<&hir::Ty<'_>>, Option<&hir::FnHeader>, Option<&hir::FnDecl<'_>>)> {
+) -> Option<(hir::BodyId, Option<&hir::Ty<'_>>, Option<&hir::FnSig<'_>>)> {
match tcx.hir().get(id) {
Node::Item(item) => match item.kind {
hir::ItemKind::Const(ref ty, body) | hir::ItemKind::Static(ref ty, _, body) => {
- Some((body, Some(ty), None, None))
+ Some((body, Some(ty), None))
}
- hir::ItemKind::Fn(ref sig, .., body) => {
- Some((body, None, Some(&sig.header), Some(&sig.decl)))
- }
+ hir::ItemKind::Fn(ref sig, .., body) => Some((body, None, Some(&sig))),
_ => None,
},
Node::TraitItem(item) => match item.kind {
- hir::TraitItemKind::Const(ref ty, Some(body)) => Some((body, Some(ty), None, None)),
+ hir::TraitItemKind::Const(ref ty, Some(body)) => Some((body, Some(ty), None)),
hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(body)) => {
- Some((body, None, Some(&sig.header), Some(&sig.decl)))
+ Some((body, None, Some(&sig)))
}
_ => None,
},
Node::ImplItem(item) => match item.kind {
- hir::ImplItemKind::Const(ref ty, body) => Some((body, Some(ty), None, None)),
- hir::ImplItemKind::Fn(ref sig, body) => {
- Some((body, None, Some(&sig.header), Some(&sig.decl)))
- }
+ hir::ImplItemKind::Const(ref ty, body) => Some((body, Some(ty), None)),
+ hir::ImplItemKind::Fn(ref sig, body) => Some((body, None, Some(&sig))),
_ => None,
},
- Node::AnonConst(constant) => Some((constant.body, None, None, None)),
+ Node::AnonConst(constant) => Some((constant.body, None, None)),
_ => None,
}
}
@@ -362,14 +357,14 @@
let span = tcx.hir().span(id);
// Figure out what primary body this item has.
- let (body_id, body_ty, fn_header, fn_decl) = primary_body_of(tcx, id).unwrap_or_else(|| {
+ let (body_id, body_ty, fn_sig) = primary_body_of(tcx, id).unwrap_or_else(|| {
span_bug!(span, "can't type-check body of {:?}", def_id);
});
let body = tcx.hir().body(body_id);
let typeck_results = Inherited::build(tcx, def_id).enter(|inh| {
let param_env = tcx.param_env(def_id);
- let fcx = if let (Some(header), Some(decl)) = (fn_header, fn_decl) {
+ let (fcx, wf_tys) = if let Some(hir::FnSig { header, decl, .. }) = fn_sig {
let fn_sig = if crate::collect::get_infer_ret_ty(&decl.output).is_some() {
let fcx = FnCtxt::new(&inh, param_env, body.value.hir_id);
<dyn AstConv<'_>>::ty_of_fn(
@@ -388,17 +383,25 @@
check_abi(tcx, id, span, fn_sig.abi());
+ // When normalizing the function signature, we assume all types are
+ // well-formed. So, we don't need to worry about the obligations
+ // from normalization. We could just discard these, but to align with
+ // compare_method and elsewhere, we just add implied bounds for
+ // these types.
+ let mut wf_tys = vec![];
// Compute the fty from point of view of inside the fn.
let fn_sig = tcx.liberate_late_bound_regions(def_id.to_def_id(), fn_sig);
+ wf_tys.extend(fn_sig.inputs_and_output.iter());
let fn_sig = inh.normalize_associated_types_in(
body.value.span,
body_id.hir_id,
param_env,
fn_sig,
);
+ wf_tys.extend(fn_sig.inputs_and_output.iter());
- let fcx = check_fn(&inh, param_env, fn_sig, decl, id, body, None).0;
- fcx
+ let fcx = check_fn(&inh, param_env, fn_sig, decl, id, body, None, true).0;
+ (fcx, wf_tys)
} else {
let fcx = FnCtxt::new(&inh, param_env, body.value.hir_id);
let expected_type = body_ty
@@ -448,57 +451,15 @@
fcx.write_ty(id, expected_type);
- fcx
+ (fcx, vec![])
};
- // All type checking constraints were added, try to fallback unsolved variables.
- fcx.select_obligations_where_possible(false, |_| {});
- let mut fallback_has_occurred = false;
-
- // We do fallback in two passes, to try to generate
- // better error messages.
- // The first time, we do *not* replace opaque types.
- for ty in &fcx.unsolved_variables() {
- fallback_has_occurred |= fcx.fallback_if_possible(ty, FallbackMode::NoOpaque);
- }
- // We now see if we can make progress. This might
- // cause us to unify inference variables for opaque types,
- // since we may have unified some other type variables
- // during the first phase of fallback.
- // This means that we only replace inference variables with their underlying
- // opaque types as a last resort.
- //
- // In code like this:
- //
- // ```rust
- // type MyType = impl Copy;
- // fn produce() -> MyType { true }
- // fn bad_produce() -> MyType { panic!() }
- // ```
- //
- // we want to unify the opaque inference variable in `bad_produce`
- // with the diverging fallback for `panic!` (e.g. `()` or `!`).
- // This will produce a nice error message about conflicting concrete
- // types for `MyType`.
- //
- // If we had tried to fallback the opaque inference variable to `MyType`,
- // we will generate a confusing type-check error that does not explicitly
- // refer to opaque types.
- fcx.select_obligations_where_possible(fallback_has_occurred, |_| {});
-
- // We now run fallback again, but this time we allow it to replace
- // unconstrained opaque type variables, in addition to performing
- // other kinds of fallback.
- for ty in &fcx.unsolved_variables() {
- fallback_has_occurred |= fcx.fallback_if_possible(ty, FallbackMode::All);
- }
-
- // See if we can make any more progress.
- fcx.select_obligations_where_possible(fallback_has_occurred, |_| {});
+ let fallback_has_occurred = fcx.type_inference_fallback();
// Even though coercion casts provide type hints, we check casts after fallback for
// backwards compatibility. This makes fallback a stronger type hint than a cast coercion.
fcx.check_casts();
+ fcx.select_obligations_where_possible(fallback_has_occurred, |_| {});
// Closure and generator analysis may run after fallback
// because they don't constrain other type variables.
@@ -513,8 +474,8 @@
fcx.select_all_obligations_or_error();
- if fn_decl.is_some() {
- fcx.regionck_fn(id, body);
+ if fn_sig.is_some() {
+ fcx.regionck_fn(id, body, span, &wf_tys);
} else {
fcx.regionck_expr(body);
}
@@ -695,7 +656,7 @@
debug!("predicate {:?}", predicate);
let bound_predicate = predicate.kind();
match bound_predicate.skip_binder() {
- ty::PredicateKind::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() {
@@ -791,7 +752,7 @@
})
})
.chain(std::iter::once(if sig.c_variadic { Some("...".to_string()) } else { None }))
- .filter_map(|arg| arg)
+ .flatten()
.collect::<Vec<String>>()
.join(", ");
let output = sig.output();
@@ -920,16 +881,6 @@
TupleArguments,
}
-/// Controls how we perform fallback for unconstrained
-/// type variables.
-enum FallbackMode {
- /// Do not fallback type variables to opaque types.
- NoOpaque,
- /// Perform all possible kinds of fallback, including
- /// turning type variables to opaque types.
- All,
-}
-
/// A wrapper for `InferCtxt`'s `in_progress_typeck_results` field.
#[derive(Copy, Clone)]
struct MaybeInProgressTables<'a, 'tcx> {
diff --git a/compiler/rustc_typeck/src/check/op.rs b/compiler/rustc_typeck/src/check/op.rs
index 963436d..9b495fb 100644
--- a/compiler/rustc_typeck/src/check/op.rs
+++ b/compiler/rustc_typeck/src/check/op.rs
@@ -428,7 +428,7 @@
}
}
if let Some(missing_trait) = missing_trait {
- let mut visitor = TypeParamVisitor(vec![]);
+ let mut visitor = TypeParamVisitor(self.tcx, vec![]);
visitor.visit_ty(lhs_ty);
if op.node == hir::BinOpKind::Add
@@ -439,7 +439,7 @@
// This has nothing here because it means we did string
// concatenation (e.g., "Hello " + "World!"). This means
// we don't want the note in the else clause to be emitted
- } else if let [ty] = &visitor.0[..] {
+ } else if let [ty] = &visitor.1[..] {
if let ty::Param(p) = *ty.kind() {
// Check if the method would be found if the type param wasn't
// involved. If so, it means that adding a trait bound to the param is
@@ -1003,12 +1003,15 @@
}
}
-struct TypeParamVisitor<'tcx>(Vec<Ty<'tcx>>);
+struct TypeParamVisitor<'tcx>(TyCtxt<'tcx>, Vec<Ty<'tcx>>);
impl<'tcx> TypeVisitor<'tcx> for TypeParamVisitor<'tcx> {
+ fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
+ Some(self.0)
+ }
fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
if let ty::Param(_) = ty.kind() {
- self.0.push(ty);
+ self.1.push(ty);
}
ty.super_visit_with(self)
}
diff --git a/compiler/rustc_typeck/src/check/pat.rs b/compiler/rustc_typeck/src/check/pat.rs
index 981a040..140a9d1 100644
--- a/compiler/rustc_typeck/src/check/pat.rs
+++ b/compiler/rustc_typeck/src/check/pat.rs
@@ -15,7 +15,8 @@
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_span::{BytePos, MultiSpan, DUMMY_SP};
+use rustc_trait_selection::autoderef::Autoderef;
use rustc_trait_selection::traits::{ObligationCause, Pattern};
use ty::VariantDef;
@@ -626,15 +627,15 @@
let binding_parent = tcx.hir().get(binding_parent_id);
debug!("inner {:?} pat {:?} parent {:?}", inner, pat, binding_parent);
match binding_parent {
- hir::Node::Param(hir::Param { span, .. }) => {
- if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(inner.span) {
- err.span_suggestion(
- *span,
- &format!("did you mean `{}`", snippet),
- format!(" &{}", expected),
- Applicability::MachineApplicable,
- );
- }
+ hir::Node::Param(hir::Param { span, .. })
+ if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(inner.span) =>
+ {
+ err.span_suggestion(
+ *span,
+ &format!("did you mean `{}`", snippet),
+ format!(" &{}", expected),
+ Applicability::MachineApplicable,
+ );
}
hir::Node::Arm(_) | hir::Node::Pat(_) => {
// rely on match ergonomics or it might be nested `&&pat`
@@ -989,10 +990,25 @@
) {
let subpats_ending = pluralize!(subpats.len());
let fields_ending = pluralize!(fields.len());
+
+ let subpat_spans = if subpats.is_empty() {
+ vec![pat_span]
+ } else {
+ subpats.iter().map(|p| p.span).collect()
+ };
+ let last_subpat_span = *subpat_spans.last().unwrap();
let res_span = self.tcx.def_span(res.def_id());
+ let def_ident_span = self.tcx.def_ident_span(res.def_id()).unwrap_or(res_span);
+ let field_def_spans = if fields.is_empty() {
+ vec![res_span]
+ } else {
+ fields.iter().map(|f| f.ident.span).collect()
+ };
+ let last_field_def_span = *field_def_spans.last().unwrap();
+
let mut err = struct_span_err!(
self.tcx.sess,
- pat_span,
+ MultiSpan::from_spans(subpat_spans),
E0023,
"this pattern has {} field{}, but the corresponding {} has {} field{}",
subpats.len(),
@@ -1002,10 +1018,22 @@
fields_ending,
);
err.span_label(
- pat_span,
- format!("expected {} field{}, found {}", fields.len(), fields_ending, subpats.len(),),
- )
- .span_label(res_span, format!("{} defined here", res.descr()));
+ last_subpat_span,
+ &format!("expected {} field{}, found {}", fields.len(), fields_ending, subpats.len()),
+ );
+ if self.tcx.sess.source_map().is_multiline(qpath.span().between(last_subpat_span)) {
+ err.span_label(qpath.span(), "");
+ }
+ if self.tcx.sess.source_map().is_multiline(def_ident_span.between(last_field_def_span)) {
+ err.span_label(def_ident_span, format!("{} defined here", res.descr()));
+ }
+ for span in &field_def_spans[..field_def_spans.len() - 1] {
+ err.span_label(*span, "");
+ }
+ err.span_label(
+ last_field_def_span,
+ &format!("{} has {} field{}", res.descr(), fields.len(), fields_ending),
+ );
// Identify the case `Some(x, y)` where the expected type is e.g. `Option<(T, U)>`.
// More generally, the expected type wants a tuple variant with one field of an
@@ -1249,15 +1277,23 @@
tcx.sess.struct_span_err(pat.span, "`..` cannot be used in union patterns").emit();
}
} else if !etc && !unmentioned_fields.is_empty() {
- let no_accessible_unmentioned_fields = !unmentioned_fields.iter().any(|(field, _)| {
- field.vis.is_accessible_from(tcx.parent_module(pat.hir_id).to_def_id(), tcx)
- });
+ let accessible_unmentioned_fields: Vec<_> = unmentioned_fields
+ .iter()
+ .copied()
+ .filter(|(field, _)| {
+ field.vis.is_accessible_from(tcx.parent_module(pat.hir_id).to_def_id(), tcx)
+ })
+ .collect();
- if no_accessible_unmentioned_fields {
+ if accessible_unmentioned_fields.is_empty() {
unmentioned_err = Some(self.error_no_accessible_fields(pat, &fields));
} else {
- unmentioned_err =
- Some(self.error_unmentioned_fields(pat, &unmentioned_fields, &fields));
+ unmentioned_err = Some(self.error_unmentioned_fields(
+ pat,
+ &accessible_unmentioned_fields,
+ accessible_unmentioned_fields.len() != unmentioned_fields.len(),
+ &fields,
+ ));
}
}
match (inexistent_fields_err, unmentioned_err) {
@@ -1284,13 +1320,12 @@
(Some(mut err), None) => {
err.emit();
}
- (None, None) => {
- if let Some(mut err) =
- self.error_tuple_variant_index_shorthand(variant, pat, fields)
- {
- err.emit();
- }
+ (None, None) if let Some(mut err) =
+ self.error_tuple_variant_index_shorthand(variant, pat, fields) =>
+ {
+ err.emit();
}
+ (None, None) => {}
}
no_field_errors
}
@@ -1582,17 +1617,19 @@
&self,
pat: &Pat<'_>,
unmentioned_fields: &[(&ty::FieldDef, Ident)],
+ have_inaccessible_fields: bool,
fields: &'tcx [hir::PatField<'tcx>],
) -> DiagnosticBuilder<'tcx> {
+ let inaccessible = if have_inaccessible_fields { " and inaccessible fields" } else { "" };
let field_names = if unmentioned_fields.len() == 1 {
- format!("field `{}`", unmentioned_fields[0].1)
+ format!("field `{}`{}", unmentioned_fields[0].1, inaccessible)
} else {
let fields = unmentioned_fields
.iter()
.map(|(_, name)| format!("`{}`", name))
.collect::<Vec<String>>()
.join(", ");
- format!("fields {}", fields)
+ format!("fields {}{}", fields, inaccessible)
};
let mut err = struct_span_err!(
self.tcx.sess,
@@ -1623,17 +1660,19 @@
err.span_suggestion(
sp,
&format!(
- "include the missing field{} in the pattern",
+ "include the missing field{} in the pattern{}",
if len == 1 { "" } else { "s" },
+ if have_inaccessible_fields { " and ignore the inaccessible fields" } else { "" }
),
format!(
- "{}{}{}",
+ "{}{}{}{}",
prefix,
unmentioned_fields
.iter()
.map(|(_, name)| name.to_string())
.collect::<Vec<_>>()
.join(", "),
+ if have_inaccessible_fields { ", .." } else { "" },
postfix,
),
Applicability::MachineApplicable,
@@ -1769,7 +1808,7 @@
// The expected type must be an array or slice, but was neither, so error.
_ => {
if !expected.references_error() {
- self.error_expected_array_or_slice(span, expected);
+ self.error_expected_array_or_slice(span, expected, ti);
}
let err = self.tcx.ty_error();
(err, Some(err), err)
@@ -1882,7 +1921,7 @@
.emit();
}
- fn error_expected_array_or_slice(&self, span: Span, expected_ty: Ty<'tcx>) {
+ fn error_expected_array_or_slice(&self, span: Span, expected_ty: Ty<'tcx>, ti: TopInfo<'tcx>) {
let mut err = struct_span_err!(
self.tcx.sess,
span,
@@ -1894,6 +1933,19 @@
if let ty::Array(..) | ty::Slice(..) = ty.kind() {
err.help("the semantics of slice patterns changed recently; see issue #62254");
}
+ } else if Autoderef::new(&self.infcx, self.param_env, self.body_id, span, expected_ty, span)
+ .any(|(ty, _)| matches!(ty.kind(), ty::Slice(..)))
+ {
+ if let (Some(span), true) = (ti.span, ti.origin_expr) {
+ if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) {
+ err.span_suggestion(
+ span,
+ "consider slicing here",
+ format!("{}[..]", snippet),
+ Applicability::MachineApplicable,
+ );
+ }
+ }
}
err.span_label(span, format!("pattern cannot match with input type `{}`", expected_ty));
err.emit();
diff --git a/compiler/rustc_typeck/src/check/regionck.rs b/compiler/rustc_typeck/src/check/regionck.rs
index 8f8514c..290fa5f 100644
--- a/compiler/rustc_typeck/src/check/regionck.rs
+++ b/compiler/rustc_typeck/src/check/regionck.rs
@@ -144,11 +144,20 @@
/// rest of type check and because sometimes we need type
/// inference to have completed before we can determine which
/// constraints to add.
- pub fn regionck_fn(&self, fn_id: hir::HirId, body: &'tcx hir::Body<'tcx>) {
+ pub(crate) fn regionck_fn(
+ &self,
+ fn_id: hir::HirId,
+ body: &'tcx hir::Body<'tcx>,
+ span: Span,
+ wf_tys: &[Ty<'tcx>],
+ ) {
debug!("regionck_fn(id={})", fn_id);
let subject = self.tcx.hir().body_owner_def_id(body.id());
let hir_id = body.value.hir_id;
let mut rcx = RegionCtxt::new(self, hir_id, Subject(subject), self.param_env);
+ // We need to add the implied bounds from the function signature
+ rcx.outlives_environment.add_implied_bounds(self, wf_tys, fn_id, span);
+ rcx.outlives_environment.save_implied_bounds(fn_id);
if !self.errors_reported_since_creation() {
// regionck assumes typeck succeeded
@@ -291,10 +300,7 @@
self.visit_body(body);
self.visit_region_obligations(body_id.hir_id);
- self.constrain_opaque_types(
- &self.fcx.opaque_types.borrow(),
- self.outlives_environment.free_region_map(),
- );
+ self.constrain_opaque_types(self.outlives_environment.free_region_map());
}
fn visit_region_obligations(&mut self, hir_id: hir::HirId) {
diff --git a/compiler/rustc_typeck/src/check/upvar.rs b/compiler/rustc_typeck/src/check/upvar.rs
index 39874f4..524cda3 100644
--- a/compiler/rustc_typeck/src/check/upvar.rs
+++ b/compiler/rustc_typeck/src/check/upvar.rs
@@ -47,7 +47,7 @@
};
use rustc_session::lint;
use rustc_span::sym;
-use rustc_span::{MultiSpan, Span, Symbol};
+use rustc_span::{BytePos, MultiSpan, Pos, Span, Symbol};
use rustc_trait_selection::infer::InferCtxtExt;
use rustc_data_structures::stable_map::FxHashMap;
@@ -65,6 +65,7 @@
enum PlaceAncestryRelation {
Ancestor,
Descendant,
+ SamePlace,
Divergent,
}
@@ -350,9 +351,13 @@
for (place, mut capture_info) in capture_information {
// Apply rules for safety before inferring closure kind
- let place = restrict_capture_precision(place);
+ let (place, capture_kind) =
+ restrict_capture_precision(place, capture_info.capture_kind);
+ capture_info.capture_kind = capture_kind;
- let place = truncate_capture_for_optimization(&place);
+ let (place, capture_kind) =
+ truncate_capture_for_optimization(place, capture_info.capture_kind);
+ capture_info.capture_kind = capture_kind;
let usage_span = if let Some(usage_expr) = capture_info.path_expr_id {
self.tcx.hir().span(usage_expr)
@@ -395,7 +400,19 @@
}
};
+ // This restriction needs to be applied after we have handled adjustments for `move`
+ // closures. We want to make sure any adjustment that might make us move the place into
+ // the closure gets handled.
+ let (place, capture_kind) =
+ restrict_precision_for_drop_types(self, place, capture_kind, usage_span);
+
capture_info.capture_kind = capture_kind;
+
+ let capture_info = if let Some(existing) = processed.get(&place) {
+ determine_capture_info(*existing, capture_info)
+ } else {
+ capture_info
+ };
processed.insert(place, capture_info);
}
@@ -485,7 +502,7 @@
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() {
+ for (mut 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),
@@ -520,8 +537,18 @@
// current place is ancestor of possible_descendant
PlaceAncestryRelation::Ancestor => {
descendant_found = true;
+
+ let mut possible_descendant = possible_descendant.clone();
let backup_path_expr_id = updated_capture_info.path_expr_id;
+ // Truncate the descendant (already in min_captures) to be same as the ancestor to handle any
+ // possible change in capture mode.
+ truncate_place_to_len_and_update_capture_kind(
+ &mut possible_descendant.place,
+ &mut possible_descendant.info.capture_kind,
+ place.projections.len(),
+ );
+
updated_capture_info =
determine_capture_info(updated_capture_info, possible_descendant.info);
@@ -539,11 +566,22 @@
for possible_ancestor in min_cap_list.iter_mut() {
match determine_place_ancestry_relation(&place, &possible_ancestor.place) {
// current place is descendant of possible_ancestor
- PlaceAncestryRelation::Descendant => {
+ PlaceAncestryRelation::Descendant | PlaceAncestryRelation::SamePlace => {
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);
+
+ // Truncate the descendant (current place) to be same as the ancestor to handle any
+ // possible change in capture mode.
+ truncate_place_to_len_and_update_capture_kind(
+ &mut place,
+ &mut updated_capture_info.capture_kind,
+ possible_ancestor.place.projections.len(),
+ );
+
+ possible_ancestor.info = determine_capture_info(
+ possible_ancestor.info,
+ updated_capture_info,
+ );
// we need to keep the ancestor's `path_expr_id`
possible_ancestor.info.path_expr_id = backup_path_expr_id;
@@ -565,7 +603,78 @@
}
}
- debug!("For closure={:?}, min_captures={:#?}", closure_def_id, root_var_min_capture_list);
+ debug!(
+ "For closure={:?}, min_captures before sorting={:?}",
+ closure_def_id, root_var_min_capture_list
+ );
+
+ // Now that we have the minimized list of captures, sort the captures by field id.
+ // This causes the closure to capture the upvars in the same order as the fields are
+ // declared which is also the drop order. Thus, in situations where we capture all the
+ // fields of some type, the obserable drop order will remain the same as it previously
+ // was even though we're dropping each capture individually.
+ // See https://github.com/rust-lang/project-rfc-2229/issues/42 and
+ // `src/test/ui/closures/2229_closure_analysis/preserve_field_drop_order.rs`.
+ for (_, captures) in &mut root_var_min_capture_list {
+ captures.sort_by(|capture1, capture2| {
+ for (p1, p2) in capture1.place.projections.iter().zip(&capture2.place.projections) {
+ // We do not need to look at the `Projection.ty` fields here because at each
+ // step of the iteration, the projections will either be the same and therefore
+ // the types must be as well or the current projection will be different and
+ // we will return the result of comparing the field indexes.
+ match (p1.kind, p2.kind) {
+ // Paths are the same, continue to next loop.
+ (ProjectionKind::Deref, ProjectionKind::Deref) => {}
+ (ProjectionKind::Field(i1, _), ProjectionKind::Field(i2, _))
+ if i1 == i2 => {}
+
+ // Fields are different, compare them.
+ (ProjectionKind::Field(i1, _), ProjectionKind::Field(i2, _)) => {
+ return i1.cmp(&i2);
+ }
+
+ // We should have either a pair of `Deref`s or a pair of `Field`s.
+ // Anything else is a bug.
+ (
+ l @ (ProjectionKind::Deref | ProjectionKind::Field(..)),
+ r @ (ProjectionKind::Deref | ProjectionKind::Field(..)),
+ ) => bug!(
+ "ProjectionKinds Deref and Field were mismatched: ({:?}, {:?})",
+ l,
+ r
+ ),
+ (
+ l
+ @
+ (ProjectionKind::Index
+ | ProjectionKind::Subslice
+ | ProjectionKind::Deref
+ | ProjectionKind::Field(..)),
+ r
+ @
+ (ProjectionKind::Index
+ | ProjectionKind::Subslice
+ | ProjectionKind::Deref
+ | ProjectionKind::Field(..)),
+ ) => bug!(
+ "ProjectionKinds Index or Subslice were unexpected: ({:?}, {:?})",
+ l,
+ r
+ ),
+ }
+ }
+
+ unreachable!(
+ "we captured two identical projections: capture1 = {:?}, capture2 = {:?}",
+ capture1, capture2
+ );
+ });
+ }
+
+ debug!(
+ "For closure={:?}, min_captures after sorting={:#?}",
+ closure_def_id, root_var_min_capture_list
+ );
typeck_results.closure_min_captures.insert(closure_def_id, root_var_min_capture_list);
}
@@ -596,7 +705,7 @@
self.tcx.struct_span_lint_hir(
lint::builtin::RUST_2021_INCOMPATIBLE_CLOSURE_CAPTURES,
closure_hir_id,
- closure_head_span,
+ closure_head_span,
|lint| {
let mut diagnostics_builder = lint.build(
format!(
@@ -611,7 +720,7 @@
for (captured_hir_id, captured_name, reasons) in diagnostics_info.iter() {
if let Some(captured_hir_id) = captured_hir_id {
let cause_span = self.tcx.hir().span(*captured_hir_id);
- diagnostics_builder.span_label(cause_span, format!("in Rust 2018, closure captures all of `{}`, but in Rust 2021, it only captures `{}`",
+ diagnostics_builder.span_label(cause_span, format!("in Rust 2018, this closure captures all of `{}`, but in Rust 2021, it will only capture `{}`",
self.tcx.hir().name(*var_hir_id),
captured_name,
));
@@ -622,7 +731,7 @@
if reasons.contains("drop order") {
let drop_location_span = drop_location_span(self.tcx, &closure_hir_id);
- diagnostics_builder.span_label(drop_location_span, format!("in Rust 2018, `{}` would be dropped here, but in Rust 2021, only `{}` would be dropped here alongside the closure",
+ diagnostics_builder.span_label(drop_location_span, format!("in Rust 2018, `{}` is dropped here, but in Rust 2021, only `{}` will be dropped here as part of the closure",
self.tcx.hir().name(*var_hir_id),
captured_name,
));
@@ -632,7 +741,7 @@
if reasons.contains("trait implementation") {
let missing_trait = &reasons[..reasons.find("trait implementation").unwrap() - 1];
- diagnostics_builder.span_label(closure_head_span, format!("in Rust 2018, this closure would implement {} as `{}` implements {}, but in Rust 2021, this closure would no longer implement {} as `{}` does not implement {}",
+ diagnostics_builder.span_label(closure_head_span, format!("in Rust 2018, this closure implements {} as `{}` implements {}, but in Rust 2021, this closure will no longer implement {} as `{}` does not implement {}",
missing_trait,
self.tcx.hir().name(*var_hir_id),
missing_trait,
@@ -644,35 +753,85 @@
}
}
diagnostics_builder.note("for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/disjoint-capture-in-closures.html>");
- let closure_body_span = self.tcx.hir().span(body_id.hir_id);
- let (sugg, app) =
- match self.tcx.sess.source_map().span_to_snippet(closure_body_span) {
- Ok(s) => {
- let trimmed = s.trim_start();
-
- // If the closure contains a block then replace the opening brace
- // with "{ let _ = (..); "
- let sugg = if let Some('{') = trimmed.chars().next() {
- format!("{{ {}; {}", migration_string, &trimmed[1..])
- } else {
- format!("{{ {}; {} }}", migration_string, s)
- };
- (sugg, Applicability::MachineApplicable)
- }
- Err(_) => (migration_string.clone(), Applicability::HasPlaceholders),
- };
let diagnostic_msg = format!(
"add a dummy let to cause {} to be fully captured",
migrated_variables_concat
);
- diagnostics_builder.span_suggestion(
- closure_body_span,
- &diagnostic_msg,
- sugg,
- app,
- );
+ let mut closure_body_span = {
+ // If the body was entirely expanded from a macro
+ // invocation, i.e. the body is not contained inside the
+ // closure span, then we walk up the expansion until we
+ // find the span before the expansion.
+ let s = self.tcx.hir().span(body_id.hir_id);
+ s.find_ancestor_inside(closure_span).unwrap_or(s)
+ };
+
+ if let Ok(mut s) = self.tcx.sess.source_map().span_to_snippet(closure_body_span) {
+ if s.starts_with('$') {
+ // Looks like a macro fragment. Try to find the real block.
+ if let Some(hir::Node::Expr(&hir::Expr {
+ kind: hir::ExprKind::Block(block, ..), ..
+ })) = self.tcx.hir().find(body_id.hir_id) {
+ // If the body is a block (with `{..}`), we use the span of that block.
+ // E.g. with a `|| $body` expanded from a `m!({ .. })`, we use `{ .. }`, and not `$body`.
+ // Since we know it's a block, we know we can insert the `let _ = ..` without
+ // breaking the macro syntax.
+ if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(block.span) {
+ closure_body_span = block.span;
+ s = snippet;
+ }
+ }
+ }
+
+ let mut lines = s.lines();
+ let line1 = lines.next().unwrap_or_default();
+
+ if line1.trim_end() == "{" {
+ // This is a multi-line closure with just a `{` on the first line,
+ // so we put the `let` on its own line.
+ // We take the indentation from the next non-empty line.
+ let line2 = lines.filter(|line| !line.is_empty()).next().unwrap_or_default();
+ let indent = line2.split_once(|c: char| !c.is_whitespace()).unwrap_or_default().0;
+ diagnostics_builder.span_suggestion(
+ closure_body_span.with_lo(closure_body_span.lo() + BytePos::from_usize(line1.len())).shrink_to_lo(),
+ &diagnostic_msg,
+ format!("\n{}{};", indent, migration_string),
+ Applicability::MachineApplicable,
+ );
+ } else if line1.starts_with('{') {
+ // This is a closure with its body wrapped in
+ // braces, but with more than just the opening
+ // brace on the first line. We put the `let`
+ // directly after the `{`.
+ diagnostics_builder.span_suggestion(
+ closure_body_span.with_lo(closure_body_span.lo() + BytePos(1)).shrink_to_lo(),
+ &diagnostic_msg,
+ format!(" {};", migration_string),
+ Applicability::MachineApplicable,
+ );
+ } else {
+ // This is a closure without braces around the body.
+ // We add braces to add the `let` before the body.
+ diagnostics_builder.multipart_suggestion(
+ &diagnostic_msg,
+ vec![
+ (closure_body_span.shrink_to_lo(), format!("{{ {}; ", migration_string)),
+ (closure_body_span.shrink_to_hi(), " }".to_string()),
+ ],
+ Applicability::MachineApplicable
+ );
+ }
+ } else {
+ diagnostics_builder.span_suggestion(
+ closure_span,
+ &diagnostic_msg,
+ migration_string,
+ Applicability::HasPlaceholders
+ );
+ }
+
diagnostics_builder.emit();
},
);
@@ -1392,7 +1551,7 @@
// 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.
+ // The place isn't mutable once we dereference an immutable reference.
ty::Ref(.., hir::Mutability::Not) => return hir::Mutability::Not,
// Dereferencing a box doesn't change mutability
@@ -1412,7 +1571,8 @@
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
place: &Place<'tcx>,
-) -> Place<'tcx> {
+ mut curr_borrow_kind: ty::UpvarCapture<'tcx>,
+) -> (Place<'tcx>, ty::UpvarCapture<'tcx>) {
let pos = place.projections.iter().enumerate().position(|(i, p)| {
let ty = place.ty_before_projection(i);
@@ -1420,7 +1580,7 @@
match p.kind {
ProjectionKind::Field(..) => match ty.kind() {
ty::Adt(def, _) if def.repr.packed() => {
- match tcx.layout_raw(param_env.and(p.ty)) {
+ match tcx.layout_of(param_env.and(p.ty)) {
Ok(layout) if layout.align.abi.bytes() == 1 => {
// if the alignment is 1, the type can't be further
// disaligned.
@@ -1446,10 +1606,10 @@
let mut place = place.clone();
if let Some(pos) = pos {
- place.projections.truncate(pos);
+ truncate_place_to_len_and_update_capture_kind(&mut place, &mut curr_borrow_kind, pos);
}
- place
+ (place, curr_borrow_kind)
}
/// Returns a Ty that applies the specified capture kind on the provided capture Ty
@@ -1570,20 +1730,11 @@
);
if let PlaceBase::Upvar(_) = place_with_id.place.base {
- let mut borrow_kind = ty::MutBorrow;
- for pointer_ty in place_with_id.place.deref_tys() {
- match pointer_ty.kind() {
- // Raw pointers don't inherit mutability.
- ty::RawPtr(_) => return,
- // assignment to deref of an `&mut`
- // borrowed pointer implies that the
- // pointer itself must be unique, but not
- // necessarily *mutable*
- ty::Ref(.., hir::Mutability::Mut) => borrow_kind = ty::UniqueImmBorrow,
- _ => (),
- }
+ // Raw pointers don't inherit mutability
+ if place_with_id.place.deref_tys().any(ty::TyS::is_unsafe_ptr) {
+ return;
}
- self.adjust_upvar_deref(place_with_id, diag_expr_id, borrow_kind);
+ self.adjust_upvar_deref(place_with_id, diag_expr_id, ty::MutBorrow);
}
}
@@ -1700,9 +1851,19 @@
if let PlaceBase::Upvar(_) = place.base {
// We need to restrict Fake Read precision to avoid fake reading unsafe code,
// such as deref of a raw pointer.
- let place = restrict_capture_precision(place);
- let place =
- restrict_repr_packed_field_ref_capture(self.fcx.tcx, self.fcx.param_env, &place);
+ let dummy_capture_kind = ty::UpvarCapture::ByRef(ty::UpvarBorrow {
+ kind: ty::BorrowKind::ImmBorrow,
+ region: &ty::ReErased,
+ });
+
+ let (place, _) = restrict_capture_precision(place, dummy_capture_kind);
+
+ let (place, _) = restrict_repr_packed_field_ref_capture(
+ self.fcx.tcx,
+ self.fcx.param_env,
+ &place,
+ dummy_capture_kind,
+ );
self.fake_reads.push((place, cause, diag_expr_id));
}
}
@@ -1728,13 +1889,18 @@
place_with_id, diag_expr_id, bk
);
+ // The region here will get discarded/ignored
+ let dummy_capture_kind =
+ ty::UpvarCapture::ByRef(ty::UpvarBorrow { kind: bk, region: &ty::ReErased });
+
// We only want repr packed restriction to be applied to reading references into a packed
// struct, and not when the data is being moved. Therefore we call this method here instead
// of in `restrict_capture_precision`.
- let place = restrict_repr_packed_field_ref_capture(
+ let (place, updated_kind) = restrict_repr_packed_field_ref_capture(
self.fcx.tcx,
self.fcx.param_env,
&place_with_id.place,
+ dummy_capture_kind,
);
let place_with_id = PlaceWithHirId { place, ..*place_with_id };
@@ -1743,14 +1909,19 @@
self.init_capture_info_for_place(&place_with_id, diag_expr_id);
}
- match bk {
- ty::ImmBorrow => {}
- ty::UniqueImmBorrow => {
- self.adjust_upvar_borrow_kind_for_unique(&place_with_id, diag_expr_id);
- }
- ty::MutBorrow => {
- self.adjust_upvar_borrow_kind_for_mut(&place_with_id, diag_expr_id);
- }
+ match updated_kind {
+ ty::UpvarCapture::ByRef(ty::UpvarBorrow { kind, .. }) => match kind {
+ ty::ImmBorrow => {}
+ ty::UniqueImmBorrow => {
+ self.adjust_upvar_borrow_kind_for_unique(&place_with_id, diag_expr_id);
+ }
+ ty::MutBorrow => {
+ self.adjust_upvar_borrow_kind_for_mut(&place_with_id, diag_expr_id);
+ }
+ },
+
+ // Just truncating the place will never cause capture kind to be updated to ByValue
+ ty::UpvarCapture::ByValue(..) => unreachable!(),
}
}
@@ -1761,34 +1932,84 @@
}
}
-/// Truncate projections so that following rules are obeyed by the captured `place`:
+/// Rust doesn't permit moving fields out of a type that implements drop
+fn restrict_precision_for_drop_types<'a, 'tcx>(
+ fcx: &'a FnCtxt<'a, 'tcx>,
+ mut place: Place<'tcx>,
+ mut curr_mode: ty::UpvarCapture<'tcx>,
+ span: Span,
+) -> (Place<'tcx>, ty::UpvarCapture<'tcx>) {
+ let is_copy_type = fcx.infcx.type_is_copy_modulo_regions(fcx.param_env, place.ty(), span);
+
+ if let (false, UpvarCapture::ByValue(..)) = (is_copy_type, curr_mode) {
+ for i in 0..place.projections.len() {
+ match place.ty_before_projection(i).kind() {
+ ty::Adt(def, _) if def.destructor(fcx.tcx).is_some() => {
+ truncate_place_to_len_and_update_capture_kind(&mut place, &mut curr_mode, i);
+ break;
+ }
+ _ => {}
+ }
+ }
+ }
+
+ (place, curr_mode)
+}
+
+/// Truncate `place` so that an `unsafe` block isn't required to capture it.
/// - 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>) -> Place<'tcx> {
- if place.projections.is_empty() {
- // Nothing to do here
- return place;
- }
-
+/// - No projections are applied on top of Union ADTs, since these require unsafe blocks.
+fn restrict_precision_for_unsafe(
+ mut place: Place<'tcx>,
+ mut curr_mode: ty::UpvarCapture<'tcx>,
+) -> (Place<'tcx>, ty::UpvarCapture<'tcx>) {
if place.base_ty.is_unsafe_ptr() {
- place.projections.truncate(0);
- return place;
+ truncate_place_to_len_and_update_capture_kind(&mut place, &mut curr_mode, 0);
}
- let mut truncated_length = usize::MAX;
+ if place.base_ty.is_union() {
+ truncate_place_to_len_and_update_capture_kind(&mut place, &mut curr_mode, 0);
+ }
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);
+ // Don't apply any projections on top of an unsafe ptr.
+ truncate_place_to_len_and_update_capture_kind(&mut place, &mut curr_mode, i + 1);
break;
}
+
+ if proj.ty.is_union() {
+ // Don't capture preicse fields of a union.
+ truncate_place_to_len_and_update_capture_kind(&mut place, &mut curr_mode, i + 1);
+ break;
+ }
+ }
+
+ (place, curr_mode)
+}
+
+/// Truncate projections so that following rules are obeyed by the captured `place`:
+/// - No Index projections are captured, since arrays are captured completely.
+/// - No unsafe block is required to capture `place`
+/// Returns the truncated place and updated cature mode.
+fn restrict_capture_precision<'tcx>(
+ place: Place<'tcx>,
+ curr_mode: ty::UpvarCapture<'tcx>,
+) -> (Place<'tcx>, ty::UpvarCapture<'tcx>) {
+ let (mut place, mut curr_mode) = restrict_precision_for_unsafe(place, curr_mode);
+
+ if place.projections.is_empty() {
+ // Nothing to do here
+ return (place, curr_mode);
+ }
+
+ for (i, proj) in place.projections.iter().enumerate() {
match proj.kind {
ProjectionKind::Index => {
// Arrays are completely captured, so we drop Index projections
- truncated_length = truncated_length.min(i);
- break;
+ truncate_place_to_len_and_update_capture_kind(&mut place, &mut curr_mode, i);
+ return (place, curr_mode);
}
ProjectionKind::Deref => {}
ProjectionKind::Field(..) => {} // ignore
@@ -1796,72 +2017,45 @@
}
}
- let length = place.projections.len().min(truncated_length);
-
- place.projections.truncate(length);
-
- place
+ return (place, curr_mode);
}
-/// Take ownership if data being accessed is owned by the variable used to access it
-/// (or if closure attempts to move data that it doesn’t own).
-/// Note: When taking ownership, only capture data found on the stack.
+/// Truncate deref of any reference.
fn adjust_for_move_closure<'tcx>(
mut place: Place<'tcx>,
- kind: ty::UpvarCapture<'tcx>,
+ mut kind: ty::UpvarCapture<'tcx>,
) -> (Place<'tcx>, ty::UpvarCapture<'tcx>) {
- let contains_deref_of_ref = place.deref_tys().any(|ty| ty.is_ref());
let first_deref = place.projections.iter().position(|proj| proj.kind == ProjectionKind::Deref);
- match kind {
- ty::UpvarCapture::ByRef(..) if contains_deref_of_ref => (place, kind),
-
- // If there's any Deref and the data needs to be moved into the closure body,
- // or it's a Deref of a Box, truncate the path to the first deref
- _ if first_deref.is_some() => {
- let place = match first_deref {
- Some(idx) => {
- place.projections.truncate(idx);
- place
- }
- None => place,
- };
-
- // AMAN: I think we don't need the span inside the ByValue anymore
- // we have more detailed span in CaptureInfo
- (place, ty::UpvarCapture::ByValue(None))
- }
-
- _ => (place, ty::UpvarCapture::ByValue(None)),
+ if let Some(idx) = first_deref {
+ truncate_place_to_len_and_update_capture_kind(&mut place, &mut kind, idx);
}
+
+ // AMAN: I think we don't need the span inside the ByValue anymore
+ // we have more detailed span in CaptureInfo
+ (place, ty::UpvarCapture::ByValue(None))
}
/// Adjust closure capture just that if taking ownership of data, only move data
/// from enclosing stack frame.
fn adjust_for_non_move_closure<'tcx>(
mut place: Place<'tcx>,
- kind: ty::UpvarCapture<'tcx>,
+ mut kind: ty::UpvarCapture<'tcx>,
) -> (Place<'tcx>, ty::UpvarCapture<'tcx>) {
let contains_deref =
place.projections.iter().position(|proj| proj.kind == ProjectionKind::Deref);
match kind {
- ty::UpvarCapture::ByValue(..) if contains_deref.is_some() => {
- let place = match contains_deref {
- Some(idx) => {
- place.projections.truncate(idx);
- place
- }
- // Because of the if guard on the match on `kind`, we should never get here.
- None => unreachable!(),
- };
-
- (place, kind)
+ ty::UpvarCapture::ByValue(..) => {
+ if let Some(idx) = contains_deref {
+ truncate_place_to_len_and_update_capture_kind(&mut place, &mut kind, idx);
+ }
}
- ty::UpvarCapture::ByValue(..) => (place, kind),
- ty::UpvarCapture::ByRef(..) => (place, kind),
+ ty::UpvarCapture::ByRef(..) => {}
}
+
+ (place, kind)
}
fn construct_place_string(tcx: TyCtxt<'_>, place: &Place<'tcx>) -> String {
@@ -2050,6 +2244,45 @@
}
}
+/// Truncates `place` to have up to `len` projections.
+/// `curr_mode` is the current required capture kind for the place.
+/// Returns the truncated `place` and the updated required capture kind.
+///
+/// Note: Capture kind changes from `MutBorrow` to `UniqueImmBorrow` if the truncated part of the `place`
+/// contained `Deref` of `&mut`.
+fn truncate_place_to_len_and_update_capture_kind(
+ place: &mut Place<'tcx>,
+ curr_mode: &mut ty::UpvarCapture<'tcx>,
+ len: usize,
+) {
+ let is_mut_ref = |ty: Ty<'_>| matches!(ty.kind(), ty::Ref(.., hir::Mutability::Mut));
+
+ // If the truncated part of the place contains `Deref` of a `&mut` then convert MutBorrow ->
+ // UniqueImmBorrow
+ // Note that if the place contained Deref of a raw pointer it would've not been MutBorrow, so
+ // we don't need to worry about that case here.
+ match curr_mode {
+ ty::UpvarCapture::ByRef(ty::UpvarBorrow { kind: ty::BorrowKind::MutBorrow, region }) => {
+ for i in len..place.projections.len() {
+ if place.projections[i].kind == ProjectionKind::Deref
+ && is_mut_ref(place.ty_before_projection(i))
+ {
+ *curr_mode = ty::UpvarCapture::ByRef(ty::UpvarBorrow {
+ kind: ty::BorrowKind::UniqueImmBorrow,
+ region,
+ });
+ break;
+ }
+ }
+ }
+
+ ty::UpvarCapture::ByRef(..) => {}
+ ty::UpvarCapture::ByValue(..) => {}
+ }
+
+ place.projections.truncate(len);
+}
+
/// Determines the Ancestry relationship of Place A relative to Place B
///
/// `PlaceAncestryRelation::Ancestor` implies Place A is ancestor of Place B
@@ -2071,15 +2304,17 @@
let projections_b = &place_b.projections;
let same_initial_projections =
- iter::zip(projections_a, projections_b).all(|(proj_a, proj_b)| proj_a == proj_b);
+ iter::zip(projections_a, projections_b).all(|(proj_a, proj_b)| proj_a.kind == proj_b.kind);
if same_initial_projections {
+ use std::cmp::Ordering;
+
// First min(n, m) projections are the same
// Select Ancestor/Descendant
- if projections_b.len() >= projections_a.len() {
- PlaceAncestryRelation::Ancestor
- } else {
- PlaceAncestryRelation::Descendant
+ match projections_b.len().cmp(&projections_a.len()) {
+ Ordering::Greater => PlaceAncestryRelation::Ancestor,
+ Ordering::Equal => PlaceAncestryRelation::SamePlace,
+ Ordering::Less => PlaceAncestryRelation::Descendant,
}
} else {
PlaceAncestryRelation::Divergent
@@ -2111,7 +2346,10 @@
/// // it is constrained to `'a`
/// }
/// ```
-fn truncate_capture_for_optimization<'tcx>(place: &Place<'tcx>) -> Place<'tcx> {
+fn truncate_capture_for_optimization<'tcx>(
+ mut place: Place<'tcx>,
+ mut curr_mode: ty::UpvarCapture<'tcx>,
+) -> (Place<'tcx>, ty::UpvarCapture<'tcx>) {
let is_shared_ref = |ty: Ty<'_>| matches!(ty.kind(), ty::Ref(.., hir::Mutability::Not));
// Find the right-most deref (if any). All the projections that come after this
@@ -2122,10 +2360,12 @@
match idx {
// If that pointer is a shared reference, then we don't need those fields.
Some(idx) if is_shared_ref(place.ty_before_projection(idx)) => {
- Place { projections: place.projections[0..=idx].to_vec(), ..place.clone() }
+ truncate_place_to_len_and_update_capture_kind(&mut place, &mut curr_mode, idx + 1)
}
- None | Some(_) => place.clone(),
+ None | Some(_) => {}
}
+
+ (place, curr_mode)
}
/// Precise capture is enabled if the feature gate `capture_disjoint_fields` is enabled or if
diff --git a/compiler/rustc_typeck/src/check/wfcheck.rs b/compiler/rustc_typeck/src/check/wfcheck.rs
index e33cc60..17716af 100644
--- a/compiler/rustc_typeck/src/check/wfcheck.rs
+++ b/compiler/rustc_typeck/src/check/wfcheck.rs
@@ -194,12 +194,13 @@
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
let trait_item = tcx.hir().expect_trait_item(hir_id);
- let method_sig = match trait_item.kind {
- hir::TraitItemKind::Fn(ref sig, _) => Some(sig),
- _ => None,
+ let (method_sig, span) = match trait_item.kind {
+ hir::TraitItemKind::Fn(ref sig, _) => (Some(sig), trait_item.span),
+ hir::TraitItemKind::Type(_bounds, Some(ty)) => (None, ty.span),
+ _ => (None, trait_item.span),
};
check_object_unsafe_self_trait_by_name(tcx, &trait_item);
- check_associated_item(tcx, trait_item.hir_id(), trait_item.span, method_sig);
+ check_associated_item(tcx, trait_item.hir_id(), span, method_sig);
}
fn could_be_self(trait_def_id: LocalDefId, ty: &hir::Ty<'_>) -> bool {
@@ -268,12 +269,13 @@
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
let impl_item = tcx.hir().expect_impl_item(hir_id);
- let method_sig = match impl_item.kind {
- hir::ImplItemKind::Fn(ref sig, _) => Some(sig),
- _ => None,
+ let (method_sig, span) = match impl_item.kind {
+ hir::ImplItemKind::Fn(ref sig, _) => (Some(sig), impl_item.span),
+ hir::ImplItemKind::TyAlias(ty) => (None, ty.span),
+ _ => (None, impl_item.span),
};
- check_associated_item(tcx, impl_item.hir_id(), impl_item.span, method_sig);
+ check_associated_item(tcx, impl_item.hir_id(), span, method_sig);
}
fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) {
@@ -288,7 +290,7 @@
let err_ty_str;
let mut is_ptr = true;
- let err = if tcx.features().const_generics {
+ let err = if tcx.features().adt_const_params {
match ty.peel_refs().kind() {
ty::FnPtr(_) => Some("function pointers"),
ty::RawPtr(_) => Some("raw pointers"),
@@ -326,7 +328,7 @@
err.note("the only supported types are integers, `bool` and `char`");
if tcx.sess.is_nightly_build() {
err.help(
- "more complex types are supported with `#![feature(const_generics)]`",
+ "more complex types are supported with `#![feature(adt_const_params)]`",
);
}
err.emit()
@@ -539,10 +541,10 @@
fcx.register_predicate(traits::Obligation::new(
cause,
fcx.param_env,
- ty::PredicateKind::ConstEvaluatable(
+ ty::PredicateKind::ConstEvaluatable(ty::Unevaluated::new(
ty::WithOptConstParam::unknown(discr_def_id.to_def_id()),
discr_substs,
- )
+ ))
.to_predicate(tcx),
));
}
@@ -744,7 +746,7 @@
// Ignore dependent defaults -- that is, where the default of one type
// parameter includes another (e.g., `<T, U = T>`). In those cases, we can't
// be sure if it will error or not as user might always specify the other.
- if !ty.needs_subst() {
+ if !ty.definitely_needs_subst(tcx) {
fcx.register_wf_obligation(
ty.into(),
tcx.def_span(param.def_id),
@@ -760,7 +762,7 @@
// for `struct Foo<const N: usize, const M: usize = { 1 - 2 }>`
// we should eagerly error.
let default_ct = tcx.const_param_default(param.def_id);
- if !default_ct.needs_subst() {
+ if !default_ct.definitely_needs_subst(tcx) {
fcx.register_wf_obligation(
default_ct.into(),
tcx.def_span(param.def_id),
@@ -794,7 +796,7 @@
if is_our_default(param) {
let default_ty = tcx.type_of(param.def_id);
// ... and it's not a dependent default, ...
- if !default_ty.needs_subst() {
+ if !default_ty.definitely_needs_subst(tcx) {
// ... then substitute it with the default.
return default_ty.into();
}
@@ -807,7 +809,7 @@
if is_our_default(param) {
let default_ct = tcx.const_param_default(param.def_id);
// ... and it's not a dependent default, ...
- if !default_ct.needs_subst() {
+ if !default_ct.definitely_needs_subst(tcx) {
// ... then substitute it with the default.
return default_ct.into();
}
@@ -823,12 +825,15 @@
.predicates
.iter()
.flat_map(|&(pred, sp)| {
- #[derive(Default)]
- struct CountParams {
+ struct CountParams<'tcx> {
+ tcx: TyCtxt<'tcx>,
params: FxHashSet<u32>,
}
- impl<'tcx> ty::fold::TypeVisitor<'tcx> for CountParams {
+ impl<'tcx> ty::fold::TypeVisitor<'tcx> for CountParams<'tcx> {
type BreakTy = ();
+ fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
+ Some(self.tcx)
+ }
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
if let ty::Param(param) = t.kind() {
@@ -848,12 +853,12 @@
c.super_visit_with(self)
}
}
- let mut param_count = CountParams::default();
+ let mut param_count = CountParams { tcx: fcx.tcx, params: FxHashSet::default() };
let has_region = pred.visit_with(&mut param_count).is_break();
let substituted_pred = pred.subst(tcx, substs);
// Don't check non-defaulted params, dependent defaults (including lifetimes)
// or preds with multiple params.
- if substituted_pred.has_param_types_or_consts()
+ if substituted_pred.definitely_has_param_types_or_consts(tcx)
|| param_count.params.len() > 1
|| has_region
{
@@ -906,6 +911,7 @@
}
}
+#[tracing::instrument(level = "debug", skip(fcx, span, hir_decl))]
fn check_fn_or_method<'fcx, 'tcx>(
fcx: &FnCtxt<'fcx, 'tcx>,
span: Span,
@@ -916,6 +922,11 @@
) {
let sig = fcx.tcx.liberate_late_bound_regions(def_id, sig);
+ // Unnormalized types in signature are WF too
+ implied_bounds.extend(sig.inputs());
+ // FIXME(#27579) return types should not be implied bounds
+ implied_bounds.push(sig.output());
+
// Normalize the input and output types one at a time, using a different
// `WellFormedLoc` for each. We cannot call `normalize_associated_types`
// on the entire `FnSig`, since this would use the same `WellFormedLoc`
@@ -965,9 +976,11 @@
ObligationCauseCode::ReturnType,
);
- // FIXME(#25759) return types should not be implied bounds
+ // FIXME(#27579) return types should not be implied bounds
implied_bounds.push(sig.output());
+ debug!(?implied_bounds);
+
check_where_clauses(fcx, span, def_id, Some((sig.output(), hir_decl.output.span())));
}
@@ -1047,26 +1060,24 @@
let arg_is_param = match arg.unpack() {
GenericArgKind::Type(ty) => matches!(ty.kind(), ty::Param(_)),
- GenericArgKind::Lifetime(region) => {
- if let ty::ReStatic = region {
- tcx.sess
- .struct_span_err(
- span,
- "non-defining opaque type use in defining scope",
- )
- .span_label(
- tcx.def_span(generics.param_at(i, tcx).def_id),
- "cannot use static lifetime; use a bound lifetime \
- instead or remove the lifetime parameter from the \
- opaque type",
- )
- .emit();
- continue;
- }
-
- true
+ GenericArgKind::Lifetime(region) if let ty::ReStatic = region => {
+ tcx.sess
+ .struct_span_err(
+ span,
+ "non-defining opaque type use in defining scope",
+ )
+ .span_label(
+ tcx.def_span(generics.param_at(i, tcx).def_id),
+ "cannot use static lifetime; use a bound lifetime \
+ instead or remove the lifetime parameter from the \
+ opaque type",
+ )
+ .emit();
+ continue;
}
+ GenericArgKind::Lifetime(_) => true,
+
GenericArgKind::Const(ct) => matches!(ct.val, ty::ConstKind::Param(_)),
};
@@ -1114,6 +1125,7 @@
`self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one \
of the previous types except `Self`)";
+#[tracing::instrument(level = "debug", skip(fcx))]
fn check_method_receiver<'fcx, 'tcx>(
fcx: &FnCtxt<'fcx, 'tcx>,
fn_sig: &hir::FnSig<'_>,
@@ -1377,7 +1389,7 @@
for obligation in implied_obligations {
let pred = obligation.predicate;
// Match the existing behavior.
- if pred.is_global() && !pred.has_late_bound_regions() {
+ if pred.is_global(fcx.tcx) && !pred.has_late_bound_regions() {
let pred = fcx.normalize_associated_types_in(span, pred);
let obligation = traits::Obligation::new(
traits::ObligationCause::new(span, id, traits::TrivialBound),
diff --git a/compiler/rustc_typeck/src/check/writeback.rs b/compiler/rustc_typeck/src/check/writeback.rs
index 935bcc9..c57ec9e 100644
--- a/compiler/rustc_typeck/src/check/writeback.rs
+++ b/compiler/rustc_typeck/src/check/writeback.rs
@@ -130,7 +130,7 @@
fn write_ty_to_typeck_results(&mut self, hir_id: hir::HirId, ty: Ty<'tcx>) {
debug!("write_ty_to_typeck_results({:?}, {:?})", hir_id, ty);
- assert!(!ty.needs_infer() && !ty.has_placeholders() && !ty.has_free_regions());
+ assert!(!ty.needs_infer() && !ty.has_placeholders() && !ty.has_free_regions(self.tcx()));
self.typeck_results.node_types_mut().insert(hir_id, ty);
}
@@ -175,10 +175,10 @@
}
}
}
- hir::ExprKind::AssignOp(..) => {
- if let Some(a) = typeck_results.adjustments_mut().get_mut(lhs.hir_id) {
- a.pop();
- }
+ hir::ExprKind::AssignOp(..)
+ if let Some(a) = typeck_results.adjustments_mut().get_mut(lhs.hir_id) =>
+ {
+ a.pop();
}
_ => {}
}
@@ -331,6 +331,15 @@
let ty = self.resolve(ty, &hir_ty.span);
self.write_ty_to_typeck_results(hir_ty.hir_id, ty);
}
+
+ fn visit_infer(&mut self, inf: &'tcx hir::InferArg) {
+ intravisit::walk_inf(self, inf);
+ // Ignore cases where the inference is a const.
+ if let Some(ty) = self.fcx.node_ty_opt(inf.hir_id) {
+ let ty = self.resolve(ty, &inf.span);
+ self.write_ty_to_typeck_results(inf.hir_id, ty);
+ }
+ }
}
impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
@@ -489,7 +498,8 @@
}
fn visit_opaque_types(&mut self, span: Span) {
- for &(opaque_type_key, opaque_defn) in self.fcx.opaque_types.borrow().iter() {
+ let opaque_types = self.fcx.infcx.inner.borrow().opaque_types.clone();
+ for (opaque_type_key, opaque_defn) in opaque_types {
let hir_id =
self.tcx().hir().local_def_id_to_hir_id(opaque_type_key.def_id.expect_local());
let instantiated_ty = self.resolve(opaque_defn.concrete_ty, &hir_id);
@@ -542,23 +552,7 @@
// in some other location, or we'll end up emitting an error due
// to the lack of defining usage
if !skip_add {
- let old_concrete_ty = self
- .typeck_results
- .concrete_opaque_types
- .insert(opaque_type_key, definition_ty);
- if let Some(old_concrete_ty) = old_concrete_ty {
- if old_concrete_ty != definition_ty {
- span_bug!(
- span,
- "`visit_opaque_types` tried to write different types for the same \
- opaque type: {:?}, {:?}, {:?}, {:?}",
- opaque_type_key.def_id,
- definition_ty,
- opaque_defn,
- old_concrete_ty,
- );
- }
- }
+ self.typeck_results.concrete_opaque_types.insert(opaque_type_key.def_id);
}
}
}
diff --git a/compiler/rustc_typeck/src/check_unused.rs b/compiler/rustc_typeck/src/check_unused.rs
index 7e5cc77..cb12788 100644
--- a/compiler/rustc_typeck/src/check_unused.rs
+++ b/compiler/rustc_typeck/src/check_unused.rs
@@ -9,8 +9,7 @@
pub fn check_crate(tcx: TyCtxt<'_>) {
let mut used_trait_imports = FxHashSet::default();
- for &body_id in tcx.hir().krate().bodies.keys() {
- let item_def_id = tcx.hir().body_owner_def_id(body_id);
+ for item_def_id in tcx.body_owners() {
let imports = tcx.used_trait_imports(item_def_id);
debug!("GatherVisitor: item_def_id={:?} with imports {:#?}", item_def_id, imports);
used_trait_imports.extend(imports.iter());
@@ -155,7 +154,7 @@
}
// If the extern crate isn't in the extern prelude,
- // there is no way it can be written as an `use`.
+ // there is no way it can be written as a `use`.
let orig_name = extern_crate.orig_name.unwrap_or(item.ident.name);
if !extern_prelude.get(&orig_name).map_or(false, |from_item| !from_item) {
continue;
diff --git a/compiler/rustc_typeck/src/coherence/inherent_impls.rs b/compiler/rustc_typeck/src/coherence/inherent_impls.rs
index 5169843..c7be9e2 100644
--- a/compiler/rustc_typeck/src/coherence/inherent_impls.rs
+++ b/compiler/rustc_typeck/src/coherence/inherent_impls.rs
@@ -60,6 +60,17 @@
ty::Dynamic(ref data, ..) if data.principal_def_id().is_some() => {
self.check_def_id(item, data.principal_def_id().unwrap());
}
+ ty::Dynamic(..) => {
+ struct_span_err!(
+ self.tcx.sess,
+ ty.span,
+ E0785,
+ "cannot define inherent `impl` for a dyn auto trait"
+ )
+ .span_label(ty.span, "impl requires at least one non-auto trait")
+ .note("define and implement a new trait or type instead")
+ .emit();
+ }
ty::Bool => {
self.check_primitive_impl(
item.def_id,
diff --git a/compiler/rustc_typeck/src/coherence/inherent_impls_overlap.rs b/compiler/rustc_typeck/src/coherence/inherent_impls_overlap.rs
index f039790..1c36335 100644
--- a/compiler/rustc_typeck/src/coherence/inherent_impls_overlap.rs
+++ b/compiler/rustc_typeck/src/coherence/inherent_impls_overlap.rs
@@ -222,8 +222,8 @@
let id_to_set = *ids.iter().min().unwrap();
// Sort the id list so that the algorithm is deterministic
- let mut ids = ids.into_iter().collect::<SmallVec<[_; 8]>>();
- ids.sort();
+ let mut ids = ids.into_iter().collect::<SmallVec<[usize; 8]>>();
+ ids.sort_unstable();
let mut region = connected_regions.remove(&id_to_set).unwrap();
region.idents.extend_from_slice(&idents_to_add);
@@ -266,8 +266,8 @@
// for each pair of impl blocks in the same connected region.
for (_id, region) in connected_regions.into_iter() {
let mut impl_blocks =
- region.impl_blocks.into_iter().collect::<SmallVec<[_; 8]>>();
- impl_blocks.sort();
+ region.impl_blocks.into_iter().collect::<SmallVec<[usize; 8]>>();
+ impl_blocks.sort_unstable();
for (i, &impl1_items_idx) in impl_blocks.iter().enumerate() {
let &(&impl1_def_id, impl_items1) = &impls_items[impl1_items_idx];
for &impl2_items_idx in impl_blocks[(i + 1)..].iter() {
diff --git a/compiler/rustc_typeck/src/coherence/mod.rs b/compiler/rustc_typeck/src/coherence/mod.rs
index 03a9fe0..7ac26a3 100644
--- a/compiler/rustc_typeck/src/coherence/mod.rs
+++ b/compiler/rustc_typeck/src/coherence/mod.rs
@@ -195,7 +195,7 @@
}
pub fn check_coherence(tcx: TyCtxt<'_>) {
- for &trait_def_id in tcx.hir().krate().trait_impls.keys() {
+ for &trait_def_id in tcx.all_local_trait_impls(()).keys() {
tcx.ensure().coherent_trait(trait_def_id);
}
diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs
index 1a4c2eb..6412051 100644
--- a/compiler/rustc_typeck/src/collect.rs
+++ b/compiler/rustc_typeck/src/collect.rs
@@ -1,4 +1,3 @@
-// ignore-tidy-filelength
//! "Collection" is the process of determining the type and other external
//! details of each item in Rust. Collection is specifically concerned
//! with *inter-procedural* things -- for example, for a function
@@ -15,8 +14,6 @@
//! At present, however, we do run collection across all items in the
//! crate as a kind of pass. This should eventually be factored away.
-// ignore-tidy-filelength
-
use crate::astconv::{AstConv, SizedByDefault};
use crate::bounds::Bounds;
use crate::check::intrinsic::intrinsic_operation_unsafety;
@@ -24,6 +21,7 @@
use crate::errors;
use crate::middle::resolve_lifetime as rl;
use rustc_ast as ast;
+use rustc_ast::Attribute;
use rustc_ast::{MetaItemKind, NestedMetaItem};
use rustc_attr::{list_contains_name, InlineAttr, InstructionSetAttr, OptimizeAttr};
use rustc_data_structures::captures::Captures;
@@ -70,6 +68,7 @@
pub fn provide(providers: &mut Providers) {
*providers = Providers {
opt_const_param_of: type_of::opt_const_param_of,
+ default_anon_const_substs: type_of::default_anon_const_substs,
type_of: type_of::type_of,
item_bounds: item_bounds::item_bounds,
explicit_item_bounds: item_bounds::explicit_item_bounds,
@@ -129,6 +128,16 @@
}
intravisit::walk_ty(self, t)
}
+ fn visit_generic_arg(&mut self, generic_arg: &'v hir::GenericArg<'v>) {
+ match generic_arg {
+ hir::GenericArg::Infer(inf) => {
+ self.0.push(inf.span);
+ intravisit::walk_inf(self, inf);
+ }
+ hir::GenericArg::Type(t) => self.visit_ty(t),
+ _ => {}
+ }
+ }
}
struct CollectItemTypesVisitor<'tcx> {
@@ -356,10 +365,6 @@
Some(self.item_def_id)
}
- fn default_constness_for_trait_bounds(&self) -> hir::Constness {
- self.node().constness()
- }
-
fn get_type_parameter_bounds(
&self,
span: Span,
@@ -633,7 +638,7 @@
)
.into_iter()
.filter(|(predicate, _)| match predicate.kind().skip_binder() {
- ty::PredicateKind::Trait(data, _) => data.self_ty().is_param(index),
+ ty::PredicateKind::Trait(data) => data.self_ty().is_param(index),
_ => false,
}),
);
@@ -655,7 +660,6 @@
only_self_bounds: OnlySelfBounds,
assoc_name: Option<Ident>,
) -> Vec<(ty::Predicate<'tcx>, Span)> {
- let constness = self.default_constness_for_trait_bounds();
let from_ty_params = ast_generics
.params
.iter()
@@ -668,7 +672,7 @@
Some(assoc_name) => self.bound_defines_assoc_item(b, assoc_name),
None => true,
})
- .flat_map(|b| predicates_from_bound(self, ty, b, constness));
+ .flat_map(|b| predicates_from_bound(self, ty, b));
let from_where_clauses = ast_generics
.where_clause
@@ -694,7 +698,7 @@
})
.filter_map(move |b| bt.map(|bt| (bt, b)))
})
- .flat_map(|(bt, b)| predicates_from_bound(self, bt, b, constness));
+ .flat_map(|(bt, b)| predicates_from_bound(self, bt, b));
from_ty_params.chain(from_where_clauses).collect()
}
@@ -742,6 +746,7 @@
// These don't define types.
hir::ItemKind::ExternCrate(_)
| hir::ItemKind::Use(..)
+ | hir::ItemKind::Macro(_)
| hir::ItemKind::Mod(_)
| hir::ItemKind::GlobalAsm(_) => {}
hir::ItemKind::ForeignMod { items, .. } => {
@@ -1191,7 +1196,7 @@
// which will, in turn, reach indirect supertraits.
for &(pred, span) in superbounds {
debug!("superbound: {:?}", pred);
- if let ty::PredicateKind::Trait(bound, _) = pred.kind().skip_binder() {
+ if let ty::PredicateKind::Trait(bound) = pred.kind().skip_binder() {
tcx.at(span).super_predicates_of(bound.def_id());
}
}
@@ -1437,8 +1442,54 @@
// of a const parameter type, e.g. `struct Foo<const N: usize, const M: [u8; N]>` is not allowed.
None
} else if tcx.lazy_normalization() {
+ if let Some(param_id) = tcx.hir().opt_const_param_default_param_hir_id(hir_id) {
+ // If the def_id we are calling generics_of on is an anon ct default i.e:
+ //
+ // struct Foo<const N: usize = { .. }>;
+ // ^^^ ^ ^^^^^^ def id of this anon const
+ // ^ ^ param_id
+ // ^ parent_def_id
+ //
+ // then we only want to return generics for params to the left of `N`. If we don't do that we
+ // end up with that const looking like: `ty::ConstKind::Unevaluated(def_id, substs: [N#0])`.
+ //
+ // This causes ICEs (#86580) when building the substs for Foo in `fn foo() -> Foo { .. }` as
+ // we substitute the defaults with the partially built substs when we build the substs. Subst'ing
+ // the `N#0` on the unevaluated const indexes into the empty substs we're in the process of building.
+ //
+ // We fix this by having this function return the parent's generics ourselves and truncating the
+ // generics to only include non-forward declared params (with the exception of the `Self` ty)
+ //
+ // For the above code example that means we want `substs: []`
+ // For the following struct def we want `substs: [N#0]` when generics_of is called on
+ // the def id of the `{ N + 1 }` anon const
+ // struct Foo<const N: usize, const M: usize = { N + 1 }>;
+ //
+ // This has some implications for how we get the predicates available to the anon const
+ // see `explicit_predicates_of` for more information on this
+ let generics = tcx.generics_of(parent_def_id.to_def_id());
+ let param_def = tcx.hir().local_def_id(param_id).to_def_id();
+ let param_def_idx = generics.param_def_id_to_index[¶m_def];
+ // In the above example this would be .params[..N#0]
+ let params = generics.params[..param_def_idx as usize].to_owned();
+ let param_def_id_to_index =
+ params.iter().map(|param| (param.def_id, param.index)).collect();
+
+ return ty::Generics {
+ // we set the parent of these generics to be our parent's parent so that we
+ // dont end up with substs: [N, M, N] for the const default on a struct like this:
+ // struct Foo<const N: usize, const M: usize = { ... }>;
+ parent: generics.parent,
+ parent_count: generics.parent_count,
+ params,
+ param_def_id_to_index,
+ has_self: generics.has_self,
+ has_late_bound_regions: generics.has_late_bound_regions,
+ };
+ }
+
// HACK(eddyb) this provides the correct generics when
- // `feature(const_generics)` is enabled, so that const expressions
+ // `feature(generic_const_expressions)` is enabled, so that const expressions
// used with const generics, e.g. `Foo<{N+1}>`, can work at all.
//
// Note that we do not supply the parent generics when using
@@ -1668,13 +1719,11 @@
}
fn are_suggestable_generic_args(generic_args: &[hir::GenericArg<'_>]) -> bool {
- generic_args
- .iter()
- .filter_map(|arg| match arg {
- hir::GenericArg::Type(ty) => Some(ty),
- _ => None,
- })
- .any(is_suggestable_infer_ty)
+ generic_args.iter().any(|arg| match arg {
+ hir::GenericArg::Type(ty) => is_suggestable_infer_ty(ty),
+ hir::GenericArg::Infer(_) => true,
+ _ => false,
+ })
}
/// Whether `ty` is a type with `_` placeholders that can be inferred. Used in diagnostics only to
@@ -1953,7 +2002,16 @@
// prove that the trait applies to the types that were
// used, and adding the predicate into this list ensures
// that this is done.
- let span = tcx.sess.source_map().guess_head_span(tcx.def_span(def_id));
+ let mut span = tcx.def_span(def_id);
+ if tcx.sess.source_map().is_local_span(span) {
+ // `guess_head_span` reads the actual source file from
+ // disk to try to determine the 'head' snippet of the span.
+ // Don't do this for a span that comes from a file outside
+ // of our crate, since this would make our query output
+ // (and overall crate metadata) dependent on the
+ // *current* state of an external file.
+ span = tcx.sess.source_map().guess_head_span(span);
+ }
result.predicates =
tcx.arena.alloc_from_iter(result.predicates.iter().copied().chain(std::iter::once((
ty::TraitRef::identity(tcx, def_id).without_const().to_predicate(tcx),
@@ -1978,7 +2036,6 @@
let mut is_default_impl_trait = None;
let icx = ItemCtxt::new(tcx, def_id);
- let constness = icx.default_constness_for_trait_bounds();
const NO_GENERICS: &hir::Generics<'_> = &hir::Generics::empty();
@@ -2174,9 +2231,13 @@
match bound {
hir::GenericBound::Trait(poly_trait_ref, modifier) => {
let constness = match modifier {
- hir::TraitBoundModifier::MaybeConst => hir::Constness::NotConst,
- hir::TraitBoundModifier::None => constness,
- hir::TraitBoundModifier::Maybe => bug!("this wasn't handled"),
+ hir::TraitBoundModifier::None => ty::BoundConstness::NotConst,
+ hir::TraitBoundModifier::MaybeConst => {
+ ty::BoundConstness::ConstIfConst
+ }
+ // We ignore `where T: ?Sized`, it is already part of
+ // type parameter `T`.
+ hir::TraitBoundModifier::Maybe => continue,
};
let mut bounds = Bounds::default();
@@ -2206,6 +2267,8 @@
predicates.extend(bounds.predicates(tcx, ty));
}
+ hir::GenericBound::Unsized(_) => {}
+
hir::GenericBound::Outlives(lifetime) => {
let region =
<dyn AstConv<'_>>::ast_region_to_region(&icx, lifetime, None);
@@ -2246,7 +2309,7 @@
}
}
- if tcx.features().const_evaluatable_checked {
+ if tcx.features().generic_const_exprs {
predicates.extend(const_evaluatable_predicates_of(tcx, def_id.expect_local()));
}
@@ -2264,7 +2327,7 @@
tcx,
&mut predicates,
trait_ref,
- &mut cgp::parameters_for_impl(self_ty, trait_ref),
+ &mut cgp::parameters_for_impl(tcx, self_ty, trait_ref),
);
}
@@ -2299,7 +2362,7 @@
assert_eq!(uv.promoted, None);
let span = self.tcx.hir().span(c.hir_id);
self.preds.insert((
- ty::PredicateKind::ConstEvaluatable(uv.def, uv.substs).to_predicate(self.tcx),
+ ty::PredicateKind::ConstEvaluatable(uv.shrink()).to_predicate(self.tcx),
span,
));
}
@@ -2355,7 +2418,8 @@
}
fn explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicates<'_> {
- if let DefKind::Trait = tcx.def_kind(def_id) {
+ let def_kind = tcx.def_kind(def_id);
+ if let DefKind::Trait = def_kind {
// Remove bounds on associated types from the predicates, they will be
// returned by `explicit_item_bounds`.
let predicates_and_bounds = tcx.trait_explicit_predicates_and_bounds(def_id.expect_local());
@@ -2383,7 +2447,7 @@
.iter()
.copied()
.filter(|(pred, _)| match pred.kind().skip_binder() {
- ty::PredicateKind::Trait(tr, _) => !is_assoc_item_ty(tr.self_ty()),
+ ty::PredicateKind::Trait(tr) => !is_assoc_item_ty(tr.self_ty()),
ty::PredicateKind::Projection(proj) => {
!is_assoc_item_ty(proj.projection_ty.self_ty())
}
@@ -2400,6 +2464,26 @@
}
}
} else {
+ if matches!(def_kind, DefKind::AnonConst) && tcx.lazy_normalization() {
+ let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
+ if let Some(_) = tcx.hir().opt_const_param_default_param_hir_id(hir_id) {
+ // In `generics_of` we set the generics' parent to be our parent's parent which means that
+ // we lose out on the predicates of our actual parent if we dont return those predicates here.
+ // (See comment in `generics_of` for more information on why the parent shenanigans is necessary)
+ //
+ // struct Foo<T, const N: usize = { <T as Trait>::ASSOC }>(T) where T: Trait;
+ // ^^^ ^^^^^^^^^^^^^^^^^^^^^^^ the def id we are calling
+ // ^^^ explicit_predicates_of on
+ // parent item we dont have set as the
+ // parent of generics returned by `generics_of`
+ //
+ // In the above code we want the anon const to have predicates in its param env for `T: Trait`
+ let item_id = tcx.hir().get_parent_item(hir_id);
+ let item_def_id = tcx.hir().local_def_id(item_id).to_def_id();
+ // In the above code example we would be calling `explicit_predicates_of(Foo)` here
+ return tcx.explicit_predicates_of(item_def_id);
+ }
+ }
gather_explicit_predicates_of(tcx, def_id)
}
}
@@ -2413,14 +2497,13 @@
astconv: &dyn AstConv<'tcx>,
param_ty: Ty<'tcx>,
bound: &'tcx hir::GenericBound<'tcx>,
- constness: hir::Constness,
) -> Vec<(ty::Predicate<'tcx>, Span)> {
match *bound {
hir::GenericBound::Trait(ref tr, modifier) => {
let constness = match modifier {
hir::TraitBoundModifier::Maybe => return vec![],
- hir::TraitBoundModifier::MaybeConst => hir::Constness::NotConst,
- hir::TraitBoundModifier::None => constness,
+ hir::TraitBoundModifier::MaybeConst => ty::BoundConstness::ConstIfConst,
+ hir::TraitBoundModifier::None => ty::BoundConstness::NotConst,
};
let mut bounds = Bounds::default();
@@ -2446,6 +2529,7 @@
);
bounds.predicates(astconv.tcx(), param_ty)
}
+ hir::GenericBound::Unsized(_) => vec![],
hir::GenericBound::Outlives(ref lifetime) => {
let region = astconv.ast_region_to_region(lifetime, None);
let pred = ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(param_ty, region))
@@ -2692,13 +2776,11 @@
let mut link_ordinal_span = None;
let mut no_sanitize_span = None;
for attr in attrs.iter() {
- if tcx.sess.check_name(attr, sym::cold) {
+ if attr.has_name(sym::cold) {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::COLD;
- } else if tcx.sess.check_name(attr, sym::rustc_allocator) {
+ } else if attr.has_name(sym::rustc_allocator) {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::ALLOCATOR;
- } else if tcx.sess.check_name(attr, sym::unwind) {
- codegen_fn_attrs.flags |= CodegenFnAttrFlags::UNWIND;
- } else if tcx.sess.check_name(attr, sym::ffi_returns_twice) {
+ } else if attr.has_name(sym::ffi_returns_twice) {
if tcx.is_foreign_item(id) {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::FFI_RETURNS_TWICE;
} else {
@@ -2711,9 +2793,9 @@
)
.emit();
}
- } else if tcx.sess.check_name(attr, sym::ffi_pure) {
+ } else if attr.has_name(sym::ffi_pure) {
if tcx.is_foreign_item(id) {
- if attrs.iter().any(|a| tcx.sess.check_name(a, sym::ffi_const)) {
+ if attrs.iter().any(|a| a.has_name(sym::ffi_const)) {
// `#[ffi_const]` functions cannot be `#[ffi_pure]`
struct_span_err!(
tcx.sess,
@@ -2735,7 +2817,7 @@
)
.emit();
}
- } else if tcx.sess.check_name(attr, sym::ffi_const) {
+ } else if attr.has_name(sym::ffi_const) {
if tcx.is_foreign_item(id) {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::FFI_CONST;
} else {
@@ -2748,19 +2830,19 @@
)
.emit();
}
- } else if tcx.sess.check_name(attr, sym::rustc_allocator_nounwind) {
- codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_ALLOCATOR_NOUNWIND;
- } else if tcx.sess.check_name(attr, sym::naked) {
+ } else if attr.has_name(sym::rustc_allocator_nounwind) {
+ codegen_fn_attrs.flags |= CodegenFnAttrFlags::NEVER_UNWIND;
+ } else if attr.has_name(sym::naked) {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::NAKED;
- } else if tcx.sess.check_name(attr, sym::no_mangle) {
+ } else if attr.has_name(sym::no_mangle) {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_MANGLE;
- } else if tcx.sess.check_name(attr, sym::no_coverage) {
+ } else if attr.has_name(sym::no_coverage) {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_COVERAGE;
- } else if tcx.sess.check_name(attr, sym::rustc_std_internal_symbol) {
+ } else if attr.has_name(sym::rustc_std_internal_symbol) {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL;
- } else if tcx.sess.check_name(attr, sym::used) {
+ } else if attr.has_name(sym::used) {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED;
- } else if tcx.sess.check_name(attr, sym::cmse_nonsecure_entry) {
+ } else if attr.has_name(sym::cmse_nonsecure_entry) {
if !matches!(tcx.fn_sig(id).abi(), abi::Abi::C { .. }) {
struct_span_err!(
tcx.sess,
@@ -2775,15 +2857,15 @@
.emit();
}
codegen_fn_attrs.flags |= CodegenFnAttrFlags::CMSE_NONSECURE_ENTRY;
- } else if tcx.sess.check_name(attr, sym::thread_local) {
+ } else if attr.has_name(sym::thread_local) {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::THREAD_LOCAL;
- } else if tcx.sess.check_name(attr, sym::track_caller) {
+ } else if attr.has_name(sym::track_caller) {
if tcx.is_closure(id) || tcx.fn_sig(id).abi() != abi::Abi::Rust {
struct_span_err!(tcx.sess, attr.span, E0737, "`#[track_caller]` requires Rust ABI")
.emit();
}
codegen_fn_attrs.flags |= CodegenFnAttrFlags::TRACK_CALLER;
- } else if tcx.sess.check_name(attr, sym::export_name) {
+ } else if attr.has_name(sym::export_name) {
if let Some(s) = attr.value_str() {
if s.as_str().contains('\0') {
// `#[export_name = ...]` will be converted to a null-terminated string,
@@ -2798,7 +2880,7 @@
}
codegen_fn_attrs.export_name = Some(s);
}
- } else if tcx.sess.check_name(attr, sym::target_feature) {
+ } else if attr.has_name(sym::target_feature) {
if !tcx.is_closure(id) && tcx.fn_sig(id).unsafety() == hir::Unsafety::Normal {
if tcx.sess.target.is_like_wasm || tcx.sess.opts.actually_rustdoc {
// The `#[target_feature]` attribute is allowed on
@@ -2838,11 +2920,11 @@
&supported_target_features,
&mut codegen_fn_attrs.target_features,
);
- } else if tcx.sess.check_name(attr, sym::linkage) {
+ } else if attr.has_name(sym::linkage) {
if let Some(val) = attr.value_str() {
codegen_fn_attrs.linkage = Some(linkage_by_name(tcx, id, &val.as_str()));
}
- } else if tcx.sess.check_name(attr, sym::link_section) {
+ } else if attr.has_name(sym::link_section) {
if let Some(val) = attr.value_str() {
if val.as_str().bytes().any(|b| b == 0) {
let msg = format!(
@@ -2855,14 +2937,14 @@
codegen_fn_attrs.link_section = Some(val);
}
}
- } else if tcx.sess.check_name(attr, sym::link_name) {
+ } else if attr.has_name(sym::link_name) {
codegen_fn_attrs.link_name = attr.value_str();
- } else if tcx.sess.check_name(attr, sym::link_ordinal) {
+ } else if attr.has_name(sym::link_ordinal) {
link_ordinal_span = Some(attr.span);
if let ordinal @ Some(_) = check_link_ordinal(tcx, attr) {
codegen_fn_attrs.link_ordinal = ordinal;
}
- } else if tcx.sess.check_name(attr, sym::no_sanitize) {
+ } else if attr.has_name(sym::no_sanitize) {
no_sanitize_span = Some(attr.span);
if let Some(list) = attr.meta_item_list() {
for item in list.iter() {
@@ -2882,7 +2964,7 @@
}
}
}
- } else if tcx.sess.check_name(attr, sym::instruction_set) {
+ } else if attr.has_name(sym::instruction_set) {
codegen_fn_attrs.instruction_set = match attr.meta().map(|i| i.kind) {
Some(MetaItemKind::List(ref items)) => match items.as_slice() {
[NestedMetaItem::MetaItem(set)] => {
@@ -2951,7 +3033,7 @@
None
}
};
- } else if tcx.sess.check_name(attr, sym::repr) {
+ } else if attr.has_name(sym::repr) {
codegen_fn_attrs.alignment = match attr.meta_item_list() {
Some(items) => match items.as_slice() {
[item] => match item.name_value_literal() {
@@ -2989,12 +3071,8 @@
return ia;
}
match attr.meta().map(|i| i.kind) {
- Some(MetaItemKind::Word) => {
- tcx.sess.mark_attr_used(attr);
- InlineAttr::Hint
- }
+ Some(MetaItemKind::Word) => InlineAttr::Hint,
Some(MetaItemKind::List(ref items)) => {
- tcx.sess.mark_attr_used(attr);
inline_span = Some(attr.span);
if items.len() != 1 {
struct_span_err!(
@@ -3037,7 +3115,6 @@
ia
}
Some(MetaItemKind::List(ref items)) => {
- tcx.sess.mark_attr_used(attr);
inline_span = Some(attr.span);
if items.len() != 1 {
err(attr.span, "expected one argument");
@@ -3106,7 +3183,7 @@
if tcx.is_weak_lang_item(id) {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL;
}
- let check_name = |attr, sym| tcx.sess.check_name(attr, sym);
+ let check_name = |attr: &Attribute, sym| attr.has_name(sym);
if let Some(name) = weak_lang_items::link_name(check_name, &attrs) {
codegen_fn_attrs.export_name = Some(name);
codegen_fn_attrs.link_name = Some(name);
@@ -3120,6 +3197,15 @@
codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_MANGLE;
}
+ // Any linkage to LLVM intrinsics for now forcibly marks them all as never
+ // unwinds since LLVM sometimes can't handle codegen which `invoke`s
+ // intrinsic functions.
+ if let Some(name) = &codegen_fn_attrs.link_name {
+ if name.as_str().starts_with("llvm.") {
+ codegen_fn_attrs.flags |= CodegenFnAttrFlags::NEVER_UNWIND;
+ }
+ }
+
codegen_fn_attrs
}
diff --git a/compiler/rustc_typeck/src/collect/item_bounds.rs b/compiler/rustc_typeck/src/collect/item_bounds.rs
index a5b3644..1d08c44 100644
--- a/compiler/rustc_typeck/src/collect/item_bounds.rs
+++ b/compiler/rustc_typeck/src/collect/item_bounds.rs
@@ -38,7 +38,7 @@
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::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,
diff --git a/compiler/rustc_typeck/src/collect/type_of.rs b/compiler/rustc_typeck/src/collect/type_of.rs
index 50e4ba4..26a9ce6 100644
--- a/compiler/rustc_typeck/src/collect/type_of.rs
+++ b/compiler/rustc_typeck/src/collect/type_of.rs
@@ -7,7 +7,7 @@
use rustc_hir::intravisit::Visitor;
use rustc_hir::{HirId, Node};
use rustc_middle::hir::map::Map;
-use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts};
+use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts, SubstsRef};
use rustc_middle::ty::util::IntTypeExt;
use rustc_middle::ty::{self, DefIdTree, Ty, TyCtxt, TypeFoldable, TypeFolder};
use rustc_span::symbol::Ident;
@@ -20,6 +20,9 @@
///
/// 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> {
+ // FIXME(generic_arg_infer): allow for returning DefIds of inference of
+ // GenericArg::Infer below. This may require a change where GenericArg::Infer has some flag
+ // for const or type.
use hir::*;
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
@@ -187,8 +190,12 @@
// Try to use the segment resolution if it is valid, otherwise we
// default to the path resolution.
let res = segment.res.filter(|&r| r != Res::Err).unwrap_or(path.res);
+ use def::CtorOf;
let generics = match res {
- Res::Def(DefKind::Ctor(..), def_id) => {
+ Res::Def(DefKind::Ctor(CtorOf::Variant, _), def_id) => tcx.generics_of(
+ tcx.parent(def_id).and_then(|def_id| tcx.parent(def_id)).unwrap(),
+ ),
+ Res::Def(DefKind::Variant | DefKind::Ctor(CtorOf::Struct, _), def_id) => {
tcx.generics_of(tcx.parent(def_id).unwrap())
}
// Other `DefKind`s don't have generics and would ICE when calling
@@ -197,7 +204,6 @@
DefKind::Struct
| DefKind::Union
| DefKind::Enum
- | DefKind::Variant
| DefKind::Trait
| DefKind::OpaqueTy
| DefKind::TyAlias
@@ -268,6 +274,31 @@
arg_path
}
+pub(super) fn default_anon_const_substs(tcx: TyCtxt<'_>, def_id: DefId) -> SubstsRef<'_> {
+ let generics = tcx.generics_of(def_id);
+ if let Some(parent) = generics.parent {
+ // This is the reason we bother with having optional anon const substs.
+ //
+ // In the future the substs of an anon const will depend on its parents predicates
+ // at which point eagerly looking at them will cause a query cycle.
+ //
+ // So for now this is only an assurance that this approach won't cause cycle errors in
+ // the future.
+ let _cycle_check = tcx.predicates_of(parent);
+ }
+
+ let substs = InternalSubsts::identity_for_item(tcx, def_id);
+ // We only expect substs with the following type flags as default substs.
+ //
+ // Getting this wrong can lead to ICE and unsoundness, so we assert it here.
+ for arg in substs.iter() {
+ let allowed_flags = ty::TypeFlags::MAY_NEED_DEFAULT_CONST_SUBSTS
+ | ty::TypeFlags::STILL_FURTHER_SPECIALIZABLE;
+ assert!(!arg.has_type_flags(!allowed_flags));
+ }
+ substs
+}
+
pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
let def_id = def_id.expect_local();
use rustc_hir::*;
@@ -396,6 +427,7 @@
}
ItemKind::Trait(..)
| ItemKind::TraitAlias(..)
+ | ItemKind::Macro(..)
| ItemKind::Mod(..)
| ItemKind::ForeignMod { .. }
| ItemKind::GlobalAsm(..)
@@ -440,13 +472,13 @@
}
}
- Node::AnonConst(_) => {
- if let Some(param) = tcx.opt_const_param_of(def_id) {
- // We defer to `type_of` of the corresponding parameter
- // for generic arguments.
- return tcx.type_of(param);
- }
+ Node::AnonConst(_) if let Some(param) = tcx.opt_const_param_of(def_id) => {
+ // We defer to `type_of` of the corresponding parameter
+ // for generic arguments.
+ tcx.type_of(param)
+ }
+ Node::AnonConst(_) => {
let parent_node = tcx.hir().get(tcx.hir().get_parent_node(hir_id));
match parent_node {
Node::Ty(&Ty { kind: TyKind::Array(_, ref constant), .. })
@@ -534,13 +566,7 @@
}
// Calling `mir_borrowck` can lead to cycle errors through
// const-checking, avoid calling it if we don't have to.
- if self
- .tcx
- .typeck(def_id)
- .concrete_opaque_types
- .any_value_matching(|(key, _)| key.def_id == self.def_id)
- .is_none()
- {
+ if !self.tcx.typeck(def_id).concrete_opaque_types.contains(&self.def_id) {
debug!("no constraints in typeck results");
return;
}
@@ -750,29 +776,31 @@
// us to improve in typeck so we do that now.
match tcx.sess.diagnostic().steal_diagnostic(span, StashKey::ItemNoType) {
Some(mut err) => {
- // The parser provided a sub-optimal `HasPlaceholders` suggestion for the type.
- // We are typeck and have the real type, so remove that and suggest the actual type.
- err.suggestions.clear();
+ if !ty.references_error() {
+ // The parser provided a sub-optimal `HasPlaceholders` suggestion for the type.
+ // We are typeck and have the real type, so remove that and suggest the actual type.
+ err.suggestions.clear();
- // Suggesting unnameable types won't help.
- let mut mk_nameable = MakeNameable::new(tcx);
- let ty = mk_nameable.fold_ty(ty);
- let sugg_ty = if mk_nameable.success { Some(ty) } else { None };
- if let Some(sugg_ty) = sugg_ty {
- err.span_suggestion(
- span,
- &format!("provide a type for the {item}", item = kind),
- format!("{}: {}", item_ident, sugg_ty),
- Applicability::MachineApplicable,
- );
- } else {
- err.span_note(
- tcx.hir().body(body_id).value.span,
- &format!("however, the inferred type `{}` cannot be named", ty.to_string()),
- );
+ // Suggesting unnameable types won't help.
+ let mut mk_nameable = MakeNameable::new(tcx);
+ let ty = mk_nameable.fold_ty(ty);
+ let sugg_ty = if mk_nameable.success { Some(ty) } else { None };
+ if let Some(sugg_ty) = sugg_ty {
+ err.span_suggestion(
+ span,
+ &format!("provide a type for the {item}", item = kind),
+ format!("{}: {}", item_ident, sugg_ty),
+ Applicability::MachineApplicable,
+ );
+ } else {
+ err.span_note(
+ tcx.hir().body(body_id).value.span,
+ &format!("however, the inferred type `{}` cannot be named", ty.to_string()),
+ );
+ }
}
- err.emit_unless(ty.references_error());
+ err.emit();
}
None => {
let mut diag = bad_placeholder_type(tcx, vec![span], kind);
diff --git a/compiler/rustc_typeck/src/constrained_generic_params.rs b/compiler/rustc_typeck/src/constrained_generic_params.rs
index 529de1a..9b6f0be 100644
--- a/compiler/rustc_typeck/src/constrained_generic_params.rs
+++ b/compiler/rustc_typeck/src/constrained_generic_params.rs
@@ -27,12 +27,13 @@
/// Returns the set of parameters constrained by the impl header.
pub fn parameters_for_impl<'tcx>(
+ tcx: TyCtxt<'tcx>,
impl_self_ty: Ty<'tcx>,
impl_trait_ref: Option<ty::TraitRef<'tcx>>,
) -> FxHashSet<Parameter> {
let vec = match impl_trait_ref {
- Some(tr) => parameters_for(&tr, false),
- None => parameters_for(&impl_self_ty, false),
+ Some(tr) => parameters_for(tcx, &tr, false),
+ None => parameters_for(tcx, &impl_self_ty, false),
};
vec.into_iter().collect()
}
@@ -43,20 +44,26 @@
/// of parameters whose values are needed in order to constrain `ty` - these
/// differ, with the latter being a superset, in the presence of projections.
pub fn parameters_for<'tcx>(
+ tcx: TyCtxt<'tcx>,
t: &impl TypeFoldable<'tcx>,
include_nonconstraining: bool,
) -> Vec<Parameter> {
- let mut collector = ParameterCollector { parameters: vec![], include_nonconstraining };
+ let mut collector = ParameterCollector { tcx, parameters: vec![], include_nonconstraining };
t.visit_with(&mut collector);
collector.parameters
}
-struct ParameterCollector {
+struct ParameterCollector<'tcx> {
+ tcx: TyCtxt<'tcx>,
parameters: Vec<Parameter>,
include_nonconstraining: bool,
}
-impl<'tcx> TypeVisitor<'tcx> for ParameterCollector {
+impl<'tcx> TypeVisitor<'tcx> for ParameterCollector<'tcx> {
+ fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
+ Some(self.tcx)
+ }
+
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
match *t.kind() {
ty::Projection(..) | ty::Opaque(..) if !self.include_nonconstraining => {
@@ -198,12 +205,12 @@
// `<<T as Bar>::Baz as Iterator>::Output = <U as Iterator>::Output`
// Then the projection only applies if `T` is known, but it still
// does not determine `U`.
- let inputs = parameters_for(&projection.projection_ty, true);
+ let inputs = parameters_for(tcx, &projection.projection_ty, true);
let relies_only_on_inputs = inputs.iter().all(|p| input_parameters.contains(&p));
if !relies_only_on_inputs {
continue;
}
- input_parameters.extend(parameters_for(&projection.ty, false));
+ input_parameters.extend(parameters_for(tcx, &projection.ty, false));
} else {
continue;
}
diff --git a/compiler/rustc_typeck/src/expr_use_visitor.rs b/compiler/rustc_typeck/src/expr_use_visitor.rs
index 806f1a2..b5c4d6a 100644
--- a/compiler/rustc_typeck/src/expr_use_visitor.rs
+++ b/compiler/rustc_typeck/src/expr_use_visitor.rs
@@ -2,6 +2,7 @@
//! normal visitor, which just walks the entire body in one shot, the
//! `ExprUseVisitor` determines how expressions are being used.
+use hir::def::DefKind;
// Export these here so that Clippy can use them.
pub use rustc_middle::hir::place::{Place, PlaceBase, PlaceWithHirId, Projection};
@@ -14,35 +15,32 @@
use rustc_infer::infer::InferCtxt;
use rustc_middle::hir::place::ProjectionKind;
use rustc_middle::mir::FakeReadCause;
-use rustc_middle::ty::{self, adjustment, TyCtxt};
+use rustc_middle::ty::{self, adjustment, AdtKind, Ty, TyCtxt};
use rustc_target::abi::VariantIdx;
use std::iter;
use crate::mem_categorization as mc;
-///////////////////////////////////////////////////////////////////////////
-// The Delegate trait
-
/// This trait defines the callbacks you can expect to receive when
/// employing the ExprUseVisitor.
pub trait Delegate<'tcx> {
- // The value found at `place` is moved, depending
- // on `mode`. Where `diag_expr_id` is the id used for diagnostics for `place`.
- //
- // Use of a `Copy` type in a ByValue context is considered a use
- // by `ImmBorrow` and `borrow` is called instead. This is because
- // a shared borrow is the "minimum access" that would be needed
- // to perform a copy.
- //
- //
- // The parameter `diag_expr_id` indicates the HIR id that ought to be used for
- // diagnostics. Around pattern matching such as `let pat = expr`, the diagnostic
- // id will be the id of the expression `expr` but the place itself will have
- // the id of the binding in the pattern `pat`.
+ /// The value found at `place` is moved, depending
+ /// on `mode`. Where `diag_expr_id` is the id used for diagnostics for `place`.
+ ///
+ /// Use of a `Copy` type in a ByValue context is considered a use
+ /// by `ImmBorrow` and `borrow` is called instead. This is because
+ /// a shared borrow is the "minimum access" that would be needed
+ /// to perform a copy.
+ ///
+ ///
+ /// The parameter `diag_expr_id` indicates the HIR id that ought to be used for
+ /// diagnostics. Around pattern matching such as `let pat = expr`, the diagnostic
+ /// id will be the id of the expression `expr` but the place itself will have
+ /// the id of the binding in the pattern `pat`.
fn consume(&mut self, place_with_id: &PlaceWithHirId<'tcx>, diag_expr_id: hir::HirId);
- // The value found at `place` is being borrowed with kind `bk`.
- // `diag_expr_id` is the id used for diagnostics (see `consume` for more details).
+ /// The value found at `place` is being borrowed with kind `bk`.
+ /// `diag_expr_id` is the id used for diagnostics (see `consume` for more details).
fn borrow(
&mut self,
place_with_id: &PlaceWithHirId<'tcx>,
@@ -50,44 +48,47 @@
bk: ty::BorrowKind,
);
- // The path at `assignee_place` is being assigned to.
- // `diag_expr_id` is the id used for diagnostics (see `consume` for more details).
+ /// The path at `assignee_place` is being assigned to.
+ /// `diag_expr_id` is the id used for diagnostics (see `consume` for more details).
fn mutate(&mut self, assignee_place: &PlaceWithHirId<'tcx>, diag_expr_id: hir::HirId);
- // The `place` should be a fake read because of specified `cause`.
+ /// The `place` should be a fake read because of specified `cause`.
fn fake_read(&mut self, place: Place<'tcx>, cause: FakeReadCause, diag_expr_id: hir::HirId);
}
#[derive(Copy, Clone, PartialEq, Debug)]
enum ConsumeMode {
- Copy, // reference to x where x has a type that copies
- Move, // reference to x where x has a type that moves
+ /// reference to x where x has a type that copies
+ Copy,
+ /// reference to x where x has a type that moves
+ Move,
}
#[derive(Copy, Clone, PartialEq, Debug)]
pub enum MutateMode {
Init,
- JustWrite, // x = y
- WriteAndRead, // x += y
+ /// Example: `x = y`
+ JustWrite,
+ /// Example: `x += y`
+ WriteAndRead,
}
-///////////////////////////////////////////////////////////////////////////
-// The ExprUseVisitor type
-//
-// This is the code that actually walks the tree.
+/// The ExprUseVisitor type
+///
+/// This is the code that actually walks the tree.
pub struct ExprUseVisitor<'a, 'tcx> {
mc: mc::MemCategorizationContext<'a, 'tcx>,
body_owner: LocalDefId,
delegate: &'a mut dyn Delegate<'tcx>,
}
-// If the MC results in an error, it's because the type check
-// failed (or will fail, when the error is uncovered and reported
-// during writeback). In this case, we just ignore this part of the
-// code.
-//
-// Note that this macro appears similar to try!(), but, unlike try!(),
-// it does not propagate the error.
+/// If the MC results in an error, it's because the type check
+/// failed (or will fail, when the error is uncovered and reported
+/// during writeback). In this case, we just ignore this part of the
+/// code.
+///
+/// Note that this macro appears similar to try!(), but, unlike try!(),
+/// it does not propagate the error.
macro_rules! return_if_err {
($inp: expr) => {
match $inp {
@@ -120,9 +121,8 @@
}
}
+ #[instrument(skip(self), level = "debug")]
pub fn consume_body(&mut self, body: &hir::Body<'_>) {
- debug!("consume_body(body={:?})", body);
-
for param in body.params {
let param_ty = return_if_err!(self.mc.pat_ty_adjusted(¶m.pat));
debug!("consume_body: param_ty = {:?}", param_ty);
@@ -229,6 +229,10 @@
}
}
+ hir::ExprKind::Let(ref pat, ref expr, _) => {
+ self.walk_local(expr, pat, |t| t.borrow_expr(&expr, ty::ImmBorrow));
+ }
+
hir::ExprKind::Match(ref discr, arms, _) => {
let discr_place = return_if_err!(self.mc.cat_expr(&discr));
@@ -248,31 +252,52 @@
needs_to_be_read = true;
}
}
- PatKind::TupleStruct(..)
- | PatKind::Path(..)
- | PatKind::Struct(..)
- | PatKind::Tuple(..) => {
- // If the PatKind is a TupleStruct, Path, Struct or Tuple then we want to check
- // whether the Variant is a MultiVariant or a SingleVariant. We only want
- // to borrow discr if it is a MultiVariant.
- // If it is a SingleVariant and creates a binding we will handle that when
- // this callback gets called again.
+ PatKind::Path(qpath) => {
+ // A `Path` pattern is just a name like `Foo`. This is either a
+ // named constant or else it refers to an ADT variant
- // Get the type of the Place after all projections have been applied
- let place_ty = place.place.ty();
-
- if let ty::Adt(def, _) = place_ty.kind() {
- if def.variants.len() > 1 {
+ let res = self.mc.typeck_results.qpath_res(qpath, pat.hir_id);
+ match res {
+ Res::Def(DefKind::Const, _)
+ | Res::Def(DefKind::AssocConst, _) => {
+ // Named constants have to be equated with the value
+ // being matched, so that's a read of the value being matched.
+ //
+ // FIXME: We don't actually reads for ZSTs.
needs_to_be_read = true;
}
+ _ => {
+ // Otherwise, this is a struct/enum variant, and so it's
+ // only a read if we need to read the discriminant.
+ needs_to_be_read |= is_multivariant_adt(place.place.ty());
+ }
}
}
- PatKind::Lit(_) => {
- // If the PatKind is a Lit then we want
+ PatKind::TupleStruct(..) | PatKind::Struct(..) | PatKind::Tuple(..) => {
+ // For `Foo(..)`, `Foo { ... }` and `(...)` patterns, check if we are matching
+ // against a multivariant enum or struct. In that case, we have to read
+ // the discriminant. Otherwise this kind of pattern doesn't actually
+ // read anything (we'll get invoked for the `...`, which may indeed
+ // perform some reads).
+
+ let place_ty = place.place.ty();
+ needs_to_be_read |= is_multivariant_adt(place_ty);
+ }
+ PatKind::Lit(_) | PatKind::Range(..) => {
+ // If the PatKind is a Lit or a Range then we want
// to borrow discr.
needs_to_be_read = true;
}
- _ => {}
+ PatKind::Or(_)
+ | PatKind::Box(_)
+ | PatKind::Slice(..)
+ | PatKind::Ref(..)
+ | PatKind::Wild => {
+ // If the PatKind is Or, Box, Slice or Ref, the decision is made later
+ // as these patterns contains subpatterns
+ // If the PatKind is Wild, the decision is made based on the other patterns being
+ // examined
+ }
}
}));
}
@@ -319,12 +344,8 @@
match op {
hir::InlineAsmOperand::In { expr, .. }
| hir::InlineAsmOperand::Sym { expr, .. } => self.consume_expr(expr),
- hir::InlineAsmOperand::Out { expr, .. } => {
- if let Some(expr) = expr {
- self.mutate_expr(expr);
- }
- }
- hir::InlineAsmOperand::InOut { expr, .. } => {
+ hir::InlineAsmOperand::Out { expr: Some(expr), .. }
+ | hir::InlineAsmOperand::InOut { expr, .. } => {
self.mutate_expr(expr);
}
hir::InlineAsmOperand::SplitInOut { in_expr, out_expr, .. } => {
@@ -333,7 +354,8 @@
self.mutate_expr(out_expr);
}
}
- hir::InlineAsmOperand::Const { .. } => {}
+ hir::InlineAsmOperand::Out { expr: None, .. }
+ | hir::InlineAsmOperand::Const { .. } => {}
}
}
}
@@ -419,10 +441,12 @@
fn walk_stmt(&mut self, stmt: &hir::Stmt<'_>) {
match stmt.kind {
- hir::StmtKind::Local(ref local) => {
- self.walk_local(&local);
+ hir::StmtKind::Local(hir::Local { pat, init: Some(ref expr), .. }) => {
+ self.walk_local(expr, pat, |_| {});
}
+ hir::StmtKind::Local(_) => {}
+
hir::StmtKind::Item(_) => {
// We don't visit nested items in this visitor,
// only the fn body we were given.
@@ -434,16 +458,14 @@
}
}
- fn walk_local(&mut self, local: &hir::Local<'_>) {
- if let Some(ref expr) = local.init {
- // Variable declarations with
- // initializers are considered
- // "assigns", which is handled by
- // `walk_pat`:
- self.walk_expr(&expr);
- let init_place = return_if_err!(self.mc.cat_expr(&expr));
- self.walk_irrefutable_pat(&init_place, &local.pat);
- }
+ fn walk_local<F>(&mut self, expr: &hir::Expr<'_>, pat: &hir::Pat<'_>, mut f: F)
+ where
+ F: FnMut(&mut Self),
+ {
+ self.walk_expr(&expr);
+ let expr_place = return_if_err!(self.mc.cat_expr(&expr));
+ f(self);
+ self.walk_irrefutable_pat(&expr_place, &pat);
}
/// Indicates that the value of `blk` will be consumed, meaning either copied or moved
@@ -515,9 +537,9 @@
self.walk_expr(with_expr);
}
- // Invoke the appropriate delegate calls for anything that gets
- // consumed or borrowed as part of the automatic adjustment
- // process.
+ /// Invoke the appropriate delegate calls for anything that gets
+ /// consumed or borrowed as part of the automatic adjustment
+ /// process.
fn walk_adjustment(&mut self, expr: &hir::Expr<'_>) {
let adjustments = self.mc.typeck_results.expr_adjustments(expr);
let mut place_with_id = return_if_err!(self.mc.cat_expr_unadjusted(expr));
@@ -597,6 +619,8 @@
if let Some(hir::Guard::If(ref e)) = arm.guard {
self.consume_expr(e)
+ } else if let Some(hir::Guard::IfLet(_, ref e)) = arm.guard {
+ self.consume_expr(e)
}
self.consume_expr(&arm.body);
@@ -667,7 +691,7 @@
/// When the current body being handled is a closure, then we must make sure that
/// - The parent closure only captures Places from the nested closure that are not local to it.
///
- /// In the following example the closures `c` only captures `p.x`` even though `incr`
+ /// In the following example the closures `c` only captures `p.x` even though `incr`
/// is a capture of the nested closure
///
/// ```rust,ignore(cannot-test-this-because-pseudo-code)
@@ -803,7 +827,7 @@
}
// - If a place is used in a `ByValue` context then move it if it's not a `Copy` type.
-// - If the place that is a `Copy` type consider it a `ImmBorrow`.
+// - If the place that is a `Copy` type consider it an `ImmBorrow`.
fn delegate_consume<'a, 'tcx>(
mc: &mc::MemCategorizationContext<'a, 'tcx>,
delegate: &mut (dyn Delegate<'tcx> + 'a),
@@ -821,3 +845,22 @@
}
}
}
+
+fn is_multivariant_adt(ty: Ty<'tcx>) -> bool {
+ if let ty::Adt(def, _) = ty.kind() {
+ // Note that if a non-exhaustive SingleVariant is defined in another crate, we need
+ // to assume that more cases will be added to the variant in the future. This mean
+ // that we should handle non-exhaustive SingleVariant the same way we would handle
+ // a MultiVariant.
+ // If the variant is not local it must be defined in another crate.
+ let is_non_exhaustive = match def.adt_kind() {
+ AdtKind::Struct | AdtKind::Union => {
+ def.non_enum_variant().is_field_list_non_exhaustive()
+ }
+ AdtKind::Enum => def.is_variant_list_non_exhaustive(),
+ };
+ def.variants.len() > 1 || (!def.did.is_local() && is_non_exhaustive)
+ } else {
+ false
+ }
+}
diff --git a/compiler/rustc_typeck/src/hir_wf_check.rs b/compiler/rustc_typeck/src/hir_wf_check.rs
index e7503d3..b7ede0e 100644
--- a/compiler/rustc_typeck/src/hir_wf_check.rs
+++ b/compiler/rustc_typeck/src/hir_wf_check.rs
@@ -38,20 +38,20 @@
// given the type `Option<MyStruct<u8>>`, we will check
// `Option<MyStruct<u8>>`, `MyStruct<u8>`, and `u8`.
// For each type, we perform a well-formed check, and see if we get
- // an erorr that matches our expected predicate. We keep save
+ // an error that matches our expected predicate. We save
// the `ObligationCause` corresponding to the *innermost* type,
// which is the most specific type that we can point to.
// In general, the different components of an `hir::Ty` may have
- // completely differentr spans due to macro invocations. Pointing
+ // completely different spans due to macro invocations. Pointing
// to the most accurate part of the type can be the difference
// between a useless span (e.g. the macro invocation site)
- // and a useful span (e.g. a user-provided type passed in to the macro).
+ // and a useful span (e.g. a user-provided type passed into the macro).
//
// This approach is quite inefficient - we redo a lot of work done
// by the normal WF checker. However, this code is run at most once
// per reported error - it will have no impact when compilation succeeds,
- // and should only have an impact if a very large number of errors are
- // displaydd to the user.
+ // and should only have an impact if a very large number of errors is
+ // displayed to the user.
struct HirWfCheck<'tcx> {
tcx: TyCtxt<'tcx>,
predicate: ty::Predicate<'tcx>,
@@ -126,10 +126,12 @@
WellFormedLoc::Ty(_) => match hir.get(hir_id) {
hir::Node::ImplItem(item) => match item.kind {
hir::ImplItemKind::TyAlias(ty) => Some(ty),
+ hir::ImplItemKind::Const(ty, _) => Some(ty),
ref item => bug!("Unexpected ImplItem {:?}", item),
},
hir::Node::TraitItem(item) => match item.kind {
hir::TraitItemKind::Type(_, ty) => ty,
+ hir::TraitItemKind::Const(ty, _) => Some(ty),
ref item => bug!("Unexpected TraitItem {:?}", item),
},
hir::Node::Item(item) => match item.kind {
diff --git a/compiler/rustc_typeck/src/impl_wf_check.rs b/compiler/rustc_typeck/src/impl_wf_check.rs
index 1240946..194c4ef 100644
--- a/compiler/rustc_typeck/src/impl_wf_check.rs
+++ b/compiler/rustc_typeck/src/impl_wf_check.rs
@@ -119,7 +119,7 @@
let impl_predicates = tcx.predicates_of(impl_def_id);
let impl_trait_ref = tcx.impl_trait_ref(impl_def_id);
- let mut input_parameters = cgp::parameters_for_impl(impl_self_ty, impl_trait_ref);
+ let mut input_parameters = cgp::parameters_for_impl(tcx, impl_self_ty, impl_trait_ref);
cgp::identify_constrained_generic_params(
tcx,
impl_predicates,
@@ -136,7 +136,7 @@
match item.kind {
ty::AssocKind::Type => {
if item.defaultness.has_value() {
- cgp::parameters_for(&tcx.type_of(def_id), true)
+ cgp::parameters_for(tcx, &tcx.type_of(def_id), true)
} else {
Vec::new()
}
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 505d9a5..8ecd603 100644
--- a/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs
+++ b/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs
@@ -68,7 +68,6 @@
use crate::constrained_generic_params as cgp;
use rustc_data_structures::fx::FxHashSet;
-use rustc_hir as hir;
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_infer::infer::outlives::env::OutlivesEnvironment;
use rustc_infer::infer::{InferCtxt, RegionckMode, TyCtxtInferExt};
@@ -207,15 +206,15 @@
continue;
}
- unconstrained_parameters.extend(cgp::parameters_for(&projection_ty, true));
+ unconstrained_parameters.extend(cgp::parameters_for(tcx, &projection_ty, true));
- for param in cgp::parameters_for(&projected_ty, false) {
+ for param in cgp::parameters_for(tcx, &projected_ty, false) {
if !unconstrained_parameters.contains(¶m) {
constrained_params.insert(param.0);
}
}
- unconstrained_parameters.extend(cgp::parameters_for(&projected_ty, true));
+ unconstrained_parameters.extend(cgp::parameters_for(tcx, &projected_ty, true));
}
}
@@ -249,7 +248,7 @@
parent_substs: &Vec<GenericArg<'tcx>>,
span: Span,
) {
- let mut base_params = cgp::parameters_for(parent_substs, true);
+ let mut base_params = cgp::parameters_for(tcx, parent_substs, true);
base_params.sort_by_key(|param| param.0);
if let (_, [duplicate, ..]) = base_params.partition_dedup() {
let param = impl1_substs[duplicate.0 as usize];
@@ -363,10 +362,13 @@
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() => (),
+ _ if predicate.is_global(tcx) => (),
// We allow specializing on explicitly marked traits with no associated
// items.
- ty::PredicateKind::Trait(pred, hir::Constness::NotConst) => {
+ ty::PredicateKind::Trait(ty::TraitPredicate {
+ trait_ref,
+ constness: ty::BoundConstness::NotConst,
+ }) => {
if !matches!(
trait_predicate_kind(tcx, predicate),
Some(TraitSpecializationKind::Marker)
@@ -376,7 +378,7 @@
span,
&format!(
"cannot specialize on trait `{}`",
- tcx.def_path_str(pred.def_id()),
+ tcx.def_path_str(trait_ref.def_id),
),
)
.emit()
@@ -394,15 +396,17 @@
predicate: ty::Predicate<'tcx>,
) -> Option<TraitSpecializationKind> {
match predicate.kind().skip_binder() {
- ty::PredicateKind::Trait(pred, hir::Constness::NotConst) => {
- Some(tcx.trait_def(pred.def_id()).specialization_kind)
- }
- ty::PredicateKind::Trait(_, hir::Constness::Const)
+ ty::PredicateKind::Trait(ty::TraitPredicate {
+ trait_ref,
+ constness: ty::BoundConstness::NotConst,
+ }) => Some(tcx.trait_def(trait_ref.def_id).specialization_kind),
+ ty::PredicateKind::Trait(_)
| ty::PredicateKind::RegionOutlives(_)
| ty::PredicateKind::TypeOutlives(_)
| ty::PredicateKind::Projection(_)
| ty::PredicateKind::WellFormed(_)
| ty::PredicateKind::Subtype(_)
+ | ty::PredicateKind::Coerce(_)
| ty::PredicateKind::ObjectSafe(_)
| ty::PredicateKind::ClosureKind(..)
| ty::PredicateKind::ConstEvaluatable(..)
diff --git a/compiler/rustc_typeck/src/lib.rs b/compiler/rustc_typeck/src/lib.rs
index 5b71786..749f681 100644
--- a/compiler/rustc_typeck/src/lib.rs
+++ b/compiler/rustc_typeck/src/lib.rs
@@ -56,11 +56,11 @@
*/
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
-#![feature(bindings_after_at)]
+#![cfg_attr(bootstrap, feature(bindings_after_at))]
#![feature(bool_to_option)]
-#![feature(box_syntax)]
#![feature(crate_visibility_modifier)]
#![feature(format_args_capture)]
+#![feature(if_let_guard)]
#![feature(in_band_lifetimes)]
#![feature(is_sorted)]
#![feature(iter_zip)]
@@ -69,6 +69,7 @@
#![feature(never_type)]
#![feature(slice_partition_dedup)]
#![feature(control_flow_enum)]
+#![cfg_attr(bootstrap, allow(incomplete_features))] // if_let_guard
#![recursion_limit = "256"]
#[macro_use]
@@ -292,7 +293,7 @@
}
for attr in tcx.get_attrs(main_def_id) {
- if tcx.sess.check_name(attr, sym::track_caller) {
+ if attr.has_name(sym::track_caller) {
tcx.sess
.struct_span_err(
attr.span,
@@ -406,7 +407,7 @@
let attrs = tcx.hir().attrs(start_id);
for attr in attrs {
- if tcx.sess.check_name(attr, sym::track_caller) {
+ if attr.has_name(sym::track_caller) {
tcx.sess
.struct_span_err(
attr.span,
@@ -547,7 +548,7 @@
&item_cx,
hir_trait,
DUMMY_SP,
- hir::Constness::NotConst,
+ ty::BoundConstness::NotConst,
self_ty,
&mut bounds,
true,
diff --git a/compiler/rustc_typeck/src/mem_categorization.rs b/compiler/rustc_typeck/src/mem_categorization.rs
index 14af110..f876d0f 100644
--- a/compiler/rustc_typeck/src/mem_categorization.rs
+++ b/compiler/rustc_typeck/src/mem_categorization.rs
@@ -368,6 +368,7 @@
| hir::ExprKind::Tup(..)
| hir::ExprKind::Binary(..)
| hir::ExprKind::Block(..)
+ | hir::ExprKind::Let(..)
| hir::ExprKind::Loop(..)
| hir::ExprKind::Match(..)
| hir::ExprKind::Lit(..)
diff --git a/compiler/rustc_typeck/src/outlives/explicit.rs b/compiler/rustc_typeck/src/outlives/explicit.rs
index 6e5be87..2ac1a18 100644
--- a/compiler/rustc_typeck/src/outlives/explicit.rs
+++ b/compiler/rustc_typeck/src/outlives/explicit.rs
@@ -56,6 +56,7 @@
| ty::PredicateKind::ObjectSafe(..)
| ty::PredicateKind::ClosureKind(..)
| ty::PredicateKind::Subtype(..)
+ | ty::PredicateKind::Coerce(..)
| 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 6e6ecf6..0e96601 100644
--- a/compiler/rustc_typeck/src/outlives/implicit_infer.rs
+++ b/compiler/rustc_typeck/src/outlives/implicit_infer.rs
@@ -114,7 +114,18 @@
required_predicates: &mut RequiredPredicates<'tcx>,
explicit_map: &mut ExplicitPredicatesMap<'tcx>,
) {
- for arg in field_ty.walk() {
+ // We must not look into the default substs of consts
+ // as computing those depends on the results of `predicates_of`.
+ //
+ // Luckily the only types contained in default substs are type
+ // parameters which don't matter here.
+ //
+ // FIXME(adt_const_params): Once complex const parameter types
+ // are allowed, this might be incorrect. I think that we will still be
+ // fine, as all outlives relations of the const param types should also
+ // be part of the adt containing it, but we should still both update the
+ // documentation and add some tests for this.
+ for arg in field_ty.walk_ignoring_default_const_substs() {
let ty = match arg.unpack() {
GenericArgKind::Type(ty) => ty,
@@ -297,7 +308,7 @@
// to apply the substs, and not filter this predicate, we might then falsely
// conclude that e.g., `X: 'x` was a reasonable inferred requirement.
//
- // Another similar case is where we have a inferred
+ // Another similar case is where we have an inferred
// requirement like `<Self as Trait>::Foo: 'b`. We presently
// ignore such requirements as well (cc #54467)-- though
// conceivably it might be better if we could extract the `Foo
@@ -306,7 +317,7 @@
// 'b`.
if let Some(self_ty) = ignored_self_ty {
if let GenericArgKind::Type(ty) = outlives_predicate.0.unpack() {
- if ty.walk().any(|arg| arg == self_ty.into()) {
+ if ty.walk(tcx).any(|arg| arg == self_ty.into()) {
debug!("skipping self ty = {:?}", &ty);
continue;
}
diff --git a/compiler/rustc_typeck/src/outlives/mod.rs b/compiler/rustc_typeck/src/outlives/mod.rs
index d7eb31c..70a2ba7 100644
--- a/compiler/rustc_typeck/src/outlives/mod.rs
+++ b/compiler/rustc_typeck/src/outlives/mod.rs
@@ -20,6 +20,27 @@
fn inferred_outlives_of(tcx: TyCtxt<'_>, item_def_id: DefId) -> &[(ty::Predicate<'_>, Span)] {
let id = tcx.hir().local_def_id_to_hir_id(item_def_id.expect_local());
+ if matches!(tcx.def_kind(item_def_id), hir::def::DefKind::AnonConst) && tcx.lazy_normalization()
+ {
+ if let Some(_) = tcx.hir().opt_const_param_default_param_hir_id(id) {
+ // In `generics_of` we set the generics' parent to be our parent's parent which means that
+ // we lose out on the predicates of our actual parent if we dont return those predicates here.
+ // (See comment in `generics_of` for more information on why the parent shenanigans is necessary)
+ //
+ // struct Foo<'a, 'b, const N: usize = { ... }>(&'a &'b ());
+ // ^^^ ^^^^^^^ the def id we are calling
+ // ^^^ inferred_outlives_of on
+ // parent item we dont have set as the
+ // parent of generics returned by `generics_of`
+ //
+ // In the above code we want the anon const to have predicates in its param env for `'b: 'a`
+ let item_id = tcx.hir().get_parent_item(id);
+ let item_def_id = tcx.hir().local_def_id(item_id).to_def_id();
+ // In the above code example we would be calling `inferred_outlives_of(Foo)` here
+ return tcx.inferred_outlives_of(item_def_id);
+ }
+ }
+
match tcx.hir().get(id) {
Node::Item(item) => match item.kind {
hir::ItemKind::Struct(..) | hir::ItemKind::Enum(..) | hir::ItemKind::Union(..) => {